Mu2eKinKal: fix defects found by a static sweep of the package - #1955
Mu2eKinKal: fix defects found by a static sweep of the package#1955oksuzian wants to merge 1 commit into
Conversation
RegrowKinematicLine indexed KalSeedMCAssns with a counter local to its own input KalSeedCollection. That product is a single flat Assns spanning every collection SelectRecoMC was configured with (KKDe, KKDmu, KKUe, KKUmu, KKLine, KKCHmu), so for KKLine the index is wrong whenever an earlier collection has seeds, and the ptr self-check throws. Replace the positional lookup with a KalSeed -> KalSeedMC map built once per event; this also removes the O(N*M) scan the sibling RegrowLoopHelix does. RegrowLoopHelix declared MustRegrow as a mandatory fhicl::Atom, but no job config supplies it: Production/JobConfig/reco/regrowLH.fcl builds the producer block literally instead of pulling @table::Mu2eKinKal.RegrowLH, which is the only place the key is set. Give the Atom the "None" default that table implies, so validation no longer fails before the module is constructed. BkgANNSHU passed sqrt(docaVar()) to the MVA unclamped. A non-positive docaVar gives NaN, and NaN < mvacut_ is false, so an unscoreable hit is left active or re-activated. DriftANNSHU, CADSHU and KKFit all clamp the same quantity; do the same here. KKFit::createSeed dereferenced rbegin() of the domain set when SaveDomains is set. That set is empty whenever the fit ran without BField correction, making this undefined behaviour. Throw a named exception instead; the CHTruthSeed prolog comment that documented the crash is updated to match. StrawHitUpdaters::name() indexed names_ with the enumerator value, but 'unknown' is -1, so printing that state at diag > 1 was undefined behaviour. Bounds-check and return "unknown". KLSeedFit took KKFitSettings straight from KKFIT, which deliberately does not set the mandatory SaveTrajectory key. Every sibling supplies its own; add T0 to match CHSeedFit, whose fit and extension settings KLSeedFit already shares. Found by a static review of the package at 0ef02a6. Not built locally -- relying on CI for the build. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
☀️ The build tests passed at 87d7c03.
N.B. These results were obtained from a build of this Pull Request at 87d7c03 after being merged into the base branch at 0ef02a6. For more information, please check the job page here. |
| // SaveDomains with a fit that ran without BField correction leaves no domains at all; | ||
| // rbegin() would then be rend() and dereferencing it is undefined behaviour | ||
| if(kktrk.domains().empty())throw cet::exception("RECO") | ||
| << "mu2e::KKFit: SaveDomains is set but the fit has no BField domains; set BFieldCorrection or SaveDomains:false" << std::endl; |
There was a problem hiding this comment.
I think this should be a warning and a clean return (with empty domains collection) rather than an exception. An uncaught exception would abort the entire art job.
There was a problem hiding this comment.
I agree with Rob, there is no need to throw here. A track with no domains will produce an empty domainsbounds container, regardless of how savedomains is set.
|
I encountered an exception when running Production/JobConfig/reco/regrow_kl.fcl, but not the "wrong KalSeed ptr" exception addressed in this PR. Instead, it was "Invalid Time Range" in KinKal::TimeRange constructor: The Offline call is in toTrackerPerimeter here: Offline/Mu2eKinKal/inc/KKExtrap.hh Line 159 in 0ef02a6 The failure is unrelated to the suggested fix in this PR, but it hides any actual problem that this PR would fix. A cheap fix would be TimeRange(ftraj.range().begin(), tref, false). Maybe that should be added to this PR. Edit: I confirmed that adding ordered=false (last argument of TimeRange) to both the forward and backward branches allows the regrow_kl.fcl job to complete without exceptions. I also confirmed that this PR produces no changes in output across standard production KL, CH, and LH jobs. |
|
@RobMina Thanks for running I looked into the Root cause
Why
|
brownd1978
left a comment
There was a problem hiding this comment.
I have no objection adding prolog default. Hard coded defaults should not be introduced.
Adding a map for KKLine KalSeed/KalSeedMC mapping is fine: it future-proofs against potential changes in production, but is currently unnecessary: there is no known use cases reconstructing KKLine with any other kind of KKTrack.
SaveDomains configuration 'inconsistency' checking is unnecessary: if a KKTrack has domains they should be saved. The SaveDomains config should simply be retired, now that regrowing is a standard workflow, as there's no way to correctly regrow a KalSeed that didn't save its domains. Seeds without domains (from KKLine) aren't affected either way.
| // SaveDomains with a fit that ran without BField correction leaves no domains at all; | ||
| // rbegin() would then be rend() and dereferencing it is undefined behaviour | ||
| if(kktrk.domains().empty())throw cet::exception("RECO") | ||
| << "mu2e::KKFit: SaveDomains is set but the fit has no BField domains; set BFieldCorrection or SaveDomains:false" << std::endl; |
There was a problem hiding this comment.
I agree with Rob, there is no need to throw here. A track with no domains will produce an empty domainsbounds container, regardless of how savedomains is set.
| fhicl::Table<KKConfig> fitSettings { Name("RefitSettings") }; | ||
| fhicl::Atom<bool> extend {Name("Extend"), Comment("Extend the fit") }; | ||
| fhicl::Atom<std::string> mustRegrow{ Name("MustRegrow"), Comment("Required track regrowing success for event to pass")}; | ||
| fhicl::Atom<std::string> mustRegrow{ Name("MustRegrow"), Comment("Required track regrowing success for event to pass: 'None', 'Any' or 'All'"), "None"}; |
There was a problem hiding this comment.
hardcoded defaults for parameters which have no default 'correct' value are against Mu2e policy. The MustRegrow setting is context dependent and mustbe set outside the code.
|
@brownd1978 @RobMina Thanks both. I agree the throw is wrong — aborting the art job over a configuration state the code can handle is not the right response. But I don't think deleting it gets us to the behaviour you both described, and I'd rather flag that now than have it come back as a segfault. The empty-container claim doesn't hold for the current code
That is what we want, but it isn't what happens today. if(savedomains_){
kseed._domainbounds.reserve(kktrk.domains().size()+1);
for (auto const& domain : kktrk.domains()){
kseed._domainbounds.push_back(domain->begin());
}
// save end of last domain
kseed._domainbounds.push_back((*(kktrk.domains().rbegin()))->end());
}The loop is correctly a no-op on an empty set, but the final Proposed replacementGuard the block on the set instead of throwing: if(savedomains_ && !kktrk.domains().empty()){This gives the clean return with an empty It also lands where you want to end up, David:
With the guard written this way, retiring the config later is a one-token deletion — the I'll also drop the amended comment in MustRegrowAgreed, I'll revert One note on where the fix then belongs. The prolog default you have no objection to already exists: I'll open a companion Production PR adding the key to both blocks. Worth saying that this one is still unverified by a run: Rob, your Extrapolation TimeRangeI'd like to take the |
Six defects found by a static review of
Mu2eKinKalat0ef02a66d. All six are mechanical fixes with an existing in-package precedent; none changes fit acceptance or any tuning constant. I have not built this locally — relying onmu2e/buildtest.1.
RegrowKinematicLineindexes a flatKalSeedMCAssnswith a collection-local counterRegrowKinematicLine_module.cc:249did(*ksmca_H)[iseed], whereiseedcounts position within this module's own inputKalSeedCollection(wired toKKLine).KalSeedMCAssnsis one flat product:CommonMC/src/SelectRecoMC_module.cc:170does a singleproduces<KalSeedMCAssns>(), and:468-498runs one loop overgetMany<KalSeedCollection>callingaddSingleonce per seed per collection.Production/JobConfig/recoMC/prolog.fcl:32orders them["KKDe","KKDmu","KKUe","KKUmu","KKLine","KKCHmu"]— KKLine is 5th of 6. So on any event with a seed in an earlier collection,(*ksmca_H)[0]for the first KKLine seed returns a KKDe entry, the ptr self-check fails, and the art job dies withcet::exception("Reco").The sibling
RegrowLoopHelix(:305-317) does anart::Ptr-equality search, correct at any offset — which is also why the bug is invisible there:RegrowLHtargetsKKDe, index 0.Fixed with a
KalSeed -> KalSeedMCmap built once per event, which is correct at any offset and also drops the sibling's O(N·M) scan.2.
RegrowLoopHelix: mandatoryMustRegrowis absent from the live job configRegrowLoopHelix_module.cc:98declared a two-argumentfhicl::Atom<std::string>— mandatory, unlikedebugat:86in the same struct.No job config supplies it.
Production/JobConfig/reco/regrowLH.fcl:34-55buildsphysics.producers.RegrowLHas a literal block rather than pulling@table::Mu2eKinKal.RegrowLH, andProduction/JobConfig/reco/prolog.fcl:122-140omits it too. The onlyMustRegrow : "None"in the tree isMu2eKinKal/fcl/prolog.fcl:642, in the table neither Production block references —grep -rn MustRegrow Production/returns nothing. Validation fails before the module is constructed, so the constructor's own value check at:200-207is never reached.Fixed by giving the Atom the
"None"default that table already implies. (The alternative — adding the key toProduction— would need a companion PR there; this way the module is correct on its own.)3.
BkgANNSHU: unguardedsqrt(docaVar())feeds NaN to the MVABkgANNSHU.cc:30waspars[2] = sqrt(tpdata.docaVar());. A non-positivedocaVargives NaN;NaN < mvacut_is false under IEEE-754, so theelsebranch runs and the hit is left active — or, if it was inactive, re-activated at:45.Three sibling call sites clamp the identical quantity:
DriftANNSHU.cc:44,CADSHU.cc:31,KKFit.hh:510,567. Adopted the same clamp.4.
KKFit::createSeeddereferencesrbegin()of a possibly-empty domain setKKFit.hh:796did(*(kktrk.domains().rbegin()))->end()undersavedomains_.domains()is astd::set, empty whenever the fit ran without BField correction;rbegin()then equalsrend()and dereferencing it is UB.No committed config triggers it today — but only because
Mu2eKinKal/fcl/prolog.fcl:606-608carries a hand-written comment telling the next author not to setSaveDomains:truethere, citing this exact SIGSEGV. Replaced the load-bearing comment with a namedcet::exception, and updated the comment to say what now happens.5.
StrawHitUpdaters::name()indexes with a negative enumeratorunknown = -1(StrawHitUpdaters.hh:12), andname()didnames_[static_cast<size_t>(alg)]— UB whenever an unknown state is printed atdiag > 1. Bounds-checked; returns"unknown".6.
KLSeedFitomits the mandatorySaveTrajectorykeyKKFITdeliberately does not setSaveTrajectory, and every producer that builds from it supplies its own — verified atLHSeedFit:468,LHDriftFit:490,KLDriftFit:531,CHSeedFit:547,CHDriftFit:562,KLTruthSeed:587,CHTruthSeed:606,RegrowLH:636.KLSeedFitdid not, so its table cannot pass validation the moment it is added to a path. AddedSaveTrajectory : T0, matchingCHSeedFit, whoseFitSettingsandExtensionSettingsKLSeedFitalready shares.Validation
Productionandmu2e-trig-config, plus grep. Please letbuildtestbe the arbiter.mu2e -c Production/JobConfig/reco/regrowKL.fcland oneregrowLH.fclover a few events; if either already runs green today, the corresponding finding is wrong and I will withdraw it.fhicl-dump -aprovenance was produced. Add diagnostics #2 and Adjust parameters for new production #6 rest on reading the prologs and grepping@table::references; a resolution path I failed to model would change them.KinematicLineFit::goodFit()returning onlyfitStatus().usable()while both siblings also requireinDetector()/charge/helicity;KKBField::fieldGrad()returning the transpose of its own documenteddB_i/dx_jconvention; andExtrapolateCRVRegion's short-piece fallback being backward-only. Those need an author decision, so I left them out. Happy to open an issue with the full list.