Skip to content

Add TPC-only helix/Kalman fitters and V0 candidate diagnostics - #4359

Open
997873828mcx wants to merge 1 commit into
sPHENIX-Collaboration:masterfrom
997873828mcx:integration/tpc-kalman-v0-pr4354
Open

Add TPC-only helix/Kalman fitters and V0 candidate diagnostics#4359
997873828mcx wants to merge 1 commit into
sPHENIX-Collaboration:masterfrom
997873828mcx:integration/tpc-kalman-v0-pr4354

Conversation

@997873828mcx

@997873828mcx 997873828mcx commented Jul 24, 2026

Copy link
Copy Markdown

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work for users)
  • Requiring change in macros repository (Please provide links to the macros pull request in the last section)
  • I am a member of GitHub organization of sPHENIX Collaboration, EIC, or ECCE (contact Chris Pinkenburg to join)

What kind of change does this PR introduce? (Bug fix, feature, ...)

This PR adds reusable TPC-only track-fitting utilities to tpctrackreco and a
Fun4All V0 reconstruction and diagnostics module to TrackingDiagnostics.

The new functionality includes:

  • Common TPC track point, state, helix, fit-result, and configuration types.
  • A standalone TPC helix fitter supporting:
    • configurable point ordering, including looper-aware ordering;
    • least-squares and high-momentum curvature-refined circle fits;
    • charge-consistent track orientation;
    • track-to-vertex DCA calculations;
    • bounded two-track PCA searches anchored to the measured TPC trajectory.
  • A standalone six-parameter TPC Kalman fitter using
    (x, y, z, phi, q/pT, tan(lambda)), with:
    • forward filtering and backward smoothing;
    • configurable local (r, rphi, z) measurement uncertainties;
    • analytic propagation in a uniform solenoidal field;
    • numerical propagation through a PHField field map;
    • configurable process noise, multiple scattering, and energy loss;
    • DCA and two-track PCA extrapolation;
    • optional per-measurement innovation diagnostics.
  • TpcV0CandidateTree, a Fun4All diagnostics module that:
    • consumes TPC pattern-recognition cluster and track containers;
    • supports helix fitting, Kalman fitting, and upstream fitted-track states;
    • reconstructs two-track V0 candidates;
    • writes track, pair, fit-quality, residual, invariant-mass, and
      Armenteros-Podolanski observables;
    • optionally writes same-sign pairs and simulation-truth diagnostics;
    • provides configurable track and pair preselection.

The existing tracking workflow is unchanged unless the new module is explicitly
registered and configured.

TODOs (if applicable)

Links to other PRs in macros and calibration repositories (if applicable)

  • Companion macros PR: planned; link will be added when opened.

Motivation / Context

Adds reusable TPC-only track-fitting utilities and an opt-in Fun4All module for reconstructing and diagnosing two-track V0 candidates, enabling detailed tracking QA without changing existing workflows.

Key Changes

  • Added configurable TPC helix fitting, point ordering, DCA, and helix/line PCA utilities.
  • Added six-parameter TPC Kalman fitting with:
    • Uniform-field or field-map propagation
    • Adaptive integration and process-noise options
    • Material effects and energy loss
    • Forward filtering, smoothing, and innovation diagnostics
  • Added TpcV0CandidateTree for:
    • Track and pair preselection, including optional same-sign pairs
    • Helix, Kalman, or no-fit modes
    • V0, invariant-mass, Armenteros-Podolanski, fit-quality, residual, and truth observables
    • Optional cluster-residual and simulation-truth trees
  • Updated build configurations and library dependencies.

Potential Risk Areas

  • New ROOT tree schemas and diagnostic outputs may require downstream consumer updates.
  • Complex fitting and propagation logic could affect reconstruction quality, numerical stability, and runtime, especially with field maps or large candidate samples.
  • Output-file and module state management should be reviewed for concurrent or repeated use; thread-safety is not established.
  • AI-generated summaries can contain inaccuracies; implementation details and behavior should be verified against the source and physics validation results.

Possible Future Improvements

  • Add focused unit tests and physics validation for helix, Kalman, PCA, DCA, and V0 observables.
  • Provide companion macros and documented configuration examples.
  • Benchmark field-map propagation and candidate-pair performance.
  • Define and version output tree schemas and add regression tests for diagnostic content.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

