]> git.uio.no Git - u/mrichter/AliRoot.git/blame - PWG/CaloTrackCorrBase/AliCaloPID.cxx
activate time cut to reject exotics
[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
3c1d9afb 81fDoClusterSplitting(kFALSE),
5a72d9af 82fUseSimpleMassCut(kFALSE),
83fUseSimpleM02Cut(kFALSE),
3c1d9afb 84fSplitM02MaxCut(0), fSplitM02MinCut(0), fSplitMinNCells(0),
85fMassEtaMin(0), fMassEtaMax(0),
86fMassPi0Min(0), fMassPi0Max(0),
5a72d9af 87fMassPhoMin(0), fMassPhoMax(0),
88fSplitEFracMin(0), fSplitWidthSigma(0)
1c5acb87 89{
477d6cee 90 //Ctor
91
92 //Initialize parameters
93 InitParameters();
1c5acb87 94}
95
49b5c49b 96//________________________________________
bdd2a262 97AliCaloPID::AliCaloPID(const Int_t flux) :
49b5c49b 98TObject(), fDebug(-1), fParticleFlux(flux),
99//Bayesian
100fEMCALPIDUtils(), fUseBayesianWeights(kFALSE), fRecalculateBayesian(kFALSE),
a5fb4114 101fEMCALPhotonWeight(0.), fEMCALPi0Weight(0.),
102fEMCALElectronWeight(0.), fEMCALChargeWeight(0.), fEMCALNeutralWeight(0.),
103fPHOSPhotonWeight(0.), fPHOSPi0Weight(0.),
104fPHOSElectronWeight(0.), fPHOSChargeWeight(0.) , fPHOSNeutralWeight(0.),
105fPHOSWeightFormula(0), fPHOSPhotonWeightFormula(0), fPHOSPi0WeightFormula(0),
49b5c49b 106fPHOSPhotonWeightFormulaExpression(""),
107fPHOSPi0WeightFormulaExpression(""),
108//PID calculation
109fEMCALL0CutMax(100.), fEMCALL0CutMin(0),
110fEMCALDEtaCut(2000.), fEMCALDPhiCut(2000.),
111fTOFCut(0.),
3c1d9afb 112fPHOSDispersionCut(1000), fPHOSRCut(1000),
5a72d9af 113//Split
3c1d9afb 114fDoClusterSplitting(kFALSE),
5a72d9af 115fUseSimpleMassCut(kFALSE),
116fUseSimpleM02Cut(kFALSE),
3c1d9afb 117fSplitM02MaxCut(0), fSplitM02MinCut(0), fSplitMinNCells(0),
118fMassEtaMin(0), fMassEtaMax(0),
119fMassPi0Min(0), fMassPi0Max(0),
5a72d9af 120fMassPhoMin(0), fMassPhoMax(0),
121fSplitEFracMin(0), fSplitWidthSigma(0)
bdd2a262 122{
9a6fa057 123 //Ctor
bdd2a262 124
9a6fa057 125 //Initialize parameters
126 InitParameters();
49b5c49b 127
bdd2a262 128}
129
49b5c49b 130//_______________________________________________
f21fc003 131AliCaloPID::AliCaloPID(const TNamed * emcalpid) :
49b5c49b 132TObject(), fDebug(-1), fParticleFlux(kLow),
133//Bayesian
134fEMCALPIDUtils((AliEMCALPIDUtils*)emcalpid),
135fUseBayesianWeights(kFALSE), fRecalculateBayesian(kFALSE),
136fEMCALPhotonWeight(0.), fEMCALPi0Weight(0.),
137fEMCALElectronWeight(0.), fEMCALChargeWeight(0.), fEMCALNeutralWeight(0.),
138fPHOSPhotonWeight(0.), fPHOSPi0Weight(0.),
139fPHOSElectronWeight(0.), fPHOSChargeWeight(0.) , fPHOSNeutralWeight(0.),
140fPHOSWeightFormula(0), fPHOSPhotonWeightFormula(0), fPHOSPi0WeightFormula(0),
141fPHOSPhotonWeightFormulaExpression(""),
142fPHOSPi0WeightFormulaExpression(""),
143//PID calculation
144fEMCALL0CutMax(100.), fEMCALL0CutMin(0),
145fEMCALDEtaCut(2000.), fEMCALDPhiCut(2000.),
146fTOFCut(0.),
3c1d9afb 147fPHOSDispersionCut(1000), fPHOSRCut(1000),
5a72d9af 148//Split
3c1d9afb 149fDoClusterSplitting(kFALSE),
5a72d9af 150fUseSimpleMassCut(kFALSE),
151fUseSimpleM02Cut(kFALSE),
3c1d9afb 152fSplitM02MaxCut(0), fSplitM02MinCut(0), fSplitMinNCells(0),
153fMassEtaMin(0), fMassEtaMax(0),
154fMassPi0Min(0), fMassPi0Max(0),
5a72d9af 155fMassPhoMin(0), fMassPhoMax(0),
156fSplitEFracMin(0), fSplitWidthSigma(0)
157
bdd2a262 158{
9a6fa057 159 //Ctor
49b5c49b 160
9a6fa057 161 //Initialize parameters
162 InitParameters();
bdd2a262 163}
164
49b5c49b 165//_______________________
166AliCaloPID::~AliCaloPID()
167{
477d6cee 168 //Dtor
169
a5fb4114 170 delete fPHOSPhotonWeightFormula ;
171 delete fPHOSPi0WeightFormula ;
172 delete fEMCALPIDUtils ;
49b5c49b 173
9a6fa057 174}
1c5acb87 175
49b5c49b 176//_______________________________
1c5acb87 177void AliCaloPID::InitParameters()
178{
477d6cee 179 //Initialize the parameters of the PID.
180
49b5c49b 181 // Bayesian
2007809d 182 fEMCALPhotonWeight = 0.6 ;
183 fEMCALPi0Weight = 0.6 ;
184 fEMCALElectronWeight = 0.6 ;
185 fEMCALChargeWeight = 0.6 ;
186 fEMCALNeutralWeight = 0.6 ;
477d6cee 187
2007809d 188 fPHOSPhotonWeight = 0.6 ;
189 fPHOSPi0Weight = 0.6 ;
190 fPHOSElectronWeight = 0.6 ;
191 fPHOSChargeWeight = 0.6 ;
192 fPHOSNeutralWeight = 0.6 ;
477d6cee 193
194 //Formula to set the PID weight threshold for photon or pi0
a5fb4114 195 fPHOSWeightFormula = kFALSE;
196 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))";
197 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))" ;
198
bdd2a262 199 if(fRecalculateBayesian){
49b5c49b 200 if(fParticleFlux == kLow){
201 printf("AliCaloPID::Init() - SetLOWFluxParam\n");
202 fEMCALPIDUtils->SetLowFluxParam() ;
203 }
204 else if (fParticleFlux == kHigh){
205 printf("AliCaloPID::Init() - SetHIGHFluxParam\n");
206 fEMCALPIDUtils->SetHighFluxParam() ;
207 }
208 }
209
210 //PID recalculation, not bayesian
211
212 //EMCAL
213 fEMCALL0CutMax = 0.3 ;
214 fEMCALL0CutMin = 0.01;
215
216 fEMCALDPhiCut = 0.05; // Same cut as in AliEMCALRecoUtils
217 fEMCALDEtaCut = 0.025;// Same cut as in AliEMCALRecoUtils
218
219 // PHOS / EMCAL, not used
220 fTOFCut = 1.e-6;
221
222 //PHOS
223 fPHOSRCut = 2. ;
224 fPHOSDispersionCut = 2.5;
225
3c1d9afb 226 // Cluster splitting
227
5a72d9af 228 fSplitM02MinCut = 0.3 ;
229 fSplitM02MaxCut = 5 ;
230 fSplitMinNCells = 4 ;
3c1d9afb 231
232 fMassEtaMin = 0.4;
233 fMassEtaMax = 0.6;
234
5a72d9af 235 fMassPi0Min = 0.11;
236 fMassPi0Max = 0.18;
3c1d9afb 237
238 fMassPhoMin = 0.0;
5a72d9af 239 fMassPhoMax = 0.08;
240
241 fMassWidthPi0Param[0] = 0.111; // Aboslute Low mass cut for NLM=1 and E < 12 GeV
242 fMassWidthPi0Param[1] = 0.110; // Aboslute Low mass cut for NLM=2 and E < 9 GeV
243 fMassWidthPi0Param[2] = 0.009; // constant width for E < 8 GeV, 9 MeV
244 fMassWidthPi0Param[3] = 0.0023; // pol1 param0 of width for E > 8 GeV
245 fMassWidthPi0Param[4] = 0.0008; // pol1 param1 of width for E > 8 GeV
246 fMassWidthPi0Param[5] = 0.130; // Mean mass value for NLM=1
247 fMassWidthPi0Param[6] = 0.134; // Mean mass value for NLM=2
248
249 fM02MinParam[0] = 0.6 ; // Min for NLM>1 and E < 8 NLM=1
250 fM02MinParam[1] = 1.9 ; // pol2 param0 for NLM=1 , 8 < E < 18 GeV
251 fM02MinParam[2] =-0.186 ; // pol2 param1 for NLM=1 , 8 < E < 18 GeV
252 fM02MinParam[3] = 0.0053 ; // pol2 param2 for NLM=1 , 8 < E < 18 GeV
253 fM02MinParam[4] = 0.3; // absolute minimum in any case
254
255 fSplitEFracMin = 0.85 ;
256 fSplitWidthSigma = 2.5 ;
257
258}
259
260//_________________________________________________________________________________________________
261Bool_t AliCaloPID::IsInPi0SplitMassRange(const Float_t energy, const Float_t mass, const Int_t nlm)
262{
263 // Select the appropriate mass range for pi0 selection in splitting method
264
265 if(fUseSimpleMassCut)
266 {
267 if(mass < fMassPi0Max && mass > fMassPi0Min) return kTRUE;
268 else return kFALSE;
269 }
270
271 // Get the selected mean value as reference for the mass
272 Float_t meanMass = fMassWidthPi0Param[6];
273 if(nlm == 1) meanMass = fMassWidthPi0Param[5];
274
275 // Get the parametrized width of the mass
276 Float_t width = 0.009;
277 if(energy < 8) width = fMassWidthPi0Param[2];
278 else width = fMassWidthPi0Param[3]+energy*fMassWidthPi0Param[4];
279
280 // Calculate the 2 sigma cut
281 Float_t minMass = meanMass-fSplitWidthSigma*width;
282 Float_t maxMass = meanMass+fSplitWidthSigma*width;
283
284 // In case of low energy, hard cut to avoid conversions
285 if(energy < 12 && nlm == 1) minMass = fMassWidthPi0Param[0];
286 if(energy < 9 && nlm == 2) minMass = fMassWidthPi0Param[1];
287
288 //printf("\t \t sigma %1.1f width %3.1f, mean Mass %3.0f, minMass %3.0f, maxMass %3.0f\n ",
289 // fSplitWidthSigma, width*1000, meanMass*1000,minMass*1000,maxMass*1000);
290
291 if(mass < maxMass && mass > minMass) return kTRUE;
292 else return kFALSE;
293
294
295}
296
297//_____________________________________________________________________________________________
298Bool_t AliCaloPID::IsInSplitM02Range(const Float_t energy, const Float_t m02, const Int_t nlm)
299{
300 // Select the appropriate m02 range in splitting method
301 // Min value between 0.3 and 0.6
302
303 Float_t minCut = fSplitM02MinCut;
3c1d9afb 304
5a72d9af 305 if(!fUseSimpleM02Cut)
306 {
307 if ( nlm > 1 || (nlm==1 && energy<8) ) minCut = fM02MinParam[0]; // 0.6
308 else minCut = fM02MinParam[1]+energy*fM02MinParam[2]+energy*energy*fM02MinParam[3];
309
310 //In any case, the parameter cannot be smaller than this (0.3)
311 if(minCut < fM02MinParam[4]) minCut = fM02MinParam[4];
312 }
313
314 //printf("\t \t m02 %2.2f, minM02 %2.2f, maxM02 %2.2f\n",m02,minCut,fSplitM02MaxCut);
315
316 if(m02 < fSplitM02MaxCut && m02 > minCut) return kTRUE;
317 else return kFALSE;
318
49b5c49b 319}
320
5a72d9af 321
c5693f62 322//______________________________________________
323AliEMCALPIDUtils *AliCaloPID::GetEMCALPIDUtils()
324{
325 // return pointer to AliEMCALPIDUtils, create it if needed
326
327 if(!fEMCALPIDUtils) fEMCALPIDUtils = new AliEMCALPIDUtils ;
328 return fEMCALPIDUtils ;
329
330}
331
332
49b5c49b 333//______________________________________________________________________
3c1d9afb 334Int_t AliCaloPID::GetIdentifiedParticleType(const AliVCluster * cluster)
49b5c49b 335{
336 // Returns a PDG number corresponding to the likely ID of the cluster
337
3c1d9afb 338 Float_t energy = cluster->E();
49b5c49b 339 Float_t lambda0 = cluster->GetM02();
340 Float_t lambda1 = cluster->GetM20();
341
342 // ---------------------
343 // Use bayesian approach
344 // ---------------------
345
3c1d9afb 346 if(fUseBayesianWeights)
347 {
00a38d07 348 Double_t weights[AliPID::kSPECIESCN];
49b5c49b 349
3c1d9afb 350 if(cluster->IsEMCAL() && fRecalculateBayesian)
351 {
49b5c49b 352 fEMCALPIDUtils->ComputePID(energy, lambda0);
00a38d07 353 for(Int_t i = 0; i < AliPID::kSPECIESCN; i++) weights[i] = fEMCALPIDUtils->GetPIDFinal(i);
49b5c49b 354 }
3c1d9afb 355 else
356 {
00a38d07 357 for(Int_t i = 0; i < AliPID::kSPECIESCN; i++) weights[i] = cluster->GetPID()[i];
49b5c49b 358 }
359
3c1d9afb 360 if(fDebug > 0) PrintClusterPIDWeights(weights);
49b5c49b 361
3c1d9afb 362 return GetIdentifiedParticleTypeFromBayesWeights(cluster->IsEMCAL(), weights, energy);
bdd2a262 363 }
49b5c49b 364
365 // -------------------------------------------------------
366 // Calculate PID SS from data, do not use bayesian weights
367 // -------------------------------------------------------
368
3c1d9afb 369 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",
370 cluster->IsEMCAL(),energy,lambda0,cluster->GetM20(),cluster->GetDispersion(),cluster->GetTOF(),
49b5c49b 371 cluster->GetEmcCpvDistance(), cluster->GetDistanceToBadChannel(),cluster->GetNExMax());
372
3c1d9afb 373 if(cluster->IsEMCAL())
374 {
49b5c49b 375 if(fDebug > 0) printf("AliCaloPID::GetIdentifiedParticleType() - EMCAL SS %f <%f < %f?\n",fEMCALL0CutMin, lambda0, fEMCALL0CutMax);
376
377 if(lambda0 < fEMCALL0CutMax && lambda0 > fEMCALL0CutMin) return kPhoton ;
378 else return kNeutralUnknown ;
3c1d9afb 379 } // EMCAL
380 else // PHOS
381 {
382 if(TestPHOSDispersion(energy,lambda0,lambda1) < fPHOSDispersionCut) return kPhoton;
383 else return kNeutralUnknown;
49b5c49b 384 }
385
1c5acb87 386}
387
49b5c49b 388//_______________________________________________________________________________
3c1d9afb 389Int_t AliCaloPID::GetIdentifiedParticleTypeFromBayesWeights(const Bool_t isEMCAL,
49b5c49b 390 const Double_t * pid,
391 const Float_t energy)
392{
393 //Return most probable identity of the particle after bayesian weights calculated in reconstruction
477d6cee 394
3c1d9afb 395 if(!pid)
396 {
21a4b1c0 397 printf("AliCaloPID::GetIdentifiedParticleType() - pid pointer not initialized!!!\n");
477d6cee 398 abort();
399 }
400
15800db4 401 Float_t wPh = fPHOSPhotonWeight ;
477d6cee 402 Float_t wPi0 = fPHOSPi0Weight ;
15800db4 403 Float_t wE = fPHOSElectronWeight ;
404 Float_t wCh = fPHOSChargeWeight ;
405 Float_t wNe = fPHOSNeutralWeight ;
49b5c49b 406
3c1d9afb 407 if(!isEMCAL && fPHOSWeightFormula){
a5fb4114 408 wPh = GetPHOSPhotonWeightFormula()->Eval(energy) ;
409 wPi0 = GetPHOSPi0WeightFormula() ->Eval(energy);
410 }
3c1d9afb 411 else
412 {
477d6cee 413 wPh = fEMCALPhotonWeight ;
414 wPi0 = fEMCALPi0Weight ;
415 wE = fEMCALElectronWeight ;
416 wCh = fEMCALChargeWeight ;
417 wNe = fEMCALNeutralWeight ;
477d6cee 418 }
419
3c1d9afb 420 if(fDebug > 0) PrintClusterPIDWeights(pid);
421
477d6cee 422 Int_t pdg = kNeutralUnknown ;
c8fe2783 423 Float_t chargedHadronWeight = pid[AliVCluster::kProton]+pid[AliVCluster::kKaon]+
49b5c49b 424 pid[AliVCluster::kPion]+pid[AliVCluster::kMuon];
c8fe2783 425 Float_t neutralHadronWeight = pid[AliVCluster::kNeutron]+pid[AliVCluster::kKaon0];
426 Float_t allChargedWeight = pid[AliVCluster::kElectron]+pid[AliVCluster::kEleCon]+ chargedHadronWeight;
427 Float_t allNeutralWeight = pid[AliVCluster::kPhoton]+pid[AliVCluster::kPi0]+ neutralHadronWeight;
477d6cee 428
429 //Select most probable ID
3c1d9afb 430 if(!isEMCAL) // PHOS
431 {
a5fb4114 432 if(pid[AliVCluster::kPhoton] > wPh) pdg = kPhoton ;
433 else if(pid[AliVCluster::kPi0] > wPi0) pdg = kPi0 ;
c8fe2783 434 else if(pid[AliVCluster::kElectron] > wE) pdg = kElectron ;
a5fb4114 435 else if(pid[AliVCluster::kEleCon] > wE) pdg = kEleCon ;
436 else if(chargedHadronWeight > wCh) pdg = kChargedHadron ;
437 else if(neutralHadronWeight > wNe) pdg = kNeutralHadron ;
477d6cee 438 else if(allChargedWeight > allNeutralWeight)
439 pdg = kChargedUnknown ;
440 else
441 pdg = kNeutralUnknown ;
442 }
3c1d9afb 443 else //EMCAL
444 {
2007809d 445 if(pid[AliVCluster::kPhoton] > wPh) pdg = kPhoton ;
446 else if(pid[AliVCluster::kElectron] > wE) pdg = kElectron ;
447 else if(pid[AliVCluster::kPhoton]+pid[AliVCluster::kElectron] > wPh) pdg = kPhoton ; //temporal sollution until track matching for electrons is considered
448 else if(pid[AliVCluster::kPi0] > wPi0) pdg = kPi0 ;
477d6cee 449 else if(chargedHadronWeight + neutralHadronWeight > wCh) pdg = kChargedHadron ;
450 else if(neutralHadronWeight + chargedHadronWeight > wNe) pdg = kNeutralHadron ;
2007809d 451 else pdg = kNeutralUnknown ;
477d6cee 452 }
453
21a4b1c0 454 if(fDebug > 0)printf("AliCaloPID::GetIdentifiedParticleType:Final Pdg: %d, cluster energy %2.2f \n", pdg,energy);
1c5acb87 455
49b5c49b 456 return pdg ;
9a6fa057 457
1c5acb87 458}
459
3c1d9afb 460//____________________________________________________________________________________________________
461Int_t AliCaloPID::GetIdentifiedParticleTypeFromClusterSplitting(AliVCluster* cluster,
462 AliVCaloCells* cells,
463 AliCalorimeterUtils * caloutils,
464 Double_t vertex[3],
465 Int_t & nMax,
bfdcf7fb 466 Double_t & mass, Double_t & angle,
467 Double_t & e1 , Double_t & e2 )
3c1d9afb 468{
469 // Split the cluster in 2, do invariant mass, get the mass and decide
470 // if this is a photon, pi0, eta, ...
471
2bf17171 472 Int_t absId1 = -1; Int_t absId2 = -1;
5a72d9af 473 Float_t eClus = cluster->E();
474 Float_t m02 = cluster->GetM02();
2bf17171 475 const Int_t nc = cluster->GetNCells();
476 Int_t absIdList[nc];
477 Float_t maxEList [nc];
3c1d9afb 478
3c1d9afb 479 mass = -1.;
480 angle = -1.;
5a72d9af 481
3c1d9afb 482 // Get Number of local maxima
5a72d9af 483 nMax = caloutils->GetNumberOfLocalMaxima(cluster, cells, absIdList, maxEList) ;
3c1d9afb 484
5a72d9af 485 if(fDebug > 0) printf("AliCaloPID::GetIdentifiedParticleTypeFromClusterSplitting() - Cluster : E %1.1f, M02 %1.2f, NLM %d, N Cells %d\n",
486 eClus,m02,nMax,nc);
487
3c1d9afb 488 //---------------------------------------------------------------------
489 // Get the 2 max indeces and do inv mass
490 //---------------------------------------------------------------------
491
492 if ( nMax == 2 )
493 {
494 absId1 = absIdList[0];
495 absId2 = absIdList[1];
496 }
497 else if( nMax == 1 )
498 {
499
500 absId1 = absIdList[0];
501
502 //Find second highest energy cell
503
504 TString calorimeter = "EMCAL";
505 if(cluster->IsPHOS()) calorimeter = "PHOS";
506 Float_t enmax = 0 ;
507 for(Int_t iDigit = 0 ; iDigit < cluster->GetNCells() ; iDigit++)
508 {
509 Int_t absId = cluster->GetCellsAbsId()[iDigit];
510 if( absId == absId1 ) continue ;
511 Float_t endig = cells->GetCellAmplitude(absId);
512 caloutils->RecalibrateCellAmplitude(endig,calorimeter,absId);
513 if(endig > enmax)
514 {
515 enmax = endig ;
516 absId2 = absId ;
517 }
518 }// cell loop
519 }// 1 maxima
520 else
521 { // n max > 2
522 // loop on maxima, find 2 highest
523
524 // First max
525 Float_t enmax = 0 ;
526 for(Int_t iDigit = 0 ; iDigit < nMax ; iDigit++)
527 {
528 Float_t endig = maxEList[iDigit];
529 if(endig > enmax)
530 {
531 enmax = endig ;
532 absId1 = absIdList[iDigit];
533 }
534 }// first maxima loop
535
536 // Second max
537 Float_t enmax2 = 0;
538 for(Int_t iDigit = 0 ; iDigit < nMax ; iDigit++)
539 {
540 if(absIdList[iDigit]==absId1) continue;
541 Float_t endig = maxEList[iDigit];
542 if(endig > enmax2)
543 {
544 enmax2 = endig ;
545 absId2 = absIdList[iDigit];
546 }
547 }// second maxima loop
548
549 } // n local maxima > 2
550
551 //---------------------------------------------------------------------
552 // Split the cluster energy in 2, around the highest 2 local maxima
553 //---------------------------------------------------------------------
554
2bf17171 555 AliAODCaloCluster cluster1(0, 0,NULL,0.,NULL,NULL,1,0);
556 AliAODCaloCluster cluster2(1, 0,NULL,0.,NULL,NULL,1,0);
3c1d9afb 557
2bf17171 558 caloutils->SplitEnergy(absId1,absId2,cluster, cells, &cluster1, &cluster2,nMax); /*absIdList, maxEList,*/
3c1d9afb 559
560 TLorentzVector cellMom1;
561 TLorentzVector cellMom2;
562
2bf17171 563 cluster1.GetMomentum(cellMom1,vertex);
564 cluster2.GetMomentum(cellMom2,vertex);
3c1d9afb 565
566 mass = (cellMom1+cellMom2).M();
567 angle = cellMom2.Angle(cellMom1.Vect());
bfdcf7fb 568 e1 = cluster1.E();
569 e2 = cluster2.E();
570
5a72d9af 571 if(fDebug > 0)
572 printf("\t Split : E1 %1.2f, E2 %1.2f, mass %3.3f \n", e1,e2,mass);
573
574 // Consider clusters with splitted energy not too different to original cluster energy
575 if((e1+e2)/eClus < fSplitEFracMin) return kNeutralUnknown ;
576
577 if(fDebug > 0) printf("\t pass Split E frac cut\n");
578
579 //If too small or big E or low number of cells, or close to a bad channel skip it
580 if ( !IsInSplitM02Range(eClus,m02,nMax) || nc < fSplitMinNCells) return kNeutralUnknown ;
581
582 if(fDebug > 0) printf("\t pass M02 and nCells cut\n");
583
584 // Check the mass, and set an ID to the splitted cluster
585 if (mass < fMassPhoMax && mass > fMassPhoMin ) { if(fDebug > 0) printf("\t Split Conv \n"); return kPhoton ; }
586 else if(mass < fMassEtaMax && mass > fMassEtaMin ) { if(fDebug > 0) printf("\t Split Eta \n"); return kEta ; }
587 else if(IsInPi0SplitMassRange(cluster->E(),mass,nMax)) { if(fDebug > 0) printf("\t Split Pi0 \n"); return kPi0 ; }
588 else return kNeutralUnknown ;
3c1d9afb 589
3c1d9afb 590}
591
49b5c49b 592//_________________________________________
593TString AliCaloPID::GetPIDParametersList()
594{
477d6cee 595 //Put data member values in string to keep in output container
596
597 TString parList ; //this will be list of parameters used for this analysis.
5ae09196 598 const Int_t buffersize = 255;
599 char onePar[buffersize] ;
600 snprintf(onePar,buffersize,"--- AliCaloPID ---\n") ;
477d6cee 601 parList+=onePar ;
49b5c49b 602 if(fUseBayesianWeights){
603 snprintf(onePar,buffersize,"fEMCALPhotonWeight =%2.2f (EMCAL bayesian weight for photons)\n",fEMCALPhotonWeight) ;
604 parList+=onePar ;
605 snprintf(onePar,buffersize,"fEMCALPi0Weight =%2.2f (EMCAL bayesian weight for pi0)\n",fEMCALPi0Weight) ;
606 parList+=onePar ;
607 snprintf(onePar,buffersize,"fEMCALElectronWeight =%2.2f(EMCAL bayesian weight for electrons)\n",fEMCALElectronWeight) ;
608 parList+=onePar ;
609 snprintf(onePar,buffersize,"fEMCALChargeWeight =%2.2f (EMCAL bayesian weight for charged hadrons)\n",fEMCALChargeWeight) ;
610 parList+=onePar ;
611 snprintf(onePar,buffersize,"fEMCALNeutralWeight =%2.2f (EMCAL bayesian weight for neutral hadrons)\n",fEMCALNeutralWeight) ;
612 parList+=onePar ;
613 snprintf(onePar,buffersize,"fPHOSPhotonWeight =%2.2f (PHOS bayesian weight for photons)\n",fPHOSPhotonWeight) ;
614 parList+=onePar ;
615 snprintf(onePar,buffersize,"fPHOSPi0Weight =%2.2f (PHOS bayesian weight for pi0)\n",fPHOSPi0Weight) ;
616 parList+=onePar ;
617 snprintf(onePar,buffersize,"fPHOSElectronWeight =%2.2f(PHOS bayesian weight for electrons)\n",fPHOSElectronWeight) ;
618 parList+=onePar ;
619 snprintf(onePar,buffersize,"fPHOSChargeWeight =%2.2f (PHOS bayesian weight for charged hadrons)\n",fPHOSChargeWeight) ;
620 parList+=onePar ;
621 snprintf(onePar,buffersize,"fPHOSNeutralWeight =%2.2f (PHOS bayesian weight for neutral hadrons)\n",fPHOSNeutralWeight) ;
622 parList+=onePar ;
623
624 if(fPHOSWeightFormula){
625 snprintf(onePar,buffersize,"PHOS Photon Weight Formula: %s\n",fPHOSPhotonWeightFormulaExpression.Data() ) ;
626 parList+=onePar;
627 snprintf(onePar,buffersize,"PHOS Pi0 Weight Formula: %s\n",fPHOSPi0WeightFormulaExpression.Data() ) ;
628 parList+=onePar;
629 }
630 }
631 else {
632 snprintf(onePar,buffersize,"EMCAL: fEMCALL0CutMin =%2.2f, fEMCALL0CutMax =%2.2f (Cut on Shower Shape) \n",fEMCALL0CutMin, fEMCALL0CutMax) ;
633 parList+=onePar ;
634 snprintf(onePar,buffersize,"EMCAL: fEMCALDEtaCut =%2.2f, fEMCALDPhiCut =%2.2f (Cut on track matching) \n",fEMCALDEtaCut, fEMCALDPhiCut) ;
635 parList+=onePar ;
636 snprintf(onePar,buffersize,"fTOFCut =%e (Cut on TOF, used in PID evaluation) \n",fTOFCut) ;
637 parList+=onePar ;
638 snprintf(onePar,buffersize,"fPHOSRCut =%2.2f, fPHOSDispersionCut =%2.2f (Cut on Shower Shape and CPV) \n",fPHOSRCut,fPHOSDispersionCut) ;
639 parList+=onePar ;
640
a5fb4114 641 }
477d6cee 642
3c1d9afb 643 if(fDoClusterSplitting)
644 {
645 snprintf(onePar,buffersize,"%2.2f< M02 < %2.2f \n", fSplitM02MinCut, fSplitM02MaxCut) ;
646 parList+=onePar ;
647 snprintf(onePar,buffersize,"fMinNCells =%d \n", fSplitMinNCells) ;
648 parList+=onePar ;
649 snprintf(onePar,buffersize,"pi0 : %2.1f < m <%2.1f\n", fMassPi0Min,fMassPi0Max);
650 parList+=onePar ;
651 snprintf(onePar,buffersize,"eta : %2.1f < m <%2.1f\n", fMassEtaMin,fMassEtaMax);
652 parList+=onePar ;
653 snprintf(onePar,buffersize,"conv: %2.1f < m <%2.1f\n", fMassPhoMin,fMassPhoMax);
654 parList+=onePar ;
655 }
656
477d6cee 657 return parList;
658
1c5acb87 659}
660
49b5c49b 661//________________________________________________
1c5acb87 662void AliCaloPID::Print(const Option_t * opt) const
663{
477d6cee 664
665 //Print some relevant parameters set for the analysis
666 if(! opt)
667 return;
668
669 printf("***** Print: %s %s ******\n", GetName(), GetTitle() ) ;
670
3c1d9afb 671 if(fUseBayesianWeights)
672 {
49b5c49b 673 printf("PHOS PID weight , photon %0.2f, pi0 %0.2f, e %0.2f, charge %0.2f, neutral %0.2f \n",
3c1d9afb 674 fPHOSPhotonWeight, fPHOSPi0Weight,
675 fPHOSElectronWeight, fPHOSChargeWeight, fPHOSNeutralWeight) ;
49b5c49b 676 printf("EMCAL PID weight, photon %0.2f, pi0 %0.2f, e %0.2f, charge %0.2f, neutral %0.2f\n",
3c1d9afb 677 fEMCALPhotonWeight, fEMCALPi0Weight,
678 fEMCALElectronWeight, fEMCALChargeWeight, fEMCALNeutralWeight) ;
49b5c49b 679
680 printf("PHOS Parametrized weight on? = %d\n", fPHOSWeightFormula) ;
3c1d9afb 681 if(fPHOSWeightFormula)
682 {
49b5c49b 683 printf("Photon weight formula = %s\n", fPHOSPhotonWeightFormulaExpression.Data());
684 printf("Pi0 weight formula = %s\n", fPHOSPi0WeightFormulaExpression .Data());
685 }
686 if(fRecalculateBayesian) printf(" Recalculate bayesian with Particle Flux? = %d\n",fParticleFlux);
687 }
3c1d9afb 688 else
689 {
690 printf("TOF cut = %e\n", fTOFCut);
691 printf("EMCAL Lambda0 cut min = %2.2f; max = %2.2f\n", fEMCALL0CutMin,fEMCALL0CutMax);
692 printf("EMCAL cluster-track dEta < %2.3f; dPhi < %2.3f\n", fEMCALDEtaCut, fEMCALDPhiCut);
693 printf("PHOS Treac matching cut =%2.2f, Dispersion Cut =%2.2f \n",fPHOSRCut, fPHOSDispersionCut) ;
49b5c49b 694
a5fb4114 695 }
477d6cee 696
3c1d9afb 697 if(fDoClusterSplitting)
698 {
699 printf("Min. N Cells =%d \n", fSplitMinNCells) ;
700 printf("%2.2f < lambda_0^2 <%2.2f \n",fSplitM02MinCut,fSplitM02MaxCut);
701 printf("pi0 : %2.2f<m<%2.2f \n", fMassPi0Min,fMassPi0Max);
702 printf("eta : %2.2f<m<%2.2f \n", fMassEtaMin,fMassEtaMax);
703 printf("phot: %2.2f<m<%2.2f \n", fMassPhoMin,fMassPhoMax);
704 }
705
477d6cee 706 printf(" \n");
707
1c5acb87 708}
709
3c1d9afb 710//_________________________________________________________________
711void AliCaloPID::PrintClusterPIDWeights(const Double_t * pid) const
712{
713 // print PID of cluster, (AliVCluster*)cluster->GetPID()
714
c2791479 715 printf("AliCaloPID::PrintClusterPIDWeights() \n \t ph %0.2f, pi0 %0.2f, el %0.2f, conv el %0.2f, \n \t \
3c1d9afb 716 pion %0.2f, kaon %0.2f, proton %0.2f , neutron %0.2f, kaon %0.2f \n",
717 pid[AliVCluster::kPhoton], pid[AliVCluster::kPi0],
718 pid[AliVCluster::kElectron], pid[AliVCluster::kEleCon],
719 pid[AliVCluster::kPion], pid[AliVCluster::kKaon],
720 pid[AliVCluster::kProton],
721 pid[AliVCluster::kNeutron], pid[AliVCluster::kKaon0]);
722
723}
724
49b5c49b 725//___________________________________________________________________________
3c1d9afb 726void AliCaloPID::SetPIDBits(AliVCluster * cluster,
49b5c49b 727 AliAODPWG4Particle * ph, AliCalorimeterUtils* cu,
728 AliVEvent* event)
729{
477d6cee 730 //Set Bits for PID selection
731
732 //Dispersion/lambdas
5ae09196 733 //Double_t disp= cluster->GetDispersion() ;
734 Double_t l1 = cluster->GetM20() ;
735 Double_t l0 = cluster->GetM02() ;
736 Bool_t isDispOK = kTRUE ;
9a6fa057 737 if(cluster->IsPHOS()){
49b5c49b 738 if(TestPHOSDispersion(ph->Pt(),l0,l1) < fPHOSDispersionCut) isDispOK = kTRUE;
739 else isDispOK = kFALSE;
5ae09196 740 }
741 else{//EMCAL
742
49b5c49b 743 if(l0 > fEMCALL0CutMin && l0 < fEMCALL0CutMax) isDispOK = kTRUE;
744
5ae09196 745 }
746
747 ph->SetDispBit(isDispOK) ;
477d6cee 748
749 //TOF
750 Double_t tof=cluster->GetTOF() ;
751 ph->SetTOFBit(TMath::Abs(tof)<fTOFCut) ;
752
49b5c49b 753 //Charged
754 Bool_t isNeutral = IsTrackMatched(cluster,cu,event);
5ae09196 755
756 ph->SetChargedBit(isNeutral);
477d6cee 757
758 //Set PID pdg
3c1d9afb 759 ph->SetIdentifiedParticleType(GetIdentifiedParticleType(cluster));
477d6cee 760
5a72d9af 761 if(fDebug > 0)
762 {
5ae09196 763 printf("AliCaloPID::SetPIDBits: TOF %e, Lambda0 %2.2f, Lambda1 %2.2f\n",tof , l0, l1);
477d6cee 764 printf("AliCaloPID::SetPIDBits: pdg %d, bits: TOF %d, Dispersion %d, Charge %d\n",
49b5c49b 765 ph->GetIdentifiedParticleType(), ph->GetTOFBit() , ph->GetDispBit() , ph->GetChargedBit());
477d6cee 766 }
1c5acb87 767}
768
09273901 769//_________________________________________________________
49b5c49b 770Bool_t AliCaloPID::IsTrackMatched(AliVCluster* cluster,
771 AliCalorimeterUtils * cu,
772 AliVEvent* event) const
773{
5ae09196 774 //Check if there is any track attached to this cluster
775
776 Int_t nMatches = cluster->GetNTracksMatched();
49b5c49b 777 AliVTrack * track = 0;
778 Double_t p[3];
779
44443bbd 780 if(nMatches > 0)
781 {
49b5c49b 782 //In case of ESDs, by default without match one entry with negative index, no match, reject.
783 if(!strcmp("AliESDCaloCluster",Form("%s",cluster->ClassName())))
784 {
785 Int_t iESDtrack = cluster->GetTrackMatchedIndex();
786 if(iESDtrack >= 0) track = dynamic_cast<AliVTrack*> (event->GetTrack(iESDtrack));
787 else return kFALSE;
d39cba7e 788
44443bbd 789 if (!track)
790 {
791 if(fDebug > 0) printf("AliCaloPID::IsTrackMatched() - Null matched track in ESD when index is OK!\n");
49b5c49b 792 return kFALSE;
793 }
794 }
795 else { // AOD
796 track = dynamic_cast<AliVTrack*> (cluster->GetTrackMatched(0));
44443bbd 797 if (!track)
798 {
799 if(fDebug > 0) printf("AliCaloPID::IsTrackMatched() - Null matched track in AOD!\n");
49b5c49b 800 return kFALSE;
c76f0089 801 }
d39cba7e 802 }
5ae09196 803
49b5c49b 804 Float_t dZ = cluster->GetTrackDz();
805 Float_t dR = cluster->GetTrackDx();
806
807 // if track matching was recalculated
44443bbd 808 if(cluster->IsEMCAL() && cu && cu->IsRecalculationOfClusterTrackMatchingOn())
809 {
49b5c49b 810 dR = 2000., dZ = 2000.;
31ae6d59 811 cu->GetEMCALRecoUtils()->GetMatchedResiduals(cluster->GetID(),dZ,dR);
49b5c49b 812 }
09273901 813
44443bbd 814 if(cluster->IsPHOS())
815 {
49b5c49b 816 track->GetPxPyPz(p) ;
817 TLorentzVector trackmom(p[0],p[1],p[2],0);
818 Int_t charge = track->Charge();
819 Double_t mf = event->GetMagneticField();
820 if(TestPHOSChargedVeto(dR, dZ, trackmom.Pt(), charge, mf ) < fPHOSRCut) return kTRUE;
821 else return kFALSE;
822
823 }//PHOS
5a72d9af 824 else //EMCAL
825 {
826 if(fDebug > 1)
49b5c49b 827 printf("AliCaloPID::IsTrackMatched - EMCAL dR %f < %f, dZ %f < %f \n",dR, fEMCALDPhiCut, dZ, fEMCALDEtaCut);
828
829 if(TMath::Abs(dR) < fEMCALDPhiCut &&
830 TMath::Abs(dZ) < fEMCALDEtaCut) return kTRUE;
831 else return kFALSE;
832
833 }//EMCAL cluster
834
835
836 } // more than 1 match, at least one track in array
837 else return kFALSE;
838
839}
840
841//___________________________________________________________________________________________________
842Float_t AliCaloPID::TestPHOSDispersion(const Double_t pt, const Double_t l1, const Double_t l2) const
843{
844 //Check if cluster photon-like. Uses photon cluster parameterization in real pp data
845 //Returns distance in sigmas. Recommended cut 2.5
846
847 Double_t l2Mean = 1.53126+9.50835e+06/(1.+1.08728e+07*pt+1.73420e+06*pt*pt) ;
848 Double_t l1Mean = 1.12365+0.123770*TMath::Exp(-pt*0.246551)+5.30000e-03*pt ;
849 Double_t l2Sigma = 6.48260e-02+7.60261e+10/(1.+1.53012e+11*pt+5.01265e+05*pt*pt)+9.00000e-03*pt;
850 Double_t l1Sigma = 4.44719e-04+6.99839e-01/(1.+1.22497e+00*pt+6.78604e-07*pt*pt)+9.00000e-03*pt;
851 Double_t c =-0.35-0.550*TMath::Exp(-0.390730*pt) ;
f3138ecf 852 Double_t r2 = 0.5* (l1-l1Mean)*(l1-l1Mean)/l1Sigma/l1Sigma +
49b5c49b 853 0.5* (l2-l2Mean)*(l2-l2Mean)/l2Sigma/l2Sigma +
854 0.5*c*(l1-l1Mean)*(l2-l2Mean)/l1Sigma/l2Sigma ;
855
f3138ecf 856 if(fDebug > 0) printf("AliCaloPID::TestPHOSDispersion() - PHOS SS R %f < %f?\n", TMath::Sqrt(r2), fPHOSDispersionCut);
5ae09196 857
f3138ecf 858 return TMath::Sqrt(r2) ;
5ae09196 859
860}
861
49b5c49b 862//_______________________________________________________________________________________________
863Float_t AliCaloPID::TestPHOSChargedVeto(const Double_t dx, const Double_t dz, const Double_t pt,
864 const Int_t charge, const Double_t mf) const
865{
866 //Checks distance to the closest track. Takes into account
867 //non-perpendicular incidence of tracks.
868 //returns distance in sigmas. Recommended cut: 2.
869 //Requires (sign) of magnetic filed. onc can find it for example as following
870 // Double_t mf=0. ;
871 // AliESDEvent *event = dynamic_cast<AliESDEvent*>(InputEvent());
872 // if(event)
873 // mf = event->GetMagneticField(); //Positive for ++ and negative for --
874
875
876 Double_t meanX = 0.;
877 Double_t meanZ = 0.;
878 Double_t sx = TMath::Min(5.4,2.59719e+02*TMath::Exp(-pt/1.02053e-01)+
879 6.58365e-01*5.91917e-01*5.91917e-01/((pt-9.61306e-01)*(pt-9.61306e-01)+5.91917e-01*5.91917e-01)+
880 1.59219);
881 Double_t sz = TMath::Min(2.75,4.90341e+02*1.91456e-02*1.91456e-02/(pt*pt+1.91456e-02*1.91456e-02)+
882 1.60) ;
883
884 if(mf<0.){ //field --
885 meanZ = -0.468318 ;
886 if(charge>0)
887 meanX = TMath::Min(7.3, 3.89994*1.20679 *1.20679 /(pt*pt+1.20679*1.20679)+
888 0.249029+2.49088e+07*TMath::Exp(-pt*3.33650e+01)) ;
889 else
890 meanX =-TMath::Min(7.7, 3.86040*0.912499*0.912499/(pt*pt+0.912499*0.912499)+
891 1.23114 +4.48277e+05*TMath::Exp(-pt*2.57070e+01)) ;
892 }
893 else{ //Field ++
894 meanZ = -0.468318;
895 if(charge>0)
896 meanX =-TMath::Min(8.0,3.86040*1.31357*1.31357/(pt*pt+1.31357*1.31357)+
897 0.880579+7.56199e+06*TMath::Exp(-pt*3.08451e+01)) ;
898 else
899 meanX = TMath::Min(6.85, 3.89994*1.16240*1.16240/(pt*pt+1.16240*1.16240)-
900 0.120787+2.20275e+05*TMath::Exp(-pt*2.40913e+01)) ;
901 }
9a6fa057 902
49b5c49b 903 Double_t rz = (dz-meanZ)/sz ;
904 Double_t rx = (dx-meanX)/sx ;
9a6fa057 905
49b5c49b 906 if(fDebug > 0)
907 printf("AliCaloPID::TestPHOSDispersion() - PHOS Matching R %f < %f\n",TMath::Sqrt(rx*rx+rz*rz), fPHOSRCut);
9a6fa057 908
49b5c49b 909 return TMath::Sqrt(rx*rx+rz*rz) ;
9a6fa057 910
911}