Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RDFActionHelpers.cxx
Go to the documentation of this file.
1// Author: Enrico Guiraud, Danilo Piparo CERN 12/2016
2
3/*************************************************************************
4 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
12
13#include "ROOT/RDF/Utils.hxx" // CacheLineStep
14
15#include <RtypesCore.h>
16#include <cmath>
17#include <cstddef>
18#include <TStatistic.h>
19
20namespace ROOT {
21namespace Internal {
22namespace RDF {
23
25{
26 *h = TStatistic();
27}
28// cannot safely re-initialize variations of the result, hence error out
30{
31 throw std::runtime_error(
32 "A systematic variation was requested for a custom Fill action, but the type of the object to be filled does "
33 "not implement a Reset method, so we cannot safely re-initialize variations of the result. Aborting.");
34}
35
37{
38 h->SetDirectory(nullptr);
39}
41
42CountHelper::CountHelper(const std::shared_ptr<ULong64_t> &resultCount, const unsigned int nSlots)
43 : fResultCount(resultCount), fCounts(nSlots, 0)
44{
45}
46
47void CountHelper::Exec(unsigned int slot)
48{
49 fCounts[slot]++;
50}
51
52void CountHelper::Finalize()
53{
54 *fResultCount = 0;
55 for (auto &c : fCounts) {
56 *fResultCount += c;
57 }
58}
59
60ULong64_t &CountHelper::PartialUpdate(unsigned int slot)
61{
62 return fCounts[slot];
63}
64
65void BufferedFillHelper::UpdateMinMax(unsigned int slot, double v)
66{
67 auto &thisMin = fMin[slot * CacheLineStep<BufEl_t>()];
68 auto &thisMax = fMax[slot * CacheLineStep<BufEl_t>()];
69 thisMin = std::min(thisMin, v);
70 thisMax = std::max(thisMax, v);
71}
72
73BufferedFillHelper::BufferedFillHelper(const std::shared_ptr<Hist_t> &h, const unsigned int nSlots)
74 : fResultHist(h), fNSlots(nSlots), fBufSize(fgTotalBufSize / nSlots), fPartialHists(fNSlots),
75 fMin(nSlots * CacheLineStep<BufEl_t>(), std::numeric_limits<BufEl_t>::max()),
76 fMax(nSlots * CacheLineStep<BufEl_t>(), std::numeric_limits<BufEl_t>::lowest())
77{
78 fBuffers.reserve(fNSlots);
79 fWBuffers.reserve(fNSlots);
80 for (unsigned int i = 0; i < fNSlots; ++i) {
81 Buf_t v;
82 v.reserve(fBufSize);
83 fBuffers.emplace_back(v);
84 fWBuffers.emplace_back(v);
85 }
86}
87
88void BufferedFillHelper::Exec(unsigned int slot, double v)
89{
91 fBuffers[slot].emplace_back(v);
92}
93
94void BufferedFillHelper::Exec(unsigned int slot, double v, double w)
95{
97 fBuffers[slot].emplace_back(v);
98 fWBuffers[slot].emplace_back(w);
99}
100
101Hist_t &BufferedFillHelper::PartialUpdate(unsigned int slot)
102{
104 // TODO it is inefficient to re-create the partial histogram everytime the callback is called
105 // ideally we could incrementally fill it with the latest entries in the buffers
106 partialHist = std::make_unique<Hist_t>(*fResultHist);
107 auto weights = fWBuffers[slot].empty() ? nullptr : fWBuffers[slot].data();
108 partialHist->FillN(fBuffers[slot].size(), fBuffers[slot].data(), weights);
109 return *partialHist;
110}
111
112void BufferedFillHelper::Finalize()
113{
114 for (unsigned int i = 0; i < fNSlots; ++i) {
115 if (!fWBuffers[i].empty() && fBuffers[i].size() != fWBuffers[i].size()) {
116 throw std::runtime_error("Cannot fill weighted histogram with values in containers of different sizes.");
117 }
118 }
119
120 BufEl_t globalMin = *std::min_element(fMin.begin(), fMin.end());
121 BufEl_t globalMax = *std::max_element(fMax.begin(), fMax.end());
122
123 if (fResultHist->CanExtendAllAxes() && globalMin != std::numeric_limits<BufEl_t>::max() &&
124 globalMax != std::numeric_limits<BufEl_t>::lowest()) {
125 fResultHist->SetBins(fResultHist->GetNbinsX(), globalMin, globalMax);
126 }
127
128 for (unsigned int i = 0; i < fNSlots; ++i) {
129 auto weights = fWBuffers[i].empty() ? nullptr : fWBuffers[i].data();
130 fResultHist->FillN(fBuffers[i].size(), fBuffers[i].data(), weights);
131 }
132}
133
134MeanHelper::MeanHelper(const std::shared_ptr<double> &meanVPtr, const unsigned int nSlots)
136{
137}
138
139void MeanHelper::Exec(unsigned int slot, double v)
140{
141 fCounts[slot]++;
142 // Kahan Sum:
143 double y = v - fCompensations[slot];
144 double t = fSums[slot] + y;
145 fCompensations[slot] = (t - fSums[slot]) - y;
146 fSums[slot] = t;
147}
148
149void MeanHelper::Finalize()
150{
151 double sumOfSums = 0;
152 // Kahan Sum:
153 double compensation(0);
154 double y(0);
155 double t(0);
156 for (auto &m : fSums) {
157 y = m - compensation;
158 t = sumOfSums + y;
159 compensation = (t - sumOfSums) - y;
160 sumOfSums = t;
161 }
163 for (auto &c : fCounts)
164 sumOfCounts += c;
166}
167
168double &MeanHelper::PartialUpdate(unsigned int slot)
169{
170 fPartialMeans[slot] = fSums[slot] / fCounts[slot];
171 return fPartialMeans[slot];
172}
173
174StdDevHelper::StdDevHelper(const std::shared_ptr<double> &meanVPtr, const unsigned int nSlots)
175 : fNSlots(nSlots), fResultStdDev(meanVPtr), fCounts(nSlots, 0), fMeans(nSlots, 0), fDistancesfromMean(nSlots, 0)
176{
177}
178
179void StdDevHelper::Exec(unsigned int slot, double v)
180{
181 // Applies the Welford's algorithm to the stream of values received by the thread
182 auto count = ++fCounts[slot];
183 auto delta = v - fMeans[slot];
184 auto mean = fMeans[slot] + delta / count;
185 auto delta2 = v - mean;
186 auto distance = fDistancesfromMean[slot] + delta * delta2;
187
188 fCounts[slot] = count;
189 fMeans[slot] = mean;
191}
192
193void StdDevHelper::Finalize()
194{
195 // Evaluates and merges the partial result of each set of data to get the overall standard deviation.
196 double totalElements = 0;
197 for (auto c : fCounts) {
198 totalElements += c;
199 }
200 if (totalElements == 0 || totalElements == 1) {
201 // Std deviation is not defined for 1 element.
202 *fResultStdDev = 0;
203 return;
204 }
205
206 double overallMean = 0;
207 for (unsigned int i = 0; i < fNSlots; ++i) {
208 overallMean += fCounts[i] * fMeans[i];
209 }
211
212 double variance = 0;
213 for (unsigned int i = 0; i < fNSlots; ++i) {
214 if (fCounts[i] == 0) {
215 continue;
216 }
217 auto setVariance = fDistancesfromMean[i] / (fCounts[i]);
218 variance += (fCounts[i]) * (setVariance + std::pow((fMeans[i] - overallMean), 2));
219 }
220
222 *fResultStdDev = std::sqrt(variance);
223}
224
225MedianHelper::MedianHelper(const std::shared_ptr<double> &meanVPtr, const unsigned int nSlots)
226 : fResult(meanVPtr), fBuffers(nSlots, std::vector<double>())
227{
228}
229
230void MedianHelper::Exec(unsigned int slot, double v)
231{
232 fBuffers[slot].push_back(v);
233}
234
235void MedianHelper::Finalize()
236{
237 std::vector<double> fullBuffer;
238 std::size_t fullBufferSize = 0;
239 for (const auto &buffer : fBuffers) {
240 fullBufferSize += buffer.size();
241 }
242
243 if (fullBufferSize == 0) {
244 *fResult = std::numeric_limits<double>::signaling_NaN();
245 return;
246 }
247
248 fullBuffer.reserve(fullBufferSize);
249
250 for (const auto &buffer : fBuffers)
251 fullBuffer.insert(fullBuffer.end(), buffer.begin(), buffer.end());
252
253 const std::size_t k = fullBufferSize / 2;
254 std::nth_element(fullBuffer.begin(), fullBuffer.begin() + k, fullBuffer.end());
255 const double upper = fullBuffer[k];
256
257 if (fullBuffer.size() % 2) {
258 *fResult = upper;
259 } else {
260 const double lower = *std::max_element(fullBuffer.begin(), fullBuffer.begin() + k);
261 *fResult = 0.5 * (lower + upper);
262 }
263}
264
265// External templates are disabled for gcc5 since this version wrongly omits the C++11 ABI attribute
266#if __GNUC__ > 5
276#endif
277
278} // namespace RDF
279} // namespace Internal
280} // namespace ROOT
#define c(i)
Definition RSha256.hxx:101
#define h(i)
Definition RSha256.hxx:106
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
Basic types used by ROOT and required by TInterpreter.
unsigned long long ULong64_t
Portable unsigned long integer 8 bytes.
Definition RtypesCore.h:85
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
const_iterator begin() const
const_iterator end() const
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:109
Statistical variable, defined by its mean and variance (RMS).
Definition TStatistic.h:33
Double_t y[n]
Definition legend1.C:17
void ResetIfPossible(TStatistic *h)
constexpr std::size_t CacheLineStep()
Stepping through CacheLineStep<T> values in a vector<T> brings you to a new cache line.
Definition Utils.hxx:225
void UnsetDirectoryIfPossible(TH1 *h)
TMarker m
Definition textangle.C:8