Repository navigation
Conversation
ariostas
left a comment
There was a problem hiding this comment.
🤖 AI text below 🤖
Thanks for this, it's a really nice addition! I checked the efficiencies and intervals against ROOT 6.40.02 (writing with PyROOT, reading back with this branch), and almost everything matches exactly, including the weighted and Bayesian paths. A few things I found, roughly in order of importance:
- Feldman-Cousins is wrong for bins with more than ~1030 entries (inline comment with a fix that matches ROOT exactly).
- The objectwise branch of
_read_beta_bin_paramscan't read ROOT-written files (inline comment with a fix). to_TEfficiencyisn't exported fromuproot.writing, unlike the otherto_*functions.- Two minor ones: histogram names when
fNameisNone, and Feldman-Cousins performance for large 2D efficiencies.
One design note, not blocking: the root cause of needing a hand-written reader is that containers.AsVector can't read a memberwise vector<pair<T1,T2>> when the file has no pair streamer (main fails on modern TEfficiency files with NotImplementedError: streamerless memberwise serialization of class AsVector(pair<double,double>)). Synthesizing the pair model from its template arguments there would fix this for any class with such a member, not just TEfficiency. That's fine as a follow-up though.
|
Hi @jburzy, thanks for the PR! I left a few review comments. Btw don't worry about the CI failures. Those are unrelated and should work if you rebase or merge main. |
TEfficiency's fBeta_bin_params member is a std::vector<std::pair<double,double>> that ROOT serializes memberwise. Uproot could only read it when the file contained a TStreamerInfo for pair<double,double>, which ROOT generally does not write (none of the files written by ROOT 6.28 through 6.40 that were tested have it), so TEfficiency objects from recent ROOT could not be read. - models/TEfficiency.py: hand-written Model_TEfficiency_v2 that reads fBeta_bin_params directly (memberwise; objectwise falls back to the generic path), independent of the file's streamers. It is also writable, emitting ROOT's memberwise layout and preserving the TEfficiency status bits in TObject::fBits. - behaviors/TEfficiency.py: passed/total histograms, values(), errors(), intervals(), and option accessors. Efficiencies and intervals are ported from TEfficiency.cxx for all EStatOption values, weights, posterior mode, shortest intervals, and per-bin priors (requires scipy). - writing/identify.py: to_TEfficiency() builds a writable TEfficiency from any histograms that to_writable() accepts. - extras.scipy(), scipy in the dev "extra" group, and reset_classes() reloads the new model. fBeta_bin_params is now a NumPy structured array with fields "first" and "second", rather than a list of pair objects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Compute Feldman-Cousins probabilities and likelihood ratios in log space, as ROOT does; they overflowed for totals above ~1030 entries. Each distinct (total, passed) pair is computed once and both bounds are cached. - Read objectwise vector<pair<double,double>> directly, skipping each pair's byte count, version and checksum. - Export to_TEfficiency from uproot.writing. - Name the histograms "passed"/"total" when the efficiency has no name. - Add tests for large-total Feldman-Cousins, objectwise reading (written by ROOT), the export and the histogram names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
f2032ad to
eac9fd6
Compare
|
Thank you for the review @ariostas ! I have addressed all of your comments in a new commit. |
Refs #38.
The problem
TEfficiency::fBeta_bin_paramsis astd::vector<std::pair<double,double>>, which ROOT serializes memberwise. Uproot can only read it when the file also contains aTStreamerInfoforpair<double,double>, and ROOT generally does not write one. In practice, released Uproot (5.7.0) cannot read TEfficiency objects from recent ROOT:pairstreamer in fileuproot-issue209.root)NotImplementedErroruproot-issue38c.root)NotImplementedErrorNotImplementedErrorFor each version I wrote two objects, one with default settings and one with per-bin priors (
SetBetaBinParameters); both fail. The error happens even when the vector is empty.What this PR does
models/TEfficiency.py: a hand-writtenModel_TEfficiency_v2that readsfBeta_bin_paramsdirectly, so it no longer depends on the file's streamers. The objectwise layout (very old ROOT) still uses the generic path. The model is writable. It writes ROOT's memberwise layout and keeps the TEfficiency status bits stored inTObject::fBits(Bayesian, posterior mode, shortest interval, bin prior, weights). It also names the histograms<name>_passedand<name>_total, asTEfficiency::SetNamedoes.behaviors/TEfficiency.py:.passedand.totalreturn the histograms..values(flow=False)returns the efficiencies, and.errors(flow=False)/.intervals(flow=False)return the uncertainties and interval bounds.The calculations are ported from
TEfficiency.cxx(GetEfficiency,GetEfficiencyErrorLow/Upand the interval functions) for all 9EStatOptionvalues, including weights, posterior mode, shortest intervals and per-bin priors. SciPy is needed for the uncertainties; it's imported lazily through the newuproot.extras.scipy().writing/identify.py:to_TEfficiency(name, title, passed, total, ...)builds a writable TEfficiency from anythingto_writableaccepts (uproot histograms,hist/boost-histogram,numpy.histogramtuples). It checks that the binning matches and detects weighted histograms automatically. A TEfficiency read from a file can be written back withfile["eff"] = eff.Other changes:
scipyadded to the devextragroup, andreset_classes()reloads the new model.Behavior change
fBeta_bin_paramsis now a NumPy structured array with fields"first"and"second", rather than a list of dynamically generatedpairobjects (and only for the files where the old version could read it at all).tests/test_0038_memberwise_serialization.pyis updated accordingly. Itstest_read_efficiency_without_streamerpreviously assertedNotImplementedErrorand now checks that the object reads.Not included (possible follow-ups)
containers.pyfor streamerless memberwisevector<pair<...>>in other classes.TGraphAsymmErrors, likeTEfficiency::CreateGraph.AI disclosure
Following CONTRIBUTING.md: this contribution was developed with significant help from Claude (Anthropic) via Claude Code. That covers diagnosing the problem, writing the code and tests, and running the validation against ROOT described above. I reviewed the changes, checked them on my own files, and am happy to answer questions about them.
🤖 Generated with Claude Code