2 // Emcal jet finder task.
4 // Authors: C.Loizides, S.Aiola, M. Verweij
7 #include "AliEmcalJetTask.h"
10 #include <TClonesArray.h>
12 #include <TLorentzVector.h>
16 #include "AliAnalysisManager.h"
17 #include "AliCentrality.h"
18 #include "AliEMCALGeometry.h"
19 #include "AliESDEvent.h"
20 #include "AliEmcalJet.h"
21 #include "AliEmcalParticle.h"
22 #include "AliFJWrapper.h"
23 #include "AliMCEvent.h"
24 #include "AliVCluster.h"
25 #include "AliVEvent.h"
26 #include "AliVParticle.h"
27 #include "AliEmcalJetUtility.h"
33 ClassImp(AliEmcalJetTask)
35 //________________________________________________________________________
36 AliEmcalJetTask::AliEmcalJetTask() :
37 AliAnalysisTaskSE("AliEmcalJetTask"),
38 fTracksName("Tracks"),
39 fCaloName("CaloClusters"),
41 fJetType(kAKT|kFullJet|kRX1Jet),
42 fMinLabelTracks(-kMaxInt),
43 fMaxLabelTracks(kMaxInt),
44 fMinLabelClusters(-kMaxInt),
45 fMaxLabelClusters(kMaxInt),
51 fPhiMax(TMath::TwoPi()),
61 fRecombScheme(fastjet::pt_scheme),
76 fFastJetWrapper("AliEmcalJetTask","AliEmcalJetTask")
78 // Default constructor.
85 //________________________________________________________________________
86 AliEmcalJetTask::AliEmcalJetTask(const char *name) :
87 AliAnalysisTaskSE(name),
88 fTracksName("Tracks"),
89 fCaloName("CaloClusters"),
91 fJetType(kAKT|kFullJet|kRX1Jet),
92 fMinLabelTracks(-kMaxInt),
93 fMaxLabelTracks(kMaxInt),
94 fMinLabelClusters(-kMaxInt),
95 fMaxLabelClusters(kMaxInt),
101 fPhiMax(TMath::TwoPi()),
111 fRecombScheme(fastjet::pt_scheme),
112 fTrackEfficiency(1.),
126 fFastJetWrapper(name,name)
128 // Standard constructor.
130 fBranchNames="ESD:AliESDRun.,AliESDHeader.,PrimaryVertex.";
137 //________________________________________________________________________
138 AliEmcalJetTask::~AliEmcalJetTask()
143 //________________________________________________________________________
144 AliEmcalJetUtility* AliEmcalJetTask::AddUtility(AliEmcalJetUtility* utility)
146 // Addition of utilities.
148 if (!fUtilities) fUtilities = new TObjArray();
149 if (fUtilities->FindObject(utility)) {
150 Error("AddSupply", "Jet utility %s already connected.", utility->GetName());
153 fUtilities->Add(utility);
154 utility->SetJetTask(this);
159 //________________________________________________________________________
160 void AliEmcalJetTask::InitUtilities()
162 TIter next(fUtilities);
163 AliEmcalJetUtility *utility = 0;
164 while ((utility=static_cast<AliEmcalJetUtility*>(next()))) utility->Init();
167 //________________________________________________________________________
168 void AliEmcalJetTask::PrepareUtilities()
170 TIter next(fUtilities);
171 AliEmcalJetUtility *utility = 0;
172 while ((utility=static_cast<AliEmcalJetUtility*>(next()))) utility->Prepare(fFastJetWrapper);
175 //________________________________________________________________________
176 void AliEmcalJetTask::ExecuteUtilities(AliEmcalJet* jet, Int_t ij)
178 TIter next(fUtilities);
179 AliEmcalJetUtility *utility = 0;
180 while ((utility=static_cast<AliEmcalJetUtility*>(next()))) utility->ProcessJet(jet, ij, fFastJetWrapper);
183 //________________________________________________________________________
184 void AliEmcalJetTask::TerminateUtilities()
186 TIter next(fUtilities);
187 AliEmcalJetUtility *utility = 0;
188 while ((utility=static_cast<AliEmcalJetUtility*>(next()))) utility->Terminate(fFastJetWrapper);
191 //________________________________________________________________________
192 void AliEmcalJetTask::UserCreateOutputObjects()
194 // Create user objects.
197 //________________________________________________________________________
198 void AliEmcalJetTask::UserExec(Option_t *)
200 // Main loop, called for each event.
207 // clear the jet array (normally a null operation)
210 // get primary vertex
211 if(fEvent->GetPrimaryVertex()) fEvent->GetPrimaryVertex()->GetXYZ(fVertex);
218 //________________________________________________________________________
219 void AliEmcalJetTask::FindJets()
223 if (!fTracks && !fClus){
224 AliError("No tracks or clusters, returning.");
228 fFastJetWrapper.Clear();
230 AliDebug(2,Form("Jet type = %d", fJetType));
233 const Int_t Ntracks = fTracks->GetEntries();
234 for (Int_t iTracks = 0; iTracks < Ntracks; ++iTracks) {
235 AliVParticle *t = static_cast<AliVParticle*>(fTracks->At(iTracks));
239 if (t->Pt() < fMinJetTrackPt) continue;
240 Double_t eta = t->Eta();
241 Double_t phi = t->Phi();
242 if ((eta<fEtaMin) || (eta>fEtaMax) ||
243 (phi<fPhiMin) || (phi>fPhiMax))
246 if (((fJetType & kChargedJet) != 0) && (t->Charge() == 0)) {
247 AliDebug(2,Form("Skipping track %d because it is neutral.", iTracks));
251 if (((fJetType & kNeutralJet) != 0) && (t->Charge() != 0)) {
252 AliDebug(2,Form("Skipping track %d because it is charged.", iTracks));
256 Int_t lab = TMath::Abs(t->GetLabel());
257 if (lab < fMinLabelTracks || lab > fMaxLabelTracks) {
258 AliDebug(2,Form("Skipping track %d because label %d is not in range (%d, %d)", iTracks, lab, fMinLabelTracks, fMaxLabelTracks));
262 if ((t->GetFlag() & fMCFlag) != fMCFlag) {
263 AliDebug(2,Form("Skipping track %d because it does not match the MC flags", iTracks));
267 if (fGeneratorIndex >= 0 && t->GetGeneratorIndex() != fGeneratorIndex) {
268 AliDebug(2,Form("Skipping track %d because it does not match the MC generator index", iTracks));
272 // artificial inefficiency
273 if (fTrackEfficiency < 1.) {
274 Double_t rnd = gRandom->Rndm();
275 if (fTrackEfficiency < rnd) {
276 AliDebug(2,Form("Track %d rejected due to artificial tracking inefficiency", iTracks));
281 // offset of 100 for consistency with cluster ids
282 AliDebug(2,Form("Track %d accepted (label = %d, pt = %f)", iTracks, lab, t->Pt()));
283 fFastJetWrapper.AddInputVector(t->Px(), t->Py(), t->Pz(), t->E(), iTracks + 100);
288 const Int_t Nclus = fClus->GetEntries();
289 for (Int_t iClus = 0; iClus < Nclus; ++iClus) {
291 Double_t cEta=0,cPhi=0,cPt=0;
292 Double_t cPx=0,cPy=0,cPz=0;
294 AliEmcalParticle *ep = static_cast<AliEmcalParticle*>(fClus->At(iClus));
296 c = ep->GetCluster();
307 c = static_cast<AliVCluster*>(fClus->At(iClus));
311 c->GetMomentum(nP, fVertex);
320 if (!c->IsEMCAL()) continue;
321 if (cPt < fMinJetClusPt) continue;
322 if ((cEta<fEtaMin) || (cEta>fEtaMax) ||
323 (cPhi<fPhiMin) || (cPhi>fPhiMax))
326 Int_t lab = TMath::Abs(c->GetLabel());
327 if (lab < fMinLabelClusters || lab > fMaxLabelClusters) {
328 AliDebug(2,Form("Skipping cluster %d because label %d is not in range (%d, %d)", iClus, lab, fMinLabelClusters, fMaxLabelClusters));
332 // offset of 100 to skip ghost particles uid = -1
333 AliDebug(2,Form("Cluster %d accepted (label = %d)", iClus, c->GetLabel()));
334 Double_t e = TMath::Sqrt(cPx*cPx+cPy*cPy+cPz*cPz);
335 fFastJetWrapper.AddInputVector(cPx, cPy, cPz, e, -iClus - 100);
340 fFastJetWrapper.Run();
343 //________________________________________________________________________
344 void AliEmcalJetTask::FillJetBranch()
346 // Fill jet branch with fastjet jets.
350 // loop over fastjet jets
351 std::vector<fastjet::PseudoJet> jets_incl = fFastJetWrapper.GetInclusiveJets();
352 // sort jets according to jet pt
353 static Int_t indexes[9999] = {-1};
354 GetSortedArray(indexes, jets_incl);
356 AliDebug(1,Form("%d jets found", (Int_t)jets_incl.size()));
357 for (UInt_t ijet = 0, jetCount = 0; ijet < jets_incl.size(); ++ijet) {
358 Int_t ij = indexes[ijet];
359 AliDebug(3,Form("Jet pt = %f, area = %f", jets_incl[ij].perp(), fFastJetWrapper.GetJetArea(ij)));
361 if (jets_incl[ij].perp() < fMinJetPt) continue;
362 if (fFastJetWrapper.GetJetArea(ij) < fMinJetArea) continue;
363 if ((jets_incl[ij].eta() < fJetEtaMin) || (jets_incl[ij].eta() > fJetEtaMax) ||
364 (jets_incl[ij].phi() < fJetPhiMin) || (jets_incl[ij].phi() > fJetPhiMax))
367 AliEmcalJet *jet = new ((*fJets)[jetCount])
368 AliEmcalJet(jets_incl[ij].perp(), jets_incl[ij].eta(), jets_incl[ij].phi(), jets_incl[ij].m());
371 fastjet::PseudoJet area(fFastJetWrapper.GetJetAreaVector(ij));
372 jet->SetArea(area.perp());
373 jet->SetAreaEta(area.eta());
374 jet->SetAreaPhi(area.phi());
375 jet->SetAreaE(area.E());
377 // Fill constituent info
378 std::vector<fastjet::PseudoJet> constituents(fFastJetWrapper.GetJetConstituents(ij));
379 FillJetConstituents(jet, constituents, fTracks, fClus, constituents);
382 if ((jet->Phi() > fGeom->GetArm1PhiMin() * TMath::DegToRad()) &&
383 (jet->Phi() < fGeom->GetArm1PhiMax() * TMath::DegToRad()) &&
384 (jet->Eta() > fGeom->GetArm1EtaMin()) &&
385 (jet->Eta() < fGeom->GetArm1EtaMax()))
386 jet->SetAxisInEmcal(kTRUE);
389 ExecuteUtilities(jet, ij);
391 AliDebug(2,Form("Added jet n. %d, pt = %f, area = %f, constituents = %d", jetCount, jet->Pt(), jet->Area(), jet->GetNumberOfConstituents()));
395 TerminateUtilities();
398 //________________________________________________________________________
399 Bool_t AliEmcalJetTask::GetSortedArray(Int_t indexes[], std::vector<fastjet::PseudoJet> array) const
401 // Get the leading jets.
403 static Float_t pt[9999] = {0};
405 const Int_t n = (Int_t)array.size();
410 for (Int_t i = 0; i < n; i++)
411 pt[i] = array[i].perp();
413 TMath::Sort(n, pt, indexes);
418 //________________________________________________________________________
419 Bool_t AliEmcalJetTask::DoInit()
421 // Init. Return true if successful.
423 if (fTrackEfficiency < 1.) {
424 if (gRandom) delete gRandom;
425 gRandom = new TRandom3(0);
429 fGeom = AliEMCALGeometry::GetInstance();
431 AliWarning(Form("%s: Can not create EMCal geometry, some features will not work...", GetName()));
434 // get input collections
435 AliAnalysisManager *am = AliAnalysisManager::GetAnalysisManager();
438 fEvent = InputEvent();
440 AliError(Form("%s: Could not retrieve event! Returning", GetName()));
444 if (fTracksName == "Tracks")
445 am->LoadBranch("Tracks");
446 if (!fTracks && !fTracksName.IsNull()) {
447 fTracks = dynamic_cast<TClonesArray*>(fEvent->FindListObject(fTracksName));
449 AliError(Form("%s: Pointer to tracks %s == 0", GetName(), fTracksName.Data()));
454 if (fCaloName == "CaloClusters")
455 am->LoadBranch("CaloClusters");
456 if (!fClus && !fCaloName.IsNull()) {
457 fClus = dynamic_cast<TClonesArray*>(fEvent->FindListObject(fCaloName));
459 AliError(Form("%s: Pointer to clus %s == 0", GetName(), fCaloName.Data()));
464 TClass cls(fClus->GetClass()->GetName());
465 if (cls.InheritsFrom("AliEmcalParticle"))
469 // add jets to event if not yet there
470 if (!(fEvent->FindListObject(fJetsName))) {
471 fJets = new TClonesArray("AliEmcalJet");
472 fJets->SetName(fJetsName);
473 fEvent->AddObject(fJets);
476 AliError(Form("%s: Object with name %s already in event! Returning", GetName(), fJetsName.Data()));
481 fastjet::JetAlgorithm jalgo(fastjet::kt_algorithm);
482 if ((fJetType & kAKT) != 0) {
484 jalgo = fastjet::antikt_algorithm;
485 AliDebug(1,"Using AKT algorithm");
488 AliDebug(1,"Using KT algorithm");
491 if ((fJetType & kR020Jet) != 0)
493 else if ((fJetType & kR030Jet) != 0)
495 else if ((fJetType & kR040Jet) != 0)
499 fFastJetWrapper.SetName(name);
500 fFastJetWrapper.SetTitle(name);
501 fFastJetWrapper.SetAreaType(fastjet::active_area_explicit_ghosts);
502 fFastJetWrapper.SetGhostArea(fGhostArea);
503 fFastJetWrapper.SetR(fRadius);
504 fFastJetWrapper.SetAlgorithm(jalgo);
505 fFastJetWrapper.SetRecombScheme(static_cast<fastjet::RecombinationScheme>(fRecombScheme));
506 fFastJetWrapper.SetMaxRap(fEtaMax);
508 // setting legacy mode
510 fFastJetWrapper.SetLegacyMode(kTRUE);
518 //___________________________________________________________________________________________________________________
519 void AliEmcalJetTask::FillJetConstituents(AliEmcalJet *jet, std::vector<fastjet::PseudoJet>& constituents, TClonesArray *tracks, TClonesArray *clusters,
520 std::vector<fastjet::PseudoJet>& constituents_unsub, Int_t flag, TClonesArray *particles_sub)
524 Double_t neutralE = 0.;
537 jet->SetNumberOfTracks(constituents.size());
538 jet->SetNumberOfClusters(constituents.size());
540 for (UInt_t ic = 0; ic < constituents.size(); ++ic) {
542 if (flag == 0) uid = constituents[ic].user_index();
543 else uid = GetIndexSub(constituents[ic].phi(), constituents_unsub);
545 AliDebug(3,Form("Processing constituent %d", uid));
546 if (uid == -1) { //ghost particle
549 Double_t gphi = constituents[ic].phi();
550 if (gphi < 0) gphi += TMath::TwoPi();
551 gphi *= TMath::RadToDeg();
552 Double_t geta = constituents[ic].eta();
553 if ((gphi > fGeom->GetArm1PhiMin()) && (gphi < fGeom->GetArm1PhiMax()) &&
554 (geta > fGeom->GetArm1EtaMin()) && (geta < fGeom->GetArm1EtaMax()))
558 else if ((uid >= 100) && tracks) { // track constituent
559 Int_t tid = uid - 100;
560 AliVParticle *t = static_cast<AliVParticle*>(tracks->At(tid));
562 AliError(Form("Could not find track %d",tid));
566 Double_t cEta = t->Eta();
567 Double_t cPhi = t->Phi();
568 Double_t cPt = t->Pt();
569 Double_t cP = t->P();
570 if (t->Charge() == 0) {
573 if (cPt > maxNe) maxNe = cPt;
576 if (cPt > maxCh) maxCh = cPt;
579 // check if MC particle
580 if (TMath::Abs(t->GetLabel()) > fMinMCLabel) mcpt += cPt;
583 if (cPhi < 0) cPhi += TMath::TwoPi();
584 cPhi *= TMath::RadToDeg();
585 if ((cPhi > fGeom->GetArm1PhiMin()) && (cPhi < fGeom->GetArm1PhiMax()) &&
586 (cEta > fGeom->GetArm1EtaMin()) && (cEta < fGeom->GetArm1EtaMax())) {
592 if (flag == 0 || particles_sub == 0) {
593 jet->AddTrackAt(tid, nt);
596 Int_t part_sub_id = particles_sub->GetEntriesFast();
597 AliEmcalParticle* part_sub = new ((*particles_sub)[part_sub_id]) AliEmcalParticle(t);
598 part_sub->SetPtEtaPhiM(constituents[ic].perp(),constituents[ic].eta(),constituents[ic].phi(),constituents[ic].m());
599 jet->AddTrackAt(part_sub_id, nt);
604 else if ((uid <= -100) && clusters) { // cluster constituent
605 Int_t cid = -uid - 100;
607 Double_t cEta=0,cPhi=0,cPt=0,cP=0;
609 AliEmcalParticle *ep = static_cast<AliEmcalParticle*>(fClus->At(cid));
611 c = ep->GetCluster();
620 c = static_cast<AliVCluster*>(fClus->At(cid));
624 c->GetMomentum(nP, fVertex);
632 if (cPt > maxNe) maxNe = cPt;
635 if (TMath::Abs(c->GetLabel()) > fMinMCLabel) mcpt += c->GetMCEnergyFraction() > 1e-6 ? cPt * c->GetMCEnergyFraction() : cPt;
638 if (cPhi<0) cPhi += TMath::TwoPi();
639 cPhi *= TMath::RadToDeg();
640 if ((cPhi > fGeom->GetArm1PhiMin()) && (cPhi < fGeom->GetArm1PhiMax()) &&
641 (cEta > fGeom->GetArm1EtaMin()) && (cEta < fGeom->GetArm1EtaMax())) {
647 if (flag == 0 || particles_sub == 0) {
648 jet->AddClusterAt(cid, nc);
651 Int_t part_sub_id = particles_sub->GetEntriesFast();
652 AliEmcalParticle* part_sub = new ((*particles_sub)[part_sub_id]) AliEmcalParticle(c);
653 part_sub->SetPtEtaPhiM(constituents[ic].perp(),constituents[ic].eta(),constituents[ic].phi(),constituents[ic].m());
654 jet->AddTrackAt(part_sub_id, nt);
661 AliError(Form("%s: No logical way to end up here.", GetName()));
666 jet->SetNumberOfTracks(nt);
667 jet->SetNumberOfClusters(nc);
668 jet->SetNEF(neutralE / jet->E());
669 jet->SetMaxChargedPt(maxCh);
670 jet->SetMaxNeutralPt(maxNe);
671 if (gall > 0) jet->SetAreaEmc(jet->Area() * gemc / gall);
672 else jet->SetAreaEmc(-1);
674 jet->SetNumberOfCharged(ncharged);
675 jet->SetNumberOfNeutrals(nneutral);
677 jet->SetPtEmc(emcpt);
678 jet->SortConstituents();
681 //______________________________________________________________________________________
682 Int_t AliEmcalJetTask::GetIndexSub(Double_t phi_sub, std::vector<fastjet::PseudoJet>& constituents_unsub)
684 for (UInt_t ii = 0; ii < constituents_unsub.size(); ii++) {
685 Double_t phi_unsub = constituents_unsub[ii].phi();
686 if (phi_sub == phi_unsub) return constituents_unsub[ii].user_index();