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