]> git.uio.no Git - u/mrichter/AliRoot.git/commitdiff
New task to mesure the spectrometer resolution (Philippe P.)
authormartinez <martinez@f7af4fe6-9843-0410-8265-dc069ae4e863>
Thu, 15 Jul 2010 16:20:11 +0000 (16:20 +0000)
committermartinez <martinez@f7af4fe6-9843-0410-8265-dc069ae4e863>
Thu, 15 Jul 2010 16:20:11 +0000 (16:20 +0000)
PWG3/PWG3muondepLinkDef.h
PWG3/READMEmuon
PWG3/libPWG3muondep.pkg
PWG3/muondep/AddTaskMuonResolution.C [new file with mode: 0644]
PWG3/muondep/AliAnalysisTaskMuonResolution.cxx [new file with mode: 0644]
PWG3/muondep/AliAnalysisTaskMuonResolution.h [new file with mode: 0644]
PWG3/muondep/RunMuonResolution.C [new file with mode: 0644]

index bc4dc3a03d3e82cd10b04d701a41040dae5d18d5..b7ee54a220a566d8f70eea5128fa5359fe7f2add 100644 (file)
@@ -8,6 +8,7 @@
 #pragma link C++ class AliCheckMuonDetEltResponse+;
 #pragma link C++ class AliAnalysisTaskRecoCheck+;
 #pragma link C++ class AliAnalysisTaskESDMCLabelAddition+;
+#pragma link C++ class AliAnalysisTaskMuonResolution+;
 #endif
 
 
index 8cb6ffb3c64344c3350b9311be05b733d3ecad92..74075fddec126fb5d1fee2dbd86f4a99192af6b3 100644 (file)
@@ -442,3 +442,22 @@ X. M. Zhang, Clermont-Ferrand and Wuhan
     Bool_t isMC = kTRUE;     \\ get MC information
     Bool_t isTree = kFALSE;  \\ flag for tree output
     AliAnalysisTaskSEMuonsHF *taskMuonsHF = AddTaskMuonsHF(mode, isMC, isTree);
+
+
+===================================================
+ New task to mesure the spectrometer resolution
+ Philippe Pillot, Subatech
+---------------------------------------------------------------
+1) Compute the cluster resolution per chamber, half chamber and detection element by using 2 methods:
+    a) combining the cluster-track residuals obtained with and without using the cluster to reconstruct the track
+    b) subtracting the track resolution component to the cluster-track residual obtained without using the cluster to reconstruct the track
+
+- In principle, this task should be run iteratively, using the chamber resolution computed in the step n-1 to weight the clusters when refitting the tracks in the step n.
+--> The macro RunMuonResolution.C gives an example on how to do it locally or in PROOF.
+Neverthless, the convergence is quite fast so it can also be run only once provided that the starting chamber resolutions are closed to the real one (e.g. to monitor the variation of the resolution with time).
+
+- If not specified by user when initializing the task, the starting chamber resolution is taken from the recoParam. In addition, the task load several data from the OCDB (mapping, magnetic field...) so the default storage must be properly set.
+
+2) Return the momentum, transverse momentum and angular resolutions of the reconstructed tracks at first cluster and at vertex (i.e. including absorber effects). These resolutions are computed by using the chamber resolutions given as input (i.e. the ones from the step n-1 or the starting ones).
+
+3) Finally, it is possible to re-align the clusters before computing the resolution, by providing the OCDB path to the old and new alignment data (see comments in the code for more details).
index 112d6274e91e60667aea1e8aacbe2a730a9eedfd..6738df30f039f5ac89ad0279bc6cbcc5726e0c48 100644 (file)
@@ -3,7 +3,8 @@
 SRCS:=  muondep/AliAnalysisTaskMuonTrackingEff.cxx \
          muondep/AliCheckMuonDetEltResponse.cxx \
          muondep/AliAnalysisTaskRecoCheck.cxx \
-         muondep/AliAnalysisTaskESDMCLabelAddition.cxx
+         muondep/AliAnalysisTaskESDMCLabelAddition.cxx \
+         muondep/AliAnalysisTaskMuonResolution.cxx
 
 HDRS:= $(SRCS:.cxx=.h)
 
