ATLAS Offline Software
Loading...
Searching...
No Matches
DeviceDetectorDescriptionSvc.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
7
8#include <cmath>
9#include <optional>
10
11namespace ActsTrk {
12
13std::vector<traccc::scalar> makeEquidistantEdges(float halfWidth, int nBins) {
14 std::vector<traccc::scalar> edges;
15 edges.reserve(nBins + 1);
16 const float min = -halfWidth;
17 const float pitch = (2.f * halfWidth) / static_cast<float>(nBins);
18 for (int i = 0; i <= nBins; ++i) {
19 edges.push_back(static_cast<traccc::scalar>(min + static_cast<float>(i) * pitch));
20 }
21 return edges;
22}
23
25{
26 ATH_MSG_DEBUG("Initializing device detector description provider service ");
27
28 ATH_CHECK(m_MRs.retrieve());
29 ATH_CHECK(m_copy.retrieve());
30 ATH_CHECK(m_detStore.retrieve());
31
34 ATH_CHECK(m_detStore->retrieve(m_pixelManager, "ITkPixel"));
35 ATH_CHECK(m_detStore->retrieve(m_stripManager, "ITkStrip"));
36
37 std::map<Acts::GeometryIdentifier, Identifier> actsToAthena;
38 std::unordered_map<uint64_t, Identifier> detrayToAthenaMap;
39 std::unordered_map<Identifier, uint64_t> athenaToDetrayMap;
40
41 int nPix = 0, nStrip = 0, nEC = 0, nBar = 0;
42 std::vector<Acts::GeometryIdentifier> actsHGTD;
43 if (!m_trackingGeometrySvc.empty()) {
44
45 // ---- 1. Get ACTS Tracking Geometry, populate Athena<->ACTS maps and fill module design (segmentation) information ----
46 // all of these are static upon construction through the run
47
49 m_trackingGeometry = m_trackingGeometrySvc->trackingGeometry();
50
51 m_trackingGeometry->visitSurfaces([&](const Acts::Surface *surface) {
52 if (!surface) return;
53 const auto *actsElement = getActsDetectorElement(surface);
54 if (!actsElement){
55 ATH_MSG_DEBUG("Could not find matching Acts detector element for surface with geometryId " << surface->geometryId());
56 return;
57 }
58
59 const ActsTrk::DetectorType detType = actsElement->detectorType();
60 if (detType == ActsTrk::DetectorType::Hgtd) {
61 // skip HGTD surfaces for now
62 // currently no time info is being used in traccc
63 ATH_MSG_VERBOSE("Found HGTD surface with geometryId " << surface->geometryId());
64 actsHGTD.push_back(surface->geometryId());
65 return;
66 }
67 if (detType != ActsTrk::DetectorType::Pixel && detType != ActsTrk::DetectorType::Sct) {
68 ATH_MSG_DEBUG("Found non-pixel, non-strip detector element with geometryId " << surface->geometryId());
69 return;
70 }
71 const auto *detElem = dynamic_cast<const InDetDD::SiDetectorElement*>(actsElement->upstreamDetectorElement());
72 if (!detElem) {
73 ATH_MSG_DEBUG("Could not find matching Athena silicon detector element for surface with geometryId " << surface->geometryId());
74 return;
75 }
76
77 Identifier athenaID;
78 moduleInfo thismod;
79 // NOTE: lorentz_shift_x/y intentionally left at their default
80 // (0.f) — they're not used for design-shape grouping and are
81 // computed per-IOV by DeviceDetectorDescriptionCondAlg, so no
82 // Lorentz-tool call happens here.
83
84 thismod.isAnnulus = false;
85 thismod.pixel = false;
86 thismod.equidistant_binning = true;
87
88 switch (detType) {
90 ++nPix;
91 athenaID = detElem->identify();
92 const auto* p_design = static_cast<const InDetDD::PixelModuleDesign*>(&detElem->design());
93
94 thismod.pixel = true;
95 thismod.side = 2; // for pixel
96
97 std::vector<traccc::scalar> row_centres;
98 std::vector<traccc::scalar> column_centres;
99
100 // pixels with cross design
101 // the middle four rows and columns are double pitch
102 if ((m_pixelID->barrel_ec(athenaID) == 0 && m_pixelID->layer_disk(athenaID) > 0) ||
103 (m_pixelID->barrel_ec(athenaID) != 0 && m_pixelID->layer_disk(athenaID) > 1)) {
104
105 thismod.equidistant_binning = false;
106
107 for(int row = 0; row < p_design->rows(); row++){
108
109 std::array<InDetDD::PixelDiodeTree::CellIndexType, 2>
111 row, 0);
113 p_design->diodeProxyFromIdxCachePosition(diode_idx));
114
115 (row_centres).push_back(si_param.position()[0]-0.5*si_param.width()[0]);
116 if(row == p_design->rows()-1){
117 (row_centres).push_back(si_param.position()[0]+0.5*si_param.width()[0]);
118 }
119
120 float leading_edge = si_param.position()[0] - 0.5f*si_param.width()[0];
121 float trailing_edge = si_param.position()[0] + 0.5f*si_param.width()[0];
122 float midpoint = (leading_edge + trailing_edge) / 2.f;
123 if(std::abs(midpoint - si_param.position()[0]) > 1e-6f){
124 ATH_MSG_ERROR("Row " << row << " edge midpoint " << midpoint
125 << " != geometry centre " << si_param.position()[0]
126 << " (diff=" << midpoint - si_param.position()[0] << ")");
127 }
128
129 }
130 for(int col = 0; col < p_design->columns(); col++){
131
132 std::array<InDetDD::PixelDiodeTree::CellIndexType, 2>
134 0, col);
136 p_design->diodeProxyFromIdxCachePosition(diode_idx));
137
138 (column_centres).push_back(si_param.position()[1]-0.5*si_param.width()[1]);
139 if(col == p_design->columns()-1){
140 (column_centres).push_back(si_param.position()[1]+0.5*si_param.width()[1]);
141 }
142
143 float leading_edge = si_param.position()[1] - 0.5f*si_param.width()[1];
144 float trailing_edge = si_param.position()[1] + 0.5f*si_param.width()[1];
145 float midpoint = (leading_edge + trailing_edge) / 2.f;
146 if(std::abs(midpoint - si_param.position()[1]) > 1e-6f){
147 ATH_MSG_ERROR("Column " << col << " edge midpoint " << midpoint
148 << " != geometry centre " << si_param.position()[1]
149 << " (diff=" << midpoint - si_param.position()[1] << ")");
150 }
151
152 }
153
154 }
155
156 thismod.row_centres = std::move(row_centres);
157 thismod.column_centres = std::move(column_centres);
158
159 thismod.module_width = p_design->width();
160 thismod.module_length = p_design->length();
161 thismod.rows = p_design->rows();
162 thismod.columns = p_design->columns();
163 break;
164 }
166 ++nStrip;
167 const Identifier moduleID = m_stripID->module_id(detElem->identify());
168 const IdentifierHash moduleHash = m_stripID->wafer_hash(moduleID);
169 const int side = m_stripID->side(detElem->identify());
170 athenaID = m_stripID->wafer_id(moduleHash + side);
171
172 thismod.pixel = false;
173 thismod.side = side;
174 thismod.columns = 1; // for strip
175
176 if (m_stripID->barrel_ec(athenaID) == 0) {
177 ++nBar;
178 const auto* s_design = static_cast<const InDetDD::SCT_BarrelModuleSideDesign*>(&detElem->design());
179
180 thismod.module_width = s_design->width();
181 thismod.module_length = s_design->length();
182 thismod.rows = s_design->cells();
183 } else {
184 ++nEC;
185 const auto* annulus_design = static_cast<const InDetDD::StripStereoAnnulusDesign*>(&detElem->design());
186 const InDetDD::SiCellId annulus_cell = detElem->cellIdFromIdentifier(athenaID);
187 const double pitch_row = annulus_design->phiPitchPhi(annulus_cell);
188 const int nDiodes = annulus_design->diodesInRow(0.);
189 const double max_phi = nDiodes * pitch_row;
190 thismod.module_width = -max_phi;
191 // this could be the halfway point in radius, number is arbitrary
192 // const double radius = annulus_design->centreR();
193 thismod.module_length = 0.2; //radius;
194 thismod.rows = nDiodes;
195 thismod.isAnnulus = true;
196 }
197 break;
198 }
199 default:
200 // unreachable, see filter above
201 //coverity[DEADCODE]
202 return;
203 }
204
205 m_atlasModuleInfo[athenaID] = std::move(thismod);
206 const auto geo_id = surface->geometryId();
207 actsToAthena[geo_id] = athenaID;
208
209 });
210
211 ATH_MSG_DEBUG(nPix << " Atlas Pixel modules found.");
212 ATH_MSG_DEBUG(nStrip << " Atlas Strip modules found, " << nBar << " in barrel and " << nEC << " in the endcap");
213 ATH_MSG_DEBUG("Wrote segmentation info for " << m_atlasModuleInfo.size() << " modules");
214
215 // ---- 2. Get Detray Tracking Geometry and populate Detray<->ACTS map ----
216 ATH_MSG_INFO("Loading detray detector");
217
218 int found_detray = 0;
219 int missing_detray = 0;
220 int missing_detray_passives = 0;
221
222 auto hostDetector = m_trackingGeometrySvc->detrayGeometry();
223 const auto& itkDetector = hostDetector->as<traccc::itk_detector>();
224 for (const auto& surface : itkDetector.surfaces()) {
225 const auto geo_id = surface.source;
226 const Acts::GeometryIdentifier acts_geom_id{geo_id};
227 auto sf = detray::tracking_surface{itkDetector, surface};
228 const auto detray_id = sf.identifier().value();
229
230 if (auto pIdPair = actsToAthena.find(acts_geom_id); pIdPair != actsToAthena.end()) {
231 auto athena_id = pIdPair->second;
232 detrayToAthenaMap[detray_id] = athena_id;
233 athenaToDetrayMap[athena_id] = detray_id;
234 found_detray++;
235 } else {
236 if (std::find(actsHGTD.begin(), actsHGTD.end(), acts_geom_id) != actsHGTD.end()) {
237 ATH_MSG_VERBOSE("ACTS surface with key " << acts_geom_id << " is HGTD, detray id: " << detray_id);
238 continue;
239 }
240 ATH_MSG_VERBOSE("ACTS surface with key " << acts_geom_id << " was not translated to detray geometry.");
241 missing_detray++;
242 if (surface.is_sensitive()) continue;
243 ATH_MSG_VERBOSE("found this passive surface in detray: " << acts_geom_id);
244 missing_detray_passives++;
245 }
246 }
247
248 ATH_MSG_DEBUG("Traccc detector has " << found_detray << " surfaces matching ACTS and " << missing_detray << " additional surfaces, out of which " << missing_detray_passives << " are not sensitive.");
249
250 // ---- 3. Deduplicate the designs ----
251 // there are only a handful of unique module designs, only store unique values
252 // and populate the detray<->acts<->athena geometry ID relationship map
253 std::map<designKey, unsigned int> designLookup;
254 unsigned int nextDesignId = 0;
255
256 const std::size_t nSurfaces = itkDetector.surfaces().size();
257 m_staticCondEntries.resize(nSurfaces);
258
259 auto idMapping = std::make_unique<ActsTrk::GeometryIdMapping>();
260 idMapping->reserve(nSurfaces);
261
262 for (std::size_t condIndex = 0; condIndex < nSurfaces; ++condIndex) {
263 const auto& surface = itkDetector.surfaces()[condIndex];
264 if (!surface.is_sensitive()) {
265 ATH_MSG_VERBOSE("Skipping passive surface with geometryId " << surface.source);
266 continue;
267 }
268 const auto geo_id = surface.source;
269 const Acts::GeometryIdentifier acts_geom_id{geo_id};
270 auto sf = detray::tracking_surface{itkDetector, surface};
271 const auto detray_id = sf.identifier().value();
272
273 StaticCondEntry entry;
274 entry.detrayGeometryId = detray::geometry::identifier{detray_id};
275 entry.actsGeometryId = acts_geom_id.value();
276
277 auto detrayIt = detrayToAthenaMap.find(detray_id);
278 std::optional<Identifier> athenaId;
279 if (detrayIt != detrayToAthenaMap.end()) {
280 athenaId = detrayIt->second;
281 auto modIt = m_atlasModuleInfo.find(*athenaId);
282 if (modIt != m_atlasModuleInfo.end()) {
283 const moduleInfo& thismod = modIt->second;
284
285 const int nBinsX = thismod.rows;
286 const int nBinsY = thismod.pixel ? thismod.columns : 1;
287
288 auto edgesX = makeEquidistantEdges(0.5f * thismod.module_width, nBinsX);
289 auto edgesY = makeEquidistantEdges(0.5f * thismod.module_length, nBinsY);
290
291 if(!thismod.equidistant_binning){
292 edgesX = thismod.row_centres;
293 edgesY = thismod.column_centres;
294 }
295
296 designKey key{thismod.pixel, thismod.isAnnulus, std::move(edgesX), std::move(edgesY),
297 std::abs(thismod.module_width), thismod.module_length};
298
299 const auto [it, inserted] = designLookup.try_emplace(key, nextDesignId);
300 entry.designId = it->second;
301 if (inserted) ++nextDesignId;
302
303 entry.athenaId = *athenaId;
304 entry.hasAthenaModule = true;
305 entry.isPixel = thismod.pixel;
306 }
307 }else{
308 if (std::find(actsHGTD.begin(), actsHGTD.end(), acts_geom_id) != actsHGTD.end()) {
309 ATH_MSG_VERBOSE("ACTS surface with key " << acts_geom_id << " is HGTD, detray id: " << detray_id);
310 continue;
311 }
312 ATH_MSG_ERROR("Could not find matching Athena module for detray surface with geometryId " << detray_id);
313 return StatusCode::FAILURE;
314 }
315
316 idMapping->addEntry(detray_id, acts_geom_id.value(), athenaId);
317 // condIndex is the row of this surface in the detector conditions description
318 idMapping->addDetDescIndex(detray_id, static_cast<unsigned int>(condIndex));
319 m_staticCondEntries[condIndex] = entry;
320 }
321
322
323 // ---- 4. Write detector design object ----
324 auto hostDesign = std::make_unique<traccc::detector_design_description::host>(*m_MRs->hostMR());
325 hostDesign->resize(designLookup.size());
326 for (const auto& [key, id] : designLookup) {
327 hostDesign->design_id()[id] = static_cast<int>(id);
328
329 hostDesign->dimensions()[id] = key.pixel ? 2 : 1;
330
331 if(!key.isAnnulus){
332 hostDesign->bin_edges_x()[id].assign(key.edgesX.begin(), key.edgesX.end());
333 hostDesign->bin_edges_y()[id].assign(key.edgesY.begin(), key.edgesY.end());
334 hostDesign->subspace()[id] = std::array<detray::dindex_type<traccc::default_algebra>, 2u>{0u, 1u};
335 }else{
336 hostDesign->bin_edges_y()[id].assign(key.edgesX.begin(), key.edgesX.end());
337 hostDesign->bin_edges_x()[id].assign(key.edgesY.begin(), key.edgesY.end());
338 hostDesign->subspace()[id] = std::array<detray::dindex_type<traccc::default_algebra>, 2u>{1u, 0u};
339 }
340
341 }
342
343 std::vector<unsigned int> designSizes(hostDesign->size());
344 for (std::size_t i = 0; i < hostDesign->size(); ++i) {
345 auto thisDesign = hostDesign->at(i);
346 designSizes[i] = std::max(
347 static_cast<unsigned int>(thisDesign.bin_edges_x().size()),
348 static_cast<unsigned int>(thisDesign.bin_edges_y().size()));
349 }
350
351 auto initCopy = m_copy->copy(EventContext{});
352 auto deviceDesign = std::make_unique<traccc::detector_design_description::buffer>(
353 designSizes, m_MRs->mainMR(), m_MRs->hostMR(),
354 vecmem::data::buffer_type::resizable);
355 (*initCopy).setup(*deviceDesign)->wait();
356 (*initCopy)(vecmem::get_data(*hostDesign), *deviceDesign)->wait();
357
358 constexpr bool allowMods = false;
359 ATH_CHECK(m_detStore->record(std::move(deviceDesign), m_deviceDesignObjectName.value(), allowMods));
360 ATH_CHECK(m_detStore->record(std::move(hostDesign), m_hostDesignObjectName.value(), allowMods));
361 ATH_CHECK(m_detStore->record(std::move(idMapping), m_geoIdMappingObjectName.value(), allowMods));
362
363 auto deviceDetector = std::make_unique<traccc::detector_buffer>();
364 deviceDetector->set<traccc::itk_detector>(
365 detray::get_buffer(itkDetector, m_MRs->mainMR(), const_cast<vecmem::copy&>(*initCopy)));
366 ATH_CHECK(m_detStore->record(std::move(deviceDetector), m_deviceDetectorName.value(), allowMods));
367
368 ATH_MSG_DEBUG("Recorded host and device detector design description: " << m_hostDesignObjectName.value() << ", " << m_deviceDesignObjectName.value());
369
370 } else {
371 ATH_MSG_FATAL("Tracking Geometry empty!!");
372 return StatusCode::FAILURE;
373 }
374
375
376 return StatusCode::SUCCESS;
377}
378
379} // namespace ActsTrk
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_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_MSG_INFO(x,...)
#define ATH_MSG_FATAL(x,...)
#define min(a, b)
Definition cfImp.cxx:40
const PixelID * m_pixelID
Conversion helpers (to retrieve module design, hash, etc.) {.
const InDetDD::SCT_DetectorManager * m_stripManager
ToolHandle< AthDevice::ICopyTool > m_copy
The copy tool used for copying data to device.
ToolHandle< AthDevice::IMemoryResourcesTool > m_MRs
Gaudi::Property< std::string > m_geoIdMappingObjectName
Gaudi::Property< std::string > m_deviceDesignObjectName
ServiceHandle< ActsTrk::ITrackingGeometrySvc > m_trackingGeometrySvc
const InDetDD::PixelDetectorManager * m_pixelManager
std::shared_ptr< const Acts::TrackingGeometry > m_trackingGeometry
virtual StatusCode initialize() override
Function initializing and executing the geometry conversion.
std::map< Identifier, moduleInfo > m_atlasModuleInfo
Gaudi::Property< std::string > m_hostDesignObjectName
Gaudi::Property< std::string > m_deviceDetectorName
This is a "hash" representation of an Identifier.
static constexpr std::array< PixelDiodeTree::CellIndexType, 2 > makeCellIndex(T local_x_idx, T local_y_idx)
Create a 2D cell index from the indices in local-x (phi, row) and local-y (eta, column) direction.
Class used to describe the design of a module (diode segmentation and readout scheme).
Barrel module design description for the SCT.
Identifier for the strip or pixel cell.
Definition SiCellId.h:29
Class to hold geometrical description of a silicon detector element.
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
DetectorType
Simple enum to Identify the Type of the ACTS sub detector.
@ Pixel
Inner detector legacy.
std::vector< traccc::scalar > makeEquidistantEdges(float halfWidth, int nBins)
A diode proxy which caches the position of a diode.
const Vector2D & position() const
get the cached position of this diode
const PixelDiodeTree::Vector2D & width() const
get the width stored for this diode.
std::vector< traccc::scalar > row_centres
std::vector< traccc::scalar > column_centres