CMS 3D CMS Logo

GenericTnPFitter.h
Go to the documentation of this file.
1 #include "RooGaussian.h"
2 #include "RooChebychev.h"
3 #include "RooVoigtian.h"
4 #include "RooExponential.h"
5 #include "RooRealVar.h"
6 #include "RooFormulaVar.h"
7 #include "RooDataHist.h"
8 #include "RooAddPdf.h"
9 #include "RooGlobalFunc.h"
10 #include "RooCategory.h"
11 #include "RooSimultaneous.h"
12 #include "TFile.h"
13 #include "TH1F.h"
14 #include "TH2F.h"
15 #include "TH3F.h"
16 #include "TProfile2D.h"
17 #include "TCanvas.h"
18 #include "RooPlot.h"
19 
20 namespace dqmTnP {
21 
23  protected:
24  RooRealVar mass;
25  RooRealVar mean;
26  double expectedMean;
27  RooRealVar sigma;
28  double expectedSigma;
29  RooRealVar efficiency;
30  RooRealVar nSignalAll;
31  RooFormulaVar nSignalPass;
32  RooFormulaVar nSignalFail;
33  RooRealVar nBackgroundFail;
34  RooRealVar nBackgroundPass;
35  RooCategory category;
36  RooSimultaneous simPdf;
37  RooDataHist* data;
38  double chi2;
39  bool verbose;
40 
41  public:
42  AbstractFitter(bool verbose_ = false)
43  : mass("mass", "mass", 0., 100., "GeV"),
44  mean("mean", "mean", 0., 100., "GeV"),
45  sigma("sigma", "sigma", 0., 100., "GeV"),
46  efficiency("efficiency", "efficiency", 0.5, 0.0, 1.0),
47  nSignalAll("nSignalAll", "nSignalAll", 0., 1e10),
48  nSignalPass("nSignalPass", "nSignalAll*efficiency", RooArgList(nSignalAll, efficiency)),
49  nSignalFail("nSignalFail", "nSignalAll*(1-efficiency)", RooArgList(nSignalAll, efficiency)),
50  nBackgroundFail("nBackgroundFail", "nBackgroundFail", 0., 1e10),
51  nBackgroundPass("nBackgroundPass", "nBackgroundPass", 0., 1e10),
52  category("category", "category"),
53  simPdf("simPdf", "simPdf", category),
54  data(nullptr),
55  verbose(verbose_) {
56  //turn on/off default messaging of roofit
57  RooMsgService::instance().setSilentMode(!verbose ? kTRUE : kFALSE);
58  for (int i = 0; i < RooMsgService::instance().numStreams(); i++) {
59  RooMsgService::instance().setStreamStatus(i, verbose ? kTRUE : kFALSE);
60  }
61  category.defineType("pass");
62  category.defineType("fail");
63  };
64  virtual ~AbstractFitter() = default;
65  ;
66  void setup(double expectedMean_, double massLow, double massHigh, double expectedSigma_) {
67  expectedMean = expectedMean_;
68  expectedSigma = expectedSigma_;
69  mass.setRange(massLow, massHigh);
70  mean.setRange(massLow, massHigh);
71  }
72  virtual void fit(TH1* num, TH1* den) = 0;
73  double getEfficiency() { return efficiency.getVal(); }
74  double getEfficiencyError() { return efficiency.getError(); }
75  double getChi2() { return chi2; }
76  void savePlot(const TString& name) {
77  using namespace RooFit;
78  RooPlot* frame = mass.frame(Name(name), Title("Failing and Passing Probe Distributions"));
79  data->plotOn(frame, Cut("category==category::pass"), LineColor(kGreen), MarkerColor(kGreen));
80  data->plotOn(frame, Cut("category==category::fail"), LineColor(kRed), MarkerColor(kRed));
81  simPdf.plotOn(frame, Slice(category, "pass"), ProjWData(category, *data), LineColor(kGreen));
82  simPdf.plotOn(frame, Slice(category, "fail"), ProjWData(category, *data), LineColor(kRed));
83  simPdf.paramOn(frame, Layout(0.58, 0.99, 0.99));
84  data->statOn(frame, Layout(0.70, 0.99, 0.5));
85  frame->Write();
86  delete frame;
87  }
88 
90  TH3* pass, TH3* all, int massDimension, TProfile2D*& eff, TProfile2D*& effChi2, const TString& plotName = "") {
91  //sort out the TAxis
92  TAxis *par1Axis, *par2Axis, *massAxis;
93  int par1C, par2C, massC;
94  if (massDimension == 1) {
95  massAxis = all->GetXaxis();
96  massC = 1;
97  par1Axis = all->GetYaxis();
98  par1C = all->GetXaxis()->GetNbins() + 2;
99  par2Axis = all->GetZaxis();
100  par2C = (all->GetXaxis()->GetNbins() + 2) * (all->GetYaxis()->GetNbins() + 2);
101  } else if (massDimension == 2) {
102  par1Axis = all->GetXaxis();
103  par1C = 1;
104  massAxis = all->GetYaxis();
105  massC = all->GetXaxis()->GetNbins() + 2;
106  par2Axis = all->GetZaxis();
107  par2C = (all->GetXaxis()->GetNbins() + 2) * (all->GetYaxis()->GetNbins() + 2);
108  } else if (massDimension == 3) {
109  par1Axis = all->GetXaxis();
110  par1C = 1;
111  par2Axis = all->GetYaxis();
112  par2C = all->GetXaxis()->GetNbins() + 2;
113  massAxis = all->GetZaxis();
114  massC = (all->GetXaxis()->GetNbins() + 2) * (all->GetYaxis()->GetNbins() + 2);
115  } else {
116  return "massDimension > 3 !, skipping...";
117  }
118 
119  //create eff and effChi2 TProfiles
120  if (!par1Axis || !par2Axis)
121  return "No par1Axis or par2Axis!";
122  if (par1Axis->GetXbins()->GetSize() == 0 && par2Axis->GetXbins()->GetSize() == 0) {
123  eff = new TProfile2D("efficiency",
124  "efficiency",
125  par1Axis->GetNbins(),
126  par1Axis->GetXmin(),
127  par1Axis->GetXmax(),
128  par2Axis->GetNbins(),
129  par2Axis->GetXmin(),
130  par2Axis->GetXmax());
131  } else if (par1Axis->GetXbins()->GetSize() == 0) {
132  eff = new TProfile2D("efficiency",
133  "efficiency",
134  par1Axis->GetNbins(),
135  par1Axis->GetXmin(),
136  par1Axis->GetXmax(),
137  par2Axis->GetNbins(),
138  par2Axis->GetXbins()->GetArray());
139  } else if (par2Axis->GetXbins()->GetSize() == 0) {
140  eff = new TProfile2D("efficiency",
141  "efficiency",
142  par1Axis->GetNbins(),
143  par1Axis->GetXbins()->GetArray(),
144  par2Axis->GetNbins(),
145  par2Axis->GetXmin(),
146  par2Axis->GetXmax());
147  } else {
148  eff = new TProfile2D("efficiency",
149  "efficiency",
150  par1Axis->GetNbins(),
151  par1Axis->GetXbins()->GetArray(),
152  par2Axis->GetNbins(),
153  par2Axis->GetXbins()->GetArray());
154  }
155  eff->SetTitle("");
156  eff->SetXTitle(par1Axis->GetTitle());
157  eff->SetYTitle(par2Axis->GetTitle());
158  eff->SetStats(kFALSE);
159  effChi2 = (TProfile2D*)eff->Clone("efficiencyChi2");
160  eff->SetZTitle("Efficiency");
161  eff->SetOption("colztexte");
162  eff->GetZaxis()->SetRangeUser(-0.001, 1.001);
163  effChi2->SetZTitle("Chi^2/NDF");
164  effChi2->SetOption("colztext");
165 
166  //create the 1D mass distribution container histograms
167  TH1D* all1D = (massAxis->GetXbins()->GetSize() == 0)
168  ? new TH1D("all1D", "all1D", massAxis->GetNbins(), massAxis->GetXmin(), massAxis->GetXmax())
169  : new TH1D("all1D", "all1D", massAxis->GetNbins(), massAxis->GetXbins()->GetArray());
170  auto* pass1D = (TH1D*)all1D->Clone("pass1D");
171 
172  //for each parameter bin fit the mass distributions
173  for (int par1 = 1; par1 <= par1Axis->GetNbins(); par1++) {
174  for (int par2 = 1; par2 <= par2Axis->GetNbins(); par2++) {
175  for (int mass = 1; mass <= massAxis->GetNbins(); mass++) {
176  int index = par1 * par1C + par2 * par2C + mass * massC;
177  all1D->SetBinContent(mass, all->GetBinContent(index));
178  pass1D->SetBinContent(mass, pass->GetBinContent(index));
179  }
180  fit(pass1D, all1D);
181  int index = par1 + par2 * (par1Axis->GetNbins() + 2);
182  eff->SetBinContent(index, getEfficiency());
183  eff->SetBinEntries(index, 1);
184  eff->SetBinError(index,
186  effChi2->SetBinContent(index, getChi2());
187  effChi2->SetBinEntries(index, 1);
188  if (plotName != "") {
189  savePlot(TString::Format("%s_%d_%d", plotName.Data(), par1, par2));
190  }
191  }
192  }
193  delete all1D;
194  delete pass1D;
195  return ""; //OK
196  }
197 
199  TH2* pass, TH2* all, int massDimension, TProfile*& eff, TProfile*& effChi2, const TString& plotName = "") {
200  //sort out the TAxis
201  TAxis *par1Axis, *massAxis;
202  int par1C, massC;
203  if (massDimension == 1) {
204  massAxis = all->GetXaxis();
205  massC = 1;
206  par1Axis = all->GetYaxis();
207  par1C = all->GetXaxis()->GetNbins() + 2;
208  } else if (massDimension == 2) {
209  par1Axis = all->GetXaxis();
210  par1C = 1;
211  massAxis = all->GetYaxis();
212  massC = all->GetXaxis()->GetNbins() + 2;
213  } else {
214  return "massDimension > 2 !, skipping...";
215  }
216 
217  //create eff and effChi2 TProfiles
218  if (!par1Axis)
219  return "No par1Axis!";
220  eff =
221  (par1Axis->GetXbins()->GetSize() == 0)
222  ? new TProfile("efficiency", "efficiency", par1Axis->GetNbins(), par1Axis->GetXmin(), par1Axis->GetXmax())
223  : new TProfile("efficiency", "efficiency", par1Axis->GetNbins(), par1Axis->GetXbins()->GetArray());
224  eff->SetTitle("");
225  eff->SetXTitle(par1Axis->GetTitle());
226  eff->SetLineColor(2);
227  eff->SetLineWidth(2);
228  eff->SetMarkerStyle(20);
229  eff->SetMarkerSize(0.8);
230  eff->SetStats(kFALSE);
231  effChi2 = (TProfile*)eff->Clone("efficiencyChi2");
232  eff->SetYTitle("Efficiency");
233  eff->SetOption("PE");
234  eff->GetYaxis()->SetRangeUser(-0.001, 1.001);
235  effChi2->SetYTitle("Chi^2/NDF");
236  effChi2->SetOption("HIST");
237 
238  //create the 1D mass distribution container histograms
239  TH1D* all1D = (massAxis->GetXbins()->GetSize() == 0)
240  ? new TH1D("all1D", "all1D", massAxis->GetNbins(), massAxis->GetXmin(), massAxis->GetXmax())
241  : new TH1D("all1D", "all1D", massAxis->GetNbins(), massAxis->GetXbins()->GetArray());
242  auto* pass1D = (TH1D*)all1D->Clone("pass1D");
243 
244  //for each parameter bin fit the mass distributions
245  for (int par1 = 1; par1 <= par1Axis->GetNbins(); par1++) {
246  for (int mass = 1; mass <= massAxis->GetNbins(); mass++) {
247  int index = par1 * par1C + mass * massC;
248  all1D->SetBinContent(mass, all->GetBinContent(index));
249  pass1D->SetBinContent(mass, pass->GetBinContent(index));
250  }
251  fit(pass1D, all1D);
252  int index = par1;
253  eff->SetBinContent(index, getEfficiency());
254  eff->SetBinEntries(index, 1);
256  effChi2->SetBinContent(index, getChi2());
257  effChi2->SetBinEntries(index, 1);
258  if (plotName != "") {
259  savePlot(TString::Format("%s_%d", plotName.Data(), par1));
260  }
261  }
262  delete all1D;
263  delete pass1D;
264  return ""; //OK
265  }
266  };
267 
268  //concrete fitter: Gaussian signal plus linear background
270  protected:
271  RooGaussian gaussian;
272  RooRealVar slopeFail;
273  RooChebychev linearFail;
274  RooRealVar slopePass;
275  RooChebychev linearPass;
276  RooAddPdf pdfFail;
277  RooAddPdf pdfPass;
278 
279  public:
282  gaussian("gaussian", "gaussian", mass, mean, sigma),
283  slopeFail("slopeFail", "slopeFail", 0., -1., 1.),
284  linearFail("linearFail", "linearFail", mass, slopeFail),
285  slopePass("slopePass", "slopePass", 0., -1., 1.),
286  linearPass("linearPass", "linearPass", mass, slopePass),
287  pdfFail("pdfFail", "pdfFail", RooArgList(gaussian, linearFail), RooArgList(nSignalFail, nBackgroundFail)),
288  pdfPass("pdfPass", "pdfPass", RooArgList(gaussian, linearPass), RooArgList(nSignalPass, nBackgroundPass)) {
289  simPdf.addPdf(pdfFail, "fail");
290  simPdf.addPdf(pdfPass, "pass");
291  };
292  ~GaussianPlusLinearFitter() override = default;
293  ;
294  void fit(TH1* pass, TH1* all) override {
295  using namespace RooFit;
296  all->Add(pass, -1);
297  TH1*& fail = all;
298  if (!data)
299  delete data;
300  data = new RooDataHist("data", "data", mass, Index(category), Import("fail", *fail), Import("pass", *pass));
301  if (pass->Integral() + fail->Integral() < 5) {
302  efficiency.setVal(0.5);
303  efficiency.setError(0.5);
304  chi2 = 0;
305  return;
306  }
307  mean.setVal(expectedMean);
308  sigma.setVal(expectedSigma);
309  efficiency.setVal(pass->Integral() / (pass->Integral() + fail->Integral()));
310  nSignalAll.setVal(0.5 * (fail->Integral() + pass->Integral()));
311  nBackgroundFail.setVal(0.5 * fail->Integral());
312  nBackgroundPass.setVal(0.5 * pass->Integral());
313  slopeFail.setVal(0.);
314  slopePass.setVal(0.);
315  if (verbose) {
316  simPdf.fitTo(*data);
317  } else {
318  simPdf.fitTo(*data, Verbose(kFALSE), PrintLevel(-1), Warnings(kFALSE), PrintEvalErrors(-1));
319  }
320  RooDataHist dataFail("fail", "fail", mass, fail);
321  RooDataHist dataPass("pass", "pass", mass, pass);
322  using AbsRealPtr = std::unique_ptr<RooAbsReal>;
323  const double chi2Fail = AbsRealPtr(pdfFail.createChi2(dataFail, DataError(RooAbsData::Poisson)))->getVal();
324  const double chi2Pass = AbsRealPtr(pdfPass.createChi2(dataPass, DataError(RooAbsData::Poisson)))->getVal();
325  chi2 = (chi2Fail + chi2Pass) / (2 * pass->GetNbinsX() - 8);
326  if (chi2 > 3) {
327  efficiency.setVal(0.5);
328  efficiency.setError(0.5);
329  }
330  }
331  };
332 
333  //concrete fitter: voigtian signal plus exponential background
335  protected:
336  RooRealVar width;
337  RooVoigtian voigtian;
338  RooRealVar slopeFail;
339  RooExponential exponentialFail;
340  RooRealVar slopePass;
341  RooExponential exponentialPass;
342  RooAddPdf pdfFail;
343  RooAddPdf pdfPass;
344 
345  public:
348  width("width", "width", 2.5, "GeV"),
349  voigtian("voigtian", "voigtian", mass, mean, width, sigma),
350  slopeFail("slopeFail", "slopeFail", 0., -1., 0.),
351  exponentialFail("linearFail", "linearFail", mass, slopeFail),
352  slopePass("slopePass", "slopePass", 0., -1., 0.),
353  exponentialPass("linearPass", "linearPass", mass, slopePass),
354  pdfFail(
355  "pdfFail", "pdfFail", RooArgList(voigtian, exponentialFail), RooArgList(nSignalFail, nBackgroundFail)),
356  pdfPass(
357  "pdfPass", "pdfPass", RooArgList(voigtian, exponentialPass), RooArgList(nSignalPass, nBackgroundPass)) {
358  width.setConstant(kTRUE);
359  simPdf.addPdf(pdfFail, "fail");
360  simPdf.addPdf(pdfPass, "pass");
361  };
362  ~VoigtianPlusExponentialFitter() override = default;
363  ;
364  void setup(double expectedMean_, double massLow, double massHigh, double expectedSigma_, double width_) {
365  expectedMean = expectedMean_;
366  expectedSigma = expectedSigma_;
367  mass.setRange(massLow, massHigh);
368  mean.setRange(massLow, massHigh);
369  width.setVal(width_);
370  }
371  void fit(TH1* pass, TH1* all) override {
372  using namespace RooFit;
373  all->Add(pass, -1);
374  TH1*& fail = all;
375  if (!data)
376  delete data;
377  data = new RooDataHist("data", "data", mass, Index(category), Import("fail", *fail), Import("pass", *pass));
378  if (pass->Integral() + fail->Integral() < 5) {
379  efficiency.setVal(0.5);
380  efficiency.setError(0.5);
381  chi2 = 0;
382  return;
383  }
384  mean.setVal(expectedMean);
385  sigma.setVal(expectedSigma);
386  efficiency.setVal(pass->Integral() / (pass->Integral() + fail->Integral()));
387  nSignalAll.setVal(0.5 * (fail->Integral() + pass->Integral()));
388  nBackgroundFail.setVal(0.5 * fail->Integral());
389  nBackgroundPass.setVal(0.5 * pass->Integral());
390  slopeFail.setVal(0.);
391  slopePass.setVal(0.);
392  if (verbose) {
393  simPdf.fitTo(*data);
394  } else {
395  simPdf.fitTo(*data, Verbose(kFALSE), PrintLevel(-1), Warnings(kFALSE), PrintEvalErrors(-1));
396  }
397  RooDataHist dataFail("fail", "fail", mass, fail);
398  RooDataHist dataPass("pass", "pass", mass, pass);
399  using AbsRealPtr = std::unique_ptr<RooAbsReal>;
400  const double chi2Fail = AbsRealPtr(pdfFail.createChi2(dataFail, DataError(RooAbsData::Poisson)))->getVal();
401  const double chi2Pass = AbsRealPtr(pdfPass.createChi2(dataPass, DataError(RooAbsData::Poisson)))->getVal();
402  chi2 = (chi2Fail + chi2Pass) / (2 * all->GetNbinsX() - 8);
403  if (chi2 > 3) {
404  efficiency.setVal(0.5);
405  efficiency.setError(0.5);
406  }
407  }
408  };
409 
410 } //namespace dqmTnP
def all(container)
workaround iterator generators for ROOT classes
Definition: cmstools.py:25
static PFTauRenderPlugin instance
void setup(double expectedMean_, double massLow, double massHigh, double expectedSigma_)
void savePlot(const TString &name)
void setup(double expectedMean_, double massLow, double massHigh, double expectedSigma_, double width_)
T sqrt(T t)
Definition: SSEVec.h:19
virtual ~AbstractFitter()=default
TString calculateEfficiency(TH3 *pass, TH3 *all, int massDimension, TProfile2D *&eff, TProfile2D *&effChi2, const TString &plotName="")
GaussianPlusLinearFitter(bool verbose=false)
void fit(TH1 *pass, TH1 *all) override
VoigtianPlusExponentialFitter(bool verbose=false)
void fit(TH1 *pass, TH1 *all) override
AbstractFitter(bool verbose_=false)
TString calculateEfficiency(TH2 *pass, TH2 *all, int massDimension, TProfile *&eff, TProfile *&effChi2, const TString &plotName="")
virtual void fit(TH1 *num, TH1 *den)=0
RooSimultaneous simPdf