Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooChi2Var.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 RooChi2Var
21 \ingroup Roofitcore
22 \brief Simple \f$ \chi^2 \f$ calculation from a binned dataset and a PDF.
23 *
24 * It calculates:
25 *
26 \f{align*}{
27 \chi^2 &= \sum_{\mathrm{bins}} \left( \frac{N_\mathrm{PDF,bin} - N_\mathrm{Data,bin}}{\Delta_\mathrm{bin}} \right)^2 \\
28 N_\mathrm{PDF,bin} &=
29 \begin{cases}
30 \mathrm{pdf}(\text{bin centre}) \cdot V_\mathrm{bin} \cdot N_\mathrm{Data,tot} &\text{normal PDF}\\
31 \mathrm{pdf}(\text{bin centre}) \cdot V_\mathrm{bin} \cdot N_\mathrm{Data,expected} &\text{extended PDF}
32 \end{cases} \\
33 \Delta_\mathrm{bin} &=
34 \begin{cases}
35 \sqrt{N_\mathrm{PDF,bin}} &\text{if } \mathtt{DataError == RooAbsData::Expected}\\
36 \mathtt{data{\rightarrow}weightError()} &\text{otherwise} \\
37 \end{cases}
38 \f}
39 * If the dataset doesn't have user-defined errors, errors are assumed to be \f$ \sqrt{N} \f$.
40 * In extended PDF mode, N_tot (total number of data events) is substituted with N_expected, the
41 * expected number of events that the PDF predicts.
42 *
43 * \note If the dataset has errors stored, empty bins will prevent the calculation of \f$ \chi^2 \f$, because those have
44 * zero error. This leads to messages like:
45 * ```
46 * [#0] ERROR:Eval -- RooChi2Var::RooChi2Var(chi2_GenPdf_data_hist) INFINITY ERROR: bin 2 has zero error
47 * ```
48 *
49 * \note In this case, one can use the expected errors of the PDF instead of the data errors:
50 * ```{.cpp}
51 * RooChi2Var chi2(..., ..., RooFit::DataError(RooAbsData::Expected), ...);
52 * ```
53 */
54
55#include "RooChi2Var.h"
56
57#include "FitHelpers.h"
58#include "RooDataHist.h"
59#include "RooAbsPdf.h"
60#include "RooCmdConfig.h"
61#include "RooMsgService.h"
62
63#include "Riostream.h"
64#include "TClass.h"
65
66#include "RooRealVar.h"
67#include "RooAbsDataStore.h"
68
69#include <ROOT/StringUtils.hxx>
70
71RooChi2Var::RooChi2Var(const char *name, const char *title, RooAbsReal &func, RooDataHist &data, bool extended,
72 RooDataHist::ErrorType etype, RooAbsTestStatistic::Configuration const &cfg)
73 : RooAbsOptTestStatistic(name, title, func, data, RooArgSet{}, cfg),
74 _etype{etype == RooAbsData::Auto ? (data.isNonPoissonWeighted() ? RooAbsData::SumW2 : RooAbsData::Expected)
75 : etype},
77{
78}
79
80
81////////////////////////////////////////////////////////////////////////////////
82/// Copy constructor
83
84RooChi2Var::RooChi2Var(const RooChi2Var& other, const char* name) :
85 RooAbsOptTestStatistic(other,name),
88{
89}
90
91
92////////////////////////////////////////////////////////////////////////////////
93/// Calculate chi^2 in partition from firstEvent to lastEvent using given stepSize
94/// Throughout the calculation, we use Kahan's algorithm for summing to
95/// prevent loss of precision - this is a factor four more expensive than
96/// straight addition, but since evaluating the PDF is usually much more
97/// expensive than that, we tolerate the additional cost...
98
99double RooChi2Var::evaluatePartition(std::size_t firstEvent, std::size_t lastEvent, std::size_t stepSize) const
100{
101 double result(0);
102 double carry(0);
103
104 // Also consider the composite case of multiple ranges
105 std::vector<std::string> rangeTokens;
106 if (!_rangeName.empty()) {
107 rangeTokens = ROOT::Split(_rangeName, ",");
108 }
109
110 // Determine normalization factor depending on type of input function
111 double normFactor(1) ;
112 switch (_funcMode) {
113 case Function: normFactor=1 ; break ;
114 case Pdf: normFactor = _dataClone->sumEntries() ; break ;
115 case ExtendedPdf: normFactor = (static_cast<RooAbsPdf*>(_funcClone))->expectedEvents(_dataClone->get()) ; break ;
116 }
117
118 // Loop over bins of dataset
119 RooDataHist* hdata = static_cast<RooDataHist*>(_dataClone) ;
120 for (auto i=firstEvent ; i<lastEvent ; i+=stepSize) {
121
122 // get the data values for this event
123 RooArgSet const *row = hdata->get(i);
124
125 // Skip bins that are outside of the selected range
126 bool doSelect(true) ;
127 if (!_rangeName.empty()) {
128 doSelect = false;
129 // A row is selected if it is inside at least one complete named range.
130 for (const auto &rangeName : rangeTokens) {
131 bool inThisRange = true;
132 for (const auto arg : *row) {
133 if (!arg->inRange(rangeName.c_str())) {
134 inThisRange = false;
135 break;
136 }
137 }
138 if (inThisRange) {
139 doSelect = true;
140 break;
141 }
142 }
143 }
144 if (!doSelect) continue ;
145
146 const double nData = hdata->weight() ;
147
148 const double nPdf = _funcClone->getVal(_normSet) * normFactor * hdata->binVolume() ;
149
150 const double eExt = nPdf-nData ;
151
152
153 double eInt ;
155 double eIntLo;
156 double eIntHi;
157 hdata->weightError(eIntLo, eIntHi, _etype);
158 eInt = (eExt > 0) ? eIntHi : eIntLo;
159 } else {
160 eInt = sqrt(nPdf) ;
161 }
162
163 // Skip cases where pdf=0 and there is no data
164 if (0. == eInt * eInt && 0. == nData * nData && 0. == nPdf * nPdf) continue ;
165
166 // Return 0 if eInt=0, special handling in MINUIT will follow
167 if (0. == eInt * eInt) {
168 coutE(Eval) << "RooChi2Var::RooChi2Var(" << GetName() << ") INFINITY ERROR: bin " << i
169 << " has zero error" << std::endl;
170 return 0.;
171 }
172
173// std::cout << "Chi2Var[" << i << "] nData = " << nData << " nPdf = " << nPdf << " errorExt = " << eExt << " errorInt = " << eInt << " contrib = " << eExt*eExt/(eInt*eInt) << std::endl ;
174
175 double term = eExt*eExt/(eInt*eInt) ;
176 double y = term - carry;
177 double t = result + y;
178 carry = (t - result) - y;
179 result = t;
180 }
181
182 _evalCarry = carry;
183 return result ;
184}
185
186/// \endcond
#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
Double_t(* Function)(Double_t)
Definition Functor.C:4
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:57
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:40
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 N-dimensional binned data.
Definition RooDataHist.h:40
Double_t y[n]
Definition legend1.C:17
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
const UInt_t eInt[256]