ATLAS Offline Software
Loading...
Searching...
No Matches
Acts/ActsGeometry/src/TrackingGeometrySvc.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// This absolutely needs to go first to ensure Eigen plugin is loaded
7//
8
10
13// ATHENA
14#include "GaudiKernel/EventContext.h"
23#include "GeoModelKernel/GeoTube.h"
24
25// ACTS
26#include "Acts/ActsVersion.hpp"
27#include "Acts/Geometry/Blueprint.hpp"
28#include "Acts/Geometry/ContainerBlueprintNode.hpp"
29#include "Acts/Geometry/CylinderVolumeBounds.hpp"
30#include "Acts/Geometry/CylinderVolumeBuilder.hpp"
31#include "Acts/Geometry/CylinderVolumeHelper.hpp"
32#include "Acts/Geometry/ITrackingVolumeBuilder.hpp"
33#include "Acts/Geometry/LayerArrayCreator.hpp"
34#include "Acts/Geometry/LayerCreator.hpp"
35#include "Acts/Geometry/SurfaceArrayCreator.hpp"
36#include "Acts/Geometry/TrackingGeometry.hpp"
37#include "Acts/Geometry/TrackingGeometryBuilder.hpp"
38#include "Acts/Geometry/TrackingVolume.hpp"
39#include "Acts/Geometry/TrackingVolumeArrayCreator.hpp"
40#include "Acts/Utilities/Logger.hpp"
41#include "Acts/Definitions/Units.hpp"
42#include "Acts/Geometry/PassiveLayerBuilder.hpp"
43#include <ActsPlugins/Detray/DetrayGeometryConverter.hpp>
44#include <ActsPlugins/Json/JsonMaterialDecorator.hpp>
45#include <ActsPlugins/Json/MaterialMapJsonConverter.hpp>
46#include <detray/geometry/surface.hpp>
47#include <detray/geometry/tracking_volume.hpp>
48#include <detray/utils/consistency_checker.hpp>
49#include <detray/utils/invalid_values.hpp>
50#include <traccc/geometry/host_detector.hpp>
51#include <algorithm>
52#include <set>
53#include <utility>
54#include <vector>
55#include <Acts/Surfaces/PlanarBounds.hpp>
56#include <Acts/Surfaces/AnnulusBounds.hpp>
57#include <Acts/Surfaces/DiscSurface.hpp>
58#include <Acts/Surfaces/LineSurface.hpp>
59#include <Acts/Surfaces/RectangleBounds.hpp>
60#include <Acts/Visualization/ObjVisualization3D.hpp>
61#include <Acts/Visualization/ViewConfig.hpp>
62#include <Acts/Geometry/detail/TrackingGeometryPrintVisitor.hpp>
63
64// PACKAGE
71#include "ActsInterop/Logger.h"
73
75#include <Acts/Utilities/AxisDefinitions.hpp>
76#include <cstdint>
77#include <fstream>
78#include <limits>
79#include <optional>
80#include <random>
81#include <stdexcept>
82
83using namespace Acts::UnitLiterals;
84
85namespace {
88 Acts::ViewConfigFunc viewConfigFunc(const Acts::ViewConfig& volumeCfg,
89 const Acts::ViewConfig& portalCfg,
90 const Acts::ViewConfig& sensitiveCfg) {
91 //coverity[AUTO_CAUSES_COPY]
92 return [volumeCfg, portalCfg, sensitiveCfg](const Acts::GeometryObject& geoObj) {
93 if (geoObj.geometryId().boundary() != 0) {
94 return portalCfg;
95 }
96 if (geoObj.geometryId().sensitive() != 0) {
97 return sensitiveCfg;
98 }
99 return volumeCfg;
100 };
101 }
102
103 inline Acts::GeometryIdentifier volumeId(const std::size_t volume) {
104 return Acts::GeometryIdentifier{}.withVolume(volume);
105 }
107 std::optional<Acts::SurfaceArray::NeighborWindow> toNeighborWindow(
108 const std::vector<unsigned int>& maxBins) {
109 constexpr unsigned int limit = std::numeric_limits<std::uint8_t>::max();
110 if (maxBins.size() != 2 || maxBins[0] > limit || maxBins[1] > limit) {
111 return std::nullopt;
112 }
113 return Acts::SurfaceArray::NeighborWindow{
114 {0, 0},
115 {static_cast<std::uint8_t>(maxBins[0]), static_cast<std::uint8_t>(maxBins[1])}};
116 }
117}
118
119namespace ActsTrk{
121 ISvcLocator *svc)
122 : base_class(name, svc),
123 m_detStore("StoreGateSvc/DetectorStore", name),
124 m_elementStore (std::make_shared<ActsElementVector>())
125{
126}
127
129
131 ATH_MSG_INFO(name() << " is initializing");
132 for (unsigned int skipAlign : m_subDetNoAlignProp) {
133 try {
134 m_subDetNoAlign.insert(static_cast<DetectorType>(skipAlign));
135 } catch (...) {
136 ATH_MSG_FATAL("Failed to interpret " << m_subDetNoAlignProp << " as ActsDetectorElements");
137 return StatusCode::FAILURE;
138 }
139 }
140 ATH_CHECK(m_caloVolumeBuilder.retrieve(EnableTool{!m_caloVolumeBuilder.empty()}));
141
142 // FIXME: ActsCaloTrackingVolumeBuilder holds ReadHandle to
143 // CaloDetDescrManager. Hopefully this service is never called before that
144 // object is available.
145 m_autoRetrieveTools = false;
146 m_checkToolDeps = false;
147
148 ATH_MSG_INFO("ACTS version is: v"
149 << Acts::VersionMajor << "." << Acts::VersionMinor << "."
150 << Acts::VersionPatch << " [" << Acts::CommitHash.value_or("unknown hash") << "]");
151
152 // load which subdetectors to build from property
153 std::set<std::string, std::less<>> buildSubdet(m_buildSubdetectors.begin(),
154 m_buildSubdetectors.end());
155 ATH_MSG_INFO("Configured to build " << buildSubdet.size()
156 << " subdetectors:");
157 for (const auto &s : buildSubdet) {
158 ATH_MSG_INFO(" - " << s);
159 }
160
161 for (const Gaudi::Property<std::vector<unsigned int>>* window :
165 if (!toNeighborWindow(window->value()).has_value()) {
166 ATH_MSG_FATAL((*window)
167 << " must hold two bin counts of at most "
168 << static_cast<unsigned int>(std::numeric_limits<std::uint8_t>::max()));
169 return StatusCode::FAILURE;
170 }
171 }
172 if (m_surfaceArrayOverfill.value() > std::numeric_limits<std::uint8_t>::max()) {
174 << " exceeds " << static_cast<unsigned int>(std::numeric_limits<std::uint8_t>::max()));
175 return StatusCode::FAILURE;
176 }
177
178 ATH_MSG_DEBUG("Loading detector manager(s)");
179 if (buildSubdet.contains("Pixel") ) {
180 ATH_CHECK(m_detStore->retrieve(p_pixelManager, "Pixel"));
181 }
182 if (buildSubdet.contains("SCT") ) {
183 ATH_CHECK(m_detStore->retrieve(p_SCTManager, "SCT"));
184 }
185 if (buildSubdet.contains("TRT") ) {
186 ATH_CHECK(m_detStore->retrieve(p_TRTManager, "TRT"));
187 ATH_CHECK(m_detStore->retrieve(m_TRT_idHelper, "TRT_ID"));
188 }
189 if (buildSubdet.contains("ITkPixel") ) {
190 ATH_CHECK(m_detStore->retrieve(p_ITkPixelManager, "ITkPixel"));
191 }
192 if (buildSubdet.contains("ITkStrip") ) {
193 ATH_CHECK(m_detStore->retrieve(p_ITkStripManager, "ITkStrip"));
194 }
195 if (buildSubdet.contains("HGTD") ) {
196 ATH_CHECK(m_detStore->retrieve(p_HGTDManager, "HGTD"));
197 ATH_CHECK(m_detStore->retrieve(m_HGTD_idHelper, "HGTD_ID"));
198 }
199
200 if(m_buildBeamPipe) {
201 ATH_CHECK(m_detStore->retrieve(p_beamPipeMgr, "BeamPipe"));
202 }
203
204 // Consistency check on the size vectors for passive layers
207 ATH_MSG_FATAL("Consistency check for ITk inner pixel barrel passive layer construction failed. Please check your inputs! ");
208 return StatusCode::FAILURE;
209 }
210
213 ATH_MSG_FATAL("Consistency check for ITk outer pixel barrel passive layer construction failed. Please check your inputs! ");
214 return StatusCode::FAILURE;
215 }
216
219 ATH_MSG_FATAL("Consistency check for ITk strip barrel passive layer construction failed. Please check your inputs! ");
220 return StatusCode::FAILURE;
221 }
222
223 if (m_useBlueprint) {
224
225
226 ATH_MSG_INFO("Using Blueprint API for geometry construction");
227 std::set<std::string, std::less<>> buildSubdet(m_buildSubdetectors.begin(),
228 m_buildSubdetectors.end());
229
231 ATH_CHECK(m_refineVisitors.retrieve());
232
233 using enum Acts::AxisDirection;
234
235 std::vector<ActsTrk::IBlueprintNodeBuilder*> ptrBuilders;
236 std::transform(m_blueprintNodeBuilders.begin(), m_blueprintNodeBuilders.end(),
237 std::back_inserter(ptrBuilders),
238 [](ToolHandle<ActsTrk::IBlueprintNodeBuilder>& b) { return b.get(); });
239
240 auto logger = makeActsAthenaLogger(this, name());
241
242 Acts::Blueprint::Config cfg;
243 cfg.envelope[AxisZ] = {20_mm, 20_mm};
244 cfg.envelope[AxisR] = {0_mm, 20_mm};
245
246 auto blueprint = std::make_unique<Acts::Blueprint>(cfg);
247
248 auto& root = blueprint->addCylinderContainer("Detector", AxisZ);
249 //The starting top node
250 std::shared_ptr<Acts::BlueprintNode> currentTop{nullptr};
251
252 for (auto& builder : ptrBuilders) {
253 currentTop = builder->buildBlueprintNode(getNominalContext().context(), std::move(currentTop));
254
255 }
256
257 root.addChild(std::move(currentTop));
258
259 Acts::BlueprintOptions blueprintOptions;
260 blueprintOptions.keepGoingOnMaterialMergeFailure = m_keepGoingOnMaterialMergeFailure;
261 std::unique_ptr<Acts::TrackingGeometry> trackingGeometry = blueprint->construct(
262 blueprintOptions, getNominalContext().context(), *logger->clone(std::nullopt, Acts::Logging::DEBUG));
263
264 for (auto& refineVisitor : m_refineVisitors) {
265 trackingGeometry->apply(*refineVisitor);
266 ATH_CHECK(refineVisitor->finalize());
267 }
268 m_refineVisitors.clear();
269
271
272 if (m_objDebugOutput) {
273 Acts::ObjVisualization3D vis;
274 m_trackingGeometry->visualize(vis, getNominalContext().context(),
275 viewConfigFunc({.visible = true}, {.visible = false}, {.visible = false}));
276 vis.write("blueprint_envelopes.obj");
277 vis.clear();
278
279 m_trackingGeometry->visualize(vis, getNominalContext().context(),
280 viewConfigFunc({.visible = false}, {.visible = true}, {.visible = false}));
281 vis.write("blueprint_portals.obj");
282
283 m_trackingGeometry->visualize(vis, getNominalContext().context(),
284 viewConfigFunc({.visible = false}, {.visible = false}, {.visible = true}));
285 vis.write("blueprint_sensitive.obj");
286 vis.clear();
287
288 }
289 if (m_printGeo) {
290 Acts::detail::TrackingGeometryPrintVisitor printer{m_nominalContext.context()};
291 m_trackingGeometry->apply(printer);
292 ATH_MSG_INFO("Built tracking geometry \n"<<printer.stream().str());
293 }
295 if (!m_detIdMap) {
296 return StatusCode::FAILURE;
297 }
298
301 }
302
303 return StatusCode::SUCCESS;
304 }
305
306 ATH_MSG_DEBUG("Setting up ACTS geometry helpers");
307
308 Acts::LayerArrayCreator::Config lacCfg;
309 auto layerArrayCreator = std::make_shared<const Acts::LayerArrayCreator>(
310 lacCfg, makeActsAthenaLogger(this, std::string("LayArrCrtr"), std::string("ActsTGSvc")));
311
312 Acts::TrackingVolumeArrayCreator::Config tvcCfg;
313 auto trackingVolumeArrayCreator =
314 std::make_shared<const Acts::TrackingVolumeArrayCreator>(
315 tvcCfg, makeActsAthenaLogger(this, std::string("TrkVolArrCrtr"), std::string("ActsTGSvc")));
316
317 Acts::CylinderVolumeHelper::Config cvhConfig;
318 cvhConfig.layerArrayCreator = layerArrayCreator;
319 cvhConfig.trackingVolumeArrayCreator = trackingVolumeArrayCreator;
320
321 auto cylinderVolumeHelper =
322 std::make_shared<const Acts::CylinderVolumeHelper>(
323 cvhConfig, makeActsAthenaLogger(this, std::string("CylVolHlpr"), std::string("ActsTGSvc")));
324
325 Acts::TrackingGeometryBuilder::Config tgbConfig;
326 tgbConfig.trackingVolumeHelper = cylinderVolumeHelper;
327
328 if (m_useMaterialMap) {
329 std::shared_ptr<const Acts::IMaterialDecorator> matDeco = nullptr;
330
331 std::string matFileFullPath = PathResolverFindCalibFile(m_materialMapCalibFolder.value()+"/"+m_materialMapInputFileBase.value());
332 if (matFileFullPath.empty()) {
333 ATH_MSG_ERROR( "Material Map Input File " << m_materialMapCalibFolder.value() << "/" << m_materialMapInputFileBase.value() << " not found.");
334 return StatusCode::FAILURE;
335 }
336 ATH_MSG_INFO("Configured to use material input: " << matFileFullPath);
337
338 if (matFileFullPath.find(".json") != std::string::npos) {
339 // Set up the converter first
340 Acts::MaterialMapJsonConverter::Config jsonGeoConvConfig;
341 // Set up the json-based decorator
342 matDeco = std::make_shared<const Acts::JsonMaterialDecorator>(
343 jsonGeoConvConfig, matFileFullPath, ActsTrk::actsLevelVector(msg().level()));
344 }
345 tgbConfig.materialDecorator = std::move(matDeco);
346 }
347
348 std::array<double, 2> sctECEnvelopeZ{20_mm, 20_mm};
349
350 try {
351 // BeamPipe
352 if(m_buildBeamPipe) {
353 tgbConfig.trackingVolumeBuilders.push_back([&](const auto &gctx,
354 const auto &inner,
355 const auto &) {
356
357 Acts::CylinderVolumeBuilder::Config bpvConfig =
358 makeBeamPipeConfig(cylinderVolumeHelper);
359
360 Acts::CylinderVolumeBuilder beamPipeVolumeBuilder {
361 bpvConfig, makeActsAthenaLogger(this, std::string("BPVolBldr"), std::string("ActsTGSvc"))};
362
363 return beamPipeVolumeBuilder.trackingVolume(gctx, inner);
364 });
365 }
366
367
368
369 // PIXEL
370 if (buildSubdet.contains("Pixel")) {
371 tgbConfig.trackingVolumeBuilders.push_back([&](const auto &gctx,
372 const auto &inner,
373 const auto &) {
376 auto lb = std::make_shared<ActsLayerBuilder>(
377 cfg, makeActsAthenaLogger(this, std::string("PixelGMSLayBldr"), std::string("ActsTGSvc")));
378 Acts::CylinderVolumeBuilder::Config cvbConfig;
379 cvbConfig.layerEnvelopeR = {3_mm, 3_mm};
380 cvbConfig.layerEnvelopeZ = 1_mm;
381 cvbConfig.trackingVolumeHelper = cylinderVolumeHelper;
382 cvbConfig.volumeName = "Pixel";
383 cvbConfig.layerBuilder = lb;
384 cvbConfig.buildToRadiusZero = !m_buildBeamPipe;
385
386 Acts::CylinderVolumeBuilder cvb(
387 cvbConfig, makeActsAthenaLogger(this, std::string("CylVolBldr"), std::string("ActsTGSvc")));
388
389 return cvb.trackingVolume(gctx, inner);
390 });
391 }
392
393 // ITK PIXEL
394 if (buildSubdet.contains("ITkPixel") ) {
395 tgbConfig.trackingVolumeBuilders.push_back(
396 [&](const auto &gctx, const auto &inner, const auto &) {
399 cfg.barrelNeighborWindow = *toNeighborWindow(m_itkPixelInnerBarrelNeighborWindow);
400 cfg.endcapNeighborWindow = *toNeighborWindow(m_itkPixelInnerEndcapNeighborWindow);
401 cfg.objDebugOutput = m_objDebugOutput;
402 cfg.doEndcapLayerMerging = true;
403 cfg.passiveBarrelLayerRadii = m_passiveITkInnerPixelBarrelLayerRadii;
404 cfg.passiveBarrelLayerHalflengthZ = m_passiveITkInnerPixelBarrelLayerHalflengthZ;
405 cfg.passiveBarrelLayerThickness = m_passiveITkInnerPixelBarrelLayerThickness;
406 auto lb = std::make_shared<ActsLayerBuilder>(
407 cfg, makeActsAthenaLogger(this, std::string("ITkPxInLb"), std::string("ActsTGSvc")));
408
409 Acts::CylinderVolumeBuilder::Config cvbConfig;
410 cvbConfig.layerEnvelopeR = {5_mm, 5_mm};
411 cvbConfig.layerEnvelopeZ = 1_mm;
412 cvbConfig.trackingVolumeHelper = cylinderVolumeHelper;
413 cvbConfig.volumeName = "ITkPixelInner";
414 cvbConfig.layerBuilder = lb;
415 cvbConfig.buildToRadiusZero = !m_buildBeamPipe;
416
417 Acts::CylinderVolumeBuilder cvb(
418 cvbConfig,
419 makeActsAthenaLogger(this, std::string("CylVolBldr"), std::string("ActsTGSvc")));
420
421 return cvb.trackingVolume(gctx, inner);
422 });
423
424 tgbConfig.trackingVolumeBuilders.push_back(
425 [&](const auto &gctx, const auto &inner, const auto &) {
428 cfg.barrelNeighborWindow = *toNeighborWindow(m_itkPixelOuterBarrelNeighborWindow);
429 cfg.endcapNeighborWindow = *toNeighborWindow(m_itkPixelOuterEndcapNeighborWindow);
430 cfg.objDebugOutput = m_objDebugOutput;
431 cfg.doEndcapLayerMerging = false;
432 cfg.passiveBarrelLayerRadii = m_passiveITkOuterPixelBarrelLayerRadii;
433 cfg.passiveBarrelLayerHalflengthZ = m_passiveITkOuterPixelBarrelLayerHalflengthZ;
434 cfg.passiveBarrelLayerThickness = m_passiveITkOuterPixelBarrelLayerThickness;
435 auto lb = std::make_shared<ActsLayerBuilder>(
436 cfg, makeActsAthenaLogger(this, std::string("ITkPxOtLb"), std::string("ActsTGSvc")));
437
438 Acts::CylinderVolumeBuilder::Config cvbConfig;
439 cvbConfig.layerEnvelopeR = {5_mm, 5_mm};
440 cvbConfig.layerEnvelopeZ = 1_mm;
441 cvbConfig.trackingVolumeHelper = cylinderVolumeHelper;
442 cvbConfig.volumeName = "ITkPixelOuter";
443 cvbConfig.layerBuilder = lb;
444 cvbConfig.buildToRadiusZero = false;
445 cvbConfig.checkRingLayout = true;
446 cvbConfig.ringTolerance = 10_mm;
447
448 Acts::CylinderVolumeBuilder cvb(
449 cvbConfig,
450 makeActsAthenaLogger(this, std::string("CylVolBldr"), std::string("ActsTGSvc")));
451
452 return cvb.trackingVolume(gctx, inner);
453 });
454 }
455
456 // ITK STRIP
457 if (buildSubdet.contains("ITkStrip")) {
458 tgbConfig.trackingVolumeBuilders.push_back(
459 [&](const auto &gctx, const auto &inner, const auto &) {
462 cfg.barrelNeighborWindow = *toNeighborWindow(m_itkStripBarrelNeighborWindow);
463 cfg.endcapNeighborWindow = *toNeighborWindow(m_itkStripEndcapNeighborWindow);
464 cfg.objDebugOutput = m_objDebugOutput;
465 cfg.passiveBarrelLayerRadii = m_passiveITkStripBarrelLayerRadii;
466 cfg.passiveBarrelLayerHalflengthZ = m_passiveITkStripBarrelLayerHalflengthZ;
467 cfg.passiveBarrelLayerThickness = m_passiveITkStripBarrelLayerThickness;
468 auto lb = std::make_shared<ActsLayerBuilder>(
469 cfg, makeActsAthenaLogger(this, std::string("ITkStripLB"), std::string("ActsTGSvc")));
470
471 Acts::CylinderVolumeBuilder::Config cvbConfig;
472 cvbConfig.layerEnvelopeR = {5_mm, 5_mm};
473 cvbConfig.layerEnvelopeZ = 1_mm;
474 cvbConfig.trackingVolumeHelper = cylinderVolumeHelper;
475 cvbConfig.volumeName = "ITkStrip";
476 cvbConfig.layerBuilder = lb;
477 cvbConfig.buildToRadiusZero =
478 !buildSubdet.contains("ITkPixel") && !m_buildBeamPipe;
479
480 Acts::CylinderVolumeBuilder cvb(
481 cvbConfig,
482 makeActsAthenaLogger(this, std::string("CylVolBldr"), std::string("ActsTGSvc")));
483
484 return cvb.trackingVolume(gctx, inner);
485 });
486 }
487
488 bool buildSCT = buildSubdet.contains("SCT") ;
489 bool buildTRT = buildSubdet.contains("TRT");
490
491 if (buildSCT && buildTRT) {
492 // building both we need to take care
493 tgbConfig.trackingVolumeBuilders.push_back(
494 [&](const auto &gctx, const auto &inner, const auto &) {
497 cfg.endcapEnvelopeZ = sctECEnvelopeZ;
498 auto sct_lb = std::make_shared<ActsLayerBuilder>(
499 cfg, makeActsAthenaLogger(this, std::string("SCTGMSLayBldr"), std::string("ActsTGSvc")));
500
501 auto trt_lb = makeStrawLayerBuilder(p_TRTManager);
502
503 return makeSCTTRTAssembly(gctx, *sct_lb, *trt_lb,
504 *cylinderVolumeHelper, inner);
505 });
506
507 } else if (buildSCT) {
508 tgbConfig.trackingVolumeBuilders.push_back(
509 [&](const auto &gctx, const auto &inner, const auto &) {
511 lbCfg.mode = ActsLayerBuilder::Mode::SCT;
512 lbCfg.endcapEnvelopeZ = sctECEnvelopeZ;
513 auto lb = std::make_shared<ActsLayerBuilder>(
514 lbCfg,
515 makeActsAthenaLogger(this, std::string("SCTGMSLayBldr"), std::string("ActsTGSvc")));
516
517 Acts::CylinderVolumeBuilder::Config cvbConfig;
518 cvbConfig.layerEnvelopeR = {5_mm, 5_mm};
519 cvbConfig.layerEnvelopeZ = 2_mm;
520 cvbConfig.trackingVolumeHelper = cylinderVolumeHelper;
521 cvbConfig.volumeName = "SCT";
522 cvbConfig.layerBuilder = lb;
523 cvbConfig.buildToRadiusZero = false;
524
525 Acts::CylinderVolumeBuilder cvb(
526 cvbConfig,
527 makeActsAthenaLogger(this, std::string("SCTCylVolBldr"), std::string("ActsTGSvc")));
528
529 return cvb.trackingVolume(gctx, inner);
530 });
531 } else if (buildTRT) {
532 tgbConfig.trackingVolumeBuilders.push_back(
533 [&](const auto &gctx, const auto &inner, const auto &) {
535 Acts::CylinderVolumeBuilder::Config cvbConfig;
536 cvbConfig.layerEnvelopeR = {5_mm, 5_mm};
537 cvbConfig.layerEnvelopeZ = 2_mm;
538 cvbConfig.trackingVolumeHelper = cylinderVolumeHelper;
539 cvbConfig.volumeName = "TRT";
540 cvbConfig.layerBuilder = std::move(lb);
541 cvbConfig.buildToRadiusZero = false;
542
543 Acts::CylinderVolumeBuilder cvb(
544 cvbConfig,
545 makeActsAthenaLogger(this, std::string("TRTCylVolBldr"), std::string("ActsTGSvc")));
546
547 return cvb.trackingVolume(gctx, inner);
548 });
549 }
550
551 //HGTD
552 if(buildSubdet.contains("HGTD") ) {
553 tgbConfig.trackingVolumeBuilders.push_back(
554 [&](const auto &gctx, const auto &inner, const auto &) {
555 auto lb = makeHGTDLayerBuilder(p_HGTDManager); //using ActsHGTDLayerBuilder
556 Acts::CylinderVolumeBuilder::Config cvbConfig;
557 cvbConfig.layerEnvelopeR = {5_mm, 5_mm};
558 cvbConfig.layerEnvelopeZ = 1_mm;
559 cvbConfig.trackingVolumeHelper = cylinderVolumeHelper;
560 cvbConfig.volumeName = "HGTD";
561 cvbConfig.layerBuilder = std::move(lb);
562 cvbConfig.buildToRadiusZero = false;
563
564 Acts::CylinderVolumeBuilder cvb(
565 cvbConfig,
566 makeActsAthenaLogger(this, std::string("HGTDCylVolBldr"), std::string("ActsTGSvc")));
567
568 return cvb.trackingVolume(gctx, inner);
569 });
570 }
571
572 // Calo
573 if (m_caloVolumeBuilder.isEnabled()) {
574 tgbConfig.trackingVolumeBuilders.push_back(
575 [&](const auto &gctx, const auto &inner, const auto &) {
576 return m_caloVolumeBuilder->trackingVolume(gctx, inner, nullptr);
577 });
578 }
579
580 } catch (const std::exception &e) {
581 ATH_MSG_ERROR("Encountered error when building Acts tracking geometry");
582 ATH_MSG_ERROR(e.what());
583 return StatusCode::FAILURE;
584 }
585
586 auto trackingGeometryBuilder =
587 std::make_shared<const Acts::TrackingGeometryBuilder>(
588 tgbConfig, makeActsAthenaLogger(this, std::string("TrkGeomBldr"), std::string("ActsTGSvc")));
589
590 ATH_MSG_VERBOSE("Begin building process");
592 trackingGeometryBuilder->trackingGeometry(getNominalContext().context());
593 ATH_MSG_VERBOSE("Building process completed");
594
595 if (!m_trackingGeometry) {
596 ATH_MSG_ERROR("No ACTS tracking geometry was built. Cannot proceeed");
597 return StatusCode::FAILURE;
598 }
599
600
602 ATH_MSG_INFO("Running extra consistency check! (this is SLOW)");
603 if(!runConsistencyChecks()) {
604 ATH_MSG_ERROR("Consistency check has failed! Geometry is not consistent");
605 return StatusCode::FAILURE;
606 }
607 }
608
610 if (!m_detIdMap) {
611 return StatusCode::FAILURE;
612 }
613
616 }
617
618 ATH_MSG_INFO("Acts TrackingGeometry construction completed");
619
620 return StatusCode::SUCCESS;
621}
626 bool result = true;
627
628 std::vector<Acts::Vector2> localPoints;
629 localPoints.reserve(m_consistencyCheckPoints);
630 std::mt19937 gen;
631 std::uniform_real_distribution<> dist(0.0, 1.0);
632
633 std::optional<std::ofstream> os;
634 if(!m_consistencyCheckOutput.empty()){
635 os = std::ofstream{m_consistencyCheckOutput};
636 if(!os->good()) {
637 throw std::runtime_error{"Failed to open consistency check output file"};
638 }
639 }
640
641 if(os) {
642 (*os) << "geo_id,vol_id,lay_id,sen_id,type,acts_loc0,acts_loc1,acts_inside,trk_loc0,trk_loc1,trk_inside,x,y,z,g2l_loc0,g2l_loc1,trk_x,trk_y,trk_z" << std::endl;
643 }
644 for(size_t i=0;i<m_consistencyCheckPoints;i++) {
645 localPoints.emplace_back(dist(gen), dist(gen));
646 }
647
648 Acts::GeometryContext gctx = getNominalContext().context();
649
650 size_t nTotalSensors = 0;
651 std::array<size_t,3> nInconsistent{0,0,0};
652 size_t nMismatchedCenters = 0;
653 size_t nMismatchedNormals = 0;
654
655 // Comparison of Eigen vectors, similar to a.isApprox(b), but use absolute comparison to also work with zero vectors.
656 // All values will be mm or radians, so 1e-5 is a reasonable precision.
657 auto isApprox = [](auto& a, auto& b) -> bool {
658 return ((a - b).array().abs() < 1e-5).all();
659 };
660
661 m_trackingGeometry->visitSurfaces([&](const Acts::Surface *surface) {
662 nTotalSensors++;
663 const auto* actsDetElem = getActsDetectorElement(surface);
664 if(actsDetElem == nullptr) {
665 ATH_MSG_ERROR("Invalid detector element found");
666 result = false;
667 return;
668 }
669 const auto* siDetElem = dynamic_cast<const InDetDD::SiDetectorElement*>(actsDetElem->upstreamDetectorElement());
670 if(siDetElem == nullptr) {
671 return;
672 }
673
674 const auto* regSurface = dynamic_cast<const Acts::RegularSurface*>(surface);
675 const auto& trkSurface = siDetElem->surface();
676 if(regSurface == nullptr) {
677 ATH_MSG_ERROR("Invalid surface found");
678 result = false;
679 return;
680 }
681
682 Acts::Vector3 center{regSurface->center(gctx)};
683 Amg::Vector3D trkCenter{trkSurface.center()};
684 if (/* auto *b = */ dynamic_cast<const Acts::AnnulusBounds *>(&surface->bounds()))
685 {
686 // // Acts::AnnulusBounds defines center() as center of whole disc, so get it from the bounds
687 // Acts::Vector2 locCenter{0.5 * (b->rMin() + b->rMax()), 0.5 * (b->phiMin() + b->phiMax())};
688 // center = surface->localToGlobal(gctx, locCenter, Acts::Vector3::Zero());
689 center.head<2>() = trkCenter.head<2>(); // that doesn't (quite) work for xy, so just pass that check
690 }
691
692 if(!isApprox(trkCenter, center)) {
693 std::string trkName;
694 if (auto idHelper = siDetElem->getIdHelper())
695 {
696 trkName = idHelper->show_to_string(siDetElem->identify());
697 }
698 ATH_MSG_WARNING("Acts surface "
699 << surface->geometryId()
700 << " center (" << center[0] << ',' << center[1] << ',' << center[2]
701 << ") does not match Trk surface " << trkName
702 << " center (" << trkCenter[0] << ',' << trkCenter[1] << ',' << trkCenter[2] << ')');
703 nMismatchedCenters++;
704 result = false;
705 }
706
707 const auto* lineSurface = dynamic_cast<const Acts::LineSurface*>(surface);
708 if(lineSurface == nullptr) {
709 Acts::Vector3 norm{regSurface->normal(gctx, regSurface->center(gctx))};
710 Amg::Vector3D trkNorm{trkSurface.normal()};
711 if(!isApprox(trkNorm, norm)) {
712 std::string trkName;
713 if (auto idHelper = siDetElem->getIdHelper())
714 {
715 trkName = idHelper->show_to_string(siDetElem->identify());
716 }
717 ATH_MSG_WARNING("Acts surface "
718 << surface->geometryId()
719 << " normal (" << norm[0] << ',' << norm[1] << ',' << norm[2]
720 << ") does not match Trk surface " << trkName
721 << " normal (" << trkNorm[0] << ',' << trkNorm[1] << ',' << trkNorm[2] << ')');
722 nMismatchedNormals++;
723 result = false;
724 }
725 }
726
727 auto doPoints = [&](unsigned int type, const Acts::Vector2& loc) -> std::array<bool,3> {
728 Acts::Vector3 glb = surface->localToGlobal(gctx, loc, Acts::Vector3::Zero());
729
730 Amg::Vector2D locTrk = Amg::Vector2D::Zero();
731 Amg::Vector3D glbTrk = Amg::Vector3D::Zero();
732 Acts::Vector2 locg2l = Acts::Vector2::Zero();
733 bool locg2lOk = false;
734 auto locTrkRes = trkSurface.globalToLocal(glb);
735 if (locTrkRes) {
736 locTrk = locTrkRes.value();
737 glbTrk = trkSurface.localToGlobal(locTrk);
738
739 auto locg2lRes = surface->globalToLocal(gctx, glbTrk, Acts::Vector3::Zero());
740 if (locg2lRes.ok()) {
741 locg2lOk = true;
742 locg2l = locg2lRes.value();
743 }
744 }
745
746 auto gId = surface->geometryId();
747 if(os) {
748 (*os) << gId.value()
749 << "," << gId.volume()
750 << "," << gId.layer()
751 << "," << gId.sensitive()
752 << "," << type
753 << "," << loc[0]
754 << "," << loc[1]
755 << "," << surface->insideBounds(loc)
756 << "," << locTrk[0]
757 << "," << locTrk[1]
758 << "," << trkSurface.insideBounds(locTrk)
759 << "," << glb[0]
760 << "," << glb[1]
761 << "," << glb[2]
762 << "," << locg2l[0]
763 << "," << locg2l[1]
764 << "," << glbTrk[0]
765 << "," << glbTrk[1]
766 << "," << glbTrk[2]
767 << std::endl;
768 }
769
770 return {surface->insideBounds(loc) == trkSurface.insideBounds(locTrk),
771 locg2lOk ? isApprox(loc, locg2l) : true,
772 locTrkRes ? isApprox(glb, glbTrk) : true};
773 };
774
775
776 constexpr double envelope = 10.0 * Acts::UnitConstants::mm;
777
778 std::array<bool,3> allOk{true,true,true};
779 if(const auto* bounds = dynamic_cast<const Acts::PlanarBounds*>(&surface->bounds()); bounds) {
780 ATH_MSG_VERBOSE("Planar bounds");
781
782 const Acts::RectangleBounds& boundingBox = bounds->boundingBox();
783 Acts::Vector2 min = boundingBox.min().array() - envelope;
784 Acts::Vector2 max = boundingBox.max().array() + envelope;
785 Acts::Vector2 diag = max - min;
786
787 for(const auto& testPoint : localPoints) {
788 Acts::Vector2 loc = min.array() + (testPoint.array() * diag.array());
789 auto pointOk = doPoints(0, loc);
790 for (size_t i=0; i<pointOk.size(); ++i) {
791 if (!pointOk[i]) {
792 result = false;
793 allOk[i] = false;
794 }
795 }
796 }
797
798 }
799 else if(const auto* bounds = dynamic_cast<const Acts::AnnulusBounds*>(&surface->bounds()); bounds) {
800 ATH_MSG_VERBOSE("Annulus bounds");
801
802 // custom bounding box algo
803 std::vector<Acts::Vector2> vertices = bounds->vertices(5); // 5 segments on the radial edges
804 Acts::Vector2 min{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()};
805 Acts::Vector2 max{std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest()};
806 for (const auto& vtx : vertices) {
807 min = min.array().min(vtx.array());
808 max = max.array().max(vtx.array());
809 }
810 min.array() -= envelope;
811 max.array() += envelope;
812 Acts::Vector2 diag = max - min;
813
814 for(const auto& testPoint : localPoints) {
815 Acts::Vector2 locXY = min.array() + (testPoint.array() * diag.array());
816 Acts::Vector2 locPC = dynamic_cast<const Acts::DiscSurface&>(*surface).localCartesianToPolar(locXY);
817
818 auto pointOk = doPoints(1, locPC);
819 for (size_t i=0; i<pointOk.size(); ++i) {
820 if (!pointOk[i]) {
821 result = false;
822 allOk[i] = false;
823 }
824 }
825 }
826
827 }
828 else {
829 result = false;
830 }
831
832 for (size_t i=0; i<allOk.size(); ++i) {
833 if (!allOk[i]) {
834 ++nInconsistent[i];
835 }
836 }
837
838 });
839
840 ATH_MSG_INFO("Total number of sensors : " << nTotalSensors);
841 ATH_MSG_INFO("Number of sensors with mismatched centers : " << nMismatchedCenters);
842 ATH_MSG_INFO("Number of sensors with mismatched normals : " << nMismatchedNormals);
843 ATH_MSG_INFO("Number of sensors with inconsistent inside: " << nInconsistent[0]);
844 ATH_MSG_INFO("Number of sensors with inconsistent g2l : " << nInconsistent[1]);
845 ATH_MSG_INFO("Number of sensors with inconsistent l2g : " << nInconsistent[2]);
846
847 return result;
848}
849
850std::shared_ptr<const Acts::TrackingGeometry>
852
853 ATH_MSG_VERBOSE("Retrieving tracking geometry");
854 return m_trackingGeometry;
855}
856
857std::shared_ptr<const Acts::ILayerBuilder>
859 const InDetDD::InDetDetectorManager *manager) {
860
861 std::string managerName = manager->getName();
862 auto matcher = [](const Acts::GeometryContext & /*gctx*/,
863 Acts::AxisDirection /*aDir*/, const Acts::Surface * /*aS*/,
864 const Acts::Surface *
865 /*bS*/) -> bool { return false; };
866
867 Acts::SurfaceArrayCreator::Config sacCfg;
868 sacCfg.surfaceMatcher = matcher;
869 sacCfg.doPhiBinningOptimization = false;
870
871 auto surfaceArrayCreator = std::make_shared<Acts::SurfaceArrayCreator>(
872 sacCfg,
873 makeActsAthenaLogger(this, managerName + "SrfArrCrtr", std::string("ActsTGSvc")));
874 Acts::LayerCreator::Config lcCfg;
875 lcCfg.surfaceArrayCreator = surfaceArrayCreator;
876 auto layerCreator = std::make_shared<Acts::LayerCreator>(
877 lcCfg, makeActsAthenaLogger(this, managerName + "LayCrtr", std::string("ActsTGSvc")));
878
880 cfg.mng = static_cast<const InDetDD::TRT_DetectorManager *>(manager);
881 cfg.elementStore = m_elementStore;
882 cfg.layerCreator = layerCreator;
883 cfg.idHelper = m_TRT_idHelper;
884 return std::make_shared<const ActsStrawLayerBuilder>(
885 cfg, makeActsAthenaLogger(this, managerName + "GMSLayBldr", std::string("ActsTGSvc")));
886}
887
888std::shared_ptr<const Acts::ILayerBuilder>
890 const HGTD_DetectorManager *manager) {
891
892 std::string managerName = manager->getName();
893 auto matcher = [](const Acts::GeometryContext & /*gctx*/,
894 Acts::AxisDirection /*aDir*/, const Acts::Surface * /*aS*/,
895 const Acts::Surface *
896 /*bS*/) -> bool { return false; };
897
898 Acts::SurfaceArrayCreator::Config sacCfg;
899 sacCfg.surfaceMatcher = matcher;
900 sacCfg.doPhiBinningOptimization = false;
901
902 auto surfaceArrayCreator = std::make_shared<Acts::SurfaceArrayCreator>(
903 sacCfg,
904 makeActsAthenaLogger(this, managerName + "SrfArrCrtr", std::string("ActsTGSvc")));
905 Acts::LayerCreator::Config lcCfg;
906 lcCfg.surfaceArrayCreator = surfaceArrayCreator;
907 auto layerCreator = std::make_shared<Acts::LayerCreator>(
908 lcCfg, makeActsAthenaLogger(this, managerName + "LayCrtr", std::string("ActsTGSvc")));
909
911 cfg.mng = static_cast<const HGTD_DetectorManager *>(manager);
912 cfg.elementStore = m_elementStore;
913 cfg.layerCreator = layerCreator;
914 cfg.idHelper = m_HGTD_idHelper;
915 cfg.numberOfBinsFactor = m_numberOfHgtdBinsFactor;
916 return std::make_shared<const ActsHGTDLayerBuilder>(
917 cfg, makeActsAthenaLogger(this, managerName + "GMSLayBldr", std::string("ActsTGSvc")));
918}
919
921 const InDetDD::InDetDetectorManager *manager) {
922 using enum Acts::AxisDirection;
923
924 std::string managerName = manager->getName();
925
926 std::shared_ptr<const Acts::ILayerBuilder> gmLayerBuilder;
927 auto matcher = [](const Acts::GeometryContext & /*gctx*/,
928 Acts::AxisDirection aDir, const Acts::Surface *aS,
929 const Acts::Surface *bS) -> bool {
930 auto* a = getActsDetectorElement(aS);
931 auto* b = getActsDetectorElement(bS);
932
933 if ((not a) or (not b)) {
934 throw std::runtime_error(
935 "Cast of surface associated element to ActsDetectorElement failed "
936 "in TrackingGeometrySvc::makeVolumeBuilder");
937 }
938
939 IdentityHelper idA = a->identityHelper();
940 IdentityHelper idB = b->identityHelper();
941
942 // check if same bec
943 // can't be same if not
944 if (idA.bec() != idB.bec())
945 return false;
946
947 if (aDir == AxisPhi) {
948 // std::cout << idA.phi_module() << " <-> " << idB.phi_module() <<
949 // std::endl;
950 return idA.phi_module() == idB.phi_module();
951 }
952
953 if (aDir == AxisZ) {
954 return (idA.eta_module() == idB.eta_module()) &&
955 (idA.layer_disk() == idB.layer_disk()) && (idA.bec() == idB.bec());
956 }
957
958 if (aDir == AxisR) {
959 return (idA.eta_module() == idB.eta_module()) &&
960 (idA.layer_disk() == idB.layer_disk()) && (idB.bec() == idA.bec());
961 }
962
963 return false;
964 };
965
966 Acts::SurfaceArrayCreator::Config sacCfg;
967 sacCfg.surfaceMatcher = matcher;
968
969 auto surfaceArrayCreator = std::make_shared<Acts::SurfaceArrayCreator>(
970 sacCfg,
971 makeActsAthenaLogger(this, managerName + "SrfArrCrtr", std::string("ActsTGSvc")));
972 Acts::LayerCreator::Config lcCfg;
973 lcCfg.surfaceArrayCreator = surfaceArrayCreator;
974 auto layerCreator = std::make_shared<Acts::LayerCreator>(
975 lcCfg, makeActsAthenaLogger(this, managerName + "LayCrtr", std::string("ActsTGSvc")));
976
978 cfg.surfaceMatcher = matcher;
979
980 // set bins from configuration
981 if (m_barrelMaterialBins.size() != 2) {
982 throw std::invalid_argument("Number of barrel material bin counts != 2");
983 }
984 std::vector<size_t> brlBins(m_barrelMaterialBins);
985 cfg.barrelMaterialBins = {brlBins.at(0), brlBins.at(1)};
986
987 if (m_endcapMaterialBins.size() != 2) {
988 throw std::invalid_argument("Number of endcap material bin counts != 2");
989 }
990 std::vector<size_t> ecBins(m_endcapMaterialBins);
991 cfg.endcapMaterialBins = {ecBins.at(0), ecBins.at(1)};
992
993 cfg.mng = static_cast<const InDetDD::SiDetectorManager *>(manager);
994 // use class member element store
995 cfg.elementStore = m_elementStore;
996 cfg.layerCreator = layerCreator;
997
998 cfg.numberOfBinsFactor = m_numberOfBinsFactor;
999 cfg.surfaceArrayOverfill = static_cast<std::uint8_t>(m_surfaceArrayOverfill.value());
1000
1001 // gmLayerBuilder = std::make_shared<const ActsLayerBuilder>(
1002 // cfg, makeActsAthenaLogger(this, managerName + "GMLayBldr",
1003 // "ActsTGSvc"));
1004
1005 // return gmLayerBuilder;
1006 return cfg;
1007}
1008
1009std::shared_ptr<Acts::TrackingVolume>
1011 const Acts::GeometryContext &gctx, const Acts::ILayerBuilder &sct_lb,
1012 const Acts::ILayerBuilder &trt_lb, const Acts::CylinderVolumeHelper &cvh,
1013 const std::shared_ptr<const Acts::TrackingVolume> &pixel) {
1014 ATH_MSG_VERBOSE("Building SCT+TRT assembly");
1015
1016 Acts::CylinderVolumeBuilder::Config cvbCfg;
1017 Acts::CylinderVolumeBuilder cvb(
1018 cvbCfg, makeActsAthenaLogger(this, std::string("SCTTRTCVB"), std::string("ActsTGSvc")));
1019
1020 ATH_MSG_VERBOSE("Making SCT negative layers: ");
1021 Acts::VolumeConfig sctNegEC =
1022 cvb.analyzeContent(gctx, sct_lb.negativeLayers(gctx), {});
1023 ATH_MSG_VERBOSE("Making SCT positive layers: ");
1024 Acts::VolumeConfig sctPosEC =
1025 cvb.analyzeContent(gctx, sct_lb.positiveLayers(gctx), {});
1026 ATH_MSG_VERBOSE("Making SCT central layers: ");
1027 Acts::VolumeConfig sctBrl =
1028 cvb.analyzeContent(gctx, sct_lb.centralLayers(gctx), {});
1029
1030 ATH_MSG_VERBOSE("Making TRT negative layers: ");
1031 Acts::VolumeConfig trtNegEC =
1032 cvb.analyzeContent(gctx, trt_lb.negativeLayers(gctx), {});
1033 ATH_MSG_VERBOSE("Making TRT positive layers: ");
1034 Acts::VolumeConfig trtPosEC =
1035 cvb.analyzeContent(gctx, trt_lb.positiveLayers(gctx), {});
1036 ATH_MSG_VERBOSE("Making TRT central layers: ");
1037 Acts::VolumeConfig trtBrl =
1038 cvb.analyzeContent(gctx, trt_lb.centralLayers(gctx), {});
1039
1040 // synchronize trt
1041
1042 double absZMinEC = std::min(std::abs(trtNegEC.zMax), std::abs(trtPosEC.zMin));
1043 double absZMaxEC = std::max(std::abs(trtNegEC.zMin), std::abs(trtPosEC.zMax));
1044
1045 trtNegEC.zMin = -absZMaxEC;
1046 trtNegEC.zMax = -absZMinEC;
1047 trtPosEC.zMin = absZMinEC;
1048 trtPosEC.zMax = absZMaxEC;
1049
1050 using CVBBV = Acts::CylinderVolumeBounds::BoundValues;
1051
1052 // if pixel is present, shrink SCT volumes in R
1053 bool isSCTSmallerInZ = false;
1054 if (pixel) {
1055 ATH_MSG_VERBOSE("Shrinking SCT in R (and maybe in increase size in Z) to fit around Pixel");
1056 auto pixelBounds = dynamic_cast<const Acts::CylinderVolumeBounds *>(
1057 &pixel->volumeBounds());
1058 if (!pixelBounds) {
1059 throw std::runtime_error(
1060 "Pixel volume must have cylindrical bounds when building the SCT+TRT assembly");
1061 }
1062 double sctNegECzMin = std::min(sctNegEC.zMin, -pixelBounds->get(CVBBV::eHalfLengthZ));
1063 double sctPosECzMax = std::max(sctPosEC.zMax, pixelBounds->get(CVBBV::eHalfLengthZ));
1064
1065 ATH_MSG_VERBOSE("- SCT +-EC.rMin: " << sctNegEC.rMin << " -> " << pixelBounds->get(CVBBV::eMaxR));
1066 ATH_MSG_VERBOSE("- SCT BRL.rMin: " << sctBrl.rMin << " -> " << pixelBounds->get(CVBBV::eMaxR));
1067 ATH_MSG_VERBOSE("- SCT EC.zMin: " << sctNegEC.zMin << " -> " << sctNegECzMin);
1068 ATH_MSG_VERBOSE("- SCT EC.zMax: " << sctPosEC.zMax << " -> " << sctPosECzMax);
1069
1070 sctNegEC.rMin = pixelBounds->get(CVBBV::eMaxR);
1071 sctPosEC.rMin = pixelBounds->get(CVBBV::eMaxR);
1072 sctBrl.rMin = pixelBounds->get(CVBBV::eMaxR);
1073
1074 isSCTSmallerInZ = sctPosEC.zMax < pixelBounds->get(CVBBV::eHalfLengthZ);
1075
1076 sctNegEC.zMin = sctNegECzMin;
1077 sctPosEC.zMax = sctPosECzMax;
1078
1079
1080 } else {
1081 ATH_MSG_VERBOSE("Pixel is not configured, not wrapping");
1082 }
1083
1084 ATH_MSG_VERBOSE("SCT Volume Configuration:");
1085 ATH_MSG_VERBOSE("- SCT::NegativeEndcap: " << sctNegEC.layers.size()
1086 << " layers, "
1087 << sctNegEC.toString());
1088 ATH_MSG_VERBOSE("- SCT::Barrel: " << sctBrl.layers.size() << " layers, "
1089 << sctBrl.toString());
1090 ATH_MSG_VERBOSE("- SCT::PositiveEncap: " << sctPosEC.layers.size()
1091 << " layers, "
1092 << sctPosEC.toString());
1093
1094 ATH_MSG_VERBOSE("TRT Volume Configuration:");
1095 ATH_MSG_VERBOSE("- TRT::NegativeEndcap: " << trtNegEC.layers.size()
1096 << " layers, "
1097 << trtNegEC.toString());
1098 ATH_MSG_VERBOSE("- TRT::Barrel: " << trtBrl.layers.size() << " layers, "
1099 << trtBrl.toString());
1100 ATH_MSG_VERBOSE("- TRT::PositiveEncap: " << trtPosEC.layers.size()
1101 << " layers, "
1102 << trtPosEC.toString());
1103
1104 // harmonize SCT BRL <-> EC, normally the CVB does this, but we're skipping
1105 // that
1106 sctBrl.zMax = (sctBrl.zMax + sctPosEC.zMin) / 2.;
1107 sctBrl.zMin = -sctBrl.zMax;
1108
1109 // and now harmonize everything
1110 // inflate TRT Barrel to match SCT
1111 trtBrl.zMin = sctBrl.zMin;
1112 trtBrl.zMax = sctBrl.zMax;
1113
1114 // extend TRT endcaps outwards z so they match SCT
1115 trtNegEC.zMin = sctNegEC.zMin;
1116 trtPosEC.zMax = sctPosEC.zMax;
1117
1118 // extend endcap in z so it touches barrel
1119 trtNegEC.zMax = trtBrl.zMin;
1120 sctNegEC.zMax = trtBrl.zMin;
1121 trtPosEC.zMin = trtBrl.zMax;
1122 sctPosEC.zMin = trtBrl.zMax;
1123
1124 // extend SCT in R so they touch TRT barel
1125 sctBrl.rMax = trtBrl.rMin;
1126 sctNegEC.rMax = trtNegEC.rMin;
1127 sctPosEC.rMax = trtPosEC.rMin;
1128
1129 // extend TRT endcaps in r to that of Barrel
1130 trtNegEC.rMax = trtBrl.rMax;
1131 trtPosEC.rMax = trtBrl.rMax;
1132
1133 ATH_MSG_VERBOSE("Dimensions after synchronization between SCT and TRT");
1134 ATH_MSG_VERBOSE("SCT Volume Configuration:");
1135 ATH_MSG_VERBOSE("- SCT::NegativeEndcap: " << sctNegEC.layers.size()
1136 << " layers, "
1137 << sctNegEC.toString());
1138 ATH_MSG_VERBOSE("- SCT::Barrel: " << sctBrl.layers.size() << " layers, "
1139 << sctBrl.toString());
1140 ATH_MSG_VERBOSE("- SCT::PositiveEncap: " << sctPosEC.layers.size()
1141 << " layers, "
1142 << sctPosEC.toString());
1143
1144 ATH_MSG_VERBOSE("TRT Volume Configuration:");
1145 ATH_MSG_VERBOSE("- TRT::NegativeEndcap: " << trtNegEC.layers.size()
1146 << " layers, "
1147 << trtNegEC.toString());
1148 ATH_MSG_VERBOSE("- TRT::Barrel: " << trtBrl.layers.size() << " layers, "
1149 << trtBrl.toString());
1150 ATH_MSG_VERBOSE("- TRT::PositiveEncap: " << trtPosEC.layers.size()
1151 << " layers, "
1152 << trtPosEC.toString());
1153
1154 auto makeTVol = [&](const auto &vConf, const auto &name) {
1155 return cvh.createTrackingVolume(gctx, vConf.layers, {},
1156 nullptr, // no material
1157 vConf.rMin, vConf.rMax, vConf.zMin,
1158 vConf.zMax, name);
1159 };
1160
1161 // now turn them into actual TrackingVolumes
1162 auto tvSctNegEC = makeTVol(sctNegEC, "SCT::NegativeEndcap");
1163 auto tvSctBrl = makeTVol(sctBrl, "SCT::Barrel");
1164 auto tvSctPosEC = makeTVol(sctPosEC, "SCT::PositiveEndcap");
1165
1166 auto tvTrtNegEC = makeTVol(trtNegEC, "TRT::NegativeEndcap");
1167 auto tvTrtBrl = makeTVol(trtBrl, "TRT::Barrel");
1168 auto tvTrtPosEC = makeTVol(trtPosEC, "TRT::PositiveEndcap");
1169
1170 // combine the endcaps and the barrels, respetively
1171 auto negEC =
1172 cvh.createContainerTrackingVolume(gctx, {tvSctNegEC, tvTrtNegEC});
1173 auto posEC =
1174 cvh.createContainerTrackingVolume(gctx, {tvSctPosEC, tvTrtPosEC});
1175 auto barrel = cvh.createContainerTrackingVolume(gctx, {tvSctBrl, tvTrtBrl});
1176
1177 // and now combine all of those into one container for the assembly
1178
1179 auto container =
1180 cvh.createContainerTrackingVolume(gctx, {negEC, barrel, posEC});
1181
1182 // if pixel is present, add positive and negative gap volumes so we can wrap
1183 // it all
1184 if (pixel) {
1185 auto containerBounds = dynamic_cast<const Acts::CylinderVolumeBounds *>(
1186 &container->volumeBounds());
1187 if (!containerBounds) {
1188 throw std::runtime_error(
1189 "SCT+TRT container volume must have cylindrical bounds when wrapping Pixel");
1190 }
1191 auto pixelBounds = dynamic_cast<const Acts::CylinderVolumeBounds *>(
1192 &pixel->volumeBounds());
1193 if (!pixelBounds) {
1194 throw std::runtime_error(
1195 "Pixel volume must have cylindrical bounds when wrapping it with the SCT+TRT assembly");
1196 }
1197 std::vector<std::shared_ptr<Acts::TrackingVolume>> noVolumes;
1198
1199 if(!isSCTSmallerInZ) {
1200 // pixel is smaller in z, need gap volumes
1201 auto posGap = cvh.createGapTrackingVolume(
1202 gctx, noVolumes,
1203 nullptr, // no material,
1204 pixelBounds->get(CVBBV::eMinR), pixelBounds->get(CVBBV::eMaxR),
1205 pixelBounds->get(CVBBV::eHalfLengthZ),
1206 containerBounds->get(CVBBV::eHalfLengthZ),
1207 0, // material layers,
1208 true, // cylinder
1209 "Pixel::PositiveGap");
1210 auto negGap = cvh.createGapTrackingVolume(
1211 gctx, noVolumes,
1212 nullptr, // no material,
1213 pixelBounds->get(CVBBV::eMinR), pixelBounds->get(CVBBV::eMaxR),
1214 -containerBounds->get(CVBBV::eHalfLengthZ),
1215 -pixelBounds->get(CVBBV::eHalfLengthZ),
1216 0, // material layers,
1217 true, // cylinder
1218 "Pixel::NegativeGap");
1219
1220 auto pixelContainer =
1221 cvh.createContainerTrackingVolume(gctx, {negGap, pixel, posGap});
1222 // and now create one container that contains Pixel+SCT+TRT
1223 container =
1224 cvh.createContainerTrackingVolume(gctx, {pixelContainer, container});
1225 }
1226 else {
1227 // wrap the pixel directly
1228 container =
1229 cvh.createContainerTrackingVolume(gctx, {pixel, container});
1230 }
1231
1232 }
1233
1234 return container;
1235}
1236
1238 ATH_MSG_DEBUG("Populate the alignment store with all detector elements");
1239 TrackingGeoAlignVisitor visitor{store};
1240 m_trackingGeometry->apply(visitor);
1241 ATH_MSG_DEBUG("Populated with " << visitor.alignedObjects() << " elements");
1242 return visitor.alignedObjects();
1243}
1245
1246Acts::CylinderVolumeBuilder::Config
1248 std::shared_ptr<const Acts::CylinderVolumeHelper> cvh) const {
1249
1250 // adapted from InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/BeamPipeBuilder.cxx
1251
1252 PVConstLink beamPipeTopVolume = p_beamPipeMgr->getTreeTop(0);
1253
1254 if (p_beamPipeMgr->getNumTreeTops() == 1){
1255 beamPipeTopVolume = p_beamPipeMgr->getTreeTop(0)->getChildVol(0)->getChildVol(0);
1256 }
1257
1258 Acts::Transform3 beamPipeTransform;
1259 beamPipeTransform.setIdentity();
1260
1261 beamPipeTransform = Acts::Translation3(beamPipeTopVolume->getX().translation());
1262
1263 double beamPipeRadius = 20;
1264
1265 const GeoLogVol* beamPipeLogVolume = beamPipeTopVolume->getLogVol();
1266 const GeoTube* beamPipeTube = nullptr;
1267
1268
1269 if (beamPipeLogVolume == nullptr) {
1270 ATH_MSG_ERROR("Beam pip volume has no log volume");
1271 throw std::runtime_error("Beam pip volume has no log volume");
1272 }
1273 // get the geoShape and translate
1274 beamPipeTube = dynamic_cast<const GeoTube*>(beamPipeLogVolume->getShape());
1275 if (beamPipeTube == nullptr){
1276 ATH_MSG_ERROR("BeamPipeLogVolume was not of type GeoTube");
1277 throw std::runtime_error{"BeamPipeLogVolume was not of type GeoTube"};
1278 }
1279
1280 for(unsigned int i=0;i<beamPipeTopVolume->getNChildVols();i++) {
1281
1282 if(beamPipeTopVolume->getNameOfChildVol(i) == "SectionC03"){
1283
1284 PVConstLink childTopVolume = beamPipeTopVolume->getChildVol(i);
1285 const GeoLogVol* childLogVolume = childTopVolume->getLogVol();
1286 const GeoTube* childTube = nullptr;
1287
1288 if (childLogVolume){
1289 childTube = dynamic_cast<const GeoTube*>(childLogVolume->getShape());
1290 if (childTube){
1291 beamPipeRadius = 0.5 * (childTube->getRMax()+childTube->getRMin());
1292 }
1293 }
1294
1295 break; // Exit loop after SectionC03 is found
1296 }
1297
1298 } // Loop over child volumes
1299
1300 ATH_MSG_VERBOSE("BeamPipe constructed from Database: translation (yes) - radius "
1301 << ( beamPipeTube ? "(yes)" : "(no)") << " - r = " << beamPipeRadius );
1302
1303 ATH_MSG_VERBOSE("BeamPipe shift estimated as : " << Amg::toString(beamPipeTransform.translation()));
1304
1305 Acts::CylinderVolumeBuilder::Config cfg;
1306
1307 Acts::PassiveLayerBuilder::Config bplConfig;
1308 bplConfig.layerIdentification = "BeamPipe";
1309 bplConfig.centralLayerRadii = {beamPipeRadius * 1_mm};
1310 bplConfig.centralLayerHalflengthZ = {3000_mm};
1311 bplConfig.centralLayerThickness = {1_mm};
1312 auto beamPipeBuilder = std::make_shared<const Acts::PassiveLayerBuilder>(
1313 bplConfig, makeActsAthenaLogger(this, std::string("BPLayBldr"), std::string("ActsTGSvc")));
1314
1315 // create the volume for the beam pipe
1316 cfg.trackingVolumeHelper = cvh;
1317 cfg.volumeName = "BeamPipe";
1318 cfg.layerBuilder = beamPipeBuilder;
1319 cfg.layerEnvelopeR = {1_mm, 1_mm};
1320 cfg.buildToRadiusZero = true;
1321
1322 return cfg;
1323}
1324
1325
1326const Acts::TrackingVolume*
1328 const Acts::TrackingVolume* retVol{nullptr};
1329 using namespace ActsTrk::detail::GeoVolIds;
1330 switch (envType) {
1331 using enum ActsTrk::SystemEnvelope;
1332 case ITkExit:
1333 retVol = m_trackingGeometry->findVolume(volumeId(s_ITkEnvelopeId));
1334 break;
1335 case HgtdExit:
1336 retVol = m_trackingGeometry->findVolume(volumeId(s_hgtdEnvelopeId));
1337 break;
1338 case HgtdSideA:
1339 retVol = m_trackingGeometry->findVolume(volumeId(s_hgtdPosVolumeId));
1340 break;
1341 case HgtdSideC:
1342 retVol = m_trackingGeometry->findVolume(volumeId(s_hgtdNegVolumeId));
1343 break;
1344 case CaloExit:
1345 retVol = m_trackingGeometry->findVolume(volumeId(s_caloEnvelopeID));
1346 break;
1347 case MsExit:
1348 break;
1349 }
1350 if(!retVol) {
1351 ATH_MSG_WARNING("There is no system envelope "<<envType);
1352 }
1353 return retVol;
1354}
1355
1357 // Release the Detray geometry while the memory resource tool it allocated
1358 // from is still around, which is not guaranteed any more once the service
1359 // itself is destroyed.
1360 m_detrayGeometry.reset();
1361 return AthService::finalize();
1362}
1363
1365 using DetrayDetector = traccc::itk_detector;
1366 using DetrayMetadata = detray::detector_metadata_t<DetrayDetector>;
1367 using namespace ActsTrk::detail::GeoVolIds;
1368 // The Detray detector allocates through this memory resource and keeps
1369 // referring to it for the deallocations, so the tool has to be held for as
1370 // long as m_detrayGeometry lives.
1371 if (m_hostMR.empty()) {
1372 ATH_MSG_ERROR("BuildDetrayGeometry was requested, but no host memory "
1373 "resource tool was configured (HostMR)");
1374 return StatusCode::FAILURE;
1375 }
1376 ATH_CHECK(m_hostMR.retrieve());
1377
1378 // Detray puts the beam pipe volume at detector index 0 and requires it to
1379 // contain the origin, so resolve it by position instead of by GeometryIdentifier.
1380 // An id-based lookup would not work anyway: BeamPipeBlueprintNodeBuilder assigns
1381 // s_beamPipeVolumeId to *every* volume of the beam pipe subtree (the static
1382 // cylinder plus whatever gap volumes the container spawned) and hands out layer
1383 // ids incrementally starting at 1, so findVolume() on volume=s_beamPipeVolumeId
1384 // -- which implies layer == 0 -- never matches.
1385 auto beamPipeResult = m_trackingGeometry->resolveLowestTrackingVolume(
1386 getNominalContext().context(), Acts::Vector3::Zero());
1387 if (!beamPipeResult.ok()) {
1388 ATH_MSG_ERROR("BuildDetrayGeometry was requested, but the tracking volume "
1389 "containing the origin could not be resolved: "
1390 << beamPipeResult.error().message());
1391 return StatusCode::FAILURE;
1392 }
1393
1394 const Acts::TrackingVolume* beamPipeVolume = *beamPipeResult;
1395 if (beamPipeVolume == nullptr) {
1396 ATH_MSG_ERROR("BuildDetrayGeometry was requested, but no tracking volume "
1397 "contains the origin. Detray requires a beam pipe volume "
1398 "covering (0, 0, 0).");
1399 return StatusCode::FAILURE;
1400 }
1401 if (beamPipeVolume->geometryId().volume() != s_beamPipeVolumeId) {
1402 ATH_MSG_WARNING("The tracking volume containing the origin, '"
1403 << beamPipeVolume->volumeName() << "' ("
1404 << beamPipeVolume->geometryId()
1405 << "), is not part of the beam pipe subtree (expected "
1406 "GeometryIdentifier volume=" << s_beamPipeVolumeId
1407 << "). Using it as the Detray beam pipe volume regardless.");
1408 }
1409 ATH_MSG_INFO("Using '" << beamPipeVolume->volumeName() << "' ("
1410 << beamPipeVolume->geometryId() << ") as the Detray beam pipe volume");
1411
1412 ActsPlugins::DetrayPayloadConverter::Config payloadConfig{};
1413 payloadConfig.beampipeVolume = beamPipeVolume;
1414
1415 auto payloadConverter = std::make_shared<const ActsPlugins::DetrayPayloadConverter>(
1416 payloadConfig,
1417 makeActsAthenaLogger(this, "DetrayPayloadCnv", std::string("ActsTGSvc")));
1418
1419 ActsPlugins::DetrayGeometryConverter::Config converterConfig{};
1420 converterConfig.payloadConverter = std::move(payloadConverter);
1421 converterConfig.convertSurfaceGrids = m_buildDetraySurfaceGrids;
1422 converterConfig.convertMaterial = m_buildDetrayMaterial;
1423
1424 ActsPlugins::DetrayGeometryConverter converter(
1425 std::move(converterConfig),
1426 makeActsAthenaLogger(this, "DetrayGeomCnv", std::string("ActsTGSvc")));
1427
1428 ActsPlugins::DetrayGeometryConverter::DetrayGeometry<DetrayMetadata> detrayGeometry{};
1429 try {
1430 detrayGeometry = converter.convert<DetrayMetadata>(
1431 m_hostMR->mr(), getNominalContext().context(), m_trackingGeometry, name());
1432 } catch (const std::exception& e) {
1433 ATH_MSG_ERROR("Failed to convert the Acts::TrackingGeometry into a Detray geometry: " << e.what());
1434 return StatusCode::FAILURE;
1435 }
1436
1437 if (!detrayGeometry.detector) {
1438 ATH_MSG_ERROR("Detray geometry conversion did not produce a detector");
1439 return StatusCode::FAILURE;
1440 }
1441
1443 ATH_MSG_INFO("Checking the consistency of the converted Detray geometry");
1444 try {
1445 detray::detail::check_consistency(*detrayGeometry.detector, true,
1446 detrayGeometry.names);
1447 } catch (const std::exception& e) {
1448 ATH_MSG_ERROR("The converted Detray geometry is not consistent: " << e.what());
1449 return StatusCode::FAILURE;
1450 }
1451 const auto reportDetrayPortalLinks = [this](
1452 const auto& detector, const detray::name_map& names) {
1453 const std::size_t nVolumes = detector.volumes().size();
1454
1455 // Directed portal graph: outgoing[a] holds every volume a portal of
1456 // volume a links into. A healthy interface between a and b shows up as
1457 // a -> b and b -> a.
1458 std::vector<std::set<detray::dindex>> outgoing(nVolumes);
1459 std::size_t nPortals{0};
1460 std::size_t nEndOfWorld{0};
1461
1462 for (const auto& volDesc : detector.volumes()) {
1463 const auto volume = detray::tracking_volume{detector, volDesc};
1464 const detray::dindex volIdx = volume.index();
1465
1466 for (const auto& sfDesc : volume.portals()) {
1467 const auto surface = detray::geometry::surface{detector, sfDesc};
1468 ++nPortals;
1469
1470 for (const auto link : surface.volume_links()) {
1471 if (detray::detail::is_invalid_value(link)) {
1472 ++nEndOfWorld;
1473 continue;
1474 }
1475 if (link == volIdx || link >= nVolumes) {
1476 continue;
1477 }
1478 outgoing[volIdx].insert(link);
1479 }
1480 }
1481 }
1482
1483 std::size_t nReciprocal{0};
1484 std::vector<std::pair<detray::dindex, detray::dindex>> oneWay;
1485 for (detray::dindex a = 0; a < nVolumes; ++a) {
1486 for (const detray::dindex b : outgoing[a]) {
1487 if (outgoing[b].contains(a)) {
1488 ++nReciprocal;
1489 } else {
1490 oneWay.emplace_back(a, b);
1491 }
1492 }
1493 }
1494
1495 auto volName = [&names](detray::dindex idx) -> std::string {
1496 return names.contains(idx) ? names.at(idx)
1497 : std::format("volume {:}", idx);
1498 };
1499
1500 ATH_MSG_INFO("Detray portal links: " << nPortals
1501 << " portal surfaces, " << nEndOfWorld
1502 << " end-of-world links, " << (nReciprocal / 2)
1503 << " reciprocal volume interfaces, " << oneWay.size()
1504 << " one-directional");
1505
1506 if (!oneWay.empty()) {
1507 ATH_MSG_WARNING(oneWay.size()
1508 << " portal links are one-directional: the neighbour "
1509 "volume has no portal linking back. Detray's "
1510 "check_consistency() does not catch this.");
1511 const std::size_t nShow =
1512 std::min<std::size_t>(oneWay.size(), 20);
1513 for (std::size_t i = 0; i < nShow; ++i) {
1514 ATH_MSG_WARNING(" one-way: '" << volName(oneWay[i].first) << "' ("
1515 << oneWay[i].first << ") -> '"
1516 << volName(oneWay[i].second) << "' ("
1517 << oneWay[i].second << ") with no return link");
1518 }
1519 if (oneWay.size() > nShow) {
1520 ATH_MSG_WARNING(" ... and " << (oneWay.size() - nShow) << " more");
1521 }
1522 }
1523 };
1524 reportDetrayPortalLinks(*detrayGeometry.detector, detrayGeometry.names);
1525 }
1526
1527 auto hostDetector = std::make_unique<traccc::host_detector>();
1528 hostDetector->set<DetrayDetector>(std::move(*detrayGeometry.detector));
1529 m_detrayGeometry = std::move(hostDetector);
1530
1531 ATH_MSG_INFO("Successfully built the Detray geometry from the Acts::TrackingGeometry");
1532 return StatusCode::SUCCESS;
1533}
1534
1535std::unique_ptr<ActsTrk::DetectorElementToActsGeometryIdMap>
1537 // create map from
1538 auto detector_element_to_geoid = std::make_unique<DetectorElementToActsGeometryIdMap>();
1539
1540 struct Counter{
1541 unsigned n_sensitive_elements{0};
1542 unsigned n_detector_elements{0};
1543 unsigned n_wrong_type{0};
1544 };
1545 Counter counter {};
1546 trackingGeometry()->visitSurfaces([this, &counter, &detector_element_to_geoid](const Acts::Surface *surface) {
1547 if (!surface || !surface->isSensitive()) {
1548 ++counter.n_wrong_type;
1549 return;
1550 }
1551 ++counter.n_sensitive_elements;
1552 const auto* placement = dynamic_cast<const ISurfacePlacement*>(surface->surfacePlacement());
1553 if (!placement) {
1554 return;
1555 }
1556
1557 auto insert_id = [&detector_element_to_geoid, &surface, &counter](const xAOD::UncalibMeasType type) {
1558 auto * possibleElement = getActsDetectorElement(surface);
1559 if (!possibleElement){
1560 return;
1561 }
1562 auto hash = possibleElement->identifyHash();
1563 detector_element_to_geoid->insert(std::make_pair(makeDetectorElementKey(type, hash),
1564 DetectorElementToActsGeometryIdMap::makeValue(surface->geometryId(), surface)));
1565 ++counter.n_detector_elements;
1566 };
1567 switch(placement->detectorType()) {
1568 using enum DetectorType;
1569 case Pixel:
1571 break;
1572 case Sct:
1574 break;
1575 case Hgtd:
1577 break;
1578 case Trt: {
1579 break;
1580 }
1582 case Mdt:
1583 case Rpc:
1584 case Tgc:
1585 case Csc:
1586 case Mm:
1587 case sTgc:{
1588 // surface map not needed for the muon detectors
1589 ++counter.n_detector_elements;
1590 break;
1591 }
1592 case UnDefined:
1593 ATH_MSG_ERROR("Undefined element encountered");
1594 counter.n_detector_elements = 0;
1595 return;
1596 }
1597 }, true /*sensitive surfaces*/);
1598 ATH_MSG_INFO( "Surfaces without associated detector elements " << (counter.n_sensitive_elements -counter.n_detector_elements)
1599 << " (with " << counter.n_detector_elements << ")" );
1600 if (counter.n_sensitive_elements > 0 &&
1601 counter.n_detector_elements==0) {
1602 ATH_MSG_ERROR( "No surface with associated detector element" );
1603 return nullptr;
1604 }
1605 if (counter.n_wrong_type>0) {
1606 ATH_MSG_WARNING( "Surfaces associated to detector elements not of type Trk::TrkDetElementBase :" << counter.n_wrong_type);
1607 }
1608 return detector_element_to_geoid;
1609}
1610}
Acts::CylinderVolumeBounds::BoundValues CVBBV
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_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_MSG_INFO(x,...)
#define ATH_MSG_FATAL(x,...)
static Double_t a
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
This is an Identifier helper class for the TRT subdetector.
std::unique_ptr< const Acts::Logger > makeActsAthenaLogger(IMessageSvc *svc, const std::string &name, int level, std::optional< std::string > parent_name)
Definition Logger.cxx:64
#define min(a, b)
Definition cfImp.cxx:40
#define max(a, b)
Definition cfImp.cxx:41
Helper to hold elements for deletion.
Acts::GeometryContext context() const
Extension of the interface of the Acts::SurfacePlacementBase for ATLAS.
TrackingGeometryVisitor to load the aligned surface and volume transforms into the DetectorAlignStore...
unsigned alignedObjects() const
Returns how many transforms have been written into the store.
StatusCode buildDetrayGeometry()
Converts the built Acts::TrackingGeometry into a Detray geometry and stores it in m_detrayGeometry.
Gaudi::Property< std::vector< size_t > > m_endcapMaterialBins
Gaudi::Property< std::vector< unsigned int > > m_itkStripBarrelNeighborWindow
std::shared_ptr< const Acts::TrackingGeometry > m_trackingGeometry
const InDetDD::TRT_DetectorManager * p_TRTManager
Gaudi::Property< std::vector< std::string > > m_buildSubdetectors
Gaudi::Property< std::vector< unsigned int > > m_itkPixelInnerBarrelNeighborWindow
Most bins the surface array lookup serves on each side of the crossing, as {phi, z}...
const traccc::host_detector * detrayGeometry() const override
Returns the Detray geometry converted from the Acts::TrackingGeometry, or nullptr if none was built.
Gaudi::Property< std::vector< unsigned int > > m_itkPixelOuterBarrelNeighborWindow
Gaudi::Property< std::vector< unsigned int > > m_itkStripEndcapNeighborWindow
Gaudi::Property< std::vector< float > > m_passiveITkInnerPixelBarrelLayerThickness
ActsLayerBuilder::Config makeLayerBuilderConfig(const InDetDD::InDetDetectorManager *manager)
const InDetDD::SiDetectorManager * p_ITkStripManager
Gaudi::Property< std::vector< unsigned int > > m_subDetNoAlignProp
Define the subdetectors for which the tracking geometry does not expect a valid alignment store.
unsigned int populateAlignmentStore(ActsTrk::DetectorAlignStore &store) const override
Loops through the volumes of the tracking geometry and caches the aligned transforms in the store.
Gaudi::Property< std::vector< float > > m_passiveITkOuterPixelBarrelLayerThickness
ToolHandleArray< ActsTrk::IRefineTrackingGeoTool > m_refineVisitors
Gaudi::Property< std::vector< float > > m_passiveITkOuterPixelBarrelLayerHalflengthZ
Acts::CylinderVolumeBuilder::Config makeBeamPipeConfig(std::shared_ptr< const Acts::CylinderVolumeHelper > cvh) const
Gaudi::Property< std::vector< unsigned int > > m_itkPixelOuterEndcapNeighborWindow
Gaudi::Property< std::vector< float > > m_passiveITkStripBarrelLayerRadii
ToolHandle< AthDevice::IMemoryResourceTool > m_hostMR
Tool providing the memory resource that the Detray geometry is allocated from.
Gaudi::Property< std::vector< float > > m_passiveITkStripBarrelLayerThickness
std::shared_ptr< const Acts::ILayerBuilder > makeHGTDLayerBuilder(const HGTD_DetectorManager *manager)
Gaudi::Property< double > m_numberOfHgtdBinsFactor
Special treatment for hgtd layers as well.
std::unique_ptr< const ActsTrk::DetectorElementToActsGeometryIdMap > m_detIdMap
Gaudi::Property< bool > m_printGeo
Print the assembled tracking geometry after building.
Gaudi::Property< unsigned int > m_surfaceArrayOverfill
Extra cells per direction and axis that each surface fills around its footprint.
Gaudi::Property< std::vector< float > > m_passiveITkInnerPixelBarrelLayerRadii
the specifications for building additional passive cylinders in the barrel region: for each cylinder ...
const ActsTrk::GeometryContext & getNominalContext() const override
Returns an empty nominal context without any alignment caches.
std::shared_ptr< const Acts::ILayerBuilder > makeStrawLayerBuilder(const InDetDD::InDetDetectorManager *manager)
Gaudi::Property< std::vector< size_t > > m_barrelMaterialBins
ToolHandleArray< ActsTrk::IBlueprintNodeBuilder > m_blueprintNodeBuilders
virtual const ActsTrk::DetectorElementToActsGeometryIdMap * surfaceIdMap() const override
Returns the pointer to the identifier mapping between Acts::surface ID & IdentifierHash of the ITk su...
ToolHandle< IActsTrackingVolumeBuilder > m_caloVolumeBuilder
std::unique_ptr< ActsTrk::DetectorElementToActsGeometryIdMap > createDetectorElementToGeoIdMap() const
Creates and popules the DetectorElement -> Acts::Surface geo identifier map from the geometry service...
std::shared_ptr< const Acts::TrackingGeometry > trackingGeometry() const override
Returns a pointer to the internal ACTS tracking geometry.
std::unique_ptr< traccc::host_detector > m_detrayGeometry
Gaudi::Property< std::vector< float > > m_passiveITkOuterPixelBarrelLayerRadii
const Acts::TrackingVolume * getEnvelope(const ActsTrk::SystemEnvelope envType) const override
Returns the envelope volume from the tracking geometry that's containing all volumes of the subsystem...
Gaudi::Property< std::vector< float > > m_passiveITkInnerPixelBarrelLayerHalflengthZ
std::shared_ptr< ActsElementVector > m_elementStore
Gaudi::Property< std::vector< float > > m_passiveITkStripBarrelLayerHalflengthZ
TrackingGeometrySvc(const std::string &name, ISvcLocator *pSvcLocator)
Gaudi::Property< double > m_numberOfBinsFactor
controls how many bins are created for the sensitive surface grid.
Gaudi::Property< std::vector< unsigned int > > m_itkPixelInnerEndcapNeighborWindow
const InDetDD::SiDetectorManager * p_ITkPixelManager
std::shared_ptr< Acts::TrackingVolume > makeSCTTRTAssembly(const Acts::GeometryContext &gctx, const Acts::ILayerBuilder &sct_lb, const Acts::ILayerBuilder &trt_lb, const Acts::CylinderVolumeHelper &cvh, const std::shared_ptr< const Acts::TrackingVolume > &pixel)
The Detector manager has methods to retrieve the Identifier helper and methods to retrieve the detect...
int phi_module() const
int eta_module() const
int layer_disk() const
Virtual base class for all ID detector managers.
Class to hold geometrical description of a silicon detector element.
Base class for Pixel and SCT Detector managers.
Trk::Surface & surface()
Element Surface.
The Detector Manager for all TRT Detector elements, it acts as the interface to the detector elements...
int lb
Definition globals.cxx:23
bool contains(const std::string &s, const std::string &regx)
does a string contain the substring
Definition hcg.cxx:116
static Root::TMsgLogger logger("iLumiCalc")
Define the volume parts of the GeometryIdentifier for each ATLAS subsystem centrally.
constexpr std::size_t s_hgtdEnvelopeId
constexpr std::size_t s_hgtdNegVolumeId
constexpr std::size_t s_caloEnvelopeID
Volume Ids ofthe Calorimeter.
constexpr std::size_t s_hgtdPosVolumeId
HGTD volume IDs.
constexpr std::size_t s_beamPipeVolumeId
constexpr std::size_t s_ITkEnvelopeId
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.
@ Mm
Maybe not needed in the migration.
@ Tgc
Resitive Plate Chambers.
@ sTgc
Micromegas (NSW).
@ Rpc
Monitored Drift Tubes.
@ Csc
Thin gap champers.
@ Mdt
MuonSpectrometer.
@ UnDefined
Small Thing Gap chambers (NSW).
DetectorElementKey makeDetectorElementKey(xAOD::UncalibMeasType meas_type, unsigned int identifier_hash)
Acts::Logging::Level actsLevelVector(MSG::Level lvl)
SystemEnvelope
Define an enumeration to retrieve the envelope tracking volume from.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
Acts::GeometryIdentifier volumeId(const Acts::Surface &surface)
Returns the identifier of the volume in which the surface is embedded.
STL namespace.
UncalibMeasType
Define the type of the uncalibrated measurement.
nested configuration struct for steering of the layer builder
nested configuration struct for steering of the layer builder
static DetectorElementGeoInfo makeValue(const Acts::GeometryIdentifier &geo_id, const Acts::Surface *surface=nullptr)
MsgStream & msg
Definition testRead.cxx:32