Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooXYChi2Var.cxx
Go to the documentation of this file.
1/// \cond ROOFIT_INTERNAL
2
3/*****************************************************************************
4 * Project: RooFit *
5 * Package: RooFitCore *
6 * @(#)root/roofitcore:$Id$
7 * Authors: *
8 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
9 * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
10 * *
11 * Copyright (c) 2000-2005, Regents of the University of California *
12 * and Stanford University. All rights reserved. *
13 * *
14 * Redistribution and use in source and binary forms, *
15 * with or without modification, are permitted according to the terms *
16 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
17 *****************************************************************************/
18
19//////////////////////////////////////////////////////////////////////////////
20/// \class RooXYChi2Var
21/// RooXYChi2Var implements a simple chi^2 calculation from an unbinned
22/// dataset with values x,y with errors on y (and optionally on x) and a function.
23/// The function can be either a RooAbsReal, or an extended RooAbsPdf where
24/// the function value is calculated as the probability density times the
25/// expected number of events.
26/// The chi^2 is calculated as
27/// ```
28///
29/// / (Data[y]-) - func \+2
30/// Sum[point] | ------------------ |
31/// \ Data[ErrY] /
32/// ```
33///
34
35#include "RooXYChi2Var.h"
36#include "RooDataSet.h"
37#include "RooAbsReal.h"
38
39#include "Riostream.h"
40
41#include "RooRealVar.h"
42
43#include "RooAbsDataStore.h"
44#include "RooRealBinding.h"
45#include "RooNumIntFactory.h"
46
47using std::endl;
48
49namespace {
50 RooAbsTestStatistic::Configuration makeRooAbsTestStatisticCfg() {
51 RooAbsTestStatistic::Configuration cfg;
52 cfg.verbose = false;
53 return cfg;
54 }
55}
56
57
58////////////////////////////////////////////////////////////////////////////////
59///
60/// RooXYChi2Var constructor with function and X-Y values dataset
61///
62/// If the function is a pdf, it must be extendable. in this case, hhe value of
63/// the function that defines the chi^2 in this form is takes as the p.d.f.
64/// times the expected number of events
65///
66/// An X-Y dataset is a weighted dataset with one or more observables X where the weight is interpreted
67/// as the Y value and the weight error is interpreted as the Y value error. The weight must have an
68/// non-zero error defined at each point for the chi^2 calculation to be meaningful.
69///
70/// To store errors associated with the x and y values in a RooDataSet, call RooRealVar::setAttribute("StoreError")
71/// on each X-type observable for which the error should be stored and add datapoints to the dataset as follows
72///
73/// RooDataSet::add(xset,yval,yerr) where xset is the RooArgSet of x observables (with or without errors) and yval and yerr
74/// are the double values that correspond to the Y and its error
75///
76
77RooXYChi2Var::RooXYChi2Var(const char *name, const char *title, RooAbsReal &func, RooDataSet &xydata, bool integrate)
78 : RooXYChi2Var{name, title, func, xydata, nullptr, integrate, makeRooAbsTestStatisticCfg()}
79{
80}
81
82////////////////////////////////////////////////////////////////////////////////
83///
84/// RooXYChi2Var constructor with function and X-Y values dataset.
85///
86/// If the function is a pdf, it must be extendable. in this case, hhe value of
87/// the function that defines the chi^2 in this form is takes as the p.d.f.
88/// times the expected number of events
89///
90/// An X-Y dataset is a weighted dataset with one or more observables X where given yvar is interpreted
91/// as the Y value. The Y variable must have a non-zero error defined at each point for the chi^2 calculation to be meaningful.
92///
93/// To store errors associated with the x and y values in a RooDataSet, call RooRealVar::setAttribute("StoreError")
94/// on each X-type observable for which the error should be stored and add datapoints to the dataset as follows
95///
96/// RooDataSet::add(xset,yval,yerr) where xset is the RooArgSet of x observables (with or without errors) and yval and yerr
97/// are the double values that correspond to the Y and its error
98///
99
100RooXYChi2Var::RooXYChi2Var(const char *name, const char *title, RooAbsReal &func, RooDataSet &xydata, RooRealVar &yvar,
101 bool integrate)
102 : RooXYChi2Var{name, title, func, xydata, &yvar, integrate, makeRooAbsTestStatisticCfg()}
103{
104}
105
106
107/// \cond ROOFIT_INTERNAL
108// For internal use in RooAbsReal::createChi2().
109RooXYChi2Var::RooXYChi2Var(const char *name, const char *title, RooAbsReal &func, RooAbsData &data, RooRealVar *yvar,
110 bool integrate, RooAbsTestStatistic::Configuration const &cfg)
111 : RooAbsOptTestStatistic(name, title, func, data, RooArgSet(), cfg),
112 _integrate(integrate),
113 _intConfig(*defaultIntegratorConfig())
114{
115 bool isPdf = dynamic_cast<RooAbsPdf const *>(&func) != nullptr;
116
117 if (isPdf) {
118 auto &extPdf = static_cast<RooAbsPdf const &>(func);
119 if (!extPdf.canBeExtended()) {
120 throw std::runtime_error(
121 Form("RooXYChi2Var::RooXYChi2Var(%s) ERROR: Input p.d.f. must be extendable", GetName()));
122 }
123 }
124
125 _extended = isPdf;
126 _yvar = yvar ? static_cast<RooRealVar *>(_dataClone->get()->find(yvar->GetName())) : nullptr;
127
128 initialize();
129}
130/// \endcond ROOFIT_INTERNAL
131
132
133////////////////////////////////////////////////////////////////////////////////
134/// Copy constructor
135
136RooXYChi2Var::RooXYChi2Var(const RooXYChi2Var &other, const char *name)
137 : RooAbsOptTestStatistic(other, name),
138 _extended(other._extended),
140 _yvar(other._yvar ? static_cast<RooRealVar *>(_dataClone->get()->find(other._yvar->GetName())) : nullptr),
142{
143
144 initialize() ;
145
146}
147
148
149////////////////////////////////////////////////////////////////////////////////
150/// Common constructor initialization
151
152void RooXYChi2Var::initialize()
153{
154 // If this tests statistic is not a "Slave" in the RooAbsOptTestStatistic
155 // framework, it doesn't do any actual computation and no initialization is
156 // needed. It would not even work, because _funcObsSet would be a nullptr.
157 if(operMode() != Slave) return;
158
159 for(RooAbsArg * arg : *_funcObsSet) {
160 if (auto* var = dynamic_cast<RooRealVar*>(arg)) {
161 _rrvArgs.add(*var) ;
162 }
163 }
164 if (_yvar) {
165 _rrvArgs.add(*_yvar) ;
166 }
167
168 // Define alternate numeric integrator configuration for bin integration
169 // We expect bin contents to very only very slowly so a non-adaptive
170 // Gauss-Kronrod integrator is expected to perform well (if RooFitMore is available)
171 _intConfig.setEpsRel(1e-7) ;
172 _intConfig.setEpsAbs(1e-7) ;
173#ifdef R__HAS_MATHMORE
174 _intConfig.method1D().setLabel("RooGaussKronrodIntegrator1D") ;
175#endif
176 _intConfig.methodND().setLabel("RooAdaptiveIntegratorND") ;
177
179
180}
181
182
183
184////////////////////////////////////////////////////////////////////////////////
185/// Initialize bin content integrator
186
187void RooXYChi2Var::initIntegrator()
188{
189 if (!_funcInt) {
190 _funcInt = std::unique_ptr<RooAbsReal>{_funcClone->createIntegral(_rrvArgs,_rrvArgs,_intConfig,"bin")};
191 for(auto * x : static_range_cast<RooRealVar*>(_rrvArgs)) {
192 _binList.push_back(&x->getBinning("bin",false,true)) ;
193 }
194 }
195
196}
197
198
199RooXYChi2Var::~RooXYChi2Var() = default;
200
201
202////////////////////////////////////////////////////////////////////////////////
203/// Calculate contribution to internal error due to error on 'x' coordinates
204/// at point i
205
206double RooXYChi2Var::xErrorContribution(double ydata) const
207{
208 double ret(0) ;
209
210 for(auto * var : static_range_cast<RooRealVar*>(_rrvArgs)) {
211
212 if (var->hasAsymError()) {
213
214 // Get value at central X
215 double cxval = var->getVal() ;
216 double xerrLo = -var->getAsymErrorLo() ;
217 double xerrHi = var->getAsymErrorHi() ;
218 double xerr = (xerrLo+xerrHi)/2 ;
219
220 // Get value at X-eps
221 var->setVal(cxval - xerr/100) ;
222 double fxmin = fy() ;
223
224 // Get value at X+eps
225 var->setVal(cxval + xerr/100) ;
226 double fxmax = fy() ;
227
228 // Calculate slope
229 double slope = (fxmax-fxmin)/(2*xerr/100.) ;
230
231// std::cout << "xerrHi = " << xerrHi << " xerrLo = " << xerrLo << " slope = " << slope << std::endl ;
232
233 // Asymmetric X error, decide which one to use
234 if ((ydata>cxval && fxmax>fxmin) || (ydata<=cxval && fxmax<=fxmin)) {
235 // Use right X error
236 ret += pow(xerrHi*slope,2) ;
237 } else {
238 // Use left X error
239 ret += pow(xerrLo*slope,2) ;
240 }
241
242 } else if (var->hasError()) {
243
244 // Get value at central X
245 double cxval = var->getVal() ;
246 double xerr = var->getError() ;
247
248 // Get value at X-eps
249 var->setVal(cxval - xerr/100) ;
250 double fxmin = fy() ;
251
252 // Get value at X+eps
253 var->setVal(cxval + xerr/100) ;
254 double fxmax = fy() ;
255
256 // Calculate slope
257 double slope = (fxmax-fxmin)/(2*xerr/100.) ;
258
259// std::cout << var << " " ;
260// var->Print() ;
261
262// std::cout << var->GetName() << " xerr = " << xerr << " slope = " << slope << std::endl ;
263
264 // Symmetric X error
265 ret += pow(xerr*slope,2) ;
266 }
267 }
268 return ret ;
269}
270
271
272
273
274////////////////////////////////////////////////////////////////////////////////
275/// Return function value requested bu present configuration
276///
277/// If integration is required, the function value integrated
278/// over the bin volume divided by the bin volume is returned,
279/// otherwise the value at the bin center is returned.
280/// The bin volume is defined by the error on the 'X' coordinates
281///
282/// If an extended p.d.f. is used as function, its value is
283/// also multiplied by the expected number of events here
284
285double RooXYChi2Var::fy() const
286{
287 // Get function value
288 double yfunc ;
289 if (!_integrate) {
290 yfunc = _funcClone->getVal(_dataClone->get()) ;
291 } else {
292 double volume(1) ;
293 auto rrvIter = _rrvArgs.begin();
294 for (auto iter = _binList.begin() ; iter != _binList.end() ; ++iter) {
295 auto* x = static_cast<RooRealVar*>(*rrvIter);
296 double xmin = x->getVal() + x->getErrorLo() ;
297 double xmax = x->getVal() + x->getErrorHi() ;
298 (*iter)->setRange(xmin,xmax) ;
299 x->setShapeDirty() ;
300 volume *= (xmax - xmin) ;
301 ++rrvIter;
302 }
303 double ret = _funcInt->getVal() ;
304 return ret / volume ;
305 }
306 if (_extended) {
307 RooAbsPdf* pdf = static_cast<RooAbsPdf*>(_funcClone) ;
308 // Multiply with expected number of events
309 yfunc *= pdf->expectedEvents(_dataClone->get()) ;
310 }
311 return yfunc ;
312}
313
314
315
316////////////////////////////////////////////////////////////////////////////////
317/// Calculate chi^2 in partition from firstEvent to lastEvent using given stepSize
318
319double RooXYChi2Var::evaluatePartition(std::size_t firstEvent, std::size_t lastEvent, std::size_t stepSize) const
320{
321 double result(0);
322 double carry(0);
323
324 // Loop over bins of dataset
325 RooDataSet* xydata = static_cast<RooDataSet*>(_dataClone) ;
326
327 for (auto i=firstEvent ; i<lastEvent ; i+=stepSize) {
328
329 // get the data values for this event
330 xydata->get(i);
331
332 // Get function value
333 double yfunc = fy() ;
334
335 // Get data value and error
336 double ydata ;
337 double eylo;
338 double eyhi;
339 if (_yvar) {
340 ydata = _yvar->getVal() ;
341 eylo = -1*_yvar->getErrorLo() ;
342 eyhi = _yvar->getErrorHi() ;
343 } else {
344 ydata = xydata->weight() ;
345 xydata->weightError(eylo,eyhi) ;
346 }
347
348 // Calculate external error
349 double eExt = yfunc-ydata ;
350
351 // Pick upper or lower error bar depending on sign of external error
352 double eInt = (eExt>0) ? eyhi : eylo ;
353
354 // Add contributions due to error in x coordinates
355 double eIntX2 = _integrate ? 0 : xErrorContribution(ydata) ;
356
357// std::cout << "fy = " << yfunc << " eExt = " << eExt << " eInt = " << eInt << " eIntX2 = " << eIntX2 << std::endl ;
358
359 // Return 0 if eInt=0, special handling in MINUIT will follow
360 if (eInt==0.) {
361 coutE(Eval) << "RooXYChi2Var::RooXYChi2Var(" << GetName() << ") INFINITY ERROR: data point " << i
362 << " has zero error, but function is not zero (f=" << yfunc << ")" << std::endl ;
363 return 0 ;
364 }
365
366 // Add chi2 term
367 double term = eExt*eExt/(eInt*eInt+ eIntX2);
368 double y = term - carry;
369 double t = result + y;
370 carry = (t - result) - y;
371 result = t;
372 }
373
374 _evalCarry = carry;
375 return result ;
376}
377
378
379
380RooArgSet RooXYChi2Var::requiredExtraObservables() const
381{
382 // Inform base class that observable yvar cannot be optimized away from the dataset
383 if (_yvar) return RooArgSet(*_yvar) ;
384 return RooArgSet() ;
385}
386
387/// \endcond
#define e(i)
Definition RSha256.hxx:103
ROOT::RRangeCast< T, false, Range_t > static_range_cast(Range_t &&coll)
#define coutE(a)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
char name[80]
Definition TGX11.cxx:110
float xmin
float xmax
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2489
const_iterator begin() const
const_iterator end() const
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:77
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:57
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:40
virtual double expectedEvents(const RooArgSet *nset) const
Return expected number of events to be used in calculation of extended likelihood.
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:59
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
Container class to hold unbinned data.
Definition RooDataSet.h:34
Variable that can be changed from the outside.
Definition RooRealVar.h:37
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const UInt_t eInt[256]
void initialize(typename Architecture_t::Matrix_t &A, EInitialization m)
Definition Functions.h:282