CMS 3D CMS Logo

DiMuonMassBiasClient.cc
Go to the documentation of this file.
1 // user includes
7 
8 // RooFit includes
9 #include "TCanvas.h"
10 #include "RooAddPdf.h"
11 #include "RooDataHist.h"
12 #include "RooExponential.h"
13 #include "RooGaussian.h"
14 #include "RooPlot.h"
15 #include "RooRealVar.h"
16 #include "RooVoigtian.h"
17 #include "RooCBShape.h"
18 
19 //-----------------------------------------------------------------------------------
21  : TopFolder_(iConfig.getParameter<std::string>("FolderName")),
22  useTH1s_(iConfig.getParameter<bool>("useTH1s")),
23  fitBackground_(iConfig.getParameter<bool>("fitBackground")),
24  useRooCBShape_(iConfig.getParameter<bool>("useRooCBShape")),
25  useRooCMSShape_(iConfig.getParameter<bool>("useRooCMSShape")),
26  debugMode_(iConfig.getParameter<bool>("debugMode")),
27  MEtoHarvest_(iConfig.getParameter<std::vector<std::string>>("MEtoHarvest"))
28 //-----------------------------------------------------------------------------------
29 {
30  edm::LogInfo("DiMuonMassBiasClient") << "DiMuonMassBiasClient::Constructing DiMuonMassBiasClient ";
31 
32  // fill the parameters for the fit
37 
38  if (debugMode_) {
39  edm::LogPrint("DiMuonMassBiasClient")
40  << "mean: " << meanConfig_[0] << " (" << meanConfig_[1] << "," << meanConfig_[2] << ") " << std::endl;
41  edm::LogPrint("DiMuonMassBiasClient")
42  << "width: " << widthConfig_[0] << " (" << widthConfig_[1] << "," << widthConfig_[2] << ")" << std::endl;
43  edm::LogPrint("DiMuonMassBiasClient")
44  << "sigma: " << sigmaConfig_[0] << " (" << sigmaConfig_[1] << "," << sigmaConfig_[2] << ")" << std::endl;
45  }
46 }
47 
48 //-----------------------------------------------------------------------------------
50 //-----------------------------------------------------------------------------------
51 {
52  edm::LogInfo("DiMuonMassBiasClient") << "DiMuonMassBiasClient::Deleting DiMuonMassBiasClient ";
53 }
54 
55 //-----------------------------------------------------------------------------------
57 //-----------------------------------------------------------------------------------
58 {
59  edm::LogInfo("DiMuonMassBiasClient") << "DiMuonMassBiasClient::beginJob done";
60 }
61 
62 //-----------------------------------------------------------------------------------
64 //-----------------------------------------------------------------------------------
65 {
66  edm::LogInfo("DiMuonMassBiasClient") << "DiMuonMassBiasClient:: Begining of Run";
67 }
68 
69 //-----------------------------------------------------------------------------------
71 //-----------------------------------------------------------------------------------
72 {
73  iBooker.setCurrentFolder(TopFolder_ + "/DiMuonMassBiasMonitor/MassBias/Profiles");
74  for (const auto& [key, ME] : harvestTargets_) {
75  if (ME == nullptr) {
76  edm::LogError("DiMuonMassBiasClient") << "could not find MonitorElement for key: " << key << std::endl;
77  continue;
78  }
79 
80  const auto& title = ME->getTitle();
81  const auto& xtitle = ME->getAxisTitle(1);
82  const auto& ytitle = ME->getAxisTitle(2);
83 
84  const auto& nxbins = ME->getNbinsX();
85  const auto& xmin = ME->getAxisMin(1);
86  const auto& xmax = ME->getAxisMax(1);
87 
88  MonitorElement* meanToBook =
89  iBooker.book1D(("Mean" + key), (title + ";#LT M_{#mu^{-}#mu^{+}} #GT [GeV];" + ytitle), nxbins, xmin, xmax);
90  meanHistos_.insert({key, meanToBook});
91 
92  MonitorElement* sigmaToBook =
93  iBooker.book1D(("Sigma" + key), (title + ";" + xtitle + ";" + "#sigma of " + ytitle), nxbins, xmin, xmax);
94  widthHistos_.insert({key, sigmaToBook});
95  }
96 }
97 
98 //-----------------------------------------------------------------------------------
100 //-----------------------------------------------------------------------------------
101 {
102  std::string inFolder = TopFolder_ + "/DiMuonMassBiasMonitor/MassBias/";
103 
104  //loop on the list of histograms to harvest
105  for (const auto& hname : MEtoHarvest_) {
106  MonitorElement* toHarvest = iGetter.get(inFolder + hname);
107 
108  if (toHarvest == nullptr) {
109  edm::LogError("DiMuonMassBiasClient") << "could not find input MonitorElement: " << inFolder + hname << std::endl;
110  continue;
111  }
112 
113  harvestTargets_.insert({hname, toHarvest});
114  }
115 }
116 
117 //-----------------------------------------------------------------------------------
118 void DiMuonMassBiasClient::fitAndFillProfile(std::pair<std::string, MonitorElement*> toHarvest,
119  DQMStore::IBooker& iBooker)
120 //-----------------------------------------------------------------------------------
121 {
122  const auto& key = toHarvest.first;
123  const auto& ME = toHarvest.second;
124 
125  if (debugMode_)
126  edm::LogPrint("DiMuonMassBiasClient") << "dealing with key: " << key << std::endl;
127 
128  if (ME == nullptr) {
129  edm::LogError("DiMuonMassBiasClient") << "could not find MonitorElement for key: " << key << std::endl;
130  return;
131  }
132 
133  const auto& title = ME->getTitle();
134  const auto& xtitle = ME->getAxisTitle(1);
135  const auto& ytitle = ME->getAxisTitle(2);
136 
137  const auto& nxbins = ME->getNbinsX();
138  const auto& xmin = ME->getAxisMin(1);
139  const auto& xmax = ME->getAxisMax(1);
140 
141  TProfile* p_mean = new TProfile(("Mean" + key).c_str(),
142  (title + ";" + xtitle + ";#LT M_{#mu^{-}#mu^{+}} #GT [GeV]").c_str(),
143  nxbins,
144  xmin,
145  xmax,
146  "g");
147 
148  TProfile* p_width = new TProfile(
149  ("Sigma" + key).c_str(), (title + ";" + xtitle + ";#sigma of " + ytitle).c_str(), nxbins, xmin, xmax, "g");
150 
151  p_mean->Sumw2();
152  p_width->Sumw2();
153 
154  TH2F* bareHisto = ME->getTH2F();
155  for (int bin = 1; bin <= nxbins; bin++) {
156  const auto& xaxis = bareHisto->GetXaxis();
157  const auto& low_edge = xaxis->GetBinLowEdge(bin);
158  const auto& high_edge = xaxis->GetBinUpEdge(bin);
159 
160  if (debugMode_)
161  edm::LogPrint("DiMuonMassBiasClient") << "dealing with bin: " << bin << " range: (" << std::setprecision(2)
162  << low_edge << "," << std::setprecision(2) << high_edge << ")";
163 
164  TH1D* Proj = bareHisto->ProjectionY(Form("%s_proj_%i", key.c_str(), bin), bin, bin);
165  Proj->SetTitle(Form("%s #in (%.2f,%.2f), bin: %i", Proj->GetTitle(), low_edge, high_edge, bin));
166 
168 
169  if (results.isInvalid()) {
170  edm::LogWarning("DiMuonMassBiasClient") << "the current bin has invalid data" << std::endl;
171  continue;
172  }
173 
174  // fill the mean profiles
175  const Measurement1D& bias = results.getBias();
176 
177  // ============================================= DISCLAIMER ================================================
178  // N.B. this is sort of a hack in order to fill arbitrarily both central values and error bars of a TProfile.
179  // Choosing the option "g" in the constructor the bin error will be 1/sqrt(W(j)), where W(j) is the sum of weights.
180  // Filling the sum of weights with the 1 / err^2, the bin error automatically becomes "err".
181  // In order to avoid the central value to be shifted, that's divided by 1 / err^2 as well.
182  // For more information, please consult the https://root.cern.ch/doc/master/classTProfile.html
183 
184  p_mean->SetBinContent(bin, bias.value() / (bias.error() * bias.error()));
185  p_mean->SetBinEntries(bin, 1. / (bias.error() * bias.error()));
186 
187  if (debugMode_)
188  LogDebug("DiMuonBassBiasClient") << " Bin: " << bin << " value: " << bias.value() << " from profile ( "
189  << p_mean->GetBinContent(bin) << ") - error: " << bias.error()
190  << " from profile ( " << p_mean->GetBinError(bin) << " )";
191 
192  // fill the width profiles
193  const Measurement1D& width = results.getWidth();
194 
195  // see discussion above
196  p_width->SetBinContent(bin, width.value() / (width.error() * width.error()));
197  p_width->SetBinEntries(bin, 1. / (width.error() * width.error()));
198  }
199 
200  // now book the profiles
201  iBooker.setCurrentFolder(TopFolder_ + "/DiMuonMassBiasMonitor/MassBias/Profiles");
202  MonitorElement* meanToBook = iBooker.bookProfile(p_mean->GetName(), p_mean);
203  meanProfiles_.insert({key, meanToBook});
204 
205  MonitorElement* sigmaToBook = iBooker.bookProfile(p_width->GetName(), p_width);
206  widthProfiles_.insert({key, sigmaToBook});
207 
208  delete p_mean;
209  delete p_width;
210 }
211 
212 //-----------------------------------------------------------------------------------
213 void DiMuonMassBiasClient::fitAndFillHisto(std::pair<std::string, MonitorElement*> toHarvest,
214  DQMStore::IBooker& iBooker)
215 //-----------------------------------------------------------------------------------
216 {
217  const auto& key = toHarvest.first;
218  const auto& ME = toHarvest.second;
219 
220  if (debugMode_)
221  edm::LogPrint("DiMuonMassBiasClient") << "dealing with key: " << key << std::endl;
222 
223  if (ME == nullptr) {
224  edm::LogError("DiMuonMassBiasClient") << "could not find MonitorElement for key: " << key << std::endl;
225  return;
226  }
227 
228  TH2F* bareHisto = ME->getTH2F();
229  for (int bin = 1; bin <= ME->getNbinsX(); bin++) {
230  const auto& xaxis = bareHisto->GetXaxis();
231  const auto& low_edge = xaxis->GetBinLowEdge(bin);
232  const auto& high_edge = xaxis->GetBinUpEdge(bin);
233 
234  if (debugMode_)
235  edm::LogPrint("DiMuonMassBiasClient") << "dealing with bin: " << bin << " range: (" << std::setprecision(2)
236  << low_edge << "," << std::setprecision(2) << high_edge << ")";
237  TH1D* Proj = bareHisto->ProjectionY(Form("%s_proj_%i", key.c_str(), bin), bin, bin);
238  Proj->SetTitle(Form("%s #in (%.2f,%.2f), bin: %i", Proj->GetTitle(), low_edge, high_edge, bin));
239 
241 
242  if (results.isInvalid()) {
243  edm::LogWarning("DiMuonMassBiasClient") << "the current bin has invalid data" << std::endl;
244  continue;
245  }
246 
247  // fill the mean profiles
248  const Measurement1D& bias = results.getBias();
249  meanHistos_[key]->setBinContent(bin, bias.value());
250  meanHistos_[key]->setBinError(bin, bias.error());
251 
252  // fill the width profiles
253  const Measurement1D& width = results.getWidth();
254  widthHistos_[key]->setBinContent(bin, width.value());
255  widthHistos_[key]->setBinError(bin, width.error());
256  }
257 }
258 
259 //-----------------------------------------------------------------------------------
261 //-----------------------------------------------------------------------------------
262 {
263  edm::LogInfo("DiMuonMassBiasClient") << "DiMuonMassBiasClient::endLuminosityBlock";
264 
265  getMEsToHarvest(igetter);
266 
267  // book the histograms upfront
268  if (useTH1s_) {
269  bookMEs(ibooker);
270  }
271 
272  for (const auto& element : harvestTargets_) {
273  if (!useTH1s_) {
274  // if using profiles
275  this->fitAndFillProfile(element, ibooker);
276  } else {
277  // if using histograms
278  this->fitAndFillHisto(element, ibooker);
279  }
280  }
281 }
282 
283 //-----------------------------------------------------------------------------------
285 //-----------------------------------------------------------------------------------
286 {
287  if (hist->GetEntries() < diMuonMassBias::minimumHits) {
288  edm::LogWarning("DiMuonMassBiasClient") << " Input histogram:" << hist->GetName() << " has not enough entries ("
289  << hist->GetEntries() << ") for a meaningful Voigtian fit!\n"
290  << "Skipping!";
291 
292  return diMuonMassBias::fitOutputs(Measurement1D(0., 0.), Measurement1D(0., 0.));
293  }
294 
295  TCanvas* c1 = new TCanvas();
296  if (debugMode_) {
297  c1->Clear();
298  c1->SetLeftMargin(0.15);
299  c1->SetRightMargin(0.10);
300  }
301 
302  // silence messages
303  RooMsgService::instance().setGlobalKillBelow(RooFit::FATAL);
304 
305  Double_t xmin = hist->GetXaxis()->GetXmin();
306  Double_t xmax = hist->GetXaxis()->GetXmax();
307 
308  if (debugMode_) {
309  edm::LogPrint("DiMuonMassBiasClient") << "fitting range: (" << xmin << "-" << xmax << ")" << std::endl;
310  }
311 
312  RooRealVar InvMass("InvMass", "di-muon mass M(#mu^{+}#mu^{-}) [GeV]", xmin, xmax);
313  std::unique_ptr<RooPlot> frame{InvMass.frame()};
314  RooDataHist datahist("datahist", "datahist", InvMass, RooFit::Import(*hist));
315  datahist.plotOn(frame.get());
316 
317  // parameters of the Voigtian
318  RooRealVar mean("#mu", "mean", meanConfig_[0], meanConfig_[1], meanConfig_[2]); //90.0, 60.0, 120.0 (for Z)
319  RooRealVar width("width", "width", widthConfig_[0], widthConfig_[1], widthConfig_[2]); // 5.0, 0.0, 120.0 (for Z)
320  RooRealVar sigma("#sigma", "sigma", sigmaConfig_[0], sigmaConfig_[1], sigmaConfig_[2]); // 5.0, 0.0, 120.0 (for Z)
321  RooVoigtian voigt("voigt", "voigt", InvMass, mean, width, sigma);
322 
323  // parameters of the Crystal-ball
324  RooRealVar peakCB("peakCB", "peakCB", meanConfig_[0], meanConfig_[1], meanConfig_[2]);
325  RooRealVar sigmaCB("#sigma", "sigma", sigmaConfig_[0], sigmaConfig_[1], sigmaConfig_[2]);
326  RooRealVar alphaCB("#alpha", "alpha", 1., 0., 10.);
327  RooRealVar nCB("n", "n", 1., 0., 100.);
328  RooCBShape crystalball("crystalball", "crystalball", InvMass, peakCB, sigmaCB, alphaCB, nCB);
329 
330  // for the simple background fit
331  RooRealVar lambda("#lambda", "slope", 0., -50., 50.);
332  RooExponential expo("expo", "expo", InvMass, lambda);
333 
334  // for the more refined background fit
335  RooRealVar exp_alpha("#alpha", "alpha", 40.0, 20.0, 160.0);
336  RooRealVar exp_beta("#beta", "beta", 0.05, 0.0, 2.0);
337  RooRealVar exp_gamma("#gamma", "gamma", 0.02, 0.0, 0.1);
338  RooRealVar exp_peak("peak", "peak", meanConfig_[0]);
339  RooCMSShape exp_pdf("exp_pdf", "bkg shape", InvMass, exp_alpha, exp_beta, exp_gamma, exp_peak);
340 
341  // define the signal and background fractions
342  RooRealVar b("N_{b}", "Number of background events", 0, hist->GetEntries() / 10.);
343  RooRealVar s("N_{s}", "Number of signal events", 0, hist->GetEntries());
344 
345  if (fitBackground_) {
346  RooArgList listPdf;
347  if (useRooCBShape_) {
348  if (useRooCMSShape_) {
349  // crystal-ball + CMS-shape fit
350  listPdf.add(crystalball);
351  listPdf.add(exp_pdf);
352  } else {
353  // crystal-ball + exponential fit
354  listPdf.add(crystalball);
355  listPdf.add(expo);
356  }
357  } else {
358  if (useRooCMSShape_) {
359  // voigtian + CMS-shape fit
360  listPdf.add(voigt);
361  listPdf.add(exp_pdf);
362  } else {
363  // voigtian + exponential fit
364  listPdf.add(voigt);
365  listPdf.add(expo);
366  }
367  }
368 
369  RooAddPdf fullModel("fullModel", "Signal + Background Model", listPdf, RooArgList(s, b));
370  fullModel.fitTo(datahist, RooFit::PrintLevel(-1));
371  fullModel.plotOn(frame.get(), RooFit::LineColor(kRed));
372  if (useRooCMSShape_) {
373  fullModel.plotOn(frame.get(), RooFit::Components(exp_pdf), RooFit::LineStyle(kDashed)); //Other option
374  } else {
375  fullModel.plotOn(frame.get(), RooFit::Components(expo), RooFit::LineStyle(kDashed)); //Other option
376  }
377  fullModel.paramOn(frame.get(), RooFit::Layout(0.65, 0.90, 0.90));
378  } else {
379  if (useRooCBShape_) {
380  // use crystal-ball for a fit-only signal
381  crystalball.fitTo(datahist, RooFit::PrintLevel(-1));
382  crystalball.plotOn(frame.get(), RooFit::LineColor(kRed)); //this will show fit overlay on canvas
383  crystalball.paramOn(frame.get(),
384  RooFit::Layout(0.65, 0.90, 0.90)); //this will display the fit parameters on canvas
385  } else {
386  // use voigtian for a fit-only signal
387  voigt.fitTo(datahist, RooFit::PrintLevel(-1));
388  voigt.plotOn(frame.get(), RooFit::LineColor(kRed)); //this will show fit overlay on canvas
389  voigt.paramOn(frame.get(), RooFit::Layout(0.65, 0.90, 0.90)); //this will display the fit parameters on canvas
390  }
391  }
392 
393  // Redraw data on top and print / store everything
394  datahist.plotOn(frame.get());
395  frame->GetYaxis()->SetTitle("n. of events");
396  TString histName = hist->GetName();
397  frame->SetName("frame" + histName);
398  frame->SetTitle(hist->GetTitle());
399  frame->Draw();
400 
401  if (debugMode_) {
402  c1->Print("fit_debug" + histName + ".pdf");
403  }
404  delete c1;
405 
406  float mass_mean = useRooCBShape_ ? peakCB.getVal() : mean.getVal();
407  float mass_sigma = useRooCBShape_ ? sigmaCB.getVal() : sigma.getVal();
408 
409  float mass_mean_err = useRooCBShape_ ? peakCB.getError() : mean.getError();
410  float mass_sigma_err = useRooCBShape_ ? sigmaCB.getError() : sigma.getError();
411 
412  Measurement1D resultM(mass_mean, mass_mean_err);
413  Measurement1D resultW(mass_sigma, mass_sigma_err);
414 
415  return diMuonMassBias::fitOutputs(resultM, resultW);
416 }
417 
418 //-----------------------------------------------------------------------------------
420 //-----------------------------------------------------------------------------------
421 {
423  desc.add<std::string>("FolderName", "DiMuonMassBiasMonitor");
424  desc.add<bool>("useTH1s", false);
425  desc.add<bool>("fitBackground", false);
426  desc.add<bool>("useRooCMSShape", false);
427  desc.add<bool>("useRooCBShape", false);
428  desc.add<bool>("debugMode", false);
429 
431  fit_par.add<std::vector<double>>("mean_par",
434  std::numeric_limits<float>::max()}); // par = mean
435 
436  fit_par.add<std::vector<double>>("width_par",
439  std::numeric_limits<float>::max()}); // par = width
440 
441  fit_par.add<std::vector<double>>("sigma_par",
444  std::numeric_limits<float>::max()}); // par = sigma
445 
446  desc.add<edm::ParameterSetDescription>("fit_par", fit_par);
447 
448  desc.add<std::vector<std::string>>("MEtoHarvest",
449  {"DiMuMassVsMuMuPhi",
450  "DiMuMassVsMuMuEta",
451  "DiMuMassVsMuPlusPhi",
452  "DiMuMassVsMuPlusEta",
453  "DiMuMassVsMuMinusPhi",
454  "DiMuMassVsMuMinusEta",
455  "DiMuMassVsMuMuDeltaEta",
456  "DiMuMassVsCosThetaCS"});
457  descriptions.addWithDefaultLabel(desc);
458 }
459 
void getMEsToHarvest(DQMStore::IGetter &igetter)
void addWithDefaultLabel(ParameterSetDescription const &psetDescription)
T getParameter(std::string const &) const
Definition: ParameterSet.h:303
std::map< std::string, MonitorElement * > widthHistos_
virtual void setCurrentFolder(std::string const &fullpath)
Definition: DQMStore.cc:36
static PFTauRenderPlugin instance
diMuonMassBias::fitOutputs fitLineShape(TH1 *hist, const bool &fitBackground=false) const
~DiMuonMassBiasClient() override
Destructor.
const std::string TopFolder_
void beginRun(edm::Run const &run, edm::EventSetup const &eSetup) override
BeginRun.
Log< level::Error, false > LogError
std::map< std::string, MonitorElement * > harvestTargets_
std::map< std::string, MonitorElement * > meanProfiles_
std::map< std::string, MonitorElement * > widthProfiles_
Definition: ME.h:11
MonitorElement * bookProfile(TString const &name, TString const &title, int nchX, double lowX, double highX, int, double lowY, double highY, char const *option="s", FUNC onbooking=NOOP())
Definition: DQMStore.h:399
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
std::vector< std::string > MEtoHarvest_
Log< level::Warning, true > LogPrint
void dqmEndJob(DQMStore::IBooker &ibooker_, DQMStore::IGetter &igetter_) override
EndJob.
void beginJob(void) override
BeginJob.
Log< level::Info, false > LogInfo
void fitAndFillProfile(std::pair< std::string, MonitorElement *> toHarvest, DQMStore::IBooker &iBooker)
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
double b
Definition: hdecay.h:118
static constexpr int minimumHits
virtual MonitorElement * get(std::string const &fullpath) const
Definition: DQMStore.cc:712
DiMuonMassBiasClient(const edm::ParameterSet &ps)
Constructor.
double value() const
Definition: Measurement1D.h:25
std::map< std::string, MonitorElement * > meanHistos_
void bookMEs(DQMStore::IBooker &ibooker)
book MEs
results
Definition: mysort.py:8
double error() const
Definition: Measurement1D.h:27
void fitAndFillHisto(std::pair< std::string, MonitorElement *> toHarvest, DQMStore::IBooker &iBooker)
double crystalball(double *x, double *par)
Definition: myFunctions.cc:98
Log< level::Warning, false > LogWarning
MonitorElement * book1D(TString const &name, TString const &title, int const nchX, double const lowX, double const highX, FUNC onbooking=NOOP())
Definition: DQMStore.h:98
void fillArrayF(float *x, const edm::ParameterSet &cfg, const char *name)
Definition: Run.h:45
#define LogDebug(id)