File indexing completed on 2025-01-18 09:11:19
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Geometry/Blueprint.hpp"
0010
0011 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0012 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0013 #include "Acts/Geometry/Extent.hpp"
0014 #include "Acts/Geometry/PortalShell.hpp"
0015 #include "Acts/Geometry/VolumeBounds.hpp"
0016 #include "Acts/Navigation/INavigationPolicy.hpp"
0017 #include "Acts/Utilities/GraphViz.hpp"
0018
0019 namespace {
0020 const std::string s_rootName = "Root";
0021 }
0022
0023 namespace Acts {
0024
0025 Blueprint::Blueprint(const Config &config) : m_cfg(config) {}
0026
0027 const std::string &Blueprint::name() const {
0028 return s_rootName;
0029 }
0030
0031 Volume &Blueprint::build(const BlueprintOptions & ,
0032 const GeometryContext & ,
0033 const Logger & ) {
0034 throw std::logic_error("Root node cannot be built");
0035 }
0036
0037 PortalShellBase &Blueprint::connect(const BlueprintOptions & ,
0038 const GeometryContext & ,
0039 const Logger & ) {
0040 throw std::logic_error("Root node cannot be connected");
0041 }
0042
0043 void Blueprint::finalize(const BlueprintOptions & ,
0044 const GeometryContext & ,
0045 TrackingVolume & ,
0046 const Logger & ) {
0047 throw std::logic_error("Root node cannot be finalized");
0048 }
0049
0050 void Blueprint::addToGraphviz(std::ostream &os) const {
0051 GraphViz::Node node{
0052 .id = name(), .label = "World", .shape = GraphViz::Shape::House};
0053
0054 os << node;
0055 BlueprintNode::addToGraphviz(os);
0056 }
0057
0058 std::unique_ptr<TrackingGeometry> Blueprint::construct(
0059 const BlueprintOptions &options, const GeometryContext &gctx,
0060 const Logger &logger) {
0061 using enum AxisDirection;
0062
0063 ACTS_INFO(prefix() << "Building tracking geometry from blueprint tree");
0064
0065 options.validate();
0066
0067 if (m_cfg.envelope == ExtentEnvelope::Zero()) {
0068 ACTS_WARNING(prefix() << "Root node is configured with zero envelope. This "
0069 "might lead to navigation issues");
0070 }
0071
0072 if (children().size() != 1) {
0073 ACTS_ERROR(prefix() << "Root node must have exactly one child");
0074 throw std::logic_error("Root node must have exactly one child");
0075 }
0076
0077 auto &child = children().at(0);
0078
0079 ACTS_DEBUG(prefix() << "Executing building on tree");
0080 Volume &topVolume = child.build(options, gctx, logger);
0081 const auto &bounds = topVolume.volumeBounds();
0082
0083 std::stringstream ss;
0084 bounds.toStream(ss);
0085 ACTS_DEBUG(prefix() << "have top volume: " << ss.str() << "\n"
0086 << topVolume.transform().matrix());
0087
0088 std::shared_ptr<VolumeBounds> worldBounds;
0089
0090 if (const auto *cyl = dynamic_cast<const CylinderVolumeBounds *>(&bounds);
0091 cyl != nullptr) {
0092 using enum CylinderVolumeBounds::BoundValues;
0093
0094
0095 auto newBounds = std::make_shared<CylinderVolumeBounds>(*cyl);
0096
0097 const auto &zEnv = m_cfg.envelope[AxisZ];
0098 if (zEnv[0] != zEnv[1]) {
0099 ACTS_ERROR(
0100 prefix() << "Root node cylinder envelope for z must be symmetric");
0101 throw std::logic_error(
0102 "Root node cylinder envelope for z must be "
0103 "symmetric");
0104 }
0105
0106 const auto &rEnv = m_cfg.envelope[AxisR];
0107
0108 newBounds->set({
0109 {eHalfLengthZ, newBounds->get(eHalfLengthZ) + zEnv[0]},
0110 {eMinR, std::max(0.0, newBounds->get(eMinR) - rEnv[0])},
0111 {eMaxR, newBounds->get(eMaxR) + rEnv[1]},
0112 });
0113
0114 worldBounds = std::move(newBounds);
0115
0116 } else if (const auto *box =
0117 dynamic_cast<const CuboidVolumeBounds *>(&bounds);
0118 box != nullptr) {
0119 throw std::logic_error{"Not implemented"};
0120 } else {
0121 throw std::logic_error{"Unsupported volume bounds type"};
0122 }
0123
0124 ACTS_DEBUG(prefix() << "New root volume bounds are: " << *worldBounds);
0125
0126 auto world = std::make_unique<TrackingVolume>(
0127 topVolume.transform(), std::move(worldBounds), "World");
0128
0129
0130 world->setNavigationPolicy(
0131 options.defaultNavigationPolicyFactory->build(gctx, *world, logger));
0132
0133
0134 SingleCylinderPortalShell worldShell{*world};
0135 worldShell.applyToVolume();
0136
0137 auto &shell = child.connect(options, gctx, logger);
0138
0139 shell.fill(*world);
0140
0141 child.finalize(options, gctx, *world, logger);
0142
0143 std::set<std::string, std::less<>> names;
0144
0145 world->visitVolumes([&names, &logger, this](const auto *volume) {
0146 if (names.contains(volume->volumeName())) {
0147 ACTS_ERROR(prefix() << "Duplicate volume name: " << volume->volumeName());
0148 throw std::logic_error("Duplicate volume name");
0149 }
0150 names.insert(volume->volumeName());
0151 });
0152
0153 return std::make_unique<TrackingGeometry>(
0154 std::move(world), nullptr, m_cfg.geometryIdentifierHook, logger);
0155 }
0156
0157 }