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