diff --git a/Core/include/Acts/Geometry/LayerBlueprintNode.hpp b/Core/include/Acts/Geometry/LayerBlueprintNode.hpp index 41c712ca2c7..f949addf962 100644 --- a/Core/include/Acts/Geometry/LayerBlueprintNode.hpp +++ b/Core/include/Acts/Geometry/LayerBlueprintNode.hpp @@ -78,9 +78,30 @@ class LayerBlueprintNode final : public StaticBlueprintNode { LayerBlueprintNode& setSurfaces( std::vector> surfaces); + /// Register a set of surface placemen with the layer node. The surfaces that + /// are not yet registered with the layer are also registered + /// @param placements The list of placements to be registered with the layer + /// @note This will clear any previously registered proto layer + /// @return Reference to this node for chaining + LayerBlueprintNode& setPlacements( + std::vector> placements); + + /// Register a new surface with the layer + /// @note This will clear any previously registered proto layer + /// @param surface Pointer to the surface tobe appended + /// @return Reference to this node for chaining + LayerBlueprintNode& addSurface(std::shared_ptr surface); + + /// Register a new placement with the layer + /// @note This will clear any previously registered proto layer + /// @param placement Pointer to be placement to be appended + /// @return Reference to this node for chaining + LayerBlueprintNode& addPlacement( + std::shared_ptr placement); + /// Access the registered surfaces. /// @return The registered surfaces - const std::vector>& surfaces() const; + std::vector> surfaces() const; /// Register a proto layer with the layer node. /// @param protoLayer The proto layer to register diff --git a/Core/include/Acts/Geometry/TrackingGeometry.hpp b/Core/include/Acts/Geometry/TrackingGeometry.hpp index bb777dd9c7a..c9ccb179885 100644 --- a/Core/include/Acts/Geometry/TrackingGeometry.hpp +++ b/Core/include/Acts/Geometry/TrackingGeometry.hpp @@ -219,6 +219,8 @@ class TrackingGeometry { // lookup containers std::unordered_map m_volumesById; std::unordered_map m_surfacesById; + using PlacementOwnPtr = TrackingVolume::PlacementOwnPtr; + std::vector m_placements; }; } // namespace Acts diff --git a/Core/include/Acts/Geometry/TrackingVolume.hpp b/Core/include/Acts/Geometry/TrackingVolume.hpp index cad61646049..65e4d43e343 100644 --- a/Core/include/Acts/Geometry/TrackingVolume.hpp +++ b/Core/include/Acts/Geometry/TrackingVolume.hpp @@ -51,7 +51,6 @@ class TrackingVolume; struct GeometryIdentifierHook; class Portal; class INavigationPolicy; - /// Interface types of the Gen1 geometry model /// @note This interface is being replaced, and is subject to removal /// @{ @@ -127,6 +126,18 @@ class TrackingVolume : public Volume { std::shared_ptr volbounds, const std::string& volumeName = "undefined"); + /// Constructor for an aligned container volumes where the tracking volume + /// also takes (temporary) ownership of the placement. This constructor is + /// only memory safe if the volume is appended to the tracking geometry tree + /// or if the placement does not own the placement + /// @param placement is the shared_ptr to the volume placement object + /// dynamically positioning the volume in space + /// @param volbounds is the description of the volume boundaries + /// @param volumeName is a string identifier + TrackingVolume(std::shared_ptr placement, + std::shared_ptr volBounds, + const std::string& volumeName = "undefined"); + /// Constructor for a container Volume /// - vacuum filled volume either as a for other tracking volumes /// @@ -339,7 +350,10 @@ class TrackingVolume : public Volume { using PortalRange = detail::TransformRange>>; - + /// Abrivation of the shared ptr variant holding the placements + using PlacementOwnPtr = + std::variant, + std::shared_ptr>; /// Return all portals registered under this tracking volume /// @return the range of portals PortalRange portals() const; @@ -371,7 +385,11 @@ class TrackingVolume : public Volume { /// Add a surface to this tracking volume /// @param surface The surface to add - void addSurface(std::shared_ptr surface); + /// @param placement Optional pointer to the surface placement associated with the surface + /// @note The volume takes shared ownership of the placement + void addSurface( + std::shared_ptr surface, + std::shared_ptr placement = nullptr); /// Add a child volume to this tracking volume /// @param volume The volume to add @@ -554,6 +572,12 @@ class TrackingVolume : public Volume { AppendOnlyNavigationStream& stream, const Logger& logger) const; + /// Pass over a (Volume / Surface) placement to share owner ship + /// with the volume + /// @param placement: Pointer to the placement to be managed by the + /// tracking volume + void cachePlacement(PlacementOwnPtr placement); + private: void connectDenseBoundarySurfaces( MutableTrackingVolumeVector& confinedDenseVolumes); @@ -570,6 +594,10 @@ class TrackingVolume : public Volume { /// @param envelope is the clearance between volume boundary and layer void synchronizeLayers(double envelope = 1.) const; + /// Return the garbage container into which the placements are pushed. If the + /// volume does not have a mother it's the volume itself otherwise the mother + std::vector& cachedPlacements(); + // the boundary surfaces std::vector m_boundarySurfaces; @@ -600,6 +628,7 @@ class TrackingVolume : public Volume { std::vector> m_volumes; std::vector> m_portals; std::vector> m_surfaces; + std::vector m_placements; std::unique_ptr m_navigationPolicy; diff --git a/Core/src/Geometry/LayerBlueprintNode.cpp b/Core/src/Geometry/LayerBlueprintNode.cpp index d538a345ecd..1ca98fb27db 100644 --- a/Core/src/Geometry/LayerBlueprintNode.cpp +++ b/Core/src/Geometry/LayerBlueprintNode.cpp @@ -23,7 +23,10 @@ struct LayerBlueprintNodeImpl { std::string m_name; - std::vector> m_surfaces{}; + using LayerNodePtr = std::variant, + std::shared_ptr>; + + std::vector m_nodes{}; /// If a proto layer is already given externally, this node will not perform /// sizing from surfaces @@ -57,21 +60,20 @@ const detail::LayerBlueprintNodeImpl& LayerBlueprintNode::impl() const { Volume& LayerBlueprintNode::build(const BlueprintOptions& options, const GeometryContext& gctx, const Logger& logger) { - if (impl().m_surfaces.empty()) { + if (impl().m_nodes.empty()) { ACTS_ERROR("LayerBlueprintNode: no surfaces provided"); throw std::invalid_argument("LayerBlueprintNode: no surfaces provided"); } ACTS_DEBUG(prefix() << "Building Layer " << name() << " from " - << impl().m_surfaces.size() << " surfaces"); + << impl().m_nodes.size() << " nodes"); ACTS_VERBOSE(prefix() << " -> layer type: " << impl().m_layerType); ACTS_VERBOSE(prefix() << " -> transform:\n" << impl().m_transform.matrix()); Extent extent; if (!impl().m_protoLayer.has_value()) { - impl().m_protoLayer.emplace(gctx, impl().m_surfaces, - impl().m_transform.inverse()); + impl().m_protoLayer.emplace(gctx, surfaces(), impl().m_transform.inverse()); ACTS_VERBOSE(prefix() << "Built proto layer: " << impl().m_protoLayer.value()); } else { @@ -86,10 +88,20 @@ Volume& LayerBlueprintNode::build(const BlueprintOptions& options, buildVolume(extent, logger); assert(m_volume != nullptr && "Volume not built from proto layer"); - for (auto& surface : impl().m_surfaces) { + for (auto& surface : surfaces()) { m_volume->addSurface(surface); } + auto visitor = overloaded{ + [](const std::shared_ptr&) { + + }, + [this](const std::shared_ptr& placement) { + m_volume->cachePlacement(placement); + }}; + for (auto& node : impl().m_nodes) { + std::visit(visitor, node); + } return StaticBlueprintNode::build(options, gctx, logger); } @@ -148,23 +160,73 @@ const std::string& LayerBlueprintNode::name() const { LayerBlueprintNode& LayerBlueprintNode::setSurfaces( std::vector> surfaces) { - impl().m_surfaces = std::move(surfaces); + impl().m_nodes.reserve(impl().m_nodes.size() + surfaces.size()); + for (auto& surface : surfaces) { + impl().m_nodes.emplace_back(std::move(surface)); + } impl().m_protoLayer.reset(); return *this; } -const std::vector>& LayerBlueprintNode::surfaces() - const { - return impl().m_surfaces; +LayerBlueprintNode& LayerBlueprintNode::setPlacements( + std::vector> placements) { + impl().m_nodes.reserve(impl().m_nodes.size() + placements.size()); + for (auto& placement : placements) { + impl().m_nodes.emplace_back(std::move(placement)); + } + impl().m_protoLayer.reset(); + + return *this; +} + +/// Register a new surface with the layer +/// @note This will clear any previously registered proto layer +/// @return Reference to this node for chaining +LayerBlueprintNode& LayerBlueprintNode::addSurface( + std::shared_ptr surface) { + impl().m_nodes.emplace_back(std::move(surface)); + return *this; +} + +/// Register a new placement with the layer +/// @note This will clear any previously registered proto layer +/// @return Reference to this node for chaining +LayerBlueprintNode& LayerBlueprintNode::addPlacement( + std::shared_ptr placement) { + impl().m_nodes.emplace_back(std::move(placement)); + return *this; +} + +std::vector> LayerBlueprintNode::surfaces() const { + std::vector> surfaces{}; + surfaces.reserve(impl().m_nodes.size()); + auto visitor = overloaded{ + [&surfaces](const std::shared_ptr& surface) { + surfaces.emplace_back(surface); + }, + [&surfaces](const std::shared_ptr& placement) { + surfaces.emplace_back(placement->surface().getSharedPtr()); + }}; + for (const auto& node : impl().m_nodes) { + std::visit(visitor, node); + } + auto nonUniqueRange = std::ranges::unique( + surfaces.begin(), surfaces.end(), + [](const std::shared_ptr& a, const std::shared_ptr& b) { + return a == b; + }); + surfaces.erase(nonUniqueRange.begin(), nonUniqueRange.end()); + + return surfaces; } LayerBlueprintNode& LayerBlueprintNode::setProtoLayer( std::optional protoLayer) { impl().m_protoLayer = std::move(protoLayer); - impl().m_surfaces.clear(); + impl().m_nodes.clear(); // also take ownership of the surfaces now for (auto& surface : impl().m_protoLayer.value().surfaces()) { - impl().m_surfaces.push_back(surface->getSharedPtr()); + impl().m_nodes.emplace_back(surface->getSharedPtr()); } return *this; } diff --git a/Core/src/Geometry/TrackingGeometry.cpp b/Core/src/Geometry/TrackingGeometry.cpp index b36b3f4297f..0655ddcf659 100644 --- a/Core/src/Geometry/TrackingGeometry.cpp +++ b/Core/src/Geometry/TrackingGeometry.cpp @@ -210,6 +210,11 @@ TrackingGeometry::TrackingGeometry( ACTS_DEBUG("Closing tracking geometry with Gen1 assignment"); Gen1GeometryClosureVisitor visitor{logger, materialDecorator, hook}; apply(visitor); + m_placements.insert( + m_placements.end(), + std::make_move_iterator(highestVolume->m_placements.begin()), + std::make_move_iterator(highestVolume->m_placements.end())); + highestVolume->m_placements.clear(); } GeometryIdMapVisitor mapVisitor{logger}; diff --git a/Core/src/Geometry/TrackingVolume.cpp b/Core/src/Geometry/TrackingVolume.cpp index 4a576835abd..056fbdf78ba 100644 --- a/Core/src/Geometry/TrackingVolume.cpp +++ b/Core/src/Geometry/TrackingVolume.cpp @@ -76,6 +76,16 @@ TrackingVolume::TrackingVolume(VolumePlacementBase& placement, m_navigationDelegate.connect<&INavigationPolicy::noopInitializeCandidates>(); } +TrackingVolume::TrackingVolume(std::shared_ptr placement, + std::shared_ptr volBounds, + const std::string& volumeName) + : TrackingVolume(*placement, std::move(volBounds), volumeName) { + if (placement == nullptr) { + throw std::invalid_argument("The passed placement must not be a nullptr"); + } + m_placements.emplace_back(placement); +} + TrackingVolume::~TrackingVolume() = default; TrackingVolume::TrackingVolume(TrackingVolume&&) noexcept = default; TrackingVolume& TrackingVolume::operator=(TrackingVolume&&) noexcept = default; @@ -562,10 +572,25 @@ TrackingVolume& TrackingVolume::addVolume( } volume->setMotherVolume(this); + // Take over the ownership of all placements hold + auto& placements = cachedPlacements(); + placements.insert(placements.end(), + std::make_move_iterator(volume->m_placements.begin()), + std::make_move_iterator(volume->m_placements.end())); + volume->m_placements.clear(); m_volumes.push_back(std::move(volume)); return *m_volumes.back(); } +void TrackingVolume::cachePlacement(PlacementOwnPtr placement) { + cachedPlacements().emplace_back(std::move(placement)); +} +std::vector& +TrackingVolume::cachedPlacements() { + return m_motherVolume == nullptr ? m_placements + : m_motherVolume->cachedPlacements(); +} + TrackingVolume::PortalRange TrackingVolume::portals() const { return PortalRange{m_portals}; } @@ -589,11 +614,16 @@ TrackingVolume::MutableSurfaceRange TrackingVolume::surfaces() { return MutableSurfaceRange{m_surfaces}; } -void TrackingVolume::addSurface(std::shared_ptr surface) { +void TrackingVolume::addSurface( + std::shared_ptr surface, + std::shared_ptr placement) { if (surface == nullptr) { throw std::invalid_argument("Surface is nullptr"); } m_surfaces.push_back(std::move(surface)); + if (placement != nullptr) { + cachePlacement(std::move(placement)); + } } void TrackingVolume::visualize(IVisualization3D& helper,