ATLAS Offline Software
ElectronSelector.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 //==================================================================================
5 //
6 // ElectronSelector.cxx : Class designed to reconstruct di-electrons events
7 // in particular Z0 -> e+ e- events.
8 //==================================================================================
9 
10 //==================================================================================
11 // Include files...
12 //==================================================================================
13 
14 // This files header
16 // Package Headers
18 #include <sstream>
19 // ATLAS headers
21 #include "StoreGate/StoreGateSvc.h"
22 #include "CLHEP/Random/RandFlat.h"
23 
24 // Static declarations
25 std::atomic<unsigned int> ElectronSelector::s_uNumInstances;
26 
27 //==================================================================================
28 // Public Methods
29 //==================================================================================
31  m_doDebug ( false ),
32  m_ptCut ( 10. ),
33  m_etaCut ( 2.47 ) // 2.47 is the official acceptance for central electrons. Forward electrons is another story...
34 {
36 
37  std::stringstream xTmp; xTmp << s_uNumInstances;
38  m_xSampleName = "ElectronSelector_" + xTmp.str();
39 
40  m_pxElectron = nullptr;
41 
42  m_msgStream = new MsgStream(Athena::getMessageSvc(), "InDetPerformanceMonitoring" );
43 }
44 
47 {
49  delete m_msgStream;
50 }
51 
54 {
55  (*m_msgStream) << MSG::DEBUG << " -- ElectronSelector::Init -- START -- " << endmsg;
56 
57  // PARENT::Init();
58 
59  //---Electron Likelihood tool---
60  // m_doIDCuts = true;
61  (*m_msgStream) << MSG::INFO << "ElectronSelector::Init -- Setting up electron LH tool." << endmsg;
62  m_LHTool2015 = new AsgElectronLikelihoodTool ("m_LHTool2015");
63 
64  const std::string elecWorkingPoint = "LooseLHElectron"; // "MediumLHElectron" "TightLHElectron"
65 
66  if((m_LHTool2015->setProperty("WorkingPoint",elecWorkingPoint.c_str())).isFailure()) {
67  (*m_msgStream) << MSG::WARNING << "Failure loading ConfigFile for electron likelihood tool with working point: " << elecWorkingPoint.c_str() << endmsg;
68  }
69  else {
70  (*m_msgStream) << MSG::INFO << "Loading ConfigFile for electron likelihood tool with working point: " << elecWorkingPoint << ". SUCCESS " << endmsg;
71  }
72 
73  // check config files at: https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/EGammaIdentificationRun2
74  std::string confDir = "ElectronPhotonSelectorTools/offline/mc20_20210514/ElectronLikelihoodVeryLooseOfflineConfig2017_Smooth.conf";
75  if ( (m_LHTool2015->setProperty("ConfigFile", confDir)).isSuccess()) {
76  (*m_msgStream) << MSG::INFO << "Electron likelihood config ("<< confDir.c_str() << ") setting SUCCESS!" << endmsg;
77  }
78  else {
79  (*m_msgStream) << MSG::WARNING << "Electron likelihood config ("<< confDir.c_str() << ") setting FAILURE" << endmsg;
80  }
81 
82  if (m_LHTool2015->initialize().isSuccess()) {
83  (*m_msgStream) << MSG::INFO << "Electron likelihood tool initialize() SUCCESS!" << endmsg;
84  }
85  else {
86  (*m_msgStream) << MSG::WARNING << "Electron likelihood tool initialize() FAILURE!" << endmsg;
87  }
88 
89  (*m_msgStream) << MSG::DEBUG << " --ElectronSelector::Init -- COMPLETED -- " << endmsg;
90  return;
91 }
92 
95 {
96  (*m_msgStream) << MSG::DEBUG << " --ElectronSelector::PrepareElectronList -- START -- " << endmsg;
97  Clear(); // clear current list records
98 
99  using electron_iterator = xAOD::ElectronContainer::const_iterator;
100  electron_iterator iter = pxElecContainer->begin();
101  electron_iterator iterEnd = pxElecContainer->end();
102 
103  // Loop over the Electrons
104  int electroncount = 0;
105  for(; iter != iterEnd ; ++iter) {
106  electroncount++;
107  (*m_msgStream) << MSG::DEBUG << " -- ElectronSelector::PrepareElectronList -- candiate electron " << electroncount
108  << " has author " << (*iter)->author(xAOD::EgammaParameters::AuthorElectron)
109  << endmsg;
110  const xAOD::Electron * ELE = (*iter);
111  if ( RecordElectron(ELE) ) {
112  (*m_msgStream) << MSG::DEBUG << " -- ElectronSelector::PrepareElectronList -- candiate electron " << electroncount
113  << " is good "
114  << endmsg;
115  }
116  }
117  bool progressingwell = true;
118 
119  (*m_msgStream) << MSG::DEBUG << " -- ElectronSelector::PrepareElectronList -- finished recording electrons. "
120  << " recorded electrons: " << m_pxElTrackList.size()
121  << " out of tested electron candidates:" << electroncount << endmsg;
122  if (m_pxElTrackList.size() < 2) progressingwell = false;
123  if (progressingwell) progressingwell = OrderElectronList ();
124  if (progressingwell) progressingwell = RetrieveVertices ();
125 
126  if (!progressingwell) {
127  (*m_msgStream) << MSG::DEBUG << " -- ElectronSelector::PrepareElectronList -- FAILED -- this event has not even a good e+e- pair " << endmsg;
128  this->Clear(); // reset the content as it is not going to be used
129  }
130 
131  (*m_msgStream) << MSG::DEBUG << " -- ElectronSelector::PrepareElectronList -- COMPLETED -- electroncount -- m_pxElTrackList.size() / all = "
132  << m_pxElTrackList.size() << " / " << electroncount
133  << endmsg;
134  return;
135 }
136 
139 {
140  // start assuming electron candidate is good
141  bool electronisgood = true;
142 
143  // check the electron satisfies the working point
144  if (!m_LHTool2015->accept(thisElec) ) {
145  electronisgood = false;
146  (*m_msgStream) << MSG::DEBUG << " -- electron fails workingpoint selection -- " << endmsg;
147  }
148 
149  //Get the track particle
150  const xAOD::TrackParticle* theTrackParticle = thisElec->trackParticle();
151 
152  if (!theTrackParticle) {
153  electronisgood = false;
154  (*m_msgStream) << MSG::DEBUG << " -- electron fails trackparticle -- " << endmsg;
155  }
156 
157  if (electronisgood && thisElec->author(xAOD::EgammaParameters::AuthorElectron) != 1) {
158  electronisgood = false;
159  (*m_msgStream) << MSG::DEBUG << " -- electron fails author -- " << thisElec->author(xAOD::EgammaParameters::AuthorElectron) << endmsg;
160  }
161 
162  if (electronisgood && theTrackParticle->pt() * m_CGeV < m_ptCut ) { // pt cut given in GeV
163  electronisgood = false;
164  (*m_msgStream) << MSG::DEBUG << " -- electron fails pt cut -- pt= " << theTrackParticle->pt()
165  << " < " << m_ptCut << " (cut value) "
166  << endmsg;
167  }
168 
169  const xAOD::CaloCluster* cluster = thisElec->caloCluster();
170  if(!cluster) {
171  electronisgood = false;
172  (*m_msgStream) << MSG::DEBUG << " -- electron candidate has no CaloCluster " << endmsg;
173  }
174 
175  if (electronisgood && (cluster->e() * sin(theTrackParticle->theta())) * m_CGeV < m_ptCut) { // cut on et of the cluster
176  electronisgood = false;
177  (*m_msgStream) << MSG::DEBUG << " -- electron fails cluster Et cut -- Et= " << (cluster->e() * cos(theTrackParticle->theta()))* m_CGeV
178  << " < " << m_ptCut << " (cut value) "
179  << endmsg;
180  }
181 
182  if (electronisgood && (std::abs(cluster->eta())> m_etaCut || std::abs(theTrackParticle->eta())> m_etaCut) ) { // cut in eta for the cluster and the track
183  electronisgood = false;
184  (*m_msgStream) << MSG::DEBUG << " -- electron fails eta cut -- cluster_eta= " << cluster->eta() << endmsg;
185  }
186 
187  if (electronisgood) {
188  // store this electron
189  m_pxElTrackList.push_back(theTrackParticle);
190 
191  (*m_msgStream) << MSG::DEBUG << " * RecordElectron * good electron found -> store this electron with pt " << theTrackParticle->pt()
192  << " --> current m_pxElTrackList.size(): " << m_pxElTrackList.size()
193  << std::endl;
194  }
195 
196  return electronisgood;
197 }
198 
201 {
202  m_pxElTrackList.clear();
205 
206  // -1 means not assigned
207  m_elecneg1 = -1;
208  m_elecneg2 = -1;
209  m_elecpos1 = -1;
210  m_elecpos2 = -1;
211 
212  return;
213 }
214 
217 {
218  (*m_msgStream) << MSG::DEBUG << " -- ElectronSelector::OrderElectronList -- START -- list size: " << m_pxElTrackList.size( ) << endmsg;
219 
220  bool goodlist = true;
221 
222  if (m_pxElTrackList.size() >= 2) { // we need at least 2 electrons
223  double ptMinus1 = 0.;
224  double ptMinus2 = 0.;
225  double ptPlus1 = 0.;
226  double ptPlus2 = 0.;
227 
228  int elecnegcount = 0;
229  int elecposcount = 0;
230 
231  for (int ielec=0; ielec < (int) m_pxElTrackList.size(); ielec++) {
232  // negative electrons
233  if (m_pxElTrackList.at(ielec)->charge()== -1) { // positive electron
234  elecnegcount++;
235  if (m_pxElTrackList.at(ielec)->pt()> ptMinus1) {
236  // store 1st in 2nd
237  ptMinus2 = ptMinus1;
239  // now store the new one in 1st place
240  ptMinus1 = m_pxElTrackList.at(ielec)->pt();
241  m_elecneg1 = ielec;
242  }
243  else if (m_pxElTrackList.at(ielec)->pt()> ptMinus2) {
244  // store the new one in 2nd place
245  ptMinus2 = m_pxElTrackList.at(ielec)->pt();
246  m_elecneg2 = ielec;
247  }
248  }
249  // positive electrons
250  if (m_pxElTrackList.at(ielec)->charge()== 1) { // positive electron
251  elecposcount++;
252  if (m_pxElTrackList.at(ielec)->pt()> ptPlus1) {
253  // store 1st in 2nd
254  ptPlus2 = ptPlus1;
256  // now store the new one in 1st place
257  ptPlus1 = m_pxElTrackList.at(ielec)->pt();
258  m_elecpos1 = ielec;
259  }
260  else if (m_pxElTrackList.at(ielec)->pt()> ptPlus2) {
261  // store the new one in 2nd place
262  ptPlus2 = m_pxElTrackList.at(ielec)->pt();
263  m_elecpos2 = ielec;
264  }
265  }
266  }
267 
268  if (elecposcount == 0 || elecnegcount == 0) {
269  // We need at least one e- and one e+
270  if (m_doDebug) std::cout << " -- ElectronSelector::OrderElectronList -- No opposite charge electrons --> DISCARD ALL ELECTRONS -- " << std::endl;
271  elecposcount = 0;
272  elecnegcount = 0;
273  this->Clear();
274  goodlist = false;
275  }
276 
277  if (m_doDebug && elecposcount + elecnegcount >= 2 ){
278  std::cout << " -- ElectronSelector::OrderElectronList -- electron summary list taking " << elecposcount + elecnegcount
279  << " electrons from the input list of " << m_pxElTrackList.size() << " electrons: " << std::endl;
280  if (m_elecneg1 >= 0) std::cout << " leading e-: " << m_elecneg1 << " Pt = " << ptMinus1 << std::endl;
281  if (m_elecneg2 >= 0) std::cout << " second e-: " << m_elecneg2 << " Pt = " << ptMinus2 << std::endl;
282  if (m_elecpos1 >= 0) std::cout << " leading e+: " << m_elecpos1 << " Pt = " << ptPlus1 << std::endl;
283  if (m_elecpos2 >= 0) std::cout << " second e+: " << m_elecpos2 << " Pt = " << ptPlus2 << std::endl;
284  }
285 
286  if (elecposcount + elecnegcount >= 2){ // fill the final list of electrons
291  }
292  }
293 
294  (*m_msgStream) << MSG::DEBUG << " -- ElectronSelector::OrderElectronList -- COMPLETED -- status: "<< goodlist << std::endl;
295  return goodlist;
296 }
297 
300 {
301  if (m_doDebug) std::cout << " -- ElectronSelector::RetrieveVertices -- START -- list size: "
303  << std::endl;
304  bool goodvertices = false;
305  int nverticesfound = 1; // WARNING default must be 0 --> set to 1 for R22 --> needs to be fixed
306 
307  if (m_goodElecNegTrackParticleList.size() >= 1 && m_goodElecPosTrackParticleList.size() >= 1) { // we need at least 1 e- and 1 e+
308  // then, check the distances between the e- and e+ vertices, and make sure at least 1 pair comes from same vertex
309  for (size_t ielec = 0; ielec < m_goodElecNegTrackParticleList.size(); ielec++) {
310  // loop on e-
311  // R21 -> R22 SALVA // TrkParticles have no vertex in R22 --> THIS NEEDS A FIX
312  /*
313  if (m_goodElecNegTrackParticleList.at(ielec)->vertex()) {
314  if (m_doDebug) std::cout << " e-(" << ielec <<")->vertex()->v= (" << m_goodElecNegTrackParticleList.at(ielec)->vertex()->x()
315  << ", " << m_goodElecNegTrackParticleList.at(ielec)->vertex()->y()
316  << ", " << m_goodElecNegTrackParticleList.at(ielec)->vertex()->z()
317  << ") " << std::endl;
318 
319  // for (unsigned int iposi = 0; iposi < m_goodElecPosTrackParticleList.size(); iposi++) {
320  for (size_t iposi = 0; iposi < m_goodElecPosTrackParticleList.size(); iposi++) {
321  if (m_goodElecPosTrackParticleList.at(iposi)->vertex()) {
322  if (m_doDebug) std::cout << " e+(" << iposi <<")->vertex()->v= (" << m_goodElecPosTrackParticleList.at(iposi)->vertex()->x()
323  << ", " << m_goodElecPosTrackParticleList.at(iposi)->vertex()->y()
324  << ", " << m_goodElecPosTrackParticleList.at(iposi)->vertex()->z()
325  << ") " << std::endl;
326  float delta_x = std::abs( m_goodElecNegTrackParticleList.at(ielec)->vertex()->x()-m_goodElecPosTrackParticleList.at(iposi)->vertex()->x() );
327  float delta_y = std::abs( m_goodElecNegTrackParticleList.at(ielec)->vertex()->y()-m_goodElecPosTrackParticleList.at(iposi)->vertex()->y() );
328  float delta_z = std::abs( m_goodElecNegTrackParticleList.at(ielec)->vertex()->z()-m_goodElecPosTrackParticleList.at(iposi)->vertex()->z() );
329 
330  if (delta_x < m_deltaXYcut && delta_y < m_deltaXYcut && delta_z < m_deltaZcut) {
331  nverticesfound++;
332  if (m_doDebug) std::cout << " ELEC-BINGO !!! e+e- pair in same vertex !!! e-[" << ielec
333  << "] e+[" << iposi<< "] count: " << nverticesfound << std::endl;
334  } // vertex is the same
335  } // positron has vertex
336  } // loop on positrons
337  } // electron has vertex
338  */
339  } // loop on electrons (e-)
340  } // at least one e+e- pair
341 
342  if (nverticesfound >= 1) goodvertices = true;
343 
344  if (m_doDebug) std::cout << " -- ElectronSelector::RetrieveVertices -- COMPLETED -- status: " << goodvertices << std::endl;
345  return goodvertices;
346 }
347 
350 {
351  if (i >= m_goodElecNegTrackParticleList.size()) { // requesting out of range electron
352  return nullptr;
353  }
355 }
356 
359 {
360  if (i >= m_goodElecPosTrackParticleList.size()) { // requesting out of range electron
361  return nullptr;
362  }
364 }
ElectronSelector::m_etaCut
float m_etaCut
Definition: ElectronSelector.h:76
ElectronSelector::m_pxElTrackList
std::vector< const xAOD::TrackParticle * > m_pxElTrackList
Definition: ElectronSelector.h:68
ElectronSelector::GetElecNegTrackParticle
const xAOD::TrackParticle * GetElecNegTrackParticle(size_t i)
Definition: ElectronSelector.cxx:349
xAOD::TrackParticle_v1::pt
virtual double pt() const override final
The transverse momentum ( ) of the particle.
Definition: TrackParticle_v1.cxx:73
ElectronSelector::m_goodElecPosTrackParticleList
std::vector< const xAOD::TrackParticle * > m_goodElecPosTrackParticleList
Definition: ElectronSelector.h:70
getMessageSvc.h
singleton-like access to IMessageSvc via open function and helper
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
DataVector::const_iterator
DataModel_detail::const_iterator< DataVector > const_iterator
Standard const_iterator.
Definition: DataVector.h:837
ElectronSelector::GetElecPosTrackParticle
const xAOD::TrackParticle * GetElecPosTrackParticle(size_t i)
Definition: ElectronSelector.cxx:358
ElectronSelector::m_doDebug
bool m_doDebug
Definition: ElectronSelector.h:73
xAOD::TrackParticle_v1::eta
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
Definition: TrackParticle_v1.cxx:77
ElectronSelector::s_uNumInstances
static std::atomic< unsigned int > s_uNumInstances
Definition: ElectronSelector.h:56
xAOD::Egamma_v1::author
uint16_t author(uint16_t bitmask=EgammaParameters::AuthorALL) const
Get author.
Definition: Egamma_v1.cxx:166
AsgElectronLikelihoodTool::accept
virtual asg::AcceptData accept(const xAOD::IParticle *part) const override final
The main accept method: using the generic interface.
Definition: AsgElectronLikelihoodTool.cxx:868
xAOD::Electron_v1::trackParticle
const xAOD::TrackParticle * trackParticle(size_t index=0) const
Pointer to the xAOD::TrackParticle/s that match the electron candidate.
Definition: Electron_v1.cxx:55
ElectronSelector::OrderElectronList
bool OrderElectronList()
Definition: ElectronSelector.cxx:216
drawFromPickle.cos
cos
Definition: drawFromPickle.py:36
PerfMonServices.h
AsgElectronLikelihoodTool
Electron selector tool to select objects in Athena using an underlying pure ROOT tool.
Definition: AsgElectronLikelihoodTool.h:30
Athena::getMessageSvc
IMessageSvc * getMessageSvc(bool quiet=false)
Definition: getMessageSvc.cxx:20
ElectronSelector::m_elecpos2
int m_elecpos2
Definition: ElectronSelector.h:85
ElectronSelector::m_msgStream
MsgStream * m_msgStream
Definition: ElectronSelector.h:64
ElectronSelector::m_goodElecNegTrackParticleList
std::vector< const xAOD::TrackParticle * > m_goodElecNegTrackParticleList
Definition: ElectronSelector.h:69
xAOD::CaloCluster_v1
Description of a calorimeter cluster.
Definition: CaloCluster_v1.h:59
xAOD::CaloCluster_v1::eta
virtual double eta() const
The pseudorapidity ( ) of the particle.
Definition: CaloCluster_v1.cxx:251
lumiFormat.i
int i
Definition: lumiFormat.py:85
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
ElectronSelector::RecordElectron
bool RecordElectron(const xAOD::Electron *)
Definition: ElectronSelector.cxx:138
ElectronSelector::PrepareElectronList
void PrepareElectronList(const xAOD::ElectronContainer *pxElecContainer)
Definition: ElectronSelector.cxx:94
ElectronSelector::m_pxElectron
const xAOD::Muon * m_pxElectron
Definition: ElectronSelector.h:67
ElectronSelector::ElectronSelector
ElectronSelector()
Definition: ElectronSelector.cxx:30
xAOD::Egamma_v1::caloCluster
const xAOD::CaloCluster * caloCluster(size_t index=0) const
Pointer to the xAOD::CaloCluster/s that define the electron candidate.
Definition: Egamma_v1.cxx:388
DataVector
Derived DataVector<T>.
Definition: DataVector.h:794
ElectronSelector::m_LHTool2015
AsgElectronLikelihoodTool * m_LHTool2015
Definition: ElectronSelector.h:79
xAOD::Electron_v1
Definition: Electron_v1.h:34
DataVector::end
const_iterator end() const noexcept
Return a const_iterator pointing past the end of the collection.
ElectronSelector::m_CGeV
const float m_CGeV
Definition: ElectronSelector.h:88
ElectronSelector::RetrieveVertices
bool RetrieveVertices()
Definition: ElectronSelector.cxx:299
ElectronSelector.h
DEBUG
#define DEBUG
Definition: page_access.h:11
ElectronSelector::Clear
void Clear()
Definition: ElectronSelector.cxx:200
ElectronSelector::m_elecneg1
int m_elecneg1
Definition: ElectronSelector.h:82
AsgElectronLikelihoodTool::initialize
virtual StatusCode initialize() override
Gaudi Service Interface method implementations.
Definition: AsgElectronLikelihoodTool.cxx:80
xAOD::TrackParticle_v1
Class describing a TrackParticle.
Definition: TrackParticle_v1.h:43
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
ElectronSelector::m_ptCut
float m_ptCut
Definition: ElectronSelector.h:75
ElectronSelector::~ElectronSelector
~ElectronSelector()
Definition: ElectronSelector.cxx:46
EventAnalysis::m_xSampleName
std::string m_xSampleName
Definition: EventAnalysis.h:80
ElectronSelector::Init
void Init()
Definition: ElectronSelector.cxx:53
ElectronSelector::m_elecpos1
int m_elecpos1
Definition: ElectronSelector.h:84
xAOD::TrackParticle_v1::theta
float theta() const
Returns the parameter, which has range 0 to .
StoreGateSvc.h
xAOD::CaloCluster_v1::e
virtual double e() const
The total energy of the particle.
Definition: CaloCluster_v1.cxx:265
DataVector::begin
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
xAOD::EgammaParameters::AuthorElectron
const uint16_t AuthorElectron
Object Reconstructed by standard cluster-based algorithm.
Definition: EgammaDefs.h:24
ElectronSelector::m_elecneg2
int m_elecneg2
Definition: ElectronSelector.h:83