diff --git a/PWGLF/Tasks/Resonances/CMakeLists.txt b/PWGLF/Tasks/Resonances/CMakeLists.txt index a77be78b62b..6462ddc715d 100644 --- a/PWGLF/Tasks/Resonances/CMakeLists.txt +++ b/PWGLF/Tasks/Resonances/CMakeLists.txt @@ -228,3 +228,8 @@ o2physics_add_dpl_workflow(kstar-in-oo SOURCES kstarInOO.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + + o2physics_add_dpl_workflow(phioo + SOURCES phiOO.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/PWGLF/Tasks/Resonances/phiOO.cxx b/PWGLF/Tasks/Resonances/phiOO.cxx new file mode 100644 index 00000000000..7e85c7a400f --- /dev/null +++ b/PWGLF/Tasks/Resonances/phiOO.cxx @@ -0,0 +1,670 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file phiInJets.cxx +/// \brief Reconstruction of Phi yield through track-track Minv correlations for resonance OO analysis +/// +/// +/// \author Adrian Fereydon Nassirpour +#include +#include +#include +#include +#include + +#include "TRandom.h" +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct phiOO { + + SliceCache cache; + Preslice perCollision = aod::track::collisionId; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Event configurables + Configurable cfg_Event_Sel{"cfg_Event_Sel", "sel8", "choose event selection"}; + Configurable cfg_Event_VtxCut{"cfg_Event_VtxCut", 10.0, "V_z cut selection"}; + Configurable cfg_Event_Timeframe{"cfg_Event_Timeframe", true, "Timeframe border cut"}; + Configurable cfg_Event_Timerange{"cfg_Event_Timerange", true, "Timerange border cut"}; + Configurable cfg_Event_Centrality{"cfg_Event_Centrality", true, "Centrality cut"}; + Configurable cfg_Event_CentralityMax{"cfg_Event_CentralityMax", 100, "CentralityMax cut"}; + Configurable cfg_Event_Pileup{"cfg_Event_Pileup", true, "Pileup border cut"}; + Configurable cfg_Event_OccupancyCut{"cfg_Event_OccupancyCut", true, "Occupancy border cut"}; + Configurable cfg_Event_MaxOccupancy{"cfg_Event_MaxOccupancy", 1, "Max TPC Occupancy"}; + + ConfigurableAxis cfg_bins_Cent{"cfg_bins_Cent", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0}, "Binning of the centrality axis"}; + ConfigurableAxis cfg_bins_MixVtx{"cfg_bins_MixVtx", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis cfg_bins_MixMult{"cfg_bins_MixMult", {VARIABLE_WIDTH, 0.0f, 1.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f}, "Mixing bins - z-vertex"}; + + // Track configurables + Configurable cfg_Track_Sel{"cfg_Track_Sel", "globalTracks", "set track selections"}; + Configurable cfg_Track_MinPt{"cfg_Track_MinPt", 0.15, "set track min pT"}; + Configurable cfg_Track_MaxEta{"cfg_Track_MaxEta", 0.9, "set track max Eta"}; + Configurable cfg_Track_MaxDCArToPVcut{"cfg_Track_MaxDCArToPVcut", 0.5, "Track DCAr cut to PV Maximum"}; + Configurable cfg_Track_MaxDCAzToPVcut{"cfg_Track_MaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; + Configurable cfg_Track_PrimaryTrack{"cfg_Track_PrimaryTrack", true, "Primary track selection"}; // kGoldenChi2 | kDCAxy | kDCAz + Configurable cfg_Track_ConnectedToPV{"cfg_Track_ConnectedToPV", true, "PV contributor track selection"}; // PV Contributor + Configurable cfg_Track_GlobalWoDCATrack{"cfg_Track_GlobalWoDCATrack", true, "Global track selection without DCA"}; // kQualityTracks (kTrackType | kTPCNCls | kTPCCrossedRows | kTPCCrossedRowsOverNCls | kTPCChi2NDF | kTPCRefit | kITSNCls | kITSChi2NDF | kITSRefit | kITSHits) | kInAcceptanceTracks (kPtRange | kEtaRange) + Configurable cfg_Track_nFindableTPCClusters{"cfg_Track_FindableTPCClusters", 50, "nFindable TPC Clusters"}; + Configurable cfg_Track_nTPCCrossedRows{"cfg_Track_TPCCrossedRows", 70, "nCrossed TPC Rows"}; + Configurable cfg_Track_nRowsOverFindable{"cfg_Track_RowsOverFindable", 1.2, "nRowsOverFindable TPC CLusters"}; + Configurable cfg_Track_nTPCChi2{"cfg_Track_TPCChi2", 4.0, "nTPC Chi2 per Cluster"}; + Configurable cfg_Track_nITSChi2{"cfg_Track_ITSChi2", 36.0, "nITS Chi2 per Cluster"}; + Configurable cfg_Track_TPCPID{"cfg_Track_TPCPID", true, "Enables TPC PID"}; + Configurable cfg_Track_TOFPID{"cfg_Track_TOFPID", true, "Enables TOF PID"}; + Configurable cfg_Track_Hard_TOFPID{"cfg_Track_Hard_TOFPID", true, "Enables STRICT TOF Reqruirement"}; + Configurable cfg_Track_TPCPID_nSig{"cfg_Track_TPCPID_nSig", 4, "nTPC PID sigma"}; + Configurable cfg_Track_TOFPID_nSig{"cfg_Track_TOFPID_nSig", 4, "nTOF PID sigma"}; + Configurable cfg_Track_Explicit_PID{"cfg_Track_Explicit_PID", true, "Enables explicit pid cehck"}; + Configurable cDebugLevel{"cDebugLevel", 0, "Resolution of Debug"}; + + // Pair configurables + Configurable cfg_Pair_MinvBins{"cfg_Pair_MinvBins", 300, "Number of bins for Minv axis"}; + Configurable cfg_Pair_MinvMin{"cfg_Pair_MinvMin", 0.90, "Minimum Minv value"}; + Configurable cfg_Pair_MinvMax{"cfg_Pair_MinvMax", 1.50, "Maximum Minv value"}; + + Configurable cfg_Mix_NMixedEvents{"cfg_Mix_NMixedEvents", 5, "Number of mixed events per event"}; + + // MCGen configurables + Configurable cfg_Force_GenReco{"cfg_Force_GenReco", false, "Only consider events which are reconstructed (neglect event-loss)"}; + Configurable cfg_Force_BR{"cfg_Force_BR", false, "Only consider phi->K+K-"}; + Configurable cfg_Force_Kaon_Acceptence{"cfg_Force_Kaon_Acceptence", false, "Only consider phi's whose daughters decay inside acceptence (no signal loss)"}; + + // Histogram Configurables + Configurable cfg_Event_CutQA{"cfg_Event_CutsQA", true, "Enables Track QA plots"}; + Configurable cfg_Track_CutQA{"cfg_Track_CutsQA", true, "Enables Track QA plots"}; + + void init(o2::framework::InitContext&) + { + const AxisSpec MinvAxis = {cfg_Pair_MinvBins, cfg_Pair_MinvMin, cfg_Pair_MinvMax}; + const AxisSpec PtAxis = {200, 0, 20.0}; + const AxisSpec MultAxis = {100, 0, 100}; + const AxisSpec dRAxis = {100, 0, 100}; + const AxisSpec pidAxis = {100, -5, 5}; + + // Event QA + if (cfg_Event_CutQA) { + histos.add("hPosZ_BC", "PosZ_BC", kTH1F, {{100, 0.0, 15.0}}); + histos.add("hcentFT0C_BC", "centFT0C_BC", kTH1F, {{100, 0.0, 100.0}}); + histos.add("hOccupancy_BC", "Occupancy_BC", kTH1F, {{100, 0.0, 20000}}); + // + histos.add("hcentFT0C_AC", "centFT0C_AC", kTH1F, {{100, 0.0, 100.0}}); + histos.add("hPosZ_AC", "PosZ_AC", kTH1F, {{100, 0.0, 15.0}}); + histos.add("hOccupancy_AC", "Occupancy_AC", kTH1F, {{100, 0.0, 20000}}); + } + // Track QA + if (cfg_Track_CutQA) { + histos.add("hDCArToPv_BC", "DCArToPv_BC", kTH1F, {{300, 0.0, 3.0}}); + histos.add("hDCAzToPv_BC", "DCAzToPv_BC", kTH1F, {{300, 0.0, 3.0}}); + histos.add("hIsPrim_BC", "hIsPrim_BC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsGood_BC", "hIsGood_BC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsPrimCont_BC", "hIsPrimCont_BC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hFindableTPCClusters_BC", "hFindableTPCClusters_BC", kTH1F, {{200, 0, 200}}); + histos.add("hFindableTPCRows_BC", "hFindableTPCRows_BC", kTH1F, {{200, 0, 200}}); + histos.add("hClustersVsRows_BC", "hClustersVsRows_BC", kTH1F, {{200, 0, 2}}); + histos.add("hTPCChi2_BC", "hTPCChi2_BC", kTH1F, {{200, 0, 100}}); + histos.add("hITSChi2_BC", "hITSChi2_BC", kTH1F, {{200, 0, 100}}); + histos.add("hTPC_nSigma_BC", "hTPC_nSigma_BC", kTH1F, {pidAxis}); + histos.add("hTOF_nSigma_BC", "hTOF_nSigma_BC", kTH1F, {pidAxis}); + histos.add("hTPC_nSigma_v_pt_BC", "hTPC_nSigma_v_pt_BC", HistType::kTHnSparseD, {pidAxis, PtAxis}); + histos.add("hTOF_nSigma_v_pt_BC", "hTOF_nSigma_v_pt_BC", HistType::kTHnSparseD, {pidAxis, PtAxis}); + // + histos.add("hDCArToPv_AC", "DCArToPv_AC", kTH1F, {{300, 0.0, 3.0}}); + histos.add("hDCAzToPv_AC", "DCAzToPv_AC", kTH1F, {{300, 0.0, 3.0}}); + histos.add("hIsPrim_AC", "hIsPrim_AC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsGood_AC", "hIsGood_AC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hIsPrimCont_AC", "hIsPrimCont_AC", kTH1F, {{2, -0.5, 1.5}}); + histos.add("hFindableTPCClusters_AC", "hFindableTPCClusters_AC", kTH1F, {{200, 0, 200}}); + histos.add("hFindableTPCRows_AC", "hFindableTPCRows_AC", kTH1F, {{200, 0, 200}}); + histos.add("hClustersVsRows_AC", "hClustersVsRows_AC", kTH1F, {{200, 0, 2}}); + histos.add("hTPCChi2_AC", "hTPCChi2_AC", kTH1F, {{200, 0, 100}}); + histos.add("hITSChi2_AC", "hITSChi2_AC", kTH1F, {{200, 0, 100}}); + histos.add("hTPC_nSigma_AC", "hTPC_nSigma_AC", kTH1F, {pidAxis}); + histos.add("hTOF_nSigma_AC", "hTOF_nSigma_AC", kTH1F, {pidAxis}); + histos.add("hTPC_nSigma_v_pt_AC", "hTPC_nSigma_v_pt_AC", HistType::kTHnSparseD, {pidAxis, PtAxis}); + histos.add("hTOF_nSigma_v_pt_AC", "hTOF_nSigma_v_pt_AC", HistType::kTHnSparseD, {pidAxis, PtAxis}); + } + // Data histos + histos.add("hUSS", "hUSS", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hLSS", "hLSS", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hUSS_Mix", "hUSS_Mix", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hLSS_Mix", "hLSS_Mix", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + + // MC histos + histos.add("hMC_USS", "hMC_USS", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hMC_LSS", "hMC_LSS", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hMC_USS_Mix", "hMC_USS_Mix", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hMC_LSS_Mix", "hMC_LSS_Mix", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hMC_USS_True", "hMC_USS_True", HistType::kTHnSparseD, {cfg_bins_Cent, MinvAxis, PtAxis}); + histos.add("hMC_Phi_True", "hMC_Phi_True", HistType::kTHnSparseD, {cfg_bins_Cent, PtAxis}); + + // Event Histograms + histos.add("hnEvents", "Event selection decision", kTH1I, {{10, -0.5, 9.5}}); + histos.add("hnEvents_MC", "Event selection decision", kTH1I, {{10, -0.5, 9.5}}); + histos.add("hnEvents_MC_True", "Event selection decision", kTH1I, {{10, -0.5, 9.5}}); + + } // end of init + + Filter collisionFilter = nabs(aod::collision::posZ) <= cfg_Event_VtxCut; + Filter collisionFilter_MC = nabs(aod::mccollision::posZ) <= cfg_Event_VtxCut; + Filter centralityFilter = nabs(aod::cent::centFT0C) <= cfg_Event_CentralityMax; + Filter acceptanceFilter = (nabs(aod::track::eta) < cfg_Track_MaxEta && nabs(aod::track::pt) >= cfg_Track_MinPt); + using EventCandidates = soa::Filtered>; + using EventCandidates_True = soa::Filtered; + + using TrackCandidates = soa::Filtered>; + using TrackCandidates_MC = soa::Filtered>; + + using BinningTypeVtxCent = ColumnBinningPolicy; + + Partition PosKaon_MC = + (aod::track::signed1Pt > static_cast(0)) && + (!cfg_Track_TPCPID || (nabs(aod::pidtpc::tpcNSigmaKa) <= cfg_Track_TPCPID_nSig)); + Partition NegKaon_MC = + (aod::track::signed1Pt < static_cast(0)) && + (!cfg_Track_TPCPID || (nabs(aod::pidtpc::tpcNSigmaKa) <= cfg_Track_TPCPID_nSig)); + Partition PosKaon = + (aod::track::signed1Pt > static_cast(0)) && + (!cfg_Track_TPCPID || (nabs(aod::pidtpc::tpcNSigmaKa) <= cfg_Track_TPCPID_nSig)); + Partition NegKaon = + (aod::track::signed1Pt < static_cast(0)) && + (!cfg_Track_TPCPID || (nabs(aod::pidtpc::tpcNSigmaKa) <= cfg_Track_TPCPID_nSig)); + + double massKa = o2::constants::physics::MassKPlus; + //***********************************// + // First, we declare some helper functions + template + void fillQA(const bool pass, const objType& obj, const int objecttype = 0) + { + + if (objecttype == 1) { + if constexpr (requires { obj.posZ(); }) { + if (!pass) { + histos.fill(HIST("hPosZ_BC"), obj.posZ()); + histos.fill(HIST("hcentFT0C_BC"), obj.centFT0C()); + } else { + histos.fill(HIST("hPosZ_AC"), obj.posZ()); + histos.fill(HIST("hcentFT0C_AC"), obj.centFT0C()); + } + } + } + if constexpr (requires { obj.tpcCrossedRowsOverFindableCls(); }) { + if (objecttype == 2) { + if (!pass) { + histos.fill(HIST("hDCArToPv_BC"), obj.dcaXY()); + histos.fill(HIST("hDCAzToPv_BC"), obj.dcaZ()); + histos.fill(HIST("hIsPrim_BC"), obj.isPrimaryTrack()); + histos.fill(HIST("hIsGood_BC"), obj.isGlobalTrackWoDCA()); + histos.fill(HIST("hIsPrimCont_BC"), obj.isPVContributor()); + histos.fill(HIST("hFindableTPCClusters_BC"), obj.tpcNClsFindable()); + histos.fill(HIST("hFindableTPCRows_BC"), obj.tpcNClsCrossedRows()); + histos.fill(HIST("hClustersVsRows_BC"), obj.tpcCrossedRowsOverFindableCls()); + histos.fill(HIST("hTPCChi2_BC"), obj.tpcChi2NCl()); + } else { + histos.fill(HIST("hDCArToPv_AC"), obj.dcaXY()); + histos.fill(HIST("hDCAzToPv_AC"), obj.dcaZ()); + histos.fill(HIST("hIsPrim_AC"), obj.isPrimaryTrack()); + histos.fill(HIST("hIsGood_AC"), obj.isGlobalTrackWoDCA()); + histos.fill(HIST("hIsPrimCont_AC"), obj.isPVContributor()); + histos.fill(HIST("hFindableTPCClusters_AC"), obj.tpcNClsFindable()); + histos.fill(HIST("hFindableTPCRows_AC"), obj.tpcNClsCrossedRows()); + histos.fill(HIST("hClustersVsRows_AC"), obj.tpcCrossedRowsOverFindableCls()); + histos.fill(HIST("hTPCChi2_AC"), obj.tpcChi2NCl()); + } + } + if (objecttype == 3) { + if (!pass) { + histos.fill(HIST("hTPC_nSigma_BC"), obj.tpcNSigmaKa()); + histos.fill(HIST("hTOF_nSigma_BC"), obj.tofNSigmaKa()); + histos.fill(HIST("hTPC_nSigma_v_pt_BC"), obj.tpcNSigmaKa(), obj.pt()); + histos.fill(HIST("hTOF_nSigma_v_pt_BC"), obj.tofNSigmaKa(), obj.pt()); + } else { + histos.fill(HIST("hTPC_nSigma_AC"), obj.tpcNSigmaKa()); + histos.fill(HIST("hTOF_nSigma_AC"), obj.tofNSigmaKa()); + histos.fill(HIST("hTPC_nSigma_v_pt_AC"), obj.tpcNSigmaKa(), obj.pt()); + histos.fill(HIST("hTOF_nSigma_v_pt_AC"), obj.tofNSigmaKa(), obj.pt()); + } + } + } + }; + //***********************************// + + // evsel + template + std::pair eventSelection(const EventType event, const bool QA) + { + + if (cfg_Track_CutQA && QA) + fillQA(false, event, 1); + + if (!event.sel8()) + return {false, 1}; + if (std::abs(event.posZ()) > cfg_Event_VtxCut) + return {false, 2}; + if (cfg_Event_Timeframe && (!event.selection_bit(aod::evsel::kNoTimeFrameBorder) || !event.selection_bit(aod::evsel::kNoITSROFrameBorder))) + return {false, 3}; + if (cfg_Event_Timerange && (!event.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard))) + return {false, 4}; + if (cfg_Event_Pileup && (!event.selection_bit(aod::evsel::kNoSameBunchPileup) || !event.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) + return {false, 5}; + if (cfg_Event_Centrality && (event.centFT0C() > cfg_Event_CentralityMax)) + return {false, 6}; + if (cfg_Event_OccupancyCut && (event.trackOccupancyInTimeRange() > cfg_Event_MaxOccupancy)) + return {false, 7}; + + if (cfg_Track_CutQA && QA) + fillQA(true, event, 1); + + return {true, 8}; + }; + + // tracksel + template + bool trackSelection(const TrackType track, const bool QA) + { + if (cfg_Track_CutQA && QA) + fillQA(false, track, 2); + + // basic track cuts + if (track.pt() < cfg_Track_MinPt) + return false; + if (std::abs(track.eta()) > cfg_Track_MaxEta) + return false; + if (std::abs(track.dcaXY()) > cfg_Track_MaxDCArToPVcut) + return false; + if (std::abs(track.dcaZ()) > cfg_Track_MaxDCAzToPVcut) + return false; + if (cfg_Track_PrimaryTrack && !track.isPrimaryTrack()) + return false; + if (track.tpcNClsFindable() < cfg_Track_nFindableTPCClusters) + return false; + if (track.tpcNClsCrossedRows() < cfg_Track_nTPCCrossedRows) + return false; + if (track.tpcCrossedRowsOverFindableCls() > cfg_Track_nRowsOverFindable) + return false; + if (track.tpcChi2NCl() > cfg_Track_nTPCChi2) + return false; + if (track.itsChi2NCl() > cfg_Track_nITSChi2) + return false; + if (cfg_Track_ConnectedToPV && !track.isPVContributor()) + return false; + + if (cfg_Track_CutQA && QA) + fillQA(true, track, 2); + return true; + }; + + // trackpid + + template + bool trackPIDKaon(const TrackPID& candidate, const bool QA) + { + bool tpcPIDPassed{false}, tofPIDPassed{false}; + + if (cfg_Track_CutQA && QA) + fillQA(false, candidate, 3); + + if (!cfg_Track_TPCPID) { + tpcPIDPassed = true; + } else { + if (std::abs(candidate.tpcNSigmaKa()) < cfg_Track_TPCPID_nSig) + tpcPIDPassed = true; + } + + if (!cfg_Track_TOFPID) { + tofPIDPassed = true; + } else { + if (candidate.hasTOF()) { + if (std::abs(candidate.tofNSigmaKa()) < cfg_Track_TOFPID_nSig) { + tofPIDPassed = true; + } + } else if (!cfg_Track_Hard_TOFPID) { + tofPIDPassed = true; + } + if (!candidate.hasTOF()) { + std::cout << candidate.tofNSigmaKa() << std::endl; + } + } + if (tpcPIDPassed && tofPIDPassed) { + if (cfg_Track_CutQA && QA) { + fillQA(true, candidate, 3); + } + return true; + } + return false; + } + + template + void TrackSlicing(const CollisionType& collision1, const TracksType&, const CollisionType& collision2, const TracksType&, const bool QA, const bool IsMix) + { + auto slicedtracks1 = PosKaon->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); + auto slicedtracks2 = NegKaon->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); + auto centrality = collision1.centFT0C(); + for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(slicedtracks1, slicedtracks2))) { + auto [Minv, PhiPt] = minvReconstruction(track1, track2, QA); + if (Minv < 0) + continue; + double conjugate = track1.sign() * track2.sign(); + if (!IsMix) { + if (conjugate < 0) { + histos.fill(HIST("hUSS"), centrality, Minv, PhiPt); + } else if (conjugate > 0) { + histos.fill(HIST("hLSS"), centrality, Minv, PhiPt); + } + } else { + if (conjugate < 0) { + histos.fill(HIST("hUSS_Mix"), centrality, Minv, PhiPt); + } else if (conjugate > 0) { + histos.fill(HIST("hLSS_Mix"), centrality, Minv, PhiPt); + } + } + } + } // TrackSlicing + + template + void TrackSlicing_MC(const CollisionType& collision1, const TracksType&, const CollisionType& collision2, const TracksType&, const bool QA, const bool IsMix) + { + auto slicedtracks1 = PosKaon_MC->sliceByCached(aod::track::collisionId, collision1.globalIndex(), cache); + auto slicedtracks2 = NegKaon_MC->sliceByCached(aod::track::collisionId, collision2.globalIndex(), cache); + auto centrality = collision1.centFT0C(); + for (auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(slicedtracks1, slicedtracks2))) { + auto [Minv, PhiPt] = minvReconstruction(track1, track2, QA); + if (Minv < 0) + continue; + double conjugate = track1.sign() * track2.sign(); + if (!IsMix) { + if (conjugate < 0) { + histos.fill(HIST("hMC_USS"), centrality, Minv, PhiPt); + } else if (conjugate > 0) { + histos.fill(HIST("hMC_LSS"), centrality, Minv, PhiPt); + } + } else { + if (conjugate < 0) { + histos.fill(HIST("hMC_USS_Mix"), centrality, Minv, PhiPt); + } else if (conjugate > 0) { + histos.fill(HIST("hMC_LSS_Mix"), centrality, Minv, PhiPt); + } + } + // now we do mc true + if (!track1.has_mcParticle() || !track2.has_mcParticle()) + continue; + auto part1 = track1.mcParticle(); + auto part2 = track2.mcParticle(); + if (std::fabs(part1.pdgCode()) != 321) + continue; // Not Kaon + if (std::fabs(part2.pdgCode()) != 321) + continue; // Not Kaon + + if (!part1.has_mothers()) + continue; // Not decaying Kaon + if (!part2.has_mothers()) + continue; // Not decaying Kaon + + std::vector mothers1{}; + std::vector mothers1PDG{}; + for (auto& part1_mom : part1.template mothers_as()) { + mothers1.push_back(part1_mom.globalIndex()); + mothers1PDG.push_back(part1_mom.pdgCode()); + } + + std::vector mothers2{}; + std::vector mothers2PDG{}; + for (auto& part2_mom : part2.template mothers_as()) { + mothers2.push_back(part2_mom.globalIndex()); + mothers2PDG.push_back(part2_mom.pdgCode()); + } + + if (mothers1PDG[0] != 333) + continue; // mother not phi + if (mothers2PDG[0] != 333) + continue; // mother not phi + + if (mothers1[0] != mothers2[0]) + continue; // Kaons not from the same phi + + histos.fill(HIST("hMC_USS_True"), centrality, Minv, PhiPt); + } + } // TrackSlicing + + // Invariant mass + template + std::pair minvReconstruction(const TracksType& trk1, const TracksType& trk2, const bool QA) + { + TLorentzVector lDecayDaughter1, lDecayDaughter2, lResonance; + //==================================================== + + if (!trackSelection(trk1, QA) || !trackSelection(trk2, false)) + return {-1.0, -1.0}; + + if (cfg_Track_Explicit_PID) { + if (!trackPIDKaon(trk1, QA) || !trackPIDKaon(trk2, false)) + return {-1.0, -1.0}; + } + + if (trk1.globalIndex() >= trk2.globalIndex()) + return {-1.0, -1.0}; + + lDecayDaughter1.SetXYZM(trk1.px(), trk1.py(), trk1.pz(), massKa); + lDecayDaughter2.SetXYZM(trk2.px(), trk2.py(), trk2.pz(), massKa); + lResonance = lDecayDaughter1 + lDecayDaughter2; + + return {lResonance.M(), lResonance.Pt()}; + } // MinvReconstruction + + //***************// + // DATA + //***************// + + int nEvents = 0; + void processSameEvent(EventCandidates::iterator const& collision, TrackCandidates const& tracks) + { + if (cDebugLevel > 0) { + ++nEvents; + if (nEvents % 10000 == 0) { + std::cout << "Processed Data Events: " << nEvents << std::endl; + } + } + + auto [goodEv, code] = eventSelection(collision, true); + histos.fill(HIST("hnEvents"), code); + if (!goodEv) + return; + TrackSlicing(collision, tracks, collision, tracks, true, false); + + } // end of process + + PROCESS_SWITCH(phiOO, processSameEvent, "Process Same events", true); + + //***************// + // DATA (MIX) + //***************// + + int nEvents_Mix = 0; + void processMixedEvent(EventCandidates const& collisions, TrackCandidates const& tracks) + { + auto tracksTuple = std::make_tuple(tracks); + BinningTypeVtxCent colBinning{{cfg_bins_MixVtx, cfg_bins_MixMult}, true}; + SameKindPair pairs{colBinning, cfg_Mix_NMixedEvents, -1, collisions, tracksTuple, &cache}; + + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (cDebugLevel > 0) { + ++nEvents_Mix; + if (nEvents_Mix % 10000 == 0) { + std::cout << "Processed Mixed Events: " << nEvents_Mix << std::endl; + } + } + auto [goodEv1, code1] = eventSelection(collision1, false); + auto [goodEv2, code2] = eventSelection(collision2, false); + if (!goodEv1 || !goodEv2) + continue; + TrackSlicing(collision1, tracks1, collision2, tracks2, false, true); + } // mixing + } // end of process + PROCESS_SWITCH(phiOO, processMixedEvent, "Process Mixed events", false); + + //***************// + // RECONSTRUCTED MC + //***************// + + int nEvents_MC = 0; + void processSameEvent_MC(EventCandidates::iterator const& collision, TrackCandidates_MC const& tracks, aod::McParticles const&) + { + if (cDebugLevel > 0) { + ++nEvents_MC; + if (nEvents_MC % 10000 == 0) { + std::cout << "Processed MC (REC) Events: " << nEvents_MC << std::endl; + } + } + + auto [goodEv, code] = eventSelection(collision, true); + histos.fill(HIST("hnEvents_MC"), code); + if (!goodEv) + return; + TrackSlicing_MC(collision, tracks, collision, tracks, true, false); + + } // end of process + PROCESS_SWITCH(phiOO, processSameEvent_MC, "Process Same events (MC)", true); + + //***************// + // RECONSTRUCTED MC (MIX) + //***************// + + int nEvents_MC_Mix = 0; + void processMixedEvent_MC(EventCandidates const& collisions, TrackCandidates_MC const& tracks, aod::McParticles const&) + { + auto tracksTuple = std::make_tuple(tracks); + BinningTypeVtxCent colBinning{{cfg_bins_MixVtx, cfg_bins_MixMult}, true}; + SameKindPair pairs{colBinning, cfg_Mix_NMixedEvents, -1, collisions, tracksTuple, &cache}; + for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + if (cDebugLevel > 0) { + ++nEvents_MC_Mix; + if (nEvents_MC_Mix % 10000 == 0) { + std::cout << "Processed Mixed Events: " << nEvents_MC_Mix << std::endl; + } + } + auto [goodEv1, code1] = eventSelection(collision1, false); + auto [goodEv2, code2] = eventSelection(collision2, false); + if (!goodEv1 || !goodEv2) + continue; + TrackSlicing_MC(collision1, tracks1, collision2, tracks2, false, true); + } // mixing + } // end of process + PROCESS_SWITCH(phiOO, processMixedEvent_MC, "Process Mixed events (MC)", false); + + //***************// + // GENERATED MC + //***************// + + int nEvents_True = 0; + void processParticles(EventCandidates_True::iterator const& collision, soa::SmallGroups> const& recocolls, aod::McParticles const& particles) + { + if (cDebugLevel > 0) { + ++nEvents_True; + if (nEvents_True % 10000 == 0) { + std::cout << "Processed MC (GEN) Events: " << nEvents_True << std::endl; + } + } + + if (fabs(collision.posZ()) > cfg_Event_VtxCut) + return; + + if (recocolls.size() <= 0) { // not reconstructed + if (cfg_Force_GenReco) { + return; + } + } + + double centrality = -1; + for (auto& recocoll : recocolls) { // poorly reconstructed + centrality = recocoll.centFT0C(); + auto [goodEv, code] = eventSelection(recocoll, false); + histos.fill(HIST("hnEvents_MC_True"), code); + if (!goodEv) + return; + } + + for (auto& particle : particles) { + if (particle.pdgCode() != 333) + continue; + if (std::fabs(particle.eta()) > cfg_Track_MaxEta) + continue; + + if (cfg_Force_BR) { + bool baddecay = false; + for (auto& phidaughter : particle.daughters_as()) { + if (std::fabs(phidaughter.pdgCode()) != 321) { + baddecay = true; + break; + } + if (cfg_Force_Kaon_Acceptence) { + if (std::fabs(phidaughter.eta()) > cfg_Track_MaxEta) { + baddecay = true; + break; + } + } + } // loop over daughters + + if (baddecay) + continue; + } // enforce BR restriction + + histos.fill(HIST("hMC_Phi_True"), centrality, particle.pt()); + } // loop over particles + + } // end of process + PROCESS_SWITCH(phiOO, processParticles, "Process Particles", false); + +}; // end of main struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +};