CMS 3D CMS Logo

ElectronMVAEstimatorRun2Spring15NonTrig.cc
Go to the documentation of this file.
2 
5 
7 
9 
10 #include "TMath.h"
11 #include "TMVA/MethodBDT.h"
12 
15  _tag(conf.getParameter<std::string>("mvaTag")),
16  _MethodName("BDTG method"),
17  _beamSpotLabel(conf.getParameter<edm::InputTag>("beamSpot")),
18  _conversionsLabelAOD(conf.getParameter<edm::InputTag>("conversionsAOD")),
19  _conversionsLabelMiniAOD(conf.getParameter<edm::InputTag>("conversionsMiniAOD")) {
20 
21  const std::vector <std::string> weightFileNames
22  = conf.getParameter<std::vector<std::string> >("weightFileNames");
23 
24  if( (int)(weightFileNames.size()) != nCategories )
25  throw cms::Exception("MVA config failure: ")
26  << "wrong number of weightfiles" << std::endl;
27 
28  _gbrForests.clear();
29  // Create a TMVA reader object for each category
30  for(int i=0; i<nCategories; i++){
31 
32  // Use unique_ptr so that all readers are properly cleaned up
33  // when the vector clear() is called in the destructor
34 
35  edm::FileInPath weightFile( weightFileNames[i] );
36  _gbrForests.push_back( GBRForestTools::createGBRForest( weightFile ) );
37 
38  }
39 
40 }
41 
44 }
45 
46 
48 
49  // All tokens for event content needed by this MVA
50 
51  // Beam spot (same for AOD and miniAOD)
52  cc.consumes<reco::BeamSpot>(_beamSpotLabel);
53 
54  // Conversions collection (different names in AOD and miniAOD)
57 
58 
59 }
60 
62 mvaValue( const edm::Ptr<reco::Candidate>& particle, const edm::Event& iEvent) const {
63 
64  const int iCategory = findCategory( particle );
65  const std::vector<float> vars = fillMVAVariables( particle, iEvent );
66  const float result = _gbrForests.at(iCategory)->GetResponse(vars.data()); // The BDT score
67 
68  const bool debug = false;
69  if(debug) {
70  std::cout << " *** Inside the class _MethodName " << _MethodName << std::endl;
71  std::cout << " bin " << iCategory
72  << " fbrem " << vars[11]
73  << " kfchi2 " << vars[9]
74  << " mykfhits " << vars[8]
75  << " gsfchi2 " << vars[10]
76  << " deta " << vars[18]
77  << " dphi " << vars[19]
78  << " detacalo " << vars[20]
79  << " see " << vars[0]
80  << " spp " << vars[1]
81  << " etawidth " << vars[4]
82  << " phiwidth " << vars[5]
83  << " OneMinusE1x5E5x5 " << vars[2]
84  << " R9 " << vars[3]
85  << " HoE " << vars[6]
86  << " EoP " << vars[15]
87  << " IoEmIoP " << vars[17]
88  << " eleEoPout " << vars[16]
89  << " eta " << vars[24]
90  << " pt " << vars[21] << std::endl;
91  std::cout << " ### MVA " << result << std::endl;
92  }
93 
94  return result;
95 }
96 
98 
99  // Try to cast the particle into a reco particle.
100  // This should work for both reco and pat.
101  const edm::Ptr<reco::GsfElectron> eleRecoPtr = ( edm::Ptr<reco::GsfElectron> )particle;
102  if( eleRecoPtr.get() == nullptr )
103  throw cms::Exception("MVA failure: ")
104  << " given particle is expected to be reco::GsfElectron or pat::Electron," << std::endl
105  << " but appears to be neither" << std::endl;
106 
107  float pt = eleRecoPtr->pt();
108  float eta = eleRecoPtr->superCluster()->eta();
109 
110  //
111  // Determine the category
112  //
113  int iCategory = UNDEFINED;
114  const float ptSplit = 10; // we have above and below 10 GeV categories
115  const float ebSplit = 0.800;// barrel is split into two regions
116  const float ebeeSplit = 1.479; // division between barrel and endcap
117 
118  if (pt < ptSplit && std::abs(eta) < ebSplit)
119  iCategory = CAT_EB1_PT5to10;
120 
121  if (pt < ptSplit && std::abs(eta) >= ebSplit && std::abs(eta) < ebeeSplit)
122  iCategory = CAT_EB2_PT5to10;
123 
124  if (pt < ptSplit && std::abs(eta) >= ebeeSplit)
125  iCategory = CAT_EE_PT5to10;
126 
127  if (pt >= ptSplit && std::abs(eta) < ebSplit)
128  iCategory = CAT_EB1_PT10plus;
129 
130  if (pt >= ptSplit && std::abs(eta) >= ebSplit && std::abs(eta) < ebeeSplit)
131  iCategory = CAT_EB2_PT10plus;
132 
133  if (pt >= ptSplit && std::abs(eta) >= ebeeSplit)
134  iCategory = CAT_EE_PT10plus;
135 
136  return iCategory;
137 }
138 
141 
142  bool isEndcap = false;
143  if( category == CAT_EE_PT5to10 || category == CAT_EE_PT10plus )
144  isEndcap = true;
145 
146  return isEndcap;
147 }
148 
149 // A function that should work on both pat and reco objects
152  const edm::Event& iEvent ) const {
153 
154  //
155  // Declare all value maps corresponding to the products we defined earlier
156  //
157  edm::Handle<reco::BeamSpot> theBeamSpot;
159 
160  // Get data needed for conversion rejection
161  iEvent.getByLabel(_beamSpotLabel, theBeamSpot);
162 
163  // Conversions in miniAOD and AOD have different names,
164  // but the same type, so we use the same handle with different tokens.
165  iEvent.getByLabel(_conversionsLabelAOD, conversions);
166  if( !conversions.isValid() )
167  iEvent.getByLabel(_conversionsLabelMiniAOD, conversions);
168 
169  // Make sure everything is retrieved successfully
170  if(! (theBeamSpot.isValid()
171  && conversions.isValid() )
172  )
173  throw cms::Exception("MVA failure: ")
174  << "Failed to retrieve event content needed for this MVA"
175  << std::endl
176  << "Check python MVA configuration file."
177  << std::endl;
178 
179  // Try to cast the particle into a reco particle.
180  // This should work for both reco and pat.
181  const edm::Ptr<reco::GsfElectron> eleRecoPtr = ( edm::Ptr<reco::GsfElectron> )particle;
182  if( eleRecoPtr.get() == nullptr )
183  throw cms::Exception("MVA failure: ")
184  << " given particle is expected to be reco::GsfElectron or pat::Electron," << std::endl
185  << " but appears to be neither" << std::endl;
186 
187  // Both pat and reco particles have exactly the same accessors, so we use a reco ptr
188  // throughout the code, with a single exception as of this writing, handled separately below.
189  auto superCluster = eleRecoPtr->superCluster();
190 
191  AllVariables allMVAVars;
192 
193  // Pure ECAL -> shower shapes
194  allMVAVars.see = eleRecoPtr->full5x5_sigmaIetaIeta();
195  allMVAVars.spp = eleRecoPtr->full5x5_sigmaIphiIphi();
196  allMVAVars.OneMinusE1x5E5x5 = 1. - eleRecoPtr->full5x5_e1x5() / eleRecoPtr->full5x5_e5x5();
197  allMVAVars.R9 = eleRecoPtr->full5x5_r9();
198  allMVAVars.etawidth = superCluster->etaWidth();
199  allMVAVars.phiwidth = superCluster->phiWidth();
200  allMVAVars.HoE = eleRecoPtr->hadronicOverEm();
201  // Endcap only variables
202  allMVAVars.PreShowerOverRaw = superCluster->preshowerEnergy() / superCluster->rawEnergy();
203 
204  // To get to CTF track information in pat::Electron, we have to have the pointer
205  // to pat::Electron, it is not accessible from the pointer to reco::GsfElectron.
206  // This behavior is reported and is expected to change in the future (post-7.4.5 some time).
207  bool validKF= false;
208  reco::TrackRef myTrackRef = eleRecoPtr->closestCtfTrackRef();
209  const edm::Ptr<pat::Electron> elePatPtr(eleRecoPtr);
210  // Check if this is really a pat::Electron, and if yes, get the track ref from this new
211  // pointer instead
212  if( elePatPtr.get() != nullptr )
213  myTrackRef = elePatPtr->closestCtfTrackRef();
214  validKF = (myTrackRef.isAvailable() && (myTrackRef.isNonnull()) );
215 
216  //Pure tracking variables
217  allMVAVars.kfhits = (validKF) ? myTrackRef->hitPattern().trackerLayersWithMeasurement() : -1. ;
218  allMVAVars.kfchi2 = (validKF) ? myTrackRef->normalizedChi2() : 0;
219  allMVAVars.gsfchi2 = eleRecoPtr->gsfTrack()->normalizedChi2();
220 
221  // Energy matching
222  allMVAVars.fbrem = eleRecoPtr->fbrem();
223 
224  allMVAVars.gsfhits = eleRecoPtr->gsfTrack()->hitPattern().trackerLayersWithMeasurement();
225  allMVAVars.expectedMissingInnerHits = eleRecoPtr->gsfTrack()
226  ->hitPattern().numberOfLostHits(reco::HitPattern::MISSING_INNER_HITS);
227 
229  conversions,
230  theBeamSpot->position());
231  double vertexFitProbability = -1.;
232  if(!conv_ref.isNull()) {
233  const reco::Vertex &vtx = conv_ref.get()->conversionVertex(); if (vtx.isValid()) {
234  vertexFitProbability = TMath::Prob( vtx.chi2(), vtx.ndof());
235  }
236  }
237  allMVAVars.convVtxFitProbability = vertexFitProbability;
238 
239  allMVAVars.EoP = eleRecoPtr->eSuperClusterOverP();
240  allMVAVars.eleEoPout = eleRecoPtr->eEleClusterOverPout();
241  float pAtVertex = eleRecoPtr->trackMomentumAtVtx().R();
242  allMVAVars.IoEmIoP = (1.0/eleRecoPtr->ecalEnergy()) - (1.0 / pAtVertex );
243 
244  // Geometrical matchings
245  allMVAVars.deta = eleRecoPtr->deltaEtaSuperClusterTrackAtVtx();
246  allMVAVars.dphi = eleRecoPtr->deltaPhiSuperClusterTrackAtVtx();
247  allMVAVars.detacalo = eleRecoPtr->deltaEtaSeedClusterTrackAtCalo();
248 
249  // Spectator variables
250  allMVAVars.pt = eleRecoPtr->pt();
251  float scEta = superCluster->eta();
252  constexpr float ebeeSplit = 1.479;
253  allMVAVars.isBarrel = ( std::abs(scEta) < ebeeSplit );
254  allMVAVars.isEndcap = ( std::abs(scEta) >= ebeeSplit );
255  allMVAVars.SCeta = scEta;
256  // The spectator variables below were examined for training, but
257  // are not necessary for evaluating the discriminator, so they are
258  // given dummy values (the specator variables above are also unimportant).
259  // They are introduced only to match the definition of the discriminator
260  // in the weights file.
261  constexpr unsigned nines = 999;
262  allMVAVars.eClass = nines;
263  allMVAVars.pfRelIso = nines;
264  allMVAVars.expectedInnerHits = nines;
265  allMVAVars.vtxconv = nines;
266  allMVAVars.mcEventWeight = nines;
267  allMVAVars.mcCBmatchingCategory = nines;
268 
269  constrainMVAVariables(allMVAVars);
270 
271  std::vector<float> vars;
272 
273  if( isEndcapCategory( findCategory( particle ) ) ) {
274  vars = packMVAVariables(allMVAVars.see,
275  allMVAVars.spp,
276  allMVAVars.OneMinusE1x5E5x5,
277  allMVAVars.R9,
278  allMVAVars.etawidth,
279  allMVAVars.phiwidth,
280  allMVAVars.HoE,
281  // Endcap only variables
282  allMVAVars.PreShowerOverRaw,
283  //Pure tracking variables
284  allMVAVars.kfhits,
285  allMVAVars.kfchi2,
286  allMVAVars.gsfchi2,
287  // Energy matching
288  allMVAVars.fbrem,
289  allMVAVars.gsfhits,
290  allMVAVars.expectedMissingInnerHits,
291  allMVAVars.convVtxFitProbability,
292  allMVAVars.EoP,
293  allMVAVars.eleEoPout,
294  allMVAVars.IoEmIoP,
295  // Geometrical matchings
296  allMVAVars.deta,
297  allMVAVars.dphi,
298  allMVAVars.detacalo,
299  // Spectator variables
300  allMVAVars.pt,
301  allMVAVars.isBarrel,
302  allMVAVars.isEndcap,
303  allMVAVars.SCeta,
304  allMVAVars.eClass,
305  allMVAVars.pfRelIso,
306  allMVAVars.expectedInnerHits,
307  allMVAVars.vtxconv,
308  allMVAVars.mcEventWeight,
309  allMVAVars.mcCBmatchingCategory);
310  } else {
311  vars = packMVAVariables(allMVAVars.see,
312  allMVAVars.spp,
313  allMVAVars.OneMinusE1x5E5x5,
314  allMVAVars.R9,
315  allMVAVars.etawidth,
316  allMVAVars.phiwidth,
317  allMVAVars.HoE,
318  //Pure tracking variables
319  allMVAVars.kfhits,
320  allMVAVars.kfchi2,
321  allMVAVars.gsfchi2,
322  // Energy matching
323  allMVAVars.fbrem,
324  allMVAVars.gsfhits,
325  allMVAVars.expectedMissingInnerHits,
326  allMVAVars.convVtxFitProbability,
327  allMVAVars.EoP,
328  allMVAVars.eleEoPout,
329  allMVAVars.IoEmIoP,
330  // Geometrical matchings
331  allMVAVars.deta,
332  allMVAVars.dphi,
333  allMVAVars.detacalo,
334  // Spectator variables
335  allMVAVars.pt,
336  allMVAVars.isBarrel,
337  allMVAVars.isEndcap,
338  allMVAVars.SCeta,
339  allMVAVars.eClass,
340  allMVAVars.pfRelIso,
341  allMVAVars.expectedInnerHits,
342  allMVAVars.vtxconv,
343  allMVAVars.mcEventWeight,
344  allMVAVars.mcCBmatchingCategory);
345  }
346  return vars;
347 }
348 
350 
351  // Check that variables do not have crazy values
352 
353  if(allMVAVars.fbrem < -1.)
354  allMVAVars.fbrem = -1.;
355 
356  allMVAVars.deta = fabs(allMVAVars.deta);
357  if(allMVAVars.deta > 0.06)
358  allMVAVars.deta = 0.06;
359 
360 
361  allMVAVars.dphi = fabs(allMVAVars.dphi);
362  if(allMVAVars.dphi > 0.6)
363  allMVAVars.dphi = 0.6;
364 
365 
366  if(allMVAVars.EoP > 20.)
367  allMVAVars.EoP = 20.;
368 
369  if(allMVAVars.eleEoPout > 20.)
370  allMVAVars.eleEoPout = 20.;
371 
372 
373  allMVAVars.detacalo = fabs(allMVAVars.detacalo);
374  if(allMVAVars.detacalo > 0.2)
375  allMVAVars.detacalo = 0.2;
376 
377  if(allMVAVars.OneMinusE1x5E5x5 < -1.)
378  allMVAVars.OneMinusE1x5E5x5 = -1;
379 
380  if(allMVAVars.OneMinusE1x5E5x5 > 2.)
381  allMVAVars.OneMinusE1x5E5x5 = 2.;
382 
383 
384 
385  if(allMVAVars.R9 > 5)
386  allMVAVars.R9 = 5;
387 
388  if(allMVAVars.gsfchi2 > 200.)
389  allMVAVars.gsfchi2 = 200;
390 
391 
392  if(allMVAVars.kfchi2 > 10.)
393  allMVAVars.kfchi2 = 10.;
394 
395 
396 }
397 
400  "ElectronMVAEstimatorRun2Spring15NonTrig");
bool isAvailable() const
Definition: Ref.h:577
T getParameter(std::string const &) const
GsfTrackRef gsfTrack() const override
reference to a GsfTrack
Definition: GsfElectron.h:185
std::vector< std::unique_ptr< const GBRForest > > _gbrForests
virtual TrackRef closestCtfTrackRef() const
Definition: GsfElectron.h:201
bool isNonnull() const
Checks for non-null.
Definition: Ref.h:253
float eSuperClusterOverP() const
Definition: GsfElectron.h:245
float full5x5_e5x5() const
Definition: GsfElectron.h:459
float full5x5_e1x5() const
Definition: GsfElectron.h:457
T const * get() const
Returns C++ pointer to the item.
Definition: Ptr.h:159
bool isValid() const
Tells whether the vertex is valid.
Definition: Vertex.h:68
math::XYZVectorF trackMomentumAtVtx() const
Definition: GsfElectron.h:291
float full5x5_sigmaIphiIphi() const
Definition: GsfElectron.h:456
double pt() const final
transverse momentum
int findCategory(const edm::Ptr< reco::Candidate > &particle) const override
float fbrem() const
Definition: GsfElectron.h:750
#define nullptr
#define constexpr
std::vector< Conversion > ConversionCollection
collectin of Conversion objects
Definition: ConversionFwd.h:9
float full5x5_sigmaIetaIeta() const
Definition: GsfElectron.h:455
std::vector< float > packMVAVariables(const Args...args) const
float deltaEtaSuperClusterTrackAtVtx() const
Definition: GsfElectron.h:249
int iEvent
Definition: GenABIO.cc:230
float hadronicOverEm() const
Definition: GsfElectron.h:487
static std::unique_ptr< const GBRForest > createGBRForest(const std::string &weightFile)
float deltaPhiSuperClusterTrackAtVtx() const
Definition: GsfElectron.h:252
void setConsumes(edm::ConsumesCollector &&) const final
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
double chi2() const
chi-squares
Definition: Vertex.h:98
float eEleClusterOverPout() const
Definition: GsfElectron.h:248
T const * get() const
Returns C++ pointer to the item.
Definition: Ref.h:245
bool isValid() const
Definition: HandleBase.h:74
bool getByLabel(InputTag const &tag, Handle< PROD > &result) const
Definition: Event.h:464
bool isEndcap(GeomDetEnumerators::SubDetector m)
bool isNull() const
Checks for null.
Definition: Ref.h:250
double ndof() const
Definition: Vertex.h:105
#define debug
Definition: HDRShower.cc:19
reco::TrackRef closestCtfTrackRef() const override
override the reco::GsfElectron::closestCtfTrackRef method, to access the internal storage of the trac...
float ecalEnergy() const
Definition: GsfElectron.h:837
float full5x5_r9() const
Definition: GsfElectron.h:460
float deltaEtaSeedClusterTrackAtCalo() const
Definition: GsfElectron.h:250
HLT enums.
float mvaValue(const edm::Ptr< reco::Candidate > &particle, const edm::Event &) const override
SuperClusterRef superCluster() const override
reference to a SuperCluster
Definition: GsfElectron.h:184
#define DEFINE_EDM_PLUGIN(factory, type, name)
const Point & position() const
position
Definition: BeamSpot.h:62
static reco::ConversionRef matchedConversion(const reco::GsfElectron &ele, const edm::Handle< reco::ConversionCollection > &convCol, const math::XYZPoint &beamspot, bool allowCkfMatch=true, float lxyMin=2.0, float probMin=1e-6, unsigned int nHitsBeforeVtxMax=0)
std::vector< float > fillMVAVariables(const edm::Ptr< reco::Candidate > &particle, const edm::Event &) const override