]> git.uio.no Git - u/mrichter/AliRoot.git/commitdiff
Split the TaskMuMu into more manageable sub-analysis (Laurent)
authorCROCHET Philippe <crochet@clermont.in2p3.fr>
Fri, 20 Dec 2013 12:50:04 +0000 (13:50 +0100)
committerCROCHET Philippe <crochet@clermont.in2p3.fr>
Fri, 20 Dec 2013 12:50:04 +0000 (13:50 +0100)
36 files changed:
PWG/CMakelibPWGmuon.pkg
PWG/PWGmuonLinkDef.h
PWG/muon/AddTaskMuMu.C
PWG/muon/AliAnalysisMuMuBase.cxx [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuBase.h [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuBinning.cxx
PWG/muon/AliAnalysisMuMuBinning.h
PWG/muon/AliAnalysisMuMuCutCombination.cxx [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuCutCombination.h [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuCutElement.cxx [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuCutElement.h [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuCutRegistry.cxx [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuCutRegistry.h [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuEventCutter.cxx [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuEventCutter.h [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuGlobal.cxx [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuGlobal.h [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuMinv.cxx [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuMinv.h [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuNch.cxx [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuNch.h [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuSingle.cxx [new file with mode: 0644]
PWG/muon/AliAnalysisMuMuSingle.h [new file with mode: 0644]
PWG/muon/AliAnalysisMuonUtility.cxx
PWG/muon/AliAnalysisMuonUtility.h
PWG/muon/AliAnalysisTaskMuMu.cxx
PWG/muon/AliAnalysisTaskMuMu.h
PWG/muon/AliMergeableCollection.cxx
PWG/muon/AliMergeableCollection.h
PWG/muon/AliMuonEventCuts.cxx
PWG/muon/AliMuonEventCuts.h
PWG/muon/Doxyfile [new file with mode: 0644]
PWG/muon/DoxygenLayout.xml [new file with mode: 0644]
PWG/muon/runMuMu.C [new file with mode: 0755]
PWG/muondep/AliAnalysisMuMu.cxx
PWG/muondep/AliAnalysisMuMuSpectra.cxx

index 2acbe24fa73e677a7da6f17e5b101da5e092f19e..f76c44aa7ebfa6e3f40a2b51bdff8e9e77ee6ed0 100644 (file)
@@ -68,6 +68,16 @@ set ( SRCS
     muon/AliAnalysisNonMuonTrackCuts.cxx
     muon/AliAnalysisNonPrimaryVertices.cxx
     muon/AliAnalysisTaskAOD2MuonAOD.cxx
+    muon/AliAnalysisTaskMuMu.cxx
+    muon/AliAnalysisMuMuBase.cxx
+    muon/AliAnalysisMuMuGlobal.cxx
+    muon/AliAnalysisMuMuCutRegistry.cxx
+    muon/AliAnalysisMuMuCutElement.cxx
+    muon/AliAnalysisMuMuEventCutter.cxx
+    muon/AliAnalysisMuMuCutCombination.cxx
+    muon/AliAnalysisMuMuSingle.cxx
+    muon/AliAnalysisMuMuMinv.cxx
+    muon/AliAnalysisMuMuNch.cxx
     )
 
 string ( REPLACE ".cxx" ".h" HDRS "${SRCS}" )
@@ -76,7 +86,7 @@ string ( REPLACE ".cxx" ".h" EXPORT "${SRCS}" )
 
 set ( DHDR  PWGmuonLinkDef.h)
 
-set ( EINCLUDE  PWG/muon ANALYSIS STEER/AOD STEER/ESD STEER/STEERBase)
+set ( EINCLUDE  RooUnfold/src  PWG/muon ANALYSIS STEER/AOD STEER/ESD STEER/STEERBase)
 
 if( ALICE_TARGET STREQUAL "win32gcc")
         set ( PACKSOFLAGS  ${SOFLAGS} )
index ef507e4670e2930d652ce045c5f629a6c557f901..8fb12e97bee496fc946456c198f5d5c8d5ce5cbf 100644 (file)
@@ -34,8 +34,6 @@
 #pragma link C++ class AliHistogramCollectionIterator+;
 #pragma link C++ class AliAnalysisTaskMuonCollisionMultiplicity+;
 #pragma link C++ class AliCFMuonResUpsilon+;
-#pragma link C++ class AliAnalysisTaskMuMu+;
-#pragma link C++ class AliAnalysisTaskMuMu::PairCut+;
 #pragma link C++ class AliMuonEventCuts+;
 #pragma link C++ class AliMuonTrackCuts+;
 #pragma link C++ class AliMuonPairCuts+;
 #pragma link C++ class AliAnalysisMuonUtility+;
 #pragma link C++ class AliUtilityMuonAncestor+;
 #pragma link C++ class AliOADBMuonTrackCutsParam+;
-#pragma link C++ class AliAnalysisMuMuBinning+;
-#pragma link C++ class AliAnalysisMuMuBinning::Range+;
 #pragma link C++ class AliAnalysisTaskAOD2MuonAOD+;
 #pragma link C++ class AliAnalysisNonMuonTrackCuts+;
 #pragma link C++ class AliAnalysisNonPrimaryVertices+;
 
+#pragma link C++ class AliAnalysisTaskMuMu+;
+#pragma link C++ class AliAnalysisMuMuBinning+;
+#pragma link C++ class AliAnalysisMuMuBinning::Range+;
+#pragma link C++ class AliAnalysisMuMuBase+;
+#pragma link C++ class AliAnalysisMuMuGlobal+;
+#pragma link C++ class AliAnalysisMuMuCutRegistry+;
+#pragma link C++ class AliAnalysisMuMuCutElement+;
+#pragma link C++ class AliAnalysisMuMuCutElementBar+;
+#pragma link C++ class AliAnalysisMuMuCutCombination+;
+#pragma link C++ class AliAnalysisMuMuEventCutter+;
+#pragma link C++ class AliAnalysisMuMuSingle+;
+#pragma link C++ class AliAnalysisMuMuMinv+;
+#pragma link C++ class AliAnalysisMuMuNch+;
+//#pragma link C++ class AliAnalysisMuMuMeanPt+;
+
 #endif
 
index 13a9d4a1f72202eb571efe5ef0076920251fa7af..9ac7c8192b4d31e7f30d3b2226402b7cff7c2573 100644 (file)
@@ -1,14 +1,13 @@
 ///
-/// Configure a task to get invariant mass spectrum of dimuons
+/// Configuration example of a task to get invariant mass spectrum of dimuons
 ///
-/// author: L. Aphecetche (Subatech) (laurent.aphecetche - at - subatech.in2p3.fr)
+/// \author: L. Aphecetche (Subatech) (laurent.aphecetche - at - subatech.in2p3.fr)
 ///
 
 AliAnalysisTask* AddTaskMuMu(const char* outputname, 
-                                                        TList* triggerClassesToConsider, 
-                                                        const char* beamYear, 
-                                                        TArrayF* centralities,
-                                                        Bool_t simulations)                                    
+                             TList* triggerClassesToConsider,
+                             const char* beamYear,
+                             Bool_t simulations)
 {
   AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
   if (!mgr) {
@@ -27,186 +26,203 @@ AliAnalysisTask* AddTaskMuMu(const char* outputname,
   
   // Configure analysis
   //===========================================================================  
-  
-  AliAnalysisTaskMuMu* task;
-  
+
   if (simulations && triggerClassesToConsider )
   {
-    triggerClassesToConsider->Add(new TObjString("CMULLO-B-NOPF-MUON"));
-       triggerClassesToConsider->Add(new TObjString("CMSNGL-B-NOPF-MUON"));
-       triggerClassesToConsider->Add(new TObjString("ANY"));
+//    triggerClassesToConsider->Add(new TObjString("CMULLO-B-NOPF-MUON"));
+//    triggerClassesToConsider->Add(new TObjString("CMSNGL-B-NOPF-MUON"));
+    triggerClassesToConsider->Add(new TObjString("ANY"));
+
+//    triggerClassesToConsider->Add(new TObjString("MB1"));
+//    triggerClassesToConsider->Add(new TObjString("C0T0A"));
+
+    //    triggerClassesToConsider->Add(new TObjString("MULow"));
+//    triggerClassesToConsider->Add(new TObjString("V0L"));
+//    triggerClassesToConsider->Add(new TObjString("V0R"));
+//
+// for dpmjet simulations (at least) we have the following "triggers" :
+//    C0T0A,C0T0C,MB1,MBBG1,V0L,V0R,MULow,EMPTY,MBBG3,MULL,MULU,MUHigh
   }
+
+  AliAnalysisTaskMuMu* task = new AliAnalysisTaskMuMu;
   
-  if ( triggerClassesToConsider ) 
-  {
-    task = new AliAnalysisTaskMuMu((inputDataType=="ESD"),triggerClassesToConsider,beamYear,centralities);    
-  }
-  else 
-  {
-    task = new AliAnalysisTaskMuMu((inputDataType=="ESD"),beamYear,centralities);    
-  }
+  AliAnalysisMuMuEventCutter* eventCutter = new AliAnalysisMuMuEventCutter(triggerClassesToConsider);
   
-  task->AddEventCut("ALL",AliAnalysisTaskMuMu::kEventAll);
+  AliAnalysisMuMuCutRegistry* cr = task->CutRegistry();
+  
+  AliAnalysisMuMuCutElement* eventTrue = cr->AddEventCut(*eventCutter,"IsTrue","const AliVEvent&","");
 
-if (!simulations) 
-  {
-       task->AddEventCut("PSALL",AliAnalysisTaskMuMu::kEventAll | AliAnalysisTaskMuMu::kEventPS);  
-//     task->AddEventCut("OFFLINE1",AliAnalysisTaskMuMu::kEventAll | AliAnalysisTaskMuMu::kEventPS | AliAnalysisTaskMuMu::kEventOFFLINEMUL1);  
-//     task->AddEventCut("REJECTED",AliAnalysisTaskMuMu::kEventAll | AliAnalysisTaskMuMu::kEventREJECTED);  
-   }
-  
-//  task->AddEventCut("PSALLNOTZEROPILEUP",AliAnalysisTaskMuMu::kEventAll | AliAnalysisTaskMuMu::kEventPS | AliAnalysisTaskMuMu::kEventNOTZEROPILEUP);  
-
-//  task->AddEventCut("PSALLMUL1", AliAnalysisTaskMuMu::kEventAll | AliAnalysisTaskMuMu::kEventPS | AliAnalysisTaskMuMu::kEventOFFLINEMUL1);
-
-//  task->AddEventCut("PSALLMUL2", AliAnalysisTaskMuMu::kEventAll | AliAnalysisTaskMuMu::kEventPS | AliAnalysisTaskMuMu::kEventOFFLINEMUL2);
-
-//   task->AddSingleCut("MATCHLOWRABSDCA",
-//                      AliAnalysisTaskMuMu::kAll|AliAnalysisTaskMuMu::kMatchedLow|AliAnalysisTaskMuMu::kRabs|AliAnalysisTaskMuMu::kDCA);
-// 
-   task->AddSingleCut("MATCHLOWRABS",
-                      AliAnalysisTaskMuMu::kAll|AliAnalysisTaskMuMu::kMatchedLow|AliAnalysisTaskMuMu::kRabs);
-
-   task->AddSingleCut("MATCHLOWRABSETA",
-                      AliAnalysisTaskMuMu::kAll|AliAnalysisTaskMuMu::kMatchedLow|AliAnalysisTaskMuMu::kRabs);
-
-  task->AddSingleCut("MATCHLOWRABSETADCA",
-                     AliAnalysisTaskMuMu::kAll|AliAnalysisTaskMuMu::kMatchedLow|AliAnalysisTaskMuMu::kRabs|AliAnalysisTaskMuMu::kEta|AliAnalysisTaskMuMu::kDCA);
-
-
-//  task->AddPairCut("ALL",AliAnalysisTaskMuMu::kAll);
-
-   task->AddPairCut("MATCHLOWRABSBOTH",
-                    AliAnalysisTaskMuMu::kAll|AliAnalysisTaskMuMu::kMatchedLow|AliAnalysisTaskMuMu::kRabs,
-                    AliAnalysisTaskMuMu::kAll|AliAnalysisTaskMuMu::kMatchedLow|AliAnalysisTaskMuMu::kRabs);
-
-   task->AddPairCut("MATCHLOWRABSETABOTH",
-                    AliAnalysisTaskMuMu::kAll|AliAnalysisTaskMuMu::kMatchedLow|AliAnalysisTaskMuMu::kRabs|AliAnalysisTaskMuMu::kEta,
-                    AliAnalysisTaskMuMu::kAll|AliAnalysisTaskMuMu::kMatchedLow|AliAnalysisTaskMuMu::kRabs|AliAnalysisTaskMuMu::kEta);
-
-   task->AddPairCut("MATCHLOWRABSETADCABOTH",
-                    AliAnalysisTaskMuMu::kAll|AliAnalysisTaskMuMu::kMatchedLow|AliAnalysisTaskMuMu::kRabs|AliAnalysisTaskMuMu::kEta|AliAnalysisTaskMuMu::kDCA,
-                    AliAnalysisTaskMuMu::kAll|AliAnalysisTaskMuMu::kMatchedLow|AliAnalysisTaskMuMu::kRabs|AliAnalysisTaskMuMu::kEta|AliAnalysisTaskMuMu::kDCA);
-
-// igor binning
-
-task->AddBin("psi","pt", 0.0, 0.5,"IGOR");
-task->AddBin("psi","pt", 0.5, 1.0,"IGOR");
-task->AddBin("psi","pt", 1.0, 1.5,"IGOR");
-task->AddBin("psi","pt", 1.5, 2.0,"IGOR");
-task->AddBin("psi","pt", 2.0, 2.5,"IGOR");
-task->AddBin("psi","pt", 2.5, 3.0,"IGOR");
-task->AddBin("psi","pt", 3.0, 3.5,"IGOR");
-task->AddBin("psi","pt", 3.5, 4.0,"IGOR");
-task->AddBin("psi","pt", 4.0, 4.5,"IGOR");
-task->AddBin("psi","pt", 4.5, 5.0,"IGOR");
-task->AddBin("psi","pt", 5.0, 6.0,"IGOR");
-task->AddBin("psi","pt", 6.0, 7.0,"IGOR");
-task->AddBin("psi","pt", 7.0, 8.0,"IGOR");
-task->AddBin("psi","pt", 8.0, 9.0,"IGOR");
-task->AddBin("psi","pt", 9.0,11.0,"IGOR");
-task->AddBin("psi","pt",11.0,13.0,"IGOR");
-task->AddBin("psi","pt",13.0,15.0,"IGOR");
-
-// roberta binning
-task->AddBin("psi","pt",0.0,1.0,"ROBERTA");
-task->AddBin("psi","pt",1.0,2.0,"ROBERTA");
-task->AddBin("psi","pt",2.0,3.0,"ROBERTA");
-task->AddBin("psi","pt",3.0,4.0,"ROBERTA");
-task->AddBin("psi","pt",4.0,5.0,"ROBERTA");
-task->AddBin("psi","pt",5.0,6.0,"ROBERTA");
-task->AddBin("psi","pt",6.0,8.0,"ROBERTA");
-
-/*
-
-  for ( Int_t i = 0; i < 10; ++i ) 
+  AliAnalysisMuMuCutElement* ps = eventTrue;
+  
+  if (!simulations)
   {
-    Double_t xmin = i*1.0;
-    
-       task->AddBin("psi","pt",xmin,xmin+1.0);
+    ps = cr->AddEventCut(*eventCutter,"IsPhysicsSelected","const AliInputEventHandler&","");
   }
 
-  for ( Int_t i = 0; i < 5; ++i ) 
-  {
-    Double_t xmin = 10+i*2.0;
-    
-       task->AddBin("psi","pt",xmin,xmin+2.0);
-  }
+  AliAnalysisMuMuCutElement* triggerSelection = cr->AddTriggerClassCut(*eventCutter,"SelectTriggerClass","const TString&,TString&,UInt_t,UInt_t,UInt_t","");
 
-  for ( Int_t i = 0; i < 6; ++i ) 
+  cr->AddCutCombination(triggerSelection);
+  
+//  AliAnalysisMuMuCutElement* cutVDM = cr->AddEventCut(*eventCutter,"IsPhysicsSelectedVDM","const AliVEvent&","");
+//
+//  AliAnalysisMuMuCutElement* cutTZEROPileUp = cr->AddEventCut(*eventCutter,"IsTZEROPileUp","const AliVEvent&","");
+//
+//  AliAnalysisMuMuCutElement* notTZEROPileUp = cr->Not(*cutTZEROPileUp);
+
+  cr->AddCutCombination(ps);
+
+  task->SetBeamYear(beamYear);
+
+  AliAnalysisMuMuGlobal* globalAnalysis = 0x0;//new AliAnalysisMuMuGlobal;
+  
+  AliAnalysisMuMuSingle* singleAnalysis = new AliAnalysisMuMuSingle;
+  
+  AliAnalysisMuMuMinv* minvAnalysis = new AliAnalysisMuMuMinv;
+
+//  TFile f("$HOME/Downloads/ResponseMatrix_QASPDZPSALL_ANY.root");
+//  TH2* h = static_cast<TH2*>(f.Get("ResponseMatrix"));
+  
+  AliAnalysisMuMuNch* nchAnalysis = new AliAnalysisMuMuNch; // (0x0,-2,2,-40,40);
+  
+//  AliAnalysisMuMuNch(TH2* spdCorrection=0x0,
+//                     Int_t nbinsEta=10, Double_t etaMin=-0.5, Double_t etaMax=0.5,
+//                     Int_t nbinsZ=320, Double_t zmin=-40, Double_t zmax=40);
+
+
+  if ( globalAnalysis )
   {
-    Double_t xmin = -4+i*0.25;
+    AliAnalysisMuMuCutElement* triggerAll = cr->AddTriggerClassCut(*globalAnalysis,"SelectAnyTriggerClass","const TString&,TString&","");
+    
+    cr->AddCutCombination(triggerAll);
     
-       task->AddBin("psi","y",xmin,xmin+0.25);
+    task->AdoptSubAnalysis(globalAnalysis);
   }
-
-  Int_t nphiSteps = 18;
   
-  for ( Int_t i = 0; i < nphiSteps; ++i ) 
+  if ( nchAnalysis )
   {
-    Double_t xstep = 2*TMath::Pi()/nphiSteps;
-    Double_t xmin = -TMath::Pi() + i*xstep;
+//    AliAnalysisMuMuCutElement* trketa2 = cr->AddEventCut(*nchAnalysis,"HasAtLeastNTrackletsInEtaRange","const AliVEvent&,Int_t, Double_t& , Double_t& ","1,-2.0,2.0");
+//    AliAnalysisMuMuCutElement* trketa1 = cr->AddEventCut(*nchAnalysis,"HasAtLeastNTrackletsInEtaRange","const AliVEvent&,Int_t, Double_t& , Double_t& ","1,-1.0,1.0");
+//    AliAnalysisMuMuCutElement* trk5eta1 = cr->AddEventCut(*nchAnalysis,"HasAtLeastNTrackletsInEtaRange","const AliVEvent&,Int_t, Double_t& , Double_t& ","5,-1.0,1.0");
+//    
+//    cr->AddCutCombination(ps,trketa1);
+//    cr->AddCutCombination(ps,trk5eta1);
+//    cr->AddCutCombination(ps,trketa2);
+    
+    AliAnalysisMuMuCutElement* cutZ18= cr->AddEventCut(*eventCutter,"IsAbsZBelowValue","const AliVEvent&,Double_t","18");
+    
+    AliAnalysisMuMuCutElement* cutZ10 = cr->AddEventCut(*eventCutter,"IsAbsZBelowValue","const AliVEvent&,Double_t","10");
     
-       task->AddBin("psi","phi",xmin,xmin+xstep);
+    cr->AddCutCombination(ps,cutZ18);
+    cr->AddCutCombination(ps,cutZ10);
+    
+    task->AdoptSubAnalysis(nchAnalysis);
   }
   
-  */
-  
-  Double_t ymin(-4.0);
-  Double_t ymax(-3.43);
+  if ( singleAnalysis )
+  {
+    AliAnalysisMuMuCutElement* trackTrue = cr->AddTrackCut(*cr,"AlwaysTrue","const AliVParticle&","");
+    AliAnalysisMuMuCutElement* rabs = cr->AddTrackCut(*singleAnalysis,"IsRabsOK","const AliVParticle&","");
+    AliAnalysisMuMuCutElement* eta = cr->AddTrackCut(*singleAnalysis,"IsEtaInRange","const AliVParticle&,Double_t&,Double_t&","-4.0,-2.5");
+    
+    cr->AddCutCombination(trackTrue);
 
-  Double_t ymin(-4.0);
-  Double_t ymax(-3.43);
+    cr->AddCutCombination(rabs);
+    
+    cr->AddCutCombination(eta);
+
+    cr->AddCutCombination(rabs,eta);
 
-  task->AddBin("psi","y",-4,-2.5,"ILAB");
+    task->AdoptSubAnalysis(singleAnalysis);
+
+    if ( minvAnalysis )
+    {
+      AliAnalysisMuMuCutElement* pairTrue = cr->AddTrackPairCut(*cr,"AlwaysTrue","const AliVParticle&, const AliVParticle&","");
+      
+      AliAnalysisMuMuCutElement* pairy = cr->AddTrackPairCut(*minvAnalysis,"IsRapidityInRange","const AliVParticle&,const AliVParticle&,Double_t&,Double_t&","-4,-2.5");
   
-  task->AddBin("psi","y",ymin,ymax,"ICOMMON");
+      cr->AddCutCombination(rabs,eta,pairy);
 
-  for ( Int_t i = 0; i < 6; ++i ) 
-  {
-    Double_t y = -4+i*0.25;
-    
-    task->AddBin("psi","y",y,y+0.25,"6PACK");
-  }
+      cr->AddCutCombination(rabs,pairy);
 
-/*  
-  for ( Int_t i = 0; i < 20; ++i ) 
-  {
-    Double_t xmin = i*0.25;
-    
-       task->AddBin("psi","y vs pt",xmin,xmin+0.25,ymin,ymax);
+      cr->AddCutCombination(pairy);
+
+      cr->AddCutCombination(pairTrue);
+
+      task->AdoptSubAnalysis(minvAnalysis);
+    }
   }
+  
+  /// below are the kind of configurations that can be performed :
+  /// - adding cuts (at event, track or pair level)
+  /// - adding bins (in pt, y, centrality, etc...) for minv (and meanpt)
 
-  for ( Int_t i = 0; i < 4; ++i ) 
+  AliAnalysisMuMuBinning* binning = task->Binning();
+  
+  if (minvAnalysis)
   {
-    Double_t xmin = 5+i*1.0;
+    binning->AddBin("psi","pt");
+    
+    // pt binning
+    
+    binning->AddBin("psi","pt", 0.0, 1.0,"IGOR");
+    binning->AddBin("psi","pt", 1.0, 2.0,"IGOR");
+    binning->AddBin("psi","pt", 2.0, 3.0,"IGOR");
+    binning->AddBin("psi","pt", 3.0, 4.0,"IGOR");
+    binning->AddBin("psi","pt", 4.0, 5.0,"IGOR");
+    binning->AddBin("psi","pt", 5.0, 6.0,"IGOR");
+    binning->AddBin("psi","pt", 6.0, 7.0,"IGOR");
+    binning->AddBin("psi","pt", 7.0, 9.0,"IGOR");
+    binning->AddBin("psi","pt", 9.0,11.0,"IGOR");
+    binning->AddBin("psi","pt",11.0,15.0,"IGOR");
+    binning->AddBin("psi","pt",15.0,25.0,"IGOR");
+    
+    // y binning
     
-       task->AddBin("psi","y vs pt",xmin,xmin+1.0,ymin,ymax);
+    binning->AddBin("psi","y",-4,-2.5,"ILAB");
+    
+    for ( Int_t i = 0; i < 6; ++i )
+    {
+      Double_t y = -4+i*0.25;
+      
+      binning->AddBin("psi","y",y,y+0.25,"6PACK");
+    }
+    
+    // nch binning
+    if (nchAnalysis)
+    {
+      binning->AddBin("psi","nch",0.0,30.0,"JAVI"); // 0 - 29
+      binning->AddBin("psi","nch",29.0,42.0,"JAVI"); // 30 - 41
+      binning->AddBin("psi","nch",41.0,56.0,"JAVI"); // 42 - 55
+      binning->AddBin("psi","nch",55.0,72.0,"JAVI"); // 56 - 72
+      binning->AddBin("psi","nch",72.0,301.0,"JAVI"); // 73 - 300
+    }
   }
+  
+  // v0 centrality binning
+  
+  binning->AddBin("centrality","v0a");
+//  binning->AddBin("centrality","v0a",0,5);
+//  binning->AddBin("centrality","v0a",5,10);
+//  binning->AddBin("centrality","v0a",10,20);
+//  binning->AddBin("centrality","v0a",20,40);
+//  binning->AddBin("centrality","v0a",40,60);
+//  binning->AddBin("centrality","v0a",60,80);
+//  binning->AddBin("centrality","v0a",80,100);
 
-*/
-/*
-  task->CreateMesh("psi","pt","y");
-*/
-
+  // disable some histograms if we don't want them
   task->DisableHistograms("^V02D");
   task->DisableHistograms("^dca");
   task->DisableHistograms("^Chi12");
   task->DisableHistograms("^Rabs12");
-  
+
+  // add the configured task to the analysis manager
   mgr->AddTask(task);  
   
-  static int n(0);
-  
-  ++n;
-  
-  if ( n > 1 ) containerName += Form("%d",n);
-  
   // Create containers for input/output
   AliAnalysisDataContainer *cinput = mgr->GetCommonInputContainer();  
 
   AliAnalysisDataContainer *coutputHC = 
-  mgr->CreateContainer("HC",AliMergeableCollection::Class(),AliAnalysisManager::kOutputContainer,outputname);
+  mgr->CreateContainer("OC",AliMergeableCollection::Class(),AliAnalysisManager::kOutputContainer,outputname);
 
   AliAnalysisDataContainer *coutputCC = 
   mgr->CreateContainer("CC",AliCounterCollection::Class(),AliAnalysisManager::kOutputContainer,outputname);
diff --git a/PWG/muon/AliAnalysisMuMuBase.cxx b/PWG/muon/AliAnalysisMuMuBase.cxx
new file mode 100644 (file)
index 0000000..a6a5330
--- /dev/null
@@ -0,0 +1,416 @@
+#include "AliAnalysisMuMuBase.h"
+
+/**
+ *
+ * \ingroup pwg-muon-mumu
+ *
+ * \class AliAnalysisMuMuBase
+ *
+ * Defines the interface of a sub-analysis to be steered by AliAnalysisTaskMuMu
+ *
+ * Daugther class has to implement one method :
+ *
+ * - \ref DefineHistogramCollection
+ *
+ * It may implement one or several of the FillHistosForXXX methods :
+ *
+ * - \ref FillHistosForEvent to fill histograms for one event
+ * - \ref FillHistosForMCEvent to fill histograms for one MC event
+ * - \ref FillHistosForTrack to fill histograms for one track
+ * - \ref FillHistosForPair to fill histograms for one muon track pair
+ *
+ * More rarely it may also implement :
+ *
+ * - \ref SetRun to do some changes when run number changes
+ * - \ref Terminate to finalize before ending
+ * - \ref SetEvent to e.g. append information to VEvent
+ *
+ * Daugther class can use the following methods :
+ *
+ * - \ref HasMC to know if MC information is available in the analyzed data
+ * - \ref Event to access the current event
+ * - \ref MCEvent to access to current MC event (if available)
+ *
+ * A few trivial cut methods (\ref AlwaysTrue and \ref AlwaysFalse) are defined as well and
+ * can be used to register some control cut combinations (see \ref AliAnalysisMuMuCutCombination)
+ *
+ */
+
+#include "AliMergeableCollection.h"
+#include "AliCounterCollection.h"
+#include "TList.h"
+#include "TObjString.h"
+#include "TMath.h"
+#include "TObjArray.h"
+#include "AliLog.h"
+#include "AliAnalysisMuMuBinning.h"
+#include "TH1F.h"
+#include "TH2F.h"
+#include "TProfile.h"
+#include "TRegexp.h"
+#include "AliVEvent.h"
+#include "AliAODEvent.h"
+#include "AliESDEvent.h"
+#include "AliLog.h"
+#include "AliAnalysisMuMuCutCombination.h"
+#include "AliAnalysisMuMuCutRegistry.h"
+
+ClassImp(AliAnalysisMuMuBase)
+
+namespace
+{
+    const char* MCINPUTPREFIX = "MCINPUT";
+};
+
+//_____________________________________________________________________________
+AliAnalysisMuMuBase::AliAnalysisMuMuBase()
+:
+TObject(),
+fEventCounters(0x0),
+fHistogramCollection(0x0),
+fBinning(0x0),
+fCutRegistry(0x0),
+fEvent(0x0),
+fMCEvent(0x0),
+fHistogramToDisable(0x0),
+fHasMC(kFALSE)
+{
+ /// default ctor
+}
+
+//_____________________________________________________________________________
+void
+AliAnalysisMuMuBase::CreateEventHistos(UInt_t dataType,
+                                       const char* what,
+                                       const char* hname, const char* htitle,
+                                       Int_t nbinsx, Double_t xmin, Double_t xmax,
+                                       Int_t nbinsy, Double_t ymin, Double_t ymax) const
+{
+  /** Append histograms at the event level. Depending on dataType the created histograms
+   * are for real data only, MC data only, or both
+   */
+  
+  if ( IsHistogramDisabled(hname) ) return;
+  
+  TObjArray pathNames;
+  pathNames.SetOwner(kTRUE);
+  
+  if ( dataType & kHistoForData )
+  {
+    pathNames.Add(new TObjString(Form("/%s",what)));
+  }
+  if ( ( dataType & kHistoForMCInput ) && HasMC() )
+  {
+    pathNames.Add(new TObjString(Form("/%s/%s",MCINPUTPREFIX,what)));
+  }
+  
+  CreateHistos(pathNames,hname,htitle,nbinsx,xmin,xmax,nbinsy,ymin,ymax);
+}
+
+//_____________________________________________________________________________
+void
+AliAnalysisMuMuBase::CreateEventHistos(UInt_t dataType,
+                                       const char* eventSelection,
+                                       const char* triggerClassName,
+                                       const char* centrality,
+                                       const char* hname, const char* htitle,
+                                       Int_t nbinsx, Double_t xmin, Double_t xmax,
+                                       Int_t nbinsy, Double_t ymin, Double_t ymax) const
+{
+  /** Append histograms at the event level. Depending on dataType the created histograms
+   * are for real data only, MC data only, or both
+   */
+  
+  if ( IsHistogramDisabled(hname) ) return;
+  
+  TObjArray pathNames;
+  pathNames.SetOwner(kTRUE);
+
+  if ( dataType & kHistoForData )
+  {
+    pathNames.Add(new TObjString(Form("/%s/%s/%s",eventSelection,triggerClassName,centrality)));
+  }
+  if ( ( dataType & kHistoForMCInput ) && HasMC() )
+  {
+    pathNames.Add(new TObjString(Form("/%s/%s/%s/%s",MCINPUTPREFIX,eventSelection,triggerClassName,centrality)));
+  }
+  
+  CreateHistos(pathNames,hname,htitle,nbinsx,xmin,xmax,nbinsy,ymin,ymax);
+}
+
+//_____________________________________________________________________________
+void
+AliAnalysisMuMuBase::CreateHistos(const TObjArray& paths,
+                                  const char* hname, const char* htitle,
+                                  Int_t nbinsx, Double_t xmin, Double_t xmax,
+                                  Int_t nbinsy, Double_t ymin, Double_t ymax) const
+{
+  /// Create multiple copies of histogram hname, one per path
+  
+  if ( IsHistogramDisabled(hname) ) return;
+
+  StdoutToAliDebug(1,paths.Print(););
+  
+  TIter next(&paths);
+  TObjString* pathName;
+
+  while ( ( pathName = static_cast<TObjString*>(next()) ) )
+  {
+    TH1* h(0x0);
+    
+    if ( nbinsy > 0 )
+    {
+      AliDebug(1,Form("Created TH2F %s/%s",pathName->String().Data(),hname));
+      h = new TH2F(hname,htitle,nbinsx,xmin,xmax,nbinsy,ymin,ymax);
+    }
+    else if ( nbinsy == 0 )
+    {
+      AliDebug(1,Form("Created TProfile %s/%s",pathName->String().Data(),hname));
+      h = new TProfile(hname,htitle,nbinsx,xmin,xmax,ymin,ymax);
+      h->Sumw2();
+    }
+    else
+    {
+      AliDebug(1,Form("Created TH1F %s/%s",pathName->String().Data(),hname));
+      h = new TH1F(hname,htitle,nbinsx,xmin,xmax);
+      
+      if ( nbinsy < -1 )
+      {
+        h->Sumw2();
+      }
+    }
+    
+    HistogramCollection()->Adopt(pathName->String().Data(),h);
+  }
+  
+  StdoutToAliDebug(1,HistogramCollection()->Print("*"););
+}
+
+//_____________________________________________________________________________
+void
+AliAnalysisMuMuBase::CreateTrackHistos(const char* eventSelection,
+                                       const char* triggerClassName,
+                                       const char* centrality,
+                                       const char* hname, const char* htitle,
+                                       Int_t nbinsx, Double_t xmin, Double_t xmax,
+                                       Int_t nbinsy, Double_t ymin, Double_t ymax) const
+{
+  /// Create n copies of an histogram (with name=hname, title=htitle, etc..)
+  /// where n = # of track cut combinations defined
+  /// see also CreateHistos
+  
+  
+  if ( IsHistogramDisabled(hname) ) return;
+  
+  TObjArray pathNames;
+  pathNames.SetOwner(kTRUE);
+  
+  TIter nextCutCombination(CutRegistry()->GetCutCombinations(AliAnalysisMuMuCutElement::kTrack));
+  AliAnalysisMuMuCutCombination* cutCombination;
+  
+  while ( ( cutCombination = static_cast<AliAnalysisMuMuCutCombination*>(nextCutCombination())) )
+  {
+    pathNames.Add(new TObjString(Form("/%s/%s/%s/%s",eventSelection,triggerClassName,centrality,cutCombination->GetName())));
+  }
+  
+  CreateHistos(pathNames,hname,htitle,nbinsx,xmin,xmax,nbinsy,ymin,ymax);
+}
+
+//_____________________________________________________________________________
+void
+AliAnalysisMuMuBase::CreatePairHistos(const char* eventSelection,
+                                       const char* triggerClassName,
+                                       const char* centrality,
+                                       const char* hname, const char* htitle,
+                                       Int_t nbinsx, Double_t xmin, Double_t xmax,
+                                       Int_t nbinsy, Double_t ymin, Double_t ymax) const
+{
+  /// Create n copies of an histogram (with name=hname, title=htitle, etc..)
+  /// where n = # of track *pair* cut combinations defined
+  /// see also CreateHistos
+  
+  
+  if ( IsHistogramDisabled(hname) ) return;
+  
+  TObjArray pathNames;
+  pathNames.SetOwner(kTRUE);
+  
+  TIter nextCutCombination(CutRegistry()->GetCutCombinations(AliAnalysisMuMuCutElement::kTrackPair));
+  AliAnalysisMuMuCutCombination* cutCombination;
+  
+  while ( ( cutCombination = static_cast<AliAnalysisMuMuCutCombination*>(nextCutCombination())) )
+  {
+    pathNames.Add(new TObjString(Form("/%s/%s/%s/%s",eventSelection,triggerClassName,centrality,cutCombination->GetName())));
+  }
+  
+  CreateHistos(pathNames,hname,htitle,nbinsx,xmin,xmax,nbinsy,ymin,ymax);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuBase::DisableHistograms(const char* pattern)
+{
+  /// Disable the histogramming of all the histograms matching the pattern
+  
+  TString spattern(pattern);
+  if (spattern=="*")
+  {
+    delete fHistogramToDisable;
+    fHistogramToDisable = 0x0;
+  }
+  
+  if (!fHistogramToDisable)
+  {
+    fHistogramToDisable = new TList;
+    fHistogramToDisable->SetOwner(kTRUE);
+  }
+  
+  fHistogramToDisable->Add(new TObjString(spattern));
+}
+
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuBase::GetNbins(Double_t xmin, Double_t xmax, Double_t xstep)
+{
+  /// Compute number of bins to get a given step between each values in the xmin,xmax range
+  if ( TMath::AreEqualRel(xstep,0.0,1E-9) ) return 1;
+  
+  return TMath::Nint(TMath::Abs((xmax-xmin)/xstep));
+}
+
+//_____________________________________________________________________________
+TH1* AliAnalysisMuMuBase::Histo(const char* eventSelection, const char* triggerClassName, const char* histoname)
+{
+  /// Get one histo back
+  return fHistogramCollection ? fHistogramCollection->Histo(Form("/%s/%s/%s",eventSelection,triggerClassName,histoname)) : 0x0;
+}
+
+//_____________________________________________________________________________
+TH1* AliAnalysisMuMuBase::Histo(const char* eventSelection, const char* histoname)
+{
+  /// Get one histo back
+  return fHistogramCollection ? fHistogramCollection->Histo(eventSelection,histoname) : 0x0;
+}
+
+//_____________________________________________________________________________
+TH1* AliAnalysisMuMuBase::Histo(const char* eventSelection,
+                                const char* triggerClassName,
+                                const char* cent,
+                                const char* histoname)
+{
+  /// Get one histo back
+  return fHistogramCollection ? fHistogramCollection->Histo(Form("/%s/%s/%s",eventSelection,triggerClassName,cent),histoname) : 0x0;
+}
+
+//_____________________________________________________________________________
+TH1* AliAnalysisMuMuBase::Histo(const char* eventSelection,
+                                const char* triggerClassName,
+                                const char* cent,
+                                const char* what,
+                                const char* histoname)
+{
+  /// Get one histo back
+  
+  return fHistogramCollection ? fHistogramCollection->Histo(Form("/%s/%s/%s/%s",eventSelection,triggerClassName,cent,what),histoname) : 0x0;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuBase::Init(AliCounterCollection& cc,
+                               AliMergeableCollection& hc,
+                               const AliAnalysisMuMuBinning& binning,
+                               const AliAnalysisMuMuCutRegistry& registry)
+{
+  /// Set the internal references
+  fEventCounters = &cc;
+  fHistogramCollection = &hc;
+  fBinning = &binning;
+  fCutRegistry = &registry;
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuBase::IsHistogramDisabled(const char* hname) const
+{
+  /// Whether or not a given histogram (identified by its name)
+  /// is disabled or not
+  
+  if ( !fHistogramToDisable )
+  {
+    return kFALSE;
+  }
+  TString shname(hname);
+  TIter next(fHistogramToDisable);
+  TObjString* str(0x0);
+  
+  while ( ( str = static_cast<TObjString*>(next()) ) )
+  {
+    if ( shname.Contains(TRegexp(str->String()) ) )
+    {
+      return kTRUE;
+    }
+  }
+  return kFALSE;
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuBase::IsHistogrammingDisabled() const
+{
+  /// Whether or not *all* histograms are disabled
+  
+  if ( fHistogramToDisable && fHistogramToDisable->GetEntries()==1 )
+  {
+    TObjString* r = static_cast<TObjString*>(fHistogramToDisable->First());
+    if ( r->String() == "*" )
+    {
+      return kTRUE;
+    }
+  }
+  return kFALSE;
+}
+
+//_____________________________________________________________________________
+TH1* AliAnalysisMuMuBase::MCHisto(const char* eventSelection, const char* triggerClassName, const char* histoname)
+{
+  /// Get one histo back
+  return fHistogramCollection ? fHistogramCollection->Histo(Form("/%s/%s/%s/%s",MCINPUTPREFIX,eventSelection,triggerClassName,histoname)) : 0x0;
+}
+
+//_____________________________________________________________________________
+TH1* AliAnalysisMuMuBase::MCHisto(const char* eventSelection, const char* histoname)
+{
+  /// Get one histo back
+  return fHistogramCollection ? fHistogramCollection->Histo(Form("/%s/%s/%s",MCINPUTPREFIX,eventSelection,histoname)) : 0x0;
+}
+
+//_____________________________________________________________________________
+TH1* AliAnalysisMuMuBase::MCHisto(const char* eventSelection,
+                                  const char* triggerClassName,
+                                  const char* cent,
+                                  const char* histoname)
+{
+  /// Get one histo back
+  return fHistogramCollection ? fHistogramCollection->Histo(Form("/%s/%s/%s/%s",MCINPUTPREFIX,eventSelection,triggerClassName,cent),histoname) : 0x0;
+}
+
+//_____________________________________________________________________________
+TH1* AliAnalysisMuMuBase::MCHisto(const char* eventSelection,
+                                  const char* triggerClassName,
+                                  const char* cent,
+                                  const char* what,
+                                  const char* histoname)
+{
+  /// Get one histo back
+  
+  return fHistogramCollection ? fHistogramCollection->Histo(Form("/%s/%s/%s/%s/%s",MCINPUTPREFIX,eventSelection,triggerClassName,cent,what),histoname) : 0x0;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuBase::SetEvent(AliVEvent* event, AliMCEvent* mcEvent)
+{
+  /// Set pointers to event (and mcEvent)
+  /// This is the place where a sub analysis might (if really needed)
+  /// append things to the event. Please DO NOT alter the original content,
+  /// only add to it. Unless of course you want to shoot yourself in the
+  /// foot...
+  
+  fEvent = event;
+  fMCEvent = mcEvent;
+}
+
diff --git a/PWG/muon/AliAnalysisMuMuBase.h b/PWG/muon/AliAnalysisMuMuBase.h
new file mode 100644 (file)
index 0000000..e8e672a
--- /dev/null
@@ -0,0 +1,169 @@
+#ifndef ALIANALYSISMUMUBASE_H
+#define ALIANALYSISMUMUBASE_H
+
+/**
+ *
+ * \class AliAnalysisMuMuBase
+ *
+ * \brief Base class of the sub-analysis for AliAnalysisTaskMuMu
+ *
+ * \author L. Aphecetche (Subatech)
+ */
+
+#include "TObject.h"
+#include "TString.h"
+
+class AliCounterCollection;
+class AliAnalysisMuMuBinning;
+class AliMergeableCollection;
+class AliVParticle;
+class AliVEvent;
+class AliMCEvent;
+class TH1;
+class AliInputEventHandler;
+class AliAnalysisMuMuCutRegistry;
+
+class AliAnalysisMuMuBase : public TObject
+{
+public:
+
+  AliAnalysisMuMuBase();
+  virtual ~AliAnalysisMuMuBase() {}
+
+  /** Define the histograms needed for the path starting at eventSelection/triggerClassName/centrality.
+   * This method has to ensure the histogram creation is performed only once !
+   */
+  virtual void DefineHistogramCollection(const char* eventSelection,
+                                         const char* triggerClassName,
+                                         const char* centrality) = 0;
+
+  /** Fill histograms for one event */
+  virtual void FillHistosForEvent(const char* /*eventSelection*/,const char* /*triggerClassName*/,const char* /*centrality*/) {}
+
+  /** Fill histograms for one MC event */
+  virtual void FillHistosForMCEvent(const char* /*eventSelection*/,const char* /*triggerClassName*/,const char* /*centrality*/) {}
+  
+  /** Fill histograms for one track */
+  virtual void FillHistosForTrack(const char* /*eventSelection*/,const char* /*triggerClassName*/,const char* /*centrality*/,
+                                  const char* /*trackCutName*/,
+                                  const AliVParticle& /*part*/) {}
+
+  /** Fill histograms for one track pair */
+  virtual void FillHistosForPair(const char* /*eventSelection*/,const char* /*triggerClassName*/,const char* /*centrality*/,
+                                 const char* /*pairCutName*/,
+                                 const AliVParticle& /*part1*/,
+                                 const AliVParticle& /*part2*/) {}
+  
+  virtual void Init(AliCounterCollection& cc,
+                    AliMergeableCollection& hc,
+                    const AliAnalysisMuMuBinning& binning,
+                    const AliAnalysisMuMuCutRegistry& cutRegister);
+
+  virtual void SetEvent(AliVEvent* event, AliMCEvent* mcEvent=0x0);
+
+  virtual Bool_t IsHistogramDisabled(const char* hname) const;
+  
+  virtual Bool_t IsHistogrammingDisabled() const;
+  
+  virtual void DisableHistograms(const char* pattern="*");
+  
+  AliVEvent* Event() const { return fEvent; }
+  
+  AliMCEvent* MCEvent() const { return fMCEvent; }
+  
+  /// Called at each new run
+  void SetRun(const AliInputEventHandler* /*eventHandler*/) {}
+
+  void Terminate(Option_t* /*opt*/="") {}
+  
+  enum EDataType
+  {
+    kHistoForMCInput = (1<<0),
+    kHistoForData = (1<<1)
+  };
+  
+  void SetMC() { fHasMC = kTRUE; }
+  
+  Bool_t HasMC() const { return fHasMC; }
+  
+  Bool_t AlwaysTrue(const AliVEvent& /*event*/) const { return kTRUE; }
+  Bool_t AlwaysTrue(const AliVParticle& /*particle*/) const { return kTRUE; }
+  Bool_t AlwaysTrue(const AliVParticle& /*particle*/, const AliVParticle& /*particle*/) const { return kTRUE; }
+  void NameOfAlwaysTrue(TString& name) const { name = "ALL"; }
+
+  Bool_t AlwaysFalse(const AliVEvent& /*event*/) const { return kFALSE; }
+  Bool_t AlwaysFalse(const AliVParticle& /*particle*/) const { return kFALSE; }
+  Bool_t AlwaysFalse(const AliVParticle& /*particle*/, const AliVParticle& /*particle*/) const { return kFALSE; }
+  void NameOfAlwaysFalse(TString& name) const { name = "NONE"; }
+  
+protected:
+
+  void CreateHistos(const TObjArray& paths,
+                    const char* hname, const char* htitle,
+                    Int_t nbinsx, Double_t xmin, Double_t xmax,
+                    Int_t nbinsy=-1, Double_t ymin=0.0, Double_t ymax=0.0) const;
+
+  void CreateEventHistos(UInt_t dataType,
+                         const char* what,
+                         const char* hname, const char* htitle,
+                         Int_t nbinsx, Double_t xmin, Double_t xmax,
+                         Int_t nbinsy=-1, Double_t ymin=0.0, Double_t ymax=0.0) const;
+
+  void CreateEventHistos(UInt_t dataType,
+                         const char* eventSelection,
+                         const char* triggerClassName,
+                         const char* centrality,
+                         const char* hname, const char* htitle,
+                         Int_t nbinsx, Double_t xmin, Double_t xmax,
+                         Int_t nbinsy=-1, Double_t ymin=0.0, Double_t ymax=0.0) const;
+  
+  
+  void CreateTrackHistos(const char* eventSelection,
+                         const char* triggerClassName,
+                         const char* centrality,
+                         const char* hname, const char* htitle,
+                         Int_t nbinsx, Double_t xmin, Double_t xmax,
+                         Int_t nbinsy=-1, Double_t ymin=0.0, Double_t ymax=0.0) const;
+  
+  void CreatePairHistos(const char* eventSelection,
+                        const char* triggerClassName,
+                        const char* centrality,
+                        const char* hname, const char* htitle,
+                        Int_t nbinsx, Double_t xmin, Double_t xmax,
+                        Int_t nbinsy=-1, Double_t ymin=0.0, Double_t ymax=0.0) const;
+
+  TH1* Histo(const char* eventSelection, const char* histoname);
+  TH1* Histo(const char* eventSelection, const char* triggerClassName, const char* histoname);
+  TH1* Histo(const char* eventSelection, const char* triggerClassName, const char* cent, const char* histoname);
+  TH1* Histo(const char* eventSelection, const char* triggerClassName, const char* cent,
+             const char* what, const char* histoname);
+
+  TH1* MCHisto(const char* eventSelection, const char* histoname);
+  TH1* MCHisto(const char* eventSelection, const char* triggerClassName, const char* histoname);
+  TH1* MCHisto(const char* eventSelection, const char* triggerClassName, const char* cent, const char* histoname);
+  TH1* MCHisto(const char* eventSelection, const char* triggerClassName, const char* cent,
+             const char* what, const char* histoname);
+
+  Int_t GetNbins(Double_t xmin, Double_t xmax, Double_t xstep);
+
+  AliCounterCollection* CounterCollection() const { return fEventCounters; }
+  AliMergeableCollection* HistogramCollection() const { return fHistogramCollection; }
+  const AliAnalysisMuMuBinning* Binning() const { return fBinning; }
+  const AliAnalysisMuMuCutRegistry* CutRegistry() const { return fCutRegistry; }
+  
+private:
+  
+  AliCounterCollection* fEventCounters; //! event counters
+  AliMergeableCollection* fHistogramCollection; //! collection of histograms
+  const AliAnalysisMuMuBinning* fBinning; //! binning for particles
+  const AliAnalysisMuMuCutRegistry* fCutRegistry; //! registry of cut combinations
+  AliVEvent* fEvent; //! current event
+  AliMCEvent* fMCEvent; //! current MC event
+  TList* fHistogramToDisable; // list of regexp of histo name to disable
+  Bool_t fHasMC; // whether or not we're dealing with MC data
+  
+  ClassDef(AliAnalysisMuMuBase,1) // base class for a companion class to AliAnalysisMuMu
+};
+
+#endif
+
index 00451fe9cf313d456ea6a71332e645ba05df3bee..3d4eb92e28533eaf5e62dd2baf2d776697ab0093 100644 (file)
@@ -75,62 +75,62 @@ AliAnalysisMuMuBinning::~AliAnalysisMuMuBinning()
 void AliAnalysisMuMuBinning::AddBin(const AliAnalysisMuMuBinning::Range& bin)
 {
   /// add one bin
-  AddBin(bin.Particle().Data(),bin.Type().Data(),
+  AddBin(bin.What().Data(),bin.Quantity().Data(),
          bin.Xmin(),bin.Xmax(),
          bin.Ymin(),bin.Ymax(),bin.Flavour());
 }
 
 //______________________________________________________________________________
-void AliAnalysisMuMuBinning::AddBin(const char* particle, const char* type,
+void AliAnalysisMuMuBinning::AddBin(const char* what, const char* quantity,
                                     Double_t xmin, Double_t xmax,
                                     Double_t ymin, Double_t ymax,
                                     const char* flavour)
 {
   /// Add a bin
-  /// Note that particle and type are not case sensitive.
+  /// Note that what and Quantity are not case sensitive.
   if (!fBins)
   {
     fBins = new TMap;
     fBins->SetOwnerKeyValue(kTRUE,kTRUE);
   }
   
-  TString sparticle(particle);
-  sparticle.ToUpper();
+  TString swhat(what);
+  swhat.ToUpper();
   
-  TString stype(type);
-  stype.ToUpper();
+  TString sQuantity(quantity);
+  sQuantity.ToUpper();
   
-  TObjArray* b = static_cast<TObjArray*>(fBins->GetValue(sparticle.Data()));
+  TObjArray* b = static_cast<TObjArray*>(fBins->GetValue(swhat.Data()));
   if (!b)
   {
     b = new TObjArray;
     b->SetOwner(kTRUE);
-    fBins->Add(new TObjString(sparticle),b);
+    fBins->Add(new TObjString(swhat),b);
   }
 
-  Range* r = new Range(sparticle.Data(),stype.Data(),xmin,xmax,ymin,ymax,flavour);
+  Range* r = new Range(swhat.Data(),sQuantity.Data(),xmin,xmax,ymin,ymax,flavour);
   
   if ( b->FindObject(r) )
   {
-    AliDebug(1,"Trying to add an already existing bin. Not doing it.");
+    AliDebug(1,Form("Trying to add an already existing bin : %s. Not doing it.",r->AsString().Data()));
     delete r;
   }
   else
   {
     b->Add(r);
     
-    TString btype(Form("%s-%s",sparticle.Data(),stype.Data()));
+    TString bQuantity(Form("%s-%s",swhat.Data(),sQuantity.Data()));
     
     TString name(GetName());
     
-    if ( !name.Contains(btype) )
+    if ( !name.Contains(bQuantity) )
     {
       if (name.Length()>0)
       {
         name += " ";
       }
         
-      name += btype;
+      name += bQuantity;
       SetName(name);
     }
   }
@@ -174,12 +174,12 @@ TObjArray* AliAnalysisMuMuBinning::CreateBinObjArray() const
   TObjArray* a = new TObjArray;
   a->SetOwner(kTRUE);
 
-  TIter nextParticle(fBins);
-  TObjString* particle;
+  TIter nextwhat(fBins);
+  TObjString* what;
   
-  while ( ( particle = static_cast<TObjString*>(nextParticle()) ) )
+  while ( ( what = static_cast<TObjString*>(nextwhat()) ) )
   {
-    TObjArray* b = static_cast<TObjArray*>(fBins->GetValue(particle->String().Data()));
+    TObjArray* b = static_cast<TObjArray*>(fBins->GetValue(what->String().Data()));
     TIter next(b);
     Range* r;
   
@@ -198,9 +198,9 @@ TObjArray* AliAnalysisMuMuBinning::CreateBinObjArray() const
 }
 
 //______________________________________________________________________________
-TObjArray* AliAnalysisMuMuBinning::CreateBinObjArray(const char* particle) const
+TObjArray* AliAnalysisMuMuBinning::CreateBinObjArray(const char* what) const
 {
-  /// Get the list of bins for a given particle 
+  /// Get the list of bins for a given what 
   /// The returned array must be deleted by the user
   
   if (!fBins) return 0x0;
@@ -208,10 +208,10 @@ TObjArray* AliAnalysisMuMuBinning::CreateBinObjArray(const char* particle) const
   TObjArray* a = new TObjArray;
   a->SetOwner(kTRUE);
   
-  TString sparticle(particle);
-  sparticle.ToUpper();
+  TString swhat(what);
+  swhat.ToUpper();
   
-  TObjArray* b = static_cast<TObjArray*>(fBins->GetValue(sparticle.Data()));
+  TObjArray* b = static_cast<TObjArray*>(fBins->GetValue(swhat.Data()));
   if (!b) return 0x0;
   
   TIter next(b);
@@ -232,39 +232,39 @@ TObjArray* AliAnalysisMuMuBinning::CreateBinObjArray(const char* particle) const
 
 
 //______________________________________________________________________________
-TObjArray* AliAnalysisMuMuBinning::CreateBinObjArray(const char* particle, const char* type, const char* flavour) const
+TObjArray* AliAnalysisMuMuBinning::CreateBinObjArray(const char* what, const char* quantity, const char* flavour) const
 {
-  /// Get the list of bins for a given particle and given type
+  /// Get the list of bins for a given what and given Quantity
   /// The returned array must be deleted by the user
-  /// Type can be a single type or several types separated by comma
+  /// Quantity can be a single Quantity or several Quantitys separated by comma
   
   TObjArray* a = new TObjArray;
   a->SetOwner(kTRUE);
   
-  TString sparticle(particle);
-  sparticle.ToUpper();
+  TString swhat(what);
+  swhat.ToUpper();
 
-  TObjArray* b = static_cast<TObjArray*>(fBins->GetValue(sparticle.Data()));
+  TObjArray* b = static_cast<TObjArray*>(fBins->GetValue(swhat.Data()));
   if (!b) return 0x0;
   
   TIter next(b);
   Range* r;
 
-  TString stype(type);
-  stype.ToUpper();
+  TString sQuantity(quantity);
+  sQuantity.ToUpper();
 
   TString sflavour(flavour);
   
-  TObjArray* types = stype.Tokenize(",");
-  TObjString* onetype;
-  TIter nextType(types);
+  TObjArray* Quantitys = sQuantity.Tokenize(",");
+  TObjString* oneQuantity;
+  TIter nextQuantity(Quantitys);
   
   while ( ( r = static_cast<Range*>(next()) ) )
   {
-    nextType.Reset();
-    while ( ( onetype = static_cast<TObjString*>(nextType()) ) )
+    nextQuantity.Reset();
+    while ( ( oneQuantity = static_cast<TObjString*>(nextQuantity()) ) )
     {
-      if ( r->Type() == onetype->String() &&
+      if ( r->Quantity() == oneQuantity->String() &&
           ( ( sflavour.Length() > 0 && r->Flavour() == sflavour.Data() ) || sflavour.Length()==0 ) )
       {
         a->Add(r->Clone());
@@ -278,31 +278,31 @@ TObjArray* AliAnalysisMuMuBinning::CreateBinObjArray(const char* particle, const
     a = 0x0;
   }
   
-  delete types;
+  delete Quantitys;
   return a;
 }
 
 //______________________________________________________________________________
-void AliAnalysisMuMuBinning::CreateMesh(const char* particle,
-                                        const char* type1, const char* type2,
+void AliAnalysisMuMuBinning::CreateMesh(const char* what,
+                                        const char* quantity1, const char* quantity2,
                                         const char* flavour,
                                         Bool_t remove12)
 {
-  /// Create 2D bins from existing 1d ones of type1 and type2
-  TObjArray* a1 = CreateBinObjArray(particle,type1,flavour);
+  /// Create 2D bins from existing 1d ones of Quantity1 and Quantity2
+  TObjArray* a1 = CreateBinObjArray(what,quantity1,flavour);
   if (!a1)
   {
-    AliError(Form("No bin for type %s. Done nothing.",type1));
+    AliError(Form("No bin for Quantity %s. Done nothing.",quantity1));
     return;
   }
-  TObjArray* a2 = CreateBinObjArray(particle,type2,flavour);
+  TObjArray* a2 = CreateBinObjArray(what,quantity2,flavour);
   if (!a2)
   {
-    AliError(Form("No bin for type %s. Done nothing.",type2));
+    AliError(Form("No bin for Quantity %s. Done nothing.",quantity2));
     return;
   }
   
-  TString meshType(Form("%s VS %s - %s",type1,type2,flavour));
+  TString meshQuantity(Form("%s VS %s - %s",quantity1,quantity2,flavour));
   
   for ( Int_t i1 = 0; i1 <= a1->GetLast(); ++i1 )
   {
@@ -312,7 +312,7 @@ void AliAnalysisMuMuBinning::CreateMesh(const char* particle,
     {
       Range* r2 = static_cast<Range*>(a2->At(i2));
       
-      AddBin(particle,meshType,r2->Xmin(),r2->Xmax(),r1->Xmin(),r1->Xmax(),Form("%s VS %s",r1->Flavour().Data(),r2->Flavour().Data()));
+      AddBin(what,meshQuantity,r2->Xmin(),r2->Xmax(),r1->Xmin(),r1->Xmax(),Form("%s VS %s",r1->Flavour().Data(),r2->Flavour().Data()));
     }
   }
   
@@ -321,19 +321,19 @@ void AliAnalysisMuMuBinning::CreateMesh(const char* particle,
 
   if ( remove12 )
   {
-    TObjArray* b = static_cast<TObjArray*>(fBins->GetValue(particle));
+    TObjArray* b = static_cast<TObjArray*>(fBins->GetValue(what));
     TIter next(b);
     Range* r;
-    TString stype1(type1);
-    TString stype2(type2);
+    TString sQuantity1(quantity1);
+    TString sQuantity2(quantity2);
 
-    stype1.ToUpper();
-    stype2.ToUpper();
+    sQuantity1.ToUpper();
+    sQuantity2.ToUpper();
     
     while ( ( r = static_cast<Range*>(next())) )
     {
-      if ( r->Type() == type1 ||
-           r->Type() == type2 )
+      if ( r->Quantity() == quantity1 ||
+           r->Quantity() == quantity2 )
       {
         b->Remove(r);
       }
@@ -342,60 +342,60 @@ void AliAnalysisMuMuBinning::CreateMesh(const char* particle,
 }
 
 //______________________________________________________________________________
-TObjArray* AliAnalysisMuMuBinning::CreateParticleArray() const
+TObjArray* AliAnalysisMuMuBinning::CreateWhatArray() const
 {
-  /// Create a TObjString array with the names of the particle we're holding results for
+  /// Create a TObjString array with the names of the what we're holding results for
   /// Returned array must be delete by user
   
-  TObjArray* particleArray(0x0);
+  TObjArray* whatArray(0x0);
   
-  TIter nextParticle(fBins);
-  TObjString* particle;
+  TIter nextwhat(fBins);
+  TObjString* what;
 
-  while ( ( particle = static_cast<TObjString*>(nextParticle()) ) )
+  while ( ( what = static_cast<TObjString*>(nextwhat()) ) )
   {
-    if (!particleArray)
+    if (!whatArray)
     {
-      particleArray = new TObjArray;
-      particleArray->SetOwner(kTRUE);
+      whatArray = new TObjArray;
+      whatArray->SetOwner(kTRUE);
     }
-    particleArray->Add(new TObjString(*particle));
+    whatArray->Add(new TObjString(*what));
   }
-  return particleArray;
+  return whatArray;
 }
 
 //______________________________________________________________________________
-TObjArray* AliAnalysisMuMuBinning::CreateTypeArray() const
+TObjArray* AliAnalysisMuMuBinning::CreateQuantityArray() const
 {
-  /// Create a TObjString array with the names of the binning types
+  /// Create a TObjString array with the names of the binning Quantitys
   /// Returned array must be delete by user
 
-  TObjArray* typeArray(0x0);
+  TObjArray* QuantityArray(0x0);
   
-  TIter nextParticle(fBins);
-  TObjString* particle;
+  TIter nextwhat(fBins);
+  TObjString* what;
   
-  while ( ( particle = static_cast<TObjString*>(nextParticle()) ) )
+  while ( ( what = static_cast<TObjString*>(nextwhat()) ) )
   {
-    TObjArray* particles = static_cast<TObjArray*>(fBins->GetValue(particle->String()));
+    TObjArray* whats = static_cast<TObjArray*>(fBins->GetValue(what->String()));
     
-    TIter next(particles);
+    TIter next(whats);
     Range* r;
     
     while ( ( r = static_cast<Range*>(next())) )
     {
-      if (!typeArray)
+      if (!QuantityArray)
       {
-        typeArray = new TObjArray;
-        typeArray->SetOwner(kTRUE);
+        QuantityArray = new TObjArray;
+        QuantityArray->SetOwner(kTRUE);
       }
-      if ( !typeArray->FindObject(r->Type()) )
+      if ( !QuantityArray->FindObject(r->Quantity()) )
       {
-        typeArray->Add(new TObjString(r->Type()));
+        QuantityArray->Add(new TObjString(r->Quantity()));
       }
     }
   }
-  return typeArray;
+  return QuantityArray;
 }
 
 //______________________________________________________________________________
@@ -489,23 +489,27 @@ Long64_t AliAnalysisMuMuBinning::Merge(TCollection* list)
 
 //______________________________________________________________________________
 AliAnalysisMuMuBinning*
-AliAnalysisMuMuBinning::Project(const char* particle, const char* type, const char* flavour) const
+AliAnalysisMuMuBinning::Project(const char* what, const char* quantity, const char* flavour) const
 {
-  /// Create a sub-binning object with only the bins pertaining to (particle,type)
+  /// Create a sub-binning object with only the bins pertaining to (what,Quantity)
   
-  TObjArray* bins = CreateBinObjArray(particle,type,flavour);
+  TObjArray* bins = CreateBinObjArray(what,quantity,flavour);
   if (!bins) return 0x0;
   AliAnalysisMuMuBinning* p = new AliAnalysisMuMuBinning;
   TIter next(bins);
   AliAnalysisMuMuBinning::Range* bin;
-  TString stype(type);
-  stype.ToUpper();
+  TString sQuantity(quantity);
+  sQuantity.ToUpper();
   
   while ( ( bin = static_cast<AliAnalysisMuMuBinning::Range*>(next())) )
   {
-    assert  (bin->Type()==stype && bin->Flavour()==flavour);
+    if  (bin->Quantity()!=sQuantity || bin->Flavour()!=flavour)
     {
-      p->AddBin(particle,bin->Type(),bin->Xmin(),bin->Xmax(),bin->Ymin(),bin->Ymax(),bin->Flavour().Data());
+      AliDebug(1,Form("sQuantity=%s flavour=%s bin=%s => skip",sQuantity.Data(),flavour,bin->AsString().Data()));
+      continue;
+    }
+    {
+      p->AddBin(what,bin->Quantity(),bin->Xmin(),bin->Xmax(),bin->Ymin(),bin->Ymax(),bin->Flavour().Data());
     }
   }
   
@@ -525,12 +529,12 @@ void AliAnalysisMuMuBinning::Print(Option_t* /*opt*/) const
     return;
   }
   
-  TIter nextParticle(fBins);
+  TIter nextwhat(fBins);
   TObjString* str;
   
-  while ( ( str = static_cast<TObjString*>(nextParticle()) ) )
+  while ( ( str = static_cast<TObjString*>(nextwhat()) ) )
   {
-    std::cout << "Particle : " << str->String().Data() << std::endl;
+    std::cout << "what : " << str->String().Data() << std::endl;
     TObjArray* b = static_cast<TObjArray*>(fBins->GetValue(str->String()));
     TIter next(b);
     Range* r(0x0);
@@ -550,17 +554,17 @@ void AliAnalysisMuMuBinning::Print(Option_t* /*opt*/) const
 //______________________________________________________________________________
 
 //______________________________________________________________________________
-AliAnalysisMuMuBinning::Range::Range(const char* particle, const char* type,
+AliAnalysisMuMuBinning::Range::Range(const char* what, const char* quantity,
                                      Double_t xmin, Double_t xmax,
                                      Double_t ymin, Double_t ymax,
                                      const char* flavour)
-: TObject(), fParticle(particle), fType(type),
+: TObject(), fWhat(what), fQuantity(quantity),
   fXmin(xmin), fXmax(xmax), fYmin(ymin), fYmax(ymax),
   fFlavour(flavour)
 {
   /// ctor
-  fParticle.ToUpper();
-  fType.ToUpper();
+  fWhat.ToUpper();
+  fQuantity.ToUpper();
 }
 
 //______________________________________________________________________________
@@ -568,17 +572,17 @@ TString AliAnalysisMuMuBinning::Range::AsString() const
 {
   /// Return a string representation of this range
   
-  if ( IsNullObject()) return "";
+  if ( IsIntegrated()) return Quantity().Data();
   
   TString s;
   
   if ( fFlavour.Length() > 0 )
   {
-    s.Form("%s_%s_%05.2f_%05.2f",Type().Data(),Flavour().Data(),Xmin(),Xmax());
+    s.Form("%s_%s_%05.2f_%05.2f",Quantity().Data(),Flavour().Data(),Xmin(),Xmax());
   }
   else
   {
-    s.Form("%s_%05.2f_%05.2f",Type().Data(),Xmin(),Xmax());
+    s.Form("%s_%05.2f_%05.2f",Quantity().Data(),Xmin(),Xmax());
   }
   
   if (Is2D())
@@ -600,11 +604,11 @@ Int_t     AliAnalysisMuMuBinning::Range::Compare(const TObject* obj) const
   // than obj, 0 if objects are equal and 1 if this is larger than obj.
   const Range* other = static_cast<const Range*>(obj);
   
-  int s = strcmp(Particle().Data(),other->Particle().Data());
+  int s = strcmp(What().Data(),other->What().Data());
   
   if ( s ) return s;
   
-  s = strcmp(Type().Data(),other->Type().Data());
+  s = strcmp(Quantity().Data(),other->Quantity().Data());
   
   if (s) return s;
   
@@ -612,7 +616,7 @@ Int_t       AliAnalysisMuMuBinning::Range::Compare(const TObject* obj) const
   
   if (s) return s;
   
-  if ( IsNullObject() ) return 0;
+//  if ( IsIntegrated() && other->IsIntegrated() ) return 0;
   
   if ( Xmin() < other->Xmin() )
   {
@@ -651,7 +655,7 @@ Int_t       AliAnalysisMuMuBinning::Range::Compare(const TObject* obj) const
         {
           return 1;
         }
-      }        
+      }
     }
   }
   return 0;
@@ -663,7 +667,7 @@ Bool_t AliAnalysisMuMuBinning::Range::IsInRange(Double_t x, Double_t y) const
   /// If Range is 1D, returns true if x is in range
   /// If Range is 2D, returns true if (x,y) is in range
   
-  if ( IsNullObject() )
+  if ( IsIntegrated() )
   {
     return kTRUE;
   }
@@ -671,19 +675,19 @@ Bool_t AliAnalysisMuMuBinning::Range::IsInRange(Double_t x, Double_t y) const
   {
     if ( Is2D() )
     {
-      return ( x > Xmin() && x < Xmax() && y > Ymin() && y < Ymax());
+      return ( x >= Xmin() && x < Xmax() && y >= Ymin() && y < Ymax());
     }
     else
     {
-      return ( x > Xmin() && x < Xmax() );
+      return ( x >= Xmin() && x < Xmax() );
     }
   }
 }
 
 //______________________________________________________________________________
-Bool_t AliAnalysisMuMuBinning::Range::IsNullObject() const
+Bool_t AliAnalysisMuMuBinning::Range::IsIntegrated() const
 {
-  /// Whether we're a null object or not
+  /// Whether we're a null object (aka integrated) or not
   return
   Xmin() >= TMath::Limits<Double_t>::Max() &&
   Ymin() >= TMath::Limits<Double_t>::Max() &&
@@ -697,14 +701,14 @@ void AliAnalysisMuMuBinning::Range::Print(Option_t* /*opt*/) const
 {
   /// Output to stdout
   
-  if (IsNullObject())
+  if (IsIntegrated())
   {
-    std::cout << Form("%s : %s : NullObject",Particle().Data(),Type().Data()) << std::endl;
+    std::cout << Form("%s : %s : INTEGRATED",What().Data(),Quantity().Data()) << std::endl;
   
     return;
   }
   
-  std::cout << Form("%s : %s : %5.2f : %5.2f",Particle().Data(),Type().Data(),Xmin(),Xmax());
+  std::cout << Form("%s : %s : %5.2f : %5.2f",What().Data(),Quantity().Data(),Xmin(),Xmax());
   
   if (Is2D())
   {
index ccf111bcb726b08d58a94781e27ff7695ff4fa5f..2f06c080e5ce0777a8e2551e5704f52a0672f26c 100644 (file)
@@ -30,28 +30,34 @@ public:
   
   void AddBin(const AliAnalysisMuMuBinning::Range& bin);
 
-  void AddBin(const char* particle, const char* type,
+  void AddBin(const char* what, const char* quantity,
               Double_t xmin=TMath::Limits<Double_t>::Max(),
               Double_t xmax=TMath::Limits<Double_t>::Max(),
-              Double_t ymin=TMath::Limits<Double_t>::Max(),
-              Double_t ymax=TMath::Limits<Double_t>::Max(),
+              const char* flavour="")
+  { AddBin(what,quantity,xmin,xmax,TMath::Limits<Double_t>::Max(),TMath::Limits<Double_t>::Max(),flavour); }
+
+  void AddBin(const char* what, const char* quantity,
+              Double_t xmin,
+              Double_t xmax,
+              Double_t ymin,
+              Double_t ymax,
               const char* flavour="");
 
-  TObjArray* CreateParticleArray() const;
+  TObjArray* CreateWhatArray() const;
 
-  TObjArray* CreateTypeArray() const;
+  TObjArray* CreateQuantityArray() const;
   
   Double_t* CreateBinArray() const;
 
   TObjArray* CreateBinObjArray() const;
-  TObjArray* CreateBinObjArray(const char* particle) const;
-  TObjArray* CreateBinObjArray(const char* particle, const char* type, const char* flavour) const;
+  TObjArray* CreateBinObjArray(const char* what) const;
+  TObjArray* CreateBinObjArray(const char* what, const char* quantity, const char* flavour) const;
   
-  AliAnalysisMuMuBinning* Project(const char* particle, const char* type, const char* flavour="") const;
+  AliAnalysisMuMuBinning* Project(const char* what, const char* quantity, const char* flavour="") const;
   
   virtual void Print(Option_t* opt="") const;
   
-  void CreateMesh(const char* particle, const char* type1, const char* type2, const char* flavour="", Bool_t remove12=kFALSE);
+  void CreateMesh(const char* what, const char* quantity1, const char* quantity2, const char* flavour="", Bool_t remove12=kFALSE);
 
   Long64_t Merge(TCollection* list);
 
@@ -61,7 +67,7 @@ public:
     
   public:
     
-    Range(const char* particle="",const char* type="",
+    Range(const char* what="",const char* quantity="",
           Double_t xmin=TMath::Limits<Double_t>::Max(),
           Double_t xmax=TMath::Limits<Double_t>::Max(),
           Double_t ymin=TMath::Limits<Double_t>::Max(),
@@ -78,10 +84,10 @@ public:
 
     bool operator!=(const Range& other) const { return !(*this==other); }
 
-    Bool_t IsNullObject() const;
-    
-    TString Type() const { return fType; }
-    TString Particle() const { return fParticle; }
+    Bool_t IsIntegrated() const;
+
+    TString Quantity() const { return fQuantity; }
+    TString What() const { return fWhat; }
     Double_t Xmin() const { return fXmin; }
     Double_t Xmax() const { return fXmax; }
     Double_t Ymin() const { return fYmin; }
@@ -93,7 +99,7 @@ public:
     
     Bool_t Is2D() const { return fYmax > fYmin; }
     
-    const char* GetName() const { return Type().Data(); }
+    const char* GetName() const { return What().Data(); }
     
     TString AsString() const;
     
@@ -104,23 +110,23 @@ public:
     TString Flavour() const { return fFlavour; }
     
   private:
-    TString fParticle; // particle
-    TString fType; // binning type (e.g. pt, y, phi)
+    TString fWhat; // what this range is about (e.g. J/psi particle, event, etc...)
+    TString fQuantity; // binning type (e.g. pt, y, phi)
     Double_t fXmin; // x-min of the range
     Double_t fXmax; // x-max of the range
     Double_t fYmin; // x-min of the range
     Double_t fYmax; // x-max of the range
     TString fFlavour; // flavour (if any) this range, e.g. coarse, fine, etc...
     
-    ClassDef(AliAnalysisMuMuBinning::Range,2)
+    ClassDef(AliAnalysisMuMuBinning::Range,3)
   };
   
 
  private:
 
-  TMap* fBins; // list of bins (particle -> list of bins) = (TObjString -> TObjArray)
+  TMap* fBins; // list of bins (what -> list of bins) = (TObjString -> TObjArray)
   
-  ClassDef(AliAnalysisMuMuBinning,1) // custom binning for MuMu analysis
+  ClassDef(AliAnalysisMuMuBinning,2) // custom binning for MuMu analysis
 };
 
 #endif
diff --git a/PWG/muon/AliAnalysisMuMuCutCombination.cxx b/PWG/muon/AliAnalysisMuMuCutCombination.cxx
new file mode 100644 (file)
index 0000000..068c821
--- /dev/null
@@ -0,0 +1,307 @@
+#include "AliAnalysisMuMuCutCombination.h"
+
+/**
+ *
+ * \ingroup pwg-muon-mumu
+ *
+ * \class AliAnalysisMuMuCutCombination
+ *
+ * A cut combination is the real cut class that is used in the sub-analysis. It is composed
+ * of one or several AliAnalysisMuMuCutElement.
+ *
+ * Unlike the cut elements, it can be of several types at the same time (i.e. it can
+ * be an event cutter and a track cutter for instance). The work is done in the
+ * Pass method(s).
+ *
+ */
+
+#include "AliAnalysisMuMuCutElement.h"
+#include "TList.h"
+#include "Riostream.h"
+#include "AliInputEventHandler.h"
+#include "AliLog.h"
+
+ClassImp(AliAnalysisMuMuCutCombination)
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutCombination::AliAnalysisMuMuCutCombination()
+: TObject(), fCuts(0x0), fName(""),
+fIsEventCutter(kFALSE), fIsEventHandlerCutter(kFALSE),
+fIsTrackCutter(kFALSE), fIsTrackPairCutter(kFALSE),
+fIsTriggerClassCutter(kFALSE)
+{
+  /// Default ctor.
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutCombination::~AliAnalysisMuMuCutCombination()
+{
+  /// Dtor
+  delete fCuts;
+}
+  
+//_____________________________________________________________________________
+void AliAnalysisMuMuCutCombination::Add(AliAnalysisMuMuCutElement* ce)
+{
+  /** Add a cut element to this combination, if the cut is not void and
+   *  not already part of the combination
+   */
+  
+  if (!ce || !ce->IsValid()) return;
+  
+  if (!fCuts)
+  {
+    fCuts = new TObjArray;
+    fCuts->SetOwner(kFALSE);
+    fIsEventCutter = ce->IsEventCutter();
+    fIsEventHandlerCutter = ce->IsEventHandlerCutter();
+    fIsTrackCutter = ce->IsTrackCutter();
+    fIsTrackPairCutter = ce->IsTrackPairCutter();
+    fIsTriggerClassCutter = ce->IsTriggerClassCutter();
+  }
+  
+  if (!fCuts->FindObject(ce))
+  {
+    fCuts->Add(ce);
+    fName += ce->GetName();
+    
+    fIsEventCutter = fIsEventCutter || ce->IsEventCutter();
+    fIsEventHandlerCutter = fIsEventHandlerCutter || ce->IsEventHandlerCutter();
+    fIsTrackCutter = fIsTrackCutter || ce->IsTrackCutter();
+    fIsTrackPairCutter = fIsTrackPairCutter || ce->IsTrackPairCutter();
+    fIsTriggerClassCutter = fIsTriggerClassCutter || ce->IsTriggerClassCutter();
+
+  }
+  
+  // update the name
+  
+  if ( IsTrackPairCutter() )
+  {
+    if ( fName[0] == 's' )
+    {
+      fName[0] = 'p';
+    }
+    else if ( fName[0] == 'p')
+    {
+      // already ok
+    }
+    else
+    {
+      TString tmp = fName;
+      fName = "p";
+      fName += tmp;
+    }
+  }
+  else if ( IsTrackCutter() )
+  {
+    if ( fName[0] == 's')
+    {
+      // already ok
+    }
+    else
+    {
+      TString tmp = fName;
+      fName = "s";
+      fName += tmp;
+    }
+  }
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuCutCombination::IsEqual(const TObject* obj) const
+{
+  /// Whether or not we are the same cut combination as obj
+  
+  if ( obj->IsA() != AliAnalysisMuMuCutCombination::Class() )
+  {
+    return kFALSE;
+  }
+  
+  const AliAnalysisMuMuCutCombination* other = static_cast<const AliAnalysisMuMuCutCombination*>(obj);
+
+  if ( IsEventCutter() != other->IsEventCutter() ) return kFALSE;
+  if ( IsTrackCutter() != other->IsTrackCutter() ) return kFALSE;
+  if ( IsTrackPairCutter() != other->IsTrackPairCutter() ) return kFALSE;
+  if ( IsTriggerClassCutter() != other->IsTriggerClassCutter() ) return kFALSE;
+  
+  if ( fCuts && !other->fCuts ) return kFALSE;
+  if ( !fCuts && other->fCuts ) return kFALSE;
+  
+  if ( fCuts->GetEntries() != other->fCuts->GetEntries() ) return kFALSE;
+  
+  // ok, looks similar so far, now have compute the set of cuts in common
+  // (whatever the order) to see if they really are the same combination or not
+  
+  Int_t n1in2(0);
+  Int_t n2in1(0);
+  
+  for ( Int_t i = 0; i <= fCuts->GetLast(); ++i )
+  {
+    AliAnalysisMuMuCutElement* thisCuti = static_cast<AliAnalysisMuMuCutElement*>(fCuts->At(i));
+  
+    if ( other->fCuts->FindObject(thisCuti) )
+    {
+      ++n1in2;
+    }
+  }
+
+  for ( Int_t i = 0; i <= fCuts->GetLast(); ++i )
+  {
+    AliAnalysisMuMuCutElement* otherCuti = static_cast<AliAnalysisMuMuCutElement*>(other->fCuts->At(i));
+    
+    if ( fCuts->FindObject(otherCuti) )
+    {
+      ++n2in1;
+    }
+  }
+
+  return (n1in2==n2in1 && n1in2==fCuts->GetLast()+1);
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuCutCombination::Pass(const AliInputEventHandler& eventHandler) const
+{
+  /// Whether or not the event handler is passing the cut
+  
+  if (!fCuts) return kFALSE;
+  TIter next(fCuts);
+  AliAnalysisMuMuCutElement* ce;
+  
+  const AliVEvent* event = eventHandler.GetEvent();
+  
+  Bool_t passEvent(kTRUE);
+  Bool_t passEventHandler(kTRUE);
+  
+  while ( ( ce = static_cast<AliAnalysisMuMuCutElement*>(next()) ) )
+  {
+    if ( ce->IsEventCutter() && !ce->Pass(*event) )
+    {
+      passEvent = kFALSE;
+    }
+
+    if ( ce->IsEventHandlerCutter() && !ce->Pass(eventHandler) )
+    {
+      passEventHandler = kFALSE;
+    }
+  }
+  
+  if ( IsEventCutter() && IsEventHandlerCutter() )
+  {
+    return passEvent && passEventHandler;
+  }
+
+  if ( IsEventHandlerCutter() )
+  {
+    return passEventHandler;
+  }
+
+  if ( IsEventCutter() )
+  {
+    return passEvent;
+  }
+  
+  return kFALSE;
+}
+  
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuCutCombination::Pass(const AliVParticle& particle) const
+{
+  /// Whether or not the particle is passing the cut
+
+  if (!fCuts) return kFALSE;
+  TIter next(fCuts);
+  AliAnalysisMuMuCutElement* ce;
+  
+  while ( ( ce = static_cast<AliAnalysisMuMuCutElement*>(next()) ) )
+  {
+    if (ce->IsTrackCutter() && !ce->Pass(particle))
+    {
+      return kFALSE;
+    }
+  }
+
+  return kTRUE;
+}
+  
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuCutCombination::Pass(const AliVParticle& p1, const AliVParticle& p2) const
+{
+  /// Whether or not the particle pair is passing the cut
+
+  if (!fCuts) return kFALSE;
+  TIter next(fCuts);
+  AliAnalysisMuMuCutElement* ce;
+  
+  while ( ( ce = static_cast<AliAnalysisMuMuCutElement*>(next()) ) )
+  {
+    if (ce->IsTrackPairCutter() && !ce->Pass(p1,p2))
+    {
+      return kFALSE;
+    }
+  }
+  
+  return kTRUE;
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuCutCombination::Pass(const TString& firedTriggerClasses,
+                                           TString& acceptedTriggerClasses,
+                                           UInt_t L0, UInt_t L1, UInt_t L2) const
+{
+  /** Whether or not the firedTriggerClasses pass the cut.
+   * \param firedTriggerClasses (input) list of fired trigger classes (separated by space)
+   * \param acceptedTriggerClasses (output) list of accepted classes
+   * \param L0 (input, optional) level 0 trigger mask
+   * \param L1 (input, optional) level 1 trigger mask
+   * \param L2 (input, optional) level 2 trigger mask
+   */
+
+  if (!fCuts) return kFALSE;
+  TIter next(fCuts);
+  AliAnalysisMuMuCutElement* ce;
+  Bool_t rv(kFALSE);
+  
+  // contrary to the other cut types, here we make a full loop on all
+  // the cuts, as we need to give each cut a chance to update the acceptedTriggerClasses
+  // string
+  
+  acceptedTriggerClasses = "";
+  
+  while ( ( ce = static_cast<AliAnalysisMuMuCutElement*>(next()) ) )
+  {
+    TString tmp;
+    
+    if (ce->IsTriggerClassCutter() && ce->Pass(firedTriggerClasses,tmp,L0,L1,L2))
+    {
+      acceptedTriggerClasses += tmp;
+      acceptedTriggerClasses += " ";
+      rv = kTRUE;
+    }
+  }
+  
+  return rv;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuCutCombination::Print(Option_t* space) const
+{
+  /// Printout of the cut combination
+  std::cout << Form("%s(%p) [",GetName(),this);
+  if ( IsEventCutter() ) std::cout << " E";
+  if ( IsEventHandlerCutter() ) std::cout << " EH";
+  if ( IsTrackCutter() ) std::cout << " T";
+  if ( IsTrackPairCutter() ) std::cout << " TP";
+  if ( IsTriggerClassCutter() ) std::cout << " TC";
+  std::cout << " ]" << std::endl;
+  
+  TIter next(fCuts);
+  AliAnalysisMuMuCutElement* ce;
+  
+  while ( ( ce = static_cast<AliAnalysisMuMuCutElement*>(next()) ) )
+  {
+    std::cout << space;
+    ce->Print();
+  }
+}
+
diff --git a/PWG/muon/AliAnalysisMuMuCutCombination.h b/PWG/muon/AliAnalysisMuMuCutCombination.h
new file mode 100644 (file)
index 0000000..de53645
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef ALIANALYSISMUMUCUTCOMBINATION_H
+#define ALIANALYSISMUMUCUTCOMBINATION_H
+
+/**
+ *
+ * \class AliAnalysisMuMuCutCombination
+ *
+ * \brief Defines a cut by combining several cut elements
+ *
+ * \author L. Aphecetche (Subatech)
+ */
+
+#include "TObject.h"
+#include "TString.h"
+
+class AliAnalysisMuMuCutElement;
+class AliVEvent;
+class AliInputEventHandler;
+class AliVParticle;
+
+class AliAnalysisMuMuCutCombination : public TObject
+{
+public:
+  AliAnalysisMuMuCutCombination();
+  virtual ~AliAnalysisMuMuCutCombination();
+  
+  void Add(AliAnalysisMuMuCutElement* ce);
+
+  Bool_t Pass(const AliInputEventHandler& eventHandler) const;
+  
+  Bool_t Pass(const AliVParticle& particle) const;
+  
+  Bool_t Pass(const AliVParticle& p1, const AliVParticle& p2) const;
+  
+  Bool_t Pass(const TString& firedTriggerClasses, TString& acceptedTriggerClasses,
+              UInt_t L0, UInt_t L1, UInt_t L2) const;
+  
+  const char* GetName() const { return fName.Data(); }
+  
+  Bool_t IsEventCutter() const { return fIsEventCutter; }
+  Bool_t IsEventHandlerCutter() const { return fIsEventHandlerCutter; }
+  Bool_t IsTrackCutter() const { return fIsTrackCutter; }
+  Bool_t IsTrackPairCutter() const { return fIsTrackPairCutter; }
+  Bool_t IsTriggerClassCutter() const { return fIsTriggerClassCutter; }
+
+  void Print(Option_t* opt="") const;
+  
+  Bool_t IsEqual(const TObject* obj) const;
+  
+private:
+  /// not implemented on purpose
+  AliAnalysisMuMuCutCombination(const AliAnalysisMuMuCutCombination& rhs);
+  /// not implemented on purpose
+  AliAnalysisMuMuCutCombination& operator=(const AliAnalysisMuMuCutCombination& rhs);
+  
+private:
+  TObjArray* fCuts; // array of cut elements that form this cut combination
+  TString fName; // name of the combination
+  Bool_t fIsEventCutter; // whether or not the combination cuts on event
+  Bool_t fIsEventHandlerCutter; // whether or not the combination cuts on event handler
+  Bool_t fIsTrackCutter; // whether or not the combination cuts on track
+  Bool_t fIsTrackPairCutter; // whether or not the combination cuts on track pairs
+  Bool_t fIsTriggerClassCutter; // whether or not the combination cuts on trigger class
+  
+  ClassDef(AliAnalysisMuMuCutCombination,1) // combination of 1 or more individual cuts
+};
+
+#endif
+
diff --git a/PWG/muon/AliAnalysisMuMuCutElement.cxx b/PWG/muon/AliAnalysisMuMuCutElement.cxx
new file mode 100644 (file)
index 0000000..e2991a3
--- /dev/null
@@ -0,0 +1,602 @@
+#include "AliAnalysisMuMuCutElement.h"
+
+/**
+ * \ingroup pwg-muon-mumu
+ *
+ * \class AliAnalysisMuMuCutElement
+ *
+ * An AliAnalysisMuMuCutElement is an interface/proxy to another method (see ctor)
+ *
+ * A cut has a type (event cut, track cut, etc..., see ECutType and the IsXXX methods),
+ * a name, and offers a Pass method. A cut can be of one type only. 
+ * Generally a real cut is made of several cut elements, 
+ * see \ref AliAnalysisMuMuCutCombination
+ *
+ *  \author L. Aphecetche (Subatech)
+ */
+
+#include "TMethodCall.h"
+#include "AliLog.h"
+#include "Riostream.h"
+#include "AliVParticle.h"
+
+ClassImp(AliAnalysisMuMuCutElement)
+ClassImp(AliAnalysisMuMuCutElementBar)
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutElement::AliAnalysisMuMuCutElement()
+: TObject(), fName(""), fIsEventCutter(kFALSE), fIsEventHandlerCutter(kFALSE),
+fIsTrackCutter(kFALSE), fIsTrackPairCutter(kFALSE), fIsTriggerClassCutter(kFALSE),
+fCutObject(0x0), fCutMethodName(""), fCutMethodPrototype(""),
+fDefaultParameters(""), fNofParams(0), fCutMethod(0x0), fCallParams()
+{
+  /// Default ctor, leading to an invalid cut object
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutElement::AliAnalysisMuMuCutElement(ECutType expectedType,
+                                                     TObject& cutObject,
+                                                     const char* cutMethodName,
+                                                     const char* cutMethodPrototype,
+                                                     const char* defaultParameters)
+: TObject(), fName(""), fIsEventCutter(kFALSE), fIsEventHandlerCutter(kFALSE),
+fIsTrackCutter(kFALSE), fIsTrackPairCutter(kFALSE), fIsTriggerClassCutter(kFALSE),
+fCutObject(&cutObject), fCutMethodName(cutMethodName),
+fCutMethodPrototype(cutMethodPrototype),fDefaultParameters(defaultParameters),
+fNofParams(0), fCutMethod(0x0), fCallParams()
+{
+  /**
+   * Construct a cut, which is a proxy to another method of (most probably) another object
+   *
+   * \param expectedType the type of cut which is expected (this cut will be invalidated if
+   * the actual method does not comply with this type)
+   * \param cutObject the object which has the cut method
+   * \param cutMethodName the name of the method of cutObject that should do the cut work
+   * \param cutMethodPrototype the prototype (i.e. list of arguments) of cutMethod
+   * \param defaultParameters values of the default parameters (if any) of the cutMethod
+   *
+   * See the \ref Init method for details.
+   */
+
+  Init(expectedType);
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutElement::~AliAnalysisMuMuCutElement()
+{
+  /// Dtor
+  delete fCutMethod;
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuCutElement::CallCutMethod(Long_t p) const
+{
+  /// Call the cut method with one parameter
+  if (!fCutMethod)
+  {
+    Init();
+    if (!fCutMethod) return kFALSE;
+  }
+  
+  fCallParams[0] = p;
+
+  fCutMethod->SetParamPtrs(&fCallParams[0]);
+  Long_t result;
+  fCutMethod->Execute(fCutObject,result);
+  
+  return (result!=0);
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuCutElement::CallCutMethod(Long_t p1, Long_t p2) const
+{
+  /// Call the cut method with two parameters
+
+  if (!fCutMethod)
+  {
+    Init();
+    if (!fCutMethod) return kFALSE;
+  }
+
+  fCallParams[0] = p1;
+  fCallParams[1] = p2;
+  
+  fCutMethod->SetParamPtrs(&fCallParams[0]);
+  Long_t result;
+  fCutMethod->Execute(fCutObject,result);
+  
+  return (result!=0);
+}
+
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuCutElement::CountOccurences(const TString& prototype, const char* search) const
+{
+  /// Count the number of times "search" is found in prototype
+  
+  TObjArray* a = prototype.Tokenize(",");
+  TObjString* str;
+  TIter next(a);
+  
+  Int_t n(0);
+  
+  while ( ( str = static_cast<TObjString*>(next()) ) )
+  {
+    if  ( str->String().Contains(search) )
+    {
+      ++n;
+    }
+  }
+  delete a;
+  return n;
+}
+
+//_____________________________________________________________________________
+const char* AliAnalysisMuMuCutElement::CutTypeName(ECutType type)
+{
+  /// Convert the enum into a string
+  
+  if ( type == kEvent )
+  {
+    return "Event";
+  }
+  if ( type == kTrack )
+  {
+    return "Track";
+  }
+  if ( type == kTrackPair )
+  {
+    return "TrackPair";
+  }
+  if ( type == kTriggerClass )
+  {
+    return "TriggerClass";
+  }
+  return "Any";
+}
+
+//_____________________________________________________________________________
+const char* AliAnalysisMuMuCutElement::GetCallMethodName() const
+{
+  /// Return the cut method name
+  return ( fCutMethod ? fCutMethod->GetMethodName() : "");
+}
+
+//_____________________________________________________________________________
+const char* AliAnalysisMuMuCutElement::GetCallMethodProto() const
+{
+  /// Return the cut method prototype
+  return ( fCutMethod ? fCutMethod->GetProto() : "");
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuCutElement::Init(ECutType expectedType) const
+{
+  /** Build the non-persistent members (TMethodCalls)
+    *
+    * Each cut method XXXX must have
+    * a companion method, called NameOfXXXX(TString& nameOfCut) which fills the nameOfCut
+    * string with the name of cut (using the default parameter values if need be to distinguish
+    * different cuts using the same method).
+    * The cut method we're proxy-ing can not be of any kind. We basically only recognize the
+    * following prototypes (more or less based on the Pass() method prototypes). The checks
+    * performed below to ensure that are far from being bullet-proof though... You've been
+    * warned !
+    *
+    * For event cutters (3 or them instead of just one because of the, imo, 
+    * improper event/eventhandler interfaces we currently have in AliRoot)
+    *
+    * Bool_t XXXX(const AliVEvent&, ...)
+    * Bool_t XXXX(const AliVEventHandler&, ...)
+    * Bool_t XXXX(const AliInputEventHandler&, ...)
+    * 
+    * For track cutters :
+    *
+    * Bool_t XXXX(const AliVParticle&, ...)
+    *
+    * For track pairs cutters :
+    *
+    * Bool_t XXXX(const AliVParticle&, const AliVParticle&, ...)
+    *
+    * For trigger class cutters :
+    *
+    * Bool_t XXXX(const TString& firedTriggerClasses, TString& acceptedTriggerClasses)
+    *
+    * where ... stands for optional arguments (different from VEvent VParticle, etc...), 
+    * which can have default values
+    * 
+    * Note that Root reflexion does not allow (yet?) to check for constness of the arguments,
+    * so AliVEvent& and const AliVEvent& will be the same.
+    *
+    *
+   */
+  
+  TString scutMethodPrototype(fCutMethodPrototype);
+  
+  // some basic checks first
+  
+  TObjArray* tmp = fCutMethodPrototype.Tokenize(",");
+  fNofParams = tmp->GetEntries();
+  delete tmp;
+  
+  Int_t nVEvent = CountOccurences(fCutMethodPrototype,"AliVEvent");
+  Int_t nVEventHandler = CountOccurences(fCutMethodPrototype,"AliVEventHandler");
+  Int_t nInputHandler = CountOccurences(fCutMethodPrototype,"AliInputEventHandler");
+  Int_t nparticles = CountOccurences(fCutMethodPrototype,"AliVParticle");
+  Int_t nstrings = CountOccurences(fCutMethodPrototype,"TString");
+  
+  if ( expectedType == kEvent && ( nVEvent == 0 && nVEventHandler == 0 && nInputHandler == 0 ) )
+  {
+    AliError(Form("Cut not of the expected %s type : did not find required prototype arguments AliVEvent, AliVEventHandler or AliInputEventHandler",CutTypeName(kEvent)));
+    return;
+  }
+  
+  if ( expectedType == kTrack && ( nparticles != 1 ) )
+  {
+    AliError(Form("Cut not of the expected %s type : did not find the required prototype argument AliVParticle (one and only one required)",CutTypeName(kTrack)));
+    return;
+  }
+
+  if ( expectedType == kTrackPair && ( nparticles != 2 ) )
+  {
+    AliError(Form("Cut not of the expected %s type : did not find the required prototype arguments AliVParticle (2 of them required)",CutTypeName(kTrackPair)));
+    return;
+  }
+
+  if ( expectedType == kTriggerClass && ( nstrings != 2 ) )
+  {
+    AliError(Form("Cut not of the expected %stype : did not find the required prototype arguments TString& (2 of them required)",CutTypeName(kTriggerClass)));
+    return;
+  }
+  
+  // OK, at least the prototype seems to match what we require. Let's continue...
+  
+  scutMethodPrototype.ReplaceAll("  ","");
+  
+  fCutMethod = new TMethodCall;
+  
+  fCutMethod->InitWithPrototype(fCutObject->IsA(),fCutMethodName.Data(),scutMethodPrototype.Data());
+  
+  if (!fCutMethod->IsValid())
+  {
+    AliError(Form("Could not find method %s(%s) in class %s",fCutMethodName.Data(),
+                  scutMethodPrototype.Data(),fCutObject->ClassName()));
+    delete fCutMethod;
+    fCutMethod=0x0;
+    return;
+  }
+  
+  TMethodCall nameOfMethod;
+  
+  TString prototype("TString&");
+  
+  Int_t nMainPar = 0;
+  
+  if ( scutMethodPrototype.Contains("AliVEvent") )
+  {
+    fIsEventCutter=kTRUE;
+    ++nMainPar;
+  }
+  if ( scutMethodPrototype.Contains("AliInputEventHandler") )
+  {
+    fIsEventHandlerCutter=kTRUE;
+    ++nMainPar;
+  }
+
+  if ( nMainPar > 1 )
+  {
+    AliError(Form("Got an invalid prototype %s (more than one main parameter)",scutMethodPrototype.Data()));
+    delete fCutMethod;
+    fCutMethod=0x0;
+    return;
+  }
+  
+  if ( nparticles == 1 )
+  {
+    fIsTrackCutter=kTRUE;
+  }
+  else if ( nparticles == 2 )
+  {
+    fIsTrackPairCutter=kTRUE;
+  }
+  else if ( nstrings == 2 )
+  {
+    fIsTriggerClassCutter = kTRUE;
+  }
+  
+  nMainPar += nparticles;
+  nMainPar += nstrings;
+  
+  if ( nMainPar > 2 )
+  {
+    AliError(Form("Got an invalid prototype %s (more than two main parameters)",scutMethodPrototype.Data()));
+    delete fCutMethod;
+    fCutMethod=0x0;
+    return;
+  }
+  
+  if ( nMainPar == 0 )
+  {
+    AliError(Form("Got an invalid prototype %s (no main parameter found)",scutMethodPrototype.Data()));
+    delete fCutMethod;
+    fCutMethod=0x0;
+    return;
+  }
+  
+  if ( !fIsTriggerClassCutter )
+  {
+    scutMethodPrototype.ReplaceAll("const AliVEvent&","");
+    scutMethodPrototype.ReplaceAll("const AliVParticle&","");
+    scutMethodPrototype.ReplaceAll("const AliInputEventHandler&","");
+    
+    prototype += scutMethodPrototype;
+    
+    nameOfMethod.InitWithPrototype(fCutObject->IsA(),Form("NameOf%s",fCutMethodName.Data()),prototype);
+    
+    if (!nameOfMethod.IsValid())
+    {
+      AliError(Form("Could not find method NameOf%s(%s) in class %s",fCutMethodName.Data(),
+                    prototype.Data(),fCutObject->ClassName()));
+      delete fCutMethod;
+      fCutMethod=0x0;
+      return;
+    }
+    
+    // Now check if we have some default parameters for the NameOf method
+    // Note that the only supported types for those default parameters
+    // are Int_t and Double_t (which must be then of the form const Double_t&,
+    // note the reference).
+    
+    prototype.ReplaceAll("TString&","");
+    
+    TObjArray* paramTypes = prototype.Tokenize(",");
+    TObjArray* paramValues = fDefaultParameters.Tokenize(",");
+    
+    fDoubleParams.resize(paramValues->GetEntries());
+    
+    Int_t nparams = paramValues->GetEntries();
+    
+    // first parameter is always the TString&, i.e. the "output" of the NameOf
+    // method
+    
+    fCallParams.resize(nparams+nMainPar);
+    
+    if ( nMainPar == 2 )
+    {
+      fCallParams[0] = 0;
+      fCallParams[1] = reinterpret_cast<Long_t>(&fName);
+    }
+    else
+    {
+      fCallParams[0] = reinterpret_cast<Long_t>(&fName);
+    }
+    
+    for ( Int_t i = 0; i < nparams; ++i )
+    {
+      TString pValue = static_cast<TObjString*>(paramValues->At(i))->String();
+      TString pType = static_cast<TObjString*>(paramTypes->At(i))->String();
+      
+      if ( pType.Contains("Double_t"))
+      {
+        fDoubleParams[i] = pValue.Atof();
+        fCallParams[i+nMainPar] = reinterpret_cast<Long_t>(&fDoubleParams[i]);
+      }
+      else if ( pType.Contains("Int_t") )
+      {
+        fCallParams[i+nMainPar] = pValue.Atoi();
+      }
+      else
+      {
+        AliError(Form("Got a parameter of type %s which I don't exactly know how to deal with. Expect something bad to happen...",pType.Data()));
+        fCallParams[i+nMainPar] = reinterpret_cast<Long_t>(&pValue);
+      }
+    }
+    
+    nameOfMethod.SetParamPtrs(&fCallParams[0+nMainPar-1]);
+    
+    nameOfMethod.Execute(fCutObject);
+    
+    delete paramTypes;
+    delete paramValues;
+  }
+  else
+  {
+      // check whether we have the input bit masks as well
+    Int_t nuint = CountOccurences(scutMethodPrototype,"UInt_t");
+    
+    Bool_t ok =
+     ( nuint == 3 && nstrings == 2 && ( nuint + nstrings ) == fNofParams ) ||
+    ( nuint == 0 && nstrings == 2 && nstrings == fNofParams );
+    
+    if (!ok)
+    {
+      AliError("Incorrect prototype for a trigger class cutter");
+      delete fCutMethod;
+      fCutMethod=0x0;
+      return;
+    }
+  }
+  
+  // Final consistency ross-check
+  
+  if ( expectedType == kEvent && ! (fIsEventCutter || fIsEventHandlerCutter) )
+  {
+    AliError("No, it's not an event cutter. Invalidate");
+    delete fCutMethod;
+    fCutMethod=0x0;
+  }
+
+  if ( expectedType == kTrack && !fIsTrackCutter )
+  {
+    AliError("No, it's not a track cutter. Invalidate");
+    delete fCutMethod;
+    fCutMethod=0x0;
+  }
+
+  if ( expectedType == kTrackPair && !fIsTrackPairCutter )
+  {
+    AliError("No, it's not a track pair cutter. Invalidate");
+    delete fCutMethod;
+    fCutMethod=0x0;
+  }
+
+  if ( expectedType == kTriggerClass && !fIsTriggerClassCutter )
+  {
+    AliError("No, it's not a trigger class cutter. Invalidate");
+    delete fCutMethod;
+    fCutMethod=0x0;
+  }
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuCutElement::IsEqual(const TObject* obj) const
+{
+  /// Whether we're the same cut as obj
+  
+  if ( obj->IsA() != IsA() ) return kFALSE;
+  
+  const AliAnalysisMuMuCutElement* cut = static_cast<const AliAnalysisMuMuCutElement*>(obj);
+  
+  return ( fName == cut->fName &&
+    fIsEventCutter == cut->fIsEventCutter &&
+    fIsEventHandlerCutter == cut->fIsEventHandlerCutter &&
+    fIsTrackCutter == cut->fIsTrackCutter &&
+    fIsTrackPairCutter == cut->fIsTrackPairCutter &&
+    fIsTriggerClassCutter == cut->fIsTriggerClassCutter &&
+    fCutMethodName == cut->fCutMethodName &&
+    fCutMethodPrototype == cut->fCutMethodPrototype &&
+    fDefaultParameters == cut->fDefaultParameters &&
+    fCutObject == cut->fCutObject /* CHECK: should we really impose object equality or class equality would be enough ? */
+  );
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuCutElement::Pass(const AliVEvent& event) const
+{
+  /// Whether the event pass this cut
+  return CallCutMethod(reinterpret_cast<Long_t>(&event));
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuCutElement::Pass(const AliInputEventHandler& eventHandler) const
+{
+  /// Whether the eventHandler pass this cut
+  return CallCutMethod(reinterpret_cast<Long_t>(&eventHandler));
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuCutElement::Pass(const AliVParticle& part) const
+{
+  /// Whether the particle pass this cut
+  return CallCutMethod(reinterpret_cast<Long_t>(&part));
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuCutElement::Pass(const AliVParticle& p1, const AliVParticle& p2) const
+{
+  /// Whether the particle pair pass this cut
+  return CallCutMethod(reinterpret_cast<Long_t>(&p1),reinterpret_cast<Long_t>(&p2));
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuCutElement::Pass(const TString& firedTriggerClasses,
+                                       TString& acceptedTriggerClasses,
+                                       UInt_t L0, UInt_t L1, UInt_t L2) const
+{
+  /** Whether the firedTriggerClasses pass the cut.
+   * \param firedTriggerClasses (input) list of fired trigger classes (separated by space)
+   * \param acceptedTriggerClasses (output) list of accepted classes
+   * \param L0 (input, optional) level 0 trigger mask
+   * \param L1 (input, optional) level 1 trigger mask
+   * \param L2 (input, optional) level 2 trigger mask
+   */
+  
+  if (!fCutMethod)
+  {
+    Init();
+    if (!fCutMethod) return kFALSE;
+  }
+  
+  acceptedTriggerClasses = "";
+  
+  Long_t result;
+  Long_t params[] = { reinterpret_cast<Long_t>(&firedTriggerClasses),
+    reinterpret_cast<Long_t>(&acceptedTriggerClasses),
+    L0,L1,L2 };
+  
+  fCutMethod->SetParamPtrs(params);
+  fCutMethod->Execute(fCutObject,result);
+  return (result!=0);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuCutElement::Print(Option_t* /*opt*/) const
+{
+  /// Printout of the cut information
+  if ( !fCutMethod )
+  {
+    Init();
+  }
+  
+  std::cout << Form("Cut %s(%p) %s(%p)::%s(%s) [",
+                    fName.Data(),this,
+                    fCutObject->ClassName(),
+                    fCutObject,
+                    GetCallMethodName(),
+                    GetCallMethodProto());
+  
+  if ( IsEventCutter() ) std::cout << " E";
+  if ( IsEventHandlerCutter() ) std::cout << " EH";
+  if ( IsTrackCutter() ) std::cout << " T";
+  if ( IsTrackPairCutter() ) std::cout << " TP";
+  if ( IsTriggerClassCutter() ) std::cout << " TC";
+
+  std::cout << " ]" << std::endl;
+}
+
+//_____________________________________________________________________________
+//_____________________________________________________________________________
+//_____________________________________________________________________________
+
+/**
+ * \ingroup pwg-muon-mumu
+ *
+ * \class AliAnalysisMuMuCutElementBar
+ *
+ * \brief The negation of an AliAnalysisMuMuCutElement
+ *
+ *  \author L. Aphecetche (Subatech)
+ */
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutElementBar::AliAnalysisMuMuCutElementBar() : AliAnalysisMuMuCutElement(),
+fCutElement(0x0)
+{
+  /// default ctor
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutElementBar::AliAnalysisMuMuCutElementBar(const AliAnalysisMuMuCutElement& ce)
+: AliAnalysisMuMuCutElement(), fCutElement(&ce)
+{
+  /// ctor
+  fIsEventCutter = ce.IsEventCutter();
+  fIsEventHandlerCutter = ce.IsEventHandlerCutter();
+  fIsTrackCutter = ce.IsTrackCutter();
+  fIsTrackPairCutter = ce.IsTrackPairCutter();
+  fName = TString::Format("NOT%s",ce.GetName());
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutElementBar::~AliAnalysisMuMuCutElementBar()
+{
+  /// dtor (nop as we're not the owner of fCutElement)
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuCutElementBar::Print(Option_t* /*opt*/) const
+{
+  /// Printout of the cut information
+  std::cout << Form("Cut %s(%p) : negation of %s(%p)",GetName(),this,fCutElement->GetName(),fCutElement)
+  << std::endl;
+}
+
diff --git a/PWG/muon/AliAnalysisMuMuCutElement.h b/PWG/muon/AliAnalysisMuMuCutElement.h
new file mode 100644 (file)
index 0000000..7e476cd
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef ALIANALYSISMUMUCUTELEMENT_H
+#define ALIANALYSISMUMUCUTELEMENT_H
+
+/**
+ *
+ * \class AliAnalysisMuMuCutElement
+ *
+ * \brief Describes an elementary cut (either event cut, track cut, pair cut, or trigger class cut)
+ *
+ */
+
+#include "TObject.h"
+#include "TString.h"
+
+#include <vector>
+
+class TMethodCall;
+class AliVEvent;
+class AliInputEventHandler;
+class AliVParticle;
+
+class AliAnalysisMuMuCutElement : public TObject
+{
+public:
+  
+  enum ECutType
+  {
+    kEvent=0, // a cut on event
+    kTrack=1, // a cut on track
+    kTrackPair=2, // a cut on track pair
+    kTriggerClass=3, // a cut on trigger class
+    kAny=4 // must be the last one
+  };
+  
+  static const char* CutTypeName(ECutType type);
+  
+  AliAnalysisMuMuCutElement();
+  
+  AliAnalysisMuMuCutElement(ECutType expectedType,
+                            TObject& cutObject,
+                            const char* cutMethodName,
+                            const char* cutMethodPrototype,
+                            const char* defaultParameters);
+  
+  virtual ~AliAnalysisMuMuCutElement();
+  
+  virtual Bool_t IsValid() const { return (fCutMethod != 0x0); }
+  
+  const char* GetName() const { return fName.Data(); }
+  
+  virtual Bool_t Pass(const AliVEvent& event) const;
+
+  virtual Bool_t Pass(const AliInputEventHandler& eventHandler) const;
+
+  virtual Bool_t Pass(const AliVParticle& particle) const;
+  
+  virtual Bool_t Pass(const AliVParticle& p1, const AliVParticle& p2) const;
+  
+  virtual Bool_t Pass(const TString& firedTriggerClasses, TString& acceptedTriggerClasses,
+                      UInt_t L0, UInt_t L1, UInt_t L2) const;
+  
+  virtual void Print(Option_t* opt="") const;
+  
+  Bool_t IsEventCutter() const { return fIsEventCutter; }
+  Bool_t IsEventHandlerCutter() const { return fIsEventHandlerCutter; }
+  Bool_t IsTrackCutter() const { return fIsTrackCutter; }
+  Bool_t IsTrackPairCutter() const { return fIsTrackPairCutter; }
+  Bool_t IsTriggerClassCutter() const { return fIsTriggerClassCutter; }
+  
+  TObject* GetCutObject() const { return fCutObject; }
+  
+  const Long_t* GetCallParams() const { return &fCallParams[0]; }
+  
+  const char* GetCallMethodName() const;
+  const char* GetCallMethodProto() const;
+  
+  Bool_t IsEqual(const TObject* obj) const;
+  
+private:
+  
+  void Init(ECutType type=kAny) const;
+  
+  Bool_t CallCutMethod(Long_t p) const;
+  Bool_t CallCutMethod(Long_t p1, Long_t p2) const;
+  
+  Int_t CountOccurences(const TString& prototype, const char* search) const;
+
+  /// not implemented on purpose
+  AliAnalysisMuMuCutElement(const AliAnalysisMuMuCutElement& rhs);
+  /// not implemented on purpose
+  AliAnalysisMuMuCutElement& operator=(const AliAnalysisMuMuCutElement& rhs);
+  
+protected:
+  TString fName; // name of the cut
+  mutable Bool_t fIsEventCutter; // whether or not the cut is an event cutter
+  mutable Bool_t fIsEventHandlerCutter; // whether or not the cut is an event handler cutter
+  mutable Bool_t fIsTrackCutter; // whether or not the cut is a track cutter
+  mutable Bool_t fIsTrackPairCutter; // whether or not the cut is a track pair cutter
+  mutable Bool_t fIsTriggerClassCutter; // whether or not the cut is a trigger class cutter
+private:
+  
+  TObject* fCutObject; // pointer (not owner) to the object doing the actual cut work
+  TString fCutMethodName; // method (of fCutObject) to be called to do the cut
+  TString fCutMethodPrototype; // prototype of the method to be called to do the cut
+  TString fDefaultParameters; // default parameters of the cut method (might be empty)
+  mutable Int_t fNofParams; // number of parameters
+  mutable TMethodCall* fCutMethod; //! cut method
+  
+  mutable std::vector<Long_t> fCallParams; //! vector of parameters for the fCutMethod
+  mutable std::vector<Double_t> fDoubleParams; //! temporary vector to hold the references
+
+  ClassDef(AliAnalysisMuMuCutElement,1) // One piece of a cut combination
+};
+
+class AliAnalysisMuMuCutElementBar : public AliAnalysisMuMuCutElement
+{
+public:
+  AliAnalysisMuMuCutElementBar();
+  
+  AliAnalysisMuMuCutElementBar(const AliAnalysisMuMuCutElement& ce);
+  
+  virtual ~AliAnalysisMuMuCutElementBar();
+  
+  Bool_t IsValid() const { return fCutElement && fCutElement->IsValid(); }
+  
+  Bool_t Pass(const AliVEvent& event) const { return !fCutElement->Pass(event); }
+  
+  Bool_t Pass(const AliInputEventHandler& eventHandler) const { return !fCutElement->Pass(eventHandler); }
+  
+  Bool_t Pass(const AliVParticle& particle) const { return !fCutElement->Pass(particle); }
+  
+  Bool_t Pass(const AliVParticle& p1, const AliVParticle& p2) const { return !fCutElement->Pass(p1,p2); }
+  
+  Bool_t Pass(const TString& firedTriggerClasses, TString& acceptedTriggerClasses,
+              UInt_t L0, UInt_t L1, UInt_t L2) const
+  { return fCutElement->Pass(firedTriggerClasses,acceptedTriggerClasses,L0,L1,L2); }
+
+  void Print(Option_t* opt="") const;
+  
+private:
+  const AliAnalysisMuMuCutElement* fCutElement; // the cut element we're the negation of
+  
+  ClassDef(AliAnalysisMuMuCutElementBar,1) // opposite of cut element (i.e. !cutelement)
+};
+
+#endif
+
diff --git a/PWG/muon/AliAnalysisMuMuCutRegistry.cxx b/PWG/muon/AliAnalysisMuMuCutRegistry.cxx
new file mode 100644 (file)
index 0000000..414b0e5
--- /dev/null
@@ -0,0 +1,431 @@
+#include "AliAnalysisMuMuCutRegistry.h"
+
+/**
+ *
+ * \ingroup pwg-muon-mumu
+ *
+ * \class AliAnalysisMuMuCutRegistry
+ * The cut elements and cut combinations are stored per type, i.e. there's a set for
+ * event cuts/combinations, a set for track cuts/combinations, and a set for track pair cuts/combinations.
+ *
+ * To define a new cut use the AddEventCut, AddTrackCut, AndTrackPairCut and AddTriggerClassCut methods.
+ *
+ * To add an existing cut see AddCutElement.
+ *
+ * To define the negation of a cut, use the Not method.
+ *
+ * To add a new combination use one of the AddCutCombination methods, depending on the number
+ * of cut element(s) the combination is made of.
+ *
+ * Note that what the sub-analysis are really concerned with are cut combinations (i.e. if
+ * you fail to define any combination, nothing will be cut, whatever the number of cut elements
+ * you've defined).
+ *
+ * This class also defines a few default control cut elements aptly named AlwaysTrue.
+ *
+ */
+
+#include <utility>
+#include "AliLog.h"
+#include "TMethodCall.h"
+#include "AliVEvent.h"
+#include <set>
+#include "AliAnalysisMuMuCutElement.h"
+#include "AliAnalysisMuMuCutCombination.h"
+#include "TObjArray.h"
+#include "Riostream.h"
+#include "TList.h"
+
+ClassImp(AliAnalysisMuMuCutRegistry)
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutRegistry::AliAnalysisMuMuCutRegistry()
+: TObject(),
+fCutElements(0x0),
+fCutCombinations(0x0)
+{
+  /// ctor
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutRegistry::~AliAnalysisMuMuCutRegistry()
+{
+  /// dtor
+  
+  delete fCutElements;
+  delete fCutCombinations;
+}
+
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuCutRegistry::AddCutCombination(const TObjArray& cutElements)
+{
+  /// Add a cut combination composed of the cuts in the cutElements array.
+  ///
+  /// \return 1 in case of success, 0 if already there, -1 failure
+  
+  if ( cutElements.IsEmpty() ) return -1;
+  
+  AliAnalysisMuMuCutCombination* cutCombination = new AliAnalysisMuMuCutCombination;
+  
+  TIter next(&cutElements);
+  AliAnalysisMuMuCutElement* ce;
+  
+  while ( ( ce = static_cast<AliAnalysisMuMuCutElement*>(next()) ) )
+  {
+    cutCombination->Add(ce);
+  }
+  
+  if ( GetCutCombinations(AliAnalysisMuMuCutElement::kAny)->FindObject(cutCombination) )
+  {
+    delete cutCombination;
+    return 0;
+  }
+  
+  GetCutCombinations(AliAnalysisMuMuCutElement::kAny)->Add(cutCombination);
+  
+  if ( cutCombination->IsEventCutter() || cutCombination->IsEventHandlerCutter() )
+  {
+    GetCutCombinations(AliAnalysisMuMuCutElement::kEvent)->Add(cutCombination);
+  }
+
+  if ( cutCombination->IsTrackCutter() )
+  {
+    GetCutCombinations(AliAnalysisMuMuCutElement::kTrack)->Add(cutCombination);
+  }
+
+  if ( cutCombination->IsTrackPairCutter() )
+  {
+    GetCutCombinations(AliAnalysisMuMuCutElement::kTrackPair)->Add(cutCombination);
+  }
+
+  if ( cutCombination->IsTriggerClassCutter() )
+  {
+    GetCutCombinations(AliAnalysisMuMuCutElement::kTriggerClass)->Add(cutCombination);
+  }
+
+  return 1;
+}
+
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuCutRegistry::AddCutCombination(AliAnalysisMuMuCutElement* ce1)
+{
+  /// Convenience method to create a cut combination made of a single cut
+  TObjArray cutElements;
+  if ( ce1 ) cutElements.Add(ce1);
+  return AddCutCombination(cutElements);
+}
+
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuCutRegistry::AddCutCombination(AliAnalysisMuMuCutElement* ce1,
+                                                    AliAnalysisMuMuCutElement* ce2)
+{
+  /// Convenience method to create a cut combination made of 2 cuts
+  TObjArray cutElements;
+  if ( ce1 ) cutElements.Add(ce1);
+  if ( ce2 ) cutElements.Add(ce2);
+  return AddCutCombination(cutElements);
+}
+
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuCutRegistry::AddCutCombination(AliAnalysisMuMuCutElement* ce1,
+                                                    AliAnalysisMuMuCutElement* ce2,
+                                                    AliAnalysisMuMuCutElement* ce3)
+{
+  /// Convenience method to create a cut combination made of 3 cuts
+  TObjArray cutElements;
+  if ( ce1 ) cutElements.Add(ce1);
+  if ( ce2 ) cutElements.Add(ce2);
+  if ( ce3 ) cutElements.Add(ce3);
+  return AddCutCombination(cutElements);
+}
+
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuCutRegistry::AddCutCombination(AliAnalysisMuMuCutElement* ce1, AliAnalysisMuMuCutElement* ce2, AliAnalysisMuMuCutElement* ce3,
+                        AliAnalysisMuMuCutElement* ce4)
+{
+  /// Convenience method to create a cut combination made of 4 cuts
+  TObjArray cutElements;
+  if ( ce1 ) cutElements.Add(ce1);
+  if ( ce2 ) cutElements.Add(ce2);
+  if ( ce3 ) cutElements.Add(ce3);
+  if ( ce4 ) cutElements.Add(ce4);
+  return AddCutCombination(cutElements);
+}
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuCutRegistry::AddCutCombination(AliAnalysisMuMuCutElement* ce1, AliAnalysisMuMuCutElement* ce2, AliAnalysisMuMuCutElement* ce3,
+                        AliAnalysisMuMuCutElement* ce4, AliAnalysisMuMuCutElement* ce5)
+{
+  /// Convenience method to create a cut combination made of 5 cuts
+
+  TObjArray cutElements;
+  if ( ce1 ) cutElements.Add(ce1);
+  if ( ce2 ) cutElements.Add(ce2);
+  if ( ce3 ) cutElements.Add(ce3);
+  if ( ce4 ) cutElements.Add(ce4);
+  if ( ce5 ) cutElements.Add(ce5);
+  return AddCutCombination(cutElements);
+}
+
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuCutRegistry::AddCutCombination(AliAnalysisMuMuCutElement* ce1, AliAnalysisMuMuCutElement* ce2, AliAnalysisMuMuCutElement* ce3,
+                        AliAnalysisMuMuCutElement* ce4, AliAnalysisMuMuCutElement* ce5, AliAnalysisMuMuCutElement* ce6)
+{
+  /// Convenience method to create a cut combination made of 6 cuts
+
+  TObjArray cutElements;
+  if ( ce1 ) cutElements.Add(ce1);
+  if ( ce2 ) cutElements.Add(ce2);
+  if ( ce3 ) cutElements.Add(ce3);
+  if ( ce4 ) cutElements.Add(ce4);
+  if ( ce5 ) cutElements.Add(ce5);
+  if ( ce6 ) cutElements.Add(ce6);
+  return AddCutCombination(cutElements);
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutElement*
+AliAnalysisMuMuCutRegistry::CreateCutElement(AliAnalysisMuMuCutElement::ECutType type,
+                                             TObject& cutClass,
+                                             const char* cutMethodName,
+                                             const char* cutMethodPrototype,
+                                             const char* defaultParameters)
+{
+  /** Create a cut element. See the ctor of AliAnalysisMuMuCutElement for the meaning
+   * of the parameters.
+   */
+  
+  AliAnalysisMuMuCutElement* ce = new AliAnalysisMuMuCutElement(type,cutClass,cutMethodName,cutMethodPrototype,defaultParameters);
+
+  AliAnalysisMuMuCutElement* added = AddCutElement(ce);
+  
+  if (!added)
+  {
+    delete ce;
+  }
+  
+  return added;
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutElement*
+AliAnalysisMuMuCutRegistry::AddCutElement(AliAnalysisMuMuCutElement* ce)
+{
+  /// Add an existing cut element to the registry if it is valid
+  
+  if ( ce && ce->IsValid() )
+  {
+    if (!GetCutElements(AliAnalysisMuMuCutElement::kAny)->FindObject(ce))
+    {
+      GetCutElements(AliAnalysisMuMuCutElement::kAny)->Add(ce);
+      if ( ce->IsEventCutter() || ce->IsEventHandlerCutter() )
+      {
+        GetCutElements(AliAnalysisMuMuCutElement::kEvent)->Add(ce);
+      }
+      else if ( ce->IsTrackCutter() )
+      {
+        GetCutElements(AliAnalysisMuMuCutElement::kTrack)->Add(ce);
+      }
+      else if ( ce->IsTrackPairCutter() )
+      {
+        GetCutElements(AliAnalysisMuMuCutElement::kTrackPair)->Add(ce);
+      }
+      else if ( ce->IsTriggerClassCutter() )
+      {
+        GetCutElements(AliAnalysisMuMuCutElement::kTriggerClass)->Add(ce);
+      }
+    }
+    return ce;
+  }
+  return 0x0;
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutElement* AliAnalysisMuMuCutRegistry::AddEventCut(TObject& cutClass,
+                                       const char* cutMethodName,
+                                       const char* cutMethodPrototype,
+                                       const char* defaultParameters)
+{
+  /// Shortcut method to create a cut element of type kEvent
+  return CreateCutElement(AliAnalysisMuMuCutElement::kEvent,cutClass,cutMethodName,
+                          cutMethodPrototype,defaultParameters);
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutElement* AliAnalysisMuMuCutRegistry::AddTrackCut(TObject& cutClass,
+                                       const char* cutMethodName,
+                                       const char* cutMethodPrototype,
+                                       const char* defaultParameters)
+{
+  /// Shortcut method to create a cut element of type kTrack
+  return CreateCutElement(AliAnalysisMuMuCutElement::kTrack,cutClass,cutMethodName,
+                          cutMethodPrototype,defaultParameters);
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutElement* AliAnalysisMuMuCutRegistry::AddTrackPairCut(TObject& cutClass,
+                                        const char* cutMethodName,
+                                        const char* cutMethodPrototype,
+                                        const char* defaultParameters)
+{
+  /// Shortcut method to create a cut element of type kTrackPair
+  return CreateCutElement(AliAnalysisMuMuCutElement::kTrackPair,cutClass,cutMethodName,
+                          cutMethodPrototype,defaultParameters);
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutElement* AliAnalysisMuMuCutRegistry::AddTriggerClassCut(TObject& cutClass,
+                                              const char* cutMethodName,
+                                              const char* cutMethodPrototype,
+                                              const char* defaultParameters)
+{
+  /// Shortcut method to create a cut element of type kTriggerClass
+  return CreateCutElement(AliAnalysisMuMuCutElement::kTriggerClass,cutClass,cutMethodName,
+                          cutMethodPrototype,defaultParameters);
+}
+
+//_____________________________________________________________________________
+const TObjArray* AliAnalysisMuMuCutRegistry::GetCutCombinations(AliAnalysisMuMuCutElement::ECutType type) const
+{
+  /// Get (and create if not already done) the array of cut combinations of the given type
+
+  if (!fCutCombinations) return 0x0;
+  
+  return static_cast<TObjArray*>(fCutCombinations->At(type));
+}
+
+//_____________________________________________________________________________
+TObjArray* AliAnalysisMuMuCutRegistry::GetCutCombinations(AliAnalysisMuMuCutElement::ECutType type)
+{
+  /// Get (and create if not already done) the array of cut combinations of the given type
+
+  if (!fCutCombinations)
+  {
+    // the fCutCombinations array will be the owner of all the cut combinations
+  
+    Int_t N = AliAnalysisMuMuCutElement::kAny + 1;
+    
+    fCutCombinations = new TObjArray(N);
+    fCutCombinations->SetOwner(kTRUE);
+  
+    for ( Int_t i = 0; i < N; ++i )
+    {
+      TObjArray* array = new TObjArray;
+      array->SetOwner(kFALSE);
+      if (i==AliAnalysisMuMuCutElement::kAny)
+      {
+        // only the first array, containing all the combinations
+        // is the owner of the combinations
+        // the other arrays are just pointing to those
+        array->SetOwner(kTRUE);
+      }
+      fCutCombinations->AddAt(array,i);
+    }
+  }
+  return static_cast<TObjArray*>(fCutCombinations->At(type));
+}
+
+//_____________________________________________________________________________
+const TObjArray* AliAnalysisMuMuCutRegistry::GetCutElements(AliAnalysisMuMuCutElement::ECutType type) const
+{
+  /// Get the array of cut elements of the given type. Return 0x0 if the array does not exist yet
+
+  if (!fCutElements) return 0x0;
+  
+  return static_cast<TObjArray*>(fCutElements->At(type));
+}
+
+//_____________________________________________________________________________
+TObjArray* AliAnalysisMuMuCutRegistry::GetCutElements(AliAnalysisMuMuCutElement::ECutType type)
+{
+  /// Get (and create if not already done) the array of cut elements of the given type
+  
+  if (!fCutElements)
+  {
+    // owner of all the cut elements
+    Int_t N = AliAnalysisMuMuCutElement::kAny + 1;
+    fCutElements = new TObjArray(N);
+    fCutElements->SetOwner(kTRUE);
+  
+    for ( Int_t i = 0; i < N; ++i )
+    {
+      TObjArray* array = new TObjArray;
+      array->SetOwner(kFALSE);
+      if (i == AliAnalysisMuMuCutElement::kAny )
+      {
+        // only the first array is the owner of the cuts
+        // the other ones are just pointing to this one
+        array->SetOwner(kTRUE);
+      }
+      fCutElements->AddAt(array,i);
+    }
+  }
+  return static_cast<TObjArray*>(fCutElements->At(type));
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuCutElement* AliAnalysisMuMuCutRegistry::Not(const AliAnalysisMuMuCutElement& cutElement)
+{
+  /// Create a cut which is the opposite of cutElement, and adds it.
+  
+  AliAnalysisMuMuCutElementBar* bar = new AliAnalysisMuMuCutElementBar(cutElement);
+  
+  AliAnalysisMuMuCutElement* added = AddCutElement(bar);
+  
+  if (!added)
+  {
+    delete bar;
+  }
+  
+  return added;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuCutRegistry::Print(Option_t* opt) const
+{
+  /// Printout
+  
+  TString sopt(opt);
+  sopt.ToUpper();
+  
+  std::cout << "++++ Cut combinations defined : " << std::endl;
+  
+  AliAnalysisMuMuCutElement::ECutType cutTypes[] = { AliAnalysisMuMuCutElement::kEvent, AliAnalysisMuMuCutElement::kTrack,
+    AliAnalysisMuMuCutElement::kTrackPair, AliAnalysisMuMuCutElement::kTriggerClass };
+
+  Int_t i(1);
+
+  for ( Int_t iCutType = 0; iCutType < 4; ++iCutType )
+  {
+    if (GetCutElements(cutTypes[iCutType])->IsEmpty()) continue;
+    std::cout << "  Cutting on " << AliAnalysisMuMuCutElement::CutTypeName(cutTypes[iCutType]) << std::endl;
+    TIter next(GetCutCombinations(cutTypes[iCutType]));
+    AliAnalysisMuMuCutCombination* cutCombination;
+  
+    while ( ( cutCombination = static_cast<AliAnalysisMuMuCutCombination*>(next())) )
+    {
+      std::cout << Form("    %4d ",i);
+      cutCombination->Print("            ");
+      ++i;
+    }
+  }
+  
+  if ( sopt.Contains("FULL") || sopt.Contains("ALL") )
+  {
+    std::cout << "++++ Individual cuts defined : " << std::endl;
+    
+    for ( Int_t iCutType = 0; iCutType < 4; ++iCutType )
+    {
+      if (GetCutElements(cutTypes[iCutType])->IsEmpty()) continue;
+      std::cout << "  Cutting on " << AliAnalysisMuMuCutElement::CutTypeName(cutTypes[iCutType]) << std::endl;
+      TIter nextCutRef(GetCutElements(cutTypes[iCutType]));
+      AliAnalysisMuMuCutElement* ce;
+      i = 1;
+      while ( ( ce = static_cast<AliAnalysisMuMuCutElement*>(nextCutRef()) ) )
+      {
+        std::cout << Form("%4d ",i);
+        ce->Print();
+        ++i;
+      }
+    }
+  }
+}
diff --git a/PWG/muon/AliAnalysisMuMuCutRegistry.h b/PWG/muon/AliAnalysisMuMuCutRegistry.h
new file mode 100644 (file)
index 0000000..0675d50
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef ALIANALYSISMUMUCUTREGISTRY_H
+#define ALIANALYSISMUMUCUTREGISTRY_H
+
+/**
+ *
+ * \class AliAnalysisMuMuCutRegistry
+ *
+ * \brief Container of AliAnalysisMuMuCutElement and AliAnalysisMuMuCutCombination objects.
+ *
+ * \author L. Aphecetche (Subatech)
+ *
+ */
+
+#include "TObject.h"
+#include "TString.h"
+#include "TMethodCall.h"
+#include "AliAnalysisMuMuCutElement.h"
+
+class AliVEvent;
+class AliAnalysisMuMuCutCombination;
+class AliVParticle;
+class AliVEventHandler;
+
+class AliAnalysisMuMuCutRegistry : public TObject
+{
+public:
+  AliAnalysisMuMuCutRegistry();
+  virtual ~AliAnalysisMuMuCutRegistry();
+
+  AliAnalysisMuMuCutElement* AddEventCut(TObject& cutClass,
+                                         const char* cutMethodName,
+                                         const char* cutMethodPrototype,
+                                         const char* defaultParameters);
+  
+  AliAnalysisMuMuCutElement* AddTrackCut(TObject& cutClass,
+                                         const char* cutMethodName,
+                                         const char* cutMethodPrototype,
+                                         const char* defaultParameters);
+  
+  AliAnalysisMuMuCutElement* AddTrackPairCut(TObject& cutClass,
+                                             const char* cutMethodName,
+                                             const char* cutMethodPrototype,
+                                             const char* defaultParameters);
+  
+  AliAnalysisMuMuCutElement* AddTriggerClassCut(TObject& cutClass,
+                                                const char* cutMethodName,
+                                                const char* cutMethodPrototype,
+                                                const char* defaultParameters);
+  
+  AliAnalysisMuMuCutElement* Not(const AliAnalysisMuMuCutElement& cutElement);
+
+  AliAnalysisMuMuCutElement* AddCutElement(AliAnalysisMuMuCutElement* ce);
+
+  Int_t AddCutCombination(const TObjArray& cutElements);
+  
+  Int_t AddCutCombination(AliAnalysisMuMuCutElement* ce1);
+  Int_t AddCutCombination(AliAnalysisMuMuCutElement* ce1, AliAnalysisMuMuCutElement* ce2);
+  Int_t AddCutCombination(AliAnalysisMuMuCutElement* ce1, AliAnalysisMuMuCutElement* ce2,
+                          AliAnalysisMuMuCutElement* ce3);
+  Int_t AddCutCombination(AliAnalysisMuMuCutElement* ce1, AliAnalysisMuMuCutElement* ce2,
+                          AliAnalysisMuMuCutElement* ce3, AliAnalysisMuMuCutElement* ce4);
+  Int_t AddCutCombination(AliAnalysisMuMuCutElement* ce1, AliAnalysisMuMuCutElement* ce2,
+                          AliAnalysisMuMuCutElement* ce3, AliAnalysisMuMuCutElement* ce4,
+                          AliAnalysisMuMuCutElement* ce5);
+  Int_t AddCutCombination(AliAnalysisMuMuCutElement* ce1, AliAnalysisMuMuCutElement* ce2,
+                          AliAnalysisMuMuCutElement* ce3, AliAnalysisMuMuCutElement* ce4,
+                          AliAnalysisMuMuCutElement* ce5, AliAnalysisMuMuCutElement* ce6);
+
+  const TObjArray* GetCutCombinations(AliAnalysisMuMuCutElement::ECutType type) const;
+  TObjArray* GetCutCombinations(AliAnalysisMuMuCutElement::ECutType type);
+
+  const TObjArray* GetCutElements(AliAnalysisMuMuCutElement::ECutType type) const;
+  TObjArray* GetCutElements(AliAnalysisMuMuCutElement::ECutType type);
+
+  virtual void Print(Option_t* opt="") const;
+  
+  Bool_t AlwaysTrue(const AliVEvent& /*event*/) const { return kTRUE; }
+  void NameOfAlwaysTrue(TString& name) const { name="ALL"; }
+  Bool_t AlwaysTrue(const AliVEventHandler& /*eventHandler*/) const { return kTRUE; }
+  Bool_t AlwaysTrue(const AliVParticle& /*part*/) const { return kTRUE; }
+  Bool_t AlwaysTrue(const AliVParticle& /*p1*/, const AliVParticle& /*p2*/) const { return kTRUE; }
+  
+private:
+  
+  /// not implemented on purpose
+  AliAnalysisMuMuCutRegistry(const AliAnalysisMuMuCutRegistry& rhs);
+  /// not implemented on purpose
+  AliAnalysisMuMuCutRegistry& operator=(const AliAnalysisMuMuCutRegistry& rhs);
+  
+  AliAnalysisMuMuCutElement* CreateCutElement(AliAnalysisMuMuCutElement::ECutType expectedType,
+                                              TObject& cutClass,
+                                              const char* cutMethodName,
+                                              const char* cutMethodPrototype,
+                                              const char* defaultParameters);
+  
+private:
+  
+  mutable TObjArray* fCutElements; // cut elements
+  mutable TObjArray* fCutCombinations; // cut combinations
+  
+  ClassDef(AliAnalysisMuMuCutRegistry,1) // storage for cut pointers
+};
+
+#endif
diff --git a/PWG/muon/AliAnalysisMuMuEventCutter.cxx b/PWG/muon/AliAnalysisMuMuEventCutter.cxx
new file mode 100644 (file)
index 0000000..e710679
--- /dev/null
@@ -0,0 +1,291 @@
+#include "AliAnalysisMuMuEventCutter.h"
+
+/**
+ *
+ * \ingroup pwg-muon-mumu
+ *
+ * \class AliAnalysisMuMuEventCutter
+ *
+ * We're grouping here various event cut methods that can be used
+ * as AliAnalysisMuMuCutElement. For instance :
+ *
+ * - \ref IsPhysicsSelected this is the normal physics selection check
+ * - \ref IsPhysicsSelectedVDM version of the physics selection used for VdM analysis
+ * - \ref IsSPDzVertexInRange selects event with a SPDvertex in a given range
+ * - \ref IsAbsZBelowValue selects event with |Zvertex| (being SPD or not) below a given value
+ * - \ref IsAbsZBelowValue as above but requesting explicitely the SPD vertex
+ * - \ref IsSPDzQA whether the SPD vertex is a good one
+ */
+
+#include "TObjString.h"
+#include "AliLog.h"
+#include "AliMuonEventCuts.h"
+#include "TList.h"
+#include "Riostream.h"
+#include "AliVVertex.h"
+#include "AliAODVertex.h"
+#include "AliVVZERO.h"
+#include "AliInputEventHandler.h"
+#include "AliVEvent.h"
+#include "TMath.h"
+#include "AliESDTZERO.h"
+#include "AliAODTZERO.h"
+#include "AliESDEvent.h"
+#include "AliAODEvent.h"
+
+ClassImp(AliAnalysisMuMuEventCutter)
+
+//______________________________________________________________________________
+AliAnalysisMuMuEventCutter::AliAnalysisMuMuEventCutter(TList* triggerClasses)
+: TObject(), fMuonEventCuts(0x0)
+{
+  /// ctor
+  TString tclasses;
+  
+  if ( !triggerClasses )
+  {
+    tclasses = "ANY";
+  }
+  else
+  {
+    TObjString* tname;
+    TIter next(triggerClasses);
+    
+    while ( ( tname = static_cast<TObjString*>(next()) ) )
+    {
+      if (tclasses.Length()>0)
+      {
+        tclasses += ",";
+      }
+      
+      tclasses += tname->String();
+    }
+  }
+  
+  MuonEventCuts()->SetTrigClassPatterns(tclasses);
+}
+
+//______________________________________________________________________________
+AliAnalysisMuMuEventCutter::~AliAnalysisMuMuEventCutter()
+{
+  /// dtor
+  delete fMuonEventCuts;
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuEventCutter::SelectTriggerClass(const TString& firedTriggerClasses,
+                                                      TString& acceptedClasses,
+                                                      UInt_t L0, UInt_t L1, UInt_t L2) const
+{
+  /// Forward the trigger class selection to MuonEventCuts::GetSelectedTrigClassesInEvent
+  acceptedClasses = "";
+  
+  TIter next(MuonEventCuts()->GetSelectedTrigClassesInEvent(firedTriggerClasses,L0,L1,L2));
+  TObjString* str;
+  
+  while ( ( str = static_cast<TObjString*>(next()) ) )
+  {
+    acceptedClasses += str->String();
+    acceptedClasses += " ";
+  }
+  return (acceptedClasses.Length()>0);
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuEventCutter::IsPhysicsSelected(const AliInputEventHandler& eventHandler) const
+{
+  /// Whether or not the event is physics selected
+  return const_cast<AliInputEventHandler&>(eventHandler).IsEventSelected() & AliVEvent::kAny;
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuEventCutter::IsPhysicsSelectedVDM(const AliVEvent& event) const
+{
+  // cut used in vdM scans
+  
+  AliVVZERO* vzero = event.GetVZEROData();
+  
+  if (vzero)
+  {
+    Float_t v0a = vzero->GetV0ATime();
+    Float_t v0c = vzero->GetV0CTime();
+    
+    Float_t v0diff = v0a-v0c;
+    Float_t v0sum = v0a+v0c;
+    
+    if ( ( v0sum > 10.5 && v0sum < 18 ) && ( v0diff > 4 && v0diff < 12 ) )
+    {
+      return kTRUE;
+    }
+  }
+  return kFALSE;
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuEventCutter::IsAbsZBelowValue(const AliVEvent& event, const Double_t& z) const
+{
+  // Checks if the absolute value of the Z component of the primary vertex is below a certain value
+  
+  const AliVVertex* vertex = event.GetPrimaryVertex();
+  return (TMath::Abs(vertex->GetZ())<=z);
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuEventCutter::IsAbsZSPDBelowValue(const AliVEvent& event, const Double_t& z) const
+{
+  // Checks if the absolute value of the SPD Z component of the given vertex is below a certain value
+  AliAODVertex* SPDVertex = static_cast<const AliAODEvent*>(&event)->GetPrimaryVertexSPD();
+  
+  if ( !SPDVertex )
+  {
+    AliError("SPD |z| cut requested and no SPD vertex found in the event");
+    return kFALSE;
+  }
+  
+  else return (TMath::Abs(SPDVertex->GetZ())<=z);
+}
+
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuEventCutter::IsSPDzVertexInRange(AliVEvent& event, const Double_t& zMin, const Double_t& zMax) const
+{
+  /// Whether or not the SPD Z vertex is in the range [zMin,zMax[
+  
+  AliAODVertex* SPDVertex = static_cast<AliAODEvent*>(&event)->GetPrimaryVertexSPD();
+  
+  if ( !SPDVertex )
+  {
+    AliError("Cut on SPD z Vertex requested for an event with no SPD vertex info");
+    return kFALSE;
+  }
+  Double_t zV = SPDVertex->GetZ();
+  
+  if ( zV >= zMin && zV < zMax ) return kTRUE;
+  else return kFALSE;
+}
+
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuEventCutter::HasSPDVertex(AliVEvent& event) const
+{
+  /// Does the event have a SPD vertex ?
+  AliAODVertex* SPDVertex = static_cast<AliAODEvent*>(&event)->GetPrimaryVertexSPD();
+  if ( SPDVertex && SPDVertex->GetNContributors() > 0) return kTRUE;
+  else return kFALSE;
+}
+
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuEventCutter::IsSPDzQA(const AliVEvent& event, /*const AliVVertex& vertex2Test,*/ const Double_t& zResCut, const Double_t& zDifCut) const
+{
+  // Checks if the value of the Z component of the given vertex fullfills the quality assurance condition
+  
+  const AliVVertex* vertex = event.GetPrimaryVertex();
+  const AliAODVertex* vertex2Test = static_cast<const AliAODEvent*>(&event)->GetPrimaryVertexSPD();
+  
+  Double_t cov[6]={0};
+  vertex2Test->GetCovarianceMatrix(cov);
+  Double_t zRes = TMath::Sqrt(cov[5]);
+  
+  if ( (zRes < zResCut) && TMath::Abs(vertex2Test->GetZ() - vertex->GetZ()) <= zDifCut )
+  {
+    return kTRUE;
+  }
+  else return kFALSE;
+}
+
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuEventCutter::IsMeandNchdEtaInRange(AliVEvent& event, const Double_t& dNchdEtaMin, const Double_t& dNchdEtaMax) const
+{
+  TList* nchList = static_cast<TList*>(event.FindListObject("NCH"));
+  
+  if (!nchList || nchList->IsEmpty())
+  {
+    AliFatal("No NCH information found in event. Nch analysis MUST be executed to apply a NCH cut");
+    return kFALSE;
+  }
+  
+  Int_t i(0);
+  
+  while ( nchList->At(i)->IsA() != TObjString::Class() ) //Asign a name to find it by name
+  {
+    i++;
+  }
+  
+  TObjString* value = static_cast<TObjString*>(nchList->At(i));
+  Double_t meandNchdEta = value->String().Atof();
+  
+  if ( meandNchdEta >= dNchdEtaMin && meandNchdEta < dNchdEtaMax ) return kTRUE;
+  else return kFALSE;
+}
+
+
+//_____________________________________________________________________________
+AliMuonEventCuts*
+AliAnalysisMuMuEventCutter::MuonEventCuts() const
+{
+  /// Return the single instance of AliMuonEventCuts object we're using
+  
+  if (!fMuonEventCuts)
+  {
+    fMuonEventCuts = new AliMuonEventCuts("EventCut","");
+  }
+  return fMuonEventCuts;
+}
+
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuEventCutter::NameOfIsSPDzVertexInRange(TString& name, const Double_t& zMin, const Double_t& zMax) const
+{
+  name.Form("SPDZBTW%3.2f_%3.2f",zMin,zMax);
+}
+//_____________________________________________________________________________
+void AliAnalysisMuMuEventCutter::NameOfIsAbsZBelowValue(TString& name, const Double_t& z) const
+{
+  name.Form("ABSZLT%3.2f",z);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuEventCutter::NameOfIsAbsZSPDBelowValue(TString& name, const Double_t& z) const
+{
+  name.Form("SPDABSZLT%3.2f",z);
+}
+
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuEventCutter::NameOfIsSPDzQA(TString& name, const Double_t& zResCut, const Double_t& zDifCut) const
+{
+  name.Form("SPDZQA_RES%3.2f_ZDIF%3.2f",zResCut,zDifCut);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuEventCutter::NameOfIsMeandNchdEtaInRange(TString& name, const Double_t& dNchdEtaMin, const Double_t& dNchdEtaMax) const
+{
+  name.Form("MEANDNDETABTW%3.2f_%3.2f",dNchdEtaMin,dNchdEtaMax);
+}
+
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuEventCutter::IsTZEROPileUp(const AliVEvent& event) const
+{
+  Bool_t pileupFlag(kFALSE);
+  
+  if ( event.IsA() == AliESDEvent::Class() )
+  {
+    const AliESDTZERO* tzero = static_cast<AliESDEvent&>(const_cast<AliVEvent&>(event)).GetESDTZERO();
+    if ( tzero )
+    {
+      pileupFlag = tzero->GetPileupFlag();
+    }
+  }
+  else if ( event.IsA() == AliAODEvent::Class() )
+  {
+    AliAODTZERO* tzero = static_cast<const AliAODEvent&>(event).GetTZEROData();
+    if ( tzero )
+    {
+      pileupFlag = tzero->GetPileupFlag();
+    }
+  }
+  return pileupFlag;
+}
diff --git a/PWG/muon/AliAnalysisMuMuEventCutter.h b/PWG/muon/AliAnalysisMuMuEventCutter.h
new file mode 100644 (file)
index 0000000..c107bc6
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef ALIANALYSISMUMUEVENTCUTTER_H
+#define ALIANALYSISMUMUEVENTCUTTER_H
+
+/**
+ * 
+ * \class AliAnalysisMuMuEventCutter
+ *
+ * \brief Various event cuts used in AliAnalysisTaskMuMu
+ *
+ * \author L. Aphecetche and J. Martin-Bianco
+ *
+ */
+
+#include "TObject.h"
+#include "TString.h"
+
+class AliMuonEventCuts;
+class TList;
+class AliVEvent;
+class AliVVertex;
+class AliInputEventHandler;
+
+class AliAnalysisMuMuEventCutter : public TObject
+{
+public:
+  AliAnalysisMuMuEventCutter(TList* triggerClassesToConsider=0x0);
+  virtual ~AliAnalysisMuMuEventCutter();
+  
+  Bool_t SelectTriggerClass(const TString& firedTriggerClasses, TString& acceptedClasses,
+                            UInt_t L0, UInt_t L1, UInt_t L2) const;
+  
+  Bool_t IsTrue(const AliVEvent& /*event*/) const { return kTRUE; }
+  void NameOfIsTrue(TString& name) const { name="ALL"; }
+
+  Bool_t IsFalse(const AliVEvent& /*event*/) const { return kFALSE; }
+  void NameOfIsFalse(TString& name) const { name="NONE"; }
+
+  Bool_t IsPhysicsSelected(const AliInputEventHandler& eventHandler) const;
+  void NameOfIsPhysicsSelected(TString& name) const { name="PSALL"; }
+
+  Bool_t IsPhysicsSelectedVDM(const AliVEvent& event) const;
+  void NameOfIsPhysicsSelectedVDM(TString& name) const { name="VDM"; }
+
+  Bool_t IsAbsZBelowValue(const AliVEvent& event, const Double_t& z) const;
+  void NameOfIsAbsZBelowValue(TString& name, const Double_t& z) const;
+  
+  Bool_t IsAbsZSPDBelowValue(const AliVEvent& event, const Double_t& z) const;
+  void NameOfIsAbsZSPDBelowValue(TString& name, const Double_t& z) const;
+  
+  Bool_t IsSPDzVertexInRange(AliVEvent& event, const Double_t& zMin, const Double_t& zMax) const;
+  void NameOfIsSPDzVertexInRange(TString& name, const Double_t& zMin, const Double_t& zMax) const;
+  
+  Bool_t IsSPDzQA(const AliVEvent& event/*, const AliVVertex& vertex2Test*/, const Double_t& zResCut, const Double_t& zDifCut) const;
+  void NameOfIsSPDzQA(TString& name, const Double_t& zResCut, const Double_t& zDifCut) const;
+  
+  Bool_t HasSPDVertex(AliVEvent& event) const;
+  void NameOfHasSPDVertex(TString& name) const { name = "HASSPD"; }
+  
+  Bool_t IsMeandNchdEtaInRange(AliVEvent& event, const Double_t& dNchdEtaMin, const Double_t& dNchdEtaMax) const;
+  void NameOfIsMeandNchdEtaInRange(TString& name, const Double_t& dNchdEtaMin, const Double_t& dNchdEtaMax) const;
+  
+  Bool_t IsTZEROPileUp(const AliVEvent& event) const;
+  void NameOfIsTZEROPileUp(TString& name) const { name="TZEROPILEUP"; }
+  
+  AliMuonEventCuts* MuonEventCuts() const;
+  
+//  enum EEventCut
+//  {
+//    kEventIR2PILEUP     = BIT( 6), /// events with pile-up (using AliAnalysisUtils::IsOutOfBunchPileUp)
+//    
+//    kEventGOODVERTEX    = BIT(10), /// events with a good vertex
+//    kEventZPOS          = BIT(14), /// events with z > 0
+//    kEventZNEG          = BIT(15), /// events with z < 0
+//    
+//    kEventTRKLETA1      = BIT(20), /// event with at least one tracklet in |eta| < fTrackletEtaCutValue[0]
+
+//    kEvent0TVX          = BIT(31), /// events with 0TVX L0 input
+//    kEventV0AND         = BIT(32), /// events with both 0V0C and 0V0A L0 inputs
+//    kEvent0SM2          = BIT(33), /// events with 0SM2 L0 input
+//    kEvent0MSL          = BIT(34), /// events with 0MSL input
+//  };
+  
+private:
+  
+  mutable AliMuonEventCuts* fMuonEventCuts; // common cuts for muon events (from Diego)
+  
+  ClassDef(AliAnalysisMuMuEventCutter,1) // default event cutters for AliAnalysisTaskMuMu
+};
+
+#endif
diff --git a/PWG/muon/AliAnalysisMuMuGlobal.cxx b/PWG/muon/AliAnalysisMuMuGlobal.cxx
new file mode 100644 (file)
index 0000000..8294abf
--- /dev/null
@@ -0,0 +1,334 @@
+#include "AliAnalysisMuMuGlobal.h"
+
+/**
+ * \ingroup pwg-muon-mumu
+ *
+ * \class AliAnalysisMuMuGlobal
+ *
+ * Very simple histogramming analysis for global event properties, like vertex, bunch-crossing,
+ * background, etc...
+ *
+ * Warning : not really ready for prime-time
+ *
+ */
+
+#include "TH1.h"
+#include "AliVVertex.h"
+#include "AliVEvent.h"
+#include "AliAODEvent.h"
+#include "AliAnalysisMuonUtility.h"
+#include "AliAODTZERO.h"
+#include "AliESDEvent.h"
+#include "AliAnalysisMuMuBinning.h"
+#include <set>
+#include "AliMergeableCollection.h"
+#include "AliAnalysisMuonUtility.h"
+
+ClassImp(AliAnalysisMuMuGlobal)
+
+//_____________________________________________________________________________
+AliAnalysisMuMuGlobal::AliAnalysisMuMuGlobal() : AliAnalysisMuMuBase()
+{
+  /// ctor
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuGlobal::DefineHistogramCollection(const char* eventSelection,
+                                                      const char* triggerClassName,
+                                                      const char* centrality)
+{
+  /// Actually create the histograms for phyics/triggerClassName
+  
+  //  AliInfo(Form("%s %s %s %d",eventSelection,triggerClassName,centrality,hasMC));
+  
+  if (HistogramCollection()->Histo(Form("/%s/%s/%s/Zvertex",eventSelection,triggerClassName,centrality)))
+  {
+    return;
+  }
+  
+  Double_t xmin = -40;
+  Double_t xmax = +40;
+  Int_t nbins = GetNbins(xmin,xmax,0.5);
+  
+  CreateEventHistos(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"Zvertex","z vertex",nbins,xmin,xmax);
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"T0Zvertex","T0 zvertex",nbins,xmin,xmax);
+  
+  CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,
+                    "RecZvertexVsMCZvertex","Reconstructed vertex (w/ Ncontrib>=1) vs MC vertex",nbins,xmin,xmax,nbins,xmin,xmax);
+  
+  xmin = -5;
+  xmax = 5;
+  nbins = GetNbins(xmin,xmax,0.01);
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"ZvertexMinusZvertexSPD","Primary vertex z - SPD vertex",nbins,xmin,xmax);
+  
+  xmin = -1;
+  xmax = 50;
+  nbins = GetNbins(xmin,xmax,1);
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"ZvertexNContributors","z vertex nof contributors",nbins,xmin,xmax);
+  
+  xmin = -2;
+  xmax = 2;
+  nbins = GetNbins(xmin,xmax,0.01);
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"Xvertex","x vertex",nbins,xmin,xmax);
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"Yvertex","y vertex",nbins,xmin,xmax);
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"Nevents","number of events",2,-0.5,1.5);
+  
+  CreateEventHistos(kHistoForMCInput | kHistoForData,eventSelection,triggerClassName,centrality,
+                    "VertexType","Type of vertexer used",10,0,10);
+  
+  
+  xmin = 0;
+  xmax = 3564;
+  nbins = GetNbins(xmin,xmax,1.0);
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"BCX","bunch-crossing ids",nbins,xmin-0.5,xmax-0.5);
+  
+  
+  xmin = -30;
+  xmax = +30;
+  nbins = GetNbins(xmin,xmax,0.1);
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"V02D","V0C+V0A versus V0A-V0C;Time V0A - V0C (ns);Time V0A+V0C (ns)",nbins,xmin,xmax,nbins,xmin,xmax);
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"V02DwT0BB","V0C+V0A versus V0A-V0C with T0 BB;Time V0A - V0C (ns);Time V0A+V0C (ns)",nbins,xmin,xmax,nbins,xmin,xmax);
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"V02DwT0BG","V0C+V0A versus V0A-V0C with T0 background flag on;Time V0A - V0C (ns);Time V0A+V0C (ns)",nbins,xmin,xmax,nbins,xmin,xmax);
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"V02DwT0PU","V0C+V0A versus V0A-V0C with T0 pile up flag on;Time V0A - V0C (ns);Time V0A+V0C (ns)",nbins,xmin,xmax,nbins,xmin,xmax);
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"V02DwT0SAT","V0C+V0A versus V0A-V0C with T0 satellite flag on;Time V0A - V0C (ns);Time V0A+V0C (ns)",nbins,xmin,xmax,nbins,xmin,xmax);
+  
+  xmin = 0;
+  xmax = 600;
+  nbins = GetNbins(xmin,xmax,1);
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"V0AMult","V0A multiplicity",nbins,xmin,xmax);
+  
+  if ( !IsHistogramDisabled("Centrality") )
+  {
+    TObjArray* centralities = Binning()->CreateBinObjArray("centrality");
+    TIter next(centralities);
+    AliAnalysisMuMuBinning::Range* r;
+    std::set<std::string> estimators;
+    
+    while ( ( r = static_cast<AliAnalysisMuMuBinning::Range*>(next())) )
+    {
+      estimators.insert(r->Quantity().Data());
+    }
+    
+    std::set<std::string>::const_iterator it;
+    
+    for ( it = estimators.begin(); it != estimators.end(); ++it )
+    {
+      TH1* h = new TH1F("Centrality","Centrality",12,-10,110);
+      HistogramCollection()->Adopt(Form("/%s/%s/%s",eventSelection,triggerClassName,it->c_str()),h);
+    }
+    
+    delete centralities;
+  }
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"PileUpEstimators","pile up estimators",10,0,10);
+}
+
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuGlobal::FillHistosForEvent(const char* eventSelection,
+                                               const char* triggerClassName,
+                                               const char* centrality)
+{
+  // Fill event-wise histograms
+  
+  if (!IsHistogramDisabled("BCX"))
+  {
+    Histo(eventSelection,triggerClassName,centrality,"BCX")->Fill(1.0*Event()->GetBunchCrossNumber());
+  }
+  if (!IsHistogramDisabled("Nevents"))
+  {
+    Histo(eventSelection,triggerClassName,centrality,"Nevents")->Fill(1.0);
+  }
+  
+  const AliVVertex* vertex = Event()->GetPrimaryVertex();
+  const AliVVertex* vertexFromSPD = AliAnalysisMuonUtility::GetVertexSPD(Event());
+  
+  if ( vertex && vertexFromSPD )
+  {
+    if ( vertex->GetNContributors() > 0 )
+    {
+      if (!IsHistogramDisabled("Xvertex"))
+      {
+        Histo(eventSelection,triggerClassName,centrality,"Xvertex")->Fill(vertex->GetX());
+      }
+      if (!IsHistogramDisabled("Yvertex"))
+      {
+        Histo(eventSelection,triggerClassName,centrality,"Yvertex")->Fill(vertex->GetY());
+      }
+      if (!IsHistogramDisabled("Zvertex"))
+      {
+        Histo(eventSelection,triggerClassName,centrality,"Zvertex")->Fill(vertex->GetZ());
+      }
+      if (!IsHistogramDisabled("ZvertexMinusZvertexSPD"))
+      {
+        Histo(eventSelection,triggerClassName,centrality,"ZvertexMinusZvertexSPD")->Fill(vertexFromSPD->GetZ()-vertex->GetZ());
+      }
+      if (!IsHistogramDisabled("VertexType"))
+      {
+        Histo(eventSelection,triggerClassName,centrality,"VertexType")->Fill(vertex->GetTitle(),1.0);
+      }
+    }
+    if (!IsHistogramDisabled("ZvertexNContributors"))
+    {
+      Histo(eventSelection,triggerClassName,centrality,"ZvertexNContributors")->Fill(vertex->GetNContributors());
+    }
+  }
+  
+  if ( AliAnalysisMuonUtility::IsAODEvent(Event()) )
+  {
+    const AliAODTZERO* tzero = static_cast<const AliAODEvent*>(Event())->GetTZEROData();
+    
+    if (tzero && !IsHistogramDisabled("T0Zvertex"))
+    {
+      Histo(eventSelection,triggerClassName,centrality,"T0Zvertex")->Fill(tzero->GetT0VertexRaw());
+    }
+  }
+  else
+  {
+    const AliESDTZERO* tzero = static_cast<const AliESDEvent*>(Event())->GetESDTZERO();
+    
+    if (tzero && !IsHistogramDisabled("T0Zvertex"))
+    {
+      Histo(eventSelection,triggerClassName,centrality,"T0Zvertex")->Fill(tzero->GetT0zVertex());
+    }
+  }
+  
+  AliVVZERO* vzero = Event()->GetVZEROData();
+  
+  if (vzero)
+  {
+    Float_t v0a = vzero->GetV0ATime();
+    Float_t v0c = vzero->GetV0CTime();
+    
+    Float_t x = v0a-v0c;
+    Float_t y = v0a+v0c;
+    
+    if (!IsHistogramDisabled("V0A"))
+    {
+      Histo(eventSelection,triggerClassName,centrality,"V0AMult")->Fill(vzero->GetMTotV0A());
+    }
+    if (!IsHistogramDisabled("V02D"))
+    {
+      Histo(eventSelection,triggerClassName,centrality,"V02D")->Fill(x,y);
+    }
+    
+    Bool_t background,pileup,satellite;
+    
+    Bool_t tzero = AliAnalysisMuonUtility::EAGetTZEROFlags(Event(),background,pileup,satellite);
+    
+    if (tzero)
+    {
+      if ( background )
+      {
+        if (!IsHistogramDisabled("V02DwT0BG"))
+        {
+          Histo(eventSelection,triggerClassName,centrality,"V02DwT0BG")->Fill(x,y);
+        }
+      }
+      
+      if ( pileup )
+      {
+        if (!IsHistogramDisabled("V02DwT0PU"))
+        {
+          Histo(eventSelection,triggerClassName,centrality,"V02DwT0PU")->Fill(x,y);
+        }
+        
+        if ( !IsHistogramDisabled("PileUpEstimators") )
+        {
+          Histo(eventSelection,triggerClassName,centrality,"PileUpEstimators")->Fill("TZERO",1.0);
+        }
+      }
+      
+      if ( satellite )
+      {
+        if (!IsHistogramDisabled("V02DwT0SAT"))
+        {
+          Histo(eventSelection,triggerClassName,centrality,"V02DwT0SAT")->Fill(x,y);
+        }
+      }
+      
+      if ( !background && !pileup && !satellite )
+      {
+        if (!IsHistogramDisabled("V02DwT0BB"))
+        {
+          Histo(eventSelection,triggerClassName,centrality,"V02DwT0BB")->Fill(x,y);
+        }
+      }
+    }
+  }
+  
+  //  /* FIXME : how to properly get multiplicity from AOD and ESD consistently ?
+  //   is is doable at all ?
+  
+  TH1* hpileup = Histo(eventSelection,triggerClassName,centrality,"PileUpEstimators");
+  
+  
+  //  virtual Bool_t  IsPileupFromSPD(Int_t minContributors=3, Double_t minZdist=0.8, Double_t nSigmaZdist=3., Double_t nSigmaDiamXY=2., Double_t nSigmaDiamZ=5.) const;
+  
+  const Double_t nSigmaZdist=3.0;
+  const Double_t nSigmaDiamXY=2.0;
+  const Double_t nSigmaDiamZ=5.0;
+  
+  for ( Int_t minContributors = 3; minContributors <= 6; ++minContributors )
+  {
+    for ( double minZdist = 0.6; minZdist <= 0.8; minZdist += 0.2 )
+    {
+      if ( Event()->IsPileupFromSPD(minContributors,minZdist,nSigmaZdist,nSigmaDiamXY,nSigmaDiamZ) )
+      {
+        hpileup->Fill(Form("SPD:n%dd%d",minContributors,static_cast<Int_t>(10*minZdist)),1);
+      }
+    }
+  }
+  
+  
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuGlobal::FillHistosForMCEvent(const char* eventSelection,
+                                                 const char* triggerClassName,
+                                                 const char* centrality)
+{
+  // Fill MCEvent-wise histograms
+  
+  Double_t Zvertex = AliAnalysisMuonUtility::GetMCVertexZ(Event(),MCEvent());
+  
+  if (!IsHistogramDisabled("Zvertex"))
+  {
+    MCHisto(eventSelection,triggerClassName,centrality,"Zvertex")->Fill(Zvertex);
+  }
+
+  if (!IsHistogramDisabled("RecZvertexVsMCZvertex"))
+  {
+    const AliVVertex* vertex = Event()->GetPrimaryVertex();
+    if  (vertex && vertex->GetNContributors()>0)
+    {
+      MCHisto(eventSelection,triggerClassName,centrality,"RecZvertexVsMCZvertex")->Fill(Zvertex,vertex->GetZ());
+    }
+  }
+  
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuGlobal::SelectAnyTriggerClass(const TString& firedTriggerClasses, TString& acceptedTriggerClasses) const
+{
+  /// Accept all trigger classes
+  if ( firedTriggerClasses.Length()>0)
+  {
+    acceptedTriggerClasses = "NOTRIGGERSELECTION";
+    return kTRUE;
+  }
+  return kFALSE;
+}
+
diff --git a/PWG/muon/AliAnalysisMuMuGlobal.h b/PWG/muon/AliAnalysisMuMuGlobal.h
new file mode 100644 (file)
index 0000000..f39eb71
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef ALIANALYSISMUMUGLOBAL_H
+#define ALIANALYSISMUMUGLOBAL_H
+
+/**
+ * \class AliAnalysisMuMuGlobal
+ * \brief Basic histogramming of global event properties (vertex, pile-up, background)
+ * \author L. Aphecetche (Subatech)
+ */
+
+#include "AliAnalysisMuMuBase.h"
+
+class AliAnalysisMuMuGlobal : public AliAnalysisMuMuBase
+{
+public:
+  AliAnalysisMuMuGlobal();
+  virtual ~AliAnalysisMuMuGlobal() {}
+  
+  void FillHistosForEvent(const char* eventSelection, const char* triggerClassName,
+                          const char* centrality);
+
+  void FillHistosForMCEvent(const char* eventSelection, const char* triggerClassName,
+                            const char* centrality);
+
+  virtual void DefineHistogramCollection(const char* eventSelection, const char* triggerClassName,
+                                         const char* centrality);
+
+  Bool_t SelectAnyTriggerClass(const TString& firedTriggerClasses, TString& acceptedTriggerClasses) const;
+  
+
+private:
+  ClassDef(AliAnalysisMuMuGlobal,1) // implementation of AliAnalysisMuMuBase for global event properties
+};
+
+#endif
diff --git a/PWG/muon/AliAnalysisMuMuMinv.cxx b/PWG/muon/AliAnalysisMuMuMinv.cxx
new file mode 100644 (file)
index 0000000..179433d
--- /dev/null
@@ -0,0 +1,544 @@
+#include "AliAnalysisMuMuMinv.h"
+
+/**
+ *
+ * \ingroup pwg-muon-mumu
+ *
+ * \class AliAnalysisMuMuMinv
+ * 
+ * Analysis which fills a bunch of histograms for invariant mass analysis of J/psi 
+ *
+ * Can be used on real data and/or simulated (for instance to get Acc x Eff)
+ *
+ * Can optionally use as input an already computed Acc x Eff matrix that will be applied
+ * when filling the invariant mass histograms.
+ *
+ */
+
+#include "TH2F.h"
+#include "AliLog.h"
+#include "TObjArray.h"
+#include "AliAnalysisMuMuBinning.h"
+#include "TString.h"
+#include "TLorentzVector.h"
+#include "TString.h"
+#include "AliMCEvent.h"
+#include "AliMergeableCollection.h"
+#include "AliAnalysisMuonUtility.h"
+#include "TParameter.h"
+#include <cassert>
+
+ClassImp(AliAnalysisMuMuMinv)
+
+//_____________________________________________________________________________
+AliAnalysisMuMuMinv::AliAnalysisMuMuMinv()
+: AliAnalysisMuMuBase(),
+fAccEffHisto(0x0)
+{
+  // FIXME : find the AccxEff histogram from HistogramCollection()->Histo("/EXCHANGE/JpsiAccEff")
+  
+//  if ( accEff )
+//  {
+//    fAccEffHisto = static_cast<TH2F*>(accEff->Clone());
+//    fAccEffHisto->SetDirectory(0);
+//  }
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuMinv::~AliAnalysisMuMuMinv()
+{
+  /// dtor
+  delete fAccEffHisto;
+}
+
+//_____________________________________________________________________________
+void
+AliAnalysisMuMuMinv::DefineHistogramCollection(const char* eventSelection,
+                                               const char* triggerClassName,
+                                               const char* centrality)
+{
+  /// Define the histograms this analysis will use
+  
+  if ( Histo(eventSelection,triggerClassName,centrality,"AliAnalysisMuMuMinv") )
+  {
+    return;
+  }
+  
+  // dummy histogram to signal that we already defined all our histograms (see above)
+  CreateEventHistos(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"AliAnalysisMuMuMinv","Dummy semaphore",1,0,1);
+
+  /// Create invariant mass histograms
+  
+  Double_t minvMin = 0;
+  Double_t minvMax = 16;
+  Int_t nMinvBins = GetNbins(minvMin,minvMax,0.025);
+  
+  Int_t nMCMinvBins = GetNbins(minvMin,minvMax,0.1);
+  
+  //  TObjArray* bins = fBinning->CreateBinObjArray("psi","y vs pt,integrated,pt,y,phi","");
+  TObjArray* bins = Binning()->CreateBinObjArray("psi");
+  
+  CreatePairHistos(eventSelection,triggerClassName,centrality,"Pt","#mu+#mu- Pt distribution",
+                  200,0,20);
+
+  Int_t nbinsy = 6;
+  Double_t ymin = -4.0;
+  Double_t ymax = -2.5;
+  
+  CreatePairHistos(eventSelection,triggerClassName,centrality,"y","#mu+#mu- y distribution",nbinsy,ymin,ymax);
+
+  //  CreatePairHistos(eventSelection,triggerClassName,centrality,"BinFlowPt","#mu+#mu- BinFlowPt distribution",
+  //                  200,0,20);
+  
+  CreatePairHistos(eventSelection,triggerClassName,centrality,"PtRecVsSim","#mu+#mu- Pt distribution rec vs sim",
+                  200,0,20,200,0,20);
+  
+  if (!Histo("INPUT","ALL","Pt"))
+  {
+    HistogramCollection()->Adopt("/INPUT/ALL",new TH1F("Pt","Pt",200,0,20));
+    HistogramCollection()->Adopt("/INPUT/INYRANGE",new TH1F("Pt","Pt",200,0,20));
+    HistogramCollection()->Adopt("/INPUT/ALL",new TH1F("Y","Y",nbinsy,ymin,ymax));
+    HistogramCollection()->Adopt("/INPUT/INYRANGE",new TH1F("Y","Y",nbinsy,ymin,ymax));
+  }
+  
+  TIter next(bins);
+  AliAnalysisMuMuBinning::Range* r;
+  Int_t nb(0);
+  
+  while ( ( r = static_cast<AliAnalysisMuMuBinning::Range*>(next()) ) )
+  {
+    TString minvName(GetMinvHistoName(*r,ShouldCorrectDimuonForAccEff()));
+    
+    if ( IsHistogramDisabled(minvName.Data()) ) continue;
+    
+    ++nb;
+    
+    AliDebug(1,Form("bin %d %s histoname = %s",nb,r->AsString().Data(),minvName.Data()));
+    
+    CreatePairHistos(eventSelection,triggerClassName,centrality,minvName.Data(),
+                     Form("#mu+#mu- inv. mass %s %s;M_{#mu^+#mu^-} (GeV/c^2)",
+                          ShouldCorrectDimuonForAccEff() ? "(AccxEff corrected)":"",
+                          r->AsString().Data()),
+                     nMinvBins,minvMin,minvMax);
+    
+    TString hname(GetMinvHistoName(*r,kFALSE));
+    
+    TH1* h = HistogramCollection()->Histo("/INPUT/ALL",hname.Data());
+    if (!h)
+    {
+      h = new TH1F(hname.Data(),Form("MC #mu+#mu- inv. mass %s",r->AsString().Data()),
+                   nMCMinvBins,minvMin,minvMax);
+      
+      HistogramCollection()->Adopt("/INPUT/ALL",h);
+      
+      HistogramCollection()->Adopt("/INPUT/INYRANGE",static_cast<TH1*>(h->Clone()));
+    }
+  }
+  
+  delete bins;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuMinv::FillHistosForPair(const char* eventSelection, const char* triggerClassName,
+                                            const char* centrality, const char* pairCutName,
+                                            const AliVParticle& tracki,
+                                            const AliVParticle& trackj)
+{
+  /** Fill histograms for muon track pairs
+   */
+  
+  if (!AliAnalysisMuonUtility::IsMuonTrack(&tracki) ) return;
+  if (!AliAnalysisMuonUtility::IsMuonTrack(&trackj) ) return;
+
+  TLorentzVector pi(tracki.Px(),tracki.Py(),tracki.Pz(),
+                    TMath::Sqrt(AliAnalysisMuonUtility::MuonMass2()+tracki.P()*tracki.P()));
+  
+  
+  TLorentzVector pair4Momentum(trackj.Px(),trackj.Py(),trackj.Pz(),
+                               TMath::Sqrt(AliAnalysisMuonUtility::MuonMass2()+trackj.P()*trackj.P()));
+  
+  pair4Momentum += pi;
+  
+  
+  if (!IsHistogramDisabled("Chi12"))
+  {
+    Histo(eventSelection,triggerClassName,centrality,pairCutName,"Chi12")
+    ->Fill(
+           AliAnalysisMuonUtility::GetChi2perNDFtracker(&tracki),
+           AliAnalysisMuonUtility::GetChi2perNDFtracker(&trackj));
+  }
+  
+  if (!IsHistogramDisabled("Rabs12"))
+  {
+    Histo(eventSelection,triggerClassName,centrality,pairCutName,"Rabs12")
+    ->Fill(AliAnalysisMuonUtility::GetRabs(&tracki),
+           AliAnalysisMuonUtility::GetRabs(&trackj));
+  }
+  
+  if ( ( tracki.Charge() != trackj.Charge() ) )
+  {
+    if ( !IsHistogramDisabled("Pt") )
+    {
+      Histo(eventSelection,triggerClassName,centrality,pairCutName,"Pt")->Fill(pair4Momentum.Pt());
+    }
+
+    if ( !IsHistogramDisabled("y") )
+    {
+      Histo(eventSelection,triggerClassName,centrality,pairCutName,"y")->Fill(pair4Momentum.Y());
+    }
+
+    if ( HasMC() )
+    {
+      Int_t labeli = tracki.GetLabel();
+      Int_t labelj = trackj.GetLabel();
+      
+      if ( labeli < 0 || labelj < 0 )
+      {
+        AliError("Got negative labels!");
+      }
+      else
+      {
+        AliVParticle* mcTracki = MCEvent()->GetTrack(labeli);
+        AliVParticle* mcTrackj = MCEvent()->GetTrack(labelj);
+        
+        TLorentzVector mcpi(mcTracki->Px(),mcTracki->Py(),mcTracki->Pz(),
+                            TMath::Sqrt(AliAnalysisMuonUtility::MuonMass2()+mcTracki->P()*mcTracki->P()));
+        TLorentzVector mcpj(mcTrackj->Px(),mcTrackj->Py(),mcTrackj->Pz(),
+                            TMath::Sqrt(AliAnalysisMuonUtility::MuonMass2()+mcTrackj->P()*mcTrackj->P()));
+        
+        mcpj += mcpi;
+        
+        Histo(eventSelection,triggerClassName,centrality,pairCutName,"PtRecVsSim")->Fill(mcpj.Pt(),pair4Momentum.Pt());
+        
+      }
+    }
+    
+
+    TObjArray* bins = Binning()->CreateBinObjArray("psi","ptvsy,yvspt,pt,y,phi","");
+    TIter nextBin(bins);
+    AliAnalysisMuMuBinning::Range* r;
+    
+    while ( ( r = static_cast<AliAnalysisMuMuBinning::Range*>(nextBin()) ) )
+    {
+      Bool_t ok(kFALSE);
+      
+      if ( r->IsIntegrated() )
+      {
+        ok = kTRUE;
+      }
+      else if ( r->Is2D() )
+      {
+        if ( r->AsString().BeginsWith("PTVSY") )
+        {
+          ok = r->IsInRange(pair4Momentum.Rapidity(),pair4Momentum.Pt());
+        }
+        else if ( r->AsString().BeginsWith("YVSPT") )
+        {
+          ok = r->IsInRange(pair4Momentum.Pt(),pair4Momentum.Rapidity());
+        }
+        else
+        {
+          AliError(Form("Don't know how to deal with 2D bin %s",r->AsString().Data()));
+        }
+      }
+      else
+      {
+        if ( r->Quantity() == "PT" )
+        {
+          ok = r->IsInRange(pair4Momentum.Pt());
+        }
+        else if ( r->Quantity() == "Y" )
+        {
+          ok = r->IsInRange(pair4Momentum.Rapidity());
+        }
+        else if ( r->Quantity() == "PHI" )
+        {
+          ok = r->IsInRange(pair4Momentum.Phi());
+        }
+        else if ( r->Quantity() == "NCH" )
+        {
+          TList* list = static_cast<TList*>(Event()->FindListObject("NCH"));
+          if (list)
+          {
+            TIter next(list);
+            TParameter<Double_t>* p;
+            
+            while ( ( p = static_cast<TParameter<Double_t>*>(next())) )
+            {
+              if (TString(eventSelection).Contains(p->GetName()))
+              {
+                ok = r->IsInRange(p->GetVal());
+                break;
+              }
+            }
+          }
+        }
+      }
+      
+      if ( ok )
+      {
+        TString minvName = GetMinvHistoName(*r,kFALSE);
+        
+        if (!IsHistogramDisabled(minvName.Data()))
+        {
+          TH1* h = Histo(eventSelection,triggerClassName,centrality,pairCutName,minvName.Data());
+          
+          if (!h)
+          {
+            AliError(Form("Could not get %s",minvName.Data()));
+            continue;
+          }
+          h->Fill(pair4Momentum.M());
+          
+          if ( fAccEffHisto )
+          {
+            // FIXME : fill Minv with weight = 1/AccxEff
+          }
+        }
+      }
+    }
+    
+    delete bins;
+  }
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuMinv::FillHistosForMCEvent(const char* /*eventSelection*/,
+                                               const char* /*triggerClassName*/,
+                                               const char* /*centrality*/)
+{
+  /** Fill histograms for MC event
+   *
+   * FIXME: this is here we should streamline a bit the code to carefully
+   * compute the measured and truth values for Pt, Y, and (Pt,Y), in order
+   * to be able to investigate unfolding techniques later on...
+   */
+  
+  Int_t nMCTracks = MCEvent()->GetNumberOfTracks();
+
+  for ( Int_t i = 0; i < nMCTracks; ++i )
+  {
+    AliVParticle* part = MCEvent()->GetTrack(i);
+    
+    if  ( AliAnalysisMuonUtility::IsPrimary(part,MCEvent()) &&
+          AliAnalysisMuonUtility::GetMotherIndex(part)==-1 )
+    {
+            Histo("INPUT","ALL","Pt")->Fill(part->Pt());
+            Histo("INPUT","ALL","Y")->Fill(part->Y());
+            if ( part->Y() < -2.5 && part->Y() > -4.0 )
+            {
+              Histo("INPUT","INYRANGE","Pt")->Fill(part->Pt());
+              Histo("INPUT","INYRANGE","Y")->Fill(part->Y());
+            }
+
+    }
+    
+  }
+  
+//  Int_t nTracks = AliAnalysisMuonUtility::GetNTracks(Event());
+//
+//  Double_t measuredY(0.0);
+//  
+//  for (Int_t i = 0; i < nTracks; ++i)
+//  {
+//    AliVParticle* tracki = AliAnalysisMuonUtility::GetTrack(i,Event());
+//
+//    if (!AliAnalysisMuonUtility::IsMuonTrack(tracki) ) continue;
+//
+//    for (Int_t j = i+1; j < nTracks; ++j )
+//    {
+//      AliVParticle* trackj = AliAnalysisMuonUtility::GetTrack(j,Event());
+//      
+//      if (!AliAnalysisMuonUtility::IsMuonTrack(trackj) ) continue;
+//
+//      TLorentzVector pi(tracki->Px(),tracki->Py(),tracki->Pz(),
+//                        TMath::Sqrt(AliAnalysisMuonUtility::MuonMass2()+tracki->P()*tracki->P()));
+//      
+//      TLorentzVector pair4Momentum(trackj->Px(),trackj->Py(),trackj->Pz(),
+//                                   TMath::Sqrt(AliAnalysisMuonUtility::MuonMass2()+trackj->P()*trackj->P()));
+//      
+//      pair4Momentum += pi;
+//      
+//      measuredY = pi.Y();
+//      
+//      rur->Fill(measuredY,trueY); // FIXME : is this working if more than one pair is found in the reconstructed tracks ???
+//      // should we try to find the closest one in minv and assign the other(s)
+//      // to rur->Fake() ?
+//    }
+//    
+//  }
+//
+//  if ( ! ( measuredY < 0.0 ) )
+//  {
+//    rur->Miss(trueY);
+//  }
+}
+
+////_____________________________________________________________________________
+//void AliAnalysisMuMuMinv::FillMC()
+//{
+//  // Fill the input Monte-Carlo histograms related to muons
+//  
+//  // Specific things for MC
+//  if (!Histo("INPUT","ALL","Pt"))
+//  {
+//    HistogramCollection()->Adopt("/INPUT/ALL",new TH1F("Pt","Pt",200,0,20));
+//    HistogramCollection()->Adopt("/INPUT/INYRANGE",new TH1F("Pt","Pt",200,0,20));
+//    
+//    Double_t rapidityMin = -5;
+//    Double_t rapidityMax = -2;
+//    Int_t nbinsRapidity = GetNbins(rapidityMin,rapidityMax,0.05);
+//    
+//    HistogramCollection()->Adopt("/INPUT/ALL",new TH1F("Y","Y",nbinsRapidity,rapidityMin,rapidityMax));
+//    HistogramCollection()->Adopt("/INPUT/INYRANGE",new TH1F("Y","Y",nbinsRapidity,rapidityMin,rapidityMax));
+//    
+//    Double_t etaMin = -5;
+//    Double_t etaMax = -2;
+//    Int_t nbinsEta = GetNbins(etaMin,etaMax,0.05);
+//    
+//    HistogramCollection()->Adopt("/INPUT/ALL",new TH1F("Eta","Eta",nbinsEta,etaMin,etaMax));
+//    HistogramCollection()->Adopt("/INPUT/INYRANGE",new TH1F("Eta","Eta",nbinsEta,etaMin,etaMax));
+//  }
+//  
+//  Int_t nMCTracks = MCEvent()->GetNumberOfTracks();
+//  
+//  TObjArray* bins = Binning()->CreateBinObjArray("psi","ptvsy,yvspt,pt,y,phi","");
+//  TIter nextBin(bins);
+//  AliAnalysisMuMuBinning::Range* r;
+//  
+//  for ( Int_t i = 0; i < nMCTracks; ++i )
+//  {
+//    AliVParticle* part = MCEvent()->GetTrack(i);
+//    
+//    //    std::cout << "part " << i << " isprimary=" << AliAnalysisMuonUtility::IsPrimary(part,MCEvent()) << " motherindex=" << AliAnalysisMuonUtility::GetMotherIndex(part) << std::endl;
+//    //
+//    //    part->Print();
+//    
+//    if  (AliAnalysisMuonUtility::IsPrimary(part,MCEvent()) &&
+//         AliAnalysisMuonUtility::GetMotherIndex(part)==-1)
+//    {
+//      
+//      Histo("INPUT","ALL","Pt")->Fill(part->Pt());
+//      Histo("INPUT","ALL","Y")->Fill(part->Y());
+//      Histo("INPUT","ALL","Eta")->Fill(part->Eta());
+//      
+//      if ( part->Y() < -2.5 && part->Y() > -4.0 )
+//      {
+//        Histo("INPUT","INYRANGE","Pt")->Fill(part->Pt());
+//        Histo("INPUT","INYRANGE","Y")->Fill(part->Y());
+//        Histo("INPUT","INYRANGE","Eta")->Fill(part->Eta());
+//      }
+//      
+//      nextBin.Reset();
+//      
+//      while ( ( r = static_cast<AliAnalysisMuMuBinning::Range*>(nextBin()) ) )
+//      {
+//        Bool_t ok(kFALSE);
+//        
+//        if ( r->IsIntegrated() )
+//        {
+//          ok = kTRUE;
+//        }
+//        else if ( r->Is2D() )
+//        {
+//          if ( r->AsString().BeginsWith("PTVSY") )
+//          {
+//            ok = r->IsInRange(part->Y(),part->Pt());
+//          }
+//          else if ( r->AsString().BeginsWith("YVSPT") )
+//          {
+//            ok = r->IsInRange(part->Pt(),part->Y());
+//          }
+//          else
+//          {
+//            AliError(Form("Don't know how to deal with 2D bin %s",r->AsString().Data()));
+//          }
+//        }
+//        else
+//        {
+//          if ( r->Quantity() == "PT" )
+//          {
+//            ok = r->IsInRange(part->Pt());
+//          }
+//          else if ( r->Quantity() == "Y" )
+//          {
+//            ok = r->IsInRange(part->Y());
+//          }
+//          else if ( r->Quantity() == "PHI" )
+//          {
+//            ok = r->IsInRange(part->Phi());
+//          }
+//        }
+//        
+//        if ( ok )
+//        {
+//          TString hname = GetMinvHistoName(*r,kFALSE);
+//          
+//          if (!IsHistogramDisabled(hname.Data()))
+//          {
+//            
+//            TH1* h = Histo("INPUT","ALL",hname.Data());
+//            
+//            if (!h)
+//            {
+//              AliError(Form("Could not get ALL %s",hname.Data()));
+//              continue;
+//            }
+//            
+//            h->Fill(part->M());
+//            
+//            if ( part->Y() < -2.5 && part->Y() > -4.0 )
+//            {
+//              h = Histo("INPUT","INYRANGE",hname.Data());
+//              if (!h)
+//              {
+//                AliError(Form("Could not get INYRANGE %s",hname.Data()));
+//                continue;
+//              }
+//              h->Fill(part->M());
+//            }
+//            
+//          }
+//          
+//        }
+//      }
+//    }
+//  }
+//  
+//  delete bins;
+//}
+//
+
+//_____________________________________________________________________________
+TString AliAnalysisMuMuMinv::GetMinvHistoName(const AliAnalysisMuMuBinning::Range& r, Bool_t accEffCorrected) const
+{
+  /// Get the invariant mass histogram name
+  return TString::Format("MinvUS%s%s",r.AsString().Data(),
+                         accEffCorrected ? "_AccEffCorr" : "");
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuMinv::IsRapidityInRange(const AliVParticle& t1, const AliVParticle& t2, Double_t& ymin, Double_t& ymax) const
+{
+  /// Whether the particle pair has its rapidity within [ymin,ymax[
+  
+  TLorentzVector p1(t1.Px(),t1.Py(),t1.Pz(),TMath::Sqrt(AliAnalysisMuonUtility::MuonMass2()+t1.P()*t1.P()));
+  TLorentzVector p2(t2.Px(),t2.Py(),t2.Pz(),TMath::Sqrt(AliAnalysisMuonUtility::MuonMass2()+t2.P()*t2.P()));
+  
+  TLorentzVector total(p1+p2);
+  
+  Double_t y = total.Rapidity();
+
+  return  ( y < ymax && y > ymin );
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuMinv::NameOfIsRapidityInRange(TString& name, Double_t& ymin, Double_t& ymax) const
+{
+  /** Get the name of the rapidity range (making the IsRapidityInRange method useable as an
+   * AliAnalysisMuMuCutElement
+   */
+  
+  name.Form("PAIRYIN%2.1f-%2.1f",ymin,ymax);
+}
+
diff --git a/PWG/muon/AliAnalysisMuMuMinv.h b/PWG/muon/AliAnalysisMuMuMinv.h
new file mode 100644 (file)
index 0000000..ca41935
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef ALIANALYSISMUMUMINV_H
+#define ALIANALYSISMUMUMINV_H
+
+/**
+ * \class AliAnalysisMuMuMinv
+ * \brief Invariant mass analysis of muon pairs
+ * \author L. Aphecetche (Subatech)
+ */
+
+#include "AliAnalysisMuMuBase.h"
+#include "AliAnalysisMuMuBinning.h"
+#include "TString.h"
+
+class TH2F;
+class AliVParticle;
+
+class AliAnalysisMuMuMinv : public AliAnalysisMuMuBase
+{
+public:
+
+  AliAnalysisMuMuMinv();
+  virtual ~AliAnalysisMuMuMinv();
+  
+  Bool_t IsRapidityInRange(const AliVParticle& t1, const AliVParticle& t2,
+                           Double_t& ymin, Double_t& ymax) const;
+
+  virtual void FillHistosForMCEvent(const char* /*eventSelection*/,const char* /*triggerClassName*/,const char* /*centrality*/);
+
+  void NameOfIsRapidityInRange(TString& name, Double_t& ymin, Double_t& ymax) const;
+
+  Bool_t ShouldCorrectDimuonForAccEff() const { return (fAccEffHisto != 0x0); }
+  
+  void DefineHistogramCollection(const char* eventSelection, const char* triggerClassName,
+                                 const char* centrality);
+
+  virtual void FillHistosForPair(const char* eventSelection,const char* triggerClassName,
+                                 const char* centrality,
+                                 const char* pairCutName,
+                                 const AliVParticle& part,
+                                 const AliVParticle& part2);
+  
+private:
+  
+  /// not implemented on purpose
+  AliAnalysisMuMuMinv(const AliAnalysisMuMuMinv& rhs);
+  /// not implemented on purpose
+  AliAnalysisMuMuMinv& operator=(const AliAnalysisMuMuMinv& rhs);
+  
+  void CreateMinvHistograms(const char* eventSelection, const char* triggerClassName, const char* centrality);
+  
+  TString GetMinvHistoName(const AliAnalysisMuMuBinning::Range& r, Bool_t accEffCorrected) const;
+  
+
+private:
+  TH2F* fAccEffHisto; // input Acc x Eff (optional)
+  
+  ClassDef(AliAnalysisMuMuMinv,1) // implementation of AliAnalysisMuMuBase for muon pairs
+};
+
+#endif
+
diff --git a/PWG/muon/AliAnalysisMuMuNch.cxx b/PWG/muon/AliAnalysisMuMuNch.cxx
new file mode 100644 (file)
index 0000000..792634c
--- /dev/null
@@ -0,0 +1,1135 @@
+#include "AliAnalysisMuMuNch.h"
+
+/**
+ *
+ * \ingroup pwg-muon-mumu
+ *
+ * \class AliAnalysisMuMuNch
+ *
+ * SPD tracklet to Nch analysis
+ *
+ * The idea is that this sub-analysis is used first (within the AliAnalysisTaskMuMu sub-framework)
+ * in order to compute the number of charged particles within an event, so that information
+ * can be used in subsequent sub-analysis, like the invariant mass or mean pt ones.
+ *
+ */
+
+#include "AliAODTracklets.h"
+#include "AliAnalysisMuonUtility.h"
+#include "AliLog.h"
+#include "AliAODEvent.h"
+#include "AliESDUtils.h"
+#include "TMath.h"
+#include "AliAnalysisMuMuCutRegistry.h"
+#include "AliAnalysisMuMuCutElement.h"
+#include "Riostream.h"
+#include "TParameter.h"
+#include <set>
+#include <utility>
+#include "AliMergeableCollection.h"
+#include "AliMCEvent.h"
+#include "AliAODMCParticle.h"
+#include "TAxis.h"
+#include "TCanvas.h"
+#include "TH2F.h"
+#include "TF1.h"
+#include "TProfile.h"
+#include "TObjString.h"
+
+
+namespace {
+
+  Double_t SPDgeomR(Double_t* x,Double_t* par) // Eta position of the SPD right edge eta as "seen" from a z vertex position
+  {
+    // par[0] = radius of SPD layer
+    
+    Double_t d = x[0];
+    Double_t z(0.);
+    Double_t theta(0.);
+    
+    if( d < 14.09999 )
+    {
+      z = 14.1 - d;
+      theta = TMath::ATan(par[0]/z);
+    }
+    
+    else if( d > 14.09999 )
+    {
+      z = d - 14.1;
+      theta = TMath::Pi() - TMath::ATan(par[0]/z);
+    }
+    
+    return -TMath::Log(TMath::Tan(theta/2.));
+  }
+  
+  Double_t SPDgeomL(Double_t* x,Double_t* par) // Eta position of the SPD left edge eta as "seen" from a z vertex position
+  {
+    // par[0] = radius of SPD layer
+    
+    Double_t d = x[0];
+    Double_t z(0.);
+    Double_t theta(0.);
+    
+    if( d > -14.09999 )
+    {
+      z = 14.1 + d;
+      theta = TMath::Pi() - TMath::ATan(par[0]/z);
+    }
+    
+    if( d < -14.09999 )
+    {
+      z = -14.1 - d;
+      theta = TMath::ATan(par[0]/z);
+    }
+    
+    return -TMath::Log(TMath::Tan(theta/2.));
+  }
+
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuNch::AliAnalysisMuMuNch(TH2* spdCorrection, Double_t etaMin, Double_t etaMax
+                                      , Double_t zMin, Double_t zMax,Bool_t disableHistos, Bool_t computeResolution)
+: AliAnalysisMuMuBase(),
+fSPDCorrection(0x0),
+fEtaAxis(new TAxis(TMath::Nint(10./0.1),-5.,5.)),
+fZAxis(new TAxis(TMath::Nint(80/0.25),-40.,40.)),
+fCurrentEvent(0x0),
+fEtaMin(etaMin),
+fEtaMax(etaMax),
+fZMin(zMin),
+fZMax(zMax),
+fResolution(computeResolution)
+{
+  if ( spdCorrection )
+  {
+    fSPDCorrection = static_cast<TH2F*>(spdCorrection->Clone());
+    fSPDCorrection->SetDirectory(0);
+  }
+  DefineSPDAcceptance();
+  
+  if ( disableHistos )
+  {
+    DisableHistograms("*");
+  }
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuNch::~AliAnalysisMuMuNch()
+{
+  delete fSPDCorrection;
+  delete fEtaAxis;
+  delete fZAxis;
+  delete fSPD1LR;
+  delete fSPD1LL;
+  delete fSPD2LR;
+  delete fSPD2LL;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuNch::DefineHistogramCollection(const char* eventSelection,
+                                                   const char* triggerClassName,
+                                                   const char* centrality)
+{
+  // Define multiplicity histos
+  
+  if ( Histo(eventSelection,triggerClassName,centrality,"AliAnalysisMuMuNch") )
+  {
+    return;
+  }
+
+  // dummy histogram to signal that we already defined all our histograms (see above)
+  CreateEventHistos(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"AliAnalysisMuMuNch","Dummy semaphore",1,0,1);
+
+  Double_t multMin = 0.;  //Tracklets multiplicity range
+  Double_t multMax = 500.;
+  Int_t nbinsMult = GetNbins(multMin,multMax,1.);
+  
+  Double_t phimin = 0.; //Phi range
+  Double_t phimax = 2*TMath::Pi();
+  Int_t nphibins = GetNbins(phimin,phimax,0.05);
+  
+  if ( !fSPDCorrection && fResolution ) // Resolution histos
+  {
+    CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"EtaRes","#eta resolution;#eta_{Reco} - #eta_{MC};Counts",(fEtaAxis->GetNbins())*2,fEtaAxis->GetXmin(),fEtaAxis->GetXmax());
+    
+    CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"PhiRes","#phi resolution;#phi_{Reco} - #phi_{MC};Counts",nphibins*2,-phimax,phimax);
+    
+    CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"PhiResShifted","#phi resolution;#phi_{Reco} - #phi_{MC};Counts",nphibins*4,-phimax/4,phimax/4);
+    
+    CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"EtaResVsZ","#eta resolution vs MC Zvertex;ZVertex (cm);#eta_{Reco} - #eta_{MC}",(fZAxis->GetNbins())*20,fZAxis->GetXmin(),fZAxis->GetXmax(),(fEtaAxis->GetNbins())*8,fEtaAxis->GetXmin(),fEtaAxis->GetXmax());
+    
+    CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"PhiResVsZ","#phi resolution vs MC Zvertex;ZVertex (cm);#phi_{Reco} - #phi_{MC}",(fZAxis->GetNbins())*20,fZAxis->GetXmin(),fZAxis->GetXmax(),nphibins*4,-phimax/4,phimax/4);
+    
+    CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"EtaResVsnC","#eta resolution vs Nof contributors to SPD vertex;NofContributors;#eta_{Reco} - #eta_{MC}",200,0,200,(fEtaAxis->GetNbins())*8,fEtaAxis->GetXmin(),fEtaAxis->GetXmax());
+    
+    CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"PhiResVsnC","#phi resolution vs Nof contributors to SPD vertex;NofContributors;#phi_{Reco} - #phi_{MC}",200,0,200,nphibins*4,-phimax/4,phimax/4);
+    
+    CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"SPDZvResVsnC","SPD Zvertex resolution vs Nof contributors;NofContributors;Zvertex_{Reco} - Zvertex_{MC} (cm)",200,0,200,(fZAxis->GetNbins())*20,fZAxis->GetXmin(),fZAxis->GetXmax());
+    
+    CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"SPDZvResVsMCz","SPD Zvertex resolution vs MC z vertex;MC Zvertex (cm);Zvertex_{Reco} - Zvertex_{MC} (cm)",(fZAxis->GetNbins())*20,fZAxis->GetXmin(),fZAxis->GetXmax(),(fZAxis->GetNbins())*10,fZAxis->GetXmin(),fZAxis->GetXmax());
+    
+    CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"Phi","Reco #phi distribution;#phi;Counts",nphibins,phimin,phimax);
+    
+    CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"MCPhi","MC #phi distribution;#phi;Counts",nphibins,phimin,phimax);
+    
+    CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"Eta","Reco #eta distribution;#phi;Counts",(fEtaAxis->GetNbins())*2,fEtaAxis->GetXmin(),fEtaAxis->GetXmax());
+    
+    CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"MCEta","MC #eta distribution;#phi;Counts",(fEtaAxis->GetNbins())*2,fEtaAxis->GetXmin(),fEtaAxis->GetXmax());
+    
+    return; // When computing resolutions we don't want to create the rest of histos
+  }
+
+  CreateEventHistos(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"TrackletsVsZVertexVsPhi","Number of tracklets vs Z vertex vs #phi;Z vertex;#phi",fZAxis->GetNbins(),fZAxis->GetXmin(),fZAxis->GetXmax(),nphibins,phimin,phimax);
+  AttachSPDAcceptance(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"TrackletsVsZVertexVsPhi");// Attach the SPD acc curves
+  
+  CreateEventHistos(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"TrackletsVsZVertexVsEta","Number of tracklets vs ZVertex vs #eta;ZVertex;#eta",fZAxis->GetNbins(),fZAxis->GetXmin(),fZAxis->GetXmax(),fEtaAxis->GetNbins(),fEtaAxis->GetXmin(),fEtaAxis->GetXmax());
+  AttachSPDAcceptance(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"TrackletsVsZVertexVsEta");
+  
+  CreateEventHistos(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"Tracklets","Number of tracklets distribution;N_{Tracklets};N_{events}",nbinsMult,multMin,multMax);
+    
+  CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"NBkgTrackletsVsZVertexVsEta","Number of background tracklets vs ZVertex vs #eta;ZVertex;#eta",fZAxis->GetNbins(),fZAxis->GetXmin(),fZAxis->GetXmax(),fEtaAxis->GetNbins(),fEtaAxis->GetXmin(),fEtaAxis->GetXmax());
+  AttachSPDAcceptance(kHistoForMCInput,eventSelection,triggerClassName,centrality,"NBkgTrackletsVsZVertexVsEta");
+  
+  CreateEventHistos(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"NchVsZVertexVsEta","Number of charged particles vs ZVertex vs #eta;ZVertex;#eta",fZAxis->GetNbins(),fZAxis->GetXmin(),fZAxis->GetXmax(),fEtaAxis->GetNbins(),fEtaAxis->GetXmin(),fEtaAxis->GetXmax());
+  AttachSPDAcceptance(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"NchVsZVertexVsEta");
+  
+  CreateEventHistos(kHistoForMCInput,eventSelection,triggerClassName,centrality,"NchVsZVertexVsPhi","Number of charged particles vs ZVertex vs #phi;ZVertex;#eta",fZAxis->GetNbins(),fZAxis->GetXmin(),fZAxis->GetXmax(),nphibins,phimin,phimax);
+  
+  CreateEventHistos(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"EventsVsZVertexVsEta","Effective number of events vs ZVertex vs #eta;ZVertex;#eta",fZAxis->GetNbins(),fZAxis->GetXmin(),fZAxis->GetXmax(),fEtaAxis->GetNbins(),fEtaAxis->GetXmin(),fEtaAxis->GetXmax()); // Fill 1 unit in each "touched" eta bin per event (represents the eta bins in which each event contributes)
+  AttachSPDAcceptance(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"EventsVsZVertexVsEta");
+  
+  CreateEventHistos(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"Nch","Number of charged particles distribution;N_{ch};N_{events}",nbinsMult,multMin,multMax);
+  
+  CreateEventHistos(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"dNchdEta","<dNchdEta> distribution;dN_{ch}/d#eta;N_{events}",nbinsMult,multMin,multMax);
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"TrackletsVsNch","Number of tracklets vs Number of charged particles;N_{ch};N_{tracklets}",nbinsMult,multMin,multMax,nbinsMult,multMin,multMax); //Response matrix
+  
+  CreateEventHistos(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"V0AMultVsNch","V0A multiplicity vs Number of charged particles;N_{ch};V0A Mult",nbinsMult,multMin,multMax,nbinsMult,multMin,multMax);
+  
+  CreateEventHistos(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"V0CMultVsNch","V0C multiplicity vs Number of charged particles;N_{ch};V0C Mult",nbinsMult,multMin,multMax,nbinsMult,multMin,multMax);
+  
+  // profile histograms
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"MeanTrackletsVsEta","Mean number of tracklets vs #eta;#eta;<N_{Tracklets}>",fEtaAxis->GetNbins(),fEtaAxis->GetXmin(),fEtaAxis->GetXmax(),0);
+  
+  CreateEventHistos(kHistoForData,eventSelection,triggerClassName,centrality,"MeanTrackletsVsZVertex","Mean number of tracklets vs Z vertex;Z vertex;<N_{Tracklets}>",fZAxis->GetNbins(),fZAxis->GetXmin(),fZAxis->GetXmax(),0);
+
+  CreateEventHistos(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"MeanNchVsEta","Mean number of charged particles vs #eta;#eta;<N_{ch}>",fEtaAxis->GetNbins(),fEtaAxis->GetXmin(),fEtaAxis->GetXmax(),0); // Each bin has to be divided by the binwidth to became dNch/dEta (Done in the terminate and stored in MeandNchdEta histo)
+  
+   CreateEventHistos(kHistoForData | kHistoForMCInput,eventSelection,triggerClassName,centrality,"MeanNchVsZVertex","Mean number of charged particles vs Z vertex;Z vertex;<N_{ch}>",fZAxis->GetNbins(),fZAxis->GetXmin(),fZAxis->GetXmax(),0);
+    
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuNch::DefineSPDAcceptance()
+{
+  // Defines the functions ( eta = f(z) )of the edges (right/left) of the inner and outer SPD layers
+  // R_in = 3.9 cm ; R_out = 7.6 cm
+  fSPD1LR = new TF1("fSPD1LR",SPDgeomR,-40,40,1);
+  fSPD1LR->SetParameter(0,3.9);
+  fSPD1LL = new TF1("fSPD1LL",SPDgeomL,-40,40,1);
+  fSPD1LL->SetParameter(0,3.9);
+  fSPD2LR = new TF1("fSPD2LR",SPDgeomR,-40,40,1);
+  fSPD2LR->SetParameter(0,7.6);
+  fSPD2LL = new TF1("fSPD2LL",SPDgeomL,-40,40,1);
+  fSPD2LL->SetParameter(0,7.6);
+  
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuNch::AddHisto(const char* eventSelection,
+                                  const char* triggerClassName,
+                                  const char* centrality,
+                                  const char* histoname,
+                                  Double_t z,
+                                  TH1* h,Bool_t isMC)
+{
+  // Adds the content of a 1D histo to a 2D histo a the z position
+  
+  Int_t zbin = fZAxis->FindBin(z);
+  TH2F* h2;
+  if (isMC) h2 = static_cast<TH2F*>(MCHisto(eventSelection,triggerClassName,centrality,histoname));
+  else h2 = static_cast<TH2F*>(Histo(eventSelection,triggerClassName,centrality,histoname));
+  
+  for ( Int_t i = 1; i <= h->GetXaxis()->GetNbins(); ++i )
+  {
+    Double_t content = h2->GetCellContent(zbin,i);
+    
+    if ( h->GetBinContent(i) >  0 )
+    {
+      h2->SetCellContent(zbin,i,content + h->GetBinContent(i));
+    }
+  }
+  
+  h2->SetEntries(h2->GetSumOfWeights());
+}
+
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuNch::AttachSPDAcceptance(UInt_t dataType,
+                                             const char* eventSelection,
+                                             const char* triggerClassName,
+                                             const char* centrality,const char* histoname)
+{
+  if ( dataType & kHistoForData )
+  {
+    if( !Histo(eventSelection,triggerClassName,centrality,histoname) )
+    {
+      AliError(Form("ERROR: SPD Acceptance curves attach failed. Histo /%s/%s/%s/%s not found",eventSelection,triggerClassName,centrality,histoname));
+      return;
+    }
+    
+    Histo(eventSelection,triggerClassName,centrality,histoname)->GetListOfFunctions()->Add(fSPD1LR);
+    Histo(eventSelection,triggerClassName,centrality,histoname)->GetListOfFunctions()->Add(fSPD1LL);
+    Histo(eventSelection,triggerClassName,centrality,histoname)->GetListOfFunctions()->Add(fSPD2LR);
+    Histo(eventSelection,triggerClassName,centrality,histoname)->GetListOfFunctions()->Add(fSPD2LL);
+  }
+  if ( dataType & kHistoForMCInput )
+  {
+    if( !MCHisto(eventSelection,triggerClassName,centrality,histoname) )
+    {
+      AliError(Form("ERROR: SPD Acceptance curves attach failed. MC Histo /%s/%s/%s/%s not found",eventSelection,triggerClassName,centrality,histoname));
+      return;
+    }
+    
+    MCHisto(eventSelection,triggerClassName,centrality,histoname)->GetListOfFunctions()->Add(fSPD1LR);
+    MCHisto(eventSelection,triggerClassName,centrality,histoname)->GetListOfFunctions()->Add(fSPD1LL);
+    MCHisto(eventSelection,triggerClassName,centrality,histoname)->GetListOfFunctions()->Add(fSPD2LR);
+    MCHisto(eventSelection,triggerClassName,centrality,histoname)->GetListOfFunctions()->Add(fSPD2LL);
+  }
+  
+}
+
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuNch::FillHistosForEvent(const char* eventSelection,
+                                            const char* triggerClassName,
+                                            const char* centrality)
+{
+  // Fills the data (or reco if simu) multiplicity histos
+  
+  if ( IsHistogrammingDisabled() ) return;
+  
+  if ( fResolution ) return; //When computing resolutions we skip this method
+
+  if ( !AliAnalysisMuonUtility::IsAODEvent(Event()) )
+  {
+    AliError("Don't know how to deal with ESDs...");
+    return;
+  }
+  
+  if ( HasMC() && !fSPDCorrection ) // We have MC but no correction (SPD correction computation mode)so we skip the method
+  {
+    return;
+  }
+
+  AliAODEvent* aod = static_cast<AliAODEvent*>(Event());
+
+  AliVVertex* vertex = aod->GetPrimaryVertexSPD();
+  
+  TList* nchList = static_cast<TList*>(Event()->FindListObject("NCH"));
+  
+  if (!nchList || nchList->IsEmpty() ) // Empty NCH means that there is no SPD vertex ( see SetEvent() ) when runing on data.
+  {
+    return;
+  }
+  
+  Double_t SPDZv;
+  
+  if ( !vertex || vertex->GetZ() == 0.0 ) // Running in Simu the spdZ == 0 means no SPD info. In data, avoid breaks in events w/o SPD vertex
+  {
+    SPDZv = -40.;
+  } 
+  
+  else SPDZv = vertex->GetZ();
+  
+  TH1* hSPDcorrectionVsEta = static_cast<TH1*>(nchList->FindObject("SPDcorrectionVsEta"));
+  TH1* hNTrackletVsEta = static_cast<TH1*>(nchList->FindObject("NTrackletVsEta"));
+  TH1* hNTrackletVsPhi = static_cast<TH1*>(nchList->FindObject("NTrackletVsPhi"));
+  
+  TH1* hNchVsEta =static_cast<TH1*>(hNTrackletVsEta->Clone("NchVsEta"));
+  
+  TProfile* hMeanTrackletsVsEta = static_cast<TProfile*>(Histo(eventSelection,triggerClassName,centrality,"MeanTrackletsVsEta"));
+  TProfile* hMeanNchVsEta = static_cast<TProfile*>(Histo(eventSelection,triggerClassName,centrality,"MeanNchVsEta"));
+
+  TH2* hEventsVsZVertexVsEta = static_cast<TH2*>(Histo(eventSelection,triggerClassName,centrality,"EventsVsZVertexVsEta"));
+    
+  Int_t nBins(0);
+
+  Double_t nch(0.0);
+  Double_t nTracklets(0.0);
+  
+  for (Int_t j = 1 ; j <= fEtaAxis->GetNbins() ; j++) // Loop over eta bins
+  {
+    Double_t correction = hSPDcorrectionVsEta->GetBinContent(j);
+    
+    Double_t eta = fEtaAxis->GetBinCenter(j);
+    
+    if ( correction < 0 ) continue;
+    else if ( correction == 0.0 ) // No tracklets found in this eta bin.
+    {
+      correction = GetSPDCorrection(SPDZv,eta);
+
+      if ( correction == 0. || correction > 2.5) continue; // We need to know if the eta bin is in a region we want to take into account to count or not the zero
+    }
+  
+    Double_t ntr = hNTrackletVsEta->GetBinContent(j); // Tracklets in eta bin
+    
+    nch += ntr * correction; // Number of charged particles (corrected tracklets)
+    
+    nTracklets += ntr;
+    
+    hMeanTrackletsVsEta->Fill(eta,ntr); // Fill the number of tracklets of each eta bin in the profile
+
+    hMeanNchVsEta->Fill(eta,ntr*correction);
+
+    ++nBins; // We sum up the number of bins entering in the computation
+    
+    // Fill the number of charged particles of each eta bin in the profile
+    hNchVsEta->SetBinContent( j, hNchVsEta->GetBinContent(j) * correction );
+    
+    hEventsVsZVertexVsEta->Fill(SPDZv,eta,1.0); // Fill 1 count each eta bin where the events contributes
+  }
+  
+  AddHisto(eventSelection,triggerClassName,centrality,"TrackletsVsZVertexVsPhi",SPDZv,hNTrackletVsPhi);
+  AddHisto(eventSelection,triggerClassName,centrality,"TrackletsVsZVertexVsEta",SPDZv,hNTrackletVsEta);
+
+  AddHisto(eventSelection,triggerClassName,centrality,"NchVsZVertexVsEta",SPDZv,hNchVsEta);
+  
+  Histo(eventSelection,triggerClassName,centrality,"Tracklets")->Fill(nTracklets);
+  Histo(eventSelection,triggerClassName,centrality,"MeanTrackletsVsZVertex")->Fill(SPDZv,nTracklets);
+  Histo(eventSelection,triggerClassName,centrality,"MeanNchVsZVertex")->Fill(SPDZv,nch);
+  
+  Histo(eventSelection,triggerClassName,centrality,"TrackletsVsNch")->Fill(nTracklets,nch);
+  Histo(eventSelection,triggerClassName,centrality,"Nch")->Fill(nch);
+  
+  Double_t V0AMult = 0.;
+  Double_t V0CMult = 0.;
+  
+  AliVVZERO* vzero = aod->GetVZEROData();
+  if (vzero)
+  {
+    Double_t multV0A = vzero->GetMTotV0A();
+    V0AMult = AliESDUtils::GetCorrV0A(multV0A,SPDZv);
+    Double_t multV0C = vzero->GetMTotV0C();
+    V0CMult = AliESDUtils::GetCorrV0C(multV0C,SPDZv);
+    
+    Histo(eventSelection,triggerClassName,centrality,"V0AMultVsNch")->Fill(V0AMult,nch);
+    Histo(eventSelection,triggerClassName,centrality,"V0CMultVsNch")->Fill(V0CMult,nch);
+
+  }
+
+  
+  delete hNchVsEta;
+  
+  // Mean dNch/dEta computation
+  Double_t meandNchdEta(0.);
+  
+  if ( nBins >  0 )
+  {
+    meandNchdEta = nch / (nBins*fEtaAxis->GetBinWidth(5)); // Divide by nBins to get the mean and by the binWidht to get the d/dEta
+  }
+  
+  Histo(eventSelection,triggerClassName,centrality,"dNchdEta")->Fill(meandNchdEta);
+  
+  
+  
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuNch::FillHistosForMCEvent(const char* eventSelection,const char* triggerClassName,const char* centrality)
+{
+  /// Fill input MC multiplicity histos
+  
+  if ( IsHistogrammingDisabled() ) return;
+  
+  TList* nchList = static_cast<TList*>(Event()->FindListObject("NCH"));
+  
+  if (!nchList || nchList->IsEmpty())
+  {
+    return;
+  }
+
+  Double_t MCZv = AliAnalysisMuonUtility::GetMCVertexZ(Event(),MCEvent()); // Definition of MC generated z vertex
+  AliVVertex* vertex = static_cast<AliAODEvent*>(Event())->GetPrimaryVertexSPD();
+  
+  Double_t SPDZv(0.);
+  
+  //____Resolution Histos___
+  if ( !fSPDCorrection && fResolution )
+  {
+    Int_t nContributors(0);
+    if ( vertex )
+    {
+      nContributors  = vertex->GetNContributors();
+      SPDZv = vertex->GetZ();
+    }
+    MCHisto(eventSelection,triggerClassName,centrality,"SPDZvResVsnC")->Fill(nContributors,SPDZv - MCZv);
+    MCHisto(eventSelection,triggerClassName,centrality,"SPDZvResVsMCz")->Fill(MCZv,SPDZv - MCZv);
+    
+    Double_t EtaReco(0.),EtaMC(0.),PhiReco(0.),PhiMC(0.);
+    Int_t i(-1),labelEtaReco(-1),labelEtaMC(-1),labelPhiReco(-1),labelPhiMC(-1);
+    
+    while ( i < nchList->GetEntries() - 1 )
+    {
+      i++;
+      while ( nchList->At(i)->IsA() != TObjString::Class() ) // In case there is a diferent object, just to skip it
+      {
+        i++;
+      }
+      
+      TParameter<Double_t>* p = static_cast<TParameter<Double_t>*>(nchList->At(i));
+
+      
+         //Eta Resolution
+      if ( TString(p->GetName()).Contains("EtaReco") ) // We take the reco eta
+      {
+        sscanf(p->GetName(),"EtaReco%d",&labelEtaReco);
+        EtaReco = p->GetVal();
+        MCHisto(eventSelection,triggerClassName,centrality,"Eta")->Fill(EtaReco);
+      }
+      else if ( TString(p->GetName()).Contains("EtaMC") ) // We take the generated eta
+      {
+        sscanf(p->GetName(),"EtaMC%d",&labelEtaMC);
+        EtaMC = p->GetVal();
+        MCHisto(eventSelection,triggerClassName,centrality,"MCEta")->Fill(EtaMC);
+      }
+      if ( labelEtaReco > 0 && labelEtaReco == labelEtaMC ) // To be sure we compute the difference for the same particle
+      {
+        labelEtaReco = -1; // Restart of the label value to avoid double count the eta difference when computing the phi one 
+        Double_t EtaDif = EtaReco - EtaMC;
+        MCHisto(eventSelection,triggerClassName,centrality,"EtaRes")->Fill(EtaDif);
+        MCHisto(eventSelection,triggerClassName,centrality,"EtaResVsZ")->Fill(MCZv,EtaDif);
+        MCHisto(eventSelection,triggerClassName,centrality,"EtaResVsnC")->Fill(nContributors,EtaDif);
+      }
+      
+         //Phi Resolution
+      else if ( TString(p->GetName()).Contains("PhiReco") ) // We take the reco phi
+      {
+        sscanf(p->GetName(),"PhiReco%d",&labelPhiReco);
+        PhiReco = p->GetVal();
+        MCHisto(eventSelection,triggerClassName,centrality,"Phi")->Fill(PhiReco);
+      }
+      else if ( TString(p->GetName()).Contains("PhiMC") ) // We take the generated phi
+      {
+        sscanf(p->GetName(),"PhiMC%d",&labelPhiMC);
+        PhiMC = p->GetVal();
+        MCHisto(eventSelection,triggerClassName,centrality,"MCPhi")->Fill(PhiMC);
+      }
+      
+      if ( labelPhiReco > 0 && labelPhiReco == labelPhiMC ) // To be sure we compute the difference for the same particle
+      {
+        labelPhiReco = -1; // Restart of the label value to avoid double count the phi difference when computing the eta one
+        Double_t PhiDif = PhiReco - PhiMC;
+        MCHisto(eventSelection,triggerClassName,centrality,"PhiRes")->Fill(PhiDif);
+        
+        //___With the following algorithm we refer the differences to the interval [-Pi/2,Pi/2]
+        if ( PhiDif < -TMath::PiOver2() && PhiDif > -TMath::Pi() )
+        {
+          PhiDif = -TMath::Pi() - PhiDif;
+        }
+        else if ( PhiDif < -TMath::Pi() )
+        {
+          PhiDif = -2.*TMath::Pi() - PhiDif;
+          if ( PhiDif < -TMath::PiOver2() )
+          {
+            PhiDif = -TMath::Pi() - PhiDif;
+          }
+        }
+        
+        else if ( PhiDif > TMath::PiOver2() && PhiDif < TMath::Pi() )
+        {
+          PhiDif = TMath::Pi() - PhiDif;
+        }  
+        else if ( PhiDif > TMath::Pi() )
+        {
+          PhiDif = 2.*TMath::Pi() - PhiDif;
+          if ( PhiDif > TMath::PiOver2() )
+          {
+            PhiDif = TMath::Pi() - PhiDif;
+          }
+        }
+        //___
+        
+        MCHisto(eventSelection,triggerClassName,centrality,"PhiResVsZ")->Fill(MCZv,PhiDif);
+        MCHisto(eventSelection,triggerClassName,centrality,"PhiResShifted")->Fill(PhiDif);
+        MCHisto(eventSelection,triggerClassName,centrality,"PhiResVsnC")->Fill(nContributors,PhiDif);
+      }
+    }
+    
+    return; // When computing resolutions we skip the rest of the method
+  }
+  //_____
+  
+  
+  //___Multiplicity histos (just when not computing resolutions)___
+  TH1* hSPDcorrectionVsEta = static_cast<TH1*>(nchList->FindObject("MCSPDcorrectionVsEta"));
+  TH1* hNBkgTrackletsVSEta = static_cast<TH1*>(nchList->FindObject("NBkgTrackletsVSEta"));
+  TH1* hNchVsPhi = static_cast<TH1*>(nchList->FindObject("MCNchVsPhi"));
+  TH1* hNchVsEta = static_cast<TH1*>(nchList->FindObject("MCNchVsEta"));
+  TH1* hNTrackletVsEta = static_cast<TH1*>(nchList->FindObject("MCNTrackletVsEta"));
+  TH1* hNTrackletVsPhi = static_cast<TH1*>(nchList->FindObject("MCNTrackletVsPhi"));
+  
+  TProfile* hMeanNchVsEta = static_cast<TProfile*>(MCHisto(eventSelection,triggerClassName,centrality,"MeanNchVsEta"));
+  
+  TH2* hEventsVsZVertexVsEta = static_cast<TH2*>(MCHisto(eventSelection,triggerClassName,centrality,"EventsVsZVertexVsEta"));
+  
+  Int_t nBins(0);
+  
+  Double_t nchSum(0.),nTracklets(0.);
+  for (Int_t j = 1 ; j <= fEtaAxis->GetNbins() ; j++) //Loop over eta bins
+  {
+    Double_t correction = hSPDcorrectionVsEta->GetBinContent(j);
+    
+    if ( correction < 0 ) continue; // We count just the particles in the SPD acceptance.
+    
+    nTracklets += hNTrackletVsEta->GetBinContent(j); // Reco tracklets
+    
+    ++nBins; // We sum up the number of bins entering in the computation
+    
+    Double_t eta = fEtaAxis->GetBinCenter(j);
+    Double_t nch = hNchVsEta->GetBinContent(j); // Generated particles
+    
+    nchSum += nch;
+    
+    hMeanNchVsEta->Fill(eta,nch); // Fill the number of charged particles of each eta bin in the profile
+    
+    hEventsVsZVertexVsEta->Fill(MCZv,eta,1.0); // Fill 1 count each eta bin where the events contributes
+  }
+  
+  MCHisto(eventSelection,triggerClassName,centrality,"Tracklets")->Fill(nTracklets);
+  
+  if ( vertex )
+  {
+    SPDZv = vertex->GetZ();
+  }
+
+  Bool_t isMChisto = kTRUE; // Used to get the MC histos in the Add method
+  
+  AddHisto(eventSelection,triggerClassName,centrality,"NBkgTrackletsVsZVertexVsEta",SPDZv,hNBkgTrackletsVSEta,isMChisto);
+  AddHisto(eventSelection,triggerClassName,centrality,"NchVsZVertexVsPhi",MCZv,hNchVsPhi,isMChisto);
+  AddHisto(eventSelection,triggerClassName,centrality,"NchVsZVertexVsEta",MCZv,hNchVsEta,isMChisto);
+  AddHisto(eventSelection,triggerClassName,centrality,"TrackletsVsZVertexVsEta",SPDZv,hNTrackletVsEta,isMChisto);
+  AddHisto(eventSelection,triggerClassName,centrality,"TrackletsVsZVertexVsPhi",SPDZv,hNTrackletVsPhi,isMChisto);
+  
+  MCHisto(eventSelection,triggerClassName,centrality,"MeanNchVsZVertex")->Fill(MCZv,nchSum);
+  MCHisto(eventSelection,triggerClassName,centrality,"Nch")->Fill(nchSum);
+  
+  
+  // Mean dNch/dEta computation
+  Double_t meandNchdEta(0.);
+  
+  if ( nBins >  0 )
+  {
+    meandNchdEta = nchSum / (nBins*fEtaAxis->GetBinWidth(5)); // Divide by nBins to get the mean and by the binWidht to get the d/dEta
+  }
+  
+  MCHisto(eventSelection,triggerClassName,centrality,"dNchdEta")->Fill(meandNchdEta);
+  
+  Double_t V0AMult = 0.;
+  Double_t V0CMult = 0.;
+  
+  AliVVZERO* vzero = Event()->GetVZEROData();
+  if (vzero)
+  {
+    Double_t multV0A = vzero->GetMTotV0A();
+    V0AMult = AliESDUtils::GetCorrV0A(multV0A,MCZv);
+    Double_t multV0C = vzero->GetMTotV0C();
+    V0CMult = AliESDUtils::GetCorrV0C(multV0C,MCZv);
+    
+    MCHisto(eventSelection,triggerClassName,centrality,"V0AMultVsNch")->Fill(V0AMult,nchSum);
+    MCHisto(eventSelection,triggerClassName,centrality,"V0CMultVsNch")->Fill(V0CMult,nchSum);
+    
+  }
+  //____
+}
+
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuNch::GetEtaRangeSPD(Double_t spdZVertex, Double_t etaRange[])
+{
+  // Returns the SPD eta range for a given z vertex.
+  
+  Double_t etaMax(fEtaMax),etaMin(fEtaMin);
+  
+  Double_t vf1LR = fSPD1LR->Eval(spdZVertex); //Eta values for the z vertex over the SPD acceptance curves
+  Double_t vf2LR = fSPD2LR->Eval(spdZVertex);
+  Double_t vf1LL = fSPD1LL->Eval(spdZVertex);
+  Double_t vf2LL = fSPD2LL->Eval(spdZVertex);
+  
+  //____We start by asigning the eta range as the eta values in the SPD acceptance curve
+  if ( spdZVertex < 0. )
+  {
+    etaMax = vf2LR;
+    etaMin = TMath::Max(vf1LL,vf2LL);
+  }
+  else
+  {
+    etaMax = TMath::Min(vf1LR,vf2LR);
+    etaMin = vf2LL;
+  }
+  //____
+  
+  
+  //____Algorithm to avoid taking bins which are crossed by the SPD acceptance curves
+  Int_t binYMin = fEtaAxis->FindBin(etaMin); // Find the corresponding bins for eta max & min and z vertex
+  Int_t binYMax = fEtaAxis->FindBin(etaMax);
+  Int_t binX = fZAxis->FindBin(spdZVertex);
+  
+  // Define the values for the relevant edges of the eta and z bins
+  Double_t upEdge = fEtaAxis->GetBinUpEdge(binYMax);  // up edge of the top eta bin
+  Double_t lowEdge = fEtaAxis->GetBinLowEdge(binYMin); // low edge of the bottom eta bin
+  Double_t leftEdge = fZAxis->GetBinLowEdge(binX); // left edge of the z bin
+  Double_t rightEdge = fZAxis->GetBinUpEdge(binX); // right edge of the z bin
+  
+  Double_t etaMaxTemp(0.),etaMinTemp(0.);
+  if ( spdZVertex < 0. )
+  {
+    etaMaxTemp = fSPD2LR->Eval(rightEdge); // Define the temporary eta max as the value of the curve int the righ edge of the bin
+    etaMinTemp = TMath::Max(fSPD1LL->Eval(leftEdge),fSPD2LL->Eval(leftEdge));
+  }
+  else
+  {
+    etaMaxTemp = TMath::Min(fSPD1LR->Eval(rightEdge),fSPD2LR->Eval(rightEdge));
+    etaMinTemp = fSPD2LL->Eval(leftEdge);
+  }
+  
+  while ( upEdge > etaMaxTemp ) //We take eta max as the up edge of the 1st bin which is inside the SPD acceptance but not crossed by the curve
+  {
+    binYMax = binYMax - 1; // Since the up edge of the current bin is bigger than the SPD acc curve we move 1 bin below
+    upEdge = fEtaAxis->GetBinUpEdge(binYMax); // Take the up edge of the new bin
+    etaMax = upEdge - 1E-6; // We substract 1E-6 cause the up edge of the a bin belongs to the bin+1
+    
+  }
+  
+  //We take eta min as the low edge of the 1st bin which is inside the SPD acceptance but not crossed by the curve
+  while ( lowEdge < etaMinTemp )
+  {
+    binYMin = binYMin + 1; // Since the low edge of the current bin is smaller than the SPD acc curve we move 1 bin above
+    lowEdge = fEtaAxis->GetBinLowEdge(binYMin); // Take the low edge of the new bin
+    etaMin = lowEdge + 1E-6;
+  }
+  //____
+  
+  // In case the eta range we want (given in the constructor) is smaller than the one found by the algorithm (max range) we redefine the values
+  if ( etaMin < fEtaMin ) etaMin = fEtaMin + 1E-6;
+  if ( etaMax > fEtaMax ) etaMax = fEtaMax - 1E-6;
+  
+  etaRange[0] = etaMin;
+  etaRange[1] = etaMax;
+}
+
+//_____________________________________________________________________________
+Double_t AliAnalysisMuMuNch::GetSPDCorrection(Double_t zvert, Double_t eta) const
+{
+  if (!fSPDCorrection)
+  {
+    AliFatal("ERROR: No SPD Correction");
+    return 0;
+  }
+  Int_t bin = fSPDCorrection->FindBin(zvert,eta);
+  return fSPDCorrection->GetBinContent(bin);
+}
+
+
+//==============================These methods are useless here, anyway they should go in the EventCutterClass=================
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuNch::HasAtLeastNTrackletsInEtaRange(const AliVEvent& event, Int_t n, Double_t& etaMin, Double_t& etaMax) const
+{
+  if ( event.IsA() != AliAODEvent::Class() )
+  {
+    return kFALSE;
+  }
+  
+  AliAODTracklets* tracklets = static_cast<const AliAODEvent&>(event).GetTracklets();
+  
+  if (!tracklets)
+  {
+    return kFALSE;
+  }
+  
+  Int_t nTrackletsInRange(0);
+  
+  Int_t nTracklets = tracklets->GetNumberOfTracklets();
+  
+  for (Int_t i = 0 ; i < nTracklets && nTrackletsInRange < n; i++)
+  {
+    Double_t eta = -TMath::Log(TMath::Tan(tracklets->GetTheta(i)/2.0));
+    
+    if ( eta > etaMin && eta < etaMax )
+    {
+      ++nTrackletsInRange;
+    }
+  }
+  
+  return (nTrackletsInRange>=n);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuNch::NameOfHasAtLeastNTrackletsInEtaRange(TString& name, Int_t n, Double_t& etaMin, Double_t& etaMax) const
+{
+  if ( TMath::AreEqualAbs(TMath::Abs(etaMin),TMath::Abs(etaMax),1E-9 ) )
+  {
+    name.Form("ATLEAST%dTRKLINABSETALT%3.1f",n,TMath::Abs(etaMin));
+  }
+  else
+  {
+    name.Form("ATLEAST%dTRKLINETA%3.1f-%3.1f",n,etaMin,etaMax);
+  }
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuNch::SetEvent(AliVEvent* event, AliMCEvent* mcEvent)
+{
+  /// Set the event, compute multiplicities and add them to the event
+
+  if ( event->IsA() != AliAODEvent::Class() )
+  {
+    AliError("Only working for AODs for the moment.");
+    return;
+  }
+  
+  AliAnalysisMuMuBase::SetEvent(event,mcEvent); // To have Event() and MCEvent() method working
+  
+  TList* nchList = static_cast<TList*>(event->FindListObject("NCH")); // Define the list with the NCH info for each event
+  if (!nchList)
+  {
+    nchList = new TList;
+    nchList->SetOwner(kTRUE);
+    nchList->SetName("NCH");
+    event->AddObject(nchList);
+  }
+  
+  const AliAODVertex* vertexSPD = static_cast<const AliAODEvent*>(Event())->GetPrimaryVertexSPD(); // SPD vertex object
+  AliAODTracklets* tracklets = static_cast<const AliAODEvent*>(Event())->GetTracklets(); // Tracklets object
+  
+  TH1* hSPDcorrectionVsEta(0x0); // Pointers for the individual event histos
+  TH1* hNchVsEta(0x0);
+  TH1* hNTrackletVsEta(0x0);
+  TH1* hNTrackletVsPhi(0x0);
+  
+  //_______Create once the histos with the individual event "properties" (cleared at the beginning of each new event)_______
+  if ( !fResolution ) // When computing resolutions we dont do anything else
+  {
+    if ( !Histo("AliAnalysisMuMuNch","SPDcorrectionVsEta") )
+    {
+      CreateEventHistos(kHistoForData | kHistoForMCInput,"AliAnalysisMuMuNch","SPDcorrectionVsEta","SPD correction-like vs #eta;#eta",fEtaAxis->GetNbins(),fEtaAxis->GetXmin(),fEtaAxis->GetXmax());
+      
+      CreateEventHistos(kHistoForMCInput,"AliAnalysisMuMuNch","NchVsEta","Nch vs #eta;#eta",fEtaAxis->GetNbins(),fEtaAxis->GetXmin(),fEtaAxis->GetXmax());
+
+      CreateEventHistos(kHistoForData | kHistoForMCInput,"AliAnalysisMuMuNch","NTrackletVsEta","Ntracklet vs #eta;#eta",fEtaAxis->GetNbins(),fEtaAxis->GetXmin(),fEtaAxis->GetXmax());
+      
+      CreateEventHistos(kHistoForData,"AliAnalysisMuMuNch","NBkgTrackletsVSEta","NBkg Tracklets vs #eta;#eta",fEtaAxis->GetNbins(),fEtaAxis->GetXmin(),fEtaAxis->GetXmax());
+      
+      Double_t phimin = 0.; //Phi range
+      Double_t phimax = 2*TMath::Pi();
+      Int_t nphibins = GetNbins(phimin,phimax,0.05);
+      
+      CreateEventHistos(kHistoForData | kHistoForMCInput,"AliAnalysisMuMuNch","NTrackletVsPhi","Ntracklet vs #phi;#phi",nphibins,phimin,phimax);
+      
+      CreateEventHistos(kHistoForMCInput,"AliAnalysisMuMuNch","NchVsPhi","Nch vs #phi;#phi",nphibins,phimin,phimax);
+      
+      CreateEventHistos(kHistoForData | kHistoForMCInput,"AliAnalysisMuMuNch","test","test",fZAxis->GetNbins(),fZAxis->GetXmin(),fZAxis->GetXmax(),fEtaAxis->GetNbins(),fEtaAxis->GetXmin(),fEtaAxis->GetXmax());
+      
+      Histo("AliAnalysisMuMuNch","test")->GetListOfFunctions()->Add(fSPD1LR);
+      Histo("AliAnalysisMuMuNch","test")->GetListOfFunctions()->Add(fSPD1LL);
+      Histo("AliAnalysisMuMuNch","test")->GetListOfFunctions()->Add(fSPD2LR);
+      Histo("AliAnalysisMuMuNch","test")->GetListOfFunctions()->Add(fSPD2LL);
+    }
+    //_________
+    
+    
+    hSPDcorrectionVsEta = Histo("AliAnalysisMuMuNch","SPDcorrectionVsEta"); // Set the individual event histos
+    hNTrackletVsEta = Histo("AliAnalysisMuMuNch","NTrackletVsEta");
+    hNTrackletVsPhi = Histo("AliAnalysisMuMuNch","NTrackletVsPhi");
+    
+    
+    hSPDcorrectionVsEta->Reset(); // Reset of the individual event histos
+    hNTrackletVsEta->Reset();
+    hNTrackletVsPhi->Reset();
+  }
+  
+  Double_t etaRange[2]; // Variables we will use in the multiplicity computation
+  Int_t binMin,binMax;
+  Int_t nTracklets(0);
+  Double_t thetaTracklet(0.),phiTracklet(0.),etaTracklet(0.);
+  Double_t nch(0.0);
+  Int_t nBins(0);
+  
+  
+  //____Data (or Reco if simu) multiplicity computation___
+  if ( fSPDCorrection && !fResolution ) // When computing resolutions we dont do anything else
+  {
+    if ( tracklets && vertexSPD )
+    {
+      Double_t SPDZv = vertexSPD->GetZ();
+
+      GetEtaRangeSPD(SPDZv,etaRange);
+      
+      Histo("AliAnalysisMuMuNch","test")->Fill(SPDZv,etaRange[1]);
+      Histo("AliAnalysisMuMuNch","test")->Fill(SPDZv,etaRange[0]);
+      
+      nTracklets = tracklets->GetNumberOfTracklets();
+      
+      Double_t SPDr;
+      for (Int_t i = 0 ; i < nTracklets ; i++)
+      {
+        thetaTracklet = tracklets->GetTheta(i);
+        etaTracklet = -TMath::Log(TMath::Tan(thetaTracklet/2.));
+        if ( etaTracklet < etaRange[0] || etaTracklet > etaRange[1] ) continue; // Avoid tracklets out of the eta SPD acceptance or out of the eta cut
+        
+        SPDr = GetSPDCorrection(SPDZv,etaTracklet);
+        
+        Int_t bin = fEtaAxis->FindBin(etaTracklet);
+        
+        if ( SPDr!=0. && SPDr <= 2.5) // Threshold to reduce border effects
+        {
+          hSPDcorrectionVsEta->SetBinContent(bin,SPDr);
+          hNTrackletVsEta->Fill(etaTracklet);
+          hNTrackletVsPhi->Fill(tracklets->GetPhi(i));
+        }
+        else // If the correction is above the threshold we store a -1 in the correction to skip this eta bin int the fill method
+        {
+          hSPDcorrectionVsEta->SetBinContent(bin,-1.0);
+        }
+      }
+      
+      //___ Fill the out-of-eta-range bins with -1.0
+      
+      binMin = fEtaAxis->FindBin(etaRange[0]);
+      binMax = fEtaAxis->FindBin(etaRange[1]);
+      
+      for ( Int_t i = 1; i < binMin; ++i )
+      {
+        hSPDcorrectionVsEta->SetBinContent(i,-1.0);
+      }
+      for ( Int_t i = binMax + 1 ; i <= fEtaAxis->GetNbins(); ++i )
+      {
+        hSPDcorrectionVsEta->SetBinContent(i,-1.0);
+      }
+      //____
+      nchList->Clear(); // We clear the NCH list for this new event
+      
+      if ( !IsHistogrammingDisabled() )
+      {
+        nchList->Add(hSPDcorrectionVsEta->Clone());
+        nchList->Add(hNTrackletVsEta->Clone());
+        nchList->Add(hNTrackletVsPhi->Clone());
+      }
+      
+          //----- Mean dNchdEta computation to set it into the event
+      for (Int_t j = 1 ; j <= fEtaAxis->GetNbins() ; j++) // Loop over eta bins
+      {
+        Double_t correction = hSPDcorrectionVsEta->GetBinContent(j);
+        
+        Double_t eta = fEtaAxis->GetBinCenter(j);
+        
+        if ( correction < 0 ) continue; // If the correction is < 0 we skip that eta bin 
+        else if ( correction == 0.0 ) // If the correction is 0 we have no tracklets in that eta bin
+        {
+          Double_t spdCorrection = GetSPDCorrection(SPDZv,eta);
+          if ( spdCorrection == 0. || spdCorrection > 2.5) continue; // If the correction in the eta bin is not within the threshold we do not count the "0"(that eta bin will not count for nBins)
+        }
+        
+        nch += hNTrackletVsEta->GetBinContent(j) * correction; // Number of charged particles (tracklets*SPDcorrection)
+        
+        ++nBins; // We sum up the number of bins entering in the computation
+      }
+      
+      Double_t meandNchdEta(0.); // We compute the mean dNch/dEta in the event
+      if ( nBins >  0 ) 
+      {
+        meandNchdEta = nch / (nBins*fEtaAxis->GetBinWidth(5));
+      }
+      
+      nchList->Add(new TParameter<Double_t>("MeandNchdEta",meandNchdEta)); // We add the mean dNch/dEta to the event. It will serve us as a multiplicity estimator.
+      //------
+      
+    }
+    
+    else  nchList->Clear(); //To clear the NCH list for MC in case the event has no reconstructed SPD vertex
+  }
+  //_______
+  
+  else nchList->Clear(); // To clear the NCH list for MC in case we have MC and no correction (SPD correction computation mode)
+
+  
+  //____Input MC multiplicity computation ___
+  if ( HasMC() )
+  {
+    if ( !fResolution ) //When computing resolutions we dont do anything else
+    {
+      Double_t MCZv = AliAnalysisMuonUtility::GetMCVertexZ(Event(),MCEvent());
+      GetEtaRangeSPD(MCZv,etaRange);
+      
+      hNchVsEta = MCHisto("AliAnalysisMuMuNch","NchVsEta");
+      hSPDcorrectionVsEta = MCHisto("AliAnalysisMuMuNch","SPDcorrectionVsEta");
+      TH1* hNchVsPhi = MCHisto("AliAnalysisMuMuNch","NchVsPhi");
+      hNTrackletVsEta = MCHisto("AliAnalysisMuMuNch","NTrackletVsEta");
+      hNTrackletVsPhi = MCHisto("AliAnalysisMuMuNch","NTrackletVsPhi");
+      
+      hNTrackletVsEta->Reset();
+      hNchVsEta->Reset();
+      hNchVsPhi->Reset();
+      hSPDcorrectionVsEta->Reset();
+      hNTrackletVsPhi->Reset();
+      
+      //___ Fill the out-of-eta-range bins with -1.0
+      binMin = fEtaAxis->FindBin(etaRange[0]);
+      binMax = fEtaAxis->FindBin(etaRange[1]);
+      
+      for ( Int_t i = 1; i < binMin; ++i )
+      {
+        hSPDcorrectionVsEta->SetBinContent(i,-1.0);
+      }
+      for ( Int_t i = binMax + 1 ; i <= fEtaAxis->GetNbins(); ++i )
+      {
+        hSPDcorrectionVsEta->SetBinContent(i,-1.0);
+      }
+      for ( Int_t i = binMin; i <= binMax; ++i ) // Fill the bins inside the eta range with +1
+      {
+        hSPDcorrectionVsEta->SetBinContent(i,1.0);
+      }
+      //___
+      
+      Int_t nMCTracks = MCEvent()->GetNumberOfTracks(); // MC number of MC tracks
+      
+      for ( Int_t i = 0; i < nMCTracks ; ++i ) //Loop over generated tracks
+      {
+        AliAODMCParticle* AODpart = static_cast<AliAODMCParticle*>(mcEvent->GetTrack(i));
+        
+        if ( AODpart->IsPhysicalPrimary() ) // We take only particles produced in the collision (Particles produced in the collision including products of strong and electromagnetic decay and excluding feed-down from weak decays of strange particles)
+        {
+          if ( AODpart->Charge()!=0 ) // We take only charged particles
+          {
+            hNchVsEta->Fill(AODpart->Eta());
+            hNchVsPhi->Fill(AODpart->Phi());
+            
+          }
+        }
+      }
+      
+      nchList->Add(hNchVsEta->Clone("MCNchVsEta"));
+      nchList->Add(hNchVsPhi->Clone("MCNchVsPhi"));
+      nchList->Add(hSPDcorrectionVsEta->Clone("MCSPDcorrectionVsEta"));
+    }
+              //__Bkg tracklets and Resolution estimation __
+    if ( tracklets ) // We can compute the Bkg tracklets and resolution only if we have the tracklets object in the event
+    {
+      TH1* hNBkgTrackletsVSEta(0x0); // Pointer for the Bkg histo
+      if ( !fResolution )
+      {
+        hNBkgTrackletsVSEta = Histo("AliAnalysisMuMuNch","NBkgTrackletsVSEta");
+        
+        hNBkgTrackletsVSEta->Reset();
+      }
+      
+      nTracklets = tracklets->GetNumberOfTracklets();
+      
+      for (Int_t i = 0 ; i < nTracklets ; i++) // Loop over tracklets to check if they come or not from the same MC particle
+      {
+        thetaTracklet = tracklets->GetTheta(i);
+        etaTracklet = -TMath::Log(TMath::Tan(thetaTracklet/2.));
+        phiTracklet = tracklets->GetPhi(i);
+        
+        
+        if ( !fResolution )
+        {
+          hNTrackletVsEta->Fill(etaTracklet);
+          hNTrackletVsPhi->Fill(phiTracklet);
+        }
+        
+        Int_t label1 = tracklets->GetLabel(i,0);
+        Int_t label2 = tracklets->GetLabel(i,1);  
+        
+        if (label1 != label2 ) // Tracklets not comming from the same MC particle are Bkg
+        {
+         if (!fResolution ) hNBkgTrackletsVSEta->Fill(etaTracklet);
+        }
+        else if ( !fSPDCorrection && fResolution ) // Compute the resolutions with the tracklets comming from the same MC particle
+        {
+          AliAODMCParticle* AODpartMC = static_cast<AliAODMCParticle*>(MCEvent()->GetTrack(label1));
+          Double_t etaTrackletMC = AODpartMC->Eta();
+          Double_t phiTrackletMC = AODpartMC->Phi();
+          
+          // Resolution variables
+          nchList->Add(new TParameter<Double_t>(Form("EtaReco%d",label1),etaTracklet));
+          nchList->Add(new TParameter<Double_t>(Form("EtaMC%d",label1),etaTrackletMC));
+          
+          nchList->Add(new TParameter<Double_t>(Form("PhiReco%d",label1),phiTracklet));
+          nchList->Add(new TParameter<Double_t>(Form("PhiMC%d",label1),phiTrackletMC));
+                 
+        }
+      }
+      
+      if (!fResolution )
+      {
+        nchList->Add(hNTrackletVsEta->Clone("MCNTrackletVsEta"));
+        nchList->Add(hNTrackletVsPhi->Clone("MCNTrackletVsPhi"));
+        nchList->Add(hNBkgTrackletsVSEta->Clone());
+      }
+      
+    }
+    
+  }
+  //_______
+  
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuNch::Terminate(Option_t *)
+{
+  /// Called once at the end of the query
+  if ( !HistogramCollection() ) return;
+
+  if ( HistogramCollection()->FindObject("/MCINPUT/AliAnalysisMuMuNch/NTrackletVsEta") )
+  {
+    HistogramCollection()->Remove("/MCINPUT/AliAnalysisMuMuNch/NTrackletVsEta");
+    HistogramCollection()->Remove("/MCINPUT/AliAnalysisMuMuNch/NTrackletVsPhi");
+    HistogramCollection()->Remove("/MCINPUT/AliAnalysisMuMuNch/NchVsEta");
+    HistogramCollection()->Remove("/MCINPUT/AliAnalysisMuMuNch/NchVsPhi");
+    HistogramCollection()->Remove("/MCINPUT/AliAnalysisMuMuNch/SPDcorrectionVsEta");
+    HistogramCollection()->Remove("/AliAnalysisMuMuNch/NBkgTrackletsVSEta");
+  }
+  
+  if ( HistogramCollection()->FindObject("/AliAnalysisMuMuNch/NTrackletVsEta") )
+  {
+    HistogramCollection()->Remove("/AliAnalysisMuMuNch/NTrackletVsEta");
+    HistogramCollection()->Remove("/AliAnalysisMuMuNch/test");
+    HistogramCollection()->Remove("/AliAnalysisMuMuNch/NTrackletVsPhi");
+    HistogramCollection()->Remove("/AliAnalysisMuMuNch/SPDcorrectionVsEta");
+  }
+  //____ Compute dNchdEta histo
+  TObjArray* idArr =  HistogramCollection()->SortAllIdentifiers();
+
+  TIter next(idArr);
+  TObjString* id;
+  
+  while ( (id = static_cast<TObjString*>(next())) )
+  {
+    TProfile* p = static_cast<TProfile*>(HistogramCollection()->FindObject(Form("%s%s",id->GetName(),"MeanNchVsEta")));
+
+    if ( !p ) continue;
+    
+    TH1* h = new TH1F("MeandNchdEta","Event averaged dN_{ch}/d#eta ;#eta;<dN_{ch}/d#eta>",fEtaAxis->GetNbins(),fEtaAxis->GetXmin(),fEtaAxis->GetXmax());
+
+    if ( p->GetNbinsX() != h->GetNbinsX() || p->GetXaxis()->GetXmin() != h->GetXaxis()->GetXmin() || p->GetXaxis()->GetXmax() != h->GetXaxis()->GetXmax() )
+    {
+      AliError("ERROR: Cannot compute MeandNchdEta since the binning doesn't match with MeanNchVsEta histo");
+      continue;
+    }
+    
+    for ( Int_t i = 1 ; i < h->GetNbinsX() ; i++ )
+    {
+      h->SetBinContent(i,p->GetBinContent(i)/p->GetBinWidth(i));
+      h->SetBinError(i,p->GetBinError(i)/p->GetBinWidth(i));
+      h->SetEntries(p->GetEntries());
+    }
+  
+    HistogramCollection()->Adopt(Form("%s",id->GetName()),h);
+  }
+    
+  delete idArr;
+  //___
+}
diff --git a/PWG/muon/AliAnalysisMuMuNch.h b/PWG/muon/AliAnalysisMuMuNch.h
new file mode 100644 (file)
index 0000000..429dc25
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef ALIANALYSISMUMUNCH_H
+#define ALIANALYSISMUMUNCH_H
+
+/**
+ *
+ * \class AliAnalysisMuMuNch
+ * \brief Charged particle multiplicity analysis (for plotting muon variables against it)
+ * \author L. Aphecetche and J. Martin-Bianco (Subatech)
+ */
+
+#include "AliAnalysisMuMuBase.h"
+
+class TH2F;
+class TH2;
+class AliVEvent;
+class TAxis;
+class TF1;
+class AliAODVertex;
+
+class AliAnalysisMuMuNch : public AliAnalysisMuMuBase
+{
+public:
+  
+  AliAnalysisMuMuNch(TH2* spdCorrection=0x0, Double_t etaMin=-0.5, Double_t etaMax=0.5
+                     , Double_t zmin=-40, Double_t zmax=40,Bool_t disableHistos=kFALSE,
+                     Bool_t computeResolution=kFALSE);
+  virtual ~AliAnalysisMuMuNch();
+  
+  Bool_t HasAtLeastNTrackletsInEtaRange(const AliVEvent& event, Int_t n,
+                                        Double_t& etaMin, Double_t& etaMax) const;
+
+  void NameOfHasAtLeastNTrackletsInEtaRange(TString& name, Int_t n,
+                                            Double_t& etaMin, Double_t& etaMax) const;
+  
+  virtual void SetEvent(AliVEvent* event, AliMCEvent* mcEvent=0x0);
+
+  virtual void Terminate(Option_t* /*opt*/="");
+
+protected:
+
+  void AddHisto(const char* eventSelection,
+                const char* triggerClassName,
+                const char* centrality,
+                const char* histoname,
+                Double_t z,
+                TH1* h,
+                Bool_t isMC=kFALSE);
+  
+  void AttachSPDAcceptance(UInt_t dataType,
+                           const char* eventSelection,
+                           const char* triggerClassName,
+                           const char* centrality,const char* histoname);
+
+
+  void FillHistosForMCEvent(const char* eventSelection, const char* triggerClassName,
+              const char* centrality);
+  
+
+  void FillHistosForEvent(const char* eventSelection, const char* triggerClassName,
+                          const char* centrality);
+  
+  virtual void DefineHistogramCollection(const char* eventSelection, const char* triggerClassName,
+                                         const char* centrality);
+
+  void DefineSPDAcceptance();
+  
+  void GetEtaRangeSPD(Double_t spdZVertex, Double_t etaRange[]);
+
+  Double_t GetSPDCorrection(Double_t zvert, Double_t eta) const;
+
+private:
+  TH2F* fSPDCorrection; // Nch/Tracklets_SPD (eta vs z)
+  TAxis* fEtaAxis; // Eta axis used for the histos
+  TAxis* fZAxis;  // Z vertex axis used for the histos
+  AliVEvent* fCurrentEvent; //! cache of the current event
+  Double_t fEtaMin; // Minimum tracklet eta value 
+  Double_t fEtaMax; // Maximum tracklet eta value 
+  Double_t fZMin; // Minimum z vertex value 
+  Double_t fZMax; // Maximum z vertex value 
+  Bool_t fResolution; // Flag to set the resolution computation
+  
+  TF1* fSPD1LR; // SPD acceptance shape
+  TF1* fSPD1LL; // SPD acceptance shape
+  TF1* fSPD2LR; // SPD acceptance shape
+  TF1* fSPD2LL; // SPD acceptance shape
+  
+  ClassDef(AliAnalysisMuMuNch,1) // implementation of AliAnalysisMuMuBase for Nch analysis
+};
+
+#endif
diff --git a/PWG/muon/AliAnalysisMuMuSingle.cxx b/PWG/muon/AliAnalysisMuMuSingle.cxx
new file mode 100644 (file)
index 0000000..5fdd212
--- /dev/null
@@ -0,0 +1,359 @@
+#include "AliAnalysisMuMuSingle.h"
+
+/**
+ *
+ * \ingroup pwg-muon-mumu
+ *
+ * \class AliAnalysisMuMuSingle
+ *
+ * Histogramming of single muon tracks. Mostly to get control plots for
+ * the AliAnalysisMuMuMinv sub-analysis, with respect to track cuts used, 
+ * like Rabs, p x DCA, etc...
+ *
+ */
+
+
+#include "TH2F.h"
+#include "AliMuonTrackCuts.h"
+#include "AliAnalysisMuonUtility.h"
+#include "TMath.h"
+#include "AliLog.h"
+#include "AliVParticle.h"
+#include "TLorentzVector.h"
+#include "AliAnalysisMuMuCutCombination.h"
+#include "AliAnalysisMuMuCutRegistry.h"
+#include "AliMergeableCollection.h"
+
+ClassImp(AliAnalysisMuMuSingle)
+
+//_____________________________________________________________________________
+AliAnalysisMuMuSingle::AliAnalysisMuMuSingle()
+: AliAnalysisMuMuBase(),
+fMuonTrackCuts(0x0),
+fShouldSeparatePlusAndMinus(kFALSE),
+fAccEffHisto(0x0)
+{
+  /// ctor
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuSingle::~AliAnalysisMuMuSingle()
+{
+  /// dtor
+  delete fMuonTrackCuts;
+  delete fAccEffHisto;
+}
+
+
+//_____________________________________________________________________________
+void
+AliAnalysisMuMuSingle::CreateTrackHisto(const char* eventSelection,
+                                        const char* triggerClassName,
+                                        const char* centrality,
+                                        const char* hname, const char* htitle,
+                                        Int_t nbinsx, Double_t xmin, Double_t xmax,
+                                        Int_t nbinsy, Double_t ymin, Double_t ymax,
+                                        Bool_t separatePlusAndMinus) const
+{
+  /// Append histograms for single track to our histogram collection
+  
+  if ( IsHistogramDisabled(hname) ) return;
+  
+  if ( separatePlusAndMinus )
+  {
+    const char* suffix[] = { "Plus", "Minus" };
+    const char* symbol[] = { "+", "-" };
+    
+    for ( Int_t i = 0; i < 2; ++i )
+    {
+      TString shtitle(htitle);
+      TString shname(hname);
+      
+      shtitle.ReplaceAll("#mu",Form("#mu^{%s}",symbol[i]));
+      
+      shname += suffix[i];
+      
+      CreateTrackHistos(eventSelection,triggerClassName,centrality,shname.Data(),shtitle.Data(),
+                        nbinsx,xmin,xmax,nbinsy,ymin,ymax);
+    }
+  }
+  else
+  {
+    CreateTrackHistos(eventSelection,triggerClassName,centrality,hname,htitle,
+                nbinsx,xmin,xmax,nbinsy,ymin,ymax);
+  }
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuSingle::IsRabsOK(const AliVParticle& part) const
+{
+  Double_t thetaAbsEndDeg = AliAnalysisMuonUtility::GetThetaAbsDeg(&part);
+  
+  return ( thetaAbsEndDeg > 2. && thetaAbsEndDeg < 10. );
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuSingle::IsEtaInRange(const AliVParticle& part, Double_t& etamin, Double_t& etamax) const
+{
+  return (part.Eta() >= etamin && part.Eta() <= etamax);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuSingle::SetRun(const AliInputEventHandler* eventHandler)
+{
+  MuonTrackCuts()->SetRun(eventHandler);
+}
+
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuSingle::EAGetNumberOfMuonTracks() const
+{
+  // Get the number of muon tracks *that are not ghosts*
+  
+  Int_t ntracks = AliAnalysisMuonUtility::GetNTracks(Event());
+  
+  for ( Int_t i = 0; i < ntracks; ++i )
+  {
+    AliVParticle* track = AliAnalysisMuonUtility::GetTrack(i,Event());
+    if (AliAnalysisMuonUtility::IsMuonGhost(track)) --ntracks;
+  }
+  
+  return ntracks;
+}
+
+////_____________________________________________________________________________
+//Int_t AliAnalysisMuMuSingle::EAGetNumberOfSelectMuonTracks() const
+//{
+//  // Get the number of "very good" muon tracks :
+//  // Rabs + DCA + pT > 1.5 Gev/C
+//  
+//  Int_t nTracks = AliAnalysisMuonUtility::GetNTracks(Event());
+//  
+//  UInt_t check = kAll | kMatched | kRabs | kDCA | kEta | kPt1dot5;
+//  
+//  Int_t nGood(0);
+//  
+//  for ( Int_t i = 0; i < nTracks; ++i )
+//  {
+//    ULong64_t m = GetTrackMask(i);
+//    if ( ( m & check ) == check )
+//    {
+//      ++nGood;
+//    }
+//  }
+//  return nGood;
+//}
+
+//_____________________________________________________________________________
+Double_t AliAnalysisMuMuSingle::EAGetTrackDCA(const AliVParticle& track) const
+{
+  // Get track DCA
+  
+  Double_t xdca = AliAnalysisMuonUtility::GetXatDCA(&track);
+  Double_t ydca = AliAnalysisMuonUtility::GetYatDCA(&track);
+  
+  return TMath::Sqrt(xdca*xdca+ydca*ydca);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuSingle::DefineHistogramCollection(const char* eventSelection,
+                                                      const char* triggerClassName,
+                                                      const char* centrality)
+{
+  /// Actually create the histograms for phyics/triggerClassName
+  if ( Histo(eventSelection,triggerClassName,centrality,"AliAnalysisMuMuSingle") )
+  {
+    return;
+  }
+
+  AliAnalysisMuMuBase::EDataType dt = AliAnalysisMuMuBase::kHistoForData;
+  
+  // dummy histogram to signal that we already defined all our histograms (see above)
+  CreateEventHistos(dt,eventSelection,triggerClassName,centrality,"AliAnalysisMuMuSingle","Dummy semaphore",1,0,1);
+  
+  Double_t ptMin = 0;
+  Double_t ptMax = 12*3;
+  Int_t nbinsPt = GetNbins(ptMin,ptMax,0.5);
+  Double_t pMin = 0;
+  Double_t pMax = 100*3;
+  Int_t nbinsP = GetNbins(pMin,pMax,2.0);
+  Double_t etaMin = -5;
+  Double_t etaMax = -2;
+  Int_t nbinsEta = GetNbins(etaMin,etaMax,0.05);
+  
+  Double_t rapidityMin = -5;
+  Double_t rapidityMax = -2;
+  Int_t nbinsRapidity = GetNbins(rapidityMin,rapidityMax,0.05);
+  
+  Double_t phiMin = -TMath::Pi();
+  Double_t phiMax = TMath::Pi();
+  Int_t nbinsPhi = GetNbins(phiMin,phiMax,0.05);
+  
+  CreateTrackHisto(eventSelection,triggerClassName,centrality,"Chi2MatchTrigger","Chi2 Match Trigger",72,0,72);
+  
+  CreateTrackHisto(eventSelection,triggerClassName,centrality,"EtaRapidityMu", "Eta distribution vs Rapidity for #mu", nbinsRapidity,rapidityMin,rapidityMax,nbinsEta,etaMin,etaMax, fShouldSeparatePlusAndMinus);
+  
+  CreateTrackHisto(eventSelection,triggerClassName,centrality,"PtEtaMu", "P_{T} distribution vs Eta for #mu", nbinsEta,etaMin,etaMax, nbinsPt,ptMin,ptMax,fShouldSeparatePlusAndMinus);
+  
+  CreateTrackHisto(eventSelection,triggerClassName,centrality,"PtRapidityMu", "P_{T} distribution vs Rapidity for #mu", nbinsRapidity,rapidityMin,rapidityMax, nbinsPt,ptMin,ptMax,fShouldSeparatePlusAndMinus);
+  
+  CreateTrackHisto(eventSelection,triggerClassName,centrality,"PtPhiMu", "P_{T} distribution vs phi for #mu", nbinsPhi,phiMin,phiMax, nbinsPt,ptMin,ptMax,fShouldSeparatePlusAndMinus);
+  
+  
+  CreateTrackHisto(eventSelection,triggerClassName,centrality,"PEtaMu", "P distribution for #mu",nbinsEta,etaMin,etaMax,nbinsP,pMin,pMax,fShouldSeparatePlusAndMinus);
+  
+  Double_t chi2min = 0;
+  Double_t chi2max = 20;
+  Int_t nbinchi2 = GetNbins(chi2min,chi2max,0.05);
+  
+  CreateTrackHisto(eventSelection, triggerClassName, centrality, "Chi2Mu", "chisquare per NDF #mu", nbinchi2, chi2min, chi2max,-1, 0.0, 0.0, fShouldSeparatePlusAndMinus);
+  
+  Double_t xmin = 0;
+  Double_t xmax = 150;
+  Int_t nbins = GetNbins(xmin,xmax,2.0);
+  
+  CreateTrackHisto(eventSelection,triggerClassName,centrality,"dcaP23Mu","#mu DCA vs P for 2-3 degrees;P (GeV);DCA (cm)",nbinsP,pMin,pMax,nbins,xmin,xmax,fShouldSeparatePlusAndMinus);
+  
+  CreateTrackHisto(eventSelection,triggerClassName,centrality,"dcaP310Mu","#mu DCA vs P for 3-10 degrees;P (GeV);DCA (cm)",nbinsP,pMin,pMax,nbins,xmin,xmax,fShouldSeparatePlusAndMinus);
+  
+  CreateTrackHisto(eventSelection,triggerClassName,centrality,"dcaPwPtCut23Mu","#mu DCA vs P for 2-3 degrees with Pt Cut;P (GeV);DCA (cm)",nbinsP,pMin,pMax,nbins,xmin,xmax,fShouldSeparatePlusAndMinus);
+  
+  CreateTrackHisto(eventSelection,triggerClassName,centrality,"dcaPwPtCut310Mu","#mu DCA vs P for 3-10 degrees with Pt Cut;P (GeV);DCA (cm)",nbinsP,pMin,pMax,nbins,xmin,xmax,fShouldSeparatePlusAndMinus);
+  
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuSingle::FillHistosForTrack(const char* eventSelection,
+                                               const char* triggerClassName,
+                                               const char* centrality,
+                                               const char* trackCutName,
+                                               const AliVParticle& track)
+{
+  /// Fill histograms for one track
+  
+  if (!AliAnalysisMuonUtility::IsMuonTrack(&track) ) return;
+  
+  if ( HasMC() )
+  {
+    MuonTrackCuts()->SetIsMC();
+  }
+  
+  TLorentzVector p(track.Px(),track.Py(),track.Pz(),
+                   TMath::Sqrt(AliAnalysisMuonUtility::MuonMass2()+track.P()*track.P()));
+  
+  
+  TString charge("");
+  
+  if ( ShouldSeparatePlusAndMinus() )
+  {
+    if ( track.Charge() < 0 )
+    {
+      charge = "Minus";
+    }
+    else
+    {
+      charge = "Plus";
+    }
+  }
+  
+  Double_t dca = EAGetTrackDCA(track);
+  
+  Double_t theta = AliAnalysisMuonUtility::GetThetaAbsDeg(&track);
+  
+  if (!IsHistogramDisabled("Chi2MatchTrigger"))
+  {
+    Histo(eventSelection,triggerClassName,centrality,trackCutName,"Chi2MatchTrigger")->Fill(AliAnalysisMuonUtility::GetChi2MatchTrigger(&track));
+  }
+  
+  if (!IsHistogramDisabled("EtaRapidityMu*"))
+  {
+    Histo(eventSelection,triggerClassName,centrality,trackCutName,Form("EtaRapidityMu%s",charge.Data()))->Fill(p.Rapidity(),p.Eta());
+  }
+  
+  if (!IsHistogramDisabled("PtEtaMu*"))
+  {
+    Histo(eventSelection,triggerClassName,centrality,trackCutName,Form("PtEtaMu%s",charge.Data()))->Fill(p.Eta(),p.Pt());
+  }
+  
+  if (!IsHistogramDisabled("PtRapidityMu*"))
+  {
+    Histo(eventSelection,triggerClassName,centrality,trackCutName,Form("PtRapidityMu%s",charge.Data()))->Fill(p.Rapidity(),p.Pt());
+  }
+  
+  if (!IsHistogramDisabled("PEtaMu*"))
+  {
+    Histo(eventSelection,triggerClassName,centrality,trackCutName,Form("PEtaMu%s",charge.Data()))->Fill(p.Eta(),p.P());
+  }
+  
+  if (!IsHistogramDisabled("PtPhiMu*"))
+  {
+    Histo(eventSelection,triggerClassName,centrality,trackCutName,Form("PtPhiMu%s",charge.Data()))->Fill(p.Phi(),p.Pt());
+  }
+  
+  if (!IsHistogramDisabled("Chi2Mu*"))
+  {
+    Histo(eventSelection,triggerClassName,centrality,trackCutName,Form("Chi2Mu%s",charge.Data()))->Fill(AliAnalysisMuonUtility::GetChi2perNDFtracker(&track));
+  }
+  
+  if ( theta >= 2.0 && theta < 3.0 )
+  {
+    
+    if (!IsHistogramDisabled("dcaP23Mu*"))
+    {
+      Histo(eventSelection,triggerClassName,centrality,trackCutName,Form("dcaP23Mu%s",charge.Data()))->Fill(p.P(),dca);
+    }
+    
+    if ( p.Pt() > 2 )
+    {
+      if (!IsHistogramDisabled("dcaPwPtCut23Mu*"))
+      {
+        Histo(eventSelection,triggerClassName,centrality,trackCutName,Form("dcaPwPtCut23Mu%s",charge.Data()))->Fill(p.P(),dca);
+      }
+    }
+  }
+  else if ( theta >= 3.0 && theta < 10.0 )
+  {
+    if (!IsHistogramDisabled("dcaP310Mu*"))
+    {
+      Histo(eventSelection,triggerClassName,centrality,trackCutName,Form("dcaP310Mu%s",charge.Data()))->Fill(p.P(),dca);
+    }
+    if ( p.Pt() > 2 )
+    {
+      if (!IsHistogramDisabled("dcaPwPtCut310Mu*"))
+      {
+        Histo(eventSelection,triggerClassName,centrality,trackCutName,Form("dcaPwPtCut310Mu%s",charge.Data()))->Fill(p.P(),dca);
+      }
+    }
+  }
+}
+
+//_____________________________________________________________________________
+AliMuonTrackCuts* AliAnalysisMuMuSingle::MuonTrackCuts()
+{
+  /// Get (and create the first time) our internal track cuts
+  if (!fMuonTrackCuts)
+  {
+    fMuonTrackCuts = new AliMuonTrackCuts;
+    
+    fMuonTrackCuts->SetAllowDefaultParams(kTRUE);
+    
+    fMuonTrackCuts->SetFilterMask(AliMuonTrackCuts::kMuEta |
+                                  AliMuonTrackCuts::kMuThetaAbs |
+                                  AliMuonTrackCuts::kMuPdca |
+                                  AliMuonTrackCuts::kMuMatchApt |
+                                  AliMuonTrackCuts::kMuMatchLpt |
+                                  AliMuonTrackCuts::kMuMatchHpt |
+                                  AliMuonTrackCuts::kMuTrackChiSquare);
+    
+  }
+  
+  return fMuonTrackCuts;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuSingle::SetMuonTrackCuts(const AliMuonTrackCuts& trackCuts)
+{
+  /// Set our muontrackcuts from external source
+  delete fMuonTrackCuts;
+  fMuonTrackCuts = static_cast<AliMuonTrackCuts*>(trackCuts.Clone());
+}
diff --git a/PWG/muon/AliAnalysisMuMuSingle.h b/PWG/muon/AliAnalysisMuMuSingle.h
new file mode 100644 (file)
index 0000000..a8b7988
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef ALIANALYSISMUMUSINGLE_H
+#define ALIANALYSISMUMUSINGLE_H
+
+/**
+ *
+ * \class AliAnalysisMuMuSingle
+ * 
+ * \brief Histogramming of single muon tracks.
+ *
+ * \author L. Aphecetche (Subatech)
+ *
+ */
+
+#include "AliAnalysisMuMuBase.h"
+
+class AliMuonTrackCuts;
+class TH2F;
+class TObjArray;
+
+class AliAnalysisMuMuSingle : public AliAnalysisMuMuBase
+{
+public:
+  
+  AliAnalysisMuMuSingle();
+  virtual ~AliAnalysisMuMuSingle();
+  
+  virtual void ShouldSeparatePlusAndMinus(Bool_t value) { fShouldSeparatePlusAndMinus = value; }
+  
+  virtual Bool_t ShouldSeparatePlusAndMinus() const { return fShouldSeparatePlusAndMinus; }
+
+  AliMuonTrackCuts* MuonTrackCuts();
+  
+  void SetMuonTrackCuts(const AliMuonTrackCuts& trackCuts);
+  
+  Bool_t IsRabsOK(const AliVParticle& part) const;
+  void NameOfIsRabsOK(TString& name) const { name = "RABS"; }
+
+  Bool_t IsEtaInRange(const AliVParticle& part, Double_t& etamin, Double_t& etamax) const;
+  void NameOfIsEtaInRange(TString& name, Double_t& etamin, Double_t& etamax) const
+  { name.Form("ETA%3.1f-%3.1f",etamin,etamax); }
+
+  void SetRun(const AliInputEventHandler* eventHandler);
+
+protected:
+  
+  void DefineHistogramCollection(const char* eventSelection, const char* triggerClassName,
+                                 const char* centrality);
+
+  virtual void FillHistosForTrack(const char* eventSelection, const char* triggerClassName,
+                                  const char* centrality,
+                                  const char* trackCutName,
+                                  const AliVParticle& part);
+
+private:
+  
+  void CreateTrackHisto(const char* eventSelection,
+                        const char* triggerClassName,
+                        const char* centrality,
+                        const char* hname, const char* htitle,
+                        Int_t nbinsx, Double_t xmin, Double_t xmax,
+                        Int_t nbinsy=-1, Double_t ymin=0.0, Double_t ymax=0.0,
+                        Bool_t separatePlusAndMinus=kFALSE) const;
+
+  Double_t GetTrackTheta(const AliVParticle& particle) const;
+  
+  /* methods prefixed with EA should really not exist at all. They are there
+   only because the some of our base interfaces are shamelessly incomplete or
+   inadequate...
+   */
+  
+  Int_t EAGetNumberOfMuonTracks() const;
+  
+//  Int_t EAGetNumberOfSelectMuonTracks() const;
+  
+  Double_t EAGetTrackDCA(const AliVParticle& particle) const;
+     
+private:
+  AliMuonTrackCuts* fMuonTrackCuts; //! common cuts for muon tracks (from Diego)
+  Bool_t fShouldSeparatePlusAndMinus; // whether or not to histogram mu+ and mu- separately
+  TH2F* fAccEffHisto; // dimuon acc x eff (y vs pt)
+  
+  ClassDef(AliAnalysisMuMuSingle,1) // implementation of AliAnalysisMuMuBase for single mu analysis
+};
+
+#endif
index 3fdf1e6d19fe6a24432a4a9491c44e43c4db9d61..8689795a73bf38e9126591c1404b1b52ba29647d 100644 (file)
 #include "TFile.h"
 
 // STEER includes
-#include "AliInputEventHandler.h"
-#include "AliAODHeader.h"
 #include "AliAODEvent.h"
-#include "AliAODTrack.h"
+#include "AliAODHeader.h"
 #include "AliAODMCHeader.h"
 #include "AliAODMCParticle.h"
-#include "AliMCEvent.h"
-#include "AliMCParticle.h"
+#include "AliAODTrack.h"
+#include "AliAODTZERO.h"
 #include "AliESDEvent.h"
 #include "AliESDMuonTrack.h"
-#include "AliVVertex.h"
+#include "AliESDTZERO.h"
+#include "AliInputEventHandler.h"
 #include "AliLog.h"
+#include "AliMCEvent.h"
+#include "AliMCParticle.h"
+#include "AliVVertex.h"
 #include "AliStack.h"
 
 // CORRFW includes
@@ -548,6 +550,43 @@ TString AliAnalysisMuonUtility::GetTrackHistory ( const AliVParticle* track, con
   return trackHistory;
 }
 
+//________________________________________________________________________
+Bool_t AliAnalysisMuonUtility::EAGetTZEROFlags(const AliVEvent* event, Bool_t& backgroundFlag, Bool_t& pileupFlag, Bool_t& satelliteFlag)
+{
+  // get the TZERO decisions
+  // return false if there's no tzero information in this event
+  
+  Bool_t rv(kFALSE);
+  
+  if ( event->IsA() == AliESDEvent::Class() )
+  {
+    const AliESDTZERO* tzero = static_cast<AliESDEvent*>(const_cast<AliVEvent*>(event))->GetESDTZERO();
+    if ( tzero )
+    {
+      backgroundFlag = tzero->GetBackgroundFlag();
+      pileupFlag = tzero->GetPileupFlag();
+      satelliteFlag = tzero->GetSatellite();
+      rv = kTRUE;
+    }
+  }
+  else if ( event->IsA() == AliAODEvent::Class() )
+  {
+    AliAODTZERO* tzero = static_cast<const AliAODEvent*>(event)->GetTZEROData();
+    if ( tzero )
+    {
+      backgroundFlag = tzero->GetBackgroundFlag();
+      pileupFlag = tzero->GetPileupFlag();
+      satelliteFlag = tzero->GetSatellite();
+      rv = kTRUE;
+    }
+  }
+  else
+  {
+    AliErrorClass(Form("Unknown class for the event = %s",event->ClassName()));
+  }
+  
+  return rv;
+}
 
 //_______________________________________________________________________
 Bool_t AliAnalysisMuonUtility::SetSparseRange(AliCFGridSparse* gridSparse,
index 7c35271b02c576e030ec1c4639fd41ea786cc096..9f9661fdba3f39aa1a524ca2e1093c6383617e07 100644 (file)
@@ -73,6 +73,8 @@ class AliAnalysisMuonUtility : public TObject {
   static UInt_t GetMCProcess ( const AliVParticle* mcParticle );
   static UInt_t GetStatusCode ( const AliVParticle* mcParticle );
   
+  static Bool_t EAGetTZEROFlags(const AliVEvent* event, Bool_t& backgroundFlag, Bool_t& pileupFlag, Bool_t& satelliteFlag);
+
   // A useful constant
   static Double_t MuonMass2();
   
index 622f853fd3c4496a102a6822bac0aa280127e090..ee6bb24f69505c04376c107a91ddf41a2ce5a32a 100644 (file)
@@ -3,6 +3,7 @@
 #include "AliAnalysisManager.h"
 #include "AliAnalysisMuMuBinning.h"
 #include "AliAnalysisMuonUtility.h"
+#include "AliAnalysisUtils.h"
 #include "AliAODEvent.h"
 #include "AliAODMCParticle.h"
 #include "AliAODTrack.h"
@@ -11,7 +12,6 @@
 #include "AliCodeTimer.h"
 #include "AliCounterCollection.h"
 #include "AliESDEvent.h"
-#include "AliESDMuonTrack.h"
 #include "AliESDTZERO.h"
 #include "AliInputEventHandler.h"
 #include "AliLog.h" 
 #include "TMath.h"
 #include "TObjString.h"
 #include "TPaveText.h"
+#include "TProfile.h"
 #include "TRegexp.h"
 #include "TROOT.h"
 #include <algorithm>
 #include <cassert>
-
-//
-// AliAnalysisTaskMuMu : base class for mu pairs analysis 
-//
-// Mainly invariant mass (for J/psi and Upsilon) but also 
-// some single control histograms.
-//
-// This base class contains common things for ESD-based
-// and AOD-based analysis
-//
-// The output contains an AliHistogramCollection and
-// an AliCounterCollection
-//
-// author: L. Aphecetche (Subatech)
-//
+#include "AliAnalysisMuMuBase.h"
+#include "AliInputEventHandler.h"
+#include "AliAnalysisMuMuCutRegistry.h"
+#include "AliAnalysisMuMuCutElement.h"
+#include "AliAnalysisMuMuCutCombination.h"
+#include <set>
+
+/**
+ * \class AliAnalysisTaskMuMu
+ * 
+ * This class steers the work of one or more sub-analysis deriving from AliAnalysisMuMuBase
+ * The output contains an AliHistogramCollection, an AliCounterCollection 
+ * and an AliAnalysisMuMuBinning
+ * This task must be configured a bit before being used. For instance
+ * you can select various event cuts, single muon track cuts and
+ *  muon pairs cut, as well as defining various bins (for minv and mean pt
+ * histograms) in pt,y,phi etc...
+ *
+ * Note that it's also possible to disable some (or all) histograms
+ * (to save speed/memory), using DisableHistograms() method.
+ *
+ * For an example of such configuration, \see AddTaskMuMu.C
+ */
 
 using std::cout;
 using std::endl;
 
 ClassImp(AliAnalysisTaskMuMu)
-ClassImp(AliAnalysisTaskMuMu::PairCut)
-
-namespace
-{
-  Int_t GetNbins(Double_t xmin, Double_t xmax, Double_t xstep)
-  {
-    if ( TMath::AreEqualRel(xstep,0.0,1E-9) ) return 1;
-    
-    return TMath::Nint(TMath::Abs((xmax-xmin)/xstep));
-  }
-  
-  TObjArray* GetMuonTriggerList()
-  {
-    TObjArray* a = new TObjArray;
-    a->SetOwner(kTRUE);
-    
-    a->Add(new TObjString("CMUL"));
-    a->Add(new TObjString("CMLL"));
-    a->Add(new TObjString("C0MUL"));
-    a->Add(new TObjString("CMSL"));
-    a->Add(new TObjString("CMSH"));
-    
-    return a;
-  }
-
-  TObjArray* GetEmcalTriggerList()
-  {
-    TObjArray* a = new TObjArray;
-    a->SetOwner(kTRUE);
-    
-    a->Add(new TObjString("CEMC"));
-    
-    return a;
-  }
-
-  TObjArray* GetMBTriggerList()
-  {
-    TObjArray* a = new TObjArray;
-    a->SetOwner(kTRUE);
-    
-    a->Add(new TObjString("CINT7-S-"));
-    a->Add(new TObjString("CINT7-B-"));
-    a->Add(new TObjString("CINT8-S-"));
-    
-    return a;
-  }
-  
-  TString GetMinvHistoName(const AliAnalysisMuMuBinning::Range& r)
-  {
-    return TString::Format("MinvUS%s",r.AsString().Data());
-  }
-
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::PairCut::Print(Option_t* /*opt*/) const
-{
-  std::cout << Form("PAIR   CUT %20s SINGLE MASK %x PAIR MASK %x",GetName(),MaskForOneOrBothTrack(),MaskForTrackPair())
-  << std::endl;
-}
-
-//_____________________________________________________________________________
-AliAnalysisTaskMuMu::AliAnalysisTaskMuMu() : AliAnalysisTaskSE("AliAnalysisTaskMuMu"),
-fHistogramCollection(0),
-fEventCounters(0),
-fMuonTrackCuts(0x0),
-fPrecomputedTrackMasks(),
-fIsFromESD(kFALSE),
-fShouldSeparatePlusAndMinus(kFALSE),
-fBeamYear("pp"),
-fSingleTrackCutNames(0x0),
-fPairTrackCutNames(0x0),
-fCentralityNames(0x0),
-fEventCutNames(0x0),
-fUseBackgroundTriggers(kFALSE),
-fTriggerInputBitMap(),
-fBinning(0x0),
-fHistogramToDisable(0x0),
-fBinArray(0x0),
-fHasMC(kFALSE),
-fEventCuts(0x0)
-{
-  /// default ctor
-}
-
-//_____________________________________________________________________________
-AliAnalysisTaskMuMu::AliAnalysisTaskMuMu(Bool_t fromESD, const char* beamYear, TArrayF* centralities)
-: AliAnalysisTaskSE(Form("AliAnalysisTaskMuMu-from%s",fromESD ? "ESD":"AOD")),
-fHistogramCollection(0),
-fEventCounters(0),
-fMuonTrackCuts(0x0),
-fPrecomputedTrackMasks(),
-fIsFromESD(fromESD),
-fShouldSeparatePlusAndMinus(kFALSE),
-fBeamYear(beamYear),
-fSingleTrackCutNames(0x0),
-fPairTrackCutNames(0x0),
-fCentralityNames(new TObjArray),
-fEventCutNames(0x0),
-fUseBackgroundTriggers(kFALSE),
-fTriggerInputBitMap(),
-fBinning(0x0),
-fHistogramToDisable(0x0),
-fBinArray(0x0),
-fHasMC(kFALSE),
-fEventCuts(0x0)
-{
-  /// Constructor
-  /// The list of triggers to be considered will be updated on the fly
-  
-  DefineOutput(1,AliMergeableCollection::Class());
-  DefineOutput(2,AliCounterCollection::Class());
-  DefineOutput(3,AliAnalysisMuMuBinning::Class());
-  
-  DefineDefaultBinning();
-
-  DefineCentralityClasses(centralities);
-}
 
 //_____________________________________________________________________________
-AliAnalysisTaskMuMu::AliAnalysisTaskMuMu(Bool_t fromESD, TList* triggerClasses, const char* beamYear, TArrayF* centralities)
-: AliAnalysisTaskSE(Form("AliAnalysisTaskMuMu-from%s",fromESD ? "ESD":"AOD")),
+AliAnalysisTaskMuMu::AliAnalysisTaskMuMu()
+: AliAnalysisTaskSE("AliAnalysisTaskMuMu"),
 fHistogramCollection(0),
 fEventCounters(0),
-fMuonTrackCuts(0x0),
-fPrecomputedTrackMasks(),
-fIsFromESD(fromESD),
-fShouldSeparatePlusAndMinus(kFALSE),
-fBeamYear(beamYear),
-fSingleTrackCutNames(0x0),
-fPairTrackCutNames(0x0),
-fCentralityNames(new TObjArray),
-fEventCutNames(0x0),
-fUseBackgroundTriggers(kFALSE),
-fTriggerInputBitMap(),
 fBinning(0x0),
+fCutRegistry(0x0),
+fBeamYear(""),
 fHistogramToDisable(0x0),
-fBinArray(0x0),
-fHasMC(kFALSE),
-fEventCuts(0x0)
+fSubAnalysisVector(0x0)
 {
   /// Constructor with a predefined list of triggers to consider
+  /// Note that we take ownership of cutRegister
+  ///
+  
+//  fBranchNames = "AOD:header,tracks,vertices,tracklets,AliAODTZERO,AliAODVZERO";
 
   DefineOutput(1,AliMergeableCollection::Class());
   DefineOutput(2,AliCounterCollection::Class());
   DefineOutput(3,AliAnalysisMuMuBinning::Class());
-  
-  TObjString* tname;
-  TIter next(triggerClasses);
-  TString tclasses;
-  
-  while ( ( tname = static_cast<TObjString*>(next()) ) )
-  {
-    if (tclasses.Length()>0)
-    {
-      tclasses += ",";
-    }
-    
-    tclasses += tname->String();    
-  }
-
-  EventCuts()->SetTrigClassPatterns(tclasses);
-  
-  DefineDefaultBinning();
-  
-  DefineCentralityClasses(centralities);
 }
 
 //_____________________________________________________________________________
@@ -243,368 +107,36 @@ AliAnalysisTaskMuMu::~AliAnalysisTaskMuMu()
     delete fBinning;
   }
 
-  delete fMuonTrackCuts;
-
-  delete fSingleTrackCutNames;
-  delete fPairTrackCutNames;
-  delete fCentralityNames;
-  delete fEventCutNames;
   delete fHistogramToDisable;
-  delete fBinArray;
-  delete fEventCuts;
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::AddBin(const char* particle, const char* type,
-                                 Double_t xmin, Double_t xmax,
-                                 Double_t ymin, Double_t ymax,
-                                 const char* flavour)
-{
-  /// Add one bin
-  fBinning->AddBin(particle,type,xmin,xmax,ymin,ymax,flavour);
-
-  // invalidate cached bins, if any
-  if (fBinArray)
-  {
-    delete fBinArray;
-    fBinArray = 0x0;
-  }
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::AddPairCut(const char* cutName, UInt_t maskForOneOrBothTrack, UInt_t maskForTrackPair)
-{
-  /// Add a cut for a pair.
-  /// maskForOneOrBothTrack is the mask of cuts that at least one track must satisfy
-  /// maskForTrackPair is the mask of cuts that *both* tracks must satisfy.
-  /// if maskForTrackPair is 0, then no (extra) condition is applied to the pair
-  
-  if ( !fPairTrackCutNames ) 
-  {
-    fPairTrackCutNames = new TObjArray;
-    fPairTrackCutNames->SetOwner(kTRUE);
-  }
-  fPairTrackCutNames->Add(new AliAnalysisTaskMuMu::PairCut(cutName,maskForOneOrBothTrack,maskForTrackPair));
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::AddSingleCut(const char* name, UInt_t mask)
-{
-  /// Add a cut for single tracks
-  if ( !fSingleTrackCutNames ) 
-  {
-    fSingleTrackCutNames = new TObjArray;
-    fSingleTrackCutNames->SetOwner(kTRUE);
-  }
-  TObjString* oname = new TObjString(Form("s%s",name));
-  oname->SetUniqueID(mask);
-  fSingleTrackCutNames->Add(oname);
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::AddEventCut(const char* name, UInt_t mask)
-{
-  /// Add a cut at event level
-  if ( !fEventCutNames )
-  {
-    fEventCutNames = new TObjArray;
-    fEventCutNames->SetOwner(kTRUE);
-  }
-  TObjString* oname = new TObjString(Form("%s",name));
-  oname->SetUniqueID(mask);
-  fEventCutNames->Add(oname);
-}
-
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::AssertHistogramCollection(const char* physics, const char* triggerClassName)
-{
-  // insure that a given set of histogram is created
-  if (!fHistogramCollection->Histo(Form("/%s/%s/%s/Zvertex",physics,triggerClassName,DefaultCentralityName())))
-  {
-    FillHistogramCollection(physics,triggerClassName);
-  }
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::BeautifyHistos()
-{
-  /// Put the titles, marker sizes, color, etc...
-  
-  TIter next(fHistogramCollection->CreateIterator());
-  TH1* h;
-  
-  while ( ( h = static_cast<TH1*>(next()) ) )
-  {
-    TString name(h->GetName());
-    
-    if ( name.Contains("Plus") ) 
-    {
-      h->SetMarkerStyle(kFullCircle);
-      h->SetMarkerColor(kBlue);
-      h->SetLineColor(kBlue);        
-    }
-    else if ( name.Contains("Minus") )
-    {
-      h->SetMarkerStyle(kOpenCircle);
-      h->SetMarkerColor(kRed);
-      h->SetLineColor(kRed);        
-    }      
-  }
-}
-
-//_____________________________________________________________________________
-const char* 
-AliAnalysisTaskMuMu::CentralityName(Double_t centrality) const
-{
-  /// Get centrality name corresponding to the floating ^point value
-  
-  if ( centrality > 0 && centrality <= 100.0 ) 
-  {
-    return Form("CENT%02d",TMath::Nint(centrality));
-  }
-  else
-  {
-    return DefaultCentralityName();
-  }
-}
-
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::ComputeTrackMask(const AliVParticle& track, Int_t trackIndex)
-{
-  // Compute the track mask
-  UInt_t m(kAll);
   
-  UInt_t selectionMask = MuonTrackCuts()->GetSelectionMask(&track);
+  delete fCutRegistry;
   
-  if ( ( selectionMask & AliMuonTrackCuts::kMuThetaAbs ) == AliMuonTrackCuts::kMuThetaAbs ) m |= kRabs;
-  
-  Double_t angle = AliAnalysisMuonUtility::GetThetaAbsDeg(&track);
-  
-  if ( angle >= 2.0 && angle < 3.0 ) m |= kDeg23;
-  
-  if ( angle >= 3.0 && angle < 10.0 ) m |= kDeg310;
-  
-  if ( selectionMask & AliMuonTrackCuts::kMuEta ) m |= kEta;
-  
-  Double_t pt = track.Pt();
-  
-  if ( pt >  1.0 ) m |= kPt1;
-  if ( pt >  1.2 ) m |= kPt1dot2;
-  if ( pt >  1.5 ) m |= kPt1dot5;
-  if ( pt >  2.0 ) m |= kPt2;
-  
-  if ( track.P() > 10.0 ) m |= kP10;
-  
-  if ( pt < 4.0 ) m |= kBelowPt;
-  
-  if ( ( selectionMask & AliMuonTrackCuts::kMuMatchApt ) == AliMuonTrackCuts::kMuMatchApt ) m |= kMatched;
-  
-  if ( ( selectionMask & AliMuonTrackCuts::kMuMatchLpt ) == AliMuonTrackCuts::kMuMatchLpt ) m |= kMatchedLow;
-  
-  if ( ( selectionMask & AliMuonTrackCuts::kMuMatchHpt ) == AliMuonTrackCuts::kMuMatchHpt) m |= kMatchedHigh;
-  
-  if ( ( selectionMask & AliMuonTrackCuts::kMuTrackChiSquare ) ==  AliMuonTrackCuts::kMuTrackChiSquare ) m |= kChi2;
-  
-  if ( ( selectionMask & AliMuonTrackCuts::kMuPdca ) == AliMuonTrackCuts::kMuPdca ) m |= kDCA;
-  
-  if ( AliAnalysisMuonUtility::GetChi2MatchTrigger(&track) < 16.0 ) m |= kChi2MatchTrigger;
-  
-  fPrecomputedTrackMasks.SetAt(m,trackIndex);
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::CreateMesh(const char* particle, const char* type1, const char* type2, const char* flavour, Bool_t remove12)
-{
-  /// Create a 2d binning from 2 1d binning.
-  /// WARNING : not fully tested yet
-  
-  if (!fBinning)
-  {
-    AliError("Cannot create a mesh as I have no bin at all !");
-    return;
-  }
-  fBinning->CreateMesh(particle,type1,type2,flavour,remove12);
+  delete fSubAnalysisVector;
 }
 
 //_____________________________________________________________________________
-void
-AliAnalysisTaskMuMu::CreateMinvHistograms(const char* physics,
-                                          const char* triggerClassName)
+void AliAnalysisTaskMuMu::AdoptSubAnalysis(AliAnalysisMuMuBase* analysis)
 {
-  /// Create invariant mass histograms
-  
-  Double_t minvMin = 0;
-  Double_t minvMax = 16;
-  Int_t nMinvBins = GetNbins(minvMin,minvMax,0.025);
-
-  Int_t nMCMinvBins = GetNbins(minvMin,minvMax,0.1);
-
-  TObjArray* bins = fBinning->CreateBinObjArray("psi","y vs pt,integrated,pt,y,phi","");
-  
-  CreatePairHisto(physics,triggerClassName,"Pt","#mu+#mu- Pt distribution",
-                  200,0,20);
-
-//  CreatePairHisto(physics,triggerClassName,"BinFlowPt","#mu+#mu- BinFlowPt distribution",
-//                  200,0,20);
-
-  CreatePairHisto(physics,triggerClassName,"PtRecVsSim","#mu+#mu- Pt distribution rec vs sim",
-                  200,0,20,200,0,20);
-
-  TIter next(bins);
-  AliAnalysisMuMuBinning::Range* r;
-  while ( ( r = static_cast<AliAnalysisMuMuBinning::Range*>(next()) ) )
-  {
-    TString hname(GetMinvHistoName(*r));    
-    
-    if ( IsHistogramDisabled(hname.Data()) ) continue;
-    
-    AliDebug(1,Form("histoname = %s",hname.Data()));
-    
-    CreatePairHisto(physics,triggerClassName,hname.Data(),
-                    Form("#mu+#mu- inv. mass %s",r->AsString().Data()),
-                    nMinvBins,minvMin,minvMax);
-
-    TH1* h = fHistogramCollection->Histo("/INPUT/ALL",hname.Data());
-    if (!h)
-    {
-      h = new TH1F(hname.Data(),Form("MC #mu+#mu- inv. mass %s",r->AsString().Data()),
-                   nMCMinvBins,minvMin,minvMax);
-
-      fHistogramCollection->Adopt("/INPUT/ALL",h);
-
-      fHistogramCollection->Adopt("/INPUT/INYRANGE",static_cast<TH1*>(h->Clone()));
-    }
-  }
-  
-  
-  delete bins;
-}
-
-//_____________________________________________________________________________
-void 
-AliAnalysisTaskMuMu::CreateSingleHisto(const char* physics,
-                                       const char* triggerClassName,
-                                       const char* hname, const char* htitle,
-                                       Int_t nbinsx, Double_t xmin, Double_t xmax,
-                                       Int_t nbinsy, Double_t ymin, Double_t ymax,
-                                       Bool_t separatePlusAndMinus) const
-{  
-  /// Append histograms for single track to our histogram collection
-  
-  if ( IsHistogramDisabled(hname) ) return;
-  
-  if ( separatePlusAndMinus ) 
+  if (!fSubAnalysisVector)
   {
-    const char* suffix[] = { "Plus", "Minus" };
-    const char* symbol[] = { "+", "-" };
-
-    for ( Int_t i = 0; i < 2; ++i )
-    {
-      TString shtitle(htitle);
-      TString shname(hname);
-      
-      shtitle.ReplaceAll("#mu",Form("#mu^{%s}",symbol[i]));
-      
-      shname += suffix[i];
-      
-      CreateHisto(fSingleTrackCutNames,physics,triggerClassName,shname.Data(),shtitle.Data(),
-                  nbinsx,xmin,xmax,nbinsy,ymin,ymax);
-    }
+    fSubAnalysisVector = new TObjArray;
+    fSubAnalysisVector->SetOwner(kTRUE);
   }
-  else 
+  if ( !fSubAnalysisVector->FindObject(analysis) )
   {
-    CreateHisto(fSingleTrackCutNames,physics,triggerClassName,hname,htitle,
-                nbinsx,xmin,xmax,nbinsy,ymin,ymax);
+    fSubAnalysisVector->Add(analysis);
   }
 }
 
 //_____________________________________________________________________________
-void 
-AliAnalysisTaskMuMu::CreatePairHisto(const char* physics,
-                                     const char* triggerClassName,
-                                     const char* hname, const char* htitle,
-                                     Int_t nbinsx, Double_t xmin, Double_t xmax,
-                                     Int_t nbinsy, Double_t ymin, Double_t ymax) const
-{
-  /// Append histograms for track pairs to our histogram collection
-
-  if ( IsHistogramDisabled(hname) ) return;
-
-  CreateHisto(fPairTrackCutNames,physics,triggerClassName,hname,htitle,
-              nbinsx,xmin,xmax,nbinsy,ymin,ymax);
-}
-
-//_____________________________________________________________________________
-void 
-AliAnalysisTaskMuMu::CreateEventHisto(const char* physics,
-                                      const char* triggerClassName,
-                                      const char* hname, const char* htitle,
-                                      Int_t nbinsx, Double_t xmin, Double_t xmax,
-                                      Int_t nbinsy, Double_t ymin, Double_t ymax) const
+AliAnalysisMuMuCutRegistry* AliAnalysisTaskMuMu::CutRegistry() const
 {
-  /// Append histograms at the event level
-  
-  if ( IsHistogramDisabled(hname) ) return;
-
-  TIter next(fCentralityNames);
-  TObjString* cent;
-  
-  while ( ( cent = static_cast<TObjString*>(next()) ) )
+    /// Return (and create if not yet there) our cut registry
+  if (!fCutRegistry)
   {
-    TH1* h(0x0);
-    
-    if ( nbinsy > 0 )
-    {  
-      h = new TH2F(hname,htitle,nbinsx,xmin,xmax,nbinsy,ymin,ymax);
-    }
-    else
-    {
-      h = new TH1F(hname,htitle,nbinsx,xmin,xmax);
-    }
-    
-    fHistogramCollection->Adopt(Form("/%s/%s/%s/",physics,triggerClassName,cent->String().Data()),h);
+    fCutRegistry = new AliAnalysisMuMuCutRegistry;
   }
-}
-
-//_____________________________________________________________________________
-void 
-AliAnalysisTaskMuMu::CreateHisto(TObjArray* array,
-                                 const char* physics,
-                                 const char* triggerClassName,
-                                 const char* hname, const char* htitle,
-                                 Int_t nbinsx, Double_t xmin, Double_t xmax,
-                                 Int_t nbinsy, Double_t ymin, Double_t ymax) const
-{
-  /// Create a bunch of histograms for all centralities
-  /// FIXME: have a way to specify the histo precision (i.e. F vs I vs S ...)
-  
-  if ( IsHistogramDisabled(hname) ) return;
-
-  TIter next(array);
-  TObjString* tcn;
-  while ( ( tcn = static_cast<TObjString*>(next()) ) )
-  {
-    TIter nextCent(fCentralityNames);
-    TObjString* cent;
-    
-    while ( ( cent = static_cast<TObjString*>(nextCent()) ) )
-    {
-      TH1* h(0x0);
-    
-      if ( nbinsy > 0 )
-      {  
-        h = new TH2F(hname,htitle,nbinsx,xmin,xmax,nbinsy,ymin,ymax);
-      }
-      else
-      {
-        h = new TH1F(hname,htitle,nbinsx,xmin,xmax);
-      }
-    
-      fHistogramCollection->Adopt(Form("/%s/%s/%s/%s",physics,triggerClassName,cent->String().Data(),tcn->String().Data()),h);
-    }
-  }      
+  return fCutRegistry;
 }
 
 //_____________________________________________________________________________
@@ -616,1302 +148,216 @@ AliAnalysisTaskMuMu::DefaultCentralityName() const
   else return "PP";
 }
 
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::DefineCentralityClasses(TArrayF* centralities)
-{
-  /// Define the default centrality classes that will be used.
-  
-  if ( !fBeamYear.Contains("pp") ) 
-  {
-    if ( !centralities ) 
-    {
-//      // default values
-//      fCentralityLimits.push_back(10.0);
-//      fCentralityLimits.push_back(30.0);
-//      fCentralityLimits.push_back(50.0);
-//      fCentralityLimits.push_back(80.0);
-    }
-    else
-    {
-      for ( Int_t i = 0; i < centralities->GetSize(); ++i ) 
-      {
-//        fCentralityLimits.push_back(centralities->At(i));
-      }
-    }
-  }
-  
-//  for ( std::vector<double>::size_type i = 0; i < fCentralityLimits.size(); ++i )
-//  {
-//    Double_t limit = fCentralityLimits[i];
-//    fCentralityNames->Add(new TObjString(CentralityName(limit)));
-//  }
-  
-  fCentralityNames->Add(new TObjString(DefaultCentralityName()));
-  fCentralityNames->SetOwner(kTRUE);
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::DefineDefaultBinning()
-{
-  fBinning = new AliAnalysisMuMuBinning("BIN");
-  fBinning->AddBin("psi","integrated");
-}
-
 //_____________________________________________________________________________
 void AliAnalysisTaskMuMu::DisableHistograms(const char* pattern)
 {
   /// Disable the histogramming of all the histograms matching the pattern
   
-  TString spattern(pattern);
-  if (spattern=="*")
-  {
-    delete fHistogramToDisable;
-    fHistogramToDisable = 0x0;
-  }
-  
-  if (!fHistogramToDisable)
-  {
-    fHistogramToDisable = new TList;
-    fHistogramToDisable->SetOwner(kTRUE);
-  }
-    
-  fHistogramToDisable->Add(new TObjString(spattern));
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::EAComputeTrackMasks()
-{
-  // compute the track masks for the event
-  
-  fPrecomputedTrackMasks.Reset();
-  Int_t n = AliAnalysisMuonUtility::GetNTracks(Event()); //EAGetNumberOfMuonTracks();
-  fPrecomputedTrackMasks.Set(n);
+  TIter next(fSubAnalysisVector);
+  AliAnalysisMuMuBase* a;
   
-  for ( Int_t i = 0; i < n; ++i )
+  while ( ( a = static_cast<AliAnalysisMuMuBase*>(next()) ) )
   {
-    AliVParticle* track = AliAnalysisMuonUtility::GetTrack(i,Event());
-    ComputeTrackMask(*track,i);
+    a->DisableHistograms(pattern);
   }
 }
 
 //_____________________________________________________________________________
-Int_t AliAnalysisTaskMuMu::EAGetNumberOfMuonTracks() const
+AliVEvent*
+AliAnalysisTaskMuMu::Event() const
 {
-  // Get the number of muon tracks *that are not ghosts*
-  
-  Int_t ntracks = AliAnalysisMuonUtility::GetNTracks(Event());
-  
-  for ( Int_t i = 0; i < ntracks; ++i )
-  {
-    AliVParticle* track = AliAnalysisMuonUtility::GetTrack(i,Event());
-    if (AliAnalysisMuonUtility::IsMuonGhost(track)) --ntracks;
-  }
-  
-  return ntracks;
+  // some const-dirty-dancing
+  return const_cast<AliAnalysisTaskMuMu*>(this)->InputEvent();
 }
 
 //_____________________________________________________________________________
-Int_t AliAnalysisTaskMuMu::EAGetNumberOfSelectMuonTracks() const
-{
-  // Get the number of "very good" muon tracks :
-  // Rabs + DCA + pT > 1.5 Gev/C
-  // must be called after EAComputeTrackMasks
-  
-  Int_t nTracks = AliAnalysisMuonUtility::GetNTracks(Event());
-
-  UInt_t check = kAll | kMatched | kRabs | kDCA | kEta | kPt1dot5;
-  
-  Int_t nGood(0);
-  
-  for ( Int_t i = 0; i < nTracks; ++i )
-  {
-    UInt_t m = GetTrackMask(i);
-    if ( ( m & check ) == check )
-    {
-      ++nGood;
-    }
-  }  
-  return nGood;
-}
-
-//_____________________________________________________________________________
-Double_t AliAnalysisTaskMuMu::EAGetTrackDCA(const AliVParticle& track) const
-{
-  // Get track DCA
-  
-  Double_t xdca = AliAnalysisMuonUtility::GetXatDCA(&track);
-  Double_t ydca = AliAnalysisMuonUtility::GetYatDCA(&track);
-  
-  return TMath::Sqrt(xdca*xdca+ydca*ydca);
-}
-
-//_____________________________________________________________________________
-Bool_t AliAnalysisTaskMuMu::EAGetTZEROFlags(Bool_t& backgroundFlag, Bool_t& pileupFlag, Bool_t& satelliteFlag) const
-{
-  // get the TZERO decisions
-  // return false if there's no tzero information in this event
-  
-  Bool_t rv(kFALSE);
-  
-  if ( Event()->IsA() == AliESDEvent::Class() )
-  {
-    const AliESDTZERO* tzero = static_cast<AliESDEvent*>(const_cast<AliVEvent*>(Event()))->GetESDTZERO();
-    if ( tzero )
-    {
-      backgroundFlag = tzero->GetBackgroundFlag();
-      pileupFlag = tzero->GetPileupFlag();
-      satelliteFlag = tzero->GetSatellite();
-      rv = kTRUE;
-    }    
-  }
-  else if ( Event()->IsA() == AliAODEvent::Class() )
-  {
-    AliAODTZERO* tzero = static_cast<const AliAODEvent*>(Event())->GetTZEROData();
-    if ( tzero )
-    {
-      backgroundFlag = tzero->GetBackgroundFlag();
-      pileupFlag = tzero->GetPileupFlag();
-      satelliteFlag = tzero->GetSatellite();
-      rv = kTRUE;
-    }
-  }
-  else
-  {
-    AliError(Form("Unknown class for the event = %s",Event()->ClassName()));
-  }  
-  
-  return rv;
-
-}
-
-//_____________________________________________________________________________
-AliVEvent*
-AliAnalysisTaskMuMu::Event() const
-{
-  // some const-dirty-dancing
-  return const_cast<AliAnalysisTaskMuMu*>(this)->InputEvent();
-}
-
-//_____________________________________________________________________________
-AliMuonEventCuts*
-AliAnalysisTaskMuMu::EventCuts() const
-{
-  /// Return the single instance of AliMuonEventCuts object we're using
-  
-  if (!fEventCuts)
-  {
-    fEventCuts = new AliMuonEventCuts("EventCut","");
-  }
-  return fEventCuts;
-}
-
-//_____________________________________________________________________________
-Bool_t
-AliAnalysisTaskMuMu::AtLeastOneMBTrigger(const TString& firedTriggerClasses) const
-{
-  // whether or not we have a least one MB trigger in the fired trigger classes
-  static TObjArray* triggerList = GetMBTriggerList();
-  TIter next(triggerList);
-  TObjString* str;
-  
-  while ( ( str = static_cast<TObjString*>(next())))
-  {
-    if ( firedTriggerClasses.Contains(str->String().Data())) return kTRUE;
-  }
-  
-  return kFALSE;
-}
-
-//_____________________________________________________________________________
-Bool_t
-AliAnalysisTaskMuMu::AtLeastOneMuonTrigger(const TString& firedTriggerClasses) const
-{
-  // whether or not we have a least one muon trigger in the fired trigger classes
-  static TObjArray* triggerList = GetMuonTriggerList();
-  TIter next(triggerList);
-  TObjString* str;
-  
-  while ( ( str = static_cast<TObjString*>(next())))
-  {
-    if ( firedTriggerClasses.Contains(str->String().Data())) return kTRUE;
-  }
-  
-  return kFALSE;
-}
-
-//_____________________________________________________________________________
-Bool_t
-AliAnalysisTaskMuMu::AtLeastOneEmcalTrigger(const TString& firedTriggerClasses) const
-{
-  // whether or not we have a least one emcal trigger in the fired trigger classes
-  static TObjArray* triggerList = GetEmcalTriggerList();
-  TIter next(triggerList);
-  TObjString* str;
-  
-  while ( ( str = static_cast<TObjString*>(next())))
-  {
-    if ( firedTriggerClasses.Contains(str->String().Data())) return kTRUE;
-  }
-  
-  return kFALSE;
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::FillMC()
-{
-  // Fill the input MC histograms
-  
-  if (!HasMC()) return;
-
-  // Specific things for MC
-  if (!Histo("INPUT","ALL","Pt"))
-  {
-    fHistogramCollection->Adopt("/INPUT/ALL",new TH1F("Pt","Pt",200,0,20));
-    fHistogramCollection->Adopt("/INPUT/INYRANGE",new TH1F("Pt","Pt",200,0,20));
-    
-    Double_t rapidityMin = -5;
-    Double_t rapidityMax = -2;
-    Int_t nbinsRapidity = GetNbins(rapidityMin,rapidityMax,0.05);
-    
-    fHistogramCollection->Adopt("/INPUT/ALL",new TH1F("Y","Y",nbinsRapidity,rapidityMin,rapidityMax));
-    fHistogramCollection->Adopt("/INPUT/INYRANGE",new TH1F("Y","Y",nbinsRapidity,rapidityMin,rapidityMax));
-    
-    Double_t etaMin = -5;
-    Double_t etaMax = -2;
-    Int_t nbinsEta = GetNbins(etaMin,etaMax,0.05);
-    
-    fHistogramCollection->Adopt("/INPUT/ALL",new TH1F("Eta","Eta",nbinsEta,etaMin,etaMax));
-    fHistogramCollection->Adopt("/INPUT/INYRANGE",new TH1F("Eta","Eta",nbinsEta,etaMin,etaMax));
-  }
-
-  Int_t nMCTracks = MCEvent()->GetNumberOfTracks();
-
-  if (!fBinArray)
-  {
-    fBinArray = fBinning->CreateBinObjArray("psi","y vs pt,integrated,pt,y","");
-  }
-
-  TIter nextBin(fBinArray);
-  AliAnalysisMuMuBinning::Range* r;
-  
-  for ( Int_t i = 0; i < nMCTracks; ++i )
-  {
-    AliVParticle* part = MCEvent()->GetTrack(i);
-    
-//    std::cout << "part " << i << " isprimary=" << AliAnalysisMuonUtility::IsPrimary(part,MCEvent()) << " motherindex=" << AliAnalysisMuonUtility::GetMotherIndex(part) << std::endl;
-//    
-//    part->Print();
-    
-    if  (AliAnalysisMuonUtility::IsPrimary(part,MCEvent()) &&
-         AliAnalysisMuonUtility::GetMotherIndex(part)==-1)
-    {
-      
-      Histo("INPUT","ALL","Pt")->Fill(part->Pt());
-      Histo("INPUT","ALL","Y")->Fill(part->Y());
-      Histo("INPUT","ALL","Eta")->Fill(part->Eta());
-      
-      if ( part->Y() < -2.5 && part->Y() > -4.0 )
-      {
-        Histo("INPUT","INYRANGE","Pt")->Fill(part->Pt());
-        Histo("INPUT","INYRANGE","Y")->Fill(part->Y());
-        Histo("INPUT","INYRANGE","Eta")->Fill(part->Eta());
-      }
-      
-      nextBin.Reset();
-      
-      while ( ( r = static_cast<AliAnalysisMuMuBinning::Range*>(nextBin()) ) )
-      {
-        Bool_t ok(kFALSE);
-        
-        if ( r->IsNullObject() )
-        {
-          ok = kTRUE;
-        }
-        else if ( r->Is2D() )
-        {
-          if ( r->AsString().BeginsWith("PTVSY") )
-          {
-            ok = r->IsInRange(part->Y(),part->Pt());
-          }
-          else if ( r->AsString().BeginsWith("YVSPT") )
-          {
-            ok = r->IsInRange(part->Pt(),part->Y());
-          }
-          else
-          {
-            AliError(Form("Don't know how to deal with 2D bin %s",r->AsString().Data()));
-          }
-        }
-        else
-        {
-          if ( r->Type() == "PT" )
-          {
-            ok = r->IsInRange(part->Pt());
-          }
-          else if ( r->Type() == "Y" )
-          {
-            ok = r->IsInRange(part->Y());
-          }
-          else if ( r->Type() == "PHI" )
-          {
-            ok = r->IsInRange(part->Phi());
-          }
-        }
-        
-        if ( ok )
-        {
-          TString hname = GetMinvHistoName(*r);
-          
-          if (!IsHistogramDisabled(hname.Data()))
-          {
-            TH1* h = Histo("INPUT","ALL",hname.Data());
-            
-            if (!h)
-            {
-              AliError(Form("Could not get ALL %s",hname.Data()));
-              continue;
-            }
-            
-            h->Fill(part->M());
-            
-            if ( part->Y() < -2.5 && part->Y() > -4.0 )
-            {
-              h = Histo("INPUT","INYRANGE",hname.Data());
-              if (!h)
-              {
-                AliError(Form("Could not get INYRANGE %s",hname.Data()));
-                continue;
-              }
-              h->Fill(part->M());
-            }
-            
-          }
-
-        }
-      }
-    }
-  }
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::Fill(const char* eventtype,
-                           TObjString* tname,
-                           const char* centrality,
-                           float fcent)
-{
-  // Fill one set of histograms
-  
-  TString seventtype(eventtype);
-  seventtype.ToLower();
-  
-  fEventCounters->Count(Form("event:%s/trigger:%s/run:%d", seventtype.Data(), tname->GetName(), fCurrentRunNumber));
-
-  if ( !IsHistogrammingDisabled() )
-  {
-    AssertHistogramCollection(eventtype,tname->String().Data());
-    FillHistos(eventtype,tname->String().Data(),centrality);
-    if (!IsHistogramDisabled("Centrality"))
-    {
-      fHistogramCollection->Histo(Form("/%s/%s/Centrality",eventtype,tname->String().Data()))->Fill(fcent);
-    }
-  }
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::FillEventHistos(const char* physics, const char* triggerClassName,
-                                          const char* centrality)
-{
-  // Fill event-wise histograms
-  
-//  AliCodeTimerAuto("",0);
-  
-  if (!IsHistogramDisabled("BCX"))
-  {
-    Histo(physics,triggerClassName,centrality,"BCX")->Fill(1.0*Event()->GetBunchCrossNumber());
-  }
-  
-  if (!IsHistogramDisabled("Nevents"))
-  {
-    Histo(physics,triggerClassName,centrality,"Nevents")->Fill(1.0);
-  }
-  
-  const AliVVertex* vertex = Event()->GetPrimaryVertex();
-  
-  if ( vertex )
-  {
-    if (!IsHistogramDisabled("Xvertex"))
-    {
-      Histo(physics,triggerClassName,centrality,"Xvertex")->Fill(vertex->GetX());
-    }
-    if (!IsHistogramDisabled("Yvertex"))
-    {
-      Histo(physics,triggerClassName,centrality,"Yvertex")->Fill(vertex->GetY());
-    }
-    if (!IsHistogramDisabled("Zvertex"))
-    {
-      Histo(physics,triggerClassName,centrality,"Zvertex")->Fill(vertex->GetZ());
-    }
-  }
-  
-  if ( !fIsFromESD )
-  {
-    const AliAODTZERO* tzero = static_cast<const AliAODEvent*>(Event())->GetTZEROData();
-    
-    if (tzero && !IsHistogramDisabled("T0Zvertex"))
-    {
-      Histo(physics,triggerClassName,centrality,"T0Zvertex")->Fill(tzero->GetT0VertexRaw());
-    }
-  }
-  else
-  {
-    const AliESDTZERO* tzero = static_cast<const AliESDEvent*>(Event())->GetESDTZERO();
-    
-    if (tzero && !IsHistogramDisabled("T0Zvertex"))
-    {
-      Histo(physics,triggerClassName,centrality,"T0Zvertex")->Fill(tzero->GetT0zVertex());
-    }
-  }
-  
-  AliVVZERO* vzero = Event()->GetVZEROData();
-  
-  if (vzero)
-  {
-    Float_t v0a = vzero->GetV0ATime();
-    Float_t v0c = vzero->GetV0CTime();
-    
-    Float_t x = v0a-v0c;
-    Float_t y = v0a+v0c;
-    
-    if (!IsHistogramDisabled("V02D"))
-    {
-      Histo(physics,triggerClassName,centrality,"V02D")->Fill(x,y);
-    }
-    
-    Bool_t background,pileup,satellite;
-    
-    Bool_t tzero = EAGetTZEROFlags(background,pileup,satellite);
-    
-    if (tzero)
-    {
-      if ( background )
-      {
-        if (!IsHistogramDisabled("V02DwT0BG"))
-        {
-          Histo(physics,triggerClassName,centrality,"V02DwT0BG")->Fill(x,y);
-        }
-      }
-      
-      if ( pileup )
-      {
-        if (!IsHistogramDisabled("V02DwT0PU"))
-        {
-          Histo(physics,triggerClassName,centrality,"V02DwT0PU")->Fill(x,y);
-        }
-      }
-      
-      if ( satellite )
-      {
-        if (!IsHistogramDisabled("V02DwT0SAT"))
-        {
-          Histo(physics,triggerClassName,centrality,"V02DwT0SAT")->Fill(x,y);
-        }
-      }
-      
-      if ( !background && !pileup && !satellite )
-      {
-        if (!IsHistogramDisabled("V02DwT0BB"))
-        {
-          Histo(physics,triggerClassName,centrality,"V02DwT0BB")->Fill(x,y);
-        }
-      }
-    }
-  }
-  
-  /* FIXME : how to properly get multiplicity from AOD and ESD consistently ?
-   is is doable at all ?
-   Int_t ntracklets(0);
-   AliAODTracklets* tracklets = aod.GetTracklets();
-   if ( tracklets )
-   {
-   ntracklets = tracklets->GetNumberOfTracklets();
-   }
-   Histo(physics,triggerClassName,centrality,"Tracklets")->Fill(ntracklets);
-   */
-
-}
-
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::FillHistogramCollection(const char* physics, const char* triggerClassName)
-{
-  /// Actually create the histograms for phyics/triggerClassName
-  
-  AliDebug(1,Form("(%s,%s)",physics,triggerClassName));
-  
-  Double_t ptMin = 0;
-  Double_t ptMax = 12*3;
-  Int_t nbinsPt = GetNbins(ptMin,ptMax,0.5);
-  Double_t pMin = 0;
-  Double_t pMax = 100*3;
-  Int_t nbinsP = GetNbins(pMin,pMax,2.0);
-  Double_t etaMin = -5;
-  Double_t etaMax = -2;
-  Int_t nbinsEta = GetNbins(etaMin,etaMax,0.05);
-  
-  Double_t rapidityMin = -5;
-  Double_t rapidityMax = -2;
-  Int_t nbinsRapidity = GetNbins(rapidityMin,rapidityMax,0.05);
-  
-  Double_t phiMin = -TMath::Pi();
-  Double_t phiMax = TMath::Pi();
-  Int_t nbinsPhi = GetNbins(phiMin,phiMax,0.05);
-  
-  CreateSingleHisto(physics,triggerClassName,"Chi2MatchTrigger","Chi2 Match Trigger",72,0,72);
-
-  CreateSingleHisto(physics,triggerClassName,"EtaRapidityMu", "Eta distribution vs Rapidity for #mu", nbinsRapidity,rapidityMin,rapidityMax,nbinsEta,etaMin,etaMax, fShouldSeparatePlusAndMinus);
-
-  CreateSingleHisto(physics,triggerClassName,"PtEtaMu", "P_{T} distribution vs Eta for #mu", nbinsEta,etaMin,etaMax, nbinsPt,ptMin,ptMax,fShouldSeparatePlusAndMinus);
-
-  CreateSingleHisto(physics,triggerClassName,"PtRapidityMu", "P_{T} distribution vs Rapidity for #mu", nbinsRapidity,rapidityMin,rapidityMax, nbinsPt,ptMin,ptMax,fShouldSeparatePlusAndMinus);
-
-  CreateSingleHisto(physics,triggerClassName,"PtPhiMu", "P_{T} distribution vs phi for #mu", nbinsPhi,phiMin,phiMax, nbinsPt,ptMin,ptMax,fShouldSeparatePlusAndMinus);
-  
-
-  CreateSingleHisto(physics,triggerClassName,"PEtaMu", "P distribution for #mu",nbinsEta,etaMin,etaMax,nbinsP,pMin,pMax,fShouldSeparatePlusAndMinus);
-
-  Double_t chi2min = 0;
-  Double_t chi2max = 20;
-  Int_t nbinchi2 = GetNbins(chi2min,chi2max,0.05);
-  
-  CreateSingleHisto(physics, triggerClassName, "Chi2Mu", "chisquare per NDF #mu", nbinchi2, chi2min, chi2max,fShouldSeparatePlusAndMinus);
-  
-  CreateMinvHistograms(physics,triggerClassName);
-  
-  CreatePairHisto(physics,triggerClassName,"Chi12","Chi2MatchTrigger of muon 1 vs muon 2",72,0,72,72,0,72);
-  CreatePairHisto(physics,triggerClassName,"Rabs12","Rabs of muon 1 vs muon ",100,0,100,100,0,100);
-
-  Double_t xmin = -40;
-  Double_t xmax = +40;
-  Int_t nbins = GetNbins(xmin,xmax,0.5);
-  
-  CreateEventHisto(physics,triggerClassName,"Zvertex","z vertex",nbins,xmin,xmax);  
-
-  CreateEventHisto(physics,triggerClassName,"T0Zvertex","T0 zvertex",nbins,xmin,xmax);
-
-  xmin = -5;
-  xmax = 5;
-  nbins = GetNbins(xmin,xmax,0.01);
-
-  CreateEventHisto(physics,triggerClassName,"Xvertex","x vertex",nbins,xmin,xmax);  
-  CreateEventHisto(physics,triggerClassName,"Yvertex","y vertex",nbins,xmin,xmax);  
-  
-//  CreateEventHisto(physics,triggerClassName,"YXvertex","y vs x vertex",nbins,xmin,xmax,nbins,xmin,xmax);  
-  
-//  if (!fIsFromESD)
-//  {
-//    
-//    CreateEventHisto(physics,triggerClassName,"PileUpZvertex","pileup z vertex",nbins,xmin,xmax);  
-//    
-//    CreateEventHisto(physics,triggerClassName,"PileUpXvertex","pileup x vertex",nbins,xmin,xmax);  
-//    CreateEventHisto(physics,triggerClassName,"PileUpYvertex","pileup y vertex",nbins,xmin,xmax);  
-//    
-//    CreateEventHisto(physics,triggerClassName,"PileUpYXvertex","pileup y vs x vertex",nbins,xmin,xmax,
-//                     nbins,xmin,xmax);  
-//    
-//  }
-
-  CreateEventHisto(physics,triggerClassName,"Nevents","number of events",2,-0.5,1.5);  
-
-  xmin = 0;
-  xmax = 3564;
-  nbins = GetNbins(xmin,xmax,1.0);
-  
-  CreateEventHisto(physics,triggerClassName,"BCX","bunch-crossing ids",nbins,xmin-0.5,xmax-0.5);
-
-  CreateEventHisto(physics,triggerClassName,"BCXD","bunch-crossing distances",nbins,xmin-0.5,xmax-0.5);
-
-  xmin = -200;
-  xmax = +200;
-  nbins = GetNbins(xmin,xmax,1.0);
-  
-  xmin = 0;
-  xmax = 150;
-  nbins = GetNbins(xmin,xmax,2.0);
-  
-  CreateSingleHisto(physics,triggerClassName,"dcaP23Mu","#mu DCA vs P for 2-3 degrees;P (GeV);DCA (cm)",nbinsP,pMin,pMax,nbins,xmin,xmax,fShouldSeparatePlusAndMinus);  
-
-  CreateSingleHisto(physics,triggerClassName,"dcaP310Mu","#mu DCA vs P for 3-10 degrees;P (GeV);DCA (cm)",nbinsP,pMin,pMax,nbins,xmin,xmax,fShouldSeparatePlusAndMinus);  
-
-  CreateSingleHisto(physics,triggerClassName,"dcaPwPtCut23Mu","#mu DCA vs P for 2-3 degrees with Pt Cut;P (GeV);DCA (cm)",nbinsP,pMin,pMax,nbins,xmin,xmax,fShouldSeparatePlusAndMinus);  
-
-  CreateSingleHisto(physics,triggerClassName,"dcaPwPtCut310Mu","#mu DCA vs P for 3-10 degrees with Pt Cut;P (GeV);DCA (cm)",nbinsP,pMin,pMax,nbins,xmin,xmax,fShouldSeparatePlusAndMinus);  
-  
-  xmin = -30;
-  xmax = +30;
-  nbins = GetNbins(xmin,xmax,0.1);
-  
-  CreateEventHisto(physics,triggerClassName,"V02D","V0C+V0A versus V0A-V0C;Time V0A - V0C (ns);Time V0A+V0C (ns)",nbins,xmin,xmax,nbins,xmin,xmax);
-
-  CreateEventHisto(physics,triggerClassName,"V02DwT0BB","V0C+V0A versus V0A-V0C with T0 BB;Time V0A - V0C (ns);Time V0A+V0C (ns)",nbins,xmin,xmax,nbins,xmin,xmax);
-  
-  CreateEventHisto(physics,triggerClassName,"V02DwT0BG","V0C+V0A versus V0A-V0C with T0 background flag on;Time V0A - V0C (ns);Time V0A+V0C (ns)",nbins,xmin,xmax,nbins,xmin,xmax);
-
-  CreateEventHisto(physics,triggerClassName,"V02DwT0PU","V0C+V0A versus V0A-V0C with T0 pile up flag on;Time V0A - V0C (ns);Time V0A+V0C (ns)",nbins,xmin,xmax,nbins,xmin,xmax);
-
-  CreateEventHisto(physics,triggerClassName,"V02DwT0SAT","V0C+V0A versus V0A-V0C with T0 satellite flag on;Time V0A - V0C (ns);Time V0A+V0C (ns)",nbins,xmin,xmax,nbins,xmin,xmax);
-
-  /*
-  CreateEventHisto(physics,triggerClassName,"T02D","(T0C+T0A)/2 versus (T0A-T0C)/2;Time (T0A-T0C)/2 (ns);Time (T0A+T0C)/2 (ns)",nbins,xmin,xmax,nbins,xmin,xmax);
-   CreateEventHisto(physics,triggerClassName,"T0Flags","T0 flags",3,0,3);
-   */
-
-  
-  if ( !IsHistogramDisabled("Centrality") )
-  {
-    TH1* h = new TH1F("Centrality","Centrality",12,-10,110);
-
-    fHistogramCollection->Adopt(Form("/%s/%s",physics,triggerClassName),h);
-  }
-  
-  xmin = 0;
-  xmax = 5000;
-  nbins = GetNbins(xmin,xmax,10);
-  
-  CreateEventHisto(physics,triggerClassName,"Tracklets","Number of tracklets",nbins,xmin,xmax);
-  
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::FillHistosForTrack(const char* physics,
-                                             const char* triggerClassName, 
-                                             const char* centrality,
-                                             const AliVParticle& track,
-                                             Int_t trackIndex)
-{
-  /// Fill histograms for one track
-  
-//  AliCodeTimerAuto("",0);
-  
-  TLorentzVector p(track.Px(),track.Py(),track.Pz(),
-                   TMath::Sqrt(MuonMass2()+track.P()*track.P()));
-  
-  
-  TString charge("");
-  
-  if ( ShouldSeparatePlusAndMinus() ) 
-  { 
-    if ( track.Charge() < 0 ) 
-    {
-      charge = "Minus";
-    }
-    else
-    {
-      charge = "Plus";
-    }
-  }
-  
-  UInt_t mask = GetTrackMask(trackIndex);
-  
-  Double_t dca = EAGetTrackDCA(track);
-  
-  Double_t theta = AliAnalysisMuonUtility::GetThetaAbsDeg(&track);
-  
-  TIter next(fSingleTrackCutNames);
-  TObjString* str;
-  
-  while ( ( str = static_cast<TObjString*>(next()) ) )
-  {
-    Bool_t test = ( ( str->GetUniqueID() & mask ) == str->GetUniqueID() );
-    
-    if ( test ) 
-    {
-      if (!IsHistogramDisabled("Chi2MatchTrigger"))
-      {
-        Histo(physics,triggerClassName,centrality,str->String().Data(),"Chi2MatchTrigger")->Fill(AliAnalysisMuonUtility::GetChi2MatchTrigger(&track));
-      }
-      
-      if (!IsHistogramDisabled("EtaRapidityMu*"))
-      {
-        Histo(physics,triggerClassName,centrality,str->String().Data(),Form("EtaRapidityMu%s",charge.Data()))->Fill(p.Rapidity(),p.Eta());
-      }
-      
-      if (!IsHistogramDisabled("PtEtaMu*"))
-      {
-        Histo(physics,triggerClassName,centrality,str->String().Data(),Form("PtEtaMu%s",charge.Data()))->Fill(p.Eta(),p.Pt());
-      }
-      
-      if (!IsHistogramDisabled("PtRapidityMu*"))
-      {
-        Histo(physics,triggerClassName,centrality,str->String().Data(),Form("PtRapidityMu%s",charge.Data()))->Fill(p.Rapidity(),p.Pt());
-      }
-      
-      if (!IsHistogramDisabled("PEtaMu*"))
-      {
-        Histo(physics,triggerClassName,centrality,str->String().Data(),Form("PEtaMu%s",charge.Data()))->Fill(p.Eta(),p.P());
-      }
-      
-      if (!IsHistogramDisabled("PtPhiMu*"))
-      {
-        Histo(physics,triggerClassName,centrality,str->String().Data(),Form("PtPhiMu%s",charge.Data()))->Fill(p.Phi(),p.Pt());
-      }
-      
-      if (!IsHistogramDisabled("Chi2Mu*"))
-      {
-        Histo(physics,triggerClassName,centrality,str->String().Data(),Form("Chi2Mu%s",charge.Data()))->Fill(AliAnalysisMuonUtility::GetChi2perNDFtracker(&track));
-      }
-      
-      if ( theta >= 2.0 && theta < 3.0 )
-      {
-        
-        if (!IsHistogramDisabled("dcaP23Mu*"))
-        {
-          Histo(physics,triggerClassName,centrality,str->String().Data(),Form("dcaP23Mu%s",charge.Data()))->Fill(p.P(),dca);
-        }
-
-        if ( p.Pt() > 2 )
-        {
-          if (!IsHistogramDisabled("dcaPwPtCut23Mu*"))
-          {
-            Histo(physics,triggerClassName,centrality,str->String().Data(),Form("dcaPwPtCut23Mu%s",charge.Data()))->Fill(p.P(),dca);
-          }
-        }
-      }
-      else if ( theta >= 3.0 && theta < 10.0 )
-      {
-        if (!IsHistogramDisabled("dcaP310Mu*"))
-        {
-          Histo(physics,triggerClassName,centrality,str->String().Data(),Form("dcaP310Mu%s",charge.Data()))->Fill(p.P(),dca);
-        }
-        if ( p.Pt() > 2 )
-        {
-          if (!IsHistogramDisabled("dcaPwPtCut310Mu*"))
-          {
-            Histo(physics,triggerClassName,centrality,str->String().Data(),Form("dcaPwPtCut310Mu%s",charge.Data()))->Fill(p.P(),dca);
-          }
-        }
-      }
-    }
-  }
-  
-  
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::FillHistos(const char* physics, const char* triggerClassName, 
-                                      const char* centrality)
-{
-  /// Fill histograms for /physics/triggerClassName/centrality
-  
-//  AliCodeTimerAuto("",0);
-
-  FillEventHistos(physics,triggerClassName,centrality);
-  
-  // Track loop
-  
-  if (!fBinArray)
-  {
-    fBinArray = fBinning->CreateBinObjArray("psi","y vs pt,integrated,pt,y,phi","");
-  }
-  
-  Int_t nTracks = AliAnalysisMuonUtility::GetNTracks(Event());
-  
-  for (Int_t i = 0; i < nTracks; ++i)
-  {
-    AliVParticle* tracki = AliAnalysisMuonUtility::GetTrack(i,Event());
-    
-    if (!tracki) continue;
-    
-    FillHistosForTrack(physics,triggerClassName,centrality,*tracki,i);
-    
-    TLorentzVector pi(tracki->Px(),tracki->Py(),tracki->Pz(),
-                      TMath::Sqrt(MuonMass2()+tracki->P()*tracki->P()));
-    
-    for (Int_t j = i+1; j < nTracks; ++j)
-    {
-      AliVParticle* trackj = AliAnalysisMuonUtility::GetTrack(j,Event());
-      
-      if (!trackj) continue;
-      
-      TLorentzVector pj(trackj->Px(),trackj->Py(),trackj->Pz(),
-                        TMath::Sqrt(MuonMass2()+trackj->P()*trackj->P()));
-      
-      pj += pi;
-      
-      TIter next(fPairTrackCutNames);
-      AliAnalysisTaskMuMu::PairCut* str;
-      
-      UInt_t maski(0),maskj(0),maskij(0);
-      
-      GetPairMask(*tracki,*trackj,i,j,maski,maskj,maskij);
-      
-      while ( ( str = static_cast<AliAnalysisTaskMuMu::PairCut*>(next()) ) )
-      {
-        UInt_t singleTrackMask = str->MaskForOneOrBothTrack();
-        UInt_t pairMask = str->MaskForTrackPair();
-        
-        Bool_t testi = ( ( maski & singleTrackMask ) == singleTrackMask ) ;
-        Bool_t testj = ( ( maskj & singleTrackMask ) == singleTrackMask ) ;
-        Bool_t testij(kTRUE);
-        
-        if (pairMask>0) testij = ( ( maskij & pairMask ) == pairMask ) ;
-        
-        if ( ( testi || testj ) && testij )
-        {
-          if (!IsHistogramDisabled("Chi12"))
-          {
-            Histo(physics,triggerClassName,centrality,str->GetName(),"Chi12")
-            ->Fill(
-                   AliAnalysisMuonUtility::GetChi2perNDFtracker(tracki),
-                   AliAnalysisMuonUtility::GetChi2perNDFtracker(trackj));
-          }
-          
-          if (!IsHistogramDisabled("Rabs12"))
-          {
-            Histo(physics,triggerClassName,centrality,str->GetName(),"Rabs12")
-            ->Fill(AliAnalysisMuonUtility::GetRabs(tracki),
-                   AliAnalysisMuonUtility::GetRabs(trackj));
-          }
-          
-          if ( ( tracki->Charge() != trackj->Charge() ) )
-          {
-            TIter nextBin(fBinArray);
-            AliAnalysisMuMuBinning::Range* r;
-            
-            Histo(physics,triggerClassName,centrality,str->GetName(),"Pt")->Fill(pj.Pt());
-
-            if ( HasMC() )
-            {
-              Int_t labeli = tracki->GetLabel();
-              Int_t labelj = trackj->GetLabel();
-            
-              if ( labeli < 0 || labelj < 0 )
-              {
-                AliError("Got negative labels!");
-              }
-              else
-              {
-                AliVParticle* mcTracki = MCEvent()->GetTrack(labeli);
-                AliVParticle* mcTrackj = MCEvent()->GetTrack(labelj);
-                
-                TLorentzVector mcpi(mcTracki->Px(),mcTracki->Py(),mcTracki->Pz(),
-                                  TMath::Sqrt(MuonMass2()+mcTracki->P()*mcTracki->P()));
-                TLorentzVector mcpj(mcTrackj->Px(),mcTrackj->Py(),mcTrackj->Pz(),
-                                  TMath::Sqrt(MuonMass2()+mcTrackj->P()*mcTrackj->P()));
-
-                mcpj += mcpi;
-                
-                Histo(physics,triggerClassName,centrality,str->GetName(),"PtRecVsSim")->Fill(mcpj.Pt(),pj.Pt());
-                
-              }
-            }
-            
-            while ( ( r = static_cast<AliAnalysisMuMuBinning::Range*>(nextBin()) ) )
-            {
-//              AliInfo(Form("%s y %e pt %e ok1 %d ok2 %d",
-//                           r->AsString().Data(),
-//                           pj.Rapidity(),
-//                           pj.Pt(),
-//                           r->IsInRange(pj.Rapidity(),pj.Pt()),
-//                           r->IsInRange(pj.Pt(),pj.Rapidity())));
-              
-                           
-              Bool_t ok(kFALSE);
-              
-              if ( r->IsNullObject() )
-              {
-                ok = kTRUE;
-              }
-              else if ( r->Is2D() )
-              {
-                if ( r->AsString().BeginsWith("PTVSY") )
-                {
-                  ok = r->IsInRange(pj.Rapidity(),pj.Pt());                  
-                }
-                else if ( r->AsString().BeginsWith("YVSPT") )
-                {
-                  ok = r->IsInRange(pj.Pt(),pj.Rapidity());
-                }
-                else
-                {
-                  AliError(Form("Don't know how to deal with 2D bin %s",r->AsString().Data()));
-                }
-              }
-              else
-              {
-                if ( r->Type() == "PT" )
-                {
-                  ok = r->IsInRange(pj.Pt());
-                }
-                else if ( r->Type() == "Y" )
-                {
-                  ok = r->IsInRange(pj.Rapidity());
-                }
-                else if ( r->Type() == "PHI" )
-                {
-                  ok = r->IsInRange(pj.Phi());
-                }
-              }
-              
-              if ( ok )
-              {
-                TString hname = GetMinvHistoName(*r);
-              
-                if (!IsHistogramDisabled(hname.Data()))
-                {
-                  TH1* h = Histo(physics,triggerClassName,centrality,str->GetName(),hname.Data());
-                
-                  if (!h)
-                  {
-                    AliError(Form("Could not get %s",hname.Data()));
-                  }
-                  h->Fill(pj.M());
-                }
-              }
-            }
-              
-          }
-        }
-      }
-    }
-  } //track loop
-  
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::FinishTaskOutput()
-{
-  /// prune empty histograms BEFORE mergin, in order to save some bytes...
-  
-  if ( fHistogramCollection )
-  {
-    fHistogramCollection->PruneEmptyObjects();
-  }
-}
-
-//_____________________________________________________________________________
-UInt_t AliAnalysisTaskMuMu::GetEventMask() const
-{
-  /// Compute the event mask
-  
-  /*
-  
-  kEventAll = all events
-  kEventPS = physics selected events
-  kEventTVX = events with 0TVX input present
-  kEventV0AND = events with 0VBA and 0VBC present
-  kEventV0UP = a check of events within a narrow square range of v0a+c vs v0a-c
-  kEventZSPD = events with a vertex computed by SPD
-  kEventZ7 = events with | zvertex | < 7cm
-  kEventZ10 = events with | zvertex | < 10 cm
-  kEventSD2 = events with 0SD2 input present (was for PbPb 2010)
-  kEventMSL = events with 0MSL input present
-  kEventNOPILEUP = events with the T0 pile-up flag not present
-  kEventREJECTED = events not physics selected
-   */
-  
-//  AliCodeTimerAuto("",0);
-  
-  UInt_t eMask = EventCuts()->GetSelectionMask(fInputHandler);
-
-  UInt_t m(AliAnalysisTaskMuMu::kEventAll);
-
-  if ( eMask & AliMuonEventCuts::kPhysicsSelected )
-  {
-    m |= AliAnalysisTaskMuMu::kEventPS;
-  }
-  else
-  {
-    m |= AliAnalysisTaskMuMu::kEventREJECTED;
-  }
-  
-  UInt_t trigger = AliAnalysisMuonUtility::GetL0TriggerInputs(Event());
-  
-  UInt_t l0TVXBIT = GetTriggerInputBitMaskFromInputName("0TVX");
-  
-  if ( ( trigger & (l0TVXBIT) ) == l0TVXBIT )
-  {
-    m |= AliAnalysisTaskMuMu::kEventTVX;
-  }
-  
-  UInt_t l0VBABIT = GetTriggerInputBitMaskFromInputName("0VBA");
-  UInt_t l0VBCBIT = GetTriggerInputBitMaskFromInputName("0VBC");
-  
-  if ( ( ( trigger & (l0VBABIT ) ) == l0VBABIT ) && 
-      ( ( trigger & (l0VBCBIT ) ) == l0VBCBIT ) )
-  {
-    m |= AliAnalysisTaskMuMu::kEventV0AND;
-  }
-  
-  UInt_t l0MSLBIT = GetTriggerInputBitMaskFromInputName("0MSL");
-  
-  if ( ( trigger & (l0MSLBIT) ) == l0MSLBIT )
-  {
-    m |= AliAnalysisTaskMuMu::kEventMSL;
-  }
-  
-  if ( fBeamYear == "PbPb2010" ) 
-  {
-    // consider only events with OSM2 fired
-    UInt_t sd2 = GetTriggerInputBitMaskFromInputName("0SM2");
-    if ( ( trigger & sd2 ) == sd2 )
-    {
-      m |= AliAnalysisTaskMuMu::kEventSD2;
-    }
-  }
-  
-  //  Bool_t hasPileUp = aod->IsPileupFromSPD(3,0.8);
-  //  Bool_t hasPileUp2 = aod->IsPileupFromSPD(5,0.8);  
-  //  Bool_t isIsolated = ( aod->GetBunchCrossNumber() > 1000 && aod->GetBunchCrossNumber() < 2900 );
-  
-  //  Bool_t hasPileUp2 = aod->IsPileupFromSPDInMultBins();
-  
-  //  TIter nextV(aod->GetVertices());
-  //  AliAODVertex* v;
-  //  while ( ( v = static_cast<AliAODVertex*>(nextV())) && !hasPileUp2 )
-  //  {
-  //    if ( v->GetType() == AliAODVertex::kPileupSPD ) hasPileUp2 = kTRUE;
-  //  }
-  
-  //  Bool_t isIsolated = false;//( aod->GetClosestBunchCrossingDistance() > 10 );
-  
-  const AliVVertex* vertex = Event()->GetPrimaryVertex();
-  
-  if ( vertex->IsA() == AliAODVertex::Class() )
-  {
-    AliAODVertex* spdVertex = static_cast<const AliAODEvent*>(Event())->GetPrimaryVertexSPD();
-
-    if ( spdVertex && spdVertex->GetNContributors() > 0 ) 
-    {
-      m |= AliAnalysisTaskMuMu::kEventZSPD;
-    }
-  }
-  
-  if ( TMath::Abs(vertex->GetZ()) < 10.0 )
-  {
-    m |= AliAnalysisTaskMuMu::kEventZ10;
-  }
-  
-  if ( TMath::Abs(vertex->GetZ()) < 7.0 )
-  {
-    m |= AliAnalysisTaskMuMu::kEventZ7;
-  }
-  
-//  AliVVZERO* vzero = Event()->GetVZEROData();
-//  
-//  if (vzero)
-//  {
-//    Float_t v0a = vzero->GetV0ATime();
-//    Float_t v0c = vzero->GetV0CTime();
-//    
-//    Float_t x = v0a-v0c;
-//    Float_t y = v0a+v0c;
-//    
-//    if ( ( x > 6 && x < 10 ) && y > 20 )
-//    {
-//      m |= AliAnalysisTaskMuMu::kEventV0UP;
-//    }
-//  }
-  
-  Bool_t backgroundFlag(kFALSE);
-  Bool_t pileupFlag(kFALSE);
-  Bool_t satelliteFlag(kFALSE);
-  
-  EAGetTZEROFlags(backgroundFlag,pileupFlag,satelliteFlag);
-  
-  if ( !pileupFlag )
-  {
-    m |= AliAnalysisTaskMuMu::kEventNOTZEROPILEUP;
-  }
-  
-  int nmu = EAGetNumberOfSelectMuonTracks();
-
-  if ( nmu >=1 )
-  {
-    m |= AliAnalysisTaskMuMu::kEventOFFLINEMUL1;
-  }
-
-  if ( nmu >=2 )
-  {
-    m |= AliAnalysisTaskMuMu::kEventOFFLINEMUL2;
-  }
-
-  return m;
-}
-
-//_____________________________________________________________________________
-UInt_t AliAnalysisTaskMuMu::GetTriggerInputBitMaskFromInputName(const char* inputName) const
-{
-  // Get trigger input bit from its name
-  // FIXME : this should really come directly from the trigger configuration
-  // object, if only this one would be available in a more convenient
-  // way than the OCDB (e.g. in RunBasedContainer ?)
-  //
-
-  if ( fTriggerInputBitMap.empty() )
-  {
-    // nothing given to us, use the bad bad hard-coded values !
-    
-    TString sInputName(inputName);
-
-    if ( sInputName == "0SM2" ) return (1<<12);
-
-    
-    if ( sInputName == "0VBA" ) return (1<<0);
-    if ( sInputName == "0VBC" ) return (1<<1);
-    if ( sInputName == "0SMB" ) return (1<<2);
-    if ( sInputName == "0TVX" ) return (1<<3);
-    if ( sInputName == "0VGC" ) return (1<<4);
-    if ( sInputName == "0VGA" ) return (1<<5);
-    if ( sInputName == "0SH1" ) return (1<<6);
-    if ( sInputName == "0SH2" ) return (1<<7);
-    if ( sInputName == "0HPT" ) return (1<<8);
-    if ( sInputName == "0AMU" ) return (1<<9);
-    if ( sInputName == "0OB0" ) return (1<<10);
-    if ( sInputName == "0ASL" ) return (1<<11);
-
-    /*
-    if ( sInputName == "0MSL" ) return (1<<12);
-
-//    if ( sInputName == "0MSH" ) return (1<<13);
-    if ( sInputName == "0MSH" ) return (1<<8);
-    
-    if ( sInputName == "0MUL" ) return (1<<14);
-    if ( sInputName == "0MLL" ) return (1<<15);
-     */
-    
-    if ( sInputName == "0MSL") return (1<<12);
-    if ( sInputName == "0MSH") return (1<<13);
-    if ( sInputName == "0MUL") return (1<<14);
-    if ( sInputName == "0MLL") return (1<<15);
-    
-    if ( sInputName == "0EMC" ) return (1<<16);
-    if ( sInputName == "0PH0" ) return (1<<17);
-    if ( sInputName == "0HWU" ) return (1<<18);
-    if ( sInputName == "0LSR" ) return (1<<19);
-    if ( sInputName == "0T0A" ) return (1<<20);
-    if ( sInputName == "0BPA" ) return (1<<21);
-    if ( sInputName == "0BPC" ) return (1<<22);
-    if ( sInputName == "0T0C" ) return (1<<23);
+void AliAnalysisTaskMuMu::Fill(const char* eventSelection, const char* triggerClassName)
+{
+  // Fill one set of histograms (only called for events which pass the eventSelection cut)
+  
+  TString seventSelection(eventSelection);
+  seventSelection.ToLower();
+  
+  fEventCounters->Count(Form("event:%s/trigger:%s/centrality:%s/run:%d", seventSelection.Data(), triggerClassName, "ALL", fCurrentRunNumber));
 
-    if ( sInputName == "1EJE" ) return (1<<0);
-    if ( sInputName == "1EGA" ) return (1<<1);
-    if ( sInputName == "1EJ2" ) return (1<<2);
-    if ( sInputName == "1EG2" ) return (1<<3);
-    if ( sInputName == "1PHL" ) return (1<<4);
-    if ( sInputName == "1PHM" ) return (1<<5);
-    if ( sInputName == "1PHH" ) return (1<<6);
-    if ( sInputName == "1HCO" ) return (1<<8);
-    if ( sInputName == "1HJT" ) return (1<<9);
-    if ( sInputName == "1HSE" ) return (1<<10);
-    if ( sInputName == "1DUM" ) return (1<<11);
-    if ( sInputName == "1HQU" ) return (1<<12);
-    if ( sInputName == "1H14" ) return (1<<13);
-    if ( sInputName == "1ZMD" ) return (1<<14);
-    if ( sInputName == "1ZMB" ) return (1<<16);
-    if ( sInputName == "1ZED" ) return (1<<17);
-    if ( sInputName == "1ZAC" ) return (1<<18);
-    if ( sInputName == "1EJE" ) return (1<<19);
+  if ( !IsHistogrammingDisabled() )
+  {
+    TObjArray* centralities = fBinning->CreateBinObjArray("centrality");
     
-    AliError(Form("Don't know this input %s",inputName));
+    TIter next(centralities);
+    AliAnalysisMuMuBinning::Range* r;
     
-    return (1<<31);
-  }
-  else
-  {
-    std::map<std::string,int>::const_iterator it = fTriggerInputBitMap.find(inputName);
-    if ( it != fTriggerInputBitMap.end() )
+    while ( ( r = static_cast<AliAnalysisMuMuBinning::Range*>(next()) ) )
     {
-      return ( 1 << it->second );
-    }
-    else
-    {
-      AliError(Form("Don't know this input %s",inputName));
+      TString estimator = r->Quantity();
       
-      return (1<<31);
+      Float_t fcent = Event()->GetCentrality()->GetCentralityPercentile(estimator.Data());
+      if ( fcent < 0.) FillHistos(eventSelection,triggerClassName,"MV0");
+      if ( fcent == 0.) FillHistos(eventSelection,triggerClassName,"0V0");
+      if ( r->IsInRange(fcent) )
+      {
+        FillHistos(eventSelection,triggerClassName,r->AsString());
+      }
     }
+    delete centralities;
   }
 }
 
 //_____________________________________________________________________________
-void AliAnalysisTaskMuMu::GetPairMask(const AliVParticle& t1, const AliVParticle& t2,
-                                      Int_t trackIndex1, Int_t trackIndex2,
-                                      UInt_t& mask1, UInt_t& mask2,
-                                      UInt_t& mask12) const
+void AliAnalysisTaskMuMu::FillHistos(const char* eventSelection,
+                                     const char* triggerClassName,
+                                     const char* centrality)
 {
-  /// Get the mask of the track pair
+  /// Fill histograms for /physics/triggerClassName/centrality
   
-  mask1 = GetTrackMask(trackIndex1);
-  mask2 = GetTrackMask(trackIndex2);
+  AliCodeTimerAuto("",0);
   
-  mask12 = mask1 & mask2;
+  TIter nextAnalysis(fSubAnalysisVector);
+  AliAnalysisMuMuBase* analysis;
   
-  if ( PairRapidityCut(t1,t2) ) mask12 |= kPairRapidity;
-}
-
-//_____________________________________________________________________________
-UInt_t AliAnalysisTaskMuMu::GetTrackMask(Int_t trackIndex) const
-{
-  /// Get the mask of all the cuts this track pass
+  Int_t nTracks = AliAnalysisMuonUtility::GetNTracks(Event());
   
-  return static_cast<UInt_t>(fPrecomputedTrackMasks.At(trackIndex));
-}
+  fEventCounters->Count(Form("event:%s/trigger:%s/centrality:%s/run:%d", eventSelection, triggerClassName, centrality, fCurrentRunNumber));
+  
+  TIter nextTrackCut(fCutRegistry->GetCutCombinations(AliAnalysisMuMuCutElement::kTrack));
+  TIter nextPairCut(fCutRegistry->GetCutCombinations(AliAnalysisMuMuCutElement::kTrackPair));
+  
+  // loop on single tracks (whatever the type of tracks
+  while ( ( analysis = static_cast<AliAnalysisMuMuBase*>(nextAnalysis()) ) )
+  {
+    analysis->DefineHistogramCollection(eventSelection,triggerClassName,centrality);
+    
+    AliCodeTimerAuto(Form("%s (FillHistosForEvent)",analysis->ClassName()),1);
 
-//_____________________________________________________________________________
-TH1* AliAnalysisTaskMuMu::Histo(const char* physics, const char* triggerClassName, const char* histoname)
-{
-  /// Get one histo back
-  return fHistogramCollection ? fHistogramCollection->Histo(Form("/%s/%s/%s",physics,triggerClassName,histoname)) : 0x0;
-}
+    if ( MCEvent() != 0x0 )
+    {
+      analysis->FillHistosForMCEvent(eventSelection,triggerClassName,centrality);
+    }
 
-//_____________________________________________________________________________
-TH1* AliAnalysisTaskMuMu::Histo(const char* physics, const char* histoname)
-{
-  /// Get one histo back
-  return fHistogramCollection ? fHistogramCollection->Histo(physics,histoname) : 0x0;
+    analysis->FillHistosForEvent(eventSelection,triggerClassName,centrality);
+    
+    for (Int_t i = 0; i < nTracks; ++i)
+    {
+      AliVParticle* tracki = AliAnalysisMuonUtility::GetTrack(i,Event());
+      
+      nextTrackCut.Reset();
+      AliAnalysisMuMuCutCombination* trackCut;
+      
+      while ( ( trackCut = static_cast<AliAnalysisMuMuCutCombination*>(nextTrackCut()) ) )
+      {
+        if ( trackCut->Pass(*tracki) )
+        {
+          analysis->FillHistosForTrack(eventSelection,triggerClassName,centrality,trackCut->GetName(),*tracki);
+        }
+      }
+      
+      if (!AliAnalysisMuonUtility::IsMuonTrack(tracki) ) continue;
+      
+      // loop on track pairs (here we only consider muon pairs)
+      
+      for (Int_t j = i+1; j < nTracks; ++j)
+      {
+        AliVParticle* trackj = AliAnalysisMuonUtility::GetTrack(j,Event());
+        
+        if (!AliAnalysisMuonUtility::IsMuonTrack(trackj) ) continue;
+        
+        nextPairCut.Reset();
+        AliAnalysisMuMuCutCombination* pairCut;
+        
+        while ( ( pairCut = static_cast<AliAnalysisMuMuCutCombination*>(nextPairCut()) ) )
+        {
+          Bool_t testi = (pairCut->IsTrackCutter()) ? pairCut->Pass(*tracki) : kTRUE;
+          Bool_t testj = (pairCut->IsTrackCutter()) ? pairCut->Pass(*trackj) : kTRUE;
+          Bool_t testij = pairCut->Pass(*tracki,*trackj);
+          
+          if ( ( testi || testj ) && testij )
+          {
+            analysis->FillHistosForPair(eventSelection,triggerClassName,centrality,pairCut->GetName(),*tracki,*trackj);
+          }
+        }
+      }
+    }
+  }
 }
 
 //_____________________________________________________________________________
-TH1* AliAnalysisTaskMuMu::Histo(const char* physics,
-                            const char* triggerClassName, 
-                            const char* what,
-                            const char* histoname)
+void AliAnalysisTaskMuMu::FinishTaskOutput()
 {
-  /// Get one histo back
-  return fHistogramCollection ? fHistogramCollection->Histo(Form("/%s/%s/%s",physics,triggerClassName,what),histoname) : 0x0;
+  /// prune empty histograms BEFORE mergin, in order to save some bytes...
+  
+  if ( fHistogramCollection )
+  {
+    fHistogramCollection->PruneEmptyObjects();
+  }
 }
 
 //_____________________________________________________________________________
-TH1* AliAnalysisTaskMuMu::Histo(const char* physics,
-                            const char* triggerClassName, 
-                            const char* cent,
-                            const char* what,
-                            const char* histoname)
+void AliAnalysisTaskMuMu::GetSelectedTrigClassesInEvent(const AliVEvent* event, TObjArray& array)
 {
-  /// Get one histo back
+  /// Fills the array with a list of TObjString of the trigger classes that the various
+  /// cuts accept for this event
+  
+  array.Clear();
+  
+  if (!event)
+  {
+    AliError("Will get a hard time selecting trigger classes with an empty event...");
+    return;
+  }
+  
+  TString firedTriggerClasses = event->GetFiredTriggerClasses();
+  UInt_t l0 = AliAnalysisMuonUtility::GetL0TriggerInputs(event);
+  UInt_t l1 = AliAnalysisMuonUtility::GetL1TriggerInputs(event);
+  UInt_t l2 = AliAnalysisMuonUtility::GetL2TriggerInputs(event);
 
-  return fHistogramCollection ? fHistogramCollection->Histo(Form("/%s/%s/%s/%s",physics,triggerClassName,cent,what),histoname) : 0x0;
+  std::set<std::string> tmpArray;
+  
+  TIter nextCutCombination(CutRegistry()->GetCutCombinations(AliAnalysisMuMuCutElement::kTriggerClass));
+  AliAnalysisMuMuCutCombination* cutCombination;
+  
+  while ( ( cutCombination = static_cast<AliAnalysisMuMuCutCombination*>(nextCutCombination()) ) )
+  {
+    TString acceptedTriggerClasses;
+    
+    if ( cutCombination->Pass(firedTriggerClasses,acceptedTriggerClasses,l0,l1,l2) )
+    {
+      TObjArray* split = acceptedTriggerClasses.Tokenize(" ");
+      TIter next(split);
+      TObjString* str;
+      while ( ( str = static_cast<TObjString*>(next()) ) )
+      {
+        tmpArray.insert(str->String().Data());
+      }
+      delete split;
+    }
+  }
+  
+  std::set<std::string>::const_iterator it;
+  
+  for ( it = tmpArray.begin(); it != tmpArray.end(); ++it )
+  {
+    array.Add(new TObjString(it->c_str()));
+  }
 }
 
+
 //_____________________________________________________________________________
 Bool_t AliAnalysisTaskMuMu::IsHistogramDisabled(const char* hname) const
 {
   /// Whether or not a given histogram (identified by its name)
   /// is disabled or not
-  if ( !fHistogramToDisable )
-  {
-    return kFALSE;
-  }
-  TString shname(hname);
-  TIter next(fHistogramToDisable);
-  TObjString* str(0x0);
   
-  while ( ( str = static_cast<TObjString*>(next()) ) )
+  TIter next(fSubAnalysisVector);
+  AliAnalysisMuMuBase* analysis;
+  
+  while ( ( analysis = static_cast<AliAnalysisMuMuBase*>(next()) ) )
   {
-    if ( shname.Contains(TRegexp(str->String()) ) )
+    if ( analysis->IsHistogramDisabled(hname) )
     {
       return kTRUE;
     }
   }
+  
   return kFALSE;
 }
 
@@ -1920,15 +366,17 @@ Bool_t AliAnalysisTaskMuMu::IsHistogrammingDisabled() const
 {
   /// Whether or not *all* histograms are disabled
   
-  if ( fHistogramToDisable && fHistogramToDisable->GetEntries()==1 )
+  Bool_t disabled(kTRUE);
+  
+  TIter next(fSubAnalysisVector);
+  AliAnalysisMuMuBase* analysis;
+
+  while ( ( analysis = static_cast<AliAnalysisMuMuBase*>(next()) ) )
   {
-    TObjString* r = static_cast<TObjString*>(fHistogramToDisable->First());
-    if ( r->String() == "*" )
-    {
-      return kTRUE;
-    }
+    disabled = disabled && analysis->IsHistogrammingDisabled();
   }
-  return kFALSE;
+
+  return disabled;
 }
 
 //_____________________________________________________________________________
@@ -1938,107 +386,6 @@ Bool_t AliAnalysisTaskMuMu::IsPP() const
   return fBeamYear.Contains("pp");
 }
 
-//_____________________________________________________________________________
-//void AliAnalysisTaskMuMu::MergeCentralities(AliHistogramCollection* histogramCollection)
-//{
-  /// FIXME : Reimplement using AliMergeableCollection::GetSum ?
-  
-  /// Merge CENT10 + CENT20 + ... into CENTMB
-  
-//  TList* listA = histogramCollection->CreateListOfKeysA();
-//  TList* listB = histogramCollection->CreateListOfKeysB();
-//  TList* listC = histogramCollection->CreateListOfKeysC();
-//  TList* listD = histogramCollection->CreateListOfKeysD();
-//  
-//  if (!listA) 
-//  {
-//    AliErrorClass("listA=0x0");
-//    return;
-//  }
-//  
-//  if (!listB) 
-//  {
-//    AliErrorClass("listB=0x0");
-//    return;
-//  }
-//  
-//  if (!listC) 
-//  {
-//    AliErrorClass("listC=0x0");
-//    return;
-//  }
-//  
-//  if (!listD) 
-//  {
-//    AliErrorClass("listD=0x0");
-//    return;
-//  }
-//  
-//  for ( Int_t id = 0; id <= listD->GetLast(); ++id ) 
-//  {
-//    TString keyD = static_cast<TObjString*>(listD->At(id))->String();
-//    
-//    for ( Int_t ia = 0; ia <= listA->GetLast(); ++ia )
-//    {
-//      TString keyA = static_cast<TObjString*>(listA->At(ia))->String();
-//      
-//      for ( Int_t ib = 0; ib <= listB->GetLast(); ++ib ) 
-//      {
-//        TString keyB = static_cast<TObjString*>(listB->At(ib))->String();
-//        
-//        TList* list = new TList;
-//        list->SetOwner(kTRUE);
-//        
-//        AliHistogramCollection* hmerge(0x0);
-//        
-//        for ( Int_t ic = 0; ic <= listC->GetLast(); ++ic ) 
-//        {
-//          TString keyC = static_cast<TObjString*>(listC->At(ic))->String();
-//          
-//          if ( keyC != "CENTX" && keyC != "CENTMB" )
-//          {
-//            AliHistogramCollection* hc = histogramCollection->Project(keyA.Data(),keyB.Data(),keyC.Data(),keyD.Data());
-//            if (!hmerge) 
-//            {
-//              hmerge = hc;
-//            }
-//            else
-//            {
-//              list->Add(hc);
-//            }
-//          }
-//        }
-//        if (hmerge)
-//        {
-//          hmerge->Merge(list);
-//          TIter next(hmerge->CreateIterator());
-//          TH1* h;
-//          while ( ( h = static_cast<TH1*>(next()) ) )
-//          {
-//            histogramCollection->Adopt(keyA.Data(),keyB.Data(),"CENTMB",keyD.Data(),static_cast<TH1*>(h->Clone()));
-//          }
-//        }
-//        delete list;
-//        delete hmerge;
-//      }      
-//    }
-//  }
-//  
-//  delete listA;
-//  delete listB;
-//  delete listC;
-//  delete listD;
-//}
-
-//_____________________________________________________________________________
-Double_t AliAnalysisTaskMuMu::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...
-  //  static Double_t m2 = TDatabasePDG::Instance()->GetParticle("mu-")->Mass()*TDatabasePDG::Instance()->GetParticle("mu-")->Mass();
-  return m2;
-}
-
 //_____________________________________________________________________________
 void AliAnalysisTaskMuMu::NotifyRun()
 {
@@ -2046,143 +393,113 @@ void AliAnalysisTaskMuMu::NotifyRun()
   
   AliDebug(1,Form("Run %09d File %s",fCurrentRunNumber,CurrentFileName()));
  
-  MuonTrackCuts()->SetRun(fInputHandler);
-}
-
-//_____________________________________________________________________________
-Bool_t AliAnalysisTaskMuMu::PairRapidityCut(const AliVParticle& t1, const AliVParticle& t2) const
-{
-  /// Whether the pair passes the rapidity cut
-  
-  TLorentzVector p1(t1.Px(),t1.Py(),t1.Pz(),TMath::Sqrt(MuonMass2()+t1.P()*t1.P()));
-  TLorentzVector p2(t2.Px(),t2.Py(),t2.Pz(),TMath::Sqrt(MuonMass2()+t2.P()*t2.P()));
+  TIter next(fSubAnalysisVector);
+  AliAnalysisMuMuBase* analysis;
   
-  TLorentzVector total(p1+p2);
-  
-  Double_t y = total.Rapidity();
-  
-  return  ( y < -2.5 && y > -4.0 );
+  while ( ( analysis = static_cast<AliAnalysisMuMuBase*>(next()) ) )
+  {
+    analysis->SetRun(fInputHandler);
+  }
 }
 
 //_____________________________________________________________________________
 void 
-AliAnalysisTaskMuMu::Print(Option_t* /*opt*/) const
+AliAnalysisTaskMuMu::Print(Option_t* opt) const
 {
   /// Print the definition of this analysis
   
   cout << ClassName() << " - " << GetName() << " - " << fBeamYear.Data() << endl;
+
+  TIter next(fSubAnalysisVector);
+  AliAnalysisMuMuBase* analysis;
   
-  if  ( !fSingleTrackCutNames || !fSingleTrackCutNames )
-  {
-    cout << "No single track cut defined yet" << endl;    
-  }
-  else
-  {
-    TIter next(fSingleTrackCutNames);
-    TObjString* str;
-    
-    while ( ( str = static_cast<TObjString*>(next()) ) )
-    {
-      cout << Form("SINGLE CUT %20s MASK %x",str->String().Data(),str->GetUniqueID()) << endl;
-    }
-  }
-  
-  if  ( !fPairTrackCutNames || !fPairTrackCutNames )
-  {
-    cout << "No track pair cut defined yet" << endl;    
-  }
-  else
+  while ( ( analysis = static_cast<AliAnalysisMuMuBase*>(next()) ) )
   {
-    TIter next2(fPairTrackCutNames);
-    AliAnalysisTaskMuMu::PairCut* str;
-
-    while ( ( str = static_cast<AliAnalysisTaskMuMu::PairCut*>(next2()) ) )
-    {
-      str->Print();
-    }
+    analysis->Print(opt);
   }
 
-  if ( !fEventCutNames )
-  {
-    cout << "No event cut defined yet" << endl;
-  }
-  else
-  {
-    TIter nextEventCutName(fEventCutNames);
-    TObjString* eventCutName;
-    
-    while ( ( eventCutName = static_cast<TObjString*>(nextEventCutName()) ) )
-    {
-      cout << Form("EVENT  CUT %s MASK %x",eventCutName->String().Data(),eventCutName->GetUniqueID()) << endl;
-    }
-  }
+  fCutRegistry->Print("ALL");
   
   if ( fBinning )
   {
-    cout << "Binning for Minv plots" << endl;
+    cout << "Binning" << endl;
     fBinning->Print();
   }
 }
 
 //_____________________________________________________________________________
 void
-AliAnalysisTaskMuMu::Terminate(Option_t *)
+AliAnalysisTaskMuMu::Terminate(Option_t* opt)
 {
   /// Called once at the end of the query
   /// Just a simple printout of the stat we analyse and how many histograms
   /// we got
   
+  TIter next(fSubAnalysisVector);
+  AliAnalysisMuMuBase* analysis;
+  
+  while ( ( analysis = static_cast<AliAnalysisMuMuBase*>(next()) ) )
+  {
+    analysis->Terminate(opt);
+  }
+
   fHistogramCollection = dynamic_cast<AliMergeableCollection*>(GetOutputData(1));
 
   if (!fHistogramCollection)
   {
     AliError("Could not find back histogram collection in output...");
-    return;
   }
-  
-  fHistogramCollection->PruneEmptyObjects();
-
-  UInt_t size2 = fHistogramCollection->EstimateSize();
+  else
+  {
+    // Removes empty objects and also the event histos of the Nch task
+    fHistogramCollection->PruneEmptyObjects();
+    
+    UInt_t size2 = fHistogramCollection->EstimateSize();
 
-  AliInfo(Form("size after prune histograms = %5.1f MB",size2/1024.0/1024.0));
-  
-//  if ( !IsPP() && fCentralityLimits.size() > 1 ) 
-//  {
-//    MergeCentralities(fHistogramCollection);    
-//  }
+    TIter nextHistogram(fHistogramCollection->CreateIterator());
+    TObject* object;
+    
+    while ( ( object = nextHistogram() ) )
+    {
+      if ( object->IsA()->InheritsFrom(TH1::Class()) )
+      {
+        TH1* h = static_cast<TH1*>(object);
+        if ( h->GetXaxis()->GetLabels() )
+        {
+          h->LabelsDeflate("X");
+        }
+      }
+    }
+    
+    AliInfo(Form("size after prune histograms = %5.1f MB",size2/1024.0/1024.0));
   
-  BeautifyHistos();
-
-  fHistogramCollection->Print("^MinvUS$");
+    fHistogramCollection->Print("-");
+  }
   
   fEventCounters = dynamic_cast<AliCounterCollection*>(GetOutputData(2));
   
   if (!fEventCounters)
   {
     AliError("Could not find back counters in output...");
-    return;
   }
-  
-  fEventCounters->Print("trigger");
+  else
+  {
+    fEventCounters->Print("trigger/event");
+  }
   
   // post param container(s)
   PostData(3,fBinning);
 }
 
 //_____________________________________________________________________________
-Bool_t AliAnalysisTaskMuMu::TriggerSBACECondition(const TString& triggerName) const
+AliAnalysisMuMuBinning* AliAnalysisTaskMuMu::Binning() const
 {
-  // check the beam condition in the trigger name
+  // Return our binning (making a default one if not already created
+  if ( fBinning ) return fBinning;
   
-  if ( triggerName.Contains("-S-") ) return kTRUE;
-
-  if ( triggerName.Contains("-B-") ) return kTRUE;
-
-  if ( fUseBackgroundTriggers )
-  {
-    if ( triggerName.Contains("-ACE-") ) return kTRUE;
-  }
-  return kFALSE;
+  fBinning = new AliAnalysisMuMuBinning("BIN");
+  
+  return fBinning;
 }
 
 //_____________________________________________________________________________
@@ -2190,112 +507,82 @@ void AliAnalysisTaskMuMu::UserExec(Option_t* /*opt*/)
 {
   /// Executed at each event
   
-//  AliCodeTimerAuto("",0);
-  
-  fHasMC = (MCEvent()!=0x0);
-
-  if ( HasMC() )
-  {
-    MuonTrackCuts()->SetIsMC();
-  }
-  
-  TString firedTriggerClasses(AliAnalysisMuonUtility::GetFiredTriggerClasses(Event()));
-
-  TString centrality(DefaultCentralityName());
-  
-  Float_t fcent(EventCuts()->GetCentrality(Event()));
+//  static Int_t n(0);
+//  AliInfo(Form("EVENT %10d Event()=%p MCEvent()=%p",n,Event(),MCEvent()));
+//  ++n;
+//  
+  AliCodeTimerAuto("",0);
   
-  Double_t cent(-100);
+  Binning(); // insure we have a binning...
   
-  if ( fcent > 0 )
+  //  if ( MCEvent() )
+  //  {
+  TIter nextAnalysis(fSubAnalysisVector);
+  AliAnalysisMuMuBase* analysis;  
+  while ( ( analysis = static_cast<AliAnalysisMuMuBase*>(nextAnalysis()) ) )
   {
-//    for ( std::vector<double>::size_type i = 0 ; i < fCentralityLimits.size() && cent < 0 ; ++i )
-//    {
-//      if ( fcent < fCentralityLimits[i] ) 
-//      {
-//        cent = fCentralityLimits[i];
-//      }
-//    }
+    if ( MCEvent() ) // Set the MC flag for all analysis (prior to call anything from them
+      // (e.g. any trigger class selection that might behave differently for
+      // MC and real trigger classes)
+    {
+      analysis->SetMC();
+    }
+    analysis->SetEvent(Event(),MCEvent()); // Set the new event properties derived in the analysis
   }
+  //  }
   
-  if ( cent > -1 ) 
-  {
-    centrality = CentralityName(cent);
-  }
   
-  int nmu = EAGetNumberOfMuonTracks();
+  TString firedTriggerClasses(AliAnalysisMuonUtility::GetFiredTriggerClasses(Event()));
   
-  EAComputeTrackMasks();
-
   // first loop to count things not associated to a specific trigger
-  TIter nextEventCut(fEventCutNames);
-  TObjString* et;
+  TIter nextEventCutCombination(CutRegistry()->GetCutCombinations(AliAnalysisMuMuCutElement::kEvent));
+  AliAnalysisMuMuCutCombination* cutCombination;
   
-  UInt_t mask = GetEventMask();
-
-//  TString eventType;
-//  eventType.Form("EVENTTYPE%d",event->GetEventType());
-
-  while ( ( et = static_cast<TObjString*>(nextEventCut()) ) )
+  while ( ( cutCombination = static_cast<AliAnalysisMuMuCutCombination*>(nextEventCutCombination())))
   {
-    Bool_t test = ( ( et->GetUniqueID() & mask ) == et->GetUniqueID() );
-    
-    if ( test )
+    if ( cutCombination->Pass(*fInputHandler) )
     {
-      fEventCounters->Count(Form("event:%s/trigger:%s/run:%d", et->String().Data(), "EVERYTHING", fCurrentRunNumber));
+      fEventCounters->Count(Form("event:%s/trigger:%s/centrality:%s/run:%d", cutCombination->GetName(), "EVERYTHING",  "ALL", fCurrentRunNumber));
 
-      if ( HasMC() )
-      {
-        fEventCounters->Count(Form("event:%s/trigger:%s/run:%d", et->String().Data(), "HASMC", fCurrentRunNumber));
-      }
-      
       if ( firedTriggerClasses == "" )
       {
-        fEventCounters->Count(Form("event:%s/trigger:%s/run:%d", et->String().Data(), "EMPTY", fCurrentRunNumber));
-      }
-      
-      if (nmu)
-      {
-        fEventCounters->Count(Form("event:%s/trigger:%s/run:%d", et->String().Data(), "ATLEASTONEMUONTRACK", fCurrentRunNumber));
-      }
-
-      if ( AtLeastOneMuonTrigger(firedTriggerClasses) )
-      {
-        fEventCounters->Count(Form("event:%s/trigger:%s/run:%d", et->String().Data(), "ATLEASTONEMUONTRIGGER", fCurrentRunNumber));
-        if ( AtLeastOneMBTrigger(firedTriggerClasses) )
-        {
-          fEventCounters->Count(Form("event:%s/trigger:%s/run:%d", et->String().Data(), "ATLEASTONEMUONORMBTRIGGER", fCurrentRunNumber));
-        }
-      }
-
-      if ( AtLeastOneMBTrigger(firedTriggerClasses) )
-      {
-        fEventCounters->Count(Form("event:%s/trigger:%s/run:%d", et->String().Data(), "ATLEASTONEMBTRIGGER", fCurrentRunNumber));
+        fEventCounters->Count(Form("event:%s/trigger:%s/centrality:%s/run:%d", cutCombination->GetName(), "EMPTY", "ALL", fCurrentRunNumber));
       }
     }
   }
 
   // second loop to count only the triggers we're interested in
+  TObjArray selectedTriggerClasses;
 
-  TIter next(EventCuts()->GetSelectedTrigClassesInEvent(Event()));
-  TObjString* tname;
+  GetSelectedTrigClassesInEvent(Event(),selectedTriggerClasses);
   
+  TIter next(&selectedTriggerClasses);
+  TObjString* tname;
+//  Bool_t hasSetEventBeenCalled(kFALSE);
+
   while ( ( tname = static_cast<TObjString*>(next()) ) )
   {
-    nextEventCut.Reset();
-    
-    while ( ( et = static_cast<TObjString*>(nextEventCut()) ) )
+    nextEventCutCombination.Reset();
+
+    while ( ( cutCombination = static_cast<AliAnalysisMuMuCutCombination*>(nextEventCutCombination())) )
     {
-      Bool_t test = ( ( et->GetUniqueID() & mask ) == et->GetUniqueID() );
-      
-      if ( test ) 
+      if ( cutCombination->Pass(*fInputHandler) )
       {
-        Fill(et->String().Data(),tname,centrality,fcent);
+//        if (!hasSetEventBeenCalled)
+//        {
+//          TIter nextAnalysis(fSubAnalysisVector);
+//          AliAnalysisMuMuBase* analysis;
+//          
+//          while ( ( analysis = static_cast<AliAnalysisMuMuBase*>(nextAnalysis()) ) )
+//          {
+//            analysis->SetEvent(Event(),MCEvent());
+//          }
+//          hasSetEventBeenCalled = kTRUE;
+//        }
+        Fill(cutCombination->GetName(),tname->String().Data());
       }
     }
   }
-
-  FillMC();
   
   // Post output data.
   PostData(1, fHistogramCollection);
@@ -2306,31 +593,54 @@ void AliAnalysisTaskMuMu::UserExec(Option_t* /*opt*/)
 //_____________________________________________________________________________
 void AliAnalysisTaskMuMu::UserCreateOutputObjects()
 {
-  // Create histograms
-  // Called once
+  /// Create histograms
+  /// Called once
   
   OpenFile(1);
   
-  fHistogramCollection = new AliMergeableCollection("MC");
+  AliInfo(Form("fCutRegistry=%p",fCutRegistry));
   
-  // initialize event counters
+  if ( fCutRegistry )
+  {
+    fCutRegistry->Print();
+  }
+  
+  fHistogramCollection = new AliMergeableCollection("OC");
+
   fEventCounters = new AliCounterCollection("CC");
 
-  TIter nextEventCutName(fEventCutNames);
-  TObjString* str;
+  // initialize event counters
+
   TString eventRubric;
-  while ( ( str = static_cast<TObjString*>(nextEventCutName()) ) )
+  TIter next(CutRegistry()->GetCutCombinations(AliAnalysisMuMuCutElement::kEvent));
+  AliAnalysisMuMuCutCombination* cutCombination;
+  
+  while ( ( cutCombination = static_cast<AliAnalysisMuMuCutCombination*>(next())) )
   {
-    if ( eventRubric.Length() > 0 ) eventRubric += "/"; 
-    eventRubric += str->String();
+    TString cutName = cutCombination->GetName();
+    if ( eventRubric.Length() > 0 ) eventRubric += "/";
+    eventRubric += cutName;
   }
   
   fEventCounters->AddRubric("event", eventRubric.Data());
   
   fEventCounters->AddRubric("trigger", 100);
   
+  fEventCounters->AddRubric("centrality", 100);
+  
   fEventCounters->AddRubric("run", 1000000);
   
+  // Initialize our subtasks, if any...
+  
+  TIter nextAnalysis(fSubAnalysisVector);
+  AliAnalysisMuMuBase* analysis;
+  
+  while ( ( analysis = static_cast<AliAnalysisMuMuBase*>(nextAnalysis()) ) )
+  {
+    analysis->Init(*fEventCounters,*fHistogramCollection,*fBinning,*fCutRegistry);
+  }
+
+  // finally end the counters initialization
   fEventCounters->Init();
   
   // Post output data.
@@ -2338,32 +648,3 @@ void AliAnalysisTaskMuMu::UserCreateOutputObjects()
   PostData(2,fEventCounters);
   PostData(3,fBinning);
 }
-
-//_____________________________________________________________________________
-AliMuonTrackCuts* AliAnalysisTaskMuMu::MuonTrackCuts()
-{
-  if (!fMuonTrackCuts)
-  {
-    fMuonTrackCuts = new AliMuonTrackCuts;
-    
-    fMuonTrackCuts->SetAllowDefaultParams(kTRUE);
-    
-    fMuonTrackCuts->SetFilterMask(AliMuonTrackCuts::kMuEta |
-                                  AliMuonTrackCuts::kMuThetaAbs |
-                                  AliMuonTrackCuts::kMuPdca |
-                                  AliMuonTrackCuts::kMuMatchApt |
-                                  AliMuonTrackCuts::kMuMatchLpt |
-                                  AliMuonTrackCuts::kMuMatchHpt |
-                                  AliMuonTrackCuts::kMuTrackChiSquare);
-    
-  }
-
-  return fMuonTrackCuts;
-}
-
-//_____________________________________________________________________________
-void AliAnalysisTaskMuMu::SetMuonTrackCuts(const AliMuonTrackCuts& trackCuts)
-{
-  delete fMuonTrackCuts;
-  fMuonTrackCuts = static_cast<AliMuonTrackCuts*>(trackCuts.Clone());
-}
index 861b276011effe68bd92fe15fed710c7f9230d5a..a42100ebdd0ad4fed759ce84a3e90171a4cf10c0 100644 (file)
@@ -1,24 +1,34 @@
 #ifndef ALIANALYSISTASKMUMU_H
 #define ALIANALYSISTASKMUMU_H
 
-//
-// AliAnalysisTaskMuMu : base class for mu pairs analysis 
-// Contains common things for ESD-based and AOD-based analysis
-//
-// author: L. Aphecetche (Subatech)
-//
+/**
+ * \defgroup pwg-muon-mumu pwg-muon-mumu
+ *
+ * \brief Small sub-framework to analyse muon pairs and more...
+ *
+ * Started as a simple invariant mass analysis and grew into a bit more general thing...
+ *
+ * Can now compute the charged particle multiplicy (from SPD tracklets only) in order
+ * to be able to correlate it with e.g. J/psi or single mu.
+ */
+
+/**
+ * \ingroup pwg-muon-mumu
+ *
+ * \class AliAnalysisTaskMuMu 
+ *
+ * \brief Steering class for mu pairs analysis (and more...)
+ *
+ * This class acts as a small sub-framework to steer various sub-analysis which 
+ * share the same MergeableCollection and the same CounterCollection.
+ *
+ *  \author: L. Aphecetche (Subatech)
+ */
 
 #ifndef ALIANALYSISTASKSE_H
 #  include "AliAnalysisTaskSE.h"
 #endif
 
-#include <set>
-#include <vector>
-
-#ifndef ROOT_TArrayI
-#  include "TArrayI.h"
-#endif
-
 #ifndef ROOT_TMath
 #  include "TMath.h"
 #endif
 class AliAnalysisMuMuBinning;
 class AliCounterCollection;
 class AliMergeableCollection;
-class AliMuonTrackCuts;
-class AliMuonEventCuts;
 class AliVParticle;
-class TArrayF;
 class TList;
 class TObjArray;
+class AliAnalysisMuMuBase;
+class AliAnalysisMuMuCutRegistry;
 
 class AliAnalysisTaskMuMu : public AliAnalysisTaskSE
 {
 public:
-  
-  enum ETrackCut
-  {
-    kAll=BIT(0),
-    kPt1=BIT(1),
-    kRabs=BIT(2),
-    kMatched=BIT(3),
-    kMatchedLow=BIT(4),
-    kMatchedHigh=BIT(5),
-    kEta=BIT(6),
-    kChi2=BIT(7),
-    kDCA=BIT(8),
-    kPairRapidity=BIT(9),
-    kBelowPt=BIT(10),
-    kPt1dot2=BIT(11),
-    kPt1dot5=BIT(12),
-    kPt2=BIT(13),
-    kDeg23=BIT(14),
-    kDeg310=BIT(15),
-    kP10=BIT(16),
-    kChi2MatchTrigger=BIT(17)
-  };
-  
-  enum EEventCut
-  {
-    kEventAll=BIT(0),
-    kEventPS=BIT(1),
-    kEventTVX=BIT(2),
-    kEventV0AND=BIT(3),
-    kEventV0UP=BIT(4),
-    kEventZSPD=BIT(5),
-    kEventZ7=BIT(7),    
-    kEventNOTZEROPILEUP=BIT(8),
-    kEventOFFLINEMUL1=BIT(9),
-    kEventZ10=BIT(10),
-    kEventOFFLINEMUL2=BIT(11),
-    kEventSD2=BIT(16),
-    kEventMSL=BIT(17),
-    kEventREJECTED=BIT(18),
-    kEventPSTS=BIT(19)
-  };
-  
   AliAnalysisTaskMuMu();
-  AliAnalysisTaskMuMu(Bool_t fromESD, TList* triggerClassesToConsider, const char* beamYear=0x0, TArrayF* centralities=0x0);
-  AliAnalysisTaskMuMu(Bool_t fromESD, const char* beamYear, TArrayF* centralities=0x0);
   virtual ~AliAnalysisTaskMuMu();
 
-  void AddBin(const char* particle, const char* type,
-              Double_t xmin, Double_t xmax,
-              Double_t ymin,
-              Double_t ymax,
-              const char* flavour="");
-
-  void AddBin(const char* particle, const char* type,
-              Double_t xmin, Double_t xmax,
-              const char* flavour="") { AddBin(particle,type,xmin,xmax,TMath::Limits<Double_t>::Max(),TMath::Limits<Double_t>::Max(),flavour); }
-  
-  void CreateMesh(const char* particle, const char* type1, const char* type2, const char* flavour="", Bool_t remove12=kFALSE);
-  
-  virtual void AddEventCut(const char* cutName, UInt_t mask);
-  
-  virtual void AddPairCut(const char* cutName, UInt_t maskForOneOrBothTrack, UInt_t maskForTrackPair=0);
+  AliAnalysisMuMuCutRegistry* CutRegistry() const;
   
-  virtual void AddSingleCut(const char* cutName, UInt_t mask);
+  AliAnalysisMuMuBinning* Binning() const;
+
+  void AdoptSubAnalysis(AliAnalysisMuMuBase* analysis);
   
   virtual void DisableHistograms(const char* pattern="*");
-  
-  AliMuonEventCuts* EventCuts() const;
+
+  void SetBeamYear(const char* beamYear) { fBeamYear = beamYear; }
   
   virtual void FinishTaskOutput();
   
-  Bool_t IsPP() const;
-
-  Bool_t IsHistogrammingDisabled() const;
-
-  virtual Bool_t IsHistogramDisabled(const char* hname) const;
-
   virtual void NotifyRun();
   
   virtual void Print(Option_t* opt="") const;
   
-  virtual void ShouldSeparatePlusAndMinus(Bool_t value) { fShouldSeparatePlusAndMinus = value; }
-  
-  virtual Bool_t ShouldSeparatePlusAndMinus() const { return fShouldSeparatePlusAndMinus; }
-  
   virtual void Terminate(Option_t *);
   
-  void UseBackgroundTriggers(Bool_t value=kTRUE) { fUseBackgroundTriggers = value; }
-
   void UserCreateOutputObjects();
 
   virtual void UserExec(Option_t* opt);
   
-  AliMuonTrackCuts* MuonTrackCuts();
-  
-  void SetMuonTrackCuts(const AliMuonTrackCuts& trackCuts);
-  
-  class PairCut : public TObject {
-  public:
-    PairCut(const char* name="", UInt_t maskForOneOrBothTrack=0, UInt_t maskForTrackPair=0)
-    : TObject(), fName("p"),fMaskForOneOrBothTrack(maskForOneOrBothTrack),fMaskForTrackPair(maskForTrackPair)
-    {
-      fName += name;
-    }
-    const char* GetName() const { return fName.Data(); }
-    UInt_t MaskForOneOrBothTrack() const { return fMaskForOneOrBothTrack; }
-    UInt_t MaskForTrackPair() const { return fMaskForTrackPair; }
-    void Print(Option_t* opt="") const;
-    
-  private:
-    TString fName; // name of the cut
-    UInt_t fMaskForOneOrBothTrack; // mask for the cut that at least of the two tracks should match
-    UInt_t fMaskForTrackPair; // mask for the cut both tracks should match
-    
-    ClassDef(AliAnalysisTaskMuMu::PairCut,1); // a simple wrapper for two masks
-  };
-  
-  
 private:
-
-  virtual void FillHistos(const char* physics, const char* triggerClassName, const char* centrality);
-
-  void FillHistosForTrack(const char* physics, const char* triggerClassName, const char* centrality, const AliVParticle& track, Int_t trackIndex);
-
-  void FillHistogramCollection(const char* physics, const char* triggerClassName);
   
-  void FillEventHistos(const char* physics, const char* triggerClassName,
-                       const char* centrality);
-  
-  void Fill(const char* eventtype, TObjString* tname, const char* centrality, float fcent);
-
-  void FillMC();
-
-  void AssertHistogramCollection(const char* physics, const char* triggerClassName);
-
-  void BeautifyHistos();
-
-  void CreateMinvHistograms(const char* physics, const char* triggerClassName);
-
-   void CreateHisto(TObjArray* array,
-                   const char* physics,
-                   const char* triggerClassName,
-                   const char* hname, const char* htitle, 
-                   Int_t nbinsx, Double_t xmin, Double_t xmax,
-                   Int_t nbinsy, Double_t ymin, Double_t ymax) const;
-  
-  void CreateEventHisto(const char* physics,
+  void CreateTrackHisto(const char* eventSelection,
                         const char* triggerClassName,
-                        const char* hname, const char* htitle, 
+                        const char* hname, const char* htitle,
                         Int_t nbinsx, Double_t xmin, Double_t xmax,
-                        Int_t nbinsy=0, Double_t ymin=0.0, Double_t ymax=0.0) const;
+                        Int_t nbinsy=-1, Double_t ymin=0.0, Double_t ymax=0.0,
+                        Bool_t separatePlusAndMinus=kFALSE) const;
   
-  void CreateSingleHisto(const char* physics,
-                         const char* triggerClassName,
-                         const char* hname, const char* htitle, 
-                         Int_t nbinsx, Double_t xmin, Double_t xmax,
-                         Int_t nbinsy=0, Double_t ymin=0.0, Double_t ymax=0.0,
-                         Bool_t separatePlusAndMinus=kFALSE) const;
-
-  void CreatePairHisto(const char* physics,
+  void CreatePairHisto(const char* eventSelection,
                        const char* triggerClassName,
-                       const char* hname, const char* htitle, 
+                       const char* hname, const char* htitle,
                        Int_t nbinsx, Double_t xmin, Double_t xmax,
-                       Int_t nbinsy=0, Double_t ymin=0.0, Double_t ymax=0.0) const;
+                       Int_t nbinsy=-1, Double_t ymin=0.0, Double_t ymax=0.0) const;
   
-   void DefineCentralityClasses(TArrayF* centralities);
-  
-  UInt_t GetTriggerInputBitMaskFromInputName(const char* inputName) const;
-
-  TH1* Histo(const char* physics, const char* histoname);
-  
-  TH1* Histo(const char* physics, const char* triggerClassName, const char* histoname);
-  
-  TH1* Histo(const char* physics, const char* triggerClassName, const char* what, const char* histoname);
-
-  TH1* Histo(const char* physics, const char* triggerClassName, const char* cent, const char* what, const char* histoname);
+  const char* DefaultCentralityName() const;
 
-  Double_t MuonMass2() const;
+  AliVEvent* Event() const;
   
-  const char* DefaultCentralityName() const;
+  void FillHistos(const char* eventSelection, const char* triggerClassName, const char* centrality);
   
-  const char* CentralityName(Double_t centrality) const;
+  void Fill(const char* eventSelection, const char* triggerClassName);
   
-  Bool_t HasMC() const { return fHasMC; }
+  void FillMC();
   
-  void ComputeTrackMask(const AliVParticle& track, Int_t trackIndex);
-
-  UInt_t GetEventMask() const;
+  void GetSelectedTrigClassesInEvent(const AliVEvent* event, TObjArray& array);
 
-  void GetPairMask(const AliVParticle& t1, const AliVParticle& t2,
-                   Int_t trackIndex1, Int_t trackIndex2,
-                   UInt_t& mask1, UInt_t& mask2,
-                   UInt_t& mask12) const;
+  Bool_t IsHistogrammingDisabled() const;
   
-  UInt_t GetTrackMask(Int_t trackIndex) const;
+  virtual Bool_t IsHistogramDisabled(const char* hname) const;
   
-  Double_t GetTrackTheta(const AliVParticle& particle) const;
+  Bool_t IsPP() const;
   
-  Bool_t PairRapidityCut(const AliVParticle& t1, const AliVParticle& t2) const;
-
-  /* methods prefixed with EA should really not exist at all. They are there
-   only because the some of our base interfaces are shamelessly incomplete or
-   inadequate...
-   */
+private:
   
-  void EAComputeTrackMasks();
-
-  Int_t EAGetNumberOfMuonTracks() const;
-
-  Int_t EAGetNumberOfSelectMuonTracks() const;
-
-  Double_t EAGetTrackDCA(const AliVParticle& particle) const;
-
-  Bool_t EAGetTZEROFlags(Bool_t& backgroundFlag, Bool_t& pileupFlag, Bool_t& satelliteFlag) const;
-
-  Bool_t AtLeastOneMuonTrigger(const TString& firedTriggerClasses) const;
-
-  Bool_t AtLeastOneEmcalTrigger(const TString& firedTriggerClasses) const;
-
-  Bool_t AtLeastOneMBTrigger(const TString& firedTriggerClasses) const;
-
-  Bool_t TriggerSBACECondition(const TString& triggerName) const;
+  AliAnalysisTaskMuMu(const AliAnalysisTaskMuMu&); // not implemented (on purpose)
+  AliAnalysisTaskMuMu& operator=(const AliAnalysisTaskMuMu&); // not implemented (on purpose)
 
-  void DefineDefaultBinning();
-  
-  AliVEvent* Event() const;
-  
 private:
   
   AliMergeableCollection* fHistogramCollection; //! collection of histograms
   AliCounterCollection* fEventCounters; //! event counters
-  
-  AliMuonTrackCuts* fMuonTrackCuts; //! common cuts for muon tracks (from Diego)
-  TArrayI fPrecomputedTrackMasks; //! track masks
+  mutable AliAnalysisMuMuBinning* fBinning; // binning for particles
 
-  Bool_t fIsFromESD; // whether we read from ESD or AOD
-  Bool_t fShouldSeparatePlusAndMinus; // whether or not to histogram mu+ and mu- separately
-  TString fBeamYear; // beam and year
-  
-  TObjArray* fSingleTrackCutNames; // cut on single tracks (array of TObjString)
-  TObjArray* fPairTrackCutNames; // cut on track pairs (array of TObjString)
-  TObjArray* fCentralityNames; // names to create histograms
-  TObjArray* fEventCutNames; // cut at event level (array of TObjString)
-  
-  Bool_t fUseBackgroundTriggers; // whether or not we should use the ACE triggers
-  
-  std::map<std::string,int> fTriggerInputBitMap; // map of L0 input name to bit
-  
-  AliAnalysisMuMuBinning* fBinning; // binning for particles
+  mutable AliAnalysisMuMuCutRegistry* fCutRegistry; // cuts (owner)
   
-  TList* fHistogramToDisable; // list of regexp of histo name to disable
-
-  TObjArray* fBinArray; //!  cache for the bins
-  Bool_t fHasMC; //! current event has MC information
+  TString fBeamYear; // beam and year
   
-  mutable AliMuonEventCuts* fEventCuts; // common cuts for muon events (from Diego)
+  TList* fHistogramToDisable; // list of regexp of histo name(s) to disable
   
-  AliAnalysisTaskMuMu(const AliAnalysisTaskMuMu&); // not implemented (on purpose)
-  AliAnalysisTaskMuMu& operator=(const AliAnalysisTaskMuMu&); // not implemented (on purpose)
+  TObjArray* fSubAnalysisVector; // list of companion analysis
   
-  ClassDef(AliAnalysisTaskMuMu,24) // a class to analyse muon pairs (and single also ;-) )
+  ClassDef(AliAnalysisTaskMuMu,26) // a class to analyse muon pairs (and single also ;-) )
 };
 
 #endif
index 4577b94a5b0b7acecf4e43022a0a70d4916025fa..3daace6c25c03ab4c2b45fefe320439470b7c7e3 100644 (file)
@@ -413,6 +413,13 @@ TH1*
 AliMergeableCollection::Histo(const char* identifier,
                               const char* objectName) const
 {
+  /// Get histogram key1/key2/.../objectName:action
+  /// action is used for 2D histograms :
+  /// might be px for projection along x-axis
+  /// py for projection along y-axis
+  /// pfx for profile along x-axis
+  /// pfy for profile along y-axis
+  
   TObject* o = GetObject(identifier,objectName);
   
   TObjArray* arr = TString(objectName).Tokenize(":");
@@ -469,6 +476,71 @@ AliMergeableCollection::HistoWithAction(const char* identifier, TObject* o, cons
   return static_cast<TH1*>(o);
 }
 
+//_____________________________________________________________________________
+TH2*
+AliMergeableCollection::H2(const char* fullIdentifier) const
+{
+  /// Short-cut method to grab a 2D histogram
+  /// Will return 0x0 if the object if not a TH2xxx
+
+  TObject* o = GetObject(fullIdentifier);
+  
+  if (o->IsA()->InheritsFrom(TH2::Class()))
+  {
+    return static_cast<TH2*>(o);
+  }
+  return 0x0;
+}
+
+//_____________________________________________________________________________
+TH2*
+AliMergeableCollection::H2(const char* identifier,
+                           const char* objectName) const
+{
+  /// Short-cut method to grab a 2D histogram
+  /// Will return 0x0 if the object if not a TH2xxx
+  
+  TObject* o = GetObject(identifier,objectName);
+  
+  if (o->IsA()->InheritsFrom(TH2::Class()))
+  {
+    return static_cast<TH2*>(o);
+  }
+  return 0x0;
+}
+
+//_____________________________________________________________________________
+TProfile*
+AliMergeableCollection::Prof(const char* fullIdentifier) const
+{
+  /// Short-cut method to grab a TProfile histogram
+  /// Will return 0x0 if the object if not a TProfile
+  
+  TObject* o = GetObject(fullIdentifier);
+  
+  if (o->IsA()->InheritsFrom(TProfile::Class()))
+  {
+    return static_cast<TProfile*>(o);
+  }
+  return 0x0;
+}
+
+//_____________________________________________________________________________
+TProfile*
+AliMergeableCollection::Prof(const char* identifier,
+                           const char* objectName) const
+{
+  /// Short-cut method to grab a TProfile histogram
+  /// Will return 0x0 if the object if not a TProfile
+  
+  TObject* o = GetObject(identifier,objectName);
+  
+  if (o->IsA()->InheritsFrom(TProfile::Class()))
+  {
+    return static_cast<TProfile*>(o);
+  }
+  return 0x0;
+}
 
 //_____________________________________________________________________________
 TObject* 
@@ -492,7 +564,6 @@ AliMergeableCollection::GetObject(const char* fullIdentifier) const
   }
 }
 
-
 //_____________________________________________________________________________
 TObject* 
 AliMergeableCollection::GetObject(const char* identifier, 
@@ -632,12 +703,7 @@ Bool_t AliMergeableCollection::InternalAdopt(const char* identifier, TObject* ob
   if ( obj->IsA()->InheritsFrom(TH1::Class()) ) (static_cast<TH1*> ( obj ))->SetDirectory(0);  
   
   hlist->AddLast(obj);
-  
-  // invalidate the TFolder structure, if any, so it will
-  // be recomputed next time Browse() is called
-  delete fFolders;
-  fFolders = 0x0;
-  
+    
   return kTRUE;
   
 }
@@ -932,8 +998,8 @@ AliMergeableCollection::Print(Option_t* option) const
   /// output to only those objects matching a given classname pattern
   ///
   
-  cout << Form("AliMergeableCollection(%s,%s) : %d keys and %d objects",
-               GetName(),GetTitle(),
+  cout << Form("AliMergeableCollection(%s,%s)[%p] : %d keys and %d objects",
+               GetName(),GetTitle(),this,
                NumberOfKeys(), NumberOfObjects()) << endl;
   
   if (!strlen(option)) return;
@@ -960,7 +1026,7 @@ AliMergeableCollection::Print(Option_t* option) const
   
   TObjArray* identifiers = SortAllIdentifiers();
   
-  printf("identifiers entries %i\n", identifiers->GetEntries());
+  std::cout << Form("Number of identifiers %d", identifiers->GetEntries()) << std::endl;
     
   TIter nextIdentifier(identifiers);
   
@@ -1097,7 +1163,8 @@ AliMergeableCollection::EstimateSize(Bool_t show) const
   while ( ( obj = next() ) )
   {
     UInt_t thissize=0;
-    if ( obj->IsA()->InheritsFrom(TH1::Class()) ) {
+    if ( obj->IsA()->InheritsFrom(TH1::Class()) || obj->IsA()->InheritsFrom(TProfile::Class()) )
+    {
       TH1* histo = static_cast<TH1*> (obj);
       Int_t nbins = (histo->GetNbinsX()+2);
     
@@ -1122,6 +1189,7 @@ AliMergeableCollection::EstimateSize(Bool_t show) const
       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 (cname=="TProfile") nbytesPerBin = sizeof(Double_t);
         
       if (!nbytesPerBin)
       {
@@ -1134,6 +1202,14 @@ AliMergeableCollection::EstimateSize(Bool_t show) const
       + strlen(histo->GetTitle());
       
       if ( hasErrors) thissize += nbins*8;
+      
+      if ( obj->IsA()->InheritsFrom(TProfile::Class()) )
+      {
+        TProfile* prof = static_cast<TProfile*>(obj);
+        TArrayD* d = prof->GetBinSumw2();
+        thissize += d->GetSize()*8*2; // 2 TArrayD
+        thissize += sizeof(prof) - sizeof(histo);
+      }
     }
     else if ( obj->IsA()->InheritsFrom(THnSparse::Class()) ) {
       THnSparse* sparse = static_cast<THnSparse*> (obj);
index b8a04dea1e53c25bc5dd9af9d36161e287fbdde5..4da06f58efb7cae0c99306cc5301dcc079d7b587 100644 (file)
@@ -37,6 +37,8 @@
 class TMap;
 class AliMergeableCollectionIterator;
 class TH1;
+class TH2;
+class TProfile;
 
 class AliMergeableCollection : public TFolder
 {
@@ -74,6 +76,15 @@ public:
   TH1* Histo(const char* fullIdentifier) const;
   TH1* Histo(const char* identifier, const char* objectName) const;
 
+  TH1* H1(const char* fullIdentifier) const { return Histo(fullIdentifier); }
+  TH1* H1(const char* identifier, const char* objectName) const { return Histo(identifier,objectName); }
+
+  TH2* H2(const char* fullIdentifier) const;
+  TH2* H2(const char* identifier, const char* objectName) const;
+
+  TProfile* Prof(const char* fullIdentifier) const;
+  TProfile* Prof(const char* identifier, const char* objectName) const;
+
   virtual TIterator* CreateIterator(Bool_t dir = kIterForward) const;
   
   virtual TList* CreateListOfKeys(Int_t index) const;
@@ -143,7 +154,7 @@ private:
   mutable Int_t fMapVersion; /// internal version of map (to avoid custom streamer...)
   mutable std::map<std::string,int> fMessages; //! log messages
   
-  ClassDef(AliMergeableCollection,3) /// A collection of mergeable objects
+  ClassDef(AliMergeableCollection,4) /// A collection of mergeable objects
 };
 
 class AliMergeableCollectionIterator : public TIterator
index d9fcc033a688ef320063e764c99e7f4bd856f37e..7859ec60514bb6cb6f135dd629902d911098ff32 100644 (file)
@@ -439,6 +439,26 @@ void AliMuonEventCuts::SetTrigClassLevels ( TString pattern )
   delete fullList;
 }
 
+//________________________________________________________________________
+UInt_t AliMuonEventCuts::GetTriggerInputBitMaskFromInputName(const char* inputName) const
+{
+  // Get trigger input bit from its name
+  
+  if (!fTrigInputsMap)
+  {
+    AliError("No Inputs Map available");
+    return TMath::Limits<UInt_t>::Max();
+  }
+  
+  TObjString* s = static_cast<TObjString*>(fTrigInputsMap->FindObject(inputName));
+  if (!s)
+  {
+    AliError(Form("Did not find input %s",inputName));
+    return TMath::Limits<UInt_t>::Max();    
+  }
+  return s->GetUniqueID();
+}
+
 //________________________________________________________________________
 TArrayI AliMuonEventCuts::GetTrigClassPtCutLevel ( const TString trigClassName ) const
 {
@@ -546,6 +566,20 @@ void AliMuonEventCuts::SetDefaultTrigInputsMap ()
   SetTrigInputsMap(trigInputsMap);
 }
 
+//________________________________________________________________________
+const TObjArray*
+AliMuonEventCuts::GetSelectedTrigClassesInEvent(const TString& firedTriggerClasses,
+                                                UInt_t l0Inputs, UInt_t l1Inputs,
+                                                UInt_t l2Inputs)
+{
+  /// Return the selected trigger classes in the fired trigger classes
+  /// give also the L0,L1,L2 input bit masks
+  
+  BuildTriggerClasses(firedTriggerClasses,l0Inputs,l1Inputs,l2Inputs);
+
+  return fSelectedTrigClassesInEvent;
+}
+
 //________________________________________________________________________
 const TObjArray* AliMuonEventCuts::GetSelectedTrigClassesInEvent( const AliVEvent* event )
 {
index fdc048156e6582be98bd836329cb1c2d8cbc81c5..c2843baf21b459b10e46dceb543ac6abaadd0e94 100644 (file)
@@ -47,8 +47,11 @@ class AliMuonEventCuts : public AliAnalysisCuts
   /// Get trigger classes found in run
   TList* GetAllSelectedTrigClasses () const { return fAllSelectedTrigClasses; }
   const TObjArray* GetSelectedTrigClassesInEvent ( const AliVEvent* event );
+  const TObjArray* GetSelectedTrigClassesInEvent(const TString& firedTriggerClasses,
+                                                 UInt_t l0Inputs, UInt_t l1Inputs, UInt_t l2Inputs);
+
+  UInt_t GetTriggerInputBitMaskFromInputName(const char* inputName) const;
 
-  
   // Handle centrality
   void SetCentralityClasses(Int_t nCentralityBins = -1, Double_t* centralityBins = 0x0);
   /// Get centrality classes
diff --git a/PWG/muon/Doxyfile b/PWG/muon/Doxyfile
new file mode 100644 (file)
index 0000000..efdb7ec
--- /dev/null
@@ -0,0 +1,1938 @@
+# Doxyfile 1.8.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed
+# in front of the TAG it is preceding .
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME           = "PWG/muon"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = "PWG/muon"
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "Classes relevant to muon analyses"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = $(ALICE_INSTALL)
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian,
+# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic,
+# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip. Note that you specify absolute paths here, but also
+# relative paths, which will be relative from the directory where doxygen is
+# started.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = NO
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension,
+# and language is one of the parsers supported by doxygen: IDL, Java,
+# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
+# C++. For instance to make doxygen treat .inc files as Fortran files (default
+# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
+# that for custom extensions you also need to set FILE_PATTERNS otherwise the
+# files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES (the
+# default) will make doxygen replace the get and set methods by a property in
+# the documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields or simple typedef fields will be shown
+# inline in the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO (the default), structs, classes, and unions are shown on a separate
+# page (for HTML and Man pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can
+# be an expensive process and often the same symbol appear multiple times in
+# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too
+# small doxygen will become slower. If the cache is too large, memory is wasted.
+# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid
+# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536
+# symbols.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if section-label ... \endif
+# and \cond section-label ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            = DoxygenLayout.xml
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path. Do not use
+# file names with spaces, bibtex cannot handle them.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+# for the moment we are very specific (instead of just giving the full PWG/muon directory
+# as input ...) as many classes have no doxygen comments at all
+
+INPUT                  = \
+AliAnalysisMuMuBase.cxx \
+AliAnalysisMuMuBase.h \
+AliAnalysisMuMuBinning.cxx \
+AliAnalysisMuMuBinning.h \
+AliAnalysisMuMuCutCombination.cxx \
+AliAnalysisMuMuCutCombination.h \
+AliAnalysisMuMuCutElement.cxx \
+AliAnalysisMuMuCutElement.h \
+AliAnalysisMuMuCutRegistry.cxx \
+AliAnalysisMuMuCutRegistry.h \
+AliAnalysisMuMuEventCutter.cxx \
+AliAnalysisMuMuEventCutter.h \
+AliAnalysisMuMuGlobal.cxx \
+AliAnalysisMuMuGlobal.h \
+AliAnalysisMuMuMinv.cxx \
+AliAnalysisMuMuMinv.h \
+AliAnalysisMuMuNch.cxx \
+AliAnalysisMuMuNch.h \
+AliAnalysisMuMuSingle.cxx \
+AliAnalysisMuMuSingle.h \
+AliAnalysisMuonUtility.cxx \
+AliAnalysisMuonUtility.h \
+AliAnalysisTaskMuMu.cxx \
+AliAnalysisTaskMuMu.h \
+AliMergeableCollection.cxx \
+AliMergeableCollection.h \
+AliMuonEventCuts.cxx \
+AliMuonEventCuts.h \
+AliMuonTrackCuts.cxx \
+AliMuonTrackCuts.h
+
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          = 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = "G__*"
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             = .
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be ignored.
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C, C++ and Fortran comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = NO
+
+# If CLANG_ASSISTED_PARSING is set to YES, then doxygen will use the clang parser
+# for more acurate parsing at the cost of reduced performance. This can be
+# particularly helpful with template rich C++ code for which doxygen's built-in
+# parser lacks the necessairy type information.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified at INPUT and INCLUDE_PATH.
+
+CLANG_OPTIONS          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 2
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = Ali
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+#  for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If left blank doxygen will
+# generate a default style sheet. Note that it is recommended to use
+# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
+# tag will in the future become obsolete.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
+# user-defined cascading style sheet that is included after the standard
+# style sheets created by doxygen. Using this option one can overrule
+# certain style aspects. This is preferred over using HTML_STYLESHEET
+# since it does not replace the standard style sheet and is therefor more
+# robust against future updates. Doxygen will copy the style sheet file to
+# the output directory.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
+# entries shown in the various tree structured indices initially; the user
+# can expand and collapse entries dynamically later on. Doxygen will expand
+# the tree to such a level that at most the specified number of entries are
+# visible (unless a fully collapsed tree already exceeds this amount).
+# So setting the number of entries 1 will produce a full collapsed tree by
+# default. 0 is a special value representing an infinite number of entries
+# and will result in a full expanded tree by default.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
+# identify the documentation publisher. This should be a reverse domain-name
+# style string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+#  will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
+# SVG. The default value is HTML-CSS, which is slower, but has the best
+# compatibility.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax.
+# However, it is strongly recommended to install a local
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript
+# pieces of code that will be used on startup of the MathJax code.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript.
+# There are two flavours of web server based search depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools.
+# See the manual for details.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain
+# the search results. Doxygen ships with an example indexer (doxyindexer) and
+# search engine (doxysearch.cgi) which are based on the open source search
+# engine library Xapian. See the manual for configuration details.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will returned the search results when EXTERNAL_SEARCH is enabled.
+# Doxygen ships with an example search engine (doxysearch) which is based on
+# the open source search engine library Xapian. See the manual for configuration
+# details.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id
+# of to a relative location where the documentation can be found.
+# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ...
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4 will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images
+# or other source files which should be copied to the LaTeX output directory.
+# Note that the files will be copied as-is; there are no commands or markers
+# available.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files
+# that can be used to generate PDF.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it. If left blank docbook will be used as the default path.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
+# doxygen is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed
+# in the related pages index. If set to NO, only the current project's
+# pages will be listed.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = NO
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# manageable. Set this to 0 for no limit. Note that the threshold may be
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG        = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/PWG/muon/DoxygenLayout.xml b/PWG/muon/DoxygenLayout.xml
new file mode 100644 (file)
index 0000000..531dfca
--- /dev/null
@@ -0,0 +1,196 @@
+<doxygenlayout version="1.0">
+  <!-- Generated by doxygen 1.8.4 -->
+  <!-- Navigation index tabs for HTML output -->
+  <navindex>
+    <tab type="mainpage" visible="yes" title=""/>
+    <tab type="pages" visible="yes" title="" intro=""/>
+    <tab type="modules" visible="yes" title="" intro=""/>
+    <tab type="namespaces" visible="yes" title="">
+      <tab type="namespacelist" visible="yes" title="" intro=""/>
+      <tab type="namespacemembers" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="classes" visible="yes" title="">
+      <tab type="classlist" visible="yes" title="" intro=""/>
+      <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/> 
+      <tab type="hierarchy" visible="yes" title="" intro=""/>
+      <tab type="classmembers" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="files" visible="yes" title="">
+      <tab type="filelist" visible="yes" title="" intro=""/>
+      <tab type="globals" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="examples" visible="yes" title="" intro=""/>
+    <tab type="user" url="http://aliweb.cern.ch/Offline/" title="Alice Offline Pages"/>
+    <tab type="user" url="http://git.cern.ch/pubweb/AliRoot.git/tree" title="AliRoot git web"/>
+  </navindex>
+
+  <!-- Layout definition for a class page -->
+  <class>
+    <briefdescription visible="yes"/>
+    <includes visible="$SHOW_INCLUDE_FILES"/>
+    <inheritancegraph visible="$CLASS_GRAPH"/>
+    <collaborationgraph visible="$COLLABORATION_GRAPH"/>
+    <detaileddescription title=""/>
+    <memberdecl>
+      <nestedclasses visible="yes" title=""/>
+      <publictypes title=""/>
+      <services title=""/>
+      <interfaces title=""/>
+      <publicslots title=""/>
+      <signals title=""/>
+      <publicmethods title=""/>
+      <publicstaticmethods title=""/>
+      <publicattributes title=""/>
+      <publicstaticattributes title=""/>
+      <protectedtypes title=""/>
+      <protectedslots title=""/>
+      <protectedmethods title=""/>
+      <protectedstaticmethods title=""/>
+      <protectedattributes title=""/>
+      <protectedstaticattributes title=""/>
+      <packagetypes title=""/>
+      <packagemethods title=""/>
+      <packagestaticmethods title=""/>
+      <packageattributes title=""/>
+      <packagestaticattributes title=""/>
+      <properties title=""/>
+      <events title=""/>
+      <privatetypes title=""/>
+      <privateslots title=""/>
+      <privatemethods title=""/>
+      <privatestaticmethods title=""/>
+      <privateattributes title=""/>
+      <privatestaticattributes title=""/>
+      <friends title=""/>
+      <related title="" subtitle=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <memberdef>
+      <inlineclasses title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <services title=""/>
+      <interfaces title=""/>
+      <constructors title=""/>
+      <functions title=""/>
+      <related title=""/>
+      <variables title=""/>
+      <properties title=""/>
+      <events title=""/>
+    </memberdef>
+    <allmemberslink visible="yes"/>
+    <usedfiles visible="$SHOW_USED_FILES"/>
+    <authorsection visible="yes"/>
+  </class>
+
+  <!-- Layout definition for a namespace page -->
+  <namespace>
+    <briefdescription visible="yes"/>
+    <memberdecl>
+      <nestednamespaces visible="yes" title=""/>
+      <constantgroups visible="yes" title=""/>
+      <classes visible="yes" title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <inlineclasses title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+    </memberdef>
+    <authorsection visible="yes"/>
+  </namespace>
+
+  <!-- Layout definition for a file page -->
+  <file>
+    <briefdescription visible="yes"/>
+    <includes visible="$SHOW_INCLUDE_FILES"/>
+    <includegraph visible="$INCLUDE_GRAPH"/>
+    <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
+    <sourcelink visible="yes"/>
+    <memberdecl>
+      <classes visible="yes" title=""/>
+      <namespaces visible="yes" title=""/>
+      <constantgroups visible="yes" title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <inlineclasses title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+    </memberdef>
+    <authorsection/>
+  </file>
+
+  <!-- Layout definition for a group page -->
+  <group>
+    <briefdescription visible="yes"/>
+    <groupgraph visible="$GROUP_GRAPHS"/>
+    <memberdecl>
+      <nestedgroups visible="yes" title=""/>
+      <dirs visible="yes" title=""/>
+      <files visible="yes" title=""/>
+      <namespaces visible="yes" title=""/>
+      <classes visible="yes" title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <enumvalues title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <signals title=""/>
+      <publicslots title=""/>
+      <protectedslots title=""/>
+      <privateslots title=""/>
+      <events title=""/>
+      <properties title=""/>
+      <friends title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <pagedocs/>
+      <inlineclasses title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <enumvalues title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <signals title=""/>
+      <publicslots title=""/>
+      <protectedslots title=""/>
+      <privateslots title=""/>
+      <events title=""/>
+      <properties title=""/>
+      <friends title=""/>
+    </memberdef>
+    <authorsection visible="yes"/>
+  </group>
+
+  <!-- Layout definition for a directory page -->
+  <directory>
+    <briefdescription visible="yes"/>
+    <directorygraph visible="yes"/>
+    <memberdecl>
+      <dirs visible="yes"/>
+      <files visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+  </directory>
+</doxygenlayout>
diff --git a/PWG/muon/runMuMu.C b/PWG/muon/runMuMu.C
new file mode 100755 (executable)
index 0000000..a7f2dd9
--- /dev/null
@@ -0,0 +1,381 @@
+///
+/// Example macro to run the AliAnalysisTaskMuMu task
+///
+/// \author L. Aphecetche
+///
+
+//______________________________________________________________________________
+void LoadLocalLibs(Bool_t localAnalysis=kTRUE)
+{
+  gSystem->Load("libVMC");
+  gSystem->Load("libMinuit");
+  gSystem->Load("libTree");
+  gSystem->Load("libProofPlayer");
+  gSystem->Load("libXMLParser");
+  gSystem->Load("libSTEERBase");
+  gSystem->Load("libESD");
+  gSystem->Load("libAOD");
+  gSystem->Load("libANALYSIS");
+  gSystem->Load("libANALYSISalice");
+
+  if (!localAnalysis)
+  {
+    gSystem->Load("libCORRFW");
+  }
+  else
+  {
+       gROOT->LoadMacro("AliOADBMuonTrackCutsParam.cxx+g");
+       gROOT->LoadMacro("AliAnalysisMuonUtility.cxx+g");
+       gROOT->LoadMacro("AliMuonTrackCuts.cxx+g");
+       gROOT->LoadMacro("AliMergeableCollection.cxx+g");
+       gROOT->LoadMacro("AliAnalysisMuMuBinning.cxx+g");
+       gROOT->LoadMacro("AliMuonEventCuts.cxx+g");
+    
+    gROOT->LoadMacro("AliAnalysisMuMuCutElement.cxx+g");
+    gROOT->LoadMacro("AliAnalysisMuMuCutCombination.cxx+g");
+    gROOT->LoadMacro("AliAnalysisMuMuCutRegistry.cxx+g");
+    gROOT->LoadMacro("AliAnalysisMuMuEventCutter.cxx+g");
+    gROOT->LoadMacro("AliAnalysisMuMuBase.cxx+g");
+
+    gROOT->LoadMacro("AliAnalysisTaskMuMu.cxx+g");
+
+    gROOT->LoadMacro("AliAnalysisMuMuGlobal.cxx+g");
+
+    gROOT->LoadMacro("AliAnalysisMuMuMinv.cxx+g");
+    gROOT->LoadMacro("AliAnalysisMuMuSingle.cxx+g");
+    gROOT->LoadMacro("AliAnalysisMuMuNch.cxx+g");
+
+  }
+}
+
+//______________________________________________________________________________
+TChain* CreateLocalChain(const char* filelist)
+{
+       TChain* c = new TChain("aodTree");
+       
+       char line[1024];
+       
+       ifstream in(filelist);
+       while ( in.getline(line,1024,'\n') )
+       {
+               c->Add(line);
+       }
+       return c;
+}
+
+//______________________________________________________________________________
+TString GetInputType(const TString& sds, TProof* p)
+{
+   if (sds.Length()==0 ) return "AOD";
+
+   if (sds.Contains("SIM_JPSI")) return "AOD";
+   
+   if (sds.Contains("AOD")) return "AOD";
+   if (sds.Contains("ESD")) return "ESD";
+   
+   if ( gSystem->AccessPathName(gSystem->ExpandPathName(sds.Data())) )
+   {
+       // dataset is not a local file so it must be a dataset name
+       if (!p) return "NOPROOF";
+       
+       TFileCollection* fc = p->GetDataSet(sds.Data());
+    if (!fc) return "NODATASET";
+    
+    TIter next(fc->GetList());
+    TFileInfo* fi;
+    while ( ( fi = static_cast<TFileInfo*>(next()) ) )
+    {
+      TUrl url(*(fi->GetFirstUrl()));
+         TString surl(url.GetUrl());
+         
+         if (surl.Contains("AOD")) return "AOD";
+         if (surl.Contains("AliESD")) return "ESD";      
+    }      
+
+   }
+   else
+   {
+   std::cout << "Will use datasets from file " << sds.Data() << std::endl;
+   
+   // dataset is a local text file containing a list of dataset names
+       std::ifstream in(sds.Data());
+       char line[1014];
+   
+       while (in.getline(line,1023,'\n'))
+       {
+         TString sline(line);
+       sline.ToUpper();
+       if ( sline.Contains("SIM_JPSI") ) return "AOD";
+       if ( sline.Contains("AOD") ) return "AOD";
+       if ( sline.Contains("ESD") ) return "ESD";
+       }
+   }
+   
+   return "BUG";   
+}
+
+//______________________________________________________________________________
+AliAnalysisTask* runMuMu(const char* dataset="SIM_JPSI_LHC13f_CynthiaTuneWithRejectList_000197388",
+                         Bool_t simulations=kTRUE,
+                         Bool_t baseline=kFALSE,
+                         const char* where="laphecet@nansafmaster.in2p3.fr/?N")
+{
+  // Create the analysis manager
+  
+  Bool_t prooflite = (strlen(where)==0) || TString(where).Contains("workers");
+
+  TString sds(dataset);
+  
+//  if (!prooflite && sds.Length()>0) TProof::Mgr(where)->SetROOTVersion("VO_ALICE@ROOT::v5-34-05");
+  
+  TProof* p(0x0);
+  TString alirootMode("");
+  TString workers("workers=8x");
+
+  if (TString(where).Contains("alice-caf"))
+  {
+    workers="workers=1x";
+  }
+  if (TString(where).Contains("localhost:2093"))
+  {
+    workers="workers=8x";
+  }
+  
+  if (prooflite)
+  {
+    cout << "Will work in LITE mode" << endl;
+  }
+  
+  if ( sds.Length()>0 )
+  {
+    p = TProof::Open(where,workers.Data());
+    
+    if (!p)
+    {
+      cout << "Cannot connect to Proof : " << where << endl;
+      return 0;
+    }
+    
+    alirootMode.ToUpper();
+    
+    if ( alirootMode == "PAR" ) 
+    {
+      cout << "Will work with PAR files" << endl;
+      
+      std::vector<std::string> pars;
+      
+      pars.push_back("STEERBase");
+      pars.push_back("ESD");
+      pars.push_back("AOD");
+      pars.push_back("ANALYSIS");
+      pars.push_back("OADB");
+      pars.push_back("ANALYSISalice");
+      //       pars.push_back("CORRFW");
+      //       pars.push_back("PWGmuon");
+      
+      Bool_t ok(kTRUE);
+      
+      for ( std::vector<std::string>::size_type i = 0; i < pars.size(); ++i )
+      {
+        std::string package = pars[i];
+        
+        if ( gProof->UploadPackage(package.c_str()) ) 
+        {
+          ok = kFALSE;
+        }
+        
+        if ( gProof->EnablePackage(package.c_str(),"",kTRUE) ) 
+        {
+          ok = kFALSE;
+        }
+        
+        if (!ok) 
+        {
+          cout << "Problem with PAR " << package.c_str() << endl;
+          return 0;           
+        }
+      }
+    }
+    else 
+    {
+      TList* list = new TList();
+      
+      //       list->Add(new TNamed("ALIROOT_EXTRA_LIBS", "PWG3base"));
+      //       list->Add(new TNamed("ALIROOT_EXTRA_INCLUDES", "PWG3"));
+      //       list->Add(new TNamed("ALIROOT_EXTRA_LIBS", "PWG3base"));//:CORRFW:PWG3muon"));
+      //       list->Add(new TNamed("ALIROOT_EXTRA_INCLUDES", "PWG3/base"));//:PWG3/muon"));
+      
+      //    list->Add(new TNamed("ALIROOT_ENABLE_ALIEN", "1"));
+      
+      if (!alirootMode.IsNull())
+      {
+        list->Add(new TNamed("ALIROOT_MODE", alirootMode.Data()));  
+      }
+      else
+      {
+        list->Add(new TNamed("ALIROOT_MODE",""));
+      }
+      
+      if (!prooflite)
+      {
+//        p->SetParameter("PROOF_UseTreeCache", 0);
+        p->EnablePackage("VO_ALICE@AliRoot::v5-04-65-AN", list, kTRUE);
+      }
+      else
+      {
+        //      list->Add(new TNamed("ALIROOT_LOCAL_PATH",gSystem->Getenv("ALICE_ROOT")));       
+        p->UploadPackage("$ALICE_ROOT/ANALYSIS/macros/AliRootProofLite.par");
+        if (p->EnablePackage("AliRootProofLite",list)) return 0;
+      }
+    }
+    
+    // compile task on workers
+    if ( alirootMode != "PAR" )
+    {
+      p->Load("AliOADBMuonTrackCutsParam.cxx+");
+      p->Load("AliAnalysisMuonUtility.cxx+");
+      p->Load("AliMuonTrackCuts.cxx+");
+      p->Load("AliMergeableCollection.cxx+");
+      p->Load("AliAnalysisMuMuBinning.cxx+");
+      p->Load("AliMuonEventCuts.cxx+");
+       p->Load("AliAnalysisMuMuCutElement.cxx+");
+       p->Load("AliAnalysisMuMuCutCombination.cxx+");       
+       p->Load("AliAnalysisMuMuCutRegistry.cxx+");
+      p->Load("AliAnalysisMuMuBase.cxx+");      
+      p->Load("AliAnalysisTaskMuMu.cxx+");
+       p->Load("AliAnalysisMuMuEventCutter.cxx+");       
+     p->Load("AliAnalysisMuMuGlobal.cxx+");
+     p->Load("AliAnalysisMuMuNch.cxx+");
+     p->Load("AliAnalysisMuMuSingle.cxx+");
+     p->Load("AliAnalysisMuMuMinv.cxx+");
+       }
+  }
+  
+  LoadLocalLibs(kTRUE);
+  
+  AliAnalysisManager *mgr = new AliAnalysisManager("MuMu");
+  
+  AliInputEventHandler* input(0x0);
+
+  TString inputType = GetInputType(sds,p);
+  
+  if ( inputType == "AOD" ) 
+  {
+    input = new AliAODInputHandler;
+  }
+  else if ( inputType == "ESD" ) 
+  {
+    input = new AliESDInputHandler;
+  }
+  else
+  {
+       std::cout << "Cannot get input type !" << std::endl;
+       return 0;
+  }
+
+  mgr->SetInputEventHandler(input);
+  
+  TList* triggers = new TList;
+  triggers->SetOwner(kTRUE);
+
+  if (!simulations)
+  {
+    triggers->Add(new TObjString("CINT7-B-NOPF-ALLNOTRD"));
+
+//   triggers->Add(new TObjString("CINT7-B-NOPF-ALLNOTRD & 0MUL"));
+//   triggers->Add(new TObjString("CINT7-B-NOPF-ALLNOTRD & 0MSL"));
+//   triggers->Add(new TObjString("CINT7-B-NOPF-ALLNOTRD & 0MSH"));
+//   triggers->Add(new TObjString("CMSL7-B-NOPF-MUON & 0MUL"));
+//   triggers->Add(new TObjString("CMSL7-B-NOPF-MUON & 0MSH"));
+// 
+//   triggers->Add(new TObjString("CMSL7-B-NOPF-MUON"));
+//   triggers->Add(new TObjString("CMSH7-B-NOPF-MUON"));
+//    triggers->Add(new TObjString("CMUL7-B-NOPF-MUON"));
+  // below for MB periods only
+//  triggers->Add(new TObjString("CMSL7-B-NOPF-ALLNOTRD"));
+//   triggers->Add(new TObjString("CMSH7-B-NOPF-ALLNOTRD"));
+  triggers->Add(new TObjString("CMUL7-B-NOPF-ALLNOTRD"));
+  triggers->Add(new TObjString("CMUL7-B-NOPF-MUON"));
+//   triggers->Add(new TObjString("CMSL7-B-NOPF-ALLNOTRD & 0MUL"));
+//   triggers->Add(new TObjString("CMSL7-B-NOPF-ALLNOTRD & 0MSH"));
+  }
+
+  TString outputname("test.MuMu.AOD.1.root");
+  
+  if ( sds.Length()>0 ) 
+  {
+       TString af("local");
+       
+       if ( gProof )
+       {
+         af="unknown";
+         TString master(gProof->GetSessionTag());
+      if (master.Contains("lx")) af = "caf";
+      if (master.Contains("nansaf")) af = "saf";
+      if (master.Contains("skaf")) af = "skaf";
+      if (master.Contains("localhost:2093")) af="laf";
+       }
+       outputname = Form("%s.%s.root",gSystem->BaseName(sds.Data()),af.Data());
+    outputname.ReplaceAll("|","-");
+       cout << outputname << endl;
+  }
+
+  AliAnalysisTask* task(0x0);
+
+  if (!baseline)
+  {  
+       gROOT->LoadMacro("AddTaskMuMu.C");
+
+       task = AddTaskMuMu(outputname.Data(),triggers,"pA",simulations);
+  }
+  else
+  {
+       gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/train/AddTaskBaseLine.C");
+       task = AddTaskBaseLine();
+  }
+  
+  if (!mgr->InitAnalysis()) 
+  {
+       cout << "Could not InitAnalysis" << endl;
+    return 0;
+  }
+  
+  if ( sds.Length()>0 )
+  {
+    TStopwatch timer;
+    
+    mgr->StartAnalysis("proof",sds.Data());
+    
+    timer.Print();
+  }
+  else
+  {
+    mgr->PrintStatus();
+  
+       task->Print();
+       
+//     return task;
+       
+    TChain* c = CreateLocalChain("list.aod.txt");
+//     mgr->SetNSysInfo(10);
+    TStopwatch timer;
+//    mgr->SetDebugLevel(10);
+    mgr->StartAnalysis("local",c);
+    timer.Print();
+//    mgr->ProfileTask("AliAnalysisTaskMuMu");
+//    if (baseline) mgr->ProfileTask("baseline");
+  }
+  
+  AliCodeTimer::Instance()->Print();
+  
+  if (alirootMode=="PAR")
+  {
+    TProofLog *pl = TProof::Mgr(where)->GetSessionLogs(); pl->Save("*","aod.log");
+  }
+  
+  delete triggers;
+  
+  return task;
+}
+
index e0ee87bdff4399598f42f3482bb4a3a979be42da..13d00109d7ae626946b6ec96534bf67e22f90502 100644 (file)
@@ -1574,7 +1574,7 @@ AliAnalysisMuMu::FitParticle(const char* particle,
     
     if (!hminv)
     {
-      if (!fBinning && bin->IsNullObject() )
+      if (!fBinning && bin->IsIntegrated() )
       {
         // old file, we only had MinvUSPt
         hminv = fMergeableCollection->Histo(Form("/%s/%s/%s/%s",eventType,trigger,centrality,pairCut),"MinvUSPt:py");
@@ -1665,11 +1665,11 @@ AliAnalysisMuMu::GetMCCB2Tails(const AliAnalysisMuMuBinning::Range& bin) const
   }
 
 
-  AliAnalysisMuMuSpectra* s = static_cast<AliAnalysisMuMuSpectra*>(SIM()->GetSpectra(bin.Type().Data(),bin.Flavour().Data()));
+  AliAnalysisMuMuSpectra* s = static_cast<AliAnalysisMuMuSpectra*>(SIM()->GetSpectra(bin.Quantity().Data(),bin.Flavour().Data()));
   
   if (!s)
   {
-    AliError(Form("Could not find spectra %s,%s for associated simulation",bin.Type().Data(),bin.Flavour().Data()));
+    AliError(Form("Could not find spectra %s,%s for associated simulation",bin.Quantity().Data(),bin.Flavour().Data()));
     fAssociatedSimulation->MC()->Print("*:Ali*");
     return par;
   }
@@ -3274,7 +3274,7 @@ AliAnalysisMuMuSpectra* AliAnalysisMuMu::RABy(const char* realFile, const char*
     Double_t ylowcms, yhighcms;
     Double_t ylownorm, yhighnorm;
     
-    if ( bin->IsNullObject() )
+    if ( bin->IsIntegrated() )
     {
       ylowlab = -4;
       yhighlab = -2.5;
@@ -3330,7 +3330,7 @@ AliAnalysisMuMuSpectra* AliAnalysisMuMu::RABy(const char* realFile, const char*
     r->Set("NofInputJpsi",rsim->GetValue("NofInputJpsi",accEffSubResultName),rsim->GetErrorStat("NofInputJpsi",accEffSubResultName));
     r->Set("AccEffJpsi",rsim->GetValue("AccEffJpsi",accEffSubResultName),rsim->GetErrorStat("AccEffJpsi",accEffSubResultName));
     
-    AliAnalysisMuMuBinning::Range* bincm = new AliAnalysisMuMuBinning::Range(bin->Particle(),bin->Type(),ylowcms,yhighcms);
+    AliAnalysisMuMuBinning::Range* bincm = new AliAnalysisMuMuBinning::Range(bin->What(),bin->Quantity(),ylowcms,yhighcms);
     
     r->SetBin(*bincm);
         
index ac8673a2616cd9b95360e452d37ef2995a2c19d4..eadabaee310611449b99755c5a523531caabf706 100644 (file)
@@ -151,8 +151,8 @@ Bool_t AliAnalysisMuMuSpectra::Correct(const AliAnalysisMuMuSpectra& accEff, con
     return kFALSE;
   }
   
-  TObjArray* particles = fBinning->CreateParticleArray();
-  TObjArray* types = fBinning->CreateTypeArray();
+  TObjArray* particles = fBinning->CreateWhatArray();
+  TObjArray* types = fBinning->CreateQuantityArray();
   
   if (particles->GetEntries()!=1 || types->GetEntries()!=1 )
   {