ATLAS Offline Software
Loading...
Searching...
No Matches
TrackTruthMatchingBaseAlg.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5#ifndef ACTSTRK_TRACKTRUTHMATCHINGBASEALG_H
6#define ACTSTRK_TRACKTRUTHMATCHINGBASEALG_H 1
7
8// Base Class
10
11// Gaudi includes
12#include "Gaudi/Property.h"
13
14// Handle Keys
17
21
22#include <mutex>
25
26#include <string>
27#include <memory>
28#include <array>
29#include <atomic>
30#include <type_traits>
31
32#include <cmath>
33#include <iomanip>
34#include <ostream>
35#include <sstream>
36#include <vector>
37
38namespace ActsTrk
39{
40 constexpr bool TrackFindingValidationDebugHists = false;
42
44 {
45 template <bool DetailEnabled>
46 struct BaseStat;
47
48 template <bool DetailEnabled>
49 friend struct BaseStat;
50
51 public:
52 using AthReentrantAlgorithm::AthReentrantAlgorithm;
53
54 virtual StatusCode initialize() override;
55 virtual StatusCode finalize() override;
56
57 protected:
58 const TruthParticleHitCounts &getTruthParticleHitCounts(const EventContext &ctx) const {
59 const TruthParticleHitCounts* truth_particle_hit_counts_handle{};
60 if (!SG::get(truth_particle_hit_counts_handle, m_truthHitCounts, ctx).isSuccess()) {
61 ATH_MSG_ERROR("No truth particle hit count map for key " << m_truthHitCounts.key() );
62 throw std::runtime_error("Failed to get truth particle hit count map");
63 }
64 return *truth_particle_hit_counts_handle;
65 }
66 std::size_t perEtaSize() const {
67 return m_detailedStat.perEtaSize();
68 }
69 std::size_t perPdgIdSize() const {
70 return m_detailedStat.perPdgIdSize();
71 }
72
73 template <bool DetailEnabled>
74 struct EventStatBase : public BaseStat<DetailEnabled> {
75 static constexpr bool doDetail = DetailEnabled;
76
77 EventStatBase(const IAthSelectionTool &truth_selection_tool,
78 std::size_t per_eta_size,
79 std::size_t per_pdg_size,
80 [[maybe_unused]] std::size_t track_to_truth_size)
81 : BaseStat<DetailEnabled>(truth_selection_tool, per_eta_size, per_pdg_size),
82 m_nTruthCuts(truth_selection_tool.nCuts())
83 {
84 if constexpr(DetailEnabled) {
85 m_truthParticlesWithAssociatedTrack.reserve(track_to_truth_size);
86 }
87
88 };
89 void fill([[maybe_unused]] unsigned int eta_category_i,
90 [[maybe_unused]] unsigned int pdg_id_category_i,
91 [[maybe_unused]] float hit_efficiency,
92 [[maybe_unused]] float hit_purity,
93 [[maybe_unused]] float match_prob,
94 [[maybe_unused]] const xAOD::TruthParticle *best_match) {
95 BaseStat<DetailEnabled>::fill(eta_category_i,
96 pdg_id_category_i,
97 hit_efficiency,
98 hit_purity,
99 match_prob);
100 if constexpr(DetailEnabled) {
101 if (!m_truthParticlesWithAssociatedTrack.insert(best_match).second) {
102 // truth particle already had a best match
105 }
106 else {
107 ++this->m_counterPerEta[eta_category_i][kNParticleWithAssociatedTrack];
108 ++this->m_counterPerPdgId[pdg_id_category_i][kNParticleWithAssociatedTrack];
109 }
110 }
111 }
112 using TruthParticleSet = std::conditional_t< DetailEnabled,
113 std::unordered_set<const xAOD::TruthParticle *>,
116
121
122 unsigned int m_nTruthCuts{0u};
123 };
125
131 float m_hitPurity{0.f};
132 float m_hitEfficiency{0.f};
133 };
134
137 TruthMatchResult
138 analyseTrackTruth(const TruthParticleHitCounts &truth_particle_hit_counts,
139 const HitCountsPerTrack &track_hit_counts,
140 EventStat &event_stat) const;
141
142 void postProcessEventStat(const TruthParticleHitCounts &truth_particle_hit_counts,
143 std::size_t n_tracks,
144 EventStat &event_stat) const;
145 protected:
146 ToolHandle<IAthSelectionTool> m_truthSelectionTool{this, "TruthSelectionTool","AthTruthSelectionTool", "Truth selection tool (for efficiencies and resolutions)"};
147 private:
149 {this, "TruthParticleHitCounts","", "Map from truth particle to hit counts." };
150
151 Gaudi::Property<std::vector<float> > m_weightsForProb
152 {this, "MatchWeights", std::vector<float>(s_NMeasurementTypes,1.f),
153 "Weights applied to the counts per measurement type for weighted sums"
154 " which are used compute the match probability." };
155 Gaudi::Property<std::vector<float> > m_weights
156 {this, "CountWeights", std::vector<float>(s_NMeasurementTypes,1.f),
157 "Weights applied to the counts per measurement type for weighted sums"
158 " which are used to compute hit efficiencies and purities." };
159 Gaudi::Property<bool> m_truthLinkedFakeRate
160 {this, "TruthLinkedFakeRate", false, "Compute the match probability from the truth-linked measurements only:"
161 " measurements without truth particle weigh 1 and cannot be the best match, so a"
162 " track made only of them has probability 0. By default the probability is"
163 " computed the way the legacy truth matching does (DetailedTrackTruthBuilder,"
164 " TruthMatchRatio): measurements without truth particle keep their full weight and"
165 " together compete for the best match as one pseudo particle; if it wins, the"
166 " probability is their weighted fraction and there is no matching truth particle." };
167 Gaudi::Property<std::vector<float>> m_statEtaBins
168 {this, "StatisticEtaBins", {-4, -2.6, -2, 0, 2., 2.6, 4}, "Gather statistics separately for these eta bins."};
169 Gaudi::Property<std::vector<float>> m_statPtBins
170 {this, "StatisticPtBins", {1.e3,2.5e3,10e3, 100e3}, "Gather statistics separately for these pt bins."};
171 Gaudi::Property<bool> m_pdgIdCategorisation
172 {this, "PdgIdCategorisation", false, "Categorise by pdg id."};
173 Gaudi::Property<bool> m_showRawCounts
174 {this, "ShowRawCounts", false, "Show all counters."};
175 Gaudi::Property<bool> m_printDetails
176 {this, "ShowDetailedTables", false, "Show more details; stat. uncert., RMS, entries"};
177 Gaudi::Property<bool> m_computeTrackRecoEfficiency
178 {this, "ComputeTrackRecoEfficiency", true, "Compute and print track reconstruction efficiency."};
179
180 // helper struct for compile time optional statistics
181 template <bool IsDebug>
183 struct Empty {
184 template <typename... T_Args>
185 Empty(T_Args... ) {}
186 };
187 mutable typename std::conditional<IsDebug,
188 std::mutex,
190 mutable typename std::conditional<IsDebug,
192 Empty>::type m_measPerTruthParticleWithoutCounts ATLAS_THREAD_SAFE {20,-.5,20.-.5};
193 mutable typename std::conditional<IsDebug,
195 Empty>::type m_bestMatchProb ATLAS_THREAD_SAFE {20,0.,1.};
196 mutable typename std::conditional<IsDebug,
198 Empty>::type m_nextToBestMatchProb ATLAS_THREAD_SAFE {20,0.,1.};
199
200 template <class T_OutStream>
201 void dumpStatistics(T_OutStream &out) const;
202 void fillMeasForTruthParticleWithoutCount(double weighted_measurement_sum) const;
203 void fillTruthMatchProb(const std::array<float,2> &best_match_prob) const;
204 };
206
207 // s_NMeasurementTypes is equal to the number of UncalibMeasType
208 constexpr static unsigned int s_NMeasurementTypes = Acts::toUnderlying(xAOD::UncalibMeasType::nTypes);
209
210 // statistics counter
220
234
235 constexpr static int s_pdgIdMax = 1000000000; // categorise all truth particles with this or larger PDG ID as "Other"
236
237
238 bool m_useAbsEtaForStat = false;
239
240 template <bool DetailEnabled>
241 struct BaseStat {
242 BaseStat() = default;
243 BaseStat([[maybe_unused]] const IAthSelectionTool &truth_selection_tool,
244 [[maybe_unused]] std::size_t per_eta_size,
245 [[maybe_unused]] std::size_t per_pdg_size)
246 : m_truthSelectionCuts(truth_selection_tool.nCuts()+1, -0.5,truth_selection_tool.nCuts()+.5)
247 {
248 if constexpr(DetailEnabled) {
249 m_counterPerEta.resize(per_eta_size);
250 m_counterPerPdgId.resize( per_pdg_size);
251 m_statPerEta.resize( per_eta_size );
252 m_statPerPdgId.resize( per_pdg_size );
253 }
254
255 }
256 void reset(const IAthSelectionTool &truth_selection_tool,
257 [[maybe_unused]] std::size_t per_eta_size,
258 [[maybe_unused]] std::size_t per_pdg_size)
259 {
260 m_truthSelectionCuts.setBinning(truth_selection_tool.nCuts()+1, -0.5,truth_selection_tool.nCuts()+.5);
261 if constexpr(DetailEnabled) {
262 m_counterPerEta.clear();
263 m_counterPerPdgId.clear();
264 m_statPerEta.clear();
265 m_statPerPdgId.clear();
266 m_counterPerEta.resize(per_eta_size);
267 m_counterPerPdgId.resize( per_pdg_size);
268 m_statPerEta.resize( per_eta_size );
269 m_statPerPdgId.resize( per_pdg_size );
270 }
271 }
272 void fill([[maybe_unused]] unsigned int eta_category_i,
273 [[maybe_unused]] unsigned int pdg_id_category_i,
274 [[maybe_unused]] float hit_efficiency,
275 [[maybe_unused]] float hit_purity,
276 [[maybe_unused]] float match_prob) {
277 if (DetailEnabled) {
278 assert( eta_category_i <m_statPerEta.size());
279 m_statPerEta[eta_category_i][kHitEfficiency].add( hit_efficiency);
280 m_statPerEta[eta_category_i][kHitPurity].add( hit_purity);
281 m_statPerEta[eta_category_i][kMatchProbability].add( match_prob);
282 assert( pdg_id_category_i <m_statPerPdgId.size());
283 m_statPerPdgId[pdg_id_category_i][kHitEfficiency].add( hit_efficiency);
284 m_statPerPdgId[pdg_id_category_i][kHitPurity].add( hit_purity);
285 m_statPerPdgId[pdg_id_category_i][kMatchProbability].add( match_prob);
286 assert( eta_category_i < m_counterPerEta.size());
287 assert( pdg_id_category_i <m_counterPerPdgId.size());
288 ++m_counterPerEta[eta_category_i][kNTotalTracks];
289 ++m_counterPerPdgId[pdg_id_category_i][kNTotalTracks];
290 }
291 }
292 void incrementTotal([[maybe_unused]] unsigned int eta_category_i,
293 [[maybe_unused]] unsigned int pdg_id_category_i) {
294 if constexpr(DetailEnabled) {
295 ++m_counterPerEta[eta_category_i][kNTotalParticles];
296 ++m_counterPerPdgId[pdg_id_category_i][kNTotalParticles];
297 }
298 }
299
301
303 const std::vector<float> &statPtBins,
304 const std::vector<float> &statEtaBins,
305 std::vector< int > &pdgId,
306 bool printDetails,
307 bool pdgIdCategorisation,
308 bool useAbsEtaForStat);
309
310
311 std::size_t perEtaSize() const {
312 if constexpr(DetailEnabled) { return m_counterPerEta.size(); }
313 else { return 0u; }
314 }
315 std::size_t perPdgIdSize() const {
316 if constexpr(DetailEnabled) { return m_counterPerPdgId.size(); }
317 else { return 0u; }
318 }
320 // per event statistics
321 struct Empty {};
322 using CounterArrayVec = std::conditional< DetailEnabled,
323 std::vector< std::array< std::size_t, kNCategorisedCounter> >,
324 Empty >::type;
325 using StatArrayVec = std::conditional< DetailEnabled,
326 std::vector< std::array<ActsUtils::Stat, kNCategorisedStat> >,
327 Empty >::type;
332
333 };
334
335
336 mutable std::mutex m_statMutex ATLAS_THREAD_SAFE;
337 mutable std::array< std::size_t, kNCounter > m_counter ATLAS_THREAD_SAFE {};
338 mutable std::vector< int > m_pdgId ATLAS_THREAD_SAFE;
340
343 void checkBinOrder( const std::vector<float> &bin_edges, const std::string &bin_label) const;
344
349 std::size_t getPtEtaStatCategory(float pt, float eta) const;
350
355 std::size_t getPtPdgIdStatCategory(float pt, int pdg_id) const;
356 void initStatTables();
357 void printStatTables() const;
358 void printCategories(const std::vector<std::string> &pt_category_labels,
359 const std::vector<std::string> &eta_category_labels,
360 std::vector<std::string> &counter_labels,
361 std::vector< std::array< ActsUtils::Stat, kNCategorisedStat> > &stat_per_category,
362 std::vector< std::array< std::size_t, kNCategorisedCounter> > &counts_per_category,
363 const std::string &top_left_label,
364 bool print_sub_categories) const;
365 void printData2D(const std::vector<std::string> &row_category_labels,
366 const std::vector<std::string> &col_category_labels,
367 const std::string &top_left_label,
368 std::vector< std::array< ActsUtils::Stat, kNCategorisedStat> > &stat_per_category,
369 std::vector< std::array< std::size_t, kNCategorisedCounter> > &counts_per_category,
370 bool rotate) const;
371
372 StatusCode checkMatchWeights();
373
374 static double weightedCountSum(const ActsTrk::HitCounterArray &counts,
375 const std::vector<float> &weights);
376 static double noiseCorrection(const ActsTrk::HitCounterArray &noise_counts,
377 const std::vector<float> &weights);
378
379 };
380
381} // namespace
382
383#endif
Scalar eta() const
pseudorapidity method
#define ATH_MSG_ERROR(x,...)
header file for interface of selection tools in this package
Property holding a SG store/key/clid from which a ReadHandle is made.
Property holding a SG store/key/clid from which a WriteHandle is made.
void rotate(double angler, GeoTrf::Vector2D &vector)
Container for hit counts per track Contains hit counts per associated truth particle and the total hi...
void checkBinOrder(const std::vector< float > &bin_edges, const std::string &bin_label) const
check that bins are in increasing order.
static constexpr unsigned int s_NMeasurementTypes
void printData2D(const std::vector< std::string > &row_category_labels, const std::vector< std::string > &col_category_labels, const std::string &top_left_label, std::vector< std::array< ActsUtils::Stat, kNCategorisedStat > > &stat_per_category, std::vector< std::array< std::size_t, kNCategorisedCounter > > &counts_per_category, bool rotate) const
SG::ReadHandleKey< TruthParticleHitCounts > m_truthHitCounts
TruthMatchResult analyseTrackTruth(const TruthParticleHitCounts &truth_particle_hit_counts, const HitCountsPerTrack &track_hit_counts, EventStat &event_stat) const
DebugCounter< TrackFindingValidationDebugHists > m_debugCounter
void printCategories(const std::vector< std::string > &pt_category_labels, const std::vector< std::string > &eta_category_labels, std::vector< std::string > &counter_labels, std::vector< std::array< ActsUtils::Stat, kNCategorisedStat > > &stat_per_category, std::vector< std::array< std::size_t, kNCategorisedCounter > > &counts_per_category, const std::string &top_left_label, bool print_sub_categories) const
const TruthParticleHitCounts & getTruthParticleHitCounts(const EventContext &ctx) const
EventStatBase< TrackFindingValidationDetailedStat > EventStat
static double noiseCorrection(const ActsTrk::HitCounterArray &noise_counts, const std::vector< float > &weights)
std::size_t getPtPdgIdStatCategory(float pt, int pdg_id) const
Return the category based on the PDG ID.
static double weightedCountSum(const ActsTrk::HitCounterArray &counts, const std::vector< float > &weights)
void postProcessEventStat(const TruthParticleHitCounts &truth_particle_hit_counts, std::size_t n_tracks, EventStat &event_stat) const
Gaudi::Property< std::vector< float > > m_weightsForProb
Gaudi::Property< std::vector< float > > m_statEtaBins
std::size_t getPtEtaStatCategory(float pt, float eta) const
Return the category based on the provided eta value.
Gaudi::Property< std::vector< float > > m_statPtBins
Gaudi::Property< std::vector< float > > m_weights
ToolHandle< IAthSelectionTool > m_truthSelectionTool
Extend Stat helper by an equidistant binned histogram.
Definition StatUtils.h:81
An algorithm that can be simultaneously executed in multiple threads.
IAthSelectionTool is a virtual baseclass for selection methods.
virtual unsigned int nCuts() const =0
return the number of cuts.
Property holding a SG store/key/clid from which a ReadHandle is made.
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
std::unordered_map< const xAOD::TruthParticle *, HitCounterArray > TruthParticleHitCounts
constexpr bool TrackFindingValidationDetailedStat
constexpr bool TrackFindingValidationDebugHists
std::array< uint8_t, NHitCounter > HitCounterArray
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
TruthParticle_v1 TruthParticle
Typedef to implementation.
void reset(const IAthSelectionTool &truth_selection_tool, std::size_t per_eta_size, std::size_t per_pdg_size)
void incrementTotal(unsigned int eta_category_i, unsigned int pdg_id_category_i)
BaseStat< DetailEnabled > & operator+=(const BaseStat< DetailEnabled > &event_stat)
std::conditional< DetailEnabled, std::vector< std::array< std::size_t, kNCategorisedCounter > >, Empty >::type CounterArrayVec
std::conditional< DetailEnabled, std::vector< std::array< ActsUtils::Stat, kNCategorisedStat > >, Empty >::type StatArrayVec
void fill(unsigned int eta_category_i, unsigned int pdg_id_category_i, float hit_efficiency, float hit_purity, float match_prob)
BaseStat(const IAthSelectionTool &truth_selection_tool, std::size_t per_eta_size, std::size_t per_pdg_size)
void fillMeasForTruthParticleWithoutCount(double weighted_measurement_sum) const
std::conditional< IsDebug, std::mutex, Empty >::type m_mutex ATLAS_THREAD_SAFE
void fillTruthMatchProb(const std::array< float, 2 > &best_match_prob) const
EventStatBase(const IAthSelectionTool &truth_selection_tool, std::size_t per_eta_size, std::size_t per_pdg_size, std::size_t track_to_truth_size)
std::conditional_t< DetailEnabled, std::unordered_set< const xAOD::TruthParticle * >, typename BaseStat< DetailEnabled >::Empty > TruthParticleSet
void fill(unsigned int eta_category_i, unsigned int pdg_id_category_i, float hit_efficiency, float hit_purity, float match_prob, const xAOD::TruthParticle *best_match)
float m_hitPurity
fraction of hits originting from best match over total reco hits
float m_matchProbability
the matching probability based on weighted hit sums
float m_hitEfficiency
fraction of hits originting from best match over total best match hits
const xAOD::TruthParticle * m_truthParticle
best matching truth particle or nullptr