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