Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
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 namespace ROOT {
14 namespace Internal {
15 namespace RDF {
16 
17 CountHelper::CountHelper(const std::shared_ptr<ULong64_t> &resultCount, const unsigned int nSlots)
18  : fResultCount(resultCount), fCounts(nSlots, 0)
19 {
20 }
21 
22 void CountHelper::Exec(unsigned int slot)
23 {
24  fCounts[slot]++;
25 }
26 
27 void CountHelper::Finalize()
28 {
29  *fResultCount = 0;
30  for (auto &c : fCounts) {
31  *fResultCount += c;
32  }
33 }
34 
35 ULong64_t &CountHelper::PartialUpdate(unsigned int slot)
36 {
37  return fCounts[slot];
38 }
39 
40 void 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 
48 FillHelper::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 
62 void FillHelper::Exec(unsigned int slot, double v)
63 {
64  UpdateMinMax(slot, v);
65  fBuffers[slot].emplace_back(v);
66 }
67 
68 void 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 
75 Hist_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 
86 void 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 
108 template void FillHelper::Exec(unsigned int, const std::vector<float> &);
109 template void FillHelper::Exec(unsigned int, const std::vector<double> &);
110 template void FillHelper::Exec(unsigned int, const std::vector<char> &);
111 template void FillHelper::Exec(unsigned int, const std::vector<int> &);
112 template void FillHelper::Exec(unsigned int, const std::vector<unsigned int> &);
113 template void FillHelper::Exec(unsigned int, const std::vector<float> &, const std::vector<float> &);
114 template void FillHelper::Exec(unsigned int, const std::vector<double> &, const std::vector<double> &);
115 template void FillHelper::Exec(unsigned int, const std::vector<char> &, const std::vector<char> &);
116 template void FillHelper::Exec(unsigned int, const std::vector<int> &, const std::vector<int> &);
117 template 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 
132 MeanHelper::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 
137 void MeanHelper::Exec(unsigned int slot, double v)
138 {
139  fSums[slot] += v;
140  fCounts[slot]++;
141 }
142 
143 void 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 
154 double &MeanHelper::PartialUpdate(unsigned int slot)
155 {
156  fPartialMeans[slot] = fSums[slot] / fCounts[slot];
157  return fPartialMeans[slot];
158 }
159 
160 template void MeanHelper::Exec(unsigned int, const std::vector<float> &);
161 template void MeanHelper::Exec(unsigned int, const std::vector<double> &);
162 template void MeanHelper::Exec(unsigned int, const std::vector<char> &);
163 template void MeanHelper::Exec(unsigned int, const std::vector<int> &);
164 template void MeanHelper::Exec(unsigned int, const std::vector<unsigned int> &);
165 
166 StdDevHelper::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 
171 void 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 
185 void 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 
217 template void StdDevHelper::Exec(unsigned int, const std::vector<float> &);
218 template void StdDevHelper::Exec(unsigned int, const std::vector<double> &);
219 template void StdDevHelper::Exec(unsigned int, const std::vector<char> &);
220 template void StdDevHelper::Exec(unsigned int, const std::vector<int> &);
221 template 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
225 template class TakeHelper<bool, bool, std::vector<bool>>;
226 template class TakeHelper<unsigned int, unsigned int, std::vector<unsigned int>>;
227 template class TakeHelper<unsigned long, unsigned long, std::vector<unsigned long>>;
228 template class TakeHelper<unsigned long long, unsigned long long, std::vector<unsigned long long>>;
229 template class TakeHelper<int, int, std::vector<int>>;
230 template class TakeHelper<long, long, std::vector<long>>;
231 template class TakeHelper<long long, long long, std::vector<long long>>;
232 template class TakeHelper<float, float, std::vector<float>>;
233 template class TakeHelper<double, double, std::vector<double>>;
234 #endif
235 
236 } // end NS RDF
237 } // end NS Internal
238 } // end NS ROOT