Skip to content

Fix critical bugs in KinKal integration code#1786

Merged
oksuzian merged 4 commits intomainfrom
copilot/review-kinkal
Apr 8, 2026
Merged

Fix critical bugs in KinKal integration code#1786
oksuzian merged 4 commits intomainfrom
copilot/review-kinkal

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 7, 2026

Summary

This PR fixes 17 bugs discovered during a code review of the Mu2eKinKal package. The bugs range from critical logic errors (dead code due to variable shadowing) to numeric precision issues (float limits used for double variables) and uninitialized members. No functional behavior is intentionally changed beyond correcting these defects.


Critical Bugs

Fix 1: KKStrawMaterial.cc — Typo assigns wallpath twice instead of wirepath

File: Mu2eKinKal/src/KKStrawMaterial.cc line 34
Bug: In averagePathLengths(), the output parameter wirepath is never set — instead wallpath is assigned 0.0 a second time (overwriting the correct value just assigned on the previous line). The caller receives an uninitialized wirepath and a zeroed wallpath.
Fix: Change wallpath = 0.0wirepath = 0.0.

Fix 2: KKStrawHit.hh — Copy constructor reads from uninitialized this instead of rhs

File: Mu2eKinKal/inc/KKStrawHit.hh lines 57–58
Bug: The copy constructor initializes dVar_ and dDdT_ by calling driftVariance() and driftVelocity() on the partially-constructed object (this). These methods depend on members that haven't been initialized yet (e.g. whstate_, chit_), producing undefined behavior.
Fix: Copy from rhs.dVar_ and rhs.dDdT_ directly.

Fix 11: LoopHelixFit_module.cc — Variable shadowing makes helicity/charge checks dead code

File: Mu2eKinKal/src/LoopHelixFit_module.cc line 481
Bug: Inside goodFit(), a new bool retval is declared in the inner scope (line 481), shadowing the outer retval (line 476). The inner variable captures the helicity sign check, charge sign check, and detector-volume check — but it goes out of scope at the closing brace. The outer retval (which only checks fitStatus().usable()) is what gets returned. This means tracks with wrong helicity or charge sign are never rejected, and the in-detector check is never applied.
Fix: Remove the bool keyword so line 481 assigns to the existing outer retval.


Stream/Diagnostic Bugs

Fix 3: Chi2SHU.ccoperator<< writes to std::cout instead of os

File: Mu2eKinKal/src/Chi2SHU.cc lines 82–83
Bug: The operator<<(std::ostream& os, ClusterState const&) overload writes the hit states to std::cout instead of the passed os stream. This breaks logging to files or string streams.
Fix: Replace std::cout with os.

Fix 4: DriftANNSHU.cc — Copy-paste prints sign weights path for cluster weights

File: Mu2eKinKal/src/DriftANNSHU.cc line 26
Bug: The diagnostic message says "cluster weights" but prints std::get<0>(config) (the sign weights file) instead of std::get<2>(config) (the cluster weights file).
Fix: Change to std::get<2>(config).


Numeric Precision: float Limits Used for double Variables (10 locations)

All of these share the same root cause: std::numeric_limits<float>::max() (≈3.4e38) is used to initialize double variables that should hold extreme sentinel values. For "minimum so far" patterns this works by accident (3.4e38 is large enough), but for "maximum so far" patterns, -std::numeric_limits<float>::max() is used instead of std::numeric_limits<double>::lowest(). More critically, std::numeric_limits<float>::min() (≈1.2e-38, the smallest positive normalized float) is used where a negative lower bound is needed, which silently prevents finding any maximum value less than 1.2e-38.

Fix 5: KKFitUtilities.cctimeBounds() and zMid()

File: Mu2eKinKal/src/KKFitUtilities.cc lines 45–46, 57–58
Bug: tmax initialized with float::min() (positive ~1e-38) instead of double::lowest(). Any negative time would never be selected as max.
Fix: Use std::numeric_limits<double>::max() for min-trackers and std::numeric_limits<double>::lowest() for max-trackers.

Fix 6: KKFit.hhrange() and createSeed() detector trajectory saving

File: Mu2eKinKal/inc/KKFit.hh lines 628–629, 766–767
Fix: Same pattern — floatdouble, using ::lowest() for tmax.

Fix 10: KKStrawHitCluster.hhtime()

File: Mu2eKinKal/inc/KKStrawHitCluster.hh line 146
Fix: float::max()double::max() for the min-time tracker.

Fix 13: ExtrapolateIPA.hh — default constructor bounds

File: Mu2eKinKal/inc/ExtrapolateIPA.hh lines 20–21
Fix: float::max() / -float::max()double::max() / double::lowest() for zmin_, zmax_.

Fix 14: ExtrapolateST.hh — default constructor bounds

File: Mu2eKinKal/inc/ExtrapolateST.hh lines 27–30
Fix: Same for zmin_, zmax_, rmin_, rmax_.

Fix 15: ExtrapolateTCRV.hh — default constructor bounds

