]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWG/muon/AliHistogramCollection.cxx
adding cuts for muons
[u/mrichter/AliRoot.git] / PWG / muon / AliHistogramCollection.cxx
1 /**************************************************************************
2 * Copyright(c) 1998-1999, 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 /// A (fake) "4D" histogram container. 
20 ///
21 /// For each tuple (keyA,keyB,keyC,keyD) a (hash)list of histogram is associated.
22 /// Note that keyA, keyB (optional), keyC (optional) and keyD (optional) are strings. 
23 /// Those strings should not contain "/" themselves.
24 ///
25 /// More helper functions might be added in the future (e.g. Project, etc...)
26
27 #include "AliHistogramCollection.h"
28
29 #include "AliLog.h"
30 #include "Riostream.h"
31 #include "TError.h"
32 #include "TH1.h"
33 #include "TH2.h"
34 #include "THashList.h"
35 #include "TKey.h"
36 #include "TMap.h"
37 #include "TObjArray.h"
38 #include "TObjString.h"
39 #include "TRegexp.h"
40 #include "TROOT.h"
41 #include "TSystem.h"
42 #include "TProfile.h"
43
44 using std::cout;
45 using std::endl;
46 ClassImp(AliHistogramCollection)
47
48 //_____________________________________________________________________________
49 AliHistogramCollection::AliHistogramCollection(const char* name, const char* title) 
50 : TNamed(name,title), fMap(0x0), fMustShowEmptyHistogram(kFALSE), fMapVersion(0), fMessages()
51 {
52   /// Ctor
53 }
54
55 //_____________________________________________________________________________
56 AliHistogramCollection::~AliHistogramCollection()
57 {
58   /// dtor. Note that the map is owner
59   if ( fMap ) fMap->DeleteAll();
60   delete fMap;
61 //  PrintMessages("AliHistogramCollection::~AliHistogramCollection");
62 }
63
64 //_____________________________________________________________________________
65 Bool_t 
66 AliHistogramCollection::Adopt(TH1* histo)
67 {
68   /// Adopt a given histogram at top level (i.e. no key)
69   return InternalAdopt("",histo);
70 }
71
72 //_____________________________________________________________________________
73 Bool_t 
74 AliHistogramCollection::Adopt(const char* key, TH1* histo)
75 {
76   /// Adopt a given histogram, and associate it with pair (keyA)
77   return InternalAdopt(Form("/%s/",key),histo);
78 }
79
80 //_____________________________________________________________________________
81 Bool_t 
82 AliHistogramCollection::Adopt(const char* keyA, const char* keyB, TH1* histo)
83 {
84   /// Adopt a given histogram, and associate it with pair (keyA,keyB)
85   return InternalAdopt(Form("/%s/%s/",keyA,keyB),histo);
86 }
87
88 //_____________________________________________________________________________
89 Bool_t 
90 AliHistogramCollection::Adopt(const char* keyA, const char* keyB, const char* keyC, TH1* histo)
91 {
92   /// Adopt a given histogram, and associate it with pair (keyA,keyB,keyC)
93   return InternalAdopt(Form("/%s/%s/%s/",keyA,keyB,keyC),histo);
94 }
95
96 //_____________________________________________________________________________
97 Bool_t 
98 AliHistogramCollection::Adopt(const char* keyA, const char* keyB, const char* keyC, const char* keyD, TH1* histo)
99 {
100   /// Adopt a given histogram, and associate it with pair (keyA,keyB,keyC,keyD)
101   return InternalAdopt(Form("/%s/%s/%s/%s/",keyA,keyB,keyC,keyD),histo);
102 }
103
104 //_____________________________________________________________________________
105 void AliHistogramCollection::ClearMessages()
106 {
107   /// clear pending messages
108   fMessages.clear();
109 }
110
111 //_____________________________________________________________________________
112 TIterator*
113 AliHistogramCollection::CreateIterator(Bool_t direction) const
114 {
115   /// Create an iterator (must be deleted by the client)
116   return fMap ? new AliHistogramCollectionIterator(this,direction) : 0x0;
117 }
118
119 //_____________________________________________________________________________
120 AliHistogramCollection*
121 AliHistogramCollection::Clone(const char* name) const
122 {
123   /// Clone this collection.
124   /// We loose the messages.
125   
126   AliHistogramCollection* newone = new AliHistogramCollection(name,GetTitle());
127   
128   newone->fMap = static_cast<TMap*>(fMap->Clone());
129   newone->fMustShowEmptyHistogram = fMustShowEmptyHistogram;
130   newone->fMapVersion = fMapVersion;  
131   
132   return newone;
133 }
134
135 //_____________________________________________________________________________
136 void 
137 AliHistogramCollection::Delete(Option_t*)
138 {
139   /// Delete all the histograms
140   fMap->DeleteAll();
141   delete fMap;
142   fMap=0x0;
143 }
144
145 //_____________________________________________________________________________
146 TObject* 
147 AliHistogramCollection::FindObject(const char* identifier) const
148 {
149   /// Find an object by its full identifier.
150   
151   return Histo(KeyA(identifier),
152                KeyB(identifier),
153                KeyC(identifier),
154                KeyD(identifier),
155                HistoName(identifier));
156 }
157
158 //_____________________________________________________________________________
159 TObject* 
160 AliHistogramCollection::FindObject(const TObject *key) const
161 {
162   /// Find an object 
163   AliWarning("This method is awfully inefficient. Please improve it or use FindObject(const char*)");
164   TIter next(CreateIterator());
165   TObject* o;
166   while ( ( o=next() ) )
167   {
168     if ( o->IsEqual(key) ) return o;
169   }
170   return 0x0;
171 }
172
173 //_____________________________________________________________________________
174 TH1* 
175 AliHistogramCollection::Histo(const char* keyA, 
176                               const char* histoname) const
177 {
178   /// Get histo for (keyA,histoname) triplet
179   
180   return InternalHisto(Form("/%s/",keyA),histoname);
181 }
182
183 //_____________________________________________________________________________
184 TH1* 
185 AliHistogramCollection::Histo(const char* keyA, const char* keyB, 
186                               const char* histoname) const
187 {
188   /// Get histo for (keyA,keyB,histoname) triplet
189
190   return InternalHisto(Form("/%s/%s/",keyA,keyB),histoname);
191 }
192
193 //_____________________________________________________________________________
194 TH1* 
195 AliHistogramCollection::Histo(const char* keyA, const char* keyB, const char* keyC,
196                               const char* histoname) const
197 {
198   /// Get histo for (keyA,keyB,keyC,histoname) quad
199   
200   return InternalHisto(Form("/%s/%s/%s/",keyA,keyB,keyC),histoname);
201 }
202
203 //_____________________________________________________________________________
204 TH1* 
205 AliHistogramCollection::Histo(const char* keyA, const char* keyB, 
206                               const char* keyC, const char* keyD,
207                               const char* histoname) const
208 {
209   /// Get histo for (keyA,keyB,keyC,histoname) quad
210   
211   return InternalHisto(Form("/%s/%s/%s/%s/",keyA,keyB,keyC,keyD),histoname);
212 }
213
214 //_____________________________________________________________________________
215 TString
216 AliHistogramCollection::HistoName(const char* identifier) const
217 {
218   /// Extract the histogram name from an identifier
219   
220   return InternalDecode(identifier,-1);  
221 }
222
223 //_____________________________________________________________________________
224 Bool_t AliHistogramCollection::InternalAdopt(const char* identifier, TH1* histo)
225 {
226   /// Adopt an histogram
227   
228   if (!histo)
229   {
230     Error("Adopt","Cannot adopt a null histogram");
231     return kFALSE;
232   }
233   
234   THashList* hlist = 0x0;
235   
236   hlist = static_cast<THashList*>(Map()->GetValue(identifier));
237   
238   if (!hlist)
239   {
240     hlist = new THashList;
241     hlist->SetOwner(kTRUE);
242     Map()->Add(new TObjString(identifier),hlist);
243     hlist->SetName(identifier);
244   }
245   
246   TH1* h = static_cast<TH1*>(hlist->FindObject(histo->GetName()));
247   
248   if (h)
249   {
250     AliError(Form("Cannot adopt an already existing histogram : %s -> %s",identifier,h->GetName()));
251     return kFALSE;
252   }
253   
254   
255   histo->SetDirectory(0);  
256   
257   hlist->AddLast(histo);
258   
259   return kTRUE;
260   
261 }
262
263 //_____________________________________________________________________________
264 TH1* 
265 AliHistogramCollection::Histo(const char* sidentifier) const
266 {
267   /// Get histogram keyA/keyB/keyC/keyD/histoname:action
268   
269   TObjArray* a = TString(sidentifier).Tokenize(":");
270   
271   TString identifier(static_cast<TObjString*>(a->At(0))->String());
272   TString action;
273   
274   if ( a->GetLast() > 0 ) 
275   {
276     action = static_cast<TObjString*>(a->At(1))->String();
277     action.ToUpper();
278   }
279   
280   Int_t nslashes = identifier.CountChar('/');
281
282   TH1* h(0x0);
283   
284   switch (nslashes)
285   {
286     case 0:
287     case 1:
288       // no slash : the identifier is just the histogram name
289       h = InternalHisto("",identifier);
290       break;      
291     case 2:
292       h = Histo(InternalDecode(identifier,0),
293                 InternalDecode(identifier,-1));
294       break;
295     case 3:
296       h = Histo(InternalDecode(identifier,0),
297                 InternalDecode(identifier,1),
298                 InternalDecode(identifier,-1));
299       break;
300     case 4:
301       h = Histo(InternalDecode(identifier,0),
302                 InternalDecode(identifier,1),
303                 InternalDecode(identifier,2),
304                 InternalDecode(identifier,-1));
305       break;
306     case 5:
307       h = Histo(InternalDecode(identifier,0),
308                 InternalDecode(identifier,1),
309                 InternalDecode(identifier,2),
310                 InternalDecode(identifier,3),
311                 InternalDecode(identifier,-1));
312       break;
313     default:
314       AliError(Form("Invalid identifier %s",identifier.Data()));
315       break;
316   }
317   
318   if (h)
319   {
320     TH2* h2(0x0);
321     
322     if ( action == "PX" && ( (h2 = dynamic_cast<TH2*>(h)) ) ) 
323     {
324       return h2->ProjectionX(NormalizeName(identifier.Data(),action.Data()).Data());
325     }
326     else if ( action == "PY" && ( (h2 = dynamic_cast<TH2*>(h)) ) ) 
327     {
328       return h2->ProjectionY(NormalizeName(identifier.Data(),action.Data()).Data());
329     }
330     else if ( action == "PFX" && ( (h2 = dynamic_cast<TH2*>(h)) ) ) 
331     {
332       return h2->ProfileX(NormalizeName(identifier.Data(),action.Data()).Data());
333     }
334     else if ( action == "PFY" && ( (h2 = dynamic_cast<TH2*>(h)) ) ) 
335     {
336       return h2->ProfileY(NormalizeName(identifier.Data(),action.Data()).Data());
337     }
338     
339   }
340   else
341   {
342     AliDebug(1,Form("histogram %s not found",sidentifier));
343   }
344   return h;
345 }
346
347 //_____________________________________________________________________________
348 TString
349 AliHistogramCollection::InternalDecode(const char* identifier, Int_t index) const
350 {
351   /// Extract the index-th element of the identifier (/keyA/keyB/keyC/keyD/histoname)
352   /// keyA is index=0
353   /// keyB is index=1
354   /// keyC is index=2
355   /// keyD is index=3
356   /// histo is index=-1 (i.e. last)
357   
358   if ( strlen(identifier) > 0 && identifier[0] != '/' ) 
359   {    
360     AliError(Form("identifier %s is malformed (should start with /)",identifier));
361     return "";
362   }
363   
364   TObjArray* array = TString(identifier).Tokenize("/");
365
366   if ( array->GetLast()>5 ) 
367   {
368     AliError(Form("identifier %s is malformed (more than 5 /)",identifier));
369     delete array;
370     return "";    
371   }
372
373   TString value("");
374   
375   if ( index < 0 ) 
376   {
377     value = static_cast<TObjString*>(array->Last())->String();    
378   }
379   else if ( index <= array->GetLast() ) 
380   {
381     value = static_cast<TObjString*>(array->At(index))->String();
382   }
383   
384   delete array;
385   
386   return value;
387 }
388
389 //_____________________________________________________________________________
390 TH1* 
391 AliHistogramCollection::InternalHisto(const char* identifier,
392                                       const char* histoname) const
393 {
394   /// Get histo for (identifier,histoname) 
395   
396   if (!fMap) 
397   {
398     return 0x0;
399   }
400   
401   THashList* hlist = static_cast<THashList*>(Map()->GetValue(identifier));
402   if (!hlist) 
403   {
404     TString msg(Form("Did not find hashlist for identifier=%s dir=%s",identifier,gDirectory ? gDirectory->GetName() : "" ));
405     fMessages[msg.Data()]++;
406     return 0x0;
407   }
408   
409   TH1* h = static_cast<TH1*>(hlist->FindObject(histoname));  
410   if (!h)
411   {
412     TString msg(Form("Did not find histoname=%s in %s",histoname,identifier));
413     fMessages[msg.Data()]++;
414   }
415   return h;
416 }
417
418
419 //_____________________________________________________________________________
420 TString
421 AliHistogramCollection::KeyA(const char* identifier) const
422 {
423   /// Extract the first element of the key pair from an identifier
424   
425   return InternalDecode(identifier,0);
426 }
427
428 //_____________________________________________________________________________
429 TString
430 AliHistogramCollection::KeyB(const char* identifier) const
431 {
432   /// Extract the second element (if present) 
433   return InternalDecode(identifier,1);
434 }
435
436 //_____________________________________________________________________________
437 TString
438 AliHistogramCollection::KeyC(const char* identifier) const
439 {
440   /// Extract the 3rd element (if present) 
441   return InternalDecode(identifier,2);
442 }
443
444 //_____________________________________________________________________________
445 TString
446 AliHistogramCollection::KeyD(const char* identifier) const
447 {
448   /// Extract the 4th element (if present) 
449   return InternalDecode(identifier,3);
450 }
451
452 //_____________________________________________________________________________
453 TMap* AliHistogramCollection::Map() const
454 {
455   /// Wrapper to insure proper key formats (i.e. new vs old)
456   
457   if (!fMap)
458   {
459     fMap = new TMap;
460     fMap->SetOwnerKeyValue(kTRUE,kTRUE);
461     fMapVersion = 1;
462   }
463   else
464   {
465     if ( fMapVersion < 1 ) 
466     {
467       // change the keys
468       TIter next(fMap);
469       TObjString* str;
470       
471       while ( ( str = static_cast<TObjString*>(next()) ) )
472       {
473         if ( str->String().Contains("./") )
474         {
475           TString newkey(str->String());
476           
477           newkey.ReplaceAll("./","");
478           
479           TObject* o = fMap->GetValue(str);
480           
481           TPair* p = fMap->RemoveEntry(str);
482           if (!p)
483           {
484             AliError("oups oups oups");
485             return 0x0;
486           }
487           
488           fMap->Add(new TObjString(newkey.Data()),o);
489           
490           delete p;
491         }
492       }
493       
494       fMapVersion = 1;
495     }
496   }
497   
498   return fMap;
499 }
500
501 //_____________________________________________________________________________
502 Long64_t
503 AliHistogramCollection::Merge(TCollection* list)
504 {
505   // Merge a list of AliHistogramCollection objects with this
506   // Returns the number of merged objects (including this).
507   
508   if (!list) return 0;
509   
510   if (list->IsEmpty()) return 1;
511   
512   TIter next(list);
513   TObject* o;
514   TList mapList;
515   Int_t count(0);
516   
517   while ( ( o = next() ) )
518   {
519     AliHistogramCollection* hcol = dynamic_cast<AliHistogramCollection*>(o);
520     if (!hcol) {
521       AliFatal(Form("object named \"%s\" is a %s instead of an AliHistogramCollection!", o->GetName(), o->ClassName()));
522       continue;
523     }
524     
525     ++count;
526     
527     if ( hcol->fMap ) hcol->Map(); // to insure keys in the new format
528     
529     TIter nextIdentifier(hcol->fMap);
530     TObjString* identifier;
531
532     while ( ( identifier = static_cast<TObjString*>(nextIdentifier()) ) )
533     {
534       THashList* otherList = static_cast<THashList*>(hcol->fMap->GetValue(identifier->String().Data()));
535
536       TIter nextHisto(otherList);
537       TH1* h;
538       
539       while ( ( h = static_cast<TH1*>(nextHisto()) ) )
540       {
541         TString newid(Form("%s%s",identifier->String().Data(),h->GetName()));
542         
543         TH1* thisHisto = Histo(newid.Data());
544         
545         if (!thisHisto)
546         {
547           AliDebug(1,Form("Adopting a new histo = %s%s",identifier->String().Data(),h->GetName()));
548           
549           // this is an histogram we don't have yet. Let's add it
550           
551           Int_t nslashes = TString(newid).CountChar('/');
552           
553           Bool_t ok(kFALSE);
554           
555           switch (nslashes)
556           {
557             case 2:
558               ok = Adopt(KeyA(identifier->String()),
559                         static_cast<TH1*>(h->Clone()));
560               break;
561             case 3:
562               ok = Adopt(KeyA(identifier->String()),
563                         KeyB(identifier->String()),
564                         static_cast<TH1*>(h->Clone()));
565               break;
566             case 4:
567               ok = Adopt(KeyA(identifier->String()),
568                         KeyB(identifier->String()),
569                         KeyC(identifier->String()),
570                         static_cast<TH1*>(h->Clone()));
571               break;
572             case 5:
573               ok = Adopt(KeyA(identifier->String()),
574                         KeyB(identifier->String()),
575                         KeyC(identifier->String()),
576                         KeyD(identifier->String()),
577                         static_cast<TH1*>(h->Clone()));
578               break;
579             default:
580               AliError(Form("Invalid identifier %s",identifier->String().Data()));
581               break;
582           }
583           
584           if (!ok)
585           {
586             AliError(Form("Adoption of histogram %s failed",h->GetName()));
587           }
588         }
589         else
590         {
591           // add it...
592           AliDebug(1,Form("Merging histo = %s%s (%g vs %g)",
593                           identifier->String().Data(),
594                           h->GetName(),
595                           h->GetSumOfWeights(),
596                           thisHisto->GetSumOfWeights()));
597           
598           if ( HistoSameAxis(h,thisHisto) )
599           {
600             thisHisto->Add(h);
601           }
602           else
603           {
604             TList l;
605             l.Add(h);
606           
607             thisHisto->Merge(&l);
608           }
609         }
610       }
611     }
612   }
613          
614   AliDebug(1,Form("count=%d",count));
615   
616   return count+1;
617 }
618
619 //_____________________________________________________________________________
620 TString AliHistogramCollection::NormalizeName(const char* identifier,const char* action) const
621 {
622   // Replace / by _ to build a root-compliant histo name
623   TString name(identifier);
624   name += "_";
625   name += action;
626   name.ReplaceAll("/","_");
627   return name;
628 }
629
630 //_____________________________________________________________________________
631 Int_t 
632 AliHistogramCollection::NumberOfHistograms() const
633 {
634   /// Get the number of histograms we hold
635   TIter next(CreateIterator(this));
636   Int_t n(0);
637   while ( next() ) ++n;
638   return n;
639 }
640
641 //_____________________________________________________________________________
642 Int_t 
643 AliHistogramCollection::NumberOfKeys() const
644 {
645   /// Get the number of keys we have
646   return fMap ? fMap->GetSize() : 0;
647 }
648
649 //_____________________________________________________________________________
650 void 
651 AliHistogramCollection::Print(Option_t* option) const
652 {
653   /// Print all the histograms we hold, in a hopefully visually pleasing
654   /// way.
655   ///
656   /// Option can be used to select given part only, using the schema :
657   /// /*/*/*/*/*
658   /// Where the stars are wilcards for /keyA/keyB/keyC/KeyD/histoname
659   ///
660   /// if * is used it is assumed to be a wildcard for histoname
661   ///
662   /// For other selections the full syntax /*/*/*/*/* must be used.
663   /// 
664   /// Use "-" as histoname to disable histogram's name output
665   
666   cout << Form("AliHistogramCollection : %d keys and %d histos",
667                NumberOfKeys(), NumberOfHistograms()) << endl;
668   
669   if (!strlen(option)) return;
670   
671   TString sreKeyA("*");
672   TString sreKeyB("*");
673   TString sreKeyC("*");
674   TString sreKeyD("*");
675   TString sreHistoname("*");
676   
677   TObjArray* select = TString(option).Tokenize("/");
678   Int_t n = select->GetLast();
679   
680   if (n>=0)
681   {
682     sreHistoname = static_cast<TObjString*>(select->At(n))->String();
683   }
684   if (n>=1)
685   {
686     sreKeyD = static_cast<TObjString*>(select->At(n-1))->String();    
687   }
688   if (n>=2)
689   {
690     sreKeyC = static_cast<TObjString*>(select->At(n-2))->String();    
691   }
692   if (n>=3)
693   {
694     sreKeyB = static_cast<TObjString*>(select->At(n-3))->String();    
695   }
696   if (n>=4)
697   {
698     sreKeyA = static_cast<TObjString*>(select->At(n-3))->String();    
699   }
700   
701   TRegexp reKeyA(sreKeyA,kTRUE);
702   TRegexp reKeyB(sreKeyB,kTRUE);
703   TRegexp reKeyC(sreKeyC,kTRUE);
704   TRegexp reKeyD(sreKeyD,kTRUE);
705   TRegexp reHistoname(sreHistoname,kTRUE);
706
707   delete select;
708   
709   TObjArray* identifiers = SortAllIdentifiers();
710     
711   TIter nextIdentifier(identifiers);
712   
713   TObjString* sid(0x0);
714   
715   while ( ( sid = static_cast<TObjString*>(nextIdentifier()) ) )
716   {
717     Bool_t identifierPrinted(kFALSE);
718
719     TString identifier(sid->String());
720     
721     if ( ( InternalDecode(identifier,0).Contains(reKeyA) &&
722           InternalDecode(identifier,1).Contains(reKeyB) &&
723           InternalDecode(identifier,2).Contains(reKeyC) &&
724           InternalDecode(identifier,3).Contains(reKeyD) )
725         )
726     {
727       if ( sreHistoname == "*" ) 
728       {
729         identifierPrinted = kTRUE;
730         cout << identifier.Data() << endl;
731       }
732       
733       THashList * list = static_cast<THashList*>(Map()->GetValue(sid->String().Data()));      
734       TObjArray names;
735       names.SetOwner(kTRUE);
736       TIter nextUnsortedHisto(list);
737       TH1* h;
738       while ( ( h = static_cast<TH1*>(nextUnsortedHisto()) ) )
739       {
740         names.Add(new TObjString(h->GetName()));
741       }
742       names.Sort();
743       TIter nextHistoName(&names);
744       TObjString* hname;
745       while ( ( hname = static_cast<TObjString*>(nextHistoName()) ) )
746       {
747         TString histoName(hname->String());
748         if (histoName.Contains(reHistoname) )
749         {
750           h = static_cast<TH1*>(list->FindObject(histoName.Data()));
751           if ( h->GetEntries()==0 && !fMustShowEmptyHistogram ) continue;
752           if (!identifierPrinted)
753           {
754             cout << identifier.Data() << endl;
755             identifierPrinted = kTRUE;
756           }
757           cout << Form("    %s %s Entries=%d Sum=%g",h->GetName(),h->GetTitle(),Int_t(h->GetEntries()),h->GetSumOfWeights()) << endl;
758         }
759       }
760       if (!identifierPrinted && sreHistoname=="-" )
761       { 
762         // to handle the case where we used histoname="-" to disable showing the histonames,
763         // but we still want to see the matching keys maybe...
764         cout << identifier.Data() << endl;
765       }
766     }
767   }
768   
769   delete identifiers;
770 }
771
772 //_____________________________________________________________________________
773 void 
774 AliHistogramCollection::PrintMessages(const char* prefix) const
775 {
776   /// Print pending messages
777   
778   std::map<std::string,int>::const_iterator it;
779   
780   for ( it = fMessages.begin(); it != fMessages.end(); ++it ) 
781   {
782     cout << Form("%s : message %s appeared %5d times",prefix,it->first.c_str(),it->second) << endl;
783   }
784 }
785
786
787 //_____________________________________________________________________________
788 UInt_t 
789 AliHistogramCollection::EstimateSize(Bool_t show) const
790 {
791   /// Estimate the memory (in kilobytes) used by our histograms
792   
793 //  sizeof(TH1) + (nbins+2)*(nbytes_per_bin) +name+title_sizes 
794 //  if you have errors add (nbins+2)*8 
795     
796   TIter next(CreateIterator());
797   TH1* h;
798   UInt_t n(0);
799   
800   while ( ( h = static_cast<TH1*>(next()) ) )
801   {
802     Int_t nbins = (h->GetNbinsX()+2);
803     
804     if (h->GetNbinsY()>1)
805     {
806       nbins *= (h->GetNbinsY()+2);
807     }
808     
809     if (h->GetNbinsZ()>1)
810     {
811       nbins *= (h->GetNbinsZ()+2);
812     }
813       
814     Bool_t hasErrors = ( h->GetSumw2N() > 0 );
815     
816     TString cname(h->ClassName());
817     
818     Int_t nbytesPerBin(0);
819     
820     if (cname.Contains(TRegexp("C$")) ) nbytesPerBin = sizeof(Char_t);
821     if (cname.Contains(TRegexp("S$")) ) nbytesPerBin = sizeof(Short_t);
822     if (cname.Contains(TRegexp("I$")) ) nbytesPerBin = sizeof(Int_t);
823     if (cname.Contains(TRegexp("F$")) ) nbytesPerBin = sizeof(Float_t);
824     if (cname.Contains(TRegexp("D$")) ) nbytesPerBin = sizeof(Double_t);
825         
826     if (!nbytesPerBin)
827     {
828       AliError(Form("Could not get the number of bytes per bin for histo %s of class %s. Thus the size estimate will be wrong !",
829                     h->GetName(),h->ClassName()));
830       continue;
831     }
832     
833     UInt_t thissize = sizeof(h) + nbins*(nbytesPerBin) + strlen(h->GetName())
834     + strlen(h->GetTitle());
835     
836     if ( hasErrors) thissize += nbins*8;
837
838     n += thissize;
839     
840     if ( show ) 
841     {
842       AliInfo(Form("Size of %30s is %20d bytes",h->GetName(),thissize));
843     }
844   }
845
846   return n;
847 }
848
849 //_____________________________________________________________________________
850 void AliHistogramCollection::PruneEmptyHistograms()
851 {
852   /// Delete the empty histograms
853   TIter next(Map());
854   TObjString* key;
855   
856   TList toBeRemoved;
857   toBeRemoved.SetOwner(kTRUE);
858   
859   while ( ( key = static_cast<TObjString*>(next()) ) )
860   {
861     TString identifier(key->String());
862     THashList* hlist = static_cast<THashList*>(Map()->GetValue(identifier.Data()));
863     TIter nextHisto(hlist);
864     TH1* h;
865     while ( ( h = static_cast<TH1*>(nextHisto())))
866     {
867       if ( h->GetEntries()==0)
868       {
869         toBeRemoved.Add(new TObjString(Form("%s%s",identifier.Data(),h->GetName())));
870       }
871     }
872   }
873   
874   TIter nextTBR(&toBeRemoved);
875   while ( ( key = static_cast<TObjString*>(nextTBR()) ) )
876   {
877     Remove(key);
878   }
879 }
880
881 //_____________________________________________________________________________
882 AliHistogramCollection* 
883 AliHistogramCollection::Project(const char* keyA, const char* keyB, const char* keyC, const char* keyD) const
884 {
885   /// To be implemented : would create a new collection starting at keyA/keyB/keyC/keyD
886   
887   if (!fMap) return 0x0;
888   
889   AliHistogramCollection* hc = new AliHistogramCollection(Form("%s %s/%s/%s/%s",GetName(),keyA,keyB,keyC,keyD),
890                                                           GetTitle());
891   
892   TIter next(Map());
893   TObjString* str;
894   
895   while ( ( str = static_cast<TObjString*>(next()) ) )
896   {
897     TString identifier = str->String();
898     
899     Bool_t copy= ( KeyA(identifier) == keyA &&
900                   ( strlen(keyB)==0 || KeyB(identifier)==keyB ) && 
901                   ( strlen(keyC)==0 || KeyC(identifier)==keyC ) && 
902                   ( strlen(keyD)==0 || KeyD(identifier)==keyD ));
903
904     if ( !copy ) continue;
905     
906     THashList* list = static_cast<THashList*>(Map()->GetValue(identifier.Data()));
907     
908     TIter nextHisto(list);
909     TH1* h;
910     
911     while ( ( h = static_cast<TH1*>(nextHisto()) ) )
912     {
913       TH1* hclone = static_cast<TH1*>(h->Clone());
914
915       TString newkey(identifier.Data());
916       
917       if ( strlen(keyD) > 0 ) newkey.ReplaceAll(Form("/%s",keyD),"");
918       if ( strlen(keyC) > 0 ) newkey.ReplaceAll(Form("/%s",keyC),"");
919       if ( strlen(keyB) > 0 ) newkey.ReplaceAll(Form("/%s",keyB),"");
920       if ( strlen(keyA) > 0 ) newkey.ReplaceAll(Form("/%s",keyA),"");
921
922       if (newkey=="/") newkey="";
923       
924       hc->InternalAdopt(newkey.Data(),hclone);
925     }    
926   }
927
928   return hc;
929 }
930
931 //_____________________________________________________________________________
932 TObject* 
933 AliHistogramCollection::Remove(TObject* key)
934 {
935   ///
936   /// Remove a given histogram (given its key=full identifier=/keyA/keyB/keyC/keyD/histoname)
937   ///
938   /// Note that we do *not* remove the /keyA/keyB/keyC/keyD entry even if there's no
939   /// more histogram for this triplet.
940   ///
941   /// Not very efficient. Could be improved ?
942   ///
943   
944   TObjString* str = dynamic_cast<TObjString*>(key);
945   
946   if (!str)
947   {
948     AliError(Form("key is not of the expected TObjString type, but of %s",key->ClassName()));
949     return 0x0;
950   }
951   
952   TString identifier(str->String());
953     
954   Int_t nslashes = TString(identifier).CountChar('/');
955
956   TString skey;
957   
958   switch (nslashes )
959   {
960     case 2:
961       skey = Form("/%s/",
962                   KeyA(identifier).Data());
963       break;
964     case 3:
965       skey = Form("/%s/%s/",
966                   KeyA(identifier).Data(),
967                   KeyB(identifier).Data());
968       break;
969     case 4:
970       skey = Form("/%s/%s/%s/",
971                   KeyA(identifier).Data(),
972                   KeyB(identifier).Data(),
973                   KeyC(identifier).Data());
974       break;
975     case 5:
976       skey = Form("/%s/%s/%s/%s/",
977                   KeyA(identifier).Data(),
978                   KeyB(identifier).Data(),
979                   KeyC(identifier).Data(),
980                   KeyD(identifier).Data()
981                   );
982       break;
983     default:
984       AliError("Oups");
985       break;
986   };
987   
988   THashList* hlist = dynamic_cast<THashList*>(Map()->GetValue(skey.Data()));
989   
990   if (!hlist)
991   {
992     AliWarning(Form("Could not get hlist for key=%s",skey.Data()));
993     return 0x0;
994   }
995     
996   TH1* h = InternalHisto(skey,HistoName(identifier.Data()));
997   if (!h)
998   {
999     AliError(Form("Could not find histo %s",identifier.Data()));
1000     return 0x0;
1001   }
1002   
1003   TObject* o = hlist->Remove(h);
1004   if (!o)
1005   {
1006     AliError("Remove failed");
1007     return 0x0;
1008   }
1009
1010 //  if ( hlist->IsEmpty() ) 
1011 //  {
1012 //    // we should remove the key as well
1013 //    TObject* k = fMap->Remove(key);
1014 //    if (!k)
1015 //    {
1016 //      AliError("Removal of the key failed");
1017 //    }
1018 //  }
1019   
1020   return o;
1021 }
1022
1023 //______________________________________________________________________________
1024 Bool_t AliHistogramCollection::HistoSameAxis(TH1 *h0, TH1 *h1) const
1025 {
1026   // shameless copy from TProofPlayerRemote::HistoSameAxis
1027   //
1028   // Return kTRUE is the histograms 'h0' and 'h1' have the same binning and ranges
1029   // on the axis (i.e. if they can be just Add-ed for merging).
1030   
1031   Bool_t rc = kFALSE;
1032   if (!h0 || !h1) return rc;
1033   
1034   TAxis *a0 = 0, *a1 = 0;
1035   
1036   // Check X
1037   a0 = h0->GetXaxis();
1038   a1 = h1->GetXaxis();
1039   if (a0->GetNbins() == a1->GetNbins())
1040     if (TMath::Abs(a0->GetXmax() - a1->GetXmax()) < 1.e-9)
1041       if (TMath::Abs(a0->GetXmin() - a1->GetXmin()) < 1.e-9) rc = kTRUE;
1042   
1043   // Check Y, if needed
1044   if (h0->GetDimension() > 1) {
1045     rc = kFALSE;
1046     a0 = h0->GetYaxis();
1047     a1 = h1->GetYaxis();
1048     if (a0->GetNbins() == a1->GetNbins())
1049       if (TMath::Abs(a0->GetXmax() - a1->GetXmax()) < 1.e-9)
1050         if (TMath::Abs(a0->GetXmin() - a1->GetXmin()) < 1.e-9) rc = kTRUE;
1051   }
1052   
1053   // Check Z, if needed
1054   if (h0->GetDimension() > 2) {
1055     rc = kFALSE;
1056     a0 = h0->GetZaxis();
1057     a1 = h1->GetZaxis();
1058     if (a0->GetNbins() == a1->GetNbins())
1059       if (TMath::Abs(a0->GetXmax() - a1->GetXmax()) < 1.e-9)
1060         if (TMath::Abs(a0->GetXmin() - a1->GetXmin()) < 1.e-9) rc = kTRUE;
1061   }
1062   
1063   // Done
1064   return rc;
1065 }
1066
1067 //_____________________________________________________________________________
1068 TObjArray*
1069 AliHistogramCollection::SortAllIdentifiers() const
1070 {
1071   /// Sort our internal identifiers. Returned array must be deleted.
1072   TObjArray* identifiers = new TObjArray;
1073   identifiers->SetOwner(kFALSE); 
1074   TIter next(Map());
1075   TObjString* sid;
1076   
1077   while ( ( sid = static_cast<TObjString*>(next()) ) )
1078   {
1079     if ( !identifiers->FindObject(sid->String().Data()) )
1080     {
1081       identifiers->Add(sid);      
1082     }
1083   }
1084   identifiers->Sort();
1085   return identifiers;
1086 }
1087
1088
1089 ///////////////////////////////////////////////////////////////////////////////
1090 //
1091 // AliHistogramCollectionIterator
1092 //
1093 ///////////////////////////////////////////////////////////////////////////////
1094
1095 class AliHistogramCollectionIterator;
1096
1097 //_____________________________________________________________________________
1098 AliHistogramCollectionIterator::AliHistogramCollectionIterator(const AliHistogramCollection* hcol, Bool_t dir)
1099 : fkHistogramCollection(hcol), fMapIterator(0x0), fHashListIterator(0x0), fDirection(dir)
1100 {
1101   /// Default ctor
1102 }
1103
1104 //_____________________________________________________________________________
1105 AliHistogramCollectionIterator&
1106 AliHistogramCollectionIterator::operator=(const TIterator&)
1107 {
1108   /// Overriden operator= (imposed by Root's declaration of TIterator ?)
1109   Fatal("TIterator::operator=","Not implementeable"); // because there's no clone in TIterator :-(
1110   return *this;
1111 }
1112
1113 //_____________________________________________________________________________
1114 AliHistogramCollectionIterator::~AliHistogramCollectionIterator()
1115 {
1116   /// dtor
1117   Reset();
1118 }
1119
1120 //_____________________________________________________________________________
1121 TObject* AliHistogramCollectionIterator::Next()
1122 {
1123   /// Advance to next object in the collection
1124   
1125   if (!fHashListIterator)
1126   {
1127     if ( !fMapIterator ) 
1128     {
1129       fMapIterator = fkHistogramCollection->fMap->MakeIterator(fDirection);
1130     }
1131     TObjString* key = static_cast<TObjString*>(fMapIterator->Next());
1132     if (!key)
1133     {
1134       // we are done
1135       return 0x0;
1136     }      
1137     THashList* list = static_cast<THashList*>(fkHistogramCollection->Map()->GetValue(key->String().Data()));
1138     if (!list) return 0x0;
1139     fHashListIterator = list->MakeIterator(fDirection);
1140   }
1141
1142   TObject* o = fHashListIterator->Next();
1143   
1144   if (!o) 
1145   {
1146     delete fHashListIterator;
1147     fHashListIterator = 0x0;
1148     return Next();
1149   }
1150   
1151   return o;
1152 }
1153
1154 //_____________________________________________________________________________
1155 void AliHistogramCollectionIterator::Reset()
1156 {
1157   /// Reset the iterator
1158   delete fHashListIterator;
1159   delete fMapIterator;
1160 }