From 4a0e2d7599ad54a3727a6162fbf0beac1be7223a Mon Sep 17 00:00:00 2001 From: Pritam Chakraborty <47203359+prchakra@users.noreply.github.com> Date: Mon, 13 Oct 2025 23:00:10 +0200 Subject: [PATCH] [PWGCF] FemtoUniverse: Add function to pair MCTruth particles --- ...irTaskTrackTrackSpherHarMultKtExtended.cxx | 252 ++++++++++++++++-- 1 file changed, 232 insertions(+), 20 deletions(-) diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx index 83497834459..60161fe04a6 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackSpherHarMultKtExtended.cxx @@ -61,6 +61,7 @@ static const float cutsTable[nPart][nCuts]{ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { Service pdg; + Service pdgMC; /// Particle selection part @@ -101,6 +102,9 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { SliceCache cache; Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + using FemtoTruthParticles = soa::Join; + Preslice perColMCTruth = aod::femtouniverseparticle::fdCollisionId; + /// Particle 1 struct : o2::framework::ConfigurableGroup { Configurable ConfPDGCodePartOne{"ConfPDGCodePartOne", 211, "Particle 1 - PDG code"}; @@ -114,6 +118,8 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { /// Partition for particle 1 Partition partsOne = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == as(trackonefilter.ConfChargePart1) && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfPtLowPart1; Partition partsOneMC = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && aod::femtouniverseparticle::sign == as(trackonefilter.ConfChargePart1) && aod::femtouniverseparticle::pt < trackonefilter.ConfPtHighPart1 && aod::femtouniverseparticle::pt > trackonefilter.ConfPtLowPart1; + Partition partsOneMCTruth = aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack); + // /// Histogramming for particle 1 @@ -133,6 +139,7 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { /// Partition for particle 2 Partition partsTwo = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == as(tracktwofilter.ConfChargePart2)) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfPtLowPart2; Partition partsTwoMC = aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack) && (aod::femtouniverseparticle::sign == as(tracktwofilter.ConfChargePart2)) && aod::femtouniverseparticle::pt < tracktwofilter.ConfPtHighPart2 && aod::femtouniverseparticle::pt > tracktwofilter.ConfPtLowPart2; + Partition partsTwoMCTruth = aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack); /// Histogramming for particle 2 FemtoUniverseParticleHisto trackHistoPartTwo; @@ -695,6 +702,138 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { } PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processSameEventMC, "Enable processing same event for Monte Carlo", false); + /// This function processes the same event and takes care of all the histogramming + /// \todo the trivial loops over the tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... + /// @tparam PartitionType + /// @tparam PartType + /// @tparam isMC: enables Monte Carlo truth specific histograms + /// @param groupPartsOne partition for the first particle passed by the process function + /// @param groupPartsTwo partition for the second particle passed by the process function + /// @param parts femtoUniverseParticles table (in case of Monte Carlo joined with FemtoUniverseMCLabels) + /// @param magFieldTesla magnetic field of the collision + /// @param multCol multiplicity of the collision + template + void doSameEventMCTruth(PartitionType groupPartsOne, PartitionType groupPartsTwo, int multCol, int ContType, bool fillQA) + { + + /// Histogramming same event + if ((ContType == 1 || ContType == 2) && fillQA) { + for (const auto& part : groupPartsOne) { + if (part.partType() == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) { + int pdgCode = static_cast(part.tempFitVar()); + const auto& pdgParticle = pdgMC->GetParticle(pdgCode); + if (pdgParticle) { + trackHistoPartOne.fillQA(part); + } + } + } + } + + if ((ContType == 1 || ContType == 3) && fillQA) { + for (const auto& part : groupPartsTwo) { + if (part.partType() == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) { + int pdgCode = static_cast(part.tempFitVar()); + const auto& pdgParticle = pdgMC->GetParticle(pdgCode); + if (pdgParticle) { + trackHistoPartTwo.fillQA(part); + } + } + } + } + + if (ContType == 1) { + + /// Now build the combinations for non-identical particle pairs + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + + int pdgCodePartOne = static_cast(p1.tempFitVar()); + const auto& pdgParticleOne = pdgMC->GetParticle(pdgCodePartOne); + int pdgCodePartTwo = static_cast(p2.tempFitVar()); + const auto& pdgParticleTwo = pdgMC->GetParticle(pdgCodePartTwo); + if (pdgParticleOne && pdgParticleTwo && (pdgCodePartOne == trackonefilter.ConfPDGCodePartOne) && (pdgCodePartTwo == tracktwofilter.ConfPDGCodePartTwo)) { + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + sameEventMultCont.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } + } + } else { + for (const auto& [p1, p2] : combinations(CombinationsStrictlyUpperIndexPolicy(groupPartsOne, groupPartsOne))) { + + int pdgCodePartOne = static_cast(p1.tempFitVar()); + const auto& pdgParticleOne = pdgMC->GetParticle(pdgCodePartOne); + int pdgCodePartTwo = static_cast(p2.tempFitVar()); + const auto& pdgParticleTwo = pdgMC->GetParticle(pdgCodePartTwo); + + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + double rand; + rand = randgen->Rndm(); + std::vector f3d; + if (pdgParticleOne && pdgParticleTwo && (pdgCodePartOne == trackonefilter.ConfPDGCodePartOne) && (pdgCodePartTwo == tracktwofilter.ConfPDGCodePartTwo)) { + + switch (ContType) { + case 2: { + if (rand > 0.5) { + sameEventMultContPP.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } else if (rand <= 0.5) { + sameEventMultContPP.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } + break; + } + + case 3: { + if (rand > 0.5) { + sameEventMultContMM.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } else if (rand <= 0.5) { + sameEventMultContMM.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::same, 2, multCol, kT, ConfIsIden); + } + break; + } + default: + break; + } + } + } + } + } + + /// process function for to call doSameEvent with Monte Carlo + /// \param col subscribe to the collision table (Monte Carlo Reconstructed reconstructed) + /// \param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth + /// \param FemtoUniverseMCParticles subscribe to the Monte Carlo truth table + void processSameEventMCTruth(o2::aod::FdCollision const& col, + FemtoTruthParticles const&) + { + fillCollision(col, ConfIsCent); + + auto thegroupPartsOne = partsOneMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + auto thegroupPartsTwo = partsTwoMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + bool fillQA = true; + randgen = new TRandom2(0); + + if (ConfIsCent) { + if (cfgProcessPM) { + doSameEventMCTruth(thegroupPartsOne, thegroupPartsTwo, col.multV0M(), 1, fillQA); + } + if (cfgProcessPP) { + doSameEventMCTruth(thegroupPartsOne, thegroupPartsOne, col.multV0M(), 2, fillQA); + } + if (cfgProcessMM) { + doSameEventMCTruth(thegroupPartsTwo, thegroupPartsTwo, col.multV0M(), 3, fillQA); + } + } else { + if (cfgProcessPM) { + doSameEventMCTruth(thegroupPartsOne, thegroupPartsTwo, col.multNtr(), 1, fillQA); + } + if (cfgProcessPP) { + doSameEventMCTruth(thegroupPartsOne, thegroupPartsOne, col.multNtr(), 2, fillQA); + } + if (cfgProcessMM) { + doSameEventMCTruth(thegroupPartsTwo, thegroupPartsTwo, col.multNtr(), 3, fillQA); + } + } + delete randgen; + } + PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processSameEventMCTruth, "Enable processing same event for MC truth", false); + /// This function processes the mixed event /// \todo the trivial loops over the collisions and tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... /// \tparam PartitionType @@ -864,26 +1003,6 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { } PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processMixedEventNtr, "Enable processing mixed events for centrality", false); - /// process function for to fill covariance histograms - /// \param col subscribe to the collision table (Data) - /// \param parts subscribe to the femtoUniverseParticleTable - void processCov(soa::Filtered::iterator const& /*col*/, - FilteredFemtoFullParticles const& /*parts*/) - { - int JMax = (ConfLMax + 1) * (ConfLMax + 1); - if (cfgProcessMM) { - sameEventMultContMM.fillMultkTCov(femto_universe_sh_container::EventType::same, JMax); - mixedEventMultContMM.fillMultkTCov(femto_universe_sh_container::EventType::mixed, JMax); - } else if (cfgProcessPP) { - sameEventMultContPP.fillMultkTCov(femto_universe_sh_container::EventType::same, JMax); - mixedEventMultContPP.fillMultkTCov(femto_universe_sh_container::EventType::mixed, JMax); - } else if (cfgProcessPM) { - sameEventMultCont.fillMultkTCov(femto_universe_sh_container::EventType::same, JMax); - mixedEventMultCont.fillMultkTCov(femto_universe_sh_container::EventType::mixed, JMax); - } - } - PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processCov, "Enable processing same event covariance", false); - /// brief process function for to call doMixedEvent with Monte Carlo /// @param cols subscribe to the collisions table (Monte Carlo Reconstructed reconstructed) /// @param parts subscribe to joined table FemtoUniverseParticles and FemtoUniverseMCLables to access Monte Carlo truth @@ -971,6 +1090,99 @@ struct femtoUniversePairTaskTrackTrackSpherHarMultKtExtended { delete randgen; } PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processMixedEventMCNtr, "Enable processing mixed events MC", false); + + /// This function processes the mixed event + /// \todo the trivial loops over the collisions and tracks should be factored out since they will be common to all combinations of T-T, T-V0, V0-V0, ... + /// \tparam PartitionType + /// \tparam PartType + /// \tparam isMC: enables Monte Carlo truth specific histograms + /// \param groupPartsOne partition for the first particle passed by the process function + /// \param groupPartsTwo partition for the second particle passed by the process function + /// \param parts femtoUniverseParticles table (in case of Monte Carlo joined with FemtoUniverseMCLabels) + /// \param magFieldTesla magnetic field of the collision + /// \param multCol multiplicity of the collision + template + void doMixedEventMCTruth(PartitionType groupPartsOne, PartitionType groupPartsTwo, int multCol, int ContType) + { + + for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { + + int pdgCodePartOne = static_cast(p1.tempFitVar()); + const auto& pdgParticleOne = pdgMC->GetParticle(pdgCodePartOne); + int pdgCodePartTwo = static_cast(p2.tempFitVar()); + const auto& pdgParticleTwo = pdgMC->GetParticle(pdgCodePartTwo); + + float kT = FemtoUniverseMath::getkT(p1, mass1, p2, mass2); + double rand; + rand = randgen->Rndm(); + if (pdgParticleOne && pdgParticleTwo && (pdgCodePartOne == trackonefilter.ConfPDGCodePartOne) && (pdgCodePartTwo == tracktwofilter.ConfPDGCodePartTwo)) { + + switch (ContType) { + case 1: { + if (rand > 0.5) { + mixedEventMultCont.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } else { + mixedEventMultCont.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } + break; + } + + case 2: { + if (rand > 0.5) { + mixedEventMultContPP.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } else { + mixedEventMultContPP.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } + break; + } + + case 3: { + if (rand > 0.5) { + mixedEventMultContMM.fillMultNumDen(p1, p2, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } else { + mixedEventMultContMM.fillMultNumDen(p2, p1, femto_universe_sh_container::EventType::mixed, 2, multCol, kT, ConfIsIden); + } + break; + } + default: + break; + } + } + } + } + + /// process function for to call doMixedEvent with Data + /// @param cols subscribe to the collisions table (Data) + /// @param parts subscribe to the femtoUniverseParticleTable + void processMixedEventNtrMCTruth(o2::aod::FdCollisions const& cols, + FemtoTruthParticles const&) + { + randgen = new TRandom2(0); + + for (const auto& [collision1, collision2] : soa::selfCombinations(colBinningNtr, ConfNEventsMix, -1, cols, cols)) { + + const int multiplicityCol = collision1.multNtr(); + MixQaRegistry.fill(HIST("MixingQA/hMECollisionBins"), colBinningNtr.getBin({collision1.posZ(), multiplicityCol})); + + if (cfgProcessPM) { + auto groupPartsOne = partsOneMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEventMCTruth(groupPartsOne, groupPartsTwo, multiplicityCol, 1); + } + if (cfgProcessPP) { + auto groupPartsOne = partsOneMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsOneMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEventMCTruth(groupPartsOne, groupPartsTwo, multiplicityCol, 2); + } + if (cfgProcessMM) { + auto groupPartsOne = partsTwoMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); + auto groupPartsTwo = partsTwoMCTruth->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); + doMixedEventMCTruth(groupPartsOne, groupPartsTwo, multiplicityCol, 3); + } + } + delete randgen; + } + PROCESS_SWITCH(femtoUniversePairTaskTrackTrackSpherHarMultKtExtended, processMixedEventNtrMCTruth, "Enable processing MC Truth mixed events for multiplicity", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)