File indexing completed on 2025-01-18 09:11:20
0001
0002
0003
0004
0005
0006
0007
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
0053
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
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
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
0129
0130
0131
0132 std::vector<CylinderPortalShell*> shells =
0133 collectChildShells(options, gctx, logger);
0134
0135
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 }