Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
flatToGaussian.cc
Go to the documentation of this file.
1// $Id:$
2// -*- C++ -*-
3//
4// -----------------------------------------------------------------------
5// HEP Random
6// --- flatToGaussian ---
7// class implementation file
8// -----------------------------------------------------------------------
9
10// Contains the methods that depend on the 30K-footpring gaussTables.cdat.
11//
12// flatToGaussian (double x)
13// inverseErf (double x)
14// erf (double x)
15
16// =======================================================================
17// M Fischler - Created 1/25/00.
18//
19// =======================================================================
20
21#include "CLHEP/Random/Stat.h"
23#include <iostream>
24#include <cmath>
25
26namespace CLHEP {
27
28double transformSmall (double r);
29
30//
31// Table of errInts, for use with transform(r) and quickTransform(r)
32//
33
34#ifdef Traces
35#define Trace1
36#define Trace2
37#define Trace3
38#endif
39
40// Since all these are this is static to this compilation unit only, the
41// info is establised a priori and not at each invocation.
42
43// The main data is of course the gaussTables table; the rest is all
44// bookkeeping to know what the tables mean.
45
46#define Table0size 200
47#define Table1size 250
48#define Table2size 200
49#define Table3size 250
50#define Table4size 1000
51#define TableSize (Table0size+Table1size+Table2size+Table3size+Table4size)
52
53static const int Tsizes[5] = { Table0size,
57 Table4size };
58
59#define Table0step (2.0E-13)
60#define Table1step (4.0E-11)
61#define Table2step (1.0E-8)
62#define Table3step (2.0E-6)
63#define Table4step (5.0E-4)
64
65static const double Tsteps[5] = { Table0step,
69 Table4step };
70
71#define Table0offset 0
72#define Table1offset (2*(Table0size))
73#define Table2offset (2*(Table0size + Table1size))
74#define Table3offset (2*(Table0size + Table1size + Table2size))
75#define Table4offset (2*(Table0size + Table1size + Table2size + Table3size))
76
77static const int Toffsets[5] = { Table0offset,
82
83 // Here comes the big (30K bytes) table, kept in a file ---
84
85static const double gaussTables [2*TableSize] = {
86#include "CLHEP/Random/gaussTables.cdat"
87};
88
89double HepStat::flatToGaussian (double r) {
90
91 double sign = +1.0; // We always compute a negative number of
92 // sigmas. For r > 0 we will multiply by
93 // sign = -1 to return a positive number.
94#ifdef Trace1
95std::cout << "r = " << r << "\n";
96#endif
97
98 if ( r > .5 ) {
99 r = 1-r;
100 sign = -1.0;
101#ifdef Trace1
102std::cout << "r = " << r << "sign negative \n";
103#endif
104 } else if ( r == .5 ) {
105 return 0.0;
106 }
107
108 // Find a pointer to the proper table entries, along with the fraction
109 // of the way in the relevant bin dx and the bin size h.
110
111 // Optimize for the case of table 4 by testing for that first.
112 // By removing that case from the for loop below, we save not only
113 // several table lookups, but also several index calculations that
114 // now become (compile-time) constants.
115 //
116 // Past the case of table 4, we need not be as concerned about speed since
117 // this will happen only .1% of the time.
118
119 const double* tptr = 0;
120 double dx = 0;
121 double h = 0;
122
123 // The following big if block will locate tptr, h, and dx from whichever
124 // table is applicable:
125
126 register int index;
127
128 if ( r >= Table4step ) {
129
130 index = int((Table4size<<1) * r); // 1 to Table4size-1
131 if (index <= 0) index = 1; // in case of rounding problem
132 if (index >= Table4size) index = Table4size-1;
133 dx = (Table4size<<1) * r - index; // fraction of way to next bin
134 h = Table4step;
135#ifdef Trace2
136std::cout << "index = " << index << " dx = " << dx << " h = " << h << "\n";
137#endif
138 index = (index<<1) + (Table4offset-2);
139 // at r = table4step+eps, index refers to the start of table 4
140 // and at r = .5 - eps, index refers to the next-to-last entry:
141 // remember, the table has two numbers per actual entry.
142#ifdef Trace2
143std::cout << "offset index = " << index << "\n";
144#endif
145
146 tptr = &gaussTables [index];
147
148 } else if (r < Tsteps[0]) {
149
150 // If r is so small none of the tables apply, use the asymptotic formula.
151 return (sign * transformSmall (r));
152
153 } else {
154
155 for ( int tableN = 3; tableN >= 0; tableN-- ) {
156 if ( r < Tsteps[tableN] ) {continue;} // can't happen when tableN==0
157#ifdef Trace2
158std::cout << "Using table " << tableN << "\n";
159#endif
160 double step = Tsteps[tableN];
161 index = int(r/step); // 1 to TableNsize-1
162 // The following two tests should probably never be true, but
163 // roundoff might cause index to be outside its proper range.
164 // In such a case, the interpolation still makes sense, but we
165 // need to take care that tptr points to valid data in the right table.
166 if (index == 0) index = 1;
167 if (index >= Tsizes[tableN]) index = Tsizes[tableN] - 1;
168 dx = r/step - index; // fraction of way to next bin
169 h = step;
170#ifdef Trace2
171std::cout << "index = " << index << " dx = " << dx << " h = " << h << "\n";
172#endif
173 index = (index<<1) + Toffsets[tableN] - 2;
174 tptr = &gaussTables [index];
175 break;
176 } // end of the for loop which finds tptr, dx and h in one of the tables
177
178 // The code can only get to here by a break statement, having set dx etc.
179 // It not get to here without going through one of the breaks,
180 // because before the for loop we test for the case of r < Tsteps[0].
181
182 } // End of the big if block.
183
184 // At the end of this if block, we have tptr, dx and h -- and if r is less
185 // than the smallest step, we have already returned the proper answer.
186
187 double y0 = *tptr++;
188 double d0 = *tptr++;
189 double y1 = *tptr++;
190 double d1 = *tptr;
191
192#ifdef Trace3
193std::cout << "y0: " << y0 << " y1: " << y1 << " d0: " << d0 << " d1: " << d1 << "\n";
194#endif
195
196 double x2 = dx * dx;
197 double oneMinusX = 1 - dx;
198 double oneMinusX2 = oneMinusX * oneMinusX;
199
200 double f0 = (2. * dx + 1.) * oneMinusX2;
201 double f1 = (3. - 2. * dx) * x2;
202 double g0 = h * dx * oneMinusX2;
203 double g1 = - h * oneMinusX * x2;
204
205#ifdef Trace3
206std::cout << "f0: " << f0 << " f1: " << f1 << " g0: " << g0 << " g1: " << g1 << "\n";
207#endif
208
209 double answer = f0 * y0 + f1 * y1 + g0 * d0 + g1 * d1;
210
211#ifdef Trace1
212std::cout << "variate is: " << sign*answer << "\n";
213#endif
214
215 return sign * answer;
216
217} // flatToGaussian
218
219double transformSmall (double r) {
220
221 // Solve for -v in the asymtotic formula
222 //
223 // errInt (-v) = exp(-v*v/2) 1 1*3 1*3*5
224 // ------------ * (1 - ---- + ---- - ----- + ... )
225 // v*sqrt(2*pi) v**2 v**4 v**6
226
227 // The value of r (=errInt(-v)) supplied is going to less than 2.0E-13,
228 // which is such that v < -7.25. Since the value of r is meaningful only
229 // to an absolute error of 1E-16 (double precision accuracy for a number
230 // which on the high side could be of the form 1-epsilon), computing
231 // v to more than 3-4 digits of accuracy is suspect; however, to ensure
232 // smoothness with the table generator (which uses quite a few terms) we
233 // also use terms up to 1*3*5* ... *13/v**14, and insist on accuracy of
234 // solution at the level of 1.0e-7.
235
236 // This routine is called less than one time in a trillion firings, so
237 // speed is of no concern. As a matter of technique, we terminate the
238 // iterations in case they would be infinite, but this should not happen.
239
240 double eps = 1.0e-7;
241 double guess = 7.5;
242 double v;
243
244 for ( int i = 1; i < 50; i++ ) {
245 double vn2 = 1.0/(guess*guess);
246 double s1 = -13*11*9*7*5*3 * vn2*vn2*vn2*vn2*vn2*vn2*vn2;
247 s1 += 11*9*7*5*3 * vn2*vn2*vn2*vn2*vn2*vn2;
248 s1 += -9*7*5*3 * vn2*vn2*vn2*vn2*vn2;
249 s1 += 7*5*3 * vn2*vn2*vn2*vn2;
250 s1 += -5*3 * vn2*vn2*vn2;
251 s1 += 3 * vn2*vn2 - vn2 + 1.0;
252 v = std::sqrt ( 2.0 * std::log ( s1 / (r*guess*std::sqrt(CLHEP::twopi)) ) );
253 if ( std::abs(v-guess) < eps ) break;
254 guess = v;
255 }
256
257 return -v;
258
259} // transformSmall()
260
261double HepStat::inverseErf (double t) {
262
263 // This uses erf(x) = 2*gaussCDF(sqrt(2)*x) - 1
264
265 return std::sqrt(0.5) * flatToGaussian(.5*(t+1));
266
267}
268
269double HepStat::erf (double x) {
270
271// Math:
272//
273// For any given x we can "quickly" find t0 = erfQ (x) = erf(x) + epsilon.
274//
275// Then we can find x1 = inverseErf (t0) = inverseErf (erf(x)+epsilon)
276//
277// Expanding in the small epsion,
278//
279// x1 = x + epsilon * [deriv(inverseErf(u),u) at u = t0] + O(epsilon**2)
280//
281// so epsilon is (x1-x) / [deriv(inverseErf(u),u) at u = t0] + O(epsilon**2)
282//
283// But the derivative of an inverse function is one over the derivative of the
284// function, so
285// epsilon = (x1-x) * [deriv(erf(v),v) at v = x] + O(epsilon**2)
286//
287// And the definition of the erf integral makes that derivative trivial.
288// Ultimately,
289//
290// erf(x) = erfQ(x) - (inverseErf(erfQ(x))-x) * exp(-x**2) * 2/sqrt(CLHEP::pi)
291//
292
293 double t0 = erfQ(x);
294 double deriv = std::exp(-x*x) * (2.0 / std::sqrt(CLHEP::pi));
295
296 return t0 - (inverseErf (t0) - x) * deriv;
297
298}
299
300
301} // namespace CLHEP
302
static double flatToGaussian(double r)
static double erfQ(double x)
Definition: erfQ.cc:24
static double erf(double x)
static double inverseErf(double t)
#define Table3offset
#define Table4step
#define Table1offset
#define Table4offset
#define Table0step
#define Table3step
#define Table3size
#define TableSize
#define Table2step
#define Table2offset
#define Table0offset
#define Table0size
#define Table1step
#define Table1size
#define Table2size
#define Table4size
Definition: DoubConv.h:17
double transformSmall(double r)