diff --git a/hist/hist/src/TAxis.cxx b/hist/hist/src/TAxis.cxx index 5b6c0ae65dff9..999ceebbe1fbd 100644 --- a/hist/hist/src/TAxis.cxx +++ b/hist/hist/src/TAxis.cxx @@ -477,15 +477,38 @@ Int_t TAxis::GetLast() const //////////////////////////////////////////////////////////////////////////////// /// Return center of bin +/// +/// If fXmin is -inf, it will return -inf even if fXmax is finite +/// If fXmax is +inf, it will return +inf even if fXmin is finite Double_t TAxis::GetBinCenter(Int_t bin) const { Double_t binwidth; if (!fXbins.fN || bin<1 || bin>fNbins) { binwidth = (fXmax - fXmin) / Double_t(fNbins); + if (std::isinf(binwidth)) { + if (std::isfinite(fXmin)) + return fXmax; + else if (std::isfinite(fXmax)) + return fXmin; + else if (fXmin == -std::numeric_limits::infinity() && fXmax == std::numeric_limits::infinity()) + return 0.; + else + return std::numeric_limits::quiet_NaN(); + } return fXmin + (bin - 0.5) * binwidth; } else { binwidth = fXbins.fArray[bin] - fXbins.fArray[bin-1]; + if (std::isinf(binwidth)) { + if (std::isfinite(fXbins.fArray[bin-1])) + return fXbins.fArray[bin]; + else if (std::isfinite(fXbins.fArray[bin])) + return fXbins.fArray[bin-1]; + else if (fXbins.fArray[bin-1] == -std::numeric_limits::infinity() && fXbins.fArray[bin] == std::numeric_limits::infinity()) + return 0.; + else + return std::numeric_limits::quiet_NaN(); + } return fXbins.fArray[bin-1] + 0.5*binwidth; } } diff --git a/hist/hist/src/TH1Merger.cxx b/hist/hist/src/TH1Merger.cxx index 78db015d8331a..da0d4f2e0ff37 100644 --- a/hist/hist/src/TH1Merger.cxx +++ b/hist/hist/src/TH1Merger.cxx @@ -714,6 +714,17 @@ Bool_t TH1Merger::AutoP2Merge() Double_t xu = hist->GetBinCenter(ibin); Int_t jbin = fH0->FindBin(xu); + if (jbin == fH0->GetXaxis()->GetNbins() + 1 || jbin == 0) { + auto eps = 1e-12; + // if upper/lower edge is +/-infinite, the bin center is +/-infinite if the other edge is finite, + // so FindBin is in overflow/underflow + // Check close to the lower or upper edges instead of the bin center in these cases + if (std::isinf(hist->GetXaxis()->GetBinUpEdge(ibin))) { + jbin = fH0->GetXaxis()->FindBin(hist->GetXaxis()->GetBinLowEdge(ibin) + eps); + } else if (std::isinf(hist->GetXaxis()->GetBinLowEdge(ibin))) { + jbin = fH0->GetXaxis()->FindBin(hist->GetXaxis()->GetBinUpEdge(ibin) - eps); + } + } fH0->AddBinContent(jbin, cu); if (fH0->fSumw2.fN) diff --git a/hist/hist/src/TH1Merger.h b/hist/hist/src/TH1Merger.h index ba8d4fe54aef8..a7e0c2dd5a730 100644 --- a/hist/hist/src/TH1Merger.h +++ b/hist/hist/src/TH1Merger.h @@ -16,6 +16,7 @@ #include "TProfile2D.h" #include "TProfile3D.h" #include "TList.h" +#include class TH1Merger { @@ -41,13 +42,25 @@ class TH1Merger { return outAxis.FindFixBin(inAxis.GetBinCenter(ibin)); } - // find bin number estending the axis + /// find bin number extending the axis static Int_t FindBinNumber(Int_t ibin, const TAxis & inAxis, TAxis & outAxis) { // should I ceck in case of underflow/overflow if underflow/overflow values of input axis // outside output axis ? if (ibin == 0 ) return 0; // return underflow if (ibin == inAxis.GetNbins()+1 ) return outAxis.GetNbins()+1; // return overflow - return outAxis.FindBin(inAxis.GetBinCenter(ibin)); + auto binOut = outAxis.FindBin(inAxis.GetBinCenter(ibin)); + if (binOut == outAxis.GetNbins() + 1 || binOut == 0) { + auto eps = 1e-12; + // if upper/lower edge is +/-infinite, the bin center is +/-infinite if the other edge is finite, + // so FindBin is in overflow/underflow + // Check close to the lower or upper edges instead of the bin center in these cases + if (std::isinf(inAxis.GetBinUpEdge(ibin))) { + binOut = outAxis.FindBin(inAxis.GetBinLowEdge(ibin) + eps); + } else if (std::isinf(inAxis.GetBinLowEdge(ibin))) { + binOut = outAxis.FindBin(inAxis.GetBinUpEdge(ibin) - eps); + } + } + return binOut; } // Function to find if axis label list has duplicates diff --git a/hist/hist/src/TH2.cxx b/hist/hist/src/TH2.cxx index 43d773a7c8311..2e32a118c0471 100644 --- a/hist/hist/src/TH2.cxx +++ b/hist/hist/src/TH2.cxx @@ -2293,7 +2293,18 @@ TH1D *TH2::DoProjection(bool onX, const char *name, Int_t firstbin, Int_t lastbi } } // find corresponding bin number in h1 for outbin - Int_t binOut = h1->GetXaxis()->FindBin( outAxis->GetBinCenter(outbin) ); + Int_t binOut = h1->GetXaxis()->FindBin(outAxis->GetBinCenter(outbin)); + if (binOut == h1->GetXaxis()->GetNbins() + 1 || binOut == 0) { + auto eps = 1e-12; + // if upper/lower edge is +/-infinite, the bin center is +/-infinite if the other edge is finite, + // so FindBin is in overflow/underflow + // Check close to the lower or upper edges instead of the bin center in these cases + if (std::isinf(outAxis->GetBinUpEdge(outbin))) { + binOut = h1->GetXaxis()->FindBin(outAxis->GetBinLowEdge(outbin) + eps); + } else if (std::isinf(outAxis->GetBinLowEdge(outbin))) { + binOut = h1->GetXaxis()->FindBin(outAxis->GetBinUpEdge(outbin) - eps); + } + } h1->SetBinContent(binOut ,cont); if (computeErrors) h1->SetBinError(binOut,TMath::Sqrt(err2)); // sum all content diff --git a/hist/hist/src/TH3.cxx b/hist/hist/src/TH3.cxx index 7cda8abb37676..b8d3f276c3e85 100644 --- a/hist/hist/src/TH3.cxx +++ b/hist/hist/src/TH3.cxx @@ -2058,14 +2058,25 @@ TH1D *TH3::DoProject1D(const char* name, const char * title, const TAxis* projX, } } } - Int_t ix = h1->FindBin( projX->GetBinCenter(ixbin) ); + Int_t ix = h1->FindBin(projX->GetBinCenter(ixbin)); + if (ix == h1->GetNbinsX() + 1 || ix == 0) { + auto eps = 1e-12; + // if upper/lower edge is +/-infinite, the bin center is +/-infinite if the other edge is finite, + // so FindBin is in overflow/underflow + // Check close to the lower or upper edges instead of the bin center in these cases + if (std::isinf(projX->GetBinUpEdge(ixbin))) { + ix = h1->FindBin(projX->GetBinLowEdge(ixbin) + eps); + } else if (std::isinf(projX->GetBinLowEdge(ixbin))) { + ix = h1->FindBin(projX->GetBinUpEdge(ixbin) - eps); + } + } h1->SetBinContent(ix ,cont); if (computeErrors) h1->SetBinError(ix, TMath::Sqrt(err2) ); // sum all content totcont += cont; } - if ( labels ) h1->GetXaxis()->SetCanExtend(extendable); + if (labels) h1->GetXaxis()->SetCanExtend(extendable); // since we use a combination of fill and SetBinError we need to reset and recalculate the statistics // for weighted histograms otherwise sumw2 will be wrong. @@ -2267,11 +2278,32 @@ TH2D *TH3::DoProject2D(const char* name, const char * title, const TAxis* projX, for (ixbin=0;ixbin<=1+projX->GetNbins();ixbin++) { if ( projX->TestBit(TAxis::kAxisRange) && ( ixbin < ixmin || ixbin > ixmax )) continue; - Int_t ix = h2->GetYaxis()->FindBin( projX->GetBinCenter(ixbin) ); + Int_t ix = h2->GetYaxis()->FindBin(projX->GetBinCenter(ixbin)); + auto eps = 1e-12; + if (ix == h2->GetYaxis()->GetNbins() + 1 || ix == 0) { + // if upper/lower edge is +/-infinite, the bin center is +/-infinite if the other edge is finite, + // so FindBin is in overflow/underflow + // Check close to the lower or upper edges instead of the bin center in these cases + if (std::isinf(projX->GetBinUpEdge(ixbin))) { + ix = h2->GetYaxis()->FindBin(projX->GetBinLowEdge(ixbin) + eps); + } else if (std::isinf(projX->GetBinLowEdge(ixbin))) { + ix = h2->GetYaxis()->FindBin(projX->GetBinUpEdge(ixbin) - eps); + } + } for (iybin=0;iybin<=1+projY->GetNbins();iybin++) { if ( projY->TestBit(TAxis::kAxisRange) && ( iybin < iymin || iybin > iymax )) continue; Int_t iy = h2->GetXaxis()->FindBin( projY->GetBinCenter(iybin) ); + if (iy == h2->GetXaxis()->GetNbins() + 1 || iy == 0) { + // if upper/lower edge is +/-infinite, the bin center is +/-infinite if the other edge is finite, + // so FindBin is in overflow/underflow + // Check close to the lower or upper edges instead of the bin center in these cases + if (std::isinf(projY->GetBinUpEdge(iybin))) { + iy = h2->GetXaxis()->FindBin(projY->GetBinLowEdge(iybin) + eps); + } else if (std::isinf(projY->GetBinLowEdge(iybin))) { + iy = h2->GetXaxis()->FindBin(projY->GetBinUpEdge(iybin) - eps); + } + } Double_t cont = 0; Double_t err2 = 0; diff --git a/hist/hist/test/test_TH1.cxx b/hist/hist/test/test_TH1.cxx index 73d4ba9f5cef1..4cdbd50c485f6 100644 --- a/hist/hist/test/test_TH1.cxx +++ b/hist/hist/test/test_TH1.cxx @@ -10,6 +10,7 @@ #include #include #include +#include #include "ROOT/TestSupport.hxx" @@ -320,3 +321,23 @@ TEST(TAxis, EqualBinEdges) { ROOT_EXPECT_ERROR(TAxis _({1, 1}), "TAxis::Set", "bins must be in increasing order"); } + +TEST(TH2, ProjectionYInfiniteUpperEdge) +{ + Double_t xedges[] = {0., 1.}; + Double_t yedges[] = {1., std::numeric_limits::infinity()}; + TH2D h("h_inf", "h_inf;X;Y", 1, xedges, 1, yedges); + h.SetBinContent(1, 1, 11.); + auto projY = h.ProjectionY(); + EXPECT_EQ(projY->GetBinContent(1), h.Integral(1, 1, 1, 1)); +} + +TEST(TH2, ProjectionYInfiniteLowerEdge) +{ + Double_t xedges[] = {0, 1.}; + Double_t yedges[] = {-std::numeric_limits::infinity(), 2}; + TH2D h("h_inf", "h_inf;X;Y", 1, xedges, 1, yedges); + h.SetBinContent(1, 1, 11.); + auto projY = h.ProjectionY(); + EXPECT_EQ(projY->GetBinContent(1), h.Integral(1, 1, 1, 1)); +}