Skip to content

Add GenFit2-based Track Fitting Functional#77

Open
andread3vita wants to merge 23 commits intokey4hep:mainfrom
andread3vita:PRtrackingPipeline
Open

Add GenFit2-based Track Fitting Functional#77
andread3vita wants to merge 23 commits intokey4hep:mainfrom
andread3vita:PRtrackingPipeline

Conversation

@andread3vita
Copy link
Copy Markdown
Contributor

@andread3vita andread3vita commented Feb 26, 2026

BEGINRELEASENOTES

  • Rename the track finder functional to align with the current coding style
  • Add GenFit interfaces to enable running the track fitter
  • Implement the GenFit-based track fitter
  • Implement PerfectTrackFinder
  • Add test for the track fitter

ENDRELEASENOTES

Hello! This PR includes the implementation of the track fitter using Genfit2.
See more info here.

TODO:

  • Remove debug_lvl and use the gaudi-friendly version of the OutputLevel -> DONE
  • Add functionality to filter hits based on their weights after the fit - DONE
  • Add multiple fitters -> DONE

andread3vita and others added 5 commits February 25, 2026 18:10
FIX comments and track finder test
FIX fit initialization

ADD fitter test

ADD README for fitter

FIX small fix

FIX hit ordering function for fitter

ADD comments

Remove compatibility with older Gaudi versions (key4hep#76)
…NAME m_skip_background to m_skip_unmatchedTracks + COMMENT m_singleEvaluation
@jmcarcell
Copy link
Copy Markdown
Member

For every comment everyone watching the repository gets a notification. In addition, if someone reviews the PR and there are conversations, it will be very hard to find them between all your comments. As an alternative you can make a todo list in the original post with boxes and click the boxes once they are done. Or you can put comments in your own code.

@andread3vita
Copy link
Copy Markdown
Contributor Author

You are right! Sorry! I can modify the first comment with the TO-DO list

@andread3vita
Copy link
Copy Markdown
Contributor Author

@SanghyunKo I have finalized all modifications for standalone muon system fitting. The PR is ready for review.

@SanghyunKo
Copy link
Copy Markdown
Collaborator

As there were quite a number of formatting issues, I ran the clang hook and pushed to the PR myself. I will start reviewing the PR based on the updated one. Next time, it'll be very helpful for reviewers if you can run the pre-commit in advance, especially for a big PR like this :) I'll come back soon with the real comments.

Copy link
Copy Markdown
Collaborator

@SanghyunKo SanghyunKo left a comment

Choose a reason for hiding this comment

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

Impressive amount of work! I made my first round of passes. Frankly, I'm not confident enough that I caught everything properly (or even that my comments were proper). I'd highly appreciate comments from others.

I think most of my comments are rather easy to address, except the ones in GenfitTrack.cpp; Personally I feel that we might need to iterate on GenfitTrack.cpp a couple of times more. Anyway, let's make it converge soon ;)

namespace GenfitInterface {

GenfitField::GenfitField(dd4hep::OverlayedField dd4hepField) : m_dd4hepField(dd4hepField) {
genfit::FieldManager::getInstance()->init(this);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think you're calling the init function twice - you already have the call in L138 of GenfitTrackFitter.cpp. I'd remove this call in this constructor.


double rx = center.X() - pos.X();
double ry = center.Y() - pos.Y();
double signed_param = init_mom.X() * ry - init_mom.y() * rx;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Perhaps you wanted the capital letter Y? (everywhere else uses the capital letter)

Comment on lines +637 to +650
points_Rz.emplace_back(R, z_coord);
}

double sumR = 0.0;
double sumZ = 0.0;
double sumRZ = 0.0;
double sumR2 = 0.0;

for (const auto& p : points_Rz) {
sumR += p.x;
sumZ += p.y;
sumRZ += p.x * p.y;
sumR2 += p.x * p.x;
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why do you use Point2D_xy to store R & Z? It seems really confusing. You could use something else (e.g. std::pair) if you simply wanted to store the two doubles.

Comment on lines +652 to +667
double denominator = N * sumR2 - sumR * sumR;

double a = (N * sumRZ - sumR * sumZ) / denominator;
double b = (sumZ - a * sumR) / N;
pZ = a * init_pT;
init_mom.SetZ(pZ);

if (std::abs(denominator) < 1e-12) {
pZ = 0;
init_mom.SetZ(pZ);
}

double z_PCA = b;

// CHARGE
TVector3 pos(closestPoint.x, closestPoint.y, z_PCA);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Zero guard seems to be imperfect; if the denominator is zero, then z_PCA will be NaN.

// Initialize the Genfit: FieldManager and MaterialEffects
m_detector = m_geoSvc->getDetector();
auto fieldMap = m_detector->field();
m_genfitField = new GenfitInterface::GenfitField(fieldMap);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The m_genfitField is created and never deleted. Please delete this in the right place, or simply make this std::unique_ptr.

pz = gen_momentum.Z(); // gev
pt = gen_momentum.Perp(); // gev

double Bz = m_fieldMap->getBz(gen_position) / 10.; // Tesla
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same comment regarding the B field unit above (should be *dd4hep::kilogauss).

pz = gen_momentum.Z(); // gev
pt = gen_momentum.Perp(); // gev

Bz = m_fieldMap->getBz(gen_position) / 10.; // Tesla
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same (B field unit)

Comment on lines +1023 to +1028
trackStateFirstHit.D0 = d0;
trackStateFirstHit.Z0 = z0;
trackStateFirstHit.phi = phi;
trackStateFirstHit.omega = omega;
trackStateFirstHit.tanLambda = tanLambda;
trackStateFirstHit.time = 0.;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Probably you could make a function for setting the track state and save a couple of hundred lines here (same operations are repeated for the first hit, last hit, and at IP).
(+ avoid the battle with units)

Comment on lines +56 to +58
const int layer = decoder->get(cellid, "layer");
const int superlayer = decoder->get(cellid, "superlayer");
const int nphi = decoder->get(cellid, "nphi");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Are we 100% sure that all users of the SenseWireHit will use the same cell ID encoding scheme?

rawHitCov(7, 7) = positionAlongWireError * positionAlongWireError;

// Create the genfit::WirePointMeasurement
m_genfitHit = new genfit::WirePointMeasurement(rawHitCoords, rawHitCov, det_idx, hit_idx, nullptr);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same comment with the planar measurement (explain the ownership).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants