New classes for getting the results out of the output of AliAnalysisTaskMuMu: AliAnal...
authorpcrochet <pcrochet@f7af4fe6-9843-0410-8265-dc069ae4e863>
Mon, 18 Feb 2013 14:55:15 +0000 (14:55 +0000)
committerpcrochet <pcrochet@f7af4fe6-9843-0410-8265-dc069ae4e863>
Mon, 18 Feb 2013 14:55:15 +0000 (14:55 +0000)
PWG/CMakelibPWGmuondep.pkg
PWG/PWGmuondepLinkDef.h
PWG/muondep/AliAnalysisMuMu.cxx
PWG/muondep/AliAnalysisMuMu.h
PWG/muondep/AliAnalysisMuMuResult.cxx [new file with mode: 0644]
PWG/muondep/AliAnalysisMuMuResult.h [new file with mode: 0644]
PWG/muondep/AliAnalysisMuMuSpectra.cxx [new file with mode: 0644]
PWG/muondep/AliAnalysisMuMuSpectra.h [new file with mode: 0644]
PWG/muondep/AliMuonAccEffSubmitter.cxx [new file with mode: 0644]
PWG/muondep/AliMuonAccEffSubmitter.h [new file with mode: 0644]

index 798b72f..1a28e3a 100644 (file)
@@ -32,6 +32,9 @@ set ( SRCS
     muondep/AliAnalysisTaskMuonRefit.cxx
     muondep/AliAnalysisTriggerScalers.cxx
     muondep/AliAnalysisMuMu.cxx
+    muondep/AliAnalysisMuMuResult.cxx
+    muondep/AliAnalysisMuMuSpectra.cxx
+    muondep/AliMuonAccEffSubmitter.cxx
     )
 
 string ( REPLACE ".cxx" ".h" HDRS "${SRCS}" )
@@ -40,4 +43,4 @@ set ( DHDR  PWGmuondepLinkDef.h )
 
 set ( EXPORT "muondep/AliAnalysisTriggerScalers.h" )
 
-set ( EINCLUDE  MUON MUON/mapping PWG/muondep STEER/STEER STEER/STEERBase)
+set ( EINCLUDE RAW MUON MUON/mapping PWG/muondep STEER/STEER STEER/STEERBase)
index c86db30..bb80273 100644 (file)
@@ -9,10 +9,13 @@
 #pragma link C++ class AliAnalysisTaskMuonRefit+;
 
 #pragma link C++ class AliAnalysisMuMu+;
-#pragma link C++ class AliAnalysisMuMu::Result+;
+#pragma link C++ class AliAnalysisMuMuResult+;
+#pragma link C++ class AliAnalysisMuMuSpectra+;
 #pragma link C++ class AliAnalysisTriggerScalers+;
 #pragma link C++ class AliAnalysisTriggerScalerItem+;
 
+#pragma link C++ class AliMuonAccEffSubmitter+;
+
 #endif
 
 
index a3a7648..7ebbd7f 100644 (file)
 
 #include "AliAnalysisMuMu.h"
 
+#include "AliAnalysisMuMuBinning.h"
+#include "AliAnalysisMuMuResult.h"
+#include "AliAnalysisMuMuSpectra.h"
 #include "AliAnalysisTriggerScalers.h"
 #include "AliCounterCollection.h"
 #include "AliHistogramCollection.h"
 #include "AliLog.h"
+#include "AliMergeableCollection.h"
 #include "Riostream.h"
 #include "TArrayL64.h"
+#include "TASImage.h"
 #include "TAxis.h"
 #include "TCanvas.h"
+#include "TColor.h"
 #include "TF1.h"
 #include "TFile.h"
 #include "TGraphErrors.h"
 #include "TGrid.h"
 #include "TH1.h"
 #include "TH2.h"
+#include "TKey.h"
 #include "TLegend.h"
 #include "TLegendEntry.h"
+#include "TLine.h"
 #include "TList.h"
+#include "TMap.h"
 #include "TMath.h"
 #include "TObjArray.h"
 #include "TObjString.h"
+#include "TParameter.h"
+#include "TPaveText.h"
 #include "TROOT.h"
 #include "TStyle.h"
+#include "TStyle.h"
 #include "TSystem.h"
+#include <cassert>
 #include <map>
 #include <set>
 #include <string>
-#include "TParameter.h"
-#include "TMap.h"
-#include "TFitResult.h"
-#include "TLine.h"
-#include "TASImage.h"
-#include "TPaveText.h"
-#include "TStyle.h"
-#include "TColor.h"
 
 ClassImp(AliAnalysisMuMu)
 
-void Add(TObjArray* a, AliAnalysisMuMu::Result* r)
-{
-  if ( r ) a->Add(r);
-}
-
-void ALICEseal(Double_t xPad, Double_t yPad, TList* extraLines)
-{
-  TVirtualPad* currPad = gPad;
-  TPad *myPadLogo = new TPad("myPadLogo", "Pad for ALICE Logo",0.76,0.7,0.90,0.87);
-  myPadLogo->SetFillColor(kWhite);
-  myPadLogo->SetFillStyle(1001);
-  myPadLogo->SetBorderMode(0);
-  myPadLogo->SetBorderSize(2);
-  myPadLogo->SetFrameBorderMode(0);
-  myPadLogo->SetLeftMargin(0.0);
-  myPadLogo->SetTopMargin(0.0);
-  myPadLogo->SetBottomMargin(0.0);
-  myPadLogo->SetRightMargin(0.0);
-  myPadLogo->Draw();
-  myPadLogo->cd();
-  TASImage *myAliceLogo = new TASImage("$HOME/Pictures/2011-Nov-24-ALICE_PERFORMANCE_logo_BLACK_small_usage_design.gif");
-  myAliceLogo->Draw();
-  currPad->cd();
-  Double_t x1 = xPad - 0.07, y1 = yPad - 0.06;
-  Double_t x2 = x1 + 0.25, y2 = y1 + 0.08;
-  TPaveText* t2=new TPaveText(x1+0.06,y1-0.06,x2-0.06,y2-0.06,"NDC");
-  //  t2->SetFillStyle(0);
-  t2->SetFillColor(kWhite);
-  t2->SetBorderSize(0);
-  t2->SetTextColor(kBlack);
-  t2->SetTextFont(52);
-  t2->SetTextSize(0.035);
-  TDatime dt;
-  TString today = Form("%02i/%02i/%4i", dt.GetDay(), dt.GetMonth(), dt.GetYear());
-  t2->AddText(0.,0.,today.Data());
-  t2->Draw();
-  
-  if ( extraLines ) 
-  {
-    int n = extraLines->GetSize();
-    TPaveText* t3 = new TPaveText(xPad-0.07,yPad-0.06*2,xPad-0.07+0.25,yPad-0.06*(n+3),"NDC");
-    t3->SetFillColor(kWhite);
-    t3->SetBorderSize(0);
-    t3->SetTextColor(kBlack);
-    t3->SetTextFont(42);
-    t3->SetTextSize(0.035);
-    
-    TIter next(extraLines);
-    TObjString* str;
-    
-    while ( ( str = static_cast<TObjString*>(next()) ) )
-    {
-      t3->AddText(str->String().Data());
-    }
-    t3->SetFillColor(kWhite);
-    t3->Draw();
-  }
-}
-
-Double_t funcCB(Double_t* xx, Double_t* par)
-{ 
-  Double_t N = par[0];
-  Double_t alpha = par[1];
-  Double_t n = par[2];
-  Double_t mean = par[3];
-  Double_t sigma = par[4];
-  
-  Double_t x = xx[0];
-  
-  Double_t A = TMath::Power(n/TMath::Abs(alpha),n)*TMath::Exp(-0.5*alpha*alpha);
-  Double_t B = n/TMath::Abs(alpha) - TMath::Abs(alpha);
-  
-  Double_t y = ( TMath::Abs(sigma) > 1E-12 ? (x-mean)/sigma : 0 );
-  
-  if ( y > alpha*-1.0 ) 
-  {
-    return N*TMath::Exp(-0.5*y*y);
-  }
-  else 
-  {
-    return N*A*TMath::Power(B-y,-n);
-  }
-}
-
-Double_t funcJpsiGCBE(Double_t* xx, Double_t* par)
-{
-  Double_t x = xx[0];
-  
-  Double_t g = par[0]*TMath::Gaus(x,par[1],par[2]);
-  
-  Double_t jpsi = funcCB(xx,par+3);
-  
-  Double_t expo = par[8]*TMath::Exp(par[9]*x);
-  
-  return g+expo+jpsi;
-}
-
-Double_t funcJpsiJpsiPrimeCustom(Double_t* xx, Double_t* par)
-{ 
-  Double_t N = par[0];
-  Double_t alpha = par[1];
-  Double_t n = par[2];
-  Double_t mean = par[3];
-  Double_t sigma = par[4];
-  Double_t alphaprime = par[5];
-  Double_t nprime = par[6];
-  
-  Double_t x = xx[0];
-  
-  Double_t A = TMath::Power(n/TMath::Abs(alpha),n)*TMath::Exp(-0.5*alpha*alpha);
-  Double_t B = n/TMath::Abs(alpha) - TMath::Abs(alpha);
-  Double_t C = TMath::Power(nprime/TMath::Abs(alphaprime),nprime)*TMath::Exp(-0.5*alphaprime*alphaprime);
-  Double_t D = nprime/TMath::Abs(alphaprime) - TMath::Abs(alphaprime);
-  
-  Double_t y = ( TMath::Abs(sigma) > 1E-12 ? (x-mean)/sigma : 0 );
-  
-  Double_t cb(0);
-  
-  if ( y > alphaprime )
-  {
-    cb = N*C*TMath::Power(D+y,-nprime);
-  }
-  else if ( y > alpha*-1.0 ) 
-  {
-    cb = N*TMath::Exp(-0.5*y*y);
-  }
-  else 
-  {
-    cb = N*A*TMath::Power(B-y,-n);
-  }
-  
-  if ( x < mean )
-  {
-    return cb + par[7] + par[8]*x; // gaus + pol1
-  }
-  else
-  {
-    Double_t yprime = (x-par[10])/par[11];
-    return cb + par[9]*TMath::Exp(-0.5*yprime*yprime)+par[12]*TMath::Exp(-par[13]*x);
-    // gaus (j/psi) + gaus (psi') + expo
-  }
-}
-
-
-Double_t funcCB2(Double_t* xx, Double_t* par)
-{ 
-  Double_t N = par[0];
-  Double_t alpha = par[1];
-  Double_t n = par[2];
-  Double_t mean = par[3];
-  Double_t sigma = par[4];
-  Double_t alphaprime = par[5];
-  Double_t nprime = par[6];
-  
-  Double_t x = xx[0];
-  
-  Double_t A = TMath::Power(n/TMath::Abs(alpha),n)*TMath::Exp(-0.5*alpha*alpha);
-  Double_t B = n/TMath::Abs(alpha) - TMath::Abs(alpha);
-  Double_t C = TMath::Power(nprime/TMath::Abs(alphaprime),nprime)*TMath::Exp(-0.5*alphaprime*alphaprime);
-  Double_t D = nprime/TMath::Abs(alphaprime) - TMath::Abs(alphaprime);
-  
-  Double_t y = ( TMath::Abs(sigma) > 1E-12 ? (x-mean)/sigma : 0 );
-  
-  if ( y > alphaprime )
-  {
-    return N*C*TMath::Power(D+y,-nprime);
-  }
-  else if ( y > alpha*-1.0 ) 
-  {
-    return N*TMath::Exp(-0.5*y*y);
-  }
-  else 
-  {
-    return N*A*TMath::Power(B-y,-n);
-  }
-}
-
-Double_t funcJpsiJpsiPrime(Double_t* xx, Double_t* par)
-{
-  Double_t jpsi = funcCB(xx,par);
-  Double_t jpsiprime = funcCB2(xx,par+5);
-  
-  int n = 10;
-  Double_t x = xx[0];
-    
-  Double_t e1 = par[n]*TMath::Exp(par[n+1]*x);
-  Double_t e2 = par[n+2]*TMath::Exp(par[n+3]*x);    
-  
-  Double_t e = e1;
-  
-  if ( x > par[3] ) e=e2;
-  
-  return jpsi+jpsiprime+e;
-}
-
-Double_t funcJpsiCBE(Double_t* xx, Double_t* par)
-{
-  // CB + expo
-  
-  Double_t jpsi = funcCB(xx,par);
-  
-  Double_t x = xx[0];
-  
-  Double_t e1 = par[5]*TMath::Exp(par[6]*x);
-  
-  return jpsi+e1;
-}
-
-
-Double_t funcJpsiPCBE(Double_t* xx, Double_t* par)
-{
-  Double_t x = xx[0];
-
-  Double_t pol2 = par[0] + par[1]*x + par[2]*x*x;
-
-  Double_t jpsi = funcCB(xx,par+3);
-  
-  Double_t expo = par[8]*TMath::Exp(par[9]*x);
-  
-  return pol2+jpsi+expo;
-}
-
-Double_t funcJpsiECBE(Double_t* xx, Double_t* par)
-{
-  // CB + expo
-  
-  Double_t jpsi = funcCB(xx,par+2);
-  
-  Double_t x = xx[0];
-  
-  Double_t e1 = par[0]*TMath::Exp(par[1]*x);
-  
-  Double_t e2 = par[7]*TMath::Exp(par[8]*x);
-  
-  return e1+e2+jpsi;
-}
-
-const char* NormalizeName(const char* name, const char* suffix)
-{
-  TString str(Form("%s_%s",name,suffix));
-  
-  str.ReplaceAll("-","_");
-  str.ReplaceAll("/","%");
-  
-  return str.Data();
-}
-
-//_____________________________________________________________________________
-AliAnalysisMuMu::Result::~Result()
-{
-  delete fHC;
-  delete fMap;
-}
-
-//_____________________________________________________________________________
-void AliAnalysisMuMu::Result::FitJpsiJpsiPrimeCustom(TH1& h)
-{
-  std::cout << "Fit with jpsi + jpsiprime' (custom)" << std::endl;
-  
-  const Double_t xmin(1.5);
-  const Double_t xmax(8.0);
-  
-  fFitTotal = new TF1("fFitTotal",funcJpsiJpsiPrimeCustom,xmin,xmax,14);
-  fFitTotal->SetLineColor(4);
-  
-  fFitTotal->SetParName(0,"cstecb");
-  fFitTotal->SetParName(1,"alpha");
-  fFitTotal->SetParName(2,"n");
-  fFitTotal->SetParName(3,"meanjpsi");
-  fFitTotal->SetParName(4,"sigmajpsi");
-  fFitTotal->SetParName(5,"alphaprime");
-  fFitTotal->SetParName(6,"nprime");
-  fFitTotal->SetParName(7,"cstepol1");
-  fFitTotal->SetParName(8,"slopepol1");
-  fFitTotal->SetParName(9,"cstegaus");
-  fFitTotal->SetParName(10,"meanpsiprime");
-  fFitTotal->SetParName(11,"sigmapsiprime");
-  fFitTotal->SetParName(12,"csteexpo");
-  fFitTotal->SetParName(13,"slopeexpo");
-  
-  fFitTotal->SetParameter( 0,1);
-    
-  const char* fitOption = "SQBR+";
-  const Double_t alphaMC = 0.936;
-  const Double_t nMC = 4.44;
-  const Double_t alphaprimeMC = 1.60;
-  const Double_t nprimeMC = 3.23;
-  
-  TF1* fcb = new TF1("cb",funcCB2,2.9,3.3,7);
-  fcb->SetParameters(1,1.0,4.0,3.1,0.1,1.5,3);
-
-  fcb->SetParLimits(3,3,4); 
-  fcb->SetParLimits(4,0,1); 
-
-  fcb->FixParameter(1,alphaMC);
-  fcb->FixParameter(2,nMC);
-  fcb->FixParameter(5,alphaprimeMC);
-  fcb->FixParameter(6,nprimeMC);
-  
-  TFitResultPtr rcb = h.Fit(fcb,fitOption,"",2.9,3.3);
-
-  if (!rcb.Get())
-  {
-    return;
-  }
-  
-  fFitTotal->SetParameter(0,rcb->Parameter(0));
-  fFitTotal->SetParameter(1,rcb->Parameter(1)); fFitTotal->SetParLimits(1,0,10); // alpha
-  fFitTotal->SetParameter(2,rcb->Parameter(2)); fFitTotal->SetParLimits(2,1,10); // n
-  fFitTotal->SetParameter(3,rcb->Parameter(3)); fFitTotal->SetParLimits(3,3.0,3.5); // mean
-  fFitTotal->SetParameter(4,rcb->Parameter(4)); fFitTotal->SetParLimits(4,0,1); // sigma
-  fFitTotal->SetParameter(5,rcb->Parameter(5)); fFitTotal->SetParLimits(1,0,10); // alphaprime
-  fFitTotal->SetParameter(6,rcb->Parameter(6)); fFitTotal->SetParLimits(2,1,10); // nprime
-
-  fFitTotal->FixParameter(1,alphaMC);
-  fFitTotal->FixParameter(2,nMC);
-  fFitTotal->FixParameter(5,alphaprimeMC);
-  fFitTotal->FixParameter(6,nprimeMC);
-  
-  TF1* fge = new TF1("fge","gaus(0)+expo(3)",3.5,4.4);
-  fge->SetParameters(1,3.6,0.25,1,1);
-  TFitResultPtr rpsiprime = h.Fit(fge,fitOption,"",3.5,4.4);
-  
-  if (static_cast<int>(rpsiprime))
-  {
-    AliInfo("Will fix psiprime parameters");
-    fFitTotal->FixParameter(9,0);
-    fFitTotal->FixParameter(10,3.7);
-    fFitTotal->FixParameter(11,0.1);
-  }
-  else
-  {
-    fFitTotal->SetParameter(10,rpsiprime->Parameter(1)); fFitTotal->SetParLimits(10,3.5,3.8); // mean'
-    fFitTotal->SetParameter(11,rpsiprime->Parameter(2)); fFitTotal->SetParLimits(11,0.05,0.7); // sigma'
-  }
-  
-  TFitResultPtr rpol1 = h.Fit("pol1",fitOption,"",1.5,2.5);
-  fFitTotal->SetParameter( 7,rpol1->Parameter(0));
-  fFitTotal->SetParameter( 8,rpol1->Parameter(1));
-  
-  TFitResultPtr rexpo = h.Fit("expo",fitOption,"",4.5,7.0);
-  fFitTotal->SetParameter(12,rexpo->Parameter(0));
-  fFitTotal->SetParameter(13,rexpo->Parameter(1));
-  
-  
-  TFitResultPtr r = h.Fit(fFitTotal,fitOption,"",1.5,7);
-  
-  TF1* signal = new TF1("signal","gaus",2,6);  
-  signal->SetParameters(fFitTotal->GetParameter(0),
-                        fFitTotal->GetParameter(3),
-                        fFitTotal->GetParameter(4));
-
-  TF1* signalPrime = new TF1("signalPrime","gaus",2,6);  
-  signalPrime->SetParameters(fFitTotal->GetParameter(9),
-                             fFitTotal->GetParameter(10),
-                             fFitTotal->GetParameter(11));
-  
-  Double_t gausParameters[3];
-  Double_t covarianceMatrix[3][3];
-  Double_t gausParametersPrime[3];
-  Double_t covarianceMatrixPrime[3][3];
-  
-  covarianceMatrix[0][0] = (r->GetCovarianceMatrix())(0,0);
-  covarianceMatrix[1][0] = (r->GetCovarianceMatrix())(3,0);
-  covarianceMatrix[2][0] = (r->GetCovarianceMatrix())(4,0);
-  covarianceMatrix[0][1] = (r->GetCovarianceMatrix())(0,3);
-  covarianceMatrix[0][2] = (r->GetCovarianceMatrix())(0,4);  
-  
-  for ( int iy = 1; iy < 3; ++iy )
-  {
-    for ( int ix = 1; ix < 3; ++ix )
-    {
-      covarianceMatrix[ix][iy] = (r->GetCovarianceMatrix())(ix+2,iy+2);
-    }
-  }
-  
-  gausParameters[0] = fFitTotal->GetParameter(0);
-  gausParameters[1] = fFitTotal->GetParameter(3);
-  gausParameters[2] = fFitTotal->GetParameter(4);
-
-  gausParametersPrime[0] = fFitTotal->GetParameter(9);
-  gausParametersPrime[1] = fFitTotal->GetParameter(10);
-  gausParametersPrime[2] = fFitTotal->GetParameter(11);
-  
-  covarianceMatrixPrime[0][0] = (r->GetCovarianceMatrix())(9,9);
-  covarianceMatrixPrime[1][0] = (r->GetCovarianceMatrix())(10,9);
-  covarianceMatrixPrime[2][0] = (r->GetCovarianceMatrix())(11,9);
-  covarianceMatrixPrime[0][1] = (r->GetCovarianceMatrix())(9,10);
-  covarianceMatrixPrime[0][2] = (r->GetCovarianceMatrix())(9,11);  
-  
-  for ( int iy = 1; iy < 3; ++iy )
-  {
-    for ( int ix = 1; ix < 3; ++ix )
-    {
-      covarianceMatrixPrime[ix][iy] = (r->GetCovarianceMatrix())(ix+2,iy+2);
-    }
-  }
-  
-  double n = signal->Integral(2,6)/h.GetBinWidth(10);
-  double nerr = signal->IntegralError(2,6,&gausParameters[0],&covarianceMatrix[0][0])/h.GetBinWidth(10);
-  Set("NofJpsi",n,nerr);      
-  Set("MeanJpsi",fFitTotal->GetParameter(3),fFitTotal->GetParError(3));
-  Set("SigmaJpsi",fFitTotal->GetParameter(4),fFitTotal->GetParError(4));
-
-  double nprime = signalPrime->Integral(2,6)/h.GetBinWidth(10);
-  double nerrprime = signalPrime->IntegralError(2,6,&gausParametersPrime[0],&covarianceMatrixPrime[0][0])/h.GetBinWidth(10);
-  Set("NofJpsiPrime",nprime,nerrprime);      
-  Set("MeanJpsiPrime",fFitTotal->GetParameter(10),fFitTotal->GetParError(10));
-  Set("SigmaJpsiPrime",fFitTotal->GetParameter(11),fFitTotal->GetParError(11));
-}
-
-//_____________________________________________________________________________
-void AliAnalysisMuMu::Result::FitJpsiJpsiPrimeCB(TH1& h)
-{
-  std::cout << "Fit with jpsi + jpsiprime' (CB) " << std::endl;
-
-  const Double_t xmin(1.5);
-  const Double_t xmax(8.0);
-  
-  fFitTotal = new TF1("fFitTotal",funcJpsiJpsiPrime,xmin,xmax,14);
-
-//  Double_t N = par[0];
-//  Double_t alpha = par[1];
-//  Double_t n = par[2];
-//  Double_t mean = par[3];
-//  Double_t sigma = par[4];
-  
-  fFitTotal->SetParameter( 0,1); // N
-  fFitTotal->FixParameter( 1,0.936); // alpha
-  fFitTotal->FixParameter( 2,4.44); // n
-  fFitTotal->SetParameter( 3,3.1); fFitTotal->SetParLimits(3,3.0,3.2); // mean
-  fFitTotal->SetParameter( 4,0.07); fFitTotal->SetParLimits(4,0.02,1); // sigma
-
-  fFitTotal->SetParameter( 5,0.01); // N'
-  fFitTotal->FixParameter( 6,0.936); // alpha'
-  fFitTotal->FixParameter( 7,4.44); // n'
-  fFitTotal->SetParameter( 8,3.7); fFitTotal->SetParLimits(8,3.5,3.8); // mean'
-  fFitTotal->SetParameter( 9,0.1); fFitTotal->SetParLimits(9,0.02,1.0); // sigma'
-  
-  fFitTotal->SetParameter(10,h.GetMaximum());
-  fFitTotal->SetParameter(11,-1);
-
-  fFitTotal->SetParameter(12,h.GetMaximum()/100);
-  fFitTotal->SetParameter(13,-1);
-
-  TFitResultPtr r = h.Fit(fFitTotal,"SQBI","",1.5,6);
-  
-//  for ( int ix = 0; ix < fFitTotal->GetNpar(); ++ix )
-//  {
-//    for ( int iy = 0; iy < fFitTotal->GetNpar(); ++iy )
-//    {      
-//      std::cout << Form("COV(%d,%d)=%e ",ix,iy,r->GetCovarianceMatrix()(ix,iy));        
-//    }
-//    std::cout << std::endl;
-//  }
-  
-  
-  TF1* signal = new TF1("signal","gaus",2,8);
-  
-  signal->SetParameters(fFitTotal->GetParameter(0),
-                        fFitTotal->GetParameter(3),
-                        fFitTotal->GetParameter(4));
-
-  TF1* signalPrime = new TF1("signalPrime","gaus",2,8);
-  
-  signalPrime->SetParameters(fFitTotal->GetParameter(0),
-                             fFitTotal->GetParameter(8),
-                             fFitTotal->GetParameter(9));
-  
-  Double_t gausParameters[3];
-  Double_t gausParametersPrime[3];
-  Double_t covarianceMatrix[3][3];
-  Double_t covarianceMatrixPrime[3][3];
-  
-  gausParameters[0] = fFitTotal->GetParameter(0);
-  gausParameters[1] = fFitTotal->GetParameter(3);
-  gausParameters[2] = fFitTotal->GetParameter(4);
-
-  covarianceMatrix[0][0] = (r->GetCovarianceMatrix())(0,0);
-  covarianceMatrix[1][0] = (r->GetCovarianceMatrix())(3,0);
-  covarianceMatrix[2][0] = (r->GetCovarianceMatrix())(4,0);
-  covarianceMatrix[0][1] = (r->GetCovarianceMatrix())(0,3);
-  covarianceMatrix[0][2] = (r->GetCovarianceMatrix())(0,4);
-  
-  for ( int iy = 1; iy < 3; ++iy )
-  {
-    for ( int ix = 1; ix < 3; ++ix )
-    {
-      covarianceMatrix[ix][iy] = (r->GetCovarianceMatrix())(ix+2,iy+2);
-    }
-  }
-
-  gausParametersPrime[0] = fFitTotal->GetParameter(0);
-  gausParametersPrime[1] = fFitTotal->GetParameter(8);
-  gausParametersPrime[2] = fFitTotal->GetParameter(9);
-
-  covarianceMatrixPrime[0][0] = (r->GetCovarianceMatrix())(0,0);
-  covarianceMatrixPrime[1][0] = (r->GetCovarianceMatrix())(8,0);
-  covarianceMatrixPrime[2][0] = (r->GetCovarianceMatrix())(9,0);
-  covarianceMatrixPrime[0][1] = (r->GetCovarianceMatrix())(0,8);
-  covarianceMatrixPrime[0][2] = (r->GetCovarianceMatrix())(0,9);
-  
-  for ( int iy = 1; iy < 3; ++iy )
-  {
-    for ( int ix = 1; ix < 3; ++ix )
-    {
-      covarianceMatrixPrime[ix][iy] = (r->GetCovarianceMatrix())(ix+2,iy+2);
-    }
-  }
-  
-  double n = signal->Integral(2,6)/h.GetBinWidth(10);
-  double nerr = signal->IntegralError(2,6,&gausParameters[0],&covarianceMatrix[0][0])/h.GetBinWidth(10);
-
-  Set("NofJpsi",n,nerr);      
-  Set("MeanJpsi",fFitTotal->GetParameter(3),fFitTotal->GetParError(3));
-  Set("SigmaJpsi",fFitTotal->GetParameter(4),fFitTotal->GetParError(4));
-
-  double nprime = signalPrime->Integral(2,6)/h.GetBinWidth(10);
-  double nerrprime = signalPrime->IntegralError(2,6,&gausParametersPrime[0],&covarianceMatrixPrime[0][0])/h.GetBinWidth(10);
-  
-  Set("NofJpsiPrime",nprime,nerrprime);
-  Set("MeanJpsiPrime",fFitTotal->GetParameter(8),fFitTotal->GetParError(8));
-  Set("SigmaJpsiPrime",fFitTotal->GetParameter(9),fFitTotal->GetParError(9));
-  
-}
-  
-//_____________________________________________________________________________
-void AliAnalysisMuMu::Result::FitJpsiGCBE(TH1& h)
-{
-  std::cout << "Fit with jpsi alone (gaus + CB + expo)" << std::endl;
-  
-  const Double_t xmin(1.0);
-  const Double_t xmax(8.0);
-  
-  fFitTotal = new TF1("fFitTotal",funcJpsiGCBE,xmin,xmax,10);
-  fFitTotal->SetParNames("cste","x0","sigma0","N","alpha","n","mean","sigma","expocste","exposlope");
-  
-  fFitTotal->SetParLimits(3,0,h.GetMaximum()*2); // N
-  
-  const Double_t cbalpha(0.98);
-  const Double_t cbn(5.2);
-  
-  fFitTotal->FixParameter(4,cbalpha);
-  fFitTotal->FixParameter(5,cbn);
-  
-  fFitTotal->SetParLimits(6,2.8,3.2); // mean
-  fFitTotal->SetParLimits(7,0.02,0.3); // sigma
-  
-  TF1* fg = new TF1("fg","gaus",xmin,xmax);
-  
-  h.Fit(fg,"","",0.75,3.0);
-  
-  fFitTotal->SetParameter(0,fg->GetParameter(0));
-  fFitTotal->SetParameter(1,fg->GetParameter(1));
-  fFitTotal->SetParameter(2,fg->GetParameter(2));
-  
-  TF1* fexpo = new TF1("expo","expo",xmin,xmax);
-  
-  h.Fit(fexpo,"","",3.5,5);
-  
-  fFitTotal->SetParameter(8,fexpo->GetParameter(0));
-  fFitTotal->SetParameter(9,fexpo->GetParameter(1));
-  
-  fFitTotal->SetParameter(3,h.GetMaximum()),
-  fFitTotal->SetParameter(4,cbalpha);
-  fFitTotal->SetParameter(5,cbn);
-  fFitTotal->SetParameter(6,3.15);
-  fFitTotal->SetParameter(7,0.1);
-  
-  const char* fitOption = "SI+";
-  
-  TFitResultPtr r = h.Fit(fFitTotal,fitOption,"",2,5);
-  
-  Set("MeanJpsi",fFitTotal->GetParameter(6),fFitTotal->GetParError(6));
-  Set("SigmaJpsi",fFitTotal->GetParameter(7),fFitTotal->GetParError(7));
-  
-  double m = MeanJpsi();
-  double s = SigmaJpsi();
-  double n = 3.0;
-  
-  TF1* fcb = new TF1("fcb",funcCB,xmin,xmax,5);
-  fcb->SetParameters(fFitTotal->GetParameter(3),
-                     fFitTotal->GetParameter(4),
-                     fFitTotal->GetParameter(5),
-                     fFitTotal->GetParameter(6),
-                     fFitTotal->GetParameter(7));
-  
-  fcb->SetLineColor(6);
-  fcb->SetNpx(100);
-  TLine* l1 = new TLine(m-n*s,0,m-n*s,fFitTotal->GetParameter(3));
-  TLine* l2 = new TLine(m+n*s,0,m+n*s,fFitTotal->GetParameter(3));
-  l1->SetLineColor(6);
-  l2->SetLineColor(6);
-  h.GetListOfFunctions()->Add(fcb);
-  h.GetListOfFunctions()->Add(l1);
-  h.GetListOfFunctions()->Add(l2);
-  
-  
-  Double_t cbParameters[5];
-  Double_t covarianceMatrix[5][5];
-  
-  cbParameters[0] = fFitTotal->GetParameter(3);
-  cbParameters[1] = fFitTotal->GetParameter(4);
-  cbParameters[2] = fFitTotal->GetParameter(5);
-  cbParameters[3] = fFitTotal->GetParameter(6);
-  cbParameters[4] = fFitTotal->GetParameter(7);
-  
-  for ( int iy = 0; iy < 5; ++iy )
-  {
-    for ( int ix = 0; ix < 5; ++ix )
-    {
-      covarianceMatrix[ix][iy] = (r->GetCovarianceMatrix())(ix+3,iy+3);
-    }
-  }
-  
-  double njpsi = fcb->Integral(m-n*s,m+n*s)/h.GetBinWidth(1);
-  
-  double nerr = fcb->IntegralError(m-n*s,m+n*s,&cbParameters[0],&covarianceMatrix[0][0])/h.GetBinWidth(1);
-  
-  Set("NofJpsi",njpsi,nerr);
-}
-
-//_____________________________________________________________________________
-void AliAnalysisMuMu::Result::FitJpsiPCBE(TH1& h)
-{
-  std::cout << "Fit with jpsi alone (pol2 + CB + expo)" << std::endl;
-  
-  const Double_t xmin(2.0);
-  const Double_t xmax(5.0);
-  
-  fFitTotal = new TF1("fFitTotal",funcJpsiPCBE,xmin,xmax,10);
-  fFitTotal->SetParNames("p0","p1","p2","N","alpha","n","mean","sigma","expocste","exposlope");
-  
-  fFitTotal->SetParLimits(3,0,h.GetMaximum()*2); // N
-
-  const Double_t cbalpha(0.98);
-  const Double_t cbn(5.2);
-  
-  fFitTotal->FixParameter(4,cbalpha);
-  fFitTotal->FixParameter(5,cbn);
-  
-  fFitTotal->SetParLimits(6,2,4); // mean
-  fFitTotal->SetParLimits(7,0.05,0.2); // sigma
-  
-  TF1* fpol2 = new TF1("pol2","pol2",xmin,xmax);
-                       
-  h.Fit(fpol2,"+","",2,2.8);
-  
-  fFitTotal->SetParameter(0,fpol2->GetParameter(0));
-  fFitTotal->SetParameter(1,fpol2->GetParameter(1));
-  fFitTotal->SetParameter(2,fpol2->GetParameter(2));
-
-  TF1* fexpo = new TF1("expo","expo",xmin,xmax);
-  
-  h.Fit(fexpo,"+","",3.5,4.5);
-  
-  fFitTotal->SetParameter(8,fexpo->GetParameter(0));
-  fFitTotal->SetParameter(9,fexpo->GetParameter(1));
-    
-  fFitTotal->SetParameter(3,h.GetMaximum()),
-  fFitTotal->SetParameter(4,cbalpha);
-  fFitTotal->SetParameter(5,cbn);
-  fFitTotal->SetParameter(6,3.15);
-  fFitTotal->SetParameter(7,0.1);
-  
-  h.Fit(fFitTotal,"+","",2.5,5);
-    
-  Set("MeanJpsi",fFitTotal->GetParameter(6),fFitTotal->GetParError(6));
-  Set("SigmaJpsi",fFitTotal->GetParameter(7),fFitTotal->GetParError(7));
-  
-  double m = MeanJpsi();
-  double s = SigmaJpsi();
-  double n = 2.0;
-  
-  TF1* fcb = new TF1("fcb",funcCB,xmin,xmax,5);
-  fcb->SetParameters(fFitTotal->GetParameter(3),
-                     fFitTotal->GetParameter(4),
-                     fFitTotal->GetParameter(5),
-                     fFitTotal->GetParameter(6),
-                     fFitTotal->GetParameter(7));
-  
-  fcb->SetLineColor(6);
-  fcb->SetNpx(100);
-  TLine* l1 = new TLine(m-n*s,0,m-n*s,fFitTotal->GetParameter(3));
-  TLine* l2 = new TLine(m+n*s,0,m+n*s,fFitTotal->GetParameter(3));
-  l1->SetLineColor(6);
-  l2->SetLineColor(6);
-  h.GetListOfFunctions()->Add(fcb);
-  h.GetListOfFunctions()->Add(l1);
-  h.GetListOfFunctions()->Add(l2);
-  
-  
-  Set("NofJpsi",fFitTotal->Integral(m-n*s,m+n*s)/h.GetBinWidth(1),fFitTotal->IntegralError(m-n*s,m+n*s)/h.GetBinWidth(1));
-  
-  //  Set("NofJpsi",fFitTotal->Integral(0,10)/h.GetBinWidth(1),fFitTotal->IntegralError(0,10)/h.GetBinWidth(1));
-  
-}
-
-//_____________________________________________________________________________
-void AliAnalysisMuMu::Result::FitJpsiCBE(TH1& h)
-{
-  std::cout << "Fit with jpsi alone" << std::endl;
-  
-  const Double_t xmin(1.5);
-  const Double_t xmax(8.0);
-  
-  fFitTotal = new TF1("fFitTotal",funcJpsiCBE,xmin,xmax,7);
-  fFitTotal->SetParNames("N","alpha","n","mean","sigma","expocste","exposlope");
-  
-//  fFitTotal->SetParameters(h.GetMaximum(),1,5,3.0,0.07,1.5,3,1,0);
-
-  fFitTotal->SetParameters(1,1.15,3.6,3.0,0.07,1,-1);
-
-  fFitTotal->SetParLimits(0,0,h.GetMaximum()); // N
-//  fFitTotal->SetParLimits(1,0.1,2); // alpha
-  fFitTotal->FixParameter(1,0.98);
-//  fFitTotal->SetParLimits(2,0.01,5); // n
-  fFitTotal->FixParameter(2,5.2);
-  fFitTotal->SetParLimits(3,2.8,3.5); // mean
-  fFitTotal->SetParLimits(4,0.05,0.2); // sigma
-  
-  TF1* fexpo = new TF1("expo","expo",xmin,xmax);
-  
-  h.Fit(fexpo,"+","",2,3);
-  
-  fFitTotal->SetParameter(5,fexpo->GetParameter(0));
-  fFitTotal->SetParameter(6,fexpo->GetParameter(1));
-  
-  h.Fit(fFitTotal,"+","",2,5);
-  
-  
-  Set("MeanJpsi",fFitTotal->GetParameter(3),fFitTotal->GetParError(3));
-  Set("SigmaJpsi",fFitTotal->GetParameter(4),fFitTotal->GetParError(4));
-  
-  double m = MeanJpsi();
-  double s = SigmaJpsi();
-  double n = 2.0;
-  
-  TF1* fcb = new TF1("fcb",funcCB,xmin,xmax,5);
-  fcb->SetParameters(fFitTotal->GetParameter(0),
-                     fFitTotal->GetParameter(1),
-                     fFitTotal->GetParameter(2),
-                     fFitTotal->GetParameter(3),
-                     fFitTotal->GetParameter(4));
-
-  fcb->SetLineColor(6);
-  fcb->SetNpx(1000);
-  TLine* l1 = new TLine(m-n*s,0,m-n*s,fFitTotal->GetParameter(0));
-  TLine* l2 = new TLine(m+n*s,0,m+n*s,fFitTotal->GetParameter(0));
-  l1->SetLineColor(6);
-  l2->SetLineColor(6);
-  h.GetListOfFunctions()->Add(fcb);
-  h.GetListOfFunctions()->Add(l1);
-  h.GetListOfFunctions()->Add(l2);
-  
-  
-  Set("NofJpsi",fFitTotal->Integral(m-n*s,m+n*s)/h.GetBinWidth(1),fFitTotal->IntegralError(m-n*s,m+n*s)/h.GetBinWidth(1));
-  
-  //  Set("NofJpsi",fFitTotal->Integral(0,10)/h.GetBinWidth(1),fFitTotal->IntegralError(0,10)/h.GetBinWidth(1));
-  
-}
-
-//_____________________________________________________________________________
-void AliAnalysisMuMu::Result::FitJpsiECBE(TH1& h)
-{
-  std::cout << "Fit with jpsi alone (expo + CB + expo)" << std::endl;
-  
-  const Double_t xmin(1.5);
-  const Double_t xmax(8.0);
-  
-  fFitTotal = new TF1("fFitTotal",funcJpsiECBE,xmin,xmax,9);
-  fFitTotal->SetParNames("e0","s0","N","alpha","n","mean","sigma","e1","s1");
-  
-  fFitTotal->SetParameters(1,-1,1,1.15,3.6,3.2,0.06,-1);
-
-  fFitTotal->SetParLimits(0,0,h.GetMaximum()*2);
-  
-  fFitTotal->FixParameter(3,0.98); // alpha
-  fFitTotal->FixParameter(4,5.2); // n
-  fFitTotal->SetParLimits(5,2.8,3.5); // mean
-  fFitTotal->SetParLimits(6,0.05,0.2); // sigma
-  
-  TF1* fexpo1 = new TF1("expo1","expo",xmin,xmax);
-  TF1* fexpo2 = new TF1("expo2","expo",xmin,xmax);
-  
-  h.Fit(fexpo1,"","",1.5,3);
-  
-  fFitTotal->SetParameter(0,fexpo1->GetParameter(0));
-  fFitTotal->SetParameter(1,fexpo1->GetParameter(1));
-
-  h.Fit(fexpo2,"","",3.5,5.0);
-
-  fFitTotal->SetParameter(7,fexpo2->GetParameter(0));
-  fFitTotal->SetParameter(8,fexpo2->GetParameter(1));
-
-  const char* fitOption = "SI+";
-  
-  TFitResultPtr r = h.Fit(fFitTotal,fitOption,"",2,5);
-  
-  Set("MeanJpsi",fFitTotal->GetParameter(5),fFitTotal->GetParError(5));
-  Set("SigmaJpsi",fFitTotal->GetParameter(6),fFitTotal->GetParError(6));
-  
-  double m = MeanJpsi();
-  double s = SigmaJpsi();
-  double n = 3.0;
-  
-  TF1* fcb = new TF1("fcb",funcCB,xmin,xmax,5);
-  fcb->SetParameters(fFitTotal->GetParameter(2),
-                     fFitTotal->GetParameter(3),
-                     fFitTotal->GetParameter(4),
-                     fFitTotal->GetParameter(5),
-                     fFitTotal->GetParameter(6));
-
-  fcb->SetParError(0,fFitTotal->GetParError(2));
-  fcb->SetParError(1,fFitTotal->GetParError(3));
-  fcb->SetParError(2,fFitTotal->GetParError(4));
-  fcb->SetParError(3,fFitTotal->GetParError(5));
-  fcb->SetParError(4,fFitTotal->GetParError(6));
-  
-  fcb->SetLineColor(6);
-  fcb->SetNpx(1000);
-  TLine* l1 = new TLine(m-n*s,0,m-n*s,fFitTotal->GetParameter(2));
-  TLine* l2 = new TLine(m+n*s,0,m+n*s,fFitTotal->GetParameter(2));
-  l1->SetLineColor(6);
-  l2->SetLineColor(6);
-  h.GetListOfFunctions()->Add(fcb);
-  h.GetListOfFunctions()->Add(l1);
-  h.GetListOfFunctions()->Add(l2);
-  
-  
-  Double_t cbParameters[5];
-  Double_t covarianceMatrix[5][5];
-  
-  cbParameters[0] = fFitTotal->GetParameter(2);
-  cbParameters[1] = fFitTotal->GetParameter(3);
-  cbParameters[2] = fFitTotal->GetParameter(4);
-  cbParameters[3] = fFitTotal->GetParameter(5);
-  cbParameters[4] = fFitTotal->GetParameter(6);
-  
-  for ( int iy = 0; iy < 5; ++iy )
-  {
-    for ( int ix = 0; ix < 5; ++ix )
-    {
-      covarianceMatrix[ix][iy] = (r->GetCovarianceMatrix())(ix+2,iy+2);
-    }
-  }
-  
-
-  double njpsi = fcb->Integral(m-n*s,m+n*s)/h.GetBinWidth(1);
-  
-  double nerr = fcb->IntegralError(m-n*s,m+n*s,&cbParameters[0],&covarianceMatrix[0][0])/h.GetBinWidth(1);
-  
-
-  Set("NofJpsi",njpsi,nerr);
-}
-
-//_____________________________________________________________________________
-void AliAnalysisMuMu::Result::FitJpsi(TH1& h)
-{
-  std::cout << "Fit with jpsi alone" << std::endl;
-
-  const Double_t xmin(1.5);
-  const Double_t xmax(8.0);
-
-  fFitTotal = new TF1("fFitTotal",funcCB2,xmin,xmax,7);
-  fFitTotal->SetParNames("N","alpha","n","mean","sigma","alphaprime","nprime");
-  fFitTotal->SetParameters(h.GetMaximum(),1,5,3.0,0.07,1.5,3);
-  fFitTotal->SetParLimits(0,0,h.GetMaximum()*2); // N
-  fFitTotal->SetParLimits(1,0,10); // alpha
-  fFitTotal->SetParLimits(2,1,10); // n
-  fFitTotal->SetParLimits(3,1,4); // mean
-  fFitTotal->SetParLimits(4,0.01,1); // sigma
-  fFitTotal->SetParLimits(5,0,10); // alpha
-  fFitTotal->SetParLimits(6,1,10); // n
-  
-  h.Fit(fFitTotal,"+","",2,5);
-  
-  
-  Set("MeanJpsi",fFitTotal->GetParameter(3),fFitTotal->GetParError(3));
-  Set("SigmaJpsi",fFitTotal->GetParameter(4),fFitTotal->GetParError(4));
-
-  double m = MeanJpsi();
-  double s = SigmaJpsi();
-  double n = 2.0;
-  
-  Set("NofJpsi",fFitTotal->Integral(m-n*s,m+n*s)/h.GetBinWidth(1),fFitTotal->IntegralError(m-n*s,m+n*s)/h.GetBinWidth(1));
-
-//  Set("NofJpsi",fFitTotal->Integral(0,10)/h.GetBinWidth(1),fFitTotal->IntegralError(0,10)/h.GetBinWidth(1));
-
-}
-
-//_____________________________________________________________________________
-void AliAnalysisMuMu::Result::FitUpsilon(TH1& h)
-{
-  std::cout << "Fit with upsilon alone" << std::endl;
-  
-  const Double_t xmin(6.0);
-  const Double_t xmax(12.0);
-  
-  fFitTotal = new TF1("fFitTotal",funcCB2,xmin,xmax,7);
-  fFitTotal->SetParNames("N","alpha","n","mean","sigma","alphaprime","nprime");
-  fFitTotal->SetParameters(h.GetMaximum(),1,5,9.46,0.2,1.5,3);
-  fFitTotal->SetParLimits(0,0,h.GetMaximum()*2); // N
-  fFitTotal->SetParLimits(1,0,10); // alpha
-  fFitTotal->SetParLimits(2,1,10); // n
-  fFitTotal->SetParLimits(3,8,12); // mean
-  fFitTotal->SetParLimits(4,0.01,1); // sigma
-  fFitTotal->SetParLimits(5,0,10); // alpha
-  fFitTotal->SetParLimits(6,1,10); // n
-  
-  h.Fit(fFitTotal,"+","",6,12);
-  
-  
-  Set("MeanUpsilon",fFitTotal->GetParameter(3),fFitTotal->GetParError(3));
-  Set("SigmaUpsilon",fFitTotal->GetParameter(4),fFitTotal->GetParError(4));
-  
-  double m = MeanUpsilon();
-  double s = SigmaUpsilon();
-  double n = 2.0;
-  
-  Set("NofUpsilon",fFitTotal->Integral(m-n*s,m+n*s)/h.GetBinWidth(1),fFitTotal->IntegralError(m-n*s,m+n*s)/h.GetBinWidth(1));  
-}
-
-//_____________________________________________________________________________
-void AliAnalysisMuMu::Result::Fit(Int_t nrebin)
-{
-  //  new TCanvas;
-  
-  static int n(0);
-  
-  fRebin = nrebin;
-  
-//  TH2* h2 = static_cast<TH2*>(fHC->Histo("MinvUSPt"));  
-//  int binptmin = h2->GetXaxis()->FindBin(2.0);
-//  TH1* hminv = static_cast<TH1*>(h2->ProjectionY("minv0",binptmin,h2->GetXaxis()->GetNbins()));
-  
-  TH1* hminv = fHC->Histo("MinvUSPt:py");
-  
-  if (!hminv || hminv->GetEntries()<100 ) return;
-    
-  fMinv = static_cast<TH1*>(hminv->Clone(Form("minv%d",n)));
-  fMinv->Rebin(fRebin);
-  fMinv->SetDirectory(0);
-//  fMinv->SetStats(false);
-  fMinv->SetTitle(TriggerClass());
-                  
-  if ( ( fFitType & kJpsi ) &&
-      ( fFitType & kJpsiPrime ) )
-  {
-    FitJpsiJpsiPrimeCustom(*fMinv);
-//    FitJpsiJpsiPrimeCB(*fMinv);
-  }
-  else if ( ( fFitType & kJpsi ) && ( fFitType & kPbPb2011 ) )
-  {
-    if ( fFitType & kMatchAny )
-    {
-      FitJpsiECBE(*fMinv); // for MATCH
-    }
-    else
-    {
-      //    FitJpsiPCBE(*fMinv);
-      FitJpsiGCBE(*fMinv); // for MATCHLOW      
-    }
-    fMinv->GetXaxis()->SetRangeUser(2.0,5.0);
-    fMinv->SetMarkerStyle(kFullDotMedium);
-    fMinv->SetMarkerColor(kBlue);
-    fMinv->SetLineColor(kBlue);
-    fMinv->SetDrawOption("EP");
-  }
-  else
-  {
-    int bminjpsi = fMinv->GetXaxis()->FindBin(2);
-    int bmaxjpsi = fMinv->GetXaxis()->FindBin(4);
-
-    int bminupsilon = fMinv->GetXaxis()->FindBin(8);
-    int bmaxupsilon = fMinv->GetXaxis()->FindBin(12);
-
-    if ( fMinv->Integral(bminjpsi,bmaxjpsi) > 100.0 ) FitJpsi(*fMinv);
-    if ( fMinv->Integral(bminupsilon,bmaxupsilon) > 100.0 ) FitUpsilon(*fMinv);
-  }
-  
-  TH2* hpp = static_cast<TH2*>(fHC->Histo("MinvPPPt"));
-  TH2* hmm = static_cast<TH2*>(fHC->Histo("MinvMMPt"));
-  
-  if ( hpp && hmm )
-  {
-    TH2* htmp = static_cast<TH2*>(hpp->Clone("htmp"));
-    htmp->SetDirectory(0);
-    htmp->Add(hmm);
-    htmp->Scale(0.5);
-  
-    fMinvLS = htmp->ProjectionY();
-    fMinvLS->SetDirectory(0);
-    fMinvLS->Rebin(fRebin);
-      
-    delete htmp;
-  }
-  else
-  {
-    AliDebug(1,Form("hpp=%p hmm=%p",hpp,hmm)); // this might happen for small runs and
-    // strict cuts on pairs
-  }
-  
-//  Print();
-}
-
-//_____________________________________________________________________________
-TMap* AliAnalysisMuMu::Result::Map() const
-{
-  if (!fMap)
-  {
-    fMap = new TMap;
-    fMap->SetOwnerKeyValue(kTRUE,kTRUE);
-  }
-  return fMap;
-}
+TString AliAnalysisMuMu::fgOCDBPath("raw://");
 
