Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions hist/histv7/inc/ROOT/RBinWithError.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ struct RBinWithError final {
double fSum = 0;
double fSum2 = 0;

explicit operator float() const { return fSum; }
explicit operator double() const { return fSum; }

RBinWithError &operator++()
{
fSum++;
Expand Down
20 changes: 20 additions & 0 deletions hist/histv7/inc/ROOT/RHist.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ Feedback is welcome!
*/
template <typename BinContentType>
class RHist final {
// For conversion, all other template instantiations must be a friend.
template <typename U>
friend class RHist;

friend class RHistFillContext<BinContentType>;

/// The histogram engine including the bin contents.
Expand Down Expand Up @@ -246,6 +250,22 @@ public:
return h;
}

/// Convert this histogram to a different bin content type.
///
/// There is no bounds checking to make sure that the converted values can be represented. Note that it is not
/// possible to convert to RBinWithError since the information about individual weights has been lost since filling.
///
/// Converting all bin contents can be an expensive operation, depending on the number of bins.
///
/// \return the converted object
template <typename U>
RHist<U> Convert() const
{
RHist<U> h(fEngine.template Convert<U>());
h.fStats = fStats;
return h;
}

/// Fill an entry into the histogram.
///
/// \code
Expand Down
22 changes: 22 additions & 0 deletions hist/histv7/inc/ROOT/RHistEngine.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ Feedback is welcome!
*/
template <typename BinContentType>
class RHistEngine final {
// For conversion, all other template instantiations must be a friend.
template <typename U>
friend class RHistEngine;

template <typename T, std::size_t N>
friend void Internal::SetBinContent(RHistEngine<T> &, const std::array<RBinIndex, N> &, const T &);

Expand Down Expand Up @@ -256,6 +260,24 @@ public:
return h;
}

/// Convert this histogram engine to a different bin content type.
///
/// There is no bounds checking to make sure that the converted values can be represented. Note that it is not
/// possible to convert to RBinWithError since the information about individual weights has been lost since filling.
///
/// Converting all bin contents can be an expensive operation, depending on the number of bins.
///
/// \return the converted object
template <typename U>
RHistEngine<U> Convert() const
{
RHistEngine<U> h(fAxes.Get());
for (std::size_t i = 0; i < fBinContents.size(); i++) {
h.fBinContents[i] = static_cast<U>(fBinContents[i]);
}
return h;
}

/// Whether this histogram engine type supports weighted filling.
static constexpr bool SupportsWeightedFilling = !std::is_integral_v<BinContentType>;

Expand Down
44 changes: 44 additions & 0 deletions hist/histv7/test/hist_engine.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,29 @@ TEST(RHistEngine, Clone)
}
}

TEST(RHistEngine, Convert)
{
static constexpr std::size_t Bins = 20;
const RRegularAxis axis(Bins, {0, Bins});
RHistEngine<int> engineI({axis});

engineI.Fill(-100);
for (std::size_t i = 0; i < Bins; i++) {
engineI.Fill(i);
}
engineI.Fill(100);

RHistEngine<float> engineF = engineI.Convert<float>();
ASSERT_EQ(engineF.GetNDimensions(), 1);
ASSERT_EQ(engineF.GetTotalNBins(), Bins + 2);

EXPECT_EQ(engineF.GetBinContent(RBinIndex::Underflow()), 1);
for (auto index : axis.GetNormalRange()) {
EXPECT_EQ(engineF.GetBinContent(index), 1);
}
EXPECT_EQ(engineF.GetBinContent(RBinIndex::Overflow()), 1);
}

TEST(RHistEngine, Fill)
{
static constexpr std::size_t Bins = 20;
Expand Down Expand Up @@ -423,6 +446,27 @@ TEST(RHistEngine_RBinWithError, Add)
}
}

TEST(RHistEngine_RBinWithError, Convert)
{
static constexpr std::size_t Bins = 20;
const RRegularAxis axis(Bins, {0, Bins});
RHistEngine<RBinWithError> engine({axis});

for (std::size_t i = 0; i < Bins; i++) {
engine.Fill(i, RWeight(0.1 + i * 0.03));
}

// It is not possible to convert to RBinWithError, but the other way around is fine.
RHistEngine<float> engineF = engine.Convert<float>();
RHistEngine<double> engineD = engine.Convert<double>();

for (auto index : axis.GetNormalRange()) {
double weight = 0.1 + index.GetIndex() * 0.03;
EXPECT_FLOAT_EQ(engineF.GetBinContent(index), weight);
EXPECT_EQ(engineD.GetBinContent(index), weight);
}
}

TEST(RHistEngine_RBinWithError, Fill)
{
static constexpr std::size_t Bins = 20;
Expand Down
16 changes: 16 additions & 0 deletions hist/histv7/test/hist_hist.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,22 @@ TEST(RHist, Clone)
EXPECT_EQ(histB.GetBinContent(9), 1);
}

TEST(RHist, Convert)
{
static constexpr std::size_t Bins = 20;
const RRegularAxis axis(Bins, {0, Bins});
RHist<int> histI({axis});

histI.Fill(8.5);

RHist<float> histF = histI.Convert<float>();
ASSERT_EQ(histF.GetNDimensions(), 1);
ASSERT_EQ(histF.GetTotalNBins(), Bins + 2);

EXPECT_EQ(histF.GetNEntries(), 1);
EXPECT_EQ(histF.GetBinContent(8), 1);
}

TEST(RHist, Fill)
{
static constexpr std::size_t Bins = 20;
Expand Down
Loading