]> git.uio.no Git - u/mrichter/AliRoot.git/blame - PWG/CaloTrackCorrBase/AliCaloPID.cxx
Avoid names that only differ in use of capital/small letters
[u/mrichter/AliRoot.git] / PWG / CaloTrackCorrBase / AliCaloPID.cxx
CommitLineData
1c5acb87 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 **************************************************************************/
1c5acb87 15
16//_________________________________________________________________________
bdd2a262 17// Class for PID selection with calorimeters
49b5c49b 18// The Output of the main method GetIdentifiedParticleType is a PDG number identifying the cluster,
bdd2a262 19// being kPhoton, kElectron, kPi0 ... as defined in the header file
3c1d9afb 20// - GetIdentifiedParticleType(const AliVCluster * cluster)
49b5c49b 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.
bdd2a262 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
26// AliCaloPID(flux)
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.
49b5c49b 30
3c1d9afb 31// - GetGetIdentifiedParticleTypeFromBayesian(const Double_t * pid, const Float_t energy)
49b5c49b 32// Reads the PID weights array of the ESDs and depending on its magnitude identifies the particle,
3c1d9afb 33// executed when bayesian is ON by GetIdentifiedParticleType(const AliVCluster * cluster)
49b5c49b 34// - SetPIDBits: Simple PID, depending on the thresholds fLOCut fTOFCut and even the
bdd2a262 35// result of the PID bayesian a different PID bit is set.
36//
49b5c49b 37// - IsTrackMatched(): Independent method that needs to be combined with GetIdentifiedParticleType to know if the cluster was matched
bdd2a262 38//
49b5c49b 39//*-- Author: Gustavo Conesa (INFN-LNF)
1c5acb87 40//////////////////////////////////////////////////////////////////////////////
41
42
43// --- ROOT system ---
44#include <TMath.h>
1c5acb87 45#include <TString.h>
f21fc003 46#include <TList.h>
1c5acb87 47
c5693f62 48// ---- ANALYSIS system ----
1c5acb87 49#include "AliCaloPID.h"
3c1d9afb 50#include "AliAODCaloCluster.h"
51#include "AliVCaloCells.h"
d39cba7e 52#include "AliVTrack.h"
1c5acb87 53#include "AliAODPWG4Particle.h"
f2ccb5b8 54#include "AliCalorimeterUtils.h"
49b5c49b 55#include "AliVEvent.h"
f2ccb5b8 56
c5693f62 57// ---- Detector ----
58#include "AliEMCALPIDUtils.h"
59
1c5acb87 60ClassImp(AliCaloPID)
61
62
49b5c49b 63//________________________
1c5acb87 64AliCaloPID::AliCaloPID() :
49b5c49b 65TObject(), fDebug(-1), fParticleFlux(kLow),
66//Bayesian
67fEMCALPIDUtils(), fUseBayesianWeights(kFALSE), fRecalculateBayesian(kFALSE),
a5fb4114 68fEMCALPhotonWeight(0.), fEMCALPi0Weight(0.),
69fEMCALElectronWeight(0.), fEMCALChargeWeight(0.), fEMCALNeutralWeight(0.),
70fPHOSPhotonWeight(0.), fPHOSPi0Weight(0.),
71fPHOSElectronWeight(0.), fPHOSChargeWeight(0.) , fPHOSNeutralWeight(0.),
72fPHOSWeightFormula(0), fPHOSPhotonWeightFormula(0), fPHOSPi0WeightFormula(0),
49b5c49b 73fPHOSPhotonWeightFormulaExpression(""),
74fPHOSPi0WeightFormulaExpression(""),
75//PID calculation
76fEMCALL0CutMax(100.), fEMCALL0CutMin(0),
77fEMCALDEtaCut(2000.), fEMCALDPhiCut(2000.),
78fTOFCut(0.),
3c1d9afb 79fPHOSDispersionCut(1000), fPHOSRCut(1000),
5a72d9af 80//Split
5a72d9af 81fUseSimpleMassCut(kFALSE),
82fUseSimpleM02Cut(kFALSE),
667432ef 83fUseSplitAsyCut(kFALSE),
035e250e 84fUseSplitSSCut(kTRUE),
3c1d9afb 85fSplitM02MaxCut(0), fSplitM02MinCut(0), fSplitMinNCells(0),
86fMassEtaMin(0), fMassEtaMax(0),
87fMassPi0Min(0), fMassPi0Max(0),
5a72d9af 88fMassPhoMin(0), fMassPhoMax(0),
1be44524 89fM02MaxParamShiftNLMN(0),
ac207ee4 90fSplitWidthSigma(0), fMassShiftHighECell(0)
1c5acb87 91{
477d6cee 92 //Ctor
93
94 //Initialize parameters
95 InitParameters();
1c5acb87 96}
97
49b5c49b 98//________________________________________
8a2dbbff 99AliCaloPID::AliCaloPID(Int_t flux) :
49b5c49b 100TObject(), fDebug(-1), fParticleFlux(flux),
101//Bayesian
102fEMCALPIDUtils(), fUseBayesianWeights(kFALSE), fRecalculateBayesian(kFALSE),
a5fb4114 103fEMCALPhotonWeight(0.), fEMCALPi0Weight(0.),
104fEMCALElectronWeight(0.), fEMCALChargeWeight(0.), fEMCALNeutralWeight(0.),
105fPHOSPhotonWeight(0.), fPHOSPi0Weight(0.),
106fPHOSElectronWeight(0.), fPHOSChargeWeight(0.) , fPHOSNeutralWeight(0.),
107fPHOSWeightFormula(0), fPHOSPhotonWeightFormula(0), fPHOSPi0WeightFormula(0),
49b5c49b 108fPHOSPhotonWeightFormulaExpression(""),
109fPHOSPi0WeightFormulaExpression(""),
110//PID calculation
111fEMCALL0CutMax(100.), fEMCALL0CutMin(0),
112fEMCALDEtaCut(2000.), fEMCALDPhiCut(2000.),
113fTOFCut(0.),
3c1d9afb 114fPHOSDispersionCut(1000), fPHOSRCut(1000),
5a72d9af 115//Split
5a72d9af 116fUseSimpleMassCut(kFALSE),
117fUseSimpleM02Cut(kFALSE),
667432ef 118fUseSplitAsyCut(kFALSE),
035e250e 119fUseSplitSSCut(kTRUE),
3c1d9afb 120fSplitM02MaxCut(0), fSplitM02MinCut(0), fSplitMinNCells(0),
121fMassEtaMin(0), fMassEtaMax(0),
122fMassPi0Min(0), fMassPi0Max(0),
5a72d9af 123fMassPhoMin(0), fMassPhoMax(0),
10507906 124fM02MaxParamShiftNLMN(0),
ac207ee4 125fSplitWidthSigma(0), fMassShiftHighECell(0)
bdd2a262 126{
9a6fa057 127 //Ctor
bdd2a262 128
9a6fa057 129 //Initialize parameters
130 InitParameters();
49b5c49b 131
bdd2a262 132}
133
49b5c49b 134//_______________________________________________
f21fc003 135AliCaloPID::AliCaloPID(const TNamed * emcalpid) :
49b5c49b 136TObject(), fDebug(-1), fParticleFlux(kLow),
137//Bayesian
138fEMCALPIDUtils((AliEMCALPIDUtils*)emcalpid),
139fUseBayesianWeights(kFALSE), fRecalculateBayesian(kFALSE),
140fEMCALPhotonWeight(0.), fEMCALPi0Weight(0.),
141fEMCALElectronWeight(0.), fEMCALChargeWeight(0.), fEMCALNeutralWeight(0.),
142fPHOSPhotonWeight(0.), fPHOSPi0Weight(0.),
143fPHOSElectronWeight(0.), fPHOSChargeWeight(0.) , fPHOSNeutralWeight(0.),
144fPHOSWeightFormula(0), fPHOSPhotonWeightFormula(0), fPHOSPi0WeightFormula(0),
145fPHOSPhotonWeightFormulaExpression(""),
146fPHOSPi0WeightFormulaExpression(""),
147//PID calculation
148fEMCALL0CutMax(100.), fEMCALL0CutMin(0),
149fEMCALDEtaCut(2000.), fEMCALDPhiCut(2000.),
150fTOFCut(0.),
3c1d9afb 151fPHOSDispersionCut(1000), fPHOSRCut(1000),
5a72d9af 152//Split
5a72d9af 153fUseSimpleMassCut(kFALSE),
154fUseSimpleM02Cut(kFALSE),
667432ef 155fUseSplitAsyCut(kFALSE),
035e250e 156fUseSplitSSCut(kTRUE),
3c1d9afb 157fSplitM02MaxCut(0), fSplitM02MinCut(0), fSplitMinNCells(0),
158fMassEtaMin(0), fMassEtaMax(0),
159fMassPi0Min(0), fMassPi0Max(0),
5a72d9af 160fMassPhoMin(0), fMassPhoMax(0),
10507906 161fM02MaxParamShiftNLMN(0),
ac207ee4 162fSplitWidthSigma(0), fMassShiftHighECell(0)
5a72d9af 163
bdd2a262 164{
9a6fa057 165 //Ctor
49b5c49b 166
9a6fa057 167 //Initialize parameters
168 InitParameters();
bdd2a262 169}
170
49b5c49b 171//_______________________
172AliCaloPID::~AliCaloPID()
173{
477d6cee 174 //Dtor
175
a5fb4114 176 delete fPHOSPhotonWeightFormula ;
177 delete fPHOSPi0WeightFormula ;
178 delete fEMCALPIDUtils ;
49b5c49b 179
9a6fa057 180}
1c5acb87 181
49b5c49b 182//_______________________________
1c5acb87 183void AliCaloPID::InitParameters()
184{
477d6cee 185 //Initialize the parameters of the PID.
186
49b5c49b 187 // Bayesian
2007809d 188 fEMCALPhotonWeight = 0.6 ;
189 fEMCALPi0Weight = 0.6 ;
190 fEMCALElectronWeight = 0.6 ;
191 fEMCALChargeWeight = 0.6 ;
192 fEMCALNeutralWeight = 0.6 ;
477d6cee 193
2007809d 194 fPHOSPhotonWeight = 0.6 ;
195 fPHOSPi0Weight = 0.6 ;
196 fPHOSElectronWeight = 0.6 ;
197 fPHOSChargeWeight = 0.6 ;
198 fPHOSNeutralWeight = 0.6 ;
477d6cee 199
200 //Formula to set the PID weight threshold for photon or pi0
a5fb4114 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))" ;
204
bdd2a262 205 if(fRecalculateBayesian){
49b5c49b 206 if(fParticleFlux == kLow){
207 printf("AliCaloPID::Init() - SetLOWFluxParam\n");
208 fEMCALPIDUtils->SetLowFluxParam() ;
209 }
210 else if (fParticleFlux == kHigh){
211 printf("AliCaloPID::Init() - SetHIGHFluxParam\n");
212 fEMCALPIDUtils->SetHighFluxParam() ;
213 }
214 }
215
216 //PID recalculation, not bayesian
217
218 //EMCAL
219 fEMCALL0CutMax = 0.3 ;
220 fEMCALL0CutMin = 0.01;
221
222 fEMCALDPhiCut = 0.05; // Same cut as in AliEMCALRecoUtils
223 fEMCALDEtaCut = 0.025;// Same cut as in AliEMCALRecoUtils
224
225 // PHOS / EMCAL, not used
226 fTOFCut = 1.e-6;
227
228 //PHOS
229 fPHOSRCut = 2. ;
230 fPHOSDispersionCut = 2.5;
231
3c1d9afb 232 // Cluster splitting
233
5a72d9af 234 fSplitM02MinCut = 0.3 ;
235 fSplitM02MaxCut = 5 ;
236 fSplitMinNCells = 4 ;
3c1d9afb 237
238 fMassEtaMin = 0.4;
239 fMassEtaMax = 0.6;
240
5a72d9af 241 fMassPi0Min = 0.11;
242 fMassPi0Max = 0.18;
3c1d9afb 243
244 fMassPhoMin = 0.0;
5a72d9af 245 fMassPhoMax = 0.08;
246
1be44524 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
1e5d986c 250 fMassPi0Param[0][3] = 0.044 ; // constant term on mass dependence
251 fMassPi0Param[0][4] = 0.0049; // slope term on mass dependence
1be44524 252 fMassPi0Param[0][5] = 0.070 ; // Absolute low mass cut
253
1e5d986c 254 fMassPi0Param[1][0] = 0.115 ; // Constant term below 21 GeV
255 fMassPi0Param[1][1] = 0.00096; // slope term below 21 GeV
1be44524 256 fMassPi0Param[1][2] = 21 ; // E function change
1e5d986c 257 fMassPi0Param[1][3] = 0.10 ; // constant term on mass dependence
1be44524 258 fMassPi0Param[1][4] = 0.0017; // slope term on mass dependence
259 fMassPi0Param[1][5] = 0.070 ; // Absolute low mass cut
260
1e5d986c 261 fWidthPi0Param[0][0] = 0.012 ; // Constant term on width dependence
1be44524 262 fWidthPi0Param[0][1] = 0.0 ; // Slope term on width dependence
1e5d986c 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
1be44524 266 fWidthPi0Param[0][5] = 0.0 ; // xx term
267
1e5d986c 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
ac207ee4 274
275 fMassShiftHighECell = 0; // Shift of cuts in case of higher energy threshold in cells, 5 MeV when Ecell>150 MeV
276
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 ;
1be44524 283
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 ;
ac207ee4 289 fM02MinParam[1][4] = 0.0 ;
ac207ee4 290
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 ;
ac207ee4 297
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 ;
ac207ee4 304
1be44524 305 fM02MaxParamShiftNLMN = 0.75;
995c6150 306
1be44524 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
312
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
318
4d97a954 319 fSplitEFracMin[0] = 0.0 ; // 0.96
320 fSplitEFracMin[1] = 0.0 ; // 0.96
321 fSplitEFracMin[2] = 0.0 ; // 0.7
322
2c36e041 323 fSubClusterEMin[0] = 0.0; // 3 GeV
324 fSubClusterEMin[1] = 0.0; // 1 GeV
325 fSubClusterEMin[2] = 0.0; // 1 GeV
326
327
5b4c2f5b 328 fSplitWidthSigma = 3. ;
5a72d9af 329
330}
331
995c6150 332
8a2dbbff 333//_________________________________________________________________________________________
334Bool_t AliCaloPID::IsInPi0SplitAsymmetryRange(Float_t energy, Float_t asy, Int_t nlm) const
995c6150 335{
336 // Select the appropriate mass range for pi0 selection in splitting method
337 // No used yet in splitting ID decision
338
035e250e 339 if(!fUseSplitAsyCut) return kTRUE ;
340
995c6150 341 Float_t abasy = TMath::Abs(asy);
342
afc83530 343 Int_t inlm = nlm-1;
344 if(nlm > 2) inlm=1; // only 2 cases defined nlm=1 and nlm>=2
345
995c6150 346 // Get the parametrized min cut of asymmetry for NLM=2 up to 11 GeV
667432ef 347
1be44524 348 Float_t cut = fAsyMinParam[inlm][0] + fAsyMinParam[inlm][1]*energy + fAsyMinParam[inlm][2]/energy/energy/energy ;
ac207ee4 349
667432ef 350 // In any case and beyond validity energy range of the function,
351 // the parameter cannot be smaller than 1
1be44524 352 if( cut > fAsyMinParam[inlm][3] ) cut = fAsyMinParam[inlm][3];
995c6150 353
afc83530 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);
995c6150 356
357 if(abasy < cut) return kTRUE;
358 else return kFALSE;
359
360}
361
8a2dbbff 362//______________________________________________________________________________________
363Bool_t AliCaloPID::IsInPi0SplitMassRange(Float_t energy, Float_t mass, Int_t nlm) const
5a72d9af 364{
365 // Select the appropriate mass range for pi0 selection in splitting method
366
367 if(fUseSimpleMassCut)
368 {
369 if(mass < fMassPi0Max && mass > fMassPi0Min) return kTRUE;
370 else return kFALSE;
371 }
372
373 // Get the selected mean value as reference for the mass
ac207ee4 374 Int_t inlm = nlm-1;
375 if(nlm > 2) inlm=1; // only 2 cases defined nlm=1 and nlm>=2
04852512 376
1be44524 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];
ac207ee4 379
1e5d986c 380 // In case of higher energy cell cut than 50 MeV, smaller mean mass 0-5 MeV, not really necessary
ac207ee4 381 meanMass -= fMassShiftHighECell;
382
5a72d9af 383 // Get the parametrized width of the mass
384 Float_t width = 0.009;
1be44524 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];
389
5a72d9af 390 // Calculate the 2 sigma cut
391 Float_t minMass = meanMass-fSplitWidthSigma*width;
392 Float_t maxMass = meanMass+fSplitWidthSigma*width;
393
394 // In case of low energy, hard cut to avoid conversions
1be44524 395 if(energy < 10 && minMass < fMassPi0Param[inlm][5] ) minMass = fMassPi0Param[inlm][5];
5a72d9af 396
ac207ee4 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);
5a72d9af 399
400 if(mass < maxMass && mass > minMass) return kTRUE;
401 else return kFALSE;
5a72d9af 402
403}
404
1be44524 405//________________________________________________
8a2dbbff 406Bool_t AliCaloPID::IsInM02Range(Float_t m02) const
1be44524 407{
408 // Select the appropriate m02 range, fix cut, not E dependent
409
410 Float_t minCut = fSplitM02MinCut;
411 Float_t maxCut = fSplitM02MaxCut;
412
413 if(m02 < maxCut && m02 > minCut) return kTRUE;
414 else return kFALSE;
415
416}
417
8a2dbbff 418//_______________________________________________________________________________
419Bool_t AliCaloPID::IsInPi0M02Range(Float_t energy, Float_t m02, Int_t nlm) const
5a72d9af 420{
5b4c2f5b 421 // Select the appropriate m02 range in splitting method for pi0
5a72d9af 422
035e250e 423 if(!fUseSplitSSCut) return kTRUE ;
1be44524 424
425 //First check the absolute minimum and maximum
426 if(!IsInM02Range(m02)) return kFALSE ;
035e250e 427
1be44524 428 //If requested, check the E dependent cuts
429 else if(!fUseSimpleM02Cut)
5a72d9af 430 {
a5a3f703 431 Int_t inlm = nlm-1;
432 if(nlm > 2) inlm=1; // only 2 cases defined nlm=1 and nlm>=2
5b4c2f5b 433
1be44524 434 Float_t minCut = fSplitM02MinCut;
435 Float_t maxCut = fSplitM02MaxCut;
436
ac207ee4 437 //e^{a+bx} + c + dx + e/x
1be44524 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;
440
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;
443
667432ef 444 // In any case and beyond validity energy range of the function,
1be44524 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;
449
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);
451
452 if(m02 < maxCut && m02 > minCut) return kTRUE;
453 else return kFALSE;
454
5a72d9af 455 }
456
1be44524 457 else return kTRUE;
5a72d9af 458
49b5c49b 459}
460
5a72d9af 461
8a2dbbff 462//______________________________________________________________________________
463Bool_t AliCaloPID::IsInEtaM02Range(Float_t energy, Float_t m02, Int_t nlm) const
5b4c2f5b 464{
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)
467
035e250e 468 if(!fUseSplitSSCut) return kTRUE ;
469
1be44524 470 //First check the absolute minimum and maximum
471 if(!IsInM02Range(m02)) return kFALSE ;
5b4c2f5b 472
1be44524 473 //DO NOT USE, study parametrization
474
475 //If requested, check the E dependent cuts
476 else if(!fUseSimpleM02Cut)
5b4c2f5b 477 {
478 Int_t inlm = nlm-1;
479 if(nlm > 2) inlm=1; // only 2 cases defined nlm=1 and nlm>=2
480
1be44524 481 Float_t minCut = fSplitM02MinCut;
482 Float_t maxCut = fSplitM02MaxCut;
483
5b4c2f5b 484 Float_t shiftE = energy-20; // to be tuned
485 if(nlm==1) shiftE=energy-28;
486
ac207ee4 487 //e^{a+bx} + c + dx + e/x
1be44524 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;
490
491 // In any case the parameter cannot be smaller than 0.3
492 if( minCut < fSplitM02MinCut) minCut = fSplitM02MinCut;
5b4c2f5b 493
5b4c2f5b 494 shiftE = energy+20; // to be tuned
5b4c2f5b 495
1be44524 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;
498
499 // In any case the parameter cannot be smaller than 4-5
500 if( maxCut > fSplitM02MaxCut) maxCut = fSplitM02MaxCut;
501 if( nlm > 2 ) maxCut+=fM02MaxParamShiftNLMN;
502
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);
504
505 if(m02 < maxCut && m02 > minCut) return kTRUE;
506 else return kFALSE;
507
5b4c2f5b 508 }
509
1be44524 510 else return kTRUE;
5b4c2f5b 511
512}
513
8a2dbbff 514//______________________________________________________________________________
515Bool_t AliCaloPID::IsInConM02Range(Float_t energy, Float_t m02, Int_t nlm) const
5b4c2f5b 516{
517 // Select the appropriate m02 range in splitting method for converted photons
518 // Just min limit for pi0s is max for conversion.
519
035e250e 520 if(!fUseSplitSSCut) return kTRUE ;
521
5b4c2f5b 522 Float_t minCut = 0.1;
1be44524 523 Float_t maxCut = fSplitM02MinCut;
5b4c2f5b 524
525 if(!fUseSimpleM02Cut)
526 {
527 Int_t inlm = nlm-1;
528 if(nlm > 2) inlm=1; // only 2 cases defined nlm=1 and nlm>=2
529
ac207ee4 530 //e^{a+bx} + c + dx + e/x
1be44524 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;
5b4c2f5b 533
1be44524 534 if( maxCut < fSplitM02MinCut) maxCut = fSplitM02MinCut;
5b4c2f5b 535 }
536
5b4c2f5b 537 if(m02 < maxCut && m02 > minCut) return kTRUE;
538 else return kFALSE;
539
540}
541
c5693f62 542//______________________________________________
543AliEMCALPIDUtils *AliCaloPID::GetEMCALPIDUtils()
544{
545 // return pointer to AliEMCALPIDUtils, create it if needed
546
547 if(!fEMCALPIDUtils) fEMCALPIDUtils = new AliEMCALPIDUtils ;
548 return fEMCALPIDUtils ;
549
550}
551
552
8a2dbbff 553//________________________________________________________________
554Int_t AliCaloPID::GetIdentifiedParticleType(AliVCluster * cluster)
49b5c49b 555{
556 // Returns a PDG number corresponding to the likely ID of the cluster
557
3c1d9afb 558 Float_t energy = cluster->E();
49b5c49b 559 Float_t lambda0 = cluster->GetM02();
560 Float_t lambda1 = cluster->GetM20();
561
562 // ---------------------
563 // Use bayesian approach
564 // ---------------------
565
3c1d9afb 566 if(fUseBayesianWeights)
567 {
00a38d07 568 Double_t weights[AliPID::kSPECIESCN];
49b5c49b 569
3c1d9afb 570 if(cluster->IsEMCAL() && fRecalculateBayesian)
571 {
49b5c49b 572 fEMCALPIDUtils->ComputePID(energy, lambda0);
00a38d07 573 for(Int_t i = 0; i < AliPID::kSPECIESCN; i++) weights[i] = fEMCALPIDUtils->GetPIDFinal(i);
49b5c49b 574 }
3c1d9afb 575 else
576 {
00a38d07 577 for(Int_t i = 0; i < AliPID::kSPECIESCN; i++) weights[i] = cluster->GetPID()[i];
49b5c49b 578 }
579
3c1d9afb 580 if(fDebug > 0) PrintClusterPIDWeights(weights);
49b5c49b 581
3c1d9afb 582 return GetIdentifiedParticleTypeFromBayesWeights(cluster->IsEMCAL(), weights, energy);
bdd2a262 583 }
49b5c49b 584
585 // -------------------------------------------------------
586 // Calculate PID SS from data, do not use bayesian weights
587 // -------------------------------------------------------
588
3c1d9afb 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(),
49b5c49b 591 cluster->GetEmcCpvDistance(), cluster->GetDistanceToBadChannel(),cluster->GetNExMax());
592
3c1d9afb 593 if(cluster->IsEMCAL())
594 {
49b5c49b 595 if(fDebug > 0) printf("AliCaloPID::GetIdentifiedParticleType() - EMCAL SS %f <%f < %f?\n",fEMCALL0CutMin, lambda0, fEMCALL0CutMax);
596
597 if(lambda0 < fEMCALL0CutMax && lambda0 > fEMCALL0CutMin) return kPhoton ;
598 else return kNeutralUnknown ;
3c1d9afb 599 } // EMCAL
600 else // PHOS
601 {
602 if(TestPHOSDispersion(energy,lambda0,lambda1) < fPHOSDispersionCut) return kPhoton;
603 else return kNeutralUnknown;
49b5c49b 604 }
605
1c5acb87 606}
607
8a2dbbff 608//_________________________________________________________________________________________________________
609Int_t AliCaloPID::GetIdentifiedParticleTypeFromBayesWeights(Bool_t isEMCAL, Double_t * pid, Float_t energy)
49b5c49b 610{
611 //Return most probable identity of the particle after bayesian weights calculated in reconstruction
477d6cee 612
3c1d9afb 613 if(!pid)
614 {
b8bec44f 615 AliFatal("pid pointer not initialized!!!");
c31af35c 616 return kNeutralUnknown; // not needed, added to content coverity
477d6cee 617 }
618
15800db4 619 Float_t wPh = fPHOSPhotonWeight ;
477d6cee 620 Float_t wPi0 = fPHOSPi0Weight ;
15800db4 621 Float_t wE = fPHOSElectronWeight ;
622 Float_t wCh = fPHOSChargeWeight ;
623 Float_t wNe = fPHOSNeutralWeight ;
49b5c49b 624
3c1d9afb 625 if(!isEMCAL && fPHOSWeightFormula){
a5fb4114 626 wPh = GetPHOSPhotonWeightFormula()->Eval(energy) ;
627 wPi0 = GetPHOSPi0WeightFormula() ->Eval(energy);
628 }
3c1d9afb 629 else
630 {
477d6cee 631 wPh = fEMCALPhotonWeight ;
632 wPi0 = fEMCALPi0Weight ;
633 wE = fEMCALElectronWeight ;
634 wCh = fEMCALChargeWeight ;
635 wNe = fEMCALNeutralWeight ;
477d6cee 636 }
637
3c1d9afb 638 if(fDebug > 0) PrintClusterPIDWeights(pid);
639
477d6cee 640 Int_t pdg = kNeutralUnknown ;
c8fe2783 641 Float_t chargedHadronWeight = pid[AliVCluster::kProton]+pid[AliVCluster::kKaon]+
49b5c49b 642 pid[AliVCluster::kPion]+pid[AliVCluster::kMuon];
c8fe2783 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;
477d6cee 646
647 //Select most probable ID
3c1d9afb 648 if(!isEMCAL) // PHOS
649 {
a5fb4114 650 if(pid[AliVCluster::kPhoton] > wPh) pdg = kPhoton ;
651 else if(pid[AliVCluster::kPi0] > wPi0) pdg = kPi0 ;
c8fe2783 652 else if(pid[AliVCluster::kElectron] > wE) pdg = kElectron ;
a5fb4114 653 else if(pid[AliVCluster::kEleCon] > wE) pdg = kEleCon ;
654 else if(chargedHadronWeight > wCh) pdg = kChargedHadron ;
655 else if(neutralHadronWeight > wNe) pdg = kNeutralHadron ;
477d6cee 656 else if(allChargedWeight > allNeutralWeight)
657 pdg = kChargedUnknown ;
658 else
659 pdg = kNeutralUnknown ;
660 }
3c1d9afb 661 else //EMCAL
662 {
2007809d 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 ;
477d6cee 667 else if(chargedHadronWeight + neutralHadronWeight > wCh) pdg = kChargedHadron ;
668 else if(neutralHadronWeight + chargedHadronWeight > wNe) pdg = kNeutralHadron ;
2007809d 669 else pdg = kNeutralUnknown ;
477d6cee 670 }
671
21a4b1c0 672 if(fDebug > 0)printf("AliCaloPID::GetIdentifiedParticleType:Final Pdg: %d, cluster energy %2.2f \n", pdg,energy);
1c5acb87 673
49b5c49b 674 return pdg ;
9a6fa057 675
1c5acb87 676}
677
8a2dbbff 678//____________________________________________________________________________________________________________
3c1d9afb 679Int_t AliCaloPID::GetIdentifiedParticleTypeFromClusterSplitting(AliVCluster* cluster,
680 AliVCaloCells* cells,
681 AliCalorimeterUtils * caloutils,
682 Double_t vertex[3],
683 Int_t & nMax,
19391b8c 684 Double_t & mass, Double_t & angle,
cfdf2b91 685 TLorentzVector & l1, TLorentzVector & l2,
4914e781 686 Int_t & absId1, Int_t & absId2,
687 Float_t & distbad1, Float_t & distbad2,
8a2dbbff 688 Bool_t & fidcut1, Bool_t & fidcut2 ) const
3c1d9afb 689{
690 // Split the cluster in 2, do invariant mass, get the mass and decide
691 // if this is a photon, pi0, eta, ...
692
5a72d9af 693 Float_t eClus = cluster->E();
694 Float_t m02 = cluster->GetM02();
2bf17171 695 const Int_t nc = cluster->GetNCells();
696 Int_t absIdList[nc];
4d97a954 697 Float_t maxEList [nc];
3c1d9afb 698
3c1d9afb 699 mass = -1.;
700 angle = -1.;
667432ef 701
cf7e2ca9 702 //If too low number of cells, skip it
703 if ( nc < fSplitMinNCells) return kNeutralUnknown ;
704
705 if(fDebug > 0) printf("\t pass nCells cut\n");
706
3c1d9afb 707 // Get Number of local maxima
5a72d9af 708 nMax = caloutils->GetNumberOfLocalMaxima(cluster, cells, absIdList, maxEList) ;
3c1d9afb 709
5a72d9af 710 if(fDebug > 0) printf("AliCaloPID::GetIdentifiedParticleTypeFromClusterSplitting() - Cluster : E %1.1f, M02 %1.2f, NLM %d, N Cells %d\n",
711 eClus,m02,nMax,nc);
712
3c1d9afb 713 //---------------------------------------------------------------------
714 // Get the 2 max indeces and do inv mass
715 //---------------------------------------------------------------------
716
19391b8c 717 TString calorimeter = "EMCAL";
718 if(cluster->IsPHOS()) calorimeter = "PHOS";
719
720 if ( nMax == 2 )
3c1d9afb 721 {
722 absId1 = absIdList[0];
723 absId2 = absIdList[1];
19391b8c 724
725 //Order in energy
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);
730 if(en1 < en2)
731 {
732 absId2 = absIdList[0];
733 absId1 = absIdList[1];
734 }
3c1d9afb 735 }
736 else if( nMax == 1 )
737 {
738
739 absId1 = absIdList[0];
740
741 //Find second highest energy cell
742
3c1d9afb 743 Float_t enmax = 0 ;
744 for(Int_t iDigit = 0 ; iDigit < cluster->GetNCells() ; iDigit++)
745 {
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);
750 if(endig > enmax)
751 {
752 enmax = endig ;
753 absId2 = absId ;
754 }
755 }// cell loop
756 }// 1 maxima
757 else
758 { // n max > 2
759 // loop on maxima, find 2 highest
760
761 // First max
762 Float_t enmax = 0 ;
763 for(Int_t iDigit = 0 ; iDigit < nMax ; iDigit++)
764 {
765 Float_t endig = maxEList[iDigit];
766 if(endig > enmax)
767 {
768 enmax = endig ;
769 absId1 = absIdList[iDigit];
770 }
771 }// first maxima loop
772
773 // Second max
774 Float_t enmax2 = 0;
775 for(Int_t iDigit = 0 ; iDigit < nMax ; iDigit++)
776 {
777 if(absIdList[iDigit]==absId1) continue;
778 Float_t endig = maxEList[iDigit];
779 if(endig > enmax2)
780 {
781 enmax2 = endig ;
782 absId2 = absIdList[iDigit];
783 }
784 }// second maxima loop
785
786 } // n local maxima > 2
787
cf7e2ca9 788 if(absId2<0 || absId1<0)
789 {
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 ;
793 }
794
3c1d9afb 795 //---------------------------------------------------------------------
796 // Split the cluster energy in 2, around the highest 2 local maxima
797 //---------------------------------------------------------------------
798
2bf17171 799 AliAODCaloCluster cluster1(0, 0,NULL,0.,NULL,NULL,1,0);
800 AliAODCaloCluster cluster2(1, 0,NULL,0.,NULL,NULL,1,0);
3c1d9afb 801
2bf17171 802 caloutils->SplitEnergy(absId1,absId2,cluster, cells, &cluster1, &cluster2,nMax); /*absIdList, maxEList,*/
3c1d9afb 803
4914e781 804 fidcut1 = caloutils->GetEMCALRecoUtils()->CheckCellFiducialRegion(caloutils->GetEMCALGeometry(), &cluster1,cells);
805 fidcut2 = caloutils->GetEMCALRecoUtils()->CheckCellFiducialRegion(caloutils->GetEMCALGeometry(), &cluster2,cells);
806
807 caloutils->GetEMCALRecoUtils()->RecalculateClusterDistanceToBadChannel(caloutils->GetEMCALGeometry(),cells,&cluster1);
808 caloutils->GetEMCALRecoUtils()->RecalculateClusterDistanceToBadChannel(caloutils->GetEMCALGeometry(),cells,&cluster2);
809
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);
816
cfdf2b91 817 cluster1.GetMomentum(l1,vertex);
818 cluster2.GetMomentum(l2,vertex);
3c1d9afb 819
cfdf2b91 820 mass = (l1+l2).M();
821 angle = l2.Angle(l1.Vect());
822 Float_t e1 = cluster1.E();
823 Float_t e2 = cluster2.E();
4914e781 824
5a72d9af 825 // Consider clusters with splitted energy not too different to original cluster energy
4d97a954 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 ;
2c36e041 830
5a72d9af 831 if(fDebug > 0) printf("\t pass Split E frac cut\n");
2c36e041 832
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)
838 {
839 //printf("Reject: e1 %2.1f, e2 %2.1f, cut %2.1f\n",e1,e2,minECut);
840 return kNeutralUnknown ;
841 }
842
843 if(fDebug > 0) printf("\t pass min sub-cluster E cut\n");
844
667432ef 845 // Asymmetry of cluster
846 Float_t asy =-10;
847 if(e1+e2 > 0) asy = (e1-e2) / (e1+e2);
1be44524 848
035e250e 849 if( !IsInPi0SplitAsymmetryRange(eClus,asy,nMax) ) return kNeutralUnknown ;
667432ef 850
1be44524 851
667432ef 852 if (fDebug>0) printf("\t pass asymmetry cut\n");
5b4c2f5b 853
854 Bool_t pi0OK = kFALSE;
855 Bool_t etaOK = kFALSE;
856 Bool_t conOK = kFALSE;
857
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;
862
1e5d986c 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.
865
5a72d9af 866 // Check the mass, and set an ID to the splitted cluster
745a2967 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 ;
3c1d9afb 871
3c1d9afb 872}
873
49b5c49b 874//_________________________________________
875TString AliCaloPID::GetPIDParametersList()
876{
477d6cee 877 //Put data member values in string to keep in output container
878
879 TString parList ; //this will be list of parameters used for this analysis.
5ae09196 880 const Int_t buffersize = 255;
881 char onePar[buffersize] ;
882 snprintf(onePar,buffersize,"--- AliCaloPID ---\n") ;
477d6cee 883 parList+=onePar ;
745a2967 884 if(fUseBayesianWeights)
885 {
49b5c49b 886 snprintf(onePar,buffersize,"fEMCALPhotonWeight =%2.2f (EMCAL bayesian weight for photons)\n",fEMCALPhotonWeight) ;
887 parList+=onePar ;
888 snprintf(onePar,buffersize,"fEMCALPi0Weight =%2.2f (EMCAL bayesian weight for pi0)\n",fEMCALPi0Weight) ;
889 parList+=onePar ;
890 snprintf(onePar,buffersize,"fEMCALElectronWeight =%2.2f(EMCAL bayesian weight for electrons)\n",fEMCALElectronWeight) ;
891 parList+=onePar ;
892 snprintf(onePar,buffersize,"fEMCALChargeWeight =%2.2f (EMCAL bayesian weight for charged hadrons)\n",fEMCALChargeWeight) ;
893 parList+=onePar ;
894 snprintf(onePar,buffersize,"fEMCALNeutralWeight =%2.2f (EMCAL bayesian weight for neutral hadrons)\n",fEMCALNeutralWeight) ;
895 parList+=onePar ;
896 snprintf(onePar,buffersize,"fPHOSPhotonWeight =%2.2f (PHOS bayesian weight for photons)\n",fPHOSPhotonWeight) ;
897 parList+=onePar ;
898 snprintf(onePar,buffersize,"fPHOSPi0Weight =%2.2f (PHOS bayesian weight for pi0)\n",fPHOSPi0Weight) ;
899 parList+=onePar ;
900 snprintf(onePar,buffersize,"fPHOSElectronWeight =%2.2f(PHOS bayesian weight for electrons)\n",fPHOSElectronWeight) ;
901 parList+=onePar ;
902 snprintf(onePar,buffersize,"fPHOSChargeWeight =%2.2f (PHOS bayesian weight for charged hadrons)\n",fPHOSChargeWeight) ;
903 parList+=onePar ;
904 snprintf(onePar,buffersize,"fPHOSNeutralWeight =%2.2f (PHOS bayesian weight for neutral hadrons)\n",fPHOSNeutralWeight) ;
905 parList+=onePar ;
906
745a2967 907 if(fPHOSWeightFormula)
908 {
49b5c49b 909 snprintf(onePar,buffersize,"PHOS Photon Weight Formula: %s\n",fPHOSPhotonWeightFormulaExpression.Data() ) ;
910 parList+=onePar;
911 snprintf(onePar,buffersize,"PHOS Pi0 Weight Formula: %s\n",fPHOSPi0WeightFormulaExpression.Data() ) ;
912 parList+=onePar;
913 }
914 }
745a2967 915 else
916 {
49b5c49b 917 snprintf(onePar,buffersize,"EMCAL: fEMCALL0CutMin =%2.2f, fEMCALL0CutMax =%2.2f (Cut on Shower Shape) \n",fEMCALL0CutMin, fEMCALL0CutMax) ;
918 parList+=onePar ;
919 snprintf(onePar,buffersize,"EMCAL: fEMCALDEtaCut =%2.2f, fEMCALDPhiCut =%2.2f (Cut on track matching) \n",fEMCALDEtaCut, fEMCALDPhiCut) ;
920 parList+=onePar ;
921 snprintf(onePar,buffersize,"fTOFCut =%e (Cut on TOF, used in PID evaluation) \n",fTOFCut) ;
922 parList+=onePar ;
923 snprintf(onePar,buffersize,"fPHOSRCut =%2.2f, fPHOSDispersionCut =%2.2f (Cut on Shower Shape and CPV) \n",fPHOSRCut,fPHOSDispersionCut) ;
924 parList+=onePar ;
925
a5fb4114 926 }
477d6cee 927
745a2967 928 if(fUseSimpleM02Cut)
3c1d9afb 929 {
930 snprintf(onePar,buffersize,"%2.2f< M02 < %2.2f \n", fSplitM02MinCut, fSplitM02MaxCut) ;
931 parList+=onePar ;
745a2967 932 }
933 snprintf(onePar,buffersize,"fMinNCells =%d \n", fSplitMinNCells) ;
934 parList+=onePar ;
935 if(fUseSimpleMassCut)
936 {
3c1d9afb 937 snprintf(onePar,buffersize,"pi0 : %2.1f < m <%2.1f\n", fMassPi0Min,fMassPi0Max);
938 parList+=onePar ;
3c1d9afb 939 }
745a2967 940 snprintf(onePar,buffersize,"eta : %2.1f < m <%2.1f\n", fMassEtaMin,fMassEtaMax);
941 parList+=onePar ;
942 snprintf(onePar,buffersize,"conv: %2.1f < m <%2.1f\n", fMassPhoMin,fMassPhoMax);
943 parList+=onePar ;
3c1d9afb 944
745a2967 945
946 return parList;
477d6cee 947
1c5acb87 948}
949
49b5c49b 950//________________________________________________
1c5acb87 951void AliCaloPID::Print(const Option_t * opt) const
952{
477d6cee 953
954 //Print some relevant parameters set for the analysis
955 if(! opt)
956 return;
957
958 printf("***** Print: %s %s ******\n", GetName(), GetTitle() ) ;
959
3c1d9afb 960 if(fUseBayesianWeights)
961 {
49b5c49b 962 printf("PHOS PID weight , photon %0.2f, pi0 %0.2f, e %0.2f, charge %0.2f, neutral %0.2f \n",
3c1d9afb 963 fPHOSPhotonWeight, fPHOSPi0Weight,
964 fPHOSElectronWeight, fPHOSChargeWeight, fPHOSNeutralWeight) ;
49b5c49b 965 printf("EMCAL PID weight, photon %0.2f, pi0 %0.2f, e %0.2f, charge %0.2f, neutral %0.2f\n",
3c1d9afb 966 fEMCALPhotonWeight, fEMCALPi0Weight,
967 fEMCALElectronWeight, fEMCALChargeWeight, fEMCALNeutralWeight) ;
49b5c49b 968
969 printf("PHOS Parametrized weight on? = %d\n", fPHOSWeightFormula) ;
3c1d9afb 970 if(fPHOSWeightFormula)
971 {
49b5c49b 972 printf("Photon weight formula = %s\n", fPHOSPhotonWeightFormulaExpression.Data());
973 printf("Pi0 weight formula = %s\n", fPHOSPi0WeightFormulaExpression .Data());
974 }
975 if(fRecalculateBayesian) printf(" Recalculate bayesian with Particle Flux? = %d\n",fParticleFlux);
976 }
3c1d9afb 977 else
978 {
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) ;
49b5c49b 983
a5fb4114 984 }
477d6cee 985
745a2967 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);
3c1d9afb 991
477d6cee 992 printf(" \n");
993
1c5acb87 994}
995
3c1d9afb 996//_________________________________________________________________
997void AliCaloPID::PrintClusterPIDWeights(const Double_t * pid) const
998{
999 // print PID of cluster, (AliVCluster*)cluster->GetPID()
1000
c2791479 1001 printf("AliCaloPID::PrintClusterPIDWeights() \n \t ph %0.2f, pi0 %0.2f, el %0.2f, conv el %0.2f, \n \t \
3c1d9afb 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]);
1008
1009}
1010
49b5c49b 1011//___________________________________________________________________________
3c1d9afb 1012void AliCaloPID::SetPIDBits(AliVCluster * cluster,
49b5c49b 1013 AliAODPWG4Particle * ph, AliCalorimeterUtils* cu,
1014 AliVEvent* event)
1015{
477d6cee 1016 //Set Bits for PID selection
1017
1018 //Dispersion/lambdas
5ae09196 1019 //Double_t disp= cluster->GetDispersion() ;
1020 Double_t l1 = cluster->GetM20() ;
1021 Double_t l0 = cluster->GetM02() ;
1022 Bool_t isDispOK = kTRUE ;
9a6fa057 1023 if(cluster->IsPHOS()){
49b5c49b 1024 if(TestPHOSDispersion(ph->Pt(),l0,l1) < fPHOSDispersionCut) isDispOK = kTRUE;
1025 else isDispOK = kFALSE;
5ae09196 1026 }
1027 else{//EMCAL
1028
49b5c49b 1029 if(l0 > fEMCALL0CutMin && l0 < fEMCALL0CutMax) isDispOK = kTRUE;
1030
5ae09196 1031 }
1032
1033 ph->SetDispBit(isDispOK) ;
477d6cee 1034
1035 //TOF
1036 Double_t tof=cluster->GetTOF() ;
1037 ph->SetTOFBit(TMath::Abs(tof)<fTOFCut) ;
1038
49b5c49b 1039 //Charged
1040 Bool_t isNeutral = IsTrackMatched(cluster,cu,event);
5ae09196 1041
1042 ph->SetChargedBit(isNeutral);
477d6cee 1043
1044 //Set PID pdg
3c1d9afb 1045 ph->SetIdentifiedParticleType(GetIdentifiedParticleType(cluster));
477d6cee 1046
5a72d9af 1047 if(fDebug > 0)
1048 {
5ae09196 1049 printf("AliCaloPID::SetPIDBits: TOF %e, Lambda0 %2.2f, Lambda1 %2.2f\n",tof , l0, l1);
477d6cee 1050 printf("AliCaloPID::SetPIDBits: pdg %d, bits: TOF %d, Dispersion %d, Charge %d\n",
49b5c49b 1051 ph->GetIdentifiedParticleType(), ph->GetTOFBit() , ph->GetDispBit() , ph->GetChargedBit());
477d6cee 1052 }
1c5acb87 1053}
1054
09273901 1055//_________________________________________________________
49b5c49b 1056Bool_t AliCaloPID::IsTrackMatched(AliVCluster* cluster,
1057 AliCalorimeterUtils * cu,
1058 AliVEvent* event) const
1059{
5ae09196 1060 //Check if there is any track attached to this cluster
1061
1062 Int_t nMatches = cluster->GetNTracksMatched();
49b5c49b 1063 AliVTrack * track = 0;
1064 Double_t p[3];
1065
44443bbd 1066 if(nMatches > 0)
1067 {
49b5c49b 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())))
1070 {
1071 Int_t iESDtrack = cluster->GetTrackMatchedIndex();
1072 if(iESDtrack >= 0) track = dynamic_cast<AliVTrack*> (event->GetTrack(iESDtrack));
1073 else return kFALSE;
d39cba7e 1074
44443bbd 1075 if (!track)
1076 {
1077 if(fDebug > 0) printf("AliCaloPID::IsTrackMatched() - Null matched track in ESD when index is OK!\n");
49b5c49b 1078 return kFALSE;
1079 }
1080 }
1081 else { // AOD
1082 track = dynamic_cast<AliVTrack*> (cluster->GetTrackMatched(0));
44443bbd 1083 if (!track)
1084 {
1085 if(fDebug > 0) printf("AliCaloPID::IsTrackMatched() - Null matched track in AOD!\n");
49b5c49b 1086 return kFALSE;
c76f0089 1087 }
d39cba7e 1088 }
5ae09196 1089
49b5c49b 1090 Float_t dZ = cluster->GetTrackDz();
1091 Float_t dR = cluster->GetTrackDx();
1092
1093 // if track matching was recalculated
44443bbd 1094 if(cluster->IsEMCAL() && cu && cu->IsRecalculationOfClusterTrackMatchingOn())
1095 {
49b5c49b 1096 dR = 2000., dZ = 2000.;
31ae6d59 1097 cu->GetEMCALRecoUtils()->GetMatchedResiduals(cluster->GetID(),dZ,dR);
49b5c49b 1098 }
09273901 1099
44443bbd 1100 if(cluster->IsPHOS())
1101 {
49b5c49b 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;
1107 else return kFALSE;
1108
1109 }//PHOS
5a72d9af 1110 else //EMCAL
1111 {
1112 if(fDebug > 1)
49b5c49b 1113 printf("AliCaloPID::IsTrackMatched - EMCAL dR %f < %f, dZ %f < %f \n",dR, fEMCALDPhiCut, dZ, fEMCALDEtaCut);
1114
1115 if(TMath::Abs(dR) < fEMCALDPhiCut &&
1116 TMath::Abs(dZ) < fEMCALDEtaCut) return kTRUE;
1117 else return kFALSE;
1118
1119 }//EMCAL cluster
1120
1121
1122 } // more than 1 match, at least one track in array
1123 else return kFALSE;
1124
1125}
1126
1127//___________________________________________________________________________________________________
1128Float_t AliCaloPID::TestPHOSDispersion(const Double_t pt, const Double_t l1, const Double_t l2) const
1129{
1130 //Check if cluster photon-like. Uses photon cluster parameterization in real pp data
1131 //Returns distance in sigmas. Recommended cut 2.5
1132
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) ;
f3138ecf 1138 Double_t r2 = 0.5* (l1-l1Mean)*(l1-l1Mean)/l1Sigma/l1Sigma +
49b5c49b 1139 0.5* (l2-l2Mean)*(l2-l2Mean)/l2Sigma/l2Sigma +
1140 0.5*c*(l1-l1Mean)*(l2-l2Mean)/l1Sigma/l2Sigma ;
1141
f3138ecf 1142 if(fDebug > 0) printf("AliCaloPID::TestPHOSDispersion() - PHOS SS R %f < %f?\n", TMath::Sqrt(r2), fPHOSDispersionCut);
5ae09196 1143
f3138ecf 1144 return TMath::Sqrt(r2) ;
5ae09196 1145
1146}
1147
49b5c49b 1148//_______________________________________________________________________________________________
1149Float_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
1151{
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
1156 // Double_t mf=0. ;
1157 // AliESDEvent *event = dynamic_cast<AliESDEvent*>(InputEvent());
1158 // if(event)
1159 // mf = event->GetMagneticField(); //Positive for ++ and negative for --
1160
1161
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)+
1166 1.59219);
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)+
1168 1.60) ;
1169
1170 if(mf<0.){ //field --
1171 meanZ = -0.468318 ;
1172 if(charge>0)
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)) ;
1175 else
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)) ;
1178 }
1179 else{ //Field ++
1180 meanZ = -0.468318;
1181 if(charge>0)
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)) ;
1184 else
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)) ;
1187 }
9a6fa057 1188
49b5c49b 1189 Double_t rz = (dz-meanZ)/sz ;
1190 Double_t rx = (dx-meanX)/sx ;
9a6fa057 1191
49b5c49b 1192 if(fDebug > 0)
1193 printf("AliCaloPID::TestPHOSDispersion() - PHOS Matching R %f < %f\n",TMath::Sqrt(rx*rx+rz*rz), fPHOSRCut);
9a6fa057 1194
49b5c49b 1195 return TMath::Sqrt(rx*rx+rz*rz) ;
9a6fa057 1196
1197}