]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWG3/muondep/AliAnalysisTaskMuonResolution.cxx
Fixing violations to the coding convention rules of ALICE (Philipe P.)
[u/mrichter/AliRoot.git] / PWG3 / muondep / AliAnalysisTaskMuonResolution.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 // ROOT includes
17 #include <TFile.h>
18 #include <TTree.h>
19 #include <TH1F.h>
20 #include <TH2F.h>
21 #include <TMultiGraph.h>
22 #include <TGraphErrors.h>
23 #include <TCanvas.h>
24 #include <TLegend.h>
25 #include <Riostream.h>
26 #include <TString.h>
27 #include <TGeoManager.h>
28 #include <TList.h>
29 #include <TObjString.h>
30 #include <TRegexp.h>
31
32 // STEER includes
33 #include "AliESDEvent.h"
34 #include "AliESDMuonTrack.h"
35 #include "AliCDBManager.h"
36 #include "AliCDBStorage.h"
37 #include "AliGeomManager.h"
38
39 // ANALYSIS includes
40 #include "AliAnalysisDataSlot.h"
41 #include "AliAnalysisManager.h"
42 #include "AliInputEventHandler.h"
43 #include "AliAnalysisTaskMuonResolution.h"
44
45 // MUON includes
46 #include "AliMUONCDB.h"
47 #include "AliMUONRecoParam.h"
48 #include "AliMUONESDInterface.h"
49 #include "AliMUONVTrackReconstructor.h"
50 #include "AliMUONTrack.h"
51 #include "AliMUONTrackParam.h"
52 #include "AliMUONTrackExtrap.h"
53 #include "AliMUONVCluster.h"
54 #include "AliMUONGeometryTransformer.h"
55 #include "AliMUONGeometryModuleTransformer.h"
56 #include "AliMUONGeometryDetElement.h"
57 #include "AliMpDEIterator.h"
58
59 #ifndef SafeDelete
60 #define SafeDelete(x) if (x != NULL) { delete x; x = NULL; }
61 #endif
62
63 ClassImp(AliAnalysisTaskMuonResolution)
64
65 const Int_t AliAnalysisTaskMuonResolution::fgkMinEntries = 10;
66
67 //________________________________________________________________________
68 AliAnalysisTaskMuonResolution::AliAnalysisTaskMuonResolution() :
69   AliAnalysisTaskSE(), 
70   fResiduals(NULL),
71   fResidualsVsP(NULL),
72   fLocalChi2(NULL),
73   fChamberRes(NULL),
74   fTrackRes(NULL),
75   fCanvases(NULL),
76   fDefaultStorage(""),
77   fNEvents(0),
78   fShowProgressBar(kFALSE),
79   fPrintClResPerCh(kFALSE),
80   fPrintClResPerDE(kFALSE),
81   fGaus(NULL),
82   fMinMomentum(0.),
83   fSelectPhysics(kFALSE),
84   fMatchTrig(kFALSE),
85   fApplyAccCut(kFALSE),
86   fSelectTrigger(kFALSE),
87   fTriggerMask(0),
88   fExtrapMode(1),
89   fCorrectForSystematics(kTRUE),
90   fOCDBLoaded(kFALSE),
91   fNDE(0),
92   fReAlign(kFALSE),
93   fOldAlignStorage(""),
94   fNewAlignStorage(""),
95   fOldGeoTransformer(NULL),
96   fNewGeoTransformer(NULL),
97   fSelectTriggerClass(NULL)
98 {
99   /// Default constructor
100 }
101
102 //________________________________________________________________________
103 AliAnalysisTaskMuonResolution::AliAnalysisTaskMuonResolution(const char *name) :
104   AliAnalysisTaskSE(name), 
105   fResiduals(NULL),
106   fResidualsVsP(NULL),
107   fLocalChi2(NULL),
108   fChamberRes(NULL),
109   fTrackRes(NULL),
110   fCanvases(NULL),
111   fDefaultStorage("raw://"),
112   fNEvents(0),
113   fShowProgressBar(kFALSE),
114   fPrintClResPerCh(kFALSE),
115   fPrintClResPerDE(kFALSE),
116   fGaus(NULL),
117   fMinMomentum(0.),
118   fSelectPhysics(kFALSE),
119   fMatchTrig(kFALSE),
120   fApplyAccCut(kFALSE),
121   fSelectTrigger(kFALSE),
122   fTriggerMask(0),
123   fExtrapMode(1),
124   fCorrectForSystematics(kTRUE),
125   fOCDBLoaded(kFALSE),
126   fNDE(0),
127   fReAlign(kFALSE),
128   fOldAlignStorage(""),
129   fNewAlignStorage(""),
130   fOldGeoTransformer(NULL),
131   fNewGeoTransformer(NULL),
132   fSelectTriggerClass(NULL)
133 {
134   /// Constructor
135   
136   for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) SetStartingResolution(i, -1., -1.);
137   
138   FitResiduals();
139   
140   // Output slot #1 writes into a TObjArray container
141   DefineOutput(1,TObjArray::Class());
142   // Output slot #2 writes into a TObjArray container
143   DefineOutput(2,TObjArray::Class());
144   // Output slot #3 writes into a TObjArray container
145   DefineOutput(3,TObjArray::Class());
146   // Output slot #4 writes into a TObjArray container
147   DefineOutput(4,TObjArray::Class());
148   // Output slot #5 writes into a TObjArray container
149   DefineOutput(5,TObjArray::Class());
150 }
151
152 //________________________________________________________________________
153 AliAnalysisTaskMuonResolution::~AliAnalysisTaskMuonResolution()
154 {
155   /// Destructor
156   if (!AliAnalysisManager::GetAnalysisManager()->IsProofMode()) {
157     SafeDelete(fResiduals);
158     SafeDelete(fResidualsVsP);
159     SafeDelete(fTrackRes);
160   }
161   SafeDelete(fChamberRes);
162   SafeDelete(fCanvases);
163   SafeDelete(fGaus);
164   SafeDelete(fOldGeoTransformer);
165   SafeDelete(fNewGeoTransformer);
166   SafeDelete(fSelectTriggerClass);
167 }
168
169 //___________________________________________________________________________
170 void AliAnalysisTaskMuonResolution::UserCreateOutputObjects()
171 {
172   /// Create histograms
173   
174   // do it once the OCDB has been loaded (i.e. from NotifyRun())
175   if (!fOCDBLoaded) return;
176   
177   // set the list of trigger classes that can be selected to fill histograms (in case the physics selection is not used)
178   fSelectTriggerClass = new TList();
179   fSelectTriggerClass->SetOwner();
180   fSelectTriggerClass->AddLast(new TObjString(" CINT1B-ABCE-NOPF-ALL ")); fSelectTriggerClass->Last()->SetUniqueID(AliVEvent::kMB);
181   fSelectTriggerClass->AddLast(new TObjString(" CMUS1B-ABCE-NOPF-MUON ")); fSelectTriggerClass->Last()->SetUniqueID(AliVEvent::kMUON);
182   fSelectTriggerClass->AddLast(new TObjString(" CINT1-B-")); fSelectTriggerClass->Last()->SetUniqueID(AliVEvent::kMB);
183   fSelectTriggerClass->AddLast(new TObjString(" CMUS1-B-")); fSelectTriggerClass->Last()->SetUniqueID(AliVEvent::kMUON);
184   fSelectTriggerClass->AddLast(new TObjString(" CSH1-B-")); fSelectTriggerClass->Last()->SetUniqueID(AliVEvent::kHighMult);
185   
186   fResiduals = new TObjArray(1000);
187   fResiduals->SetOwner();
188   fResidualsVsP = new TObjArray(1000);
189   fResidualsVsP->SetOwner();
190   fTrackRes = new TObjArray(1000);
191   fTrackRes->SetOwner();
192   TH2F* h2;
193   
194   // find the highest chamber resolution and set histogram bins
195   const AliMUONRecoParam* recoParam = AliMUONESDInterface::GetTracker()->GetRecoParam();
196   Double_t maxSigma[2] = {-1., -1.};
197   for (Int_t i = 0; i < 10; i++) {
198     if (recoParam->GetDefaultNonBendingReso(i) > maxSigma[0]) maxSigma[0] = recoParam->GetDefaultNonBendingReso(i);
199     if (recoParam->GetDefaultBendingReso(i) > maxSigma[1]) maxSigma[1] = recoParam->GetDefaultBendingReso(i);
200   }
201   const char* axes[2] = {"X", "Y"};
202   const Int_t nBins = 5000;
203   const Int_t nSigma = 10;
204   const Int_t pNBins = 20;
205   const Double_t pEdges[2] = {0., 50.};
206   
207   for (Int_t ia = 0; ia < 2; ia++) {
208     
209     Double_t maxRes = nSigma*maxSigma[ia];
210     
211     // List of residual histos
212     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);
213     fResiduals->AddAtAndExpand(h2, kResidualPerChClusterIn+ia);
214     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);
215     fResiduals->AddAtAndExpand(h2, kResidualPerChClusterOut+ia);
216     
217     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);
218     fResiduals->AddAtAndExpand(h2, kResidualPerHalfChClusterIn+ia);
219     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);
220     fResiduals->AddAtAndExpand(h2, kResidualPerHalfChClusterOut+ia);
221     
222     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);
223     for (Int_t i = 1; i <= fNDE; i++) h2->GetXaxis()->SetBinLabel(i, Form("%d",fDEIds[i]));
224     fResiduals->AddAtAndExpand(h2, kResidualPerDEClusterIn+ia);
225     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);
226     for (Int_t i = 1; i <= fNDE; i++) h2->GetXaxis()->SetBinLabel(i, Form("%d",fDEIds[i]));
227     fResiduals->AddAtAndExpand(h2, kResidualPerDEClusterOut+ia);
228     
229     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);
230     fResiduals->AddAtAndExpand(h2, kTrackResPerCh+ia);
231     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);
232     fResiduals->AddAtAndExpand(h2, kTrackResPerHalfCh+ia);
233     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);
234     for (Int_t i = 1; i <= fNDE; i++) h2->GetXaxis()->SetBinLabel(i, Form("%d",fDEIds[i]));
235     fResiduals->AddAtAndExpand(h2, kTrackResPerDE+ia);
236     
237     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);
238     fResiduals->AddAtAndExpand(h2, kMCSPerCh+ia);
239     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);
240     fResiduals->AddAtAndExpand(h2, kMCSPerHalfCh+ia);
241     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);
242     for (Int_t i = 1; i <= fNDE; i++) h2->GetXaxis()->SetBinLabel(i, Form("%d",fDEIds[i]));
243     fResiduals->AddAtAndExpand(h2, kMCSPerDE+ia);
244     
245     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);
246     fResiduals->AddAtAndExpand(h2, kClusterRes2PerCh+ia);
247     
248     // List of residual vs. p histos
249     for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
250       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);
251       fResidualsVsP->AddAtAndExpand(h2, kResidualInChVsPClusterIn+10*ia+i);
252       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);
253       fResidualsVsP->AddAtAndExpand(h2, kResidualInChVsPClusterOut+10*ia+i);
254     }
255     
256     // local chi2
257     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.);
258     fResiduals->AddAtAndExpand(h2, kLocalChi2PerCh+ia);
259     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.);
260     for (Int_t i = 1; i <= fNDE; i++) h2->GetXaxis()->SetBinLabel(i, Form("%d",fDEIds[i]));
261     fResiduals->AddAtAndExpand(h2, kLocalChi2PerDE+ia);
262     
263     // track resolution
264     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);
265     fTrackRes->AddAtAndExpand(h2, kUncorrSlopeRes+ia);
266     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);
267     fTrackRes->AddAtAndExpand(h2, kSlopeRes+ia);
268   }
269   
270   // local chi2 X+Y
271   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.);
272   fResiduals->AddAtAndExpand(h2, kLocalChi2PerCh+2);
273   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.);
274   for (Int_t i = 1; i <= fNDE; i++) h2->GetXaxis()->SetBinLabel(i, Form("%d",fDEIds[i]));
275   fResiduals->AddAtAndExpand(h2, kLocalChi2PerDE+2);
276   
277   // track resolution
278   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.);
279   fTrackRes->AddAtAndExpand(h2, kUncorrPRes);
280   h2 = new TH2F("hPRes", "muon momentum reconstructed resolution at vertex vs p;p (GeV/c); #sigma_{p}/p (%)", 300, 0., 300., 1000, 0., 10.);
281   fTrackRes->AddAtAndExpand(h2, kPRes);
282   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.);
283   fTrackRes->AddAtAndExpand(h2, kUncorrPtRes);
284   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.);
285   fTrackRes->AddAtAndExpand(h2, kPtRes);
286   
287   // Post data at least once per task to ensure data synchronisation (required for merging)
288   PostData(1, fResiduals);
289   PostData(2, fResidualsVsP);
290   PostData(5, fTrackRes);
291 }
292
293 //________________________________________________________________________
294 void AliAnalysisTaskMuonResolution::UserExec(Option_t *)
295 {
296   /// Main event loop
297   
298   // check if OCDB properly loaded
299   if (!fOCDBLoaded) return;
300   
301   AliESDEvent* esd = dynamic_cast<AliESDEvent*>(InputEvent());
302   if (!esd) return;
303   
304   if (fShowProgressBar && (++fNEvents)%100 == 0) cout<<"\rEvent processing... "<<fNEvents<<"\r"<<flush;
305   
306   // skip events that do not pass the physics selection if required
307   UInt_t triggerWord = (fInputHandler) ? fInputHandler->IsEventSelected() : 0;
308   if (fSelectPhysics && triggerWord == 0) return;
309   
310   // skip events that do not pass the trigger selection if required
311   TString firedTriggerClasses = esd->GetFiredTriggerClasses();
312   if (!fSelectPhysics) triggerWord = BuildTriggerWord(firedTriggerClasses);
313   if (fSelectTrigger && (triggerWord & fTriggerMask) == 0) return;
314   
315   // get tracker to refit
316   AliMUONVTrackReconstructor* tracker = AliMUONESDInterface::GetTracker();
317   
318   // loop over tracks
319   Int_t nTracks = (Int_t) esd->GetNumberOfMuonTracks(); 
320   for (Int_t iTrack = 0; iTrack < nTracks; ++iTrack) {
321     
322     // get the ESD track
323     AliESDMuonTrack* esdTrack = esd->GetMuonTrack(iTrack);
324     
325     // skip ghost tracks
326     if (!esdTrack->ContainTrackerData()) continue;
327     
328     // skip tracks not matched with trigger if required
329     if (fMatchTrig && !esdTrack->ContainTriggerData()) continue;
330     
331     // skip tracks that do not pass the acceptance cuts if required
332     Double_t thetaAbs = TMath::ATan(esdTrack->GetRAtAbsorberEnd()/505.) * TMath::RadToDeg();
333     Double_t eta = esdTrack->Eta();
334     if (fApplyAccCut && (thetaAbs < 2. || thetaAbs > 9. || eta < -4. || eta > -2.5)) continue;
335     
336     // skip low momentum tracks
337     if (esdTrack->PUncorrected() < fMinMomentum) continue;
338     
339     // get the corresponding MUON track
340     AliMUONTrack track;
341     AliMUONESDInterface::ESDToMUON(*esdTrack, track, kFALSE);
342     
343     // change the cluster resolution (and position)
344     ModifyClusters(track);
345     
346     // refit the track
347     if (!tracker->RefitTrack(track, kFALSE)) break;
348     
349     // save track unchanged
350     AliMUONTrack referenceTrack(track);
351     
352     // get track param at first cluster and add MCS in first chamber
353     AliMUONTrackParam trackParamAtFirstCluster(*(static_cast<AliMUONTrackParam*>(track.GetTrackParamAtCluster()->First())));
354     Int_t firstCh = 0; while (firstCh < 10 && !esdTrack->IsInMuonClusterMap(firstCh)) firstCh++;
355     AliMUONTrackExtrap::AddMCSEffect(&trackParamAtFirstCluster, AliMUONConstants::ChamberThicknessInX0(firstCh)/2., -1.);
356     
357     // fill momentum error at first cluster
358     Double_t pXUncorr = trackParamAtFirstCluster.Px();
359     Double_t pYUncorr = trackParamAtFirstCluster.Py();
360     Double_t pZUncorr = trackParamAtFirstCluster.Pz();
361     Double_t pUncorr = trackParamAtFirstCluster.P();
362     TMatrixD covUncorr(5,5);
363     Cov2CovP(trackParamAtFirstCluster,covUncorr);
364     Double_t sigmaPUncorr = TMath::Sqrt(pXUncorr * (pXUncorr*covUncorr(2,2) + pYUncorr*covUncorr(2,3) + pZUncorr*covUncorr(2,4)) +
365                                         pYUncorr * (pXUncorr*covUncorr(3,2) + pYUncorr*covUncorr(3,3) + pZUncorr*covUncorr(3,4)) +
366                                         pZUncorr * (pXUncorr*covUncorr(4,2) + pYUncorr*covUncorr(4,3) + pZUncorr*covUncorr(4,4))) / pUncorr;
367     ((TH2F*)fTrackRes->UncheckedAt(kUncorrPRes))->Fill(pUncorr,100.*sigmaPUncorr/pUncorr);
368     
369     // fill transverse momentum error at first cluster
370     Double_t ptUncorr = TMath::Sqrt(pXUncorr*pXUncorr + pYUncorr*pYUncorr);
371     Double_t sigmaPtUncorr = TMath::Sqrt(pXUncorr * (pXUncorr*covUncorr(2,2)  + pYUncorr*covUncorr(2,3)) + pYUncorr * (pXUncorr*covUncorr(3,2) + pYUncorr*covUncorr(3,3))) / ptUncorr;
372     ((TH2F*)fTrackRes->UncheckedAt(kUncorrPtRes))->Fill(ptUncorr,100.*sigmaPtUncorr/ptUncorr);
373     
374     // fill slopeX-Y error at first cluster
375     ((TH2F*)fTrackRes->UncheckedAt(kUncorrSlopeRes))->Fill(pUncorr,TMath::Sqrt(trackParamAtFirstCluster.GetCovariances()(1,1)));
376     ((TH2F*)fTrackRes->UncheckedAt(kUncorrSlopeRes+1))->Fill(pUncorr,TMath::Sqrt(trackParamAtFirstCluster.GetCovariances()(3,3)));
377     
378     // fill momentum error at vertex
379     AliMUONTrackParam trackParamAtVtx(trackParamAtFirstCluster);
380     AliMUONTrackExtrap::ExtrapToVertex(&trackParamAtVtx, esdTrack->GetNonBendingCoor(), esdTrack->GetBendingCoor(), esdTrack->GetZ(), 0., 0.);
381     Double_t pXVtx = trackParamAtVtx.Px();
382     Double_t pYVtx = trackParamAtVtx.Py();
383     Double_t pZVtx = trackParamAtVtx.Pz();
384     Double_t pVtx = trackParamAtVtx.P();
385     TMatrixD covVtx(5,5);
386     Cov2CovP(trackParamAtVtx,covVtx);
387     Double_t sigmaPVtx = TMath::Sqrt(pXVtx * (pXVtx*covVtx(2,2) + pYVtx*covVtx(2,3) + pZVtx*covVtx(2,4)) +
388                                      pYVtx * (pXVtx*covVtx(3,2) + pYVtx*covVtx(3,3) + pZVtx*covVtx(3,4)) +
389                                      pZVtx * (pXVtx*covVtx(4,2) + pYVtx*covVtx(4,3) + pZVtx*covVtx(4,4))) / pVtx;
390     ((TH2F*)fTrackRes->UncheckedAt(kPRes))->Fill(pVtx,100.*sigmaPVtx/pVtx);
391     
392     // fill transverse momentum error at vertex
393     Double_t ptVtx = TMath::Sqrt(pXVtx*pXVtx + pYVtx*pYVtx);
394     Double_t sigmaPtVtx = TMath::Sqrt(pXVtx * (pXVtx*covVtx(2,2)  + pYVtx*covVtx(2,3)) + pYVtx * (pXVtx*covVtx(3,2) + pYVtx*covVtx(3,3))) / ptVtx;
395     ((TH2F*)fTrackRes->UncheckedAt(kPtRes))->Fill(ptVtx,100.*sigmaPtVtx/ptVtx);
396     
397     // fill slopeX-Y error at vertex
398     ((TH2F*)fTrackRes->UncheckedAt(kSlopeRes))->Fill(pVtx,TMath::Sqrt(trackParamAtVtx.GetCovariances()(1,1)));
399     ((TH2F*)fTrackRes->UncheckedAt(kSlopeRes+1))->Fill(pVtx,TMath::Sqrt(trackParamAtVtx.GetCovariances()(3,3)));
400     
401     // loop over clusters
402     Int_t nClusters = track.GetNClusters();
403     for (Int_t iCluster=0; iCluster<nClusters; iCluster++) {
404       
405       // Get current, previous and next trackParams
406       AliMUONTrackParam* trackParam = static_cast<AliMUONTrackParam*>(track.GetTrackParamAtCluster()->UncheckedAt(iCluster));
407       AliMUONTrackParam* previousTrackParam = static_cast<AliMUONTrackParam*>(track.GetTrackParamAtCluster()->Before(trackParam));
408       AliMUONTrackParam* nextTrackParam = static_cast<AliMUONTrackParam*>(track.GetTrackParamAtCluster()->After(trackParam));
409       
410       // save current trackParam and remove it from the track
411       AliMUONTrackParam currentTrackParam(*trackParam);
412       track.RemoveTrackParamAtCluster(trackParam);
413       
414       // get cluster info
415       AliMUONVCluster* cluster = currentTrackParam.GetClusterPtr();
416       Int_t chId = cluster->GetChamberId();
417       Int_t halfChId = (cluster->GetX() > 0) ? 2*chId : 2*chId+1;
418       Int_t deId = cluster->GetDetElemId();
419       
420       // compute residuals with cluster still attached to the track
421       AliMUONTrackParam* referenceTrackParam = static_cast<AliMUONTrackParam*>(referenceTrack.GetTrackParamAtCluster()->UncheckedAt(iCluster));
422       Double_t deltaX = cluster->GetX() - referenceTrackParam->GetNonBendingCoor();
423       Double_t deltaY = cluster->GetY() - referenceTrackParam->GetBendingCoor();
424       
425       // compute local chi2
426       Double_t sigmaDeltaX2 = cluster->GetErrX2() - referenceTrackParam->GetCovariances()(0,0);
427       Double_t sigmaDeltaY2 = cluster->GetErrY2() - referenceTrackParam->GetCovariances()(2,2);
428       Double_t localChi2X = (sigmaDeltaX2 > 0.) ? deltaX*deltaX/sigmaDeltaX2 : 0.;
429       Double_t localChi2Y = (sigmaDeltaY2 > 0.) ? deltaY*deltaY/sigmaDeltaY2 : 0.;
430       Double_t localChi2 = 0.5 * referenceTrackParam->GetLocalChi2();
431       
432       // fill local chi2 info at every clusters
433       ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerCh))->Fill(chId+1, localChi2X);
434       ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerCh+1))->Fill(chId+1, localChi2Y);
435       ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerCh+2))->Fill(chId+1, localChi2);
436       ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerDE))->Fill(fDEIndices[deId], localChi2X);
437       ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerDE+1))->Fill(fDEIndices[deId], localChi2Y);
438       ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerDE+2))->Fill(fDEIndices[deId], localChi2);
439       
440       // make sure the track has another cluster in the same station and can still be refitted
441       Bool_t refit = track.IsValid( 1 << (chId/2) );
442       if (refit) {
443         
444         // refit the track and proceed if everything goes fine
445         if (tracker->RefitTrack(track, kFALSE)) {
446           
447           // fill histograms of residuals with cluster still attached to the track
448           ((TH2F*)fResiduals->UncheckedAt(kResidualPerChClusterIn))->Fill(chId+1, deltaX);
449           ((TH2F*)fResiduals->UncheckedAt(kResidualPerChClusterIn+1))->Fill(chId+1, deltaY);
450           ((TH2F*)fResiduals->UncheckedAt(kResidualPerHalfChClusterIn))->Fill(halfChId+1, deltaX);
451           ((TH2F*)fResiduals->UncheckedAt(kResidualPerHalfChClusterIn+1))->Fill(halfChId+1, deltaY);
452           ((TH2F*)fResiduals->UncheckedAt(kResidualPerDEClusterIn))->Fill(fDEIndices[deId], deltaX);
453           ((TH2F*)fResiduals->UncheckedAt(kResidualPerDEClusterIn+1))->Fill(fDEIndices[deId], deltaY);
454           ((TH2F*)fResidualsVsP->UncheckedAt(kResidualInChVsPClusterIn+chId))->Fill(pUncorr, deltaX);
455           ((TH2F*)fResidualsVsP->UncheckedAt(kResidualInChVsPClusterIn+10+chId))->Fill(pUncorr, deltaY);
456           
457           // find the track parameters closest to the current cluster position
458           Double_t dZWithPrevious = (previousTrackParam) ? TMath::Abs(previousTrackParam->GetClusterPtr()->GetZ() - cluster->GetZ()) : FLT_MAX;
459           Int_t previousChId = (previousTrackParam) ? previousTrackParam->GetClusterPtr()->GetChamberId() : -1;
460           Double_t dZWithNext = (nextTrackParam) ? TMath::Abs(nextTrackParam->GetClusterPtr()->GetZ() - cluster->GetZ()) : FLT_MAX;
461           AliMUONTrackParam* startingTrackParam = 0x0;
462           if ((fExtrapMode == 0 && dZWithPrevious < dZWithNext) ||
463               (fExtrapMode == 1 && previousTrackParam && !(chId/2 == 2 && previousChId/2 == 1) &&
464                !(chId/2 == 3 && previousChId/2 == 2))) startingTrackParam = previousTrackParam;
465           else startingTrackParam = nextTrackParam;
466           
467           // reset current parameters
468           currentTrackParam.SetParameters(startingTrackParam->GetParameters());
469           currentTrackParam.SetZ(startingTrackParam->GetZ());
470           currentTrackParam.SetCovariances(startingTrackParam->GetCovariances());
471           currentTrackParam.ResetPropagator();
472           
473           // extrapolate to the current cluster position and fill histograms of residuals if everything goes fine
474           if (AliMUONTrackExtrap::ExtrapToZCov(&currentTrackParam, currentTrackParam.GetClusterPtr()->GetZ(), kTRUE)) {
475             
476             // compute MCS dispersion on the first chamber
477             TMatrixD mcsCov(5,5);
478             if (startingTrackParam == nextTrackParam && chId == 0) {
479               AliMUONTrackParam trackParamForMCS;
480               trackParamForMCS.SetParameters(nextTrackParam->GetParameters());
481               AliMUONTrackExtrap::AddMCSEffect(&trackParamForMCS,AliMUONConstants::ChamberThicknessInX0(nextTrackParam->GetClusterPtr()->GetChamberId()),-1.);
482               const TMatrixD &propagator = currentTrackParam.GetPropagator();
483               TMatrixD tmp(trackParamForMCS.GetCovariances(),TMatrixD::kMultTranspose,propagator);
484               mcsCov.Mult(propagator,tmp);
485             } else mcsCov.Zero();
486             
487             // compute residuals
488             Double_t trackResX2 = currentTrackParam.GetCovariances()(0,0) + mcsCov(0,0);
489             Double_t trackResY2 = currentTrackParam.GetCovariances()(2,2) + mcsCov(2,2);
490             deltaX = cluster->GetX() - currentTrackParam.GetNonBendingCoor();
491             deltaY = cluster->GetY() - currentTrackParam.GetBendingCoor();
492             
493             // fill histograms with cluster not attached to the track
494             ((TH2F*)fResiduals->UncheckedAt(kResidualPerChClusterOut))->Fill(chId+1, deltaX);
495             ((TH2F*)fResiduals->UncheckedAt(kResidualPerChClusterOut+1))->Fill(chId+1, deltaY);
496             ((TH2F*)fResiduals->UncheckedAt(kResidualPerHalfChClusterOut))->Fill(halfChId+1, deltaX);
497             ((TH2F*)fResiduals->UncheckedAt(kResidualPerHalfChClusterOut+1))->Fill(halfChId+1, deltaY);
498             ((TH2F*)fResiduals->UncheckedAt(kResidualPerDEClusterOut))->Fill(fDEIndices[deId], deltaX);
499             ((TH2F*)fResiduals->UncheckedAt(kResidualPerDEClusterOut+1))->Fill(fDEIndices[deId], deltaY);
500             ((TH2F*)fResidualsVsP->UncheckedAt(kResidualInChVsPClusterOut+chId))->Fill(pUncorr, deltaX);
501             ((TH2F*)fResidualsVsP->UncheckedAt(kResidualInChVsPClusterOut+10+chId))->Fill(pUncorr, deltaY);
502             ((TH2F*)fResiduals->UncheckedAt(kTrackResPerCh))->Fill(chId+1, TMath::Sqrt(trackResX2));
503             ((TH2F*)fResiduals->UncheckedAt(kTrackResPerCh+1))->Fill(chId+1, TMath::Sqrt(trackResY2));
504             ((TH2F*)fResiduals->UncheckedAt(kTrackResPerHalfCh))->Fill(halfChId+1, TMath::Sqrt(trackResX2));
505             ((TH2F*)fResiduals->UncheckedAt(kTrackResPerHalfCh+1))->Fill(halfChId+1, TMath::Sqrt(trackResY2));
506             ((TH2F*)fResiduals->UncheckedAt(kTrackResPerDE))->Fill(fDEIndices[deId], TMath::Sqrt(trackResX2));
507             ((TH2F*)fResiduals->UncheckedAt(kTrackResPerDE+1))->Fill(fDEIndices[deId], TMath::Sqrt(trackResY2));
508             ((TH2F*)fResiduals->UncheckedAt(kMCSPerCh))->Fill(chId+1, TMath::Sqrt(mcsCov(0,0)));
509             ((TH2F*)fResiduals->UncheckedAt(kMCSPerCh+1))->Fill(chId+1, TMath::Sqrt(mcsCov(2,2)));
510             ((TH2F*)fResiduals->UncheckedAt(kMCSPerHalfCh))->Fill(halfChId+1, TMath::Sqrt(mcsCov(0,0)));
511             ((TH2F*)fResiduals->UncheckedAt(kMCSPerHalfCh+1))->Fill(halfChId+1, TMath::Sqrt(mcsCov(2,2)));
512             ((TH2F*)fResiduals->UncheckedAt(kMCSPerDE))->Fill(fDEIndices[deId], TMath::Sqrt(mcsCov(0,0)));
513             ((TH2F*)fResiduals->UncheckedAt(kMCSPerDE+1))->Fill(fDEIndices[deId], TMath::Sqrt(mcsCov(2,2)));
514             ((TH2F*)fResiduals->UncheckedAt(kClusterRes2PerCh))->Fill(chId+1, deltaX*deltaX - trackResX2);
515             ((TH2F*)fResiduals->UncheckedAt(kClusterRes2PerCh+1))->Fill(chId+1, deltaY*deltaY - trackResY2);
516           }
517           
518         }
519         
520       }
521       
522       // restore the track
523       track.AddTrackParamAtCluster(currentTrackParam, *(currentTrackParam.GetClusterPtr()), kTRUE);
524       
525     }
526     
527   }
528   
529   // Post final data. It will be written to a file with option "RECREATE"
530   PostData(1, fResiduals);
531   PostData(2, fResidualsVsP);
532   PostData(5, fTrackRes);
533 }
534
535 //________________________________________________________________________
536 void AliAnalysisTaskMuonResolution::NotifyRun()
537 {
538   /// load necessary data from OCDB corresponding to the first run number and initialize analysis
539   
540   if (fOCDBLoaded) return;
541   
542   AliCDBManager* cdbm = AliCDBManager::Instance();
543   cdbm->SetDefaultStorage(fDefaultStorage.Data());
544   cdbm->SetRun(fCurrentRunNumber);
545   
546   if (!AliMUONCDB::LoadField()) return;
547   
548   if (!AliMUONCDB::LoadMapping()) return;
549   
550   AliMUONRecoParam* recoParam = AliMUONCDB::LoadRecoParam();
551   if (!recoParam) return;
552   
553   AliMUONESDInterface::ResetTracker(recoParam);
554   
555   for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
556     
557     // set the cluster resolution to default if not already set and create output objects
558     if (fClusterResNB[i] < 0.) fClusterResNB[i] = recoParam->GetDefaultNonBendingReso(i);
559     if (fClusterResB[i] < 0.) fClusterResB[i] = recoParam->GetDefaultBendingReso(i);
560     
561     // fill correspondence between DEId and indices for histo (starting from 1)
562     AliMpDEIterator it;
563     it.First(i);
564     while (!it.IsDone()) {
565       fNDE++;
566       fDEIndices[it.CurrentDEId()] = fNDE;
567       fDEIds[fNDE] = it.CurrentDEId();
568       it.Next();
569     }
570     
571   }
572   
573   if (fReAlign) {
574     
575     // recover default storage full name (raw:// cannot be used to set specific storage)
576     TString defaultStorage(cdbm->GetDefaultStorage()->GetType());
577     if (defaultStorage == "alien") defaultStorage += Form("://folder=%s", cdbm->GetDefaultStorage()->GetBaseFolder().Data());
578     else defaultStorage += Form("://%s", cdbm->GetDefaultStorage()->GetBaseFolder().Data());
579     
580     // reset existing geometry/alignment if any
581     if (cdbm->GetEntryCache()->Contains("GRP/Geometry/Data")) cdbm->UnloadFromCache("GRP/Geometry/Data");
582     if (cdbm->GetEntryCache()->Contains("MUON/Align/Data")) cdbm->UnloadFromCache("MUON/Align/Data");
583     if (AliGeomManager::GetGeometry()) AliGeomManager::GetGeometry()->UnlockGeometry();
584     
585     // get original geometry transformer
586     AliGeomManager::LoadGeometry();
587     if (!AliGeomManager::GetGeometry()) return;
588     if (fOldAlignStorage != "none") {
589       if (!fOldAlignStorage.IsNull()) cdbm->SetSpecificStorage("MUON/Align/Data",fOldAlignStorage.Data());
590       else cdbm->SetSpecificStorage("MUON/Align/Data",defaultStorage.Data());
591       AliGeomManager::ApplyAlignObjsFromCDB("MUON");
592     }
593     fOldGeoTransformer = new AliMUONGeometryTransformer();
594     fOldGeoTransformer->LoadGeometryData();
595     
596     // get new geometry transformer
597     cdbm->UnloadFromCache("GRP/Geometry/Data");
598     if (fOldAlignStorage != "none") cdbm->UnloadFromCache("MUON/Align/Data");
599     AliGeomManager::GetGeometry()->UnlockGeometry();
600     AliGeomManager::LoadGeometry();
601     if (!AliGeomManager::GetGeometry()) return;
602     if (!fNewAlignStorage.IsNull()) cdbm->SetSpecificStorage("MUON/Align/Data",fNewAlignStorage.Data());
603     else cdbm->SetSpecificStorage("MUON/Align/Data",defaultStorage.Data());
604     AliGeomManager::ApplyAlignObjsFromCDB("MUON");
605     fNewGeoTransformer = new AliMUONGeometryTransformer();
606     fNewGeoTransformer->LoadGeometryData();
607     
608   } else {
609     
610     // load geometry for track extrapolation to vertex
611     if (cdbm->GetEntryCache()->Contains("GRP/Geometry/Data")) cdbm->UnloadFromCache("GRP/Geometry/Data");
612     if (AliGeomManager::GetGeometry()) AliGeomManager::GetGeometry()->UnlockGeometry();
613     AliGeomManager::LoadGeometry();
614     if (!AliGeomManager::GetGeometry()) return;
615     
616   }
617   
618   // print starting chamber resolution if required
619   if (fPrintClResPerCh) {
620     printf("\nstarting chamber resolution:\n");
621     printf(" - non-bending:");
622     for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) printf((i==0)?" %5.3f":", %5.3f",fClusterResNB[i]);
623     printf("\n -     bending:");
624     for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) printf((i==0)?" %6.4f":", %6.4f",fClusterResB[i]);
625     printf("\n\n");
626   }
627   
628   fOCDBLoaded = kTRUE;
629   
630   UserCreateOutputObjects();
631   
632 }
633
634 //________________________________________________________________________
635 void AliAnalysisTaskMuonResolution::Terminate(Option_t *)
636 {
637   /// compute final results
638   
639   // recover output objects
640   fResiduals = static_cast<TObjArray*> (GetOutputData(1));
641   fResidualsVsP = static_cast<TObjArray*> (GetOutputData(2));
642   fTrackRes = static_cast<TObjArray*> (GetOutputData(5));
643   if (!fResiduals || !fResidualsVsP || !fTrackRes) return;
644   
645   // summary graphs
646   fLocalChi2 = new TObjArray(1000);
647   fLocalChi2->SetOwner();
648   fChamberRes = new TObjArray(1000);
649   fChamberRes->SetOwner();
650   TGraphErrors* g;
651   TMultiGraph* mg;
652   
653   const char* axes[2] = {"X", "Y"};
654   Double_t newClusterRes[2][10], newClusterResErr[2][10];
655   fNDE = ((TH2F*)fResiduals->UncheckedAt(kResidualPerDEClusterIn))->GetXaxis()->GetNbins();
656   
657   for (Int_t ia = 0; ia < 2; ia++) {
658     
659     g = new TGraphErrors(AliMUONConstants::NTrackingCh());
660     g->SetName(Form("gResidual%sPerChMean_ClusterIn",axes[ia]));
661     g->SetTitle(Form("cluster-track residual-%s per Ch: mean (cluster in);chamber ID;<#Delta_{%s}> (cm)",axes[ia],axes[ia]));
662     g->SetMarkerStyle(kFullDotLarge);
663     fChamberRes->AddAtAndExpand(g, kResidualPerChMeanClusterIn+ia);
664     g = new TGraphErrors(AliMUONConstants::NTrackingCh());
665     g->SetName(Form("gResidual%sPerChMean_ClusterOut",axes[ia]));
666     g->SetTitle(Form("cluster-track residual-%s per Ch: mean (cluster out);chamber ID;<#Delta_{%s}> (cm)",axes[ia],axes[ia]));
667     g->SetMarkerStyle(kFullDotLarge);
668     fChamberRes->AddAtAndExpand(g, kResidualPerChMeanClusterOut+ia);
669     
670     g = new TGraphErrors(2*AliMUONConstants::NTrackingCh());
671     g->SetName(Form("gResidual%sPerHalfChMean_ClusterIn",axes[ia]));
672     g->SetTitle(Form("cluster-track residual-%s per half Ch: mean (cluster in);half chamber ID;<#Delta_{%s}> (cm)",axes[ia],axes[ia]));
673     g->SetMarkerStyle(kFullDotLarge);
674     fChamberRes->AddAtAndExpand(g, kResidualPerHalfChMeanClusterIn+ia);
675     g = new TGraphErrors(2*AliMUONConstants::NTrackingCh());
676     g->SetName(Form("gResidual%sPerHalfChMean_ClusterOut",axes[ia]));
677     g->SetTitle(Form("cluster-track residual-%s per half Ch: mean (cluster out);half chamber ID;<#Delta_{%s}> (cm)",axes[ia],axes[ia]));
678     g->SetMarkerStyle(kFullDotLarge);
679     fChamberRes->AddAtAndExpand(g, kResidualPerHalfChMeanClusterOut+ia);
680     
681     g = new TGraphErrors(fNDE);
682     g->SetName(Form("gResidual%sPerDEMean_ClusterIn",axes[ia]));
683     g->SetTitle(Form("cluster-track residual-%s per DE: mean (cluster in);DE ID;<#Delta_{%s}> (cm)",axes[ia],axes[ia]));
684     g->SetMarkerStyle(kFullDotLarge);
685     fChamberRes->AddAtAndExpand(g, kResidualPerDEMeanClusterIn+ia);
686     g = new TGraphErrors(fNDE);
687     g->SetName(Form("gResidual%sPerDEMean_ClusterOut",axes[ia]));
688     g->SetTitle(Form("cluster-track residual-%s per DE: mean (cluster out);DE ID;<#Delta_{%s}> (cm)",axes[ia],axes[ia]));
689     g->SetMarkerStyle(kFullDotLarge);
690     fChamberRes->AddAtAndExpand(g, kResidualPerDEMeanClusterOut+ia);
691     
692     g = new TGraphErrors(AliMUONConstants::NTrackingCh());
693     g->SetName(Form("gResidual%sPerChSigma_ClusterIn",axes[ia]));
694     g->SetTitle(Form("cluster-track residual-%s per Ch: sigma (cluster in);chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
695     g->SetMarkerStyle(kFullDotLarge);
696     fChamberRes->AddAtAndExpand(g, kResidualPerChSigmaClusterIn+ia);
697     g = new TGraphErrors(AliMUONConstants::NTrackingCh());
698     g->SetName(Form("gResidual%sPerChSigma_ClusterOut",axes[ia]));
699     g->SetTitle(Form("cluster-track residual-%s per Ch: sigma (cluster out);chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
700     g->SetMarkerStyle(kFullDotLarge);
701     fChamberRes->AddAtAndExpand(g, kResidualPerChSigmaClusterOut+ia);
702     
703     g = new TGraphErrors(AliMUONConstants::NTrackingCh());
704     g->SetName(Form("gResidual%sPerChDispersion_ClusterOut",axes[ia]));
705     g->SetTitle(Form("cluster-track residual-%s per Ch: dispersion (cluster out);chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
706     g->SetMarkerStyle(kFullDotLarge);
707     fChamberRes->AddAtAndExpand(g, kResidualPerChDispersionClusterOut+ia);
708     
709     g = new TGraphErrors(AliMUONConstants::NTrackingCh());
710     g->SetName(Form("gCombinedResidual%sPerChSigma",axes[ia]));
711     g->SetTitle(Form("combined cluster-track residual-%s per Ch: sigma;chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
712     g->SetMarkerStyle(kFullDotLarge);
713     fChamberRes->AddAtAndExpand(g, kCombinedResidualPerChSigma+ia);
714     
715     g = new TGraphErrors(2*AliMUONConstants::NTrackingCh());
716     g->SetName(Form("gCombinedResidual%sPerHalfChSigma",axes[ia]));
717     g->SetTitle(Form("combined cluster-track residual-%s per half Ch: sigma;half chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
718     g->SetMarkerStyle(kFullDotLarge);
719     fChamberRes->AddAtAndExpand(g, kCombinedResidualPerHalfChSigma+ia);
720     
721     g = new TGraphErrors(fNDE);
722     g->SetName(Form("gCombinedResidual%sPerDESigma",axes[ia]));
723     g->SetTitle(Form("combined cluster-track residual-%s per DE: sigma;DE ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
724     g->SetMarkerStyle(kFullDotLarge);
725     fChamberRes->AddAtAndExpand(g, kCombinedResidualPerDESigma+ia);
726     
727     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]));
728     for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
729       g = new TGraphErrors(((TH2F*)fResidualsVsP->UncheckedAt(kResidualInChVsPClusterIn+10*ia+i))->GetNbinsX());
730       g->SetName(Form("gRes%sVsP_ch%d",axes[ia],i+1));
731       g->SetMarkerStyle(kFullDotMedium);
732       g->SetMarkerColor(i+1+i/9);
733       mg->Add(g,"p");
734     }
735     fChamberRes->AddAtAndExpand(mg, kCombinedResidualSigmaVsP+ia);
736     
737     g = new TGraphErrors(AliMUONConstants::NTrackingCh());
738     g->SetName(Form("gTrackRes%sPerCh",axes[ia]));
739     g->SetTitle(Form("track <#sigma_{%s}> per Ch;chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
740     g->SetMarkerStyle(kFullDotLarge);
741     fChamberRes->AddAtAndExpand(g, kTrackResPerChMean+ia);
742     
743     g = new TGraphErrors(AliMUONConstants::NTrackingCh());
744     g->SetName(Form("gMCS%sPerCh",axes[ia]));
745     g->SetTitle(Form("MCS %s-dispersion of extrapolated track per Ch;chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
746     g->SetMarkerStyle(kFullDotLarge);
747     fChamberRes->AddAtAndExpand(g, kMCSPerChMean+ia);
748     
749     g = new TGraphErrors(AliMUONConstants::NTrackingCh());
750     g->SetName(Form("gClusterRes%sPerCh",axes[ia]));
751     g->SetTitle(Form("cluster <#sigma_{%s}> per Ch;chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
752     g->SetMarkerStyle(kFullDotLarge);
753     fChamberRes->AddAtAndExpand(g, kClusterResPerCh+ia);
754     
755     g = new TGraphErrors(2*AliMUONConstants::NTrackingCh());
756     g->SetName(Form("gClusterRes%sPerHalfCh",axes[ia]));
757     g->SetTitle(Form("cluster <#sigma_{%s}> per half Ch;half chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
758     g->SetMarkerStyle(kFullDotLarge);
759     fChamberRes->AddAtAndExpand(g, kClusterResPerHalfCh+ia);
760     
761     g = new TGraphErrors(fNDE);
762     g->SetName(Form("gClusterRes%sPerDE",axes[ia]));
763     g->SetTitle(Form("cluster <#sigma_{%s}> per DE;DE ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
764     g->SetMarkerStyle(kFullDotLarge);
765     fChamberRes->AddAtAndExpand(g, kClusterResPerDE+ia);
766     
767     g = new TGraphErrors(AliMUONConstants::NTrackingCh());
768     g->SetName(Form("gCalcClusterRes%sPerCh",axes[ia]));
769     g->SetTitle(Form("calculated cluster <#sigma_{%s}> per Ch;chamber ID;#sigma_{%s} (cm)",axes[ia],axes[ia]));
770     g->SetMarkerStyle(kFullDotLarge);
771     fChamberRes->AddAtAndExpand(g, kCalcClusterResPerCh+ia);
772     
773     g = new TGraphErrors(AliMUONConstants::NTrackingCh());
774     g->SetName(Form("gLocalChi2%sPerChMean",axes[ia]));
775     g->SetTitle(Form("local chi2-%s per Ch: mean;chamber ID;<local #chi^{2}_{%s}>",axes[ia],axes[ia]));
776     g->SetMarkerStyle(kFullDotLarge);
777     fLocalChi2->AddAtAndExpand(g, kLocalChi2PerChMean+ia);
778     
779     g = new TGraphErrors(fNDE);
780     g->SetName(Form("gLocalChi2%sPerDEMean",axes[ia]));
781     g->SetTitle(Form("local chi2-%s per DE: mean;DE ID;<local #chi^{2}_{%s}>",axes[ia],axes[ia]));
782     g->SetMarkerStyle(kFullDotLarge);
783     fLocalChi2->AddAtAndExpand(g, kLocalChi2PerDEMean+ia);
784     
785     // compute residual mean and dispersion and averaged local chi2 per chamber and half chamber
786     Double_t meanIn, meanInErr, meanOut, meanOutErr, sigma, sigmaIn, sigmaInErr, sigmaOut, sigmaOutErr;
787     Double_t sigmaTrack, sigmaTrackErr, sigmaMCS, sigmaMCSErr, clusterRes, clusterResErr, sigmaCluster, sigmaClusterErr;
788     for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
789       
790       // method 1
791       TH1D *tmp = ((TH2F*)fResiduals->UncheckedAt(kResidualPerChClusterIn+ia))->ProjectionY("tmp",i+1,i+1,"e");
792       GetMean(tmp, meanIn, meanInErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChMeanClusterIn+ia), i, i+1);
793       GetRMS(tmp, sigmaIn, sigmaInErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChSigmaClusterIn+ia), i, i+1);
794       delete tmp;
795       
796       tmp = ((TH2F*)fResiduals->UncheckedAt(kResidualPerChClusterOut+ia))->ProjectionY("tmp",i+1,i+1,"e");
797       GetMean(tmp, meanOut, meanOutErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChMeanClusterOut+ia), i, i+1);
798       GetRMS(tmp, sigmaOut, sigmaOutErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChSigmaClusterOut+ia), i, i+1);
799       delete tmp;
800       
801       if (fCorrectForSystematics) {
802         sigma = TMath::Sqrt(sigmaIn*sigmaIn + meanIn*meanIn);
803         sigmaInErr = (sigma>0) ? TMath::Sqrt(sigmaIn*sigmaIn*sigmaInErr*sigmaInErr + meanIn*meanIn*meanInErr*meanInErr) / sigma : 0.;
804         sigmaIn = sigma;
805         sigma = TMath::Sqrt(sigmaOut*sigmaOut + meanOut*meanOut);
806         sigmaOutErr = (sigma>0) ? TMath::Sqrt(sigmaOut*sigmaOut*sigmaOutErr*sigmaOutErr + meanOut*meanOut*meanOutErr*meanOutErr) / sigma : 0.;
807         sigmaOut = sigma;
808       }
809       ((TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChDispersionClusterOut+ia))->SetPoint(i, i+1, sigmaOut);
810       ((TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChDispersionClusterOut+ia))->SetPointError(i, 0., sigmaOutErr);
811       
812       clusterRes = TMath::Sqrt(sigmaIn*sigmaOut);
813       //      clusterResErr = (clusterRes > 0.) ? 0.5 * TMath::Sqrt(sigmaInErr*sigmaInErr*sigmaOut*sigmaOut + sigmaIn*sigmaIn*sigmaOutErr*sigmaOutErr) / clusterRes : 0.;
814       clusterResErr = TMath::Sqrt(sigmaInErr*sigmaOutErr);
815       ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerChSigma+ia))->SetPoint(i, i+1, clusterRes);
816       ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerChSigma+ia))->SetPointError(i, 0., clusterResErr);
817       newClusterRes[ia][i] = clusterRes;
818       newClusterResErr[ia][i] = clusterResErr;
819       
820       // method 2
821       tmp = ((TH2F*)fResiduals->UncheckedAt(kTrackResPerCh+ia))->ProjectionY("tmp",i+1,i+1,"e");
822       GetMean(tmp, sigmaTrack, sigmaTrackErr, (TGraphErrors*)fChamberRes->UncheckedAt(kTrackResPerChMean+ia), i, i+1, kFALSE, kFALSE);
823       delete tmp;
824       
825       tmp = ((TH2F*)fResiduals->UncheckedAt(kMCSPerCh+ia))->ProjectionY("tmp",i+1,i+1,"e");
826       GetMean(tmp, sigmaMCS, sigmaMCSErr, (TGraphErrors*)fChamberRes->UncheckedAt(kMCSPerChMean+ia), i, i+1, kFALSE, kFALSE);
827       delete tmp;
828       
829       sigmaCluster = sigmaOut*sigmaOut - sigmaTrack*sigmaTrack;
830       if (sigmaCluster > 0.) {
831         sigmaCluster = TMath::Sqrt(sigmaCluster);
832         sigmaClusterErr = TMath::Sqrt(sigmaOut*sigmaOut*sigmaOutErr*sigmaOutErr + sigmaTrack*sigmaTrack*sigmaTrackErr*sigmaTrackErr) / sigmaCluster;
833       } else {
834         sigmaCluster = 0.;
835         sigmaClusterErr = 0.;
836       }
837       ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerCh+ia))->SetPoint(i, i+1, sigmaCluster);
838       ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerCh+ia))->SetPointError(i, 0., sigmaClusterErr);
839       
840       // method 3
841       tmp = ((TH2F*)fResiduals->UncheckedAt(kClusterRes2PerCh+ia))->ProjectionY("tmp",i+1,i+1,"e");
842       ZoomRight(tmp);
843       clusterRes = tmp->GetMean();
844       if (clusterRes > 0.) {
845         ((TGraphErrors*)fChamberRes->UncheckedAt(kCalcClusterResPerCh+ia))->SetPoint(i, i+1, TMath::Sqrt(clusterRes));
846         ((TGraphErrors*)fChamberRes->UncheckedAt(kCalcClusterResPerCh+ia))->SetPointError(i, 0., 0.5 * tmp->GetMeanError() / TMath::Sqrt(clusterRes));
847       } else {
848         ((TGraphErrors*)fChamberRes->UncheckedAt(kCalcClusterResPerCh+ia))->SetPoint(i, i+1, 0.);
849         ((TGraphErrors*)fChamberRes->UncheckedAt(kCalcClusterResPerCh+ia))->SetPointError(i, 0., 0.);
850       }
851       delete tmp;
852       
853       // method 1 versus p
854       FillSigmaClusterVsP((TH2F*)fResidualsVsP->UncheckedAt(kResidualInChVsPClusterIn+10*ia+i),
855                           (TH2F*)fResidualsVsP->UncheckedAt(kResidualInChVsPClusterOut+10*ia+i),
856                           (TGraphErrors*)((TMultiGraph*)fChamberRes->UncheckedAt(kCombinedResidualSigmaVsP+ia))->GetListOfGraphs()->FindObject(Form("gRes%sVsP_ch%d",axes[ia],i+1)));
857       
858       // compute residual mean and dispersion per half chamber
859       for (Int_t j = 0; j < 2; j++) {
860         Int_t k = 2*i+j;
861         
862         // method 1
863         tmp = ((TH2F*)fResiduals->UncheckedAt(kResidualPerHalfChClusterIn+ia))->ProjectionY("tmp",k+1,k+1,"e");
864         GetMean(tmp, meanIn, meanInErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerHalfChMeanClusterIn+ia), k, k+1);
865         GetRMS(tmp, sigmaIn, sigmaInErr);
866         delete tmp;
867         
868         tmp = ((TH2F*)fResiduals->UncheckedAt(kResidualPerHalfChClusterOut+ia))->ProjectionY("tmp",k+1,k+1,"e");
869         GetMean(tmp, meanOut, meanOutErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerHalfChMeanClusterOut+ia), k, k+1);
870         GetRMS(tmp, sigmaOut, sigmaOutErr);
871         delete tmp;
872         
873         if (fCorrectForSystematics) {
874           sigma = TMath::Sqrt(sigmaIn*sigmaIn + meanIn*meanIn);
875           sigmaInErr = (sigma>0) ? TMath::Sqrt(sigmaIn*sigmaIn*sigmaInErr*sigmaInErr + meanIn*meanIn*meanInErr*meanInErr) / sigma : 0.;
876           sigmaIn = sigma;
877           sigma = TMath::Sqrt(sigmaOut*sigmaOut + meanOut*meanOut);
878           sigmaOutErr = (sigma>0) ? TMath::Sqrt(sigmaOut*sigmaOut*sigmaOutErr*sigmaOutErr + meanOut*meanOut*meanOutErr*meanOutErr) / sigma : 0.;
879           sigmaOut = sigma;
880         }
881         
882         clusterRes = TMath::Sqrt(sigmaIn*sigmaOut);
883         //      clusterResErr = (clusterRes > 0.) ? 0.5 * TMath::Sqrt(sigmaInErr*sigmaInErr*sigmaOut*sigmaOut + sigmaIn*sigmaIn*sigmaOutErr*sigmaOutErr) / clusterRes : 0.;
884         clusterResErr = TMath::Sqrt(sigmaInErr*sigmaOutErr);
885         ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerHalfChSigma+ia))->SetPoint(k, k+1, clusterRes);
886         ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerHalfChSigma+ia))->SetPointError(k, 0., clusterResErr);
887         
888         // method 2
889         tmp = ((TH2F*)fResiduals->UncheckedAt(kTrackResPerHalfCh+ia))->ProjectionY("tmp",k+1,k+1,"e");
890         GetMean(tmp, sigmaTrack, sigmaTrackErr, 0x0, 0, 0, kFALSE, kFALSE);
891         delete tmp;
892         
893         tmp = ((TH2F*)fResiduals->UncheckedAt(kMCSPerHalfCh+ia))->ProjectionY("tmp",k+1,k+1,"e");
894         GetMean(tmp, sigmaMCS, sigmaMCSErr, 0x0, 0, 0, kFALSE, kFALSE);
895         delete tmp;
896         
897         sigmaCluster = sigmaOut*sigmaOut - sigmaTrack*sigmaTrack;
898         if (sigmaCluster > 0.) {
899           sigmaCluster = TMath::Sqrt(sigmaCluster);
900           sigmaClusterErr = TMath::Sqrt(sigmaOut*sigmaOut*sigmaOutErr*sigmaOutErr + sigmaTrack*sigmaTrack*sigmaTrackErr*sigmaTrackErr) / sigmaCluster;
901         } else {
902           sigmaCluster = 0.;
903           sigmaClusterErr = 0.;
904         }
905         ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerHalfCh+ia))->SetPoint(k, k+1, sigmaCluster);
906         ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerHalfCh+ia))->SetPointError(k, 0., sigmaClusterErr);
907         
908       }
909       
910       // compute averaged local chi2
911       tmp = ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerCh+ia))->ProjectionY("tmp",i+1,i+1,"e");
912       ((TGraphErrors*)fLocalChi2->UncheckedAt(kLocalChi2PerChMean+ia))->SetPoint(i, i+1, tmp->GetMean());
913       ((TGraphErrors*)fLocalChi2->UncheckedAt(kLocalChi2PerChMean+ia))->SetPointError(i, 0., tmp->GetMeanError());
914       delete tmp;
915       
916     }
917     
918     // compute residual mean and dispersion per DE
919     for (Int_t i = 0; i < fNDE; i++) {
920       
921       // method 1
922       TH1D *tmp = ((TH2F*)fResiduals->UncheckedAt(kResidualPerDEClusterIn+ia))->ProjectionY("tmp",i+1,i+1,"e");
923       GetMean(tmp, meanIn, meanInErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMeanClusterIn+ia), i, i+1);
924       GetRMS(tmp, sigmaIn, sigmaInErr);
925       delete tmp;
926       
927       tmp = ((TH2F*)fResiduals->UncheckedAt(kResidualPerDEClusterOut+ia))->ProjectionY("tmp",i+1,i+1,"e");
928       GetMean(tmp, meanOut, meanOutErr, (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMeanClusterOut+ia), i, i+1);
929       GetRMS(tmp, sigmaOut, sigmaOutErr);
930       delete tmp;
931       
932       if (fCorrectForSystematics) {
933         sigma = TMath::Sqrt(sigmaIn*sigmaIn + meanIn*meanIn);
934         sigmaInErr = (sigma>0) ? TMath::Sqrt(sigmaIn*sigmaIn*sigmaInErr*sigmaInErr + meanIn*meanIn*meanInErr*meanInErr) / sigma : 0.;
935         sigmaIn = sigma;
936         sigma = TMath::Sqrt(sigmaOut*sigmaOut + meanOut*meanOut);
937         sigmaOutErr = (sigma>0) ? TMath::Sqrt(sigmaOut*sigmaOut*sigmaOutErr*sigmaOutErr + meanOut*meanOut*meanOutErr*meanOutErr) / sigma : 0.;
938         sigmaOut = sigma;
939       }
940       
941       clusterRes = TMath::Sqrt(sigmaIn*sigmaOut);
942       //      clusterResErr = (clusterRes > 0.) ? 0.5 * TMath::Sqrt(sigmaInErr*sigmaInErr*sigmaOut*sigmaOut + sigmaIn*sigmaIn*sigmaOutErr*sigmaOutErr) / clusterRes : 0.;
943       clusterResErr = TMath::Sqrt(sigmaInErr*sigmaOutErr);
944       ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerDESigma+ia))->SetPoint(i, i+1, clusterRes);
945       ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerDESigma+ia))->SetPointError(i, 0., clusterResErr);
946       
947       // method 2
948       tmp = ((TH2F*)fResiduals->UncheckedAt(kTrackResPerDE+ia))->ProjectionY("tmp",i+1,i+1,"e");
949       GetMean(tmp, sigmaTrack, sigmaTrackErr, 0x0, 0, 0, kFALSE, kFALSE);
950       delete tmp;
951       
952       tmp = ((TH2F*)fResiduals->UncheckedAt(kMCSPerDE+ia))->ProjectionY("tmp",i+1,i+1,"e");
953       GetMean(tmp, sigmaMCS, sigmaMCSErr, 0x0, 0, 0, kFALSE, kFALSE);
954       delete tmp;
955       
956       sigmaCluster = sigmaOut*sigmaOut - sigmaTrack*sigmaTrack;
957       if (sigmaCluster > 0.) {
958         sigmaCluster = TMath::Sqrt(sigmaCluster);
959         sigmaClusterErr = TMath::Sqrt(sigmaOut*sigmaOut*sigmaOutErr*sigmaOutErr + sigmaTrack*sigmaTrack*sigmaTrackErr*sigmaTrackErr) / sigmaCluster;
960       } else {
961         sigmaCluster = 0.;
962         sigmaClusterErr = 0.;
963       }
964       ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerDE+ia))->SetPoint(i, i+1, sigmaCluster);
965       ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerDE+ia))->SetPointError(i, 0., sigmaClusterErr);
966       
967       // compute averaged local chi2
968       tmp = ((TH2F*)fResiduals->UncheckedAt(kLocalChi2PerDE+ia))->ProjectionY("tmp",i+1,i+1,"e");
969       ((TGraphErrors*)fLocalChi2->UncheckedAt(kLocalChi2PerDEMean+ia))->SetPoint(i, i+1, tmp->GetMean());
970       ((TGraphErrors*)fLocalChi2->UncheckedAt(kLocalChi2PerDEMean+ia))->SetPointError(i, 0., tmp->GetMeanError());
971       delete tmp;
972       
973     }
974     
975     // set graph labels
976     TAxis* xAxis = ((TH2F*)fResiduals->UncheckedAt(kResidualPerDEClusterOut+ia))->GetXaxis();
977     ((TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMeanClusterIn+ia))->GetXaxis()->Set(fNDE, 0.5, fNDE+0.5);
978     ((TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMeanClusterOut+ia))->GetXaxis()->Set(fNDE, 0.5, fNDE+0.5);
979     ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerDESigma+ia))->GetXaxis()->Set(fNDE, 0.5, fNDE+0.5);
980     ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerDE+ia))->GetXaxis()->Set(fNDE, 0.5, fNDE+0.5);
981     ((TGraphErrors*)fLocalChi2->UncheckedAt(kLocalChi2PerDEMean+ia))->GetXaxis()->Set(fNDE, 0.5, fNDE+0.5);
982     for (Int_t i = 1; i <= fNDE; i++) {
983       const char* label = xAxis->GetBinLabel(i);
984       ((TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMeanClusterIn+ia))->GetXaxis()->SetBinLabel(i, label);
985       ((TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMeanClusterOut+ia))->GetXaxis()->SetBinLabel(i, label);
986       ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerDESigma+ia))->GetXaxis()->SetBinLabel(i, label);
987       ((TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerDE+ia))->GetXaxis()->SetBinLabel(i, label);
988       ((TGraphErrors*)fLocalChi2->UncheckedAt(kLocalChi2PerDEMean+ia))->GetXaxis()->SetBinLabel(i, label);
989     }
990     
991   }
992   
993   // compute averaged local chi2 per chamber (X+Y)
994   TH2F* h2 = (TH2F*)fResiduals->UncheckedAt(kLocalChi2PerCh+2);
995   g = new TGraphErrors(AliMUONConstants::NTrackingCh());
996   g->SetName("gLocalChi2PerChMean");
997   g->SetTitle("local chi2 per Ch: mean;chamber ID;<local #chi^{2}>");
998   g->SetMarkerStyle(kFullDotLarge);
999   fLocalChi2->AddAtAndExpand(g, kLocalChi2PerChMean+2);
1000   for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) {
1001     TH1D* tmp = h2->ProjectionY("tmp",i+1,i+1,"e");
1002     g->SetPoint(i, i+1, tmp->GetMean());
1003     g->SetPointError(i, 0., tmp->GetMeanError());
1004     delete tmp;
1005   }
1006   
1007   // compute averaged local chi2 per DE (X+Y)
1008   h2 = (TH2F*)fResiduals->UncheckedAt(kLocalChi2PerDE+2);
1009   g = new TGraphErrors(fNDE);
1010   g->SetName("gLocalChi2PerDEMean");
1011   g->SetTitle("local chi2 per DE: mean;DE ID;<local #chi^{2}>");
1012   g->SetMarkerStyle(kFullDotLarge);
1013   fLocalChi2->AddAtAndExpand(g, kLocalChi2PerDEMean+2);
1014   for (Int_t i = 0; i < fNDE; i++) {
1015     TH1D* tmp = h2->ProjectionY("tmp",i+1,i+1,"e");
1016     g->SetPoint(i, i+1, tmp->GetMean());
1017     g->SetPointError(i, 0., tmp->GetMeanError());
1018     delete tmp;
1019   }
1020   
1021   // set graph labels
1022   g->GetXaxis()->Set(fNDE, 0.5, fNDE+0.5);
1023   for (Int_t i = 1; i <= fNDE; i++) {
1024     const char* label = h2->GetXaxis()->GetBinLabel(i);
1025     g->GetXaxis()->SetBinLabel(i, label);
1026   }
1027   
1028   // display
1029   fCanvases = new TObjArray(1000);
1030   fCanvases->SetOwner();
1031   
1032   TLegend *lResPerChMean = new TLegend(0.75,0.85,0.99,0.99);
1033   TLegend *lResPerChSigma1 = new TLegend(0.75,0.85,0.99,0.99);
1034   TLegend *lResPerChSigma2 = new TLegend(0.75,0.85,0.99,0.99);
1035   TLegend *lResPerChSigma3 = new TLegend(0.75,0.85,0.99,0.99);
1036   
1037   TCanvas* cResPerCh = new TCanvas("cResPerCh","cResPerCh",1200,500);
1038   cResPerCh->Divide(4,2);
1039   for (Int_t ia = 0; ia < 2; ia++) {
1040     cResPerCh->cd(1+4*ia);
1041     g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChMeanClusterOut+ia);
1042     g->Draw("ap");
1043     g->SetMarkerColor(2);
1044     g->SetLineColor(2);
1045     if (ia == 0) lResPerChMean->AddEntry(g,"cluster out","PL");
1046     g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChMeanClusterIn+ia);
1047     g->Draw("p");
1048     g->SetMarkerColor(4);
1049     g->SetLineColor(4);
1050     if (ia == 0) lResPerChMean->AddEntry(g,"cluster in","PL");
1051     if (ia == 0) lResPerChMean->Draw();
1052     else lResPerChMean->DrawClone();
1053     cResPerCh->cd(2+4*ia);
1054     g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChSigmaClusterOut+ia);
1055     g->Draw("ap");
1056     g->SetMinimum(0.);
1057     g->SetMarkerColor(2);
1058     g->SetLineColor(2);
1059     if (ia == 0) lResPerChSigma1->AddEntry(g,"cluster out","PL");
1060     g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChSigmaClusterIn+ia);
1061     g->Draw("p");
1062     g->SetMarkerColor(4);
1063     g->SetLineColor(4);
1064     if (ia == 0) lResPerChSigma1->AddEntry(g,"cluster in","PL");
1065     g = (TGraphErrors*)fChamberRes->UncheckedAt(kMCSPerChMean+ia);
1066     g->Draw("p");
1067     g->SetMarkerColor(5);
1068     g->SetLineColor(5);
1069     if (ia == 0) lResPerChSigma1->AddEntry(g,"MCS","PL");
1070     g = (TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerChSigma+ia);
1071     g->Draw("p");
1072     g->SetMarkerColor(3);
1073     g->SetLineColor(3);
1074     if (ia == 0) lResPerChSigma1->AddEntry(g,"combined 1","PL");
1075     if (ia == 0) lResPerChSigma1->Draw();
1076     else lResPerChSigma1->DrawClone();
1077     cResPerCh->cd(3+4*ia);
1078     g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerChDispersionClusterOut+ia);
1079     g->Draw("ap");
1080     g->SetMinimum(0.);
1081     g->SetMarkerColor(2);
1082     g->SetLineColor(2);
1083     if (ia == 0) lResPerChSigma2->AddEntry(g,"cluster out","PL");
1084     g = (TGraphErrors*)fChamberRes->UncheckedAt(kMCSPerChMean+ia);
1085     g->Draw("p");
1086     if (ia == 0) lResPerChSigma2->AddEntry(g,"MCS","PL");
1087     g = (TGraphErrors*)fChamberRes->UncheckedAt(kTrackResPerChMean+ia);
1088     g->Draw("p");
1089     g->SetMarkerColor(4);
1090     g->SetLineColor(4);
1091     if (ia == 0) lResPerChSigma2->AddEntry(g,"track res.","PL");
1092     g = (TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerCh+ia);
1093     g->Draw("p");
1094     if (ia == 0) lResPerChSigma2->AddEntry(g,"combined 2","PL");
1095     if (ia == 0) lResPerChSigma2->Draw();
1096     else lResPerChSigma2->DrawClone();
1097     cResPerCh->cd(4+4*ia);
1098     g = (TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerChSigma+ia);
1099     g->Draw("ap");
1100     g->SetMinimum(0.);
1101     if (ia == 0) lResPerChSigma3->AddEntry(g,"combined 1","PL");
1102     g = (TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerCh+ia);
1103     g->Draw("p");
1104     if (ia == 0) lResPerChSigma3->AddEntry(g,"combined 2","PL");
1105     if (ia == 0) lResPerChSigma3->Draw();
1106     else lResPerChSigma3->DrawClone();
1107   }
1108   fCanvases->AddAtAndExpand(cResPerCh, kResPerCh);
1109   
1110   TCanvas* cResPerHalfCh = new TCanvas("cResPerHalfCh","cResPerHalfCh",1200,500);
1111   cResPerHalfCh->Divide(2,2);
1112   for (Int_t ia = 0; ia < 2; ia++) {
1113     cResPerHalfCh->cd(1+2*ia);
1114     g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerHalfChMeanClusterOut+ia);
1115     g->Draw("ap");
1116     g->SetMarkerColor(2);
1117     g->SetLineColor(2);
1118     g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerHalfChMeanClusterIn+ia);
1119     g->Draw("p");
1120     g->SetMarkerColor(4);
1121     g->SetLineColor(4);
1122     lResPerChMean->DrawClone();
1123     cResPerHalfCh->cd(2+2*ia);
1124     g = (TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerHalfChSigma+ia);
1125     g->Draw("ap");
1126     g->SetMinimum(0.);
1127     g->SetMarkerColor(3);
1128     g->SetLineColor(3);
1129     g = (TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerHalfCh+ia);
1130     g->Draw("p");
1131     lResPerChSigma3->DrawClone();
1132   }
1133   fCanvases->AddAtAndExpand(cResPerHalfCh, kResPerHalfCh);
1134   
1135   TCanvas* cResPerDE = new TCanvas("cResPerDE","cResPerDE",1200,800);
1136   cResPerDE->Divide(1,4);
1137   for (Int_t ia = 0; ia < 2; ia++) {
1138     cResPerDE->cd(1+ia);
1139     g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMeanClusterOut+ia);
1140     g->Draw("ap");
1141     g->SetMarkerColor(2);
1142     g->SetLineColor(2);
1143     g = (TGraphErrors*)fChamberRes->UncheckedAt(kResidualPerDEMeanClusterIn+ia);
1144     g->Draw("p");
1145     g->SetMarkerColor(4);
1146     g->SetLineColor(4);
1147     lResPerChMean->DrawClone();
1148     cResPerDE->cd(3+ia);
1149     g = (TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerDESigma+ia);
1150     g->Draw("ap");
1151     g->SetMinimum(0.);
1152     g->SetMarkerColor(3);
1153     g->SetLineColor(3);
1154     g = (TGraphErrors*)fChamberRes->UncheckedAt(kClusterResPerDE+ia);
1155     g->Draw("p");
1156     lResPerChSigma3->DrawClone();
1157   }
1158   fCanvases->AddAtAndExpand(cResPerDE, kResPerDE);
1159   
1160   TCanvas* cResPerChVsP = new TCanvas("cResPerChVsP","cResPerChVsP");
1161   cResPerChVsP->Divide(1,2);
1162   for (Int_t ia = 0; ia < 2; ia++) {
1163     cResPerChVsP->cd(1+ia);
1164     mg = (TMultiGraph*)fChamberRes->UncheckedAt(kCombinedResidualSigmaVsP+ia);
1165     mg->Draw("ap");
1166   }
1167   fCanvases->AddAtAndExpand(cResPerChVsP, kResPerChVsP);
1168   
1169   // print results
1170   if (fPrintClResPerCh) {
1171     printf("\nchamber resolution:\n");
1172     printf(" - non-bending:");
1173     for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) printf((i==0)?" %5.3f":", %5.3f",newClusterRes[0][i]);
1174     printf("\n -     bending:");
1175     for (Int_t i = 0; i < AliMUONConstants::NTrackingCh(); i++) printf((i==0)?" %6.4f":", %6.4f",newClusterRes[1][i]);
1176     printf("\n\n");
1177   }
1178   
1179   if (fPrintClResPerDE) {
1180     Double_t iDE, clRes;
1181     printf("\nDE resolution:\n");
1182     printf(" - non-bending:");
1183     for (Int_t i = 0; i < fNDE; i++) {
1184       ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerDESigma))->GetPoint(i, iDE, clRes);
1185       printf((i==0)?" %5.3f":", %5.3f", clRes);
1186     }
1187     printf("\n -     bending:");
1188     for (Int_t i = 0; i < fNDE; i++) {
1189       ((TGraphErrors*)fChamberRes->UncheckedAt(kCombinedResidualPerDESigma+1))->GetPoint(i, iDE, clRes);
1190       printf((i==0)?" %6.4f":", %6.4f", clRes);
1191     }
1192     printf("\n\n");
1193   }
1194   
1195   // Post final data.
1196   PostData(3, fLocalChi2);
1197   PostData(4, fChamberRes);
1198 }
1199
1200 //________________________________________________________________________
1201 void AliAnalysisTaskMuonResolution::ModifyClusters(AliMUONTrack& track)
1202 {
1203   /// Reset the clusters resolution from the ones given to the task and change
1204   /// the cluster position according to the new alignment parameters if required
1205   
1206   Double_t gX,gY,gZ,lX,lY,lZ;
1207   
1208   // loop over clusters
1209   Int_t nClusters = track.GetNClusters();
1210   for (Int_t iCluster=0; iCluster<nClusters; iCluster++) {
1211     
1212     AliMUONVCluster* cl = static_cast<AliMUONTrackParam*>(track.GetTrackParamAtCluster()->UncheckedAt(iCluster))->GetClusterPtr();
1213     
1214     // change their resolution
1215     cl->SetErrXY(fClusterResNB[cl->GetChamberId()], fClusterResB[cl->GetChamberId()]);
1216     
1217     // change their position
1218     if (fReAlign) {
1219       gX = cl->GetX();
1220       gY = cl->GetY();
1221       gZ = cl->GetZ();
1222       fOldGeoTransformer->Global2Local(cl->GetDetElemId(),gX,gY,gZ,lX,lY,lZ);
1223       fNewGeoTransformer->Local2Global(cl->GetDetElemId(),lX,lY,lZ,gX,gY,gZ);
1224       cl->SetXYZ(gX,gY,gZ);
1225     }
1226     
1227   }
1228   
1229 }
1230
1231 //________________________________________________________________________
1232 void AliAnalysisTaskMuonResolution::Zoom(TH1* h, Double_t fractionCut)
1233 {
1234   /// Reduce the range of the histogram by removing a given fration of the statistic at each edge
1235   ZoomLeft(h, fractionCut);
1236   ZoomRight(h, fractionCut);
1237 }
1238
1239 //________________________________________________________________________
1240 void AliAnalysisTaskMuonResolution::ZoomLeft(TH1* h, Double_t fractionCut)
1241 {
1242   /// Reduce the range of the histogram by removing a given fration of the statistic on the left side
1243   Int_t maxEventsCut = (Int_t) (fractionCut * h->GetEntries());
1244   Int_t nBins = h->GetNbinsX();
1245   
1246   // set low edge  
1247   Int_t minBin;
1248   Int_t eventsCut = 0;
1249   for (minBin = 1; minBin <= nBins; minBin++) {
1250     eventsCut += (Int_t) h->GetBinContent(minBin);
1251     if (eventsCut > maxEventsCut) break;
1252   }
1253   
1254   // set new axis range
1255   h->GetXaxis()->SetRange(--minBin, h->GetXaxis()->GetLast());
1256 }
1257
1258 //________________________________________________________________________
1259 void AliAnalysisTaskMuonResolution::ZoomRight(TH1* h, Double_t fractionCut)
1260 {
1261   /// Reduce the range of the histogram by removing a given fration of the statistic on the right side
1262   Int_t maxEventsCut = (Int_t) (fractionCut * h->GetEntries());
1263   Int_t nBins = h->GetNbinsX();
1264   
1265   // set high edge
1266   Int_t maxBin;
1267   Int_t eventsCut = 0;
1268   for (maxBin = nBins; maxBin >= 1; maxBin--) {
1269     eventsCut += (Int_t) h->GetBinContent(maxBin);
1270     if (eventsCut > maxEventsCut) break;
1271   }
1272   
1273   // set new axis range
1274   h->GetXaxis()->SetRange(h->GetXaxis()->GetFirst(), ++maxBin);
1275 }
1276
1277 //________________________________________________________________________
1278 void AliAnalysisTaskMuonResolution::GetMean(TH1* h, Double_t& mean, Double_t& meanErr, TGraphErrors* g, Int_t i, Double_t x, Bool_t zoom, Bool_t enableFit)
1279 {
1280   /// Fill graph with the mean value and the corresponding error (zooming if required)
1281   
1282   if (h->GetEntries() < fgkMinEntries) { // not enough entries
1283     
1284     mean = 0.;
1285     meanErr = 0.;
1286     
1287   } else if (enableFit && fGaus) { // take the mean of a gaussian fit
1288     
1289     fGaus->SetParameters(h->GetEntries(), 0., 0.1);
1290     
1291     h->Fit("fGaus", "WWNQ");
1292     
1293     mean = fGaus->GetParameter(1);
1294     meanErr = fGaus->GetParError(1);
1295     
1296   } else { // take the mean of the distribution
1297     
1298     Int_t firstBin = h->GetXaxis()->GetFirst();
1299     Int_t lastBin = h->GetXaxis()->GetLast();
1300     
1301     if (zoom) Zoom(h);
1302     
1303     mean = h->GetMean();
1304     meanErr = h->GetMeanError();
1305     
1306     if (zoom) h->GetXaxis()->SetRange(firstBin,lastBin);
1307     
1308   }
1309   
1310   // fill graph if required
1311   if (g) {
1312     g->SetPoint(i, x, mean);
1313     g->SetPointError(i, 0., meanErr);
1314   }
1315   
1316 }
1317
1318 //________________________________________________________________________
1319 void AliAnalysisTaskMuonResolution::GetRMS(TH1* h, Double_t& rms, Double_t& rmsErr, TGraphErrors* g, Int_t i, Double_t x, Bool_t zoom)
1320 {
1321   /// Return the dispersion value and the corresponding error (zooming if required) and fill graph if !=0x0
1322   
1323   if (h->GetEntries() < fgkMinEntries) { // not enough entries
1324     
1325     rms = 0.;
1326     rmsErr = 0.;
1327     
1328   } else if (fGaus) { // take the sigma of a gaussian fit
1329     
1330     fGaus->SetParameters(h->GetEntries(), 0., 0.1);
1331     
1332     h->Fit("fGaus", "WWNQ");
1333     
1334     rms = fGaus->GetParameter(2);
1335     rmsErr = fGaus->GetParError(2);
1336     
1337   } else { // take the RMS of the distribution
1338     
1339     Int_t firstBin = h->GetXaxis()->GetFirst();
1340     Int_t lastBin = h->GetXaxis()->GetLast();
1341     
1342     if (zoom) Zoom(h);
1343     
1344     rms = h->GetRMS();
1345     rmsErr = h->GetRMSError();
1346     
1347     if (zoom) h->GetXaxis()->SetRange(firstBin,lastBin);
1348     
1349   }
1350   
1351   // fill graph if required
1352   if (g) {
1353     g->SetPoint(i, x, rms);
1354     g->SetPointError(i, 0., rmsErr);
1355   }
1356   
1357 }
1358
1359 //________________________________________________________________________
1360 void AliAnalysisTaskMuonResolution::FillSigmaClusterVsP(const TH2* hIn, const TH2* hOut, TGraphErrors* g, Bool_t zoom)
1361 {
1362   /// Fill graph with cluster resolution from combined residuals with cluster in/out (zooming if required)
1363   Double_t sigmaIn, sigmaInErr, sigmaOut, sigmaOutErr, clusterRes, clusterResErr;
1364   for (Int_t j = 1; j <= hIn->GetNbinsX(); j++) {
1365     TH1D* tmp = hIn->ProjectionY("tmp",j,j,"e");
1366     GetRMS(tmp, sigmaIn, sigmaInErr, 0x0, 0, 0., zoom);
1367     delete tmp;
1368     tmp = hOut->ProjectionY("tmp",j,j,"e");
1369     GetRMS(tmp, sigmaOut, sigmaOutErr, 0x0, 0, 0., zoom);
1370     delete tmp;
1371     Double_t p = 0.5 * (hIn->GetBinLowEdge(j) + hIn->GetBinLowEdge(j+1));
1372     Double_t pErr = p - hIn->GetBinLowEdge(j);
1373     clusterRes = TMath::Sqrt(sigmaIn*sigmaOut);
1374     //clusterResErr = (clusterRes > 0.) ? 0.5 * TMath::Sqrt(sigmaInErr*sigmaInErr*sigmaOut*sigmaOut + sigmaIn*sigmaIn*sigmaOutErr*sigmaOutErr) / clusterRes : 0.;
1375     clusterResErr = TMath::Sqrt(sigmaInErr*sigmaOutErr);
1376     g->SetPoint(j, p, clusterRes);
1377     g->SetPointError(j, pErr, clusterResErr);
1378   }
1379 }
1380
1381 //__________________________________________________________________________
1382 void AliAnalysisTaskMuonResolution::Cov2CovP(const AliMUONTrackParam &param, TMatrixD &covP)
1383 {
1384   /// change coordinate system: (X, SlopeX, Y, SlopeY, q/Pyz) -> (X, Y, pX, pY, pZ)
1385   /// parameters (param) are given in the (X, SlopeX, Y, SlopeY, q/Pyz) coordinate system
1386   
1387   // Get useful parameters
1388   Double_t slopeX = param.GetNonBendingSlope();
1389   Double_t slopeY = param.GetBendingSlope();
1390   Double_t qOverPYZ = param.GetInverseBendingMomentum();
1391   Double_t pZ = param.Pz();
1392   
1393   // compute Jacobian to change the coordinate system from (X,SlopeX,Y,SlopeY,c/pYZ) to (X,Y,pX,pY,pZ)
1394   Double_t dpZdSlopeY = - qOverPYZ * qOverPYZ * pZ * pZ * pZ * slopeY;
1395   Double_t dpZdQOverPYZ = (qOverPYZ != 0.) ? - pZ / qOverPYZ : - FLT_MAX;
1396   TMatrixD jacob(5,5);
1397   jacob.Zero();
1398   jacob(0,0) = 1.;
1399   jacob(1,2) = 1.;
1400   jacob(2,1) = pZ;
1401   jacob(2,3) = slopeX * dpZdSlopeY;
1402   jacob(2,4) = slopeX * dpZdQOverPYZ;
1403   jacob(3,3) = pZ + slopeY * dpZdSlopeY;
1404   jacob(3,4) = slopeY * dpZdQOverPYZ;
1405   jacob(4,3) = dpZdSlopeY;
1406   jacob(4,4) = dpZdQOverPYZ;
1407   
1408   // compute covariances in new coordinate system
1409   TMatrixD tmp(param.GetCovariances(),TMatrixD::kMultTranspose,jacob);
1410   covP.Mult(jacob,tmp);
1411 }
1412
1413 //__________________________________________________________________________
1414 UInt_t AliAnalysisTaskMuonResolution::BuildTriggerWord(const TString& firedTriggerClasses)
1415 {
1416   /// build the trigger word from the fired trigger classes and the list of selectable trigger
1417   
1418   UInt_t word = 0;
1419   
1420   TObjString* trigClasseName = 0x0;
1421   TIter nextTrigger(fSelectTriggerClass);
1422   while ((trigClasseName = static_cast<TObjString*>(nextTrigger()))) {
1423     
1424     TRegexp GenericTriggerClasseName(trigClasseName->String());
1425     if (firedTriggerClasses.Contains(GenericTriggerClasseName)) word |= trigClasseName->GetUniqueID();
1426     
1427   }
1428   
1429   return word;
1430 }
1431