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