Standard constructors to easily include muon (track and pair) cuts. Methods to handle...
authormartinez <martinez@f7af4fe6-9843-0410-8265-dc069ae4e863>
Tue, 17 Jan 2012 22:10:28 +0000 (22:10 +0000)
committermartinez <martinez@f7af4fe6-9843-0410-8265-dc069ae4e863>
Tue, 17 Jan 2012 22:10:28 +0000 (22:10 +0000)
PWG3/CMakelibPWG3muon.pkg
PWG3/PWG3muonLinkDef.h
PWG3/muon/AliMergeableCollection.cxx [new file with mode: 0644]
PWG3/muon/AliMergeableCollection.h [new file with mode: 0644]
PWG3/muon/AliVAnalysisMuon.cxx [new file with mode: 0644]
PWG3/muon/AliVAnalysisMuon.h [new file with mode: 0644]

index cd6397c..e57bbf2 100644 (file)
@@ -61,6 +61,8 @@ set ( SRCS
     muon/AliCFMuonResUpsilon.cxx 
     muon/AliMuonTrackCuts.cxx 
     muon/AliMuonPairCuts.cxx 
+    muon/AliMergeableCollection.cxx 
+    muon/AliVAnalysisMuon.cxx 
     )
 
 string ( REPLACE ".cxx" ".h" HDRS "${SRCS}" )
index 59fe71b..02a832e 100644 (file)
@@ -41,5 +41,8 @@
 #pragma link C++ class AliAnalysisMuMuFromESD+;
 #pragma link C++ class AliMuonTrackCuts+;
 #pragma link C++ class AliMuonPairCuts+;
+#pragma link C++ class AliMergeableCollection+;
+#pragma link C++ class AliMergeableCollectionIterator+;
+#pragma link C++ class AliVAnalysisMuon+;
 #endif
 