TPC tracking and V0 diagnostics

Layer / File(s) Summary
Track-fit contracts and helix geometry
offline/packages/tpctrackreco/TpcTrackFit.h, offline/packages/tpctrackreco/TpcTrackHelixFitter.*, offline/packages/tpctrackreco/Makefile.am
Adds shared track-fit structures and helix fitting, ordering, PCA, search-range, DCA, and vector utilities.
Kalman propagation and fitting
offline/packages/tpctrackreco/TpcTrackKalmanFitter.*, offline/packages/tpctrackreco/Makefile.am
Adds configurable uniform-field or RK propagation, covariance transport, filtering, smoothing, diagnostics, state propagation, and DCA calculations.
V0 candidate diagnostics
offline/packages/TrackingDiagnostics/TpcV0CandidateTree.*, offline/packages/TrackingDiagnostics/Makefile.am
Adds truth and pattern tracklet processing, helix/Kalman integration, pair selection, QA and residual rows, and ROOT tree lifecycle management.

Sequence Diagram(s)

sequenceDiagram
  participant TpcV0CandidateTree
  participant PHCompositeNode
  participant TpcTrackHelixFitter
  participant TpcTrackKalmanFitter
  participant ROOT
  TpcV0CandidateTree->>PHCompositeNode: Read event, vertex, truth, and TPC inputs
  TpcV0CandidateTree->>TpcTrackHelixFitter: Build helix tracklets and PCA candidates
  TpcV0CandidateTree->>TpcTrackKalmanFitter: Fit and propagate configured tracks
  TpcV0CandidateTree->>TpcV0CandidateTree: Apply preselection and pair selection
  TpcV0CandidateTree->>ROOT: Write pair, track, and residual trees
Loading

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 06a2883d-69e1-46b4-856f-9de4e6d0a5aa

📥 Commits

Reviewing files that changed from the base of the PR and between 3f9ccc3 and ebd9bfe.

📒 Files selected for processing (9)
  • offline/packages/TrackingDiagnostics/Makefile.am
  • offline/packages/TrackingDiagnostics/TpcV0CandidateTree.cc
  • offline/packages/TrackingDiagnostics/TpcV0CandidateTree.h
  • offline/packages/tpctrackreco/Makefile.am
  • offline/packages/tpctrackreco/TpcTrackFit.h
  • offline/packages/tpctrackreco/TpcTrackHelixFitter.cc
  • offline/packages/tpctrackreco/TpcTrackHelixFitter.h
  • offline/packages/tpctrackreco/TpcTrackKalmanFitter.cc
  • offline/packages/tpctrackreco/TpcTrackKalmanFitter.h

Comment on lines +35 to +36
static std::array<double, StateDim> propagation_state(const TpcKalmanResult &fit,
const TpcTrackVec3 &reference_vertex);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

propagation_state takes a reference_vertex it deliberately ignores.

The definition names the parameter /*reference_vertex*/ and the comment at TpcTrackKalmanFitter.cc Line 1034-1036 states the vertex must not influence the choice of end state. Every call site in TpcV0CandidateTree.cc (Lines 664, 826, 893, 1362, 2407, 2423, 2439) passes a vertex — two of them a dummy Vec3{}, the rest a real primary vertex — so the results are identical while the signature suggests otherwise. On a brand-new public API this is worth resolving now, before downstream code starts relying on a vertex dependence that does not exist.

Either drop the parameter, or keep it and document that it is reserved. Dropping it is cleaner and the call sites are all in this PR.

♻️ Proposed signature simplification
-  static std::array<double, StateDim> propagation_state(const TpcKalmanResult &fit,
-                                                        const TpcTrackVec3 &reference_vertex);
+  // Selects the physical initial state of the fitted sequence from the charge
+  // sign alone; no vertex or transverse-distance heuristic is involved.
+  static std::array<double, StateDim> propagation_state(const TpcKalmanResult &fit);

dca_to_vertex at Line 41-43 would then call propagation_state(fit) and the TpcV0CandidateTree helpers (kalman_point/kalman_tangent/kalman_momentum) can drop their reference_vertex argument too.