File: Mu2eKinKal/inc/ExtrapolateTCRV.hh lines 25–26
Fix: Same for ymin_, ymax_.

Fix 16: Chi2SHU_updateCluster.hh — determinant tolerance

File: Mu2eKinKal/inc/Chi2SHU_updateCluster.hh line 36
Bug: determinant is a double, but compared against std::numeric_limits<float>::min() (~1.2e-38). For double-precision covariance matrices, valid small determinants between float::min and double::min would be rejected.
Fix: Use std::numeric_limits<double>::min().


Uninitialized / Unsafe Variables

Fix 7: KKFit.hh — Mutable cache variables uninitialized

File: Mu2eKinKal/inc/KKFit.hh lines 149–152
Bug: strawradius_, ymin_, ymax_, umax_, rmin_, rmax_, spitch_ are mutable and lazy-initialized, but have no default value. If any code path reads them before the lazy init fires, the values are garbage.
Fix: Initialize all to 0.

Fix 8: KKShellXing.hh — Division by zero and missing fabs in transitTime() (updated per @brownd1978 review)

File: Mu2eKinKal/inc/KKShellXing.hh lines 103–105
Bug: thick_ / (norm · pdir) divides by the dot product of the surface normal and particle direction. Two issues: (1) when the particle travels nearly parallel to the surface the dot product is near zero, producing an extremely large or infinite result, and (2) the dot product can be negative when the particle direction is opposite to the surface normal, which would produce a negative (unphysical) path length.
Fix: Take the absolute value and clamp to a minimum: std::max(1e-6, fabs(inter_.norm_.Dot(inter_.pdir_))). This ensures the path length is always positive and capped at a physically reasonable maximum.

Fix 9: KKFit.hh — Division by zero in sqrt(docaVar())

File: Mu2eKinKal/inc/KKFit.hh lines 479, 536
Bug: dsig = max(0, doca - strawradius_) / sqrt(pca.docaVar()). If the closest approach variance is zero (e.g. degenerate fit), this divides by zero.
Fix: Clamp the denominator: sqrt(max(docaVar(), double::min())).

Fix 12: DriftANNSHU.hh — Uninitialized diag_ member

File: Mu2eKinKal/inc/DriftANNSHU.hh line 37
Bug: int diag_ has no default initializer. All other updater classes (Chi2SHU, CADSHU, BkgANNSHU) initialize their diag_ to 0. If a code path reads diag_ before the constructor body sets it, the value is indeterminate.
Fix: int diag_ = 0.


Minor

Fix 17: KinematicLineFit_module.cc — Unnecessary variable shadowing

File: Mu2eKinKal/src/KinematicLineFit_module.cc line 340
Bug: auto hptr = art::Ptr<CosmicTrackSeed>(hseedcol_h,iseed) re-declares hptr, shadowing the identical variable from the outer scope (line 288). The shadowed version is used on the next line. While the result is the same, it's confusing and masks the intent.
Fix: Remove the redundant declaration; the outer hptr is already correct.


Files Changed (15 files)

File Fixes
Mu2eKinKal/src/KKStrawMaterial.cc #1
Mu2eKinKal/inc/KKStrawHit.hh #2
Mu2eKinKal/src/Chi2SHU.cc #3
Mu2eKinKal/src/DriftANNSHU.cc #4
Mu2eKinKal/src/KKFitUtilities.cc #5
Mu2eKinKal/inc/KKFit.hh #6, #7, #9
Mu2eKinKal/inc/KKShellXing.hh #8
Mu2eKinKal/inc/KKStrawHitCluster.hh #10
Mu2eKinKal/src/LoopHelixFit_module.cc #11
Mu2eKinKal/inc/DriftANNSHU.hh #12
Mu2eKinKal/inc/ExtrapolateIPA.hh #13
Mu2eKinKal/inc/ExtrapolateST.hh #14
Mu2eKinKal/inc/ExtrapolateTCRV.hh #15
Mu2eKinKal/inc/Chi2SHU_updateCluster.hh #16
Mu2eKinKal/src/KinematicLineFit_module.cc #17

- KKStrawMaterial: fix wallpath/wirepath typo in averagePathLengths
- KKStrawHit: fix copy constructor to copy dVar_/dDdT_ from rhs
- Chi2SHU: fix operator<< to use os parameter instead of std::cout
- DriftANNSHU: fix copy-paste error printing wrong config index
- KKFitUtilities/KKFit/KKStrawHitCluster: use double limits instead
  of float limits for min/max tracking
- KKFit: initialize mutable cache variables to zero
- KKShellXing: guard transitTime against division by zero
- KKFit: guard dsig calculation against zero docaVar

Agent-Logs-Url: https://github.com/Mu2e/Offline/sessions/c56c0d14-d58e-4d88-9e5a-7d64ba5efda6

Co-authored-by: oksuzian <48927306+oksuzian@users.noreply.github.com>
@FNALbuild
Copy link
Copy Markdown
Collaborator

