Skip to content

Commit

Permalink
refactor: Refactor AdaptiveGridTrackDensity (#2830)
Browse files Browse the repository at this point in the history
Sorry this got more radical then I anticipated

Summary of the changes:
- dynamic `spatialTrkGridSize` and `temporalTrkGridSize`
  - replaced it with a sigma scale and maximum window for space and time
- refactored the optional time handling
- truncated pair construction
- tried to simplify some of the density map handling e.g. default zero, no need to count
  • Loading branch information
andiwand authored Dec 18, 2023
1 parent 2dbf768 commit 858a48a
Show file tree
Hide file tree
Showing 11 changed files with 546 additions and 446 deletions.
Binary file modified CI/physmon/reference/performance_amvf_gridseeder_ttbar_hist.root
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

#pragma once

#include "Acts/Definitions/Algebra.hpp"
#include "Acts/EventData/TrackParameters.hpp"
#include "Acts/Utilities/Result.hpp"
#include "Acts/Vertexing/AdaptiveGridTrackDensity.hpp"
Expand Down Expand Up @@ -75,9 +74,6 @@ class AdaptiveGridDensityVertexFinder {
// Map from input track to corresponding track density map
std::unordered_map<const InputTrack_t*, DensityMap> trackDensities;

// Map to store bool if track has passed track selection or not
std::unordered_map<const InputTrack_t*, bool> trackSelectionMap;

// Store tracks that have been removed from track collection. These
// tracks will be removed from the main grid
std::vector<const InputTrack_t*> tracksToRemove;
Expand Down
71 changes: 32 additions & 39 deletions Core/include/Acts/Vertexing/AdaptiveGridDensityVertexFinder.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -14,72 +14,65 @@ auto Acts::AdaptiveGridDensityVertexFinder<vfitter_t>::find(
// Remove density contributions from tracks removed from track collection
if (m_cfg.cacheGridStateForTrackRemoval && state.isInitialized &&
!state.tracksToRemove.empty()) {
// Bool to check if removable tracks, that pass selection, still exist
bool couldRemoveTracks = false;
for (auto trk : state.tracksToRemove) {
if (!state.trackSelectionMap.at(trk)) {
auto it = state.trackDensities.find(trk);
if (it == state.trackDensities.end()) {
// Track was never added to grid, so cannot remove it
continue;
}
couldRemoveTracks = true;
auto trackDensityMap = state.trackDensities.at(trk);
m_cfg.gridDensity.subtractTrack(trackDensityMap, state.mainDensityMap);
}
if (!couldRemoveTracks) {
// No tracks were removed anymore
// Return empty seed, i.e. vertex at constraint position
// (Note: Upstream finder should check for this break condition)
std::vector<Vertex<InputTrack_t>> seedVec{vertexingOptions.constraint};
return seedVec;
m_cfg.gridDensity.subtractTrack(it->second, state.mainDensityMap);
}
} else {
state.mainDensityMap.clear();
state.mainDensityMap = DensityMap();
// Fill with track densities
for (auto trk : trackVector) {
const BoundTrackParameters& trkParams = m_extractParameters(*trk);
// Take only tracks that fulfill selection criteria
if (!doesPassTrackSelection(trkParams)) {
if (m_cfg.cacheGridStateForTrackRemoval) {
state.trackSelectionMap[trk] = false;
}
continue;
}
auto trackDensityMap =
m_cfg.gridDensity.addTrack(trkParams, state.mainDensityMap);
// Cache track density contribution to main grid if enabled
if (m_cfg.cacheGridStateForTrackRemoval) {
state.trackDensities[trk] = trackDensityMap;
state.trackSelectionMap[trk] = true;
state.trackDensities[trk] = std::move(trackDensityMap);
}
}
state.isInitialized = true;
}

if (state.mainDensityMap.empty()) {
// No tracks passed selection
// Return empty seed, i.e. vertex at constraint position
// (Note: Upstream finder should check for this break condition)
std::vector<Vertex<InputTrack_t>> seedVec{vertexingOptions.constraint};
return seedVec;
}

double z = 0;
double t = 0;
double zWidth = 0;
if (!state.mainDensityMap.empty()) {
if (!m_cfg.estimateSeedWidth) {
// Get z value of highest density bin
auto maxZTRes = m_cfg.gridDensity.getMaxZTPosition(state.mainDensityMap);

if (!maxZTRes.ok()) {
return maxZTRes.error();
}
z = (*maxZTRes).first;
t = (*maxZTRes).second;
} else {
// Get z value of highest density bin and width
auto maxZTResAndWidth =
m_cfg.gridDensity.getMaxZTPositionAndWidth(state.mainDensityMap);

if (!maxZTResAndWidth.ok()) {
return maxZTResAndWidth.error();
}
z = (*maxZTResAndWidth).first.first;
t = (*maxZTResAndWidth).first.second;
zWidth = (*maxZTResAndWidth).second;
if (!m_cfg.estimateSeedWidth) {
// Get z value of highest density bin
auto maxZTRes = m_cfg.gridDensity.getMaxZTPosition(state.mainDensityMap);

if (!maxZTRes.ok()) {
return maxZTRes.error();
}
z = (*maxZTRes).first;
t = (*maxZTRes).second;
} else {
// Get z value of highest density bin and width
auto maxZTResAndWidth =
m_cfg.gridDensity.getMaxZTPositionAndWidth(state.mainDensityMap);

if (!maxZTResAndWidth.ok()) {
return maxZTResAndWidth.error();
}
z = (*maxZTResAndWidth).first.first;
t = (*maxZTResAndWidth).first.second;
zWidth = (*maxZTResAndWidth).second;
}

// Construct output vertex, t will be 0 if temporalTrkGridSize == 1
Expand Down
208 changes: 119 additions & 89 deletions Core/include/Acts/Vertexing/AdaptiveGridTrackDensity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
#include "Acts/EventData/TrackParameters.hpp"
#include "Acts/Utilities/Result.hpp"

#include <unordered_map>

#include <boost/container/flat_map.hpp> // TODO use flat unordered map
#include <boost/functional/hash.hpp>

namespace Acts {
Expand All @@ -29,81 +28,65 @@ namespace Acts {
/// Unlike in the GaussianGridTrackDensity, the overall density map
/// grows adaptively when tracks densities are added to the grid.
class AdaptiveGridTrackDensity {
// Assert odd spatial and temporal track grid size

public:
// The first (second) integer indicates the bin's z (t) position
using Bin = std::pair<int, int>;
// Mapping between bins and track densities
using DensityMap = std::unordered_map<Bin, float, boost::hash<Bin>>;
// Coordinates in the z-t plane; the t value will be set to 0 if time
// vertex seeding is disabled
using ZTPosition = std::pair<float, float>;
// z-t position of a maximum and its width
using ZTPositionAndWidth = std::pair<ZTPosition, float>;
/// The first (second) integer indicates the bin's z (t) position
using Bin = std::pair<std::int32_t, std::int32_t>;
/// Mapping between bins and track densities
using DensityMap = boost::container::flat_map<Bin, float>;
/// Coordinates in the z-t plane; the t value will be set to 0 if time
/// vertex seeding is disabled
using ZTPosition = std::pair<double, double>;
/// z-t position of a maximum and its width
using ZTPositionAndWidth = std::pair<ZTPosition, double>;
/// Optional grid size range
using GridSizeRange =
std::pair<std::optional<std::uint32_t>, std::optional<std::uint32_t>>;

/// The configuration struct
struct Config {
/// Default constructor
Config() = default;

// In total, a track is represented by a grid of size
// spatialTrkGridSize * temporalTrkGridSize
// Number of bins per track in z direction
unsigned int spatialTrkGridSize = 15;

// Spatial extent of a bin in d0 and z0 direction, should always be set to a
// positive value
float spatialBinExtent = 0.; // mm

// Number of bins per track in t direction
unsigned int temporalTrkGridSize = 1;

// Temporal extent of a bin, should be set to 0 if time vertex seeding is
// disabled (i.e., if temporalTrkGridSize = 1)
float temporalBinExtent = 0.; // mm

// Do NOT use just the z-bin with the highest
// track density, but instead check (up to)
// first three density maxima (only those that have
// a maximum relative deviation of 'relativeDensityDev'
// from the main maximum) and take the z-bin of the
// maximum with the highest surrounding density sum
/// Spatial extent of a bin in d0 and z0 direction, should always be set to
/// a positive value
double spatialBinExtent = 15 * UnitConstants::um;

/// Number of standard deviations that the grid covers in z direction
double nSpatialTrkSigmas = 3.0;

/// Temporal extent of a bin, not used if useTime == true
double temporalBinExtent = 19 * UnitConstants::mm;

/// Number of standard deviations that the grid covers in t direction, not
/// used if useTime == true
double nTemporalTrkSigmas = 3.0;

/// Spatial window for filling the density map
std::pair<double, double> spatialWindow = {-250 * UnitConstants::mm,
250 * UnitConstants::mm};
/// Temporal window for filling the density map
std::pair<double, double> temporalWindow = {-10 * UnitConstants::ns,
10 * UnitConstants::ns};

/// Optional minimal and maximal number of bins in z direction
GridSizeRange spatialTrkGridSizeRange = {std::nullopt, std::nullopt};
/// Optional minimal and maximal number of bins in time direction
GridSizeRange temporalTrkGridSizeRange = {std::nullopt, std::nullopt};

bool useTime = false;

/// Do NOT use just the z-bin with the highest
/// track density, but instead check (up to)
/// first three density maxima (only those that have
/// a maximum relative deviation of 'relativeDensityDev'
/// from the main maximum) and take the z-bin of the
/// maximum with the highest surrounding density sum
bool useHighestSumZPosition = false;

// The maximum relative density deviation from the main
// maximum to consider the second and third maximum for
// the highest-sum approach from above
float maxRelativeDensityDev = 0.01;
/// The maximum relative density deviation from the main
/// maximum to consider the second and third maximum for
/// the highest-sum approach from above
double maxRelativeDensityDev = 0.01;
};

AdaptiveGridTrackDensity(const Config& cfg) : m_cfg(cfg) {
// Check that spatial and temporal track grid size are odd
if (!bool(m_cfg.spatialTrkGridSize % 2) ||
!bool(m_cfg.temporalTrkGridSize % 2)) {
throw std::invalid_argument(
"Please choose an odd spatialTrkGridSize and temporalTrkGridSize.");
}
}

/// @brief Calculates the bin center from the bin number
/// @param bin Bin number
/// @param binExtent Bin extent
/// @return Bin center
static float getBinCenter(int bin, float binExtent);

/// @brief Calculates the bin number corresponding to a d, z, or time value
/// @param value d, z, or time value
/// @param binExtent Bin extent
/// @return Bin number
static int getBin(float value, float binExtent);

/// @brief Finds the maximum density of a DensityMap
/// @param densityMap Map between bins and corresponding density
/// values
/// @return Iterator of the map entry with the highest density
DensityMap::const_iterator highestDensityEntry(
const DensityMap& densityMap) const;
AdaptiveGridTrackDensity(const Config& cfg);

/// @brief Returns the z and t coordinate of maximum (surrounding)
/// track density
Expand Down Expand Up @@ -145,7 +128,68 @@ class AdaptiveGridTrackDensity {
void subtractTrack(const DensityMap& trackDensityMap,
DensityMap& mainDensityMap) const;

// TODO this should not be public
/// @brief Calculates the bin center from the bin number
/// @param bin Bin number
/// @param binExtent Bin extent
/// @return Bin center
static double getBinCenter(std::int32_t bin, double binExtent);

private:
Config m_cfg;

/// @brief Calculates the bin number corresponding to a d, z, or time value
/// @param value d, z, or time value
/// @param binExtent Bin extent
/// @return Bin number
static std::int32_t getBin(double value, double binExtent);

/// @brief Calculates the grid size in z or time direction
/// @param sigma Standard deviation of the track density
/// @param trkSigmas Number of standard deviations that the grid
/// covers in z or time direction
/// @param binExtent Bin extent
/// @param trkGridSizeRange Optional minimal and maximal number of bins
/// in z or time direction
/// @return Grid size
static std::uint32_t getTrkGridSize(double sigma, double trkSigmas,
double binExtent,
const GridSizeRange& trkGridSizeRange);

/// @brief Calculates the bin number corresponding to a z value
/// @param value z value
/// @return Bin number
std::int32_t getSpatialBin(double value) const;
/// @brief Calculates the bin number corresponding to a time value
/// @param value Time value
/// @return Bin number
std::int32_t getTemporalBin(double value) const;

/// @brief Calculates the spatial bin center corresponding to a bin number
/// @param bin Bin number
/// @return Bin center
double getSpatialBinCenter(std::int32_t bin) const;
/// @brief Calculates the temporal bin center corresponding to a bin number
/// @param bin Bin number
/// @return Bin center
double getTemporalBinCenter(std::int32_t bin) const;

/// @brief Calculates the grid size in z direction
/// @param sigma Standard deviation of the track density
/// @return Grid size
std::uint32_t getSpatialTrkGridSize(double sigma) const;
/// @brief Calculates the grid size in time direction
/// @param sigma Standard deviation of the track density
/// @return Grid size
std::uint32_t getTemporalTrkGridSize(double sigma) const;

/// @brief Finds the maximum density of a DensityMap
/// @param densityMap Map between bins and corresponding density
/// values
/// @return Iterator of the map entry with the highest density
DensityMap::const_iterator highestDensityEntry(
const DensityMap& densityMap) const;

/// @brief Function that creates a track density map, i.e., a map from bins
/// to the corresponding density values for a single track.
///
Expand All @@ -155,7 +199,9 @@ class AdaptiveGridTrackDensity {
/// @param cov 3x3 impact parameter covariance matrix
DensityMap createTrackGrid(const Acts::Vector3& impactParams,
const Bin& centralBin,
const Acts::SquareMatrix3& cov) const;
const Acts::SquareMatrix3& cov,
std::uint32_t spatialTrkGridSize,
std::uint32_t temporalTrkGridSize) const;

/// @brief Function that estimates the seed width in z direction based
/// on the full width at half maximum (FWHM) of the maximum density peak
Expand All @@ -167,22 +213,8 @@ class AdaptiveGridTrackDensity {
/// @param maxZT z-t position of the maximum density value
///
/// @return The width
Result<float> estimateSeedWidth(const DensityMap& densityMap,
const ZTPosition& maxZT) const;

/// @brief Helper to retrieve values of an nDim-dimensional normal
/// distribution
/// @note The constant prefactor (2 * pi)^(- nDim / 2) is discarded
///
/// @param args Coordinates where the Gaussian should be evaluated
/// @note args must be in a coordinate system with origin at the mean
/// values of the Gaussian
/// @param cov Covariance matrix
///
/// @return Multivariate Gaussian evaluated at args
template <unsigned int nDim>
static float multivariateGaussian(const Acts::ActsVector<nDim>& args,
const Acts::ActsSquareMatrix<nDim>& cov);
Result<double> estimateSeedWidth(const DensityMap& densityMap,
const ZTPosition& maxZT) const;

/// @brief Checks (up to) first three density maxima that have a
/// maximum relative deviation of 'relativeDensityDev' from the
Expand All @@ -201,9 +233,7 @@ class AdaptiveGridTrackDensity {
/// @param bin Bin whose neighbors in z we want to sum up
///
/// @return The density sum
float getDensitySum(const DensityMap& densityMap, const Bin& bin) const;

Config m_cfg;
double getDensitySum(const DensityMap& densityMap, const Bin& bin) const;
};

} // namespace Acts
Loading

0 comments on commit 858a48a

Please sign in to comment.