Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-01 07:52:47

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 VolumeResizeStrategy ContainerBlueprintNode::resizeStrategy() const {
0145   if (m_resizeStrategies.first != m_resizeStrategies.second) {
0146     throw std::runtime_error(
0147         "Resize strategy is not the same for inner and outer. Use "
0148         "resizeStrategies() instead.");
0149   }
0150   return m_resizeStrategies.first;
0151 }
0152 
0153 std::pair<VolumeResizeStrategy, VolumeResizeStrategy>
0154 ContainerBlueprintNode::resizeStrategies() const {
0155   return m_resizeStrategies;
0156 }
0157 
0158 void ContainerBlueprintNode::addToGraphviz(std::ostream& os) const {
0159   std::stringstream ss;
0160   ss << "<b>" + name() + "</b>";
0161   ss << "<br/>" << typeName() << "Container";
0162   ss << "<br/>dir: " << m_direction;
0163   GraphViz::Node node{
0164       .id = name(), .label = ss.str(), .shape = GraphViz::Shape::DoubleOctagon};
0165   os << node << std::endl;
0166   for (const auto& child : children()) {
0167     os << indent() << GraphViz::Edge{{.id = name()}, {.id = child.name()}}
0168        << std::endl;
0169     child.addToGraphviz(os);
0170   }
0171 }
0172 
0173 template <typename BaseShell, typename SingleShell>
0174 std::vector<BaseShell*> ContainerBlueprintNode::collectChildShells(
0175     const Experimental::BlueprintOptions& options, const GeometryContext& gctx,
0176     VolumeStack& stack, const std::string& prefix, const Logger& logger) {
0177   std::vector<BaseShell*> shells;
0178   ACTS_DEBUG(prefix << "Have " << m_childVolumes.size() << " child volumes");
0179   std::size_t nGaps = 0;
0180   for (Volume* volume : m_childVolumes) {
0181     if (stack.isGapVolume(*volume)) {
0182       // We need to create a TrackingVolume from the gap and put it in the
0183       // shell
0184       auto gap = std::make_unique<TrackingVolume>(*volume);
0185       gap->setVolumeName(name() + "::Gap" + std::to_string(nGaps + 1));
0186       nGaps++;
0187       ACTS_DEBUG(prefix << " ~> Gap volume (" << gap->volumeName()
0188                         << "): " << gap->volumeBounds());
0189       auto shell = std::make_unique<SingleShell>(*gap);
0190       assert(shell->isValid());
0191       shells.push_back(shell.get());
0192 
0193       m_gaps.emplace_back(std::move(shell), std::move(gap));
0194 
0195     } else {
0196       // Figure out which child we got this volume from
0197       auto it = m_volumeToNode.find(volume);
0198       if (it == m_volumeToNode.end()) {
0199         throw std::runtime_error("Volume not found in child volumes");
0200       }
0201 
0202       BlueprintNode& child = *it->second;
0203 
0204       ACTS_DEBUG(prefix << " ~> Child (" << child.name()
0205                         << ") volume: " << volume->volumeBounds());
0206 
0207       auto* shell =
0208           dynamic_cast<BaseShell*>(&child.connect(options, gctx, logger));
0209       if (shell == nullptr) {
0210         ACTS_ERROR(prefix << "Child volume stack type mismatch");
0211         throw std::runtime_error("Child volume stack type mismatch");
0212       }
0213       assert(shell->isValid());
0214 
0215       shells.push_back(shell);
0216     }
0217   }
0218   return shells;
0219 }
0220 
0221 template <typename BaseShell, typename SingleShell, typename ShellStack>
0222 PortalShellBase& ContainerBlueprintNode::connectImpl(
0223     const Experimental::BlueprintOptions& options, const GeometryContext& gctx,
0224     VolumeStack* stack, const std::string& prefix, const Logger& logger) {
0225   ACTS_DEBUG(prefix << "Container connect");
0226   if (stack == nullptr) {
0227     ACTS_ERROR(prefix << "Volume is not built");
0228     throw std::runtime_error("Volume is not built");
0229   }
0230   ACTS_DEBUG(prefix << "Collecting child shells from " << children().size()
0231                     << " children");
0232 
0233   // We have child volumes and gaps as bare Volumes in `m_childVolumes` after
0234   // `build()` has completed. For the stack shell, we need TrackingVolumes in
0235   // the right order.
0236 
0237   std::vector<BaseShell*> shells = collectChildShells<BaseShell, SingleShell>(
0238       options, gctx, *stack, prefix, logger);
0239 
0240   // Sanity checks
0241   throw_assert(shells.size() == m_childVolumes.size(),
0242                "Number of shells does not match number of child volumes");
0243 
0244   throw_assert(std::ranges::none_of(
0245                    shells, [](const auto* shell) { return shell == nullptr; }),
0246                "Invalid shell pointer");
0247 
0248   throw_assert(std::ranges::all_of(
0249                    shells, [](const auto* shell) { return shell->isValid(); }),
0250                "Invalid shell");
0251 
0252   ACTS_DEBUG(prefix << "Producing merged stack shell in " << direction()
0253                     << " direction from " << shells.size() << " shells");
0254   m_shell = std::make_unique<ShellStack>(gctx, std::move(shells), direction(),
0255                                          logger);
0256 
0257   assert(m_shell != nullptr && "No shell was built at the end of connect");
0258   assert(m_shell->isValid() && "Shell is not valid at the end of connect");
0259   return *m_shell;
0260 }
0261 
0262 PortalShellBase& CylinderContainerBlueprintNode::connect(
0263     const Experimental::BlueprintOptions& options, const GeometryContext& gctx,
0264     const Logger& logger) {
0265   return connectImpl<CylinderPortalShell, SingleCylinderPortalShell,
0266                      CylinderStackPortalShell>(options, gctx, m_stack.get(),
0267                                                prefix(), logger);
0268 }
0269 
0270 const std::string& CylinderContainerBlueprintNode::typeName() const {
0271   return s_typeName;
0272 }
0273 
0274 std::unique_ptr<VolumeStack> CylinderContainerBlueprintNode::makeStack(
0275     std::vector<Volume*>& volumes, const Logger& logger) {
0276   return std::make_unique<CylinderVolumeStack>(
0277       volumes, m_direction, m_attachmentStrategy, m_resizeStrategies, logger);
0278 }
0279 
0280 PortalShellBase& CuboidContainerBlueprintNode::connect(
0281     const Experimental::BlueprintOptions& options, const GeometryContext& gctx,
0282     const Logger& logger) {
0283   return connectImpl<CuboidPortalShell, SingleCuboidPortalShell,
0284                      CuboidStackPortalShell>(options, gctx, m_stack.get(),
0285                                              prefix(), logger);
0286 }
0287 
0288 const std::string& CuboidContainerBlueprintNode::typeName() const {
0289   return s_typeName;
0290 }
0291 
0292 std::unique_ptr<VolumeStack> CuboidContainerBlueprintNode::makeStack(
0293     std::vector<Volume*>& volumes, const Logger& logger) {
0294   return std::make_unique<CuboidVolumeStack>(volumes, m_direction,
0295                                              m_attachmentStrategy,
0296                                              m_resizeStrategies.first, logger);
0297 }
0298 
0299 }  // namespace Acts::Experimental