6363#include < array>
6464#include < cmath>
6565#include < cstdlib>
66+ #include < deque>
6667#include < memory>
6768#include < ranges>
6869#include < string>
@@ -157,7 +158,7 @@ struct PhiStrangenessCorrelation {
157158 Configurable<int > eventSelectionType{" eventSelectionType" , 0 , " Event selection type: 0 - default selection only, 1 - default + phi meson selection" };
158159
159160 // Configurable for analysis mode
160- Configurable<int > analysisMode{" analysisMode" , kMassvsMass , " Analysis mode: 0 - old method with online normalization, 1 - new method with offline normlization, 2 - deltay vs deltaphi" };
161+ Configurable<int > analysisMode{" analysisMode" , kDeltaYvsDeltaPhi , " Analysis mode: 0 - old method with online normalization, 1 - new method with offline normlization, 2 - deltay vs deltaphi" };
161162
162163 // Configurable for event selection
163164 Configurable<float > cutZVertex{" cutZVertex" , 10 .0f , " Accepted z-vertex range (cm)" }; // TO BE REMOVED
@@ -173,13 +174,13 @@ struct PhiStrangenessCorrelation {
173174
174175 // Configurables for K0s selection
175176 struct : ConfigurableGroup {
176- Configurable<bool > selectK0sInSigRegion{" selectK0sInSigRegion" , false , " Select K0s candidates in signal region" };
177+ Configurable<bool > selectK0sInSigRegion{" selectK0sInSigRegion" , true , " Select K0s candidates in signal region" };
177178 Configurable<std::pair<float , float >> rangeMK0sSignal{" rangeMK0sSignal" , {0 .47f , 0 .53f }, " K0S mass range for signal extraction" };
178179 } k0sConfigs;
179180
180181 // Configurables for Pions selection
181182 struct : ConfigurableGroup {
182- Configurable<bool > selectPionInSigRegion{" selectPionInSigRegion" , false , " Select Pion candidates in signal region" };
183+ Configurable<bool > selectPionInSigRegion{" selectPionInSigRegion" , true , " Select Pion candidates in signal region" };
183184 Configurable<float > pidTPCMax{" pidTPCMax" , 2 .0f , " Maximum nSigma TPC" };
184185 Configurable<float > pidTOFMax{" pidTOFMax" , 2 .0f , " Maximum nSigma TOF" };
185186 Configurable<float > tofPIDThreshold{" tofPIDThreshold" , 0 .5f , " Minimum pT after which TOF PID is applicable" };
@@ -260,6 +261,24 @@ struct PhiStrangenessCorrelation {
260261
261262 static constexpr std::array<std::string_view, 2 > phiMassRegionLabels{" Signal" , " Sideband" };
262263 static constexpr std::array<std::string_view, ParticleOfInterestSize> particleOfInterestLabels{" Phi" , " K0S" , " Pion" /* "PionTPC", "PionTPCTOF"*/ };
264+ static constexpr std::array<std::string_view, ParticleOfInterestSize - 1 > assocParticleLabels{" K0S" , " Pi" };
265+
266+ // Light structures to store only the necessary information for the correlation analysis at MCGen level
267+ struct MiniParticle {
268+ float pt;
269+ float y;
270+ float phi;
271+ };
272+
273+ struct MiniEvent {
274+ float multiplicity;
275+ std::vector<MiniParticle> phiParticles;
276+ std::vector<MiniParticle> k0sParticles;
277+ std::vector<MiniParticle> pionParticles;
278+ };
279+
280+ // Buffer for mixed event, organized as a vector of deques, one for each multiplicity bin, containing the past events with their particles of interest needed for mixing
281+ std::vector<std::deque<MiniEvent>> eventBuffer;
263282
264283 void init (InitContext&)
265284 {
@@ -316,6 +335,12 @@ struct PhiStrangenessCorrelation {
316335 histos.add (" pi/h3PiMCGen" , " Pion in MC Gen" , kTH3F , {binnedmultAxis, binnedpTPiAxis, yAxis});
317336 histos.add (" pi/h4PiMCGenAssocReco" , " Pion in MC Gen Assoc Reco" , kTHnSparseF , {vertexZAxis, binnedmultAxis, binnedpTPiAxis, yAxis});
318337
338+ histos.add (" phiK0S/h5PhiK0SClosureMCGen" , " Deltay vs deltaphi for Phi and K0Short in MCGen" , kTHnSparseF , {binnedmultAxis, binnedpTPhiAxis, binnedpTK0SAxis, deltayAxis, deltaphiAxis});
339+ histos.add (" phiPi/h5PhiPiClosureMCGen" , " Deltay vs deltaphi for Phi and Pion in MCGen" , kTHnSparseF , {binnedmultAxis, binnedpTPhiAxis, binnedpTPiAxis, deltayAxis, deltaphiAxis});
340+
341+ histos.add (" phiK0S/h5PhiK0SClosureMCGenME" , " Deltay vs deltaphi for Phi and K0Short in MCGen ME" , kTHnSparseF , {binnedmultAxis, binnedpTPhiAxis, binnedpTK0SAxis, deltayAxis, deltaphiAxis});
342+ histos.add (" phiPi/h5PhiPiClosureMCGenME" , " Deltay vs deltaphi for Phi and Pion in MCGen ME" , kTHnSparseF , {binnedmultAxis, binnedpTPhiAxis, binnedpTPiAxis, deltayAxis, deltaphiAxis});
343+
319344 // Load efficiency maps from CCDB
320345 if (applyEfficiency) {
321346 ccdb->setURL (ccdbUrl);
@@ -327,6 +352,8 @@ struct PhiStrangenessCorrelation {
327352 loadEfficiencyMapFromCCDB (static_cast <ParticleOfInterest>(i));
328353 }
329354 }
355+
356+ eventBuffer.resize (binsMult->size () - 1 );
330357 }
331358
332359 void loadEfficiencyMapFromCCDB (ParticleOfInterest poi)
@@ -354,6 +381,15 @@ struct PhiStrangenessCorrelation {
354381 return RecoDecay::constrainAngle (phiTrigger - phiAssociated, -o2::constants::math::PIHalf);
355382 }
356383
384+ int getCentBin (float multiplicity)
385+ {
386+ if (multiplicity < binsMult->front () || multiplicity >= binsMult->back ())
387+ return -1 ;
388+
389+ auto it = std::upper_bound (binsMult->begin (), binsMult->end (), multiplicity);
390+ return std::distance (binsMult->begin (), it) - 1 ;
391+ }
392+
357393 template <typename TCollision, typename TPhiCands, typename TK0SCands, typename TPionCands>
358394 void processPhiK0SPionSE (TCollision const & collision, TPhiCands const & phiCandidates, TK0SCands const & k0sReduced, TPionCands const & pionTracks)
359395 {
@@ -798,6 +834,213 @@ struct PhiStrangenessCorrelation {
798834 }
799835
800836 PROCESS_SWITCH (PhiStrangenessCorrelation, processParticleEfficiency, " Process function for Efficiency Computation for Particles of Interest" , false );
837+
838+ /* void processMCGenClosureSE(MCCollisions::iterator const& mcCollision, aod::McParticles const& mcParticles)
839+ {
840+ float multiplicity = mcCollision.centFT0M();
841+
842+ std::vector<int64_t> phiIndices;
843+ std::vector<int64_t> k0sIndices;
844+ std::vector<int64_t> pionIndices;
845+ std::vector<std::vector<int64_t>> assocIndices;
846+
847+ auto inYAcceptance = [&](const auto& mcParticle) {
848+ return std::abs(mcParticle.y()) <= yConfigs.cfgYAcceptance;
849+ };
850+
851+ for (const auto& mcParticle : mcParticles) {
852+ if (!inYAcceptance(mcParticle))
853+ continue;
854+
855+ switch (std::abs(mcParticle.pdgCode())) {
856+ case o2::constants::physics::Pdg::kPhi:
857+ if (eventSelectionType == 0 && mcParticle.pt() >= minPtMcGenConfigs.minPhiPt)
858+ phiIndices.push_back(mcParticle.globalIndex());
859+ break;
860+ case PDG_t::kK0Short:
861+ if (mcParticle.isPhysicalPrimary() && mcParticle.pt() >= minPtMcGenConfigs.v0SettingMinPt)
862+ k0sIndices.push_back(mcParticle.globalIndex());
863+ break;
864+ case PDG_t::kPiPlus:
865+ if (mcParticle.isPhysicalPrimary() && mcParticle.pt() >= minPtMcGenConfigs.cMinPionPtcut)
866+ pionIndices.push_back(mcParticle.globalIndex());
867+ break;
868+ default:
869+ break;
870+ }
871+ }
872+
873+ assocIndices.push_back(k0sIndices);
874+ assocIndices.push_back(pionIndices);
875+
876+ for (std::size_t iTrigg{0}; iTrigg < phiIndices.size(); ++iTrigg) {
877+ auto& phiParticle = mcParticles.rawIteratorAt(phiIndices[iTrigg]);
878+
879+ static_for<0, assocIndices.size() - 1>([&](auto i_idx) {
880+ constexpr unsigned int i = i_idx.value;
881+
882+ for (std::size_t iAssoc{0}; iAssoc < assocIndices[i].size(); ++iAssoc) {
883+ auto& assocParticle = mcParticles.rawIteratorAt(assocIndices[i][iAssoc]);
884+
885+ histos.fill(HIST("mcGenClosure/h5Phi") + HIST(assocParticleLabels[i]) + HIST("ClosureGenSE"), multiplicity, phiParticle.pt(), assocParticle.pt(), phiParticle.y() - assocParticle.y(), getDeltaPhi(phiParticle.phi(), assocParticle.phi()));
886+ }
887+ });
888+ }
889+ }
890+
891+ PROCESS_SWITCH(PhiStrangenessCorrelation, processMCGenClosureSE, "Process function for MC Gen Closure Test in SE", false);
892+
893+ void processMCGenClosureME(MCCollisions::iterator const& mcCollision, aod::McParticles const& mcParticles)
894+ {
895+ float multiplicity = mcCollision.centFT0M();
896+
897+ std::vector<MiniParticle> phiParticles;
898+ std::vector<MiniParticle> k0sParticles;
899+ std::vector<MiniParticle> pionParticles;
900+
901+ auto inYAcceptance = [&](const auto& mcParticle) {
902+ return std::abs(mcParticle.y()) <= yConfigs.cfgYAcceptance;
903+ };
904+
905+ for (const auto& mcParticle : mcParticles) {
906+ if (!inYAcceptance(mcParticle))
907+ continue;
908+
909+ switch (std::abs(mcParticle.pdgCode())) {
910+ case o2::constants::physics::Pdg::kPhi:
911+ if (eventSelectionType == 0 && mcParticle.pt() >= minPtMcGenConfigs.minPhiPt)
912+ phiParticles.emplace_back(mcParticle.pt(), mcParticle.y(), mcParticle.phi());
913+ break;
914+ case PDG_t::kK0Short:
915+ if (mcParticle.isPhysicalPrimary() && mcParticle.pt() >= minPtMcGenConfigs.v0SettingMinPt)
916+ k0sParticles.emplace_back(mcParticle.pt(), mcParticle.y(), mcParticle.phi());
917+ break;
918+ case PDG_t::kPiPlus:
919+ if (mcParticle.isPhysicalPrimary() && mcParticle.pt() >= minPtMcGenConfigs.cMinPionPtcut)
920+ pionParticles.emplace_back(mcParticle.pt(), mcParticle.y(), mcParticle.phi());
921+ break;
922+ default:
923+ break;
924+ }
925+ }
926+
927+ if (phiParticles.empty() && k0sParticles.empty() && pionParticles.empty())
928+ return;
929+
930+ int multBin = getCentBin(multiplicity);
931+
932+ // Loop over past events in the same multiplicity bin and fill histograms with all combinations of current phi particles and past K0S and pion particles
933+ for (const auto& pastEvent : eventBuffer[multBin]) {
934+ for (const auto& phiParticle : phiParticles) {
935+ for (const auto& k0sParticle : pastEvent.k0sParticles) {
936+ histos.fill(HIST("mcGenClosure/h5PhiK0SClosureGenME"), multiplicity, phiParticle.pt, k0sParticle.pt, phiParticle.y - k0sParticle.y, getDeltaPhi(phiParticle.phi, k0sParticle.phi));
937+ }
938+ for (const auto& pionParticle : pastEvent.pionParticles) {
939+ histos.fill(HIST("mcGenClosure/h5PhiPiClosureGenME"), multiplicity, phiParticle.pt, pionParticle.pt, phiParticle.y - pionParticle.y, getDeltaPhi(phiParticle.phi, pionParticle.phi));
940+ }
941+ }
942+ }
943+
944+ // Add current event to buffer
945+ MiniEvent currentEvent;
946+ currentEvent.multiplicity = multiplicity;
947+ currentEvent.phiParticles = std::move(phiParticles);
948+ currentEvent.k0sParticles = std::move(k0sParticles);
949+ currentEvent.pionParticles = std::move(pionParticles);
950+
951+ eventBuffer[multBin].push_front(std::move(currentEvent));
952+ if (eventBuffer[multBin].size() > static_cast<std::size_t>(cfgNoMixedEvents.value))
953+ eventBuffer[multBin].pop_back();
954+ }
955+
956+ PROCESS_SWITCH(PhiStrangenessCorrelation, processMCGenClosureME, "Process function for MC Gen Closure Test in ME", false);*/
957+
958+ void processMCGenClosure (MCCollisions::iterator const & mcCollision, aod::McParticles const & mcParticles)
959+ {
960+ float multiplicity = mcCollision.centFT0M ();
961+
962+ std::vector<MiniParticle> phiParticles;
963+ std::vector<MiniParticle> k0sParticles;
964+ std::vector<MiniParticle> pionParticles;
965+
966+ auto inYAcceptance = [&](const auto & mcParticle) {
967+ return std::abs (mcParticle.y ()) <= yConfigs.cfgYAcceptance ;
968+ };
969+
970+ for (const auto & mcParticle : mcParticles) {
971+ if (!inYAcceptance (mcParticle))
972+ continue ;
973+
974+ switch (std::abs (mcParticle.pdgCode ())) {
975+ case o2::constants::physics::Pdg::kPhi :
976+ if (eventSelectionType == 0 && mcParticle.pt () >= minPtMcGenConfigs.minPhiPt )
977+ phiParticles.emplace_back (mcParticle.pt (), mcParticle.y (), mcParticle.phi ());
978+ break ;
979+ case PDG_t::kK0Short :
980+ if (mcParticle.isPhysicalPrimary () && mcParticle.pt () >= minPtMcGenConfigs.v0SettingMinPt )
981+ k0sParticles.emplace_back (mcParticle.pt (), mcParticle.y (), mcParticle.phi ());
982+ break ;
983+ case PDG_t::kPiPlus :
984+ if (mcParticle.isPhysicalPrimary () && mcParticle.pt () >= minPtMcGenConfigs.cMinPionPtcut )
985+ pionParticles.emplace_back (mcParticle.pt (), mcParticle.y (), mcParticle.phi ());
986+ break ;
987+ default :
988+ break ;
989+ }
990+ }
991+
992+ if (phiParticles.empty () && k0sParticles.empty () && pionParticles.empty ())
993+ return ;
994+
995+ int multBin = getCentBin (multiplicity);
996+ if (multBin < 0 )
997+ return ;
998+
999+ std::vector<MiniParticle>* currentAssocParticles[] = {&k0sParticles, &pionParticles};
1000+
1001+ for (const auto & phiParticle : phiParticles) {
1002+ static_for<0 , assocParticleLabels.size () - 1 >([&](auto i_idx) {
1003+ constexpr unsigned int i = i_idx.value ;
1004+
1005+ for (const auto & assocParticle : *(currentAssocParticles[i])) {
1006+ histos.fill (HIST (" phi" ) + HIST (assocParticleLabels[i]) + HIST (" /h5Phi" ) + HIST (assocParticleLabels[i]) + HIST (" ClosureMCGen" ),
1007+ multiplicity, phiParticle.pt , assocParticle.pt ,
1008+ phiParticle.y - assocParticle.y ,
1009+ getDeltaPhi (phiParticle.phi , assocParticle.phi ));
1010+ }
1011+ });
1012+ }
1013+
1014+ for (const auto & pastEvent : eventBuffer[multBin]) {
1015+ const std::vector<MiniParticle>* pastAssocParticles[] = {&pastEvent.k0sParticles , &pastEvent.pionParticles };
1016+
1017+ // Loop over past events in the same multiplicity bin and fill histograms with all combinations of current phi particles and past associated particles
1018+ for (const auto & phiParticle : phiParticles) {
1019+ static_for<0 , assocParticleLabels.size () - 1 >([&](auto i_idx) {
1020+ constexpr unsigned int i = i_idx.value ;
1021+
1022+ for (const auto & assocParticle : *(pastAssocParticles[i])) {
1023+ histos.fill (HIST (" phi" ) + HIST (assocParticleLabels[i]) + HIST (" /h5Phi" ) + HIST (assocParticleLabels[i]) + HIST (" ClosureMCGenME" ),
1024+ multiplicity, phiParticle.pt , assocParticle.pt ,
1025+ phiParticle.y - assocParticle.y ,
1026+ getDeltaPhi (phiParticle.phi , assocParticle.phi ));
1027+ }
1028+ });
1029+ }
1030+ }
1031+
1032+ MiniEvent currentEvent;
1033+ currentEvent.multiplicity = multiplicity;
1034+ currentEvent.phiParticles = std::move (phiParticles);
1035+ currentEvent.k0sParticles = std::move (k0sParticles);
1036+ currentEvent.pionParticles = std::move (pionParticles);
1037+
1038+ eventBuffer[multBin].push_front (std::move (currentEvent));
1039+ if (eventBuffer[multBin].size () > static_cast <std::size_t >(cfgNoMixedEvents.value ))
1040+ eventBuffer[multBin].pop_back ();
1041+ }
1042+
1043+ PROCESS_SWITCH (PhiStrangenessCorrelation, processMCGenClosure, " Process function for MC Gen Closure Test in SE and ME" , false );
8011044};
8021045
8031046WorkflowSpec defineDataProcessing (ConfigContext const & cfgc)
0 commit comments