ATLAS Offline Software
Loading...
Searching...
No Matches
DefectsEmulatorBase.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
5#include "TH2.h"
6#include <sstream>
7#include "HistUtil.h"
8#include "Acts/Surfaces/Surface.hpp"
9#include "Acts/Geometry/TrackingGeometry.hpp"
10
11namespace InDet{
12 const std::array<std::string_view,DefectsEmulatorBase::kNHistTypes> DefectsEmulatorBase::s_histNames{
13 "rejected",
14 "noise"
15 };
16 const std::array<std::string_view,DefectsEmulatorBase::kNHistTypes> DefectsEmulatorBase::s_histTitles{
17 "Rejected",
18 "Noise"
19 };
20
21 DefectsEmulatorBase::DefectsEmulatorBase(const std::string &name, ISvcLocator *pSvcLocator)
22 : AthReentrantAlgorithm(name, pSvcLocator)
23 {}
24
25 StatusCode DefectsEmulatorBase::initializeBase(unsigned int wafer_hash_max){
26 ATH_CHECK( m_trackingGeometryTool.retrieve( DisableTool{m_noiseProbability.empty()} ));
27 if (!m_noiseProbability.value().empty()) {
28 if (m_modulePattern.value().size() != m_noiseProbability.value().size()) {
29 ATH_MSG_FATAL("Number of module patterns and noise probabilities differs: "
30 << m_modulePattern.value().size() << " != " << m_noiseProbability.size() );
31 return StatusCode::FAILURE;
32 }
33
34 if (m_noiseProbability.value().size() != m_noiseShape.value().size()) {
35 ATH_MSG_FATAL("Number of noise probabilities and number of noise shapes differs: "
36 << m_noiseProbability.size() << " != " << m_noiseShape.size());
37 return StatusCode::FAILURE;
38 }
39 ATH_CHECK(m_rndmSvc.retrieve());
40 m_rngName = name()+"RandomEngine";
41
42 if (wafer_hash_max>std::numeric_limits<unsigned short>::max()) {
43 ATH_MSG_FATAL("Maximjum wafer hash too large (" << wafer_hash_max
44 << "). This algorithm only supports wafer hashes up to "
45 << std::numeric_limits<unsigned short>::max());
46 return StatusCode::FAILURE;
47 }
48 m_noiseParamIdx.resize(wafer_hash_max, static_cast<unsigned short>(m_noiseProbability.size()));
50 std::shared_ptr<const Acts::TrackingGeometry> tracking_geometry = m_trackingGeometryTool->trackingGeometry();
51
53 std::vector<unsigned int> module_pattern_idx;
54 module_pattern_idx.reserve( m_modulePattern.value().size() );
55
56 // Associate noise probabilities and noise shapes to module identifier hashes.
57 // The association is done according to the module match criteria. The derived
58 // class has to ensure that only modules with umambigous identifier hash are
59 // considered.
60 using Counter = struct { unsigned int n_detector_elements, n_missing_detector_elements, n_wrong_type,
61 n_no_matching_pattern, n_detector_elements_of_correct_type; };
62 Counter counter {0u,0u,0u,0u,0u};
63 tracking_geometry->visitSurfaces([&counter, &module_data, &module_pattern_idx, this](const Acts::Surface *surface_ptr) {
64
65 const auto *acts_detector_element = getActsDetectorElement(surface_ptr);
66
67 if (!acts_detector_element) return;
68 if (setModuleData(*acts_detector_element, module_data)) {
69 ModuleIdentifierMatchUtil::moduleMatches(m_modulePattern.value(), module_data, module_pattern_idx);
70 if (module_pattern_idx.empty()) {
71 ++counter.n_no_matching_pattern;
72 } else {
73 m_noiseParamIdx.at(acts_detector_element->identifyHash()) = module_pattern_idx.front();
74 }
75 ++counter.n_detector_elements_of_correct_type;
76 }
77 }, true /*sensitive surfaces*/);
78 ATH_MSG_DEBUG("Visited surfaces with " << counter.n_detector_elements << " / "
79 << (counter.n_missing_detector_elements + counter.n_detector_elements)
80 << " (wrong type " << counter.n_wrong_type << ")"
81 << " expected detector type " << counter.n_detector_elements_of_correct_type
82 << " without match " << counter.n_no_matching_pattern);
83 if (counter.n_missing_detector_elements || counter.n_wrong_type>0) {
84 ATH_MSG_ERROR("Encountered " << counter.n_wrong_type << " associated detector elements with wrong type and "
85 << counter.n_missing_detector_elements << " surfaces without detector element.");
86 }
87
88 // create normalised cummulative distributions of noise shape distributions
90 unsigned int pattern_i=0;
91 for (const std::vector<double> &shape : m_noiseShape.value()) {
92 m_noiseShapeCummulative[pattern_i].reserve( shape.size());
93 double scale=std::accumulate(shape.begin(), shape.end(),0.);
94 if (std::abs(scale-1.)>1e-5) {
95 ATH_MSG_FATAL("Noise shape integral for pattern " << pattern_i << " not 1. but " << scale);
96 return StatusCode::FAILURE;
97 }
98 //coverity[DIVIDE_BY_ZERO:FALSE]
99 scale = 1./scale;
100 double sum =0.;
101 for (double value : shape) {
102 sum += value * scale;
103 m_noiseShapeCummulative[pattern_i].push_back( sum );
104 }
105 m_maxNShape=std::max(m_maxNShape,static_cast<unsigned int>(shape.size()));
106 ++pattern_i;
107 }
109 }
110
111 if (!m_histSvc.name().empty() && !m_histogramGroupName.value().empty()) {
112 ATH_CHECK( m_histSvc.retrieve() );
113 // reserve space for histograms for 6 different sensor types
114 constexpr unsigned int n_different_pixel_matrices_max=6;
115 m_dimPerHist.reserve(n_different_pixel_matrices_max);
116 for (unsigned int hist_type_i=0; hist_type_i<kNHistTypes; ++hist_type_i) {
117 m_hist[hist_type_i].reserve(n_different_pixel_matrices_max);
118 }
119
120 // create per id-hash histograms
121 m_noiseShapeHist.reserve(n_different_pixel_matrices_max);
122
123 unsigned int max_y_axis = (((wafer_hash_max+99)/100+9)/10)*10;
124 for (unsigned int hist_type_i=0; hist_type_i<kNHistTypes; ++hist_type_i) {
125 {
126 HistUtil::StringCat hist_name;
127 hist_name << s_histNames.at(hist_type_i) << "_hits_per_module";
128 HistUtil::StringCat hist_title;
129 hist_title << s_histTitles.at(hist_type_i) << " hits per module";
130
131 HistUtil::ProtectHistogramCreation protect;
132 m_moduleHist.at(hist_type_i) = new TH2F(hist_name.str().c_str(), hist_title.str().c_str(),
133 100, -0.5, 100-0.5,
134 max_y_axis, -0.5, max_y_axis-0.5
135 );
136 }
137 m_moduleHist[hist_type_i]->GetXaxis()->SetTitle("ID hash % 100");
138 m_moduleHist[hist_type_i]->GetYaxis()->SetTitle("ID hash / 100");
139 if ( m_histSvc->regHist(m_histogramGroupName.value() + m_moduleHist[hist_type_i]->GetName(),m_moduleHist[hist_type_i]).isFailure() ) {
140 return StatusCode::FAILURE;
141 }
142 }
144 }
145 return StatusCode::SUCCESS;
146 }
148 ATH_MSG_INFO( "Total number of rejected RDOs " << m_rejectedRDOs << ", kept " << m_totalRDOs
149 << (m_splitRDOs>0 ? (", split " + std::to_string(m_splitRDOs) ) : "")
150 << ", additional noise " << m_totalNoise);
151 return StatusCode::SUCCESS;
152 }
153
154 std::tuple<TH2 *,TH2 *, TH1 *> DefectsEmulatorBase::findHist(unsigned int n_rows, unsigned int n_cols) const {
155 unsigned int key=(n_rows << 16) | n_cols;
156 std::vector<unsigned int>::const_iterator iter = std::find(m_dimPerHist.begin(),m_dimPerHist.end(), key );
157 if (iter == m_dimPerHist.end()) {
158 if (m_dimPerHist.size() == m_dimPerHist.capacity()) {
159 if (m_dimPerHist.capacity()==0) {
160 return std::make_tuple(nullptr,nullptr,nullptr);
161 }
162 else {
163 return std::make_tuple(m_hist[kRejectedHits].back(),
164 m_hist[kNoiseHits].empty() ? nullptr : m_hist[kNoiseHits].back(),
165 m_noiseShapeHist.empty() ? nullptr : m_noiseShapeHist.back());
166 }
167 }
168 else {
169 // if no "sensor" with this dimensions has been registered yet, create histograms
170 // and register it.
171 for (unsigned int hist_type_i=0; hist_type_i<kNHistTypes; ++hist_type_i) {
173 name << s_histNames.at(hist_type_i) << "_hits_" << n_rows << "_" << n_cols;
175 title << s_histTitles.at(hist_type_i) << "hits for " << n_rows << "(rows) #times " << n_cols << " (columns)";
176 {
178 m_hist.at(hist_type_i).push_back(new TH2F(name.str().c_str(), title.str().c_str(),
179 n_cols, -0.5, n_cols-0.5,
180 n_rows, -0.5, n_rows-0.5
181 ));
182 }
183 m_hist[hist_type_i].back()->GetXaxis()->SetTitle("offline column");
184 m_hist[hist_type_i].back()->GetYaxis()->SetTitle("offline row");
185 if ( m_histSvc->regHist(m_histogramGroupName.value() + name.str(),m_hist[hist_type_i].back()).isFailure() ) {
186 throw std::runtime_error("Failed to register histogram.");
187 }
188 }
189 {
190 std::stringstream name;
191 name << "noise_shape_" << n_rows << "_" << n_cols;
192 std::stringstream title;
193 title << "Noise shape for " << n_rows << "(rows) #times " << n_cols << " (columns)";
194 m_noiseShapeHist.push_back(new TH1F(name.str().c_str(), title.str().c_str(), m_maxNShape+1, -0.5, m_maxNShape+.5));
195 m_noiseShapeHist.back()->GetXaxis()->SetTitle("offline column");
196 m_noiseShapeHist.back()->GetYaxis()->SetTitle("offline row");
197 if ( m_histSvc->regHist(m_histogramGroupName.value() + name.str(),m_noiseShapeHist.back()).isFailure() ) {
198 throw std::runtime_error("Failed to register histogram.");
199 }
200 }
201 m_dimPerHist.push_back(key);
202 return std::make_tuple(m_hist[kRejectedHits].back(),
203 m_hist[kNoiseHits].empty() ? nullptr : m_hist[kNoiseHits].back(),
204 m_noiseShapeHist.empty() ? nullptr : m_noiseShapeHist.back()
205 );
206 }
207 }
208 else {
209 return std::make_tuple(m_hist[kRejectedHits].at(iter-m_dimPerHist.begin()),
210 m_hist[kNoiseHits].empty() ? nullptr : m_hist[kNoiseHits].at(iter-m_dimPerHist.begin()),
211 m_noiseShapeHist.empty() ? nullptr : m_noiseShapeHist.at(iter-m_dimPerHist.begin()));
212 }
213 }
214
215}// namespace closure
const ActsDetectorElement * getActsDetectorElement(const Acts::Surface &surf)
Attempts to retrieve the ActsDetectorElement associated to the passed ActsSurface.
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
static const Attributes_t empty
An algorithm that can be simultaneously executed in multiple threads.
const std::string & str() const
Definition HistUtil.h:47
std::atomic< std::size_t > m_rejectedRDOs
virtual bool setModuleData(const ActsDetectorElement &acts_detector_element, ModuleIdentifierMatchUtil::ModuleData_t &module_data) const =0
Set the module data for matching for the given detector element.
static const std::array< std::string_view, kNHistTypes > s_histTitles
PublicToolHandle< ActsTrk::ITrackingGeometryTool > m_trackingGeometryTool
std::atomic< std::size_t > m_totalNoise
std::atomic< std::size_t > m_totalRDOs
StatusCode initializeBase(unsigned int wafer_hash_max)
static const std::array< std::string_view, kNHistTypes > s_histNames
std::tuple< TH2 *, TH2 *, TH1 * > findHist(unsigned int n_rows, unsigned int n_cols) const
Get rejected hits and noise histograms for a certain module design.
std::atomic< std::size_t > m_splitRDOs
ServiceHandle< IAthRNGSvc > m_rndmSvc
std::vector< std::vector< float > > m_noiseShapeCummulative
Gaudi::Property< std::vector< std::vector< int > > > m_modulePattern
Gaudi::Property< std::string > m_histogramGroupName
ServiceHandle< ITHistSvc > m_histSvc
std::vector< unsigned short > m_noiseParamIdx
Gaudi::Property< std::vector< std::vector< double > > > m_noiseShape
Gaudi::Property< std::vector< float > > m_noiseProbability
DefectsEmulatorBase(const std::string &name, ISvcLocator *pSvcLocator)
virtual StatusCode finalize() override
std::array< int, ModuleIdentifierMatchUtil::kAllRows/2 > ModuleData_t
void moduleMatches(const std::vector< std::vector< int > > &module_pattern, const ModuleData_t &module_data, std::vector< unsigned int > &module_pattern_idx)
Test whether an identifier, which is split into various parts, matches some of the given patterns.
Primary Vertex Finder.
TH2F(name, title, nxbins, bins_par2, bins_par3, bins_par4, bins_par5=None, bins_par6=None, path='', **kwargs)