Skip to content

Commit

Permalink
refactor: Generalizing telescope seeding interface (#3725)
Browse files Browse the repository at this point in the history
Cleaning up and generalizing the interface of the `PathSeeder`. Adding a concept to constrain the grid type during the instantiation.
  • Loading branch information
ssdetlab authored Oct 21, 2024
1 parent 7b71164 commit 7559227
Show file tree
Hide file tree
Showing 3 changed files with 215 additions and 271 deletions.
248 changes: 90 additions & 158 deletions Core/include/Acts/Seeding/PathSeeder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
#pragma once

#include "Acts/EventData/SourceLink.hpp"
#include "Acts/EventData/TrackParameters.hpp"
#include "Acts/Seeding/detail/UtilityFunctions.hpp"
#include "Acts/Surfaces/Surface.hpp"
#include "Acts/Utilities/Delegate.hpp"
#include "Acts/Utilities/GridIterator.hpp"

namespace Acts::Experimental {
namespace Acts {

/// @brief Seeding algorigthm that extracts
/// the IP parameters and sorts the source links
Expand All @@ -23,7 +26,7 @@ namespace Acts::Experimental {
/// source links -- as follows: First the source links
/// are sorted into a user-defined grid. Then, iteration over the source links
/// is performed. If a source link is attached to a surface that is
/// in the first tracking layer, as defined by the user, the IP parameters
/// in the reference tracking layer, as defined by the user, the IP parameters
/// are estimated and the tracking layers are intersected to construct the
/// core of the "Path". The source links in the subsequent layers are then
/// added to the seed if they lie within the path width of the core.
Expand All @@ -39,84 +42,34 @@ namespace Acts::Experimental {
///
/// @note Handling of the rotated surfaces has to happen
/// in the user-defined delegate functions.

template <typename grid_t>
class PathSeeder {
public:
using GridType = grid_t;

/// @brief The seed struct
///
/// The seed struct contains the IP parameters
/// and the source links that are associated with
/// the seed.
struct Seed {
/// The IP momentum magnitude
ActsScalar ipP;

/// The IP momentum direction
Vector3 ipDir;

/// The IP vertex position
Vector3 ipVertex;

/// The source links associated with the seed
std::vector<SourceLink> sourceLinks;

Seed() = delete;
Seed(ActsScalar ipPmag, Vector3 ipPdir, Vector3 ipPos,
std::vector<SourceLink> sls)
: ipP(ipPmag),
ipDir(std::move(ipPdir)),
ipVertex(std::move(ipPos)),
sourceLinks(std::move(sls)) {};
};

/// @brief Delegate to provide the relevant grid
/// filled with source links for the given geometry
/// member
///
/// @arg The geometry identifier to use
///
/// @return The grid filled with source links
using SourceLinkGridLookup = Delegate<GridType(const GeometryIdentifier&)>;
using PathSeed =
std::pair<CurvilinearTrackParameters, std::vector<SourceLink>>;

/// @brief Delegate to estimate the IP parameters
/// and the momentum direction at the first tracking layer
///
/// @arg The geometry context to use
/// @arg The global position of the pivot source link
///
/// @return Particle charge, the IP momentum magnitude, the IP vertex position,
/// the IP momentum direction, the momentum direction at the
/// first tracking layer
using TrackEstimator =
Delegate<std::tuple<ActsScalar, ActsScalar, Vector3, Vector3, Vector3>(
const GeometryContext&, const Vector3&)>;

/// @brief Delegate to transform the source link to the
/// appropriate global frame.
/// and the momentum direction at the reference tracking layer
///
/// @arg The geometry context to use
/// @arg The source link to calibrate
/// @arg Geometry context to use
/// @arg Pivot source link
///
/// @return The global position of the source link measurement
using SourceLinkCalibrator =
Delegate<Vector3(const GeometryContext&, const SourceLink&)>;
/// @return Pair of the track parameters at the IP and
/// the reference tracking layer
using TrackEstimator = Delegate<
std::pair<CurvilinearTrackParameters, CurvilinearTrackParameters>(
const GeometryContext&, const SourceLink&)>;

/// @brief Delegate to find the intersections for the given pivot
/// source link
///
/// @arg The geometry context to use
/// @arg The global position of the pivot source link
/// @arg The momentum direction of the pivot source link
/// at the first tracking layer
/// @arg The IP momentum magnitude
/// @arg The particle charge
/// @arg Track parameters at the reference tracking layer
///
/// @return Vector of pairs of the geometry identifier
/// and the local intersection point
using IntersectionLookup =
Delegate<std::vector<std::pair<GeometryIdentifier, Vector3>>(
const GeometryContext&, const Vector3&, const Vector3&,
const ActsScalar&, const ActsScalar&)>;
Delegate<std::vector<std::pair<GeometryIdentifier, Vector2>>(
const GeometryContext&, const CurvilinearTrackParameters&)>;

/// @brief Delegate to provide the path width around
/// the intersection point to pull the source links
Expand All @@ -133,24 +86,18 @@ class PathSeeder {

/// @brief The nested configuration struct
struct Config {
/// Binned SourceLink provider
SourceLinkGridLookup sourceLinkGridLookup;
/// Parameters estimator
TrackEstimator trackEstimator;
/// SourceLink calibrator
SourceLinkCalibrator sourceLinkCalibrator;
/// Intersection finder
IntersectionLookup intersectionFinder;
/// Path width provider
PathWidthLookup pathWidthProvider;
/// First layer extent
Extent firstLayerExtent;
/// Direction of the telescope extent
BinningValue orientation = BinningValue::binX;
/// Reference layer IDs
std::vector<GeometryIdentifier> refLayerIds;
};

/// @brief Constructor
PathSeeder(const Config& config) : m_cfg(std::move(config)) {};
PathSeeder(const Config& config) : m_cfg(config) {};

/// @brief Destructor
~PathSeeder() = default;
Expand All @@ -159,101 +106,86 @@ class PathSeeder {
/// sort the source links into the seeds
///
/// @param gctx The geometry context
/// @param sourceLinks The source links to seed
/// @param sourceLinkGridLookup The lookup table for the source links
/// @param seedCollection The collection of seeds to fill
///
/// @return The vector of seeds
std::vector<Seed> getSeeds(const GeometryContext& gctx,
const std::vector<SourceLink>& sourceLinks) const {
// Get plane of the telescope
// sensitive surfaces
int bin0 = static_cast<int>(BinningValue::binX);
int bin1 = static_cast<int>(BinningValue::binY);
if (m_cfg.orientation == BinningValue::binX) {
bin0 = static_cast<int>(BinningValue::binY);
bin1 = static_cast<int>(BinningValue::binZ);
} else if (m_cfg.orientation == BinningValue::binY) {
bin0 = static_cast<int>(BinningValue::binX);
bin1 = static_cast<int>(BinningValue::binZ);
}

template <Acts::detail::SourceLinkGrid grid_t, typename container_t>
void findSeeds(const GeometryContext& gctx,
const std::unordered_map<GeometryIdentifier, grid_t>&
sourceLinkGridLookup,
container_t& seedCollection) const {
// Create the seeds
std::vector<Seed> seeds;
for (const auto& sl : sourceLinks) {
Vector3 globalPos = m_cfg.sourceLinkCalibrator(gctx, sl);

// Check if the hit is in the
// first tracking layer
if (!m_cfg.firstLayerExtent.contains(globalPos)) {
continue;
}

// Get the IP parameters
auto [q, ipP, ipVertex, ipDir, flDir] =
m_cfg.trackEstimator(gctx, globalPos);

// Intersect with the surfaces
std::vector<std::pair<GeometryIdentifier, Vector3>> intersections =
m_cfg.intersectionFinder(gctx, globalPos, flDir, ipP, q);

// Continue if no intersections
if (intersections.empty()) {
continue;
}
// Vector to store the source links
std::vector<SourceLink> seedSourceLinks;

// Store the pivot source link
seedSourceLinks.push_back(sl);
for (auto& refGeoId : m_cfg.refLayerIds) {
auto refGrid = sourceLinkGridLookup.at(refGeoId);

// Iterate over the intersections
// and get the source links
// in the subsequent layers
for (auto& [geoId, refPoint] : intersections) {
// Get the path width
auto [pathWidth0, pathWidth1] = m_cfg.pathWidthProvider(gctx, geoId);
for (auto it = refGrid.begin(); it != refGrid.end(); it++) {
std::vector<SourceLink> pivotSourceLinks = *it;

// Get the bounds of the path
ActsScalar top0 = refPoint[bin0] + pathWidth0;
ActsScalar bot0 = refPoint[bin0] - pathWidth0;
ActsScalar top1 = refPoint[bin1] + pathWidth1;
ActsScalar bot1 = refPoint[bin1] - pathWidth1;
for (const auto& pivot : pivotSourceLinks) {
// Get the IP parameters
auto [ipParameters, refLayerParameters] =
m_cfg.trackEstimator(gctx, pivot);

// Get the lookup table for the source links
auto grid = m_cfg.sourceLinkGridLookup(geoId);
// Intersect with the surfaces
std::vector<std::pair<GeometryIdentifier, Vector2>> intersections =
m_cfg.intersectionFinder(gctx, refLayerParameters);

// Get the range of bins to search for source links
auto botLeftBin = grid.localBinsFromPosition(Vector2(bot0, bot1));
auto topRightBin = grid.localBinsFromPosition(Vector2(top0, top1));

// Get the source links from the lookup table
// by iterating over the bin ranges
auto currentBin = botLeftBin;
while (currentBin.at(1) <= topRightBin.at(1)) {
while (currentBin.at(0) <= topRightBin.at(0)) {
auto sourceLinksToAdd = grid.atLocalBins(currentBin);
// Continue if no intersections
if (intersections.empty()) {
continue;
}

seedSourceLinks.insert(seedSourceLinks.end(),
sourceLinksToAdd.begin(),
sourceLinksToAdd.end());
currentBin.at(0)++;
// Iterate over the intersections
// and get the source links
// in the subsequent layers
std::vector<SourceLink> seedSourceLinks;
for (auto& [geoId, refPoint] : intersections) {
// Get the path width
auto [pathWidth0, pathWidth1] =
m_cfg.pathWidthProvider(gctx, geoId);

// Get the bounds of the path
ActsScalar top0 = refPoint[0] + pathWidth0;
ActsScalar bot0 = refPoint[0] - pathWidth0;
ActsScalar top1 = refPoint[1] + pathWidth1;
ActsScalar bot1 = refPoint[1] - pathWidth1;

// Get the lookup table for the source links
auto grid = sourceLinkGridLookup.at(geoId);

// Get the range of bins to search for source links
auto botLeftBin = grid.localBinsFromPosition(Vector2(bot0, bot1));
auto topRightBin = grid.localBinsFromPosition(Vector2(top0, top1));

// Get the source links from the lookup table
// by iterating over the bin ranges
auto currentBin = botLeftBin;
while (currentBin.at(1) <= topRightBin.at(1)) {
while (currentBin.at(0) <= topRightBin.at(0)) {
auto sourceLinksToAdd = grid.atLocalBins(currentBin);

seedSourceLinks.insert(seedSourceLinks.end(),
sourceLinksToAdd.begin(),
sourceLinksToAdd.end());

currentBin.at(0)++;
}
currentBin.at(1)++;
currentBin.at(0) = botLeftBin.at(0);
}
}
currentBin.at(1)++;
currentBin.at(0) = botLeftBin.at(0);
PathSeed seed = {ipParameters, seedSourceLinks};

// Add the seed to the collection
Acts::detail::pushBackOrInsertAtEnd(seedCollection, seed);
}
}

// Store the IP parameters and
// add the source links to the seed
Seed seed{ipP, ipDir, ipVertex, seedSourceLinks};

// Add the seed to the list
seeds.push_back(seed);
}
return seeds;
};
}

private:
Config m_cfg;
};

} // namespace Acts::Experimental
} // namespace Acts
6 changes: 6 additions & 0 deletions Core/include/Acts/Seeding/detail/UtilityFunctions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#pragma once

#include "Acts/EventData/SourceLink.hpp"

#include <ranges>

namespace Acts::detail {
Expand All @@ -29,6 +31,10 @@ concept isCollectionThatSupportsInsert =
coll.insert(std::ranges::end(coll), val);
};

template <typename grid_t>
concept SourceLinkGrid =
std::same_as<typename grid_t::value_type, std::vector<Acts::SourceLink>>;

// Define some functions
template <Acts::detail::isCollectionThatSupportsPushBack storage_t,
typename value_t>
Expand Down
Loading

0 comments on commit 7559227

Please sign in to comment.