ATLAS Offline Software
Loading...
Searching...
No Matches
VertexDecoratorAlg.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#include <TLorentzVector.h>
14#include <cmath>
15
16
18{
19 VertexDecoratorAlg ::VertexDecoratorAlg(const std::string &name,
20 ISvcLocator *pSvcLocator)
21 : AthHistogramAlgorithm (name, pSvcLocator)
22 {
23 }
24
25 StatusCode VertexDecoratorAlg ::initialize()
26 {
27 ATH_CHECK(m_vertexInKey.initialize());
28 ATH_CHECK(m_eventInKey.initialize());
29 ATH_CHECK(m_photonsInKey.initialize());
30 ATH_CHECK(m_electronsInKey.initialize());
31 ATH_CHECK(m_muonsInKey.initialize());
32 ATH_CHECK(m_jetsInKey.initialize());
33 ATH_CHECK(m_multiPhotonsOutKey.initialize());
34
35 const std::string baseName = m_vertexInKey.key();
36
37 // WriteHandleKeys
38 m_photonLinksKey = baseName + ".photonLinks";
39 m_jetLinksKey = baseName + ".jetLinks";
40 m_electronLinksKey = baseName + ".electronLinks";
41 m_muonLinksKey = baseName + ".muonLinks";
42 m_mDecor_ntrk = baseName + "." + m_mDecor_ntrk.key();
43 m_mDecor_sumPt = baseName + "." + m_mDecor_sumPt.key();
44 m_mDecor_chi2Over_ndf = baseName + "." + m_mDecor_chi2Over_ndf.key();
45 m_mDecor_z_asym = baseName + "." + m_mDecor_z_asym.key();
48 m_mDecor_z_skew = baseName + "." + m_mDecor_z_skew.key();
49 m_mDecor_photon_deltaz = baseName + "." + m_mDecor_photon_deltaz.key();
52 m_multiPhotonLinksKey = baseName + ".multiPhotonLinks";
53
54 ATH_CHECK(m_multiPhotonLinksKey.initialize());
55 ATH_CHECK(m_photonLinksKey.initialize());
56 ATH_CHECK(m_jetLinksKey.initialize());
57 ATH_CHECK(m_electronLinksKey.initialize());
58 ATH_CHECK(m_muonLinksKey.initialize());
59 ATH_CHECK(m_mDecor_ntrk.initialize());
60 ATH_CHECK(m_mDecor_sumPt.initialize());
61 ATH_CHECK(m_mDecor_chi2Over_ndf.initialize());
62 ATH_CHECK(m_mDecor_z_asym.initialize());
65 ATH_CHECK(m_mDecor_z_skew.initialize());
69
70 // ReadHandleKeys
71 m_deltaZKey = baseName + ".deltaZ";
72 m_deltaPhiKey = baseName + ".deltaPhi";
73 ATH_CHECK(m_deltaZKey.initialize());
74 ATH_CHECK(m_deltaPhiKey.initialize());
75
76 // additional ReadHandleKeys to declare dependencies to the scheduler
77 std::string photonBaseName = m_photonsInKey.key();
78
79 m_caloPointingZKey = photonBaseName + ".caloPointingZ";
80 m_zCommonKey = photonBaseName + ".zCommon";
81 m_zCommonErrorKey = photonBaseName + ".zCommonError";
82
83 ATH_CHECK(m_caloPointingZKey.initialize());
84 ATH_CHECK(m_zCommonKey.initialize());
85 ATH_CHECK(m_zCommonErrorKey.initialize());
86
87 // Tools
88 ATH_CHECK(m_gnnTool.retrieve());
89 ATH_CHECK(m_trkVtxAssociationTool->setProperty("WorkingPoint","Prompt_MaxWeight"));
90 ATH_CHECK(m_trkVtxAssociationTool->setProperty("AMVFVerticesDeco","TTVA_AMVFVertices_forReco"));
91 ATH_CHECK(m_trkVtxAssociationTool->setProperty("AMVFWeightsDeco","TTVA_AMVFWeights_forReco"));
94
95 return StatusCode::SUCCESS;
96 }
97
98 StatusCode VertexDecoratorAlg ::execute()
99 {
100 const EventContext &ctx = Gaudi::Hive::currentContext();
102 ATH_CHECK(vertices.isValid());
103
105 ATH_CHECK(photonsIn.isValid());
106
108 ATH_CHECK(electronsIn.isValid());
110 ATH_CHECK(muonsIn.isValid());
112 ATH_CHECK(jetsIn.isValid());
114 ATH_CHECK(eventInfo.isValid());
115
121
127
128 // Decorations needed by the GNNTool
140
141 auto mpCont = std::make_unique<xAOD::CompositeParticleContainer>();
142 auto mpAux = std::make_unique<xAOD::CompositeParticleAuxContainer>();
143 mpCont->setStore(mpAux.get());
144
145 const xAOD::Vertex* bestVtxForMP = nullptr;
146 ElementLink<xAOD::CompositeParticleContainer> mpLink; // will be valid only if created
147 bool haveMP = false;
148
149 // For MT safety, decoration keys must be initialized and available upfront.
150 const bool haveZCommonDecor = acc_zCommon.isAvailable() && acc_zCommonError.isAvailable();
151 const bool haveCaloPointingDecor = acc_caloPointingZ.isAvailable();
152
153 if (photonsIn->size() > 1 && (!haveZCommonDecor || !haveCaloPointingDecor))
154 {
155 ATH_MSG_ERROR("photonsIn has size > 1 but required decorations are missing: "
156 << m_zCommonKey.key() << " and/or " << m_zCommonErrorKey.key()
157 << " and/or " << m_caloPointingZKey.key());
158 return StatusCode::FAILURE;
159 }
160
161 if (photonsIn->size() > 1)
162 {
163 // Combined pointing Z (weighted)
164 double sumW = 0.0;
165 double sumWZ = 0.0;
166
167 TLorentzVector p4sum;
168 int nUsed = 0;
169 for (const xAOD::Photon* ph : *photonsIn)
170 {
171 const float zCommon = acc_zCommon(*ph);
172 const float zCaloPointing = acc_caloPointingZ(*ph);
173 // Value-based selection only: prefer zCommon, then fallback to caloPointing value.
174 const bool useZCommonValue = std::isfinite(zCommon);
175 const float z = useZCommonValue ? zCommon : zCaloPointing;
176 if (!std::isfinite(z)) {
177 ATH_MSG_ERROR("Non-finite photon pointing values found in both "
178 << m_zCommonKey.key() << " and " << m_caloPointingZKey.key());
179 return StatusCode::FAILURE;
180 }
181
182 // Keep weighting consistent with the z source:
183 // use zCommonError only when z comes from zCommon.
184 double w = 1.0;
185 if (useZCommonValue) {
186 const float s = acc_zCommonError(*ph);
187 if (std::isfinite(s) && s > 0.0f) w = 1.0 / (double(s) * double(s));
188 }
189
190 sumW += w;
191 sumWZ += w * z;
192 p4sum += ph->p4();
193 ++nUsed;
194 }
195
196 if (nUsed > 1 && sumW > 0.0)
197 {
198 const float zPoint = sumWZ / sumW;
199
200 // Choose vertex closest in z to combined pointing
201 float bestAbsDZ = 1e30;
202 for (const xAOD::Vertex* vtx : *vertices)
203 {
204 if (vtx->vertexType() == xAOD::VxType::NoVtx) continue;
205
206 const float dz = zPoint - vtx->z();
207 const float adz = std::abs(dz);
208 if (adz < bestAbsDZ)
209 {
210 bestAbsDZ = adz;
211 bestVtxForMP = vtx;
212 }
213 }
214
215 if (bestVtxForMP)
216 {
217 // Create exactly one CompositeParticle node
218 auto* mp = new xAOD::CompositeParticle();
219 mpCont->push_back(mp);
220
221 mp->setP4(p4sum);
222
223 SG::AuxElement::Decorator<float> dec_mp_deltaZ("deltaZ");
224 SG::AuxElement::Decorator<float> dec_mp_deltaPhi("deltaPhi");
225 SG::AuxElement::Decorator<int> dec_mp_nPhotons("nPhotons");
226 SG::AuxElement::Decorator<float> dec_mp_zPointing("zPointing");
227
228 const float deltaZ = zPoint - bestVtxForMP->z();
229 dec_mp_deltaZ(*mp) = deltaZ;
230 dec_mp_zPointing(*mp) = zPoint;
231 dec_mp_nPhotons(*mp) = static_cast<int>(photonsIn->size());
232
233 float dphi = 0.0f;
234 if (acc_deltaPhi.isAvailable())
235 {
236 dphi = acc_deltaPhi(*bestVtxForMP);
237 if (!std::isfinite(dphi)) dphi = 0.0f;
238 }
239 dec_mp_deltaPhi(*mp) = dphi;
240 mpLink.setElement(mp);
241 mpLink.setStorableObject(*mpCont, true);
242
243 haveMP = true;
244 }
245 }
246 }
247
248 // Record the MultiPhotons container (even if empty)
249 ATH_CHECK(mpHandle.record(std::move(mpCont), std::move(mpAux)));
250
251 std::map< const xAOD::Vertex*, std::vector<ElementLink<xAOD::JetContainer>> > jetsInVertex;
252 std::map< const xAOD::Jet*, std::map< const xAOD::Vertex*, int> > jetVertexPt;
253
254 // initialize jet-vertex map
255 for(const xAOD::Vertex *vertex : *vertices){
256 jetsInVertex[vertex] = {};
257 for(const xAOD::Jet *jet : *jetsIn){
258 jetVertexPt[jet][vertex] = 0;
259 }
260 }
261
262 // pre-fill the jet-vertex map
263 for(const xAOD::Jet* jet : *jetsIn){
264
265 // for each jet, calculate the track pT associated to each vertex
266 std::vector<const xAOD::TrackParticle*> ghostTracks = jet->getAssociatedObjects<xAOD::TrackParticle >(xAOD::JetAttribute::GhostTrack);
267 for(const xAOD::TrackParticle* jtrk : ghostTracks){
268 if( !jtrk ) continue;
269 auto jetTrackVertex = m_trkVtxAssociationTool->getUniqueMatchVertexLink(*jtrk, *vertices);
270 if(jetTrackVertex) jetVertexPt[jet][*jetTrackVertex] += jtrk->pt();
271 }
272
273 // find vertex with the largest fraction of jet track pt
274 float maxPtFrac = -1;
275 const xAOD::Vertex* uniqueVertexAddress = nullptr;
276 for (const xAOD::Vertex *vertex : *vertices) {
277 if (vertex->vertexType() == xAOD::VxType::NoVtx) continue;
278 if(jetVertexPt[jet][vertex] > maxPtFrac){
279 maxPtFrac = jetVertexPt[jet][vertex];
280 uniqueVertexAddress = vertex;
281 }
282 }
283
284 // add jet to that vertex's vector of links
286 jetLink.setElement(jet);
287 jetLink.setStorableObject(*jetsIn.ptr(), true);
288 jetsInVertex[uniqueVertexAddress].push_back(jetLink);
289 }
290
291 for (const xAOD::Vertex *vertex : *vertices)
292 {
293 if (vertex->vertexType() == xAOD::VxType::NoVtx)
294 continue;
295
296 if (vertex->nTrackParticles() < 2)
297 continue;
298
299 dec_actualInterPerXing(*vertex) = eventInfo->actualInteractionsPerCrossing();
300
301 // variables for calculation of delta Z asymmetry and delta d asymmetry
302 float z_asym = 0;
303 float sumDZ = 0;
304 float deltaZ = 0;
305 float modsumDZ = 0;
306 float weighted_sumDZ = 0;
307 float weighted_deltaZ = 0;
308 float weighted_modsumDZ = 0;
309 float weighted_z_asym = 0;
310
311 // make vector
312 std::vector<float> track_deltaZ;
313
314 for (size_t i = 0; i < vertex->nTrackParticles(); i++) {
315
316 const xAOD::TrackParticle *trackTmp = vertex->trackParticle(i);
317
318 if(!trackTmp) continue;
319
320 deltaZ = trackTmp->z0() + trackTmp->vz() - vertex->z();
321 track_deltaZ.push_back(deltaZ);
322 // get the track weight for each track to get the deltaZ/trk_weight
323 float trk_weight = vertex->trackWeight(i);
324 weighted_deltaZ = deltaZ * trk_weight;
325 // sum of delta z
326 sumDZ += deltaZ;
327 modsumDZ += std::abs(deltaZ);
328 weighted_sumDZ += weighted_deltaZ;
329 weighted_modsumDZ += std::abs(weighted_deltaZ);
330 } // end loop over tracks
331
332 if (modsumDZ > 0) {
333 z_asym = sumDZ / modsumDZ;
334 }
335 if (weighted_modsumDZ > 0) {
336 weighted_z_asym = weighted_sumDZ / weighted_modsumDZ;
337 }
338
339 const float number_tracks = track_deltaZ.size(); // get number of tracks
340 const float mean_Dz =
341 number_tracks > 0 ? sumDZ / number_tracks : 0.F; // calculate average
342
343 float z_skew = 0; // skewness of DeltaZ asymmetry
344 float z_kurt = 0; // Kurtosis of DeltaZ asymmetry
345 float z_var = 0; // variance of DeltaZ
346
347 for (auto i : track_deltaZ)
348 {
349 float z_zbar = (i - mean_Dz);
350 z_var += std::pow(z_zbar, 2);
351 z_skew += std::pow(z_zbar, 3);
352 z_kurt += std::pow(z_zbar, 4);
353 }
354 if (number_tracks > 1 && z_var > 0) {
355 z_var /= (number_tracks - 1);
356 float z_sd = std::sqrt(z_var);
357 const float skew_denom = (number_tracks - 1) * std::pow(z_sd, 3);
358 const float kurt_denom = (number_tracks - 1) * std::pow(z_sd, 4);
359 if (std::isfinite(skew_denom) && skew_denom != 0.F) {
360 z_skew /= skew_denom;
361 } else {
362 z_skew = 0.F;
363 }
364 if (std::isfinite(kurt_denom) && kurt_denom != 0.F) {
365 z_kurt /= kurt_denom;
366 } else {
367 z_kurt = 0.F;
368 }
369 }
370 else
371 {
372 ATH_MSG_WARNING("z momenta are NaN: setting to zero");
373 z_skew = 0.;
374 z_kurt = 0.;
375 }
376
377 dec_ntrk(*vertex) = number_tracks;
378
379 if(!dec_sumPt.isAvailable()){
380 dec_sumPt(*vertex) = xAOD::PVHelpers::getVertexSumPt(vertex, 1, false);
381 }
382 const float numberDoF = vertex->numberDoF();
383 dec_chi2Over_ndf(*vertex) =
384 numberDoF > 0.F ? vertex->chiSquared() / numberDoF : 0.F;
385 dec_z_asym(*vertex) = z_asym;
386 dec_weighted_z_asym(*vertex) = weighted_z_asym;
387 dec_z_kurt(*vertex) = z_kurt;
388 dec_z_skew(*vertex) = z_skew;
389
390 if (acc_deltaZ.isAvailable() && photonsIn->size() > 0 ) {
391 //protect against rare NaNs before assigning decorator: setting to 0 (-999 cause NaNs)
392 if (!std::isfinite(acc_deltaZ(*vertex))) {
393 ATH_MSG_WARNING("photon deltaPhi is NaN: setting to -1!");
394 dec_photon_deltaz(*vertex) = -1;
395 }
396 else{
397 dec_photon_deltaz(*vertex) = acc_deltaZ(*vertex);
398 }
399 }
400 else{
401 dec_photon_deltaz(*vertex) = -1;
402 }
403 if (acc_deltaPhi.isAvailable() && photonsIn->size() > 0) {
404
405 if (!std::isfinite(acc_deltaPhi(*vertex))) {
406 ATH_MSG_WARNING("photon deltaPhi is NaN: setting to 0!");
407 dec_photon_deltaPhi(*vertex) = -1;
408 }
409 else{
410 dec_photon_deltaPhi(*vertex) = acc_deltaPhi(*vertex);
411 }
412 }
413 else{
414 dec_photon_deltaPhi(*vertex) = -1;
415 }
416
417 // associate objects to vertices
418 std::vector<ElementLink<xAOD::ElectronContainer>> electronLinks;
419 for(const xAOD::Electron* electron : *electronsIn){
420 const auto *id_trk = xAOD::EgammaHelpers::getOriginalTrackParticle(electron);
421 if(!id_trk) continue;
422 auto eleVertex = m_trkVtxAssociationTool->getUniqueMatchVertexLink(*id_trk, *vertices);
423 if(!eleVertex) continue;
425 if(*eleVertex == vertex){
426 elLink.setElement(electron);
427 elLink.setStorableObject(*electronsIn.ptr(), true);
428 electronLinks.push_back(elLink);
429 }
430 }
431 dec_electronLinks(*vertex) = electronLinks;
432
433 std::vector<ElementLink<xAOD::PhotonContainer>> photonLinks;
434 for(const xAOD::Photon* photon : *photonsIn){
436 phLink.setElement(photon);
437 phLink.setStorableObject(*photonsIn.ptr(), true);
438 photonLinks.push_back(phLink);
439 }
440 dec_photonLinks(*vertex) = photonLinks;
441
442 // multi-photon link
443 std::vector<ElementLink<xAOD::CompositeParticleContainer>> mpLinks;
444 if (haveMP && vertex == bestVtxForMP)
445 {
446 mpLinks.push_back(mpLink);
447 }
448 dec_multiPhotonLinks(*vertex) = mpLinks;
449
450 // for jets, use prefilled map
451 dec_jetLinks(*vertex) = jetsInVertex[vertex];
452
453 std::vector<ElementLink<xAOD::MuonContainer>> muonLinks;
454 for(const xAOD::Muon* muon : *muonsIn){
455 const auto *tp = muon->trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
456 if(!tp) continue;
457 try{
458 auto muonVertex = m_trkVtxAssociationTool->getUniqueMatchVertexLink(*tp, *vertices);
459 if(!muonVertex) continue;
461 if(*muonVertex == vertex){
462 muonLink.setElement(muon);
463 muonLink.setStorableObject(*muonsIn.ptr(), true);
464 muonLinks.push_back(muonLink);
465 }
466 }catch(...) {
467 ATH_MSG_DEBUG("Skipping muon as the track is not associated to any PV ");
468 ATH_MSG_DEBUG("Muon pT, eta = " << muon->pt() << " " << muon->eta());
469 }
470
471 }
472 dec_muonLinks(*vertex) = muonLinks;
473
474 // Finally, decorate the vertices with the GNN score
475 m_gnnTool->decorate(*vertex);
476 }
477
478 return StatusCode::SUCCESS;
479 }
480
481} // namespace InDetGNNHardScatterSelection
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Handle class for reading a decoration on an object.
Handle class for adding a decoration to an object.
Base class for elements of a container that can have aux data.
Property holding a SG store/key/clid from which a WriteHandle is made.
#define z
AthHistogramAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor with parameters:
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_mDecor_photon_deltaPhi
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_mDecor_z_skew
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_muonLinksKey
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_mDecor_sumPt
SG::WriteHandleKey< xAOD::CompositeParticleContainer > m_multiPhotonsOutKey
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_mDecor_chi2Over_ndf
SG::ReadDecorHandleKey< xAOD::VertexContainer > m_deltaZKey
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_photonLinksKey
SG::ReadHandleKey< xAOD::MuonContainer > m_muonsInKey
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_mDecor_weighted_z_asym
SG::ReadDecorHandleKey< xAOD::PhotonContainer > m_zCommonKey
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_electronLinksKey
SG::ReadHandleKey< xAOD::EventInfo > m_eventInKey
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_mDecor_ntrk
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_mDecor_actualInterPerXing
ToolHandle< CP::TrackVertexAssociationTool > m_trkVtxAssociationTool
SG::ReadDecorHandleKey< xAOD::VertexContainer > m_deltaPhiKey
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_mDecor_weighted_z_kurt
SG::ReadDecorHandleKey< xAOD::PhotonContainer > m_zCommonErrorKey
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_mDecor_photon_deltaz
SG::ReadDecorHandleKey< xAOD::PhotonContainer > m_caloPointingZKey
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_multiPhotonLinksKey
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_mDecor_z_asym
SG::ReadHandleKey< xAOD::VertexContainer > m_vertexInKey
SG::ReadHandleKey< xAOD::PhotonContainer > m_photonsInKey
SG::WriteDecorHandleKey< xAOD::VertexContainer > m_jetLinksKey
SG::ReadHandleKey< xAOD::ElectronContainer > m_electronsInKey
SG::ReadHandleKey< xAOD::JetContainer > m_jetsInKey
Handle class for reading a decoration on an object.
bool isAvailable()
Test to see if this variable exists in the store, for the referenced object.
const_pointer_type ptr()
Dereference the pointer.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
Handle class for adding a decoration to an object.
bool isAvailable()
Test to see if this variable exists in the store, for the referenced object.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
float z0() const
Returns the parameter.
float vz() const
The z origin for the parameters.
float z() const
Returns the z position.
const xAOD::TrackParticle * getOriginalTrackParticle(const xAOD::Electron *el)
Helper function for getting the "Original" Track Particle (i.e before GSF) via the electron.
float getVertexSumPt(const xAOD::Vertex *vertex, int power=1, bool useAux=true)
Loop over track particles associated with vertex and return scalar sum of pT^power in GeV (from auxda...
@ NoVtx
Dummy vertex. TrackParticle was not used in vertex fit.
Jet_v1 Jet
Definition of the current "jet version".
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Vertex_v1 Vertex
Define the latest version of the vertex class.
CompositeParticle_v1 CompositeParticle
Define the latest version of the composite particle class.
Muon_v1 Muon
Reference the current persistent version:
Photon_v1 Photon
Definition of the current "egamma version".
Electron_v1 Electron
Definition of the current "egamma version".