Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
RandGeneral.cc
Go to the documentation of this file.
1// $Id:$
2// -*- C++ -*-
3//
4// -----------------------------------------------------------------------
5// HEP Random
6// --- RandGeneral ---
7// class implementation file
8// -----------------------------------------------------------------------
9
10// =======================================================================
11// S.Magni & G.Pieri - Created: 5th September 1995
12// G.Cosmo - Added constructor using default engine from the
13// static generator. Simplified shoot() and
14// shootArray() (not needed in principle!): 20th Aug 1998
15// M.G.Pia & G.Cosmo - Fixed bug in computation of theIntegralPdf in
16// two constructors: 5th Jan 1999
17// S.Magni & G.Pieri - Added linear interpolation: 24th Mar 1999
18// M. Fischler - General cleanup: 14th May 1999
19// + Eliminated constructor code replication by factoring
20// common code into prepareTable.
21// + Eliminated fire/shoot code replication by factoring
22// out common code into mapRandom.
23// + A couple of methods are moved inline to avoid a
24// speed cost for factoring out mapRandom: fire()
25// and shoot(anEngine).
26// + Inserted checks for negative weight and zero total
27// weight in the bins.
28// + Modified the binary search loop to avoid incorrect
29// behavior when rand is example on a boundary.
30// + Moved the check of InterpolationType up into
31// the constructor. A type other than 0 or 1
32// will give the interpolated distribution (instead of
33// a distribution that always returns 0).
34// + Modified the computation of the returned value
35// to use algeraic simplification to improve speed.
36// Eliminated two of the three divisionns, made
37// use of the fact that nabove-nbelow is always 1, etc.
38// + Inserted a check for rand hitting the boundary of a
39// zero-width bin, to avoid dividing 0/0.
40// M. Fischler - Minor correction in assert 31 July 2001
41// + changed from assert (above = below+1) to ==
42// M Fischler - put and get to/from streams 12/15/04
43// + Modifications to use a vector as theIntegraPdf
44// M Fischler - put/get to/from streams uses pairs of ulongs when
45// + storing doubles avoid problems with precision
46// 4/14/05
47//
48// =======================================================================
49
52#include <cassert>
53
54namespace CLHEP {
55
56std::string RandGeneral::name() const {return "RandGeneral";}
57HepRandomEngine & RandGeneral::engine() {return *localEngine;}
58
59
60//////////////////
61// Constructors
62//////////////////
63
64RandGeneral::RandGeneral( const double* aProbFunc,
65 int theProbSize,
66 int IntType )
67 : HepRandom(),
68 localEngine(HepRandom::getTheEngine(), do_nothing_deleter()),
69 nBins(theProbSize),
70 InterpolationType(IntType)
71{
72 prepareTable(aProbFunc);
73}
74
76 const double* aProbFunc,
77 int theProbSize,
78 int IntType )
79: HepRandom(),
80 localEngine(&anEngine, do_nothing_deleter()),
81 nBins(theProbSize),
82 InterpolationType(IntType)
83{
84 prepareTable(aProbFunc);
85}
86
88 const double* aProbFunc,
89 int theProbSize,
90 int IntType )
91: HepRandom(),
92 localEngine(anEngine),
93 nBins(theProbSize),
94 InterpolationType(IntType)
95{
96 prepareTable(aProbFunc);
97}
98
99void RandGeneral::prepareTable(const double* aProbFunc) {
100//
101// Private method called only by constructors. Prepares theIntegralPdf.
102//
103 if (nBins < 1) {
104 std::cerr <<
105 "RandGeneral constructed with no bins - will use flat distribution\n";
106 useFlatDistribution();
107 return;
108 }
109
110 theIntegralPdf.resize(nBins+1);
111 theIntegralPdf[0] = 0;
112 register int ptn;
113 register double weight;
114
115 for ( ptn = 0; ptn<nBins; ++ptn ) {
116 weight = aProbFunc[ptn];
117 if ( weight < 0 ) {
118 // We can't stomach negative bin contents, they invalidate the
119 // search algorithm when the distribution is fired.
120 std::cerr <<
121 "RandGeneral constructed with negative-weight bin " << ptn <<
122 " = " << weight << " \n -- will substitute 0 weight \n";
123 weight = 0;
124 }
125 // std::cout << ptn << " " << weight << " " << theIntegralPdf[ptn] << "\n";
126 theIntegralPdf[ptn+1] = theIntegralPdf[ptn] + weight;
127 }
128
129 if ( theIntegralPdf[nBins] <= 0 ) {
130 std::cerr <<
131 "RandGeneral constructed nothing in bins - will use flat distribution\n";
132 useFlatDistribution();
133 return;
134 }
135
136 for ( ptn = 0; ptn < nBins+1; ++ptn ) {
137 theIntegralPdf[ptn] /= theIntegralPdf[nBins];
138 // std::cout << ptn << " " << theIntegralPdf[ptn] << "\n";
139 }
140
141 // And another useful variable is ...
142 oneOverNbins = 1.0 / nBins;
143
144 // One last chore:
145
146 if ( (InterpolationType != 0) && (InterpolationType != 1) ) {
147 std::cerr <<
148 "RandGeneral does not recognize IntType " << InterpolationType
149 << "\n Will use type 0 (continuous linear interpolation \n";
150 InterpolationType = 0;
151 }
152
153} // prepareTable()
154
155void RandGeneral::useFlatDistribution() {
156//
157// Private method called only by prepareTables in case of user error.
158//
159 nBins = 1;
160 theIntegralPdf.resize(2);
161 theIntegralPdf[0] = 0;
162 theIntegralPdf[1] = 1;
163 oneOverNbins = 1.0;
164 return;
165
166} // UseFlatDistribution()
167
168//////////////////
169// Destructor
170//////////////////
171
173}
174
175
176///////////////////
177// mapRandom(rand)
178///////////////////
179
180double RandGeneral::mapRandom(double rand) const {
181//
182// Private method to take the random (however it is created) and map it
183// according to the distribution.
184//
185
186 int nbelow = 0; // largest k such that I[k] is known to be <= rand
187 int nabove = nBins; // largest k such that I[k] is known to be > rand
188 int middle;
189
190 while (nabove > nbelow+1) {
191 middle = (nabove + nbelow+1)>>1;
192 if (rand >= theIntegralPdf[middle]) {
193 nbelow = middle;
194 } else {
195 nabove = middle;
196 }
197 } // after this loop, nabove is always nbelow+1 and they straddle rad:
198 assert ( nabove == nbelow+1 );
199 assert ( theIntegralPdf[nbelow] <= rand );
200 assert ( theIntegralPdf[nabove] >= rand );
201 // If a defective engine produces rand=1, that will
202 // still give sensible results so we relax the > rand assertion
203
204 if ( InterpolationType == 1 ) {
205
206 return nbelow * oneOverNbins;
207
208 } else {
209
210 double binMeasure = theIntegralPdf[nabove] - theIntegralPdf[nbelow];
211 // binMeasure is always aProbFunc[nbelow],
212 // but we don't have aProbFunc any more so we subtract.
213
214 if ( binMeasure == 0 ) {
215 // rand lies right in a bin of measure 0. Simply return the center
216 // of the range of that bin. (Any value between k/N and (k+1)/N is
217 // equally good, in this rare case.)
218 return (nbelow + .5) * oneOverNbins;
219 }
220
221 double binFraction = (rand - theIntegralPdf[nbelow]) / binMeasure;
222
223 return (nbelow + binFraction) * oneOverNbins;
224 }
225
226} // mapRandom(rand)
227
229 const int size, double* vect )
230{
231 register int i;
232
233 for (i=0; i<size; ++i) {
234 vect[i] = shoot(anEngine);
235 }
236}
237
238void RandGeneral::fireArray( const int size, double* vect )
239{
240 register int i;
241
242 for (i=0; i<size; ++i) {
243 vect[i] = fire();
244 }
245}
246
247std::ostream & RandGeneral::put ( std::ostream & os ) const {
248 int pr=os.precision(20);
249 std::vector<unsigned long> t(2);
250 os << " " << name() << "\n";
251 os << "Uvec" << "\n";
252 os << nBins << " " << oneOverNbins << " " << InterpolationType << "\n";
253 t = DoubConv::dto2longs(oneOverNbins);
254 os << t[0] << " " << t[1] << "\n";
255 assert (static_cast<int>(theIntegralPdf.size())==nBins+1);
256 for (unsigned int i=0; i<theIntegralPdf.size(); ++i) {
257 t = DoubConv::dto2longs(theIntegralPdf[i]);
258 os << theIntegralPdf[i] << " " << t[0] << " " << t[1] << "\n";
259 }
260 os.precision(pr);
261 return os;
262}
263
264std::istream & RandGeneral::get ( std::istream & is ) {
265 std::string inName;
266 is >> inName;
267 if (inName != name()) {
268 is.clear(std::ios::badbit | is.rdstate());
269 std::cerr << "Mismatch when expecting to read state of a "
270 << name() << " distribution\n"
271 << "Name found was " << inName
272 << "\nistream is left in the badbit state\n";
273 return is;
274 }
275 if (possibleKeywordInput(is, "Uvec", nBins)) {
276 std::vector<unsigned long> t(2);
277 is >> nBins >> oneOverNbins >> InterpolationType;
278 is >> t[0] >> t[1]; oneOverNbins = DoubConv::longs2double(t);
279 theIntegralPdf.resize(nBins+1);
280 for (unsigned int i=0; i<theIntegralPdf.size(); ++i) {
281 is >> theIntegralPdf[i] >> t[0] >> t[1];
282 theIntegralPdf[i] = DoubConv::longs2double(t);
283 }
284 return is;
285 }
286 // is >> nBins encompassed by possibleKeywordInput
287 is >> oneOverNbins >> InterpolationType;
288 theIntegralPdf.resize(nBins+1);
289 for (unsigned int i=0; i<theIntegralPdf.size(); ++i) is >> theIntegralPdf[i];
290 return is;
291}
292
293} // namespace CLHEP
static double longs2double(const std::vector< unsigned long > &v)
Definition: DoubConv.cc:114
static std::vector< unsigned long > dto2longs(double d)
Definition: DoubConv.cc:98
RandGeneral(const double *aProbFunc, int theProbSize, int IntType=0)
Definition: RandGeneral.cc:64
std::istream & get(std::istream &is)
Definition: RandGeneral.cc:264
virtual ~RandGeneral()
Definition: RandGeneral.cc:172
std::ostream & put(std::ostream &os) const
Definition: RandGeneral.cc:247
void fireArray(const int size, double *vect)
Definition: RandGeneral.cc:238
std::string name() const
Definition: RandGeneral.cc:56
HepRandomEngine & engine()
Definition: RandGeneral.cc:57
void shootArray(const int size, double *vect)
Definition: DoubConv.h:17
bool possibleKeywordInput(IS &is, const std::string &key, T &t)
Definition: RandomEngine.h:167