Logo ROOT   6.18/05
Reference Guide
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
13namespace ROOT {
14namespace Internal {
15namespace RDF {
16
17CountHelper::CountHelper(const std::shared_ptr<ULong64_t> &resultCount, const unsigned int nSlots)
18 : fResultCount(resultCount), fCounts(nSlots, 0)
19{
20}
21
22void CountHelper::Exec(unsigned int slot)
23{
24 fCounts[slot]++;
25}
26
27void CountHelper::Finalize()
28{
29 *fResultCount = 0;
30 for (auto &c : fCounts) {
31 *fResultCount += c;
32 }
33}
34
35ULong64_t &CountHelper::PartialUpdate(unsigned int slot)
36{
37 return fCounts[slot];
38}
39
40void FillHelper::UpdateMinMax(unsigned int slot, double v)
41{
42 auto &thisMin = fMin[slot];
43 auto &thisMax = fMax[slot];
44 thisMin = std::min(thisMin, v);
45 thisMax = std::max(thisMax, v);
46}
47
48FillHelper::FillHelper(const std::shared_ptr<Hist_t> &h, const unsigned int nSlots)
49 : fResultHist(h), fNSlots(nSlots), fBufSize(fgTotalBufSize / nSlots), fPartialHists(fNSlots),
50 fMin(nSlots, std::numeric_limits<BufEl_t>::max()), fMax(nSlots, std::numeric_limits<BufEl_t>::lowest())
51{
52 fBuffers.reserve(fNSlots);
53 fWBuffers.reserve(fNSlots);
54 for (unsigned int i = 0; i < fNSlots; ++i) {
55 Buf_t v;
56 v.reserve(fBufSize);
57 fBuffers.emplace_back(v);
58 fWBuffers.emplace_back(v);
59 }
60}
61
62void FillHelper::Exec(unsigned int slot, double v)
63{
64 UpdateMinMax(slot, v);
65 fBuffers[slot].emplace_back(v);
66}
67
68void FillHelper::Exec(unsigned int slot, double v, double w)
69{
70 UpdateMinMax(slot, v);
71 fBuffers[slot].emplace_back(v);
72 fWBuffers[slot].emplace_back(w);
73}
74
75Hist_t &FillHelper::PartialUpdate(unsigned int slot)
76{
77 auto &partialHist = fPartialHists[slot];
78 // TODO it is inefficient to re-create the partial histogram everytime the callback is called
79 // ideally we could incrementally fill it with the latest entries in the buffers
80 partialHist = std::make_unique<Hist_t>(*fResultHist);
81 auto weights = fWBuffers[slot].empty() ? nullptr : fWBuffers[slot].data();
82 partialHist->FillN(fBuffers[slot].size(), fBuffers[slot].data(), weights);
83 return *partialHist;
84}
85
86void FillHelper::Finalize()
87{
88 for (unsigned int i = 0; i < fNSlots; ++i) {
89 if (!fWBuffers[i].empty() && fBuffers[i].size() != fWBuffers[i].size()) {
90 throw std::runtime_error("Cannot fill weighted histogram with values in containers of different sizes.");
91 }
92 }
93
94 BufEl_t globalMin = *std::min_element(fMin.begin(), fMin.end());
95 BufEl_t globalMax = *std::max_element(fMax.begin(), fMax.end());
96
97 if (fResultHist->CanExtendAllAxes() && globalMin != std::numeric_limits<BufEl_t>::max() &&
98 globalMax != std::numeric_limits<BufEl_t>::lowest()) {
99 fResultHist->SetBins(fResultHist->GetNbinsX(), globalMin, globalMax);
100 }
101
102 for (unsigned int i = 0; i < fNSlots; ++i) {
103 auto weights = fWBuffers[i].empty() ? nullptr : fWBuffers[i].data();
104 fResultHist->FillN(fBuffers[i].size(), fBuffers[i].data(), weights);
105 }
106}
107
108template void FillHelper::Exec(unsigned int, const std::vector<float> &);
109template void FillHelper::Exec(unsigned int, const std::vector<double> &);
110template void FillHelper::Exec(unsigned int, const std::vector<char> &);
111template void FillHelper::Exec(unsigned int, const std::vector<int> &);
112template void FillHelper::Exec(unsigned int, const std::vector<unsigned int> &);
113template void FillHelper::Exec(unsigned int, const std::vector<float> &, const std::vector<float> &);
114template void FillHelper::Exec(unsigned int, const std::vector<double> &, const std::vector<double> &);
115template void FillHelper::Exec(unsigned int, const std::vector<char> &, const std::vector<char> &);
116template void FillHelper::Exec(unsigned int, const std::vector<int> &, const std::vector<int> &);
117template void FillHelper::Exec(unsigned int, const std::vector<unsigned int> &, const std::vector<unsigned int> &);
118
119// TODO
120// template void MinHelper::Exec(unsigned int, const std::vector<float> &);
121// template void MinHelper::Exec(unsigned int, const std::vector<double> &);
122// template void MinHelper::Exec(unsigned int, const std::vector<char> &);
123// template void MinHelper::Exec(unsigned int, const std::vector<int> &);
124// template void MinHelper::Exec(unsigned int, const std::vector<unsigned int> &);
125
126// template void MaxHelper::Exec(unsigned int, const std::vector<float> &);
127// template void MaxHelper::Exec(unsigned int, const std::vector<double> &);
128// template void MaxHelper::Exec(unsigned int, const std::vector<char> &);
129// template void MaxHelper::Exec(unsigned int, const std::vector<int> &);
130// template void MaxHelper::Exec(unsigned int, const std::vector<unsigned int> &);
131
132MeanHelper::MeanHelper(const std::shared_ptr<double> &meanVPtr, const unsigned int nSlots)
133 : fResultMean(meanVPtr), fCounts(nSlots, 0), fSums(nSlots, 0), fPartialMeans(nSlots)
134{
135}
136
137void MeanHelper::Exec(unsigned int slot, double v)
138{
139 fSums[slot] += v;
140 fCounts[slot]++;
141}
142
143void MeanHelper::Finalize()
144{
145 double sumOfSums = 0;
146 for (auto &s : fSums)
147 sumOfSums += s;
148 ULong64_t sumOfCounts = 0;
149 for (auto &c : fCounts)
150 sumOfCounts += c;
151 *fResultMean = sumOfSums / (sumOfCounts > 0 ? sumOfCounts : 1);
152}
153
154double &MeanHelper::PartialUpdate(unsigned int slot)
155{
156 fPartialMeans[slot] = fSums[slot] / fCounts[slot];
157 return fPartialMeans[slot];
158}
159
160template void MeanHelper::Exec(unsigned int, const std::vector<float> &);
161template void MeanHelper::Exec(unsigned int, const std::vector<double> &);
162template void MeanHelper::Exec(unsigned int, const std::vector<char> &);
163template void MeanHelper::Exec(unsigned int, const std::vector<int> &);
164template void MeanHelper::Exec(unsigned int, const std::vector<unsigned int> &);
165
166StdDevHelper::StdDevHelper(const std::shared_ptr<double> &meanVPtr, const unsigned int nSlots)
167 : fNSlots(nSlots), fResultStdDev(meanVPtr), fCounts(nSlots, 0), fMeans(nSlots, 0), fDistancesfromMean(nSlots, 0)
168{
169}
170
171void StdDevHelper::Exec(unsigned int slot, double v)
172{
173 // Applies the Welford's algorithm to the stream of values received by the thread
174 auto count = ++fCounts[slot];
175 auto delta = v - fMeans[slot];
176 auto mean = fMeans[slot] + delta / count;
177 auto delta2 = v - mean;
178 auto distance = fDistancesfromMean[slot] + delta * delta2;
179
180 fCounts[slot] = count;
181 fMeans[slot] = mean;
182 fDistancesfromMean[slot] = distance;
183}
184
185void StdDevHelper::Finalize()
186{
187 // Evaluates and merges the partial result of each set of data to get the overall standard deviation.
188 double totalElements = 0;
189 for (auto c : fCounts) {
190 totalElements += c;
191 }
192 if (totalElements == 0 || totalElements == 1) {
193 // Std deviation is not defined for 1 element.
194 *fResultStdDev = 0;
195 return;
196 }
197
198 double overallMean = 0;
199 for (unsigned int i = 0; i < fNSlots; ++i) {
200 overallMean += fCounts[i] * fMeans[i];
201 }
202 overallMean = overallMean / totalElements;
203
204 double variance = 0;
205 for (unsigned int i = 0; i < fNSlots; ++i) {
206 if (fCounts[i] == 0) {
207 continue;
208 }
209 auto setVariance = fDistancesfromMean[i] / (fCounts[i]);
210 variance += (fCounts[i]) * (setVariance + std::pow((fMeans[i] - overallMean), 2));
211 }
212
213 variance = variance / (totalElements - 1);
214 *fResultStdDev = std::sqrt(variance);
215}
216
217template void StdDevHelper::Exec(unsigned int, const std::vector<float> &);
218template void StdDevHelper::Exec(unsigned int, const std::vector<double> &);
219template void StdDevHelper::Exec(unsigned int, const std::vector<char> &);
220template void StdDevHelper::Exec(unsigned int, const std::vector<int> &);
221template void StdDevHelper::Exec(unsigned int, const std::vector<unsigned int> &);
222
223// External templates are disabled for gcc5 since this version wrongly omits the C++11 ABI attribute
224#if __GNUC__ > 5
225template class TakeHelper<bool, bool, std::vector<bool>>;
226template class TakeHelper<unsigned int, unsigned int, std::vector<unsigned int>>;
227template class TakeHelper<unsigned long, unsigned long, std::vector<unsigned long>>;
228template class TakeHelper<unsigned long long, unsigned long long, std::vector<unsigned long long>>;
229template class TakeHelper<int, int, std::vector<int>>;
230template class TakeHelper<long, long, std::vector<long>>;
231template class TakeHelper<long long, long long, std::vector<long long>>;
232template class TakeHelper<float, float, std::vector<float>>;
233template class TakeHelper<double, double, std::vector<double>>;
234#endif
235
236} // end NS RDF
237} // end NS Internal
238} // end NS ROOT
SVector< double, 2 > v
Definition: Dict.h:5
#define c(i)
Definition: RSha256.hxx:101
#define h(i)
Definition: RSha256.hxx:106
unsigned long long ULong64_t
Definition: RtypesCore.h:70
double pow(double, double)
double sqrt(double)
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
static constexpr double s