All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
IsolatedLeptonTaggingProcessor.cc
Go to the documentation of this file.
1 // *****************************************************
2 // Processor for isolated lepton tagging
3 // ----originally developped by C.Duerig and J.Tian
4 // ----for Higgs self-coupling analysis
5 // *****************************************************
7 
8 #include <EVENT/LCCollection.h>
9 #include <IMPL/LCCollectionVec.h>
10 #include <EVENT/ReconstructedParticle.h>
11 #include <EVENT/Cluster.h>
12 #include <UTIL/LCTypedVector.h>
13 #include <EVENT/Track.h>
14 #include <marlin/Exceptions.h>
15 #include <EVENT/Vertex.h>
16 #include <UTIL/LCIterator.h>
17 
18 // ----- include for verbosity dependend logging ---------
19 #include "marlin/VerbosityLevels.h"
20 
21 //root
22 #include "TVector3.h"
23 #include "TMath.h"
24 #include "TMVA/Reader.h"
25 //local
26 #include "Utilities.h"
27 
28 #include <memory>
29 #include <algorithm>
30 
31 using namespace lcio ;
32 using namespace marlin ;
33 using namespace std;
34 
35 using namespace TMVA;
36 using namespace isolep;
37 
39 
40 
41 IsolatedLeptonTaggingProcessor::IsolatedLeptonTaggingProcessor() : Processor("IsolatedLeptonTaggingProcessor") {
42 
43  // modify processor description
44  _description = "IsolatedLeptonTaggingProcessor does whatever it does ..." ;
45 
46 
47  // register steering parameters: name, description, class-variable, default value
48 
49  registerInputCollection( LCIO::RECONSTRUCTEDPARTICLE,
50  "InputPandoraPFOsCollection" ,
51  "Name of the PandoraPFOs collection" ,
52  _colPFOs ,
53  std::string("PandoraPFOs") ) ;
54 
55  registerInputCollection( LCIO::VERTEX,
56  "InputPrimaryVertexCollection" ,
57  "Name of the Primary Vertex collection" ,
58  _colPVtx ,
59  std::string("PrimaryVertex") ) ;
60 
61  registerOutputCollection( LCIO::RECONSTRUCTEDPARTICLE,
62  "OutputPFOsWithoutIsoLepCollection",
63  "Name of the new PFOs collection without isolated lepton",
65  std::string("PandoraPFOsWithoutIsoLep") );
66 
67  registerOutputCollection( LCIO::RECONSTRUCTEDPARTICLE,
68  "OutputIsoLeptonsCollection",
69  "Name of collection with the selected isolated lepton",
71  std::string("ISOLeptons") );
72 
73  registerProcessorParameter("DirOfISOElectronWeights",
74  "Directory of Weights for the Isolated Electron MVA Classification" ,
76  std::string("isolated_electron_weights") ) ;
77 
78  registerProcessorParameter("DirOfISOMuonWeights",
79  "Directory of Weights for the Isolated Muon MVA Classification" ,
81  std::string("isolated_muon_weights") ) ;
82 
83  registerProcessorParameter("CutOnTheISOElectronMVA",
84  "Cut on the mva output of isolated electron selection" ,
86  float(0.5) ) ;
87 
88  registerProcessorParameter("CutOnTheISOMuonMVA",
89  "Cut on the mva output of isolated muon selection" ,
91  float(0.7) ) ;
92 
93  registerProcessorParameter("IsSelectingOneIsoLep",
94  "flag to select one most like isolated lepton" ,
96  bool(true) ) ;
97 
98  registerProcessorParameter("MinEOverPForElectron",
99  "minimum ratio of energy in calorimeters over momentum for electron" ,
101  float(0.5) ) ;
102 
103  registerProcessorParameter("MaxEOverPForElectron",
104  "Maximum ratio of energy in calorimeters over momentum for electron" ,
106  float(1.3) ) ;
107 
108  registerProcessorParameter("MinEecalOverTotEForElectron",
109  "minimum ratio of energy in ecal over energy in ecal+hcal" ,
111  float(0.9) ) ;
112 
113  registerProcessorParameter("MaxD0SigForElectron",
114  "Maximum d0 significance for electron" ,
116  float(50.) ) ;
117 
118  registerProcessorParameter("MaxZ0SigForElectron",
119  "Maximum Z0 significance for electron" ,
121  float(5.) ) ;
122 
123  registerProcessorParameter("MinPForElectron",
124  "Minimum momentum for electron" ,
126  float(5.) ) ;
127 
128  registerProcessorParameter("MaxEOverPForMuon",
129  "Maximum ratio of energy in calorimeters over momentum for muon" ,
131  float(0.3) ) ;
132 
133  registerProcessorParameter("MinEyokeForMuon",
134  "Minimum energy in yoke for electron" ,
136  float(1.2) ) ;
137 
138  registerProcessorParameter("MaxD0SigForMuon",
139  "Maximum D0 significance for muon" ,
141  float(5.) ) ;
142 
143  registerProcessorParameter("MaxZ0SigForMuon",
144  "Maximum Z0 significance for muon" ,
146  float(5.) ) ;
147 
148  registerProcessorParameter("MinPForMuon",
149  "Minimum momentum for muon" ,
150  _minPForMuon ,
151  float(5.) ) ;
152 
153  registerProcessorParameter("CosConeSmall",
154  "cosine of the smaller cone" ,
155  _cosConeSmall ,
156  float(0.98) ) ;
157 
158  registerProcessorParameter("CosConeLarge",
159  "cosine of the larger cone" ,
160  _cosConeLarge ,
161  float(0.95) ) ;
162 
163  registerProcessorParameter("UseYokeForMuonID",
164  "use yoke for muon ID" ,
166  bool(true) ) ;
167 
168  registerProcessorParameter("UseIP",
169  "use impact parameters" ,
170  _use_ip ,
171  bool(true) );
172 }
173 
175 
176  streamlog_out(DEBUG) << "IsolatedLeptonTagging init called "
177  << std::endl ;
178 
179 
180  // usually a good idea to
181  printParameters() ;
182 
183 
184  for (Int_t i=0;i<2;i++) {
185  TMVA::Reader *reader = new TMVA::Reader( "Color:Silent" );
186  // add input variables
187  if (i == 0) { // electron
188  reader->AddVariable( "coneec", &_coneec ); // neutral energy in the smaller cone
189  reader->AddVariable( "coneen", &_coneen ); // charged energy in the smaller cone
190  reader->AddVariable( "momentum", &_momentum ); // momentum
191  reader->AddVariable( "coslarcon", &_coslarcon ); // angle between lep and large cone momentum
192  reader->AddVariable( "energyratio", &_energyratio ); // energy ration of lep and large cone
193  reader->AddVariable( "ratioecal", &_ratioecal ); // ratio of energy in ecal over energy in ecal+hcal
194  reader->AddVariable( "ratiototcal", &_ratiototcal ); // ratio of energy in ecal+hcal over momentum
195  if (_use_ip) {
196  reader->AddVariable( "nsigd0", &_nsigd0 ); // significance of d0
197  reader->AddVariable( "nsigz0", &_nsigz0 ); // significance of z0
198  }
199  }
200  else { // muon
201  reader->AddVariable( "coneec", &_coneec );
202  reader->AddVariable( "coneen", &_coneen );
203  reader->AddVariable( "momentum", &_momentum );
204  reader->AddVariable( "coslarcon", &_coslarcon );
205  reader->AddVariable( "energyratio", &_energyratio );
206  if (_use_yoke_for_muon) reader->AddVariable( "yokeenergy", &_yokeenergy ); // energy in yoke
207  if (_use_ip) {
208  reader->AddVariable( "nsigd0", &_nsigd0 );
209  reader->AddVariable( "nsigz0", &_nsigz0 );
210  }
211  reader->AddVariable( "totalcalenergy", &_totalcalenergy );
212  }
213 
214  // book the reader (method, weights)
215  TString dir = _isolated_electron_weights;
216  if (i == 1) dir = _isolated_muon_weights;
217  TString prefix = "TMVAClassification";
218  TString methodName = "MLP method";
219  TString weightfile = dir + "/" + prefix + "_" + "MLP.weights.xml";
220  reader->BookMVA( methodName, weightfile );
221  _readers.push_back(reader);
222  }
223 
224 }
225 
227 }
228 
230 
231  streamlog_out(DEBUG) << "Hello, Isolated Lepton Tagging!" << endl;
232 
233  // Fill empty collections in case of problems
234  // unique_ptr to make sure cleanup happens even in case of problems
235  auto pPFOsWithoutIsoLepCollection = std::make_unique<LCCollectionVec>(LCIO::RECONSTRUCTEDPARTICLE);
236  auto pIsoLepCollection = std::make_unique<LCCollectionVec>(LCIO::RECONSTRUCTEDPARTICLE);
237  pPFOsWithoutIsoLepCollection->setSubset(true);
238  pIsoLepCollection->setSubset(true);
239 
240 
241  // -- get PFO collection --
242  LCCollection *colPFO = evt->getCollection(_colPFOs);
243  // Not catching here, since a missing PFO collection is definitely a problem
244 
245  // get Primary Vertex collection --
246  // primary vertex from VertexFinder (LCFIPlus)
247  LCCollection *colPVtx = evt->getCollection(_colPVtx);
248  if (colPVtx->getNumberOfElements() == 0) {
249  streamlog_out(DEBUG5) << "Vertex collection (" << _colPVtx << ") is empty!" << std::endl;
250  // Fill all elements from the input PFOs to the output PFOs. Since without
251  // PV the isolated lepton tagging cannot be done, there will also be no
252  // isolated leptons to be removed from this collection
253  auto collIter = lcio::LCIterator<lcio::ReconstructedParticle>(colPFO);
254  while (auto* obj = collIter.next()) {
255  pPFOsWithoutIsoLepCollection->addElement(obj);
256  }
257  addOutputColls(evt, pPFOsWithoutIsoLepCollection.release(), pIsoLepCollection.release());
258  return;
259  }
260 
261  Vertex *pvtx = dynamic_cast<Vertex*>(colPVtx->getElementAt(0));
262  Double_t z_pvtx = pvtx->getPosition()[2];
263 
264  Int_t nPFOs = colPFO->getNumberOfElements();
265  std::vector<lcio::ReconstructedParticle*> newPFOs;
266  std::vector<lcio::ReconstructedParticle*> isoLeptons;
267  FloatVec isoLepTagging;
268  IntVec isoLepType;
269 
270  // loop all the PFOs
271  float _mva_lep_max = -1.;
272  int _lep_type = 0;
273  for (Int_t i=0;i<nPFOs;i++) {
274  ReconstructedParticle *recPart = dynamic_cast<ReconstructedParticle*>(colPFO->getElementAt(i));
275  Double_t energy = recPart->getEnergy();
276  Double_t charge = recPart->getCharge();
277  // get track impact parameters
278  TrackVec tckvec = recPart->getTracks();
279  Int_t ntracks = tckvec.size();
280  Double_t d0=0.,z0=0.,deltad0=0.,deltaz0=0.,nsigd0=0.,nsigz0=0.;
281  if (ntracks > 0) {
282  d0 = tckvec[0]->getD0();
283  z0 = tckvec[0]->getZ0();
284  z0 -= z_pvtx; // substract z of primary vertex
285  deltad0 = TMath::Sqrt(tckvec[0]->getCovMatrix()[0]);
286  deltaz0 = TMath::Sqrt(tckvec[0]->getCovMatrix()[9]);
287  nsigd0 = d0/deltad0;
288  nsigz0 = z0/deltaz0;
289  }
290  // here in principle can add any precut on each PFO
291  newPFOs.push_back(recPart);
292  // get energies deposited in each subdetector
293  Double_t ecalEnergy = 0;
294  Double_t hcalEnergy = 0;
295  Double_t yokeEnergy = 0;
296  Double_t totalCalEnergy = 0;
297  std::vector<lcio::Cluster*> clusters = recPart->getClusters();
298  for (std::vector<lcio::Cluster*>::const_iterator iCluster=clusters.begin();iCluster!=clusters.end();++iCluster) {
299  ecalEnergy += (*iCluster)->getSubdetectorEnergies()[0];
300  hcalEnergy += (*iCluster)->getSubdetectorEnergies()[1];
301  yokeEnergy += (*iCluster)->getSubdetectorEnergies()[2];
302  ecalEnergy += (*iCluster)->getSubdetectorEnergies()[3];
303  hcalEnergy += (*iCluster)->getSubdetectorEnergies()[4];
304  }
305  totalCalEnergy = ecalEnergy + hcalEnergy;
306  TVector3 momentum = TVector3(recPart->getMomentum());
307  Double_t momentumMagnitude = momentum.Mag();
308  // get cone information
309  // double cone based isolation algorithm
310  Bool_t woFSR = kTRUE; // by default bremsstrahlung and FSR are not included in cone energy
311  Double_t coneEnergy0[3] = {0.,0.,0.}; // {total, neutral, charged} cone energy
312  Double_t pFSR[4] = {0.,0.,0.,0.}; // 4-momentum of BS/FSR if any found, not being used by MVA
313  Double_t pLargeCone[4] = {0.,0.,0.,0.}; // 4-momentum of all particles inside the larger cone
314  Int_t nConePhoton = 0; // number of BS/FSR photons found, not being used by MVA
315  getConeEnergy(recPart,colPFO,_cosConeSmall,woFSR,coneEnergy0,pFSR,_cosConeLarge,pLargeCone,nConePhoton);
316  Double_t coneEN = coneEnergy0[1];
317  Double_t coneEC = coneEnergy0[2];
318  TLorentzVector lortzLargeCone = TLorentzVector(pLargeCone[0],pLargeCone[1],pLargeCone[2],pLargeCone[3]);
319  TVector3 momentumLargeCone = lortzLargeCone.Vect();
320  Double_t cosThetaWithLargeCone = 1.;
321  if (momentumLargeCone.Mag() > 0.0000001) {
322  cosThetaWithLargeCone = momentum.Dot(momentumLargeCone)/momentumMagnitude/momentumLargeCone.Mag();
323  }
324  Double_t energyRatioWithLargeCone = energy/(energy+lortzLargeCone.E());
325  Double_t ratioECal = 0., ratioTotalCal = 0.;
326  if (ecalEnergy > 0.) ratioECal = ecalEnergy/totalCalEnergy;
327  ratioTotalCal = totalCalEnergy/momentumMagnitude;
328  // all the input variables to MVA are ready
329  // evaluate the neural-net output of isolated-lepton classfication
330  Double_t mva_electron = -1.,mva_muon = -1.;
331  _coneec = coneEC;
332  _coneen = coneEN;
333  _momentum = momentumMagnitude;
334  _coslarcon = cosThetaWithLargeCone;
335  _energyratio = energyRatioWithLargeCone;
336  _ratioecal = ratioECal;
337  _ratiototcal = ratioTotalCal;
338  _nsigd0 = nsigd0;
339  _nsigz0 = nsigz0;
340  _yokeenergy = yokeEnergy;
341  _totalcalenergy = totalCalEnergy;
342  Double_t fEpsilon = 1.E-10;
343  if (charge != 0 &&
344  totalCalEnergy/momentumMagnitude > _minEOverPForElectron &&
345  totalCalEnergy/momentumMagnitude < _maxEOverPForElectron &&
346  ecalEnergy/(totalCalEnergy + fEpsilon) > _minEecalOverTotEForElectron &&
347  (momentumMagnitude > _minPForElectron)) { // basic electron ID, should be replaced by external general PID
348  if (TMath::Abs(nsigd0) < _maxD0SigForElectron && TMath::Abs(nsigz0) < _maxZ0SigForElectron) { // contraint to primary vertex
349  mva_electron = _readers[0]->EvaluateMVA( "MLP method" );
350  }
351  }
352  if (charge != 0 &&
353  totalCalEnergy/momentumMagnitude < _maxEOverPForMuon &&
354  (momentumMagnitude > _minPForMuon)) { // basic muon ID, should be replaced by external general PID
355  if (TMath::Abs(nsigd0) < _maxD0SigForMuon && TMath::Abs(nsigz0) < _maxZ0SigForMuon) { // contraint to primary vertex
356  if (_use_yoke_for_muon && yokeEnergy > _minEyokeForMuon) {
357  mva_muon = _readers[1]->EvaluateMVA( "MLP method" );
358  }
359  else { // temporarily, provide this option for muon ID without using energy in Yoke; default option for now before problems get fixed
360  mva_muon = _readers[1]->EvaluateMVA( "MLP method" );
361  }
362  }
363  }
364  // use output tagging for isolation requirement
365  // default option to select the lepton with largest tagging
366  if (mva_electron > _mvaCutForElectron) {
367  if (!_is_one_isolep) {
368  isoLeptons.push_back(recPart);
369  isoLepTagging.push_back(mva_electron);
370  _lep_type = 11;
371  isoLepType.push_back(_lep_type);
372  }
373  else {
374  if (mva_electron > _mva_lep_max) {
375  _lep_type = 11;
376  _mva_lep_max = mva_electron;
377  isoLeptons.clear();
378  isoLeptons.push_back(recPart);
379  }
380  }
381  }
382  if (mva_muon > _mvaCutForMuon) {
383  if (!_is_one_isolep) {
384  isoLeptons.push_back(recPart);
385  isoLepTagging.push_back(mva_muon);
386  _lep_type = 13;
387  isoLepType.push_back(_lep_type);
388  }
389  else {
390  if (mva_muon > _mva_lep_max) {
391  _lep_type = 13;
392  _mva_lep_max = mva_muon;
393  isoLeptons.clear();
394  isoLeptons.push_back(recPart);
395  }
396  }
397  }
398  }
399 
400 
401  // save the selected lepton to a new collection
402  for (auto* obj : isoLeptons) {
403  pIsoLepCollection->addElement(obj);
404  }
405 
406  // save other PFOs to a new collection
407  for (auto* obj : newPFOs) {
408  // Only add the ones that are not isolated leptons
409  if (std::find(isoLeptons.cbegin(), isoLeptons.cend(), obj) == isoLeptons.cend()) {
410  pPFOsWithoutIsoLepCollection->addElement(obj);
411  }
412  }
413 
414  // set the isolated lepton tagging as the collection parameter
415  if (_is_one_isolep) {
416  // save the largest one
417  pIsoLepCollection->parameters().setValue( "ISOLepTagging", _mva_lep_max );
418  pIsoLepCollection->parameters().setValue( "ISOLepType", _lep_type );
419  }
420  else {
421  // save a vector of tagging
422  pIsoLepCollection->parameters().setValues( "ISOLepTagging", isoLepTagging );
423  pIsoLepCollection->parameters().setValues( "ISOLepType", isoLepType );
424 
425  }
426  // add new collections (hand over ownership to LCEvent)
427  addOutputColls(evt, pPFOsWithoutIsoLepCollection.release(), pIsoLepCollection.release());
428 }
429 
430 
431 
432 void IsolatedLeptonTaggingProcessor::check( LCEvent * /*evt*/ ) {
433 }
434 
435 
437 
438  for (std::vector<TMVA::Reader*>::const_iterator ireader=_readers.begin();ireader!=_readers.end();++ireader) {
439  delete *ireader;
440  }
441 
442 }
443 
444 void IsolatedLeptonTaggingProcessor::addOutputColls(LCEvent* evt, LCCollection* pfosWithoutIsoLepColl, LCCollection* isoLepColl) {
445  evt->addCollection(pfosWithoutIsoLepColl, _colNewPFOs);
446  evt->addCollection(isoLepColl, _colLeptons);
447 }
virtual void end()
Called after data processing for clean up.
virtual void init()
Called at the begin of the job before anything is read.
IsolatedLeptonTaggingProcessor aIsolatedLeptonTaggingProcessor
Double_t getConeEnergy(ReconstructedParticle *recPart, LCCollection *colPFO, Double_t cosCone)
Definition: Utilities.cc:361
virtual void processEvent(LCEvent *evt)
Called for every event - the working horse.
virtual void processRunHeader(LCRunHeader *run)
Called for every run.
processor for isolated lepton tagging.
virtual void addOutputColls(LCEvent *evt, LCCollection *pfosWithoutIsoLepColl, LCCollection *isoLepColl)
Add the expected output collections.
std::vector< TMVA::Reader * > _readers
std::string _colPFOs
Input collection name.