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),
69 fDoGenericSubtraction(kFALSE),
70 fDoConstituentSubtraction(kFALSE),
71 fUseExternalBkg(kFALSE),
84 // Default constructor.
87 //________________________________________________________________________
88 AliEmcalJetTask::AliEmcalJetTask(const char *name) :
89 AliAnalysisTaskSE(name),
90 fTracksName("Tracks"),
91 fCaloName("CaloClusters"),
94 fJetType(kAKT|kFullJet|kRX1Jet),
102 fPhiMax(TMath::TwoPi()),
113 fRecombScheme(fastjet::pt_scheme),
114 fTrackEfficiency(1.),
122 fDoGenericSubtraction(kFALSE),
123 fDoConstituentSubtraction(kFALSE),
124 fUseExternalBkg(kFALSE),
137 // Standard constructor.
139 fBranchNames="ESD:AliESDRun.,AliESDHeader.,PrimaryVertex.";
142 //________________________________________________________________________
143 AliEmcalJetTask::~AliEmcalJetTask()
148 //________________________________________________________________________
149 void AliEmcalJetTask::UserCreateOutputObjects()
151 // Create user objects.
153 fJets = new TClonesArray("AliEmcalJet");
154 fJets->SetName(fJetsName);
156 if(!fJetsSubName.IsNull()) {
157 fJetsSub = new TClonesArray("AliEmcalJet");
158 fJetsSub->SetName(fJetsSubName);
162 //________________________________________________________________________
163 void AliEmcalJetTask::UserExec(Option_t *)
165 // Main loop, called for each event.
172 // clear the jet array (normally a null operation)
174 if(fJetsSub) fJetsSub->Delete();
179 //________________________________________________________________________
180 void AliEmcalJetTask::Terminate(Option_t *)
182 // Called once at the end of the analysis.
185 //________________________________________________________________________
186 void AliEmcalJetTask::FindJets()
189 if (!fTracks && !fClus){
190 cout << "WARNING NO TRACKS OR CLUSTERS:" <<endl;
195 fRho = fRhoParam->GetVal();
197 fRhom = fRhomParam->GetVal();
200 fastjet::JetAlgorithm jalgo(fastjet::kt_algorithm);
201 if ((fJetType & kAKT) != 0) {
203 jalgo = fastjet::antikt_algorithm;
204 AliDebug(1,"Using AKT algorithm");
207 AliDebug(1,"Using KT algorithm");
210 if ((fJetType & kR020Jet) != 0)
212 else if ((fJetType & kR030Jet) != 0)
214 else if ((fJetType & kR040Jet) != 0)
218 AliFJWrapper fjw(name, name);
219 fjw.SetAreaType(fastjet::active_area_explicit_ghosts);
220 fjw.SetGhostArea(fGhostArea);
222 fjw.SetAlgorithm(jalgo);
223 fjw.SetRecombScheme(static_cast<fastjet::RecombinationScheme>(fRecombScheme));
224 fjw.SetMaxRap(fEtaMax);
227 // get primary vertex
228 Double_t vertex[3] = {0, 0, 0};
229 if(fEvent->GetPrimaryVertex()) fEvent->GetPrimaryVertex()->GetXYZ(vertex);
231 AliDebug(2,Form("Jet type = %d", fJetType));
233 if ((fIsMcPart || ((fJetType & kFullJet) != 0) || ((fJetType & kChargedJet) != 0)) && fTracks) {
234 const Int_t Ntracks = fTracks->GetEntries();
235 for (Int_t iTracks = 0; iTracks < Ntracks; ++iTracks) {
236 AliVParticle *t = static_cast<AliVParticle*>(fTracks->At(iTracks));
240 if (((fJetType & kChargedJet) != 0) && (t->Charge() == 0)) {
241 AliDebug(2,Form("Skipping track %d because it is neutral.", iTracks));
244 if (((fJetType & kNeutralJet) != 0) && (t->Charge() != 0)) {
245 AliDebug(2,Form("Skipping track %d because it is charged.", iTracks));
249 if (fIsMcPart || TMath::Abs(t->GetLabel()) > fMinMCLabel) {
250 if (t->TestBits(fMCConstSel) != (Int_t)fMCConstSel) {
251 AliDebug(2,Form("Skipping track %d because it does not match the bit mask (%d, %d)", iTracks, fMCConstSel, t->TestBits(TObject::kBitMask)));
255 AliDebug(2,Form("Track %d matches the bit mask (%d, %d)", iTracks, fMCConstSel, t->TestBits(TObject::kBitMask)));
259 if (t->TestBits(fConstSel) != (Int_t)fConstSel) {
260 AliDebug(2,Form("Skipping track %d because it does not match the bit mask (%d, %d)", iTracks, fConstSel, t->TestBits(TObject::kBitMask)));
264 AliDebug(2,Form("Track %d matches the bit mask (%d, %d)", iTracks, fConstSel, t->TestBits(TObject::kBitMask)));
267 if (t->Pt() < fMinJetTrackPt)
269 Double_t eta = t->Eta();
270 Double_t phi = t->Phi();
271 if ((eta<fEtaMin) || (eta>fEtaMax) ||
272 (phi<fPhiMin) || (phi>fPhiMax))
275 // artificial inefficiency
276 if (fTrackEfficiency < 1.) {
277 Double_t rnd = gRandom->Rndm();
278 if (fTrackEfficiency < rnd) {
279 AliDebug(2,Form("Track %d rejected due to artificial tracking inefficiency", iTracks));
284 // offset of 100 for consistency with cluster ids
285 AliDebug(2,Form("Track %d accepted (label = %d, pt = %f)", iTracks, t->GetLabel(), t->Pt()));
286 fjw.AddInputVector(t->Px(), t->Py(), t->Pz(), t->E(), iTracks + 100);
290 if ((((fJetType & kFullJet) != 0) || ((fJetType & kNeutralJet) != 0)) && fClus) {
291 const Int_t Nclus = fClus->GetEntries();
292 for (Int_t iClus = 0; iClus < Nclus; ++iClus) {
294 Double_t cEta=0,cPhi=0,cPt=0;
295 Double_t cPx=0,cPy=0,cPz=0;
297 AliEmcalParticle *ep = static_cast<AliEmcalParticle*>(fClus->At(iClus));
301 c = ep->GetCluster();
305 if (c->GetLabel() > fMinMCLabel) {
306 if (ep->TestBits(fMCConstSel) != (Int_t)fMCConstSel) {
307 AliDebug(2,Form("Skipping cluster %d because it does not match the bit mask (%d, %d)", iClus, fMCConstSel, ep->TestBits(TObject::kBitMask)));
311 AliDebug(2,Form("Cluster %d matches the bit mask (%d, %d)", iClus, fMCConstSel, ep->TestBits(TObject::kBitMask)));
315 if (ep->TestBits(fConstSel) != (Int_t)fConstSel) {
316 AliDebug(2,Form("Skipping cluster %d because it does not match the bit mask (%d, %d)", iClus, fConstSel, ep->TestBits(TObject::kBitMask)));
320 AliDebug(2,Form("Cluster %d matches the bit mask (%d, %d)", iClus, fConstSel, ep->TestBits(TObject::kBitMask)));
331 c = static_cast<AliVCluster*>(fClus->At(iClus));
335 if (c->GetLabel() > fMinMCLabel) {
336 if (c->TestBits(fMCConstSel) != (Int_t)fMCConstSel) {
337 AliDebug(2,Form("Skipping cluster %d because it does not match the bit mask (%d, %d)", iClus, fMCConstSel, c->TestBits(TObject::kBitMask)));
341 AliDebug(2,Form("Cluster %d matches the bit mask (%d, %d)", iClus, fMCConstSel, c->TestBits(TObject::kBitMask)));
345 if (c->TestBits(fConstSel) != (Int_t)fConstSel) {
346 AliDebug(2,Form("Skipping cluster %d because it does not match the bit mask (%d, %d)", iClus, fConstSel, c->TestBits(TObject::kBitMask)));
350 AliDebug(2,Form("Cluster %d matches the bit mask (%d, %d)", iClus, fConstSel, c->TestBits(TObject::kBitMask)));
355 c->GetMomentum(nP, vertex);
365 if (cPt < fMinJetClusPt)
367 if ((cEta<fEtaMin) || (cEta>fEtaMax) ||
368 (cPhi<fPhiMin) || (cPhi>fPhiMax))
370 // offset of 100 to skip ghost particles uid = -1
371 AliDebug(2,Form("Cluster %d accepted (label = %d)", iClus, c->GetLabel()));
372 fjw.AddInputVector(cPx, cPy, cPz, TMath::Sqrt(cPx*cPx+cPy*cPy+cPz*cPz), -iClus - 100);
376 // setting legacy mode
378 fjw.SetLegacyMode(kTRUE);
384 //run generic subtractor
385 if(fDoGenericSubtraction) {
386 fjw.SetUseExternalBkg(fUseExternalBkg,fRho,fRhom);
387 fjw.DoGenericSubtractionJetMass();
390 //run constituent subtractor
391 if(fDoConstituentSubtraction) {
392 fjw.SetUseExternalBkg(fUseExternalBkg,fRho,fRhom);
393 fjw.DoConstituentSubtraction();
397 AliEMCALGeometry *geom = AliEMCALGeometry::GetInstance();
399 AliFatal(Form("%s: Can not create geometry", GetName()));
403 // loop over fastjet jets
404 std::vector<fastjet::PseudoJet> jets_incl = fjw.GetInclusiveJets();
405 // sort jets according to jet pt
406 static Int_t indexes[9999] = {-1};
407 GetSortedArray(indexes, jets_incl);
409 AliDebug(1,Form("%d jets found", (Int_t)jets_incl.size()));
410 for (UInt_t ijet=0, jetCount=0; ijet<jets_incl.size(); ++ijet) {
411 Int_t ij = indexes[ijet];
412 AliDebug(3,Form("Jet pt = %f, area = %f", jets_incl[ij].perp(), fjw.GetJetArea(ij)));
414 if (jets_incl[ij].perp()<fMinJetPt)
416 if (fjw.GetJetArea(ij)<fMinJetArea)
418 if ((jets_incl[ij].eta()<fJetEtaMin) || (jets_incl[ij].eta()>fJetEtaMax) ||
419 (jets_incl[ij].phi()<fJetPhiMin) || (jets_incl[ij].phi()>fJetPhiMax))
422 AliEmcalJet *jet = new ((*fJets)[jetCount])
423 AliEmcalJet(jets_incl[ij].perp(), jets_incl[ij].eta(), jets_incl[ij].phi(), jets_incl[ij].m());
426 //do generic subtraction if requested
427 if(fDoGenericSubtraction) {
428 #ifdef FASTJET_VERSION
429 std::vector<fastjet::contrib::GenericSubtractorInfo> jetMassInfo = fjw.GetGenSubtractorInfoJetMass();
430 UInt_t n = (UInt_t)jetMassInfo.size();
432 jet->SetFirstDerivative(jetMassInfo[ij].first_derivative());
433 jet->SetSecondDerivative(jetMassInfo[ij].second_derivative());
434 jet->SetFirstOrderSubtracted(jetMassInfo[ij].first_order_subtracted());
435 jet->SetSecondOrderSubtracted(jetMassInfo[ij].second_order_subtracted());
440 // loop over constituents
441 std::vector<fastjet::PseudoJet> constituents(fjw.GetJetConstituents(ij));
442 jet->SetNumberOfTracks(constituents.size());
443 jet->SetNumberOfClusters(constituents.size());
447 Double_t neutralE = 0;
458 for(UInt_t ic = 0; ic < constituents.size(); ++ic) {
459 Int_t uid = constituents[ic].user_index();
460 AliDebug(3,Form("Processing constituent %d", uid));
461 if ((uid == -1) /*&& (constituents[ic].kt2() < 1e-25)*/) { //ghost particle
463 Double_t gphi = constituents[ic].phi();
465 gphi += TMath::TwoPi();
466 gphi *= TMath::RadToDeg();
467 Double_t geta = constituents[ic].eta();
468 if ((gphi > geom->GetArm1PhiMin()) && (gphi < geom->GetArm1PhiMax()) &&
469 (geta > geom->GetArm1EtaMin()) && (geta < geom->GetArm1EtaMax()))
471 } else if ((uid > 0) && fTracks) { // track constituent
472 Int_t tid = uid - 100;
473 AliVParticle *t = static_cast<AliVParticle*>(fTracks->At(tid));
475 AliError(Form("Could not find track %d",tid));
478 if (jetCount < fMarkConst) {
479 AliDebug(2,Form("Marking track %d with bit map %d", tid, fJetType));
482 Double_t cEta = t->Eta();
483 Double_t cPhi = t->Phi();
484 Double_t cPt = t->Pt();
485 Double_t cP = t->P();
486 if (t->Charge() == 0) {
496 if (fIsMcPart || TMath::Abs(t->GetLabel()) > fMinMCLabel) // check if MC particle
500 cPhi += TMath::TwoPi();
501 cPhi *= TMath::RadToDeg();
502 if ((cPhi > geom->GetArm1PhiMin()) && (cPhi < geom->GetArm1PhiMax()) &&
503 (cEta > geom->GetArm1EtaMin()) && (cEta < geom->GetArm1EtaMax())) {
508 jet->AddTrackAt(tid, nt);
510 } else if (fClus) { // cluster constituent
511 Int_t cid = -uid - 100;
513 Double_t cEta=0,cPhi=0,cPt=0,cP=0;
515 AliEmcalParticle *ep = static_cast<AliEmcalParticle*>(fClus->At(cid));
518 c = ep->GetCluster();
521 if (jetCount < fMarkConst)
522 ep->SetBit(fJetType);
528 c = static_cast<AliVCluster*>(fClus->At(cid));
531 if (jetCount < fMarkConst)
534 c->GetMomentum(nP, vertex);
545 if (c->GetLabel() > fMinMCLabel) // MC particle
546 mcpt += c->GetMCEnergyFraction() > 1e-6 ? cPt * c->GetMCEnergyFraction() : cPt;
549 cPhi += TMath::TwoPi();
550 cPhi *= TMath::RadToDeg();
551 if ((cPhi > geom->GetArm1PhiMin()) && (cPhi < geom->GetArm1PhiMax()) &&
552 (cEta > geom->GetArm1EtaMin()) && (cEta < geom->GetArm1EtaMax())) {
557 jet->AddClusterAt(cid, nc);
561 AliError(Form("%s: No logical way to end up here.", GetName()));
564 } /* end of constituent loop */
566 jet->SetNumberOfTracks(nt);
567 jet->SetNumberOfClusters(nc);
568 jet->SortConstituents();
569 jet->SetMaxNeutralPt(maxNe);
570 jet->SetMaxChargedPt(maxCh);
571 jet->SetNEF(neutralE / jet->E());
572 fastjet::PseudoJet area(fjw.GetJetAreaVector(ij));
573 jet->SetArea(area.perp());
574 jet->SetAreaEta(area.eta());
575 jet->SetAreaPhi(area.phi());
576 jet->SetNumberOfCharged(ncharged);
577 jet->SetNumberOfNeutrals(nneutral);
580 jet->SetPtEmc(emcpt);
583 jet->SetAreaEmc(fjw.GetJetArea(ij) * gemc / gall);
586 if ((jet->Phi() > geom->GetArm1PhiMin() * TMath::DegToRad()) &&
587 (jet->Phi() < geom->GetArm1PhiMax() * TMath::DegToRad()) &&
588 (jet->Eta() > geom->GetArm1EtaMin()) &&
589 (jet->Eta() < geom->GetArm1EtaMax()))
590 jet->SetAxisInEmcal(kTRUE);
592 AliDebug(2,Form("Added jet n. %d, pt = %f, area = %f, constituents = %d", jetCount, jet->Pt(), jet->Area(), (Int_t)constituents.size()));
597 //run constituent subtractor if requested
598 if(fDoConstituentSubtraction) {
599 #ifdef FASTJET_VERSION
600 if(!fJetsSub) AliWarning(Form("No jet branch to write to for subtracted jets. fJetsSubName: %s",fJetsSubName.Data()));
602 std::vector<fastjet::PseudoJet> jets_sub;
603 jets_sub = fjw.GetConstituentSubtrJets();
604 AliDebug(1,Form("%d constituent subtracted jets found", (Int_t)jets_sub.size()));
605 for (UInt_t ijet=0, jetCount=0; ijet<jets_sub.size(); ++ijet) {
606 //Only storing 4-vector and jet area of unsubtracted jet
607 AliEmcalJet *jet_sub = new ((*fJetsSub)[jetCount])
608 AliEmcalJet(jets_sub[ijet].perp(), jets_sub[ijet].eta(), jets_sub[ijet].phi(), jets_sub[ijet].m());
609 jet_sub->SetLabel(ijet);
610 fastjet::PseudoJet area(fjw.GetJetAreaVector(ijet));
611 jet_sub->SetArea(area.perp());
612 jet_sub->SetAreaEta(area.eta());
613 jet_sub->SetAreaPhi(area.phi());
614 jet_sub->SetAreaEmc(area.perp());
619 } //constituent subtraction
622 //________________________________________________________________________
623 Bool_t AliEmcalJetTask::GetSortedArray(Int_t indexes[], std::vector<fastjet::PseudoJet> array) const
625 // Get the leading jets.
627 static Float_t pt[9999] = {0};
629 const Int_t n = (Int_t)array.size();
634 for (Int_t i = 0; i < n; i++)
635 pt[i] = array[i].perp();
637 TMath::Sort(n, pt, indexes);
642 //________________________________________________________________________
643 Bool_t AliEmcalJetTask::DoInit()
645 // Init. Return true if successful.
647 if (fTrackEfficiency < 1.) {
648 if (gRandom) delete gRandom;
649 gRandom = new TRandom3(0);
652 // get input collections
653 AliAnalysisManager *am = AliAnalysisManager::GetAnalysisManager();
656 fEvent = InputEvent();
658 AliError(Form("%s: Could not retrieve event! Returning", GetName()));
662 // add jets to event if not yet there
663 if (!(fEvent->FindListObject(fJetsName)))
664 fEvent->AddObject(fJets);
666 AliError(Form("%s: Object with name %s already in event! Returning", GetName(), fJetsName.Data()));
670 if (!(fEvent->FindListObject(fJetsSubName)) && fJetsSub)
671 fEvent->AddObject(fJetsSub);
673 if (fTracksName == "Tracks")
674 am->LoadBranch("Tracks");
675 if (!fTracks && !fTracksName.IsNull()) {
676 fTracks = dynamic_cast<TClonesArray*>(fEvent->FindListObject(fTracksName));
678 AliError(Form("%s: Pointer to tracks %s == 0", GetName(), fTracksName.Data()));
683 TClass cls(fTracks->GetClass()->GetName());
684 if (cls.InheritsFrom("AliMCParticle") || cls.InheritsFrom("AliAODMCParticle"))
688 if (fCaloName == "CaloClusters")
689 am->LoadBranch("CaloClusters");
690 if (!fClus && !fCaloName.IsNull()) {
691 fClus = dynamic_cast<TClonesArray*>(fEvent->FindListObject(fCaloName));
693 AliError(Form("%s: Pointer to clus %s == 0", GetName(), fCaloName.Data()));
698 TClass cls(fClus->GetClass()->GetName());
699 if (cls.InheritsFrom("AliEmcalParticle"))
703 if (!fRhoName.IsNull() && !fRhoParam) { // get rho from the event
704 fRhoParam = dynamic_cast<AliRhoParameter*>(InputEvent()->FindListObject(fRhoName));
706 AliError(Form("%s: Could not retrieve rho %s!", GetName(), fRhoName.Data()));
710 if (!fRhomName.IsNull() && !fRhomParam) { // get rhom from the event
711 fRhomParam = dynamic_cast<AliRhoParameter*>(InputEvent()->FindListObject(fRhomName));
713 AliError(Form("%s: Could not retrieve rho %s!", GetName(), fRhomName.Data()));