ATLAS Offline Software
EGammaAmbiguityTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
13 
15 #include "xAODTracking/Vertex.h"
17 
18 #include "xAODEgamma/Egamma.h"
19 #include "xAODEgamma/Electron.h"
20 #include "xAODEgamma/Photon.h"
24 
25 #include "xAODEgamma/EgammaDefs.h"
28 
29 #define CHECK_HITS(EXP) \
30  if (!(EXP)) { \
31  ATH_MSG_WARNING("Failed \"" << #EXP << "\""); \
32  return false; \
33  }
34 
35 //=============================================================================
36 // Standard constructor
37 //=============================================================================
38 EGammaAmbiguityTool::EGammaAmbiguityTool(const std::string& myname)
39  : asg::AsgTool(myname)
40 {
42  "minNoSiHits",
43  m_MinNoSiHits = 4,
44  "Minimum number of silicon hits to be an electron==>not photon for sure");
46  "minNoPixHits",
47  m_MinNoPixHits = 2,
48  "Minimum number of Pixel hits to be an electron==>not photon for sure");
49  declareProperty("maxEoverPCut",
50  m_maxEoverPCut = 10,
51  "Maximum EoverP , more that this is ambiguous");
53  "minPCut", m_minPtCut = 2000, "Minimum Pt, less than that is ambiguous");
54  declareProperty("maxDeltaR_innermost",
56  "Maximum value for Rconv - RfirstHit for Si+Si conversions "
57  "where both tracks have innermost hits");
58  declareProperty("noVertexNoInnermostAsAmb",
60  "If true classify as ambiguous when there is no vertex and "
61  "no innermost Hits. "
62  "If false classify no vertex as for sure not photon");
63  declareProperty("AcceptAmbiguous",
64  m_acceptAmbiguous = true,
65  "When used as a selector accept the ambiguous as default");
66 }
67 
69  ATH_MSG_DEBUG("Initializing " << name() << "...");
70  return StatusCode::SUCCESS;
71 }
72 
73 // ====================================================================
74 // return value: AuthorElectron, AuthorPhoton, AuthorAmbiguous, AuthorUnknown
76  const xAOD::Vertex* vx,
77  const xAOD::TrackParticle* tp,
79 
81  // Result should stay the same before after calibration corrections
82  double cluster_e = (cluster->clusterSize() != xAOD::CaloCluster::SW_35ele &&
85  ? cluster->altE()
86  : cluster->e();
87 
88  //Number of hits from the track
89  uint8_t trkPixelHits(0);
90  uint8_t trkSiHits(0);
91  if (tp && !tp->summaryValue(trkPixelHits,xAOD::numberOfPixelHits)){
92  ATH_MSG_WARNING("Could not retrieve number of pixel hits from track");
93  }
94  if (tp && !tp->summaryValue(trkSiHits, xAOD::numberOfSCTHits)){
95  ATH_MSG_WARNING("Could not retrieve number of SCT hits from track");
96  }
97  trkSiHits += trkPixelHits;
98 
99  //Check if the vertex is double silicon
101  bool vxDoubleSi = (convType == xAOD::EgammaParameters::doubleSi);
102 
103  // Check if the track particle and the ones associated to the conversion vertex
104  // have innermost pixel hits
105  bool trkHasInnermostHit = tp && hasInnermostPixelHit(*tp);
106  size_t nTrkVxWithInnermostHit{};
107  if (vx and vxDoubleSi) nTrkVxWithInnermostHit = nTrkWithInnermostPixelHits(*vx);
108 
109  //See if the Si+Si conversion shares one track with the electron
110  //if not we might have a trident.
111  //if yes and the track is not good we definitely matched the conversion as electron.
112  bool shareTrack = vx && tp && trkSiHits>=m_MinNoSiHits && vxDoubleSi && isInVertex(*tp, *vx);
113 
114  //Debug messages
115  ATH_MSG_DEBUG("Vertex, SiSi, tracks with innermost pixel hits: "
116  << (vx != nullptr) << ", " << vxDoubleSi << ", " << nTrkVxWithInnermostHit);
117  ATH_MSG_DEBUG("Track, Si hits, pixel hits, has innermost pixel hit: "
118  << (tp != nullptr) << ", " << (int) trkSiHits << ", " << (int) trkPixelHits
119  << " , " << (int) trkHasInnermostHit);
120  ATH_MSG_DEBUG("Share track : " << shareTrack);
121 
122  //The Electron collection will NOT contain Photons
123  //The Photon collection will NOT contain Electrons
124 
125  //So for conversions vs electrons better to go to ambiguous
126  //except if we are sure.
127 
128  //Practically a photon here means definetely not Electron
129  //And vice-versa
130 
131  //Photon ==> Surely not electron
132  // - no track
133  // - or no track with the minimum requirent hits to be an electron
134  // - or Si+Si vertex and
135  // - No pixel
136  // - The electron track is part of the conversion
137  // In this case we do not want this to be in Electrons
138  if (!tp ||
139  trkSiHits<m_MinNoSiHits ||
140  (vxDoubleSi && !trkPixelHits && shareTrack)){
141  ATH_MSG_DEBUG("Returning Photon");
144  }
145 
146  // Ambigous due to E/P, Min Pt, pixel hits
147  // We are not sure it is a Photon, but is not good enough either to be surely
148  // an Electron
149  // - E/P >10 or track Pt < 2.0 GeV or no-pixel then Ambiguous
150  double track_ep = cluster_e * fabs(tp->qOverP());
151 
152  if(tp->pt()<m_minPtCut) {
153  ATH_MSG_DEBUG("Returning Ambiguous due min Pt");
156  }
157 
158  if( track_ep > m_maxEoverPCut) {
159  ATH_MSG_DEBUG("Returning Ambiguous due to E over P");
162  }
163 
164 
165  if(!trkPixelHits) {
166  ATH_MSG_DEBUG("Returning Ambiguous due to no pixels");
169  }
170 
171  // Electron ==> Surely not Photon
172  // - No vertex Matched (and trk has "innermost pixel hits" when
173  // m_noVertexNoInnermostAsAmb is true,
174  // othewise ambiguous)
175  // - Track with at least the minimum Si and Pixel hits (previous selection for
176  // photons/ambiguous)
177  // - And has E/P < 10 and Pt > 2.0 GeV (previous for ambiguous)
178  // - Or if a vertex exists and:
179  // * is not Si+Si
180  // * is Si+Si but only 1 trk has "innermost pixel hits"
181  // * is Si+Si and both tracks have "innermost pixel hits" but
182  // Rconv - RfirstHit > maxDeltaR_innermost
183  // In this case we do not want this to be in Photons
184 
185  if (!vx) {
186  if (trkHasInnermostHit || !m_noVertexNoInnermostAsAmb) {
187  ATH_MSG_DEBUG("Returning Electron");
190  } else {
191  // the true photons falling here are classified as unconverted photons
192  // but it may happen that they are late single-track conversions
193  // very few true electrons are falling here, since there is no innermost
194  // hits
195  ATH_MSG_DEBUG("Returning Ambiguous due to no conv vertex and track with "
196  "no innermost hits");
199  }
200  }
201 
202  // here we have a conv vertex
203  if (trkHasInnermostHit && (!vxDoubleSi || nTrkVxWithInnermostHit == 1 ||
204  !passDeltaR_innermost(*vx))) {
205  ATH_MSG_DEBUG("Returning Electron");
208  }
209 
210  // Ambiguous all else, these will go to both electrons and photons
211  // A matched Si+Si vertex (where either both or none of the tracks have
212  // "innermost pixel hits")
213  // and a track with "innermost pixel hits"
214  // A non Si+Si vertex matched and a track with no "innermost pixel hits"
215 
216  //If we have no double si
217  //or if the single track p matches the cluster E than the vertex p
218  //mark TrackEoverPBetterThanVertexEover.
219  //Otherwise maek as TrackEoverPBetterThanVertexEover
220  //as the double si vertex is a better match to the cluster E.
221  const double track_p = fabs(1.0/tp->qOverP());
222  const double vertex_p=xAOD::EgammaHelpers::momentumAtVertex(*vx).mag() ;
223  type = !vxDoubleSi || (fabs(track_p - cluster_e) < fabs(vertex_p- cluster_e))?
226  //end of types
227 
228  ATH_MSG_DEBUG("Returning Ambiguous");
230 }
231 
233  const xAOD::Vertex* vx,
234  const xAOD::TrackParticle* tp) const{
235 
237  return ambiguityResolve(cluster,
238  vx,
239  tp,
240  type);
241 
242 }
243 
244 
245 
251 
252  //Fwd and Topo seeded not handled
255  ATH_MSG_DEBUG("Author Fwd of Topo seeded. Do not do overlap or ambiguity");
256  return egamma.author();
257  }
258 
259  //No overlap found so either photon or electron
260  if (!egamma.ambiguousObject()){
262  ATH_MSG_DEBUG("No overlaping object found");
263  return egamma.author();
264  }
265 
266  // Overlap found. define the electron and the photon
267  const xAOD::Electron* electron = static_cast<const xAOD::Electron*>(
268  egamma.type() == xAOD::Type::Electron ? &egamma : egamma.ambiguousObject());
269  const xAOD::Photon* photon = static_cast<const xAOD::Photon*>(
270  egamma.type() == xAOD::Type::Photon ? &egamma : egamma.ambiguousObject());
271 
272  //Error if cannot define any of them
273  if (!electron || !photon){
274  ATH_MSG_WARNING("Could not cast to electron and/or photon");
275  return egamma.author();
276  }
277 
278  //pass the proper input to the ambiguity resolve method
280  unsigned int result = ambiguityResolve(electron->caloCluster(),
281  photon->vertex(),
282  electron->trackParticle(),
283  type);
284  ATH_MSG_DEBUG("Performed ambiguity resolution, resulting type is: "<< type);
285  return result;
286 }
287 
290  unsigned int author = ambiguityResolve(egamma);
291 
294  return true;
295  }
296 
298  return true;
299  }
300 
301  return (author == (egamma.type() == xAOD::Type::Electron ?
303 }
304 
310 {
311  uint8_t trkExpectHit(0);
312  uint8_t trkNhits(0);
313  CHECK_HITS( tp.summaryValue(trkNhits,xAOD::numberOfInnermostPixelLayerHits) );
314  if (trkNhits) {return true;}
315 
316  CHECK_HITS( tp.summaryValue(trkExpectHit,xAOD::expectInnermostPixelLayerHit) );
317  if (trkExpectHit) {return false;}
318 
320  if (trkNhits) {return true;}
321 
322  CHECK_HITS( tp.summaryValue(trkExpectHit,xAOD::expectNextToInnermostPixelLayerHit) );
323  if (trkExpectHit) {return false;}
324 
325  CHECK_HITS( tp.summaryValue(trkNhits,xAOD::numberOfPixelHits) );
326  return (trkNhits >= m_MinNoPixHits);
327 }
328 
332  size_t n = 0;
333  for (size_t i = 0; i < vx.nTrackParticles(); ++i){
334  const xAOD::TrackParticle *tp = vx.trackParticle(i);
335  if (!tp) {ATH_MSG_WARNING("Null pointer to track particle in vertex");}
336  else if (hasInnermostPixelHit(*tp)) {++n;}
337  }
338  return n;
339 }
340 
343  for (size_t i = 0; i < vx.nTrackParticles(); ++i){
344  const xAOD::TrackParticle *tp = vx.trackParticle(i);
345  if (!tp) {ATH_MSG_WARNING("Null pointer to track particle in vertex");}
346  if (tp == &trk) {return true;}
347  }
348  return false;
349 }
350 
353 {
354  static const SG::AuxElement::Accessor<float> minRfirstHitAcc("minRfirstHit");
355  if (not minRfirstHitAcc.isAvailable(vx)) {
356  ATH_MSG_WARNING("minRfirstHit not available");
357  return false;
358  }
359  return xAOD::EgammaHelpers::conversionRadius(&vx) - minRfirstHitAcc(vx) < m_maxDeltaR_innermost;
360 }
CHECK_HITS
#define CHECK_HITS(EXP)
Definition: EGammaAmbiguityTool.cxx:29
xAOD::Electron
Electron_v1 Electron
Definition of the current "egamma version".
Definition: Event/xAOD/xAODEgamma/xAODEgamma/Electron.h:17
get_generator_info.result
result
Definition: get_generator_info.py:21
xAOD::Vertex_v1::nTrackParticles
size_t nTrackParticles() const
Get the number of tracks associated with this vertex.
Definition: Vertex_v1.cxx:270
EGammaAmbiguityTool::m_maxDeltaR_innermost
float m_maxDeltaR_innermost
Maximum value for Rconv - RfirstHit for Si+Si conversions where both tracks have innermost hits.
Definition: EGammaAmbiguityTool.h:93
xAOD::uint8_t
uint8_t
Definition: Muon_v1.cxx:558
SG::Accessor
Helper class to provide type-safe access to aux data.
Definition: Control/AthContainers/AthContainers/Accessor.h:68
EGammaAmbiguityTool::m_MinNoSiHits
int m_MinNoSiHits
Minimum number of silicon hits to be an electron and not a photon.
Definition: EGammaAmbiguityTool.h:85
EGammaAmbiguityTool::ambiguityResolve
virtual unsigned int ambiguityResolve(const xAOD::CaloCluster *cluster, const xAOD::Vertex *vx, const xAOD::TrackParticle *tp, xAOD::AmbiguityTool::AmbiguityType &type) const override final
Return value: AuthorElectron, AuthorPhoton, AuthorAmbiguous, AuthorUnknown.
Definition: EGammaAmbiguityTool.cxx:75
EGammaAmbiguityTool::nTrkWithInnermostPixelHits
size_t nTrkWithInnermostPixelHits(const xAOD::Vertex &vx) const
Return the number of tracks with "innermost pixel hits" (see above) in the given vertex.
Definition: EGammaAmbiguityTool.cxx:331
xAODP4Helpers.h
xAOD::AmbiguityTool::unknown
@ unknown
Definition: IEGammaAmbiguityTool.h:42
asg
Definition: DataHandleTestTool.h:28
xAOD::CaloCluster_v1::SuperCluster
@ SuperCluster
Definition: CaloCluster_v1.h:110
ParticleTest.tp
tp
Definition: ParticleTest.py:25
EGammaAmbiguityTool.h
xAOD::numberOfPixelHits
@ numberOfPixelHits
these are the pixel hits, including the b-layer [unit8_t].
Definition: TrackingPrimitives.h:260
xAOD::expectInnermostPixelLayerHit
@ expectInnermostPixelLayerHit
Do we expect a 0th-layer barrel hit for this track?
Definition: TrackingPrimitives.h:237
xAOD::Egamma_v1
Definition: Egamma_v1.h:56
EGammaAmbiguityTool::accept
virtual bool accept(const xAOD::Egamma &egamma) const override final
Accept or reject egamma object based on ambiguity resolution (e.g.
Definition: EGammaAmbiguityTool.cxx:289
xAOD::EgammaParameters::ConversionType
ConversionType
Definition: EgammaEnums.h:268
xAOD::EgammaParameters::AuthorFwdElectron
const uint16_t AuthorFwdElectron
Electron reconstructed by the Forward cluster-based algorithm.
Definition: EgammaDefs.h:30
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
EGammaAmbiguityTool::hasInnermostPixelHit
bool hasInnermostPixelHit(const xAOD::TrackParticle &tp) const
Return true if track has innermost pixel hit or next-to-innermost in case innermost is not expected o...
Definition: EGammaAmbiguityTool.cxx:309
egamma
Definition: egamma.h:58
EgammaContainer.h
xAOD::CaloCluster_v1::clusterSize
ClusterSize clusterSize() const
Get cluster size.
Definition: CaloCluster_v1.cxx:364
Egamma.h
xAOD::CaloCluster_v1
Description of a calorimeter cluster.
Definition: CaloCluster_v1.h:62
EgammaxAODHelpers.h
xAOD::AmbiguityTool::electron
@ electron
Definition: IEGammaAmbiguityTool.h:34
xAOD::expectNextToInnermostPixelLayerHit
@ expectNextToInnermostPixelLayerHit
Do we expect a 1st-layer barrel hit for this track?
Definition: TrackingPrimitives.h:248
ElectronContainer.h
lumiFormat.i
int i
Definition: lumiFormat.py:85
CaloCluster.h
xAOD::EgammaParameters::AuthorCaloTopo35
const uint16_t AuthorCaloTopo35
Photon reconstructed by SW CaloTopo35 seeded clusters.
Definition: EgammaDefs.h:38
xAOD::EgammaParameters::AuthorAmbiguous
const uint16_t AuthorAmbiguous
Object Reconstructed by standard cluster-based algorithm.
Definition: EgammaDefs.h:32
beamspotman.n
n
Definition: beamspotman.py:729
Photon.h
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
Definition: AthCommonDataStore.h:145
xAOD::CaloCluster_v1::SW_35gam
@ SW_35gam
Definition: CaloCluster_v1.h:96
xAOD::AmbiguityTool::ambiguousVertexEoverPBetterThanTrackEoverP
@ ambiguousVertexEoverPBetterThanTrackEoverP
Definition: IEGammaAmbiguityTool.h:40
xAOD::EgammaHelpers::momentumAtVertex
Amg::Vector3D momentumAtVertex(const xAOD::Photon *, bool debug=false)
return the momentum at the vertex (which can be 0)
Definition: PhotonxAODHelpers.cxx:70
xAOD::EgammaParameters::doubleSi
@ doubleSi
two tracks, both with Si hits
Definition: EgammaEnums.h:279
xAOD::AmbiguityTool::ambiguousTrackEoverPBetterThanVertexEoverP
@ ambiguousTrackEoverPBetterThanVertexEoverP
Definition: IEGammaAmbiguityTool.h:35
EGammaAmbiguityTool::m_acceptAmbiguous
bool m_acceptAmbiguous
@When used as a selector reject/accpet ambiguous cases
Definition: EGammaAmbiguityTool.h:97
EGammaAmbiguityTool::initialize
virtual StatusCode initialize() override final
Gaudi Service Interface method implementations.
Definition: EGammaAmbiguityTool.cxx:68
EGammaAmbiguityTool::m_MinNoPixHits
int m_MinNoPixHits
Minimum number of pixel hits to be an electron and not a photon.
Definition: EGammaAmbiguityTool.h:87
xAOD::Vertex_v1::trackParticle
const TrackParticle * trackParticle(size_t i) const
Get the pointer to a given track that was used in vertex reco.
Definition: Vertex_v1.cxx:249
xAOD::AmbiguityTool::AmbiguityType
AmbiguityType
Definition: IEGammaAmbiguityTool.h:33
Vertex.h
egamma::author
unsigned int author() const
Reconstruction Author
Definition: egamma.h:244
xAOD::numberOfNextToInnermostPixelLayerHits
@ numberOfNextToInnermostPixelLayerHits
these are the hits in the 1st pixel barrel layer
Definition: TrackingPrimitives.h:249
xAOD::AmbiguityTool::photon
@ photon
Definition: IEGammaAmbiguityTool.h:41
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
xAOD::AmbiguityTool::ambiguousNoInnermost
@ ambiguousNoInnermost
Definition: IEGammaAmbiguityTool.h:39
xAOD::CaloCluster_v1::altE
flt_t altE() const
Get Energy in signal state ALTCALIBRATED.
xAOD::EgammaHelpers::conversionRadius
float conversionRadius(const xAOD::Vertex *vx)
return the conversion radius or 9999.
Definition: PhotonxAODHelpers.cxx:58
xAOD::Electron_v1
Definition: Electron_v1.h:34
xAOD::AmbiguityTool::ambiguousTrackHighEoverP
@ ambiguousTrackHighEoverP
Definition: IEGammaAmbiguityTool.h:37
xAOD::Photon
Photon_v1 Photon
Definition of the current "egamma version".
Definition: Event/xAOD/xAODEgamma/xAODEgamma/Photon.h:17
EGammaAmbiguityTool::passDeltaR_innermost
bool passDeltaR_innermost(const xAOD::Vertex &vx) const
Return true if the vertex passes the requirement on Rconv - RfirstHit.
Definition: EGammaAmbiguityTool.cxx:352
TrackParticle.h
python.plotting.G4DebuggerConfig.egamma
list egamma
Definition: G4DebuggerConfig.py:21
xAOD::photon
@ photon
Definition: TrackingPrimitives.h:200
EGammaAmbiguityTool::isInVertex
bool isInVertex(const xAOD::TrackParticle &, const xAOD::Vertex &) const
Return true if the given TrackParticle is part of the vertex.
Definition: EGammaAmbiguityTool.cxx:342
EGammaAmbiguityTool::m_noVertexNoInnermostAsAmb
bool m_noVertexNoInnermostAsAmb
no vertex && no innermost hit -> amb.
Definition: EGammaAmbiguityTool.h:95
xAOD::AmbiguityTool::ambiguousTrackNoPixel
@ ambiguousTrackNoPixel
Definition: IEGammaAmbiguityTool.h:38
xAOD::Vertex_v1
Class describing a Vertex.
Definition: Vertex_v1.h:42
EGammaAmbiguityTool::EGammaAmbiguityTool
EGammaAmbiguityTool(const std::string &myname)
Standard constructor.
Definition: EGammaAmbiguityTool.cxx:38
xAOD::Photon_v1
Definition: Photon_v1.h:37
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
EGammaAmbiguityTool::m_minPtCut
float m_minPtCut
Minimum Pt, less that this is ambiguous.
Definition: EGammaAmbiguityTool.h:91
CaloCondBlobAlgs_fillNoiseFromASCII.author
string author
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:25
EgammaDefs.h
xAOD::EgammaParameters::electron
@ electron
Definition: EgammaEnums.h:18
xAOD::EgammaHelpers::conversionType
xAOD::EgammaParameters::ConversionType conversionType(const xAOD::Photon *ph)
return the photon conversion type (see EgammaEnums)
Definition: PhotonxAODHelpers.cxx:21
xAOD::EgammaParameters::AuthorPhoton
const uint16_t AuthorPhoton
Object Reconstructed by standard cluster-based algorithm.
Definition: EgammaDefs.h:28
xAOD::numberOfSCTHits
@ numberOfSCTHits
number of hits in SCT [unit8_t].
Definition: TrackingPrimitives.h:269
SG::ConstAccessor< T, AuxAllocator_t< T > >::isAvailable
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
Electron.h
xAOD::TrackParticle_v1
Class describing a TrackParticle.
Definition: TrackParticle_v1.h:43
xAOD::AmbiguityTool::ambiguousTrackLowPt
@ ambiguousTrackLowPt
Definition: IEGammaAmbiguityTool.h:36
xAOD::CaloCluster_v1::SW_35ele
@ SW_35ele
Definition: CaloCluster_v1.h:92
PhotonContainer.h
xAOD::CaloCluster_v1::e
virtual double e() const
The total energy of the particle.
Definition: CaloCluster_v1.cxx:265
xAOD::numberOfInnermostPixelLayerHits
@ numberOfInnermostPixelLayerHits
these are the hits in the 0th pixel barrel layer
Definition: TrackingPrimitives.h:238
EGammaAmbiguityTool::m_maxEoverPCut
float m_maxEoverPCut
Maximum EoverP, more that this is ambiguous.
Definition: EGammaAmbiguityTool.h:89
xAOD::EgammaParameters::AuthorElectron
const uint16_t AuthorElectron
Object Reconstructed by standard cluster-based algorithm.
Definition: EgammaDefs.h:24