HackAnalysis  2
smearing.h
1 
2 
16 #pragma once
17 
18 #include <cassert>
19 #include <cstdlib>
20 #include <cstddef>
21 #include <type_traits>
22 
23 #include <random>
24 #include <cfloat> // for DBL_MAX
25 
26 
27 #include "heputil.h"
28 
29 
30 using namespace std;
31 
32 
33 
34 
35 
41 template<typename T1> void filterEfficiency(std::vector<T1*> &vec_t1, double eff_fn(T1* t1), std::mt19937 &engine)
42 {
43  //std::vector<bool> mask(vec_t1.size(),false);
44  std::uniform_real_distribution<double> rd(0.0,1.0);
45  auto it = vec_t1.begin();
46  while(it != vec_t1.end())
47  {
48  double eff=eff_fn(*it);
49  if(rd(engine) > eff)
50  {
51  it = vec_t1.erase(it);
52  }
53  else
54  {
55  it++;
56  }
57 
58  }
59 
60 
61 }
62 
63 
64 
65 
70 inline void smearbtag75(bool *btag, double pT, std::mt19937 &engine)
71 {
72  if(!(*btag)) return;
73 
74  const std::vector<double> binedges_pt = {0,20.,30.,40.,60.,80.,200.,250.,DBL_MAX};
75  const std::vector<double> btageff = {0.0,0.54,0.64,0.7,0.74,0.77,0.75,0.7};
76  static HEP::BinnedFn1D<double> _btageff1D(binedges_pt,btageff);
77 
78  double teff=_btageff1D.get_at(pT);
79  static std::uniform_real_distribution<double> rd(0.0,1.0);
80 
81 
82  if(rd(engine) > teff)
83  {
84  *btag=false;
85  }
86 
87 }
88 
89 
90 
91 
92 
94 inline double ATLASMediumJetEff(const HEP::Jet* jet) {
95 
96 
97  const std::vector<double> binedges_pt = {0,20.,25.,30.,35.,40.,45.,50.,55.,120.,DBL_MAX};
98  const std::vector<double> JVTeff = {0.0,0.86,0.9,0.92,0.93,0.94,0.95,0.95,0.96,1.0}; // jets with pT > 120 don't need to satify JVT
99  static HEP::BinnedFn1D<double> _JVTeff1D(binedges_pt,JVTeff);
100 
101 
102  if(jet->abseta() > 2.8) return 0.0; // vertex tagger to suppress pileup only used for central jets
103  if(jet->abseta() > 2.5) return 1.0; // Don't apply vertex tagger below eta = 2.5
104 
105  double teff=_JVTeff1D.get_at(jet->pT());
106  return teff;
107 
108 }
109 
110 
111 
112 
113 
114 
115 /*
116 double ElectronEff(HEP::Particle* electron) {
117  static HEP::BinnedFn2D<double> _elEff2d({{0, 1.5, 2.5, DBL_MAX}}, //< |eta|
118  {{0, 10., DBL_MAX}}, //< pT
119  {{0., 0.95, // |eta| 0.1-1.5
120  0., 0.85, // |eta| 1.5-2.5
121  0., 0.}}); // |eta| > 2.5
122  double teff=_elEff2d.get_at(electron->abseta(),electron->pT());
123  return (teff);
124 
125 }
126 
127 
128 
129 double MuonEff(HEP::Particle* muon) {
130  static HEP::BinnedFn2D<double> _muEff2d({{0,0.1,2.5,2.7,DBL_MAX}}, //< |eta|
131  {{0,5.0,10.0,DBL_MAX}}, //< pT
132  {{0.0,0.9,0.9, // |eta| < 0.1
133  0.0,0.98,0.99, // |eta| < 2.5
134  0.0,0.0,0.99, // |eta| < 2.7
135  0.0,0.0,0.0 // large eta
136  }});
137 
138 
139  double teff=_muEff2d.get_at(muon->abseta(),muon->pT());
140  return (teff);
141  }
142 
143 
144 
145 
146 HEP::P4 smearMET(const HEP::P4 &pTmiss, std::mt19937 &engine) {
147 
148  // uncertainty on MET is ~ 20 GeV on perp and , assume normal distribution
149  double MET=pTmiss.pT();
150  std::normal_distribution<> d(MET,20.0);
151 
152  double smear_factor=d(engine);
153  if(smear_factor <=0.0) return pTmiss;
154 
155  return HEP::P4::mkEtaPhiMPt(pTmiss.eta(),pTmiss.phi(),pTmiss.m(), smear_factor);
156 
157 }
158 
159 
160 */
161 
162 
163 
164 
165 
166 
167 
168  template<typename T1> void filtereff(std::vector<T1*> &particles, double eff, std::mt19937 &engine, bool do_delete=false)
169  {
170  static std::uniform_real_distribution<double> rd(0.0,1.0);
171  if (particles.empty()) return;
172  auto keptParticlesEnd = std::remove_if(particles.begin(), particles.end(),
173  [&](const T1* p)
174  {
175  const bool rm = rd(engine) > eff;
176  if (do_delete && rm) delete p;
177  return rm;
178  } );
179  particles.erase(keptParticlesEnd, particles.end());
180  }
181 
182 
183 
184 
185 
186  // Utility function for filtering a supplied particle vector by sampling wrt a binned 1D efficiency map in pT
187  template<typename T1> void filtereff_pt(std::vector<T1*> &particles, const HEP::BinnedFn1D<double>& eff_pt, std::mt19937 &engine, bool do_delete=false)
188  {
189  static std::uniform_real_distribution<double> rd(0.0,1.0);
190  if (particles.empty()) return;
191  auto keptParticlesEnd = std::remove_if(particles.begin(), particles.end(),
192  [&](const T1* p)
193  {
194  const bool rm = rd(engine) > eff_pt.get_at(p->pT());
195  if (do_delete && rm) delete p;
196  return rm;
197  } );
198  particles.erase(keptParticlesEnd, particles.end());
199  }
200 
201 
202  // Utility function for filtering a supplied particle vector by sampling wrt a binned 2D efficiency map in |eta| and pT
203  template<typename T1> void filtereff_etapt(std::vector<T1*> &particles, const HEP::BinnedFn2D<double>& eff_etapt, std::mt19937 &engine, bool do_delete=false)
204  {
205  static std::uniform_real_distribution<double> rd(0.0,1.0);
206  if (particles.empty()) return;
207  auto keptParticlesEnd = std::remove_if(particles.begin(), particles.end(),
208  [&](const T1* p)
209  {
210  const bool rm = rd(engine) > eff_etapt.get_at(p->abseta(),p->pT());
211  if (do_delete && rm) delete p;
212  return rm;
213  } );
214  particles.erase(keptParticlesEnd, particles.end());
215  }
216 
218  inline std::vector<double> mk_bin_values(const std::vector<double>& binEdgeValues) {
219  std::vector<double> results;
220  results.reserve(binEdgeValues.size()-1);
221  for (size_t i = 0; i < binEdgeValues.size()-1; ++i)
222  results.push_back( (binEdgeValues[i] + binEdgeValues[i+1])/2.0 );
223  return results;
224  }
226  inline std::vector<double> makeBinValues(const std::vector<double>& binEdgeValues) {
227  return mk_bin_values(binEdgeValues);
228  }
229 
230 
233  inline void MA5smearMuon(std::vector<HEP::Particle*>& muons, std::mt19937 &engine) {
234 
235  // Now loop over the muons and smear the 4-vectors
236  for (HEP::Particle* mu : muons) {
237  double abseta = mu->abseta();
238  if (abseta > 2.5) continue;
239 
240  // Look up resolution
241 
242  double pT = mu->pT();
243  double resolution=0.0;
244  if (abseta < 0.5)
245  {
246  resolution = sqrt(0.01*0.01+pT*pT*1.0e-8);
247  }
248  else if(abseta < 1.5)
249  {
250  resolution = sqrt(0.015*0.015+pT*pT*2.25e-8);
251 
252  }
253  else
254  {
255  resolution = sqrt(0.025*0.025+pT*pT*3.5*3.5e-8);
256 
257  }
258 
259 
260 
261  // Smear by a Gaussian centered on the current energy, with width given by the resolution
262  std::normal_distribution<> d(mu->pT(), resolution*mu->pT());
263  double smeared_pt = d(engine);
264  if (smeared_pt < 0) smeared_pt = 0;
265  // const double smeared_E = smeared_pt*cosh(mu->eta()); ///< @todo Should be cosh(|eta|)?
266  // std::cout << "Muon pt " << mu_pt << " smeared " << smeared_pt << endl;
267  mu->set_mom(HEP::P4::mkEtaPhiMPt(mu->eta(), mu->phi(), mu->mass(), smeared_pt));
268  }
269  }
270 
271  inline void MA5smearMuon(std::vector<const HEP::Particle*>& electrons, std::mt19937 &engine) {
272  MA5smearMuon(reinterpret_cast<std::vector<HEP::Particle*>&>(electrons),engine);
273  }
274 
275 
276 
277 namespace Gambit
278 {
279 
280  namespace ColliderBit
281  {
282 
283 
285  namespace ATLAS
286  {
287 
288 
289  static std::uniform_real_distribution<double> ATLASrd(0.0,1.0);
292 
293  // /// Randomly filter the supplied particle list by parameterised electron tracking efficiency
294  // /// @todo Remove? This is not the electron efficiency
295  // inline void applyElectronTrackingEff(std::vector<const HEPUtils::Particle*>& electrons) {
296  // static HEPUtils::BinnedFn2D<double> _elTrackEff2d({{0, 1.5, 2.5, DBL_MAX}}, //< |eta|
297  // {{0, 0.1, 1.0, 100, DBL_MAX}}, //< pT
298  // {{0., 0.73, 0.95, 0.99,
299  // 0., 0.5, 0.83, 0.90,
300  // 0., 0., 0., 0.}});
301  // filtereff_etapt(electrons, _elTrackEff2d);
302  // }
303 
304 
307  inline void applyElectronEff(std::vector<const HEP::Particle*>& electrons, std::mt19937 &engine) {
308  static HEP::BinnedFn2D<double> _elEff2d({{0,1.5,2.5,DBL_MAX}}, //< |eta|
309  {{0,10.,DBL_MAX}}, //< pT
310  {{0., 0.95,
311  0., 0.85,
312  0., 0.}});
313  filtereff_etapt(electrons, _elEff2d, engine);
314  }
315 
316 
317  // /// Randomly filter the supplied particle list by parameterised muon tracking efficiency
318  // /// @todo Remove? This is not the muon efficiency
319  // inline void applyMuonTrackEff(std::vector<const HEPUtils::Particle*>& muons) {
320  // static HEPUtils::BinnedFn2D<double> _muTrackEff2d({{0,1.5,2.5,DBL_MAX}}, //< |eta|
321  // {{0,0.1,1.0,DBL_MAX}}, //< pT
322  // {{0., 0.75, 0.99,
323  // 0., 0.70, 0.98,
324  // 0., 0., 0.}});
325  // filtereff_etapt(muons, _muTrackEff2d);
326  // }
327 
328 
330  inline void applyMuonEff(std::vector<const HEP::Particle*>& muons, std::mt19937 &engine) {
331  static HEP::BinnedFn2D<double> _muEff2d({{0,1.5,2.7,DBL_MAX}}, //< |eta|
332  {{0,10.0,DBL_MAX}}, //< pT
333  {{0., 0.95,
334  0., 0.85,
335  0., 0.}});
336  filtereff_etapt(muons, _muEff2d, engine);
337  }
338 
339 
341  inline void applyMuonEffR2(std::vector<const HEP::Particle*>& muons, std::mt19937 &engine) {
342  static HEP::BinnedFn2D<double> _muEff2d({0, 2.7, DBL_MAX}, //< |eta|
343  {0., 3.5, 4., 5., 6., 7., 8., 10., DBL_MAX}, //< pT
344  {0.00, 0.76, 0.94, 0.97, 0.98, 0.98, 0.98, 0.99,//
345  0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00});
346  filtereff_etapt(muons, _muEff2d, engine);
347  }
348 
349 
353  inline void applyTauEfficiencyR1(std::vector<const HEP::Particle*>& taus, std::mt19937 &engine) {
354  filtereff(taus, 0.40,engine);
355  }
356 
357 
361  inline void applyTauEfficiencyR2(std::vector<const HEP::Particle*>& taus, std::mt19937 &engine) {
362 
363  // Delphes 3.3.2 config:
364  // set DeltaR 0.2
365  // set DeltaRTrack 0.2
366  // set TrackPTMin 1.0
367  // set TauPTMin 1.0
368  // set TauEtaMax 2.5
369  // # instructions: {n-prongs} {eff}
370  // # 1 - one prong efficiency
371  // # 2 - two or more efficiency
372  // # -1 - one prong mistag rate
373  // # -2 - two or more mistag rate
374  // set BitNumber 0
375  // # taken from ATL-PHYS-PUB-2015-045 (medium working point)
376  // add EfficiencyFormula {1} {0.70}
377  // add EfficiencyFormula {2} {0.60}
378  // add EfficiencyFormula {-1} {0.02}
379  // add EfficiencyFormula {-2} {0.01}
380  // filtereff(taus, 0.65);
381 
382  // Distributions from ATL-PHYS-PUB-2015-045, Fig 10
383  const static std::vector<double> binedges_pt = { 0., 20., 40., 60., 120., 160., 220., 280., 380., 500., DBL_MAX };
384  const static std::vector<double> bineffs_pt_1p = { 0., .54, .55, .56, .58, .57, .56, .54, .51, 0. };
385  const static std::vector<double> bineffs_pt_3p = { 0., .40, .41, .42, .46, .46, .43, .39, .33, 0. };
386  const static HEP::BinnedFn1D<double> _eff_pt_1p(binedges_pt, bineffs_pt_1p);
387  const static HEP::BinnedFn1D<double> _eff_pt_3p(binedges_pt, bineffs_pt_3p);
388  // 85% 1-prong, 15% >=3-prong
389  const static std::vector<double> bineffs_pt_avg = { 0., .52, .53, .54, .56, .55, .54, .52, .48, 0. };
390  const static HEP::BinnedFn1D<double> _eff_pt_avg(binedges_pt, bineffs_pt_avg);
391  filtereff_pt(taus, _eff_pt_avg,engine);
392 
393  }
394 
395 
396 
397  inline void applyPhotonEfficiencyR2(std::vector<const HEP::Particle*>& photons, std::mt19937 &engine) {
398 
399  const static std::vector<double> binedges_eta = { 0., 0.6, 1.37, 1.52, 1.81, 2.37, DBL_MAX };
400  const static std::vector<double> binedges_pt = { 0., 10., 15., 20., 25., 30., 35., 40., 45., 50., 60., 80., 100., 125., 150., 175., 250., DBL_MAX };
401  const static std::vector<double> bineffs_etapt = { 0.00, 0.55, 0.70, 0.85, 0.89, 0.93, 0.95, 0.96, 0.96, 0.97, 0.97, 0.98, 0.97, 0.97, 0.97, 0.97, 0.97, //
402  0.00, 0.47, 0.66, 0.79, 0.86, 0.89, 0.94, 0.96, 0.97, 0.97, 0.98, 0.97, 0.98, 0.98, 0.98, 0.98, 0.98, //
403  0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, //
404  0.00, 0.54, 0.71, 0.84, 0.88, 0.92, 0.93, 0.94, 0.95, 0.96, 0.96, 0.96, 0.96, 0.96, 0.96, 0.96, 0.96, //
405  0.00, 0.61, 0.74, 0.83, 0.88, 0.91, 0.94, 0.95, 0.96, 0.97, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98, //
406  0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00 };
407  const static HEP::BinnedFn2D<double> _eff_etapt(binedges_eta, binedges_pt, bineffs_etapt);
408  filtereff_etapt(photons, _eff_etapt,engine);
409  }
410 
411 
413  inline void smearElectronEnergy(std::vector<HEP::Particle*>& electrons, std::mt19937 &engine) {
414  // Function that mimics the DELPHES electron energy resolution
415  // We need to smear E, then recalculate pT, then reset 4 vector
416 
417  static HEP::BinnedFn2D<double> coeffE2({{0, 2.5, 3., 5.}}, //< |eta|
418  {{0, 0.1, 25., DBL_MAX}}, //< pT
419  {{0., 0.015*0.015, 0.005*0.005,
420  0.005*0.005, 0.005*0.005, 0.005*0.005,
421  0.107*0.107, 0.107*0.107, 0.107*0.107}});
422 
423  static HEP::BinnedFn2D<double> coeffE({{0, 2.5, 3., 5.}}, //< |eta|
424  {{0, 0.1, 25., DBL_MAX}}, //< pT
425  {{0., 0., 0.05*0.05,
426  0.05*0.05, 0.05*0.05, 0.05*0.05,
427  2.08*2.08, 2.08*2.08, 2.08*2.08}});
428 
429  static HEP::BinnedFn2D<double> coeffC({{0, 2.5, 3., 5.}}, //< |eta|
430  {{0, 0.1, 25., DBL_MAX}}, //< pT
431  {{0., 0., 0.25*0.25,
432  0.25*0.25,0.25*0.25,0.25*0.25,
433  0., 0., 0.}});
434 
435  // Now loop over the electrons and smear the 4-vectors
436  for (HEP::Particle* e : electrons) {
437  if (e->abseta() > 5) continue;
438 
439  // Look up / calculate resolution
440  const double c1 = coeffE2.get_at(e->abseta(), e->pT());
441  const double c2 = coeffE.get_at(e->abseta(), e->pT());
442  const double c3 = coeffC.get_at(e->abseta(), e->pT());
443  const double resolution = sqrt(c1*HEP::sqr(e->E()) + c2*e->E() + c3);
444 
445  // Smear by a Gaussian centered on the current energy, with width given by the resolution
446  std::normal_distribution<> d(e->E(), resolution);
447  double smeared_E = d(engine);
448  if (smeared_E < e->mass()) smeared_E = 1.01*e->mass();
449  // double smeared_pt = smeared_E/cosh(e->eta()); ///< @todo Should be cosh(|eta|)?
450  e->set_mom(HEP::P4::mkEtaPhiME(e->eta(), e->phi(), e->mass(), smeared_E));
451  }
452  }
453 
454 
455  inline void smearElectronEnergy(std::vector<const HEP::Particle*>& electrons, std::mt19937 &engine) {
456  smearElectronEnergy(reinterpret_cast<std::vector<HEP::Particle*>&>(electrons),engine);
457  }
458 
460  inline void smearMuonMomentum(std::vector<HEP::Particle*>& muons, std::mt19937 &engine) {
461  // Function that mimics the DELPHES muon momentum resolution
462  // We need to smear pT, then recalculate E, then reset 4 vector
463 
464  static HEP::BinnedFn2D<double> _muEff({{0,1.5,2.5}},
465  {{0,0.1,1.,10.,200.,DBL_MAX}},
466  {{0.,0.03,0.02,0.03,0.05,
467  0.,0.04,0.03,0.04,0.05}});
468 
469  // Now loop over the muons and smear the 4-vectors
470  for (HEP::Particle* mu : muons) {
471  if (mu->abseta() > 2.5) continue;
472 
473  // Look up resolution
474  const double resolution = _muEff.get_at(mu->abseta(), mu->pT());
475 
476  // Smear by a Gaussian centered on the current energy, with width given by the resolution
477  std::normal_distribution<> d(mu->pT(), resolution*mu->pT());
478  double smeared_pt = d(engine);
479  if (smeared_pt < 0) smeared_pt = 0;
480  // const double smeared_E = smeared_pt*cosh(mu->eta()); ///< @todo Should be cosh(|eta|)?
481  // std::cout << "Muon pt " << mu_pt << " smeared " << smeared_pt << endl;
482  mu->set_mom(HEP::P4::mkEtaPhiMPt(mu->eta(), mu->phi(), mu->mass(), smeared_pt));
483  }
484  }
485 
486  inline void smearMuonMomentum(std::vector<const HEP::Particle*>& electrons, std::mt19937 &engine) {
487  smearMuonMomentum(reinterpret_cast<std::vector<HEP::Particle*>&>(electrons),engine);
488  }
489 
491  inline void smearJets(std::vector<HEP::Jet*>& jets, std::mt19937 &engine) {
492  // Function that mimics the DELPHES jet momentum resolution.
493  // We need to smear pT, then recalculate E, then reset the 4-vector.
494  // Const resolution for now
495  //const double resolution = 0.03;
496 
497  // Matthias jet smearing implemented roughly from
498  // https://atlas.web.cern.ch/Atlas/GROUPS/PHYSICS/CONFNOTES/ATLAS-CONF-2015-017/
499  // Parameterisation can be still improved, but eta dependence is minimal
500  const std::vector<double> binedges_eta = {0,10.};
501  const std::vector<double> binedges_pt = {0,50.,70.,100.,150.,200.,1000.,10000.};
502  const std::vector<double> JetsJER = {0.145,0.115,0.095,0.075,0.07,0.05,0.04};
503  static HEP::BinnedFn2D<double> _resJets2D(binedges_eta,binedges_pt,JetsJER);
504 
505  // Now loop over the jets and smear the 4-vectors
506  for (HEP::Jet* jet : jets) {
507  const double resolution = _resJets2D.get_at(jet->abseta(), jet->pT());
508  std::normal_distribution<> d(1., resolution);
509  // Smear by a Gaussian centered on 1 with width given by the (fractional) resolution
510  double smear_factor = d(engine);
512  jet->set_mom(HEP::P4::mkXYZM(jet->mom().px()*smear_factor, jet->mom().py()*smear_factor, jet->mom().pz()*smear_factor, jet->mass()));
513  }
514  }
515 
516 
518  inline void smearMET(HEP::P4& pmiss, double set, std::mt19937 &engine) {
519  // Smearing function from ATLAS Run 1 performance paper, converted from Rivet
520  // cf. https://arxiv.org/pdf/1108.5602v2.pdf, Figs 14 and 15
521 
522  // Linearity offset (Fig 14)
523  if (pmiss.pT() < 25) pmiss *= 1.05;
524  else if (pmiss.pT() < 40) pmiss *= (1.05 - (0.04/15)*(pmiss.pT() - 25)); //< linear decrease
525  else pmiss *= 1.01;
526 
527  // Smear by a Gaussian with width given by the resolution(sumEt) ~ 0.45 sqrt(sumEt) GeV
528  const double resolution = 0.45 * sqrt(set);
529  std::normal_distribution<> d(pmiss.pT(), resolution);
530  const double smearedmet = std::max(d(engine), 0.);
531 
532  pmiss *= smearedmet / pmiss.pT();
533  }
534 
535 
537  inline void smearTaus(std::vector<HEP::Particle*>& taus, std::mt19937 &engine) {
538  // We need to smear pT, then recalculate E, then reset the 4-vector.
539  // Same as for jets, but on a vector of particles. (?)
540  // Const resolution for now
541  const double resolution = 0.03;
542 
543  // Now loop over the jets and smear the 4-vectors
544  std::normal_distribution<> d(1., resolution);
545  for (HEP::Particle* p : taus) {
546  // Smear by a Gaussian centered on 1 with width given by the (fractional) resolution
547  double smear_factor = d(engine);
549  p->set_mom(HEP::P4::mkXYZM(p->mom().px()*smear_factor, p->mom().py()*smear_factor, p->mom().pz()*smear_factor, p->mass()));
550  }
551  }
552 
553 
557  inline void applyLooseIDElectronSelectionR2(std::vector<const HEP::Particle*>& electrons, std::mt19937 &engine) {
558  if (electrons.empty()) return;
559 
560  // Manually symmetrised eta eff histogram
561  const static std::vector<double> binedges_eta = { 0.0, 0.1, 0.8, 1.37, 1.52, 2.01, 2.37, 2.47, DBL_MAX };
562  const static std::vector<double> bineffs_eta = { 0.950, 0.965, 0.955, 0.885, 0.950, 0.935, 0.90, 0 };
563  const static HEP::BinnedFn1D<double> _eff_eta(binedges_eta, bineffs_eta);
564  // Et eff histogram (10-20 GeV bin added by hand)
565  const static std::vector<double> binedges_et = { 10, 20, 25, 30, 35, 40, 45, 50, 60, 80, DBL_MAX };
566  const static std::vector<double> bineffs_et = { 0.90, 0.91, 0.92, 0.94, 0.95, 0.955, 0.965, 0.97, 0.98, 0.98 };
567  const static HEP::BinnedFn1D<double> _eff_et(binedges_et, bineffs_et);
568  //static std::uniform_real_distribution<double> ATLASrd(0.0,1.0);
569  auto keptElectronsEnd = std::remove_if(electrons.begin(), electrons.end(),
570  [&engine](const HEP::Particle* electron) {
571  const double e_pt = electron->pT();
572  const double e_aeta = electron->abseta();
573  if (e_aeta > 2.47 || e_pt < 10) return true;
574  const double eff1 = _eff_eta.get_at(e_aeta), eff2 = _eff_et.get_at(e_pt);
575  const double eff = std::min(eff1 * eff2 / 0.95, 1.0); //< norm factor as approximate double differential
576  return ATLASrd(engine) < (1-eff);
577  } );
578  electrons.erase(keptElectronsEnd, electrons.end());
579  }
580 
582  inline void applyLooseIDElectronSelectionR2(std::vector<HEP::Particle*>& electrons, std::mt19937 &engine) {
583  applyLooseIDElectronSelectionR2(reinterpret_cast<std::vector<const HEP::Particle*>&>(electrons),engine);
584  }
585 
588  inline void applyMediumIDElectronSelectionR2(std::vector<const HEP::Particle*>& electrons, std::mt19937 &engine) {
589  if (electrons.empty()) return;
590 
591  // Manually symmetrised eta eff histogram
592  const static std::vector<double> binedges_eta = { 0.0, 0.1, 0.8, 1.37, 1.52, 2.01, 2.37, 2.47, DBL_MAX };
593  const static std::vector<double> bineffs_eta = { 0.900, 0.930, 0.905, 0.830, 0.900, 0.880, 0.85, 0 };
594  const static HEP::BinnedFn1D<double> _eff_eta(binedges_eta, bineffs_eta);
595  // Et eff histogram (10-20 GeV bin added by hand)
596  const static std::vector<double> binedges_et = { 10, 20, 25, 30, 35, 40, 45, 50, 60, 80, DBL_MAX };
597  const static std::vector<double> bineffs_et = { 0.83, 0.845, 0.87, 0.89, 0.90, 0.91, 0.92, 0.93, 0.95, 0.95 };
598  const static HEP::BinnedFn1D<double> _eff_et(binedges_et, bineffs_et);
599  //static std::uniform_real_distribution<double> ATLASrd(0.0,1.0);
600  auto keptElectronsEnd = std::remove_if(electrons.begin(), electrons.end(),
601  [&engine](const HEP::Particle* electron) {
602  const double e_pt = electron->pT();
603  const double e_aeta = electron->abseta();
604  if (e_aeta > 2.47 || e_pt < 10) return true;
605  const double eff1 = _eff_eta.get_at(e_aeta), eff2 = _eff_et.get_at(e_pt);
606  const double eff = std::min(eff1 * eff2 / 0.95, 1.0); //< norm factor as approximate double differential
607  return ATLASrd(engine) < (1-eff);
608  } );
609  electrons.erase(keptElectronsEnd, electrons.end());
610  }
611 
613  inline void applyMediumIDElectronSelectionR2(std::vector<HEP::Particle*>& electrons, std::mt19937 &engine) {
614  applyMediumIDElectronSelectionR2(reinterpret_cast<std::vector<const HEP::Particle*>&>(electrons),engine);
615  }
616 
617 
618 
621  inline void applyMediumIDElectronSelection(std::vector<const HEP::Particle*>& electrons, std::mt19937 &engine) {
622  if (electrons.empty()) return;
623 
624  const static std::vector<double> binedges_E10_15 = {0., 0.0494681, 0.453578, 1.10675, 1.46298, 1.78963, 2.2766, 2.5};
625  const static std::vector<double> binvalues_E10_15 = makeBinValues({0.730435, 0.730435, 0.782609, 0.776812, 0.765217, 0.773913, 0.77971, 0.776812});
626  const static HEP::BinnedFn1D<double> _eff_E10_15(binedges_E10_15, binvalues_E10_15);
627 
628  const static std::vector<double> binedges_E15_20 = {0., 0.0533175, 0.456161, 1.1019, 1.46327, 1.78318, 2.26303, 2.5};
629  const static std::vector<double> binvalues_E15_20 = makeBinValues({0.77971, 0.77971, 0.82029, 0.817391, 0.701449, 0.797101, 0.828986, 0.828986});
630  const static HEP::BinnedFn1D<double> _eff_E15_20(binedges_E15_20, binvalues_E15_20);
631 
632  const static std::vector<double> binedges_E20_25 = {-2.5, -2.45249, -2.21496, -1.94181, -1.6924, -1.46675, -1.26485, -0.991686, -0.682898, -0.350356, -0.0415677, 0.0653207, 0.362233, 0.718527, 0.97981, 1.2886, 1.45487, 1.68052, 1.94181, 2.23872, 2.45249, 2.5};
633  const static std::vector<double> binvalues_E20_25 = makeBinValues({0.827811, 0.82572, 0.790414, 0.798585, 0.779843, 0.727974, 0.802447, 0.798192, 0.812561, 0.812423, 0.808153, 0.779115, 0.822483, 0.816123, 0.795304, 0.793105, 0.772326, 0.778446, 0.794906, 0.78857, 0.821617, 0.821593});
634  const static HEP::BinnedFn1D<double> _eff_E20_25(binedges_E20_25, binvalues_E20_25);
635 
636  const static std::vector<double> binedges_E25_30 = {-2.5, -2.45249, -2.22684, -1.92993, -1.6924, -1.46675, -1.26485, -0.97981, -0.694774, -0.33848, -0.0534442, 0.0771971, 0.33848, 0.74228, 1.00356, 1.26485, 1.46675, 1.6924, 1.94181, 2.22684, 2.45249, 2.5};
637  const static std::vector<double> binvalues_E25_30 = makeBinValues({0.84095, 0.838892, 0.8286, 0.830801, 0.818436, 0.76037, 0.841463, 0.83535, 0.850008, 0.852233, 0.837812, 0.82748, 0.854592, 0.854759, 0.838251, 0.844591, 0.76782, 0.815688, 0.836563, 0.824219, 0.838853, 0.838877});
638  const static HEP::BinnedFn1D<double> _eff_E25_30(binedges_E25_30, binvalues_E25_30);
639 
640  const static std::vector<double> binedges_E30_35 = {-2.5, -2.44062, -2.21496, -1.92993, -1.68052, -1.46675, -1.27672, -0.991686, -0.706651, -0.350356, -0.0534442, 0.0771971, 0.350356, 0.706651, 0.97981, 1.2886, 1.47862, 1.68052, 1.94181, 2.23872, 2.44062, 2.5};
641  const static std::vector<double> binvalues_E30_35 = makeBinValues({0.849263, 0.849233, 0.840831, 0.853176, 0.844763, 0.771974, 0.873676, 0.865249, 0.877593, 0.883677, 0.869013, 0.856496, 0.879231, 0.883238, 0.870661, 0.870533, 0.779059, 0.839213, 0.84949, 0.834827, 0.834743, 0.834718});
642  const static HEP::BinnedFn1D<double> _eff_E30_35(binedges_E30_35, binvalues_E30_35);
643 
644  const static std::vector<double> binedges_E35_40 = {-2.5, -2.44841, -2.23431, -1.94914, -1.69969, -1.46336, -1.28359, -0.998664, -0.713488, -0.357087, -0.0723338, 0.0580256, 0.343519, 0.699955, 1.0085, 1.26989, 1.45836, 1.685, 1.93451, 2.23118, 2.46818, 2.5};
645  const static std::vector<double> binvalues_E35_40 = makeBinValues({0.836795, 0.84095, 0.859644, 0.867953, 0.87003, 0.799407, 0.894955, 0.888724, 0.897033, 0.903264, 0.886647, 0.87003, 0.897033, 0.905341, 0.890801, 0.897033, 0.805638, 0.863798, 0.87003, 0.85549, 0.824332, 0.826409});
646  const static HEP::BinnedFn1D<double> _eff_E35_40(binedges_E35_40, binvalues_E35_40);
647 
648  const static std::vector<double> binedges_E40_45 = {-2.5, -2.45261, -2.22749, -1.93128, -1.68246, -1.46919, -1.27962, -0.995261, -0.7109, -0.343602, -0.0592417, 0.0473934, 0.35545, 0.699052, 0.983412, 1.27962, 1.4455, 1.69431, 1.94313, 2.22749, 2.44076, 2.5};
649  const static std::vector<double> binvalues_E40_45 = makeBinValues({0.836795, 0.836795, 0.87003, 0.882493, 0.897033, 0.84095, 0.911573, 0.89911, 0.907418, 0.909496, 0.89911, 0.888724, 0.907418, 0.91365, 0.89911, 0.907418, 0.843027, 0.890801, 0.882493, 0.87003, 0.816024, 0.816024});
650  const static HEP::BinnedFn1D<double> _eff_E40_45(binedges_E40_45, binvalues_E40_45);
651 
652  const static std::vector<double> binedges_E45_50 = {-2.5, -2.46086, -2.22192, -1.93675, -1.68709, -1.46211, -1.27124, -0.986416, -0.689328, -0.356822, -0.0482438, 0.0584337, 0.355838, 0.712203, 0.996992, 1.28217, 1.45947, 1.68576, 1.93499, 2.21988, 2.44378, 2.5};
653  const static std::vector<double> binvalues_E45_50 = makeBinValues({0.807101, 0.807101, 0.889941, 0.898225, 0.912722, 0.873373, 0.923077, 0.910651, 0.921006, 0.918935, 0.906509, 0.894083, 0.923077, 0.927219, 0.912722, 0.921006, 0.871302, 0.90858, 0.898225, 0.889941, 0.786391, 0.786391});
654  const static HEP::BinnedFn1D<double> _eff_E45_50 = {binedges_E45_50, binvalues_E45_50};
655 
656  const static std::vector<double> binedges_E50_60 = {-2.5, -2.44076, -2.21564, -1.93128, -1.69431, -1.46919, -1.26777, -0.983412, -0.7109, -0.35545, -0.0592417, 0.0592417, 0.35545, 0.7109, 0.983412, 1.27962, 1.46919, 1.68246, 1.91943, 2.22749, 2.44076, 2.5};
657  const static std::vector<double> binvalues_E50_60 = makeBinValues({0.785417, 0.785417, 0.891667, 0.9, 0.916667, 0.877083, 0.927083, 0.91875, 0.91875, 0.922917, 0.90625, 0.9, 0.922917, 0.929167, 0.920833, 0.925, 0.885417, 0.9125, 0.904167, 0.885417, 0.7625, 0.7625});
658  const static HEP::BinnedFn1D<double> _eff_E50_60 = {binedges_E50_60, binvalues_E50_60};
659 
660  const static std::vector<double> binedges_E60_80 = {-2.5, -2.44933, -2.22119, -1.9353, -1.68491, -1.47115, -1.2682, -0.982628, -0.696912, -0.351494, -0.0423579, 0.0526683, 0.350856, 0.719871, 1.00552, 1.29137, 1.46938, 1.69596, 1.94572, 2.24305, 2.45479, 2.5};
661  const static std::vector<double> binvalues_E60_80 = makeBinValues({0.779163, 0.779188, 0.893866, 0.904402, 0.927423, 0.896262, 0.92968, 0.921466, 0.921585, 0.932145, 0.909357, 0.896897, 0.930355, 0.928425, 0.924377, 0.93283, 0.899571, 0.922582, 0.908102, 0.89156, 0.741648, 0.741678});
662  const static HEP::BinnedFn1D<double> _eff_E60_80 = {binedges_E60_80, binvalues_E60_80};
663 
664  const static std::vector<double> binedges_E80 = {-2.5, -2.45835, -2.22058, -1.94663, -1.68451, -1.44712, -1.27961, -0.970161, -0.708258, -0.351259, -0.0537477, 0.0532884, 0.351188, 0.72041, 0.994111, 1.29176, 1.4815, 1.70839, 1.93419, 2.21998, 2.45825, 2.5};
665  const static std::vector<double> binvalues_E80 = makeBinValues({0.951041, 0.948944, 0.930151, 0.938346, 0.9507, 0.909058, 0.95884, 0.954557, 0.954449, 0.945992, 0.939637, 0.933361, 0.949854, 0.960086, 0.953741, 0.955695, 0.911996, 0.953445, 0.930502, 0.934538, 0.944824, 0.9448});
666  const static HEP::BinnedFn1D<double> _eff_E80 = {binedges_E80, binvalues_E80};
667 
668  // Now loop over the electrons and only keep those that pass the random efficiency cut
671  auto keptElectronsEnd = std::remove_if(electrons.begin(), electrons.end(),
672  [&engine](const HEP::Particle* electron) {
673  const double e_pt = electron->pT();
674  const double e_eta = electron->eta();
675  if (!(fabs(e_eta) < 2.5 && e_pt >= 10)) return true;
676  else if (HEP::in_range(e_pt, 10, 15)) return ATLASrd(engine) > _eff_E10_15.get_at(fabs(e_eta));
677  else if (HEP::in_range(e_pt, 15, 20)) return ATLASrd(engine) > _eff_E15_20.get_at(fabs(e_eta));
678  else if (HEP::in_range(e_pt, 20, 25)) return ATLASrd(engine) > _eff_E20_25.get_at(fabs(e_eta));
679  else if (HEP::in_range(e_pt, 25, 30)) return ATLASrd(engine) > _eff_E25_30.get_at(fabs(e_eta));
680  else if (HEP::in_range(e_pt, 30, 35)) return ATLASrd(engine) > _eff_E30_35.get_at(fabs(e_eta));
681  else if (HEP::in_range(e_pt, 35, 40)) return ATLASrd(engine) > _eff_E35_40.get_at(fabs(e_eta));
682  else if (HEP::in_range(e_pt, 40, 45)) return ATLASrd(engine) > _eff_E40_45.get_at(fabs(e_eta));
683  else if (HEP::in_range(e_pt, 45, 50)) return ATLASrd(engine) > _eff_E45_50.get_at(fabs(e_eta));
684  else if (HEP::in_range(e_pt, 50, 60)) return ATLASrd(engine) > _eff_E50_60.get_at(fabs(e_eta));
685  else if (HEP::in_range(e_pt, 60, 80)) return ATLASrd(engine) > _eff_E60_80.get_at(fabs(e_eta));
686  else return ATLASrd(engine) > _eff_E80.get_at(fabs(e_eta));
687  } );
688  electrons.erase(keptElectronsEnd, electrons.end());
689  }
690 
691 
693  inline void applyMediumIDElectronSelection(std::vector<HEP::Particle*>& electrons,std::mt19937 &engine) {
694  applyMediumIDElectronSelection(reinterpret_cast<std::vector<const HEP::Particle*>&>(electrons),engine);
695  }
696 
697 
700  inline void applyTightIDElectronSelection(std::vector<const HEP::Particle*>& electrons, std::mt19937 &engine) {
701 
702  const static std::vector<double> binedges_E10_15 = {0., 0.0485903, 0.458914, 1.10009, 1.46117, 1.78881, 2.27013, 2.5};
703  const static std::vector<double> binvalues_E10_15 = makeBinValues({0.57971, 0.582609, 0.681159, 0.655072, 0.46087, 0.634783, 0.689855, 0.689855});
704  const static HEP::BinnedFn1D<double> _eff_E10_15(binedges_E10_15, binvalues_E10_15);
705 
706  const static std::vector<double> binedges_E15_20 = {0., 0.0533175, 0.450237, 1.09597, 1.46327, 1.78318, 2.26896, 2.5};
707  const static std::vector<double> binvalues_E15_20 = makeBinValues({0.631884, 0.628986, 0.727536, 0.701449, 0.565217, 0.666667, 0.733333, 0.733333});
708  const static HEP::BinnedFn1D<double> _eff_E15_20(binedges_E15_20, binvalues_E15_20);
709 
710  const static std::vector<double> binedges_E20_25 = {-2.5, -2.44062, -2.22684, -1.92993, -1.66865, -1.45487, -1.26485, -0.967933, -0.706651, -0.350356, -0.0415677, 0.0653207, 0.362233, 0.718527, 0.991686, 1.27672, 1.47862, 1.6924, 1.92993, 2.22684, 2.46437, 2.5};
711  const static std::vector<double> binvalues_E20_25 = makeBinValues({0.678698, 0.678674, 0.70965, 0.65361, 0.655573, 0.599567, 0.6844, 0.694632, 0.729731, 0.731654, 0.665254, 0.640358, 0.743785, 0.733282, 0.697962, 0.672992, 0.585926, 0.660394, 0.652011, 0.703663, 0.670429, 0.668338});
712  const static HEP::BinnedFn1D<double> _eff_E20_25(binedges_E20_25, binvalues_E20_25);
713 
714  const static std::vector<double> binedges_E25_30 = {-2.5, -2.44062, -2.22684, -1.91805, -1.68052, -1.45487, -1.27672, -0.97981, -0.706651, -0.350356, -0.0415677, 0.0771971, 0.362233, 0.718527, 0.991686, 1.30048, 1.47862, 1.6924, 1.94181, 2.22684, 2.46437, 2.5};
715  const static std::vector<double> binvalues_E25_30 = makeBinValues({0.678932, 0.681034, 0.737205, 0.683328, 0.695889, 0.633669, 0.720983, 0.733569, 0.758609, 0.769142, 0.69657, 0.688311, 0.771515, 0.771663, 0.734388, 0.717899, 0.636964, 0.699368, 0.689086, 0.730747, 0.67684, 0.67686});
716  const static HEP::BinnedFn1D<double> _eff_E25_30(binedges_E25_30, binvalues_E25_30);
717 
718  const static std::vector<double> binedges_E30_35 = {-2.5, -2.45249, -2.21496, -1.94181, -1.68052, -1.47862, -1.27672, -0.97981, -0.706651, -0.33848, -0.0415677, 0.0534442, 0.362233, 0.718527, 1.00356, 1.27672, 1.46675, 1.68052, 1.95368, 2.23872, 2.45249, 2.5};
719  const static std::vector<double> binvalues_E30_35 = makeBinValues({0.691395, 0.691375, 0.749436, 0.716089, 0.726366, 0.653582, 0.749047, 0.771772, 0.800739, 0.802663, 0.731916, 0.71526, 0.802372, 0.810532, 0.773025, 0.75214, 0.656512, 0.722892, 0.712393, 0.745509, 0.670643, 0.6727});
720  const static HEP::BinnedFn1D<double> _eff_E30_35(binedges_E30_35, binvalues_E30_35);
721 
722  const static std::vector<double> binedges_E35_40 = {-2.5, -2.46296, -2.22413, -1.93966, -1.7017, -1.47721, -1.28567, -0.988409, -0.714721, -0.334744, -0.0510125, 0.0437527, 0.342215, 0.710598, 0.971211, 1.27968, 1.45638, 1.68306, 1.94399, 2.21764, 2.44185, 2.5};
723  const static std::vector<double> binvalues_E35_40 = makeBinValues({0.683086, 0.683086, 0.759941, 0.726706, 0.751632, 0.683086, 0.772404, 0.793175, 0.824332, 0.820178, 0.743323, 0.728783, 0.820178, 0.832641, 0.793175, 0.774481, 0.689318, 0.749555, 0.728783, 0.757864, 0.6727, 0.6727});
724  const static HEP::BinnedFn1D<double> _eff_E35_40(binedges_E35_40, binvalues_E35_40);
725 
726  const static std::vector<double> binedges_E40_45 = {-2.5, -2.45261, -2.21564, -1.94313, -1.69431, -1.45735, -1.27962, -0.983412, -0.7109, -0.35545, -0.0592417, 0.0473934, 0.35545, 0.699052, 0.983412, 1.26777, 1.45735, 1.67062, 1.93128, 2.20379, 2.45261, 2.5};
727  const static std::vector<double> binvalues_E40_45 = makeBinValues({0.693472, 0.693472, 0.782789, 0.757864, 0.784866, 0.726706, 0.797329, 0.803561, 0.836795, 0.805638, 0.747478, 0.735015, 0.805638, 0.843027, 0.807715, 0.797329, 0.732938, 0.780712, 0.762018, 0.782789, 0.674777, 0.674777});
728  const static HEP::BinnedFn1D<double> _eff_E40_45(binedges_E40_45, binvalues_E40_45);
729 
730  const static std::vector<double> binedges_E45_50 = {-2.5, -2.46311, -2.22329, -1.93875, -1.70073, -1.47585, -1.273, -0.976015, -0.714205, -0.358403, -0.0625448, 0.0560444, 0.354151, 0.711078, 0.98364, 1.28045, 1.45768, 1.68407, 1.94493, 2.20653, 2.4415, 2.5};
731  const static std::vector<double> binvalues_E45_50 = makeBinValues({0.674556, 0.674556, 0.809172, 0.780178, 0.809172, 0.763609, 0.819527, 0.823669, 0.854734, 0.82574, 0.763609, 0.753254, 0.823669, 0.860947, 0.82574, 0.819527, 0.76568, 0.809172, 0.78432, 0.802959, 0.651775, 0.651775});
732  const static HEP::BinnedFn1D<double> _eff_E45_50 = {binedges_E45_50, binvalues_E45_50};
733 
734  const static std::vector<double> binedges_E50_60 = {-2.5, -2.45261, -2.21564, -1.93128, -1.68246, -1.45735, -1.27962, -0.995261, -0.699052, -0.343602, -0.0592417, 0.0592417, 0.35545, 0.699052, 0.983412, 1.26777, 1.4455, 1.68246, 1.94313, 2.21564, 2.45261, 2.5};
735  const static std::vector<double> binvalues_E50_60 = makeBinValues({0.6625, 0.6625, 0.810417, 0.795833, 0.81875, 0.779167, 0.839583, 0.84375, 0.860417, 0.841667, 0.777083, 0.764583, 0.841667, 0.877083, 0.85, 0.839583, 0.785417, 0.816667, 0.8, 0.804167, 0.64375, 0.64375});
736  const static HEP::BinnedFn1D<double> _eff_E50_60 = {binedges_E50_60, binvalues_E50_60};
737 
738  const static std::vector<double> binedges_E60_80 = {-2.5, -2.46326, -2.22265, -1.93711, -1.69844, -1.47299, -1.28152, -0.995631, -0.709702, -0.364674, -0.0564949, 0.0504716, 0.349652, 0.707116, 0.980538, 1.27812, 1.46757, 1.69447, 1.94394, 2.24157, 2.45288, 2.5};
739  const static std::vector<double> binvalues_E60_80 = makeBinValues({0.660412, 0.660432, 0.808449, 0.798151, 0.831584, 0.787928, 0.846341, 0.856877, 0.869496, 0.85714, 0.778101, 0.767729, 0.859521, 0.87842, 0.855617, 0.853658, 0.79332, 0.835081, 0.803935, 0.804059, 0.629147, 0.629172});
740  const static HEP::BinnedFn1D<double> _eff_E60_80 = {binedges_E60_80, binvalues_E60_80};
741 
742  const static std::vector<double> binedges_E80 = {-2.5, -2.45987, -2.22149, -1.94797, -1.69748, -1.47206, -1.29251, -0.994818, -0.709105, -0.352212, -0.0558319, 0.0513809, 0.374044, 0.719562, 0.981359, 1.27873, 1.46843, 1.70723, 1.9449, 2.20712, 2.45676, 2.5};
743  const static std::vector<double> binvalues_E80 = makeBinValues({0.859652, 0.859627, 0.876145, 0.859415, 0.888391, 0.8426, 0.900685, 0.904716, 0.904597, 0.889909, 0.817086, 0.821195, 0.893762, 0.910235, 0.903895, 0.889231, 0.843455, 0.884899, 0.859875, 0.87846, 0.857585, 0.85756});
744  const static HEP::BinnedFn1D<double> _eff_E80 = {binedges_E80, binvalues_E80};
745 
746  // Now loop over the electrons and only keep those that pass the random efficiency cut
749  auto keptElectronsEnd = std::remove_if(electrons.begin(), electrons.end(),
750  [&engine](const HEP::Particle* electron) {
751  const double e_pt = electron->pT();
752  const double e_eta = electron->eta();
753  if (!(fabs(e_eta) < 2.5 && e_pt >= 10)) return true;
754  else if (HEP::in_range(e_pt, 10, 15)) return ATLASrd(engine) > _eff_E10_15.get_at(fabs(e_eta));
755  else if (HEP::in_range(e_pt, 15, 20)) return ATLASrd(engine) > _eff_E15_20.get_at(fabs(e_eta));
756  else if (HEP::in_range(e_pt, 20, 25)) return ATLASrd(engine) > _eff_E20_25.get_at(fabs(e_eta));
757  else if (HEP::in_range(e_pt, 25, 30)) return ATLASrd(engine) > _eff_E25_30.get_at(fabs(e_eta));
758  else if (HEP::in_range(e_pt, 30, 35)) return ATLASrd(engine) > _eff_E30_35.get_at(fabs(e_eta));
759  else if (HEP::in_range(e_pt, 35, 40)) return ATLASrd(engine) > _eff_E35_40.get_at(fabs(e_eta));
760  else if (HEP::in_range(e_pt, 40, 45)) return ATLASrd(engine) > _eff_E40_45.get_at(fabs(e_eta));
761  else if (HEP::in_range(e_pt, 45, 50)) return ATLASrd(engine) > _eff_E45_50.get_at(fabs(e_eta));
762  else if (HEP::in_range(e_pt, 50, 60)) return ATLASrd(engine) > _eff_E50_60.get_at(fabs(e_eta));
763  else if (HEP::in_range(e_pt, 60, 80)) return ATLASrd(engine) > _eff_E60_80.get_at(fabs(e_eta));
764  else return ATLASrd(engine) > _eff_E80.get_at(fabs(e_eta));
765  } );
766  electrons.erase(keptElectronsEnd, electrons.end());
767  }
768 
769 
771  inline void applyTightIDElectronSelection(std::vector<HEP::Particle*>& electrons,std::mt19937 &engine) {
772  applyTightIDElectronSelection(reinterpret_cast<std::vector<const HEP::Particle*>&>(electrons),engine);
773  }
774 
775 
778  inline void applyElectronIDEfficiency2019(std::vector<const HEP::Particle*>& electrons, std::string operating_point,std::mt19937 &engine)
779  {
780 
781  // digitised from Fig 8
782  const static std::vector<double> binedges_pt = { 0.0, 6.668795911849248, 9.673354432217419, 14.643593391597225, 19.57318312476409, 24.71356813100665, 29.655352632037403, 34.594233616910074, 39.73636073284749, 44.68221015649952, 49.6292209866148, 59.52440405330856, 79.51859702099242, DBL_MAX};
783  const static std::vector<double> bineffs_pt_loose = { 0.9054376657824932, 0.9267904509283819, 0.8757294429708221, 0.8450928381962863, 0.8775862068965516, 0.889655172413793, 0.9035809018567638, 0.9193633952254641, 0.929575596816976, 0.9370026525198938, 0.942572944297082, 0.9509283819628646, 0.9592838196286471};
784  const static std::vector<double> bineffs_pt_medium = { 0.7355437665782492, 0.7912466843501325, 0.7986737400530503, 0.7717506631299733, 0.8135278514588858, 0.8348806366047744, 0.8525198938992041, 0.8692307692307691, 0.8822281167108752, 0.889655172413793, 0.902652519893899, 0.9230769230769229, 0.9407161803713526 };
785  const static std::vector<double> bineffs_pt_tight = { 0.5572944297082227, 0.6213527851458884, 0.6547745358090185, 0.6714854111405835, 0.699336870026525, 0.7299734748010609, 0.7559681697612731, 0.7754641909814322, 0.7921750663129972, 0.8079575596816975, 0.8311671087533155, 0.8710875331564986, 0.8989389920424402 };
786 
787  // select operating point
788  std::vector<double> bineffs_pt;
789  if (operating_point == "Loose" || operating_point == "VeryLoose")
790  bineffs_pt = bineffs_pt_loose;
791  else if (operating_point == "Medium")
792  bineffs_pt = bineffs_pt_medium;
793  else if (operating_point == "Tight")
794  bineffs_pt = bineffs_pt_tight;
795  else
796  bineffs_pt = bineffs_pt_loose;
797  const static HEP::BinnedFn1D<double> _eff_pt(binedges_pt, bineffs_pt);
798 
799  // filter electrons
800  filtereff_pt(electrons, _eff_pt,engine);
801 
802  }
803 
806  inline void applyElectronIsolationEfficiency2019(std::vector<const HEP::Particle*>& electrons, std::string operating_point,std::mt19937 &engine)
807  {
808 
809  // digitised from Fig 12
810  const static std::vector<double> binedges_pt = {0.0, 6.548307897301772, 9.706735099256047, 14.643593391597225, 19.611982283197417, 24.561829913760132, 29.71154676569653, 34.461525174885566, 39.61370954807349, 44.56047277707178, 49.5109372879474, 59.60803424919497, 79.4086585320716, DBL_MAX};
811  const static std::vector<double> bineffs_pt_loose_trackonly = {0.9694027334287603, 0.9841898810834618, 0.9915715839022242, 0.9890807366218896, 0.9875756991852016, 0.9875509249064084, 0.9875261506276152, 0.9879947974014535, 0.9884634441752919, 0.9884386698964986, 0.9888959617925568, 0.9907953231667035, 0.9930404921823388};
812  const static std::vector<double> bineffs_pt_loose = {0.9595332801145123, 0.9812303870292888, 0.9891055109006828, 0.9875994412023784, 0.9856020149746753, 0.9826167143800926, 0.9820985190486677, 0.9820737447698745, 0.9820489704910813, 0.9825186495265361, 0.9829749091609778, 0.9903008698524555, 0.9930394599207224};
813  const static std::vector<double> bineffs_pt_gradient_loose = {0.8973632597445498, 0.9471843343977098, 0.9693676365338032, 0.9466465260955738, 0.947115172869412, 0.9485706617485136, 0.9539735190486678, 0.9593784408720547, 0.9642868448579609, 0.9706755120017618, 0.9780417308962784, 0.9843808494824929, 0.9851457553402335};
814  const static std::vector<double> bineffs_pt_gradient = {0.8425935229024444, 0.9082030389781987, 0.944204195111209, 0.9007573359392205, 0.9081359419731337, 0.9145235768553183, 0.924368255890773, 0.9351987447698745, 0.9460292336489761, 0.9573531435807092, 0.9716251926888351, 0.9838874284298613, 0.9851457553402335};
815 
816  // select operating point
817  std::vector<double> bineffs_pt;
818  if (operating_point == "LooseTrackOnly")
819  bineffs_pt = bineffs_pt_loose_trackonly;
820  else if (operating_point == "Loose")
821  bineffs_pt = bineffs_pt_loose;
822  else if (operating_point == "GradientLoose")
823  bineffs_pt = bineffs_pt_gradient_loose;
824  else if (operating_point == "Gradient")
825  bineffs_pt = bineffs_pt_gradient;
826  else
827  bineffs_pt = bineffs_pt_loose;
828  const static HEP::BinnedFn1D<double> _eff_pt(binedges_pt, bineffs_pt);
829 
830  // filter electrons
831  filtereff_pt(electrons, _eff_pt,engine);
832  }
833 
834 
837  inline void applyElectronReconstructionEfficiency2020(std::vector<const HEP::Particle*>& electrons, std::string operating_point,std::mt19937 &engine){
838 
839  // Digitised from Fig 5
840  const static std::vector<double> binedges_pt = {0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, 10.5, 11.0, 11.5, 12.0, 12.5, 13.0, 13.5, 14.0, 14.5, 15.0, 15.5, 16.0, 16.5, 17.0, 17.5, 18.0, 18.5, 19.0, 19.5, 20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.5, 24.0, 24.5, DBL_MAX};
841  const static std::vector<double> bineffs_pt_candidate = {0.0, 0.0, 0.0, 0.0, 0.003218, 0.049709, 0.203532, 0.388353, 0.546803, 0.662459, 0.749662, 0.807719, 0.850278, 0.875487, 0.893757, 0.907169, 0.919424, 0.926128, 0.932831, 0.936759, 0.940224, 0.944846, 0.947386, 0.949695, 0.951078, 0.953849, 0.955695, 0.956847, 0.958924, 0.959845, 0.962154, 0.96238, 0.96492, 0.966766, 0.966762, 0.967914, 0.967678, 0.970912, 0.970676, 0.97229, 0.972286, 0.97205, 0.973664, 0.97366, 0.973655, 0.973419, 0.975496, 0.976417, 0.977106, 0.976639};
842 
843  // Select operating point
844  std::vector<double> bineffs_pt;
845  //if (operating_point == "Candidate")
846  bineffs_pt = bineffs_pt_candidate;
847  //else
848 
849  const static HEP::BinnedFn1D<double> _eff_pt(binedges_pt, bineffs_pt);
850 
851  // Filter muons
852  filtereff_pt(electrons, _eff_pt,engine);
853  }
854 
855 
856 
859  inline void applyElectronIDEfficiency2020(std::vector<const HEP::Particle*>& electrons, std::string operating_point,std::mt19937 &engine){
860 
861  // Digitised from Fig 23a
862  const static std::vector<double> binedges_pt = {4.5, 7.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 60.0, 80.0, DBL_MAX};
863  const static std::vector<double> bineffs_pt_loose = {0.976333, 0.928653, 0.882698, 0.830078, 0.86466, 0.884306, 0.901769, 0.920381, 0.930032, 0.936581, 0.938994, 0.943589, 0.949449};
864  const static std::vector<double> bineffs_pt_medium = {0.790671, 0.797679, 0.816062, 0.752183, 0.794807, 0.82801, 0.847541, 0.868796, 0.882008, 0.887868, 0.897518, 0.916475, 0.93233};
865  const static std::vector<double> bineffs_pt_tight = {0.582835, 0.608686, 0.670726, 0.651999, 0.684283, 0.716567, 0.747358, 0.768038, 0.782399, 0.795381, 0.815832, 0.853631, 0.884536};
866 
867  // Select operating point
868  std::vector<double> bineffs_pt;
869  if (operating_point == "Loose")
870  bineffs_pt = bineffs_pt_loose;
871  else if (operating_point == "Medium")
872  bineffs_pt = bineffs_pt_medium;
873  else if (operating_point == "Tight")
874  bineffs_pt = bineffs_pt_tight;
875  else
876  bineffs_pt = bineffs_pt_loose;
877 
878  const static HEP::BinnedFn1D<double> _eff_pt(binedges_pt, bineffs_pt);
879 
880  // Filter muons
881  filtereff_pt(electrons, _eff_pt,engine);
882  }
883 
884 
887  inline void applyElectronIsolationEfficiency2020(std::vector<const HEP::Particle*>& electrons, std::string operating_point,std::mt19937 &engine){
888 
889  // Digitised from Fig 23a
890  const static std::vector<double> binedges_pt = {4.5, 7.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 60.0, 80.0, 150.0, 200.0, 250.0, 300.0, 350.0, DBL_MAX};
891  const static std::vector<double> bineffs_pt_gradient = {0.800008, 0.880847, 0.927209, 0.879823, 0.888724, 0.895806, 0.908012, 0.9198, 0.929307, 0.941235, 0.960432, 0.979162, 0.982515, 0.993515, 0.994261, 0.995376, 0.993139, 0.992581};
892  const static std::vector<double> bineffs_pt_loose = {0.740555, 0.826427, 0.905545, 0.951997, 0.972965, 0.983728, 0.990392, 0.994352, 0.996819, 0.997565, 0.997844, 0.998311, 0.99859, 0.99859, 0.999057, 0.999105, 0.996589, 0.997614};
893  const static std::vector<double> bineffs_pt_tight = {0.458893, 0.541276, 0.617828, 0.698061, 0.769957, 0.822, 0.862863, 0.895528, 0.924554, 0.940538, 0.95321, 0.970449, 0.985547, 0.992351, 0.993187, 0.993606, 0.991326, 0.991326};
894  const static std::vector<double> bineffs_pt_highptcaloonly = {0.982097, 0.975105, 0.969703, 0.967933, 0.966908, 0.965137, 0.965416, 0.966859, 0.970449, 0.970358, 0.967138, 0.962014, 0.950973, 0.926185, 0.904053, 0.908291, 0.925906, 0.929168};
895 
896  // Select operating point
897  std::vector<double> bineffs_pt;
898  if (operating_point == "Gradient")
899  {bineffs_pt = bineffs_pt_gradient;}
900  else if (operating_point == "Loose")
901  bineffs_pt = bineffs_pt_loose;
902  else if (operating_point == "Tight")
903  bineffs_pt = bineffs_pt_tight;
904  else if (operating_point == "HighPtCaloOnly")
905  bineffs_pt = bineffs_pt_highptcaloonly;
906  else
907  bineffs_pt = bineffs_pt_loose;
908  const static HEP::BinnedFn1D<double> _eff_pt(binedges_pt, bineffs_pt);
909 
910  // Filter muons
911  filtereff_pt(electrons, _eff_pt,engine);
912  }
913 
914 
917  inline void applyMuonIDEfficiency2020(std::vector<const HEP::Particle*>& muons, std::string operating_point,std::mt19937 &engine){
918 
919  // Digitised from Fig 11a
920  const static std::vector<double> binedges_pt = {3.0, 3.5, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 12.0, 14.0, 16.0, 18.0, DBL_MAX};
921  const static std::vector<double> bineffs_pt_tight = {0.0, 0.0, 0.66948, 0.8143, 0.85466, 0.87816, 0.89246, 0.90421, 0.91418, 0.91877, 0.92031, 0.92669, 0.93972};
922  const static std::vector<double> bineffs_pt_medium = {0.45262, 0.61328, 0.80766, 0.9387, 0.96245, 0.97063, 0.97165, 0.97216, 0.97292, 0.97292, 0.97216, 0.97114, 0.97522};
923  const static std::vector<double> bineffs_pt_loose = {0.87075, 0.93129, 0.97241, 0.98851, 0.99157, 0.98851, 0.98799, 0.98799, 0.98799, 0.98748, 0.98672, 0.98748, 0.98927};
924 
925  // Select operating point
926  std::vector<double> bineffs_pt;
927  if (operating_point == "Tight")
928  bineffs_pt = bineffs_pt_tight;
929  else if (operating_point == "Medium")
930  bineffs_pt = bineffs_pt_medium;
931  else if (operating_point == "Loose")
932  //std::cout << "Loose ";
933  bineffs_pt = bineffs_pt_loose;
934  else
935  bineffs_pt = bineffs_pt_tight;
936  const static HEP::BinnedFn1D<double> _eff_pt(binedges_pt, bineffs_pt);
937 
938  // Filter muons
939  filtereff_pt(muons, _eff_pt,engine);
940  }
941 
944  inline void applyMuonIsolationEfficiency2020(std::vector<const HEP::Particle*>& muons, std::string operating_point,std::mt19937 &engine){
945 
946  // Digitised from Fig 19a
947  const static std::vector<double> binedges_pt = {3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 15.0, 20.0, 30.0, 40.0, 55.0, 70.0, 90.0, 150.0, DBL_MAX};
948  const static std::vector<double> bineffs_pt_tight = {0.56788, 0.63355, 0.66702, 0.68974, 0.70173, 0.71814, 0.7314, 0.75917, 0.79262, 0.84313, 0.9189, 0.96941, 0.9915, 0.99653, 0.99649, 0.99517};
949  const static std::vector<double> bineffs_pt_loose = {0.655349, 0.725581, 0.765116, 0.788605, 0.82093, 0.851395, 0.877907, 0.92, 0.956279, 0.981163, 0.992558, 0.996744, 0.997442, 0.997442, 0.997674, 0.995116};
950 
951  // Select operating point
952  std::vector<double> bineffs_pt;
953  if (operating_point == "Tight")
954  bineffs_pt = bineffs_pt_tight;
955  else if (operating_point == "Loose")
956  {bineffs_pt = bineffs_pt_loose;}
957  else
958  bineffs_pt = bineffs_pt_loose;
959  const static HEP::BinnedFn1D<double> _eff_pt(binedges_pt, bineffs_pt);
960 
961  // Filter muons
962  filtereff_pt(muons, _eff_pt,engine);
963  }
964 
966 
967  }
968  }
969 }
const T & get_at(const TX &x, const TY &y) const
Get the value in the bin at position (x,y)
Definition: BinnedFn.h:332
Definition: Jet.h:21
double abseta() const
Get the abs pseudorapidity.
Definition: Jet.h:78
const P4 & mom() const
Get the 4 vector.
Definition: Jet.h:63
double mass()
Get the mass (of the 4 vector)
Definition: Jet.h:69
double pT() const
Get the squared transverse momentum.
Definition: Jet.h:96
void set_mom(const P4 &p4)
Set the 4 vector.
Definition: Jet.h:65
A 4-momentum class for vectors.
Definition: Vectors.h:45
double px() const
Get px.
Definition: Vectors.h:393
static P4 mkXYZM(double px, double py, double pz, double mass)
Make a vector from (px,py,pz) coordinates and the mass.
Definition: Vectors.h:101
static P4 mkEtaPhiME(double eta, double phi, double mass, double E)
Make a vector from (eta,phi,energy) coordinates and the mass.
Definition: Vectors.h:106
double pT() const
Get the transverse momentum (same as rho)
Definition: Vectors.h:453
double pz() const
Get pz.
Definition: Vectors.h:401
static P4 mkEtaPhiMPt(double eta, double phi, double mass, double pt)
Make a vector from (eta,phi,pT) coordinates and the mass.
Definition: Vectors.h:111
double py() const
Get py.
Definition: Vectors.h:397
Definition: Particle.h:24
void applyMuonIDEfficiency2020(std::vector< const HEP::Particle * > &muons, std::string operating_point, std::mt19937 &engine)
Definition: smearing.h:917
void applyMuonEffR2(std::vector< const HEP::Particle * > &muons, std::mt19937 &engine)
Randomly filter the supplied particle list by parameterised muon efficiency.
Definition: smearing.h:341
void smearTaus(std::vector< HEP::Particle * > &taus, std::mt19937 &engine)
Randomly smear the supplied taus' momenta by parameterised resolutions.
Definition: smearing.h:537
void applyElectronIsolationEfficiency2020(std::vector< const HEP::Particle * > &electrons, std::string operating_point, std::mt19937 &engine)
Definition: smearing.h:887
void smearJets(std::vector< HEP::Jet * > &jets, std::mt19937 &engine)
Randomly smear the supplied jets' momenta by parameterised resolutions.
Definition: smearing.h:491
void applyMuonIsolationEfficiency2020(std::vector< const HEP::Particle * > &muons, std::string operating_point, std::mt19937 &engine)
Definition: smearing.h:944
void applyTauEfficiencyR1(std::vector< const HEP::Particle * > &taus, std::mt19937 &engine)
Definition: smearing.h:353
void applyElectronReconstructionEfficiency2020(std::vector< const HEP::Particle * > &electrons, std::string operating_point, std::mt19937 &engine)
Definition: smearing.h:837
void applyTauEfficiencyR2(std::vector< const HEP::Particle * > &taus, std::mt19937 &engine)
Definition: smearing.h:361
void applyMediumIDElectronSelection(std::vector< const HEP::Particle * > &electrons, std::mt19937 &engine)
Definition: smearing.h:621
void applyTightIDElectronSelection(std::vector< const HEP::Particle * > &electrons, std::mt19937 &engine)
Definition: smearing.h:700
void smearElectronEnergy(std::vector< HEP::Particle * > &electrons, std::mt19937 &engine)
Randomly smear the supplied electrons' momenta by parameterised resolutions.
Definition: smearing.h:413
void applyElectronIDEfficiency2020(std::vector< const HEP::Particle * > &electrons, std::string operating_point, std::mt19937 &engine)
Definition: smearing.h:859
void applyElectronIDEfficiency2019(std::vector< const HEP::Particle * > &electrons, std::string operating_point, std::mt19937 &engine)
Definition: smearing.h:778
void smearMuonMomentum(std::vector< HEP::Particle * > &muons, std::mt19937 &engine)
Randomly smear the supplied muons' momenta by parameterised resolutions.
Definition: smearing.h:460
void applyElectronIsolationEfficiency2019(std::vector< const HEP::Particle * > &electrons, std::string operating_point, std::mt19937 &engine)
Definition: smearing.h:806
void applyMuonEff(std::vector< const HEP::Particle * > &muons, std::mt19937 &engine)
Randomly filter the supplied particle list by parameterised muon efficiency.
Definition: smearing.h:330
void applyLooseIDElectronSelectionR2(std::vector< const HEP::Particle * > &electrons, std::mt19937 &engine)
Definition: smearing.h:557
void applyElectronEff(std::vector< const HEP::Particle * > &electrons, std::mt19937 &engine)
Definition: smearing.h:307
void applyMediumIDElectronSelectionR2(std::vector< const HEP::Particle * > &electrons, std::mt19937 &engine)
Definition: smearing.h:588
void smearMET(HEP::P4 &pmiss, double set, std::mt19937 &engine)
Randomly smear the MET vector by parameterised resolutions.
Definition: smearing.h:518
GAMBIT smearing functions, shamelessly taken for comparison.
Definition: smearing.h:278
constexpr std::enable_if< std::is_arithmetic< N1 >::value, N1 >::type sqr(const N1 val)
Convenience function for squaring (better than repeating long expressions/calcs or using intermediate...
Definition: MathUtils.h:45