1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
16 /* $Id: AliEMCALRecoUtils.cxx 33808 2009-07-15 09:48:08Z gconesab $ */
18 ///////////////////////////////////////////////////////////////////////////////
20 // Class AliEMCALRecoUtils
21 // Some utilities to recalculate the cluster position or energy linearity
24 // Author: Gustavo Conesa (LPSC- Grenoble)
25 // Track matching part: Rongrong Ma (Yale)
27 ///////////////////////////////////////////////////////////////////////////////
30 // standard C++ includes
31 //#include <Riostream.h>
34 #include <TGeoManager.h>
35 #include <TGeoMatrix.h>
40 #include "TObjArray.h"
43 #include "AliVCluster.h"
44 #include "AliVCaloCells.h"
45 #include "AliVEvent.h"
48 #include "AliESDEvent.h"
49 #include "AliAODEvent.h"
50 #include "AliESDtrack.h"
51 #include "AliAODTrack.h"
52 #include "AliExternalTrackParam.h"
53 #include "AliESDfriendTrack.h"
54 #include "AliTrackerBase.h"
57 #include "AliEMCALRecoUtils.h"
58 #include "AliEMCALGeometry.h"
59 #include "AliEMCALTrack.h"
60 #include "AliEMCALCalibTimeDepCorrection.h"
61 #include "AliEMCALPIDUtils.h"
63 ClassImp(AliEMCALRecoUtils)
65 //______________________________________________
66 AliEMCALRecoUtils::AliEMCALRecoUtils():
67 fNonLinearityFunction (kNoCorrection), fParticleType(kPhoton),
68 fPosAlgo(kUnchanged),fW0(4.), fNonLinearThreshold(30),
69 fRecalibration(kFALSE), fEMCALRecalibrationFactors(),
70 fRemoveBadChannels(kFALSE), fRecalDistToBadChannels(kFALSE), fEMCALBadChannelMap(),
71 fNCellsFromEMCALBorder(0), fNoEMCALBorderAtEta0(kTRUE),
73 fMatchedTrackIndex(0x0), fMatchedClusterIndex(0x0),
74 fResidualEta(0x0), fResidualPhi(0x0), fCutEtaPhiSum(kTRUE), fCutEtaPhiSeparate(kFALSE), fCutR(0.1), fCutEta(0.02), fCutPhi(0.04), fMass(0.139), fStep(50),
75 fRejectExoticCluster(kFALSE),
76 fTrackCutsType(kTPCOnlyCut), fCutMinTrackPt(0), fCutMinNClusterTPC(-1), fCutMinNClusterITS(-1), fCutMaxChi2PerClusterTPC(1e10), fCutMaxChi2PerClusterITS(1e10),
77 fCutRequireTPCRefit(kFALSE), fCutRequireITSRefit(kFALSE), fCutAcceptKinkDaughters(kFALSE),
78 fCutMaxDCAToVertexXY(1e10), fCutMaxDCAToVertexZ(1e10),fCutDCAToVertex2D(kFALSE),fPIDUtils(),
79 fUseTimeCorrectionFactors(kFALSE), fTimeCorrectionFactorsSet(kFALSE)
83 // Initialize all constant values which have to be used
84 // during Reco algorithm execution
87 //Misalignment matrices
88 for(Int_t i = 0; i < 15 ; i++) {
89 fMisalTransShift[i] = 0.;
90 fMisalRotShift[i] = 0.;
94 for(Int_t i = 0; i < 7 ; i++) fNonLinearityParams[i] = 0.;
96 //For kBeamTestCorrected case, but default is no correction
97 fNonLinearityParams[0] = 0.99078;
98 fNonLinearityParams[1] = 0.161499;
99 fNonLinearityParams[2] = 0.655166;
100 fNonLinearityParams[3] = 0.134101;
101 fNonLinearityParams[4] = 163.282;
102 fNonLinearityParams[5] = 23.6904;
103 fNonLinearityParams[6] = 0.978;
105 //For kPi0GammaGamma case
106 //fNonLinearityParams[0] = 0.1457/0.1349766/1.038;
107 //fNonLinearityParams[1] = -0.02024/0.1349766/1.038;
108 //fNonLinearityParams[2] = 1.046;
111 fMatchedTrackIndex = new TArrayI();
112 fMatchedClusterIndex = new TArrayI();
113 fResidualPhi = new TArrayF();
114 fResidualEta = new TArrayF();
117 fPIDUtils = new AliEMCALPIDUtils();
120 //______________________________________________________________________
121 AliEMCALRecoUtils::AliEMCALRecoUtils(const AliEMCALRecoUtils & reco)
122 : TNamed(reco), fNonLinearityFunction(reco.fNonLinearityFunction),
123 fParticleType(reco.fParticleType), fPosAlgo(reco.fPosAlgo), fW0(reco.fW0), fNonLinearThreshold(reco.fNonLinearThreshold),
124 fRecalibration(reco.fRecalibration),fEMCALRecalibrationFactors(reco.fEMCALRecalibrationFactors),
125 fRemoveBadChannels(reco.fRemoveBadChannels),fRecalDistToBadChannels(reco.fRecalDistToBadChannels),
126 fEMCALBadChannelMap(reco.fEMCALBadChannelMap),
127 fNCellsFromEMCALBorder(reco.fNCellsFromEMCALBorder),fNoEMCALBorderAtEta0(reco.fNoEMCALBorderAtEta0),
128 fAODFilterMask(reco.fAODFilterMask),
129 fMatchedTrackIndex(reco.fMatchedTrackIndex?new TArrayI(*reco.fMatchedTrackIndex):0x0),
130 fMatchedClusterIndex(reco.fMatchedClusterIndex?new TArrayI(*reco.fMatchedClusterIndex):0x0),
131 fResidualEta(reco.fResidualEta?new TArrayF(*reco.fResidualEta):0x0),
132 fResidualPhi(reco.fResidualPhi?new TArrayF(*reco.fResidualPhi):0x0),
133 fCutEtaPhiSum(reco.fCutEtaPhiSum), fCutEtaPhiSeparate(reco.fCutEtaPhiSeparate), fCutR(reco.fCutR), fCutEta(reco.fCutEta), fCutPhi(reco.fCutPhi),
134 fMass(reco.fMass), fStep(reco.fStep),
135 fRejectExoticCluster(reco.fRejectExoticCluster),
136 fTrackCutsType(reco.fTrackCutsType), fCutMinTrackPt(reco.fCutMinTrackPt), fCutMinNClusterTPC(reco.fCutMinNClusterTPC), fCutMinNClusterITS(reco.fCutMinNClusterITS),
137 fCutMaxChi2PerClusterTPC(reco.fCutMaxChi2PerClusterTPC), fCutMaxChi2PerClusterITS(reco.fCutMaxChi2PerClusterITS),
138 fCutRequireTPCRefit(reco.fCutRequireTPCRefit), fCutRequireITSRefit(reco.fCutRequireITSRefit),
139 fCutAcceptKinkDaughters(reco.fCutAcceptKinkDaughters),
140 fCutMaxDCAToVertexXY(reco.fCutMaxDCAToVertexXY), fCutMaxDCAToVertexZ(reco.fCutMaxDCAToVertexZ),fCutDCAToVertex2D(reco.fCutDCAToVertex2D),
141 fPIDUtils(reco.fPIDUtils),
142 fUseTimeCorrectionFactors(reco.fUseTimeCorrectionFactors), fTimeCorrectionFactorsSet(reco.fTimeCorrectionFactorsSet)
146 for(Int_t i = 0; i < 15 ; i++) {
147 fMisalRotShift[i] = reco.fMisalRotShift[i];
148 fMisalTransShift[i] = reco.fMisalTransShift[i];
150 for(Int_t i = 0; i < 7 ; i++) fNonLinearityParams[i] = reco.fNonLinearityParams[i];
155 //______________________________________________________________________
156 AliEMCALRecoUtils & AliEMCALRecoUtils::operator = (const AliEMCALRecoUtils & reco)
158 //Assignment operator
160 if(this == &reco)return *this;
161 ((TNamed *)this)->operator=(reco);
163 fNonLinearityFunction = reco.fNonLinearityFunction;
164 fParticleType = reco.fParticleType;
165 fPosAlgo = reco.fPosAlgo;
167 fNonLinearThreshold = reco.fNonLinearThreshold;
168 fRecalibration = reco.fRecalibration;
169 fEMCALRecalibrationFactors = reco.fEMCALRecalibrationFactors;
170 fRemoveBadChannels = reco.fRemoveBadChannels;
171 fRecalDistToBadChannels = reco.fRecalDistToBadChannels;
172 fEMCALBadChannelMap = reco.fEMCALBadChannelMap;
173 fNCellsFromEMCALBorder = reco.fNCellsFromEMCALBorder;
174 fNoEMCALBorderAtEta0 = reco.fNoEMCALBorderAtEta0;
177 for(Int_t i = 0; i < 15 ; i++) {fMisalTransShift[i] = reco.fMisalTransShift[i]; fMisalRotShift[i] = reco.fMisalRotShift[i];}
178 for(Int_t i = 0; i < 7 ; i++) fNonLinearityParams[i] = reco.fNonLinearityParams[i];
180 fAODFilterMask = reco.fAODFilterMask;
182 fCutEtaPhiSum = reco.fCutEtaPhiSum;
183 fCutEtaPhiSeparate = reco.fCutEtaPhiSeparate;
185 fCutEta = reco.fCutEta;
186 fCutPhi = reco.fCutPhi;
189 fRejectExoticCluster = reco.fRejectExoticCluster;
191 fTrackCutsType = reco.fTrackCutsType;
192 fCutMinTrackPt = reco.fCutMinTrackPt;
193 fCutMinNClusterTPC = reco.fCutMinNClusterTPC;
194 fCutMinNClusterITS = reco.fCutMinNClusterITS;
195 fCutMaxChi2PerClusterTPC = reco.fCutMaxChi2PerClusterTPC;
196 fCutMaxChi2PerClusterITS = reco.fCutMaxChi2PerClusterITS;
197 fCutRequireTPCRefit = reco.fCutRequireTPCRefit;
198 fCutRequireITSRefit = reco.fCutRequireITSRefit;
199 fCutAcceptKinkDaughters = reco.fCutAcceptKinkDaughters;
200 fCutMaxDCAToVertexXY = reco.fCutMaxDCAToVertexXY;
201 fCutMaxDCAToVertexZ = reco.fCutMaxDCAToVertexZ;
202 fCutDCAToVertex2D = reco.fCutDCAToVertex2D;
204 fPIDUtils = reco.fPIDUtils;
206 fUseTimeCorrectionFactors = reco.fUseTimeCorrectionFactors;
207 fTimeCorrectionFactorsSet = reco.fTimeCorrectionFactorsSet;
210 if(reco.fResidualEta){
211 // assign or copy construct
213 *fResidualEta = *reco.fResidualEta;
215 else fResidualEta = new TArrayF(*reco.fResidualEta);
218 if(fResidualEta)delete fResidualEta;
222 if(reco.fResidualPhi){
223 // assign or copy construct
225 *fResidualPhi = *reco.fResidualPhi;
227 else fResidualPhi = new TArrayF(*reco.fResidualPhi);
230 if(fResidualPhi)delete fResidualPhi;
234 if(reco.fMatchedTrackIndex){
235 // assign or copy construct
236 if(fMatchedTrackIndex){
237 *fMatchedTrackIndex = *reco.fMatchedTrackIndex;
239 else fMatchedTrackIndex = new TArrayI(*reco.fMatchedTrackIndex);
242 if(fMatchedTrackIndex)delete fMatchedTrackIndex;
243 fMatchedTrackIndex = 0;
246 if(reco.fMatchedClusterIndex){
247 // assign or copy construct
248 if(fMatchedClusterIndex){
249 *fMatchedClusterIndex = *reco.fMatchedClusterIndex;
251 else fMatchedClusterIndex = new TArrayI(*reco.fMatchedClusterIndex);
254 if(fMatchedClusterIndex)delete fMatchedClusterIndex;
255 fMatchedClusterIndex = 0;
262 //__________________________________________________
263 AliEMCALRecoUtils::~AliEMCALRecoUtils()
267 if(fEMCALRecalibrationFactors) {
268 fEMCALRecalibrationFactors->Clear();
269 delete fEMCALRecalibrationFactors;
272 if(fEMCALBadChannelMap) {
273 fEMCALBadChannelMap->Clear();
274 delete fEMCALBadChannelMap;
277 delete fMatchedTrackIndex ;
278 delete fMatchedClusterIndex ;
279 delete fResidualEta ;
280 delete fResidualPhi ;
284 //_______________________________________________________________
285 Bool_t AliEMCALRecoUtils::CheckCellFiducialRegion(AliEMCALGeometry* geom, AliVCluster* cluster, AliVCaloCells* cells)
287 // Given the list of AbsId of the cluster, get the maximum cell and
288 // check if there are fNCellsFromBorder from the calorimeter border
291 AliInfo("Cluster pointer null!");
295 //If the distance to the border is 0 or negative just exit accept all clusters
296 if(cells->GetType()==AliVCaloCells::kEMCALCell && fNCellsFromEMCALBorder <= 0 ) return kTRUE;
298 Int_t absIdMax = -1, iSM =-1, ieta = -1, iphi = -1;
299 Bool_t shared = kFALSE;
300 GetMaxEnergyCell(geom, cells, cluster, absIdMax, iSM, ieta, iphi, shared);
302 AliDebug(2,Form("Cluster Max AbsId %d, Cell Energy %2.2f, Cluster Energy %2.2f, Ncells from border %d, EMCAL eta=0 %d\n",
303 absIdMax, cells->GetCellAmplitude(absIdMax), cluster->E(), fNCellsFromEMCALBorder, fNoEMCALBorderAtEta0));
305 if(absIdMax==-1) return kFALSE;
307 //Check if the cell is close to the borders:
308 Bool_t okrow = kFALSE;
309 Bool_t okcol = kFALSE;
311 if(iSM < 0 || iphi < 0 || ieta < 0 ) {
312 AliFatal(Form("Negative value for super module: %d, or cell ieta: %d, or cell iphi: %d, check EMCAL geometry name\n",
318 if(iphi >= fNCellsFromEMCALBorder && iphi < 24-fNCellsFromEMCALBorder) okrow =kTRUE;
321 if(iphi >= fNCellsFromEMCALBorder && iphi < 12-fNCellsFromEMCALBorder) okrow =kTRUE;
325 if(!fNoEMCALBorderAtEta0){
326 if(ieta > fNCellsFromEMCALBorder && ieta < 48-fNCellsFromEMCALBorder) okcol =kTRUE;
330 if(ieta >= fNCellsFromEMCALBorder) okcol = kTRUE;
333 if(ieta < 48-fNCellsFromEMCALBorder) okcol = kTRUE;
337 AliDebug(2,Form("EMCAL Cluster in %d cells fiducial volume: ieta %d, iphi %d, SM %d: column? %d, row? %d\nq",
338 fNCellsFromEMCALBorder, ieta, iphi, iSM, okcol, okrow));
340 if (okcol && okrow) {
341 //printf("Accept\n");
345 //printf("Reject\n");
346 AliDebug(2,Form("Reject cluster in border, max cell : ieta %d, iphi %d, SM %d\n",ieta, iphi, iSM));
353 //_________________________________________________________________________________________________________
354 Bool_t AliEMCALRecoUtils::ClusterContainsBadChannel(AliEMCALGeometry* geom, UShort_t* cellList, const Int_t nCells){
355 // Check that in the cluster cells, there is no bad channel of those stored
356 // in fEMCALBadChannelMap or fPHOSBadChannelMap
358 if(!fRemoveBadChannels) return kFALSE;
359 if(!fEMCALBadChannelMap) return kFALSE;
364 for(Int_t iCell = 0; iCell<nCells; iCell++){
366 //Get the column and row
367 Int_t iTower = -1, iIphi = -1, iIeta = -1;
368 geom->GetCellIndex(cellList[iCell],imod,iTower,iIphi,iIeta);
369 if(fEMCALBadChannelMap->GetEntries() <= imod) continue;
370 geom->GetCellPhiEtaIndexInSModule(imod,iTower,iIphi, iIeta,irow,icol);
371 if(GetEMCALChannelStatus(imod, icol, irow)){
372 AliDebug(2,Form("Cluster with bad channel: SM %d, col %d, row %d\n",imod, icol, irow));
376 }// cell cluster loop
382 //_________________________________________________
383 Bool_t AliEMCALRecoUtils::IsExoticCluster(AliVCluster *cluster) const {
384 // Check if the cluster has high energy but small number of cells
385 // The criteria comes from Gustavo's study
389 AliInfo("Cluster pointer null!");
393 if(cluster->GetNCells()<(1+cluster->E()/3.))
399 //__________________________________________________
400 Float_t AliEMCALRecoUtils::CorrectClusterEnergyLinearity(AliVCluster* cluster){
401 // Correct cluster energy from non linearity functions
404 AliInfo("Cluster pointer null!");
409 Float_t energy = cluster->E();
411 switch (fNonLinearityFunction) {
415 //Non-Linearity correction (from MC with function ([0]*exp(-[1]/E))+(([2]/([3]*2.*TMath::Pi())*exp(-(E-[4])^2/(2.*[3]^2)))))
416 //Double_t fNonLinearityParams[0] = 1.014;
417 //Double_t fNonLinearityParams[1] = -0.03329;
418 //Double_t fNonLinearityParams[2] = -0.3853;
419 //Double_t fNonLinearityParams[3] = 0.5423;
420 //Double_t fNonLinearityParams[4] = -0.4335;
421 energy *= (fNonLinearityParams[0]*exp(-fNonLinearityParams[1]/energy))+
422 ((fNonLinearityParams[2]/(fNonLinearityParams[3]*2.*TMath::Pi())*
423 exp(-(energy-fNonLinearityParams[4])*(energy-fNonLinearityParams[4])/(2.*fNonLinearityParams[3]*fNonLinearityParams[3]))));
429 //Non-Linearity correction (from Olga Data with function p0+p1*exp(-p2*E))
430 //Double_t fNonLinearityParams[0] = 1.04;
431 //Double_t fNonLinearityParams[1] = -0.1445;
432 //Double_t fNonLinearityParams[2] = 1.046;
433 energy /= (fNonLinearityParams[0]+fNonLinearityParams[1]*exp(-fNonLinearityParams[2]*energy)); //Olga function
437 case kPi0GammaConversion:
439 //Non-Linearity correction (Nicolas from Dimitri Data with function C*[1-a*exp(-b*E)])
440 //fNonLinearityParams[0] = 0.139393/0.1349766;
441 //fNonLinearityParams[1] = 0.0566186;
442 //fNonLinearityParams[2] = 0.982133;
443 energy /= fNonLinearityParams[0]*(1-fNonLinearityParams[1]*exp(-fNonLinearityParams[2]*energy));
450 //From beam test, Alexei's results, for different ZS thresholds
451 // th=30 MeV; th = 45 MeV; th = 75 MeV
452 //fNonLinearityParams[0] = 1.007; 1.003; 1.002
453 //fNonLinearityParams[1] = 0.894; 0.719; 0.797
454 //fNonLinearityParams[2] = 0.246; 0.334; 0.358
455 //Rescale the param[0] with 1.03
456 energy /= fNonLinearityParams[0]/(1+fNonLinearityParams[1]*exp(-energy/fNonLinearityParams[2]));
461 case kBeamTestCorrected:
463 //From beam test, corrected for material between beam and EMCAL
464 //fNonLinearityParams[0] = 0.99078
465 //fNonLinearityParams[1] = 0.161499;
466 //fNonLinearityParams[2] = 0.655166;
467 //fNonLinearityParams[3] = 0.134101;
468 //fNonLinearityParams[4] = 163.282;
469 //fNonLinearityParams[5] = 23.6904;
470 //fNonLinearityParams[6] = 0.978;
471 energy *= fNonLinearityParams[6]/(fNonLinearityParams[0]*(1./(1.+fNonLinearityParams[1]*exp(-energy/fNonLinearityParams[2]))*1./(1.+fNonLinearityParams[3]*exp((energy-fNonLinearityParams[4])/fNonLinearityParams[5]))));
477 AliDebug(2,"No correction on the energy\n");
485 //__________________________________________________
486 void AliEMCALRecoUtils::InitNonLinearityParam()
488 //Initialising Non Linearity Parameters
490 if(fNonLinearityFunction == kPi0MC)
492 fNonLinearityParams[0] = 1.014;
493 fNonLinearityParams[1] = -0.03329;
494 fNonLinearityParams[2] = -0.3853;
495 fNonLinearityParams[3] = 0.5423;
496 fNonLinearityParams[4] = -0.4335;
499 if(fNonLinearityFunction == kPi0GammaGamma)
501 fNonLinearityParams[0] = 1.04;
502 fNonLinearityParams[1] = -0.1445;
503 fNonLinearityParams[2] = 1.046;
506 if(fNonLinearityFunction == kPi0GammaConversion)
508 fNonLinearityParams[0] = 0.139393;
509 fNonLinearityParams[1] = 0.0566186;
510 fNonLinearityParams[2] = 0.982133;
513 if(fNonLinearityFunction == kBeamTest)
515 if(fNonLinearThreshold == 30)
517 fNonLinearityParams[0] = 1.007;
518 fNonLinearityParams[1] = 0.894;
519 fNonLinearityParams[2] = 0.246;
521 if(fNonLinearThreshold == 45)
523 fNonLinearityParams[0] = 1.003;
524 fNonLinearityParams[1] = 0.719;
525 fNonLinearityParams[2] = 0.334;
527 if(fNonLinearThreshold == 75)
529 fNonLinearityParams[0] = 1.002;
530 fNonLinearityParams[1] = 0.797;
531 fNonLinearityParams[2] = 0.358;
535 if(fNonLinearityFunction == kBeamTestCorrected)
537 fNonLinearityParams[0] = 0.99078;
538 fNonLinearityParams[1] = 0.161499;
539 fNonLinearityParams[2] = 0.655166;
540 fNonLinearityParams[3] = 0.134101;
541 fNonLinearityParams[4] = 163.282;
542 fNonLinearityParams[5] = 23.6904;
543 fNonLinearityParams[6] = 0.978;
547 //__________________________________________________
548 Float_t AliEMCALRecoUtils::GetDepth(const Float_t energy, const Int_t iParticle, const Int_t iSM) const
550 //Calculate shower depth for a given cluster energy and particle type
560 depth = x0 * (TMath::Log(energy*1000/ ecr) + 0.5); //Multiply energy by 1000 to transform to MeV
564 depth = x0 * (TMath::Log(energy*1000/ ecr) - 0.5); //Multiply energy by 1000 to transform to MeV
571 gGeoManager->cd("ALIC_1/XEN1_1");
572 TGeoNode *geoXEn1 = gGeoManager->GetCurrentNode();
573 TGeoNodeMatrix *geoSM = dynamic_cast<TGeoNodeMatrix *>(geoXEn1->GetDaughter(iSM));
575 TGeoVolume *geoSMVol = geoSM->GetVolume();
576 TGeoShape *geoSMShape = geoSMVol->GetShape();
577 TGeoBBox *geoBox = dynamic_cast<TGeoBBox *>(geoSMShape);
578 if(geoBox) depth = 0.5 * geoBox->GetDX()*2 ;
579 else AliFatal("Null GEANT box");
580 }else AliFatal("NULL GEANT node matrix");
583 depth = x0 * (TMath::Log(energy*1000 / ecr) - 0.5); //Multiply energy by 1000 to transform to MeV
589 depth = x0 * (TMath::Log(energy*1000 / ecr) + 0.5); //Multiply energy by 1000 to transform to MeV
596 //__________________________________________________
597 void AliEMCALRecoUtils::GetMaxEnergyCell(AliEMCALGeometry *geom, AliVCaloCells* cells, AliVCluster* clu,
598 Int_t & absId, Int_t& iSupMod, Int_t& ieta, Int_t& iphi, Bool_t &shared)
600 //For a given CaloCluster gets the absId of the cell
601 //with maximum energy deposit.
604 Double_t eCell = -1.;
605 Float_t fraction = 1.;
606 Float_t recalFactor = 1.;
607 Int_t cellAbsId = -1 ;
615 AliInfo("Cluster pointer null!");
616 absId=-1; iSupMod0=-1, ieta = -1; iphi = -1; shared = -1;
620 for (Int_t iDig=0; iDig< clu->GetNCells(); iDig++) {
621 cellAbsId = clu->GetCellAbsId(iDig);
622 fraction = clu->GetCellAmplitudeFraction(iDig);
623 //printf("a Cell %d, id, %d, amp %f, fraction %f\n",iDig,cellAbsId,cells->GetCellAmplitude(cellAbsId),fraction);
624 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
625 geom->GetCellIndex(cellAbsId,iSupMod,iTower,iIphi,iIeta);
626 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi, iIeta,iphi,ieta);
627 if(iDig==0) iSupMod0=iSupMod;
628 else if(iSupMod0!=iSupMod) {
630 //printf("AliEMCALRecoUtils::GetMaxEnergyCell() - SHARED CLUSTER\n");
632 if(IsRecalibrationOn()) {
633 recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
635 eCell = cells->GetCellAmplitude(cellAbsId)*fraction*recalFactor;
636 //printf("b Cell %d, id, %d, amp %f, fraction %f\n",iDig,cellAbsId,eCell,fraction);
640 //printf("\t new max: cell %d, e %f, ecell %f\n",maxId, eMax,eCell);
644 //Get from the absid the supermodule, tower and eta/phi numbers
645 geom->GetCellIndex(absId,iSupMod,iTower,iIphi,iIeta);
646 //Gives SuperModule and Tower numbers
647 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,
648 iIphi, iIeta,iphi,ieta);
649 //printf("Max id %d, iSM %d, col %d, row %d\n",absId,iSupMod,ieta,iphi);
650 //printf("Max end---\n");
654 //________________________________________________________________
655 void AliEMCALRecoUtils::InitEMCALRecalibrationFactors(){
656 //Init EMCAL recalibration factors
657 AliDebug(2,"AliCalorimeterUtils::InitEMCALRecalibrationFactors()");
658 //In order to avoid rewriting the same histograms
659 Bool_t oldStatus = TH1::AddDirectoryStatus();
660 TH1::AddDirectory(kFALSE);
662 fEMCALRecalibrationFactors = new TObjArray(10);
663 for (int i = 0; i < 10; i++) fEMCALRecalibrationFactors->Add(new TH2F(Form("EMCALRecalFactors_SM%d",i),Form("EMCALRecalFactors_SM%d",i), 48, 0, 48, 24, 0, 24));
664 //Init the histograms with 1
665 for (Int_t sm = 0; sm < 10; sm++) {
666 for (Int_t i = 0; i < 48; i++) {
667 for (Int_t j = 0; j < 24; j++) {
668 SetEMCALChannelRecalibrationFactor(sm,i,j,1.);
672 fEMCALRecalibrationFactors->SetOwner(kTRUE);
673 fEMCALRecalibrationFactors->Compress();
675 //In order to avoid rewriting the same histograms
676 TH1::AddDirectory(oldStatus);
680 //________________________________________________________________
681 void AliEMCALRecoUtils::InitEMCALBadChannelStatusMap(){
682 //Init EMCAL bad channels map
683 AliDebug(2,"AliEMCALRecoUtils::InitEMCALBadChannelStatusMap()");
684 //In order to avoid rewriting the same histograms
685 Bool_t oldStatus = TH1::AddDirectoryStatus();
686 TH1::AddDirectory(kFALSE);
688 fEMCALBadChannelMap = new TObjArray(10);
689 //TH2F * hTemp = new TH2I("EMCALBadChannelMap","EMCAL SuperModule bad channel map", 48, 0, 48, 24, 0, 24);
690 for (int i = 0; i < 10; i++) {
691 fEMCALBadChannelMap->Add(new TH2I(Form("EMCALBadChannelMap_Mod%d",i),Form("EMCALBadChannelMap_Mod%d",i), 48, 0, 48, 24, 0, 24));
696 fEMCALBadChannelMap->SetOwner(kTRUE);
697 fEMCALBadChannelMap->Compress();
699 //In order to avoid rewriting the same histograms
700 TH1::AddDirectory(oldStatus);
703 //________________________________________________________________
704 void AliEMCALRecoUtils::RecalibrateClusterEnergy(AliEMCALGeometry* geom, AliVCluster * cluster, AliVCaloCells * cells){
705 // Recalibrate the cluster energy, considering the recalibration map and the energy of the cells that compose the cluster.
708 AliInfo("Cluster pointer null!");
712 //Get the cluster number of cells and list of absId, check what kind of cluster do we have.
713 UShort_t * index = cluster->GetCellsAbsId() ;
714 Double_t * fraction = cluster->GetCellsAmplitudeFraction() ;
715 Int_t ncells = cluster->GetNCells();
717 //Initialize some used variables
720 Int_t icol = -1, irow = -1, imod=1;
721 Float_t factor = 1, frac = 0;
723 //Loop on the cells, get the cell amplitude and recalibration factor, multiply and and to the new energy
724 for(Int_t icell = 0; icell < ncells; icell++){
725 absId = index[icell];
726 frac = fraction[icell];
727 if(frac < 1e-5) frac = 1; //in case of EMCAL, this is set as 0 since unfolding is off
728 Int_t iTower = -1, iIphi = -1, iIeta = -1;
729 geom->GetCellIndex(absId,imod,iTower,iIphi,iIeta);
730 if(fEMCALRecalibrationFactors->GetEntries() <= imod) continue;
731 geom->GetCellPhiEtaIndexInSModule(imod,iTower,iIphi, iIeta,irow,icol);
732 factor = GetEMCALChannelRecalibrationFactor(imod,icol,irow);
733 AliDebug(2,Form("AliEMCALRecoUtils::RecalibrateClusterEnergy - recalibrate cell: module %d, col %d, row %d, cell fraction %f,recalibration factor %f, cell energy %f\n",
734 imod,icol,irow,frac,factor,cells->GetCellAmplitude(absId)));
736 energy += cells->GetCellAmplitude(absId)*factor*frac;
740 AliDebug(2,Form("AliEMCALRecoUtils::RecalibrateClusterEnergy - Energy before %f, after %f\n",cluster->E(),energy));
742 cluster->SetE(energy);
747 //__________________________________________________
748 void AliEMCALRecoUtils::RecalculateClusterPosition(AliEMCALGeometry *geom, AliVCaloCells* cells, AliVCluster* clu)
750 //For a given CaloCluster recalculates the position for a given set of misalignment shifts and puts it again in the CaloCluster.
753 AliInfo("Cluster pointer null!");
757 if (fPosAlgo==kPosTowerGlobal) RecalculateClusterPositionFromTowerGlobal( geom, cells, clu);
758 else if(fPosAlgo==kPosTowerIndex) RecalculateClusterPositionFromTowerIndex ( geom, cells, clu);
759 else AliDebug(2,"Algorithm to recalculate position not selected, do nothing.");
763 //__________________________________________________
764 void AliEMCALRecoUtils::RecalculateClusterPositionFromTowerGlobal(AliEMCALGeometry *geom, AliVCaloCells* cells, AliVCluster* clu)
766 // For a given CaloCluster recalculates the position for a given set of misalignment shifts and puts it again in the CaloCluster.
767 // The algorithm is a copy of what is done in AliEMCALRecPoint
770 Float_t fraction = 1.;
771 Float_t recalFactor = 1.;
774 Int_t iTower = -1, iIphi = -1, iIeta = -1;
775 Int_t iSupModMax = -1, iSM=-1, iphi = -1, ieta = -1;
776 Float_t weight = 0., totalWeight=0.;
777 Float_t newPos[3] = {0,0,0};
778 Double_t pLocal[3], pGlobal[3];
779 Bool_t shared = kFALSE;
781 Float_t clEnergy = clu->E(); //Energy already recalibrated previously
782 GetMaxEnergyCell(geom, cells, clu, absId, iSupModMax, ieta, iphi,shared);
783 Double_t depth = GetDepth(clEnergy,fParticleType,iSupModMax) ;
785 //printf("** Cluster energy %f, ncells %d, depth %f\n",clEnergy,clu->GetNCells(),depth);
787 for (Int_t iDig=0; iDig< clu->GetNCells(); iDig++) {
788 absId = clu->GetCellAbsId(iDig);
789 fraction = clu->GetCellAmplitudeFraction(iDig);
790 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
791 geom->GetCellIndex(absId,iSM,iTower,iIphi,iIeta);
792 geom->GetCellPhiEtaIndexInSModule(iSM,iTower,iIphi, iIeta,iphi,ieta);
794 if(IsRecalibrationOn()) {
795 recalFactor = GetEMCALChannelRecalibrationFactor(iSM,ieta,iphi);
797 eCell = cells->GetCellAmplitude(absId)*fraction*recalFactor;
799 weight = GetCellWeight(eCell,clEnergy);
800 //printf("cell energy %f, weight %f\n",eCell,weight);
801 totalWeight += weight;
802 geom->RelPosCellInSModule(absId,depth,pLocal[0],pLocal[1],pLocal[2]);
803 //printf("pLocal (%f,%f,%f), SM %d, absId %d\n",pLocal[0],pLocal[1],pLocal[2],iSupModMax,absId);
804 geom->GetGlobal(pLocal,pGlobal,iSupModMax);
805 //printf("pLocal (%f,%f,%f)\n",pGlobal[0],pGlobal[1],pGlobal[2]);
807 for(int i=0; i<3; i++ ) newPos[i] += (weight*pGlobal[i]);
812 for(int i=0; i<3; i++ ) newPos[i] /= totalWeight;
815 //Float_t pos[]={0,0,0};
816 //clu->GetPosition(pos);
817 //printf("OldPos : %2.3f,%2.3f,%2.3f\n",pos[0],pos[1],pos[2]);
818 //printf("NewPos : %2.3f,%2.3f,%2.3f\n",newPos[0],newPos[1],newPos[2]);
820 if(iSupModMax > 1) {//sector 1
821 newPos[0] +=fMisalTransShift[3];//-=3.093;
822 newPos[1] +=fMisalTransShift[4];//+=6.82;
823 newPos[2] +=fMisalTransShift[5];//+=1.635;
824 //printf(" + : %2.3f,%2.3f,%2.3f\n",fMisalTransShift[3],fMisalTransShift[4],fMisalTransShift[5]);
828 newPos[0] +=fMisalTransShift[0];//+=1.134;
829 newPos[1] +=fMisalTransShift[1];//+=8.2;
830 newPos[2] +=fMisalTransShift[2];//+=1.197;
831 //printf(" + : %2.3f,%2.3f,%2.3f\n",fMisalTransShift[0],fMisalTransShift[1],fMisalTransShift[2]);
834 //printf("NewPos : %2.3f,%2.3f,%2.3f\n",newPos[0],newPos[1],newPos[2]);
836 clu->SetPosition(newPos);
840 //__________________________________________________
841 void AliEMCALRecoUtils::RecalculateClusterPositionFromTowerIndex(AliEMCALGeometry *geom, AliVCaloCells* cells, AliVCluster* clu)
843 // For a given CaloCluster recalculates the position for a given set of misalignment shifts and puts it again in the CaloCluster.
844 // The algorithm works with the tower indeces, averages the indeces and from them it calculates the global position
847 Float_t fraction = 1.;
848 Float_t recalFactor = 1.;
852 Int_t iIphi = -1, iIeta = -1;
853 Int_t iSupMod = -1, iSupModMax = -1;
854 Int_t iphi = -1, ieta =-1;
855 Bool_t shared = kFALSE;
857 Float_t clEnergy = clu->E(); //Energy already recalibrated previously.
858 GetMaxEnergyCell(geom, cells, clu, absId, iSupModMax, ieta, iphi,shared);
859 Float_t depth = GetDepth(clEnergy,fParticleType,iSupMod) ;
861 Float_t weight = 0., weightedCol = 0., weightedRow = 0., totalWeight=0.;
862 Bool_t areInSameSM = kTRUE; //exclude clusters with cells in different SMs for now
863 Int_t startingSM = -1;
865 for (Int_t iDig=0; iDig< clu->GetNCells(); iDig++) {
866 absId = clu->GetCellAbsId(iDig);
867 fraction = clu->GetCellAmplitudeFraction(iDig);
868 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
869 geom->GetCellIndex(absId,iSupMod,iTower,iIphi,iIeta);
870 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi, iIeta,iphi,ieta);
872 if (iDig==0) startingSM = iSupMod;
873 else if(iSupMod != startingSM) areInSameSM = kFALSE;
875 eCell = cells->GetCellAmplitude(absId);
877 if(IsRecalibrationOn()) {
878 recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
880 eCell = cells->GetCellAmplitude(absId)*fraction*recalFactor;
882 weight = GetCellWeight(eCell,clEnergy);
883 if(weight < 0) weight = 0;
884 totalWeight += weight;
885 weightedCol += ieta*weight;
886 weightedRow += iphi*weight;
888 //printf("Max cell? cell %d, amplitude org %f, fraction %f, recalibration %f, amplitude new %f \n",cellAbsId, cells->GetCellAmplitude(cellAbsId), fraction, recalFactor, eCell) ;
892 Float_t xyzNew[]={0.,0.,0.};
893 if(areInSameSM == kTRUE) {
894 //printf("In Same SM\n");
895 weightedCol = weightedCol/totalWeight;
896 weightedRow = weightedRow/totalWeight;
897 geom->RecalculateTowerPosition(weightedRow, weightedCol, iSupModMax, depth, fMisalTransShift, fMisalRotShift, xyzNew);
900 //printf("In Different SM\n");
901 geom->RecalculateTowerPosition(iphi, ieta, iSupModMax, depth, fMisalTransShift, fMisalRotShift, xyzNew);
904 clu->SetPosition(xyzNew);
908 //____________________________________________________________________________
909 void AliEMCALRecoUtils::RecalculateClusterDistanceToBadChannel(AliEMCALGeometry * geom, AliVCaloCells* cells, AliVCluster * cluster){
911 //re-evaluate distance to bad channel with updated bad map
913 if(!fRecalDistToBadChannels) return;
916 AliInfo("Cluster pointer null!");
920 //Get channels map of the supermodule where the cluster is.
921 Int_t absIdMax = -1, iSupMod =-1, icolM = -1, irowM = -1;
922 Bool_t shared = kFALSE;
923 GetMaxEnergyCell(geom, cells, cluster, absIdMax, iSupMod, icolM, irowM, shared);
924 TH2D* hMap = (TH2D*)fEMCALBadChannelMap->At(iSupMod);
927 Float_t minDist = 10000.;
930 //Loop on tower status map
931 for(Int_t irow = 0; irow < AliEMCALGeoParams::fgkEMCALRows; irow++){
932 for(Int_t icol = 0; icol < AliEMCALGeoParams::fgkEMCALCols; icol++){
933 //Check if tower is bad.
934 if(hMap->GetBinContent(icol,irow)==0) continue;
935 //printf("AliEMCALRecoUtils::RecalculateDistanceToBadChannels() - \n \t Bad channel in SM %d, col %d, row %d, \n \t Cluster max in col %d, row %d\n",
936 // iSupMod,icol, irow, icolM,irowM);
938 dRrow=TMath::Abs(irowM-irow);
939 dRcol=TMath::Abs(icolM-icol);
940 dist=TMath::Sqrt(dRrow*dRrow+dRcol*dRcol);
942 //printf("MIN DISTANCE TO BAD %2.2f\n",dist);
949 //In case the cluster is shared by 2 SuperModules, need to check the map of the second Super Module
954 //The only possible combinations are (0,1), (2,3) ... (8,9)
955 if(iSupMod%2) iSupMod2 = iSupMod-1;
956 else iSupMod2 = iSupMod+1;
957 hMap2 = (TH2D*)fEMCALBadChannelMap->At(iSupMod2);
959 //Loop on tower status map of second super module
960 for(Int_t irow = 0; irow < AliEMCALGeoParams::fgkEMCALRows; irow++){
961 for(Int_t icol = 0; icol < AliEMCALGeoParams::fgkEMCALCols; icol++){
962 //Check if tower is bad.
963 if(hMap2->GetBinContent(icol,irow)==0) continue;
964 //printf("AliEMCALRecoUtils::RecalculateDistanceToBadChannels(shared) - \n \t Bad channel in SM %d, col %d, row %d \n \t Cluster max in SM %d, col %d, row %d\n",
965 // iSupMod2,icol, irow,iSupMod,icolM,irowM);
967 dRrow=TMath::Abs(irow-irowM);
970 dRcol=TMath::Abs(icol-(AliEMCALGeoParams::fgkEMCALCols+icolM));
973 dRcol=TMath::Abs(AliEMCALGeoParams::fgkEMCALCols+icol-icolM);
976 dist=TMath::Sqrt(dRrow*dRrow+dRcol*dRcol);
977 if(dist < minDist) minDist = dist;
982 }// shared cluster in 2 SuperModules
984 AliDebug(2,Form("Max cluster cell (SM,col,row)=(%d %d %d) - Distance to Bad Channel %2.2f",iSupMod, icolM, irowM, minDist));
985 cluster->SetDistanceToBadChannel(minDist);
989 //____________________________________________________________________________
990 void AliEMCALRecoUtils::RecalculateClusterPID(AliVCluster * cluster){
992 //re-evaluate identification parameters with bayesian
995 AliInfo("Cluster pointer null!");
999 if ( cluster->GetM02() != 0)
1000 fPIDUtils->ComputePID(cluster->E(),cluster->GetM02());
1002 Float_t pidlist[AliPID::kSPECIESN+1];
1003 for(Int_t i = 0; i < AliPID::kSPECIESN+1; i++) pidlist[i] = fPIDUtils->GetPIDFinal(i);
1005 cluster->SetPID(pidlist);
1009 //____________________________________________________________________________
1010 void AliEMCALRecoUtils::RecalculateClusterShowerShapeParameters(AliEMCALGeometry * geom, AliVCaloCells* cells, AliVCluster * cluster)
1012 // Calculates new center of gravity in the local EMCAL-module coordinates
1013 // and tranfers into global ALICE coordinates
1014 // Calculates Dispersion and main axis
1017 AliInfo("Cluster pointer null!");
1023 Double_t eCell = 0.;
1024 Float_t fraction = 1.;
1025 Float_t recalFactor = 1.;
1033 Double_t etai = -1.;
1034 Double_t phii = -1.;
1041 Double_t xmean = 0.;
1042 Double_t zmean = 0.;
1045 for(Int_t iDigit=0; iDigit < cluster->GetNCells(); iDigit++) {
1047 //Get from the absid the supermodule, tower and eta/phi numbers
1048 geom->GetCellIndex(cluster->GetCellAbsId(iDigit),iSupMod,iTower,iIphi,iIeta);
1049 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi,iIeta, iphi,ieta);
1051 //Get the cell energy, if recalibration is on, apply factors
1052 fraction = cluster->GetCellAmplitudeFraction(iDigit);
1053 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
1054 if(IsRecalibrationOn()) {
1055 recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
1057 eCell = cells->GetCellAmplitude(cluster->GetCellAbsId(iDigit))*fraction*recalFactor;
1059 if(cluster->E() > 0 && eCell > 0){
1061 w = GetCellWeight(eCell,cluster->E());
1063 etai=(Double_t)ieta;
1064 phii=(Double_t)iphi;
1069 dxx += w * etai * etai ;
1071 dzz += w * phii * phii ;
1073 dxz += w * etai * phii ;
1077 AliError(Form("Wrong energy %f and/or amplitude %f\n", eCell, cluster->E()));
1080 //Normalize to the weight
1086 AliError(Form("Wrong weight %f\n", wtot));
1088 //Calculate dispersion
1089 for(Int_t iDigit=0; iDigit < cluster->GetNCells(); iDigit++) {
1091 //Get from the absid the supermodule, tower and eta/phi numbers
1092 geom->GetCellIndex(cluster->GetCellAbsId(iDigit),iSupMod,iTower,iIphi,iIeta);
1093 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi,iIeta, iphi,ieta);
1095 //Get the cell energy, if recalibration is on, apply factors
1096 fraction = cluster->GetCellAmplitudeFraction(iDigit);
1097 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
1098 if(IsRecalibrationOn()) {
1099 recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
1101 eCell = cells->GetCellAmplitude(cluster->GetCellAbsId(iDigit))*fraction*recalFactor;
1103 if(cluster->E() > 0 && eCell > 0){
1105 w = GetCellWeight(eCell,cluster->E());
1107 etai=(Double_t)ieta;
1108 phii=(Double_t)iphi;
1109 if(w > 0.0) d += w*((etai-xmean)*(etai-xmean)+(phii-zmean)*(phii-zmean));
1112 AliError(Form("Wrong energy %f and/or amplitude %f\n", eCell, cluster->E()));
1115 //Normalize to the weigth and set shower shape parameters
1116 if (wtot > 0 && nstat > 1) {
1121 dxx -= xmean * xmean ;
1122 dzz -= zmean * zmean ;
1123 dxz -= xmean * zmean ;
1124 cluster->SetM02(0.5 * (dxx + dzz) + TMath::Sqrt( 0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz ));
1125 cluster->SetM20(0.5 * (dxx + dzz) - TMath::Sqrt( 0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz ));
1129 cluster->SetM20(0.) ;
1130 cluster->SetM02(0.) ;
1134 cluster->SetDispersion(TMath::Sqrt(d)) ;
1136 cluster->SetDispersion(0) ;
1139 //____________________________________________________________________________
1140 void AliEMCALRecoUtils::FindMatches(AliVEvent *event,TObjArray * clusterArr, AliEMCALGeometry *geom)
1142 //This function should be called before the cluster loop
1143 //Before call this function, please recalculate the cluster positions
1144 //Given the input event, loop over all the tracks, select the closest cluster as matched with fCutR
1145 //Store matched cluster indexes and residuals
1147 fMatchedTrackIndex->Reset();
1148 fMatchedClusterIndex->Reset();
1149 fResidualPhi->Reset();
1150 fResidualEta->Reset();
1152 fMatchedTrackIndex->Set(500);
1153 fMatchedClusterIndex->Set(500);
1154 fResidualPhi->Set(500);
1155 fResidualEta->Set(500);
1157 AliESDEvent* esdevent = dynamic_cast<AliESDEvent*> (event);
1158 AliAODEvent* aodevent = dynamic_cast<AliAODEvent*> (event);
1162 for (Int_t i=0; i<21;i++) cv[i]=0;
1163 for(Int_t itr=0; itr<event->GetNumberOfTracks(); itr++)
1165 AliExternalTrackParam *trackParam = 0;
1167 //If the input event is ESD, the starting point for extrapolation is TPCOut, if available, or TPCInner
1170 AliESDtrack *esdTrack = esdevent->GetTrack(itr);
1171 if(!esdTrack || !IsAccepted(esdTrack)) continue;
1172 if(esdTrack->Pt()<fCutMinTrackPt) continue;
1173 const AliESDfriendTrack* friendTrack = esdTrack->GetFriendTrack();
1174 if(friendTrack && friendTrack->GetTPCOut())
1176 //Use TPC Out as starting point if it is available
1177 trackParam= const_cast<AliExternalTrackParam*>(friendTrack->GetTPCOut());
1181 //Otherwise use TPC inner
1182 trackParam = const_cast<AliExternalTrackParam*>(esdTrack->GetInnerParam());
1186 //If the input event is AOD, the starting point for extrapolation is at vertex
1187 //AOD tracks are selected according to its bit.
1190 AliAODTrack *aodTrack = aodevent->GetTrack(itr);
1191 if(!aodTrack) continue;
1192 if(!aodTrack->TestFilterMask(fAODFilterMask)) continue; //Select AOD tracks that fulfill GetStandardITSTPCTrackCuts2010()
1193 if(aodTrack->Pt()<fCutMinTrackPt) continue;
1194 Double_t pos[3],mom[3];
1195 aodTrack->GetXYZ(pos);
1196 aodTrack->GetPxPyPz(mom);
1197 AliDebug(5,Form("aod track: i=%d | pos=(%5.4f,%5.4f,%5.4f) | mom=(%5.4f,%5.4f,%5.4f) | charge=%d\n",itr,pos[0],pos[1],pos[2],mom[0],mom[1],mom[2],aodTrack->Charge()));
1198 trackParam= new AliExternalTrackParam(pos,mom,cv,aodTrack->Charge());
1201 //Return if the input data is not "AOD" or "ESD"
1204 printf("Wrong input data type! Should be \"AOD\" or \"ESD\"\n");
1208 if(!trackParam) continue;
1210 Float_t dRMax = fCutR, dEtaMax=fCutEta, dPhiMax=fCutPhi;
1212 if(!clusterArr){// get clusters from event
1213 for(Int_t icl=0; icl<event->GetNumberOfCaloClusters(); icl++)
1215 AliVCluster *cluster = (AliVCluster*) event->GetCaloCluster(icl);
1216 if(geom && !IsGoodCluster(cluster,geom,(AliVCaloCells*)event->GetEMCALCells())) continue;
1217 AliExternalTrackParam trkPamTmp(*trackParam);//Retrieve the starting point every time before the extrapolation
1218 Float_t tmpEta=-999, tmpPhi=-999;
1219 if(!ExtrapolateTrackToCluster(&trkPamTmp, cluster, tmpEta, tmpPhi)) continue;
1222 Float_t tmpR=TMath::Sqrt(tmpEta*tmpEta + tmpPhi*tmpPhi);
1231 else if(fCutEtaPhiSeparate)
1233 if(TMath::Abs(tmpEta)<TMath::Abs(dEtaMax) && TMath::Abs(tmpPhi)<TMath::Abs(dPhiMax))
1242 printf("Error: please specify your cut criteria\n");
1243 printf("To cut on sqrt(dEta^2+dPhi^2), use: SwitchOnCutEtaPhiSum()\n");
1244 printf("To cut on dEta and dPhi separately, use: SwitchOnCutEtaPhiSeparate()\n");
1245 if(aodevent && trackParam) delete trackParam;
1250 else { // external cluster array, not from ESD event
1251 for(Int_t icl=0; icl<clusterArr->GetEntriesFast(); icl++)
1253 AliVCluster *cluster = dynamic_cast<AliVCluster*> (clusterArr->At(icl)) ;
1255 AliInfo("Cluster not found!!!");
1258 if(!cluster->IsEMCAL()) continue;
1259 AliExternalTrackParam trkPamTmp (*trackParam);//Retrieve the starting point every time before the extrapolation
1260 Float_t tmpEta=-999, tmpPhi=-999;
1261 if(!ExtrapolateTrackToCluster(&trkPamTmp, cluster, tmpEta, tmpPhi)) continue;
1264 Float_t tmpR=TMath::Sqrt(tmpEta*tmpEta + tmpPhi*tmpPhi);
1273 else if(fCutEtaPhiSeparate)
1275 if(TMath::Abs(tmpEta)<TMath::Abs(dEtaMax) && TMath::Abs(tmpPhi)<TMath::Abs(dPhiMax))
1284 printf("Error: please specify your cut criteria\n");
1285 printf("To cut on sqrt(dEta^2+dPhi^2), use: SwitchOnCutEtaPhiSum()\n");
1286 printf("To cut on dEta and dPhi separately, use: SwitchOnCutEtaPhiSeparate()\n");
1287 if(aodevent && trackParam) delete trackParam;
1291 }// external list of clusters
1295 fMatchedTrackIndex ->AddAt(itr,matched);
1296 fMatchedClusterIndex->AddAt(index,matched);
1297 fResidualEta ->AddAt(dEtaMax,matched);
1298 fResidualPhi ->AddAt(dPhiMax,matched);
1301 if(aodevent && trackParam) delete trackParam;
1304 AliDebug(2,Form("Number of matched pairs = %d !\n",matched));
1306 fMatchedTrackIndex ->Set(matched);
1307 fMatchedClusterIndex->Set(matched);
1308 fResidualPhi ->Set(matched);
1309 fResidualEta ->Set(matched);
1312 //________________________________________________________________________________
1313 Int_t AliEMCALRecoUtils::FindMatchedCluster(AliESDtrack *track, AliVEvent *event, AliEMCALGeometry *geom)
1316 // This function returns the index of matched cluster to input track
1317 // Returns -1 if no match is found
1320 Float_t dRMax = fCutR, dEtaMax = fCutEta, dPhiMax = fCutPhi;
1323 AliExternalTrackParam *trackParam=0;
1324 const AliESDfriendTrack* friendTrack = track->GetFriendTrack();
1325 if(friendTrack && friendTrack->GetTPCOut())
1326 trackParam= const_cast<AliExternalTrackParam*>(friendTrack->GetTPCOut());
1328 trackParam = const_cast<AliExternalTrackParam*>(track->GetInnerParam());
1330 if(!trackParam) return index;
1331 for(Int_t icl=0; icl<event->GetNumberOfCaloClusters(); icl++)
1333 AliVCluster *cluster = (AliVCluster*) event->GetCaloCluster(icl);
1334 if(geom && !IsGoodCluster(cluster,geom,(AliVCaloCells*)event->GetEMCALCells())) continue;
1335 AliExternalTrackParam trkPamTmp (*trackParam);//Retrieve the starting point every time before the extrapolation
1336 Float_t tmpEta=-999, tmpPhi=-999;
1337 if(!ExtrapolateTrackToCluster(&trkPamTmp, cluster, tmpEta, tmpPhi)) continue;
1340 Float_t tmpR=TMath::Sqrt(tmpEta*tmpEta + tmpPhi*tmpPhi);
1349 else if(fCutEtaPhiSeparate)
1351 if(TMath::Abs(tmpEta)<TMath::Abs(dEtaMax) && TMath::Abs(tmpPhi)<TMath::Abs(dPhiMax))
1360 printf("Error: please specify your cut criteria\n");
1361 printf("To cut on sqrt(dEta^2+dPhi^2), use: SwitchOnCutEtaPhiSum()\n");
1362 printf("To cut on dEta and dPhi separately, use: SwitchOnCutEtaPhiSeparate()\n");
1369 //________________________________________________________________________________
1370 Bool_t AliEMCALRecoUtils::ExtrapolateTrackToCluster(AliExternalTrackParam *trkParam, AliVCluster *cluster, Float_t &tmpEta, Float_t &tmpPhi)
1373 //Return the residual by extrapolating a track to a cluster
1375 if(!trkParam || !cluster) return kFALSE;
1378 cluster->GetPosition(clsPos); //Has been recalculated
1379 TVector3 vec(clsPos[0],clsPos[1],clsPos[2]);
1380 Double_t alpha = ((int)(vec.Phi()*TMath::RadToDeg()/20)+0.5)*20*TMath::DegToRad();
1381 vec.RotateZ(-alpha); //Rotate the cluster to the local extrapolation coordinate system
1382 trkParam->Rotate(alpha); //Rotate the track to the same local extrapolation system
1383 if(!AliTrackerBase::PropagateTrackToBxByBz(trkParam, vec.X(), fMass, fStep,kFALSE, 0.8, -1)) return kFALSE;
1384 trkParam->GetXYZ(trkPos); //Get the extrapolated global position
1386 TVector3 clsPosVec(clsPos[0],clsPos[1],clsPos[2]);
1387 TVector3 trkPosVec(trkPos[0],trkPos[1],trkPos[2]);
1389 Float_t clsPhi = (Float_t)clsPosVec.Phi();
1390 if(clsPhi<0) clsPhi+=2*TMath::Pi();
1391 Float_t trkPhi = (Float_t)trkPosVec.Phi();
1392 if(trkPhi<0) trkPhi+=2*TMath::Pi();
1393 tmpPhi = clsPhi-trkPhi; // track cluster matching
1394 tmpEta = clsPosVec.Eta()-trkPosVec.Eta(); // track cluster matching
1399 //________________________________________________________________________________
1400 void AliEMCALRecoUtils::GetMatchedResiduals(Int_t clsIndex, Float_t &dEta, Float_t &dPhi)
1402 //Given a cluster index as in AliESDEvent::GetCaloCluster(clsIndex)
1403 //Get the residuals dEta and dPhi for this cluster to the closest track
1404 //Works with ESDs and AODs
1406 if( FindMatchedPosForCluster(clsIndex) >= 999 )
1408 AliDebug(2,"No matched tracks found!\n");
1413 dEta = fResidualEta->At(FindMatchedPosForCluster(clsIndex));
1414 dPhi = fResidualPhi->At(FindMatchedPosForCluster(clsIndex));
1416 //________________________________________________________________________________
1417 void AliEMCALRecoUtils::GetMatchedClusterResiduals(Int_t trkIndex, Float_t &dEta, Float_t &dPhi)
1419 //Given a track index as in AliESDEvent::GetTrack(trkIndex)
1420 //Get the residuals dEta and dPhi for this track to the closest cluster
1421 //Works with ESDs and AODs
1423 if( FindMatchedPosForTrack(trkIndex) >= 999 )
1425 AliDebug(2,"No matched cluster found!\n");
1430 dEta = fResidualEta->At(FindMatchedPosForTrack(trkIndex));
1431 dPhi = fResidualPhi->At(FindMatchedPosForTrack(trkIndex));
1434 //__________________________________________________________
1435 Int_t AliEMCALRecoUtils::GetMatchedTrackIndex(Int_t clsIndex)
1437 //Given a cluster index as in AliESDEvent::GetCaloCluster(clsIndex)
1438 //Get the index of matched track to this cluster
1439 //Works with ESDs and AODs
1441 if(IsClusterMatched(clsIndex))
1442 return fMatchedTrackIndex->At(FindMatchedPosForCluster(clsIndex));
1447 //__________________________________________________________
1448 Int_t AliEMCALRecoUtils::GetMatchedClusterIndex(Int_t trkIndex)
1450 //Given a track index as in AliESDEvent::GetTrack(trkIndex)
1451 //Get the index of matched cluster to this track
1452 //Works with ESDs and AODs
1454 if(IsTrackMatched(trkIndex))
1455 return fMatchedClusterIndex->At(FindMatchedPosForTrack(trkIndex));
1460 //__________________________________________________
1461 Bool_t AliEMCALRecoUtils::IsClusterMatched(Int_t clsIndex) const
1463 //Given a cluster index as in AliESDEvent::GetCaloCluster(clsIndex)
1464 //Returns if the cluster has a match
1465 if(FindMatchedPosForCluster(clsIndex) < 999)
1471 //__________________________________________________
1472 Bool_t AliEMCALRecoUtils::IsTrackMatched(Int_t trkIndex) const
1474 //Given a track index as in AliESDEvent::GetTrack(trkIndex)
1475 //Returns if the track has a match
1476 if(FindMatchedPosForTrack(trkIndex) < 999)
1482 //__________________________________________________________
1483 UInt_t AliEMCALRecoUtils::FindMatchedPosForCluster(Int_t clsIndex) const
1485 //Given a cluster index as in AliESDEvent::GetCaloCluster(clsIndex)
1486 //Returns the position of the match in the fMatchedClusterIndex array
1487 Float_t tmpR = fCutR;
1490 for(Int_t i=0; i<fMatchedClusterIndex->GetSize(); i++)
1492 if(fMatchedClusterIndex->At(i)==clsIndex)
1494 Float_t r = TMath::Sqrt(fResidualEta->At(i)*fResidualEta->At(i) + fResidualPhi->At(i)*fResidualPhi->At(i));
1499 AliDebug(3,Form("Matched cluster index: index: %d, dEta: %2.4f, dPhi: %2.4f.\n",fMatchedClusterIndex->At(i),fResidualEta->At(i),fResidualPhi->At(i)));
1506 //__________________________________________________________
1507 UInt_t AliEMCALRecoUtils::FindMatchedPosForTrack(Int_t trkIndex) const
1509 //Given a track index as in AliESDEvent::GetTrack(trkIndex)
1510 //Returns the position of the match in the fMatchedTrackIndex array
1511 Float_t tmpR = fCutR;
1514 for(Int_t i=0; i<fMatchedTrackIndex->GetSize(); i++)
1516 if(fMatchedTrackIndex->At(i)==trkIndex)
1518 Float_t r = TMath::Sqrt(fResidualEta->At(i)*fResidualEta->At(i) + fResidualPhi->At(i)*fResidualPhi->At(i));
1523 AliDebug(3,Form("Matched track index: index: %d, dEta: %2.4f, dPhi: %2.4f.\n",fMatchedTrackIndex->At(i),fResidualEta->At(i),fResidualPhi->At(i)));
1530 //__________________________________________________________
1531 Bool_t AliEMCALRecoUtils::IsGoodCluster(AliVCluster *cluster, AliEMCALGeometry *geom, AliVCaloCells* cells)
1533 // check if the cluster survives some quality cut
1536 Bool_t isGood=kTRUE;
1537 if(!cluster || !cluster->IsEMCAL()) return kFALSE;
1538 if(ClusterContainsBadChannel(geom,cluster->GetCellsAbsId(),cluster->GetNCells())) return kFALSE;
1539 if(!CheckCellFiducialRegion(geom,cluster,cells)) return kFALSE;
1540 if(fRejectExoticCluster && IsExoticCluster(cluster)) return kFALSE;
1545 //__________________________________________________________
1546 Bool_t AliEMCALRecoUtils::IsAccepted(AliESDtrack *esdTrack)
1548 // Given a esd track, return whether the track survive all the cuts
1550 // The different quality parameter are first
1551 // retrieved from the track. then it is found out what cuts the
1552 // track did not survive and finally the cuts are imposed.
1554 UInt_t status = esdTrack->GetStatus();
1556 Int_t nClustersITS = esdTrack->GetITSclusters(0);
1557 Int_t nClustersTPC = esdTrack->GetTPCclusters(0);
1559 Float_t chi2PerClusterITS = -1;
1560 Float_t chi2PerClusterTPC = -1;
1561 if (nClustersITS!=0)
1562 chi2PerClusterITS = esdTrack->GetITSchi2()/Float_t(nClustersITS);
1563 if (nClustersTPC!=0)
1564 chi2PerClusterTPC = esdTrack->GetTPCchi2()/Float_t(nClustersTPC);
1568 Float_t maxDCAToVertexXYPtDep = 0.0182 + 0.0350/TMath::Power(esdTrack->Pt(),1.01); //This expression comes from AliESDtrackCuts::GetStandardITSTPCTrackCuts2010()
1569 //AliDebug(3,Form("Track pT = %f, DCAtoVertexXY = %f",esdTrack->Pt(),MaxDCAToVertexXYPtDep));
1570 SetMaxDCAToVertexXY(maxDCAToVertexXYPtDep); //Set pT dependent DCA cut to vertex in x-y plane
1575 esdTrack->GetImpactParameters(b,bCov);
1576 if (bCov[0]<=0 || bCov[2]<=0) {
1577 AliDebug(1, "Estimated b resolution lower or equal zero!");
1578 bCov[0]=0; bCov[2]=0;
1581 Float_t dcaToVertexXY = b[0];
1582 Float_t dcaToVertexZ = b[1];
1583 Float_t dcaToVertex = -1;
1585 if (fCutDCAToVertex2D)
1586 dcaToVertex = TMath::Sqrt(dcaToVertexXY*dcaToVertexXY/fCutMaxDCAToVertexXY/fCutMaxDCAToVertexXY + dcaToVertexZ*dcaToVertexZ/fCutMaxDCAToVertexZ/fCutMaxDCAToVertexZ);
1588 dcaToVertex = TMath::Sqrt(dcaToVertexXY*dcaToVertexXY + dcaToVertexZ*dcaToVertexZ);
1592 Bool_t cuts[kNCuts];
1593 for (Int_t i=0; i<kNCuts; i++) cuts[i]=kFALSE;
1595 // track quality cuts
1596 if (fCutRequireTPCRefit && (status&AliESDtrack::kTPCrefit)==0)
1598 if (fCutRequireITSRefit && (status&AliESDtrack::kITSrefit)==0)
1600 if (nClustersTPC<fCutMinNClusterTPC)
1602 if (nClustersITS<fCutMinNClusterITS)
1604 if (chi2PerClusterTPC>fCutMaxChi2PerClusterTPC)
1606 if (chi2PerClusterITS>fCutMaxChi2PerClusterITS)
1608 if (!fCutAcceptKinkDaughters && esdTrack->GetKinkIndex(0)>0)
1610 if (fCutDCAToVertex2D && dcaToVertex > 1)
1612 if (!fCutDCAToVertex2D && TMath::Abs(dcaToVertexXY) > fCutMaxDCAToVertexXY)
1614 if (!fCutDCAToVertex2D && TMath::Abs(dcaToVertexZ) > fCutMaxDCAToVertexZ)
1617 //Require at least one SPD point + anything else in ITS
1618 if( (esdTrack->HasPointOnITSLayer(0) || esdTrack->HasPointOnITSLayer(1)) == kFALSE)
1622 for (Int_t i=0; i<kNCuts; i++)
1623 if (cuts[i]) {cut = kTRUE;}
1631 //__________________________________________________
1632 void AliEMCALRecoUtils::InitTrackCuts()
1634 //Intilize the track cut criteria
1635 //By default these cuts are set according to AliESDtrackCuts::GetStandardTPCOnlyTrackCuts()
1636 //Also you can customize the cuts using the setters
1638 switch (fTrackCutsType)
1642 AliInfo(Form("Track cuts for matching: GetStandardTPCOnlyTrackCuts()\n"));
1644 SetMinNClustersTPC(70);
1645 SetMaxChi2PerClusterTPC(4);
1646 SetAcceptKinkDaughters(kFALSE);
1647 SetRequireTPCRefit(kFALSE);
1650 SetRequireITSRefit(kFALSE);
1651 SetMaxDCAToVertexZ(3.2);
1652 SetMaxDCAToVertexXY(2.4);
1653 SetDCAToVertex2D(kTRUE);
1660 AliInfo(Form("Track cuts for matching: GetStandardITSTPCTrackCuts2010(kTURE)\n"));
1662 SetMinNClustersTPC(70);
1663 SetMaxChi2PerClusterTPC(4);
1664 SetAcceptKinkDaughters(kFALSE);
1665 SetRequireTPCRefit(kTRUE);
1668 SetRequireITSRefit(kTRUE);
1669 SetMaxDCAToVertexZ(2);
1670 SetMaxDCAToVertexXY();
1671 SetDCAToVertex2D(kFALSE);
1678 //___________________________________________________
1679 void AliEMCALRecoUtils::Print(const Option_t *) const
1683 printf("AliEMCALRecoUtils Settings: \n");
1684 printf("Misalignment shifts\n");
1685 for(Int_t i=0; i<5; i++) printf("\t sector %d, traslation (x,y,z)=(%f,%f,%f), rotation (x,y,z)=(%f,%f,%f)\n",i,
1686 fMisalTransShift[i*3],fMisalTransShift[i*3+1],fMisalTransShift[i*3+2],
1687 fMisalRotShift[i*3], fMisalRotShift[i*3+1], fMisalRotShift[i*3+2] );
1688 printf("Non linearity function %d, parameters:\n", fNonLinearityFunction);
1689 for(Int_t i=0; i<6; i++) printf("param[%d]=%f\n",i, fNonLinearityParams[i]);
1691 printf("Position Recalculation option %d, Particle Type %d, fW0 %2.2f, Recalibrate Data %d \n",fPosAlgo,fParticleType,fW0, fRecalibration);
1693 printf("Matching criteria: ");
1696 printf("sqrt(dEta^2+dPhi^2)<%2.2f\n",fCutR);
1698 else if(fCutEtaPhiSeparate)
1700 printf("dEta<%2.2f, dPhi<%2.2f\n",fCutEta,fCutPhi);
1705 printf("please specify your cut criteria\n");
1706 printf("To cut on sqrt(dEta^2+dPhi^2), use: SwitchOnCutEtaPhiSum()\n");
1707 printf("To cut on dEta and dPhi separately, use: SwitchOnCutEtaPhiSeparate()\n");
1710 printf("Mass hypothesis = %2.3f [GeV/c^2], extrapolation step = %2.2f[cm]\n",fMass,fStep);
1712 printf("Track cuts: \n");
1713 printf("Minimum track pT: %1.2f\n",fCutMinTrackPt);
1714 printf("AOD track selection mask: %d\n",fAODFilterMask);
1715 printf("TPCRefit = %d, ITSRefit = %d\n",fCutRequireTPCRefit,fCutRequireITSRefit);
1716 printf("AcceptKinks = %d\n",fCutAcceptKinkDaughters);
1717 printf("MinNCulsterTPC = %d, MinNClusterITS = %d\n",fCutMinNClusterTPC,fCutMinNClusterITS);
1718 printf("MaxChi2TPC = %2.2f, MaxChi2ITS = %2.2f\n",fCutMaxChi2PerClusterTPC,fCutMaxChi2PerClusterITS);
1719 printf("DCSToVertex2D = %d, MaxDCAToVertexXY = %2.2f, MaxDCAToVertexZ = %2.2f\n",fCutDCAToVertex2D,fCutMaxDCAToVertexXY,fCutMaxDCAToVertexZ);
1723 //_____________________________________________________________________
1724 void AliEMCALRecoUtils::SetTimeDependentCorrections(Int_t runnumber){
1725 //Get EMCAL time dependent corrections from file and put them in the recalibration histograms
1726 //Do it only once and only if it is requested
1728 if(!fUseTimeCorrectionFactors) return;
1729 if(fTimeCorrectionFactorsSet) return;
1731 printf("AliEMCALRecoUtils::GetTimeDependentCorrections() - Get Correction Factors for Run number %d\n",runnumber);
1733 AliEMCALCalibTimeDepCorrection *corr = new AliEMCALCalibTimeDepCorrection();
1734 corr->ReadRootInfo(Form("CorrectionFiles/Run%d_Correction.root",runnumber));
1736 SwitchOnRecalibration();
1737 for(Int_t ism = 0; ism < 4; ism++){
1738 for(Int_t icol = 0; icol < 48; icol++){
1739 for(Int_t irow = 0; irow < 24; irow++){
1740 Float_t orgRecalFactor = GetEMCALChannelRecalibrationFactors(ism)->GetBinContent(icol,irow);
1741 Float_t newRecalFactor = orgRecalFactor*corr->GetCorrection(ism, icol,irow,0);
1742 GetEMCALChannelRecalibrationFactors(ism)->SetBinContent(icol,irow,newRecalFactor);
1743 //printf("ism %d, icol %d, irow %d, corrections : org %f, time dep %f, final %f (org*time %f)\n",ism, icol, irow,
1744 // orgRecalFactor, corr->GetCorrection(ism, icol,irow,0),
1745 // (GetEMCALChannelRecalibrationFactors(ism))->GetBinContent(icol,irow),newRecalFactor);
1749 fTimeCorrectionFactorsSet = kTRUE;