ATLAS Offline Software
Loading...
Searching...
No Matches
EGElectronAmbiguityTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
9
12
14
15#include <cmath>
16#include <numbers>
17
18namespace {
19
20constexpr double TwoPi = 2 * std::numbers::pi;
21constexpr double PiOver2 = std::numbers::pi/2.;
22
23void
24helix(const xAOD::TrackParticle* trkP,
25 const xAOD::Vertex* pvtx,
26 std::vector<double>& he)
27{
28 constexpr double PTTOCURVATURE = -0.301;
29
30 he[0] = 1. / std::tan(trkP->theta());
31 he[1] = PTTOCURVATURE * trkP->charge() / trkP->pt();
32
33 if (trkP->phi0() > 0.)
34 he[4] = trkP->phi0();
35 else
36 he[4] = TwoPi + trkP->phi0();
37
38 double c1 = std::cos(trkP->phi0());
39 double s1 = std::sin(trkP->phi0());
40 he[3] = trkP->d0() + c1 * pvtx->y() - s1 * pvtx->x();
41
42 c1 *= he[0];
43 s1 *= he[0];
44 he[2] = trkP->z0() - c1 * pvtx->x() - s1 * pvtx->y() + pvtx->z();
45}
46}//end anonymous
47
48
49namespace DerivationFramework {
50
53{
54
55 ATH_CHECK(m_containerName.initialize());
56 ATH_CHECK(m_VtxContainerName.initialize());
57 ATH_CHECK(m_tpContainerName.initialize());
58 ATH_CHECK(m_tpCName.initialize());
59
60 ATH_CHECK(m_drv.initialize());
61 ATH_CHECK(m_dphiv.initialize());
62 ATH_CHECK(m_dmee.initialize());
63 ATH_CHECK(m_dmeeVtx.initialize());
64 ATH_CHECK(m_dsep.initialize());
65 ATH_CHECK(m_dambi.initialize());
66 ATH_CHECK(m_dtrv.initialize());
67 ATH_CHECK(m_dtpv.initialize());
68 ATH_CHECK(m_dtzv.initialize());
69
70 return StatusCode::SUCCESS;
71}
72
74 (const EGElectronAmbiguityTool& tool, const EventContext& ctx)
75 : drv (tool.m_drv, ctx),
76 dphiv (tool.m_dphiv, ctx),
77 dmee (tool.m_dmee, ctx),
78 dmeeVtx (tool.m_dmeeVtx, ctx),
79 dsep (tool.m_dsep, ctx),
80 dambi (tool.m_dambi, ctx),
81 dtrv (tool.m_dtrv, ctx),
82 dtpv (tool.m_dtpv, ctx),
83 dtzv (tool.m_dtzv, ctx)
84{
85}
86
87StatusCode
88EGElectronAmbiguityTool::addBranches(const EventContext& ctx) const
89{
90
91 DecorHandles dh (*this, ctx);
92
93 static const SG::ConstAccessor<char> aidCut(m_idCut);
94
95 // retrieve primary vertex
96 const xAOD::Vertex* pvtx(nullptr);
98 if (inputVtx.ptr()){
99 const xAOD::VertexContainer* vtxC = inputVtx.ptr();
100 for (const auto* vertex : *vtxC) {
101 if (vertex->vertexType() == xAOD::VxType::VertexType::PriVtx) {
102 pvtx = vertex;
103 break;
104 }
105 }
106 }
107
108 // retrieve electron container
110 ctx };
111 const xAOD::ElectronContainer* eleC = inputElectrons.ptr();
112
113 if (!eleC) {
115 "Couldn't retrieve Electron container with key: " << m_containerName);
116 return StatusCode::FAILURE;
117 }
118 if (!pvtx) {
119 ATH_MSG_DEBUG("No primary vertex found. Setting default values.");
120 for (const xAOD::Electron* iele : *eleC) {
121 dh.drv(*iele) = -1;
122 dh.dphiv(*iele) = -1;
123 dh.dmee(*iele) = -1;
124 dh.dmeeVtx(*iele) = -1;
125 dh.dsep(*iele) = -1;
126 dh.dambi(*iele) = -1;
127 dh.dtrv(*iele) = -1;
128 dh.dtpv(*iele) = -1;
129 dh.dtzv(*iele) = -1;
130 }
131 return StatusCode::SUCCESS;
132 }
133 ATH_MSG_DEBUG("Pvx z = " << pvtx->z() << ", number of electrons "
134 << eleC->size());
135
136 // Make a container of selected tracks : with Si hits, close to electron track
139 };
140 const xAOD::TrackParticleContainer* idtpC = inputTrackParticles.ptr();
141
142 std::set<const xAOD::TrackParticle*> alreadyStored;
143 std::set<const xAOD::TrackParticle*> eleIDtpStored, eleGSFtpStored;
144 auto closeByTracks =
145 std::make_unique<ConstDataVector<xAOD::TrackParticleContainer>>(
147
148 for (const auto* ele : *eleC) {
149
150 dh.dambi(*ele) = -1;
151
152 // Electron preselection
153 if (ele->pt() < m_elepTCut ||
154 m_idCut.empty() || !aidCut.isAvailable(*ele) || !aidCut(*ele))
155 continue;
156
157 // Just for debug
158 const xAOD::TrackParticle* eleGSFtp = ele->trackParticle();
159 eleGSFtpStored.insert(eleGSFtp);
160
161 const xAOD::TrackParticle* eleIDtp =
163 eleIDtpStored.insert(eleIDtp);
164
165 // The loop on track
166 for (const auto* tp : *idtpC) {
167
168 // Keep the electron track (I build a container to run vertexing on it...)
169 if (tp == eleIDtp) {
170 closeByTracks->push_back(tp);
171 alreadyStored.insert(tp);
172 continue;
173 }
174
175 // potential candidate to store if not already there
176 if (alreadyStored.find(tp) != alreadyStored.end())
177 continue;
178
180 // if (tp->charge() * ele->charge() > 0)
181 // continue;
182
183 // Close-by
184 double dR = eleIDtp->p4().DeltaR(tp->p4());
185 double dz = std::abs(eleIDtp->z0() - tp->z0()) * std::sin(eleIDtp->theta());
186 if (dR >= 0.3 || dz >= m_dzCut)
187 continue;
188
189 // With minimum number of Si hits
191 continue;
192
193 alreadyStored.insert(tp);
194
195 closeByTracks->push_back(tp);
196 }
197 }
198
199 if (closeByTracks->empty())
200 return StatusCode::SUCCESS;
201
202 if (msgLvl(MSG::DEBUG)) {
204 ctx };
205 const xAOD::TrackParticleContainer* tpC = tpCReadHandle.ptr();
206
207 ATH_MSG_DEBUG("Number of input tracks "
208 << idtpC->size() << " , number of selected close-by tracks "
209 << closeByTracks->size() << " , number of GSF tracks "
210 << tpC->size());
211 for (const auto* trk : eleIDtpStored)
212 ATH_MSG_DEBUG("ele ID trk "
213 << trk << " pt = " << trk->pt() * 1e-3
214 << " eta = " << trk->eta() << " phi = " << trk->phi()
215 << " nSi = " << xAOD::EgammaHelpers::numberOfSiHits(trk));
216 for (const auto* trk : eleGSFtpStored)
217 ATH_MSG_DEBUG("ele GSF trk "
218 << trk << " pt = " << trk->pt() * 1e-3
219 << " eta = " << trk->eta() << " phi = " << trk->phi()
220 << " nSi = " << xAOD::EgammaHelpers::numberOfSiHits(trk));
221 for (const xAOD::TrackParticle* trk : *closeByTracks)
222 ATH_MSG_DEBUG("closeby trk "
223 << trk << " pt = " << trk->pt() * 1e-3
224 << " eta = " << trk->eta() << " phi = " << trk->phi()
225 << " nSi = " << xAOD::EgammaHelpers::numberOfSiHits(trk));
226 }
227
228 for (const auto* ele : *eleC) {
229
230 // Electron preselection
231 if (ele->pt() < m_elepTCut ||
232 m_idCut.empty() || !aidCut.isAvailable(*ele) || !aidCut(*ele))
233 continue;
234
235 // Henri's circles
236 if (decorateSimple(dh, closeByTracks, ele, pvtx).isFailure()) {
237 ATH_MSG_ERROR("Cannot decorate the electron with the simple info");
238 return StatusCode::FAILURE;
239 }
240
241 } // loop on electrons to decorate
242
243 return StatusCode::SUCCESS;
244}
245}
246
247StatusCode
249 DecorHandles& dh,
251 const xAOD::Electron* ele,
252 const xAOD::Vertex* pvtx) const
253{
254 // This is the GSF electron track
255 const xAOD::TrackParticle* eleGSFtrkP = ele->trackParticle();
256
257 // And the ID one
258 const xAOD::TrackParticle* eleIDtrkP =
260
261 // For the time being, use the ID one, to be consistent when we only find a
262 // good ID to make a conversion and no GSF
263 bool useGSF = false; // hardcoded because it seems we will not use true. Kept
264 // for the time being, as not 100% sure
265 const xAOD::TrackParticle* eletrkP = useGSF ? eleGSFtrkP : eleIDtrkP;
266
267 ATH_MSG_DEBUG("Electron pt = " << ele->pt() * 1e-3 << " eta = " << ele->eta()
268 << " phi = " << ele->phi() << " GSF trk ptr = "
269 << eleGSFtrkP << " ID trk ptr " << eleIDtrkP);
270
271 if (m_isMC) {
272 const xAOD::TruthParticle* truthEl =
274 double tpvr = -1, tpvp = 9e9, tpvz = 9e9;
275 if (truthEl && MC::isElectron(truthEl) &&
276 truthEl->prodVtx() != nullptr) {
277 tpvr = truthEl->prodVtx()->perp();
278 tpvp = truthEl->prodVtx()->phi();
279 tpvz = truthEl->prodVtx()->z();
280 }
281 dh.dtrv(*ele) = tpvr;
282 dh.dtpv(*ele) = tpvp;
283 dh.dtzv(*ele) = tpvz;
284 }
285
286 // Find the closest track particle with opposite charge and a minimum nb of Si
287 // hits
288 const xAOD::TrackParticle* otrkP(nullptr);
289 double detaMin = 9e9;
290 for (const xAOD::TrackParticle* tp : *tpC) {
291 // Keep only opposite charge
292 if (tp->charge() * eletrkP->charge() > 0)
293 continue;
294
295 // Close-by
296 double dR = eletrkP->p4().DeltaR(tp->p4());
297 double dz = std::abs(eletrkP->z0() - tp->z0()) * std::sin(eletrkP->theta());
298 if (dR >= 0.3 || dz >= m_dzCut)
299 continue;
300
301 double deta = std::abs(eletrkP->eta() - tp->eta());
302 if (deta < detaMin) {
303 otrkP = tp;
304 detaMin = deta;
305 }
306 }
307
308 double rv = -9e9;
309 double pv = -9e9;
310 double mee = -1.;
311 double meeAtVtx = -1.;
312 double sep = -9e9;
313 bool goodConv = false;
314
315 if (otrkP) {
316
317 // To be consistent with the other, use the ID track.
318 TLorentzVector ep4;
319 ep4.SetPtEtaPhiM(eletrkP->pt(), eletrkP->eta(), eletrkP->phi(), ParticleConstants::electronMassInMeV);
320
321 // Maybe could see if a GSF tp exists for this ID tp and use it if yes ?
322 TLorentzVector op4;
323 op4.SetPtEtaPhiM(otrkP->pt(), otrkP->eta(), otrkP->phi(), ParticleConstants::electronMassInMeV);
324
325 // Simple masses
326 mee = (ep4 + op4).M();
327 op4.SetPhi(eletrkP->phi());
328 meeAtVtx = (ep4 + op4).M();
329
330 // And the conversion point
331 std::vector<double> helix1, helix2;
332 helix1.resize(5);
333 helix2.resize(5);
334 helix(eletrkP, pvtx, helix1);
335 helix(otrkP, pvtx, helix2);
336
337 double beta(0.);
338 if (helix1[4] < helix2[4])
339 beta = PiOver2 - helix1[4];
340 else
341 beta = PiOver2 - helix2[4];
342
343 double phi1(helix1[4] + beta);
344 if (phi1 > TwoPi)
345 phi1 -= TwoPi;
346 if (phi1 < 0.)
347 phi1 += TwoPi;
348
349 double phi2(helix2[4] + beta);
350 if (phi2 > TwoPi)
351 phi2 -= TwoPi;
352 if (phi2 < 0.)
353 phi2 += TwoPi;
354
356 double r1 = 1 / (2. * std::abs(helix1[1]));
357
358 double charge1(1.);
359 if (helix1[1] < 0.)
360 charge1 = -1.;
361 double rcenter1(helix1[3] / charge1 + r1);
362 double phicenter1(phi1 + PiOver2 * charge1);
363
364 double x1 = rcenter1 * std::cos(phicenter1);
365 double y1 = rcenter1 * std::sin(phicenter1);
366
368 double r2 = 1 / (2. * std::abs(helix2[1]));
369
370 double charge2(1.);
371 if (helix2[1] < 0.)
372 charge2 = -1.;
373 double rcenter2(helix2[3] / charge2 + r2);
374 double phicenter2(phi2 + PiOver2 * charge2);
375
376 double x2 = rcenter2 * std::cos(phicenter2);
377 double y2 = rcenter2 * std::sin(phicenter2);
379
380 double dx = x1 - x2;
381 if (std::abs(dx) < 1e-9) {
382 dx = std::copysign(1e-9, dx);
383 }
384 double slope((y1 - y2) / dx);
385 double b(y1 - slope * x1);
386 double alpha(std::atan(slope));
387 double d(std::sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
388 // only keeping opposite sign option
389 double separation = d - r1 - r2;
390 double cpx1, cpx2;
391 if (x1 > x2) {
392 cpx1 = x1 - r1 * std::cos(alpha);
393 cpx2 = x2 + r2 * std::cos(alpha);
394 } else {
395 cpx1 = x1 + r1 * std::cos(alpha);
396 cpx2 = x2 - r2 * std::cos(alpha);
397 }
398
399 double temp1 = (cpx1 + cpx2) / 2;
400 double temp2 = slope * temp1 + b;
401 double convX = std::cos(beta) * temp1 + std::sin(beta) * temp2;
402 double convY = -std::sin(beta) * temp1 + std::cos(beta) * temp2;
403
404 double dct(helix1[0] - helix2[0]);
405
407 if (std::abs(separation) < m_sepCut && std::abs(dct) < m_dctCut) {
408 goodConv = true;
409 sep = separation;
410 pv = std::atan2(convY, convX);
411 rv = std::sqrt(convX * convX + convY * convY);
412 if (convX * std::cos(eletrkP->phi()) + convY * std::sin(eletrkP->phi()) < 0)
413 rv *= -1.;
414 }
415 } else {
416 dh.dambi(*ele) = -1;
417 }
418 dh.drv(*ele) = rv;
419 dh.dphiv(*ele) = pv;
420 dh.dmee(*ele) = mee;
421 dh.dmeeVtx(*ele) = meeAtVtx;
422 dh.dsep(*ele) = sep;
423 if (goodConv && rv > m_rvECCut && meeAtVtx < m_meeAtVtxECCut)
424 dh.dambi(*ele) = 2;
425 else if (otrkP) {
426 if (mee < m_meeICCut)
427 dh.dambi(*ele) = 1;
428 else
429 dh.dambi(*ele) = 0;
430 }
431 return StatusCode::SUCCESS;
432}
433
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
ATLAS-specific HepMC functions.
DataVector adapter that acts like it holds const pointers.
size_type size() const noexcept
Returns the number of elements in the collection.
virtual StatusCode addBranches(const EventContext &ctx) const override final
SG::WriteDecorHandleKey< xAOD::ElectronContainer > m_dsep
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_tpContainerName
SG::WriteDecorHandleKey< xAOD::ElectronContainer > m_dtzv
StatusCode decorateSimple(DecorHandles &dh, std::unique_ptr< ConstDataVector< xAOD::TrackParticleContainer > > &tpC, const xAOD::Electron *ele, const xAOD::Vertex *pvtx) const
SG::ReadHandleKey< xAOD::ElectronContainer > m_containerName
SG::WriteDecorHandleKey< xAOD::ElectronContainer > m_dambi
SG::WriteDecorHandleKey< xAOD::ElectronContainer > m_dmee
SG::WriteDecorHandleKey< xAOD::ElectronContainer > m_dtrv
SG::WriteDecorHandleKey< xAOD::ElectronContainer > m_dphiv
SG::WriteDecorHandleKey< xAOD::ElectronContainer > m_dtpv
SG::WriteDecorHandleKey< xAOD::ElectronContainer > m_dmeeVtx
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_tpCName
SG::WriteDecorHandleKey< xAOD::ElectronContainer > m_drv
SG::ReadHandleKey< xAOD::VertexContainer > m_VtxContainerName
Helper class to provide constant type-safe access to aux data.
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
const_pointer_type ptr()
Dereference the pointer.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
Definition Egamma_v1.cxx:66
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
Definition Egamma_v1.cxx:71
virtual double phi() const override final
The azimuthal angle ( ) of the particle.
Definition Egamma_v1.cxx:76
const xAOD::TrackParticle * trackParticle(size_t index=0) const
Pointer to the xAOD::TrackParticle/s that match the electron candidate.
float z0() const
Returns the parameter.
float theta() const
Returns the parameter, which has range 0 to .
virtual FourMom_t p4() const override final
The full 4-momentum of the particle.
virtual double phi() const override final
The azimuthal angle ( ) of the particle (has range to .).
float d0() const
Returns the parameter.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
float charge() const
Returns the charge.
float phi0() const
Returns the parameter, which has range to .
const TruthVertex_v1 * prodVtx() const
The production vertex of this particle.
float z() const
Vertex longitudinal distance along the beam line form the origin.
float phi() const
Vertex azimuthal angle.
float perp() const
Vertex transverse distance from the beam line.
float z() const
Returns the z position.
float y() const
Returns the y position.
float x() const
Returns the x position.
THE reconstruction tool.
::StatusCode StatusCode
StatusCode definition for legacy code.
bool isElectron(const T &p)
constexpr double electronMassInMeV
the mass of the electron (in MeV)
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
std::size_t numberOfSiHits(const xAOD::TrackParticle *tp)
return the number of Si hits in the track particle
const xAOD::TrackParticle * getOriginalTrackParticle(const xAOD::Electron *el)
Helper function for getting the "Original" Track Particle (i.e before GSF) via the electron.
const xAOD::TruthParticle * getTruthParticle(const xAOD::IParticle &p)
Return the truthParticle associated to the given IParticle (if any).
@ PriVtx
Primary vertex.
ElectronContainer_v1 ElectronContainer
Definition of the current "electron container version".
TrackParticle_v1 TrackParticle
Reference the current persistent version:
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
Vertex_v1 Vertex
Define the latest version of the vertex class.
TruthParticle_v1 TruthParticle
Typedef to implementation.
TrackParticleContainer_v1 TrackParticleContainer
Definition of the current "TrackParticle container version".
Electron_v1 Electron
Definition of the current "egamma version".
SG::WriteDecorHandle< xAOD::ElectronContainer, float > dtrv
SG::WriteDecorHandle< xAOD::ElectronContainer, int > dambi
SG::WriteDecorHandle< xAOD::ElectronContainer, float > dtpv
SG::WriteDecorHandle< xAOD::ElectronContainer, float > dsep
SG::WriteDecorHandle< xAOD::ElectronContainer, float > dmee
DecorHandles(const EGElectronAmbiguityTool &tool, const EventContext &ctx)
SG::WriteDecorHandle< xAOD::ElectronContainer, float > dphiv
SG::WriteDecorHandle< xAOD::ElectronContainer, float > drv
SG::WriteDecorHandle< xAOD::ElectronContainer, float > dtzv
SG::WriteDecorHandle< xAOD::ElectronContainer, float > dmeeVtx