CLHEP 2.4.6.4
C++ Class Library for High Energy Physics
Loading...
Searching...
No Matches
RandGeneral.cc
Go to the documentation of this file.
1//
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
50#include "CLHEP/Random/defs.h"
51#include "CLHEP/Random/RandGeneral.h"
52#include "CLHEP/Random/DoubConv.h"
53#include <cassert>
54#include <iostream>
55#include <string>
56#include <vector>
57
58namespace CLHEP {
59
60std::string RandGeneral::name() const {return "RandGeneral";}
61HepRandomEngine & RandGeneral::engine() {return *localEngine;}
62
63
64//////////////////
65// Constructors
66//////////////////
67
68RandGeneral::RandGeneral( const double* aProbFunc,
69 int theProbSize,
70 int IntType )
71 : HepRandom(),
72 localEngine(HepRandom::getTheEngine(), do_nothing_deleter()),
73 nBins(theProbSize),
74 InterpolationType(IntType)
75{
76 prepareTable(aProbFunc);
77}
78
80 const double* aProbFunc,
81 int theProbSize,
82 int IntType )
83: HepRandom(),
84 localEngine(&anEngine, do_nothing_deleter()),
85 nBins(theProbSize),
86 InterpolationType(IntType)
87{
88 prepareTable(aProbFunc);
89}
90
92 const double* aProbFunc,
93 int theProbSize,
94 int IntType )
95: HepRandom(),
96 localEngine(anEngine),
97 nBins(theProbSize),
98 InterpolationType(IntType)
99{
100 prepareTable(aProbFunc);
101}
102
103void RandGeneral::prepareTable(const double* aProbFunc) {
104//
105// Private method called only by constructors. Prepares theIntegralPdf.
106//
107 if (nBins < 1) {
108 std::cerr <<
109 "RandGeneral constructed with no bins - will use flat distribution\n";
110 useFlatDistribution();
111 return;
112 }
113
114 theIntegralPdf.resize(nBins+1);
115 theIntegralPdf[0] = 0;
116 int ptn;
117 double weight;
118
119 for ( ptn = 0; ptn<nBins; ++ptn ) {
120 weight = aProbFunc[ptn];
121 if ( weight < 0 ) {
122 // We can't stomach negative bin contents, they invalidate the
123 // search algorithm when the distribution is fired.
124 std::cerr <<
125 "RandGeneral constructed with negative-weight bin " << ptn <<
126 " = " << weight << " \n -- will substitute 0 weight \n";
127 weight = 0;
128 }
129 // std::cout << ptn << " " << weight << " " << theIntegralPdf[ptn] << "\n";
130 theIntegralPdf[ptn+1] = theIntegralPdf[ptn] + weight;
131 }
132
133 if ( theIntegralPdf[nBins] <= 0 ) {
134 std::cerr <<
135 "RandGeneral constructed nothing in bins - will use flat distribution\n";
136 useFlatDistribution();
137 return;
138 }
139
140 for ( ptn = 0; ptn < nBins+1; ++ptn ) {
141 theIntegralPdf[ptn] /= theIntegralPdf[nBins];
142 // std::cout << ptn << " " << theIntegralPdf[ptn] << "\n";
143 }
144
145 // And another useful variable is ...
146 oneOverNbins = 1.0 / nBins;
147
148 // One last chore:
149
150 if ( (InterpolationType != 0) && (InterpolationType != 1) ) {
151 std::cerr <<
152 "RandGeneral does not recognize IntType " << InterpolationType
153 << "\n Will use type 0 (continuous linear interpolation \n";
154 InterpolationType = 0;
155 }
156
157} // prepareTable()
158
159void RandGeneral::useFlatDistribution() {
160//
161// Private method called only by prepareTables in case of user error.
162//
163 nBins = 1;
164 theIntegralPdf.resize(2);
165 theIntegralPdf[0] = 0;
166 theIntegralPdf[1] = 1;
167 oneOverNbins = 1.0;
168 return;
169
170} // UseFlatDistribution()
171
172//////////////////
173// Destructor
174//////////////////
175
177}
178
179
180///////////////////
181// mapRandom(rand)
182///////////////////
183
184double RandGeneral::mapRandom(double rand) const {
185//
186// Private method to take the random (however it is created) and map it
187// according to the distribution.
188//
189
190 int nbelow = 0; // largest k such that I[k] is known to be <= rand
191 int nabove = nBins; // largest k such that I[k] is known to be > rand
192 int middle;
193
194 while (nabove > nbelow+1) {
195 middle = (nabove + nbelow+1)>>1;
196 if (rand >= theIntegralPdf[middle]) {
197 nbelow = middle;
198 } else {
199 nabove = middle;
200 }
201 } // after this loop, nabove is always nbelow+1 and they straddle rad:
202 assert ( nabove == nbelow+1 );
203 assert ( theIntegralPdf[nbelow] <= rand );
204 assert ( theIntegralPdf[nabove] >= rand );
205 // If a defective engine produces rand=1, that will
206 // still give sensible results so we relax the > rand assertion
207
208 if ( InterpolationType == 1 ) {
209
210 return nbelow * oneOverNbins;
211
212 } else {
213
214 double binMeasure = theIntegralPdf[nabove] - theIntegralPdf[nbelow];
215 // binMeasure is always aProbFunc[nbelow],
216 // but we don't have aProbFunc any more so we subtract.
217
218 if ( binMeasure == 0 ) {
219 // rand lies right in a bin of measure 0. Simply return the center
220 // of the range of that bin. (Any value between k/N and (k+1)/N is
221 // equally good, in this rare case.)
222 return (nbelow + .5) * oneOverNbins;
223 }
224
225 double binFraction = (rand - theIntegralPdf[nbelow]) / binMeasure;
226
227 return (nbelow + binFraction) * oneOverNbins;
228 }
229
230} // mapRandom(rand)
231
233 const int size, double* vect )
234{
235 int i;
236
237 for (i=0; i<size; ++i) {
238 vect[i] = shoot(anEngine);
239 }
240}
241
242void RandGeneral::fireArray( const int size, double* vect )
243{
244 int i;
245
246 for (i=0; i<size; ++i) {
247 vect[i] = fire();
248 }
249}
250
251std::ostream & RandGeneral::put ( std::ostream & os ) const {
252 long pr=os.precision(20);
253 std::vector<unsigned long> t(2);
254 os << " " << name() << "\n";
255 os << "Uvec" << "\n";
256 os << nBins << " " << oneOverNbins << " " << InterpolationType << "\n";
257 t = DoubConv::dto2longs(oneOverNbins);
258 os << t[0] << " " << t[1] << "\n";
259 assert (static_cast<int>(theIntegralPdf.size())==nBins+1);
260 for (unsigned int i=0; i<theIntegralPdf.size(); ++i) {
261 t = DoubConv::dto2longs(theIntegralPdf[i]);
262 os << theIntegralPdf[i] << " " << t[0] << " " << t[1] << "\n";
263 }
264 os.precision(pr);
265 return os;
266#ifdef REMOVED
267 long pr=os.precision(20);
268 os << " " << name() << "\n";
269 os << nBins << " " << oneOverNbins << " " << InterpolationType << "\n";
270 assert (static_cast<int>(theIntegralPdf.size())==nBins+1);
271 for (unsigned int i=0; i<theIntegralPdf.size(); ++i)
272 os << theIntegralPdf[i] << "\n";
273 os.precision(pr);
274 return os;
275#endif
276}
277
278std::istream & RandGeneral::get ( std::istream & is ) {
279 std::string inName;
280 is >> inName;
281 if (inName != name()) {
282 is.clear(std::ios::badbit | is.rdstate());
283 std::cerr << "Mismatch when expecting to read state of a "
284 << name() << " distribution\n"
285 << "Name found was " << inName
286 << "\nistream is left in the badbit state\n";
287 return is;
288 }
289 if (possibleKeywordInput(is, "Uvec", nBins)) {
290 std::vector<unsigned long> t(2);
291 is >> nBins >> oneOverNbins >> InterpolationType;
292 is >> t[0] >> t[1]; oneOverNbins = DoubConv::longs2double(t);
293 theIntegralPdf.resize(nBins+1);
294 for (unsigned int i=0; i<theIntegralPdf.size(); ++i) {
295 is >> theIntegralPdf[i] >> t[0] >> t[1];
296 theIntegralPdf[i] = DoubConv::longs2double(t);
297 }
298 return is;
299 }
300 // is >> nBins encompassed by possibleKeywordInput
301 is >> oneOverNbins >> InterpolationType;
302 theIntegralPdf.resize(nBins+1);
303 for (unsigned int i=0; i<theIntegralPdf.size(); ++i) is >> theIntegralPdf[i];
304 return is;
305}
306
307} // namespace CLHEP
static double longs2double(const std::vector< unsigned long > &v)
Definition: DoubConv.cc:110
static std::vector< unsigned long > dto2longs(double d)
Definition: DoubConv.cc:94
RandGeneral(const double *aProbFunc, int theProbSize, int IntType=0)
Definition: RandGeneral.cc:68
std::istream & get(std::istream &is)
Definition: RandGeneral.cc:278
virtual ~RandGeneral()
Definition: RandGeneral.cc:176
std::ostream & put(std::ostream &os) const
Definition: RandGeneral.cc:251
void fireArray(const int size, double *vect)
Definition: RandGeneral.cc:242
std::string name() const
Definition: RandGeneral.cc:60
HepRandomEngine & engine()
Definition: RandGeneral.cc:61
void shootArray(const int size, double *vect)
bool possibleKeywordInput(IS &is, const std::string &key, T &t)
Definition: RandomEngine.h:168