-//_____________________________________________________________________________
-void AliAnalysisMuMu::Result::Set(const char* name, double value, double error)
-{
-  TObjArray* p = static_cast<TObjArray*>(Map()->GetValue(name));
-  if (!p) 
-  {
-    TParameter<double>* v = new TParameter<double>(name,value);
-    TParameter<double>* e = new TParameter<double>(name,error);
-    p = new TObjArray;
-    p->SetOwner(kTRUE);
-    p->Add(v);
-    p->Add(e);
-    Map()->Add(new TObjString(name),p);
-  }
-  else
-  {
-    TParameter<double>* v = static_cast<TParameter<double>*>(p->At(0));
-    TParameter<double>* e = static_cast<TParameter<double>*>(p->At(1));
-    v->SetVal(value);
-    e->SetVal(error);    
-  }
-}
+TString AliAnalysisMuMu::fgDefaultDimuonTriggers("CMUL7-B-NOPF-MUON,CMUL7-S-NOPF-ALLNOTRD,CMUL7-S-NOPF-MUON,CMUL8-S-NOPF-MUON,CMUL7-B-NOPF-ALLNOTRD,CMUU7-B-NOPF-ALLNOTRD,CMUU7-B-NOPF-MUON,CPBI1MUL-B-NOPF-MUON,CMULLO-B-NOPF-MUON");
 
-//_____________________________________________________________________________
-Bool_t AliAnalysisMuMu::Result::HasValue(const char* name) const
-{
-  return ( Map()->GetValue(name) != 0x0 );
-}
-
-//_____________________________________________________________________________
-Double_t AliAnalysisMuMu::Result::GetValue(const char* name) const
-{
-  TObjArray* p = static_cast<TObjArray*>(Map()->GetValue(name));
-  if (p)
-  {
-    TParameter<double>* val = static_cast<TParameter<double>*>(p->At(0));
-    return val->GetVal();
-  }
-  return 0.0;
-}
+TString AliAnalysisMuMu::fgDefaultMuonTriggers("CMSL7-S-NOPF-MUON,CMSL7-S-NOPF-ALLNOTRD,CMSL8-S-NOPF-MUON,CMSL8-S-NOPF-ALLNOTRD,CMSL7-B-NOPF-MUON,CMUS1-B-NOPF-MUON,CMUS7-B-NOPF-MUON,CMSNGL-B-NOPF-MUON");
 
-//_____________________________________________________________________________
-Double_t AliAnalysisMuMu::Result::GetError(const char* name) const
-{
-  TObjArray* p = static_cast<TObjArray*>(Map()->GetValue(name));
-  if (p)
-  {
-    TParameter<double>* val = static_cast<TParameter<double>*>(p->At(1));
-    return val->GetVal();
-  }
-  return 0.0;
-}
+TString AliAnalysisMuMu::fgDefaultMinbiasTriggers("CINT7-B-NOPF-ALLNOTRD,CINT7-S-NOPF-ALLNOTRD,CINT8-B-NOPF-ALLNOTRD,CINT8-S-NOPF-ALLNOTRD,CINT1-B-NOPF-ALLNOTRD,CPBI2_B1-B-NOPF-ALLNOTRD");
 
-//_____________________________________________________________________________
-void AliAnalysisMuMu::Result::Print(Option_t* /*opt*/) const
-{
-  std::cout << Form("%20s - %s %s %s - NRUNS %d - NTRIGGER %10d",
-               GetName(),
-               EventSelection(),
-                    PairSelection(),
-                    CentralitySelection(),
-                    NofRuns(),
-               NofTriggers()) << std::endl;
-  
-  if (NofJpsi())
-  {
-    std::cout << Form("\t\tNjpsi %7.2f +- %5.2f \n\t\tRatio (x10^4) %7.2f +- %5.2f CHI2/NDF %5.2f"
-                 "\n\t\tPEAK %7.2f +- %5.2f Gev/c^2 SIGMA %7.2f +- %5.2f MeV/c^2",
-                 NofJpsi(),ErrorOnNofJpsi(),
-                 NofJpsi()*1E4/fNofTriggers,
-                 ErrorOnNofJpsi()*1E4/fNofTriggers,
-                 (fFitTotal ? fFitTotal->GetChisquare()/fFitTotal->GetNDF() : 0),
-                 MeanJpsi(),ErrorOnMeanJpsi(),
-                 1E3*SigmaJpsi(),1E3*ErrorOnSigmaJpsi()) << std::endl;
+TString AliAnalysisMuMu::fgDefaultEventSelectionList("PSALL");
 
-  }
+TString AliAnalysisMuMu::fgDefaultPairSelectionList("pMATCHLOWRABSBOTH");
 
-  if (NofJpsiPrime())
-  {
-    std::cout << Form("\t\tNjpsiPrime %7.2f +- %5.2f \n\t\tRatio (x10^4) %7.2f +- %5.2f CHI2/NDF %5.2f"
-                 "\n\t\tPEAK %7.2f +- %5.2f Gev/c^2 SIGMA %7.2f +- %5.2f MeV/c^2",
-                 NofJpsiPrime(),ErrorOnNofJpsiPrime(),
-                 NofJpsiPrime()*1E4/fNofTriggers,
-                 ErrorOnNofJpsiPrime()*1E4/fNofTriggers,
-                 (fFitTotal ? fFitTotal->GetChisquare()/fFitTotal->GetNDF() : 0),
-                 MeanJpsiPrime(),ErrorOnMeanJpsiPrime(),
-                 1E3*SigmaJpsiPrime(),1E3*ErrorOnSigmaJpsiPrime()) << std::endl;
-    
-  }
-  
-  if ( NofUpsilon() )
-  {
-    std::cout << Form("\t\tNupsilon %7.2f +- %5.2f \n\t\tRatio (x10^4) %7.2f +- %5.2f CHI2/NDF %5.2f"
-                 "\n\t\tPEAK %7.2f +- %5.2f Gev/c^2 SIGMA %7.2f +- %5.2f MeV/c^2",
-                 NofUpsilon(),ErrorOnNofUpsilon(),
-                 NofUpsilon()*1E4/fNofTriggers,
-                 ErrorOnNofUpsilon()*1E4/fNofTriggers,
-                 (fFitTotal ? fFitTotal->GetChisquare()/fFitTotal->GetNDF() : 0),
-                 MeanUpsilon(),ErrorOnMeanUpsilon(),
-                 1E3*SigmaUpsilon(),1E3*ErrorOnSigmaUpsilon()) << std::endl;
-  }
-}
+TString AliAnalysisMuMu::fgDefaultCentralitySelectionList("PP");
 
+Bool_t AliAnalysisMuMu::fgIsCompactGraphs(kFALSE);
 
 //_____________________________________________________________________________
