Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:23:04

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/Geometry/ContainerBlueprintNode.hpp"
0010 
0011 #include "Acts/Geometry/CuboidPortalShell.hpp"
0012 #include "Acts/Geometry/CuboidVolumeStack.hpp"
0013 #include "Acts/Geometry/CylinderPortalShell.hpp"
0014 #include "Acts/Geometry/CylinderVolumeStack.hpp"
0015 
0016 namespace Acts::Experimental {
0017 
0018 ContainerBlueprintNode::ContainerBlueprintNode(
0019     const std::string& name, AxisDirection axis,
0020     VolumeAttachmentStrategy attachmentStrategy,
0021     VolumeResizeStrategy resizeStrategy)
0022     : ContainerBlueprintNode(name, axis, attachmentStrategy,
0023                              {resizeStrategy, resizeStrategy}) {}
0024 
0025 ContainerBlueprintNode::ContainerBlueprintNode(
0026     const std::string& name, AxisDirection axis,
0027     VolumeAttachmentStrategy attachmentStrategy,
0028     std::pair<VolumeResizeStrategy, VolumeResizeStrategy> resizeStrategies)
0029     : m_name(name),
0030       m_direction(axis),
0031       m_attachmentStrategy(attachmentStrategy),
0032       m_resizeStrategies(resizeStrategies) {}
0033 
0034 const std::string& ContainerBlueprintNode::name() const {
0035   return m_name;
0036 }
0037 
0038 Volume& ContainerBlueprintNode::build(
0039     const Experimental::BlueprintOptions& options, const GeometryContext& gctx,
0040     const Logger& logger) {
0041   ACTS_DEBUG(prefix() << "container build (dir=" << m_direction << ")");
0042 
0043   if (m_stack != nullptr) {
0044     ACTS_ERROR(prefix() << "Volume is already built");
0045     throw std::runtime_error("Volume is already built");
0046   }
0047 
0048   for (auto& child : children()) {
0049     Volume& volume = child.build(options, gctx, logger);
0050     m_childVolumes.push_back(&volume);
0051     // We need to remember which volume we got from which child, so we can
0052     // assemble a crrect portal shell later
0053     m_volumeToNode[&volume] = &child;
0054   }
0055   ACTS_VERBOSE(prefix() << "-> Collected " << m_childVolumes.size()
0056                         << " child volumes");
0057   ACTS_VERBOSE(prefix() << "-> Building the stack");
0058   m_stack = makeStack(m_childVolumes, logger);
0059   ACTS_DEBUG(prefix() << "-> Stack bounds are: " << m_stack->volumeBounds());
0060 
0061   ACTS_DEBUG(prefix() << " *** build complete ***");
0062 
0063   return *m_stack;
0064 }
0065 
0066 void ContainerBlueprintNode::finalize(
0067     const Experimental::BlueprintOptions& options, const GeometryContext& gctx,
0068     TrackingVolume& parent, const Logger& logger) {
0069   ACTS_DEBUG(prefix() << "Finalizing container");
0070 
0071   if (m_stack == nullptr) {
0072     ACTS_ERROR(prefix() << "Volume is not built");
0073     throw std::runtime_error("Volume is not built");
0074   }
0075 
0076   if (m_shell == nullptr) {
0077     ACTS_ERROR(prefix() << "Volume is not connected");
0078     throw std::runtime_error("Volume is not connected");
0079   }
0080 
0081   const auto* policyFactory = options.defaultNavigationPolicyFactory.get();
0082 
0083   ACTS_DEBUG(prefix() << "Registering " << m_gaps.size()
0084                       << " gap volumes with parent");
0085   for (auto& [shell, gap] : m_gaps) {
0086     auto* gapPtr = gap.get();
0087     parent.addVolume(std::move(gap));
0088     shell->applyToVolume();
0089     auto policy = policyFactory->build(gctx, *gapPtr, logger);
0090     gapPtr->setNavigationPolicy(std::move(policy));
0091   }
0092 
0093   ACTS_DEBUG(prefix() << "Finalizing " << children().size() << " children");
0094 
0095   for (auto& child : children()) {
0096     child.finalize(options, gctx, parent, logger);
0097   }
0098 }
0099 
0100 ContainerBlueprintNode& ContainerBlueprintNode::setDirection(
0101     AxisDirection direction) {
0102   if (m_stack != nullptr) {
0103     throw std::runtime_error("Cannot change direction after build");
0104   }
0105   m_direction = direction;
0106   return *this;
0107 }
0108 
0109 ContainerBlueprintNode& ContainerBlueprintNode::setAttachmentStrategy(
0110     VolumeAttachmentStrategy attachmentStrategy) {
0111   if (m_stack != nullptr) {
0112     throw std::runtime_error("Cannot change direction after build");
0113   }
0114   m_attachmentStrategy = attachmentStrategy;
0115   return *this;
0116 }
0117 
0118 ContainerBlueprintNode& ContainerBlueprintNode::setResizeStrategy(
0119     VolumeResizeStrategy resizeStrategy) {
0120   if (m_stack != nullptr) {
0121     throw std::runtime_error("Cannot change direction after build");
0122   }
0123   m_resizeStrategies = {resizeStrategy, resizeStrategy};
0124   return *this;
0125 }
0126 
0127 ContainerBlueprintNode& ContainerBlueprintNode::setResizeStrategies(
0128     VolumeResizeStrategy inner, VolumeResizeStrategy outer) {
0129   if (m_stack != nullptr) {
0130     throw std::runtime_error("Cannot change direction after build");
0131   }
0132   m_resizeStrategies = {inner, outer};
0133   return *this;
0134 }
0135 
0136 AxisDirection ContainerBlueprintNode::direction() const {
0137   return m_direction;
0138 }
0139 
0140 VolumeAttachmentStrategy ContainerBlueprintNode::attachmentStrategy() const {
0141   return m_attachmentStrategy;
0142 }
0143 
0144 std::pair<VolumeResizeStrategy, VolumeResizeStrategy>
0145 ContainerBlueprintNode::resizeStrategies() const {
0146   return m_resizeStrategies;
0147 }
0148 
0149 void ContainerBlueprintNode::addToGraphviz(std::ostream& os) const {
0150   std::stringstream ss;
0151   ss << "<b>" + name() + "</b>";
0152   ss << "<br/>" << typeName() << "Container";
0153   ss << "<br/>dir: " << m_direction;
0154   GraphViz::Node node{
0155       .id = name(), .label = ss.str(), .shape = GraphViz::Shape::DoubleOctagon};
0156   os << node << std::endl;
0157   for (const auto& child : children()) {
0158     os << indent() << GraphViz::Edge{{.id = name()}, {.id = child.name()}}
0159        << std::endl;
0160     child.addToGraphviz(os);
0161   }
0162 }
0163 
0164 template <typename BaseShell, typename SingleShell>
0165 std::vector<BaseShell*> ContainerBlueprintNode::collectChildShells(
0166     const Experimental::BlueprintOptions& options, const GeometryContext& gctx,
0167     VolumeStack& stack, const std::string& prefix, const Logger& logger) {
0168   std::vector<BaseShell*> shells;
0169   ACTS_DEBUG(prefix << "Have " << m_childVolumes.size() << " child volumes");
0170   std::size_t nGaps = 0;
0171   for (Volume* volume : m_childVolumes) {
0172     if (stack.isGapVolume(*volume)) {
0173       // We need to create a TrackingVolume from the gap and put it in the
0174       // shell
0175       auto gap = std::make_unique<TrackingVolume>(*volume);
0176       gap->setVolumeName(name() + "::Gap" + std::to_string(nGaps + 1));
0177       nGaps++;
0178       ACTS_DEBUG(prefix << " ~> Gap volume (" << gap->volumeName()
0179                         << "): " << gap->volumeBounds());
0180       auto shell = std::make_unique<SingleShell>(*gap);
0181       assert(shell->isValid());
0182       shells.push_back(shell.get());
0183 
0184       m_gaps.emplace_back(std::move(shell), std::move(gap));
0185 
0186     } else {
0187       // Figure out which child we got this volume from
0188       auto it = m_volumeToNode.find(volume);
0189       if (it == m_volumeToNode.end()) {
0190         throw std::runtime_error("Volume not found in child volumes");
0191       }
0192 
0193       BlueprintNode& child = *it->second;
0194 
0195       ACTS_DEBUG(prefix << " ~> Child (" << child.name()
0196                         << ") volume: " << volume->volumeBounds());
0197 
0198       auto* shell =
0199           dynamic_cast<BaseShell*>(&child.connect(options, gctx, logger));
0200       if (shell == nullptr) {
0201         ACTS_ERROR(prefix << "Child volume stack type mismatch");
0202         throw std::runtime_error("Child volume stack type mismatch");
0203       }
0204       assert(shell->isValid());
0205 
0206       shells.push_back(shell);
0207     }
0208   }
0209   return shells;
0210 }
0211 
0212 template <typename BaseShell, typename SingleShell, typename ShellStack>
0213 PortalShellBase& ContainerBlueprintNode::connectImpl(
0214     const Experimental::BlueprintOptions& options, const GeometryContext& gctx,
0215     VolumeStack* stack, const std::string& prefix, const Logger& logger) {
0216   ACTS_DEBUG(prefix << "Container connect");
0217   if (stack == nullptr) {
0218     ACTS_ERROR(prefix << "Volume is not built");
0219     throw std::runtime_error("Volume is not built");
0220   }
0221   ACTS_DEBUG(prefix << "Collecting child shells from " << children().size()
0222                     << " children");
0223 
0224   // We have child volumes and gaps as bare Volumes in `m_childVolumes` after
0225   // `build()` has completed. For the stack shell, we need TrackingVolumes in
0226   // the right order.
0227 
0228   std::vector<BaseShell*> shells = collectChildShells<BaseShell, SingleShell>(
0229       options, gctx, *stack, prefix, logger);
0230 
0231   // Sanity checks
0232   throw_assert(shells.size() == m_childVolumes.size(),
0233                "Number of shells does not match number of child volumes");
0234 
0235   throw_assert(std::ranges::none_of(
0236                    shells, [](const auto* shell) { return shell == nullptr; }),
0237                "Invalid shell pointer");
0238 
0239   throw_assert(std::ranges::all_of(
0240                    shells, [](const auto* shell) { return shell->isValid(); }),
0241                "Invalid shell");
0242 
0243   ACTS_DEBUG(prefix << "Producing merged stack shell in " << direction()
0244                     << " direction from " << shells.size() << " shells");
0245   m_shell = std::make_unique<ShellStack>(gctx, std::move(shells), direction(),
0246                                          logger);
0247 
0248   assert(m_shell != nullptr && "No shell was built at the end of connect");
0249   assert(m_shell->isValid() && "Shell is not valid at the end of connect");
0250   return *m_shell;
0251 }
0252 
0253 PortalShellBase& CylinderContainerBlueprintNode::connect(
0254     const Experimental::BlueprintOptions& options, const GeometryContext& gctx,
0255     const Logger& logger) {
0256   return connectImpl<CylinderPortalShell, SingleCylinderPortalShell,
0257                      CylinderStackPortalShell>(options, gctx, m_stack.get(),
0258                                                prefix(), logger);
0259 }
0260 
0261 const std::string& CylinderContainerBlueprintNode::typeName() const {
0262   return s_typeName;
0263 }
0264 
0265 std::unique_ptr<VolumeStack> CylinderContainerBlueprintNode::makeStack(
0266     std::vector<Volume*>& volumes, const Logger& logger) {
0267   return std::make_unique<CylinderVolumeStack>(
0268       volumes, m_direction, m_attachmentStrategy, m_resizeStrategies, logger);
0269 }
0270 
0271 PortalShellBase& CuboidContainerBlueprintNode::connect(
0272     const Experimental::BlueprintOptions& options, const GeometryContext& gctx,
0273     const Logger& logger) {
0274   return connectImpl<CuboidPortalShell, SingleCuboidPortalShell,
0275                      CuboidStackPortalShell>(options, gctx, m_stack.get(),
0276                                              prefix(), logger);
0277 }
0278 
0279 const std::string& CuboidContainerBlueprintNode::typeName() const {
0280   return s_typeName;
0281 }
0282 
0283 std::unique_ptr<VolumeStack> CuboidContainerBlueprintNode::makeStack(
0284     std::vector<Volume*>& volumes, const Logger& logger) {
0285   return std::make_unique<CuboidVolumeStack>(volumes, m_direction,
0286                                              m_attachmentStrategy,
0287                                              m_resizeStrategies.first, logger);
0288 }
0289 
0290 }  // namespace Acts::Experimental