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 //_________________________________________________________________________
17 // Class for PID selection with calorimeters
18 // The Output of the main method GetIdentifiedParticleType is a PDG number identifying the cluster,
19 // being kPhoton, kElectron, kPi0 ... as defined in the header file
20 // - GetIdentifiedParticleType(const AliVCluster * cluster)
21 // Assignes a PID tag to the cluster, right now there is the possibility to : use bayesian weights from reco,
22 // recalculate them (EMCAL) or use other procedures not used in reco.
23 // In order to recalculate Bayesian, it is necessary to load the EMCALUtils library
24 // and do SwitchOnBayesianRecalculation().
25 // To change the PID parameters from Low to High like the ones by default, use the constructor
27 // where flux is AliCaloPID::kLow or AliCaloPID::kHigh
28 // If it is necessary to change the parameters use the constructor
29 // AliCaloPID(AliEMCALPIDUtils *utils) and set the parameters before.
31 // - GetGetIdentifiedParticleTypeFromBayesian(const Double_t * pid, const Float_t energy)
32 // Reads the PID weights array of the ESDs and depending on its magnitude identifies the particle,
33 // executed when bayesian is ON by GetIdentifiedParticleType(const AliVCluster * cluster)
34 // - SetPIDBits: Simple PID, depending on the thresholds fLOCut fTOFCut and even the
35 // result of the PID bayesian a different PID bit is set.
37 // - IsTrackMatched(): Independent method that needs to be combined with GetIdentifiedParticleType to know if the cluster was matched
39 //*-- Author: Gustavo Conesa (INFN-LNF)
40 //////////////////////////////////////////////////////////////////////////////
43 // --- ROOT system ---
48 // ---- ANALYSIS system ----
49 #include "AliCaloPID.h"
50 #include "AliAODCaloCluster.h"
51 #include "AliVCaloCells.h"
52 #include "AliVTrack.h"
53 #include "AliAODPWG4Particle.h"
54 #include "AliCalorimeterUtils.h"
55 #include "AliVEvent.h"
58 #include "AliEMCALPIDUtils.h"
63 //________________________
64 AliCaloPID::AliCaloPID() :
65 TObject(), fDebug(-1), fParticleFlux(kLow),
67 fEMCALPIDUtils(), fUseBayesianWeights(kFALSE), fRecalculateBayesian(kFALSE),
68 fEMCALPhotonWeight(0.), fEMCALPi0Weight(0.),
69 fEMCALElectronWeight(0.), fEMCALChargeWeight(0.), fEMCALNeutralWeight(0.),
70 fPHOSPhotonWeight(0.), fPHOSPi0Weight(0.),
71 fPHOSElectronWeight(0.), fPHOSChargeWeight(0.) , fPHOSNeutralWeight(0.),
72 fPHOSWeightFormula(0), fPHOSPhotonWeightFormula(0), fPHOSPi0WeightFormula(0),
73 fPHOSPhotonWeightFormulaExpression(""),
74 fPHOSPi0WeightFormulaExpression(""),
76 fEMCALL0CutMax(100.), fEMCALL0CutMin(0),
77 fEMCALDEtaCut(2000.), fEMCALDPhiCut(2000.),
79 fPHOSDispersionCut(1000), fPHOSRCut(1000),
81 fUseSimpleMassCut(kFALSE),
82 fUseSimpleM02Cut(kFALSE),
83 fUseSplitAsyCut(kFALSE),
84 fUseSplitSSCut(kTRUE),
85 fSplitM02MaxCut(0), fSplitM02MinCut(0), fSplitMinNCells(0),
86 fMassEtaMin(0), fMassEtaMax(0),
87 fMassPi0Min(0), fMassPi0Max(0),
88 fMassPhoMin(0), fMassPhoMax(0),
89 fM02MaxParamShiftNLMN(0),
90 fSplitWidthSigma(0), fMassShiftHighECell(0)
94 //Initialize parameters
98 //________________________________________
99 AliCaloPID::AliCaloPID(Int_t flux) :
100 TObject(), fDebug(-1), fParticleFlux(flux),
102 fEMCALPIDUtils(), fUseBayesianWeights(kFALSE), fRecalculateBayesian(kFALSE),
103 fEMCALPhotonWeight(0.), fEMCALPi0Weight(0.),
104 fEMCALElectronWeight(0.), fEMCALChargeWeight(0.), fEMCALNeutralWeight(0.),
105 fPHOSPhotonWeight(0.), fPHOSPi0Weight(0.),
106 fPHOSElectronWeight(0.), fPHOSChargeWeight(0.) , fPHOSNeutralWeight(0.),
107 fPHOSWeightFormula(0), fPHOSPhotonWeightFormula(0), fPHOSPi0WeightFormula(0),
108 fPHOSPhotonWeightFormulaExpression(""),
109 fPHOSPi0WeightFormulaExpression(""),
111 fEMCALL0CutMax(100.), fEMCALL0CutMin(0),
112 fEMCALDEtaCut(2000.), fEMCALDPhiCut(2000.),
114 fPHOSDispersionCut(1000), fPHOSRCut(1000),
116 fUseSimpleMassCut(kFALSE),
117 fUseSimpleM02Cut(kFALSE),
118 fUseSplitAsyCut(kFALSE),
119 fUseSplitSSCut(kTRUE),
120 fSplitM02MaxCut(0), fSplitM02MinCut(0), fSplitMinNCells(0),
121 fMassEtaMin(0), fMassEtaMax(0),
122 fMassPi0Min(0), fMassPi0Max(0),
123 fMassPhoMin(0), fMassPhoMax(0),
124 fM02MaxParamShiftNLMN(0),
125 fSplitWidthSigma(0), fMassShiftHighECell(0)
129 //Initialize parameters
134 //_______________________________________________
135 AliCaloPID::AliCaloPID(const TNamed * emcalpid) :
136 TObject(), fDebug(-1), fParticleFlux(kLow),
138 fEMCALPIDUtils((AliEMCALPIDUtils*)emcalpid),
139 fUseBayesianWeights(kFALSE), fRecalculateBayesian(kFALSE),
140 fEMCALPhotonWeight(0.), fEMCALPi0Weight(0.),
141 fEMCALElectronWeight(0.), fEMCALChargeWeight(0.), fEMCALNeutralWeight(0.),
142 fPHOSPhotonWeight(0.), fPHOSPi0Weight(0.),
143 fPHOSElectronWeight(0.), fPHOSChargeWeight(0.) , fPHOSNeutralWeight(0.),
144 fPHOSWeightFormula(0), fPHOSPhotonWeightFormula(0), fPHOSPi0WeightFormula(0),
145 fPHOSPhotonWeightFormulaExpression(""),
146 fPHOSPi0WeightFormulaExpression(""),
148 fEMCALL0CutMax(100.), fEMCALL0CutMin(0),
149 fEMCALDEtaCut(2000.), fEMCALDPhiCut(2000.),
151 fPHOSDispersionCut(1000), fPHOSRCut(1000),
153 fUseSimpleMassCut(kFALSE),
154 fUseSimpleM02Cut(kFALSE),
155 fUseSplitAsyCut(kFALSE),
156 fUseSplitSSCut(kTRUE),
157 fSplitM02MaxCut(0), fSplitM02MinCut(0), fSplitMinNCells(0),
158 fMassEtaMin(0), fMassEtaMax(0),
159 fMassPi0Min(0), fMassPi0Max(0),
160 fMassPhoMin(0), fMassPhoMax(0),
161 fM02MaxParamShiftNLMN(0),
162 fSplitWidthSigma(0), fMassShiftHighECell(0)
167 //Initialize parameters
171 //_______________________
172 AliCaloPID::~AliCaloPID()
176 delete fPHOSPhotonWeightFormula ;
177 delete fPHOSPi0WeightFormula ;
178 delete fEMCALPIDUtils ;
182 //_______________________________
183 void AliCaloPID::InitParameters()
185 //Initialize the parameters of the PID.
188 fEMCALPhotonWeight = 0.6 ;
189 fEMCALPi0Weight = 0.6 ;
190 fEMCALElectronWeight = 0.6 ;
191 fEMCALChargeWeight = 0.6 ;
192 fEMCALNeutralWeight = 0.6 ;
194 fPHOSPhotonWeight = 0.6 ;
195 fPHOSPi0Weight = 0.6 ;
196 fPHOSElectronWeight = 0.6 ;
197 fPHOSChargeWeight = 0.6 ;
198 fPHOSNeutralWeight = 0.6 ;
200 //Formula to set the PID weight threshold for photon or pi0
201 fPHOSWeightFormula = kFALSE;
202 fPHOSPhotonWeightFormulaExpression = "0.98*(x<40)+ 0.68*(x>=100)+(x>=40 && x<100)*(0.98+x*(6e-3)-x*x*(2e-04)+x*x*x*(1.1e-06))";
203 fPHOSPi0WeightFormulaExpression = "0.98*(x<65)+ 0.915*(x>=100)+(x>=65 && x-x*(1.95e-3)-x*x*(4.31e-05)+x*x*x*(3.61e-07))" ;
205 if(fRecalculateBayesian){
206 if(fParticleFlux == kLow){
207 printf("AliCaloPID::Init() - SetLOWFluxParam\n");
208 fEMCALPIDUtils->SetLowFluxParam() ;
210 else if (fParticleFlux == kHigh){
211 printf("AliCaloPID::Init() - SetHIGHFluxParam\n");
212 fEMCALPIDUtils->SetHighFluxParam() ;
216 //PID recalculation, not bayesian
219 fEMCALL0CutMax = 0.3 ;
220 fEMCALL0CutMin = 0.01;
222 fEMCALDPhiCut = 0.05; // Same cut as in AliEMCALRecoUtils
223 fEMCALDEtaCut = 0.025;// Same cut as in AliEMCALRecoUtils
225 // PHOS / EMCAL, not used
230 fPHOSDispersionCut = 2.5;
234 fSplitM02MinCut = 0.3 ;
235 fSplitM02MaxCut = 5 ;
236 fSplitMinNCells = 4 ;
247 fMassPi0Param[0][0] = 0 ; // Constant term on mass dependence
248 fMassPi0Param[0][1] = 0 ; // slope term on mass dependence
249 fMassPi0Param[0][2] = 0 ; // E function change
250 fMassPi0Param[0][3] = 0.044 ; // constant term on mass dependence
251 fMassPi0Param[0][4] = 0.0049; // slope term on mass dependence
252 fMassPi0Param[0][5] = 0.070 ; // Absolute low mass cut
254 fMassPi0Param[1][0] = 0.115 ; // Constant term below 21 GeV
255 fMassPi0Param[1][1] = 0.00096; // slope term below 21 GeV
256 fMassPi0Param[1][2] = 21 ; // E function change
257 fMassPi0Param[1][3] = 0.10 ; // constant term on mass dependence
258 fMassPi0Param[1][4] = 0.0017; // slope term on mass dependence
259 fMassPi0Param[1][5] = 0.070 ; // Absolute low mass cut
261 fWidthPi0Param[0][0] = 0.012 ; // Constant term on width dependence
262 fWidthPi0Param[0][1] = 0.0 ; // Slope term on width dependence
263 fWidthPi0Param[0][2] = 19 ; // E function change
264 fWidthPi0Param[0][3] = 0.0012; // Constant term on width dependence
265 fWidthPi0Param[0][4] = 0.0006; // Slope term on width dependence
266 fWidthPi0Param[0][5] = 0.0 ; // xx term
268 fWidthPi0Param[1][0] = 0.009 ; // Constant term on width dependence
269 fWidthPi0Param[1][1] = 0.000 ; // Slope term on width dependence
270 fWidthPi0Param[1][2] = 10 ; // E function change
271 fWidthPi0Param[1][3] = 0.0023 ; // Constant term on width dependence
272 fWidthPi0Param[1][4] = 0.00067; // Slope term on width dependence
273 fWidthPi0Param[1][5] = 0.000 ;// xx term
275 fMassShiftHighECell = 0; // Shift of cuts in case of higher energy threshold in cells, 5 MeV when Ecell>150 MeV
277 //TF1 *lM02MinNLM1 = new TF1("M02MinNLM1","exp(2.135-0.245*x)",6,13.6);
278 fM02MinParam[0][0] = 2.135 ;
279 fM02MinParam[0][1] =-0.245 ;
280 fM02MinParam[0][2] = 0.0 ;
281 fM02MinParam[0][3] = 0.0 ;
282 fM02MinParam[0][4] = 0.0 ;
284 // Same as NLM=1 for NLM=2
285 fM02MinParam[1][0] = 2.135 ;
286 fM02MinParam[1][1] =-0.245 ;
287 fM02MinParam[1][2] = 0.0 ;
288 fM02MinParam[1][3] = 0.0 ;
289 fM02MinParam[1][4] = 0.0 ;
291 //TF1 *lM02MaxNLM1 = new TF1("M02MaxNLM1","exp(0.0662-0.0201*x)-0.0955+0.00186*x[0]+9.91/x[0]",6,100);
292 fM02MaxParam[0][0] = 0.0662 ;
293 fM02MaxParam[0][1] =-0.0201 ;
294 fM02MaxParam[0][2] =-0.0955 ;
295 fM02MaxParam[0][3] = 0.00186;
296 fM02MaxParam[0][4] = 9.91 ;
298 //TF1 *lM02MaxNLM2 = new TF1("M02MaxNLM2","exp(0.353-0.0264*x)-0.524+0.00559*x[0]+21.9/x[0]",6,100);
299 fM02MaxParam[1][0] = 0.353 ;
300 fM02MaxParam[1][1] =-0.0264 ;
301 fM02MaxParam[1][2] =-0.524 ;
302 fM02MaxParam[1][3] = 0.00559;
303 fM02MaxParam[1][4] = 21.9 ;
305 fM02MaxParamShiftNLMN = 0.75;
307 //TF1 *lAsyNLM1 = new TF1("lAsyNLM1","0.96-879/(x*x*x)",5,100);
308 fAsyMinParam[0][0] = 0.96 ;
309 fAsyMinParam[0][1] = 0 ;
310 fAsyMinParam[0][2] =-879 ;
311 fAsyMinParam[0][3] = 0.96 ; // Absolute max
313 //TF1 *lAsyNLM2 = new TF1("lAsyNLM2","0.95+0.0015*x-233/(x*x*x)",5,100);
314 fAsyMinParam[1][0] = 0.95 ;
315 fAsyMinParam[1][1] = 0.0015;
316 fAsyMinParam[1][2] =-233 ;
317 fAsyMinParam[1][3] = 1.0 ; // Absolute max
319 fSplitEFracMin[0] = 0.0 ; // 0.96
320 fSplitEFracMin[1] = 0.0 ; // 0.96
321 fSplitEFracMin[2] = 0.0 ; // 0.7
323 fSubClusterEMin[0] = 0.0; // 3 GeV
324 fSubClusterEMin[1] = 0.0; // 1 GeV
325 fSubClusterEMin[2] = 0.0; // 1 GeV
328 fSplitWidthSigma = 3. ;
333 //_________________________________________________________________________________________
334 Bool_t AliCaloPID::IsInPi0SplitAsymmetryRange(Float_t energy, Float_t asy, Int_t nlm) const
336 // Select the appropriate mass range for pi0 selection in splitting method
337 // No used yet in splitting ID decision
339 if(!fUseSplitAsyCut) return kTRUE ;
341 Float_t abasy = TMath::Abs(asy);
344 if(nlm > 2) inlm=1; // only 2 cases defined nlm=1 and nlm>=2
346 // Get the parametrized min cut of asymmetry for NLM=2 up to 11 GeV
348 Float_t cut = fAsyMinParam[inlm][0] + fAsyMinParam[inlm][1]*energy + fAsyMinParam[inlm][2]/energy/energy/energy ;
350 // In any case and beyond validity energy range of the function,
351 // the parameter cannot be smaller than 1
352 if( cut > fAsyMinParam[inlm][3] ) cut = fAsyMinParam[inlm][3];
354 //printf("energy %2.2f - nlm: %d (%d)- p0 %f, p1 %f, p2 %f, p3 %f ; cut: %2.2f\n",energy,nlm,inlm,
355 // fAsyMinParam[inlm][0],fAsyMinParam[inlm][1],fAsyMinParam[inlm][2],fAsyMinParam[inlm][3],cut);
357 if(abasy < cut) return kTRUE;
362 //______________________________________________________________________________________
363 Bool_t AliCaloPID::IsInPi0SplitMassRange(Float_t energy, Float_t mass, Int_t nlm) const
365 // Select the appropriate mass range for pi0 selection in splitting method
367 if(fUseSimpleMassCut)
369 if(mass < fMassPi0Max && mass > fMassPi0Min) return kTRUE;
373 // Get the selected mean value as reference for the mass
375 if(nlm > 2) inlm=1; // only 2 cases defined nlm=1 and nlm>=2
377 Float_t meanMass = energy * fMassPi0Param[inlm][1] + fMassPi0Param[inlm][0];
378 if(energy > fMassPi0Param[inlm][2]) meanMass = energy * fMassPi0Param[inlm][4] + fMassPi0Param[inlm][3];
380 // In case of higher energy cell cut than 50 MeV, smaller mean mass 0-5 MeV, not really necessary
381 meanMass -= fMassShiftHighECell;
383 // Get the parametrized width of the mass
384 Float_t width = 0.009;
385 if (energy > 8 && energy < fWidthPi0Param[inlm][2])
386 width = energy * fWidthPi0Param[inlm][1] + fWidthPi0Param[inlm][0];
387 else if( energy > fWidthPi0Param[inlm][2])
388 width = energy * energy * fWidthPi0Param[inlm][5] + energy * fWidthPi0Param[inlm][4] + fWidthPi0Param[inlm][3];
390 // Calculate the 2 sigma cut
391 Float_t minMass = meanMass-fSplitWidthSigma*width;
392 Float_t maxMass = meanMass+fSplitWidthSigma*width;
394 // In case of low energy, hard cut to avoid conversions
395 if(energy < 10 && minMass < fMassPi0Param[inlm][5] ) minMass = fMassPi0Param[inlm][5];
397 //printf("E %2.2f, mass %1.1f, nlm %d: sigma %1.1f width %3.1f, mean Mass %3.0f, minMass %3.0f, maxMass %3.0f\n ",
398 // energy,mass *1000, inlm, fSplitWidthSigma, width*1000, meanMass*1000,minMass*1000,maxMass*1000);
400 if(mass < maxMass && mass > minMass) return kTRUE;
405 //________________________________________________
406 Bool_t AliCaloPID::IsInM02Range(Float_t m02) const
408 // Select the appropriate m02 range, fix cut, not E dependent
410 Float_t minCut = fSplitM02MinCut;
411 Float_t maxCut = fSplitM02MaxCut;
413 if(m02 < maxCut && m02 > minCut) return kTRUE;
418 //_______________________________________________________________________________
419 Bool_t AliCaloPID::IsInPi0M02Range(Float_t energy, Float_t m02, Int_t nlm) const
421 // Select the appropriate m02 range in splitting method for pi0
423 if(!fUseSplitSSCut) return kTRUE ;
425 //First check the absolute minimum and maximum
426 if(!IsInM02Range(m02)) return kFALSE ;
428 //If requested, check the E dependent cuts
429 else if(!fUseSimpleM02Cut)
432 if(nlm > 2) inlm=1; // only 2 cases defined nlm=1 and nlm>=2
434 Float_t minCut = fSplitM02MinCut;
435 Float_t maxCut = fSplitM02MaxCut;
437 //e^{a+bx} + c + dx + e/x
438 if(energy > 1) minCut = TMath::Exp( fM02MinParam[inlm][0] + fM02MinParam[inlm][1]*energy ) +
439 fM02MinParam[inlm][2] + fM02MinParam[inlm][3]*energy + fM02MinParam[inlm][4]/energy;
441 if(energy > 1) maxCut = TMath::Exp( fM02MaxParam[inlm][0] + fM02MaxParam[inlm][1]*energy ) +
442 fM02MaxParam[inlm][2] + fM02MaxParam[inlm][3]*energy + fM02MaxParam[inlm][4]/energy;
444 // In any case and beyond validity energy range of the function,
445 // the parameter cannot be smaller than 0.3 or larger than 4-5
446 if( minCut < fSplitM02MinCut) minCut = fSplitM02MinCut;
447 if( maxCut > fSplitM02MaxCut) maxCut = fSplitM02MaxCut;
448 if( nlm > 2 ) maxCut+=fM02MaxParamShiftNLMN;
450 //if(energy > 7) printf("\t \t E %2.2f, nlm %d, m02 %2.2f, minM02 %2.2f, maxM02 %2.2f\n",energy, nlm, m02,minCut,maxCut);
452 if(m02 < maxCut && m02 > minCut) return kTRUE;
462 //______________________________________________________________________________
463 Bool_t AliCaloPID::IsInEtaM02Range(Float_t energy, Float_t m02, Int_t nlm) const
465 // Select the appropriate m02 range in splitting method to select eta's
466 // Use same parametrization as pi0, just shift the distributions (to be tuned)
468 if(!fUseSplitSSCut) return kTRUE ;
470 //First check the absolute minimum and maximum
471 if(!IsInM02Range(m02)) return kFALSE ;
473 //DO NOT USE, study parametrization
475 //If requested, check the E dependent cuts
476 else if(!fUseSimpleM02Cut)
479 if(nlm > 2) inlm=1; // only 2 cases defined nlm=1 and nlm>=2
481 Float_t minCut = fSplitM02MinCut;
482 Float_t maxCut = fSplitM02MaxCut;
484 Float_t shiftE = energy-20; // to be tuned
485 if(nlm==1) shiftE=energy-28;
487 //e^{a+bx} + c + dx + e/x
488 if(shiftE > 1) minCut = TMath::Exp( fM02MinParam[inlm][0] + fM02MinParam[inlm][1]*shiftE ) +
489 fM02MinParam[inlm][2] + fM02MinParam[inlm][3]*shiftE + fM02MinParam[inlm][4]/shiftE;
491 // In any case the parameter cannot be smaller than 0.3
492 if( minCut < fSplitM02MinCut) minCut = fSplitM02MinCut;
494 shiftE = energy+20; // to be tuned
496 if(shiftE > 1) maxCut = 1 + TMath::Exp( fM02MaxParam[inlm][0] + fM02MaxParam[inlm][1]*shiftE ) +
497 fM02MaxParam[inlm][2] + fM02MaxParam[inlm][3]*shiftE + fM02MaxParam[inlm][4]/shiftE;
499 // In any case the parameter cannot be smaller than 4-5
500 if( maxCut > fSplitM02MaxCut) maxCut = fSplitM02MaxCut;
501 if( nlm > 2 ) maxCut+=fM02MaxParamShiftNLMN;
503 //if(energy>6)printf("\t \t E %2.2f, nlm %d, m02 %2.2f, minM02 %2.2f, maxM02 %2.2f\n",energy, nlm, m02,minCut,maxCut);
505 if(m02 < maxCut && m02 > minCut) return kTRUE;
514 //______________________________________________________________________________
515 Bool_t AliCaloPID::IsInConM02Range(Float_t energy, Float_t m02, Int_t nlm) const
517 // Select the appropriate m02 range in splitting method for converted photons
518 // Just min limit for pi0s is max for conversion.
520 if(!fUseSplitSSCut) return kTRUE ;
522 Float_t minCut = 0.1;
523 Float_t maxCut = fSplitM02MinCut;
525 if(!fUseSimpleM02Cut)
528 if(nlm > 2) inlm=1; // only 2 cases defined nlm=1 and nlm>=2
530 //e^{a+bx} + c + dx + e/x
531 if(energy > 1) maxCut = TMath::Exp( fM02MinParam[inlm][0] + fM02MinParam[inlm][1]*energy ) +
532 fM02MinParam[inlm][2] + fM02MinParam[inlm][3]*energy + fM02MinParam[inlm][4]/energy;
534 if( maxCut < fSplitM02MinCut) maxCut = fSplitM02MinCut;
537 if(m02 < maxCut && m02 > minCut) return kTRUE;
542 //______________________________________________
543 AliEMCALPIDUtils *AliCaloPID::GetEMCALPIDUtils()
545 // return pointer to AliEMCALPIDUtils, create it if needed
547 if(!fEMCALPIDUtils) fEMCALPIDUtils = new AliEMCALPIDUtils ;
548 return fEMCALPIDUtils ;
553 //________________________________________________________________
554 Int_t AliCaloPID::GetIdentifiedParticleType(AliVCluster * cluster)
556 // Returns a PDG number corresponding to the likely ID of the cluster
558 Float_t energy = cluster->E();
559 Float_t lambda0 = cluster->GetM02();
560 Float_t lambda1 = cluster->GetM20();
562 // ---------------------
563 // Use bayesian approach
564 // ---------------------
566 if(fUseBayesianWeights)
568 Double_t weights[AliPID::kSPECIESCN];
570 if(cluster->IsEMCAL() && fRecalculateBayesian)
572 fEMCALPIDUtils->ComputePID(energy, lambda0);
573 for(Int_t i = 0; i < AliPID::kSPECIESCN; i++) weights[i] = fEMCALPIDUtils->GetPIDFinal(i);
577 for(Int_t i = 0; i < AliPID::kSPECIESCN; i++) weights[i] = cluster->GetPID()[i];
580 if(fDebug > 0) PrintClusterPIDWeights(weights);
582 return GetIdentifiedParticleTypeFromBayesWeights(cluster->IsEMCAL(), weights, energy);
585 // -------------------------------------------------------
586 // Calculate PID SS from data, do not use bayesian weights
587 // -------------------------------------------------------
589 if(fDebug > 0) printf("AliCaloPID::GetIdentifiedParticleType: EMCAL %d?, E %3.2f, l0 %3.2f, l1 %3.2f, disp %3.2f, tof %1.11f, distCPV %3.2f, distToBC %1.1f, NMax %d\n",
590 cluster->IsEMCAL(),energy,lambda0,cluster->GetM20(),cluster->GetDispersion(),cluster->GetTOF(),
591 cluster->GetEmcCpvDistance(), cluster->GetDistanceToBadChannel(),cluster->GetNExMax());
593 if(cluster->IsEMCAL())
595 if(fDebug > 0) printf("AliCaloPID::GetIdentifiedParticleType() - EMCAL SS %f <%f < %f?\n",fEMCALL0CutMin, lambda0, fEMCALL0CutMax);
597 if(lambda0 < fEMCALL0CutMax && lambda0 > fEMCALL0CutMin) return kPhoton ;
598 else return kNeutralUnknown ;
602 if(TestPHOSDispersion(energy,lambda0,lambda1) < fPHOSDispersionCut) return kPhoton;
603 else return kNeutralUnknown;
608 //_________________________________________________________________________________________________________
609 Int_t AliCaloPID::GetIdentifiedParticleTypeFromBayesWeights(Bool_t isEMCAL, Double_t * pid, Float_t energy)
611 //Return most probable identity of the particle after bayesian weights calculated in reconstruction
615 AliFatal("pid pointer not initialized!!!");
616 return kNeutralUnknown; // not needed, added to content coverity
619 Float_t wPh = fPHOSPhotonWeight ;
620 Float_t wPi0 = fPHOSPi0Weight ;
621 Float_t wE = fPHOSElectronWeight ;
622 Float_t wCh = fPHOSChargeWeight ;
623 Float_t wNe = fPHOSNeutralWeight ;
625 if(!isEMCAL && fPHOSWeightFormula){
626 wPh = GetPHOSPhotonWeightFormula()->Eval(energy) ;
627 wPi0 = GetPHOSPi0WeightFormula() ->Eval(energy);
631 wPh = fEMCALPhotonWeight ;
632 wPi0 = fEMCALPi0Weight ;
633 wE = fEMCALElectronWeight ;
634 wCh = fEMCALChargeWeight ;
635 wNe = fEMCALNeutralWeight ;
638 if(fDebug > 0) PrintClusterPIDWeights(pid);
640 Int_t pdg = kNeutralUnknown ;
641 Float_t chargedHadronWeight = pid[AliVCluster::kProton]+pid[AliVCluster::kKaon]+
642 pid[AliVCluster::kPion]+pid[AliVCluster::kMuon];
643 Float_t neutralHadronWeight = pid[AliVCluster::kNeutron]+pid[AliVCluster::kKaon0];
644 Float_t allChargedWeight = pid[AliVCluster::kElectron]+pid[AliVCluster::kEleCon]+ chargedHadronWeight;
645 Float_t allNeutralWeight = pid[AliVCluster::kPhoton]+pid[AliVCluster::kPi0]+ neutralHadronWeight;
647 //Select most probable ID
650 if(pid[AliVCluster::kPhoton] > wPh) pdg = kPhoton ;
651 else if(pid[AliVCluster::kPi0] > wPi0) pdg = kPi0 ;
652 else if(pid[AliVCluster::kElectron] > wE) pdg = kElectron ;
653 else if(pid[AliVCluster::kEleCon] > wE) pdg = kEleCon ;
654 else if(chargedHadronWeight > wCh) pdg = kChargedHadron ;
655 else if(neutralHadronWeight > wNe) pdg = kNeutralHadron ;
656 else if(allChargedWeight > allNeutralWeight)
657 pdg = kChargedUnknown ;
659 pdg = kNeutralUnknown ;
663 if(pid[AliVCluster::kPhoton] > wPh) pdg = kPhoton ;
664 else if(pid[AliVCluster::kElectron] > wE) pdg = kElectron ;
665 else if(pid[AliVCluster::kPhoton]+pid[AliVCluster::kElectron] > wPh) pdg = kPhoton ; //temporal sollution until track matching for electrons is considered
666 else if(pid[AliVCluster::kPi0] > wPi0) pdg = kPi0 ;
667 else if(chargedHadronWeight + neutralHadronWeight > wCh) pdg = kChargedHadron ;
668 else if(neutralHadronWeight + chargedHadronWeight > wNe) pdg = kNeutralHadron ;
669 else pdg = kNeutralUnknown ;
672 if(fDebug > 0)printf("AliCaloPID::GetIdentifiedParticleType:Final Pdg: %d, cluster energy %2.2f \n", pdg,energy);
678 //____________________________________________________________________________________________________________
679 Int_t AliCaloPID::GetIdentifiedParticleTypeFromClusterSplitting(AliVCluster* cluster,
680 AliVCaloCells* cells,
681 AliCalorimeterUtils * caloutils,
684 Double_t & mass, Double_t & angle,
685 TLorentzVector & l1, TLorentzVector & l2,
686 Int_t & absId1, Int_t & absId2,
687 Float_t & distbad1, Float_t & distbad2,
688 Bool_t & fidcut1, Bool_t & fidcut2 ) const
690 // Split the cluster in 2, do invariant mass, get the mass and decide
691 // if this is a photon, pi0, eta, ...
693 Float_t eClus = cluster->E();
694 Float_t m02 = cluster->GetM02();
695 const Int_t nc = cluster->GetNCells();
697 Float_t maxEList [nc];
702 //If too low number of cells, skip it
703 if ( nc < fSplitMinNCells) return kNeutralUnknown ;
705 if(fDebug > 0) printf("\t pass nCells cut\n");
707 // Get Number of local maxima
708 nMax = caloutils->GetNumberOfLocalMaxima(cluster, cells, absIdList, maxEList) ;
710 if(fDebug > 0) printf("AliCaloPID::GetIdentifiedParticleTypeFromClusterSplitting() - Cluster : E %1.1f, M02 %1.2f, NLM %d, N Cells %d\n",
713 //---------------------------------------------------------------------
714 // Get the 2 max indeces and do inv mass
715 //---------------------------------------------------------------------
717 TString calorimeter = "EMCAL";
718 if(cluster->IsPHOS()) calorimeter = "PHOS";
722 absId1 = absIdList[0];
723 absId2 = absIdList[1];
726 Float_t en1 = cells->GetCellAmplitude(absId1);
727 caloutils->RecalibrateCellAmplitude(en1,calorimeter,absId1);
728 Float_t en2 = cells->GetCellAmplitude(absId2);
729 caloutils->RecalibrateCellAmplitude(en2,calorimeter,absId2);
732 absId2 = absIdList[0];
733 absId1 = absIdList[1];
739 absId1 = absIdList[0];
741 //Find second highest energy cell
744 for(Int_t iDigit = 0 ; iDigit < cluster->GetNCells() ; iDigit++)
746 Int_t absId = cluster->GetCellsAbsId()[iDigit];
747 if( absId == absId1 ) continue ;
748 Float_t endig = cells->GetCellAmplitude(absId);
749 caloutils->RecalibrateCellAmplitude(endig,calorimeter,absId);
759 // loop on maxima, find 2 highest
763 for(Int_t iDigit = 0 ; iDigit < nMax ; iDigit++)
765 Float_t endig = maxEList[iDigit];
769 absId1 = absIdList[iDigit];
771 }// first maxima loop
775 for(Int_t iDigit = 0 ; iDigit < nMax ; iDigit++)
777 if(absIdList[iDigit]==absId1) continue;
778 Float_t endig = maxEList[iDigit];
782 absId2 = absIdList[iDigit];
784 }// second maxima loop
786 } // n local maxima > 2
788 if(absId2<0 || absId1<0)
790 if(fDebug > 0) printf("AliCaloPID::GetIdentifiedParticleTypeFromClusterSplitting() - Bad index for local maxima : N max %d, i1 %d, i2 %d, cluster E %2.2f, ncells %d, m02 %2.2f\n",
791 nMax,absId1,absId2,eClus,nc,m02);
792 return kNeutralUnknown ;
795 //---------------------------------------------------------------------
796 // Split the cluster energy in 2, around the highest 2 local maxima
797 //---------------------------------------------------------------------
799 AliAODCaloCluster cluster1(0, 0,NULL,0.,NULL,NULL,1,0);
800 AliAODCaloCluster cluster2(1, 0,NULL,0.,NULL,NULL,1,0);
802 caloutils->SplitEnergy(absId1,absId2,cluster, cells, &cluster1, &cluster2,nMax); /*absIdList, maxEList,*/
804 fidcut1 = caloutils->GetEMCALRecoUtils()->CheckCellFiducialRegion(caloutils->GetEMCALGeometry(), &cluster1,cells);
805 fidcut2 = caloutils->GetEMCALRecoUtils()->CheckCellFiducialRegion(caloutils->GetEMCALGeometry(), &cluster2,cells);
807 caloutils->GetEMCALRecoUtils()->RecalculateClusterDistanceToBadChannel(caloutils->GetEMCALGeometry(),cells,&cluster1);
808 caloutils->GetEMCALRecoUtils()->RecalculateClusterDistanceToBadChannel(caloutils->GetEMCALGeometry(),cells,&cluster2);
810 distbad1 = cluster1.GetDistanceToBadChannel();
811 distbad2 = cluster2.GetDistanceToBadChannel();
812 // if(!fidcut2 || !fidcut1 || distbad1 < 2 || distbad2 < 2)
813 // printf("*** Dist to bad channel cl %f, cl1 %f, cl2 %f; fid cut cl %d, cl1 %d, cl2 %d \n",
814 // cluster->GetDistanceToBadChannel(),distbad1,distbad2,
815 // caloutils->GetEMCALRecoUtils()->CheckCellFiducialRegion(caloutils->GetEMCALGeometry(), cluster,cells),fidcut1,fidcut2);
817 cluster1.GetMomentum(l1,vertex);
818 cluster2.GetMomentum(l2,vertex);
821 angle = l2.Angle(l1.Vect());
822 Float_t e1 = cluster1.E();
823 Float_t e2 = cluster2.E();
825 // Consider clusters with splitted energy not too different to original cluster energy
826 Float_t splitFracCut = 0;
827 if(nMax < 3) splitFracCut = fSplitEFracMin[nMax-1];
828 else splitFracCut = fSplitEFracMin[2];
829 if((e1+e2)/eClus < splitFracCut) return kNeutralUnknown ;
831 if(fDebug > 0) printf("\t pass Split E frac cut\n");
833 // Consider sub-clusters with minimum energy
834 Float_t minECut = fSubClusterEMin[2];
835 if (nMax == 2) minECut = fSubClusterEMin[1];
836 else if(nMax == 1) minECut = fSubClusterEMin[0];
837 if(e1 < minECut || e2 < minECut)
839 //printf("Reject: e1 %2.1f, e2 %2.1f, cut %2.1f\n",e1,e2,minECut);
840 return kNeutralUnknown ;
843 if(fDebug > 0) printf("\t pass min sub-cluster E cut\n");
845 // Asymmetry of cluster
847 if(e1+e2 > 0) asy = (e1-e2) / (e1+e2);
849 if( !IsInPi0SplitAsymmetryRange(eClus,asy,nMax) ) return kNeutralUnknown ;
852 if (fDebug>0) printf("\t pass asymmetry cut\n");
854 Bool_t pi0OK = kFALSE;
855 Bool_t etaOK = kFALSE;
856 Bool_t conOK = kFALSE;
858 //If too small or big M02, skip it
859 if (IsInPi0M02Range(eClus,m02,nMax)) pi0OK = kTRUE;
860 else if(IsInEtaM02Range(eClus,m02,nMax)) etaOK = kTRUE;
861 else if(IsInConM02Range(eClus,m02,nMax)) conOK = kTRUE;
863 Float_t energy = eClus;
864 if(nMax > 2) energy = e1+e2; // In case of NLM>2 use mass cut for NLM=2 but for the split sum not the cluster energy that is not the pi0 E.
866 // Check the mass, and set an ID to the splitted cluster
867 if ( conOK && mass < fMassPhoMax && mass > fMassPhoMin ) { if(fDebug > 0) printf("\t Split Conv \n"); return kPhoton ; }
868 else if( etaOK && mass < fMassEtaMax && mass > fMassEtaMin ) { if(fDebug > 0) printf("\t Split Eta \n"); return kEta ; }
869 else if( pi0OK && IsInPi0SplitMassRange(energy,mass,nMax) ) { if(fDebug > 0) printf("\t Split Pi0 \n"); return kPi0 ; }
870 else return kNeutralUnknown ;
874 //_________________________________________
875 TString AliCaloPID::GetPIDParametersList()
877 //Put data member values in string to keep in output container
879 TString parList ; //this will be list of parameters used for this analysis.
880 const Int_t buffersize = 255;
881 char onePar[buffersize] ;
882 snprintf(onePar,buffersize,"--- AliCaloPID ---\n") ;
884 if(fUseBayesianWeights)
886 snprintf(onePar,buffersize,"fEMCALPhotonWeight =%2.2f (EMCAL bayesian weight for photons)\n",fEMCALPhotonWeight) ;
888 snprintf(onePar,buffersize,"fEMCALPi0Weight =%2.2f (EMCAL bayesian weight for pi0)\n",fEMCALPi0Weight) ;
890 snprintf(onePar,buffersize,"fEMCALElectronWeight =%2.2f(EMCAL bayesian weight for electrons)\n",fEMCALElectronWeight) ;
892 snprintf(onePar,buffersize,"fEMCALChargeWeight =%2.2f (EMCAL bayesian weight for charged hadrons)\n",fEMCALChargeWeight) ;
894 snprintf(onePar,buffersize,"fEMCALNeutralWeight =%2.2f (EMCAL bayesian weight for neutral hadrons)\n",fEMCALNeutralWeight) ;
896 snprintf(onePar,buffersize,"fPHOSPhotonWeight =%2.2f (PHOS bayesian weight for photons)\n",fPHOSPhotonWeight) ;
898 snprintf(onePar,buffersize,"fPHOSPi0Weight =%2.2f (PHOS bayesian weight for pi0)\n",fPHOSPi0Weight) ;
900 snprintf(onePar,buffersize,"fPHOSElectronWeight =%2.2f(PHOS bayesian weight for electrons)\n",fPHOSElectronWeight) ;
902 snprintf(onePar,buffersize,"fPHOSChargeWeight =%2.2f (PHOS bayesian weight for charged hadrons)\n",fPHOSChargeWeight) ;
904 snprintf(onePar,buffersize,"fPHOSNeutralWeight =%2.2f (PHOS bayesian weight for neutral hadrons)\n",fPHOSNeutralWeight) ;
907 if(fPHOSWeightFormula)
909 snprintf(onePar,buffersize,"PHOS Photon Weight Formula: %s\n",fPHOSPhotonWeightFormulaExpression.Data() ) ;
911 snprintf(onePar,buffersize,"PHOS Pi0 Weight Formula: %s\n",fPHOSPi0WeightFormulaExpression.Data() ) ;
917 snprintf(onePar,buffersize,"EMCAL: fEMCALL0CutMin =%2.2f, fEMCALL0CutMax =%2.2f (Cut on Shower Shape) \n",fEMCALL0CutMin, fEMCALL0CutMax) ;
919 snprintf(onePar,buffersize,"EMCAL: fEMCALDEtaCut =%2.2f, fEMCALDPhiCut =%2.2f (Cut on track matching) \n",fEMCALDEtaCut, fEMCALDPhiCut) ;
921 snprintf(onePar,buffersize,"fTOFCut =%e (Cut on TOF, used in PID evaluation) \n",fTOFCut) ;
923 snprintf(onePar,buffersize,"fPHOSRCut =%2.2f, fPHOSDispersionCut =%2.2f (Cut on Shower Shape and CPV) \n",fPHOSRCut,fPHOSDispersionCut) ;
930 snprintf(onePar,buffersize,"%2.2f< M02 < %2.2f \n", fSplitM02MinCut, fSplitM02MaxCut) ;
933 snprintf(onePar,buffersize,"fMinNCells =%d \n", fSplitMinNCells) ;
935 if(fUseSimpleMassCut)
937 snprintf(onePar,buffersize,"pi0 : %2.1f < m <%2.1f\n", fMassPi0Min,fMassPi0Max);
940 snprintf(onePar,buffersize,"eta : %2.1f < m <%2.1f\n", fMassEtaMin,fMassEtaMax);
942 snprintf(onePar,buffersize,"conv: %2.1f < m <%2.1f\n", fMassPhoMin,fMassPhoMax);
950 //________________________________________________
951 void AliCaloPID::Print(const Option_t * opt) const
954 //Print some relevant parameters set for the analysis
958 printf("***** Print: %s %s ******\n", GetName(), GetTitle() ) ;
960 if(fUseBayesianWeights)
962 printf("PHOS PID weight , photon %0.2f, pi0 %0.2f, e %0.2f, charge %0.2f, neutral %0.2f \n",
963 fPHOSPhotonWeight, fPHOSPi0Weight,
964 fPHOSElectronWeight, fPHOSChargeWeight, fPHOSNeutralWeight) ;
965 printf("EMCAL PID weight, photon %0.2f, pi0 %0.2f, e %0.2f, charge %0.2f, neutral %0.2f\n",
966 fEMCALPhotonWeight, fEMCALPi0Weight,
967 fEMCALElectronWeight, fEMCALChargeWeight, fEMCALNeutralWeight) ;
969 printf("PHOS Parametrized weight on? = %d\n", fPHOSWeightFormula) ;
970 if(fPHOSWeightFormula)
972 printf("Photon weight formula = %s\n", fPHOSPhotonWeightFormulaExpression.Data());
973 printf("Pi0 weight formula = %s\n", fPHOSPi0WeightFormulaExpression .Data());
975 if(fRecalculateBayesian) printf(" Recalculate bayesian with Particle Flux? = %d\n",fParticleFlux);
979 printf("TOF cut = %e\n", fTOFCut);
980 printf("EMCAL Lambda0 cut min = %2.2f; max = %2.2f\n", fEMCALL0CutMin,fEMCALL0CutMax);
981 printf("EMCAL cluster-track dEta < %2.3f; dPhi < %2.3f\n", fEMCALDEtaCut, fEMCALDPhiCut);
982 printf("PHOS Treac matching cut =%2.2f, Dispersion Cut =%2.2f \n",fPHOSRCut, fPHOSDispersionCut) ;
986 printf("Min. N Cells =%d \n", fSplitMinNCells) ;
987 if(fUseSimpleM02Cut) printf("%2.2f < lambda_0^2 <%2.2f \n",fSplitM02MinCut,fSplitM02MaxCut);
988 if(fUseSimpleMassCut)printf("pi0 : %2.2f<m<%2.2f \n", fMassPi0Min,fMassPi0Max);
989 printf("eta : %2.2f<m<%2.2f \n", fMassEtaMin,fMassEtaMax);
990 printf("phot: %2.2f<m<%2.2f \n", fMassPhoMin,fMassPhoMax);
996 //_________________________________________________________________
997 void AliCaloPID::PrintClusterPIDWeights(const Double_t * pid) const
999 // print PID of cluster, (AliVCluster*)cluster->GetPID()
1001 printf("AliCaloPID::PrintClusterPIDWeights() \n \t ph %0.2f, pi0 %0.2f, el %0.2f, conv el %0.2f, \n \t \
1002 pion %0.2f, kaon %0.2f, proton %0.2f , neutron %0.2f, kaon %0.2f \n",
1003 pid[AliVCluster::kPhoton], pid[AliVCluster::kPi0],
1004 pid[AliVCluster::kElectron], pid[AliVCluster::kEleCon],
1005 pid[AliVCluster::kPion], pid[AliVCluster::kKaon],
1006 pid[AliVCluster::kProton],
1007 pid[AliVCluster::kNeutron], pid[AliVCluster::kKaon0]);
1011 //___________________________________________________________________________
1012 void AliCaloPID::SetPIDBits(AliVCluster * cluster,
1013 AliAODPWG4Particle * ph, AliCalorimeterUtils* cu,
1016 //Set Bits for PID selection
1018 //Dispersion/lambdas
1019 //Double_t disp= cluster->GetDispersion() ;
1020 Double_t l1 = cluster->GetM20() ;
1021 Double_t l0 = cluster->GetM02() ;
1022 Bool_t isDispOK = kTRUE ;
1023 if(cluster->IsPHOS()){
1024 if(TestPHOSDispersion(ph->Pt(),l0,l1) < fPHOSDispersionCut) isDispOK = kTRUE;
1025 else isDispOK = kFALSE;
1029 if(l0 > fEMCALL0CutMin && l0 < fEMCALL0CutMax) isDispOK = kTRUE;
1033 ph->SetDispBit(isDispOK) ;
1036 Double_t tof=cluster->GetTOF() ;
1037 ph->SetTOFBit(TMath::Abs(tof)<fTOFCut) ;
1040 Bool_t isNeutral = IsTrackMatched(cluster,cu,event);
1042 ph->SetChargedBit(isNeutral);
1045 ph->SetIdentifiedParticleType(GetIdentifiedParticleType(cluster));
1049 printf("AliCaloPID::SetPIDBits: TOF %e, Lambda0 %2.2f, Lambda1 %2.2f\n",tof , l0, l1);
1050 printf("AliCaloPID::SetPIDBits: pdg %d, bits: TOF %d, Dispersion %d, Charge %d\n",
1051 ph->GetIdentifiedParticleType(), ph->GetTOFBit() , ph->GetDispBit() , ph->GetChargedBit());
1055 //_________________________________________________________
1056 Bool_t AliCaloPID::IsTrackMatched(AliVCluster* cluster,
1057 AliCalorimeterUtils * cu,
1058 AliVEvent* event) const
1060 //Check if there is any track attached to this cluster
1062 Int_t nMatches = cluster->GetNTracksMatched();
1063 AliVTrack * track = 0;
1068 //In case of ESDs, by default without match one entry with negative index, no match, reject.
1069 if(!strcmp("AliESDCaloCluster",Form("%s",cluster->ClassName())))
1071 Int_t iESDtrack = cluster->GetTrackMatchedIndex();
1072 if(iESDtrack >= 0) track = dynamic_cast<AliVTrack*> (event->GetTrack(iESDtrack));
1077 if(fDebug > 0) printf("AliCaloPID::IsTrackMatched() - Null matched track in ESD when index is OK!\n");
1082 track = dynamic_cast<AliVTrack*> (cluster->GetTrackMatched(0));
1085 if(fDebug > 0) printf("AliCaloPID::IsTrackMatched() - Null matched track in AOD!\n");
1090 Float_t dZ = cluster->GetTrackDz();
1091 Float_t dR = cluster->GetTrackDx();
1093 // if track matching was recalculated
1094 if(cluster->IsEMCAL() && cu && cu->IsRecalculationOfClusterTrackMatchingOn())
1096 dR = 2000., dZ = 2000.;
1097 cu->GetEMCALRecoUtils()->GetMatchedResiduals(cluster->GetID(),dZ,dR);
1100 if(cluster->IsPHOS())
1102 track->GetPxPyPz(p) ;
1103 TLorentzVector trackmom(p[0],p[1],p[2],0);
1104 Int_t charge = track->Charge();
1105 Double_t mf = event->GetMagneticField();
1106 if(TestPHOSChargedVeto(dR, dZ, trackmom.Pt(), charge, mf ) < fPHOSRCut) return kTRUE;
1113 printf("AliCaloPID::IsTrackMatched - EMCAL dR %f < %f, dZ %f < %f \n",dR, fEMCALDPhiCut, dZ, fEMCALDEtaCut);
1115 if(TMath::Abs(dR) < fEMCALDPhiCut &&
1116 TMath::Abs(dZ) < fEMCALDEtaCut) return kTRUE;
1122 } // more than 1 match, at least one track in array
1127 //___________________________________________________________________________________________________
1128 Float_t AliCaloPID::TestPHOSDispersion(const Double_t pt, const Double_t l1, const Double_t l2) const
1130 //Check if cluster photon-like. Uses photon cluster parameterization in real pp data
1131 //Returns distance in sigmas. Recommended cut 2.5
1133 Double_t l2Mean = 1.53126+9.50835e+06/(1.+1.08728e+07*pt+1.73420e+06*pt*pt) ;
1134 Double_t l1Mean = 1.12365+0.123770*TMath::Exp(-pt*0.246551)+5.30000e-03*pt ;
1135 Double_t l2Sigma = 6.48260e-02+7.60261e+10/(1.+1.53012e+11*pt+5.01265e+05*pt*pt)+9.00000e-03*pt;
1136 Double_t l1Sigma = 4.44719e-04+6.99839e-01/(1.+1.22497e+00*pt+6.78604e-07*pt*pt)+9.00000e-03*pt;
1137 Double_t c =-0.35-0.550*TMath::Exp(-0.390730*pt) ;
1138 Double_t r2 = 0.5* (l1-l1Mean)*(l1-l1Mean)/l1Sigma/l1Sigma +
1139 0.5* (l2-l2Mean)*(l2-l2Mean)/l2Sigma/l2Sigma +
1140 0.5*c*(l1-l1Mean)*(l2-l2Mean)/l1Sigma/l2Sigma ;
1142 if(fDebug > 0) printf("AliCaloPID::TestPHOSDispersion() - PHOS SS R %f < %f?\n", TMath::Sqrt(r2), fPHOSDispersionCut);
1144 return TMath::Sqrt(r2) ;
1148 //_______________________________________________________________________________________________
1149 Float_t AliCaloPID::TestPHOSChargedVeto(const Double_t dx, const Double_t dz, const Double_t pt,
1150 const Int_t charge, const Double_t mf) const
1152 //Checks distance to the closest track. Takes into account
1153 //non-perpendicular incidence of tracks.
1154 //returns distance in sigmas. Recommended cut: 2.
1155 //Requires (sign) of magnetic filed. onc can find it for example as following
1157 // AliESDEvent *event = dynamic_cast<AliESDEvent*>(InputEvent());
1159 // mf = event->GetMagneticField(); //Positive for ++ and negative for --
1162 Double_t meanX = 0.;
1163 Double_t meanZ = 0.;
1164 Double_t sx = TMath::Min(5.4,2.59719e+02*TMath::Exp(-pt/1.02053e-01)+
1165 6.58365e-01*5.91917e-01*5.91917e-01/((pt-9.61306e-01)*(pt-9.61306e-01)+5.91917e-01*5.91917e-01)+
1167 Double_t sz = TMath::Min(2.75,4.90341e+02*1.91456e-02*1.91456e-02/(pt*pt+1.91456e-02*1.91456e-02)+
1170 if(mf<0.){ //field --
1173 meanX = TMath::Min(7.3, 3.89994*1.20679 *1.20679 /(pt*pt+1.20679*1.20679)+
1174 0.249029+2.49088e+07*TMath::Exp(-pt*3.33650e+01)) ;
1176 meanX =-TMath::Min(7.7, 3.86040*0.912499*0.912499/(pt*pt+0.912499*0.912499)+
1177 1.23114 +4.48277e+05*TMath::Exp(-pt*2.57070e+01)) ;
1182 meanX =-TMath::Min(8.0,3.86040*1.31357*1.31357/(pt*pt+1.31357*1.31357)+
1183 0.880579+7.56199e+06*TMath::Exp(-pt*3.08451e+01)) ;
1185 meanX = TMath::Min(6.85, 3.89994*1.16240*1.16240/(pt*pt+1.16240*1.16240)-
1186 0.120787+2.20275e+05*TMath::Exp(-pt*2.40913e+01)) ;
1189 Double_t rz = (dz-meanZ)/sz ;
1190 Double_t rx = (dx-meanX)/sx ;
1193 printf("AliCaloPID::TestPHOSDispersion() - PHOS Matching R %f < %f\n",TMath::Sqrt(rx*rx+rz*rz), fPHOSRCut);
1195 return TMath::Sqrt(rx*rx+rz*rz) ;