ATLAS Offline Software
Loading...
Searching...
No Matches
HgtdBlueprintNodeBuilder.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//
9
10#include "GeoModelKernel/GeoTube.h"
11#include "GeoModelKernel/GeoVPhysVol.h"
12
13#include "Acts/Definitions/Direction.hpp"
14#include "Acts/Definitions/Units.hpp"
15#include "Acts/Geometry/Blueprint.hpp"
16#include "Acts/Geometry/BlueprintNode.hpp"
17#include "Acts/Geometry/ContainerBlueprintNode.hpp"
18#include "Acts/Geometry/CylinderVolumeBounds.hpp"
19#include "Acts/Geometry/Extent.hpp"
20#include "Acts/Geometry/GeometryIdentifierBlueprintNode.hpp"
21#include "Acts/Geometry/LayerBlueprintNode.hpp"
22#include "Acts/Geometry/MaterialDesignatorBlueprintNode.hpp"
23#include "Acts/Geometry/PadBlueprintNode.hpp"
24#include "Acts/Geometry/ProtoLayer.hpp"
25#include "Acts/Geometry/TrackingVolume.hpp"
26#include "Acts/Geometry/VolumeAttachmentStrategy.hpp"
27#include "Acts/Navigation/SurfaceArrayNavigationPolicy.hpp"
28#include "Acts/Navigation/CylinderNavigationPolicy.hpp"
29#include "Acts/Navigation/TryAllNavigationPolicy.hpp"
30#include "Acts/Surfaces/SurfaceArray.hpp"
31#include "Acts/Utilities/AxisDefinitions.hpp"
32#include "Acts/Utilities/AxisSpec.hpp"
33#include "Acts/Geometry/StaticBlueprintNode.hpp"
34#include "Acts/Geometry/VolumeResizeStrategy.hpp"
35#include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
36
37
38
39
43#include "ActsInterop/Logger.h"
47
48
49#include <cstddef>
50#include <ranges>
51#include <string>
52using namespace Acts;
53using namespace Acts::Experimental;
54using namespace Acts::UnitLiterals;
55
56namespace {
58using namespace ActsTrk::detail::GeoVolIds;
59using enum Acts::CylinderVolumeBounds::Face;
60using enum Acts::AxisDirection;
61using enum Acts::SurfaceArrayNavigationPolicy::LayerType;
62using AttachmentStrategy = Acts::VolumeAttachmentStrategy;
63using ResizeStrategy = Acts::VolumeResizeStrategy;
64} // namespace
65
66namespace ActsTrk {
68 ATH_MSG_DEBUG("Initializing HgtdBlueprintNodeBuilder");
69
70 ATH_CHECK(detStore()->retrieve(m_hgtdMgr, "HGTD"));
71
72 m_elementStore = std::make_shared<ActsElementVector>();
73
74 return StatusCode::SUCCESS;
75}
76
77std::shared_ptr<Acts::BlueprintNode>
79 const Acts::GeometryContext& gctx,
80 std::shared_ptr<Acts::BlueprintNode>&& child) {
81
82 ExtentEnvelope envelope = ExtentEnvelope{{
83 .z = {20_mm, 20_mm},
84 .r = {0_mm, 20_mm},
85 }};
86
87 auto itkHgtdNode =
88 std::make_shared<Acts::CylinderContainerBlueprintNode>(
89 "itkHgtd", AxisZ);
90
91 if (child) {
92 itkHgtdNode->addChild(std::move(child));
93 }
94 buildHgtdBlueprintNode(gctx, *itkHgtdNode);
95 auto itkHgtdPad = std::make_shared<Acts::PadBlueprintNode>("itkHgtdPad", envelope);
96 itkHgtdPad->addChild(std::move(itkHgtdNode));
97
98 auto idNode = std::make_shared<Acts::GeometryIdentifierBlueprintNode>();
99 idNode->setDirectChildVolumeIdTo(s_hgtdEnvelopeId);
100 idNode->addChild(std::move(itkHgtdPad));
101 return idNode;
102}
103
105 const Acts::GeometryContext& /*gctx*/,
106 Acts::BlueprintNode& node) {
107 if (not m_hgtdMgr) {
108 ATH_MSG_ERROR("HGTD manager not available");
109 throw std::runtime_error("HGTD manager not available");
110 }
111
112 ATH_MSG_DEBUG("Detector manager has "
113 << m_hgtdMgr->getDetectorElementCollection()->size()
114 << " elements");
115
116 std::vector<std::shared_ptr<ActsDetectorElement>> elements;
117
118 for (const auto* element : *m_hgtdMgr->getDetectorElementCollection()) {
119 const InDetDD::HGTD_DetectorElement* hgtdDetElement =
120 dynamic_cast<const InDetDD::HGTD_DetectorElement*>(element);
121 if (hgtdDetElement == nullptr) {
122 ATH_MSG_ERROR("Detector element was nullptr");
123 throw std::runtime_error{"Corrupt detector element collection"};
124 }
125 elements.push_back(std::make_shared<ActsDetectorElement>(
126 *hgtdDetElement, hgtdDetElement->identify()));
127 }
128 ATH_MSG_VERBOSE("Retrieved " << elements.size() << " elements");
129
130 m_elementStore->vector().insert(m_elementStore->vector().end(),
131 elements.begin(), elements.end());
132
133 for (int bec : {-2, 2}) {
134 const std::string s = bec > 0 ? "p" : "n";
135
136 std::map<int, std::vector<std::shared_ptr<Acts::Surface>>> layers{};
137
138 for (auto& element : elements) {
139 IdentityHelper id = element->identityHelper();
140
141 ATH_MSG_VERBOSE("Reading element with bec "
142 << id.bec() << ", layer/disk " << id.layer_disk()
143 << ", eta_module " << id.eta_module() << ", phi_module "
144 << id.phi_module());
145
146 if (id.bec() * bec <= 0) {
147 continue;
148 }
149
150 layers[id.layer_disk()].push_back(element->surface().getSharedPtr());
151 }
152
153 ATH_MSG_DEBUG("Found " << layers.size() << " layers in HGTD " << s << "EC");
154 for (auto& [key, surfaces] : layers) {
155 ATH_MSG_DEBUG("Layer " << key << " has " << surfaces.size()
156 << " surfaces");
157 }
158
159 node.withGeometryIdentifier([&layers, bec, s, this](auto& geoId) {
160 std::string ecName = "HGTD_" + s + "EC";
161 geoId.setAllVolumeIdsTo((bec > 0 ? s_hgtdPosVolumeId : s_hgtdNegVolumeId))
162 .incrementLayerIds(1);
163
164 geoId.addCylinderContainer(ecName, AxisR, [&](auto& hgtd) {
165 hgtd.setAttachmentStrategy(AttachmentStrategy::Gap);
166 hgtd.setResizeStrategy(ResizeStrategy::Gap);
167
168 hgtd.addCylinderContainer(
169 ecName + "_Container", AxisZ, [&](auto& hgtdContainer) {
170 // Collapse inter-disk gaps by extending the outer disk inward
171 // (Second for +z, First for -z); material kept only on outward
172 // discs (see addHgtdLayers), so it stays at the smaller-|z| side.
173 hgtdContainer.setAttachmentStrategy(
174 bec > 0 ? AttachmentStrategy::Second
175 : AttachmentStrategy::First);
176 hgtdContainer.setResizeStrategy(ResizeStrategy::Gap);
177
178 const int innermostLayer = layers.begin()->first;
179 for (auto& [key, surfaces] : layers) {
180 std::string layerName = ecName + "_" + std::to_string(key);
181
182 ATH_MSG_DEBUG("Adding layer " << layerName << " with "
183 << surfaces.size()
184 << " surfaces");
185
186 addHgtdLayers(hgtdContainer, bec, key, layerName, surfaces,
187 key == innermostLayer);
188 }
189 });
190 });
191 });
192 }
193}
194
196 Acts::BlueprintNode& parent, int bec, int index,
197 const std::string& name,
198 std::vector<std::shared_ptr<Acts::Surface>>& surfaces, bool isInnermost) {
199 using enum Acts::SurfaceArrayNavigationPolicy::LayerType;
200 using enum Acts::CylinderVolumeBounds::Face;
201 using enum Acts::AxisDirection;
202
203 // Keep material on each layer's outward disc so the inter-disk gaps can be
204 // collapsed (the material-free inward disc fuses with the neighbour's kept
205 // outward disc); the innermost layer keeps its inward disc too. The outermost
206 // layer (index 3) historically carries material only on its inward disc and,
207 // being non-innermost, becomes material-free — that gap's material survives
208 // on the previous layer's kept outward disc, at the smaller-|z| side.
209 const auto outwardDisc = (bec > 0) ? PositiveDisc : NegativeDisc;
210 const auto inwardDisc = (bec > 0) ? NegativeDisc : PositiveDisc;
211 const bool hasMaterial = (index != 3) || isInnermost;
212
213 auto configureLayer = [&](auto& node) {
214 node.addLayer(name, [&surfaces](auto& layer) {
215 layer.setNavigationPolicyFactory(
216 Acts::NavigationPolicyFactory{}
217 .add<Acts::SurfaceArrayNavigationPolicy>(
218 Acts::SurfaceArrayNavigationPolicy::Config{.layerType = Disc,
219 .bins = {0, 0}, .numberOfBinsFactor = 5.0})
220 .add<Acts::CylinderNavigationPolicy>()
221 .asUniquePtr());
222 layer.setSurfaces(surfaces);
223 layer.setEnvelope(Acts::ExtentEnvelope{{
224 .z = {0.1_mm, 0.1_mm},
225 .r = {2_mm, 2_mm},
226 }});
227 });
228 };
229
230 // Layer 3 (non-innermost) has no material faces; skip the
231 // MaterialDesignator wrapper to avoid empty-designator warnings.
232 if (hasMaterial) {
233 const std::string materialName = name + "_Material";
234 parent.addMaterial(materialName, [&](auto& mat) {
235 if (index != 3) {
236 mat.configureFace(outwardDisc, AxisSpec::DeferredEquidistant(50, AxisR),
237 AxisSpec::DeferredEquidistant(50, AxisPhi),
238 materialName + "_Outward");
239 }
240 if (isInnermost) {
241 mat.configureFace(inwardDisc, AxisSpec::DeferredEquidistant(50, AxisR),
242 AxisSpec::DeferredEquidistant(50, AxisPhi),
243 materialName + "_Inward");
244 }
245 configureLayer(mat);
246 });
247 } else {
248 configureLayer(parent);
249 }
250}
251
252} // namespace ActsTrk
Helper to hold elements for deletion.
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_VERBOSE(x,...)
void buildHgtdBlueprintNode(const Acts::GeometryContext &gctx, Acts::BlueprintNode &node)
Build the HGTD Blueprint Node.
void addHgtdLayers(Acts::BlueprintNode &parent, int bec, int layer, const std::string &name, std::vector< std::shared_ptr< Acts::Surface > > &surfaces, bool isInnermost)
const HGTD_DetectorManager * m_hgtdMgr
std::shared_ptr< ActsElementVector > m_elementStore
std::shared_ptr< Acts::BlueprintNode > buildBlueprintNode(const Acts::GeometryContext &gctx, std::shared_ptr< Acts::BlueprintNode > &&child) override
Build the HGTD Blueprint Node.
Class to hold geometrical description of an HGTD detector element.
virtual Identifier identify() const override final
identifier of this detector element (inline)
Definition node.h:24
Define the volume parts of the GeometryIdentifier for each ATLAS subsystem centrally.
constexpr std::size_t s_hgtdEnvelopeId
constexpr std::size_t s_hgtdNegVolumeId
constexpr std::size_t s_hgtdPosVolumeId
HGTD volume IDs.
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
Definition index.py:1