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 ///////////////////////////////////////////////////////////////////////////////
29 // standard C++ includes
30 //#include <Riostream.h>
33 #include <TGeoManager.h>
34 #include <TGeoMatrix.h>
38 #include "AliEMCALRecoUtils.h"
39 #include "AliEMCALGeometry.h"
40 #include "AliVCluster.h"
41 #include "AliVCaloCells.h"
42 #include "AliVEvent.h"
44 #include "AliEMCALPIDUtils.h"
46 #include "AliESDEvent.h"
47 #include "AliESDtrack.h"
48 #include "AliEMCALTrack.h"
50 ClassImp(AliEMCALRecoUtils)
52 //______________________________________________
53 AliEMCALRecoUtils::AliEMCALRecoUtils():
54 fNonLinearityFunction (kNoCorrection), fParticleType(kPhoton),
55 fPosAlgo(kUnchanged),fW0(4.),
56 fRecalibration(kFALSE), fEMCALRecalibrationFactors(),
57 fRemoveBadChannels(kFALSE), fRecalDistToBadChannels(kFALSE), fEMCALBadChannelMap(),
58 fNCellsFromEMCALBorder(0), fNoEMCALBorderAtEta0(kTRUE),
59 fMatchedClusterIndex(0x0), fResidualZ(0x0), fResidualR(0x0), fCutR(20), fCutZ(20),
60 fCutMinNClusterTPC(0), fCutMinNClusterITS(0), fCutMaxChi2PerClusterTPC(0), fCutMaxChi2PerClusterITS(0),
61 fCutRequireTPCRefit(0), fCutRequireITSRefit(0), fCutAcceptKinkDaughters(0),
62 fCutMaxDCAToVertexXY(0), fCutMaxDCAToVertexZ(0),fCutDCAToVertex2D(0),
67 // Initialize all constant values which have to be used
68 // during Reco algorithm execution
71 for(Int_t i = 0; i < 15 ; i++) {
72 fMisalTransShift[i] = 0.;
73 fMisalRotShift[i] = 0.;
75 for(Int_t i = 0; i < 6 ; i++) fNonLinearityParams[i] = 0.;
76 //For kPi0GammaGamma case, but default is no correction
77 fNonLinearityParams[0] = 0.1457/0.1349766/1.038;
78 fNonLinearityParams[1] = -0.02024/0.1349766/1.038;
79 fNonLinearityParams[2] = 1.046;
81 fMatchedClusterIndex = new TArrayI();
82 fResidualZ = new TArrayF();
83 fResidualR = new TArrayF();
85 fPIDUtils = new AliEMCALPIDUtils();
91 //______________________________________________________________________
92 AliEMCALRecoUtils::AliEMCALRecoUtils(const AliEMCALRecoUtils & reco)
93 : TNamed(reco), fNonLinearityFunction(reco.fNonLinearityFunction),
94 fParticleType(reco.fParticleType), fPosAlgo(reco.fPosAlgo), fW0(reco.fW0),
95 fRecalibration(reco.fRecalibration),fEMCALRecalibrationFactors(reco.fEMCALRecalibrationFactors),
96 fRemoveBadChannels(reco.fRemoveBadChannels),fRecalDistToBadChannels(reco.fRecalDistToBadChannels),
97 fEMCALBadChannelMap(reco.fEMCALBadChannelMap),
98 fNCellsFromEMCALBorder(reco.fNCellsFromEMCALBorder),fNoEMCALBorderAtEta0(reco.fNoEMCALBorderAtEta0),
99 fMatchedClusterIndex(reco.fMatchedClusterIndex?new TArrayI(*reco.fMatchedClusterIndex):0x0),
100 fResidualZ(reco.fResidualZ?new TArrayF(*reco.fResidualZ):0x0),
101 fResidualR(reco.fResidualR?new TArrayF(*reco.fResidualR):0x0),
102 fCutR(reco.fCutR),fCutZ(reco.fCutZ),
103 fCutMinNClusterTPC(reco.fCutMinNClusterTPC), fCutMinNClusterITS(reco.fCutMinNClusterITS),
104 fCutMaxChi2PerClusterTPC(reco.fCutMaxChi2PerClusterTPC), fCutMaxChi2PerClusterITS(reco.fCutMaxChi2PerClusterITS),
105 fCutRequireTPCRefit(reco.fCutRequireTPCRefit), fCutRequireITSRefit(reco.fCutRequireITSRefit),
106 fCutAcceptKinkDaughters(reco.fCutAcceptKinkDaughters),
107 fCutMaxDCAToVertexXY(reco.fCutMaxDCAToVertexXY), fCutMaxDCAToVertexZ(reco.fCutMaxDCAToVertexZ),fCutDCAToVertex2D(reco.fCutDCAToVertex2D),
108 fPIDUtils(reco.fPIDUtils)
113 for(Int_t i = 0; i < 15 ; i++) {
114 fMisalRotShift[i] = reco.fMisalRotShift[i];
115 fMisalTransShift[i] = reco.fMisalTransShift[i];
117 for(Int_t i = 0; i < 6 ; i++) fNonLinearityParams[i] = reco.fNonLinearityParams[i];
122 //______________________________________________________________________
123 AliEMCALRecoUtils & AliEMCALRecoUtils::operator = (const AliEMCALRecoUtils & reco)
125 //Assignment operator
127 if(this == &reco)return *this;
128 ((TNamed *)this)->operator=(reco);
130 fNonLinearityFunction = reco.fNonLinearityFunction;
131 fParticleType = reco.fParticleType;
132 fPosAlgo = reco.fPosAlgo;
134 fRecalibration = reco.fRecalibration;
135 fEMCALRecalibrationFactors = reco.fEMCALRecalibrationFactors;
136 fRemoveBadChannels = reco.fRemoveBadChannels;
137 fRecalDistToBadChannels= reco.fRecalDistToBadChannels;
138 fEMCALBadChannelMap = reco.fEMCALBadChannelMap;
139 fNCellsFromEMCALBorder = reco.fNCellsFromEMCALBorder;
140 fNoEMCALBorderAtEta0 = reco.fNoEMCALBorderAtEta0;
143 for(Int_t i = 0; i < 15 ; i++) {fMisalTransShift[i] = reco.fMisalTransShift[i]; fMisalRotShift[i] = reco.fMisalRotShift[i];}
144 for(Int_t i = 0; i < 6 ; i++) fNonLinearityParams[i] = reco.fNonLinearityParams[i];
149 fCutMinNClusterTPC = reco.fCutMinNClusterTPC;
150 fCutMinNClusterITS = reco.fCutMinNClusterITS;
151 fCutMaxChi2PerClusterTPC = reco.fCutMaxChi2PerClusterTPC;
152 fCutMaxChi2PerClusterITS = reco.fCutMaxChi2PerClusterITS;
153 fCutRequireTPCRefit = reco.fCutRequireTPCRefit;
154 fCutRequireITSRefit = reco.fCutRequireITSRefit;
155 fCutAcceptKinkDaughters = reco.fCutAcceptKinkDaughters;
156 fCutMaxDCAToVertexXY = reco.fCutMaxDCAToVertexXY;
157 fCutMaxDCAToVertexZ = reco.fCutMaxDCAToVertexZ;
158 fCutDCAToVertex2D = reco.fCutDCAToVertex2D;
160 fPIDUtils = reco.fPIDUtils;
164 // assign or copy construct
166 *fResidualR = *reco.fResidualR;
168 else fResidualR = new TArrayF(*reco.fResidualR);
171 if(fResidualR)delete fResidualR;
176 // assign or copy construct
178 *fResidualZ = *reco.fResidualZ;
180 else fResidualZ = new TArrayF(*reco.fResidualZ);
183 if(fResidualZ)delete fResidualZ;
188 if(reco.fMatchedClusterIndex){
189 // assign or copy construct
190 if(fMatchedClusterIndex){
191 *fMatchedClusterIndex = *reco.fMatchedClusterIndex;
193 else fMatchedClusterIndex = new TArrayI(*reco.fMatchedClusterIndex);
196 if(fMatchedClusterIndex)delete fMatchedClusterIndex;
197 fMatchedClusterIndex = 0;
205 //__________________________________________________
206 AliEMCALRecoUtils::~AliEMCALRecoUtils()
210 if(fEMCALRecalibrationFactors) {
211 fEMCALRecalibrationFactors->Clear();
212 delete fEMCALRecalibrationFactors;
215 if(fEMCALBadChannelMap) {
216 fEMCALBadChannelMap->Clear();
217 delete fEMCALBadChannelMap;
220 if(fMatchedClusterIndex) {delete fMatchedClusterIndex; fMatchedClusterIndex=0;}
221 if(fResidualR) {delete fResidualR; fResidualR=0;}
222 if(fResidualZ) {delete fResidualZ; fResidualZ=0;}
226 //_______________________________________________________________
227 Bool_t AliEMCALRecoUtils::CheckCellFiducialRegion(AliEMCALGeometry* geom, AliVCluster* cluster, AliVCaloCells* cells)
229 // Given the list of AbsId of the cluster, get the maximum cell and
230 // check if there are fNCellsFromBorder from the calorimeter border
232 //If the distance to the border is 0 or negative just exit accept all clusters
233 if(cells->GetType()==AliVCaloCells::kEMCALCell && fNCellsFromEMCALBorder <= 0 ) return kTRUE;
235 Int_t absIdMax = -1, iSM =-1, ieta = -1, iphi = -1;
236 Bool_t shared = kFALSE;
237 GetMaxEnergyCell(geom, cells, cluster, absIdMax, iSM, ieta, iphi, shared);
239 AliDebug(2,Form("Cluster Max AbsId %d, Cell Energy %2.2f, Cluster Energy %2.2f, Ncells from border %d, EMCAL eta=0 %d\n",
240 absIdMax, cells->GetCellAmplitude(absIdMax), cluster->E(), fNCellsFromEMCALBorder, fNoEMCALBorderAtEta0));
242 if(absIdMax==-1) return kFALSE;
244 //Check if the cell is close to the borders:
245 Bool_t okrow = kFALSE;
246 Bool_t okcol = kFALSE;
248 if(iSM < 0 || iphi < 0 || ieta < 0 ) {
249 AliFatal(Form("Negative value for super module: %d, or cell ieta: %d, or cell iphi: %d, check EMCAL geometry name\n",
255 if(iphi >= fNCellsFromEMCALBorder && iphi < 24-fNCellsFromEMCALBorder) okrow =kTRUE;
258 if(iphi >= fNCellsFromEMCALBorder && iphi < 12-fNCellsFromEMCALBorder) okrow =kTRUE;
262 if(!fNoEMCALBorderAtEta0){
263 if(ieta > fNCellsFromEMCALBorder && ieta < 48-fNCellsFromEMCALBorder) okcol =kTRUE;
267 if(ieta >= fNCellsFromEMCALBorder) okcol = kTRUE;
270 if(ieta < 48-fNCellsFromEMCALBorder) okcol = kTRUE;
274 AliDebug(2,Form("EMCAL Cluster in %d cells fiducial volume: ieta %d, iphi %d, SM %d: column? %d, row? %d\nq",
275 fNCellsFromEMCALBorder, ieta, iphi, iSM, okcol, okrow));
277 if (okcol && okrow) {
278 //printf("Accept\n");
282 //printf("Reject\n");
283 AliDebug(2,Form("Reject cluster in border, max cell : ieta %d, iphi %d, SM %d\n",ieta, iphi, iSM));
290 //_________________________________________________________________________________________________________
291 Bool_t AliEMCALRecoUtils::ClusterContainsBadChannel(AliEMCALGeometry* geom, UShort_t* cellList, Int_t nCells){
292 // Check that in the cluster cells, there is no bad channel of those stored
293 // in fEMCALBadChannelMap or fPHOSBadChannelMap
295 if(!fRemoveBadChannels) return kFALSE;
296 if(!fEMCALBadChannelMap) return kFALSE;
301 for(Int_t iCell = 0; iCell<nCells; iCell++){
303 //Get the column and row
304 Int_t iTower = -1, iIphi = -1, iIeta = -1;
305 geom->GetCellIndex(cellList[iCell],imod,iTower,iIphi,iIeta);
306 if(fEMCALBadChannelMap->GetEntries() <= imod) continue;
307 geom->GetCellPhiEtaIndexInSModule(imod,iTower,iIphi, iIeta,irow,icol);
308 if(GetEMCALChannelStatus(imod, icol, irow)){
309 AliDebug(2,Form("Cluster with bad channel: SM %d, col %d, row %d\n",imod, icol, irow));
313 }// cell cluster loop
319 //__________________________________________________
320 Float_t AliEMCALRecoUtils::CorrectClusterEnergyLinearity(AliVCluster* cluster){
321 // Correct cluster energy from non linearity functions
322 Float_t energy = cluster->E();
324 switch (fNonLinearityFunction) {
327 //Non-Linearity correction (from MC with function ([0]*exp(-[1]/E))+(([2]/([3]*2.*TMath::Pi())*exp(-(E-[4])^2/(2.*[3]^2)))))
328 //Double_t par0 = 1.001;
329 //Double_t par1 = -0.01264;
330 //Double_t par2 = -0.03632;
331 //Double_t par3 = 0.1798;
332 //Double_t par4 = -0.522;
333 energy /= (fNonLinearityParams[0]*exp(-fNonLinearityParams[1]/energy))+
334 ((fNonLinearityParams[2]/(fNonLinearityParams[3]*2.*TMath::Pi())*
335 exp(-(energy-fNonLinearityParams[4])*(energy-fNonLinearityParams[4])/(2.*fNonLinearityParams[3]*fNonLinearityParams[3]))));
340 //Non-Linearity correction (from Olga Data with function p0+p1*exp(-p2*E))
341 //Double_t par0 = 0.1457;
342 //Double_t par1 = -0.02024;
343 //Double_t par2 = 1.046;
344 energy /= (fNonLinearityParams[0]+fNonLinearityParams[1]*exp(-fNonLinearityParams[2]*energy)); //Olga function
347 case kPi0GammaConversion:
349 //Non-Linearity correction (Nicolas from Dimitri Data with function C*[1-a*exp(-b*E)])
350 //Double_t C = 0.139393/0.1349766;
351 //Double_t a = 0.0566186;
352 //Double_t b = 0.982133;
353 energy /= fNonLinearityParams[0]*(1-fNonLinearityParams[1]*exp(-fNonLinearityParams[2]*energy));
358 AliDebug(2,"No correction on the energy\n");
367 //__________________________________________________
368 Float_t AliEMCALRecoUtils::GetDepth(const Float_t energy, const Int_t iParticle, const Int_t iSM) const
370 //Calculate shower depth for a given cluster energy and particle type
380 depth = x0 * (TMath::Log(energy*1000/ ecr) + 0.5); //Multiply energy by 1000 to transform to MeV
384 depth = x0 * (TMath::Log(energy*1000/ ecr) - 0.5); //Multiply energy by 1000 to transform to MeV
391 gGeoManager->cd("ALIC_1/XEN1_1");
392 TGeoNode *geoXEn1 = gGeoManager->GetCurrentNode();
393 TGeoNodeMatrix *geoSM = dynamic_cast<TGeoNodeMatrix *>(geoXEn1->GetDaughter(iSM));
395 TGeoVolume *geoSMVol = geoSM->GetVolume();
396 TGeoShape *geoSMShape = geoSMVol->GetShape();
397 TGeoBBox *geoBox = dynamic_cast<TGeoBBox *>(geoSMShape);
398 if(geoBox) depth = 0.5 * geoBox->GetDX()*2 ;
399 else AliFatal("Null GEANT box");
400 }else AliFatal("NULL GEANT node matrix");
403 depth = x0 * (TMath::Log(energy*1000 / ecr) - 0.5); //Multiply energy by 1000 to transform to MeV
409 depth = x0 * (TMath::Log(energy*1000 / ecr) + 0.5); //Multiply energy by 1000 to transform to MeV
416 //__________________________________________________
417 void AliEMCALRecoUtils::GetMaxEnergyCell(AliEMCALGeometry *geom, AliVCaloCells* cells, AliVCluster* clu,
418 Int_t & absId, Int_t& iSupMod, Int_t& ieta, Int_t& iphi, Bool_t &shared)
420 //For a given CaloCluster gets the absId of the cell
421 //with maximum energy deposit.
424 Double_t eCell = -1.;
425 Float_t fraction = 1.;
426 Float_t recalFactor = 1.;
427 Int_t cellAbsId = -1 ;
433 //printf("---Max?\n");
434 for (Int_t iDig=0; iDig< clu->GetNCells(); iDig++) {
435 cellAbsId = clu->GetCellAbsId(iDig);
436 fraction = clu->GetCellAmplitudeFraction(iDig);
437 //printf("a Cell %d, id, %d, amp %f, fraction %f\n",iDig,cellAbsId,cells->GetCellAmplitude(cellAbsId),fraction);
438 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
439 geom->GetCellIndex(cellAbsId,iSupMod,iTower,iIphi,iIeta);
440 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi, iIeta,iphi,ieta);
441 if(iDig==0) iSupMod0=iSupMod;
442 else if(iSupMod0!=iSupMod) {
444 //printf("AliEMCALRecoUtils::GetMaxEnergyCell() - SHARED CLUSTER\n");
446 if(IsRecalibrationOn()) {
447 recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
449 eCell = cells->GetCellAmplitude(cellAbsId)*fraction*recalFactor;
450 //printf("b Cell %d, id, %d, amp %f, fraction %f\n",iDig,cellAbsId,eCell,fraction);
454 //printf("\t new max: cell %d, e %f, ecell %f\n",maxId, eMax,eCell);
458 //Get from the absid the supermodule, tower and eta/phi numbers
459 geom->GetCellIndex(absId,iSupMod,iTower,iIphi,iIeta);
460 //Gives SuperModule and Tower numbers
461 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,
462 iIphi, iIeta,iphi,ieta);
463 //printf("Max id %d, iSM %d, col %d, row %d\n",absId,iSupMod,ieta,iphi);
464 //printf("Max end---\n");
468 //________________________________________________________________
469 void AliEMCALRecoUtils::InitEMCALRecalibrationFactors(){
470 //Init EMCAL recalibration factors
471 AliDebug(2,"AliCalorimeterUtils::InitEMCALRecalibrationFactors()");
472 //In order to avoid rewriting the same histograms
473 Bool_t oldStatus = TH1::AddDirectoryStatus();
474 TH1::AddDirectory(kFALSE);
476 fEMCALRecalibrationFactors = new TObjArray(10);
477 for (int i = 0; i < 12; i++) fEMCALRecalibrationFactors->Add(new TH2F(Form("EMCALRecalFactors_SM%d",i),Form("EMCALRecalFactors_SM%d",i), 48, 0, 48, 24, 0, 24));
478 //Init the histograms with 1
479 for (Int_t sm = 0; sm < 12; sm++) {
480 for (Int_t i = 0; i < 48; i++) {
481 for (Int_t j = 0; j < 24; j++) {
482 SetEMCALChannelRecalibrationFactor(sm,i,j,1.);
486 fEMCALRecalibrationFactors->SetOwner(kTRUE);
487 fEMCALRecalibrationFactors->Compress();
489 //In order to avoid rewriting the same histograms
490 TH1::AddDirectory(oldStatus);
494 //________________________________________________________________
495 void AliEMCALRecoUtils::InitEMCALBadChannelStatusMap(){
496 //Init EMCAL bad channels map
497 AliDebug(2,"AliEMCALRecoUtils::InitEMCALBadChannelStatusMap()");
498 //In order to avoid rewriting the same histograms
499 Bool_t oldStatus = TH1::AddDirectoryStatus();
500 TH1::AddDirectory(kFALSE);
502 fEMCALBadChannelMap = new TObjArray(10);
503 //TH2F * hTemp = new TH2I("EMCALBadChannelMap","EMCAL SuperModule bad channel map", 48, 0, 48, 24, 0, 24);
504 for (int i = 0; i < 12; i++) {
505 fEMCALBadChannelMap->Add(new TH2I(Form("EMCALBadChannelMap_Mod%d",i),Form("EMCALBadChannelMap_Mod%d",i), 48, 0, 48, 24, 0, 24));
510 fEMCALBadChannelMap->SetOwner(kTRUE);
511 fEMCALBadChannelMap->Compress();
513 //In order to avoid rewriting the same histograms
514 TH1::AddDirectory(oldStatus);
517 //________________________________________________________________
518 void AliEMCALRecoUtils::RecalibrateClusterEnergy(AliEMCALGeometry* geom, AliVCluster * cluster, AliVCaloCells * cells){
519 // Recalibrate the cluster energy, considering the recalibration map and the energy of the cells that compose the cluster.
521 //Get the cluster number of cells and list of absId, check what kind of cluster do we have.
522 UShort_t * index = cluster->GetCellsAbsId() ;
523 Double_t * fraction = cluster->GetCellsAmplitudeFraction() ;
524 Int_t ncells = cluster->GetNCells();
526 //Initialize some used variables
529 Int_t icol = -1, irow = -1, imod=1;
530 Float_t factor = 1, frac = 0;
532 //Loop on the cells, get the cell amplitude and recalibration factor, multiply and and to the new energy
533 for(Int_t icell = 0; icell < ncells; icell++){
534 absId = index[icell];
535 frac = fraction[icell];
536 if(frac < 1e-5) frac = 1; //in case of EMCAL, this is set as 0 since unfolding is off
537 Int_t iTower = -1, iIphi = -1, iIeta = -1;
538 geom->GetCellIndex(absId,imod,iTower,iIphi,iIeta);
539 if(fEMCALRecalibrationFactors->GetEntries() <= imod) continue;
540 geom->GetCellPhiEtaIndexInSModule(imod,iTower,iIphi, iIeta,irow,icol);
541 factor = GetEMCALChannelRecalibrationFactor(imod,icol,irow);
542 AliDebug(2,Form("AliEMCALRecoUtils::RecalibrateClusterEnergy - recalibrate cell: module %d, col %d, row %d, cell fraction %f,recalibration factor %f, cell energy %f\n",
543 imod,icol,irow,frac,factor,cells->GetCellAmplitude(absId)));
545 energy += cells->GetCellAmplitude(absId)*factor*frac;
549 AliDebug(2,Form("AliEMCALRecoUtils::RecalibrateClusterEnergy - Energy before %f, after %f\n",cluster->E(),energy));
551 cluster->SetE(energy);
556 //__________________________________________________
557 void AliEMCALRecoUtils::RecalculateClusterPosition(AliEMCALGeometry *geom, AliVCaloCells* cells, AliVCluster* clu)
559 //For a given CaloCluster recalculates the position for a given set of misalignment shifts and puts it again in the CaloCluster.
561 if (fPosAlgo==kPosTowerGlobal) RecalculateClusterPositionFromTowerGlobal( geom, cells, clu);
562 else if(fPosAlgo==kPosTowerIndex) RecalculateClusterPositionFromTowerIndex ( geom, cells, clu);
563 else AliDebug(2,"Algorithm to recalculate position not selected, do nothing.");
567 //__________________________________________________
568 void AliEMCALRecoUtils::RecalculateClusterPositionFromTowerGlobal(AliEMCALGeometry *geom, AliVCaloCells* cells, AliVCluster* clu)
570 // For a given CaloCluster recalculates the position for a given set of misalignment shifts and puts it again in the CaloCluster.
571 // The algorithm is a copy of what is done in AliEMCALRecPoint
574 Float_t fraction = 1.;
575 Float_t recalFactor = 1.;
578 Int_t iTower = -1, iIphi = -1, iIeta = -1;
579 Int_t iSupModMax = -1, iSM=-1, iphi = -1, ieta = -1;
580 Float_t weight = 0., totalWeight=0.;
581 Float_t newPos[3] = {0,0,0};
582 Double_t pLocal[3], pGlobal[3];
583 Bool_t shared = kFALSE;
585 Float_t clEnergy = clu->E(); //Energy already recalibrated previously
586 GetMaxEnergyCell(geom, cells, clu, absId, iSupModMax, ieta, iphi,shared);
587 Double_t depth = GetDepth(clEnergy,fParticleType,iSupModMax) ;
589 //printf("** Cluster energy %f, ncells %d, depth %f\n",clEnergy,clu->GetNCells(),depth);
591 for (Int_t iDig=0; iDig< clu->GetNCells(); iDig++) {
592 absId = clu->GetCellAbsId(iDig);
593 fraction = clu->GetCellAmplitudeFraction(iDig);
594 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
595 geom->GetCellIndex(absId,iSM,iTower,iIphi,iIeta);
596 geom->GetCellPhiEtaIndexInSModule(iSM,iTower,iIphi, iIeta,iphi,ieta);
598 if(IsRecalibrationOn()) {
599 recalFactor = GetEMCALChannelRecalibrationFactor(iSM,ieta,iphi);
601 eCell = cells->GetCellAmplitude(absId)*fraction*recalFactor;
603 weight = GetCellWeight(eCell,clEnergy);
604 //printf("cell energy %f, weight %f\n",eCell,weight);
605 totalWeight += weight;
606 geom->RelPosCellInSModule(absId,depth,pLocal[0],pLocal[1],pLocal[2]);
607 //printf("pLocal (%f,%f,%f), SM %d, absId %d\n",pLocal[0],pLocal[1],pLocal[2],iSupModMax,absId);
608 geom->GetGlobal(pLocal,pGlobal,iSupModMax);
609 //printf("pLocal (%f,%f,%f)\n",pGlobal[0],pGlobal[1],pGlobal[2]);
611 for(int i=0; i<3; i++ ) newPos[i] += (weight*pGlobal[i]);
616 for(int i=0; i<3; i++ ) newPos[i] /= totalWeight;
619 //Float_t pos[]={0,0,0};
620 //clu->GetPosition(pos);
621 //printf("OldPos : %2.3f,%2.3f,%2.3f\n",pos[0],pos[1],pos[2]);
622 //printf("NewPos : %2.3f,%2.3f,%2.3f\n",newPos[0],newPos[1],newPos[2]);
624 if(iSupModMax > 1) {//sector 1
625 newPos[0] +=fMisalTransShift[3];//-=3.093;
626 newPos[1] +=fMisalTransShift[4];//+=6.82;
627 newPos[2] +=fMisalTransShift[5];//+=1.635;
628 //printf(" + : %2.3f,%2.3f,%2.3f\n",fMisalTransShift[3],fMisalTransShift[4],fMisalTransShift[5]);
632 newPos[0] +=fMisalTransShift[0];//+=1.134;
633 newPos[1] +=fMisalTransShift[1];//+=8.2;
634 newPos[2] +=fMisalTransShift[2];//+=1.197;
635 //printf(" + : %2.3f,%2.3f,%2.3f\n",fMisalTransShift[0],fMisalTransShift[1],fMisalTransShift[2]);
638 //printf("NewPos : %2.3f,%2.3f,%2.3f\n",newPos[0],newPos[1],newPos[2]);
640 clu->SetPosition(newPos);
644 //__________________________________________________
645 void AliEMCALRecoUtils::RecalculateClusterPositionFromTowerIndex(AliEMCALGeometry *geom, AliVCaloCells* cells, AliVCluster* clu)
647 // For a given CaloCluster recalculates the position for a given set of misalignment shifts and puts it again in the CaloCluster.
648 // The algorithm works with the tower indeces, averages the indeces and from them it calculates the global position
651 Float_t fraction = 1.;
652 Float_t recalFactor = 1.;
656 Int_t iIphi = -1, iIeta = -1;
657 Int_t iSupMod = -1, iSupModMax = -1;
658 Int_t iphi = -1, ieta =-1;
659 Bool_t shared = kFALSE;
661 Float_t clEnergy = clu->E(); //Energy already recalibrated previously.
662 GetMaxEnergyCell(geom, cells, clu, absId, iSupModMax, ieta, iphi,shared);
663 Float_t depth = GetDepth(clEnergy,fParticleType,iSupMod) ;
665 Float_t weight = 0., weightedCol = 0., weightedRow = 0., totalWeight=0.;
666 Bool_t areInSameSM = kTRUE; //exclude clusters with cells in different SMs for now
667 Int_t startingSM = -1;
669 for (Int_t iDig=0; iDig< clu->GetNCells(); iDig++) {
670 absId = clu->GetCellAbsId(iDig);
671 fraction = clu->GetCellAmplitudeFraction(iDig);
672 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
673 geom->GetCellIndex(absId,iSupMod,iTower,iIphi,iIeta);
674 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi, iIeta,iphi,ieta);
676 if (iDig==0) startingSM = iSupMod;
677 else if(iSupMod != startingSM) areInSameSM = kFALSE;
679 eCell = cells->GetCellAmplitude(absId);
681 if(IsRecalibrationOn()) {
682 recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
684 eCell = cells->GetCellAmplitude(absId)*fraction*recalFactor;
686 weight = GetCellWeight(eCell,clEnergy);
687 if(weight < 0) weight = 0;
688 totalWeight += weight;
689 weightedCol += ieta*weight;
690 weightedRow += iphi*weight;
692 //printf("Max cell? cell %d, amplitude org %f, fraction %f, recalibration %f, amplitude new %f \n",cellAbsId, cells->GetCellAmplitude(cellAbsId), fraction, recalFactor, eCell) ;
696 Float_t xyzNew[]={0.,0.,0.};
697 if(areInSameSM == kTRUE) {
698 //printf("In Same SM\n");
699 weightedCol = weightedCol/totalWeight;
700 weightedRow = weightedRow/totalWeight;
701 geom->RecalculateTowerPosition(weightedRow, weightedCol, iSupModMax, depth, fMisalTransShift, fMisalRotShift, xyzNew);
704 //printf("In Different SM\n");
705 geom->RecalculateTowerPosition(iphi, ieta, iSupModMax, depth, fMisalTransShift, fMisalRotShift, xyzNew);
708 clu->SetPosition(xyzNew);
712 //____________________________________________________________________________
713 void AliEMCALRecoUtils::RecalculateClusterDistanceToBadChannel(AliEMCALGeometry * geom, AliVCaloCells* cells, AliVCluster * cluster){
715 //re-evaluate distance to bad channel with updated bad map
717 if(!fRecalDistToBadChannels) return;
719 //Get channels map of the supermodule where the cluster is.
720 Int_t absIdMax = -1, iSupMod =-1, icolM = -1, irowM = -1;
721 Bool_t shared = kFALSE;
722 GetMaxEnergyCell(geom, cells, cluster, absIdMax, iSupMod, icolM, irowM, shared);
723 TH2D* hMap = (TH2D*)fEMCALBadChannelMap->At(iSupMod);
726 Float_t minDist = 10000.;
729 //Loop on tower status map
730 for(Int_t irow = 0; irow < AliEMCALGeoParams::fgkEMCALRows; irow++){
731 for(Int_t icol = 0; icol < AliEMCALGeoParams::fgkEMCALCols; icol++){
732 //Check if tower is bad.
733 if(hMap->GetBinContent(icol,irow)==0) continue;
734 //printf("AliEMCALRecoUtils::RecalculateDistanceToBadChannels() - \n \t Bad channel in SM %d, col %d, row %d, \n \t Cluster max in col %d, row %d\n",
735 // iSupMod,icol, irow, icolM,irowM);
737 dRrow=TMath::Abs(irowM-irow);
738 dRcol=TMath::Abs(icolM-icol);
739 dist=TMath::Sqrt(dRrow*dRrow+dRcol*dRcol);
741 //printf("MIN DISTANCE TO BAD %2.2f\n",dist);
748 //In case the cluster is shared by 2 SuperModules, need to check the map of the second Super Module
753 //The only possible combinations are (0,1), (2,3) ... (8,9)
754 if(iSupMod%2) iSupMod2 = iSupMod-1;
755 else iSupMod2 = iSupMod+1;
756 hMap2 = (TH2D*)fEMCALBadChannelMap->At(iSupMod2);
758 //Loop on tower status map of second super module
759 for(Int_t irow = 0; irow < AliEMCALGeoParams::fgkEMCALRows; irow++){
760 for(Int_t icol = 0; icol < AliEMCALGeoParams::fgkEMCALCols; icol++){
761 //Check if tower is bad.
762 if(hMap2->GetBinContent(icol,irow)==0) continue;
763 //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",
764 // iSupMod2,icol, irow,iSupMod,icolM,irowM);
766 dRrow=TMath::Abs(irow-irowM);
769 dRcol=TMath::Abs(icol-(AliEMCALGeoParams::fgkEMCALCols+icolM));
772 dRcol=TMath::Abs(AliEMCALGeoParams::fgkEMCALCols+icol-icolM);
775 dist=TMath::Sqrt(dRrow*dRrow+dRcol*dRcol);
776 if(dist < minDist) minDist = dist;
781 }// shared cluster in 2 SuperModules
783 AliDebug(2,Form("AliEMCALRecoUtils::RecalculateDistanceToBadChannels() - Max cluster cell (SM,col,row)=(%d %d %d) - Distance to Bad Channel %2.2f\n",iSupMod, icolM, irowM, minDist));
784 cluster->SetDistanceToBadChannel(minDist);
788 //____________________________________________________________________________
789 void AliEMCALRecoUtils::RecalculateClusterPID(AliVCluster * cluster){
791 //re-evaluate identification parameters with bayesian
793 if ( cluster->GetM02() != 0)
794 fPIDUtils->ComputePID(cluster->E(),cluster->GetM02());
796 Float_t pidlist[AliPID::kSPECIESN+1];
797 for(Int_t i = 0; i < AliPID::kSPECIESN+1; i++) pidlist[i] = fPIDUtils->GetPIDFinal(i);
799 cluster->SetPID(pidlist);
803 //____________________________________________________________________________
804 void AliEMCALRecoUtils::RecalculateClusterShowerShapeParameters(AliEMCALGeometry * geom, AliVCaloCells* cells, AliVCluster * cluster)
806 // Calculates new center of gravity in the local EMCAL-module coordinates
807 // and tranfers into global ALICE coordinates
808 // Calculates Dispersion and main axis
813 Float_t fraction = 1.;
814 Float_t recalFactor = 1.;
834 for(Int_t iDigit=0; iDigit < cluster->GetNCells(); iDigit++) {
836 //Get from the absid the supermodule, tower and eta/phi numbers
837 geom->GetCellIndex(cluster->GetCellAbsId(iDigit),iSupMod,iTower,iIphi,iIeta);
838 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi,iIeta, iphi,ieta);
840 //Get the cell energy, if recalibration is on, apply factors
841 fraction = cluster->GetCellAmplitudeFraction(iDigit);
842 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
843 if(IsRecalibrationOn()) {
844 recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
846 eCell = cells->GetCellAmplitude(cluster->GetCellAbsId(iDigit))*fraction*recalFactor;
848 if(cluster->E() > 0 && eCell > 0){
850 w = GetCellWeight(eCell,cluster->E());
858 dxx += w * etai * etai ;
860 dzz += w * phii * phii ;
862 dxz += w * etai * phii ;
866 AliError(Form("Wrong energy %f and/or amplitude %f\n", eCell, cluster->E()));
869 //Normalize to the weight
875 AliError(Form("Wrong weight %f\n", wtot));
877 //Calculate dispersion
878 for(Int_t iDigit=0; iDigit < cluster->GetNCells(); iDigit++) {
880 //Get from the absid the supermodule, tower and eta/phi numbers
881 geom->GetCellIndex(cluster->GetCellAbsId(iDigit),iSupMod,iTower,iIphi,iIeta);
882 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi,iIeta, iphi,ieta);
884 //Get the cell energy, if recalibration is on, apply factors
885 fraction = cluster->GetCellAmplitudeFraction(iDigit);
886 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
887 if(IsRecalibrationOn()) {
888 recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
890 eCell = cells->GetCellAmplitude(cluster->GetCellAbsId(iDigit))*fraction*recalFactor;
892 if(cluster->E() > 0 && eCell > 0){
894 w = GetCellWeight(eCell,cluster->E());
898 if(w > 0.0) d += w*((etai-xmean)*(etai-xmean)+(phii-zmean)*(phii-zmean));
901 AliError(Form("Wrong energy %f and/or amplitude %f\n", eCell, cluster->E()));
904 //Normalize to the weigth and set shower shape parameters
905 if (wtot > 0 && nstat > 1) {
910 dxx -= xmean * xmean ;
911 dzz -= zmean * zmean ;
912 dxz -= xmean * zmean ;
913 cluster->SetM02(0.5 * (dxx + dzz) + TMath::Sqrt( 0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz ));
914 cluster->SetM20(0.5 * (dxx + dzz) - TMath::Sqrt( 0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz ));
918 cluster->SetM20(0.) ;
919 cluster->SetM02(0.) ;
923 cluster->SetDispersion(TMath::Sqrt(d)) ;
925 cluster->SetDispersion(0) ;
929 //__________________________________________________
930 void AliEMCALRecoUtils::FindMatches(AliVEvent *event)
932 //This function should be called before the cluster loop
933 //Before call this function, please recalculate the cluster positions
934 //Given the input event, loop over all the tracks, select the closest cluster as matched with fCutR
935 //Store matched cluster indexes and residuals
936 //It only works with ESDs, not AODs
938 fMatchedClusterIndex->Reset();
942 fMatchedClusterIndex->Set(100);
943 fResidualZ->Set(100);
944 fResidualR->Set(100);
949 for(Int_t itr=0; itr<event->GetNumberOfTracks(); itr++)
951 AliESDtrack *track = ((AliESDEvent*)event)->GetTrack(itr);
952 if(!track || !IsAccepted(track)) continue;
954 Float_t dRMax = fCutR, dZMax = fCutZ;
956 AliEMCALTrack *emctrack = new AliEMCALTrack(*track);
957 for(Int_t icl=0; icl<event->GetNumberOfCaloClusters(); icl++)
959 AliVCluster *cluster = (AliVCluster*) event->GetCaloCluster(icl);
960 if(!cluster->IsEMCAL()) continue;
961 cluster->GetPosition(clsPos); //Has been recalculated
962 if(!emctrack->PropagateToGlobal(clsPos[0],clsPos[1],clsPos[2],0.,0.) ) continue;
963 emctrack->GetXYZ(trkPos);
964 Float_t tmpR = TMath::Sqrt( TMath::Power(clsPos[0]-trkPos[0],2)+TMath::Power(clsPos[1]-trkPos[1],2)+TMath::Power(clsPos[2]-trkPos[2],2) );
965 Float_t tmpZ = TMath::Abs(clsPos[2]-trkPos[2]);
978 fMatchedClusterIndex->AddAt(index,matched);
979 fResidualZ->AddAt(dZMax,matched);
980 fResidualR->AddAt(dRMax,matched);
985 fMatchedClusterIndex->Set(matched);
986 fResidualZ->Set(matched);
987 fResidualR->Set(matched);
989 //printf("Number of matched pairs: %d\n",matched);
992 //__________________________________________________
993 void AliEMCALRecoUtils::GetMatchedResiduals(Int_t index, Float_t &dR, Float_t &dZ)
995 //Given a cluster index as in AliESDEvent::GetCaloCluster(index)
996 //Get the residuals dR and dZ for this cluster
997 //It only works with ESDs, not AODs
999 if( FindMatchedPos(index) >= 999 )
1001 AliDebug(2,"No matched tracks found!\n");
1006 dR = fResidualR->At(FindMatchedPos(index));
1007 dZ = fResidualZ->At(FindMatchedPos(index));
1010 //__________________________________________________
1011 Bool_t AliEMCALRecoUtils::IsMatched(Int_t index)
1013 //Given a cluster index as in AliESDEvent::GetCaloCluster(index)
1014 //Returns if cluster has a match
1015 if(FindMatchedPos(index) < 999)
1020 //__________________________________________________
1021 UInt_t AliEMCALRecoUtils::FindMatchedPos(Int_t index) const
1023 //Given a cluster index as in AliESDEvent::GetCaloCluster(index)
1024 //Returns the position of the match in the fMatchedClusterIndex array
1025 Float_t tmpR = fCutR;
1028 for(Int_t i=0; i<fMatchedClusterIndex->GetSize(); i++)
1030 if(fMatchedClusterIndex->At(i)==index && fResidualR->At(i)<tmpR)
1033 tmpR=fResidualR->At(i);
1035 AliDebug(3,Form("Matched cluster pos: %d, index: %d, dR: %2.4f, dZ: %2.4f.\n",i,fMatchedClusterIndex->At(i),fResidualR->At(i),fResidualZ->At(i)));
1040 Bool_t AliEMCALRecoUtils::IsAccepted(AliESDtrack *esdTrack)
1042 // Given a esd track, return whether the track survive all the cuts
1044 // The different quality parameter are first
1045 // retrieved from the track. then it is found out what cuts the
1046 // track did not survive and finally the cuts are imposed.
1048 UInt_t status = esdTrack->GetStatus();
1050 Int_t nClustersITS = esdTrack->GetITSclusters(0);
1051 Int_t nClustersTPC = esdTrack->GetTPCclusters(0);
1053 Float_t chi2PerClusterITS = -1;
1054 Float_t chi2PerClusterTPC = -1;
1055 if (nClustersITS!=0)
1056 chi2PerClusterITS = esdTrack->GetITSchi2()/Float_t(nClustersITS);
1057 if (nClustersTPC!=0)
1058 chi2PerClusterTPC = esdTrack->GetTPCchi2()/Float_t(nClustersTPC);
1062 Float_t MaxDCAToVertexXYPtDep = 0.0182 + 0.0350/TMath::Power(esdTrack->Pt(),1.01); //This expression comes from AliESDtrackCuts::GetStandardITSTPCTrackCuts2010()
1063 //AliDebug(3,Form("Track pT = %f, DCAtoVertexXY = %f",esdTrack->Pt(),MaxDCAToVertexXYPtDep));
1064 SetMaxDCAToVertexXY(MaxDCAToVertexXYPtDep); //Set pT dependent DCA cut to vertex in x-y plane
1069 esdTrack->GetImpactParameters(b,bCov);
1070 if (bCov[0]<=0 || bCov[2]<=0) {
1071 AliDebug(1, "Estimated b resolution lower or equal zero!");
1072 bCov[0]=0; bCov[2]=0;
1075 Float_t dcaToVertexXY = b[0];
1076 Float_t dcaToVertexZ = b[1];
1077 Float_t dcaToVertex = -1;
1079 if (fCutDCAToVertex2D)
1080 dcaToVertex = TMath::Sqrt(dcaToVertexXY*dcaToVertexXY/fCutMaxDCAToVertexXY/fCutMaxDCAToVertexXY + dcaToVertexZ*dcaToVertexZ/fCutMaxDCAToVertexZ/fCutMaxDCAToVertexZ);
1082 dcaToVertex = TMath::Sqrt(dcaToVertexXY*dcaToVertexXY + dcaToVertexZ*dcaToVertexZ);
1086 Bool_t cuts[kNCuts];
1087 for (Int_t i=0; i<kNCuts; i++) cuts[i]=kFALSE;
1089 // track quality cuts
1090 if (fCutRequireTPCRefit && (status&AliESDtrack::kTPCrefit)==0)
1092 if (fCutRequireITSRefit && (status&AliESDtrack::kITSrefit)==0)
1094 if (nClustersTPC<fCutMinNClusterTPC)
1096 if (nClustersITS<fCutMinNClusterITS)
1098 if (chi2PerClusterTPC>fCutMaxChi2PerClusterTPC)
1100 if (chi2PerClusterITS>fCutMaxChi2PerClusterITS)
1102 if (!fCutAcceptKinkDaughters && esdTrack->GetKinkIndex(0)>0)
1104 if (fCutDCAToVertex2D && dcaToVertex > 1)
1106 if (!fCutDCAToVertex2D && TMath::Abs(dcaToVertexXY) > fCutMaxDCAToVertexXY)
1108 if (!fCutDCAToVertex2D && TMath::Abs(dcaToVertexZ) > fCutMaxDCAToVertexZ)
1111 //Require at least one SPD point + anything else in ITS
1112 if( (esdTrack->HasPointOnITSLayer(0) || esdTrack->HasPointOnITSLayer(1)) == kFALSE)
1116 for (Int_t i=0; i<kNCuts; i++)
1117 if (cuts[i]) {cut = kTRUE;}
1125 //__________________________________________________
1126 void AliEMCALRecoUtils::InitTrackCuts()
1128 //Intilize the track cut criteria
1129 //By default these cuts are set according to AliESDtrackCuts::GetStandardITSTPCTrackCuts2010()
1130 //Also you can customize the cuts using the setters
1133 SetMinNClustersTPC(70);
1134 SetMaxChi2PerClusterTPC(4);
1135 SetAcceptKinkDaughters(kFALSE);
1136 SetRequireTPCRefit(kTRUE);
1139 SetRequireITSRefit(kTRUE);
1140 SetMaxDCAToVertexZ(2);
1141 SetDCAToVertex2D(kFALSE);
1144 //__________________________________________________
1145 void AliEMCALRecoUtils::Print(const Option_t *) const
1149 printf("AliEMCALRecoUtils Settings: \n");
1150 printf("Misalignment shifts\n");
1151 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,
1152 fMisalTransShift[i*3],fMisalTransShift[i*3+1],fMisalTransShift[i*3+2],
1153 fMisalRotShift[i*3], fMisalRotShift[i*3+1], fMisalRotShift[i*3+2] );
1154 printf("Non linearity function %d, parameters:\n", fNonLinearityFunction);
1155 for(Int_t i=0; i<6; i++) printf("param[%d]=%f\n",i, fNonLinearityParams[i]);
1157 printf("Position Recalculation option %d, Particle Type %d, fW0 %2.2f, Recalibrate Data %d \n",fPosAlgo,fParticleType,fW0, fRecalibration);
1159 printf("Matching criteria: dR < %2.2f[cm], dZ < %2.2f[cm]\n",fCutR,fCutZ);
1161 printf("Track cuts: \n");
1162 printf("TPCRefit = %d, ITSRefit = %d\n",fCutRequireTPCRefit,fCutRequireITSRefit);
1163 printf("AcceptKinks = %d\n",fCutAcceptKinkDaughters);
1164 printf("MinNCulsterTPC = %d, MinNClusterITS = %d\n",fCutMinNClusterTPC,fCutMinNClusterITS);
1165 printf("MaxChi2TPC = %2.2f, MaxChi2ITS = %2.2f\n",fCutMaxChi2PerClusterTPC,fCutMaxChi2PerClusterITS);
1166 printf("DCSToVertex2D = %d, MaxDCAToVertexXY = %2.2f, MaxDCAToVertexZ = %2.2f\n",fCutDCAToVertex2D,fCutMaxDCAToVertexXY,fCutMaxDCAToVertexZ);