Update master to aliroot
[u/mrichter/AliRoot.git] / STEER / STEERBase / AliCounterCollection.cxx
CommitLineData
94ef1a28 1/**************************************************************************
2 * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
3 * *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
6 * *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
15
27de2dfb 16/* $Id$ */
17
94ef1a28 18//-----------------------------------------------------------------------------
19/// \class AliCounterCollection
20///
21/// generic class to handle a collection of counters
22///
23/// \author Philippe Pillot
24//-----------------------------------------------------------------------------
25
26#include "AliCounterCollection.h"
27
5d8c0c8a 28#include <limits.h>
29
94ef1a28 30#include <AliLog.h>
31
32#include <TString.h>
33#include <TObjString.h>
34#include <TObjArray.h>
35#include <THnSparse.h>
36#include <THashList.h>
37#include <TArrayI.h>
38#include <TH1D.h>
39#include <TH2D.h>
40#include <TCollection.h>
41
42ClassImp(AliCounterCollection)
43
44//-----------------------------------------------------------------------
45AliCounterCollection::AliCounterCollection(const char* name) :
46TNamed(name,name),
47fRubrics(new THashList(10)),
48fRubricsSize(new TArrayI(10)),
d810835e 49fCounters(0x0),
5d8c0c8a 50fWeightedCounters(kFALSE),
51fLongCounters(kFALSE)
94ef1a28 52{
53 /// Constructor
54 fRubrics->SetOwner();
55}
56
57//-----------------------------------------------------------------------
58AliCounterCollection::~AliCounterCollection()
59{
60 /// Destructor
61 delete fRubrics;
62 delete fRubricsSize;
63 delete fCounters;
64}
65
66//-----------------------------------------------------------------------
67void AliCounterCollection::Clear(Option_t*)
68{
69 /// Clear counters
70 fRubrics->Clear();
71 fRubricsSize->Reset();
72 delete fCounters; fCounters = 0x0;
d810835e 73 fWeightedCounters = kFALSE;
5d8c0c8a 74 fLongCounters = kFALSE;
94ef1a28 75}
76
77//-----------------------------------------------------------------------
78void AliCounterCollection::AddRubric(TString name, TString listOfKeyWords)
79{
80 /// Add a new rubric with the complete list of related key words separated by "/".
81 /// If the key word "any" is not defined, the overall statistics is
82 /// assumed to be the sum of the statistics under each key word.
83
84 name.ToUpper();
85 listOfKeyWords.ToUpper();
86
87 if (fRubrics->Contains(name.Data())) {
88 AliError(Form("rubric named %s already exist",name.Data()));
89 return;
90 }
91
92 // add the list of autorized key words
93 TObjArray* rubric = listOfKeyWords.Tokenize("/");
94 CleanListOfStrings(rubric);
95 rubric->SetName(name.Data());
96 Int_t nRubrics = fRubrics->GetSize();
97 rubric->SetUniqueID(nRubrics);
98 fRubrics->AddLast(rubric);
99
100 // save the number of autorized key words (expand the array if needed)
101 if (nRubrics+1 > fRubricsSize->GetSize()) fRubricsSize->Set(2*fRubricsSize->GetSize());
102 (*fRubricsSize)[nRubrics] = rubric->GetEntriesFast();
103}
104
105//-----------------------------------------------------------------------
106void AliCounterCollection::AddRubric(TString name, Int_t maxNKeyWords)
107{
108 /// Add a new rubric containing at maximum maxNKeyWords key words.
109 /// Key words will be added as the counters get filled until the maximum is reached.
110 /// If the key word "any" is never defined, the overall statistics is
111 /// assumed to be the sum of the statistics under each key word.
112
113 name.ToUpper();
114
115 if (fRubrics->Contains(name.Data())) {
116 AliError(Form("rubric named %s already exist",name.Data()));
117 return;
118 }
119
120 // create the empty rubric
121 TObjString* rubric = new TObjString(name.Data());
122 Int_t nRubrics = fRubrics->GetSize();
123 rubric->SetUniqueID(nRubrics);
124 fRubrics->AddLast(rubric);
125
126 // save the maximum number of autorized key words
127 if (nRubrics+1 > fRubricsSize->GetSize()) fRubricsSize->Set(2*fRubricsSize->GetSize());
128 (*fRubricsSize)[nRubrics] = maxNKeyWords;
129}
130
131//-----------------------------------------------------------------------
d810835e 132void AliCounterCollection::Init(Bool_t weightedCounters)
94ef1a28 133{
134 /// Initialize the internal counters from the added rubrics.
135
136 // create the counters
137 delete fCounters;
d810835e 138 fWeightedCounters = weightedCounters;
139 if (fWeightedCounters)
140 fCounters = new THnSparseT<TArrayF>("hCounters", "hCounters", fRubrics->GetSize(), fRubricsSize->GetArray(), 0x0, 0x0);
141 else
142 fCounters = new THnSparseT<TArrayI>("hCounters", "hCounters", fRubrics->GetSize(), fRubricsSize->GetArray(), 0x0, 0x0);
94ef1a28 143
144 // loop over axis
145 TObject* rubric = 0x0;
146 TIter nextRubric(fRubrics);
147 while ((rubric = nextRubric())) {
148 TAxis* axis = fCounters->GetAxis((Int_t)rubric->GetUniqueID());
149
150 // set axis name
151 axis->SetName(rubric->GetName());
152
153 // set labels if already known
154 TObjArray* keyWords = dynamic_cast<TObjArray*>(rubric);
155 if (keyWords) {
156 TObjString* label = 0x0;
157 Int_t bin = 1;
158 TIter nextLabel(keyWords);
159 while ((label = static_cast<TObjString*>(nextLabel()))) axis->SetBinLabel(bin++, label->String().Data());
160 }
161
162 }
163
164}
165
166//-----------------------------------------------------------------------
6f5626c7 167Int_t AliCounterCollection::GetNActiveBins(Int_t dim)
168{
169 /// return the number of labels in that rubric.
170 THashList* labels = fCounters->GetAxis(dim)->GetLabels();
171 return (labels) ? labels->GetSize() : 0;
172}
173
174//-----------------------------------------------------------------------
175Bool_t AliCounterCollection::ContainsAny(Int_t dim)
176{
177 /// return kTRUE if that rubric contains the keyWord "ANY".
178 THashList* labels = fCounters->GetAxis(dim)->GetLabels();
179 return (labels && labels->Contains("ANY"));
180}
181
182//-----------------------------------------------------------------------
94ef1a28 183const Int_t* AliCounterCollection::FindBins(const TString& externalKey, Bool_t allocate, Int_t& nEmptySlots)
184{
185 /// Return the corresponding bins ordered by rubric or 0x0 if externalKey is not valid.
186 /// The externalKey format must be rubric:keyWord/rubric:keyWord/rubric:keyWord/...
187 /// If allocate = kTRUE, new key words are added to the corresponding rubric if possible.
188 /// If a rubric is not filled in, the coresponding slot contain -1 in the array.
189 /// It is the responsability of the user to delete the returned array.
190
191 // produce an empty array of keys
192 Int_t nRubrics = fRubrics->GetSize();
193 Int_t* bins = new Int_t[nRubrics];
6f5626c7 194 for (Int_t i=0; i<nRubrics; i++) bins[i] = -1;
94ef1a28 195 nEmptySlots = nRubrics;
196 Bool_t isValid = kTRUE;
197
198 // get the list of rubric:keyWord pairs
199 TObjArray* rubricKeyPairs = externalKey.Tokenize("/");
200
201 // loop over each rubric:keyWord pair
202 TObjString* pair = 0x0;
203 TIter next(rubricKeyPairs);
204 while ((pair = static_cast<TObjString*>(next()))) {
205
206 // get both rubric and associated key word
207 TObjArray* rubricKeyPair = pair->String().Tokenize(":");
208
209 // check the format of the pair
210 if (rubricKeyPair->GetEntriesFast() != 2) {
211 AliError("invalid key format");
212 isValid = kFALSE;
213 delete rubricKeyPair;
214 break;
215 }
216
217 // get the axis corresponding to that rubric
218 Int_t dim = FindDim(static_cast<TObjString*>(rubricKeyPair->UncheckedAt(0))->String());
219 if (dim < 0) {
220 isValid = kFALSE;
221 delete rubricKeyPair;
222 break;
223 }
224
225 // find the bin corresponding to that key word
226 Int_t bin = FindBin(dim, static_cast<TObjString*>(rubricKeyPair->UncheckedAt(1))->String(), allocate);
227 if (bin < 0) {
228 isValid = kFALSE;
229 delete rubricKeyPair;
230 break;
231 }
232
233 // check if the array of keys already contains something for that rubric
234 if (bins[dim] >= 0) {
235 AliWarning("key already given for that rubric --> ignored");
236 delete rubricKeyPair;
237 continue;
238 }
239
240 // store the corresponding bin for that slot
241 bins[dim] = bin;
242 nEmptySlots--;
243
244 // clean memory
245 delete rubricKeyPair;
246 }
247
248 // delete the array in case of problem
249 if (!isValid) {
250 delete[] bins;
251 bins = 0x0;
252 nEmptySlots = nRubrics;
253 }
254
255 // clean memory
256 delete rubricKeyPairs;
257
258 return bins;
259}
260
261//-----------------------------------------------------------------------
262Int_t AliCounterCollection::FindDim(const TString& rubricName) const
263{
264 /// Return the dimension corresponding to that rubric (or -1 in case of failure).
265 TObject* rubric = fRubrics->FindObject(rubricName.Data());
266 if (!rubric) {
267 AliError(Form("invalid rubric: %s",rubricName.Data()));
268 return -1;
269 }
270 return (Int_t) rubric->GetUniqueID();
271}
272
273//-----------------------------------------------------------------------
274Int_t AliCounterCollection::FindBin(Int_t dim, const TString& keyWord, Bool_t allocate)
275{
276 /// Return the bin number corresponding to that key word (or -1 in case of failure).
277 /// If allocate = kTRUE, try to add the key word if possible.
278
279 TAxis* axis = fCounters->GetAxis(dim);
280
281 // look for the bin corresponding to keyWord
282 THashList* labels = axis->GetLabels();
283 TObjString* label = (labels) ? static_cast<TObjString*>(labels->FindObject(keyWord.Data())) : 0x0;
284 Int_t bin = (label) ? (Int_t)label->GetUniqueID() : -1;
285
286 // in case the keyWord does not exist, try to add it if required
287 if (bin<0 && allocate) {
288 Int_t nLabels = (labels) ? labels->GetSize() : 0;
289 if (nLabels < axis->GetNbins()) {
290 bin = nLabels+1;
291 axis->SetBinLabel(bin, keyWord.Data());
292 }
293 }
294
295 if (bin<0) AliError(Form("invalid key word: %s:%s",axis->GetName(),keyWord.Data()));
296
297 return bin;
298}
299
300//-----------------------------------------------------------------------
6f5626c7 301Short_t** AliCounterCollection::DecodeSelection(const TString& selections, const TObjArray& displayedRubrics)
302{
303 /// Tag the selected keywords in each rubric (-1=subtract; 0=discard; 1=add). Format:
304 /// "rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.." (order does not matter).
305 /// It is the responsability of the user to delete the returned array.
306
307 // produce an empty array of selected keys
308 Int_t nRubrics = fCounters->GetNdimensions();
309 Short_t** selects = new Short_t*[nRubrics];
310 for (Int_t i=0; i<nRubrics; i++) selects[i] = 0x0;
311
312 // get the list of rubric:LisOfKeyWord pairs
313 TObjArray* rubricKeyPairs = selections.Tokenize("/");
314
315 // loop over each rubric:keyWord pair
316 TObjString* pair = 0x0;
317 TIter next(rubricKeyPairs);
318 while ((pair = static_cast<TObjString*>(next()))) {
319
320 // get both rubric and associated list of key words
321 TObjArray* rubricKeyPair = pair->String().Tokenize(":");
322
323 // check the format of the pair
324 if (rubricKeyPair->GetEntriesFast() != 2) {
325 AliError("invalid key format");
326 delete rubricKeyPair;
327 delete rubricKeyPairs;
328 for (Int_t i=0; i<nRubrics; i++) if (selects[i]) delete[] selects[i];
329 delete[] selects;
330 return 0x0;
331 }
332
333 // check wether to select or to discard the keyWords
334 Int_t include = kTRUE;
335 TString ListOfKeyWords(static_cast<TObjString*>(rubricKeyPair->UncheckedAt(1))->String());
336 if (ListOfKeyWords.BeginsWith("ANY-")) {
337 ListOfKeyWords.Remove(0,4);
338 include = kFALSE;
339 }
340
341 // select the key words
342 const TString& rubric = static_cast<TObjString*>(rubricKeyPair->UncheckedAt(0))->String();
343 if (!Select(include, rubric, ListOfKeyWords, displayedRubrics.Contains(rubric.Data()), selects)) {
344 delete rubricKeyPair;
345 delete rubricKeyPairs;
346 for (Int_t i=0; i<nRubrics; i++) if (selects[i]) delete[] selects[i];
347 delete[] selects;
348 return 0x0;
349 }
350
351 // clean memory
352 delete rubricKeyPair;
353 }
354
355 // clean memory
356 delete rubricKeyPairs;
357
358 // complete the selection of other rubrics
359 for (Int_t i=0; i<nRubrics; i++) {
360
361 // skip already processed rubrics
362 if (selects[i]) continue;
363
364 // create the list of bins
365 Int_t nBins = GetNActiveBins(i) + 1;
366 selects[i] = new Short_t[nBins];
367
368 // select all key words or only the key work "ANY"
369 if (ContainsAny(i) && !displayedRubrics.Contains(fCounters->GetAxis(i)->GetName())) {
370 memset(selects[i], 0, sizeof(Short_t) * nBins);
371 selects[i][FindBin(i, "ANY", kFALSE)] = 1;
372 } else for (Int_t j=0; j<nBins; j++) selects[i][j] = 1;
373
374 }
375
376 return selects;
377}
378
379//-----------------------------------------------------------------------
380Bool_t AliCounterCollection::Select(Bool_t include, const TString& rubric, const TString& keywords,
381 Bool_t displayed, Short_t* selectBins[])
382{
383 /// Tag the selected keywords (separated by ',') in that rubric (-1=subtract; 0=discard; 1=add).
384
385 Int_t dim = FindDim(rubric);
386 if (dim < 0) return kFALSE;
387
388 if (selectBins[dim]) {
389 AliWarning(Form("selection already made for rubric %s --> ignored",rubric.Data()));
390 return kTRUE;
391 }
392
393 // get list of key words to select
394 TObjArray* keys = keywords.Tokenize(",");
395 if (keys->GetEntriesFast() == 0) {
396 AliError(Form("no key word specified for rubric %s",rubric.Data()));
397 delete keys;
398 return kFALSE;
399 }
400
401 // create the list of bins
402 Int_t nBins = GetNActiveBins(dim) + 1;
403 selectBins[dim] = new Short_t[nBins];
404
405 // select/unselect all bins
406 Bool_t containsAny = ContainsAny(dim);
407 if (include || (containsAny && !displayed)) {
408 memset(selectBins[dim], 0, sizeof(Short_t) * nBins);
409 if (!include) selectBins[dim][FindBin(dim, "ANY", kFALSE)] = 1;
410 } else for (Int_t j=0; j<nBins; j++) selectBins[dim][j] = 1;
411
412 // select/unselect specific key words
413 TObjString* key = 0x0;
414 TIter nextKey(keys);
415 while ((key = static_cast<TObjString*>(nextKey()))) {
416
417 // special case of key word "ANY"
418 if (key->String() == "ANY") {
419
420 if (containsAny) {
421
422 Int_t binAny = FindBin(dim, "ANY", kFALSE);
423 if (include) selectBins[dim][binAny] = 1;
424 else selectBins[dim][binAny] = 0;
425
426 } else {
427
428 if (include) for (Int_t j=0; j<nBins; j++) selectBins[dim][j] = 1;
429 else memset(selectBins[dim], 0, sizeof(Short_t) * nBins);
430
431 }
432
433 } else { // other cases
434
435 // find the corresponding bin
436 Int_t bin = FindBin(dim, key->String().Data(), kFALSE);
437 if (bin < 0) {
438 delete keys;
439 return kFALSE;
440 }
441
442 // select/unselect it
443 if (include) selectBins[dim][bin] = 1;
444 else if (containsAny && !displayed) selectBins[dim][bin] = -1;
445 else selectBins[dim][bin] = 0;
446
447 }
448
449 }
450
451 // clean memory
452 delete keys;
453
454 return kTRUE;
455}
456
457//-----------------------------------------------------------------------
94ef1a28 458void AliCounterCollection::CleanListOfStrings(TObjArray* list)
459{
460 /// Make sure all strings appear only once in this list
461
462 // remove multiple-occurrence
463 Int_t nEntries = list->GetEntriesFast();
464 for (Int_t i = 0; i < nEntries; i++) {
465 TObjString* entry1 = static_cast<TObjString*>(list->UncheckedAt(i));
466 if (!entry1) continue;
467 for (Int_t j = i+1; j < nEntries; j++) {
468 TObjString* entry2 = static_cast<TObjString*>(list->UncheckedAt(j));
469 if (entry2 && entry2->IsEqual(entry1)) {
470 AliWarning(Form("multiple-occurence of string \"%s\" --> removed",entry2->String().Data()));
471 list->RemoveAt(j);
472 }
473 }
474 }
475
476 // remove empty slots
477 list->Compress();
478}
479
480//-----------------------------------------------------------------------
481void AliCounterCollection::Count(TString externalKey, Int_t value)
482{
483 /// Add "value" to the counter referenced by "externalKey".
484 /// The externalKey format must be rubric:keyWord/rubric:keyWord/rubric:keyWord/...
d810835e 485 if (value > 0) CountAsDouble(externalKey, (Double_t)value);
486 else if (value < 0) AliError("cannot count negative values");
487}
488
489//-----------------------------------------------------------------------
490void AliCounterCollection::Count(TString externalKey, Double_t value)
491{
492 /// Add "value" to the counter referenced by "externalKey".
493 /// The externalKey format must be rubric:keyWord/rubric:keyWord/rubric:keyWord/...
494 if (fWeightedCounters) CountAsDouble(externalKey, value);
495 else AliError("non-weighted counters can only be filled with intergers");
496}
497
498//-----------------------------------------------------------------------
499void AliCounterCollection::CountAsDouble(TString externalKey, Double_t value)
500{
501 /// Add "value" to the counter referenced by "externalKey".
502 /// The externalKey format must be rubric:keyWord/rubric:keyWord/rubric:keyWord/...
94ef1a28 503
94ef1a28 504 if (!fCounters) {
505 AliError("counters are not initialized");
506 return;
507 }
508
509 externalKey.ToUpper();
510
511 // convert external to internal key
512 Int_t nEmptySlots = 0;
513 const Int_t* bins = FindBins(externalKey, kTRUE, nEmptySlots);
514 if (!bins) return;
515
516 // check for empty slots
517 if (nEmptySlots > 0) {
518 AliError("incomplete key");
519 delete[] bins;
520 return;
521 }
522
5d8c0c8a 523 if (fWeightedCounters || fLongCounters) {
524
525 // increment the corresponding counter
526 fCounters->AddBinContent(bins, value);
527
528 } else {
529
530 // switch to long counters if needed before incrementing
531 Long64_t linBin = fCounters->GetBin(bins, kTRUE);
532 Double_t currentValue = fCounters->GetBinContent(linBin);
533 if (currentValue+value > INT_MAX) {
534 ConvertToTHnSparseL(fCounters);
535 fLongCounters = kTRUE;
536 fCounters->AddBinContent(bins, value);
537 } else fCounters->AddBinContent(linBin, value);
538
539 }
94ef1a28 540
541 // clean memory
542 delete[] bins;
543}
544
545//-----------------------------------------------------------------------
546void AliCounterCollection::Print(const Option_t* opt) const
547{
7471ae1a 548 /// Print every individual counters if opt=="" or call "Print(opt, "")".
94ef1a28 549
550 if (strcmp(opt,"")) {
551 const_cast<AliCounterCollection*>(this)->Print(opt, "");
552 return;
553 }
554
555 if (!fCounters) {
556 AliError("counters are not initialized");
557 return;
558 }
559
560 if (fCounters->GetNbins() == 0) {
561 printf("\nall counters are empty\n\n");
562 return;
563 }
564
565 Int_t nRubrics = fCounters->GetNdimensions();
566 Int_t* bins = new Int_t[nRubrics];
567
568 // loop over every filled counters
569 for (Long64_t i=0; i<fCounters->GetNbins(); ++i) {
570
571 // get the content of the bin
d810835e 572 Double_t value = fCounters->GetBinContent(i, bins);
94ef1a28 573
574 // build the corresponding counter name
575 TString counter;
576 for (Int_t j=0; j<nRubrics; j++) counter += Form("/%s",fCounters->GetAxis(j)->GetBinLabel(bins[j]));
577 counter += "/";
578
579 // print value
d810835e 580 if (fWeightedCounters) printf("\n%s %g", counter.Data(), value);
5d8c0c8a 581 else if (fLongCounters) printf("\n%s %ld", counter.Data(), (Long_t)value);
d810835e 582 else printf("\n%s %d", counter.Data(), (Int_t)value);
94ef1a28 583 }
584 printf("\n\n");
585
586 // clean memory
587 delete[] bins;
588}
589
590//-----------------------------------------------------------------------
d649ab79 591TString AliCounterCollection::GetKeyWords(TString rubric) const
592{
593 /// return the list of key words for the given rubric.
594
595 TString keyWords = "";
596
597 if (!fCounters) {
598 AliError("counters are not initialized");
599 return keyWords;
600 }
601
602 rubric.ToUpper();
603
604 // get the dimension corresponding to that rubric
605 Int_t dim = FindDim(rubric);
606 if (dim < 0) return keyWords;
607
608 // build list of key words
609 TObjString* label = 0x0;
610 TIter nextLabel(fCounters->GetAxis(dim)->GetLabels());
611 while ((label = static_cast<TObjString*>(nextLabel()))) keyWords += Form("%s,",label->String().Data());
612 keyWords.Remove(TString::kTrailing, ',');
613
614 return keyWords;
615}
616
617//-----------------------------------------------------------------------
5d8c0c8a 618Double_t AliCounterCollection::GetSum(TString selections, Bool_t* longCounters)
d810835e 619{
620 /// Get the overall statistics for the given selection (result is integrated over not specified rubrics):
621 /// - format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter).
5d8c0c8a 622 /// - The flag "longCounters" tells whether the histogram contains value(s) larger than INT_MAX.
623
624 // set the flag "longCounters" according to the content of current counters
625 if (longCounters) *longCounters = fLongCounters;
d810835e 626
627 if (!fCounters) {
628 AliError("counters are not initialized");
629 return 0.;
630 }
631
632 selections.ToUpper();
633
634 // decode the selections
635 Short_t** select = DecodeSelection(selections, TObjArray());
636 if (!select) return 0.;
637
638 // loop over every filled counters and compute integral
639 Double_t sum = 0.;
640 Int_t nDims = fCounters->GetNdimensions();
641 Int_t* coord = new Int_t[nDims];
642 for (Long64_t i=0; i<fCounters->GetNbins(); ++i) {
643
644 // get the content of the counter
645 Double_t value = fCounters->GetBinContent(i, coord);
646
647 // discard not selected counters and compute the selection factor
648 Int_t selectionFactor = 1;
649 for (Int_t dim = 0; dim < nDims && selectionFactor != 0; dim++) selectionFactor *= select[dim][coord[dim]];
650 if (selectionFactor == 0) continue;
651
652 // compute integral
653 sum += selectionFactor * value;
654 }
655
5d8c0c8a 656 // check if the sum exceed INT_MAX (only in case of integer counters)
657 if (longCounters && !fWeightedCounters && sum > INT_MAX) *longCounters = kTRUE;
658
d810835e 659 // clean memory
660 for (Int_t iDim=0; iDim<nDims; iDim++) delete[] select[iDim];
661 delete[] select;
662 delete[] coord;
663
664 return sum;
665}
666
667//-----------------------------------------------------------------------
94ef1a28 668void AliCounterCollection::PrintKeyWords() const
669{
670 /// Print the full list of key words.
671
672 if (!fCounters) {
673 AliError("counters are not initialized");
674 return;
675 }
676
677 // loop over rubrics
678 Int_t nRubrics = fCounters->GetNdimensions();
679 for (Int_t iDim=0; iDim<nRubrics; iDim++) {
680 TAxis* axis = fCounters->GetAxis(iDim);
681
682 // print rubric's name
683 printf("\n%s:", axis->GetName());
684
685 // loop over key words
686 Bool_t first = kTRUE;
687 TObjString* label = 0x0;
688 TIter nextLabel(axis->GetLabels());
689 while ((label = static_cast<TObjString*>(nextLabel()))) {
690
691 //print key word's name
692 if (first) {
693 printf("%s", label->String().Data());
694 first = kFALSE;
695 } else printf(",%s", label->String().Data());
696
697 }
698 }
699 printf("\n\n");
700}
701
702//-----------------------------------------------------------------------
703void AliCounterCollection::PrintValue(TString selections)
704{
705 /// Print value of selected counter.
6f5626c7 706 /// format of "selections" is rubric:keyWord/rubric:keyWord/rubric:keyWord/...
94ef1a28 707
708 if (!fCounters) {
709 AliError("counters are not initialized");
710 return;
711 }
712
713 selections.ToUpper();
714
715 // convert external to internal key
716 Int_t nEmptySlots = 0;
717 const Int_t* selectedBins = FindBins(selections, kFALSE, nEmptySlots);
718 if (!selectedBins) return;
719
720 // check for empty slots
721 if (nEmptySlots > 0) {
722 AliError("incomplete key");
723 delete[] selectedBins;
724 return;
725 }
726
727 // print value
d810835e 728 if (fWeightedCounters) printf("\n%g\n\n", fCounters->GetBinContent(selectedBins));
5d8c0c8a 729 else if (fLongCounters) printf("\n%ld\n\n", (Long_t) fCounters->GetBinContent(selectedBins));
d810835e 730 else printf("\n%d\n\n", (Int_t) fCounters->GetBinContent(selectedBins));
94ef1a28 731
732 // clean memory
733 delete[] selectedBins;
734}
735
736//-----------------------------------------------------------------------
7471ae1a 737void AliCounterCollection::Print(TString rubrics, TString selections, Bool_t removeEmpty)
94ef1a28 738{
739 /// Print desired rubrics for the given selection:
740 /// - format of "rubrics" is rubric1/rubric2/.. (order matters only for output).
6f5626c7 741 /// - format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter).
94ef1a28 742 /// If "data" contains 1 rubric, the output will be one counter for each element of that rubric.
743 /// If "data" contains 2 rubrics, the output will be an array of counters, rubric1 vs rubric2.
744 /// If "data" contains 3 rubrics, the output will be an array rubric1 vs rubric2 for each element in rubric3.
745 /// ...
746 /// Results are integrated over rubrics not specified neither in "rubrics" nor in "selections".
747
748 if (!fCounters) {
749 AliError("counters are not initialized");
750 return;
751 }
752
753 rubrics.ToUpper();
754 selections.ToUpper();
755
756 // get the rubrics to print
757 TObjArray* rubricsToPrint = rubrics.Tokenize("/");
758 if (rubricsToPrint->GetEntriesFast() == 0) {
759 delete rubricsToPrint;
760 return;
761 }
762
763 // remove rubrics called twice
764 CleanListOfStrings(rubricsToPrint);
765
766 // project counters in the rubrics to print according to the selections
5d8c0c8a 767 Bool_t longCounters = kFALSE;
768 TObject* hist = Projection(*rubricsToPrint, selections, longCounters);
94ef1a28 769 if (!hist) {
770 delete rubricsToPrint;
771 return;
772 }
773
774 // print counters
775 Int_t nRubricsToPrint = rubricsToPrint->GetEntriesFast();
6f5626c7 776 if (nRubricsToPrint == 1 && (static_cast<TH1D*>(hist))->GetEntries() > 0)
5d8c0c8a 777 PrintList(static_cast<TH1D*>(hist), removeEmpty, longCounters);
6f5626c7 778 else if (nRubricsToPrint == 2 && (static_cast<TH2D*>(hist))->GetEntries() > 0)
5d8c0c8a 779 PrintArray(static_cast<TH2D*>(hist), removeEmpty, longCounters);
6f5626c7 780 else if (nRubricsToPrint > 2 && (static_cast<THnSparse*>(hist))->GetEntries() > 0)
5d8c0c8a 781 PrintListOfArrays(static_cast<THnSparse*>(hist), removeEmpty, longCounters);
94ef1a28 782 else
783 printf("\nselected counters are empty\n\n");
784
785 // clean memory
786 delete rubricsToPrint;
787 delete hist;
788}
789
790//-----------------------------------------------------------------------
6f5626c7 791void AliCounterCollection::PrintSum(TString selections)
94ef1a28 792{
6f5626c7 793 /// Print the overall statistics for the given selection (result is integrated over not specified rubrics):
794 /// - format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter).
5d8c0c8a 795 Bool_t longCounters = kFALSE;
796 Double_t sum = GetSum(selections, &longCounters);
d810835e 797 if (fWeightedCounters) printf("\n%g\n\n", sum);
5d8c0c8a 798 else if (longCounters) printf("\n%ld\n\n", (Long_t)sum);
d810835e 799 else printf("\n%d\n\n", (Int_t)sum);
94ef1a28 800}
801
802//-----------------------------------------------------------------------
5d8c0c8a 803void AliCounterCollection::PrintList(const TH1D* hist, Bool_t removeEmpty, Bool_t longCounters) const
94ef1a28 804{
805 /// Print the content of 1D histogram as a list.
806
807 // set the format to print labels
808 THashList* labels = hist->GetXaxis()->GetLabels();
d810835e 809 TString format = "";
5d8c0c8a 810 if (fWeightedCounters) format = Form("\n%%%ds %%10g",GetMaxLabelSize(labels));
811 else if (longCounters) format = Form("\n%%%ds %%16ld",GetMaxLabelSize(labels));
812 else format = Form("\n%%%ds %%10d",GetMaxLabelSize(labels));
94ef1a28 813
814 // print value for each label
815 TObjString* label = 0x0;
816 TIter nextLabel(labels);
817 while ((label = static_cast<TObjString*>(nextLabel()))) {
818 Int_t bin = (Int_t) label->GetUniqueID();
7471ae1a 819 Double_t value = hist->GetBinContent(bin);
820 if (removeEmpty && value == 0.) continue;
821 if (fWeightedCounters) printf(format.Data(), label->String().Data(), value);
5d8c0c8a 822 else if (longCounters) printf(format.Data(), label->String().Data(), (Long_t) value);
7471ae1a 823 else printf(format.Data(), label->String().Data(), (Int_t) value);
94ef1a28 824 }
825 printf("\n\n");
826}
827
828//-----------------------------------------------------------------------
5d8c0c8a 829void AliCounterCollection::PrintArray(const TH2D* hist, Bool_t removeEmpty, Bool_t longCounters) const
94ef1a28 830{
831 /// Print the content of 2D histogram as an array.
832
833 // set the format to print labels in X direction
834 THashList* labelsX = hist->GetXaxis()->GetLabels();
835 TString formatX(Form("\n%%%ds ",GetMaxLabelSize(labelsX)));
836
5d8c0c8a 837 // set the format to print labels in Y direction
94ef1a28 838 THashList* labelsY = hist->GetYaxis()->GetLabels();
5d8c0c8a 839 Int_t maxLabelSizeY = GetMaxLabelSize(labelsY);
840 TString formatYv = "";
841 if (fWeightedCounters) {
842 maxLabelSizeY = TMath::Max(10, maxLabelSizeY);
843 formatYv = Form("%%%dg ",maxLabelSizeY);
844 } else if (longCounters) {
845 maxLabelSizeY = TMath::Max(16, maxLabelSizeY);
846 formatYv = Form("%%%dld ",maxLabelSizeY);
847 } else {
848 maxLabelSizeY = TMath::Max(10, maxLabelSizeY);
849 formatYv = Form("%%%dd ",maxLabelSizeY);
850 }
851 TString formatYs = Form("%%%ds ",maxLabelSizeY);
94ef1a28 852
7471ae1a 853 // if required, set the list of labels for which all counters are not empty
854 Bool_t *useLabelX = 0x0, *useLabelY = 0x0;
855 TObjString *labelX = 0x0, *labelY = 0x0;
856 TIter nextLabelX(labelsX);
857 TIter nextLabelY(labelsY);
858 if (removeEmpty) {
859
860 // create label flags and set them as unused
861 useLabelX = new Bool_t[labelsX->GetSize()+1];
862 memset(useLabelX, kFALSE, sizeof(Bool_t) * (labelsX->GetSize()+1));
863 useLabelY = new Bool_t[labelsY->GetSize()+1];
864 memset(useLabelY, kFALSE, sizeof(Bool_t) * (labelsY->GetSize()+1));
865
866 // loop over labels in X direction
867 while ((labelX = static_cast<TObjString*>(nextLabelX()))) {
868 Int_t binX = (Int_t) labelX->GetUniqueID();
869
870 // loop over labels in Y direction
871 nextLabelY.Reset();
872 while ((labelY = static_cast<TObjString*>(nextLabelY()))) {
873 Int_t binY = (Int_t) labelY->GetUniqueID();
874
875 // both labels already set as used
876 if (useLabelX[binX] && useLabelY[binY]) continue;
877
878 // skip empty bins
879 if (hist->GetBinContent(binX, binY) == 0.) continue;
880
881 // set label as used
882 useLabelX[binX] = kTRUE;
883 useLabelY[binY] = kTRUE;
884
885 }
886
887 }
888
889 }
890
94ef1a28 891 // print labels in Y axis
892 printf(formatX.Data()," ");
7471ae1a 893 nextLabelY.Reset();
894 while ((labelY = static_cast<TObjString*>(nextLabelY()))) {
895 if (removeEmpty && !useLabelY[labelY->GetUniqueID()]) continue;
94ef1a28 896 printf(formatYs.Data(), labelY->String().Data());
7471ae1a 897 }
94ef1a28 898
899 // fill array for each label in X axis
7471ae1a 900 nextLabelX.Reset();
94ef1a28 901 while ((labelX = static_cast<TObjString*>(nextLabelX()))) {
902 Int_t binX = (Int_t) labelX->GetUniqueID();
903
7471ae1a 904 if (removeEmpty && !useLabelX[binX]) continue;
905
94ef1a28 906 // print label X
907 printf(formatX.Data(), labelX->String().Data());
908
909 // print value for each label in Y axis
910 nextLabelY.Reset();
911 while ((labelY = static_cast<TObjString*>(nextLabelY()))) {
912 Int_t binY = (Int_t) labelY->GetUniqueID();
7471ae1a 913 if (removeEmpty && !useLabelY[binY]) continue;
5d8c0c8a 914 if (fWeightedCounters) printf(formatYv.Data(), hist->GetBinContent(binX, binY));
915 else if (longCounters) printf(formatYv.Data(), (Long_t) hist->GetBinContent(binX, binY));
916 else printf(formatYv.Data(), (Int_t) hist->GetBinContent(binX, binY));
94ef1a28 917 }
918 }
919 printf("\n\n");
7471ae1a 920
921 // clean memory
922 if (removeEmpty) {
923 delete[] useLabelX;
924 delete[] useLabelY;
925 }
94ef1a28 926}
927
928//-----------------------------------------------------------------------
5d8c0c8a 929void AliCounterCollection::PrintListOfArrays(const THnSparse* hist, Bool_t removeEmpty, Bool_t longCounters) const
94ef1a28 930{
931 /// Print the content of nD histogram as a list of arrays.
932
933 // set the format to print labels in X direction
934 THashList* labelsX = hist->GetAxis(0)->GetLabels();
935 TString formatX(Form("\n%%%ds ",GetMaxLabelSize(labelsX)));
936
5d8c0c8a 937 // set the format to print labels in Y direction
94ef1a28 938 THashList* labelsY = hist->GetAxis(1)->GetLabels();
5d8c0c8a 939 Int_t maxLabelSizeY = GetMaxLabelSize(labelsY);
940 TString formatYv = "";
941 if (fWeightedCounters) {
942 maxLabelSizeY = TMath::Max(10, maxLabelSizeY);
943 formatYv = Form("%%%dg ",maxLabelSizeY);
944 } else if (longCounters) {
945 maxLabelSizeY = TMath::Max(16, maxLabelSizeY);
946 formatYv = Form("%%%dld ",maxLabelSizeY);
947 } else {
948 maxLabelSizeY = TMath::Max(10, maxLabelSizeY);
949 formatYv = Form("%%%dd ",maxLabelSizeY);
950 }
94ef1a28 951 TString formatYs(Form("%%%ds ",maxLabelSizeY));
94ef1a28 952
953 // create a list containing each combination of labels refering the arrays to be printout
954 TList listOfCombis;
955 listOfCombis.SetOwner();
956
957 // add a first empty combination
958 Int_t nDim = hist->GetNdimensions();
959 listOfCombis.AddLast(new TObjArray(nDim-2));
960
961 // loop over the nDim-2 other rubrics
962 for (Int_t i=2; i<nDim; i++) {
963
964 // save the last label of that rubic
965 THashList* labels = hist->GetAxis(i)->GetLabels();
966 TObjString* lastLabel = (labels) ? static_cast<TObjString*>(labels->Last()) : 0x0;
967 if (!lastLabel) return;
968
969 // prepare iteration over the list of labels
970 TIter nextLabel(labels);
971
972 // loop over existing combinations
973 TObjLink* lnk = listOfCombis.FirstLink();
974 while (lnk) {
975
976 // get the current combination
977 TObjArray* currentCombi = static_cast<TObjArray*>(lnk->GetObject());
978
979 // loop over labels in the current rubric
980 nextLabel.Reset();
981 TObjString* label = 0x0;
982 while ((label = static_cast<TObjString*>(nextLabel()))) {
983
984 // stop at the last one
985 if (label == lastLabel) break;
986
987 // copy the current combination, add the current label to it and add it to the list of combinations
988 TObjArray* combi = new TObjArray(*currentCombi);
989 combi->AddLast(label);
990 listOfCombis.AddBefore(lnk, combi);
991 }
992
993 // add the last label to the current combination
994 currentCombi->AddLast(lastLabel);
995
996 lnk = lnk->Next();
997 }
998
999 }
1000
1001 // create bin coordinates to access individual counters
1002 Int_t* bins = new Int_t[nDim];
1003
7471ae1a 1004 // create label flags
1005 Bool_t *useLabelX = 0x0, *useLabelY = 0x0;
1006 if (removeEmpty) {
1007 useLabelX = new Bool_t[labelsX->GetSize()+1];
1008 useLabelY = new Bool_t[labelsY->GetSize()+1];
1009 }
1010
94ef1a28 1011 // loop over each combination of labels
1012 TObjArray* combi = 0x0;
1013 TIter nextCombi(&listOfCombis);
1014 while ((combi = static_cast<TObjArray*>(nextCombi()))) {
1015
1016 // make the name of the combination and fill the corresponding bin coordinates
1017 TString combiName = "/";
1018 for (Int_t i=2; i<nDim; i++) {
1019 TObjString* label = static_cast<TObjString*>(combi->UncheckedAt(i-2));
1020 combiName += Form("%s/",label->String().Data());
1021 bins[i] = (Int_t)label->GetUniqueID();
1022 }
1023
7471ae1a 1024 // reset the list of labels for which all counters are not empty
1025 if (removeEmpty) {
1026 memset(useLabelX, kFALSE, sizeof(Bool_t) * (labelsX->GetSize()+1));
1027 memset(useLabelY, kFALSE, sizeof(Bool_t) * (labelsY->GetSize()+1));
1028 }
1029
94ef1a28 1030 Bool_t empty = kTRUE;
1031 TObjString* labelX = 0x0;
1032 TObjString* labelY = 0x0;
1033 TIter nextLabelX(labelsX);
1034 TIter nextLabelY(labelsY);
7471ae1a 1035 // loop over labels in X direction
94ef1a28 1036 while ((labelX = static_cast<TObjString*>(nextLabelX()))) {
1037 bins[0] = (Int_t) labelX->GetUniqueID();
7471ae1a 1038
1039 // loop over labels in Y direction
94ef1a28 1040 nextLabelY.Reset();
1041 while ((labelY = static_cast<TObjString*>(nextLabelY()))) {
1042 bins[1] = (Int_t) labelY->GetUniqueID();
7471ae1a 1043
1044 // both labels already set as used
1045 if (removeEmpty && useLabelX[bins[0]] && useLabelY[bins[1]]) continue;
1046
1047 // skip empty bins
1048 if (hist->GetBinContent(bins) == 0.) continue;
1049
1050 // set label as used and array as not empty
1051 empty = kFALSE;
1052 if (removeEmpty) {
1053 useLabelX[bins[0]] = kTRUE;
1054 useLabelY[bins[1]] = kTRUE;
1055 } else break;
1056
94ef1a28 1057 }
7471ae1a 1058
1059 if (!removeEmpty && !empty) break;
1060
94ef1a28 1061 }
7471ae1a 1062
1063 // skip empty arrays
94ef1a28 1064 if (empty) continue;
1065
1066 // print the name of the combination of labels refering the incoming array
1067 printf("\n%s:\n",combiName.Data());
1068
1069 // print labels in Y axis
1070 printf(formatX.Data()," ");
1071 nextLabelY.Reset();
7471ae1a 1072 while ((labelY = static_cast<TObjString*>(nextLabelY()))) {
1073 if (removeEmpty && !useLabelY[labelY->GetUniqueID()]) continue;
94ef1a28 1074 printf(formatYs.Data(), labelY->String().Data());
7471ae1a 1075 }
94ef1a28 1076
1077 // fill array for each label in X axis
1078 nextLabelX.Reset();
1079 while ((labelX = static_cast<TObjString*>(nextLabelX()))) {
1080 bins[0] = (Int_t) labelX->GetUniqueID();
1081
7471ae1a 1082 if (removeEmpty && !useLabelX[bins[0]]) continue;
1083
94ef1a28 1084 // print label X
1085 printf(formatX.Data(), labelX->String().Data());
1086
1087 // print value for each label in Y axis
1088 nextLabelY.Reset();
1089 while ((labelY = static_cast<TObjString*>(nextLabelY()))) {
1090 bins[1] = (Int_t) labelY->GetUniqueID();
7471ae1a 1091 if (removeEmpty && !useLabelY[bins[1]]) continue;
5d8c0c8a 1092 if (fWeightedCounters) printf(formatYv.Data(), hist->GetBinContent(bins));
1093 else if (longCounters) printf(formatYv.Data(), (Long_t) hist->GetBinContent(bins));
1094 else printf(formatYv.Data(), (Int_t) hist->GetBinContent(bins));
94ef1a28 1095 }
1096 }
1097 printf("\n\n");
1098 }
1099
1100 // clean memory
1101 delete[] bins;
7471ae1a 1102 if (removeEmpty) {
1103 delete[] useLabelX;
1104 delete[] useLabelY;
1105 }
94ef1a28 1106}
1107
1108//-----------------------------------------------------------------------
1109Int_t AliCounterCollection::GetMaxLabelSize(THashList* labels) const
1110{
1111 /// Return the number of characters of the longest label.
1112 Int_t maxLabelSize = 0;
1113 TObjString* label = 0x0;
1114 TIter nextLabel(labels);
1115 while ((label = static_cast<TObjString*>(nextLabel())))
1116 maxLabelSize = TMath::Max(maxLabelSize, label->String().Length());
1117 return maxLabelSize;
1118}
1119
1120//-----------------------------------------------------------------------
0dc8b856 1121TH1D* AliCounterCollection::Get(TString rubric, TString selections)
94ef1a28 1122{
0dc8b856 1123 /// Get counters of the rubric "rubric" for the given "selection".
6f5626c7 1124 /// Format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter).
94ef1a28 1125 /// Results are integrated over rubrics not specified neither in "rubric1" nor in "selections".
1126 /// It is the responsability of the user to delete the returned histogram.
1127
1128 if (!fCounters) {
1129 AliError("counters are not initialized");
1130 return 0x0;
1131 }
1132
1133 rubric.ToUpper();
1134 selections.ToUpper();
1135
1136 // fill the rubrics to print
1137 TObjArray rubricsToPrint(1);
1138 rubricsToPrint.SetOwner();
1139 rubricsToPrint.AddLast(new TObjString(rubric.Data()));
1140
1141 // project counters in the rubrics to print according to the selections
5d8c0c8a 1142 Bool_t longCounters = kFALSE;
1143 TH1D* hist = static_cast<TH1D*>(Projection(rubricsToPrint, selections, longCounters));
94ef1a28 1144
0dc8b856 1145 // make it ready to display
94ef1a28 1146 if (hist) {
1147
0dc8b856 1148 // remove statistic box
94ef1a28 1149 hist->SetStats(kFALSE);
1150
0dc8b856 1151 // prepare X axis
94ef1a28 1152 TAxis* axis = hist->GetXaxis();
1153 THashList* labels = axis->GetLabels();
1154 Int_t nLabels = (labels) ? labels->GetSize() : 1;
1155 axis->SetRange(1,nLabels);
1156 axis->SetNdivisions(1,kFALSE);
1157 axis->SetTitle(rubric.Data());
1158
0dc8b856 1159 // prepare Y axis
94ef1a28 1160 hist->GetYaxis()->SetTitle("Counts");
1161 }
1162
1163 return hist;
1164}
1165
1166//-----------------------------------------------------------------------
0dc8b856 1167TH2D* AliCounterCollection::Get(TString rubric1, TString rubric2, TString selections)
94ef1a28 1168{
0dc8b856 1169 /// Get counters of the "rubric1" vs "rubric2" for the given "selection".
6f5626c7 1170 /// Format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter).
94ef1a28 1171 /// Results are integrated over rubrics not specified neither in "rubric1", "rubric2" nor in "selections".
1172 /// It is the responsability of the user to delete the returned histogram.
1173
1174 if (!fCounters) {
1175 AliError("counters are not initialized");
1176 return 0x0;
1177 }
1178
1179 rubric1.ToUpper();
1180 rubric2.ToUpper();
1181 selections.ToUpper();
1182
1183 // fill the rubrics to print
1184 TObjArray rubricsToPrint(2);
1185 rubricsToPrint.SetOwner();
1186 rubricsToPrint.AddLast(new TObjString(rubric2.Data()));
1187 rubricsToPrint.AddLast(new TObjString(rubric1.Data()));
1188
1189 // project counters in the rubrics to print according to the selections
5d8c0c8a 1190 Bool_t longCounters = kFALSE;
1191 TH2D* hist = static_cast<TH2D*>(Projection(rubricsToPrint, selections, longCounters));
94ef1a28 1192
1193 // draw counters
1194 if (hist) {
1195
0dc8b856 1196 // remove statistic box
94ef1a28 1197 hist->SetStats(kFALSE);
1198
0dc8b856 1199 // prepare X axis
94ef1a28 1200 TAxis* axisX = hist->GetXaxis();
1201 THashList* labelsX = axisX->GetLabels();
1202 Int_t nLabelsX = (labelsX) ? labelsX->GetSize() : 1;
1203 axisX->SetRange(1,nLabelsX);
1204 axisX->SetNdivisions(1,kFALSE);
1205 axisX->SetTitle(rubric2.Data());
1206
0dc8b856 1207 // prepare Y axis
94ef1a28 1208 TAxis* axisY = hist->GetYaxis();
1209 THashList* labelsY = axisY->GetLabels();
1210 Int_t nLabelsY = (labelsY) ? labelsY->GetSize() : 1;
1211 axisY->SetRange(1,nLabelsY);
1212 axisY->SetNdivisions(1,kFALSE);
1213 axisY->SetTitle(rubric1.Data());
1214 }
1215
1216 return hist;
1217}
1218
1219//-----------------------------------------------------------------------
0dc8b856 1220TH1D* AliCounterCollection::Draw(TString rubric, TString selections)
1221{
1222 /// Draw counters of the rubric "rubric" for the given "selection".
1223 /// Format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter).
1224 /// Results are integrated over rubrics not specified neither in "rubric1" nor in "selections".
1225 /// It is the responsability of the user to delete the returned histogram.
1226 TH1D* hist = Get(rubric, selections);
1227 if (hist) hist->Draw("htext");
1228 return hist;
1229}
1230
1231//-----------------------------------------------------------------------
1232TH2D* AliCounterCollection::Draw(TString rubric1, TString rubric2, TString selections)
1233{
1234 /// Draw counters of the "rubric1" vs "rubric2" for the given "selection".
1235 /// Format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter).
1236 /// Results are integrated over rubrics not specified neither in "rubric1", "rubric2" nor in "selections".
1237 /// It is the responsability of the user to delete the returned histogram.
1238 TH2D* hist = Get(rubric1, rubric2, selections);
1239 if (hist) hist->Draw("text");
1240 return hist;
1241}
1242
1243//-----------------------------------------------------------------------
5d8c0c8a 1244TObject* AliCounterCollection::Projection(const TObjArray& data, const TString& selections, Bool_t& longCounters)
94ef1a28 1245{
1246 /// Return desired "data" for the given "selection" stored in a new histogram or 0x0 in case of failure.
1247 /// The type of the histogram (TH1D, TH2D or THnSparse) depend on the number of data.
5d8c0c8a 1248 /// The flag "longCounters" tells whether the histogram contains value(s) larger than INT_MAX.
94ef1a28 1249 /// It is the responsability of the user to delete the returned histogram.
1250
5d8c0c8a 1251 // set the flag "longCounters" according to the content of current counters
1252 longCounters = fLongCounters;
1253
6f5626c7 1254 // decode the selections
1255 Short_t** select = DecodeSelection(selections, data);
1256 if (!select) return 0x0;
1257
1258 // define name and dimensions of projection histo
1259 TString name(fCounters->GetName());
1260 Int_t nDims = fCounters->GetNdimensions();
1261 Int_t nTargetDims = data.GetEntriesFast();
1262 TArrayI targetDims(nTargetDims);
1263 TArrayI nNewBins(nTargetDims);
1264 TArrayI* OldToNewCoord = new TArrayI[nTargetDims];
1265 for (Int_t i=0; i<nTargetDims; i++) {
1266
1267 // histo name
1268 name += Form("_%s",static_cast<TObjString*>(data.UncheckedAt(i))->String().Data());
1269
1270 // find target dims
94ef1a28 1271 targetDims[i] = FindDim(static_cast<TObjString*>(data.UncheckedAt(i))->String());
6f5626c7 1272
1273 // set number of selected bins in the target dims and make the correspondence between old and new coordinates
1274 nNewBins[i] = 0;
1275 if (targetDims[i] > -1) {
1276 Int_t nBins = GetNActiveBins(targetDims[i]) + 1;
1277 OldToNewCoord[i].Set(nBins);
1278 for (Int_t j=1; j<nBins; j++) if (select[targetDims[i]][j] > 0) OldToNewCoord[i][j] = ++nNewBins[i];
1279 }
1280
1281 // clean memory and return 0x0 in case of problem
1282 if (nNewBins[i] == 0) {
1283 for (Int_t iDim=0; iDim<nDims; iDim++) delete[] select[iDim];
1284 delete[] select;
1285 delete[] OldToNewCoord;
94ef1a28 1286 return 0x0;
1287 }
6f5626c7 1288
94ef1a28 1289 }
1290
6f5626c7 1291 // define title of projection histo
1292 TString title = "Selections: ";
1293 TString selectionString(selections);
1294 selectionString.Remove(TString::kBoth, '/');
1295 if (selectionString.Length() > 0) title += Form("%s/", selectionString.Data());
1296 TObject* rub = 0x0;
1297 TIter nextRubric(fRubrics);
1298 while ((rub = nextRubric())) {
1299 if (selectionString.Contains(Form("%s:",rub->GetName()))) continue;
1300 if (data.Contains(rub->GetName())) continue;
1301 title += Form("%s:ANY/", rub->GetName());
94ef1a28 1302 }
6f5626c7 1303 title.ReplaceAll("/", " ");
94ef1a28 1304
6f5626c7 1305 // Create new histograms
1306 TObject* hist;
1307 if (nTargetDims == 1) hist = new TH1D(name.Data(), title.Data(), nNewBins[0], 0., 1.);
1308 else if (nTargetDims == 2) hist = new TH2D(name.Data(), title.Data(), nNewBins[0], 0., 1., nNewBins[1], 0., 1.);
d810835e 1309 else if (fWeightedCounters) hist = new THnSparseT<TArrayF>(name.Data(), title.Data(), nTargetDims, nNewBins.GetArray(), 0x0, 0x0);
5d8c0c8a 1310 else if (fLongCounters) hist = new THnSparseT<TArrayL>(name.Data(), title.Data(), nTargetDims, nNewBins.GetArray(), 0x0, 0x0);
6f5626c7 1311 else hist = new THnSparseT<TArrayI>(name.Data(), title.Data(), nTargetDims, nNewBins.GetArray(), 0x0, 0x0);
94ef1a28 1312
6f5626c7 1313 // Set new axis labels
1314 TObjString* label;
1315 if (nTargetDims < 3) {
94ef1a28 1316
6f5626c7 1317 // X axis
1318 TIter nextLabelX(fCounters->GetAxis(targetDims[0])->GetLabels());
1319 while ((label = static_cast<TObjString*>(nextLabelX()))) {
1320 if (select[targetDims[0]][label->GetUniqueID()] > 0) {
1321 static_cast<TH1*>(hist)->GetXaxis()->SetBinLabel(OldToNewCoord[0][label->GetUniqueID()], label->String().Data());
1322 }
94ef1a28 1323 }
1324
6f5626c7 1325 // Y axis if any
1326 if (nTargetDims == 2) {
1327 TIter nextLabelY(fCounters->GetAxis(targetDims[1])->GetLabels());
1328 while ((label = static_cast<TObjString*>(nextLabelY()))) {
1329 if (select[targetDims[1]][label->GetUniqueID()] > 0) {
1330 static_cast<TH1*>(hist)->GetYaxis()->SetBinLabel(OldToNewCoord[1][label->GetUniqueID()], label->String().Data());
1331 }
1332 }
1333 }
94ef1a28 1334
6f5626c7 1335 } else {
94ef1a28 1336
6f5626c7 1337 // all axes
1338 for (Int_t i=0; i<nTargetDims; i++) {
1339 TIter nextLabel(fCounters->GetAxis(targetDims[i])->GetLabels());
1340 while ((label = static_cast<TObjString*>(nextLabel()))) {
1341 if (select[targetDims[i]][label->GetUniqueID()] > 0) {
1342 static_cast<THnSparse*>(hist)->GetAxis(i)->SetBinLabel(OldToNewCoord[i][label->GetUniqueID()], label->String().Data());
1343 }
1344 }
94ef1a28 1345 }
1346
6f5626c7 1347 }
1348
1349 // loop over every filled counters
1350 Int_t* coord = new Int_t[nDims];
1351 Int_t* newCoord = new Int_t[nTargetDims];
1352 Int_t nEntries = 0;
1353 for (Long64_t i=0; i<fCounters->GetNbins(); ++i) {
94ef1a28 1354
6f5626c7 1355 // get the content of the counter
1356 Double_t value = fCounters->GetBinContent(i, coord);
94ef1a28 1357
6f5626c7 1358 // discard not selected counters and compute the selection factor
1359 Int_t selectionFactor = 1;
1360 for (Int_t dim = 0; dim < nDims && selectionFactor != 0; dim++) selectionFactor *= select[dim][coord[dim]];
1361 if (selectionFactor == 0) continue;
94ef1a28 1362
6f5626c7 1363 // find new coordinates in the projection histo
1364 for (Int_t d = 0; d < nTargetDims; ++d) newCoord[d] = OldToNewCoord[d][coord[targetDims[d]]];
1365
1366 // fill projection histo
1367 if (nTargetDims < 3) {
5d8c0c8a 1368
6f5626c7 1369 Int_t linBin = (nTargetDims == 1) ? newCoord[0] : static_cast<TH1*>(hist)->GetBin(newCoord[0], newCoord[1]);
1370 static_cast<TH1*>(hist)->AddBinContent(linBin, selectionFactor*value);
5d8c0c8a 1371
1372 // check if the new value exceed INT_MAX (only in case of integer counters)
1373 if (!fWeightedCounters && !longCounters && static_cast<TH1*>(hist)->GetBinContent(linBin) > INT_MAX)
1374 longCounters = kTRUE;
1375
1376 } else if (fWeightedCounters || longCounters) {
1377
1378 static_cast<THnSparse*>(hist)->AddBinContent(newCoord, selectionFactor*value);
1379
1380 } else {
1381
1382 // switch to long counters if needed before filling
1383 Long64_t linBin = static_cast<THnSparse*>(hist)->GetBin(newCoord, kTRUE);
1384 Double_t currentValue = static_cast<THnSparse*>(hist)->GetBinContent(linBin);
1385 if (currentValue+selectionFactor*value > INT_MAX) {
1386 THnSparse* h = static_cast<THnSparse*>(hist);
1387 ConvertToTHnSparseL(h);
1388 hist = h;
1389 longCounters = kTRUE;
1390 static_cast<THnSparse*>(hist)->AddBinContent(newCoord, selectionFactor*value);
1391 } else static_cast<THnSparse*>(hist)->AddBinContent(linBin, selectionFactor*value);
1392
1393 }
94ef1a28 1394
6f5626c7 1395 nEntries++;
94ef1a28 1396 }
1397
6f5626c7 1398 // update the number of entries
1399 if (nTargetDims < 3) static_cast<TH1*>(hist)->SetEntries(nEntries);
1400 else static_cast<THnSparse*>(hist)->SetEntries(nEntries);
1401
94ef1a28 1402 // clean memory
6f5626c7 1403 for (Int_t iDim=0; iDim<nDims; iDim++) delete[] select[iDim];
1404 delete[] select;
1405 delete[] coord;
1406 delete[] newCoord;
1407 delete[] OldToNewCoord;
94ef1a28 1408
1409 return hist;
1410}
1411
1412//-----------------------------------------------------------------------
1413Int_t* AliCounterCollection::CheckConsistency(const AliCounterCollection* c)
1414{
1415 /// Consistency check of the two counter collections. To be consistent, both counters
1416 /// must have the same rubrics with the same list of authorized key words if any.
1417 /// Return the correspondence between the local rubric ordering and the one of the other counter,
1418 /// or 0x0 in case of problem. It is the responsability of the user to delete the returned array.
1419
1420 if (!fCounters || !c->fCounters) {
1421 AliError("counters are not initialized");
1422 return 0x0;
1423 }
1424
d810835e 1425 // check if both counters are weighted or not
1426 if (c->fWeightedCounters != fWeightedCounters) AliWarning("merging non-weighted with weigthed counters");
1427
94ef1a28 1428 // check if the number of rubrics is the same
1429 Int_t nRubrics = fRubrics->GetSize();
1430 if (c->fRubrics->GetSize() != nRubrics) {
1431 AliError("both counters do not contain the same number of rubrics");
1432 return 0x0;
1433 }
1434
1435 Int_t* otherDims = new Int_t[nRubrics];
1436
1437 // loop over local rubrics
1438 TObject* rubric1 = 0x0;
1439 TIter nextRubric(fRubrics);
1440 while ((rubric1 = nextRubric())) {
1441
1442 // find that rubric in the other counter
1443 TObject* rubric2 = c->fRubrics->FindObject(rubric1->GetName());
1444 if (!rubric2) {
1445 AliError(Form("the other counter does not contain the rubric %s", rubric1->GetName()));
1446 delete[] otherDims;
1447 return 0x0;
1448 }
1449
1450 // check the list of authorized key words if any
1451 TObjArray* keyWords1 = dynamic_cast<TObjArray*>(rubric1);
1452 TObjArray* keyWords2 = dynamic_cast<TObjArray*>(rubric2);
1453 if (keyWords1 && keyWords2) {
1454
1455 // check if the number of key words is the same
1456 if (keyWords1->GetEntriesFast() != keyWords2->GetEntriesFast()) {
1457 AliError("that rubric does not contain the same number of authorized key words in both counters");
1458 delete[] otherDims;
1459 return 0x0;
1460 }
1461
1462 // loop over local key words
1463 TObjString* keyWord = 0x0;
1464 TIter nextKeyWord(keyWords1);
1465 while ((keyWord = static_cast<TObjString*>(nextKeyWord()))) {
1466
1467 // find that key word in the corresponding rubric of the other counter
1468 if (!keyWords2->FindObject(keyWord->String().Data())) {
1469 AliError(Form("rubric %s does not contain the key word %s in the other counter", rubric1->GetName(), keyWord->String().Data()));
1470 delete[] otherDims;
1471 return 0x0;
1472 }
1473
1474 }
1475
1476 } else if (keyWords1 || keyWords2) {
1477
1478 // that rubric has not been initialized the same way in both counter
1479 if (keyWords1) {
1480 AliError(Form("rubric %s of the other counter does not contain a list of authorized key words while this does", rubric1->GetName()));
1481 } else {
1482 AliError(Form("rubric %s of this counter does not contain a list of authorized key words while the other does", rubric1->GetName()));
1483 }
1484 delete[] otherDims;
1485 return 0x0;
1486
1487 }
1488
1489 // save the correspondence of rubric IDs in both counters
1490 otherDims[rubric1->GetUniqueID()] = rubric2->GetUniqueID();
1491
1492 }
1493
1494 return otherDims;
1495}
1496
1497//-----------------------------------------------------------------------
1498void AliCounterCollection::Add(const AliCounterCollection* counter)
1499{
1500 /// Add the given AliCounterCollections to this. They must have the
1501 /// same rubrics with the same list of authorized key words if any.
1502
1503 // check the consistency between the other counter and this and get the correspondences between rubric IDs.
1504 Int_t* otherDims = CheckConsistency(counter);
1505 if (!otherDims) return;
1506
5d8c0c8a 1507 // switch to long counters if the given counter collection is of that type
1508 if (counter->fLongCounters && !fLongCounters) {
1509 ConvertToTHnSparseL(fCounters);
1510 fLongCounters = kTRUE;
1511 }
1512
94ef1a28 1513 Int_t nRubrics = fCounters->GetNdimensions();
1514 Int_t* thisBins = new Int_t[nRubrics];
1515 Int_t* otherBins = new Int_t[nRubrics];
1516
1517 // loop over every filled bins inside the other counter
1518 for (Long64_t i = 0; i < counter->fCounters->GetNbins(); i++) {
1519
1520 // get the content of the bin
1521 Double_t value = counter->fCounters->GetBinContent(i, otherBins);
1522
1523 // convert "other" bin coordinates to "this" bin coordinates
1524 Bool_t ok = kTRUE;
1525 for (Int_t dim = 0; dim < nRubrics; dim++) {
1526 TString label = counter->fCounters->GetAxis(otherDims[dim])->GetBinLabel(otherBins[otherDims[dim]]);
1527 thisBins[dim] = FindBin(dim, label, kTRUE);
1528 if (thisBins[dim] < 0) {
1529 AliError("this counter is full, unable to add that key word");
1530 ok = kFALSE;
1531 break;
1532 }
1533 }
1534 if (!ok) continue;
1535
5d8c0c8a 1536 if (fWeightedCounters || fLongCounters) {
1537
1538 // increment the corresponding local counter
1539 fCounters->AddBinContent(thisBins, value);
1540
1541 } else {
1542
1543 // switch to long counters if needed before incrementing
1544 Long64_t linBin = fCounters->GetBin(thisBins, kTRUE);
1545 Double_t currentValue = fCounters->GetBinContent(linBin);
1546 if (currentValue+value > INT_MAX) {
1547 ConvertToTHnSparseL(fCounters);
1548 fLongCounters = kTRUE;
1549 fCounters->AddBinContent(thisBins, value);
1550 } else fCounters->AddBinContent(linBin, value);
1551
1552 }
1553
94ef1a28 1554 }
1555
1556 // clean memory
1557 delete[] otherDims;
1558 delete[] thisBins;
1559 delete[] otherBins;
1560}
1561
1562//-----------------------------------------------------------------------
1563Long64_t AliCounterCollection::Merge(TCollection* list)
1564{
1565 /// Merge this with a list of AliCounterCollections. All AliCounterCollections provided
1566 /// must have the same rubrics with the same list of authorized key words if any.
1567
1568 if (!list || !fCounters) return 0;
1569 if (list->IsEmpty()) return (Long64_t)fCounters->GetEntries();
1570
1571 TIter next(list);
1572 const TObject* obj = 0x0;
1573 while ((obj = next())) {
1574
1575 // check that "obj" is an object of the class AliCounterCollection
1576 const AliCounterCollection* counter = dynamic_cast<const AliCounterCollection*>(obj);
1577 if (!counter) {
ca23a51f 1578 AliFatal(Form("object named \"%s\" is a %s instead of an AliCounterCollection!", obj->GetName(), obj->ClassName()));
94ef1a28 1579 continue;
1580 }
1581
1582 // merge counter to this one
1583 Add(counter);
1584
1585 }
1586
1587 return (Long64_t)fCounters->GetEntries();
1588}
1589
1590//-----------------------------------------------------------------------
1591void AliCounterCollection::Sort(Option_t* opt, Bool_t asInt)
1592{
1593 /// Sort rubrics defined without a list of authorized key words or all rubrics if opt=="all".
1594 /// If asInt=kTRUE, key words are ordered as interger instead of alphabetically.
1595
1596 if (!fCounters) {
1597 AliError("counters are not initialized");
1598 return;
1599 }
1600
1601 Bool_t all = (!strcasecmp(opt, "all"));
1602
1603 Bool_t somethingToSort = kFALSE;
1604 Int_t nRubrics = fRubrics->GetSize();
1605 Bool_t* rubricsToSort = new Bool_t[nRubrics];
1606 memset(rubricsToSort, kFALSE, sizeof(Bool_t) * nRubrics);
1607
1608 // choose rubrics to sort
1609 TObject* rubric = 0x0;
1610 TIter nextRubric(fRubrics);
1611 while ((rubric = nextRubric())) {
1612
1613 if (all || dynamic_cast<TObjString*>(rubric)) {
1614
1615 // check if something to sort
1616 THashList* labels = fCounters->GetAxis((Int_t)rubric->GetUniqueID())->GetLabels();
1617 if (!labels || labels->GetSize() < 2) continue;
1618
1619 // select that rubric
1620 rubricsToSort[(Int_t)rubric->GetUniqueID()] = kTRUE;
1621 somethingToSort = kTRUE;
1622
1623 }
1624
1625 }
1626
1627 // sort selected rubrics if any
1628 if (somethingToSort) Sort(rubricsToSort, asInt);
1629
1630 // clean memory
1631 delete[] rubricsToSort;
1632}
1633
1634//-----------------------------------------------------------------------
1635void AliCounterCollection::SortRubric(TString rubric, Bool_t asInt)
1636{
1637 /// Sort only that rubric. If asInt=kTRUE, key words are ordered as interger instead of alphabetically.
1638
1639 if (!fCounters) {
1640 AliError("counters are not initialized");
1641 return;
1642 }
1643
1644 rubric.ToUpper();
1645
1646 // find the rubric to sort
1647 Int_t dim = FindDim(rubric);
1648 if (dim < 0) return;
1649
1650 // check if something to sort
1651 THashList* labels = fCounters->GetAxis(dim)->GetLabels();
1652 if (!labels || labels->GetSize() < 2) return;
1653
1654 // select that rubric
1655 Int_t nRubrics = fRubrics->GetSize();
1656 Bool_t* rubricsToSort = new Bool_t[nRubrics];
1657 memset(rubricsToSort, kFALSE, sizeof(Bool_t) * nRubrics);
1658 rubricsToSort[dim] = kTRUE;
1659
1660 // sort it
1661 Sort(rubricsToSort, asInt);
1662
1663 // clean memory
1664 delete[] rubricsToSort;
1665}
1666
1667//-----------------------------------------------------------------------
1668void AliCounterCollection::Sort(const Bool_t* rubricsToSort, Bool_t asInt)
1669{
1670 /// Sort labels (alphabetically or as integer) in each rubric flagged in "rubricsToSort".
1671
1672 // create a new counter
1673 THnSparse* oldCounters = fCounters;
1674 Int_t nRubrics = fRubrics->GetSize();
d810835e 1675 if (fWeightedCounters)
1676 fCounters = new THnSparseT<TArrayF>("hCounters", "hCounters", nRubrics, fRubricsSize->GetArray(), 0x0, 0x0);
5d8c0c8a 1677 else if (fLongCounters)
1678 fCounters = new THnSparseT<TArrayL>("hCounters", "hCounters", nRubrics, fRubricsSize->GetArray(), 0x0, 0x0);
d810835e 1679 else
1680 fCounters = new THnSparseT<TArrayI>("hCounters", "hCounters", nRubrics, fRubricsSize->GetArray(), 0x0, 0x0);
94ef1a28 1681 Int_t** newBins = new Int_t*[nRubrics];
ca23a51f 1682 Bool_t newBinsFilled = kTRUE;
94ef1a28 1683
1684 // define the new axes
1685 for (Int_t i=0; i<nRubrics; i++) {
1686 TAxis* oldAxis = oldCounters->GetAxis(i);
1687 TAxis* newAxis = fCounters->GetAxis(i);
1688
1689 // set the name of the new axis
1690 newAxis->SetName(oldAxis->GetName());
1691
1692 // get old labels
1693 THashList* oldLabels = oldAxis->GetLabels();
ca23a51f 1694 if (!oldLabels) {
1695 newBins[i] = 0x0;
1696 newBinsFilled = kFALSE;
1697 continue;
1698 }
94ef1a28 1699
1700 // sort them if required
1701 if (rubricsToSort[i]) {
1702 if (asInt) { oldLabels = SortAsInt(oldLabels); }
1703 else { oldLabels->Sort(); }
1704 }
1705
1706 // set labels in the new axis and save the correspondence between new and old bins
1707 newBins[i] = new Int_t[oldLabels->GetSize()+1];
1708 TObjString* label = 0x0;
1709 Int_t bin = 1;
1710 TIter nextLabel(oldLabels);
1711 while ((label = static_cast<TObjString*>(nextLabel()))) {
1712 newAxis->SetBinLabel(bin, label->String().Data());
1713 newBins[i][(Int_t)label->GetUniqueID()] = bin;
1714 bin++;
1715 }
1716
1717 // clean memory
1718 if (rubricsToSort[i] && asInt) delete oldLabels;
1719 }
1720
ca23a51f 1721 // fill the new fCounters only if all axes have label(s) defined (otherwise it is empty)
1722 if (newBinsFilled) {
1723
1724 // fill the new counters
1725 Int_t* oldCoor = new Int_t[nRubrics];
1726 Int_t* newCoor = new Int_t[nRubrics];
1727 for (Long64_t i = 0; i < oldCounters->GetNbins(); i++) {
1728 Double_t value = oldCounters->GetBinContent(i, oldCoor);
1729 for (Int_t dim = 0; dim < nRubrics; dim++) newCoor[dim] = newBins[dim][oldCoor[dim]];
1730 fCounters->AddBinContent(newCoor, value);
1731 }
1732
1733 // clean memory
1734 delete[] oldCoor;
1735 delete[] newCoor;
94ef1a28 1736 }
1737
1738 // clean memory
1739 for (Int_t i=0; i<nRubrics; i++) delete[] newBins[i];
1740 delete[] newBins;
94ef1a28 1741 delete oldCounters;
1742}
1743
1744//-----------------------------------------------------------------------
1745THashList* AliCounterCollection::SortAsInt(const THashList* labels)
1746{
1747 /// Return a list (not owner) of labels sorted assuming they are integers.
1748 /// It is the responsability of user to delete the returned list.
1749
1750 THashList* sortedLabels = new THashList(labels->GetSize());
1751 TIter nextSortedLabel(sortedLabels);
1752
1753 // loop over labels
1754 TObjString* label = 0x0;
1755 TIter nextLabel(labels);
1756 while ((label = static_cast<TObjString*>(nextLabel()))) {
1757
1758 // find where to add it
1759 TObjString* sortedLabel = 0x0;
1760 nextSortedLabel.Reset();
1761 while ((sortedLabel = static_cast<TObjString*>(nextSortedLabel())) &&
1762 (sortedLabel->String().Atoi() <= label->String().Atoi())) {}
1763
1764 // add it
1765 if (sortedLabel) sortedLabels->AddBefore(sortedLabel, label);
1766 else sortedLabels->AddLast(label);
1767 }
1768
1769 return sortedLabels;
1770}
1771
5d8c0c8a 1772//-----------------------------------------------------------------------
1773void AliCounterCollection::ConvertToTHnSparseL(THnSparse* &h)
1774{
1775 /// Convert the given THnSparse to a THnSparseL (able to handle numbers >= 2^31)
1776
1777 // create the new THnSparse
1778 Int_t nDims = h->GetNdimensions();
1779 Int_t* nBins = new Int_t[nDims];
1780 for (Int_t i=0; i<nDims; i++) nBins[i] = h->GetAxis(i)->GetNbins();
1781 THnSparse* hNew = new THnSparseT<TArrayL>("new", "new", nDims, nBins, 0x0, 0x0);
1782 delete[] nBins;
1783
1784 // transfer the axes
1785 for (Int_t i=0; i<nDims; i++) {
1786 TAxis* oldAxis = h->GetAxis(i);
1787 TAxis* newAxis = hNew->GetAxis(i);
1788
1789 // transfer the name
1790 newAxis->SetName(oldAxis->GetName());
1791
1792 // transfer labels
1793 TObjString* label = 0x0;
1794 TIter nextLabel(oldAxis->GetLabels());
1795 while ((label = static_cast<TObjString*>(nextLabel())))
1796 newAxis->SetBinLabel(label->GetUniqueID(), label->String().Data());
1797 }
1798
1799 // fill the new THnSparse
1800 Int_t* coor = new Int_t[nDims];
1801 for (Long64_t i = 0; i < h->GetNbins(); i++) {
1802 Double_t value = h->GetBinContent(i, coor);
1803 hNew->AddBinContent(coor, value);
1804 }
1805 delete[] coor;
1806
1807 // transfer the number of entries
1808 hNew->SetEntries(h->GetEntries());
1809
1810 // remove old THnSparse and transfer its name and title to the new one
1811 TString name(h->GetName());
1812 TString title(h->GetTitle());
1813 delete h;
1814 h = hNew;
1815 h->SetNameTitle(name.Data(), title.Data());
1816}
1817