Skip to content

FEATURE: ACTS extrapolation to TPOT#4188

Merged
osbornjd merged 4 commits into
sPHENIX-Collaboration:masterfrom
hupereir:extrapolation_to_tpot
Feb 23, 2026
Merged

FEATURE: ACTS extrapolation to TPOT#4188
osbornjd merged 4 commits into
sPHENIX-Collaboration:masterfrom
hupereir:extrapolation_to_tpot

Conversation

@hupereir
Copy link
Copy Markdown
Contributor

@hupereir hupereir commented Feb 20, 2026

When disabling Micromegas clusters from fit, use acts to propagate the track parameters to any TPOT surface for which a cluster was found at the seeding stage.

This is similar to the extrapolation performed to TPC layers in distortion-targeted Silicon-MM fit. This will allow to obtain unbiased residuals in the Micromegas.

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, ...)

TODOs (if applicable)

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

ACTS Extrapolation to TPOT (Micromegas)

Motivation & Context

When Micromegas clusters are excluded from the track fit (e.g., distortion-targeted Silicon–MM fits), fitted track parameters are not available at Micromegas surfaces, preventing unbiased residual calculations. This PR adds ACTS-based propagation to extrapolate fitted parameters to TPOT (Micromegas) surfaces that had clusters at seeding, mirroring existing TPC extrapolation behavior and enabling unbiased Micromegas residuals when those clusters are not included in the fit.

Key Changes

  • PHActsTrkFitter::updateSvtxTrack:
    • Adds a conditional propagation block that runs only when Micromegas are disabled in the fit (m_useMicromegas == false) and a TPC seed exists.
    • Instantiates an ActsPropagator, iterates over seed cluster keys for Micromegas, looks up the corresponding TPOT surface via ActsGeometry maps, and propagates fitted track parameters to each Micromegas surface.
    • On successful propagation converts path length to cm, creates extrapolated track parameters, and inserts new SvtxTrackState entries (one per Micromegas cluster) using the existing transformer. Placement mirrors the existing TPC extrapolation flow; the rest of updateSvtxTrack is unchanged.
  • TrackAnalysisUtils:
    • Function parameter types for calc_dedx and calc_dedx_calib updated to take a const-qualified thickness_per_region array (float const thickness_per_region[4]) and a minor explicit pointer adjustment for tpc seed retrieval. Changes are small and largely stylistic/const-correctness.

Potential Risk Areas

  • Reconstruction behavior: Downstream code that consumes SvtxTrackState contents may observe additional Micromegas states in configurations where Micromegas clusters are excluded from the fit; verify consumers tolerate these entries.
  • Performance: Extra ACTS propagations per track increase CPU cost for affected configurations (when Micromegas are disabled and a seed exists). Measure runtime impact in representative workflows.
  • Thread safety: Implementation follows existing fitter patterns and uses per-track objects, but any shared resources used in propagation or geometry maps should be reviewed for concurrency issues.
  • Geometry / correctness: Relies on ActsGeometry maps and correct TPOT surface lookup; incorrect geometry initialization or missing map entries can cause failed propagations or misplaced states—validate geometry and propagation success rates.
  • API/ABI: The TrackAnalysisUtils changes are const-correctness refinements to function parameter types; review callers for compatibility (likely non-breaking within the same codebase but worth scanning for build warnings).

Possible Future Improvements

  • Factor common extrapolation code (TPC vs. Micromegas) into a shared utility to reduce duplication.
  • Add unit/integration tests and performance benchmarks for the new extrapolation path.
  • Extend consistent extrapolation behavior to other subsystems with similar "excluded-from-fit" needs.
  • Instrument propagation failures and add configurable logging or metrics to aid validation.

Note on AI assistance: This summary was prepared with AI assistance. AI can make mistakes—please review the code diffs and run the usual validation tests to confirm behavior and correctness.

…e track parameters to any TPOT surface for which a cluster was found at the seeding stage.

This is similar to the extrapolation performed to TPC layers in distortion-targeted Silicon-MM fit.
This will allow to obtain unbiased residuals in the Micromegas.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 20, 2026

📝 Walkthrough

Walkthrough

Adds Micromegas-surface propagation during Svtx track post-fit updates when Micromegas is excluded from the fit, and updates dE/dx helper signatures to use a const thickness_per_region array and explicit pointer typing in TrackAnalysisUtils.

Changes

Cohort / File(s) Summary
Micromegas Track Propagation
offline/packages/trackreco/PHActsTrkFitter.cc
Adds a propagation block (~+20 lines) that mirrors existing TPC extrapolation: constructs an ActsPropagator, iterates TPC-seed cluster keys, filters Micromegas clusters, retrieves Micromegas surfaces, propagates track parameters, converts path length to cm, and appends extrapolated track states via the transformer. Guarded by "Micromegas not used for fit" and presence of a seed; rest of flow unchanged.
dE/dx API and minor pointer fix
offline/packages/trackbase_historic/TrackAnalysisUtils.cc
Changes signatures of calc_dedx and calc_dedx_calib to accept float const thickness_per_region[4] (const-qualified array) and adjusts local TPC-seed retrieval to an explicit pointer (auto*). Minor formatting/whitespace tweaks only.
✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Comment thread offline/packages/trackreco/PHActsTrkFitter.cc
hupereir and others added 3 commits February 20, 2026 14:12
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
offline/packages/trackbase_historic/TrackAnalysisUtils.cc (1)

