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