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 if (mSumw2[step]) {
331 target->Sumw2();
332 }
333
334 Int_t* binIdx = new Int_t[mNVars];
335 Int_t* nBins = new Int_t[mNVars];
336 for (Int_t j = 0; j < mNVars; j++) {
337 binIdx[j] = 1;
338 nBins[j] = target->GetAxis(j)->GetNbins();
339 }
340
341 Long64_t count = 0;
342
343 while (1) {
344 // for (Int_t j=0; j<mNVars; j++)
345 // printf("%d ", binIdx[j]);
346
347 Long64_t globalBin = getGlobalBinIndex(binIdx);
348 // Printf(" --> %lld", globalBin);
349
350 // TODO probably slow
351 double value = source->GetAt(globalBin);
352 if (value != 0) {
353 target->SetBinContent(binIdx, value);
354 target->SetBinError(binIdx, TMath::Sqrt(sourceSumw2->GetAt(globalBin)));
355
356 count++;
357 }
358
359 binIdx[mNVars - 1]++;
360
361 for (Int_t j = mNVars - 1; j > 0; j--) {
362 if (binIdx[j] > nBins[j]) {
363 binIdx[j] = 1;
364 binIdx[j - 1]++;
365 }
366 }
367
368 if (binIdx[0] > nBins[0]) {
369 break;
370 }
371 }
372
373 LOGF(info, "Step %d: copied %lld entries out of %lld bins", step, count, getGlobalBinIndex(binIdx));
374
375 delete[] binIdx;
376 delete[] nBins;
377
378 delete mValues[step];
379 mValues[step] = nullptr;
380}
381
382void StepTHn::Fill(int iStep, int nParams, double positionAndWeight[])
383{
384 if (iStep >= mNSteps) {
385 LOGF(fatal, "Selected step for filling is not in range of StepTHn.");
386 }
387
388 double weight = 1.0;
389 if (nParams == mNVars + 1) {
390 weight = positionAndWeight[mNVars];
391 } else if (nParams != mNVars) {
392 LOGF(fatal, "Fill called with invalid number of parameters (%d vs %d)", mNVars, nParams);
393 }
394
395 // fill axis cache
396 if (!mAxisCache) {
397 mAxisCache = new TAxis*[mNVars];
398 mNbinsCache = new Int_t[mNVars];
399 for (Int_t i = 0; i < mNVars; i++) {
400 mAxisCache[i] = mPrototype->GetAxis(i);
401 mNbinsCache[i] = mAxisCache[i]->GetNbins();
402 }
403
404 mLastVars = new Double_t[mNVars];
405 mLastBins = new Int_t[mNVars];
406
407 // initial values to prevent checking for 0 below
408 for (Int_t i = 0; i < mNVars; i++) {
409 mLastVars[i] = positionAndWeight[i];
410 mLastBins[i] = mAxisCache[i]->FindBin(mLastVars[i]);
411 }
412 }
413
414 // calculate global bin index
415 Long64_t bin = 0;
416 for (Int_t i = 0; i < mNVars; i++) {
417 bin *= mNbinsCache[i];
418
419 Int_t tmpBin = 0;
420 if (mLastVars[i] == positionAndWeight[i]) {
421 tmpBin = mLastBins[i];
422 } else {
423 tmpBin = mAxisCache[i]->FindBin(positionAndWeight[i]);
424 mLastBins[i] = tmpBin;
425 mLastVars[i] = positionAndWeight[i];
426 }
427 //Printf("%d", tmpBin);
428
429 // under/overflow not supported
430 if (tmpBin < 1 || tmpBin > mNbinsCache[i]) {
431 return;
432 }
433
434 // bins start from 0 here
435 bin += tmpBin - 1;
436 // Printf("%lld", bin);
437 }
438
439 if (!mValues[iStep]) {
440 mValues[iStep] = createArray();
441 LOGF(info, "Created values container for step %d", iStep);
442 }
443
444 if (weight != 1.) {
445 // initialize with already filled entries (which have been filled with weight == 1), in this case mSumw2 := mValues
446 if (!mSumw2[iStep]) {
447 mSumw2[iStep] = createArray(mValues[iStep]);
448 LOGF(info, "Created sumw2 container for step %d", iStep);
449 }
450 }
451
452 // TODO probably slow; add StepTHnT::add ?
453 mValues[iStep]->SetAt(mValues[iStep]->GetAt(bin) + weight, bin);
454 if (mSumw2[iStep]) {
455 mSumw2[iStep]->SetAt(mSumw2[iStep]->GetAt(bin) + weight * weight, bin);
456 }
457}
458
459template class StepTHnT<TArrayF>;
460template 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