Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
rs301_splot.C
Go to the documentation of this file.
1 /// \file
2 /// \ingroup tutorial_roostats
3 /// \notebook -js
4 /// SPlot tutorial
5 ///
6 /// This tutorial shows an example of using SPlot to unfold two distributions.
7 /// The physics context for the example is that we want to know
8 /// the isolation distribution for real electrons from Z events
9 /// and fake electrons from QCD. Isolation is our 'control' variable.
10 /// To unfold them, we need a model for an uncorrelated variable that
11 /// discriminates between Z and QCD. To do this, we use the invariant
12 /// mass of two electrons. We model the Z with a Gaussian and the QCD
13 /// with a falling exponential.
14 ///
15 /// Note, since we don't have real data in this tutorial, we need to generate
16 /// toy data. To do that we need a model for the isolation variable for
17 /// both Z and QCD. This is only used to generate the toy data, and would
18 /// not be needed if we had real data.
19 ///
20 /// \macro_image
21 /// \macro_code
22 /// \macro_output
23 ///
24 /// \author Kyle Cranmer
25 
26 #include "RooRealVar.h"
27 #include "RooStats/SPlot.h"
28 #include "RooDataSet.h"
29 #include "RooRealVar.h"
30 #include "RooGaussian.h"
31 #include "RooExponential.h"
32 #include "RooChebychev.h"
33 #include "RooAddPdf.h"
34 #include "RooProdPdf.h"
35 #include "RooAddition.h"
36 #include "RooProduct.h"
37 #include "TCanvas.h"
38 #include "RooAbsPdf.h"
39 #include "RooFit.h"
40 #include "RooFitResult.h"
41 #include "RooWorkspace.h"
42 #include "RooConstVar.h"
43 #include <iomanip>
44 
45 // use this order for safety on library loading
46 using namespace RooFit;
47 using namespace RooStats;
48 
49 // see below for implementation
50 void AddModel(RooWorkspace *);
51 void AddData(RooWorkspace *);
52 void DoSPlot(RooWorkspace *);
53 void MakePlots(RooWorkspace *);
54 
55 void rs301_splot()
56 {
57 
58  // Create a new workspace to manage the project.
59  RooWorkspace *wspace = new RooWorkspace("myWS");
60 
61  // add the signal and background models to the workspace.
62  // Inside this function you will find a description of our model.
63  AddModel(wspace);
64 
65  // add some toy data to the workspace
66  AddData(wspace);
67 
68  // inspect the workspace if you wish
69  // wspace->Print();
70 
71  // do sPlot.
72  // This will make a new dataset with sWeights added for every event.
73  DoSPlot(wspace);
74 
75  // Make some plots showing the discriminating variable and
76  // the control variable after unfolding.
77  MakePlots(wspace);
78 
79  // cleanup
80  delete wspace;
81 }
82 
83 //____________________________________
84 void AddModel(RooWorkspace *ws)
85 {
86 
87  // Make models for signal (Higgs) and background (Z+jets and QCD)
88  // In real life, this part requires an intelligent modeling
89  // of signal and background -- this is only an example.
90 
91  // set range of observable
92  Double_t lowRange = 0., highRange = 200.;
93 
94  // make a RooRealVar for the observables
95  RooRealVar invMass("invMass", "M_{inv}", lowRange, highRange, "GeV");
96  RooRealVar isolation("isolation", "isolation", 0., 20., "GeV");
97 
98  // --------------------------------------
99  // make 2-d model for Z including the invariant mass
100  // distribution and an isolation distribution which we want to
101  // unfold from QCD.
102  std::cout << "make z model" << std::endl;
103  // mass model for Z
104  RooRealVar mZ("mZ", "Z Mass", 91.2, lowRange, highRange);
105  RooRealVar sigmaZ("sigmaZ", "Width of Gaussian", 2, 0, 10, "GeV");
106  RooGaussian mZModel("mZModel", "Z+jets Model", invMass, mZ, sigmaZ);
107  // we know Z mass
108  mZ.setConstant();
109  // we leave the width of the Z free during the fit in this example.
110 
111  // isolation model for Z. Only used to generate toy MC.
112  // the exponential is of the form exp(c*x). If we want
113  // the isolation to decay an e-fold every R GeV, we use
114  // c = -1/R.
115  RooConstVar zIsolDecayConst("zIsolDecayConst", "z isolation decay constant", -1);
116  RooExponential zIsolationModel("zIsolationModel", "z isolation model", isolation, zIsolDecayConst);
117 
118  // make the combined Z model
119  RooProdPdf zModel("zModel", "2-d model for Z", RooArgSet(mZModel, zIsolationModel));
120 
121  // --------------------------------------
122  // make QCD model
123 
124  std::cout << "make qcd model" << std::endl;
125  // mass model for QCD.
126  // the exponential is of the form exp(c*x). If we want
127  // the mass to decay an e-fold every R GeV, we use
128  // c = -1/R.
129  // We can leave this parameter free during the fit.
130  RooRealVar qcdMassDecayConst("qcdMassDecayConst", "Decay const for QCD mass spectrum", -0.01, -100, 100, "1/GeV");
131  RooExponential qcdMassModel("qcdMassModel", "qcd Mass Model", invMass, qcdMassDecayConst);
132 
133  // isolation model for QCD. Only used to generate toy MC
134  // the exponential is of the form exp(c*x). If we want
135  // the isolation to decay an e-fold every R GeV, we use
136  // c = -1/R.
137  RooConstVar qcdIsolDecayConst("qcdIsolDecayConst", "Et resolution constant", -.1);
138  RooExponential qcdIsolationModel("qcdIsolationModel", "QCD isolation model", isolation, qcdIsolDecayConst);
139 
140  // make the 2-d model
141  RooProdPdf qcdModel("qcdModel", "2-d model for QCD", RooArgSet(qcdMassModel, qcdIsolationModel));
142 
143  // --------------------------------------
144  // combined model
145 
146  // These variables represent the number of Z or QCD events
147  // They will be fitted.
148  RooRealVar zYield("zYield", "fitted yield for Z", 50, 0., 1000);
149  RooRealVar qcdYield("qcdYield", "fitted yield for QCD", 100, 0., 1000);
150 
151  // now make the combined model
152  std::cout << "make full model" << std::endl;
153  RooAddPdf model("model", "z+qcd background models", RooArgList(zModel, qcdModel), RooArgList(zYield, qcdYield));
154 
155  // interesting for debugging and visualizing the model
156  model.graphVizTree("fullModel.dot");
157 
158  std::cout << "import model" << std::endl;
159 
160  ws->import(model);
161 }
162 
163 //____________________________________
164 void AddData(RooWorkspace *ws)
165 {
166  // Add a toy dataset
167 
168  // how many events do we want?
169  Int_t nEvents = 1000;
170 
171  // get what we need out of the workspace to make toy data
172  RooAbsPdf *model = ws->pdf("model");
173  RooRealVar *invMass = ws->var("invMass");
174  RooRealVar *isolation = ws->var("isolation");
175 
176  // make the toy data
177  std::cout << "make data set and import to workspace" << std::endl;
178  RooDataSet *data = model->generate(RooArgSet(*invMass, *isolation), nEvents);
179 
180  // import data into workspace
181  ws->import(*data, Rename("data"));
182 }
183 
184 //____________________________________
185 void DoSPlot(RooWorkspace *ws)
186 {
187  std::cout << "Calculate sWeights" << std::endl;
188 
189  // get what we need out of the workspace to do the fit
190  RooAbsPdf *model = ws->pdf("model");
191  RooRealVar *zYield = ws->var("zYield");
192  RooRealVar *qcdYield = ws->var("qcdYield");
193  RooDataSet *data = (RooDataSet *)ws->data("data");
194 
195  // fit the model to the data.
196  model->fitTo(*data, Extended());
197 
198  // The sPlot technique requires that we fix the parameters
199  // of the model that are not yields after doing the fit.
200  //
201  // This *could* be done with the lines below, however this is taken care of
202  // by the RooStats::SPlot constructor (or more precisely the AddSWeight
203  // method).
204  //
205  // RooRealVar* sigmaZ = ws->var("sigmaZ");
206  // RooRealVar* qcdMassDecayConst = ws->var("qcdMassDecayConst");
207  // sigmaZ->setConstant();
208  // qcdMassDecayConst->setConstant();
209 
210  RooMsgService::instance().setSilentMode(true);
211 
212  std::cout << "\n\n------------------------------------------\nThe dataset before creating sWeights:\n";
213  data->Print();
214 
215  RooMsgService::instance().setGlobalKillBelow(RooFit::ERROR);
216 
217  // Now we use the SPlot class to add SWeights to our data set
218  // based on our model and our yield variables
219  RooStats::SPlot *sData = new RooStats::SPlot("sData", "An SPlot", *data, model, RooArgList(*zYield, *qcdYield));
220 
221  std::cout << "\n\nThe dataset after creating sWeights:\n";
222  data->Print();
223 
224  // Check that our weights have the desired properties
225 
226  std::cout << "\n\n------------------------------------------\n\nCheck SWeights:" << std::endl;
227 
228  std::cout << std::endl
229  << "Yield of Z is\t" << zYield->getVal() << ". From sWeights it is "
230  << sData->GetYieldFromSWeight("zYield") << std::endl;
231 
232  std::cout << "Yield of QCD is\t" << qcdYield->getVal() << ". From sWeights it is "
233  << sData->GetYieldFromSWeight("qcdYield") << std::endl
234  << std::endl;
235 
236  for (Int_t i = 0; i < 10; i++) {
237  std::cout << "z Weight for event " << i << std::right << std::setw(12) << sData->GetSWeight(i, "zYield") << " qcd Weight"
238  << std::setw(12) << sData->GetSWeight(i, "qcdYield") << " Total Weight" << std::setw(12) << sData->GetSumOfEventSWeight(i)
239  << std::endl;
240  }
241 
242  std::cout << std::endl;
243 
244  // import this new dataset with sWeights
245  std::cout << "import new dataset with sWeights" << std::endl;
246  ws->import(*data, Rename("dataWithSWeights"));
247 
248  RooMsgService::instance().setGlobalKillBelow(RooFit::INFO);
249 }
250 
251 void MakePlots(RooWorkspace *ws)
252 {
253 
254  // Here we make plots of the discriminating variable (invMass) after the fit
255  // and of the control variable (isolation) after unfolding with sPlot.
256  std::cout << "make plots" << std::endl;
257 
258  // make our canvas
259  TCanvas *cdata = new TCanvas("sPlot", "sPlot demo", 400, 600);
260  cdata->Divide(1, 3);
261 
262  // get what we need out of the workspace
263  RooAbsPdf *model = ws->pdf("model");
264  RooAbsPdf *zModel = ws->pdf("zModel");
265  RooAbsPdf *qcdModel = ws->pdf("qcdModel");
266 
267  RooRealVar *isolation = ws->var("isolation");
268  RooRealVar *invMass = ws->var("invMass");
269 
270  // note, we get the dataset with sWeights
271  RooDataSet *data = (RooDataSet *)ws->data("dataWithSWeights");
272 
273  // this shouldn't be necessary, need to fix something with workspace
274  // do this to set parameters back to their fitted values.
275 // model->fitTo(*data, Extended());
276 
277  // plot invMass for data with full model and individual components overlaid
278  // TCanvas* cdata = new TCanvas();
279  cdata->cd(1);
280  RooPlot *frame = invMass->frame();
281  data->plotOn(frame);
282  model->plotOn(frame, Name("FullModel"));
283  model->plotOn(frame, Components(*zModel), LineStyle(kDashed), LineColor(kRed), Name("ZModel"));
284  model->plotOn(frame, Components(*qcdModel), LineStyle(kDashed), LineColor(kGreen), Name("QCDModel"));
285 
286  TLegend leg(0.11, 0.5, 0.5, 0.8);
287  leg.AddEntry(frame->findObject("FullModel"), "Full model", "L");
288  leg.AddEntry(frame->findObject("ZModel"), "Z model", "L");
289  leg.AddEntry(frame->findObject("QCDModel"), "QCD model", "L");
290  leg.SetBorderSize(0);
291  leg.SetFillStyle(0);
292 
293  frame->SetTitle("Fit of model to discriminating variable");
294  frame->Draw();
295  leg.DrawClone();
296 
297  // Now use the sWeights to show isolation distribution for Z and QCD.
298  // The SPlot class can make this easier, but here we demonstrate in more
299  // detail how the sWeights are used. The SPlot class should make this
300  // very easy and needs some more development.
301 
302  // Plot isolation for Z component.
303  // Do this by plotting all events weighted by the sWeight for the Z component.
304  // The SPlot class adds a new variable that has the name of the corresponding
305  // yield + "_sw".
306  cdata->cd(2);
307 
308  // create weighted data set
309  RooDataSet *dataw_z = new RooDataSet(data->GetName(), data->GetTitle(), data, *data->get(), 0, "zYield_sw");
310 
311  RooPlot *frame2 = isolation->frame();
312  // Since the data are weighted, we use SumW2 to compute the errors.
313  dataw_z->plotOn(frame2, DataError(RooAbsData::SumW2));
314 
315  frame2->SetTitle("Isolation distribution with s weights to project out Z");
316  frame2->Draw();
317 
318  // Plot isolation for QCD component.
319  // Eg. plot all events weighted by the sWeight for the QCD component.
320  // The SPlot class adds a new variable that has the name of the corresponding
321  // yield + "_sw".
322  cdata->cd(3);
323  RooDataSet *dataw_qcd = new RooDataSet(data->GetName(), data->GetTitle(), data, *data->get(), 0, "qcdYield_sw");
324  RooPlot *frame3 = isolation->frame();
325  dataw_qcd->plotOn(frame3, DataError(RooAbsData::SumW2));
326 
327  frame3->SetTitle("Isolation distribution with s weights to project out QCD");
328  frame3->Draw();
329 
330  // cdata->SaveAs("SPlot.gif");
331 }