ATLAS Offline Software
Loading...
Searching...
No Matches
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
11
13
15#include "xAODTracking/Vertex.h"
17
18#include "xAODEgamma/Egamma.h"
19#include "xAODEgamma/Electron.h"
20#include "xAODEgamma/Photon.h"
24
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//=============================================================================
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",
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
249
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
319 CHECK_HITS( tp.summaryValue(trkNhits,xAOD::numberOfNextToInnermostPixelLayerHits) );
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}
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define CHECK_HITS(EXP)
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
EGammaAmbiguityTool(const std::string &myname)
Standard constructor.
bool m_noVertexNoInnermostAsAmb
no vertex && no innermost hit -> amb.
int m_MinNoSiHits
Minimum number of silicon hits to be an electron and not a photon.
float m_maxEoverPCut
Maximum EoverP, more that this is ambiguous.
size_t nTrkWithInnermostPixelHits(const xAOD::Vertex &vx) const
Return the number of tracks with "innermost pixel hits" (see above) in the given vertex.
bool isInVertex(const xAOD::TrackParticle &, const xAOD::Vertex &) const
Return true if the given TrackParticle is part of the vertex.
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.
float m_maxDeltaR_innermost
Maximum value for Rconv - RfirstHit for Si+Si conversions where both tracks have innermost hits.
float m_minPtCut
Minimum Pt, less that this is ambiguous.
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...
int m_MinNoPixHits
Minimum number of pixel hits to be an electron and not a photon.
virtual bool accept(const xAOD::Egamma &egamma) const override final
Accept or reject egamma object based on ambiguity resolution (e.g.
virtual StatusCode initialize() override final
Gaudi Service Interface method implementations.
bool passDeltaR_innermost(const xAOD::Vertex &vx) const
Return true if the vertex passes the requirement on Rconv - RfirstHit.
bool m_acceptAmbiguous
@When used as a selector reject/accpet ambiguous cases
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
elec/gamma data class.
Definition egamma.h:58
unsigned int author() const
Reconstruction Author.
Definition egamma.h:244
ClusterSize clusterSize() const
Get cluster size.
virtual double e() const
The total energy of the particle.
flt_t altE() const
Get Energy in signal state ALTCALIBRATED.
size_t nTrackParticles() const
Get the number of tracks associated with this vertex.
const TrackParticle * trackParticle(size_t i) const
Get the pointer to a given track that was used in vertex reco.
@ Photon
The object is a photon.
Definition ObjectType.h:47
@ Electron
The object is an electron.
Definition ObjectType.h:46
Amg::Vector3D momentumAtVertex(const xAOD::Photon *, bool debug=false)
return the momentum at the vertex (which can be 0)
xAOD::EgammaParameters::ConversionType conversionType(const xAOD::Photon *ph)
return the photon conversion type (see EgammaEnums)
float conversionRadius(const xAOD::Vertex *vx)
return the conversion radius or 9999.
const uint16_t AuthorPhoton
Object Reconstructed by standard cluster-based algorithm.
Definition EgammaDefs.h:28
const uint16_t AuthorCaloTopo35
Photon reconstructed by SW CaloTopo35 seeded clusters.
Definition EgammaDefs.h:38
@ doubleSi
two tracks, both with Si hits
const uint16_t AuthorElectron
Object Reconstructed by standard cluster-based algorithm.
Definition EgammaDefs.h:24
const uint16_t AuthorAmbiguous
Object Reconstructed by standard cluster-based algorithm.
Definition EgammaDefs.h:32
const uint16_t AuthorFwdElectron
Electron reconstructed by the Forward cluster-based algorithm.
Definition EgammaDefs.h:30
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Vertex_v1 Vertex
Define the latest version of the vertex class.
Egamma_v1 Egamma
Definition of the current "egamma version".
Definition Egamma.h:17
Photon_v1 Photon
Definition of the current "egamma version".
@ expectInnermostPixelLayerHit
Do we expect a 0th-layer barrel hit for this track?
@ numberOfNextToInnermostPixelLayerHits
these are the hits in the 1st pixel barrel layer
@ expectNextToInnermostPixelLayerHit
Do we expect a 1st-layer barrel hit for this track?
@ numberOfSCTHits
number of hits in SCT [unit8_t].
@ numberOfInnermostPixelLayerHits
these are the hits in the 0th pixel barrel layer
@ numberOfPixelHits
these are the pixel hits, including the b-layer [unit8_t].
Electron_v1 Electron
Definition of the current "egamma version".