diff --git a/PWGHF/HFC/DataModel/CorrelationTables.h b/PWGHF/HFC/DataModel/CorrelationTables.h index 83470e9f26c..c366a3e4186 100644 --- a/PWGHF/HFC/DataModel/CorrelationTables.h +++ b/PWGHF/HFC/DataModel/CorrelationTables.h @@ -51,6 +51,57 @@ DECLARE_SOA_TABLE(DDbarRecoInfo, "AOD", "DDBARRECOINFO", aod::hf_correlation_d_dbar::MDbar, aod::hf_correlation_d_dbar::SignalStatus); +// Table to store event by event D meson selection information for event mixing in D-hadron correlation analysis +namespace hf_d0_meson +{ +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(PtD, ptD, float); +DECLARE_SOA_COLUMN(MD, mD, float); +DECLARE_SOA_COLUMN(PoolBin, poolBin, int); +DECLARE_SOA_COLUMN(GIndexCol, gIndexCol, int); +DECLARE_SOA_COLUMN(TimeStamp, timeStamp, int64_t); +DECLARE_SOA_COLUMN(SignalStatus, signalStatus, int); +} // namespace hf_d0_meson + +DECLARE_SOA_TABLE(D0, "AOD", "D0", + aod::hf_d0_meson::Phi, + aod::hf_d0_meson::Eta, + aod::hf_d0_meson::PtD, + aod::hf_d0_meson::MD, + aod::hf_d0_meson::PoolBin, + aod::hf_d0_meson::GIndexCol, + aod::hf_d0_meson::TimeStamp, + aod::hf_d0_meson::SignalStatus); + +// Table to store event-by-event associated tracks for offline D0-hadron event mixing +namespace hf_d0_assoc_tracks +{ +DECLARE_SOA_COLUMN(Phi, phi, float); //! Phi of hadron +DECLARE_SOA_COLUMN(Eta, eta, float); //! Eta of hadron +DECLARE_SOA_COLUMN(PtH, ptH, float); //! Transverse momentum of hadron +DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Pool Bin of event defined using zvtx and multiplicity +DECLARE_SOA_COLUMN(GIndexCol, gIndexCol, int); //! Global index for the collision +DECLARE_SOA_COLUMN(TimeStamp, timeStamp, int64_t); //! Timestamp for the collision +DECLARE_SOA_COLUMN(SoftPiStatus, softPiStatus, int); //! Soft-pion status for D0 offline mixing + +enum SoftPionStatus { + NotSoftPi = 0, + SoftPiD0 = 1, + SoftPiD0bar = 2, + SoftPiD0D0bar = 3 +}; +} // namespace hf_d0_assoc_tracks + +DECLARE_SOA_TABLE(D0Hadron, "AOD", "D0HADRON", + aod::hf_d0_assoc_tracks::Phi, + aod::hf_d0_assoc_tracks::Eta, + aod::hf_d0_assoc_tracks::PtH, + aod::hf_d0_assoc_tracks::PoolBin, + aod::hf_d0_assoc_tracks::GIndexCol, + aod::hf_d0_assoc_tracks::TimeStamp, + aod::hf_d0_assoc_tracks::SoftPiStatus); + // definition of columns and tables for D0-Hadron correlation pairs namespace hf_correlation_d0_hadron { diff --git a/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx b/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx index 85ec82b5ed9..23161549f4f 100644 --- a/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx @@ -214,6 +214,8 @@ struct HfCorrelatorD0Hadrons { Produces entryD0CandRecoInfo; Produces entryD0CandGenInfo; Produces entryTrackRecoInfo; + Produces entryD0; + Produces entryD0Hadron; Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; @@ -283,9 +285,9 @@ struct HfCorrelatorD0Hadrons { AxisSpec const axisSignalStatus = {200, 0., 200., "Signal status"}; AxisSpec axisEvtCount = {1, -0.5, 0.5}; AxisSpec const axisTrkCount = {5, 0., 5.}; - AxisSpec axisBdtScoreBkg = {100, 0., 1., "Bdt score background"}; - AxisSpec axisBdtScorePrompt = {100, 0., 1., "Bdt score prompt"}; - AxisSpec axisBdtScoreNonPrompt = {100, 0., 1., "Bdt score Nonprompt"}; + AxisSpec axisBdtScoreBkg = {500, 0., 1., "Bdt score background"}; + AxisSpec axisBdtScorePrompt = {200, 0., 1., "Bdt score prompt"}; + AxisSpec axisBdtScoreNonPrompt = {200, 0., 1., "Bdt score Nonprompt"}; AxisSpec axisOrigin = {10, 0., 10., "Candidate origin"}; AxisSpec axisCent = {binsCentFt0m, "Centrality"}; @@ -306,6 +308,9 @@ struct HfCorrelatorD0Hadrons { registry.add("hMassD0bar1D", "D0bar candidates mass", {HistType::kTH1F, {axisMassD}}); registry.add("hMassD0VsPtVsCent", "D0 candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH3F, {{axisMassD}, {axisPtD}, {axisCent}}}); registry.add("hMLScoresVsMassVsPtVsEtaVsOriginVsCent", "D0, D0bar candidates BkgVspromptVsNonPromptVsMassVsPtVsEtaVsOrigin", {HistType::kTHnSparseD, {{axisBdtScoreBkg}, {axisBdtScorePrompt}, {axisBdtScoreNonPrompt}, {axisMassD}, {axisPtD}, {axisEta}, {axisOrigin}, {axisCent}}}); + registry.add("hTracksBeforeSoftMix", "Tracks before soft pion reject offline mixing", {HistType::kTH1F, {axisPtHadron}}); + registry.add("hTracksAfterSoftMix", "Tracks after soft pion reject offline mixing", {HistType::kTH1F, {axisPtHadron}}); + // Histograms for MC Reco registry.add("hPtCandRec", "D0, D0bar candidates - MC reco", {HistType::kTH1F, {axisPtD}}); registry.add("hPtProng0Rec", "D0, D0bar candidates prong 0 - MC reco", {HistType::kTH1F, {axisPtD}}); @@ -359,9 +364,15 @@ struct HfCorrelatorD0Hadrons { /// D0-h correlation pair builder - for real data and data-like analysis (i.e. reco-level w/o matching request via MC truth) void processData(SelectedCollisions::iterator const& collision, SelectedTracks const& tracks, - SelectedCandidatesDataMl const& candidates) + SelectedCandidatesDataMl const& candidates, + aod::BCsWithTimestamps const&) { BinningType const corrBinning{{zPoolBins, multPoolBins}, true}; + + auto bc = collision.bc_as(); + int gCollisionId = collision.globalIndex(); + int64_t timeStamp = bc.timestamp(); + // find leading particle if (correlateD0WithLeadingParticle) { leadingIndex = findLeadingParticle(tracks, etaTrackMax.value); @@ -397,6 +408,30 @@ struct HfCorrelatorD0Hadrons { std::vector outputMlD0 = {-1., -1., -1.}; std::vector outputMlD0bar = {-1., -1., -1.}; + std::vector softPionTrackIdsForOfflineMixing; + std::vector softPionStatusesForOfflineMixing; + bool hasAcceptedD0ForOfflineMixing = false; + + auto addSoftPionTrackForOfflineMixing = [&softPionTrackIdsForOfflineMixing, &softPionStatusesForOfflineMixing](int64_t trackId, int softPiStatus) { + for (auto iTrack = 0u; iTrack < softPionTrackIdsForOfflineMixing.size(); ++iTrack) { + if (softPionTrackIdsForOfflineMixing[iTrack] == trackId) { + softPionStatusesForOfflineMixing[iTrack] |= softPiStatus; + return; + } + } + softPionTrackIdsForOfflineMixing.push_back(trackId); + softPionStatusesForOfflineMixing.push_back(softPiStatus); + }; + + auto getSoftPionStatusForOfflineMixing = [&softPionTrackIdsForOfflineMixing, &softPionStatusesForOfflineMixing](int64_t trackId) { + for (auto iTrack = 0u; iTrack < softPionTrackIdsForOfflineMixing.size(); ++iTrack) { + if (softPionTrackIdsForOfflineMixing[iTrack] == trackId) { + return softPionStatusesForOfflineMixing[iTrack]; + } + } + return static_cast(aod::hf_d0_assoc_tracks::NotSoftPi); + }; + for (const auto& candidate : candidates) { if (std::abs(HfHelper::yD0(candidate)) >= yCandMax || candidate.pt() <= ptCandMin || candidate.pt() >= ptTrackMax) { continue; @@ -420,6 +455,10 @@ struct HfCorrelatorD0Hadrons { const auto invMassD0 = HfHelper::invMassD0ToPiK(candidate); const auto invMassD0bar = HfHelper::invMassD0barToKPi(candidate); + if (candidate.isSelD0() >= selectionFlagD0 || candidate.isSelD0bar() >= selectionFlagD0bar) { + hasAcceptedD0ForOfflineMixing = true; + } + // ========================== Fill mass histo ================================ if (candidate.isSelD0() >= selectionFlagD0) { registry.fill(HIST("hMass"), invMassD0, candidate.pt(), efficiencyWeight); @@ -430,6 +469,7 @@ struct HfCorrelatorD0Hadrons { outputMlD0[iclass] = candidate.mlProbD0()[classMl->at(iclass)]; } registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOriginVsCent"), outputMlD0[0], outputMlD0[1], outputMlD0[2], invMassD0, candidate.pt(), candidate.eta(), (candidate.isSelD0bar() != 0) ? o2::aod::hf_correlation_d0_hadron::D0D0barBoth : o2::aod::hf_correlation_d0_hadron::D0Only, cent, efficiencyWeight); + entryD0(candidate.phi(), candidate.eta(), candidate.pt(), invMassD0, poolBin, gCollisionId, timeStamp, (candidate.isSelD0bar() != 0) ? o2::aod::hf_correlation_d0_hadron::D0D0barBoth : o2::aod::hf_correlation_d0_hadron::D0Only); } if (candidate.isSelD0bar() >= selectionFlagD0bar) { registry.fill(HIST("hMass"), invMassD0bar, candidate.pt(), efficiencyWeight); @@ -440,6 +480,7 @@ struct HfCorrelatorD0Hadrons { outputMlD0bar[iclass] = candidate.mlProbD0bar()[classMl->at(iclass)]; } registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOriginVsCent"), outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2], invMassD0bar, candidate.pt(), candidate.eta(), (candidate.isSelD0() != 0) ? o2::aod::hf_correlation_d0_hadron::D0D0barBoth : o2::aod::hf_correlation_d0_hadron::D0barOnly, cent, efficiencyWeight); + entryD0(candidate.phi(), candidate.eta(), candidate.pt(), invMassD0bar, poolBin, gCollisionId, timeStamp, (candidate.isSelD0() != 0) ? o2::aod::hf_correlation_d0_hadron::D0D0barBoth : o2::aod::hf_correlation_d0_hadron::D0barOnly); } entryD0CandRecoInfo(invMassD0, invMassD0bar, candidate.pt(), outputMlD0[0], outputMlD0[2], outputMlD0bar[0], outputMlD0bar[2]); @@ -477,12 +518,14 @@ struct HfCorrelatorD0Hadrons { if (candidate.isSelD0() >= selectionFlagD0) { if ((std::abs(invMassDstar1 - invMassD0) - softPiMass) < ptSoftPionMax) { + addSoftPionTrackForOfflineMixing(track.globalIndex(), aod::hf_d0_assoc_tracks::SoftPiD0); continue; } } if (candidate.isSelD0bar() >= selectionFlagD0bar) { if ((std::abs(invMassDstar2 - invMassD0bar) - softPiMass) < ptSoftPionMax) { + addSoftPionTrackForOfflineMixing(track.globalIndex(), aod::hf_d0_assoc_tracks::SoftPiD0bar); continue; } } @@ -518,6 +561,20 @@ struct HfCorrelatorD0Hadrons { } // end inner loop (tracks) } // end outer loop + + // loop to save tables for offline event mixing + if (hasAcceptedD0ForOfflineMixing) { + for (const auto& track : tracks) { + const auto softPiStatus = getSoftPionStatusForOfflineMixing(track.globalIndex()); + + registry.fill(HIST("hTracksBeforeSoftMix"), track.pt()); + if (softPiStatus == aod::hf_d0_assoc_tracks::NotSoftPi) { + registry.fill(HIST("hTracksAfterSoftMix"), track.pt()); + } + + entryD0Hadron(track.phi(), track.eta(), track.pt(), poolBin, gCollisionId, timeStamp, softPiStatus); + } + } } PROCESS_SWITCH(HfCorrelatorD0Hadrons, processData, "Process data", false);