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 TrackTruthMatchingBaseAlg(const std::string &name,
53 ISvcLocator *pSvcLocator);
54
55 virtual StatusCode initialize() override;
56 virtual StatusCode finalize() override;
57
58 protected:
59 const TruthParticleHitCounts &getTruthParticleHitCounts(const EventContext &ctx) const {
60 SG::ReadHandle<TruthParticleHitCounts> truth_particle_hit_counts_handle = SG::makeHandle(m_truthHitCounts, ctx);
61 if (!truth_particle_hit_counts_handle.isValid()) {
62 ATH_MSG_ERROR("No truth particle hit count map for key " << m_truthHitCounts.key() );
63 std::runtime_error("Failed to get truth particle hit count map");
64 }
65 return *truth_particle_hit_counts_handle;
66 }
67
69
70 std::size_t perEtaSize() const {
71 return m_detailedStat.perEtaSize();
72 }
73 std::size_t perPdgIdSize() const {
74 return m_detailedStat.perPdgIdSize();
75 }
76
77 template <bool DetailEnabled>
78 struct EventStatBase : public BaseStat<DetailEnabled> {
79 static constexpr bool doDetail = DetailEnabled;
80
81 EventStatBase(const IAthSelectionTool &truth_selection_tool,
82 std::size_t per_eta_size,
83 std::size_t per_pdg_size,
84 [[maybe_unused]] std::size_t track_to_truth_size)
85 : BaseStat<DetailEnabled>(truth_selection_tool, per_eta_size, per_pdg_size),
86 m_nTruthCuts(truth_selection_tool.nCuts())
87 {
88 if constexpr(DetailEnabled) {
89 m_truthParticlesWithAssociatedTrack.reserve(track_to_truth_size);
90 }
91
92 };
93 void fill([[maybe_unused]] unsigned int eta_category_i,
94 [[maybe_unused]] unsigned int pdg_id_category_i,
95 [[maybe_unused]] float hit_efficiency,
96 [[maybe_unused]] float hit_purity,
97 [[maybe_unused]] float match_prob,
98 [[maybe_unused]] const xAOD::TruthParticle *best_match) {
99 BaseStat<DetailEnabled>::fill(eta_category_i,
100 pdg_id_category_i,
101 hit_efficiency,
102 hit_purity,
103 match_prob);
104 if constexpr(DetailEnabled) {
105 if (!m_truthParticlesWithAssociatedTrack.insert(best_match).second) {
106 // truth particle already had a best match
109 }
110 else {
111 ++this->m_counterPerEta[eta_category_i][kNParticleWithAssociatedTrack];
112 ++this->m_counterPerPdgId[pdg_id_category_i][kNParticleWithAssociatedTrack];
113 }
114 }
115 }
116 using TruthParticleSet = std::conditional< DetailEnabled,
117 std::unordered_set<const xAOD::TruthParticle *>,
120
125
126 unsigned int m_nTruthCuts;
127 };
129
138
142 analyseTrackTruth(const TruthParticleHitCounts &truth_particle_hit_counts,
143 const HitCountsPerTrack &track_hit_counts,
144 EventStat &event_stat) const;
145
146 void postProcessEventStat(const TruthParticleHitCounts &truth_particle_hit_counts,
147 std::size_t n_tracks,
148 EventStat &event_stat) const;
149
150 private:
152 {this, "TruthParticleHitCounts","", "Map from truth particle to hit counts." };
153
154 Gaudi::Property<std::vector<float> > m_weightsForProb
155 {this, "MatchWeights", {}, "Weights applied to the counts per measurement type for weighted sums"
156 " which are used compute the match probability." };
157 Gaudi::Property<std::vector<float> > m_weights
158 {this, "CountWeights", {}, "Weights applied to the counts per measurement type for weighted sums"
159 " which are used to compute hit efficiencies and purities." };
160
161 // Empty struct emulating the interface of a Gaudi property to replace optional properties if disabled.
162 template <class Base>
164 template <class OWNER>
165 DummyProperty( OWNER*, std::string, Base&&, std::string ) {}
166 Base value() const { return Base{}; }
167 operator Base() const { return Base{}; }
168
169 // some dummy implementations for vector properties:
170 std::size_t size() const {return 0u; }
171 bool empty() const {return true; }
172 auto operator[](std::size_t /*idx*/) { throw std::out_of_range("DummyProperty");}
173
174 // Delegate operator() to the value
175 template <class... Args>
176 decltype( std::declval<Base>()( std::declval<Args&&>()... ) ) operator()( Args&&... args ) const
177 noexcept( noexcept( std::declval<Base>()( std::declval<Args&&>()... ) ) ) {
178 return value()( std::forward<Args>( args )... );
179 }
180 };
181
182 template <class Base>
183 using Property = std::conditional< TrackFindingValidationDetailedStat, Gaudi::Property<Base>, DummyProperty<Base> >::type;
184
186 {this, "StatisticEtaBins", {-4, -2.6, -2, 0, 2., 2.6, 4}, "Gather statistics separately for these eta bins."};
188 {this, "StatisticPtBins", {1.e3,2.5e3,10e3, 100e3}, "Gather statistics separately for these pt bins."};
190 {this, "PdgIdCategorisation", false, "Categorise by pdg id."};
192 {this, "ShowRawCounts", false, "Show all counters."};
194 {this, "ShowDetailedTables", false, "Show more details; stat. uncert., RMS, entries"};
196 {this, "ComputeTrackRecoEfficiency", true, "Compute and print track reconstruction efficiency."};
197
198 ToolHandle<IAthSelectionTool> m_truthSelectionTool{this, "TruthSelectionTool","AthTruthSelectionTool", "Truth selection tool (for efficiencies and resolutions)"};
199
200
201 // helper struct for compile time optional statistics
202 template <bool IsDebug>
204 struct Empty {
205 template <typename... T_Args>
206 Empty(T_Args... ) {}
207 };
208 mutable typename std::conditional<IsDebug,
209 std::mutex,
211 mutable typename std::conditional<IsDebug,
213 Empty>::type m_measPerTruthParticleWithoutCounts ATLAS_THREAD_SAFE {20,-.5,20.-.5};
214 mutable typename std::conditional<IsDebug,
216 Empty>::type m_bestMatchProb ATLAS_THREAD_SAFE {20,0.,1.};
217 mutable typename std::conditional<IsDebug,
219 Empty>::type m_nextToBestMatchProb ATLAS_THREAD_SAFE {20,0.,1.};
220
221 template <class T_OutStream>
222 void dumpStatistics(T_OutStream &out) const;
223 void fillMeasForTruthParticleWithoutCount(double weighted_measurement_sum) const;
224 void fillTruthMatchProb(const std::array<float,2> &best_match_prob) const;
225 };
227
228 // s_NMeasurementTypes is equal to the number of UncalibMeasType
229 constexpr static unsigned int s_NMeasurementTypes = static_cast<unsigned int>(xAOD::UncalibMeasType::nTypes);
230
231 // statistics counter
241
255
256 constexpr static int s_pdgIdMax = 1000000000; // categorise all truth particles with this or larger PDG ID as "Other"
257
258
259 bool m_useAbsEtaForStat = false;
260
261 template <bool DetailEnabled>
262 struct BaseStat {
263 BaseStat() = default;
264 BaseStat([[maybe_unused]] const IAthSelectionTool &truth_selection_tool,
265 [[maybe_unused]] std::size_t per_eta_size,
266 [[maybe_unused]] std::size_t per_pdg_size)
267 : m_truthSelectionCuts(truth_selection_tool.nCuts()+1, -0.5,truth_selection_tool.nCuts()+.5)
268 {
269 if constexpr(DetailEnabled) {
270 m_counterPerEta.resize(per_eta_size);
271 m_counterPerPdgId.resize( per_pdg_size);
272 m_statPerEta.resize( per_eta_size );
273 m_statPerPdgId.resize( per_pdg_size );
274 }
275
276 }
277 void reset(const IAthSelectionTool &truth_selection_tool,
278 [[maybe_unused]] std::size_t per_eta_size,
279 [[maybe_unused]] std::size_t per_pdg_size)
280 {
281 m_truthSelectionCuts.setBinning(truth_selection_tool.nCuts()+1, -0.5,truth_selection_tool.nCuts()+.5);
282 if constexpr(DetailEnabled) {
283 m_counterPerEta.clear();
284 m_counterPerPdgId.clear();
285 m_statPerEta.clear();
286 m_statPerPdgId.clear();
287 m_counterPerEta.resize(per_eta_size);
288 m_counterPerPdgId.resize( per_pdg_size);
289 m_statPerEta.resize( per_eta_size );
290 m_statPerPdgId.resize( per_pdg_size );
291 }
292 }
293 void fill([[maybe_unused]] unsigned int eta_category_i,
294 [[maybe_unused]] unsigned int pdg_id_category_i,
295 [[maybe_unused]] float hit_efficiency,
296 [[maybe_unused]] float hit_purity,
297 [[maybe_unused]] float match_prob) {
298 if (DetailEnabled) {
299 assert( eta_category_i <m_statPerEta.size());
300 m_statPerEta[eta_category_i][kHitEfficiency].add( hit_efficiency);
301 m_statPerEta[eta_category_i][kHitPurity].add( hit_purity);
302 m_statPerEta[eta_category_i][kMatchProbability].add( match_prob);
303 assert( pdg_id_category_i <m_statPerPdgId.size());
304 m_statPerPdgId[pdg_id_category_i][kHitEfficiency].add( hit_efficiency);
305 m_statPerPdgId[pdg_id_category_i][kHitPurity].add( hit_purity);
306 m_statPerPdgId[pdg_id_category_i][kMatchProbability].add( match_prob);
307 assert( eta_category_i < m_counterPerEta.size());
308 assert( pdg_id_category_i <m_counterPerPdgId.size());
309 ++m_counterPerEta[eta_category_i][kNTotalTracks];
310 ++m_counterPerPdgId[pdg_id_category_i][kNTotalTracks];
311 }
312 }
313 void incrementTotal([[maybe_unused]] unsigned int eta_category_i,
314 [[maybe_unused]] unsigned int pdg_id_category_i) {
315 if constexpr(DetailEnabled) {
316 ++m_counterPerEta[eta_category_i][kNTotalParticles];
317 ++m_counterPerPdgId[pdg_id_category_i][kNTotalParticles];
318 }
319 }
320
322
324 const std::vector<float> &statPtBins,
325 const std::vector<float> &statEtaBins,
326 std::vector< int > &pdgId,
327 bool printDetails,
328 bool pdgIdCategorisation,
329 bool useAbsEtaForStat);
330
331
332 std::size_t perEtaSize() const {
333 if constexpr(DetailEnabled) { return m_counterPerEta.size(); }
334 else { return 0u; }
335 }
336 std::size_t perPdgIdSize() const {
337 if constexpr(DetailEnabled) { return m_counterPerPdgId.size(); }
338 else { return 0u; }
339 }
341 // per event statistics
342 struct Empty {};
343 using CounterArrayVec = std::conditional< DetailEnabled,
344 std::vector< std::array< std::size_t, kNCategorisedCounter> >,
345 Empty >::type;
346 using StatArrayVec = std::conditional< DetailEnabled,
347 std::vector< std::array<ActsUtils::Stat, kNCategorisedStat> >,
348 Empty >::type;
353
354 };
355
356
357 mutable std::mutex m_statMutex ATLAS_THREAD_SAFE;
358 mutable std::array< std::size_t, kNCounter > m_counter ATLAS_THREAD_SAFE {};
359 mutable std::vector< int > m_pdgId ATLAS_THREAD_SAFE;
361
364 void checkBinOrder( const std::vector<float> &bin_edges, const std::string &bin_label) const;
365
370 std::size_t getPtEtaStatCategory(float pt, float eta) const;
371
376 std::size_t getPtPdgIdStatCategory(float pt, int pdg_id) const;
377 void initStatTables();
378 void printStatTables() const;
379 void printCategories(const std::vector<std::string> &pt_category_labels,
380 const std::vector<std::string> &eta_category_labels,
381 std::vector<std::string> &counter_labels,
382 std::vector< std::array< ActsUtils::Stat, kNCategorisedStat> > &stat_per_category,
383 std::vector< std::array< std::size_t, kNCategorisedCounter> > &counts_per_category,
384 const std::string &top_left_label,
385 bool print_sub_categories) const;
386 void printData2D(const std::vector<std::string> &row_category_labels,
387 const std::vector<std::string> &col_category_labels,
388 const std::string &top_left_label,
389 std::vector< std::array< ActsUtils::Stat, kNCategorisedStat> > &stat_per_category,
390 std::vector< std::array< std::size_t, kNCategorisedCounter> > &counts_per_category,
391 bool rotate) const;
392
393 StatusCode checkMatchWeights();
394
395 static double weightedCountSum(const ActsTrk::HitCounterArray &counts,
396 const std::vector<float> &weights);
397 static double noiseCorrection(const ActsTrk::HitCounterArray &noise_counts,
398 const std::vector<float> &weights);
399
400 };
401
402} // namespace
403
404#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
const IAthSelectionTool & truthSelectionTool() const
std::conditional< TrackFindingValidationDetailedStat, Gaudi::Property< Base >, DummyProperty< Base > >::type Property
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)
Property< std::vector< float > > m_statPtBins
void postProcessEventStat(const TruthParticleHitCounts &truth_particle_hit_counts, std::size_t n_tracks, EventStat &event_stat) const
Gaudi::Property< std::vector< float > > m_weightsForProb
std::size_t getPtEtaStatCategory(float pt, float eta) const
Return the category based on the provided eta value.
TrackTruthMatchingBaseAlg(const std::string &name, ISvcLocator *pSvcLocator)
Property< std::vector< float > > m_statEtaBins
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.
doing TRTHTH Hypo selection
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.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
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
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
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
DummyProperty(OWNER *, std::string, Base &&, std::string)
decltype(std::declval< Base >()(std::declval< Args && >()...)) operator()(Args &&... args) const noexcept(noexcept(std::declval< Base >()(std::declval< Args && >()...)))
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< DetailEnabled, std::unordered_set< const xAOD::TruthParticle * >, typename BaseStat< DetailEnabled >::Empty >::type 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