MINT2
SplineGenerator.cpp
Go to the documentation of this file.
1 #include <Mint/SplineGenerator.h>
2 #include <TRandom3.h>
3 #include <iostream>
4 
5 using namespace std ;
6 
7 SplineGenerator::SplineGenerator(TRandom3* rndm, const TSpline3& spline) :
8  m_rndm(rndm),
9  m_spline(spline),
10  m_integral(0.),
11  m_boxintegral(0.),
12  m_mean(0.),
13  m_bins(spline.GetNp())
14 {
15  BinInfo ibin ;
16  double xmin(0.), a(0.), b(0.), c(0.), d(0.) ;
17  int i = m_spline.GetNp() - 1 ;
18  // Get info on the highest knot in the spline.
19  m_spline.GetCoeff(i, xmin, a, b, c, d) ;
20  ibin.xmin = xmin ;
21  ibin.xmax = 1e30 ;
22  ibin.integral = 0. ;
23  ibin.ymin = 0. ;
24  ibin.ymax = 1e30 ;
25  m_bins[i] = ibin ;
26  --i ;
27  // Loop backwards over knots, so we can use the x value of the knot above
28  // to set the range.
29  for( ; i >= 0 ; --i){
30  m_spline.GetCoeff(i, xmin, a, b, c, d) ;
31  ibin.xmin = xmin ;
32  ibin.xmax = m_bins[i+1].xmin ;
33  // cout << "ibin " << i << " xmin " << ibin.xmin << " xmax " << ibin.xmax << endl ;
34  // cout << "a " << a << " b " << b << " c " << c << " d " << d << endl ;
35  ibin.integral = integral(i, ibin.xmin, ibin.xmax) ;
36  // cout << "integral " << ibin.integral << endl ;
37  m_integral += ibin.integral ;
38  pair<double, double> tps = turning_points(i) ;
39  // cout << "tps.first " << tps.first << " tps.second " << tps.second << endl ;
40  tps.first = max(min(tps.first, ibin.xmax), ibin.xmin) ;
41  tps.second = max(min(tps.second, ibin.xmax), ibin.xmin) ;
42  // cout << "tps.first " << tps.first << " tps.second " << tps.second << endl ;
43  ibin.ymax = max(
44  max(
45  max(m_spline.Eval(ibin.xmin),
46  m_spline.Eval(ibin.xmax)),
47  m_spline.Eval(tps.first)),
48  m_spline.Eval(tps.second)) ;
49  ibin.ymin = min(
50  min(
51  min(m_spline.Eval(ibin.xmin),
52  m_spline.Eval(ibin.xmax)),
53  m_spline.Eval(tps.first)),
54  m_spline.Eval(tps.second)) ;
55  if(ibin.ymin < 0.){
56  cerr << "SplineGenerator ERROR: ymin < 0. (" << ibin.ymin << ") for bin " << i << endl ;
57  }
58  ibin.boxintegral = ibin.ymax * (ibin.xmax - ibin.xmin) ;
59  // cout << "ymax " << ibin.ymax << " ymin " << ibin.ymin << " boxintegral " << ibin.boxintegral << endl ;
60  m_boxintegral += ibin.boxintegral ;
61  m_bins[i] = ibin ;
62  m_mean += mean(i, ibin.xmin, ibin.xmax) ;
63  }
64  if(m_integral != 0.)
65  m_mean /= m_integral ;
66 }
67 
68 // Total integral between the minimum and maximum knots.
69 double SplineGenerator::integral() const {
70  return m_integral ;
71 }
72 
73 // Mean of the PDF.
74 double SplineGenerator::mean() const {
75  return m_mean ;
76 }
77 
78 // Generate a random number from the spline.
80  while(true){
81  double boxsel = m_rndm->Rndm() * m_boxintegral ;
82  double boxsum(0.) ;
83  vector<BinInfo>::const_iterator ibin = m_bins.begin() ;
84  for(; ibin != m_bins.end() ; ++ibin){
85  boxsum += ibin->boxintegral ;
86  if(boxsum >= boxsel)
87  break ;
88  }
89  double x = m_rndm->Rndm() * (ibin->xmax - ibin->xmin) + ibin->xmin ;
90  if(m_rndm->Rndm() * ibin->ymax < m_spline.Eval(x))
91  return x ;
92  }
93 }
94 
95 // Get the integral of the spline between xmin and xmax.
96 double SplineGenerator::integral(double xmin, double xmax) {
97  int istart = m_spline.FindX(xmin) ;
98  int iend = m_spline.FindX(xmax) ;
99  double _integral = integral(istart, xmin, m_bins[istart].xmax)
100  + integral(iend, m_bins[iend].xmin, xmax) ;
101  for(int ibin = istart + 1 ; ibin != iend ; ++ibin)
102  _integral += m_bins[ibin].integral ;
103  return _integral ;
104 }
105 
106 // Get the spline.
107 const TSpline3& SplineGenerator::spline() const {
108  return m_spline ;
109 }
110 
111 // Partial integral for knot i at x.
112 double SplineGenerator::partial_integral(int i, double x) {
113  double xmin(0.), a(0.), b(0.), c(0.), d(0.) ;
114  m_spline.GetCoeff(i, xmin, a, b, c, d) ;
115  x -= xmin ;
116  return x * (a + x * (b/2. + x * (c/3. + x * d/4.))) ;
117 }
118 
119 // Integral for knot i between xmin and xmax.
120 double SplineGenerator::integral(int i, double xmin, double xmax) {
121  return partial_integral(i, xmax) - partial_integral(i, xmin) ;
122 }
123 
124 // Get the turning points of knot i.
125 pair<double, double> SplineGenerator::turning_points(int i) const {
126  // Note the reversal of coefficient labelling, as the standard
127  // quadratic formula is a x^2 + b x + c while TSplinePoly
128  // uses a + b x + c x^2 + d x^3.
129  double xmin(0.), d(0.), c(0.), b(0.), a(0.) ;
130  m_spline.GetCoeff(i, xmin, d, c, b, a) ;
131  b *= 2. ;
132  a *= 3. ;
133  double arg = b*b - 4. * a * c ;
134  if(arg < 0.)
135  return pair<double, double>(xmin-1e30, xmin-1e30) ;
136  return pair<double, double>(xmin + (-b - sqrt(arg))/2./a, xmin + (-b + sqrt(arg))/2./a) ;
137 }
138 
139 // The partial integral of x * f(x) used for calculating the mean.
140 double SplineGenerator::mean_part_integral(int i, double x) {
141  double xmin(0.), a(0.), b(0.), c(0.), d(0.) ;
142  m_spline.GetCoeff(i, xmin, a, b, c, d) ;
143  double xshift = x - xmin ;
144  return x * xshift * (a + xshift * (b/2. + xshift * (c/3. + xshift * d/4.)))
145  - xshift * xshift * (a/2. + xshift * (b/6. + xshift * (c/12. + xshift * d/20.))) ;
146 }
147 
148 // Get the mean between xmin and xmax for knot i.
149 double SplineGenerator::mean(int i, double xmin, double xmax) {
150  return mean_part_integral(i, xmax) - mean_part_integral(i, xmin) ;
151 }
double mean() const
double integral() const
double gen_random() const
SplineGenerator(TRandom3 *rndm, const TSpline3 &spline)
std::pair< double, double > turning_points(int i) const
std::vector< BinInfo > m_bins
double mean_part_integral(int i, double x)
double partial_integral(int i, double x)
const TSpline3 & spline() const
TRandom3 * m_rndm