]> git.uio.no Git - u/mrichter/AliRoot.git/commitdiff
General updates, including new class to compute the normalization factors using the...
authorpcrochet <pcrochet@f7af4fe6-9843-0410-8265-dc069ae4e863>
Fri, 14 Jun 2013 21:18:30 +0000 (21:18 +0000)
committerpcrochet <pcrochet@f7af4fe6-9843-0410-8265-dc069ae4e863>
Fri, 14 Jun 2013 21:18:30 +0000 (21:18 +0000)
25 files changed:
PWG/muondep/AccEffTemplates/GenParamCustomSingle.C [new file with mode: 0644]
PWG/muondep/AccEffTemplates/rec.C
PWG/muondep/AliAnalysisMuMu.cxx
PWG/muondep/AliAnalysisMuMu.h
PWG/muondep/AliAnalysisMuMuFnorm.cxx [new file with mode: 0644]
PWG/muondep/AliAnalysisMuMuFnorm.h [new file with mode: 0644]
PWG/muondep/AliAnalysisMuMuGraphUtil.cxx [new file with mode: 0644]
PWG/muondep/AliAnalysisMuMuGraphUtil.h [new file with mode: 0644]
PWG/muondep/AliAnalysisMuMuJpsiResult.cxx [new file with mode: 0644]
PWG/muondep/AliAnalysisMuMuJpsiResult.h [new file with mode: 0644]
PWG/muondep/AliAnalysisMuMuResult.cxx
PWG/muondep/AliAnalysisMuMuResult.h
PWG/muondep/AliAnalysisMuMuSpectra.cxx
PWG/muondep/AliAnalysisMuMuSpectra.h
PWG/muondep/AliAnalysisTriggerScalers.cxx
PWG/muondep/AliAnalysisTriggerScalers.h
PWG/muondep/AliMuonAccEffSubmitter.cxx
PWG/muondep/AliMuonAccEffSubmitter.h
PWG/muondep/AliMuonGridSubmitter.cxx [new file with mode: 0644]
PWG/muondep/AliMuonGridSubmitter.h [new file with mode: 0644]
PWG/muondep/AliMuonQAMergeSubmitter.cxx [new file with mode: 0644]
PWG/muondep/AliMuonQAMergeSubmitter.h [new file with mode: 0644]
PWG/muondep/QAMergeTemplates/QAMerge.C [new file with mode: 0644]
PWG/muondep/QAMergeTemplates/QAMerge.sh [new file with mode: 0644]
PWG/muondep/QAMergeTemplates/validation.sh [new file with mode: 0644]

diff --git a/PWG/muondep/AccEffTemplates/GenParamCustomSingle.C b/PWG/muondep/AccEffTemplates/GenParamCustomSingle.C
new file mode 100644 (file)
index 0000000..33094b4
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *  MuonGenerator.C
+ *  aliroot_dev
+ *
+ *  Created by philippe pillot on 05/03/13.
+ *  Copyright 2013 SUBATECH. All rights reserved.
+ *
+ */
+
+
+#if !defined(__CINT__) || defined(__MAKECINT__)
+#include <Riostream.h>
+#include "TRandom.h"
+#include "AliGenerator.h"
+#include "AliGenParam.h"
+#endif
+
+
+static Int_t IpMuon( TRandom *ran);
+static Double_t PtMuon( const Double_t *px, const Double_t */*dummy*/ );
+static Double_t YMuon( const Double_t *py, const Double_t */*dummy*/ );
+static Double_t V2Muon( const Double_t *pv, const Double_t */*dummy*/ );
+
+
+//-------------------------------------------------------------------------
+AliGenerator* GenParamCustomSingle()
+{
+  AliGenParam *singleMu = new AliGenParam(1,-1,PtMuon,YMuon,V2Muon,IpMuon);
+  singleMu->SetMomentumRange(0,1e6);
+  singleMu->SetPtRange(VAR_GENPARAMCUSTOMSINGLE_PTMIN,999.);
+  singleMu->SetYRange(-4.2, -2.3);
+  singleMu->SetPhiRange(0., 360.);
+  singleMu->SetForceDecay(kNoDecay);
+  singleMu->SetTrackingFlag(1);
+  return singleMu;
+}
+
+//-------------------------------------------------------------------------
+Int_t IpMuon(TRandom *ran)
+{
+  // muon composition
+  
+  if (ran->Rndm() < 0.5 )
+  {
+    return 13;
+  }
+  else
+  {
+    return -13;
+  }
+}
+
+//-------------------------------------------------------------------------
+Double_t PtMuon( const Double_t *px, const Double_t */*dummy*/ )
+{
+  // muon pT
+  
+  Double_t x=*px;
+  Float_t p0,p1,p2,p3;
+  p0 = VAR_GENPARAMCUSTOMSINGLE_PT_P0; //4.05962;
+  p1 = VAR_GENPARAMCUSTOMSINGLE_PT_P1; //1;
+  p2 = VAR_GENPARAMCUSTOMSINGLE_PT_P2; //2.46187;
+  p3 = VAR_GENPARAMCUSTOMSINGLE_PT_P3; //2.08644;
+  return p0 / TMath::Power( p1 + TMath::Power(x,p2), p3 );
+}
+
+//-------------------------------------------------------------------------
+Double_t YMuon( const Double_t *py, const Double_t */*dummy*/ )
+{
+  // muon y
+  
+  Double_t y = *py;
+  //pol4 only valid in y= -4;-2.5
+  Float_t p0,p1,p2,p3;
+  p0 = VAR_GENPARAMCUSTOMSINGLE_Y_P0; //0.729545;
+  p1 = VAR_GENPARAMCUSTOMSINGLE_Y_P1; //0.53837;
+  p2 = VAR_GENPARAMCUSTOMSINGLE_Y_P2; //0.141776;
+  p3 = VAR_GENPARAMCUSTOMSINGLE_Y_P3; //0.0130173;
+  return p0 * (1. + p1*y + p2*y*y + p3*y*y*y);
+}
+
+//-------------------------------------------------------------------------
+Double_t V2Muon( const Double_t */*dummy*/, const Double_t */*dummy*/ )
+{
+  //muon v2
+  return 0.;
+}
+
index a5399b7b905d9874ad7d5fb0cbbf9278c9f47b60..ac6d356b2b3c675a90b7cb3ed34bfc1313c2d435 100644 (file)
@@ -29,6 +29,7 @@ void rec(int dset=0)
   
   // MUON Tracker Residual Alignment
   reco.SetSpecificStorage("MUON/Align/Data","alien://folder=/alice/simulation/2008/v4-15-Release/Residual");
-
+reco.SetSpecificStorage("MUON/Calib/RejectList","alien://folder=/alice/cern.ch/user/l/laphecet/OCDB");
+  
   reco.Run();
 }
index fcfc807c28c0cdb62b5907cf6174a1e4f429b535..1eec1cf1d3e6aa41988876e2940a31b62c0b22c6 100644 (file)
@@ -19,7 +19,9 @@
 #include "AliAnalysisMuMu.h"
 
 #include "AliAnalysisMuMuBinning.h"
-#include "AliAnalysisMuMuResult.h"
+#include "AliAnalysisMuMuFnorm.h"
+#include "AliAnalysisMuMuGraphUtil.h"
+#include "AliAnalysisMuMuJpsiResult.h"
 #include "AliAnalysisMuMuSpectra.h"
 #include "AliAnalysisTriggerScalers.h"
 #include "AliCounterCollection.h"
@@ -38,6 +40,7 @@
 #include "TGrid.h"
 #include "TH1.h"
 #include "TH2.h"
+#include "THashList.h"
 #include "TKey.h"
 #include "TLegend.h"
 #include "TLegendEntry.h"
@@ -173,16 +176,20 @@ fAssociatedSimulation(0x0)
   
   GetCollections(fFilename,fMergeableCollection,fCounterCollection,fBinning,fRunNumbers);
   
-  if (IsSimulation())
+  if ( fCounterCollection )
   {
-    SetEventSelectionList("ALL");
-    SetDimuonTriggerList("CMULLO-B-NOPF-MUON");
-    SetFitTypeList("PSI1:1,COUNTJPSI:1");
-  }
+    if (IsSimulation())
+    {
+      SetEventSelectionList("ALL");
+      SetDimuonTriggerList("CMULLO-B-NOPF-MUON");
+      SetFitTypeList("COUNTJPSI:1");
+//    SetFitTypeList("PSI1:1,COUNTJPSI:1");
+    }
   
-  if ( strlen(associatedSimFileName) )
-  {
-    fAssociatedSimulation = new AliAnalysisMuMu(associatedSimFileName);
+    if ( strlen(associatedSimFileName) )
+    {
+      fAssociatedSimulation = new AliAnalysisMuMu(associatedSimFileName);
+    }
   }
 }
 
@@ -190,6 +197,14 @@ fAssociatedSimulation(0x0)
 AliAnalysisMuMu::~AliAnalysisMuMu()
 {
   // dtor
+  
+  if ( fAssociatedSimulation )
+  {
+    fAssociatedSimulation->Update();
+  }
+  
+  Update();
+  
   delete fCounterCollection;
   delete fBinning;
   delete fMergeableCollection;
@@ -412,43 +427,6 @@ void AliAnalysisMuMu::CleanAllSpectra()
   Update();
 }
 
-//_____________________________________________________________________________
-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,
@@ -939,6 +917,8 @@ Bool_t AliAnalysisMuMu::DecodeFileName(const char* filename,
                                              int& aodtrain,
                                              int& runnumber)
 {
+  // tries to extract period and pass numbers from a file name.
+  
   esdpass=aodtrain=runnumber=-1;
   period="";
   
@@ -946,6 +926,29 @@ Bool_t AliAnalysisMuMu::DecodeFileName(const char* filename,
   
   if (!sfile.BeginsWith("LHC") && !sfile.BeginsWith("SIM") ) 
   {
+    // does not look nice but let's try at least to get the period
+    
+    TObjArray* tmp = sfile.Tokenize(".");
+    
+    for ( Int_t j = 0; j < tmp->GetEntries(); ++j )
+    {
+      TString s = static_cast<TObjString*>(tmp->At(j))->String();
+      s.ToLower();
+      if ( s.BeginsWith("lhc") )
+      {
+        period = s;
+        period.ReplaceAll("lhc","LHC");
+        break;
+      }
+    }
+
+    delete tmp;
+    
+    if ( period.Length() )
+    {
+      return kTRUE;
+    }
+
     std::cerr << Form("filename %s does not start with LHC or SIM",filename) << std::endl;
     return kFALSE;
   }
@@ -1077,7 +1080,13 @@ void AliAnalysisMuMu::DrawMinv(const char* type,
   TString stype(type);
   stype.ToUpper();
   
-  TString spectraName(Form("/%s/%s/%s/%s/%s-%s-%s",eventType,trigger,centrality,pairCut,particle,stype.Data(),flavour));
+  TString spectraName(Form("/%s/%s/%s/%s/%s-%s",eventType,trigger,centrality,pairCut,particle,stype.Data()));
+  
+  if ( strlen(flavour))
+  {
+    spectraName += "-";
+    spectraName += flavour;
+  }
   
   AliAnalysisMuMuSpectra* spectra = static_cast<AliAnalysisMuMuSpectra*>(MC()->GetObject(spectraName.Data()));
   
@@ -1086,7 +1095,7 @@ void AliAnalysisMuMu::DrawMinv(const char* type,
   TObjArray* spectraBins(0x0);
   if ( spectra )
   {
-    spectraBins = spectra->Bins();
+    spectraBins = spectra->BinContentArray();
   }
   
   TCanvas* c = new TCanvas;
@@ -1108,13 +1117,13 @@ void AliAnalysisMuMu::DrawMinv(const char* type,
 
     AliDebug(1,name.Data());
     
-    AliAnalysisMuMuResult* spectraBin(0x0);
+    AliAnalysisMuMuJpsiResult* spectraBin(0x0);
     
     if ( spectraBins )
     {
       AliAnalysisMuMuResult* sr = static_cast<AliAnalysisMuMuResult*>(spectraBins->At(ci));
       
-      spectraBin = sr->SubResult(subresultname);
+      spectraBin = static_cast<AliAnalysisMuMuJpsiResult*>(sr->SubResult(subresultname));
       
       AliDebug(1,Form("spectraBin(%s)=%p",subresultname,spectraBin));
     }
@@ -1245,6 +1254,229 @@ AliAnalysisMuMu::ExpandPathName(const char* file)
   return file;
 }
 
+//_____________________________________________________________________________
+void AliAnalysisMuMu::TwikiOutputFnorm(const char* series) const
+{
+  // make a twiki-compatible output of the Fnorm factor(s)
+  TObjArray* what = TString(series).Tokenize(",");
+  TObjString* s;
+  TObjArray graphs;
+  TIter next(what);
+
+  std::cout << "| *Run* |";
+  while ( ( s = static_cast<TObjString*>(next())) )
+  {
+    TGraph* g = static_cast<TGraph*>(MC()->GetObject(Form("/FNORM/GRAPHS/%s",s->String().Data())));
+    if (!g)
+    {
+      AliError(Form("Could not find graph for %s",s->String().Data()));
+      continue;
+    }
+    std::cout << " *" << s->String().Data();
+    if ( s->String().BeginsWith("RelDif") ) std::cout << " %";
+    std::cout << "*|";
+    graphs.Add(g);
+  }
+  
+  std::cout << endl;
+  
+  TGraphErrors* g0 = static_cast<TGraphErrors*>(graphs.First());
+  if (!g0) return;
+  
+  for ( Int_t i = 0; i < g0->GetN(); ++i )
+  {
+    TString msg;
+    
+    msg.Form("|%6d|",TMath::Nint(g0->GetX()[i]));
+    
+    for ( Int_t j = 0; j < graphs.GetEntries(); ++j )
+    {
+      TGraphErrors* g = static_cast<TGraphErrors*>(graphs.At(j));
+      
+      msg += TString::Format(" %6.2f +- %6.2f |",g->GetY()[i],g->GetEY()[i]);
+    }
+    
+    std::cout << msg.Data() << std::endl;
+  }
+  
+  next.Reset();
+  
+  std::cout << "|*Weigthed mean (*)*|";
+
+  AliAnalysisMuMuResult* r = static_cast<AliAnalysisMuMuResult*>(MC()->GetObject("/FNORM/RESULTS/Fnorm"));
+  
+  if (!r)
+  {
+    AliError("Could not find Fnorm result !");
+    return;
+  }
+
+  
+  while ( ( s = static_cast<TObjString*>(next())) )
+  {
+    TString var("Fnorm");
+    TString unit;
+    
+    if ( s->String().BeginsWith("Fnorm") )
+    {
+      r = static_cast<AliAnalysisMuMuResult*>(MC()->GetObject("/FNORM/RESULTS/Fnorm"));
+    }
+    else if ( s->String().BeginsWith("RelDif") )
+    {
+      r = static_cast<AliAnalysisMuMuResult*>(MC()->GetObject("/FNORM/RESULTS/RelDif"));
+      unit = "%";
+    }
+      
+    r->Exclude("*");
+    r->Include(s->String().Data());
+
+    std::cout << Form(" * %5.2f +- %5.2f %s * |",
+                      r->GetValue(var.Data()),
+                      r->GetErrorStat(var.Data()),
+                      unit.Data());
+  }
+  
+  next.Reset();
+  
+  std::cout << std::endl;
+
+  std::cout << "|*RMS*|";
+
+  while ( ( s = static_cast<TObjString*>(next())) )
+  {
+    TString var("Fnorm");
+    
+    if ( s->String().BeginsWith("Fnorm") )
+    {
+      r = static_cast<AliAnalysisMuMuResult*>(MC()->GetObject("/FNORM/RESULTS/Fnorm"));
+    }
+    else if ( s->String().BeginsWith("RelDif") )
+    {
+      r = static_cast<AliAnalysisMuMuResult*>(MC()->GetObject("/FNORM/RESULTS/RelDif"));
+    }
+    
+    r->Exclude("*");
+    r->Include(s->String().Data());
+    
+    Double_t d = 100.0*r->GetRMS(var.Data())/r->GetValue(var.Data());
+    
+    std::cout << Form(" * %5.2f (%5.2f %%) * |",
+                      r->GetRMS(var.Data()),d);
+  }
+  
+  std::cout << std::endl;
+  std::cout << "(*) weight is the number of CMUL7-B-NOPF-MUON triggers (physics-selected and pile-up corrected) in each run" << std::endl;
+  
+  delete what;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMu::FigureOutputFnorm(const char* filelist)
+{
+  /// Make some figure of the Fnorm factors for files in filelist
+  
+  TObjArray* periods = ReadFileList(filelist);
+  
+  if (!periods || periods->IsEmpty() ) return;
+  
+  TIter next(periods);
+  
+  TObjArray fnormoffline1;
+  TObjArray fnormoffline2;
+  TObjArray reldif;
+  TObjArray correctionPSMUL;
+  TObjArray correctionPSMB;
+  TObjArray correctionPUPS;
+  TObjArray correctionPSRatio;
+  
+  fnormoffline1.SetOwner(kTRUE);
+  fnormoffline2.SetOwner(kTRUE);
+  reldif.SetOwner(kTRUE);
+  correctionPUPS.SetOwner(kTRUE);
+  correctionPSMUL.SetOwner(kTRUE);
+  correctionPSMB.SetOwner(kTRUE);
+  correctionPSRatio.SetOwner(kTRUE);
+  
+  for ( Int_t i = 0; i <= periods->GetLast(); ++i )
+  {
+    TString period("unknown");
+    
+    TString filename(static_cast<TObjString*>(periods->At(i))->String());
+    
+    Int_t dummy(0);
+    
+    if (!DecodeFileName(filename,period,dummy,dummy,dummy))
+    {
+      continue;
+    }
+    
+    if ( gSystem->AccessPathName(filename) )
+    {
+      AliErrorClass(Form("Could not find file %s. Skipping it.",filename.Data()));
+      continue;
+      
+    }
+    
+    AliAnalysisMuMu m(filename.Data());
+    
+    fnormoffline1.Add(m.MC()->GetObject("/FNORM/GRAPHS/FnormOffline1PUPS")->Clone());
+    fnormoffline2.Add(m.MC()->GetObject("/FNORM/GRAPHS/FnormOffline2PUPS")->Clone());
+    
+    
+    correctionPSMUL.Add(m.MC()->GetObject("/FNORM/GRAPHS/CorrectionPSMUL")->Clone());
+    correctionPSMB.Add(m.MC()->GetObject("/FNORM/GRAPHS/CorrectionPSMB")->Clone());
+    correctionPUPS.Add(m.MC()->GetObject("/FNORM/GRAPHS/CorrectionPUPSMB")->Clone());
+    
+    correctionPSRatio.Add(m.MC()->GetObject("/FNORM/GRAPHS/CorrectionPSRatio")->Clone());
+    
+    
+    reldif.Add(m.MC()->GetObject("/FNORM/GRAPHS/RelDifFnormScalersPUPSvsFnormOffline2PUPS")->Clone());
+
+  }
+
+  AliAnalysisMuMuGraphUtil gu(fgOCDBPath);
+  
+  gu.ShouldDrawPeriods(kTRUE);
+  
+  TObjArray a;
+  
+  a.Add(gu.Combine(fnormoffline1,fgIsCompactGraphs));
+  a.Add(gu.Combine(fnormoffline2,fgIsCompactGraphs));
+
+  Double_t ymin(0.0);
+  Double_t ymax(3000.0);
+  
+  new TCanvas("fnormoffline","fnormoffline");
+  
+  gu.PlotSameWithLegend(a,ymin,ymax);
+  
+  new TCanvas("corrections","corrections");
+  
+  a.Clear();
+  
+  a.Add(gu.Combine(correctionPSMB,fgIsCompactGraphs));
+  a.Add(gu.Combine(correctionPSMUL,fgIsCompactGraphs));
+  a.Add(gu.Combine(correctionPUPS,fgIsCompactGraphs));
+  
+  gu.PlotSameWithLegend(a,0.8,1.2);
+
+  new TCanvas("psratio","psratio");
+  
+  a.Clear();
+  
+  a.Add(gu.Combine(correctionPSRatio,fgIsCompactGraphs));
+  
+  gu.PlotSameWithLegend(a,0.8,1.2);
+  
+  new TCanvas("offlinevsscalers","fig:offlinevsscalers");
+  
+  a.Clear();
+  
+  a.Add(gu.Combine(reldif,fgIsCompactGraphs));
+
+  gu.PlotSameWithLegend(a,-15,15);
+}
+
 //_____________________________________________________________________________
 TFile* 
 AliAnalysisMuMu::FileOpen(const char* file)
@@ -1316,7 +1548,12 @@ AliAnalysisMuMu::FitParticle(const char* particle,
     delete bins;
     return 0x0;
   }
-  
+
+  TObjArray* runs = fCounterCollection->GetKeyWords("run").Tokenize(",");
+  Int_t nruns = runs->GetEntries();
+  delete runs;
+                            
+
 //  binning.Print();
   
   AliAnalysisMuMuSpectra* spectra(0x0);
@@ -1353,14 +1590,15 @@ AliAnalysisMuMu::FitParticle(const char* particle,
     hminv = static_cast<TH1*>(hminv->Clone(Form("minv%d",n++)));
     
     
-    AliAnalysisMuMuResult* r = new AliAnalysisMuMuResult(*hminv,
-                                                         trigger,
-                                                         eventType,
-                                                         pairCut,
-                                                         centrality,
-                                                         *bin);
+    AliAnalysisMuMuJpsiResult* r = new AliAnalysisMuMuJpsiResult(*hminv,
+                                                                 trigger,
+                                                                 eventType,
+                                                                 pairCut,
+                                                                 centrality,
+                                                                 *bin);
     
     r->SetNofTriggers(ntrigger);
+    r->SetNofRuns(nruns);
     
     nextFitType.Reset();
     
@@ -1444,7 +1682,7 @@ AliAnalysisMuMu::GetMCCB2Tails(const AliAnalysisMuMuBinning::Range& bin) const
   
   if ( r )
   {
-    AliAnalysisMuMuResult* r1 = r->SubResult("JPSI:1");
+    AliAnalysisMuMuJpsiResult* r1 = dynamic_cast<AliAnalysisMuMuJpsiResult*>(r->SubResult("JPSI:1"));
     if  (r1)
     {
       TF1* func = static_cast<TF1*>(r1->Minv()->GetListOfFunctions()->FindObject("fitTotal"));
@@ -1498,8 +1736,8 @@ AliAnalysisMuMuSpectra* AliAnalysisMuMu::GetSpectra(const char* what, const char
   sflavour.ToUpper();
   
   TString spectraName(Form("/PSALL/%s/PP/%s/PSI-%s",
-                           First(fgDefaultDimuonTriggers).Data(),
-                           First(fgDefaultPairSelectionList).Data(),
+                           First(fDimuonTriggers).Data(),
+                           First(fPairSelectionList).Data(),
                            swhat.Data()));
 
   if (sflavour.Length()>0)
@@ -1623,6 +1861,8 @@ Bool_t AliAnalysisMuMu::IsSimulation() const
 {
   // whether or not we have MC information
   
+  if (!fMergeableCollection) return kFALSE;
+  
   return ( fMergeableCollection->Histo(Form("/INPUT/%s/MinvUS",fgDefaultEventSelectionForSimulations.Data())) != 0x0 );
 }
 
@@ -1675,14 +1915,15 @@ AliAnalysisMuMu::Jpsi(const char* what, const char* binningFlavour)
       binning->AddBin("psi",swhat->String().Data());
     }
     
-    std::cout << "++++++++++++ swhat=" << swhat->String().Data() << std::endl;
+    StdoutToAliDebug(1,std::cout << "++++++++++++ swhat=" << swhat->String().Data() << std::endl;);
     
     if (!binning)
     {
       AliError("oups. binning is NULL");
       continue;
     }
-    binning->Print();
+    
+    StdoutToAliDebug(1,binning->Print(););
     
     nextTrigger.Reset();
     
@@ -1733,7 +1974,7 @@ AliAnalysisMuMu::Jpsi(const char* what, const char* binningFlavour)
           
             fMergeableCollection->Adopt(id.Data(),spectra);
             
-            spectra->Print();
+            StdoutToAliDebug(1,spectra->Print(););
           }
         }
       }
@@ -1745,7 +1986,7 @@ AliAnalysisMuMu::Jpsi(const char* what, const char* binningFlavour)
   delete eventTypeArray;
   delete pairCutArray;
 
-  timer.Print();
+  StdoutToAliDebug(1,timer.Print(););
 
   if (nfits)
   {
@@ -1760,6 +2001,144 @@ AliAnalysisMuMu::Jpsi(const char* what, const char* binningFlavour)
   
 }
 
+//_____________________________________________________________________________
+void AliAnalysisMuMu::LatexOutputFnorm(const char* filelist, const char* subresultnames, Bool_t rms)
+{
+  /// Make a LaTeX output of the Fnorm factors for each file in filelist
+  
+  TObjArray* periods = ReadFileList(filelist);
+  
+  if (!periods || periods->IsEmpty() ) return;
+  
+  TIter next(periods);
+  
+  TObjArray* subresults = TString(subresultnames).Tokenize(",");
+  TIter nextSub(subresults);
+
+  Int_t ic(0);
+  Int_t iclast = subresults->GetLast();
+  
+
+  std::cout << "\\begin{tabular}{l|r|r|r|r}" << std::endl;
+  
+  std::cout << "Period & ";
+  
+  TObjString* rname;
+
+  
+  while ( ( rname = static_cast<TObjString*>(nextSub())) )
+  {
+    std::cout << rname->String().Data();
+    
+    if ( ic != iclast )
+    {
+      std::cout << " & ";
+    }
+    ++ic;
+  }
+  
+  std::cout << "\\\\" << std::endl << "\\hline" << std::endl;
+
+  for ( Int_t i = 0; i <= periods->GetLast(); ++i )
+  {
+    TString period("unknown");
+    
+    TString filename(static_cast<TObjString*>(periods->At(i))->String());
+    
+    Int_t dummy(0);
+    
+    if (!DecodeFileName(filename,period,dummy,dummy,dummy))
+    {
+      continue;
+    }
+
+    if ( gSystem->AccessPathName(filename) )
+    {
+      AliErrorClass(Form("Could not find file %s. Skipping it.",filename.Data()));
+      continue;
+      
+    }
+    
+    AliAnalysisMuMu m(filename.Data());
+    
+    AliMergeableCollection* norm = m.MC()->Project("/FNORM/RESULTS/");
+  
+    AliAnalysisMuMuResult* r = static_cast<AliAnalysisMuMuResult*>(norm->GetObject("Fnorm")->Clone());
+  
+    nextSub.Reset();
+    
+    if (!r)
+    {
+      AliErrorClass(Form("Could not get result for file %s.",filename.Data()));
+      continue;    
+    }
+
+    std::cout << period << " & ";
+    
+    next.Reset();
+    
+    ic = 0;
+    
+    while ( ( rname = static_cast<TObjString*>(nextSub())) )
+    {
+      TString name(rname->String());
+      TString var("Fnorm");
+      
+      if ( name.BeginsWith("RelDif"))
+      {
+        r = static_cast<AliAnalysisMuMuResult*>(norm->GetObject("RelDif"));
+        
+      }
+      else if ( name.BeginsWith("Correction"))
+      {
+        r = static_cast<AliAnalysisMuMuResult*>(norm->GetObject("Correction"));
+      }
+      else
+      {
+        r = static_cast<AliAnalysisMuMuResult*>(norm->GetObject("Fnorm"));
+      }
+      r->Exclude("*");
+      r->Include(name.Data());
+
+      if ( rms )
+      {
+        std::cout << Form(" $%7.2f (%5.2f \%%)$ ",
+                          r->GetRMS(var.Data()),
+                          100.0*r->GetRMS(var.Data())/r->GetValue(var.Data()));
+        
+      }
+      else
+      {
+        std::cout << Form(" $%7.2f \\pm %5.3f$  ",r->GetValue(var.Data()),
+                          r->GetErrorStat(var.Data()));
+      }
+      
+      if ( ic != iclast )
+      {
+        std::cout << "&";
+      }
+      
+      ++ic;
+    }
+
+    if ( i != periods->GetLast() )
+    {
+      std::cout << "\\\\";
+    }
+
+    std::cout << std::endl;
+
+    delete norm;
+  }
+  
+
+  std::cout << "\\end{tabular}" << std::endl;
+  
+  
+  
+  delete periods;
+}
+
 //_____________________________________________________________________________
 void AliAnalysisMuMu::PlotBackgroundEvolution(const char* gfile, const char* triggerList, Double_t ymax, Bool_t fillBoundaries)
 {
@@ -1942,7 +2321,7 @@ AliAnalysisMuMu::PlotJpsiEvolution(const char* resultFile, const char* triggerLi
     {
       TObjArray* a = static_cast<TObjArray*>(m->GetValue(str->String().Data()));
       if (!a) continue;
-      AliAnalysisMuMuResult* r = static_cast<AliAnalysisMuMuResult*>(a->FindObject(triggerClass.Data()));
+      AliAnalysisMuMuJpsiResult* r = static_cast<AliAnalysisMuMuJpsiResult*>(a->FindObject(triggerClass.Data()));
       if (!r) continue;
 
       TString period;
@@ -2080,7 +2459,7 @@ AliAnalysisMuMu::PlotJpsiEvolution(const char* resultFile, const char* triggerLi
     
     if ( CompactGraphs() )
     {
-      Compact(*g);
+      AliAnalysisMuMuGraphUtil::Compact(*g);
     }
     
     g->Draw("P");
@@ -2293,7 +2672,7 @@ TObjArray*
 AliAnalysisMuMu::ReadFileList(const char* filelist)
 {
   //
-  // read the filelist and try to order it by runnumber
+  // read the filelist and try to order it by runnumber (or periods)
   //
   // filelist can either be a real filelist (i.e. a text file containing
   // root filenames) or a root file itself.
@@ -2312,8 +2691,8 @@ AliAnalysisMuMu::ReadFileList(const char* filelist)
     return files;
   }
   
-  std::set<int> runnumbers;
-  std::map<int,std::string> filemap;
+  std::set<std::string> sorting;
+  std::map<std::string,std::string> filemap;
   
   std::ifstream in(sfilelist.Data());
   
@@ -2322,24 +2701,32 @@ AliAnalysisMuMu::ReadFileList(const char* filelist)
   
   while ( in.getline(line,1022,'\n') )
   {
+    TString sline(line);
+    if (sline.BeginsWith("#")) continue;
+    
     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);
+    TString key(Form("%d",runnumber));
+    
+    if ( runnumber <= 0 )
+    {
+      key = period;
+    }
+    sorting.insert(key.Data());
+    filemap.insert(std::make_pair<std::string,std::string>(key.Data(),line));
   }
   
   in.close();
   
-  std::set<int>::const_iterator it;
-  
-  for ( it = runnumbers.begin(); it != runnumbers.end(); ++it )
+  std::set<std::string>::const_iterator it;
+    
+  for ( it = sorting.begin(); it != sorting.end(); ++it )
   {
     files->Add(new TObjString(filemap[*it].c_str()));
   }
-  
   return files;
 }
 
@@ -2449,7 +2836,7 @@ Bool_t AliAnalysisMuMu::SetCorrectionPerRun(const TGraph& corr, const char* form
 }
 
 //_____________________________________________________________________________
-void AliAnalysisMuMu::SetNofInputParticles(AliAnalysisMuMuResult& r)
+void AliAnalysisMuMu::SetNofInputParticles(AliAnalysisMuMuJpsiResult& r)
 {
   /// Set the "NofInput" variable(s) of one result
   
@@ -2599,11 +2986,18 @@ void AliAnalysisMuMu::Update()
 {
   /// update the current file with memory
  
+  if (!CC() || !MC()) return;
+  
   ReOpen(fFilename,"UPDATE");
 
-  MC()->Write("MC",TObject::kSingleKey);
+  if (MC())
+  {
+    MC()->Write("MC",TObject::kSingleKey|TObject::kOverwrite);
+  }
 
   ReOpen(fFilename,"READ");
+  
+  GetCollections(fFilename,fMergeableCollection,fCounterCollection,fBinning,fRunNumbers);
 }
 
 //_____________________________________________________________________________
@@ -2670,6 +3064,26 @@ Bool_t AliAnalysisMuMu::Upgrade()
   return kTRUE;
 }
 
+//_____________________________________________________________________________
+void AliAnalysisMuMu::ComputeFnorm()
+{
+  /// Compute the CMUL to CINT ratio(s)
+  
+  if (!CC()) return;
+  
+  MC()->Prune("/FNORM");
+  
+  AliAnalysisMuMuFnorm computer(*(CC()),AliAnalysisMuMuFnorm::kMUL,fgOCDBPath.Data(),fgIsCompactGraphs);
+  
+  computer.ComputeFnorm();
+
+  AliMergeableCollection* fnorm = computer.DetachMC();
+  
+  MC()->Attach(fnorm,"/FNORM/");
+  
+  Update();
+}
+
 //_____________________________________________________________________________
 AliAnalysisMuMuSpectra* AliAnalysisMuMu::CorrectSpectra(const char* type, const char* flavour)
 {
@@ -2750,22 +3164,22 @@ AliAnalysisMuMuSpectra* AliAnalysisMuMu::ComputeYield(const char* type, const ch
   TIter nextBin(bins);
   AliAnalysisMuMuBinning::Range* bin;
   Int_t i(0);
-  AliAnalysisMuMuResult* r;
+  AliAnalysisMuMuJpsiResult* r;
   
   while ( ( bin = static_cast<AliAnalysisMuMuBinning::Range*>(nextBin()) ) )
   {
-    r = static_cast<AliAnalysisMuMuResult*>(realSpectra->Bins()->At(i));
+    r = static_cast<AliAnalysisMuMuJpsiResult*>(realSpectra->BinContentArray()->At(i));
    
     StdoutToAliDebug(1,std::cout << "bin=";r->Print(););
     
-    AliAnalysisMuMuResult* rsim = static_cast<AliAnalysisMuMuResult*>(simSpectra->Bins()->At(i));
+    AliAnalysisMuMuJpsiResult* rsim = static_cast<AliAnalysisMuMuJpsiResult*>(simSpectra->BinContentArray()->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),
+    r->Set("Fnorm",nofCINT7/nofCINT7w0MUL,(nofCINT7/nofCINT7w0MUL)*AliAnalysisMuMuResult::ErrorAB( nofCINT7w0MUL, TMath::Sqrt(nofCINT7w0MUL),
                                                                                                 nofCINT7,TMath::Sqrt(nofCINT7)));
     
     Double_t yield =  r->GetValue("CorrNofJpsi") * mbeq;
@@ -2788,77 +3202,6 @@ AliAnalysisMuMuSpectra* AliAnalysisMuMu::ComputeYield(const char* type, const ch
   return realSpectra;
 }
 
-////_____________________________________________________________________________
-//AliAnalysisMuMuSpectra* AliAnalysisMuMu::ComputeYield(const char* realFile, const char* simFile,
-//                                                      const  char* type)
-//{
-//  const char* accEffSubResultName="COUNTJPSI-1";
-//
-//  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 )
-//  {
-//    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 = corrSpectra->Binning();
-//  TObjArray* bins = binning->CreateBinObjArray();
-//  TIter nextBin(bins);
-//  AliAnalysisMuMuBinning::Range* bin;
-//  Int_t i(0);
-//  AliAnalysisMuMuResult* r;
-//  
-//  while ( ( bin = static_cast<AliAnalysisMuMuBinning::Range*>(nextBin()) ) )
-//  {
-//    r = static_cast<AliAnalysisMuMuResult*>(corrSpectra->Bins()->At(i));
-//
-//    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("YJpsi",yield,yieldError);
-//        
-//    r->Set("NofInputJpsi",rsim->GetValue("NofInputJpsi",accEffSubResultName),rsim->GetErrorStat("NofInputJpsi",accEffSubResultName));
-//    r->Set("AccEffJpsi",rsim->GetValue("AccEffJpsi",accEffSubResultName),rsim->GetErrorStat("AccEffJpsi",accEffSubResultName));
-//    
-//    ++i;
-//  }
-//
-//  delete bins;
-//  
-//  return corrSpectra;
-//}
-
 //_____________________________________________________________________________
 AliAnalysisMuMuSpectra* AliAnalysisMuMu::RABy(const char* realFile, const char* simFile, const char* type,
                                                const char* direction)
@@ -2913,7 +3256,7 @@ AliAnalysisMuMuSpectra* AliAnalysisMuMu::RABy(const char* realFile, const char*
   TIter nextBin(bins);
   AliAnalysisMuMuBinning::Range* bin;
   Int_t i(0);
-  AliAnalysisMuMuResult* r;
+  AliAnalysisMuMuJpsiResult* r;
   
   Int_t n = bins->GetLast();
   
@@ -2959,16 +3302,16 @@ AliAnalysisMuMuSpectra* AliAnalysisMuMu::RABy(const char* realFile, const char*
     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());
+    r = static_cast<AliAnalysisMuMuJpsiResult*>(corrSpectra->BinContentArray()->At(i)->Clone());
 
-    AliAnalysisMuMuResult* rsim = static_cast<AliAnalysisMuMuResult*>(simSpectra->Bins()->At(i));
+    AliAnalysisMuMuJpsiResult* rsim = static_cast<AliAnalysisMuMuJpsiResult*>(simSpectra->BinContentArray()->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),
+    r->Set("Fnorm",nofCINT7/nofCINT7w0MUL,(nofCINT7/nofCINT7w0MUL)*AliAnalysisMuMuResult::ErrorAB( nofCINT7w0MUL, TMath::Sqrt(nofCINT7w0MUL),
                                                                       nofCINT7,TMath::Sqrt(nofCINT7)));
     
     Double_t yield =  r->GetValue("CorrNofJpsi") * mbeq;
@@ -3009,7 +3352,7 @@ AliAnalysisMuMuSpectra* AliAnalysisMuMu::RABy(const char* realFile, const char*
       j = n-i;
     }
     
-    r = static_cast<AliAnalysisMuMuResult*>(finalResults.At(j));
+    r = static_cast<AliAnalysisMuMuJpsiResult*>(finalResults.At(j));
 
     bin = static_cast<AliAnalysisMuMuBinning::Range*>(finalBins.At(j));
     
@@ -3023,7 +3366,141 @@ AliAnalysisMuMuSpectra* AliAnalysisMuMu::RABy(const char* realFile, const char*
 }
 
 //_____________________________________________________________________________
-TGraph* AliAnalysisMuMu::ResultEvolution(const char* runlist, const char* period, const char* what, Bool_t forceRecomputation)
+void AliAnalysisMuMu::ComputeJpsi(const char* runlist, const char* prefix, const char* what, const char* binningFlavour)
+{
+  /// Call the Jpsi method for each file
+  
+  std::vector<int> runs;
+  AliAnalysisTriggerScalers::ReadIntegers(runlist,runs);
+  
+  for ( std::vector<int>::size_type i = 0; i < runs.size(); ++i )
+  {
+    Int_t runNumber = runs[i];
+    
+    TString filename(Form("RUNBYRUN/%s_%09d.saf.root",prefix,runNumber));
+    
+    if ( gSystem->AccessPathName(filename.Data())==kTRUE ) continue;
+    
+    AliAnalysisMuMu m(filename.Data());
+    m.Jpsi(what,binningFlavour);
+  }
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuSpectra*
+AliAnalysisMuMu::CombineSpectra(const char* runlist,
+                                const char* realPrefix,
+                                const char* simPrefix,
+                                const char* quantity,
+                                const char* variable,
+                                const char* binningFlavour)
+{
+  std::vector<int> runs;
+  AliAnalysisTriggerScalers::ReadIntegers(runlist,runs);
+
+  std::vector<double> vw;
+  std::vector<AliAnalysisMuMuSpectra*> vspectra;
+  
+  for ( std::vector<int>::size_type i = 0; i < runs.size(); ++i )
+  {
+    Int_t runNumber = runs[i];
+
+    TString filename(Form("RUNBYRUN/%s_%09d.saf.root",realPrefix,runNumber));
+  
+    AliAnalysisMuMu mreal(filename.Data());
+
+    std::cout << filename.Data() << std::flush << std::endl;
+    
+    if ( !mreal.CC() || !mreal.MC() )
+    {
+      AliErrorClass(Form("Have to skip %s CC=%p MC=%p",filename.Data(),mreal.CC(),mreal.MC()));
+      continue;
+    }
+
+    TGraph* g = static_cast<TGraph*>(mreal.MC()->GetObject("/FNORM/GRAPHS/NMBeqBest2"));
+      
+    if (!g)
+    {
+      mreal.ComputeFnorm();
+      g  = static_cast<TGraph*>(mreal.MC()->GetObject("/FNORM/GRAPHS/NMBeqBest2"));
+    }
+
+    if (!g) continue;
+    
+    if ( TMath::Nint(g->GetX()[0]) != runNumber )
+    {
+      AliErrorClass("Wrong run number in NMBeqBest2 graph !");
+      continue;
+    }
+    
+    filename.Form("RUNBYRUN/%s_%09d.saf.root",simPrefix,runNumber);
+
+    AliAnalysisMuMu msim(filename.Data());
+
+    TString spectraName(Form("/ALL/CMULLO-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-%s",variable));
+    if (strlen(binningFlavour))
+    {
+      spectraName += "-";
+      spectraName += binningFlavour;
+    }
+    
+    AliAnalysisMuMuSpectra* s = static_cast<AliAnalysisMuMuSpectra*>(msim.MC()->GetObject(spectraName.Data()));
+    
+    if (!s)
+    {
+      msim.Jpsi(quantity,binningFlavour);
+
+      s = static_cast<AliAnalysisMuMuSpectra*>(msim.MC()->GetObject(spectraName.Data()));
+    }
+    
+    if (!s)
+    {
+      AliErrorClass(Form("Could not find spectra for sim %s",filename.Data()));
+      continue;
+    }
+    
+    vw.push_back(g->GetY()[0]);
+    vspectra.push_back(static_cast<AliAnalysisMuMuSpectra*>(s->Clone()));
+  }
+  
+  Double_t sumw(0.0);
+  
+  for ( std::vector<int>::size_type i = 0; i < vw.size(); ++i )
+  {
+    sumw += vw[i];
+    vspectra[i]->Print();
+  }
+  
+  // normalize the weights
+  TList list;
+  list.SetOwner(kTRUE);
+  
+  for ( std::vector<int>::size_type i = 0; i < vw.size(); ++i )
+  {
+    vw[i] /= sumw;
+    
+    vspectra[i]->SetWeight(vw[i]);
+
+    if ( i > 0 ) list.Add(vspectra[i]);
+  }
+
+  std::cout << "before merging" << std::endl;
+  for ( std::vector<int>::size_type i = 0; i < vw.size(); ++i )
+  {
+    std::cout << " ---------------- " << i << std::endl;
+    
+    vspectra[i]->Print();
+  }
+
+  vspectra[0]->Merge(&list);
+  
+
+  return vspectra[0];
+}
+
+
+//_____________________________________________________________________________
+TGraph* AliAnalysisMuMu::ResultEvolution(const char* runlist, const char* realPrefix, const char* simPrefix, const char* what, Bool_t forceRecomputation)
 {
   std::vector<int> runs;
   AliAnalysisTriggerScalers::ReadIntegers(runlist,runs);
@@ -3031,104 +3508,139 @@ TGraph* AliAnalysisMuMu::ResultEvolution(const char* runlist, const char* period
   TGraphErrors* g = new TGraphErrors(runs.size());
   
   TString direction("Pbp");
+  TString check(realPrefix);
+  check.ToUpper();
   
-  if (TString(period) == "LHC13b" ||
-    TString(period) == "LHC13c" ||
-      TString(period) == "LHC13d" ||
-      TString(period) == "LHC13e"
+  if (check.Contains("LHC13B") ||
+    check.Contains("LHC13C") ||
+      check.Contains("LHC13D") ||
+      check.Contains("LHC13E")
       )
   {
     direction = "pPb";
   }
   
-  AliInfoClass(Form("period %s direction %s",period,direction.Data()));
+  AliInfoClass(Form("direction %s",direction.Data()));
   
-  Double_t weightedMean(0.0);
-  Double_t sumOfWeights(0.0);
-
   Double_t mean(0.0);
+  Double_t v1(0.0);
+  
   TString subResultName("");
+  
   TString swhat(what);
-    
+  
+  TObjArray* parts = swhat.Tokenize(":");
+  
+  if ( parts->GetEntries() > 1 )
+  {
+    subResultName = static_cast<TObjString*>(parts->At(1))->String();
+  }
+
+  delete parts;
+  
   for ( std::vector<int>::size_type i = 0; i < runs.size(); ++i )
   {
     Int_t runNumber = runs[i];
     
-    AliInfoClass(Form("RUN %09d",runNumber));
+    AliDebugClass(1,Form("RUN %09d",runNumber));
     
-    TString realFile(Form("RUNBYRUN/%s_muon_calo_AODMUON000_%09d.saf.root",period,runNumber));
+    TString realFile(Form("RUNBYRUN/%s_%09d.saf.root",realPrefix,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 simFileName(Form("RUNBYRUN/%s_%09d.saf.root",simPrefix,runNumber));
+        
     TString simFile(simFileName);
 
     TString resultName(Form("%s%sJpsi",what,direction.Data()));
     
-    if ( swhat == "MBR")
+    if ( swhat == "Fnorm")
     {
-      resultName = "MBR";
+      resultName = "Fnorm";
     }
     else if ( swhat.Contains("Acc") )
     {
       resultName.ReplaceAll(direction,"");
     }
     
-    AliAnalysisMuMu mreal(realFile);
+    AliAnalysisMuMu* mreal(0x0);
     
-    AliAnalysisMuMuSpectra* real = static_cast<AliAnalysisMuMuSpectra*>(mreal.MC()->GetObject("/PSALL/CMUL7-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-"));
-
-    if (!real || forceRecomputation)
+    if ( !swhat.Contains("Acc"))
+    {
+        mreal = new AliAnalysisMuMu(realFile);      
+    }
+    
+    AliAnalysisMuMuSpectra* real(0x0);
+    
+    if ( mreal )
     {
-      mreal.Jpsi();
-      real = static_cast<AliAnalysisMuMuSpectra*>(mreal.MC()->GetObject("/PSALL/CMUL7-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-"));
-      if (!real)
+      real = static_cast<AliAnalysisMuMuSpectra*>(mreal->MC()->GetObject("/PSALL/CMUL7-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-INTEGRATED"));
+
+      if (!real || forceRecomputation)
       {
-        AliErrorClass(Form("Could not get real spectra for run %d",runNumber));
-        return 0x0;
+        mreal->Jpsi();
+        real = static_cast<AliAnalysisMuMuSpectra*>(mreal->MC()->GetObject("/PSALL/CMUL7-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-INTEGRATED"));
+        if (!real)
+        {
+          AliErrorClass(Form("Could not get real spectra for run %d",runNumber));
+          delete mreal;
+          return 0x0;
+        }
       }
     }
     
     AliAnalysisMuMu msim(simFile);
     
-    AliAnalysisMuMuSpectra* sim = static_cast<AliAnalysisMuMuSpectra*>(msim.MC()->GetObject("/ALL/CMULLO-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-"));
+    AliAnalysisMuMuSpectra* sim = static_cast<AliAnalysisMuMuSpectra*>(msim.MC()->GetObject("/ALL/CMULLO-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-INTEGRATED"));
 
     if (!sim || forceRecomputation)
     {
       msim.SetEventSelectionList("ALL");
       msim.Jpsi();
-      sim = static_cast<AliAnalysisMuMuSpectra*>(msim.MC()->GetObject("/ALL/CMULLO-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-"));
+      sim = static_cast<AliAnalysisMuMuSpectra*>(msim.MC()->GetObject("/ALL/CMULLO-B-NOPF-MUON/PP/pMATCHLOWRABSBOTH/PSI-INTEGRATED"));
       if (!sim)
       {
         AliErrorClass(Form("Could not get sim spectra for run %d",runNumber));
+        delete mreal;
         return 0x0;
       }
     }
     
-    AliAnalysisMuMuSpectra* corrected = AliAnalysisMuMu::RABy(realFile.Data(),simFile.Data(),"",direction.Data());
+    AliAnalysisMuMuSpectra* corrected = 0x0;
+    
+    if ( real )
+    {
+        corrected = AliAnalysisMuMu::RABy(realFile.Data(),simFile.Data(),"",direction.Data());
+    }
+    else
+    {
+      corrected = sim;
+    }
 
-    AliAnalysisMuMuResult* result = static_cast<AliAnalysisMuMuResult*>(corrected->Bins()->First());
+    AliAnalysisMuMuResult* result = static_cast<AliAnalysisMuMuResult*>(corrected->BinContentArray()->First());
 
-    result->Print();
+//    result->Print();
 
-    Double_t value = result->GetValue(resultName.Data());
-    Double_t error = result->GetErrorStat(resultName.Data());
+    Double_t value = result->GetValue(resultName.Data(),subResultName.Data());
+    Double_t error = result->GetErrorStat(resultName.Data(),subResultName.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));
+    Double_t n = 1.0;
     
-    weightedMean += n*result->GetValue(resultName.Data());
-    sumOfWeights += n;
+    if ( mreal )
+    {
+      n = mreal->CC()->GetSum(Form("trigger:CMUL7-B-NOPF-MUON/event:PSALL/run:%d",runNumber));
+    }
+
+    Double_t w(0.0);
+    if ( error > 0 ) w = 1.0/error/error;
     
-    mean += result->GetValue(resultName.Data());
+    mean += value*w;
+    v1 += w;
     
 //    std::cout << result->SubResults() << " " << result->GetError(resultName.Data()) << std::endl;
 
+    delete mreal;
   }
   
   gStyle->SetOptFit(1);
@@ -3149,91 +3661,20 @@ TGraph* AliAnalysisMuMu::ResultEvolution(const char* runlist, const char* period
   {
     g->GetYaxis()->SetTitle("Acc#timesEff_{J/#psi}");    
   }
-  else if ( TString(what).Contains("MBR") )
+  else if ( TString(what).Contains("Fnorm") )
   {
     g->GetYaxis()->SetTitle("CINT7 / CINT7&0MUL");
   }
   
   if (CompactGraphs())
   {
-    Compact(*g);
+    AliAnalysisMuMuGraphUtil::Compact(*g);
   }
   
-  mean /= runs.size();
-  weightedMean /= sumOfWeights;
-  
-  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 )
-  {
-    ULong64_t a = TMath::Nint(fCounterCollection->GetSum(Form("trigger:CINT7-B-NOPF-ALLNOTRD/event:%s/run:%d",
-                                                  eventSelection,runNumber)));
-    
-    ULong64_t b = TMath::Nint(fCounterCollection->GetSum(Form("trigger:CINT7-B-NOPF-ALLNOTRD&0MUL/event:%s/run:%d",
-                                                  eventSelection,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;
-  
-  TObjArray* runs = fCounterCollection->GetKeyWords("run").Tokenize(",");
-  runs->Sort();
-  TIter nextRun(runs);
-  TObjString* srun;
-  
-  std::set<int> runnumbers;
-  
-  TGraphErrors* g = new TGraphErrors(runs->GetEntries());
-  Int_t i(0);
-  
-  while ( ( srun = static_cast<TObjString*>(nextRun()) ) )
-  {
-    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;
-  }
+  mean /= v1;
   
-  g->GetXaxis()->SetNoExponent();
+  AliInfoClass(Form("Weighted Mean %e",mean));
   
-  AliAnalysisTriggerScalers ts(RunNumbers(),fgOCDBPath.Data());
-  ts.DrawFills(0,1000);
-
   return g;
 }
 
-
-
-
index b14cf7a72ade533b0b4255bf7474e4b75ee5bd8e..5615e43fd02d957d4d49b54d865912d7bd3bce3a 100644 (file)
 #include "RQ_OBJECT.h"
 
 class AliAnalysisMuMuResult;
+class AliAnalysisMuMuJpsiResult;
 class AliAnalysisMuMuSpectra;
 class AliCounterCollection;
 class AliMergeableCollection;
 class TF1;
 class TFile;
 class TGraph;
+class TGraphErrors;
 class TH1;
 class TMap;
 
@@ -85,8 +87,16 @@ public:
 
   AliAnalysisMuMuSpectra* CorrectSpectra(const char* type, const char* flavour="");
 
-  AliAnalysisMuMuSpectra* ComputeYield(const char* type, const char* flavour="");
+  void ComputeFnorm();
+
+  void TwikiOutputFnorm(const char* series="FnormOffline2PUPS,FnormScalersPUPS,FnormBest2,RelDifFnormScalersPUPSvsFnormOffline2PUPS") const;
+
+  static void FigureOutputFnorm(const char* filelist);
   
+  static void LatexOutputFnorm(const char* filelist, const char* subresultnames="FnormOffline2PUPS,FnormScalersPUPS,FnormBest2,RelDifFnormScalersPUPSvsFnormOffline2PUPS", Bool_t rms=kFALSE);
+  
+  AliAnalysisMuMuSpectra* ComputeYield(const char* type, const char* flavour="");
+
   void CleanAllSpectra();
   
   ///------
@@ -97,9 +107,20 @@ public:
 
   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",
+  static TGraph* ResultEvolution(const char* runlist,
+                                 const char* realPrefix="LHC13f_muon_calo_AODMUON127",
+                                 const char* simPrefix="SIM_JPSI_LHC13f_CynthiaTuneWithRejectList",
+                                 const char* what="Y",
                                  Bool_t forceRecomputation=kFALSE);
   
+  static void ComputeJpsi(const char* runlist, const char* prefix="SIM_JPSI_LHC13f_CynthiaTuneWithRejectList", const char* what="integrated", const char* binningFlavour="");
+  
+  static AliAnalysisMuMuSpectra* CombineSpectra(const char* runlist,
+                                                const char* realPrefix="LHC13f_muon_calo_AODMUON127",
+                                                const char* simPrefix="SIM_JPSI_LHC13f_CynthiaTuneWithRejectList",
+                                                const char* quantity="AccEff",
+                                                const char* variable="INTEGRATED",
+                                                const char* binningFlavour="");
   ///-------
   
   TGraph* PlotEventSelectionEvolution(const char* trigger1="CINT7-B-NOPF-MUON", const char* event1="PSALL",
@@ -189,14 +210,8 @@ public:
   
   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;
-
-  TGraph* MBREvolution(const char* eventSelection1="PSALLNOTZEROPILEUP", const char* eventSelection2="PSALL") const;
-
   const std::set<int>& RunNumbers() const { return fRunNumbers; }
   
   void DrawMinv(const char* type,
@@ -234,7 +249,7 @@ private:
   
 private:
 
-  void SetNofInputParticles(AliAnalysisMuMuResult& r);
+  void SetNofInputParticles(AliAnalysisMuMuJpsiResult& r);
 
   static TString ExpandPathName(const char* file);
   
diff --git a/PWG/muondep/AliAnalysisMuMuFnorm.cxx b/PWG/muondep/AliAnalysisMuMuFnorm.cxx
new file mode 100644 (file)
index 0000000..03b459a
--- /dev/null
@@ -0,0 +1,1849 @@
+/**************************************************************************
+ * 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.                  *
+ **************************************************************************/
+
+///
+/// AliAnalysisMuMuFnorm : class to encapsulate computation(s)
+/// of the normalisation factor used to get the equivalent
+/// number of MB events from the number of CMUL triggers
+///
+/// The computed objects are stored within a AliMergeableCollection
+/// with 3 subdirectories, dependinf on their type
+///
+/// /GRAPHS/
+/// /RESULTS/
+/// /HISTOS/
+///
+/// author: Laurent Aphecetche (Subatech)
+
+#include "AliAnalysisMuMuFnorm.h"
+
+#include "AliAnalysisMuMuGraphUtil.h"
+#include "AliAnalysisMuMuResult.h"
+#include "AliAnalysisTriggerScalers.h"
+#include "AliCounterCollection.h"
+#include "AliLog.h"
+#include "AliMergeableCollection.h"
+#include "Riostream.h"
+#include "TAxis.h"
+#include "TCanvas.h"
+#include "TGraphErrors.h"
+#include "TH1F.h"
+#include "TList.h"
+#include "TMap.h"
+#include "TMath.h"
+#include "TObjArray.h"
+#include "TObjString.h"
+#include "TPaveText.h"
+#include "TStyle.h"
+#include <cassert>
+#include <numeric>
+
+ClassImp(AliAnalysisMuMuFnorm)
+
+//_____________________________________________________________________________
+AliAnalysisMuMuFnorm::AliAnalysisMuMuFnorm(AliCounterCollection& cc,
+                                           AliAnalysisMuMuFnorm::ETriggerType refTriggerType,
+                                           const char* ocdbpath,
+                                           Bool_t compactGraphs) :
+TObject(),
+fCounterCollection(cc),
+fMergeableCollection(0x0),
+fIsOwner(kTRUE),
+fOCDBPath(ocdbpath),
+fIsCompactGraphs(compactGraphs),
+fReferenceTriggerType(refTriggerType)
+{
+  // ctor
+  
+  
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuFnorm::~AliAnalysisMuMuFnorm()
+{
+  // dtor
+  if ( fIsOwner )
+  {
+    delete fMergeableCollection;
+  }
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::ComputeFnorm()
+{
+  /// Compute the CMUL to CINT ratio(s)
+  ///
+  /// Using offline method
+  ///   - in one go CINT/CMUL
+  ///   - in two steps CINT/CMSL and CMSL/CMUL
+  ///
+  /// Using scaler method
+  ///   - bare scaler values
+  ///   - scaler values corrected for pile-up
+  ///   - scaler values corrected for pile-up and physics selection
+
+  const ETriggerType triggerTypes[] = { kMB, kMUL, kMSL, kMSH };
+  const Bool_t trueFalse[] = { kTRUE, kFALSE };
+  
+  for ( Int_t i = 0; i < 4; ++i )
+  {
+    for ( Int_t pileup = 0; pileup < 2; ++pileup )
+    {
+      for ( Int_t ps = 0; ps < 2; ++ps )
+      {
+        ComputeNofEvents(triggerTypes[i],trueFalse[pileup],ps);
+      }
+    }
+  }
+
+  ComputeFnormOffline(1,kFALSE,0);
+  ComputeFnormOffline(1,kFALSE,1);
+  ComputeFnormOffline(1,kTRUE,1);
+  
+  ComputeFnormOffline(2,kFALSE,0);
+  ComputeFnormOffline(2,kFALSE,1);
+  ComputeFnormOffline(2,kTRUE,1);
+
+//  ComputeFnormOffline(2,kFALSE,2);
+//  ComputeFnormOffline(2,kTRUE,2);
+
+  ComputeFnormScalers(kFALSE,0);
+  ComputeFnormScalers(kTRUE,0);
+  ComputeFnormScalers(kTRUE,1);
+//  ComputeFnormScalers(kTRUE,2);
+
+  WeightedMeanGraphs("Offline");
+  WeightedMeanGraphs("Scalers");
+  WeightedMeanGraphs("FnormOffline2PUPS,FnormOffline1PUPS","FnormOffline12PUPS");
+  
+  WeightedMeanGraphs("FnormOffline2PUPS,FnormScalersPUPS","FnormBest2");
+  
+  ComputeGraphRelDif("FnormOffline2PUPS","FnormScalersPUPS");
+
+  ComputeGraphRelDif("FnormOffline2PUPS","FnormOffline2");
+  ComputeGraphRelDif("FnormOffline2PUPS","FnormOffline2PS");
+  
+  ComputeGraphRelDif("CorrectionPSMB","CorrectionPSMUL");
+
+//  for ( Int_t i = 0; i < 4; ++i )
+///  {
+    TString triggerEvents;
+    
+//  triggerEvents.Form("NofEvent%sPUPS",GetTriggerTypeName(triggerTypes[i]).Data());
+  triggerEvents.Form("NofEvent%sPUPS",GetTriggerTypeName(fReferenceTriggerType).Data());
+  
+  MultiplyGraphs(triggerEvents.Data(),"FnormBest2","NMBeqBest2");
+  
+    MultiplyGraphs(triggerEvents.Data(),"FnormOffline2PUPS","NMBeqOffline2PUPS");
+  MultiplyGraphs(triggerEvents.Data(),"FnormScalersPUPS","NMBeqScalersPUPS");
+//  }
+
+//  MultiplyGraphs(Form("NofEvent%sPUTS",GetTriggerTypeName(fReferenceTriggerType).Data()),"FnormOffline2PUTS","NMBeqOffline2PUTS");
+//  MultiplyGraphs(Form("NofEvent%sPUTS",GetTriggerTypeName(fReferenceTriggerType).Data()),"FnormOffline2TS","NMBeqOffline2TS");
+
+  ComputeResultsFromGraphs();
+  
+  AliAnalysisMuMuResult* result = GetResult("Fnorm");
+  if (result)
+  {
+    result->Exclude("*");
+    result->Include("FnormBest2");
+  }
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::ComputeCorrectionFactors(Int_t eventSelectionCorrected)
+{
+  /// Compute individual graphs for the correction factors (PS_CMUL, PS_CINT,
+  /// F_pile-up,PS_CINT/PS_CMUL) used in the computation of (some) Fnorm factors
+  ///
+
+  TString graphName(Form("CorrectionGlobal%s",GetEventSelectionName(eventSelectionCorrected).Data()));;
+
+  if ( GetGraph(graphName) )
+  {
+    // insure we compute it only once
+    return;
+  }
+  
+  AliDebug(2,"");
+  
+  std::vector<double> vx;
+  std::vector<double> vxerr;
+  std::vector<double> vy;
+  std::vector<double> vyerr;
+
+  std::vector<double> vyGlobal;
+  std::vector<double> vyGlobalErr;
+
+  const ETriggerType triggerTypes[] = { kMB, kMUL, kMSL, kMSH };
+  
+  for ( Int_t i = 0; i < 4; ++i )
+  {
+    ComputeEventSelectionGraph(triggerTypes[i],eventSelectionCorrected);
+    ComputePileUpGraph(triggerTypes[i],eventSelectionCorrected);
+  }
+  
+  TGraphErrors* gPSCINT = GetGraph(Form("Correction%s%s",GetEventSelectionName(eventSelectionCorrected).Data(),GetTriggerTypeName(AliAnalysisMuMuFnorm::kMB).Data()));
+                                   
+  TGraphErrors* gPSCMUL = GetGraph(Form("Correction%s%s", GetEventSelectionName(eventSelectionCorrected).Data(), GetTriggerTypeName(AliAnalysisMuMuFnorm::kMUL).Data()));
+                                   
+  TGraphErrors* gPU = GetGraph(Form("CorrectionPU%s%s",GetEventSelectionName(eventSelectionCorrected).Data(), GetTriggerTypeName(AliAnalysisMuMuFnorm::kMB).Data()));
+  
+  if ( !gPSCINT || !gPSCMUL || !gPU )
+  {
+    AliError("Did not get the relevant graphs. Cannot work");
+    return;
+  }
+  
+  for ( Int_t i = 0; i < gPSCINT->GetN(); ++i )
+  {
+    Double_t x,y,yerr,yGlobal,yGlobalErr;
+    
+    gPSCINT->GetPoint(i,x,y);
+    
+    if ( fIsCompactGraphs )
+    {
+      x = TString(gPSCINT->GetXaxis()->GetBinLabel(i)).Atoi();
+    }
+    
+    yGlobal = gPSCINT->GetY()[i] * gPU->GetY()[i] / gPSCMUL->GetY()[i];
+    
+    yGlobalErr = yGlobal*AliAnalysisMuMuResult::ErrorABC(gPSCINT->GetY()[i],gPSCINT->GetEY()[i],
+                                                         gPSCMUL->GetY()[i],gPSCMUL->GetEY()[i],
+                                                         gPU->GetY()[i],gPU->GetEY()[i]);
+    
+    y = gPSCINT->GetY()[i] / gPSCMUL->GetY()[i];
+    yerr = y * AliAnalysisMuMuResult::ErrorAB(gPSCINT->GetY()[i],gPSCINT->GetEY()[i],
+                                              gPSCMUL->GetY()[i],gPSCMUL->GetEY()[i]);
+
+    vx.push_back(x);
+    vxerr.push_back(gPSCINT->GetEX()[i]);
+
+    vyGlobal.push_back(yGlobal);
+    vyGlobalErr.push_back(yGlobalErr);
+    
+    vy.push_back(y);
+    vyerr.push_back(yerr);
+  }
+  
+  TString name(Form("Correction%sRatio",GetEventSelectionName(eventSelectionCorrected).Data()));
+  TString title(Form("%s_MB/%s_%s",GetEventSelectionName(eventSelectionCorrected).Data(),GetTriggerTypeName(fReferenceTriggerType).Data(),
+                     GetEventSelectionName(eventSelectionCorrected).Data()));
+  
+  CreateAndAddGraph(name,title,vx,vxerr,vy,vyerr);
+  
+  title = TString::Format("%s_MB x Fpile-up / %s_%s ",GetEventSelectionName(eventSelectionCorrected).Data(),GetTriggerTypeName(fReferenceTriggerType).Data(),GetEventSelectionName(eventSelectionCorrected).Data());
+  
+  CreateAndAddGraph(graphName,title,vx,vxerr,vyGlobal,vyGlobalErr);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::ComputeFnormOffline(Int_t nstep, Bool_t pileUpCorrected, Int_t eventSelectionCorrected)
+{
+  /// Compute MB to CMUL ratio using offline method, either in 1 or 2 steps
+  
+  TString name("FnormOffline");
+  TString title("Computed using offline information");
+  
+  if (nstep==1)
+  {
+    name += "1";
+    title += " in one step (CINT/CINT&0MUL)";
+  }
+  else
+  {
+    name += "2";
+    title += " in two steps (CMSL/CMSL&0MUL x CINT/CINT&MSL)";
+  }
+  
+  if (pileUpCorrected)
+  {
+    name += "PU";
+    title += " with pile-up correction";
+  }
+  if (eventSelectionCorrected==1)
+  {
+    name += "PS";
+    title += " with (ps) purity corrections";
+  }
+  else if ( eventSelectionCorrected==2 )
+  {
+    name += "TS";
+    title += " with (ts) purity corrections";
+  }
+
+  if ( GetGraph(name) )
+  {
+    // insure we're computing it only once
+    return;
+  }
+  
+  AliDebug(2,name);
+  
+  std::vector<double> vx;
+  std::vector<double> vxerr;
+  std::vector<double> vy;
+  std::vector<double> vyerr;
+
+  const std::set<int>& runs = RunNumbers();
+  
+  for ( std::set<int>::const_iterator it = runs.begin(); it != runs.end(); ++it )
+  {
+    Int_t runNumber = *it;
+    
+    TString mbTrigger = GetTriggerClassName(kMB,runNumber);
+    TString muonTrigger = GetTriggerClassName(kMSL,runNumber);
+    TString dimuonTrigger = GetTriggerClassName(kMUL,runNumber);
+    
+    if (!mbTrigger.Length())
+    {
+      AliError(Form("Cannot get MB trigger for run %d",runNumber));
+      continue;
+    }
+    
+    Double_t nofMB = GetSum(mbTrigger.Data(),runNumber,eventSelectionCorrected);
+    Double_t nofMSL(0.0);
+    Double_t nofMSLw0MUL(0.0);
+    
+    if ( nstep==2 )
+    {
+      nofMSL = GetSum(muonTrigger.Data(),runNumber,eventSelectionCorrected);
+      nofMSLw0MUL = GetSum(Form("%s&0MUL",muonTrigger.Data()),runNumber,eventSelectionCorrected);
+    }
+    
+    Double_t nofMBw0MUL = GetSum(Form("%s&0MUL",mbTrigger.Data()),runNumber,eventSelectionCorrected);
+    Double_t nofMBw0MSL = GetSum(Form("%s&0MSL",mbTrigger.Data()),runNumber,eventSelectionCorrected);
+    
+    if ( !nofMBw0MUL ) continue;
+    if ( !nofMBw0MSL && nstep == 2 ) continue;
+    
+    Double_t purityMB(1.0);
+    Double_t purityMBerror(0.0);
+
+    if ( eventSelectionCorrected > 0 )
+    {
+      ComputeEventSelectionGraph(kMB,eventSelectionCorrected);
+      
+      TGraphErrors* gps = GetGraph(Form("Correction%s%s",GetEventSelectionName(eventSelectionCorrected).Data(),GetTriggerTypeName(kMB).Data()));
+      
+      GetValueAndErrorFromGraph(gps,runNumber,purityMB,purityMBerror);
+    }
+    
+    Double_t pileUpFactor(1.0);
+    Double_t pileUpFactorError(0.0);
+    
+    if (pileUpCorrected)
+    {      
+      ComputePileUpGraph(kMB,eventSelectionCorrected);
+      
+      TGraphErrors* gpu = GetGraph(Form("CorrectionPU%s%s",GetEventSelectionName(eventSelectionCorrected).Data(),GetTriggerTypeName(kMB).Data()));
+      
+      GetValueAndErrorFromGraph(gpu,runNumber,pileUpFactor,pileUpFactorError);
+
+      nofMB *= pileUpFactor;
+    }
+        
+    double value = nofMBw0MUL > 0.0 ? nofMB/nofMBw0MUL : 0.0;
+    double error = value*AliAnalysisMuMuResult::ErrorABC(nofMB,TMath::Sqrt(nofMB),
+                                                              nofMBw0MUL,TMath::Sqrt(nofMBw0MUL),
+                                                              pileUpFactor,pileUpFactorError);
+    
+    if ( nstep == 2 )
+    {
+      value = (nofMB/nofMSLw0MUL)*(nofMSL/nofMBw0MSL);
+      
+      if ( runNumber == 196310 )
+      {
+        AliDebug(1,Form("RUN %09d %d-%d-%d value=%e nofMB %e nofMSLw0MUL %e nofMSL %e nofMBw0MSL %e",
+                        runNumber,nstep,pileUpCorrected,eventSelectionCorrected,
+                        value,nofMB,nofMSLw0MUL,nofMSL,nofMBw0MSL));
+      }
+      
+      error = value*AliAnalysisMuMuResult::ErrorABCD(nofMB,TMath::Sqrt(nofMB),
+                                                          nofMSLw0MUL,TMath::Sqrt(nofMSLw0MUL),
+                                                          nofMSL,TMath::Sqrt(nofMSL),
+                                                          nofMBw0MSL,TMath::Sqrt(nofMBw0MSL));
+    }
+    
+    if ( value > 0.0 )
+    {
+      vx.push_back(1.0*runNumber);
+      vxerr.push_back(0.5);
+      vy.push_back(value);
+      vyerr.push_back(error);
+    }
+  }
+  
+    
+  CreateAndAddGraph(name,title,vx,vxerr,vy,vyerr);
+}
+
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::ComputeFnormScalers(Bool_t pileUpCorrected,
+                                               Int_t eventSelectionCorrected)
+{
+  /// Compute the MB to CMUL ratio using the scalers method (from OCDB)
+  ///
+  /// i.e. Fnorm = L0B(MB) x PS(MB) x Fpile-up / ( L0B(REF) x PS(REF) )
+  ///
+  /// where MB is the minbias trigger
+  /// REF is the fReferenceTrigger
+  /// and PS is the fraction of events selected by the physics selection
+  ///
+  /// The correction factor (the two PS and one Fpile-up) are
+  /// taken from graphs computed in other methods
+  ///
+  
+  TString name("FnormScalers");
+  TString title("Computed using OCDB scalers");
+  
+  if (pileUpCorrected)
+  {
+    name += "PU";
+    title += " with pile-up correction";
+  }
+  if (eventSelectionCorrected==1)
+  {
+    name += "PS";
+    title += " with (ps) purity corrections";
+  }
+  if (eventSelectionCorrected==2)
+  {
+    name += "TS";
+    title += " with (ts) purity corrections";
+  }
+  
+  if ( GetGraph(name) )
+  {
+    // insure we're computing it only once
+    return;
+  }
+  
+  AliDebug(2,name);
+  
+  // insure we have all the graphs we need to work
+  ComputeTriggerL0B(kMB);
+  ComputeTriggerL0B(fReferenceTriggerType);
+  
+  const std::set<int>& runs = RunNumbers();
+  
+  std::vector<double> vx;
+  std::vector<double> vxerr;
+  std::vector<double> vy;
+  std::vector<double> vyerr;
+  
+  Double_t purityREF(1.0);
+  Double_t purityMB(1.0);
+  Double_t purityREFerror(00);
+  Double_t purityMBerror(0.0);
+  
+  // compute the per run values
+  for ( std::set<int>::const_iterator it = runs.begin(); it != runs.end(); ++it )
+  {
+    Int_t runNumber = *it;
+    
+    TString mbTrigger = GetTriggerClassName(kMB,runNumber);
+    TString refTrigger = GetTriggerClassName(fReferenceTriggerType,runNumber);
+    
+    purityMB=purityREF=1.0;
+    purityMBerror=purityREFerror=0.0;
+    
+    if (eventSelectionCorrected>0)
+    {
+      ComputeEventSelectionGraph(kMB,eventSelectionCorrected);
+      ComputeEventSelectionGraph(fReferenceTriggerType,eventSelectionCorrected);
+      
+      TGraphErrors* gpsMB  = GetGraph(Form("Correction%s%s",GetEventSelectionName(eventSelectionCorrected).Data(),GetTriggerTypeName(kMB).Data()));
+      TGraphErrors* gpsREF = GetGraph(Form("Correction%s%s",GetEventSelectionName(eventSelectionCorrected).Data(),GetTriggerTypeName(fReferenceTriggerType).Data()));
+      
+      GetValueAndErrorFromGraph(gpsMB,runNumber,purityMB,purityMBerror);
+      GetValueAndErrorFromGraph(gpsREF,runNumber,purityREF,purityREFerror);
+    }
+    
+    if (purityMB<=0.0)
+    {
+      AliError(Form("Got purity=%e for MB for run %9d",purityMB,runNumber));
+      continue;
+    }
+    
+    TGraphErrors* gl0bMB = GetGraph(Form("L0B%s",GetTriggerTypeName(kMB).Data()));
+    TGraphErrors* gl0bREF = GetGraph(Form("L0B%s",GetTriggerTypeName(fReferenceTriggerType).Data()));
+    
+    Double_t L0bMB,L0bMBError;
+    Double_t L0bREF,L0bREFError;
+    
+    GetValueAndErrorFromGraph(gl0bMB,runNumber,L0bMB,L0bMBError);
+    GetValueAndErrorFromGraph(gl0bREF,runNumber,L0bREF,L0bREFError);
+    
+    Double_t pileUpFactor(1.0);
+    Double_t pileUpFactorError(0.0);
+    
+    if (pileUpCorrected)
+    {
+      TGraphErrors* gpu = GetGraph((Form("CorrectionPU%s%s",GetEventSelectionName(eventSelectionCorrected).Data(),GetTriggerTypeName(kMB).Data())));
+      
+      GetValueAndErrorFromGraph(gpu,runNumber,pileUpFactor,pileUpFactorError);
+    }
+    
+    Double_t value;
+    Double_t error;
+    
+    ScalerFnorm(value,error,
+                L0bREF,purityREF,purityREFerror,
+                L0bMB,purityMB,purityMBerror,
+                pileUpFactor,pileUpFactorError);
+    
+    if ( value > 0.0 )
+    {
+      vx.push_back(1.0*runNumber);
+      vxerr.push_back(0.5);
+      vy.push_back(value);
+      vyerr.push_back(error);
+    }
+  }
+  
+  CreateAndAddGraph(name,title,vx,vxerr,vy,vyerr);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::ComputeGraphRelDif(const char* a, const char* b) const
+{
+  // compute dispersion of b versus a
+  //
+  // computed differences graphs are put into the GRAPHS/ directory
+  // computed differences results are put into the HISTOS/ directory
+  
+  TString name(Form("RelDif%svs%s",b,a));
+  
+  if ( GetGraph(name) )
+  {
+    // insure we compute it only once
+    return;
+  }
+  
+  AliDebug(2,name);
+  
+  TGraphErrors* ga = static_cast<TGraphErrors*>(MC()->GetObject(Form("/GRAPHS/%s",a)));
+  TGraphErrors* gb = static_cast<TGraphErrors*>(MC()->GetObject(Form("/GRAPHS/%s",b)));
+  
+  if (!ga)
+  {
+    AliError(Form("Cannot get graph for %s",a));
+    return;
+  }
+  
+  if (!gb)
+  {
+    AliError(Form("Cannot get graph for %s",b));
+    return;
+  }
+  
+  if ( ga->GetN() != gb->GetN() )
+  {
+    AliError(Form("Cannot work with different number of points in the graphs : %d vs %d",
+                  ga->GetN(),gb->GetN()));
+    return;
+  }
+  
+  TString title(Form("%s-%s (RelDif,%%)",b,a));
+  
+  std::vector<double> vx;
+  std::vector<double> vxerr;
+  std::vector<double> vy;
+  std::vector<double> vyerr;
+  
+  for ( Int_t i = 0; i < ga->GetN(); ++i )
+  {
+    Double_t xa,xb,ya,yb;
+    
+    ga->GetPoint(i,xa,ya);
+    gb->GetPoint(i,xb,yb);
+    
+    if ( xa != xb )
+    {
+      AliError(Form("Incompatible graphs : got xa=%e and xb=%e",xa,xb));
+      return;
+    }
+  
+    Double_t newvalue = 0.0;
+    
+    if ( TMath::Abs(xa) > 1E-12 )
+    {
+      newvalue = 100.0*( yb - ya ) / ya;
+    }
+
+    Double_t yerr = newvalue*AliAnalysisMuMuResult::ErrorAB(ya,ga->GetEY()[i],
+                                                            yb,gb->GetEY()[i]);
+
+    if ( fIsCompactGraphs )
+    {
+      xa = TString(ga->GetXaxis()->GetBinLabel(i+1)).Atoi()*1.0;
+    }
+
+    vx.push_back(xa);
+    vxerr.push_back(0.5);
+    vy.push_back(newvalue);
+    vyerr.push_back(yerr);
+    
+  }
+  
+  CreateAndAddGraph(name,title,vx,vxerr,vy,vyerr);
+
+  // FIXME : fill here an histogram from the graph to get the
+  // weight of 1/e2 ?
+  //  h->Fill(newvalue,1.0/(yerr*yerr));
+  //  MC()->Adopt("/HISTOS/",h);
+  
+  //  AliAnalysisMuMuResult* r = GetRunIntegratedResult(*g,"FnormDispersion");
+  //  if (r)
+  //  {
+  //    if (!dispersion)
+  //    {
+  //      dispersion = new AliAnalysisMuMuResult("FnormDispersion");
+  //    }
+  //    dispersion->AdoptSubResult(r);
+  //    if ( !TString(g->GetName()).BeginsWith("Fnorm") )
+  //    {
+  //      dispersion->Exclude(r->Alias());
+  //    }
+  //  }
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::ComputePileUpGraph(ETriggerType tt, Int_t eventSelectionCorrected)
+{
+  /// Compute the per-run graph of pile-up factor
+  
+  TString graphName(Form("CorrectionPU%s%s",GetEventSelectionName(eventSelectionCorrected).Data(),GetTriggerTypeName(tt).Data()));
+  
+  if ( GetGraph(graphName) )
+  {
+    // insure we're computing it only once
+    return;
+  }
+  
+  AliDebug(2,graphName);
+  
+  std::vector<double> vx;
+  std::vector<double> vxerr;
+  std::vector<double> vy;
+  std::vector<double> vyerr;
+  
+  const std::set<int>& runs = RunNumbers();
+  
+  AliAnalysisTriggerScalers ts(runs,OCDBPath().Data());
+  
+  for ( std::set<int>::const_iterator it = runs.begin(); it != runs.end(); ++it )
+  {
+    Int_t runNumber = *it;
+    
+    Double_t pileUpFactor(1.0);
+    Double_t pileUpFactorError(0.0);
+    Double_t purity(1.0);
+    Double_t purityError(0.0);
+    
+    TString triggerClassName = GetTriggerClassName(tt,runNumber);
+    
+    if ( triggerClassName.Length()==0 )
+    {
+      AliError(Form("Unknown trigger type %d",tt));
+      return;
+    }
+    
+    if (eventSelectionCorrected)
+    {
+      GetPurity(triggerClassName.Data(),runNumber,purity,purityError,eventSelectionCorrected);
+    }
+    ts.GetPileUpFactor(runNumber,triggerClassName.Data(),purity,pileUpFactor,pileUpFactorError);
+   
+    vx.push_back(runNumber);
+    vxerr.push_back(0.5);
+    vy.push_back(pileUpFactor);
+    vyerr.push_back(pileUpFactorError);
+  }
+  
+  TString title(Form("Pile-up correction factor for trigger %s",GetTriggerTypeName(tt).Data()));
+  
+  if (eventSelectionCorrected)
+  {
+    title += "( L0BRate corrected by event selection";
+    title += GetEventSelectionName(eventSelectionCorrected);
+    title += " accept fraction)";
+  }
+  
+  CreateAndAddGraph(graphName,title,vx,vxerr,vy,vyerr);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::ComputeEventSelectionGraph(ETriggerType tt, Int_t eventSelectionCorrected)
+{
+  /// Compute the per-run graph of physics selection accept fraction
+  /// for the given trigger
+  
+  TString graphName(Form("Correction%s%s",GetEventSelectionName(eventSelectionCorrected).Data(), GetTriggerTypeName(tt).Data()));
+  
+  if (GetGraph(graphName))
+  {
+    // insure we're computing it only once
+    return;
+  }
+
+  AliDebug(2,graphName);
+  
+  std::vector<double> vx;
+  std::vector<double> vxerr;
+  std::vector<double> vy;
+  std::vector<double> vyerr;
+  
+  const std::set<int>& runs = RunNumbers();
+  
+  AliAnalysisTriggerScalers ts(runs,OCDBPath().Data());
+  
+  for ( std::set<int>::const_iterator it = runs.begin(); it != runs.end(); ++it )
+  {
+    Int_t runNumber = *it;
+    
+    Double_t purity, purityError;
+    
+    TString triggerClassName = GetTriggerClassName(tt,runNumber);
+    
+    if ( triggerClassName.Length()==0 )
+    {
+      AliError(Form("Unknown trigger type %d",tt));
+      return;
+    }
+
+    GetPurity(triggerClassName.Data(),runNumber,purity,purityError,eventSelectionCorrected);
+    
+    vx.push_back(runNumber);
+    vxerr.push_back(0.5);
+    vy.push_back(purity);
+    vyerr.push_back(purityError);
+  }
+  
+  TString title(Form("Fraction of events accepted by the event selection %s for trigger %s",GetTriggerTypeName(tt).Data(),
+                     GetEventSelectionName(eventSelectionCorrected).Data()));
+  
+  CreateAndAddGraph(graphName,title,vx,vxerr,vy,vyerr);
+}
+
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::ComputeResultsFromGraphs()
+{
+  // Compute one single value for each graph, by weighting by the fraction
+  // of events in each run
+  // do this for certain groups of graphs
+  
+  TObjArray groups;
+  groups.SetOwner(kTRUE);
+  
+  groups.Add(new TObjString("Fnorm"));
+  groups.Add(new TObjString("NMBeq"));
+  groups.Add(new TObjString("Correction"));
+  groups.Add(new TObjString("RelDif"));
+  
+  TList* objectList = MC()->CreateListOfObjectNames("/GRAPHS/");
+  
+  TIter nextGroup(&groups);
+  TObjString* grp;
+  
+  TIter next(objectList);
+  TObjString* str(0x0);
+
+  while ( ( grp = static_cast<TObjString*>(nextGroup()) ) )
+  {
+    TString oname(Form("/RESULTS/%s",grp->String().Data()));
+    
+    if ( MC()->GetObject(oname) )
+    {
+      // delete if we have it already so we can replace it
+      MC()->Remove(oname);
+    }
+    
+    AliAnalysisMuMuResult* result = new AliAnalysisMuMuResult(grp->String());
+    
+    MC()->Adopt("/RESULTS/",result);
+    
+    next.Reset();
+    
+    while ( ( str = static_cast<TObjString*>(next()) ) )
+    {
+      if ( ! ( str->String().BeginsWith(grp->String() ) ) ) continue;
+
+      TGraphErrors* g = GetGraph(str->String());
+
+      if (!g) continue;
+    
+      AliAnalysisMuMuResult* sub = GetRunIntegratedResult(*g);
+
+      if ( !sub )
+      {
+        AliError(Form("Could not get result for graph %s",g->GetName()));
+      }
+      if ( sub )
+      {
+        result->AdoptSubResult(sub);
+      }
+    }
+  }
+  
+  delete objectList;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::ComputeNofEvents(ETriggerType triggerType,
+                                            Bool_t pileUpCorrected,
+                                            Int_t eventSelectionCorrected)
+{
+  /// Compute trigger fractions
+  
+  TString graphName(Form("NofEvent%s%s%s",GetTriggerTypeName(triggerType).Data(),
+                         pileUpCorrected ? "PU" : "",
+                         GetEventSelectionName(eventSelectionCorrected).Data()));
+  
+  if ( GetGraph(graphName) )
+  {
+    // compute it only once
+    return;
+  }
+  
+  ComputeCorrectionFactors(eventSelectionCorrected);
+  
+  TString gpsname(Form("Correction%s%s",GetEventSelectionName(eventSelectionCorrected).Data(),GetTriggerTypeName(triggerType).Data()));
+  TString gpuname(Form("CorrectionPU%s%s",GetEventSelectionName(eventSelectionCorrected).Data(), GetTriggerTypeName(triggerType).Data()));
+  
+  TGraphErrors* gPS = GetGraph(gpsname);
+  
+  if (!gPS)
+  {
+    AliError(Form("Could not find %s",gpsname.Data()));
+    return;
+  }
+  
+  TGraphErrors* gPU = GetGraph(gpuname);
+
+  if (!gPU)
+  {
+    AliError(Form("Could not find %s",gpuname.Data()));
+    return;
+  }
+
+  AliDebug(2,graphName);
+  
+  std::vector<double> vx;
+  std::vector<double> vxerr;
+  std::vector<double> vy;
+  std::vector<double> vyerr;
+  
+  const std::set<int>& runs = RunNumbers();
+  
+  Int_t i(0);
+  
+  for ( std::set<int>::const_iterator it = runs.begin(); it != runs.end(); ++it )
+  {
+    Int_t runNumber = *it;
+    
+    TString triggerClassName = GetTriggerClassName(triggerType,runNumber);
+    
+    if ( triggerClassName.Length() )
+    {
+      Double_t n = GetSum(triggerClassName,runNumber,0);
+      
+      vx.push_back(runNumber);
+      vxerr.push_back(0.5);
+
+      assert(runNumber==TMath::Nint(gPU->GetX()[i]));
+      
+      Double_t y(n);
+      Double_t y1(1.0);
+      Double_t y2(1.0);
+      Double_t e1(0);
+      Double_t e2(0);
+      
+      if ( pileUpCorrected )
+      {
+        y1 = gPU->GetY()[i];
+        e1 = gPU->GetEY()[i];
+      }
+
+      if ( eventSelectionCorrected > 0 )
+      {
+        y2 = gPS->GetY()[i];
+        e2 = gPS->GetEY()[i];
+      }
+      
+      y *= y1*y2;
+
+      AliDebug(2,Form("RUN %09d n %e y1 %e y2 %e y% e",runNumber,n,y1,y2,y));
+      
+      Double_t yerr = y*AliAnalysisMuMuResult::ErrorABC( n, TMath::Sqrt(n),
+                                                        y1, e1,
+                                                        y2, e2);
+
+      vy.push_back(y);
+      vyerr.push_back(yerr);
+      
+      ++i;
+    }
+  }
+    
+  TString title(Form("Number of event of trigger %s",GetTriggerTypeName(triggerType).Data()));
+  
+  CreateAndAddGraph(graphName,title,vx,vxerr,vy,vyerr);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::ComputeTriggerFractions(ETriggerType triggerType,
+                                                   Bool_t physicsSelectionCorrected)
+{
+  /// Compute trigger fractions
+  
+  TString graphName(Form("Fractions%s%s",GetTriggerTypeName(triggerType).Data(),physicsSelectionCorrected ? "PS" : ""));
+
+  if ( GetGraph(graphName) )
+  {
+    // compute it only once
+    return;
+  }
+
+  AliDebug(2,graphName);
+  
+  std::vector<double> vx;
+  std::vector<double> vxerr;
+  std::vector<double> vy;
+  std::vector<double> vyerr;
+  
+  const std::set<int>& runs = RunNumbers();
+
+  Double_t n(0.0);
+  
+  for ( std::set<int>::const_iterator it = runs.begin(); it != runs.end(); ++it )
+  {
+    Int_t runNumber = *it;
+    
+    TString triggerClassName = GetTriggerClassName(triggerType,runNumber);
+    
+    if ( triggerClassName.Length() )
+    {
+      n += GetSum(triggerClassName,runNumber,physicsSelectionCorrected);
+    }
+  }
+
+  if ( n <= 0.0 )
+  {
+    AliWarning(Form("Got zero trigger for %s",GetTriggerTypeName(triggerType).Data()));
+    return;
+  }
+  
+  for ( std::set<int>::const_iterator it = runs.begin(); it != runs.end(); ++it )
+  {
+    Int_t runNumber = *it;
+    
+    TString triggerClassName = GetTriggerClassName(triggerType,runNumber);
+    
+    vx.push_back(runNumber);
+    vxerr.push_back(0.5);
+    Double_t y = GetSum(triggerClassName,runNumber,physicsSelectionCorrected);
+    vy.push_back(y/n);
+    vyerr.push_back( (y/n) * AliAnalysisMuMuResult::ErrorAB( y,TMath::Sqrt(y),
+                                                        n, TMath::Sqrt(n)));
+  }
+  
+
+  TString title(Form("Fraction of event of trigger %s",GetTriggerTypeName(triggerType).Data()));
+  
+  CreateAndAddGraph(graphName,title,vx,vxerr,vy,vyerr);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::ComputeTriggerL0B(ETriggerType triggerType)
+{
+  /// Compute trigger L0B
+  
+  std::vector<double> vx;
+  std::vector<double> vxerr;
+  std::vector<double> vy;
+  std::vector<double> vyerr;
+  
+  TString graphName(Form("L0B%s",GetTriggerTypeName(triggerType).Data()));
+
+  if ( GetGraph(graphName) )
+  {
+    // insure we're computing it only once
+    return;
+  }
+  
+  AliDebug(2,graphName);
+  
+  const std::set<int>& runs = RunNumbers();
+  
+  AliAnalysisTriggerScalers ts(runs,OCDBPath().Data());
+
+  for ( std::set<int>::const_iterator it = runs.begin(); it != runs.end(); ++it )
+  {
+    Int_t runNumber = *it;
+    
+    TString triggerClassName = GetTriggerClassName(triggerType,runNumber);
+    
+    AliAnalysisTriggerScalerItem* item = ts.GetTriggerScaler(runNumber,"L0B",triggerClassName);
+    if (!item) continue;
+    
+    vx.push_back(runNumber);
+    vxerr.push_back(0.5);
+
+    Double_t y = item->Value();
+
+    vy.push_back(y);
+    
+    vyerr.push_back( TMath::Sqrt(y) );
+  }
+  
+  TString title(Form("L0B of trigger %s",GetTriggerTypeName(triggerType).Data()));
+  
+  CreateAndAddGraph(graphName,title,vx,vxerr,vy,vyerr);
+}
+
+////_____________________________________________________________________________
+//void AliAnalysisMuMuFnorm::ComputeTSGraph(ETriggerType tt)
+//{
+//  /// Compute the per-run graph of physics selection accept fraction x track
+//  /// accept fraction for the given trigger
+//  
+//  TString graphName(Form("CorrectionTS%s",GetTriggerTypeName(tt).Data()));
+//  
+//  if (GetGraph(graphName))
+//  {
+//    // insure we're computing it only once
+//    return;
+//  }
+//  
+//  AliDebug(1,graphName);
+//  
+//  std::vector<double> vx;
+//  std::vector<double> vxerr;
+//  std::vector<double> vy;
+//  std::vector<double> vyerr;
+//  
+//  const std::set<int>& runs = RunNumbers();
+//  
+//  AliAnalysisTriggerScalers ts(runs,OCDBPath().Data());
+//  
+//  for ( std::set<int>::const_iterator it = runs.begin(); it != runs.end(); ++it )
+//  {
+//    Int_t runNumber = *it;
+//    
+//    Double_t purity, purityError;
+//    
+//    TString triggerClassName = GetTriggerClassName(tt,runNumber);
+//    
+//    if ( triggerClassName.Length()==0 )
+//    {
+//      AliError(Form("Unknown trigger type %d",tt));
+//      return;
+//    }
+//    
+//    GetPurity(triggerClassName.Data(),runNumber,purity,purityError,"OFFLINE1");
+//    
+//    vx.push_back(runNumber);
+//    vxerr.push_back(0.5);
+//    vy.push_back(purity);
+//    vyerr.push_back(purityError);
+//  }
+//  
+//  TString title(Form("Fraction of events accepted by the physics selection x track selection for trigger %s",GetTriggerTypeName(tt).Data()));
+//  
+//  CreateAndAddGraph(graphName,title,vx,vxerr,vy,vyerr);
+//}
+//
+
+//_____________________________________________________________________________
+TGraphErrors* AliAnalysisMuMuFnorm::CreateAndAddGraph(const TString& name,
+                                                      const TString& title,
+                                                      const std::vector<double>& vx,
+                                                      const std::vector<double>& vxerr,
+                                                      const std::vector<double>& vy,
+                                                      const std::vector<double>& vyerr) const
+{
+  /// Creates a graph and adds it to our mergeable collection
+  
+  TGraphErrors* g = new TGraphErrors(vx.size(),&vx[0],&vy[0],&vxerr[0],&vyerr[0]);
+  g->SetName(name.Data());
+  g->SetTitle(title.Data());
+  
+  if  (fIsCompactGraphs)
+  {
+    AliAnalysisMuMuGraphUtil::Compact(*g);
+  }
+
+  g->GetXaxis()->SetNoExponent();
+//  g->GetXaxis()->SetTitle("Run number");
+
+  TPaveText* text = new TPaveText(0.70,0.70,0.89,0.89,"NDC");
+  text->SetBorderSize(0);
+  text->SetFillColor(0);
+  text->AddText(Form("Mean %e",g->GetMean(2)));
+  text->AddText(Form("RMS  %e",g->GetRMS(2)));
+  g->GetListOfFunctions()->Add(text);
+  
+  MC()->Adopt("/GRAPHS/",g);
+  return g;
+}
+
+//_____________________________________________________________________________
+AliMergeableCollection* AliAnalysisMuMuFnorm::DetachMC()
+{
+  // let go the ownership of our mergeable collection
+  fIsOwner = kFALSE;
+  return fMergeableCollection;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::DrawWith2Scales(const char* graphName1, const char* graphName2)
+{
+  TGraphErrors* g1 = static_cast<TGraphErrors*>(GetGraph(graphName1)->Clone());
+  TGraphErrors* g2 = static_cast<TGraphErrors*>(GetGraph(graphName2)->Clone());
+  
+  if ( g1 && g2 )
+  {
+    gStyle->SetOptTitle(0);
+    
+    AliAnalysisMuMuGraphUtil gu;
+    
+    TCanvas* c = gu.DrawWith2Scales(*g1,*g2);
+    c->Draw();
+    
+    for ( Int_t i = 0; i < 2; ++i )
+    {
+      c->cd(i);
+      gPad->SetLeftMargin(0.15);
+      gPad->SetRightMargin(0.15);
+    }
+    
+    c->Update();
+    
+    //    TGraphErrors* g = new TGraphErrors(g1->GetN());
+    //
+    //    Double_t check(0.0);
+    //
+    //    for ( Int_t i = 0; i < g->GetN(); ++i )
+    //    {
+    //      Double_t y = g1->GetY()[i]*g2->GetY()[i];
+    //
+    //      check += g2->GetY()[i];
+    //
+    //      g->SetPoint(i,g2->GetX()[i],y);
+    //      g->SetPointError(i,g2->GetEX()[i],
+    //                       y*AliAnalysisMuMuResult::ErrorAB(g1->GetY()[i],g1->GetEY()[i],
+    //                                                        g2->GetY()[i],g2->GetEY()[i]));
+    //    }
+    //
+    //    new TCanvas;
+    //
+    //    g->Draw("ap");
+    //
+    //    AliInfo(Form("check: %e g mean %e rms %e",check,g->GetMean(2),g->GetRMS(2)));
+
+    /*
+     
+    // g1 vs g2 
+     
+    TGraphErrors* g = new TGraphErrors(g1->GetN());
+    
+    for ( Int_t i = 0; i < g->GetN(); ++i )
+    {
+      g->SetPoint(i,g2->GetY()[i],g1->GetY()[i]);
+      g->SetPointError(i,g2->GetEY()[i],g1->GetEY()[i]);
+    }
+    
+    new TCanvas;
+    
+    g->Draw("ap");
+    
+    AliInfo(Form("g mean %e rms %e",g->GetMean(2),g->GetRMS(2)));
+     
+     */
+    
+  }
+  
+}
+
+//_____________________________________________________________________________
+TString AliAnalysisMuMuFnorm::GetEventSelectionName(Int_t eventSelectionCorrected) const
+{
+  if ( eventSelectionCorrected == 1 )
+  {
+    return "PS";
+  }
+  else if ( eventSelectionCorrected == 2 )
+  {
+    return "TS";
+  }
+  return "";
+}
+
+//_____________________________________________________________________________
+TGraphErrors* AliAnalysisMuMuFnorm::GetGraph(const char* name) const
+{
+  // shortcut method to give access to one graph
+  
+  TObject* o = MC()->GetObject(Form("/GRAPHS/%s",name));
+  
+  if (!o) return 0x0;
+  
+  if ( o->IsA() != TGraphErrors::Class() )
+  {
+    AliError(Form("Object %s is not of the expected type",o->GetName()));
+    return 0x0;
+  }
+  
+  return static_cast<TGraphErrors*>(o);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::GetPurity(const char* triggerClassName, Int_t runNumber,
+                                     Double_t& value, Double_t& error, Int_t eventSelectionCorrected) const
+{
+  /// Get the physics selection accept fraction for a given trigger
+  
+  value=error=0.0;
+
+  TString runCondition;
+  
+  if (runNumber>0)
+  {
+    runCondition.Form("/run:%d",runNumber);
+  }
+  
+  Double_t nall = fCounterCollection.GetSum(Form("trigger:%s/event:ALL%s",triggerClassName,runCondition.Data()));
+  
+  TString ename;
+  
+  if ( eventSelectionCorrected == 1 )
+  {
+    ename = "PSALL";
+  }
+  else if ( eventSelectionCorrected == 2 )
+  {
+    ename = "OFFLINE1";
+  }
+  else
+  {
+    value = 1.0;
+    return;
+    
+  }
+  Double_t nps = fCounterCollection.GetSum(Form("trigger:%s/event:%s%s",
+                                                triggerClassName,ename.Data(),runCondition.Data()));
+  
+  if ( nall <= 0.0 ) return;
+  
+  value = nps/nall;
+  
+  error = AliAnalysisMuMuResult::ErrorAB(nall,TMath::Sqrt(nall),nps,TMath::Sqrt(nps));
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuResult* AliAnalysisMuMuFnorm::GetResult(const char* name) const
+{
+  // shortcut method to give access to one result
+  
+  TObject* o = MC()->GetObject(Form("/RESULTS/%s",name));
+  
+  if (!o) return 0x0;
+  
+  if ( o->IsA() != AliAnalysisMuMuResult::Class() )
+  {
+    AliError(Form("Object %s is not of the expected type",o->GetName()));
+    return 0x0;
+  }
+  
+  return static_cast<AliAnalysisMuMuResult*>(o);
+}
+
+//______________________________________________________________________________
+AliAnalysisMuMuResult* AliAnalysisMuMuFnorm::GetRunIntegratedResult(const TGraphErrors& g, const char* basename)
+{
+  /// get one value +- error for this graph (weighting the run-by-run values
+  /// by the fraction of the number of triggers in that run)
+  /// also the rms is computed.
+  
+  Bool_t physicsSelectionCorrected(kFALSE);
+  
+  if ( TString(g.GetName()).Contains("PS") )
+  {
+    physicsSelectionCorrected=kTRUE;
+  }
+
+  ComputeTriggerFractions(fReferenceTriggerType,physicsSelectionCorrected);
+
+  TString fname(Form("Fractions%s%s",GetTriggerTypeName(fReferenceTriggerType).Data(),physicsSelectionCorrected ? "PS" : ""));
+  
+  TGraphErrors* gTriggerFractions = GetGraph(fname);
+  
+  StdoutToAliDebug(2,std::cout << g.GetName() << std::endl; g.Print(););
+  
+  if (!gTriggerFractions)
+  {
+    AliError(Form("Did not find graph for %s",fname.Data()));
+    return 0x0;
+  }
+  
+  Double_t mean = g.GetY()[0];
+  Int_t n = g.GetN();
+  
+  Double_t errorOnMean = g.GetEY()[0];
+  Double_t rms = 0.0;
+  
+  if ( n > 1 )
+  {
+    mean = errorOnMean = 0.0;
+    Double_t d(0.0);
+    Double_t v1(0.0);
+    Double_t v2(0.0);
+    
+    for ( Int_t i = 0; i < n; ++i )
+    {
+      Double_t y = g.GetY()[i];
+      
+      Double_t weight = gTriggerFractions->GetY()[i]; // sum of weight should be 1.0
+      
+      AliDebug(2,Form("%s i %3d y %e weight %e",g.GetName(),i,y,weight));
+      
+      mean += y * weight;
+      
+      v1 += weight;
+      v2 += weight*weight;
+    }
+    
+    mean /= v1;
+    
+    for ( Int_t i = 0; i < n; ++i )
+    {
+      Double_t weight = gTriggerFractions->GetY()[i]; // sum of weight should be 1.0
+      Double_t y = g.GetY()[i];
+      
+      d += (y-mean)*(y-mean)*weight;
+    }
+    
+    AliDebug(2,Form("v1=%e v2=%e d=%e",v1,v2,d));
+    
+    if ( v1 <= 0) return 0x0;
+    
+    errorOnMean = TMath::Sqrt((1.0/v1)*(1.0/(n-1))*d);
+    
+    rms = TMath::Sqrt( (v1/(v1*v1-v2))*d );    
+  }
+  
+  AliAnalysisMuMuResult* result = new AliAnalysisMuMuResult(g.GetName(),g.GetTitle());  
+
+  result->Set(basename,mean,errorOnMean,rms);
+  
+  if ( TString(g.GetName()) == "FnormScalersPUPS" )
+  {
+    AliDebug(1,Form("mean %e errorOnMean %e rms %e",mean,errorOnMean,rms));
+    StdoutToAliDebug(1,result->Print("full"));
+  }
+
+  return result;
+}
+
+//_____________________________________________________________________________
+Double_t AliAnalysisMuMuFnorm::GetSum(const char* triggerClassName,
+                                      Int_t runNumber,
+                                      Int_t eventSelectionCorrected) const
+{
+  TString condition(Form("trigger:%s/run:%d",triggerClassName,runNumber));
+  
+  if (eventSelectionCorrected==1)
+  {
+    condition += "/event:PSALL";
+  }
+  else if ( eventSelectionCorrected == 2 )
+  {
+    condition += "/event:OFFLINE1";
+  }
+  else
+  {
+    condition += "/event:ALL";
+  }
+  
+  Double_t n = fCounterCollection.GetSum(condition.Data());
+  
+  if (n<=0)
+  {
+    AliError(Form("Got no count for %s for run %d (physicsSelected:%d)",triggerClassName,runNumber,eventSelectionCorrected));
+    return 0;
+  }
+  
+  return n;
+}
+
+//_____________________________________________________________________________
+TString AliAnalysisMuMuFnorm::GetTriggerClassName(ETriggerType tt, Int_t runNumber) const
+{
+  // get the triggerclass to for a given trigger type and run number
+  
+  if ( tt == kMB )
+  {
+    return MBTriggerClassName(runNumber);
+  }
+  else if ( tt == kMUL )
+  {
+    return MULTriggerClassName(runNumber);
+  }
+  else if ( tt == kMSL)
+  {
+    return MSLTriggerClassName(runNumber);
+  }
+  else if ( tt == kMSH)
+  {
+    return MSHTriggerClassName(runNumber);
+  }
+  return "";
+}
+
+//_____________________________________________________________________________
+TString AliAnalysisMuMuFnorm::GetTriggerTypeName(ETriggerType tt) const
+{
+  // get the name of the trigger type
+  if ( tt == kMB )
+  {
+    return "MB";
+  }
+  else if ( tt == kMUL )
+  {
+    return "MUL";
+  }
+  else if ( tt == kMSL)
+  {
+    return "MSL";
+  }
+  else if ( tt == kMSH)
+  {
+    return "MSH";
+  }
+  return "";
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::GetValueAndErrorFromGraph(TGraphErrors* graph,
+                                                     Int_t runNumber,
+                                                     Double_t& value,
+                                                     Double_t& error) const
+{
+  /// get (value,error) corresponding to run=runNumber.
+  /// Works both for compact and non-compact graphs
+  
+  value = TMath::Limits<Double_t>::Max();
+  error = 0.0;
+  
+  if (!graph) return;
+  
+  TAxis* axis = graph->GetXaxis();
+  
+  for ( Int_t i = 0; i < graph->GetN(); ++i )
+  {
+    Int_t rbin = TMath::Nint(graph->GetX()[i]);
+    Int_t rlabel = TString(axis->GetBinLabel(i+1)).Atoi();
+    if ( rbin == runNumber || rlabel == runNumber )
+    {
+      value = graph->GetY()[i];
+      error = graph->GetEY()[i];
+    }
+  }
+}
+
+//_____________________________________________________________________________
+AliMergeableCollection* AliAnalysisMuMuFnorm::MC() const
+{
+  // get our mergeable collection
+  if (!fMergeableCollection)
+  {
+    fMergeableCollection = new AliMergeableCollection("Fnorm",Form("MB to %s trigger normalization results",GetTriggerTypeName(fReferenceTriggerType).Data()));
+  }
+  return fMergeableCollection;
+}
+
+//_____________________________________________________________________________
+TString AliAnalysisMuMuFnorm::MBTriggerClassName(Int_t runNumber) const
+{
+  /// FIXME : find a better way ?
+  
+  if ( TriggerClassnameTest("CINT7-B-NOPF-ALLNOTRD",runNumber) )
+  {
+    return "CINT7-B-NOPF-ALLNOTRD";
+  }
+  return "";
+}
+
+//_____________________________________________________________________________
+TString AliAnalysisMuMuFnorm::MSHTriggerClassName(Int_t runNumber) const
+{
+  /// FIXME : find a better way ?
+  
+  if ( TriggerClassnameTest("CMSH7-B-NOPF-ALLNOTRD",runNumber) )
+  {
+    return "CMSH7-B-NOPF-ALLNOTRD";
+  }
+  else if ( TriggerClassnameTest("CMSH7-B-NOPF-MUON",runNumber) )
+  {
+    return "CMSH7-B-NOPF-MUON";
+  }
+  return "";
+}
+
+//_____________________________________________________________________________
+TString AliAnalysisMuMuFnorm::MSLTriggerClassName(Int_t runNumber) const
+{
+  /// FIXME : find a better way ?
+  
+  if ( TriggerClassnameTest("CMSL7-B-NOPF-MUON",runNumber) )
+  {
+      return "CMSL7-B-NOPF-MUON";
+  }
+//  else
+//    if ( TriggerClassnameTest("CMSL7-B-NOPF-ALLNOTRD",runNumber) )
+//  {
+//    return "CMSL7-B-NOPF-ALLNOTRD";
+//  }
+  return "";
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::MultiplyGraphs(const char* g1name, const char* g2name, const char* name)
+{
+  /// Make a new graph = g1*g2
+  std::vector<double> vx;
+  std::vector<double> vy;
+  std::vector<double> vxerr;
+  std::vector<double> vyerr;
+  
+  TGraphErrors* g1 = GetGraph(g1name);
+  TGraphErrors* g2 = GetGraph(g2name);
+  
+  if (!g1)
+  {
+    AliError(Form("Could not get graph %s",g1name));
+    return;
+  }
+
+  if (!g2)
+  {
+    AliError(Form("Could not get graph %s",g2name));
+    return;
+  }
+
+  if ( g1->GetN() != g2->GetN() )
+  {
+    AliError(Form("Could not multiply incompatible graphs %d pts vs %d pts",g1->GetN(),g2->GetN()));
+    return;
+  }
+  
+  for ( Int_t i = 0; i < g1->GetN(); ++i )
+  {
+    if ( g1->GetX()[i] != g2->GetX()[i] )
+    {
+      AliError(Form("Incompatible bin %d : %e vs %e",i,g1->GetX()[i],g2->GetX()[i]));
+      return;
+    }
+    
+    vx.push_back(g1->GetX()[i]);
+    vxerr.push_back(g1->GetEX()[i]);
+    
+    Double_t y = g1->GetY()[i]*g2->GetY()[i];
+    Double_t yerr = y*AliAnalysisMuMuResult::ErrorAB( g1->GetY()[i], g1->GetEY()[i],
+                                                     g2->GetY()[i], g2->GetEY()[i]);
+    
+    vy.push_back(y);
+    vyerr.push_back(yerr);
+  }
+  
+  TString gname(name);
+  
+  if ( gname.Length() == 0 )
+  {
+    gname = g1->GetName();
+    gname += "x";
+    gname += g2->GetName();
+  }
+  
+  TString title(Form("Product of %s by %s",g1->GetName(),g2->GetName()));
+  
+  CreateAndAddGraph(gname,title,vx,vxerr,vy,vyerr);
+}
+
+//_____________________________________________________________________________
+TString AliAnalysisMuMuFnorm::MULTriggerClassName(Int_t runNumber) const
+{
+  /// FIXME : find a better way ?
+  
+  if ( TriggerClassnameTest("CMUL7-B-NOPF-ALLNOTRD",runNumber) )
+  {
+    return "CMUL7-B-NOPF-ALLNOTRD";
+  }
+  else if ( TriggerClassnameTest("CMUL7-B-NOPF-MUON",runNumber) )
+  {
+    return "CMUL7-B-NOPF-MUON";
+  }
+  return "";
+  
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::Print(Option_t* opt) const
+{
+  if ( fMergeableCollection )
+  {
+    fMergeableCollection->Print(opt);
+  }
+}
+
+//_____________________________________________________________________________
+std::set<int> AliAnalysisMuMuFnorm::RunNumbers() const
+{
+  // Extract the run numbers from our counter collection
+  
+  std::set<int> runset;
+  
+  TString sruns = fCounterCollection.GetKeyWords("run");
+  TObjArray* runs = sruns.Tokenize(",");
+  
+  TIter next(runs);
+  TObjString* s;
+  
+  while ( ( s = static_cast<TObjString*>(next())) )
+  {
+    runset.insert(s->String().Atoi());
+  }
+  delete runs;
+  
+  return runset;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::ScalerFnorm(Double_t& value, Double_t& error,
+                                       Double_t L0bREF, Double_t purityREF, Double_t purityREFerror,
+                                       Double_t L0bMB, Double_t purityMB, double_t purityMBerror,
+                                       Double_t pileUpFactor, Double_t pileUpFactorError)
+{
+  /// Compute the MB to CMUL ratio and its associated error
+  
+  value = error = 0.0;
+  
+  value = L0bREF*purityREF;
+  
+  if (!value) return;
+  
+  value = L0bMB*purityMB*pileUpFactor/value;
+  
+  error = value*AliAnalysisMuMuResult::ErrorABCDE(L0bREF,TMath::Sqrt(L0bREF),
+                                                  purityREF,purityREFerror,
+                                                  L0bMB,TMath::Sqrt(L0bMB),
+                                                  purityMB,purityMBerror,
+                                                  pileUpFactor,pileUpFactorError);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuFnorm::ShowFnorm(const TObjArray& a) const
+{
+  /// Print and plot Fnorm values
+  TIter next(&a);
+  TGraphErrors* g;
+  
+  while ( ( g = static_cast<TGraphErrors*>(next()) ) )
+  {
+    g->SetTitle(Form("Fnorm %s",g->GetTitle()));
+
+    new TCanvas(Form("c%s",g->GetName()));
+
+    if (fIsCompactGraphs)
+    {
+      AliAnalysisMuMuGraphUtil::Compact(*g);
+    }
+    else
+    {
+      g->GetXaxis()->SetNoExponent();
+    }
+    g->Draw("lpa");
+    
+    Double_t y(0.0);
+    Double_t yerr(0.0);
+    
+    for ( Int_t i = 0; i < g->GetN(); ++i )
+    {
+      y += g->GetY()[i];
+      Double_t e = ( y != 0.0  ? g->GetEY()[i]/y : 0.0);
+      
+      yerr += e*e;
+    }
+    
+    y /= (g->GetN());
+    yerr = TMath::Sqrt(yerr)*y;
+    
+    AliInfo(Form("%30s graph %e +- %e (%5.2f %%) RMS %e",g->GetName(),
+                 y,yerr,yerr*100/y,g->GetRMS(2)));
+
+  }
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuFnorm::TriggerClassnameTest(const char* triggerClassName, Int_t runNumber) const
+{
+  /// Check if we have counts for that trigger,run combination
+  
+  TString runs = fCounterCollection.GetKeyWords("run");
+  
+  if ( !runs.Contains(Form("%d",runNumber)) ) return kFALSE;
+  
+  TString triggers = fCounterCollection.GetKeyWords("trigger");
+  
+  if (!triggers.Contains(triggerClassName)) return kFALSE;
+  
+  Double_t n = fCounterCollection.GetSum(Form("trigger:%s/run:%d",triggerClassName,runNumber));
+  
+  return ( n > 0.0 );
+}
+
+//_____________________________________________________________________________
+void
+AliAnalysisMuMuFnorm::WeightedMeanGraphs(const char* patternOrList, const char* graphName)
+{
+  /// Sum the graphs which name matches pattern
+  /// Sum is made using a weighted mean (each element is weighted by the inverse
+  /// of its error squared)
+  
+  TString spattern(patternOrList);
+  TObjArray* slist(0x0);
+  
+  if ( spattern.CountChar(',') )
+  {
+    // it's not a pattern but a list...
+    slist = spattern.Tokenize(",");
+    spattern = "";
+  }
+  
+  TList* objectList = MC()->CreateListOfObjectNames("/GRAPHS/");
+  TIter next(objectList);
+  TObjString* str(0x0);
+  TObjArray selected;
+  selected.SetOwner(kFALSE);
+  
+  while ( ( str = static_cast<TObjString*>(next()) ) )
+  {
+    TGraphErrors* g = GetGraph(str->String());
+    
+    if (!g) continue;
+    
+    TString name(g->GetName());
+    
+    if ( spattern.Length() >0 && !name.Contains(spattern.Data()) ) continue;
+    
+    if ( slist && !slist->FindObject(name)) continue;
+    
+    AliDebug(2,Form("Selected for sum : %s",name.Data()));
+    
+    selected.Add(g);
+  }
+  
+  delete slist;
+  delete objectList;
+  
+  if (selected.GetLast()<0) return;
+  
+  std::vector<double> vx;
+  std::vector<double> vy;
+  std::vector<double> vxerr;
+  std::vector<double> vyerr;
+  
+  Int_t npts = static_cast<TGraphErrors*>(selected.First())->GetN();
+  
+  for ( Int_t ipoint = 0; ipoint < npts; ++ipoint )
+  {
+    Double_t x,xref,xerr;
+    Double_t sum(0.0);
+    Double_t sume2(0.0);
+    
+    for ( Int_t igraph = 0; igraph <= selected.GetLast(); ++igraph )
+    {
+      TGraphErrors* g = static_cast<TGraphErrors*>(selected.At(igraph));
+      
+      if ( g->GetN() != npts )
+      {
+        AliError(Form("Graph %s does not have the expected %d points",g->GetName(),npts));
+        continue;
+      }
+      Double_t runNumber;
+      
+      if ( fIsCompactGraphs )
+      {
+        runNumber = TString(g->GetXaxis()->GetBinLabel(ipoint+1)).Atoi()*1.0;
+      }
+      else
+      {
+        runNumber = g->GetX()[ipoint];
+      }
+      
+      if ( igraph == 0 )
+      {
+        xref = g->GetX()[ipoint];
+        x = runNumber;
+        xerr = g->GetEX()[ipoint];
+      }
+      else
+      {
+        if ( xref != g->GetX()[ipoint] )
+        {
+          AliError(Form("Cannot sum graphs with different axis : get %e and expected %e : %s vs %s",xref,x,selected.At(0)->GetName(),g->GetName()));
+          return;
+        }
+      }
+      
+      Double_t e2 = g->GetEY()[ipoint]*g->GetEY()[ipoint];
+      
+      if ( e2 != 0.0 )
+      {
+        sum += g->GetY()[ipoint]/e2;
+        sume2 += 1.0/e2;
+      }
+    }
+    
+    if (sume2 != 0.0)
+    {
+      vx.push_back(x);
+      vxerr.push_back(xerr);
+      vy.push_back(sum/sume2);
+      vyerr.push_back(TMath::Sqrt(1/sume2));
+    }
+  }
+  
+  Int_t n = selected.GetEntries();
+  
+  TString name(graphName);
+  TString title(Form("Weighted mean from %d individual graphs",n));
+  
+  if ( strlen(graphName) == 0)
+  {
+    name = TString::Format("WeightMeanFnorm%s",patternOrList);
+    name.ReplaceAll(",","_");
+    title = TString::Format("WeightMeanFnorm%s from %d individual graphs",patternOrList,n);
+  }
+  
+  CreateAndAddGraph(name,title,vx,vxerr,vy,vyerr);
+}
+
+
diff --git a/PWG/muondep/AliAnalysisMuMuFnorm.h b/PWG/muondep/AliAnalysisMuMuFnorm.h
new file mode 100644 (file)
index 0000000..38dc6ee
--- /dev/null
@@ -0,0 +1,148 @@
+#ifndef ALIANALYSISMUMUFNORM_H
+#define ALIANALYSISMUMUFNORM_H
+
+/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * See cxx source for full Copyright notice                               */
+
+#ifndef ROOT_TObject
+#  include "TObject.h"
+#endif
+
+#ifndef ROOT_TString
+#  include "TString.h"
+#endif
+
+#include <set>
+#include <vector>
+
+class TObjArray;
+class TGraphErrors;
+class TGraph;
+class AliAnalysisMuMuResult;
+class AliCounterCollection;
+class AliMergeableCollection;
+
+class AliAnalysisMuMuFnorm : public TObject
+{
+
+public:
+  
+  enum ETriggerType
+  {
+    kMB=1,
+    kMUL=2,
+    kMSL=3,
+    kMSH=4
+  };
+  
+  AliAnalysisMuMuFnorm(AliCounterCollection& cc,
+                       AliAnalysisMuMuFnorm::ETriggerType triggerType=AliAnalysisMuMuFnorm::kMUL,
+                       const char* ocdbpath="raw://",
+                       Bool_t compactGraphs=kFALSE);
+  
+  virtual ~AliAnalysisMuMuFnorm();
+  
+  void ComputeFnorm();
+  
+  void ComputeCorrectionFactors(Int_t eventSelectionCorrected);
+
+  void ComputeFnormOffline(Int_t nstep, Bool_t pileUpCorrected, Int_t eventSelectionCorrected);
+
+
+  void ComputeFnormScalers(Bool_t pileUpCorrected, Int_t eventSelectionCorrected);
+
+  void ComputeGraphRelDif(const char* a, const char* b) const;
+
+  void ComputeNofEvents(ETriggerType triggerType, Bool_t pileUpCorrected, Int_t eventSelectionCorrected);
+
+  void ComputePileUpGraph(ETriggerType tt, Int_t eventSelectionCorrected=0);
+  
+  void ComputeEventSelectionGraph(ETriggerType tt, Int_t eventSelectionCorrected);
+
+  void ComputeResultsFromGraphs();
+
+  void ComputeTriggerFractions(ETriggerType triggerType, Bool_t physicsSelectionCorrected);
+  
+  void ComputeTriggerL0B(ETriggerType tt);
+
+  void ComputeTSGraph(ETriggerType tt);
+
+  AliMergeableCollection* DetachMC();
+
+  void DrawWith2Scales(const char* graphName1, const char* graphName2);
+  
+  TString GetEventSelectionName(Int_t eventSelectionCorrected) const;
+
+  void GetFnorm(Int_t runNumber, const char* eventSelection, Double_t& value, Double_t& error) const;
+  
+  TGraphErrors* GetGraph(const char* name) const;
+  
+  void GetPurity(const char* triggerClassName, Int_t runNumber, Double_t& value, Double_t& error, Int_t eventSelectionCorrected) const;
+
+  void GetValueAndErrorFromGraph(TGraphErrors* graph,
+                                 Int_t runNumber,
+                                 Double_t& value,
+                                 Double_t& error) const;
+  
+  AliAnalysisMuMuResult* GetResult(const char* name) const;
+
+  AliAnalysisMuMuResult* GetRunIntegratedResult(const TGraphErrors& g, const char* basename="Fnorm");
+
+  AliMergeableCollection* MC() const;
+  
+  void MultiplyGraphs(const char* g1, const char* g2, const char* name="");
+  
+  TString OCDBPath() const { return fOCDBPath; }
+  
+  void Print(Option_t* opt="") const;
+
+  void ScalerFnorm(Double_t& value, Double_t& error,
+                   Double_t L0bCMUL7, Double_t purityCMUL7, Double_t purityCMUL7error,
+                   Double_t L0bCINT7, Double_t purityCINT7, Double_t purityCINT7error,
+                   Double_t pileUpFactor, Double_t pileUpFactorError);
+  
+  void ShowFnorm(const TObjArray& a) const;
+
+  Bool_t TriggerClassnameTest(const char* triggerClassName, Int_t runNumber) const;
+
+  void WeightedMeanGraphs(const char* pattern, const char* name="");
+  
+private:
+  
+  AliAnalysisMuMuFnorm(const AliAnalysisMuMuFnorm& rhs); // not implemented on purpose
+  AliAnalysisMuMuFnorm& operator=(const AliAnalysisMuMuFnorm& rhs); // not implemented on purpose
+
+  TGraphErrors* CreateAndAddGraph(const TString& name,
+                                  const TString& title,
+                                  const std::vector<double>& vx,
+                                  const std::vector<double>& vxerr,
+                                  const std::vector<double>& vy,
+                                  const std::vector<double>& vyerr) const;
+
+  Double_t GetSum(const char* triggerClassName, Int_t runNumber, Int_t eventSelectionCorrected) const;
+
+  TString GetTriggerClassName(ETriggerType tt, Int_t runNumber) const;
+
+  TString GetTriggerTypeName(ETriggerType tt) const;
+
+  std::set<int> RunNumbers() const;
+
+  TString MBTriggerClassName(Int_t runNumber) const;
+  TString MSLTriggerClassName(Int_t runNumber) const;
+  TString MULTriggerClassName(Int_t runNumber) const;
+  TString MSHTriggerClassName(Int_t runNumber) const;
+
+private:
+  
+  /*const*/ AliCounterCollection& fCounterCollection; // collection of trigger counters (not owner)
+  mutable AliMergeableCollection* fMergeableCollection; // collection of results, histograms, graphs (ownership is in fIsOwner)
+  Bool_t fIsOwner; // whether we are the owner of the mergeable collection
+  TString fOCDBPath; // OCDB to be used (raw:// by default)
+  mutable AliAnalysisMuMuResult* fResult; // combined result of the various computations
+  Bool_t fIsCompactGraphs; // whether the graph produced should be compact
+  ETriggerType fReferenceTriggerType; // reference trigger to get the weighting factors
+  
+  ClassDef(AliAnalysisMuMuFnorm,0) // class to compute MB to MUON trigger normalization factor
+};
+
+#endif
diff --git a/PWG/muondep/AliAnalysisMuMuGraphUtil.cxx b/PWG/muondep/AliAnalysisMuMuGraphUtil.cxx
new file mode 100644 (file)
index 0000000..26b238d
--- /dev/null
@@ -0,0 +1,462 @@
+#include "AliAnalysisMuMuGraphUtil.h"
+
+#include "TAxis.h"
+#include "TCanvas.h"
+#include "TPad.h"
+#include "TGraphErrors.h"
+#include "TString.h"
+#include <vector>
+#include <map>
+#include "TMath.h"
+#include "TObjArray.h"
+#include "AliLog.h"
+#include "TLegend.h"
+#include "TH2F.h"
+#include "TStyle.h"
+#include "AliAnalysisTriggerScalers.h"
+#include <set>
+#include "AliAnalysisMuMuResult.h"
+
+ClassImp(AliAnalysisMuMuGraphUtil)
+
+//____________________________________________________________________________
+AliAnalysisMuMuGraphUtil::AliAnalysisMuMuGraphUtil(const char* ocdbpath) : TObject(),
+fOCDBPath(ocdbpath),
+fAttLine(),
+fAttMarker(),
+fAttFill(),
+fAttXaxis(),
+fAttYaxis(),
+fDrawOptions(),
+fShouldDrawPeriods(kFALSE)
+{
+  // default ctor
+  DefaultStyle();
+}
+
+//____________________________________________________________________________
+TGraphErrors* AliAnalysisMuMuGraphUtil::Combine(TObjArray& graphs, Bool_t compact)
+{
+  // make one graph out of several
+  // x axis is supposed to be run numbers and will end up ordered in the
+  // returned graph
+  
+  std::map<int, std::vector<double> > values;
+  std::map<int, std::vector<double> >::const_iterator it;
+
+  TIter next(&graphs);
+  TGraph* g;
+  
+  while ( ( g = static_cast<TGraph*>(next())) )
+  {
+    TGraphErrors* ge = dynamic_cast<TGraphErrors*>(g);
+    
+    for ( Int_t i = 0; i < g->GetN(); ++i )
+    {
+      Int_t runNumber = GetRunNumber(*g,i); // by doing this we "de-compact" the graph
+
+      it = values.find(runNumber);
+      if ( it != values.end() )
+      {
+        AliErrorClass(Form("Already got values for run %d !",runNumber));
+        StdoutToAliErrorClass(graphs.Print(););
+        return 0x0;
+      }
+
+      std::vector<double> quartet;
+    
+      quartet.push_back(runNumber);
+      quartet.push_back(g->GetY()[i]);
+      
+      if ( ge )
+      {
+        quartet.push_back(ge->GetEX()[i]);
+        quartet.push_back(ge->GetEY()[i]);
+      }
+      else
+      {
+        quartet.push_back(0.0);
+        quartet.push_back(0.0);
+      }
+      
+      values.insert( std::make_pair<int, std::vector<double> >(runNumber,quartet));      
+    }
+  }
+  
+  TGraphErrors* rv(0x0);
+  
+  if ( values.size() )
+  {
+    std::vector<double> vx;
+    std::vector<double> vy;
+    std::vector<double> vxerr;
+    std::vector<double> vyerr;
+    
+    for ( it = values.begin(); it != values.end(); ++it )
+    {
+      const std::vector<double>& q = it->second;
+      
+      vx.push_back(q[0]);
+      vy.push_back(q[1]);
+      vxerr.push_back(q[2]);
+      vyerr.push_back(q[3]);
+    }
+    
+    rv = new TGraphErrors(values.size(),&vx[0],&vy[0],&vxerr[0],&vyerr[0]);
+    rv->GetXaxis()->SetNoExponent();
+    
+    g = static_cast<TGraph*>(graphs.At(0));
+    
+    rv->SetName(g->GetName());
+    rv->SetTitle(g->GetTitle());
+    
+    if ( compact || IsCompact(*g) )
+    {
+      Compact(*rv);
+    }
+  }
+  
+  return rv;
+}
+
+//____________________________________________________________________________
+void AliAnalysisMuMuGraphUtil::DefaultStyle()
+{
+  // Define default color/styles to be used, for at least 2 graphs
+  // (here 5)
+  
+  Int_t colors[] = { 1, kGray+1, 4, 2, 6 };
+  
+  for ( Int_t i = 0; i < 5; ++i )
+  {
+    Int_t color = colors[i];
+    
+    fAttLine.push_back(TAttLine(color,1,1));
+    fAttFill.push_back(TAttFill(color,1001));
+    fAttMarker.push_back(TAttMarker(color,20+i,1));
+    fAttXaxis.push_back(TAttAxis());
+    
+    TAttAxis a;
+    
+    a.ResetAttAxis();
+    
+    a.SetLabelColor(color);
+    a.SetTitleColor(color);
+    
+    fAttYaxis.push_back(a);
+    
+    fDrawOptions.push_back("LP");
+  }
+}
+
+//____________________________________________________________________________
+TCanvas* AliAnalysisMuMuGraphUtil::DrawWith2Scales(TGraph& g1, TGraph& g2, const char* canvasName)
+{
+  TCanvas* c1 = new TCanvas(canvasName,canvasName);
+  c1->Draw();
+  
+  TPad* pad1 = new TPad("pad1","",0,0,1,1);
+  TPad* pad2 = new TPad("pad2","",0,0,1,1);
+  
+  g2.GetYaxis()->SetTitle(g2.GetTitle());
+  g1.GetYaxis()->SetTitle(g1.GetTitle());
+  
+  pad1->SetFillStyle(4000);
+  pad1->SetFrameFillStyle(0); //  transparent pad
+  
+  pad2->Draw();
+  pad2->cd();
+  
+  StyleGraph(g2,1);
+  
+  g2.Draw("abxy+");
+  
+  pad1->Draw();
+  pad1->cd();
+  
+  StyleGraph(g1,0);
+  
+  g1.Draw("alp");
+  
+  return c1;
+}
+
+//____________________________________________________________________________
+void AliAnalysisMuMuGraphUtil::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;
+  
+  Double_t x,y;
+  
+  std::vector<int> runs;
+  std::vector<double> bins;
+  
+  Int_t i(0);
+  
+  for ( i = 0; i < g.GetN(); ++i )
+  {
+    g.GetPoint(i,x,y);
+    runs.push_back(TMath::Nint(x));
+    bins.push_back(i);
+    g.SetPoint(i,i+0.5,y);
+  }
+  
+  bins.push_back(i);
+  
+  TAxis* axis = g.GetXaxis();
+  
+  axis->Set(g.GetN(),&bins[0]);
+  
+  for ( std::vector<int>::size_type j = 0; j < runs.size(); ++j )
+  {
+    axis->SetBinLabel(j+1,TString::Format("%d",runs[j]).Data());
+  }
+  
+  axis->LabelsOption("v");
+}
+
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuGraphUtil::GetRunNumber(const TGraph& g, Int_t i)
+{
+  // get the run number associated with bin i+1
+  // if graph is not compacted then run number = x-value
+  // otherwise we get it from the axis label
+  Int_t runNumber = TMath::Nint(g.GetX()[i]);
+
+  TString runLabel = g.GetXaxis()->GetBinLabel(i+1);
+  
+  if ( runLabel.Length() )
+  {
+    runNumber = runLabel.Atoi();
+  }
+
+  return runNumber;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuGraphUtil::GetRuns(std::set<int>& runs, TGraph& graph) const
+{
+  // extract the list of runs in graph's x-axis
+  
+  for ( Int_t i = 0; i < graph.GetN(); ++i )
+  {
+    runs.insert(GetRunNumber(graph,i));
+  }
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuGraphUtil::GetYMinAndMax(TGraph& graph, Double_t& ymin, Double_t& ymax)
+{
+  // find graph y-range
+  // note that ymin and ymax *must* be initialized correctly outside
+  // (this is done this way so that this method can be used easily
+  // to get the range of a set of graphs)
+  
+  Double_t x,y;
+  
+  for ( Int_t i = 0; i < graph.GetN(); ++i )
+  {
+    graph.GetPoint(i,x,y);
+    ymin = TMath::Min(ymin,y);
+    ymax = TMath::Max(ymax,y);
+  }
+  
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuGraphUtil::IsCompact(TGraph& g)
+{
+  // whether the graph is compact or not
+  Double_t delta(0.0);
+  
+  for ( Int_t i = 1; i < g.GetN(); ++i )
+  {
+    delta = TMath::Max(delta,g.GetX()[i] - g.GetX()[i-1]);
+  }
+  
+  Bool_t hasLabels(kFALSE);
+
+  for ( Int_t i = 1; ( i <= g.GetN() ) && ( !hasLabels ); ++i )
+  {
+    TString label(g.GetXaxis()->GetBinLabel(i));
+    if ( label.Length() ) hasLabels = kTRUE;
+  }
+  
+  return hasLabels && delta == 1.0;
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuGraphUtil::PlotSameWithLegend(TObjArray& a,
+                                                  Double_t ymin, Double_t ymax) const
+{
+  // plot on same canvas
+  if (!gPad) new TCanvas;
+  
+  Double_t xmin = TMath::Limits<Double_t>::Max();
+  Double_t xmax = TMath::Limits<Double_t>::Min();
+  
+  TIter next(&a);
+  TGraph* g;
+  
+  while ( ( g = static_cast<TGraph*>(next())))
+  {
+    xmin = TMath::Min(xmin,g->GetX()[0]);
+
+    xmax = TMath::Max(xmax,g->GetX()[g->GetN()-1]);
+
+  }
+
+  TH2* hframe = new TH2F("hframe","hframe",100,xmin,xmax,100,ymin,ymax);
+  
+  gStyle->SetOptTitle(0);
+  gStyle->SetOptStat(0);
+
+  hframe->GetXaxis()->SetNoExponent();
+
+//  if ( IsCompact(g1) )
+//  {
+//    (*(hframe->GetXaxis()))=(*(g1.GetXaxis()));
+//  }
+
+  hframe->Draw();
+
+  if ( fShouldDrawPeriods )
+  {
+    std::set<int> runs;
+  
+    next.Reset();
+    
+    while ( ( g = static_cast<TGraph*>(next())))
+    {
+      GetRuns(runs,*g);
+    }
+    
+    AliAnalysisTriggerScalers ts(runs,fOCDBPath);
+  
+    ts.DrawPeriods(ymin,ymax,kGray);
+    
+    hframe->Draw("axissame");
+  }
+
+  next.Reset();
+  
+  Int_t i(0);
+  TLegend* l = new TLegend(0.5,0.7,0.9,0.9); // fixme: how to get the legend position/size ?
+  l->SetFillColor(0);
+  
+  while ( ( g = static_cast<TGraph*>(next())))
+  {
+    StyleGraph(*g,i);
+    g->Draw(fDrawOptions[i].c_str());
+    ++i;
+    l->AddEntry(g,g->GetName(),fDrawOptions[0].c_str());
+  }
+  
+  l->Draw();  
+
+}
+
+//_____________________________________________________________________________
+TGraph* AliAnalysisMuMuGraphUtil::RelDif(TGraph& ga, TGraph& gb)
+{
+  // compute the relative difference between two graphs
+  
+  std::vector<double> vx;
+  std::vector<double> vxerr;
+  std::vector<double> vy;
+  std::vector<double> vyerr;
+
+  for ( Int_t i = 0; i < ga.GetN(); ++i )
+  {
+    Double_t xa,xb,ya,yb;
+  
+    ga.GetPoint(i,xa,ya);
+    gb.GetPoint(i,xb,yb);
+  
+    if ( xa != xb )
+    {
+      AliErrorClass(Form("Incompatible graphs : got xa=%e and xb=%e",xa,xb));
+      return 0x0;
+    }
+  
+    Double_t newvalue = 0.0;
+  
+    if ( TMath::Abs(xa) > 1E-12 )
+    {
+      newvalue = 100.0*( yb - ya ) / ya;
+    }
+  
+    Double_t yerr = 0.0;
+    
+    if ( dynamic_cast<TGraphErrors*>(&ga) && dynamic_cast<TGraphErrors*>(&gb) )
+    {
+        yerr = newvalue*AliAnalysisMuMuResult::ErrorAB(ya,ga.GetEY()[i],
+                                                       yb,gb.GetEY()[i]);
+    }
+  
+    vx.push_back(xa);
+    vxerr.push_back(0.5);
+    vy.push_back(newvalue);
+    vyerr.push_back(yerr);
+  }
+  
+  
+  return new TGraphErrors(vx.size(),&vx[0],&vy[0],&vxerr[0],&vyerr[0]);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuGraphUtil::StyleGraph(TGraph& g, UInt_t index) const
+{
+  if ( index >= fAttFill.size() ) index = 0;
+  
+  static_cast<TAttFill&>(g) = fAttFill[index];
+  static_cast<TAttLine&>(g) = fAttLine[index];
+  static_cast<TAttMarker&>(g) = fAttMarker[index];
+  
+  g.GetYaxis()->SetLabelColor(fAttYaxis[index].GetLabelColor());
+  g.GetYaxis()->SetTitleColor(fAttYaxis[index].GetTitleColor());
+  
+  //static_cast<TAttAxis&>((*g.GetYaxis())) = fAttYaxis[index];
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuGraphUtil::UnCompact(TGraph& g)
+{
+  /// Reverse operation of the Compact method
+  /// Only works if the labels of this graph represents run numbers. Otherwise
+  /// result is unpredictable ;-)
+  
+  if ( !g.GetN() ) return;
+  
+  //  Int_t run1 = TString(g.GetXaxis()->GetBinLabel(1)).Atoi();
+  //  Int_t run2 = TString(g.GetXaxis()->GetBinLabel(g.GetN())).Atoi();
+  
+  std::vector<double> runs;
+  Int_t runNumber;
+  
+  for ( Int_t i = 0; i < g.GetN(); ++i )
+  {
+    runNumber = TString(g.GetXaxis()->GetBinLabel(i+1)).Atoi();
+    runs.push_back(runNumber*1.0);
+  }
+  
+  runs.push_back(runNumber+1);
+  
+  g.GetXaxis()->Set(g.GetN(),&runs[0]);
+  
+  for ( Int_t i = 0; i < g.GetN(); ++i )
+  {
+    g.SetPoint(i,runs[i],g.GetY()[i]);
+  }
+  
+  g.GetXaxis()->SetNoExponent();
+  
+}
+
+
diff --git a/PWG/muondep/AliAnalysisMuMuGraphUtil.h b/PWG/muondep/AliAnalysisMuMuGraphUtil.h
new file mode 100644 (file)
index 0000000..66c5d2e
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef ALIANALYSISMUMUGRAPHUTIL_H
+#define ALIANALYSISMUMUGRAPHUTIL_H
+
+#ifndef ROOT_TObject
+#  include "TObject.h"
+#endif
+
+#include <vector>
+#include <string>
+#include <set>
+
+class TGraph;
+class TGraphErrors;
+class TCanvas;
+class TObjArray;
+
+#include "TAttFill.h"
+#include "TAttMarker.h"
+#include "TAttLine.h"
+#include "TAttAxis.h"
+#include "TString.h"
+
+class AliAnalysisMuMuGraphUtil : public TObject
+{
+public:
+  
+  AliAnalysisMuMuGraphUtil(const char* ocdbpath="raw://");
+  virtual ~AliAnalysisMuMuGraphUtil() {}
+
+  static TGraphErrors* Combine(TObjArray& graph, Bool_t compact);
+  
+  static void Compact(TGraph& g);
+  
+  void DefaultStyle();
+
+  TCanvas* DrawWith2Scales(TGraph& g1, TGraph& g2, const char* canvasName="c1");
+
+  static Int_t GetRunNumber(const TGraph& g, Int_t i);
+
+  void GetRuns(std::set<int>& runs, TGraph& graph) const;
+
+  static Bool_t IsCompact(TGraph& g);
+  
+  void PlotSameWithLegend(TObjArray& a, Double_t ymin, Double_t ymax) const;
+
+  void ShouldDrawPeriods(Bool_t value) { fShouldDrawPeriods = value; }
+
+  void StyleGraph(TGraph& graph, UInt_t index) const;
+  
+  static void UnCompact(TGraph& g);
+  
+  static void GetYMinAndMax(TGraph& g, Double_t& ymin, Double_t& ymax);
+  
+  static TGraph* RelDif(TGraph& ga, TGraph& gb);
+
+  
+private:
+  AliAnalysisMuMuGraphUtil(const AliAnalysisMuMuGraphUtil& rhs); // not implemented
+  AliAnalysisMuMuGraphUtil& operator=(const AliAnalysisMuMuGraphUtil& rhs); // not implemented
+
+  TString fOCDBPath; // OCDB path
+
+  std::vector<TAttLine> fAttLine; // line attributes
+  std::vector<TAttMarker> fAttMarker; // marker attributes
+  std::vector<TAttFill> fAttFill; // fill attributes
+  std::vector<TAttAxis> fAttXaxis; // x-axis attributes
+  std::vector<TAttAxis> fAttYaxis; // y-axis attributes
+  std::vector<std::string> fDrawOptions; // draw options
+  
+  Bool_t fShouldDrawPeriods; // draw period names on top of graphs
+  
+  ClassDef(AliAnalysisMuMuGraphUtil,0) // utility class to modify/plot graphs
+};
+
+#endif
diff --git a/PWG/muondep/AliAnalysisMuMuJpsiResult.cxx b/PWG/muondep/AliAnalysisMuMuJpsiResult.cxx
new file mode 100644 (file)
index 0000000..fe241cd
--- /dev/null
@@ -0,0 +1,1290 @@
+/**************************************************************************
+ * 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.                  *
+ **************************************************************************/
+
+///
+/// Class to hold results about J/psi 
+/// like number of of J/psi (before and after Acc x Eff correction),
+/// Acc x Eff correction, Yield, RAB, etc...
+///
+/// author: Laurent Aphecetche (Subatech)
+///
+
+#include "AliAnalysisMuMuJpsiResult.h"
+
+ClassImp(AliAnalysisMuMuJpsiResult)
+
+#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 "AliLog.h"
+#include <map>
+
+namespace {
+  
+  const std::map<std::string,Double_t>& MassMap()
+  {
+    /// a simple map of masses...
+    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 funcCB(Double_t* xx, Double_t* par)
+  {
+    /// Crystal ball
+    
+    Double_t norm = 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 norm*TMath::Exp(-0.5*y*y);
+    }
+    else 
+    {
+      return norm*a*TMath::Power(b-y,-n);
+    }
+  }
+  
+  Double_t funcJpsiGCBE(Double_t* xx, Double_t* par)
+  {
+    /// crystal ball + expo + gaussian
+    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 funcCB2(Double_t* xx, Double_t* par)
+  {
+    /// CB2 = extended crystal ball
+    
+    Double_t norm = 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 norm*c*TMath::Power(d+y,-nprime);
+    }
+    else if ( y > alpha*-1.0 ) 
+    {
+      return norm*TMath::Exp(-0.5*y*y);
+    }
+    else 
+    {
+      return norm*a*TMath::Power(b-y,-n);
+    }
+  }
+  
+  
+  Double_t funcJpsiNA48(Double_t*x, Double_t* par)
+  {
+    /// Fit function from e.q. 4.8 of Ruben's PhD.
+    Double_t c1 = par[0];
+    Double_t c2 = par[1];
+    Double_t d1 = par[2];
+    Double_t d2 = par[3];
+    Double_t g1 = par[4];
+    Double_t g2 = par[5];
+    Double_t m0 = par[6];
+    Double_t sigma1 = par[7];
+    Double_t sigma2 = par[8];
+    Double_t b1 = par[9];
+    Double_t b2 = par[10];
+    Double_t norm = par[11];
+    
+    Double_t m = x[0];
+    
+    Double_t rv(0);
+    
+    if ( m <= c1*m0 )
+    {
+      Double_t e = d1-g1*TMath::Sqrt(c1*m0-m);
+      rv = TMath::Power(b1*(c1*m0-m),e);
+      rv += sigma1;
+    }
+    else if( m >= c1*m0 && m <= m0 )
+    {
+      rv = sigma1;
+    }
+    else if ( m >= m0 && m < c2*m0 )
+    {
+      rv = sigma2;
+    }
+    else if( m >= c2*m0 )
+    {
+      Double_t e = d2-g2*TMath::Sqrt(m-c2*m0);
+      rv = TMath::Power(b2*(m-c2*m0),e);
+      rv += sigma2;
+    }
+    
+    return norm*TMath::Exp(-(m-m0)*(m-m0)/(2.0*rv*rv));
+  }
+  
+  //------------------------------------------------------------------------------
+  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 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)
+  {
+    /// 2 extended crystal balls + variable width gaussian
+    /// width of the second CB related to the first (free) one.
+    
+    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);
+  }
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuJpsiResult::AliAnalysisMuMuJpsiResult(TRootIOCtor* /*io*/) :
+AliAnalysisMuMuResult("",""),
+fNofRuns(),
+fNofTriggers(-1),
+fMinv(0x0),
+fBin(),
+fRebin(0),
+fTriggerClass(),
+fEventSelection(),
+fPairSelection(),
+fCentralitySelection()
+{
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuJpsiResult::AliAnalysisMuMuJpsiResult(const TH1& hminv) :
+AliAnalysisMuMuResult("",""),
+fNofRuns(1),
+fNofTriggers(-1),
+fMinv(0x0),
+fBin(),
+fRebin(0),
+fTriggerClass(),
+fEventSelection(),
+fPairSelection(),
+fCentralitySelection()
+{
+  SetMinv(hminv);
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuJpsiResult::AliAnalysisMuMuJpsiResult(const TH1& hminv,
+                                             const char* fitType,
+                                             Int_t nrebin)
+:
+AliAnalysisMuMuResult(Form("%s:%d",fitType,nrebin),""),
+fNofRuns(1),
+fNofTriggers(-1),
+fMinv(0x0),
+fBin(),
+fRebin(nrebin),
+fTriggerClass(),
+fEventSelection(),
+fPairSelection(),
+fCentralitySelection()
+{
+  SetMinv(hminv);
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuJpsiResult::AliAnalysisMuMuJpsiResult(const TH1& hminv,
+                                             const char* triggerName,
+                                             const char* eventSelection,
+                                             const char* pairSelection,
+                                             const char* centSelection,
+                                             const AliAnalysisMuMuBinning::Range& bin)
+:
+AliAnalysisMuMuResult(Form("%s-%s-%s-%s",triggerName,eventSelection,pairSelection,centSelection),""),
+fNofRuns(1),
+fNofTriggers(-1),
+fMinv(0x0),
+fBin(bin),
+fRebin(1),
+fTriggerClass(triggerName),
+fEventSelection(eventSelection),
+fPairSelection(pairSelection),
+fCentralitySelection(centSelection)
+{
+  SetMinv(hminv);
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuJpsiResult::AliAnalysisMuMuJpsiResult(const AliAnalysisMuMuJpsiResult& rhs)
+:
+AliAnalysisMuMuResult(rhs),
+fNofRuns(rhs.NofRuns()),
+fNofTriggers(rhs.NofTriggers()),
+fMinv(0x0),
+fBin(rhs.Bin()),
+fRebin(rhs.fRebin),
+fTriggerClass(rhs.fTriggerClass),
+fEventSelection(rhs.fEventSelection),
+fPairSelection(rhs.fPairSelection),
+fCentralitySelection(rhs.fCentralitySelection)
+{
+  /// 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());
+  }  
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuJpsiResult& AliAnalysisMuMuJpsiResult::operator=(const AliAnalysisMuMuJpsiResult& rhs)
+{
+  /// Assignment operator
+  
+  if (this!=&rhs)
+  {
+    static_cast<AliAnalysisMuMuResult&>(*this) = static_cast<const AliAnalysisMuMuResult&>(rhs);
+    delete fMinv;
+
+    if ( rhs.fMinv )
+    {
+      fMinv = static_cast<TH1*>(rhs.fMinv->Clone());
+    }
+    
+    fNofRuns = rhs.NofRuns();
+    fNofTriggers = rhs.NofTriggers();
+    fBin = rhs.Bin();
+    fRebin = rhs.fRebin;    
+  }
+  
+  return *this;
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuJpsiResult::~AliAnalysisMuMuJpsiResult()
+{
+  // dtor
+  delete fMinv;
+}
+
+//_____________________________________________________________________________
+const AliAnalysisMuMuBinning::Range& AliAnalysisMuMuJpsiResult::Bin() const
+{
+  /// Get the bin of this result
+  if ( !Mother() ) return fBin;
+  else return Mother()->Bin();
+}
+
+//_____________________________________________________________________________
+TObject* AliAnalysisMuMuJpsiResult::Clone(const char* /*newname*/) const
+{
+  /// Clone this result
+  return new AliAnalysisMuMuJpsiResult(*this);
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuJpsiResult::Correct(const AliAnalysisMuMuJpsiResult& 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;
+  }
+  else
+  {
+    AliError(Form("Result does not have Nof%s : cannot correct it !",particle));
+  }
+  return kFALSE;
+}
+
+//_____________________________________________________________________________
+Double_t AliAnalysisMuMuJpsiResult::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);
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuJpsiResult* AliAnalysisMuMuJpsiResult::FitJpsiGCBE(TH1& h)
+{
+  /// Fit Jpsi spectra with crystal ball + gaussian + exponential
+  
+  std::cout << "Fit with jpsi alone (gaus + CB + expo)" << std::endl;
+  
+  Int_t nrebin = fMinv->GetXaxis()->GetNbins() / h.GetXaxis()->GetNbins();
+  
+  AliAnalysisMuMuJpsiResult* r = new AliAnalysisMuMuJpsiResult(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 = "QSI+";
+  
+  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;
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuJpsiResult* AliAnalysisMuMuJpsiResult::FitJpsi(TH1& h)
+{
+  /// Fit Jpsi spectra using extended crystall ball (CB2) with free tails
+  
+  StdoutToAliDebug(1,std::cout << "Fit with jpsi alone" << std::endl;);
+
+  Int_t nrebin = fMinv->GetXaxis()->GetNbins() / h.GetXaxis()->GetNbins();
+  
+  AliAnalysisMuMuJpsiResult* r = new AliAnalysisMuMuJpsiResult(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","alphaLow","nLow","mean","sigma","alphaUp","nUp");
+  fitTotal->SetParameters(h.GetMaximum(),1,5,3.1,0.07,1.5,3);
+  fitTotal->SetParLimits(0,0,h.GetMaximum()*2); // N
+  fitTotal->SetParLimits(1,0,10); // alpha
+  fitTotal->SetParLimits(2,0.1,10); // n
+  fitTotal->SetParLimits(3,3,3.15); // mean
+  fitTotal->SetParLimits(4,0.01,1); // sigma
+  fitTotal->SetParLimits(5,0,10); // alpha
+  fitTotal->SetParLimits(6,0.1,10); // n
+  
+  hfit->Fit(fitTotal,"QSER+","",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;
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuJpsiResult* AliAnalysisMuMuJpsiResult::FitJpsiCB2VWG(const TH1& h)
+{
+  /// Fit Jpsi spectra using extended crystal ball (CB2) + variable width gaussian (VWG)
+  
+  StdoutToAliDebug(1,std::cout << "Fit with jpsi VWG" << std::endl;);
+  
+  Int_t nrebin = fMinv->GetXaxis()->GetNbins() / h.GetXaxis()->GetNbins();
+  
+  AliAnalysisMuMuJpsiResult* r = new AliAnalysisMuMuJpsiResult(h,"JPSICB2VWG",nrebin);
+  
+  
+  TH1* hfit = r->Minv();
+  
+  const Double_t xmin(2.0);
+  const Double_t xmax(5.0);
+  
+//  // 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'
+
+  TF1* fitTotal = new TF1("fitTotal",fitFunctionCB2VWG,xmin,xmax,11);
+  fitTotal->SetParNames("kVWG","mVWG","sVWG1","sVWG2","norm","mean","sigma","alpha","n","alpha'","n'");
+  
+  fitTotal->SetParameter(0, 10000.); // kVWG
+  fitTotal->SetParameter(1, 1.9); // mVWG
+  
+  fitTotal->SetParameter(2, 0.5); // sVWG1
+  fitTotal->SetParLimits(2, 0., 100.);
+  
+  fitTotal->SetParameter(3, 0.3); // sVWG2
+  fitTotal->SetParLimits(3, 0., 100.);
+  
+  fitTotal->SetParameter(4, h.GetMaximum()); // norm
+  
+  fitTotal->SetParameter(5, 3.1); // mean
+  fitTotal->SetParLimits(5, 3.0, 3.2);
+  
+  fitTotal->SetParameter(6, 0.08); // sigma
+  fitTotal->SetParLimits(6, 0.04, 0.20);
+  
+  fitTotal->SetParameter(7,1.0); // alpha
+  fitTotal->SetParameter(8,5); // n
+  fitTotal->SetParameter(9,2.0); // alpha'
+  fitTotal->SetParameter(10,4); // n'
+  
+//  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 = "QSIER"; //+";
+  
+  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;
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuJpsiResult* AliAnalysisMuMuJpsiResult::FitJpsi2CB2VWG(const TH1& h,
+                                                             Double_t alphaLow,
+                                                             Double_t nLow,
+                                                             Double_t alphaUp,
+                                                             Double_t nUp)
+{
+  /// Fit using extended crystal ball + variable width gaussian
+  
+  StdoutToAliDebug(1,std::cout << Form("Fit with jpsi + psiprime VWG alphaLow=%5.2f nLow=%5.2f alphaUp=%5.2f nUp=%5.2f",
+                                       alphaLow,nLow,alphaUp,nUp) << std::endl;);
+  
+  Int_t nrebin = fMinv->GetXaxis()->GetNbins() / h.GetXaxis()->GetNbins();
+  
+  TString resultName("JPSI2CB2VWG");
+  if ( alphaLow > 0 )
+  {
+    resultName += TString::Format("alphaLow=%5.2f",alphaLow);
+  }
+  if ( nLow > 0 )
+  {
+    resultName += TString::Format("nLow=%5.2f",nLow);
+  }
+  if ( alphaUp > 0 )
+  {
+    resultName += TString::Format("alphaUp=%5.2f",alphaUp);
+  }
+  if ( nUp > 0 )
+  {
+    resultName += TString::Format("nUp=%5.2f",nUp);
+  }
+  resultName.ReplaceAll(" ","");
+  
+  AliAnalysisMuMuJpsiResult* r = new AliAnalysisMuMuJpsiResult(h,resultName.Data(),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.1);
+  fitTotal->SetParLimits(5, 3.08, 3.2);
+  fitTotal->SetParameter(6, 0.08);
+  fitTotal->SetParLimits(6, 0.05, 0.15);
+  
+//  r = FitJpsi2CB2VWG(*hminv,0.93,5.59,2.32,3.39);
+
+  if ( alphaLow > 0 )
+  {
+    fitTotal->FixParameter(7, alphaLow);
+  }
+  else
+  {
+    fitTotal->SetParameter(7,0.9);
+    fitTotal->SetParLimits(7,0.1,10.0);
+  }
+  
+  if ( nLow > 0 )
+  {
+    fitTotal->FixParameter(8, nLow);
+  }
+  else
+  {
+    fitTotal->SetParameter(8,5.0);
+    fitTotal->SetParLimits(8,0.0,10.0);
+  }
+  
+  if ( alphaUp > 0 )
+  {
+    fitTotal->FixParameter(9, alphaUp);
+  }
+  else
+  {
+    fitTotal->SetParameter(9, 2.0);
+    fitTotal->SetParLimits(9,0.1,10.0);
+  }
+  
+  if ( nUp > 0 )
+  {
+    fitTotal->FixParameter(10, nUp);    
+  }
+  else
+  {
+    fitTotal->SetParameter(10,3.0);
+    fitTotal->SetParLimits(10,0.0,10.0);
+  }
+  
+  fitTotal->SetParameter(11, 10.);
+
+  const char* fitOption = "QSER"; //+";
+  
+  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;
+}
+
+//_____________________________________________________________________________
+AliAnalysisMuMuJpsiResult* AliAnalysisMuMuJpsiResult::FitJpsiNA48(const TH1& h)
+{
+  /// fit using functional form from Ruben Shahoyan's thesis (2001) (eq. 4.8.)
+  
+  StdoutToAliDebug(1,std::cout << "Fit with jpsi NA50 Ruben eq. 4.8" << std::endl;);
+  
+  Int_t nrebin = fMinv->GetXaxis()->GetNbins() / h.GetXaxis()->GetNbins();
+  
+  AliAnalysisMuMuJpsiResult* r = new AliAnalysisMuMuJpsiResult(h,"JPSINA",nrebin);
+  
+  TH1* hfit = r->Minv();
+  
+  const Double_t xmin(2.0);
+  const Double_t xmax(5.0);
+  
+  TF1* fitTotal = new TF1("fitTotal",funcJpsiNA48,xmin,xmax,12);
+  
+  fitTotal->SetParName( 0, "c1");
+  fitTotal->FixParameter(0,0.97);
+  
+  fitTotal->SetParName( 1, "c2");
+  fitTotal->FixParameter(1,1.05);
+  
+  fitTotal->SetParName( 2, "d1");
+  fitTotal->SetParameter(2,0.0);
+  fitTotal->SetParLimits(2,0,1);
+  
+  fitTotal->SetParName( 3, "d2");
+  fitTotal->SetParameter(3,0.0);
+  fitTotal->SetParLimits(3,0,1);
+  
+  fitTotal->SetParName( 4, "g1");
+  fitTotal->SetParameter(4,0.0);
+  fitTotal->SetParLimits(4,0.0,1);
+  
+  fitTotal->SetParName( 5, "g2");
+  fitTotal->SetParameter(5,0.0);
+  fitTotal->SetParLimits(5,0.0,1);
+  
+  fitTotal->SetParName( 6, "m0");
+  fitTotal->SetParameter(6,3.1);
+  fitTotal->SetParLimits(6,2.8,3.4);
+
+  fitTotal->SetParName( 7, "sigma1");
+  fitTotal->SetParameter(7,0.05);
+  fitTotal->SetParLimits(7,0.01,0.2);
+  
+  fitTotal->SetParName( 8, "sigma2");
+  fitTotal->SetParameter(8,0.05);
+  fitTotal->SetParLimits(8,0.01,0.2);
+
+  fitTotal->SetParName( 9, "b1");
+  fitTotal->SetParameter(9,1.0);
+  fitTotal->SetParLimits(9,0,1);
+  
+  fitTotal->SetParName(10, "b2");
+  fitTotal->SetParameter(10,1.0);
+  fitTotal->SetParLimits(10,0,1);
+  
+  fitTotal->SetParName(11, "norm");
+  fitTotal->SetParameter(11,h.GetMaximum());
+  
+  const char* fitOption = "QSIER"; //+";
+  
+  TFitResultPtr fitResult = hfit->Fit(fitTotal,fitOption,"");
+  
+  r->Set("MeanJpsi",fitTotal->GetParameter(6),fitTotal->GetParError(6));
+  r->Set("SigmaJpsi",
+         fitTotal->GetParameter(7)+fitTotal->GetParameter(8),
+         0.0);
+
+  double m = r->GetValue("MeanJpsi");
+  double s = r->GetValue("SigmaJpsi");
+  double n = 3.0;
+  
+  TLine* l1 = new TLine(m-n*s,0,m-n*s,fitTotal->GetParameter(11));
+  TLine* l2 = new TLine(m+n*s,0,m+n*s,fitTotal->GetParameter(11));
+  l1->SetLineColor(6);
+  l2->SetLineColor(6);
+  hfit->GetListOfFunctions()->Add(l1);
+  hfit->GetListOfFunctions()->Add(l2);
+  
+  double njpsi = fitTotal->Integral(m-n*s,m+n*s)/h.GetBinWidth(1);
+  double nerr = fitTotal->IntegralError(m-n*s,m+n*s)/h.GetBinWidth(1);
+  
+  r->Set("NofJpsi",njpsi,nerr);
+  
+  return r;
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuJpsiResult::AddFit(const char* fitType, Int_t npar, Double_t* par)
+{
+  // Add a fit to this result
+  
+  TString msg(Form("fitType=%s npar=%d par[]=",fitType,npar));
+  
+  for ( Int_t i = 0; i < npar; ++i )
+  {
+    msg += TString::Format("%e,",par[i]);
+  }
+  
+  msg += TString::Format(" minv=%p %d",fMinv,fMinv?TMath::Nint(fMinv->GetEntries()):0);
+  
+  if ( !fMinv ) return kFALSE;
+  
+  TString sFitType(fitType);
+  sFitType.ToUpper();
+  Int_t nrebin(1);
+  
+  if (sFitType.CountChar(':'))
+  {
+    Int_t index = sFitType.Index(":");
+    nrebin = TString(sFitType(index+1,sFitType.Length()-index-1)).Atoi();
+    sFitType = sFitType(0,index);
+  }
+  
+  msg += TString::Format(" nrebin=%d",nrebin);
+  
+  AliDebug(1,msg.Data());
+  
+
+  if ( fMinv->GetEntries()<100 && !sFitType.Contains("COUNT")) return kFALSE;
+  
+  TH1* hminv = static_cast<TH1*>(fMinv->Clone());
+  
+  hminv->Rebin(nrebin);
+  hminv->SetDirectory(0);
+
+  AliAnalysisMuMuJpsiResult* r(0x0);
+  
+  if ( sFitType=="PSI1")
+  {
+    r = FitJpsi(*hminv);
+  }
+  else if ( sFitType == "PSILOW")
+  {
+    r = FitJpsi2CB2VWG(*hminv,-1,-1,-1,-1); // free tails
+  }
+  else if ( sFitType == "PSILOWMCTAILS" )
+  {
+    if ( npar!= 4 )
+    {
+      AliError("Cannot use PSILOWMCTAILS without being given the MC tails !");
+      delete hminv;
+      return kFALSE;
+    }
+    r = FitJpsi2CB2VWG(*hminv,par[0],par[1],par[2],par[3]);
+    if (r)
+    {
+      r->SetAlias("MCTAILS");
+    }
+  }
+  else if ( sFitType.BeginsWith("PSILOWALPHA") )
+  {
+    Float_t lpar[] = { 0.0, 0.0, 0.0, 0.0 };
+    
+    AliDebug(1,Form("sFitType=%s",sFitType.Data()));
+    
+    sscanf(sFitType.Data(),"PSILOWALPHALOW%fNLOW%fALPHAUP%fNUP%f",
+           &lpar[0],&lpar[1],&lpar[2],&lpar[3]);
+    
+    AliDebug(1,Form("PSILOW ALPHALOW=%f NLOW=%f ALPHAUP=%f NUP=%f",lpar[0],lpar[1],lpar[2],lpar[3]));
+    
+    if ( lpar[0] == 0.0 && lpar[1] == 0.0 && lpar[0] == 0.0 && lpar[1] == 0.0 )
+    {
+      AliError("Cannot work with zero tails !");
+    }
+    else
+    {
+      r = FitJpsi2CB2VWG(*hminv,lpar[0],lpar[1],lpar[2],lpar[3]);      
+    }
+  }
+  else if ( sFitType == "COUNTJPSI" )
+  {
+    r = new AliAnalysisMuMuJpsiResult(*hminv,"COUNTJPSI",1);
+    Double_t n = CountParticle(*hminv,"Jpsi");
+    r->Set("NofJpsi",n,TMath::Sqrt(n));
+  }
+  
+  
+  if ( r )
+  {
+    StdoutToAliDebug(1,r->Print(););
+    r->SetBin(Bin());
+    r->SetNofTriggers(NofTriggers());
+    r->SetNofRuns(NofRuns());
+
+    AdoptSubResult(r);
+  }
+  
+  delete hminv;
+  
+  return (r!=0x0);
+}
+
+//_____________________________________________________________________________
+Long64_t AliAnalysisMuMuJpsiResult::Merge(TCollection* list)
+{
+  /// Merge method
+  ///
+  /// Merge a list of AliAnalysisMuMuJpsiResult objects with this
+  /// Returns the number of merged objects (including this).
+  ///
+  /// Note that the merging is to be understood here as an weighted mean operation
+  ///
+  /// FIXME ! (compared to base class Merge, should only Minv merging ?)
+  
+  AliError("Implement me !");
+  if (!list) return 0;
+  
+  if (list->IsEmpty()) return 1;
+  
+  return 0;
+  
+}
+
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuJpsiResult::NofRuns() const
+{
+  /// Get the number of runs
+  if ( !Mother() ) return fNofRuns;
+  else return Mother()->NofRuns();
+}
+
+//_____________________________________________________________________________
+Int_t AliAnalysisMuMuJpsiResult::NofTriggers() const
+{
+  /// Get the number of triggers
+  
+  if ( !Mother() ) return fNofTriggers;
+  else return Mother()->NofTriggers();
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuJpsiResult::Print(Option_t* opt) const
+{
+  /// printout
+
+  std::cout << Form("NRUNS %d - NTRIGGER %10d - %s",
+                                      NofRuns(),
+                                      NofTriggers(),
+                                      fBin.AsString().Data());
+  
+  AliAnalysisMuMuResult::Print(opt);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuJpsiResult::PrintValue(const char* key, const char* opt, Double_t value, Double_t errorStat,
+                                           Double_t rms) const
+{
+  /// exclude the particles with zero stat
+  
+  const std::map<std::string,Double_t>& m = MassMap();
+
+  for( std::map<std::string,Double_t>::const_iterator it = m.begin(); it != m.end(); ++it )
+  {
+    TString particle(it->first.c_str());
+    
+    if (TString(key).Contains(particle.Data()))
+    {
+      if ( GetValue("Nof%s",particle.Data()) <= 0.0 ) return;
+    }
+  }
+  
+  AliAnalysisMuMuResult::PrintValue(key,opt,value,errorStat,rms);
+
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuJpsiResult::PrintParticle(const char* particle, const char* opt) const
+{
+  /// Print all information about one particule type
+  
+  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()),GetRMS(key->String()));
+  } 
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuJpsiResult::SetBin(const AliAnalysisMuMuBinning::Range& bin)
+{
+  /// Set the bin
+  
+  if (!Mother()) fBin = bin;
+  else Mother()->SetBin(bin);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuJpsiResult::SetNofInputParticles(const TH1& hminv)
+{
+  /// Set the number of input particle from the invariant mass spectra
+  
+  static const char* particleNames[] = { "Jpsi" , "PsiPrime", "Upsilon","UpsilonPrime" };
+
+  const std::map<std::string,Double_t>& m = MassMap();
+
+  for ( Int_t i = 0; i < 4; ++i )
+  {
+    std::map<std::string,Double_t>::const_iterator it = m.find(particleNames[i]);
+
+    Double_t sigma(-1.0);
+
+    if (it != m.end() )
+    {
+      sigma = it->second*0.1;
+    }
+
+    Double_t n = CountParticle(hminv,particleNames[i],sigma);
+
+    AliDebug(1,Form("i=%d particle %s n %e",i,particleNames[i],n));
+    
+    if ( n > 0 )
+    {
+      SetNofInputParticles(particleNames[i],TMath::Nint(n));
+    }
+  }
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuJpsiResult::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(SubResults());
+  AliAnalysisMuMuJpsiResult* r;
+  
+  while ( ( r = static_cast<AliAnalysisMuMuJpsiResult*>(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 AliAnalysisMuMuJpsiResult::SetNofRuns(Int_t n)
+{
+  if ( !Mother() ) fNofRuns=n;
+  else Mother()->SetNofRuns(n);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuJpsiResult::SetNofTriggers(Int_t n)
+{
+  if ( !Mother() ) fNofTriggers=n;
+  else Mother()->SetNofTriggers(n);
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuJpsiResult::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/AliAnalysisMuMuJpsiResult.h b/PWG/muondep/AliAnalysisMuMuJpsiResult.h
new file mode 100644 (file)
index 0000000..c82b1e2
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef ALIANALYSISMUMUJPSIRESULT_H
+#define ALIANALYSISMUMUJPSIRESULT_H
+
+/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * See cxx source for full Copyright notice                               */
+
+///
+/// AliAnalysisMuMuJpsiResult : helper class to store Jpsi results from
+/// AliAnalysisTaskMuMu
+///
+/// author : Laurent Aphecetche (Subatech)
+
+#include "TNamed.h"
+#include <TString.h>
+#include "AliAnalysisMuMuResult.h"
+#include "AliAnalysisMuMuBinning.h"
+
+class TH1;
+class THashList;
+class TF1;
+class TMap;
+
+class AliAnalysisMuMuJpsiResult : public AliAnalysisMuMuResult
+{
+  
+public:
+  
+  AliAnalysisMuMuJpsiResult(TRootIOCtor* io);
+  
+  AliAnalysisMuMuJpsiResult(const TH1& hminv);
+
+  AliAnalysisMuMuJpsiResult(const TH1& hminv,
+                        const char* fitType,
+                        Int_t nrebin);
+
+  AliAnalysisMuMuJpsiResult(const TH1& hminv,
+                        const char* triggerClass,
+                        const char* eventSelection,
+                        const char* pairSelection,
+                        const char* centSelection,
+                        const AliAnalysisMuMuBinning::Range& bin);
+  
+  AliAnalysisMuMuJpsiResult(const AliAnalysisMuMuJpsiResult& rhs);
+  AliAnalysisMuMuJpsiResult& operator=(const AliAnalysisMuMuJpsiResult& rhs);
+  
+  virtual ~AliAnalysisMuMuJpsiResult();
+
+  virtual TObject* Clone(const char* newname = "") const;
+  
+  Bool_t Correct(const AliAnalysisMuMuJpsiResult& other, const char* particle, const char* subResultName="");
+  
+  TH1* Minv() const { return fMinv; }
+  
+  Int_t NofTriggers() const;
+  
+  void SetNofTriggers(Int_t n);
+  
+  void Print(Option_t* opt="") const;
+  
+  Bool_t AddFit(const char* fitType, Int_t npar=0, Double_t* par=0x0);
+
+  AliAnalysisMuMuJpsiResult* CountJpsi(TH1& h);
+
+  AliAnalysisMuMuJpsiResult*  FitJpsi(TH1& h);
+
+  AliAnalysisMuMuJpsiResult* FitJpsiNA48(const TH1& h);
+  AliAnalysisMuMuJpsiResult* FitJpsiCB2VWG(const TH1& h);
+  AliAnalysisMuMuJpsiResult* FitJpsi2CB2VWG(const TH1& h, Double_t alphaLow=-1.0, Double_t nLow=-1.0, Double_t alphaUp=-1.0, Double_t nUp=-1.0);
+  
+  AliAnalysisMuMuJpsiResult* FitJpsiGCBE(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);
+
+  Long64_t Merge(TCollection* list);
+
+  static Double_t CountParticle(const TH1& hminv, const char* particle, Double_t sigma=-1.0);
+  
+  virtual AliAnalysisMuMuJpsiResult* Mother() const { return static_cast<AliAnalysisMuMuJpsiResult*>(AliAnalysisMuMuResult::Mother()); }
+
+  void PrintValue(const char* key, const char* opt, Double_t value, Double_t errorStat, Double_t rms=0.0) const;
+  
+private:
+  
+  enum EIndex
+  {
+    kValue=0,
+    kErrorStat=1
+  };
+  
+  void PrintParticle(const char* particle, const char* opt) 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
+  Int_t fRebin; // rebin level of minv spectra
+  
+  TString fTriggerClass; // trigger class for this result
+  TString fEventSelection; // event selection for this result
+  TString fPairSelection; // pair selection for this result
+  TString fCentralitySelection; // centrality selection for this result
+
+  ClassDef(AliAnalysisMuMuJpsiResult,1) // a class to hold invariant mass analysis results (counts, yields, AccxEff, R_AB, etc...)
+};
+
+#endif
index b783c24a4a5a8bea439075acaa1c76acd9674ee1..a44408800e2c5911a674f5387585ff8d4b3dcd19 100644 (file)
  * provided "as is" without express or implied warranty.                  *
  **************************************************************************/
 
-
-// $Id$
+///
+/// Base class to hold a set of results for the same quantity,
+/// computed using various methods, each with their errors
+///
+/// author: Laurent Aphecetche (Subatech)
+///
 
 #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"
@@ -31,509 +31,39 @@ ClassImp(AliAnalysisMuMuResult)
 #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()
-{
-  /// a simple map of masses...
-  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 funcCB(Double_t* xx, Double_t* par)
-{
-  /// Crystal ball
-  
-  Double_t norm = 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 norm*TMath::Exp(-0.5*y*y);
-  }
-  else 
-  {
-    return norm*a*TMath::Power(b-y,-n);
-  }
-}
-
-Double_t funcJpsiGCBE(Double_t* xx, Double_t* par)
-{
-  /// crystal ball + expo + gaussian
-  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)
-{
-  // custom fit for jpsi + psi prime
-  
-  Double_t norm = 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 = norm*c*TMath::Power(d+y,-nprime);
-  }
-  else if ( y > alpha*-1.0 ) 
-  {
-    cb = norm*TMath::Exp(-0.5*y*y);
-  }
-  else 
-  {
-    cb = norm*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)
-{
-  /// CB2 = extended crystal ball
-  
-  Double_t norm = 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 norm*c*TMath::Power(d+y,-nprime);
-  }
-  else if ( y > alpha*-1.0 ) 
-  {
-    return norm*TMath::Exp(-0.5*y*y);
-  }
-  else 
-  {
-    return norm*a*TMath::Power(b-y,-n);
-  }
-}
-
-Double_t funcJpsiPsiPrime(Double_t* xx, Double_t* par)
-{
-  /// CB + CB2
-  
-  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)
-{
-  // CB + expo + pol2
-  
-  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;
-}
-
-Double_t funcJpsiNA48(Double_t*x, Double_t* par)
-{
-  /// Fit function from e.q. 4.8 of Ruben's PhD.
-  Double_t c1 = par[0];
-  Double_t c2 = par[1];
-  Double_t d1 = par[2];
-  Double_t d2 = par[3];
-  Double_t g1 = par[4];
-  Double_t g2 = par[5];
-  Double_t m0 = par[6];
-  Double_t sigma1 = par[7];
-  Double_t sigma2 = par[8];
-  Double_t b1 = par[9];
-  Double_t b2 = par[10];
-  Double_t norm = par[11];
-  
-  Double_t m = x[0];
-  
-  Double_t rv(0);
-  
-  if ( m <= c1*m0 )
-  {
-    Double_t e = d1-g1*TMath::Sqrt(c1*m0-m);
-    rv = TMath::Power(b1*(c1*m0-m),e);
-    rv += sigma1;
-  }
-  else if( m >= c1*m0 && m <= m0 )
-  {
-    rv = sigma1;
-  }
-  else if ( m >= m0 && m < c2*m0 )
-  {
-    rv = sigma2;
-  }
-  else if( m >= c2*m0 )
-  {
-    Double_t e = d2-g2*TMath::Sqrt(m-c2*m0);
-    rv = TMath::Power(b2*(m-c2*m0),e);
-    rv += sigma2;
-  }
-  
-  return norm*TMath::Exp(-(m-m0)*(m-m0)/(2.0*rv*rv));
-}
-
-const char* NormalizeName(const char* name, const char* suffix)
-{
-  /// Remove - and / from the name, and adds _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)
-{
-  /// 2 extended crystal balls + variable width gaussian
-  /// width of the second CB related to the first (free) one.
-  
-  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(),
+AliAnalysisMuMuResult::AliAnalysisMuMuResult(const char* name, const char* title) :
+TNamed(name,title),
 fSubResults(0x0),
 fMap(0x0),
 fMother(0x0),
 fKeys(0x0),
 fWeight(0.0),
-fRebin(0),
-fTriggerClass(),
-fEventSelection(),
-fPairSelection(),
-fCentralitySelection(),
-fAlias()
+fAlias(),
+fSubResultsToBeIncluded(0x0)
 {
-}
-
-//_____________________________________________________________________________
-AliAnalysisMuMuResult::AliAnalysisMuMuResult(const TH1& hminv)
-:
-  TNamed("",""),
-  fNofRuns(1),
-  fNofTriggers(-1),
-  fMinv(0x0),
-  fBin(),
-  fSubResults(0x0),
-  fMap(0x0),
-  fMother(0x0),
-fKeys(0x0),
-fWeight(0.0),
-fRebin(0),
-fTriggerClass(),
-fEventSelection(),
-fPairSelection(),
-fCentralitySelection(),
-fAlias()
-{
-  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),
-fRebin(nrebin),
-fTriggerClass(),
-fEventSelection(),
-fPairSelection(),
-fCentralitySelection(),
-fAlias()
-{
-  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),
-fRebin(1),
-fTriggerClass(triggerName),
-fEventSelection(eventSelection),
-fPairSelection(pairSelection),
-fCentralitySelection(centSelection),
-fAlias()
-{
-  SetMinv(hminv);
+  /// default ctor
 }
 
 //_____________________________________________________________________________
 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),
-fRebin(rhs.fRebin),
-fTriggerClass(rhs.fTriggerClass),
-fEventSelection(rhs.fEventSelection),
-fPairSelection(rhs.fPairSelection),
-fCentralitySelection(rhs.fCentralitySelection),
-fAlias()
+fAlias(),
+fSubResultsToBeIncluded(0x0)
 {
   /// 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());
@@ -548,6 +78,12 @@ fAlias()
   {
     fAlias = rhs.fAlias;
   }
+  
+  if ( rhs.fSubResultsToBeIncluded )
+  {
+    fSubResultsToBeIncluded = static_cast<TList*>(rhs.fSubResultsToBeIncluded->Clone());
+  }
+
 }
 
 //_____________________________________________________________________________
@@ -557,19 +93,14 @@ AliAnalysisMuMuResult& AliAnalysisMuMuResult::operator=(const AliAnalysisMuMuRes
   
   if (this!=&rhs)
   {
-    delete fMinv;
     delete fMap;
     delete fSubResults;
+    delete fSubResultsToBeIncluded;
     
-    fMinv = 0x0;
     fMap = 0x0;
     fSubResults = 0x0;
     fKeys = 0x0;
-    
-    if ( rhs.fMinv )
-    {
-      fMinv = static_cast<TH1*>(rhs.fMinv->Clone());
-    }
+    fSubResultsToBeIncluded = 0x0;
     
     if (rhs.fSubResults)
     {
@@ -581,14 +112,14 @@ AliAnalysisMuMuResult& AliAnalysisMuMuResult::operator=(const AliAnalysisMuMuRes
       fMap = static_cast<TMap*>(rhs.fMap->Clone());
     }
 
+    if ( rhs.fSubResultsToBeIncluded )
+    {
+      fSubResultsToBeIncluded = static_cast<TList*>(rhs.fSubResultsToBeIncluded->Clone());
+    }
+
     static_cast<TNamed&>(*this)=rhs;
-    
-    fNofRuns = rhs.NofRuns();
-    fNofTriggers = rhs.NofTriggers();
-    fBin = rhs.Bin();
+
     fWeight = rhs.fWeight;
-    fRebin = rhs.fRebin;
-    
     fAlias="";
     
     if ( rhs.fAlias.Length() > 0 )
@@ -605,17 +136,24 @@ AliAnalysisMuMuResult::~AliAnalysisMuMuResult()
 {
   // dtor
   delete fMap;
-  delete fMinv;
   delete fSubResults;
   delete fKeys;
+  delete fSubResultsToBeIncluded;
 }
 
 //_____________________________________________________________________________
-const AliAnalysisMuMuBinning::Range& AliAnalysisMuMuResult::Bin() const
+void AliAnalysisMuMuResult::AdoptSubResult(AliAnalysisMuMuResult* r)
 {
-  /// Get the bin of this result
-  if ( !Mother() ) return fBin;
-  else return Mother()->Bin();
+  /// Adopt (i.e. becomes owner) of a subresult
+  if (!fSubResults)
+  {
+    fSubResults = new TObjArray;
+    fSubResults->SetOwner(kTRUE);
+  }
+
+  fSubResults->Add(r);
+  
+  SubResultsToBeIncluded()->Add(new TObjString(r->Alias()));
 }
 
 //_____________________________________________________________________________
@@ -625,1292 +163,233 @@ TObject* AliAnalysisMuMuResult::Clone(const char* /*newname*/) const
   return new AliAnalysisMuMuResult(*this);
 }
 
+
 //_____________________________________________________________________________
-Bool_t AliAnalysisMuMuResult::Correct(const AliAnalysisMuMuResult& other, const char* particle, const char* subResultName)
+Double_t AliAnalysisMuMuResult::ErrorAB(Double_t a, Double_t aerr, Double_t b, Double_t berr)
 {
-  /// Assuming other has an AccxEff entry, correct this value by AccxEff of other
+  /// Compute the quadratic sum of 2 errors
+
+  Double_t e(0.0);
   
-  if ( HasValue(Form("Nof%s",particle)) )
+  if ( TMath::Abs(a) > 1E-12 )
   {
-    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;
+    e += (aerr*aerr)/(a*a);
   }
-  else
+  
+  if ( TMath::Abs(b) > 1E-12 )
   {
-    AliError(Form("Result does not have Nof%s : cannot correct it !",particle));
+    e += (berr*berr)/(b*b);
   }
-  return kFALSE;
+  
+  return TMath::Sqrt(e);
 }
 
 //_____________________________________________________________________________
-Double_t AliAnalysisMuMuResult::CountParticle(const TH1& hminv, const char* particle, Double_t sigma)
+Double_t AliAnalysisMuMuResult::ErrorABC(Double_t a, Double_t aerr, Double_t b, Double_t berr, Double_t c, Double_t cerror)
 {
-  /// Count the number of entries in an invariant mass range
-  
-  const std::map<std::string,Double_t>& m = MassMap();
+  /// Compute the quadratic sum of 3 errors
   
-  std::map<std::string,Double_t>::const_iterator it = m.find(particle);
+  Double_t e(0.0);
   
-  if ( it == m.end() )
+  if ( TMath::Abs(a) > 1E-12 )
   {
-    AliErrorClass(Form("Don't know the mass of particle %s",particle));
-    return 0.0;
+    e += (aerr*aerr)/(a*a);
   }
   
-  Double_t mass = it->second;
-  
-  if ( sigma < 0 )
+  if ( TMath::Abs(b) > 1E-12 )
   {
-    AliDebugClass(1,Form("Oups. Got a sigma of %e for particle %s !",sigma,particle));
-    return hminv.Integral();
+    e += (berr*berr)/(b*b);
   }
   
-  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)));
+  if ( TMath::Abs(c) > 1E-12 )
+  {
+    e += (cerror*cerror)/(c*c);
+  }
   
-  return hminv.Integral(b1,b2);
+  return TMath::Sqrt(e);
 }
 
-/*
 //_____________________________________________________________________________
-void AliAnalysisMuMuResult::FitJpsiPsiPrimeCustom(TH1& h)
+Double_t AliAnalysisMuMuResult::ErrorABCD(Double_t a, Double_t aerr, Double_t b, Double_t berr, Double_t c, Double_t cerror, Double_t d, Double_t derror)
 {
-  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);
+  /// Compute the quadratic sum of 4 errors
   
-  TFitResultPtr rcb = h.Fit(fcb,fitOption,"",2.9,3.3);
-
-  if (!rcb.Get())
+  Double_t e(0.0);
+  
+  if ( TMath::Abs(a) > 1E-12 )
   {
-    return;
+    e += (aerr*aerr)/(a*a);
   }
   
-  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 )
+  if ( TMath::Abs(b) > 1E-12 )
   {
-    for ( int ix = 1; ix < 3; ++ix )
-    {
-      covarianceMatrixPrime[ix][iy] = (r->GetCovarianceMatrix())(ix+2,iy+2);
-    }
+    e += (berr*berr)/(b*b);
   }
   
-  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 )
+  if ( TMath::Abs(c) > 1E-12 )
   {
-    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);
-    }
+    e += (cerror*cerror)/(c*c);
   }
-  
-  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)
-{
-  /// Fit Jpsi spectra with crystal ball + gaussian + exponential
-  
-  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 )
+  if ( TMath::Abs(d) > 1E-12 )
   {
-    for ( int ix = 0; ix < 5; ++ix )
-    {
-      covarianceMatrix[ix][iy] = (fitResult->GetCovarianceMatrix())(ix+3,iy+3);
-    }
+    e += (derror*derror)/(d*d);
   }
-  
-  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));
-  
+  return TMath::Sqrt(e);
 }
 
 //_____________________________________________________________________________
-void AliAnalysisMuMuResult::FitJpsiECBE(TH1& h)
+Double_t AliAnalysisMuMuResult::ErrorABCDE(Double_t a, Double_t aerr, Double_t b, Double_t berr, Double_t c, Double_t cerror, Double_t d, Double_t derror, Double_t ee, Double_t eeerror)
 {
-  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);
+  /// Compute the quadratic sum of 4 errors
   
-  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;
+  Double_t e(0.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 )
+  if ( TMath::Abs(a) > 1E-12 )
   {
-    for ( int ix = 0; ix < 5; ++ix )
-    {
-      covarianceMatrix[ix][iy] = (r->GetCovarianceMatrix())(ix+2,iy+2);
-    }
+    e += (aerr*aerr)/(a*a);
   }
   
-
-  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)
-{
-  /// Fit Jpsi spectra using extended crystall ball (CB2) with free tails
-  
-  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","alphaLow","nLow","mean","sigma","alphaUp","nUp");
-  fitTotal->SetParameters(h.GetMaximum(),1,5,3.1,0.07,1.5,3);
-  fitTotal->SetParLimits(0,0,h.GetMaximum()*2); // N
-  fitTotal->SetParLimits(1,0,10); // alpha
-  fitTotal->SetParLimits(2,0.1,10); // n
-  fitTotal->SetParLimits(3,3,3.1); // mean
-  fitTotal->SetParLimits(4,0.01,1); // sigma
-  fitTotal->SetParLimits(5,0,10); // alpha
-  fitTotal->SetParLimits(6,0.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::FitJpsiCB2VWG(const TH1& h)
-{
-  /// Fit Jpsi spectra using extended crystal ball (CB2) + variable width gaussian (VWG)
-  
-  std::cout << "Fit with jpsi VWG" << std::endl;
-  
-  Int_t nrebin = fMinv->GetXaxis()->GetNbins() / h.GetXaxis()->GetNbins();
-  
-  AliAnalysisMuMuResult* r = new AliAnalysisMuMuResult(h,"JPSICB2VWG",nrebin);
-  
-  
-  TH1* hfit = r->Minv();
-  
-  const Double_t xmin(2.0);
-  const Double_t xmax(5.0);
-  
-//  // 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'
-
-  TF1* fitTotal = new TF1("fitTotal",fitFunctionCB2VWG,xmin,xmax,11);
-  fitTotal->SetParNames("kVWG","mVWG","sVWG1","sVWG2","norm","mean","sigma","alpha","n","alpha'","n'");
-  
-  fitTotal->SetParameter(0, 10000.); // kVWG
-  fitTotal->SetParameter(1, 1.9); // mVWG
-  
-  fitTotal->SetParameter(2, 0.5); // sVWG1
-  fitTotal->SetParLimits(2, 0., 100.);
-  
-  fitTotal->SetParameter(3, 0.3); // sVWG2
-  fitTotal->SetParLimits(3, 0., 100.);
-  
-  fitTotal->SetParameter(4, h.GetMaximum()); // norm
-  
-  fitTotal->SetParameter(5, 3.1); // mean
-  fitTotal->SetParLimits(5, 3.0, 3.2);
-  
-  fitTotal->SetParameter(6, 0.08); // sigma
-  fitTotal->SetParLimits(6, 0.04, 0.20);
-  
-  fitTotal->SetParameter(7,1.0); // alpha
-  fitTotal->SetParameter(8,5); // n
-  fitTotal->SetParameter(9,2.0); // alpha'
-  fitTotal->SetParameter(10,4); // n'
-  
-//  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 )
+  if ( TMath::Abs(b) > 1E-12 )
   {
-    cbParameters[ix] = fitTotal->GetParameter(ix+4);
+    e += (berr*berr)/(b*b);
   }
   
-  for ( int iy = 0; iy < 5; ++iy )
+  if ( TMath::Abs(c) > 1E-12 )
   {
-    for ( int ix = 0; ix < 5; ++ix )
-    {
-      covarianceMatrix[ix][iy] = (fitResult->GetCovarianceMatrix())(ix+4,iy+4);
-    }
+    e += (cerror*cerror)/(c*c);
   }
   
-  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;
-}
-
-//_____________________________________________________________________________
-AliAnalysisMuMuResult* AliAnalysisMuMuResult::FitJpsi2CB2VWG(const TH1& h,
-                                                             Double_t alphaLow,
-                                                             Double_t nLow,
-                                                             Double_t alphaUp,
-                                                             Double_t nUp)
-{
-  /// Fit using extended crystal ball + variable width gaussian
-  
-  std::cout << Form("Fit with jpsi + psiprime VWG alphaLow=%5.2f nLow=%5.2f alphaUp=%5.2f nUp=%5.2f",
-                    alphaLow,nLow,alphaUp,nUp) << std::endl;
-  
-  Int_t nrebin = fMinv->GetXaxis()->GetNbins() / h.GetXaxis()->GetNbins();
-  
-  TString resultName("JPSI2CB2VWG");
-  if ( alphaLow > 0 )
+  if ( TMath::Abs(d) > 1E-12 )
   {
-    resultName += TString::Format("alphaLow=%5.2f",alphaLow);
+    e += (derror*derror)/(d*d);
   }
-  if ( nLow > 0 )
-  {
-    resultName += TString::Format("nLow=%5.2f",nLow);
-  }
-  if ( alphaUp > 0 )
-  {
-    resultName += TString::Format("alphaUp=%5.2f",alphaUp);
-  }
-  if ( nUp > 0 )
-  {
-    resultName += TString::Format("nUp=%5.2f",nUp);
-  }
-  resultName.ReplaceAll(" ","");
-  
-  AliAnalysisMuMuResult* r = new AliAnalysisMuMuResult(h,resultName.Data(),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.1);
-  fitTotal->SetParLimits(5, 3.08, 3.2);
-  fitTotal->SetParameter(6, 0.08);
-  fitTotal->SetParLimits(6, 0.05, 0.15);
-  
-//  r = FitJpsi2CB2VWG(*hminv,0.93,5.59,2.32,3.39);
-
-  if ( alphaLow > 0 )
+  if ( TMath::Abs(e) > 1E-12 )
   {
-    fitTotal->FixParameter(7, alphaLow);
+    e += (eeerror*eeerror)/(ee*ee);
   }
-  else
-  {
-    fitTotal->SetParameter(7,0.9);
-    fitTotal->SetParLimits(7,0.1,10.0);
-  }
-  
-  if ( nLow > 0 )
-  {
-    fitTotal->FixParameter(8, nLow);
-  }
-  else
-  {
-    fitTotal->SetParameter(8,5.0);
-    fitTotal->SetParLimits(8,0.0,10.0);
-  }
-  
-  if ( alphaUp > 0 )
-  {
-    fitTotal->FixParameter(9, alphaUp);
-  }
-  else
-  {
-    fitTotal->SetParameter(9, 2.0);
-    fitTotal->SetParLimits(9,0.1,10.0);
-  }
-  
-  if ( nUp > 0 )
-  {
-    fitTotal->FixParameter(10, nUp);    
-  }
-  else
-  {
-    fitTotal->SetParameter(10,3.0);
-    fitTotal->SetParLimits(10,0.0,10.0);
-  }
-  
-  fitTotal->SetParameter(11, 10.);
 
-  const char* fitOption = "SER"; //+";
-  
-  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;
+  return TMath::Sqrt(e);
 }
 
-//_____________________________________________________________________________
-AliAnalysisMuMuResult* AliAnalysisMuMuResult::FitJpsiNA48(const TH1& h)
-{
-  /// fit using functional form from Ruben Shahoyan's thesis (2001) (eq. 4.8.)
-  
-  std::cout << "Fit with jpsi NA50 Ruben eq. 4.8" << std::endl;
-  
-  Int_t nrebin = fMinv->GetXaxis()->GetNbins() / h.GetXaxis()->GetNbins();
-  
-  AliAnalysisMuMuResult* r = new AliAnalysisMuMuResult(h,"JPSINA",nrebin);
-  
-  TH1* hfit = r->Minv();
-  
-  const Double_t xmin(2.0);
-  const Double_t xmax(5.0);
-  
-  TF1* fitTotal = new TF1("fitTotal",funcJpsiNA48,xmin,xmax,12);
-  
-  fitTotal->SetParName( 0, "c1");
-  fitTotal->FixParameter(0,0.97);
-  
-  fitTotal->SetParName( 1, "c2");
-  fitTotal->FixParameter(1,1.05);
-  
-  fitTotal->SetParName( 2, "d1");
-  fitTotal->SetParameter(2,0.0);
-  fitTotal->SetParLimits(2,0,1);
-  
-  fitTotal->SetParName( 3, "d2");
-  fitTotal->SetParameter(3,0.0);
-  fitTotal->SetParLimits(3,0,1);
-  
-  fitTotal->SetParName( 4, "g1");
-  fitTotal->SetParameter(4,0.0);
-  fitTotal->SetParLimits(4,0.0,1);
-  
-  fitTotal->SetParName( 5, "g2");
-  fitTotal->SetParameter(5,0.0);
-  fitTotal->SetParLimits(5,0.0,1);
-  
-  fitTotal->SetParName( 6, "m0");
-  fitTotal->SetParameter(6,3.1);
-  fitTotal->SetParLimits(6,2.8,3.4);
-
-  fitTotal->SetParName( 7, "sigma1");
-  fitTotal->SetParameter(7,0.05);
-  fitTotal->SetParLimits(7,0.01,0.2);
-  
-  fitTotal->SetParName( 8, "sigma2");
-  fitTotal->SetParameter(8,0.05);
-  fitTotal->SetParLimits(8,0.01,0.2);
-
-  fitTotal->SetParName( 9, "b1");
-  fitTotal->SetParameter(9,1.0);
-  fitTotal->SetParLimits(9,0,1);
-  
-  fitTotal->SetParName(10, "b2");
-  fitTotal->SetParameter(10,1.0);
-  fitTotal->SetParLimits(10,0,1);
-  
-  fitTotal->SetParName(11, "norm");
-  fitTotal->SetParameter(11,h.GetMaximum());
-  
-  const char* fitOption = "SIER"; //+";
-  
-  TFitResultPtr fitResult = hfit->Fit(fitTotal,fitOption,"");
-  
-  r->Set("MeanJpsi",fitTotal->GetParameter(6),fitTotal->GetParError(6));
-  r->Set("SigmaJpsi",
-         fitTotal->GetParameter(7)+fitTotal->GetParameter(8),
-         0.0);
-
-  double m = r->GetValue("MeanJpsi");
-  double s = r->GetValue("SigmaJpsi");
-  double n = 3.0;
-  
-  TLine* l1 = new TLine(m-n*s,0,m-n*s,fitTotal->GetParameter(11));
-  TLine* l2 = new TLine(m+n*s,0,m+n*s,fitTotal->GetParameter(11));
-  l1->SetLineColor(6);
-  l2->SetLineColor(6);
-  hfit->GetListOfFunctions()->Add(l1);
-  hfit->GetListOfFunctions()->Add(l2);
-  
-  double njpsi = fitTotal->Integral(m-n*s,m+n*s)/h.GetBinWidth(1);
-  double nerr = fitTotal->IntegralError(m-n*s,m+n*s)/h.GetBinWidth(1);
-  
-  r->Set("NofJpsi",njpsi,nerr);
-  
-  return r;
-}
 
-/*
 //_____________________________________________________________________________
-void AliAnalysisMuMuResult::FitUpsilon(TH1& h)
+void AliAnalysisMuMuResult::Exclude(const char* subResultList)
 {
-  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);
-  
+  // exclude some subresult names from the list of subresult
+  // to be used when computing the mean 
   
-  Set("MeanUpsilon",fitTotal->GetParameter(3),fitTotal->GetParError(3));
-  Set("SigmaUpsilon",fitTotal->GetParameter(4),fitTotal->GetParError(4));
+  TString slist(subResultList);
   
-  double m = GetValue("MeanUpsilon");
-  double s = GetValue("SigmaUpsilon");
-  double n = 3.0;
+  TString tobeincluded = GetSubResultNameList();
   
-  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)
-{
-  /// Compute the quadratic sum of 2 errors
-
-  Double_t e(0.0);
-  
-  if ( TMath::Abs(a) > 1E-12 )
+  if ( slist == "*" )
   {
-    e += (aerr*aerr)/(a*a);
+    Exclude(tobeincluded);
+    return;
   }
   
-  if ( TMath::Abs(b) > 1E-12 )
+  if ( fSubResultsToBeIncluded )
   {
-    e += (berr*berr)/(b*b);
-  }
-  
-  return TMath::Sqrt(e);
-}
+    TObjArray* a = slist.Tokenize(",");
+    TIter nextA(a);
+    TObjString* s;
 
-//_____________________________________________________________________________
-Double_t AliAnalysisMuMuResult::ErrorABC(Double_t a, Double_t aerr, Double_t b, Double_t berr, Double_t c, Double_t cerror)
-{
-  /// Compute the quadratic sum of 3 errors
-  
-  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);
+    while ( ( s = static_cast<TObjString*>(nextA())) )
+    {
+      TObject* o = fSubResultsToBeIncluded->FindObject(s->String());
+      fSubResultsToBeIncluded->Remove(o);
+    }
+    
+    delete a;
   }
-  
-  return TMath::Sqrt(e);
 }
 
-
 //_____________________________________________________________________________
-Bool_t AliAnalysisMuMuResult::AddFit(const char* fitType, Int_t npar, Double_t* par)
+Double_t AliAnalysisMuMuResult::GetErrorStat(const char* name, const char* subResultName) const
 {
-  // Add a fit to this result
-  
-  TString msg(Form("fitType=%s npar=%d par[]=",fitType,npar));
-  
-  for ( Int_t i = 0; i < npar; ++i )
-  {
-    msg += TString::Format("%e,",par[i]);
-  }
-  
-  msg += TString::Format(" minv=%p %d",fMinv,fMinv?TMath::Nint(fMinv->GetEntries()):0);
-  
-  if ( !fMinv ) return kFALSE;
-  
-  TString sFitType(fitType);
-  sFitType.ToUpper();
-  Int_t nrebin(1);
-  
-  if (sFitType.CountChar(':'))
-  {
-    Int_t index = sFitType.Index(":");
-    nrebin = TString(sFitType(index+1,sFitType.Length()-index-1)).Atoi();
-    sFitType = sFitType(0,index);
-  }
-  
-  msg += TString::Format(" nrebin=%d",nrebin);
+  // compute the mean value from all subresults that are included
   
-  AliDebug(1,msg.Data());
-  
-
-  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=="PSI1")
-  {
-    r = FitJpsi(*hminv);
-  }
-  else if ( sFitType == "PSILOW")
-  {
-    r = FitJpsi2CB2VWG(*hminv,-1,-1,-1,-1); // free tails
-  }
-  else if ( sFitType == "PSILOWMCTAILS" )
+  if ( strlen(subResultName) > 0 )
   {
-    if ( npar!= 4 )
+    if ( !fSubResults)
     {
-      AliError("Cannot use PSILOWMCTAILS without being given the MC tails !");
-      delete hminv;
-      return kFALSE;
+      AliError(Form("No subresult from which I could get the %s one...",subResultName));
+      return TMath::Limits<Double_t>::Max();
     }
-    r = FitJpsi2CB2VWG(*hminv,par[0],par[1],par[2],par[3]);
-    if (r)
+    AliAnalysisMuMuResult* sub = static_cast<AliAnalysisMuMuResult*>(fSubResults->FindObject(subResultName));
+    if (!sub)
     {
-      r->SetAlias("MCTAILS");
+      AliError(Form("Could not get subresult named %s",subResultName));
+      return TMath::Limits<Double_t>::Max();
     }
+    return sub->GetErrorStat(name);
   }
-  else if ( sFitType.BeginsWith("PSILOWALPHA") )
+  
+  if ( fMap )
   {
-    Float_t lpar[] = { 0.0, 0.0, 0.0, 0.0 };
-    
-    AliDebug(1,Form("sFitType=%s",sFitType.Data()));
-    
-    sscanf(sFitType.Data(),"PSILOWALPHALOW%fNLOW%fALPHAUP%fNUP%f",
-           &lpar[0],&lpar[1],&lpar[2],&lpar[3]);
-    
-    AliDebug(1,Form("PSILOW ALPHALOW=%f NLOW=%f ALPHAUP=%f NUP=%f",lpar[0],lpar[1],lpar[2],lpar[3]));
-    
-    if ( lpar[0] == 0.0 && lpar[1] == 0.0 && lpar[0] == 0.0 && lpar[1] == 0.0 )
+    TObjArray* p = static_cast<TObjArray*>(fMap->GetValue(name));
+    if (p)
     {
-      AliError("Cannot work with zero tails !");
+      TParameter<double>* val = static_cast<TParameter<double>*>(p->At(kErrorStat));
+      return val->GetVal();
     }
-    else
+  }
+  
+  TIter next(fSubResults);
+  AliAnalysisMuMuResult* r;
+  Int_t n(0);
+  Double_t v1(0);
+  Double_t v2(0);
+  Double_t d(0);
+  
+  Double_t mean = GetValue(name);
+  
+  while ( ( r = static_cast<AliAnalysisMuMuResult*>(next()) ) )
+  {    
+    if ( IsIncluded(r->Alias()) && r->HasValue(name) )
     {
-      r = FitJpsi2CB2VWG(*hminv,lpar[0],lpar[1],lpar[2],lpar[3]);      
+      Double_t error = r->GetErrorStat(name);
+      if (error)
+      {
+        v1 += 1.0/(error*error);
+        v2 += 1.0/(error*error*error*error);
+       
+        d += ( (r->GetValue(name) - mean)*(r->GetValue(name)-mean) / (error*error));
+      }
+      ++n;
     }
   }
-  else if ( sFitType == "COUNTJPSI" )
-  {
-    r = new AliAnalysisMuMuResult(*hminv,"COUNTJPSI",1);
-    Double_t n = CountParticle(*hminv,"Jpsi");
-    r->Set("NofJpsi",n,TMath::Sqrt(n));
-  }
   
+  if ( n<1 ) return 0.0;
   
-  if ( r )
+  if ( n == 1 )
   {
-    r->Print();
-    r->SetBin(Bin());
-    r->SetNofTriggers(NofTriggers());
-    r->SetNofRuns(NofRuns());
-
-    if (!fSubResults)
+    next.Reset();
+    while ( ( r = static_cast<AliAnalysisMuMuResult*>(next()) ) )
     {
-      fSubResults = new TObjArray;
-      fSubResults->SetOwner(kTRUE);
+      if ( IsIncluded(r->Alias()) && r->HasValue(name) )
+      {
+        return r->GetErrorStat(name);
+      }
     }
-
-    fSubResults->Add(r);
   }
   
-  delete hminv;
+  Double_t variance= (1.0/v1)*(1.0/(n-1))*d;
+    // variance corrected by over/under-estimation of errors
+    // i.e. scaled by chisquare per ndf
   
-  return (r!=0x0);
+  return TMath::Sqrt(variance);
 }
 
 //_____________________________________________________________________________
-Double_t AliAnalysisMuMuResult::GetErrorStat(const char* name, const char* subResultName) const
+Double_t AliAnalysisMuMuResult::GetRMS(const char* name, const char* subResultName) const
 {
-  // compute the mean value from all subresults
-  
+  // compute the rms of the subresults
+  // returns zero if no subresults
+
   if ( strlen(subResultName) > 0 )
   {
     if ( !fSubResults)
@@ -1924,7 +403,7 @@ Double_t AliAnalysisMuMuResult::GetErrorStat(const char* name, const char* subRe
       AliError(Form("Could not get subresult named %s",subResultName));
       return TMath::Limits<Double_t>::Max();
     }
-    return sub->GetErrorStat(name);
+    return sub->GetRMS(name);
   }
   
   if ( fMap )
@@ -1932,25 +411,74 @@ Double_t AliAnalysisMuMuResult::GetErrorStat(const char* name, const char* subRe
     TObjArray* p = static_cast<TObjArray*>(fMap->GetValue(name));
     if (p)
     {
-      TParameter<double>* val = static_cast<TParameter<double>*>(p->At(kErrorStat));
-      return val->GetVal();
+      TParameter<double>* val = static_cast<TParameter<double>*>(p->At(kRMS));
+      return val ? val->GetVal() : 0.0; // val can be null for old results which did not have the rms set
     }
   }
   
   TIter next(fSubResults);
   AliAnalysisMuMuResult* r;
+  Double_t v1(0);
+  Double_t v2(0);
+  Double_t sum(0);
   Int_t n(0);
-  Double_t mean(0);
+  
+  Double_t xmean = GetValue(name);
   
   while ( ( r = static_cast<AliAnalysisMuMuResult*>(next()) ) )
   {
-    if ( r->HasValue(name) )
+    if ( IsIncluded(r->Alias()) && r->HasValue(name) )
     {
-      mean += r->GetErrorStat(name);
-      ++n;
+      if ( r->GetErrorStat(name) > 0 )
+      {
+        Double_t ei = r->GetErrorStat(name);
+        Double_t wi = 1.0/(ei*ei);
+        v1 += wi;
+        v2 += wi*wi;
+        Double_t diff = r->GetValue(name) - xmean;
+        sum += wi*diff*diff;
+        ++n;
+      }
+    }
+  }
+  
+  if ( n < 1 ) return 0.0;
+  
+  if ( n == 1 )
+  {
+    next.Reset();
+    while ( ( r = static_cast<AliAnalysisMuMuResult*>(next()) ) )
+    {
+      if ( IsIncluded(r->Alias()) && r->HasValue(name) )
+      {
+        return r->GetRMS(name);
+      }
     }
   }
-  return ( n ? mean/n : 0.0 );
+  
+  Double_t unbiased = TMath::Sqrt( (v1/(v1*v1-v2)) * sum);
+  
+  Double_t biased = TMath::Sqrt( sum/v1 );
+  
+  AliDebug(1,Form("v1 %e v1*v1 %e v2 %e -> biased %e unbiased %e (ratio %e)",v1,v1*v1,v2,biased,unbiased,unbiased/biased));
+  
+  return unbiased;
+}
+
+//_____________________________________________________________________________
+TString AliAnalysisMuMuResult::GetSubResultNameList() const
+{
+  // get a comma separated list of our subresult aliases
+  TString tobeincluded;
+  TIter next(fSubResults);
+  AliAnalysisMuMuResult* r;
+  
+  while ( ( r = static_cast<AliAnalysisMuMuResult*>(next())) )
+  {
+    if (tobeincluded.Length()>0) tobeincluded+=",";
+    tobeincluded += r->Alias();
+  }
+  return tobeincluded;
 }
 
 //_____________________________________________________________________________
@@ -1987,18 +515,30 @@ Double_t AliAnalysisMuMuResult::GetValue(const char* name, const char* subResult
   // compute the mean value from all subresults
   TIter next(fSubResults);
   AliAnalysisMuMuResult* r;
-  Int_t n(0);
   Double_t mean(0);
+  Double_t errorSum(0.0);
   
   while ( ( r = static_cast<AliAnalysisMuMuResult*>(next()) ) )
   {
-    if ( r->HasValue(name) )
+    if ( IsIncluded(r->Alias()) && r->HasValue(name) )
     {
-      mean += r->GetValue(name);
-      ++n;
+      Double_t e = r->GetErrorStat(name);
+      Double_t e2 = e*e;
+      if ( e != 0.0 )
+      {
+        mean += r->GetValue(name)/e2;
+        errorSum += 1.0/e2;
+      }
     }
   }
-  return ( n ? mean/n : 0.0 );
+  if ( errorSum != 0.0 )
+  {
+    return mean/errorSum;
+  }
+  else
+  {
+    return TMath::Limits<Double_t>::Max();
+  }
 }
 
 //_____________________________________________________________________________
@@ -2039,6 +579,55 @@ Bool_t AliAnalysisMuMuResult::HasValue(const char* name, const char* subResultNa
   return kFALSE;
 }
 
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::Include(const char* subResultList)
+{
+  // (re)include some subresult names
+  
+  TString slist(subResultList);
+
+  if ( slist.Length()==0 )
+  {
+    Exclude("*");
+    return;
+  }
+  
+  if ( slist == "*" )
+  {
+    slist = GetSubResultNameList();
+  }
+
+  TObjArray* a = slist.Tokenize(",");
+  a->SetOwner(kFALSE);
+  TIter next(a);
+  TObjString* s;
+  
+  while ( ( s = static_cast<TObjString*>(next()) ) )
+  {
+    if (!fSubResultsToBeIncluded )
+    {
+      fSubResultsToBeIncluded = new TList;
+      fSubResultsToBeIncluded->SetOwner(kTRUE);
+    }
+    if (!IsIncluded(s->String()))
+    {
+      fSubResultsToBeIncluded->Add(s);      
+    }
+  }
+  
+  delete a;
+}
+
+//_____________________________________________________________________________
+Bool_t AliAnalysisMuMuResult::IsIncluded(const TString& alias) const
+{
+  // whether that subresult alias should be included when computing means, etc...
+  
+  if (!fSubResultsToBeIncluded) return kTRUE;
+  
+  return ( fSubResultsToBeIncluded->FindObject(alias) != 0x0 );
+}
+
 //_____________________________________________________________________________
 THashList* AliAnalysisMuMuResult::Keys() const
 {
@@ -2087,25 +676,16 @@ Long64_t AliAnalysisMuMuResult::Merge(TCollection* list)
   /// 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
+  /// Note that the merging is to be understood here as a weighed mean 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 = TMath::Nint(fNofRuns*thisWeight);
+  Double_t sumw(Weight()); // sum of weights
   
   while ( ( currObj = next() ) )
   {
@@ -2116,32 +696,17 @@ Long64_t AliAnalysisMuMuResult::Merge(TCollection* list)
       continue;
     }
     
-    Double_t w = result->Weight();
-    
-    nofRuns += result->NofRuns()*w;
-    nofTriggers += result->NofTriggers()*w;
-    fWeight += result->fWeight;
-    sumOfWeights += w;
+    sumw += result->Weight();
   }
   
-  thisWeight/= sumOfWeights;
-  fNofRuns = TMath::Nint(nofRuns/sumOfWeights);
-  fNofTriggers = TMath::Nint(nofTriggers/sumOfWeights);
-  fWeight /= sumOfWeights;
-  
-  AliInfo(Form("thisWeight=%e sumOfWeight=%8.2f noftriggers=%e weight=%e",thisWeight,sumOfWeights,1.0*fNofTriggers,fWeight));
-  
-  TIter nextKey(fMap);
+  TIter nextKey(Keys());
   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);
+    Double_t value = GetValue(key->String())*Weight()/sumw;
+    Double_t e = GetErrorStat(key->String());
+    Double_t e2 = e*e*Weight()*Weight()/sumw/sumw;
 
     next.Reset();
     
@@ -2162,55 +727,18 @@ Long64_t AliAnalysisMuMuResult::Merge(TCollection* list)
       
       // 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 w = result->Weight()/sumw;
       
       Double_t w2 = w*w;
       
-      test += w;
-      
       value += result->GetValue(key->String())*w;
-      estat += result->GetErrorStat(key->String())*result->GetErrorStat(key->String())*w2;
+      e2 += 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);
+        TMath::Sqrt(e2));
   }
   
   TIter nextSubresult(fSubResults);
@@ -2230,24 +758,27 @@ Long64_t AliAnalysisMuMuResult::Merge(TCollection* list)
     r->Merge(&sublist);
   }
   
+  fWeight = sumw;
+  
   return list->GetEntries()+1;
 }
 
 //_____________________________________________________________________________
-Int_t AliAnalysisMuMuResult::NofRuns() const
-{
-  /// Get the number of runs
-  if ( !Mother() ) return fNofRuns;
-  else return Mother()->NofRuns();
-}
-
-//_____________________________________________________________________________
-Int_t AliAnalysisMuMuResult::NofTriggers() const
+Int_t AliAnalysisMuMuResult::NofIncludedSubResults(const char* name) const
 {
-  /// Get the number of triggers
+  // Return the number of subresults which have key name and are included
   
-  if ( !Mother() ) return fNofTriggers;
-  else return Mother()->NofTriggers();
+  TIter next(fSubResults);
+  AliAnalysisMuMuResult* r;
+  Int_t n(0);
+  while ( ( r = static_cast<AliAnalysisMuMuResult*>(next()) ) )
+  {
+    if ( IsIncluded(r->Alias()) && r->HasValue(name) )
+    {
+      ++n;
+    }
+  }
+  return n;
 }
 
 //_____________________________________________________________________________
@@ -2269,127 +800,136 @@ void AliAnalysisMuMuResult::Print(Option_t* opt) const
 
   std::cout << pot.Data();
   
-  if ( fAlias.Length() > 0 )
-  {
-    std::cout << Form("%s - ",fAlias.Data());
-  }
-  
-  std::cout << 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 )
+    if ( fAlias.Length() > 0 )
     {
-      std::cout << " (" << fSubResults->GetEntries()-1 << " subresults)";
+      std::cout << Form("%s - ",fAlias.Data());
     }
   
-  if (!fSubResults )
-  {
-    std::cout << Form(" - REBIN %d",fRebin) << std::endl;
-  }
+    std::cout << Form("%s %s %s",
+                      GetName(),GetTitle(),fWeight > 0.0 ? Form(" WEIGHT %e",fWeight) : "");
   
-  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
+  if ( fSubResults && fSubResults->GetEntries()>1 )
   {
-    
-    PrintParticle("Jpsi",pot.Data());
-    PrintParticle("PsiPrime",pot.Data());
-    PrintParticle("Upsilon",pot.Data());
+    std::cout << " (" << fSubResults->GetEntries() << " subresults)";
   }
+
+  std::cout << std::endl;
+  
+  TIter next(Keys());
+  TObjString* key;
   
-  if ( HasValue("MBR"))
+  while ( ( key = static_cast<TObjString*>(next())) )
   {
-    std::cout << Form("\t\tMBR %e +- %e",GetValue("MBR"),GetErrorStat("MBR")) << std::endl;
+    PrintValue(key->String().Data(),pot.Data(),
+               GetValue(key->String()),
+               GetErrorStat(key->String()),
+               GetRMS(key->String()));
   }
-  
+
   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);
+    TIter nextSubresult(fSubResults);
     AliAnalysisMuMuResult* r;
     
-    while ( ( r = static_cast<AliAnalysisMuMuResult*>(next()) ) )
+    while ( ( r = static_cast<AliAnalysisMuMuResult*>(nextSubresult()) ) )
     {
+      if ( !IsIncluded(r->Alias()) )
+      {
+        std::cout << " [EXCLUDED]";
+      }
       r->Print(sopt.Data());
     }
   }
 }
 
 //_____________________________________________________________________________
-void AliAnalysisMuMuResult::PrintParticle(const char* particle, const char* opt) const
-{
-  /// Print all information about one particule type
-  
-  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)
+void AliAnalysisMuMuResult::PrintValue(const char* key, const char* opt,
+                                       Double_t value, Double_t errorStat, Double_t rms) 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;
+    std::cout << opt << Form("\t\t%20s %9.2f +- %5.2f %% (%5.2f %%)",key,value*100,errorStat*100,
+                             value != 0.0 ? errorStat*100.0/value : 0.0 );
+    
+    if ( rms )
+    {
+      std::cout << Form(" RMS %9.2f (%5.2f %%)",rms,100.0*rms/value);
+    }
+
+    std::cout << 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;
+    std::cout << opt << Form("\t\t%20s %9.2f +- %5.2f (%5.2f %%) MeV/c^2",key,value*1E3,1E3*errorStat,
+                             value != 0.0 ? errorStat*100.0/value : 0.0);
+    
+    if ( rms )
+    {
+      std::cout << Form(" RMS %9.2f (%5.2f %%)",rms,100.0*rms/value);
+    }
+
+    std::cout << std::endl;
   }
-  else if ( TString(key).Contains("Nof") )
+  else if ( TString(key).Contains("Nof") || ( TString(key).Contains("Fnorm") && !TString(key).Contains("persion") ) )
   {
-    std::cout << opt << Form("\t\t%20s %9.2f +- %5.2f",key,value,errorStat) << std::endl;
+    std::cout << opt << Form("\t\t%20s %9.2f +- %5.2f (%5.2f %%)",key,value,errorStat,
+                             value != 0.0 ? errorStat*100.0/value : 0.0);
+    
+    if ( rms )
+    {
+      std::cout << Form(" RMS %9.2f (%5.2f %%)",rms,100.0*rms/value);
+    }
+    std::cout << 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;
+    std::cout << opt << Form("\t\t%20s %9.2f +- %5.2f (%5.2f %%)",key,value,errorStat,
+                             value != 0.0 ? errorStat*100.0/value : 0.0);
+    if ( rms )
+    {
+      std::cout << Form(" RMS %9.2f (%5.2f %%)",rms,100.0*rms/value);
+    }
+    std::cout << std::endl;
   }
   else
   {
-    std::cout << opt << Form("\t\t%20s %9.2e +- %9.2e",key,value,errorStat) << std::endl;    
+    std::cout << opt << Form("\t\t%20s %9.2e +- %9.2e (%5.2f %%)",key,value,errorStat,
+                             value != 0.0 ? errorStat*100.0/value : 0.0);
+    if ( rms )
+    {
+      std::cout << Form(" RMS %9.2e (%5.2f %%)",rms,100.0*rms/value);
+    }
+    std::cout << std::endl;
+  }
+}
+
+//_____________________________________________________________________________
+void AliAnalysisMuMuResult::Scale(Double_t w)
+{
+  /// Scale all our internal values by value
+  
+  TIter next(Keys());
+  TObjString* key;
+  
+  while ( ( key = static_cast<TObjString*>(next())) )
+  {
+    Double_t value = GetValue(key->String());
+    Double_t error = GetErrorStat(key->String());
+    Double_t rms = GetRMS(key->String());
+    
+    Set(key->String(),value*w,error*w,rms*w);
   }
+
 }
 
 //_____________________________________________________________________________
-void AliAnalysisMuMuResult::Set(const char* name, Double_t value, Double_t errorStat)
+void AliAnalysisMuMuResult::Set(const char* name, Double_t value, Double_t errorStat, Double_t rms)
 {
   /// Set a (value,error) pair with a given name
   
@@ -2408,6 +948,7 @@ void AliAnalysisMuMuResult::Set(const char* name, Double_t value, Double_t error
     
     p->AddAt(new TParameter<Double_t>(name,value),kValue);
     p->AddAt(new TParameter<Double_t>(name,errorStat),kErrorStat);
+    p->AddAt(new TParameter<Double_t>(name,rms),kRMS);
     
     fMap->Add(new TObjString(name),p);
   }
@@ -2415,111 +956,8 @@ void AliAnalysisMuMuResult::Set(const char* name, Double_t value, Double_t error
   {
     static_cast<TParameter<double>*>(p->At(kValue))->SetVal(value);
     static_cast<TParameter<double>*>(p->At(kErrorStat))->SetVal(errorStat);
+    static_cast<TParameter<double>*>(p->At(kRMS))->SetVal(rms);
   }
-  
-  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)
-{
-  /// Set the bin
-  
-  if (!Mother()) fBin = bin;
-  else Mother()->SetBin(bin);
-}
-
-//_____________________________________________________________________________
-void AliAnalysisMuMuResult::SetNofInputParticles(const TH1& hminv)
-{
-  /// Set the number of input particle from the invariant mass spectra
-  
-  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],TMath::Nint(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);
 }
 
 //_____________________________________________________________________________
@@ -2543,3 +981,14 @@ AliAnalysisMuMuResult::SubResult(const char* subResultName) const
   return 0x0;
 }
 
+//_____________________________________________________________________________
+TList* AliAnalysisMuMuResult::SubResultsToBeIncluded() const
+{
+  if (!fSubResultsToBeIncluded)
+  {
+    fSubResultsToBeIncluded = new TList;
+    fSubResultsToBeIncluded->SetOwner(kTRUE);
+  }
+  return fSubResultsToBeIncluded;
+}
+
index 0b009a79dfd8a28051e2d500615d5dbbabfa1eec..cba1f27e2f4d7325185f3fd4686b309b169cb44d 100644 (file)
 
 #include "TNamed.h"
 #include <TString.h>
-#include "AliAnalysisMuMuBinning.h"
 
 class TH1;
 class THashList;
-class TF1;
 class TMap;
 
 class AliAnalysisMuMuResult : public TNamed
@@ -26,33 +24,17 @@ 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 char* name="", const char* title="");
   AliAnalysisMuMuResult(const AliAnalysisMuMuResult& rhs);
   AliAnalysisMuMuResult& operator=(const AliAnalysisMuMuResult& rhs);
   
   virtual ~AliAnalysisMuMuResult();
 
+  void AdoptSubResult(AliAnalysisMuMuResult* r);
+
   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);
+  void Set(const char* name, Double_t value, Double_t errorStat, Double_t rms=0.0);
   
   Bool_t HasValue(const char* name, const char* subResultName="") const;
   
@@ -60,38 +42,10 @@ public:
   
   Double_t GetErrorStat(const char* name, const char* subResultName="") const;
 
-  Int_t NofTriggers() const;
-  
-  void SetNofTriggers(Int_t n);
+  Double_t GetRMS(const char* name, const char* subResultName="") const;
   
   void Print(Option_t* opt="") const;
   
-  Bool_t AddFit(const char* fitType, Int_t npar=0, Double_t* par=0x0);
-
-  AliAnalysisMuMuResult* CountJpsi(TH1& h);
-
-  AliAnalysisMuMuResult*  FitJpsi(TH1& h);
-
-  AliAnalysisMuMuResult* FitJpsiNA48(const TH1& h);
-  AliAnalysisMuMuResult* FitJpsiCB2VWG(const TH1& h);
-  AliAnalysisMuMuResult* FitJpsi2CB2VWG(const TH1& h, Double_t alphaLow=-1.0, Double_t nLow=-1.0, Double_t alphaUp=-1.0, Double_t nUp=-1.0);
-  
-  AliAnalysisMuMuResult* FitJpsiGCBE(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);
-
   AliAnalysisMuMuResult* SubResult(const char* subResultName) const;
   
   TObjArray* SubResults() const { return fSubResults; }
@@ -102,52 +56,61 @@ public:
   
   THashList* Keys() const;
   
-  Double_t Weight() const { return fWeight > 0  ? fWeight : fNofTriggers; }
+  Double_t Weight() const { return fWeight; }
   
   void SetWeight(Double_t w) { fWeight=w; }
 
-  static Double_t CountParticle(const TH1& hminv, const char* particle, Double_t sigma=-1.0);
-  
   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);
 
-  static void PrintValue(const char* key, const char* opt, Double_t value, Double_t errorStat);
+  static Double_t ErrorABCD(Double_t a, Double_t aerr, Double_t b, Double_t berr, Double_t c, Double_t cerror,
+                            Double_t d, Double_t derror);
+
+  static Double_t ErrorABCDE(Double_t a, Double_t aerr, Double_t b, Double_t berr, Double_t c, Double_t cerror,
+                             Double_t d, Double_t derror, Double_t e, Double_t eerror);
+
+  void PrintValue(const char* key, const char* opt, Double_t value, Double_t errorStat, Double_t rms=0.0) const;
 
   void SetAlias(const char* alias) { fAlias = alias; }
   
   TString Alias() const { if ( fAlias.Length()>0) return fAlias; else return GetName(); }
   
+  void Include(const char* subResultsList);
+
+  void Exclude(const char* subResultsList);
+
+  Bool_t IsIncluded(const TString& alias) const;
+  
+  void Scale(Double_t value);
+  
 private:
   
   enum EIndex
   {
     kValue=0,
-    kErrorStat=1
+    kErrorStat=1,
+    kRMS=2
   };
   
   void PrintParticle(const char* particle, const char* opt) const;
 
+  TList* SubResultsToBeIncluded() const;
+  
+  TString GetSubResultNameList() const;
+
+  Int_t NofIncludedSubResults(const char* name) 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)
-  Int_t fRebin; // rebin level of minv spectra
-  
-  TString fTriggerClass; // trigger class for this result
-  TString fEventSelection; // event selection for this result
-  TString fPairSelection; // pair selection for this result
-  TString fCentralitySelection; // centrality selection for this result
-
   TString fAlias; // alias name
+  mutable TList* fSubResultsToBeIncluded; // inclusion list
   
-  ClassDef(AliAnalysisMuMuResult,8) // a class to hold invariant mass analysis results (counts, yields, AccxEff, R_AB, etc...)
+  ClassDef(AliAnalysisMuMuResult,11) // a class to some results (counts, yields, AccxEff, R_AB, etc...)
 };
 
 #endif
index a5aa8b8aecf2b6661fba35b24d69638b33f1385d..ac8673a2616cd9b95360e452d37ef2995a2c19d4 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "AliLog.h"
 #include "AliAnalysisMuMuBinning.h"
-#include "AliAnalysisMuMuResult.h"
+#include "AliAnalysisMuMuJpsiResult.h"
 #include "Riostream.h"
 #include "TH1.h"
 #include "TList.h"
@@ -37,7 +37,8 @@ ClassImp(AliAnalysisMuMuSpectra)
 AliAnalysisMuMuSpectra::AliAnalysisMuMuSpectra(const char* name, const char* title) :
 TNamed(name,title),
 fBinning(0x0),
-fBins(0x0)
+fBins(0x0),
+fWeight(1.0)
 {
   // default ctor
 }
@@ -46,7 +47,8 @@ fBins(0x0)
 AliAnalysisMuMuSpectra::AliAnalysisMuMuSpectra(const AliAnalysisMuMuSpectra& rhs)
 : TNamed(rhs.GetName(),rhs.GetTitle()),
 fBinning(0x0),
-fBins(0x0)
+fBins(0x0),
+fWeight(rhs.Weight())
 {
   // copy ctor
 
@@ -56,9 +58,9 @@ fBins(0x0)
   }
 
   TIter next(rhs.fBins);
-  AliAnalysisMuMuBinning::Range* bin;
+  AliAnalysisMuMuResult* bin;
   
-  while ( ( bin = static_cast<AliAnalysisMuMuBinning::Range*>(next()) ) )
+  while ( ( bin = static_cast<AliAnalysisMuMuResult*>(next()) ) )
   {
     if (!fBins)
     {
@@ -67,6 +69,8 @@ fBins(0x0)
     }
     fBins->Add(bin);
   }
+  
+  
 }
 
 //______________________________________________________________________________
@@ -88,9 +92,9 @@ AliAnalysisMuMuSpectra::operator=(const AliAnalysisMuMuSpectra& rhs)
   }
   
   TIter next(rhs.fBins);
-  AliAnalysisMuMuBinning::Range* bin;
+  AliAnalysisMuMuResult* bin;
   
-  while ( ( bin = static_cast<AliAnalysisMuMuBinning::Range*>(next()) ) )
+  while ( ( bin = static_cast<AliAnalysisMuMuResult*>(next()) ) )
   {
     if (!fBins)
     {
@@ -100,6 +104,8 @@ AliAnalysisMuMuSpectra::operator=(const AliAnalysisMuMuSpectra& rhs)
     fBins->Add(bin);
   }
   
+  fWeight = rhs.Weight();
+  
   return *this;
 }
 
@@ -155,13 +161,13 @@ Bool_t AliAnalysisMuMuSpectra::Correct(const AliAnalysisMuMuSpectra& accEff, con
     return kFALSE;
   }
   
-  TObjArray* bins = accEff.Bins();
+  TObjArray* bins = accEff.BinContentArray();
 
   
   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));
+    AliAnalysisMuMuJpsiResult* thisResult = static_cast<AliAnalysisMuMuJpsiResult*>(fBins->At(i));
+    AliAnalysisMuMuJpsiResult* accResult = static_cast<AliAnalysisMuMuJpsiResult*>(bins->At(i));
 //    AliInfoClass(Form("i=%d",i ));
 //    StdoutToAliInfoClass(thisResult->Print("full");
 //                         std::cout << "----" << std::endl;
@@ -251,7 +257,15 @@ Long64_t AliAnalysisMuMuSpectra::Merge(TCollection* list)
   
   TList binningList;
   
-  for ( Int_t i = 0; i <= fBins->GetLast(); ++i )
+  // for each bin must do a list of results, and merge that list
+  
+  TObjArray* bins = fBinning->CreateBinObjArray();
+  TIter nextBin(bins);
+  AliAnalysisMuMuBinning::Range* bin;
+
+  Int_t i(0);
+  
+  while ( ( bin = static_cast<AliAnalysisMuMuBinning::Range*>(nextBin()) ) )
   {
     next.Reset();
     
@@ -259,35 +273,31 @@ Long64_t AliAnalysisMuMuSpectra::Merge(TCollection* list)
     
     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;
-      }
-    
+      AliAnalysisMuMuSpectra* spectra = static_cast<AliAnalysisMuMuSpectra*>(currObj);
+
       if (i==0)
       {
         binningList.Add(spectra->Binning());
   
-        if ( !fBinning->IsEqual(spectra->Binning()) || spectra->Bins()->GetLast() != Bins()->GetLast() )
+        if ( !fBinning->IsEqual(spectra->Binning()) || spectra->BinContentArray()->GetLast() != BinContentArray()->GetLast() )
         {
           AliError("Cannot merge spectra with different binning");
           continue;
         }
-        
         ++count;
       }
       
-      binList.Add(fBins->At(i));
+      binList.Add(spectra->GetResultForBin(*bin));
     }
     
-    AliAnalysisMuMuResult* r = static_cast<AliAnalysisMuMuResult*>(fBins->At(i));
+    ++i;
+    
+    AliAnalysisMuMuResult* r = static_cast<AliAnalysisMuMuResult*>(GetResultForBin(*bin));
     r->Merge(&binList);
     
   }
-  
-  fBinning->Merge(&binningList);
+
+  delete bins;
   
   return count+1;
 }
@@ -310,13 +320,13 @@ TH1* AliAnalysisMuMuSpectra::Plot(const char* what, const char* subresult, Bool_
   
   for ( Int_t j = 0; j < TMath::Min(binArray->GetEntries(),fBins->GetEntries()); ++j )
   {
-    AliAnalysisMuMuResult* r = static_cast<AliAnalysisMuMuResult*>(fBins->At(j));
+    AliAnalysisMuMuJpsiResult* r = static_cast<AliAnalysisMuMuJpsiResult*>(fBins->At(j));
     
     if ( strlen(subresult) > 0 && r->SubResults() )
     {
       TString sub(subresult);
       sub.ToUpper();
-      r = r->SubResult(sub.Data());
+      r = static_cast<AliAnalysisMuMuJpsiResult*>(r->SubResult(sub.Data()));
       if (!r) continue;
     }
     
@@ -337,8 +347,11 @@ TH1* AliAnalysisMuMuSpectra::Plot(const char* what, const char* subresult, Bool_
       yerr /= (b.WidthX());
     }
     
+    if (!TMath::Finite(y)) y = 0.0;
+    if (!TMath::Finite(yerr)) yerr = 0.0;
+
     std::cout << b.AsString();
-    AliAnalysisMuMuResult::PrintValue(swhat.Data(),"",y,yerr);
+    r->PrintValue(swhat.Data(),"",y,yerr);
     
     h->SetBinContent(j+1,y);
     h->SetBinError(j+1,yerr);
@@ -369,3 +382,31 @@ void AliAnalysisMuMuSpectra::Print(Option_t* opt) const
     }
   }
 }
+
+//______________________________________________________________________________
+void AliAnalysisMuMuSpectra::Scale(Double_t value)
+{
+  // scale all bins by value
+
+  TIter next(fBins);
+  AliAnalysisMuMuResult* r;
+
+  while ( ( r = static_cast<AliAnalysisMuMuResult*>(next()) ) )
+  {
+    r->Scale(value);
+  }
+}
+
+//______________________________________________________________________________
+void AliAnalysisMuMuSpectra::SetWeight(Double_t w)
+{
+  // Set the weight of this spectra
+  fWeight = w;
+  TIter next(fBins);
+  AliAnalysisMuMuResult* r;
+  
+  while ( ( r = static_cast<AliAnalysisMuMuResult*>(next()) ) )
+  {
+    r->SetWeight(Weight());
+  }
+}
index 3080d82d39e91c6dead0871eab9e69307bb31882..0902d7805f6fbf7117dfd7c458d5871a29c43cfe 100644 (file)
@@ -39,7 +39,7 @@ public:
 
   void Print(Option_t* opt="") const;
 
-  TObjArray* Bins() const { return fBins; }
+  TObjArray* BinContentArray() const { return fBins; }
   
   AliAnalysisMuMuBinning* Binning() const { return fBinning; }
   
@@ -49,11 +49,18 @@ public:
   
   Bool_t HasValue(const char* what="NofJpsi") const;
   
+  void Scale(Double_t value);
+  
+  void SetWeight(Double_t w);
+  
+  Double_t Weight() const { return fWeight; }
+  
 private:
   AliAnalysisMuMuBinning* fBinning; // internal binning
   TObjArray* fBins; // the results (bin by bin)
+  Double_t fWeight; // weight of this spectra (assumed to be a normalized weight)
   
-  ClassDef(AliAnalysisMuMuSpectra,1) // class to hold spectra (with its associated binning and errors)
+  ClassDef(AliAnalysisMuMuSpectra,2) // class to hold spectra (with its associated binning and errors)
 };
 
 #endif
index eeb832440df51f660d6063bb1fc59838f0eeea69..95fb28ccc6851f87bfcb737da0895949d6725bd4 100644 (file)
@@ -112,18 +112,6 @@ namespace {
     return 0;
   }
   
-  
-  //______________________________________________________________________________
-  Double_t Mu(Double_t L0B, Double_t Nb)
-  {
-    /// L0B = trigger rate before any veto
-    /// Nb = number of crossing bunches
-    
-    Double_t p0 = 1-L0B/(Nb*11245.0); // proba to get *no* collision per bunch crossing
-    
-    return -TMath::Log(p0);
-  }
-  
   //______________________________________________________________________________
   TCanvas* NewCanvas(const char* name)
   {
@@ -211,14 +199,14 @@ Bool_t AliAnalysisTriggerScalers::CheckRecord(const AliTriggerScalersRecord& rec
 
 
 //______________________________________________________________________________
-void AliAnalysisTriggerScalers::DrawFill(Int_t run1, Int_t run2, double ymin, double ymax, const char* label)
+void AliAnalysisTriggerScalers::DrawFill(Int_t run1, Int_t run2, double ymin, double ymax, const char* label, Int_t color)
 {
   // Draw a yellow box to indicate a run range
   
   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->SetFillColor(color);
   b->Draw();
   TText* text = new TText((run1+run2)/2.0,ymin + (ymax-ymin)*0.85,label);
   text->SetTextSize(0.025);
@@ -229,7 +217,7 @@ void AliAnalysisTriggerScalers::DrawFill(Int_t run1, Int_t run2, double ymin, do
 }
 
 //_____________________________________________________________________________
-void AliAnalysisTriggerScalers::DrawFills(Double_t ymin, Double_t ymax)
+void AliAnalysisTriggerScalers::DrawFills(Double_t ymin, Double_t ymax, Int_t color)
 {
   /// Draw the fill ranges corresponding to the list of runs
   /// Note that this method will scan the OCDB to get the run -> fill number relationship,
@@ -247,8 +235,28 @@ void AliAnalysisTriggerScalers::DrawFills(Double_t ymin, Double_t ymax)
     const std::pair<int,int>& p = it->second;
     TString fillnumber;
     fillnumber.Form("%d",it->first);
-    DrawFill(p.first,p.second,ymin,ymax,fillnumber.Data());
+    DrawFill(p.first,p.second,ymin,ymax,fillnumber.Data(),color);
+  }
+}
+
+//_____________________________________________________________________________
+void AliAnalysisTriggerScalers::DrawPeriods(Double_t ymin, Double_t ymax, Int_t color)
+{
+  /// Draw the period ranges corresponding to the list of runs
+  /// Note that this method will scan the OCDB to get the run -> fill number relationship,
+  /// so it's better in this case to use a local copy of the OCDB if you have one. Otherwise
+  /// it will be long.
+
+  std::map<std::string, std::pair<int,int> > periods;
+  
+  GetLHCPeriodBoundaries(periods);
+  
+  for ( std::map<std::string, std::pair<int,int> >::const_iterator it = periods.begin(); it != periods.end(); ++it )
+  {
+    const std::pair<int,int>& p = it->second;
+    DrawFill(p.first,p.second,ymin,ymax,it->first.c_str(),color);
   }
+
 }
 
 //_____________________________________________________________________________
@@ -321,6 +329,7 @@ TObject* AliAnalysisTriggerScalers::GetOCDBObject(const char* path, Int_t runNum
   
   if ( !AliCDBManager::Instance()->IsDefaultStorageSet() )
   {
+    AliInfo(Form("Setting OCDB default storage to %s",fOCDBPath.Data()));
     AliCDBManager::Instance()->SetDefaultStorage(fOCDBPath.Data());
   }
   
@@ -527,6 +536,66 @@ AliAnalysisTriggerScalers::GetPauseAndConfigCorrection(Int_t runNumber, const ch
   return total > 0 ? nopac*1.0/total : 0.0;
 }
 
+//______________________________________________________________________________
+void AliAnalysisTriggerScalers::GetPileUpFactor(Int_t runNumber, const char* triggerClassName,
+                                                Double_t purity,
+                                                Double_t& value, Double_t& error)
+{
+  /// Get the mean pile-up correction factor for the given run
+
+  value = error = 0.0;
+
+  if (purity<=0.0)
+  {
+    AliError(Form("Cannot work with purity=%f for trigger %s in run %d. Should be strictly positive",purity,triggerClassName,runNumber));
+    return;             
+  }
+  
+  AliTriggerRunScalers* trs = static_cast<AliTriggerRunScalers*>(GetOCDBObject("GRP/CTP/Scalers",runNumber));
+  const TObjArray* scalers = trs->GetScalersRecords();
+  const AliTriggerScalersRecord* begin = (AliTriggerScalersRecord*)(scalers->First());
+  const AliTriggerScalersRecord* end = (AliTriggerScalersRecord*)(scalers->Last());
+  
+  time_t duration = TMath::Nint((end->GetTimeStamp()->GetBunchCross() - begin->GetTimeStamp()->GetBunchCross())*AliTimeStamp::fNanosecPerBC*1E-9);
+  
+  if (!duration)
+  {
+    AliError(Form("Got zero duration for run %d",runNumber));
+    return;
+  }
+  
+  AliAnalysisTriggerScalerItem* item = GetTriggerScaler(runNumber,"L0B",triggerClassName);
+  if (!item)
+  {
+    AliError(Form("Could not get L0B for trigger %s in run %d",triggerClassName,runNumber));
+    return;
+  }
+  
+  AliLHCData* lhc = static_cast<AliLHCData*>(GetOCDBObject("GRP/GRP/LHCData",runNumber));
+  
+  Int_t nbcx = NumberOfInteractingBunches(*lhc,runNumber);
+  
+  if ( nbcx<=0.0 )
+  {
+    AliError(Form("Cannot work with nbcx=%d for trigger %s in run %d. Should be strictly positive",nbcx,triggerClassName,runNumber));
+    return;
+  }
+  
+  Double_t itemValue = purity*item->Value();
+  
+  if (itemValue<=0.0)
+  {
+    AliError(Form("Cannot work with value=%f for trigger %s in run %d. Should be strictly positive",itemValue,triggerClassName,runNumber));
+    return;
+  }
+
+  Double_t mu = Mu(itemValue/duration,nbcx);
+  
+  value = mu/(1.0-TMath::Exp(-mu));
+  
+  error = 0.0; // FIXME
+}
+
 //______________________________________________________________________________
 AliAnalysisTriggerScalerItem* 
 AliAnalysisTriggerScalers::GetTriggerScaler(Int_t runNumber, const char* level, const char* triggerClassName)
@@ -704,7 +773,7 @@ AliAnalysisTriggerScalers::IntegratedLuminosityGraph(Int_t runNumber, const char
     return 0x0;
   }
 
-  Int_t nbcx = NumberOfInteractingBunches(*lhc);
+  Int_t nbcx = NumberOfInteractingBunches(*lhc,runNumber);
   
   if (nbcx <= 0 && ShouldCorrectForPileUp())
   {
@@ -1156,7 +1225,18 @@ TGraph* AliAnalysisTriggerScalers::MakeGraph(const std::vector<int>& vx,
 }
 
 //______________________________________________________________________________
-Int_t AliAnalysisTriggerScalers::NumberOfInteractingBunches(const AliLHCData& lhc) const
+Double_t AliAnalysisTriggerScalers::Mu(Double_t L0B, Double_t Nb)
+{
+  /// L0B = trigger rate before any veto
+  /// Nb = number of crossing bunches
+  
+  Double_t p0 = 1-L0B/(Nb*11245.0); // proba to get *no* collision per bunch crossing
+  
+  return -TMath::Log(p0);
+}
+
+//______________________________________________________________________________
+Int_t AliAnalysisTriggerScalers::NumberOfInteractingBunches(const AliLHCData& lhc, Int_t runNumber) const
 {
   /// Extract the number of colliding bunches from the LHC data
   
@@ -1188,11 +1268,29 @@ Int_t AliAnalysisTriggerScalers::NumberOfInteractingBunches(const AliLHCData& lh
     if ( valm->GetValue(i) <= 0 ) ++nIBM2;
   }
 
+  if (!numberOfInteractingBunches)
+  {
+    return 0;
+  }
+
   if ( numberOfInteractingBunches != numberOfInteractingBunchesMeasured ||
        numberOfInteractingBunches != nIBM2 )
   {
-    AliWarning(Form("Got some different number of interacting bunches here ! NumberOfInteractingBunches=%3d NumberOfInteractingBunchesMeasured=%3d NIBM2=%3d",
-                  numberOfInteractingBunches,numberOfInteractingBunchesMeasured,nIBM2));
+    Int_t delta = TMath::Max(numberOfInteractingBunches - numberOfInteractingBunchesMeasured,numberOfInteractingBunches-nIBM2);
+    
+    if ( 1.0*TMath::Abs(delta)/numberOfInteractingBunches > 0.05 ) // more than 5% difference
+    {
+      AliWarning(Form("Got some different number of interacting bunches for fill %d run %d ! NumberOfInteractingBunches=%3d NumberOfInteractingBunchesMeasured=%3d NIBM2=%3d. Will use %d",
+                    lhc.GetFillNumber(),runNumber,
+                      numberOfInteractingBunches,numberOfInteractingBunchesMeasured,nIBM2,numberOfInteractingBunches));
+    }
+    else
+    {
+      AliDebug(1,Form("Got some different number of interacting bunches for fill %d run %d ! NumberOfInteractingBunches=%3d NumberOfInteractingBunchesMeasured=%3d NIBM2=%3d. Will use %d",
+                      lhc.GetFillNumber(),runNumber,
+                      numberOfInteractingBunches,numberOfInteractingBunchesMeasured,nIBM2,numberOfInteractingBunches));
+      
+    }
   }
   
   return numberOfInteractingBunches;
@@ -1347,7 +1445,7 @@ TGraph* AliAnalysisTriggerScalers::PlotTriggerEvolution(const char* triggerClass
     
     GetCTPObjects(runNumber,tc,trs,lhc);
     
-    Int_t numberOfInteractingBunches = NumberOfInteractingBunches(*lhc);
+    Int_t numberOfInteractingBunches = NumberOfInteractingBunches(*lhc,runNumber);
     
     const TObjArray* scalers = trs->GetScalersRecords();
     
@@ -1453,6 +1551,7 @@ TGraph* AliAnalysisTriggerScalers::PlotTriggerEvolution(const char* triggerClass
         }
         else if ( swhat.Contains("MU") )
         {
+          if (timelapse==0) continue;
           value = Mu(l0b/timelapse,numberOfInteractingBunches);
           error = 0.0; // FIXME
         }
@@ -1697,7 +1796,12 @@ void AliAnalysisTriggerScalers::ReadIntegers(const char* filename,
 {
   /// Read integers from filename, where integers are either
   /// separated by "," or by return carriage
-    std::ifstream in(gSystem->ExpandPathName(filename));
+  
+  if ( gSystem->AccessPathName(filename)==kTRUE ) 
+  {
+    return;
+  }
+  std::ifstream in(gSystem->ExpandPathName(filename));
   int i;
   
   std::set<int> runset;
@@ -1814,6 +1918,17 @@ void AliAnalysisTriggerScalers::SetRunList(const char* runlist)
   else
   {
     ReadIntegers(runlist,fRunList);
+    if (fRunList.empty())
+    {
+      if ( TString(runlist).IsDigit() )
+      {
+        SetRunList(TString(runlist).Atoi());
+      }
+      else
+      {
+        AliError("Could not set run list !");
+      }
+    }
   }
 }
 
index db2ad09a17ad88fcf545a50b4987d5de8c1acef4..2d94ce8dd71e656c640dd6336a24928323cc259d 100644 (file)
@@ -40,8 +40,10 @@ public:
   void CrossSectionUnit(const char* unit="ub") { fCrossSectionUnit=unit; fCrossSectionUnit.ToUpper(); }
   TString CrossSectionUnit() const { return fCrossSectionUnit; }
   
-  void DrawFills(Double_t ymin, Double_t ymax);
-  void DrawFill(Int_t run1, Int_t run2, double ymin, double ymax, const char* label);
+  void DrawFills(Double_t ymin, Double_t ymax, Int_t color=5);
+  void DrawFill(Int_t run1, Int_t run2, double ymin, double ymax, const char* label,Int_t color=5);
+
+  void DrawPeriods(Double_t ymin, Double_t ymax, Int_t color=5);
 
   void GetCTPObjects(Int_t runNumber, AliTriggerConfiguration*& tc, AliTriggerRunScalers*& trs, AliLHCData*& lhc) const;
 
@@ -62,6 +64,8 @@ public:
   
   Float_t GetPauseAndConfigCorrection(Int_t runNumber, const char* triggerClassName);
 
+  void GetPileUpFactor(Int_t runNumber, const char* triggerClassName, Double_t purity, Double_t& value, Double_t& error);
+  
   const std::vector<int>& GetRunList() const { return fRunList; }
 
   Int_t GetTriggerInput(Int_t runNumber, const char* inputname);
@@ -82,7 +86,9 @@ public:
   TGraph* MakeGraph(const std::vector<int>& vx, const std::vector<int>& vex,
                     const std::vector<double>& vy, const std::vector<double>& vey);
 
-  Int_t NumberOfInteractingBunches(const AliLHCData& lhc) const;
+  static Double_t Mu(Double_t L0B, Double_t Nb);
+
+  Int_t NumberOfInteractingBunches(const AliLHCData& lhc, Int_t runNumber) const;
 
   TGraph* PlotTrigger(const char* triggerClassName, const char* what);
   
index a5b6610e06d5c87fb002445001418ece813a70ea..dcb2b3830f5b978f0cd891c54c318a503a91f688 100644 (file)
@@ -74,44 +74,25 @@ namespace
   Int_t splitLevel=10;
 }
 
+ClassImp(AliMuonAccEffSubmitter)
+
 //______________________________________________________________________________
 AliMuonAccEffSubmitter::AliMuonAccEffSubmitter(const char* generator)
-: TObject(),
-fScalers(0x0),
-fRemoteDir(""),
-fReferenceTrigger(""),
-fRatio(1.0),
+: AliMuonGridSubmitter(AliMuonGridSubmitter::kAccEff),
+fRatio(-1.0),
 fFixedNofEvents(10000),
 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),
+fUseOCDBSnapshots(kFALSE),
 fUseAODMerging(kFALSE)
 {
   // ctor
   
-  if (!TGrid::Connect("alien://"))
-  {
-    AliError("cannot connect to grid");
-    fIsValid = kFALSE;
-  }
-
-  SetPackages("VO_ALICE@AliRoot::v5-03-Rev-18","VO_ALICE@GEANT3::v1-14-8","VO_ALICE@ROOT::v5-34-05-1");
+  SetOCDBPath("raw://");
+  
+  SetLocalDirectory("Snapshot",LocalDir());
   
   SetVar("VAR_OCDB_PATH","\"raw://\"");
 
@@ -146,324 +127,47 @@ fUseAODMerging(kFALSE)
   SetVar("VAR_GENPARAMCUSTOMSINGLE_Y_P2","0.141776");
   SetVar("VAR_GENPARAMCUSTOMSINGLE_Y_P3","0.0130173");
 
-  UseOCDBSnapshots(kTRUE);
+  UseOCDBSnapshots(fUseOCDBSnapshots);
   
   SetGenerator(generator);
-}
-
-//______________________________________________________________________________
-AliMuonAccEffSubmitter::~AliMuonAccEffSubmitter()
-{
-  // dtor
-  delete fScalers;
-  delete fTemplateFileList;
-  delete fLocalFileList;
-  delete fVars;
-}
-
-//______________________________________________________________________________
-Bool_t AliMuonAccEffSubmitter::CheckCompilation(const char* file) const
-{
-  /// Check whether file can be compiled or not
-  /// FIXME: use gSystem->TempFileName for tmpfile !
-  
-  Bool_t rv(kTRUE);
-  
-  TString sfile(gSystem->BaseName(file));
-  TString tmpfile(Form("tmpfile_%s",sfile.Data()));
-  
-  gSystem->Exec(Form("cp %s %s",file,tmpfile.Data()));
   
-  ReplaceVars(tmpfile.Data());
+  MakeNofEventsPropToTriggerCount();
   
-  gSystem->AddIncludePath("-I$ALICE_ROOT/include");
-  gSystem->AddIncludePath("-I$ALICE_ROOT/EVGEN");
-
-  if (gROOT->LoadMacro(Form("%s++",tmpfile.Data())))
-  {
-    AliError(Form("macro %s can not be compiled. Please check.",file));
-    rv = kFALSE;
-  }
+  AddToTemplateFileList("CheckESD.C");
+  AddToTemplateFileList("CheckAOD.C");
+  AddToTemplateFileList("AODtrain.C");
+  AddToTemplateFileList("validation.sh");
   
-  gSystem->Exec(Form("rm %s",tmpfile.Data()));
+  AddToTemplateFileList("Config.C");
+  AddToTemplateFileList("rec.C");
+  AddToTemplateFileList("sim.C");
+  AddToTemplateFileList("simrun.C");
+  AddToTemplateFileList(RunJDLName().Data());
   
-  return rv;
+  UseExternalConfig(fExternalConfig);
 }
 
-
 //______________________________________________________________________________
-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
+AliMuonAccEffSubmitter::~AliMuonAccEffSubmitter()
 {
-  /// Clean (remove) remote files
-  AliWarning("implement me");
+  // dtor
 }
 
-//______________________________________________________________________________
-Bool_t AliMuonAccEffSubmitter::CopyFile(const char* localFile)
+///______________________________________________________________________________
+Bool_t AliMuonAccEffSubmitter::Generate(const char* jdlname) const
 {
-  /// copy a local file to remote destination
-  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 )
+  if ( TString(jdlname).Contains("merge",TString::kIgnoreCase) )
   {
-    AliDebug(1,Form("cp %s alien://%s",local.Data(),remote.Data()));
-    return TFile::Cp(local.Data(),Form("alien://%s",remote.Data()));
+    return GenerateMergeJDL(jdlname);
   }
   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;
-  
-  AliDebug(1,"");
-  
-  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 GenerateRunJDL(jdlname);
   }
-  
-  return kFALSE;
-}
-
-//______________________________________________________________________________
-Bool_t AliMuonAccEffSubmitter::CopyTemplateFilesToLocal()
-{
-  // copy (or generate) local files from the template ones
-  
-  if (!IsValid()) return kFALSE;
-
-  AliDebug(1,"");
-
-  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
-{
-  /// Create a JDL file
-  AliDebug(1,"");
-
-  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)
+Bool_t AliMuonAccEffSubmitter::GenerateMergeJDL(const char* name) const
 {
   /// Create the JDL for merging jobs
   /// FIXME: not checked !
@@ -484,57 +188,60 @@ Bool_t AliMuonAccEffSubmitter::GenerateMergeJDL(const char* name)
   << "# $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());
+  OutputToJDL(*os,"Packages",
+         GetMapValue("AliRoot"),
+         GetMapValue("Geant3"),
+         GetMapValue("Root"),
+         GetMapValue("API"));
   
-  Output(*os,"Executable","AOD_merge.sh");
+  OutputToJDL(*os,"Executable","AOD_merge.sh");
   
-  Output(*os,"Price","1");
+  OutputToJDL(*os,"Price","1");
 
   if ( final )
   {
-    Output(*os,"Jobtag","comment: AliMuonAccEffSubmitter final merging");
+    OutputToJDL(*os,"Jobtag","comment: AliMuonAccEffSubmitter final merging");
   }
   else
   {
-    Output(*os,"Jobtag","comment: AliMuonAccEffSubmitter merging stage $2");
+    OutputToJDL(*os,"Jobtag","comment: AliMuonAccEffSubmitter merging stage $2");
   }
   
-  Output(*os,"Workdirectorysize","5000MB");
+  OutputToJDL(*os,"Workdirectorysize","5000MB");
   
-  Output(*os,"Validationcommand",Form("%s/validation_merge.sh",fRemoteDir.Data()));
+  OutputToJDL(*os,"Validationcommand",Form("%s/validation_merge.sh",RemoteDir().Data()));
   
-  Output(*os,"TTL","7200");
+  OutputToJDL(*os,"TTL","7200");
 
-  Output(*os,"OutputArchive",
+  OutputToJDL(*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
+  OutputToJDL(*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");
+    OutputToJDL(*os,"InputFile",Form("LF:%s/AODtrain.C",RemoteDir().Data()));
+    OutputToJDL(*os,"OutputDir",Form("%s/$1/Stage_$2/#alien_counter_03i#",RemoteDir().Data()));
+    OutputToJDL(*os,"InputDataCollection",Form("%s/$1/Stage_$2.xml,nodownload",RemoteDir().Data()));
+    OutputToJDL(*os,"split","se");
+    OutputToJDL(*os,"SplitMaxInputFileNumber",GetSplitMaxInputFileNumber());
+    OutputToJDL(*os,"InputDataListFormat","xml-single");
+    OutputToJDL(*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()));
+    OutputToJDL(*os,"InputFile",Form("LF:%s/AODtrain.C",RemoteDir().Data()),
+           Form("LF:%s/$1/wn.xml",RemoteDir().Data()));
+    OutputToJDL(*os,"OutputDir",Form("%s/$1",RemoteDir().Data()));
   }
   
   return kTRUE;
 }
 
 //______________________________________________________________________________
-Bool_t AliMuonAccEffSubmitter::GenerateRunJDL(const char* name)
+Bool_t AliMuonAccEffSubmitter::GenerateRunJDL(const char* name) const
 {
   /// Generate (locally) the JDL to perform the simulation+reco+aod filtering
   /// (to be then copied to the grid and finally submitted)
@@ -548,18 +255,21 @@ Bool_t AliMuonAccEffSubmitter::GenerateRunJDL(const char* name)
     return kFALSE;
   }
   
-  Output(*os,"Packages",fPackageAliroot.Data(),fPackageGeant3.Data(),
-         fPackageRoot.Data(),fPackageApi.Data());
-
-  Output(*os,"Jobtag","comment: AliMuonAccEffSubmitter RUN $1");
+  OutputToJDL(*os,"Packages",
+              GetMapValue("AliRoot"),
+              GetMapValue("Geant3"),
+              GetMapValue("Root"),
+              GetMapValue("API"));
+              
+  OutputToJDL(*os,"Jobtag","comment: AliMuonAccEffSubmitter RUN $1");
 
-  Output(*os,"split","production:1-$2");
+  OutputToJDL(*os,"split","production:1-$2");
 
-  Output(*os,"Price","1");
+  OutputToJDL(*os,"Price","1");
   
-  Output(*os,"OutputDir",Form("%s/$1/#alien_counter_03i#",fRemoteDir.Data()));
+  OutputToJDL(*os,"OutputDir",Form("%s/$1/#alien_counter_03i#",RemoteDir().Data()));
 
-  Output(*os,"Executable","/alice/bin/aliroot_new");
+  OutputToJDL(*os,"Executable","/alice/bin/aliroot_new");
   
   TObjArray files;
   files.SetOwner(kTRUE);
@@ -571,29 +281,29 @@ Bool_t AliMuonAccEffSubmitter::GenerateRunJDL(const char* name)
     if ( !file->String().Contains(".jdl",TString::kIgnoreCase) ||
          !file->String().Contains("OCDB_") )
     {
-      files.Add(new TObjString(Form("LF:%s/%s",fRemoteDir.Data(),file->String().Data())));      
+      files.Add(new TObjString(Form("LF:%s/%s",RemoteDir().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())));
+    files.Add(new TObjString(Form("LF:%s/OCDB/$1/OCDB_sim.root",RemoteDir().Data())));
+    files.Add(new TObjString(Form("LF:%s/OCDB/$1/OCDB_rec.root",RemoteDir().Data())));
   }
   
-  Output(*os,"InputFile",files);
+  OutputToJDL(*os,"InputFile",files);
   
   if ( CompactMode() == 0 )
   {
     // store everything
-    Output(*os,"OutputArchive",  "log_archive.zip:stderr,stdout,aod.log,checkaod.log,checkesd.log,rec.log,sim.log@disk=1",
+    OutputToJDL(*os,"OutputArchive",  "log_archive.zip:stderr,stdout,aod.log,checkaod.log,checkesd.log,rec.log,sim.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");
+    // keep only muon AODs and QA
+    OutputToJDL(*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,Merged.QA.Data.root@disk=2");
   }
   else
   {
@@ -602,108 +312,19 @@ Bool_t AliMuonAccEffSubmitter::GenerateRunJDL(const char* name)
     return kFALSE;
   }
   
-  Output(*os,"splitarguments","simrun.C --run $1 --chunk #alien_counter# --event $3");
+  OutputToJDL(*os,"splitarguments","simrun.C --run $1 --chunk #alien_counter# --event $3");
   
-  Output(*os,"Workdirectorysize","5000MB");
+  OutputToJDL(*os,"Workdirectorysize","5000MB");
   
-  Output(*os,"JDLVariables","Packages","OutputDir");
+  OutputToJDL(*os,"JDLVariables","Packages","OutputDir");
 
-  Output(*os,"Validationcommand",Form("%s/validation.sh",fRemoteDir.Data()));
+  OutputToJDL(*os,"Validationcommand",Form("%s/validation.sh",RemoteDir().Data()));
 
-  Output(*os,"TTL","72000");
+  OutputToJDL(*os,"TTL","72000");
   
   return kTRUE;
 }
 
-//______________________________________________________________________________
-Bool_t AliMuonAccEffSubmitter::GetLastStage(const char* remoteDir) const
-{
-  /// Get the last staging phase already performed
-  /// FIXME : not checked !
-  
-  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;
-}
-
-//______________________________________________________________________________
-TObjArray* AliMuonAccEffSubmitter::GetVariables(const char* file) const
-{
-  /// Find the variables in the file
-  
-  std::ifstream in(file);
-  char line[1024];
-  TObjArray* variables(0x0);
-  
-  while ( in.getline(line,1023,'\n') )
-  {
-    TString sline(line);
-    while (sline.Contains("VAR_") && !sline.BeginsWith("//") )
-    {
-      Int_t i1 = sline.Index("VAR_");
-      Int_t i2(i1);
-      
-      while ( ( i2 < sline.Length() ) && ( isalnum(sline[i2]) || sline[i2]=='_' ) ) ++i2;
-      
-      if (!variables)
-      {
-        variables = new TObjArray;
-        variables->SetOwner(kTRUE);
-      }
-      
-      TString var = sline(i1,i2-i1);
-      if ( !variables->FindObject(var) )
-      {
-        variables->Add(new TObjString(var));
-      }
-      sline.ReplaceAll(var,"");
-    }
-  }
-  
-  in.close();
-  
-  return variables;
-}
-
-//______________________________________________________________________________
-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()
 {
@@ -714,14 +335,14 @@ Bool_t AliMuonAccEffSubmitter::MakeOCDBSnapshots()
 
   if (!fUseOCDBSnapshots) return kTRUE;
   
-  if (!fScalers) return kFALSE;
+  if (!NofRuns()) return kFALSE;
   
   AliDebug(1,"");
 
-  const std::vector<int>& runs = fScalers->GetRunList();
-
   Bool_t ok(kTRUE);
   
+  const std::vector<int>& runs = RunList();
+  
   for ( std::vector<int>::size_type i = 0; i < runs.size(); ++i )
   {
     Int_t runNumber = runs[i];
@@ -775,22 +396,22 @@ Bool_t AliMuonAccEffSubmitter::Merge(Int_t stage, Bool_t dryRun)
   /// - stage=0 --> final merging / stage>0 --> intermediate merging i
   ///
   
-  if (!RemoteDirectoryExists(fMergedDir.Data())) {
-    AliError(Form("directory %s does not exist", fMergedDir.Data()));
+  if (!RemoteDirectoryExists(MergedDir().Data())) {
+    AliError(Form("directory %s does not exist", MergedDir().Data()));
     return kFALSE;
   }
   
-  gGrid->Cd(fMergedDir.Data());
+  gGrid->Cd(MergedDir().Data());
   
   TString jdl = MergeJDLName(stage==0);
   
   if (!RemoteFileExists(jdl.Data()))
   {
-    AliError(Form("file %s does not exist in %s\n", jdl.Data(), fRemoteDir.Data()));
+    AliError(Form("file %s does not exist in %s\n", jdl.Data(), RemoteDir().Data()));
     return kFALSE;
   }
   
-  const std::vector<int>& runs = fScalers->GetRunList();
+  const std::vector<int>& runs = RunList();
   
   if (runs.empty())
   {
@@ -808,7 +429,7 @@ Bool_t AliMuonAccEffSubmitter::Merge(Int_t stage, Bool_t dryRun)
     Int_t run = runs[i];
     AliInfo(Form("\n --- processing run %d ---\n", run));
     
-    TString runDir = Form("%s/%d", fMergedDir.Data(), run);
+    TString runDir = Form("%s/%d", MergedDir().Data(), run);
     
     if (!RemoteDirectoryExists(runDir.Data()))
     {
@@ -832,8 +453,8 @@ Bool_t AliMuonAccEffSubmitter::Merge(Int_t stage, Bool_t dryRun)
     
     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);
+    Form("alien_find -x %s %s/%d *root_archive.zip", wn.Data(), RemoteDir().Data(), run) :
+    Form("alien_find -x %s %s/%d/Stage_%d *root_archive.zip", wn.Data(), RemoteDir().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__");
@@ -923,107 +544,16 @@ Bool_t AliMuonAccEffSubmitter::Merge(Int_t stage, Bool_t dryRun)
 }
 
 //______________________________________________________________________________
-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
-{
-  /// output to ostream of key,{values} pair
-  
-  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
-{
-  /// output to ostream
-  
-  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
+void AliMuonAccEffSubmitter::Print(Option_t* opt) const
 {
   /// Printout
   
-  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;
-  
-  if ( fSnapshotDir != fLocalDir )
-  {
-    std::cout << "Snapshots directory = " << fSnapshotDir.Data() << std::endl;
-  }
-  
-  std::cout << "OCDB path = " << fOCDBPath.Data() << std::endl;
-  
+  AliMuonGridSubmitter::Print(opt);
+
   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;
+                      fRatio,ReferenceTrigger().Data()) << std::endl;
   }
   else
   {
@@ -1032,142 +562,7 @@ void AliMuonAccEffSubmitter::Print(Option_t* /*opt*/) const
   
   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) const
-{
-  /// Replace the variables (i.e. things starting by VAR_) found in 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;
+  std::cout << "Will" << (fUseOCDBSnapshots ? "" : " NOT") << " use OCDB snaphosts" << std::endl;
 }
 
 //______________________________________________________________________________
@@ -1241,56 +636,16 @@ Bool_t AliMuonAccEffSubmitter::Run(const char* mode)
   return kFALSE;
 }
 
-//______________________________________________________________________________
-void AliMuonAccEffSubmitter::SetPackages(const char* aliroot,
-                                         const char* root,
-                                         const char* geant3,
-                                         const char* api)
-{
-  /// Set the packages to be used by the jobs
-  /// Must be a valid combination, see http://alimonitor.cern.ch/packages/
-  ///
-  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::SetGenerator(const char* generator)
 {
   // set the variable to select the generator macro in Config.C
   
   gSystem->Load("libEVGEN");
-    
-  fIsValid = kFALSE;
   
-  TString generatorFile(Form("%s/%s.C",fTemplateDir.Data(),generator));
+  Invalidate();
+  
+  TString generatorFile(Form("%s/%s.C",TemplateDir().Data(),generator));
   
   Int_t nofMissingVariables(0);
   
@@ -1304,7 +659,7 @@ Bool_t AliMuonAccEffSubmitter::SetGenerator(const char* generator)
     
     while ( ( var = static_cast<TObjString*>(next())) )
     {
-      if ( !fVars->GetValue(var->String()) )
+      if ( !Vars()->GetValue(var->String()) )
       {
         ++nofMissingVariables;
         AliError(Form("file %s expect the variable %s to be defined, but we've not defined it !",generatorFile.Data(),var->String().Data()));
@@ -1317,9 +672,9 @@ Bool_t AliMuonAccEffSubmitter::SetGenerator(const char* generator)
     {
       if (CheckCompilation(generatorFile.Data()))
       {
-        fIsValid = kTRUE;
+        Validate();
         SetVar("VAR_GENERATOR",Form("%s",generator));        
-        TemplateFileList()->Add(new TObjString(Form("%s.C",generator)));
+        AddToTemplateFileList(Form("%s.C",generator));
         return kTRUE;
       }
     }
@@ -1335,69 +690,12 @@ Bool_t AliMuonAccEffSubmitter::SetGenerator(const char* generator)
   return kFALSE;
 }
 
-//______________________________________________________________________________
-Bool_t AliMuonAccEffSubmitter::SetMergedDir(const char* dir, Bool_t create)
-{
-  // Set the merged directory to be used
-  fMergedDir = GetRemoteDir(dir,create);
-  return (fMergedDir.Length()>0);
-}
-
-//______________________________________________________________________________
-Bool_t AliMuonAccEffSubmitter::SetRemoteDir(const char* dir, Bool_t create)
-{
-  // Set the remote directory to be used
-  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);
-}
-
 //______________________________________________________________________________
 void AliMuonAccEffSubmitter::SetOCDBPath(const char* ocdbPath)
 {
   /// Sets the OCDB path to be used
   
-  fOCDBPath = ocdbPath;
-  
-  if (fScalers)
-  {
-    // redefine trigger scalers to use the new ocdb path
-    AliAnalysisTriggerScalers* ts = new AliAnalysisTriggerScalers(fScalers->GetRunList(),
-                                                                  fOCDBPath.Data());
-    
-    delete fScalers;
-    fScalers = ts;
-  }
+  SetMapKeyValue("OCDBPath",ocdbPath);
 }
 
 
@@ -1412,36 +710,26 @@ void AliMuonAccEffSubmitter::SetOCDBSnapshotDir(const char* dir)
   }
   else
   {
-    fSnapshotDir = dir;
+    SetMapKeyValue("OCDBSnapshot",dir);
   }
 }
 
 //______________________________________________________________________________
-Bool_t AliMuonAccEffSubmitter::SetVar(const char* varname, const char* value)
+void AliMuonAccEffSubmitter::MakeNofEventsPropToTriggerCount(const char* trigger, Float_t ratio)
 {
-  /// Set a variable
-  
-  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;
+  SetMapKeyValue("ReferenceTrigger",trigger);
+  fRatio = ratio;
+}
+
+//______________________________________________________________________________
+void AliMuonAccEffSubmitter::MakeNofEventsFixed(Int_t nevents)
+{
+  fFixedNofEvents = nevents;
+  fRatio=0.0;
+  SetMapKeyValue("ReferenceTrigger","");
 }
 
+
 //______________________________________________________________________________
 Int_t AliMuonAccEffSubmitter::Submit(Bool_t dryRun)
 {
@@ -1468,12 +756,12 @@ Int_t AliMuonAccEffSubmitter::Submit(Bool_t dryRun)
     return 0;
   }
   
-  if ( !fScalers )
+  if ( !NofRuns() )
   {
     AliError("No run list set. Use SetRunList");
     return 0;
   }
-  const std::vector<int>& runs = fScalers->GetRunList();
+  const std::vector<int>& runs = RunList();
   
   if (runs.empty())
   {
@@ -1492,6 +780,8 @@ Int_t AliMuonAccEffSubmitter::Submit(Bool_t dryRun)
   Int_t nJobs(0);
   Int_t nEvts(0);
   
+  AliAnalysisTriggerScalers* ts(0x0);
+  
   for (std::vector<int>::size_type i=0; i < runs.size(); ++i)
   {
     Int_t runNumber = runs[i];
@@ -1500,7 +790,13 @@ Int_t AliMuonAccEffSubmitter::Submit(Bool_t dryRun)
     
     if ( fRatio > 0 )
     {
-      AliAnalysisTriggerScalerItem* trigger = fScalers->GetTriggerScaler(runNumber, "L2A", ReferenceTrigger().Data());
+      if (!ts)
+      {
+        AliInfo(Form("Creating AliAnalysisTriggerScalers from OCDB=%s",OCDBPath().Data()));
+        ts = new AliAnalysisTriggerScalers(runs,OCDBPath().Data());
+      }
+      
+      AliAnalysisTriggerScalerItem* trigger = ts->GetTriggerScaler(runNumber, "L2A", ReferenceTrigger().Data());
     
       if (!trigger)
       {
@@ -1565,46 +861,9 @@ Int_t AliMuonAccEffSubmitter::Submit(Bool_t dryRun)
   << "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()));
-    if ( fUseAODMerging )
-    {
-      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"));
-    }
-  }
+  delete ts;
   
-  return fTemplateFileList;
+  return nJobs;
 }
 
 //______________________________________________________________________________
@@ -1612,7 +871,9 @@ void AliMuonAccEffSubmitter::UpdateLocalFileList(Bool_t clearSnapshots)
 {
   /// Update the list of local files
   
-  if (!fScalers) return;
+  AliMuonGridSubmitter::UpdateLocalFileList();
+  
+  if (!NofRuns()) return;
   
   if ( clearSnapshots )
   {
@@ -1629,10 +890,10 @@ void AliMuonAccEffSubmitter::UpdateLocalFileList(Bool_t clearSnapshots)
     LocalFileList()->Compress();
   }
 
-  const std::vector<int>& runs = fScalers->GetRunList();
-  
   const char* type[] = { "sim","rec" };
   
+  const std::vector<int>& runs = RunList();
+  
   for ( std::vector<int>::size_type i = 0; i < runs.size(); ++i )
   {
     Int_t runNumber = runs[i];
@@ -1679,5 +940,25 @@ void AliMuonAccEffSubmitter::UseAODMerging(Bool_t flag)
   /// whether or not we should generate JDL for merging AODs
   
   fUseAODMerging = flag;
-  // FIXME: here should update the TemplateFileList() (and LocalFileList as well ?)
+  
+  AddToTemplateFileList(MergeJDLName(kFALSE).Data());
+  AddToTemplateFileList(MergeJDLName(kTRUE).Data());
+  AddToTemplateFileList("AOD_merge.sh");
+  AddToTemplateFileList("validation_merge.sh");
+}
+
+//______________________________________________________________________________
+void AliMuonAccEffSubmitter::UseExternalConfig(const char* externalConfigFullFilePath)
+{
+  // use an external config (or the default Config.C if externalConfigFullFilePath="")
+  
+  fExternalConfig = externalConfigFullFilePath;
+  if ( fExternalConfig.Length() > 0 )
+  {
+    AddToTemplateFileList(fExternalConfig);
+  }
+  else
+  {
+    AddToTemplateFileList("Config.C");
+  }
 }
index 5a172c8153f7f38905ef809133c4ef9e20d4ae57..d3a1b39b115f00cd212b0d766a68a451b7f30cdc 100644 (file)
@@ -8,59 +8,27 @@
 // author: Laurent Aphecetche (Subatech)
 //
 
-#include "TObject.h"
-#include "TString.h"
-#include "Riostream.h"
+#include "AliMuonGridSubmitter.h"
 
-class AliAnalysisTriggerScalers;
-class TMap;
-
-class AliMuonAccEffSubmitter : public TObject
+class AliMuonAccEffSubmitter : public AliMuonGridSubmitter
 {
 public:
   AliMuonAccEffSubmitter(const char* generator="GenParamCustom");
 
-  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; }
-  
-  void UseAODMerging(Bool_t flag);
-  
-  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;
+  virtual Bool_t Generate(const char* jdlname) const;
+  virtual Bool_t Run(const char* mode);
 
-  Int_t MaxEventsPerChunk() const { return fMaxEventsPerChunk; }
-  void SetMaxEventsPerChunk(Int_t n) { fMaxEventsPerChunk = n; }
+  virtual ~AliMuonAccEffSubmitter();
 
-  UInt_t NofRuns() const;
-  
-  void SetRatio(Float_t ratio) { fRatio = ratio; }
-  void SetOCDBPath(const char* ocdbPath);
+  void MakeNofEventsPropToTriggerCount(const char* trigger="CMUL7-B-NOPF-MUON", Float_t ratio=1.0);
   
-  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 MakeNofEventsFixed(Int_t nevents);
   
-  void SetRunList(const char* runlist);
-  void SetRunList(int runNumber);
+  void UseOCDBSnapshots(Bool_t flag);
   
-  TString ReferenceTrigger() const { return fReferenceTrigger; }
+  void UseExternalConfig(const char* externalConfigFullFilePath);
   
-  Bool_t Run(const char* mode);
+  void UseAODMerging(Bool_t flag);
   
   Bool_t Merge(Int_t stage, Bool_t dryRun=kTRUE);
 
@@ -72,17 +40,6 @@ public:
 
   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; }
@@ -91,85 +48,46 @@ public:
   
   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 SetOCDBPath(const char* ocdbPath);
+
   void SetOCDBSnapshotDir(const char* dir);
 
   Bool_t SetGenerator(const char* generator);
-  
-  TObjArray* GetVariables(const char* file) const;
-  
-  Bool_t IsValid() const { return fIsValid; }
-  
-private:
 
-  TString SnapshotDir() const { return fSnapshotDir; }
+  void CleanLocal(const char* excludeList="OCDB_") const;
   
-  TString GetRemoteDir(const char* dir, Bool_t create);
-
-  std::ostream* CreateJDLFile(const char* name) const;
-
-  Bool_t CheckRemoteDir() const;
+  Int_t MaxEventsPerChunk() const { return fMaxEventsPerChunk; }
+  void SetMaxEventsPerChunk(Int_t n) { fMaxEventsPerChunk = n; }
 
-  Bool_t CopyFile(const char* localFile);
+  TString OCDBPath() const { return GetMapValue("OCDBPath"); }
   
-  Bool_t GetLastStage(const char* remoteDir) const;
-
-  Bool_t RemoteDirectoryExists(const char *dirname) const;
-  Bool_t RemoteFileExists(const char *lfn) const;
+  TString SnapshotDir() const { return GetMapValue("OCDBsnapshot"); }
 
-  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;
+private:
   
-  void Output(std::ostream& out, const char* key, const TObjArray& values) const;
-
-  Bool_t ReplaceVars(const char* file) const;
-
-  TObjArray* TemplateFileList() const;
-
-  TObjArray* LocalFileList() const;
+  Bool_t GenerateRunJDL(const char* name) const;
   
-  Bool_t HasVars(const char* localFile) const;
-
-  void UpdateLocalFileList(Bool_t clearSnapshot=kFALSE);
+  Bool_t GenerateMergeJDL(const char* name) const;
   
-  Bool_t CheckCompilation(const char* file) const;
+  TString ReferenceTrigger() const { return GetMapValue("ReferenceTrigger"); }
   
+  void UpdateLocalFileList(Bool_t clearSnapshots=kFALSE);
+
 private:
   AliMuonAccEffSubmitter(const AliMuonAccEffSubmitter& rhs);
   AliMuonAccEffSubmitter& operator=(const AliMuonAccEffSubmitter& rhs);
   
 private:
-  AliAnalysisTriggerScalers* fScalers; // helper class used to handle the runlist and the scalers
-  TString fRemoteDir; // remote directory to used in alien
-  TString fReferenceTrigger; // reference trigger (if any) to be used to get the number of events to be used per run
   Float_t fRatio; // ratio simulated events vs real events
   Int_t fFixedNofEvents; // fixed number of events to be used per run
   Int_t fMaxEventsPerChunk; // max events to generate per subjob
-  TString fLocalDir; // local directory
   TString fOCDBPath; // OCDB path
-  TString fTemplateDir; // template directory
-  TString fPackageAliroot; // which aliroot package to use
-  TString fPackageGeant3; // which geant3 package to use
-  TString fPackageRoot; // which root package to use (for valid root,geant3,aliroot combinations see http://alimonitor.cern.ch/packages/)
-  TString fPackageApi; // which API package to use
-  TString fMergedDir; // merge directory
   Int_t fSplitMaxInputFileNumber; // used for merging jdl
   Int_t fCompactMode; // controls which outputs are kept (0=everything, 1=only aods)
-  Bool_t fShouldOverwriteFiles; // whether any copy (of template to local) is allowed to overwrite existing files
-  TMap* fVars; // map of the variables we can replace in template files
   TString fExternalConfig; // path to an (optional) external config file
   Bool_t fUseOCDBSnapshots; // whether to use OCDB snapshots or not
-  Bool_t fIsValid; // whether this object is valid (i.e. properly configured)
-  mutable TObjArray* fTemplateFileList; // list of template files
-  mutable TObjArray* fLocalFileList; // list of local files
   TString fSnapshotDir; // directory for OCDB snapshots
   Bool_t fUseAODMerging; // whether or not to perform (aod) merging
   
diff --git a/PWG/muondep/AliMuonGridSubmitter.cxx b/PWG/muondep/AliMuonGridSubmitter.cxx
new file mode 100644 (file)
index 0000000..41347bb
--- /dev/null
@@ -0,0 +1,931 @@
+/**************************************************************************
+ * 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.                  *
+ **************************************************************************/
+
+//
+// AliMuonGridSubmitter : a class to help submit jobs for several runs
+//
+// This class is dealing with 3 different directories :
+//
+// - template directory ($ALICE_ROOT/PWG/muondep/XXXTemplates) containing the
+//   basic template files to be used for a particular job type (XXX). A template can contain
+//   some variables that will be replaced during during the copy from template
+//   to local dir
+//
+// - local directory, where the files from the template directory, are copied
+//   once the class has been configured properly (i.e. using the various Set, Use,
+//   etc... methods). Some other files (e.g. JDL ones) are generated from
+//   scratch and also copied into this directory.
+//   At this point one could(should) check the files, as they are the ones
+//   to be copied to the remote directory for the production
+//
+// - remote directory, the alien directory where the files will be copied
+//   (from the local directory) before the actual submission
+//
+// author: Laurent Aphecetche (Subatech
+//
+
+#include "AliMuonGridSubmitter.h"
+
+#include "AliLog.h"
+#include "TFile.h"
+#include "TGrid.h"
+#include "TGridResult.h"
+#include "TMap.h"
+#include "TMath.h"
+#include "TObjString.h"
+#include "TROOT.h"
+#include "TString.h"
+#include "TSystem.h"
+#include <vector>
+#include "AliAnalysisTriggerScalers.h"
+#include "Riostream.h"
+
+//______________________________________________________________________________
+AliMuonGridSubmitter::AliMuonGridSubmitter(AliMuonGridSubmitter::EJobType jobType)
+: TObject(),
+fInternalMap(0x0),
+fVars(0x0),
+fIsValid(kFALSE),
+fShouldOverwriteFiles(kFALSE),
+fTemplateFileList(0x0),
+fLocalFileList(0x0)
+{
+  // ctor
+  
+  if (!gGrid)
+  {
+    TGrid::Connect("alien://");
+    if ( !gGrid )
+    {
+      AliError("cannot connect to grid");
+    }
+  }
+  
+  SetPackages("VO_ALICE@AliRoot::v5-04-46-AN","VO_ALICE@GEANT3::v1-15","VO_ALICE@ROOT::v5-34-05");
+
+  TString basedir = gSystem->ExpandPathName("$ALICE_ROOT/PWG/muondep");
+  
+  TString dir;
+  dir.Form("%s/%sTemplates",basedir.Data(),JobTypeName(jobType).Data());
+  
+  if (!SetTemplateDir(dir.Data()))
+  {
+    AliError(Form("Could not find %s directory. Please check.",dir.Data()));
+  }
+  
+  SetLocalDir(gSystem->pwd());
+}
+
+//______________________________________________________________________________
+AliMuonGridSubmitter::~AliMuonGridSubmitter()
+{
+  // dtor
+  delete fTemplateFileList;
+  delete fLocalFileList;
+  delete fInternalMap;
+  delete fVars;
+}
+
+//______________________________________________________________________________
+void AliMuonGridSubmitter::AddToTemplateFileList(const char* filename)
+{
+  // add a file to the list of templates
+  // and update the local file list if needed
+  
+  TObjArray* a = TemplateFileList();
+  
+  if ( !a->FindObject(filename) )
+  {
+    a->Add(new TObjString(filename));
+    UpdateLocalFileList();
+  }
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonGridSubmitter::CheckCompilation(const char* file) const
+{
+  /// Check whether file can be compiled or not
+  /// FIXME: use gSystem->TempFileName for tmpfile !
+  
+  Bool_t rv(kTRUE);
+  
+  TString sfile(gSystem->BaseName(file));
+  TString tmpfile(Form("tmpfile_%s",sfile.Data()));
+  
+  gSystem->Exec(Form("cp %s %s",file,tmpfile.Data()));
+  
+  ReplaceVars(tmpfile.Data());
+  
+  gSystem->AddIncludePath("-I$ALICE_ROOT/include");
+  gSystem->AddIncludePath("-I$ALICE_ROOT/EVGEN");
+
+  if (gROOT->LoadMacro(Form("%s++",tmpfile.Data())))
+  {
+    AliError(Form("macro %s can not be compiled. Please check.",file));
+    rv = kFALSE;
+  }
+  
+  gSystem->Exec(Form("rm %s",tmpfile.Data()));
+  
+  return rv;
+}
+
+
+//______________________________________________________________________________
+Bool_t AliMuonGridSubmitter::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 AliMuonGridSubmitter::CheckRemote() const
+{
+  /// Check whether all required remote files are there
+  AliWarning("implement me");
+  return kFALSE;
+}
+
+//______________________________________________________________________________
+void AliMuonGridSubmitter::CleanLocal(const char* excludeList) const
+{
+  /// Clean (remove) local generated files
+  /// exclude contains a list of comma separated pattern of files
+  /// to be avoided
+  
+  TIter next(LocalFileList());
+  TObjString* file;
+  TObjArray* excludeArray = TString(excludeList).Tokenize(",");
+  
+  while ( ( file = static_cast<TObjString*>(next())) )
+  {
+    Bool_t shouldExclude(kFALSE);
+    
+    TIter nextExclude(excludeArray);
+    TObjString* s;
+    
+    while ( ( s = static_cast<TObjString*>(nextExclude()))  && !shouldExclude )
+    {
+      if ( file->String().Contains(s->String()) ) shouldExclude=kTRUE;
+    }
+    
+    if (!shouldExclude)
+    {
+      gSystem->Unlink(file->String().Data());
+    }
+  }
+  
+  delete excludeArray;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonGridSubmitter::CopyFile(const char* localFile)
+{
+  /// copy a local file to remote destination
+  TString local;
+  
+  if ( gSystem->IsAbsoluteFileName(localFile) )
+  {
+    local = localFile;
+  }
+  else
+  {
+    local = Form("%s/%s",LocalDir().Data(),gSystem->ExpandPathName(localFile));
+  }
+  
+  if (gSystem->AccessPathName(local.Data()))
+  {
+    AliErrorClass(Form("Local file %s does not exist",local.Data()));
+    return kFALSE;
+  }
+  
+  TString remote;
+  
+  remote += RemoteDir().Data();
+  remote += "/";
+  
+  if ( gSystem->IsAbsoluteFileName(localFile) )
+  {
+    TString tmp(localFile);
+    tmp.ReplaceAll(GetMapValue("Snapshot"),"");
+    tmp.ReplaceAll(GetMapValue("Local"),"");
+    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 )
+  {
+    AliDebugClass(1,Form("cp %s alien://%s",local.Data(),remote.Data()));
+    return TFile::Cp(local.Data(),Form("alien://%s",remote.Data()));
+  }
+  else
+  {
+    return kFALSE;
+  }
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonGridSubmitter::CheckRemoteDir() const
+{
+  /// Check we have a grid connection and that the remote dir exists
+  
+  if (RemoteDir().IsNull())
+  {
+    AliError("you must provide the grid location where to copy the files");
+    return kFALSE;
+  }
+  
+  if (!RemoteDirectoryExists(RemoteDir()))
+  {
+    AliError(Form("directory %s does not exist", RemoteDir().Data()));
+    return kFALSE;
+  }
+
+  return kTRUE;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonGridSubmitter::CopyLocalFilesToRemote()
+{
+  /// copy all files necessary to run the simulation into remote directory
+  
+  TIter next(LocalFileList());
+  TObjString* ftc;
+    
+  Bool_t allok(kTRUE);
+    
+  while ( ( ftc = static_cast<TObjString*>(next())) )
+  {
+    allok = allok && CopyFile(ftc->String());
+  }
+  return allok;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonGridSubmitter::CopyTemplateFilesToLocal()
+{
+  // copy (or generate) local files from the template ones
+  
+  if (!IsValid()) return kFALSE;
+
+  AliDebug(1,"");
+
+  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",TemplateDir().Data(),file->String().Data()));
+      TString slocal(Form("%s/%s",LocalDir().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) )
+        {
+          ok = Generate(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* AliMuonGridSubmitter::CreateJDLFile(const char* name) const
+{
+  /// Create a (local and empty) JDL file
+  
+  AliDebugClass(1,"");
+  
+  TString jdl(Form("%s/%s",LocalDir().Data(),name));
+  
+  if ( !ShouldOverwriteFiles() && !gSystem->AccessPathName(jdl.Data()) )
+  {
+    AliErrorClass(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())
+  {
+    AliErrorClass(Form("Cannot create file %s",jdl.Data()));
+    delete os;
+    os=0x0;
+  }
+  
+  return os;
+}
+
+//______________________________________________________________________________
+Int_t AliMuonGridSubmitter::GetLastStage(const char* remoteDir)
+{
+  /// Get the last staging phase already performed
+  
+  TGridResult* r = gGrid->Ls(remoteDir);
+  Int_t i(0);
+  Int_t lastStage(0);
+  Int_t offset = TString("Stage_").Length();
+  
+  while ( r->GetFileName(i) )
+  {
+    TString file(r->GetFileName(i));
+    if  (file.BeginsWith("Stage_") && !file.Contains("xml") )
+    {
+      Int_t n = TString(file(offset,file.Length()-offset)).Atoi();
+      lastStage = TMath::Max(lastStage,n);
+    }
+    ++i;
+  }
+  delete r;
+  return lastStage;
+}
+
+//______________________________________________________________________________
+TString AliMuonGridSubmitter::GetMapValue(const char* key) const
+{
+  // convenience method to access internal map of TObjStrings
+  if (!fInternalMap) return "";
+  
+  TObject* o = fInternalMap->GetValue(key);
+  
+  if (o)
+  {
+    return static_cast<TObjString*>(o)->String();
+  }
+  
+  return "";
+}
+
+//______________________________________________________________________________
+TObjArray* AliMuonGridSubmitter::GetVariables(const char* file) const
+{
+  /// Find the variables in the file
+  
+  std::ifstream in(file);
+  char line[1024];
+  TObjArray* variables(0x0);
+  
+  while ( in.getline(line,1023,'\n') )
+  {
+    TString sline(line);
+    while (sline.Contains("VAR_") && !sline.BeginsWith("//") )
+    {
+      Int_t i1 = sline.Index("VAR_");
+      Int_t i2(i1);
+      
+      while ( ( i2 < sline.Length() ) && ( isalnum(sline[i2]) || sline[i2]=='_' ) ) ++i2;
+      
+      if (!variables)
+      {
+        variables = new TObjArray;
+        variables->SetOwner(kTRUE);
+      }
+      
+      TString var = sline(i1,i2-i1);
+      if ( !variables->FindObject(var) )
+      {
+        variables->Add(new TObjString(var));
+      }
+      sline.ReplaceAll(var,"");
+    }
+  }
+  
+  in.close();
+  
+  return variables;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonGridSubmitter::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;
+}
+
+//______________________________________________________________________________
+TMap* AliMuonGridSubmitter::InternalMap() const
+{
+  if (!fInternalMap)
+  {
+    fInternalMap = new TMap;
+    fInternalMap->SetOwnerKeyValue(kTRUE,kTRUE);
+  }
+  return fInternalMap;
+}
+
+//______________________________________________________________________________
+TString AliMuonGridSubmitter::JobTypeName(AliMuonGridSubmitter::EJobType jobType) const
+{
+  if ( jobType == kAccEff )
+  {
+    return "AccEff";
+  }
+  else if ( jobType == kQAMerge)
+  {
+    return "QAMerge";
+  }
+  return "unknown";
+}
+
+//______________________________________________________________________________
+TObjArray* AliMuonGridSubmitter::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;
+}
+
+//______________________________________________________________________________
+UInt_t AliMuonGridSubmitter::NofRuns() const
+{
+    // number of runs we're dealing with
+  return fRunList.size();
+}
+
+//______________________________________________________________________________
+void AliMuonGridSubmitter::OutputToJDL(std::ostream& out, const char* key,
+                                    const TObjArray& values) const
+{
+  /// output to ostream of key,{values} pair
+  
+  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() && !(TString(key).Contains("SplitMax")) && !(TString(key).Contains("TTL")) )
+    {
+      out << v1.Atoi();
+    }
+    else
+    {
+      out << "\"" << v1.Data() << "\"";
+    }
+  }
+  out << ";" << std::endl;
+}
+
+//______________________________________________________________________________
+void AliMuonGridSubmitter::OutputToJDL(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
+{
+  /// output to ostream
+  
+  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));
+  
+  OutputToJDL(out,key,values);
+}
+
+
+//______________________________________________________________________________
+void AliMuonGridSubmitter::Print(Option_t* /*opt*/) const
+{
+  /// Printout
+  
+  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;
+  }
+
+  TIter next(fInternalMap);
+  TObjString* key;
+  
+  while ( ( key = static_cast<TObjString*>(next()) ) )
+  {
+    TString value = static_cast<TObjString*>(fInternalMap->GetValue(key->String()))->String();
+    
+    std::cout << key->String() << " : " << value.Data() << std::endl;
+  }
+  
+  if ( NofRuns() )
+  {
+    std::cout << NofRuns() << " run";
+    if ( NofRuns() > 1 ) std::cout << "s";
+    std::cout << " = ";
+    for ( std::vector<int>::size_type i = 0; i < fRunList.size(); ++i )
+    {
+      std::cout << fRunList[i] << " ";
+    }
+  }
+  
+  TIter nextVar(fVars);
+  while ( ( key = static_cast<TObjString*>(nextVar())) )
+  {
+    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 AliMuonGridSubmitter::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 AliMuonGridSubmitter::RemoteFileExists(const char *lfn)
+{
+  // 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 AliMuonGridSubmitter::ReplaceVars(const char* file) const
+{
+  /// Replace the variables (i.e. things starting by VAR_) found in 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;
+}
+
+//______________________________________________________________________________
+const std::vector<int>& AliMuonGridSubmitter::RunList() const
+{
+  /// Return a reference to our runlist
+  return fRunList;
+}
+
+//______________________________________________________________________________
+void AliMuonGridSubmitter::SetPackages(const char* aliroot,
+                                         const char* root,
+                                         const char* geant3,
+                                         const char* api)
+{
+  /// Set the packages to be used by the jobs
+  /// Must be a valid combination, see http://alimonitor.cern.ch/packages/
+  ///
+  
+  SetMapKeyValue("AliRoot",aliroot);
+  SetMapKeyValue("Root",root);
+  SetMapKeyValue("Geant3",geant3);
+  SetMapKeyValue("API",api);
+}
+
+//______________________________________________________________________________
+TString AliMuonGridSubmitter::GetRemoteDir(const char* dir, Bool_t create)
+{
+  /// Set the target remote directory (on the grid)
+  
+  if (!RemoteDirectoryExists(dir))
+  {
+    if (!create)
+    {
+      AliErrorClass(Form("Remote directory %s does not exist", dir));
+      return "";
+    }
+    else
+    {
+      AliInfoClass(Form("Remote directory %s does not exist. Trying to create it...",dir));
+      if (!gGrid)
+      {
+          AliErrorClass("cannot connect to grid");
+          return "";
+      }
+      if ( !gGrid->Mkdir(dir,"-p") )
+      {
+        AliErrorClass(Form("Could not create remote dir. Sorry."));
+        return "";
+      }
+    }
+  }
+  return dir;
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonGridSubmitter::SetLocalDirectory(const char* type, const char* path)
+{
+  if (gSystem->AccessPathName(path)==kFALSE)
+  {
+    SetMapKeyValue(type,path);
+    return kTRUE;
+  }
+  return kFALSE;
+}
+
+//______________________________________________________________________________
+void AliMuonGridSubmitter::SetMapKeyValue(const char* key, const char* value)
+{
+  TObjString skey(key);
+  InternalMap()->Remove(&skey);
+  InternalMap()->Add(new TObjString(key),new TObjString(value));
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonGridSubmitter::SetRemoteDirectory(const char* type, const char* path)
+{
+  // Set the merged directory to be used
+  TString v = GetRemoteDir(path,kTRUE);
+  SetMapKeyValue(type,v);
+  return (v.Length()>0);
+}
+
+//______________________________________________________________________________
+void AliMuonGridSubmitter::SetRunList(const char* runlist)
+{
+    // set the runlist from a text file
+  AliAnalysisTriggerScalers ts(runlist);
+  fRunList = ts.GetRunList();
+}
+
+//______________________________________________________________________________
+void AliMuonGridSubmitter::SetRunList(int runNumber)
+{
+  // set the runlist from a text file
+  fRunList.clear();
+  fRunList.push_back(runNumber);
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonGridSubmitter::SetVar(const char* varname, const char* value)
+{
+  /// Set a variable
+  
+  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;
+}
+
+//______________________________________________________________________________
+TObjArray* AliMuonGridSubmitter::TemplateFileList() const
+{
+  /// Return (after createing if needed)
+  
+  if (!fTemplateFileList)
+  {
+    fTemplateFileList = new TObjArray;
+    fTemplateFileList->SetOwner(kTRUE);
+  }
+  return fTemplateFileList;
+}
+
+//______________________________________________________________________________
+void AliMuonGridSubmitter::UpdateLocalFileList()
+{
+  // insure that local file list contains at least all of the template files
+  TIter next(TemplateFileList());
+  TObjString* s;
+  
+  while ( ( s = static_cast<TObjString*>(next())) )
+  {
+    TObjArray* local = LocalFileList();
+    if ( !local->FindObject(s->String()))
+    {
+      local->Add(new TObjString(*s));
+    }
+  }
+}
+
+//______________________________________________________________________________
+TMap* AliMuonGridSubmitter::Vars() const
+{
+  if (!fVars)
+  {
+    fVars = new TMap;
+    fVars->SetOwnerKeyValue(kTRUE,kTRUE);
+  }
+  return fVars;
+}
+
diff --git a/PWG/muondep/AliMuonGridSubmitter.h b/PWG/muondep/AliMuonGridSubmitter.h
new file mode 100644 (file)
index 0000000..3810fa2
--- /dev/null
@@ -0,0 +1,150 @@
+#ifndef ALIMUONGRIDSUBMITTER_H
+#define ALIMUONGRIDSUBMITTER_H
+
+//
+// AliMuonGridSubmitter : a base class to help submit some
+// mini-productions for muon studies (e.g. Acc x Eff, qa merging, etc...)
+//
+// author: Laurent Aphecetche (Subatech)
+//
+
+#include "TObject.h"
+#include "TString.h"
+#include "Riostream.h"
+#include <vector>
+
+class TMap;
+
+class AliMuonGridSubmitter : public TObject
+{
+public:
+  
+  enum EJobType
+  {
+    kAccEff=0,
+    kQAMerge=1
+  };
+  
+  AliMuonGridSubmitter(AliMuonGridSubmitter::EJobType jobType);
+  virtual ~AliMuonGridSubmitter();
+
+  virtual Bool_t Generate(const char* jdlname) const = 0;
+  virtual Bool_t Run(const char* mode) = 0;
+  
+  TString JobTypeName(AliMuonGridSubmitter::EJobType jobType) const;
+    
+  Bool_t SetLocalDir(const char* localdir) { return SetLocalDirectory("Local",localdir); }
+  Bool_t SetMergedDir(const char* dir) { return SetRemoteDirectory("Merged",dir); }
+  Bool_t SetRemoteDir(const char* dir) { return SetRemoteDirectory("Remote",dir); }
+  Bool_t SetTemplateDir(const char* templatedir) { return SetLocalDirectory("Template",templatedir); }
+  
+  Bool_t CheckLocal() const;
+  Bool_t CheckRemote() const;
+  
+  void CleanLocal(const char* excludeList="") const;
+  
+  void Invalidate() { fIsValid = kFALSE; }
+
+  void Validate() { fIsValid = kTRUE; }
+
+  TString MergedDir() const { return GetMapValue("Merged"); }
+  TString RemoteDir() const { return GetMapValue("Remote"); }
+  TString LocalDir() const { return GetMapValue("Local"); }
+  TString TemplateDir() const { return GetMapValue("Template"); }
+  
+  TString FilePath(const char* what) const;
+  
+  UInt_t NofRuns() const;
+  
+  const std::vector<Int_t>& RunList() const;
+  
+  void SetRunList(const char* runlist);
+  void SetRunList(int runNumber);
+  
+  virtual void Print(Option_t* opt="") const;
+
+  Bool_t CopyLocalFilesToRemote();
+
+  Bool_t CopyTemplateFilesToLocal();
+
+  void SetPackages(const char* aliroot, const char* root, const char* geant3,
+                   const char* api="VO_ALICE@APISCONFIG::V1.1x");
+  
+  Bool_t ShouldOverwriteFiles() const { return fShouldOverwriteFiles; }
+
+  void ShouldOverwriteFiles(Bool_t flag) { fShouldOverwriteFiles = flag; }
+
+  Bool_t IsValid() const { return fIsValid; }
+  
+  void OutputToJDL(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 OutputToJDL(std::ostream& out, const char* key, const TObjArray& values) const;
+  
+  TString GetRemoteDir(const char* dir, Bool_t create=kTRUE);
+  
+  Bool_t RemoteDirectoryExists(const char *dirname) const;
+  Bool_t RemoteFileExists(const char *lfn);
+  
+  Bool_t CopyLocalFilesToRemote(const TObjArray& localFiles);
+
+  Bool_t CopyFile(const char* localFile);
+  
+  Int_t GetLastStage(const char* remoteDir);
+  
+  std::ostream* CreateJDLFile(const char* name) const;
+
+  Bool_t CheckRemoteDir() const;
+
+  Bool_t ReplaceVars(const char* file) const;
+  
+  Bool_t HasVars(const char* localFile) const;
+
+  Bool_t SetVar(const char* varname, const char* value);
+  
+  TObjArray* GetVariables(const char* file) const;
+  
+  Bool_t CheckCompilation(const char* file) const;
+
+  TObjArray* LocalFileList() const;
+  
+  TObjArray* TemplateFileList() const;
+  
+protected:
+  
+  std::ostream* CreateJDLFile(const char* name);
+
+  TString GetMapValue(const char* key) const;
+  
+  TMap* InternalMap() const;
+  TMap* Vars() const;
+  
+  void SetMapKeyValue(const char* key, const char* value);
+  
+  Bool_t SetLocalDirectory(const char* type, const char* path);
+
+  Bool_t SetRemoteDirectory(const char* type, const char* path);
+
+  void UpdateLocalFileList();
+  
+  void AddToTemplateFileList(const char* filename);
+  
+private:
+  AliMuonGridSubmitter(const AliMuonGridSubmitter& rhs);
+  AliMuonGridSubmitter& operator=(const AliMuonGridSubmitter& rhs);
+  
+private:
+  mutable TMap* fInternalMap; // map of directory paths and packages versions
+  mutable TMap* fVars; // map of the variables we can replace in template files
+  Bool_t fIsValid; // whether this object is valid (i.e. properly configured)
+  Bool_t fShouldOverwriteFiles; // whether or not to overwrite the local files each time we run
+  mutable TObjArray* fTemplateFileList; // list of template files
+  mutable TObjArray* fLocalFileList; // list of local files
+  std::vector<Int_t> fRunList; // run list to process
+
+  ClassDef(AliMuonGridSubmitter,0) // Helper class to submit some muon jobs
+};
+
+#endif
+
diff --git a/PWG/muondep/AliMuonQAMergeSubmitter.cxx b/PWG/muondep/AliMuonQAMergeSubmitter.cxx
new file mode 100644 (file)
index 0000000..7bdb6cd
--- /dev/null
@@ -0,0 +1,484 @@
+#include "AliMuonQAMergeSubmitter.h"
+
+#include "AliMuonAccEffSubmitter.h"
+#include "AliAnalysisTriggerScalers.h"
+#include "AliLog.h"
+#include "TSystem.h"
+#include "Riostream.h"
+#include "TGrid.h"
+#include "TGridResult.h"
+
+namespace {
+  const Int_t kFinal(999);
+}
+
+ClassImp(AliMuonQAMergeSubmitter)
+
+//_____________________________________________________________________________
+AliMuonQAMergeSubmitter::AliMuonQAMergeSubmitter(const char* period, const char* pass) :
+AliMuonGridSubmitter(AliMuonGridSubmitter::kQAMerge),
+fPeriod(period),
+fPass(pass),
+fWhatToMerge("Merged.QA.Data.root"),
+fSplitMaxInputFileNumber(50)
+{
+  if (!fPeriod.BeginsWith("LHC"))
+  {
+    AliError("Period not starting with LHC !");
+  }
+  
+  AddToTemplateFileList("QAMerge.C");
+  AddToTemplateFileList("QAMerge.sh");
+  AddToTemplateFileList("validation.sh");
+  AddToTemplateFileList(MergeJDLName(kFALSE).Data());
+  AddToTemplateFileList(MergeJDLName(kTRUE).Data());
+  
+  SetVar("VAR_MERGED_OUTPUT_NAME",Form("%s",fWhatToMerge.Data()));
+
+  ShouldOverwriteFiles(kTRUE);
+
+  TString speriod(period);
+  
+  Int_t year = 2000 + TString(speriod(3,3)).Atoi();
+
+  SetMapKeyValue("DataDirFormat",Form("/alice/data/%d/%s/%%09d/ESDs/%s",year,period,pass));
+}
+
+//_____________________________________________________________________________
+AliMuonQAMergeSubmitter::~AliMuonQAMergeSubmitter()
+{
+}
+
+//______________________________________________________________________________
+Bool_t AliMuonQAMergeSubmitter::Generate(const char* jdlname) const
+{
+  /// Create the JDL for merging jobs
+  
+  AliDebug(1,"");
+  
+  std::ostream* os = CreateJDLFile(jdlname);
+  
+  if (!os)
+  {
+    return kFALSE;
+  }
+  
+  Bool_t final = TString(jdlname).Contains("final",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>/*" << fWhatToMerge.Data() << std::endl;
+  
+  OutputToJDL(*os,"Packages",
+         GetMapValue("AliRoot").Data(),
+         GetMapValue("Geant3").Data(),
+         GetMapValue("Root").Data(),
+         GetMapValue("API").Data());
+         
+  OutputToJDL(*os,"Executable","QAMerge.sh");
+  
+  OutputToJDL(*os,"Price","1");
+  
+  if ( final )
+  {
+    OutputToJDL(*os,"Jobtag","comment: AliMuonQAMergeSubmitter final merging RUN $1");
+  }
+  else
+  {
+    OutputToJDL(*os,"Jobtag","comment: AliMuonQAMergeSubmitter merging RUN $1 stage $2");
+  }
+  
+  OutputToJDL(*os,"Workdirectorysize","5000MB");
+  
+  OutputToJDL(*os,"Validationcommand",Form("%s/validation.sh",RemoteDir().Data()));
+  
+  OutputToJDL(*os,"TTL","14400");
+  
+  OutputToJDL(*os,"OutputArchive",
+         "log_archive.zip:stderr,stdout@disk=1",
+         Form("root_archive.zip:%s@disk=3",fWhatToMerge.Data())
+         );
+  
+//  OutputToJDL(*os,"Arguments",(final ? "2":"1")); // for QAmerge.sh, 1 means intermediate merging stage, 2 means final merging
+  
+  if ( !final )
+  {
+    OutputToJDL(*os,"Arguments","wn.xml");
+    OutputToJDL(*os,"InputFile",Form("LF:%s/QAMerge.C",RemoteDir().Data()));
+    OutputToJDL(*os,"OutputDir",Form("%s/$1/Stage_$2/#alien_counter_03i#",RemoteDir().Data()));
+    OutputToJDL(*os,"Split","se");
+    OutputToJDL(*os,"InputDataCollection",Form("LF:%s/$1/Stage_$2.xml,nodownload",RemoteDir().Data()));    
+    OutputToJDL(*os,"SplitMaxInputFileNumber",Form("%d",GetSplitMaxInputFileNumber()));
+    OutputToJDL(*os,"InputDataListFormat","xml-single");
+    OutputToJDL(*os,"InputDataList","wn.xml");
+  }
+  else
+  {
+    OutputToJDL(*os,"InputFile",Form("LF:%s/QAMerge.C",RemoteDir().Data()),
+           Form("LF:%s/$1/Stage_$2.xml",RemoteDir().Data()));
+    OutputToJDL(*os,"Arguments","Stage_$2.xml $1");
+    OutputToJDL(*os,"OutputDir",Form("%s/$1",RemoteDir().Data()));
+  }
+  
+  return kTRUE;
+}
+
+//_____________________________________________________________________________
+UInt_t AliMuonQAMergeSubmitter::MakeXMLCollectionForRun(Int_t runNumber, Int_t stage)
+{
+  /// Create a collection named Stage_[stage].xml
+  /// with the files from stage-1 (or all the files if stage=0)
+  /// Return the total number of files to be merged
+  
+  if ( stage < 0 )
+  {
+    AliError(Form("Stage (%d) should be >=0",stage));
+    return 0;
+  }
+  
+  TString filename;
+  TString sourcedir;
+
+  if ( stage > 1 )
+  {
+    filename.Form("%s/%d/Stage_%d.xml",LocalDir().Data(),runNumber,stage);
+    sourcedir.Form("%s/%d/Stage_%d",RemoteDir().Data(),runNumber,stage-1);
+  }
+  else if ( stage == 1 )
+  {
+    sourcedir = GetMapValue("DataDirFormat");
+    
+    if ( sourcedir.Length() == 0 )
+    {
+      AliError("Cannot make collections from an empty data dir !");
+      return 0;
+    }
+    filename.Form("%s/%d/Stage_%d.xml",LocalDir().Data(),runNumber,stage);
+  }
+  else
+  {
+    AliError("oups");
+    return 0;
+  }
+  
+  UInt_t count(0);
+
+  TGridResult* res = gGrid->Query(Form(sourcedir.Data(),runNumber),fWhatToMerge.Data());
+  
+  Int_t nFiles = res->GetEntries();
+  
+  if (!nFiles)
+  {
+    AliError(Form("Got no file for run %d",runNumber));
+    return 0;
+  }
+  
+  gSystem->mkdir(Form("%s/",gSystem->DirName(filename.Data())),kTRUE);
+  
+  AliDebug(1,Form("Creating %s",filename.Data()));
+  
+  std::ofstream out(filename.Data());
+  
+  out << Form("<?xml version=\"1.0\"?>\n<alien>\n  <collection name=\"%d-stage-%d\">",runNumber,stage) << std::endl;
+  
+  Long64_t size(0);
+  const Double_t byte2GB(1024*1024*1024);
+  
+  for (Int_t i = 0; i < nFiles; ++i)
+  {
+    ++count;
+    
+    size += TString(res->GetKey(i,"size")).Atoll();
+    
+    out << Form("    <event name=\"%d\">",count) << endl;
+    out << Form("      <file name=\"%s\" aclId=\"%s\" broken=\"%s\" ctime=\"%s\" "
+                "dir=\"%s\" entryId=\"%s\" expiretime=\"%s\" gowner=\"%s\" "
+                "guid=\"%s\" guidtime=\"%s\" lfn=\"%s\" md5=\"%s\" owner=\"%s\" "
+                " perm=\"%s\" replicated=\"%s\" size=\"%s\" turl=\"%s\" type=\"%s\" />",
+                gSystem->BaseName(res->GetKey(i,"lfn")),
+                res->GetKey(i,"aclId"),
+                res->GetKey(i,"broken"),
+                res->GetKey(i,"ctime"),
+                res->GetKey(i,"dir"),
+                res->GetKey(i,"entryId"),
+                res->GetKey(i,"expiretime"),
+                res->GetKey(i,"gowner"),
+                res->GetKey(i,"guid"),
+                res->GetKey(i,"guidtime"),
+                res->GetKey(i,"lfn"),
+                res->GetKey(i,"md5"),
+                res->GetKey(i,"owner"),
+                res->GetKey(i,"perm"),
+                res->GetKey(i,"replicated"),
+                res->GetKey(i,"size"),
+                res->GetKey(i,"turl"),
+                res->GetKey(i,"type")) << endl;
+    out <<      "    </event>" << endl;
+  }
+  
+  TString summary(Form("numberoffiles=\"%d\" size=\"%7.2f GB\" ",count,size/byte2GB));
+  
+  out << Form("  <summary %s />",summary.Data()) << endl;
+  out << "  </collection>" << endl;
+  out << "</alien>" << endl;
+  
+  out.close();
+  
+  delete res;
+
+  Bool_t ok = CopyFile(filename.Data());
+
+  if (!ok) return 0;
+
+  return count;
+}
+
+//_____________________________________________________________________________
+void AliMuonQAMergeSubmitter::Print(Option_t*) const
+{
+  std::cout << "SplitMaxInputFileNumber : " << GetSplitMaxInputFileNumber() << std::endl;
+  AliMuonGridSubmitter::Print();
+}
+
+//_____________________________________________________________________________
+Bool_t AliMuonQAMergeSubmitter::Run(const char* mode)
+{
+  if (!IsValid()) return kFALSE;
+  
+  TString smode(mode);
+  smode.ToUpper();
+  
+  if ( smode == "FULL")
+  {
+    return  ( Run("LOCAL") && Run("UPLOAD") && Run("SUBMIT") );
+  }
+  
+  if ( smode == "LOCAL")
+  {
+    return CopyTemplateFilesToLocal();
+  }
+  
+  if ( smode == "UPLOAD" )
+  {
+    return CopyLocalFilesToRemote();
+  }
+  
+  if ( smode == "TEST" )
+  {
+    Bool_t ok = Run("LOCAL") && Run("UPLOAD");
+    if ( ok )
+    {
+      ok = (Submit(kTRUE)>0);
+    }
+    return ok;
+  }
+  
+  if ( smode == "SUBMIT" )
+  {
+    return (Submit(kFALSE)>0);
+  }
+  
+  return kFALSE;
+
+}
+
+//_____________________________________________________________________________
+Bool_t AliMuonQAMergeSubmitter::SetRemoteDir(const char* dir)
+{
+  if ( AliMuonGridSubmitter::SetRemoteDir(dir) )
+  {
+    Validate();
+    return kTRUE;
+  }
+  else
+  {
+    Invalidate();
+    return kFALSE;
+  }
+}
+
+//______________________________________________________________________________
+void AliMuonQAMergeSubmitter::ShowStage(Int_t runNumber)
+{
+  /// Show stage for a given run number
+  
+  Int_t stage(0);
+  
+  if ( RemoteFileExists(Form("%s/%d/%s",RemoteDir().Data(),runNumber,fWhatToMerge.Data())) )
+  {
+    stage = kFinal;
+  }
+  else
+  {
+    stage = GetLastStage(Form("%s/%d",RemoteDir().Data(),runNumber));
+  }
+
+  std::cout << "RUN " << runNumber << " ";
+
+  if ( stage == kFinal )
+  {
+    std::cout << "FINAL";
+  }
+  else
+  {
+    std::cout << "Stage " << stage;
+  }
+  std::cout << std::endl;
+}
+
+//______________________________________________________________________________
+void AliMuonQAMergeSubmitter::ShowStages()
+{
+  /// Show in remote dir the list of stages we're in for each run
+  
+  TGridResult* r = gGrid->Ls(RemoteDir());
+  Int_t i(0);
+  std::map<int,std::vector<int> > stages;
+  
+  while ( r->GetFileName(i) )
+  {
+    TString s(r->GetFileName(i));
+    if  (s.IsDec())
+    {
+      Int_t runNumber = s.Atoi();
+      Int_t stage(0);
+      
+      if ( RemoteFileExists(Form("%s/%d/%s",RemoteDir().Data(),runNumber,fWhatToMerge.Data())) )
+      {
+        stage = kFinal;
+      }
+      else
+      {
+        stage = GetLastStage(Form("%s/%d",RemoteDir().Data(),runNumber));
+      }
+
+      stages[stage].push_back(runNumber);
+    }
+    ++i;
+  }
+  delete r;
+  
+  std::map<int,std::vector<int> >::const_iterator it;
+  
+  for ( it = stages.begin(); it != stages.end(); ++it )
+  {
+    const std::vector<int>& runs = it->second;
+    Int_t stage = it->first;
+    if ( stage == kFinal )
+    {
+      std::cout << "FINAL";
+    }
+    else
+    {
+      std::cout << "Stage " << stage;
+    }
+    std::cout << std::endl;
+    for ( std::vector<int>::size_type irun = 0; irun < runs.size(); ++irun )
+    {
+      std::cout << runs[irun] << " ";
+    }
+    std::cout << std::endl;
+  }
+}
+
+
+//_____________________________________________________________________________
+Bool_t AliMuonQAMergeSubmitter::Submit(Int_t runNumber, Bool_t dryRun)
+{
+  /// Submit merging job for one run
+  
+  TString runDir = GetRemoteDir(Form("%s/%d", RemoteDir().Data(), runNumber),kTRUE);
+  
+  if (RemoteFileExists(Form("%s/%s", runDir.Data(),fWhatToMerge.Data())))
+  {
+    AliWarning(" ! final merging already done");
+    return kTRUE;
+  }
+  
+  Int_t lastStage = GetLastStage(runDir.Data());
+  
+  AliDebug(1,Form("lastStage=%d",lastStage));
+  
+  ++lastStage;
+  
+  UInt_t n = MakeXMLCollectionForRun(runNumber,lastStage);
+  
+  Bool_t final  = ( n < GetSplitMaxInputFileNumber() );
+  
+  TString query;
+  TString jdl(MergeJDLName(final));
+  
+  gGrid->Cd(RemoteDir().Data());
+  
+  query.Form("submit %s %d %d", jdl.Data(), runNumber, lastStage);
+
+  AliInfo(Form("query=%s",query.Data()));
+  
+  if (dryRun)
+  {
+    return kTRUE;
+  }
+
+  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");
+  }
+  
+  return done;
+}
+
+//_____________________________________________________________________________
+Int_t AliMuonQAMergeSubmitter::Submit(Bool_t dryRun)
+{
+  /// Submit merging jobs
+
+  if (!NofRuns())
+  {
+    AliError("No run to work with");
+    return 0;
+  }
+  
+  const std::vector<int>& runs = RunList();
+  
+  TString failed;
+  
+  for ( std::vector<int>::size_type i = 0; i < runs.size(); ++i )
+  {
+    Int_t run = runs[i];
+    Bool_t ok = Submit(run,dryRun);
+  
+    if (!ok)
+    {
+      failed += TString::Format("%d",run);
+      failed += " ";
+    }
+  }
+  
+  if (failed.Length()>0)
+  {
+    AliInfo(Form("List of failed runs : %s",failed.Data()));
+    return 0;
+  }
+  
+  return 1;
+}
+
diff --git a/PWG/muondep/AliMuonQAMergeSubmitter.h b/PWG/muondep/AliMuonQAMergeSubmitter.h
new file mode 100644 (file)
index 0000000..70db209
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef ALIMUONQAMERGESUBMITTER_H
+#define ALIMUONQAMERGESUBMITTER_H
+
+#include "AliMuonGridSubmitter.h"
+#include "TString.h"
+
+#include <vector>
+
+class AliMuonQAMergeSubmitter : public AliMuonGridSubmitter
+{
+public:
+  AliMuonQAMergeSubmitter(const char* period, const char* pass);
+  virtual ~AliMuonQAMergeSubmitter();
+  
+  Bool_t Run(const char* mode);
+
+  Bool_t Submit(Int_t runNumber, Bool_t dryRun);
+  
+  Int_t Submit(Bool_t dryRun);
+
+  TString MergeJDLName(Bool_t final) const { return (final ? "QAMerge_final.jdl" : "QAMerge.jdl"); }
+
+  Bool_t Generate(const char* name) const;
+
+  Bool_t SetRemoteDir(const char* dir);
+
+  UInt_t MakeXMLCollectionForRun(Int_t runNumber, Int_t stage);
+
+  UInt_t GetSplitMaxInputFileNumber() const { return fSplitMaxInputFileNumber; }
+  
+  void SetSplitMaxInputFileNumber(UInt_t n) { fSplitMaxInputFileNumber=n; }
+  
+  virtual void Print(Option_t* opt="") const;
+  
+  void ShowStages();
+  
+  void ShowStage(Int_t runNumber);
+
+private:
+
+  TString fPeriod;
+  TString fPass;
+  TString fWhatToMerge; // file to be merged
+  UInt_t fSplitMaxInputFileNumber;
+  
+  ClassDef(AliMuonQAMergeSubmitter,1)
+};
+
+#endif
diff --git a/PWG/muondep/QAMergeTemplates/QAMerge.C b/PWG/muondep/QAMergeTemplates/QAMerge.C
new file mode 100644 (file)
index 0000000..194e9be
--- /dev/null
@@ -0,0 +1,485 @@
+#include "TSystem.h"
+#include "TList.h"
+#include "TObjString.h"
+#include "Riostream.h"
+#include "TRegexp.h"
+#include "AliMUONVTrackerData.h"
+#include "TFile.h"
+#include "TKey.h"
+#include "TGrid.h"
+#include "TGridResult.h"
+#include "TUrl.h"
+#include "TMath.h"
+#include "TFile.h"
+#include "TStopwatch.h"
+#include "TGridCollection.h"
+#include "TROOT.h"
+#include "TError.h"
+#include "TH1.h"
+#include "TMethodCall.h"
+
+void CopyFromRemote(Int_t runNumber, const char* period, const char* pass);
+void CopyFromRemote(const TList& files);
+TList* GetFileList(Int_t runNumber, const char* period, const char* pass);
+void QAMerge(Int_t runNumber, const char* period, const char* pass);
+void QAMerge(const TList& files, const char* outputfile);
+
+////______________________________________________________________________________
+//AliMUONVTrackerData* GetTrackerData(TDirectory* dir, const char* trackerDataName)
+//{
+//  AliMUONVTrackerData* trackerData(0x0);
+//
+//  TIter next(dir->GetListOfKeys());
+//  TKey* key;
+//  
+//  while ( ( key = static_cast<TKey*>(next()) ) && !trackerData )
+//  {
+//    if ( key->IsFolder() )
+//    {
+//      trackerData = GetTrackerData(static_cast<TDirectory*>(key->ReadObj()),trackerDataName);
+//    }
+//    else
+//    {
+//      TString name(key->GetName());
+//      
+//      if ( name.Contains(trackerDataName) )
+//      {
+//        trackerData = dynamic_cast<AliMUONVTrackerData*>(key->ReadObj());
+//      }
+//    }
+//  }
+//  
+//  return trackerData;
+//  
+//}
+//
+////______________________________________________________________________________
+//AliMUONVTrackerData* GetTrackerData(const char* filename, const char* trackerDataName)
+//{
+//  TFile* file = TFile::Open(filename);
+//  
+//  cout << filename << endl;
+//  
+//  if (!file) return 0x0;
+//
+//  AliMUONVTrackerData* trackerData = GetTrackerData(file,trackerDataName);  
+//
+//  delete file;
+//  
+//  return trackerData;
+//  
+//}
+
+////______________________________________________________________________________
+//AliMUONVTrackerData* MergeTrackerData(const TList& filelist, const char* trackerDataName)
+//{
+//  TIter next(&filelist);
+//  TObjString* s;
+//  
+//  s = static_cast<TObjString*>(next());
+//  
+//  AliMUONVTrackerData* d = GetTrackerData(s->String().Data(),trackerDataName);
+//  
+//  if (!d)
+//  {
+//    cout << Form("ERROR : no tracker data found in %s",s->String().Data()) << endl;
+//    return 0x0;
+//  }
+//  
+//  AliMUONVTrackerData* merged = static_cast<AliMUONVTrackerData*>(d->Clone(Form("%s-MERGED",trackerDataName)));
+//  
+//  while ( ( s = static_cast<TObjString*>(next()) ) )
+//  {
+//    d = GetTrackerData(s->String().Data(),trackerDataName);
+//    if (d)
+//    {
+//      TList list;
+//      list.Add(d);
+//      cout << "Merging " << s->String().Data() << " " << d->GetName() << " " << d->NumberOfEvents(-1) << endl;
+//      
+//      merged->Merge(&list);
+//      delete d;
+//    }
+//  }
+//  
+//  merged->SetName(Form("%s-MERGED-%d",trackerDataName,runNumber));
+//  
+//  merged->SetTitle(Form("%s merged for run %d",trackerDataName,runNumber));
+//  
+//
+//  return merged;
+//}
+
+//______________________________________________________________________________
+void GenerateFileList(const char* runlist="philippe.runlist")
+{
+  if (!gGrid)
+  {
+    TGrid::Connect("alien://");    
+  }
+  if (!gGrid) return;
+  
+  ifstream in(runlist);
+  Int_t run;
+  
+  Int_t n(0);
+  
+  while ( in >> run )
+  {
+    TString basedir("/alice/data/2009/LHC09d/");
+    
+    TString dir(Form("%s%09d/ESDs/pass1/*/Merged.QA.Data.root",basedir.Data(),run));
+    
+    TGridResult* r = gGrid->Ls(dir.Data());
+
+    Int_t i(0);
+    
+    while ( r->GetFileName(i) ) 
+    {
+      cout << "alien://" << r->GetFileNamePath(i) << endl;
+      ++i;      
+    }
+    
+    delete r;
+    
+    ++n;
+  }
+}
+
+//______________________________________________________________________________
+void CopyFromRemote(Int_t runNumber, const char* period, const char* pass)
+{
+  TList* list = GetFileList(runNumber,period,pass);
+  if ( list )
+  {
+    CopyFromRemote(*list);
+  }
+  delete list;
+}
+
+//______________________________________________________________________________
+void CopyFromRemote(const TList& files)
+{
+  TStopwatch timer;
+  
+  TIter next(&files);
+  TObjString* line;
+  
+  while ( ( line = static_cast<TObjString*>(next()) ) )
+  {
+    TUrl url(line->String());
+
+    if ( TString(url.GetProtocol()) == "alien" )
+    {
+      if (!gGrid)
+      {
+        TGrid::Connect("alien://");
+        if (!gGrid)
+        {
+          cout << "Cannot get alien connection" << endl;
+          return;
+        }
+      }
+    }
+
+    TString file(url.GetFile());
+
+    TString dir(gSystem->DirName(file));
+
+    gSystem->mkdir(dir.Data(),kTRUE);
+
+    if ( gSystem->AccessPathName(file.Data())==kFALSE)
+    {
+      cout << "Skipping copy of " << file.Data() << " as it already exists" << endl;
+    }
+    else
+    {
+      TFile::Cp(line->String().Data(),file.Data());
+      if ( line->String().Contains("root_archive.zip") )
+      {
+        gSystem->Exec(Form("unzip %s -d %s",file.Data(),gSystem->DirName(file.Data())));
+        gSystem->Exec(Form("rm %s",file.Data()));
+      }
+    }
+  }
+  
+  timer.Print();
+}
+
+//______________________________________________________________________________
+TList* GetFileList(Int_t runNumber, const char* period, const char* pass)
+{
+  if (!gGrid) TGrid::Connect("alien://");
+  if (!gGrid)
+  {
+    return 0x0;
+  }
+
+  Int_t year;
+  
+  TString speriod(period);
+  
+  if (!speriod.BeginsWith("LHC"))
+  {
+    std::cerr << "Period not starting with LHC !" << std::endl;
+    return 0x0;
+  }
+  
+  year = 2000 + TString(speriod(3,3)).Atoi();
+  
+  TString sbasedir(Form("/alice/data/%d/%s/%09d/ESDs/%s",year,period,runNumber,pass));
+  
+  std::cout << sbasedir.Data() << std::endl;
+  
+  TString search("Merged.QA.Data.root");
+  
+  TGridResult* res = gGrid->Query(sbasedir.Data(),search.Data());
+  
+  Int_t nFiles = res->GetEntries();
+  
+  nFiles = res->GetEntries();
+  
+  Long64_t size(0);
+  Int_t count(0);
+  TList* files(0x0);
+  
+  for (Int_t i = 0; i < nFiles; ++i)
+  {
+    Long64_t thisSize = TString(res->GetKey(i,"size")).Atoll();
+    
+//    TUrl url(res->GetKey(i,"turl"));
+    
+    if (!files)
+    {
+      files = new TList;
+      files->SetOwner(kTRUE);
+    }
+    
+    files->Add(new TObjString(res->GetKey(i,"turl")));
+    
+    ++count;
+    
+    size += thisSize;
+  }
+  
+  std::cout << Form("%d files for a total of %d MB",count,TMath::Nint(size/1024.0/1024)) << std::endl;
+
+  delete res;
+  
+  return files;
+}
+
+//______________________________________________________________________________
+void QAMerge(Int_t runNumber, const char* period, const char* pass)
+{
+  TList* list = GetFileList(runNumber,period,pass);
+  if ( list )
+  {
+    QAMerge(*list,Form("QA.%s.%s.%d.root",period,pass,runNumber));
+  }
+  delete list;
+
+}
+
+//______________________________________________________________________________
+TObject* GetObject(const char* filepath, const char* objectPath)
+{
+  TFile* f = TFile::Open(filepath);
+  
+  if (!f)
+  {
+    std::cerr << "Could not open file " << filepath << std::endl;
+    return 0x0;    
+  }
+  
+  TObject* o = f->Get(objectPath);
+  
+  if (!o)
+  {
+    std::cout << "Cannot get object " << objectPath << " from " << filepath << std::endl;
+    return 0x0;
+  }
+  
+  if ( o->InheritsFrom("TH1") )
+  {
+    TH1* h = static_cast<TH1*>(o);
+    h->SetDirectory(0);
+  }
+  
+  delete f;
+  
+  return o;
+}
+
+//______________________________________________________________________________
+TObject* Merge(const TList& files, const char* objectPath)
+{
+  TIter next(&files);
+  TObjString* filename;
+  
+  filename = static_cast<TObjString*>(next());
+  
+  TObject* d = GetObject(filename->String().Data(),objectPath);
+  
+  if (!d)
+  {
+    cout << Form("ERROR : no object found in %s",filename->String().Data()) << endl;
+    return 0x0;
+  }
+  
+  TString oname(gSystem->BaseName(objectPath));
+  
+  TObject* merged = d->Clone();
+  
+  TMethodCall callEnv;
+
+  if ( merged->IsA() )
+  {
+    callEnv.InitWithPrototype(merged->IsA(), "Merge", "TCollection*");
+  }
+  
+  if (!callEnv.IsValid())
+  {
+    std::cout << "callEnv invalid" << std::endl;
+    delete merged;
+    return 0x0;
+  }
+
+  while ( ( filename = static_cast<TObjString*>(next()) ) )
+  {
+//    std::cout << filename->String().Data() << " : " << objectPath << std::endl;
+    
+    d = GetObject(filename->String().Data(),objectPath);
+    
+    if (!d)
+    {
+      continue;
+    }
+    
+    TList list;
+    list.Add(d);
+    callEnv.SetParam((Long_t) (&list));
+    callEnv.Execute(merged);
+    
+    delete d;
+  }
+  
+  return merged;
+
+}
+
+//______________________________________________________________________________
+void QAMerge(const TList& files, const char* outputfile)
+{
+  const char* eventSpecie = "HighMultiplicity";
+  
+  TList objectsToMerge;
+  objectsToMerge.SetOwner(kTRUE);
+
+  objectsToMerge.Add(new TObjString(Form("MUON/Raws/%s/Expert/%s_hTrackerDDLNofEventsSeen",eventSpecie,eventSpecie)));
+
+  objectsToMerge.Add(new TObjString(Form("MUON/RecPoints/%s/Expert/%s_RecPoints",eventSpecie,eventSpecie)));
+  objectsToMerge.Add(new TObjString(Form("MUON/RecPoints/%s/Expert/%s_RecCharges",eventSpecie,eventSpecie)));
+
+  objectsToMerge.Add(new TObjString(Form("MUON/Raws/%s/Expert/%s_RawCharges",eventSpecie,eventSpecie)));
+
+  for ( Int_t i = 1; i <= 10; ++i )
+  {
+    objectsToMerge.Add(new TObjString(Form("MUON/RecPoints/%s/Expert/%s_hTrackerClusterHitMapForChamber%d",eventSpecie,eventSpecie,i)));
+    objectsToMerge.Add(new TObjString(Form("MUON/ESDs/%s/Expert/%s_hESDClusterHitMap%d",eventSpecie,eventSpecie,i)));
+  }
+
+  TObjArray output;
+  output.SetOwner(kTRUE);
+
+  TIter next(&objectsToMerge);
+  TObjString* s;
+  
+  while ( ( s = static_cast<TObjString*>(next())) )
+  {
+    output.Add(Merge(files,s->String().Data()));
+  }
+  
+  TFile* f = TFile::Open(outputfile,"recreate");
+  
+  next.Reset();
+
+  Int_t i(0);
+  while ( ( s = static_cast<TObjString*>(next())) )
+  {
+    TObject* o = output.At(i);
+    if (o)
+    {
+      TString dir = gSystem->DirName(s->String());
+      TString file = gSystem->BaseName(s->String());
+      TDirectory* tdir = static_cast<TDirectory*>(f->Get(dir.Data()));
+      if (!tdir)
+      {
+        f->mkdir(dir.Data()," ");
+        tdir = static_cast<TDirectory*>(f->Get(dir.Data()));
+      }
+      tdir->cd();
+      o->Write(file.Data());
+    }
+    ++i;
+  }
+
+  f->Write();
+  
+  f->Close();
+  
+  delete f;
+}
+
+//______________________________________________________________________________
+void QAMerge(const char* inputfilelist, const char* mergedFile)
+{
+  if (!gGrid)
+  {
+    TGrid::Connect("alien://");    
+  }
+  if (!gGrid) return;
+  
+  TString sinput(inputfilelist);
+  TList filelist;
+  filelist.SetOwner(kTRUE);
+  
+  if (sinput.Contains(".xml"))
+  {
+    TGridCollection *coll = reinterpret_cast<TGridCollection*>(gROOT->ProcessLine(Form("TAlienCollection::Open(\"%s\");", inputfilelist)));
+    if (!coll)
+    {
+      ::Error("MergeOutput", "Input XML collection empty.");
+      return;
+    }
+    // Iterate grid collection
+    while (coll->Next())
+    {
+      filelist.Add(new TObjString(coll->GetTURL()));
+    }
+  }
+  else
+  {
+    ifstream in(inputfilelist);
+    char filename[1024];
+
+    while (in.getline(filename,1024,'\n'))
+    {
+      filelist.Add(new TObjString(filename));
+    }
+  }
+    
+  if ( filelist.GetEntries()==0 )
+  {
+    std::cout << "No file to be merged !" << std::endl;
+  }
+  else
+  {
+    QAMerge(filelist,mergedFile);
+  }
+  
+  ofstream out;
+  out.open("outputs_valid_merge", ios::out);
+  out.close();
+}
+
diff --git a/PWG/muondep/QAMergeTemplates/QAMerge.sh b/PWG/muondep/QAMergeTemplates/QAMerge.sh
new file mode 100644 (file)
index 0000000..712981d
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/bash
+export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
+echo "========================================="
+echo "############## PATH : ##############"
+echo $PATH
+echo "############## LD_LIBRARY_PATH : ##############"
+echo $LD_LIBRARY_PATH
+echo "############## ROOTSYS : ##############"
+echo $ROOTSYS
+echo "############## which root : ##############"
+which root
+echo "############## ALICE_ROOT : ##############"
+echo $ALICE_ROOT
+echo "############## which aliroot : ##############"
+which aliroot
+echo "############## system limits : ##############"
+ulimit -a
+echo "############## memory : ##############"
+free -m
+echo "========================================="
+
+aliroot -b << EOF
+gSystem->SetIncludePath("-I$ALICE_ROOT/MUON");
+.L QAMerge.C+
+QAMerge("$1","VAR_MERGED_OUTPUT_NAME");
+EOF
+
+echo "======== QAmerge.C finished with exit code: $? ========"
+echo "############## memory after: ##############"
+free -m
diff --git a/PWG/muondep/QAMergeTemplates/validation.sh b/PWG/muondep/QAMergeTemplates/validation.sh
new file mode 100644 (file)
index 0000000..e6f8c8d
--- /dev/null
@@ -0,0 +1,80 @@
+#!/bin/bash
+
+##################################################
+validateout=`dirname $0`
+validatetime=`date`
+validated="0";
+error=0
+if [ -z $validateout ]
+then
+validateout="."
+fi
+
+cd $validateout;
+validateworkdir=`pwd`;
+
+echo "*******************************************************" >> stdout
+echo "* Automatically generated validation script           *" >> stdout
+
+echo "* Time:    $validatetime " >> stdout
+echo "* Dir:     $validateout" >> stdout
+echo "* Workdir: $validateworkdir" >> stdout
+echo "* ----------------------------------------------------*" >> stdout
+ls -la ./ >> stdout
+echo "* ----------------------------------------------------*" >> stdout
+
+##################################################
+
+if [ ! -f stderr ] ; then
+error=1
+echo "* ########## Job not validated - no stderr  ###"  >> stdout
+echo "Error = $error"  >> stdout
+fi
+parArch=`grep -Ei "Cannot Build the PAR Archive" stderr`
+segViol=`grep -Ei "Segmentation violation" stderr`
+segFault=`grep -Ei "Segmentation fault" stderr`
+glibcErr=`grep -Ei "*** glibc detected ***" stderr`
+
+if [ "$parArch" != "" ] ; then
+error=1
+echo "* ########## Job not validated - PAR archive not built  ###"  >> stdout
+echo "$parArch"  >> stdout
+echo "Error = $error"  >> stdout
+fi
+if [ "$segViol" != "" ] ; then
+error=1
+echo "* ########## Job not validated - Segment. violation  ###"  >> stdout
+echo "$segViol"  >> stdout
+echo "Error = $error"  >> stdout
+fi
+if [ "$segFault" != "" ] ; then
+error=1
+echo "* ########## Job not validated - Segment. fault  ###"  >> stdout
+echo "$segFault"  >> stdout
+echo "Error = $error"  >> stdout
+fi
+if [ "$glibcErr" != "" ] ; then
+error=1
+echo "* ########## Job not validated - *** glibc detected ***  ###"  >> stdout
+echo "$glibcErr"  >> stdout
+echo "Error = $error"  >> stdout
+fi
+# Only check all desired files have been merged properly.
+# Skip the validation by the analysis manager after the Terminate
+# since all the output files have not been registered at the
+# previous stage (like EventStat_temp.root or pyxsec_hists.root)
+# and the manager will complain about...
+if ! [ -f outputs_valid_merge ] ; then
+error=1
+echo "Output files were not validated by the analysis manager" >> stdout
+echo "Output files were not validated by the analysis manager" >> stderr
+fi
+if [ $error = 0 ] ; then
+echo "* ----------------   Job Validated  ------------------*" >> stdout
+#   echo "* === Logs std* will be deleted === "
+#   rm -f std*
+fi
+echo "* ----------------------------------------------------*"
+echo "*******************************************************"
+cd -
+exit $error