Repository navigation
Fixes from AI static scans - #226
Conversation
|
Response to issue #225:
|
edcallaghan
left a comment
There was a problem hiding this comment.
I only really inspected at the copy-constructors, which look fine to me. I can put effort into the rest if that would be helpful.
| auto db = next_->bnom() - prev_->bnom(); | ||
| dpfwd_ = refpiece.dPardB(this->time(),db); | ||
| dpdpdb_ = refpiece.dPardPardB(this->time(),db); | ||
| // dpdpdb_ = refpiece.dPardPardB(this->time(),db); |
There was a problem hiding this comment.
I'm missing the context of why dpdpdb_ is consistently commented out, so I'm pointing it out in case it was meant to be temporary.
| VEC3 phidir(momdir.Y(),-momdir.X(),0.0); | ||
| retval = phidir.Unit(); | ||
| } else if( tdir == perpdir_){ | ||
| if(momdir.Z() == 0.0)throw std::invalid_argument("Perp directions undefined when momentum is perpendicular to Z"); |
There was a problem hiding this comment.
== 0.0 can be a bit dodgy. I don't know the source of momdir, maybe there are semantics that will "guarantee" a true-zero, but if it is always a computed quantity then may want to do a tolerance instead.
There was a problem hiding this comment.
In testing with the production job fcls, this PR shows a reduction in the number of good tracks, especially for CentralHelix. See the comment above on the specific line.
Edit: I think the root of the problem is Detector/Hit.hh line 66:
Line 66 in dbc9aef
After the change in PieceWiseClosestApproach.hh, the trajectory piece where a hit's weight was applied at construction might differ from the piece its closest approach points to, so that the subtraction in Detector/Hit.hh can result in a negative projected distance variance. When that happens, the hit gets turned off. Sometimes (about 6% of the time), this results in a degraded fit that causes more hits to fail distance and variance cuts, and the track is ultimately dropped with LowNDOF.
| phint = this->hint(); | ||
| oldindex = pindex; | ||
| pindex = ptraj.nearestIndex(hint.particleToca_); | ||
| pindex = ptraj.nearestIndex(phint.particleToca_); |
There was a problem hiding this comment.
I think this change is correct in itself, but in testing it reveals another bug downstream, see below.
In testing with production LoopHelix and CentralHelix job fcls, this small change results in a ~6% drop in the number of tracks. Some of the lost tracks are actually good fits, especially for CentralHelix. I verified that this particular line is the suspect by reverting just this change and re-running. I am still trying to pin down the exact reason. It seems to be related to a negative unbiased variance caused when Hit::unbiasedParameters() in Detector/Hit.hh subtracts out the weight for a hit from a piece that is different from the one where its weight was originally applied.
|
I'm also seeing low reco efficiency.
It seems to be related to a negative unbiased variance caused when
Hit::unbiasedParameters()
That's a plausible explanation: the hit cache is WRT the previous
residual/trajectory; after POCA is updated, if the piece has changed it
won't reference the same parameters or derivatives, so the 1st order
variance subtraction can fail.
I think this says we need to compute uparams before updating POCA. Since
UPOCA is only used by the updaters it won't directly affect the fit. There
could be more knock-on effects though...
…On Thu, Oct 1, 2026 at 12:10 PM Rob Mina ***@***.***> wrote:
***@***.**** commented on this pull request.
In testing with the production job fcls, this PR shows a reduction in the
number of good tracks, especially for CentralHelix. See the comment above
on the specific line. I am still working on diagnosing the problem.
------------------------------
In Trajectory/PiecewiseClosestApproach.hh
<#226 (comment)>:
> @@ -30,7 +30,7 @@ namespace KinKal {
this->findTCA(phint);
phint = this->hint();
oldindex = pindex;
- pindex = ptraj.nearestIndex(hint.particleToca_);
+ pindex = ptraj.nearestIndex(phint.particleToca_);
I think this change is correct in itself, but in testing it reveals
another bug downstream, see below.
In testing with production LoopHelix and CentralHelix job fcls, this small
change results in a ~6% drop in the number of tracks. Some of the lost
tracks are actually good fits, especially for CentralHelix. I verified that
this particular line is the suspect by reverting just this change and
re-running. I am still trying to pin down the exact reason. It seems to be
related to a negative unbiased variance caused when
Hit::unbiasedParameters() in Detector/Hit.hh subtracts out the weight for a
hit from a piece that is different from the one where its weight was
originally applied.
—
Reply to this email directly, view it on GitHub
<#226?email_source=notifications&email_token=ABAH57YPA4Z7MHDR5KQ2CI35R2TZHA5CNFSNUABKM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UKJSXM2LFO4XTKMZYGQZDEMBXGQ3KM4TFMFZW63VGMF2XI2DPOKSWK5TFNZ2KYZTPN52GK4S7MNWGSY3L#pullrequestreview-5384220746>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABAH57YF5P3B6RH7H6WDSQT5R2TZHAVCNFSNUABFKJSXA33TNF2G64TZHMZDIMJZHE2TENJYHNEXG43VMU5TKNRUHE2DGOJZGA22C5QC>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
--
David Brown ***@***.***
Office Phone (510) 486-7261
Lawrence Berkeley National Lab
M/S 50R5008 (50-6026C) Berkeley, CA 94720
|
oksuzian
left a comment
There was a problem hiding this comment.
PR Review Summary — #226
Reviewed at head a3406dd56dd438b75c5cbc19cc0929f2a5530f80. first pass
Decision
- 🟡 comment only. The fixes for the eight original #225 items are in, and most of them are right. Hold the merge until the
unbiasedParametersordering issue Rob found is resolved. There are also two incomplete fixes and one behaviour change worth a look.
Scope understood
- 21 files, 251 lines, addressing issue #225: the original eight items plus several follow-ups (
pdir_,scatterAngleVarstatics,findDetMaterial,ResidualHitpvar,LoopHelix::constructible,transverseSpeed,KinematicLinemass/charge,PiecewiseTrajectory::clone).
Findings
-
🟠 [S1] The track loss Rob reported. I agree with the diagnosis, and here is one data point.
- The
PiecewiseClosestApproachfix (item 2) is correct. Before it, the closest approach never left the hinted piece. Now it can, which exposes the mismatch inHit::unbiasedParameters(): the reference parameters now come from the new piece, whileweight_is still from the old one. - In Offline, the order is
KKStrawHit::updateReference(movesca_, and with itrefTrajPtr()) →updateState(first)→updateWHS→unbiasedClosestApproach()→unbiasedParameters().updateWeight()runs only after that.KKCaloHit::unbiasedClosestApproachfollows the same order. - My measurement: Offline#2021 head, 2000 CeEndpoint OnSpill events, KinKal main
dbc9aefvs this PR. LoopHelix KalmanConverged is unchanged to slightly up: KKDe 1889→1910, KKDmu 1895→1905, KKUe 1848→1847, KKUmu 1869→1891. - So the loss doesn't show up in LoopHelix fits of conversion electrons, which fits Rob seeing it worst in CentralHelix. I couldn't run CentralHelix: I have no field-on cosmic digi sample.
- I also tried the obvious Offline-side fix: caching
unbiasedParameters()inupdateReferencebeforeca_moves. It made things worse, with upstream fits down 13–23%, so it's not the right fix. Dave's suggestion needs more than reordering that one call.
- The
-
🟡 [S2]
TimeRange::overlapsnow counts touching ranges as overlapping.- Executed at this head and at main:
[0,10)vs[10,20):overlapsis true here, false on main.- The null range
[10,10)against[0,10): now correctly false.
- The new
inRange(other.end())term is true at the shared endpoint. - It feeds
PiecewiseTrajectory::setRangeandpieceRangeand the domain trim atTrack.hh:226, so a neighbouring piece or domain that only touches the boundary is now kept. - That may be harmless, but it's a behaviour change beyond the null-range fix, and it's worth checking against the CentralHelix efficiency.
- Executed at this head and at main:
-
🟡 [S2] Two fixes are incomplete.
MatElementList: the failed open still spins. With a nonexistent path and-DNDEBUG,assert(elements.good())is compiled out and the failed open setsfailbit, noteofbit. So the new!elements.eof()guard never fires. I ran it: still looping after 5 s. Testgood()orfail()instead.- The same tag-search loop is untouched in
MatMaterialList.cc:74andMatIsotopeList.cc:72.
- The same tag-search loop is untouched in
FitData::invertstill never checksvec_.isfiniteonmat_(0,0)is better thanisnan, but the overflow I showed in #225 is invec_ = mat_*vec_, a finite-but-huge matrix times a normal vector, andvec_is still not checked.
-
⚪ [S3] Small items.
Domain.hh:43: the newoperator<<is a non-inlinedefinition in a header. Two translation units that includeDomain.hhgive a multiple-definition link error; I reproduced it. The copy constructor andclonealready have the same problem on main.inlineon all three fixes it.Intersect.hh:300:pdir_ = kkline.direction(retval.time_)readstime_one line before it is assigned. That's harmless for a line, whose direction doesn't depend on time, but swapping the two lines matchesstepIntersect.PiecewiseTrajectory::clone:rv->is fixed, butpush_back(*piece)still pushes aKTRAJinto a deque ofshared_ptr, and no trajectory class definesclone. It still won't compile if anything instantiates it.- The commented-out
dpdpdb_lines (Ed's comment): if the covariance rotation is being dropped, delete them rather than comment them out.
Not in this PR (about 35 items from #225 are untouched, almost all latent or unreachable from Offline):
Track.hhStatus(0)×3;prepend(…,true);setRangewith an empty container;- the
PointPiecewiseClosestApproachcompile errors; - the
SensorLineunit error; ConstantDistanceToTimeabs();- the
CentralHelix::dPardPardBidentity stub; - all of the
General/BField-map items; - most of the
MatEnvandGeometryitems.
Fine to defer, but it would help to say whether #225 stays open for them.
Validation check
- Build/tests run:
- KinKal built at this head and at main (CMake, Release).
- Offline#2021 built against each.
- 2000-event LoopHelix reco A/B (numbers in finding 1).
- Standalone programs for
TimeRangeoverlaps, theMatElementListfailed open, and theDomain.hhlink.
- Not run: KinKal ctest at this head (GitHub Actions is green on 4 configs), and any CentralHelix sample.
- Cross-repo: Offline#2021 depends on #224, and this PR changes fit behaviour under it.
Residual risk
- CentralHelix efficiency, until the
unbiasedParametersordering is fixed and re-measured.
Author follow-ups
- The
unbiasedParametersfix, then Rob's efficiency re-run (finding 1). - Confirm the touching-range change in
overlapsis intended (finding 2). MatElementListfailed-open,vec_ininvert(finding 3);inlineinDomain.hh(finding 4).
oksuzian
left a comment
There was a problem hiding this comment.
PR Review Summary — #226
Reviewed at head 3f849fe15d436927635eb16488c4f4be0b298e68. Re-review of a3406dd56dd438b75c5cbc19cc0929f2a5530f80.
Decision
- 🟡 comment only. Nothing in this increment changes my first-pass review.
Scope understood
- One commit, "disambiguate messages":
Fit/DomainWall.hh:124, inDomainWall::extrapolate, changes the exception text from "Can't append piece" to "Can't extrapolate piece". - 🟢 This is correct: the throw is inside
extrapolate, andappendhas its own message. It's text only, with no behaviour change.
Carried forward from a3406dd5, all still open at this head
- 🟠 [S1] The
unbiasedParameterspiece mismatch behind Rob's track loss. The ordering fix Dave proposed isn't in yet.- Since my last review, I tried a field-on OffSpill cosmic sample (
CosmicSignalOffSpill.MDC2025an, 2000 events). It gave only 15 CentralHelix tracks, which is too few to measure anything. - On the same sample, the LoopHelix path kept 1194 events with this PR against 1214 with main (−1.6%), and converged LoopHelix fits fell from 40 to 27. Also small numbers, but they point the same way as Rob's result.
- Rob's 112-file sample is still the right test.
- Since my last review, I tried a field-on OffSpill cosmic sample (
- 🟡 [S2]
TimeRange::overlapsnow counts touching ranges as overlapping. - 🟡 [S2]
MatElementList: a failed open still spins.FitData::invertstill doesn't checkvec_. - ⚪ [S3] The non-inline
operator<<inDomain.hh,Intersect.hh:300readingtime_before it is set,PiecewiseTrajectory::clone, and the commented-outdpdpdb_lines.
Validation check
- Build/tests run: none for this increment, a one-string change I read in full. GitHub Actions results at this head: not checked.
oksuzian
left a comment
There was a problem hiding this comment.
PR Review Summary — #226
Reviewed at head 79fefa9134f51ce89d47525b2f3a59b28e277aa8. Re-review of 3f849fe15d436927635eb16488c4f4be0b298e68.
Decision
- 🟡 comment only. "Small fixes" clears most of my S2/S3 items, thank you. The
unbiasedParametersordering (S1) isn't in this commit, so the track loss is still open.
Scope understood
- One commit across six files. It answers my earlier findings 2, 3 and 4, and adds a
forceRangechange.
Verified in this increment, by reading the diff
- 🟢
TimeRange::overlapsgoes back toinRange(other.begin()) || other.inRange(begin()). Touching ranges[0,10)/[10,20)no longer overlap, and a null range at the boundary doesn't either. This resolves my finding 2. - 🟢
MatElementList: a stream that fails to open now throws (!good() || eof()) instead of hitting a release-mode no-opassert. This resolves the failed-open part of finding 3. - 🟢
Domain.hhoperator<<is nowinline. - 🟢
Intersect.hh:pdir_is now set aftertime_. - 🟢
PiecewiseTrajectory::clone: it now pushesmake_shared<KTRAJ>(*piece), which matches the deque'sshared_ptrelement type. Not compiled, because nothing in the repo instantiates it. - 🟢 The commented-out
dpdpdb_lines are deleted.
Findings
- 🟠 [S1] Still open: the
Hit::unbiasedParameters()piece mismatch behind the CentralHelix loss. Dave agreed on 10-01 thatuparamsshould be computed before the POCA update, but that change isn't in this commit. My cosmic numbers from the last review stand (LoopHelix converged fits 40 → 27 on 2000 OffSpill events), and Rob's 112-file sample is still the right test. - 🟡 [S2] The new
forceRangeupper clamp is a no-op.end() - std::numeric_limits<double>::min()subtracts the smallest normalised double, about 2.2e-308. For anyend()above roughly 1e-292, that rounds back toend()exactly. For example, one ULP at 1695 ns is about 2.3e-13. So a time clamped to the end still failsinRange, which usest < end().- Suggested fix:
std::nextafter(end(), begin()). Or, if one ULP is too fine for the callers, an explicit small epsilon in ns. - Not run. This is double-precision arithmetic, and I haven't checked which callers depend on the clamp.
- Suggested fix:
- 🟡 [S2] Still open:
FitData::invertdoesn't checkvec_, the overflow from #225. This commit doesn't touchFitData.hh. - ⚪ [S3] The other two non-inline definitions in
Domain.hhremain. At this head,Domain::Domain(Domain const&)(line 33) andDomain::clone(line 38) are still non-inlineout-of-class definitions in the header.operator<<was the one I reproduced. These two give the same multiple-definition link error once two translation units include the header. Addinginlineto both finishes the job.
Validation check
- Build/tests run: none locally for this increment. I read the compare diff
3f849fe1...79fefa91in full. - GitHub Actions: Tests pass on all 4 configurations (Debug/Release × ubuntu/macos) at this head.
- Cross-repo: Offline#2021 still needs a KinKal tag with #224 and #226, then an envset and a
.musebump.
Author follow-ups
- The
unbiasedParametersordering, then a re-measurement of CentralHelix efficiency (finding 1). nextafterinforceRange(finding 2).- A
vec_finiteness check ininvert(finding 3).
|
I tested again at current head (79fefa9) I still see the reco efficiency loss of about 7% on the LoopHelix sample and 6% of the CentralHelix sample. The LoopHelix tracks dropped are mostly marginal quality, but the CentralHelix loses some good tracks. The LoopHelix base config is Production/JobConfig/reco/OnSpill.fcl and the input file was dig.mu2e.data_like_no_primary_1BB.MDC2025af_best_v1_1.001430_00000000.art The CentralHelix base config is Production/JobConfig/recoMC/OffSpill.fcl and the input file was dig.mu2e.CosmicSignalOffSpill.MDC2025an_best_v1_1.001430_00000000.art I have a proposed fix that I am testing now. |
oksuzian
left a comment
There was a problem hiding this comment.
PR Review Summary — #226
Reviewed at head cbab3c3f450d009c0f5f14e111a8afcd98d4c788. Re-review of 79fefa9134f51ce89d47525b2f3a59b28e277aa8.
Decision
- 🟡 comment only. "Address last issues" closes three of my four remaining items. The new
invertcheck only looks at one component, though, and the track loss is still open. Rob is testing a fix for it, per his comment.
Scope understood
- One commit:
Domaincopy constructor andclonemove out of the header into a newFit/Domain.cc, added to theFitlibrary;forceRangenow usesstd::nextafter;FitData::invertadds a finiteness check onvec_.
Verified in this increment, by reading the diff
- 🟢
Domain.hhno longer holds any non-inline out-of-class definition, so the multiple-definition link error is gone. The two definitions are now inDomain.cc, which is inFit/CMakeLists.txt. Not compiled locally. - 🟢
forceRange:std::nextafter(end(), begin())is one ULP belowend(), so a clamped time now passesinRange. For a null range it givesbegin(), which is harmless. This resolves my previous finding 2.
Findings
- 🟠 [S1] Still open: the
Hit::unbiasedParameters()piece mismatch. Rob measured it again at79fefa91and still sees the loss: about 7% on LoopHelix and 6% on CentralHelix, including good CentralHelix tracks. This commit doesn't touch it, and he says a fix is being tested. - 🟡 [S2] The new
vec_check tests onlyvec_[0].static double ones[DVEC::kSize] = {1.0};sets the first element to 1 and zero-initialises the rest; that's aggregate initialisation. Souvecis (1,0,0,0,0,0), andDot(vec_,uvec)is justvec_[0]. An overflow in any of the other five components still gets through. That includes the case I showed in #225, a finite-but-hugemat_times a normal vector.- Suggested fix: a plain loop with no statics,
for(size_t i=0;i<DVEC::kSize;++i) if(!std::isfinite(vec_[i])) throw std::runtime_error("Inversion failure");. Alternatively, fillonesexplicitly. A NaN or ±inf in any element makes the all-ones dot product non-finite, so that version would also work. - Minor point: function-local statics in a header member function are thread-safe to initialise, but the loop avoids them altogether.
- Suggested fix: a plain loop with no statics,
Validation check
- Build/tests run: none locally. I read the compare diff
79fefa91...cbab3c3fin full. Finding 2 is a language rule, not a measurement. - GitHub Actions at this head: all 4 configurations were pending when I checked.
- Cross-repo: Offline#2021 still needs a KinKal tag with #224 and #226, then an envset and a
.musebump.
Author follow-ups
- The
unbiasedParametersfix and a re-measurement on Rob's two samples (finding 1). - Check all six
vec_components ininvert(finding 2).
oksuzian
left a comment
There was a problem hiding this comment.
PR Review Summary — #226
Reviewed at head c3ead80e1e97c595281dc5053267b49fce4f7099. Re-review of cbab3c3f450d009c0f5f14e111a8afcd98d4c788.
Decision
- 🟡 comment only. The
vec_check is fixed, thank you. The only thing still open is the track-loss item.
Scope understood
- One commit, "Test all elements". In
FitData::invert,onesis nowstd::vector<double>(DVEC::kSize, 1.0), souvecis all ones.
Verified in this increment, by reading the diff
- 🟢
Dot(vec_, uvec)is now the sum of all six components. A NaN or ±inf in any of them makes the sum non-finite, and so does an opposing pair +inf/−inf, which gives NaN. The overflow case from #225 is now caught. This resolves my previous finding 2. - The only edge case: finite components whose sum overflows, which needs values around 1e308. That would throw on a result that was technically finite, which is the safe direction.
Findings
- 🟠 [S1] Still open: the
Hit::unbiasedParameters()piece mismatch behind the reco efficiency loss Rob measured at79fefa91(about 7% LoopHelix, about 6% CentralHelix). This commit doesn't touch it, and Rob's proposed fix hasn't been pushed yet.
Validation check
- Build/tests run: none locally. I read the compare diff
cbab3c3f...c3ead80ein full. - GitHub Actions at this head: Tests pass on all 4 configurations.
- Cross-repo: Offline#2021 still needs a KinKal tag with #224 and #226, then an envset and a
.musebump.
Author follow-ups
- The
unbiasedParametersfix, then a re-measurement on Rob's two samples.
RobMina
left a comment
There was a problem hiding this comment.
I'll keep digging into the CH efficiency drop. In the meantime, this PR can be merged.



This PR addresses issues raised by AI static scans (issue #225 )