ATLAS Offline Software
Loading...
Searching...
No Matches
DefectsEmulatorBase.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 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 if (!surface_ptr) return;
65 const Acts::Surface &surface = *surface_ptr;
66 const Acts::DetectorElementBase*detector_element = surface.associatedDetectorElement();
67 if (detector_element) {
68 const ActsDetectorElement *acts_detector_element = dynamic_cast<const ActsDetectorElement*>(detector_element);
69 if (acts_detector_element) {
70 if (setModuleData(*acts_detector_element, module_data)) {
71 ModuleIdentifierMatchUtil::moduleMatches(m_modulePattern.value(), module_data, module_pattern_idx);
72 if (module_pattern_idx.empty()) {
73 ++counter.n_no_matching_pattern;
74 }
75 else {
76 m_noiseParamIdx.at(acts_detector_element->identifyHash()) = module_pattern_idx.front();
77 }
78 ++counter.n_detector_elements_of_correct_type;
79 }
80 }
81 else {
82 ++counter.n_wrong_type;
83 }
84 ++counter.n_detector_elements;
85 }
86 else {
87 ++counter.n_missing_detector_elements;
88 }
89 }, true /*sensitive surfaces*/);
90 ATH_MSG_DEBUG("Visited surfaces with " << counter.n_detector_elements << " / "
91 << (counter.n_missing_detector_elements + counter.n_detector_elements)
92 << " (wrong type " << counter.n_wrong_type << ")"
93 << " expected detector type " << counter.n_detector_elements_of_correct_type
94 << " without match " << counter.n_no_matching_pattern);
95 if (counter.n_missing_detector_elements || counter.n_wrong_type>0) {
96 ATH_MSG_ERROR("Encountered " << counter.n_wrong_type << " associated detector elements with wrong type and "
97 << counter.n_missing_detector_elements << " surfaces without detector element.");
98 }
99
100 // create normalised cummulative distributions of noise shape distributions
102 unsigned int pattern_i=0;
103 for (const std::vector<double> &shape : m_noiseShape.value()) {
104 m_noiseShapeCummulative[pattern_i].reserve( shape.size());
105 double scale=std::accumulate(shape.begin(), shape.end(),0.);
106 if (std::abs(scale-1.)>1e-5) {
107 ATH_MSG_FATAL("Noise shape integral for pattern " << pattern_i << " not 1. but " << scale);
108 return StatusCode::FAILURE;
109 }
110 scale = 1./scale;
111 double sum =0.;
112 for (double value : shape) {
113 sum += value * scale;
114 m_noiseShapeCummulative[pattern_i].push_back( sum );
115 }
116 m_maxNShape=std::max(m_maxNShape,static_cast<unsigned int>(shape.size()));
117 ++pattern_i;
118 }
120 }
121
122 if (!m_histSvc.name().empty() && !m_histogramGroupName.value().empty()) {
123 ATH_CHECK( m_histSvc.retrieve() );
124 // reserve space for histograms for 6 different sensor types
125 constexpr unsigned int n_different_pixel_matrices_max=6;
126 m_dimPerHist.reserve(n_different_pixel_matrices_max);
127 for (unsigned int hist_type_i=0; hist_type_i<kNHistTypes; ++hist_type_i) {
128 m_hist[hist_type_i].reserve(n_different_pixel_matrices_max);
129 }
130
131 // create per id-hash histograms
132 m_noiseShapeHist.reserve(n_different_pixel_matrices_max);
133
134 unsigned int max_y_axis = (((wafer_hash_max+99)/100+9)/10)*10;
135 for (unsigned int hist_type_i=0; hist_type_i<kNHistTypes; ++hist_type_i) {
136 {
137 HistUtil::StringCat hist_name;
138 hist_name << s_histNames.at(hist_type_i) << "_hits_per_module";
139 HistUtil::StringCat hist_title;
140 hist_title << s_histTitles.at(hist_type_i) << " hits per module";
141
142 HistUtil::ProtectHistogramCreation protect;
143 m_moduleHist.at(hist_type_i) = new TH2F(hist_name.str().c_str(), hist_title.str().c_str(),
144 100, -0.5, 100-0.5,
145 max_y_axis, -0.5, max_y_axis-0.5
146 );
147 }
148 m_moduleHist[hist_type_i]->GetXaxis()->SetTitle("ID hash % 100");
149 m_moduleHist[hist_type_i]->GetYaxis()->SetTitle("ID hash / 100");
150 if ( m_histSvc->regHist(m_histogramGroupName.value() + m_moduleHist[hist_type_i]->GetName(),m_moduleHist[hist_type_i]).isFailure() ) {
151 return StatusCode::FAILURE;
152 }
153 }
155 }
156 return StatusCode::SUCCESS;
157 }
159 ATH_MSG_INFO( "Total number of rejected RDOs " << m_rejectedRDOs << ", kept " << m_totalRDOs
160 << (m_splitRDOs>0 ? (", split " + std::to_string(m_splitRDOs) ) : "")
161 << ", additional noise " << m_totalNoise);
162 return StatusCode::SUCCESS;
163 }
164
165 std::tuple<TH2 *,TH2 *, TH1 *> DefectsEmulatorBase::findHist(unsigned int n_rows, unsigned int n_cols) const {
166 unsigned int key=(n_rows << 16) | n_cols;
167 std::vector<unsigned int>::const_iterator iter = std::find(m_dimPerHist.begin(),m_dimPerHist.end(), key );
168 if (iter == m_dimPerHist.end()) {
169 if (m_dimPerHist.size() == m_dimPerHist.capacity()) {
170 if (m_dimPerHist.capacity()==0) {
171 return std::make_tuple(nullptr,nullptr,nullptr);
172 }
173 else {
174 return std::make_tuple(m_hist[kRejectedHits].back(),
175 m_hist[kNoiseHits].empty() ? nullptr : m_hist[kNoiseHits].back(),
176 m_noiseShapeHist.empty() ? nullptr : m_noiseShapeHist.back());
177 }
178 }
179 else {
180 // if no "sensor" with this dimensions has been registered yet, create histograms
181 // and register it.
182 for (unsigned int hist_type_i=0; hist_type_i<kNHistTypes; ++hist_type_i) {
184 name << s_histNames.at(hist_type_i) << "_hits_" << n_rows << "_" << n_cols;
186 title << s_histTitles.at(hist_type_i) << "hits for " << n_rows << "(rows) #times " << n_cols << " (columns)";
187 {
189 m_hist.at(hist_type_i).push_back(new TH2F(name.str().c_str(), title.str().c_str(),
190 n_cols, -0.5, n_cols-0.5,
191 n_rows, -0.5, n_rows-0.5
192 ));
193 }
194 m_hist[hist_type_i].back()->GetXaxis()->SetTitle("offline column");
195 m_hist[hist_type_i].back()->GetYaxis()->SetTitle("offline row");
196 if ( m_histSvc->regHist(m_histogramGroupName.value() + name.str(),m_hist[hist_type_i].back()).isFailure() ) {
197 throw std::runtime_error("Failed to register histogram.");
198 }
199 }
200 {
201 std::stringstream name;
202 name << "noise_shape_" << n_rows << "_" << n_cols;
203 std::stringstream title;
204 title << "Noise shape for " << n_rows << "(rows) #times " << n_cols << " (columns)";
205 m_noiseShapeHist.push_back(new TH1F(name.str().c_str(), title.str().c_str(), m_maxNShape+1, -0.5, m_maxNShape+.5));
206 m_noiseShapeHist.back()->GetXaxis()->SetTitle("offline column");
207 m_noiseShapeHist.back()->GetYaxis()->SetTitle("offline row");
208 if ( m_histSvc->regHist(m_histogramGroupName.value() + name.str(),m_noiseShapeHist.back()).isFailure() ) {
209 throw std::runtime_error("Failed to register histogram.");
210 }
211 }
212 m_dimPerHist.push_back(key);
213 return std::make_tuple(m_hist[kRejectedHits].back(),
214 m_hist[kNoiseHits].empty() ? nullptr : m_hist[kNoiseHits].back(),
215 m_noiseShapeHist.empty() ? nullptr : m_noiseShapeHist.back()
216 );
217 }
218 }
219 else {
220 return std::make_tuple(m_hist[kRejectedHits].at(iter-m_dimPerHist.begin()),
221 m_hist[kNoiseHits].empty() ? nullptr : m_hist[kNoiseHits].at(iter-m_dimPerHist.begin()),
222 m_noiseShapeHist.empty() ? nullptr : m_noiseShapeHist.at(iter-m_dimPerHist.begin()));
223 }
224 }
225
226}// namespace closure
#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
IdentifierHash identifyHash() const
Identifier hash.
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)