1 /**************************************************************************
2 * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
16 //-----------------------------------------------------------------------------
17 /// \class AliCounterCollection
19 /// generic class to handle a collection of counters
21 /// \author Philippe Pillot
22 //-----------------------------------------------------------------------------
24 #include "AliCounterCollection.h"
29 #include <TObjString.h>
30 #include <TObjArray.h>
31 #include <THnSparse.h>
32 #include <THashList.h>
36 #include <TCollection.h>
38 ClassImp(AliCounterCollection)
40 //-----------------------------------------------------------------------
41 AliCounterCollection::AliCounterCollection(const char* name) :
43 fRubrics(new THashList(10)),
44 fRubricsSize(new TArrayI(10)),
51 //-----------------------------------------------------------------------
52 AliCounterCollection::~AliCounterCollection()
60 //-----------------------------------------------------------------------
61 void AliCounterCollection::Clear(Option_t*)
65 fRubricsSize->Reset();
66 delete fCounters; fCounters = 0x0;
69 //-----------------------------------------------------------------------
70 void AliCounterCollection::AddRubric(TString name, TString listOfKeyWords)
72 /// Add a new rubric with the complete list of related key words separated by "/".
73 /// If the key word "any" is not defined, the overall statistics is
74 /// assumed to be the sum of the statistics under each key word.
77 listOfKeyWords.ToUpper();
79 if (fRubrics->Contains(name.Data())) {
80 AliError(Form("rubric named %s already exist",name.Data()));
84 // add the list of autorized key words
85 TObjArray* rubric = listOfKeyWords.Tokenize("/");
86 CleanListOfStrings(rubric);
87 rubric->SetName(name.Data());
88 Int_t nRubrics = fRubrics->GetSize();
89 rubric->SetUniqueID(nRubrics);
90 fRubrics->AddLast(rubric);
92 // save the number of autorized key words (expand the array if needed)
93 if (nRubrics+1 > fRubricsSize->GetSize()) fRubricsSize->Set(2*fRubricsSize->GetSize());
94 (*fRubricsSize)[nRubrics] = rubric->GetEntriesFast();
97 //-----------------------------------------------------------------------
98 void AliCounterCollection::AddRubric(TString name, Int_t maxNKeyWords)
100 /// Add a new rubric containing at maximum maxNKeyWords key words.
101 /// Key words will be added as the counters get filled until the maximum is reached.
102 /// If the key word "any" is never defined, the overall statistics is
103 /// assumed to be the sum of the statistics under each key word.
107 if (fRubrics->Contains(name.Data())) {
108 AliError(Form("rubric named %s already exist",name.Data()));
112 // create the empty rubric
113 TObjString* rubric = new TObjString(name.Data());
114 Int_t nRubrics = fRubrics->GetSize();
115 rubric->SetUniqueID(nRubrics);
116 fRubrics->AddLast(rubric);
118 // save the maximum number of autorized key words
119 if (nRubrics+1 > fRubricsSize->GetSize()) fRubricsSize->Set(2*fRubricsSize->GetSize());
120 (*fRubricsSize)[nRubrics] = maxNKeyWords;
123 //-----------------------------------------------------------------------
124 void AliCounterCollection::Init()
126 /// Initialize the internal counters from the added rubrics.
128 // create the counters
130 fCounters = new THnSparseT<TArrayI>("hCounters", "hCounters", fRubrics->GetSize(), fRubricsSize->GetArray(), 0x0, 0x0);
133 TObject* rubric = 0x0;
134 TIter nextRubric(fRubrics);
135 while ((rubric = nextRubric())) {
136 TAxis* axis = fCounters->GetAxis((Int_t)rubric->GetUniqueID());
139 axis->SetName(rubric->GetName());
141 // set labels if already known
142 TObjArray* keyWords = dynamic_cast<TObjArray*>(rubric);
144 TObjString* label = 0x0;
146 TIter nextLabel(keyWords);
147 while ((label = static_cast<TObjString*>(nextLabel()))) axis->SetBinLabel(bin++, label->String().Data());
154 //-----------------------------------------------------------------------
155 Int_t AliCounterCollection::GetNActiveBins(Int_t dim)
157 /// return the number of labels in that rubric.
158 THashList* labels = fCounters->GetAxis(dim)->GetLabels();
159 return (labels) ? labels->GetSize() : 0;
162 //-----------------------------------------------------------------------
163 Bool_t AliCounterCollection::ContainsAny(Int_t dim)
165 /// return kTRUE if that rubric contains the keyWord "ANY".
166 THashList* labels = fCounters->GetAxis(dim)->GetLabels();
167 return (labels && labels->Contains("ANY"));
170 //-----------------------------------------------------------------------
171 const Int_t* AliCounterCollection::FindBins(const TString& externalKey, Bool_t allocate, Int_t& nEmptySlots)
173 /// Return the corresponding bins ordered by rubric or 0x0 if externalKey is not valid.
174 /// The externalKey format must be rubric:keyWord/rubric:keyWord/rubric:keyWord/...
175 /// If allocate = kTRUE, new key words are added to the corresponding rubric if possible.
176 /// If a rubric is not filled in, the coresponding slot contain -1 in the array.
177 /// It is the responsability of the user to delete the returned array.
179 // produce an empty array of keys
180 Int_t nRubrics = fRubrics->GetSize();
181 Int_t* bins = new Int_t[nRubrics];
182 for (Int_t i=0; i<nRubrics; i++) bins[i] = -1;
183 nEmptySlots = nRubrics;
184 Bool_t isValid = kTRUE;
186 // get the list of rubric:keyWord pairs
187 TObjArray* rubricKeyPairs = externalKey.Tokenize("/");
189 // loop over each rubric:keyWord pair
190 TObjString* pair = 0x0;
191 TIter next(rubricKeyPairs);
192 while ((pair = static_cast<TObjString*>(next()))) {
194 // get both rubric and associated key word
195 TObjArray* rubricKeyPair = pair->String().Tokenize(":");
197 // check the format of the pair
198 if (rubricKeyPair->GetEntriesFast() != 2) {
199 AliError("invalid key format");
201 delete rubricKeyPair;
205 // get the axis corresponding to that rubric
206 Int_t dim = FindDim(static_cast<TObjString*>(rubricKeyPair->UncheckedAt(0))->String());
209 delete rubricKeyPair;
213 // find the bin corresponding to that key word
214 Int_t bin = FindBin(dim, static_cast<TObjString*>(rubricKeyPair->UncheckedAt(1))->String(), allocate);
217 delete rubricKeyPair;
221 // check if the array of keys already contains something for that rubric
222 if (bins[dim] >= 0) {
223 AliWarning("key already given for that rubric --> ignored");
224 delete rubricKeyPair;
228 // store the corresponding bin for that slot
233 delete rubricKeyPair;
236 // delete the array in case of problem
240 nEmptySlots = nRubrics;
244 delete rubricKeyPairs;
249 //-----------------------------------------------------------------------
250 Int_t AliCounterCollection::FindDim(const TString& rubricName) const
252 /// Return the dimension corresponding to that rubric (or -1 in case of failure).
253 TObject* rubric = fRubrics->FindObject(rubricName.Data());
255 AliError(Form("invalid rubric: %s",rubricName.Data()));
258 return (Int_t) rubric->GetUniqueID();
261 //-----------------------------------------------------------------------
262 Int_t AliCounterCollection::FindBin(Int_t dim, const TString& keyWord, Bool_t allocate)
264 /// Return the bin number corresponding to that key word (or -1 in case of failure).
265 /// If allocate = kTRUE, try to add the key word if possible.
267 TAxis* axis = fCounters->GetAxis(dim);
269 // look for the bin corresponding to keyWord
270 THashList* labels = axis->GetLabels();
271 TObjString* label = (labels) ? static_cast<TObjString*>(labels->FindObject(keyWord.Data())) : 0x0;
272 Int_t bin = (label) ? (Int_t)label->GetUniqueID() : -1;
274 // in case the keyWord does not exist, try to add it if required
275 if (bin<0 && allocate) {
276 Int_t nLabels = (labels) ? labels->GetSize() : 0;
277 if (nLabels < axis->GetNbins()) {
279 axis->SetBinLabel(bin, keyWord.Data());
283 if (bin<0) AliError(Form("invalid key word: %s:%s",axis->GetName(),keyWord.Data()));
288 //-----------------------------------------------------------------------
289 Short_t** AliCounterCollection::DecodeSelection(const TString& selections, const TObjArray& displayedRubrics)
291 /// Tag the selected keywords in each rubric (-1=subtract; 0=discard; 1=add). Format:
292 /// "rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.." (order does not matter).
293 /// It is the responsability of the user to delete the returned array.
295 // produce an empty array of selected keys
296 Int_t nRubrics = fCounters->GetNdimensions();
297 Short_t** selects = new Short_t*[nRubrics];
298 for (Int_t i=0; i<nRubrics; i++) selects[i] = 0x0;
300 // get the list of rubric:LisOfKeyWord pairs
301 TObjArray* rubricKeyPairs = selections.Tokenize("/");
303 // loop over each rubric:keyWord pair
304 TObjString* pair = 0x0;
305 TIter next(rubricKeyPairs);
306 while ((pair = static_cast<TObjString*>(next()))) {
308 // get both rubric and associated list of key words
309 TObjArray* rubricKeyPair = pair->String().Tokenize(":");
311 // check the format of the pair
312 if (rubricKeyPair->GetEntriesFast() != 2) {
313 AliError("invalid key format");
314 delete rubricKeyPair;
315 delete rubricKeyPairs;
316 for (Int_t i=0; i<nRubrics; i++) if (selects[i]) delete[] selects[i];
321 // check wether to select or to discard the keyWords
322 Int_t include = kTRUE;
323 TString ListOfKeyWords(static_cast<TObjString*>(rubricKeyPair->UncheckedAt(1))->String());
324 if (ListOfKeyWords.BeginsWith("ANY-")) {
325 ListOfKeyWords.Remove(0,4);
329 // select the key words
330 const TString& rubric = static_cast<TObjString*>(rubricKeyPair->UncheckedAt(0))->String();
331 if (!Select(include, rubric, ListOfKeyWords, displayedRubrics.Contains(rubric.Data()), selects)) {
332 delete rubricKeyPair;
333 delete rubricKeyPairs;
334 for (Int_t i=0; i<nRubrics; i++) if (selects[i]) delete[] selects[i];
340 delete rubricKeyPair;
344 delete rubricKeyPairs;
346 // complete the selection of other rubrics
347 for (Int_t i=0; i<nRubrics; i++) {
349 // skip already processed rubrics
350 if (selects[i]) continue;
352 // create the list of bins
353 Int_t nBins = GetNActiveBins(i) + 1;
354 selects[i] = new Short_t[nBins];
356 // select all key words or only the key work "ANY"
357 if (ContainsAny(i) && !displayedRubrics.Contains(fCounters->GetAxis(i)->GetName())) {
358 memset(selects[i], 0, sizeof(Short_t) * nBins);
359 selects[i][FindBin(i, "ANY", kFALSE)] = 1;
360 } else for (Int_t j=0; j<nBins; j++) selects[i][j] = 1;
367 //-----------------------------------------------------------------------
368 Bool_t AliCounterCollection::Select(Bool_t include, const TString& rubric, const TString& keywords,
369 Bool_t displayed, Short_t* selectBins[])
371 /// Tag the selected keywords (separated by ',') in that rubric (-1=subtract; 0=discard; 1=add).
373 Int_t dim = FindDim(rubric);
374 if (dim < 0) return kFALSE;
376 if (selectBins[dim]) {
377 AliWarning(Form("selection already made for rubric %s --> ignored",rubric.Data()));
381 // get list of key words to select
382 TObjArray* keys = keywords.Tokenize(",");
383 if (keys->GetEntriesFast() == 0) {
384 AliError(Form("no key word specified for rubric %s",rubric.Data()));
389 // create the list of bins
390 Int_t nBins = GetNActiveBins(dim) + 1;
391 selectBins[dim] = new Short_t[nBins];
393 // select/unselect all bins
394 Bool_t containsAny = ContainsAny(dim);
395 if (include || (containsAny && !displayed)) {
396 memset(selectBins[dim], 0, sizeof(Short_t) * nBins);
397 if (!include) selectBins[dim][FindBin(dim, "ANY", kFALSE)] = 1;
398 } else for (Int_t j=0; j<nBins; j++) selectBins[dim][j] = 1;
400 // select/unselect specific key words
401 TObjString* key = 0x0;
403 while ((key = static_cast<TObjString*>(nextKey()))) {
405 // special case of key word "ANY"
406 if (key->String() == "ANY") {
410 Int_t binAny = FindBin(dim, "ANY", kFALSE);
411 if (include) selectBins[dim][binAny] = 1;
412 else selectBins[dim][binAny] = 0;
416 if (include) for (Int_t j=0; j<nBins; j++) selectBins[dim][j] = 1;
417 else memset(selectBins[dim], 0, sizeof(Short_t) * nBins);
421 } else { // other cases
423 // find the corresponding bin
424 Int_t bin = FindBin(dim, key->String().Data(), kFALSE);
430 // select/unselect it
431 if (include) selectBins[dim][bin] = 1;
432 else if (containsAny && !displayed) selectBins[dim][bin] = -1;
433 else selectBins[dim][bin] = 0;
445 //-----------------------------------------------------------------------
446 void AliCounterCollection::CleanListOfStrings(TObjArray* list)
448 /// Make sure all strings appear only once in this list
450 // remove multiple-occurrence
451 Int_t nEntries = list->GetEntriesFast();
452 for (Int_t i = 0; i < nEntries; i++) {
453 TObjString* entry1 = static_cast<TObjString*>(list->UncheckedAt(i));
454 if (!entry1) continue;
455 for (Int_t j = i+1; j < nEntries; j++) {
456 TObjString* entry2 = static_cast<TObjString*>(list->UncheckedAt(j));
457 if (entry2 && entry2->IsEqual(entry1)) {
458 AliWarning(Form("multiple-occurence of string \"%s\" --> removed",entry2->String().Data()));
464 // remove empty slots
468 //-----------------------------------------------------------------------
469 void AliCounterCollection::Count(TString externalKey, Int_t value)
471 /// Add "value" to the counter referenced by "externalKey".
472 /// The externalKey format must be rubric:keyWord/rubric:keyWord/rubric:keyWord/...
474 if (value < 1) return;
476 AliError("counters are not initialized");
480 externalKey.ToUpper();
482 // convert external to internal key
483 Int_t nEmptySlots = 0;
484 const Int_t* bins = FindBins(externalKey, kTRUE, nEmptySlots);
487 // check for empty slots
488 if (nEmptySlots > 0) {
489 AliError("incomplete key");
494 // increment the corresponding counter
495 fCounters->AddBinContent(bins, (Double_t)value);
501 //-----------------------------------------------------------------------
502 void AliCounterCollection::Print(const Option_t* opt) const
504 /// Print every individual counters if opt=="", else call "Print(TString rubrics=opt, TString selections="")".
506 if (strcmp(opt,"")) {
507 const_cast<AliCounterCollection*>(this)->Print(opt, "");
512 AliError("counters are not initialized");
516 if (fCounters->GetNbins() == 0) {
517 printf("\nall counters are empty\n\n");
521 Int_t nRubrics = fCounters->GetNdimensions();
522 Int_t* bins = new Int_t[nRubrics];
524 // loop over every filled counters
525 for (Long64_t i=0; i<fCounters->GetNbins(); ++i) {
527 // get the content of the bin
528 Int_t value = (Int_t) fCounters->GetBinContent(i, bins);
530 // build the corresponding counter name
532 for (Int_t j=0; j<nRubrics; j++) counter += Form("/%s",fCounters->GetAxis(j)->GetBinLabel(bins[j]));
536 printf("\n%s %d", counter.Data(), value);
544 //-----------------------------------------------------------------------
545 void AliCounterCollection::PrintKeyWords() const
547 /// Print the full list of key words.
550 AliError("counters are not initialized");
555 Int_t nRubrics = fCounters->GetNdimensions();
556 for (Int_t iDim=0; iDim<nRubrics; iDim++) {
557 TAxis* axis = fCounters->GetAxis(iDim);
559 // print rubric's name
560 printf("\n%s:", axis->GetName());
562 // loop over key words
563 Bool_t first = kTRUE;
564 TObjString* label = 0x0;
565 TIter nextLabel(axis->GetLabels());
566 while ((label = static_cast<TObjString*>(nextLabel()))) {
568 //print key word's name
570 printf("%s", label->String().Data());
572 } else printf(",%s", label->String().Data());
579 //-----------------------------------------------------------------------
580 void AliCounterCollection::PrintValue(TString selections)
582 /// Print value of selected counter.
583 /// format of "selections" is rubric:keyWord/rubric:keyWord/rubric:keyWord/...
586 AliError("counters are not initialized");
590 selections.ToUpper();
592 // convert external to internal key
593 Int_t nEmptySlots = 0;
594 const Int_t* selectedBins = FindBins(selections, kFALSE, nEmptySlots);
595 if (!selectedBins) return;
597 // check for empty slots
598 if (nEmptySlots > 0) {
599 AliError("incomplete key");
600 delete[] selectedBins;
605 printf("\n%d\n\n", (Int_t) fCounters->GetBinContent(selectedBins));
608 delete[] selectedBins;
611 //-----------------------------------------------------------------------
612 void AliCounterCollection::Print(TString rubrics, TString selections)
614 /// Print desired rubrics for the given selection:
615 /// - format of "rubrics" is rubric1/rubric2/.. (order matters only for output).
616 /// - format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter).
617 /// If "data" contains 1 rubric, the output will be one counter for each element of that rubric.
618 /// If "data" contains 2 rubrics, the output will be an array of counters, rubric1 vs rubric2.
619 /// If "data" contains 3 rubrics, the output will be an array rubric1 vs rubric2 for each element in rubric3.
621 /// Results are integrated over rubrics not specified neither in "rubrics" nor in "selections".
624 AliError("counters are not initialized");
629 selections.ToUpper();
631 // get the rubrics to print
632 TObjArray* rubricsToPrint = rubrics.Tokenize("/");
633 if (rubricsToPrint->GetEntriesFast() == 0) {
634 delete rubricsToPrint;
638 // remove rubrics called twice
639 CleanListOfStrings(rubricsToPrint);
641 // project counters in the rubrics to print according to the selections
642 TObject* hist = Projection(*rubricsToPrint, selections);
644 delete rubricsToPrint;
649 Int_t nRubricsToPrint = rubricsToPrint->GetEntriesFast();
650 if (nRubricsToPrint == 1 && (static_cast<TH1D*>(hist))->GetEntries() > 0)
651 PrintList(static_cast<TH1D*>(hist));
652 else if (nRubricsToPrint == 2 && (static_cast<TH2D*>(hist))->GetEntries() > 0)
653 PrintArray(static_cast<TH2D*>(hist));
654 else if (nRubricsToPrint > 2 && (static_cast<THnSparse*>(hist))->GetEntries() > 0)
655 PrintListOfArrays(static_cast<THnSparse*>(hist));
657 printf("\nselected counters are empty\n\n");
660 delete rubricsToPrint;
664 //-----------------------------------------------------------------------
665 void AliCounterCollection::PrintSum(TString selections)
667 /// Print the overall statistics for the given selection (result is integrated over not specified rubrics):
668 /// - format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter).
671 AliError("counters are not initialized");
675 selections.ToUpper();
677 // decode the selections
678 Short_t** select = DecodeSelection(selections, TObjArray());
681 // loop over every filled counters and compute integral
683 Int_t nDims = fCounters->GetNdimensions();
684 Int_t* coord = new Int_t[nDims];
685 for (Long64_t i=0; i<fCounters->GetNbins(); ++i) {
687 // get the content of the counter
688 Double_t value = fCounters->GetBinContent(i, coord);
690 // discard not selected counters and compute the selection factor
691 Int_t selectionFactor = 1;
692 for (Int_t dim = 0; dim < nDims && selectionFactor != 0; dim++) selectionFactor *= select[dim][coord[dim]];
693 if (selectionFactor == 0) continue;
696 sum += selectionFactor * ((Int_t) value);
700 for (Int_t iDim=0; iDim<nDims; iDim++) delete[] select[iDim];
705 printf("\n%d\n\n", sum);
708 //-----------------------------------------------------------------------
709 void AliCounterCollection::PrintList(const TH1D* hist) const
711 /// Print the content of 1D histogram as a list.
713 // set the format to print labels
714 THashList* labels = hist->GetXaxis()->GetLabels();
715 TString format(Form("\n%%%ds %%9d",GetMaxLabelSize(labels)));
717 // print value for each label
718 TObjString* label = 0x0;
719 TIter nextLabel(labels);
720 while ((label = static_cast<TObjString*>(nextLabel()))) {
721 Int_t bin = (Int_t) label->GetUniqueID();
722 printf(format.Data(), label->String().Data(), (Int_t) hist->GetBinContent(bin));
727 //-----------------------------------------------------------------------
728 void AliCounterCollection::PrintArray(const TH2D* hist) const
730 /// Print the content of 2D histogram as an array.
732 // set the format to print labels in X direction
733 THashList* labelsX = hist->GetXaxis()->GetLabels();
734 TString formatX(Form("\n%%%ds ",GetMaxLabelSize(labelsX)));
736 // set the format to print labels in Y direction and values
737 THashList* labelsY = hist->GetYaxis()->GetLabels();
738 Int_t maxLabelSizeY = TMath::Max(9, GetMaxLabelSize(labelsY));
739 TString formatYs(Form("%%%ds ",maxLabelSizeY));
740 TString formatYd(Form("%%%dd ",maxLabelSizeY));
742 // print labels in Y axis
743 printf(formatX.Data()," ");
744 TObjString* labelY = 0x0;
745 TIter nextLabelY(labelsY);
746 while ((labelY = static_cast<TObjString*>(nextLabelY())))
747 printf(formatYs.Data(), labelY->String().Data());
749 // fill array for each label in X axis
750 TObjString* labelX = 0x0;
751 TIter nextLabelX(labelsX);
752 while ((labelX = static_cast<TObjString*>(nextLabelX()))) {
753 Int_t binX = (Int_t) labelX->GetUniqueID();
756 printf(formatX.Data(), labelX->String().Data());
758 // print value for each label in Y axis
760 while ((labelY = static_cast<TObjString*>(nextLabelY()))) {
761 Int_t binY = (Int_t) labelY->GetUniqueID();
762 printf(formatYd.Data(), (Int_t) hist->GetBinContent(binX, binY));
768 //-----------------------------------------------------------------------
769 void AliCounterCollection::PrintListOfArrays(const THnSparse* hist) const
771 /// Print the content of nD histogram as a list of arrays.
773 // set the format to print labels in X direction
774 THashList* labelsX = hist->GetAxis(0)->GetLabels();
775 TString formatX(Form("\n%%%ds ",GetMaxLabelSize(labelsX)));
777 // set the format to print labels in Y direction and values
778 THashList* labelsY = hist->GetAxis(1)->GetLabels();
779 Int_t maxLabelSizeY = TMath::Max(9, GetMaxLabelSize(labelsY));
780 TString formatYs(Form("%%%ds ",maxLabelSizeY));
781 TString formatYd(Form("%%%dd ",maxLabelSizeY));
783 // create a list containing each combination of labels refering the arrays to be printout
785 listOfCombis.SetOwner();
787 // add a first empty combination
788 Int_t nDim = hist->GetNdimensions();
789 listOfCombis.AddLast(new TObjArray(nDim-2));
791 // loop over the nDim-2 other rubrics
792 for (Int_t i=2; i<nDim; i++) {
794 // save the last label of that rubic
795 THashList* labels = hist->GetAxis(i)->GetLabels();
796 TObjString* lastLabel = (labels) ? static_cast<TObjString*>(labels->Last()) : 0x0;
797 if (!lastLabel) return;
799 // prepare iteration over the list of labels
800 TIter nextLabel(labels);
802 // loop over existing combinations
803 TObjLink* lnk = listOfCombis.FirstLink();
806 // get the current combination
807 TObjArray* currentCombi = static_cast<TObjArray*>(lnk->GetObject());
809 // loop over labels in the current rubric
811 TObjString* label = 0x0;
812 while ((label = static_cast<TObjString*>(nextLabel()))) {
814 // stop at the last one
815 if (label == lastLabel) break;
817 // copy the current combination, add the current label to it and add it to the list of combinations
818 TObjArray* combi = new TObjArray(*currentCombi);
819 combi->AddLast(label);
820 listOfCombis.AddBefore(lnk, combi);
823 // add the last label to the current combination
824 currentCombi->AddLast(lastLabel);
831 // create bin coordinates to access individual counters
832 Int_t* bins = new Int_t[nDim];
834 // loop over each combination of labels
835 TObjArray* combi = 0x0;
836 TIter nextCombi(&listOfCombis);
837 while ((combi = static_cast<TObjArray*>(nextCombi()))) {
839 // make the name of the combination and fill the corresponding bin coordinates
840 TString combiName = "/";
841 for (Int_t i=2; i<nDim; i++) {
842 TObjString* label = static_cast<TObjString*>(combi->UncheckedAt(i-2));
843 combiName += Form("%s/",label->String().Data());
844 bins[i] = (Int_t)label->GetUniqueID();
848 Bool_t empty = kTRUE;
849 TObjString* labelX = 0x0;
850 TObjString* labelY = 0x0;
851 TIter nextLabelX(labelsX);
852 TIter nextLabelY(labelsY);
853 while ((labelX = static_cast<TObjString*>(nextLabelX()))) {
854 bins[0] = (Int_t) labelX->GetUniqueID();
856 while ((labelY = static_cast<TObjString*>(nextLabelY()))) {
857 bins[1] = (Int_t) labelY->GetUniqueID();
858 if (((Int_t) hist->GetBinContent(bins)) > 0) {
867 // print the name of the combination of labels refering the incoming array
868 printf("\n%s:\n",combiName.Data());
870 // print labels in Y axis
871 printf(formatX.Data()," ");
873 while ((labelY = static_cast<TObjString*>(nextLabelY())))
874 printf(formatYs.Data(), labelY->String().Data());
876 // fill array for each label in X axis
878 while ((labelX = static_cast<TObjString*>(nextLabelX()))) {
879 bins[0] = (Int_t) labelX->GetUniqueID();
882 printf(formatX.Data(), labelX->String().Data());
884 // print value for each label in Y axis
886 while ((labelY = static_cast<TObjString*>(nextLabelY()))) {
887 bins[1] = (Int_t) labelY->GetUniqueID();
888 printf(formatYd.Data(), (Int_t) hist->GetBinContent(bins));
898 //-----------------------------------------------------------------------
899 Int_t AliCounterCollection::GetMaxLabelSize(THashList* labels) const
901 /// Return the number of characters of the longest label.
902 Int_t maxLabelSize = 0;
903 TObjString* label = 0x0;
904 TIter nextLabel(labels);
905 while ((label = static_cast<TObjString*>(nextLabel())))
906 maxLabelSize = TMath::Max(maxLabelSize, label->String().Length());
910 //-----------------------------------------------------------------------
911 TH1D* AliCounterCollection::Draw(TString rubric, TString selections)
913 /// Draw counters of the rubric "rubric" for the given "selection".
914 /// Format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter).
915 /// Results are integrated over rubrics not specified neither in "rubric1" nor in "selections".
916 /// It is the responsability of the user to delete the returned histogram.
919 AliError("counters are not initialized");
924 selections.ToUpper();
926 // fill the rubrics to print
927 TObjArray rubricsToPrint(1);
928 rubricsToPrint.SetOwner();
929 rubricsToPrint.AddLast(new TObjString(rubric.Data()));
931 // project counters in the rubrics to print according to the selections
932 TH1D* hist = static_cast<TH1D*>(Projection(rubricsToPrint, selections));
939 hist->SetStats(kFALSE);
942 TAxis* axis = hist->GetXaxis();
943 THashList* labels = axis->GetLabels();
944 Int_t nLabels = (labels) ? labels->GetSize() : 1;
945 axis->SetRange(1,nLabels);
946 axis->SetNdivisions(1,kFALSE);
947 axis->SetTitle(rubric.Data());
950 hist->GetYaxis()->SetTitle("Counts");
956 //-----------------------------------------------------------------------
957 TH2D* AliCounterCollection::Draw(TString rubric1, TString rubric2, TString selections)
959 /// Draw counters of the "rubric1" vs "rubric2" for the given "selection".
960 /// Format of "selections" is rubric:[any-]keyWord,keyWord,../rubric:[any-]keyWord,.. (order does not matter).
961 /// Results are integrated over rubrics not specified neither in "rubric1", "rubric2" nor in "selections".
962 /// It is the responsability of the user to delete the returned histogram.
965 AliError("counters are not initialized");
971 selections.ToUpper();
973 // fill the rubrics to print
974 TObjArray rubricsToPrint(2);
975 rubricsToPrint.SetOwner();
976 rubricsToPrint.AddLast(new TObjString(rubric2.Data()));
977 rubricsToPrint.AddLast(new TObjString(rubric1.Data()));
979 // project counters in the rubrics to print according to the selections
980 TH2D* hist = static_cast<TH2D*>(Projection(rubricsToPrint, selections));
987 hist->SetStats(kFALSE);
990 TAxis* axisX = hist->GetXaxis();
991 THashList* labelsX = axisX->GetLabels();
992 Int_t nLabelsX = (labelsX) ? labelsX->GetSize() : 1;
993 axisX->SetRange(1,nLabelsX);
994 axisX->SetNdivisions(1,kFALSE);
995 axisX->SetTitle(rubric2.Data());
998 TAxis* axisY = hist->GetYaxis();
999 THashList* labelsY = axisY->GetLabels();
1000 Int_t nLabelsY = (labelsY) ? labelsY->GetSize() : 1;
1001 axisY->SetRange(1,nLabelsY);
1002 axisY->SetNdivisions(1,kFALSE);
1003 axisY->SetTitle(rubric1.Data());
1009 //-----------------------------------------------------------------------
1010 TObject* AliCounterCollection::Projection(const TObjArray& data, const TString& selections)
1012 /// Return desired "data" for the given "selection" stored in a new histogram or 0x0 in case of failure.
1013 /// The type of the histogram (TH1D, TH2D or THnSparse) depend on the number of data.
1014 /// It is the responsability of the user to delete the returned histogram.
1016 // decode the selections
1017 Short_t** select = DecodeSelection(selections, data);
1018 if (!select) return 0x0;
1020 // define name and dimensions of projection histo
1021 TString name(fCounters->GetName());
1022 Int_t nDims = fCounters->GetNdimensions();
1023 Int_t nTargetDims = data.GetEntriesFast();
1024 TArrayI targetDims(nTargetDims);
1025 TArrayI nNewBins(nTargetDims);
1026 TArrayI* OldToNewCoord = new TArrayI[nTargetDims];
1027 for (Int_t i=0; i<nTargetDims; i++) {
1030 name += Form("_%s",static_cast<TObjString*>(data.UncheckedAt(i))->String().Data());
1033 targetDims[i] = FindDim(static_cast<TObjString*>(data.UncheckedAt(i))->String());
1035 // set number of selected bins in the target dims and make the correspondence between old and new coordinates
1037 if (targetDims[i] > -1) {
1038 Int_t nBins = GetNActiveBins(targetDims[i]) + 1;
1039 OldToNewCoord[i].Set(nBins);
1040 for (Int_t j=1; j<nBins; j++) if (select[targetDims[i]][j] > 0) OldToNewCoord[i][j] = ++nNewBins[i];
1043 // clean memory and return 0x0 in case of problem
1044 if (nNewBins[i] == 0) {
1045 for (Int_t iDim=0; iDim<nDims; iDim++) delete[] select[iDim];
1047 delete[] OldToNewCoord;
1053 // define title of projection histo
1054 TString title = "Selections: ";
1055 TString selectionString(selections);
1056 selectionString.Remove(TString::kBoth, '/');
1057 if (selectionString.Length() > 0) title += Form("%s/", selectionString.Data());
1059 TIter nextRubric(fRubrics);
1060 while ((rub = nextRubric())) {
1061 if (selectionString.Contains(Form("%s:",rub->GetName()))) continue;
1062 if (data.Contains(rub->GetName())) continue;
1063 title += Form("%s:ANY/", rub->GetName());
1065 title.ReplaceAll("/", " ");
1067 // Create new histograms
1069 if (nTargetDims == 1) hist = new TH1D(name.Data(), title.Data(), nNewBins[0], 0., 1.);
1070 else if (nTargetDims == 2) hist = new TH2D(name.Data(), title.Data(), nNewBins[0], 0., 1., nNewBins[1], 0., 1.);
1071 else hist = new THnSparseT<TArrayI>(name.Data(), title.Data(), nTargetDims, nNewBins.GetArray(), 0x0, 0x0);
1073 // Set new axis labels
1075 if (nTargetDims < 3) {
1078 TIter nextLabelX(fCounters->GetAxis(targetDims[0])->GetLabels());
1079 while ((label = static_cast<TObjString*>(nextLabelX()))) {
1080 if (select[targetDims[0]][label->GetUniqueID()] > 0) {
1081 static_cast<TH1*>(hist)->GetXaxis()->SetBinLabel(OldToNewCoord[0][label->GetUniqueID()], label->String().Data());
1086 if (nTargetDims == 2) {
1087 TIter nextLabelY(fCounters->GetAxis(targetDims[1])->GetLabels());
1088 while ((label = static_cast<TObjString*>(nextLabelY()))) {
1089 if (select[targetDims[1]][label->GetUniqueID()] > 0) {
1090 static_cast<TH1*>(hist)->GetYaxis()->SetBinLabel(OldToNewCoord[1][label->GetUniqueID()], label->String().Data());
1098 for (Int_t i=0; i<nTargetDims; i++) {
1099 TIter nextLabel(fCounters->GetAxis(targetDims[i])->GetLabels());
1100 while ((label = static_cast<TObjString*>(nextLabel()))) {
1101 if (select[targetDims[i]][label->GetUniqueID()] > 0) {
1102 static_cast<THnSparse*>(hist)->GetAxis(i)->SetBinLabel(OldToNewCoord[i][label->GetUniqueID()], label->String().Data());
1109 // loop over every filled counters
1110 Int_t* coord = new Int_t[nDims];
1111 Int_t* newCoord = new Int_t[nTargetDims];
1113 for (Long64_t i=0; i<fCounters->GetNbins(); ++i) {
1115 // get the content of the counter
1116 Double_t value = fCounters->GetBinContent(i, coord);
1118 // discard not selected counters and compute the selection factor
1119 Int_t selectionFactor = 1;
1120 for (Int_t dim = 0; dim < nDims && selectionFactor != 0; dim++) selectionFactor *= select[dim][coord[dim]];
1121 if (selectionFactor == 0) continue;
1123 // find new coordinates in the projection histo
1124 for (Int_t d = 0; d < nTargetDims; ++d) newCoord[d] = OldToNewCoord[d][coord[targetDims[d]]];
1126 // fill projection histo
1127 if (nTargetDims < 3) {
1128 Int_t linBin = (nTargetDims == 1) ? newCoord[0] : static_cast<TH1*>(hist)->GetBin(newCoord[0], newCoord[1]);
1129 static_cast<TH1*>(hist)->AddBinContent(linBin, selectionFactor*value);
1130 } else static_cast<THnSparse*>(hist)->AddBinContent(newCoord, selectionFactor*value);
1135 // update the number of entries
1136 if (nTargetDims < 3) static_cast<TH1*>(hist)->SetEntries(nEntries);
1137 else static_cast<THnSparse*>(hist)->SetEntries(nEntries);
1140 for (Int_t iDim=0; iDim<nDims; iDim++) delete[] select[iDim];
1144 delete[] OldToNewCoord;
1149 //-----------------------------------------------------------------------
1150 Int_t* AliCounterCollection::CheckConsistency(const AliCounterCollection* c)
1152 /// Consistency check of the two counter collections. To be consistent, both counters
1153 /// must have the same rubrics with the same list of authorized key words if any.
1154 /// Return the correspondence between the local rubric ordering and the one of the other counter,
1155 /// or 0x0 in case of problem. It is the responsability of the user to delete the returned array.
1157 if (!fCounters || !c->fCounters) {
1158 AliError("counters are not initialized");
1162 // check if the number of rubrics is the same
1163 Int_t nRubrics = fRubrics->GetSize();
1164 if (c->fRubrics->GetSize() != nRubrics) {
1165 AliError("both counters do not contain the same number of rubrics");
1169 Int_t* otherDims = new Int_t[nRubrics];
1171 // loop over local rubrics
1172 TObject* rubric1 = 0x0;
1173 TIter nextRubric(fRubrics);
1174 while ((rubric1 = nextRubric())) {
1176 // find that rubric in the other counter
1177 TObject* rubric2 = c->fRubrics->FindObject(rubric1->GetName());
1179 AliError(Form("the other counter does not contain the rubric %s", rubric1->GetName()));
1184 // check the list of authorized key words if any
1185 TObjArray* keyWords1 = dynamic_cast<TObjArray*>(rubric1);
1186 TObjArray* keyWords2 = dynamic_cast<TObjArray*>(rubric2);
1187 if (keyWords1 && keyWords2) {
1189 // check if the number of key words is the same
1190 if (keyWords1->GetEntriesFast() != keyWords2->GetEntriesFast()) {
1191 AliError("that rubric does not contain the same number of authorized key words in both counters");
1196 // loop over local key words
1197 TObjString* keyWord = 0x0;
1198 TIter nextKeyWord(keyWords1);
1199 while ((keyWord = static_cast<TObjString*>(nextKeyWord()))) {
1201 // find that key word in the corresponding rubric of the other counter
1202 if (!keyWords2->FindObject(keyWord->String().Data())) {
1203 AliError(Form("rubric %s does not contain the key word %s in the other counter", rubric1->GetName(), keyWord->String().Data()));
1210 } else if (keyWords1 || keyWords2) {
1212 // that rubric has not been initialized the same way in both counter
1214 AliError(Form("rubric %s of the other counter does not contain a list of authorized key words while this does", rubric1->GetName()));
1216 AliError(Form("rubric %s of this counter does not contain a list of authorized key words while the other does", rubric1->GetName()));
1223 // save the correspondence of rubric IDs in both counters
1224 otherDims[rubric1->GetUniqueID()] = rubric2->GetUniqueID();
1231 //-----------------------------------------------------------------------
1232 void AliCounterCollection::Add(const AliCounterCollection* counter)
1234 /// Add the given AliCounterCollections to this. They must have the
1235 /// same rubrics with the same list of authorized key words if any.
1237 // check the consistency between the other counter and this and get the correspondences between rubric IDs.
1238 Int_t* otherDims = CheckConsistency(counter);
1239 if (!otherDims) return;
1241 Int_t nRubrics = fCounters->GetNdimensions();
1242 Int_t* thisBins = new Int_t[nRubrics];
1243 Int_t* otherBins = new Int_t[nRubrics];
1245 // loop over every filled bins inside the other counter
1246 for (Long64_t i = 0; i < counter->fCounters->GetNbins(); i++) {
1248 // get the content of the bin
1249 Double_t value = counter->fCounters->GetBinContent(i, otherBins);
1251 // convert "other" bin coordinates to "this" bin coordinates
1253 for (Int_t dim = 0; dim < nRubrics; dim++) {
1254 TString label = counter->fCounters->GetAxis(otherDims[dim])->GetBinLabel(otherBins[otherDims[dim]]);
1255 thisBins[dim] = FindBin(dim, label, kTRUE);
1256 if (thisBins[dim] < 0) {
1257 AliError("this counter is full, unable to add that key word");
1264 // increment the corresponding local counter
1265 fCounters->AddBinContent(thisBins, value);
1274 //-----------------------------------------------------------------------
1275 Long64_t AliCounterCollection::Merge(TCollection* list)
1277 /// Merge this with a list of AliCounterCollections. All AliCounterCollections provided
1278 /// must have the same rubrics with the same list of authorized key words if any.
1280 if (!list || !fCounters) return 0;
1281 if (list->IsEmpty()) return (Long64_t)fCounters->GetEntries();
1284 const TObject* obj = 0x0;
1285 while ((obj = next())) {
1287 // check that "obj" is an object of the class AliCounterCollection
1288 const AliCounterCollection* counter = dynamic_cast<const AliCounterCollection*>(obj);
1290 AliError(Form("object named %s is not AliCounterCollection! Skipping it.", counter->GetName()));
1294 // merge counter to this one
1299 return (Long64_t)fCounters->GetEntries();
1302 //-----------------------------------------------------------------------
1303 void AliCounterCollection::Sort(Option_t* opt, Bool_t asInt)
1305 /// Sort rubrics defined without a list of authorized key words or all rubrics if opt=="all".
1306 /// If asInt=kTRUE, key words are ordered as interger instead of alphabetically.
1309 AliError("counters are not initialized");
1313 Bool_t all = (!strcasecmp(opt, "all"));
1315 Bool_t somethingToSort = kFALSE;
1316 Int_t nRubrics = fRubrics->GetSize();
1317 Bool_t* rubricsToSort = new Bool_t[nRubrics];
1318 memset(rubricsToSort, kFALSE, sizeof(Bool_t) * nRubrics);
1320 // choose rubrics to sort
1321 TObject* rubric = 0x0;
1322 TIter nextRubric(fRubrics);
1323 while ((rubric = nextRubric())) {
1325 if (all || dynamic_cast<TObjString*>(rubric)) {
1327 // check if something to sort
1328 THashList* labels = fCounters->GetAxis((Int_t)rubric->GetUniqueID())->GetLabels();
1329 if (!labels || labels->GetSize() < 2) continue;
1331 // select that rubric
1332 rubricsToSort[(Int_t)rubric->GetUniqueID()] = kTRUE;
1333 somethingToSort = kTRUE;
1339 // sort selected rubrics if any
1340 if (somethingToSort) Sort(rubricsToSort, asInt);
1343 delete[] rubricsToSort;
1346 //-----------------------------------------------------------------------
1347 void AliCounterCollection::SortRubric(TString rubric, Bool_t asInt)
1349 /// Sort only that rubric. If asInt=kTRUE, key words are ordered as interger instead of alphabetically.
1352 AliError("counters are not initialized");
1358 // find the rubric to sort
1359 Int_t dim = FindDim(rubric);
1360 if (dim < 0) return;
1362 // check if something to sort
1363 THashList* labels = fCounters->GetAxis(dim)->GetLabels();
1364 if (!labels || labels->GetSize() < 2) return;
1366 // select that rubric
1367 Int_t nRubrics = fRubrics->GetSize();
1368 Bool_t* rubricsToSort = new Bool_t[nRubrics];
1369 memset(rubricsToSort, kFALSE, sizeof(Bool_t) * nRubrics);
1370 rubricsToSort[dim] = kTRUE;
1373 Sort(rubricsToSort, asInt);
1376 delete[] rubricsToSort;
1379 //-----------------------------------------------------------------------
1380 void AliCounterCollection::Sort(const Bool_t* rubricsToSort, Bool_t asInt)
1382 /// Sort labels (alphabetically or as integer) in each rubric flagged in "rubricsToSort".
1384 // create a new counter
1385 THnSparse* oldCounters = fCounters;
1386 Int_t nRubrics = fRubrics->GetSize();
1387 fCounters = new THnSparseT<TArrayI>("hCounters", "hCounters", nRubrics, fRubricsSize->GetArray(), 0x0, 0x0);
1388 Int_t** newBins = new Int_t*[nRubrics];
1390 // define the new axes
1391 for (Int_t i=0; i<nRubrics; i++) {
1392 TAxis* oldAxis = oldCounters->GetAxis(i);
1393 TAxis* newAxis = fCounters->GetAxis(i);
1395 // set the name of the new axis
1396 newAxis->SetName(oldAxis->GetName());
1399 THashList* oldLabels = oldAxis->GetLabels();
1400 if (!oldLabels) continue;
1402 // sort them if required
1403 if (rubricsToSort[i]) {
1404 if (asInt) { oldLabels = SortAsInt(oldLabels); }
1405 else { oldLabels->Sort(); }
1408 // set labels in the new axis and save the correspondence between new and old bins
1409 newBins[i] = new Int_t[oldLabels->GetSize()+1];
1410 TObjString* label = 0x0;
1412 TIter nextLabel(oldLabels);
1413 while ((label = static_cast<TObjString*>(nextLabel()))) {
1414 newAxis->SetBinLabel(bin, label->String().Data());
1415 newBins[i][(Int_t)label->GetUniqueID()] = bin;
1420 if (rubricsToSort[i] && asInt) delete oldLabels;
1423 // fill the new counters
1424 Int_t* oldCoor = new Int_t[nRubrics];
1425 Int_t* newCoor = new Int_t[nRubrics];
1426 for (Long64_t i = 0; i < oldCounters->GetNbins(); i++) {
1427 Double_t value = oldCounters->GetBinContent(i, oldCoor);
1428 for (Int_t dim = 0; dim < nRubrics; dim++) newCoor[dim] = newBins[dim][oldCoor[dim]];
1429 fCounters->AddBinContent(newCoor, value);
1433 for (Int_t i=0; i<nRubrics; i++) delete[] newBins[i];
1440 //-----------------------------------------------------------------------
1441 THashList* AliCounterCollection::SortAsInt(const THashList* labels)
1443 /// Return a list (not owner) of labels sorted assuming they are integers.
1444 /// It is the responsability of user to delete the returned list.
1446 THashList* sortedLabels = new THashList(labels->GetSize());
1447 TIter nextSortedLabel(sortedLabels);
1450 TObjString* label = 0x0;
1451 TIter nextLabel(labels);
1452 while ((label = static_cast<TObjString*>(nextLabel()))) {
1454 // find where to add it
1455 TObjString* sortedLabel = 0x0;
1456 nextSortedLabel.Reset();
1457 while ((sortedLabel = static_cast<TObjString*>(nextSortedLabel())) &&
1458 (sortedLabel->String().Atoi() <= label->String().Atoi())) {}
1461 if (sortedLabel) sortedLabels->AddBefore(sortedLabel, label);
1462 else sortedLabels->AddLast(label);
1465 return sortedLabels;