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