Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
Rebin2DHelpers.h
Go to the documentation of this file.
1// @(#)root/hist:$Id$
2// Author: Jonas Rembser, CERN 09/2026
3
4/*************************************************************************
5 * Copyright (C) 1995-2026, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#ifndef ROOT_Rebin2DHelpers
13#define ROOT_Rebin2DHelpers
14
15// Internal helpers shared by TH2::Rebin2D and TProfile2D::Rebin2D.
16
17#include "TAxis.h"
18#include "TH1.h"
19#include "TMath.h"
20
21#include <initializer_list>
22#include <utility>
23#include <vector>
24
25namespace ROOT {
26namespace Internal {
27
28/// Define the axis of the rebinned histogram: either from the user-provided
29/// bin edges, or by merging groups of ngroup bins of the old axis. The value
30/// of xmax is the (possibly truncated) upper limit for the uniform-bin case.
32 Double_t xmax, TAxis &newAxis)
33{
34 if (userBins) {
35 newAxis.Set(nnew, userBins);
36 } else if (oldAxis.GetXbins()->GetSize() > 0) {
37 std::vector<Double_t> edges(nnew + 1);
38 for (Int_t i = 0; i <= nnew; ++i)
39 edges[i] = oldAxis.GetBinLowEdge(1 + i * ngroup);
40 newAxis.Set(nnew, edges.data());
41 } else {
42 newAxis.Set(nnew, xmin, xmax);
43 }
44}
45
46/// Map each cell of the old axis (including underflow 0 and overflow n+1) to
47/// the cell of the new axis that contains its bin center. Old bins outside
48/// the new axis range are mapped to the new under-/overflow.
49inline std::vector<Int_t> MakeRebinMap(const TAxis &oldAxis, const TAxis &newAxis)
50{
51 const Int_t nOld = oldAxis.GetNbins();
52 std::vector<Int_t> map(nOld + 2);
53 map[0] = 0;
54 map[nOld + 1] = newAxis.GetNbins() + 1;
55 for (Int_t o = 1; o <= nOld; ++o)
56 map[o] = newAxis.FindFixBin(oldAxis.GetBinCenter(o));
57 return map;
58}
59
60/// Warn when a bin edge of the new axis that lies inside the old axis range
61/// does not line up with a bin edge of the old axis: the entries of the old
62/// bin that is split cannot be distributed correctly.
63inline void WarnAboutMisalignedEdges(const TAxis &oldAxis, const TAxis &newAxis, TH1 &hist, const char *where)
64{
65 for (Int_t b = 0; b <= newAxis.GetNbins(); ++b) {
66 const Double_t edge = newAxis.GetBinUpEdge(b); // GetBinUpEdge(0) is the axis minimum
67 if (edge <= oldAxis.GetXmin() || edge >= oldAxis.GetXmax())
68 continue;
69 const Int_t o = oldAxis.FindFixBin(edge);
70 const Double_t tol = TMath::Max(1.E-8 * oldAxis.GetBinWidth(o), 1.E-16);
71 if (!TMath::AreEqualAbs(edge, oldAxis.GetBinLowEdge(o), tol) &&
72 !TMath::AreEqualAbs(edge, oldAxis.GetBinUpEdge(o), tol)) {
73 hist.Warning(where,
74 "Bin edge %d of rebinned histogram does not match any bin edges of the old histogram. "
75 "Result can be inconsistent",
76 b);
77 }
78 }
79}
80
81/// The definition of one axis of the rebinned histogram.
83 Int_t nNewBins = 0; ///< number of bins of the rebinned axis
84 TAxis newAxis; ///< the rebinned axis
85 std::vector<Int_t> binMap; ///< map from old cell (0..n+1) to new cell
86 bool truncated = false; ///< the group count does not divide the old bin count: top bins move to the overflow
87};
88
89/// Validate the rebinning parameters for one axis and fill the definition of
90/// the rebinned axis and the map from old to new bins. For an axis with
91/// user-provided bin edges, ngroup is directly the new number of bins,
92/// otherwise the old bins are merged in groups of ngroup. Returns false on an
93/// invalid group count.
94inline bool SetupRebinnedAxis(const TAxis &oldAxis, Int_t ngroup, const Double_t *userBins, char axisName, TH1 &hist,
95 const char *where, RebinnedAxisInfo &info)
96{
97 const Int_t nOldBins = oldAxis.GetNbins();
99 hist.Error(where, "Illegal value of n%cgroup=%d", axisName, ngroup);
100 return false;
101 }
102 Double_t newMax = oldAxis.GetXmax();
103 if (userBins) {
104 info.nNewBins = ngroup;
105 } else {
106 info.nNewBins = nOldBins / ngroup;
107 if (info.nNewBins * ngroup != nOldBins) {
108 hist.Warning(where, "n%cgroup=%d is not an exact divider of n%cbins=%d.", axisName, ngroup, axisName,
109 nOldBins);
110 // the top limit is truncated and the top bins move to the overflow
111 newMax = oldAxis.GetBinUpEdge(info.nNewBins * ngroup);
112 info.truncated = true;
113 }
114 }
115 DefineRebinnedAxis(oldAxis, ngroup, info.nNewBins, userBins, oldAxis.GetXmin(), newMax, info.newAxis);
116 if (userBins)
118 info.binMap = MakeRebinMap(oldAxis, info.newAxis);
119 return true;
120}
121
122/// Warn when the range of the new axis extends beyond the old one while the
123/// corresponding flow bins hold content: that content stays in the flow bins
124/// and is not redistributed into the range of the new axis. The flow bins of
125/// the mapped axis are addressed as flowIndex * stride + k * otherStride for
126/// the nOther cells of the other axis.
128 char axisName, const Double_t *bins, Int_t stride, Int_t nOther,
129 Int_t otherStride, TH1 &hist, const char *where)
130{
131 if (!userBins)
132 return;
133 auto flowContent = [&](Int_t flowIndex) {
134 Double_t sum = 0.;
135 for (Int_t k = 0; k < nOther; ++k)
136 sum += bins[flowIndex * stride + k * otherStride];
137 return sum;
138 };
139 if (userBins[0] < oldAxis.GetXmin() && flowContent(0) != 0.)
140 hist.Warning(where, "underflow entries for %c axis will not be used when rebinning", axisName);
141 if (userBins[info.nNewBins] > oldAxis.GetXmax() && flowContent(oldAxis.GetNbins() + 1) != 0.)
142 hist.Warning(where, "overflow entries for %c axis will not be used when rebinning", axisName);
143}
144
145/// Apply the axes of the rebinned histogram, using explicit bin edges if any
146/// of the two axes has non-uniform bins.
147inline void SetRebinnedBins2D(TH1 &hnew, const TAxis &newXaxis, const TAxis &newYaxis)
148{
149 const Int_t nx = newXaxis.GetNbins();
150 const Int_t ny = newYaxis.GetNbins();
151 if (newXaxis.GetXbins()->GetSize() > 0 || newYaxis.GetXbins()->GetSize() > 0) {
152 std::vector<Double_t> xEdges(nx + 1);
153 std::vector<Double_t> yEdges(ny + 1);
154 for (Int_t i = 0; i <= nx; ++i)
155 xEdges[i] = newXaxis.GetBinUpEdge(i);
156 for (Int_t i = 0; i <= ny; ++i)
157 yEdges[i] = newYaxis.GetBinUpEdge(i);
158 hnew.SetBins(nx, xEdges.data(), ny, yEdges.data()); // changes also errors array (if any)
159 } else {
160 hnew.SetBins(nx, newXaxis.GetXmin(), newXaxis.GetXmax(), ny, newYaxis.GetXmin(), newYaxis.GetXmax());
161 }
162}
163
164/// Accumulate every old cell (including under- and overflow) into the new
165/// cell given by the per-axis bin maps, for each (old array, new array) pair.
166/// The new arrays must be zero-initialized by the caller.
167inline void MergeRebinnedCells(Int_t nOldX, Int_t nOldY, Int_t nNewX, const std::vector<Int_t> &mapX,
168 const std::vector<Int_t> &mapY,
169 std::initializer_list<std::pair<const Double_t *, Double_t *>> arrays)
170{
171 for (Int_t oy = 0; oy < nOldY + 2; ++oy) {
172 for (Int_t ox = 0; ox < nOldX + 2; ++ox) {
173 const Int_t oldBin = ox + (nOldX + 2) * oy;
174 const Int_t newBin = mapX[ox] + (nNewX + 2) * mapY[oy];
175 for (auto const &arr : arrays)
176 arr.second[newBin] += arr.first[oldBin];
177 }
178 }
179}
180
181} // namespace Internal
182} // namespace ROOT
183
184#endif
#define b(i)
Definition RSha256.hxx:100
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
float xmin
float xmax
Class to manage histogram axis.
Definition TAxis.h:32
virtual void Set(Int_t nbins, Double_t xmin, Double_t xmax)
Initialize axis with fix bins.
Definition TAxis.cxx:790
virtual Int_t FindFixBin(Double_t x) const
Find bin number corresponding to abscissa x
Definition TAxis.cxx:422
Int_t GetNbins() const
Definition TAxis.h:127
virtual Double_t GetBinUpEdge(Int_t bin) const
Return up edge of bin.
Definition TAxis.cxx:532
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:109
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1082
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1096
void DefineRebinnedAxis(const TAxis &oldAxis, Int_t ngroup, Int_t nnew, const Double_t *userBins, Double_t xmin, Double_t xmax, TAxis &newAxis)
Define the axis of the rebinned histogram: either from the user-provided bin edges,...
void WarnAboutUnusedFlowContent(const TAxis &oldAxis, const RebinnedAxisInfo &info, const Double_t *userBins, char axisName, const Double_t *bins, Int_t stride, Int_t nOther, Int_t otherStride, TH1 &hist, const char *where)
Warn when the range of the new axis extends beyond the old one while the corresponding flow bins hold...
void WarnAboutMisalignedEdges(const TAxis &oldAxis, const TAxis &newAxis, TH1 &hist, const char *where)
Warn when a bin edge of the new axis that lies inside the old axis range does not line up with a bin ...
std::vector< Int_t > MakeRebinMap(const TAxis &oldAxis, const TAxis &newAxis)
Map each cell of the old axis (including underflow 0 and overflow n+1) to the cell of the new axis th...
void SetRebinnedBins2D(TH1 &hnew, const TAxis &newXaxis, const TAxis &newYaxis)
Apply the axes of the rebinned histogram, using explicit bin edges if any of the two axes has non-uni...
void MergeRebinnedCells(Int_t nOldX, Int_t nOldY, Int_t nNewX, const std::vector< Int_t > &mapX, const std::vector< Int_t > &mapY, std::initializer_list< std::pair< const Double_t *, Double_t * > > arrays)
Accumulate every old cell (including under- and overflow) into the new cell given by the per-axis bin...
bool SetupRebinnedAxis(const TAxis &oldAxis, Int_t ngroup, const Double_t *userBins, char axisName, TH1 &hist, const char *where, RebinnedAxisInfo &info)
Validate the rebinning parameters for one axis and fill the definition of the rebinned axis and the m...
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:249
Bool_t AreEqualAbs(Double_t af, Double_t bf, Double_t epsilon)
Comparing floating points.
Definition TMath.h:421
The definition of one axis of the rebinned histogram.
Int_t nNewBins
number of bins of the rebinned axis
TAxis newAxis
the rebinned axis
bool truncated
the group count does not divide the old bin count: top bins move to the overflow
std::vector< Int_t > binMap
map from old cell (0..n+1) to new cell
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2335