Skip to content

Commit

Permalink
feat: add useTime to AMVFinder + python binding (#2721)
Browse files Browse the repository at this point in the history
Enables time seeding and time impact point estimation for `AMVF (+grid seeder) seeded`!

For  `AMVF (+grid seeder) ttbar` the performance is deteriorating because the parameters of `AdaptiveGridDensityVertexFinder` were tuned for  `AMVF (+grid seeder) seeded`. The parameters for ttbar will be tuned once #2745 went in (at the moment, the grid seeder is templated to the grid size so we can't adapt these parameters at run time).

In the following, we will discuss the physmon for  `AMVF (+grid seeder) seeded`:

We get some sensible pulls for the vertex time:
![image](https://github.com/acts-project/acts/assets/72298366/a04db989-f19a-432c-a923-32ee7af8159f)

Also, the vertex time residual looks good:
![image](https://github.com/acts-project/acts/assets/72298366/153294d5-591e-4570-9b1f-c51b9b63b692)

Using the additional coordinate we are able to resolve more vertices:
![image](https://github.com/acts-project/acts/assets/72298366/b5d7d6a6-4d42-4e45-bb98-019bfc68ac72)
At the same time, we don't overshoot (i.e., reconstruct more vertices than there are) as this plot nicely shows.

Finally, we are able to better resolve which track corresponds to which vertex:
![image](https://github.com/acts-project/acts/assets/72298366/580b46c4-ac34-4670-b9d6-0f7db3dcbb91)

Some remarks:
Even though we reconstruct more vertices, the number of entries in the histogram of the vertex covariance seems to decrease: 
![image](https://github.com/acts-project/acts/assets/72298366/cc798708-bbf3-4f4c-b4a8-1acda0d03ae4)
However, this is not actually the case: the tail of the monitored distribution just gets longer.

For higher pile-ups, we expect the improvement to be even more significant.
  • Loading branch information
felix-russo authored Dec 7, 2023
1 parent 5cc42d2 commit 0d1e675
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 29 deletions.
Binary file not shown.
Binary file modified CI/physmon/reference/performance_amvf_gridseeder_ttbar_hist.root
Binary file not shown.
11 changes: 9 additions & 2 deletions CI/physmon/workflows/physmon_ckf_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,17 @@ def run_ckf_tracking(truthSmearedSeeded, truthEstimatedSeeded, label):
)
)

# Choosing a seeder only has an effect on VertexFinder.AMVF. For
# VertexFinder.IVF we always use acts.VertexSeedFinder.GaussianSeeder
# (Python binding is not implemented).
# Setting useTime also only has an effect on VertexFinder.AMVF due to
# the same reason.
addVertexFitting(
s,
setup.field,
trackParameters="trackParameters",
outputProtoVertices="ivf_protovertices",
outputVertices="ivf_fittedVertices",
seeder=acts.VertexSeedFinder.GaussianSeeder,
vertexFinder=VertexFinder.Iterative,
outputDirRoot=tp / "ivf",
)
Expand All @@ -162,12 +166,14 @@ def run_ckf_tracking(truthSmearedSeeded, truthEstimatedSeeded, label):
outputProtoVertices="amvf_protovertices",
outputVertices="amvf_fittedVertices",
seeder=acts.VertexSeedFinder.GaussianSeeder,
useTime=False, # Time seeding not implemented for the Gaussian seeder
vertexFinder=VertexFinder.AMVF,
outputDirRoot=tp / "amvf",
)

# Use the adaptive grid vertex seeder in combination with the AMVF
# To avoid having too many physmon cases, we only do this for the label "seeded"
# To avoid having too many physmon cases, we only do this for the label
# "seeded"
if label == "seeded":
addVertexFitting(
s,
Expand All @@ -176,6 +182,7 @@ def run_ckf_tracking(truthSmearedSeeded, truthEstimatedSeeded, label):
outputProtoVertices="amvf_gridseeder_protovertices",
outputVertices="amvf_gridseeder_fittedVertices",
seeder=acts.VertexSeedFinder.AdaptiveGridSeeder,
useTime=True,
vertexFinder=VertexFinder.AMVF,
outputDirRoot=tp / "amvf_gridseeder",
)
Expand Down
10 changes: 8 additions & 2 deletions Core/include/Acts/Vertexing/AdaptiveMultiVertexFinder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,10 @@ class AdaptiveMultiVertexFinder {
// consider a lot of tracks which just slow down the fit.
double tracksMaxZinterval = 3. * Acts::UnitConstants::mm;

// Maximum allowed significance of track position to vertex seed
// to consider track as compatible track for vertex fit
// Maximum allowed significance of track position to vertex seed to consider
// track as compatible to vertex. If useTime is set to true, the time
// coordinate also contributes to the significance and tracksMaxSignificance
// needs to be increased.
double tracksMaxSignificance = 5.;

// Max chi2 value for which tracks are considered compatible with
Expand Down Expand Up @@ -157,6 +159,10 @@ class AdaptiveMultiVertexFinder {
// So definitely consider setting this to true.
bool useVertexCovForIPEstimation = false;

// Use time information when assigning tracks to vertices. If this is set to
// true, useTime of the vertex fitter configuration should also be set to
// true, and time seeding should be enabled.
bool useTime = false;
}; // Config struct

/// State struct for fulfilling interface
Expand Down
54 changes: 35 additions & 19 deletions Core/include/Acts/Vertexing/AdaptiveMultiVertexFinder.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -208,17 +208,25 @@ auto Acts::AdaptiveMultiVertexFinder<vfitter_t, sfinder_t>::getIPSignificance(

auto estRes = m_cfg.ipEstimator.getImpactParameters(
m_extractParameters(*track), newVtx, vertexingOptions.geoContext,
vertexingOptions.magFieldContext);
vertexingOptions.magFieldContext, m_cfg.useTime);
if (!estRes.ok()) {
return estRes.error();
}

ImpactParametersAndSigma ipas = *estRes;

// TODO: throw error when encountering negative standard deviations
double chi2Time = 0;
if (m_cfg.useTime) {
if (ipas.sigmaDeltaT.value() > 0) {
chi2Time = std::pow(ipas.deltaT.value() / ipas.sigmaDeltaT.value(), 2);
}
}

double significance = 0.;
if (ipas.sigmaD0 > 0 && ipas.sigmaZ0 > 0) {
significance = std::sqrt(std::pow(ipas.d0 / ipas.sigmaD0, 2) +
std::pow(ipas.z0 / ipas.sigmaZ0, 2));
std::pow(ipas.z0 / ipas.sigmaZ0, 2) + chi2Time);
}

return significance;
Expand Down Expand Up @@ -507,39 +515,47 @@ auto Acts::AdaptiveMultiVertexFinder<vfitter_t, sfinder_t>::isMergedVertex(
const std::vector<Vertex<InputTrack_t>*>& allVertices) const -> bool {
const Vector4& candidatePos = vtx.fullPosition();
const SquareMatrix4& candidateCov = vtx.fullCovariance();
const double candidateZPos = candidatePos[eZ];
const double candidateZCov = candidateCov(eZ, eZ);

for (const auto otherVtx : allVertices) {
if (&vtx == otherVtx) {
continue;
}
const Vector4& otherPos = otherVtx->fullPosition();
const SquareMatrix4& otherCov = otherVtx->fullCovariance();
const double otherZPos = otherPos[eZ];
const double otherZCov = otherCov(eZ, eZ);

const Vector4 deltaPos = otherPos - candidatePos;
const double deltaZPos = otherZPos - candidateZPos;
const double sumCovZ = otherZCov + candidateZCov;

double significance = 0;
if (!m_cfg.do3dSplitting) {
if (sumCovZ <= 0) {
const double deltaZPos = otherPos[eZ] - candidatePos[eZ];
const double sumVarZ = otherCov(eZ, eZ) + candidateCov(eZ, eZ);
if (sumVarZ <= 0) {
// TODO FIXME this should never happen
continue;
}
// Use only z significance
significance = std::abs(deltaZPos) / std::sqrt(sumCovZ);
significance = std::abs(deltaZPos) / std::sqrt(sumVarZ);
} else {
// Use full 3d information for significance
SquareMatrix4 sumCov = candidateCov + otherCov;
auto sumCovInverse = safeInverse(sumCov);
if (!sumCovInverse) {
// TODO FIXME this should never happen
continue;
if (m_cfg.useTime) {
// Use 4D information for significance
const Vector4 deltaPos = otherPos - candidatePos;
SquareMatrix4 sumCov = candidateCov + otherCov;
auto sumCovInverse = safeInverse(sumCov);
if (!sumCovInverse) {
// TODO FIXME this should never happen
continue;
}
significance = std::sqrt(deltaPos.dot(*sumCovInverse * deltaPos));
} else {
// Use 3D information for significance
const Vector3 deltaPos = otherPos.head<3>() - candidatePos.head<3>();
SquareMatrix3 sumCov =
candidateCov.topLeftCorner<3, 3>() + otherCov.topLeftCorner<3, 3>();
auto sumCovInverse = safeInverse(sumCov);
if (!sumCovInverse) {
// TODO FIXME this should never happen
continue;
}
significance = std::sqrt(deltaPos.dot(*sumCovInverse * deltaPos));
}
significance = std::sqrt(deltaPos.dot(*sumCovInverse * deltaPos));
}
if (significance < m_cfg.maxMergeVertexSignificance) {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class AdaptiveMultiVertexFinderAlgorithm final : public IAlgorithm {
std::string outputVertices = "vertices";
/// Enum member determining the choice of the vertex seed finder
SeedFinder seedFinder;
/// Use time information in vertex seeder, finder, and fitter
bool useTime = false;
/// The magnetic field
std::shared_ptr<Acts::MagneticFieldProvider> bField;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ ActsExamples::AdaptiveMultiVertexFinderAlgorithm::execute(
Seeder seedFinder;
return executeAfterSeederChoice<Seeder, Finder>(ctx, seedFinder);
} else if (m_cfg.seedFinder == SeedFinder::AdaptiveGridSeeder) {
using Seeder = Acts::AdaptiveGridDensityVertexFinder<109, 1, Fitter>;
using Seeder = Acts::AdaptiveGridDensityVertexFinder<9, 5, Fitter>;
using Finder = Acts::AdaptiveMultiVertexFinder<Fitter, Seeder>;
// The seeder config argument corresponds to the bin size in mm
Seeder::Config seederConfig(0.05);
Seeder::Config seederConfig(0.015, 19.);
Seeder seedFinder(seederConfig);
return executeAfterSeederChoice<Seeder, Finder>(ctx, seedFinder);
} else {
Expand Down Expand Up @@ -105,6 +105,7 @@ ActsExamples::AdaptiveMultiVertexFinderAlgorithm::executeAfterSeederChoice(
fitterCfg.annealingTool = annealingUtility;
fitterCfg.minWeight = 0.001;
fitterCfg.doSmoothing = true;
fitterCfg.useTime = m_cfg.useTime;
Fitter fitter(std::move(fitterCfg),
logger().cloneWithSuffix("AdaptiveMultiVertexFitter"));

Expand All @@ -114,6 +115,21 @@ ActsExamples::AdaptiveMultiVertexFinderAlgorithm::executeAfterSeederChoice(
finderConfig.looseConstrValue = 1e2;
finderConfig.tracksMaxZinterval = 1. * Acts::UnitConstants::mm;
finderConfig.maxIterations = 200;
finderConfig.useTime = m_cfg.useTime;
if (m_cfg.useTime) {
// When using time, we have an extra contribution to the chi2 by the time
// coordinate. We thus need to increase tracksMaxSignificance (i.e., the
// maximum chi2 that a track can have to be associated with a vertex).
finderConfig.tracksMaxSignificance = 7.5;
// Check if vertices are merged in space and time
// TODO rename do3dSplitting -> doFullSplitting
finderConfig.do3dSplitting = true;
// Reset the maximum significance that two vertices can have before they are
// considered as merged. The default value 3 is tuned for comparing the
// vertices' z-coordinates. Since we consider 4 dimensions here, we need to
// multiply the value by 4 and thus we set it to 3 * 4 = 12.
finderConfig.maxMergeVertexSignificance = 12.;
}

// Instantiate the finder
Finder finder(std::move(finderConfig), logger().clone());
Expand Down
14 changes: 11 additions & 3 deletions Examples/Python/python/acts/examples/reconstruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -1609,6 +1609,7 @@ def addVertexFitting(
outputVertices: str = "fittedVertices",
seeder: Optional[acts.VertexSeedFinder] = acts.VertexSeedFinder.GaussianSeeder,
vertexFinder: VertexFinder = VertexFinder.Truth,
useTime: Optional[bool] = False,
trackSelectorConfig: Optional[TrackSelectorConfig] = None,
outputDirRoot: Optional[Union[Path, str]] = None,
logLevel: Optional[acts.logging.Level] = None,
Expand All @@ -1618,16 +1619,22 @@ def addVertexFitting(
Parameters
----------
s: Sequencer
the sequencer module to which we add the Seeding steps (returned from addVertexFitting)
the sequencer module to which we add the Seeding steps (returned from
addVertexFitting)
field : magnetic field
outputDirRoot : Path|str, path, None
the output folder for the Root output, None triggers no output
associatedParticles : str, "associatedTruthParticles"
VertexPerformanceWriter.inputAssociatedTruthParticles
seeder : enum member
determines vertex seeder, can be acts.seeder.GaussianSeeder or acts.seeder.AdaptiveGridSeeder
determines vertex seeder for AMVF, can be acts.seeder.GaussianSeeder or
acts.seeder.AdaptiveGridSeeder
vertexFinder : VertexFinder, Truth
vertexFinder algorithm: one of Truth, AMVF, Iterative
useTime : bool
determines whether time information is used in vertex seeder, finder,
and fitter
only implemented for the AMVF and the AdaptiveGridSeeder
logLevel : acts.logging.Level, None
logging level to override setting given in `s`
"""
Expand Down Expand Up @@ -1693,8 +1700,9 @@ def addVertexFitting(
elif vertexFinder == VertexFinder.AMVF:
findVertices = AdaptiveMultiVertexFinderAlgorithm(
level=customLogLevel(),
bField=field,
seedFinder=seeder,
useTime=useTime,
bField=field,
inputTrackParameters=trackParameters,
outputProtoVertices=outputProtoVertices,
outputVertices=outputVertices,
Expand Down
2 changes: 1 addition & 1 deletion Examples/Python/src/Vertexing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ void addVertexing(Context& ctx) {
ACTS_PYTHON_DECLARE_ALGORITHM(
ActsExamples::AdaptiveMultiVertexFinderAlgorithm, mex,
"AdaptiveMultiVertexFinderAlgorithm", inputTrackParameters,
outputProtoVertices, outputVertices, seedFinder, bField);
outputProtoVertices, outputVertices, seedFinder, useTime, bField);

ACTS_PYTHON_DECLARE_ALGORITHM(ActsExamples::IterativeVertexFinderAlgorithm,
mex, "IterativeVertexFinderAlgorithm",
Expand Down

0 comments on commit 0d1e675

Please sign in to comment.