Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
rf709_BarlowBeeston.C
Go to the documentation of this file.
1 /// \file rf709_BarlowBeeston.C
2 /// \ingroup tutorial_roofit
3 /// \notebook -js
4 /// Implementing the Barlow-Beeston method for taking into account the statistical uncertainty of a Monte-Carlo fit template.
5 /// \macro_image
6 /// \macro_output
7 /// \macro_code
8 /// \author 06/2019 - Stephan Hageboeck, CERN
9 /// Based on a demo by Wouter Verkerke
10 
11 #include "RooRealVar.h"
12 #include "RooGaussian.h"
13 #include "RooUniform.h"
14 #include "RooDataSet.h"
15 #include "RooDataHist.h"
16 #include "RooHistFunc.h"
17 #include "RooRealSumPdf.h"
18 #include "RooParamHistFunc.h"
19 #include "RooHistConstraint.h"
20 #include "RooProdPdf.h"
21 #include "RooPlot.h"
22 
23 #include "TCanvas.h"
24 #include "TPaveText.h"
25 
26 #include <iostream>
27 #include <memory>
28 
29 using namespace RooFit;
30 
31 void rf709_BarlowBeeston()
32 {
33  // First, construct a likelihood model with a Gaussian signal on top of a uniform background
34  RooRealVar x("x", "x", -20, 20);
35  x.setBins(25);
36 
37  RooRealVar meanG("meanG", "meanG", 1, -10, 10);
38  RooRealVar sigG("sigG", "sigG", 1.5, -10, 10);
39  RooGaussian g("g", "Gauss", x, meanG, sigG);
40  RooUniform u("u", "Uniform", x);
41 
42 
43  // Generate the data to be fitted
44  std::unique_ptr<RooDataSet> sigData(g.generate(x, 50));
45  std::unique_ptr<RooDataSet> bkgData(u.generate(x, 1000));
46 
47  RooDataSet sumData("sumData", "Gauss + Uniform", x);
48  sumData.append(*sigData);
49  sumData.append(*bkgData);
50 
51 
52  // Make histogram templates for signal and background.
53  // Let's take a signal distribution with low statistics and a more accurate
54  // background distribution.
55  // Normally, these come from Monte Carlo simulations, but we will just generate them.
56  std::unique_ptr<RooDataHist> dh_sig( g.generateBinned(x, 50) );
57  std::unique_ptr<RooDataHist> dh_bkg( u.generateBinned(x, 10000) );
58 
59 
60  // ***** Case 0 - 'Rigid templates' *****
61 
62  // Construct histogram shapes for signal and background
63  RooHistFunc p_h_sig("p_h_sig","p_h_sig",x,*dh_sig);
64  RooHistFunc p_h_bkg("p_h_bkg","p_h_bkg",x,*dh_bkg);
65 
66  // Construct scale factors for adding the two distributions
67  RooRealVar Asig0("Asig","Asig",1,0.01,5000);
68  RooRealVar Abkg0("Abkg","Abkg",1,0.01,5000);
69 
70  // Construct the sum model
71  RooRealSumPdf model0("model0","model0",
72  RooArgList(p_h_sig,p_h_bkg),
73  RooArgList(Asig0,Abkg0),
74  true);
75 
76 
77 
78  // ***** Case 1 - 'Barlow Beeston' *****
79 
80  // Construct parameterized histogram shapes for signal and background
81  RooParamHistFunc p_ph_sig1("p_ph_sig","p_ph_sig",*dh_sig);
82  RooParamHistFunc p_ph_bkg1("p_ph_bkg","p_ph_bkg",*dh_bkg);
83 
84  RooRealVar Asig1("Asig","Asig",1,0.01,5000);
85  RooRealVar Abkg1("Abkg","Abkg",1,0.01,5000);
86 
87  // Construct the sum of these
88  RooRealSumPdf model_tmp("sp_ph", "sp_ph",
89  RooArgList(p_ph_sig1,p_ph_bkg1),
90  RooArgList(Asig1,Abkg1),
91  true);
92 
93  // Construct the subsidiary poisson measurements constraining the histogram parameters
94  // These ensure that the bin contents of the histograms are only allowed to vary within
95  // the statistical uncertainty of the Monte Carlo.
96  RooHistConstraint hc_sig("hc_sig","hc_sig",p_ph_sig1);
97  RooHistConstraint hc_bkg("hc_bkg","hc_bkg",p_ph_bkg1);
98 
99  // Construct the joint model with template PDFs and constraints
100  RooProdPdf model1("model1","model1",RooArgSet(hc_sig,hc_bkg),Conditional(model_tmp,x));
101 
102 
103 
104  // ***** Case 2 - 'Barlow Beeston' light (one parameter per bin for all samples) *****
105 
106  // Construct the histogram shapes, using the same parameters for signal and background
107  // This requires passing the first histogram to the second, so that their common parameters
108  // can be re-used.
109  // The first ParamHistFunc will create one parameter per bin, such as `p_ph_sig2_gamma_bin_0`.
110  // This allows bin 0 to fluctuate up and down.
111  // Then, the SAME parameters are connected to the background histogram, so the bins flucutate
112  // synchronously. This reduces the number of parameters.
113  RooParamHistFunc p_ph_sig2("p_ph_sig2", "p_ph_sig2", *dh_sig);
114  RooParamHistFunc p_ph_bkg2("p_ph_bkg2", "p_ph_bkg2", *dh_bkg, p_ph_sig2, true);
115 
116  RooRealVar Asig2("Asig","Asig",1,0.01,5000);
117  RooRealVar Abkg2("Abkg","Abkg",1,0.01,5000);
118 
119  // As before, construct the sum of signal2 and background2
120  RooRealSumPdf model2_tmp("sp_ph","sp_ph",
121  RooArgList(p_ph_sig2,p_ph_bkg2),
122  RooArgList(Asig2,Abkg2),
123  true);
124 
125  // Construct the subsidiary poisson measurements constraining the statistical fluctuations
126  RooHistConstraint hc_sigbkg("hc_sigbkg","hc_sigbkg",RooArgSet(p_ph_sig2,p_ph_bkg2));
127 
128  // Construct the joint model
129  RooProdPdf model2("model2","model2",hc_sigbkg, RooFit::Conditional(model2_tmp,x));
130 
131 
132 
133  // ************ Fit all models to data and plot *********************
134 
135  auto result0 = model0.fitTo(sumData, PrintLevel(0), Save());
136  auto result1 = model1.fitTo(sumData, PrintLevel(0), Save());
137  auto result2 = model2.fitTo(sumData, PrintLevel(0), Save());
138 
139 
140  TCanvas* can = new TCanvas("can", "", 1500, 600);
141  can->Divide(3,1);
142 
143  TPaveText pt(-19.5, 1, -2, 25);
144  pt.SetFillStyle(0);
145  pt.SetBorderSize(0);
146 
147 
148  can->cd(1);
149  auto frame = x.frame(Title("No template uncertainties"));
150  // Plot data to enable automatic determination of model0 normalisation:
151  sumData.plotOn(frame);
152  model0.plotOn(frame, LineColor(kBlue), VisualizeError(*result0));
153  // Plot data again to show it on top of model0 error bands:
154  sumData.plotOn(frame);
155  // Plot model components
156  model0.plotOn(frame, LineColor(kBlue));
157  model0.plotOn(frame, Components(p_h_sig), LineColor(kAzure));
158  model0.plotOn(frame, Components(p_h_bkg), LineColor(kRed));
159  model0.paramOn(frame);
160 
161  sigData->plotOn(frame, MarkerColor(kBlue));
162  frame->Draw();
163 
164  for (auto text : {
165  "No template uncertainties",
166  "are taken into account.",
167  "This leads to low errors",
168  "for the parameters A, since",
169  "the only source of errors",
170  "are the data statistics."}) {
171  pt.AddText(text);
172  }
173  pt.DrawClone();
174 
175 
176  can->cd(2);
177  frame = x.frame(Title("Barlow Beeston for Sig & Bkg separately"));
178  sumData.plotOn(frame);
179  model1.plotOn(frame, LineColor(kBlue), VisualizeError(*result1));
180  // Plot data again to show it on top of error bands:
181  sumData.plotOn(frame);
182  model1.plotOn(frame, LineColor(kBlue));
183  model1.plotOn(frame, Components(p_ph_sig1), LineColor(kAzure));
184  model1.plotOn(frame, Components(p_ph_bkg1), LineColor(kRed));
185  model1.paramOn(frame, Parameters(RooArgSet(Asig1, Abkg1)));
186 
187  sigData->plotOn(frame, MarkerColor(kBlue));
188  frame->Draw();
189 
190  pt.Clear();
191  for (auto text : {
192  "With gamma parameters, the",
193  "signal & background templates",
194  "can adapt to the data.",
195  "Note how the blue signal",
196  "template changes its shape.",
197  "This leads to higher errors",
198  "of the scale parameters A."}) {
199  pt.AddText(text);
200  }
201  pt.DrawClone();
202 
203  can->cd(3);
204  frame = x.frame(Title("Barlow Beeston light for (Sig+Bkg)"));
205  sumData.plotOn(frame);
206  model2.plotOn(frame, LineColor(kBlue), VisualizeError(*result2));
207  // Plot data again to show it on top of model0 error bands:
208  sumData.plotOn(frame);
209  model2.plotOn(frame, LineColor(kBlue));
210  model2.plotOn(frame, Components(p_ph_sig2), LineColor(kAzure));
211  model2.plotOn(frame, Components(p_ph_bkg2), LineColor(kRed));
212  model2.paramOn(frame, Parameters(RooArgSet(Asig2, Abkg2)));
213 
214  sigData->plotOn(frame, MarkerColor(kBlue));
215  frame->Draw();
216 
217  pt.Clear();
218  for (auto text : {
219  "When signal and background",
220  "template share one gamma para-",
221  "meter per bin, they adapt less.",
222  "The errors of the A parameters",
223  "also shrink slightly."}) {
224  pt.AddText(text);
225  }
226  pt.DrawClone();
227 
228 
229  std::cout << "Asig [normal ] = " << Asig0.getVal() << " +/- " << Asig0.getError() << std::endl;
230  std::cout << "Asig [BB ] = " << Asig1.getVal() << " +/- " << Asig1.getError() << std::endl;
231  std::cout << "Asig [BBlight] = " << Asig2.getVal() << " +/- " << Asig2.getError() << std::endl;
232 
233 }