Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
rf709_BarlowBeeston.C
Go to the documentation of this file.
1/// \file
2/// \ingroup tutorial_roofit_main
3/// \notebook -js
4/// Implementing the Barlow-Beeston method for taking into account the statistical
5/// uncertainty of a Monte-Carlo fit template.
6///
7/// \macro_image
8/// \macro_code
9/// \macro_output
10///
11/// Based on a demo by Wouter Verkerke
12//
13/// \date June 2019
14/// \author Jonas Rembser, Stephan Hageboeck, CERN
15
16#include "RooRealVar.h"
17#include "RooGaussian.h"
18#include "RooUniform.h"
19#include "RooDataSet.h"
20#include "RooDataHist.h"
21#include "RooHistFunc.h"
22#include "RooRealSumPdf.h"
23#include "RooProduct.h"
24#include "RooConstVar.h"
25#include "RooPoisson.h"
26#include "RooProdPdf.h"
27#include "RooFitResult.h"
28#include "RooPlot.h"
29#include "RooMsgService.h"
31
32#include "TCanvas.h"
33#include "TPaveText.h"
34
35#include <cmath>
36#include <iostream>
37#include <memory>
38
39RooArgSet createConstraints(RooArgList const &gammas, RooArgList const &samples, RooArgSet &globalObservables)
40{
41 RooArgSet constraints;
42 for (std::size_t i = 0; i < gammas.size(); ++i) {
43 auto *gamma = static_cast<RooRealVar *>(&gammas[i]);
44
45 auto nomName = "nom_" + std::string(gamma->GetName());
46 auto tauName = std::string(gamma->GetName()) + "_tau";
47 auto meanName = std::string(gamma->GetName()) + "_mean";
48 auto poissonName = std::string(gamma->GetName()) + "_constraint";
49
50 double nomVal = 0.0;
51 for (auto *func : static_range_cast<RooHistFunc *>(samples)) {
52 nomVal += func->dataHist().weight(i);
53 }
54
55 // Like in HistFactory, the gamma of an empty bin is fixed and not
56 // constrained. Otherwise, it would be a flat direction of the likelihood.
57 // The other gammas get the relative Poisson uncertainty as initial error.
58 if (nomVal == 0.0) {
59 gamma->setConstant(true);
60 continue;
61 }
62 gamma->setError(1.0 / std::sqrt(nomVal));
63
64 auto nominal = std::make_unique<RooRealVar>(nomName.c_str(), nomName.c_str(), nomVal, 0.0, RooNumber::infinity());
65 nominal->setConstant(true);
66 globalObservables.add(*nominal);
67
68 auto tau = std::make_unique<RooConstVar>(tauName.c_str(), tauName.c_str(), nominal->getVal());
69
70 auto mean = std::make_unique<RooProduct>(meanName.c_str(), meanName.c_str(), *gamma, *tau);
71 mean->addOwnedComponents(std::move(tau));
72
73 auto poisson = std::make_unique<RooPoisson>(poissonName.c_str(), poissonName.c_str(), *nominal, *mean);
74 poisson->addOwnedComponents(std::move(nominal));
75 poisson->addOwnedComponents(std::move(mean));
76
77 constraints.addOwned(std::move(poisson));
78 }
79 return constraints;
80}
81
82void rf709_BarlowBeeston()
83{
84 using namespace RooFit;
85
87
88 // First, construct a likelihood model with a Gaussian signal on top of a uniform background
89 RooRealVar x("x", "x", -20, 20);
90 x.setBins(25);
91
92 RooRealVar meanG("meanG", "meanG", 1, -10, 10);
93 RooRealVar sigG("sigG", "sigG", 1.5, -10, 10);
94 RooGaussian g("g", "Gauss", x, meanG, sigG);
95 RooUniform u("u", "Uniform", x);
96
97 // Generate the data to be fitted
98 std::unique_ptr<RooDataSet> sigData(g.generate(x, 50));
99 std::unique_ptr<RooDataSet> bkgData(u.generate(x, 1000));
100
101 RooDataSet sumData("sumData", "Gauss + Uniform", x);
102 sumData.append(*sigData);
103 sumData.append(*bkgData);
104
105 // Make histogram templates for signal and background.
106 // Let's take a signal distribution with low statistics and a more accurate
107 // background distribution.
108 // Normally, these come from Monte Carlo simulations, but we will just generate them.
109 std::unique_ptr<RooDataHist> dh_sig(g.generateBinned(x, 50));
110 std::unique_ptr<RooDataHist> dh_bkg(u.generateBinned(x, 10000));
111
112 // ***** Case 0 - 'Rigid templates' *****
113
114 // Construct histogram shapes for signal and background
115 RooHistFunc p_h_sig("p_h_sig", "p_h_sig", x, *dh_sig);
116 RooHistFunc p_h_bkg("p_h_bkg", "p_h_bkg", x, *dh_bkg);
117
118 // Construct scale factors for adding the two distributions
119 RooRealVar Asig0("Asig", "Asig", 1, 0.01, 5000);
120 RooRealVar Abkg0("Abkg", "Abkg", 1, 0.01, 5000);
121
122 // Construct the sum model
123 RooRealSumPdf model0("model0", "model0", {p_h_sig, p_h_bkg}, {Asig0, Abkg0}, true);
124
125 // ***** Case 1 - 'Barlow Beeston' *****
126
127 // Construct parameterized histogram shapes for signal and background
128 RooArgList gammas_sig1{ParamHistFunc::createParamSet("p_ph_sig_gamma", x.numBins(), 0, 10)};
129 RooArgList gammas_bkg1{ParamHistFunc::createParamSet("p_ph_bkg_gamma", x.numBins(), 0, 10)};
130
131 ParamHistFunc p_phf_sig1{"p_phf_sig1", "p_phf_sig1", x, gammas_sig1};
132 ParamHistFunc p_phf_bkg1{"p_phf_bkg1", "p_phf_bkg1", x, gammas_bkg1};
133
134 RooProduct p_p_sig1{"p_p_sig1", "p_p_sig1", p_h_sig, p_phf_sig1};
135 RooProduct p_p_bkg1{"p_p_bkg1", "p_p_bkg1", p_h_bkg, p_phf_bkg1};
136
137 RooRealVar Asig1("Asig", "Asig", 1, 0.01, 5000);
138 RooRealVar Abkg1("Abkg", "Abkg", 1, 0.01, 5000);
139
140 // Construct the sum of these
141 RooRealSumPdf model1_tmp("sp_ph", "sp_ph", {p_p_sig1, p_p_bkg1}, {Asig1, Abkg1}, true);
142
143 // Construct the subsidiary poisson measurements constraining the histogram parameters
144 // These ensure that the bin contents of the histograms are only allowed to vary within
145 // the statistical uncertainty of the Monte Carlo.
146 RooArgSet globs1;
147 RooArgSet constraints_sig1{createConstraints(gammas_sig1, p_h_sig, globs1)};
148 RooArgSet constraints_bkg1{createConstraints(gammas_bkg1, p_h_bkg, globs1)};
149
150 // Construct the joint model with template PDFs and constraints
151 RooProdPdf model1("model1", "model1", {model1_tmp, constraints_sig1, constraints_bkg1});
152
153 // ***** Case 2 - 'Barlow Beeston' light (one parameter per bin for all samples) *****
154
155 // Construct the histogram shapes, using the same parameters for signal and background.
156 // There is one parameter per bin, such as `p_ph_gamma_bin_0`. This allows bin 0 to
157 // fluctuate up and down. The SAME ParamHistFunc scales both the signal and the background
158 // histogram, so the bins fluctuate synchronously. This reduces the number of parameters.
159 RooArgList gammas2{ParamHistFunc::createParamSet("p_ph_gamma", x.numBins(), 0, 10)};
160
161 ParamHistFunc p_phf2{"p_phf2", "p_phf2", x, gammas2};
162
163 RooProduct p_p_sig2{"p_p_sig2", "p_p_sig2", p_h_sig, p_phf2};
164 RooProduct p_p_bkg2{"p_p_bkg2", "p_p_bkg2", p_h_bkg, p_phf2};
165
166 RooRealVar Asig2("Asig", "Asig", 1, 0.01, 5000);
167 RooRealVar Abkg2("Abkg", "Abkg", 1, 0.01, 5000);
168
169 // As before, construct the sum of signal2 and background2
170 RooRealSumPdf model2_tmp("sp_ph", "sp_ph", {p_p_sig2, p_p_bkg2}, {Asig2, Abkg2}, true);
171
172 // Construct the subsidiary poisson measurements constraining the statistical fluctuations
173 RooArgSet globs2;
174 RooArgSet constraints2{createConstraints(gammas2, {p_h_sig, p_h_bkg}, globs2)};
175
176 // Construct the joint model
177 RooProdPdf model2("model2", "model2", {model2_tmp, constraints2});
178
179 // ************ Fit all models to data and plot *********************
180
181 std::unique_ptr<RooFitResult> result0{model0.fitTo(sumData, PrintLevel(0), Save())};
182 std::unique_ptr<RooFitResult> result1{model1.fitTo(sumData, PrintLevel(0), Save(), GlobalObservables(globs1))};
183 std::unique_ptr<RooFitResult> result2{model2.fitTo(sumData, PrintLevel(0), Save(), GlobalObservables(globs2))};
184
185 TCanvas *can = new TCanvas("can", "", 1500, 600);
186 can->Divide(3, 1);
187
188 TPaveText pt(-19.5, 1, -2, 25);
189 pt.SetFillStyle(0);
190 pt.SetBorderSize(0);
191
192 can->cd(1);
193 auto frame = x.frame(Title("No template uncertainties"));
194 // Plot data to enable automatic determination of model0 normalisation:
195 sumData.plotOn(frame);
196 model0.plotOn(frame, LineColor(kBlue), VisualizeError(*result0));
197 // Plot data again to show it on top of model0 error bands:
198 sumData.plotOn(frame);
199 // Plot model components
200 model0.plotOn(frame, LineColor(kBlue));
201 model0.plotOn(frame, Components(p_h_sig), LineColor(kAzure));
202 model0.plotOn(frame, Components(p_h_bkg), LineColor(kRed));
203 model0.paramOn(frame);
204
205 sigData->plotOn(frame, MarkerColor(kBlue));
206 frame->Draw();
207
208 for (auto text : {"No template uncertainties", "are taken into account.", "This leads to low errors",
209 "for the parameters A, since", "the only source of errors", "are the data statistics."}) {
210 pt.AddText(text);
211 }
212 pt.DrawClone();
213
214 can->cd(2);
215 frame = x.frame(Title("Barlow Beeston for Sig & Bkg separately"));
216 sumData.plotOn(frame);
217 model1.plotOn(frame, LineColor(kBlue), VisualizeError(*result1));
218 // Plot data again to show it on top of error bands:
219 sumData.plotOn(frame);
220 model1.plotOn(frame, LineColor(kBlue));
221 model1.plotOn(frame, Components(p_p_sig1), LineColor(kAzure));
222 model1.plotOn(frame, Components(p_p_bkg1), LineColor(kRed));
223 model1.paramOn(frame, Parameters({Asig1, Abkg1}));
224
225 sigData->plotOn(frame, MarkerColor(kBlue));
226 frame->Draw();
227
228 pt.Clear();
229 for (auto text : {"With gamma parameters, the", "signal & background templates", "can adapt to the data.",
230 "Note how the blue signal", "template changes its shape.", "This leads to higher errors",
231 "of the scale parameters A."}) {
232 pt.AddText(text);
233 }
234 pt.DrawClone();
235
236 can->cd(3);
237 frame = x.frame(Title("Barlow Beeston light for (Sig+Bkg)"));
238 sumData.plotOn(frame);
239 model2.plotOn(frame, LineColor(kBlue), VisualizeError(*result2));
240 // Plot data again to show it on top of model0 error bands:
241 sumData.plotOn(frame);
242 model2.plotOn(frame, LineColor(kBlue));
243 model2.plotOn(frame, Components(p_p_sig2), LineColor(kAzure));
244 model2.plotOn(frame, Components(p_p_bkg2), LineColor(kRed));
245 model2.paramOn(frame, Parameters({Asig2, Abkg2}));
246
247 sigData->plotOn(frame, MarkerColor(kBlue));
248 frame->Draw();
249
250 pt.Clear();
251 for (auto text : {"When signal and background", "template share one gamma para-", "meter per bin, they adapt less.",
252 "The errors of the A parameters", "also shrink slightly."}) {
253 pt.AddText(text);
254 }
255 pt.DrawClone();
256
257 std::cout << "Asig [normal ] = " << Asig0.getVal() << " +/- " << Asig0.getError() << std::endl;
258 std::cout << "Asig [BB ] = " << Asig1.getVal() << " +/- " << Asig1.getError() << std::endl;
259 std::cout << "Asig [BBlight] = " << Asig2.getVal() << " +/- " << Asig2.getError() << std::endl;
260}
#define g(i)
Definition RSha256.hxx:105
ROOT::RRangeCast< T, false, Range_t > static_range_cast(Range_t &&coll)
@ kRed
Definition Rtypes.h:66
@ kBlue
Definition Rtypes.h:66
@ kAzure
Definition Rtypes.h:67
Option_t Option_t TPoint TPoint const char text
A class which maps the current values of a RooRealVar (or a set of RooRealVars) to one of a number of...
static RooArgList createParamSet(RooWorkspace &w, const std::string &, const RooArgList &Vars)
Create the list of RooRealVar parameters which represent the height of the histogram bins.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
virtual bool addOwned(RooAbsArg &var, bool silent=false)
Add an argument and transfer the ownership to the collection.
RooFit::OwningPtr< RooFitResult > fitTo(RooAbsData &data, CmdArgs_t const &... cmdArgs)
Fit PDF to given dataset.
Definition RooAbsPdf.h:149
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
Container class to hold unbinned data.
Definition RooDataSet.h:32
Plain Gaussian p.d.f.
Definition RooGaussian.h:24
A real-valued function sampled from a multidimensional histogram.
Definition RooHistFunc.h:29
static RooMsgService & instance()
Return reference to singleton instance.
StreamConfig & getStream(Int_t id)
static constexpr double infinity()
Return internal infinity representation.
Definition RooNumber.h:25
Efficient implementation of a product of PDFs of the form.
Definition RooProdPdf.h:35
Represents the product of a given set of RooAbsReal objects.
Definition RooProduct.h:29
Implements a PDF constructed from a sum of functions:
Variable that can be changed from the outside.
Definition RooRealVar.h:37
Flat p.d.f.
Definition RooUniform.h:24
virtual void SetFillStyle(Style_t fstyle)
Set the fill area style.
Definition TAttFill.h:42
The Canvas class.
Definition TCanvas.h:23
TVirtualPad * cd(Int_t subpadnumber=0) override
Set current canvas & pad.
Definition TCanvas.cxx:732
virtual TObject * DrawClone(Option_t *option="") const
Draw a clone of this object in the current selected pad with: gROOT->SetSelectedPad(c1).
Definition TObject.cxx:318
void Divide(Int_t nx=1, Int_t ny=1, Float_t xmargin=0.01, Float_t ymargin=0.01, Int_t color=0) override
Automatic pad generation by division.
Definition TPad.cxx:1361
A Pave (see TPave) with text, lines or/and boxes inside.
Definition TPaveText.h:21
virtual TText * AddText(Double_t x1, Double_t y1, const char *label)
Add a new Text line to this pavetext at given coordinates.
void Clear(Option_t *option="") override
Clear all lines in this pavetext.
virtual void SetBorderSize(Int_t bordersize=4)
Sets the border size of the TPave box and shadow.
Definition TPave.h:79
void Draw(Option_t *option="") override=0
Default Draw method for all objects.
TPaveText * pt
RooCmdArg Parameters(const RooArgSet &params)
RooCmdArg Save(bool flag=true)
RooCmdArg GlobalObservables(Args_t &&... argsOrArgSet)
RooCmdArg PrintLevel(Int_t code)
RooCmdArg Components(Args_t &&... argsOrArgSet)
RooCmdArg LineColor(TColorNumber color)
RooCmdArg VisualizeError(const RooDataSet &paramData, double Z=1)
RooCmdArg MarkerColor(TColorNumber color)
Double_t x[n]
Definition legend1.C:17
double gamma(double x)
double poisson(double x, double par)
Definition MathFuncs.h:239
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
Definition CodegenImpl.h:73
const char * Title
Definition TXMLSetup.cxx:67
void removeTopic(RooFit::MsgTopic oldTopic)