]> git.uio.no Git - u/mrichter/AliRoot.git/blame_incremental - EMCAL/AliEMCALRecoUtils.cxx
correct previous non intended commit, but leaving some new things
[u/mrichter/AliRoot.git] / EMCAL / AliEMCALRecoUtils.cxx
... / ...
CommitLineData
1/**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3 * *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
6 * *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
15
16/* $Id: AliEMCALRecoUtils.cxx 33808 2009-07-15 09:48:08Z gconesab $ */
17
18///////////////////////////////////////////////////////////////////////////////
19//
20// Class AliEMCALRecoUtils
21// Some utilities to recalculate the cluster position or energy linearity
22//
23//
24// Author: Gustavo Conesa (LPSC- Grenoble)
25// Track matching part: Rongrong Ma (Yale)
26
27///////////////////////////////////////////////////////////////////////////////
28// --- standard c ---
29
30// standard C++ includes
31//#include <Riostream.h>
32
33// ROOT includes
34#include <TGeoManager.h>
35#include <TGeoMatrix.h>
36#include <TGeoBBox.h>
37#include <TH2F.h>
38#include <TArrayI.h>
39#include <TArrayF.h>
40#include <TObjArray.h>
41
42// STEER includes
43#include "AliVCluster.h"
44#include "AliVCaloCells.h"
45#include "AliLog.h"
46#include "AliPID.h"
47#include "AliESDEvent.h"
48#include "AliAODEvent.h"
49#include "AliESDtrack.h"
50#include "AliAODTrack.h"
51#include "AliExternalTrackParam.h"
52#include "AliESDfriendTrack.h"
53#include "AliTrackerBase.h"
54
55// EMCAL includes
56#include "AliEMCALRecoUtils.h"
57#include "AliEMCALGeometry.h"
58#include "AliTrackerBase.h"
59#include "AliEMCALPIDUtils.h"
60
61ClassImp(AliEMCALRecoUtils)
62
63//_____________________________________
64AliEMCALRecoUtils::AliEMCALRecoUtils():
65 fParticleType(0), fPosAlgo(0), fW0(0),
66 fNonLinearityFunction(0), fNonLinearThreshold(0),
67 fSmearClusterEnergy(kFALSE), fRandom(),
68 fCellsRecalibrated(kFALSE), fRecalibration(kFALSE), fEMCALRecalibrationFactors(),
69 fTimeRecalibration(kFALSE), fEMCALTimeRecalibrationFactors(), fUseRunCorrectionFactors(kFALSE),
70 fRemoveBadChannels(kFALSE), fRecalDistToBadChannels(kFALSE), fEMCALBadChannelMap(),
71 fNCellsFromEMCALBorder(0), fNoEMCALBorderAtEta0(kTRUE),
72 fRejectExoticCluster(kFALSE), fRejectExoticCells(kFALSE),
73 fExoticCellFraction(0), fExoticCellDiffTime(0), fExoticCellMinAmplitude(0),
74 fPIDUtils(), fAODFilterMask(0),
75 fMatchedTrackIndex(0x0), fMatchedClusterIndex(0x0),
76 fResidualEta(0x0), fResidualPhi(0x0), fCutEtaPhiSum(kFALSE), fCutEtaPhiSeparate(kFALSE),
77 fCutR(0), fCutEta(0), fCutPhi(0),
78 fClusterWindow(0), fMass(0),
79 fStepSurface(0), fStepCluster(0),
80 fITSTrackSA(kFALSE),
81 fTrackCutsType(0), fCutMinTrackPt(0), fCutMinNClusterTPC(0),
82 fCutMinNClusterITS(0), fCutMaxChi2PerClusterTPC(0), fCutMaxChi2PerClusterITS(0),
83 fCutRequireTPCRefit(kFALSE), fCutRequireITSRefit(kFALSE), fCutAcceptKinkDaughters(kFALSE),
84 fCutMaxDCAToVertexXY(0), fCutMaxDCAToVertexZ(0), fCutDCAToVertex2D(kFALSE),
85 fCutRequireITSStandAlone(kFALSE), fCutRequireITSpureSA(kFALSE)
86{
87//
88 // Constructor.
89 // Initialize all constant values which have to be used
90 // during Reco algorithm execution
91 //
92
93 // Init parameters
94 InitParameters();
95
96 //Track matching
97 fMatchedTrackIndex = new TArrayI();
98 fMatchedClusterIndex = new TArrayI();
99 fResidualPhi = new TArrayF();
100 fResidualEta = new TArrayF();
101 fPIDUtils = new AliEMCALPIDUtils();
102
103}
104
105//______________________________________________________________________
106AliEMCALRecoUtils::AliEMCALRecoUtils(const AliEMCALRecoUtils & reco)
107: TNamed(reco),
108 fParticleType(reco.fParticleType), fPosAlgo(reco.fPosAlgo), fW0(reco.fW0),
109 fNonLinearityFunction(reco.fNonLinearityFunction), fNonLinearThreshold(reco.fNonLinearThreshold),
110 fSmearClusterEnergy(reco.fSmearClusterEnergy), fRandom(),
111 fCellsRecalibrated(reco.fCellsRecalibrated),
112 fRecalibration(reco.fRecalibration), fEMCALRecalibrationFactors(reco.fEMCALRecalibrationFactors),
113 fTimeRecalibration(reco.fTimeRecalibration), fEMCALTimeRecalibrationFactors(reco.fEMCALTimeRecalibrationFactors),
114 fUseRunCorrectionFactors(reco.fUseRunCorrectionFactors),
115 fRemoveBadChannels(reco.fRemoveBadChannels), fRecalDistToBadChannels(reco.fRecalDistToBadChannels),
116 fEMCALBadChannelMap(reco.fEMCALBadChannelMap),
117 fNCellsFromEMCALBorder(reco.fNCellsFromEMCALBorder), fNoEMCALBorderAtEta0(reco.fNoEMCALBorderAtEta0),
118 fRejectExoticCluster(reco.fRejectExoticCluster), fRejectExoticCells(reco.fRejectExoticCells),
119 fExoticCellFraction(reco.fExoticCellFraction), fExoticCellDiffTime(reco.fExoticCellDiffTime),
120 fExoticCellMinAmplitude(reco.fExoticCellMinAmplitude),
121 fPIDUtils(reco.fPIDUtils), fAODFilterMask(reco.fAODFilterMask),
122 fMatchedTrackIndex( reco.fMatchedTrackIndex? new TArrayI(*reco.fMatchedTrackIndex):0x0),
123 fMatchedClusterIndex(reco.fMatchedClusterIndex?new TArrayI(*reco.fMatchedClusterIndex):0x0),
124 fResidualEta( reco.fResidualEta? new TArrayF(*reco.fResidualEta):0x0),
125 fResidualPhi( reco.fResidualPhi? new TArrayF(*reco.fResidualPhi):0x0),
126 fCutEtaPhiSum(reco.fCutEtaPhiSum), fCutEtaPhiSeparate(reco.fCutEtaPhiSeparate),
127 fCutR(reco.fCutR), fCutEta(reco.fCutEta), fCutPhi(reco.fCutPhi),
128 fClusterWindow(reco.fClusterWindow),
129 fMass(reco.fMass), fStepSurface(reco.fStepSurface), fStepCluster(reco.fStepCluster),
130 fITSTrackSA(reco.fITSTrackSA),
131 fTrackCutsType(reco.fTrackCutsType), fCutMinTrackPt(reco.fCutMinTrackPt),
132 fCutMinNClusterTPC(reco.fCutMinNClusterTPC), fCutMinNClusterITS(reco.fCutMinNClusterITS),
133 fCutMaxChi2PerClusterTPC(reco.fCutMaxChi2PerClusterTPC), fCutMaxChi2PerClusterITS(reco.fCutMaxChi2PerClusterITS),
134 fCutRequireTPCRefit(reco.fCutRequireTPCRefit), fCutRequireITSRefit(reco.fCutRequireITSRefit),
135 fCutAcceptKinkDaughters(reco.fCutAcceptKinkDaughters), fCutMaxDCAToVertexXY(reco.fCutMaxDCAToVertexXY),
136 fCutMaxDCAToVertexZ(reco.fCutMaxDCAToVertexZ), fCutDCAToVertex2D(reco.fCutDCAToVertex2D),
137 fCutRequireITSStandAlone(reco.fCutRequireITSStandAlone), fCutRequireITSpureSA(reco.fCutRequireITSpureSA)
138{
139 //Copy ctor
140
141 for(Int_t i = 0; i < 15 ; i++) { fMisalRotShift[i] = reco.fMisalRotShift[i] ;
142 fMisalTransShift[i] = reco.fMisalTransShift[i] ; }
143 for(Int_t i = 0; i < 7 ; i++) { fNonLinearityParams[i] = reco.fNonLinearityParams[i] ; }
144 for(Int_t i = 0; i < 3 ; i++) { fSmearClusterParam[i] = reco.fSmearClusterParam[i] ; }
145
146}
147
148
149//______________________________________________________________________
150AliEMCALRecoUtils & AliEMCALRecoUtils::operator = (const AliEMCALRecoUtils & reco)
151{
152 //Assignment operator
153
154 if(this == &reco)return *this;
155 ((TNamed *)this)->operator=(reco);
156
157 for(Int_t i = 0; i < 15 ; i++) { fMisalTransShift[i] = reco.fMisalTransShift[i] ;
158 fMisalRotShift[i] = reco.fMisalRotShift[i] ; }
159 for(Int_t i = 0; i < 7 ; i++) { fNonLinearityParams[i] = reco.fNonLinearityParams[i] ; }
160 for(Int_t i = 0; i < 3 ; i++) { fSmearClusterParam[i] = reco.fSmearClusterParam[i] ; }
161
162 fParticleType = reco.fParticleType;
163 fPosAlgo = reco.fPosAlgo;
164 fW0 = reco.fW0;
165
166 fNonLinearityFunction = reco.fNonLinearityFunction;
167 fNonLinearThreshold = reco.fNonLinearThreshold;
168 fSmearClusterEnergy = reco.fSmearClusterEnergy;
169
170 fCellsRecalibrated = reco.fCellsRecalibrated;
171 fRecalibration = reco.fRecalibration;
172 fEMCALRecalibrationFactors = reco.fEMCALRecalibrationFactors;
173
174 fTimeRecalibration = reco.fTimeRecalibration;
175 fEMCALTimeRecalibrationFactors = reco.fEMCALTimeRecalibrationFactors;
176
177 fUseRunCorrectionFactors = reco.fUseRunCorrectionFactors;
178
179 fRemoveBadChannels = reco.fRemoveBadChannels;
180 fRecalDistToBadChannels = reco.fRecalDistToBadChannels;
181 fEMCALBadChannelMap = reco.fEMCALBadChannelMap;
182
183 fNCellsFromEMCALBorder = reco.fNCellsFromEMCALBorder;
184 fNoEMCALBorderAtEta0 = reco.fNoEMCALBorderAtEta0;
185
186 fRejectExoticCluster = reco.fRejectExoticCluster;
187 fRejectExoticCells = reco.fRejectExoticCells;
188 fExoticCellFraction = reco.fExoticCellFraction;
189 fExoticCellDiffTime = reco.fExoticCellDiffTime;
190 fExoticCellMinAmplitude = reco.fExoticCellMinAmplitude;
191
192 fPIDUtils = reco.fPIDUtils;
193
194 fAODFilterMask = reco.fAODFilterMask;
195
196 fCutEtaPhiSum = reco.fCutEtaPhiSum;
197 fCutEtaPhiSeparate = reco.fCutEtaPhiSeparate;
198 fCutR = reco.fCutR;
199 fCutEta = reco.fCutEta;
200 fCutPhi = reco.fCutPhi;
201 fClusterWindow = reco.fClusterWindow;
202 fMass = reco.fMass;
203 fStepSurface = reco.fStepSurface;
204 fStepCluster = reco.fStepCluster;
205 fITSTrackSA = reco.fITSTrackSA;
206
207 fTrackCutsType = reco.fTrackCutsType;
208 fCutMinTrackPt = reco.fCutMinTrackPt;
209 fCutMinNClusterTPC = reco.fCutMinNClusterTPC;
210 fCutMinNClusterITS = reco.fCutMinNClusterITS;
211 fCutMaxChi2PerClusterTPC = reco.fCutMaxChi2PerClusterTPC;
212 fCutMaxChi2PerClusterITS = reco.fCutMaxChi2PerClusterITS;
213 fCutRequireTPCRefit = reco.fCutRequireTPCRefit;
214 fCutRequireITSRefit = reco.fCutRequireITSRefit;
215 fCutAcceptKinkDaughters = reco.fCutAcceptKinkDaughters;
216 fCutMaxDCAToVertexXY = reco.fCutMaxDCAToVertexXY;
217 fCutMaxDCAToVertexZ = reco.fCutMaxDCAToVertexZ;
218 fCutDCAToVertex2D = reco.fCutDCAToVertex2D;
219 fCutRequireITSStandAlone = reco.fCutRequireITSStandAlone;
220 fCutRequireITSpureSA = reco.fCutRequireITSpureSA;
221 if(reco.fResidualEta)
222 {
223 // assign or copy construct
224 if(fResidualEta)
225 {
226 *fResidualEta = *reco.fResidualEta;
227 }
228 else
229 {
230 fResidualEta = new TArrayF(*reco.fResidualEta);
231 }
232 }
233 else
234 {
235 if(fResidualEta)delete fResidualEta;
236 fResidualEta = 0;
237 }
238
239 if(reco.fResidualPhi)
240 {
241 // assign or copy construct
242 if(fResidualPhi)
243 {
244 *fResidualPhi = *reco.fResidualPhi;
245 }
246 else
247 {
248 fResidualPhi = new TArrayF(*reco.fResidualPhi);
249 }
250 }
251 else
252 {
253 if(fResidualPhi)delete fResidualPhi;
254 fResidualPhi = 0;
255 }
256
257 if(reco.fMatchedTrackIndex)
258 {
259 // assign or copy construct
260 if(fMatchedTrackIndex)
261 {
262 *fMatchedTrackIndex = *reco.fMatchedTrackIndex;
263 }
264 else
265 {
266 fMatchedTrackIndex = new TArrayI(*reco.fMatchedTrackIndex);
267 }
268 }
269 else
270 {
271 if(fMatchedTrackIndex)delete fMatchedTrackIndex;
272 fMatchedTrackIndex = 0;
273 }
274
275 if(reco.fMatchedClusterIndex)
276 {
277 // assign or copy construct
278 if(fMatchedClusterIndex)
279 {
280 *fMatchedClusterIndex = *reco.fMatchedClusterIndex;
281 }
282 else
283 {
284 fMatchedClusterIndex = new TArrayI(*reco.fMatchedClusterIndex);
285 }
286 }
287 else
288 {
289 if(fMatchedClusterIndex)delete fMatchedClusterIndex;
290 fMatchedClusterIndex = 0;
291 }
292
293 return *this;
294}
295
296
297//_____________________________________
298AliEMCALRecoUtils::~AliEMCALRecoUtils()
299{
300 //Destructor.
301
302 if(fEMCALRecalibrationFactors)
303 {
304 fEMCALRecalibrationFactors->Clear();
305 delete fEMCALRecalibrationFactors;
306 }
307
308 if(fEMCALTimeRecalibrationFactors)
309 {
310 fEMCALTimeRecalibrationFactors->Clear();
311 delete fEMCALTimeRecalibrationFactors;
312 }
313
314 if(fEMCALBadChannelMap)
315 {
316 fEMCALBadChannelMap->Clear();
317 delete fEMCALBadChannelMap;
318 }
319
320 delete fMatchedTrackIndex ;
321 delete fMatchedClusterIndex ;
322 delete fResidualEta ;
323 delete fResidualPhi ;
324 delete fPIDUtils ;
325
326 InitTrackCuts();
327}
328
329//_______________________________________________________________________________
330Bool_t AliEMCALRecoUtils::AcceptCalibrateCell(const Int_t absID, const Int_t bc,
331 Float_t & amp, Double_t & time,
332 AliVCaloCells* cells)
333{
334 // Reject cell if criteria not passed and calibrate it
335
336 AliEMCALGeometry* geom = AliEMCALGeometry::GetInstance();
337
338 if(absID < 0 || absID >= 24*48*geom->GetNumberOfSuperModules()) return kFALSE;
339
340 Int_t imod = -1, iphi =-1, ieta=-1,iTower = -1, iIphi = -1, iIeta = -1;
341
342 if(!geom->GetCellIndex(absID,imod,iTower,iIphi,iIeta))
343 {
344 // cell absID does not exist
345 amp=0; time = 1.e9;
346 return kFALSE;
347 }
348
349 geom->GetCellPhiEtaIndexInSModule(imod,iTower,iIphi, iIeta,iphi,ieta);
350
351 // Do not include bad channels found in analysis,
352 if( IsBadChannelsRemovalSwitchedOn() && GetEMCALChannelStatus(imod, ieta, iphi))
353 {
354 return kFALSE;
355 }
356
357 //Recalibrate energy
358 amp = cells->GetCellAmplitude(absID);
359 if(!fCellsRecalibrated && IsRecalibrationOn())
360 amp *= GetEMCALChannelRecalibrationFactor(imod,ieta,iphi);
361
362
363 // Recalibrate time
364 time = cells->GetCellTime(absID);
365
366 RecalibrateCellTime(absID,bc,time);
367
368 return kTRUE;
369}
370
371//_____________________________________________________________________________
372Bool_t AliEMCALRecoUtils::CheckCellFiducialRegion(const AliEMCALGeometry* geom,
373 const AliVCluster* cluster,
374 AliVCaloCells* cells)
375{
376 // Given the list of AbsId of the cluster, get the maximum cell and
377 // check if there are fNCellsFromBorder from the calorimeter border
378
379 if(!cluster)
380 {
381 AliInfo("Cluster pointer null!");
382 return kFALSE;
383 }
384
385 //If the distance to the border is 0 or negative just exit accept all clusters
386 if(cells->GetType()==AliVCaloCells::kEMCALCell && fNCellsFromEMCALBorder <= 0 ) return kTRUE;
387
388 Int_t absIdMax = -1, iSM =-1, ieta = -1, iphi = -1;
389 Bool_t shared = kFALSE;
390 GetMaxEnergyCell(geom, cells, cluster, absIdMax, iSM, ieta, iphi, shared);
391
392 AliDebug(2,Form("Cluster Max AbsId %d, Cell Energy %2.2f, Cluster Energy %2.2f, Ncells from border %d, EMCAL eta=0 %d\n",
393 absIdMax, cells->GetCellAmplitude(absIdMax), cluster->E(), fNCellsFromEMCALBorder, fNoEMCALBorderAtEta0));
394
395 if(absIdMax==-1) return kFALSE;
396
397 //Check if the cell is close to the borders:
398 Bool_t okrow = kFALSE;
399 Bool_t okcol = kFALSE;
400
401 if(iSM < 0 || iphi < 0 || ieta < 0 )
402 {
403 AliFatal(Form("Negative value for super module: %d, or cell ieta: %d, or cell iphi: %d, check EMCAL geometry name\n",
404 iSM,ieta,iphi));
405 }
406
407 //Check rows/phi
408 if(iSM < 10)
409 {
410 if(iphi >= fNCellsFromEMCALBorder && iphi < 24-fNCellsFromEMCALBorder) okrow =kTRUE;
411 }
412 else if (iSM >=10 && ( ( geom->GetEMCGeometry()->GetGeoName()).Contains("12SMV1")))
413 {
414 if(iphi >= fNCellsFromEMCALBorder && iphi < 8-fNCellsFromEMCALBorder) okrow =kTRUE; //1/3 sm case
415 }
416 else
417 {
418 if(iphi >= fNCellsFromEMCALBorder && iphi < 12-fNCellsFromEMCALBorder) okrow =kTRUE; // half SM case
419 }
420
421 //Check columns/eta
422 if(!fNoEMCALBorderAtEta0)
423 {
424 if(ieta > fNCellsFromEMCALBorder && ieta < 48-fNCellsFromEMCALBorder) okcol =kTRUE;
425 }
426 else
427 {
428 if(iSM%2==0)
429 {
430 if(ieta >= fNCellsFromEMCALBorder) okcol = kTRUE;
431 }
432 else
433 {
434 if(ieta < 48-fNCellsFromEMCALBorder) okcol = kTRUE;
435 }
436 }//eta 0 not checked
437
438 AliDebug(2,Form("EMCAL Cluster in %d cells fiducial volume: ieta %d, iphi %d, SM %d: column? %d, row? %d\nq",
439 fNCellsFromEMCALBorder, ieta, iphi, iSM, okcol, okrow));
440
441 if (okcol && okrow)
442 {
443 //printf("Accept\n");
444 return kTRUE;
445 }
446 else
447 {
448 //printf("Reject\n");
449 AliDebug(2,Form("Reject cluster in border, max cell : ieta %d, iphi %d, SM %d\n",ieta, iphi, iSM));
450 return kFALSE;
451 }
452
453}
454
455
456//_______________________________________________________________________________
457Bool_t AliEMCALRecoUtils::ClusterContainsBadChannel(const AliEMCALGeometry* geom,
458 const UShort_t* cellList,
459 const Int_t nCells)
460{
461 // Check that in the cluster cells, there is no bad channel of those stored
462 // in fEMCALBadChannelMap or fPHOSBadChannelMap
463
464 if(!fRemoveBadChannels) return kFALSE;
465 if(!fEMCALBadChannelMap) return kFALSE;
466
467 Int_t icol = -1;
468 Int_t irow = -1;
469 Int_t imod = -1;
470 for(Int_t iCell = 0; iCell<nCells; iCell++)
471 {
472 //Get the column and row
473 Int_t iTower = -1, iIphi = -1, iIeta = -1;
474 geom->GetCellIndex(cellList[iCell],imod,iTower,iIphi,iIeta);
475 if(fEMCALBadChannelMap->GetEntries() <= imod) continue;
476 geom->GetCellPhiEtaIndexInSModule(imod,iTower,iIphi, iIeta,irow,icol);
477 if(GetEMCALChannelStatus(imod, icol, irow))
478 {
479 AliDebug(2,Form("Cluster with bad channel: SM %d, col %d, row %d\n",imod, icol, irow));
480 return kTRUE;
481 }
482
483 }// cell cluster loop
484
485 return kFALSE;
486}
487
488
489//___________________________________________________________________________
490Float_t AliEMCALRecoUtils::GetECross(const Int_t absID, const Double_t tcell,
491 AliVCaloCells* cells, const Int_t bc)
492{
493 //Calculate the energy in the cross around the energy given cell
494
495 AliEMCALGeometry * geom = AliEMCALGeometry::GetInstance();
496
497 Int_t imod = -1, iphi =-1, ieta=-1,iTower = -1, iIphi = -1, iIeta = -1;
498 geom->GetCellIndex(absID,imod,iTower,iIphi,iIeta);
499 geom->GetCellPhiEtaIndexInSModule(imod,iTower,iIphi, iIeta,iphi,ieta);
500
501 //Get close cells index, energy and time, not in corners
502
503 Int_t absID1 = -1;
504 Int_t absID2 = -1;
505
506 if( iphi < AliEMCALGeoParams::fgkEMCALRows-1) absID1 = geom-> GetAbsCellIdFromCellIndexes(imod, iphi+1, ieta);
507 if( iphi > 0 ) absID2 = geom-> GetAbsCellIdFromCellIndexes(imod, iphi-1, ieta);
508
509 // In case of cell in eta = 0 border, depending on SM shift the cross cell index
510
511 Int_t absID3 = -1;
512 Int_t absID4 = -1;
513
514 if ( ieta == AliEMCALGeoParams::fgkEMCALCols-1 && !(imod%2) )
515 {
516 absID3 = geom-> GetAbsCellIdFromCellIndexes(imod+1, iphi, 0);
517 absID4 = geom-> GetAbsCellIdFromCellIndexes(imod, iphi, ieta-1);
518 }
519 else if( ieta == 0 && imod%2 )
520 {
521 absID3 = geom-> GetAbsCellIdFromCellIndexes(imod, iphi, ieta+1);
522 absID4 = geom-> GetAbsCellIdFromCellIndexes(imod-1, iphi, AliEMCALGeoParams::fgkEMCALCols-1);
523 }
524 else
525 {
526 if( ieta < AliEMCALGeoParams::fgkEMCALCols-1 )
527 absID3 = geom-> GetAbsCellIdFromCellIndexes(imod, iphi, ieta+1);
528 if( ieta > 0 )
529 absID4 = geom-> GetAbsCellIdFromCellIndexes(imod, iphi, ieta-1);
530 }
531
532 //printf("IMOD %d, AbsId %d, a %d, b %d, c %d e %d \n",imod,absID,absID1,absID2,absID3,absID4);
533
534 Float_t ecell1 = 0, ecell2 = 0, ecell3 = 0, ecell4 = 0;
535 Double_t tcell1 = 0, tcell2 = 0, tcell3 = 0, tcell4 = 0;
536 Bool_t accept1 = 0, accept2 = 0, accept3 = 0, accept4 = 0;
537
538 accept1 = AcceptCalibrateCell(absID1,bc, ecell1,tcell1,cells);
539 accept2 = AcceptCalibrateCell(absID2,bc, ecell2,tcell2,cells);
540 accept3 = AcceptCalibrateCell(absID3,bc, ecell3,tcell3,cells);
541 accept4 = AcceptCalibrateCell(absID4,bc, ecell4,tcell4,cells);
542
543 /*
544 printf("Cell absID %d \n",absID);
545 printf("\t accept1 %d, accept2 %d, accept3 %d, accept4 %d\n",
546 accept1,accept2,accept3,accept4);
547 printf("\t id %d: id1 %d, id2 %d, id3 %d, id4 %d\n",
548 absID,absID1,absID2,absID3,absID4);
549 printf("\t e %f: e1 %f, e2 %f, e3 %f, e4 %f\n",
550 ecell,ecell1,ecell2,ecell3,ecell4);
551 printf("\t t %f: t1 %f, t2 %f, t3 %f, t4 %f;\n dt1 %f, dt2 %f, dt3 %f, dt4 %f\n",
552 tcell*1.e9,tcell1*1.e9,tcell2*1.e9,tcell3*1.e9,tcell4*1.e9,
553 TMath::Abs(tcell-tcell1)*1.e9, TMath::Abs(tcell-tcell2)*1.e9, TMath::Abs(tcell-tcell3)*1.e9, TMath::Abs(tcell-tcell4)*1.e9);
554 */
555
556 if(TMath::Abs(tcell-tcell1)*1.e9 > fExoticCellDiffTime) ecell1 = 0 ;
557 if(TMath::Abs(tcell-tcell2)*1.e9 > fExoticCellDiffTime) ecell2 = 0 ;
558 if(TMath::Abs(tcell-tcell3)*1.e9 > fExoticCellDiffTime) ecell3 = 0 ;
559 if(TMath::Abs(tcell-tcell4)*1.e9 > fExoticCellDiffTime) ecell4 = 0 ;
560
561 return ecell1+ecell2+ecell3+ecell4;
562
563}
564
565//_____________________________________________________________________________________________
566Bool_t AliEMCALRecoUtils::IsExoticCell(const Int_t absID, AliVCaloCells* cells, const Int_t bc)
567{
568 // Look to cell neighbourhood and reject if it seems exotic
569 // Do before recalibrating the cells
570
571 if(!fRejectExoticCells) return kFALSE;
572
573 Float_t ecell = 0;
574 Double_t tcell = 0;
575 Bool_t accept = AcceptCalibrateCell(absID, bc, ecell ,tcell ,cells);
576
577 if(!accept) return kTRUE; // reject this cell
578
579 if(ecell < fExoticCellMinAmplitude) return kFALSE; // do not reject low energy cells
580
581 Float_t eCross = GetECross(absID,tcell,cells,bc);
582
583 if(1-eCross/ecell > fExoticCellFraction)
584 {
585 AliDebug(2,Form("AliEMCALRecoUtils::IsExoticCell() - EXOTIC CELL id %d, eCell %f, eCross %f, 1-eCross/eCell %f\n",
586 absID,ecell,eCross,1-eCross/ecell));
587 return kTRUE;
588 }
589
590 return kFALSE;
591}
592
593//___________________________________________________________________
594Bool_t AliEMCALRecoUtils::IsExoticCluster(const AliVCluster *cluster,
595 AliVCaloCells *cells,
596 const Int_t bc)
597{
598 // Check if the cluster highest energy tower is exotic
599
600 if(!cluster)
601 {
602 AliInfo("Cluster pointer null!");
603 return kFALSE;
604 }
605
606 if(!fRejectExoticCluster) return kFALSE;
607
608 // Get highest energy tower
609 AliEMCALGeometry* geom = AliEMCALGeometry::GetInstance();
610 Int_t iSupMod = -1, absId = -1, ieta = -1, iphi = -1;
611 Bool_t shared = kFALSE;
612 GetMaxEnergyCell(geom, cells, cluster, absId, iSupMod, ieta, iphi, shared);
613
614 return IsExoticCell(absId,cells,bc);
615
616}
617
618//_______________________________________________________________________
619Float_t AliEMCALRecoUtils::SmearClusterEnergy(const AliVCluster* cluster)
620{
621 //In case of MC analysis, smear energy to match resolution/calibration in real data
622
623 if(!cluster)
624 {
625 AliInfo("Cluster pointer null!");
626 return 0;
627 }
628
629 Float_t energy = cluster->E() ;
630 Float_t rdmEnergy = energy ;
631 if(fSmearClusterEnergy)
632 {
633 rdmEnergy = fRandom.Gaus(energy,fSmearClusterParam[0] * TMath::Sqrt(energy) +
634 fSmearClusterParam[1] * energy +
635 fSmearClusterParam[2] );
636 AliDebug(2, Form("Energy: original %f, smeared %f\n", energy, rdmEnergy));
637 }
638
639 return rdmEnergy;
640}
641
642//____________________________________________________________________________
643Float_t AliEMCALRecoUtils::CorrectClusterEnergyLinearity(AliVCluster* cluster)
644{
645 // Correct cluster energy from non linearity functions
646
647 if(!cluster)
648 {
649 AliInfo("Cluster pointer null!");
650 return 0;
651 }
652
653 Float_t energy = cluster->E();
654
655 if(energy < 0.05)
656 {
657 // Clusters with less than 50 MeV or negative are not possible
658 AliInfo(Form("Too Low Cluster energy!, E = %f < 0.05 GeV",energy));
659 return 0;
660 }
661
662 switch (fNonLinearityFunction)
663 {
664
665 case kPi0MC:
666 {
667 //Non-Linearity correction (from MC with function ([0]*exp(-[1]/E))+(([2]/([3]*2.*TMath::Pi())*exp(-(E-[4])^2/(2.*[3]^2)))))
668 //fNonLinearityParams[0] = 1.014;
669 //fNonLinearityParams[1] =-0.03329;
670 //fNonLinearityParams[2] =-0.3853;
671 //fNonLinearityParams[3] = 0.5423;
672 //fNonLinearityParams[4] =-0.4335;
673 energy *= (fNonLinearityParams[0]*exp(-fNonLinearityParams[1]/energy))+
674 ((fNonLinearityParams[2]/(fNonLinearityParams[3]*2.*TMath::Pi())*
675 exp(-(energy-fNonLinearityParams[4])*(energy-fNonLinearityParams[4])/(2.*fNonLinearityParams[3]*fNonLinearityParams[3]))));
676 break;
677 }
678
679 case kPi0MCv2:
680 {
681 //Non-Linearity correction (from MC with function [0]/((x+[1])^[2]))+1;
682 //fNonLinearityParams[0] = 3.11111e-02;
683 //fNonLinearityParams[1] =-5.71666e-02;
684 //fNonLinearityParams[2] = 5.67995e-01;
685
686 energy *= fNonLinearityParams[0]/TMath::Power(energy+fNonLinearityParams[1],fNonLinearityParams[2])+1;
687 break;
688 }
689
690 case kPi0MCv3:
691 {
692 //Same as beam test corrected, change parameters
693 //fNonLinearityParams[0] = 9.81039e-01
694 //fNonLinearityParams[1] = 1.13508e-01;
695 //fNonLinearityParams[2] = 1.00173e+00;
696 //fNonLinearityParams[3] = 9.67998e-02;
697 //fNonLinearityParams[4] = 2.19381e+02;
698 //fNonLinearityParams[5] = 6.31604e+01;
699 //fNonLinearityParams[6] = 1;
700 energy *= fNonLinearityParams[6]/(fNonLinearityParams[0]*(1./(1.+fNonLinearityParams[1]*exp(-energy/fNonLinearityParams[2]))*1./(1.+fNonLinearityParams[3]*exp((energy-fNonLinearityParams[4])/fNonLinearityParams[5]))));
701
702 break;
703 }
704
705
706 case kPi0GammaGamma:
707 {
708 //Non-Linearity correction (from Olga Data with function p0+p1*exp(-p2*E))
709 //fNonLinearityParams[0] = 1.04;
710 //fNonLinearityParams[1] = -0.1445;
711 //fNonLinearityParams[2] = 1.046;
712 energy /= (fNonLinearityParams[0]+fNonLinearityParams[1]*exp(-fNonLinearityParams[2]*energy)); //Olga function
713 break;
714 }
715
716 case kPi0GammaConversion:
717 {
718 //Non-Linearity correction (Nicolas from Dimitri Data with function C*[1-a*exp(-b*E)])
719 //fNonLinearityParams[0] = 0.139393/0.1349766;
720 //fNonLinearityParams[1] = 0.0566186;
721 //fNonLinearityParams[2] = 0.982133;
722 energy /= fNonLinearityParams[0]*(1-fNonLinearityParams[1]*exp(-fNonLinearityParams[2]*energy));
723
724 break;
725 }
726
727 case kBeamTest:
728 {
729 //From beam test, Alexei's results, for different ZS thresholds
730 // th=30 MeV; th = 45 MeV; th = 75 MeV
731 //fNonLinearityParams[0] = 1.007; 1.003; 1.002
732 //fNonLinearityParams[1] = 0.894; 0.719; 0.797
733 //fNonLinearityParams[2] = 0.246; 0.334; 0.358
734 //Rescale the param[0] with 1.03
735 energy /= fNonLinearityParams[0]/(1+fNonLinearityParams[1]*exp(-energy/fNonLinearityParams[2]));
736
737 break;
738 }
739
740 case kBeamTestCorrected:
741 {
742 //From beam test, corrected for material between beam and EMCAL
743 //fNonLinearityParams[0] = 0.99078
744 //fNonLinearityParams[1] = 0.161499;
745 //fNonLinearityParams[2] = 0.655166;
746 //fNonLinearityParams[3] = 0.134101;
747 //fNonLinearityParams[4] = 163.282;
748 //fNonLinearityParams[5] = 23.6904;
749 //fNonLinearityParams[6] = 0.978;
750 energy *= fNonLinearityParams[6]/(fNonLinearityParams[0]*(1./(1.+fNonLinearityParams[1]*exp(-energy/fNonLinearityParams[2]))*1./(1.+fNonLinearityParams[3]*exp((energy-fNonLinearityParams[4])/fNonLinearityParams[5]))));
751
752 break;
753 }
754
755 case kNoCorrection:
756 AliDebug(2,"No correction on the energy\n");
757 break;
758
759 }
760
761 return energy;
762}
763
764//__________________________________________________
765void AliEMCALRecoUtils::InitNonLinearityParam()
766{
767 //Initialising Non Linearity Parameters
768
769 if(fNonLinearityFunction == kPi0MC)
770 {
771 fNonLinearityParams[0] = 1.014;
772 fNonLinearityParams[1] = -0.03329;
773 fNonLinearityParams[2] = -0.3853;
774 fNonLinearityParams[3] = 0.5423;
775 fNonLinearityParams[4] = -0.4335;
776 }
777
778 if(fNonLinearityFunction == kPi0MCv2)
779 {
780 fNonLinearityParams[0] = 3.11111e-02;
781 fNonLinearityParams[1] =-5.71666e-02;
782 fNonLinearityParams[2] = 5.67995e-01;
783 }
784
785 if(fNonLinearityFunction == kPi0MCv3)
786 {
787 fNonLinearityParams[0] = 9.81039e-01;
788 fNonLinearityParams[1] = 1.13508e-01;
789 fNonLinearityParams[2] = 1.00173e+00;
790 fNonLinearityParams[3] = 9.67998e-02;
791 fNonLinearityParams[4] = 2.19381e+02;
792 fNonLinearityParams[5] = 6.31604e+01;
793 fNonLinearityParams[6] = 1;
794 }
795
796 if(fNonLinearityFunction == kPi0GammaGamma)
797 {
798 fNonLinearityParams[0] = 1.04;
799 fNonLinearityParams[1] = -0.1445;
800 fNonLinearityParams[2] = 1.046;
801 }
802
803 if(fNonLinearityFunction == kPi0GammaConversion)
804 {
805 fNonLinearityParams[0] = 0.139393;
806 fNonLinearityParams[1] = 0.0566186;
807 fNonLinearityParams[2] = 0.982133;
808 }
809
810 if(fNonLinearityFunction == kBeamTest)
811 {
812 if(fNonLinearThreshold == 30)
813 {
814 fNonLinearityParams[0] = 1.007;
815 fNonLinearityParams[1] = 0.894;
816 fNonLinearityParams[2] = 0.246;
817 }
818 if(fNonLinearThreshold == 45)
819 {
820 fNonLinearityParams[0] = 1.003;
821 fNonLinearityParams[1] = 0.719;
822 fNonLinearityParams[2] = 0.334;
823 }
824 if(fNonLinearThreshold == 75)
825 {
826 fNonLinearityParams[0] = 1.002;
827 fNonLinearityParams[1] = 0.797;
828 fNonLinearityParams[2] = 0.358;
829 }
830 }
831
832 if(fNonLinearityFunction == kBeamTestCorrected)
833 {
834 fNonLinearityParams[0] = 0.99078;
835 fNonLinearityParams[1] = 0.161499;
836 fNonLinearityParams[2] = 0.655166;
837 fNonLinearityParams[3] = 0.134101;
838 fNonLinearityParams[4] = 163.282;
839 fNonLinearityParams[5] = 23.6904;
840 fNonLinearityParams[6] = 0.978;
841 }
842}
843
844//_________________________________________________________
845Float_t AliEMCALRecoUtils::GetDepth(const Float_t energy,
846 const Int_t iParticle,
847 const Int_t iSM) const
848{
849 //Calculate shower depth for a given cluster energy and particle type
850
851 // parameters
852 Float_t x0 = 1.31;
853 Float_t ecr = 8;
854 Float_t depth = 0;
855 Float_t arg = energy*1000/ ecr; //Multiply energy by 1000 to transform to MeV
856
857 switch ( iParticle )
858 {
859 case kPhoton:
860 if (arg < 1)
861 depth = 0;
862 else
863 depth = x0 * (TMath::Log(arg) + 0.5);
864 break;
865
866 case kElectron:
867 if (arg < 1)
868 depth = 0;
869 else
870 depth = x0 * (TMath::Log(arg) - 0.5);
871 break;
872
873 case kHadron:
874 // hadron
875 // boxes anc. here
876 if(gGeoManager)
877 {
878 gGeoManager->cd("ALIC_1/XEN1_1");
879 TGeoNode *geoXEn1 = gGeoManager->GetCurrentNode();
880 TGeoNodeMatrix *geoSM = dynamic_cast<TGeoNodeMatrix *>(geoXEn1->GetDaughter(iSM));
881 if(geoSM)
882 {
883 TGeoVolume *geoSMVol = geoSM->GetVolume();
884 TGeoShape *geoSMShape = geoSMVol->GetShape();
885 TGeoBBox *geoBox = dynamic_cast<TGeoBBox *>(geoSMShape);
886 if(geoBox) depth = 0.5 * geoBox->GetDX()*2 ;
887 else AliFatal("Null GEANT box");
888 }
889 else AliFatal("NULL GEANT node matrix");
890 }
891 else
892 {//electron
893 if (arg < 1)
894 depth = 0;
895 else
896 depth = x0 * (TMath::Log(arg) - 0.5);
897 }
898
899 break;
900
901 default://photon
902 if (arg < 1)
903 depth = 0;
904 else
905 depth = x0 * (TMath::Log(arg) + 0.5);
906 }
907
908 return depth;
909}
910
911//____________________________________________________________________
912void AliEMCALRecoUtils::GetMaxEnergyCell(const AliEMCALGeometry *geom,
913 AliVCaloCells* cells,
914 const AliVCluster* clu,
915 Int_t & absId,
916 Int_t & iSupMod,
917 Int_t & ieta,
918 Int_t & iphi,
919 Bool_t & shared)
920{
921 //For a given CaloCluster gets the absId of the cell
922 //with maximum energy deposit.
923
924 Double_t eMax = -1.;
925 Double_t eCell = -1.;
926 Float_t fraction = 1.;
927 Float_t recalFactor = 1.;
928 Int_t cellAbsId = -1 ;
929
930 Int_t iTower = -1;
931 Int_t iIphi = -1;
932 Int_t iIeta = -1;
933 Int_t iSupMod0= -1;
934
935 if(!clu)
936 {
937 AliInfo("Cluster pointer null!");
938 absId=-1; iSupMod0=-1, ieta = -1; iphi = -1; shared = -1;
939 return;
940 }
941
942 for (Int_t iDig=0; iDig< clu->GetNCells(); iDig++)
943 {
944 cellAbsId = clu->GetCellAbsId(iDig);
945 fraction = clu->GetCellAmplitudeFraction(iDig);
946 //printf("a Cell %d, id, %d, amp %f, fraction %f\n",iDig,cellAbsId,cells->GetCellAmplitude(cellAbsId),fraction);
947 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
948 geom->GetCellIndex(cellAbsId,iSupMod,iTower,iIphi,iIeta);
949 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi, iIeta,iphi,ieta);
950 if (iDig==0)
951 {
952 iSupMod0=iSupMod;
953 }
954 else if(iSupMod0!=iSupMod)
955 {
956 shared = kTRUE;
957 //printf("AliEMCALRecoUtils::GetMaxEnergyCell() - SHARED CLUSTER\n");
958 }
959 if(!fCellsRecalibrated && IsRecalibrationOn())
960 {
961 recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
962 }
963 eCell = cells->GetCellAmplitude(cellAbsId)*fraction*recalFactor;
964 //printf("b Cell %d, id, %d, amp %f, fraction %f\n",iDig,cellAbsId,eCell,fraction);
965 if(eCell > eMax)
966 {
967 eMax = eCell;
968 absId = cellAbsId;
969 //printf("\t new max: cell %d, e %f, ecell %f\n",maxId, eMax,eCell);
970 }
971 }// cell loop
972
973 //Get from the absid the supermodule, tower and eta/phi numbers
974 geom->GetCellIndex(absId,iSupMod,iTower,iIphi,iIeta);
975 //Gives SuperModule and Tower numbers
976 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,
977 iIphi, iIeta,iphi,ieta);
978 //printf("Max id %d, iSM %d, col %d, row %d\n",absId,iSupMod,ieta,iphi);
979 //printf("Max end---\n");
980}
981
982//______________________________________
983void AliEMCALRecoUtils::InitParameters()
984{
985 // Initialize data members with default values
986
987 fParticleType = kPhoton;
988 fPosAlgo = kUnchanged;
989 fW0 = 4.5;
990
991 fNonLinearityFunction = kNoCorrection;
992 fNonLinearThreshold = 30;
993
994 fExoticCellFraction = 0.97;
995 fExoticCellDiffTime = 1e6;
996 fExoticCellMinAmplitude = 0.5;
997
998 fAODFilterMask = 32;
999
1000 fCutEtaPhiSum = kTRUE;
1001 fCutEtaPhiSeparate = kFALSE;
1002
1003 fCutR = 0.05;
1004 fCutEta = 0.025;
1005 fCutPhi = 0.05;
1006
1007 fClusterWindow = 100;
1008 fMass = 0.139;
1009
1010 fStepSurface = 20.;
1011 fStepCluster = 5.;
1012 fTrackCutsType = kLooseCut;
1013
1014 fCutMinTrackPt = 0;
1015 fCutMinNClusterTPC = -1;
1016 fCutMinNClusterITS = -1;
1017
1018 fCutMaxChi2PerClusterTPC = 1e10;
1019 fCutMaxChi2PerClusterITS = 1e10;
1020
1021 fCutRequireTPCRefit = kFALSE;
1022 fCutRequireITSRefit = kFALSE;
1023 fCutAcceptKinkDaughters = kFALSE;
1024
1025 fCutMaxDCAToVertexXY = 1e10;
1026 fCutMaxDCAToVertexZ = 1e10;
1027 fCutDCAToVertex2D = kFALSE;
1028
1029 fCutRequireITSStandAlone = kFALSE; //MARCEL
1030 fCutRequireITSpureSA = kFALSE; //Marcel
1031
1032 //Misalignment matrices
1033 for(Int_t i = 0; i < 15 ; i++)
1034 {
1035 fMisalTransShift[i] = 0.;
1036 fMisalRotShift[i] = 0.;
1037 }
1038
1039 //Non linearity
1040 for(Int_t i = 0; i < 7 ; i++) fNonLinearityParams[i] = 0.;
1041
1042 //For kBeamTestCorrected case, but default is no correction
1043 fNonLinearityParams[0] = 0.99078;
1044 fNonLinearityParams[1] = 0.161499;
1045 fNonLinearityParams[2] = 0.655166;
1046 fNonLinearityParams[3] = 0.134101;
1047 fNonLinearityParams[4] = 163.282;
1048 fNonLinearityParams[5] = 23.6904;
1049 fNonLinearityParams[6] = 0.978;
1050
1051 //For kPi0GammaGamma case
1052 //fNonLinearityParams[0] = 0.1457/0.1349766/1.038;
1053 //fNonLinearityParams[1] = -0.02024/0.1349766/1.038;
1054 //fNonLinearityParams[2] = 1.046;
1055
1056 //Cluster energy smearing
1057 fSmearClusterEnergy = kFALSE;
1058 fSmearClusterParam[0] = 0.07; // * sqrt E term
1059 fSmearClusterParam[1] = 0.00; // * E term
1060 fSmearClusterParam[2] = 0.00; // constant
1061}
1062
1063//_____________________________________________________
1064void AliEMCALRecoUtils::InitEMCALRecalibrationFactors()
1065{
1066 //Init EMCAL recalibration factors
1067 AliDebug(2,"AliCalorimeterUtils::InitEMCALRecalibrationFactors()");
1068 //In order to avoid rewriting the same histograms
1069 Bool_t oldStatus = TH1::AddDirectoryStatus();
1070 TH1::AddDirectory(kFALSE);
1071
1072 fEMCALRecalibrationFactors = new TObjArray(12);
1073 for (int i = 0; i < 12; i++)
1074 fEMCALRecalibrationFactors->Add(new TH2F(Form("EMCALRecalFactors_SM%d",i),
1075 Form("EMCALRecalFactors_SM%d",i), 48, 0, 48, 24, 0, 24));
1076 //Init the histograms with 1
1077 for (Int_t sm = 0; sm < 12; sm++)
1078 {
1079 for (Int_t i = 0; i < 48; i++)
1080 {
1081 for (Int_t j = 0; j < 24; j++)
1082 {
1083 SetEMCALChannelRecalibrationFactor(sm,i,j,1.);
1084 }
1085 }
1086 }
1087
1088 fEMCALRecalibrationFactors->SetOwner(kTRUE);
1089 fEMCALRecalibrationFactors->Compress();
1090
1091 //In order to avoid rewriting the same histograms
1092 TH1::AddDirectory(oldStatus);
1093}
1094
1095//_________________________________________________________
1096void AliEMCALRecoUtils::InitEMCALTimeRecalibrationFactors()
1097{
1098 //Init EMCAL recalibration factors
1099 AliDebug(2,"AliCalorimeterUtils::InitEMCALRecalibrationFactors()");
1100 //In order to avoid rewriting the same histograms
1101 Bool_t oldStatus = TH1::AddDirectoryStatus();
1102 TH1::AddDirectory(kFALSE);
1103
1104 fEMCALTimeRecalibrationFactors = new TObjArray(4);
1105 for (int i = 0; i < 4; i++)
1106 fEMCALTimeRecalibrationFactors->Add(new TH1F(Form("hAllTimeAvBC%d",i),
1107 Form("hAllTimeAvBC%d",i),
1108 48*24*12,0.,48*24*12) );
1109 //Init the histograms with 1
1110 for (Int_t bc = 0; bc < 4; bc++)
1111 {
1112 for (Int_t i = 0; i < 48*24*12; i++)
1113 SetEMCALChannelTimeRecalibrationFactor(bc,i,0.);
1114 }
1115
1116 fEMCALTimeRecalibrationFactors->SetOwner(kTRUE);
1117 fEMCALTimeRecalibrationFactors->Compress();
1118
1119 //In order to avoid rewriting the same histograms
1120 TH1::AddDirectory(oldStatus);
1121}
1122
1123//____________________________________________________
1124void AliEMCALRecoUtils::InitEMCALBadChannelStatusMap()
1125{
1126 //Init EMCAL bad channels map
1127 AliDebug(2,"AliEMCALRecoUtils::InitEMCALBadChannelStatusMap()");
1128 //In order to avoid rewriting the same histograms
1129 Bool_t oldStatus = TH1::AddDirectoryStatus();
1130 TH1::AddDirectory(kFALSE);
1131
1132 fEMCALBadChannelMap = new TObjArray(12);
1133 //TH2F * hTemp = new TH2I("EMCALBadChannelMap","EMCAL SuperModule bad channel map", 48, 0, 48, 24, 0, 24);
1134 for (int i = 0; i < 12; i++)
1135 {
1136 fEMCALBadChannelMap->Add(new TH2I(Form("EMCALBadChannelMap_Mod%d",i),Form("EMCALBadChannelMap_Mod%d",i), 48, 0, 48, 24, 0, 24));
1137 }
1138
1139 fEMCALBadChannelMap->SetOwner(kTRUE);
1140 fEMCALBadChannelMap->Compress();
1141
1142 //In order to avoid rewriting the same histograms
1143 TH1::AddDirectory(oldStatus);
1144}
1145
1146//____________________________________________________________________________
1147void AliEMCALRecoUtils::RecalibrateClusterEnergy(const AliEMCALGeometry* geom,
1148 AliVCluster * cluster,
1149 AliVCaloCells * cells,
1150 const Int_t bc)
1151{
1152 // Recalibrate the cluster energy and Time, considering the recalibration map
1153 // and the energy of the cells and time that compose the cluster.
1154 // bc= bunch crossing number returned by esdevent->GetBunchCrossNumber();
1155
1156 if(!cluster)
1157 {
1158 AliInfo("Cluster pointer null!");
1159 return;
1160 }
1161
1162 //Get the cluster number of cells and list of absId, check what kind of cluster do we have.
1163 UShort_t * index = cluster->GetCellsAbsId() ;
1164 Double_t * fraction = cluster->GetCellsAmplitudeFraction() ;
1165 Int_t ncells = cluster->GetNCells();
1166
1167 //Initialize some used variables
1168 Float_t energy = 0;
1169 Int_t absId =-1;
1170 Int_t icol =-1, irow =-1, imod=1;
1171 Float_t factor = 1, frac = 0;
1172 Int_t absIdMax = -1;
1173 Float_t emax = 0;
1174
1175 //Loop on the cells, get the cell amplitude and recalibration factor, multiply and and to the new energy
1176 for(Int_t icell = 0; icell < ncells; icell++)
1177 {
1178 absId = index[icell];
1179 frac = fraction[icell];
1180 if(frac < 1e-5) frac = 1; //in case of EMCAL, this is set as 0 since unfolding is off
1181
1182 if(!fCellsRecalibrated && IsRecalibrationOn())
1183 {
1184 // Energy
1185 Int_t iTower = -1, iIphi = -1, iIeta = -1;
1186 geom->GetCellIndex(absId,imod,iTower,iIphi,iIeta);
1187 if(fEMCALRecalibrationFactors->GetEntries() <= imod) continue;
1188 geom->GetCellPhiEtaIndexInSModule(imod,iTower,iIphi, iIeta,irow,icol);
1189 factor = GetEMCALChannelRecalibrationFactor(imod,icol,irow);
1190
1191 AliDebug(2,Form("AliEMCALRecoUtils::RecalibrateClusterEnergy - recalibrate cell: module %d, col %d, row %d, cell fraction %f,recalibration factor %f, cell energy %f\n",
1192 imod,icol,irow,frac,factor,cells->GetCellAmplitude(absId)));
1193
1194 }
1195
1196 energy += cells->GetCellAmplitude(absId)*factor*frac;
1197
1198 if(emax < cells->GetCellAmplitude(absId)*factor*frac)
1199 {
1200 emax = cells->GetCellAmplitude(absId)*factor*frac;
1201 absIdMax = absId;
1202 }
1203 }
1204
1205 AliDebug(2,Form("AliEMCALRecoUtils::RecalibrateClusterEnergy - Energy before %f, after %f \n",cluster->E(),energy));
1206
1207 cluster->SetE(energy);
1208
1209 // Recalculate time of cluster
1210 Double_t timeorg = cluster->GetTOF();
1211
1212 Double_t time = cells->GetCellTime(absIdMax);
1213 if(!fCellsRecalibrated && IsTimeRecalibrationOn())
1214 RecalibrateCellTime(absIdMax,bc,time);
1215
1216 cluster->SetTOF(time);
1217
1218 AliDebug(2,Form("AliEMCALRecoUtils::RecalibrateClusterEnergy - Time before %f, after %f \n",timeorg,cluster->GetTOF()));
1219}
1220
1221//_____________________________________________________________
1222void AliEMCALRecoUtils::RecalibrateCells(AliVCaloCells * cells,
1223 const Int_t bc)
1224{
1225 // Recalibrate the cells time and energy, considering the recalibration map and the energy
1226 // of the cells that compose the cluster.
1227 // bc= bunch crossing number returned by esdevent->GetBunchCrossNumber();
1228
1229 if(!IsRecalibrationOn() && !IsTimeRecalibrationOn() && !IsBadChannelsRemovalSwitchedOn()) return;
1230
1231 if(!cells)
1232 {
1233 AliInfo("Cells pointer null!");
1234 return;
1235 }
1236
1237 Short_t absId =-1;
1238 Bool_t accept = kFALSE;
1239 Float_t ecell = 0;
1240 Double_t tcell = 0;
1241 Double_t ecellin = 0;
1242 Double_t tcellin = 0;
1243 Short_t mclabel = -1;
1244 Double_t efrac = 0;
1245
1246 Int_t nEMcell = cells->GetNumberOfCells() ;
1247 for (Int_t iCell = 0; iCell < nEMcell; iCell++)
1248 {
1249 cells->GetCell( iCell, absId, ecellin, tcellin, mclabel, efrac );
1250
1251 accept = AcceptCalibrateCell(absId, bc, ecell ,tcell ,cells);
1252 if(!accept)
1253 {
1254 ecell = 0;
1255 tcell = -1;
1256 }
1257
1258 //Set new values
1259 cells->SetCell(iCell,absId,ecell, tcell, mclabel, efrac);
1260 }
1261
1262 fCellsRecalibrated = kTRUE;
1263}
1264
1265//_______________________________________________________________________________________________________
1266void AliEMCALRecoUtils::RecalibrateCellTime(const Int_t absId, const Int_t bc, Double_t & celltime) const
1267{
1268 // Recalibrate time of cell with absID considering the recalibration map
1269 // bc= bunch crossing number returned by esdevent->GetBunchCrossNumber();
1270
1271 if(!fCellsRecalibrated && IsTimeRecalibrationOn() && bc >= 0)
1272 {
1273 celltime -= GetEMCALChannelTimeRecalibrationFactor(bc%4,absId)*1.e-9; ;
1274 }
1275}
1276
1277//______________________________________________________________________________
1278void AliEMCALRecoUtils::RecalculateClusterPosition(const AliEMCALGeometry *geom,
1279 AliVCaloCells* cells,
1280 AliVCluster* clu)
1281{
1282 //For a given CaloCluster recalculates the position for a given set of misalignment shifts and puts it again in the CaloCluster.
1283
1284 if(!clu)
1285 {
1286 AliInfo("Cluster pointer null!");
1287 return;
1288 }
1289
1290 if (fPosAlgo==kPosTowerGlobal) RecalculateClusterPositionFromTowerGlobal( geom, cells, clu);
1291 else if(fPosAlgo==kPosTowerIndex) RecalculateClusterPositionFromTowerIndex ( geom, cells, clu);
1292 else AliDebug(2,"Algorithm to recalculate position not selected, do nothing.");
1293}
1294
1295//_____________________________________________________________________________________________
1296void AliEMCALRecoUtils::RecalculateClusterPositionFromTowerGlobal(const AliEMCALGeometry *geom,
1297 AliVCaloCells* cells,
1298 AliVCluster* clu)
1299{
1300 // For a given CaloCluster recalculates the position for a given set of misalignment shifts and puts it again in the CaloCluster.
1301 // The algorithm is a copy of what is done in AliEMCALRecPoint
1302
1303 Double_t eCell = 0.;
1304 Float_t fraction = 1.;
1305 Float_t recalFactor = 1.;
1306
1307 Int_t absId = -1;
1308 Int_t iTower = -1, iIphi = -1, iIeta = -1;
1309 Int_t iSupModMax = -1, iSM=-1, iphi = -1, ieta = -1;
1310 Float_t weight = 0., totalWeight=0.;
1311 Float_t newPos[3] = {0,0,0};
1312 Double_t pLocal[3], pGlobal[3];
1313 Bool_t shared = kFALSE;
1314
1315 Float_t clEnergy = clu->E(); //Energy already recalibrated previously
1316 if (clEnergy <= 0)
1317 return;
1318 GetMaxEnergyCell(geom, cells, clu, absId, iSupModMax, ieta, iphi,shared);
1319 Double_t depth = GetDepth(clEnergy,fParticleType,iSupModMax) ;
1320
1321 //printf("** Cluster energy %f, ncells %d, depth %f\n",clEnergy,clu->GetNCells(),depth);
1322
1323 for (Int_t iDig=0; iDig< clu->GetNCells(); iDig++)
1324 {
1325 absId = clu->GetCellAbsId(iDig);
1326 fraction = clu->GetCellAmplitudeFraction(iDig);
1327 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
1328
1329 if (!fCellsRecalibrated)
1330 {
1331 geom->GetCellIndex(absId,iSM,iTower,iIphi,iIeta);
1332 geom->GetCellPhiEtaIndexInSModule(iSM,iTower,iIphi, iIeta,iphi,ieta);
1333
1334 if(IsRecalibrationOn())
1335 {
1336 recalFactor = GetEMCALChannelRecalibrationFactor(iSM,ieta,iphi);
1337 }
1338 }
1339
1340 eCell = cells->GetCellAmplitude(absId)*fraction*recalFactor;
1341
1342 weight = GetCellWeight(eCell,clEnergy);
1343 totalWeight += weight;
1344
1345 geom->RelPosCellInSModule(absId,depth,pLocal[0],pLocal[1],pLocal[2]);
1346 //printf("pLocal (%f,%f,%f), SM %d, absId %d\n",pLocal[0],pLocal[1],pLocal[2],iSupModMax,absId);
1347 geom->GetGlobal(pLocal,pGlobal,iSupModMax);
1348 //printf("pLocal (%f,%f,%f)\n",pGlobal[0],pGlobal[1],pGlobal[2]);
1349
1350 for(int i=0; i<3; i++ ) newPos[i] += (weight*pGlobal[i]);
1351 }// cell loop
1352
1353 if(totalWeight>0)
1354 {
1355 for(int i=0; i<3; i++ ) newPos[i] /= totalWeight;
1356 }
1357
1358 //Float_t pos[]={0,0,0};
1359 //clu->GetPosition(pos);
1360 //printf("OldPos : %2.3f,%2.3f,%2.3f\n",pos[0],pos[1],pos[2]);
1361 //printf("NewPos : %2.3f,%2.3f,%2.3f\n",newPos[0],newPos[1],newPos[2]);
1362
1363 if(iSupModMax > 1) //sector 1
1364 {
1365 newPos[0] +=fMisalTransShift[3];//-=3.093;
1366 newPos[1] +=fMisalTransShift[4];//+=6.82;
1367 newPos[2] +=fMisalTransShift[5];//+=1.635;
1368 //printf(" + : %2.3f,%2.3f,%2.3f\n",fMisalTransShift[3],fMisalTransShift[4],fMisalTransShift[5]);
1369 } else //sector 0
1370 {
1371 newPos[0] +=fMisalTransShift[0];//+=1.134;
1372 newPos[1] +=fMisalTransShift[1];//+=8.2;
1373 newPos[2] +=fMisalTransShift[2];//+=1.197;
1374 //printf(" + : %2.3f,%2.3f,%2.3f\n",fMisalTransShift[0],fMisalTransShift[1],fMisalTransShift[2]);
1375 }
1376 //printf("NewPos : %2.3f,%2.3f,%2.3f\n",newPos[0],newPos[1],newPos[2]);
1377
1378 clu->SetPosition(newPos);
1379}
1380
1381//____________________________________________________________________________________________
1382void AliEMCALRecoUtils::RecalculateClusterPositionFromTowerIndex(const AliEMCALGeometry *geom,
1383 AliVCaloCells* cells,
1384 AliVCluster* clu)
1385{
1386 // For a given CaloCluster recalculates the position for a given set of misalignment shifts and puts it again in the CaloCluster.
1387 // The algorithm works with the tower indeces, averages the indeces and from them it calculates the global position
1388
1389 Double_t eCell = 1.;
1390 Float_t fraction = 1.;
1391 Float_t recalFactor = 1.;
1392
1393 Int_t absId = -1;
1394 Int_t iTower = -1;
1395 Int_t iIphi = -1, iIeta = -1;
1396 Int_t iSupMod = -1, iSupModMax = -1;
1397 Int_t iphi = -1, ieta =-1;
1398 Bool_t shared = kFALSE;
1399
1400 Float_t clEnergy = clu->E(); //Energy already recalibrated previously.
1401 if (clEnergy <= 0)
1402 return;
1403 GetMaxEnergyCell(geom, cells, clu, absId, iSupModMax, ieta, iphi,shared);
1404 Float_t depth = GetDepth(clEnergy,fParticleType,iSupMod) ;
1405
1406 Float_t weight = 0., weightedCol = 0., weightedRow = 0., totalWeight=0.;
1407 Bool_t areInSameSM = kTRUE; //exclude clusters with cells in different SMs for now
1408 Int_t startingSM = -1;
1409
1410 for (Int_t iDig=0; iDig< clu->GetNCells(); iDig++)
1411 {
1412 absId = clu->GetCellAbsId(iDig);
1413 fraction = clu->GetCellAmplitudeFraction(iDig);
1414 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
1415
1416 if (iDig==0) startingSM = iSupMod;
1417 else if(iSupMod != startingSM) areInSameSM = kFALSE;
1418
1419 eCell = cells->GetCellAmplitude(absId);
1420
1421 geom->GetCellIndex(absId,iSupMod,iTower,iIphi,iIeta);
1422 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi, iIeta,iphi,ieta);
1423
1424 if (!fCellsRecalibrated)
1425 {
1426 if(IsRecalibrationOn())
1427 {
1428 recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
1429 }
1430 }
1431
1432 eCell = cells->GetCellAmplitude(absId)*fraction*recalFactor;
1433
1434 weight = GetCellWeight(eCell,clEnergy);
1435 if(weight < 0) weight = 0;
1436 totalWeight += weight;
1437 weightedCol += ieta*weight;
1438 weightedRow += iphi*weight;
1439
1440 //printf("Max cell? cell %d, amplitude org %f, fraction %f, recalibration %f, amplitude new %f \n",cellAbsId, cells->GetCellAmplitude(cellAbsId), fraction, recalFactor, eCell) ;
1441 }// cell loop
1442
1443 Float_t xyzNew[]={0.,0.,0.};
1444 if(areInSameSM == kTRUE)
1445 {
1446 //printf("In Same SM\n");
1447 weightedCol = weightedCol/totalWeight;
1448 weightedRow = weightedRow/totalWeight;
1449 geom->RecalculateTowerPosition(weightedRow, weightedCol, iSupModMax, depth, fMisalTransShift, fMisalRotShift, xyzNew);
1450 }
1451 else
1452 {
1453 //printf("In Different SM\n");
1454 geom->RecalculateTowerPosition(iphi, ieta, iSupModMax, depth, fMisalTransShift, fMisalRotShift, xyzNew);
1455 }
1456
1457 clu->SetPosition(xyzNew);
1458}
1459
1460//___________________________________________________________________________________________
1461void AliEMCALRecoUtils::RecalculateClusterDistanceToBadChannel(const AliEMCALGeometry * geom,
1462 AliVCaloCells* cells,
1463 AliVCluster * cluster)
1464{
1465 //re-evaluate distance to bad channel with updated bad map
1466
1467 if(!fRecalDistToBadChannels) return;
1468
1469 if(!cluster)
1470 {
1471 AliInfo("Cluster pointer null!");
1472 return;
1473 }
1474
1475 //Get channels map of the supermodule where the cluster is.
1476 Int_t absIdMax = -1, iSupMod =-1, icolM = -1, irowM = -1;
1477 Bool_t shared = kFALSE;
1478 GetMaxEnergyCell(geom, cells, cluster, absIdMax, iSupMod, icolM, irowM, shared);
1479 TH2D* hMap = (TH2D*)fEMCALBadChannelMap->At(iSupMod);
1480
1481 Int_t dRrow, dRcol;
1482 Float_t minDist = 10000.;
1483 Float_t dist = 0.;
1484
1485 //Loop on tower status map
1486 for(Int_t irow = 0; irow < AliEMCALGeoParams::fgkEMCALRows; irow++)
1487 {
1488 for(Int_t icol = 0; icol < AliEMCALGeoParams::fgkEMCALCols; icol++)
1489 {
1490 //Check if tower is bad.
1491 if(hMap->GetBinContent(icol,irow)==0) continue;
1492 //printf("AliEMCALRecoUtils::RecalculateDistanceToBadChannels() - \n \t Bad channel in SM %d, col %d, row %d, \n \t Cluster max in col %d, row %d\n",
1493 // iSupMod,icol, irow, icolM,irowM);
1494
1495 dRrow=TMath::Abs(irowM-irow);
1496 dRcol=TMath::Abs(icolM-icol);
1497 dist=TMath::Sqrt(dRrow*dRrow+dRcol*dRcol);
1498 if(dist < minDist)
1499 {
1500 //printf("MIN DISTANCE TO BAD %2.2f\n",dist);
1501 minDist = dist;
1502 }
1503 }
1504 }
1505
1506 //In case the cluster is shared by 2 SuperModules, need to check the map of the second Super Module
1507 if (shared)
1508 {
1509 TH2D* hMap2 = 0;
1510 Int_t iSupMod2 = -1;
1511
1512 //The only possible combinations are (0,1), (2,3) ... (8,9)
1513 if(iSupMod%2) iSupMod2 = iSupMod-1;
1514 else iSupMod2 = iSupMod+1;
1515 hMap2 = (TH2D*)fEMCALBadChannelMap->At(iSupMod2);
1516
1517 //Loop on tower status map of second super module
1518 for(Int_t irow = 0; irow < AliEMCALGeoParams::fgkEMCALRows; irow++)
1519 {
1520 for(Int_t icol = 0; icol < AliEMCALGeoParams::fgkEMCALCols; icol++)
1521 {
1522 //Check if tower is bad.
1523 if(hMap2->GetBinContent(icol,irow)==0) continue;
1524 //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",
1525 // iSupMod2,icol, irow,iSupMod,icolM,irowM);
1526 dRrow=TMath::Abs(irow-irowM);
1527
1528 if(iSupMod%2)
1529 {
1530 dRcol=TMath::Abs(icol-(AliEMCALGeoParams::fgkEMCALCols+icolM));
1531 } else
1532 {
1533 dRcol=TMath::Abs(AliEMCALGeoParams::fgkEMCALCols+icol-icolM);
1534 }
1535
1536 dist=TMath::Sqrt(dRrow*dRrow+dRcol*dRcol);
1537 if(dist < minDist) minDist = dist;
1538 }
1539 }
1540 }// shared cluster in 2 SuperModules
1541
1542 AliDebug(2,Form("Max cluster cell (SM,col,row)=(%d %d %d) - Distance to Bad Channel %2.2f",iSupMod, icolM, irowM, minDist));
1543 cluster->SetDistanceToBadChannel(minDist);
1544}
1545
1546//__________________________________________________________________
1547void AliEMCALRecoUtils::RecalculateClusterPID(AliVCluster * cluster)
1548{
1549 //re-evaluate identification parameters with bayesian
1550
1551 if(!cluster)
1552 {
1553 AliInfo("Cluster pointer null!");
1554 return;
1555 }
1556
1557 if ( cluster->GetM02() != 0)
1558 fPIDUtils->ComputePID(cluster->E(),cluster->GetM02());
1559
1560 Float_t pidlist[AliPID::kSPECIESCN+1];
1561 for(Int_t i = 0; i < AliPID::kSPECIESCN+1; i++) pidlist[i] = fPIDUtils->GetPIDFinal(i);
1562
1563 cluster->SetPID(pidlist);
1564}
1565
1566//___________________________________________________________________________________________________________________
1567void AliEMCALRecoUtils::RecalculateClusterShowerShapeParameters(const AliEMCALGeometry * geom,
1568 AliVCaloCells* cells,
1569 AliVCluster * cluster,
1570 Float_t & l0, Float_t & l1,
1571 Float_t & disp, Float_t & dEta, Float_t & dPhi,
1572 Float_t & sEta, Float_t & sPhi, Float_t & sEtaPhi)
1573{
1574 // Calculates new center of gravity in the local EMCAL-module coordinates
1575 // and tranfers into global ALICE coordinates
1576 // Calculates Dispersion and main axis
1577
1578 if(!cluster)
1579 {
1580 AliInfo("Cluster pointer null!");
1581 return;
1582 }
1583
1584 Double_t eCell = 0.;
1585 Float_t fraction = 1.;
1586 Float_t recalFactor = 1.;
1587
1588 Int_t iSupMod = -1;
1589 Int_t iTower = -1;
1590 Int_t iIphi = -1;
1591 Int_t iIeta = -1;
1592 Int_t iphi = -1;
1593 Int_t ieta = -1;
1594 Double_t etai = -1.;
1595 Double_t phii = -1.;
1596
1597 Int_t nstat = 0 ;
1598 Float_t wtot = 0.;
1599 Double_t w = 0.;
1600 Double_t etaMean = 0.;
1601 Double_t phiMean = 0.;
1602
1603 //Loop on cells
1604 for(Int_t iDigit=0; iDigit < cluster->GetNCells(); iDigit++)
1605 {
1606 //Get from the absid the supermodule, tower and eta/phi numbers
1607 geom->GetCellIndex(cluster->GetCellAbsId(iDigit),iSupMod,iTower,iIphi,iIeta);
1608 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi,iIeta, iphi,ieta);
1609
1610 //Get the cell energy, if recalibration is on, apply factors
1611 fraction = cluster->GetCellAmplitudeFraction(iDigit);
1612 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
1613
1614 if (!fCellsRecalibrated)
1615 {
1616 if(IsRecalibrationOn())
1617 {
1618 recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
1619 }
1620 }
1621
1622 eCell = cells->GetCellAmplitude(cluster->GetCellAbsId(iDigit))*fraction*recalFactor;
1623
1624 if(cluster->E() > 0 && eCell > 0)
1625 {
1626 w = GetCellWeight(eCell,cluster->E());
1627
1628 etai=(Double_t)ieta;
1629 phii=(Double_t)iphi;
1630
1631 if(w > 0.0)
1632 {
1633 wtot += w ;
1634 nstat++;
1635 //Shower shape
1636 sEta += w * etai * etai ;
1637 etaMean += w * etai ;
1638 sPhi += w * phii * phii ;
1639 phiMean += w * phii ;
1640 sEtaPhi += w * etai * phii ;
1641 }
1642 }
1643 else
1644 AliError(Form("Wrong energy %f and/or amplitude %f\n", eCell, cluster->E()));
1645 }//cell loop
1646
1647 //Normalize to the weight
1648 if (wtot > 0)
1649 {
1650 etaMean /= wtot ;
1651 phiMean /= wtot ;
1652 }
1653 else
1654 AliError(Form("Wrong weight %f\n", wtot));
1655
1656 //Calculate dispersion
1657 for(Int_t iDigit=0; iDigit < cluster->GetNCells(); iDigit++)
1658 {
1659 //Get from the absid the supermodule, tower and eta/phi numbers
1660 geom->GetCellIndex(cluster->GetCellAbsId(iDigit),iSupMod,iTower,iIphi,iIeta);
1661 geom->GetCellPhiEtaIndexInSModule(iSupMod,iTower,iIphi,iIeta, iphi,ieta);
1662
1663 //Get the cell energy, if recalibration is on, apply factors
1664 fraction = cluster->GetCellAmplitudeFraction(iDigit);
1665 if(fraction < 1e-4) fraction = 1.; // in case unfolding is off
1666 if (IsRecalibrationOn())
1667 {
1668 recalFactor = GetEMCALChannelRecalibrationFactor(iSupMod,ieta,iphi);
1669 }
1670 eCell = cells->GetCellAmplitude(cluster->GetCellAbsId(iDigit))*fraction*recalFactor;
1671
1672 if(cluster->E() > 0 && eCell > 0)
1673 {
1674 w = GetCellWeight(eCell,cluster->E());
1675
1676 etai=(Double_t)ieta;
1677 phii=(Double_t)iphi;
1678 if(w > 0.0)
1679 {
1680 disp += w *((etai-etaMean)*(etai-etaMean)+(phii-phiMean)*(phii-phiMean));
1681 dEta += w * (etai-etaMean)*(etai-etaMean) ;
1682 dPhi += w * (phii-phiMean)*(phii-phiMean) ;
1683 }
1684 }
1685 else
1686 AliError(Form("Wrong energy %f and/or amplitude %f\n", eCell, cluster->E()));
1687 }// cell loop
1688
1689 //Normalize to the weigth and set shower shape parameters
1690 if (wtot > 0 && nstat > 1)
1691 {
1692 disp /= wtot ;
1693 dEta /= wtot ;
1694 dPhi /= wtot ;
1695 sEta /= wtot ;
1696 sPhi /= wtot ;
1697 sEtaPhi /= wtot ;
1698
1699 sEta -= etaMean * etaMean ;
1700 sPhi -= phiMean * phiMean ;
1701 sEtaPhi -= etaMean * phiMean ;
1702
1703 l0 = (0.5 * (sEta + sPhi) + TMath::Sqrt( 0.25 * (sEta - sPhi) * (sEta - sPhi) + sEtaPhi * sEtaPhi ));
1704 l1 = (0.5 * (sEta + sPhi) - TMath::Sqrt( 0.25 * (sEta - sPhi) * (sEta - sPhi) + sEtaPhi * sEtaPhi ));
1705 }
1706 else
1707 {
1708 l0 = 0. ;
1709 l1 = 0. ;
1710 dEta = 0. ; dPhi = 0. ; disp = 0. ;
1711 sEta = 0. ; sPhi = 0. ; sEtaPhi = 0. ;
1712 }
1713
1714}
1715
1716//____________________________________________________________________________________________
1717void AliEMCALRecoUtils::RecalculateClusterShowerShapeParameters(const AliEMCALGeometry * geom,
1718 AliVCaloCells* cells,
1719 AliVCluster * cluster)
1720{
1721 // Calculates new center of gravity in the local EMCAL-module coordinates
1722 // and tranfers into global ALICE coordinates
1723 // Calculates Dispersion and main axis and puts them into the cluster
1724
1725 Float_t l0 = 0., l1 = 0.;
1726 Float_t disp = 0., dEta = 0., dPhi = 0.;
1727 Float_t sEta = 0., sPhi = 0., sEtaPhi = 0.;
1728
1729 AliEMCALRecoUtils::RecalculateClusterShowerShapeParameters(geom,cells,cluster,l0,l1,disp,
1730 dEta, dPhi, sEta, sPhi, sEtaPhi);
1731
1732 cluster->SetM02(l0);
1733 cluster->SetM20(l1);
1734 if(disp > 0. ) cluster->SetDispersion(TMath::Sqrt(disp)) ;
1735
1736}
1737
1738//____________________________________________________________________________
1739void AliEMCALRecoUtils::FindMatches(AliVEvent *event,
1740 TObjArray * clusterArr,
1741 const AliEMCALGeometry *geom)
1742{
1743 //This function should be called before the cluster loop
1744 //Before call this function, please recalculate the cluster positions
1745 //Given the input event, loop over all the tracks, select the closest cluster as matched with fCutR
1746 //Store matched cluster indexes and residuals
1747
1748 fMatchedTrackIndex ->Reset();
1749 fMatchedClusterIndex->Reset();
1750 fResidualPhi->Reset();
1751 fResidualEta->Reset();
1752
1753 fMatchedTrackIndex ->Set(1000);
1754 fMatchedClusterIndex->Set(1000);
1755 fResidualPhi->Set(1000);
1756 fResidualEta->Set(1000);
1757
1758 AliESDEvent* esdevent = dynamic_cast<AliESDEvent*> (event);
1759 AliAODEvent* aodevent = dynamic_cast<AliAODEvent*> (event);
1760
1761 // init the magnetic field if not already on
1762 if(!TGeoGlobalMagField::Instance()->GetField())
1763 {
1764 AliInfo("Init the magnetic field\n");
1765 if (esdevent)
1766 {
1767 esdevent->InitMagneticField();
1768 }
1769 else if(aodevent)
1770 {
1771 Double_t curSol = 30000*aodevent->GetMagneticField()/5.00668;
1772 Double_t curDip = 6000 *aodevent->GetMuonMagFieldScale();
1773 AliMagF *field = AliMagF::CreateFieldMap(curSol,curDip);
1774 TGeoGlobalMagField::Instance()->SetField(field);
1775 }
1776 else
1777 {
1778 AliInfo("Mag Field not initialized, null esd/aod evetn pointers");
1779 }
1780
1781 } // Init mag field
1782
1783 if (esdevent) {
1784 UInt_t mask1 = esdevent->GetESDRun()->GetDetectorsInDAQ();
1785 UInt_t mask2 = esdevent->GetESDRun()->GetDetectorsInReco();
1786 Bool_t desc1 = (mask1 >> 3) & 0x1;
1787 Bool_t desc2 = (mask2 >> 3) & 0x1;
1788 if (desc1==0 || desc2==0) {
1789 AliError(Form("TPC not in DAQ/RECO: %u (%u)/%u (%u)",
1790 mask1, esdevent->GetESDRun()->GetDetectorsInReco(),
1791 mask2, esdevent->GetESDRun()->GetDetectorsInDAQ()));
1792 fITSTrackSA=kTRUE;
1793 }
1794 }
1795
1796 TObjArray *clusterArray = 0x0;
1797 if(!clusterArr)
1798 {
1799 clusterArray = new TObjArray(event->GetNumberOfCaloClusters());
1800 for(Int_t icl=0; icl<event->GetNumberOfCaloClusters(); icl++)
1801 {
1802 AliVCluster *cluster = (AliVCluster*) event->GetCaloCluster(icl);
1803 if(geom && !IsGoodCluster(cluster,geom,(AliVCaloCells*)event->GetEMCALCells())) continue;
1804 clusterArray->AddAt(cluster,icl);
1805 }
1806 }
1807
1808 Int_t matched=0;
1809 Double_t cv[21];
1810 for (Int_t i=0; i<21;i++) cv[i]=0;
1811 for(Int_t itr=0; itr<event->GetNumberOfTracks(); itr++)
1812 {
1813 AliExternalTrackParam *trackParam = 0;
1814
1815 //If the input event is ESD, the starting point for extrapolation is TPCOut, if available, or TPCInner
1816 AliESDtrack *esdTrack = 0;
1817 AliAODTrack *aodTrack = 0;
1818 if(esdevent)
1819 {
1820 esdTrack = esdevent->GetTrack(itr);
1821 if(!esdTrack) continue;
1822 if(!IsAccepted(esdTrack)) continue;
1823 if(esdTrack->Pt()<fCutMinTrackPt) continue;
1824 Double_t phi = esdTrack->Phi()*TMath::RadToDeg();
1825 if(TMath::Abs(esdTrack->Eta())>0.8 || phi <= 20 || phi >= 240 ) continue;
1826 if(!fITSTrackSA)
1827 trackParam = const_cast<AliExternalTrackParam*>(esdTrack->GetInnerParam()); // if TPC Available
1828 else
1829 trackParam = new AliExternalTrackParam(*esdTrack); // If ITS Track Standing alone
1830 }
1831
1832 //If the input event is AOD, the starting point for extrapolation is at vertex
1833 //AOD tracks are selected according to its filterbit.
1834 else if(aodevent)
1835 {
1836 aodTrack = aodevent->GetTrack(itr);
1837 if(!aodTrack) continue;
1838 if(!aodTrack->TestFilterMask(fAODFilterMask)) continue; //Select AOD tracks that fulfill GetStandardITSTPCTrackCuts2010()
1839 if(aodTrack->Pt()<fCutMinTrackPt) continue;
1840 Double_t phi = aodTrack->Phi()*TMath::RadToDeg();
1841 if(TMath::Abs(aodTrack->Eta())>0.8 || phi <= 20 || phi >= 240 ) continue;
1842 Double_t pos[3],mom[3];
1843 aodTrack->GetXYZ(pos);
1844 aodTrack->GetPxPyPz(mom);
1845 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()));
1846 trackParam= new AliExternalTrackParam(pos,mom,cv,aodTrack->Charge());
1847 }
1848
1849 //Return if the input data is not "AOD" or "ESD"
1850 else
1851 {
1852 printf("Wrong input data type! Should be \"AOD\" or \"ESD\"\n");
1853 if(clusterArray)
1854 {
1855 clusterArray->Clear();
1856 delete clusterArray;
1857 }
1858 return;
1859 }
1860
1861 if(!trackParam) continue;
1862
1863 //Extrapolate the track to EMCal surface
1864 AliExternalTrackParam emcalParam(*trackParam);
1865 Float_t eta, phi;
1866 if(!ExtrapolateTrackToEMCalSurface(&emcalParam, 430., fMass, fStepSurface, eta, phi))
1867 {
1868 if(aodevent && trackParam) delete trackParam;
1869 continue;
1870 }
1871
1872// if(esdevent)
1873// {
1874// esdTrack->SetOuterParam(&emcalParam,AliExternalTrackParam::kMultSec);
1875// }
1876
1877 if(TMath::Abs(eta)>0.75 || (phi) < 70*TMath::DegToRad() || (phi) > 190*TMath::DegToRad())
1878 {
1879 if(aodevent && trackParam) delete trackParam;
1880 continue;
1881 }
1882
1883
1884 //Find matched clusters
1885 Int_t index = -1;
1886 Float_t dEta = -999, dPhi = -999;
1887 if(!clusterArr)
1888 {
1889 index = FindMatchedClusterInClusterArr(&emcalParam, &emcalParam, clusterArray, dEta, dPhi);
1890 }
1891 else
1892 {
1893 index = FindMatchedClusterInClusterArr(&emcalParam, &emcalParam, clusterArr, dEta, dPhi);
1894 }
1895
1896 if(index>-1)
1897 {
1898 fMatchedTrackIndex ->AddAt(itr,matched);
1899 fMatchedClusterIndex ->AddAt(index,matched);
1900 fResidualEta ->AddAt(dEta,matched);
1901 fResidualPhi ->AddAt(dPhi,matched);
1902 matched++;
1903 }
1904 if(aodevent && trackParam) delete trackParam;
1905 }//track loop
1906
1907 if(clusterArray)
1908 {
1909 clusterArray->Clear();
1910 delete clusterArray;
1911 }
1912
1913 AliDebug(2,Form("Number of matched pairs = %d !\n",matched));
1914
1915 fMatchedTrackIndex ->Set(matched);
1916 fMatchedClusterIndex ->Set(matched);
1917 fResidualPhi ->Set(matched);
1918 fResidualEta ->Set(matched);
1919}
1920
1921//________________________________________________________________________________
1922Int_t AliEMCALRecoUtils::FindMatchedClusterInEvent(const AliESDtrack *track,
1923 const AliVEvent *event,
1924 const AliEMCALGeometry *geom,
1925 Float_t &dEta, Float_t &dPhi)
1926{
1927 //
1928 // This function returns the index of matched cluster to input track
1929 // Returns -1 if no match is found
1930 Int_t index = -1;
1931 Double_t phiV = track->Phi()*TMath::RadToDeg();
1932 if(TMath::Abs(track->Eta())>0.8 || phiV <= 20 || phiV >= 240 ) return index;
1933 AliExternalTrackParam *trackParam = 0;
1934 if(!fITSTrackSA)
1935 trackParam = const_cast<AliExternalTrackParam*>(track->GetInnerParam()); // If TPC
1936 else
1937 trackParam = new AliExternalTrackParam(*track);
1938
1939 if(!trackParam) return index;
1940 AliExternalTrackParam emcalParam(*trackParam);
1941 Float_t eta, phi;
1942 if(!ExtrapolateTrackToEMCalSurface(&emcalParam, 430., fMass, fStepSurface, eta, phi)) return index;
1943 if(TMath::Abs(eta)>0.75 || (phi) < 70*TMath::DegToRad() || (phi) > 190*TMath::DegToRad()) return index;
1944
1945 TObjArray *clusterArr = new TObjArray(event->GetNumberOfCaloClusters());
1946
1947 for(Int_t icl=0; icl<event->GetNumberOfCaloClusters(); icl++)
1948 {
1949 AliVCluster *cluster = (AliVCluster*) event->GetCaloCluster(icl);
1950 if(geom && !IsGoodCluster(cluster,geom,(AliVCaloCells*)event->GetEMCALCells())) continue;
1951 clusterArr->AddAt(cluster,icl);
1952 }
1953
1954 index = FindMatchedClusterInClusterArr(&emcalParam, &emcalParam, clusterArr, dEta, dPhi);
1955 clusterArr->Clear();
1956 delete clusterArr;
1957
1958 return index;
1959}
1960
1961//_______________________________________________________________________________________________
1962Int_t AliEMCALRecoUtils::FindMatchedClusterInClusterArr(const AliExternalTrackParam *emcalParam,
1963 AliExternalTrackParam *trkParam,
1964 const TObjArray * clusterArr,
1965 Float_t &dEta, Float_t &dPhi)
1966{
1967 // Find matched cluster in array
1968
1969 dEta=-999, dPhi=-999;
1970 Float_t dRMax = fCutR, dEtaMax=fCutEta, dPhiMax=fCutPhi;
1971 Int_t index = -1;
1972 Float_t tmpEta=-999, tmpPhi=-999;
1973
1974 Double_t exPos[3] = {0.,0.,0.};
1975 if(!emcalParam->GetXYZ(exPos)) return index;
1976
1977 Float_t clsPos[3] = {0.,0.,0.};
1978 for(Int_t icl=0; icl<clusterArr->GetEntriesFast(); icl++)
1979 {
1980 AliVCluster *cluster = dynamic_cast<AliVCluster*> (clusterArr->At(icl)) ;
1981 if(!cluster || !cluster->IsEMCAL()) continue;
1982 cluster->GetPosition(clsPos);
1983 Double_t dR = TMath::Sqrt(TMath::Power(exPos[0]-clsPos[0],2)+TMath::Power(exPos[1]-clsPos[1],2)+TMath::Power(exPos[2]-clsPos[2],2));
1984 if(dR > fClusterWindow) continue;
1985
1986 AliExternalTrackParam trkPamTmp (*trkParam);//Retrieve the starting point every time before the extrapolation
1987 if(!ExtrapolateTrackToCluster(&trkPamTmp, cluster, fMass, fStepCluster, tmpEta, tmpPhi)) continue;
1988 if(fCutEtaPhiSum)
1989 {
1990 Float_t tmpR=TMath::Sqrt(tmpEta*tmpEta + tmpPhi*tmpPhi);
1991 if(tmpR<dRMax)
1992 {
1993 dRMax=tmpR;
1994 dEtaMax=tmpEta;
1995 dPhiMax=tmpPhi;
1996 index=icl;
1997 }
1998 }
1999 else if(fCutEtaPhiSeparate)
2000 {
2001 if(TMath::Abs(tmpEta)<TMath::Abs(dEtaMax) && TMath::Abs(tmpPhi)<TMath::Abs(dPhiMax))
2002 {
2003 dEtaMax = tmpEta;
2004 dPhiMax = tmpPhi;
2005 index=icl;
2006 }
2007 }
2008 else
2009 {
2010 printf("Error: please specify your cut criteria\n");
2011 printf("To cut on sqrt(dEta^2+dPhi^2), use: SwitchOnCutEtaPhiSum()\n");
2012 printf("To cut on dEta and dPhi separately, use: SwitchOnCutEtaPhiSeparate()\n");
2013 return index;
2014 }
2015 }
2016
2017 dEta=dEtaMax;
2018 dPhi=dPhiMax;
2019
2020 return index;
2021}
2022
2023//------------------------------------------------------------------------------------
2024Bool_t AliEMCALRecoUtils::ExtrapolateTrackToEMCalSurface(AliExternalTrackParam *trkParam,
2025 const Double_t emcalR,
2026 const Double_t mass,
2027 const Double_t step,
2028 Float_t &eta,
2029 Float_t &phi)
2030{
2031 //Extrapolate track to EMCAL surface
2032
2033 eta = -999, phi = -999;
2034 if(!trkParam) return kFALSE;
2035 if(!AliTrackerBase::PropagateTrackToBxByBz(trkParam, emcalR, mass, step, kTRUE, 0.8, -1)) return kFALSE;
2036 Double_t trkPos[3] = {0.,0.,0.};
2037 if(!trkParam->GetXYZ(trkPos)) return kFALSE;
2038 TVector3 trkPosVec(trkPos[0],trkPos[1],trkPos[2]);
2039 eta = trkPosVec.Eta();
2040 phi = trkPosVec.Phi();
2041 if(phi<0)
2042 phi += 2*TMath::Pi();
2043
2044 return kTRUE;
2045}
2046
2047//-----------------------------------------------------------------------------------
2048Bool_t AliEMCALRecoUtils::ExtrapolateTrackToPosition(AliExternalTrackParam *trkParam,
2049 const Float_t *clsPos,
2050 Double_t mass,
2051 Double_t step,
2052 Float_t &tmpEta,
2053 Float_t &tmpPhi)
2054{
2055 //
2056 //Return the residual by extrapolating a track param to a global position
2057 //
2058 tmpEta = -999;
2059 tmpPhi = -999;
2060 if(!trkParam) return kFALSE;
2061 Double_t trkPos[3] = {0.,0.,0.};
2062 TVector3 vec(clsPos[0],clsPos[1],clsPos[2]);
2063 Double_t alpha = ((int)(vec.Phi()*TMath::RadToDeg()/20)+0.5)*20*TMath::DegToRad();
2064 vec.RotateZ(-alpha); //Rotate the cluster to the local extrapolation coordinate system
2065 if(!AliTrackerBase::PropagateTrackToBxByBz(trkParam, vec.X(), mass, step,kTRUE, 0.8, -1)) return kFALSE;
2066 if(!trkParam->GetXYZ(trkPos)) return kFALSE; //Get the extrapolated global position
2067
2068 TVector3 clsPosVec(clsPos[0],clsPos[1],clsPos[2]);
2069 TVector3 trkPosVec(trkPos[0],trkPos[1],trkPos[2]);
2070
2071 // track cluster matching
2072 tmpPhi = clsPosVec.DeltaPhi(trkPosVec); // tmpPhi is between -pi and pi
2073 tmpEta = clsPosVec.Eta()-trkPosVec.Eta();
2074
2075 return kTRUE;
2076}
2077
2078//----------------------------------------------------------------------------------
2079Bool_t AliEMCALRecoUtils::ExtrapolateTrackToCluster(AliExternalTrackParam *trkParam,
2080 const AliVCluster *cluster,
2081 const Double_t mass,
2082 const Double_t step,
2083 Float_t &tmpEta,
2084 Float_t &tmpPhi)
2085{
2086 //
2087 //Return the residual by extrapolating a track param to a cluster
2088 //
2089 tmpEta = -999;
2090 tmpPhi = -999;
2091 if(!cluster || !trkParam) return kFALSE;
2092
2093 Float_t clsPos[3] = {0.,0.,0.};
2094 cluster->GetPosition(clsPos);
2095
2096 return ExtrapolateTrackToPosition(trkParam, clsPos, mass, step, tmpEta, tmpPhi);
2097}
2098
2099//---------------------------------------------------------------------------------
2100Bool_t AliEMCALRecoUtils::ExtrapolateTrackToCluster(AliExternalTrackParam *trkParam,
2101 const AliVCluster *cluster,
2102 Float_t &tmpEta,
2103 Float_t &tmpPhi)
2104{
2105 //
2106 //Return the residual by extrapolating a track param to a clusterfStepCluster
2107 //
2108
2109 return ExtrapolateTrackToCluster(trkParam, cluster, fMass, fStepCluster, tmpEta, tmpPhi);
2110}
2111
2112//_______________________________________________________________________
2113void AliEMCALRecoUtils::GetMatchedResiduals(const Int_t clsIndex,
2114 Float_t &dEta, Float_t &dPhi)
2115{
2116 //Given a cluster index as in AliESDEvent::GetCaloCluster(clsIndex)
2117 //Get the residuals dEta and dPhi for this cluster to the closest track
2118 //Works with ESDs and AODs
2119
2120 if( FindMatchedPosForCluster(clsIndex) >= 999 )
2121 {
2122 AliDebug(2,"No matched tracks found!\n");
2123 dEta=999.;
2124 dPhi=999.;
2125 return;
2126 }
2127 dEta = fResidualEta->At(FindMatchedPosForCluster(clsIndex));
2128 dPhi = fResidualPhi->At(FindMatchedPosForCluster(clsIndex));
2129}
2130
2131//______________________________________________________________________________________________
2132void AliEMCALRecoUtils::GetMatchedClusterResiduals(Int_t trkIndex, Float_t &dEta, Float_t &dPhi)
2133{
2134 //Given a track index as in AliESDEvent::GetTrack(trkIndex)
2135 //Get the residuals dEta and dPhi for this track to the closest cluster
2136 //Works with ESDs and AODs
2137
2138 if( FindMatchedPosForTrack(trkIndex) >= 999 )
2139 {
2140 AliDebug(2,"No matched cluster found!\n");
2141 dEta=999.;
2142 dPhi=999.;
2143 return;
2144 }
2145 dEta = fResidualEta->At(FindMatchedPosForTrack(trkIndex));
2146 dPhi = fResidualPhi->At(FindMatchedPosForTrack(trkIndex));
2147}
2148
2149//__________________________________________________________
2150Int_t AliEMCALRecoUtils::GetMatchedTrackIndex(Int_t clsIndex)
2151{
2152 //Given a cluster index as in AliESDEvent::GetCaloCluster(clsIndex)
2153 //Get the index of matched track to this cluster
2154 //Works with ESDs and AODs
2155
2156 if(IsClusterMatched(clsIndex))
2157 return fMatchedTrackIndex->At(FindMatchedPosForCluster(clsIndex));
2158 else
2159 return -1;
2160}
2161
2162//__________________________________________________________
2163Int_t AliEMCALRecoUtils::GetMatchedClusterIndex(Int_t trkIndex)
2164{
2165 //Given a track index as in AliESDEvent::GetTrack(trkIndex)
2166 //Get the index of matched cluster to this track
2167 //Works with ESDs and AODs
2168
2169 if(IsTrackMatched(trkIndex))
2170 return fMatchedClusterIndex->At(FindMatchedPosForTrack(trkIndex));
2171 else
2172 return -1;
2173}
2174
2175//______________________________________________________________
2176Bool_t AliEMCALRecoUtils::IsClusterMatched(Int_t clsIndex) const
2177{
2178 //Given a cluster index as in AliESDEvent::GetCaloCluster(clsIndex)
2179 //Returns if the cluster has a match
2180 if(FindMatchedPosForCluster(clsIndex) < 999)
2181 return kTRUE;
2182 else
2183 return kFALSE;
2184}
2185
2186//____________________________________________________________
2187Bool_t AliEMCALRecoUtils::IsTrackMatched(Int_t trkIndex) const
2188{
2189 //Given a track index as in AliESDEvent::GetTrack(trkIndex)
2190 //Returns if the track has a match
2191 if(FindMatchedPosForTrack(trkIndex) < 999)
2192 return kTRUE;
2193 else
2194 return kFALSE;
2195}
2196
2197//______________________________________________________________________
2198UInt_t AliEMCALRecoUtils::FindMatchedPosForCluster(Int_t clsIndex) const
2199{
2200 //Given a cluster index as in AliESDEvent::GetCaloCluster(clsIndex)
2201 //Returns the position of the match in the fMatchedClusterIndex array
2202 Float_t tmpR = fCutR;
2203 UInt_t pos = 999;
2204
2205 for(Int_t i=0; i<fMatchedClusterIndex->GetSize(); i++)
2206 {
2207 if(fMatchedClusterIndex->At(i)==clsIndex)
2208 {
2209 Float_t r = TMath::Sqrt(fResidualEta->At(i)*fResidualEta->At(i) + fResidualPhi->At(i)*fResidualPhi->At(i));
2210 if(r<tmpR)
2211 {
2212 pos=i;
2213 tmpR=r;
2214 AliDebug(3,Form("Matched cluster index: index: %d, dEta: %2.4f, dPhi: %2.4f.\n",
2215 fMatchedClusterIndex->At(i),fResidualEta->At(i),fResidualPhi->At(i)));
2216 }
2217 }
2218 }
2219 return pos;
2220}
2221
2222//____________________________________________________________________
2223UInt_t AliEMCALRecoUtils::FindMatchedPosForTrack(Int_t trkIndex) const
2224{
2225 //Given a track index as in AliESDEvent::GetTrack(trkIndex)
2226 //Returns the position of the match in the fMatchedTrackIndex array
2227 Float_t tmpR = fCutR;
2228 UInt_t pos = 999;
2229
2230 for(Int_t i=0; i<fMatchedTrackIndex->GetSize(); i++)
2231 {
2232 if(fMatchedTrackIndex->At(i)==trkIndex)
2233 {
2234 Float_t r = TMath::Sqrt(fResidualEta->At(i)*fResidualEta->At(i) + fResidualPhi->At(i)*fResidualPhi->At(i));
2235 if(r<tmpR)
2236 {
2237 pos=i;
2238 tmpR=r;
2239 AliDebug(3,Form("Matched track index: index: %d, dEta: %2.4f, dPhi: %2.4f.\n",
2240 fMatchedTrackIndex->At(i),fResidualEta->At(i),fResidualPhi->At(i)));
2241 }
2242 }
2243 }
2244 return pos;
2245}
2246
2247//__________________________________________________________________________
2248Bool_t AliEMCALRecoUtils::IsGoodCluster(AliVCluster *cluster,
2249 const AliEMCALGeometry *geom,
2250 AliVCaloCells* cells,const Int_t bc)
2251{
2252 // check if the cluster survives some quality cut
2253 //
2254 //
2255 Bool_t isGood=kTRUE;
2256
2257 if(!cluster || !cluster->IsEMCAL()) return kFALSE;
2258
2259 if(ClusterContainsBadChannel(geom,cluster->GetCellsAbsId(),cluster->GetNCells())) return kFALSE;
2260
2261 if(!CheckCellFiducialRegion(geom,cluster,cells)) return kFALSE;
2262
2263 if(IsExoticCluster(cluster, cells,bc)) return kFALSE;
2264
2265 return isGood;
2266}
2267
2268//__________________________________________________________
2269Bool_t AliEMCALRecoUtils::IsAccepted(AliESDtrack *esdTrack)
2270{
2271 // Given a esd track, return whether the track survive all the cuts
2272
2273 // The different quality parameter are first
2274 // retrieved from the track. then it is found out what cuts the
2275 // track did not survive and finally the cuts are imposed.
2276
2277 UInt_t status = esdTrack->GetStatus();
2278
2279 Int_t nClustersITS = esdTrack->GetITSclusters(0);
2280 Int_t nClustersTPC = esdTrack->GetTPCclusters(0);
2281
2282 Float_t chi2PerClusterITS = -1;
2283 Float_t chi2PerClusterTPC = -1;
2284 if (nClustersITS!=0)
2285 chi2PerClusterITS = esdTrack->GetITSchi2()/Float_t(nClustersITS);
2286 if (nClustersTPC!=0)
2287 chi2PerClusterTPC = esdTrack->GetTPCchi2()/Float_t(nClustersTPC);
2288
2289
2290 //DCA cuts
2291 if(fTrackCutsType==kGlobalCut)
2292 {
2293 Float_t maxDCAToVertexXYPtDep = 0.0182 + 0.0350/TMath::Power(esdTrack->Pt(),1.01); //This expression comes from AliESDtrackCuts::GetStandardITSTPCTrackCuts2010()
2294 //AliDebug(3,Form("Track pT = %f, DCAtoVertexXY = %f",esdTrack->Pt(),MaxDCAToVertexXYPtDep));
2295 SetMaxDCAToVertexXY(maxDCAToVertexXYPtDep); //Set pT dependent DCA cut to vertex in x-y plane
2296 }
2297
2298
2299 Float_t b[2];
2300 Float_t bCov[3];
2301 esdTrack->GetImpactParameters(b,bCov);
2302 if (bCov[0]<=0 || bCov[2]<=0)
2303 {
2304 AliDebug(1, "Estimated b resolution lower or equal zero!");
2305 bCov[0]=0; bCov[2]=0;
2306 }
2307
2308 Float_t dcaToVertexXY = b[0];
2309 Float_t dcaToVertexZ = b[1];
2310 Float_t dcaToVertex = -1;
2311
2312 if (fCutDCAToVertex2D)
2313 dcaToVertex = TMath::Sqrt(dcaToVertexXY*dcaToVertexXY/fCutMaxDCAToVertexXY/fCutMaxDCAToVertexXY + dcaToVertexZ*dcaToVertexZ/fCutMaxDCAToVertexZ/fCutMaxDCAToVertexZ);
2314 else
2315 dcaToVertex = TMath::Sqrt(dcaToVertexXY*dcaToVertexXY + dcaToVertexZ*dcaToVertexZ);
2316
2317 // cut the track?
2318
2319 Bool_t cuts[kNCuts];
2320 for (Int_t i=0; i<kNCuts; i++) cuts[i]=kFALSE;
2321
2322 // track quality cuts
2323 if (fCutRequireTPCRefit && (status&AliESDtrack::kTPCrefit)==0)
2324 cuts[0]=kTRUE;
2325 if (fCutRequireITSRefit && (status&AliESDtrack::kITSrefit)==0)
2326 cuts[1]=kTRUE;
2327 if (nClustersTPC<fCutMinNClusterTPC)
2328 cuts[2]=kTRUE;
2329 if (nClustersITS<fCutMinNClusterITS)
2330 cuts[3]=kTRUE;
2331 if (chi2PerClusterTPC>fCutMaxChi2PerClusterTPC)
2332 cuts[4]=kTRUE;
2333 if (chi2PerClusterITS>fCutMaxChi2PerClusterITS)
2334 cuts[5]=kTRUE;
2335 if (!fCutAcceptKinkDaughters && esdTrack->GetKinkIndex(0)>0)
2336 cuts[6]=kTRUE;
2337 if (fCutDCAToVertex2D && dcaToVertex > 1)
2338 cuts[7] = kTRUE;
2339 if (!fCutDCAToVertex2D && TMath::Abs(dcaToVertexXY) > fCutMaxDCAToVertexXY)
2340 cuts[8] = kTRUE;
2341 if (!fCutDCAToVertex2D && TMath::Abs(dcaToVertexZ) > fCutMaxDCAToVertexZ)
2342 cuts[9] = kTRUE;
2343
2344 if(fTrackCutsType==kGlobalCut)
2345 {
2346 //Require at least one SPD point + anything else in ITS
2347 if( (esdTrack->HasPointOnITSLayer(0) || esdTrack->HasPointOnITSLayer(1)) == kFALSE)
2348 cuts[10] = kTRUE;
2349 }
2350
2351 // ITS
2352 if(fCutRequireITSStandAlone || fCutRequireITSpureSA){
2353 if ((status & AliESDtrack::kITSin) == 0 || (status & AliESDtrack::kTPCin)){
2354 // TPC tracks
2355 cuts[11] = kTRUE;
2356 }else{
2357 // ITS standalone tracks
2358 if(fCutRequireITSStandAlone && !fCutRequireITSpureSA){
2359 if(status & AliESDtrack::kITSpureSA) cuts[11] = kTRUE;
2360 }else if(fCutRequireITSpureSA){
2361 if(!(status & AliESDtrack::kITSpureSA)) cuts[11] = kTRUE;
2362 }
2363 }
2364 }
2365
2366 Bool_t cut=kFALSE;
2367 for (Int_t i=0; i<kNCuts; i++)
2368 if (cuts[i]) { cut = kTRUE ; }
2369
2370 // cut the track
2371 if (cut)
2372 return kFALSE;
2373 else
2374 return kTRUE;
2375}
2376
2377//_____________________________________
2378void AliEMCALRecoUtils::InitTrackCuts()
2379{
2380 //Intilize the track cut criteria
2381 //By default these cuts are set according to AliESDtrackCuts::GetStandardTPCOnlyTrackCuts()
2382 //Also you can customize the cuts using the setters
2383
2384 switch (fTrackCutsType)
2385 {
2386 case kTPCOnlyCut:
2387 {
2388 AliInfo(Form("Track cuts for matching: GetStandardTPCOnlyTrackCuts()"));
2389 //TPC
2390 SetMinNClustersTPC(70);
2391 SetMaxChi2PerClusterTPC(4);
2392 SetAcceptKinkDaughters(kFALSE);
2393 SetRequireTPCRefit(kFALSE);
2394
2395 //ITS
2396 SetRequireITSRefit(kFALSE);
2397 SetMaxDCAToVertexZ(3.2);
2398 SetMaxDCAToVertexXY(2.4);
2399 SetDCAToVertex2D(kTRUE);
2400
2401 break;
2402 }
2403
2404 case kGlobalCut:
2405 {
2406 AliInfo(Form("Track cuts for matching: GetStandardITSTPCTrackCuts2010(kTURE)"));
2407 //TPC
2408 SetMinNClustersTPC(70);
2409 SetMaxChi2PerClusterTPC(4);
2410 SetAcceptKinkDaughters(kFALSE);
2411 SetRequireTPCRefit(kTRUE);
2412
2413 //ITS
2414 SetRequireITSRefit(kTRUE);
2415 SetMaxDCAToVertexZ(2);
2416 SetMaxDCAToVertexXY();
2417 SetDCAToVertex2D(kFALSE);
2418
2419 break;
2420 }
2421
2422 case kLooseCut:
2423 {
2424 AliInfo(Form("Track cuts for matching: Loose cut w/o DCA cut"));
2425 SetMinNClustersTPC(50);
2426 SetAcceptKinkDaughters(kTRUE);
2427
2428 break;
2429 }
2430
2431 case kITSStandAlone:
2432 {
2433 AliInfo(Form("Track cuts for matching: ITS Stand Alone tracks cut w/o DCA cut"));
2434 SetRequireITSRefit(kTRUE);
2435 SetRequireITSStandAlone(kTRUE);
2436 SetITSTrackSA(kTRUE);
2437 break;
2438 }
2439
2440 }
2441}
2442
2443
2444//________________________________________________________________________
2445void AliEMCALRecoUtils::SetClusterMatchedToTrack(const AliVEvent *event)
2446{
2447 // Checks if tracks are matched to EMC clusters and set the matched EMCAL cluster index to ESD track.
2448
2449 Int_t nTracks = event->GetNumberOfTracks();
2450 for (Int_t iTrack = 0; iTrack < nTracks; ++iTrack)
2451 {
2452 AliVTrack* track = dynamic_cast<AliVTrack*>(event->GetTrack(iTrack));
2453 if (!track)
2454 {
2455 AliWarning(Form("Could not receive track %d", iTrack));
2456 continue;
2457 }
2458
2459 Int_t matchClusIndex = GetMatchedClusterIndex(iTrack);
2460 track->SetEMCALcluster(matchClusIndex); //sets -1 if track not matched within residual
2461 /*the following can be done better if AliVTrack::SetStatus will be there. Patch pending with Andreas/Peter*/
2462 AliESDtrack* esdtrack = dynamic_cast<AliESDtrack*>(track);
2463 if (esdtrack) {
2464 if(matchClusIndex != -1)
2465 esdtrack->SetStatus(AliESDtrack::kEMCALmatch);
2466 else
2467 esdtrack->ResetStatus(AliESDtrack::kEMCALmatch);
2468 } else {
2469 AliAODTrack* aodtrack = dynamic_cast<AliAODTrack*>(track);
2470 if(matchClusIndex != -1)
2471 aodtrack->SetStatus(AliESDtrack::kEMCALmatch);
2472 else
2473 aodtrack->ResetStatus(AliESDtrack::kEMCALmatch);
2474 }
2475
2476 }
2477 AliDebug(2,"Track matched to closest cluster");
2478}
2479
2480//_________________________________________________________________________
2481void AliEMCALRecoUtils::SetTracksMatchedToCluster(const AliVEvent *event)
2482{
2483 // Checks if EMC clusters are matched to ESD track.
2484 // Adds track indexes of all the tracks matched to a cluster withing residuals in ESDCalocluster.
2485
2486 for (Int_t iClus=0; iClus < event->GetNumberOfCaloClusters(); ++iClus)
2487 {
2488 AliVCluster *cluster = event->GetCaloCluster(iClus);
2489 if (!cluster->IsEMCAL())
2490 continue;
2491
2492 Int_t nTracks = event->GetNumberOfTracks();
2493 TArrayI arrayTrackMatched(nTracks);
2494
2495 // Get the closest track matched to the cluster
2496 Int_t nMatched = 0;
2497 Int_t matchTrackIndex = GetMatchedTrackIndex(iClus);
2498 if (matchTrackIndex != -1)
2499 {
2500 arrayTrackMatched[nMatched] = matchTrackIndex;
2501 nMatched++;
2502 }
2503
2504 // Get all other tracks matched to the cluster
2505 for(Int_t iTrk=0; iTrk<nTracks; ++iTrk)
2506 {
2507 AliVTrack* track = dynamic_cast<AliVTrack*>(event->GetTrack(iTrk));
2508 if(iTrk == matchTrackIndex) continue;
2509 if(track->GetEMCALcluster() == iClus)
2510 {
2511 arrayTrackMatched[nMatched] = iTrk;
2512 ++nMatched;
2513 }
2514 }
2515
2516 //printf("Tender::SetTracksMatchedToCluster - cluster E %f, N matches %d, first match %d\n",cluster->E(),nMatched,arrayTrackMatched[0]);
2517
2518 arrayTrackMatched.Set(nMatched);
2519 AliESDCaloCluster *esdcluster = dynamic_cast<AliESDCaloCluster*>(cluster);
2520 if (esdcluster)
2521 esdcluster->AddTracksMatched(arrayTrackMatched);
2522 else if (nMatched>0) {
2523 AliAODCaloCluster *aodcluster = dynamic_cast<AliAODCaloCluster*>(cluster);
2524 if (aodcluster)
2525 aodcluster->AddTrackMatched(event->GetTrack(arrayTrackMatched.At(0)));
2526 }
2527
2528 Float_t eta= -999, phi = -999;
2529 if (matchTrackIndex != -1)
2530 GetMatchedResiduals(iClus, eta, phi);
2531 cluster->SetTrackDistance(phi, eta);
2532 }
2533
2534 AliDebug(2,"Cluster matched to tracks");
2535}
2536
2537//___________________________________________________
2538void AliEMCALRecoUtils::Print(const Option_t *) const
2539{
2540 // Print Parameters
2541
2542 printf("AliEMCALRecoUtils Settings: \n");
2543 printf("Misalignment shifts\n");
2544 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,
2545 fMisalTransShift[i*3],fMisalTransShift[i*3+1],fMisalTransShift[i*3+2],
2546 fMisalRotShift[i*3], fMisalRotShift[i*3+1], fMisalRotShift[i*3+2] );
2547 printf("Non linearity function %d, parameters:\n", fNonLinearityFunction);
2548 for(Int_t i=0; i<6; i++) printf("param[%d]=%f\n",i, fNonLinearityParams[i]);
2549
2550 printf("Position Recalculation option %d, Particle Type %d, fW0 %2.2f, Recalibrate Data %d \n",fPosAlgo,fParticleType,fW0, fRecalibration);
2551
2552 printf("Matching criteria: ");
2553 if(fCutEtaPhiSum)
2554 {
2555 printf("sqrt(dEta^2+dPhi^2)<%4.3f\n",fCutR);
2556 }
2557 else if(fCutEtaPhiSeparate)
2558 {
2559 printf("dEta<%4.3f, dPhi<%4.3f\n",fCutEta,fCutPhi);
2560 }
2561 else
2562 {
2563 printf("Error\n");
2564 printf("please specify your cut criteria\n");
2565 printf("To cut on sqrt(dEta^2+dPhi^2), use: SwitchOnCutEtaPhiSum()\n");
2566 printf("To cut on dEta and dPhi separately, use: SwitchOnCutEtaPhiSeparate()\n");
2567 }
2568
2569 printf("Mass hypothesis = %2.3f [GeV/c^2], extrapolation step to surface = %2.2f[cm], step to cluster = %2.2f[cm]\n",fMass,fStepSurface, fStepCluster);
2570 printf("Cluster selection window: dR < %2.0f\n",fClusterWindow);
2571
2572 printf("Track cuts: \n");
2573 printf("Minimum track pT: %1.2f\n",fCutMinTrackPt);
2574 printf("AOD track selection mask: %d\n",fAODFilterMask);
2575 printf("TPCRefit = %d, ITSRefit = %d\n",fCutRequireTPCRefit,fCutRequireITSRefit);
2576 printf("AcceptKinks = %d\n",fCutAcceptKinkDaughters);
2577 printf("MinNCulsterTPC = %d, MinNClusterITS = %d\n",fCutMinNClusterTPC,fCutMinNClusterITS);
2578 printf("MaxChi2TPC = %2.2f, MaxChi2ITS = %2.2f\n",fCutMaxChi2PerClusterTPC,fCutMaxChi2PerClusterITS);
2579 printf("DCSToVertex2D = %d, MaxDCAToVertexXY = %2.2f, MaxDCAToVertexZ = %2.2f\n",fCutDCAToVertex2D,fCutMaxDCAToVertexXY,fCutMaxDCAToVertexZ);
2580}
2581