Skip to content

Commit caad660

Browse files
committed
change jet definition
1 parent 30ca6bf commit caad660

File tree

2 files changed

+102
-151
lines changed

2 files changed

+102
-151
lines changed
Lines changed: 7 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,3 @@
1-
#include "TFile.h"
2-
#include "TTree.h"
3-
#include "TMath.h"
4-
#include "fastjet/ClusterSequence.hh"
5-
#include <vector>
6-
#include <iostream>
7-
#include "DataFormatsMC/MCTrack.h"
8-
9-
using namespace fastjet;
10-
111
int External() {
122
std::string path{"o2sim_Kine.root"};
133

@@ -22,73 +12,16 @@ int External() {
2212
std::cerr << "Cannot find tree o2sim in file " << path << "\n";
2313
return 1;
2414
}
25-
2615
std::vector<o2::MCTrack> *tracks{};
2716
tree->SetBranchAddress("MCTrack", &tracks);
2817

29-
// Jet parameters
30-
const double ptJetThreshold = 10.0;
31-
const double jetR = 0.4;
32-
const int gapSize = 4; // 4 events auto-accepted, 5th needs strange-in-jet
33-
34-
// Xi and Omega PDG codes
35-
const std::vector<int> pdgXiOmega = {3312, -3312, 3334, -3334};
36-
37-
Long64_t nEntries = tree->GetEntries();
38-
39-
for (Long64_t iEntry = 0; iEntry < nEntries; ++iEntry) {
40-
tree->GetEntry(iEntry);
41-
if (!tracks || tracks->empty()) continue;
42-
43-
bool acceptEvent = false;
44-
45-
// Gap-trigger logic
46-
if (iEntry % (gapSize + 1) < gapSize) {
47-
// Accept event automatically
48-
acceptEvent = true;
49-
std::cout << "Gap-trigger accepted event " << iEntry << " (no Xi/Omega check)\n";
50-
} else {
51-
// Require Xi/Omega inside a jet
52-
std::vector<PseudoJet> fjParticles;
53-
std::vector<int> fjIndexMap;
54-
for (size_t i = 0; i < tracks->size(); ++i) {
55-
const auto &t = tracks->at(i);
56-
if (t.GetPdgCode() == 0) continue;
57-
if (std::abs(t.GetEta()) > 0.8) continue; // acceptance cut
58-
fjParticles.emplace_back(t.GetPx(), t.GetPy(), t.GetPz(), t.GetE());
59-
fjIndexMap.push_back(i);
60-
}
61-
62-
if (!fjParticles.empty()) {
63-
JetDefinition jetDef(antikt_algorithm, jetR);
64-
ClusterSequence cs(fjParticles, jetDef);
65-
std::vector<PseudoJet> jets = sorted_by_pt(cs.inclusive_jets(ptJetThreshold));
66-
67-
for (auto &jet : jets) {
68-
auto constituents = jet.constituents();
69-
for (auto &c : constituents) {
70-
int trackIndex = fjIndexMap[c.user_index()];
71-
int pdg = tracks->at(trackIndex).GetPdgCode();
72-
if (std::find(pdgXiOmega.begin(), pdgXiOmega.end(), pdg) != pdgXiOmega.end()) {
73-
acceptEvent = true;
74-
std::cout << "Accepted event " << iEntry
75-
<< ": Jet pt = " << jet.pt()
76-
<< ", eta = " << jet.eta()
77-
<< ", phi = " << jet.phi()
78-
<< ", contains PDG " << pdg << "\n";
79-
break;
80-
}
81-
}
82-
if (acceptEvent) break;
83-
}
84-
}
85-
}
86-
87-
if (acceptEvent) {
88-
// Here you could break if you only want the first accepted event,
89-
// or continue to process all events following the gap-trigger pattern
90-
}
18+
auto nXi = tree->Scan("MCTrack.GetPdgCode()", "TMath::Abs(MCTrack.GetPdgCode()) == 3312");
19+
auto nOmega = tree->Scan("MCTrack.GetPdgCode()", "TMath::Abs(MCTrack.GetPdgCode()) == 3334");
20+
auto nStr = nXi+nOmega;
21+
22+
if (nStr == 0) {
23+
std::cerr << "No event of interest\n";
24+
return 1;
9125
}
92-
9326
return 0;
9427
}

MC/config/PWGLF/pythia8/generator_pythia8_strangeness_in_jets.C

Lines changed: 95 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,126 @@
1+
#if !defined(__CLING__) || defined(__ROOTCLING__)
12
#include "FairGenerator.h"
23
#include "FairPrimaryGenerator.h"
34
#include "Generators/GeneratorPythia8.h"
4-
55
#include "Pythia8/Pythia.h"
6-
7-
#include <fastjet/PseudoJet.hh>
8-
#include <fastjet/JetDefinition.hh>
9-
#include <fastjet/ClusterSequence.hh>
10-
6+
#include "TDatabasePDG.h"
7+
#include "TMath.h"
8+
#include "TParticlePDG.h"
9+
#include "TRandom3.h"
10+
#include "TSystem.h"
11+
#include "TVector2.h"
12+
#include "fairlogger/Logger.h"
1113
#include <cmath>
12-
#include <vector>
14+
#include <fstream>
1315
#include <string>
14-
#include <algorithm>
15-
16+
#include <vector>
1617
using namespace Pythia8;
17-
using namespace fastjet;
18+
#endif
1819

19-
/// Pythia8 event generator for pp collisions
20-
/// Selection of events with Xi or Omega inside jets with pt > 10 GeV
21-
/// Jets built from physical primaries OR HF decay products
20+
/// Event generator using Pythia ropes for Ξ and Ω production in jets.
21+
/// Jets are defined as particles within a cone around the highest-pT particle
22+
/// (approximate jet axis) and include charged final-state particles that are
23+
/// either physical primaries or from heavy-flavor decays.
24+
/// Jets must be fully within the acceptance and have pT > 10 GeV.
25+
/// One event of interest is generated after 4 minimum-bias events.
2226

23-
class GeneratorPythia8StrangeInJet : public o2::eventgen::GeneratorPythia8 {
27+
class GeneratorPythia8StrangenessInJet : public o2::eventgen::GeneratorPythia8 {
2428
public:
2529
/// Constructor
26-
GeneratorPythia8StrangeInJet(double ptJetThreshold = 10.0,
27-
double jetR = 0.4,
28-
int gapSize = 4)
30+
GeneratorPythia8StrangenessInJet(double ptJetMin = 10.0, double Rjet = 0.4, int gapSize = 4)
2931
: o2::eventgen::GeneratorPythia8(),
30-
mPtJetThreshold(ptJetThreshold),
31-
mJetR(jetR),
32+
mptJetMin(ptJetMin),
33+
mRjet(Rjet),
3234
mGapSize(gapSize)
3335
{
3436
fmt::printf(
35-
">> Pythia8 generator: Xi/Omega inside jets with ptJet > %.1f GeV, R = %.1f, gap = %d\n",
36-
ptJetThreshold, jetR, gapSize);
37+
">> Pythia8 generator: Xi/Omega inside jets with pt_{jet} > %.1f GeV, R_{jet} = %.1f, gap = %d\n",
38+
ptJetMin, Rjet, gapSize);
3739
}
38-
39-
~GeneratorPythia8StrangeInJet() = default;
40+
/// Destructor
41+
~GeneratorPythia8StrangenessInJet() = default;
4042

4143
bool Init() override {
4244
addSubGenerator(0, "Pythia8 events with Xi/Omega inside jets");
4345
return o2::eventgen::GeneratorPythia8::Init();
4446
}
4547

4648
protected:
47-
/// Check if particle is physical primary OR from HF decay
48-
bool isPhysicalPrimaryOrFromHF(const Pythia8::Particle& p,
49-
const Pythia8::Event& event)
49+
/// Check if particle is physical primary or from HF decay
50+
bool isPhysicalPrimaryOrFromHF(const Pythia8::Particle& p, const Pythia8::Event& event)
5051
{
52+
// Select only final-state particles
5153
if (!p.isFinal()) {
5254
return false;
5355
}
5456

55-
const int absPdg = std::abs(p.id());
56-
5757
// Particle species selection
58-
const bool isAcceptedSpecies = (absPdg == 211 || absPdg == 321 || absPdg == 2212 || absPdg == 1000010020 || absPdg == 11 || absPdg == 13);
59-
60-
if (!isAcceptedSpecies) {
58+
const int absPdg = std::abs(p.id());
59+
if (absPdg!=211 && absPdg!=321 && absPdg!= 2212 && absPdg!=1000010020 && absPdg!=11 && absPdg!=13)
6160
return false;
62-
}
6361

6462
// Walk up ancestry
65-
int motherIdx = p.mother1();
63+
int motherId = p.mother1();
6664

67-
while (motherIdx > 0) {
68-
const auto& mother = event[motherIdx];
65+
while (motherId > 0) {
66+
67+
// Get mother
68+
const auto& mother = event[motherId];
6969
const int absMotherPdg = std::abs(mother.id());
7070

71-
// Charm or beauty hadron → accept (HF decay)
71+
// Check if particle is from HF decay
7272
if ((absMotherPdg / 100 == 4) || (absMotherPdg / 100 == 5) || (absMotherPdg / 1000 == 4) || (absMotherPdg / 1000 == 5)) {
7373
return true;
7474
}
7575

76-
// Weakly decaying hadron → reject (non-physical primary)
76+
// Reject non-physical primary hadrons
7777
if (mother.isHadron() && mother.tau0() > 1.0) {
7878
return false;
7979
}
80-
motherIdx = mother.mother1();
80+
motherId = mother.mother1();
8181
}
8282
return true;
8383
}
8484

85+
// Compute delta phi
86+
double getDeltaPhi(double a1, double a2)
87+
{
88+
double deltaPhi{0.0};
89+
double phi1 = TVector2::Phi_0_2pi(a1);
90+
double phi2 = TVector2::Phi_0_2pi(a2);
91+
double diff = std::fabs(phi1 - phi2);
92+
93+
if (diff <= M_PI)
94+
deltaPhi = diff;
95+
if (diff > M_PI)
96+
deltaPhi = 2.0 * M_PI - diff;
97+
98+
return deltaPhi;
99+
}
100+
85101
bool generateEvent() override {
86-
fmt::printf(">> Generating event %lu\n", mGeneratedEvents);
102+
fmt::printf(">> Generating event %d\n", mGeneratedEvents);
87103

88104
bool genOk = false;
89105
int localCounter{0};
106+
constexpr int kMaxTries{100000};
90107

91108
// Accept mGapSize events unconditionally, then one triggered event
92109
if (mGeneratedEvents % (mGapSize + 1) < mGapSize) {
93110
genOk = GeneratorPythia8::generateEvent();
94111
fmt::printf(">> Gap-trigger accepted event (no strangeness check)\n");
95112
} else {
96-
while (!genOk) {
113+
while (!genOk && localCounter < kMaxTries) {
97114
if (GeneratorPythia8::generateEvent()) {
98115
genOk = selectEvent(mPythia.event);
99116
}
100117
localCounter++;
101118
}
102-
fmt::printf(">> Event accepted after %d iterations (Xi/Omega in jet)\n",
103-
localCounter);
119+
if (!genOk) {
120+
fmt::printf("Failed to generate triggered event after %d tries\n",kMaxTries);
121+
return false;
122+
}
123+
fmt::printf(">> Event accepted after %d iterations (Xi/Omega in jet)\n", localCounter);
104124
}
105125

106126
notifySubGenerator(0);
@@ -109,56 +129,54 @@ protected:
109129
}
110130

111131
bool selectEvent(Pythia8::Event &event) {
112-
const std::vector<int> pdgXiOmega = {3312, -3312, 3334, -3334};
113-
const double mpi = 0.1395704;
114132

115-
std::vector<fastjet::PseudoJet> fjParticles;
133+
double etaJet{-999.0}, phiJet{-999.0}, ptMax{0.0};
134+
std::vector<int> particleID;
135+
bool containsXiOrOmega{false};
116136

117-
for (int i = 0; i < event.size(); ++i) {
137+
for (int i = 0; i < event.size(); i++) {
118138
const auto& p = event[i];
139+
if (std::abs(p.id()) == 3312 || std::abs(p.id()) == 3334)
140+
containsXiOrOmega = true;
119141

120-
// --- Jet input selection ---
121-
if (!p.isFinal()) continue;
122-
if (!p.isCharged()) continue;
142+
if (std::abs(p.eta()) > 0.8 || p.pT() < 0.1) continue;
123143
if (!isPhysicalPrimaryOrFromHF(p, event)) continue;
124-
if (std::abs(p.eta()) > 0.8) continue;
144+
particleID.emplace_back(i);
125145

126-
double pt = std::sqrt(p.px() * p.px() + p.py() * p.py());
127-
if (pt < 0.1) continue;
128-
129-
double energy = std::sqrt(p.p() * p.p() + mpi * mpi);
130-
131-
fastjet::PseudoJet pj(p.px(), p.py(), p.pz(), energy);
132-
pj.set_user_index(i); // map back to Pythia index
133-
fjParticles.push_back(pj);
146+
if (p.pT() > ptMax) {
147+
ptMax = p.pT();
148+
etaJet = p.eta();
149+
phiJet = p.phi();
150+
}
134151
}
152+
if (ptMax == 0.0)
153+
return false;
154+
if (std::abs(etaJet) + Rjet > 0.8)
155+
return false;
156+
if (!containsXiOrOmega)
157+
return false;
135158

136-
if (fjParticles.empty()) return false;
137-
138-
fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, mJetR);
139-
fastjet::ClusterSequence cs(fjParticles, jetDef);
140-
auto jets = fastjet::sorted_by_pt(cs.inclusive_jets(mPtJetThreshold));
141-
142-
for (const auto& jet : jets) {
143-
for (const auto& c : jet.constituents()) {
144-
int idx = c.user_index();
145-
int pdg = event[idx].id();
159+
double ptJet{0.0};
160+
for (int i = 0 ; i < particleID.size() ; i++) {
161+
int id = particleID[i];
162+
const auto& p = event[id];
146163

147-
if (std::find(pdgXiOmega.begin(), pdgXiOmega.end(), pdg) != pdgXiOmega.end()) {
148-
fmt::printf(
149-
">> Accepted jet: pt = %.2f, eta = %.2f, phi = %.2f, contains PDG %d\n",
150-
jet.pt(), jet.eta(), jet.phi(), pdg);
151-
return true;
152-
}
164+
double deltaEta = std::abs(p.eta() - etaJet);
165+
double deltaPhi = getDeltaPhi(p.phi(),phiJet);
166+
double deltaR = std::sqrt(deltaEta * deltaEta + deltaPhi * deltaPhi);
167+
if (deltaR < Rjet) {
168+
ptJet += p.pT();
153169
}
154170
}
171+
if (ptJet < ptJetMin)
172+
return false;
155173

156-
return false;
174+
return true;
157175
}
158176

159177
private:
160-
double mPtJetThreshold{10.0};
161-
double mJetR{0.4};
178+
double mptJetMin{10.0};
179+
double mRjet{0.4};
162180
int mGapSize{4};
163181
uint64_t mGeneratedEvents{0};
164182
};

0 commit comments

Comments
 (0)