As per path instructions, "Focus on API clarity/stability, ownership semantics (RAII)" and "If interfaces change, ask for compatibility notes and any needed downstream updates."

Source: Path instructions

Comment on lines +231 to +236
m_file = new TFile(m_filename.c_str(), "RECREATE");
if (!m_file || m_file->IsZombie())
{
std::cout << Name() << ": failed to create output file " << m_filename << std::endl;
return Fun4AllReturnCodes::ABORTRUN;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Failed TFile open leaves a zombie handle that End() will still write to.

When IsZombie() is true the function returns ABORTRUN but m_file stays non-null and the allocated TFile is never released. If the framework still calls End() during teardown, Lines 462-479 will cd(), Write() the trees and Close() a zombie file. Deleting and nulling the pointer here makes the failure state unambiguous and removes the leak.

🛡️ Proposed fix
   m_file = new TFile(m_filename.c_str(), "RECREATE");
   if (!m_file || m_file->IsZombie())
   {
     std::cout << Name() << ": failed to create output file " << m_filename << std::endl;
+    delete m_file;
+    m_file = nullptr;
     return Fun4AllReturnCodes::ABORTRUN;
   }

As per path instructions, "Prioritize correctness, memory safety, error handling, and thread-safety."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
m_file = new TFile(m_filename.c_str(), "RECREATE");
if (!m_file || m_file->IsZombie())
{
std::cout << Name() << ": failed to create output file " << m_filename << std::endl;
return Fun4AllReturnCodes::ABORTRUN;
}
m_file = new TFile(m_filename.c_str(), "RECREATE");
if (!m_file || m_file->IsZombie())
{
std::cout << Name() << ": failed to create output file " << m_filename << std::endl;
delete m_file;
m_file = nullptr;
return Fun4AllReturnCodes::ABORTRUN;
}

Source: Path instructions

Comment on lines +2609 to +2611
std::sort(candidates.begin(), candidates.end(),
[](const KalmanPca &lhs, const KalmanPca &rhs)
{ return lhs.dca < rhs.dca; });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Non-finite dca values can reach this sort and break the comparator's strict weak ordering.

refine_kalman_pair derives best.dca from kalman_point, which returns a NaN triple whenever propagate_rkn4 exhausts its step budget — a reachable outcome over the ±max_upstream_cm scan, and precisely what rkn_failures counts. A NaN key makes lhs.dca < rhs.dca inconsistent, which is undefined behaviour for std::sort (libstdc++ can run off the end of the range during its insertion-sort phase).

Note the seed loop at Line 2574 already filters !std::isfinite(d2) before sorting; the candidate sort needs the same protection. Dropping non-finite candidates also spares make_pair_row from consuming a NaN pair_dca.

🛡️ Proposed fix
+  candidates.erase(
+      std::remove_if(candidates.begin(), candidates.end(),
+                     [](const KalmanPca &candidate)
+                     { return !std::isfinite(candidate.dca); }),
+      candidates.end());
+
   std::sort(candidates.begin(), candidates.end(),
             [](const KalmanPca &lhs, const KalmanPca &rhs)
             { return lhs.dca < rhs.dca; });
   return candidates;

make_pair_row already treats an empty candidate list as reject_pca (Lines 1059-1063), so no caller change is needed.

As per path instructions, "Prioritize correctness, memory safety, error handling, and thread-safety."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
std::sort(candidates.begin(), candidates.end(),
[](const KalmanPca &lhs, const KalmanPca &rhs)
{ return lhs.dca < rhs.dca; });
candidates.erase(
std::remove_if(candidates.begin(), candidates.end(),
[](const KalmanPca &candidate)
{ return !std::isfinite(candidate.dca); }),
candidates.end());
std::sort(candidates.begin(), candidates.end(),
[](const KalmanPca &lhs, const KalmanPca &rhs)
{ return lhs.dca < rhs.dca; });

Source: Path instructions

@sphenix-jenkins-ci

Copy link
Copy Markdown

Build & test report

Report for commit ebd9bfe21b36c0e189c2bfc97dc3ab8d7a23e86c:
Jenkins passed


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

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.

1 participant