168-178: ⚠️ Potential issue | 🟠 Major

Missing dedxlist.empty() guard — dedxlist.at(0) will throw std::out_of_range on tracks with no TPC clusters.

calc_dedx correctly returns quiet_NaN() when dedxlist is empty (lines 79–82). calc_dedx_calib has no such guard: when dedxlist is empty, trunc_max = 0, the loop executes once (j=0 ≤ 0), and dedxlist.at(0) throws. With the current code path producing clusterKeys exclusively from the TPC seed, tracks carrying zero TPC clusters (e.g., a null or empty seed) hit this directly.

🛡️ Proposed fix — mirror the guard already present in `calc_dedx`
+    if (dedxlist.empty())
+    {
+      return std::numeric_limits<float>::quiet_NaN();
+    }
     int trunc_max = (int) dedxlist.size() * 0.7;
     float sumdedx = 0;
     int ndedx = 0;

Comment on lines +140 to 142
auto* tpcseed = track->get_tpc_seed();
float alpha = (r * r) / (2 * r * std::abs(1.0 / tpcseed->get_qOverR()));
float beta = std::atan(tpcseed->get_slope());
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.

⚠️ Potential issue | 🟠 Major

tpcseed null-dereference latent risk — move outside loop and guard explicitly.

track->get_tpc_seed() is called once at line 100 (to build clusterKeys) and again at line 140 on every loop iteration. The only protection against dereferencing a null pointer at line 141 (tpcseed->get_qOverR()) is the implicit guarantee that if get_tpc_seed() returns nullptr, get_cluster_keys returns an empty vector and the loop is never entered. This coupling is fragile: if clusterKeys is ever populated through a different path (or if the call to get_cluster_keys at line 100 is refactored), a silent null-dereference becomes possible. Retrieve and guard the seed once, before the loop.

🛡️ Proposed fix
+    auto* tpcseed = track->get_tpc_seed();
+    if (!tpcseed) { return std::numeric_limits<float>::quiet_NaN(); }
+
     std::vector<float> dedxlist;
     for (unsigned long cluster_key : clusterKeys)
     {
       ...
-      auto* tpcseed = track->get_tpc_seed();
       float alpha = (r * r) / (2 * r * std::abs(1.0 / tpcseed->get_qOverR()));

@sphenix-jenkins-ci
Copy link
Copy Markdown

Build & test report

Report for commit ecddd62c08e23cb45a76caf175a5a72ffdeb7a84:
Jenkins passed


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

@sphenix-jenkins-ci
Copy link
Copy Markdown

Build & test report

Report for commit 3e526f3ee6612c5d75b72a0c1ffff6f1b92f36c0:
Jenkins on fire


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

@sphenix-jenkins-ci
Copy link
Copy Markdown

Build & test report

Report for commit a139a428cc24a66a70ec0cd6af78ed4adebc6c04:
Jenkins passed


Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

Copy link
Copy Markdown
Contributor

@osbornjd osbornjd left a comment

Choose a reason for hiding this comment

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

This will add a track state to the track object that in some senses is "misleading" in that it was not actually used in the fit. I don't have an objection to merging this (and it is possible I missed discussion related to this) but before merging this we need to make sure everyone is on the same page that the TPOT states, after merging this PR, mean something inherently different than all the other states in the track object

@hupereir
Copy link
Copy Markdown
Contributor Author

@osbornjd we can discuss this at tomorrow's tracking meeting. Still, using track state for storing extrapolation is already what we do for calorimeters, as far as I know. (and vertex ?). As well as for the TPC states in calibration mode. So in that sense it is not a new behavior.

@osbornjd
Copy link
Copy Markdown
Contributor

@osbornjd we can discuss this at tomorrow's tracking meeting. Still, using track state for storing extrapolation is already what we do for calorimeters, as far as I know. (and vertex ?). As well as for the TPC states in calibration mode. So in that sense it is not a new behavior.

Right, my only thought is that the calos are known to be "special" and the calibration mode is "special." Again, I don't see a problem with it - it just means everyone needs to know that the TPOT state(s) will also be special

@osbornjd
Copy link
Copy Markdown
Contributor

Alternatively, perhaps we construct an SvtxTrack object at some point that has a fit_state_map and a projection_state_map to differentiate between the two.

@hupereir
Copy link
Copy Markdown
Contributor Author

Alternatively, perhaps we construct an SvtxTrack object at some point that has a fit_state_map and a projection_state_map to differentiate between the two.

I agree that this would be the cleanest, but also fear it is somewhat overkill ? My understanding is that state vectors are already an expert tool (aside from how many there are, nobody actually look at their value, except for making biased or unbiased residuals). In addition: right now TPOT is removed from the seeding entirely (so you won't get neither the cluster nor the state vector), in the official macro. For this feature to manifest, you need to

  • re-add TPOT to the seeding
  • and disable TPOT from the fitting.
    This is pretty niche, I'd say :)

@osbornjd osbornjd merged commit 4790cc5 into sPHENIX-Collaboration:master Feb 23, 2026
13 of 22 checks passed
@hupereir hupereir deleted the extrapolation_to_tpot branch February 23, 2026 21:32
@coderabbitai coderabbitai Bot mentioned this pull request May 7, 2026
4 tasks
@coderabbitai coderabbitai Bot mentioned this pull request May 20, 2026
5 tasks
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.

2 participants