Skip to content

Conversation

bishoyDHD
Copy link

Briefly, what does this PR introduce?

This adds secondary vertex finder to the EICrecon.

What kind of change does this PR introduce?

  • Bug fix (issue #__)
  • New feature (issue #__)
  • Documentation update
  • Other: __

Please check if this PR fulfills the following:

  • Tests for the changes have been added
  • Documentation has been added / updated
  • Changes have been communicated to collaborators

Does this PR introduce breaking changes? What changes might users need to make to their code?

No need to make changes to existing code. Full compliance with main EICrecon repo has been maintained throughout

Does this PR change default behavior?

No change to default behaviour

bishoyDHD and others added 30 commits September 2, 2024 13:38
@veprbl
Copy link
Member

veprbl commented Jul 27, 2025

@wdconinc I know that @bishoyDHD did a good faith attempt at adapting his code to the algorithms interface. As you know, there are objective issues with interfacing ACTS_LOCAL_LOGGER with algorithms that are the same for existing CKFTracking code. The issues with passing code to functions I can't testify, but we probably can relatively easily address in further refactoring. My proposal is to review PR without asking for algorithms interface. Likely, it will be to either me or you to take on this technical debt.

@wdconinc
Copy link
Contributor

@wdconinc I know that @bishoyDHD did a good faith attempt at adapting his code to the algorithms interface. As you know, there are objective issues with interfacing ACTS_LOCAL_LOGGER with algorithms that are the same for existing CKFTracking code. The issues with passing code to functions I can't testify, but we probably can relatively easily address in further refactoring. My proposal is to review PR without asking for algorithms interface. Likely, it will be to either me or you to take on this technical debt.

That's not the objection that's been raised. I'm ok with keeping an extra helper function that passes a spdlog logger from the factory to the algorithm, but there is no technical reason that the rest can't be using the algorithms interface.

@veprbl
Copy link
Member

veprbl commented Jul 27, 2025

@wdconinc I know that @bishoyDHD did a good faith attempt at adapting his code to the algorithms interface. As you know, there are objective issues with interfacing ACTS_LOCAL_LOGGER with algorithms that are the same for existing CKFTracking code. The issues with passing code to functions I can't testify, but we probably can relatively easily address in further refactoring. My proposal is to review PR without asking for algorithms interface. Likely, it will be to either me or you to take on this technical debt.

That's not the objection that's been raised. I'm ok with keeping an extra helper function that passes a spdlog logger from the factory to the algorithm, but there is no technical reason that the rest can't be using the algorithms interface.

I wrote "passing code" instead of "passing pointers [to other methods of the algorithm]". My assumption is that it's a trivial change, but there is some C++ gotcha that tripped up @bishoyDHD in his attempt. I'd rather work with code that is final and effective before doing the refactoring we are talking about.

@veprbl
Copy link
Member

veprbl commented Jul 27, 2025

Looks like we have two comments unaddressed from the first round of review. One on using spdlog, which we might punt on. And another about units of initialVariances and moving that to config.

@github-actions github-actions bot dismissed their stale review July 27, 2025 18:42

No Clang-Tidy warnings found so I assume my comments were addressed

@eic eic deleted a comment from github-actions bot Jul 27, 2025
@bishoyDHD
Copy link
Author

Looks like we have two comments unaddressed from the first round of review. One on using spdlog, which we might punt on. And another about units of initialVariances and moving that to config.

Moved to Config

Copy link
Contributor

@wdconinc wdconinc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two major remaining comments from my side at this point:

  • We should move the creation and initialization of algorithmic structures that are event-independent into the init function, not recreate them for each event in the process function.
  • We should not base this algorithm on the input from ActsExamples::Trajectories, but on the input from ReconstructedParticles. That will avoid the combinatorics of the matching loop. (Even if you don't do this, the matching loop should use an early break.)

float maxDistToLinPoint = 5.5 * Acts::UnitConstants::mm;
// Bin extent in z-direction
float spatialBinExtent = 25 * Acts::UnitConstants::um;
Acts::Vector4 initialVariances = Acts::Vector4{1e+2, 1e+2, 1e+2, 1e+8};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still needs units.

Comment on lines +56 to +57
void ChangeRun(int32_t) {}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inherit.

Suggested change
void ChangeRun(int32_t) {}

@@ -0,0 +1,39 @@
#pragma once
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing license header.

: SecondaryVertexFinderAlgorithm{name,
{"inputReconstructedParticles", "inputActsTrajectories"},
{"outputPrimaryVertices", "outputSecondaryVertices"},
""} {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing docstring.

Comment on lines +205 to +232
for (const auto& t : vtx.tracks()) {
const auto& par = vertexfinderConfigSec.extractParameters(t.originalParams);
m_log->trace("Track local position from vertex = {} mm, {} mm",
par.localPosition().x() / Acts::UnitConstants::mm,
par.localPosition().y() / Acts::UnitConstants::mm);
float loc_a = par.localPosition().x();
float loc_b = par.localPosition().y();

for (const auto& part : reconParticles) {
const auto& tracks = part.getTracks();
for (const auto& trk : tracks) {
const auto& traj = trk.getTrajectory();
const auto& trkPars = traj.getTrackParameters();
for (const auto& par : trkPars) {
double EPSILON = std::numeric_limits<double>::epsilon(); // mm
if (std::abs((par.getLoc().a / edm4eic::unit::mm) - (loc_a / Acts::UnitConstants::mm)) <
EPSILON &&
std::abs((par.getLoc().b / edm4eic::unit::mm) - (loc_b / Acts::UnitConstants::mm)) <
EPSILON) {
m_log->trace(
"From ReconParticles, track local position [Loc a, Loc b] = {} mm, {} mm",
par.getLoc().a / edm4eic::unit::mm, par.getLoc().b / edm4eic::unit::mm);
eicvertex.addToAssociatedParticles(part);
} // endif
} // end for par
} // end for trk
} // end for part
} // end for t
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole matching is not ideal, and I'd like to see it removed instead of getting into our code base and left for others to refactor later.

The input to seed finding is (only) a set of track parameters. You have these track parameters as input in the form of ReconstructedParticles. But you ALSO pass and use the ActsExamples::Trajectories (which we are actively trying to get away from...). Then after seed finding you have to run this nested set of loops for matching with ReconstructedParticles. Why not start from ReconstructedParticles to fill your input tracks? Then when you get the vertices they will point to the tracks that are filled parallel to the ReconstructedParticles vector. There will be no matching loops necessary.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We told @bishoyDHD that copy-pasting the

for (const auto& t : vtx.tracks()) {
const auto& par = finderCfg.extractParameters(t.originalParams);
m_log->trace("Track local position from vertex = {} mm, {} mm",
par.localPosition().x() / Acts::UnitConstants::mm,
par.localPosition().y() / Acts::UnitConstants::mm);
float loc_a = par.localPosition().x();
float loc_b = par.localPosition().y();
for (const auto& part : *reconParticles) {
const auto& tracks = part.getTracks();
for (const auto& trk : tracks) {
const auto& traj = trk.getTrajectory();
const auto& trkPars = traj.getTrackParameters();
for (const auto& par : trkPars) {
const double EPSILON = 1.0e-4; // mm
if (std::abs((par.getLoc().a / edm4eic::unit::mm) - (loc_a / Acts::UnitConstants::mm)) <
EPSILON &&
std::abs((par.getLoc().b / edm4eic::unit::mm) - (loc_b / Acts::UnitConstants::mm)) <
EPSILON) {
m_log->trace(
"From ReconParticles, track local position [Loc a, Loc b] = {} mm, {} mm",
par.getLoc().a / edm4eic::unit::mm, par.getLoc().b / edm4eic::unit::mm);
eicvertex.addToAssociatedParticles(part);
} // endif
} // end for par
} // end for trk
} // end for part
} // end for t
is an acceptable workaround to the issue of associating to PODIO. I don't think writing a routine to convert ReconstructedParticles to Trajectories is a useful exercise, if we plan to move to PODIO for Acts EDM anyway. Even once we have that, there will be some matching loop to have.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think writing a routine to convert ReconstructedParticles to Trajectories is a useful exercise.

Not what I'm suggesting. Look at the code. Instead of getTrackParameters from Trajectories, you can getTrackParameters from ReconstructedParticles, instead of doing exactly that in the loop later.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still not following you here. I don't see track parameters in edm4eic::ReconstructedParticle or edm4eic::Track. Or you want to match by momentum instead of locA/locB?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or the 3D position? But then we need to convert using bound surface.

Copy link
Member

@veprbl veprbl Jul 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can you reduce it? (Messages crossed -- GitHub is lagging)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so that is about a different piece of code where the

Acts::BoundTrackParameters<> par(trkPars);

is a non-existent conversion routine from EDM4eic to Acts EDM. And that does not yet explain how to get rid of the nested match loop.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is this: #1992 (not even tested compilation, and has some remaining FIXMEs).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non-existent conversion routine

In the sense that CKFTracking does this already (minus surface lookup since it's a perigee that is re-created).

Copy link
Author

@bishoyDHD bishoyDHD Jul 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the light. Let me see if I can make this work (I will be in the lab so please be a bit patient).
On another note. This is solution might be what I have been looking for actually, because I would like to have reconstructed particles that perhaps do not have a "good" primary vertex. Basically, let's not throwaway all of the tracks (because there could be good candidate secondary particles in there).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: tracking Relates to tracking reconstruction
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants