2222
2323#include " PWGJE/Core/JetBkgSubUtils.h"
2424#include " PWGJE/Core/JetUtilities.h"
25+ // #include "PWGJE/Core/JetV0Utilities.h"
2526#include " PWGLF/DataModel/LFStrangenessTables.h"
2627#include " PWGLF/DataModel/mcCentrality.h"
2728
6869#include < map>
6970#include < ostream>
7071#include < string>
72+ #include < type_traits>
7173#include < vector>
7274
7375using namespace std ;
@@ -130,6 +132,7 @@ struct StrangenessInJetsIons {
130132 Configurable<std::string> triggerName{" triggerName" , " fOmega" , " Software trigger name" };
131133 Configurable<int > centrEstimator{" centrEstimator" , 1 , " Select centrality estimator. Options: 0 = FT0C, 1 = FT0M. CCDB objects available only for FT0M." };
132134 Configurable<bool > calculateFeeddownMatrix{" calculateFeeddownMatrix" , true , " Fill feeddown matrix for Lambda if MC" };
135+ Configurable<bool > useV0inJetRec{" useV0inJetRec" , true , " Include V0s in jet reconstruction" };
133136
134137 // Event selection
135138 Configurable<bool > requireNoSameBunchPileup{" requireNoSameBunchPileup" , true , " Require kNoSameBunchPileup selection" };
@@ -563,6 +566,12 @@ struct StrangenessInJetsIons {
563566 return deltaPhi;
564567 }
565568
569+ // Compute energy
570+ double GetEnergy (double px, double py, double pz, double mass)
571+ {
572+ return std::sqrt (px * px + py * py + pz * pz + mass * mass);
573+ }
574+
566575 // Check if particle is a physical primary or a decay product of a heavy-flavor hadron
567576 bool isPhysicalPrimaryOrFromHF (aod::McParticle const & particle, aod::McParticles const & mcParticles)
568577 {
@@ -1529,6 +1538,145 @@ struct StrangenessInJetsIons {
15291538 }
15301539 }
15311540
1541+ /* *
1542+ * @brief Identifies the index of the common mother for two MC particles.
1543+ *
1544+ * @tparam T Type of the MC particle objects
1545+ * @param posParticle MC particle associated with the positive daughter
1546+ * @param negParticle MC particle associated with the negative daughter
1547+ * @return int The index of the common mother, or -1 if no common mother exists.
1548+ */
1549+ template <typename T>
1550+ int GetCommonMotherId (aod::McParticles const & mcParticles,
1551+ const T& posParticle, const T& negParticle)
1552+ {
1553+ int motherIdPos = posParticle.mothersIds ()[0 ];
1554+ int motherIdNeg = negParticle.mothersIds ()[0 ];
1555+
1556+ const auto & motherPos = mcParticles.iteratorAt (motherIdPos);
1557+ const auto & motherNeg = mcParticles.iteratorAt (motherIdNeg);
1558+ if (motherPos != motherNeg) {
1559+ return -1 ; // Return -1 if they originate from different parents
1560+ }
1561+
1562+ return motherIdPos; // Return mother ID
1563+ }
1564+
1565+ /* *
1566+ * Returns true if the track is a daughter of the V0 candidate
1567+ * Adapted from: PWGJE/Core/JetV0Utilities.h
1568+ *
1569+ * @param track track that is being checked
1570+ * @param candidate V0 candidate that is being checked
1571+ */
1572+ template <typename T, typename U>
1573+ bool isV0DaughterTrack (T& track, U& candidate)
1574+ {
1575+ if (candidate.posTrackId () == track.globalIndex () || candidate.negTrackId () == track.globalIndex ()) {
1576+ return true ;
1577+ } else {
1578+ return false ;
1579+ }
1580+ }
1581+
1582+ /* *
1583+ * @brief Add V0s as input for the jet finder algorithm in MC reco (detector level)
1584+ *
1585+ * @tparam Track
1586+ * @tparam V0PerColl The container type holding the sliced V0 candidates for the current collision.
1587+ *
1588+ * @param[in,out] fjInput Vector of FastJet PseudoJets where valid V0s will be appended.
1589+ * @param[in] fjTracks Vector containing tracks already selected for jet finder input.
1590+ * @param[in] v0sPerColl Sliced V0 candidates belonging to this specific collision.
1591+ * @param[in] mcParticles Global MC particles table used to look up mother particle truth information.
1592+ * @param[in] vtxPos TVector3 object representing the vertex position.
1593+ */
1594+ template <typename Track, typename V0PerColl>
1595+ void AddV0sForJetReconstructionMC (std::vector<fastjet::PseudoJet>& fjInput,
1596+ const std::vector<Track>& fjTracks,
1597+ V0PerColl const & v0sPerColl,
1598+ aod::McParticles const & mcParticles,
1599+ const TVector3& vtxPos)
1600+ {
1601+ // Vector of labels: if true remove the element from fjInput
1602+ std::vector<bool > isTrackReplaced (fjTracks.size (), false );
1603+ std::vector<fastjet::PseudoJet> v0PseudoJets; // V0s to use as input for jet finder
1604+
1605+ for (const auto & v0 : v0sPerColl) {
1606+ const auto & pos = v0.template posTrack_as <DaughterTracksMC>();
1607+ const auto & neg = v0.template negTrack_as <DaughterTracksMC>();
1608+
1609+ // Get MC particles
1610+ if (!pos.has_mcParticle () || !neg.has_mcParticle ()) {
1611+ continue ;
1612+ }
1613+ const auto & posParticle = pos.template mcParticle_as <aod::McParticles>();
1614+ const auto & negParticle = neg.template mcParticle_as <aod::McParticles>();
1615+ if (!posParticle.has_mothers () || !negParticle.has_mothers ()) {
1616+ continue ;
1617+ }
1618+
1619+ // Select particles originating from the same parent
1620+ int motherId = GetCommonMotherId (mcParticles, posParticle, negParticle);
1621+ if (motherId < 0 )
1622+ continue ; // if motherId is -1, it means no common mother was found
1623+ const auto & mother = mcParticles.iteratorAt (motherId);
1624+ // const bool isPhysPrim = mother.isPhysicalPrimary();
1625+ int pdgParent = mother.pdgCode ();
1626+
1627+ // / NOTE: V0s are not required to be primary particles;
1628+ bool isK0S = false , isLambda = false , isAntiLambda = false ;
1629+ // K0s
1630+ if (passedK0ShortSelection (v0, pos, neg, vtxPos) && pdgParent == kK0Short ) {
1631+ // LOG(info) << "[AddV0sForJetReconstructionMC] Add K0S as input for jet finder.";
1632+ double energy = GetEnergy (v0.px (), v0.py (), v0.pz (), o2::constants::physics::MassK0Short);
1633+ fastjet::PseudoJet fourMomentum (v0.px (), v0.py (), v0.pz (), energy);
1634+ v0PseudoJets.emplace_back (fourMomentum);
1635+ isK0S = true ;
1636+ }
1637+ // Lambda
1638+ if (passedLambdaSelection (v0, pos, neg, vtxPos) && pdgParent == kLambda0 ) {
1639+ // LOG(info) << "[AddV0sForJetReconstructionMC] Add Lambda as input for jet finder.";
1640+ double energy = GetEnergy (v0.px (), v0.py (), v0.pz (), o2::constants::physics::MassLambda0);
1641+ fastjet::PseudoJet fourMomentum (v0.px (), v0.py (), v0.pz (), energy);
1642+ v0PseudoJets.emplace_back (fourMomentum);
1643+ isLambda = true ;
1644+ }
1645+ // AntiLambda
1646+ if (passedAntiLambdaSelection (v0, pos, neg, vtxPos) && pdgParent == kLambda0Bar ) {
1647+ // LOG(info) << "[AddV0sForJetReconstructionMC] Add AntiLambda as input for jet finder.";
1648+ double energy = GetEnergy (v0.px (), v0.py (), v0.pz (), o2::constants::physics::MassLambda0Bar);
1649+ fastjet::PseudoJet fourMomentum (v0.px (), v0.py (), v0.pz (), energy);
1650+ v0PseudoJets.emplace_back (fourMomentum);
1651+ isAntiLambda = true ;
1652+ }
1653+
1654+ // Exclude daughter tracks in case a V0 is found
1655+ bool isV0 = isK0S || isLambda || isAntiLambda;
1656+ if (!isV0)
1657+ continue ;
1658+ for (int i = 0 ; i < fjTracks.size (); ++i) {
1659+ if (isV0DaughterTrack (fjTracks[i], v0)) {
1660+ // LOG(info) << "[AddV0sForJetReconstructionMC] V0 daughter track found in fjTracks.";
1661+ isTrackReplaced[i] = true ;
1662+ }
1663+ }
1664+ }
1665+
1666+ std::vector<fastjet::PseudoJet> cleanFjInput;
1667+ cleanFjInput.reserve (fjInput.size ());
1668+ for (size_t i = 0 ; i < fjInput.size (); ++i) {
1669+ if (!isTrackReplaced[i])
1670+ cleanFjInput.push_back (fjInput[i]);
1671+ }
1672+ for (const auto & v0pj : v0PseudoJets) {
1673+ cleanFjInput.push_back (v0pj);
1674+ }
1675+ // LOG(info) << "[AddV0sForJetReconstructionMC] Size fjInput: " << fjInput.size();
1676+ fjInput = std::move (cleanFjInput);
1677+ // LOG(info) << "[AddV0sForJetReconstructionMC] Size fjInput dopo move: " << fjInput.size();
1678+ }
1679+
15321680 // Process data
15331681 void processData (SelCollisions::iterator const & collision, aod::V0Datas const & fullV0s,
15341682 aod::CascDataExt const & Cascades, DaughterTracks const & tracks,
@@ -2190,6 +2338,9 @@ struct StrangenessInJetsIons {
21902338
21912339 const auto & mcCollision = collision.mcCollision_as <soa::Join<aod::McCollisions, aod::McCentFT0Ms, aod::McCentFT0Cs>>();
21922340
2341+ // Vertex position vector
2342+ TVector3 vtxPos (collision.posX (), collision.posY (), collision.posZ ());
2343+
21932344 // Clear containers at the start of the event loop
21942345 fjParticles.clear ();
21952346 selectedJet.clear ();
@@ -2242,14 +2393,22 @@ struct StrangenessInJetsIons {
22422393 cascPerColl, tracksPerColl, multiplicity);
22432394
22442395 // Loop over reconstructed tracks
2396+ std::vector<std::decay_t <decltype (*tracksPerColl.begin ())>> fjTracks;
22452397 for (auto const & track : tracksPerColl) {
22462398 if (!passedTrackSelectionForJetReconstruction (track))
22472399 continue ;
22482400
22492401 // 4-momentum representation of a particle
22502402 fastjet::PseudoJet fourMomentum (track.px (), track.py (), track.pz (), track.energy (o2::constants::physics::MassPionCharged));
22512403 fjParticles.emplace_back (fourMomentum);
2404+ fjTracks.push_back (track);
2405+ }
2406+
2407+ // Include V0s as tracks for jet reconstruction
2408+ if (useV0inJetRec && particleOfInterestDict[ParticleOfInterest::kV0Particles ]) {
2409+ AddV0sForJetReconstructionMC (fjParticles, fjTracks, v0sPerColl, mcParticles, vtxPos);
22522410 }
2411+ fjTracks.clear ();
22532412
22542413 // Reject empty events
22552414 if (fjParticles.size () < 1 )
@@ -2405,6 +2564,17 @@ struct StrangenessInJetsIons {
24052564 if (pdgParent == 0 )
24062565 continue ;
24072566
2567+ // --- alternative method to avoid double for loop
2568+ int motherId = GetCommonMotherId (mcParticles, posParticle, negParticle);
2569+ if (motherId < 0 )
2570+ continue ; // if motherId is -1, it means no common mother was found
2571+ const auto & motherTest = mcParticles.iteratorAt (motherId);
2572+ // const bool isPhysPrimTest = motherTest.isPhysicalPrimary();
2573+ int pdgParentTest = motherTest.pdgCode ();
2574+ if (pdgParent != pdgParentTest)
2575+ LOG (warning) << " pdgParent != pdgParentTest" << endl;
2576+ // ---
2577+
24082578 // Compute distance from jet and UE axes
24092579 double deltaEtaJet = v0dir.Eta () - selectedJet[i].Eta ();
24102580 double deltaPhiJet = getDeltaPhi (v0dir.Phi (), selectedJet[i].Phi ());
@@ -2416,9 +2586,6 @@ struct StrangenessInJetsIons {
24162586 double deltaPhiUe2 = getDeltaPhi (v0dir.Phi (), ue2[i].Phi ());
24172587 double deltaRue2 = std::sqrt (deltaEtaUe2 * deltaEtaUe2 + deltaPhiUe2 * deltaPhiUe2);
24182588
2419- // Vertex position vector
2420- TVector3 vtxPos (collision.posX (), collision.posY (), collision.posZ ());
2421-
24222589 // Fill Armenteros-Podolanski TH2
24232590 // registryQC.fill(HIST("ArmenterosPreSel_REC"), v0.alpha(), v0.qtarm());
24242591
0 commit comments