Project
Loading...
Searching...
No Matches
StepTHn.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12// Use StepTHn instead of THn and your memory consumption will be drastically reduced
13// Once you have the merged output, use getTHn() to get a standard histogram
14//
15// this storage container is optimized for small memory usage
16// under/over flow bins do not exist
17// sumw2 structure is float only and only create when the weight != 1
18//
19// Templated version allows also the use of double as storage container
20
21#include "Framework/StepTHn.h"
22#include "TList.h"
23#include "TCollection.h"
24#include "TArrayF.h"
25#include "TArrayD.h"
26#include "THn.h"
27#include "TMath.h"
28
31
32StepTHn::StepTHn() : mNBins(0),
33 mNVars(0),
34 mNSteps(0),
35 mValues(nullptr),
36 mSumw2(nullptr),
37 mTarget(nullptr),
38 mAxisCache(nullptr),
39 mNbinsCache(nullptr),
40 mLastVars(nullptr),
41 mLastBins(nullptr),
42 mPrototype(nullptr)
43{
44 // Default constructor (for streaming)
45}
46
47StepTHn::StepTHn(const Char_t* name, const Char_t* title, const Int_t nSteps, const Int_t nAxes) : TNamed(name, title),
48 mNBins(0),
49 mNVars(nAxes),
50 mNSteps(nSteps),
51 mValues(nullptr),
52 mSumw2(nullptr),
53 mTarget(nullptr),
54 mAxisCache(nullptr),
55 mNbinsCache(nullptr),
56 mLastVars(nullptr),
57 mLastBins(nullptr),
58 mPrototype(nullptr)
59{
60 // Constructor
61 //
62 // This will create a container for <nSteps> steps. The memory for such a step is only allocated once the first value is filled.
63 // Therefore you can easily create many steps which are only filled under certain analysis settings.
64 // For each step a <nAxes> dimensional histogram is created.
65 // The axis have <nBins[i]> bins. The bin edges are given in <binEdges[i]>. If there are only two bin edges, equidistant binning is set.
66
67 init();
68}
69
70// root-like constructor
71template <class TemplateArray>
72StepTHnT<TemplateArray>::StepTHnT(const char* name, const char* title, const int nSteps, const int nAxes, const int* nBins, const double* xmin, const double* xmax) : StepTHn(name, title, nSteps, nAxes)
73{
74 mNBins = 1;
75 for (Int_t i = 0; i < mNVars; i++) {
76 mNBins *= nBins[i];
77 }
78 if (mNBins > 250000000) {
79 LOGF(warning, "StepTHn: Requesting more than 250M bins (%lld). This will need extensive memory.", mNBins);
80 }
81 mPrototype = new THnSparseT<TemplateArray>(Form("%s_sparse", name), title, nAxes, nBins, xmin, xmax);
82}
83
84template <class TemplateArray>
85StepTHnT<TemplateArray>::StepTHnT(const Char_t* name, const Char_t* title, const Int_t nSteps, const Int_t nAxes,
86 Int_t* nBins, std::vector<Double_t> binEdges[], const char** axisTitles) : StepTHn(name, title, nSteps, nAxes)
87{
88 mNBins = 1;
89 for (Int_t i = 0; i < mNVars; i++) {
90 mNBins *= nBins[i];
91 }
92 if (mNBins > 250000000) {
93 LOGF(warning, "StepTHn: Requesting more than 250M bins (%lld). This will need extensive memory.", mNBins);
94 }
95 mPrototype = new THnSparseT<TemplateArray>(Form("%s_sparse", name), title, nAxes, nBins);
96
97 for (Int_t i = 0; i < mNVars; i++) {
98 if (nBins[i] + 1 == binEdges[i].size()) { // variable-width binning
99 mPrototype->GetAxis(i)->Set(nBins[i], &(binEdges[i])[0]);
100 } else if (binEdges[i].size() == 2) { // equidistant binning
101 mPrototype->GetAxis(i)->Set(nBins[i], binEdges[i][0], binEdges[i][1]);
102 } else {
103 LOGF(fatal, "Invalid binning information for axis %d with %d bins and %d entries for bin edges", i, nBins[i], binEdges[i].size());
104 }
105 LOGF(debug, "Histogram %s Axis %d created with %d bins and %d edges", name, i, nBins[i], binEdges[i].size());
106 mPrototype->GetAxis(i)->SetTitle(axisTitles[i]);
107 }
108}
109
111{
112 // initialize
113
114 mValues = new TArray*[mNSteps];
115 mSumw2 = new TArray*[mNSteps];
116
117 for (Int_t i = 0; i < mNSteps; i++) {
118 mValues[i] = nullptr;
119 mSumw2[i] = nullptr;
120 }
121}
122
123StepTHn::StepTHn(const StepTHn& c) : mNBins(c.mNBins),
124 mNVars(c.mNVars),
125 mNSteps(c.mNSteps),
126 mValues(new TArray*[c.mNSteps]),
127 mSumw2(new TArray*[c.mNSteps]),
128 mTarget(nullptr),
129 mAxisCache(nullptr),
130 mNbinsCache(nullptr),
131 mLastVars(nullptr),
132 mLastBins(nullptr),
133 mPrototype(nullptr)
134{
135 //
136 // StepTHn copy constructor
137 //
138
139 ((StepTHn&)c).Copy(*this);
140}
141
143{
144 // Destructor
145
147
148 delete[] mValues;
149 delete[] mSumw2;
150 delete[] mTarget;
151 delete[] mAxisCache;
152 delete[] mNbinsCache;
153 delete[] mLastVars;
154 delete[] mLastBins;
155 delete mPrototype;
156}
157
159{
160 // delete data containers
161
162 for (Int_t i = 0; i < mNSteps; i++) {
163 if (mValues && mValues[i]) {
164 delete mValues[i];
165 mValues[i] = nullptr;
166 }
167
168 if (mSumw2 && mSumw2[i]) {
169 delete mSumw2[i];
170 mSumw2[i] = nullptr;
171 }
172
173 if (mTarget && mTarget[i]) {
174 delete mTarget[i];
175 mTarget[i] = nullptr;
176 }
177 }
178}
179
181{
182 // assigment operator
183
184 if (this != &c) {
185 ((StepTHn&)c).Copy(*this);
186 }
187
188 return *this;
189}
190
192{
193 // copy function
194
195 StepTHn& target = (StepTHn&)c;
196
197 TNamed::Copy(c);
198
199 target.mNBins = mNBins;
200 target.mNVars = mNVars;
201 target.mNSteps = mNSteps;
202
203 target.init();
204
205 for (Int_t i = 0; i < mNSteps; i++) {
206 if (mValues[i]) {
207 target.mValues[i] = createArray(mValues[i]);
208 } else {
209 target.mValues[i] = nullptr;
210 }
211
212 if (mSumw2[i]) {
213 target.mSumw2[i] = createArray(mSumw2[i]);
214 } else {
215 target.mSumw2[i] = nullptr;
216 }
217 }
218
219 if (mPrototype) {
220 target.mPrototype = dynamic_cast<THnSparse*>(mPrototype->Clone());
221 }
222}
223
224template <class TemplateArray>
226{
227 // Merge a list of StepTHn objects with this (needed for PROOF).
228 // Returns the number of merged objects (including this).
229
230 if (!list) {
231 return 0;
232 }
233
234 if (list->IsEmpty()) {
235 return 1;
236 }
237
238 TIterator* iter = list->MakeIterator();
239 TObject* obj;
240
241 Int_t count = 0;
242 while ((obj = iter->Next())) {
243
245 if (entry == nullptr) {
246 continue;
247 }
248
249 for (Int_t i = 0; i < mNSteps; i++) {
250 if (entry->mValues[i]) {
251 if (!mValues[i]) {
252 mValues[i] = createArray();
253 }
254
255 auto source = dynamic_cast<TemplateArray*>(entry->mValues[i])->GetArray();
256 auto target = dynamic_cast<TemplateArray*>(mValues[i])->GetArray();
257 for (Long64_t l = 0; l < mNBins; l++) {
258 target[l] += source[l];
259 }
260 }
261
262 if (entry->mSumw2[i]) {
263 if (!mSumw2[i]) {
264 mSumw2[i] = createArray();
265 }
266
267 auto source = dynamic_cast<TemplateArray*>(entry->mSumw2[i])->GetArray();
268 auto target = dynamic_cast<TemplateArray*>(mSumw2[i])->GetArray();
269 for (Long64_t l = 0; l < mNBins; l++) {
270 target[l] += source[l];
271 }
272 }
273 }
274
275 count++;
276 }
277
278 return count + 1;
279}
280
281Long64_t StepTHn::getGlobalBinIndex(const Int_t* binIdx)
282{
283 // calculates global bin index
284 // binIdx contains TAxis bin indexes
285 // here bin count starts at 0 because we do not have over/underflow bins
286
287 Long64_t bin = 0;
288 for (Int_t i = 0; i < mNVars; i++) {
289 bin *= mPrototype->GetAxis(i)->GetNbins();
290 bin += binIdx[i] - 1;
291 }
292
293 return bin;
294}
295
296void StepTHn::createTarget(Int_t step, Bool_t sparse)
297{
298 // fills the information stored in the buffer in this class into the target THn
299
300 if (!mValues[step]) {
301 LOGF(fatal, "Histogram request for step %d which is empty.", step);
302 return;
303 }
304
305 if (!mTarget) {
306 mTarget = new THnBase*[mNSteps];
307 for (Int_t i = 0; i < mNSteps; i++) {
308 mTarget[i] = nullptr;
309 }
310 }
311
312 if (mTarget[step]) {
313 return;
314 }
315
316 TArray* source = mValues[step];
317 // if mSumw2 is not stored, the sqrt of the number of bin entries in source is filled below; otherwise we use mSumw2
318 TArray* sourceSumw2 = source;
319 if (mSumw2[step]) {
320 sourceSumw2 = mSumw2[step];
321 }
322
323 if (sparse) {
324 mTarget[step] = THnSparse::CreateSparse(Form("%s_%d", GetName(), step), Form("%s_%d", GetTitle(), step), mPrototype);
325 } else {
326 mTarget[step] = THn::CreateHn(Form("%s_%d", GetName(), step), Form("%s_%d", GetTitle(), step), mPrototype);
327 }
328
329 THnBase* target = mTarget[step];
330
331 Int_t* binIdx = new Int_t[mNVars];
332 Int_t* nBins = new Int_t[mNVars];
333 for (Int_t j = 0; j < mNVars; j++) {
334 binIdx[j] = 1;
335 nBins[j] = target->GetAxis(j)->GetNbins();
336 }
337
338 Long64_t count = 0;
339
340 while (1) {
341 // for (Int_t j=0; j<mNVars; j++)
342 // printf("%d ", binIdx[j]);
343
344 Long64_t globalBin = getGlobalBinIndex(binIdx);
345 // Printf(" --> %lld", globalBin);
346
347 // TODO probably slow
348 double value = source->GetAt(globalBin);
349 if (value != 0) {
350 target->SetBinContent(binIdx, value);
351 target->SetBinError(binIdx, TMath::Sqrt(sourceSumw2->GetAt(globalBin)));
352
353 count++;
354 }
355
356 binIdx[mNVars - 1]++;
357
358 for (Int_t j = mNVars - 1; j > 0; j--) {
359 if (binIdx[j] > nBins[j]) {
360 binIdx[j] = 1;
361 binIdx[j - 1]++;
362 }
363 }
364
365 if (binIdx[0] > nBins[0]) {
366 break;
367 }
368 }
369
370 LOGF(info, "Step %d: copied %lld entries out of %lld bins", step, count, getGlobalBinIndex(binIdx));
371
372 delete[] binIdx;
373 delete[] nBins;
374
375 delete mValues[step];
376 mValues[step] = nullptr;
377}
378
379void StepTHn::Fill(int iStep, int nParams, double positionAndWeight[])
380{
381 if (iStep >= mNSteps) {
382 LOGF(fatal, "Selected step for filling is not in range of StepTHn.");
383 }
384
385 double weight = 1.0;
386 if (nParams == mNVars + 1) {
387 weight = positionAndWeight[mNVars];
388 } else if (nParams != mNVars) {
389 LOGF(fatal, "Fill called with invalid number of parameters (%d vs %d)", mNVars, nParams);
390 }
391
392 // fill axis cache
393 if (!mAxisCache) {
394 mAxisCache = new TAxis*[mNVars];
395 mNbinsCache = new Int_t[mNVars];
396 for (Int_t i = 0; i < mNVars; i++) {
397 mAxisCache[i] = mPrototype->GetAxis(i);
398 mNbinsCache[i] = mAxisCache[i]->GetNbins();
399 }
400
401 mLastVars = new Double_t[mNVars];
402 mLastBins = new Int_t[mNVars];
403
404 // initial values to prevent checking for 0 below
405 for (Int_t i = 0; i < mNVars; i++) {
406 mLastVars[i] = positionAndWeight[i];
407 mLastBins[i] = mAxisCache[i]->FindBin(mLastVars[i]);
408 }
409 }
410
411 // calculate global bin index
412 Long64_t bin = 0;
413 for (Int_t i = 0; i < mNVars; i++) {
414 bin *= mNbinsCache[i];
415
416 Int_t tmpBin = 0;
417 if (mLastVars[i] == positionAndWeight[i]) {
418 tmpBin = mLastBins[i];
419 } else {
420 tmpBin = mAxisCache[i]->FindBin(positionAndWeight[i]);
421 mLastBins[i] = tmpBin;
422 mLastVars[i] = positionAndWeight[i];
423 }
424 //Printf("%d", tmpBin);
425
426 // under/overflow not supported
427 if (tmpBin < 1 || tmpBin > mNbinsCache[i]) {
428 return;
429 }
430
431 // bins start from 0 here
432 bin += tmpBin - 1;
433 // Printf("%lld", bin);
434 }
435
436 if (!mValues[iStep]) {
437 mValues[iStep] = createArray();
438 LOGF(info, "Created values container for step %d", iStep);
439 }
440
441 if (weight != 1.) {
442 // initialize with already filled entries (which have been filled with weight == 1), in this case mSumw2 := mValues
443 if (!mSumw2[iStep]) {
444 mSumw2[iStep] = createArray();
445 LOGF(info, "Created sumw2 container for step %d", iStep);
446 }
447 }
448
449 // TODO probably slow; add StepTHnT::add ?
450 mValues[iStep]->SetAt(mValues[iStep]->GetAt(bin) + weight, bin);
451 if (mSumw2[iStep]) {
452 mSumw2[iStep]->SetAt(mSumw2[iStep]->GetAt(bin) + weight, bin);
453 }
454}
455
456template class StepTHnT<TArrayF>;
457template class StepTHnT<TArrayD>;
int32_t i
uint32_t j
Definition RawData.h:0
uint32_t c
Definition RawData.h:2
templateClassImp(StepTHnT)
ClassImp(StepTHn)
std::ostringstream debug
StepTHnT()
Definition StepTHn.h:93
Long64_t Merge(TCollection *list) override
Definition StepTHn.cxx:225
Double_t * mLastVars
cache Nbins per axis
Definition StepTHn.h:81
Int_t * mLastBins
caching of last used bins (in many loops some vars are the same for a while)
Definition StepTHn.h:82
void Fill(int iStep, const Ts &... valuesAndWeight)
Definition StepTHn.h:117
StepTHn()
Definition StepTHn.cxx:32
Long64_t mNBins
Definition StepTHn.h:71
TArray ** mValues
Definition StepTHn.h:74
TAxis ** mAxisCache
target histogram
Definition StepTHn.h:79
Long64_t getGlobalBinIndex(const Int_t *binIdx)
Definition StepTHn.cxx:281
Int_t mNSteps
Definition StepTHn.h:73
StepTHn & operator=(const StepTHn &corr)
Definition StepTHn.cxx:180
virtual TArray * createArray(const TArray *src=nullptr) const =0
Int_t * mNbinsCache
cache axis pointers (about 50% of the time in Fill is spent in GetAxis otherwise)
Definition StepTHn.h:80
void deleteContainers()
Definition StepTHn.cxx:158
void createTarget(Int_t step, Bool_t sparse)
Definition StepTHn.cxx:296
THnSparse * mPrototype
caching of last used bins (in many loops some vars are the same for a while)
Definition StepTHn.h:84
void Copy(TObject &c) const override
Definition StepTHn.cxx:191
TArray ** mSumw2
Definition StepTHn.h:75
void init()
Definition StepTHn.cxx:110
THnBase ** mTarget
Definition StepTHn.h:77
Int_t mNVars
Definition StepTHn.h:72
~StepTHn() override
Definition StepTHn.cxx:142
GLint GLsizei count
Definition glcorearb.h:399
GLuint entry
Definition glcorearb.h:5735
GLsizeiptr size
Definition glcorearb.h:659
GLuint const GLchar * name
Definition glcorearb.h:781
GLuint GLuint GLfloat weight
Definition glcorearb.h:5477
GLsizei GLsizei GLchar * source
Definition glcorearb.h:798
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLenum target
Definition glcorearb.h:1641
Definition list.h:40