-TString FindTrigger(const AliHistogramCollection& hc,
+TString FindTrigger(const AliMergeableCollection& mc,
                     const char* base,
                     const char* selection,
                     const char* paircut,
@@ -1203,105 +103,55 @@ TString FindTrigger(const AliHistogramCollection& hc,
   }
   trigger2test.push_back("ANY");
   
-  for ( std::vector<std::string>::size_type i = 0; i < trigger2test.size(); ++i ) 
+  for ( std::vector<std::string>::size_type i = 0; i < trigger2test.size(); ++i )
   {
     std::string trigger = trigger2test[i];
     
-    if ( hc.Histo(selection,trigger.c_str(),centrality,paircut,"MinvUSPt") )
+    if ( mc.GetObject(Form("/%s/%s/%s/%s",selection,trigger.c_str(),centrality,paircut),"MinvUS") ||
+        mc.GetObject(Form("/%s/%s/%s/%s",selection,trigger.c_str(),centrality,paircut),"MinvUSPt")
+        )
     {
       return trigger.c_str();
     }
   }
   
-//  AliWarningGeneral("FindTrigger",Form("DID NOT FIND TRIGGER base=%s selection=%s paircut=%s centrality=%s",
-//                  base,selection,paircut,centrality));
-//  for ( std::vector<std::string>::size_type i = 0; i < trigger2test.size(); ++i ) 
-//  {
-//    AliWarningGeneral("FindTrigger",Form("tested trigger = %s",trigger2test[i].c_str()));
-//  }
+  //  AliWarningGeneral("FindTrigger",Form("DID NOT FIND TRIGGER base=%s selection=%s paircut=%s centrality=%s",
+  //                  base,selection,paircut,centrality));
+  //  for ( std::vector<std::string>::size_type i = 0; i < trigger2test.size(); ++i )
+  //  {
+  //    AliWarningGeneral("FindTrigger",Form("tested trigger = %s",trigger2test[i].c_str()));
+  //  }
   return "";
 }
 
 //_____________________________________________________________________________
-//_____________________________________________________________________________
-//_____________________________________________________________________________
-//_____________________________________________________________________________
-//_____________________________________________________________________________
-
-TString AliAnalysisMuMu::fgOCDBPath("raw://");
-
-TString AliAnalysisMuMu::fgDefaultDimuonTriggers("CMUL7-S-NOPF-ALLNOTRD,CMUL7-S-NOPF-MUON,CMUL8-S-NOPF-MUON,CMUL7-B-NOPF-ALLNOTRD,CMUL7-B-NOPF-MUON,CMUU7-B-NOPF-ALLNOTRD,CMUU7-B-NOPF-MUON,CPBI1MUL-B-NOPF-MUON");
-
-TString AliAnalysisMuMu::fgDefaultMuonTriggers("CMSL7-S-NOPF-MUON,CMSL7-S-NOPF-ALLNOTRD,CMSL8-S-NOPF-MUON,CMSL8-S-NOPF-ALLNOTRD,CMSL7-B-NOPF-MUON,CMUS1-B-NOPF-MUON,CMUS7-B-NOPF-MUON");
-
-TString AliAnalysisMuMu::fgDefaultMinbiasTriggers("CINT7-B-NOPF-ALLNOTRD,CINT7-S-NOPF-ALLNOTRD,CINT8-B-NOPF-ALLNOTRD,CINT8-S-NOPF-ALLNOTRD,CINT1-B-NOPF-ALLNOTRD,CPBI2_B1-B-NOPF-ALLNOTRD");
-
-TString AliAnalysisMuMu::fgDefaultEventSelectionList("ALL");
-
-TString AliAnalysisMuMu::fgDefaultPairSelectionList("pMATCHLOWRABSDCABOTH");
-
-//_____________________________________________________________________________
 AliAnalysisMuMu::AliAnalysisMuMu(const char* filename) : TObject(),
 fFilename(filename),
-fHistogramCollection(0x0),
 fCounterCollection(0x0),
 fDimuonTriggers(fgDefaultDimuonTriggers),
 fMuonTriggers(fgDefaultMuonTriggers),
 fMinbiasTriggers(fgDefaultMinbiasTriggers),
 fEventSelectionList(fgDefaultEventSelectionList),
-fPairSelectionList(fgDefaultPairSelectionList)
+fPairSelectionList(fgDefaultPairSelectionList),
+fCentralitySelectionList(fgDefaultCentralitySelectionList),
+fBinning(0x0),
+fMergeableCollection(0x0),
+fRunNumbers(),
+fCorrectionPerRun(0x0)
 {
   // ctor
   
-  GetCollections(fFilename,fHistogramCollection,fCounterCollection);
+  GetCollections(fFilename,fMergeableCollection,fCounterCollection,fBinning,fRunNumbers);
 }
 
 //_____________________________________________________________________________
 AliAnalysisMuMu::~AliAnalysisMuMu()
 {
   // dtor
-  gROOT->CloseFiles();
   delete fCounterCollection;
-  delete fHistogramCollection;
-}
-
-//_____________________________________________________________________________
-void AliAnalysisMuMu::CentralityCheck(const char* filelist)
-{
-  // Check if we get correctly filled centrality
-  
-  TObjArray* files = ReadFileList(filelist);
-  
-  if (!files || files->IsEmpty() ) return;
-  
-  TIter next(files);
-  TObjString* str;
-  
-  while ( ( str = static_cast<TObjString*>(next()) ) )
-  {
-    AliHistogramCollection* hc(0x0);
-    AliCounterCollection* cc(0x0);
-    
-    if (!GetCollections(str->String().Data(),hc,cc)) continue;
-    
-    int run = RunNumberFromFileName(str->String().Data());
-    
-    TH1* h = hc->Histo("/ALL/CPBI1MUL-B-NOPF-MUON/Centrality");
-    float percent(0);
-    
-    if (h)
-    {
-      percent = 100*h->Integral(1,1)/h->Integral();
-    }
-    
-    std::cout << Form("RUN %09d PERCENT %7.2f",run,percent) << std::endl;
-    
-    delete hc;
-  }
-  
-  gROOT->CloseFiles();
-  
+  delete fBinning;
+  delete fMergeableCollection;
+  delete fCorrectionPerRun;
 }
 
 //_____________________________________________________________________________
@@ -1321,7 +171,7 @@ void AliAnalysisMuMu::BasicCounts(Bool_t detailTriggers,
   // if detailTriggers is kTRUE, each kind of (MB,MUL,MSL) is counted separately
   //
   
-  if (!fHistogramCollection || !fCounterCollection) return;
+  if (!fMergeableCollection || !fCounterCollection) return;
   
   TObjArray* runs = fCounterCollection->GetKeyWords("run").Tokenize(",");
   TIter nextRun(runs);
@@ -1470,6 +320,86 @@ void AliAnalysisMuMu::BasicCountsEvolution(const char* filelist, Bool_t detailTr
 }
 
 //_____________________________________________________________________________
+void AliAnalysisMuMu::CentralityCheck(const char* filelist)
+{
+  // Check if we get correctly filled centrality
+  
+  TObjArray* files = ReadFileList(filelist);
+  
+  if (!files || files->IsEmpty() ) return;
+  
+  TIter next(files);
+  TObjString* str;
+  
+  while ( ( str = static_cast<TObjString*>(next()) ) )
+  {
+    AliMergeableCollection* mc(0x0);
+    AliCounterCollection* cc(0x0);
+    AliAnalysisMuMuBinning* bin(0x0);
+    std::set<int> runnumbers;
+    
+    if (!GetCollections(str->String().Data(),mc,cc,bin,runnumbers)) continue;
+    
+    int run = RunNumberFromFileName(str->String().Data());
+    
+    TH1* h = mc->Histo("/ALL/CPBI1MUL-B-NOPF-MUON/Centrality");
+    
+    float percent(0);
+    
+    if (h)
+    {
+      percent = 100*h->Integral(1,1)/h->Integral();
+    }
+    
+    std::cout << Form("RUN %09d PERCENT %7.2f",run,percent) << std::endl;
+    
+    delete mc;
+  }
+  
+  gROOT->CloseFiles();
+  
+}
+
+
+//_____________________________________________________________________________
+void AliAnalysisMuMu::Compact(TGraph& g)
+{
+  /// Compact (i.e. get the equivalent of 1 bin = 1 run number for an histogram)
+  /// the graph.
+  /// Only works if the x content of this graph represents run numbers. Otherwise
+  /// result is unpredictable ;-)
+  
+  if ( !g.GetN() ) return;
+  
+  TGraph* newgraph = static_cast<TGraph*>(g.Clone());
+  Double_t x,xerr,y,yerr;
+  TGraphErrors* ge = dynamic_cast<TGraphErrors*>(newgraph);
+  
+  TAxis* axis = g.GetXaxis();
+  
+  for ( Int_t i = 0; i < newgraph->GetN(); ++i )
+  {
+    g.GetPoint(i,x,y);
+    if (ge)
+    {
+      xerr = ge->GetErrorX(i);
+      yerr = ge->GetErrorY(i);
+    }
+    
+    g.SetPoint(i,i+0.5,y);
+    if (ge)
+    {
+      static_cast<TGraphErrors&>(g).SetPointError(i,0.5,yerr);
+    }
+    
+    axis->SetBinLabel(i,Form("%d",TMath::Nint(x)));
+  }
+  
+  
+}
+
+
+//_____________________________________________________________________________
 TObjArray* AliAnalysisMuMu::CompareJpsiPerCMUUWithBackground(const char* jpsiresults,
                                                                    const char* backgroundresults)
 {
@@ -1622,7 +552,8 @@ TGraph* AliAnalysisMuMu::CompareJpsiPerCMUUWithSimu(const char* realjpsiresults,
 
 //_____________________________________________________________________________
 TObjArray* AliAnalysisMuMu::ComputeBackgroundEvolution(const char* filelist, 
-                                                       const char* triggerList, 
+                                                       const char* triggerList,
+                                                       Double_t ptmin,
                                                        const char* outputFile,
                                                        const char* outputMode)
 {
@@ -1637,7 +568,7 @@ TObjArray* AliAnalysisMuMu::ComputeBackgroundEvolution(const char* filelist,
   TIter next(files);
   TObjString* str;
   
-  const char* ps = "ALL";
+  const char* ps = "PSALL";
   const char* centrality = "PP";
   const char* ts1 = "sMATCHLOWRABS";
   const char* ts2 = "sMATCHLOWRABSDCA";
@@ -1658,17 +589,26 @@ TObjArray* AliAnalysisMuMu::ComputeBackgroundEvolution(const char* filelist,
   {
     AliInfoClass(str->String().Data());
     
-    AliHistogramCollection* hc(0x0);
+    AliMergeableCollection* mc(0x0);
     AliCounterCollection* cc(0x0);
+    AliAnalysisMuMuBinning* bin(0x0);
+    std::set<int> runnumbers;
     
-    if (!GetCollections(str->String().Data(),hc,cc)) continue;
+    if (!GetCollections(str->String().Data(),mc,cc,bin,runnumbers)) continue;
     
-    TIter nextHisto(hc->CreateIterator());
-    TH1* h;
+    TIter nextObject(mc->CreateIterator());
+    TObject* o;
     int nplus(0), nminus(0);
     
-    while ( ( h = static_cast<TH1*>(nextHisto()) ) )
+    while ( (  o = nextObject() ) )
     {
+      if ( o->InheritsFrom("TH1") )
+      {
+        continue;
+      }
+      
+      TH1* h = static_cast<TH1*>(o);
+      
       if ( TString(h->GetName()).EndsWith("Plus") )
       {
         nplus++;
@@ -1705,22 +645,25 @@ TObjArray* AliAnalysisMuMu::ComputeBackgroundEvolution(const char* filelist,
         format = "/%s/%s/%s/%s/PtEtaMu:py";
       }
       
-      h1p = hc->Histo(Form(format.Data(),ps,trigger->String().Data(),centrality,ts1));
+      TString hname(Form(format.Data(),ps,trigger->String().Data(),centrality,ts1));
+      
+      h1p = mc->Histo(hname.Data());
       
       if (!h1p)
       {
+        AliInfoClass(Form("Could not get %s",hname.Data()));
         continue;
       }
       
       AliInfoClass(Form("Will use trigger %s",trigger->String().Data()));
       
-      h2p = hc->Histo(Form(format.Data(),ps,trigger->String().Data(),centrality,ts2));
+      h2p = mc->Histo(Form(format.Data(),ps,trigger->String().Data(),centrality,ts2));
       
       if ( bothSigns )
       {
         format.ReplaceAll("Plus","Minus");
-        h1m = hc->Histo(Form(format.Data(),ps,trigger->String().Data(),centrality,ts1));
-        h2m = hc->Histo(Form(format.Data(),ps,trigger->String().Data(),centrality,ts2));
+        h1m = mc->Histo(Form(format.Data(),ps,trigger->String().Data(),centrality,ts1));
+        h2m = mc->Histo(Form(format.Data(),ps,trigger->String().Data(),centrality,ts2));
       }
       else
       {
@@ -1730,19 +673,31 @@ TObjArray* AliAnalysisMuMu::ComputeBackgroundEvolution(const char* filelist,
       
       if (h1m && h2m && h1p && h2p)
       {
+        Int_t bin1 = h1m->GetXaxis()->FindBin(ptmin);
+        Int_t bin2 = h1m->GetXaxis()->GetNbins();
+
         runs[trigger->String().Data()].push_back(RunNumberFromFileName(str->String().Data()));
         errruns[trigger->String().Data()].push_back(0.5);
-        
-        double value = 100-h2m->Integral()*100/h1m->Integral();
+
+        double e1,e2;
+        double v1 = h2m->IntegralAndError(bin1,bin2,e1);
+        double v2 = h1m->IntegralAndError(bin1,bin2,e2);
+        double value = 100*(1.0-v1/v2);
+        e1/=v1;
+        e2/=v2;
         yminus[trigger->String().Data()].push_back(value);
-        double e1 = 1.0/TMath::Sqrt(h1m->GetEntries());
-        double e2 = 1.0/TMath::Sqrt(h2m->GetEntries());
+//        double e1 = 1.0/TMath::Sqrt(h1m->GetEntries());
+//        double e2 = 1.0/TMath::Sqrt(h2m->GetEntries());
         erryminus[trigger->String().Data()].push_back(TMath::Sqrt(e1*e1+e2*e2)*value);
         
-        value = 100-h2p->Integral()*100/h1p->Integral();
+        v1=h2p->IntegralAndError(bin1,bin2,e1);
+        v2=h1p->IntegralAndError(bin1,bin2,e1);
+        value = 100*(1.0-v1/v2);
+        e1/=v1;
+        e2/=v2;
         yplus[trigger->String().Data()].push_back(value);
-        e1 = 1.0/TMath::Sqrt(h1p->GetEntries());
-        e2 = 1.0/TMath::Sqrt(h2p->GetEntries());
+//        e1 = 1.0/TMath::Sqrt(h1p->GetEntries());
+//        e2 = 1.0/TMath::Sqrt(h2p->GetEntries());
         erryplus[trigger->String().Data()].push_back(TMath::Sqrt(e1*e1+e2*e2)*value);
       }
       else
@@ -1751,7 +706,7 @@ TObjArray* AliAnalysisMuMu::ComputeBackgroundEvolution(const char* filelist,
       }
     }
     
-    delete hc;
+    delete mc;
     delete cc;
     TFile* f = static_cast<TFile*>(gROOT->GetListOfFiles()->FindObject(str->String().Data()));    
     delete f;
@@ -1795,8 +750,7 @@ TObjArray* AliAnalysisMuMu::ComputeBackgroundEvolution(const char* filelist,
 //_____________________________________________________________________________
 TMap*
 AliAnalysisMuMu::ComputeJpsiEvolution(const char* filelist, const char* triggerList,
-                                      const char* outputFile, const char* outputMode,
-                                      Bool_t simulation)
+                                      const char* outputFile)
 {
   /// Compute some jpsi information for a list of files / trigger combinations
   
@@ -1809,34 +763,27 @@ AliAnalysisMuMu::ComputeJpsiEvolution(const char* filelist, const char* triggerL
   
   TIter nextFile(files);
   TObjString* str;
-  UInt_t fitType(0);
+  TString fitType;
   
-  while ( ( str = static_cast<TObjString*>(nextFile()) ) )
-  {
-    std::cout << str->String().Data() << std::endl;
-    
-    AliAnalysisMuMu m(str->String().Data());
-    
-    m.SetDimuonTriggerList(triggerList);
-    m.SetEventSelectionList("ALL");
-    
-    TObjArray* array = m.Jpsi(simulation); // the array will contain results for all triggers in fDimuonTriggers variable
-    
-    if (!array)
-    {
-      AliWarningClass(Form("Got no jpsi for %s",str->String().Data()));
-    }
-    else
-    {
-      Result* r = static_cast<Result*>(array->First());
-      if (!r) continue;
-      fitType = r->FitType();
-    }
-    
-    results.Add(new TObjString(str->String()), array);
-  }
-  
-  if (!results.GetSize()) return 0x0;
+//  while ( ( str = static_cast<TObjString*>(nextFile()) ) )
+//  {
+//    std::cout << str->String().Data() << std::endl;
+//    
+//    AliAnalysisMuMu m(str->String().Data());
+//    
+//    m.SetDimuonTriggerList(triggerList);
+//        
+//    TMap* map = m.Jpsi();
+//    
+//    if (!map)
+//    {
+//      AliWarningClass(Form("Got no jpsi for %s",str->String().Data()));
+//    }
+//    
+//    results.Add(new TObjString(str->String()), map);
+//  }
+//  
+//  if (!results.GetSize()) return 0x0;
   
   // compute the total over all files
   
@@ -1853,67 +800,79 @@ AliAnalysisMuMu::ComputeJpsiEvolution(const char* filelist, const char* triggerL
   {
     nextFile.Reset();
     
-    Int_t nruns(0);
-    Int_t n(0);
-    TList l;    
-    Result* ref(0x0);
-    AliHistogramCollection* hc(0x0);
+    TList l;
+    AliAnalysisMuMuResult* ref(0x0);
     
     while ( ( str = static_cast<TObjString*>(nextFile()) ) )
     {
-      TObjArray* a = static_cast<TObjArray*>(results.GetValue(str->String().Data()));
+//      TObjArray* a = static_cast<TObjArray*>(results.GetValue(str->String().Data()));
       
-      Result* r(0x0);
+      AliInfoClass("FIXME: write the merging of AliAnalysisMuMuResult objects !");
       
-      if (a)
-      {
-        r = static_cast<Result*>(a->FindObject(trigger->String().Data()));
-        
-        if (r)
-        {
-          if (!ref) ref = r;
-
-          if ( !hc )
-          {
-            AliHistogramCollection* htmp = r->HC();
-            if (!htmp)
-            {
-              continue;
-            }
-            hc = static_cast<AliHistogramCollection*>(htmp->Clone(Form("hc%d",0)));
-          }
-          else
-          {
-            l.Add(r->HC());
-          }
-          
-          n += r->NofTriggers();
-          ++nruns;
-        }
-      }
+//      AliAnalysisMuMuResult* r(0x0);
+//      
+//      if (a)
+//      {
+//        r = static_cast<AliAnalysisMuMuResult*>(a->FindObject(trigger->String().Data()));
+//        
+//        if (r)
+//        {
+//          if (!ref) ref = r;
+//
+//          if ( !hminv )
+//          {
+//            TH1* htmp = static_cast<TH1*>(r->Minv()->Clone());
+//            if (!htmp)
+//            {
+//              continue;
+//            }
+//            hminv = htmp;
+//          }
+//          else
+//          {
+//            l.Add(r->Minv());
+//          }
+//          
+//          n += r->NofTriggers();
+//          ++nruns;
+//        }
+//      }
     }
     
-    hc->Merge(&l);
+//    sum->Merge(&l);
     
     if (!ref) continue;
     
-    Result* sum = new Result(ref->TriggerClass(),ref->EventSelection(),
-                             ref->PairSelection(),ref->CentralitySelection(),
-                             n,hc,1,fitType);
 
-    sum->SetNofRuns(nruns);
-    
-    total->Add(new TObjString(trigger->String().Data()),sum);
+//    AliAnalysisMuMuResult* sum = new AliAnalysisMuMuResult(*hminv,
+//                                                           ref->TriggerClass(),
+//                                                           ref->EventSelection(),
+//                                                           ref->PairSelection(),
+//                                                           ref->CentralitySelection(),
+//                                                           AliAnalysisMuMuBinning::Range());
+//
+//    sum->SetNofTriggers(n);
+//    
+//    sum->SetNofRuns(nruns);
+//    
+//    sum->Fit(1);
+//    
+//    total->Add(new TObjString(trigger->String().Data()),sum);
     
   }
 
+  AliInfoClass("--------------------------------------");
   StdoutToAliInfoClass(total->Print(););
+
+  AliInfoClass("---------------------------Going to write file");
+
+  TFile* fout = new TFile(outputFile,"RECREATE");
   
-  TFile* fout = new TFile(outputFile,outputMode);
-  
-  results.Write("rbr",TObject::kSingleKey|TObject::kOverwrite);
+  results.Write("rbr",TObject::kSingleKey);
   
-  total->Write("total",TObject::kSingleKey|TObject::kOverwrite);
+  total->Write("total",TObject::kSingleKey);
+
+  fout->Close();
   
   delete fout;
   
@@ -2018,20 +977,58 @@ Bool_t AliAnalysisMuMu::DecodeFileName(const char* filename,
   return kTRUE;
 }
 
-//______________________________________________________________________________
-void AliAnalysisMuMu::DrawFill(Int_t run1, Int_t run2, double ymin, double ymax, const char* label)
+//_____________________________________________________________________________
+void AliAnalysisMuMu::DrawMinv(const char* type,
+                               const char* particle,
+                               const char* trigger,
+                               const char* eventType,
+                               const char* pairCut,
+                               const char* centrality) const
 {
-  AliDebugClass(1,Form("RUN1 %09d RUN2 %09d YMIN %e YMAX %e %s",
-                       run1,run2,ymin,ymax,label));
-  TBox* b = new TBox(run1*1.0,ymin,run2*1.0,ymax);
-  b->SetFillColor(5);
-  b->Draw();
-  TText* text = new TText((run1+run2)/2.0,ymax*0.85,label);
-  text->SetTextSize(0.025);
-  text->SetTextFont(42);
-  text->SetTextAlign(23);
-  text->SetTextAngle(45);
-  text->Draw();
+  /// Draw minv spectra for binning of given type
+  
+  if (!MC() || !BIN()) return;
+  
+  TObjArray* bins = BIN()->CreateBinObjArray(particle,type);
+  if (!bins)
+  {
+    AliError(Form("Could not get %s bins",type));
+    return;
+  }
+  
+  TIter next(bins);
+  AliAnalysisMuMuBinning::Range* r;
+  
+  while ( ( r = static_cast<AliAnalysisMuMuBinning::Range*>(next())) )
+  {
+    TString name(Form("/%s/%s/%s/%s/MinvUS%s",eventType,trigger,centrality,pairCut,r->AsString().Data()));
+
+    AliDebug(1,name.Data());
+                 
+    TH1* h = MC()->Histo(name.Data());
+    if (h)
+    {
+      TString cname(name);
+      cname.ReplaceAll("/","_");
+      TCanvas* c = new TCanvas(cname.Data(),cname.Data());
+      c->SetLogy();
+      h->Draw("histe");
+    }
+  }
+  
+  delete bins;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMu::DrawMinv(const char* type, const char* particle) const
+{
+  /// Draw minv spectra for binning of given type
+
+  DrawMinv(type,particle,           
+           First(DimuonTriggerList()).Data(),
+           First(EventSelectionList()).Data(),
+           First(PairSelectionList()).Data(),
+           First(CentralitySelectionList()).Data());
 }
 
 //_____________________________________________________________________________
@@ -2064,6 +1061,159 @@ AliAnalysisMuMu::FileOpen(const char* file)
 }
 
 //_____________________________________________________________________________
+TString AliAnalysisMuMu::First(const TString& list) const
+{
+  TObjArray* a = list.Tokenize(",");
+  if ( a->GetLast() < 0 ) return "";
+  
+  TString rv = static_cast<TObjString*>(a->First())->String();
+  
+  delete a;
+  
+  return rv;
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuSpectra*
+AliAnalysisMuMu::FitParticle(const char* particle,
+                             const char* trigger,
+                             const char* eventType,
+                             const char* pairCut,
+                             const char* centrality,
+                             const AliAnalysisMuMuBinning& binning)
+{
+  // Fit the minv spectra to find the given particle
+  // Returns an array of AliAnalysisMuMuResult objects
+  
+  static int n(0);
+  
+  TObjArray* bins = binning.CreateBinObjArray(particle);
+  if (!bins)
+  {
+    AliError(Form("Did not get any bin for particle %s",particle));
+    return 0x0;
+  }
+  
+  TObjArray* triggers = fCounterCollection->GetKeyWords("trigger").Tokenize(",");
+  if ( !triggers->FindObject(trigger) )
+  {
+    AliDebug(1,Form("Did not find trigger %s",trigger));
+    delete bins;
+    delete triggers;
+    return 0x0;
+  }
+  delete triggers;
+  
+  TObjArray* events = fCounterCollection->GetKeyWords("event").Tokenize(",");
+  if ( !events->FindObject(eventType) )
+  {
+    AliError(Form("Did not find eventType %s",eventType));
+    delete bins;
+    delete events;
+    return 0x0;
+  }
+  delete events;
+
+  Int_t ntrigger = TMath::Nint(fCounterCollection->GetSum(Form("trigger:%s/event:%s",trigger,eventType)));
+  
+  if  (ntrigger<=0)
+  {
+    AliError(Form("No trigger for trigger:%s/event:%s",trigger,eventType));
+    delete bins;
+    return 0x0;
+  }
+  
+//  AliDebug(1,Form("will project fMergeableCollection=%p...",fMergeableCollection));
+//  
+//  AliMergeableCollection* hp = fMergeableCollection->Project(Form("/%s/%s/%s/%s/",eventType,trigger,centrality,pairCut));
+//  
+//  AliDebug(1,Form("projection=hp=%p",hp));
+  
+//  if (!hp)
+//  {
+//    AliError(Form("projection %s/%s/%s/%s failed",eventType,trigger,centrality,pairCut));
+//    delete bins;
+//    return 0x0;
+//  }
+  
+  binning.Print();
+  
+  AliAnalysisMuMuSpectra* spectra(0x0);
+  
+  AliAnalysisMuMuBinning::Range* bin;
+  TIter next(bins);
+  Int_t nrebin=1;
+  
+  while ( ( bin = static_cast<AliAnalysisMuMuBinning::Range*>(next())) )
+  {
+    TString hname(Form("MinvUS%s",bin->AsString().Data()));
+    
+//    TH1* hminv = hp->Histo(hname.Data());
+    TH1* hminv = fMergeableCollection->Histo(Form("/%s/%s/%s/%s",eventType,trigger,centrality,pairCut),hname.Data());
+    
+    if (!hminv)
+    {
+      if (!fBinning && bin->IsNullObject() )
+      {
+        // old file, we only had MinvUSPt
+        hminv = fMergeableCollection->Histo(Form("/%s/%s/%s/%s",eventType,trigger,centrality,pairCut),"MinvUSPt:py");
+      }
+      
+      if (!hminv)
+      {
+        AliDebug(1,Form("Could not find histo %s",hname.Data()));
+        continue;
+      }
+    }
+    
+    hminv = static_cast<TH1*>(hminv->Clone(Form("minv%d",n++)));
+    
+    
+    AliAnalysisMuMuResult* r = new AliAnalysisMuMuResult(*hminv,
+                                                         trigger,
+                                                         eventType,
+                                                         pairCut,
+                                                         centrality,
+                                                         *bin);
+    
+    r->SetNofTriggers(ntrigger);
+    
+//    r->AddFit("PSILOW",nrebin);
+    if (IsSimulation())
+    {
+      r->AddFit("PSI1",1);
+      r->AddFit("COUNTPSI",1);
+    }
+    else
+    {
+      r->AddFit("PSILOW",nrebin+1);
+    }
+//    r->AddFit("PSILOW",nrebin+2);
+//    r->AddFit("PSILOW",nrebin+3);
+    
+//    r->Print();
+  
+    if (!spectra)
+    {
+      spectra = new AliAnalysisMuMuSpectra(binning.GetName());
+    }
+    
+    spectra->AdoptResult(*bin,r);
+    
+    if ( IsSimulation() )
+    {
+      SetNofInputParticles(*r);
+    }
+  
+    
+  } // loop on bins
+  
+  delete bins;
+  
+  return spectra;
+}
+
+//_____________________________________________________________________________
 ULong64_t AliAnalysisMuMu::GetTriggerScalerCount(const char* triggerList, Int_t runNumber)
 {
   // Get the expected (from OCDB scalers) trigger count
@@ -2090,7 +1240,8 @@ ULong64_t AliAnalysisMuMu::GetTriggerScalerCount(const char* triggerList, Int_t
 }
 
 //_____________________________________________________________________________
-UInt_t AliAnalysisMuMu::GetSum(AliCounterCollection& cc, const char* triggerList, const char* eventSelection, Int_t runNumber)
+UInt_t AliAnalysisMuMu::GetSum(AliCounterCollection& cc, const char* triggerList,
+                               const char* eventSelection, Int_t runNumber)
 {
   TObjArray* ktrigger = cc.GetKeyWords("trigger").Tokenize(",");
   TObjArray* kevent = cc.GetKeyWords("event").Tokenize(",");
@@ -2128,33 +1279,137 @@ UInt_t AliAnalysisMuMu::GetSum(AliCounterCollection& cc, const char* triggerList
 }
 
 //_____________________________________________________________________________
-TObjArray* 
-AliAnalysisMuMu::Jpsi(Bool_t simulation)
+Bool_t
+AliAnalysisMuMu::GetCollections(const char* rootfile,
+                                AliMergeableCollection*& mc,
+                                AliCounterCollection*& cc,
+                                AliAnalysisMuMuBinning*& bin,
+                                std::set<int>& runnumbers)
 {
-  // Fit the J/psi (and psiprime) peaks for the triggers in fDimuonTriggers list
+  mc = 0x0;
+  cc = 0x0;
+  bin = 0x0;
   
-  TObjArray* a = new TObjArray;
-  a->SetOwner(kTRUE);
+  TFile* f = static_cast<TFile*>(gROOT->GetListOfFiles()->FindObject(rootfile));
+  if (!f)
+  {
+    f = TFile::Open(rootfile);
+  }
   
-  if ( simulation )
+  if ( !f || f->IsZombie() )
   {
-    const char* selection = "ALL";
+    return kFALSE;
+  }
+
+  f->GetObject("MC",mc);
+  f->GetObject("CC",cc);
+  
+  TIter next(f->GetListOfKeys());
+  TKey* key;
+  
+  while ( ( key = static_cast<TKey*>(next())) && !bin )
+  {
+    if ( strcmp(key->GetClassName(),"AliAnalysisMuMuBinning")==0 )
+    {
+      bin = dynamic_cast<AliAnalysisMuMuBinning*>(key->ReadObj());
+    }
+  }
+  
+  if (!mc || !cc)
+  {
+    AliErrorClass("Old file. Please upgrade it!");
     
-    Add(a,GetResult(*fHistogramCollection,*fCounterCollection,"ANY",selection,"pMATCHLOWRABSBOTH","PP",Result::kJpsi));
+    return kFALSE;
   }
-  else
+  
+  // get run list
+  TObjArray* runs = cc->GetKeyWords("run").Tokenize(",");
+  runs->Sort();
+  TIter nextRun(runs);
+  TObjString* srun;
+
+  runnumbers.clear();
+  
+  while ( ( srun = static_cast<TObjString*>(nextRun()) ) )
   {
-    TObjArray* triggerArray = fDimuonTriggers.Tokenize(",");
-    TObjArray* eventTypeArray = fEventSelectionList.Tokenize(",");
-    TObjArray* pairCutArray = fPairSelectionList.Tokenize(",");
+    runnumbers.insert(srun->String().Atoi());
+  }
+  
+  delete runs;
+  
+  return kTRUE;
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMu::IsSimulation() const
+{
+  // whether or not we have MC information
+  
+  return ( fMergeableCollection->Histo("/INPUT/ALL/MinvUS") != 0x0 );
+}
+
+//_____________________________________________________________________________
+Int_t
+AliAnalysisMuMu::Jpsi(const char* what)
+{
+  // Fit the J/psi (and psiprime) peaks for the triggers in fDimuonTriggers list
+  // what="" => fit only fully integrated MinvUS
+  // what="pt" => fit MinvUS in pt bins
+  // what="y" => fit MinvUS in y bins
+  // what="pt,y" => fit MinvUS in (pt,y) bins
+  
+  if (!fMergeableCollection)
+  {
+    AliError("No mergeable collection. Consider Upgrade()");
+    return 0;
+  }
+  
+  Int_t nfits(0);
+  
+  TObjArray* triggerArray = fDimuonTriggers.Tokenize(",");
+  TObjArray* eventTypeArray = fEventSelectionList.Tokenize(",");
+  TObjArray* pairCutArray = fPairSelectionList.Tokenize(",");
+  TObjArray* whatArray = TString(what).Tokenize(",");
+  
+  if ( whatArray->GetEntries() <= 0 )
+  {
+    whatArray->Add(new TObjString(""));
+  }
+  
+  TIter nextTrigger(triggerArray);
+  TIter nextEventType(eventTypeArray);
+  TIter nextPairCut(pairCutArray);
+  TIter nextWhat(whatArray);
+  
+  TObjString* trigger;
+  TObjString* eventType;
+  TObjString* pairCut;
+  TObjString* swhat;
+  
+  while ( ( swhat = static_cast<TObjString*>(nextWhat()) ) )
+  {    
+    AliAnalysisMuMuBinning* binning(0x0);
     
-    TIter nextTrigger(triggerArray);
-    TIter nextEventType(eventTypeArray);
-    TIter nextPairCut(pairCutArray);
+    if ( fBinning && swhat->String().Length() > 0 )
+    {
+      binning = fBinning->Project("psi",swhat->String().Data());
+    }
+    else
+    {
+      binning = new AliAnalysisMuMuBinning;
+      binning->AddBin("psi",swhat->String().Data());
+    }
     
-    TObjString* trigger;
-    TObjString* eventType;
-    TObjString* pairCut;
+    std::cout << "++++++++++++ swhat=" << swhat->String().Data() << std::endl;
+    
+    if (!binning)
+    {
+      AliError("oups. binning is NULL");
+      continue;
+    }
+    binning->Print();
+    
+    nextTrigger.Reset();
     
     while ( ( trigger = static_cast<TObjString*>(nextTrigger())) )
     {
@@ -2164,42 +1419,178 @@ AliAnalysisMuMu::Jpsi(Bool_t simulation)
       
       while ( ( eventType = static_cast<TObjString*>(nextEventType())) )
       {
-        AliDebug(1,Form("EVENTTYPE %s",eventType->String().Data()));
+        AliDebug(1,Form("--EVENTTYPE %s",eventType->String().Data()));
         
         nextPairCut.Reset();
         
         while ( ( pairCut = static_cast<TObjString*>(nextPairCut())) )
         {
-          AliDebug(1,Form("PAIRCUT %s",pairCut->String().Data()));
-          Add(a,GetResult(*fHistogramCollection,*fCounterCollection,
-                          trigger->String().Data(),
-                          eventType->String().Data(),
-                          pairCut->String().Data(),
-                          "PP",
-                          Result::kJpsi | Result::kJpsiPrime,2));
+          AliDebug(1,Form("----PAIRCUT %s",pairCut->String().Data()));
+          
+          AliDebug(1,"----Fitting...");
+          
+          AliAnalysisMuMuSpectra* spectra = FitParticle("psi",
+                                                  trigger->String().Data(),
+                                                  eventType->String().Data(),
+                                                  pairCut->String().Data(),
+                                                  "PP",
+                                                  *binning);
+          
+          AliDebug(1,Form("----fitting done spectra = %p",spectra));
+          
+          if ( spectra )
+          {
+            ++nfits;
+            
+            TString id(Form("/%s/%s/PP/%s",eventType->String().Data(),
+                            trigger->String().Data(),
+                            pairCut->String().Data()));
+            
+            TObject* o = fMergeableCollection->GetObject(id.Data(),spectra->GetName());
+          
+            AliDebug(1,Form("----nfits=%d id=%s o=%p",nfits,id.Data(),o));
+            
+            if (o)
+            {
+              AliWarning(Form("Replacing %s/%s",id.Data(),spectra->GetName()));
+              fMergeableCollection->Remove(Form("%s/%s",id.Data(),spectra->GetName()));
+            }
+          
+            fMergeableCollection->Adopt(id.Data(),spectra);
+            
+            spectra->Print();
+          }
         }
       }
     }
-    
-    delete triggerArray;
-    delete eventTypeArray;
-    delete pairCutArray;
   }
   
-  if ( a->GetLast() < 0 )
+  delete whatArray;
+  delete triggerArray;
+  delete eventTypeArray;
+  delete pairCutArray;
+  
+  if (nfits)
   {
-    delete a;
-    a = 0;
+    ReOpen(fFilename,"UPDATE");
+    fMergeableCollection->Write("MC",TObjArray::kOverwrite);// | TObjArray::kSingleKey);
+    ReOpen(fFilename,"READ");
   }
-  return a;
+  return nfits;
+  
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMu::PlotBackgroundEvolution(const char* gfile, const char* triggerList, Double_t ymax, Bool_t fillBoundaries)
+{
+  // plot the graphs found in the file (and generated using the ComputeBackgroundEvolution() method)
+  
+  TFile* f = TFile::Open(ExpandPathName(gfile).Data());
+  
+  if ( !f || !f->IsOpen() )
+  {
+    return;
+  }
+  
+  SetColorScheme();
+  
   
+  TCanvas* c = new TCanvas("background-evolution","background-evolution");
+  
+  c->Draw();
+  
+  TLegend* l = new TLegend(0.4,0.6,0.97,0.97);
+  l->SetFillColor(0);
+  l->SetTextColor(AliAnalysisMuMu::kBlue);
+  l->SetLineColor(AliAnalysisMuMu::kBlue);
+  
+  TObjArray* triggers = TString(triggerList).Tokenize(",");
+  
+  gStyle->SetOptTitle(0);
+  
+  TObjString* str(0x0);
+  TIter next(triggers);
+  Int_t i(0);
+  Int_t run1(99999999);
+  Int_t run2(0);
+  
+  std::set<int> runnumbers;
+  
+  while ( ( str = static_cast<TObjString*>(next()) ) )
+  {
+    TGraph* g = static_cast<TGraph*>(f->Get(Form("mu_%s",str->String().Data())));
+    if (!g) continue;
+    for ( Int_t ir = 0; ir < g->GetN(); ++ir )
+    {
+      Int_t run = TMath::Nint(g->GetX()[ir]);
+      runnumbers.insert(run);
+      run1 = TMath::Min(run1,run);
+      run2 = TMath::Max(run2,run);
+    }
+  }
+  
+  AliInfoClass(Form("run1 %d run2 %d",run1,run2));
+  
+  Double_t ymin(0);
+  
+  TH2* hframe = new TH2F("hframe","hframe",run2-run1+1,run1,run2,100,ymin,ymax);
+  hframe->Draw();
+  hframe->GetXaxis()->SetNoExponent();
+  hframe->GetYaxis()->SetTitle("Background percentage");
+  
+  if (fillBoundaries)
+  {
+    AliAnalysisTriggerScalers ts(runnumbers,fgOCDBPath.Data());
+    ts.DrawFills(ymin,ymax);
+  }
+  
+  next.Reset();
+  
+  while ( ( str = static_cast<TObjString*>(next()) ) )
+  {
+    TGraph* g = static_cast<TGraph*>(f->Get(Form("mu_%s",str->String().Data())));
+    if (!g)
+    {
+      AliErrorClass(Form("Graph mu_%s not found",str->String().Data()));
+      continue;
+    }
+    
+    Int_t color(i+1);
+    
+    if (i==0) color = AliAnalysisMuMu::kBlue;
+    if (i==1) color = AliAnalysisMuMu::kOrange;
+    
+    g->SetLineColor(color);
+    g->SetMarkerColor(color);
+    g->SetMarkerStyle(20+i);
+    
+    g->Draw("LP");
+    
+    TLegendEntry* le = l->AddEntry(g,str->String().Data(),"lp");
+    le->SetTextColor(color);
+    
+    g->GetYaxis()->SetTitleColor(AliAnalysisMuMu::kBlue);
+    g->GetXaxis()->SetTitleColor(AliAnalysisMuMu::kBlue);
+    //    g->Print();
+    
+    ++i;
+  }
+  
+  hframe->Draw("sameaxis");
+  
+  l->Draw();
 }
 
 //_____________________________________________________________________________
 void
 AliAnalysisMuMu::PlotJpsiEvolution(const char* resultFile, const char* triggerList, Bool_t fillBoundaries,
-                                   const char* efficiencyFile)
+                                   const char* efficiencyFile, Bool_t simulation)
 {
+  /// Will plot the Jpsi rate (or AccxEff if simulation=kTRUE) evolution.
+  /// (JpsiRate is the number of Jpsi divided by the number of triggers)
+  
+  std::map<int, float> efficiencies;
+  
   if ( efficiencyFile && strlen(efficiencyFile) > 0 )
   {
     std::ifstream in(gSystem->ExpandPathName(efficiencyFile));
@@ -2207,20 +1598,24 @@ AliAnalysisMuMu::PlotJpsiEvolution(const char* resultFile, const char* triggerLi
     {
       char line[1024];
       int run;
-      float eff, error;
+      float eff;
+      float dummy,errorl,errorh;
+      int idummy;
       while ( in.getline(line,1023,'\n') )
       {
-        sscanf(line,"%d %f ± %f",&run,&eff,&error);
-        AliInfoClass(Form("%09d %8.6f ± %8.6f",run,eff,error));
+        sscanf(line,"%d, x[%d]=%f, y[%d]=%f, exl[%d]=%f, exh[%d]=%f, eyl[%d]=%f, eyh[%d]=%f",
+               &run,&idummy,&dummy,&idummy,&eff,&idummy,&dummy,&idummy,&dummy,&idummy,&errorl,&idummy,&errorh);
+
+        AliDebugClass(1,Form("%09d %8.6f +- %8.6f ",run,eff,errorl+errorh));
+
+        efficiencies[run] = eff;
       }
     }
-    
-    return;
   }
   
   TFile* f = TFile::Open(gSystem->ExpandPathName(resultFile));
   
-  std::map<int, std::pair<int,int> > fills;
+  std::set<int> runnumbers;
   
   TMap* m = static_cast<TMap*>(f->Get("rbr"));
 
@@ -2250,18 +1645,24 @@ AliAnalysisMuMu::PlotJpsiEvolution(const char* resultFile, const char* triggerLi
 
   TIter nextFile(&files);
 
+  Double_t ymin(TMath::Limits<double>::Max());
+  Double_t ymax(TMath::Limits<double>::Min());
+  
+
   while ( ( trigger = static_cast<TObjString*>(nextTrigger())))
   {
+    Double_t sumw(0);
+    Double_t n(0);
+    
     TString triggerClass(trigger->String());
     
     nextFile.Reset();
-    
-    
+        
     while ( ( str = static_cast<TObjString*>(nextFile())) )
     {
       TObjArray* a = static_cast<TObjArray*>(m->GetValue(str->String().Data()));
       if (!a) continue;
-      Result* r = static_cast<Result*>(a->FindObject(triggerClass.Data()));
+      AliAnalysisMuMuResult* r = static_cast<AliAnalysisMuMuResult*>(a->FindObject(triggerClass.Data()));
       if (!r) continue;
 
       TString period;
@@ -2269,77 +1670,107 @@ AliAnalysisMuMu::PlotJpsiEvolution(const char* resultFile, const char* triggerLi
 
       if ( DecodeFileName(str->String().Data(),period,esdpass,aodtrain,runnumber) )
       {
+        runnumbers.insert(runnumber);
+        
         runMin = TMath::Min(runMin,runnumber);
         runMax = TMath::Max(runMax,runnumber);
         
         x_jpsirate[triggerClass.Data()].push_back(runnumber);
         xerr_jpsirate[triggerClass.Data()].push_back(0.5);
-
-        if ( fillBoundaries )
-        {
-          AliAnalysisTriggerScalers ts(runnumber,fgOCDBPath.Data());
-          int fill = ts.GetFillNumberFromRunNumber(runnumber);
-          
-          if (fills.count(fill))
-          {
-            std::pair<int,int>& p = fills[fill];
-            p.first = TMath::Min(runnumber,p.first);
-            p.second = TMath::Max(runnumber,p.second);
-          }
-          else
-          {
-            fills[fill] = std::make_pair<int,int>(runnumber,runnumber);
-          }
-        }
         
         Double_t y(0.0);
         Double_t yerr(0.0);
+        TString what("RateJpsi");
+        if ( simulation )
+        {
+          what = "AccEffJpsi";
+        }
         
-        if ( TMath::Finite(r->SigmaJpsi()) && r->NofTriggers() > 10 )
+        if ( TMath::Finite(r->GetValue("SigmaJpsi")) && r->NofTriggers() > 10 )
         {
-          y = 100*r->NofJpsi()/r->NofTriggers();
+          y = 100*r->GetValue(what.Data());
+          yerr = 100*r->GetErrorStat(what.Data());
           
-          if ( r->NofJpsi() > 0 )
+          if  (!efficiencies.empty() )
           {
-            yerr = y * TMath::Sqrt( (r->ErrorOnNofJpsi()*r->ErrorOnNofJpsi())/(r->NofJpsi()*r->NofJpsi()) + 1.0/r->NofTriggers());
+            if (efficiencies.count(runnumber))
+            {
+              y /= ( efficiencies[runnumber] );
+            }
+            else
+            {
+              continue;
+            }
           }
+          
+          ymin = TMath::Min(ymin,y);
+          ymax = TMath::Max(ymax,y);
+          
+          sumw += y*r->NofTriggers();
+          n += r->NofTriggers();
         }
         
         y_jpsirate[triggerClass.Data()].push_back(y);
         yerr_jpsirate[triggerClass.Data()].push_back(yerr);
       }
     }
+    
+    AliInfoClass(Form("Trigger %30s ponderated mean is %7.2f",trigger->String().Data(),sumw/n));
   }
 
   delete f;
   
-  TCanvas* c = new TCanvas("cJpsiRateEvolution","cJpsiRateEvolution");
+  TString canvasName("cJpsiRateEvolution");
+  
+  if ( !efficiencies.empty() )
+  {
+    canvasName += "Corr";
+    
+  }
+  TCanvas* c = new TCanvas(canvasName.Data(),canvasName.Data());
   
   c->Draw();
   
-  Double_t ymin(0);
-  Double_t ymax(2);
+  Int_t nbins = runnumbers.size();
+  Int_t xmin(runMin);
+  Int_t xmax(runMax);
   
-  TH2* h = new TH2F("h","h;RunNumber;J/#psi per CMUL (%)",100,runMin,runMax,100,ymin,ymax);
+  if ( CompactGraphs() )
+  {
+    xmin = 0;
+    xmax = nbins-1;
+  }
+  
+  TH2* h = new TH2F("h",Form("h;RunNumber;%s",(simulation ? "AccxEff (%)":"J/#psi per CMUL (%)")),
+                    nbins,xmin,xmax,100,ymin,ymax*1.2);
   
   gStyle->SetOptTitle(0);
   gStyle->SetOptStat(0);
   
-  h->GetXaxis()->SetNoExponent();
+  if (!CompactGraphs())
+  {
+    h->GetXaxis()->SetNoExponent();
+  }
+  else
+  {
+    std::set<int>::const_iterator it;
+    int i(0);
+    
+    for ( it = runnumbers.begin(); it != runnumbers.end(); ++it )
+    {
+      h->GetXaxis()->SetBinLabel(i,Form("%d",*it));
+      ++i;
+    }
+    h->GetXaxis()->SetNdivisions(1,kFALSE);
+    
+  }
   
   h->Draw();
 
   if (fillBoundaries)
   {
-    std::map<int, std::pair<int,int> >::const_iterator it;
-    
-    for ( it = fills.begin(); it != fills.end(); ++it )
-    {
-      const std::pair<int,int>& p = it->second;
-      TString fillnumber;
-      fillnumber.Form("%d",it->first);
-      DrawFill(p.first,p.second,ymin,ymax,fillnumber.Data());
-    }
+    AliAnalysisTriggerScalers ts(runnumbers,fgOCDBPath);
+    ts.DrawFills(ymin,ymax);
   }
 
   h->Draw("sameaxis");
@@ -2349,7 +1780,7 @@ AliAnalysisMuMu::PlotJpsiEvolution(const char* resultFile, const char* triggerLi
   nextTrigger.Reset();
   
   int i(0);
-  int color[] = { 1,2,4,5,6 };
+  int color[] = { 2,1,4,5,6 };
   int marker[] = { 20,23,25,21,22 };
   
   while ( ( trigger = static_cast<TObjString*>(nextTrigger())))
@@ -2361,11 +1792,21 @@ AliAnalysisMuMu::PlotJpsiEvolution(const char* resultFile, const char* triggerLi
     
     TGraphErrors* g = new TGraphErrors(x.size(),&x[0],&y[0],&xerr[0],&yerr[0]);
     
-    g->SetLineColor(color[i]);
+    g->SetLineColor(1);//color[i]);
     g->SetMarkerColor(color[i]);
     g->SetMarkerStyle(marker[i]);
+    g->SetMarkerSize(0.7);
     g->GetXaxis()->SetNoExponent();
-    g->Draw("LP");
+    
+    if ( CompactGraphs() )
+    {
+      Compact(*g);
+    }
+    
+    g->Draw("P");
+    TString gname(trigger->String());
+    gname.ReplaceAll("-","_");
+    g->SetName(gname.Data());
 //    g->Print();
 
     Double_t m2 = g->GetMean(2);
@@ -2382,158 +1823,285 @@ AliAnalysisMuMu::PlotJpsiEvolution(const char* resultFile, const char* triggerLi
 }
 
 //_____________________________________________________________________________
-AliAnalysisMuMu::Result*
-AliAnalysisMuMu::GetResult(const AliHistogramCollection& hc,
-                           AliCounterCollection& cc,
-                           const char* base,
-                           const char* selection,
-                           const char* paircut,
-                           const char* centrality,
-                           UInt_t fitType,
-                           Int_t nrebin)
+TGraph* AliAnalysisMuMu::PlotEventSelectionEvolution(const char* trigger1, const char* event1,
+                                                     const char* trigger2, const char* event2,
+                                                     Bool_t drawFills,
+                                                     Bool_t asRejection) const
 {
-  Result* r(0x0);
+  if (!CC()) return 0x0;
+  
+  const std::set<int>& runnumbers = RunNumbers();
+  
+  TGraphErrors* g = new TGraphErrors(runnumbers.size());
+  
+  std::set<int>::const_iterator it;
+  Int_t i(0);
+
+  Double_t ymin(TMath::Limits<double>::Max());
+  Double_t ymax(TMath::Limits<double>::Min());
+
+  for ( it = runnumbers.begin(); it != runnumbers.end(); ++it )
+  {
+    Int_t runNumber = *it;
+    Double_t n = CC()->GetSum(Form("trigger:%s/event:%s/run:%d",trigger1,event1,runNumber));
+    Double_t d = CC()->GetSum(Form("trigger:%s/event:%s/run:%d",trigger2,event2,runNumber));
+    if (n>0 && d>0)
+    {
+      Double_t y = n/d;
+      
+      if ( fCorrectionPerRun )
+      {
+        Double_t xcorr,ycorr;
+        fCorrectionPerRun->GetPoint(i,xcorr,ycorr); // note that the fact that xcorr==runNumber has been checked by the SetCorrectionPerRun method
+        if ( TMath::Abs(ycorr)  > 1E-12 )
+        {
+          y /= ycorr;
+        }
+        else
+        {
+          y = 0.0;
+        }
+      }
+      
+      if ( asRejection ) y = 100*(1.0 - y);
+      ymin = TMath::Min(ymin,y);
+      ymax = TMath::Max(ymax,y);
+      Double_t yerr = y*AliAnalysisMuMuResult::ErrorAB(n,TMath::Sqrt(n),d,TMath::Sqrt(d));
+      g->SetPoint(i,runNumber,y);
+      g->SetPointError(i,0.5,yerr);
+      
+      ++i;
+    }
+    
+  }
 
-  TString trigger = FindTrigger(hc,base,selection,paircut,centrality);
+  TH2* hframe = new TH2F(Form("%s %s-%s / %s-%s",(asRejection ? "1 - ":""),trigger1,event1,trigger2,event2),
+                         Form("%s %s-%s / %s-%s",(asRejection ? "1 - ":""),trigger1,event1,trigger2,event2),
+                         runnumbers.size()+50,
+                         *(runnumbers.begin())-25,
+                         *(runnumbers.rbegin())+25,100,0,ymax*1.3);
+  
+  gStyle->SetOptStat(0);
+  
+  hframe->Draw();
+  
+  hframe->GetXaxis()->SetNoExponent();
+           
+  hframe->GetYaxis()->SetTitle(asRejection ? "Rejection (%)" : "Ratio");
   
-  if ( trigger == "" )
+  g->Set(i);
+  g->SetTitle(Form("%s %s-%s / %s-%s",(asRejection ? "1 - ":""),trigger1,event1,trigger2,event2));
+  g->GetXaxis()->SetNoExponent();
+  g->Draw("lp");
+
+  AliAnalysisTriggerScalers ts(RunNumbers(),fgOCDBPath.Data());
+
+  if ( drawFills )
   {
-    return 0;
+    ts.DrawFills(ymin,ymax);
+    g->Draw("lp");
   }
   
-  Int_t ntrigger = (Int_t)cc.GetSum(Form("trigger:%s/event:%s",trigger.Data(),selection));
+  
+  std::map<std::string, std::pair<int,int> > periods;
+  
+  ts.GetLHCPeriodBoundaries(periods);
+  
+  TLegend* legend = new TLegend(0.15,0.82,0.90,0.92);
+  legend->SetFillColor(0);
+  Int_t n(0);
+  
+
+  for ( std::map<std::string, std::pair<int,int> >::const_iterator pit = periods.begin(); pit != periods.end(); ++pit )
+  {
+    std::string period = pit->first;
+    int run1 = (pit->second).first;
+    int run2 = (pit->second).second;
+    int nruns(0);
+    for ( std::set<int>::const_iterator rit = RunNumbers().begin(); rit != RunNumbers().end(); ++ rit )
+    {
+      if ( (*rit) >= run1 && (*rit) <= run2 )
+      {
+        ++nruns;
+      }
+    }
+    AliInfo(Form("Period %s runs %6d-%6d ; %d actual runs",period.c_str(),run1,run2,nruns));
+    
+    g->Fit("pol0","+Q","",run1,run2);
+    TF1* func = static_cast<TF1*>(g->GetListOfFunctions()->Last());
+    if (func)
+    {
+      func->SetLineColor(2+n);
+      legend->AddEntry(func,Form("%s %5.2f #pm %5.2f %s (rel. error %5.2f %%)",period.c_str(),func->GetParameter(0),func->GetParError(0),
+                                 (asRejection ? "%":""),100*func->GetParError(0)/func->GetParameter(0)));
+      ++n;
+    }
+  }
+
+  legend->SetNColumns(3);
 
-//  new TCanvas;
+  Double_t mean = TMath::Mean(g->GetN(),g->GetY());
+  Double_t rms = TMath::RMS(g->GetN(),g->GetY());
+  
+  legend->AddEntry("",Form("Mean %5.2f RMS %5.2f (%5.2f %%)",mean,rms,(mean) ? 100.0*rms/mean : 0.0),"");
   
-  r = new Result(trigger.Data(),
-                 selection,
-                 paircut,
-                 centrality,
-                 ntrigger,
-                 hc.Project(selection,trigger,centrality,paircut),
-                 nrebin,
-                 fitType);
+  legend->Draw();
   
-  return r;
+  return g;
 }
 
 //_____________________________________________________________________________
-Bool_t
-AliAnalysisMuMu::GetCollections(const char* rootfile,
-                                      AliHistogramCollection*& hc,
-                                      AliCounterCollection*& cc)
+void AliAnalysisMuMu::Print(Option_t* opt) const
 {
-  hc = 0x0;
-  cc = 0x0;
-  
-  TFile* f = static_cast<TFile*>(gROOT->GetListOfFiles()->FindObject(rootfile));
+    /// printout
+  std::cout << "Reading from file : " << fFilename.Data() << std::endl;
+  std::cout << "List of dimuon triggers to consider : " << DimuonTriggerList() << std::endl;
+  std::cout << "List of   muon triggers to consider : " << MuonTriggerList() << std::endl;
+  std::cout << "List of     MB triggers to consider : " << MinbiasTriggerList() << std::endl;
+  std::cout << "Event selection list : " << EventSelectionList() << std::endl;
+  std::cout << "Pair  selection list : " << PairSelectionList() << std::endl;
   
-  if (!f)
+  std::cout << RunNumbers().size() << " runs";
+  if ( fCorrectionPerRun )
   {
-    f = TFile::Open(rootfile);    
+    std::cout << " with correction factors";
   }
-  
-  if ( !f || !f->IsOpen() ) 
+  std::cout << std::endl;
+  Int_t i(0);
+  for ( std::set<int>::const_iterator it = RunNumbers().begin(); it != RunNumbers().end(); ++it )
   {
-    return kFALSE;    
+    std::cout << (*it);
+    if ( fCorrectionPerRun )
+    {
+      std::cout << Form("(%e)",fCorrectionPerRun->GetY()[i]);
+    }
+    std::cout << ",";
+    ++i;
   }
+  std::cout << std::endl;
   
-  TList* list = static_cast<TList*>(f->Get("chist"));
+  TString sopt(opt);
+  sopt.ToUpper();
   
-  if (!list) return kFALSE;
-  
-  hc = static_cast<AliHistogramCollection*>(list->At(0));
-  cc = static_cast<AliCounterCollection*>(list->At(1));
+  if ( sopt.Contains("BIN") && BIN() )
+  {
+    std::cout << "Binning : " << std::endl;
+    TString topt(sopt);
+    topt.ReplaceAll("BIN","");
+    BIN()->Print(topt.Data());
+  }
+  if ( sopt.Contains("MC") && MC() )
+  {
+    TString topt(sopt);
+    topt.ReplaceAll("MC","");
+    MC()->Print(topt.Data());
+  }
+  if ( sopt.Contains("CC") && CC() )
+  {
+    CC()->Print("trigger/event");
+  }
   
-  return kTRUE;
+  if ( sopt.Contains("SIZE") )
+  {
+    TFile* f = ReOpen(fFilename,"READ");
+    TIter next(f->GetListOfKeys());
+    TKey* key;
+    
+    while ( ( key = static_cast<TKey*>(next()) ) )
+    {
+      std::cout << key->GetName() << " " << key->GetNbytes() << " " << key->GetObjlen() << std::endl;
+    }
+  }
 }
 
 //_____________________________________________________________________________
-void AliAnalysisMuMu::PlotBackgroundEvolution(const char* gfile, const char* triggerList)
+TObjArray*
+AliAnalysisMuMu::ReadFileList(const char* filelist)
 {
-  // plot the graphs found in the file (and generated using the ComputeBackgroundEvolution() method)
+  //
+  // read the filelist and try to order it by runnumber
+  //
+  // filelist can either be a real filelist (i.e. a text file containing
+  // root filenames) or a root file itself.
+  //
+  
+  char line[1024];
   
-  TFile* f = TFile::Open(ExpandPathName(gfile).Data());    
+  TObjArray* files = new TObjArray;
+  files->SetOwner(kTRUE);
   
-  if ( !f || !f->IsOpen() ) 
+  TString sfilelist(ExpandPathName(filelist));
+  
+  if ( sfilelist.EndsWith(".root") )
   {
-    return;
+    files->Add(new TObjString(sfilelist.Data()));
+    return files;
   }
   
-  SetColorScheme();
-  
-
-  TCanvas* c = new TCanvas("background-evolution","background-evolution");
+  std::set<int> runnumbers;
+  std::map<int,std::string> filemap;
   
-  c->Draw();
+  std::ifstream in(sfilelist.Data());
   
-  TLegend* l = new TLegend(0.4,0.6,0.97,0.97);
-  l->SetFillColor(0);
-  l->SetTextColor(AliAnalysisMuMu::kBlue);
-  l->SetLineColor(AliAnalysisMuMu::kBlue);
+  TString period;
+  int aodtrain,esdpass,runnumber;
   
-  TObjArray* triggers = TString(triggerList).Tokenize(",");
+  while ( in.getline(line,1022,'\n') )
+  {
+    DecodeFileName(line,period,esdpass,aodtrain,runnumber);
+    
+    AliDebugClass(1,Form("line %s => period %s esdpass %d aodtrain %d runnumber %09d",
+                         line,period.Data(),esdpass,aodtrain,runnumber));
+    
+    filemap.insert(std::make_pair<int,std::string>(runnumber,line));
+    runnumbers.insert(runnumber);
+  }
   
-  gStyle->SetOptTitle(0);
+  in.close();
   
-  TObjString* str(0x0);
-  TIter next(triggers);
-  Int_t i(0);
-  Int_t run1(99999999);
-  Int_t run2(0);
+  std::set<int>::const_iterator it;
   
-  while ( ( str = static_cast<TObjString*>(next()) ) )
+  for ( it = runnumbers.begin(); it != runnumbers.end(); ++it )
   {
-    TGraph* g = static_cast<TGraph*>(f->Get(Form("mu_%s",str->String().Data())));
-    if (!g) continue;
-    run1 = TMath::Min(run1,TMath::Nint(g->GetX()[0]));
-    run2 = TMath::Max(run2,TMath::Nint(g->GetX()[g->GetN()-1]));
+    files->Add(new TObjString(filemap[*it].c_str()));
   }
   
-  AliInfoClass(Form("run1 %d run2 %d",run1,run2));
-  
-  TH2* hframe = new TH2F("hframe","hframe",run2-run1+1,run1,run2,100,0,100);
-  hframe->Draw();
-  hframe->GetXaxis()->SetNoExponent();
-  hframe->GetYaxis()->SetTitle("Background percentage");
+  return files;
+}
 
-  next.Reset();
+//_____________________________________________________________________________
+TFile* AliAnalysisMuMu::ReOpen(const char* filename, const char* mode) const
+{
+  /// Tries to reopen the file with a new mode
   
-  while ( ( str = static_cast<TObjString*>(next()) ) )
+  TFile* f = static_cast<TFile*>(gROOT->GetListOfFiles()->FindObject(filename));
+  
+  if (f)
   {
-    TGraph* g = static_cast<TGraph*>(f->Get(Form("mu_%s",str->String().Data())));
-    if (!g)
-    {
-      AliErrorClass(Form("Graph mu_%s not found",str->String().Data()));
-      continue;
-    }
-    
-    Int_t color(i+1);
-    
-    if (i==0) color = AliAnalysisMuMu::kBlue;
-    if (i==1) color = AliAnalysisMuMu::kOrange;
-    
-    g->SetLineColor(color);
-    g->SetMarkerColor(color);
-    g->SetMarkerStyle(20+i);
-    
-    g->Draw("LP");
-    
-    TLegendEntry* le = l->AddEntry(g,str->String().Data(),"lp");
-    le->SetTextColor(color);
-    
-    g->GetYaxis()->SetTitleColor(AliAnalysisMuMu::kBlue);
-    g->GetXaxis()->SetTitleColor(AliAnalysisMuMu::kBlue);
-//    g->GetXaxis()->SetNoExponent();
-//    g->GetYaxis()->SetRangeUser(0,100);
-//    g->GetYaxis()->SetTitle("Background percentage");
-    g->Print();
-    
-    ++i;
+    f->Close();
+    delete f;
   }
   
-  l->Draw();
-  delete triggers;
+  f = TFile::Open(filename,"update");
+  
+  if ( !f || !f->IsOpen() )
+  {
+    AliError(Form("Cannot open file %s in mode %s",filename,mode));
+    return 0x0;
+  }
+  
+  return f;
+}
+
+//_____________________________________________________________________________
+Int_t
+AliAnalysisMuMu::RunNumberFromFileName(const char* filename)
+{
+  TString period;
+  int esdpass,aodtrain,runnumber;
+  Bool_t ok = DecodeFileName(filename,period,esdpass,aodtrain,runnumber);
+  if ( ok ) return runnumber;
+  return -1;
 }
 
 //_____________________________________________________________________________
@@ -2558,98 +2126,57 @@ void AliAnalysisMuMu::SetColorScheme()
 }
 
 //_____________________________________________________________________________
-void 
-AliAnalysisMuMu::SinglePtPlot(const char* rootfile)
+Bool_t AliAnalysisMuMu::SetCorrectionPerRun(const TGraph& corr)
 {
-  AliHistogramCollection* histogramCollection(0x0);
-  AliCounterCollection* counterCollection(0x0);
-  
-  if (!GetCollections(rootfile,histogramCollection,counterCollection))
-  {
-    return;
-  }
-
-  TCanvas* c1 = new TCanvas("singlept","singlept");
+    /// Sets the graph used to correct values per run
+  delete fCorrectionPerRun;
+  fCorrectionPerRun=0x0;
   
-  gStyle->SetTextSize(1.0);
+  // check that corr has the same runs as we do
   
-  c1->SetLogy();
-  
-  TLegend* l = new TLegend(0.12,0.12,0.4,0.3,"","NDC");
-  l->SetFillStyle(0);
-  l->SetLineWidth(0);
-  l->SetLineColor(0);
-  l->SetTextColor(kBlack);
-  l->SetTextFont(42);
-  l->SetTextSize(0.035);
+  Int_t i(0);
   
-  const char* cuts[] = { "ALL","ETA","ETARABS","ETARABSMATCH","ETARABSMATCHDCA" };
-  const char* cutnames[] = {
-    "all",
-    "+ -4 < #eta < -2.5",
-    "+ 171^{#circ} < #theta_{abs} < 178^{#circ}",
-    "+ trigger matching",
-    "+ PxDCA"
-  };
-  const int colors[] = { 1,2,3,4,6 };
-
-  for ( int i = 0; i < 5; ++i )
+  for ( std::set<int>::const_iterator it = RunNumbers().begin(); it != RunNumbers().end(); ++it )
   {
-    TH1* minus = histogramCollection->Histo(Form("/PS/CPBI1MSH-B-NOPF-MUON/CENT80/s%s/PtEtaMuMinus:py",cuts[i]));
-    TH1* plus = histogramCollection->Histo(Form("/PS/CPBI1MSH-B-NOPF-MUON/CENT80/s%s/PtEtaMuPlus:py",cuts[i]));
-    if (!minus || !plus)
-    {
-      AliErrorClass(Form("Form cannot get histos for cut %s",cuts[i]));
-      continue;
-    }
-    TH1* h = static_cast<TH1*>(minus->Clone(Form("h%d",i)));
-    h->Add(plus);
-    h->SetDirectory(0);
-    h->SetLineColor(colors[i]);
-    h->SetMinimum(1);
-    h->SetMarkerSize(0);
-    h->SetLineWidth(2);
-    h->SetStats(0);
-    h->SetBit(TH1::kNoTitle);
-    if (i==0)
+    Int_t corrRun = TMath::Nint(corr.GetX()[i]);
+    if (corrRun != *it)
     {
-      h->Draw("e");
-    }
-    else
-    {
-      h->Draw("esame");
+      AliError(Form("%d-th run mistmatch %d vs %d",i,corrRun,*it));
+      
+      return kFALSE;
     }
-    h->GetYaxis()->SetTitle("dN/dp_{t} (counts/0.5 GeV/c)");
-    h->GetXaxis()->SetTitle("p_{t} (GeV/c)");
-    
-    h->GetXaxis()->SetLabelSize(0.04);
-    h->GetYaxis()->SetLabelSize(0.04);
-    h->GetYaxis()->SetTitleSize(0.04);
-    h->GetXaxis()->SetTitleSize(0.04);
-
-    h->GetXaxis()->SetRangeUser(0,30);
-    l->AddEntry(h,cutnames[i]);
+    ++i;
   }
   
-  l->Draw();
-  
-  TList extralines;
-  extralines.SetOwner(kTRUE);
-  
-  extralines.Add(new TObjString("PbPb #sqrt{s_{NN}}=2.76 TeV"));
-  extralines.Add(new TObjString("MUON high p_{t} trigger events"));
-  extralines.Add(new TObjString("w/ phys. sel."));
-  extralines.Add(new TObjString("w/ reco. vertex"));
-  extralines.Add(new TObjString("centrality 0-80 %"));
+  fCorrectionPerRun = static_cast<TGraph*>(corr.Clone());
+
+  return kTRUE;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMu::SetNofInputParticles(AliAnalysisMuMuResult& r)
+{
+  /// Set the "NofInput" variable(s) of one result
   
-  ALICEseal(0.5,0.93,&extralines);
+  TString hname(Form("MinvUS%s",r.Bin().AsString().Data()));
+
+  TH1* hinput = fMergeableCollection->Histo("/INPUT/INYRANGE",hname.Data());
+
+  if (!hinput)
+  {
+    AliError(Form("Got a simulation file where I did not find histogram /INPUT/INYRANGE/%s",hname.Data()));
   
-  delete histogramCollection;
-  delete counterCollection;
+  }
+  else
+  {
+    r.SetNofInputParticles(*hinput);
+  }
 }
 
 //_____________________________________________________________________________
-void AliAnalysisMuMu::TriggerCountCoverage(const char* triggerList, Bool_t compact)
+void AliAnalysisMuMu::TriggerCountCoverage(const char* triggerList,
+                                           Bool_t compact,
+                                           Bool_t orderByTriggerCount)
 {
   // Give the fraction of triggers (in triggerList) relative 
   // to what is expected in the scalers
@@ -2660,7 +2187,7 @@ void AliAnalysisMuMu::TriggerCountCoverage(const char* triggerList, Bool_t compa
   
   AliLog::SetGlobalLogLevel(AliLog::kFatal);
   
-  if (!fHistogramCollection || !fCounterCollection) return;
+  if (!fMergeableCollection || !fCounterCollection) return;
   
   TObjArray* runs = fCounterCollection->GetKeyWords("run").Tokenize(",");
   TIter nextRun(runs);
@@ -2675,13 +2202,20 @@ void AliAnalysisMuMu::TriggerCountCoverage(const char* triggerList, Bool_t compa
   
   ULong64_t total(0);
   ULong64_t totalExpected(0);
+  TString msg;
+  std::multimap<ULong64_t,std::string> messages;
   
   while ( ( srun = static_cast<TObjString*>(nextRun()) ) )
   {
-    std::cout << Form("RUN %09d ",srun->String().Atoi());
-    
-    if (!compact) std::cout << std::endl;
+    msg.Form("RUN %09d ",srun->String().Atoi());
     
+    if (!compact)
+    {
+        msg += "\n";
+    }
+
+    ULong64_t nmax(0);
+
     nextTrigger.Reset();
     
     while ( ( strigger = static_cast<TObjString*>(nextTrigger()) ) )
@@ -2690,169 +2224,546 @@ void AliAnalysisMuMu::TriggerCountCoverage(const char* triggerList, Bool_t compa
       {
         continue;
       }
-      ULong64_t n = fCounterCollection->GetSum(Form("trigger:%s/event:%s/run:%d",
-                                                    strigger->String().Data(),"ALL",srun->String().Atoi()));
+      ULong64_t n = TMath::Nint(fCounterCollection->GetSum(Form("trigger:%s/event:%s/run:%d",
+                                                                strigger->String().Data(),"ALL",srun->String().Atoi())));
    
       ULong64_t expected = GetTriggerScalerCount(strigger->String().Data(),srun->String().Atoi());
     
       
+      nmax = TMath::Max(n,nmax);
+      
       total += n;
       totalExpected += expected;
       
-      std::cout << Form("%30s %9lld expected %9lld ",strigger->String().Data(),n,expected);
+      msg += TString::Format("%30s %9lld expected %9lld ",strigger->String().Data(),n,expected);
       
       if ( expected > 0 ) {
-        std::cout << Form("fraction %5.1f %%",n*100.0/expected);
+        msg += TString::Format("fraction %5.1f %%",n*100.0/expected);
       }
       if (!compact)
       {
-        std::cout << std::endl;
+        msg += "\n";
+      }
+    }
+    if (nmax>0)
+    {
+      if (!orderByTriggerCount)
+      {
+        std::cout << msg.Data() << std::endl;
+      }
+      else
+      {
+        messages.insert(std::make_pair<ULong64_t,std::string>(nmax,msg.Data()));
       }
     }
-    std::cout << std::endl;
   }
   
-  std::cout << Form("TOTAL %lld expected %lld fraction %5.1f %%",
-               total,totalExpected,totalExpected ? total*100.0/totalExpected : 0.0) << std::endl;
+  std::multimap<ULong64_t,std::string>::const_reverse_iterator it;
   
+  ULong64_t current(0);
+  Int_t n(0);
+  
+  for ( it = messages.rbegin(); it != messages.rend(); ++it )
+  {
+    ++n;
+    current += it->first;
+    std::cout << Form("%10lld",it->first) << " " << it->second << " percentage of total = " << Form("%7.2f %% %3d",current*100.0/total,n ) << std::endl;
+  }
+
+  std::cout << Form("--- TOTAL %lld expected %lld fraction %5.1f %%",
+                    total,totalExpected,totalExpected ? total*100.0/totalExpected : 0.0) << std::endl;
+  
+
   AliLog::SetGlobalLogLevel(oldLevel);
   delete triggers;
   delete runs;
 }
 
 //_____________________________________________________________________________
-void AnalyisResultLocation(const char* runlist, const char* basedir, const char* what)
+void AliAnalysisMuMu::UnsetCorrectionPerRun()
 {
-    std::ifstream in(runlist);
-  int run;
-  while ( in >> run )
+    // drop the correction factors
+  delete fCorrectionPerRun;
+  fCorrectionPerRun=0x0;
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMu::Upgrade(const char* filename)
+{
+  /// Upgrade a file
+  AliAnalysisMuMu m(filename);
+  
+  return m.Upgrade();
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMu::Upgrade()
+{
+  /// Upgrade the current file
+  /// - from single list to one key per object, if needed
+  /// - from histogramCollection to mergeableCollection, if needed
+
+  TFile* f = ReOpen(fFilename,"UPDATE");
+  
+  TList* list = static_cast<TList*>(f->Get("chist"));
+  
+  if (list)
   {
-    std::cout << Form("%s/%09d/%s",basedir,run,what) << std::endl;
+    // really old file where everything was in a single list
+  
+    AliHistogramCollection* hc = static_cast<AliHistogramCollection*>(list->At(0));
+    AliCounterCollection* cc = static_cast<AliCounterCollection*>(list->At(1));
+    
+    AliMergeableCollection* mc = hc->Convert();
+    
+    f->cd();
+    
+    mc->Write("MC",TObject::kSingleKey);
+    cc->Write("CC",TObject::kSingleKey);
+    
+    f->Delete("chist;*");
+    
+    f->Write();
+    
   }
+  else
+  {
+    AliHistogramCollection* hc = static_cast<AliHistogramCollection*>(f->Get("HC"));
+
+    if ( hc )
+    {
+      // old file with histogram collection instead of mergeable collection
+      
+      AliMergeableCollection* mc = hc->Convert();
+
+      f->cd();
+
+      mc->Write("MC",TObject::kSingleKey);
+
+      f->Delete("HC;*");
+      
+      f->Write();
+    }
+  }
+
+  delete f;
+  
+  return kTRUE;
 }
 
 //_____________________________________________________________________________
-void plot(const char* file="results.root", const char* pdfname="toto.pdf")
+AliAnalysisMuMuSpectra* AliAnalysisMuMu::CorrectSpectra(const char* realFile, const char* simFile, const char* particle, const char* type)
 {
-  gROOT->SetStyle("Plain");
-  gStyle->SetOptTitle(0);
   
-  TFile* f = TFile::Open(file);
+  AliAnalysisMuMu real(realFile);
+    AliAnalysisMuMu sim(simFile);
   
-  TObjArray* a = static_cast<TObjArray*>(f->Get("results"));
   
-  if (!a) return;
+  AliAnalysisMuMuSpectra* realpt = static_cast<AliAnalysisMuMuSpectra*>(real.MC()->GetObject(Form("/PSALL/CMUL7-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/%s",type)));
+  AliAnalysisMuMuSpectra* simpt = static_cast<AliAnalysisMuMuSpectra*>(sim.MC()->GetObject(Form("/ALL/CMULLO-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/%s",type)));
   
-  TCanvas* c = new TCanvas("jpsiresults","jpsiresults");
+  if ( !realpt )
+  {
+    AliErrorClass("could not get real spectra");
+    return 0x0;
+  }
   
-  c->Draw();
+  if ( !simpt )
+  {
+    AliErrorClass("could not get sim spectra");
+    return 0x0;
+  }
   
-  TLegend* l = new TLegend(0.5,0.7,0.9,0.9);
-  l->SetFillColor(0);
-  TH1* h0(0x0);
+  AliInfoClass("REAL >>>");
+  realpt->Print("4");
+  AliInfoClass("SIM >>>");
+  simpt->Print("1");
+  
+  AliInfoClass("CORRECTED >>>");
+
+  AliAnalysisMuMuSpectra* spectra = static_cast<AliAnalysisMuMuSpectra*>(realpt->Clone());
+  spectra->Correct(*simpt,particle);
+  
+  spectra->Print("1");
+  
+  return spectra;
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuSpectra* AliAnalysisMuMu::RABy(const char* realFile, const char* simFile, const char* type,
+                                               const char* direction)
+{
+  /// Compute the RAB...
+  Double_t rapidityShift = 0.465;// 0.5*TMath::Log(208.0/82.0);
+  const Double_t sqrts=5.023;
+  const Double_t ymax=TMath::Log(sqrts*1000.0/3.096916);
+  const Double_t tab = 0.093e-6; // nb^-1
+  const Double_t tabError = 0.0035E-6; // nb^-1
+  const char* accEffSubResultName="COUNTJPSI-1";
+  
+  TF1 ydist("ydist","[0]*TMath::Exp(-(x*x)/(2.0*0.39*0.39))",0.,0.5);
+  ydist.SetParameter(0,1.);
+
+  //Normalization to the values presented by Zaida and Rosana on January 11th 2013 https://indico.cern.ch/conferenceDisplay.py?confId=224985 slide 22
+  // Normalization is done in the rapidity range 2.75<y<3.25 where Rosanas values is 230.8+212.1
+  Double_t y1_norma= 2.75/ymax;
+  Double_t y2_norma= 3.25/ymax;
+  Double_t normalization = 0.25*(230.8+212.1)/ydist.Integral(y1_norma, y2_norma);
+  ydist.SetParameter(0,normalization);
+//  AliInfoClass(Form("ymax=%e normalization=%f",ymax,ydist.Integral(y1_norma, y2_norma)));
   
-  for ( int i = 0; i <= a->GetLast(); ++i ) 
+  AliAnalysisMuMu real(realFile);
+  AliAnalysisMuMu sim(simFile);
+  
+  
+  AliAnalysisMuMuSpectra* realSpectra = static_cast<AliAnalysisMuMuSpectra*>(real.MC()->GetObject(Form("/PSALL/CMUL7-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-%s",type)));
+  AliAnalysisMuMuSpectra* simSpectra = static_cast<AliAnalysisMuMuSpectra*>(sim.MC()->GetObject(Form("/ALL/CMULLO-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-%s",type)));
+  
+  if ( !realSpectra )
   {
-    AliAnalysisMuMu::Result* r = static_cast<AliAnalysisMuMu::Result*>(a->At(i));
-    r->Print();
-    
-    TH1* h = static_cast<TH1*>(r->Minv());
-    
-    h->SetStats(kFALSE);
-    h->SetXTitle("M_{#mu^{+}#mu^{-}} (Gev/c^{2})");
-    h->SetLineColor(i+1);
+    AliErrorClass("could not get real spectra");
+    return 0x0;
+  }
+  
+  if ( !simSpectra)
+  {
+    AliErrorClass("could not get sim spectra");
+    return 0x0;
+  }
+  
+  AliAnalysisMuMuSpectra* corrSpectra = static_cast<AliAnalysisMuMuSpectra*>(realSpectra->Clone());
+  corrSpectra->Correct(*simSpectra,"Jpsi",accEffSubResultName);
+  
+  Double_t nofCMUL7 = real.CC()->GetSum(Form("trigger:CMUL7-B-NOPF-MUON/event:PSALL"));
+  Double_t nofCINT7 = real.CC()->GetSum(Form("trigger:CINT7-B-NOPF-ALLNOTRD/event:PSALL"));
+  Double_t nofCINT7w0MUL = real.CC()->GetSum(Form("trigger:CINT7-B-NOPF-ALLNOTRD&0MUL/event:PSALL"));
+  
+  AliAnalysisMuMuBinning* binning = realSpectra->Binning();
+  TObjArray* bins = binning->CreateBinObjArray();
+  TIter nextBin(bins);
+  AliAnalysisMuMuBinning::Range* bin;
+  Int_t i(0);
+  AliAnalysisMuMuResult* r;
+  
+  Int_t n = bins->GetLast();
+  
+  TObjArray finalBins(n+1);
+  finalBins.SetOwner(kTRUE);
+  
+  TObjArray finalResults(n+1);
+  finalResults.SetOwner(kFALSE);
+  
+  while ( ( bin = static_cast<AliAnalysisMuMuBinning::Range*>(nextBin()) ) )
+  {
+    Double_t ylowlab = bin->Xmin();
+    Double_t yhighlab = bin->Xmax();
+
+    Double_t ylowcms, yhighcms;
+    Double_t ylownorm, yhighnorm;
     
-    h->SetMaximum(5E3);
-    h->SetMarkerStyle(0);
+    if ( bin->IsNullObject() )
+    {
+      ylowlab = -4;
+      yhighlab = -2.5;
+    }
     
-    if ( i == 0 )
+    if ( strcmp(direction,"pPb")==0 )
     {
-      h0 = h;
-      h->Draw("hist");
+      ylowcms = TMath::Abs(yhighlab) -  rapidityShift;
+      yhighcms = TMath::Abs(ylowlab) - rapidityShift;
+      ylownorm = ylowcms/ymax;
+      yhighnorm = yhighcms/ymax;
     }
     else
     {
-      h->Draw("histsame");
+      ylowcms = ylowlab - rapidityShift;
+      yhighcms = yhighlab - rapidityShift;
+      ylownorm = -yhighcms/ymax;
+      yhighnorm = -ylowcms/ymax;
     }
     
-    TObjArray* n = TString(r->TriggerClass()).Tokenize("-");
-    TObjString* nn = static_cast<TObjString*>(n->First());
-    l->AddEntry(h,Form("%6d %s",r->NofTriggers(),nn->String().Data()));
     
-    delete n;
+    Double_t brsigmapp = ydist.Integral(ylownorm,yhighnorm);
+    Double_t brsigmappError = 0.0; // FIXME
+    
+    AliInfoClass(Form("y range : LAB %f ; %f CMS %f ; %f -> ynorm : %f ; %f -> BR x sigmapp = %f",
+                      ylowlab,yhighlab,ylowcms,yhighcms,ylownorm,yhighnorm,brsigmapp));
+    
+    r = static_cast<AliAnalysisMuMuResult*>(corrSpectra->Bins()->At(i)->Clone());
+
+    AliAnalysisMuMuResult* rsim = static_cast<AliAnalysisMuMuResult*>(simSpectra->Bins()->At(i));
+    
+    Double_t mbeq = nofCINT7w0MUL / ( nofCINT7 * nofCMUL7);
+    Double_t mbeqError = mbeq * AliAnalysisMuMuResult::ErrorABC( nofCINT7w0MUL, TMath::Sqrt(nofCINT7w0MUL),
+                                         nofCINT7,TMath::Sqrt(nofCINT7),
+                                         nofCMUL7,TMath::Sqrt(nofCMUL7));
+    
+    r->Set("MBR",nofCINT7/nofCINT7w0MUL,(nofCINT7/nofCINT7w0MUL)*AliAnalysisMuMuResult::ErrorAB( nofCINT7w0MUL, TMath::Sqrt(nofCINT7w0MUL),
+                                                                      nofCINT7,TMath::Sqrt(nofCINT7)));
+    
+    Double_t yield =  r->GetValue("CorrNofJpsi") * mbeq;
+
+    Double_t yieldError = yield * AliAnalysisMuMuResult::ErrorAB( r->GetValue("CorrNofJpsi"), r->GetErrorStat("CorrNofJpsi"),
+                                          mbeq,mbeqError);
+    
+    r->Set(Form("Y%sJpsi",direction),yield,yieldError);
+
+    Double_t raa = yield/(tab*brsigmapp);
+    Double_t raaError = AliAnalysisMuMuResult::ErrorABC(yield,yieldError,
+                                                        tab,tabError,
+                                                        brsigmapp,brsigmappError);
+    r->Set(Form("R%sJpsi",direction),raa,raaError);
+
+    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);
+    
+    r->SetBin(*bincm);
+        
+    finalBins.Add(bincm);
+    finalResults.Add(r);
+    
+    ++i;
   }
   
-  h0->Draw("histsame");
-  l->Draw();
-  c->SetLogy();
+  delete bins;
   
-  delete f;
+  AliAnalysisMuMuSpectra* spectra = new AliAnalysisMuMuSpectra(type,direction);
   
-  c->SaveAs(pdfname);
+  for ( i = 0; i <= n; ++i )
+  {
+    Int_t j(i);
+    if ( strcmp(direction,"pPb")==0 )
+    {
+      j = n-i;
+    }
+    
+    r = static_cast<AliAnalysisMuMuResult*>(finalResults.At(j));
+
+    bin = static_cast<AliAnalysisMuMuBinning::Range*>(finalBins.At(j));
+    
+    spectra->AdoptResult(*bin,r);
+  }
+  
+
+  delete corrSpectra;
+  
+  return spectra;
 }
 
 //_____________________________________________________________________________
-TObjArray*
-AliAnalysisMuMu::ReadFileList(const char* filelist)
+TGraph* AliAnalysisMuMu::ResultEvolution(const char* runlist, const char* period, const char* what, Bool_t forceRecomputation)
 {
-  // 
-  // read the filelist and try to order it by runnumber
-  // 
-  // filelist can either be a real filelist (i.e. a text file containing
-  // root filenames) or a root file itself.
-  //
+  std::vector<int> runs;
+  AliAnalysisTriggerScalers::ReadIntegers(runlist,runs);
+
+  TGraphErrors* g = new TGraphErrors(runs.size());
   
-  char line[1024];
+  TString direction("Pbp");
   
-  TObjArray* files = new TObjArray;
-  files->SetOwner(kTRUE);
+  if (TString(period) == "LHC13b" ||
+    TString(period) == "LHC13c" ||
+      TString(period) == "LHC13d" ||
+      TString(period) == "LHC13e"
+      )
+  {
+    direction = "pPb";
+  }
   
-  TString sfilelist(ExpandPathName(filelist));
+  AliInfoClass(Form("period %s direction %s",period,direction.Data()));
   
-  if ( sfilelist.EndsWith(".root") )
+  Double_t weightedMean(0.0);
+  Double_t sumOfWeights(0.0);
+
+  Double_t mean(0.0);
+  TString subResultName("");
+  TString swhat(what);
+    
+  for ( std::vector<int>::size_type i = 0; i < runs.size(); ++i )
   {
-    files->Add(new TObjString(sfilelist.Data()));
-    return files;
+    Int_t runNumber = runs[i];
+    
+    AliInfoClass(Form("RUN %09d",runNumber));
+    
+    TString realFile(Form("RUNBYRUN/%s_muon_calo_AODMUON000_%09d.saf.root",period,runNumber));
+    
+    TString simFileName(Form("RUNBYRUN/SIM_JPSI_%s_pp503_newalign_%09d.saf.root",period,runNumber));
+    if ( direction == "pPb" )
+    {
+      simFileName = Form("RUNBYRUN/SIM_JPSI_%s_pp503_%09d.saf.root",period,runNumber);
+    }
+
+    TString simFile(simFileName);
+
+    TString resultName(Form("%s%sJpsi",what,direction.Data()));
+    
+    if ( swhat == "MBR")
+    {
+      resultName = "MBR";
+    }
+    else if ( swhat.Contains("Acc") )
+    {
+      resultName.ReplaceAll(direction,"");
+    }
+    
+    AliAnalysisMuMu mreal(realFile);
+    
+    AliAnalysisMuMuSpectra* real = static_cast<AliAnalysisMuMuSpectra*>(mreal.MC()->GetObject("/PSALL/CMUL7-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-"));
+
+    if (!real || forceRecomputation)
+    {
+      mreal.Jpsi();
+      real = static_cast<AliAnalysisMuMuSpectra*>(mreal.MC()->GetObject("/PSALL/CMUL7-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-"));
+      if (!real)
+      {
+        AliErrorClass(Form("Could not get real spectra for run %d",runNumber));
+        return 0x0;
+      }
+    }
+    
+    AliAnalysisMuMu msim(simFile);
+    
+    AliAnalysisMuMuSpectra* sim = static_cast<AliAnalysisMuMuSpectra*>(msim.MC()->GetObject("/ALL/CMULLO-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-"));
+
+    if (!sim || forceRecomputation)
+    {
+      msim.SetEventSelectionList("ALL");
+      msim.Jpsi();
+      sim = static_cast<AliAnalysisMuMuSpectra*>(msim.MC()->GetObject("/ALL/CMULLO-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-"));
+      if (!sim)
+      {
+        AliErrorClass(Form("Could not get sim spectra for run %d",runNumber));
+        return 0x0;
+      }
+    }
+    
+    AliAnalysisMuMuSpectra* corrected = AliAnalysisMuMu::RABy(realFile.Data(),simFile.Data(),"",direction.Data());
+
+    AliAnalysisMuMuResult* result = static_cast<AliAnalysisMuMuResult*>(corrected->Bins()->First());
+
+    result->Print();
+
+    Double_t value = result->GetValue(resultName.Data());
+    Double_t error = result->GetErrorStat(resultName.Data());
+    
+    g->SetPoint(i,runNumber,value);
+    g->SetPointError(i,1,error);
+    
+    Double_t n = mreal.CC()->GetSum(Form("trigger:CMUL7-B-NOPF-MUON/event:PSALL/run:%d",runNumber));
+    
+    weightedMean += n*result->GetValue(resultName.Data());
+    sumOfWeights += n;
+    
+    mean += result->GetValue(resultName.Data());
+    
+//    std::cout << result->SubResults() << " " << result->GetError(resultName.Data()) << std::endl;
+
   }
   
-  std::set<int> runnumbers;
-  std::map<int,std::string> filemap;
+  gStyle->SetOptFit(1);
+  g->Draw("alp");
+  g->Fit("pol0");
+  g->SetTitle("");
+  g->GetXaxis()->SetTitle("Run number");
+  g->GetXaxis()->SetNoExponent();
+  if ( TString(what) ==  "Y" )
+  {
+    g->GetYaxis()->SetTitle("J/#psi yield");
+  }
+  else if ( TString(what) == "R" )
+  {
+    g->GetYaxis()->SetTitle(Form("R_{%s}^{J/#psi}",direction.Data()));
+  }
+  else if ( TString(what).Contains("Acc") )
+  {
+    g->GetYaxis()->SetTitle("Acc#timesEff_{J/#psi}");    
+  }
+  else if ( TString(what).Contains("MBR") )
+  {
+    g->GetYaxis()->SetTitle("CINT7 / CINT7&0MUL");
+  }
   
-    std::ifstream in(sfilelist.Data());
+  if (CompactGraphs())
+  {
+    Compact(*g);
+  }
   
-  TString period;
-  int aodtrain,esdpass,runnumber;
+  mean /= runs.size();
+  weightedMean /= sumOfWeights;
   
-  while ( in.getline(line,1022,'\n') )
+  AliInfoClass(Form("Mean %e Weighted Mean %e",mean,weightedMean));
+  
+  return g;
+}
+
+//______________________________________________________________________________
+void AliAnalysisMuMu::GetMBR(Int_t runNumber, const char* eventSelection, Double_t& value, Double_t& error) const
+{
+   // Get the scaling factor to go from CMUL to CINT7 for a given event selection
+  value = 0.0;
+  error = 0.0;
+  if ( strlen(eventSelection) > 0 )
   {
-    DecodeFileName(line,period,esdpass,aodtrain,runnumber);
+    ULong64_t a = fCounterCollection->GetSum(Form("trigger:CINT7-B-NOPF-ALLNOTRD/event:%s/run:%d",
+                                                  eventSelection,runNumber));
     
-    AliDebugClass(1,Form("line %s => period %s esdpass %d aodtrain %d runnumber %09d",
-                         line,period.Data(),esdpass,aodtrain,runnumber));
+    ULong64_t b = fCounterCollection->GetSum(Form("trigger:CINT7-B-NOPF-ALLNOTRD&0MUL/event:%s/run:%d",
+                                                  eventSelection,runNumber));
     
-    filemap.insert(std::make_pair<int,std::string>(runnumber,line));
-    runnumbers.insert(runnumber);      
+    value = b > 0 ? a/b : 0;
+    error = value*AliAnalysisMuMuResult::ErrorAB(a,TMath::Sqrt(a),b,TMath::Sqrt(b));
   }
+}
+
+//______________________________________________________________________________
+TGraph* AliAnalysisMuMu::MBREvolution(const char* eventSelection1, const char* eventSelection2) const
+{
+  if (!fCounterCollection) return 0x0;
   
-  in.close();
+  TObjArray* runs = fCounterCollection->GetKeyWords("run").Tokenize(",");
+  runs->Sort();
+  TIter nextRun(runs);
+  TObjString* srun;
   
-  std::set<int>::const_iterator it;
+  std::set<int> runnumbers;
+  
+  TGraphErrors* g = new TGraphErrors(runs->GetEntries());
+  Int_t i(0);
   
-  for ( it = runnumbers.begin(); it != runnumbers.end(); ++it ) 
+  while ( ( srun = static_cast<TObjString*>(nextRun()) ) )
   {
-    files->Add(new TObjString(filemap[*it].c_str()));
+    Int_t runNumber = srun->String().Atoi();
+    
+    runnumbers.insert(runNumber);
+    
+    Double_t mbr1,mbrError1;
+    Double_t mbr2,mbrError2;
+    
+    GetMBR(runNumber,eventSelection1,mbr1,mbrError1);
+    
+    GetMBR(runNumber,eventSelection2,mbr2,mbrError2);
+
+    Double_t mbr = mbr1;
+    
+    if ( mbr2 > 0 ) mbr /= mbr2;
+
+    Double_t mbrError = mbr*AliAnalysisMuMuResult::ErrorAB(mbr1,mbrError1,mbr2,mbrError2);
+
+    g->SetPoint(i,runNumber,mbr);
+    g->SetPointError(i,0.5,mbrError);
+    
+    ++i;
   }
   
-  return files;
-}
+  g->GetXaxis()->SetNoExponent();
+  
+  AliAnalysisTriggerScalers ts(RunNumbers(),fgOCDBPath.Data());
+  ts.DrawFills(0,1000);
 
-//_____________________________________________________________________________
-Int_t 
-AliAnalysisMuMu::RunNumberFromFileName(const char* filename)
-{
-  TString period;
-  int esdpass,aodtrain,runnumber;
-  Bool_t ok = DecodeFileName(filename,period,esdpass,aodtrain,runnumber);
-  if ( ok ) return runnumber;
-  return -1;
+  return g;
 }
+
+
+
+
index 18b9345..fbd0ddd 100644 (file)
@@ -6,23 +6,29 @@
 
 // $Id$
 
-/// 
-/// AliAnalysisMuMu : helper class to digest results from
-/// AliAnalysisTaskMuMu(fromAOD or fromESD)
+///
+/// AliAnalysisMuMu : helper class to digest/plot/massage results from
+/// AliAnalysisTaskMuMu
 ///
 /// author : Laurent Aphecetche (Subatech)
 
+#include "AliAnalysisMuMuBinning.h"
 #include "TNamed.h"
+#include <map>
+#include <set>
 #include <string>
 #include <TString.h>
+#include <vector>
 
-class TH1;
-class AliHistogramCollection;
+class AliAnalysisMuMuResult;
+class AliAnalysisMuMuSpectra;
 class AliCounterCollection;
+class AliMergeableCollection;
 class TF1;
+class TFile;
 class TGraph;
+class TH1;
 class TMap;
-class TFile;
 
 class AliAnalysisMuMu : public TObject
 {
@@ -38,275 +44,179 @@ public:
   AliAnalysisMuMu(const char* filename="LHC12c_muons_AOD000_000179687.saf.root");
   virtual ~AliAnalysisMuMu();
   
-  class Result : public TNamed
-  {
-    
-  public:
-    
-    enum EFitType
-    {
-      kJpsi=(1<<0),
-      kJpsiPrime=(1<<1),
-      kUpsilon=(1<<2),
-      kPbPb2010=(1<<3),
-      kPbPb2011=(1<<4),
-      kpp2011=(1<<5),
-      kMatchAny=(1<<6)
-    };
-    
-    Result(TRootIOCtor* /*io*/) :
-    TNamed("",""),
-    fTriggerName(),
-    fEventSelection(),
-    fPairSelection(),
-    fCentralitySelection(),
-    fNofRuns(),
-    fNofTriggers(),
-    fHC(0x0), fRebin(0),
-    fFitTotal(0x0),
-    fMinv(0x0), fMinvLS(0), 
-    fFitType(0), fMap(0x0)
-    {
-    }
-    
-    Result(const char* triggerClass,
-           const char* eventSelection,
-           const char* pairSelection,
-           const char* centSelection,
-           Int_t ntriggers, AliHistogramCollection* hc, Int_t nrebin=1, UInt_t fitType=(kJpsi | kJpsiPrime)) :
-    TNamed("",""), fTriggerName(triggerClass),
-    fEventSelection(eventSelection),
-    fPairSelection(pairSelection),
-    fCentralitySelection(centSelection),
-    fNofRuns(1),
-    fNofTriggers(ntriggers), fHC(hc), fRebin(nrebin),
-    fFitTotal(0x0),
-    fMinv(0x0), fMinvLS(0), 
-    fFitType(fitType), fMap(0x0)
-    {
-      if (hc) Fit(nrebin);
-    }
-  
-    virtual ~Result();
-  
-    const char* GetName() const { return fTriggerName.Data(); }
-    
-    AliHistogramCollection* HC() const { return fHC; }
-    
-    const char* TriggerClass() const { return GetName(); }
-    
-    const char* EventSelection() const { return fEventSelection.Data(); }
-    const char* PairSelection() const { return fPairSelection.Data(); }
-    const char* CentralitySelection() const { return fCentralitySelection.Data(); }
-    
-    Int_t NofTriggers() const { return fNofTriggers; }
-    
-    Double_t NofJpsi() const { return GetValue("NofJpsi"); }
-    
-    Double_t ErrorOnNofJpsi() const { return GetError("NofJpsi"); }
-    
-    Double_t MeanJpsi() const { return GetValue("MeanJpsi"); }
-    
-    Double_t ErrorOnMeanJpsi() const { return GetError("MeanJpsi"); }
-    
-    Double_t SigmaJpsi() const { return GetValue("SigmaJpsi"); }
-    
-    Double_t ErrorOnSigmaJpsi() const { return GetError("SigmaJpsi"); }
-    
-    Double_t NofJpsiPrime() const { return GetValue("NofJpsiPrime"); }
-    
-    Double_t ErrorOnNofJpsiPrime() const { return GetError("NofJpsiPrime"); }
-    
-    Double_t MeanJpsiPrime() const { return GetValue("MeanJpsiPrime"); }
-    
-    Double_t ErrorOnMeanJpsiPrime() const { return GetError("MeanJpsiPrime"); }
-    
-    Double_t SigmaJpsiPrime() const { return GetValue("SigmaJpsiPrime"); }
-    
-    Double_t ErrorOnSigmaJpsiPrime() const { return GetError("SigmaJpsiPrime"); }
-    
-    Double_t NofUpsilon() const { return GetValue("NofUpsilon"); }
-    
-    Double_t ErrorOnNofUpsilon() const { return GetError("NofUpsilon"); }
-    
-    Double_t MeanUpsilon() const { return GetValue("MeanUpsilon"); }
-    
-    Double_t ErrorOnMeanUpsilon() const { return GetError("MeanUpsilon"); }
-    
-    Double_t SigmaUpsilon() const { return GetValue("SigmaUpsilon"); }
-    
-    Double_t ErrorOnSigmaUpsilon() const { return GetError("SigmaUpsilon"); }
-    
-    void Set(const char* name, double value, double error);
-    
-    void Print(Option_t* opt="") const;
-    
-    void Fit(Int_t rebin=1);
-    
-    void FitJpsiJpsiPrimeCB(TH1& h);
-    
-    void FitJpsiJpsiPrimeCustom(TH1& h);
-    
-    void FitJpsi(TH1& h);
-    
-    void FitJpsiCBE(TH1& h);
-    
-    void FitJpsiECBE(TH1& h);
-    
-    void FitJpsiPCBE(TH1& h);
-    
-    void FitUpsilon(TH1& h);
-    
-    void FitJpsiGCBE(TH1& h);
-    
-    Bool_t HasValue(const char* name) const;
-    Double_t GetValue(const char* name) const;
-    Double_t GetError(const char* name) const;
-    
-    TH1* Minv() const { return fMinv; }
-    TH1* MinvLS() const { return fMinvLS; }
-    
-    UInt_t FitType() const { return fFitType; }
-    
-    Int_t NofRuns() const { return fNofRuns; }
-    
-    void SetNofRuns(int n) { fNofRuns=n; }
-    
-  private:
-    Result(const Result&);
-    Result& operator=(const Result&);
-    TMap* Map() const;
-    
-  private:
-    TString fTriggerName;
-    TString fEventSelection;
-    TString fPairSelection;
-    TString fCentralitySelection;
-    Int_t fNofRuns;
-    Int_t fNofTriggers;
-    AliHistogramCollection* fHC;
-    Int_t fRebin;
-    TF1* fFitTotal;
-    TH1* fMinv;
-    TH1* fMinvLS;
-    UInt_t fFitType;
-    
-    mutable TMap* fMap; // map of results (string,TObjArray) each TObjArray = (value,error) = (TParameter<double>, TParameter<double>)
-    
-    ClassDef(AliAnalysisMuMu::Result,7)
-  };
-
   /* Basic checks */
   void BasicCounts(Bool_t detailTrigger=kFALSE,
                    ULong64_t* totalNmb=0x0,
                    ULong64_t* totalNmsl=0x0,
                    ULong64_t* totalNmul=0x0);
-
+  
   static void BasicCountsEvolution(const char* filelist, Bool_t detailTrigger=kFALSE);
   
-  void TriggerCountCoverage(const char* triggerList, Bool_t compact=kTRUE);
-
-
+  void TriggerCountCoverage(const char* triggerList, Bool_t compact=kTRUE,
+                            Bool_t orderByTriggerCount=kTRUE);
+  
+  
   /** Background evolution functions */
   static TObjArray* ComputeBackgroundEvolution(const char* filelist, const char* triggerList,
+                                               Double_t ptmin=0.0,
                                                const char* outputfile="background-evolution.root", const char* outputMode="UPDATE");
-
-  static void PlotBackgroundEvolution(const char* gfile, const char* triggerList);
   
-
+  static void PlotBackgroundEvolution(const char* gfile, const char* triggerList, Double_t ymax=100.0, Bool_t fillBoundaries=kFALSE);
+  
+  
   /** Fitting */
   static TMap* ComputeJpsiEvolution(const char* filelist, const char* triggerList,
-                                         const char* outputFile="jpsi-evolution.root", const char* outputMode="UPDATE",
-                                         Bool_t simulation=kFALSE);
+                                    const char* outputFile="jpsi-evolution.root");
   
   static void PlotJpsiEvolution(const char* resultFile, const char* triggerList, Bool_t fillBoundaries=kFALSE,
-                                const char* efficiencyFile=0x0);
+                                const char* efficiencyFile=0x0, Bool_t simulation=kFALSE);
+  
+  
+  AliAnalysisMuMuSpectra* FitParticle(const char* particle,
+                                      const char* trigger,
+                                      const char* eventType,
+                                      const char* pairCut,
+                                      const char* centrality,
+                                      const AliAnalysisMuMuBinning& binning);
 
   ///------
   
-  static void CentralityCheck(const char* filelist);
+  static AliAnalysisMuMuSpectra* CorrectSpectra(const char* realFile="ds.list.saf.root", const char* simFile="ds.sim.list.saf.root", const char* particle="Jpsi", const char* type="PSI-PT");
 
+  static AliAnalysisMuMuSpectra* RABy(const char* realFile="ds.list.saf.root", const char* simFile="ds.sim.list.saf.root", const char* type="", const char* direction="pPb");
+
+  static TGraph* ResultEvolution(const char* runlist, const char* period="LHC13f", const char* what="Y",
+                                 Bool_t forceRecomputation=kFALSE);
+  
+  ///-------
+  
+  TGraph* PlotEventSelectionEvolution(const char* trigger1="CINT7-B-NOPF-MUON", const char* event1="PSALL",
+                                   const char* trigger2="CINT7-B-NOPF-MUON", const char* event2="PSALL",
+                                      Bool_t drawFills=kFALSE,
+                                      Bool_t asRejection=kTRUE) const;
+
+  Bool_t Upgrade();
+  
+  static Bool_t Upgrade(const char* filename);
+  
+  static void CentralityCheck(const char* filelist);
+  
   static TObjArray* CompareJpsiPerCMUUWithBackground(const char* jpsiresults="results.root",
                                                      const char* backgroundresults="background.lhc11d.root");
-
+  
   static TGraph* CompareJpsiPerCMUUWithSimu(const char* realjpsiresults="results.root",
                                             const char* simjpsiresults="results.sim.root");
-
+  
   static Bool_t DecodeFileName(const char* filename, TString& period, int& esdpass, int& aodtrain, int& runnumber);
   
-
+  
   static TFile* FileOpen(const char* file);
   
-
+  
   static Bool_t GetCollections(const char* rootfile,
-                               AliHistogramCollection*& hc,
-                               AliCounterCollection*& cc);
-    
-  static Result* GetResult(const AliHistogramCollection& hc,
-                           AliCounterCollection& cc,
-                           const char* base,
-                           const char* selection,
-                           const char* paircut,
-                           const char* centrality,
-                           UInt_t fitType,
-                           Int_t nrebin=1);
+                               AliMergeableCollection*& mc,
+                               AliCounterCollection*& cc,
+                               AliAnalysisMuMuBinning*& bin,
+                               std::set<int>& runnumbers);
   
   static UInt_t GetSum(AliCounterCollection& cc, const char* triggerList, const char* eventSelection, Int_t runNumber=-1);
   
   static ULong64_t GetTriggerScalerCount(const char* triggerList, Int_t runNumber);
-
-  TObjArray* Jpsi(Bool_t simulation=kFALSE);
-
+  
+  Int_t Jpsi(const char* what="");
+  
+  Bool_t IsSimulation() const;
+  
   static TObjArray* ReadFileList(const char* filelist);
   
   static Int_t RunNumberFromFileName(const char* filename);
   
-  static void SinglePtPlot(const char* rootfile);
-
+  TString DimuonTriggerList() const { return fDimuonTriggers; }
   void SetDimuonTriggerList(const char* dimuonTriggerList) { fDimuonTriggers = dimuonTriggerList; }
-  void SetMuonTriggerList(const char* muonTriggerList) { fMuonTriggers = muonTriggerList; }
-  void SetMinbiasTriggerList(const char* minbiasTriggerList) { fMinbiasTriggers = minbiasTriggerList; }
 
-  TString DimuonTriggerList() const { return fDimuonTriggers; }
   TString MuonTriggerList() const { return fMuonTriggers; }
+  void SetMuonTriggerList(const char* muonTriggerList) { fMuonTriggers = muonTriggerList; }
+
   TString MinbiasTriggerList() const { return fMinbiasTriggers; }
+  void SetMinbiasTriggerList(const char* minbiasTriggerList) { fMinbiasTriggers = minbiasTriggerList; }
   
+  TString EventSelectionList() const { return fEventSelectionList; }
   void SetEventSelectionList(const char* eventSelectionList) { fEventSelectionList = eventSelectionList; }
-  void SetPairSelectionList(const char* pairSelectionList) { fPairSelectionList = pairSelectionList; }
   
+  TString PairSelectionList() const { return fPairSelectionList; }
+  void SetPairSelectionList(const char* pairSelectionList) { fPairSelectionList = pairSelectionList; }
+
+  TString CentralitySelectionList() const { return fCentralitySelectionList; }
+  void SetCentralitySelectionList(const char* centralitySelectionList) { fCentralitySelectionList = centralitySelectionList; }
+
   static void SetDefaultDimuonTriggerList(const char* dimuonTriggerList) { fgDefaultDimuonTriggers = dimuonTriggerList; }
   static void SetDefaultMuonTriggerList(const char* muonTriggerList) { fgDefaultMuonTriggers = muonTriggerList; }
   static void SetDefaultMinbiasTriggerList(const char* minbiasTriggerList) { fgDefaultMinbiasTriggers = minbiasTriggerList; }
   static void SetDefaultEventSelectionList(const char* eventSelectionList) { fgDefaultEventSelectionList = eventSelectionList; }
   static void SetDefaultPairSelectionList(const char* pairSelectionList) { fgDefaultPairSelectionList = pairSelectionList; }
-
+  static void SetDefaultCentralitySelectionList(const char* centralitySelectionList) { fgDefaultCentralitySelectionList = centralitySelectionList; }
   
-  AliHistogramCollection* HC() const { return fHistogramCollection; }
+  
+  AliMergeableCollection* MC() const { return fMergeableCollection; }
   AliCounterCollection* CC() const { return fCounterCollection; }
+  AliAnalysisMuMuBinning* BIN() const { return fBinning; }
   
   static void SetOCDBPath(const char* ocdbPath) { fgOCDBPath = ocdbPath; }
   
   static void SetColorScheme();
+  
+  static void SetCompactGraphs(Bool_t value=kTRUE) { fgIsCompactGraphs = value; }
+  
+  static Bool_t CompactGraphs() { return fgIsCompactGraphs; }
+  
+  static void Compact(TGraph& g);
+  
+  void Print(Option_t* opt="") const;
+  
+  void GetMBR(Int_t runNumber, const char* eventSelection, Double_t& value, Double_t& error) const;
 
-  static void DrawFill(Int_t run1, Int_t run2, double ymin, double ymax, const char* label);
+  TGraph* MBREvolution(const char* eventSelection1="PSALLNOTZEROPILEUP", const char* eventSelection2="PSALL") const;
 
+  const std::set<int>& RunNumbers() const { return fRunNumbers; }
+  
+  void DrawMinv(const char* type,
+                const char* particle,
+                const char* trigger,
+                const char* eventType,
+                const char* pairCut,
+                const char* centrality) const;
+
+  void DrawMinv(const char* type="PT", const char* particle="PSI") const;
+  
+  Bool_t SetCorrectionPerRun(const TGraph& corr);
+  
+  void UnsetCorrectionPerRun();
+  
 private:
   AliAnalysisMuMu(const AliAnalysisMuMu& rhs); // not implemented on purpose
   AliAnalysisMuMu& operator=(const AliAnalysisMuMu& rhs); // not implemented on purpose
   
+  TFile* ReOpen(const char* filename, const char* mode) const;
+
+  TString First(const TString& list) const;
+  
 private:
 
-  static TString ExpandPathName(const char* file);
+  void SetNofInputParticles(AliAnalysisMuMuResult& r);
 
-  TString fFilename; // file containing the result collections (of histograms and counters) from AliAnalysisTaskMuMu
-  AliHistogramCollection* fHistogramCollection; // collection of histograms in file
+  static TString ExpandPathName(const char* file);
+  
+  TString fFilename; // file containing the result collections (of objects and counters) from AliAnalysisTaskMuMu
   AliCounterCollection* fCounterCollection; // collection of counters in file
   TString fDimuonTriggers; // list of dimuon triggers to consider
   TString fMuonTriggers; // list of single muon triggers to consider
   TString fMinbiasTriggers;   // list of minbias triggers to consider
   TString fEventSelectionList; // list of event types to consider
   TString fPairSelectionList; // list of pair cuts to consider
-
+  TString fCentralitySelectionList; // list of centrality cuts to consider
+  
+  AliAnalysisMuMuBinning* fBinning; // binning
+  
   static TString fgOCDBPath; // OCDB to be used (raw:// by default)
   
   static TString fgDefaultMuonTriggers; // default list of single muon triggers
@@ -314,8 +224,17 @@ private:
   static TString fgDefaultDimuonTriggers; // default list of dimuon triggers
   static TString fgDefaultEventSelectionList; // default list of event selections
   static TString fgDefaultPairSelectionList; // default list of pair selections
+  static TString fgDefaultCentralitySelectionList; // default list of centrality selections
+  
+  static Bool_t fgIsCompactGraphs; // whether the graph produced should be compact
+  
+  AliMergeableCollection* fMergeableCollection; // collection of objects in file
 
-  ClassDef(AliAnalysisMuMu,3) // class to analysis results from AliAnalysisTaskMuMuXXX tasks
+  std::set<int> fRunNumbers; // run numbers
+  
+  TGraph* fCorrectionPerRun; // correction factor per run
+  
+  ClassDef(AliAnalysisMuMu,10) // class to analysis results from AliAnalysisTaskMuMuXXX tasks
 };
 
 #endif
diff --git a/PWG/muondep/AliAnalysisMuMuResult.cxx b/PWG/muondep/AliAnalysisMuMuResult.cxx
new file mode 100644 (file)
index 0000000..78ccc1b
--- /dev/null
@@ -0,0 +1,2077 @@
+/**************************************************************************
+ * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ *                                                                        *
+ * Author: The ALICE Off-line Project.                                    *
+ * Contributors are mentioned in the code where appropriate.              *
+ *                                                                        *
+ * Permission to use, copy, modify and distribute this software and its   *
+ * documentation strictly for non-commercial purposes is hereby granted   *
+ * without fee, provided that the above copyright notice appears in all   *
+ * copies and that both the copyright notice and this permission notice   *
+ * appear in the supporting documentation. The authors make no claims     *
+ * about the suitability of this software for any purpose. It is          *
+ * provided "as is" without express or implied warranty.                  *
+ **************************************************************************/
+
+
+// $Id$
+
+#include "AliAnalysisMuMuResult.h"
+
+ClassImp(AliAnalysisMuMuResult)
+
+#include "TF1.h"
+#include "TFitResult.h"
+#include "TH1.h"
+#include "TH2.h"
+#include "THashList.h"
+#include "TLine.h"
+#include "TList.h"
+#include "TMap.h"
+#include "TMath.h"
+#include "TObjArray.h"
+#include "TParameter.h"
+#include "AliAnalysisMuMuBinning.h"
+#include "AliHistogramCollection.h"
+#include "AliLog.h"
+#include <map>
+
+const std::map<std::string,Double_t>& MassMap()
+{
+  static std::map<std::string,Double_t> massMap;
+  // not super elegant, but that way we do not depend on TDatabasePDG and thus
+  // can decide on our particle naming
+  if (massMap.empty())
+  {
+    massMap["Jpsi"] = 3.096916e+00;
+    massMap["PsiPrime"] = 3.68609e+00;
+    massMap["Upsilon"] = 9.46030e+00;
+    massMap["UpsilonPrime"] = 1.00233e+01;
+  }
+  return massMap;
+}
+
+
+Double_t ErrorAB(Double_t a, Double_t aerr, Double_t b, Double_t berr)
+{
+  Double_t e(0.0);
+  
+  if ( TMath::Abs(a) > 1E-12 )
+  {
+    e += (aerr*aerr)/(a*a);
+  }
+  
+  if ( TMath::Abs(b) > 1E-12 )
+  {
+    e += (berr*berr)/(b*b);
+  }
+  
+  return TMath::Sqrt(e);
+}
+
+Double_t funcCB(Double_t* xx, Double_t* par)
+{ 
+  Double_t N = par[0];
+  Double_t alpha = par[1];
+  Double_t n = par[2];
+  Double_t mean = par[3];
+  Double_t sigma = par[4];
+  
+  Double_t x = xx[0];
+  
+  Double_t A = TMath::Power(n/TMath::Abs(alpha),n)*TMath::Exp(-0.5*alpha*alpha);
+  Double_t B = n/TMath::Abs(alpha) - TMath::Abs(alpha);
+  
+  Double_t y = ( TMath::Abs(sigma) > 1E-12 ? (x-mean)/sigma : 0 );
+  
+  if ( y > alpha*-1.0 ) 
+  {
+    return N*TMath::Exp(-0.5*y*y);
+  }
+  else 
+  {
+    return N*A*TMath::Power(B-y,-n);
+  }
+}
+
+Double_t funcJpsiGCBE(Double_t* xx, Double_t* par)
+{
+  Double_t x = xx[0];
+  
+  Double_t g = par[0]*TMath::Gaus(x,par[1],par[2]);
+  
+  Double_t jpsi = funcCB(xx,par+3);
+  
+  Double_t expo = par[8]*TMath::Exp(par[9]*x);
+  
+  return g+expo+jpsi;
+}
+
+Double_t funcJpsiPsiPrimeCustom(Double_t* xx, Double_t* par)
+{ 
+  Double_t N = par[0];
+  Double_t alpha = par[1];
+  Double_t n = par[2];
+  Double_t mean = par[3];
+  Double_t sigma = par[4];
+  Double_t alphaprime = par[5];
+  Double_t nprime = par[6];
+  
+  Double_t x = xx[0];
+  
+  Double_t A = TMath::Power(n/TMath::Abs(alpha),n)*TMath::Exp(-0.5*alpha*alpha);
+  Double_t B = n/TMath::Abs(alpha) - TMath::Abs(alpha);
+  Double_t C = TMath::Power(nprime/TMath::Abs(alphaprime),nprime)*TMath::Exp(-0.5*alphaprime*alphaprime);
+  Double_t D = nprime/TMath::Abs(alphaprime) - TMath::Abs(alphaprime);
+  
+  Double_t y = ( TMath::Abs(sigma) > 1E-12 ? (x-mean)/sigma : 0 );
+  
+  Double_t cb(0);
+  
+  if ( y > alphaprime )
+  {
+    cb = N*C*TMath::Power(D+y,-nprime);
+  }
+  else if ( y > alpha*-1.0 ) 
+  {
+    cb = N*TMath::Exp(-0.5*y*y);
+  }
+  else 
+  {
+    cb = N*A*TMath::Power(B-y,-n);
+  }
+  
+  if ( x < mean )
+  {
+    return cb + par[7] + par[8]*x; // gaus + pol1
+  }
+  else
+  {
+    Double_t yprime = (x-par[10])/par[11];
+    return cb + par[9]*TMath::Exp(-0.5*yprime*yprime)+par[12]*TMath::Exp(-par[13]*x);
+    // gaus (j/psi) + gaus (psi') + expo
+  }
+}
+
+
+Double_t funcCB2(Double_t* xx, Double_t* par)
+{ 
+  Double_t N = par[0];
+  Double_t alpha = par[1];
+  Double_t n = par[2];
+  Double_t mean = par[3];
+  Double_t sigma = par[4];
+  Double_t alphaprime = par[5];
+  Double_t nprime = par[6];
+  
+  Double_t x = xx[0];
+  
+  Double_t A = TMath::Power(n/TMath::Abs(alpha),n)*TMath::Exp(-0.5*alpha*alpha);
+  Double_t B = n/TMath::Abs(alpha) - TMath::Abs(alpha);
+  Double_t C = TMath::Power(nprime/TMath::Abs(alphaprime),nprime)*TMath::Exp(-0.5*alphaprime*alphaprime);
+  Double_t D = nprime/TMath::Abs(alphaprime) - TMath::Abs(alphaprime);
+  
+  Double_t y = ( TMath::Abs(sigma) > 1E-12 ? (x-mean)/sigma : 0 );
+  
+  if ( y > alphaprime )
+  {
+    return N*C*TMath::Power(D+y,-nprime);
+  }
+  else if ( y > alpha*-1.0 ) 
+  {
+    return N*TMath::Exp(-0.5*y*y);
+  }
+  else 
+  {
+    return N*A*TMath::Power(B-y,-n);
+  }
+}
+
+Double_t funcJpsiPsiPrime(Double_t* xx, Double_t* par)
+{
+  Double_t jpsi = funcCB(xx,par);
+  Double_t psiprime = funcCB2(xx,par+5);
+  
+  int n = 10;
+  Double_t x = xx[0];
+    
+  Double_t e1 = par[n]*TMath::Exp(par[n+1]*x);
+  Double_t e2 = par[n+2]*TMath::Exp(par[n+3]*x);    
+  
+  Double_t e = e1;
+  
+  if ( x > par[3] ) e=e2;
+  
+  return jpsi+psiprime+e;
+}
+
+Double_t funcJpsiCBE(Double_t* xx, Double_t* par)
+{
+  // CB + expo
+  
+  Double_t jpsi = funcCB(xx,par);
+  
+  Double_t x = xx[0];
+  
+  Double_t e1 = par[5]*TMath::Exp(par[6]*x);
+  
+  return jpsi+e1;
+}
+
+
+Double_t funcJpsiPCBE(Double_t* xx, Double_t* par)
+{
+  Double_t x = xx[0];
+
+  Double_t pol2 = par[0] + par[1]*x + par[2]*x*x;
+
+  Double_t jpsi = funcCB(xx,par+3);
+  
+  Double_t expo = par[8]*TMath::Exp(par[9]*x);
+  
+  return pol2+jpsi+expo;
+}
+
+Double_t funcJpsiECBE(Double_t* xx, Double_t* par)
+{
+  // CB + expo
+  
+  Double_t jpsi = funcCB(xx,par+2);
+  
+  Double_t x = xx[0];
+  
+  Double_t e1 = par[0]*TMath::Exp(par[1]*x);
+  
+  Double_t e2 = par[7]*TMath::Exp(par[8]*x);
+  
+  return e1+e2+jpsi;
+}
+
+const char* NormalizeName(const char* name, const char* suffix)
+{
+  TString str(Form("%s_%s",name,suffix));
+  
+  str.ReplaceAll("-","_");
+  str.ReplaceAll("/","%");
+  
+  return str.Data();
+}
+
+//------------------------------------------------------------------------------
+Double_t BackgroundVWG(Double_t *x, Double_t *par)
+{
+  // gaussian variable width
+  Double_t sigma = par[2]+par[3]*((x[0]-par[1])/par[1]);
+  return par[0]*TMath::Exp(-(x[0]-par[1])*(x[0]-par[1])/(2.*sigma*sigma));
+  
+}
+
+//------------------------------------------------------------------------------
+Double_t CrystalBallExtended(Double_t *x,Double_t *par)
+{
+  //par[0] = Normalization
+  //par[1] = mean
+  //par[2] = sigma
+  //par[3] = alpha
+  //par[4] = n
+  //par[5] = alpha'
+  //par[6] = n'
+  
+  Double_t t = (x[0]-par[1])/par[2];
+  if (par[3] < 0) t = -t;
+  
+  Double_t absAlpha = fabs((Double_t)par[3]);
+  Double_t absAlpha2 = fabs((Double_t)par[5]);
+  
+  if (t >= -absAlpha && t < absAlpha2) // gaussian core
+  {
+    return par[0]*(exp(-0.5*t*t));
+  }
+  
+  if (t < -absAlpha) //left tail
+  {
+    Double_t a =  TMath::Power(par[4]/absAlpha,par[4])*exp(-0.5*absAlpha*absAlpha);
+    Double_t b = par[4]/absAlpha - absAlpha;
+    return par[0]*(a/TMath::Power(b - t, par[4]));
+  }
+  
+  if (t >= absAlpha2) //right tail
+  {
+    
+    Double_t c =  TMath::Power(par[6]/absAlpha2,par[6])*exp(-0.5*absAlpha2*absAlpha2);
+    Double_t d = par[6]/absAlpha2 - absAlpha2;
+    return par[0]*(c/TMath::Power(d + t, par[6]));
+  }
+  
+  return 0. ;
+}
+
+//------------------------------------------------------------------------------
+Double_t Gaus(Double_t *x, Double_t *par)
+{
+  // gaussian
+  return par[0]/TMath::Sqrt(2.*TMath::Pi())/par[2]*TMath::Exp(-(x[0]-par[1])*(x[0]-par[1])/(2.*par[2]*par[2]));
+  
+}
+
+//------------------------------------------------------------------------------
+Double_t Exp(Double_t *x, Double_t *par)
+{
+  // exponential
+  return par[0]*TMath::Exp(par[1]*x[0]);
+  
+}
+
+//------------------------------------------------------------------------------
+Double_t Pow(Double_t *x, Double_t *par)
+{
+  // power law
+  return par[0]*TMath::Power(x[0],par[1]);
+  
+}
+
+//------------------------------------------------------------------------------
+Double_t fitFunctionVWG(Double_t *x, Double_t *par)
+{
+  if (x[0] > 2.9 && x[0] < 3.3) TF1::RejectPoint();
+  return BackgroundVWG(x, par);
+}
+
+//------------------------------------------------------------------------------
+Double_t fitFunctionCB2VWG(Double_t *x, Double_t *par)
+{
+  return BackgroundVWG(x, par) + CrystalBallExtended(x, &par[4]);
+}
+
+//------------------------------------------------------------------------------
+Double_t func2CB2VWG(Double_t *x, Double_t *par)
+{
+  Double_t par2[7] = {
+    par[11],
+    3.68609+(par[5]-3.096916)/3.096916*3.68609,
+    par[6]/3.096916*3.68609,
+    par[7],
+    par[8],
+    par[9],
+    par[10]
+  };
+  return BackgroundVWG(x, par) + CrystalBallExtended(x, &par[4]) + CrystalBallExtended(x, par2);
+}
+
+//_____________________________________________________________________________
+//_____________________________________________________________________________
+//_____________________________________________________________________________
+//_____________________________________________________________________________
+//_____________________________________________________________________________
+
+//_____________________________________________________________________________
+AliAnalysisMuMuResult::AliAnalysisMuMuResult(TRootIOCtor* /*io*/) :
+TNamed("",""),
+fNofRuns(),
+fNofTriggers(-1),
+fMinv(0x0),
+fBin(),
+fSubResults(0x0),
+fMap(0x0),
+fMother(0x0),
+fKeys(0x0),
+fWeight(0.0)
+{
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuResult::AliAnalysisMuMuResult(const TH1& hminv)
+:
+  TNamed("",""),
+  fNofRuns(1),
+  fNofTriggers(-1),
+  fMinv(0x0),
+  fBin(),
+  fSubResults(0x0),
+  fMap(0x0),
+  fMother(0x0),
+fKeys(0x0),
+fWeight(0.0)
+
+{
+  SetMinv(hminv);
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuResult::AliAnalysisMuMuResult(const TH1& hminv,
+                                             const char* fitType,
+                                             Int_t nrebin)
+:
+TNamed(Form("%s-%d",fitType,nrebin),""),
+fNofRuns(1),
+fNofTriggers(-1),
+fMinv(0x0),
+fBin(),
+fSubResults(0x0),
+fMap(0x0),
+fMother(0x0),
+fKeys(0x0),
+fWeight(0.0)
+
+{
+  SetMinv(hminv);
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuResult::AliAnalysisMuMuResult(const TH1& hminv,
+                                             const char* triggerName,
+                                             const char* eventSelection,
+                                             const char* pairSelection,
+                                             const char* centSelection,
+                                             const AliAnalysisMuMuBinning::Range& bin)
+:
+TNamed(Form("%s-%s-%s-%s",triggerName,eventSelection,pairSelection,centSelection),""),
+fNofRuns(1),
+fNofTriggers(-1),
+fMinv(0x0),
+fBin(bin),
+fSubResults(0x0),
+fMap(0x0),
+fMother(0x0),
+fKeys(0x0),
+fWeight(0.0)
+
+{
+  SetMinv(hminv);
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuResult::AliAnalysisMuMuResult(const AliAnalysisMuMuResult& rhs)
+:
+TNamed(rhs),
+fNofRuns(rhs.NofRuns()),
+fNofTriggers(rhs.NofTriggers()),
+fMinv(0x0),
+fBin(rhs.Bin()),
+fSubResults(0x0),
+fMap(0x0),
+fMother(0x0),
+fKeys(0x0),
+fWeight(rhs.fWeight)
+{
+  /// copy ctor
+  /// Note that the mother is lost
+  /// fKeys remains 0x0 so it will be recomputed if need be
+
+  if ( rhs.fMinv )
+  {
+    fMinv = static_cast<TH1*>(rhs.fMinv->Clone());
+  }
+  
+  if (rhs.fSubResults)
+  {
+    fSubResults = static_cast<TObjArray*>(rhs.fSubResults->Clone());
+  }
+  
+  if ( rhs.fMap )
+  {
+    fMap = static_cast<TMap*>(rhs.fMap->Clone());
+  }
+  
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuResult& AliAnalysisMuMuResult::operator=(const AliAnalysisMuMuResult& rhs)
+{
+  if (this!=&rhs)
+  {
+    delete fMinv;
+    delete fMap;
+    delete fSubResults;
+    
+    fMinv = 0x0;
+    fMap = 0x0;
+    fSubResults = 0x0;
+    fKeys = 0x0;
+    
+    if ( rhs.fMinv )
+    {
+      fMinv = static_cast<TH1*>(rhs.fMinv->Clone());
+    }
+    
+    if (rhs.fSubResults)
+    {
+      fSubResults = static_cast<TObjArray*>(rhs.fSubResults->Clone());
+    }
+    
+    if ( rhs.fMap )
+    {
+      fMap = static_cast<TMap*>(rhs.fMap->Clone());
+    }
+
+    static_cast<TNamed&>(*this)=rhs;
+    
+    fNofRuns = rhs.NofRuns();
+    fNofTriggers = rhs.NofTriggers();
+    fBin = rhs.Bin();
+    fWeight = rhs.fWeight;
+  }
+  
+  return *this;
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuResult::~AliAnalysisMuMuResult()
+{
+  delete fMap;
+  delete fMinv;
+  delete fSubResults;
+  delete fKeys;
+}
+
+//_____________________________________________________________________________
+const AliAnalysisMuMuBinning::Range& AliAnalysisMuMuResult::Bin() const
+{
+  if ( !Mother() ) return fBin;
+  else return Mother()->Bin();
+}
+
+//_____________________________________________________________________________
+TObject* AliAnalysisMuMuResult::Clone(const char* /*newname*/) const
+{
+  return new AliAnalysisMuMuResult(*this);
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuResult::Correct(const AliAnalysisMuMuResult& other, const char* particle, const char* subResultName)
+{
+  /// Assuming other has an AccxEff entry, correct this value by AccxEff of other
+  
+  if ( HasValue(Form("Nof%s",particle)) )
+  {
+    if (!other.HasValue(Form("AccEff%s",particle),subResultName))
+    {
+      AliError(Form("Cannot correct as I do not find the AccEff%s value (subResultName=%s)!",particle,subResultName));
+      return kFALSE;
+    }
+    
+    Double_t acc = other.GetValue(Form("AccEff%s",particle),subResultName);
+    Double_t value = 0.0;
+    
+    if ( acc > 0 ) value = GetValue(Form("Nof%s",particle)) / acc;
+    
+    Double_t error = ErrorAB( GetValue(Form("Nof%s",particle)),
+                              GetErrorStat(Form("Nof%s",particle)),
+                              other.GetValue(Form("AccEff%s",particle),subResultName),
+                              other.GetErrorStat(Form("AccEff%s",particle),subResultName) );
+                                    
+    Set(Form("CorrNof%s",particle),value,error*value);
+    
+    return kTRUE;
+  }
+  
+  return kFALSE;
+}
+
+//_____________________________________________________________________________
+Double_t AliAnalysisMuMuResult::CountParticle(const TH1& hminv, const char* particle, Double_t sigma)
+{
+  /// Count the number of entries in an invariant mass range
+  
+  const std::map<std::string,Double_t>& m = MassMap();
+  
+  std::map<std::string,Double_t>::const_iterator it = m.find(particle);
+  
+  if ( it == m.end() )
+  {
+    AliErrorClass(Form("Don't know the mass of particle %s",particle));
+    return 0.0;
+  }
+  
+  Double_t mass = it->second;
+  
+  if ( sigma < 0 )
+  {
+    AliDebugClass(1,Form("Oups. Got a sigma of %e for particle %s !",sigma,particle));
+    return hminv.Integral();
+  }
+  
+  TAxis* x = hminv.GetXaxis();
+
+  Int_t b1 = x->FindBin(mass-sigma);
+  Int_t b2 = x->FindBin(mass+sigma);
+  
+  AliDebugClass(1,Form("hminv getentries %e integral %e",hminv.GetEntries(),hminv.Integral(b1,b2)));
+  
+  return hminv.Integral(b1,b2);
+}
+
+/*
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::FitJpsiPsiPrimeCustom(TH1& h)
+{
+  std::cout << "Fit with jpsi + psiprime (custom)" << std::endl;
+  
+  const Double_t xmin(1.5);
+  const Double_t xmax(8.0);
+  
+  fitTotal = new TF1("fitTotal",funcJpsiPsiPrimeCustom,xmin,xmax,14);
+  fitTotal->SetLineColor(4);
+  
+  fitTotal->SetParName(0,"cstecb");
+  fitTotal->SetParName(1,"alpha");
+  fitTotal->SetParName(2,"n");
+  fitTotal->SetParName(3,"meanjpsi");
+  fitTotal->SetParName(4,"sigmajpsi");
+  fitTotal->SetParName(5,"alphaprime");
+  fitTotal->SetParName(6,"nprime");
+  fitTotal->SetParName(7,"cstepol1");
+  fitTotal->SetParName(8,"slopepol1");
+  fitTotal->SetParName(9,"cstegaus");
+  fitTotal->SetParName(10,"meanpsiprime");
+  fitTotal->SetParName(11,"sigmapsiprime");
+  fitTotal->SetParName(12,"csteexpo");
+  fitTotal->SetParName(13,"slopeexpo");
+  
+  fitTotal->SetParameter( 0,1);
+    
+  const char* fitOption = "SQBR+";
+  const Double_t alphaMC = 0.936;
+  const Double_t nMC = 4.44;
+  const Double_t alphaprimeMC = 1.60;
+  const Double_t nprimeMC = 3.23;
+  
+  TF1* fcb = new TF1("cb",funcCB2,2.9,3.3,7);
+  fcb->SetParameters(1,1.0,4.0,3.1,0.1,1.5,3);
+
+  fcb->SetParLimits(3,3,4); 
+  fcb->SetParLimits(4,0,1); 
+
+  fcb->FixParameter(1,alphaMC);
+  fcb->FixParameter(2,nMC);
+  fcb->FixParameter(5,alphaprimeMC);
+  fcb->FixParameter(6,nprimeMC);
+  
+  TFitResultPtr rcb = h.Fit(fcb,fitOption,"",2.9,3.3);
+
+  if (!rcb.Get())
+  {
+    return;
+  }
+  
+  fitTotal->SetParameter(0,rcb->Parameter(0));
+  fitTotal->SetParameter(1,rcb->Parameter(1)); fitTotal->SetParLimits(1,0,10); // alpha
+  fitTotal->SetParameter(2,rcb->Parameter(2)); fitTotal->SetParLimits(2,1,10); // n
+  fitTotal->SetParameter(3,rcb->Parameter(3)); fitTotal->SetParLimits(3,3.0,3.5); // mean
+  fitTotal->SetParameter(4,rcb->Parameter(4)); fitTotal->SetParLimits(4,0,1); // sigma
+  fitTotal->SetParameter(5,rcb->Parameter(5)); fitTotal->SetParLimits(1,0,10); // alphaprime
+  fitTotal->SetParameter(6,rcb->Parameter(6)); fitTotal->SetParLimits(2,1,10); // nprime
+
+  fitTotal->FixParameter(1,alphaMC);
+  fitTotal->FixParameter(2,nMC);
+  fitTotal->FixParameter(5,alphaprimeMC);
+  fitTotal->FixParameter(6,nprimeMC);
+  
+  TF1* fge = new TF1("fge","gaus(0)+expo(3)",3.5,4.4);
+  fge->SetParameters(1,3.6,0.25,1,1);
+  TFitResultPtr rpsiprime = h.Fit(fge,fitOption,"",3.5,4.4);
+  
+  if (static_cast<int>(rpsiprime))
+  {
+    AliInfo("Will fix psiprime parameters");
+    fitTotal->FixParameter(9,0);
+    fitTotal->FixParameter(10,3.7);
+    fitTotal->FixParameter(11,0.1);
+  }
+  else
+  {
+    fitTotal->SetParameter(10,rpsiprime->Parameter(1)); fitTotal->SetParLimits(10,3.5,3.8); // mean'
+    fitTotal->SetParameter(11,rpsiprime->Parameter(2)); fitTotal->SetParLimits(11,0.05,0.7); // sigma'
+  }
+  
+  TFitResultPtr rpol1 = h.Fit("pol1",fitOption,"",1.5,2.5);
+  fitTotal->SetParameter( 7,rpol1->Parameter(0));
+  fitTotal->SetParameter( 8,rpol1->Parameter(1));
+  
+  TFitResultPtr rexpo = h.Fit("expo",fitOption,"",4.5,7.0);
+  fitTotal->SetParameter(12,rexpo->Parameter(0));
+  fitTotal->SetParameter(13,rexpo->Parameter(1));
+  
+  
+  TFitResultPtr r = h.Fit(fitTotal,fitOption,"",1.5,7);
+  
+  TF1* signal = new TF1("signal","gaus",2,6);  
+  signal->SetParameters(fitTotal->GetParameter(0),
+                        fitTotal->GetParameter(3),
+                        fitTotal->GetParameter(4));
+
+  TF1* signalPrime = new TF1("signalPrime","gaus",2,6);  
+  signalPrime->SetParameters(fitTotal->GetParameter(9),
+                             fitTotal->GetParameter(10),
+                             fitTotal->GetParameter(11));
+  
+  Double_t gausParameters[3];
+  Double_t covarianceMatrix[3][3];
+  Double_t gausParametersPrime[3];
+  Double_t covarianceMatrixPrime[3][3];
+  
+  covarianceMatrix[0][0] = (r->GetCovarianceMatrix())(0,0);
+  covarianceMatrix[1][0] = (r->GetCovarianceMatrix())(3,0);
+  covarianceMatrix[2][0] = (r->GetCovarianceMatrix())(4,0);
+  covarianceMatrix[0][1] = (r->GetCovarianceMatrix())(0,3);
+  covarianceMatrix[0][2] = (r->GetCovarianceMatrix())(0,4);  
+  
+  for ( int iy = 1; iy < 3; ++iy )
+  {
+    for ( int ix = 1; ix < 3; ++ix )
+    {
+      covarianceMatrix[ix][iy] = (r->GetCovarianceMatrix())(ix+2,iy+2);
+    }
+  }
+  
+  gausParameters[0] = fitTotal->GetParameter(0);
+  gausParameters[1] = fitTotal->GetParameter(3);
+  gausParameters[2] = fitTotal->GetParameter(4);
+
+  gausParametersPrime[0] = fitTotal->GetParameter(9);
+  gausParametersPrime[1] = fitTotal->GetParameter(10);
+  gausParametersPrime[2] = fitTotal->GetParameter(11);
+  
+  covarianceMatrixPrime[0][0] = (r->GetCovarianceMatrix())(9,9);
+  covarianceMatrixPrime[1][0] = (r->GetCovarianceMatrix())(10,9);
+  covarianceMatrixPrime[2][0] = (r->GetCovarianceMatrix())(11,9);
+  covarianceMatrixPrime[0][1] = (r->GetCovarianceMatrix())(9,10);
+  covarianceMatrixPrime[0][2] = (r->GetCovarianceMatrix())(9,11);  
+  
+  for ( int iy = 1; iy < 3; ++iy )
+  {
+    for ( int ix = 1; ix < 3; ++ix )
+    {
+      covarianceMatrixPrime[ix][iy] = (r->GetCovarianceMatrix())(ix+2,iy+2);
+    }
+  }
+  
+  double n = signal->Integral(2,6)/h.GetBinWidth(10);
+  double nerr = signal->IntegralError(2,6,&gausParameters[0],&covarianceMatrix[0][0])/h.GetBinWidth(10);
+  Set("NofJpsi",n,nerr);      
+  Set("MeanJpsi",fitTotal->GetParameter(3),fitTotal->GetParError(3));
+  Set("SigmaJpsi",fitTotal->GetParameter(4),fitTotal->GetParError(4));
+
+  double nprime = signalPrime->Integral(2,6)/h.GetBinWidth(10);
+  double nerrprime = signalPrime->IntegralError(2,6,&gausParametersPrime[0],&covarianceMatrixPrime[0][0])/h.GetBinWidth(10);
+  Set("NofPsiPrime",nprime,nerrprime);
+  Set("MeanPsiPrime",fitTotal->GetParameter(10),fitTotal->GetParError(10));
+  Set("SigmaPsiPrime",fitTotal->GetParameter(11),fitTotal->GetParError(11));
+}
+*/
+
+/*
+//_____________________________________________________________________________
+AliAnalysisMuMuResult::SubResult AliAnalysisMuMuResult::FitJpsiPsiPrimeCB(TH1& h)
+{
+  std::cout << "Fit with jpsi + psiprime (CB) " << std::endl;
+
+  const Double_t xmin(1.5);
+  const Double_t xmax(8.0);
+  
+  fitTotal = new TF1("fitTotal",funcJpsiPsiPrime,xmin,xmax,14);
+
+//  Double_t N = par[0];
+//  Double_t alpha = par[1];
+//  Double_t n = par[2];
+//  Double_t mean = par[3];
+//  Double_t sigma = par[4];
+  
+  fitTotal->SetParameter( 0,1); // N
+  fitTotal->FixParameter( 1,0.936); // alpha
+  fitTotal->FixParameter( 2,4.44); // n
+  fitTotal->SetParameter( 3,3.1); fitTotal->SetParLimits(3,3.0,3.2); // mean
+  fitTotal->SetParameter( 4,0.07); fitTotal->SetParLimits(4,0.02,1); // sigma
+
+  fitTotal->SetParameter( 5,0.01); // N'
+  fitTotal->FixParameter( 6,0.936); // alpha'
+  fitTotal->FixParameter( 7,4.44); // n'
+  fitTotal->SetParameter( 8,3.7); fitTotal->SetParLimits(8,3.5,3.8); // mean'
+  fitTotal->SetParameter( 9,0.1); fitTotal->SetParLimits(9,0.02,1.0); // sigma'
+  
+  fitTotal->SetParameter(10,h.GetMaximum());
+  fitTotal->SetParameter(11,-1);
+
+  fitTotal->SetParameter(12,h.GetMaximum()/100);
+  fitTotal->SetParameter(13,-1);
+
+  TFitResultPtr r = h.Fit(fitTotal,"SQBI","",1.5,6);
+  
+//  for ( int ix = 0; ix < fitTotal->GetNpar(); ++ix )
+//  {
+//    for ( int iy = 0; iy < fitTotal->GetNpar(); ++iy )
+//    {      
+//      std::cout << Form("COV(%d,%d)=%e ",ix,iy,r->GetCovarianceMatrix()(ix,iy));        
+//    }
+//    std::cout << std::endl;
+//  }
+  
+  
+  TF1* signal = new TF1("signal","gaus",2,8);
+  
+  signal->SetParameters(fitTotal->GetParameter(0),
+                        fitTotal->GetParameter(3),
+                        fitTotal->GetParameter(4));
+
+  TF1* signalPrime = new TF1("signalPrime","gaus",2,8);
+  
+  signalPrime->SetParameters(fitTotal->GetParameter(0),
+                             fitTotal->GetParameter(8),
+                             fitTotal->GetParameter(9));
+  
+  Double_t gausParameters[3];
+  Double_t gausParametersPrime[3];
+  Double_t covarianceMatrix[3][3];
+  Double_t covarianceMatrixPrime[3][3];
+  
+  gausParameters[0] = fitTotal->GetParameter(0);
+  gausParameters[1] = fitTotal->GetParameter(3);
+  gausParameters[2] = fitTotal->GetParameter(4);
+
+  covarianceMatrix[0][0] = (r->GetCovarianceMatrix())(0,0);
+  covarianceMatrix[1][0] = (r->GetCovarianceMatrix())(3,0);
+  covarianceMatrix[2][0] = (r->GetCovarianceMatrix())(4,0);
+  covarianceMatrix[0][1] = (r->GetCovarianceMatrix())(0,3);
+  covarianceMatrix[0][2] = (r->GetCovarianceMatrix())(0,4);
+  
+  for ( int iy = 1; iy < 3; ++iy )
+  {
+    for ( int ix = 1; ix < 3; ++ix )
+    {
+      covarianceMatrix[ix][iy] = (r->GetCovarianceMatrix())(ix+2,iy+2);
+    }
+  }
+
+  gausParametersPrime[0] = fitTotal->GetParameter(0);
+  gausParametersPrime[1] = fitTotal->GetParameter(8);
+  gausParametersPrime[2] = fitTotal->GetParameter(9);
+
+  covarianceMatrixPrime[0][0] = (r->GetCovarianceMatrix())(0,0);
+  covarianceMatrixPrime[1][0] = (r->GetCovarianceMatrix())(8,0);
+  covarianceMatrixPrime[2][0] = (r->GetCovarianceMatrix())(9,0);
+  covarianceMatrixPrime[0][1] = (r->GetCovarianceMatrix())(0,8);
+  covarianceMatrixPrime[0][2] = (r->GetCovarianceMatrix())(0,9);
+  
+  for ( int iy = 1; iy < 3; ++iy )
+  {
+    for ( int ix = 1; ix < 3; ++ix )
+    {
+      covarianceMatrixPrime[ix][iy] = (r->GetCovarianceMatrix())(ix+2,iy+2);
+    }
+  }
+  
+  double n = signal->Integral(2,6)/h.GetBinWidth(10);
+  double nerr = signal->IntegralError(2,6,&gausParameters[0],&covarianceMatrix[0][0])/h.GetBinWidth(10);
+
+  Set("NofJpsi",n,nerr);      
+  Set("MeanJpsi",fitTotal->GetParameter(3),fitTotal->GetParError(3));
+  Set("SigmaJpsi",fitTotal->GetParameter(4),fitTotal->GetParError(4));
+
+  double nprime = signalPrime->Integral(2,6)/h.GetBinWidth(10);
+  double nerrprime = signalPrime->IntegralError(2,6,&gausParametersPrime[0],&covarianceMatrixPrime[0][0])/h.GetBinWidth(10);
+  
+  Set("NofPsiPrime",nprime,nerrprime);
+  Set("MeanPsiPrime",fitTotal->GetParameter(8),fitTotal->GetParError(8));
+  Set("SigmaPsiPrime",fitTotal->GetParameter(9),fitTotal->GetParError(9));
+  
+}
+  */
+
+//_____________________________________________________________________________
+AliAnalysisMuMuResult* AliAnalysisMuMuResult::FitJpsiGCBE(TH1& h)
+{
+  std::cout << "Fit with jpsi alone (gaus + CB + expo)" << std::endl;
+  
+  Int_t nrebin = fMinv->GetXaxis()->GetNbins() / h.GetXaxis()->GetNbins();
+  
+  AliAnalysisMuMuResult* r = new AliAnalysisMuMuResult(h,"JPSIGCBE",nrebin);
+  
+  TH1* hfit = r->Minv();
+  
+  const Double_t xmin(1.0);
+  const Double_t xmax(8.0);
+  
+  TF1* fitTotal = new TF1("fitTotal",funcJpsiGCBE,xmin,xmax,10);
+  fitTotal->SetParNames("cste","x0","sigma0","N","alpha","n","mean","sigma","expocste","exposlope");
+  
+  fitTotal->SetParLimits(3,0,h.GetMaximum()*2); // N
+  
+  const Double_t cbalpha(0.98);
+  const Double_t cbn(5.2);
+  
+  fitTotal->FixParameter(4,cbalpha);
+  fitTotal->FixParameter(5,cbn);
+  
+  fitTotal->SetParLimits(6,2.8,3.2); // mean
+  fitTotal->SetParLimits(7,0.02,0.3); // sigma
+  
+  TF1* fg = new TF1("fg","gaus",xmin,xmax);
+  
+  hfit->Fit(fg,"","",0.75,3.0);
+  
+  fitTotal->SetParameter(0,fg->GetParameter(0));
+  fitTotal->SetParameter(1,fg->GetParameter(1));
+  fitTotal->SetParameter(2,fg->GetParameter(2));
+  
+  TF1* fexpo = new TF1("expo","expo",xmin,xmax);
+  
+  hfit->Fit(fexpo,"","",3.5,5);
+  
+  fitTotal->SetParameter(8,fexpo->GetParameter(0));
+  fitTotal->SetParameter(9,fexpo->GetParameter(1));
+  
+  fitTotal->SetParameter(3,h.GetMaximum()),
+  fitTotal->SetParameter(4,cbalpha);
+  fitTotal->SetParameter(5,cbn);
+  fitTotal->SetParameter(6,3.15);
+  fitTotal->SetParameter(7,0.1);
+  
+  const char* fitOption = "SI+";
+  
+  TFitResultPtr fitResult = hfit->Fit(fitTotal,fitOption,"",2,5);
+  
+  r->Set("MeanJpsi",fitTotal->GetParameter(6),fitTotal->GetParError(6));
+  r->Set("SigmaJpsi",fitTotal->GetParameter(7),fitTotal->GetParError(7));
+  
+  double m = r->GetValue("MeanJpsi");
+  double s = r->GetValue("SigmaJpsi");
+  double n = 3.0;
+  
+  TF1* fcb = new TF1("fcb",funcCB,xmin,xmax,5);
+  fcb->SetParameters(fitTotal->GetParameter(3),
+                     fitTotal->GetParameter(4),
+                     fitTotal->GetParameter(5),
+                     fitTotal->GetParameter(6),
+                     fitTotal->GetParameter(7));
+  
+  fcb->SetLineColor(6);
+  fcb->SetNpx(100);
+  TLine* l1 = new TLine(m-n*s,0,m-n*s,fitTotal->GetParameter(3));
+  TLine* l2 = new TLine(m+n*s,0,m+n*s,fitTotal->GetParameter(3));
+  l1->SetLineColor(6);
+  l2->SetLineColor(6);
+  h.GetListOfFunctions()->Add(fcb);
+  h.GetListOfFunctions()->Add(l1);
+  h.GetListOfFunctions()->Add(l2);
+  
+  
+  Double_t cbParameters[5];
+  Double_t covarianceMatrix[5][5];
+  
+  cbParameters[0] = fitTotal->GetParameter(3);
+  cbParameters[1] = fitTotal->GetParameter(4);
+  cbParameters[2] = fitTotal->GetParameter(5);
+  cbParameters[3] = fitTotal->GetParameter(6);
+  cbParameters[4] = fitTotal->GetParameter(7);
+  
+  for ( int iy = 0; iy < 5; ++iy )
+  {
+    for ( int ix = 0; ix < 5; ++ix )
+    {
+      covarianceMatrix[ix][iy] = (fitResult->GetCovarianceMatrix())(ix+3,iy+3);
+    }
+  }
+  
+  double njpsi = fcb->Integral(m-n*s,m+n*s)/h.GetBinWidth(1);
+  
+  double nerr = fcb->IntegralError(m-n*s,m+n*s,&cbParameters[0],&covarianceMatrix[0][0])/h.GetBinWidth(1);
+  
+  r->Set("NofJpsi",njpsi,nerr);
+  
+  return r;
+}
+
+/*
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::FitJpsiPCBE(TH1& h)
+{
+  std::cout << "Fit with jpsi alone (pol2 + CB + expo)" << std::endl;
+  
+  const Double_t xmin(2.0);
+  const Double_t xmax(5.0);
+  
+  fitTotal = new TF1("fitTotal",funcJpsiPCBE,xmin,xmax,10);
+  fitTotal->SetParNames("p0","p1","p2","N","alpha","n","mean","sigma","expocste","exposlope");
+  
+  fitTotal->SetParLimits(3,0,h.GetMaximum()*2); // N
+
+  const Double_t cbalpha(0.98);
+  const Double_t cbn(5.2);
+  
+  fitTotal->FixParameter(4,cbalpha);
+  fitTotal->FixParameter(5,cbn);
+  
+  fitTotal->SetParLimits(6,2,4); // mean
+  fitTotal->SetParLimits(7,0.05,0.2); // sigma
+  
+  TF1* fpol2 = new TF1("pol2","pol2",xmin,xmax);
+                       
+  h.Fit(fpol2,"+","",2,2.8);
+  
+  fitTotal->SetParameter(0,fpol2->GetParameter(0));
+  fitTotal->SetParameter(1,fpol2->GetParameter(1));
+  fitTotal->SetParameter(2,fpol2->GetParameter(2));
+
+  TF1* fexpo = new TF1("expo","expo",xmin,xmax);
+  
+  h.Fit(fexpo,"+","",3.5,4.5);
+  
+  fitTotal->SetParameter(8,fexpo->GetParameter(0));
+  fitTotal->SetParameter(9,fexpo->GetParameter(1));
+    
+  fitTotal->SetParameter(3,h.GetMaximum()),
+  fitTotal->SetParameter(4,cbalpha);
+  fitTotal->SetParameter(5,cbn);
+  fitTotal->SetParameter(6,3.15);
+  fitTotal->SetParameter(7,0.1);
+  
+  h.Fit(fitTotal,"+","",2.5,5);
+    
+  Set("MeanJpsi",fitTotal->GetParameter(6),fitTotal->GetParError(6));
+  Set("SigmaJpsi",fitTotal->GetParameter(7),fitTotal->GetParError(7));
+  
+  double m = GetValue("MeanJpsi");
+  double s = GetValue("SigmaJpsi");
+  double n = 2.0;
+  
+  TF1* fcb = new TF1("fcb",funcCB,xmin,xmax,5);
+  fcb->SetParameters(fitTotal->GetParameter(3),
+                     fitTotal->GetParameter(4),
+                     fitTotal->GetParameter(5),
+                     fitTotal->GetParameter(6),
+                     fitTotal->GetParameter(7));
+  
+  fcb->SetLineColor(6);
+  fcb->SetNpx(100);
+  TLine* l1 = new TLine(m-n*s,0,m-n*s,fitTotal->GetParameter(3));
+  TLine* l2 = new TLine(m+n*s,0,m+n*s,fitTotal->GetParameter(3));
+  l1->SetLineColor(6);
+  l2->SetLineColor(6);
+  h.GetListOfFunctions()->Add(fcb);
+  h.GetListOfFunctions()->Add(l1);
+  h.GetListOfFunctions()->Add(l2);
+  
+  
+  Set("NofJpsi",fitTotal->Integral(m-n*s,m+n*s)/h.GetBinWidth(1),fitTotal->IntegralError(m-n*s,m+n*s)/h.GetBinWidth(1));
+  
+  //  Set("NofJpsi",fitTotal->Integral(0,10)/h.GetBinWidth(1),fitTotal->IntegralError(0,10)/h.GetBinWidth(1));
+  
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::FitJpsiCBE(TH1& h)
+{
+  std::cout << "Fit with jpsi alone" << std::endl;
+  
+  const Double_t xmin(1.5);
+  const Double_t xmax(8.0);
+  
+  fitTotal = new TF1("fitTotal",funcJpsiCBE,xmin,xmax,7);
+  fitTotal->SetParNames("N","alpha","n","mean","sigma","expocste","exposlope");
+  
+//  fitTotal->SetParameters(h.GetMaximum(),1,5,3.0,0.07,1.5,3,1,0);
+
+  fitTotal->SetParameters(1,1.15,3.6,3.0,0.07,1,-1);
+
+  fitTotal->SetParLimits(0,0,h.GetMaximum()); // N
+//  fitTotal->SetParLimits(1,0.1,2); // alpha
+  fitTotal->FixParameter(1,0.98);
+//  fitTotal->SetParLimits(2,0.01,5); // n
+  fitTotal->FixParameter(2,5.2);
+  fitTotal->SetParLimits(3,2.8,3.5); // mean
+  fitTotal->SetParLimits(4,0.05,0.2); // sigma
+  
+  TF1* fexpo = new TF1("expo","expo",xmin,xmax);
+  
+  h.Fit(fexpo,"+","",2,3);
+  
+  fitTotal->SetParameter(5,fexpo->GetParameter(0));
+  fitTotal->SetParameter(6,fexpo->GetParameter(1));
+  
+  h.Fit(fitTotal,"+","",2,5);
+  
+  
+  Set("MeanJpsi",fitTotal->GetParameter(3),fitTotal->GetParError(3));
+  Set("SigmaJpsi",fitTotal->GetParameter(4),fitTotal->GetParError(4));
+  
+  double m = GetValue("MeanJpsi");
+  double s = GetValue("SigmaJpsi");
+  double n = 3.0;
+  
+  TF1* fcb = new TF1("fcb",funcCB,xmin,xmax,5);
+  fcb->SetParameters(fitTotal->GetParameter(0),
+                     fitTotal->GetParameter(1),
+                     fitTotal->GetParameter(2),
+                     fitTotal->GetParameter(3),
+                     fitTotal->GetParameter(4));
+
+  fcb->SetLineColor(6);
+  fcb->SetNpx(1000);
+  TLine* l1 = new TLine(m-n*s,0,m-n*s,fitTotal->GetParameter(0));
+  TLine* l2 = new TLine(m+n*s,0,m+n*s,fitTotal->GetParameter(0));
+  l1->SetLineColor(6);
+  l2->SetLineColor(6);
+  h.GetListOfFunctions()->Add(fcb);
+  h.GetListOfFunctions()->Add(l1);
+  h.GetListOfFunctions()->Add(l2);
+  
+  
+  Set("NofJpsi",fitTotal->Integral(m-n*s,m+n*s)/h.GetBinWidth(1),fitTotal->IntegralError(m-n*s,m+n*s)/h.GetBinWidth(1));
+  
+  //  Set("NofJpsi",fitTotal->Integral(0,10)/h.GetBinWidth(1),fitTotal->IntegralError(0,10)/h.GetBinWidth(1));
+  
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::FitJpsiECBE(TH1& h)
+{
+  std::cout << "Fit with jpsi alone (expo + CB + expo)" << std::endl;
+  
+  const Double_t xmin(1.5);
+  const Double_t xmax(8.0);
+  
+  fitTotal = new TF1("fitTotal",funcJpsiECBE,xmin,xmax,9);
+  fitTotal->SetParNames("e0","s0","N","alpha","n","mean","sigma","e1","s1");
+  
+  fitTotal->SetParameters(1,-1,1,1.15,3.6,3.2,0.06,-1);
+
+  fitTotal->SetParLimits(0,0,h.GetMaximum()*2);
+  
+  fitTotal->FixParameter(3,0.98); // alpha
+  fitTotal->FixParameter(4,5.2); // n
+  fitTotal->SetParLimits(5,2.8,3.5); // mean
+  fitTotal->SetParLimits(6,0.05,0.2); // sigma
+  
+  TF1* fexpo1 = new TF1("expo1","expo",xmin,xmax);
+  TF1* fexpo2 = new TF1("expo2","expo",xmin,xmax);
+  
+  h.Fit(fexpo1,"","",1.5,3);
+  
+  fitTotal->SetParameter(0,fexpo1->GetParameter(0));
+  fitTotal->SetParameter(1,fexpo1->GetParameter(1));
+
+  h.Fit(fexpo2,"","",3.5,5.0);
+
+  fitTotal->SetParameter(7,fexpo2->GetParameter(0));
+  fitTotal->SetParameter(8,fexpo2->GetParameter(1));
+
+  const char* fitOption = "SI+";
+  
+  TFitResultPtr r = h.Fit(fitTotal,fitOption,"",2,5);
+  
+  Set("MeanJpsi",fitTotal->GetParameter(5),fitTotal->GetParError(5));
+  Set("SigmaJpsi",fitTotal->GetParameter(6),fitTotal->GetParError(6));
+  
+  double m = GetValue("MeanJpsi");
+  double s = GetValue("SigmaJpsi");
+  double n = 3.0;
+  
+  TF1* fcb = new TF1("fcb",funcCB,xmin,xmax,5);
+  fcb->SetParameters(fitTotal->GetParameter(2),
+                     fitTotal->GetParameter(3),
+                     fitTotal->GetParameter(4),
+                     fitTotal->GetParameter(5),
+                     fitTotal->GetParameter(6));
+
+  fcb->SetParError(0,fitTotal->GetParError(2));
+  fcb->SetParError(1,fitTotal->GetParError(3));
+  fcb->SetParError(2,fitTotal->GetParError(4));
+  fcb->SetParError(3,fitTotal->GetParError(5));
+  fcb->SetParError(4,fitTotal->GetParError(6));
+  
+  fcb->SetLineColor(6);
+  fcb->SetNpx(1000);
+  TLine* l1 = new TLine(m-n*s,0,m-n*s,fitTotal->GetParameter(2));
+  TLine* l2 = new TLine(m+n*s,0,m+n*s,fitTotal->GetParameter(2));
+  l1->SetLineColor(6);
+  l2->SetLineColor(6);
+  h.GetListOfFunctions()->Add(fcb);
+  h.GetListOfFunctions()->Add(l1);
+  h.GetListOfFunctions()->Add(l2);
+  
+  
+  Double_t cbParameters[5];
+  Double_t covarianceMatrix[5][5];
+  
+  cbParameters[0] = fitTotal->GetParameter(2);
+  cbParameters[1] = fitTotal->GetParameter(3);
+  cbParameters[2] = fitTotal->GetParameter(4);
+  cbParameters[3] = fitTotal->GetParameter(5);
+  cbParameters[4] = fitTotal->GetParameter(6);
+  
+  for ( int iy = 0; iy < 5; ++iy )
+  {
+    for ( int ix = 0; ix < 5; ++ix )
+    {
+      covarianceMatrix[ix][iy] = (r->GetCovarianceMatrix())(ix+2,iy+2);
+    }
+  }
+  
+
+  double njpsi = fcb->Integral(m-n*s,m+n*s)/h.GetBinWidth(1);
+  
+  double nerr = fcb->IntegralError(m-n*s,m+n*s,&cbParameters[0],&covarianceMatrix[0][0])/h.GetBinWidth(1);
+  
+
+  Set("NofJpsi",njpsi,nerr);
+}
+
+ */
+
+//_____________________________________________________________________________
+AliAnalysisMuMuResult* AliAnalysisMuMuResult::FitJpsi(TH1& h)
+{
+  std::cout << "Fit with jpsi alone" << std::endl;
+
+  Int_t nrebin = fMinv->GetXaxis()->GetNbins() / h.GetXaxis()->GetNbins();
+  
+  AliAnalysisMuMuResult* r = new AliAnalysisMuMuResult(h,"JPSI",nrebin);
+  
+  TH1* hfit = r->Minv();
+
+  const Double_t xmin(1.5);
+  const Double_t xmax(8.0);
+
+  TF1* fitTotal = new TF1("fitTotal",funcCB2,xmin,xmax,7);
+  fitTotal->SetParNames("N","alpha","n","mean","sigma","alphaprime","nprime");
+  fitTotal->SetParameters(h.GetMaximum(),1,5,3.0,0.07,1.5,3);
+  fitTotal->SetParLimits(0,0,h.GetMaximum()*2); // N
+  fitTotal->SetParLimits(1,0,10); // alpha
+  fitTotal->SetParLimits(2,1,10); // n
+  fitTotal->SetParLimits(3,1,4); // mean
+  fitTotal->SetParLimits(4,0.01,1); // sigma
+  fitTotal->SetParLimits(5,0,10); // alpha
+  fitTotal->SetParLimits(6,1,10); // n
+  
+  hfit->Fit(fitTotal,"+","",2,5);
+  
+  
+  r->Set("MeanJpsi",fitTotal->GetParameter(3),fitTotal->GetParError(3));
+  r->Set("SigmaJpsi",fitTotal->GetParameter(4),fitTotal->GetParError(4));
+
+  double m = r->GetValue("MeanJpsi");
+  double s = r->GetValue("SigmaJpsi");
+  double n = 10.0;
+
+  r->Set("NofJpsi",fitTotal->Integral(m-n*s,m+n*s)/h.GetBinWidth(1),fitTotal->IntegralError(m-n*s,m+n*s)/h.GetBinWidth(1));
+
+  return r;
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuResult* AliAnalysisMuMuResult::FitJpsi2CB2VWG(const TH1& h)
+{
+  std::cout << "Fit with jpsi + psiprime VWG" << std::endl;
+  
+  Int_t nrebin = fMinv->GetXaxis()->GetNbins() / h.GetXaxis()->GetNbins();
+  
+  AliAnalysisMuMuResult* r = new AliAnalysisMuMuResult(h,"JPSI2CB2VWG",nrebin);
+  
+  
+  TH1* hfit = r->Minv();
+  
+  const Double_t xmin(2.2);
+  const Double_t xmax(5.0);
+  
+  TF1* fitTotal = new TF1("fitTotal",func2CB2VWG,xmin,xmax,12);
+  fitTotal->SetParNames("kVWG","mVWG","sVWG1","sVWG2","kPsi","mPsi","sPsi","alPsi","nlPsi","auPsi","nuPsi");
+  fitTotal->SetParName(11, "kPsi'");
+
+  fitTotal->SetParameter(0, 10000.);
+  fitTotal->SetParameter(1, 1.9);
+  fitTotal->SetParameter(2, 0.5);
+  fitTotal->SetParLimits(2, 0., 100.);
+  fitTotal->SetParameter(3, 0.3);
+  fitTotal->SetParLimits(3, 0., 100.);
+  fitTotal->SetParameter(4, 100.);
+  fitTotal->SetParameter(5, 3.13);
+  fitTotal->SetParLimits(5, 3.08, 3.2);
+  fitTotal->SetParameter(6, 0.08);
+  fitTotal->SetParLimits(6, 0.05, 0.15);
+  fitTotal->FixParameter(7, 0.93);
+  fitTotal->FixParameter(8, 5.59);
+  fitTotal->FixParameter(9, 2.32);
+  fitTotal->FixParameter(10, 3.39);
+  fitTotal->SetParameter(11, 10.);
+
+  const char* fitOption = "SIER"; //+";
+  
+  TFitResultPtr fitResult = hfit->Fit(fitTotal,fitOption,"");
+  
+  r->Set("MeanJpsi",fitTotal->GetParameter(5),fitTotal->GetParError(5));
+  r->Set("SigmaJpsi",fitTotal->GetParameter(6),fitTotal->GetParError(6));
+  
+  double m = r->GetValue("MeanJpsi");
+  double s = r->GetValue("SigmaJpsi");
+  double n = 3.0;
+    
+  TF1* fcb = new TF1("fcb",CrystalBallExtended,xmin,xmax,7);
+  fcb->SetParameters(fitTotal->GetParameter(4),
+                     fitTotal->GetParameter(5),
+                     fitTotal->GetParameter(6),
+                     fitTotal->GetParameter(7),
+                     fitTotal->GetParameter(8),
+                     fitTotal->GetParameter(9),
+                     fitTotal->GetParameter(10));
+                     
+  
+  fcb->SetLineColor(1);
+  fcb->SetNpx(1000);
+  TLine* l1 = new TLine(m-n*s,0,m-n*s,fitTotal->GetParameter(4));
+  TLine* l2 = new TLine(m+n*s,0,m+n*s,fitTotal->GetParameter(4));
+  l1->SetLineColor(6);
+  l2->SetLineColor(6);
+  hfit->GetListOfFunctions()->Add(fcb);
+  hfit->GetListOfFunctions()->Add(l1);
+  hfit->GetListOfFunctions()->Add(l2);
+  
+  Double_t cbParameters[7];
+  Double_t covarianceMatrix[7][7];
+  
+  for ( int ix = 0; ix < 7; ++ix )
+  {
+    cbParameters[ix] = fitTotal->GetParameter(ix+4);
+  }
+  
+  for ( int iy = 0; iy < 5; ++iy )
+  {
+    for ( int ix = 0; ix < 5; ++ix )
+    {
+      covarianceMatrix[ix][iy] = (fitResult->GetCovarianceMatrix())(ix+4,iy+4);
+    }
+  }
+  
+  double njpsi = fcb->Integral(m-n*s,m+n*s)/h.GetBinWidth(1);
+  double nerr = fcb->IntegralError(m-n*s,m+n*s,&cbParameters[0],&covarianceMatrix[0][0])/h.GetBinWidth(1);
+  
+  r->Set("NofJpsi",njpsi,nerr);
+  
+  return r;
+}
+
+/*
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::FitUpsilon(TH1& h)
+{
+  std::cout << "Fit with upsilon alone" << std::endl;
+  
+  const Double_t xmin(6.0);
+  const Double_t xmax(12.0);
+  
+  fitTotal = new TF1("fitTotal",funcCB2,xmin,xmax,7);
+  fitTotal->SetParNames("N","alpha","n","mean","sigma","alphaprime","nprime");
+  fitTotal->SetParameters(h.GetMaximum(),1,5,9.46,0.2,1.5,3);
+  fitTotal->SetParLimits(0,0,h.GetMaximum()*2); // N
+  fitTotal->SetParLimits(1,0,10); // alpha
+  fitTotal->SetParLimits(2,1,10); // n
+  fitTotal->SetParLimits(3,8,12); // mean
+  fitTotal->SetParLimits(4,0.01,1); // sigma
+  fitTotal->SetParLimits(5,0,10); // alpha
+  fitTotal->SetParLimits(6,1,10); // n
+  
+  h.Fit(fitTotal,"+","",6,12);
+  
+  
+  Set("MeanUpsilon",fitTotal->GetParameter(3),fitTotal->GetParError(3));
+  Set("SigmaUpsilon",fitTotal->GetParameter(4),fitTotal->GetParError(4));
+  
+  double m = GetValue("MeanUpsilon");
+  double s = GetValue("SigmaUpsilon");
+  double n = 3.0;
+  
+  Set("NofUpsilon",fitTotal->Integral(m-n*s,m+n*s)/h.GetBinWidth(1),fitTotal->IntegralError(m-n*s,m+n*s)/h.GetBinWidth(1));  
+}
+*/
+
+//_____________________________________________________________________________
+Double_t AliAnalysisMuMuResult::ErrorAB(Double_t a, Double_t aerr, Double_t b, Double_t berr)
+{
+  Double_t e(0.0);
+  
+  if ( TMath::Abs(a) > 1E-12 )
+  {
+    e += (aerr*aerr)/(a*a);
+  }
+  
+  if ( TMath::Abs(b) > 1E-12 )
+  {
+    e += (berr*berr)/(b*b);
+  }
+  
+  return TMath::Sqrt(e);
+}
+
+//_____________________________________________________________________________
+Double_t AliAnalysisMuMuResult::ErrorABC(Double_t a, Double_t aerr, Double_t b, Double_t berr, Double_t c, Double_t cerror)
+{
+  Double_t e(0.0);
+  
+  if ( TMath::Abs(a) > 1E-12 )
+  {
+    e += (aerr*aerr)/(a*a);
+  }
+  
+  if ( TMath::Abs(b) > 1E-12 )
+  {
+    e += (berr*berr)/(b*b);
+  }
+  
+  if ( TMath::Abs(b) > 1E-12 )
+  {
+    e += (cerror*cerror)/(c*c);
+  }
+  
+  return TMath::Sqrt(e);
+}
+
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuResult::AddFit(const char* fitType, Int_t nrebin)
+{
+  //  new TCanvas;
+  
+  if ( !fMinv ) return kFALSE;
+  
+  TString sFitType(fitType);
+  sFitType.ToUpper();
+  
+  if ( fMinv->GetEntries()<100 && !sFitType.Contains("COUNT")) return kFALSE;
+  
+  TH1* hminv = static_cast<TH1*>(fMinv->Clone());
+  
+  hminv->Rebin(nrebin);
+  hminv->SetDirectory(0);
+
+  AliAnalysisMuMuResult* r(0x0);
+  
+//  if ( sFitType == "PSI12" )
+//  {
+//    r = FitJpsiPsiPrimeCustom(*hminv);
+//  }
+//
+  if ( sFitType=="PSI1")
+  {//
+    r = FitJpsi(*hminv);
+//    r = FitJpsiGCBE(*hminv);
+  }
+  
+  if ( sFitType == "PSILOW")
+  {
+    r = FitJpsi2CB2VWG(*hminv);
+  }
+
+  if ( sFitType == "COUNTPSI" )
+  {
+    r = new AliAnalysisMuMuResult(*hminv,"COUNTJPSI",1);
+    Double_t n = CountParticle(*hminv,"Jpsi");
+    r->Set("NofJpsi",n,TMath::Sqrt(n));
+  }
+  
+//  if (r)
+//  {
+//    r->SetNofInputParticles("Jpsi",GetValue("NofInputJpsi"));
+//  }
+
+  if (!fSubResults)
+  {
+    fSubResults = new TObjArray;
+    fSubResults->SetOwner(kTRUE);
+  }
+  
+  if ( r )
+  {
+    r->Print();
+    r->SetBin(Bin());
+    r->SetNofTriggers(NofTriggers());
+    r->SetNofRuns(NofRuns());
+    fSubResults->Add(r);
+  }
+  
+  delete hminv;
+  
+  return (r!=0x0);
+}
+
+//_____________________________________________________________________________
+Double_t AliAnalysisMuMuResult::GetErrorStat(const char* name, const char* subResultName) const
+{
+  // compute the mean value from all subresults
+  
+  if ( strlen(subResultName) > 0 )
+  {
+    if ( !fSubResults)
+    {
+      AliError(Form("No subresult from which I could get the %s one...",subResultName));
+      return TMath::Limits<Double_t>::Max();
+    }
+    AliAnalysisMuMuResult* sub = static_cast<AliAnalysisMuMuResult*>(fSubResults->FindObject(subResultName));
+    if (!sub)
+    {
+      AliError(Form("Could not get subresult named %s",subResultName));
+      return TMath::Limits<Double_t>::Max();
+    }
+    return sub->GetErrorStat(name);
+  }
+  
+  if ( fMap )
+  {
+    TObjArray* p = static_cast<TObjArray*>(fMap->GetValue(name));
+    if (p)
+    {
+      TParameter<double>* val = static_cast<TParameter<double>*>(p->At(kErrorStat));
+      return val->GetVal();
+    }
+  }
+  
+  TIter next(fSubResults);
+  AliAnalysisMuMuResult* r;
+  Int_t n(0);
+  Double_t mean(0);
+  
+  while ( ( r = static_cast<AliAnalysisMuMuResult*>(next()) ) )
+  {
+    if ( r->HasValue(name) )
+    {
+      mean += r->GetErrorStat(name);
+      ++n;
+    }
+  }
+  return ( n ? mean/n : 0.0 );
+}
+
+//_____________________________________________________________________________
+Double_t AliAnalysisMuMuResult::GetValue(const char* name, const char* subResultName) const
+{
+  // get a value (either directly or by computing the mean of the subresults)
+  
+  if ( strlen(subResultName) > 0 )
+  {
+    if ( !fSubResults)
+    {
+      AliError(Form("No subresult from which I could get the %s one...",subResultName));
+      return TMath::Limits<Double_t>::Max();
+    }
+    AliAnalysisMuMuResult* sub = static_cast<AliAnalysisMuMuResult*>(fSubResults->FindObject(subResultName));
+    if (!sub)
+    {
+      AliError(Form("Could not get subresult named %s",subResultName));
+      return TMath::Limits<Double_t>::Max();
+    }
+    return sub->GetValue(name);
+  }
+  
+  if (fMap)
+  {
+    TObjArray* p = static_cast<TObjArray*>(fMap->GetValue(name));
+    if (p)
+    {
+      TParameter<double>* val = static_cast<TParameter<double>*>(p->At(kValue));
+      return val->GetVal();
+    }
+  }
+  
+  // compute the mean value from all subresults
+  TIter next(fSubResults);
+  AliAnalysisMuMuResult* r;
+  Int_t n(0);
+  Double_t mean(0);
+  
+  while ( ( r = static_cast<AliAnalysisMuMuResult*>(next()) ) )
+  {
+    if ( r->HasValue(name) )
+    {
+      mean += r->GetValue(name);
+      ++n;
+    }
+  }
+  return ( n ? mean/n : 0.0 );
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuResult::HasValue(const char* name, const char* subResultName) const
+{
+  if ( strlen(subResultName) > 0 )
+  {
+    if ( !fSubResults)
+    {
+      AliError(Form("No subresult from which I could get the %s one...",subResultName));
+      return kFALSE;
+    }
+    AliAnalysisMuMuResult* sub = static_cast<AliAnalysisMuMuResult*>(fSubResults->FindObject(subResultName));
+    if (!sub)
+    {
+      AliError(Form("Could not get subresult named %s",subResultName));
+      return kFALSE;
+    }
+    return sub->HasValue(name);
+  }
+
+  if ( fMap && ( fMap->GetValue(name) != 0x0 ) )
+  {
+    return kTRUE;
+  }
+  
+  TIter next(fSubResults);
+  AliAnalysisMuMuResult* r;
+
+  while ( ( r = static_cast<AliAnalysisMuMuResult*>(next()) ) )
+  {
+    if ( r->HasValue(name) ) return kTRUE;
+  }
+  
+  return kFALSE;
+}
+
+//_____________________________________________________________________________
+THashList* AliAnalysisMuMuResult::Keys() const
+{
+  /// Return the complete list of keys we're using
+  if (!fKeys)
+  {
+    fKeys = new THashList;
+    fKeys->SetOwner(kTRUE);
+    TIter next(fMap);
+    TObjString* key;
+    
+    while ( ( key = static_cast<TObjString*>(next()) ) )
+    {
+      if ( !fKeys->FindObject(key->String()) )
+      {
+        fKeys->Add(new TObjString(key->String()));
+      }
+    }
+    
+    AliAnalysisMuMuResult* r;
+    TIter nextResult(fSubResults);
+    
+    while ( ( r = static_cast<AliAnalysisMuMuResult*>(nextResult())) )
+    {
+      TIter nextHL(r->Keys());
+      TObjString* s;
+      
+      while ( ( s = static_cast<TObjString*>(nextHL())) )
+      {
+        if ( !fKeys->FindObject(s->String()) )
+        {
+          fKeys->Add(new TObjString(s->String()));
+        }
+      }
+    }
+
+  }
+  return fKeys;
+}
+
+//_____________________________________________________________________________
+Long64_t AliAnalysisMuMuResult::Merge(TCollection* list)
+{
+  /// Merge method
+  ///
+  /// Merge a list of AliAnalysisMuMuResult objects with this
+  /// Returns the number of merged objects (including this).
+  ///
+  /// Note that the merging is to be understood here as an average operation
+  
+  AliInfo(Form("this=%p",this));
+  if (!list) return 0;
+  
+  if (list->IsEmpty()) return 1;
+  
+  TIter next(list);
+  TObject* currObj;
+  TList hminvList;
+  hminvList.SetOwner(kTRUE);
+  
+  Double_t thisWeight = Weight();
+  Double_t sumOfWeights = thisWeight;
+
+  Double_t nofTriggers = fNofTriggers*thisWeight;
+  Double_t nofRuns = fNofRuns*thisWeight;
+  
+  fNofRuns *= thisWeight;
+  
+  while ( ( currObj = next() ) )
+  {
+    AliAnalysisMuMuResult* result = dynamic_cast<AliAnalysisMuMuResult*>(currObj);
+    if (!result)
+    {
+      AliFatal(Form("object named \"%s\" is a %s instead of an AliAnalysisMuMuResult!", currObj->GetName(), currObj->ClassName()));
+      continue;
+    }
+    
+    Double_t w = result->Weight();
+    
+    nofRuns += result->NofRuns()*w;
+    nofTriggers += result->NofTriggers()*w;
+    fWeight += result->fWeight;
+    sumOfWeights += w;
+  }
+  
+  thisWeight/= sumOfWeights;
+  fNofRuns = nofRuns/sumOfWeights;
+  fNofTriggers = nofTriggers/sumOfWeights;
+  fWeight /= sumOfWeights;
+  
+  AliInfo(Form("thisWeight=%e sumOfWeight=%8.2f noftriggers=%e weight=%e",thisWeight,sumOfWeights,1.0*fNofTriggers,fWeight));
+  
+  TIter nextKey(fMap);
+  TObjString* key;
+  
+  while ( ( key = static_cast<TObjString*>(nextKey())) )
+  {
+    AliInfo(key->String().Data());
+
+    Double_t value = GetValue(key->String())*thisWeight;
+    Double_t estat = GetErrorStat(key->String())*GetErrorStat(key->String())*thisWeight*thisWeight;
+
+    Double_t test(thisWeight);
+
+    next.Reset();
+    
+    while ( ( currObj = next() ) )
+    {
+      AliAnalysisMuMuResult* result = dynamic_cast<AliAnalysisMuMuResult*>(currObj);
+    
+      if (!result->HasValue(key->String()))
+      {
+        AliError(Form("Did not find key %s in of the result to merge",key->String().Data()));
+        continue;
+      }
+      
+      // can only merge under the condition we have the same bin
+    
+      if ( fBin != result->Bin() )
+      {
+        AliError("Cannot merge results of different bin");
+        continue;
+      }
+    
+      Double_t w = result->Weight()/sumOfWeights;
+      
+      Double_t w2 = w*w;
+      
+      test += w;
+      
+      value += result->GetValue(key->String())*w;
+      estat += result->GetErrorStat(key->String())*result->GetErrorStat(key->String())*w2;
+      
+    }
+    
+    Set(key->String(),
+        value,
+        TMath::Sqrt(estat));
+    
+    AliInfo(Form("test=%e",test));
+  }
+
+  if ( fMinv )
+  {
+    fMinv->Scale(thisWeight);    
+  }
+  
+  next.Reset();
+  
+  while ( ( currObj = next() ) )
+  {
+    AliAnalysisMuMuResult* result = dynamic_cast<AliAnalysisMuMuResult*>(currObj);
+
+    if ( result->Minv() )
+    {
+      TH1* h = static_cast<TH1*>(result->Minv()->Clone());
+      AliInfo(Form("Nbins %d xmin %e xmax %e",h->GetXaxis()->GetNbins(),h->GetXaxis()->GetXmin(),
+                   h->GetXaxis()->GetXmax()));
+      h->Scale(result->Weight());
+      hminvList.Add(h);
+    }
+  }
+  
+  if ( fMinv )
+  {
+    fMinv->Merge(&hminvList);
+    fMinv->Scale(1.0/sumOfWeights);
+  }
+  
+  TIter nextSubresult(fSubResults);
+  AliAnalysisMuMuResult* r;
+  
+  while ( ( r = static_cast<AliAnalysisMuMuResult*>(nextSubresult())) )
+  {
+    TList sublist;
+
+    next.Reset();
+    
+    while ( ( currObj = next() ) )
+    {
+      sublist.Add(currObj);
+    }
+
+    r->Merge(&sublist);
+  }
+  
+  return list->GetEntries()+1;
+}
+
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuResult::NofRuns() const
+{
+  if ( !Mother() ) return fNofRuns;
+  else return Mother()->NofRuns();
+}
+
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuResult::NofTriggers() const
+{
+  if ( !Mother() ) return fNofTriggers;
+  else return Mother()->NofTriggers();
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::Print(Option_t* opt) const
+{
+  TString sopt(opt);
+  sopt.ToUpper();
+  
+  for ( Int_t i = 0; i < 9; ++i )
+  {
+    sopt.ReplaceAll(Form("%d",i),"");
+  }
+  
+  TString pot(sopt);
+  pot.ReplaceAll("ALL","");
+  pot.ReplaceAll("FULL","");
+
+  std::cout << pot.Data() << Form("%50s- NRUNS %d - NTRIGGER %10d - %s%s",
+               GetName(),
+                    NofRuns(),
+                    NofTriggers(),
+                                  fWeight > 0.0 ? Form(" WEIGHT %e -",fWeight) : "",
+                           fBin.AsString().Data());
+  
+    if ( fSubResults && fSubResults->GetEntries()>1 )
+    {
+      std::cout << " (" << fSubResults->GetEntries()-1 << " subresults)";
+    }
+  
+  std::cout << std::endl;
+
+  if ( sopt.Contains("DUMP") )
+  {
+    TIter next(fMap);
+    TObjString* str;
+    while ( ( str = static_cast<TObjString*>(next()) ) )
+    {
+      TObjArray* a = static_cast<TObjArray*>(fMap->GetValue(str->String()));
+
+      std::cout << Form("%s %e %e",
+                        str->String().Data(),
+                        static_cast<TParameter<Double_t>*> (a->At(kValue))->GetVal(),
+                        static_cast<TParameter<Double_t>*> (a->At(kErrorStat))->GetVal()) << std::endl;
+    }
+  }
+  else
+  {
+    
+    PrintParticle("Jpsi",pot.Data());
+    PrintParticle("PsiPrime",pot.Data());
+    PrintParticle("Upsilon",pot.Data());
+  }
+  
+  if ( HasValue("MBR"))
+  {
+    std::cout << Form("\t\tMBR %e +- %e",GetValue("MBR"),GetErrorStat("MBR")) << std::endl;
+  }
+  
+  if ( fSubResults && fSubResults->GetEntries() > 1 && ( sopt.Contains("ALL") || sopt.Contains("FULL") ) )
+  {
+    std::cout << pot.Data() << "\t===== sub results ===== " << std::endl;
+    
+    sopt += "\t\t";
+    
+    TIter next(fSubResults);
+    AliAnalysisMuMuResult* r;
+    
+    while ( ( r = static_cast<AliAnalysisMuMuResult*>(next()) ) )
+    {
+      r->Print(sopt.Data());
+    }
+  }
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::PrintParticle(const char* particle, const char* opt) const
+{
+  Double_t npart = GetValue(Form("Nof%s",particle));
+  if (npart<=0) return;
+  
+  
+  std::cout << opt << Form("\t%s",particle) << std::endl;
+  
+  //  Double_t npartError = GetErrorStat(Form("Nof%s",particle));
+//  std::cout << opt << Form("\t\t%20s %9.2f +- %5.2f","Count",npart,npartError) << std::endl;
+  
+  TIter next(Keys());
+  TObjString* key;
+  
+  while ( ( key = static_cast<TObjString*>(next()) ) )
+  {
+    if ( !key->String().Contains(particle) ) continue;
+    
+    PrintValue(key->String(),opt,GetValue(key->String()),GetErrorStat(key->String()));
+  } 
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::PrintValue(const char* key, const char* opt, Double_t value, Double_t errorStat) const
+{
+  // print one value and its associated error
+  
+  if ( TString(key).Contains("AccEff") )
+  {
+    std::cout << opt << Form("\t\t%20s %9.2f +- %5.2f %%",key,value*100,errorStat*100) << std::endl;
+  }
+  else if ( TString(key).BeginsWith("Sigma") ||  TString(key).BeginsWith("Mean") )
+  {
+    std::cout << opt << Form("\t\t%20s %9.2f +- %5.2f MeV/c^2",key,value*1E3,1E3*errorStat) << std::endl;
+  }
+  else if ( TString(key).BeginsWith("Nof") )
+  {
+    std::cout << opt << Form("\t\t%20s %9.2f +- %5.2f",key,value,errorStat) << std::endl;
+  }
+  else if ( value > 1E-3 && value < 1E3 )
+  {
+    std::cout << opt << Form("\t\t%20s %9.2f +- %5.2f",key,value,errorStat) << std::endl;
+  }
+  else
+  {
+    std::cout << opt << Form("\t\t%20s %9.2e +- %9.2e",key,value,errorStat) << std::endl;    
+  }
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::Set(const char* name, Double_t value, Double_t errorStat)
+{
+  if ( !fMap )
+  {
+    fMap = new TMap;
+    fMap->SetOwnerKeyValue(kTRUE,kTRUE);
+  }
+  
+  TObjArray* p = static_cast<TObjArray*>(fMap->GetValue(name));
+  if (!p)
+  {
+    p = new TObjArray(4);
+    
+    p->SetOwner(kTRUE);
+    
+    p->AddAt(new TParameter<Double_t>(name,value),kValue);
+    p->AddAt(new TParameter<Double_t>(name,errorStat),kErrorStat);
+    
+    fMap->Add(new TObjString(name),p);
+  }
+  else
+  {
+    static_cast<TParameter<double>*>(p->At(kValue))->SetVal(value);
+    static_cast<TParameter<double>*>(p->At(kErrorStat))->SetVal(errorStat);
+  }
+  
+  if ( TString(name)=="NofJpsi" )
+  {
+    if ( NofTriggers() > 0 )
+    {
+      Double_t rate = value/NofTriggers();
+      Double_t rateError = rate*ErrorAB(value,errorStat,NofTriggers(),TMath::Sqrt(NofTriggers()));
+      Set("RateJpsi",rate,rateError);
+    }
+  }
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::SetBin(const AliAnalysisMuMuBinning::Range& bin)
+{
+  if (!Mother()) fBin = bin;
+  else Mother()->SetBin(bin);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::SetNofInputParticles(const TH1& hminv)
+{
+  static const char* particleNames[] = { "Jpsi" , "PsiPrime", "Upsilon","UpsilonPrime" };
+
+  for ( Int_t i = 0; i < 4; ++i )
+  {
+    Double_t n = CountParticle(hminv,particleNames[i]);
+
+    AliDebug(1,Form("i=%d particle %s n %e",i,particleNames[i],n));
+    
+    if ( n > 0 )
+    {
+      SetNofInputParticles(particleNames[i],n);
+    }
+  }
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::SetNofInputParticles(const char* particle, int n)
+{
+  /// Set the number of input particles (so it is a MC result)
+  /// and (re)compute the AccxEff values
+  
+  Set(Form("NofInput%s",particle),n,TMath::Sqrt(n));
+  
+  if (n<=0)
+  {
+    Set(Form("AccEff%s",particle),0,0);
+    return;
+  }
+  
+  Double_t npart = GetValue(Form("Nof%s",particle));
+  Double_t npartErr  = GetErrorStat(Form("Nof%s",particle));
+  Double_t ninput = GetValue(Form("NofInput%s",particle));
+  Double_t ninputErr = GetErrorStat(Form("NofInput%s",particle));
+  
+  Set(Form("AccEff%s",particle),
+      npart/ninput,
+      (npart/ninput)*ErrorAB(npart,npartErr,ninput,ninputErr));
+  
+  TIter next(fSubResults);
+  AliAnalysisMuMuResult* r;
+  
+  while ( ( r = static_cast<AliAnalysisMuMuResult*>(next())) )
+  {
+    r->Set(Form("NofInput%s",particle),n,TMath::Sqrt(n));
+
+    npart = r->GetValue(Form("Nof%s",particle));
+    npartErr = r->GetErrorStat(Form("Nof%s",particle));
+    
+    r->Set(Form("AccEff%s",particle),
+           npart/ninput,
+           (npart/ninput)*ErrorAB(npart,npartErr,ninput,ninputErr));
+
+  }
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::SetNofRuns(Int_t n)
+{
+  if ( !Mother() ) fNofRuns=n;
+  else Mother()->SetNofRuns(n);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::SetNofTriggers(Int_t n)
+{
+  if ( !Mother() ) fNofTriggers=n;
+  else Mother()->SetNofTriggers(n);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::SetMinv(const TH1& hminv)
+{
+    /// Set the inv. mass spectrum to be fitted.
+  static UInt_t n(0);
+  
+  delete fMinv;
+  fMinv = static_cast<TH1*>(hminv.Clone(Form("Minv%u",n++)));
+  fMinv->SetDirectory(0);
+}
+
diff --git a/PWG/muondep/AliAnalysisMuMuResult.h b/PWG/muondep/AliAnalysisMuMuResult.h
new file mode 100644 (file)
index 0000000..a2d2d97
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef ALIANALYSISMUMURESULT_H
+#define ALIANALYSISMUMURESULT_H
+
+/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * See cxx source for full Copyright notice                               */
+
+// $Id$
+
+///
+/// AliAnalysisMuMuResult : helper class to store results from
+/// AliAnalysisTaskMuMu
+///
+/// author : Laurent Aphecetche (Subatech)
+
+#include "TNamed.h"
+#include <TString.h>
+#include "AliAnalysisMuMuBinning.h"
+
+class TH1;
+class THashList;
+class TF1;
+class TMap;
+
+class AliAnalysisMuMuResult : public TNamed
+{
+  
+public:
+  
+  AliAnalysisMuMuResult(TRootIOCtor* io);
+  
+  AliAnalysisMuMuResult(const TH1& hminv);
+
+  AliAnalysisMuMuResult(const TH1& hminv,
+                        const char* fitType,
+                        Int_t nrebin);
+
+  AliAnalysisMuMuResult(const TH1& hminv,
+                        const char* triggerClass,
+                        const char* eventSelection,
+                        const char* pairSelection,
+                        const char* centSelection,
+                        const AliAnalysisMuMuBinning::Range& bin);
+  
+  AliAnalysisMuMuResult(const AliAnalysisMuMuResult& rhs);
+  AliAnalysisMuMuResult& operator=(const AliAnalysisMuMuResult&);
+  
+  virtual ~AliAnalysisMuMuResult();
+
+  virtual TObject* Clone(const char* newname = "") const;
+  
+  Bool_t Correct(const AliAnalysisMuMuResult& other, const char* particle, const char* subResultName="");
+  
+  TH1* Minv() const { return fMinv; }
+  
+  void Set(const char* name, Double_t value, Double_t errorStat);
+  
+  Bool_t HasValue(const char* name, const char* subResultName="") const;
+  
+  Double_t GetValue(const char* name, const char* subResultName="") const;
+  
+  Double_t GetErrorStat(const char* name, const char* subResultName="") const;
+
+  Int_t NofTriggers() const;
+  
+  void SetNofTriggers(Int_t n);
+  
+  void Print(Option_t* opt="") const;
+  
+  Bool_t AddFit(const char* fitType, Int_t rebin=1);
+
+  AliAnalysisMuMuResult* CountJpsi(TH1& h);
+
+//  void FitJpsiPsiPrimeCB(TH1& h);
+  AliAnalysisMuMuResult*  FitJpsi(TH1& h);
+//  void FitJpsiCBE(TH1& h);
+//  void FitJpsiECBE(TH1& h);
+//  void FitJpsiPCBE(TH1& h);
+//  void FitUpsilon(TH1& h);
+
+  AliAnalysisMuMuResult* FitJpsi2CB2VWG(const TH1& h);
+  AliAnalysisMuMuResult* FitJpsiGCBE(TH1& h);
+  
+//  SubResult* FitJpsiPsiPrimeCustom(TH1& h);
+  
+  Int_t NofRuns() const;
+  
+  void SetNofRuns(int n);
+  
+  const AliAnalysisMuMuBinning::Range& Bin() const;
+
+  void SetBin(const AliAnalysisMuMuBinning::Range& bin);
+  
+  void SetNofInputParticles(const char* particle, int n);
+
+  void SetNofInputParticles(const TH1& hminv);
+
+  void SetMinv(const TH1& hminv);
+
+  TObjArray* SubResults() const { return fSubResults; }
+  
+  static Double_t CountParticle(const TH1& hminv, const char* particle, Double_t sigma=-1);
+
+  static Double_t ErrorAB(Double_t a, Double_t aerr, Double_t b, Double_t berr);
+
+  static Double_t ErrorABC(Double_t a, Double_t aerr, Double_t b, Double_t berr, Double_t c, Double_t cerror);
+
+  Long64_t Merge(TCollection* list);
+
+  AliAnalysisMuMuResult* Mother() const { return fMother; }
+  
+  THashList* Keys() const;
+  
+  Double_t Weight() const { return fWeight > 0  ? fWeight : fNofTriggers; }
+  
+  void SetWeight(Double_t w) { fWeight=w; }
+  
+private:
+  
+  enum EIndex
+  {
+    kValue=0,
+    kErrorStat=1
+  };
+  
+
+  void PrintParticle(const char* particle, const char* opt) const;
+  void PrintValue(const char* key, const char* opt, Double_t value, Double_t errorStat) const;
+
+private:
+  Int_t fNofRuns; // number of runs used to get this result
+  Int_t fNofTriggers; // number of trigger analyzed
+  TH1* fMinv; // invariant mass spectrum
+  AliAnalysisMuMuBinning::Range fBin; // bin range
+  TObjArray* fSubResults; // TObjArray of AliAnalysisMuMuResult*
+  TMap* fMap; // internal parameter map
+  AliAnalysisMuMuResult* fMother; // mother result
+  mutable THashList* fKeys; //! keys we have in our internal map (or the one of our subresults)
+  Double_t fWeight; // weight of this result (default 1.0)
+  
+  ClassDef(AliAnalysisMuMuResult,5) // a class to hold invariant mass analysis results (counts, yields, AccxEff, R_AB, etc...)
+};
+
+#endif
diff --git a/PWG/muondep/AliAnalysisMuMuSpectra.cxx b/PWG/muondep/AliAnalysisMuMuSpectra.cxx
new file mode 100644 (file)
index 0000000..6646c03
--- /dev/null
@@ -0,0 +1,239 @@
+#include "AliAnalysisMuMuSpectra.h"
+
+#include "AliLog.h"
+#include "AliAnalysisMuMuBinning.h"
+#include "AliAnalysisMuMuResult.h"
+#include "Riostream.h"
+#include "TH1.h"
+#include "TList.h"
+#include "TObjArray.h"
+
+ClassImp(AliAnalysisMuMuSpectra)
+
+//______________________________________________________________________________
+AliAnalysisMuMuSpectra::AliAnalysisMuMuSpectra(const char* name, const char* title) :
+TNamed(name,title),
+fBinning(0x0),
+fBins(0x0)
+{
+  
+}
+
+//______________________________________________________________________________
+AliAnalysisMuMuSpectra::~AliAnalysisMuMuSpectra()
+{
+  delete fBinning;
+  delete fBins;
+}
+
+//______________________________________________________________________________
+void AliAnalysisMuMuSpectra::AdoptResult(const AliAnalysisMuMuBinning::Range& bin,
+                                         AliAnalysisMuMuResult* result)
+{
+  if (!fBinning)
+  {
+    fBinning = new AliAnalysisMuMuBinning;
+    fBins = new TObjArray;
+    fBins->SetOwner(kTRUE);
+  }
+  fBinning->AddBin(bin);
+  fBins->Add(result);
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisMuMuSpectra::Correct(const AliAnalysisMuMuSpectra& accEff, const char* particle, const char* subResultName)
+{
+  /// Correct this spectra by acceff one
+  if (IsEmpty())
+  {
+    AliError("Cannot correct an empty spectra !");
+    return kFALSE;
+  }
+  
+  // check we have the same binning first
+  AliAnalysisMuMuBinning* accEffBins = accEff.Binning();
+  
+  if ( !fBinning->IsEqual(accEffBins) )
+  {
+    AliError("Cannot correct with a spectra which does not have the same binning");
+    return kFALSE;
+  }
+  
+  TObjArray* particles = fBinning->CreateParticleArray();
+  TObjArray* types = fBinning->CreateTypeArray();
+  
+  if (particles->GetEntries()!=1 || types->GetEntries()!=1 )
+  {
+    delete particles;
+    delete types;
+    return kFALSE;
+  }
+  
+  TObjArray* bins = accEff.Bins();
+
+  
+  for ( Int_t i = 0; i < bins->GetEntries(); ++i )
+  {
+    AliAnalysisMuMuResult* thisResult = static_cast<AliAnalysisMuMuResult*>(fBins->At(i));
+    AliAnalysisMuMuResult* accResult = static_cast<AliAnalysisMuMuResult*>(bins->At(i));
+    AliInfoClass(Form("i=%d",i ));
+    StdoutToAliInfoClass(thisResult->Print("full");
+                         std::cout << "----" << std::endl;
+                         accResult->Print("full"));
+    
+    thisResult->Correct(*accResult,particle,subResultName);
+  }
+  
+  delete particles;
+  delete types;
+  return kTRUE;
+}
+
+//______________________________________________________________________________
+Bool_t AliAnalysisMuMuSpectra::IsEmpty() const
+{
+  return ( fBins==0x0 || fBins->GetEntries()<=0 );
+}
+
+//______________________________________________________________________________
+Long64_t AliAnalysisMuMuSpectra::Merge(TCollection* list)
+{
+  /// Merge method
+  
+  // Merge a list of AliAnalysisMuMuSpectra objects with this
+  // Returns the number of merged objects (including this).
+  
+  if (!list) return 0;
+  
+  if (list->IsEmpty()) return 1;
+  
+  TIter next(list);
+  TObject* currObj;
+  Int_t count(0);
+  
+  TList binningList;
+  
+  for ( Int_t i = 0; i <= fBins->GetLast(); ++i )
+  {
+    next.Reset();
+    
+    TList binList;
+    
+    while ( ( currObj = next() ) )
+    {
+      AliAnalysisMuMuSpectra* spectra = dynamic_cast<AliAnalysisMuMuSpectra*>(currObj);
+      if (!spectra)
+      {
+        AliFatal(Form("object named \"%s\" is a %s instead of an AliAnalysisMuMuSpectra!", currObj->GetName(), currObj->ClassName()));
+        continue;
+      }
+    
+      if (i==0)
+      {
+        binningList.Add(spectra->Binning());
+  
+        if ( !fBinning->IsEqual(spectra->Binning()) || spectra->Bins()->GetLast() != Bins()->GetLast() )
+        {
+          AliError("Cannot merge spectra with different binning");
+          continue;
+        }
+        
+        ++count;
+      }
+      
+      binList.Add(fBins->At(i));
+    }
+    
+    AliAnalysisMuMuResult* r = static_cast<AliAnalysisMuMuResult*>(fBins->At(i));
+    r->Merge(&binList);
+    
+  }
+  
+  fBinning->Merge(&binningList);
+  
+  return count+1;
+}
+
+//_____________________________________________________________________________
+TH1* AliAnalysisMuMuSpectra::Plot(const char* what, const char* subresult) const
+{
+  TString swhat(what);
+  swhat.ToUpper();
+  
+  Double_t* bins = fBinning->CreateBinArray();
+  
+  TObjArray* binArray = fBinning->CreateBinObjArray();
+  
+  TH1* h(0x0);
+  
+  AliDebugClass(1,Form("nbins=%d nresults=%d",binArray->GetEntries(),fBins->GetEntries()));
+  
+  for ( Int_t j = 0; j < TMath::Min(binArray->GetEntries(),fBins->GetEntries()); ++j )
+  {
+    AliAnalysisMuMuResult* r = static_cast<AliAnalysisMuMuResult*>(fBins->At(j));
+    
+    if ( strlen(subresult) > 0 )
+    {
+      TObjArray* sr = r->SubResults();
+      if (!sr) continue;
+      TString sub(subresult);
+      sub.ToUpper();
+      r = static_cast<AliAnalysisMuMuResult*>(sr->FindObject(sub.Data()));
+      if (!r) continue;
+    }
+    
+    const AliAnalysisMuMuBinning::Range& b = r->Bin();
+    
+    r->Print();
+    b.Print();
+    
+    if (!h)
+    {
+      h = new TH1F(r->GetName(),r->GetName(),binArray->GetEntries(),bins);
+      h->SetDirectory(0);
+    }
+    
+    Double_t y = r->GetValue(what);
+    Double_t yerr = r->GetErrorStat(what);
+    
+//    if ( !swhat.BeginsWith("ACC") )
+      if ( swhat.Contains("NOF") )
+    {
+      y /= (b.WidthX());
+      yerr /= (b.WidthX());
+    }
+    
+    h->SetBinContent(j+1,y);
+    h->SetBinError(j+1,yerr);
+    
+    AliInfoClass(Form("%e +- %e",y,yerr));
+  }
+  
+  delete binArray;
+  delete[] bins;
+  
+  return h;
+}
+
+
+//______________________________________________________________________________
+void AliAnalysisMuMuSpectra::Print(Option_t* opt) const
+{
+  if (!IsEmpty())
+  {
+    TString sopt(opt);
+    sopt.ToUpper();
+    if ( sopt.Contains("BINNING") )
+    {
+      fBinning->Print(opt);
+    }
+    Int_t nmax = sopt.Atoi();
+    if ( nmax <= 0 ) nmax = fBins->GetEntries();
+    for ( Int_t i = 0; i < nmax; ++i )
+    {
+      AliAnalysisMuMuBinning::Range* r = static_cast<AliAnalysisMuMuBinning::Range*>(fBins->At(i));
+      if (r) r->Print(opt);
+    }
+    
+  }
+}
diff --git a/PWG/muondep/AliAnalysisMuMuSpectra.h b/PWG/muondep/AliAnalysisMuMuSpectra.h
new file mode 100644 (file)
index 0000000..361749e
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef ALIANALYSISMUMUSPECTRA_H
+#define ALIANALYSISMUMUSPECTRA_H
+
+///
+/// AliAnalysisMuMuSpectra : a spectra is a binning (AliAnalysisMuMuBinning)
+/// and the results per bin (AliAnalysisMuMuResult), and is mergeable, so
+/// it can be put into an AliMergeableCollection
+///
+/// author : Laurent Aphecetche (Subatech)
+//
+
+#include "TNamed.h"
+
+#ifndef ALIANALYSISMUMUBINNING_H
+#  include "AliAnalysisMuMuBinning.h"
+#endif
+
+class AliAnalysisMuMuResult;
+class TCollection;
+class TH1;
+class TObjArray;
+
+class AliAnalysisMuMuSpectra : public TNamed
+{
+public:
+  AliAnalysisMuMuSpectra(const char* name="", const char* title="");
+  virtual ~AliAnalysisMuMuSpectra();
+
+  void AdoptResult(const AliAnalysisMuMuBinning::Range& bin, AliAnalysisMuMuResult* result);
+
+  Bool_t IsEmpty() const;
+  
+  Long64_t Merge(TCollection* list);
+
+  TH1* Plot(const char* what="NofJpsi", const char* subresult="") const;
+
+  void Print(Option_t* opt="") const;
+
+  TObjArray* Bins() const { return fBins; }
+  
+  AliAnalysisMuMuBinning* Binning() const { return fBinning; }
+  
+  Bool_t Correct(const AliAnalysisMuMuSpectra& accEff, const char* particle, const char* subResultName="");
+  
+private:
+  AliAnalysisMuMuBinning* fBinning; // internal binning
+  TObjArray* fBins; // the results (bin by bin)
+  
+  ClassDef(AliAnalysisMuMuSpectra,1) // class to hold spectra (with its associated binning and errors)
+};
+
+#endif
diff --git a/PWG/muondep/AliMuonAccEffSubmitter.cxx b/PWG/muondep/AliMuonAccEffSubmitter.cxx
new file mode 100644 (file)
index 0000000..e9121b4
--- /dev/null
@@ -0,0 +1,1375 @@
+#include "AliMuonAccEffSubmitter.h"
+
+#include "AliAnalysisTriggerScalers.h"
+#include "AliLog.h"
+#include "TFile.h"
+#include "TGrid.h"
+#include "TGridResult.h"
+#include "TMap.h"
+#include "TMath.h"
+#include "TObjString.h"
+#include "TString.h"
+#include "TSystem.h"
+#include <vector>
+
+namespace
+{
+  Int_t splitLevel=10;
+}
+
+//______________________________________________________________________________
+AliMuonAccEffSubmitter::AliMuonAccEffSubmitter()
+: TObject(),
+fScalers(0x0),
+fRemoteDir(""),
+fReferenceTrigger(""),
+fRatio(1.0),
+fMaxEventsPerChunk(5000),
+fLocalDir(gSystem->pwd()),
+fOCDBPath("raw://"),
+fTemplateDir(gSystem->ExpandPathName("$ALICE_ROOT/PWG/muondep/AccEffTemplates")),
+fPackageAliroot(),
+fPackageGeant3(),
+fPackageRoot(),
+fPackageApi(),
+fMergedDir(Form("%s/AODs",fRemoteDir.Data())),
+fSplitMaxInputFileNumber(20),
+fCompactMode(1),
+fShouldOverwriteFiles(kFALSE),
+fVars(0x0),
+fExternalConfig(""),
+fUseOCDBSnapshots(kTRUE),
+fIsValid(kFALSE),
+fTemplateFileList(0x0),
+fLocalFileList(0x0),
+fSnapshotDir(fLocalDir)
+{
+  // ctor
+  
+  if (!TGrid::Connect("alien://"))
+  {
+    AliError("cannot connect to grid");
+    fIsValid = kFALSE;
+  }
+
+  SetPackages("VO_ALICE@AliRoot::v5-03-Rev-09","VO_ALICE@GEANT3::v1-14-6","VO_ALICE@ROOT::v5-34-02-1");
+  
+//  SetVar("VAR_ENERGY","5.03");
+  SetVar("VAR_GENLIB_TYPE","AliGenMUONlib::kJpsi");
+  SetVar("VAR_GENLIB_PARNAME","\"pPb 5.03\"");
+  SetVar("VAR_OCDB_PATH","\"raw://\"");
+  UseOCDBSnapshots(kTRUE);
+}
+
+//______________________________________________________________________________
+AliMuonAccEffSubmitter::~AliMuonAccEffSubmitter()
+{
+  // dtor
+  delete fScalers;
+  delete fTemplateFileList;
+  delete fLocalFileList;
+  delete fVars;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::CheckLocal() const
+{
+  /// Check whether all required local files are there
+  TIter next(LocalFileList());
+  TObjString* file;
+  
+  while ( ( file = static_cast<TObjString*>(next())) )
+  {
+      if ( gSystem->AccessPathName(file->String().Data()) )
+      {
+        return kFALSE;
+      }
+  }
+  
+  return kTRUE;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::CheckRemote() const
+{
+  /// Check whether all required remote files are there
+  AliWarning("implement me");
+  return kFALSE;
+}
+
+//______________________________________________________________________________
+void AliMuonAccEffSubmitter::CleanLocal(Bool_t cleanSnapshots) const
+{
+  /// Clean (remove) local generated files
+  /// As OCDB snapshot creation is a long process, cleanSnapshots
+  /// is kFALSE by default in order not to delete those.
+  
+  TIter next(LocalFileList());
+  TObjString* file;
+  
+  while ( ( file = static_cast<TObjString*>(next())) )
+  {
+    if ( !cleanSnapshots && file->String().Contains("OCDB_") ) continue;
+    gSystem->Unlink(file->String().Data());
+  }
+}
+
+//______________________________________________________________________________
+void AliMuonAccEffSubmitter::CleanRemote() const
+{
+  /// Clean (remove) remote files
+  AliWarning("implement me");
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::CopyFile(const char* localFile)
+{
+  TString local;
+  
+  if ( gSystem->IsAbsoluteFileName(localFile) )
+  {
+    local = localFile;
+  }
+  else
+  {
+    local = Form("%s/%s",fLocalDir.Data(),gSystem->ExpandPathName(localFile));
+  }
+  
+  if (gSystem->AccessPathName(local.Data()))
+  {
+    AliError(Form("Local file %s does not exist",local.Data()));
+    return kFALSE;
+  }
+  
+  TString remote;
+  
+  remote += fRemoteDir;
+  remote += "/";
+  
+  if ( gSystem->IsAbsoluteFileName(localFile) )
+  {
+    TString tmp(localFile);
+    tmp.ReplaceAll(fSnapshotDir.Data(),"");
+    remote += tmp;
+  }
+  else
+  {
+    remote += localFile;
+  }
+  
+  TString dirName = gSystem->DirName(remote.Data());
+  
+  Bool_t ok(kTRUE);
+  
+  if (!RemoteDirectoryExists(dirName.Data()))
+  {
+    ok = gGrid->Mkdir(dirName.Data(),"-p");
+  }
+  
+  if ( ok )
+  {
+    return TFile::Cp(local.Data(),Form("alien://%s",remote.Data()));
+  }
+  else
+  {
+    return kFALSE;
+  }
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::CheckRemoteDir() const
+{
+  /// Check we have a grid connection and that the remote dir exists
+  
+  if (fRemoteDir.IsNull())
+  {
+    AliError("you must provide the grid location where to copy the files");
+    return kFALSE;
+  }
+  
+  // connect to alien
+  if (!gGrid)
+  {
+    if (!TGrid::Connect("alien://"))
+    {
+      AliError("Cannot connect to grid");
+      return kFALSE;
+    }
+  }
+  
+  if (!RemoteDirectoryExists(fRemoteDir))
+  {
+    AliError(Form("directory %s does not exist", fRemoteDir.Data()));
+    return kFALSE;
+  }
+
+  return kTRUE;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::CopyLocalFilesToRemote()
+{
+  /// copy all files necessary to run the simulation into remote directory
+  
+  if (!IsValid()) return kFALSE;
+  
+  if ( CheckRemoteDir() )
+  {
+    TString sdir(gSystem->ExpandPathName(LocalDir()));
+  
+    TIter next(LocalFileList());
+    TObjString* ftc;
+  
+    Bool_t allok(kTRUE);
+  
+    while ( ( ftc = static_cast<TObjString*>(next())) )
+    {
+      allok = allok && CopyFile(ftc->String());
+    }
+    return allok;
+  }
+  
+  return kFALSE;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::CopyTemplateFilesToLocal()
+{
+  // copy (or generate) local files from the template ones
+  
+  if (!IsValid()) return kFALSE;
+
+  TIter next(TemplateFileList());
+  TObjString* file;
+  
+  Int_t err(0);
+  Bool_t potentialProblem(kFALSE);
+  
+  while ( ( file = static_cast<TObjString*>(next())) )
+  {
+    if ( file->String().Contains("OCDB") )
+    {
+      /// OCDB snapshots are not in template
+      continue;
+    }
+
+    if ( !ShouldOverwriteFiles() && !gSystem->AccessPathName(file->String().Data()) )
+    {
+      AliError(Form("Local file %s already exists. Remove it first if you want to update overwrite it",file->String().Data()));
+      potentialProblem = kTRUE;
+    }
+    else
+    {
+      TString stemplate(Form("%s/%s",fTemplateDir.Data(),file->String().Data()));
+      TString slocal(Form("%s/%s",fLocalDir.Data(),file->String().Data()));
+      
+      Int_t c =  gSystem->CopyFile(stemplate.Data(),slocal.Data(),ShouldOverwriteFiles());
+      if ( c )
+      {
+        Bool_t ok(kFALSE);
+        if ( stemplate.Contains(".jdl",TString::kIgnoreCase) )
+        {
+          if ( stemplate.Contains("merge",TString::kIgnoreCase) )
+          {
+            ok = GenerateMergeJDL(file->String().Data());
+          }
+          else
+          {
+            ok = GenerateRunJDL(file->String().Data());
+          }
+        }
+        if (!ok)
+        {
+          AliError(Form("Error %d copying file %s",c,stemplate.Data()));
+        }
+        else
+        {
+          c=0;
+        }
+      }
+      else
+      {
+        if ( HasVars(slocal.Data()) )
+        {
+          if (!ReplaceVars(slocal.Data()))
+          {
+            AliError("pb in ReplaceVars");
+            c=1;
+          }
+        }
+      }
+      err += c;
+    }
+  }
+  
+  if ( potentialProblem )
+  {
+    AliWarning("At least one local file could not be overwritten. Cross-check that the local files are OK before we try to upload them to the Grid !");
+    return kFALSE;
+  }
+  return (err==0);
+}
+
+//______________________________________________________________________________
+std::ostream* AliMuonAccEffSubmitter::CreateJDLFile(const char* name) const
+{
+  TString jdl(Form("%s/%s",fLocalDir.Data(),name));
+  
+  if ( !ShouldOverwriteFiles() && !gSystem->AccessPathName(jdl.Data()) )
+  {
+    AliError(Form("File %s already exists. Remove it if you want to overwrite it",jdl.Data()));
+    return 0x0;
+  }
+  
+  std::ofstream* os = new std::ofstream(gSystem->ExpandPathName(jdl.Data()));
+  
+  if (os->bad())
+  {
+    AliError(Form("Cannot create file %s",jdl.Data()));
+    delete os;
+    os=0x0;
+  }
+  
+  return os;
+}
+
+///______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::GenerateMergeJDL(const char* name)
+{
+  std::ostream* os = CreateJDLFile(name);
+  
+  if (!os)
+  {
+    return kFALSE;
+  }
+  
+  Bool_t final = TString(name).Contains("merge",TString::kIgnoreCase);
+
+  (*os) << "# Generated merging jdl (production mode)" << std::endl
+  << "# $1 = run number" << std::endl
+  << "# $2 = merging stage" << std::endl
+  << "# Stage_<n>.xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip" << std::endl;
+
+  Output(*os,"Packages",fPackageAliroot.Data(),fPackageGeant3.Data(),
+         fPackageRoot.Data(),fPackageApi.Data());
+  
+  Output(*os,"Executable","AOD_merge.sh");
+  
+  Output(*os,"Price","1");
+
+  if ( final )
+  {
+    Output(*os,"Jobtag","comment: AliMuonAccEffSubmitter final merging");
+  }
+  else
+  {
+    Output(*os,"Jobtag","comment: AliMuonAccEffSubmitter merging stage $2");
+  }
+  
+  Output(*os,"Workdirectorysize","5000MB");
+  
+  Output(*os,"Validationcommand",Form("%s/validation_merge.sh",fRemoteDir.Data()));
+  
+  Output(*os,"TTL","7200");
+
+  Output(*os,"OutputArchive",
+    "log_archive.zip:stderr,stdout@disk=1",
+    "root_archive.zip:AliAOD.root,AliAOD.Muons.root,AnalysisResults.root@disk=3"
+         );
+  
+  Output(*os,"Arguments",(final ? "2":"1")); // for AOD_merge.sh, 1 means intermediate merging stage, 2 means final merging
+  
+  if ( !final )
+  {
+    Output(*os,"InputFile",Form("LF:%s/AODtrain.C",fRemoteDir.Data()));
+    Output(*os,"OutputDir",Form("%s/$1/Stage_$2/#alien_counter_03i#",fRemoteDir.Data()));
+    Output(*os,"InputDataCollection",Form("%s/$1/Stage_$2.xml,nodownload",fRemoteDir.Data()));
+    Output(*os,"split","se");
+    Output(*os,"SplitMaxInputFileNumber",GetSplitMaxInputFileNumber());
+    Output(*os,"InputDataListFormat","xml-single");
+    Output(*os,"InputDataList","wn.xml");
+  }
+  else
+  {
+    Output(*os,"InputFile",Form("LF:%s/AODtrain.C",fRemoteDir.Data()),
+           Form("LF:%s/$1/wn.xml",fRemoteDir.Data()));
+    Output(*os,"OutputDir",Form("%s/$1",fRemoteDir.Data()));
+  }
+  
+  return kTRUE;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::GenerateRunJDL(const char* name)
+{
+  /// Generate (locally) the JDL to perform the simulation+reco+aod filtering
+  /// (to be then copied to the grid and finally submitted)
+  
+  std::ostream* os = CreateJDLFile(name);
+  
+  if (!os)
+  {
+    return kFALSE;
+  }
+  
+  Output(*os,"Packages",fPackageAliroot.Data(),fPackageGeant3.Data(),
+         fPackageRoot.Data(),fPackageApi.Data());
+
+  Output(*os,"Jobtag","comment: AliMuonAccEffSubmitter RUN $1");
+
+  Output(*os,"split","production:1-$2");
+
+  Output(*os,"Price","1");
+  
+  Output(*os,"OutputDir",Form("%s/$1/#alien_counter_03i#",fRemoteDir.Data()));
+
+  Output(*os,"Executable","/alice/bin/aliroot_new");
+  
+  TObjArray files;
+  files.SetOwner(kTRUE);
+  TIter next(TemplateFileList());
+  TObjString* file;
+  
+  while ( ( file = static_cast<TObjString*>(next())) )
+  {
+    if ( !file->String().Contains(".jdl",TString::kIgnoreCase) ||
+         !file->String().Contains("OCDB_") )
+    {
+      files.Add(new TObjString(Form("LF:%s/%s",fRemoteDir.Data(),file->String().Data())));      
+    }
+  }
+  
+  if ( fUseOCDBSnapshots )
+  {
+    files.Add(new TObjString(Form("LF:%s/OCDB/$1/OCDB_sim.root",fRemoteDir.Data())));
+    files.Add(new TObjString(Form("LF:%s/OCDB/$1/OCDB_rec.root",fRemoteDir.Data())));
+  }
+  
+  Output(*os,"InputFile",files);
+  
+  if ( CompactMode() == 0 )
+  {
+    // store everything
+    Output(*os,"OutputArchive",  "log_archive.zip:stderr,stdout,aod.log,checkaod.log,checkesd.log,rec.log,recwatch.log,sim.log,simwatch.log@disk=1",
+           "root_archive.zip:galice*.root,Kinematics*.root,TrackRefs*.root,AliESDs.root,AliAOD.root,AliAOD.Muons.root,Merged.QA.Data.root,Run*.root@disk=2");
+  }
+  else if ( CompactMode() == 1 )
+  {
+    // keep only muon AODs
+    Output(*os,"OutputArchive",  "log_archive.zip:stderr,stdout,aod.log,checkaod.log,checkesd.log,rec.log,sim.log@disk=1",
+           "root_archive.zip:galice*.root,AliAOD.Muons.root@disk=2");
+  }
+  else
+  {
+    AliError(Form("Unknown CompactMode %d",CompactMode()));
+    delete os;
+    return kFALSE;
+  }
+  
+  Output(*os,"splitarguments","simrun.C --run $1 --chunk #alien_counter# --event $3");
+  
+  Output(*os,"Workdirectorysize","5000MB");
+  
+  Output(*os,"JDLVariables","Packages","OutputDir");
+
+  Output(*os,"Validationcommand",Form("%s/validation.sh",fRemoteDir.Data()));
+
+  Output(*os,"TTL","72000");
+  
+  return kTRUE;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::GetLastStage(const char* remoteDir) const
+{
+  Int_t n = 0, lastStage = 0;
+  gSystem->Exec(Form("alien_ls -F %s | grep Stage_.*/ > __stage__", remoteDir));
+  ifstream f("__stage__");
+  std::string dummy;
+  while (std::getline(f, dummy)) n++;
+  f.close();
+  while (n > 0) if (gSystem->Exec(Form("grep Stage_%d/ __stage__ 2>&1 >/dev/null", ++lastStage)) == 0) n--;
+  gSystem->Exec("rm -f __stage__");
+  return lastStage;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::HasVars(const char* file) const
+{
+  /// Whether or not the file contains variables that have to
+  /// be substituted
+  
+  std::ifstream in(file);
+  char line[1024];
+  while ( in.getline(line,1023,'\n') )
+  {
+    TString sline(line);
+    if (sline.Contains("VAR_") && !sline.BeginsWith("//") )
+    {
+      return kTRUE;
+    }
+  }
+  return kFALSE;
+}
+
+//______________________________________________________________________________
+TObjArray* AliMuonAccEffSubmitter::LocalFileList() const
+{
+  /// Return (after createing and filling it if needed)
+  /// the internal file list with paths from the local directory
+  
+  if (!fLocalFileList)
+  {
+    fLocalFileList = static_cast<TObjArray*>(TemplateFileList()->Clone());
+  }
+  
+  return fLocalFileList;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::MakeOCDBSnapshots()
+{
+  /// Run sim.C and rec.C in a special mode to generate OCDB snapshots
+  /// Can only be done after the templates have been copied locally
+  
+  if (!IsValid()) return kFALSE;
+
+  if (!fUseOCDBSnapshots) return kTRUE;
+  
+  if (!fScalers) return kFALSE;
+  
+  const std::vector<int>& runs = fScalers->GetRunList();
+
+  Bool_t ok(kTRUE);
+  
+  for ( std::vector<int>::size_type i = 0; i < runs.size(); ++i )
+  {
+    Int_t runNumber = runs[i];
+
+    TString ocdbSim(Form("%s/OCDB/%d/OCDB_sim.root",SnapshotDir().Data(),runNumber));
+    TString ocdbRec(Form("%s/OCDB/%d/OCDB_rec.root",SnapshotDir().Data(),runNumber));
+
+    if ( !gSystem->AccessPathName(ocdbSim.Data()) && 
+         !gSystem->AccessPathName(ocdbRec.Data()) )
+    {
+      AliWarning(Form("Local OCDB snapshots already there for run %d. Will not redo them. If you want to force them, delete them by hand !",runNumber));
+    }
+    else
+    {
+      gSystem->Exec(Form("aliroot -b -q -x simrun.C --run %d --snapshot",runNumber));
+    
+      if ( gSystem->AccessPathName(ocdbSim.Data()) )
+      {
+        AliError(Form("Could not create OCDB snapshot for simulation"));
+        ok = kFALSE;
+      }
+
+      if ( gSystem->AccessPathName(ocdbRec.Data()) )
+      {
+        AliError(Form("Could not create OCDB snapshot for reconstruction"));
+        ok = kFALSE;
+      }
+    }
+    
+    LocalFileList()->Add(new TObjString(ocdbSim));
+    LocalFileList()->Add(new TObjString(ocdbRec));
+  }
+  
+  return ok;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::Merge(Int_t stage, Bool_t dryRun)
+{
+  /// Submit multiple merging jobs with the format "submit AOD_merge(_final).jdl run# (stage#)".
+  /// Also produce the xml collection before sending jobs
+  /// Initial AODs will be taken from fRemoteDir/[RUNNUMBER] while the merged
+  /// ones will be put into fMergedDir/AODs/[RUNNUMBER]
+  ///
+  /// Example:
+  /// - inDir = "/alice/sim/2012/LHC12a10_bis" (where to find the data to merge)
+  ///         = 0x0 --> inDir = homeDir/outDir/resDir
+  /// - outDir = "Sim/LHC11h/embedding/AODs" (where to store merged results)
+  /// - runList.txt must contains the list of run number
+  /// - stage=0 --> final merging / stage>0 --> intermediate merging i
+  ///
+  
+  if (!RemoteDirectoryExists(fMergedDir.Data())) {
+    AliError(Form("directory %s does not exist", fMergedDir.Data()));
+    return kFALSE;
+  }
+  
+  gGrid->Cd(fMergedDir.Data());
+  
+  TString jdl = MergeJDLName(stage==0);
+  
+  if (!RemoteFileExists(jdl.Data()))
+  {
+    AliError(Form("file %s does not exist in %s\n", jdl.Data(), fRemoteDir.Data()));
+    return kFALSE;
+  }
+  
+  const std::vector<int>& runs = fScalers->GetRunList();
+  
+  if (runs.empty())
+  {
+    AliError("No run to work with");
+    return kFALSE;
+  }
+
+  TString currRun;
+  TString reply = "";
+  gSystem->Exec("rm -f __failed__");
+  Bool_t failedRun = kFALSE;
+  
+  for ( std::vector<int>::size_type i = 0; i < runs.size(); ++i )
+  {
+    Int_t run = runs[i];
+    AliInfo(Form("\n --- processing run %d ---\n", run));
+    
+    TString runDir = Form("%s/%d", fMergedDir.Data(), run);
+    
+    if (!RemoteDirectoryExists(runDir.Data()))
+    {
+      AliInfo(Form(" - creating output directory %s\n", runDir.Data()));
+      gSystem->Exec(Form("alien_mkdir -p %s", runDir.Data()));
+    }
+    
+    if (RemoteFileExists(Form("%s/root_archive.zip", runDir.Data())))
+    {
+      AliWarning(" ! final merging already done");
+      continue;
+    }
+    
+    Int_t lastStage = GetLastStage(runDir.Data());
+    
+    if (stage > 0 && stage != lastStage+1)
+    {
+      AliError(Form(" ! lastest merging stage = %d. Next must be stage %d or final stage\n", lastStage, lastStage+1));
+      continue;
+    }
+    
+    TString wn = (stage > 0) ? Form("Stage_%d.xml", stage) : "wn.xml";
+    TString find = (lastStage == 0) ?
+    Form("alien_find -x %s %s/%d *root_archive.zip", wn.Data(), fRemoteDir.Data(), run) :
+    Form("alien_find -x %s %s/%d/Stage_%d *root_archive.zip", wn.Data(), fRemoteDir.Data(), run, lastStage);
+    gSystem->Exec(Form("%s 1> %s 2>/dev/null", find.Data(), wn.Data()));
+    gSystem->Exec(Form("grep -c /event %s > __nfiles__", wn.Data()));
+    ifstream f2("__nfiles__");
+    TString nFiles;
+    nFiles.ReadLine(f2,kTRUE);
+    f2.close();
+    gSystem->Exec("rm -f __nfiles__");
+    printf(" - number of files to merge = %d\n", nFiles.Atoi());
+    if (nFiles.Atoi() == 0) {
+      printf(" ! collection of files to merge is empty\n");
+      gSystem->Exec(Form("rm -f %s", wn.Data()));
+      continue;
+    } else if (stage > 0 && nFiles.Atoi() <= splitLevel && !reply.BeginsWith("y")) {
+      if (!reply.BeginsWith("n")) {
+        printf(" ! number of files to merge <= split level (%d). Continue? [Y/n] ", splitLevel);
+        fflush(stdout);
+        reply.Gets(stdin,kTRUE);
+        reply.ToLower();
+      }
+      if (reply.BeginsWith("n")) {
+        gSystem->Exec(Form("rm -f %s", wn.Data()));
+        continue;
+      } else reply = "y";
+    }
+    
+    if (!dryRun)
+    {
+      TString dirwn = Form("%s/%s", runDir.Data(), wn.Data());
+      if (RemoteFileExists(dirwn.Data())) gGrid->Rm(dirwn.Data());
+      gSystem->Exec(Form("alien_cp file:%s alien://%s", wn.Data(), dirwn.Data()));
+      gSystem->Exec(Form("rm -f %s", wn.Data()));
+    }
+    
+    TString query;
+    if (stage > 0) query = Form("submit %s %d %d", jdl.Data(), run, stage);
+    else query = Form("submit %s %d", jdl.Data(), run);
+    printf(" - %s ...", query.Data());
+    fflush(stdout);
+    
+    if (dryRun)
+    {
+      AliInfo(" dry run");
+      continue;
+    }
+    
+    Bool_t done = kFALSE;
+    TGridResult *res = gGrid->Command(query);
+    if (res)
+    {
+      TString cjobId1 = res->GetKey(0,"jobId");
+      if (!cjobId1.IsDec())
+      {
+        AliError(" FAILED");
+        gGrid->Stdout();
+        gGrid->Stderr();
+      }
+      else
+      {
+        AliInfo(Form(" DONE\n   --> the job Id is: %s \n", cjobId1.Data()));
+        done = kTRUE;
+      }
+      delete res;
+    }
+    else
+    {
+      AliError(" FAILED");
+    }
+    
+    if (!done)
+    {
+      gSystem->Exec(Form("echo %d >> __failed__", run));
+      failedRun = kTRUE;
+    }
+    
+  }
+  
+  if (failedRun)
+  {
+    AliInfo("\n--------------------\n");
+    AliInfo("list of failed runs:\n");
+    gSystem->Exec("cat __failed__");
+    gSystem->Exec("rm -f __failed__");
+    return kFALSE;
+  }
+  
+  return kTRUE;
+}
+
+//______________________________________________________________________________
+UInt_t AliMuonAccEffSubmitter::NofRuns() const
+{
+    // number of runs we're dealing with
+  if (!fScalers) return 0;
+  
+  return fScalers->GetRunList().size();
+}
+
+//______________________________________________________________________________
+void AliMuonAccEffSubmitter::Output(std::ostream& out, const char* key,
+                                    const TObjArray& values) const
+{
+  out << key << " = ";
+  
+  Int_t n = values.GetEntries();
+  
+  if ( n > 1 )
+  {
+    out << "{" << std::endl;
+    TIter next(&values);
+    TObjString* v;
+    
+    while ( ( v = static_cast<TObjString*>(next())) )
+    {
+      --n;
+      out << "\t\"" << v->String().Data() << "\"";
+      if  ( n ) out << ",";
+      out << std::endl;
+    }
+    out << "}";
+  }
+  else
+  {
+    TString& v1 = static_cast<TObjString*>(values.At(0))->String();
+    
+    if ( v1.IsDigit() )
+    {
+      out << v1.Atoi();
+    }
+    else
+    {
+      out << "\"" << v1.Data() << "\"";
+    }
+  }
+  out << ";" << std::endl;
+}
+
+//______________________________________________________________________________
+void AliMuonAccEffSubmitter::Output(std::ostream& out, const char* key, const char* v1,
+                                    const char* v2, const char* v3, const char* v4,
+                                    const char* v5, const char* v6, const char* v7,
+                                    const char* v8, const char* v9) const
+{
+  TObjArray values;
+  values.SetOwner(kTRUE);
+  
+  values.Add(new TObjString(v1));
+  if ( strlen(v2) > 0 ) values.Add(new TObjString(v2));
+  if ( strlen(v3) > 0 ) values.Add(new TObjString(v3));
+  if ( strlen(v4) > 0 ) values.Add(new TObjString(v4));
+  if ( strlen(v5) > 0 ) values.Add(new TObjString(v5));
+  if ( strlen(v6) > 0 ) values.Add(new TObjString(v6));
+  if ( strlen(v7) > 0 ) values.Add(new TObjString(v7));
+  if ( strlen(v8) > 0 ) values.Add(new TObjString(v8));
+  if ( strlen(v9) > 0 ) values.Add(new TObjString(v9));
+  
+  Output(out,key,values);
+}
+
+
+//______________________________________________________________________________
+void AliMuonAccEffSubmitter::Print(Option_t* /*opt*/) const
+{
+  if (!IsValid())
+  {
+    std::cout << std::string(80,'*') << std::endl;
+    std::cout << "INVALID OBJECT. CHECK BELOW THE CONFIGURATION." << std::endl;
+    std::cout << std::string(80,'*') << std::endl;
+  }
+    
+  std::cout << "Template directory = " << fTemplateDir.Data() << std::endl;
+  std::cout << "Local    directory = " << fLocalDir.Data() << std::endl;
+  std::cout << "Remote   directory = " << fRemoteDir.Data() << std::endl;
+  
+  std::cout << "OCDB path = " << fOCDBPath.Data() << std::endl;
+  
+  if ( fRatio > 0 )
+  {
+    std::cout << Form("For each run, will generate %5.2f times the number of real events for trigger %s",
+                      fRatio,fReferenceTrigger.Data()) << std::endl;
+  }
+  else
+  {
+    std::cout << Form("For each run, will generate %10d events",fFixedNofEvents) << std::endl;
+  }
+  
+  std::cout << "MaxEventsPerChunk = " << fMaxEventsPerChunk << std::endl;
+  
+  if ( NofRuns() )
+  {
+    std::cout << NofRuns() << " run";
+    if ( NofRuns() > 1 ) std::cout << "s";
+    std::cout << " = ";
+    fScalers->Print();
+  }
+  
+  if ( fVars )
+  {
+    TIter next(fVars);
+    TObjString* key;
+    while ( ( key = static_cast<TObjString*>(next())) )
+    {
+      TObjString* value = static_cast<TObjString*>(fVars->GetValue(key->String()));
+      std::cout << "Variable " << key->String() << " will be replaced by " << value->String() << std::endl;
+    }
+  }
+  
+  std::cout << "Files to be uploaded:" << std::endl;
+  TIter nextFile(LocalFileList());
+  TObjString* sfile;
+  while ( ( sfile = static_cast<TObjString*>(nextFile())) )
+  {
+    std::cout << sfile->String().Data() << std::endl;
+  }
+}
+
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::RemoteDirectoryExists(const char *dirname) const
+{
+  // Returns true if directory exists. Can be also a path.
+  if (!gGrid) return kFALSE;
+  // Check if dirname is a path
+  TString dirstripped = dirname;
+  dirstripped = dirstripped.Strip();
+  dirstripped = dirstripped.Strip(TString::kTrailing, '/');
+  TString dir = gSystem->BaseName(dirstripped);
+  dir += "/";
+  TString path = gSystem->DirName(dirstripped);
+  TGridResult *res = gGrid->Ls(path, "-F");
+  if (!res) return kFALSE;
+  TIter next(res);
+  TMap *map;
+  TObject *obj;
+  while ((map=dynamic_cast<TMap*>(next()))) {
+    obj = map->GetValue("name");
+    if (!obj) break;
+    if (dir == obj->GetName()) {
+      delete res;
+      return kTRUE;
+    }
+  }
+  delete res;
+  return kFALSE;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::RemoteFileExists(const char *lfn) const
+{
+  // Returns true if file exists.
+  if (!gGrid) return kFALSE;
+  TGridResult *res = gGrid->Ls(lfn);
+  if (!res) return kFALSE;
+  TMap *map = dynamic_cast<TMap*>(res->At(0));
+  if (!map) {
+    delete res;
+    return kFALSE;
+  }
+  TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
+  if (!objs || !objs->GetString().Length()) {
+    delete res;
+    return kFALSE;
+  }
+  delete res;
+  return kTRUE;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::ReplaceVars(const char* file)
+{
+  std::ifstream in(file);
+  char line[1024];
+  TObjArray lines;
+  lines.SetOwner(kTRUE);
+  Int_t nvars(0);
+  Int_t nreplaced(0);
+
+  TIter next(fVars);
+
+  while ( in.getline(line,1023,'\n') )
+  {
+    TString sline(line);
+    while (sline.Contains("VAR_") && !sline.BeginsWith("//") )
+    {
+      ++nvars;
+      TObjString* key;
+      next.Reset();
+      while ( ( key = static_cast<TObjString*>(next())) )
+      {
+        if ( sline.Contains(key->String()) )
+        {
+          ++nreplaced;
+          TObjString* value = static_cast<TObjString*>(fVars->GetValue(key->String()));
+          sline.ReplaceAll(key->String(),value->String());
+          break;
+        }
+      }
+    }
+
+    lines.Add(new TObjString(sline));
+  }
+  
+  in.close();
+  
+  if ( nvars > 0 )
+  {
+    if ( nreplaced != nvars )
+    {
+      AliError(Form("nvars=%d nreplaced=%d",nvars,nreplaced));
+      return kFALSE;
+    }
+    std::ofstream out(file);
+    TIter nextLine(&lines);
+    TObjString* s;
+    while ( ( s = static_cast<TObjString*>(nextLine()) ) )
+    {
+      out << s->String().Data() << std::endl;
+    }
+    out.close();
+  }
+  
+  return kTRUE;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::Run(const char* mode)
+{
+  /// mode can be one of (case insensitive)
+  ///
+  /// LOCAL : copy the template files from the template directory to the local one
+  /// UPLOAD : copy the local files to the grid (requires LOCAL)
+  /// OCDB : make ocdb snapshots (requires LOCAL)
+  /// SUBMIT : submit the jobs (requires LOCAL + UPLOAD)
+  /// FULL : all of the above (requires all of the above)
+  ///
+  /// TEST : as SUBMIT, but in dry mode (does not actually submit the jobs)
+  
+  if (!IsValid()) return kFALSE;
+  
+  TString smode(mode);
+  smode.ToUpper();
+  
+  if ( smode == "FULL")
+  {
+    return  ( Run("LOCAL") && Run("OCDB") && Run("UPLOAD") && Run("SUBMIT") );
+  }
+  
+  if ( smode == "LOCAL")
+  {
+    return CopyTemplateFilesToLocal();
+  }
+  
+  if ( smode == "UPLOAD" )
+  {
+    return (CopyLocalFilesToRemote());
+  }
+  
+  if ( smode == "OCDB" )
+  {
+    Bool_t ok = Run("LOCAL");
+    if (ok)
+    {
+      ok = MakeOCDBSnapshots();
+    }
+    return ok;
+  }
+  
+  if ( smode == "TEST" )
+  {
+    Bool_t ok = Run("LOCAL") && Run("OCDB") && Run("UPLOAD");
+    if ( ok )
+    {
+      ok = (Submit(kTRUE)>0);
+    }
+    return ok;
+  }
+  
+  if ( smode == "FULL" )
+  {
+    Bool_t ok = Run("LOCAL")  && Run("OCDB") && Run("UPLOAD");
+    if ( ok )
+    {
+      ok = (Submit(kFALSE)>0);
+    }
+    return ok;
+  }
+
+  if( smode == "SUBMIT" )
+  {
+    return (Submit(kFALSE)>0);
+  }
+  
+  return kFALSE;
+}
+
+//______________________________________________________________________________
+void AliMuonAccEffSubmitter::SetPackages(const char* aliroot,
+                                         const char* root,
+                                         const char* geant3,
+                                         const char* api)
+{
+  fPackageAliroot = aliroot;
+  fPackageRoot = root;
+  fPackageGeant3 = geant3;
+  fPackageApi = api;
+}
+
+//______________________________________________________________________________
+TString AliMuonAccEffSubmitter::GetRemoteDir(const char* dir, Bool_t create)
+{
+  /// Set the target remote directory (on the grid)
+  
+  if (!RemoteDirectoryExists(dir))
+  {
+    if (!create)
+    {
+      AliError(Form("Remote directory %s does not exist", dir));
+      return "";
+    }
+    else
+    {
+      AliInfo(Form("Remote directory %s does not exist. Trying to create it...",dir));
+      if ( !gGrid->Mkdir(dir,"-p") )
+      {
+        AliError(Form("Could not create remote dir. Sorry."));
+        return "";
+      }
+    }
+  }
+  return dir;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::SetMergedDir(const char* dir, Bool_t create)
+{
+  fMergedDir = GetRemoteDir(dir,create);
+  return (fMergedDir.Length()>0);
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::SetRemoteDir(const char* dir, Bool_t create)
+{
+  fRemoteDir = GetRemoteDir(dir,create);
+  return (fIsValid = (fRemoteDir.Length()>0));
+}
+
+
+//______________________________________________________________________________
+void AliMuonAccEffSubmitter::SetRunList(const char* runList)
+{
+    // set the runlist from a text file
+  if (!fScalers)
+  {
+    fScalers = new AliAnalysisTriggerScalers(runList,fOCDBPath.Data());
+  }
+  else
+  {
+    fScalers->SetRunList(runList);
+  }
+  UpdateLocalFileList(kTRUE);
+}
+
+//______________________________________________________________________________
+void AliMuonAccEffSubmitter::SetRunList(int runNumber)
+{
+  // set the runlist from a text file
+  if (!fScalers)
+  {
+    fScalers = new AliAnalysisTriggerScalers(runNumber,fOCDBPath.Data());
+  }
+  else
+  {
+    fScalers->SetRunList(runNumber);      
+  }
+  UpdateLocalFileList(kTRUE);
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::SetVar(const char* varname, const char* value)
+{
+  TString s(varname);
+  s.ToUpper();
+  if (!s.BeginsWith("VAR_"))
+  {
+    AliError("Variable name should start with VAR_");
+    return kFALSE;
+  }
+  if (!fVars)
+  {
+    fVars = new TMap;
+    fVars->SetOwnerKeyValue(kTRUE,kTRUE);
+  }
+  
+  TObject* o = new TObjString(s);
+  fVars->Remove(o);
+  
+  fVars->Add(o,new TObjString(value));
+  
+  return kTRUE;
+}
+
+//______________________________________________________________________________
+Int_t AliMuonAccEffSubmitter::Submit(Bool_t dryRun)
+{
+  /// Submit multiple production jobs with the format "submit jdl 000run#.xml 000run#".
+  ///
+  /// Return the number of submitted (master) jobs
+  ///
+  /// Example:
+  /// - outputDir = "/alice/cern.ch/user/p/ppillot/Sim/LHC10h/JPsiPbPb276/AlignRawVtxRaw/ESDs"
+  /// - runList must contains the list of run number
+  /// - trigger is the (fully qualified) trigger name used to compute the base number of events
+  /// - mult is the factor to apply to the number of trigger to get the number of events to be generated
+  ///   (# generated events = # triggers x mult
+  
+  if (!IsValid()) return 0;
+  
+  gGrid->Cd(RemoteDir());
+  
+  if (!RemoteFileExists(RunJDLName()))
+  {
+    AliError(Form("file %s does not exist in %s", RunJDLName().Data(), RemoteDir().Data()));
+    return 0;
+  }
+  
+  if ( !fScalers )
+  {
+    AliError("No run list set. Use SetRunList");
+    return 0;
+  }
+  const std::vector<int>& runs = fScalers->GetRunList();
+  
+  if (runs.empty())
+  {
+    AliError("No run to work with");
+    return 0;
+  }
+  
+  //  cout << "total number of selected MB events = " << totEvt << endl;
+  //  cout << "required number of generated events = " << nGenEvents << endl;
+  //  cout << "number of generated events per MB event = " << ratio << endl;
+  //  cout << endl;
+  
+  std::cout << "run\tchunks\tevents" << std::endl;
+  std::cout << "----------------------" << std::endl;
+  
+  Int_t nJobs(0);
+  Int_t nEvts(0);
+  
+  for (std::vector<int>::size_type i=0; i < runs.size(); ++i)
+  {
+    Int_t runNumber = runs[i];
+    
+    Int_t nEvtRun(fFixedNofEvents);
+    
+    if ( fRatio > 0 )
+    {
+      AliAnalysisTriggerScalerItem* trigger = fScalers->GetTriggerScaler(runNumber, "L2A", ReferenceTrigger().Data());
+    
+      if (!trigger)
+      {
+        AliError(Form("Could not get trigger %s for run %09d",ReferenceTrigger().Data(),runNumber));
+        continue;
+      }
+      nEvtRun = TMath::Nint(fRatio * trigger->Value());
+    }
+    
+    Int_t nChunk = 1;
+    
+    while (nEvtRun/nChunk+0.5 > MaxEventsPerChunk())
+    {
+      ++nChunk;
+    }
+    
+    Int_t nEvtChunk = TMath::Nint(nEvtRun/nChunk + 0.5);
+    
+    nJobs += nChunk;
+    
+    nEvts += nChunk*nEvtChunk;
+    
+    std::cout << runNumber << "\t" << nChunk << "\t" << nEvtChunk << std::endl;
+    
+    TString query(Form("submit %s %d %d %d", RunJDLName().Data(), runNumber, nChunk, nEvtChunk));
+    
+    std::cout << query.Data() << " ..." << std::flush;
+    
+    TGridResult* res = 0x0;
+    
+    if (!dryRun)
+    {
+      res = gGrid->Command(query);
+    }
+    
+    if (res)
+    {
+      TString cjobId1 = res->GetKey(0,"jobId");
+      
+      if (!cjobId1.Length())
+      {
+        std::cout << " FAILED" << std::endl << std::endl;
+        gGrid->Stdout();
+        gGrid->Stderr();
+      }
+      else
+      {
+        std::cout << "DONE" << std::endl;
+        std::cout << Form("   --> the job Id is: %s",cjobId1.Data()) << std::endl << std::endl;
+      }
+    }
+    else
+    {
+      std::cout << " FAILED" << std::endl << std::endl;
+    }
+    
+    delete res;
+  }
+  
+  std::cout << std::endl
+  << "total number of jobs = " << nJobs << std::endl
+  << "total number of generated events = " << nEvts << std::endl
+  << std::endl;
+  
+  return nJobs;
+}
+
+//______________________________________________________________________________
+TObjArray* AliMuonAccEffSubmitter::TemplateFileList() const
+{
+  /// Return (after createing and filling it if needed)
+  /// the internal file list with paths from the template directory
+  
+  if (!fTemplateFileList)
+  {
+    fTemplateFileList = new TObjArray;
+    fTemplateFileList->SetOwner(kTRUE);
+    
+    fTemplateFileList->Add(new TObjString("CheckESD.C"));
+    fTemplateFileList->Add(new TObjString("CheckAOD.C"));
+    fTemplateFileList->Add(new TObjString("AODtrain.C"));
+    fTemplateFileList->Add(new TObjString("validation.sh"));
+    if ( fExternalConfig.Length() > 0 )
+    {
+      fTemplateFileList->Add(new TObjString(fExternalConfig));
+    }
+    else
+    {
+      fTemplateFileList->Add(new TObjString("Config.C"));
+    }
+    fTemplateFileList->Add(new TObjString("rec.C"));
+    fTemplateFileList->Add(new TObjString("sim.C"));
+    fTemplateFileList->Add(new TObjString("simrun.C"));
+    fTemplateFileList->Add(new TObjString(RunJDLName().Data()));
+    fTemplateFileList->Add(new TObjString(MergeJDLName(kFALSE).Data()));
+    fTemplateFileList->Add(new TObjString(MergeJDLName(kTRUE).Data()));
+    fTemplateFileList->Add(new TObjString("AOD_merge.sh"));
+    fTemplateFileList->Add(new TObjString("validation_merge.sh"));
+  }
+  
+  return fTemplateFileList;
+}
+
+//______________________________________________________________________________
+void AliMuonAccEffSubmitter::UpdateLocalFileList(Bool_t clearSnapshots)
+{
+  if (!fScalers) return;
+  
+  if ( clearSnapshots )
+  {
+    TIter next(LocalFileList());
+    TObjString* file;
+    
+    while ( ( file = static_cast<TObjString*>(next())) )
+    {
+      if ( file->String().Contains("OCDB_") )
+      {
+        LocalFileList()->Remove(file);
+      }
+    }
+    LocalFileList()->Compress();
+  }
+
+  const std::vector<int>& runs = fScalers->GetRunList();
+  
+  const char* type[] = { "sim","rec" };
+  
+  for ( std::vector<int>::size_type i = 0; i < runs.size(); ++i )
+  {
+    Int_t runNumber = runs[i];
+    
+    for ( Int_t t = 0; t < 2; ++t )
+    {
+      TString snapshot(Form("%s/OCDB/%d/OCDB_%s.root",SnapshotDir().Data(),runNumber,type[t]));
+      
+      if ( !gSystem->AccessPathName(snapshot.Data()) )
+      {
+        if ( !LocalFileList()->FindObject(snapshot.Data()) )
+        {
+          LocalFileList()->Add(new TObjString(snapshot));
+        }
+      }
+    }
+  }
+  
+}
+
+//______________________________________________________________________________
+void AliMuonAccEffSubmitter::UseOCDBSnapshots(Bool_t flag)
+{
+  fUseOCDBSnapshots = flag;
+  if ( flag )
+  {
+    SetVar("VAR_OCDB_SNAPSHOT","kTRUE");
+  }
+  else
+  {
+    SetVar("VAR_OCDB_SNAPSHOT","kFALSE");
+  }
+  
+  UpdateLocalFileList();
+}
+
diff --git a/PWG/muondep/AliMuonAccEffSubmitter.h b/PWG/muondep/AliMuonAccEffSubmitter.h
new file mode 100644 (file)
index 0000000..3e75349
--- /dev/null
@@ -0,0 +1,160 @@
+#ifndef ALIMUONACCEFFSUBMITTER_H
+#define ALIMUONACCEFFSUBMITTER_H
+
+#include "TObject.h"
+#include "TString.h"
+#include "Riostream.h"
+
+class AliAnalysisTriggerScalers;
+class TMap;
+
+class AliMuonAccEffSubmitter : public TObject
+{
+public:
+  AliMuonAccEffSubmitter();
+
+  virtual ~AliMuonAccEffSubmitter();
+
+  Bool_t SetRemoteDir(const char* dir, Bool_t create = kTRUE);
+  void SetLocalDir(const char* LocalDir) { fLocalDir = LocalDir; }
+  Bool_t SetMergedDir(const char* dir, Bool_t create = kTRUE);
+
+  void UseOCDBSnapshots(Bool_t flag);
+  
+  void UseExternalConfig(const char* externalConfigFullFilePath) { fExternalConfig = externalConfigFullFilePath; }
+  
+  Bool_t CheckLocal() const;
+  Bool_t CheckRemote() const;
+  
+  void CleanLocal(Bool_t cleanSnapshots=kFALSE) const;
+  void CleanRemote() const;
+
+  TString MergedDir() const { return fMergedDir; }  
+  TString RemoteDir() const { return fRemoteDir; }
+  TString LocalDir() const { return fLocalDir; }
+  
+  TString FilePath(const char* what) const;
+
+  Int_t MaxEventsPerChunk() const { return fMaxEventsPerChunk; }
+  void SetMaxEventsPerChunk(Int_t n) { fMaxEventsPerChunk = n; }
+
+  UInt_t NofRuns() const;
+  
+  void SetRatio(Float_t ratio) { fRatio = ratio; }
+  void SetOCDBPath(const char* ocdbPath) { fOCDBPath = ocdbPath; }
+                   
+  void MakeNofEventsPropToTriggerCount(const char* trigger="CMUL8-S-NOPF-MUON", Float_t ratio=1.0) { fReferenceTrigger = trigger; fRatio = ratio; }
+  void MakeNofEventsFixed(Int_t nevents) { fFixedNofEvents = nevents; fReferenceTrigger=""; fRatio=0.0; }
+  
+  void SetRunList(const char* runlist);
+  void SetRunList(int runNumber);
+  
+  TString ReferenceTrigger() const { return fReferenceTrigger; }
+  
+  Bool_t Run(const char* mode);
+  
+  Bool_t Merge(Int_t stage, Bool_t dryRun=kTRUE);
+
+  Int_t Submit(Bool_t dryRun=kTRUE);
+  
+  TString RunJDLName() const { return "run.jdl"; }
+
+  TString MergeJDLName(Bool_t final) const { return (final ? "AOD_merge_final.jdl" : "AOD_merge.jdl"); }
+
+  virtual void Print(Option_t* opt="") const;
+
+  Bool_t CopyLocalFilesToRemote();
+
+  Bool_t CopyTemplateFilesToLocal();
+
+  Bool_t GenerateRunJDL(const char* name);
+
+  Bool_t GenerateMergeJDL(const char* name);
+
+  void SetPackages(const char* aliroot, const char* root, const char* geant3,
+                   const char* api="VO_ALICE@APISCONFIG::V1.1x");
+  
+  void SetSplitMaxInputFileNumber(Int_t n) { fSplitMaxInputFileNumber = n; }
+  
+  Int_t GetSplitMaxInputFileNumber() const { return fSplitMaxInputFileNumber; }
+  
+  Int_t CompactMode() const { return fCompactMode; }
+  
+  void SetCompactMode(Int_t mode) { fCompactMode=mode; }
+  
+  Bool_t ShouldOverwriteFiles() const { return fShouldOverwriteFiles; }
+
+  void ShouldOverwriteFiles(Bool_t flag) { fShouldOverwriteFiles = flag; }
+
+  Bool_t SetVar(const char* varname, const char* value);
+  
+  Bool_t MakeOCDBSnapshots();
+  
+  void SetOCDBSnapshotDir(const char* dir);
+
+private:
+
+  TString GetRemoteDir(const char* dir, Bool_t create);
+
+  std::ostream* CreateJDLFile(const char* name) const;
+
+  Bool_t CheckRemoteDir() const;
+
+  Bool_t CopyFile(const char* localFile);
+  
+  Bool_t GetLastStage(const char* remoteDir) const;
+
+  Bool_t RemoteDirectoryExists(const char *dirname) const;
+  Bool_t RemoteFileExists(const char *lfn) const;
+
+  void Output(std::ostream& out, const char* key, const char* v1,
+              const char* v2="", const char* v3="", const char* v4="", const char* v5="",
+              const char* v6="", const char* v7="", const char* v8="", const char* v9="") const;
+  
+  void Output(std::ostream& out, const char* key, const TObjArray& values) const;
+
+  Bool_t ReplaceVars(const char* file);
+
+  TObjArray* TemplateFileList() const;
+
+  TObjArray* LocalFileList() const;
+  
+  Bool_t IsValid() const { return fIsValid; }
+  
+  Bool_t HasVars(const char* localFile) const;
+
+  void UpdateLocalFileList(Bool_t clearSnapshot=kFALSE);
+  
+  TString SnapshotDir() const { return fSnapshotDir; }
+  
+private:
+  AliAnalysisTriggerScalers* fScalers;
+  TString fRemoteDir;
+  TString fReferenceTrigger;
+  Float_t fRatio;
+  Int_t fFixedNofEvents;
+  Int_t fMaxEventsPerChunk;
+  TString fLocalDir;
+  TString fOCDBPath;
+  TString fTemplateDir;
+  TString fPackageAliroot;
+  TString fPackageGeant3;
+  TString fPackageRoot;
+  TString fPackageApi;
+  TString fMergedDir;
+  Int_t fSplitMaxInputFileNumber;
+  Int_t fCompactMode;
+  Bool_t fShouldOverwriteFiles;
+  TMap* fVars;
+  TString fExternalConfig;
+  Bool_t fUseOCDBSnapshots;
+  Bool_t fIsValid;
+  mutable TObjArray* fTemplateFileList;
+  mutable TObjArray* fLocalFileList;
+  TString fSnapshotDir;
+  
+  ClassDef(AliMuonAccEffSubmitter,1) // Helper class to submit AccxEff single particle simulations
+};
+
+#endif
+