File indexing completed on 2025-07-02 07:51:05
0001
0002
0003
0004
0005
0006
0007
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
0052
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
0183
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
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
0234
0235
0236
0237 std::vector<BaseShell*> shells = collectChildShells<BaseShell, SingleShell>(
0238 options, gctx, *stack, prefix, logger);
0239
0240
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 }