@@ -128,6 +128,13 @@ struct ReducedParticle {
128128 }
129129};
130130
131+ // Jet Matching
132+ struct JetMatching {
133+ double distance;
134+ double ptTrue;
135+ double ptDiff;
136+ };
137+
131138struct AntinucleiInJets {
132139
133140 // Histogram registries for data, MC, quality control, multiplicity and correlations
@@ -145,6 +152,7 @@ struct AntinucleiInJets {
145152 Configurable<double> cfgAreaFrac{"cfgAreaFrac", 0.6, "fraction of jet area"};
146153 Configurable<double> cfgEtaJetMax{"cfgEtaJetMax", 0.5, "max jet eta"};
147154 Configurable<double> cfgMinPtTrack{"cfgMinPtTrack", 0.15, "minimum pt of tracks for jet reconstruction"};
155+ Configurable<double> alpha{"alpha", 0.3, "parameter to control jet matching"};
148156
149157 // Event selection criteria
150158 Configurable<bool> rejectITSROFBorder{"rejectITSROFBorder", true, "Reject events near the ITS ROF border"};
@@ -501,6 +509,11 @@ struct AntinucleiInJets {
501509 registryMC.add("antiproton_coal_ue", "antiproton_coal_ue", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}});
502510 }
503511
512+ // jet pt resolution
513+ if (doprocessJetPtResolution) {
514+ registryMC.add("jetPtResolution", "jet Pt Resolution", HistType::kTH2F, {{200, 0, 20, "#it{p}^{jet}_{T,true} (GeV/#it{c})"}}, {{1000, -5, 5, "#Delta #it{p}^{jet}_{T} (GeV/#it{c})"}});
515+ }
516+
504517 // Coalescence and Correlation analysis
505518 if (doprocessCoalescenceCorr) {
506519
@@ -3912,6 +3925,154 @@ struct AntinucleiInJets {
39123925 }
39133926 }
39143927 PROCESS_SWITCH(AntinucleiInJets, processCoalescenceCorr, "process coalescence correlation", false);
3928+
3929+
3930+ // Jet Pt resolution
3931+ void processJetPtResolution(RecCollisionsMc const& collisions, AntiNucleiTracksMc const& mcTracks, aod::McParticles const& mcParticles)
3932+ {
3933+ // Define per-event particle containers
3934+ std::vector<fastjet::PseudoJet> fjParticles;
3935+ std::vector<fastjet::PseudoJet> fjTracks;
3936+
3937+ // Jet and area definitions
3938+ fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, rJet);
3939+ fastjet::AreaDefinition areaDef(fastjet::active_area, fastjet::GhostedAreaSpec(1.0));
3940+
3941+ // Loop over all reconstructed collisions
3942+ for (const auto& collision : collisions) {
3943+
3944+ // Clear containers at the start of the event loop
3945+ fjParticles.clear();
3946+ fjTracks.clear();
3947+
3948+ // Reject reconstructed collisions with no simulated collision
3949+ if (!collision.has_mcCollision())
3950+ continue;
3951+
3952+ // Apply event selection: require sel8 and vertex position to be within the allowed z range
3953+ if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx)
3954+ continue;
3955+
3956+ // Reject events near the ITS Read-Out Frame border
3957+ if (rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))
3958+ continue;
3959+
3960+ // Reject events at the Time Frame border
3961+ if (rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder))
3962+ continue;
3963+
3964+ // Require at least one ITS-TPC matched track
3965+ if (requireVtxITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC))
3966+ continue;
3967+
3968+ // Reject events with same-bunch pileup
3969+ if (rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))
3970+ continue;
3971+
3972+ // Require consistent FT0 vs PV z-vertex
3973+ if (requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV))
3974+ continue;
3975+
3976+ // Require TOF match for at least one vertex track
3977+ if (requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched))
3978+ continue;
3979+
3980+ // Get tracks and particles in this MC collision
3981+ const auto mcTracksThisMcColl = mcTracks.sliceBy(mcTracksPerMcCollision, collision.globalIndex());
3982+ const auto mcParticlesThisMcColl = mcParticles.sliceBy(mcParticlesPerMcCollision, collision.globalIndex());
3983+
3984+ // Loop over reconstructed tracks
3985+ for (auto const& track : mcTracksThisMcColl) {
3986+
3987+ // Apply track selection for jet reconstruction
3988+ if (!passedTrackSelectionForJetReconstruction(track))
3989+ continue;
3990+
3991+ // 4-momentum representation of a particle
3992+ fastjet::PseudoJet fourMomentum(track.px(), track.py(), track.pz(), track.energy(MassPionCharged));
3993+ fjTracks.emplace_back(fourMomentum);
3994+ }
3995+
3996+ // Loop over MC particles
3997+ for (const auto& particle : mcParticlesThisMcColl) {
3998+
3999+ // Select physical primary particles or HF decay products
4000+ if (!isPhysicalPrimaryOrFromHF(particle, mcParticles))
4001+ continue;
4002+
4003+ // Select particles within acceptance
4004+ if (particle.eta() < minEta || particle.eta() > maxEta || particle.pt() < cfgMinPtTrack)
4005+ continue;
4006+
4007+ // 4-momentum representation of a particle
4008+ double energy = std::sqrt(particle.p() * particle.p() + MassPionCharged * MassPionCharged);
4009+ fastjet::PseudoJet fourMomentum(particle.px(), particle.py(), particle.pz(), energy);
4010+ fjParticles.emplace_back(fourMomentum);
4011+ }
4012+
4013+ // Reject empty events
4014+ if (fjTracks.empty() || fjParticles.empty())
4015+ continue;
4016+
4017+ // Cluster particles using the anti-kt algorithm
4018+ fastjet::ClusterSequenceArea csRec(fjTracks, jetDef, areaDef);
4019+ std::vector<fastjet::PseudoJet> jetsRec = fastjet::sorted_by_pt(csRec.inclusive_jets());
4020+
4021+ fastjet::ClusterSequenceArea csGen(fjParticles, jetDef, areaDef);
4022+ std::vector<fastjet::PseudoJet> jetsGen = fastjet::sorted_by_pt(csGen.inclusive_jets());
4023+
4024+ // Loop over reconstructed jets
4025+ std::vector<JetMatching> jetGenRec;
4026+ for (const auto& jetRec : jetsRec) {
4027+
4028+ // Jet must be fully contained in the acceptance
4029+ if ((std::fabs(jetRec.eta()) + rJet) > (maxEta - deltaEtaEdge))
4030+ continue;
4031+
4032+ // Apply area cut if required
4033+ if (applyAreaCut && (jetRec.area() / (PI * rJet * rJet)) > maxNormalizedJetArea)
4034+ continue;
4035+
4036+ // Clear jet-pair container
4037+ jetGenRec.clear();
4038+
4039+ for (const auto& jetGen : jetsGen) {
4040+
4041+ // Jet must be fully contained in the acceptance
4042+ if ((std::fabs(jetGen.eta()) + rJet) > (maxEta - deltaEtaEdge))
4043+ continue;
4044+
4045+ // Apply area cut if required
4046+ if (applyAreaCut && (jetGen.area() / (PI * rJet * rJet)) > maxNormalizedJetArea)
4047+ continue;
4048+
4049+ double deltaEta = jetGen.eta() - jetRec.eta();
4050+ double deltaPhi = getDeltaPhi(jetGen.phi(), jetRec.phi());
4051+ double deltaR = std::sqrt(deltaEta * deltaEta + deltaPhi * deltaPhi);
4052+ if (deltaR < rJet)
4053+ jetGenRec.emplace_back({deltaR, jetGen.pt(), jetGen.pt() - jetRec.pt()});
4054+ }
4055+ if (jetGenRec.empty())
4056+ continue;
4057+
4058+ double distanceMin(1e+06);
4059+ double diffPt(0);
4060+ double ptJetTrue(0);
4061+ for (const auto& jetPair : jetGenRec) {
4062+ if (jetPair.distance < distanceMin) {
4063+ distanceMin = jetPair.distance;
4064+ diffPt = jetPair.ptDiff;
4065+ ptJetTrue = jetPair.ptTrue;
4066+ }
4067+ }
4068+
4069+ if (distanceMin < alpha * rJet) {
4070+ registryMC.fill(HIST("jetPtResolution"), ptJetTrue, diffPt);
4071+ }
4072+ }
4073+ }
4074+ }
4075+ PROCESS_SWITCH(AntinucleiInJets, processJetPtResolution, "process jet pt resolution", false);
39154076};
39164077
39174078WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
0 commit comments