Skip to content

Commit 9ff450d

Browse files
committed
[hist] Implement RHist{,Stats}::AddAtomic
1 parent 4563a53 commit 9ff450d

File tree

4 files changed

+98
-0
lines changed

4 files changed

+98
-0
lines changed

hist/histv7/inc/ROOT/RHist.hxx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,17 @@ public:
174174
fStats.Add(other.fStats);
175175
}
176176

177+
/// Add all bin contents and statistics of another histogram using atomic instructions.
178+
///
179+
/// Throws an exception if the axes configurations are not identical.
180+
///
181+
/// \param[in] other another histogram that must not be modified during the operation
182+
void AddAtomic(const RHist<BinContentType> &other)
183+
{
184+
fEngine.AddAtomic(other.fEngine);
185+
fStats.AddAtomic(other.fStats);
186+
}
187+
177188
/// Clear all bin contents and statistics.
178189
void Clear()
179190
{

hist/histv7/inc/ROOT/RHistStats.hxx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,17 @@ public:
6868
fSumWX4 += other.fSumWX4;
6969
}
7070

71+
/// Add another statistics object using atomic instructions.
72+
///
73+
/// \param[in] other another statistics object that must not be modified during the operation
74+
void AddAtomic(const RDimensionStats &other)
75+
{
76+
Internal::AtomicAdd(&fSumWX, other.fSumWX);
77+
Internal::AtomicAdd(&fSumWX2, other.fSumWX2);
78+
Internal::AtomicAdd(&fSumWX3, other.fSumWX3);
79+
Internal::AtomicAdd(&fSumWX4, other.fSumWX4);
80+
}
81+
7182
void Clear()
7283
{
7384
fSumWX = 0.0;
@@ -125,6 +136,24 @@ public:
125136
}
126137
}
127138

139+
/// Add all entries from another statistics object using atomic instructions.
140+
///
141+
/// Throws an exception if the number of dimensions are not identical.
142+
///
143+
/// \param[in] other another statistics object that must not be modified during the operation
144+
void AddAtomic(const RHistStats &other)
145+
{
146+
if (fDimensionStats.size() != other.fDimensionStats.size()) {
147+
throw std::invalid_argument("number of dimensions not identical in Add");
148+
}
149+
Internal::AtomicAdd(&fNEntries, other.fNEntries);
150+
Internal::AtomicAdd(&fSumW, other.fSumW);
151+
Internal::AtomicAdd(&fSumW2, other.fSumW2);
152+
for (std::size_t i = 0; i < fDimensionStats.size(); i++) {
153+
fDimensionStats[i].AddAtomic(other.fDimensionStats[i]);
154+
}
155+
}
156+
128157
/// Clear this statistics object.
129158
void Clear()
130159
{

hist/histv7/test/hist_hist.cxx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,23 @@ TEST(RHist, Add)
5252
EXPECT_EQ(histA.GetBinContent(RBinIndex(9)), 1);
5353
}
5454

55+
TEST(RHist, AddAtomic)
56+
{
57+
static constexpr std::size_t Bins = 20;
58+
const RRegularAxis axis(Bins, {0, Bins});
59+
RHist<int> histA({axis});
60+
RHist<int> histB({axis});
61+
62+
histA.Fill(8.5);
63+
histB.Fill(9.5);
64+
65+
histA.AddAtomic(histB);
66+
67+
EXPECT_EQ(histA.GetNEntries(), 2);
68+
EXPECT_EQ(histA.GetBinContent(RBinIndex(8)), 1);
69+
EXPECT_EQ(histA.GetBinContent(RBinIndex(9)), 1);
70+
}
71+
5572
TEST(RHist, Clear)
5673
{
5774
static constexpr std::size_t Bins = 20;

hist/histv7/test/hist_stats.cxx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,47 @@ TEST(RHistStats, AddDifferent)
123123
EXPECT_THROW(statsA.Add(statsB), std::invalid_argument);
124124
}
125125

126+
TEST(RHistStats, AddAtomic)
127+
{
128+
RHistStats statsA(2);
129+
RHistStats statsB(2);
130+
131+
static constexpr std::size_t Entries = 20;
132+
for (std::size_t i = 0; i < Entries; i++) {
133+
statsA.Fill(i, 2 * i);
134+
statsB.Fill(2 * i, 3 * i, RWeight(0.1 + 0.03 * i));
135+
}
136+
137+
statsA.AddAtomic(statsB);
138+
139+
ASSERT_EQ(statsA.GetNEntries(), 2 * Entries);
140+
EXPECT_DOUBLE_EQ(statsA.GetSumW(), 27.7);
141+
EXPECT_DOUBLE_EQ(statsA.GetSumW2(), 23.563);
142+
143+
{
144+
const auto &dimensionStats = statsA.GetDimensionStats(/*=0*/);
145+
EXPECT_FLOAT_EQ(dimensionStats.fSumWX, 376.2);
146+
EXPECT_FLOAT_EQ(dimensionStats.fSumWX2, 7790);
147+
EXPECT_FLOAT_EQ(dimensionStats.fSumWX3, 200019.84);
148+
EXPECT_FLOAT_EQ(dimensionStats.fSumWX4, 5846915.6);
149+
}
150+
{
151+
const auto &dimensionStats = statsA.GetDimensionStats(1);
152+
EXPECT_FLOAT_EQ(dimensionStats.fSumWX, 659.3);
153+
EXPECT_FLOAT_EQ(dimensionStats.fSumWX2, 21850);
154+
EXPECT_FLOAT_EQ(dimensionStats.fSumWX3, 842029.46);
155+
EXPECT_FLOAT_EQ(dimensionStats.fSumWX4, 35754169.6);
156+
}
157+
}
158+
159+
TEST(RHistStats, AddAtomicDifferent)
160+
{
161+
RHistStats statsA(2);
162+
RHistStats statsB(3);
163+
164+
EXPECT_THROW(statsA.AddAtomic(statsB), std::invalid_argument);
165+
}
166+
126167
TEST(RHistStats, Clear)
127168
{
128169
RHistStats stats(2);

0 commit comments

Comments
 (0)