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