diff --git a/PWG3/muondep/AddTaskMuonResolution.C b/PWG3/muondep/AddTaskMuonResolution.C
new file mode 100644 (file)
index 0000000..9fb473d
--- /dev/null
@@ -0,0 +1,60 @@
+AliAnalysisTaskMuonResolution *AddTaskMuonResolution(Bool_t selectPhysics = kFALSE, Bool_t matchTrig = kFALSE, Double_t minMomentum = 0.,
+                                                    Bool_t correctForSystematics = kTRUE, Int_t extrapMode = 1)
+{
+  /// Add AliAnalysisTaskMuonResolution to the train (Philippe Pillot)
+  
+  
+  // Get the pointer to the existing analysis manager via the static access method.
+  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
+  if(!mgr) { 
+    Error("AddTaskMuonResolution","AliAnalysisManager not set!");
+    return NULL;
+  }
+  
+  // This task run on ESDs
+  TString type = mgr->GetInputEventHandler()->GetDataType();
+  if (!type.Contains("ESD")) {
+    Error("AddTaskMuonResolution", "ESD input handler needed!");
+    return NULL;
+  }
+  
+  // Create and configure task
+  AliAnalysisTaskMuonResolution *task = new AliAnalysisTaskMuonResolution("MuonResolution");
+  if (!task) {
+    Error("AddTaskMuonResolution", "Muon resolution task cannot be created!");
+    return NULL;
+  }
+  task->SelectPhysics(selectPhysics);
+  task->MatchTrigger(matchTrig);
+  task->SetMinMomentum(minMomentum);
+  task->CorrectForSystematics(correctForSystematics);
+  task->SetExtrapMode(extrapMode);
+  
+  // Add task to analysis manager
+  mgr->AddTask(task);
+  
+  // Connect input container
+  mgr->ConnectInput(task, 0, mgr->GetCommonInputContainer());
+  
+  // Define output file directory
+  TString outputfile = AliAnalysisManager::GetCommonFileName();
+  if ( outputfile.IsNull() ) {
+    Error("AddTaskMuonResolution", "Common output file is not defined!");
+    return NULL;
+  }
+  outputfile += ":MUON_Resolution";
+  
+  // Create and connect output containers
+  AliAnalysisDataContainer *cout_histo1 = mgr->CreateContainer("Residuals", TObjArray::Class(), AliAnalysisManager::kOutputContainer, outputfile);
+  AliAnalysisDataContainer *cout_histo2 = mgr->CreateContainer("ResidualsVsP", TObjArray::Class(), AliAnalysisManager::kOutputContainer, outputfile);
+  AliAnalysisDataContainer *cout_histo3 = mgr->CreateContainer("LocalChi2", TObjArray::Class(), AliAnalysisManager::kParamContainer, outputfile);
+  AliAnalysisDataContainer *cout_histo4 = mgr->CreateContainer("ChamberRes", TObjArray::Class(), AliAnalysisManager::kParamContainer, outputfile);
+  AliAnalysisDataContainer *cout_histo5 = mgr->CreateContainer("TrackRes", TObjArray::Class(), AliAnalysisManager::kOutputContainer, outputfile);
+  mgr->ConnectOutput(task, 1, cout_histo1);
+  mgr->ConnectOutput(task, 2, cout_histo2);
+  mgr->ConnectOutput(task, 3, cout_histo3);
+  mgr->ConnectOutput(task, 4, cout_histo4);
+  mgr->ConnectOutput(task, 5, cout_histo5);
+  
+  return task;
+}   
diff --git a/PWG3/muondep/AliAnalysisTaskMuonResolution.cxx b/PWG3/muondep/AliAnalysisTaskMuonResolution.cxx
new file mode 100644 (file)
index 0000000..93a4681
--- /dev/null
@@ -0,0 +1,1288 @@
+/**************************************************************************
+ * 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.                  *
+ **************************************************************************/
+
+// ROOT includes
+#include <TFile.h>
+#include <TTree.h>
+#include <TH1F.h>
+#include <TH2F.h>
+#include <TMultiGraph.h>
+#include <TGraphErrors.h>
+#include <TCanvas.h>
+#include <TLegend.h>
+#include <Riostream.h>
+#include <TString.h>
+#include <TGeoManager.h>
+
+// STEER includes
+#include "AliESDEvent.h"
+#include "AliESDMuonTrack.h"
+#include "AliCDBManager.h"
+#include "AliCDBStorage.h"
+#include "AliGeomManager.h"
+
+// ANALYSIS includes
+#include "AliAnalysisTaskSE.h"
+#include "AliAnalysisDataSlot.h"
+#include "AliAnalysisManager.h"
+#include "AliInputEventHandler.h"
+#include "AliAnalysisTaskMuonResolution.h"
+
+// MUON includes
+#include "AliMUONCDB.h"
+#include "AliMUONRecoParam.h"
+#include "AliMUONESDInterface.h"
+#include "AliMUONVTrackReconstructor.h"
+#include "AliMUONTrack.h"
+#include "AliMUONTrackParam.h"
+#include "AliMUONTrackExtrap.h"
+#include "AliMUONVCluster.h"
+#include "AliMUONGeometryTransformer.h"
+#include "AliMUONGeometryModuleTransformer.h"
+#include "AliMUONGeometryDetElement.h"
+#include "AliMpDEIterator.h"
+
+#ifndef SafeDelete
+#define SafeDelete(x) if (x != NULL) { delete x; x = NULL; }
+#endif
+
+ClassImp(AliAnalysisTaskMuonResolution)
+
+const Int_t AliAnalysisTaskMuonResolution::fgkMinEntries = 10;
+
+//________________________________________________________________________
+AliAnalysisTaskMuonResolution::AliAnalysisTaskMuonResolution() :
+  AliAnalysisTaskSE(), 
+  fResiduals(NULL),
+  fResidualsVsP(NULL),
+  fLocalChi2(NULL),
+  fChamberRes(NULL),
+  fTrackRes(NULL),
+  fCanvases(NULL),
+  fNEvents(0),
+  fMinMomentum(0.),
+  fSelectPhysics(kFALSE),
+  fMatchTrig(kFALSE),
+  fExtrapMode(1),
+  fCorrectForSystematics(kTRUE),
+  fOCDBLoaded(kFALSE),
+  fNDE(0),
+  fReAlign(kFALSE),
+  fOldAlignStorage(""),
+  fNewAlignStorage(""),
+  fOldGeoTransformer(NULL),
+  fNewGeoTransformer(NULL)
+{
+  /// Default constructor
+}
+
+//________________________________________________________________________
+AliAnalysisTaskMuonResolution::AliAnalysisTaskMuonResolution(const char *name) :
+  AliAnalysisTaskSE(name), 
+  fResiduals(NULL),
+  fResidualsVsP(NULL),
+  fLocalChi2(NULL),
+  fChamberRes(NULL),
+  fTrackRes(NULL),
+  fCanvases(NULL),
+  fNEvents(0),
+  fMinMomentum(0.),
+  fSelectPhysics(kFALSE),
+  fMatchTrig(kFALSE),
+  fExtrapMode(1),
+  fCorrectForSystematics(kTRUE),
+  fOCDBLoaded(kFALSE),
+  fNDE(0),
+  fReAlign(kFALSE),
+  fOldAlignStorage(""),
+  fNewAlignStorage(""),
+  fOldGeoTransformer(NULL),
+  fNewGeoTransformer(NULL)
+{
+  /// Constructor
+  
+  for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) SetStartingResolution(i, -1., -1.);
+  
+  // Output slot #1 writes into a TObjArray container
+  DefineOutput(1,TObjArray::Class());
+  // Output slot #2 writes into a TObjArray container
+  DefineOutput(2,TObjArray::Class());
+  // Output slot #3 writes into a TObjArray container
+  DefineOutput(3,TObjArray::Class());
+  // Output slot #4 writes into a TObjArray container
+  DefineOutput(4,TObjArray::Class());
+  // Output slot #5 writes into a TObjArray container
+  DefineOutput(5,TObjArray::Class());
+}
+
+//________________________________________________________________________
+AliAnalysisTaskMuonResolution::~AliAnalysisTaskMuonResolution()
+{
+  /// Destructor
+  SafeDelete(fResiduals);
+  SafeDelete(fResidualsVsP);
+  SafeDelete(fChamberRes);
+  SafeDelete(fTrackRes);
+  SafeDelete(fCanvases);
+  SafeDelete(fOldGeoTransformer);
+  SafeDelete(fNewGeoTransformer);
+}
+
+//___________________________________________________________________________
+void AliAnalysisTaskMuonResolution::UserCreateOutputObjects()
+{
+  /// Create histograms
+  
+  // do it once the OCDB has been loaded (i.e. from NotifyRun())
+  if (!fOCDBLoaded) return;
+  
+  fResiduals = new TObjArray(1000);
+  fResiduals->SetOwner();
+  fResidualsVsP = new TObjArray(1000);
+  fResidualsVsP->SetOwner();
+  fTrackRes = new TObjArray(1000);
+  fTrackRes->SetOwner();
+  TH2F* h2;
+  
+  // find the highest chamber resolution and set histogram bins
+  const AliMUONRecoParam* recoParam = AliMUONESDInterface::GetTracker()->GetRecoParam();
+  Double_t maxSigma[2] = {-1., -1.};
+  for (Int_t i = 0; i < 10; i++) {
+    if (recoParam->GetDefaultNonBendingReso(i) > maxSigma[0]) maxSigma[0] = recoParam->GetDefaultNonBendingReso(i);
+    if (recoParam->GetDefaultBendingReso(i) > maxSigma[1]) maxSigma[1] = recoParam->GetDefaultBendingReso(i);
+  }
+  const char* axes[2] = {"X", "Y"};
+  const Int_t nBins = 2000;
+  const Int_t nSigma = 10;
+  const Int_t pNBins = 20;
+  const Double_t pEdges[2] = {0., 50.};
+  
+  for (Int_t ia = 0; ia < 2; ia++) {
+    
+    Double_t maxRes = nSigma*maxSigma[ia];
+    
+    // List of residual histos
+    h2 = new TH2F(Form("hResidual%sPerCh_ClusterIn",axes[ia]), Form("cluster-track residual-%s distribution per chamber (cluster attached to the track);chamber ID;#Delta_{%s} (cm)",axes[ia],axes[ia]), 10, 0.5, 10.5, nBins, -maxRes, maxRes);
+    fResiduals->AddAtAndExpand(h2, kResidualPerCh_ClusterIn+ia);
+    h2 = new TH2F(Form("hResidual%sPerCh_ClusterOut",axes[ia]), Form("cluster-track residual-%s distribution per chamber (cluster not attached to the track);chamber ID;#Delta_{%s} (cm)",axes[ia],axes[ia]), 10, 0.5, 10.5, nBins, -2.*maxRes, 2.*maxRes);
+    fResiduals->AddAtAndExpand(h2, kResidualPerCh_ClusterOut+ia);
+    
+    h2 = new TH2F(Form("hResidual%sPerHalfCh_ClusterIn",axes[ia]), Form("cluster-track residual-%s distribution per half chamber (cluster attached to the track);half chamber ID;#Delta_{%s} (cm)",axes[ia],axes[ia]), 20, 0.5, 20.5, nBins, -maxRes, maxRes);
+    fResiduals->AddAtAndExpand(h2, kResidualPerHalfCh_ClusterIn+ia);
+    h2 = new TH2F(Form("hResidual%sPerHalfCh_ClusterOut",axes[ia]), Form("cluster-track residual-%s distribution per half chamber (cluster not attached to the track);half chamber ID;#Delta_{%s} (cm)",axes[ia],axes[ia]), 20, 0.5, 20.5, nBins, -2.*maxRes, 2.*maxRes);
+    fResiduals->AddAtAndExpand(h2, kResidualPerHalfCh_ClusterOut+ia);
+    
+    h2 = new TH2F(Form("hResidual%sPerDE_ClusterIn",axes[ia]), Form("cluster-track residual-%s distribution per DE (cluster not attached to the track);DE ID;#Delta_{%s} (cm)",axes[ia],axes[ia]), fNDE, 0.5, fNDE+0.5, nBins, -maxRes, maxRes);
+    for (Int_t i = 1; i <= fNDE; i++) h2->GetXaxis()->SetBinLabel(i, Form("%d",fDEIds[i]));
+    fResiduals->AddAtAndExpand(h2, kResidualPerDE_ClusterIn+ia);
+    h2 = new TH2F(Form("hResidual%sPerDE_ClusterOut",axes[ia]), Form("cluster-track residual-%s distribution per DE (cluster not attached to the track);DE ID;#Delta_{%s} (cm)",axes[ia],axes[ia]), fNDE, 0.5, fNDE+0.5, nBins, -2.*maxRes, 2.*maxRes);
+    for (Int_t i = 1; i <= fNDE; i++) h2->GetXaxis()->SetBinLabel(i, Form("%d",fDEIds[i]));
+    fResiduals->AddAtAndExpand(h2, kResidualPerDE_ClusterOut+ia);
+    
+    h2 = new TH2F(Form("hTrackRes%sPerCh",axes[ia]), Form("track #sigma_{%s} per Ch;chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]), 10, 0.5, 10.5, nBins, 0., maxRes);
+    fResiduals->AddAtAndExpand(h2, kTrackResPerCh+ia);
+    h2 = new TH2F(Form("hTrackRes%sPerHalfCh",axes[ia]), Form("track #sigma_{%s} per half Ch;half chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]), 20, 0.5, 20.5, nBins, 0., maxRes);
+    fResiduals->AddAtAndExpand(h2, kTrackResPerHalfCh+ia);
+    h2 = new TH2F(Form("hTrackRes%sPerDE",axes[ia]), Form("track #sigma_{%s} per DE;DE ID;#sigma_{%s} (cm)",axes[ia],axes[ia]), fNDE, 0.5, fNDE+0.5, nBins, 0., maxRes);
+    for (Int_t i = 1; i <= fNDE; i++) h2->GetXaxis()->SetBinLabel(i, Form("%d",fDEIds[i]));
+    fResiduals->AddAtAndExpand(h2, kTrackResPerDE+ia);
+    
+    h2 = new TH2F(Form("hMCS%sPerCh",axes[ia]), Form("MCS %s-dispersion of extrapolated track per Ch;chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]), 10, 0.5, 10.5, nBins, 0., 0.2);
+    fResiduals->AddAtAndExpand(h2, kMCSPerCh+ia);
+    h2 = new TH2F(Form("hMCS%sPerHalfCh",axes[ia]), Form("MCS %s-dispersion of extrapolated track per half Ch;half chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]), 20, 0.5, 20.5, nBins, 0., 0.2);
+    fResiduals->AddAtAndExpand(h2, kMCSPerHalfCh+ia);
+    h2 = new TH2F(Form("hMCS%sPerDE",axes[ia]), Form("MCS %s-dispersion of extrapolated track per DE;DE ID;#sigma_{%s} (cm)",axes[ia],axes[ia]), fNDE, 0.5, fNDE+0.5, nBins, 0., 0.2);
+    for (Int_t i = 1; i <= fNDE; i++) h2->GetXaxis()->SetBinLabel(i, Form("%d",fDEIds[i]));
+    fResiduals->AddAtAndExpand(h2, kMCSPerDE+ia);
+    
+    h2 = new TH2F(Form("hClusterRes2%sPerCh",axes[ia]), Form("cluster #sigma_{%s}^{2} per Ch;chamber ID;#sigma_{%s}^{2} (cm^{2})",axes[ia],axes[ia]), 10, 0.5, 10.5, nSigma*nBins, -0.1*maxRes*maxRes, maxRes*maxRes);
+    fResiduals->AddAtAndExpand(h2, kClusterRes2PerCh+ia);
+    
+    // List of residual vs. p histos
+    for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
+      h2 = new TH2F(Form("hResidual%sInCh%dVsP_ClusterIn",axes[ia],i+1), Form("cluster-track residual-%s distribution in chamber %d versus momentum (cluster attached to the track);p (GeV/c^{2});#Delta_{%s} (cm)",axes[ia],i+1,axes[ia]), pNBins, pEdges[0], pEdges[1], nBins, -maxRes, maxRes);
+      fResidualsVsP->AddAtAndExpand(h2, kResidualInChVsP_ClusterIn+10*ia+i);
+      h2 = new TH2F(Form("hResidual%sInCh%dVsP_ClusterOut",axes[ia],i+1), Form("cluster-track residual-%s distribution in chamber %d versus momentum (cluster not attached to the track);p (GeV/c^{2});#Delta_{%s} (cm)",axes[ia],i+1,axes[ia]), pNBins, pEdges[0], pEdges[1], nBins, -2.*maxRes, 2.*maxRes);
+      fResidualsVsP->AddAtAndExpand(h2, kResidualInChVsP_ClusterOut+10*ia+i);
+    }
+    
+    // local chi2
+    h2 = new TH2F(Form("hLocalChi2%sPerCh",axes[ia]), Form("local chi2-%s distribution per chamber;chamber ID;local #chi^{2}_{%s}", axes[ia], axes[ia]), 10, 0.5, 10.5, 1000, 0., 25.);
+    fResiduals->AddAtAndExpand(h2, kLocalChi2PerCh+ia);
+    h2 = new TH2F(Form("hLocalChi2%sPerDE",axes[ia]), Form("local chi2-%s distribution per DE;DE ID;local #chi^{2}_{%s}", axes[ia], axes[ia]), fNDE, 0.5, fNDE+0.5, 1000, 0., 25.);
+    for (Int_t i = 1; i <= fNDE; i++) h2->GetXaxis()->SetBinLabel(i, Form("%d",fDEIds[i]));
+    fResiduals->AddAtAndExpand(h2, kLocalChi2PerDE+ia);
+    
+    // track resolution
+    h2 = new TH2F(Form("hUncorrSlope%sRes",axes[ia]), Form("muon slope_{%s} reconstructed resolution at first cluster vs p;p (GeV/c); #sigma_{slope_{%s}}", axes[ia], axes[ia]), 300, 0., 300., 1000, 0., 0.003);
+    fTrackRes->AddAtAndExpand(h2, kUncorrSlopeRes+ia);
+    h2 = new TH2F(Form("hSlope%sRes",axes[ia]), Form("muon slope_{%s} reconstructed resolution at vertex vs p;p (GeV/c); #sigma_{slope_{%s}}", axes[ia], axes[ia]), 300, 0., 300., 1000, 0., 0.02);
+    fTrackRes->AddAtAndExpand(h2, kSlopeRes+ia);
+  }
+  
+  // local chi2 X+Y
+  h2 = new TH2F("hLocalChi2PerCh", "local chi2 (~0.5*(#chi^{2}_{X}+#chi^{2}_{Y})) distribution per chamber;chamber ID;local #chi^{2}", 10, 0.5, 10.5, 1000, 0., 25.);
+  fResiduals->AddAtAndExpand(h2, kLocalChi2PerCh+2);
+  h2 = new TH2F("hLocalChi2PerDE", "local chi2 (~0.5*(#chi^{2}_{X}+#chi^{2}_{Y})) distribution per chamber;DE ID;local #chi^{2}", fNDE, 0.5, fNDE+0.5, 1000, 0., 25.);
+  for (Int_t i = 1; i <= fNDE; i++) h2->GetXaxis()->SetBinLabel(i, Form("%d",fDEIds[i]));
+  fResiduals->AddAtAndExpand(h2, kLocalChi2PerDE+2);
+  
+  // track resolution
+  h2 = new TH2F("hUncorrPRes", "muon momentum reconstructed resolution at first cluster vs p;p (GeV/c); #sigma_{p}/p (%)", 300, 0., 300., 1000, 0., 10.);
+  fTrackRes->AddAtAndExpand(h2, kUncorrPRes);
+  h2 = new TH2F("hPRes", "muon momentum reconstructed resolution at vertex vs p;p (GeV/c); #sigma_{p}/p (%)", 300, 0., 300., 1000, 0., 10.);
+  fTrackRes->AddAtAndExpand(h2, kPRes);
+  h2 = new TH2F("hUncorrPtRes", "muon transverse momentum reconstructed resolution at first cluster vs p_{t};p_{t} (GeV/c); #sigma_{p_{t}}/p_{t} (%)", 300, 0., 30., 300, 0., 30.);
+  fTrackRes->AddAtAndExpand(h2, kUncorrPtRes);
+  h2 = new TH2F("hPtRes", "muon transverse momentum reconstructed resolution at vertex vs p_{t};p_{t} (GeV/c); #sigma_{p_{t}}/p_{t} (%)", 300, 0., 30., 300, 0., 30.);
+  fTrackRes->AddAtAndExpand(h2, kPtRes);
+  
+  // Post data at least once per task to ensure data synchronisation (required for merging)
+  PostData(1, fResiduals);
+  PostData(2, fResidualsVsP);
+  PostData(5, fTrackRes);
+}
+
+//________________________________________________________________________
+void AliAnalysisTaskMuonResolution::UserExec(Option_t *)
+{
+  /// Main event loop
+  
+  // check if OCDB properly loaded
+  if (!fOCDBLoaded) return;
+  
+  AliESDEvent* esd = dynamic_cast<AliESDEvent*>(InputEvent());
+  if (!esd) return;
+  
+  if ((++fNEvents)%100 == 0) cout<<"\rEvent processing... "<<fNEvents<<"\r"<<flush;
+  
+  // get tracker to refit
+  AliMUONVTrackReconstructor* tracker = AliMUONESDInterface::GetTracker();
+  
+  // loop over tracks
+  Int_t nTracks = (Int_t) esd->GetNumberOfMuonTracks(); 
+  for (Int_t iTrack = 0; iTrack < nTracks; ++iTrack) {
+    
+    // get the ESD track
+    AliESDMuonTrack* esdTrack = esd->GetMuonTrack(iTrack);
+    
+    // skip ghost tracks
+    if (!esdTrack->ContainTrackerData()) continue;
+    
+    // skip tracks that do not pass the physics selection if required
+    if (fSelectPhysics && fInputHandler && !fInputHandler->IsEventSelected()) continue;
+    
+    // skip tracks not matched with trigger if required
+    if (fMatchTrig && !esdTrack->ContainTriggerData()) continue;
+    
+    // skip low momentum tracks
+    if (esdTrack->PUncorrected() < fMinMomentum) continue;
+    
+    // get the corresponding MUON track
+    AliMUONTrack track;
+    AliMUONESDInterface::ESDToMUON(*esdTrack, track, kFALSE);
+    
+    // change the cluster resolution (and position)
+    ModifyClusters(track);
+    
+    // refit the track
+    if (!tracker->RefitTrack(track, kFALSE)) break;
+    
+    // save track unchanged
+    AliMUONTrack referenceTrack(track);
+    
+    // get track param at first cluster and add MCS in first chamber
+    AliMUONTrackParam trackParamAtFirstCluster(*(static_cast<AliMUONTrackParam*>(track.GetTrackParamAtCluster()->First())));
+    Int_t firstCh = 0; while (firstCh < 10 && !esdTrack->IsInMuonClusterMap(firstCh)) firstCh++;
+    AliMUONTrackExtrap::AddMCSEffect(&trackParamAtFirstCluster, AliMUONConstants::ChamberThicknessInX0(firstCh)/2., -1.);
+    
+    // fill momentum error at first cluster
+    Double_t pXUncorr = trackParamAtFirstCluster.Px();
+    Double_t pYUncorr = trackParamAtFirstCluster.Py();
+    Double_t pZUncorr = trackParamAtFirstCluster.Pz();
+    Double_t pUncorr = trackParamAtFirstCluster.P();
+    TMatrixD covUncorr(5,5);
+    Cov2CovP(trackParamAtFirstCluster,covUncorr);
+    Double_t sigmaPUncorr = TMath::Sqrt(pXUncorr * (pXUncorr*covUncorr(2,2) + pYUncorr*covUncorr(2,3) + pZUncorr*covUncorr(2,4)) +
+                                       pYUncorr * (pXUncorr*covUncorr(3,2) + pYUncorr*covUncorr(3,3) + pZUncorr*covUncorr(3,4)) +
+                                       pZUncorr * (pXUncorr*covUncorr(4,2) + pYUncorr*covUncorr(4,3) + pZUncorr*covUncorr(4,4))) / pUncorr;
+    ((TH2F*)fTrackRes->UncheckedAt(kUncorrPRes))->Fill(pUncorr,100.*sigmaPUncorr/pUncorr);
+    
+    // fill transverse momentum error at first cluster
+    Double_t ptUncorr = TMath::Sqrt(pXUncorr*pXUncorr + pYUncorr*pYUncorr);
+    Double_t sigmaPtUncorr = TMath::Sqrt(pXUncorr * (pXUncorr*covUncorr(2,2)  + pYUncorr*covUncorr(2,3)) + pYUncorr * (pXUncorr*covUncorr(3,2) + pYUncorr*covUncorr(3,3))) / ptUncorr;
+    ((TH2F*)fTrackRes->UncheckedAt(kUncorrPtRes))->Fill(ptUncorr,100.*sigmaPtUncorr/ptUncorr);
+    
+    // fill slopeX-Y error at first cluster
+    ((TH2F*)fTrackRes->UncheckedAt(kUncorrSlopeRes))->Fill(pUncorr,TMath::Sqrt(trackParamAtFirstCluster.GetCovariances()(1,1)));
+    ((TH2F*)fTrackRes->UncheckedAt(kUncorrSlopeRes+1))->Fill(pUncorr,TMath::Sqrt(trackParamAtFirstCluster.GetCovariances()(3,3)));
+    
+    // fill momentum error at vertex
+    AliMUONTrackParam trackParamAtVtx(trackParamAtFirstCluster);
+    AliMUONTrackExtrap::ExtrapToVertex(&trackParamAtVtx, esdTrack->GetNonBendingCoor(), esdTrack->GetBendingCoor(), esdTrack->GetZ(), 0., 0.);
+    Double_t pXVtx = trackParamAtVtx.Px();
+    Double_t pYVtx = trackParamAtVtx.Py();
+    Double_t pZVtx = trackParamAtVtx.Pz();
+    Double_t pVtx = trackParamAtVtx.P();
+    TMatrixD covVtx(5,5);
+    Cov2CovP(trackParamAtVtx,covVtx);
+    Double_t sigmaPVtx = TMath::Sqrt(pXVtx * (pXVtx*covVtx(2,2) + pYVtx*covVtx(2,3) + pZVtx*covVtx(2,4)) +
+                                    pYVtx * (pXVtx*covVtx(3,2) + pYVtx*covVtx(3,3) + pZVtx*covVtx(3,4)) +
+                                    pZVtx * (pXVtx*covVtx(4,2) + pYVtx*covVtx(4,3) + pZVtx*covVtx(4,4))) / pVtx;
+    ((TH2F*)fTrackRes->UncheckedAt(kPRes))->Fill(pVtx,100.*sigmaPVtx/pVtx);
+    
+    // fill transverse momentum error at vertex
+    Double_t ptVtx = TMath::Sqrt(pXVtx*pXVtx + pYVtx*pYVtx);
+    Double_t sigmaPtVtx = TMath::Sqrt(pXVtx * (pXVtx*covVtx(2,2)  + pYVtx*covVtx(2,3)) + pYVtx * (pXVtx*covVtx(3,2) + pYVtx*covVtx(3,3))) / ptVtx;
+    ((TH2F*)fTrackRes->UncheckedAt(kPtRes))->Fill(ptVtx,100.*sigmaPtVtx/ptVtx);
+    
+    // fill slopeX-Y error at vertex
+    ((TH2F*)fTrackRes->UncheckedAt(kSlopeRes))->Fill(pVtx,TMath::Sqrt(trackParamAtVtx.GetCovariances()(1,1)));
+    ((TH2F*)fTrackRes->UncheckedAt(kSlopeRes+1))->Fill(pVtx,TMath::Sqrt(trackParamAtVtx.GetCovariances()(3,3)));
+    
+    // loop over clusters
+    Int_t nClusters = track.GetNClusters();
+    for (Int_t iCluster=0; iCluster<nClusters; iCluster++) {
+      
+      // Get current, previous and next trackParams
+      AliMUONTrackParam* trackParam = static_cast<AliMUONTrackParam*>(track.GetTrackParamAtCluster()->UncheckedAt(iCluster));
+      AliMUONTrackParam* previousTrackParam = static_cast<AliMUONTrackParam*>(track.GetTrackParamAtCluster()->Before(trackParam));
+      AliMUONTrackParam* nextTrackParam = static_cast<AliMUONTrackParam*>(track.GetTrackParamAtCluster()->After(trackParam));
+      
+      // save current trackParam and remove it from the track
+      AliMUONTrackParam currentTrackParam(*trackParam);
+      track.RemoveTrackParamAtCluster(trackParam);
+      
+      // get cluster info
+      AliMUONVCluster* cluster = currentTrackParam.GetClusterPtr();
+      Int_t chId = cluster->GetChamberId();
+      Int_t halfChId = (cluster->GetX() > 0) ? 2*chId : 2*chId+1;
+      Int_t deId = cluster->GetDetElemId();
+      
+      // compute residuals with cluster still attached to the track
+      AliMUONTrackParam* referenceTrackParam = static_cast<AliMUONTrackParam*>(referenceTrack.GetTrackParamAtCluster()->UncheckedAt(iCluster));
+      Double_t deltaX = cluster->GetX() - referenceTrackParam->GetNonBendingCoor();
+      Double_t deltaY = cluster->GetY() - referenceTrackParam->GetBendingCoor();
+      
+      // compute local chi2
+      Double_t sigmaDeltaX2 = cluster->GetErrX2() - referenceTrackParam->GetCovariances()(0,0);
+      Double_t sigmaDeltaY2 = cluster->GetErrY2() - referenceTrackParam->GetCovariances()(2,2);
+      Double_t localChi2X = (sigmaDeltaX2 > 0.) ? deltaX*deltaX/sigmaDeltaX2 : 0.;
+      Double_t localChi2Y = (sigmaDeltaY2 > 0.) ? deltaY*deltaY/sigmaDeltaY2 : 0.;
+      Double_t localChi2 = 0.5 * referenceTrackParam->GetLocalChi2();
+      
+      // fill local chi2 info at every clusters
+      ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerCh))->Fill(chId+1, localChi2X);
+      ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerCh+1))->Fill(chId+1, localChi2Y);
+      ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerCh+2))->Fill(chId+1, localChi2);
+      ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerDE))->Fill(fDEIndices[deId], localChi2X);
+      ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerDE+1))->Fill(fDEIndices[deId], localChi2Y);
+      ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerDE+2))->Fill(fDEIndices[deId], localChi2);
+      
+      // make sure the track has another cluster in the same station and can still be refitted
+      Bool_t refit = track.IsValid( 1 << (chId/2) );
+      if (refit) {
+       
+       // refit the track and proceed if everything goes fine
+       if (tracker->RefitTrack(track, kFALSE)) {
+         
+         // fill histograms of residuals with cluster still attached to the track
+         ((TH2F*)fResiduals->UncheckedAt(kResidualPerCh_ClusterIn))->Fill(chId+1, deltaX);
+         ((TH2F*)fResiduals->UncheckedAt(kResidualPerCh_ClusterIn+1))->Fill(chId+1, deltaY);
+         ((TH2F*)fResiduals->UncheckedAt(kResidualPerHalfCh_ClusterIn))->Fill(halfChId+1, deltaX);
+         ((TH2F*)fResiduals->UncheckedAt(kResidualPerHalfCh_ClusterIn+1))->Fill(halfChId+1, deltaY);
+         ((TH2F*)fResiduals->UncheckedAt(kResidualPerDE_ClusterIn))->Fill(fDEIndices[deId], deltaX);
+         ((TH2F*)fResiduals->UncheckedAt(kResidualPerDE_ClusterIn+1))->Fill(fDEIndices[deId], deltaY);
+         ((TH2F*)fResidualsVsP->UncheckedAt(kResidualInChVsP_ClusterIn+chId))->Fill(pUncorr, deltaX);
+         ((TH2F*)fResidualsVsP->UncheckedAt(kResidualInChVsP_ClusterIn+10+chId))->Fill(pUncorr, deltaY);
+         
+         // find the track parameters closest to the current cluster position
+         Double_t dZWithPrevious = (previousTrackParam) ? TMath::Abs(previousTrackParam->GetClusterPtr()->GetZ() - cluster->GetZ()) : FLT_MAX;
+         Int_t previousChId = (previousTrackParam) ? previousTrackParam->GetClusterPtr()->GetChamberId() : -1;
+         Double_t dZWithNext = (nextTrackParam) ? TMath::Abs(nextTrackParam->GetClusterPtr()->GetZ() - cluster->GetZ()) : FLT_MAX;
+         AliMUONTrackParam* startingTrackParam = 0x0;
+         if ((fExtrapMode == 0 && dZWithPrevious < dZWithNext) ||
+             (fExtrapMode == 1 && previousTrackParam && !(chId/2 == 2 && previousChId/2 == 1) &&
+              !(chId/2 == 3 && previousChId/2 == 2))) startingTrackParam = previousTrackParam;
+         else startingTrackParam = nextTrackParam;
+         
+         // reset current parameters
+         currentTrackParam.SetParameters(startingTrackParam->GetParameters());
+         currentTrackParam.SetZ(startingTrackParam->GetZ());
+         currentTrackParam.SetCovariances(startingTrackParam->GetCovariances());
+         currentTrackParam.ResetPropagator();
+         
+         // extrapolate to the current cluster position and fill histograms of residuals if everything goes fine
+         if (AliMUONTrackExtrap::ExtrapToZCov(&currentTrackParam, currentTrackParam.GetClusterPtr()->GetZ(), kTRUE)) {
+           
+           // compute MCS dispersion on the first chamber
+           TMatrixD mcsCov(5,5);
+           if (startingTrackParam == nextTrackParam && chId == 0) {
+             AliMUONTrackParam trackParamForMCS;
+             trackParamForMCS.SetParameters(nextTrackParam->GetParameters());
+             AliMUONTrackExtrap::AddMCSEffect(&trackParamForMCS,AliMUONConstants::ChamberThicknessInX0(nextTrackParam->GetClusterPtr()->GetChamberId()),-1.);
+             const TMatrixD &propagator = currentTrackParam.GetPropagator();
+             TMatrixD tmp(trackParamForMCS.GetCovariances(),TMatrixD::kMultTranspose,propagator);
+             mcsCov.Mult(propagator,tmp);
+           } else mcsCov.Zero();
+           
+           // compute residuals
+           Double_t trackResX2 = currentTrackParam.GetCovariances()(0,0) + mcsCov(0,0);
+           Double_t trackResY2 = currentTrackParam.GetCovariances()(2,2) + mcsCov(2,2);
+           deltaX = cluster->GetX() - currentTrackParam.GetNonBendingCoor();
+           deltaY = cluster->GetY() - currentTrackParam.GetBendingCoor();
+           
+           // fill histograms with cluster not attached to the track
+           ((TH2F*)fResiduals->UncheckedAt(kResidualPerCh_ClusterOut))->Fill(chId+1, deltaX);
+           ((TH2F*)fResiduals->UncheckedAt(kResidualPerCh_ClusterOut+1))->Fill(chId+1, deltaY);
+           ((TH2F*)fResiduals->UncheckedAt(kResidualPerHalfCh_ClusterOut))->Fill(halfChId+1, deltaX);
+           ((TH2F*)fResiduals->UncheckedAt(kResidualPerHalfCh_ClusterOut+1))->Fill(halfChId+1, deltaY);
+           ((TH2F*)fResiduals->UncheckedAt(kResidualPerDE_ClusterOut))->Fill(fDEIndices[deId], deltaX);
+           ((TH2F*)fResiduals->UncheckedAt(kResidualPerDE_ClusterOut+1))->Fill(fDEIndices[deId], deltaY);
+           ((TH2F*)fResidualsVsP->UncheckedAt(kResidualInChVsP_ClusterOut+chId))->Fill(pUncorr, deltaX);
+           ((TH2F*)fResidualsVsP->UncheckedAt(kResidualInChVsP_ClusterOut+10+chId))->Fill(pUncorr, deltaY);
+           ((TH2F*)fResiduals->UncheckedAt(kTrackResPerCh))->Fill(chId+1, TMath::Sqrt(trackResX2));
+           ((TH2F*)fResiduals->UncheckedAt(kTrackResPerCh+1))->Fill(chId+1, TMath::Sqrt(trackResY2));
+           ((TH2F*)fResiduals->UncheckedAt(kTrackResPerHalfCh))->Fill(halfChId+1, TMath::Sqrt(trackResX2));
+           ((TH2F*)fResiduals->UncheckedAt(kTrackResPerHalfCh+1))->Fill(halfChId+1, TMath::Sqrt(trackResY2));
+           ((TH2F*)fResiduals->UncheckedAt(kTrackResPerDE))->Fill(fDEIndices[deId], TMath::Sqrt(trackResX2));
+           ((TH2F*)fResiduals->UncheckedAt(kTrackResPerDE+1))->Fill(fDEIndices[deId], TMath::Sqrt(trackResY2));
+           ((TH2F*)fResiduals->UncheckedAt(kMCSPerCh))->Fill(chId+1, TMath::Sqrt(mcsCov(0,0)));
+           ((TH2F*)fResiduals->UncheckedAt(kMCSPerCh+1))->Fill(chId+1, TMath::Sqrt(mcsCov(2,2)));
+           ((TH2F*)fResiduals->UncheckedAt(kMCSPerHalfCh))->Fill(halfChId+1, TMath::Sqrt(mcsCov(0,0)));
+           ((TH2F*)fResiduals->UncheckedAt(kMCSPerHalfCh+1))->Fill(halfChId+1, TMath::Sqrt(mcsCov(2,2)));
+           ((TH2F*)fResiduals->UncheckedAt(kMCSPerDE))->Fill(fDEIndices[deId], TMath::Sqrt(mcsCov(0,0)));
+           ((TH2F*)fResiduals->UncheckedAt(kMCSPerDE+1))->Fill(fDEIndices[deId], TMath::Sqrt(mcsCov(2,2)));
+           ((TH2F*)fResiduals->UncheckedAt(kClusterRes2PerCh))->Fill(chId+1, deltaX*deltaX - trackResX2);
+           ((TH2F*)fResiduals->UncheckedAt(kClusterRes2PerCh+1))->Fill(chId+1, deltaY*deltaY - trackResY2);
+         }
+         
+       }
+       
+      }
+      
+      // restore the track
+      track.AddTrackParamAtCluster(currentTrackParam, *(currentTrackParam.GetClusterPtr()), kTRUE);
+      
+    }
+    
+  }
+  
+  // Post final data. It will be written to a file with option "RECREATE"
+  PostData(1, fResiduals);
+  PostData(2, fResidualsVsP);
+  PostData(5, fTrackRes);
+}
+
+//________________________________________________________________________
+void AliAnalysisTaskMuonResolution::NotifyRun()
+{
+  /// load necessary data from OCDB corresponding to the first run number and initialize analysis
+  
+  if (fOCDBLoaded) return;
+  
+  AliCDBManager* cdbm = AliCDBManager::Instance();
+  cdbm->SetRun(fCurrentRunNumber);
+  
+  if (!AliMUONCDB::LoadField()) return;
+  
+  if (!AliMUONCDB::LoadMapping()) return;
+  
+  AliMUONRecoParam* recoParam = AliMUONCDB::LoadRecoParam();
+  if (!recoParam) return;
+  
+  fOCDBLoaded = kTRUE;
+  
+  AliMUONESDInterface::ResetTracker(recoParam);
+  
+  for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
+    
+    // set the cluster resolution to default if not already set and create output objects
+    if (fClusterResNB[i] < 0.) fClusterResNB[i] = recoParam->GetDefaultNonBendingReso(i);
+    if (fClusterResB[i] < 0.) fClusterResB[i] = recoParam->GetDefaultBendingReso(i);
+    
+    // fill correspondence between DEId and indices for histo (starting from 1)
+    AliMpDEIterator it;
+    it.First(i);
+    while (!it.IsDone()) {
+      fNDE++;
+      fDEIndices[it.CurrentDEId()] = fNDE;
+      fDEIds[fNDE] = it.CurrentDEId();
+      it.Next();
+    }
+    
+  }
+  
+  if (fReAlign) {
+    
+    // recover default storage name
+    TString defaultStorage(cdbm->GetDefaultStorage()->GetType());
+    if (defaultStorage == "alien") defaultStorage += Form("://folder=%s", cdbm->GetDefaultStorage()->GetBaseFolder().Data());
+    else defaultStorage += Form("://%s", cdbm->GetDefaultStorage()->GetBaseFolder().Data());
+    
+    // reset existing geometry/alignment if any
+    if (cdbm->GetEntryCache()->Contains("GRP/Geometry/Data")) cdbm->UnloadFromCache("GRP/Geometry/Data");
+    if (cdbm->GetEntryCache()->Contains("MUON/Align/Data")) cdbm->UnloadFromCache("MUON/Align/Data");
+    if (AliGeomManager::GetGeometry()) AliGeomManager::GetGeometry()->UnlockGeometry();
+    
+    // get original geometry transformer
+    AliGeomManager::LoadGeometry();
+    if (!AliGeomManager::GetGeometry()) return;
+    if (fOldAlignStorage != "none") {
+      if (!fOldAlignStorage.IsNull()) cdbm->SetSpecificStorage("MUON/Align/Data",fOldAlignStorage.Data());
+      else cdbm->SetSpecificStorage("MUON/Align/Data",defaultStorage.Data());
+      AliGeomManager::ApplyAlignObjsFromCDB("MUON");
+    }
+    fOldGeoTransformer = new AliMUONGeometryTransformer();
+    fOldGeoTransformer->LoadGeometryData();
+    
+    // get new geometry transformer
+    cdbm->UnloadFromCache("GRP/Geometry/Data");
+    if (fOldAlignStorage != "none") cdbm->UnloadFromCache("MUON/Align/Data");
+    AliGeomManager::GetGeometry()->UnlockGeometry();
+    AliGeomManager::LoadGeometry();
+    if (!AliGeomManager::GetGeometry()) return;
+    if (!fNewAlignStorage.IsNull()) cdbm->SetSpecificStorage("MUON/Align/Data",fNewAlignStorage.Data());
+    else cdbm->SetSpecificStorage("MUON/Align/Data",defaultStorage.Data());
+    AliGeomManager::ApplyAlignObjsFromCDB("MUON");
+    fNewGeoTransformer = new AliMUONGeometryTransformer();
+    fNewGeoTransformer->LoadGeometryData();
+    
+  } else {
+    
+    // load geometry for track extrapolation to vertex
+    if (cdbm->GetEntryCache()->Contains("GRP/Geometry/Data")) cdbm->UnloadFromCache("GRP/Geometry/Data");
+    if (AliGeomManager::GetGeometry()) AliGeomManager::GetGeometry()->UnlockGeometry();
+    AliGeomManager::LoadGeometry();
+    if (!AliGeomManager::GetGeometry()) return;
+    
+  }
+  
+  // print starting chamber resolution
+  printf("\nstarting chamber resolution:\n");
+  printf(" - non-bending:");
+  for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) printf((i==0)?" %5.3f":", %5.3f",fClusterResNB[i]);
+  printf("\n -     bending:");
+  for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) printf((i==0)?" %6.4f":", %6.4f",fClusterResB[i]);
+  printf("\n\n");
+  
+  UserCreateOutputObjects();
+  
+}
+
+//________________________________________________________________________
+void AliAnalysisTaskMuonResolution::Terminate(Option_t *)
+{
+  /// compute final results
+  
+  // recover output objects
+  fResiduals = static_cast<TObjArray*> (GetOutputData(1));
+  fResidualsVsP = static_cast<TObjArray*> (GetOutputData(2));
+  fTrackRes = static_cast<TObjArray*> (GetOutputData(5));
+  if (!fResiduals || !fResidualsVsP || !fTrackRes) return;
+  
+  // summary graphs
+  fLocalChi2 = new TObjArray(1000);
+  fLocalChi2->SetOwner();
+  fChamberRes = new TObjArray(1000);
+  fChamberRes->SetOwner();
+  TGraphErrors* g;
+  TMultiGraph* mg;
+  
+  const char* axes[2] = {"X", "Y"};
+  Double_t newClusterRes[2][10], newClusterResErr[2][10];
+  fNDE = ((TH2F*)fResiduals->UncheckedAt(kResidualPerDE_ClusterIn))->GetXaxis()->GetNbins();
+  
+  for (Int_t ia = 0; ia < 2; ia++) {
+    
+    g = new TGraphErrors(AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gResidual%sPerChMean_ClusterIn",axes[ia]));
+    g->SetTitle(Form("cluster-track residual-%s per Ch: mean (cluster in);chamber ID;<#Delta_{%s}> (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kResidualPerChMean_ClusterIn+ia);
+    g = new TGraphErrors(AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gResidual%sPerChMean_ClusterOut",axes[ia]));
+    g->SetTitle(Form("cluster-track residual-%s per Ch: mean (cluster out);chamber ID;<#Delta_{%s}> (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kResidualPerChMean_ClusterOut+ia);
+    
+    g = new TGraphErrors(2*AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gResidual%sPerHalfChMean_ClusterIn",axes[ia]));
+    g->SetTitle(Form("cluster-track residual-%s per half Ch: mean (cluster in);half chamber ID;<#Delta_{%s}> (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kResidualPerHalfChMean_ClusterIn+ia);
+    g = new TGraphErrors(2*AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gResidual%sPerHalfChMean_ClusterOut",axes[ia]));
+    g->SetTitle(Form("cluster-track residual-%s per half Ch: mean (cluster out);half chamber ID;<#Delta_{%s}> (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kResidualPerHalfChMean_ClusterOut+ia);
+    
+    g = new TGraphErrors(fNDE);
+    g->SetName(Form("gResidual%sPerDEMean_ClusterIn",axes[ia]));
+    g->SetTitle(Form("cluster-track residual-%s per DE: mean (cluster in);DE ID;<#Delta_{%s}> (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kResidualPerDEMean_ClusterIn+ia);
+    g = new TGraphErrors(fNDE);
+    g->SetName(Form("gResidual%sPerDEMean_ClusterOut",axes[ia]));
+    g->SetTitle(Form("cluster-track residual-%s per DE: mean (cluster out);DE ID;<#Delta_{%s}> (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kResidualPerDEMean_ClusterOut+ia);
+    
+    g = new TGraphErrors(AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gResidual%sPerChSigma_ClusterIn",axes[ia]));
+    g->SetTitle(Form("cluster-track residual-%s per Ch: sigma (cluster in);chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kResidualPerChSigma_ClusterIn+ia);
+    g = new TGraphErrors(AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gResidual%sPerChSigma_ClusterOut",axes[ia]));
+    g->SetTitle(Form("cluster-track residual-%s per Ch: sigma (cluster out);chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kResidualPerChSigma_ClusterOut+ia);
+    
+    g = new TGraphErrors(AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gResidual%sPerChDispersion_ClusterOut",axes[ia]));
+    g->SetTitle(Form("cluster-track residual-%s per Ch: dispersion (cluster out);chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kResidualPerChDispersion_ClusterOut+ia);
+    
+    g = new TGraphErrors(AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gCombinedResidual%sPerChSigma",axes[ia]));
+    g->SetTitle(Form("combined cluster-track residual-%s per Ch: sigma;chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kCombinedResidualPerChSigma+ia);
+    
+    g = new TGraphErrors(2*AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gCombinedResidual%sPerHalfChSigma",axes[ia]));
+    g->SetTitle(Form("combined cluster-track residual-%s per half Ch: sigma;half chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kCombinedResidualPerHalfChSigma+ia);
+    
+    g = new TGraphErrors(fNDE);
+    g->SetName(Form("gCombinedResidual%sPerDESigma",axes[ia]));
+    g->SetTitle(Form("combined cluster-track residual-%s per DE: sigma;DE ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kCombinedResidualPerDESigma+ia);
+    
+    mg = new TMultiGraph(Form("mgCombinedResidual%sSigmaVsP",axes[ia]),Form("cluster %s-resolution per chamber versus momentum;p (GeV/c^{2});#sigma_{%s} (cm)",axes[ia],axes[ia]));
+    for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
+      g = new TGraphErrors(((TH2F*)fResidualsVsP->UncheckedAt(kResidualInChVsP_ClusterIn+10*ia+i))->GetNbinsX());
+      g->SetName(Form("gRes%sVsP_ch%d",axes[ia],i+1));
+      g->SetMarkerStyle(kFullDotMedium);
+      g->SetMarkerColor(i+1+i/9);
+      mg->Add(g,"p");
+    }
+    fChamberRes->AddAtAndExpand(mg, kCombinedResidualSigmaVsP+ia);
+    
+    g = new TGraphErrors(AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gTrackRes%sPerCh",axes[ia]));
+    g->SetTitle(Form("track <#sigma_{%s}> per Ch;chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kTrackResPerChMean+ia);
+    
+    g = new TGraphErrors(AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gMCS%sPerCh",axes[ia]));
+    g->SetTitle(Form("MCS %s-dispersion of extrapolated track per Ch;chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kMCSPerChMean+ia);
+    
+    g = new TGraphErrors(AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gClusterRes%sPerCh",axes[ia]));
+    g->SetTitle(Form("cluster <#sigma_{%s}> per Ch;chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kClusterResPerCh+ia);
+    
+    g = new TGraphErrors(2*AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gClusterRes%sPerHalfCh",axes[ia]));
+    g->SetTitle(Form("cluster <#sigma_{%s}> per half Ch;half chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kClusterResPerHalfCh+ia);
+    
+    g = new TGraphErrors(fNDE);
+    g->SetName(Form("gClusterRes%sPerDE",axes[ia]));
+    g->SetTitle(Form("cluster <#sigma_{%s}> per DE;DE ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kClusterResPerDE+ia);
+    
+    g = new TGraphErrors(AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gCalcClusterRes%sPerCh",axes[ia]));
+    g->SetTitle(Form("calculated cluster <#sigma_{%s}> per Ch;chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fChamberRes->AddAtAndExpand(g, kCalcClusterResPerCh+ia);
+    
+    g = new TGraphErrors(AliMUONConstants::NTrackingCh());
+    g->SetName(Form("gLocalChi2%sPerChMean",axes[ia]));
+    g->SetTitle(Form("local chi2-%s per Ch: mean;chamber ID;<local #chi^{2}_{%s}>",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fLocalChi2->AddAtAndExpand(g, kLocalChi2PerChMean+ia);
+    
+    g = new TGraphErrors(fNDE);
+    g->SetName(Form("gLocalChi2%sPerDEMean",axes[ia]));
+    g->SetTitle(Form("local chi2-%s per DE: mean;DE ID;<local #chi^{2}_{%s}>",axes[ia],axes[ia]));
+    g->SetMarkerStyle(kFullDotLarge);
+    fLocalChi2->AddAtAndExpand(g, kLocalChi2PerDEMean+ia);
+    
+    // compute residual mean and dispersion and averaged local chi2 per chamber and half chamber
+    Double_t meanIn, meanInErr, meanOut, meanOutErr, sigmaIn, sigmaInErr, sigmaOut, sigmaOutErr;
+    Double_t sigmaTrack, sigmaTrackErr, sigmaMCS, sigmaMCSErr, clusterRes, clusterResErr, sigmaCluster, sigmaClusterErr;
+    for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
+      
+      // method 1
+      TH1D *tmp = ((TH2F*)fResiduals->UncheckedAt(kResidualPerCh_ClusterIn+ia))->ProjectionY("tmp",i+1,i+1,"e");
+      GetMean(tmp, meanIn, meanInErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChMean_ClusterIn+ia), i, i+1);
+      GetRMS(tmp, sigmaIn, sigmaInErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChSigma_ClusterIn+ia), i, i+1);
+      delete tmp;
+      
+      tmp = ((TH2F*)fResiduals->UncheckedAt(kResidualPerCh_ClusterOut+ia))->ProjectionY("tmp",i+1,i+1,"e");
+      GetMean(tmp, meanOut, meanOutErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChMean_ClusterOut+ia), i, i+1);
+      GetRMS(tmp, sigmaOut, sigmaOutErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChSigma_ClusterOut+ia), i, i+1);
+      delete tmp;
+      
+      if (fCorrectForSystematics) {
+       sigmaIn = TMath::Sqrt(sigmaIn*sigmaIn + meanIn*meanIn);
+       sigmaInErr = (sigmaIn>0) ? TMath::Sqrt(sigmaIn*sigmaIn*sigmaInErr*sigmaInErr + meanIn*meanIn*meanInErr*meanInErr) / sigmaIn : 0.;
+       sigmaOut = TMath::Sqrt(sigmaOut*sigmaOut + meanOut*meanOut);
+       sigmaOutErr = (sigmaOut>0) ? TMath::Sqrt(sigmaOut*sigmaOut*sigmaOutErr*sigmaOutErr + meanOut*meanOut*meanOutErr*meanOutErr) / sigmaOut : 0.;
+      }
+      ((TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChDispersion_ClusterOut+ia))->SetPoint(i, i+1, sigmaOut);
+      ((TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChDispersion_ClusterOut+ia))->SetPointError(i, 0., sigmaOutErr);
+      
+      clusterRes = TMath::Sqrt(sigmaIn*sigmaOut);
+      //      clusterResErr = (clusterRes > 0.) ? 0.5 * TMath::Sqrt(sigmaInErr*sigmaInErr*sigmaOut*sigmaOut + sigmaIn*sigmaIn*sigmaOutErr*sigmaOutErr) / clusterRes : 0.;
+      clusterResErr = TMath::Sqrt(sigmaInErr*sigmaOutErr);
+      ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerChSigma+ia))->SetPoint(i, i+1, clusterRes);
+      ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerChSigma+ia))->SetPointError(i, 0., clusterResErr);
+      newClusterRes[ia][i] = clusterRes;
+      newClusterResErr[ia][i] = clusterResErr;
+      
+      // method 2
+      tmp = ((TH2F*)fResiduals->UncheckedAt(kTrackResPerCh+ia))->ProjectionY("tmp",i+1,i+1,"e");
+      GetMean(tmp, sigmaTrack, sigmaTrackErr, (TGraphErrors*)fChamberRes->UncheckedAt(kTrackResPerChMean+ia), i, i+1, kFALSE);
+      delete tmp;
+      
+      tmp = ((TH2F*)fResiduals->UncheckedAt(kMCSPerCh+ia))->ProjectionY("tmp",i+1,i+1,"e");
+      GetMean(tmp, sigmaMCS, sigmaMCSErr, (TGraphErrors*)fChamberRes->UncheckedAt(kMCSPerChMean+ia), i, i+1, kFALSE);
+      delete tmp;
+      
+      sigmaCluster = sigmaOut*sigmaOut - sigmaTrack*sigmaTrack;
+      if (sigmaCluster > 0.) {
+       sigmaCluster = TMath::Sqrt(sigmaCluster);
+       sigmaClusterErr = TMath::Sqrt(sigmaOut*sigmaOut*sigmaOutErr*sigmaOutErr + sigmaTrack*sigmaTrack*sigmaTrackErr*sigmaTrackErr) / sigmaCluster;
+      } else {
+       sigmaCluster = 0.;
+       sigmaClusterErr = 0.;
+      }
+      ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerCh+ia))->SetPoint(i, i+1, sigmaCluster);
+      ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerCh+ia))->SetPointError(i, 0., sigmaClusterErr);
+      
+      // method 3
+      tmp = ((TH2F*)fResiduals->UncheckedAt(kClusterRes2PerCh+ia))->ProjectionY("tmp",i+1,i+1,"e");
+      ZoomRight(tmp);
+      clusterRes = tmp->GetMean();
+      if (clusterRes > 0.) {
+       ((TGraphErrors*)fChamberRes->UncheckedAt(kCalcClusterResPerCh+ia))->SetPoint(i, i+1, TMath::Sqrt(clusterRes));
+       ((TGraphErrors*)fChamberRes->UncheckedAt(kCalcClusterResPerCh+ia))->SetPointError(i, 0., 0.5 * tmp->GetMeanError() / TMath::Sqrt(clusterRes));
+      } else {
+       ((TGraphErrors*)fChamberRes->UncheckedAt(kCalcClusterResPerCh+ia))->SetPoint(i, i+1, 0.);
+       ((TGraphErrors*)fChamberRes->UncheckedAt(kCalcClusterResPerCh+ia))->SetPointError(i, 0., 0.);
+      }
+      delete tmp;
+      
+      // method 1 versus p
+      FillSigmaClusterVsP((TH2F*)fResidualsVsP->UncheckedAt(kResidualInChVsP_ClusterIn+10*ia+i),
+                         (TH2F*)fResidualsVsP->UncheckedAt(kResidualInChVsP_ClusterOut+10*ia+i),
+                         (TGraphErrors*)((TMultiGraph*)fChamberRes->UncheckedAt(kCombinedResidualSigmaVsP+ia))->GetListOfGraphs()->FindObject(Form("gRes%sVsP_ch%d",axes[ia],i+1)));
+      
+      // compute residual mean and dispersion per half chamber
+      for (Int_t j = 0; j < 2; j++) {
+       Int_t k = 2*i+j;
+       
+       // method 1
+       tmp = ((TH2F*)fResiduals->UncheckedAt(kResidualPerHalfCh_ClusterIn+ia))->ProjectionY("tmp",k+1,k+1,"e");
+       GetMean(tmp, meanIn, meanInErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerHalfChMean_ClusterIn+ia), k, k+1);
+       GetRMS(tmp, sigmaIn, sigmaInErr);
+       delete tmp;
+       
+       tmp = ((TH2F*)fResiduals->UncheckedAt(kResidualPerHalfCh_ClusterOut+ia))->ProjectionY("tmp",k+1,k+1,"e");
+       GetMean(tmp, meanOut, meanOutErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerHalfChMean_ClusterOut+ia), k, k+1);
+       GetRMS(tmp, sigmaOut, sigmaOutErr);
+       delete tmp;
+       
+       if (fCorrectForSystematics) {
+         sigmaIn = TMath::Sqrt(sigmaIn*sigmaIn + meanIn*meanIn);
+         sigmaInErr = (sigmaIn>0) ? TMath::Sqrt(sigmaIn*sigmaIn*sigmaInErr*sigmaInErr + meanIn*meanIn*meanInErr*meanInErr) / sigmaIn : 0.;
+         sigmaOut = TMath::Sqrt(sigmaOut*sigmaOut + meanOut*meanOut);
+         sigmaOutErr = (sigmaOut>0) ? TMath::Sqrt(sigmaOut*sigmaOut*sigmaOutErr*sigmaOutErr + meanOut*meanOut*meanOutErr*meanOutErr) / sigmaOut : 0.;
+       }
+       
+       clusterRes = TMath::Sqrt(sigmaIn*sigmaOut);
+       //      clusterResErr = (clusterRes > 0.) ? 0.5 * TMath::Sqrt(sigmaInErr*sigmaInErr*sigmaOut*sigmaOut + sigmaIn*sigmaIn*sigmaOutErr*sigmaOutErr) / clusterRes : 0.;
+       clusterResErr = TMath::Sqrt(sigmaInErr*sigmaOutErr);
+       ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerHalfChSigma+ia))->SetPoint(k, k+1, clusterRes);
+       ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerHalfChSigma+ia))->SetPointError(k, 0., clusterResErr);
+       
+       // method 2
+       tmp = ((TH2F*)fResiduals->UncheckedAt(kTrackResPerHalfCh+ia))->ProjectionY("tmp",k+1,k+1,"e");
+       GetMean(tmp, sigmaTrack, sigmaTrackErr, 0x0, 0, 0, kFALSE);
+       delete tmp;
+       
+       tmp = ((TH2F*)fResiduals->UncheckedAt(kMCSPerHalfCh+ia))->ProjectionY("tmp",k+1,k+1,"e");
+       GetMean(tmp, sigmaMCS, sigmaMCSErr, 0x0, 0, 0, kFALSE);
+       delete tmp;
+       
+       sigmaCluster = sigmaOut*sigmaOut - sigmaTrack*sigmaTrack;
+       if (sigmaCluster > 0.) {
+         sigmaCluster = TMath::Sqrt(sigmaCluster);
+         sigmaClusterErr = TMath::Sqrt(sigmaOut*sigmaOut*sigmaOutErr*sigmaOutErr + sigmaTrack*sigmaTrack*sigmaTrackErr*sigmaTrackErr) / sigmaCluster;
+       } else {
+         sigmaCluster = 0.;
+         sigmaClusterErr = 0.;
+       }
+       ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerHalfCh+ia))->SetPoint(k, k+1, sigmaCluster);
+       ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerHalfCh+ia))->SetPointError(k, 0., sigmaClusterErr);
+       
+      }
+      
+      // compute averaged local chi2
+      tmp = ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerCh+ia))->ProjectionY("tmp",i+1,i+1,"e");
+      ((TGraphErrors*)fLocalChi2->UncheckedAt(kLocalChi2PerChMean+ia))->SetPoint(i, i+1, tmp->GetMean());
+      ((TGraphErrors*)fLocalChi2->UncheckedAt(kLocalChi2PerChMean+ia))->SetPointError(i, 0., tmp->GetMeanError());
+      delete tmp;
+      
+    }
+    
+    // compute residual mean and dispersion per DE
+    for (Int_t i = 0; i < fNDE; i++) {
+      
+      // method 1
+      TH1D *tmp = ((TH2F*)fResiduals->UncheckedAt(kResidualPerDE_ClusterIn+ia))->ProjectionY("tmp",i+1,i+1,"e");
+      GetMean(tmp, meanIn, meanInErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMean_ClusterIn+ia), i, i+1);
+      GetRMS(tmp, sigmaIn, sigmaInErr);
+      delete tmp;
+      
+      tmp = ((TH2F*)fResiduals->UncheckedAt(kResidualPerDE_ClusterOut+ia))->ProjectionY("tmp",i+1,i+1,"e");
+      GetMean(tmp, meanOut, meanOutErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMean_ClusterOut+ia), i, i+1);
+      GetRMS(tmp, sigmaOut, sigmaOutErr);
+      delete tmp;
+      
+      if (fCorrectForSystematics) {
+       sigmaIn = TMath::Sqrt(sigmaIn*sigmaIn + meanIn*meanIn);
+       sigmaInErr = (sigmaIn>0) ? TMath::Sqrt(sigmaIn*sigmaIn*sigmaInErr*sigmaInErr + meanIn*meanIn*meanInErr*meanInErr) / sigmaIn : 0.;
+       sigmaOut = TMath::Sqrt(sigmaOut*sigmaOut + meanOut*meanOut);
+       sigmaOutErr = (sigmaOut>0) ? TMath::Sqrt(sigmaOut*sigmaOut*sigmaOutErr*sigmaOutErr + meanOut*meanOut*meanOutErr*meanOutErr) / sigmaOut : 0.;
+      }
+      
+      clusterRes = TMath::Sqrt(sigmaIn*sigmaOut);
+      //      clusterResErr = (clusterRes > 0.) ? 0.5 * TMath::Sqrt(sigmaInErr*sigmaInErr*sigmaOut*sigmaOut + sigmaIn*sigmaIn*sigmaOutErr*sigmaOutErr) / clusterRes : 0.;
+      clusterResErr = TMath::Sqrt(sigmaInErr*sigmaOutErr);
+      ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerDESigma+ia))->SetPoint(i, i+1, clusterRes);
+      ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerDESigma+ia))->SetPointError(i, 0., clusterResErr);
+      
+      // method 2
+      tmp = ((TH2F*)fResiduals->UncheckedAt(kTrackResPerDE+ia))->ProjectionY("tmp",i+1,i+1,"e");
+      GetMean(tmp, sigmaTrack, sigmaTrackErr, 0x0, 0, 0, kFALSE);
+      delete tmp;
+      
+      tmp = ((TH2F*)fResiduals->UncheckedAt(kMCSPerDE+ia))->ProjectionY("tmp",i+1,i+1,"e");
+      GetMean(tmp, sigmaMCS, sigmaMCSErr, 0x0, 0, 0, kFALSE);
+      delete tmp;
+      
+      sigmaCluster = sigmaOut*sigmaOut - sigmaTrack*sigmaTrack;
+      if (sigmaCluster > 0.) {
+       sigmaCluster = TMath::Sqrt(sigmaCluster);
+       sigmaClusterErr = TMath::Sqrt(sigmaOut*sigmaOut*sigmaOutErr*sigmaOutErr + sigmaTrack*sigmaTrack*sigmaTrackErr*sigmaTrackErr) / sigmaCluster;
+      } else {
+       sigmaCluster = 0.;
+       sigmaClusterErr = 0.;
+      }
+      ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerDE+ia))->SetPoint(i, i+1, sigmaCluster);
+      ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerDE+ia))->SetPointError(i, 0., sigmaClusterErr);
+      
+      // compute averaged local chi2
+      tmp = ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerDE+ia))->ProjectionY("tmp",i+1,i+1,"e");
+      ((TGraphErrors*)fLocalChi2->UncheckedAt(kLocalChi2PerDEMean+ia))->SetPoint(i, i+1, tmp->GetMean());
+      ((TGraphErrors*)fLocalChi2->UncheckedAt(kLocalChi2PerDEMean+ia))->SetPointError(i, 0., tmp->GetMeanError());
+      delete tmp;
+      
+    }
+    
+    // set graph labels
+    TAxis* xAxis = ((TH2F*)fResiduals->UncheckedAt(kResidualPerDE_ClusterOut+ia))->GetXaxis();
+    ((TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMean_ClusterIn+ia))->GetXaxis()->Set(fNDE, 0.5, fNDE+0.5);
+    ((TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMean_ClusterOut+ia))->GetXaxis()->Set(fNDE, 0.5, fNDE+0.5);
+    ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerDESigma+ia))->GetXaxis()->Set(fNDE, 0.5, fNDE+0.5);
+    ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerDE+ia))->GetXaxis()->Set(fNDE, 0.5, fNDE+0.5);
+    ((TGraphErrors*)fLocalChi2->UncheckedAt(kLocalChi2PerDEMean+ia))->GetXaxis()->Set(fNDE, 0.5, fNDE+0.5);
+    for (Int_t i = 1; i <= fNDE; i++) {
+      const char* label = xAxis->GetBinLabel(i);
+      ((TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMean_ClusterIn+ia))->GetXaxis()->SetBinLabel(i, label);
+      ((TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMean_ClusterOut+ia))->GetXaxis()->SetBinLabel(i, label);
+      ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerDESigma+ia))->GetXaxis()->SetBinLabel(i, label);
+      ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerDE+ia))->GetXaxis()->SetBinLabel(i, label);
+      ((TGraphErrors*)fLocalChi2->UncheckedAt(kLocalChi2PerDEMean+ia))->GetXaxis()->SetBinLabel(i, label);
+    }
+    
+  }
+  
+  // compute averaged local chi2 per chamber (X+Y)
+  TH2F* h2 = (TH2F*)fResiduals->UncheckedAt(kLocalChi2PerCh+2);
+  g = new TGraphErrors(AliMUONConstants::NTrackingCh());
+  g->SetName("gLocalChi2PerChMean");
+  g->SetTitle("local chi2 per Ch: mean;chamber ID;<local #chi^{2}>");
+  g->SetMarkerStyle(kFullDotLarge);
+  fLocalChi2->AddAtAndExpand(g, kLocalChi2PerChMean+2);
+  for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
+    TH1D* tmp = h2->ProjectionY("tmp",i+1,i+1,"e");
+    g->SetPoint(i, i+1, tmp->GetMean());
+    g->SetPointError(i, 0., tmp->GetMeanError());
+    delete tmp;
+  }
+  
+  // compute averaged local chi2 per DE (X+Y)
+  h2 = (TH2F*)fResiduals->UncheckedAt(kLocalChi2PerDE+2);
+  g = new TGraphErrors(fNDE);
+  g->SetName("gLocalChi2PerDEMean");
+  g->SetTitle("local chi2 per DE: mean;DE ID;<local #chi^{2}>");
+  g->SetMarkerStyle(kFullDotLarge);
+  fLocalChi2->AddAtAndExpand(g, kLocalChi2PerDEMean+2);
+  for (Int_t i = 0; i < fNDE; i++) {
+    TH1D* tmp = h2->ProjectionY("tmp",i+1,i+1,"e");
+    g->SetPoint(i, i+1, tmp->GetMean());
+    g->SetPointError(i, 0., tmp->GetMeanError());
+    delete tmp;
+  }
+  
+  // set graph labels
+  g->GetXaxis()->Set(fNDE, 0.5, fNDE+0.5);
+  for (Int_t i = 1; i <= fNDE; i++) {
+    const char* label = h2->GetXaxis()->GetBinLabel(i);
+    g->GetXaxis()->SetBinLabel(i, label);
+  }
+  
+  // display
+  fCanvases = new TObjArray(1000);
+  fCanvases->SetOwner();
+  
+  TLegend *lResPerChMean = new TLegend(0.75,0.85,0.99,0.99);
+  TLegend *lResPerChSigma1 = new TLegend(0.75,0.85,0.99,0.99);
+  TLegend *lResPerChSigma2 = new TLegend(0.75,0.85,0.99,0.99);
+  TLegend *lResPerChSigma3 = new TLegend(0.75,0.85,0.99,0.99);
+  
+  TCanvas* cResPerCh = new TCanvas("cResPerCh","cResPerCh",1200,500);
+  cResPerCh->Divide(4,2);
+  for (Int_t ia = 0; ia < 2; ia++) {
+    cResPerCh->cd(1+4*ia);
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChMean_ClusterOut+ia);
+    g->Draw("ap");
+    g->SetMarkerColor(2);
+    g->SetLineColor(2);
+    if (ia == 0) lResPerChMean->AddEntry(g,"cluster out","PL");
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChMean_ClusterIn+ia);
+    g->Draw("p");
+    g->SetMarkerColor(4);
+    g->SetLineColor(4);
+    if (ia == 0) lResPerChMean->AddEntry(g,"cluster in","PL");
+    if (ia == 0) lResPerChMean->Draw();
+    else lResPerChMean->DrawClone();
+    cResPerCh->cd(2+4*ia);
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChSigma_ClusterOut+ia);
+    g->Draw("ap");
+    g->SetMinimum(0.);
+    g->SetMarkerColor(2);
+    g->SetLineColor(2);
+    if (ia == 0) lResPerChSigma1->AddEntry(g,"cluster out","PL");
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChSigma_ClusterIn+ia);
+    g->Draw("p");
+    g->SetMarkerColor(4);
+    g->SetLineColor(4);
+    if (ia == 0) lResPerChSigma1->AddEntry(g,"cluster in","PL");
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kMCSPerChMean+ia);
+    g->Draw("p");
+    g->SetMarkerColor(5);
+    g->SetLineColor(5);
+    if (ia == 0) lResPerChSigma1->AddEntry(g,"MCS","PL");
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerChSigma+ia);
+    g->Draw("p");
+    g->SetMarkerColor(3);
+    g->SetLineColor(3);
+    if (ia == 0) lResPerChSigma1->AddEntry(g,"combined 1","PL");
+    if (ia == 0) lResPerChSigma1->Draw();
+    else lResPerChSigma1->DrawClone();
+    cResPerCh->cd(3+4*ia);
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChDispersion_ClusterOut+ia);
+    g->Draw("ap");
+    g->SetMinimum(0.);
+    g->SetMarkerColor(2);
+    g->SetLineColor(2);
+    if (ia == 0) lResPerChSigma2->AddEntry(g,"cluster out","PL");
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kMCSPerChMean+ia);
+    g->Draw("p");
+    if (ia == 0) lResPerChSigma2->AddEntry(g,"MCS","PL");
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kTrackResPerChMean+ia);
+    g->Draw("p");
+    g->SetMarkerColor(4);
+    g->SetLineColor(4);
+    if (ia == 0) lResPerChSigma2->AddEntry(g,"track res.","PL");
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerCh+ia);
+    g->Draw("p");
+    if (ia == 0) lResPerChSigma2->AddEntry(g,"combined 2","PL");
+    if (ia == 0) lResPerChSigma2->Draw();
+    else lResPerChSigma2->DrawClone();
+    cResPerCh->cd(4+4*ia);
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerChSigma+ia);
+    g->Draw("ap");
+    g->SetMinimum(0.);
+    if (ia == 0) lResPerChSigma3->AddEntry(g,"combined 1","PL");
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerCh+ia);
+    g->Draw("p");
+    if (ia == 0) lResPerChSigma3->AddEntry(g,"combined 2","PL");
+    if (ia == 0) lResPerChSigma3->Draw();
+    else lResPerChSigma3->DrawClone();
+  }
+  fCanvases->AddAtAndExpand(cResPerCh, kResPerCh);
+  
+  TCanvas* cResPerHalfCh = new TCanvas("cResPerHalfCh","cResPerHalfCh",1200,500);
+  cResPerHalfCh->Divide(2,2);
+  for (Int_t ia = 0; ia < 2; ia++) {
+    cResPerHalfCh->cd(1+2*ia);
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerHalfChMean_ClusterOut+ia);
+    g->Draw("ap");
+    g->SetMarkerColor(2);
+    g->SetLineColor(2);
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerHalfChMean_ClusterIn+ia);
+    g->Draw("p");
+    g->SetMarkerColor(4);
+    g->SetLineColor(4);
+    lResPerChMean->DrawClone();
+    cResPerHalfCh->cd(2+2*ia);
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerHalfChSigma+ia);
+    g->Draw("ap");
+    g->SetMinimum(0.);
+    g->SetMarkerColor(3);
+    g->SetLineColor(3);
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerHalfCh+ia);
+    g->Draw("p");
+    lResPerChSigma3->DrawClone();
+  }
+  fCanvases->AddAtAndExpand(cResPerHalfCh, kResPerHalfCh);
+  
+  TCanvas* cResPerDE = new TCanvas("cResPerDE","cResPerDE",1200,800);
+  cResPerDE->Divide(1,4);
+  for (Int_t ia = 0; ia < 2; ia++) {
+    cResPerDE->cd(1+ia);
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMean_ClusterOut+ia);
+    g->Draw("ap");
+    g->SetMarkerColor(2);
+    g->SetLineColor(2);
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMean_ClusterIn+ia);
+    g->Draw("p");
+    g->SetMarkerColor(4);
+    g->SetLineColor(4);
+    lResPerChMean->DrawClone();
+    cResPerDE->cd(3+ia);
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerDESigma+ia);
+    g->Draw("ap");
+    g->SetMinimum(0.);
+    g->SetMarkerColor(3);
+    g->SetLineColor(3);
+    g = (TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerDE+ia);
+    g->Draw("p");
+    lResPerChSigma3->DrawClone();
+  }
+  fCanvases->AddAtAndExpand(cResPerDE, kResPerDE);
+  
+  TCanvas* cResPerChVsP = new TCanvas("cResPerChVsP","cResPerChVsP");
+  cResPerChVsP->Divide(1,2);
+  for (Int_t ia = 0; ia < 2; ia++) {
+    cResPerChVsP->cd(1+ia);
+    mg = (TMultiGraph*)fChamberRes->UncheckedAt(kCombinedResidualSigmaVsP+ia);
+    mg->Draw("ap");
+  }
+  fCanvases->AddAtAndExpand(cResPerChVsP, kResPerChVsP);
+  
+  // print results
+  printf("\nchamber resolution:\n");
+  printf(" - non-bending:");
+  for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) printf((i==0)?" %5.3f":", %5.3f",newClusterRes[0][i]);
+  printf("\n -     bending:");
+  for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) printf((i==0)?" %6.4f":", %6.4f",newClusterRes[1][i]);
+  printf("\n\n");
+  
+  // Post final data.
+  PostData(3, fLocalChi2);
+  PostData(4, fChamberRes);
+}
+
+//________________________________________________________________________
+void AliAnalysisTaskMuonResolution::ModifyClusters(AliMUONTrack& track)
+{
+  /// Reset the clusters resolution from the ones given to the task and change
+  /// the cluster position according to the new alignment parameters if required
+  
+  Double_t gX,gY,gZ,lX,lY,lZ;
+  
+  // loop over clusters
+  Int_t nClusters = track.GetNClusters();
+  for (Int_t iCluster=0; iCluster<nClusters; iCluster++) {
+    
+    AliMUONVCluster* cl = static_cast<AliMUONTrackParam*>(track.GetTrackParamAtCluster()->UncheckedAt(iCluster))->GetClusterPtr();
+    
+    // change their resolution
+    cl->SetErrXY(fClusterResNB[cl->GetChamberId()], fClusterResB[cl->GetChamberId()]);
+    
+    // change their position
+    if (fReAlign) {
+      gX = cl->GetX();
+      gY = cl->GetY();
+      gZ = cl->GetZ();
+      fOldGeoTransformer->Global2Local(cl->GetDetElemId(),gX,gY,gZ,lX,lY,lZ);
+      fNewGeoTransformer->Local2Global(cl->GetDetElemId(),lX,lY,lZ,gX,gY,gZ);
+      cl->SetXYZ(gX,gY,gZ);
+    }
+    
+  }
+  
+}
+
+//________________________________________________________________________
+void AliAnalysisTaskMuonResolution::Zoom(TH1* h, Double_t fractionCut)
+{
+  /// Reduce the range of the histogram by removing a given fration of the statistic at each edge
+  ZoomLeft(h, fractionCut);
+  ZoomRight(h, fractionCut);
+}
+
+//________________________________________________________________________
+void AliAnalysisTaskMuonResolution::ZoomLeft(TH1* h, Double_t fractionCut)
+{
+  /// Reduce the range of the histogram by removing a given fration of the statistic on the left side
+  Int_t maxEventsCut = (Int_t) (fractionCut * h->GetEntries());
+  Int_t nBins = h->GetNbinsX();
+  
+  // set low edge  
+  Int_t minBin;
+  Int_t eventsCut = 0;
+  for (minBin = 1; minBin <= nBins; minBin++) {
+    eventsCut += (Int_t) h->GetBinContent(minBin);
+    if (eventsCut > maxEventsCut) break;
+  }
+  
+  // set new axis range
+  h->GetXaxis()->SetRange(--minBin, h->GetXaxis()->GetLast());
+}
+
+//________________________________________________________________________
+void AliAnalysisTaskMuonResolution::ZoomRight(TH1* h, Double_t fractionCut)
+{
+  /// Reduce the range of the histogram by removing a given fration of the statistic on the right side
+  Int_t maxEventsCut = (Int_t) (fractionCut * h->GetEntries());
+  Int_t nBins = h->GetNbinsX();
+  
+  // set high edge
+  Int_t maxBin;
+  Int_t eventsCut = 0;
+  for (maxBin = nBins; maxBin >= 1; maxBin--) {
+    eventsCut += (Int_t) h->GetBinContent(maxBin);
+    if (eventsCut > maxEventsCut) break;
+  }
+  
+  // set new axis range
+  h->GetXaxis()->SetRange(h->GetXaxis()->GetFirst(), ++maxBin);
+}
+
+//________________________________________________________________________
+void AliAnalysisTaskMuonResolution::GetMean(TH1* h, Double_t& mean, Double_t& meanErr, TGraphErrors* g, Int_t i, Double_t x, Bool_t zoom)
+{
+  /// Fill graph with the mean value of the histogram and the corresponding error (zooming if required)
+  Int_t firstBin = h->GetXaxis()->GetFirst();
+  Int_t lastBin = h->GetXaxis()->GetLast();
+  if (zoom) Zoom(h);
+  mean = (h->GetEntries() > fgkMinEntries) ? h->GetMean() : 0.;
+  meanErr = (h->GetEntries() > fgkMinEntries) ? h->GetMeanError() : 0.;
+  if (g) {
+    g->SetPoint(i, x, mean);
+    g->SetPointError(i, 0., meanErr);
+  }
+  if (zoom) h->GetXaxis()->SetRange(firstBin,lastBin);
+}
+
+//________________________________________________________________________
+void AliAnalysisTaskMuonResolution::GetRMS(TH1* h, Double_t& rms, Double_t& rmsErr, TGraphErrors* g, Int_t i, Double_t x, Bool_t zoom)
+{
+  /// Return the RMS of the histogram and the corresponding error (zooming if required) and fill graph if !=0x0
+  Int_t firstBin = h->GetXaxis()->GetFirst();
+  Int_t lastBin = h->GetXaxis()->GetLast();
+  if (zoom) Zoom(h);
+  rms = (h->GetEntries() > fgkMinEntries) ? h->GetRMS() : 0.;
+  rmsErr = (h->GetEntries() > fgkMinEntries) ? h->GetRMSError() : 0.;
+  if (g) {
+    g->SetPoint(i, x, rms);
+    g->SetPointError(i, 0., rmsErr);
+  }
+  if (zoom) h->GetXaxis()->SetRange(firstBin,lastBin);
+}
+
+//________________________________________________________________________
+void AliAnalysisTaskMuonResolution::FillSigmaClusterVsP(TH2* hIn, TH2* hOut, TGraphErrors* g, Bool_t zoom)
+{
+  /// Fill graph with cluster resolution from combined residuals with cluster in/out (zooming if required)
+  Double_t sigmaIn, sigmaInErr, sigmaOut, sigmaOutErr, clusterRes, clusterResErr;
+  for (Int_t j = 1; j <= hIn->GetNbinsX(); j++) {
+    TH1D* tmp = hIn->ProjectionY("tmp",j,j,"e");
+    GetRMS(tmp, sigmaIn, sigmaInErr, 0x0, 0, 0., zoom);
+    delete tmp;
+    tmp = hOut->ProjectionY("tmp",j,j,"e");
+    GetRMS(tmp, sigmaOut, sigmaOutErr, 0x0, 0, 0., zoom);
+    delete tmp;
+    Double_t p = 0.5 * (hIn->GetBinLowEdge(j) + hIn->GetBinLowEdge(j+1));
+    Double_t pErr = p - hIn->GetBinLowEdge(j);
+    clusterRes = TMath::Sqrt(sigmaIn*sigmaOut);
+    clusterResErr = (clusterRes > 0.) ? 0.5 * TMath::Sqrt(sigmaInErr*sigmaInErr*sigmaOut*sigmaOut + sigmaIn*sigmaIn*sigmaOutErr*sigmaOutErr) / clusterRes : 0.;
+    g->SetPoint(j, p, clusterRes);
+    g->SetPointError(j, pErr, clusterResErr);
+  }
+}
+
+//__________________________________________________________________________
+void AliAnalysisTaskMuonResolution::Cov2CovP(const AliMUONTrackParam &param, TMatrixD &covP)
+{
+  /// change coordinate system: (X, SlopeX, Y, SlopeY, q/Pyz) -> (X, Y, pX, pY, pZ)
+  /// parameters (param) are given in the (X, SlopeX, Y, SlopeY, q/Pyz) coordinate system
+  
+  // Get useful parameters
+  Double_t slopeX = param.GetNonBendingSlope();
+  Double_t slopeY = param.GetBendingSlope();
+  Double_t qOverPYZ = param.GetInverseBendingMomentum();
+  Double_t pZ = param.Pz();
+  
+  // compute Jacobian to change the coordinate system from (X,SlopeX,Y,SlopeY,c/pYZ) to (X,Y,pX,pY,pZ)
+  Double_t dpZdSlopeY = - qOverPYZ * qOverPYZ * pZ * pZ * pZ * slopeY;
+  Double_t dpZdQOverPYZ = (qOverPYZ != 0.) ? - pZ / qOverPYZ : - FLT_MAX;
+  TMatrixD jacob(5,5);
+  jacob.Zero();
+  jacob(0,0) = 1.;
+  jacob(1,2) = 1.;
+  jacob(2,1) = pZ;
+  jacob(2,3) = slopeX * dpZdSlopeY;
+  jacob(2,4) = slopeX * dpZdQOverPYZ;
+  jacob(3,3) = pZ + slopeY * dpZdSlopeY;
+  jacob(3,4) = slopeY * dpZdQOverPYZ;
+  jacob(4,3) = dpZdSlopeY;
+  jacob(4,4) = dpZdQOverPYZ;
+  
+  // compute covariances in new coordinate system
+  TMatrixD tmp(param.GetCovariances(),TMatrixD::kMultTranspose,jacob);
+  covP.Mult(jacob,tmp);
+}
+
diff --git a/PWG3/muondep/AliAnalysisTaskMuonResolution.h b/PWG3/muondep/AliAnalysisTaskMuonResolution.h
new file mode 100644 (file)
index 0000000..71749c9
--- /dev/null
@@ -0,0 +1,208 @@
+#ifndef ALIANALYSISTASKMUONRESOLUTION_H
+#define ALIANALYSISTASKMUONRESOLUTION_H
+/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
+ * See cxx source for full Copyright notice                               */
+
+/// \ingroup muondep
+/// \class AliAnalysisTaskMuonResolution
+/// \brief Muon spectrometer resolution
+//Author: Philippe Pillot - SUBATECH Nantes
+
+#include <TString.h>
+#include <TMatrixD.h>
+#include "AliMUONConstants.h"
+
+class TH1;
+class TH2;
+class TGraphErrors;
+class TObjArray;
+class AliMUONTrack;
+class AliMUONTrackParam;
+class AliMUONGeometryTransformer;
+
+class AliAnalysisTaskMuonResolution : public AliAnalysisTaskSE {
+public:
+  
+  AliAnalysisTaskMuonResolution();
+  AliAnalysisTaskMuonResolution(const char *name);
+  virtual ~AliAnalysisTaskMuonResolution();
+  
+  void SetStartingResolution(Int_t chId, Double_t valNB, Double_t valB);
+  void SetStartingResolution(Double_t valNB[10], Double_t valB[10]);
+  void GetStartingResolution(Double_t valNB[10], Double_t valB[10]);
+  
+  /// set the minimum momentum value of the tracks used to compute the resolution
+  void SetMinMomentum(Double_t val) { fMinMomentum = val; }
+  
+  /// set the flag to use only tracks passing the physics selection
+  void SelectPhysics(Bool_t flag = kTRUE) {fSelectPhysics = flag;}
+  
+  /// set the flag to use only tracks matched with trigger or not
+  void MatchTrigger(Bool_t flag = kTRUE) { fMatchTrig = flag; }
+  
+  /// set the extrapolation mode to get the track parameters and covariances at a given cluster:
+  /// 0 = extrapolate from the closest cluster; 1 = extrapolate from the previous cluster except between stations 2-3-4
+  void SetExtrapMode(Int_t val) { fExtrapMode = val; }
+  
+  /// set the flag to add or not the systematic shifts of the residuals to the resolution
+  void CorrectForSystematics(Bool_t flag = kTRUE) { fCorrectForSystematics = flag; }
+  
+  void ReAlign(const char* oldAlignStorage = 0x0, const char* newAlignStorage = "");
+  
+  /// return the list of summary canvases
+  TObjArray* GetCanvases() {return fCanvases;}
+  
+  virtual void   UserCreateOutputObjects();
+  virtual void   UserExec(Option_t *);
+  virtual void   NotifyRun();
+  virtual void   Terminate(Option_t *);
+  
+private:
+  
+  /// Not implemented
+  AliAnalysisTaskMuonResolution(const AliAnalysisTaskMuonResolution& rhs);
+  /// Not implemented
+  AliAnalysisTaskMuonResolution& operator = (const AliAnalysisTaskMuonResolution& rhs);
+  
+  void ModifyClusters(AliMUONTrack& track);
+  void Zoom(TH1* h, Double_t fractionCut = 0.01);
+  void ZoomLeft(TH1* h, Double_t fractionCut = 0.02);
+  void ZoomRight(TH1* h, Double_t fractionCut = 0.02);
+  void GetMean(TH1* h, Double_t& mean, Double_t& meanErr, TGraphErrors* g = 0x0, Int_t i = 0, Double_t x = 0, Bool_t zoom = kTRUE);
+  void GetRMS(TH1* h, Double_t& rms, Double_t& rmsErr, TGraphErrors* g = 0x0, Int_t i = 0, Double_t x = 0, Bool_t zoom = kTRUE);
+  void FillSigmaClusterVsP(TH2* hIn, TH2* hOut, TGraphErrors* g, Bool_t zoom = kTRUE);
+  void Cov2CovP(const AliMUONTrackParam &param, TMatrixD &covP);
+  
+private:
+  
+  enum outputIndices {
+    kResidualPerCh_ClusterIn            = 0,  ///< cluster-track residual-X/Y distribution per chamber (cluster attached to the track)
+    kResidualPerCh_ClusterOut           = 2,  ///< cluster-track residual-X/Y distribution per chamber (cluster not attached to the track)
+    kTrackResPerCh                      = 4,  ///< track resolution-X/Y per chamber
+    kMCSPerCh                           = 6,  ///< MCS X/Y-dispersion of extrapolated track per chamber
+    kClusterRes2PerCh                   = 8,  ///< cluster X/Y-resolution per chamber
+    kResidualInChVsP_ClusterIn          = 10, ///< cluster-track residual-X/Y distribution in chamber i versus momentum (cluster attached to the track)
+    kResidualInChVsP_ClusterOut         = 30, ///< cluster-track residual-X/Y distribution in chamber i versus momentum (cluster not attached to the track)
+    kResidualPerDE_ClusterIn            = 50, ///< cluster-track residual-X/Y distribution per DE (cluster attached to the track)
+    kResidualPerDE_ClusterOut           = 52, ///< cluster-track residual-X/Y distribution per DE (cluster not attached to the track)
+    kTrackResPerDE                      = 54, ///< track resolution-X/Y per DE
+    kMCSPerDE                           = 56, ///< MCS X/Y-dispersion of extrapolated track per DE
+    kResidualPerHalfCh_ClusterIn        = 58, ///< cluster-track residual-X/Y distribution per half chamber (cluster attached to the track)
+    kResidualPerHalfCh_ClusterOut       = 60, ///< cluster-track residual-X/Y distribution per half chamber (cluster not attached to the track)
+    kTrackResPerHalfCh                  = 62, ///< track resolution-X/Y per half chamber
+    kMCSPerHalfCh                       = 64, ///< MCS X/Y-dispersion of extrapolated track per half chamber
+    
+    kLocalChi2PerCh                     = 100, ///< local chi2-X/Y/total distribution per chamber
+    kLocalChi2PerDE                     = 103, ///< local chi2-X/Y/total distribution per DE
+    kLocalChi2PerChMean                 = 106, ///< local chi2-X/Y/total per chamber: mean
+    kLocalChi2PerDEMean                 = 109, ///< local chi2-X/Y/total per DE: mean
+    
+    kResidualPerChMean_ClusterIn        = 150, ///< cluster-track residual-X/Y per chamber: mean (cluster in)
+    kResidualPerChMean_ClusterOut       = 152, ///< cluster-track residual-X/Y per chamber: mean (cluster out)
+    kResidualPerChSigma_ClusterIn       = 154, ///< cluster-track residual-X/Y per chamber: sigma (cluster in)
+    kResidualPerChSigma_ClusterOut      = 156, ///< cluster-track residual-X/Y per chamber: sigma (cluster out)
+    kResidualPerChDispersion_ClusterOut = 158, ///< cluster-track residual-X/Y per chamber: dispersion (cluster out)
+    kCombinedResidualPerChSigma         = 160, ///< combined cluster-track residual-X/Y per chamber
+    kCombinedResidualSigmaVsP           = 162, ///< cluster X/Y-resolution per chamber versus momentum
+    kTrackResPerChMean                  = 164, ///< track X/Y-resolution per chamber
+    kMCSPerChMean                       = 166, ///< MCS X/Y-dispersion of extrapolated track per chamber
+    kClusterResPerCh                    = 168, ///< cluster X/Y-resolution per chamber
+    kCalcClusterResPerCh                = 170, ///< calculated cluster X/Y-resolution per chamber
+    kResidualPerDEMean_ClusterIn        = 172, ///< cluster-track residual-X/Y per DE: mean (cluster in)
+    kResidualPerDEMean_ClusterOut       = 174, ///< cluster-track residual-X/Y per DE: mean (cluster out)
+    kCombinedResidualPerDESigma         = 176, ///< combined cluster-track residual-X/Y per DE
+    kClusterResPerDE                    = 178, ///< cluster X/Y-resolution per DE
+    kResidualPerHalfChMean_ClusterIn    = 180, ///< cluster-track residual-X/Y per half chamber: mean (cluster in)
+    kResidualPerHalfChMean_ClusterOut   = 182, ///< cluster-track residual-X/Y per half chamber: mean (cluster out)
+    kCombinedResidualPerHalfChSigma     = 184, ///< combined cluster-track residual-X/Y per half chamber
+    kClusterResPerHalfCh                = 186, ///< cluster X/Y-resolution per half chamber
+    
+    kUncorrPRes                         = 250, ///< muon momentum reconstructed resolution at first cluster vs p
+    kPRes                               = 251, ///< muon momentum reconstructed resolution at vertex vs p
+    kUncorrPtRes                        = 252, ///< muon transverse momentum reconstructed resolution at first cluster vs p
+    kPtRes                              = 253, ///< muon transverse momentum reconstructed resolution at vertex vs p
+    kUncorrSlopeRes                     = 254, ///< muon slope-X/Y reconstructed resolution at first cluster vs p
+    kSlopeRes                           = 256, ///< muon slope-X/Y reconstructed resolution at vertex vs p
+    
+    kResPerCh                           = 300, ///< summary canvas
+    kResPerChVsP                        = 301, ///< summary canvas
+    kResPerDE                           = 302, ///< summary canvas
+    kResPerHalfCh                       = 303  ///< summary canvas
+  };
+  
+  static const Int_t fgkMinEntries; ///< minimum number of entries needed to compute resolution
+  
+  TObjArray*  fResiduals;    //!< List of residual histos
+  TObjArray*  fResidualsVsP; //!< List of residual vs. p histos
+  TObjArray*  fLocalChi2;    //!< List of plots related to local chi2 per chamber/DE
+  TObjArray*  fChamberRes;   //!< List of plots related to chamber/DE resolution
+  TObjArray*  fTrackRes;     //!< List of plots related to track resolution (p, pT, ...)
+  TObjArray*  fCanvases;     //!< List of canvases summarizing te results
+  
+  Double_t fClusterResNB[10]; ///< cluster resolution in non-bending direction
+  Double_t fClusterResB[10];  ///< cluster resolution in bending direction
+  
+  Int_t    fNEvents;               //!< number of processed events
+  Double_t fMinMomentum;           ///< use only tracks with momentum higher than this value
+  Bool_t   fSelectPhysics;         ///< use only tracks passing the physics selection
+  Bool_t   fMatchTrig;             ///< use only tracks matched with trigger
+  /// extrapolation mode to get the track parameters and covariances at a given cluster:
+  /// 0 = extrapolate from the closest cluster; 1 = extrapolate from the previous cluster except between stations 2-3-4
+  Int_t    fExtrapMode;
+  Bool_t   fCorrectForSystematics; ///< add or not the systematic shifts of the residuals to the resolution
+  Bool_t   fOCDBLoaded;            //!< flag telling if the OCDB has been properly loaded or not
+  Int_t    fNDE;                   //!< total number of DE
+  Int_t    fDEIndices[1100];       //!< index of DE in histograms refered by ID
+  Int_t    fDEIds[200];            //!< ID of DE refered by index in histograms
+  Bool_t   fReAlign;               ///< flag telling wether to re-align the spectrometer or not before computing resolution
+  TString  fOldAlignStorage;       ///< location of the OCDB storage where to find old MUON/Align/Data (use the default one if empty)
+  TString  fNewAlignStorage;       ///< location of the OCDB storage where to find new MUON/Align/Data (use the default one if empty)
+  AliMUONGeometryTransformer* fOldGeoTransformer; //!< geometry transformer used to recontruct the present data
+  AliMUONGeometryTransformer* fNewGeoTransformer; //!< new geometry transformer containing the new alignment to be applied
+  
+  ClassDef(AliAnalysisTaskMuonResolution, 1); // chamber resolution analysis
+};
+
+//________________________________________________________________________
+inline void AliAnalysisTaskMuonResolution::SetStartingResolution(Int_t chId, Double_t valNB, Double_t valB)
+{
+  /// set chamber non-bending and bending resolutions
+  if (chId < 0 || chId >= AliMUONConstants::NTrackingCh()) return;
+  fClusterResNB[chId] = valNB;
+  fClusterResB[chId] = valB;
+}
+
+//________________________________________________________________________
+inline void AliAnalysisTaskMuonResolution::SetStartingResolution(Double_t valNB[10], Double_t valB[10])
+{
+  /// set chambers non-bending and bending resolutions
+  for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
+    fClusterResNB[i] = valNB[i];
+    fClusterResB[i] = valB[i];
+  }
+}
+
+//________________________________________________________________________
+inline void AliAnalysisTaskMuonResolution::GetStartingResolution(Double_t valNB[10], Double_t valB[10])
+{
+  /// set chambers non-bending and bending resolutions
+  for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
+    valNB[i] = fClusterResNB[i];
+    valB[i] = fClusterResB[i];
+  }
+}
+
+//________________________________________________________________________
+inline void AliAnalysisTaskMuonResolution::ReAlign(const char* oldAlignStorage, const char* newAlignStorage)
+{
+  /// Set the flag to activate the re-alignment and the specific storage where to find the old/new alignment data.
+  /// If oldAlignStorage = 0x0 we assume the spectrometer was not aligned before (default geometry)
+  /// If old(new)AlignStorage = "" we assume the old(new) alignment data are in the default storage
+  if (oldAlignStorage) fOldAlignStorage = oldAlignStorage;
+  else fOldAlignStorage = "none";
+  fNewAlignStorage = newAlignStorage;
+  fReAlign = kTRUE;
+}
+
+#endif
+
diff --git a/PWG3/muondep/RunMuonResolution.C b/PWG3/muondep/RunMuonResolution.C
new file mode 100644 (file)
index 0000000..336b8b5
--- /dev/null
@@ -0,0 +1,404 @@
+//--------------------------------------------------------------------------
+// Base macro for submitting muon Resolution analysis.
+//
+// In case it is not run with full aliroot, it needs the following libraries:
+//  - libSTEERBase.so
+//  - libESD.so
+//  - libAOD.so
+//  - libANALYSIS.so
+//  - libANALYSISalice.so
+//  - libGui.so
+//  - libMinuit.so
+//  - libProofPlayer.so
+//  - libXMLParser.so
+//  - libRAWDatabase.so
+//  - libCDB.so
+//  - libSTEER.so
+//  - libMUONcore.so
+//  - libMUONmapping.so
+//  - libMUONcalib.so
+//  - libMUONgeometry.so
+//  - libMUONtrigger.so
+//  - libMUONraw.so
+//  - libMUONbase.so
+//  - libMUONrec.so
+//  - libCORRFW.so
+//  - libPWG3muondep.so
+//
+// The macro reads ESDs and store outputs in standard output file (AnalysisResults.root)
+// It also needs to load magnetic field, mapping, geometry (+alignment), and recoonstruction parameters from the OCDB
+//
+// Author: Philippe Pillot - SUBATECH Nantes
+//--------------------------------------------------------------------------
+
+TString aliroot="VO_ALICE@AliRoot::v4-19-15-AN";
+
+enum {kLocal, kInteractif_xml, kInteractif_ESDList, kProof};
+
+// global declaration needed in Proof mode, certainly because of the interpretor
+TStopwatch* localTimer;
+TMultiGraph* mgClusterResXVsStep;
+TMultiGraph* mgClusterResYVsStep;
+Double_t clusterResNB[10];
+Double_t clusterResB[10];
+Double_t clusterResNBErr[10];
+Double_t clusterResBErr[10];
+
+void RunMuonResolution(TString smode = "local", TString inputFileName = "AliESDs.root", Int_t nSteps = 10,
+                      Bool_t selectPhysics = kFALSE, Bool_t matchTrig = kFALSE, Double_t minMomentum = 0.,
+                      Bool_t correctForSystematics = kTRUE, Int_t extrapMode = 1)
+{
+  /// Compute the cluster resolution by studying cluster-track residual, deconvoluting from track resolution
+  /// if extrapMode == 0: extrapolate from the closest cluster
+  /// if extrapMode == 1: extrapolate from the previous cluster except between stations 2-3-4
+  /// if correctForSystematics == kTRUE: the systematic shifts of the residuals is included in the resolution
+  
+  // timer start...
+  localTimer = new TStopwatch;
+  
+  // check parameters
+  nSteps = TMath::Max(nSteps,1);
+  if (extrapMode != 0 && extrapMode != 1) {
+    Error("RunMuonResolution","incorrect extrapolation mode!");
+    return;
+  }
+  
+  // Check runing mode
+  Int_t mode = GetMode(smode, inputFileName);
+  if(mode < 0){
+    Error("RunMuonResolution","Please provide either an ESD root file a collection of ESDs or a dataset.");
+    return;
+  }
+  
+  gSystem->Load("libVMC");
+  gSystem->Load("libSTEERBase");
+  gSystem->Load("libESD");
+  gSystem->Load("libAOD");
+  gSystem->Load("libANALYSIS");
+  gSystem->Load("libANALYSISalice");
+  
+  // Load additional libraries
+  gSystem->Load("libProofPlayer");
+  TString extraLibs="Physics:Minuit:XMLParser:Gui:RAWDatabase:CDB:STEER:MUONcore:MUONmapping:MUONcalib:MUONgeometry:MUONtrigger:MUONraw:MUONbase:MUONrec:CORRFW:PWG3muondep";
+  TObjArray* libs = extraLibs.Tokenize(":");
+  for (Int_t i = 0; i < libs->GetEntriesFast(); i++)
+    gSystem->Load(Form("lib%s",static_cast<TObjString*>(libs->UncheckedAt(i))->GetName()));
+  
+  // check for old output file to removed
+  char remove = '';
+  if (!gSystem->Exec("ls chamberResolution_step*[0-9].root")) {
+    cout<<"above files must be removed from the current directory. Delete? [y=yes, n=no] "<<flush;
+    while (remove != 'y' && remove != 'n') cin>>remove;
+    if (remove == 'y') gSystem->Exec("rm -f chamberResolution_step*[0-9].root");
+    else {
+      Error("RunMuonResolution","cannot proceed with these files there otherwise results will be mixed up!");
+      return;
+    }
+  }
+  
+  // OCDB access
+  if(mode == kLocal) AliCDBManager::Instance()->SetDefaultStorage("local://$ALICE_ROOT/OCDB");
+  else if (mode != kProof) {
+    if (!TGrid::Connect("alien://")) return;
+    if(mode == kInteractif_ESDList || !gSystem->AccessPathName("ConfigureCuts.C"))
+      AliCDBManager::Instance()->SetDefaultStorage("raw://");
+  }
+  
+  // Create input object
+  TObject* inputObj = 0x0;
+  if (mode == kProof) inputObj = new TObjString(inputFileName);
+  else inputObj = CreateChain(mode, inputFileName);
+  if (!inputObj) return;
+  
+  // set starting chamber resolution (if -1 they will be loaded from recoParam in the task)
+  for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
+    clusterResNB[i] = -1.;
+    clusterResB[i] = -1.;
+    clusterResNBErr[i] = 0.;
+    clusterResBErr[i] = 0.;
+  }
+  
+  // output graphs
+  mgClusterResXVsStep = new TMultiGraph("mgClusterResXVsStep","cluster X-resolution versus step;step;#sigma_{X} (cm)");
+  mgClusterResYVsStep = new TMultiGraph("mgClusterResYVsStep","cluster Y-resolution versus step;step;#sigma_{Y} (cm)");
+  TGraphErrors* gClusterResXVsStep[10];
+  TGraphErrors* gClusterResYVsStep[10];
+  for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
+    gClusterResXVsStep[i] = new TGraphErrors(nSteps+1);
+    gClusterResXVsStep[i]->SetName(Form("gResX_ch%d",i+1));
+    gClusterResXVsStep[i]->SetMarkerStyle(kFullDotMedium);
+    gClusterResXVsStep[i]->SetMarkerColor(i+1+i/9);
+    mgClusterResXVsStep->Add(gClusterResXVsStep[i],"lp");
+    
+    gClusterResYVsStep[i] = new TGraphErrors(nSteps+1);
+    gClusterResYVsStep[i]->SetName(Form("gResY_ch%d",i+1));
+    gClusterResYVsStep[i]->SetMarkerStyle(kFullDotMedium);
+    gClusterResYVsStep[i]->SetMarkerColor(i+1+i/9);
+    mgClusterResYVsStep->Add(gClusterResYVsStep[i],"lp");
+  }
+  
+  // loop over step
+  for (Int_t iStep = 0; iStep < nSteps; iStep++) {
+    cout<<"step "<<iStep+1<<"/"<<nSteps<<endl;
+    
+    // Connect to proof if needed and prepare environment
+    if (mode == kProof) {
+      
+      // set general environment and close previous session
+      if (iStep == 0) {
+       gEnv->SetValue("XSec.GSI.DelegProxy","2");
+       TProof::AddEnvVar("ALIROOT_EXTRA_LIBS", extraLibs.Data());
+      } else gProof->Close("s");
+      
+      // connect
+      if (gSystem->Getenv("alien_API_USER") == NULL) TProof::Open("alice-caf.cern.ch","workers=20");
+      else TProof::Open(Form("%s@alice-caf.cern.ch",gSystem->Getenv("alien_API_USER")),"workers=20");
+      if (!gProof) return;
+      
+      // set environment and compile task on workers
+      gProof->EnablePackage(aliroot.Data());
+      
+      // prepare OCDB access on workers
+      gProof->Exec("AliCDBManager::Instance()->SetDefaultStorage(\"raw://\")");
+      
+    }
+    
+    // run one step
+    run(mode, iStep, inputObj, extrapMode, correctForSystematics, minMomentum, matchTrig, selectPhysics, clusterResNB, clusterResB);
+    
+    // fill graph with starting resolutions from the task at first step
+    if (iStep == 0) for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
+      gClusterResXVsStep[i]->SetPoint(0, 0, clusterResNB[i]);
+      gClusterResXVsStep[i]->SetPointError(0, 0., clusterResNBErr[i]);
+      gClusterResYVsStep[i]->SetPoint(0, 0, clusterResB[i]);
+      gClusterResYVsStep[i]->SetPointError(0, 0., clusterResBErr[i]);
+    }
+    
+    // read the chamber resolution from the output file
+    if (!GetChamberResolution(iStep, clusterResNB, clusterResB, clusterResNBErr, clusterResBErr)) return;
+    
+    // fill graphs with computed resolutions
+    for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
+      gClusterResXVsStep[i]->SetPoint(iStep+1, iStep+1, clusterResNB[i]);
+      gClusterResXVsStep[i]->SetPointError(iStep+1, 0., clusterResNBErr[i]);
+      gClusterResYVsStep[i]->SetPoint(iStep+1, iStep+1, clusterResB[i]);
+      gClusterResYVsStep[i]->SetPointError(iStep+1, 0., clusterResBErr[i]);
+    }
+    
+  }
+  
+  // copy final results in results.root file
+  gSystem->Exec(Form("cp chamberResolution_step%d.root results.root", nSteps-1));
+  
+  // display convergence
+  TCanvas* convergence = new TCanvas("convergence","convergence");
+  convergence->Divide(1,2);
+  convergence->cd(1);
+  mgClusterResXVsStep->Draw("ap");
+  convergence->cd(2);
+  mgClusterResYVsStep->Draw("ap");
+  
+  // save convergence plots
+  TFile* outFile = TFile::Open("results.root","UPDATE");
+  if (!outFile || !outFile->IsOpen()) return;
+  outFile->cd();
+  mgClusterResXVsStep->Write();
+  mgClusterResYVsStep->Write();
+  convergence->Write();
+  outFile->Close();
+  
+  // print results
+  printf("\nchamber resolution:\n");
+  printf(" - non-bending:");
+  for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) printf((i==0)?" %5.3f":", %5.3f",clusterResNB[i]);
+  printf("\n -     bending:");
+  for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) printf((i==0)?" %6.4f":", %6.4f",clusterResB[i]);
+  printf("\n\n");
+  
+  // ...timer stop
+  localTimer->Stop();
+  localTimer->Print();
+  
+}
+
+//______________________________________________________________________________
+void run(Int_t mode, Int_t iStep, TObject* input, Int_t extrapMode, Bool_t correctForSystematics,
+        Double_t minMomentum, Bool_t matchTrig, Bool_t selectPhysics, Double_t clusterResNB[10], Double_t clusterResB[10])
+{
+  /// launch the analysis with these parameters
+  
+  // Create the analysis manager
+  AliAnalysisManager *mgr = new AliAnalysisManager("MuonResolutionAnalysis");
+  
+  // ESD input handler
+  AliESDInputHandler* esdH = new AliESDInputHandler();
+  esdH->SetReadFriends(kFALSE);
+  mgr->SetInputEventHandler(esdH);
+  
+  // event selection
+  if (selectPhysics) {
+    gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/AddTaskPhysicsSelection.C");
+    AliPhysicsSelectionTask* physicsSelection = AddTaskPhysicsSelection();
+    if(!physicsSelection) {
+      Error("RunMuonResolution","AliPhysicsSelectionTask not created!");
+      return;
+    }
+    physicsSelection->GetPhysicsSelection()->SetUseMuonTriggers();
+  }
+  
+  // Muon Resolution analysis
+  gROOT->LoadMacro("$ALICE_ROOT/PWG3/muondep/AddTaskMuonResolution.C");
+  AliAnalysisManager::SetCommonFileName(Form("chamberResolution_step%d.root", iStep));
+  AliAnalysisTaskMuonResolution* muonResolution = AddTaskMuonResolution(selectPhysics, matchTrig, minMomentum, correctForSystematics, extrapMode);
+  if(!muonResolution) {
+    Error("RunMuonResolution","AliAnalysisTaskMuonResolution not created!");
+    return;
+  }
+  muonResolution->SetStartingResolution(clusterResNB, clusterResB);
+  
+  // Enable debug printouts
+  //mgr->SetDebugLevel(2);
+  
+  // start local analysis
+  if (mgr->InitAnalysis()) {
+    mgr->PrintStatus();
+    if (mode == kProof) mgr->StartAnalysis("proof", Form("%s",static_cast<TObjString*>(input)->GetName()));
+    else mgr->StartAnalysis("local", static_cast<TChain*>(input));
+  }
+  
+  // save the summary canvases
+  if (muonResolution->GetCanvases()) {
+    TFile* outFile = TFile::Open(Form("chamberResolution_step%d.root", iStep),"UPDATE");
+    if (outFile && outFile->IsOpen()) {
+      muonResolution->GetCanvases()->Write();
+      outFile->Close();
+    }
+  }
+  
+  // return starting chamber resolution from the task
+  muonResolution->GetStartingResolution(clusterResNB, clusterResB);
+  
+  // clean memory
+  delete mgr;
+  TObject::SetObjectStat(kFALSE);
+}
+
+//______________________________________________________________________________
+Bool_t GetChamberResolution(Int_t iStep, Double_t clusterResNB[10], Double_t clusterResB[10], Double_t clusterResNBErr[10], Double_t clusterResBErr[10])
+{
+  /// read the chamber resolution from the output file
+  
+  TFile* outFile = TFile::Open(Form("chamberResolution_step%d.root", iStep),"READ");
+  
+  if (!outFile || !outFile->IsOpen()) {
+    Error("GetChamberResolution","output file does not exist!");
+    return kFALSE;
+  }
+  
+  TObjArray* summary = static_cast<TObjArray*>(outFile->FindObjectAny("ChamberRes"));
+  TGraphErrors* gCombinedResidualXPerChSigma = (summary) ? static_cast<TGraphErrors*>(summary->FindObject("gCombinedResidualXPerChSigma")) : 0x0;
+  TGraphErrors* gCombinedResidualYPerChSigma = (summary) ? static_cast<TGraphErrors*>(summary->FindObject("gCombinedResidualYPerChSigma")) : 0x0;
+  
+  if (!gCombinedResidualXPerChSigma || !gCombinedResidualYPerChSigma) {
+    Error("GetChamberResolution","resolution graphs do not exist!");
+    return kFALSE;
+  }
+  
+  Double_t dummy;
+  for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
+    gCombinedResidualXPerChSigma->GetPoint(i, dummy, clusterResNB[i]);
+    gCombinedResidualYPerChSigma->GetPoint(i, dummy, clusterResB[i]);
+    clusterResNBErr[i] = gCombinedResidualXPerChSigma->GetErrorY(i);
+    clusterResBErr[i] = gCombinedResidualYPerChSigma->GetErrorY(i);
+  }
+  
+  outFile->Close();
+  
+  return kTRUE;
+}
+
+//______________________________________________________________________________
+Int_t GetMode(TString smode, TString input)
+{
+  if (smode == "local") {
+    if ( input.EndsWith(".xml") ) return kInteractif_xml;
+    else if ( input.EndsWith(".txt") ) return kInteractif_ESDList;
+    else if ( input.EndsWith(".root") ) return kLocal;    
+  } else if (smode == "proof") return kProof;
+  return -1;
+}
+
+//______________________________________________________________________________
+TChain* CreateChainFromCollection(const char *xmlfile)
+{
+  // Create a chain from the collection of tags.
+  TAlienCollection* coll = TAlienCollection::Open(xmlfile);
+  if (!coll) {
+    Error("CreateChainFromCollection", Form("Cannot create an AliEn collection from %s!", xmlfile));
+    return NULL;
+  }
+  
+  TGridResult* tagResult = coll->GetGridResult("",kFALSE,kFALSE);
+  AliTagAnalysis *tagAna = new AliTagAnalysis("ESD");
+  tagAna->ChainGridTags(tagResult);
+  
+  AliRunTagCuts      *runCuts = new AliRunTagCuts();
+  AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();
+  AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();
+  AliEventTagCuts    *evCuts  = new AliEventTagCuts();
+  
+  // Check if the cuts configuration file was provided
+  if (!gSystem->AccessPathName("ConfigureCuts.C")) {
+    gROOT->LoadMacro("ConfigureCuts.C");
+    ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);
+  }
+  
+  TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);
+  if (!chain || !chain->GetNtrees()) return NULL;
+  chain->ls();
+  return chain;
+}
+
+//______________________________________________________________________________
+TChain* CreateChainFromFile(const char *rootfile)
+{
+  // Create a chain using the root file.
+  TChain* chain = new TChain("esdTree");
+  chain->Add(rootfile);
+  if (!chain->GetNtrees()) return NULL;
+  chain->ls();
+  return chain;
+}
+
+//______________________________________________________________________________
+TChain* CreateChainFromESDList(const char *esdList)
+{
+  // Create a chain using tags from the run list.
+  TChain* chain = new TChain("esdTree");
+  ifstream inFile(esdList);
+  TString inFileName;
+  if (inFile.is_open()) {
+    while (! inFile.eof() ) {
+      inFileName.ReadLine(inFile,kFALSE);
+      if(!inFileName.EndsWith(".root")) continue;
+      chain->Add(inFileName.Data());
+    }
+  }
+  inFile.close();
+  if (!chain->GetNtrees()) return NULL;
+  chain->ls();
+  return chain;
+}
+
+//______________________________________________________________________________
+TChain* CreateChain(Int_t mode, TString input)
+{
+  printf("*******************************\n");
+  printf("*** Getting the Chain       ***\n");
+  printf("*******************************\n");
+  if(mode == kInteractif_xml) return CreateChainFromCollection(input.Data());
+  else if (mode == kInteractif_ESDList) return CreateChainFromESDList(input.Data());
+  else if (mode == kLocal) return CreateChainFromFile(input.Data());
+  else return NULL;
+}
+