diff --git a/PWG3/muon/AliMergeableCollection.cxx b/PWG3/muon/AliMergeableCollection.cxx
new file mode 100644 (file)
index 0000000..5f4fdb4
--- /dev/null
@@ -0,0 +1,1087 @@
+/**************************************************************************
+* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+*                                                                        *
+* Author: The ALICE Off-line Project.                                    *
+* Contributors are mentioned in the code where appropriate.              *
+*                                                                        *
+* Permission to use, copy, modify and distribute this software and its   *
+* documentation strictly for non-commercial purposes is hereby granted   *
+* without fee, provided that the above copyright notice appears in all   *
+* copies and that both the copyright notice and this permission notice   *
+* appear in the supporting documentation. The authors make no claims     *
+* about the suitability of this software for any purpose. It is          *
+* provided "as is" without express or implied warranty.                  *
+**************************************************************************/
+
+// $Id: AliMergeableCollection.cxx 50593 2011-07-14 17:42:28Z martinez $
+
+///
+/// A mergeable object container. 
+///
+/// For each tuple (key1,key2,..,keyN) a (hash)list of mergeable objects is associated.
+/// Note that key1, key2 (optional), ..., keyN (optional) are strings. 
+/// Those strings should not contain "/" themselves.
+///
+/// More helper functions might be added in the future (e.g. Project, etc...)
+
+#include "AliMergeableCollection.h"
+
+ClassImp(AliMergeableCollection)
+
+#include "AliLog.h"
+#include "Riostream.h"
+#include "TError.h"
+#include "THashList.h"
+#include "TKey.h"
+#include "TMap.h"
+#include "TObjArray.h"
+#include "TObjString.h"
+#include "TRegexp.h"
+#include "TROOT.h"
+#include "TSystem.h"
+#include "TH1.h"
+//#include "TH2.h"
+
+//_____________________________________________________________________________
+AliMergeableCollection::AliMergeableCollection(const char* name, const char* title) 
+: TNamed(name,title), fMap(0x0), fMustShowEmptyObject(0), fMapVersion(0), fMessages()
+{
+  /// Ctor
+}
+
+//_____________________________________________________________________________
+AliMergeableCollection::~AliMergeableCollection()
+{
+  /// dtor. Note that the map is owner
+  if ( fMap ) fMap->DeleteAll();
+  delete fMap;
+}
+
+//_____________________________________________________________________________
+Bool_t 
+AliMergeableCollection::Adopt(TObject* obj)
+{
+  /// Adopt a given object at top level (i.e. no key)
+  return InternalAdopt("",obj);
+}
+
+//_____________________________________________________________________________
+Bool_t 
+AliMergeableCollection::Adopt(const char* identifier, TObject* obj)
+{
+  /// Adopt a given object, and associate it with pair key
+  TString sidentifier(identifier);
+  if ( ! sidentifier.IsNull() ){
+    if ( ! sidentifier.EndsWith("/") ) sidentifier.Append("/");
+    if ( ! sidentifier.BeginsWith("/") ) sidentifier.Prepend("/");
+  }
+  return InternalAdopt(sidentifier.Data(),obj);
+}
+
+//_____________________________________________________________________________
+void AliMergeableCollection::ClearMessages()
+{
+  /// clear pending messages
+  fMessages.clear();
+}
+
+//_____________________________________________________________________________
+TIterator*
+AliMergeableCollection::CreateIterator(Bool_t direction) const
+{
+  /// Create an iterator (must be deleted by the client)
+  return fMap ? new AliMergeableCollectionIterator(this,direction) : 0x0;
+}
+
+//_____________________________________________________________________________
+AliMergeableCollection*
+AliMergeableCollection::Clone(const char* name) const
+{
+  /// Clone this collection.
+  /// We loose the messages.
+  
+  AliMergeableCollection* newone = new AliMergeableCollection(name,GetTitle());
+  
+  newone->fMap = static_cast<TMap*>(fMap->Clone());
+  newone->fMustShowEmptyObject = fMustShowEmptyObject;
+  newone->fMapVersion = fMapVersion;  
+  
+  return newone;
+}
+
+//_____________________________________________________________________________
+void 
+AliMergeableCollection::Delete(Option_t*)
+{
+  /// Delete all the objects
+  fMap->DeleteAll();
+  delete fMap;
+  fMap=0x0;
+}
+
+//_____________________________________________________________________________
+TObject* 
+AliMergeableCollection::FindObject(const char* fullIdentifier) const
+{
+  /// Find an object by its full identifier.
+  
+  return GetObject(fullIdentifier);
+}
+
+//_____________________________________________________________________________
+TObject* 
+AliMergeableCollection::FindObject(const TObject *object) const
+{
+  /// Find an object 
+  AliWarning("This method is awfully inefficient. Please improve it or use FindObject(const char*)");
+  TIter next(CreateIterator());
+  TObject* obj;
+  while ( ( obj=next() ) )
+  {
+    if ( obj->IsEqual(object) ) return obj;
+  }
+  return 0x0;
+}
+
+
+//_____________________________________________________________________________
+TList*
+AliMergeableCollection::CreateListOfKeys(Int_t index) const
+{
+  /// Create the list of keys at level index
+  
+  TList* list = new TList;
+  list->SetOwner(kTRUE);
+  
+  TObjArray* ids = SortAllIdentifiers();
+  TIter next(ids);
+  TObjString* str;
+  
+  while ( ( str = static_cast<TObjString*>(next()) ) )
+  {
+    TString oneid = GetKey(str->String().Data(),index,kFALSE);
+    if (oneid.Length()>0 && !list->Contains(oneid))
+    {
+      list->Add(new TObjString(oneid));
+    }
+  }
+  
+  delete ids;
+  return list;
+}
+
+//_____________________________________________________________________________
+TList* 
+AliMergeableCollection::CreateListOfObjectNames(const char* identifier) const
+{
+  /// Create list of object names for /key1/key2/key...
+  /// Returned list must be deleted by client
+  
+  TList* listOfNames = new TList;
+  listOfNames->SetOwner(kTRUE);
+  
+  TIter next(Map());
+  TObjString* str;
+  
+  while ( ( str = static_cast<TObjString*>(next()) ) )
+  {
+    TString currIdentifier = str->String();
+    if ( currIdentifier.CompareTo(identifier) ) continue;
+    
+    THashList* list = static_cast<THashList*>(Map()->GetValue(identifier));
+    
+    TIter nextObject(list);
+    TObject* obj;
+    
+    while ( ( obj = nextObject() ) )
+    {
+      listOfNames->Add(new TObjString(obj->GetName()));
+    }    
+  }
+  
+  return listOfNames;
+}
+
+
+//_____________________________________________________________________________
+TString
+AliMergeableCollection::GetIdentifier(const char* fullIdentifier) const
+{
+  /// Extract the identifier from the fullIdentifier
+  TString sfullIdentifier(fullIdentifier);
+  TObjArray* arr = sfullIdentifier.Tokenize("/");
+  TString identifier = "";
+  for ( Int_t istr=0; istr<arr->GetLast(); istr++ ) {
+    identifier += "/" + GetKey(fullIdentifier, istr, kTRUE);
+  }
+  delete arr;
+  identifier.Append("/");
+  return identifier;
+}
+
+//_____________________________________________________________________________
+TString
+AliMergeableCollection::GetKey(const char* identifier, Int_t index, Bool_t idContainsObjName) const
+{
+  /// Extract the index element of the key pair from the fullIdentifier
+  TString sidentifier(identifier);
+  if ( ! idContainsObjName ) sidentifier.Append("/dummy");
+  return InternalDecode(sidentifier.Data(),index);
+}
+
+//_____________________________________________________________________________
+TString
+AliMergeableCollection::GetObjectName(const char* fullIdentifier) const
+{
+  /// Extract the object name from an identifier
+  
+  return InternalDecode(fullIdentifier,-1);  
+}
+
+
+//_____________________________________________________________________________
+TObject* 
+AliMergeableCollection::GetObject(const char* fullIdentifier) const
+{
+  /// Get object key1/key2/.../objectName:action
+  
+  TObjArray* arr = TString(fullIdentifier).Tokenize(":");
+  
+  TString fullIdWithoutAction(static_cast<TObjString*>(arr->At(0))->String());
+  TString action;
+  
+  if ( arr->GetLast() > 0 ) 
+  {
+    action = static_cast<TObjString*>(arr->At(1))->String();
+    action.ToUpper();
+  }
+  
+  delete arr;
+  
+  return GetObject(GetIdentifier(fullIdWithoutAction).Data(), GetObjectName(fullIdWithoutAction));
+  
+  
+  //  if (obj)
+  //  {
+  //    TH2* h2(0x0);
+  //    
+  //    if ( action == "PX" && ( (h2 = dynamic_cast<TH2*>(obj)) ) ) 
+  //    {
+  //      return h2->ProjectionX(NormalizeName(identifier.Data(),action.Data()).Data());
+  //    }
+  //    else if ( action == "PY" && ( (h2 = dynamic_cast<TH2*>(obj)) ) ) 
+  //    {
+  //      return h2->ProjectionY(NormalizeName(identifier.Data(),action.Data()).Data());
+  //    }
+  //    else if ( action == "PFX" && ( (h2 = dynamic_cast<TH2*>(obj)) ) ) 
+  //    {
+  //      return h2->ProfileX(NormalizeName(identifier.Data(),action.Data()).Data());
+  //    }
+  //    else if ( action == "PFY" && ( (h2 = dynamic_cast<TH2*>(obj)) ) ) 
+  //    {
+  //      return h2->ProfileY(NormalizeName(identifier.Data(),action.Data()).Data());
+  //    }
+  //    
+  //  }
+  //  else
+  //  {
+  //    AliDebug(1,Form("Object %s not found",sidentifier));
+  //  }
+  //  return obj;
+}
+
+
+//_____________________________________________________________________________
+TObject* 
+AliMergeableCollection::GetObject(const char* identifier, 
+                                  const char* objectName) const
+{
+  /// Get object for (identifier,objectName) triplet
+  
+  TString sidentifier(identifier);
+  if ( ! sidentifier.IsNull() ) {
+    if ( ! sidentifier.BeginsWith("/") ) sidentifier.Prepend("/");
+    if ( ! sidentifier.EndsWith("/") ) sidentifier.Append("/");
+  }
+  return InternalObject(sidentifier.Data(),objectName);
+}
+
+//_____________________________________________________________________________
+TObject* AliMergeableCollection::GetSum(const char* idPattern)
+{
+  /// Sum objects
+  /// The pattern must be in the form:
+  /// /key1_pattern1 key1_pattern2,key1_pattern,.../key2_pattern1,key2_pattern,.../.../objectName_pattern1,objectName_pattern...
+  /// The logical or between patterns separated by commas is taken
+  
+  TObject* sumObject = 0x0;
+  
+  // Build array of lists of pattern
+  TString idPatternString(idPattern);
+  TObjArray* keyList = idPatternString.Tokenize("/");
+  TObjArray keyMatrix(keyList->GetEntries());
+  keyMatrix.SetOwner();
+  for ( Int_t ikey=0; ikey<keyList->GetEntries(); ikey++ ) {
+    TObjArray* subKeyList = ((TObjString*)keyList->At(ikey))->GetString().Tokenize(",");
+    keyMatrix.AddAt(subKeyList, ikey);
+  }
+  delete keyList;
+  
+  TString debugMsg = "Adding objects:";
+  
+  TIter next(Map());
+  TObjString* str;
+  while ( ( str = static_cast<TObjString*>(next()) ) )
+  {
+    TString identifier = str->String();
+    
+    Bool_t listMatchPattern = kTRUE;
+    for ( Int_t ikey=0; ikey<keyMatrix.GetEntries()-1; ikey++ ) {
+      TString currKey = GetKey(identifier, ikey, kFALSE);
+      Bool_t matchKey = kFALSE;
+      TObjArray* subKeyList = static_cast<TObjArray*> ( keyMatrix.At(ikey) );
+      for ( Int_t isub=0; isub<subKeyList->GetEntries(); isub++ ) {
+        TString subKeyString = static_cast<TObjString*> (subKeyList->At(isub))->GetString();
+        if ( currKey.Contains(subKeyString.Data()) ) {
+          matchKey = kTRUE;
+          break;
+        }
+      } // loop on the list of patterns of each key
+      if ( ! matchKey ) {
+        listMatchPattern = kFALSE;
+        break;
+      }
+    } // loop on keys in the idPattern
+    if ( ! listMatchPattern ) continue;
+    
+    THashList* list = static_cast<THashList*>(Map()->GetValue(identifier.Data()));
+    
+    TIter nextObj(list);
+    TObject* obj;
+    
+    while ( ( obj = nextObj()) )
+    {
+      TString currKey = obj->GetName();
+      Bool_t matchKey = kFALSE;
+      TObjArray* subKeyList = static_cast<TObjArray*> ( keyMatrix.Last() );
+      for ( Int_t isub=0; isub<subKeyList->GetEntries(); isub++ ) {
+        TString subKeyString = static_cast<TObjString*> (subKeyList->At(isub))->GetString();
+        if ( currKey.Contains(subKeyString.Data()) ) {
+          matchKey = kTRUE;
+          break;
+        }
+      }
+      if ( ! matchKey ) continue;
+      if ( ! sumObject ) sumObject = obj->Clone();
+      else MergeObject(sumObject, obj);
+      debugMsg += Form(" %s%s",identifier.Data(),obj->GetName());
+    } // loop on objects in list
+  } // loop on identifiers in map
+  
+  AliDebug(1,debugMsg.Data());
+  
+  return sumObject;
+}
+
+//_____________________________________________________________________________
+Bool_t AliMergeableCollection::InternalAdopt(const char* identifier, TObject* obj)
+{
+  /// Adopt an obj
+  
+  if (!obj)
+  {
+    Error("Adopt","Cannot adopt a null object");
+    return kFALSE;
+  }
+  
+  if ( ! obj->IsA()->InheritsFrom(TObject::Class()) ||
+        ! obj->IsA()->GetMethodWithPrototype("Merge", "TCollection*") ) {
+    Error("Adopt","Cannot adopt an object which is not mergeable!"); 
+  }
+  
+  THashList* hlist = 0x0;
+  
+  hlist = static_cast<THashList*>(Map()->GetValue(identifier));
+  
+  if (!hlist)
+  {
+    hlist = new THashList;
+    hlist->SetOwner(kTRUE);
+    Map()->Add(new TObjString(identifier),hlist);
+    hlist->SetName(identifier);
+  }
+  
+  TObject* existingObj = hlist->FindObject(obj->GetName());
+  
+  if (existingObj)
+  {
+    AliError(Form("Cannot adopt an already existing object : %s -> %s",identifier,existingObj->GetName()));
+    return kFALSE;
+  }
+  
+  if ( obj->IsA()->InheritsFrom(TH1::Class()) ) (static_cast<TH1*> ( obj ))->SetDirectory(0);  
+  
+  hlist->AddLast(obj);
+  
+  return kTRUE;
+  
+}
+
+//_____________________________________________________________________________
+TString
+AliMergeableCollection::InternalDecode(const char* identifier, Int_t index) const
+{
+  /// Extract the index-th element of the identifier (/key1/key2/.../keyN/objectName)
+  /// object is index=-1 (i.e. last)
+  
+  if ( strlen(identifier) > 0 && identifier[0] != '/' ) 
+  {    
+    AliError(Form("identifier %s is malformed (should start with /)",identifier));
+    return "";
+  }
+  
+  TObjArray* array = TString(identifier).Tokenize("/");
+
+  if ( index >= array->GetLast() ) 
+  {
+    AliError(Form("Requiring index %i of identifier %s which only have %i",index, identifier, array->GetLast()));
+    delete array;
+    return "";
+  }
+
+  TString value("");
+  
+  if ( index < 0 ) 
+  {
+    value = static_cast<TObjString*>(array->Last())->String();    
+  }
+  else if ( index <= array->GetLast() ) 
+  {
+    value = static_cast<TObjString*>(array->At(index))->String();
+  }
+  
+  delete array;
+  
+  return value;
+}
+
+//_____________________________________________________________________________
+TObject* 
+AliMergeableCollection::InternalObject(const char* identifier,
+                                       const char* objectName) const
+{
+  /// Get object for (identifier,objectName) 
+  
+  if (!fMap) 
+  {
+    return 0x0;
+  }
+  
+  THashList* hlist = static_cast<THashList*>(Map()->GetValue(identifier));
+  if (!hlist) 
+  {
+    TString msg(Form("Did not find hashlist for identifier=%s dir=%s",identifier,gDirectory ? gDirectory->GetName() : "" ));
+    fMessages[msg.Data()]++;
+    return 0x0;
+  }
+  
+  TObject* obj = hlist->FindObject(objectName);
+  if (!obj)
+  {
+    TString msg(Form("Did not find objectName=%s in %s",objectName,identifier));
+    fMessages[msg.Data()]++;
+  }
+  return obj;
+}
+
+
+//_____________________________________________________________________________
+Bool_t AliMergeableCollection::IsEmptyObject(TObject* obj) const
+{
+  /// Check if object is empty
+  /// (done only for TH1, so far)
+    
+  if ( obj->IsA()->InheritsFrom(TH1::Class()) ) {
+    TH1* histo = static_cast<TH1*> (obj);
+    if ( histo->GetEntries() == 0 ) return kTRUE;
+  }
+
+  return kFALSE;
+
+}
+
+
+//_____________________________________________________________________________
+TMap* AliMergeableCollection::Map() const
+{
+  /// Wrapper to insure proper key formats (i.e. new vs old)
+  
+  if (!fMap)
+  {
+    fMap = new TMap;
+    fMap->SetOwnerKeyValue(kTRUE,kTRUE);
+    fMapVersion = 1;
+  }
+  else
+  {
+    if ( fMapVersion < 1 ) 
+    {
+      AliInfo("Remapping");
+      // change the keys
+      TIter next(fMap);
+      TObjString* str;
+      
+      while ( ( str = static_cast<TObjString*>(next()) ) )
+      {
+        if ( str->String().Contains("./") )
+        {
+          TString newkey(str->String());
+          
+          newkey.ReplaceAll("./","");
+          
+          TObject* o = fMap->GetValue(str);
+          
+          TPair* p = fMap->RemoveEntry(str);
+          if (!p)
+          {
+            AliError("oups oups oups");
+            return 0x0;
+          }
+          
+          fMap->Add(new TObjString(newkey.Data()),o);
+          
+          delete p;
+        }
+      }
+      
+      fMapVersion = 1;
+    }
+  }
+  
+  return fMap;
+}
+
+//_____________________________________________________________________________
+Long64_t
+AliMergeableCollection::Merge(TCollection* list)
+{
+  // Merge a list of AliMergeableCollection objects with this
+  // Returns the number of merged objects (including this).
+  
+  if (!list) return 0;
+  
+  if (list->IsEmpty()) return 1;
+  
+  TIter next(list);
+  TObject* currObj;
+  TList mapList;
+  Int_t count(0);
+  
+  while ( ( currObj = next() ) )
+  {
+    AliMergeableCollection* mergeCol = dynamic_cast<AliMergeableCollection*>(currObj);
+    if (!mergeCol) {
+      AliFatal(Form("object named \"%s\" is a %s instead of an AliMergeableCollection!", currObj->GetName(), currObj->ClassName()));
+      continue;
+    }
+    
+    ++count;
+    
+    if ( mergeCol->fMap ) mergeCol->Map(); // to insure keys in the new format
+    
+    TIter nextIdentifier(mergeCol->fMap);
+    TObjString* identifier;
+
+    while ( ( identifier = static_cast<TObjString*>(nextIdentifier()) ) )
+    {
+      THashList* otherList = static_cast<THashList*>(mergeCol->fMap->GetValue(identifier->String().Data()));
+
+      TIter nextObject(otherList);
+      TObject* obj;
+      
+      while ( ( obj = nextObject() ) )
+      {
+        TString newid(Form("%s%s",identifier->String().Data(),obj->GetName()));
+        
+        TObject* thisObject = GetObject(newid.Data());
+        
+        if (!thisObject)
+        {
+          AliDebug(1,Form("Adopting a new object = %s%s",identifier->String().Data(),obj->GetName()));
+          
+          Bool_t ok = Adopt(identifier->String(), obj->Clone());
+          
+          if (!ok)
+          {
+            AliError(Form("Adoption of object %s failed",obj->GetName()));
+          }
+        }
+        else
+        {
+          // add it...
+          AliDebug(1,Form("Merging object = %s%s",
+                          identifier->String().Data(),
+                          obj->GetName()));
+          
+          MergeObject(thisObject, obj);
+        }
+      } // loop on objects in map
+    } // loop on identifiers
+  } // loop on collections in list
+         
+  AliDebug(1,Form("count=%d",count));
+  
+  return count+1;
+}
+
+//_____________________________________________________________________________
+Bool_t AliMergeableCollection::MergeObject(TObject* baseObject, TObject* objToAdd)
+{
+  /// Add objToAdd to baseObject
+  
+  if ( baseObject->IsA()->Class() != objToAdd->IsA()->Class() ) {
+    printf("MergeObject: Cannot add %s to %s", objToAdd->ClassName(), baseObject->ClassName());
+    return kFALSE;
+  }
+  if ( ! baseObject->IsA()->InheritsFrom(TObject::Class()) ||
+      ! baseObject->IsA()->GetMethodWithPrototype("Merge", "TCollection*") ) {
+    printf("MergeObject: Objects are not mergeable!");
+    return kFALSE;
+  }  
+  
+  TList list;
+  list.Add(objToAdd);
+  
+  TString listArgs = Form("((TCollection*)0x%lx)", (ULong_t)&list);
+  Int_t error = 0;
+  baseObject->Execute("Merge", listArgs.Data(), &error);
+  return kTRUE;
+}
+
+//_____________________________________________________________________________
+TString AliMergeableCollection::NormalizeName(const char* identifier,const char* action) const
+{
+  /// Replace / by _ to build a root-compliant histo name
+  TString name(GetName());
+  
+  name += "_";
+  name += identifier;
+  name += "_";
+  name += action;
+  name.ReplaceAll("/","_");
+  name.ReplaceAll("-","_");
+  return name;
+}
+
+//_____________________________________________________________________________
+Int_t 
+AliMergeableCollection::NumberOfObjects() const
+{
+  /// Get the number of objects we hold
+  TIter next(CreateIterator(this));
+  Int_t count(0);
+  while ( next() ) ++count;
+  return count;
+}
+
+//_____________________________________________________________________________
+Int_t 
+AliMergeableCollection::NumberOfKeys() const
+{
+  /// Get the number of keys we have
+  return fMap ? fMap->GetSize() : 0;
+}
+
+//_____________________________________________________________________________
+void 
+AliMergeableCollection::Print(Option_t* option) const
+{
+  /// Print all the objects we hold, in a hopefully visually pleasing
+  /// way.
+  ///
+  /// Option can be used to select given part only, using the schema :
+  /// /*/*/*/*/*
+  /// Where the stars are wilcards for /key1/key2/.../objectName
+  ///
+  /// if * is used it is assumed to be a wildcard for objectName
+  ///
+  /// For other selections the full syntax /*/*/*/*/* must be used.
+  /// 
+  /// Use "-" as objectName to disable object's name output
+  
+  cout << Form("AliMergeableCollection(%s,%s) : %d keys and %d objects",
+               GetName(),GetTitle(),
+               NumberOfKeys(), NumberOfObjects()) << endl;
+  
+  if (!strlen(option)) return;
+    
+  TObjArray* select = TString(option).Tokenize("/");
+  
+  TString sreObjectName(select->Last()->GetName());
+  TRegexp reObjectName(sreObjectName.Data(),kTRUE);
+  
+  TObjArray* identifiers = SortAllIdentifiers();
+  
+  printf("identifiers entries %i\n", identifiers->GetEntries());
+    
+  TIter nextIdentifier(identifiers);
+  
+  TObjString* sid(0x0);
+  
+  while ( ( sid = static_cast<TObjString*>(nextIdentifier()) ) )
+  {
+    Bool_t identifierPrinted(kFALSE);
+
+    TString identifier(sid->String());
+    
+    Bool_t matchPattern = kTRUE;
+    for ( Int_t isel=0; isel<select->GetLast(); isel++ ) {
+      if ( ! GetKey(identifier.Data(), isel, kFALSE).Contains(TRegexp(select->At(isel)->GetName(),kTRUE)) ) {
+        matchPattern = kFALSE;
+        break;
+      }
+    }
+    if ( ! matchPattern ) continue;
+    
+    if ( sreObjectName == "*" ) {
+      identifierPrinted = kTRUE;
+      cout << identifier.Data() << endl;
+    }
+      
+    THashList * list = static_cast<THashList*>(Map()->GetValue(sid->String().Data()));      
+    TObjArray names;
+    names.SetOwner(kTRUE);
+    TIter nextUnsortedObj(list);
+    TObject* obj;
+    while ( ( obj = nextUnsortedObj() ) )
+    {
+      names.Add(new TObjString(obj->GetName()));
+    }
+    names.Sort();
+    TIter nextObjName(&names);
+    TObjString* oname;
+    while ( ( oname = static_cast<TObjString*>(nextObjName()) ) )
+    {
+      TString objName(oname->String());
+      if (objName.Contains(reObjectName) )
+      {
+        obj = list->FindObject(objName.Data());
+        if ( IsEmptyObject(obj) && ! fMustShowEmptyObject ) continue;
+        if (!identifierPrinted)
+        {
+          cout << identifier.Data() << endl;
+          identifierPrinted = kTRUE;
+        }
+        cout << Form("    (%s) %s", obj->ClassName(), obj->GetName());
+        if ( obj->IsA()->InheritsFrom(TH1::Class()) ) {
+          TH1* histo = static_cast<TH1*> (obj);
+          cout << Form(" %s Entries=%d Sum=%g",histo->GetTitle(),Int_t(histo->GetEntries()),histo->GetSumOfWeights());
+        }
+        cout << endl;
+      }
+    }
+    if (!identifierPrinted && sreObjectName=="-" )
+    { 
+      // to handle the case where we used objectName="-" to disable showing the objectNames,
+      // but we still want to see the matching keys maybe...
+      cout << identifier.Data() << endl;
+    }
+  }
+  
+  delete select;
+  
+  delete identifiers;
+}
+
+//_____________________________________________________________________________
+void 
+AliMergeableCollection::PrintMessages(const char* prefix) const
+{
+  /// Print pending messages
+  
+  std::map<std::string,int>::const_iterator it;
+  
+  for ( it = fMessages.begin(); it != fMessages.end(); ++it ) 
+  {
+    cout << Form("%s : message %s appeared %5d times",prefix,it->first.c_str(),it->second) << endl;
+  }
+}
+
+
+//_____________________________________________________________________________
+UInt_t 
+AliMergeableCollection::EstimateSize(Bool_t show) const
+{
+  /// Estimate the memory (in kilobytes) used by some objects
+
+//  For TH1:
+//  sizeof(TH1) + (nbins+2)*(nbytes_per_bin) +name+title_sizes 
+//  if you have errors add (nbins+2)*8 
+    
+  TIter next(CreateIterator());
+  
+  TObject* obj;
+  UInt_t size(0);
+  
+  while ( ( obj = next() ) )
+  {
+    UInt_t thissize=0;
+    if ( obj->IsA()->InheritsFrom(TH1::Class()) ) {
+      TH1* histo = static_cast<TH1*> (obj);
+      Int_t nbins = (histo->GetNbinsX()+2);
+    
+      if (histo->GetNbinsY()>1)
+      {
+        nbins *= (histo->GetNbinsY()+2);
+      }
+    
+      if (histo->GetNbinsZ()>1)
+      {
+        nbins *= (histo->GetNbinsZ()+2);
+      }
+      
+      Bool_t hasErrors = ( histo->GetSumw2N() > 0 );
+    
+      TString cname(histo->ClassName());
+    
+      Int_t nbytesPerBin(0);
+    
+      if (cname.Contains(TRegexp("C$")) ) nbytesPerBin = sizeof(Char_t);
+      if (cname.Contains(TRegexp("S$")) ) nbytesPerBin = sizeof(Short_t);
+      if (cname.Contains(TRegexp("I$")) ) nbytesPerBin = sizeof(Int_t);
+      if (cname.Contains(TRegexp("F$")) ) nbytesPerBin = sizeof(Float_t);
+      if (cname.Contains(TRegexp("D$")) ) nbytesPerBin = sizeof(Double_t);
+        
+      if (!nbytesPerBin)
+      {
+        AliError(Form("Could not get the number of bytes per bin for histo %s of class %s. Thus the size estimate will be wrong !",
+                      histo->GetName(),histo->ClassName()));
+        continue;
+      }
+    
+      thissize = sizeof(histo) + nbins*(nbytesPerBin) + strlen(histo->GetName())
+      + strlen(histo->GetTitle());
+      
+      if ( hasErrors) thissize += nbins*8;
+    }
+    else {
+      AliWarning(Form("Cannot estimate size of %s\n", obj->ClassName()));
+      continue;
+    }
+
+    size += thissize;
+    
+    if ( show ) 
+    {
+      AliInfo(Form("Size of %30s is %20d bytes",obj->GetName(),thissize));
+    }
+  } // loop on objects
+
+  return size;
+}
+
+//_____________________________________________________________________________
+void AliMergeableCollection::PruneEmptyObjects()
+{
+  /// Delete the empty objects
+  /// (Implemented for TH1 only)
+  TIter next(Map());
+  TObjString* key;
+  
+  TList toBeRemoved;
+  toBeRemoved.SetOwner(kTRUE);
+  
+  while ( ( key = static_cast<TObjString*>(next()) ) )
+  {
+    TString identifier(key->String());
+    THashList* hlist = static_cast<THashList*>(Map()->GetValue(identifier.Data()));
+    TIter nextObject(hlist);
+    TObject* obj;
+    while ( ( obj = nextObject() ) )
+    {
+      if ( IsEmptyObject(obj) ) toBeRemoved.Add(new TObjString(Form("%s%s",identifier.Data(),obj->GetName())));
+    }
+  }
+  
+  TIter nextTBR(&toBeRemoved);
+  while ( ( key = static_cast<TObjString*>(nextTBR()) ) )
+  {
+    Remove(key->GetString().Data());
+    AliDebug(2,Form("Removing %s", key->GetString().Data()));
+  }
+}
+
+//_____________________________________________________________________________
+AliMergeableCollection* 
+AliMergeableCollection::Project(const char* identifier) const
+{
+  /// To be implemented : would create a new collection starting at /key1/key2/...
+  
+  if (!fMap) return 0x0;
+  
+  AliMergeableCollection* mergCol = new AliMergeableCollection(Form("%s %s",GetName(),identifier),
+                                                               GetTitle());
+  
+  TIter next(Map());
+  TObjString* str;
+  
+  while ( ( str = static_cast<TObjString*>(next()) ) )
+  {
+    TString currIdentifier = str->String();
+    if ( ! currIdentifier.Contains(identifier) ) continue;
+    
+    THashList* list = static_cast<THashList*>(Map()->GetValue(identifier));
+    
+    TIter nextObj(list);
+    TObject* obj;
+    
+    while ( ( obj = nextObj()) )
+    {
+      TObject* clone = obj->Clone();
+
+      TString newkey(currIdentifier.Data());
+      newkey.ReplaceAll(identifier,"");
+
+      if (newkey=="/") newkey="";
+      
+      mergCol->InternalAdopt(newkey.Data(),clone);
+    }    
+  }
+
+  return mergCol;
+}
+
+//_____________________________________________________________________________
+TObject* 
+AliMergeableCollection::Remove(const char* fullIdentifier)
+{
+  ///
+  /// Remove a given object (given its fullIdentifier=/key1/key2/.../objectName)
+  ///
+  /// Note that we do *not* remove the /key1/key2/... entry even if there's no
+  /// more object for this triplet.
+  ///
+  /// Not very efficient. Could be improved ?
+  ///
+  
+  TString identifier = GetIdentifier(fullIdentifier);
+  
+  THashList* hlist = dynamic_cast<THashList*>(Map()->GetValue(identifier.Data()));
+  
+  if (!hlist)
+  {
+    AliWarning(Form("Could not get hlist for key=%s",identifier.Data()));
+    return 0x0;
+  }
+    
+  TObject* obj = GetObject(fullIdentifier);
+  if (!obj)
+  {
+    AliError(Form("Could not find object %s",fullIdentifier));
+    return 0x0;
+  }
+  
+  TObject* rmObj = hlist->Remove(obj);
+  if (!rmObj)
+  {
+    AliError("Remove failed");
+    return 0x0;
+  }
+  
+  return rmObj;
+}
+
+//_____________________________________________________________________________
+TObjArray*
+AliMergeableCollection::SortAllIdentifiers() const
+{
+  /// Sort our internal identifiers. Returned array must be deleted.
+  TObjArray* identifiers = new TObjArray;
+  identifiers->SetOwner(kFALSE); 
+  TIter next(Map());
+  TObjString* sid;
+  
+  while ( ( sid = static_cast<TObjString*>(next()) ) )
+  {
+    if ( !identifiers->FindObject(sid->String().Data()) )
+    {
+      identifiers->Add(sid);      
+    }
+  }
+  identifiers->Sort();
+  return identifiers;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// AliMergeableCollectionIterator
+//
+///////////////////////////////////////////////////////////////////////////////
+
+class AliMergeableCollectionIterator;
+
+//_____________________________________________________________________________
+AliMergeableCollectionIterator::AliMergeableCollectionIterator(const AliMergeableCollection* mcol, Bool_t dir)
+: fkMergeableCollection(mcol), fMapIterator(0x0), fHashListIterator(0x0), fDirection(dir)
+{
+  /// Default ctor
+}
+
+//_____________________________________________________________________________
+AliMergeableCollectionIterator&
+AliMergeableCollectionIterator::operator=(const TIterator&)
+{
+  /// Overriden operator= (imposed by Root's declaration of TIterator ?)
+  Fatal("TIterator::operator=","Not implementeable"); // because there's no clone in TIterator :-(
+  return *this;
+}
+
+//_____________________________________________________________________________
+AliMergeableCollectionIterator::~AliMergeableCollectionIterator()
+{
+  /// dtor
+  Reset();
+}
+
+//_____________________________________________________________________________
+TObject* AliMergeableCollectionIterator::Next()
+{
+  /// Advance to next object in the collection
+  
+  if (!fHashListIterator)
+  {
+    if ( !fMapIterator ) 
+    {
+      fMapIterator = fkMergeableCollection->fMap->MakeIterator(fDirection);
+    }
+    TObjString* key = static_cast<TObjString*>(fMapIterator->Next());
+    if (!key)
+    {
+      // we are done
+      return 0x0;
+    }      
+    THashList* list = static_cast<THashList*>(fkMergeableCollection->Map()->GetValue(key->String().Data()));
+    if (!list) return 0x0;
+    fHashListIterator = list->MakeIterator(fDirection);
+  }
+
+  TObject* obj = fHashListIterator->Next();
+  
+  if (!obj) 
+  {
+    delete fHashListIterator;
+    fHashListIterator = 0x0;
+    return Next();
+  }
+  
+  return obj;
+}
+
+//_____________________________________________________________________________
+void AliMergeableCollectionIterator::Reset()
+{
+  /// Reset the iterator
+  delete fHashListIterator;
+  delete fMapIterator;
+}
diff --git a/PWG3/muon/AliMergeableCollection.h b/PWG3/muon/AliMergeableCollection.h
new file mode 100644 (file)
index 0000000..0c38d74
--- /dev/null
@@ -0,0 +1,158 @@
+#ifndef ALIMERGEABLECOLLECTION_H
+#define ALIMERGEABLECOLLECTION_H
+
+/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+* See cxx source for full Copyright notice                               */
+
+// $Id: AliMergeableCollection.h 50593 2011-07-14 17:42:28Z martinez $
+
+///////////////////////////////////////////////////////////////////////////////
+///
+/// AliMergeableCollection
+///
+/// Collection of mergeable objects, indexed by key-tuples
+///
+/// Important point is that AliMergeableCollection is *always* the
+/// owner of the objects it holds. This is why you should not
+/// use the (inherited from TCollection) Add() method but the Adopt() methods
+///
+/// \author Diego Stocco
+
+#ifndef ROOT_TNamed
+#  include "TNamed.h"
+#endif
+#ifndef ROOT_TString
+#  include "TString.h"
+#endif
+#ifndef ROOT_TCollection
+#  include "TCollection.h"
+#endif
+#include "Riostream.h"
+#include <map>
+#include <string>
+
+class TMap;
+class AliMergeableCollectionIterator;
+
+class AliMergeableCollection : public TNamed
+{
+  friend class AliMergeableCollectionIterator; // our iterator class
+
+public:
+
+  AliMergeableCollection(const char* name="", const char* title="");
+  virtual ~AliMergeableCollection();
+
+  virtual AliMergeableCollection* Clone(const char* name="") const;
+  
+  Bool_t Adopt(TObject* obj);
+  Bool_t Adopt(const char* identifier, TObject* obj);
+    
+  virtual void Clear(Option_t *option="") { Delete(option); }
+  
+  virtual TObject* FindObject(const char* fullIdentifier) const;
+
+  virtual TObject* FindObject(const TObject* object) const;
+
+  virtual void Delete(Option_t *option="");
+  
+  virtual Int_t NumberOfObjects() const;
+
+  virtual Int_t NumberOfKeys() const;
+
+  TObject* GetObject(const char* fullIdentifier) const;
+  TObject* GetObject(const char* identifier, const char* objectName) const;
+  
+  virtual TIterator* CreateIterator(Bool_t dir = kIterForward) const;
+  
+  virtual TList* CreateListOfKeys(Int_t index) const;
+  
+  virtual TList* CreateListOfObjectNames(const char* identifier) const;
+  
+  virtual TObject* Remove(const char* fullIdentifier);
+  
+  TString GetKey(const char* identifier, Int_t index, Bool_t idContainsObjName = kFALSE) const;
+  TString GetIdentifier(const char* fullIdentifier) const;
+  TString GetObjectName(const char* fullIdentifier) const;
+  
+  void Print(Option_t *option="") const;
+  
+  void ClearMessages();
+  void PrintMessages(const char* prefix="") const;
+  
+  Long64_t Merge(TCollection* list);
+  
+  AliMergeableCollection* Project(const char* identifier) const;
+  
+  UInt_t EstimateSize(Bool_t show=kFALSE) const;
+  
+  /// Turn on the display of empty objects for the Print method
+  void ShowEmptyObjects(Bool_t show=kTRUE) {
+    fMustShowEmptyObject = show;
+  }
+  
+  void PruneEmptyObjects();
+  
+  static Bool_t MergeObject(TObject* baseObject, TObject* objToAdd);
+  
+  TObject* GetSum(const char* idPattern);
+  
+  Bool_t IsEmptyObject(TObject* obj) const;
+  
+private:
+  
+  AliMergeableCollection(const AliMergeableCollection& rhs);
+  AliMergeableCollection& operator=(const AliMergeableCollection& rhs);
+  
+  Bool_t InternalAdopt(const char* identifier, TObject* obj);
+  
+  TString InternalDecode(const char* fullIdentifier, Int_t index) const;
+  
+  TObject* InternalObject(const char* identifier, const char* objectName) const;  
+  TObjArray* SortAllIdentifiers() const;
+  
+  TString NormalizeName(const char* identifier, const char* action) const;
+  
+  TMap* Map() const;
+
+private:
+  
+  mutable TMap* fMap; /// map of TMap of THashList* of TObject*...
+  Bool_t fMustShowEmptyObject; /// Whether or not to show empty objects with the Print method
+  mutable Int_t fMapVersion; /// internal version of map (to avoid custom streamer...)
+  mutable std::map<std::string,int> fMessages; //! log messages
+  
+  ClassDef(AliMergeableCollection,1) /// A collection of mergeable objects
+};
+
+class AliMergeableCollectionIterator : public TIterator
+{  
+public:
+  virtual ~AliMergeableCollectionIterator();
+  
+  AliMergeableCollectionIterator(const AliMergeableCollection* hcol, Bool_t direction=kIterForward);
+  AliMergeableCollectionIterator& operator=(const TIterator &rhs);
+  
+  const TCollection *GetCollection() const { return 0x0; }
+
+  TObject* Next();
+  
+  void Reset();
+  
+private:
+  const AliMergeableCollection* fkMergeableCollection; // Mergeable objects collection being iterated
+  TIterator* fMapIterator; // Iterator for the internal map
+  TIterator* fHashListIterator; // Iterator for the current hash list
+  Bool_t fDirection; // forward or reverse
+  
+  AliMergeableCollectionIterator() : fkMergeableCollection(0x0), fMapIterator(0x0), fHashListIterator(0x0), fDirection(kIterForward) {}
+  
+  /// not implemented
+  AliMergeableCollectionIterator& operator=(const AliMergeableCollectionIterator &rhs);
+  /// not implemented
+  AliMergeableCollectionIterator(const AliMergeableCollectionIterator &iter);
+    
+  ClassDef(AliMergeableCollectionIterator,0)  // Mergeable object collection iterator
+};
+
+#endif
diff --git a/PWG3/muon/AliVAnalysisMuon.cxx b/PWG3/muon/AliVAnalysisMuon.cxx
new file mode 100644 (file)
index 0000000..6a73b32
--- /dev/null
@@ -0,0 +1,956 @@
+/**************************************************************************
+ * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
+ *                                                                        *
+ * Author: The ALICE Off-line Project.                                    *
+ * Contributors are mentioned in the code where appropriate.              *
+ *                                                                        *
+ * Permission to use, copy, modify and distribute this software and its   *
+ * documentation strictly for non-commercial purposes is hereby granted   *
+ * without fee, provided that the above copyright notice appears in all   *
+ * copies and that both the copyright notice and this permission notice   *
+ * appear in the supporting documentation. The authors make no claims     *
+ * about the suitability of this software for any purpose. It is          *
+ * provided "as is" without express or implied warranty.                  *
+ **************************************************************************/
+
+/* $Id: AliVAnalysisMuon.cxx 47782 2011-02-24 18:37:31Z martinez $ */
+
+//-----------------------------------------------------------------------------
+/// \class AliVAnalysisMuon
+/// Base class with utilities for muon analysis
+///
+/// \author Diego Stocco
+//-----------------------------------------------------------------------------
+
+#include "AliVAnalysisMuon.h"
+
+// ROOT includes
+#include "TROOT.h"
+#include "TH1.h"
+#include "TH2.h"
+#include "TAxis.h"
+#include "TCanvas.h"
+#include "TLegend.h"
+#include "TMath.h"
+#include "TObjString.h"
+#include "TObjArray.h"
+#include "THashList.h"
+#include "TStyle.h"
+//#include "TMCProcess.h"
+#include "TLorentzVector.h"
+
+// STEER includes
+#include "AliInputEventHandler.h"
+#include "AliCentrality.h"
+
+#include "AliAODEvent.h"
+#include "AliAODTrack.h"
+#include "AliAODMCParticle.h"
+#include "AliMCEvent.h"
+#include "AliMCParticle.h"
+//#include "AliStack.h"
+#include "AliESDEvent.h"
+#include "AliESDMuonTrack.h"
+
+// ANALYSIS includes
+#include "AliAnalysisManager.h"
+#include "AliAnalysisTaskSE.h"
+#include "AliAnalysisDataSlot.h"
+#include "AliAnalysisDataContainer.h"
+
+// CORRFW includes
+#include "AliCFGridSparse.h"
+
+// PWG3 includes
+#include "AliCounterCollection.h"
+#include "AliMergeableCollection.h"
+
+/// \cond CLASSIMP
+ClassImp(AliVAnalysisMuon) // Class implementation in ROOT context
+/// \endcond
+
+
+//________________________________________________________________________
+AliVAnalysisMuon::AliVAnalysisMuon() :
+  AliAnalysisTaskSE(),
+  fMuonTrackCuts(),
+  fMuonPairCuts(),
+  fESDEvent(0x0),
+  fAODEvent(0x0),
+  fTerminateOptions(0x0),
+  fChargeKeys(0x0),
+  fSrcKeys(0x0),
+  fPhysSelKeys(0x0),
+  fTriggerClasses(0x0),
+  fCentralityClasses(0x0),
+  fEventCounters(0x0),
+  fMergeableCollection(0x0),
+  fOutputList(0x0),
+  fSelectedTrigPattern(0x0),
+  fRejectedTrigPattern(0x0),
+  fSelectedTrigLevel(0x0),
+  fOutputPrototypeList(0x0)
+{
+  /// Default ctor.
+}
+
+//________________________________________________________________________
+AliVAnalysisMuon::AliVAnalysisMuon(const char *name, const AliMuonTrackCuts& trackCuts, const AliMuonPairCuts& pairCuts) :
+  AliAnalysisTaskSE(name),
+  fMuonTrackCuts(trackCuts),
+  fMuonPairCuts(pairCuts),
+  fESDEvent(0x0),
+  fAODEvent(0x0),
+  fTerminateOptions(0x0),
+  fChargeKeys(0x0),
+  fSrcKeys(0x0),
+  fPhysSelKeys(0x0),
+  fTriggerClasses(0x0),
+  fCentralityClasses(0x0),
+  fEventCounters(0x0),
+  fMergeableCollection(0x0),
+  fOutputList(0x0),
+  fSelectedTrigPattern(0x0),
+  fRejectedTrigPattern(0x0),
+  fSelectedTrigLevel(0x0),
+  fOutputPrototypeList(0x0)
+{
+  //
+  /// Constructor.
+  //
+  InitKeys();
+
+  DefineOutput(1, TObjArray::Class());
+}
+
+//________________________________________________________________________
+AliVAnalysisMuon::AliVAnalysisMuon(const char *name, const AliMuonTrackCuts& trackCuts) :
+  AliAnalysisTaskSE(name),
+  fMuonTrackCuts(trackCuts),
+  fMuonPairCuts(),
+  fESDEvent(0x0),
+  fAODEvent(0x0),
+  fTerminateOptions(0x0),
+  fChargeKeys(0x0),
+  fSrcKeys(0x0),
+  fPhysSelKeys(0x0),
+  fTriggerClasses(0x0),
+  fCentralityClasses(0x0),
+  fEventCounters(0x0),
+  fMergeableCollection(0x0),
+  fOutputList(0x0),
+  fSelectedTrigPattern(0x0),
+  fRejectedTrigPattern(0x0),
+  fSelectedTrigLevel(0x0),
+  fOutputPrototypeList(0x0)
+{
+  //
+  /// Constructor.
+  //
+  InitKeys();
+
+  DefineOutput(1, TObjArray::Class());
+}
+
+
+//________________________________________________________________________
+AliVAnalysisMuon::AliVAnalysisMuon(const char *name, const AliMuonPairCuts& pairCuts) :
+  AliAnalysisTaskSE(name),
+  fMuonTrackCuts(),
+  fMuonPairCuts(pairCuts),
+  fESDEvent(0x0),
+  fAODEvent(0x0),
+  fTerminateOptions(0x0),
+  fChargeKeys(0x0),
+  fSrcKeys(0x0),
+  fPhysSelKeys(0x0),
+  fTriggerClasses(0x0),
+  fCentralityClasses(0x0),
+  fEventCounters(0x0),
+  fMergeableCollection(0x0),
+  fOutputList(0x0),
+  fSelectedTrigPattern(0x0),
+  fRejectedTrigPattern(0x0),
+  fSelectedTrigLevel(0x0),
+  fOutputPrototypeList(0x0)
+{
+  //
+  /// Constructor.
+  //
+  InitKeys();
+
+  DefineOutput(1, TObjArray::Class());
+}
+
+
+//________________________________________________________________________
+AliVAnalysisMuon::~AliVAnalysisMuon()
+{
+  //
+  /// Destructor
+  //
+
+  delete fTerminateOptions;
+  delete fChargeKeys;
+  delete fSrcKeys;
+  delete fPhysSelKeys;
+  delete fTriggerClasses;
+  delete fCentralityClasses;
+  delete fSelectedTrigPattern;
+  delete fRejectedTrigPattern;
+  delete fSelectedTrigLevel;
+  delete fOutputPrototypeList;
+
+
+  // For proof: do not delete output containers
+  if ( ! AliAnalysisManager::GetAnalysisManager() || ! AliAnalysisManager::GetAnalysisManager()->IsProofMode() ) {
+    delete fOutputList;
+  }
+}
+
+//___________________________________________________________________________
+void AliVAnalysisMuon::FinishTaskOutput()
+{
+  //
+  /// Remove empty histograms to reduce the number of histos to be merged
+  //
+  TString objectName = "";
+//  for ( Int_t iobj=0; iobj<fOutputPrototypeList->GetEntries(); ++iobj ) {
+//    objectName = fOutputPrototypeList->At(iobj)->GetName();
+//    for ( Int_t itrig=0; itrig<fTriggerClasses->GetEntries(); ++itrig ) {
+//      for ( Int_t icent=1; icent<=fCentralityClasses->GetNbins(); ++icent ) {
+//        TObject* objPhysSel = fMergeableCollection->GetObject(fPhysSelKeys->At(kPhysSel)->GetName(), fTriggerClasses->At(itrig)->GetName(), fCentralityClasses->GetBinLabel(icent), objectName);
+//        if ( ! objPhysSel ) continue;
+//        TObject* objAll = GetMergeableObject(fPhysSelKeys->At(kAllSel)->GetName(), fTriggerClasses->At(itrig)->GetName(), fCentralityClasses->GetBinLabel(icent), objectName);
+//        AliMergeableCollection::MergeObject(objAll, objPhysSel);
+//      } // loop on centrality
+//    } // loop on trigger classes
+//  } // loop on object type
+
+  fMergeableCollection->PruneEmptyObjects();
+   
+  // Add stat. info from physics selection
+  // (usefull when running on AODs)
+  if ( fInputHandler ) {
+    for ( Int_t istat=0; istat<2; istat++ ) {
+      TString statType = ( istat == 0 ) ? "ALL" : "BIN0";
+      TH2* hStat = dynamic_cast<TH2*>(fInputHandler->GetStatistics(statType.Data()));
+      if ( hStat ) {
+        objectName = Form("%s_%s", hStat->GetName(), GetName());
+        TH2* cloneStat = static_cast<TH2*>(hStat->Clone(objectName.Data()));
+        cloneStat->SetDirectory(0);
+        fOutputList->Add(cloneStat);
+      }
+      else {
+        AliWarning("Stat histogram not available");
+        break;
+      }
+    } // loop on stat type
+  }
+}
+
+
+//___________________________________________________________________________
+void AliVAnalysisMuon::NotifyRun()
+{
+  /// Set run number for cuts
+  if ( fMuonTrackCuts.GetFilterMask() ) fMuonTrackCuts.SetRun(fCurrentRunNumber);
+  if ( fMuonPairCuts.GetFilterMask() ) fMuonPairCuts.SetRun(fCurrentRunNumber);
+}
+
+//___________________________________________________________________________
+void AliVAnalysisMuon::UserCreateOutputObjects() 
+{
+  //
+  /// Create output objects
+  //
+  AliInfo(Form("   CreateOutputObjects of task %s\n", GetName()));
+
+  fOutputList = new TObjArray();
+  fOutputList->SetOwner();
+
+  if ( ! fPhysSelKeys ) InitKeys();
+  if ( ! fTriggerClasses ) {
+    fTriggerClasses = new THashList();
+    fTriggerClasses->SetOwner();
+  }
+  
+  // initialize object lists
+  InitMergeableOutputs();
+  
+  if ( ! fCentralityClasses ) SetCentralityClasses();
+
+  fEventCounters = new AliCounterCollection("eventCounters");
+
+  TString centralityClasses = "";
+  for ( Int_t icent=1; icent<=fCentralityClasses->GetNbins(); ++icent ) {
+    if ( ! centralityClasses.IsNull() ) centralityClasses += "/";
+    centralityClasses += fCentralityClasses->GetBinLabel(icent);
+  }
+  fEventCounters->AddRubric("selected", "yes/no");
+  fEventCounters->AddRubric("trigger", 100);
+  fEventCounters->AddRubric("centrality", centralityClasses);
+  fEventCounters->Init();
+  fOutputList->Add(fEventCounters);  
+  fMergeableCollection = new AliMergeableCollection("outputObjects");
+  fOutputList->AddLast(fMergeableCollection);
+
+  if ( ! fSelectedTrigPattern && ! fRejectedTrigPattern ) SetTrigClassPatterns();
+
+  PostData(1, fOutputList);
+}
+
+
+//________________________________________________________________________
+void AliVAnalysisMuon::UserExec(Option_t * /*option*/) 
+{
+  //
+  /// Main loop
+  /// Called for each event
+  //
+
+  fAODEvent = dynamic_cast<AliAODEvent*> (InputEvent());
+  if ( ! fAODEvent ) 
+    fESDEvent = dynamic_cast<AliESDEvent*> (InputEvent());
+
+  if ( ! fAODEvent && ! fESDEvent ) {
+    AliError ("AOD or ESD event not found. Nothing done!");
+    return;
+  }
+
+  Int_t physSel = ( fInputHandler->IsEventSelected() & AliVEvent::kAny ) ? kPhysSel : kNonPhysSel;
+
+  //
+  // Global event info
+  //
+
+  TString firedTrigClasses = ( fAODEvent ) ? fAODEvent->GetFiredTriggerClasses() : fESDEvent->GetFiredTriggerClasses();
+  firedTrigClasses.Prepend("ANY ");
+  AliDebug(2, Form("Fired classes %s", firedTrigClasses.Data()));
+  TObjArray* selectTrigClasses = BuildTriggerClasses(firedTrigClasses);
+  if ( selectTrigClasses->GetEntries() == 0 ) {
+    delete selectTrigClasses;
+    return;
+  }
+
+  Double_t centrality = InputEvent()->GetCentrality()->GetCentralityPercentile("V0M");
+  Int_t centralityBin = fCentralityClasses->FindBin(centrality);
+  TString centralityBinLabel = fCentralityClasses->GetBinLabel(centralityBin);
+
+  TString selKey = ( physSel == kPhysSel ) ? "yes" : "no";
+  for ( Int_t itrig=0; itrig<selectTrigClasses->GetEntries(); ++itrig ) {
+    TString trigName = selectTrigClasses->At(itrig)->GetName();
+    fEventCounters->Count(Form("trigger:%s/selected:%s/centrality:%s", trigName.Data(), selKey.Data(), centralityBinLabel.Data()));
+  }
+
+  ProcessEvent(fPhysSelKeys->At(physSel)->GetName(), *selectTrigClasses, fCentralityClasses->GetBinLabel(centralityBin));
+
+  delete selectTrigClasses;
+
+  // Post final data. It will be written to a file with option "RECREATE"
+  PostData(1, fOutputList);
+}
+
+//________________________________________________________________________
+void AliVAnalysisMuon::Terminate(Option_t *)
+{
+  //
+  /// Draw some histogram at the end.
+  //
+  
+  if ( gROOT->IsBatch() ) return;
+  
+  if ( ! fPhysSelKeys ) InitKeys();
+  InitMergeableOutputs();
+  if ( ! fCentralityClasses ) SetCentralityClasses();
+  
+  fOutputList = dynamic_cast<TObjArray*>(GetOutputData(1));
+  if ( ! fOutputList ) return;
+  fEventCounters = static_cast<AliCounterCollection*>(fOutputList->FindObject("eventCounters"));
+  fMergeableCollection = static_cast<AliMergeableCollection*>(fOutputList->FindObject("outputObjects"));
+  
+  if ( ! fTerminateOptions ) SetTerminateOptions();
+  if ( ! fMergeableCollection ) return;
+  AliInfo(Form("Histogram collection size %g MB", fMergeableCollection->EstimateSize()/1024.0/1024.0));
+  if ( fTerminateOptions->At(3) ) {
+    TString sopt = fTerminateOptions->At(3)->GetName();
+    if ( sopt.Contains("verbose") ) fMergeableCollection->Print("*"); 
+  }
+}
+
+
+
+//________________________________________________________________________
+Int_t AliVAnalysisMuon::GetNTracks()
+{
+  //
+  /// Return the number of tracks in event
+  //
+  return ( fAODEvent ) ? fAODEvent->GetNTracks() : fESDEvent->GetNumberOfMuonTracks();
+}
+
+
+//________________________________________________________________________
+AliVParticle* AliVAnalysisMuon::GetTrack(Int_t itrack)
+{
+  //
+  /// Get the current track
+  //
+  AliVParticle* track = 0x0;
+  if ( fAODEvent ) track = fAODEvent->GetTrack(itrack);
+  else track = fESDEvent->GetMuonTrack(itrack);
+  return track;
+}
+
+//________________________________________________________________________
+Double_t AliVAnalysisMuon::MuonMass2() const
+{
+  /// A usefull constant
+  static Double_t m2 = 1.11636129640000012e-02; // using a constant here as the line below is a problem for CINT...
+  return m2;
+}
+
+//________________________________________________________________________
+TLorentzVector AliVAnalysisMuon::GetTrackPair(AliVParticle* track1, AliVParticle* track2) const
+{
+  //
+  /// Get track pair
+  //
+  
+  AliVParticle* tracks[2] = {track1, track2};
+  
+  TLorentzVector vec[2];
+  for ( Int_t itrack=0; itrack<2; ++itrack ) {
+    Double_t trackP = tracks[itrack]->P();
+    Double_t energy = TMath::Sqrt(trackP*trackP + MuonMass2());
+    vec[itrack].SetPxPyPzE(tracks[itrack]->Px(), tracks[itrack]->Py(), tracks[itrack]->Pz(), energy);
+  }
+  
+  TLorentzVector vecPair = vec[0] + vec[1];
+  return vecPair;
+}
+
+
+//________________________________________________________________________
+Int_t AliVAnalysisMuon::GetNMCTracks()
+{
+  //
+  /// Return the number of MC tracks in event
+  //
+  Int_t nMCtracks = 0;
+  if ( fMCEvent ) nMCtracks = fMCEvent->GetNumberOfTracks();
+  else if ( fAODEvent ) {
+    TClonesArray* mcArray = (TClonesArray*)fAODEvent->GetList()->FindObject(AliAODMCParticle::StdBranchName());
+    if ( mcArray ) nMCtracks = mcArray->GetEntries();
+  }
+  return nMCtracks;
+}
+
+//________________________________________________________________________
+AliVParticle* AliVAnalysisMuon::GetMCTrack(Int_t trackLabel)
+{
+  //
+  /// MC information can be provided by the MC input handler
+  /// (mostly when analyising ESDs) or can be found inside AODs
+  /// This method returns the correct one
+  //
+  AliVParticle* mcTrack = 0x0;
+  if ( fMCEvent ) mcTrack = fMCEvent->GetTrack(trackLabel);
+  else if ( fAODEvent ) {
+    TClonesArray* mcArray = (TClonesArray*)fAODEvent->FindListObject(AliAODMCParticle::StdBranchName());
+    if ( mcArray ) mcTrack =  (AliVParticle*)mcArray->At(trackLabel);
+  }
+  if ( ! mcTrack ) AliWarning(Form("No track with label %i!", trackLabel));
+  return mcTrack;
+}
+
+//________________________________________________________________________
+Bool_t AliVAnalysisMuon::IsMC()
+{
+  //
+  /// Contains MC info
+  //
+  return ( fMCEvent || ( fAODEvent && fAODEvent->FindListObject(AliAODMCParticle::StdBranchName()) ) );
+}
+
+
+//________________________________________________________________________
+Int_t AliVAnalysisMuon::GetParticleType(AliVParticle* track)
+{
+  //
+  /// Get particle type from mathced MC track
+  //
+  
+  Int_t trackSrc = kUnidentified;
+  Int_t trackLabel = track->GetLabel();
+  if ( trackLabel >= 0 ) {
+    AliVParticle* matchedMCTrack = GetMCTrack(trackLabel);
+    if ( matchedMCTrack ) trackSrc = RecoTrackMother(matchedMCTrack);
+  } // track has MC label
+  return trackSrc;
+}
+
+
+//________________________________________________________________________
+Int_t AliVAnalysisMuon::RecoTrackMother(AliVParticle* mcParticle)
+{
+  //
+  /// Find track mother from kinematics
+  //
+  
+  Int_t recoPdg = mcParticle->PdgCode();
+  
+  // Track is not a muon
+  if ( TMath::Abs(recoPdg) != 13 ) return kRecoHadron;
+  
+  Int_t imother = ( fMCEvent ) ? ((AliMCParticle*)mcParticle)->GetMother() : ((AliAODMCParticle*)mcParticle)->GetMother();
+  
+  Int_t den[3] = {100, 1000, 1};
+  
+  Int_t motherType = kDecayMu;
+  while ( imother >= 0 ) {
+    AliVParticle* part = GetMCTrack(imother);
+    //if ( ! part ) return motherType;
+    
+    Int_t absPdg = TMath::Abs(part->PdgCode());
+    
+    Bool_t isPrimary = ( fMCEvent ) ? ( imother < fMCEvent->GetNumberOfPrimaries() ) : ((AliAODMCParticle*)part)->IsPrimary();
+    
+    if ( isPrimary ) {
+      for ( Int_t idec=0; idec<3; idec++ ) {
+        Int_t flv = (absPdg%100000)/den[idec];
+        if ( flv > 0 && flv < 4 ) return kDecayMu;
+        else if ( flv == 0 || flv > 5 ) continue;
+        else {
+          if ( den[idec] == 100 ) motherType = kQuarkoniumMu;
+          else if ( flv == 4 ) motherType = kCharmMu;
+          else motherType = kBeautyMu;
+          break; // break loop on pdg code
+          // but continue the global loop to find higher mass HF
+        }
+      } // loop on pdg code
+      if ( absPdg < 10 ) break; // particle loop
+    } // is primary
+    else {
+      if ( part->Zv() < -90. ) {
+        // If hadronic process => secondary
+        //if ( part->GetUniqueID() == kPHadronic ) {
+        return kSecondaryMu;
+        //}
+      }
+    } // is secondary
+    
+    imother = ( fMCEvent ) ? ((AliMCParticle*)part)->GetMother() : ((AliAODMCParticle*)part)->GetMother();
+    
+  } // loop on mothers
+  
+  return motherType;
+}
+
+//________________________________________________________________________
+TObjArray* AliVAnalysisMuon::GetOutputPrototypeList()
+{
+  //
+  /// Get base list of mergeable objects
+  /// (create it if necessary)
+  //
+  
+  if ( ! fOutputPrototypeList ) {
+    fOutputPrototypeList = new TObjArray();
+    fOutputPrototypeList->SetOwner();
+  }
+  return fOutputPrototypeList;
+}
+
+//________________________________________________________________________
+TObject* AliVAnalysisMuon::GetMergeableObject(TString physSel, TString trigClassName, TString centrality, TString objectName)
+{
+  //
+  /// Get mergeable object
+  /// (create collection if necessary)
+  //
+  
+  TString identifier = Form("/%s/%s/%s/", physSel.Data(), trigClassName.Data(), centrality.Data());
+  
+  TObject* obj = fMergeableCollection->GetObject(identifier.Data(), objectName.Data());
+  if ( ! obj ) {
+    CreateMergeableObjects(physSel, trigClassName, centrality);
+    obj = fMergeableCollection->GetObject(identifier.Data(), objectName.Data());
+    AliInfo(Form("Mergeable object collection size %g MB", fMergeableCollection->EstimateSize()/1024.0/1024.0));
+  }
+  return obj;
+}
+
+//________________________________________________________________________
+TObject* AliVAnalysisMuon::GetSum(TString physSel, TString trigClassNames, TString objectPattern, TString centrality)
+{
+  //
+  /// Sum objects
+  /// - physSel, trigClassNames must be in the form: key1,key2
+  /// - centrality must be in the form minValue_maxValue
+  /// - objectPattern must be in the form match1&match2&match3,match4
+  ///   meaning that the object name must contain match1 and match2 and either one of match3 and match4
+  
+  // Get centrality range
+  Int_t firstCentrality = 1;
+  Int_t lastCentrality = fCentralityClasses->GetNbins();
+  
+  TObjArray* centralityRange = centrality.Tokenize("_");
+  Float_t range[2] = {0., 100.};
+  if ( centralityRange->GetEntries() >= 2 ) {
+    for ( Int_t irange=0; irange<2; ++irange ) {
+      range[irange] = ((TObjString*)centralityRange->At(irange))->GetString().Atof();
+    }
+    firstCentrality = fCentralityClasses->FindBin(range[0]+0.0001);
+    lastCentrality = fCentralityClasses->FindBin(range[1]-0.0001);
+  }
+  delete centralityRange;
+  
+  TString sumCentralityString = "";
+  for ( Int_t icent=firstCentrality; icent<=lastCentrality; ++icent ) {
+    if ( ! sumCentralityString.IsNull() ) sumCentralityString += ",";
+    sumCentralityString += fCentralityClasses->GetBinLabel(icent);
+  }
+  
+  objectPattern.ReplaceAll(" ","");
+  TObjArray* objPatternList = objectPattern.Tokenize("&");
+  TObjArray objPatternMatrix(objPatternList->GetEntries());
+  objPatternMatrix.SetOwner();
+  for ( Int_t ikey=0; ikey<objPatternList->GetEntries(); ikey++ ) {
+    TObjArray* subKeyList = ((TObjString*)objPatternList->At(ikey))->GetString().Tokenize(",");
+    objPatternMatrix.AddAt(subKeyList, ikey);
+  }
+  delete objPatternList;
+
+  TString matchingObjectNames = "";
+  for ( Int_t iobj=0; iobj<fOutputPrototypeList->GetEntries(); iobj++ ) {
+    TString objName = fOutputPrototypeList->At(iobj)->GetName();
+    Bool_t matchAnd = kTRUE;
+    for ( Int_t ikey=0; ikey<objPatternMatrix.GetEntries(); ikey++ ) {
+      TObjArray*  subKeyList = (TObjArray*)objPatternMatrix.At(ikey);
+      Bool_t matchOr = kFALSE;
+      for ( Int_t isub=0; isub<subKeyList->GetEntries(); isub++ ) {
+        TString subKeyString = ((TObjString*)subKeyList->At(isub))->GetString();
+        if ( objName.Contains(subKeyString.Data()) ) {
+          matchOr = kTRUE;
+          break;
+        }
+      }
+      if ( ! matchOr ) {
+        matchAnd = kFALSE;
+        break;
+      }
+    }
+    if ( ! matchAnd ) continue;
+    if ( ! matchingObjectNames.IsNull() ) matchingObjectNames.Append(",");
+    matchingObjectNames += objName;
+  }
+
+  TString idPattern = Form("/%s/%s/%s/%s", physSel.Data(), trigClassNames.Data(), sumCentralityString.Data(), matchingObjectNames.Data());
+  idPattern.ReplaceAll(" ","");
+  
+  return fMergeableCollection->GetSum(idPattern.Data());
+//  
+//  TObjArray* trigArray = trigClassNames.Tokenize(" ");
+//  trigArray->SetOwner();
+//  
+//  objectPattern.ReplaceAll(" / ","/");
+//  TObjArray* objectPatternStrings = objectPattern.Tokenize("/");
+//  objectPatternStrings->SetOwner();
+//  
+//  TObject* obj = 0x0;
+//  TString objName = "", currName = "";
+//  TIter nextObject(fOutputPrototypeList);
+//  TObject* currObject = 0x0;
+//  while ( ( currObject = nextObject() ) ) {
+//    objName = currObject->GetName();
+//    Bool_t matchPattern = kTRUE;
+//    for ( Int_t ipatt=0; ipatt<objectPatternStrings->GetEntries(); ++ipatt ) {
+//      TObjArray* objectSubPattern = ((TObjString*)objectPatternStrings->At(ipatt))->GetString().Tokenize(" ");
+//      objectSubPattern->SetOwner();
+//      Bool_t matchSubPattern = kFALSE;
+//      for ( Int_t isubpatt=0; isubpatt<objectSubPattern->GetEntries(); ++isubpatt ) {
+//        if ( objName.Contains(objectSubPattern->At(isubpatt)->GetName() ) ) {
+//          matchSubPattern = kTRUE;
+//          break;
+//        }
+//      } // loop on sub pattern
+//      delete objectSubPattern;
+//      if ( ! matchSubPattern ) {
+//        matchPattern = kFALSE;
+//        break;
+//      }
+//    }
+//    if ( ! matchPattern ) continue;
+//    
+//    for ( Int_t itrig=0; itrig<trigArray->GetEntries(); ++itrig ) {
+//      for ( Int_t icent=firstCentrality; icent<=lastCentrality; ++icent ) {
+//        currName = objName;
+//        TObject* auxObj = fMergeableCollection->GetObject(physSel.Data(),trigArray->At(itrig)->GetName(),fCentralityClasses->GetBinLabel(icent),objName.Data());
+//        if ( ! auxObj ) continue;
+//        if ( ! obj ) {
+//          TString currCentrRange = Form("%g_%g", fCentralityClasses->GetBinLowEdge(firstCentrality), fCentralityClasses->GetBinUpEdge(lastCentrality));
+//          currName.ReplaceAll(fCentralityClasses->GetBinLabel(icent), currCentrRange.Data());
+//          currName += "_" + currCentrRange + "_" + physSel;
+//          obj = (TObject*)auxObj->Clone(currName.Data());
+//          if ( obj->IsA()->InheritsFrom(TH1::Class()) ) ((TH1*)obj)->SetTitle(currName.Data());
+//        }
+//        else {
+//          AliMergeableCollection::MergeObject(obj,auxObj);
+//        }
+//        AliDebug(1,Form("Add object %s %s %s %s", physSel.Data(),trigArray->At(itrig)->GetName(),fCentralityClasses->GetBinLabel(icent),objName.Data()));
+//      } // loop on centrality
+//    } // loop on trigger class
+//  } // loop on objects
+//  
+//  delete trigArray;
+//  delete objectPatternStrings;
+//  
+//  if ( obj ) AliDebug(1,Form("To object %s\n", obj->GetName()));
+//  
+//  return obj;
+}
+
+//___________________________________________________________________________
+void AliVAnalysisMuon::CreateMergeableObjects(TString physSel, TString trigClassName, TString centrality)
+{
+  TObject* obj = 0x0;
+  TString objectName = "";
+  TString identifier = Form("/%s/%s/%s/", physSel.Data(), trigClassName.Data(), centrality.Data());
+  for ( Int_t iobj=0; iobj<fOutputPrototypeList->GetEntries(); ++iobj ) {
+    objectName = fOutputPrototypeList->At(iobj)->GetName();
+    obj = fOutputPrototypeList->At(iobj)->Clone(objectName.Data());
+    fMergeableCollection->Adopt(identifier, obj);
+  } // loop on histos
+}
+
+
+//_______________________________________________________________________
+Bool_t AliVAnalysisMuon::SetSparseRange(AliCFGridSparse* gridSparse,
+                                        Int_t ivar, TString labelName,
+                                        Double_t varMin, Double_t varMax,
+                                        TString option)
+{
+  //
+  /// Set range in a smart way.
+  /// Allows to select a bin from the label.
+  /// Check the bin limits.
+  //
+  
+  option.ToUpper();
+  Int_t minVarBin = -1, maxVarBin = -1;
+  TAxis* axis = gridSparse->GetAxis(ivar);
+  
+  if ( ! axis ) {
+    printf("Warning: Axis %i not found in %s", ivar, gridSparse->GetName());
+    return kFALSE;
+  }
+  
+  if ( ! labelName.IsNull() ) {
+    minVarBin = axis->FindBin(labelName.Data());
+    maxVarBin = minVarBin;
+    if ( minVarBin < 1 ) {
+      printf("Warning: %s: label %s not found. Nothing done", gridSparse->GetName(), labelName.Data());
+      return kFALSE;
+    }
+  }
+  else if ( option.Contains( "USEBIN" ) ) {
+    minVarBin = (Int_t)varMin;
+    maxVarBin = (Int_t)varMax;
+  }
+  else {
+    minVarBin = axis->FindBin(varMin);
+    maxVarBin = axis->FindBin(varMax);
+  }
+  
+  if ( axis->GetFirst() == minVarBin && axis->GetLast() == maxVarBin ) return kFALSE;
+  
+  gridSparse->SetRangeUser(ivar, axis->GetBinCenter(minVarBin), axis->GetBinCenter(maxVarBin));
+  
+  return kTRUE;
+}
+
+//________________________________________________________________________
+void AliVAnalysisMuon::SetTrigClassPatterns(TString pattern)
+{
+  /// Set trigger classes
+  ///
+  /// Classes are filled dynamically according to the pattern
+  /// - if name contains ! (without spaces): reject it
+  /// - in the matching pattern it is also possible to specify the
+  ///   pt cut level associated to the trigger
+  /// example:
+  /// SetTrigClassPatterns("CMBAC CPBI1MSL:Lpt CPBI1MSH:Hpt !ALLNOTRD")
+  /// keeps classes containing CMBAC, CPBI1MSL and CPBI1MSH and not containing ALLNOTRD.
+  /// In addition, it knows that the class matching CPBI1MSL requires an Lpt trigger
+  /// and the one with CPBI1MSH requires a Hpt trigger.
+  /// Hence, in the analysis, the function
+  /// TrackPtCutMatchTrigClass(track, "CPBIMSL") returns true if track match Lpt
+  /// TrackPtCutMatchTrigClass(track, "CPBIMSL") returns true if track match Hpt
+  /// TrackPtCutMatchTrigClass(track, "CMBAC") always returns true
+  ///
+  /// CAVEAT: if you use an fCFContainer and you want an axis to contain the trigger classes,
+  ///         please be sure that each pattern matches only 1 trigger class, or triggers will be mixed up
+  ///         when merging different chuncks.
+
+  delete fSelectedTrigPattern;
+  fSelectedTrigPattern = new TObjArray();
+  fSelectedTrigPattern->SetOwner();
+  delete fRejectedTrigPattern;
+  fRejectedTrigPattern = new TObjArray();
+  fRejectedTrigPattern->SetOwner();
+  delete fSelectedTrigLevel;
+  fSelectedTrigLevel = new TObjArray();
+  fSelectedTrigLevel->SetOwner();  
+
+  pattern.ReplaceAll("  "," ");
+  pattern.ReplaceAll("! ","!");
+  pattern.ReplaceAll(" :",":");
+
+  TObjArray* fullList = pattern.Tokenize(" ");
+
+  for ( Int_t ipat=0; ipat<fullList->GetEntries(); ++ipat ) {
+    TString currPattern = fullList->At(ipat)->GetName();
+    if ( currPattern.Contains("!") ) {
+      currPattern.ReplaceAll("!","");
+      fRejectedTrigPattern->AddLast(new TObjString(currPattern));
+    }
+    else {
+      TObjArray* arr = currPattern.Tokenize(":");
+      fSelectedTrigPattern->AddLast(new TObjString(arr->At(0)->GetName()));
+      TString selTrigLevel = ( arr->At(1) ) ? arr->At(1)->GetName() : "none";
+      selTrigLevel.ToUpper();
+      fSelectedTrigLevel->AddLast(new TObjString(selTrigLevel));
+      delete arr;
+    }
+  }
+  
+  delete fullList;
+}
+
+//________________________________________________________________________
+void AliVAnalysisMuon::SetCentralityClasses(Int_t nCentralityBins, Double_t* centralityBins)
+{
+  //
+  /// Set centrality classes
+  //
+  if ( ! centralityBins ) {
+    Double_t defaultCentralityBins[] = {-5., 0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 100., 105.};
+    centralityBins = defaultCentralityBins;
+    nCentralityBins = sizeof(defaultCentralityBins)/sizeof(defaultCentralityBins[0])-1;
+  }
+
+  delete fCentralityClasses;
+  fCentralityClasses = new TAxis(nCentralityBins, centralityBins);
+  TString currClass = "";
+  for ( Int_t ibin=1; ibin<=fCentralityClasses->GetNbins(); ++ibin ){
+    currClass = Form("%.0f_%.0f",fCentralityClasses->GetBinLowEdge(ibin),fCentralityClasses->GetBinUpEdge(ibin));
+    fCentralityClasses->SetBinLabel(ibin, currClass.Data());
+  }  
+}
+
+//________________________________________________________________________
+void AliVAnalysisMuon::SetTerminateOptions(TString physSel, TString trigClass, TString centralityRange, TString furtherOpts)
+{
+  //
+  /// Set terminate options
+  //
+  if ( ! fTerminateOptions ) {
+    fTerminateOptions = new TObjArray(4);
+    fTerminateOptions->SetOwner();
+  }
+  fTerminateOptions->AddAt(new TObjString(physSel), 0);
+  fTerminateOptions->AddAt(new TObjString(trigClass), 1);
+  fTerminateOptions->AddAt(new TObjString(centralityRange),2);
+  fTerminateOptions->AddLast(new TObjString(furtherOpts));
+}
+
+//________________________________________________________________________
+void AliVAnalysisMuon::InitKeys()
+{
+  TString chargeKeys = "MuMinus MuPlus";
+  fChargeKeys = chargeKeys.Tokenize(" ");
+  
+  TString srcKeys = "CharmMu BeautyMu QuarkoniumMu DecayMu SecondaryMu Hadron Unidentified";
+  fSrcKeys = srcKeys.Tokenize(" ");
+  
+  TString physSelKeys = "PhysSelPass PhysSelReject";
+  fPhysSelKeys = physSelKeys.Tokenize(" ");
+}
+
+//________________________________________________________________________
+TObjArray* AliVAnalysisMuon::BuildTriggerClasses(TString firedTrigClasses)
+{
+  //
+  /// Return the list of trigger classes to be considered
+  /// for current event. Update the global list if necessary
+  //
+
+  TObjArray* selectedTrigClasses = new TObjArray(0);
+  selectedTrigClasses->SetOwner();
+  
+  TObjArray* firedTrigClassesList = firedTrigClasses.Tokenize(" ");
+
+  for ( Int_t itrig=0; itrig<firedTrigClassesList->GetEntries(); ++itrig ) {
+    TString trigName = ((TObjString*)firedTrigClassesList->At(itrig))->GetString();
+    Bool_t rejectTrig = kFALSE;
+    for ( Int_t ipat=0; ipat<fRejectedTrigPattern->GetEntries(); ++ipat ) {
+      if ( trigName.Contains(fRejectedTrigPattern->At(ipat)->GetName() ) ) {
+        rejectTrig = kTRUE;
+        break;
+      }
+    } // loop on reject pattern
+    if ( rejectTrig ) continue;
+
+    Int_t matchPatternIndex = -1;
+    for ( Int_t ipat=0; ipat<fSelectedTrigPattern->GetEntries(); ++ipat ) {
+      if ( trigName.Contains(fSelectedTrigPattern->At(ipat)->GetName() ) ) {
+        matchPatternIndex = ipat;
+        break;
+      }
+    } // loop on keep pattern
+    if ( matchPatternIndex < 0 ) continue;
+
+    selectedTrigClasses->AddLast(new TObjString(trigName));
+    if ( fTriggerClasses->FindObject(trigName.Data()) ) continue;
+    Int_t trigLevel = 0;
+    TString trigLevelString = fSelectedTrigLevel->At(matchPatternIndex)->GetName();
+    if ( trigLevelString.Contains("APT") ) trigLevel = 1;
+    else if ( trigLevelString.Contains("LPT") ) trigLevel = 2;
+    else if ( trigLevelString.Contains("HPT") ) trigLevel = 3;
+    AliInfo(Form("Adding %s to considered trigger classes",trigName.Data()));
+    TObjString* addTrig = new TObjString(trigName);
+    UInt_t uniqueId = trigLevel;
+    addTrig->SetUniqueID(uniqueId);
+    fTriggerClasses->Add(addTrig);
+  } // loop on trigger classes
+
+  delete firedTrigClassesList;
+
+  return selectedTrigClasses;
+}
+
+
+//________________________________________________________________________
+Bool_t AliVAnalysisMuon::TrackPtCutMatchTrigClass(AliVParticle* track, TString trigClassName)
+{
+  /// Check if track passes the trigger pt cut level used in the trigger class
+  Int_t matchTrig = ( fAODEvent ) ? ((AliAODTrack*)track)->GetMatchTrigger() : ((AliESDMuonTrack*)track)->GetMatchTrigger();
+  Int_t classMatchLevel = GetTrigClassPtCutLevel(trigClassName);
+  return matchTrig >= classMatchLevel;
+}
+
+
+//________________________________________________________________________
+Int_t AliVAnalysisMuon::GetTrigClassPtCutLevel(TString trigClassName)
+{
+  /// Get trigger class pt cut level for tracking/trigger matching
+  TObject* obj = fTriggerClasses->FindObject(trigClassName.Data());
+  if ( ! obj ) {
+    AliWarning(Form("Class %s not in the list!", trigClassName.Data()));
+    return -1;
+  }
+  
+  return obj->GetUniqueID();
+}
diff --git a/PWG3/muon/AliVAnalysisMuon.h b/PWG3/muon/AliVAnalysisMuon.h
new file mode 100644 (file)
index 0000000..fbce049
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef ALIVANALYSISMUON_H
+#define ALIVANALYSISMUON_H
+
+/* $Id: AliVAnalysisMuon.h 47782 2011-02-24 18:37:31Z martinez $ */ 
+
+//
+// Base class for single muon analysis
+//
+// Author: Diego Stocco
+//
+
+#include "AliAnalysisTaskSE.h"
+#include "AliMuonTrackCuts.h"
+#include "AliMuonPairCuts.h"
+
+class TString;
+class TObjArray;
+class TAxis;
+class TLorentzVector;
+class TList;
+class AliMergeableCollection;
+class AliCounterCollection;
+class AliVParticle;
+class AliAODEvent;
+class AliESDEvent;
+class AliCFGridSparse;
+
+class AliVAnalysisMuon : public AliAnalysisTaskSE {
+ public:
+  AliVAnalysisMuon();
+  AliVAnalysisMuon(const char *name, const AliMuonTrackCuts& trackCuts);
+  AliVAnalysisMuon(const char *name, const AliMuonPairCuts& pairCuts);
+  AliVAnalysisMuon(const char *name, const AliMuonTrackCuts& trackCuts, const AliMuonPairCuts& pairCuts);
+  virtual ~AliVAnalysisMuon();
+
+  virtual void   UserCreateOutputObjects();
+  virtual void   UserExec(Option_t *option);
+  virtual void   Terminate(Option_t *option);
+  virtual void   NotifyRun();
+  virtual void   FinishTaskOutput();
+
+  void SetCentralityClasses(Int_t nCentralityBins = -1, Double_t* centralityBins = 0x0);
+
+  void SetTrigClassPatterns(TString pattern = "CINT CMU !CMUP CMBAC CPBI !-ACE- !-AC- !-E- !WU !EGA !EJE");
+  void SetTerminateOptions(TString physSel="All", TString trigClass="ANY", TString centralityRange="", TString furtherOpts="");
+  
+  // Utility methods for CF container
+  static Bool_t SetSparseRange(AliCFGridSparse* gridSparse,
+                               Int_t ivar, TString labelName,
+                               Double_t varMin, Double_t varMax,
+                               TString option = "");
+
+ protected:
+  
+  /////////////////////////////////////////////////////
+  // Pure virtual methods to be implemented bu users //
+  /////////////////////////////////////////////////////
+  
+  virtual void InitMergeableOutputs() = 0;
+  // In this method you have to create the mergeable objects that will be then used
+  // in the counter collection.
+  // To do so, create your histogram and add it to outputPrototypeList:
+  //    TH1* histo = new TH1F();
+  //    GetOutputPrototypeList()->Add(histo);
+  
+  virtual void ProcessEvent(TString physSel, const TObjArray& selectTrigClasses, TString centrality) = 0;
+  // This method is called at each event.
+  // In this method you can fill the histograms or the CF container that you have created
+  
+  
+  /////////////////////
+  // Utility methods //
+  /////////////////////
+  
+  // Transparently handle tracks in ESD/AOD
+  Int_t GetNTracks();
+  AliVParticle* GetTrack(Int_t itrack);
+  TLorentzVector GetTrackPair(AliVParticle* track1, AliVParticle* track2) const;
+  
+  // Methods for MC
+  Bool_t IsMC();
+  Int_t GetNMCTracks();
+  AliVParticle* GetMCTrack(Int_t trackLabel);
+  Int_t GetParticleType(AliVParticle* track);
+  Int_t RecoTrackMother(AliVParticle* mcParticle);
+  
+  // Methods for mergeable object collections
+  TObjArray* GetOutputPrototypeList();
+  TObject* GetMergeableObject(TString physSel, TString trigClassName, TString centrality, TString objectName);
+  TObject* GetSum(TString physSel, TString trigClassNames, TString objectPattern, TString centrality = "all");
+  
+  // A useful constant
+  Double_t MuonMass2() const;
+  
+  // Handle triggers
+  Bool_t TrackPtCutMatchTrigClass(AliVParticle* track, TString trigClassName);
+  Int_t GetTrigClassPtCutLevel(TString trigClassName);
+  
+  enum {
+    kPhysSel,     ///< Physics selected events
+    kNonPhysSel,  ///< Events non-passing selection
+    kNselections  ///< Number of selections
+  };
+  
+  enum {
+    kCharmMu,       ///< Mu from charm
+    kBeautyMu,      ///< Mu from beauty
+    kQuarkoniumMu,  ///< Mu from resonance
+    kDecayMu,       ///< Decay mu
+    kSecondaryMu,   ///< Secondary mu
+    kRecoHadron,    ///< Reconstructed hadron
+    kUnidentified,  ///< Particle that fails matching kine
+    kNtrackSources  ///< Total number of track sources
+  };
+    
+  AliMuonTrackCuts fMuonTrackCuts; ///< Muon track cuts
+  AliMuonPairCuts fMuonPairCuts;   ///< Muon pair track cuts
+  AliESDEvent* fESDEvent;      //!< ESD event, not owner
+  AliAODEvent* fAODEvent;      //!< AOD event, not owner
+  TObjArray* fTerminateOptions; ///< Terminate options
+  TObjArray* fChargeKeys;      //!< Muon charge keys
+  TObjArray* fSrcKeys;         //!< MC sources names
+  TObjArray* fPhysSelKeys;     //!< Physics selection names
+  TList* fTriggerClasses;      //!< List of trigger classes
+  TAxis* fCentralityClasses;   ///< Centrality classes
+  
+  AliCounterCollection* fEventCounters;  //!< event counters
+  AliMergeableCollection* fMergeableCollection; //!< collection of mergeable objects
+  TObjArray* fOutputList;  //!< List of outputs  
+
+ private:
+  AliVAnalysisMuon(const AliVAnalysisMuon&);
+  AliVAnalysisMuon& operator=(const AliVAnalysisMuon&);
+  
+  void InitKeys();
+  void CreateMergeableObjects(TString physSel, TString trigClassName, TString centrality);
+  TObjArray* BuildTriggerClasses(TString firedTrigClasses);
+  
+  TObjArray* fSelectedTrigPattern; ///< List of triggers to be kept
+  TObjArray* fRejectedTrigPattern; ///< List of triggers to be rejected
+  TObjArray* fSelectedTrigLevel;   ///< Track-trigger pt cut for selected trigger class
+  TObjArray* fOutputPrototypeList; //!< List of prototype object to be used in collection
+
+  ClassDef(AliVAnalysisMuon, 1);
+};
+
+#endif