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