Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooChi2Var.cxx
Go to the documentation of this file.
1 /*****************************************************************************
2  * Project: RooFit *
3  * Package: RooFitCore *
4  * @(#)root/roofitcore:$Id$
5  * Authors: *
6  * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7  * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8  * *
9  * Copyright (c) 2000-2005, Regents of the University of California *
10  * and Stanford University. All rights reserved. *
11  * *
12  * Redistribution and use in source and binary forms, *
13  * with or without modification, are permitted according to the terms *
14  * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15  *****************************************************************************/
16 
17 //////////////////////////////////////////////////////////////////////////////
18 /**
19 // \class RooChi2Var
20 // Class RooChi2Var implements a simple chi^2 calculation from a binned dataset
21 // and a PDF. It calculates
22 \f[
23  \chi^2 = \sum_{[\mathrm{bins}]} \left( \frac{(f_\mathrm{PDF} \cdot N_\mathrm{tot} / V_\mathrm{bin}) - N_\mathrm{bin}}{\mathrm{err}_\mathrm{bin}} \right)^2
24 \f]
25 // If no user-defined errors are defined for the dataset, poisson errors
26 // are used. In extended PDF mode, N_tot is substituted with N_expected.
27 //
28 */
29 
30 #include "RooFit.h"
31 
32 #include "RooChi2Var.h"
33 #include "RooChi2Var.h"
34 #include "RooDataHist.h"
35 #include "RooAbsPdf.h"
36 #include "RooCmdConfig.h"
37 #include "RooMsgService.h"
38 
39 #include "Riostream.h"
40 
41 #include "RooRealVar.h"
42 #include "RooAbsDataStore.h"
43 
44 
45 using namespace std;
46 
47 ClassImp(RooChi2Var);
48 ;
49 
50 RooArgSet RooChi2Var::_emptySet ;
51 
52 
53 ////////////////////////////////////////////////////////////////////////////////
54 /// RooChi2Var constructor. Optional arguments are:
55 /// \param[in] name Name of the PDF
56 /// \param[in] title Title for plotting etc.
57 /// \param[in] func Function
58 /// \param[in] hdata Data histogram
59 /// \param[in] argX Optional arguments according to table below.
60 /// <table>
61 /// <tr><th> Argument <th> Effect
62 /// <tr><td>
63 /// DataError() <td> Choose between Poisson errors and Sum-of-weights errors
64 /// <tr><td>
65 /// NumCPU() <td> Activate parallel processing feature
66 /// <tr><td>
67 /// Range() <td> Fit only selected region
68 /// <tr><td>
69 /// Verbose() <td> Verbose output of GOF framework
70 
71 RooChi2Var::RooChi2Var(const char *name, const char* title, RooAbsReal& func, RooDataHist& hdata,
72  const RooCmdArg& arg1,const RooCmdArg& arg2,const RooCmdArg& arg3,
73  const RooCmdArg& arg4,const RooCmdArg& arg5,const RooCmdArg& arg6,
74  const RooCmdArg& arg7,const RooCmdArg& arg8,const RooCmdArg& arg9) :
75  RooAbsOptTestStatistic(name,title,func,hdata,_emptySet,
76  RooCmdConfig::decodeStringOnTheFly("RooChi2Var::RooChi2Var","RangeWithName",0,"",arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9).c_str(),
77  0,
78  RooCmdConfig::decodeIntOnTheFly("RooChi2Var::RooChi2Var","NumCPU",0,1,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9),
79  RooFit::Interleave,
80  RooCmdConfig::decodeIntOnTheFly("RooChi2Var::RooChi2Var","Verbose",0,1,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9),
81  0)
82 {
83  RooCmdConfig pc("RooChi2Var::RooChi2Var") ;
84  pc.defineInt("etype","DataError",0,(Int_t)RooDataHist::Auto) ;
85  pc.defineInt("extended","Extended",0,kFALSE) ;
86  pc.allowUndefined() ;
87 
88  pc.process(arg1) ; pc.process(arg2) ; pc.process(arg3) ;
89  pc.process(arg4) ; pc.process(arg5) ; pc.process(arg6) ;
90  pc.process(arg7) ; pc.process(arg8) ; pc.process(arg9) ;
91 
92  if (func.IsA()->InheritsFrom(RooAbsPdf::Class())) {
93  _funcMode = pc.getInt("extended") ? ExtendedPdf : Pdf ;
94  } else {
95  _funcMode = Function ;
96  }
97  _etype = (RooDataHist::ErrorType) pc.getInt("etype") ;
98 
99  if (_etype==RooAbsData::Auto) {
100  _etype = hdata.isNonPoissonWeighted()? RooAbsData::SumW2 : RooAbsData::Expected ;
101  }
102 
103 }
104 
105 
106 
107 ////////////////////////////////////////////////////////////////////////////////
108 /// RooChi2Var constructor. Optional arguments taken
109 ///
110 /// \param[in] name Name of the PDF
111 /// \param[in] title Title for plotting etc.
112 /// \param[in] pdf PDF to fit
113 /// \param[in] hdata Data histogram
114 /// \param[in] argX Optional arguments according to table below.
115 /// <table>
116 /// <tr><th> Argument <th> Effect
117 /// <tr><td>
118 /// Extended() <td> Include extended term in calculation
119 /// <tr><td>
120 /// DataError() <td> Choose between Poisson errors and Sum-of-weights errors
121 /// <tr><td>
122 /// NumCPU() <td> Activate parallel processing feature
123 /// <tr><td>
124 /// Range() <td> Fit only selected region
125 /// <tr><td>
126 /// SumCoefRange() <td> Set the range in which to interpret the coefficients of RooAddPdf components
127 /// <tr><td>
128 /// SplitRange() <td> Fit range is split by index catory of simultaneous PDF
129 /// <tr><td>
130 /// ConditionalObservables() <td> Define projected observables
131 /// <tr><td>
132 /// Verbose() <td> Verbose output of GOF framework
133 
134 RooChi2Var::RooChi2Var(const char *name, const char* title, RooAbsPdf& pdf, RooDataHist& hdata,
135  const RooCmdArg& arg1,const RooCmdArg& arg2,const RooCmdArg& arg3,
136  const RooCmdArg& arg4,const RooCmdArg& arg5,const RooCmdArg& arg6,
137  const RooCmdArg& arg7,const RooCmdArg& arg8,const RooCmdArg& arg9) :
138  RooAbsOptTestStatistic(name,title,pdf,hdata,
139  *(const RooArgSet*)RooCmdConfig::decodeObjOnTheFly("RooChi2Var::RooChi2Var","ProjectedObservables",0,&_emptySet
140  ,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9),
141  RooCmdConfig::decodeStringOnTheFly("RooChi2Var::RooChi2Var","RangeWithName",0,"",arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9).c_str(),
142  RooCmdConfig::decodeStringOnTheFly("RooChi2Var::RooChi2Var","AddCoefRange",0,"",arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9).c_str(),
143  RooCmdConfig::decodeIntOnTheFly("RooChi2Var::RooChi2Var","NumCPU",0,1,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9),
144  RooFit::Interleave,
145  RooCmdConfig::decodeIntOnTheFly("RooChi2Var::RooChi2Var","Verbose",0,1,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9),
146  RooCmdConfig::decodeIntOnTheFly("RooChi2Var::RooChi2Var","SplitRange",0,0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9))
147 {
148  RooCmdConfig pc("RooChi2Var::RooChi2Var") ;
149  pc.defineInt("extended","Extended",0,kFALSE) ;
150  pc.defineInt("etype","DataError",0,(Int_t)RooDataHist::Auto) ;
151  pc.allowUndefined() ;
152 
153  pc.process(arg1) ; pc.process(arg2) ; pc.process(arg3) ;
154  pc.process(arg4) ; pc.process(arg5) ; pc.process(arg6) ;
155  pc.process(arg7) ; pc.process(arg8) ; pc.process(arg9) ;
156 
157  _funcMode = pc.getInt("extended") ? ExtendedPdf : Pdf ;
158  _etype = (RooDataHist::ErrorType) pc.getInt("etype") ;
159  if (_etype==RooAbsData::Auto) {
160  _etype = hdata.isNonPoissonWeighted()? RooAbsData::SumW2 : RooAbsData::Expected ;
161  }
162 }
163 
164 
165 
166 ////////////////////////////////////////////////////////////////////////////////
167 /// Constructor of a chi2 for given p.d.f. with respect given binned
168 /// dataset. If cutRange is specified the calculation of the chi2 is
169 /// restricted to that named range. If addCoefRange is specified, the
170 /// interpretation of fractions for all component RooAddPdfs that do
171 /// not have a frozen range interpretation is set to chosen range
172 /// name. If nCPU is greater than one the chi^2 calculation is
173 /// paralellized over the specified number of processors. If
174 /// interleave is true the partitioning of event over processors
175 /// follows a (i % n == i_set) strategy rather than a bulk
176 /// partitioning strategy which may result in unequal load balancing
177 /// in binned datasets with many (adjacent) zero bins. If
178 /// splitCutRange is true the cutRange is used to construct an
179 /// individual cutRange for each RooSimultaneous index category state
180 /// name cutRange_{indexStateName}.
181 
182 RooChi2Var::RooChi2Var(const char *name, const char *title, RooAbsPdf& pdf, RooDataHist& hdata,
183  Bool_t extended, const char* cutRange, const char* addCoefRange,
184  Int_t nCPU, RooFit::MPSplit interleave, Bool_t verbose, Bool_t splitCutRange, RooDataHist::ErrorType etype) :
185  RooAbsOptTestStatistic(name,title,pdf,hdata,RooArgSet(),cutRange,addCoefRange,nCPU,interleave,verbose,splitCutRange),
186  _etype(etype), _funcMode(extended?ExtendedPdf:Pdf)
187 {
188 }
189 
190 
191 
192 ////////////////////////////////////////////////////////////////////////////////
193 /// Constructor of a chi2 for given p.d.f. with respect given binned
194 /// dataset taking the observables specified in projDeps as projected
195 /// observables. If cutRange is specified the calculation of the chi2
196 /// is restricted to that named range. If addCoefRange is specified,
197 /// the interpretation of fractions for all component RooAddPdfs that
198 /// do not have a frozen range interpretation is set to chosen range
199 /// name. If nCPU is greater than one the chi^2 calculation is
200 /// paralellized over the specified number of processors. If
201 /// interleave is true the partitioning of event over processors
202 /// follows a (i % n == i_set) strategy rather than a bulk
203 /// partitioning strategy which may result in unequal load balancing
204 /// in binned datasets with many (adjacent) zero bins. If
205 /// splitCutRange is true the cutRange is used to construct an
206 /// individual cutRange for each RooSimultaneous index category state
207 /// name cutRange_{indexStateName}.
208 
209 RooChi2Var::RooChi2Var(const char *name, const char *title, RooAbsReal& func, RooDataHist& hdata,
210  const RooArgSet& projDeps, RooChi2Var::FuncMode fmode, const char* cutRange, const char* addCoefRange,
211  Int_t nCPU, RooFit::MPSplit interleave, Bool_t verbose, Bool_t splitCutRange, RooDataHist::ErrorType etype) :
212  RooAbsOptTestStatistic(name,title,func,hdata,projDeps,cutRange,addCoefRange,nCPU,interleave,verbose,splitCutRange),
213  _etype(etype), _funcMode(fmode)
214 {
215 }
216 
217 
218 
219 ////////////////////////////////////////////////////////////////////////////////
220 /// Copy constructor
221 
222 RooChi2Var::RooChi2Var(const RooChi2Var& other, const char* name) :
223  RooAbsOptTestStatistic(other,name),
224  _etype(other._etype),
225  _funcMode(other._funcMode)
226 {
227 }
228 
229 
230 
231 ////////////////////////////////////////////////////////////////////////////////
232 /// Destructor
233 
234 RooChi2Var::~RooChi2Var()
235 {
236 }
237 
238 
239 
240 ////////////////////////////////////////////////////////////////////////////////
241 /// Calculate chi^2 in partition from firstEvent to lastEvent using given stepSize
242 
243 Double_t RooChi2Var::evaluatePartition(std::size_t firstEvent, std::size_t lastEvent, std::size_t stepSize) const
244 {
245  // Throughout the calculation, we use Kahan's algorithm for summing to
246  // prevent loss of precision - this is a factor four more expensive than
247  // straight addition, but since evaluating the PDF is usually much more
248  // expensive than that, we tolerate the additional cost...
249  Double_t result(0), carry(0);
250 
251  _dataClone->store()->recalculateCache( _projDeps, firstEvent, lastEvent, stepSize, kFALSE) ;
252 
253 
254  // Determine normalization factor depending on type of input function
255  Double_t normFactor(1) ;
256  switch (_funcMode) {
257  case Function: normFactor=1 ; break ;
258  case Pdf: normFactor = _dataClone->sumEntries() ; break ;
259  case ExtendedPdf: normFactor = ((RooAbsPdf*)_funcClone)->expectedEvents(_dataClone->get()) ; break ;
260  }
261 
262  // Loop over bins of dataset
263  RooDataHist* hdata = (RooDataHist*) _dataClone ;
264  for (auto i=firstEvent ; i<lastEvent ; i+=stepSize) {
265 
266  // get the data values for this event
267  hdata->get(i);
268 
269  if (!hdata->valid()) continue;
270 
271  const Double_t nData = hdata->weight() ;
272 
273  const Double_t nPdf = _funcClone->getVal(_normSet) * normFactor * hdata->binVolume() ;
274 
275  const Double_t eExt = nPdf-nData ;
276 
277 
278  Double_t eInt ;
279  if (_etype != RooAbsData::Expected) {
280  Double_t eIntLo,eIntHi ;
281  hdata->weightError(eIntLo,eIntHi,_etype) ;
282  eInt = (eExt>0) ? eIntHi : eIntLo ;
283  } else {
284  eInt = sqrt(nPdf) ;
285  }
286 
287  // Skip cases where pdf=0 and there is no data
288  if (0. == eInt * eInt && 0. == nData * nData && 0. == nPdf * nPdf) continue ;
289 
290  // Return 0 if eInt=0, special handling in MINUIT will follow
291  if (0. == eInt * eInt) {
292  coutE(Eval) << "RooChi2Var::RooChi2Var(" << GetName() << ") INFINITY ERROR: bin " << i
293  << " has zero error" << endl ;
294  return 0.;
295  }
296 
297 // cout << "Chi2Var[" << i << "] nData = " << nData << " nPdf = " << nPdf << " errorExt = " << eExt << " errorInt = " << eInt << " contrib = " << eExt*eExt/(eInt*eInt) << endl ;
298 
299  Double_t term = eExt*eExt/(eInt*eInt) ;
300  Double_t y = term - carry;
301  Double_t t = result + y;
302  carry = (t - result) - y;
303  result = t;
304  }
305 
306  _evalCarry = carry;
307  return result ;
308 }
309 
310 
311