3 #include "AliMultiplicityTask.h"
14 #include <TParticle.h>
17 #include <TObjString.h>
21 #include <AliESDVertex.h>
22 #include <AliESDEvent.h>
24 #include <AliHeader.h>
25 #include <AliGenEventHeader.h>
26 #include <AliMultiplicity.h>
27 #include <AliAnalysisManager.h>
28 #include <AliMCEventHandler.h>
29 #include <AliMCEvent.h>
30 #include <AliESDInputHandler.h>
32 #include "AliESDtrackCuts.h"
33 #include "AliPWG0Helper.h"
34 #include "multiplicity/AliMultiplicityCorrection.h"
35 #include "AliCorrection.h"
36 #include "AliCorrectionMatrix3D.h"
38 ClassImp(AliMultiplicityTask)
40 AliMultiplicityTask::AliMultiplicityTask(const char* opt) :
41 AliAnalysisTask("AliMultiplicityTask", ""),
44 fAnalysisMode(AliPWG0Helper::kSPD),
45 fTrigger(AliPWG0Helper::kMB1),
51 fSystSkipParticles(kFALSE),
52 fSelectProcessType(0),
59 // Constructor. Initialization of pointers
62 for (Int_t i = 0; i<8; i++)
63 fParticleCorrection[i] = 0;
65 // Define input and output slots here
66 DefineInput(0, TChain::Class());
67 DefineOutput(0, TList::Class());
70 AliMultiplicityTask::~AliMultiplicityTask()
76 // histograms are in the output list and deleted when the output
77 // list is deleted by the TSelector dtor
85 //________________________________________________________________________
86 void AliMultiplicityTask::ConnectInputData(Option_t *)
91 Printf("AliMultiplicityTask::ConnectInputData called");
93 TTree* tree = dynamic_cast<TTree*> (GetInputData(0));
95 Printf("ERROR: Could not read tree from input slot 0");
97 // Disable all branches and enable only the needed ones
99 tree->SetBranchStatus("*", 0);
101 tree->SetBranchStatus("AliESDHeader*", 1);
102 tree->SetBranchStatus("*Vertex*", 1);
104 if (fAnalysisMode == AliPWG0Helper::kSPD) {
105 tree->SetBranchStatus("AliMultiplicity*", 1);
108 if (fAnalysisMode == AliPWG0Helper::kTPC || fAnalysisMode == AliPWG0Helper::kTPCITS) {
109 //AliESDtrackCuts::EnableNeededBranches(tree);
110 tree->SetBranchStatus("Tracks*", 1);
114 AliESDInputHandler *esdH = dynamic_cast<AliESDInputHandler*> (AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler());
117 Printf("ERROR: Could not get ESDInputHandler");
119 fESD = esdH->GetEvent();
122 // disable info messages of AliMCEvent (per event)
123 AliLog::SetClassDebugLevel("AliMCEvent", AliLog::kWarning - AliLog::kDebug + 1);
126 void AliMultiplicityTask::CreateOutputObjects()
128 // create result objects and add to output list
133 fMultiplicity = new AliMultiplicityCorrection("Multiplicity", "Multiplicity");
134 fOutput->Add(fMultiplicity);
136 fdNdpT = new TH1F("fdNdpT", "fdNdpT", 1000, 0, 10);
138 fOutput->Add(fdNdpT);
140 if (fOption.Contains("skip-particles"))
142 fSystSkipParticles = kTRUE;
143 AliInfo("WARNING: Systematic study enabled. Particles will be skipped.");
146 if (fOption.Contains("particle-efficiency"))
147 for (Int_t i = 0; i<8; i++)
149 fParticleCorrection[i] = new AliCorrection(Form("correction_%d", i), Form("correction_%d", i));
150 fOutput->Add(fParticleCorrection[i]);
153 if (fOption.Contains("only-process-type-nd"))
154 fSelectProcessType = 1;
156 if (fOption.Contains("only-process-type-sd"))
157 fSelectProcessType = 2;
159 if (fOption.Contains("only-process-type-dd"))
160 fSelectProcessType = 3;
162 if (fSelectProcessType != 0)
163 AliInfo(Form("WARNING: Systematic study enabled. Only considering process type %d", fSelectProcessType));
165 if (fOption.Contains("pt-spectrum-hist"))
167 TFile* file = TFile::Open("ptspectrum_fit.root");
170 TString subStr(fOption(fOption.Index("pt-spectrum")+17, 3));
171 TString histName(Form("ptspectrum_%s", subStr.Data()));
172 AliInfo(Form("Pt-Spectrum modification. Using %s.", histName.Data()));
173 fPtSpectrum = (TH1D*) file->Get(histName);
175 AliError("Histogram not found");
178 AliError("Could not open ptspectrum_fit.root. Pt Spectrum study could not be enabled.");
181 if (fOption.Contains("pt-spectrum-func"))
185 Printf("Using function for systematic p_t study");
189 Printf("ERROR: Could not find function for systematic p_t study");
190 fPtSpectrum = new TH1D("fPtSpectrum", "fPtSpectrum", 1, 0, 100);
191 fPtSpectrum->SetBinContent(1, 1);
196 Printf("WARNING: Systematic study enabled. Pt spectrum will be modified");
198 if (fOption.Contains("particle-species")) {
199 fParticleSpecies = new TNtuple("fParticleSpecies", "fParticleSpecies", "vtx:Pi_True:K_True:p_True:o_True:Pi_Rec:K_Rec:p_Rec:o_Rec:nolabel:doublePrim:doubleCount");
200 fOutput->Add(fParticleSpecies);
203 // TODO set seed for random generator
206 void AliMultiplicityTask::Exec(Option_t*)
210 // Check prerequisites
213 AliDebug(AliLog::kError, "ESD not available");
217 Bool_t eventTriggered = AliPWG0Helper::IsEventTriggered(fESD, fTrigger);
218 //Printf("%lld", fESD->GetTriggerMask());
220 const AliESDVertex* vtxESD = AliPWG0Helper::GetVertex(fESD, fAnalysisMode);
221 Bool_t eventVertex = (vtxESD != 0);
227 // post the data already here
228 PostData(0, fOutput);
230 //const Float_t kPtCut = 0.3;
232 // create list of (label, eta) tuples
233 Int_t inputCount = 0;
236 if (fAnalysisMode == AliPWG0Helper::kSPD)
239 const AliMultiplicity* mult = fESD->GetMultiplicity();
242 AliDebug(AliLog::kError, "AliMultiplicity not available");
246 labelArr = new Int_t[mult->GetNumberOfTracklets()];
247 etaArr = new Float_t[mult->GetNumberOfTracklets()];
249 // get multiplicity from ITS tracklets
250 for (Int_t i=0; i<mult->GetNumberOfTracklets(); ++i)
252 //printf("%d %f %f %f\n", i, mult->GetTheta(i), mult->GetPhi(i), mult->GetDeltaPhi(i));
254 Float_t deltaPhi = mult->GetDeltaPhi(i);
256 if (fDeltaPhiCut > 0 && TMath::Abs(deltaPhi) > fDeltaPhiCut)
259 etaArr[inputCount] = mult->GetEta(i);
260 if (mult->GetLabel(i, 0) == mult->GetLabel(i, 1))
262 labelArr[inputCount] = mult->GetLabel(i, 0);
265 labelArr[inputCount] = -1;
270 else if (fAnalysisMode == AliPWG0Helper::kTPC || fAnalysisMode == AliPWG0Helper::kTPCITS)
274 AliDebug(AliLog::kError, "fESDTrackCuts not available");
280 // get multiplicity from ESD tracks
281 TObjArray* list = fEsdTrackCuts->GetAcceptedTracks(fESD, (fAnalysisMode == AliPWG0Helper::kTPC));
282 Int_t nGoodTracks = list->GetEntries();
284 labelArr = new Int_t[nGoodTracks];
285 etaArr = new Float_t[nGoodTracks];
287 // loop over esd tracks
288 for (Int_t i=0; i<nGoodTracks; i++)
290 AliESDtrack* esdTrack = dynamic_cast<AliESDtrack*> (list->At(i));
293 AliDebug(AliLog::kError, Form("ERROR: Could not retrieve track %d.", i));
297 etaArr[inputCount] = esdTrack->Eta();
298 labelArr[inputCount] = TMath::Abs(esdTrack->GetLabel());
306 // eta range for nMCTracksSpecies, nESDTracksSpecies
307 Float_t etaRange = -1;
308 switch (fAnalysisMode) {
309 case AliPWG0Helper::kInvalid: break;
310 case AliPWG0Helper::kTPC:
311 case AliPWG0Helper::kTPCITS:
312 etaRange = 1.0; break;
313 case AliPWG0Helper::kSPD: etaRange = 1.0; break;
317 if (!fReadMC) // Processing of ESD information
319 if (eventTriggered && eventVertex)
321 Int_t nESDTracks05 = 0;
322 Int_t nESDTracks10 = 0;
323 Int_t nESDTracks14 = 0;
325 for (Int_t i=0; i<inputCount; ++i)
327 Float_t eta = etaArr[i];
329 if (TMath::Abs(eta) < 0.5)
332 if (TMath::Abs(eta) < 1.0)
335 if (TMath::Abs(eta) < 1.4)
339 fMultiplicity->FillMeasured(vtx[2], nESDTracks05, nESDTracks10, nESDTracks14);
342 else if (fReadMC) // Processing of MC information
344 AliMCEventHandler* eventHandler = dynamic_cast<AliMCEventHandler*> (AliAnalysisManager::GetAnalysisManager()->GetMCtruthEventHandler());
346 Printf("ERROR: Could not retrieve MC event handler");
350 AliMCEvent* mcEvent = eventHandler->MCEvent();
352 Printf("ERROR: Could not retrieve MC event");
356 AliStack* stack = mcEvent->Stack();
359 AliDebug(AliLog::kError, "Stack not available");
363 AliHeader* header = mcEvent->Header();
366 AliDebug(AliLog::kError, "Header not available");
372 Printf("WARNING: Replacing vertex by MC vertex. This is for systematical checks only.");
374 AliGenEventHeader* genHeader = header->GenEventHeader();
376 genHeader->PrimaryVertex(vtxMC);
381 // get process information
382 AliPWG0Helper::MCProcessType processType = AliPWG0Helper::GetEventProcessType(header);
384 Bool_t processEvent = kTRUE;
385 if (fSelectProcessType > 0)
387 processEvent = kFALSE;
390 if (fSelectProcessType == 1 && processType == AliPWG0Helper::kND)
391 processEvent = kTRUE;
393 // single diffractive
394 if (fSelectProcessType == 2 && processType == AliPWG0Helper::kSD)
395 processEvent = kTRUE;
397 // double diffractive
398 if (fSelectProcessType == 3 && processType == AliPWG0Helper::kDD)
399 processEvent = kTRUE;
402 Printf("Skipping this event, because it is not of the requested process type (%d)", (Int_t) processType);
408 AliGenEventHeader* genHeader = header->GenEventHeader();
410 genHeader->PrimaryVertex(vtxMC);
412 // get number of tracks from MC
413 // loop over mc particles
414 Int_t nPrim = stack->GetNprimary();
415 Int_t nMCPart = stack->GetNtrack();
417 // tracks in different eta ranges
418 Int_t nMCTracks05 = 0;
419 Int_t nMCTracks10 = 0;
420 Int_t nMCTracks14 = 0;
421 Int_t nMCTracksAll = 0;
423 // tracks per particle species, in |eta| < 2 (systematic study)
424 Int_t nMCTracksSpecies[4]; // (pi, K, p, other)
425 for (Int_t i = 0; i<4; ++i)
426 nMCTracksSpecies[i] = 0;
428 for (Int_t iMc = 0; iMc < nPrim; ++iMc)
430 AliDebug(AliLog::kDebug+1, Form("MC Loop: Processing particle %d.", iMc));
432 TParticle* particle = stack->Particle(iMc);
436 AliDebug(AliLog::kError, Form("UNEXPECTED: particle with label %d not found in stack (mc loop).", iMc));
440 Bool_t debug = kFALSE;
441 if (AliPWG0Helper::IsPrimaryCharged(particle, nPrim, debug) == kFALSE)
443 //printf("%d) DROPPED ", iMC);
448 //printf("%d) OK ", iMC);
451 //if (particle->Pt() < kPtCut)
454 Int_t particleWeight = 1;
456 Float_t pt = particle->Pt();
458 // in case of systematic study, weight according to the change of the pt spectrum
459 // it cannot be just multiplied because we cannot count "half of a particle"
460 // instead a random generator decides if the particle is counted twice (if value > 1)
461 // or not (if value < 0)
464 Int_t bin = fPtSpectrum->FindBin(pt);
465 if (bin > 0 && bin <= fPtSpectrum->GetNbinsX())
467 Float_t factor = fPtSpectrum->GetBinContent(bin);
470 Float_t random = gRandom->Uniform();
471 if (factor > 1 && random < factor - 1)
475 else if (factor < 1 && random < 1 - factor)
481 //Printf("MC weight is: %d", particleWeight);
483 if (TMath::Abs(particle->Eta()) < 0.5)
484 nMCTracks05 += particleWeight;
486 if (TMath::Abs(particle->Eta()) < 1.0)
487 nMCTracks10 += particleWeight;
489 if (TMath::Abs(particle->Eta()) < 1.4)
490 nMCTracks14 += particleWeight;
492 nMCTracksAll += particleWeight;
494 if (particle->Pt() > 0 && TMath::Abs(particle->Eta()) < 1.0)
495 fdNdpT->Fill(particle->Pt(), 1.0 / particle->Pt());
497 if (fParticleCorrection[0] || fParticleSpecies)
500 switch (TMath::Abs(particle->GetPdgCode()))
502 case 211: id = 0; break;
503 case 321: id = 1; break;
504 case 2212: id = 2; break;
505 default: id = 3; break;
508 if (TMath::Abs(particle->Eta()) < etaRange)
509 nMCTracksSpecies[id]++;
511 if (fParticleCorrection[id])
512 fParticleCorrection[id]->GetTrackCorrection()->FillGene(vtxMC[2], particle->Eta(), particle->Pt());
514 } // end of mc particle
516 fMultiplicity->FillGenerated(vtxMC[2], eventTriggered, eventVertex, processType, (Int_t) nMCTracks05, (Int_t) nMCTracks10, (Int_t) nMCTracks14, (Int_t) nMCTracksAll);
518 if (eventTriggered && eventVertex)
520 Int_t nESDTracks05 = 0;
521 Int_t nESDTracks10 = 0;
522 Int_t nESDTracks14 = 0;
524 // tracks per particle species, in |eta| < 2 (systematic study)
525 Int_t nESDTracksSpecies[7]; // (pi, K, p, other, nolabel, doublecount_prim, doublecount_all)
526 for (Int_t i = 0; i<7; ++i)
527 nESDTracksSpecies[i] = 0;
529 Bool_t* foundPrimaries = new Bool_t[nPrim]; // to prevent double counting
530 for (Int_t i=0; i<nPrim; i++)
531 foundPrimaries[i] = kFALSE;
533 Bool_t* foundPrimaries2 = new Bool_t[nPrim]; // to prevent double counting
534 for (Int_t i=0; i<nPrim; i++)
535 foundPrimaries2[i] = kFALSE;
537 Bool_t* foundTracks = new Bool_t[nMCPart]; // to prevent double counting
538 for (Int_t i=0; i<nMCPart; i++)
539 foundTracks[i] = kFALSE;
541 for (Int_t i=0; i<inputCount; ++i)
543 Float_t eta = etaArr[i];
544 Int_t label = labelArr[i];
546 Int_t particleWeight = 1;
548 // systematic study: 5% lower efficiency
549 if (fSystSkipParticles && (gRandom->Uniform() < 0.05))
552 // in case of systematic study, weight according to the change of the pt spectrum
555 TParticle* mother = 0;
557 // preserve label for later
558 Int_t labelCopy = label;
560 labelCopy = AliPWG0Helper::FindPrimaryMotherLabel(stack, labelCopy);
562 mother = stack->Particle(labelCopy);
564 // in case of pt study we do not count particles w/o label, because they cannot be scaled
568 // it cannot be just multiplied because we cannot count "half of a particle"
569 // instead a random generator decides if the particle is counted twice (if value > 1)
570 // or not (if value < 0)
571 Int_t bin = fPtSpectrum->FindBin(mother->Pt());
572 if (bin > 0 && bin <= fPtSpectrum->GetNbinsX())
574 Float_t factor = fPtSpectrum->GetBinContent(bin);
577 Float_t random = gRandom->Uniform();
578 if (factor > 1 && random < factor - 1)
582 else if (factor < 1 && random < 1 - factor)
588 //Printf("ESD weight is: %d", particleWeight);
590 if (TMath::Abs(eta) < 0.5)
591 nESDTracks05 += particleWeight;
593 if (TMath::Abs(eta) < 1.0)
594 nESDTracks10 += particleWeight;
596 if (TMath::Abs(eta) < 1.4)
597 nESDTracks14 += particleWeight;
599 if (fParticleSpecies)
601 Int_t motherLabel = -1;
602 TParticle* mother = 0;
606 motherLabel = AliPWG0Helper::FindPrimaryMotherLabel(stack, label);
607 if (motherLabel >= 0)
608 mother = stack->Particle(motherLabel);
612 // count tracks that did not have a label
613 if (TMath::Abs(eta) < etaRange)
614 nESDTracksSpecies[4]++;
618 // get particle type (pion, proton, kaon, other) of mother
620 switch (TMath::Abs(mother->GetPdgCode()))
622 case 211: idMother = 0; break;
623 case 321: idMother = 1; break;
624 case 2212: idMother = 2; break;
625 default: idMother = 3; break;
628 // double counting is ok for particle ratio study
629 if (TMath::Abs(eta) < etaRange)
630 nESDTracksSpecies[idMother]++;
632 // double counting is not ok for efficiency study
634 // check if we already counted this particle, this way distinguishes double counted particles (bug/artefact in tracking) or double counted primaries due to secondaries (physics)
635 if (foundTracks[label])
637 if (TMath::Abs(eta) < etaRange)
638 nESDTracksSpecies[6]++;
642 foundTracks[label] = kTRUE;
644 // particle (primary) already counted?
645 if (foundPrimaries[motherLabel])
647 if (TMath::Abs(eta) < etaRange)
648 nESDTracksSpecies[5]++;
651 foundPrimaries[motherLabel] = kTRUE;
656 if (fParticleCorrection[0])
658 if (label >= 0 && stack->IsPhysicalPrimary(label))
660 TParticle* particle = stack->Particle(label);
662 // get particle type (pion, proton, kaon, other)
664 switch (TMath::Abs(particle->GetPdgCode()))
666 case 211: id = 0; break;
667 case 321: id = 1; break;
668 case 2212: id = 2; break;
669 default: id = 3; break;
672 // todo check if values are not completely off??
674 // particle (primary) already counted?
675 if (!foundPrimaries2[label])
677 foundPrimaries2[label] = kTRUE;
678 fParticleCorrection[id]->GetTrackCorrection()->FillMeas(vtxMC[2], particle->Eta(), particle->Pt());
684 if (fParticleCorrection[0])
686 // if the particle decays/stops before this radius we do not see it
687 // 8cm larger than SPD layer 2
688 // 123cm TPC radius where a track has about 50 clusters (cut limit)
689 const Float_t endRadius = (fAnalysisMode == AliPWG0Helper::kSPD) ? 8. : 123;
691 // loop over all primaries that have not been found
692 for (Int_t i=0; i<nPrim; i++)
695 if (foundPrimaries2[i])
698 TParticle* particle = 0;
699 TClonesArray* trackrefs = 0;
700 mcEvent->GetParticleAndTR(i, particle, trackrefs);
702 // true primary and charged
703 if (!AliPWG0Helper::IsPrimaryCharged(particle, nPrim))
706 //skip particles with larger |eta| than 3, to keep the log clean, is anyway not included in correction map
707 if (TMath::Abs(particle->Eta()) > 3)
710 // skipping checking of process type of daughter: Neither kPBrem, kPDeltaRay nor kPCerenkov should appear in the event generation
712 // get particle type (pion, proton, kaon, other)
714 switch (TMath::Abs(particle->GetPdgCode()))
716 case 211: id = 4; break;
717 case 321: id = 5; break;
718 case 2212: id = 6; break;
719 default: id = 7; break;
722 if (!fParticleCorrection[id])
725 // get last track reference
726 AliTrackReference* trackref = dynamic_cast<AliTrackReference*> (trackrefs->Last());
730 Printf("ERROR: Could not get trackref of %d (count %d)", i, trackrefs->GetEntries());
735 // particle in tracking volume long enough...
736 if (trackref->R() > endRadius)
739 if (particle->GetLastDaughter() >= 0)
741 Int_t uID = stack->Particle(particle->GetLastDaughter())->GetUniqueID();
742 //if (uID != kPBrem && uID != kPDeltaRay && uID < kPCerenkov)
747 Printf("Particle %d (%s) decayed at %f, daugher uniqueID: %d:", i, particle->GetName(), trackref->R(), uID);
750 for (Int_t d = particle->GetFirstDaughter(); d <= particle->GetLastDaughter(); d++)
751 stack->Particle(d)->Print();
754 fParticleCorrection[id]->GetTrackCorrection()->FillGene(vtxMC[2], particle->Eta(), particle->Pt());
759 if (trackref->DetectorId() == -1)
762 Printf("Particle %d stopped at %f:", i, trackref->R());
766 fParticleCorrection[id]->GetTrackCorrection()->FillMeas(vtxMC[2], particle->Eta(), particle->Pt());
770 Printf("Particle %d simply not tracked", i);
776 delete[] foundTracks;
777 delete[] foundPrimaries;
778 delete[] foundPrimaries2;
780 if ((Int_t) nMCTracks14 > 10 && nESDTracks14 <= 3)
782 TTree* tree = dynamic_cast<TTree*> (GetInputData(0));
783 printf("WARNING: Event %lld %s (vtx-z = %f, recon: %f, contrib: %d, res: %f) has %d generated and %d reconstructed...\n", tree->GetReadEntry(), tree->GetCurrentFile()->GetName(), vtxMC[2], vtx[2], vtxESD->GetNContributors(), vtxESD->GetZRes(), nMCTracks14, nESDTracks14);
786 // fill response matrix using vtxMC (best guess)
787 fMultiplicity->FillCorrection(vtxMC[2], nMCTracks05, nMCTracks10, nMCTracks14, nMCTracksAll, nESDTracks05, nESDTracks10, nESDTracks14);
789 fMultiplicity->FillMeasured(vtx[2], nESDTracks05, nESDTracks10, nESDTracks14);
791 if (fParticleSpecies)
792 fParticleSpecies->Fill(vtxMC[2], nMCTracksSpecies[0], nMCTracksSpecies[1], nMCTracksSpecies[2], nMCTracksSpecies[3], nESDTracksSpecies[0], nESDTracksSpecies[1], nESDTracksSpecies[2], nESDTracksSpecies[3], nESDTracksSpecies[4], nESDTracksSpecies[5], nESDTracksSpecies[6]);
803 void AliMultiplicityTask::Terminate(Option_t *)
805 // The Terminate() function is the last function to be called during
806 // a query. It always runs on the client, it can be used to present
807 // the results graphically or save the results to file.
809 fOutput = dynamic_cast<TList*> (GetOutputData(0));
811 Printf("ERROR: fOutput not available");
815 fMultiplicity = dynamic_cast<AliMultiplicityCorrection*> (fOutput->FindObject("Multiplicity"));
816 for (Int_t i = 0; i < 8; ++i)
817 fParticleCorrection[i] = dynamic_cast<AliCorrection*> (fOutput->FindObject(Form("correction_%d", i)));
818 fParticleSpecies = dynamic_cast<TNtuple*> (fOutput->FindObject("fParticleSpecies"));
820 fdNdpT = dynamic_cast<TH1*> (fOutput->FindObject("fdNdpT"));
824 AliDebug(AliLog::kError, Form("ERROR: Histograms not available %p", (void*) fMultiplicity));
828 TFile* file = TFile::Open("multiplicity.root", "RECREATE");
830 fMultiplicity->SaveHistograms();
831 for (Int_t i = 0; i < 8; ++i)
832 if (fParticleCorrection[i])
833 fParticleCorrection[i]->SaveHistograms();
834 if (fParticleSpecies)
835 fParticleSpecies->Write();
839 TObjString option(fOption);
844 Printf("Written result to multiplicity.root");