Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:11:20

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