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 "AliRhoParameter.h"
32 ClassImp(AliEmcalJetTask)
34 //________________________________________________________________________
35 AliEmcalJetTask::AliEmcalJetTask() :
36 AliAnalysisTaskSE("AliEmcalJetTask"),
37 fTracksName("Tracks"),
38 fCaloName("CaloClusters"),
49 fPhiMax(TMath::TwoPi()),
60 fRecombScheme(fastjet::pt_scheme),
71 fDoGenericSubtractionJetMass(kFALSE),
72 fDoGenericSubtractionGR(kFALSE),
73 fDoConstituentSubtraction(kFALSE),
74 fUseExternalBkg(kFALSE),
90 // Default constructor.
93 //________________________________________________________________________
94 AliEmcalJetTask::AliEmcalJetTask(const char *name) :
95 AliAnalysisTaskSE(name),
96 fTracksName("Tracks"),
97 fCaloName("CaloClusters"),
100 fJetType(kAKT|kFullJet|kRX1Jet),
105 fMinJetTrackPt(0.15),
108 fPhiMax(TMath::TwoPi()),
119 fRecombScheme(fastjet::pt_scheme),
120 fTrackEfficiency(1.),
130 fDoGenericSubtractionJetMass(kFALSE),
131 fDoGenericSubtractionGR(kFALSE),
132 fDoConstituentSubtraction(kFALSE),
133 fUseExternalBkg(kFALSE),
149 // Standard constructor.
151 fBranchNames="ESD:AliESDRun.,AliESDHeader.,PrimaryVertex.";
154 //________________________________________________________________________
155 AliEmcalJetTask::~AliEmcalJetTask()
160 //________________________________________________________________________
161 void AliEmcalJetTask::UserCreateOutputObjects()
163 // Create user objects.
165 fJets = new TClonesArray("AliEmcalJet");
166 fJets->SetName(fJetsName);
168 if(!fJetsSubName.IsNull()) {
169 fJetsSub = new TClonesArray("AliEmcalJet");
170 fJetsSub->SetName(fJetsSubName);
174 //________________________________________________________________________
175 void AliEmcalJetTask::UserExec(Option_t *)
177 // Main loop, called for each event.
184 // clear the jet array (normally a null operation)
186 if(fJetsSub) fJetsSub->Delete();
191 //________________________________________________________________________
192 void AliEmcalJetTask::Terminate(Option_t *)
194 // Called once at the end of the analysis.
197 //________________________________________________________________________
198 void AliEmcalJetTask::FindJets()
201 if (!fTracks && !fClus){
202 cout << "WARNING NO TRACKS OR CLUSTERS:" <<endl;
207 fRho = fRhoParam->GetVal();
209 fRhom = fRhomParam->GetVal();
212 fastjet::JetAlgorithm jalgo(fastjet::kt_algorithm);
213 if ((fJetType & kAKT) != 0) {
215 jalgo = fastjet::antikt_algorithm;
216 AliDebug(1,"Using AKT algorithm");
219 AliDebug(1,"Using KT algorithm");
222 if ((fJetType & kR020Jet) != 0)
224 else if ((fJetType & kR030Jet) != 0)
226 else if ((fJetType & kR040Jet) != 0)
230 AliFJWrapper fjw(name, name);
231 fjw.SetAreaType(fastjet::active_area_explicit_ghosts);
232 fjw.SetGhostArea(fGhostArea);
234 fjw.SetAlgorithm(jalgo);
235 fjw.SetRecombScheme(static_cast<fastjet::RecombinationScheme>(fRecombScheme));
236 fjw.SetMaxRap(fEtaMax);
239 // get primary vertex
240 Double_t vertex[3] = {0, 0, 0};
241 if(fEvent->GetPrimaryVertex()) fEvent->GetPrimaryVertex()->GetXYZ(vertex);
243 AliDebug(2,Form("Jet type = %d", fJetType));
245 if ((fIsMcPart || ((fJetType & kFullJet) != 0) || ((fJetType & kChargedJet) != 0)) && fTracks) {
246 const Int_t Ntracks = fTracks->GetEntries();
247 for (Int_t iTracks = 0; iTracks < Ntracks; ++iTracks) {
248 AliVParticle *t = static_cast<AliVParticle*>(fTracks->At(iTracks));
252 if (((fJetType & kChargedJet) != 0) && (t->Charge() == 0)) {
253 AliDebug(2,Form("Skipping track %d because it is neutral.", iTracks));
256 if (((fJetType & kNeutralJet) != 0) && (t->Charge() != 0)) {
257 AliDebug(2,Form("Skipping track %d because it is charged.", iTracks));
261 if (fIsMcPart || TMath::Abs(t->GetLabel()) > fMinMCLabel) {
262 if (t->TestBits(fMCConstSel) != (Int_t)fMCConstSel) {
263 AliDebug(2,Form("Skipping track %d because it does not match the bit mask (%d, %d)", iTracks, fMCConstSel, t->TestBits(TObject::kBitMask)));
267 AliDebug(2,Form("Track %d matches the bit mask (%d, %d)", iTracks, fMCConstSel, t->TestBits(TObject::kBitMask)));
271 if (t->TestBits(fConstSel) != (Int_t)fConstSel) {
272 AliDebug(2,Form("Skipping track %d because it does not match the bit mask (%d, %d)", iTracks, fConstSel, t->TestBits(TObject::kBitMask)));
276 AliDebug(2,Form("Track %d matches the bit mask (%d, %d)", iTracks, fConstSel, t->TestBits(TObject::kBitMask)));
279 if ((t->GetFlag() & fMCFlag) != fMCFlag) {
280 AliDebug(2,Form("Skipping track %d because it does not match the MC flags", iTracks));
283 if (fGeneratorIndex >= 0 && t->GetGeneratorIndex() != fGeneratorIndex) {
284 AliDebug(2,Form("Skipping track %d because it does not match the MC generator index", iTracks));
287 if (t->Pt() < fMinJetTrackPt)
289 Double_t eta = t->Eta();
290 Double_t phi = t->Phi();
291 if ((eta<fEtaMin) || (eta>fEtaMax) ||
292 (phi<fPhiMin) || (phi>fPhiMax))
295 // artificial inefficiency
296 if (fTrackEfficiency < 1.) {
297 Double_t rnd = gRandom->Rndm();
298 if (fTrackEfficiency < rnd) {
299 AliDebug(2,Form("Track %d rejected due to artificial tracking inefficiency", iTracks));
304 // offset of 100 for consistency with cluster ids
305 AliDebug(2,Form("Track %d accepted (label = %d, pt = %f)", iTracks, t->GetLabel(), t->Pt()));
306 fjw.AddInputVector(t->Px(), t->Py(), t->Pz(), t->E(), iTracks + 100);
310 if ((((fJetType & kFullJet) != 0) || ((fJetType & kNeutralJet) != 0)) && fClus) {
311 const Int_t Nclus = fClus->GetEntries();
312 for (Int_t iClus = 0; iClus < Nclus; ++iClus) {
314 Double_t cEta=0,cPhi=0,cPt=0;
315 Double_t cPx=0,cPy=0,cPz=0;
317 AliEmcalParticle *ep = static_cast<AliEmcalParticle*>(fClus->At(iClus));
321 c = ep->GetCluster();
325 if (c->GetLabel() > fMinMCLabel) {
326 if (ep->TestBits(fMCConstSel) != (Int_t)fMCConstSel) {
327 AliDebug(2,Form("Skipping cluster %d because it does not match the bit mask (%d, %d)", iClus, fMCConstSel, ep->TestBits(TObject::kBitMask)));
331 AliDebug(2,Form("Cluster %d matches the bit mask (%d, %d)", iClus, fMCConstSel, ep->TestBits(TObject::kBitMask)));
335 if (ep->TestBits(fConstSel) != (Int_t)fConstSel) {
336 AliDebug(2,Form("Skipping cluster %d because it does not match the bit mask (%d, %d)", iClus, fConstSel, ep->TestBits(TObject::kBitMask)));
340 AliDebug(2,Form("Cluster %d matches the bit mask (%d, %d)", iClus, fConstSel, ep->TestBits(TObject::kBitMask)));
351 c = static_cast<AliVCluster*>(fClus->At(iClus));
355 if (c->GetLabel() > fMinMCLabel) {
356 if (c->TestBits(fMCConstSel) != (Int_t)fMCConstSel) {
357 AliDebug(2,Form("Skipping cluster %d because it does not match the bit mask (%d, %d)", iClus, fMCConstSel, c->TestBits(TObject::kBitMask)));
361 AliDebug(2,Form("Cluster %d matches the bit mask (%d, %d)", iClus, fMCConstSel, c->TestBits(TObject::kBitMask)));
365 if (c->TestBits(fConstSel) != (Int_t)fConstSel) {
366 AliDebug(2,Form("Skipping cluster %d because it does not match the bit mask (%d, %d)", iClus, fConstSel, c->TestBits(TObject::kBitMask)));
370 AliDebug(2,Form("Cluster %d matches the bit mask (%d, %d)", iClus, fConstSel, c->TestBits(TObject::kBitMask)));
375 c->GetMomentum(nP, vertex);
385 if (cPt < fMinJetClusPt)
387 if ((cEta<fEtaMin) || (cEta>fEtaMax) ||
388 (cPhi<fPhiMin) || (cPhi>fPhiMax))
390 // offset of 100 to skip ghost particles uid = -1
391 AliDebug(2,Form("Cluster %d accepted (label = %d)", iClus, c->GetLabel()));
392 fjw.AddInputVector(cPx, cPy, cPz, TMath::Sqrt(cPx*cPx+cPy*cPy+cPz*cPz), -iClus - 100);
396 // setting legacy mode
398 fjw.SetLegacyMode(kTRUE);
404 //run generic subtractor
405 if(fDoGenericSubtractionJetMass) {
406 fjw.SetUseExternalBkg(fUseExternalBkg,fRho,fRhom);
407 fjw.DoGenericSubtractionJetMass();
410 //run constituent subtractor
411 if(fDoConstituentSubtraction) {
412 fjw.SetUseExternalBkg(fUseExternalBkg,fRho,fRhom);
413 fjw.DoConstituentSubtraction();
417 AliEMCALGeometry *geom = AliEMCALGeometry::GetInstance();
419 AliFatal(Form("%s: Can not create geometry", GetName()));
423 // loop over fastjet jets
424 std::vector<fastjet::PseudoJet> jets_incl = fjw.GetInclusiveJets();
425 // sort jets according to jet pt
426 static Int_t indexes[9999] = {-1};
427 GetSortedArray(indexes, jets_incl);
429 AliDebug(1,Form("%d jets found", (Int_t)jets_incl.size()));
430 for (UInt_t ijet=0, jetCount=0; ijet<jets_incl.size(); ++ijet) {
431 Int_t ij = indexes[ijet];
432 AliDebug(3,Form("Jet pt = %f, area = %f", jets_incl[ij].perp(), fjw.GetJetArea(ij)));
434 if (jets_incl[ij].perp()<fMinJetPt)
436 if (fjw.GetJetArea(ij)<fMinJetArea)
438 if ((jets_incl[ij].eta()<fJetEtaMin) || (jets_incl[ij].eta()>fJetEtaMax) ||
439 (jets_incl[ij].phi()<fJetPhiMin) || (jets_incl[ij].phi()>fJetPhiMax))
442 AliEmcalJet *jet = new ((*fJets)[jetCount])
443 AliEmcalJet(jets_incl[ij].perp(), jets_incl[ij].eta(), jets_incl[ij].phi(), jets_incl[ij].m());
446 //do generic subtraction if requested
447 #ifdef FASTJET_VERSION
448 if(fDoGenericSubtractionJetMass) {
449 std::vector<fastjet::contrib::GenericSubtractorInfo> jetMassInfo = fjw.GetGenSubtractorInfoJetMass();
450 Int_t n = (Int_t)jetMassInfo.size();
452 jet->SetFirstDerivative(jetMassInfo[ij].first_derivative());
453 jet->SetSecondDerivative(jetMassInfo[ij].second_derivative());
454 jet->SetFirstOrderSubtracted(jetMassInfo[ij].first_order_subtracted());
455 jet->SetSecondOrderSubtracted(jetMassInfo[ij].second_order_subtracted());
458 //here do generic subtraction for angular structure function
459 Double_t ptcorr = jets_incl[ij].perp()-fjw.GetJetArea(ij)*fRho;
461 if(fDoGenericSubtractionGR && ptcorr>fPtMinGR) {
462 fjw.SetUseExternalBkg(fUseExternalBkg,fRho,fRhom);
463 fjw.SetRMaxAndStep(fRMax,fDRStep);
464 fjw.DoGenericSubtractionGR(ij);
465 std::vector<double> num = fjw.GetGRNumerator();
466 std::vector<double> den = fjw.GetGRDenominator();
467 std::vector<double> nums = fjw.GetGRNumeratorSub();
468 std::vector<double> dens = fjw.GetGRDenominatorSub();
469 //pass this to AliEmcalJet
470 jet->SetGRNumSize(num.size());
471 jet->SetGRDenSize(den.size());
472 jet->SetGRNumSubSize(nums.size());
473 jet->SetGRDenSubSize(dens.size());
474 Int_t nsize = (Int_t)num.size();
475 for(Int_t g = 0; g<nsize; ++g) {
476 jet->AddGRNumAt(num[g],g);
477 jet->AddGRNumSubAt(nums[g],g);
479 Int_t dsize = (Int_t)den.size();
480 for(Int_t g = 0; g<dsize; ++g) {
481 jet->AddGRDenAt(den[g],g);
482 jet->AddGRDenSubAt(dens[g],g);
487 // loop over constituents
488 std::vector<fastjet::PseudoJet> constituents(fjw.GetJetConstituents(ij));
489 jet->SetNumberOfTracks(constituents.size());
490 jet->SetNumberOfClusters(constituents.size());
494 Double_t neutralE = 0;
505 for(UInt_t ic = 0; ic < constituents.size(); ++ic) {
506 Int_t uid = constituents[ic].user_index();
507 AliDebug(3,Form("Processing constituent %d", uid));
508 if ((uid == -1) /*&& (constituents[ic].kt2() < 1e-25)*/) { //ghost particle
510 Double_t gphi = constituents[ic].phi();
512 gphi += TMath::TwoPi();
513 gphi *= TMath::RadToDeg();
514 Double_t geta = constituents[ic].eta();
515 if ((gphi > geom->GetArm1PhiMin()) && (gphi < geom->GetArm1PhiMax()) &&
516 (geta > geom->GetArm1EtaMin()) && (geta < geom->GetArm1EtaMax()))
518 } else if ((uid > 0) && fTracks) { // track constituent
519 Int_t tid = uid - 100;
520 AliVParticle *t = static_cast<AliVParticle*>(fTracks->At(tid));
522 AliError(Form("Could not find track %d",tid));
525 if (jetCount < fMarkConst) {
526 AliDebug(2,Form("Marking track %d with bit map %d", tid, fJetType));
529 Double_t cEta = t->Eta();
530 Double_t cPhi = t->Phi();
531 Double_t cPt = t->Pt();
532 Double_t cP = t->P();
533 if (t->Charge() == 0) {
543 if (fIsMcPart || TMath::Abs(t->GetLabel()) > fMinMCLabel) // check if MC particle
547 cPhi += TMath::TwoPi();
548 cPhi *= TMath::RadToDeg();
549 if ((cPhi > geom->GetArm1PhiMin()) && (cPhi < geom->GetArm1PhiMax()) &&
550 (cEta > geom->GetArm1EtaMin()) && (cEta < geom->GetArm1EtaMax())) {
555 jet->AddTrackAt(tid, nt);
557 } else if (fClus) { // cluster constituent
558 Int_t cid = -uid - 100;
560 Double_t cEta=0,cPhi=0,cPt=0,cP=0;
562 AliEmcalParticle *ep = static_cast<AliEmcalParticle*>(fClus->At(cid));
565 c = ep->GetCluster();
568 if (jetCount < fMarkConst)
569 ep->SetBit(fJetType);
575 c = static_cast<AliVCluster*>(fClus->At(cid));
578 if (jetCount < fMarkConst)
581 c->GetMomentum(nP, vertex);
592 if (c->GetLabel() > fMinMCLabel) // MC particle
593 mcpt += c->GetMCEnergyFraction() > 1e-6 ? cPt * c->GetMCEnergyFraction() : cPt;
596 cPhi += TMath::TwoPi();
597 cPhi *= TMath::RadToDeg();
598 if ((cPhi > geom->GetArm1PhiMin()) && (cPhi < geom->GetArm1PhiMax()) &&
599 (cEta > geom->GetArm1EtaMin()) && (cEta < geom->GetArm1EtaMax())) {
604 jet->AddClusterAt(cid, nc);
608 AliError(Form("%s: No logical way to end up here.", GetName()));
611 } /* end of constituent loop */
613 jet->SetNumberOfTracks(nt);
614 jet->SetNumberOfClusters(nc);
615 jet->SortConstituents();
616 jet->SetMaxNeutralPt(maxNe);
617 jet->SetMaxChargedPt(maxCh);
618 jet->SetNEF(neutralE / jet->E());
619 fastjet::PseudoJet area(fjw.GetJetAreaVector(ij));
620 jet->SetArea(area.perp());
621 jet->SetAreaEta(area.eta());
622 jet->SetAreaPhi(area.phi());
623 jet->SetNumberOfCharged(ncharged);
624 jet->SetNumberOfNeutrals(nneutral);
627 jet->SetPtEmc(emcpt);
630 jet->SetAreaEmc(fjw.GetJetArea(ij) * gemc / gall);
633 if ((jet->Phi() > geom->GetArm1PhiMin() * TMath::DegToRad()) &&
634 (jet->Phi() < geom->GetArm1PhiMax() * TMath::DegToRad()) &&
635 (jet->Eta() > geom->GetArm1EtaMin()) &&
636 (jet->Eta() < geom->GetArm1EtaMax()))
637 jet->SetAxisInEmcal(kTRUE);
639 AliDebug(2,Form("Added jet n. %d, pt = %f, area = %f, constituents = %d", jetCount, jet->Pt(), jet->Area(), (Int_t)constituents.size()));
644 //run constituent subtractor if requested
645 if(fDoConstituentSubtraction) {
646 #ifdef FASTJET_VERSION
647 if(!fJetsSub) AliWarning(Form("No jet branch to write to for subtracted jets. fJetsSubName: %s",fJetsSubName.Data()));
649 std::vector<fastjet::PseudoJet> jets_sub;
650 jets_sub = fjw.GetConstituentSubtrJets();
651 AliDebug(1,Form("%d constituent subtracted jets found", (Int_t)jets_sub.size()));
652 for (UInt_t ijet=0, jetCount=0; ijet<jets_sub.size(); ++ijet) {
653 //Only storing 4-vector and jet area of unsubtracted jet
654 AliEmcalJet *jet_sub = new ((*fJetsSub)[jetCount])
655 AliEmcalJet(jets_sub[ijet].perp(), jets_sub[ijet].eta(), jets_sub[ijet].phi(), jets_sub[ijet].m());
656 jet_sub->SetLabel(ijet);
657 fastjet::PseudoJet area(fjw.GetJetAreaVector(ijet));
658 jet_sub->SetArea(area.perp());
659 jet_sub->SetAreaEta(area.eta());
660 jet_sub->SetAreaPhi(area.phi());
661 jet_sub->SetAreaEmc(area.perp());
666 } //constituent subtraction
669 //________________________________________________________________________
670 Bool_t AliEmcalJetTask::GetSortedArray(Int_t indexes[], std::vector<fastjet::PseudoJet> array) const
672 // Get the leading jets.
674 static Float_t pt[9999] = {0};
676 const Int_t n = (Int_t)array.size();
681 for (Int_t i = 0; i < n; i++)
682 pt[i] = array[i].perp();
684 TMath::Sort(n, pt, indexes);
689 //________________________________________________________________________
690 Bool_t AliEmcalJetTask::DoInit()
692 // Init. Return true if successful.
694 if (fTrackEfficiency < 1.) {
695 if (gRandom) delete gRandom;
696 gRandom = new TRandom3(0);
699 // get input collections
700 AliAnalysisManager *am = AliAnalysisManager::GetAnalysisManager();
703 fEvent = InputEvent();
705 AliError(Form("%s: Could not retrieve event! Returning", GetName()));
709 // add jets to event if not yet there
710 if (!(fEvent->FindListObject(fJetsName)))
711 fEvent->AddObject(fJets);
713 AliError(Form("%s: Object with name %s already in event! Returning", GetName(), fJetsName.Data()));
717 if (!(fEvent->FindListObject(fJetsSubName)) && fJetsSub)
718 fEvent->AddObject(fJetsSub);
720 if (fTracksName == "Tracks")
721 am->LoadBranch("Tracks");
722 if (!fTracks && !fTracksName.IsNull()) {
723 fTracks = dynamic_cast<TClonesArray*>(fEvent->FindListObject(fTracksName));
725 AliError(Form("%s: Pointer to tracks %s == 0", GetName(), fTracksName.Data()));
730 TClass cls(fTracks->GetClass()->GetName());
731 if (cls.InheritsFrom("AliMCParticle") || cls.InheritsFrom("AliAODMCParticle"))
735 if (fCaloName == "CaloClusters")
736 am->LoadBranch("CaloClusters");
737 if (!fClus && !fCaloName.IsNull()) {
738 fClus = dynamic_cast<TClonesArray*>(fEvent->FindListObject(fCaloName));
740 AliError(Form("%s: Pointer to clus %s == 0", GetName(), fCaloName.Data()));
745 TClass cls(fClus->GetClass()->GetName());
746 if (cls.InheritsFrom("AliEmcalParticle"))
750 if (!fRhoName.IsNull() && !fRhoParam) { // get rho from the event
751 fRhoParam = dynamic_cast<AliRhoParameter*>(InputEvent()->FindListObject(fRhoName));
753 AliError(Form("%s: Could not retrieve rho %s!", GetName(), fRhoName.Data()));
757 if (!fRhomName.IsNull() && !fRhomParam) { // get rhom from the event
758 fRhomParam = dynamic_cast<AliRhoParameter*>(InputEvent()->FindListObject(fRhomName));
760 AliError(Form("%s: Could not retrieve rho %s!", GetName(), fRhomName.Data()));