Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooXYChi2Var.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/// \class RooXYChi2Var
19/// RooXYChi2Var implements a simple chi^2 calculation from an unbinned
20/// dataset with values x,y with errors on y (and optionally on x) and a function.
21/// The function can be either a RooAbsReal, or an extended RooAbsPdf where
22/// the function value is calculated as the probability density times the
23/// expected number of events.
24/// The chi^2 is calculated as
25/// ```
26///
27/// / (Data[y]-) - func \+2
28/// Sum[point] | ------------------ |
29/// \ Data[ErrY] /
30/// ```
31///
32
33#include "RooXYChi2Var.h"
34#include "RooDataSet.h"
35#include "RooAbsReal.h"
36
37#include "Riostream.h"
38
39#include "RooRealVar.h"
40
41#include "RooAbsDataStore.h"
42#include "RooRealBinding.h"
43#include "RooNumIntFactory.h"
44
45#include <stdexcept>
46
47using namespace std;
48
50;
51
52namespace {
53 RooAbsTestStatistic::Configuration makeRooAbsTestStatisticCfg() {
55 cfg.verbose = false;
56 return cfg;
57 }
58}
59
60
61////////////////////////////////////////////////////////////////////////////////
62/// coverity[UNINIT_CTOR]
63
65{
66}
67
68
69////////////////////////////////////////////////////////////////////////////////
70///
71/// RooXYChi2Var constructor with function and X-Y values dataset
72///
73/// An X-Y dataset is a weighted dataset with one or more observables X where the weight is interpreted
74/// as the Y value and the weight error is interpreted as the Y value error. The weight must have an
75/// non-zero error defined at each point for the chi^2 calculation to be meaningful.
76///
77/// To store errors associated with the x and y values in a RooDataSet, call RooRealVar::setAttribute("StoreError")
78/// on each X-type observable for which the error should be stored and add datapoints to the dataset as follows
79///
80/// RooDataSet::add(xset,yval,yerr) where xset is the RooArgSet of x observables (with or without errors) and yval and yerr
81/// are the double values that correspond to the Y and its error
82///
83
84RooXYChi2Var::RooXYChi2Var(const char *name, const char* title, RooAbsReal& func, RooDataSet& xydata, bool integrate) :
85 RooAbsOptTestStatistic(name,title,func,xydata,RooArgSet(),makeRooAbsTestStatisticCfg()),
86 _extended(false),
87 _integrate(integrate),
88 _intConfig(*defaultIntegratorConfig())
89{
90 _extended = false ;
91 _yvar = 0 ;
92
93 initialize() ;
94}
95
96
97////////////////////////////////////////////////////////////////////////////////
98///
99/// RooXYChi2Var constructor with function and X-Y values dataset
100///
101/// An X-Y dataset is a weighted dataset with one or more observables X where given yvar is interpreted
102/// 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.
103///
104/// To store errors associated with the x and y values in a RooDataSet, call RooRealVar::setAttribute("StoreError")
105/// on each X-type observable for which the error should be stored and add datapoints to the dataset as follows
106///
107/// RooDataSet::add(xset,yval,yerr) where xset is the RooArgSet of x observables (with or without errors) and yval and yerr
108/// are the double values that correspond to the Y and its error
109///
110
111RooXYChi2Var::RooXYChi2Var(const char *name, const char* title, RooAbsReal& func, RooDataSet& xydata, RooRealVar& yvar, bool integrate) :
112 RooAbsOptTestStatistic(name,title,func,xydata,RooArgSet(),makeRooAbsTestStatisticCfg()),
113 _extended(false),
114 _integrate(integrate),
115 _intConfig(*defaultIntegratorConfig())
116{
117 _extended = false ;
118 _yvar = (RooRealVar*) _dataClone->get()->find(yvar.GetName()) ;
119
120 initialize() ;
121}
122
123
124////////////////////////////////////////////////////////////////////////////////
125///
126/// RooXYChi2Var constructor with an extended p.d.f. and X-Y values dataset
127/// The value of the function that defines the chi^2 in this form is takes as
128/// the p.d.f. times the expected number of events
129///
130/// An X-Y dataset is a weighted dataset with one or more observables X where the weight is interpreted
131/// as the Y value and the weight error is interpreted as the Y value error. The weight must have an
132/// non-zero error defined at each point for the chi^2 calculation to be meaningful.
133///
134/// To store errors associated with the x and y values in a RooDataSet, call RooRealVar::setAttribute("StoreError")
135/// on each X-type observable for which the error should be stored and add datapoints to the dataset as follows
136///
137/// RooDataSet::add(xset,yval,yerr) where xset is the RooArgSet of x observables (with or without errors) and yval and yerr
138/// are the double values that correspond to the Y and its error
139///
140
141RooXYChi2Var::RooXYChi2Var(const char *name, const char* title, RooAbsPdf& extPdf, RooDataSet& xydata, bool integrate) :
142 RooAbsOptTestStatistic(name,title,extPdf,xydata,RooArgSet(),makeRooAbsTestStatisticCfg()),
143 _extended(true),
144 _integrate(integrate),
145 _intConfig(*defaultIntegratorConfig())
146{
147 if (!extPdf.canBeExtended()) {
148 throw std::runtime_error(Form("RooXYChi2Var::RooXYChi2Var(%s) ERROR: Input p.d.f. must be extendible",GetName()));
149 }
150 _yvar = 0 ;
151 initialize() ;
152}
153
154
155
156
157////////////////////////////////////////////////////////////////////////////////
158///
159/// RooXYChi2Var constructor with an extended p.d.f. and X-Y values dataset
160/// The value of the function that defines the chi^2 in this form is takes as
161/// the p.d.f. times the expected number of events
162///
163/// An X-Y dataset is a weighted dataset with one or more observables X where the weight is interpreted
164/// as the Y value and the weight error is interpreted as the Y value error. The weight must have an
165/// non-zero error defined at each point for the chi^2 calculation to be meaningful.
166///
167/// To store errors associated with the x and y values in a RooDataSet, call RooRealVar::setAttribute("StoreError")
168/// on each X-type observable for which the error should be stored and add datapoints to the dataset as follows
169///
170/// RooDataSet::add(xset,yval,yerr) where xset is the RooArgSet of x observables (with or without errors) and yval and yerr
171/// are the double values that correspond to the Y and its error
172///
173
174RooXYChi2Var::RooXYChi2Var(const char *name, const char* title, RooAbsPdf& extPdf, RooDataSet& xydata, RooRealVar& yvar, bool integrate) :
175 RooAbsOptTestStatistic(name,title,extPdf,xydata,RooArgSet(),makeRooAbsTestStatisticCfg()),
176 _extended(true),
177 _integrate(integrate),
178 _intConfig(*defaultIntegratorConfig())
179{
180 if (!extPdf.canBeExtended()) {
181 throw std::runtime_error(Form("RooXYChi2Var::ctor(%s) ERROR: Input p.d.f. must be an extendible",GetName()));
182 }
183 _yvar = (RooRealVar*) _dataClone->get()->find(yvar.GetName()) ;
184 initialize() ;
185}
186
187
188
189
190////////////////////////////////////////////////////////////////////////////////
191/// Copy constructor
192
193RooXYChi2Var::RooXYChi2Var(const RooXYChi2Var& other, const char* name) :
195 _extended(other._extended),
196 _integrate(other._integrate),
197 _intConfig(other._intConfig)
198{
199 _yvar = other._yvar ? (RooRealVar*) _dataClone->get()->find(other._yvar->GetName()) : 0 ;
200 initialize() ;
201
202}
203
204
205
206
207////////////////////////////////////////////////////////////////////////////////
208/// Common constructor initialization
209
211{
212 // If this tests statistic is not a "Slave" in the RooAbsOptTestStatistic
213 // framework, it doesn't do any actual computation and no initialization is
214 // needed. It would not even work, because _funcObsSet would be a nullptr.
215 if(operMode() != Slave) return;
216
217 for(RooAbsArg * arg : *_funcObsSet) {
218 if (auto* var = dynamic_cast<RooRealVar*>(arg)) {
219 _rrvArgs.add(*var) ;
220 }
221 }
222 if (_yvar) {
223 _rrvArgs.add(*_yvar) ;
224 }
225
226 // Define alternate numeric integrator configuration for bin integration
227 // We expect bin contents to very only very slowly so a non-adaptive
228 // Gauss-Kronrod integrator is expected to perform well (if RooFitMore is available)
231#ifdef R__HAS_MATHMORE
232 _intConfig.method1D().setLabel("RooGaussKronrodIntegrator1D") ;
233#endif
234 _intConfig.methodND().setLabel("RooAdaptiveIntegratorND") ;
235
237
238}
239
240
241
242////////////////////////////////////////////////////////////////////////////////
243/// Initialize bin content integrator
244
246{
247 if (!_funcInt) {
248 _funcInt = std::unique_ptr<RooAbsReal>{_funcClone->createIntegral(_rrvArgs,_rrvArgs,_intConfig,"bin")};
249 for(auto * x : static_range_cast<RooRealVar*>(_rrvArgs)) {
250 _binList.push_back(&x->getBinning("bin",false,true)) ;
251 }
252 }
253
254}
255
256
258
259
260////////////////////////////////////////////////////////////////////////////////
261/// Calculate contribution to internal error due to error on 'x' coordinates
262/// at point i
263
264double RooXYChi2Var::xErrorContribution(double ydata) const
265{
266 double ret(0) ;
267
268 for(auto * var : static_range_cast<RooRealVar*>(_rrvArgs)) {
269
270 if (var->hasAsymError()) {
271
272 // Get value at central X
273 double cxval = var->getVal() ;
274 double xerrLo = -var->getAsymErrorLo() ;
275 double xerrHi = var->getAsymErrorHi() ;
276 double xerr = (xerrLo+xerrHi)/2 ;
277
278 // Get value at X-eps
279 var->setVal(cxval - xerr/100) ;
280 double fxmin = fy() ;
281
282 // Get value at X+eps
283 var->setVal(cxval + xerr/100) ;
284 double fxmax = fy() ;
285
286 // Calculate slope
287 double slope = (fxmax-fxmin)/(2*xerr/100.) ;
288
289// cout << "xerrHi = " << xerrHi << " xerrLo = " << xerrLo << " slope = " << slope << endl ;
290
291 // Asymmetric X error, decide which one to use
292 if ((ydata>cxval && fxmax>fxmin) || (ydata<=cxval && fxmax<=fxmin)) {
293 // Use right X error
294 ret += pow(xerrHi*slope,2) ;
295 } else {
296 // Use left X error
297 ret += pow(xerrLo*slope,2) ;
298 }
299
300 } else if (var->hasError()) {
301
302 // Get value at central X
303 double cxval = var->getVal() ;
304 double xerr = var->getError() ;
305
306 // Get value at X-eps
307 var->setVal(cxval - xerr/100) ;
308 double fxmin = fy() ;
309
310 // Get value at X+eps
311 var->setVal(cxval + xerr/100) ;
312 double fxmax = fy() ;
313
314 // Calculate slope
315 double slope = (fxmax-fxmin)/(2*xerr/100.) ;
316
317// cout << var << " " ;
318// var->Print() ;
319
320// cout << var->GetName() << " xerr = " << xerr << " slope = " << slope << endl ;
321
322 // Symmetric X error
323 ret += pow(xerr*slope,2) ;
324 }
325 }
326 return ret ;
327}
328
329
330
331
332////////////////////////////////////////////////////////////////////////////////
333/// Return function value requested bu present configuration
334///
335/// If integration is required, the function value integrated
336/// over the bin volume divided by the bin volume is returned,
337/// otherwise the value at the bin center is returned.
338/// The bin volume is defined by the error on the 'X' coordinates
339///
340/// If an extended p.d.f. is used as function, its value is
341/// also multiplied by the expected number of events here
342
343double RooXYChi2Var::fy() const
344{
345 // Get function value
346 double yfunc ;
347 if (!_integrate) {
348 yfunc = _funcClone->getVal(_dataClone->get()) ;
349 } else {
350 double volume(1) ;
351 auto rrvIter = _rrvArgs.begin();
352 for (auto iter = _binList.begin() ; iter != _binList.end() ; ++iter) {
353 auto* x = static_cast<RooRealVar*>(*rrvIter);
354 double xmin = x->getVal() + x->getErrorLo() ;
355 double xmax = x->getVal() + x->getErrorHi() ;
356 (*iter)->setRange(xmin,xmax) ;
357 x->setShapeDirty() ;
358 volume *= (xmax - xmin) ;
359 ++rrvIter;
360 }
361 double ret = _funcInt->getVal() ;
362 return ret / volume ;
363 }
364 if (_extended) {
365 RooAbsPdf* pdf = (RooAbsPdf*) _funcClone ;
366 // Multiply with expected number of events
367 yfunc *= pdf->expectedEvents(_dataClone->get()) ;
368 }
369 return yfunc ;
370}
371
372
373
374////////////////////////////////////////////////////////////////////////////////
375/// Calculate chi^2 in partition from firstEvent to lastEvent using given stepSize
376
377double RooXYChi2Var::evaluatePartition(std::size_t firstEvent, std::size_t lastEvent, std::size_t stepSize) const
378{
379 double result(0), carry(0);
380
381 // Loop over bins of dataset
382 RooDataSet* xydata = (RooDataSet*) _dataClone ;
383
384 _dataClone->store()->recalculateCache( _projDeps, firstEvent, lastEvent, stepSize,false ) ;
385
386 for (auto i=firstEvent ; i<lastEvent ; i+=stepSize) {
387
388 // get the data values for this event
389 xydata->get(i);
390
391 // Get function value
392 double yfunc = fy() ;
393
394 // Get data value and error
395 double ydata ;
396 double eylo,eyhi ;
397 if (_yvar) {
398 ydata = _yvar->getVal() ;
399 eylo = -1*_yvar->getErrorLo() ;
400 eyhi = _yvar->getErrorHi() ;
401 } else {
402 ydata = xydata->weight() ;
403 xydata->weightError(eylo,eyhi) ;
404 }
405
406 // Calculate external error
407 double eExt = yfunc-ydata ;
408
409 // Pick upper or lower error bar depending on sign of external error
410 double eInt = (eExt>0) ? eyhi : eylo ;
411
412 // Add contributions due to error in x coordinates
413 double eIntX2 = _integrate ? 0 : xErrorContribution(ydata) ;
414
415// cout << "fy = " << yfunc << " eExt = " << eExt << " eInt = " << eInt << " eIntX2 = " << eIntX2 << endl ;
416
417 // Return 0 if eInt=0, special handling in MINUIT will follow
418 if (eInt==0.) {
419 coutE(Eval) << "RooXYChi2Var::RooXYChi2Var(" << GetName() << ") INFINITY ERROR: data point " << i
420 << " has zero error, but function is not zero (f=" << yfunc << ")" << endl ;
421 return 0 ;
422 }
423
424 // Add chi2 term
425 double term = eExt*eExt/(eInt*eInt+ eIntX2);
426 double y = term - carry;
427 double t = result + y;
428 carry = (t - result) - y;
429 result = t;
430 }
431
432 _evalCarry = carry;
433 return result ;
434}
435
436
437
439{
440 // Inform base class that observable yvar cannot be optimized away from the dataset
441 if (_yvar) return RooArgSet(*_yvar) ;
442 return RooArgSet() ;
443}
#define e(i)
Definition RSha256.hxx:103
#define coutE(a)
#define ClassImp(name)
Definition Rtypes.h:377
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:2467
RooAbsArg is the common abstract base class for objects that represent a value and a "shape" in RooFi...
Definition RooAbsArg.h:74
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
const_iterator begin() const
RooAbsArg * find(const char *name) const
Find object with given name in list.
virtual void recalculateCache(const RooArgSet *, Int_t, Int_t, Int_t, bool)
virtual const RooArgSet * get() const
Definition RooAbsData.h:103
RooAbsDataStore * store()
Definition RooAbsData.h:79
RooAbsOptTestStatistic is the abstract base class for test statistics objects that evaluate a functio...
RooAbsReal * _funcClone
Pointer to internal clone of input function.
RooArgSet * _funcObsSet
List of observables in the pdf expression.
RooAbsData * _dataClone
Pointer to internal clone if input data.
RooArgSet * _projDeps
Set of projected observable.
virtual double expectedEvents(const RooArgSet *nset) const
Return expected number of events to be used in calculation of extended likelihood.
bool canBeExtended() const
If true, PDF can provide extended likelihood term.
Definition RooAbsPdf.h:278
RooAbsReal is the common abstract base class for objects that represent a real value and implements f...
Definition RooAbsReal.h:62
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:91
RooFit::OwningPtr< RooAbsReal > createIntegral(const RooArgSet &iset, const RooCmdArg &arg1, const RooCmdArg &arg2=RooCmdArg::none(), const RooCmdArg &arg3=RooCmdArg::none(), const RooCmdArg &arg4=RooCmdArg::none(), const RooCmdArg &arg5=RooCmdArg::none(), const RooCmdArg &arg6=RooCmdArg::none(), const RooCmdArg &arg7=RooCmdArg::none(), const RooCmdArg &arg8=RooCmdArg::none()) const
Create an object that represents the integral of the function over one or more observables std::liste...
double _evalCarry
! carry of Kahan sum in evaluatePartition
GOFOpMode operMode() const
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:55
bool setLabel(const char *label, bool printError=true) override
Set value by specifying the name of the desired state.
RooDataSet is a container class to hold unbinned data.
Definition RooDataSet.h:57
const RooArgSet * get(Int_t index) const override
Return RooArgSet with coordinates of event 'index'.
void weightError(double &lo, double &hi, ErrorType etype=SumW2) const override
Return the asymmetric errors on the current weight.
double weight() const override
Return event weight of current event.
RooCategory & methodND()
void setEpsRel(double newEpsRel)
Set relative convergence criteria (convergence if std::abs(Err)/abs(Int)<newEpsRel)
RooCategory & method1D()
void setEpsAbs(double newEpsAbs)
Set absolute convergence criteria (convergence if std::abs(Err)<newEpsAbs)
RooRealVar represents a variable that can be changed from the outside.
Definition RooRealVar.h:40
double getErrorLo() const
Definition RooRealVar.h:71
double getErrorHi() const
Definition RooRealVar.h:72
RooXYChi2Var implements a simple chi^2 calculation from an unbinned dataset with values x,...
double fy() const
Return function value requested bu present configuration.
std::unique_ptr< RooAbsReal > _funcInt
! Function integral
std::list< RooAbsBinning * > _binList
! Bin ranges
bool _extended
Is the input function and extended p.d.f.
void initIntegrator()
Initialize bin content integrator.
RooRealVar * _yvar
Y variable if so designated.
RooXYChi2Var()
coverity[UNINIT_CTOR]
RooArgSet requiredExtraObservables() const override
double evaluatePartition(std::size_t firstEvent, std::size_t lastEvent, std::size_t stepSize) const override
Calculate chi^2 in partition from firstEvent to lastEvent using given stepSize.
bool _integrate
Is integration over the bin volume requested.
RooArgSet _rrvArgs
Set of real-valued observables.
double xErrorContribution(double ydata) const
Calculate contribution to internal error due to error on 'x' coordinates at point i.
void initialize()
Common constructor initialization.
RooNumIntConfig _intConfig
Numeric integrator configuration for integration of function over bin.
~RooXYChi2Var() override
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17