Skip to content

Commit 7646f27

Browse files
committed
Add V0s in jet reconstruction in MC RECO with configurable useV0inJetRec
1 parent 69ad281 commit 7646f27

1 file changed

Lines changed: 170 additions & 3 deletions

File tree

PWGLF/Tasks/Strangeness/strangenessInJetsIons.cxx

Lines changed: 170 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
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

@@ -68,6 +69,7 @@
6869
#include <map>
6970
#include <ostream>
7071
#include <string>
72+
#include <type_traits>
7173
#include <vector>
7274

7375
using 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

Comments
 (0)