Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-16 07:46:58

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/Blueprint.hpp"
0010 
0011 #include "Acts/Geometry/CuboidPortalShell.hpp"
0012 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0013 #include "Acts/Geometry/CylinderPortalShell.hpp"
0014 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0015 #include "Acts/Geometry/Extent.hpp"
0016 #include "Acts/Geometry/GeometryIdentifier.hpp"
0017 #include "Acts/Geometry/PadBlueprintNode.hpp"
0018 #include "Acts/Geometry/PortalShell.hpp"
0019 #include "Acts/Geometry/VolumeBounds.hpp"
0020 #include "Acts/Geometry/detail/AlignablePortalVisitor.hpp"
0021 #include "Acts/Geometry/detail/BoundDeduplicator.hpp"
0022 #include "Acts/Navigation/INavigationPolicy.hpp"
0023 #include "Acts/Navigation/TryAllNavigationPolicy.hpp"
0024 #include "Acts/Utilities/GraphViz.hpp"
0025 #include "Acts/Utilities/Logger.hpp"
0026 
0027 #include <algorithm>
0028 
0029 namespace {
0030 const std::string s_rootName = "Root";
0031 }
0032 
0033 namespace Acts::Experimental {
0034 
0035 ///@class BlueprintVisitor
0036 /// A class for visiting blueprint hierarchy and apply the geometry identifiers
0037 class BlueprintVisitor : public TrackingGeometryMutableVisitor {
0038  public:
0039   explicit BlueprintVisitor(
0040       const Logger &logger,
0041       std::array<const TrackingVolume *, GeometryIdentifier::getMaxVolume()>
0042           &volumesById)
0043       : TrackingGeometryMutableVisitor(true),
0044         m_volumesById(volumesById),
0045         m_logger(logger) {}
0046 
0047   void visitVolume(TrackingVolume &volume) override {
0048     GeometryIdentifier::Value iportal = 0;
0049     GeometryIdentifier::Value isensitive = 0;
0050 
0051     auto id = volume.geometryId();
0052 
0053     if (id == GeometryIdentifier{}) {
0054       auto it = std::ranges::find(m_volumesById, nullptr);
0055       if (it == m_volumesById.end()) {
0056         ACTS_ERROR("No free volume IDs left, all " << m_volumesById.size()
0057                                                    << " are used");
0058         // @TODO: Maybe link to documentation about this
0059         throw std::logic_error("No free volume IDs left");
0060       }
0061 
0062       id = GeometryIdentifier().withVolume(
0063           std::distance(m_volumesById.begin(), it) + 1);
0064 
0065       ACTS_VERBOSE("Assigning volume ID " << id << " for "
0066                                           << volume.volumeName());
0067       volume.assignGeometryId(id);
0068       *it = &volume;
0069     }
0070 
0071     for (auto &portal : volume.portals()) {
0072       if (portal.surface().geometryId() != GeometryIdentifier{}) {
0073         continue;
0074       }
0075       iportal += 1;
0076       auto portalId = id.withBoundary(iportal);
0077       ACTS_VERBOSE("Assigning portal ID: " << portalId);
0078       portal.surface().assignGeometryId(portalId);
0079     }
0080     for (auto &surface : volume.surfaces()) {
0081       if (surface.geometryId() != GeometryIdentifier{}) {
0082         continue;
0083       }
0084       isensitive += 1;
0085       auto surfaceId = id.withSensitive(isensitive);
0086       ACTS_VERBOSE("Assigning surface ID: " << surfaceId);
0087       surface.assignGeometryId(surfaceId);
0088     }
0089   }
0090 
0091  private:
0092   std::array<const TrackingVolume *, GeometryIdentifier::getMaxVolume()>
0093       &m_volumesById;
0094   const Logger &m_logger;
0095   const Acts::Logger &logger() const { return m_logger; }
0096 };
0097 
0098 Blueprint::Blueprint(const Config &config) : m_cfg(config) {}
0099 
0100 const std::string &Blueprint::name() const {
0101   return s_rootName;
0102 }
0103 
0104 Volume &Blueprint::build(const BlueprintOptions & /*options*/,
0105                          const GeometryContext & /*gctx*/,
0106                          const Logger & /*logger*/) {
0107   throw std::logic_error("Root node cannot be built");
0108 }
0109 
0110 PortalShellBase &Blueprint::connect(const BlueprintOptions & /*options*/,
0111                                     const GeometryContext & /*gctx*/,
0112                                     const Logger & /*logger*/) {
0113   throw std::logic_error("Root node cannot be connected");
0114 }
0115 
0116 void Blueprint::finalize(const BlueprintOptions & /*options*/,
0117                          const GeometryContext & /*gctx*/,
0118                          TrackingVolume & /*parent*/,
0119                          const Logger & /*logger*/) {
0120   throw std::logic_error("Root node cannot be finalized");
0121 }
0122 
0123 void Blueprint::addToGraphviz(std::ostream &os) const {
0124   GraphViz::Node node{
0125       .id = name(), .label = "World", .shape = GraphViz::Shape::House};
0126 
0127   os << node;
0128   BlueprintNode::addToGraphviz(os);
0129 }
0130 
0131 std::unique_ptr<TrackingGeometry> Blueprint::construct(
0132     const BlueprintOptions &options, const GeometryContext &gctx,
0133     const Logger &logger) {
0134   using enum AxisDirection;
0135 
0136   ACTS_INFO(prefix() << "Building tracking geometry from blueprint tree");
0137 
0138   options.validate();
0139 
0140   if (m_cfg.envelope == ExtentEnvelope::Zero()) {
0141     ACTS_WARNING(prefix() << "Root node is configured with zero envelope. This "
0142                              "might lead to navigation issues");
0143   }
0144 
0145   if (children().size() != 1) {
0146     ACTS_ERROR(prefix() << "Root node must have exactly one child");
0147     throw std::logic_error("Root node must have exactly one child");
0148   }
0149 
0150   auto child = childPtr()[0];
0151   clearChildren();
0152 
0153   ACTS_DEBUG(prefix() << "Executing building on tree");
0154 
0155   auto autoSizingNode = std::make_shared<Acts::Experimental::PadBlueprintNode>(
0156       "World", m_cfg.envelope);
0157 
0158   autoSizingNode->addChild(std::move(child));
0159 
0160   autoSizingNode->build(options, gctx, logger);
0161 
0162   auto world = autoSizingNode->trackingVolume();
0163 
0164   ACTS_DEBUG(prefix() << "New root volume bounds are: "
0165                       << world->volumeBounds());
0166 
0167   world->setNavigationPolicy(std::make_unique<Acts::TryAllNavigationPolicy>(
0168       gctx, *world, logger, Acts::TryAllNavigationPolicy::Config{}));
0169 
0170   autoSizingNode->connect(options, gctx, logger);
0171 
0172   if (m_cfg.boundDeduplication) {
0173     ACTS_DEBUG("Deduplicate equivalent bounds");
0174     detail::BoundDeduplicator deduplicator{};
0175     world->apply(deduplicator);
0176   }
0177   autoSizingNode->finalize(options, gctx, *world, logger);
0178 
0179   std::set<std::string, std::less<>> volumeNames;
0180   std::array<const TrackingVolume *, GeometryIdentifier::getMaxVolume()>
0181       volumesById{};
0182   volumesById.fill(nullptr);
0183 
0184   // @TODO: Take this from GeometryIdentifier instead of hard-coding
0185 
0186   world->apply([&, this](TrackingVolume &volume) {
0187     if (volumeNames.contains(volume.volumeName())) {
0188       ACTS_ERROR(prefix() << "Duplicate volume name: " << volume.volumeName());
0189       throw std::logic_error("Duplicate volume name");
0190     }
0191     volumeNames.insert(volume.volumeName());
0192 
0193     if (volume.geometryId() != GeometryIdentifier{}) {
0194       // We can have multiple volumes with the same volume ID component, but
0195       // they should differ in other components like "layer"
0196       if (volumesById.at(volume.geometryId().volume() - 1) == nullptr) {
0197         volumesById.at(volume.geometryId().volume() - 1) = &volume;
0198       }
0199     }
0200 
0201     // Clear boundary surfaces!
0202     volume.clearBoundarySurfaces();
0203   });
0204 
0205   std::size_t unusedVolumeIds = std::ranges::count(volumesById, nullptr);
0206   ACTS_DEBUG(prefix() << "Number of unused volume IDs: " << unusedVolumeIds);
0207 
0208   ACTS_DEBUG(prefix() << "Assigning volume IDs for remaining volumes");
0209 
0210   BlueprintVisitor visitor{logger, volumesById};
0211   world->apply(visitor);
0212 
0213   Acts::detail::AlignablePortalVisitor alignPortals{gctx, logger};
0214   world->apply(alignPortals);
0215 
0216   return std::make_unique<TrackingGeometry>(
0217       std::shared_ptr<TrackingVolume>(autoSizingNode->releaseVolume()), nullptr,
0218       GeometryIdentifierHook{}, logger, false);
0219 }
0220 
0221 }  // namespace Acts::Experimental