File indexing completed on 2026-04-17 07:47:15
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsPlugins/DD4hep/OpenDataDetectorBuilder.hpp"
0010
0011 #include "Acts/Definitions/Units.hpp"
0012 #include "Acts/Geometry/Blueprint.hpp"
0013 #include "Acts/Geometry/BlueprintOptions.hpp"
0014 #include "Acts/Geometry/ContainerBlueprintNode.hpp"
0015 #include "Acts/Geometry/Extent.hpp"
0016 #include "Acts/Geometry/NavigationPolicyFactory.hpp"
0017 #include "Acts/Geometry/VolumeAttachmentStrategy.hpp"
0018 #include "Acts/Geometry/VolumeResizeStrategy.hpp"
0019 #include "Acts/Navigation/CylinderNavigationPolicy.hpp"
0020 #include "Acts/Navigation/SurfaceArrayNavigationPolicy.hpp"
0021 #include "Acts/Utilities/AxisDefinitions.hpp"
0022 #include "ActsPlugins/DD4hep/BlueprintBuilder.hpp"
0023
0024 #include <format>
0025 #include <memory>
0026 #include <optional>
0027 #include <regex>
0028 #include <stdexcept>
0029 #include <string>
0030 #include <utility>
0031
0032 #include <DD4hep/DetElement.h>
0033 #include <DD4hep/Detector.h>
0034
0035 namespace ActsPlugins::DD4hep {
0036
0037 namespace {
0038
0039 auto makeLayerCustomizer(const BlueprintBuilder& builder, std::string det,
0040 std::regex layerFilter) {
0041 return [&builder, det = std::move(det), layerFilter = std::move(layerFilter)](
0042 const std::optional<dd4hep::DetElement>& elem,
0043 Acts::Experimental::LayerBlueprintNode& layer) {
0044 layer.setEnvelope(detail::kLayerEnvelope);
0045
0046 const std::string elemName =
0047 elem.has_value() ? std::string{builder.backend().nameOf(*elem)}
0048 : layer.name();
0049 const int layerIdx = detail::layerIndexFromName(elemName, layerFilter);
0050
0051 using SrfArrayNavPol = Acts::SurfaceArrayNavigationPolicy;
0052 using enum SrfArrayNavPol::LayerType;
0053
0054 SrfArrayNavPol::Config navCfg;
0055
0056 if (layer.layerType() ==
0057 Acts::Experimental::LayerBlueprintNode::LayerType::Cylinder) {
0058
0059 navCfg.layerType = Cylinder;
0060 navCfg.bins = {
0061 builder.backend().constant("{}_b{}_sf_b_phi", det, layerIdx),
0062 builder.backend().constant("{}_b_sf_b_z", det)};
0063 } else {
0064
0065 navCfg.layerType = Disc;
0066 navCfg.bins = {builder.backend().constant("{}_e_sf_b_r", det),
0067 builder.backend().constant("{}_e_sf_b_phi", det)};
0068 }
0069
0070 layer.setNavigationPolicyFactory(Acts::NavigationPolicyFactory{}
0071 .add<Acts::CylinderNavigationPolicy>()
0072 .add<SrfArrayNavPol>(navCfg)
0073 .asUniquePtr());
0074 };
0075 }
0076
0077 void addDirectLayerSubsystem(const BlueprintBuilder& builder,
0078 Acts::Experimental::ContainerBlueprintNode& outer,
0079 std::string assembly, std::string det,
0080 const std::regex& layerFilter) {
0081 const auto assemblyElement = builder.findDetElementByName(assembly);
0082 if (!assemblyElement.has_value()) {
0083 throw std::runtime_error(
0084 std::format("Could not find assembly '{}'", assembly));
0085 }
0086
0087 auto barrels = builder.findBarrelElements(*assemblyElement);
0088 auto endcaps = builder.findEndcapElements(*assemblyElement);
0089
0090 const std::string assemblyName{builder.backend().nameOf(*assemblyElement)};
0091 auto containerNode =
0092 std::make_shared<Acts::Experimental::CylinderContainerBlueprintNode>(
0093 assemblyName, Acts::AxisDirection::AxisZ);
0094
0095 auto layerCustomizer =
0096 makeLayerCustomizer(builder, std::move(det), layerFilter);
0097
0098 auto addLayerChildren = [&](const auto& elements, auto makeNode) {
0099 for (const auto& element : elements) {
0100 auto node = makeNode(element);
0101 node->setAttachmentStrategy(Acts::VolumeAttachmentStrategy::Gap);
0102 node->setResizeStrategies(Acts::VolumeResizeStrategy::Gap,
0103 Acts::VolumeResizeStrategy::Gap);
0104 containerNode->addChild(std::move(node));
0105 }
0106 };
0107
0108 addLayerChildren(barrels, [&](const auto& barrel) {
0109 return builder.layers()
0110 .barrel()
0111 .setSensorAxes("XYZ")
0112 .setLayerFilter(layerFilter)
0113 .setContainer(barrel)
0114 .onLayer(layerCustomizer)
0115 .build();
0116 });
0117
0118 addLayerChildren(endcaps, [&](const auto& endcap) {
0119 return builder.layers()
0120 .endcap()
0121 .setSensorAxes("XZY")
0122 .setLayerFilter(layerFilter)
0123 .setContainer(endcap)
0124 .onLayer(layerCustomizer)
0125 .build();
0126 });
0127
0128 outer.addChild(std::move(containerNode));
0129 }
0130
0131 void addBarrelEndcapSubsystem(const BlueprintBuilder& builder,
0132 Acts::Experimental::ContainerBlueprintNode& outer,
0133 std::string assembly, std::string det,
0134 const std::regex& layerFilter) {
0135 const auto assemblyElement = builder.findDetElementByName(assembly);
0136 if (!assemblyElement.has_value()) {
0137 throw std::runtime_error(
0138 std::format("Could not find assembly '{}'", assembly));
0139 }
0140
0141 builder.barrelEndcap()
0142 .setAssembly(*assemblyElement)
0143 .setSensorAxes("XYZ", "XZY")
0144 .setLayerFilter(layerFilter)
0145 .onLayer(makeLayerCustomizer(builder, std::move(det), layerFilter))
0146 .onContainer(
0147 [](const auto&, Acts::Experimental::ContainerBlueprintNode& node) {
0148 node.setAttachmentStrategy(Acts::VolumeAttachmentStrategy::Gap);
0149 node.setResizeStrategies(Acts::VolumeResizeStrategy::Gap,
0150 Acts::VolumeResizeStrategy::Gap);
0151 })
0152 .addTo(outer);
0153 }
0154
0155 void addDirectLayerGroupedSubsystem(
0156 const BlueprintBuilder& builder,
0157 Acts::Experimental::ContainerBlueprintNode& outer, std::string assembly,
0158 std::string det, const std::regex& layerFilter) {
0159 const auto assemblyElement = builder.findDetElementByName(assembly);
0160 if (!assemblyElement.has_value()) {
0161 throw std::runtime_error(
0162 std::format("Could not find assembly '{}'", assembly));
0163 }
0164
0165 auto barrels = builder.findBarrelElements(*assemblyElement);
0166 auto endcaps = builder.findEndcapElements(*assemblyElement);
0167
0168 const std::string assemblyName{builder.backend().nameOf(*assemblyElement)};
0169 auto containerNode =
0170 std::make_shared<Acts::Experimental::CylinderContainerBlueprintNode>(
0171 assemblyName, Acts::AxisDirection::AxisZ);
0172
0173 auto layerCustomizer =
0174 makeLayerCustomizer(builder, std::move(det), layerFilter);
0175
0176 auto sensorToLayerKey = [&](const dd4hep::DetElement& elem) {
0177 auto current = elem;
0178 const auto world = builder.backend().world();
0179 while (!(current == world)) {
0180 std::cmatch match;
0181 if (const std::string name{builder.backend().nameOf(current)};
0182 std::regex_search(name.c_str(), match, layerFilter) &&
0183 match.size() > 1) {
0184 return builder.getPathToElementName(current);
0185 }
0186 current = builder.backend().parent(current);
0187 }
0188 return builder.getPathToElementName(elem);
0189 };
0190
0191 for (const auto& barrel : barrels) {
0192 auto sensors = builder.resolveSensitives(barrel);
0193 auto barrelNode = builder.layersFromSensors()
0194 .barrel()
0195 .setSensorAxes("XYZ")
0196 .setSensors(std::move(sensors))
0197 .setContainerName(builder.backend().nameOf(barrel))
0198 .groupBy(sensorToLayerKey)
0199 .onLayer(layerCustomizer)
0200 .build();
0201 barrelNode->setAttachmentStrategy(Acts::VolumeAttachmentStrategy::Gap);
0202 barrelNode->setResizeStrategies(Acts::VolumeResizeStrategy::Gap,
0203 Acts::VolumeResizeStrategy::Gap);
0204 containerNode->addChild(std::move(barrelNode));
0205 }
0206
0207 for (const auto& endcap : endcaps) {
0208 auto sensors = builder.resolveSensitives(endcap);
0209 auto endcapNode = builder.layersFromSensors()
0210 .endcap()
0211 .setSensorAxes("XZY")
0212 .setSensors(std::move(sensors))
0213 .setContainerName(builder.backend().nameOf(endcap))
0214 .groupBy(sensorToLayerKey)
0215 .onLayer(layerCustomizer)
0216 .build();
0217 endcapNode->setAttachmentStrategy(Acts::VolumeAttachmentStrategy::Gap);
0218 endcapNode->setResizeStrategies(Acts::VolumeResizeStrategy::Gap,
0219 Acts::VolumeResizeStrategy::Gap);
0220 containerNode->addChild(std::move(endcapNode));
0221 }
0222
0223 outer.addChild(std::move(containerNode));
0224 }
0225
0226 }
0227
0228 std::unique_ptr<Acts::TrackingGeometry> buildOpenDataDetectorBarrelEndcap(
0229 const dd4hep::Detector& detector, const Acts::GeometryContext& gctx,
0230 const Acts::Logger& logger) {
0231 using namespace Acts::Experimental;
0232 using namespace Acts;
0233 using enum AxisDirection;
0234
0235 BlueprintBuilder builder{{
0236 .dd4hepDetector = &detector,
0237 .lengthScale = Acts::UnitConstants::cm,
0238 .gctx = gctx,
0239 },
0240 logger.cloneWithSuffix("BlpBld")};
0241
0242 Blueprint::Config blueprintCfg;
0243 blueprintCfg.envelope = ActsPlugins::DD4hep::detail::kBlueprintEnvelope;
0244 Blueprint root{blueprintCfg};
0245
0246 auto& outer = root.addCylinderContainer("OpenDataDetector", AxisR);
0247 outer.setAttachmentStrategy(VolumeAttachmentStrategy::Gap);
0248
0249 outer.addChild(builder.backend().makeBeampipe());
0250
0251 addBarrelEndcapSubsystem(builder, outer, "Pixels", "pix",
0252 ActsPlugins::DD4hep::detail::kPixelLayerFilter);
0253 addBarrelEndcapSubsystem(builder, outer, "ShortStrips", "ss",
0254 ActsPlugins::DD4hep::detail::kShortStripLayerFilter);
0255 addBarrelEndcapSubsystem(builder, outer, "LongStrips", "ls",
0256 ActsPlugins::DD4hep::detail::kLongStripLayerFilter);
0257
0258 return root.construct(BlueprintOptions{}, gctx, logger);
0259 }
0260
0261 std::unique_ptr<Acts::TrackingGeometry> buildOpenDataDetectorDirectLayer(
0262 const dd4hep::Detector& detector, const Acts::GeometryContext& gctx,
0263 const Acts::Logger& logger) {
0264 using namespace Acts::Experimental;
0265 using namespace Acts;
0266 using enum AxisDirection;
0267
0268 BlueprintBuilder builder{{
0269 .dd4hepDetector = &detector,
0270 .lengthScale = Acts::UnitConstants::cm,
0271 .gctx = gctx,
0272 },
0273 logger.cloneWithSuffix("BlpBld")};
0274
0275 Blueprint::Config blueprintCfg;
0276 blueprintCfg.envelope = ActsPlugins::DD4hep::detail::kBlueprintEnvelope;
0277 Blueprint root{blueprintCfg};
0278
0279 auto& outer = root.addCylinderContainer("OpenDataDetector", AxisR);
0280 outer.setAttachmentStrategy(VolumeAttachmentStrategy::Gap);
0281
0282 outer.addChild(builder.backend().makeBeampipe());
0283
0284 addDirectLayerSubsystem(builder, outer, "Pixels", "pix",
0285 ActsPlugins::DD4hep::detail::kPixelLayerFilter);
0286 addDirectLayerSubsystem(builder, outer, "ShortStrips", "ss",
0287 ActsPlugins::DD4hep::detail::kShortStripLayerFilter);
0288 addDirectLayerSubsystem(builder, outer, "LongStrips", "ls",
0289 ActsPlugins::DD4hep::detail::kLongStripLayerFilter);
0290
0291 return root.construct(BlueprintOptions{}, gctx, logger);
0292 }
0293
0294 std::unique_ptr<Acts::TrackingGeometry> buildOpenDataDetectorDirectLayerGrouped(
0295 const dd4hep::Detector& detector, const Acts::GeometryContext& gctx,
0296 const Acts::Logger& logger) {
0297 using namespace Acts::Experimental;
0298 using namespace Acts;
0299 using enum AxisDirection;
0300
0301 BlueprintBuilder builder{{
0302 .dd4hepDetector = &detector,
0303 .lengthScale = Acts::UnitConstants::cm,
0304 .gctx = gctx,
0305 },
0306 logger.cloneWithSuffix("BlpBld")};
0307
0308 Blueprint::Config blueprintCfg;
0309 blueprintCfg.envelope = ActsPlugins::DD4hep::detail::kBlueprintEnvelope;
0310 Blueprint root{blueprintCfg};
0311
0312 auto& outer = root.addCylinderContainer("OpenDataDetector", AxisR);
0313 outer.setAttachmentStrategy(VolumeAttachmentStrategy::Gap);
0314
0315 outer.addChild(builder.backend().makeBeampipe());
0316
0317 addDirectLayerGroupedSubsystem(
0318 builder, outer, "Pixels", "pix",
0319 ActsPlugins::DD4hep::detail::kPixelLayerFilter);
0320 addDirectLayerGroupedSubsystem(
0321 builder, outer, "ShortStrips", "ss",
0322 ActsPlugins::DD4hep::detail::kShortStripLayerFilter);
0323 addDirectLayerGroupedSubsystem(
0324 builder, outer, "LongStrips", "ls",
0325 ActsPlugins::DD4hep::detail::kLongStripLayerFilter);
0326
0327 return root.construct(BlueprintOptions{}, gctx, logger);
0328 }
0329
0330 }