From 7ddb95eb662d5ce257c3831174e6217306e8fd3c Mon Sep 17 00:00:00 2001 From: Arvind Khuntia Date: Thu, 24 Sep 2026 20:50:21 +0200 Subject: [PATCH 1/4] [PWGJE] Fix leading-jet selection (Rec) and event normalization --- PWGJE/Tasks/nucleiInJets.cxx | 50 +++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/PWGJE/Tasks/nucleiInJets.cxx b/PWGJE/Tasks/nucleiInJets.cxx index 82ce31ad6da..ef26b204162 100644 --- a/PWGJE/Tasks/nucleiInJets.cxx +++ b/PWGJE/Tasks/nucleiInJets.cxx @@ -328,7 +328,8 @@ struct nucleiInJets { jetHist.add("jet/h2JetPtVsBkgRho", "jet_{p_{T}} vs background #rho; jet_{p_{T}} (GeV/c); #rho (GeV/c/area)", kTH2F, {PtJetAxis, {100, 0, 20}}); jetHist.add("jet/h1BkgRho", "Background #rho; #rho (GeV/c/area); Entries", kTH1F, {{100, 0, 20}}); jetHist.add("jet/h1JetEvents", "NumbeOfJetEvents", kTH1F, {{1, 0, 1}}); - jetHist.add("jetBkgSub/h1JetEvents", "Number of jet events with leading p_{T}^{jet,bkg sub} above cfgjetPtBkgSubMin", kTH1F, {{1, 0, 1}}); + jetHist.add("jetBkgSub/h1JetEventsBeforeRhoSelection", "Number of jet events with leading p_{T}^{jet,bkg sub} above cfgjetPtBkgSubMin before rho selection", kTH1F, {{1, 0, 1}}); + jetHist.add("jetBkgSub/h1JetEvents", "Number of jet events with leading p_{T}^{jet,bkg sub} above cfgjetPtBkgSubMin and rho > 0", kTH1F, {{1, 0, 1}}); jetHist.add("jetBkgSub/h1BkgRhoLeadingJetPtBkgSubAboveCut", "Background #rho for events with leading p_{T}^{jet,bkg sub} above cfgjetPtBkgSubMin; #rho (GeV/#it{c}/area); Entries", kTH1F, {{100, 0, 20}}); jetHist.add("jet/h1JetEta", "jet_{#eta}", kTH1F, {{100, -1.0, 1.0}}); jetHist.add("jet/h1JetPhi", "jet_{#phi}", kTH1F, {{80, -1.0, 7.}}); @@ -1807,7 +1808,7 @@ struct nucleiInJets { jetHist.fill(HIST("jetBkgSub/h1LeadingJetPtBkgSub"), leadingJetPtBkgSub); jetHist.fill(HIST("jetBkgSub/h2LeadingJetPtBkgSubVsVertexZ"), leadingJetPtBkgSub, collision.posZ()); } - if (leadingJetPtBkgSub > cfgjetPtBkgSubMin) { + if (backgroundRho > 0 && leadingJetPtBkgSub > cfgjetPtBkgSubMin) { jetHist.fill(HIST("jetBkgSub/vertexZ"), collision.posZ()); jetHist.fill(HIST("jetBkgSub/h1BkgRhoLeadingJetPtBkgSubAboveCut"), backgroundRho); jetHist.fill(HIST("hNEvents"), 8.5); @@ -1818,7 +1819,10 @@ struct nucleiInJets { return; jetHist.fill(HIST("jet/h1JetEvents"), 0.5); if (leadingJetPtBkgSub > cfgjetPtBkgSubMin) { - jetHist.fill(HIST("jetBkgSub/h1JetEvents"), 0.5); + jetHist.fill(HIST("jetBkgSub/h1JetEventsBeforeRhoSelection"), 0.5); + if (backgroundRho > 0) { + jetHist.fill(HIST("jetBkgSub/h1JetEvents"), 0.5); + } } for (const auto& track : tracks) { auto trk = track.track_as(); @@ -1909,7 +1913,7 @@ struct nucleiInJets { jetHist.fill(HIST("jetBkgSub/h1LeadingJetPtBkgSub"), leadingJetPtBkgSub); jetHist.fill(HIST("jetBkgSub/h2LeadingJetPtBkgSubVsVertexZ"), leadingJetPtBkgSub, collision.posZ()); } - if (leadingJetPtBkgSub > cfgjetPtBkgSubMin) { + if (backgroundRho > 0 && leadingJetPtBkgSub > cfgjetPtBkgSubMin) { jetHist.fill(HIST("jetBkgSub/vertexZ"), collision.posZ()); jetHist.fill(HIST("jetBkgSub/h1BkgRhoLeadingJetPtBkgSubAboveCut"), backgroundRho); jetHist.fill(HIST("hNEvents"), 8.5); @@ -1920,7 +1924,10 @@ struct nucleiInJets { return; jetHist.fill(HIST("jet/h1JetEvents"), 0.5); if (leadingJetPtBkgSub > cfgjetPtBkgSubMin) { - jetHist.fill(HIST("jetBkgSub/h1JetEvents"), 0.5); + jetHist.fill(HIST("jetBkgSub/h1JetEventsBeforeRhoSelection"), 0.5); + if (backgroundRho > 0) { + jetHist.fill(HIST("jetBkgSub/h1JetEvents"), 0.5); + } } for (auto& track : tracks) { auto trk = track.track_as(); @@ -2366,6 +2373,13 @@ struct nucleiInJets { if (!jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("sel8"))) return; + if (selNoSameBunchPileup && !jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("NoSameBunchPileup"))) + return; + if (selIsGoodZvtxFT0vsPV && !jetderiveddatautilities::selectCollision(collision, jetderiveddatautilities::initialiseEventSelectionBits("IsGoodZvtxFT0vsPV"))) + return; + if (useOccupancy && !isOccupancyAccepted(collision)) + return; + jetHist.fill(HIST("recmatched/vertexZ"), collision.posZ()); // Event-wise random splitting for closure test: decide once per event @@ -2376,6 +2390,22 @@ struct nucleiInJets { jetHist.fill(HIST("jet/h1BkgRho"), backgroundRho); } + // Select the accepted detector-level leading jet before considering matches. + int64_t leadingDetJetId = -1; + float leadingDetJetPt = -1.f; + if (isWithLeadingJet) { + for (const auto& mcdjet : mcdjets) { + if (isConeAxisAccepted(mcdjet.eta()) && mcdjet.pt() > leadingDetJetPt) { + leadingDetJetPt = mcdjet.pt(); + leadingDetJetId = mcdjet.globalIndex(); + } + } + if (leadingDetJetId < 0) { + return; + } + } + + std::vector mcdJetIds{}; std::vector mcdJetPt{}; std::vector mcdJetPhi{}; std::vector mcdJetEta{}; @@ -2396,7 +2426,7 @@ struct nucleiInJets { continue; const float mcdJetPtForResponse = usebkgSubractionMC ? mcdjet.pt() - backgroundRho * jetArea : mcdjet.pt(); - if (mcdJetPtForResponse < cfgjetPtBkgSubMinMC) { + if (mcdJetPtForResponse <= cfgjetPtBkgSubMinMC) { continue; } const double jetAxisEtaForEff = isWithLeadingJet ? (useLeadingJetDetLevelValue ? mcdjet.eta() : mcpjet.eta()) : mcdjet.eta(); @@ -2409,6 +2439,7 @@ struct nucleiInJets { jetHist.fill(HIST("recmatched/qa/h2JetConeEtaPhiAfterAcceptance"), jetAxisEtaForEff, jetAxisPhiForEff); jetHist.fill(HIST("recmatched/qa/h2PerpConeEtaPhiAfterAcceptance"), jetAxisEtaForEff, perpConePhiJet[0]); jetHist.fill(HIST("recmatched/qa/h2PerpConeEtaPhiAfterAcceptance"), jetAxisEtaForEff, perpConePhiJet[1]); + mcdJetIds.push_back(mcdjet.globalIndex()); mcdJetPt.push_back(mcdJetPtForResponse); mcdJetPhi.push_back(mcdjet.phi()); mcdJetEta.push_back(mcdjet.eta()); @@ -2436,6 +2467,13 @@ struct nucleiInJets { } else { LOGP(fatal, "Error: Index {} is out of range for vectors!", indexJet); } + if (isWithLeadingJet) { + const auto leadingMatch = std::find(mcdJetIds.begin(), mcdJetIds.end(), leadingDetJetId); + if (leadingMatch == mcdJetIds.end()) { + return; // Do not replace an unmatched or rejected leading jet with a subleading jet. + } + indexJet = std::distance(mcdJetIds.begin(), leadingMatch); + } if (useMcC) { if (useDataLikeHist) jetHist.fill(HIST("recmatched/h2ResponseMatrixLeadingJet"), mcdJetPt.at(indexJet), mcpJetPt.at(indexJet)); From cac60a357b5c3ec0fecf64501ae94e18b8121341 Mon Sep 17 00:00:00 2001 From: Arvind Khuntia Date: Fri, 25 Sep 2026 11:20:13 +0200 Subject: [PATCH 2/4] Use corrected jet pT for leading-jet selection --- PWGJE/Tasks/nucleiInJets.cxx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/PWGJE/Tasks/nucleiInJets.cxx b/PWGJE/Tasks/nucleiInJets.cxx index 80f7adf6ee3..eb2b2c12dd3 100644 --- a/PWGJE/Tasks/nucleiInJets.cxx +++ b/PWGJE/Tasks/nucleiInJets.cxx @@ -2472,6 +2472,9 @@ struct nucleiInJets { // Event-wise random splitting for closure test: decide once per event bool useDataLikeHist = (randUniform.Uniform(0, 1) < 0.5); const float backgroundRho = collision.rho(); + if (usebkgSubractionMC && backgroundRho <= 0.f) { + return; + } const float jetArea = M_PI * cfgjetR * cfgjetR; if (usebkgSubractionMC) { jetHist.fill(HIST("jet/h1BkgRho"), backgroundRho); @@ -2482,8 +2485,9 @@ struct nucleiInJets { float leadingDetJetPt = -1.f; if (isWithLeadingJet) { for (const auto& mcdjet : mcdjets) { - if (isConeAxisAccepted(mcdjet.eta()) && mcdjet.pt() > leadingDetJetPt) { - leadingDetJetPt = mcdjet.pt(); + const float mcdJetPtForResponseSel = usebkgSubractionMC ? mcdjet.pt() - backgroundRho * jetArea : mcdjet.pt(); + if (isConeAxisAccepted(mcdjet.eta()) && mcdJetPtForResponseSel > leadingDetJetPt) { + leadingDetJetPt = mcdJetPtForResponseSel; leadingDetJetId = mcdjet.globalIndex(); } } From 335d658b582567afba249367687db6442c2eb9eb Mon Sep 17 00:00:00 2001 From: Arvind Khuntia Date: Tue, 29 Sep 2026 19:31:47 +0200 Subject: [PATCH 3/4] [PWGJE] Use int32_t for jet-ID --- PWGJE/Tasks/nucleiInJets.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PWGJE/Tasks/nucleiInJets.cxx b/PWGJE/Tasks/nucleiInJets.cxx index eb2b2c12dd3..db7acbd9061 100644 --- a/PWGJE/Tasks/nucleiInJets.cxx +++ b/PWGJE/Tasks/nucleiInJets.cxx @@ -2481,7 +2481,7 @@ struct nucleiInJets { } // Select the accepted detector-level leading jet before considering matches. - int64_t leadingDetJetId = -1; + int32_t leadingDetJetId = -1; float leadingDetJetPt = -1.f; if (isWithLeadingJet) { for (const auto& mcdjet : mcdjets) { @@ -2496,7 +2496,7 @@ struct nucleiInJets { } } - std::vector mcdJetIds{}; + std::vector mcdJetIds{}; std::vector mcdJetPt{}; std::vector mcdJetPhi{}; std::vector mcdJetEta{}; From bb6032f7e70e4989c270d691899ada611f0ac711 Mon Sep 17 00:00:00 2001 From: Arvind Khuntia Date: Thu, 1 Oct 2026 12:07:00 +0200 Subject: [PATCH 4/4] [PWGJE] Update leading-jet selection corrections to include unmatched jets and normalize per selected reconstructed collision --- PWGJE/Tasks/nucleiInJets.cxx | 133 ++++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 50 deletions(-) diff --git a/PWGJE/Tasks/nucleiInJets.cxx b/PWGJE/Tasks/nucleiInJets.cxx index db7acbd9061..156020d18b3 100644 --- a/PWGJE/Tasks/nucleiInJets.cxx +++ b/PWGJE/Tasks/nucleiInJets.cxx @@ -258,6 +258,8 @@ struct nucleiInJets { using JetMCPartTable = soa::Filtered>; using JetMCDetTable = soa::Filtered>; + Preslice> detectorJetsPerCollision = aod::jet::collisionId; + SliceCache cache; HistogramRegistry jetHist{"jetHist", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -817,15 +819,23 @@ struct nucleiInJets { jetHist.add("eff/recmatched/mcCSpectra/gen/perpCone/pt/PtParticleType", "Pt (gen, mcCSpectra, perp cone) vs particletype", HistType::kTH2D, {{PtAxis}, {14, -7, 7}}); jetHist.add("jetSelCorr/genSel/hLeadingJetPt", "particle-level leading jet selected for jet-selection correction; #it{p}_{T,lead}^{gen} (GeV/#it{c}); Entries", HistType::kTH1F, {{100, 0., 100.}}); - jetHist.add("jetSelCorr/recoSel/hLeadingJetPtBkgSub", "matched detector-level leading jet selected for jet-selection correction; #it{p}_{T,lead}^{reco,corr} (GeV/#it{c}); Entries", HistType::kTH1F, {{120, -20., 100.}}); + jetHist.add("jetSelCorr/recoSel/hLeadingJetPtBkgSub", "detector-level leading jet selected for jet-selection correction; #it{p}_{T,lead}^{reco,corr} (GeV/#it{c}); Entries", HistType::kTH1F, {{120, -20., 100.}}); jetHist.add("jetSelCorr/recoSel/hMatchedLeadingJetPt", "selected matched leading jet; #it{p}_{T,lead}^{reco,corr} (GeV/#it{c}); #it{p}_{T,lead}^{gen} (GeV/#it{c})", HistType::kTH2F, {{120, -20., 100.}, {100, 0., 100.}}); jetHist.add("jetSelCorr/eventNorm/hEventCounts", "event count for leading-jet event-normalization correction; event selection; Entries", HistType::kTH1D, {{2, 0., 2.}}); jetHist.get(HIST("jetSelCorr/eventNorm/hEventCounts"))->GetXaxis()->SetBinLabel(1, "gen lead #it{p}_{T} > cut"); jetHist.get(HIST("jetSelCorr/eventNorm/hEventCounts"))->GetXaxis()->SetBinLabel(2, "reco lead #it{p}_{T}^{corr} > cut"); + jetHist.add("jetSelCorr/recoSel/hMatchStatus", "selected detector leading-jet matching; status; reconstructed collisions", HistType::kTH1D, {{3, 0., 3.}}); + jetHist.get(HIST("jetSelCorr/recoSel/hMatchStatus"))->GetXaxis()->SetBinLabel(1, "no truth match in MC collision"); + jetHist.get(HIST("jetSelCorr/recoSel/hMatchStatus"))->GetXaxis()->SetBinLabel(2, "truth axis outside acceptance"); + jetHist.get(HIST("jetSelCorr/recoSel/hMatchStatus"))->GetXaxis()->SetBinLabel(3, "accepted truth axis"); + jetHist.add("jetSelCorr/eventNorm/hSelectedRecoCollisions", "selected reconstructed collisions per MC collision; selected reconstructed collisions; MC collisions", HistType::kTH1D, {{11, -0.5, 10.5}}); + jetHist.add("jetSelCorr/matchedTruthAxis/hEventCount", "selected reconstructed collisions with accepted matched truth axis; selection; reconstructed collisions", HistType::kTH1D, {{1, 0., 1.}}); + jetHist.add("jetSelCorr/matchedTruthAxis/jetCone/pt/PtParticleType", "generated primaries around the matched truth axis; #it{p}_{T}^{gen} (GeV/#it{c}); particle type", HistType::kTH2D, {{PtAxis}, {14, -7, 7}}); + jetHist.add("jetSelCorr/matchedTruthAxis/perpCone/pt/PtParticleType", "generated primaries in perpendicular cones of the matched truth jet; #it{p}_{T}^{gen} (GeV/#it{c}); particle type", HistType::kTH2D, {{PtAxis}, {14, -7, 7}}); jetHist.add("jetSelCorr/genSel/jetCone/pt/PtParticleType", "generated primaries in particle-level leading-jet cone; #it{p}_{T}^{gen} (GeV/#it{c}); particle type", HistType::kTH2D, {{PtAxis}, {14, -7, 7}}); jetHist.add("jetSelCorr/genSel/perpCone/pt/PtParticleType", "generated primaries in particle-level perpendicular cone; #it{p}_{T}^{gen} (GeV/#it{c}); particle type", HistType::kTH2D, {{PtAxis}, {14, -7, 7}}); - jetHist.add("jetSelCorr/recoSel/jetCone/pt/PtParticleType", "generated primaries in matched reco-selected leading-jet cone; #it{p}_{T}^{gen} (GeV/#it{c}); particle type", HistType::kTH2D, {{PtAxis}, {14, -7, 7}}); - jetHist.add("jetSelCorr/recoSel/perpCone/pt/PtParticleType", "generated primaries in matched reco-selected perpendicular cone; #it{p}_{T}^{gen} (GeV/#it{c}); particle type", HistType::kTH2D, {{PtAxis}, {14, -7, 7}}); + jetHist.add("jetSelCorr/recoSel/jetCone/pt/PtParticleType", "generated primaries around the selected detector leading-jet axis; #it{p}_{T}^{gen} (GeV/#it{c}); particle type", HistType::kTH2D, {{PtAxis}, {14, -7, 7}}); + jetHist.add("jetSelCorr/recoSel/perpCone/pt/PtParticleType", "generated primaries in perpendicular cones of the selected detector leading jet; #it{p}_{T}^{gen} (GeV/#it{c}); particle type", HistType::kTH2D, {{PtAxis}, {14, -7, 7}}); jetHist.add("feeddown/antiProton/jetCone/PtOrigin", "reconstructed #bar{p} origin in jet cone; #it{p}_{T}^{rec} (GeV/#it{c}); origin", HistType::kTH2D, {{PtAxis}, {ParticleOriginAxis}}); jetHist.add("feeddown/antiProton/jetCone/PtOriginTPC", "reconstructed #bar{p} origin in jet cone, TPC PID; #it{p}_{T}^{rec} (GeV/#it{c}); origin", HistType::kTH2D, {{PtAxis}, {ParticleOriginAxis}}); @@ -2406,7 +2416,7 @@ struct nucleiInJets { return true; } - template + template void fillJetSelectionCorrectionParticles(const ParticlesType& mcParticles, double jetEta, double jetPhi) { const auto perpConePhiJet = getPerpendicuarPhi(jetPhi); @@ -2430,7 +2440,9 @@ struct nucleiInJets { const double delPhi = TVector2::Phi_mpi_pi(jetPhi - mcParticle.phi()); const double rJet = RecoDecay::sqrtSumOfSquares(delEta, delPhi); if (rJet < cfgjetR) { - if constexpr (RecoSelected) { + if constexpr (MatchedTruthAxis) { + jetHist.fill(HIST("jetSelCorr/matchedTruthAxis/jetCone/pt/PtParticleType"), mcParticle.pt(), particleType); + } else if constexpr (RecoSelected) { jetHist.fill(HIST("jetSelCorr/recoSel/jetCone/pt/PtParticleType"), mcParticle.pt(), particleType); } else { jetHist.fill(HIST("jetSelCorr/genSel/jetCone/pt/PtParticleType"), mcParticle.pt(), particleType); @@ -2442,7 +2454,9 @@ struct nucleiInJets { const double rPerpCone1 = RecoDecay::sqrtSumOfSquares(delEta, delPhiPerpCone1); const double rPerpCone2 = RecoDecay::sqrtSumOfSquares(delEta, delPhiPerpCone2); if (rPerpCone1 < cfgjetR || rPerpCone2 < cfgjetR) { - if constexpr (RecoSelected) { + if constexpr (MatchedTruthAxis) { + jetHist.fill(HIST("jetSelCorr/matchedTruthAxis/perpCone/pt/PtParticleType"), mcParticle.pt(), particleType); + } else if constexpr (RecoSelected) { jetHist.fill(HIST("jetSelCorr/recoSel/perpCone/pt/PtParticleType"), mcParticle.pt(), particleType); } else { jetHist.fill(HIST("jetSelCorr/genSel/perpCone/pt/PtParticleType"), mcParticle.pt(), particleType); @@ -2818,7 +2832,7 @@ struct nucleiInJets { int nprocessSimJEEvents = 0; void processJetSelectionCorrection(aod::JetMcCollision const& collision, soa::SmallGroups> const& recocolls, - JetMCDetTable const&, JetMCPartTable const& mcpjets, aod::JetParticles const& mcParticles) + JetMCDetTable const& mcdjets, JetMCPartTable const& mcpjets, aod::JetParticles const& mcParticles) { if (std::abs(collision.posZ()) > cfgMaxZVertex) { return; @@ -2847,61 +2861,80 @@ struct nucleiInJets { fillJetSelectionCorrectionParticles(mcParticles, genLeadingJetEta, genLeadingJetPhi); } - bool hasRecoSelectedLeadingJet = false; - double recoSelectedLeadingJetPt = -999.; - double recoSelectedMatchedGenJetPt = -999.; - double recoSelectedMatchedGenJetEta = -999.; - double recoSelectedMatchedGenJetPhi = -999.; - - for (const auto& mcpjet : mcpjets) { - if (!mcpjet.has_matchedJetGeo()) { + // Count each reconstructed collision, as in data. The generated selection + // above is independent: neither branch requires the other to pass the cut. + int nSelectedRecoCollisions = 0; + const double jetArea = M_PI * cfgjetR * cfgjetR; + for (const auto& recocoll : recocolls) { + if (!isRecoCollisionSelectedForJetSelectionCorrection(recocoll)) { continue; } - if (!isConeAxisAccepted(mcpjet.eta())) { + if (usebkgSubractionMC && !(recocoll.rho() > 0.)) { continue; } - for (const auto& mcdjet : mcpjet.template matchedJetGeo_as()) { - if (!isConeAxisAccepted(mcdjet.eta())) { - continue; - } - double selectedRecoCollisionRho = -1.; - bool hasSelectedRecoCollision = false; - for (const auto& recocoll : recocolls) { - if (mcdjet.collisionId() != recocoll.globalIndex()) { - continue; - } - if (!isRecoCollisionSelectedForJetSelectionCorrection(recocoll)) { - continue; - } - selectedRecoCollisionRho = recocoll.rho(); - hasSelectedRecoCollision = true; - break; - } - if (!hasSelectedRecoCollision) { - continue; - } - const double jetArea = M_PI * cfgjetR * cfgjetR; - const double mcdJetPtBkgSub = usebkgSubractionMC ? mcdjet.pt() - selectedRecoCollisionRho * jetArea : mcdjet.pt(); - if (mcdJetPtBkgSub <= cfgjetPtBkgSubMinMC) { + const auto jetsInCollision = mcdjets.sliceBy(detectorJetsPerCollision, recocoll.globalIndex()); + auto leadingJet = jetsInCollision.begin(); + bool hasLeadingJet = false; + double leadingJetPt = cfgjetPtBkgSubMinMC; + for (auto jet = jetsInCollision.begin(); jet != jetsInCollision.end(); ++jet) { + if (!isConeAxisAccepted(jet.eta())) { continue; } - if (mcdJetPtBkgSub > recoSelectedLeadingJetPt) { - hasRecoSelectedLeadingJet = true; - recoSelectedLeadingJetPt = mcdJetPtBkgSub; - recoSelectedMatchedGenJetPt = mcpjet.pt(); - recoSelectedMatchedGenJetEta = mcpjet.eta(); - recoSelectedMatchedGenJetPhi = mcpjet.phi(); + const double correctedPt = usebkgSubractionMC ? jet.pt() - recocoll.rho() * jetArea : jet.pt(); + if (correctedPt > leadingJetPt) { + leadingJet = jet; + leadingJetPt = correctedPt; + hasLeadingJet = true; } } - } + if (!hasLeadingJet) { + continue; + } - if (hasRecoSelectedLeadingJet) { + ++nSelectedRecoCollisions; jetHist.fill(HIST("jetSelCorr/eventNorm/hEventCounts"), 1.5); - jetHist.fill(HIST("jetSelCorr/recoSel/hLeadingJetPtBkgSub"), recoSelectedLeadingJetPt); - jetHist.fill(HIST("jetSelCorr/recoSel/hMatchedLeadingJetPt"), recoSelectedLeadingJetPt, recoSelectedMatchedGenJetPt); - fillJetSelectionCorrectionParticles(mcParticles, recoSelectedMatchedGenJetEta, recoSelectedMatchedGenJetPhi); + jetHist.fill(HIST("jetSelCorr/recoSel/hLeadingJetPtBkgSub"), leadingJetPt); + // All selected detector jets, including unmatched jets, use detector axes + // Never substitute a matched subleading jet or mix truth and detector axes + fillJetSelectionCorrectionParticles(mcParticles, leadingJet.eta(), leadingJet.phi()); + + // Preserve a separate matched-truth-axis sample for efficiency comparisons + // Resolve multiple geometrical matches by the smallest angular distance + bool hasTruthMatch = false; + double closestDistance = 1.e9; + double truthPt = 0.; + double truthEta = 0.; + double truthPhi = 0.; + if (leadingJet.has_matchedJetGeo()) { + for (const auto& truthJet : leadingJet.template matchedJetGeo_as()) { + if (truthJet.mcCollisionId() != collision.globalIndex()) { + continue; + } + const double distance = RecoDecay::sqrtSumOfSquares(leadingJet.eta() - truthJet.eta(), TVector2::Phi_mpi_pi(leadingJet.phi() - truthJet.phi())); + if (distance < closestDistance) { + closestDistance = distance; + hasTruthMatch = true; + truthPt = truthJet.pt(); + truthEta = truthJet.eta(); + truthPhi = truthJet.phi(); + } + } + } + if (!hasTruthMatch) { + jetHist.fill(HIST("jetSelCorr/recoSel/hMatchStatus"), 0.5); + continue; + } + jetHist.fill(HIST("jetSelCorr/recoSel/hMatchedLeadingJetPt"), leadingJetPt, truthPt); + if (!isConeAxisAccepted(truthEta)) { + jetHist.fill(HIST("jetSelCorr/recoSel/hMatchStatus"), 1.5); + continue; + } + jetHist.fill(HIST("jetSelCorr/recoSel/hMatchStatus"), 2.5); + jetHist.fill(HIST("jetSelCorr/matchedTruthAxis/hEventCount"), 0.5); + fillJetSelectionCorrectionParticles(mcParticles, truthEta, truthPhi); } + jetHist.fill(HIST("jetSelCorr/eventNorm/hSelectedRecoCollisions"), nSelectedRecoCollisions); } void processGenMatched(aod::JetMcCollision const& collision,