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