2 /**************************************************************************
3 * Copyright(c) 1998-2009, ALICE Experiment at CERN, All rights reserved. *
5 * Author: The ALICE Off-line Project. *
6 * Contributors are mentioned in the code where appropriate. *
8 * Permission to use, copy, modify and distribute this software and its *
9 * documentation strictly for non-commercial purposes is hereby granted *
10 * without fee, provided that the above copyright notice appears in all *
11 * copies and that both the copyright notice and this permission notice *
12 * appear in the supporting documentation. The authors make no claims *
13 * about the suitability of this software for any purpose. It is *
14 * provided "as is" without express or implied warranty. *
15 **************************************************************************/
17 //-----------------------------------------------------------------
19 //-----------------------------------------------------------------
21 #include "AliHelperPID.h"
22 #include "AliVEvent.h"
23 #include "AliAODEvent.h"
24 #include "AliMCEvent.h"
25 #include "AliMCEventHandler.h"
30 #include "AliVTrack.h"
31 #include "TParticle.h"
32 #include "AliAODMCParticle.h"
33 #include "AliPIDResponse.h"
34 #include "AliAnalysisManager.h"
35 #include "AliInputEventHandler.h"
37 using namespace AliHelperPIDNameSpace;
40 const char * kPIDTypeName[]={"TPC","TOF","TPC-TOF"} ;
41 const char * kDetectorName[]={"TPC","TOF"} ;
42 const char * kParticleSpeciesName[]={"Pions","Kaons","Protons","Undefined"} ;
44 ClassImp(AliHelperPID)
46 AliHelperPID::AliHelperPID() : TNamed("HelperPID", "PID object"),fisMC(0), fPIDType(kNSigmaTPCTOF), fNSigmaPID(3), fPIDResponse(0),fOutputList(0),fRequestTOFPID(1),fUseExclusiveNSigma(0),fPtTOFPID(.6),fHasTOFPID(0){
48 for(Int_t ipart=0;ipart<kNSpecies;ipart++)
49 for(Int_t ipid=0;ipid<=kNSigmaPIDType;ipid++)
50 fnsigmas[ipart][ipid]=999.;
52 for(Int_t ipart=0;ipart<kNSpecies;ipart++)fHasDoubleCounting[ipart]=kFALSE;
54 fOutputList = new TList;
55 fOutputList->SetOwner();
56 fOutputList->SetName("OutputList");
59 for(Int_t ipart=0;ipart<kNSpecies;ipart++){
60 for(Int_t ipid=0;ipid<=kNSigmaPIDType;ipid++){
63 if(ipid==kNSigmaTPCTOF){miny=0;maxy=50;}
64 TH2F *fHistoNSigma=new TH2F(Form("NSigma_%d_%d",ipart,ipid),Form("n#sigma %s %s",kParticleSpeciesName[ipart],kPIDTypeName[ipid]),200,0,10,200,miny,maxy);
65 fHistoNSigma->GetXaxis()->SetTitle("P_{T} (GeV / c)");
66 fHistoNSigma->GetYaxis()->SetTitle(Form("n#sigma %s %s",kParticleSpeciesName[ipart],kPIDTypeName[ipid]));
67 fOutputList->Add(fHistoNSigma);
72 for(Int_t ipart=0;ipart<kNSpecies;ipart++){
73 for(Int_t ipid=0;ipid<=kNSigmaPIDType;ipid++){
76 if(ipid==kNSigmaTPCTOF){miny=0;maxy=20;}
77 TH2F *fHistoNSigma=new TH2F(Form("NSigmaRec_%d_%d",ipart,ipid),
78 Form("n#sigma for reconstructed %s %s",kParticleSpeciesName[ipart],kPIDTypeName[ipid]),200,0,10,100,miny,maxy);
79 fHistoNSigma->GetXaxis()->SetTitle("P_{T} (GeV / c)");
80 fHistoNSigma->GetYaxis()->SetTitle(Form("n#sigma %s %s",kParticleSpeciesName[ipart],kPIDTypeName[ipid]));
81 fOutputList->Add(fHistoNSigma);
86 for(Int_t ipart=0;ipart<kNSpecies;ipart++){
87 for(Int_t ipid=0;ipid<=kNSigmaPIDType;ipid++){
90 if(ipid==kNSigmaTPCTOF){miny=0;maxy=20;}
91 TH2F *fHistoNSigma=new TH2F(Form("NSigmaDC_%d_%d",ipart,ipid),
92 Form("n#sigma for double counting %s %s",kParticleSpeciesName[ipart],kPIDTypeName[ipid]),200,0,10,100,miny,maxy);
93 fHistoNSigma->GetXaxis()->SetTitle("P_{T} (GeV / c)");
94 fHistoNSigma->GetYaxis()->SetTitle(Form("n#sigma %s %s",kParticleSpeciesName[ipart],kPIDTypeName[ipid]));
95 fOutputList->Add(fHistoNSigma);
100 for(Int_t ipart=0;ipart<kNSpecies;ipart++){
101 for(Int_t ipid=0;ipid<=kNSigmaPIDType;ipid++){
104 if(ipid==kNSigmaTPCTOF){miny=0;maxy=50;}
105 TH2F *fHistoNSigma=new TH2F(Form("NSigmaMC_%d_%d",ipart,ipid),
106 Form("n#sigma for MC %s %s",kParticleSpeciesName[ipart],kPIDTypeName[ipid]),200,0,10,100,miny,maxy);
107 fHistoNSigma->GetXaxis()->SetTitle("P_{T} (GeV / c)");
108 fHistoNSigma->GetYaxis()->SetTitle(Form("n#sigma %s %s",kParticleSpeciesName[ipart],kPIDTypeName[ipid]));
109 fOutputList->Add(fHistoNSigma);
114 for(Int_t idet=0;idet<kNDetectors;idet++){
116 if(idet==kTOF)maxy=200000;
117 TH2F *fHistoPID=new TH2F(Form("PID_%d",idet),Form("%s signal",kDetectorName[idet]),200,0,10,200,-maxy,maxy);
118 fHistoPID->GetXaxis()->SetTitle("P (GeV / c)");
119 fHistoPID->GetYaxis()->SetTitle(Form("%s signal",kDetectorName[idet]));
120 fOutputList->Add(fHistoPID);
124 //////////////////////////////////////////////////////////////////////////////////////////////////
126 TH2F* AliHelperPID::GetHistogram2D(const char * name){
127 // returns histo named name
128 return (TH2F*) fOutputList->FindObject(name);
131 //////////////////////////////////////////////////////////////////////////////////////////////////
133 Int_t AliHelperPID::GetParticleSpecies(AliVTrack * trk, Bool_t FIllQAHistos){
134 //return the specie according to the minimum nsigma value
135 //no double counting, this has to be evaluated using CheckDoubleCounting()
136 //Printf("fPtTOFPID %.1f, fRequestTOFPID %d, fNSigmaPID %.1f, fPIDType %d",fPtTOFPID,fRequestTOFPID,fNSigmaPID,fPIDType);
138 CalculateNSigmas(trk,FIllQAHistos);//fill the data member fnsigmas with the nsigmas value [ipart][iPID]
140 if(fUseExclusiveNSigma){
142 HasDC=GetDoubleCounting(trk,kFALSE);
143 for(Int_t ipart=0;ipart<kNSpecies;ipart++){
144 if(HasDC[ipart]==kTRUE) return kSpUndefined;
147 else return FindMinNSigma(trk,FIllQAHistos);//NSigmaRec distr filled here
151 //////////////////////////////////////////////////////////////////////////////////////////////////
153 void AliHelperPID::CalculateNSigmas(AliVTrack * trk, Bool_t FIllQAHistos){
154 //defines data member fnsigmas
156 AliAnalysisManager *man = AliAnalysisManager::GetAnalysisManager();
157 AliInputEventHandler* inputHandler = (AliInputEventHandler*)(man->GetInputEventHandler());
158 fPIDResponse = inputHandler->GetPIDResponse();
161 AliFatal("Cannot get pid response");
164 // Compute nsigma for each hypthesis
165 AliVParticle *inEvHMain = dynamic_cast<AliVParticle *>(trk);
167 Double_t nsigmaTPCkProton = fPIDResponse->NumberOfSigmasTPC(inEvHMain, AliPID::kProton);
168 Double_t nsigmaTPCkKaon = fPIDResponse->NumberOfSigmasTPC(inEvHMain, AliPID::kKaon);
169 Double_t nsigmaTPCkPion = fPIDResponse->NumberOfSigmasTPC(inEvHMain, AliPID::kPion);
171 Double_t nsigmaTOFkProton=999.,nsigmaTOFkKaon=999.,nsigmaTOFkPion=999.;
172 Double_t nsigmaTPCTOFkProton=999.,nsigmaTPCTOFkKaon=999.,nsigmaTPCTOFkPion=999.;
176 if(fHasTOFPID && trk->Pt()>fPtTOFPID){//use TOF information
177 nsigmaTOFkProton = fPIDResponse->NumberOfSigmasTOF(inEvHMain, AliPID::kProton);
178 nsigmaTOFkKaon = fPIDResponse->NumberOfSigmasTOF(inEvHMain, AliPID::kKaon);
179 nsigmaTOFkPion = fPIDResponse->NumberOfSigmasTOF(inEvHMain, AliPID::kPion);
181 nsigmaTPCTOFkProton = TMath::Sqrt((nsigmaTPCkProton*nsigmaTPCkProton+nsigmaTOFkProton*nsigmaTOFkProton)/2.);
182 nsigmaTPCTOFkKaon = TMath::Sqrt((nsigmaTPCkKaon*nsigmaTPCkKaon+nsigmaTOFkKaon*nsigmaTOFkKaon)/2.);
183 nsigmaTPCTOFkPion = TMath::Sqrt((nsigmaTPCkPion*nsigmaTPCkPion+nsigmaTOFkPion*nsigmaTOFkPion)/2.);
186 // if TOF is missing and below fPtTOFPID only the TPC information is used
187 nsigmaTPCTOFkProton = TMath::Abs(nsigmaTPCkProton);
188 nsigmaTPCTOFkKaon = TMath::Abs(nsigmaTPCkKaon);
189 nsigmaTPCTOFkPion = TMath::Abs(nsigmaTPCkPion);
192 //set data member fnsigmas
193 fnsigmas[kSpPion][kNSigmaTPC]=nsigmaTPCkPion;
194 fnsigmas[kSpKaon][kNSigmaTPC]=nsigmaTPCkKaon;
195 fnsigmas[kSpProton][kNSigmaTPC]=nsigmaTPCkProton;
196 fnsigmas[kSpPion][kNSigmaTOF]=nsigmaTOFkPion;
197 fnsigmas[kSpKaon][kNSigmaTOF]=nsigmaTOFkKaon;
198 fnsigmas[kSpProton][kNSigmaTOF]=nsigmaTOFkProton;
199 fnsigmas[kSpPion][kNSigmaTPCTOF]=nsigmaTPCTOFkPion;
200 fnsigmas[kSpKaon][kNSigmaTPCTOF]=nsigmaTPCTOFkKaon;
201 fnsigmas[kSpProton][kNSigmaTPCTOF]=nsigmaTPCTOFkProton;
204 //Fill NSigma SeparationPlot
205 for(Int_t ipart=0;ipart<kNSpecies;ipart++){
206 for(Int_t ipid=0;ipid<=kNSigmaPIDType;ipid++){
207 if((ipid!=kNSigmaTPC) && (!fHasTOFPID) && trk->Pt()<fPtTOFPID)continue;//not filling TOF and combined if no TOF PID
208 TH2F *h=GetHistogram2D(Form("NSigma_%d_%d",ipart,ipid));
209 h->Fill(trk->Pt(),fnsigmas[ipart][ipid]);
212 //Fill PID signal plot
213 for(Int_t idet=0;idet<kNDetectors;idet++){
214 TH2F *h=GetHistogram2D(Form("PID_%d",idet));
215 if(idet==kTPC)h->Fill(trk->P(),trk->GetTPCsignal()*trk->Charge());
216 if(idet==kTOF && fHasTOFPID)h->Fill(trk->P(),trk->GetTOFsignal()*trk->Charge());
221 //////////////////////////////////////////////////////////////////////////////////////////////////
223 Int_t AliHelperPID::FindMinNSigma(AliVTrack * trk,Bool_t FillQAHistos){
226 if(fRequestTOFPID && (!fHasTOFPID) && trk->Pt()>fPtTOFPID)return kSpUndefined;
228 //get the identity of the particle with the minimum Nsigma
229 Double_t nsigmaPion=999., nsigmaKaon=999., nsigmaProton=999.;
232 nsigmaProton = TMath::Abs(fnsigmas[kSpProton][kNSigmaTPC]);
233 nsigmaKaon = TMath::Abs(fnsigmas[kSpKaon][kNSigmaTPC]) ;
234 nsigmaPion = TMath::Abs(fnsigmas[kSpPion][kNSigmaTPC]) ;
237 nsigmaProton = TMath::Abs(fnsigmas[kSpProton][kNSigmaTOF]);
238 nsigmaKaon = TMath::Abs(fnsigmas[kSpKaon][kNSigmaTOF]) ;
239 nsigmaPion = TMath::Abs(fnsigmas[kSpPion][kNSigmaTOF]) ;
241 case kNSigmaTPCTOF://In case of no TOF matching the combined nsigma is the TPC one
242 nsigmaProton = TMath::Abs(fnsigmas[kSpProton][kNSigmaTPCTOF]);
243 nsigmaKaon = TMath::Abs(fnsigmas[kSpKaon][kNSigmaTPCTOF]) ;
244 nsigmaPion = TMath::Abs(fnsigmas[kSpPion][kNSigmaTPCTOF]) ;
248 // guess the particle based on the smaller nsigma (within fNSigmaPID)
249 if( ( nsigmaKaon==nsigmaPion ) && ( nsigmaKaon==nsigmaProton )) return kSpUndefined;//if is the default value for the three
251 if( ( nsigmaKaon < nsigmaPion ) && ( nsigmaKaon < nsigmaProton ) && (nsigmaKaon < fNSigmaPID)){
253 for(Int_t ipid=0;ipid<=kNSigmaPIDType;ipid++){
254 if((ipid!=kNSigmaTPC) && (!fHasTOFPID) && (trk->Pt()<fPtTOFPID))continue;//not filling TOF and combined if no TOF PID
255 TH2F *h=GetHistogram2D(Form("NSigmaRec_%d_%d",kSpKaon,ipid));
256 h->Fill(trk->Pt(),fnsigmas[kSpKaon][ipid]);
261 if( ( nsigmaPion < nsigmaKaon ) && ( nsigmaPion < nsigmaProton ) && (nsigmaPion < fNSigmaPID)){
263 for(Int_t ipid=0;ipid<=kNSigmaPIDType;ipid++){
264 if((ipid!=kNSigmaTPC) && (!fHasTOFPID) && (trk->Pt()<fPtTOFPID))continue;//not filling TOF and combined if no TOF PID
265 TH2F *h=GetHistogram2D(Form("NSigmaRec_%d_%d",kSpPion,ipid));
266 h->Fill(trk->Pt(),fnsigmas[kSpPion][ipid]);
271 if( ( nsigmaProton < nsigmaKaon ) && ( nsigmaProton < nsigmaPion ) && (nsigmaProton < fNSigmaPID)){
273 for(Int_t ipid=0;ipid<=kNSigmaPIDType;ipid++){
274 if((ipid!=kNSigmaTPC) && (!fHasTOFPID) && (trk->Pt()<fPtTOFPID))continue;//not filling TOF and combined if no TOF PID
275 TH2F *h=GetHistogram2D(Form("NSigmaRec_%d_%d",kSpProton,ipid));
276 h->Fill(trk->Pt(),fnsigmas[kSpProton][ipid]);
281 // else, return undefined
285 //////////////////////////////////////////////////////////////////////////////////////////////////
287 Bool_t* AliHelperPID::GetDoubleCounting(AliVTrack * trk,Bool_t FIllQAHistos){
288 //if a particle has double counting set fHasDoubleCounting[ipart]=kTRUE
290 for(Int_t ipart=0;ipart<=kNSpecies;ipart++)fHasDoubleCounting[ipart]=kFALSE;//array with kTRUE for second (or third) identity of the track
292 Int_t MinNSigma=FindMinNSigma(trk,kFALSE);//not filling the NSigmaRec histos
296 if(MinNSigma==kSpUndefined)return fHasDoubleCounting;//in case of undefined no Double counting
298 Double_t nsigmaPion=999., nsigmaKaon=999., nsigmaProton=999.;
301 nsigmaProton = TMath::Abs(fnsigmas[kSpProton][kNSigmaTPC]);
302 nsigmaKaon = TMath::Abs(fnsigmas[kSpKaon][kNSigmaTPC]) ;
303 nsigmaPion = TMath::Abs(fnsigmas[kSpPion][kNSigmaTPC]) ;
306 nsigmaProton = TMath::Abs(fnsigmas[kSpProton][kNSigmaTOF]);
307 nsigmaKaon = TMath::Abs(fnsigmas[kSpKaon][kNSigmaTOF]) ;
308 nsigmaPion = TMath::Abs(fnsigmas[kSpPion][kNSigmaTOF]) ;
310 case kNSigmaTPCTOF://In case of no TOF matching the combined nsigma is the TPC one
311 nsigmaProton = TMath::Abs(fnsigmas[kSpProton][kNSigmaTPCTOF]);
312 nsigmaKaon = TMath::Abs(fnsigmas[kSpKaon][kNSigmaTPCTOF]) ;
313 nsigmaPion = TMath::Abs(fnsigmas[kSpPion][kNSigmaTPCTOF]) ;
316 if(nsigmaPion<fNSigmaPID && MinNSigma!=kSpPion)fHasDoubleCounting[kSpPion]=kTRUE;
317 if(nsigmaKaon<fNSigmaPID && MinNSigma!=kSpKaon)fHasDoubleCounting[kSpKaon]=kTRUE;
318 if(nsigmaProton<fNSigmaPID && MinNSigma!=kSpProton)fHasDoubleCounting[kSpProton]=kTRUE;
321 //fill NSigma distr for double counting
322 for(Int_t ipart=0;ipart<kNSpecies;ipart++){
323 if(fHasDoubleCounting[ipart]){
324 for(Int_t ipid=0;ipid<=kNSigmaPIDType;ipid++){
325 if((ipid!=kNSigmaTPC) && (!fHasTOFPID) && (trk->Pt()<fPtTOFPID))continue;//not filling TOF and combined if no TOF PID
326 TH2F *h=GetHistogram2D(Form("NSigmaDC_%d_%d",ipart,ipid));
327 h->Fill(trk->Pt(),fnsigmas[ipart][ipid]);
332 return fHasDoubleCounting;
335 //////////////////////////////////////////////////////////////////////////////////////////////////
337 Int_t AliHelperPID::GetMCParticleSpecie(AliVEvent* event, AliVTrack * trk, Bool_t FillQAHistos){
338 //return the specie according to the MC truth
341 if(!fisMC)AliFatal("Error: AliHelperPID::GetMCParticleSpecie called on data\n");
346 TString nameoftrack(event->ClassName());
347 if(!nameoftrack.CompareTo("AliESDEvent"))isESD=kTRUE;
348 else if(!nameoftrack.CompareTo("AliAODEvent"))isAOD=kTRUE;
349 else AliFatal("Not processing AODs nor ESDs") ;
352 TClonesArray *arrayMC = 0;
353 arrayMC = (TClonesArray*) event->GetList()->FindObject(AliAODMCParticle::StdBranchName());
354 if (!arrayMC)AliFatal("Error: MC particles branch not found!\n");
355 AliAODMCParticle *partMC = (AliAODMCParticle*) arrayMC->At(TMath::Abs(trk->GetLabel()));
357 AliError("Cannot get MC particle");
360 code=partMC->GetPdgCode();
364 AliMCEventHandler* eventHandler = dynamic_cast<AliMCEventHandler*> (AliAnalysisManager::GetAnalysisManager()->GetMCtruthEventHandler());
365 if (!eventHandler) AliFatal("ERROR: Could not retrieve MC event handler");
366 AliMCEvent* mcEvent = eventHandler->MCEvent();
367 if (!mcEvent)AliFatal("ERROR: Could not retrieve MC event");
368 stack = mcEvent->Stack();
369 if (!stack) AliFatal("ERROR: stack not available\n");
371 part = (TParticle*)stack->Particle(TMath::Abs(trk->GetLabel()));
373 AliError("Cannot get MC particle");
376 code = part->GetPdgCode();
378 switch(TMath::Abs(code)){
381 for(Int_t ipid=0;ipid<=kNSigmaPIDType;ipid++){
382 if((ipid!=kNSigmaTPC) && (!fHasTOFPID) && (trk->Pt()<fPtTOFPID))continue;//not filling TOF and combined if no TOF PID
383 TH2F *h=GetHistogram2D(Form("NSigmaMC_%d_%d",kSpProton,ipid));
384 h->Fill(trk->Pt(),fnsigmas[kSpProton][ipid]);
391 for(Int_t ipid=0;ipid<=kNSigmaPIDType;ipid++){
392 if((ipid!=kNSigmaTPC) && (!fHasTOFPID) && (trk->Pt()<fPtTOFPID))continue;//not filling TOF and combined if no TOF PID
393 TH2F *h=GetHistogram2D(Form("NSigmaMC_%d_%d",kSpKaon,ipid));
394 h->Fill(trk->Pt(),fnsigmas[kSpKaon][ipid]);
401 for(Int_t ipid=0;ipid<=kNSigmaPIDType;ipid++){
402 if((ipid!=kNSigmaTPC) && (!fHasTOFPID) && (trk->Pt()<fPtTOFPID))continue;//not filling TOF and combined if no TOF PID
403 TH2F *h=GetHistogram2D(Form("NSigmaMC_%d_%d",kSpPion,ipid));
404 h->Fill(trk->Pt(),fnsigmas[kSpPion][ipid]);
415 //////////////////////////////////////////////////////////////////////////////////////////////////
417 void AliHelperPID::CheckTOF(AliVTrack * trk)
419 //check if the particle has TOF Matching
421 status=trk->GetStatus();
422 if((status&AliVTrack::kTOFout)==0 || (status&AliVTrack::kTIME)==0)fHasTOFPID=kFALSE;
423 else fHasTOFPID=kTRUE;
424 //in addition to KTOFout and kTIME we look at the pt
425 if(trk->Pt()<fPtTOFPID)fHasTOFPID=kFALSE;
428 //////////////////////////////////////////////////////////////////////////////////////////////////
430 Long64_t AliHelperPID::Merge(TCollection* list)
432 // Merging interface.
433 // Returns the number of merged objects (including this).
439 TIterator* iter = list->MakeIterator();
441 // collections of TList with output histos
444 while ((obj = iter->Next())) {
445 AliHelperPID* entry = dynamic_cast<AliHelperPID*> (obj);
448 TList * outputlist = entry->GetOutputList();
449 collections.Add(outputlist);
452 fOutputList->Merge(&collections);