1 /*************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
16 // Utility class for V0 PID
17 // Identifies Electrons, Pions and Protons using gamma conversions and
18 // the decays of K0s and Lambdas
19 // Containers with samples of Electrons, Pions and Protons can be accessed
20 // via GetListOfElectrons() etc.
23 // Matus Kalisky <matus.kalisky@cern.ch>
24 // Markus Heide <mheide@uni-muenster.de>
25 // Markus Fasel <M.Fasel@gsi.de>
27 #include <TDatabasePDG.h>
28 #include <TObjArray.h>
32 #include <TDatabasePDG.h>
34 #include "AliAODEvent.h"
35 #include "AliAODTrack.h"
37 #include "AliAODVertex.h"
38 #include "AliESDEvent.h"
39 #include "AliESDtrack.h"
41 #include "AliESDVertex.h"
42 #include "AliKFParticle.h"
43 #include "AliKFVertex.h"
44 #include "AliVEvent.h"
45 #include "AliVTrack.h"
47 #include "AliHFEV0pid.h"
50 //____________________________________________________________
51 AliHFEV0pid::AliHFEV0pid():
54 , fPrimaryVertex(NULL)
64 // Default constructor
66 fElectrons = new TObjArray();
67 fPionsK0 = new TObjArray();
68 fPionsL = new TObjArray();
69 fKaons = new TObjArray();
70 fProtons = new TObjArray();
71 fIndices = new AliHFEV0pidTrackIndex;
74 //____________________________________________________________
75 AliHFEV0pid::~AliHFEV0pid(){
80 if(fInputEvent) delete fInputEvent;
81 //if(fPrimaryVertex) delete fPrimaryVertex;
82 if(fElectrons) delete fElectrons;
83 if(fPionsK0) delete fPionsK0;
84 if(fPionsL) delete fPionsL;
85 if(fKaons) delete fKaons;
86 if(fProtons) delete fProtons;
87 if(fIndices) delete fIndices;
91 //____________________________________________________________
92 void AliHFEV0pid::InitQA(){
94 // Initialize QA histograms
97 fQA = new AliHFEcollection("v0pidQA", "QA histograms for V0 PID");
99 // QA histograms for cut statistics
100 fQA->CreateTH1F("h_cutEfficiencyGamma", "Cut Efficiency for Gammas", 10, 0, 10);
101 fQA->CreateTH1F("h_cutEfficiencyK0s", "Cut Efficiency for K0s", 10, 0, 10);
102 fQA->CreateTH1F("h_cutEfficiencyPhi", "Cut Efficiency for Phi", 10, 0, 10);
103 fQA->CreateTH1F("h_cutEfficiencyLambda", "Cut Efficiency for Lambdas", 10, 0, 10);
105 // QA histograms for invariant mass
106 fQA->CreateTH1F("h_InvMassGamma", "Gamma invariant mass; inv mass {[eV/c^{2}]; counts", 100, 0, 0.25);
107 fQA->CreateTH1F("h_InvMassK0s", "K0s invariant mass; inv mass [GeV/c^{2}]; counts", 100, 0.4, 0.65);
108 fQA->CreateTH1F("h_InvMassPhi", "Phi invariant mass; inv mass [GeV/c^{2}]; counts", 100, 0.4, 0.65);
109 fQA->CreateTH1F("h_InvMassLambda", "Lambda invariant mass; inv mass [GeV/c^{2}]; counts", 100, 1.05, 1.15);
111 // QA invariant mass as a functin of pt
112 fQA->CreateTH1Fvector1(20, "h_InvMassGamma_pt", "Gamma invarinat mass in pt bins; inv mass [GeV/c^{2}]; counts", 250, 0, 2);
113 fQA->CreateTH1Fvector1(20, "h_InvMassK0_pt", "K0 invarinat mass in pt bins; inv mass [GeV/c^{2}]; counts", 250, 0, 2);
114 fQA->CreateTH1Fvector1(20, "h_InvMassPhi_pt", "Phi invarinat mass in pt bins; inv mass [GeV/c^{2}]; counts", 250, 0, 2);
115 fQA->CreateTH1Fvector1(20, "h_InvMassLambda_pt", "Lambda invarinat mass in pt bins; inv mass [GeV/c^{2}]; counts", 250, 0, 2);
118 fQA->CreateTH1F("h_Pt_Gamma", "Pt of the gamma conversion; p_{T} (GeV/c); counts", 100, 0, 10);
119 fQA->CreateTH1F("h_Pt_K0", "Pt of the K0; p_{T} (GeV/c); counts", 100, 0, 10);
120 fQA->CreateTH1F("h_Pt_Phi", "Pt of the Phi; p_{T} (GeV/c); counts", 100, 0, 10);
121 fQA->CreateTH1F("h_Pt_Lambda", "Pt of the Lambda; p_{T} (GeV/c); counts", 100, 0, 10);
122 //fQA->CreateTH1F("h_Pt_electrons", "Pt of the conversion electrons; p_{T} (GeV/c); counts");
123 //fQA->CreateTH1F("h_Pt_pionsK0", "Pt of the K0 pions; p_{T} (GeV/c); counts");
124 //fQA->CreateTH1F("h_Pt_pionsL", "Pt of the Lambda pions; p_{T} (GeV/c); counts");
125 //fQA->CreateTH1F("h_Pt_protons", "Pt of the Lambda protons; p_{T} (GeV/c); counts");
128 // QA histogram for both Lambda candidate combinations -
129 fQA->CreateTH2F("h_L0_dca_v_dMass", "L0 dca verus dMass; dMass [GeV/c^{2}]; dDCA [cm]; ", 100, -1., 1., 100, 0., 5.);
132 fQA->CreateTH1F("h_chi2_gamma", "Chi2 for gammas", 10000, 0, 1000);
133 fQA->CreateTH1F("h_chi2_K0s", "Chi2 for K0s", 10000, 0, 500);
134 fQA->CreateTH1F("h_chi2_Phi", "Chi2 for K0s", 10000, 0, 500);
135 fQA->CreateTH1F("h_chi2_Lambda", "Chi2 for Lambdas", 10000, 0, 1000);
139 //____________________________________________________________
140 void AliHFEV0pid::Process(AliVEvent * const inputEvent){
143 // Find protons, pions and electrons using V0 decays and
144 // store the pointers in the TObjArray
146 Int_t nGamma = 0, nK0s = 0, nLambda = 0, nPhi = 0;
147 fInputEvent = inputEvent;
149 fIndices->Init(fInputEvent->GetNumberOfV0s() * 2);
150 fPrimaryVertex = new AliKFVertex(*(fInputEvent->GetPrimaryVertex()));
152 for(Int_t iv0 = 0; iv0 < fInputEvent->GetNumberOfV0s(); iv0++){
153 if(!TString(fInputEvent->IsA()->GetName()).CompareTo("AliESDEvent")){
156 AliESDv0 *esdV0 = (dynamic_cast<AliESDEvent *>(fInputEvent))->GetV0(iv0);
157 if(!esdV0->GetOnFlyStatus()) continue; // Take only V0s from the On-the-fly v0 finder
158 v0status = ProcessV0(esdV0);
162 AliAODv0 *aodV0 = (dynamic_cast<AliAODEvent *>(fInputEvent))->GetV0(iv0);
163 if(aodV0->GetOnFlyStatus()) continue; // Take only V0s from the On-the-fly v0 finder
164 v0status = ProcessV0(aodV0);
167 case kRecoGamma: nGamma++; break;
168 case kRecoK0s: nK0s++; break;
169 case kRecoPhi: nPhi++; break;
170 case kRecoLambda: nLambda++; break;
174 AliDebug(1, Form("Number of gammas : %d", nGamma));
175 AliDebug(1, Form("Number of K0s : %d", nK0s));
176 AliDebug(1, Form("Number of Phis : %d", nPhi));
177 AliDebug(1, Form("Number of Lambdas : %d", nLambda));
179 AliDebug(1, "Number of stored tracks:");
180 AliDebug(1, Form("Number of electrons : %d", fElectrons->GetEntries()));
181 AliDebug(1, Form("Number of K0 pions : %d", fPionsK0->GetEntries()));
182 AliDebug(1, Form("Number of Lambda pions : %d", fPionsL->GetEntries()));
183 AliDebug(1, Form("Number of Phi kaons : %d", fKaons->GetEntries()));
184 AliDebug(1, Form("Number of protons : %d", fProtons->GetEntries()));
186 delete fPrimaryVertex;
189 //____________________________________________________________
190 Int_t AliHFEV0pid::ProcessV0(TObject *v0){
193 // Apply general cut and special cuts for gamma, K0s, Lambda
195 AliVTrack* daughter[2];
196 daughter[0] = dynamic_cast<AliVTrack *>(fInputEvent->GetTrack((dynamic_cast<AliESDv0 *>(v0))->GetPindex()));
197 daughter[1] = dynamic_cast<AliVTrack *>(fInputEvent->GetTrack((dynamic_cast<AliESDv0 *>(v0))->GetPindex()));
198 if(!daughter[0] || !daughter[1]) return kUndef;
201 for(Int_t i=0; i<2; ++i){
202 if(!CutESDtrack(dynamic_cast<AliESDtrack*>(daughter[i]))) return kUndef;
206 if(IsGammaConv(v0)) return kRecoGamma;
207 else if(IsK0s(v0)) return kRecoK0s;
208 else if(IsLambda(v0)) return kRecoLambda;
213 //____________________________________________________________
214 void AliHFEV0pid::Flush(){
218 AliDebug(1, "Flushing containers");
226 //____________________________________________________________
227 Bool_t AliHFEV0pid::IsGammaConv(TObject *v0){
231 AliVTrack* daughter[2];
232 Int_t pIndex = 0, nIndex = 0;
233 Double_t invMass = 0.;
236 AliESDv0 *esdV0 = dynamic_cast<AliESDv0 *>(v0);
237 if(!CutV0(esdV0, kRecoGamma)) return kFALSE;
238 if(LooseRejectK0(esdV0) || LooseRejectLambda(esdV0)) return kFALSE;
240 //invMass = esdV0->GetEffMass(AliPID::kElectron, AliPID::kElectron);
241 invMass = GetEffMass(esdV0, AliPID::kElectron, AliPID::kElectron);
244 pIndex = esdV0->GetPindex();
245 nIndex = esdV0->GetNindex();
247 // AOD Analysis - not possible to cut
248 AliAODv0 *aodV0 = dynamic_cast<AliAODv0 *>(v0);
249 pIndex = aodV0->GetPosID();
250 nIndex = aodV0->GetNegID();
251 invMass = aodV0->InvMass2Prongs(0, 1, kElectron, kElectron);
253 daughter[0] = dynamic_cast<AliVTrack *>(fInputEvent->GetTrack(pIndex));
254 daughter[1] = dynamic_cast<AliVTrack *>(fInputEvent->GetTrack(nIndex));
255 if(!daughter[0] || !daughter[1]) return kFALSE;
257 // Get Invariant mass and chi2/ndf
258 AliKFParticle *kfMother = CreateMotherParticle(daughter[0], daughter[1], TMath::Abs(kElectron), TMath::Abs(kElectron));
259 kfMother->SetProductionVertex(*fPrimaryVertex);
260 kfMother->SetMassConstraint(0, 1.);
261 Double_t ndf = kfMother->GetNDF();
262 Double_t chi2 = kfMother->GetChi2();
265 if(fQA) fQA->Fill("h_chi2_gamma", chi2/ndf);
266 if(chi2/ndf > 7) return kFALSE;
267 Double_t mPt = kfMother->GetPt();
268 fQA->Fill("h_Pt_Gamma", mPt);
269 Int_t ptBin = (int)(mPt*10.0);
270 fQA->Fill("h_InvMassGamma_pt", ptBin+1, invMass);
272 if(fQA) fQA->Fill("h_InvMassGamma", invMass);
273 if(invMass > 0.05) return kFALSE;
275 AliDebug(1, Form("Gamma identified, daughter IDs: %d,%d", daughter[0]->GetID(), daughter[1]->GetID()));
276 // Identified gamma - store tracks in the electron containers
277 if(!fIndices->Find(daughter[0]->GetID())){
278 AliDebug(1, Form("Gamma identified, daughter IDs: %d,%d", daughter[0]->GetID(), daughter[1]->GetID()));
279 fElectrons->Add(daughter[0]);
280 fIndices->Add(daughter[0]->GetID(), AliHFEV0pid::kRecoElectron);
282 if(!fIndices->Find(daughter[1]->GetID())){
283 AliDebug(1, Form("Gamma identified, daughter IDs: %d,%d", daughter[1]->GetID(), daughter[1]->GetID()));
284 fElectrons->Add(daughter[1]);
285 fIndices->Add(daughter[1]->GetID(), AliHFEV0pid::kRecoElectron);
292 //____________________________________________________________
293 Bool_t AliHFEV0pid::IsK0s(TObject *v0){
297 const Double_t kK0smass=TDatabasePDG::Instance()->GetParticle(kK0Short)->Mass(); // PDG K0s mass
298 AliVTrack* daughter[2];
299 Int_t pIndex = 0, nIndex = 0;
300 Double_t invMass = 0.;
303 AliESDv0 *esdV0 = dynamic_cast<AliESDv0 *>(v0);
304 if(!CutV0(esdV0, kRecoK0s)) return kFALSE;
305 invMass = esdV0->GetEffMass(AliPID::kPion, AliPID::kPion);
306 pIndex = esdV0->GetPindex();
307 nIndex = esdV0->GetNindex();
309 // AOD Analysis - not possible to cut
310 AliAODv0 *aodV0 = dynamic_cast<AliAODv0 *>(v0);
311 pIndex = aodV0->GetPosID();
312 nIndex = aodV0->GetNegID();
313 invMass = aodV0->MassK0Short();
315 daughter[0] = dynamic_cast<AliVTrack *>(fInputEvent->GetTrack(pIndex));
316 daughter[1] = dynamic_cast<AliVTrack *>(fInputEvent->GetTrack(nIndex));
317 if(!daughter[0] || !daughter[1]) return kFALSE;
319 // Get Invariant mass and chi2/ndf
320 AliKFParticle *kfMother = CreateMotherParticle(daughter[0], daughter[1], TMath::Abs(kPiPlus), TMath::Abs(kPiPlus));
321 kfMother->SetProductionVertex(*fPrimaryVertex);
322 kfMother->SetMassConstraint(kK0smass, 0.);
323 Double_t ndf = kfMother->GetNDF();
324 Double_t chi2 = kfMother->GetChi2();
327 if(fQA) fQA->Fill("h_chi2_K0s", chi2/ndf);
328 if(chi2/ndf > 5) return kFALSE;
329 Double_t mPt = kfMother->GetPt();
330 fQA->Fill("h_Pt_K0", mPt);
331 Int_t ptBin = (int)(mPt*10.0);
332 fQA->Fill("h_InvMassK0_pt", ptBin+1, invMass);
334 if(fQA) fQA->Fill("h_InvMassK0s", invMass);
336 if(invMass < 0.485 || invMass > 0.51) return kFALSE;
337 AliDebug(1, Form("K0 identified, daughter IDs: %d,%d", daughter[0]->GetID(), daughter[1]->GetID()));
339 // Identified gamma - store tracks in the electron containers
340 if(!fIndices->Find(daughter[0]->GetID())){
341 AliDebug(1, Form("Adding K0 Pion track with ID %d", daughter[0]->GetID()));
342 fPionsK0->Add(daughter[0]);
343 fIndices->Add(daughter[0]->GetID(), AliHFEV0pid::kRecoPionK0);
345 if(!fIndices->Find(daughter[1]->GetID())){
346 AliDebug(1, Form("Adding K0 Pion track with ID %d", daughter[1]->GetID()));
347 fPionsK0->Add(daughter[1]);
348 fIndices->Add(daughter[1]->GetID(), AliHFEV0pid::kRecoPionK0);
353 //____________________________________________________________
354 Bool_t AliHFEV0pid::IsPhi(TObject *v0){
356 // Identify Phi - very preliminary - requires diffrent approach (V0 fnder is not effective)
359 //const Double_t kPhiMass=TDatabasePDG::Instance()->GetParticle(333)->Mass(); // PDG phi mass
360 //AliVTrack* daughter[2];
361 //AliKFParticle *mother = NULL;
362 //Double_t invMass = 0.;
364 Int_t pIndex = 0, nIndex = 0;
367 AliESDv0 *esdV0 = dynamic_cast<AliESDv0 *>(v0);
368 if(!CutV0(esdV0, kRecoPhi)) return kFALSE;
369 if(LooseRejectGamma(esdV0) || LooseRejectK0(esdV0)) return kFALSE;
370 pIndex = esdV0->GetPindex();
371 nIndex = esdV0->GetNindex();
374 // AOD Analysis - not possible to cut
380 //____________________________________________________________
381 Bool_t AliHFEV0pid::IsLambda(TObject *v0){
385 const Double_t kL0mass=TDatabasePDG::Instance()->GetParticle(kLambda0)->Mass(); // PDG lambda mass
386 AliVTrack* daughter[2];
387 Int_t pIndex = 0, nIndex = 0;
388 AliKFParticle *mother[2] = {NULL, NULL};
389 Float_t dMass[2]; // lambda mass difference for the two hypoteses
390 //Int_t lambda = 0; // [1] for lambda and [-1] for anti-lambda
393 Double_t invMass = 0.;
394 Double_t invMassEOD = 0;
397 AliESDv0 *esdV0 = dynamic_cast<AliESDv0 *>(v0);
398 if(!CutV0(esdV0, kRecoLambda)) return kFALSE;
399 if(LooseRejectK0(esdV0) || LooseRejectGamma(esdV0)) return kFALSE;
400 pIndex = esdV0->GetPindex();
401 nIndex = esdV0->GetNindex();
403 //invMass = esdV0->GetEffMass(AliPID::kPion, AliPID::kPion);
407 // AOD Analysis - not possible to cut
409 // again - two cases as above
410 AliAODv0 *aodV0 = dynamic_cast<AliAODv0 *>(v0);
411 pIndex = aodV0->GetPosID();
412 nIndex = aodV0->GetNegID();
413 invMassEOD = aodV0->MassLambda();
416 daughter[0] = dynamic_cast<AliVTrack *>(fInputEvent->GetTrack(pIndex));
417 daughter[1] = dynamic_cast<AliVTrack *>(fInputEvent->GetTrack(nIndex));
418 if(!daughter[0] || !daughter[1]) return kFALSE;
421 // now - go over two case - Lambda and AntiLambda
422 // choose the on ewhere the resulting lambda mass is close to the
423 // expected value and at the same time points closer to the primary vertex in XY plane
425 // A) lambda -> proton + negative-pion
426 // B) anti-lambda -> anti-proton + positive-pion
432 mother[0] = CreateMotherParticle(daughter[0], daughter[1], TMath::Abs(kProton), TMath::Abs(kPiPlus));
433 AliHFELambdaInf lambda0(mother[0], fPrimaryVertex);
436 *fPrimaryVertex -= *mother[0];
437 AddTrackToKFVertex(daughter[0], TMath::Abs(kProton));
438 AddTrackToKFVertex(daughter[1], TMath::Abs(kPiPlus));
443 mother[1] = CreateMotherParticle(daughter[0], daughter[1], TMath::Abs(kPiPlus), TMath::Abs(kProton));
444 AliHFELambdaInf lambda1(mother[1], fPrimaryVertex);
447 dMass[0] = lambda0.GetInvariantMass() - kL0mass;
448 dMass[1] = lambda1.GetInvariantMass() - kL0mass;
449 fQA->Fill("h_L0_dca_v_dMass", dMass[0], lambda0.GetDistanceFromPrimaryVertex());
450 fQA->Fill("h_L0_dca_v_dMass", dMass[1], lambda1.GetDistanceFromPrimaryVertex());
453 // decide on the true Lambda candidate bsaed on
455 // - vertex dca (testing needed first)
457 AliHFELambdaInf *lambdaInf[2] = {&lambda0, &lambda1};
458 Bool_t isLambda = kFALSE;
460 index = (dMass[0] <dMass[1]) ? 0 : 1;
461 invMass = lambdaInf[index]->GetInvariantMass();
462 chi2 = lambdaInf[index]->GetChi2NDF();
463 //if(!IsESDanalysis()){
464 // invMass = invMassEOD;
467 // invMass = mother[index]->GetMass();
469 if(fQA) fQA->Fill("h_chi2_Lambda", chi2);
471 if(fQA) fQA->Fill("h_InvMassLambda", invMass);
472 Double_t mPt = mother[index]->GetPt();
473 fQA->Fill("h_Pt_Lambda", mPt);
474 Int_t ptBin = (int)(mPt*10.0);
475 fQA->Fill("h_InvMassLambda_pt", ptBin+1, invMass);
477 // cut on the invariant mass for the proton and pion selection
478 if(invMass > 1.11 || invMass < 1.12){
479 // Identified lambdas - store the protons and pions and update primary vertex
480 *fPrimaryVertex += *mother[index];
484 if(!fIndices->Find(daughter[0]->GetID())){
485 fProtons->Add(daughter[0]);
486 fIndices->Add(daughter[0]->GetID(), AliHFEV0pid::kRecoProton);
488 if(!fIndices->Find(daughter[1]->GetID())){
489 fPionsL->Add(daughter[1]);
490 fIndices->Add(daughter[1]->GetID(), AliHFEV0pid::kRecoPionL);
495 if(!fIndices->Find(daughter [1]->GetID())){
496 fProtons->Add(daughter[1]);
497 fIndices->Add(daughter[1]->GetID(), AliHFEV0pid::kRecoProton);
499 if(!fIndices->Find(daughter [0]->GetID())){
500 fPionsL->Add(daughter[0]);
501 fIndices->Add(daughter [0]->GetID(), AliHFEV0pid::kRecoPionL);
509 // Add the daughters again to the primary vertex
510 AddTrackToKFVertex(daughter[0], TMath::Abs(kPiPlus));
511 AddTrackToKFVertex(daughter[1], TMath::Abs(kProton));
513 // remove the objects
514 for(Int_t i=0; i<2; ++i){
515 if (mother[i]) delete mother[i];
521 //____________________________________________________________
522 AliKFParticle *AliHFEV0pid::CreateMotherParticle(AliVTrack *pdaughter, AliVTrack *ndaughter, Int_t pspec, Int_t nspec){
524 // Creates a mother particle
526 AliKFParticle pkfdaughter(*pdaughter, pspec);
527 AliKFParticle nkfdaughter(*ndaughter, nspec);
529 // check if the daughter particles are coming from the primary vertex
532 const AliESDVertex *esdvertex = dynamic_cast<const AliESDVertex *>(fInputEvent->GetPrimaryVertex());
533 UShort_t *contrib = esdvertex->GetIndices();
536 for(Int_t id = 0; id < esdvertex->GetNIndices(); id++){
537 if(contrib[id] == pdaughter->GetID()){
538 *fPrimaryVertex -= pkfdaughter;
541 if(contrib[id] == ndaughter->GetID()){
542 *fPrimaryVertex -= nkfdaughter;
545 if(nfound == 2) break;
548 // AOD Analysis: AOD Vertex
549 const AliAODVertex *aodvertex = dynamic_cast<const AliAODVertex *>(fInputEvent->GetPrimaryVertex());
550 if(aodvertex->HasDaughter(pdaughter))
551 *fPrimaryVertex -= pkfdaughter;
552 if(aodvertex->HasDaughter(ndaughter))
553 *fPrimaryVertex -= nkfdaughter;
556 // Create the mother particle and add them to the primary vertex
557 AliKFParticle *mother = new AliKFParticle(pkfdaughter, nkfdaughter);
558 *fPrimaryVertex += *mother;
563 //____________________________________________________________
564 void AliHFEV0pid::AddTrackToKFVertex(AliVTrack *track, Int_t species){
566 // Add track to the primary vertex (if it was used in the vertex
569 Bool_t isAdd = kFALSE;
571 const AliESDVertex *esdvertex = dynamic_cast<const AliESDVertex *>(fInputEvent->GetPrimaryVertex());
572 UShort_t *contrib = esdvertex->GetIndices();
573 for(Int_t id = 0; id < esdvertex->GetNIndices(); id++){
574 if(contrib[id] == track->GetID()){
580 const AliAODVertex *aodvertex = dynamic_cast<const AliAODVertex *>(fInputEvent->GetPrimaryVertex());
581 if(aodvertex->HasDaughter(track)) isAdd = kTRUE;
584 AliKFParticle kftrack(*track, species);
585 *fPrimaryVertex += kftrack;
589 //____________________________________________________________
590 Bool_t AliHFEV0pid::CutV0(AliESDv0 *v0, Int_t V0species){
594 Int_t cutRequired = 0;
595 // For cut always take min and max
596 Double_t cutCosPoint[2] = {0., 0.},
597 cutDCA[2] = {0., 0.},
598 cutProdVtx[2] = {0., 0.},
599 cutOpAng[2] = {0., 0.},
600 cutPsiPair[2] = {0., 0.};
604 cutCosPoint[1] = 0.03;
605 SETBIT(cutRequired, 1);
607 SETBIT(cutRequired, 3);
609 SETBIT(cutRequired, 4);
611 SETBIT(cutRequired, 7);
612 cutPsiPair[1] = 0.05;
613 SETBIT(cutRequired, 9);
616 cutCosPoint[1] = 0.03;
617 SETBIT(cutRequired, 1);
619 SETBIT(cutRequired, 3);
621 SETBIT(cutRequired, 5);
626 cutCosPoint[1] = 0.03;
627 SETBIT(cutRequired, 1);
629 SETBIT(cutRequired, 3);
631 SETBIT(cutRequired, 5);
634 // unidentified, return
639 const Char_t *specname[4] = {"Gamma", "K0s", ", Phi", "Lambda"};
640 sprintf(hname, "h_cutEfficiency%s", specname[V0species-1]);
642 // Cut on pointing angle
643 Double_t cosPoint = v0->GetV0CosineOfPointingAngle();
644 if(TESTBIT(cutRequired, 0) && TMath::ACos(cosPoint) < cutCosPoint[0]) return kFALSE;
645 if(fQA) fQA->Fill(hname, 0);
646 if(TESTBIT(cutRequired, 1) && TMath::ACos(cosPoint) > cutCosPoint[1]) return kFALSE;
647 if(fQA) fQA->Fill(hname, 1);
649 // Cut on DCA between daughters
650 Double_t dca = v0->GetDcaV0Daughters();
651 if(TESTBIT(cutRequired, 2) && dca < cutDCA[0]) return kFALSE;
652 if(fQA) fQA->Fill(hname, 2);
653 if(TESTBIT(cutRequired, 3) && dca > cutDCA[1]) return kFALSE;
654 if(fQA) fQA->Fill(hname, 3);
656 // Cut on reconstructed verted position
659 Double_t r = TMath::Sqrt(x*x + y*y);
660 if(TESTBIT(cutRequired, 4) && r < cutProdVtx[0]) return kFALSE;
661 if(fQA) fQA->Fill(hname, 4);
662 if(TESTBIT(cutRequired, 5) && r > cutProdVtx[1]) return kFALSE;
663 if(fQA) fQA->Fill(hname, 5);
665 //Cut on Opening angle (conversions only)
666 if(TESTBIT(cutRequired, 6) && OpenAngle(v0) < cutOpAng[0]) return kFALSE;
667 if(fQA) fQA->Fill(hname, 6);
668 if(TESTBIT(cutRequired, 7) && OpenAngle(v0) > cutOpAng[1]) return kFALSE;
669 if(fQA) fQA->Fill(hname, 7);
671 //Cut on PsiPair angle (conversons only)
672 if(TESTBIT(cutRequired, 8) && PsiPair(v0) < cutPsiPair[0]) return kFALSE;
673 if(fQA) fQA->Fill(hname, 8);
674 if(TESTBIT(cutRequired, 9) && PsiPair(v0) > cutPsiPair[1]) return kFALSE;
675 if(fQA) fQA->Fill(hname, 9);
679 //____________________________________________________________
680 Bool_t AliHFEV0pid::CutESDtrack(AliESDtrack *track){
684 // Hard coaded cut values for the beginning
687 if(!track) return kFALSE;
690 ULong_t status = track->GetStatus();
692 // DCA - to Vertex R & Z
695 track->GetImpactParameters(dcaR, dcaZ);
696 //if(dcaR > 4.0) return kFALSE;
697 //if(dcaZ > 10.0) return kFALSE;
699 // No. of TPC clusters
700 if(track->GetTPCNcls() < 80) return kFALSE;
703 if(!(status & AliESDtrack::kTPCrefit)) return kFALSE;
705 // Chi2 per TPC cluster
706 Int_t nTPCclusters = track->GetTPCclusters(0);
707 Float_t chi2perTPCcluster = track->GetTPCchi2()/Float_t(nTPCclusters);
708 if(chi2perTPCcluster > 3.5) return kFALSE;
711 Float_t cRatioTPC = track->GetTPCNclsF() > 0. ? static_cast<Float_t>(track->GetTPCNcls())/static_cast<Float_t> (track->GetTPCNclsF()) : 1.;
712 if(cRatioTPC < 0.6) return kFALSE;
715 if(track->GetKinkIndex(0) != 0) return kFALSE;
717 // Covariance matrix - TO BE RECONSIDERED
719 track->GetExternalCovariance(extCov);
720 //if(extCov[0] > 2. ) return kFALSE;
721 //if(extCov[2] > 2. ) return kFALSE;
722 //if(extCov[5] > 0.5) return kFALSE;
723 //if(extCov[9] > 0.5) return kFALSE;
724 //if(extCov[14] > 2. ) return kFALSE;
727 if(track->Pt() < 0.1 || track->Pt() > 100) return kFALSE;
730 if(TMath::Abs(track->Eta()) > 0.9) return kFALSE;
732 // the track made it through! :-)
736 //_________________________________________________
737 Bool_t AliHFEV0pid::LooseRejectK0(AliESDv0 * const v0) const {
739 // Reject K0 based on loose cuts
741 Double_t mass = v0->GetEffMass(AliPID::kPion, AliPID::kPion);
742 if(mass > 0.494 && mass < 0.501) return kTRUE;
746 //_________________________________________________
747 Bool_t AliHFEV0pid::LooseRejectLambda(AliESDv0 * const v0) const {
749 // Reject Lambda based on loose cuts
751 Double_t mass1 = v0->GetEffMass(AliPID::kPion, AliPID::kProton);
752 Double_t mass2 = v0->GetEffMass(AliPID::kProton, AliPID::kPion);
754 if(mass1 > 1.1 && mass1 < 1.12) return kTRUE;
755 if(mass2 > 1.1 && mass2 < 1.12) return kTRUE;
759 //_________________________________________________
760 Bool_t AliHFEV0pid::LooseRejectGamma(AliESDv0 * const v0) const {
762 // Reject Lambda based on loose cuts
765 //Double_t mass = v0->GetEffMass(AliPID::kElectron, AliPID::kElectron);
766 // DEBUG temporary solution, see the comment in GetEffMass
767 Double_t mass = GetEffMass(v0, AliPID::kElectron, AliPID::kElectron);
769 if(mass < 0.02) return kTRUE;
773 //_________________________________________________
774 Float_t AliHFEV0pid::OpenAngle(AliESDv0 *v0) const {
776 // Opening angle between two daughter tracks
778 Double_t mn[3] = {0,0,0};
779 Double_t mp[3] = {0,0,0};
782 v0->GetNPxPyPz(mn[0],mn[1],mn[2]);//reconstructed cartesian momentum components of negative daughter;
783 v0->GetPPxPyPz(mp[0],mp[1],mp[2]);//reconstructed cartesian momentum components of positive daughter;
786 Float_t openAngle = TMath::ACos((mp[0]*mn[0] + mp[1]*mn[1] + mp[2]*mn[2])/(TMath::Sqrt(mp[0]*mp[0] + mp[1]*mp[1] + mp[2]*mp[2])*TMath::Sqrt(mn[0]*mn[0] + mn[1]*mn[1] + mn[2]*mn[2])));
788 return TMath::Abs(openAngle);
791 //_________________________________________________
792 Float_t AliHFEV0pid::PsiPair(AliESDv0 *v0) {
794 // Angle between daughter momentum plane and plane
796 Float_t magField = fInputEvent->GetMagneticField();
798 Int_t pIndex = v0->GetPindex();
799 Int_t nIndex = v0->GetNindex();
801 AliESDtrack* daughter[2];
803 daughter[0] = dynamic_cast<AliESDtrack *>(fInputEvent->GetTrack(pIndex));
804 daughter[1] = dynamic_cast<AliESDtrack *>(fInputEvent->GetTrack(nIndex));
807 v0->GetXYZ(x,y,z);//Reconstructed coordinates of V0; to be replaced by Markus Rammler's method in case of conversions!
809 Double_t mn[3] = {0,0,0};
810 Double_t mp[3] = {0,0,0};
813 v0->GetNPxPyPz(mn[0],mn[1],mn[2]);//reconstructed cartesian momentum components of negative daughter;
814 v0->GetPPxPyPz(mp[0],mp[1],mp[2]);//reconstructed cartesian momentum components of positive daughter;
817 Double_t deltat = 1.;
818 deltat = TMath::ATan(mp[2]/(TMath::Sqrt(mp[0]*mp[0] + mp[1]*mp[1])+1.e-13)) - TMath::ATan(mn[2]/(TMath::Sqrt(mn[0]*mn[0] + mn[1]*mn[1])+1.e-13));//difference of angles of the two daughter tracks with z-axis
820 Double_t radiussum = TMath::Sqrt(x*x + y*y) + 50;//radius to which tracks shall be propagated
822 Double_t momPosProp[3];
823 Double_t momNegProp[3];
825 AliExternalTrackParam pt(*daughter[0]), nt(*daughter[1]);
827 Float_t psiPair = 4.;
829 if(nt.PropagateTo(radiussum,magField) == 0)//propagate tracks to the outside
831 if(pt.PropagateTo(radiussum,magField) == 0)
833 pt.GetPxPyPz(momPosProp);//Get momentum vectors of tracks after propagation
834 nt.GetPxPyPz(momNegProp);
837 TMath::Sqrt(momNegProp[0]*momNegProp[0]+momNegProp[1]*momNegProp[1]+momNegProp[2]*momNegProp[2]);//absolute momentum value of negative daughter
839 TMath::Sqrt(momPosProp[0]*momPosProp[0]+momPosProp[1]*momPosProp[1]+momPosProp[2]*momPosProp[2]);//absolute momentum value of positive daughter
841 Double_t scalarproduct =
842 momPosProp[0]*momNegProp[0]+momPosProp[1]*momNegProp[1]+momPosProp[2]*momNegProp[2];//scalar product of propagated positive and negative daughters' momenta
844 Double_t chipair = TMath::ACos(scalarproduct/(pEle*pPos));//Angle between propagated daughter tracks
846 psiPair = TMath::Abs(TMath::ASin(deltat/chipair));
851 //____________________________________________________________
852 AliHFEV0pid::AliHFEV0pidTrackIndex::AliHFEV0pidTrackIndex():
858 , fIndexElectron(NULL)
865 // Default Constructor
869 //____________________________________________________________
870 AliHFEV0pid::AliHFEV0pidTrackIndex::~AliHFEV0pidTrackIndex(){
874 if(fIndexElectron) delete[] fIndexElectron;
875 if(fIndexPionK0) delete[] fIndexPionK0;
876 if(fIndexPionL) delete[] fIndexPionL;
877 if(fIndexProton) delete[] fIndexProton;
880 //____________________________________________________________
881 void AliHFEV0pid::AliHFEV0pidTrackIndex::Flush(){
886 if(fIndexElectron) delete[] fIndexElectron;
887 fIndexElectron = NULL;
888 if(fIndexPionK0) delete[] fIndexPionK0;
890 if(fIndexPionL) delete[] fIndexPionL;
892 if(fIndexKaon) delete[] fIndexKaon;
894 if(fIndexProton) delete[] fIndexProton;
904 //____________________________________________________________
905 void AliHFEV0pid::AliHFEV0pidTrackIndex::Init(Int_t capacity){
907 // Initialize container
909 fIndexElectron = new Int_t[capacity];
910 fIndexPionK0 = new Int_t[capacity];
911 fIndexPionL = new Int_t[capacity];
912 fIndexProton = new Int_t[capacity];
915 //____________________________________________________________
916 void AliHFEV0pid::AliHFEV0pidTrackIndex::Add(Int_t index, Int_t species){
918 // Add new index to the list of identified particles
921 case AliHFEV0pid::kRecoElectron:
922 fIndexElectron[fNElectrons++] = index;
924 case AliHFEV0pid::kRecoPionK0:
925 fIndexPionK0[fNPionsK0++] = index;
927 case AliHFEV0pid::kRecoPionL:
928 fIndexPionL[fNPionsL++] = index;
930 case AliHFEV0pid::kRecoProton:
931 fIndexProton[fNProtons++] = index;
936 //____________________________________________________________
937 Bool_t AliHFEV0pid::AliHFEV0pidTrackIndex::Find(Int_t index, Int_t species) const {
939 // Find track index in the specific sample of particles
942 Int_t *container = NULL; Int_t n = 0;
944 case AliHFEV0pid::kRecoElectron:
945 container = fIndexElectron;
948 case AliHFEV0pid::kRecoPionK0:
949 container = fIndexPionK0;
952 case AliHFEV0pid::kRecoPionL:
953 container = fIndexPionL;
956 case AliHFEV0pid::kRecoProton:
957 container = fIndexProton;
961 if(!container) return kFALSE;
962 if(n == 0) return kFALSE;
963 Bool_t found = kFALSE;
964 for(Int_t i = 0; i < n; i++){
965 if(container[i] == index){
973 //____________________________________________________________
974 Bool_t AliHFEV0pid::AliHFEV0pidTrackIndex::Find(Int_t index) const {
976 // Find index in all samples
978 if(Find(index, AliHFEV0pid::kRecoElectron)) return kTRUE;
979 else if(Find(index, AliHFEV0pid::kRecoPionK0)) return kTRUE;
980 else if(Find(index, AliHFEV0pid::kRecoPionL)) return kTRUE;
981 else return Find(index, AliHFEV0pid::kRecoProton);
984 //____________________________________________________________
985 AliHFEV0pid::AliHFELambdaInf::AliHFELambdaInf(AliKFParticle *mother, AliKFVertex * const primaryVertex):
994 const Double_t kL0mass=TDatabasePDG::Instance()->GetParticle(kLambda0)->Mass(); // PDG lambda mass
995 fInvariantMass = mother->GetMass();
996 // distance frm the privary vertex and mass difference for the (A) case
997 fDistVtx = mother->GetDistanceFromVertex(*primaryVertex);
998 // apply constraints for the fit
999 mother->SetMassConstraint(kL0mass, 0.);
1000 mother->SetProductionVertex(*primaryVertex);
1001 fChi2NDF = mother->GetChi2()/mother->GetNDF();
1003 //____________________________________________________________
1004 AliHFEV0pid::AliHFELambdaInf::~AliHFELambdaInf(){
1009 //____________________________________________________________
1011 //____________________________________________________________
1012 Double_t AliHFEV0pid::GetEffMass(AliESDv0 *v0, UInt_t p1, UInt_t p2) const{
1014 // TEMPORARY - this function should become obsolete with v4-18-Rev-10 or 11
1015 // calculate effective mass
1017 const Double_t kpmass[5] = {TDatabasePDG::Instance()->GetParticle(kElectron)->Mass(),
1018 TDatabasePDG::Instance()->GetParticle(kMuonMinus)->Mass(),
1019 TDatabasePDG::Instance()->GetParticle(kPiPlus)->Mass(),
1020 TDatabasePDG::Instance()->GetParticle(kKPlus)->Mass(),
1021 TDatabasePDG::Instance()->GetParticle(kProton)->Mass()}; // float
1022 if (p1>4) return -1;
1023 if (p2>4) return -1;
1024 Double_t mass1 = kpmass[p1]; // float
1025 Double_t mass2 = kpmass[p2]; // float
1030 v0->GetPPxPyPz(pMom[0], pMom[1], pMom[2]);
1031 v0->GetNPxPyPz(nMom[0], nMom[1], nMom[2]);
1034 const Double_t *m1 = pMom;
1035 const Double_t *m2 = nMom;
1037 //if (fRP[p1]+fRM[p2]<fRP[p2]+fRM[p1]){
1042 Double_t e1 = TMath::Sqrt(mass1*mass1+
1045 m1[2]*m1[2]); // float
1046 Double_t e2 = TMath::Sqrt(mass2*mass2+
1049 m2[2]*m2[2]); // float
1051 (m2[0]+m1[0])*(m2[0]+m1[0])+
1052 (m2[1]+m1[1])*(m2[1]+m1[1])+
1053 (m2[2]+m1[2])*(m2[2]+m1[2]); // float
1056 mass = (e1+e2)*(e1+e2)-mass;
1057 //if(mass < 0.00001){
1058 // printf("-D: mass: %f\n", mass);
1060 mass = TMath::Sqrt(mass);