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