Skip to content

[hist] Reset all statistics in TProfile2D/3D::Divide - #23775

Draft
Elvand-Lie wants to merge 1 commit into
root-project:masterfrom
Elvand-Lie:fix/tprofile-divide-stats
Draft

Elvand-Lie wants to merge 1 commit into
root-project:masterfrom
Elvand-Lie:fix/tprofile-divide-stats

Conversation

@Elvand-Lie

Copy link
Copy Markdown
Contributor

This Pull request:

Changes or fixes:

TProfile2D::Divide and TProfile3D::Divide return wrong statistics for the Y and Z axes:

TProfile3D num("num", "", 4, 0, 4, 5, 0, 10, 3, 0, 30);
TProfile3D den("den", "", 4, 0, 4, 5, 0, 10, 3, 0, 30);
TProfile3D res("res", "", 4, 0, 4, 5, 0, 10, 3, 0, 30);
num.Fill(0.5, 1., 25., 2.);
den.Fill(0.5, 1., 25., 1.);
res.Divide(&num, &den);
res.GetMean(3); // 5 on master; the only filled bin is at z = 25

If res already held a point at (3.5, 9, 5) before the division, master gives GetMean(2) = 5.5 and GetMean(3) = 7.5 instead of 1 and 25. TProfile2D gives GetMean(2) = 5.5 in the same situation.

There are three causes:

  • Both Divide overloads of TProfile2D and TProfile3D reset only fEntries, fTsumw, fTsumw2, fTsumwx and fTsumwx2. The loop then adds the new Y and Z contributions (in 3D also XZ, YZ and T) to the old sums. Divide(h1) always divides a filled profile, so it is always affected. The 1D TProfile::Divide(h1) already resets all of its sums.
  • TProfile3D::Divide(h1, h2) takes the Z bin center at the Y bin index: fZaxis.GetBinCenter(biny).
  • TProfile3D::Divide(h1) accumulates fTsumwz += u and fTsumwz2 += u*z instead of u*z and u*z*z.

The fix resets every sum each loop accumulates, uses binz, and corrects the two Z moments.

Four tests in hist/hist/test/test_TProfile.cxx cover both classes and both overloads. They divide into filled targets, use axes whose X, Y and Z bin centers differ, and check the Z standard deviation.

  • The four new tests fail on master and pass with this change.
  • ctest -R '^gtest-hist-hist-' passes: 32 tests, 0 failures, on Linux with a minimal build.
  • Not run: the full ROOT test suite, roottest, and platforms other than Linux.

Checklist:

  • tested changes locally
  • updated the docs (if necessary)

Codex (gpt-6.1-sol) implemented the fix and the tests; Claude Code (claude-opus-5-5) found the bugs and validated them.

Both Divide overloads rebuilt higher-axis moments on top of the target's
old statistics. Reset every sum their bin loops accumulate before
rebuilding the result.

In TProfile3D, use the Z bin index in the two-input overload and accumulate
the Z first and second moments correctly in the single-input overload.

Cover both overloads with distinct axis centers and previously filled
targets. Also check an empty 3D target and the in-place Z variance.

Assisted-by: codex:gpt-6.1-sol
Assisted-by: claude-code:claude-opus-5-5

This branch has not been deployed

No deployments
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.

3 participants