MINT2
RooCubicSplineFun.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  * Project: RooFit *
3  * Package: RooFitModels *
4  * @(#)root/roofit:$Id: RooBSpline.cxx 45780 2012-08-31 15:45:27Z moneta $
5  * Authors: *
6  * Gerhard Raven
7  * *
8  *****************************************************************************/
9 
11 //
12 // BEGIN_HTML
13 // BSpline basis polynomials are positive-definite in the range [0,1].
14 // In this implementation, we extend [0,1] to be the range of the parameter.
15 // There are n+1 BSpline basis polynomials of degree n.
16 // Thus, by providing N coefficients that are positive-definite, there
17 // is a natural way to have well bahaved polynomail PDFs.
18 // For any n, the n+1 basis polynomials 'form a partition of unity', eg.
19 // they sum to one for all values of x. See
20 // END_HTML
21 //
22 // STD & STL
23 #include <cmath>
24 #include <complex>
25 #include <sstream>
26 
27 // ROOT
28 #include "TH1.h"
29 #include "TGraph.h"
30 #include "TGraphErrors.h"
31 
32 // RooFit
33 #include "RooMsgService.h"
34 #include "RooMath.h"
35 #include "RooAbsReal.h"
36 #include "RooRealVar.h"
37 #include "RooConstVar.h"
38 #include "RooArgList.h"
39 
40 // P2VV
41 #include "Mint/RooCubicSplineFun.h"
43 
44 using namespace std;
45 
46 //ClassImp(RooCubicSplineFun);
47 
48 //_____________________________________________________________________________
49 void RooCubicSplineFun::init(const char* name,
50  const vector<double>& heights,
51  const vector<double>& errors,
52  double smooth, bool constCoeffs) {
53  vector<double> values(heights);
54  if ( smooth > 0 ) {
55  assert(int(errors.size()) == _aux.size());
56  _aux.smooth( values, errors, smooth );
57  }
58  _aux.computeCoefficients( values );
59  for (unsigned int i=0;i<values.size();++i) {
60  if (constCoeffs) {
61  _coefList.add( RooFit::RooConst( values[i] ) );
62  } else {
63  stringstream name_str;
64  name_str << name << "_bin_" << i;
65  string n(name_str.str());
66  RooRealVar* coeff = new RooRealVar(n.c_str(), n.c_str(), values[i], 0.0, 10.0);
67 // if (i == 0 || i == values.size() - 1) coeff->setConstant(true);
68  if (i == values.size() - 2){
69  coeff->setVal(1.0);
70  coeff->setConstant(true);
71  }
72  _coefList.add(*coeff);
73  addOwnedComponents( *coeff );
74  }
75  }
76 }
77 
78 //_____________________________________________________________________________
80  : _aux(0,0)
81 {
82 }
83 
84 //_____________________________________________________________________________
85 RooCubicSplineFun::RooCubicSplineFun(const char* name, const char* title, RooRealVar& x,
86  const vector<double>& knots,
87  const vector<double>& values,
88  const vector<double>& errors,
89  double smooth, bool constCoeffs) :
90  RooAbsGaussModelEfficiency(name, title),
91  _x("x", "Dependent", this, x),
92  _coefList("coefficients","List of coefficients",this),
93  _aux(knots.begin(),knots.end())
94 {
95  init(name, values, errors, smooth, constCoeffs);
96 }
97 
98 //_____________________________________________________________________________
99 RooCubicSplineFun::RooCubicSplineFun(const char* name, const char* title,
100  RooRealVar& x, const TGraph* graph, bool constCoeffs) :
101  RooAbsGaussModelEfficiency(name, title),
102  _x("x", "Dependent", this, x),
103  _coefList("coefficients","List of coefficients",this),
104  _aux(0,0)
105 {
106  int nPoints = graph->GetN();
107  vector<double> centres, values;
108  for (int i=0;i<nPoints ;++i) {
109  double x,y;
110  graph->GetPoint(i,x,y);
111  centres.push_back(x);
112  values.push_back(y);
113  }
114  _aux = RooCubicSplineKnot( centres.begin(), centres.end() );
115  vector<double> errs;
116  init(name, values, errs, 0, constCoeffs);
117 }
118 
119 //_____________________________________________________________________________
120 RooCubicSplineFun::RooCubicSplineFun(const char* name, const char* title,
121  RooRealVar& x, const TH1* hist, double smooth,
122  bool constCoeffs) :
123  RooAbsGaussModelEfficiency(name, title),
124  _x("x", "Dependent", this, x),
125  _coefList("coefficients","List of coefficients",this),
126  _aux(0,0)
127 {
128  // bin 0 is underflow, and bin nBins + 1 is overflow...
129  int nBins = hist->GetNbinsX();
130  vector<double> centres, values;
131  for (int i=0;i<nBins ;++i) {
132  centres.push_back(hist->GetBinCenter(1+i));
133  values.push_back(hist->GetBinContent(1+i));
134  }
135  _aux = RooCubicSplineKnot( centres.begin(), centres.end() );
136 
137  vector<double> errs;
138  if (smooth>0) for (int i=0;i<nBins ;++i) errs.push_back(hist->GetBinError(1+i));
139 
140  init(name, values, errs, smooth, constCoeffs);
141 }
142 //_____________________________________________________________________________
143 RooCubicSplineFun::RooCubicSplineFun(const char* name, const char* title,
144  RooRealVar& x, const TGraphErrors* graph, double smooth,
145  bool constCoeffs) :
146  RooAbsGaussModelEfficiency(name, title),
147  _x("x", "Dependent", this, x),
148  _coefList("coefficients","List of coefficients",this),
149  _aux(0,0)
150 {
151  int nPoints = graph->GetN();
152  vector<double> centres, values;
153  for (int i=0;i<nPoints ;++i) {
154  double x,y;
155  graph->GetPoint(i,x,y);
156  centres.push_back(x);
157  values.push_back(y);
158  }
159  _aux = RooCubicSplineKnot( centres.begin(), centres.end() );
160 
161  vector<double> errs;
162  if (smooth>0) for (int i=0;i<nPoints ;++i) errs.push_back(graph->GetErrorY(i));
163 
164  init(name, values, errs, smooth, constCoeffs);
165 }
166 
167 //_____________________________________________________________________________
168 RooCubicSplineFun::RooCubicSplineFun(const char* name, const char* title,
169  RooRealVar& x, const char* knotBinningName,
170  const RooArgList& coefList):
171  RooAbsGaussModelEfficiency(name, title),
172  _x("x", "Dependent", this, x),
173  _coefList("coefficients", "List of coefficients", this),
174  _aux(0,0)
175 {
176  // TODO: verify coefList is consistent with knots as specified by the knotBinningName binning
177  // should be N+2 coefficients for N bins...
178  const RooAbsBinning* binning = x.getBinningPtr(knotBinningName);
179  assert( binning!=0);
180  if ( coefList.getSize()!=2+binning->numBoundaries()) {
181  cout << TString::Format( "you have specified %d coefficients for %d knots. The differentce should 2!",coefList.getSize(),binning->numBoundaries()) << endl;
182  throw TString::Format( "you have specified %d coefficients for %d knots. The differentce should 2!",coefList.getSize(),binning->numBoundaries());
183  }
184  _coefList.add(coefList);
185 
186  Double_t* boundaries = binning->array();
187  _aux = RooCubicSplineKnot( boundaries, boundaries + binning->numBoundaries() );
188 }
189 
190 //_____________________________________________________________________________
191 RooCubicSplineFun::RooCubicSplineFun(const char* name, const char* title,
192  RooRealVar& x, const vector<double>& knots,
193  const RooArgList& coefList):
194  RooAbsGaussModelEfficiency(name, title),
195  _x("x", "Dependent", this, x),
196  _coefList("coefficients", "List of coefficients", this),
197  _aux(knots.begin(), knots.end())
198 {
199  assert(size_t(coefList.getSize()) == 2 + knots.size());
200  _coefList.add(coefList);
201 }
202 
203 //_____________________________________________________________________________
205  RooAbsGaussModelEfficiency(other, name),
206  _x("x", this, other._x),
207  _coefList("coefList", this, other._coefList),
208  _aux(other._aux)
209 {
210 }
211 
212 //_____________________________________________________________________________
214 {
215 }
216 
217 //_____________________________________________________________________________
219 {
220  return _aux.evaluate(_x,_coefList);
221 }
222 
223 //_____________________________________________________________________________
224 Int_t RooCubicSplineFun::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* rangeName) const
225 {
226  // No analytical calculation available (yet) of integrals over subranges
227  if (_x.min(rangeName)!=_aux.knots().front() || _x.max(rangeName)!=_aux.knots().back() ) return 0;
228  if (matchArgs(allVars, analVars, _x)) return 1;
229  return 0;
230 }
231 //_____________________________________________________________________________
232 Double_t RooCubicSplineFun::analyticalIntegral(Int_t code, const char* /* rangeName */) const
233 {
234  if (code != 1) {
235  coutE(InputArguments) << "RooCubicSplineFun::analyticalIntegral(" << GetName()
236  << "): argument \"code\" can only have value 1" << std::endl;
237  assert(code==1) ;
238  }
240 }
241 
242 //_____________________________________________________________________________
244  const RooGaussModelAcceptance::K_n& K, double offset,
245  double* sc) const
246 {
247  RooCubicSplineKnot::S_edge s_jk( _aux.S_jk_edge( left, _coefList ), offset );
248  return dM(0)*( s_jk(0,0) * K(0) * sc[0] + s_jk(0,1) * K(1) * sc[1] )
249  + dM(1)*( s_jk(1,0) * K(0) * sc[1] );
250 }
251 
252 //_____________________________________________________________________________
253 std::complex<double>
254 RooCubicSplineFun::productAnalyticalIntegral(Double_t umin, Double_t umax,
255  Double_t scale, Double_t offset,
256  const std::complex<double>& z) const
257 {
259  assert(knotSize()>1);
260  double lo = scale*umin+offset;
261  double hi = scale*umax+offset+1.e-7;
263  std::vector<M_n> M; M.reserve( knotSize() );
264  for (unsigned int i=0;i<knotSize();++i) {
265  double x = (u(i)-offset)/scale ;
266  // TODO: remove unnecessary calculation of integral (that gives 0) if lo>u(i) and/or u(i+1)<hi
267  if (lo>=u(i)) x = umin ; // take M[i] if lo<=u(i) else M_n(lo)
268  if (u(i)>=hi) x = umax ; // take M[i+1] if u(i+1)<=hi else M_n(hi)
269  M.push_back( M_n( x, z ) );
270  }
271  double sc[4]; for (int i=0;i<4;++i) sc[i] = pow(scale,i);
272  std::complex<double> sum(0,0);
273  if (lo<u(0)) sum += gaussIntegralE(true, M.front()-M_n( umin,z), K, offset, sc);
274  for (unsigned i=0;i<knotSize()-1 && u(i)<hi ;++i) {
275  M_n dM = M[i+1]-M[i];
276  RooCubicSplineKnot::S_jk s_jk( _aux.S_jk_sum( i, _coefList ), offset ); // pass sc into S_jk, remove from loop
277  for (int j=0;j<4;++j) for (int k=0;k<4-j;++k) sum += dM(j)*s_jk(j,k)*K(k)*sc[j+k];
278  }
279  if (hi>u(knotSize()-1)) sum += gaussIntegralE(false, M_n(umax,z)-M.back(), K, offset, sc);
280  return sum;
281 }
282 
283 //_____________________________________________________________________________
284 Int_t RooCubicSplineFun::getMaxVal(const RooArgSet& vars) const
285 {
286  // check that vars only contains _x...
287  return ( vars.getSize() == 1 && vars.contains( _x.arg() ) ) ? 1 : 0;
288 }
289 //_____________________________________________________________________________
290 Double_t RooCubicSplineFun::maxVal(Int_t code) const
291 {
292  if (code != 1) {
293  coutE(InputArguments) << "RooCubicSplineFun::maxVal(" << GetName()
294  << "): argument \"code\" can only have value 1" << std::endl;
295  assert(code==1) ;
296  }
297  RooFIter iter = _coefList.fwdIterator();
298  RooAbsReal *c(0);
299  double res = 0;
300  while((c=(RooAbsReal*)iter.next())) {
301  double x = fabs(c->getVal());
302  if (x>res) { res = x; }
303  }
304  return res;
305 }
double u(int i) const
RooCubicSplineKnot::S_jk S_jk_sum(int i, const RooArgList &b) const
RooCubicSplineKnot::S_edge S_jk_edge(bool left, const RooArgList &b) const
Int_t getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &analVars, const char *rangeName) const
Double_t evaluate() const
double analyticalIntegral(const RooArgList &b) const
void init(const char *name, const std::vector< double > &heights, const std::vector< double > &errors, double smooth, bool constCoeffs)
const std::vector< double > & knots() const
unsigned knotSize() const
Double_t analyticalIntegral(Int_t code, const char *rangeName) const
const std::vector< double > & knots() const
Int_t getMaxVal(const RooArgSet &vars) const
double evaluate(double _u, const RooArgList &b) const
std::complex< double > gaussIntegralE(bool left, const RooGaussModelAcceptance::M_n< 4U > &dM, const RooGaussModelAcceptance::K_n &K, double offset, double *sc) const
RooCubicSplineKnot _aux
RooListProxy _coefList
std::complex< double > productAnalyticalIntegral(Double_t umin, Double_t umax, Double_t scale, Double_t offset, const std::complex< double > &z) const
Double_t maxVal(Int_t code) const