1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
19 /// A (fake) "4D" histogram container.
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.
25 /// More helper functions might be added in the future (e.g. Project, etc...)
27 #include "AliHistogramCollection.h"
30 #include "Riostream.h"
33 #include "THashList.h"
36 #include "TObjArray.h"
37 #include "TObjString.h"
42 ClassImp(AliHistogramCollection)
44 //_____________________________________________________________________________
45 AliHistogramCollection::AliHistogramCollection(const char* name, const char* title)
46 : TNamed(name,title), fMap(0x0), fMustShowEmptyHistogram(kFALSE)
51 //_____________________________________________________________________________
52 AliHistogramCollection::~AliHistogramCollection()
54 /// dtor. Note that the map is owner
55 if ( fMap ) fMap->DeleteAll();
59 //_____________________________________________________________________________
61 AliHistogramCollection::Adopt(const char* key, TH1* histo)
63 /// Adopt a given histogram, and associate it with pair (keyA)
64 return InternalAdopt(Form("/%s/./././",key),histo);
67 //_____________________________________________________________________________
69 AliHistogramCollection::Adopt(const char* keyA, const char* keyB, TH1* histo)
71 /// Adopt a given histogram, and associate it with pair (keyA,keyB)
72 return InternalAdopt(Form("/%s/%s/././",keyA,keyB),histo);
75 //_____________________________________________________________________________
77 AliHistogramCollection::Adopt(const char* keyA, const char* keyB, const char* keyC, TH1* histo)
79 /// Adopt a given histogram, and associate it with pair (keyA,keyB,keyC)
80 return InternalAdopt(Form("/%s/%s/%s/./",keyA,keyB,keyC),histo);
83 //_____________________________________________________________________________
85 AliHistogramCollection::Adopt(const char* keyA, const char* keyB, const char* keyC, const char* keyD, TH1* histo)
87 /// Adopt a given histogram, and associate it with pair (keyA,keyB,keyC,keyD)
88 return InternalAdopt(Form("/%s/%s/%s/%s/",keyA,keyB,keyC,keyD),histo);
91 //_____________________________________________________________________________
93 AliHistogramCollection::CreateIterator(Bool_t direction) const
95 /// Create an iterator (must be deleted by the client)
96 return fMap ? new AliHistogramCollectionIterator(this,direction) : 0x0;
99 //_____________________________________________________________________________
101 AliHistogramCollection::Delete(Option_t*)
103 /// Delete all the histograms
109 //_____________________________________________________________________________
111 AliHistogramCollection::FindObject(const char* identifier) const
113 /// Find an object by its full identifier.
115 return Histo(KeyA(identifier),
119 HistoName(identifier));
122 //_____________________________________________________________________________
124 AliHistogramCollection::FindObject(const TObject *key) const
127 AliWarning("This method is awfully inefficient. Please improve it or use FindObject(const char*)");
128 TIter next(CreateIterator());
130 while ( ( o=next() ) )
132 if ( o->IsEqual(key) ) return o;
137 //_____________________________________________________________________________
139 AliHistogramCollection::Histo(const char* keyA,
140 const char* histoname) const
142 /// Get histo for (keyA,histoname) triplet
144 return InternalHisto(Form("/%s/./././",keyA),histoname);
147 //_____________________________________________________________________________
149 AliHistogramCollection::Histo(const char* keyA, const char* keyB,
150 const char* histoname) const
152 /// Get histo for (keyA,keyB,histoname) triplet
154 return InternalHisto(Form("/%s/%s/././",keyA,keyB),histoname);
157 //_____________________________________________________________________________
159 AliHistogramCollection::Histo(const char* keyA, const char* keyB, const char* keyC,
160 const char* histoname) const
162 /// Get histo for (keyA,keyB,keyC,histoname) quad
164 return InternalHisto(Form("/%s/%s/%s/./",keyA,keyB,keyC),histoname);
167 //_____________________________________________________________________________
169 AliHistogramCollection::Histo(const char* keyA, const char* keyB,
170 const char* keyC, const char* keyD,
171 const char* histoname) const
173 /// Get histo for (keyA,keyB,keyC,histoname) quad
175 return InternalHisto(Form("/%s/%s/%s/%s/",keyA,keyB,keyC,keyD),histoname);
178 //_____________________________________________________________________________
180 AliHistogramCollection::HistoName(const char* identifier) const
182 /// Extract the histogram name from an identifier
184 return InternalDecode(identifier,4);
187 //_____________________________________________________________________________
188 Bool_t AliHistogramCollection::InternalAdopt(const char* identifier, TH1* histo)
190 /// Adopt an histogram
194 Error("Adopt","Cannot adopt a null histogram");
198 THashList* hlist = 0x0;
203 fMap->SetOwner(kTRUE);
206 hlist = static_cast<THashList*>(fMap->GetValue(identifier));
210 hlist = new THashList;
211 hlist->SetOwner(kTRUE);
212 fMap->Add(new TObjString(identifier),hlist);
213 hlist->SetName(identifier);
216 TH1* h = static_cast<TH1*>(hlist->FindObject(histo->GetName()));
220 AliError(Form("Cannot adopt an already existing histogram : %s -> %s",identifier,h->GetName()));
225 histo->SetDirectory(0);
227 hlist->AddLast(histo);
233 //_____________________________________________________________________________
235 AliHistogramCollection::Histo(const char* identifier) const
237 /// Get histogram keyA/keyB/keyC/keyD/histoname
238 return Histo(InternalDecode(identifier,0),
239 InternalDecode(identifier,1),
240 InternalDecode(identifier,2),
241 InternalDecode(identifier,3),
242 InternalDecode(identifier,4));
245 //_____________________________________________________________________________
247 AliHistogramCollection::InternalDecode(const char* identifier, Int_t index) const
249 /// Extract the index-th element of the identifier (/keyA/keyB/keyC/keyD/histoname)
256 if ( identifier[0] != '/' )
258 AliError(Form("identifier %s is malformed.",identifier));
262 TObjArray* array = TString(identifier).Tokenize("/");
264 if ( array->GetLast()>5 )
266 AliError(Form("identifier %s is malformed.",identifier));
273 if ( index <= array->GetLast() )
275 value = static_cast<TObjString*>(array->At(index))->String();
282 // "Custom" implementation below is even slower that Tokenize... ??
283 // or at least did not change the timing result enough to be worthwhile (indicating
284 // the cpu time is wasted elsewhere ?)
286 // Int_t slashPos[6] = {0};
287 // Int_t nslashes(0);
289 // for ( Int_t i = 0; i < identifier.Length(); ++i )
291 // if ( identifier[i] == '/' )
293 // slashPos[nslashes++]=i;
295 // if ( nslashes > 5 )
297 // AliError(Form("identifier %s is malformed.",identifier.Data()));
302 // slashPos[nslashes++]=identifier.Length();
305 // if ( index < nslashes )
307 // return TString(identifier(slashPos[index]+1,slashPos[index+1]-slashPos[index]-1));
312 //_____________________________________________________________________________
314 AliHistogramCollection::InternalHisto(const char* identifier,
315 const char* histoname) const
317 /// Get histo for (identifier,histoname)
324 THashList* hlist = static_cast<THashList*>(fMap->GetValue(identifier));
330 return static_cast<TH1*>(hlist->FindObject(histoname));
334 //_____________________________________________________________________________
336 AliHistogramCollection::KeyA(const char* identifier) const
338 /// Extract the first element of the key pair from an identifier
340 return InternalDecode(identifier,0);
343 //_____________________________________________________________________________
345 AliHistogramCollection::KeyB(const char* identifier) const
347 /// Extract the second element (if present)
348 return InternalDecode(identifier,1);
351 //_____________________________________________________________________________
353 AliHistogramCollection::KeyC(const char* identifier) const
355 /// Extract the 3rd element (if present)
356 return InternalDecode(identifier,2);
359 //_____________________________________________________________________________
361 AliHistogramCollection::KeyD(const char* identifier) const
363 /// Extract the 4th element (if present)
364 return InternalDecode(identifier,3);
367 //_____________________________________________________________________________
369 AliHistogramCollection::Merge(TCollection* list)
371 // Merge a list of AliHistogramCollection objects with this
372 // Returns the number of merged objects (including this).
376 if (list->IsEmpty()) return 1;
383 while ( ( o = next() ) )
385 AliHistogramCollection* hcol = dynamic_cast<AliHistogramCollection*>(o);
387 AliFatal(Form("object named \"%s\" is a %s instead of an AliHistogramCollection!", o->GetName(), o->ClassName()));
393 TIter nextIdentifier(hcol->fMap);
394 TObjString* identifier;
396 while ( ( identifier = static_cast<TObjString*>(nextIdentifier()) ) )
398 THashList* otherList = static_cast<THashList*>(hcol->fMap->GetValue(identifier->String().Data()));
400 TIter nextHisto(otherList);
403 while ( ( h = static_cast<TH1*>(nextHisto()) ) )
405 TH1* thisHisto = Histo(KeyA(identifier->String()).Data(),
406 KeyB(identifier->String()).Data(),
407 KeyC(identifier->String()).Data(),
408 KeyD(identifier->String()).Data(),
413 AliDebug(1,Form("Adopting a new histo = %s/%s",identifier->String().Data(),h->GetName()));
415 // this is an histogram we don't have yet. Let's add it
416 Adopt(KeyA(identifier->String()),
417 KeyB(identifier->String()),
418 KeyC(identifier->String()),
419 KeyD(identifier->String()),
420 static_cast<TH1*>(h->Clone()));
425 AliDebug(1,Form("Merging histo = %s/%s (%g vs %g)",
426 identifier->String().Data(),
428 h->GetSumOfWeights(),
429 thisHisto->GetSumOfWeights()));
433 thisHisto->Merge(&l);
439 AliDebug(1,Form("count=%d",count));
444 //_____________________________________________________________________________
446 AliHistogramCollection::NumberOfHistograms() const
448 /// Get the number of histograms we hold
449 TIter next(CreateIterator(this));
451 while ( next() ) ++n;
455 //_____________________________________________________________________________
457 AliHistogramCollection::NumberOfKeys() const
459 /// Get the number of keys we have
460 return fMap ? fMap->GetSize() : 0;
463 //_____________________________________________________________________________
465 AliHistogramCollection::Print(Option_t* option) const
467 /// Print all the histograms we hold, in a hopefully visually pleasing
470 /// Option can be used to select given part only, using the schema :
472 /// Where the stars are wilcards for /keyA/keyB/keyC/KeyD/histoname
474 /// if * is used it is assumed to be a wildcard for histoname
476 /// For other selections the full syntax /*/*/*/*/* must be used.
478 /// Use "-" as histoname to disable histogram's name output
480 cout << Form("AliHistogramCollection : %d keys and %d histos",
481 NumberOfKeys(), NumberOfHistograms()) << endl;
483 if (!strlen(option)) return;
485 TString sreKeyA("*");
486 TString sreKeyB("*");
487 TString sreKeyC("*");
488 TString sreKeyD("*");
489 TString sreHistoname("*");
491 TObjArray* select = TString(option).Tokenize("/");
492 Int_t n = select->GetLast();
496 sreHistoname = static_cast<TObjString*>(select->At(n))->String();
500 sreKeyD = static_cast<TObjString*>(select->At(n-1))->String();
504 sreKeyC = static_cast<TObjString*>(select->At(n-2))->String();
508 sreKeyB = static_cast<TObjString*>(select->At(n-3))->String();
512 sreKeyA = static_cast<TObjString*>(select->At(n-3))->String();
515 TRegexp reKeyA(sreKeyA,kTRUE);
516 TRegexp reKeyB(sreKeyB,kTRUE);
517 TRegexp reKeyC(sreKeyC,kTRUE);
518 TRegexp reKeyD(sreKeyD,kTRUE);
519 TRegexp reHistoname(sreHistoname,kTRUE);
523 TObjArray* identifiers = SortAllIdentifiers();
525 TIter nextIdentifier(identifiers);
527 TObjString* sid(0x0);
529 while ( ( sid = static_cast<TObjString*>(nextIdentifier()) ) )
531 Bool_t identifierPrinted(kFALSE);
533 TString identifier(sid->String());
535 if ( InternalDecode(identifier,0).Contains(reKeyA) &&
536 InternalDecode(identifier,1).Contains(reKeyB) &&
537 InternalDecode(identifier,2).Contains(reKeyC) &&
538 InternalDecode(identifier,3).Contains(reKeyD)
541 if ( sreHistoname == "*" )
543 identifierPrinted = kTRUE;
544 cout << identifier.Data() << endl;
547 THashList * list = static_cast<THashList*>(fMap->GetValue(sid->String().Data()));
549 names.SetOwner(kTRUE);
550 TIter nextUnsortedHisto(list);
552 while ( ( h = static_cast<TH1*>(nextUnsortedHisto()) ) )
554 names.Add(new TObjString(h->GetName()));
557 TIter nextHistoName(&names);
559 while ( ( hname = static_cast<TObjString*>(nextHistoName()) ) )
561 TString histoName(hname->String());
562 if (histoName.Contains(reHistoname) )
564 h = static_cast<TH1*>(list->FindObject(histoName.Data()));
565 if ( h->GetEntries()==0 && !fMustShowEmptyHistogram ) continue;
566 if (!identifierPrinted)
568 cout << identifier.Data() << endl;
569 identifierPrinted = kTRUE;
571 cout << Form(" %s %s Entries=%d Sum=%g",h->GetName(),h->GetTitle(),Int_t(h->GetEntries()),h->GetSumOfWeights()) << endl;
574 if (!identifierPrinted && sreHistoname=="-" )
576 // to handle the case where we used histoname="-" to disable showing the histonames,
577 // but we still want to see the matching keys maybe...
578 cout << identifier.Data() << endl;
586 //_____________________________________________________________________________
588 AliHistogramCollection::EstimateSize(Bool_t show) const
590 /// Estimate the memory (in kilobytes) used by our histograms
592 // sizeof(TH1) + (nbins+2)*(nbytes_per_bin) +name+title_sizes
593 // if you have errors add (nbins+2)*8
595 TIter next(CreateIterator());
599 while ( ( h = static_cast<TH1*>(next()) ) )
601 Int_t nbins = (h->GetNbinsX()+2);
603 if (h->GetNbinsY()>1)
605 nbins *= (h->GetNbinsY()+2);
608 if (h->GetNbinsZ()>1)
610 nbins *= (h->GetNbinsZ()+2);
613 Bool_t hasErrors = ( h->GetSumw2N() > 0 );
615 TString cname(h->ClassName());
617 Int_t nbytesPerBin(0);
619 if (cname.Contains(TRegexp("C$")) ) nbytesPerBin = sizeof(Char_t);
620 if (cname.Contains(TRegexp("S$")) ) nbytesPerBin = sizeof(Short_t);
621 if (cname.Contains(TRegexp("I$")) ) nbytesPerBin = sizeof(Int_t);
622 if (cname.Contains(TRegexp("F$")) ) nbytesPerBin = sizeof(Float_t);
623 if (cname.Contains(TRegexp("D$")) ) nbytesPerBin = sizeof(Double_t);
627 AliError(Form("Could not get the number of bytes per bin for histo %s of class %s. Thus the size estimate will be wrong !",
628 h->GetName(),h->ClassName()));
632 UInt_t thissize = sizeof(h) + nbins*(nbytesPerBin) + strlen(h->GetName())
633 + strlen(h->GetTitle());
635 if ( hasErrors) thissize += nbins*8;
641 AliInfo(Form("Size of %30s is %20d bytes",h->GetName(),thissize));
648 //_____________________________________________________________________________
649 void AliHistogramCollection::PruneEmptyHistograms()
651 /// Delete the empty histograms
656 toBeRemoved.SetOwner(kTRUE);
658 while ( ( key = static_cast<TObjString*>(next()) ) )
660 TString identifier(key->String());
661 THashList* hlist = static_cast<THashList*>(fMap->GetValue(identifier.Data()));
662 TIter nextHisto(hlist);
664 while ( ( h = static_cast<TH1*>(nextHisto())))
666 if ( h->GetEntries()==0)
668 toBeRemoved.Add(new TObjString(Form("%s%s",identifier.Data(),h->GetName())));
673 TIter nextTBR(&toBeRemoved);
674 while ( ( key = static_cast<TObjString*>(nextTBR()) ) )
680 //_____________________________________________________________________________
681 AliHistogramCollection*
682 AliHistogramCollection::Project(const char* /*keyA*/, const char* /*keyB*/) const
684 /// To be implemented : would create a new collection starting at keyA/keyB
685 AliError("Implement me !");
689 //_____________________________________________________________________________
691 AliHistogramCollection::Remove(TObject* key)
694 /// Remove a given histogram (given its key=full identifier=/keyA/keyB/keyC/keyD/histoname)
696 /// Note that we do *not* remove the /keyA/keyB/keyC/keyD entry even if there's no
697 /// more histogram for this triplet.
699 /// Not very efficient. Could be improved ?
702 TObjString* str = dynamic_cast<TObjString*>(key);
706 AliError(Form("key is not of the expected TObjString type, but of %s",key->ClassName()));
710 TString identifier(str->String());
712 TString skey = Form("/%s/%s/%s/%s/",
713 KeyA(identifier).Data(),
714 KeyB(identifier).Data(),
715 KeyC(identifier).Data(),
716 KeyD(identifier).Data());
718 THashList* hlist = dynamic_cast<THashList*>(fMap->GetValue(skey.Data()));
722 AliWarning(Form("Could not get hlist for key=%s",skey.Data()));
726 TH1* h = InternalHisto(skey,HistoName(identifier.Data()));
729 AliError(Form("Could not find histo %s",identifier.Data()));
733 TObject* o = hlist->Remove(h);
736 AliError("Remove failed");
740 // if ( hlist->IsEmpty() )
742 // // we should remove the key as well
743 // TObject* k = fMap->Remove(key);
746 // AliError("Removal of the key failed");
753 //_____________________________________________________________________________
755 AliHistogramCollection::SortAllIdentifiers() const
757 /// Sort our internal identifiers. Returned array must be deleted.
758 TObjArray* identifiers = new TObjArray;
759 identifiers->SetOwner(kFALSE);
763 while ( ( sid = static_cast<TObjString*>(next()) ) )
765 if ( !identifiers->FindObject(sid->String().Data()) )
767 identifiers->Add(sid);
775 ///////////////////////////////////////////////////////////////////////////////
777 // AliHistogramCollectionIterator
779 ///////////////////////////////////////////////////////////////////////////////
781 class AliHistogramCollectionIterator;
783 //_____________________________________________________________________________
784 AliHistogramCollectionIterator::AliHistogramCollectionIterator(const AliHistogramCollection* hcol, Bool_t dir)
785 : fkHistogramCollection(hcol), fMapIterator(0x0), fHashListIterator(0x0), fDirection(dir)
790 //_____________________________________________________________________________
791 AliHistogramCollectionIterator&
792 AliHistogramCollectionIterator::operator=(const TIterator&)
794 /// Overriden operator= (imposed by Root's declaration of TIterator ?)
795 Fatal("TIterator::operator=","Not implementeable"); // because there's no clone in TIterator :-(
799 //_____________________________________________________________________________
800 AliHistogramCollectionIterator::~AliHistogramCollectionIterator()
806 //_____________________________________________________________________________
807 TObject* AliHistogramCollectionIterator::Next()
809 /// Advance to next object in the collection
811 if (!fHashListIterator)
815 fMapIterator = fkHistogramCollection->fMap->MakeIterator(fDirection);
817 TObjString* key = static_cast<TObjString*>(fMapIterator->Next());
823 THashList* list = static_cast<THashList*>(fkHistogramCollection->fMap->GetValue(key->String().Data()));
824 if (!list) return 0x0;
825 fHashListIterator = list->MakeIterator(fDirection);
828 TObject* o = fHashListIterator->Next();
832 delete fHashListIterator;
833 fHashListIterator = 0x0;
840 //_____________________________________________________________________________
841 void AliHistogramCollectionIterator::Reset()
843 /// Reset the iterator
844 delete fHashListIterator;