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