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