Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-08 08:00:23

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include "Acts/Definitions/Units.hpp"
0010 #include "Acts/Geometry/Blueprint.hpp"
0011 #include "Acts/Geometry/BlueprintOptions.hpp"
0012 #include "Acts/Geometry/ContainerBlueprintNode.hpp"
0013 #include "Acts/Geometry/NavigationPolicyFactory.hpp"
0014 #include "Acts/Geometry/StaticBlueprintNode.hpp"
0015 #include "Acts/Geometry/TrackingVolume.hpp"
0016 #include "Acts/Geometry/VolumeAttachmentStrategy.hpp"
0017 #include "Acts/Geometry/VolumeResizeStrategy.hpp"
0018 #include "Acts/Navigation/CylinderNavigationPolicy.hpp"
0019 #include "Acts/Navigation/SurfaceArrayNavigationPolicy.hpp"
0020 #include "Acts/Surfaces/CylinderBounds.hpp"
0021 #include "ActsPlugins/DD4hep/OpenDataDetectorBuilder.hpp"
0022 #include "ActsPlugins/Root/BlueprintBuilder.hpp"
0023 #include "ActsPlugins/Root/TGeoSurfaceConverter.hpp"
0024 
0025 #include <array>
0026 #include <format>
0027 #include <memory>
0028 #include <optional>
0029 #include <regex>
0030 #include <span>
0031 #include <stdexcept>
0032 #include <string>
0033 #include <string_view>
0034 
0035 #include <DD4hep/Detector.h>
0036 
0037 #include "TGeoMaterial.h"
0038 #include "TGeoMedium.h"
0039 #include "TGeoNode.h"
0040 #include "TGeoVolume.h"
0041 
0042 namespace ActsPlugins::DD4hep {
0043 
0044 namespace {
0045 
0046 const std::regex kTGeoPixelLayerFilter{"(?:PixelBarrel|PixelEndcap[NP])(\\d)"};
0047 const std::regex kTGeoShortStripLayerFilter{
0048     "(?:ShortStripBarrel|ShortStripEndcap[NP])(\\d)"};
0049 const std::regex kTGeoLongStripLayerFilter{
0050     "(?:LongStripBarrel|LongStripEndcap[NP])(\\d)"};
0051 
0052 const std::regex kTGeoPixelBarrelLayerFilter{"PixelBarrel\\d"};
0053 const std::regex kTGeoShortStripBarrelLayerFilter{"ShortStripBarrel\\d"};
0054 const std::regex kTGeoLongStripBarrelLayerFilter{"LongStripBarrel\\d"};
0055 constexpr std::string_view kTGeoBeampipeName = "BeamPipe";
0056 
0057 struct TGeoLayerBinning {
0058   std::span<const std::size_t> barrelPhiBins = {};
0059   std::size_t barrelZBins = 0u;
0060   std::array<std::size_t, 2> endcapBins = {0u, 0u};
0061 
0062   std::array<std::size_t, 2> binsFor(bool isBarrelLayer, int layerIdx) const {
0063     if (!isBarrelLayer) {
0064       return endcapBins;
0065     }
0066 
0067     if (layerIdx < 0 ||
0068         static_cast<std::size_t>(layerIdx) >= barrelPhiBins.size()) {
0069       throw std::runtime_error(std::format(
0070           "No TGeo barrel binning configured for layer {}", layerIdx));
0071     }
0072 
0073     return {barrelPhiBins[static_cast<std::size_t>(layerIdx)], barrelZBins};
0074   }
0075 };
0076 
0077 constexpr std::array<std::size_t, 4> kPixelBarrelPhiBins = {16u, 32u, 52u, 78u};
0078 constexpr TGeoLayerBinning kPixelLayerBinning{
0079     .barrelPhiBins = kPixelBarrelPhiBins,
0080     .barrelZBins = 14u,
0081     .endcapBins = {2u, 36u},
0082 };
0083 
0084 constexpr std::array<std::size_t, 4> kShortStripBarrelPhiBins = {40u, 56u, 78u,
0085                                                                  102u};
0086 constexpr TGeoLayerBinning kShortStripLayerBinning{
0087     .barrelPhiBins = kShortStripBarrelPhiBins,
0088     .barrelZBins = 21u,
0089     .endcapBins = {3u, 42u},
0090 };
0091 
0092 constexpr std::array<std::size_t, 2> kLongStripBarrelPhiBins = {60u, 80u};
0093 constexpr TGeoLayerBinning kLongStripLayerBinning{
0094     .barrelPhiBins = kLongStripBarrelPhiBins,
0095     .barrelZBins = 21u,
0096     .endcapBins = {2u, 48u},
0097 };
0098 
0099 bool hasSensitiveMaterial(const TGeoBlueprintBuilderBackend::Element& element) {
0100   if (element.context == nullptr || element.context->node == nullptr) {
0101     return false;
0102   }
0103 
0104   const auto* volume = element.context->node->GetVolume();
0105   if (volume == nullptr) {
0106     return false;
0107   }
0108 
0109   const auto* medium = volume->GetMedium();
0110   if (medium == nullptr || medium->GetMaterial() == nullptr ||
0111       medium->GetMaterial()->GetName() == nullptr) {
0112     return false;
0113   }
0114 
0115   return std::string_view{medium->GetMaterial()->GetName()}.find("Silicon") !=
0116          std::string_view::npos;
0117 }
0118 
0119 auto makeTGeoLayerCustomizer(const BlueprintBuilder& builder,
0120                              const TGeoLayerBinning& binning,
0121                              const std::regex& layerFilter) {
0122   return [&builder, &binning, layerFilter](
0123              const std::optional<TGeoBlueprintBuilderBackend::Element>& elem,
0124              Acts::Experimental::LayerBlueprintNode& layer) {
0125     layer.setEnvelope(detail::kLayerEnvelope);
0126 
0127     const std::string elemName =
0128         elem.has_value() ? std::string{builder.backend().nameOf(*elem)}
0129                          : layer.name();
0130     const int layerIdx = detail::layerIndexFromName(elemName, layerFilter);
0131 
0132     using SrfArrayNavPol = Acts::SurfaceArrayNavigationPolicy;
0133     using enum SrfArrayNavPol::LayerType;
0134 
0135     SrfArrayNavPol::Config navCfg;
0136     const bool isBarrelLayer =
0137         layer.layerType() ==
0138         Acts::Experimental::LayerBlueprintNode::LayerType::Cylinder;
0139     navCfg.layerType = isBarrelLayer ? Cylinder : Disc;
0140 
0141     const auto bins = binning.binsFor(isBarrelLayer, layerIdx);
0142     navCfg.bins = {bins[0], bins[1]};
0143 
0144     layer.setNavigationPolicyFactory(Acts::NavigationPolicyFactory{}
0145                                          .add<Acts::CylinderNavigationPolicy>()
0146                                          .add<SrfArrayNavPol>(navCfg)
0147                                          .asUniquePtr());
0148   };
0149 }
0150 
0151 std::shared_ptr<Acts::Experimental::StaticBlueprintNode> makeTGeoBeampipeNode(
0152     const BlueprintBuilder& builder) {
0153   const auto beampipeElement =
0154       builder.findDetElementByName(std::string{kTGeoBeampipeName});
0155   if (!beampipeElement.has_value()) {
0156     throw std::runtime_error(
0157         std::format("Could not find beampipe element '{}'", kTGeoBeampipeName));
0158   }
0159 
0160   const auto& node = builder.backend().nodeOf(*beampipeElement);
0161   const auto tgTransform = builder.backend().transformOf(*beampipeElement);
0162   auto [bounds, transform, thickness] =
0163       ActsPlugins::TGeoSurfaceConverter::cylinderComponents(
0164           *node.GetVolume()->GetShape(), tgTransform.GetRotationMatrix(),
0165           tgTransform.GetTranslation(), "XYZ", Acts::UnitConstants::cm);
0166   (void)thickness;
0167 
0168   if (bounds == nullptr) {
0169     throw std::runtime_error(
0170         "Beampipe element shape could not be converted to cylinder.");
0171   }
0172 
0173   auto volumeBounds = std::make_shared<Acts::CylinderVolumeBounds>(
0174       0., bounds->get(Acts::CylinderBounds::eR),
0175       bounds->get(Acts::CylinderBounds::eHalfLengthZ));
0176   auto volume = std::make_unique<Acts::TrackingVolume>(
0177       transform, volumeBounds, std::string{kTGeoBeampipeName});
0178   return std::make_shared<Acts::Experimental::StaticBlueprintNode>(
0179       std::move(volume));
0180 }
0181 
0182 void configureSubsystemNode(Acts::Experimental::ContainerBlueprintNode& node) {
0183   node.setAttachmentStrategy(Acts::VolumeAttachmentStrategy::Gap);
0184   node.setResizeStrategies(Acts::VolumeResizeStrategy::Gap,
0185                            Acts::VolumeResizeStrategy::Gap);
0186 }
0187 
0188 struct TGeoSubsystemSpec {
0189   std::string_view assembly;
0190   std::string_view barrelName;
0191   std::string_view negativeEndcapName;
0192   std::string_view positiveEndcapName;
0193   const TGeoLayerBinning& binning;
0194   const std::regex& layerFilter;
0195   const std::regex& barrelLayerFilter;
0196   const std::regex& negativeEndcapLayerFilter;
0197   const std::regex& positiveEndcapLayerFilter;
0198 };
0199 
0200 void addTGeoSubsystem(const BlueprintBuilder& builder,
0201                       Acts::Experimental::BlueprintNode& parent,
0202                       const TGeoSubsystemSpec& spec) {
0203   const auto assemblyElement =
0204       builder.findDetElementByName(std::string{spec.assembly});
0205   if (!assemblyElement.has_value()) {
0206     throw std::runtime_error(
0207         std::format("Could not find assembly '{}'", spec.assembly));
0208   }
0209   const auto barrelElement = builder.findDetElementByName(
0210       *assemblyElement, std::string{spec.barrelName});
0211   if (!barrelElement.has_value()) {
0212     throw std::runtime_error(
0213         std::format("Could not find barrel '{}'", spec.barrelName));
0214   }
0215   const auto negativeEndcapElement = builder.findDetElementByName(
0216       *assemblyElement, std::string{spec.negativeEndcapName});
0217   if (!negativeEndcapElement.has_value()) {
0218     throw std::runtime_error(std::format("Could not find negative endcap '{}'",
0219                                          spec.negativeEndcapName));
0220   }
0221   const auto positiveEndcapElement = builder.findDetElementByName(
0222       *assemblyElement, std::string{spec.positiveEndcapName});
0223   if (!positiveEndcapElement.has_value()) {
0224     throw std::runtime_error(std::format("Could not find positive endcap '{}'",
0225                                          spec.positiveEndcapName));
0226   }
0227 
0228   auto subsystemNode =
0229       std::make_shared<Acts::Experimental::CylinderContainerBlueprintNode>(
0230           builder.backend().nameOf(*assemblyElement),
0231           Acts::AxisDirection::AxisZ);
0232 
0233   auto barrelNode = builder.layers()
0234                         .barrel()
0235                         .setSensorAxes("XYZ")
0236                         .setLayerFilter(spec.barrelLayerFilter)
0237                         .setContainer(*barrelElement)
0238                         .setContainerName(std::string{spec.barrelName})
0239                         .onLayer(makeTGeoLayerCustomizer(builder, spec.binning,
0240                                                          spec.layerFilter))
0241                         .build();
0242   configureSubsystemNode(*barrelNode);
0243   subsystemNode->addChild(std::move(barrelNode));
0244 
0245   auto negativeEndcapNode =
0246       builder.layers()
0247           .endcap()
0248           .setSensorAxes("XZY")
0249           .setLayerFilter(spec.negativeEndcapLayerFilter)
0250           .setContainer(*negativeEndcapElement)
0251           .setContainerName(std::string{spec.negativeEndcapName})
0252           .onLayer(
0253               makeTGeoLayerCustomizer(builder, spec.binning, spec.layerFilter))
0254           .build();
0255   configureSubsystemNode(*negativeEndcapNode);
0256   subsystemNode->addChild(std::move(negativeEndcapNode));
0257 
0258   auto positiveEndcapNode =
0259       builder.layers()
0260           .endcap()
0261           .setSensorAxes("XZY")
0262           .setLayerFilter(spec.positiveEndcapLayerFilter)
0263           .setContainer(*positiveEndcapElement)
0264           .setContainerName(std::string{spec.positiveEndcapName})
0265           .onLayer(
0266               makeTGeoLayerCustomizer(builder, spec.binning, spec.layerFilter))
0267           .build();
0268   configureSubsystemNode(*positiveEndcapNode);
0269   subsystemNode->addChild(std::move(positiveEndcapNode));
0270 
0271   parent.addChild(std::move(subsystemNode));
0272 }
0273 
0274 }  // namespace
0275 
0276 std::unique_ptr<Acts::TrackingGeometry>
0277 buildOpenDataDetectorBarrelEndcapViaTGeo(const TGeoNode& rootNode,
0278                                          const Acts::GeometryContext& gctx,
0279                                          const Acts::Logger& logger) {
0280   using namespace Acts::Experimental;
0281   using namespace Acts;
0282   using enum AxisDirection;
0283 
0284   TGeoBlueprintBuilderBackend::Config cfg;
0285   cfg.root = &rootNode;
0286   cfg.lengthScale = Acts::UnitConstants::cm;
0287   cfg.sensitivePredicate = hasSensitiveMaterial;
0288 
0289   BlueprintBuilder builder{cfg, logger.cloneWithSuffix("TGeoBlpBld")};
0290 
0291   Blueprint::Config blueprintCfg;
0292   blueprintCfg.envelope = ActsPlugins::DD4hep::detail::kBlueprintEnvelope;
0293   Blueprint root{blueprintCfg};
0294 
0295   auto& outer = root.addCylinderContainer("OpenDataDetector", AxisR);
0296   outer.setAttachmentStrategy(VolumeAttachmentStrategy::Gap);
0297 
0298   outer.addChild(makeTGeoBeampipeNode(builder));
0299   addTGeoSubsystem(
0300       builder, outer,
0301       {.assembly = "Pixels",
0302        .barrelName = "PixelBarrel",
0303        .negativeEndcapName = "PixelEndcapN",
0304        .positiveEndcapName = "PixelEndcapP",
0305        .binning = kPixelLayerBinning,
0306        .layerFilter = kTGeoPixelLayerFilter,
0307        .barrelLayerFilter = kTGeoPixelBarrelLayerFilter,
0308        .negativeEndcapLayerFilter = detail::kPixelNegativeEndcapLayerFilter,
0309        .positiveEndcapLayerFilter = detail::kPixelPositiveEndcapLayerFilter});
0310   addTGeoSubsystem(builder, outer,
0311                    {.assembly = "ShortStrips",
0312                     .barrelName = "ShortStripBarrel",
0313                     .negativeEndcapName = "ShortStripEndcapN",
0314                     .positiveEndcapName = "ShortStripEndcapP",
0315                     .binning = kShortStripLayerBinning,
0316                     .layerFilter = kTGeoShortStripLayerFilter,
0317                     .barrelLayerFilter = kTGeoShortStripBarrelLayerFilter,
0318                     .negativeEndcapLayerFilter =
0319                         detail::kShortStripNegativeEndcapLayerFilter,
0320                     .positiveEndcapLayerFilter =
0321                         detail::kShortStripPositiveEndcapLayerFilter});
0322   addTGeoSubsystem(
0323       builder, outer,
0324       {.assembly = "LongStrips",
0325        .barrelName = "LongStripBarrel",
0326        .negativeEndcapName = "LongStripEndcapN",
0327        .positiveEndcapName = "LongStripEndcapP",
0328        .binning = kLongStripLayerBinning,
0329        .layerFilter = kTGeoLongStripLayerFilter,
0330        .barrelLayerFilter = kTGeoLongStripBarrelLayerFilter,
0331        .negativeEndcapLayerFilter = detail::kLongStripNegativeEndcapLayerFilter,
0332        .positiveEndcapLayerFilter =
0333            detail::kLongStripPositiveEndcapLayerFilter});
0334 
0335   return root.construct(BlueprintOptions{}, gctx, logger);
0336 }
0337 
0338 }  // namespace ActsPlugins::DD4hep