ATLAS Offline Software
Loading...
Searching...
No Matches
TauDecayModeNNClassifier.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// local include(s)
7
8// helper function include(s)
10
11// standard library include(s)
12#include <array>
13#include <functional>
14#include <algorithm>
15#include <fstream>
16
17using PFOPtr = const xAOD::PFO *;
18using TrkPtr = const xAOD::TauTrack *;
22using ValueMap = std::map<std::string, double>;
23using VectorMap = std::map<std::string, std::vector<double>>;
24using InputMap = std::map<std::string, ValueMap>;
25using InputSequenceMap = std::map<std::string, VectorMap>;
26
28 : TauRecToolBase(name)
29{
30}
31
35
37{
38 ATH_MSG_INFO("Initializing TauDecayModeNNClassifier");
39
40 // find input JSON file
41 std::string weightFile = find_file(m_weightFile);
42 if (weightFile.empty())
43 {
44 ATH_MSG_ERROR("Could not find network weights: " << m_weightFile);
45 return StatusCode::FAILURE;
46 }
47 ATH_MSG_INFO("Loaded network configuration from: " << weightFile);
48
49 // load lwt graph configuration
50 std::ifstream inputFile(weightFile);
51 lwt::GraphConfig lwtGraphConfig;
52 try
53 {
54 lwtGraphConfig = lwt::parse_json_graph(inputFile);
55 }
56 catch (const std::logic_error &e)
57 {
58 ATH_MSG_ERROR("Error parsing network config: " << e.what());
59 return StatusCode::FAILURE;
60 }
61
62 // configure neural network
63 try
64 {
65 m_lwtGraph = std::make_unique<lwt::LightweightGraph>(lwtGraphConfig, lwtGraphConfig.outputs.cbegin()->first);
66 }
67 catch (const lwt::NNConfigurationException &e)
68 {
69 ATH_MSG_ERROR("Error configuring network: " << e.what());
70 return StatusCode::FAILURE;
71 }
72
73 return StatusCode::SUCCESS;
74}
75
77 const EventContext& /*ctx*/) const
78{
79 // inputs
80 // ------
81 // m_inputMap will not hold any information,
82 // but it is required by the lwtnn API.
83 //
84 InputMap inputMapDummy;
85 InputSequenceMap inputSeqMap;
86 std::set<std::string> branches = {"TauTrack", "NeutralPFO", "ShotPFO", "ConvTrack"};
87 DMHelper::initMapKeys(inputSeqMap, branches);
88
89 ATH_CHECK(getInputs(xTau, inputSeqMap));
90
91 // output
92 // ------
93 ValueMap outputs;
94
95 // inference
96 // ---------
97 try
98 {
99 outputs = m_lwtGraph->compute(inputMapDummy, inputSeqMap);
100 }
101 catch (const std::exception &e)
102 {
103 ATH_MSG_ERROR("Error evaluating the network: " << e.what());
104 return StatusCode::FAILURE;
105 }
106
107 // Results
108 // -------
109 // Decay modes are "1p0n", "1p1n", "1pXn", "3p0n", "3pXn",
110 // here they are encoded as 0, 1, 2, 3, 4
111 //
112 std::array<float, DMVar::nClasses> probs;
113 // the prefix to match to output name in the json weight file
114 std::string prefix = "c_";
115 for (std::size_t i = 0; i < probs.size(); ++i)
116 {
117 probs[i] = outputs.at(prefix + DMVar::sModeNames[i]);
118 }
119
120 // Determine decay mode from classification results
121 // If requested: ensures consistency between reconstructed number of tracks and decay mode
122 // For non 1 / 3-track taus, classification is performed by maximum mode probability
123 //
124 std::array<float, DMVar::nClasses>::const_iterator itMax;
125 if (m_ensureTrackConsistency && xTau.nTracks() == 1)
126 {
127 // maximum probability of "1p0n", "1p1n", "1pXn"
128 itMax = std::max_element(probs.cbegin(), probs.cbegin() + 3);
129 }
130 else if (m_ensureTrackConsistency && xTau.nTracks() == 3)
131 {
132 // maximum probability of "3p0n", "3pXn"
133 itMax = std::max_element(probs.cbegin() + 3, probs.cend());
134 }
135 else
136 {
137 // maximum probability of all
138 itMax = std::max_element(probs.cbegin(), probs.cend());
139 }
140
141 const SG::Accessor<int> accDecayMode(m_outputName);
142 accDecayMode(xTau) = std::distance(probs.cbegin(), itMax);
143
144 if (m_decorateProb)
145 {
146 for (std::size_t i = 0; i < probs.size(); ++i)
147 {
148 const std::string probName = m_probPrefix + DMVar::sModeNames[i];
149 const SG::Accessor<float> accProb(probName);
150 accProb(xTau) = probs[i];
151 }
152 }
153
154 return StatusCode::SUCCESS;
155}
156
157StatusCode TauDecayModeNNClassifier::getInputs(const xAOD::TauJet &xTau, InputSequenceMap &inputSeqMap) const
158{
159 std::vector<TrkPtr> vTauTracks;
160 std::vector<PFOPtr> vNeutralPFOs;
161 std::vector<PFOPtr> vShotPFOs;
162 std::vector<TrkPtr> vConvTracks;
163
164 // set objects
165 // -----------
166
167 // classified tau tracks
169
170 // neutral PFOs
171 for (std::size_t i = 0; i < xTau.nNeutralPFOs(); ++i)
172 {
173 const auto pfo = xTau.neutralPFO(i);
174 // Apply pt threshold
175 if (pfo->pt() < m_neutralPFOPtCut * 1e3)
176 continue;
177 vNeutralPFOs.push_back(pfo);
178 }
179
180 // shot PFOs
181 for (std::size_t i = 0; i < xTau.nShotPFOs(); ++i)
182 {
183 const auto pfo = xTau.shotPFO(i);
184 // skip PFOs without photons
185 int nPhotons{-1};
186 try
187 {
188 nPhotons = DMVar::pfoAttr<int>(pfo, PFOAttributes::tauShots_nPhotons);
189 }
190 catch (const std::exception &e)
191 {
192 ATH_MSG_ERROR("Error retrieving tauShots_nPhotons: " << e.what());
193 return StatusCode::FAILURE;
194 }
195 if (nPhotons < 1)
196 continue;
197 vShotPFOs.push_back(pfo);
198 }
199
200 // classified conversion tracks
202
207
208 // set variables
209 // -------------
210
211 // tau variables
212 const TLorentzVector &tau_p4 = xTau.p4(xAOD::TauJetParameters::TauCalibType::IntermediateAxis);
213
214 // pair: (1st) the value, (2nd) successfully retrieved
215 std::pair<float, bool> tau_etaTrkECal{0., false};
216 std::pair<float, bool> tau_phiTrkECal{0., false};
217 if (xTau.nTracks() > 0)
218 {
219 TrkPtr trk = xTau.track(0);
220 if (!trk->detail(xAOD::TauJetParameters::CaloSamplingPhiEM, tau_phiTrkECal.first))
221 {
222 ATH_MSG_WARNING("Failed to retrieve extrapolated track phi in ECal");
223 }
224 else
225 {
226 tau_phiTrkECal.second = true;
227 }
228 if (!trk->detail(xAOD::TauJetParameters::CaloSamplingEtaEM, tau_etaTrkECal.first))
229 {
230 ATH_MSG_WARNING("Failed to retrieve extrapolated track eta in ECal");
231 }
232 else
233 {
234 tau_etaTrkECal.second = true;
235 }
236 }
237
238 // a function to set the common 4-momentum variables, this is needed for all later
239 auto setCommonP4Vars = [&tau_p4, &tau_etaTrkECal, &tau_phiTrkECal](VectorMap &in_seq_map, const TLorentzVector &obj_p4) {
240 in_seq_map["dphiECal"].push_back(DMVar::deltaPhiECal(obj_p4, tau_phiTrkECal));
241 in_seq_map["detaECal"].push_back(DMVar::deltaEtaECal(obj_p4, tau_etaTrkECal));
242 in_seq_map["dphi"].push_back(DMVar::deltaPhi(obj_p4, tau_p4));
243 in_seq_map["deta"].push_back(DMVar::deltaEta(obj_p4, tau_p4));
244 in_seq_map["pt_log"].push_back(DMHelper::Log10Robust(obj_p4.Pt()));
245 in_seq_map["jetpt_log"].push_back(DMHelper::Log10Robust(tau_p4.Pt()));
246 };
247
248 // a function to set the track impact parameter variables
249 auto setTrackIPVars = [](VectorMap &in_seq_map, const TrkPtr &trk) {
250 in_seq_map["d0TJVA"].push_back(trk->d0TJVA());
251 in_seq_map["d0SigTJVA"].push_back(trk->d0SigTJVA());
252 in_seq_map["z0sinthetaTJVA"].push_back(trk->z0sinthetaTJVA());
253 in_seq_map["z0sinthetaSigTJVA"].push_back(trk->z0sinthetaSigTJVA());
254 };
255
256 // a function to set the neutral pfo variables
257 auto setNeutralPFOVars = [](VectorMap &in_seq_map, const PFOPtr &pfo) {
258 // get the attributes of a given PFO object
259 auto getAttr = std::bind(DMVar::pfoAttr<float>, pfo, std::placeholders::_1);
260 auto getAttrInt = std::bind(DMVar::pfoAttr<int>, pfo, std::placeholders::_1);
261
262 in_seq_map["FIRST_ETA"].push_back(getAttr(PFOAttributes::cellBased_FIRST_ETA));
263 in_seq_map["SECOND_R_log"].push_back(DMHelper::Log10Robust(getAttr(PFOAttributes::cellBased_SECOND_R), 1e-3f));
264 in_seq_map["DELTA_THETA"].push_back(getAttr(PFOAttributes::cellBased_DELTA_THETA));
265 in_seq_map["CENTER_LAMBDA_log"].push_back(DMHelper::Log10Robust(getAttr(PFOAttributes::cellBased_CENTER_LAMBDA), 1e-3f));
266 in_seq_map["LONGITUDINAL"].push_back(getAttr(PFOAttributes::cellBased_LONGITUDINAL));
267 in_seq_map["ENG_FRAC_CORE"].push_back(getAttr(PFOAttributes::cellBased_ENG_FRAC_CORE));
268 in_seq_map["SECOND_ENG_DENS_log"].push_back(DMHelper::Log10Robust(getAttr(PFOAttributes::cellBased_SECOND_ENG_DENS), 1e-6f));
269 in_seq_map["NPosECells_EM1"].push_back(getAttrInt(PFOAttributes::cellBased_NPosECells_EM1));
270 in_seq_map["NPosECells_EM2"].push_back(getAttrInt(PFOAttributes::cellBased_NPosECells_EM2));
271 in_seq_map["energy_EM1"].push_back(getAttr(PFOAttributes::cellBased_energy_EM1));
272 in_seq_map["energy_EM2"].push_back(getAttr(PFOAttributes::cellBased_energy_EM2));
273 in_seq_map["EM1CoreFrac"].push_back(getAttr(PFOAttributes::cellBased_EM1CoreFrac));
274 in_seq_map["firstEtaWRTClusterPosition_EM1"].push_back(getAttr(PFOAttributes::cellBased_firstEtaWRTClusterPosition_EM1));
275 in_seq_map["firstEtaWRTClusterPosition_EM2"].push_back(getAttr(PFOAttributes::cellBased_firstEtaWRTClusterPosition_EM2));
276 in_seq_map["secondEtaWRTClusterPosition_EM1_log"].push_back(DMHelper::Log10Robust(getAttr(PFOAttributes::cellBased_secondEtaWRTClusterPosition_EM1), 1e-6f));
277 in_seq_map["secondEtaWRTClusterPosition_EM2_log"].push_back(DMHelper::Log10Robust(getAttr(PFOAttributes::cellBased_secondEtaWRTClusterPosition_EM2), 1e-6f));
278 };
279
280 // set tau tracks variables
281 VectorMap &chrg_map = inputSeqMap.at("TauTrack");
284 for (const auto &trk : vTauTracks)
285 {
286 setCommonP4Vars(chrg_map, trk->p4());
287 setTrackIPVars(chrg_map, trk);
288 }
289
290 // set Neutral PFOs variables
291 VectorMap &neut_map = inputSeqMap.at("NeutralPFO");
294 for (const auto &pfo : vNeutralPFOs)
295 {
296 setCommonP4Vars(neut_map, pfo->p4());
297 try
298 {
299 setNeutralPFOVars(neut_map, pfo);
300 }
301 catch (const std::exception &e)
302 {
303 ATH_MSG_ERROR("Error setting neutral PFO variables: " << e.what());
304 return StatusCode::FAILURE;
305 }
306 }
307
308 // set Shot PFOs variables
309 VectorMap &shot_map = inputSeqMap.at("ShotPFO");
311 for (const auto &pfo : vShotPFOs)
312 {
313 setCommonP4Vars(shot_map, pfo->p4());
314 }
315
316 // set Conversion tracks variables
317 VectorMap &conv_map = inputSeqMap.at("ConvTrack");
320 for (const auto &trk : vConvTracks)
321 {
322 setCommonP4Vars(conv_map, trk->p4());
323 setTrackIPVars(conv_map, trk);
324 }
325
326 return StatusCode::SUCCESS;
327}
328
329// Helper functions
330namespace tauRecTools
331{
332 const std::set<std::string> TauDecayModeNNVariable::sCommonP4Vars = {
333 "dphiECal", "detaECal", "dphi", "deta", "pt_log", "jetpt_log"};
334
335 const std::set<std::string> TauDecayModeNNVariable::sTrackIPVars = {
336 "d0TJVA", "d0SigTJVA", "z0sinthetaTJVA", "z0sinthetaSigTJVA"};
337
338 const std::set<std::string> TauDecayModeNNVariable::sNeutralPFOVars = {
339 "FIRST_ETA", "SECOND_R_log", "DELTA_THETA", "CENTER_LAMBDA_log", "LONGITUDINAL", "ENG_FRAC_CORE",
340 "SECOND_ENG_DENS_log", "NPosECells_EM1", "NPosECells_EM2", "energy_EM1", "energy_EM2", "EM1CoreFrac",
341 "firstEtaWRTClusterPosition_EM1", "firstEtaWRTClusterPosition_EM2",
342 "secondEtaWRTClusterPosition_EM1_log", "secondEtaWRTClusterPosition_EM2_log"};
343
344 const std::array<std::string, TauDecayModeNNVariable::nClasses> TauDecayModeNNVariable::sModeNames = {
345 "1p0n", "1p1n", "1pXn", "3p0n", "3pXn"};
346
347 float TauDecayModeNNVariable::deltaPhi(const TLorentzVector &p4, const TLorentzVector &p4_tau)
348 {
349 return p4_tau.DeltaPhi(p4);
350 }
351
352 float TauDecayModeNNVariable::deltaEta(const TLorentzVector &p4, const TLorentzVector &p4_tau)
353 {
354 return p4.Eta() - p4_tau.Eta();
355 }
356
357 float TauDecayModeNNVariable::deltaPhiECal(const TLorentzVector &p4, const std::pair<float, bool> &tau_phiTrkECal)
358 {
359 // if not retrieved, then set to 0. (mean value)
360 return tau_phiTrkECal.second ? TVector2::Phi_mpi_pi(p4.Phi() - tau_phiTrkECal.first) : 0.0f;
361 }
362
363 float TauDecayModeNNVariable::deltaEtaECal(const TLorentzVector &p4, const std::pair<float, bool> &tau_etaTrkECal)
364 {
365 // if not retrieved, then set to 0. (mean value)
366 return tau_etaTrkECal.second ? p4.Eta() - tau_etaTrkECal.first : 0.0f;
367 }
368
369 template <typename T>
371 {
372 T val{static_cast<T>(0)};
373 if (!pfo->attribute(attr, val))
374 {
375 throw std::runtime_error("Can not retrieve PFO attribute! enum = " + std::to_string(static_cast<unsigned>(attr)));
376 }
377 return val;
378 }
379
380 float TauDecayModeNNHelper::Log10Robust(const float val, const float min_val)
381 {
382 return TMath::Log10(std::max(val, min_val));
383 }
384
385 template <typename T>
386 void TauDecayModeNNHelper::sortAndKeep(std::vector<T> &vec, const std::size_t n_obj)
387 {
388 auto cmp_pt = [](const T lhs, const T rhs) { return lhs->pt() > rhs->pt(); };
389 std::sort(vec.begin(), vec.end(), cmp_pt);
390 if (vec.size() > n_obj)
391 {
392 vec.erase(vec.begin() + n_obj, vec.end());
393 }
394 }
395
396 template <typename T>
397 void TauDecayModeNNHelper::initMapKeys(std::map<std::string, T> &empty_map,
398 const std::set<std::string> &keys)
399 {
400 // T can be any type
401 for (const auto &key : keys)
402 {
403 empty_map[key];
404 }
405 }
406} // namespace tauRecTools
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_INFO(x,...)
std::vector< size_t > vec
std::map< std::string, std::vector< double > > VectorMap
std::map< std::string, VectorMap > InputSequenceMap
const xAOD::TauTrack * TrkPtr
std::map< std::string, double > ValueMap
const xAOD::PFO * PFOPtr
std::map< std::string, ValueMap > InputMap
xAOD::PFODetails::PFOAttributes PFOAttributes
tauRecTools::TauDecayModeNNVariable DMVar
tauRecTools::TauDecayModeNNHelper DMHelper
Helper class to provide type-safe access to aux data.
Gaudi::Property< bool > m_decorateProb
virtual StatusCode getInputs(const xAOD::TauJet &xTau, std::map< std::string, std::map< std::string, std::vector< double > > > &inputSeqMap) const
retrieve the input variables from a TauJet
TauDecayModeNNClassifier(const std::string &name="TauDecayModeNNClassifier")
Gaudi::Property< bool > m_ensureTrackConsistency
Gaudi::Property< std::size_t > m_maxTauTracks
Gaudi::Property< std::string > m_outputName
properties of the tool
Gaudi::Property< std::string > m_weightFile
Gaudi::Property< std::size_t > m_maxConvTracks
Gaudi::Property< float > m_neutralPFOPtCut
virtual StatusCode initialize() override
Tool initializer.
std::unique_ptr< const lwt::LightweightGraph > m_lwtGraph
lwtnn graph
virtual StatusCode executeTool(xAOD::TauJet &xTau, const EventContext &ctx) const override
Execute - called for each tau candidate.
Gaudi::Property< std::string > m_probPrefix
Gaudi::Property< std::size_t > m_maxShotPFOs
Gaudi::Property< std::size_t > m_maxNeutralPFOs
TauRecToolBase(const std::string &name)
std::string find_file(const std::string &fname) const
A closely related class that provides helper functions.
static void sortAndKeep(std::vector< T > &vec, const std::size_t n_obj)
sort the objects and only keep the leading N objects in the vector
static float Log10Robust(const float val, const float min_val=0.)
static void initMapKeys(std::map< std::string, T > &empty_map, const std::set< std::string > &keys)
initialise the map with a set of defined keys
A closely related class that calculates the input variables.
static float deltaEta(const TLorentzVector &p4, const TLorentzVector &p4_tau)
static const std::set< std::string > sCommonP4Vars
static float deltaEtaECal(const TLorentzVector &p4, const std::pair< float, bool > &tau_etaTrkECal)
static const std::set< std::string > sTrackIPVars
static const std::set< std::string > sNeutralPFOVars
static T pfoAttr(const xAOD::PFO *pfo, const xAOD::PFODetails::PFOAttributes &attr)
retrieve the PFO attributes
static const std::array< std::string, nClasses > sModeNames
static float deltaPhi(const TLorentzVector &p4, const TLorentzVector &p4_tau)
static float deltaPhiECal(const TLorentzVector &p4, const std::pair< float, bool > &tau_phiTrkECal)
bool attribute(PFODetails::PFOAttributes AttributeType, T &anAttribute) const
get a PFO Variable via enum
size_t nNeutralPFOs() const
Get the number of neutral PFO particles associated with this tau.
size_t nShotPFOs() const
Get the number of shot PFO particles associated with this tau.
virtual FourMom_t p4() const
The full 4-momentum of the particle.
Definition TauJet_v3.cxx:96
const PFO * shotPFO(size_t i) const
Get the pointer to a given shot PFO associated with this tau.
const TauTrack * track(size_t i, TauJetParameters::TauTrackFlag flag=TauJetParameters::TauTrackFlag::classifiedCharged, int *container_index=0) const
Get the pointer to a given tauTrack associated with this tau /*container index needed by trackNonCons...
const PFO * neutralPFO(size_t i) const
Get the pointer to a given neutral PFO associated with this tau.
size_t nTracks(TauJetParameters::TauTrackFlag flag=TauJetParameters::TauTrackFlag::classifiedCharged) const
std::vector< const TauTrack * > tracks(TauJetParameters::TauTrackFlag flag=TauJetParameters::TauTrackFlag::classifiedCharged) const
Get the v<const pointer> to a given tauTrack collection associated with this tau.
bool detail(TauJetParameters::TrackDetail detail, float &value) const
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
Implementation of a TrackClassifier based on an RNN.
Definition BDTHelper.cxx:12
PFO_v1 PFO
Definition of the current "pfo version".
Definition PFO.h:17
TauTrack_v1 TauTrack
Definition of the current version.
Definition TauTrack.h:16
TauJet_v3 TauJet
Definition of the current "tau version".
Definition TauJet.h:17