babymaker  e95a6a9342d4604277fe7cc6149b6b5b24447d89
lepton_tools.cc
Go to the documentation of this file.
1 
4 // System include files
5 #include <cmath>
6 #include <cstdlib>
7 
8 #include <algorithm>
9 #include <stdexcept>
10 #include <string>
11 #include <numeric>
12 
13 //ROOT include files
14 #include "TFile.h"
15 #include "TGraphAsymmErrors.h"
16 
17 // FW include files
18 #include "FWCore/Framework/interface/ESHandle.h"
19 #include "DataFormats/Math/interface/deltaR.h"
20 
21 // User include files
23 
24 #include "DataFormats/PatCandidates/interface/PFIsolation.h"
25 
26 using namespace std;
27 using namespace utilities;
28 
29 namespace{
30  template<typename T>
31  T GetSF(const string &file_name, const string &item_name){
32  string path = string(getenv("CMSSW_BASE"))+"/src/babymaker/bmaker/data/lepton_sf/"+file_name;
33  TFile f(path.c_str(), "read");
34  if(!f.IsOpen()) ERROR("Could not open " << file_name);
35  T* item = static_cast<T*>(f.Get(item_name.c_str()));
36  if(!item) ERROR("Could not find " << item_name << " in " << file_name);
37  return *item;
38  }
39 
40  template<typename T>
41  pair<double, double> GetSF(const T &h, double x, double y, bool ignore_error = false){
42  pair<double, double> sf;
43  auto bin = h.FindFixBin(x, y);
44  if((h.IsBinOverflow(bin) || h.IsBinUnderflow(bin))
45  && h.GetBinContent(bin) == 0. && h.GetBinError(bin) == 0.){
46  auto bin_x = h.GetXaxis()->FindFixBin(x);
47  auto bin_y = h.GetYaxis()->FindFixBin(y);
48  if(bin_x <= 0) bin_x = 1;
49  if(bin_x > h.GetNbinsX()) bin_x = h.GetNbinsX();
50  if(bin_y <= 0) bin_y = 1;
51  if(bin_y > h.GetNbinsY()) bin_y = h.GetNbinsY();
52  sf = {h.GetBinContent(bin_x, bin_y), h.GetBinError(bin_x, bin_y)};
53  }else{
54  sf = {h.GetBinContent(bin), h.GetBinError(bin)};
55  }
56  if(ignore_error) sf.second = 0.;
57  return sf;
58  }
59 
60  pair<double, double> MergeSF(pair<double, double> a,
61  pair<double, double> b){
62  double sf = a.first * b.first;
63  double err = hypot(a.first*b.second, b.first*a.second);
64  return {sf, err};
65  }
66 
67  TH2D GraphToHist(const TGraphAsymmErrors &g){
68  struct Point{
69  double xl, xh, y, e;
70  Point(double xl_in, double xh_in, double y_in, double e_in):
71  xl(xl_in),
72  xh(xh_in),
73  y(y_in),
74  e(e_in){
75  }
76  bool operator<(const Point &p) const{
77  return make_tuple(xl, xh, fabs(log(fabs(y))), fabs(e))
78  <make_tuple(p.xl, p.xh, fabs(log(fabs(p.y))), fabs(p.e));
79  }
80  };
81  vector<Point> bins;
82  Double_t *x = g.GetX();
83  Double_t *xl = g.GetEXlow();
84  Double_t *xh = g.GetEXhigh();
85  Double_t *y = g.GetY();
86  Double_t *yl = g.GetEYlow();
87  Double_t *yh = g.GetEYhigh();
88  for(int i = 0; i < g.GetN(); ++i){
89  bins.emplace_back(x[i]-fabs(xl[i]), x[i]+fabs(xh[i]),
90  y[i], max(fabs(yl[i]), fabs(yh[i])));
91  }
92  bool problems = true;
93  while(problems){
94  stable_sort(bins.begin(), bins.end());
95  problems = false;
96  for(auto low = bins.begin(); !problems && low != bins.end(); ++low){
97  auto high = low;
98  ++high;
99  if(high == bins.end()) break;
100  double new_y = sqrt(low->y * high->y);
101  double top = max(low->y+low->e, high->y+high->e);
102  double bot = min(low->y-low->e, high->y-high->e);
103  double new_e = max(top-new_y, new_y-bot);
104  if(low->xh < high->xl){
105  //Gap
106  bins.insert(high, Point(low->xh, high->xl, new_y, new_e));
107  }else if(low->xh > high->xl){
108  //Overlap
109  problems = true;
110  if(low->xh < high->xh){
111  //Plain overlap
112  Point new_low(low->xl, high->xl, low->y, low->e);
113  Point new_mid(high->xl, low->xh, new_y, new_e);
114  Point new_high(low->xh, high->xh, high->y, high->e);
115  *low = new_low;
116  *high = new_high;
117  bins.insert(high, new_mid);
118  }else if(low->xh == high->xh){
119  //Subset -> 2 bins
120  Point new_low(low->xl, high->xl, low->y, low->e);
121  Point new_high(high->xl, high->xh, new_y, new_e);
122  *low = new_low;
123  *high = new_high;
124  }else{
125  //Subset -> 3 bins
126  Point new_low(low->xl, high->xl, low->y, low->e);
127  Point new_mid(high->xl, high->xh, new_y, new_e);
128  Point new_high(high->xh, low->xh, low->y, low->e);
129  *low = new_low;
130  *high = new_high;
131  bins.insert(high, new_mid);
132  }
133  }
134  }
135  }
136  vector<double> bin_edges(bins.size()+1);
137  for(size_t i = 0; i < bins.size(); ++i){
138  bin_edges.at(i) = bins.at(i).xl;
139  }
140  bin_edges.back() = bins.back().xh;
141  TH2D h(g.GetName(), (string(g.GetTitle())+";"+g.GetXaxis()->GetTitle()+";"+g.GetYaxis()->GetTitle()).c_str(),
142  1, 0., 1.e4, bin_edges.size()-1, &bin_edges.at(0));
143  for(int ix = 0; ix <= 2; ++ix){
144  h.SetBinContent(ix, 0, 1.);
145  h.SetBinError(ix, 0, 1.);
146  h.SetBinContent(ix, h.GetNbinsY()+1, 1.);
147  h.SetBinError(ix, h.GetNbinsY()+1, 1.);
148  for(int iy = 1; iy <= h.GetNbinsY(); ++iy){
149  h.SetBinContent(ix, iy, bins.at(iy-1).y);
150  h.SetBinError(ix ,iy, bins.at(iy-1).e);
151  }
152  }
153  return h;
154  }
155 }
156 
158 
159 //https://twiki.cern.ch/twiki/bin/view/CMS/SUSLeptonSF#Muons_AN1
160 const TH2F lepton_tools::sf_full_muon_medium = GetSF<TH2F>("TnP_NUM_MediumID_DENOM_generalTracks_VAR_map_pt_eta.root",
161  "SF");
162 const TH2F lepton_tools::sf_full_muon_iso = GetSF<TH2F>("TnP_NUM_MiniIsoTight_DENOM_MediumID_VAR_map_pt_eta.root",
163  "SF");
164 
165 const TH2F lepton_tools::sf_full_muon_vtx = GetSF<TH2F>("TnP_NUM_MediumIP2D_DENOM_LooseID_VAR_map_pt_eta.root",
166  "SF");
167 
168 
169 //Need to add muon tracking SF if it becomes available
170 //const TH2D lepton_tools::sf_full_muon_tracking = GraphToHist(GetSF<TGraphAsymmErrors>("sf_full_muon_tracking.root",
171 // "ratio_eta"));
172 
173 //https://twiki.cern.ch/twiki/bin/view/CMS/SUSLeptonSF#Electrons_AN1
174 const TH2F lepton_tools::sf_full_electron_medium = GetSF<TH2F>("sf_full_electron_ID_and_iso_25_01_2017.root",
175  "GsfElectronToCutBasedSpring15M");
176 const TH2F lepton_tools::sf_full_electron_iso = GetSF<TH2F>("sf_full_electron_ID_and_iso_25_01_2017.root",
177  "MVAVLooseElectronToMini");
178 const TH2F lepton_tools::sf_full_electron_tracking = GetSF<TH2F>("egammaEffi_EGM2D.root",
179  "EGamma_SF2D");
180 
181 
182 const TH2D lepton_tools::sf_fast_muon_medium = GetSF<TH2D>("sf_fast_muon_medium.root",
183  "histo2D");
184 const TH2D lepton_tools::sf_fast_muon_iso = GetSF<TH2D>("sf_fast_muon_iso.root",
185  "histo2D");
186 const TH2D lepton_tools::sf_fast_electron_mediumiso = GetSF<TH2D>("sf_fast_electron_mediumiso.root",
187  "histo2D");
188 
190 bool lepton_tools::isSignalMuon(const pat::Muon &lep, edm::Handle<reco::VertexCollection> vtx, double lepIso){
191  // pT, eta cuts
192  if(lep.pt() <= SignalLeptonPtCut) return false;
193  if(fabs(lep.eta()) > MuonEtaCut) return false;
194  // ID cuts (includes dz/dz0 cuts)
195  if(!idMuon(lep, vtx, kMedium)) return false;
196  // Isolation cuts
197  if(lepIso >= 0 && lepIso > MuonMiniIsoCut) return false;
198 
199  return true;
200 }
201 
202 bool lepton_tools::isVetoMuon(const pat::Muon &lep, edm::Handle<reco::VertexCollection> vtx, double lepIso){
203  // pT, eta cuts
204  if(lep.pt() <= VetoLeptonPtCut) return false;
205  if(fabs(lep.eta()) > MuonEtaCut) return false;
206  // ID cuts (includes dz/dz0 cuts)
207  if(!idMuon(lep, vtx, kMedium)) return false; // Using RA2/b muons
208  // Isolation cuts
209  if(lepIso >= 0 && lepIso > MuonMiniIsoCut) return false;
210 
211  return true;
212 }
213 
214 bool lepton_tools::idMuon(const pat::Muon &lep, edm::Handle<reco::VertexCollection> vtx, CutLevel threshold) {
215  double dz(0.), d0(0.);
216  if(!vertexMuon(lep, vtx, dz, d0)) return false;
217 
218  bool good_global;
219  switch(threshold){
220  default:
221  case kVeto:
222  case kLoose:
223  return lep.isLooseMuon();
224  case kMedium:
225  return lep.isMediumMuon();
226  case kMediumICHEP:
227  //From https://twiki.cern.ch/twiki/bin/viewauth/CMS/SWGuideMuonIdRun2#Short_Term_Medium_Muon_Definitio
228  good_global = lep.isGlobalMuon()
229  && lep.globalTrack()->normalizedChi2() < 3.
230  && lep.combinedQuality().chi2LocalPosition < 12.
231  && lep.combinedQuality().trkKink < 20.;
232  return muon::isLooseMuon(lep)
233  && lep.innerTrack()->validFraction() > 0.49
234  && muon::segmentCompatibility(lep) > (good_global ? 0.303 : 0.451);
235  case kTight:
236  return lep.isTightMuon(vtx->at(0));
237  }
238 }
239 
240 bool lepton_tools::vertexMuon(const pat::Muon &lep, edm::Handle<reco::VertexCollection> vtx, double &dz, double &d0){
241  dz = 0.; d0 = 0.;
242  if(lep.track().isAvailable()){ // If the track is not available we probably don't want the muon
243  dz = lep.track()->vz()-vtx->at(0).z();
244  d0 = lep.track()->d0()-vtx->at(0).x()*sin(lep.track()->phi())+vtx->at(0).y()*cos(lep.track()->phi());
245  }
246  if(fabs(dz) > 0.5 || fabs(d0) > 0.2) return false;
247 
248  return true;
249 }
250 
251 double lepton_tools::getEffAreaMuon(double eta){
252  double abseta = fabs(eta);
253  if (abseta < 0.8) return 0.0735;
254  else if (abseta < 1.3) return 0.0619;
255  else if (abseta < 2.0) return 0.0465;
256  else if (abseta < 2.2) return 0.0433;
257  else if (abseta < 2.5) return 0.0577;
258  else return 0;
259 }
260 
261 double lepton_tools::getRelIsolation(const pat::Muon &lep, double rho){
262  double ch_iso(lep.pfIsolationR04().sumChargedHadronPt);
263  double neu_iso(max(0., lep.pfIsolationR04().sumNeutralHadronEt + lep.pfIsolationR04().sumPhotonEt
264  -rho*getEffAreaMuon(lep.eta())));
265 
266  return (ch_iso + neu_iso) / lep.pt();
267 }
268 
269 /*
270 double lepton_tools::getMinIsolation(const reco::Candidate* lep, double rho){
271  double ch_iso(lep->miniPFIsolation()->chargedHadronIso());
272  double neu_iso(lep->miniPFIsolation()->neutralHadronIso() + lep->miniPFIsolation()->photonIso());
273 
274  return (ch_iso + neu_iso);
275 }
276 */
278 bool lepton_tools::isSignalElectron(const pat::Electron &lep, edm::Handle<reco::VertexCollection> vtx, double lepIso){
279  // pT, eta cuts
280  if(lep.pt() <= SignalLeptonPtCut) return false;
281  if(fabs(lep.superCluster()->position().eta()) > ElectronEtaCut) return false;
282  // ID cuts (includes dz/dz0 cuts)
283  if(!idElectron(lep, vtx, kMedium)) return false;
284  // Isolation cuts
285  if(lepIso >= 0 && lepIso > ElectronMiniIsoCut) return false;
286 
287  return true;
288 }
289 
290 bool lepton_tools::isVetoElectron(const pat::Electron &lep, edm::Handle<reco::VertexCollection> vtx, double lepIso){
291  // pT, eta cuts
292  if(lep.pt() <= VetoLeptonPtCut) return false;
293  if(fabs(lep.superCluster()->position().eta()) > ElectronEtaCut) return false;
294  // ID cuts (includes dz/dz0 cuts)
295  if(!idElectron(lep, vtx, kVeto)) return false;
296  // Isolation cuts
297  if(lepIso >= 0 && lepIso > ElectronMiniIsoCut) return false;
298 
299  return true;
300 }
301 
302 bool lepton_tools::idElectron(const pat::Electron &lep, edm::Handle<reco::VertexCollection> vtx, CutLevel threshold, bool doIso) {
303 
304  bool barrel(lep.isEB());
305  double deta_cut, dphi_cut, ieta_cut, hovere_cut, d0_cut, dz_cut,
306  ooeminusoop_cut, reliso_cut, misshits_cut;
307  bool req_conv_veto;
308 
309  // if(barrel){
310  // ieta_cut = chooseVal(threshold ,0.0115, 0.011, 0.00998, 0.00998);
311  // deta_cut = chooseVal(threshold ,0.00749, 0.00477, 0.00311, 0.00308);
312  // dphi_cut = chooseVal(threshold ,0.228, 0.222, 0.103, 0.0816);
313  // hovere_cut = chooseVal(threshold ,0.356, 0.298, 0.253, 0.0414);
314  // reliso_cut = chooseVal(threshold ,0.175, 0.0994, 0.0695, 0.0588);
315  // ooeminusoop_cut = chooseVal(threshold ,0.299, 0.241, 0.134, 0.0129);
316  // d0_cut = chooseVal(threshold ,0.05, 0.05, 0.05, 0.05);
317  // dz_cut = chooseVal(threshold ,0.10 , 0.10, 0.10, 0.10);
318  // misshits_cut = chooseVal(threshold ,2, 1, 1, 1);
319  // req_conv_veto = chooseVal(threshold ,true , true , true , true );
320  // } else {
321  // ieta_cut = chooseVal(threshold ,0.037, 0.0314, 0.0298, 0.0292);
322  // deta_cut = chooseVal(threshold ,0.00895, 0.00868, 0.00609, 0.00605);
323  // dphi_cut = chooseVal(threshold ,0.213, 0.213, 0.045, 0.0394);
324  // hovere_cut = chooseVal(threshold ,0.211, 0.101, 0.0878, 0.0641);
325  // reliso_cut = chooseVal(threshold ,0.159, 0.107, 0.0821, 0.0571);
326  // ooeminusoop_cut = chooseVal(threshold ,0.15, 0.14, 0.13, 0.0129);
327  // d0_cut = chooseVal(threshold ,0.10 , 0.10, 0.10, 0.10);
328  // dz_cut = chooseVal(threshold ,0.20 , 0.20, 0.20, 0.20);
329  // misshits_cut = chooseVal(threshold ,3, 1, 1, 1);
330  // req_conv_veto = chooseVal(threshold ,true , true , true , true );
331  // }
332 
333  //https://twiki.cern.ch/twiki/bin/viewauth/CMS/CutBasedElectronIdentificationRun2#Working_points_for_Spring15_MC_s
334  // Last updated October 8th
335  if(barrel){
336  ieta_cut = chooseVal(threshold ,0.0114, 0.0103, 0.0101, 0.0101);
337  deta_cut = chooseVal(threshold ,0.0152, 0.0105, 0.0103, 0.00926);
338  dphi_cut = chooseVal(threshold ,0.216, 0.115, 0.0336, 0.0336);
339  hovere_cut = chooseVal(threshold ,0.181, 0.104, 0.0876, 0.0597);
340  reliso_cut = chooseVal(threshold ,0.126, 0.0893, 0.0766, 0.0354);
341  ooeminusoop_cut = chooseVal(threshold ,0.207, 0.102, 0.0174, 0.012);
342  d0_cut = chooseVal(threshold ,0.0564, 0.0261, 0.0118, 0.0111);
343  dz_cut = chooseVal(threshold ,0.472, 0.41, 0.373, 0.0466);
344  misshits_cut = chooseVal(threshold ,2, 2, 2, 2);
345  req_conv_veto = chooseVal(threshold ,true , true , true , true );
346  } else {
347  ieta_cut = chooseVal(threshold ,0.0352 , 0.0301 , 0.0283 , 0.0279);
348  deta_cut = chooseVal(threshold ,0.0113 , 0.00814 , 0.00733 , 0.00724);
349  dphi_cut = chooseVal(threshold ,0.237 , 0.182 , 0.114 , 0.0918);
350  hovere_cut = chooseVal(threshold ,0.116 , 0.0897 , 0.0678 , 0.0615);
351  reliso_cut = chooseVal(threshold ,0.144 , 0.121 , 0.0678 , 0.0646);
352  ooeminusoop_cut = chooseVal(threshold ,0.174 , 0.126 , 0.0898 , 0.00999);
353  d0_cut = chooseVal(threshold ,0.222 , 0.118 , 0.0739 , 0.0351);
354  dz_cut = chooseVal(threshold ,0.921 , 0.822 , 0.602 , 0.417);
355  misshits_cut = chooseVal(threshold ,3, 1, 1, 1);
356  req_conv_veto = chooseVal(threshold ,true , true , true , true );
357  }
358 
359  double dz(0.), d0(0.);
360  vertexElectron(lep, vtx, dz, d0);
361 
362  int mhits(0);
363  if(lep.gsfTrack().isAvailable()){
364  mhits = lep.gsfTrack()->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_INNER_HITS);;
365  }
366  const double sigietaieta(lep.full5x5_sigmaIetaIeta());
367 
368  return deta_cut > fabs(lep.deltaEtaSuperClusterTrackAtVtx())
369  && dphi_cut > fabs(lep.deltaPhiSuperClusterTrackAtVtx())
370  && ieta_cut > sigietaieta
371  && hovere_cut > lep.hadronicOverEm()
372  && d0_cut > fabs(d0)
373  && dz_cut > fabs(dz)
374  && ooeminusoop_cut > fabs((1.0-lep.eSuperClusterOverP())/lep.ecalEnergy())
375  && (!doIso || reliso_cut > 0) // To be implemented if we want reliso
376  && (!req_conv_veto || lep.passConversionVeto())
377  && (misshits_cut >= mhits);
378 }
379 
380 bool lepton_tools::vertexElectron(const pat::Electron &lep, edm::Handle<reco::VertexCollection> vtx, double &dz, double &d0){
381  dz = 0.; d0 = 0.;
382  if(lep.gsfTrack().isAvailable()){ // If the track is not available we probably don't want the electron
383  dz = lep.gsfTrack()->vz()-vtx->at(0).z();
384  d0 = lep.gsfTrack()->d0()-vtx->at(0).x()*sin(lep.gsfTrack()->phi())+vtx->at(0).y()*cos(lep.gsfTrack()->phi());
385  }
386  if(fabs(dz) > 0.5 || fabs(d0) > 0.2) return false;
387 
388  return true;
389 }
390 
392  double abseta = fabs(eta);
393  if (abseta < 1) return 0.1752;
394  else if (abseta < 1.479) return 0.1862;
395  else if (abseta < 2.0) return 0.1411;
396  else if (abseta < 2.2) return 0.1534;
397  else if (abseta < 2.3) return 0.1903;
398  else if (abseta < 2.4) return 0.2243;
399  else if (abseta < 2.5) return 0.2687;
400  else return 0;
401 }
402 
403 double lepton_tools::getRelIsolation(const pat::Electron &lep, double rho){
404  double ch_iso(lep.pfIsolationVariables().sumChargedHadronPt);
405  double neu_iso(max(0., lep.pfIsolationVariables().sumNeutralHadronEt + lep.pfIsolationVariables().sumPhotonEt
406  -rho*getEffAreaElectron(lep.eta())));
407 
408  return (ch_iso + neu_iso) / lep.pt();
409 }
410 /*
411 double lepton_tools::getMinIsolation(const pat::PFIsolation &lepiso, double rho) const{
412  double ch_iso(lepiso.chargedHadronIso());
413  double neu_iso(lepiso.neutralHadronIso() + lepiso.photonIso());
414  return (ch_iso+neu_iso);
415 }
416 */
417 pair<double, double> lepton_tools::getScaleFactor(const reco::Candidate &cand){
418  if(const pat::Electron * ele_ptr = dynamic_cast<const pat::Electron*>(&cand)){
419  return getScaleFactor(*ele_ptr);
420  }else if(const reco::Muon * mu_ptr = dynamic_cast<const reco::Muon*>(&cand)){
421  return getScaleFactor(*mu_ptr);
422  }else{
423  ERROR("Cannot get scale factor for type " << typeid(cand).name());
424  }
425  return {1., 0.};
426 }
427 
428 pair<double, double> lepton_tools::getScaleFactor(const vCands &sig_leps){
429  return accumulate(sig_leps.cbegin(), sig_leps.cend(), make_pair(1., 0.),
430  [](pair<double, double> sf, const reco::Candidate* cand){
431  if(cand == nullptr) ERROR("Dereferencing nullptr");
432  return MergeSF(sf, getScaleFactor(*cand));
433  });
434 }
435 
436 pair<double, double> lepton_tools::getScaleFactorFs(const reco::Candidate &cand){
437  if(const pat::Electron * ele_ptr = dynamic_cast<const pat::Electron*>(&cand)){
438  return getScaleFactorFs(*ele_ptr);
439  }else if(const reco::Muon * mu_ptr = dynamic_cast<const reco::Muon*>(&cand)){
440  return getScaleFactorFs(*mu_ptr);
441  }else{
442  ERROR("Cannot get scale factor for type " << typeid(cand).name());
443  }
444  return {1., 0.};
445 }
446 
447 pair<double, double> lepton_tools::getScaleFactorFs(const vCands &sig_leps){
448  return accumulate(sig_leps.cbegin(), sig_leps.cend(), make_pair(1., 0.),
449  [](pair<double, double> sf, const reco::Candidate* cand){
450  if(cand == nullptr) ERROR("Dereferencing nullptr");
451  return MergeSF(sf, getScaleFactorFs(*cand));
452  });
453 }
454 
455 pair<double, double> lepton_tools::getScaleFactor(const reco::Muon &lep){
456  //https://twiki.cern.ch/twiki/bin/view/CMS/SUSLeptonSF#Data_leading_order_FullSim_MC_co
457  //ID, iso, tracking SFs applied
458  //No stat error, 3% systematic from ID, iso
459  double pt = lep.pt();
460  double eta = lep.eta();
461  double abseta = fabs(eta);
462  vector<pair<double, double> > sfs{
463  GetSF(sf_full_muon_medium, pt, abseta, false),
464  make_pair(1., 0.03),//Systematic uncertainty
465  GetSF(sf_full_muon_iso, pt, abseta, false),
466  make_pair(1., 0.03),//Systematic uncertainty
467  GetSF(sf_full_muon_vtx, pt, abseta, false),
468  make_pair(1., 0.03)//Systematic uncertainty
469  //GetSF(sf_full_muon_tracking, pt, eta)//Asymmetric in eta
470  };
471  return accumulate(sfs.cbegin(), sfs.cend(), make_pair(1., 0.), MergeSF);
472 }
473 
474 pair<double, double> lepton_tools::getScaleFactor(const pat::Electron &lep){
475  //https://twiki.cern.ch/twiki/bin/view/CMS/SUSLeptonSF#Data_leading_order_FullSim_M_AN1
476  //ID, iso, tracking SFs applied
477  //ID iso systematics built-in
478  //Tracking SFs from https://twiki.cern.ch/twiki/bin/view/CMS/EgammaIDRecipesRun2#Electron_efficiencies_and_scale
479  //3% tracking systematic below 20 GeV
480  double pt = lep.superCluster()->energy()*sin(lep.superClusterPosition().theta());
481  double eta = lep.superCluster()->eta();
482  double abseta = fabs(eta);
483  vector<pair<double, double> > sfs{
484  GetSF(sf_full_electron_medium, pt, abseta),
485  GetSF(sf_full_electron_iso, pt, abseta),
486  GetSF(sf_full_electron_tracking, eta, pt),//Axes swapped, asymmetric in eta
487  //make_pair(1., pt<20. ? 0.03 : 0.)//Systematic uncertainty
488  make_pair(1., pt<20. || pt >80. ? 0.01 : 0.)//Systematic uncertainty
489  };
490  return accumulate(sfs.cbegin(), sfs.cend(), make_pair(1., 0.), MergeSF);
491 }
492 
493 pair<double, double> lepton_tools::getScaleFactorFs(const reco::Muon &lep){
494  //https://twiki.cern.ch/twiki/bin/view/CMS/SUSLeptonSF#FullSim_FastSim_TTBar_MC_compari
495  //ID, iso SFs applied
496  //No stat error, 2% systematic from ID, iso
497  double pt = lep.pt();
498  double abseta = fabs(lep.eta());
499  vector<pair<double, double> > sfs{
500  GetSF(sf_fast_muon_medium, pt, abseta, false),
501  make_pair(1., 0.02),
502  GetSF(sf_fast_muon_iso, pt, abseta, false),
503  make_pair(1., 0.02),
504  };
505  return accumulate(sfs.cbegin(), sfs.cend(), make_pair(1., 0.), MergeSF);
506 }
507 
508 pair<double, double> lepton_tools::getScaleFactorFs(const pat::Electron &lep){
509  //https://twiki.cern.ch/twiki/bin/view/CMS/SUSLeptonSF#FullSim_FastSim_TTBar_MC_com_AN1
510  //ID, iso SFs applied
511  //No stat error, 2% systematic from ID, iso
512  double pt = lep.superCluster()->energy()*sin(lep.superClusterPosition().theta());
513  double abseta = fabs(lep.superCluster()->eta());
514  vector<pair<double, double> > sfs{
515  GetSF(sf_fast_electron_mediumiso, pt, abseta, false),
516  make_pair(1., 0.02),//Systematic uncertainty
517  make_pair(1., 0.02)//Systematic uncertainty
518  };
519  return accumulate(sfs.cbegin(), sfs.cend(), make_pair(1., 0.), MergeSF);
520 }
521 
522 double lepton_tools::getPFIsolation(edm::Handle<pat::PackedCandidateCollection> pfcands,
523  const reco::Candidate* ptcl,
524  double r_iso_min, double r_iso_max, double kt_scale,
525  double rho, bool charged_only) {
526  if (ptcl->pt()<1.) return 99999.;
527 
528  double deadcone_nh(0.), deadcone_ch(0.), deadcone_ph(0.), deadcone_pu(0.);
529  if(ptcl->isElectron()) {
530  if (fabs(ptcl->eta())>1.479) {deadcone_ch = 0.015; deadcone_pu = 0.015; deadcone_ph = 0.08;}
531  } else if(ptcl->isMuon()) {
532  deadcone_ch = 0.0001; deadcone_pu = 0.01; deadcone_ph = 0.01;deadcone_nh = 0.01;
533  } else {
534  //deadcone_ch = 0.0001; deadcone_pu = 0.01; deadcone_ph = 0.01;deadcone_nh = 0.01; // maybe use muon cones??
535  }
536  double iso_nh(0.), iso_ch(0.), iso_ph(0.), iso_pu(0.);
537  double ptThresh(0.5), r_mini(kt_scale/ptcl->pt());
538  if(ptcl->isElectron()) ptThresh = 0;
539  double r_iso(max(r_iso_min, min(r_iso_max, r_mini)));
540 
541  for (const pat::PackedCandidate &pfc : *pfcands) {
542  if (abs(pfc.pdgId())<7) continue;
543  double dr = deltaR(pfc, *ptcl);
544  if (dr > r_iso) continue;
545  if (&pfc == ptcl) continue;
546  if (pfc.charge()==0){ //neutrals
547  if (pfc.pt()>ptThresh) {
548  if (abs(pfc.pdgId())==22) { //photons
549  if(dr < deadcone_ph) continue;
550  iso_ph += pfc.pt();
551  } else if (abs(pfc.pdgId())==130) { //neutral hadrons
552  if(dr < deadcone_nh) continue;
553  iso_nh += pfc.pt();
554  }
555  }
556  } else if (pfc.fromPV()>1){ //charged from PV
557  if (abs(pfc.pdgId())==211) {
558  if(dr < deadcone_ch) continue;
559  iso_ch += pfc.pt();
560  }
561  } else {
562  if (pfc.pt()>ptThresh){ //charged from PU
563  if(dr < deadcone_pu) continue;
564  iso_pu += pfc.pt();
565  }
566  }
567  } // Loop over pf cands
568 
569  double effarea = ptcl->isElectron() ? getEffAreaElectron(ptcl->eta()) : getEffAreaMuon(ptcl->eta());
570  double pu_corr = rho*effarea*pow(r_iso/0.3, 2);
571  double iso(0.);
572  if (charged_only) iso = iso_ch;
573  else iso = iso_ch + max(0.,iso_ph + iso_nh - pu_corr);
574 
575  return iso/ptcl->pt();
576 }
577 
578 vCands lepton_tools::getIsoTracks(edm::Handle<pat::PackedCandidateCollection> pfcands, double met, double met_phi){
579 
580  vCands tks;
581  //common parameters
582  float mt_max = 100.;
583  float eta_max = 2.5;
584  float dz_max = 0.1;
585  float cone_size = 0.3;
586 
587  for (size_t i(0); i < pfcands->size(); i++) {
588  const pat::PackedCandidate &tk = (*pfcands)[i];
589  unsigned int id = abs(tk.pdgId());
590 
591  //id-specific parameters
592  float pt_min = id==211 ? 10. : 5.;
593  float iso_max = id==211 ? 0.1 : 0.2;
594 
595  // track selection
596  if (tk.charge()==0) continue;
597  if (id!=11 && id!=13 && id!=211) continue;
598  if (tk.pt() < pt_min) continue;
599  if (fabs(tk.eta()) > eta_max) continue;
600  if (fabs(tk.dz()) > dz_max) continue;
601  if (mt_max>0.01 && getMT(met, met_phi, tk.pt(), tk.phi())>mt_max) continue;
602 
603  // calculate track isolation
604  double iso = 0.;
605  for (size_t j(0); j < pfcands->size(); j++) {
606  if (i==j) continue;
607  const pat::PackedCandidate &pfc = (*pfcands)[j];
608 
609  if (pfc.charge()==0) continue;
610  if (deltaR(tk,pfc) > cone_size) continue;
611  if (fabs(pfc.dz()) > dz_max) continue;
612  iso += pfc.pt();
613  }
614  if (iso/tk.pt()>iso_max) continue;
615 
616  tks.push_back(dynamic_cast<const reco::Candidate *>(&tk));
617  }
618 
619  return tks;
620 }
621 
622 vCands lepton_tools::getRA4IsoTracks(edm::Handle<pat::PackedCandidateCollection> pfcands, double met, double met_phi, double rhoEventCentral, vector<float> &isos, vector<float> &relisos, int primary_pdg){
623 
624  vCands tks;
625  //Very loose cuts to have flexibility, not the veto definition
626  float dz_max = 0.5;
627  float pt_min = 5;
628  float iso_max = 1.;
629 
630  for (size_t i(0); i < pfcands->size(); i++) {
631  const pat::PackedCandidate &tk = (*pfcands)[i];
632  unsigned int id = abs(tk.pdgId());
633 
634  // track selection
635  if (tk.charge()==0) continue;
636  if (id!=11 && id!=13 && id!=211) continue;
637  if (tk.pt() < pt_min) continue;
638  if (fabs(tk.dz()) > dz_max) continue;
639 
640  //Only save opposite sign tracks
641  if(id == 211){
642  if(tk.pdgId() * primary_pdg < 0 ) continue;
643  }
644  else{
645  if(tk.pdgId() * primary_pdg > 0 ) continue;
646  }
647 
648 
649  // calculate track isolation
650  double iso = 0.;
651  double reliso=0.;
652  if(id!=211){ //Use charged+neutral for e's and mu's
653  iso = getPFIsolation(pfcands, dynamic_cast<const reco::Candidate *>(&tk), 0.05, 0.2, 10., rhoEventCentral, false);
654  reliso = getPFIsolation(pfcands, dynamic_cast<const reco::Candidate *>(&tk), 0.3, 0.3, 10., rhoEventCentral, false);
655  }
656  else{ //Use charged only for hadronic tracks
657  iso = getPFIsolation(pfcands, dynamic_cast<const reco::Candidate *>(&tk), 0.05, 0.2, 10., rhoEventCentral, true);
658  reliso = getPFIsolation(pfcands, dynamic_cast<const reco::Candidate *>(&tk), 0.3, 0.3, 10., rhoEventCentral, true);
659  }
660 
661  if(iso>iso_max && reliso>iso_max) continue; //Save tracks that pass a very loose isolation cut, for either isolation
662  isos.push_back(iso);
663  relisos.push_back(reliso);
664  tks.push_back(dynamic_cast<const reco::Candidate *>(&tk));
665  }
666 
667  return tks;
668 }
669 
670 // Bad Global Muon filter
671 bool lepton_tools::outInOnly(const reco::Muon &mu) const {
672  const reco::Track &tk = *mu.innerTrack();
673  return tk.algoMask().count() == 1 && tk.isAlgoInMask(reco::Track::muonSeededStepOutIn);
674 }
675 bool lepton_tools::preselection(const reco::Muon &mu, bool selectClones) const {
676  return (!selectClones || outInOnly(mu));
677 }
678 bool lepton_tools::tighterId(const reco::Muon &mu) const {
679  return muon::isMediumMuon(mu) && mu.numberOfMatchedStations() >= 2;
680 }
681 bool lepton_tools::tightGlobal(const reco::Muon &mu) const {
682  return mu.isGlobalMuon() && (mu.globalTrack()->hitPattern().muonStationsWithValidHits() >= 3 && mu.globalTrack()->normalizedChi2() <= 20);
683 }
684 bool lepton_tools::safeId(const reco::Muon &mu) const {
685  if (mu.muonBestTrack()->ptError() > 0.2 * mu.muonBestTrack()->pt()) { return false; }
686  return mu.numberOfMatchedStations() >= 1 || tightGlobal(mu);
687 }
688 bool lepton_tools::partnerId(const reco::Muon &mu) const {
689  return mu.pt() >= 10 && mu.numberOfMatchedStations() >= 1;
690 }
691 
692 set<unsigned> lepton_tools::badGlobalMuonSelector(edm::Handle<reco::VertexCollection> vtx,
693  edm::Handle<pat::MuonCollection> muptr, bool selectClones) {
694  using namespace edm;
695  float ptCut_ = 20.;
696  bool verbose_ = false;
697  assert(vtx->size() >= 1);
698  const auto &PV = vtx->front().position();
699 
700  set<unsigned> badmus;
701  std::vector<int> goodMuon;
702  const pat::MuonCollection &muons = *muptr;
703  for (auto & mu : muons) {
704  if (!mu.userInt("muonsCleaned:oldPF") || mu.innerTrack().isNull()) {
705  goodMuon.push_back(-1); // bad but we don't care
706  continue;
707  }
708  if (preselection(mu, selectClones)) {
709  float dxypv = std::abs(mu.innerTrack()->dxy(PV));
710  float dzpv = std::abs(mu.innerTrack()->dz(PV));
711  if (tighterId(mu)) {
712  bool ipLoose = ((dxypv < 0.5 && dzpv < 2.0) || mu.innerTrack()->hitPattern().pixelLayersWithMeasurement() >= 2);
713  goodMuon.push_back(ipLoose || (!selectClones && tightGlobal(mu)));
714  } else if (safeId(mu)) {
715  bool ipTight = (dxypv < 0.2 && dzpv < 0.5);
716  goodMuon.push_back(ipTight);
717  } else {
718  goodMuon.push_back(0);
719  }
720  } else {
721  goodMuon.push_back(3); // maybe good, maybe bad, but we don't care
722  }
723  }
724 
725  for (unsigned int i = 0, n = muons.size(); i < n; ++i) {
726  if (muons[i].pt() < ptCut_ || goodMuon[i] != 0) continue;
727  if (verbose_) printf("potentially bad muon %d of pt %.1f eta %+.3f phi %+.3f\n", int(i+1), muons[i].pt(), muons[i].eta(), muons[i].phi());
728  bool bad = true;
729  if (selectClones) {
730  bad = false; // unless proven otherwise
731  unsigned int n1 = muons[i].numberOfMatches(reco::Muon::SegmentArbitration);
732  for (unsigned int j = 0; j < n; ++j) {
733  if (j == i || goodMuon[j] <= 0 || !partnerId(muons[j])) continue;
734  unsigned int n2 = muons[j].numberOfMatches(reco::Muon::SegmentArbitration);
735  if (deltaR2(muons[i],muons[j]) < 0.16 || (n1 > 0 && n2 > 0 && muon::sharedSegments(muons[i],muons[j]) >= 0.5*std::min(n1,n2))) {
736  if (verbose_) printf(" tagged as clone of muon %d of pt %.1f eta %+.3f phi %+.3f\n", int(j+1), muons[j].pt(), muons[j].eta(), muons[j].phi());
737  bad = true;
738  break;
739  }
740  }
741  }
742  if (bad) badmus.insert(i);
743  }
744 
745  return badmus;
746 }
747 
748 
750 }
751 
753 }
static const TH2F sf_full_electron_medium
Definition: lepton_tools.hh:96
double getPFIsolation(edm::Handle< pat::PackedCandidateCollection > pfcands, const reco::Candidate *ptcl, double r_iso_min, double r_iso_max, double kt_scale, double rho, bool charged_only)
std::set< unsigned > badGlobalMuonSelector(edm::Handle< reco::VertexCollection > vtx, edm::Handle< pat::MuonCollection > muons, bool selectClones)
bool safeId(const reco::Muon &mu) const
TH2D GraphToHist(const TGraphAsymmErrors &g)
Definition: lepton_tools.cc:67
static const TH2F sf_full_muon_medium
Definition: lepton_tools.hh:96
pair< double, double > MergeSF(pair< double, double > a, pair< double, double > b)
Definition: lepton_tools.cc:60
std::vector< const reco::Candidate * > vCands
Definition: utilities.hh:15
STL namespace.
bool isVetoElectron(const pat::Electron &lep, edm::Handle< reco::VertexCollection > vtx, double lepIso)
bool idElectron(const pat::Electron &lep, edm::Handle< reco::VertexCollection > vtx, CutLevel threshold, bool doIso=false)
float getMT(float pt1, float phi1, float pt2, float phi2)
Definition: utilities.cc:44
bool preselection(const reco::Muon &mu, bool selectClones) const
static const TH2D sf_fast_electron_mediumiso
Definition: lepton_tools.hh:97
#define ERROR(x)
Definition: utilities.hh:18
bool tighterId(const reco::Muon &mu) const
bool isVetoMuon(const pat::Muon &lep, edm::Handle< reco::VertexCollection > vtx, double lepIso)
bool isSignalElectron(const pat::Electron &lep, edm::Handle< reco::VertexCollection > vtx, double lepIso)
double getRelIsolation(const pat::Muon &lep, double rho)
vCands getRA4IsoTracks(edm::Handle< pat::PackedCandidateCollection > pfcands, double met, double met_phi, double rhoEventCentral, std::vector< float > &isos, std::vector< float > &relisos, int primary_pdg)
bool tightGlobal(const reco::Muon &mu) const
static const TH2F sf_full_muon_vtx
Definition: lepton_tools.hh:96
double getEffAreaMuon(double eta)
bool idMuon(const pat::Muon &lep, edm::Handle< reco::VertexCollection > vtx, CutLevel threshold)
bool isSignalMuon(const pat::Muon &lep, edm::Handle< reco::VertexCollection > vtx, double lepIso)
static const TH2F sf_full_muon_iso
Definition: lepton_tools.hh:96
pair< double, double > GetSF(const T &h, double x, double y, bool ignore_error=false)
Definition: lepton_tools.cc:41
bool partnerId(const reco::Muon &mu) const
static const TH2F sf_full_electron_tracking
Definition: lepton_tools.hh:96
bool vertexMuon(const pat::Muon &lep, edm::Handle< reco::VertexCollection > vtx, double &dz, double &d0)
bool outInOnly(const reco::Muon &mu) const
static std::pair< double, double > getScaleFactor(const reco::Candidate &cand)
double getEffAreaElectron(double eta)
static const TH2D sf_fast_muon_medium
Definition: lepton_tools.hh:97
static const TH2F sf_full_electron_iso
Definition: lepton_tools.hh:96
static const TH2D sf_fast_muon_iso
Definition: lepton_tools.hh:97
vCands getIsoTracks(edm::Handle< pat::PackedCandidateCollection > pfcands, double met, double met_phi)
bool vertexElectron(const pat::Electron &lep, edm::Handle< reco::VertexCollection > vtx, double &dz, double &d0)
static std::pair< double, double > getScaleFactorFs(const reco::Candidate &cand)