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