Hi @Copilot,
You have proposed changes to files in these packages:

  • Mu2eKinKal

which require these tests: build.

@Mu2e/write, @Mu2e/fnalbuild-users have access to CI actions on main.

📝 The author of this pull request is not a member of the Mu2e github organisation.

About FNALbuild. Code review on Mu2e/Offline.

- LoopHelixFit: fix critical variable shadowing making physical
  consistency checks (helicity/charge) dead code
- DriftANNSHU: initialize diag_ member to 0
- ExtrapolateIPA/ST/TCRV: use double limits instead of float
- Chi2SHU_updateCluster: use double::min() for determinant check
- KinematicLineFit: remove unnecessary variable shadowing of hptr

Agent-Logs-Url: https://github.com/Mu2e/Offline/sessions/78f0b373-e173-4e76-96d0-cac405a5ea5b

Co-authored-by: oksuzian <48927306+oksuzian@users.noreply.github.com>
@oksuzian oksuzian requested review from rlcee and removed request for oksuzian April 7, 2026 17:31
@oksuzian oksuzian marked this pull request as ready for review April 7, 2026 17:32
Copy link
Copy Markdown
Collaborator

@brownd1978 brownd1978 left a comment

Choose a reason for hiding this comment

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

Mostly correct or innocuous. There's 1 incorrect fix. The only fix that might affect results is the goodtrack test.

Comment thread Mu2eKinKal/inc/KKShellXing.hh Outdated
template <class KTRAJ,class SURF> double KKShellXing<KTRAJ,SURF>::transitTime() const {
double pathlen = thick_/(inter_.norm_.Dot(inter_.pdir_));
double dotprod = inter_.norm_.Dot(inter_.pdir_);
if(std::abs(dotprod) < 1e-10) return 0.0; // particle parallel to surface
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.

This fix is incorrect; it returns 0 when the result would (formally) be infinite. The correct fix is to require a minimum value for dotprod.
double dotprod = std::max(1e-6,inter_.norm_.Dot(inter_.pdir_);

… to min value instead of returning 0

Agent-Logs-Url: https://github.com/Mu2e/Offline/sessions/7d94d9d6-a4b8-48dc-8682-567dc69e2938

Co-authored-by: oksuzian <48927306+oksuzian@users.noreply.github.com>
Copilot AI requested a review from oksuzian April 7, 2026 17:45
@oksuzian
Copy link
Copy Markdown
Collaborator

oksuzian commented Apr 7, 2026

@FNALbuild run build test

@FNALbuild
Copy link
Copy Markdown
Collaborator

⌛ The following tests have been triggered for 1b7b2f8: build (Build queue - API unavailable)

@FNALbuild
Copy link
Copy Markdown
Collaborator

☀️ The build tests passed at 1b7b2f8.

Test Result Details
test with Command did not list any other PRs to include
merge Merged 1b7b2f8 at e229837
build (prof) Log file. Build time: 08 min 54 sec
ceSimReco Log file.
g4test_03MT Log file.
transportOnly Log file.
POT Log file.
g4study Log file.
cosmicSimReco Log file.
cosmicOffSpill Log file.
ceSteps Log file.
ceDigi Log file.
muDauSteps Log file.
ceMix Log file.
rootOverlaps Log file.
g4surfaceCheck Log file.
trigger Log file.
check_cmake Log file.
FIXME, TODO ➡️ TODO (30) FIXME (7) in 15 files
clang-tidy ➡️ 4 errors 115 warnings
whitespace check no whitespace errors found

N.B. These results were obtained from a build of this Pull Request at 1b7b2f8 after being merged into the base branch at e229837.

For more information, please check the job page here.
Build artifacts are deleted after 5 days. If this is not desired, select Keep this build forever on the job page.

Copy link
Copy Markdown
Collaborator

@brownd1978 brownd1978 left a comment

Choose a reason for hiding this comment

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

Another bug, not caught by the AI

Comment thread Mu2eKinKal/inc/KKShellXing.hh Outdated

template <class KTRAJ,class SURF> double KKShellXing<KTRAJ,SURF>::transitTime() const {
double pathlen = thick_/(inter_.norm_.Dot(inter_.pdir_));
double dotprod = std::max(1e-6,inter_.norm_.Dot(inter_.pdir_));
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 there's another bug here, missing fabs(inter_....)

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.

@copilot, fix

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added fabs() around the dot product in commit f33f89e:

double dotprod = std::max(1e-6,fabs(inter_.norm_.Dot(inter_.pdir_)));

…er brownd1978 review

Agent-Logs-Url: https://github.com/Mu2e/Offline/sessions/cb5b66ea-2ece-4f44-afab-f6cb67ed0bb1

Co-authored-by: oksuzian <48927306+oksuzian@users.noreply.github.com>
Copy link
Copy Markdown
Collaborator

@brownd1978 brownd1978 left a comment

Choose a reason for hiding this comment

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

Looks correct now

@oksuzian oksuzian merged commit 093f523 into main Apr 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants