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/Json/JsonMaterialDecorator.hpp>
44#include <ActsPlugins/Json/MaterialMapJsonConverter.hpp>
45#include <Acts/Surfaces/PlanarBounds.hpp>
46#include <Acts/Surfaces/AnnulusBounds.hpp>
47#include <Acts/Surfaces/DiscSurface.hpp>
48#include <Acts/Surfaces/LineSurface.hpp>
49#include <Acts/Surfaces/RectangleBounds.hpp>
50#include <Acts/Visualization/ObjVisualization3D.hpp>
51#include <Acts/Visualization/ViewConfig.hpp>
52#include <Acts/Geometry/detail/TrackingGeometryPrintVisitor.hpp>
53
54// PACKAGE
61#include "ActsInterop/Logger.h"
63
65#include <Acts/Utilities/AxisDefinitions.hpp>
66#include <limits>
67#include <random>
68#include <stdexcept>
69
70using namespace Acts::UnitLiterals;
71
72namespace {
75 Acts::ViewConfigFunc viewConfigFunc(const Acts::ViewConfig& volumeCfg,
76 const Acts::ViewConfig& portalCfg,
77 const Acts::ViewConfig& sensitiveCfg) {
78 //coverity[AUTO_CAUSES_COPY]
79 return [volumeCfg, portalCfg, sensitiveCfg](const Acts::GeometryObject& geoObj) {
80 if (geoObj.geometryId().boundary() != 0) {
81 return portalCfg;
82 }
83 if (geoObj.geometryId().sensitive() != 0) {
84 return sensitiveCfg;
85 }
86 return volumeCfg;
87 };
88 }
89}
90
91namespace ActsTrk{
93 ISvcLocator *svc)
94 : base_class(name, svc),
95 m_detStore("StoreGateSvc/DetectorStore", name),
96 m_elementStore (std::make_shared<ActsElementVector>())
97{
98}
99
101 ATH_MSG_INFO(name() << " is initializing");
102 for (unsigned int skipAlign : m_subDetNoAlignProp) {
103 try {
104 m_subDetNoAlign.insert(static_cast<DetectorType>(skipAlign));
105 } catch (...) {
106 ATH_MSG_FATAL("Failed to interpret " << m_subDetNoAlignProp << " as ActsDetectorElements");
107 return StatusCode::FAILURE;
108 }
109 }
110 ATH_CHECK(m_caloVolumeBuilder.retrieve(EnableTool{!m_caloVolumeBuilder.empty()}));
111
112 // FIXME: ActsCaloTrackingVolumeBuilder holds ReadHandle to
113 // CaloDetDescrManager. Hopefully this service is never called before that
114 // object is available.
115 m_autoRetrieveTools = false;
116 m_checkToolDeps = false;
117
118 ATH_MSG_INFO("ACTS version is: v"
119 << Acts::VersionMajor << "." << Acts::VersionMinor << "."
120 << Acts::VersionPatch << " [" << Acts::CommitHash.value_or("unknown hash") << "]");
121
122 // load which subdetectors to build from property
123 std::set<std::string, std::less<>> buildSubdet(m_buildSubdetectors.begin(),
124 m_buildSubdetectors.end());
125 ATH_MSG_INFO("Configured to build " << buildSubdet.size()
126 << " subdetectors:");
127 for (const auto &s : buildSubdet) {
128 ATH_MSG_INFO(" - " << s);
129 }
130
131 ATH_MSG_DEBUG("Loading detector manager(s)");
132 if (buildSubdet.contains("Pixel") ) {
133 ATH_CHECK(m_detStore->retrieve(p_pixelManager, "Pixel"));
134 }
135 if (buildSubdet.contains("SCT") ) {
136 ATH_CHECK(m_detStore->retrieve(p_SCTManager, "SCT"));
137 }
138 if (buildSubdet.contains("TRT") ) {
139 ATH_CHECK(m_detStore->retrieve(p_TRTManager, "TRT"));
140 ATH_CHECK(m_detStore->retrieve(m_TRT_idHelper, "TRT_ID"));
141 }
142 if (buildSubdet.contains("ITkPixel") ) {
143 ATH_CHECK(m_detStore->retrieve(p_ITkPixelManager, "ITkPixel"));
144 }
145 if (buildSubdet.contains("ITkStrip") ) {
146 ATH_CHECK(m_detStore->retrieve(p_ITkStripManager, "ITkStrip"));
147 }
148 if (buildSubdet.contains("HGTD") ) {
149 ATH_CHECK(m_detStore->retrieve(p_HGTDManager, "HGTD"));
150 ATH_CHECK(m_detStore->retrieve(m_HGTD_idHelper, "HGTD_ID"));
151 }
152
153 if(m_buildBeamPipe) {
154 ATH_CHECK(m_detStore->retrieve(p_beamPipeMgr, "BeamPipe"));
155 }
156
157 // Consistency check on the size vectors for passive layers
160 ATH_MSG_FATAL("Consistency check for ITk inner pixel barrel passive layer construction failed. Please check your inputs! ");
161 return StatusCode::FAILURE;
162 }
163
166 ATH_MSG_FATAL("Consistency check for ITk outer pixel barrel passive layer construction failed. Please check your inputs! ");
167 return StatusCode::FAILURE;
168 }
169
172 ATH_MSG_FATAL("Consistency check for ITk strip barrel passive layer construction failed. Please check your inputs! ");
173 return StatusCode::FAILURE;
174 }
175
176 if (m_useBlueprint) {
177
178
179 ATH_MSG_INFO("Using Blueprint API for geometry construction");
180 std::set<std::string, std::less<>> buildSubdet(m_buildSubdetectors.begin(),
181 m_buildSubdetectors.end());
182
184 ATH_CHECK(m_refineVisitors.retrieve());
185
186 using enum Acts::AxisDirection;
187
188 std::vector<ActsTrk::IBlueprintNodeBuilder*> ptrBuilders;
189 std::transform(m_blueprintNodeBuilders.begin(), m_blueprintNodeBuilders.end(),
190 std::back_inserter(ptrBuilders),
191 [](ToolHandle<ActsTrk::IBlueprintNodeBuilder>& b) { return b.get(); });
192
193 auto logger = makeActsAthenaLogger(this, name());
194
195 Acts::Blueprint::Config cfg;
196 cfg.envelope[AxisZ] = {20_mm, 20_mm};
197 cfg.envelope[AxisR] = {0_mm, 20_mm};
198
199 auto blueprint = std::make_unique<Acts::Blueprint>(cfg);
200
201 auto& root = blueprint->addCylinderContainer("Detector", AxisZ);
202 //The starting top node
203 std::shared_ptr<Acts::BlueprintNode> currentTop{nullptr};
204
205 for (auto& builder : ptrBuilders) {
206 currentTop = builder->buildBlueprintNode(getNominalContext().context(), std::move(currentTop));
207
208 }
209
210 root.addChild(std::move(currentTop));
211
212 Acts::BlueprintOptions blueprintOptions;
213 blueprintOptions.keepGoingOnMaterialMergeFailure = m_keepGoingOnMaterialMergeFailure;
214 std::unique_ptr<Acts::TrackingGeometry> trackingGeometry = blueprint->construct(
215 blueprintOptions, getNominalContext().context(), *logger->clone(std::nullopt, Acts::Logging::DEBUG));
216
217 for (auto& refineVisitor : m_refineVisitors) {
218 trackingGeometry->apply(*refineVisitor);
219 ATH_CHECK(refineVisitor->finalize());
220 }
221 m_refineVisitors.clear();
222
224
225 if (m_objDebugOutput) {
226 Acts::ObjVisualization3D vis;
227 m_trackingGeometry->visualize(vis, getNominalContext().context(),
228 viewConfigFunc({.visible = false}, {.visible = false}, {.visible = true}));
229 vis.write("blueprint_sensitive.obj");
230 vis.clear();
231
232 m_trackingGeometry->visualize(vis, getNominalContext().context(),
233 viewConfigFunc({.visible = true}, {.visible = false}, {.visible = false}));
234 vis.write("blueprint_volume.obj");
235 vis.clear();
236
237 m_trackingGeometry->visualize(vis, getNominalContext().context(),
238 viewConfigFunc({.visible = false}, {.visible = true}, {.visible = false}));
239 vis.write("blueprint_portals.obj");
240 }
241 if (m_printGeo) {
242 Acts::detail::TrackingGeometryPrintVisitor printer{m_nominalContext.context()};
243 m_trackingGeometry->apply(printer);
244 ATH_MSG_INFO("Built tracking geometry \n"<<printer.stream().str());
245 }
247 if (!m_detIdMap) {
248 return StatusCode::FAILURE;
249 }
250
251 return StatusCode::SUCCESS;
252 }
253
254 ATH_MSG_DEBUG("Setting up ACTS geometry helpers");
255
256 Acts::LayerArrayCreator::Config lacCfg;
257 auto layerArrayCreator = std::make_shared<const Acts::LayerArrayCreator>(
258 lacCfg, makeActsAthenaLogger(this, std::string("LayArrCrtr"), std::string("ActsTGSvc")));
259
260 Acts::TrackingVolumeArrayCreator::Config tvcCfg;
261 auto trackingVolumeArrayCreator =
262 std::make_shared<const Acts::TrackingVolumeArrayCreator>(
263 tvcCfg, makeActsAthenaLogger(this, std::string("TrkVolArrCrtr"), std::string("ActsTGSvc")));
264
265 Acts::CylinderVolumeHelper::Config cvhConfig;
266 cvhConfig.layerArrayCreator = layerArrayCreator;
267 cvhConfig.trackingVolumeArrayCreator = trackingVolumeArrayCreator;
268
269 auto cylinderVolumeHelper =
270 std::make_shared<const Acts::CylinderVolumeHelper>(
271 cvhConfig, makeActsAthenaLogger(this, std::string("CylVolHlpr"), std::string("ActsTGSvc")));
272
273 Acts::TrackingGeometryBuilder::Config tgbConfig;
274 tgbConfig.trackingVolumeHelper = cylinderVolumeHelper;
275
276 if (m_useMaterialMap) {
277 std::shared_ptr<const Acts::IMaterialDecorator> matDeco = nullptr;
278
279 std::string matFileFullPath = PathResolverFindCalibFile(m_materialMapCalibFolder.value()+"/"+m_materialMapInputFileBase.value());
280 if (matFileFullPath.empty()) {
281 ATH_MSG_ERROR( "Material Map Input File " << m_materialMapCalibFolder.value() << "/" << m_materialMapInputFileBase.value() << " not found.");
282 return StatusCode::FAILURE;
283 }
284 ATH_MSG_INFO("Configured to use material input: " << matFileFullPath);
285
286 if (matFileFullPath.find(".json") != std::string::npos) {
287 // Set up the converter first
288 Acts::MaterialMapJsonConverter::Config jsonGeoConvConfig;
289 // Set up the json-based decorator
290 matDeco = std::make_shared<const Acts::JsonMaterialDecorator>(
291 jsonGeoConvConfig, matFileFullPath, ActsTrk::actsLevelVector(msg().level()));
292 }
293 tgbConfig.materialDecorator = std::move(matDeco);
294 }
295
296 std::array<double, 2> sctECEnvelopeZ{20_mm, 20_mm};
297
298 try {
299 // BeamPipe
300 if(m_buildBeamPipe) {
301 tgbConfig.trackingVolumeBuilders.push_back([&](const auto &gctx,
302 const auto &inner,
303 const auto &) {
304
305 Acts::CylinderVolumeBuilder::Config bpvConfig =
306 makeBeamPipeConfig(cylinderVolumeHelper);
307
308 Acts::CylinderVolumeBuilder beamPipeVolumeBuilder {
309 bpvConfig, makeActsAthenaLogger(this, std::string("BPVolBldr"), std::string("ActsTGSvc"))};
310
311 return beamPipeVolumeBuilder.trackingVolume(gctx, inner);
312 });
313 }
314
315
316
317 // PIXEL
318 if (buildSubdet.contains("Pixel")) {
319 tgbConfig.trackingVolumeBuilders.push_back([&](const auto &gctx,
320 const auto &inner,
321 const auto &) {
324 auto lb = std::make_shared<ActsLayerBuilder>(
325 cfg, makeActsAthenaLogger(this, std::string("PixelGMSLayBldr"), std::string("ActsTGSvc")));
326 Acts::CylinderVolumeBuilder::Config cvbConfig;
327 cvbConfig.layerEnvelopeR = {3_mm, 3_mm};
328 cvbConfig.layerEnvelopeZ = 1_mm;
329 cvbConfig.trackingVolumeHelper = cylinderVolumeHelper;
330 cvbConfig.volumeName = "Pixel";
331 cvbConfig.layerBuilder = lb;
332 cvbConfig.buildToRadiusZero = !m_buildBeamPipe;
333
334 Acts::CylinderVolumeBuilder cvb(
335 cvbConfig, makeActsAthenaLogger(this, std::string("CylVolBldr"), std::string("ActsTGSvc")));
336
337 return cvb.trackingVolume(gctx, inner);
338 });
339 }
340
341 // ITK PIXEL
342 if (buildSubdet.contains("ITkPixel") ) {
343 tgbConfig.trackingVolumeBuilders.push_back(
344 [&](const auto &gctx, const auto &inner, const auto &) {
347 cfg.objDebugOutput = m_objDebugOutput;
348 cfg.doEndcapLayerMerging = true;
349 cfg.passiveBarrelLayerRadii = m_passiveITkInnerPixelBarrelLayerRadii;
350 cfg.passiveBarrelLayerHalflengthZ = m_passiveITkInnerPixelBarrelLayerHalflengthZ;
351 cfg.passiveBarrelLayerThickness = m_passiveITkInnerPixelBarrelLayerThickness;
352 auto lb = std::make_shared<ActsLayerBuilder>(
353 cfg, makeActsAthenaLogger(this, std::string("ITkPxInLb"), std::string("ActsTGSvc")));
354
355 Acts::CylinderVolumeBuilder::Config cvbConfig;
356 cvbConfig.layerEnvelopeR = {5_mm, 5_mm};
357 cvbConfig.layerEnvelopeZ = 1_mm;
358 cvbConfig.trackingVolumeHelper = cylinderVolumeHelper;
359 cvbConfig.volumeName = "ITkPixelInner";
360 cvbConfig.layerBuilder = lb;
361 cvbConfig.buildToRadiusZero = !m_buildBeamPipe;
362
363 Acts::CylinderVolumeBuilder cvb(
364 cvbConfig,
365 makeActsAthenaLogger(this, std::string("CylVolBldr"), std::string("ActsTGSvc")));
366
367 return cvb.trackingVolume(gctx, inner);
368 });
369
370 tgbConfig.trackingVolumeBuilders.push_back(
371 [&](const auto &gctx, const auto &inner, const auto &) {
374 cfg.objDebugOutput = m_objDebugOutput;
375 cfg.doEndcapLayerMerging = false;
376 cfg.passiveBarrelLayerRadii = m_passiveITkOuterPixelBarrelLayerRadii;
377 cfg.passiveBarrelLayerHalflengthZ = m_passiveITkOuterPixelBarrelLayerHalflengthZ;
378 cfg.passiveBarrelLayerThickness = m_passiveITkOuterPixelBarrelLayerThickness;
379 auto lb = std::make_shared<ActsLayerBuilder>(
380 cfg, makeActsAthenaLogger(this, std::string("ITkPxOtLb"), std::string("ActsTGSvc")));
381
382 Acts::CylinderVolumeBuilder::Config cvbConfig;
383 cvbConfig.layerEnvelopeR = {5_mm, 5_mm};
384 cvbConfig.layerEnvelopeZ = 1_mm;
385 cvbConfig.trackingVolumeHelper = cylinderVolumeHelper;
386 cvbConfig.volumeName = "ITkPixelOuter";
387 cvbConfig.layerBuilder = lb;
388 cvbConfig.buildToRadiusZero = false;
389 cvbConfig.checkRingLayout = true;
390 cvbConfig.ringTolerance = 10_mm;
391
392 Acts::CylinderVolumeBuilder cvb(
393 cvbConfig,
394 makeActsAthenaLogger(this, std::string("CylVolBldr"), std::string("ActsTGSvc")));
395
396 return cvb.trackingVolume(gctx, inner);
397 });
398 }
399
400 // ITK STRIP
401 if (buildSubdet.contains("ITkStrip")) {
402 tgbConfig.trackingVolumeBuilders.push_back(
403 [&](const auto &gctx, const auto &inner, const auto &) {
406 cfg.objDebugOutput = m_objDebugOutput;
407 cfg.passiveBarrelLayerRadii = m_passiveITkStripBarrelLayerRadii;
408 cfg.passiveBarrelLayerHalflengthZ = m_passiveITkStripBarrelLayerHalflengthZ;
409 cfg.passiveBarrelLayerThickness = m_passiveITkStripBarrelLayerThickness;
410 auto lb = std::make_shared<ActsLayerBuilder>(
411 cfg, makeActsAthenaLogger(this, std::string("ITkStripLB"), std::string("ActsTGSvc")));
412
413 Acts::CylinderVolumeBuilder::Config cvbConfig;
414 cvbConfig.layerEnvelopeR = {5_mm, 5_mm};
415 cvbConfig.layerEnvelopeZ = 1_mm;
416 cvbConfig.trackingVolumeHelper = cylinderVolumeHelper;
417 cvbConfig.volumeName = "ITkStrip";
418 cvbConfig.layerBuilder = lb;
419 cvbConfig.buildToRadiusZero =
420 !buildSubdet.contains("ITkPixel") && !m_buildBeamPipe;
421
422 Acts::CylinderVolumeBuilder cvb(
423 cvbConfig,
424 makeActsAthenaLogger(this, std::string("CylVolBldr"), std::string("ActsTGSvc")));
425
426 return cvb.trackingVolume(gctx, inner);
427 });
428 }
429
430 bool buildSCT = buildSubdet.contains("SCT") ;
431 bool buildTRT = buildSubdet.contains("TRT");
432
433 if (buildSCT && buildTRT) {
434 // building both we need to take care
435 tgbConfig.trackingVolumeBuilders.push_back(
436 [&](const auto &gctx, const auto &inner, const auto &) {
439 cfg.endcapEnvelopeZ = sctECEnvelopeZ;
440 auto sct_lb = std::make_shared<ActsLayerBuilder>(
441 cfg, makeActsAthenaLogger(this, std::string("SCTGMSLayBldr"), std::string("ActsTGSvc")));
442
443 auto trt_lb = makeStrawLayerBuilder(p_TRTManager);
444
445 return makeSCTTRTAssembly(gctx, *sct_lb, *trt_lb,
446 *cylinderVolumeHelper, inner);
447 });
448
449 } else if (buildSCT) {
450 tgbConfig.trackingVolumeBuilders.push_back(
451 [&](const auto &gctx, const auto &inner, const auto &) {
453 lbCfg.mode = ActsLayerBuilder::Mode::SCT;
454 lbCfg.endcapEnvelopeZ = sctECEnvelopeZ;
455 auto lb = std::make_shared<ActsLayerBuilder>(
456 lbCfg,
457 makeActsAthenaLogger(this, std::string("SCTGMSLayBldr"), std::string("ActsTGSvc")));
458
459 Acts::CylinderVolumeBuilder::Config cvbConfig;
460 cvbConfig.layerEnvelopeR = {5_mm, 5_mm};
461 cvbConfig.layerEnvelopeZ = 2_mm;
462 cvbConfig.trackingVolumeHelper = cylinderVolumeHelper;
463 cvbConfig.volumeName = "SCT";
464 cvbConfig.layerBuilder = lb;
465 cvbConfig.buildToRadiusZero = false;
466
467 Acts::CylinderVolumeBuilder cvb(
468 cvbConfig,
469 makeActsAthenaLogger(this, std::string("SCTCylVolBldr"), std::string("ActsTGSvc")));
470
471 return cvb.trackingVolume(gctx, inner);
472 });
473 } else if (buildTRT) {
474 tgbConfig.trackingVolumeBuilders.push_back(
475 [&](const auto &gctx, const auto &inner, const auto &) {
477 Acts::CylinderVolumeBuilder::Config cvbConfig;
478 cvbConfig.layerEnvelopeR = {5_mm, 5_mm};
479 cvbConfig.layerEnvelopeZ = 2_mm;
480 cvbConfig.trackingVolumeHelper = cylinderVolumeHelper;
481 cvbConfig.volumeName = "TRT";
482 cvbConfig.layerBuilder = std::move(lb);
483 cvbConfig.buildToRadiusZero = false;
484
485 Acts::CylinderVolumeBuilder cvb(
486 cvbConfig,
487 makeActsAthenaLogger(this, std::string("TRTCylVolBldr"), std::string("ActsTGSvc")));
488
489 return cvb.trackingVolume(gctx, inner);
490 });
491 }
492
493 //HGTD
494 if(buildSubdet.contains("HGTD") ) {
495 tgbConfig.trackingVolumeBuilders.push_back(
496 [&](const auto &gctx, const auto &inner, const auto &) {
497 auto lb = makeHGTDLayerBuilder(p_HGTDManager); //using ActsHGTDLayerBuilder
498 Acts::CylinderVolumeBuilder::Config cvbConfig;
499 cvbConfig.layerEnvelopeR = {5_mm, 5_mm};
500 cvbConfig.layerEnvelopeZ = 1_mm;
501 cvbConfig.trackingVolumeHelper = cylinderVolumeHelper;
502 cvbConfig.volumeName = "HGTD";
503 cvbConfig.layerBuilder = std::move(lb);
504 cvbConfig.buildToRadiusZero = false;
505
506 Acts::CylinderVolumeBuilder cvb(
507 cvbConfig,
508 makeActsAthenaLogger(this, std::string("HGTDCylVolBldr"), std::string("ActsTGSvc")));
509
510 return cvb.trackingVolume(gctx, inner);
511 });
512 }
513
514 // Calo
515 if (m_caloVolumeBuilder.isEnabled()) {
516 tgbConfig.trackingVolumeBuilders.push_back(
517 [&](const auto &gctx, const auto &inner, const auto &) {
518 return m_caloVolumeBuilder->trackingVolume(gctx, inner, nullptr);
519 });
520 }
521
522 } catch (const std::exception &e) {
523 ATH_MSG_ERROR("Encountered error when building Acts tracking geometry");
524 ATH_MSG_ERROR(e.what());
525 return StatusCode::FAILURE;
526 }
527
528 auto trackingGeometryBuilder =
529 std::make_shared<const Acts::TrackingGeometryBuilder>(
530 tgbConfig, makeActsAthenaLogger(this, std::string("TrkGeomBldr"), std::string("ActsTGSvc")));
531
532 ATH_MSG_VERBOSE("Begin building process");
534 trackingGeometryBuilder->trackingGeometry(getNominalContext().context());
535 ATH_MSG_VERBOSE("Building process completed");
536
537 if (!m_trackingGeometry) {
538 ATH_MSG_ERROR("No ACTS tracking geometry was built. Cannot proceeed");
539 return StatusCode::FAILURE;
540 }
541
542
544 ATH_MSG_INFO("Running extra consistency check! (this is SLOW)");
545 if(!runConsistencyChecks()) {
546 ATH_MSG_ERROR("Consistency check has failed! Geometry is not consistent");
547 return StatusCode::FAILURE;
548 }
549 }
550
552 if (!m_detIdMap) {
553 return StatusCode::FAILURE;
554 }
555
556
557 ATH_MSG_INFO("Acts TrackingGeometry construction completed");
558
559 return StatusCode::SUCCESS;
560}
565 bool result = true;
566
567 std::vector<Acts::Vector2> localPoints;
568 localPoints.reserve(m_consistencyCheckPoints);
569 std::mt19937 gen;
570 std::uniform_real_distribution<> dist(0.0, 1.0);
571
572 std::optional<std::ofstream> os;
573 if(!m_consistencyCheckOutput.empty()){
574 os = std::ofstream{m_consistencyCheckOutput};
575 if(!os->good()) {
576 throw std::runtime_error{"Failed to open consistency check output file"};
577 }
578 }
579
580 if(os) {
581 (*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;
582 }
583 for(size_t i=0;i<m_consistencyCheckPoints;i++) {
584 localPoints.emplace_back(dist(gen), dist(gen));
585 }
586
587 Acts::GeometryContext gctx = getNominalContext().context();
588
589 size_t nTotalSensors = 0;
590 std::array<size_t,3> nInconsistent{0,0,0};
591 size_t nMismatchedCenters = 0;
592 size_t nMismatchedNormals = 0;
593
594 // Comparison of Eigen vectors, similar to a.isApprox(b), but use absolute comparison to also work with zero vectors.
595 // All values will be mm or radians, so 1e-5 is a reasonable precision.
596 auto isApprox = [](auto& a, auto& b) -> bool {
597 return ((a - b).array().abs() < 1e-5).all();
598 };
599
600 m_trackingGeometry->visitSurfaces([&](const Acts::Surface *surface) {
601 nTotalSensors++;
602 const auto* actsDetElem = getActsDetectorElement(surface);
603 if(actsDetElem == nullptr) {
604 ATH_MSG_ERROR("Invalid detector element found");
605 result = false;
606 return;
607 }
608 const auto* siDetElem = dynamic_cast<const InDetDD::SiDetectorElement*>(actsDetElem->upstreamDetectorElement());
609 if(siDetElem == nullptr) {
610 return;
611 }
612
613 const auto* regSurface = dynamic_cast<const Acts::RegularSurface*>(surface);
614 const auto& trkSurface = siDetElem->surface();
615 if(regSurface == nullptr) {
616 ATH_MSG_ERROR("Invalid surface found");
617 result = false;
618 return;
619 }
620
621 Acts::Vector3 center{regSurface->center(gctx)};
622 Amg::Vector3D trkCenter{trkSurface.center()};
623 if (/* auto *b = */ dynamic_cast<const Acts::AnnulusBounds *>(&surface->bounds()))
624 {
625 // // Acts::AnnulusBounds defines center() as center of whole disc, so get it from the bounds
626 // Acts::Vector2 locCenter{0.5 * (b->rMin() + b->rMax()), 0.5 * (b->phiMin() + b->phiMax())};
627 // center = surface->localToGlobal(gctx, locCenter, Acts::Vector3::Zero());
628 center.head<2>() = trkCenter.head<2>(); // that doesn't (quite) work for xy, so just pass that check
629 }
630
631 if(!isApprox(trkCenter, center)) {
632 std::string trkName;
633 if (auto idHelper = siDetElem->getIdHelper())
634 {
635 trkName = idHelper->show_to_string(siDetElem->identify());
636 }
637 ATH_MSG_WARNING("Acts surface "
638 << surface->geometryId()
639 << " center (" << center[0] << ',' << center[1] << ',' << center[2]
640 << ") does not match Trk surface " << trkName
641 << " center (" << trkCenter[0] << ',' << trkCenter[1] << ',' << trkCenter[2] << ')');
642 nMismatchedCenters++;
643 result = false;
644 }
645
646 const auto* lineSurface = dynamic_cast<const Acts::LineSurface*>(surface);
647 if(lineSurface == nullptr) {
648 Acts::Vector3 norm{regSurface->normal(gctx, regSurface->center(gctx))};
649 Amg::Vector3D trkNorm{trkSurface.normal()};
650 if(!isApprox(trkNorm, norm)) {
651 std::string trkName;
652 if (auto idHelper = siDetElem->getIdHelper())
653 {
654 trkName = idHelper->show_to_string(siDetElem->identify());
655 }
656 ATH_MSG_WARNING("Acts surface "
657 << surface->geometryId()
658 << " normal (" << norm[0] << ',' << norm[1] << ',' << norm[2]
659 << ") does not match Trk surface " << trkName
660 << " normal (" << trkNorm[0] << ',' << trkNorm[1] << ',' << trkNorm[2] << ')');
661 nMismatchedNormals++;
662 result = false;
663 }
664 }
665
666 auto doPoints = [&](unsigned int type, const Acts::Vector2& loc) -> std::array<bool,3> {
667 Acts::Vector3 glb = surface->localToGlobal(gctx, loc, Acts::Vector3::Zero());
668
669 Amg::Vector2D locTrk = Amg::Vector2D::Zero();
670 Amg::Vector3D glbTrk = Amg::Vector3D::Zero();
671 Acts::Vector2 locg2l = Acts::Vector2::Zero();
672 bool locg2lOk = false;
673 auto locTrkRes = trkSurface.globalToLocal(glb);
674 if (locTrkRes) {
675 locTrk = locTrkRes.value();
676 glbTrk = trkSurface.localToGlobal(locTrk);
677
678 auto locg2lRes = surface->globalToLocal(gctx, glbTrk, Acts::Vector3::Zero());
679 if (locg2lRes.ok()) {
680 locg2lOk = true;
681 locg2l = locg2lRes.value();
682 }
683 }
684
685 auto gId = surface->geometryId();
686 if(os) {
687 (*os) << gId.value()
688 << "," << gId.volume()
689 << "," << gId.layer()
690 << "," << gId.sensitive()
691 << "," << type
692 << "," << loc[0]
693 << "," << loc[1]
694 << "," << surface->insideBounds(loc)
695 << "," << locTrk[0]
696 << "," << locTrk[1]
697 << "," << trkSurface.insideBounds(locTrk)
698 << "," << glb[0]
699 << "," << glb[1]
700 << "," << glb[2]
701 << "," << locg2l[0]
702 << "," << locg2l[1]
703 << "," << glbTrk[0]
704 << "," << glbTrk[1]
705 << "," << glbTrk[2]
706 << std::endl;
707 }
708
709 return {surface->insideBounds(loc) == trkSurface.insideBounds(locTrk),
710 locg2lOk ? isApprox(loc, locg2l) : true,
711 locTrkRes ? isApprox(glb, glbTrk) : true};
712 };
713
714
715 constexpr double envelope = 10.0 * Acts::UnitConstants::mm;
716
717 std::array<bool,3> allOk{true,true,true};
718 if(const auto* bounds = dynamic_cast<const Acts::PlanarBounds*>(&surface->bounds()); bounds) {
719 ATH_MSG_VERBOSE("Planar bounds");
720
721 const Acts::RectangleBounds& boundingBox = bounds->boundingBox();
722 Acts::Vector2 min = boundingBox.min().array() - envelope;
723 Acts::Vector2 max = boundingBox.max().array() + envelope;
724 Acts::Vector2 diag = max - min;
725
726 for(const auto& testPoint : localPoints) {
727 Acts::Vector2 loc = min.array() + (testPoint.array() * diag.array());
728 auto pointOk = doPoints(0, loc);
729 for (size_t i=0; i<pointOk.size(); ++i) {
730 if (!pointOk[i]) {
731 result = false;
732 allOk[i] = false;
733 }
734 }
735 }
736
737 }
738 else if(const auto* bounds = dynamic_cast<const Acts::AnnulusBounds*>(&surface->bounds()); bounds) {
739 ATH_MSG_VERBOSE("Annulus bounds");
740
741 // custom bounding box algo
742 std::vector<Acts::Vector2> vertices = bounds->vertices(5); // 5 segments on the radial edges
743 Acts::Vector2 min{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()};
744 Acts::Vector2 max{std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest()};
745 for (const auto& vtx : vertices) {
746 min = min.array().min(vtx.array());
747 max = max.array().max(vtx.array());
748 }
749 min.array() -= envelope;
750 max.array() += envelope;
751 Acts::Vector2 diag = max - min;
752
753 for(const auto& testPoint : localPoints) {
754 Acts::Vector2 locXY = min.array() + (testPoint.array() * diag.array());
755 Acts::Vector2 locPC = dynamic_cast<const Acts::DiscSurface&>(*surface).localCartesianToPolar(locXY);
756
757 auto pointOk = doPoints(1, locPC);
758 for (size_t i=0; i<pointOk.size(); ++i) {
759 if (!pointOk[i]) {
760 result = false;
761 allOk[i] = false;
762 }
763 }
764 }
765
766 }
767 else {
768 result = false;
769 }
770
771 for (size_t i=0; i<allOk.size(); ++i) {
772 if (!allOk[i]) {
773 ++nInconsistent[i];
774 }
775 }
776
777 });
778
779 ATH_MSG_INFO("Total number of sensors : " << nTotalSensors);
780 ATH_MSG_INFO("Number of sensors with mismatched centers : " << nMismatchedCenters);
781 ATH_MSG_INFO("Number of sensors with mismatched normals : " << nMismatchedNormals);
782 ATH_MSG_INFO("Number of sensors with inconsistent inside: " << nInconsistent[0]);
783 ATH_MSG_INFO("Number of sensors with inconsistent g2l : " << nInconsistent[1]);
784 ATH_MSG_INFO("Number of sensors with inconsistent l2g : " << nInconsistent[2]);
785
786 return result;
787}
788
789std::shared_ptr<const Acts::TrackingGeometry>
791
792 ATH_MSG_VERBOSE("Retrieving tracking geometry");
793 return m_trackingGeometry;
794}
795
796std::shared_ptr<const Acts::ILayerBuilder>
798 const InDetDD::InDetDetectorManager *manager) {
799
800 std::string managerName = manager->getName();
801 auto matcher = [](const Acts::GeometryContext & /*gctx*/,
802 Acts::AxisDirection /*aDir*/, const Acts::Surface * /*aS*/,
803 const Acts::Surface *
804 /*bS*/) -> bool { return false; };
805
806 Acts::SurfaceArrayCreator::Config sacCfg;
807 sacCfg.surfaceMatcher = matcher;
808 sacCfg.doPhiBinningOptimization = false;
809
810 auto surfaceArrayCreator = std::make_shared<Acts::SurfaceArrayCreator>(
811 sacCfg,
812 makeActsAthenaLogger(this, managerName + "SrfArrCrtr", std::string("ActsTGSvc")));
813 Acts::LayerCreator::Config lcCfg;
814 lcCfg.surfaceArrayCreator = surfaceArrayCreator;
815 auto layerCreator = std::make_shared<Acts::LayerCreator>(
816 lcCfg, makeActsAthenaLogger(this, managerName + "LayCrtr", std::string("ActsTGSvc")));
817
819 cfg.mng = static_cast<const InDetDD::TRT_DetectorManager *>(manager);
820 cfg.elementStore = m_elementStore;
821 cfg.layerCreator = layerCreator;
822 cfg.idHelper = m_TRT_idHelper;
823 return std::make_shared<const ActsStrawLayerBuilder>(
824 cfg, makeActsAthenaLogger(this, managerName + "GMSLayBldr", std::string("ActsTGSvc")));
825}
826
827std::shared_ptr<const Acts::ILayerBuilder>
829 const HGTD_DetectorManager *manager) {
830
831 std::string managerName = manager->getName();
832 auto matcher = [](const Acts::GeometryContext & /*gctx*/,
833 Acts::AxisDirection /*aDir*/, const Acts::Surface * /*aS*/,
834 const Acts::Surface *
835 /*bS*/) -> bool { return false; };
836
837 Acts::SurfaceArrayCreator::Config sacCfg;
838 sacCfg.surfaceMatcher = matcher;
839 sacCfg.doPhiBinningOptimization = false;
840
841 auto surfaceArrayCreator = std::make_shared<Acts::SurfaceArrayCreator>(
842 sacCfg,
843 makeActsAthenaLogger(this, managerName + "SrfArrCrtr", std::string("ActsTGSvc")));
844 Acts::LayerCreator::Config lcCfg;
845 lcCfg.surfaceArrayCreator = surfaceArrayCreator;
846 auto layerCreator = std::make_shared<Acts::LayerCreator>(
847 lcCfg, makeActsAthenaLogger(this, managerName + "LayCrtr", std::string("ActsTGSvc")));
848
850 cfg.mng = static_cast<const HGTD_DetectorManager *>(manager);
851 cfg.elementStore = m_elementStore;
852 cfg.layerCreator = layerCreator;
853 cfg.idHelper = m_HGTD_idHelper;
854 cfg.numberOfBinsFactor = m_numberOfBinsFactor;
855 return std::make_shared<const ActsHGTDLayerBuilder>(
856 cfg, makeActsAthenaLogger(this, managerName + "GMSLayBldr", std::string("ActsTGSvc")));
857}
858
860 const InDetDD::InDetDetectorManager *manager) {
861 using enum Acts::AxisDirection;
862
863 std::string managerName = manager->getName();
864
865 std::shared_ptr<const Acts::ILayerBuilder> gmLayerBuilder;
866 auto matcher = [](const Acts::GeometryContext & /*gctx*/,
867 Acts::AxisDirection aDir, const Acts::Surface *aS,
868 const Acts::Surface *bS) -> bool {
869 auto* a = getActsDetectorElement(aS);
870 auto* b = getActsDetectorElement(bS);
871
872 if ((not a) or (not b)) {
873 throw std::runtime_error(
874 "Cast of surface associated element to ActsDetectorElement failed "
875 "in TrackingGeometrySvc::makeVolumeBuilder");
876 }
877
878 IdentityHelper idA = a->identityHelper();
879 IdentityHelper idB = b->identityHelper();
880
881 // check if same bec
882 // can't be same if not
883 if (idA.bec() != idB.bec())
884 return false;
885
886 if (aDir == AxisPhi) {
887 // std::cout << idA.phi_module() << " <-> " << idB.phi_module() <<
888 // std::endl;
889 return idA.phi_module() == idB.phi_module();
890 }
891
892 if (aDir == AxisZ) {
893 return (idA.eta_module() == idB.eta_module()) &&
894 (idA.layer_disk() == idB.layer_disk()) && (idA.bec() == idB.bec());
895 }
896
897 if (aDir == AxisR) {
898 return (idA.eta_module() == idB.eta_module()) &&
899 (idA.layer_disk() == idB.layer_disk()) && (idB.bec() == idA.bec());
900 }
901
902 return false;
903 };
904
905 Acts::SurfaceArrayCreator::Config sacCfg;
906 sacCfg.surfaceMatcher = matcher;
907
908 auto surfaceArrayCreator = std::make_shared<Acts::SurfaceArrayCreator>(
909 sacCfg,
910 makeActsAthenaLogger(this, managerName + "SrfArrCrtr", std::string("ActsTGSvc")));
911 Acts::LayerCreator::Config lcCfg;
912 lcCfg.surfaceArrayCreator = surfaceArrayCreator;
913 auto layerCreator = std::make_shared<Acts::LayerCreator>(
914 lcCfg, makeActsAthenaLogger(this, managerName + "LayCrtr", std::string("ActsTGSvc")));
915
917 cfg.surfaceMatcher = matcher;
918
919 // set bins from configuration
920 if (m_barrelMaterialBins.size() != 2) {
921 throw std::invalid_argument("Number of barrel material bin counts != 2");
922 }
923 std::vector<size_t> brlBins(m_barrelMaterialBins);
924 cfg.barrelMaterialBins = {brlBins.at(0), brlBins.at(1)};
925
926 if (m_endcapMaterialBins.size() != 2) {
927 throw std::invalid_argument("Number of endcap material bin counts != 2");
928 }
929 std::vector<size_t> ecBins(m_endcapMaterialBins);
930 cfg.endcapMaterialBins = {ecBins.at(0), ecBins.at(1)};
931
932 cfg.mng = static_cast<const InDetDD::SiDetectorManager *>(manager);
933 // use class member element store
934 cfg.elementStore = m_elementStore;
935 cfg.layerCreator = layerCreator;
936
937 cfg.numberOfBinsFactor = m_numberOfBinsFactor;
938 cfg.numberOfInnermostLayerBinsFactor = m_numberOfInnermostLayerBinsFactor;
939
940 // gmLayerBuilder = std::make_shared<const ActsLayerBuilder>(
941 // cfg, makeActsAthenaLogger(this, managerName + "GMLayBldr",
942 // "ActsTGSvc"));
943
944 // return gmLayerBuilder;
945 return cfg;
946}
947
948std::shared_ptr<Acts::TrackingVolume>
950 const Acts::GeometryContext &gctx, const Acts::ILayerBuilder &sct_lb,
951 const Acts::ILayerBuilder &trt_lb, const Acts::CylinderVolumeHelper &cvh,
952 const std::shared_ptr<const Acts::TrackingVolume> &pixel) {
953 ATH_MSG_VERBOSE("Building SCT+TRT assembly");
954
955 Acts::CylinderVolumeBuilder::Config cvbCfg;
956 Acts::CylinderVolumeBuilder cvb(
957 cvbCfg, makeActsAthenaLogger(this, std::string("SCTTRTCVB"), std::string("ActsTGSvc")));
958
959 ATH_MSG_VERBOSE("Making SCT negative layers: ");
960 Acts::VolumeConfig sctNegEC =
961 cvb.analyzeContent(gctx, sct_lb.negativeLayers(gctx), {});
962 ATH_MSG_VERBOSE("Making SCT positive layers: ");
963 Acts::VolumeConfig sctPosEC =
964 cvb.analyzeContent(gctx, sct_lb.positiveLayers(gctx), {});
965 ATH_MSG_VERBOSE("Making SCT central layers: ");
966 Acts::VolumeConfig sctBrl =
967 cvb.analyzeContent(gctx, sct_lb.centralLayers(gctx), {});
968
969 ATH_MSG_VERBOSE("Making TRT negative layers: ");
970 Acts::VolumeConfig trtNegEC =
971 cvb.analyzeContent(gctx, trt_lb.negativeLayers(gctx), {});
972 ATH_MSG_VERBOSE("Making TRT positive layers: ");
973 Acts::VolumeConfig trtPosEC =
974 cvb.analyzeContent(gctx, trt_lb.positiveLayers(gctx), {});
975 ATH_MSG_VERBOSE("Making TRT central layers: ");
976 Acts::VolumeConfig trtBrl =
977 cvb.analyzeContent(gctx, trt_lb.centralLayers(gctx), {});
978
979 // synchronize trt
980
981 double absZMinEC = std::min(std::abs(trtNegEC.zMax), std::abs(trtPosEC.zMin));
982 double absZMaxEC = std::max(std::abs(trtNegEC.zMin), std::abs(trtPosEC.zMax));
983
984 trtNegEC.zMin = -absZMaxEC;
985 trtNegEC.zMax = -absZMinEC;
986 trtPosEC.zMin = absZMinEC;
987 trtPosEC.zMax = absZMaxEC;
988
989 using CVBBV = Acts::CylinderVolumeBounds::BoundValues;
990
991 // if pixel is present, shrink SCT volumes in R
992 bool isSCTSmallerInZ = false;
993 if (pixel) {
994 ATH_MSG_VERBOSE("Shrinking SCT in R (and maybe in increase size in Z) to fit around Pixel");
995 auto pixelBounds = dynamic_cast<const Acts::CylinderVolumeBounds *>(
996 &pixel->volumeBounds());
997 double sctNegECzMin = std::min(sctNegEC.zMin, -pixelBounds->get(CVBBV::eHalfLengthZ));
998 double sctPosECzMax = std::max(sctPosEC.zMax, pixelBounds->get(CVBBV::eHalfLengthZ));
999
1000 ATH_MSG_VERBOSE("- SCT +-EC.rMin: " << sctNegEC.rMin << " -> " << pixelBounds->get(CVBBV::eMaxR));
1001 ATH_MSG_VERBOSE("- SCT BRL.rMin: " << sctBrl.rMin << " -> " << pixelBounds->get(CVBBV::eMaxR));
1002 ATH_MSG_VERBOSE("- SCT EC.zMin: " << sctNegEC.zMin << " -> " << sctNegECzMin);
1003 ATH_MSG_VERBOSE("- SCT EC.zMax: " << sctPosEC.zMax << " -> " << sctPosECzMax);
1004
1005 sctNegEC.rMin = pixelBounds->get(CVBBV::eMaxR);
1006 sctPosEC.rMin = pixelBounds->get(CVBBV::eMaxR);
1007 sctBrl.rMin = pixelBounds->get(CVBBV::eMaxR);
1008
1009 isSCTSmallerInZ = sctPosEC.zMax < pixelBounds->get(CVBBV::eHalfLengthZ);
1010
1011 sctNegEC.zMin = sctNegECzMin;
1012 sctPosEC.zMax = sctPosECzMax;
1013
1014
1015 } else {
1016 ATH_MSG_VERBOSE("Pixel is not configured, not wrapping");
1017 }
1018
1019 ATH_MSG_VERBOSE("SCT Volume Configuration:");
1020 ATH_MSG_VERBOSE("- SCT::NegativeEndcap: " << sctNegEC.layers.size()
1021 << " layers, "
1022 << sctNegEC.toString());
1023 ATH_MSG_VERBOSE("- SCT::Barrel: " << sctBrl.layers.size() << " layers, "
1024 << sctBrl.toString());
1025 ATH_MSG_VERBOSE("- SCT::PositiveEncap: " << sctPosEC.layers.size()
1026 << " layers, "
1027 << sctPosEC.toString());
1028
1029 ATH_MSG_VERBOSE("TRT Volume Configuration:");
1030 ATH_MSG_VERBOSE("- TRT::NegativeEndcap: " << trtNegEC.layers.size()
1031 << " layers, "
1032 << trtNegEC.toString());
1033 ATH_MSG_VERBOSE("- TRT::Barrel: " << trtBrl.layers.size() << " layers, "
1034 << trtBrl.toString());
1035 ATH_MSG_VERBOSE("- TRT::PositiveEncap: " << trtPosEC.layers.size()
1036 << " layers, "
1037 << trtPosEC.toString());
1038
1039 // harmonize SCT BRL <-> EC, normally the CVB does this, but we're skipping
1040 // that
1041 sctBrl.zMax = (sctBrl.zMax + sctPosEC.zMin) / 2.;
1042 sctBrl.zMin = -sctBrl.zMax;
1043
1044 // and now harmonize everything
1045 // inflate TRT Barrel to match SCT
1046 trtBrl.zMin = sctBrl.zMin;
1047 trtBrl.zMax = sctBrl.zMax;
1048
1049 // extend TRT endcaps outwards z so they match SCT
1050 trtNegEC.zMin = sctNegEC.zMin;
1051 trtPosEC.zMax = sctPosEC.zMax;
1052
1053 // extend endcap in z so it touches barrel
1054 trtNegEC.zMax = trtBrl.zMin;
1055 sctNegEC.zMax = trtBrl.zMin;
1056 trtPosEC.zMin = trtBrl.zMax;
1057 sctPosEC.zMin = trtBrl.zMax;
1058
1059 // extend SCT in R so they touch TRT barel
1060 sctBrl.rMax = trtBrl.rMin;
1061 sctNegEC.rMax = trtNegEC.rMin;
1062 sctPosEC.rMax = trtPosEC.rMin;
1063
1064 // extend TRT endcaps in r to that of Barrel
1065 trtNegEC.rMax = trtBrl.rMax;
1066 trtPosEC.rMax = trtBrl.rMax;
1067
1068 ATH_MSG_VERBOSE("Dimensions after synchronization between SCT and TRT");
1069 ATH_MSG_VERBOSE("SCT Volume Configuration:");
1070 ATH_MSG_VERBOSE("- SCT::NegativeEndcap: " << sctNegEC.layers.size()
1071 << " layers, "
1072 << sctNegEC.toString());
1073 ATH_MSG_VERBOSE("- SCT::Barrel: " << sctBrl.layers.size() << " layers, "
1074 << sctBrl.toString());
1075 ATH_MSG_VERBOSE("- SCT::PositiveEncap: " << sctPosEC.layers.size()
1076 << " layers, "
1077 << sctPosEC.toString());
1078
1079 ATH_MSG_VERBOSE("TRT Volume Configuration:");
1080 ATH_MSG_VERBOSE("- TRT::NegativeEndcap: " << trtNegEC.layers.size()
1081 << " layers, "
1082 << trtNegEC.toString());
1083 ATH_MSG_VERBOSE("- TRT::Barrel: " << trtBrl.layers.size() << " layers, "
1084 << trtBrl.toString());
1085 ATH_MSG_VERBOSE("- TRT::PositiveEncap: " << trtPosEC.layers.size()
1086 << " layers, "
1087 << trtPosEC.toString());
1088
1089 auto makeTVol = [&](const auto &vConf, const auto &name) {
1090 return cvh.createTrackingVolume(gctx, vConf.layers, {},
1091 nullptr, // no material
1092 vConf.rMin, vConf.rMax, vConf.zMin,
1093 vConf.zMax, name);
1094 };
1095
1096 // now turn them into actual TrackingVolumes
1097 auto tvSctNegEC = makeTVol(sctNegEC, "SCT::NegativeEndcap");
1098 auto tvSctBrl = makeTVol(sctBrl, "SCT::Barrel");
1099 auto tvSctPosEC = makeTVol(sctPosEC, "SCT::PositiveEndcap");
1100
1101 auto tvTrtNegEC = makeTVol(trtNegEC, "TRT::NegativeEndcap");
1102 auto tvTrtBrl = makeTVol(trtBrl, "TRT::Barrel");
1103 auto tvTrtPosEC = makeTVol(trtPosEC, "TRT::PositiveEndcap");
1104
1105 // combine the endcaps and the barrels, respetively
1106 auto negEC =
1107 cvh.createContainerTrackingVolume(gctx, {tvSctNegEC, tvTrtNegEC});
1108 auto posEC =
1109 cvh.createContainerTrackingVolume(gctx, {tvSctPosEC, tvTrtPosEC});
1110 auto barrel = cvh.createContainerTrackingVolume(gctx, {tvSctBrl, tvTrtBrl});
1111
1112 // and now combine all of those into one container for the assembly
1113
1114 auto container =
1115 cvh.createContainerTrackingVolume(gctx, {negEC, barrel, posEC});
1116
1117 // if pixel is present, add positive and negative gap volumes so we can wrap
1118 // it all
1119 if (pixel) {
1120 auto containerBounds = dynamic_cast<const Acts::CylinderVolumeBounds *>(
1121 &container->volumeBounds());
1122 auto pixelBounds = dynamic_cast<const Acts::CylinderVolumeBounds *>(
1123 &pixel->volumeBounds());
1124 std::vector<std::shared_ptr<Acts::TrackingVolume>> noVolumes;
1125
1126 if(!isSCTSmallerInZ) {
1127 // pixel is smaller in z, need gap volumes
1128 auto posGap = cvh.createGapTrackingVolume(
1129 gctx, noVolumes,
1130 nullptr, // no material,
1131 pixelBounds->get(CVBBV::eMinR), pixelBounds->get(CVBBV::eMaxR),
1132 pixelBounds->get(CVBBV::eHalfLengthZ),
1133 containerBounds->get(CVBBV::eHalfLengthZ),
1134 0, // material layers,
1135 true, // cylinder
1136 "Pixel::PositiveGap");
1137 auto negGap = cvh.createGapTrackingVolume(
1138 gctx, noVolumes,
1139 nullptr, // no material,
1140 pixelBounds->get(CVBBV::eMinR), pixelBounds->get(CVBBV::eMaxR),
1141 -containerBounds->get(CVBBV::eHalfLengthZ),
1142 -pixelBounds->get(CVBBV::eHalfLengthZ),
1143 0, // material layers,
1144 true, // cylinder
1145 "Pixel::NegativeGap");
1146
1147 auto pixelContainer =
1148 cvh.createContainerTrackingVolume(gctx, {negGap, pixel, posGap});
1149 // and now create one container that contains Pixel+SCT+TRT
1150 container =
1151 cvh.createContainerTrackingVolume(gctx, {pixelContainer, container});
1152 }
1153 else {
1154 // wrap the pixel directly
1155 container =
1156 cvh.createContainerTrackingVolume(gctx, {pixel, container});
1157 }
1158
1159 }
1160
1161 return container;
1162}
1163
1165 ATH_MSG_DEBUG("Populate the alignment store with all detector elements");
1166 TrackingGeoAlignVisitor visitor{store};
1167 m_trackingGeometry->apply(visitor);
1168 ATH_MSG_DEBUG("Populated with " << visitor.alignedObjects() << " elements");
1169 return visitor.alignedObjects();
1170}
1172
1173Acts::CylinderVolumeBuilder::Config
1175 std::shared_ptr<const Acts::CylinderVolumeHelper> cvh) const {
1176
1177 // adapted from InnerDetector/InDetDetDescr/InDetTrackingGeometry/src/BeamPipeBuilder.cxx
1178
1179 PVConstLink beamPipeTopVolume = p_beamPipeMgr->getTreeTop(0);
1180
1181 if (p_beamPipeMgr->getNumTreeTops() == 1){
1182 beamPipeTopVolume = p_beamPipeMgr->getTreeTop(0)->getChildVol(0)->getChildVol(0);
1183 }
1184
1185 Acts::Transform3 beamPipeTransform;
1186 beamPipeTransform.setIdentity();
1187
1188 beamPipeTransform = Acts::Translation3(beamPipeTopVolume->getX().translation());
1189
1190 double beamPipeRadius = 20;
1191
1192 const GeoLogVol* beamPipeLogVolume = beamPipeTopVolume->getLogVol();
1193 const GeoTube* beamPipeTube = nullptr;
1194
1195
1196 if (beamPipeLogVolume == nullptr) {
1197 ATH_MSG_ERROR("Beam pip volume has no log volume");
1198 throw std::runtime_error("Beam pip volume has no log volume");
1199 }
1200 // get the geoShape and translate
1201 beamPipeTube = dynamic_cast<const GeoTube*>(beamPipeLogVolume->getShape());
1202 if (beamPipeTube == nullptr){
1203 ATH_MSG_ERROR("BeamPipeLogVolume was not of type GeoTube");
1204 throw std::runtime_error{"BeamPipeLogVolume was not of type GeoTube"};
1205 }
1206
1207 for(unsigned int i=0;i<beamPipeTopVolume->getNChildVols();i++) {
1208
1209 if(beamPipeTopVolume->getNameOfChildVol(i) == "SectionC03"){
1210
1211 PVConstLink childTopVolume = beamPipeTopVolume->getChildVol(i);
1212 const GeoLogVol* childLogVolume = childTopVolume->getLogVol();
1213 const GeoTube* childTube = nullptr;
1214
1215 if (childLogVolume){
1216 childTube = dynamic_cast<const GeoTube*>(childLogVolume->getShape());
1217 if (childTube){
1218 beamPipeRadius = 0.5 * (childTube->getRMax()+childTube->getRMin());
1219 }
1220 }
1221
1222 break; // Exit loop after SectionC03 is found
1223 }
1224
1225 } // Loop over child volumes
1226
1227 ATH_MSG_VERBOSE("BeamPipe constructed from Database: translation (yes) - radius "
1228 << ( beamPipeTube ? "(yes)" : "(no)") << " - r = " << beamPipeRadius );
1229
1230 ATH_MSG_VERBOSE("BeamPipe shift estimated as : " << Amg::toString(beamPipeTransform.translation()));
1231
1232 Acts::CylinderVolumeBuilder::Config cfg;
1233
1234 Acts::PassiveLayerBuilder::Config bplConfig;
1235 bplConfig.layerIdentification = "BeamPipe";
1236 bplConfig.centralLayerRadii = {beamPipeRadius * 1_mm};
1237 bplConfig.centralLayerHalflengthZ = {3000_mm};
1238 bplConfig.centralLayerThickness = {1_mm};
1239 auto beamPipeBuilder = std::make_shared<const Acts::PassiveLayerBuilder>(
1240 bplConfig, makeActsAthenaLogger(this, std::string("BPLayBldr"), std::string("ActsTGSvc")));
1241
1242 // create the volume for the beam pipe
1243 cfg.trackingVolumeHelper = cvh;
1244 cfg.volumeName = "BeamPipe";
1245 cfg.layerBuilder = beamPipeBuilder;
1246 cfg.layerEnvelopeR = {1_mm, 1_mm};
1247 cfg.buildToRadiusZero = true;
1248
1249 return cfg;
1250}
1251
1252
1253const Acts::TrackingVolume*
1255 const Acts::TrackingVolume* retVol{nullptr};
1256 using namespace ActsTrk::detail::GeoVolIds;
1257 switch (envType) {
1258 using enum ActsTrk::SystemEnvelope;
1259 case ITkExit:
1260 break;
1261 case CaloExit:
1262 retVol = m_trackingGeometry->findVolume(Acts::GeometryIdentifier{}.withVolume(s_caloEnvelopeID));
1263 break;
1264 case MsExit:
1265 break;
1266 }
1267 if(!retVol) {
1268 THROW_EXCEPTION("There is no system envelope "<<envType);
1269 }
1270 return retVol;
1271}
1272
1273std::unique_ptr<ActsTrk::DetectorElementToActsGeometryIdMap>
1275 // create map from
1276 auto detector_element_to_geoid = std::make_unique<DetectorElementToActsGeometryIdMap>();
1277
1278 struct Counter{
1279 unsigned n_sensitive_elements{0};
1280 unsigned n_detector_elements{0};
1281 unsigned n_wrong_type{0};
1282 };
1283 Counter counter {};
1284 trackingGeometry()->visitSurfaces([this, &counter, &detector_element_to_geoid](const Acts::Surface *surface) {
1285 if (!surface || !surface->isSensitive()) {
1286 ++counter.n_wrong_type;
1287 return;
1288 }
1289 ++counter.n_sensitive_elements;
1290 const auto* placement = dynamic_cast<const ISurfacePlacement*>(surface->surfacePlacement());
1291 if (!placement) {
1292 return;
1293 }
1294
1295 auto insert_id = [&detector_element_to_geoid, &surface, &counter](const xAOD::UncalibMeasType type) {
1296 auto * possibleElement = getActsDetectorElement(surface);
1297 if (!possibleElement){
1298 return;
1299 }
1300 auto hash = possibleElement->identifyHash();
1301 detector_element_to_geoid->insert(std::make_pair(makeDetectorElementKey(type, hash),
1302 DetectorElementToActsGeometryIdMap::makeValue(surface->geometryId(), surface)));
1303 ++counter.n_detector_elements;
1304 };
1305 switch(placement->detectorType()) {
1306 using enum DetectorType;
1307 case Pixel:
1309 break;
1310 case Sct:
1312 break;
1313 case Hgtd:
1315 break;
1316 case Trt: {
1317 break;
1318 }
1320 case Mdt:
1321 case Rpc:
1322 case Tgc:
1323 case Csc:
1324 case Mm:
1325 case sTgc:{
1326 // surface map not needed for the muon detectors
1327 ++counter.n_detector_elements;
1328 break;
1329 }
1330 case UnDefined:
1331 ATH_MSG_ERROR("Undefined element encountered");
1332 counter.n_detector_elements = 0;
1333 return;
1334 }
1335 }, true /*sensitive surfaces*/);
1336 ATH_MSG_INFO( "Surfaces without associated detector elements " << (counter.n_sensitive_elements -counter.n_detector_elements)
1337 << " (with " << counter.n_detector_elements << ")" );
1338 if (counter.n_sensitive_elements > 0 &&
1339 counter.n_detector_elements==0) {
1340 ATH_MSG_ERROR( "No surface with associated detector element" );
1341 return nullptr;
1342 }
1343 if (counter.n_wrong_type>0) {
1344 ATH_MSG_WARNING( "Surfaces associated to detector elements not of type Trk::TrkDetElementBase :" << counter.n_wrong_type);
1345 }
1346 return detector_element_to_geoid;
1347}
1348}
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.
Gaudi::Property< std::vector< size_t > > m_endcapMaterialBins
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< 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< float > > m_passiveITkStripBarrelLayerRadii
Gaudi::Property< std::vector< float > > m_passiveITkStripBarrelLayerThickness
std::shared_ptr< const Acts::ILayerBuilder > makeHGTDLayerBuilder(const HGTD_DetectorManager *manager)
std::unique_ptr< const ActsTrk::DetectorElementToActsGeometryIdMap > m_detIdMap
Gaudi::Property< bool > m_printGeo
Print the assembled tracking geometry after building.
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
Gaudi::Property< double > m_numberOfInnermostLayerBinsFactor
Special treatment for the innermost pixel layer to have more control on bin size to account for shall...
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.
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.
const InDetDD::SiDetectorManager * p_ITkPixelManager
const InDetDD::SiDetectorManager * p_pixelManager
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
static Root::TMsgLogger logger("iLumiCalc")
Define the volume parts of the GeometryIdentifier for each ATLAS subsystem centrally.
constexpr std::size_t s_caloEnvelopeID
Volume Ids ofthe Calorimeter.
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
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
#define THROW_EXCEPTION(MESSAGE)
Definition throwExcept.h:10