9 #include "AliMCParticle.h"
10 //#include "AliStack.h"
12 #include "AliAnalysisTask.h"
13 #include "AliAnalysisManager.h"
15 #include "AliESDEvent.h"
16 #include "AliMCEvent.h"
17 #include "AliESDInputHandler.h"
18 #include "AliInputEventHandler.h"
20 #include "AliVVertex.h"
21 #include "AliAnalysisFilter.h"
23 #include "AliPIDResponse.h"
24 #include "AliTPCPIDResponse.h"
25 //#include "AliTPCParamSR.h"
27 #include "AliTPCPIDEtaTree.h"
30 This task determines the eta dependence of the TPC signal.
31 For this purpose, only tracks fulfilling some standard quality cuts are taken into account.
32 The obtained data can be used to derive the functional behaviour of the eta dependence.
33 Such a function can be plugged into this task to correct for the eta dependence and to see
34 if there is then really no eta dependence left.
36 Class written by Benjamin Hess.
37 Contact: bhess@cern.ch
40 ClassImp(AliTPCPIDEtaTree)
42 //________________________________________________________________________
43 AliTPCPIDEtaTree::AliTPCPIDEtaTree()
45 , fNumEtaCorrReqErrorsIssued(0)
46 , fNumMultCorrReqErrorsIssued(0)
47 , fStoreMultiplicity(kFALSE)
48 , fStoreNumOfSubthresholdclusters(kFALSE)
49 , fStoreNumClustersInActiveVolume(kFALSE)
50 , fDoAdditionalQA(kFALSE)
61 , fTPCsignalNsubthreshold(0)
62 , fNumTPCClustersInActiveVolume(0)
65 , fCorrectdEdxEtaDependence(kFALSE)
66 , fCorrectdEdxMultiplicityDependence(kFALSE)
69 , fOutputContainer(0x0)
71 , fhMultiplicityQA(0x0)
73 // default Constructor
76 //________________________________________________________________________
77 AliTPCPIDEtaTree::AliTPCPIDEtaTree(const char *name)
79 , fNumEtaCorrReqErrorsIssued(0)
80 , fNumMultCorrReqErrorsIssued(0)
81 , fStoreMultiplicity(kFALSE)
82 , fStoreNumOfSubthresholdclusters(kFALSE)
83 , fStoreNumClustersInActiveVolume(kFALSE)
84 , fDoAdditionalQA(kFALSE)
95 , fTPCsignalNsubthreshold(0)
96 , fNumTPCClustersInActiveVolume(0)
99 , fCorrectdEdxEtaDependence(kFALSE)
100 , fCorrectdEdxMultiplicityDependence(kFALSE)
103 , fOutputContainer(0x0)
105 , fhMultiplicityQA(0x0)
109 // Define input and output slots here
110 DefineInput(0, TChain::Class());
111 DefineOutput(1, TTree::Class());
112 DefineOutput(2, TTree::Class());
113 DefineOutput(3, TObjArray::Class());
117 //________________________________________________________________________
118 AliTPCPIDEtaTree::~AliTPCPIDEtaTree()
125 delete fOutputContainer;
126 fOutputContainer = 0x0;
130 //________________________________________________________________________
131 void AliTPCPIDEtaTree::UserCreateOutputObjects()
136 AliTPCPIDBase::UserCreateOutputObjects();
138 if (fDoAdditionalQA) {
141 fOutputContainer = new TObjArray(2);
142 fOutputContainer->SetName(GetName());
143 fOutputContainer->SetOwner(kTRUE);
145 const Int_t nBins = 6;
146 // p_vert, p_TPC, eta, nSigmaTOF, beta, multiplicity
147 Int_t bins[nBins] = { 48, 48, 9, 30, 110, 4 };
148 Double_t xmin[nBins] = { 0.3, 0.3, -0.9, -5.0, 0.0, 0. };
149 Double_t xmax[nBins] = { 2.7, 2.7, 0.9, 5.0, 1.1, 3200 };
152 fhTOFqa = new THnSparseI("hTOFqa","", nBins, bins, xmin, xmax);
153 fhTOFqa->GetAxis(0)->SetTitle("p_{Vertex} (GeV/c)");
154 fhTOFqa->GetAxis(1)->SetTitle("p_{TPC_inner} (GeV/c)");
155 fhTOFqa->GetAxis(2)->SetTitle("#eta");
156 fhTOFqa->GetAxis(3)->SetTitle("n #sigma_{p} TOF");
157 fhTOFqa->GetAxis(4)->SetTitle("#beta");
158 fhTOFqa->GetAxis(5)->SetTitle("Multiplicity");
160 fOutputContainer->Add(fhTOFqa);
164 fhMultiplicityQA = new TH2I("hMultiplicityQA", "Multiplicity check; Contributors to primary vertex per event; Total number of tracks per Event",
165 120, 0, 6000, 400, 0, 20000);
166 fOutputContainer->Add(fhMultiplicityQA);
169 fOutputContainer = new TObjArray(1);
170 fOutputContainer->SetName(GetName());
171 fOutputContainer->SetOwner(kTRUE);
176 fTree = new TTree("fTree", "Tree for analysis of #eta dependence of TPC signal");
177 fTree->Branch("pTPC", &fPtpc);
178 //fTree->Branch("pT", &fPt);
179 fTree->Branch("dEdx", &fDeDx);
180 fTree->Branch("dEdxExpected", &fDeDxExpected);
181 fTree->Branch("tanTheta", &fTanTheta);
182 //fTree->Branch("sinAlpha", &fSinAlpha);
183 //fTree->Branch("y", &fY);
184 //TODO fTree->Branch("phiPrime", &fPhiPrime);
185 fTree->Branch("tpcSignalN", &fTPCsignalN);
187 if (fStoreNumOfSubthresholdclusters)
188 fTree->Branch("tpcSignalNsubthreshold", &fTPCsignalNsubthreshold);
190 if (fStoreNumClustersInActiveVolume)
191 fTree->Branch("numTPCClustersInActiveVolume", &fNumTPCClustersInActiveVolume);
193 fTree->Branch("pidType", &fPIDtype);
195 if (fStoreMultiplicity) {
196 fTree->Branch("fMultiplicity", &fMultiplicity);
201 fTreePions = new TTree("fTreePions", "Tree for analysis of #eta dependence of TPC signal - Pions");
202 fTreePions->Branch("pTPC", &fPtpc);
203 fTreePions->Branch("pT", &fPt);
204 fTreePions->Branch("dEdx", &fDeDx);
205 fTreePions->Branch("dEdxExpected", &fDeDxExpected);
206 fTreePions->Branch("tanTheta", &fTanTheta);
207 fTreePions->Branch("tpcSignalN", &fTPCsignalN);
209 if (fStoreNumOfSubthresholdclusters)
210 fTreePions->Branch("tpcSignalNsubthreshold", &fTPCsignalNsubthreshold);
212 if (fStoreMultiplicity) {
213 fTreePions->Branch("fMultiplicity", &fMultiplicity);
217 PostData(2, fTreePions);
218 PostData(3, fOutputContainer);
222 //________________________________________________________________________
223 void AliTPCPIDEtaTree::UserExec(Option_t *)
226 // Called for each event
228 fESD = dynamic_cast<AliESDEvent*>(InputEvent());
230 Printf("ERROR: fESD not available");
234 fMC = dynamic_cast<AliMCEvent*>(MCEvent());
236 if (!fPIDResponse || !fV0KineCuts)
239 if (!GetVertexIsOk(fESD))
242 const AliVVertex* primaryVertex = fESD->GetPrimaryVertexTracks();
245 //fMultiplicity = primaryVertex->GetNContributors();
248 if(primaryVertex->GetNContributors() <= 0)
251 fMultiplicity = fESD->GetNumberOfESDTracks();
253 if (fDoAdditionalQA) {
254 Int_t nTotTracks = fESD->GetNumberOfESDTracks();
255 fhMultiplicityQA->Fill(primaryVertex->GetNContributors(), nTotTracks);
258 Double_t magField = fESD->GetMagneticField();
260 // Fill V0 arrays with V0s
267 Bool_t etaCorrAvail = fPIDResponse->UseTPCEtaCorrection();
268 Bool_t multCorrAvail = fPIDResponse->UseTPCMultiplicityCorrection();
270 // Track loop to fill a Train spectrum
271 for (Int_t iTracks = 0; iTracks < fESD->GetNumberOfTracks(); iTracks++) {
272 Bool_t isPr = kFALSE;
273 Bool_t isPi = kFALSE;
275 AliESDtrack* track = fESD->GetTrack(iTracks);
277 Printf("ERROR: Could not receive track %d", iTracks);
281 if (TMath::Abs(track->Eta()) > fEtaCut)
284 // Do not distinguish positively and negatively charged V0's
285 Char_t v0tagAllCharges = TMath::Abs(GetV0tag(iTracks));
286 if (v0tagAllCharges == -99) {
287 AliError(Form("Problem with V0 tag list (requested V0 track for track %d from %d (list status %d))!", iTracks, fESD->GetNumberOfTracks(),
292 Bool_t isV0prNotMC = (v0tagAllCharges == 16) && !fMC; // Only accept V0 protons for data, not for MC
293 Bool_t isV0piNotMC = (v0tagAllCharges == 15) && !fMC; // Only accept V0 pions for data, not for MC
295 Bool_t isV0NotMC = isV0prNotMC || isV0piNotMC;
298 if(!isV0NotMC && fTrackFilter && !fTrackFilter->IsSelected(track))
301 // Note: For V0's, the cut on ncl can be done via the tree (value is stored). One should not cut on geometry
302 // for V0's since they have different topology
303 if (!isV0NotMC && GetUseTPCCutMIGeo()) {
304 if (!TPCCutMIGeo(track, InputEvent()))
309 fPtpc = track->GetTPCmomentum();
315 fPhiPrime = GetPhiPrime(track->Phi(), magField, track->Charge());
317 Int_t label = track->GetLabel();
319 AliMCParticle* mcTrack = 0x0;
323 continue; // If MC is available, reject tracks with negative ESD label
324 mcTrack = dynamic_cast<AliMCParticle*>(fMC->GetTrack(TMath::Abs(label)));
326 Printf("ERROR: Could not receive mcTrack with label %d for track %d", label, iTracks);
330 /*// Only accept MC primaries
331 if (!fMC->Stack()->IsPhysicalPrimary(TMath::Abs(label))) {
337 Int_t pdg = mcTrack->PdgCode();
339 if (TMath::Abs(pdg) == 2212) // Proton
341 else if ((pdg == 111 || TMath::Abs(pdg) == 211) && fPtpc <= fPtpcPionCut) // Pion below desired momentum threshold
344 continue; // Only take protons and pions
348 if (pdg == 111 || TMath::Abs(pdg) == 211) {//Pion
351 else if (TMath::Abs(pdg) == 311 || TMath::Abs(pdg) == 321) {//Kaon
354 else if (TMath::Abs(pdg) == 2212) {//Proton
357 else if (TMath::Abs(pdg) == 11) {//Electron
360 else if (TMath::Abs(pdg) == 13) {//Muon
365 fDeDx = track->GetTPCsignal();
367 UInt_t status = track->GetStatus();
368 Bool_t hasTOFout = status&AliESDtrack::kTOFout;
369 Bool_t hasTOFtime = status&AliESDtrack::kTIME;
370 Bool_t hasTOF = kFALSE;
371 if (hasTOFout && hasTOFtime)
373 Float_t length = track->GetIntegratedLength();
374 // Length check only for primaries, not for V0's!
375 if (length < 350 && !isV0NotMC)
379 // Note: Normally, the track cuts include a cut on primaries. Therefore, if the particle is a V0, it would usually
380 // NOT be found via the primary cuts. This means that the PIDtype describes more or less disjoint sets
386 fPIDtype = kV0idNoTOF;
389 if (TMath::Abs(fPIDResponse->NumberOfSigmasTOF(track, AliPID::kProton)) < 3.0)
390 fPIDtype = kV0idPlusTOFaccepted;
392 fPIDtype = kV0idPlusTOFrejected;
395 else if (isV0piNotMC) {
397 if (fPtpc > fPtpcPionCut || fDeDx > 140.) // Reject pions above desired momentum threshold and also reject too high dEdx
403 fPIDtype = kV0idNoTOF;
406 if (TMath::Abs(fPIDResponse->NumberOfSigmasTOF(track, AliPID::kPion)) < 3.0)
407 fPIDtype = kV0idPlusTOFaccepted;
409 fPIDtype = kV0idPlusTOFrejected;
414 isPr = kTRUE; // If particle is accepted, it is a proton (for pions, only V0s are used)
416 if (fPtpc < 4.0 && //TODO was 2.7 // Do not accept non-V0s above this threshold -> High contamination!!!
417 (fDeDx >= 50. / TMath::Power(fPtpc, 1.3))) {// Pattern recognition instead of TPC cut to be ~independent of old TPC expected dEdx
422 else if (hasTOF && TMath::Abs(fPIDResponse->NumberOfSigmasTOF(track, AliPID::kProton)) < 3.0) {
423 fPIDtype = kTPCandTOFid;
426 continue; // Reject particle
429 continue; // Reject particle
433 if (fDoAdditionalQA) {
434 Double_t tofTime = track->GetTOFsignal();//in ps
435 Double_t tof = tofTime * 1E-3; // ns, average T0 fill subtracted, no info from T0detector
436 Double_t length2 = track->GetIntegratedLength();
437 Double_t c = TMath::C() * 1.E-9;// m/ns
438 length2 = length2 * 0.01; // in meters
440 Double_t beta = length2 / tof;
442 Double_t nSigmaTOF = hasTOF ? fPIDResponse->NumberOfSigmasTOF(track, AliPID::kProton) : 999;
444 // p_vert, p_TPC, eta, nSigmaTOF, beta, multiplicity
445 Double_t entry[6] = { track->P(), fPtpc, track->Eta(), nSigmaTOF, beta, (Double_t)fMultiplicity };
446 fhTOFqa->Fill(entry);
449 // Prepare entry for tree (some quantities have already been set)
450 // Turn eta correction off -> Important here is the pure spline value and the selection via cuts. The correction
451 // can be re-done manually, if needed. But it cannot be undone!
453 if (fCorrectdEdxEtaDependence && fNumEtaCorrReqErrorsIssued < 23 && !etaCorrAvail) {
454 AliError("TPC eta correction requested, but was not activated in PID response (most likely not available)!");
455 fNumEtaCorrReqErrorsIssued++;
456 if (fNumEtaCorrReqErrorsIssued == 23)
457 AliError("Ignoring this error from now on!");
460 if (fCorrectdEdxMultiplicityDependence && fNumMultCorrReqErrorsIssued < 23 && !multCorrAvail) {
461 AliError("TPC multiplicity correction requested, but was not activated in PID response (most likely not available)!");
462 fNumMultCorrReqErrorsIssued++;
463 if (fNumMultCorrReqErrorsIssued == 23)
464 AliError("Ignoring this error from now on!");
468 fDeDxExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kProton, AliTPCPIDResponse::kdEdxDefault,
469 fCorrectdEdxEtaDependence && etaCorrAvail,
470 fCorrectdEdxMultiplicityDependence && multCorrAvail);
472 fDeDxExpected = fPIDResponse->GetTPCResponse().GetExpectedSignal(track, AliPID::kPion, AliTPCPIDResponse::kdEdxDefault,
473 fCorrectdEdxEtaDependence && etaCorrAvail,
474 fCorrectdEdxMultiplicityDependence && multCorrAvail);
477 fTanTheta = track->GetInnerParam()->GetTgl();
478 //fSinAlpha = track->GetInnerParam()->GetSnp();
479 //fY = track->GetInnerParam()->GetY();
480 fTPCsignalN = track->GetTPCsignalN();
482 if (fStoreNumOfSubthresholdclusters) {
483 const AliTPCdEdxInfo *clsInfo = track->GetTPCdEdxInfo();
486 Double32_t signal[4] = {0}; // 0: IROC only; 1: OROC short padas; 2: OROC long pads; 3:OROC combined
487 Char_t ncl[3] = {0}; // clusters above threshold; 0: IROC; 1: OROC short; 2: OROC long
488 Char_t nrows[3] = {0}; // clusters above and below threshold; 0: IROC; 1: OROC short; 2: OROC long
490 clsInfo->GetTPCSignalRegionInfo(signal, ncl, nrows);
492 fTPCsignalNsubthreshold = nrows[0] + nrows[1] + nrows[2] - ncl[0] - ncl[1] - ncl[2];
495 fTPCsignalNsubthreshold = 200;// Set to invalid value
499 if (fStoreNumClustersInActiveVolume)
500 fNumTPCClustersInActiveVolume = track->GetLengthInActiveZone(1, 1.8, 220, magField);
502 fNumTPCClustersInActiveVolume = 200.;//Set to invalid value
507 const Double_t tanTheta = track->GetInnerParam()->GetTgl();
509 // Constant in formula for B in kGauss (factor 0.1 to convert B from Tesla to kGauss),
510 // pT in GeV/c (factor c*1e-9 to arrive at GeV/c) and curvature in 1/cm (factor 0.01 to get from m to cm)
511 const Double_t constant = TMath::C()* 1e-9 * 0.1 * 0.01;
512 const Double_t curvature = magField * constant / track->Pt(); // in 1./cm
514 //const Double_t angleIROC = TMath::ASin(TMath::Min(TMath::Abs(par.GetPadRowRadii(0, par.GetNRow(0) / 2.) * curvature) * 0.5, 1.));
515 //const Double_t angleOROC = TMath::ASin(TMath::Min(TMath::Abs(par.GetPadRowRadii(36, par.GetNRow(36) / 2.) * curvature) * 0.5, 1.));
517 Double_t averageddzdr = 0.;
520 for (Double_t r = 85; r < 245; r++) {
521 Double_t sinPhiLocal = TMath::Abs(r*curvature*0.5);
523 // Cut on |sin(phi)| as during reco
524 if (TMath::Abs(sinPhiLocal) <= 0.95) {
525 const Double_t phiLocal = TMath::ASin(sinPhiLocal);
526 const Double_t tanPhiLocal = TMath::Tan(phiLocal);
528 averageddzdr += tanTheta * TMath::Sqrt(1. + tanPhiLocal * tanPhiLocal);
534 averageddzdr /= nParts;
536 AliError("Problems during determination of dz/dr. Skipping track!");
541 //printf("padRow 0 / 36: %f / %f\n", par.GetPadRowRadii(0, par.GetNRow(0) / 2.), par.GetPadRowRadii(36, par.GetNRow(36) / 2.));
542 //printf("pT: %f\nFactor/magField(kGs)/curvature^-1: %f / %f /%f\nIROC/OROC/averageOld/average: %f / %f / %f / //%f\ntanThetaGlobalFromTheta/tanTheta/dzdr: %f / %f / %f\n\n",
543 // track->Pt(), constant, magField, 1./curvature, angleIROC, angleOROC, angleAverage, averageAngle, TMath::Tan(-track->Theta() + TMath::Pi() / 2.0), tanTheta, dzdr);
544 //printf("pT: %f\nFactor/magField(kGs)/curvature^-1: %f / %f /%f\ntanThetaGlobalFromTheta/tanTheta/Averageddzdr: %f / %f / %f\n\n",
545 // track->Pt(), constant, magField, 1./curvature, TMath::Tan(-track->Theta() + TMath::Pi() / 2.0), tanTheta, averageddzdr);
548 fTanTheta = averageddzdr;
559 PostData(2, fTreePions);
562 PostData(3, fOutputContainer);
564 // Clear the V0 PID arrays
568 //________________________________________________________________________
569 void AliTPCPIDEtaTree::Terminate(const Option_t *)
571 // Called once at the end of the query