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