ATLAS Offline Software
Loading...
Searching...
No Matches
DecoratePLIT.cxx
Go to the documentation of this file.
1// This is -*- c++ -*-
2
3/*
4 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
5*/
6
10
11
12namespace Prompt {
13
14 DecoratePLIT::DecoratePLIT(const std::string &name, ISvcLocator *pSvcLocator)
15 : AthReentrantAlgorithm(name, pSvcLocator)
16 {}
17
19 ATH_MSG_DEBUG("Initializing DecoratePLIT " << name() );
20 ATH_MSG_DEBUG("m_leptonsName = " << m_leptonsName);
21
22 ATH_MSG_DEBUG("Initializing " << m_electronsKey);
23 ATH_MSG_DEBUG("Initializing " << m_muonsKey);
24 ATH_MSG_DEBUG("Initializing " << m_trackjetsKey);
25 ATH_MSG_DEBUG("Initializing " << m_tracksKey);
26 ATH_MSG_DEBUG("Initializing " << m_caloclustersKey);
27
28 ATH_CHECK(m_electronsKey.initialize(m_leptonsName == "Electrons"));
29 ATH_CHECK(m_muonsKey.initialize(m_leptonsName == "Muons"));
30 ATH_CHECK(m_trackjetsKey.initialize());
31 ATH_CHECK(m_tracksKey.initialize());
32 ATH_CHECK(m_caloclustersKey.initialize());
33
34 // initialise accessors
36
37 // Load and initialize the neural network model from the given file path.
38 if(m_leptonsName == "Electrons") {
39 std::string fullPathToOnnxFile = PathResolverFindCalibFile(m_configPath.value() + m_configFileVersion.value());
40 m_saltModel = std::make_shared<FlavorTagInference::SaltModel>(fullPathToOnnxFile);
41
42 std::string fullPathToOnnxFile_endcap = PathResolverFindCalibFile(m_configPath.value() + m_configFileVersion_endcap.value());
43 m_saltModel_endcap = std::make_shared<FlavorTagInference::SaltModel>(fullPathToOnnxFile_endcap);
44
47
48 // set up decorators using a dummy query of the onnx model
50
51 std::vector<float> elec_feat(m_num_lepton_features, 0.);
52 std::vector<int64_t> elec_feat_dim = {1, static_cast<int64_t>(elec_feat.size())};
53 FlavorTagInference::Inputs elec_info (elec_feat, elec_feat_dim);
54 gnn_input.insert({"jet_features", elec_info}); // need to use the "jet_features" keyword as we are borrowing flavour tagging code
55
56 std::vector<float> track_feat(m_num_track_features, 0.);
57 std::vector<int64_t> track_feat_dim = {1, m_num_track_features};
58 FlavorTagInference::Inputs track_info(track_feat, track_feat_dim);
59 gnn_input.insert({"track_features", track_info});
60
61 auto [out_f, out_vc, out_vf] = m_saltModel->runInference(gnn_input); // the dummy evaluation
62
63 std::vector<std::string> output_names;
64 for (auto& singlefloat : out_f){
65 ATH_MSG_DEBUG("Found Electron output: "+singlefloat.first);
66 std::string outname = m_electronsKey.key()+"." + m_TaggerName + "_" + (singlefloat.first.find("elxpromp") != std::string::npos ? "PLITel_pelxpromp" : "PLITel_pnpxall" );
67 ATH_MSG_DEBUG("Decorating as "+outname);
68 output_names.push_back(outname);
69 }
70 ATH_CHECK(m_dec_el_plit_output.assign(output_names));
71 ATH_CHECK(m_dec_el_plit_output.initialize());
72 }
73 else if (m_leptonsName == "Muons") {
74 std::string fullPathToOnnxFile = PathResolverFindCalibFile(m_configPath.value() + m_configFileVersion.value());
75 m_saltModel = std::make_shared<FlavorTagInference::SaltModel>(fullPathToOnnxFile);
76
79
80 // set up decorators using a dummy query of the onnx model
82
83 std::vector<float> muon_feat(m_num_lepton_features, 0.);
84 std::vector<int64_t> muon_feat_dim = {1, static_cast<int64_t>(muon_feat.size())};
85 FlavorTagInference::Inputs muon_info (muon_feat, muon_feat_dim);
86 gnn_input.insert({"jet_features", muon_info}); // need to use the "jet_features" keyword as we are borrowing flavour tagging code
87
88 std::vector<float> track_feat(m_num_track_features, 0.);
89 std::vector<int64_t> track_feat_dim = {1, m_num_track_features};
90 FlavorTagInference::Inputs track_info(track_feat, track_feat_dim);
91 gnn_input.insert({"track_features", track_info});
92
93 auto [out_f, out_vc, out_vf] = m_saltModel->runInference(gnn_input); // the dummy evaluation
94
95 std::vector<std::string> output_names;
96 for (auto& singlefloat : out_f){
97 ATH_MSG_DEBUG("Found Muon output: "+singlefloat.first);
98 std::string outname = m_muonsKey.key()+"." + m_TaggerName + "_" + (singlefloat.first.find("muxpromp") != std::string::npos ? "TPLTmu_pmuxpromp" : "TPLTmu_pnpxall" );
99 ATH_MSG_DEBUG("Decorating as "+outname);
100 output_names.push_back(outname);
101 }
102 ATH_CHECK(m_dec_mu_plit_output.assign(output_names));
103 ATH_CHECK(m_dec_mu_plit_output.initialize());
104 }
105 else {
106 ATH_MSG_ERROR(" ==> topology is not recognised! aborting.");
107 return StatusCode::FAILURE;
108 }
109
110 ATH_MSG_INFO("DecoratePLIT " << name() << " initialization done." );
111
112 return StatusCode::SUCCESS;
113 }
114
115 StatusCode DecoratePLIT::execute(const EventContext& ctx) const {
118
119 // Define decorators
124
125 // Make sure the decorations are filled for every track
126 for (const xAOD::TrackParticle* track : *tracks) {
127 dec_trk_dr_lepton(*track) = -999.0;
128 dec_trk_dr_leptontrack(*track) = -999.0;
129 dec_trk_electron_track(*track) = static_cast<char>(false);
130 dec_trk_muon_track(*track) = static_cast<char>(false);
131 }
132
133 if (!m_electronsKey.empty()) {
134 // prepare decorators
135 // ------------------
136 std::vector<SG::WriteDecorHandle<xAOD::ElectronContainer, float>> dec_el_plit_output;
137 for (const auto& wdhk: m_dec_el_plit_output) {
138 dec_el_plit_output.emplace_back(wdhk, ctx);
139 }
141 for (const xAOD::Electron* elec : *electrons) {
142 if (!predictElec(dec_trk_dr_lepton, dec_trk_dr_leptontrack, dec_trk_electron_track, dec_trk_muon_track,
143 *elec, *tracks, *caloclusters, dec_el_plit_output, ctx)) {
144 ATH_MSG_ERROR("DecoratePLIT::execute - failed to predict electron");
145 return StatusCode::FAILURE;
146 }
147 }
148 } else if (!m_muonsKey.empty()) {
149 // prepare decorators
150 // ------------------
151 std::vector<SG::WriteDecorHandle<xAOD::MuonContainer, float>> dec_mu_plit_output;
152 for (const auto& wdhk: m_dec_mu_plit_output) {
153 dec_mu_plit_output.emplace_back(wdhk, ctx);
154 }
156 for (const xAOD::Muon* muon : *muons) {
157 if (!predictMuon(dec_trk_dr_lepton, dec_trk_dr_leptontrack, dec_trk_electron_track, dec_trk_muon_track,
158 *muon, *tracks, dec_mu_plit_output, ctx)) {
159 ATH_MSG_ERROR("DecoratePLIT::execute - failed to predict muon");
160 return StatusCode::FAILURE;
161 }
162 }
163 }
164
165 return StatusCode::SUCCESS;
166 }
167
169
170 ATH_CHECK(m_acc_mu_ptvarcone30TTVA.initialize(!m_muonsKey.empty()));
171 ATH_CHECK(m_acc_mu_topoetcone30.initialize(!m_muonsKey.empty()));
172
173 ATH_CHECK(m_acc_el_ptvarcone30.initialize(!m_electronsKey.empty()));
174 ATH_CHECK(m_acc_el_topoetcone30.initialize(!m_electronsKey.empty()));
175
176 ATH_CHECK(m_acc_trk_dr_lepton.initialize());
178 ATH_CHECK(m_acc_trk_d0.initialize());
179 ATH_CHECK(m_acc_trk_z0SinTheta.initialize());
182 ATH_CHECK(m_acc_trk_muon_track.initialize());
184
185 ATH_CHECK(m_dec_trk_dr_lepton.initialize());
187 ATH_CHECK(m_dec_trk_muon_track.initialize());
189
194
195 return StatusCode::SUCCESS;
196
197 }
198
204 const xAOD::Muon &muon,
205 const xAOD::TrackParticleContainer &tracks,
206 std::vector<SG::WriteDecorHandle<xAOD::MuonContainer, float>> &dec_mu_plit_output,
207 const EventContext& ctx) const {
208 // set up accessors
209 // ---------------
212
220
221 // prepare input
222 // -------------
224
225 // collect muon features
226 float muon_pt = muon.pt();
227 float muon_eta = muon.eta();
228 float muon_phi = muon.phi();
229
230 float muon_ptvarcone30TTVARel = acc_ptvarcone30TTVA(muon) / muon_pt;
231 float muon_topoetcone30Rel = acc_topoetcone30(muon) / muon_pt;
232
233 float muon_caloClusterERel = -99;
234 const xAOD::CaloCluster* cluster = muon.cluster();
235 if (cluster) {
236 float energyloss = 0;
237 if (!muon.parameter(energyloss,xAOD::Muon::ParamDef::EnergyLoss)) {
238 ATH_MSG_WARNING("DecoratePLIT::execute - failed to retrieve energy loss");
239 return StatusCode::FAILURE;
240 }
241 float calE = cluster->calE();
242 // TODO: in future trainings, we need to prevent negative energy loss values
243 // keeping it as is for now, since latest trainings have been done without this check
244 // only protecting against zero energy loss
245 if (std::abs(energyloss) != 0)
246 muon_caloClusterERel = calE / energyloss;
247 }
248
249 // package muon features for inference
250 std::vector<float> muon_feat = {
251 muon_pt,
252 muon_eta,
253 muon_phi,
254 muon_ptvarcone30TTVARel,
255 muon_topoetcone30Rel,
256 muon_caloClusterERel};
257 std::vector<int64_t> muon_feat_dim = {1, static_cast<int64_t>(muon_feat.size())};
258
259 // need to use the "jet_features" keyword as we are borrowing flavour tagging code
260 FlavorTagInference::Inputs muon_info (muon_feat, muon_feat_dim);
261 gnn_input.insert({"jet_features", muon_info});
262
263 // decorate and fill track particles around the muon
264 const xAOD::TrackParticle *muonTrack = muon.trackParticle(xAOD::Muon::TrackParticleType::Primary);
265 std::vector<const xAOD::IParticle *> parts;
266
267 if(!fillParticles(dec_trk_dr_lepton, dec_trk_dr_leptontrack, dec_trk_electron_track, dec_trk_muon_track,
268 parts, muon, muonTrack, tracks, ctx)) {
269 ATH_MSG_ERROR("DecoratePLIT::execute - failed to fill particles");
270 return StatusCode::FAILURE;
271 }
272
273 // extract track features from track particles
274 std::vector<float> track_feat;
275 track_feat.reserve(parts.size() * static_cast<int64_t>(muon_feat.size()));
276
277 // loop over parts and fill track_feat vector
278 for (const xAOD::IParticle *part: parts) {
279 const xAOD::TrackParticle *track = dynamic_cast<const xAOD::TrackParticle*>(part);
280
281 // deta_lepton
282 float deta_lepton = track->p4().Eta() - muon.eta();
283 // dphi_lepton
284 float dphi_lepton = track->p4().DeltaPhi(muon.p4());
285 // qOverP
286 float qoverp = track->qOverP();
287 // btagIp_d0
288 float d0 = acc_d0(*track);
289 // btagIp_z0SinTheta
290 float z0SinTheta = acc_z0SinTheta(*track);
291 // btagIp_d0Uncertainty
292 float d0Uncertainty = acc_d0Uncertainty(*track);
293 // btagIp_z0SinThetaUncertainty
294 float z0SinThetaUncertainty = acc_z0SinThetaUncertainty(*track);
295 // btagIp_d0_significance
296 float d0_significance = -99;
297 if (abs(d0Uncertainty) > 0) d0_significance = d0 / d0Uncertainty;
298 // btagIp_z0SinTheta_significance
299 float z0SinTheta_significance = -99;
300 if (std::abs(z0SinThetaUncertainty) > 0) z0SinTheta_significance = z0SinTheta / z0SinThetaUncertainty;
301 // numberOfPixelHits
302 uint8_t pix_hits = 0;
303 if(!track->summaryValue(pix_hits,xAOD::numberOfPixelHits)){
304 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfPixelHits");
305 return StatusCode::FAILURE;
306 }
307 // numberOfInnermostPixelLayerHits
308 uint8_t pix_innermosthits = 0;
309 if(!track->summaryValue(pix_innermosthits,xAOD::numberOfInnermostPixelLayerHits)){
310 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfInnermostPixelLayerHits");
311 return StatusCode::FAILURE;
312 }
313 // numberOfNextToInnermostPixelLayerHits
314 uint8_t pix_nextinnermosthits = 0;
315 if(!track->summaryValue(pix_nextinnermosthits,xAOD::numberOfNextToInnermostPixelLayerHits)){
316 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfNextToInnermostPixelLayerHits");
317 return StatusCode::FAILURE;
318 }
319 // numberOfInnermostPixelLayerSharedHits
320 uint8_t pix_innermostsharedhits = 0;
321 if(!track->summaryValue(pix_innermostsharedhits,xAOD::numberOfInnermostPixelLayerSharedHits)){
322 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfInnermostPixelLayerSharedHits");
323 return StatusCode::FAILURE;
324 }
325 // numberOfInnermostPixelLayerSplitHits
326 uint8_t pix_innermostsplithits = 0;
327 if(!track->summaryValue(pix_innermostsplithits,xAOD::numberOfInnermostPixelLayerSplitHits)){
328 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfInnermostPixelLayerSplitHits");
329 return StatusCode::FAILURE;
330 }
331 // numberOfPixelSharedHits
332 uint8_t pix_shared = 0;
333 if(!track->summaryValue(pix_shared,xAOD::numberOfPixelSharedHits)){
334 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfPixelSharedHits");
335 return StatusCode::FAILURE;
336 }
337 // numberOfPixelSplitHits
338 uint8_t pix_split = 0;
339 if(!track->summaryValue(pix_split,xAOD::numberOfPixelSplitHits)){
340 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfPixelSplitHits");
341 return StatusCode::FAILURE;
342 }
343 // numberOfSCTHits
344 uint8_t sct_hits = 0;
345 if(!track->summaryValue(sct_hits,xAOD::numberOfSCTHits)){
346 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfSCTHits");
347 return StatusCode::FAILURE;
348 }
349 // numberOfSCTSharedHits
350 uint8_t sct_shared = 0;
351 if(!track->summaryValue(sct_shared,xAOD::numberOfSCTSharedHits)){
352 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfSCTSharedHits");
353 return StatusCode::FAILURE;
354 }
355 // muon_track
356 char muon_track = acc_muon_track(*track);
357
358 track_feat.push_back(deta_lepton);
359 track_feat.push_back(dphi_lepton);
360 track_feat.push_back(qoverp);
361 track_feat.push_back(d0);
362 track_feat.push_back(z0SinTheta);
363 //track_feat.push_back(d0Uncertainty); // removed in the latest trainings, redundant
364 //track_feat.push_back(z0SinThetaUncertainty); // removed in the latest trainings, redundant
365 track_feat.push_back(d0_significance);
366 track_feat.push_back(z0SinTheta_significance);
367 track_feat.push_back(pix_hits);
368 track_feat.push_back(pix_innermosthits);
369 track_feat.push_back(pix_nextinnermosthits);
370 track_feat.push_back(pix_innermostsharedhits);
371 track_feat.push_back(pix_innermostsplithits);
372 track_feat.push_back(pix_shared);
373 track_feat.push_back(pix_split);
374 track_feat.push_back(sct_hits);
375 track_feat.push_back(sct_shared);
376 track_feat.push_back(muon_track);
377 }
378
379 // prepare track features for inference
380 int num_cnsts = parts.size();
381 std::vector<int64_t> track_feat_dim = {num_cnsts, m_num_track_features};
382
383 FlavorTagInference::Inputs track_info(track_feat, track_feat_dim);
384 gnn_input.insert({"track_features", track_info});
385
386 if (msgLvl(MSG::VERBOSE)) {
387 ATH_MSG_VERBOSE("gnn_input size = " << gnn_input.size());
388 for (auto& inp : gnn_input){
389 ATH_MSG_VERBOSE(" " + inp.first + " dim = ");
390 for (auto & dim: inp.second.second) {
391 ATH_MSG_VERBOSE(" " + std::to_string(dim));
392 }
393 ATH_MSG_VERBOSE(" " + inp.first + " content = ");
394 for (auto & con: inp.second.first) {
395 ATH_MSG_VERBOSE(" " + std::to_string(con));
396 }
397 }
398 }
399
400 // run inference
401 // -------------
402 auto [out_f, out_vc, out_vf] = m_saltModel->runInference(gnn_input);
403 if (msgLvl(MSG::VERBOSE)) {
404 ATH_MSG_VERBOSE("runInference done.");
405
406 ATH_MSG_VERBOSE("Output Float(s):");
407 for (auto& singlefloat : out_f){
408 ATH_MSG_VERBOSE(singlefloat.first + " = " << singlefloat.second);
409 }
410 ATH_MSG_VERBOSE("Output vector char(s):");
411 for (auto& vecchar : out_vc){
412 ATH_MSG_VERBOSE(vecchar.first + " = ");
413 for (auto& cc : vecchar.second){
414 ATH_MSG_VERBOSE(cc);
415 }
416 }
417 ATH_MSG_VERBOSE("Output vector float(s):");
418 for (auto& vecfloat : out_vf){
419 ATH_MSG_VERBOSE(vecfloat.first + " = ");
420 for (auto& ff : vecfloat.second){
421 ATH_MSG_VERBOSE(ff);
422 }
423 }
424 }
425 // filling the tagger scores
426 auto it_dec_mu_plit_output = dec_mu_plit_output.begin();
427 for (auto& singlefloat : out_f){
428 ATH_MSG_DEBUG("DecoratePLIT::execute - Muon output: " + singlefloat.first + " = " + std::to_string(singlefloat.second));
429 (*it_dec_mu_plit_output)(muon) = singlefloat.second;
430 ++it_dec_mu_plit_output;
431 }
432
433 return StatusCode::SUCCESS;
434 }
435
441 const xAOD::Electron &electron,
442 const xAOD::TrackParticleContainer &tracks,
443 const xAOD::CaloClusterContainer &caloclusters,
444 std::vector<SG::WriteDecorHandle<xAOD::ElectronContainer, float>> &dec_el_plit_output,
445 const EventContext& ctx) const {
446 // prepare input
447 // -------------
449
450 // accessors
451 // ---------
454
462
463 // collect electron features
464 float elec_pt = electron.pt();
465 float elec_eta = electron.eta();
466 float elec_phi = electron.phi();
467 float elec_ptvarcone30Rel = acc_ptvarcone30(electron) / elec_pt;
468 float elec_topoetcone30Rel = acc_topoetcone30(electron) / elec_pt;
469
470 // compute electron calorimeter cluster information
471 float elec_caloClusterSumEtRel = 0.0;
472 float sumCoreEt_large = 0.0;
473 if (electron.caloCluster()) {
474 float elec_calEta = electron.caloCluster()->eta();
475 float elec_calPhi = electron.caloCluster()->phi();
476
477 for (const xAOD::CaloCluster *cluster: caloclusters) {
478 float deta = elec_calEta - cluster->eta();
479 float dphi = TVector2::Phi_mpi_pi(elec_calPhi - cluster->phi());
480 float dr = std::sqrt(deta*deta + dphi*dphi);
481
482 if (dr < m_lepCalErelConeSize) {
483 sumCoreEt_large += cluster->pt();
484 }
485 }
486 }
487 elec_caloClusterSumEtRel = sumCoreEt_large / elec_pt;
488
489 // collect best matched GSF electron track kinematics
490 const xAOD::TrackParticle *electronTrack = nullptr;
491 const xAOD::TrackParticle *bestmatchedGSFElTrack = electron.trackParticle(0);
492 if (bestmatchedGSFElTrack) {
493 electronTrack = xAOD::EgammaHelpers::getOriginalTrackParticleFromGSF(bestmatchedGSFElTrack);
494 }
495
496 //float elec_pt_track = -99;
497 //float elec_eta_track = -99;
498 //float elec_phi_track = -99;
499 //if (electronTrack) {
500 // elec_pt_track = electronTrack->pt();
501 // elec_eta_track = electronTrack->eta();
502 // elec_phi_track = electronTrack->phi();
503 //}
504
505 std::vector<float> electron_feat = {
506 elec_pt,
507 elec_eta,
508 elec_phi,
509 elec_ptvarcone30Rel,
510 elec_topoetcone30Rel,
511 elec_caloClusterSumEtRel};
512 std::vector<int64_t> electron_feat_dim = {1, static_cast<int64_t>(electron_feat.size())};
513
514 // need to use the "jet_features" keyword as we are borrowing flavour tagging code
515 FlavorTagInference::Inputs electron_info (electron_feat, electron_feat_dim);
516 gnn_input.insert({"jet_features", electron_info});
517
518 // decorate and fill track particles around the electron
519 std::vector<const xAOD::IParticle *> parts;
520 if (!fillParticles(dec_trk_dr_lepton, dec_trk_dr_leptontrack, dec_trk_electron_track, dec_trk_muon_track,
521 parts, electron, electronTrack, tracks, ctx)) {
522 ATH_MSG_ERROR("DecoratePLIT::execute - failed to fill particles");
523 return StatusCode::FAILURE;
524 }
525
526 // collect track features from track particles
527 std::vector<float> track_feat;
528 track_feat.reserve(parts.size() * static_cast<int64_t>(electron_feat.size()));
529
530 for (const xAOD::IParticle *part: parts) {
531 const xAOD::TrackParticle *track = dynamic_cast<const xAOD::TrackParticle*>(part);
532 if (!track) {
533 ATH_MSG_ERROR("DecoratePLIT::execute - null track pointer");
534 return StatusCode::FAILURE;
535 }
536
537 // dr_lepton
538 // float dr_lepton = acc_dr_lepton(*track);
539 // deta_lepton
540 float deta_lepton = track->p4().Eta() - electron.eta();
541 // dphi_lepton
542 float dphi_lepton = track->p4().DeltaPhi(electron.p4());
543 // qOverP
544 float qoverp = track->qOverP();
545 // btagIp_d0
546 float d0 = acc_d0(*track);
547 // btagIp_z0SinTheta
548 float z0SinTheta = acc_z0SinTheta(*track);
549 // btagIp_d0_significance
550 float d0Uncertainty = acc_d0Uncertainty(*track);
551 float d0_significance = -99;
552 if (std::abs(d0Uncertainty) > 0) d0_significance = d0 / d0Uncertainty;
553 // btagIp_z0SinTheta_significance
554 float z0SinThetaUncertainty = acc_z0SinThetaUncertainty(*track);
555 float z0SinTheta_significance = -99;
556 if (std::abs(z0SinThetaUncertainty) > 0) z0SinTheta_significance = z0SinTheta / z0SinThetaUncertainty;
557 // numberOfInnermostPixelLayerHits
558 uint8_t pix_innermosthits = 0;
559 if(!track->summaryValue(pix_innermosthits,xAOD::numberOfInnermostPixelLayerHits)){
560 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfInnermostPixelLayerHits");
561 return StatusCode::FAILURE;
562 }
563 // numberOfNextToInnermostPixelLayerHits
564 uint8_t pix_nextinnermosthits = 0;
565 if(!track->summaryValue(pix_nextinnermosthits,xAOD::numberOfNextToInnermostPixelLayerHits)){
566 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfNextToInnermostPixelLayerHits");
567 return StatusCode::FAILURE;
568 }
569 // numberOfInnermostPixelLayerSharedHits
570 uint8_t pix_innermostsharedhits = 0;
571 if(!track->summaryValue(pix_innermostsharedhits,xAOD::numberOfInnermostPixelLayerSharedHits)){
572 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfInnermostPixelLayerSharedHits");
573 return StatusCode::FAILURE;
574 }
575 // numberOfInnermostPixelLayerSplitHits
576 uint8_t pix_innermostsplithits = 0;
577 if(!track->summaryValue(pix_innermostsplithits,xAOD::numberOfInnermostPixelLayerSplitHits)){
578 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfInnermostPixelLayerSplitHits");
579 return StatusCode::FAILURE;
580 }
581 // numberOfPixelHits
582 uint8_t pix_hits = 0;
583 if(!track->summaryValue(pix_hits,xAOD::numberOfPixelHits)){
584 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfPixelHits");
585 return StatusCode::FAILURE;
586 }
587 // numberOfPixelSharedHits
588 uint8_t pix_shared = 0;
589 if(!track->summaryValue(pix_shared,xAOD::numberOfPixelSharedHits)){
590 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfPixelSharedHits");
591 return StatusCode::FAILURE;
592 }
593 // numberOfPixelSplitHits
594 uint8_t pix_split = 0;
595 if(!track->summaryValue(pix_split,xAOD::numberOfPixelSplitHits)){
596 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfPixelSplitHits");
597 return StatusCode::FAILURE;
598 }
599 // numberOfSCTHits
600 uint8_t sct_hits = 0;
601 if(!track->summaryValue(sct_hits,xAOD::numberOfSCTHits)){
602 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfSCTHits");
603 return StatusCode::FAILURE;
604 }
605 // numberOfSCTSharedHits
606 uint8_t sct_shared = 0;
607 if(!track->summaryValue(sct_shared,xAOD::numberOfSCTSharedHits)){
608 ATH_MSG_ERROR("DecoratePLIT::execute - failed to retrieve xAOD::numberOfSCTSharedHits");
609 return StatusCode::FAILURE;
610 }
611 // electron_track
612 char electron_track = acc_electron_track(*track);
613
614
615 //track_feat.push_back(dr_lepton); // removed in the latest trainings, redundan
616 track_feat.push_back(deta_lepton);
617 track_feat.push_back(dphi_lepton);
618 track_feat.push_back(qoverp);
619 track_feat.push_back(d0);
620 track_feat.push_back(z0SinTheta);
621 track_feat.push_back(d0_significance);
622 track_feat.push_back(z0SinTheta_significance);
623 track_feat.push_back(pix_innermosthits);
624 track_feat.push_back(pix_nextinnermosthits);
625 track_feat.push_back(pix_innermostsharedhits);
626 track_feat.push_back(pix_innermostsplithits);
627 track_feat.push_back(pix_hits);
628 track_feat.push_back(pix_shared);
629 track_feat.push_back(pix_split);
630 track_feat.push_back(sct_hits);
631 track_feat.push_back(sct_shared);
632 track_feat.push_back(electron_track);
633 }
634
635 // prepare track features for inference
636 int num_cnsts = parts.size();
637 std::vector<int64_t> track_feat_dim = {num_cnsts, m_num_track_features};
638
639 FlavorTagInference::Inputs track_info (track_feat, track_feat_dim);
640 gnn_input.insert({"track_features", track_info});
641
642 if (msgLvl(MSG::VERBOSE)) {
643 ATH_MSG_VERBOSE("gnn_input size = " << gnn_input.size());
644 for (auto& inp : gnn_input){
645 ATH_MSG_VERBOSE(" " + inp.first + " dim = ");
646 for (auto & dim: inp.second.second) {
647 ATH_MSG_VERBOSE(" " + std::to_string(dim));
648 }
649 ATH_MSG_VERBOSE(" " + inp.first + " content = ");
650 for (auto & con: inp.second.first) {
651 ATH_MSG_VERBOSE(" " + std::to_string(con));
652 }
653 }
654 }
655
656 // run inference
657 // -------------
658 // use different model for endcap electrons
659 auto [out_f, out_vc, out_vf] = (std::abs(elec_eta) < 1.37) ? m_saltModel->runInference(gnn_input) : m_saltModel_endcap->runInference(gnn_input);
660 if (msgLvl(MSG::VERBOSE)) {
661 ATH_MSG_VERBOSE("runInference done.");
662
663 ATH_MSG_VERBOSE("Output Float(s):");
664 for (auto& singlefloat : out_f){
665 ATH_MSG_VERBOSE(singlefloat.first + " = " << singlefloat.second);
666 }
667 ATH_MSG_VERBOSE("Output vector char(s):");
668 for (auto& vecchar : out_vc){
669 ATH_MSG_VERBOSE(vecchar.first + " = ");
670 for (auto& cc : vecchar.second){
671 ATH_MSG_VERBOSE(cc);
672 }
673 }
674 ATH_MSG_VERBOSE("Output vector float(s):");
675 for (auto& vecfloat : out_vf){
676 ATH_MSG_VERBOSE(vecfloat.first + " = ");
677 for (auto& ff : vecfloat.second){
678 ATH_MSG_VERBOSE(ff);
679 }
680 }
681 }
682 // filling the tagger scores
683 auto it_dec_el_plit_output = dec_el_plit_output.begin();
684 for (auto& singlefloat : out_f){
685 ATH_MSG_DEBUG("DecoratePLIT::execute - Electron output: " + singlefloat.first + " = " + std::to_string(singlefloat.second));
686 (*it_dec_el_plit_output)(electron) = singlefloat.second;
687 ++it_dec_el_plit_output;
688 }
689
690 return StatusCode::SUCCESS;
691 }
692
693 bool DecoratePLIT::passed_r22tracking_cuts(const xAOD::TrackParticle& tp, const EventContext& ctx) const
694 {
695 // r22 default track selection for flavour tagging GN2 algorithm
696 constexpr float pt_minimum = 500; // MeV
697 constexpr float abs_eta_maximum = 2.5;
698 constexpr float d0_maximum = 3.5;
699 constexpr float z0_maximum= 5.0;
700 constexpr unsigned char si_hits_minimum = 8;
701 constexpr unsigned char si_shared_maximum = 1;
702 constexpr unsigned char si_holes_maximum = 2;
703 constexpr unsigned char pix_holes_maximum = 1;
704
705 // accessors
708
709 // get hit pixel info
710 uint8_t pix_shared = 0;
712 ATH_MSG_ERROR("DecoratePLIT::passed_r22tracking_cuts - failed to retrieve xAOD::numberOfPixelSharedHits");
713 return false;
714 }
715 uint8_t sct_shared = 0;
716 if(!tp.summaryValue(sct_shared,xAOD::numberOfSCTSharedHits)){
717 ATH_MSG_ERROR("DecoratePLIT::passed_r22tracking_cuts - failed to retrieve xAOD::numberOfSCTSharedHits");
718 return false;
719 }
720 uint8_t pix_hits = 0;
721 if(!tp.summaryValue(pix_hits,xAOD::numberOfPixelHits)){
722 ATH_MSG_ERROR("DecoratePLIT::passed_r22tracking_cuts - failed to retrieve xAOD::numberOfPixelHits");
723 return false;
724 }
725 uint8_t sct_hits = 0;
726 if(!tp.summaryValue(sct_hits,xAOD::numberOfSCTHits)){
727 ATH_MSG_ERROR("DecoratePLIT::passed_r22tracking_cuts - failed to retrieve xAOD::numberOfSCTHits");
728 return false;
729 }
730 uint8_t pix_dead = 0;
732 ATH_MSG_ERROR("DecoratePLIT::passed_r22tracking_cuts - failed to retrieve xAOD::numberOfPixelDeadSensors");
733 return false;
734 }
735 uint8_t sct_dead = 0;
737 ATH_MSG_ERROR("DecoratePLIT::passed_r22tracking_cuts - failed to retrieve xAOD::numberOfSCTDeadSensors");
738 return false;
739 }
740 uint8_t pix_holes = 0;
741 if(!tp.summaryValue(pix_holes,xAOD::numberOfPixelHoles)){
742 ATH_MSG_ERROR("DecoratePLIT::passed_r22tracking_cuts - failed to retrieve xAOD::numberOfPixelHoles");
743 return false;
744 }
745 uint8_t sct_holes = 0;
746 if(!tp.summaryValue(sct_holes,xAOD::numberOfSCTHoles)){
747 ATH_MSG_ERROR("DecoratePLIT::passed_r22tracking_cuts - failed to retrieve xAOD::numberOfSCTHoles");
748 return false;
749 }
750
751 if (std::abs(tp.eta()) > abs_eta_maximum)
752 return false;
753 double n_module_shared = (pix_shared + sct_shared / 2);
754 if (n_module_shared > si_shared_maximum)
755 return false;
756 if (tp.pt() <= pt_minimum)
757 return false;
758 if (std::isfinite(d0_maximum) &&
759 std::abs(acc_d0(tp)) >= d0_maximum)
760 return false;
761 if (std::isfinite(z0_maximum) &&
762 std::abs(acc_z0SinTheta(tp)) >= z0_maximum)
763 return false;
764 if (pix_hits + pix_dead + sct_hits + sct_dead < si_hits_minimum)
765 return false;
766 if ((pix_holes + sct_holes) > si_holes_maximum)
767 return false;
768 if (pix_holes > pix_holes_maximum)
769 return false;
770 return true;
771 }
772
778 std::vector<const xAOD::IParticle *> &parts,
779 const xAOD::IParticle &lepton,
780 const xAOD::TrackParticle *trackLep,
781 const xAOD::TrackParticleContainer &trackContainer,
782 const EventContext& ctx) const
783 {
784 // get lepton four momentum
785 const FourMom_t lepton_p4 = lepton.p4();
786
787 // Precompute tracks used for reconstruction
788 std::set<const xAOD::TrackParticle*> tracksUsedForElectron;
789 std::set<const xAOD::TrackParticle*> tracksUsedForMuon;
790 if (const auto* elec = dynamic_cast<const xAOD::Electron*>(&lepton)) {
791 tracksUsedForElectron = xAOD::EgammaHelpers::getTrackParticles(elec, true); // useBremAssoc = true
792 } else if (const auto* muon = dynamic_cast<const xAOD::Muon*>(&lepton)) {
793 if (muon->muonType() == xAOD::Muon::MuonType::Combined &&
794 muon->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle)) {
795 tracksUsedForMuon.insert(muon->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle)); // even if the primary track should be a combined track, we still use the id for the match
796 }
797 }
798
799 // Loop over tracks and store them
800 for (const xAOD::TrackParticle *track: trackContainer) {
801 if (!track) {
802 ATH_MSG_ERROR("DecoratePLIT::fillParticles - null track pointer");
803 return StatusCode::FAILURE;
804 }
805 // check if track passed selection
806 if (!passed_r22tracking_cuts(*track, ctx)) continue;
807
808 // decorate track
809 float dr_lepton = (lepton.p4().Pt() > 0.) ? track->p4().DeltaR(lepton.p4()) : -99;
810
811 // do not even waste time to decorate something which is not used
812 if (dr_lepton > m_maxLepTrackdR && m_maxLepTrackdR>=0) {continue;}
813
814 bool isUsedForElectron = tracksUsedForElectron.count(track);
815 bool isUsedForMuon = tracksUsedForMuon.count(track);
816
817 if (!decorateTrack(dec_trk_dr_lepton, dec_trk_dr_leptontrack, dec_trk_electron_track, dec_trk_muon_track,
818 *track, dr_lepton, isUsedForElectron, isUsedForMuon, trackLep)) {
819 ATH_MSG_ERROR("DecoratePLIT::fillParticles - failed to decorate track");
820 return StatusCode::FAILURE;
821 }
822
823 parts.push_back(track);
824 }
825
826 // Sort tracks by dR distance to lepton
827 auto SORT_TRACKLEP = [&lepton_p4](const xAOD::IParticle* a, const xAOD::IParticle* b) {
828 return a->p4().DeltaR(lepton_p4) < b->p4().DeltaR(lepton_p4);
829 };
830 std::sort(parts.begin(), parts.end(), SORT_TRACKLEP);
831
832 return StatusCode::SUCCESS;
833 }
834
840 const xAOD::TrackParticle& track,
841 float dr_lepton,
842 bool isUsedForElectron,
843 bool isUsedForMuon,
844 const xAOD::TrackParticle* trackLep) const
845 {
846 // Apply values to decorators
847 dec_trk_dr_lepton(track) = dr_lepton;
848 dec_trk_electron_track(track) = static_cast<char>(isUsedForElectron);
849 dec_trk_muon_track(track) = static_cast<char>(isUsedForMuon);
850
851 float dr_leptontrack = -99;
852 if (trackLep) {
853 if (trackLep->pt() > 0.) {
854 dr_leptontrack = track.p4().DeltaR(trackLep->p4());
855 }
856 }
857 dec_trk_dr_leptontrack(track) = dr_leptontrack;
858
859 return StatusCode::SUCCESS;
860 }
861}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_MSG_INFO(x,...)
Handle class for reading a decoration on an object.
static Double_t a
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
std::enable_if_t< std::is_void_v< std::result_of_t< decltype(&T::renounce)(T)> > &&!std::is_base_of_v< SG::VarHandleKeyArray, T > &&std::is_base_of_v< Gaudi::DataHandle, T >, void > renounce(T &h)
bool msgLvl(const MSG::Level lvl) const
An algorithm that can be simultaneously executed in multiple threads.
SG::ReadHandleKey< xAOD::JetContainer > m_trackjetsKey
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_dec_trk_dr_leptontrack
StatusCode initializeAccessors()
SG::ReadDecorHandleKey< xAOD::ElectronContainer > m_acc_el_ptvarcone30
Gaudi::Property< std::string > m_leptonsName
StatusCode decorateTrack(SG::WriteDecorHandle< xAOD::TrackParticleContainer, float > &dec_trk_dr_lepton, SG::WriteDecorHandle< xAOD::TrackParticleContainer, float > &dec_trk_dr_leptontrack, SG::WriteDecorHandle< xAOD::TrackParticleContainer, char > &dec_trk_electron_track, SG::WriteDecorHandle< xAOD::TrackParticleContainer, char > &dec_trk_muon_track, const xAOD::TrackParticle &track, float dr_lepton, bool isUsedForElectron, bool isUsedForMuon, const xAOD::TrackParticle *trackLep) const
SG::ReadDecorHandleKey< xAOD::TrackParticleContainer > m_acc_trk_d0
SG::ReadHandleKey< xAOD::CaloClusterContainer > m_caloclustersKey
std::shared_ptr< const FlavorTagInference::SaltModel > m_saltModel_endcap
SG::WriteDecorHandleKeyArray< xAOD::ElectronContainer > m_dec_el_plit_output
Gaudi::Property< float > m_lepCalErelConeSize
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_tracksKey
bool passed_r22tracking_cuts(const xAOD::TrackParticle &tp, const EventContext &ctx) const
SG::ReadDecorHandleKey< xAOD::MuonContainer > m_acc_mu_topoetcone30
SG::ReadDecorHandleKey< xAOD::MuonContainer > m_acc_mu_ptvarcone30TTVA
SG::ReadDecorHandleKey< xAOD::ElectronContainer > m_acc_el_topoetcone30
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_dec_trk_muon_track
Gaudi::Property< std::string > m_configPath
SG::ReadDecorHandleKey< xAOD::TrackParticleContainer > m_acc_trk_z0SinThetaUncertainty
SG::ReadDecorHandleKey< xAOD::TrackParticleContainer > m_acc_trk_d0Uncertainty
std::shared_ptr< const FlavorTagInference::SaltModel > m_saltModel
Gaudi::Property< float > m_maxLepTrackdR
StatusCode predictElec(SG::WriteDecorHandle< xAOD::TrackParticleContainer, float > &dec_trk_dr_lepton, SG::WriteDecorHandle< xAOD::TrackParticleContainer, float > &dec_trk_dr_leptontrack, SG::WriteDecorHandle< xAOD::TrackParticleContainer, char > &dec_trk_electron_track, SG::WriteDecorHandle< xAOD::TrackParticleContainer, char > &dec_trk_muon_track, const xAOD::Electron &electron, const xAOD::TrackParticleContainer &tracks, const xAOD::CaloClusterContainer &caloclusters, std::vector< SG::WriteDecorHandle< xAOD::ElectronContainer, float > > &dec_el_plit_output, const EventContext &ctx) const
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_dec_trk_dr_lepton
SG::WriteDecorHandleKeyArray< xAOD::MuonContainer > m_dec_mu_plit_output
DecoratePLIT(const std::string &name, ISvcLocator *pSvcLocator)
SG::ReadDecorHandleKey< xAOD::TrackParticleContainer > m_acc_trk_z0SinTheta
StatusCode fillParticles(SG::WriteDecorHandle< xAOD::TrackParticleContainer, float > &dec_trk_dr_lepton, SG::WriteDecorHandle< xAOD::TrackParticleContainer, float > &dec_trk_dr_leptontrack, SG::WriteDecorHandle< xAOD::TrackParticleContainer, char > &dec_trk_electron_track, SG::WriteDecorHandle< xAOD::TrackParticleContainer, char > &dec_trk_muon_track, std::vector< const xAOD::IParticle * > &parts, const xAOD::IParticle &lepton, const xAOD::TrackParticle *trackLep, const xAOD::TrackParticleContainer &trackContainer, const EventContext &ctx) const
SG::ReadDecorHandleKey< xAOD::TrackParticleContainer > m_acc_trk_dr_lepton
SG::ReadDecorHandleKey< xAOD::TrackParticleContainer > m_acc_trk_electron_track
SG::WriteDecorHandleKey< xAOD::TrackParticleContainer > m_dec_trk_electron_track
SG::ReadHandleKey< xAOD::ElectronContainer > m_electronsKey
StatusCode predictMuon(SG::WriteDecorHandle< xAOD::TrackParticleContainer, float > &dec_trk_dr_lepton, SG::WriteDecorHandle< xAOD::TrackParticleContainer, float > &dec_trk_dr_leptontrack, SG::WriteDecorHandle< xAOD::TrackParticleContainer, char > &dec_trk_electron_track, SG::WriteDecorHandle< xAOD::TrackParticleContainer, char > &dec_trk_muon_track, const xAOD::Muon &muon, const xAOD::TrackParticleContainer &tracks, std::vector< SG::WriteDecorHandle< xAOD::MuonContainer, float > > &dec_mu_plit_output, const EventContext &ctx) const
Gaudi::Property< std::string > m_TaggerName
Gaudi::Property< std::string > m_configFileVersion_endcap
SG::ReadDecorHandleKey< xAOD::TrackParticleContainer > m_acc_trk_dr_leptontrack
SG::ReadDecorHandleKey< xAOD::TrackParticleContainer > m_acc_trk_muon_track
virtual StatusCode execute(const EventContext &) const override
virtual StatusCode initialize() override
SG::ReadHandleKey< xAOD::MuonContainer > m_muonsKey
Gaudi::Property< std::string > m_configFileVersion
Handle class for reading a decoration on an object.
Handle class for adding a decoration to an object.
flt_t calE() const
Geet Energy in signal state CALIBRATED.
Class providing the definition of the 4-vector interface.
virtual FourMom_t p4() const =0
The full 4-momentum of the particle.
virtual FourMom_t p4() const override final
The full 4-momentum of the particle.
bool summaryValue(uint8_t &value, const SummaryType &information) const
Accessor for TrackSummary values.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
std::map< std::string, Inputs, std::less<> > InputMap
Definition ISaltModel.h:37
TLorentzVector FourMom_t
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
std::set< const xAOD::TrackParticle * > getTrackParticles(const xAOD::Egamma *eg, bool useBremAssoc=true, bool allParticles=true)
Return a list of all or only the best TrackParticle associated to the object.
const xAOD::TrackParticle * getOriginalTrackParticleFromGSF(const xAOD::TrackParticle *trkPar)
Helper function for getting the "Original" Track Particle (i.e before GSF) via the GSF Track Particle...
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
TrackParticleContainer_v1 TrackParticleContainer
Definition of the current "TrackParticle container version".
Muon_v1 Muon
Reference the current persistent version:
Definition Muon.h:13
CaloClusterContainer_v1 CaloClusterContainer
Define the latest version of the calorimeter cluster container.
@ numberOfPixelHoles
number of pixel layers on track with absence of hits [unit8_t].
@ numberOfPixelSplitHits
number of Pixel all-layer hits split by cluster splitting [unit8_t].
@ numberOfInnermostPixelLayerSharedHits
number of Pixel 0th layer barrel hits shared by several tracks.
@ numberOfNextToInnermostPixelLayerHits
these are the hits in the 1st pixel barrel layer
@ numberOfSCTDeadSensors
number of dead SCT sensors crossed [unit8_t].
@ numberOfInnermostPixelLayerSplitHits
number of Pixel 0th layer barrel hits split by cluster splitting
@ 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].
@ numberOfPixelSharedHits
number of Pixel all-layer hits shared by several tracks [unit8_t].
@ numberOfSCTSharedHits
number of SCT hits shared by several tracks [unit8_t].
@ numberOfPixelDeadSensors
number of dead pixel sensors crossed [unit8_t].
@ numberOfSCTHoles
number of SCT holes [unit8_t].
Electron_v1 Electron
Definition of the current "egamma version".
Definition Electron.h:17