Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Generalizing telescope seeding interface #3725

Merged
merged 13 commits into from
Oct 21, 2024
253 changes: 96 additions & 157 deletions Core/include/Acts/Seeding/PathSeeder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,18 @@
#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 {

template <typename grid_t>
concept SourceLinkGrid =
std::same_as<typename grid_t::value_type, std::vector<Acts::SourceLink>>;
}
ssdetlab marked this conversation as resolved.
Show resolved Hide resolved

namespace Acts::Experimental {
ssdetlab marked this conversation as resolved.
Show resolved Hide resolved

Expand All @@ -23,7 +33,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 +49,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 +93,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 +113,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 <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);
for (auto& refGeoId : m_cfg.refLayerIds) {
auto refGrid = sourceLinkGridLookup.at(refGeoId);

// 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);

// 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::Experimental
Loading
Loading