From f6424257947babce8a362a8567af18c83f2c8ce6 Mon Sep 17 00:00:00 2001 From: Henrik Fribert Date: Mon, 16 Feb 2026 22:56:40 +0100 Subject: [PATCH 1/5] Feature: Recalculation of Kink pT for better resolution --- PWGCF/Femto/Core/femtoUtils.h | 90 +++++++++++++++++++++++++++ PWGCF/Femto/Core/pairHistManager.h | 19 +++--- PWGCF/Femto/Core/pairProcessHelpers.h | 20 ++++-- 3 files changed, 117 insertions(+), 12 deletions(-) diff --git a/PWGCF/Femto/Core/femtoUtils.h b/PWGCF/Femto/Core/femtoUtils.h index 5f9da9ab910..2ec64564c96 100644 --- a/PWGCF/Femto/Core/femtoUtils.h +++ b/PWGCF/Femto/Core/femtoUtils.h @@ -133,6 +133,96 @@ float qn(T const& col) return qn; } +/// Recalculate pT for Kinks (Sigmas) using kinematic constraints +inline float calcPtnew(float pxMother, float pyMother, float pzMother, float pxDaughter, float pyDaughter, float pzDaughter) +{ + // Particle masses in GeV/c^2 + const float massPion = 0.13957f; + const float massNeutron = 0.93957f; + const float massSigmaMinus = 1.19745f; + + // Calculate mother momentum and direction versor + float pMother = std::sqrt(pxMother * pxMother + pyMother * pyMother + pzMother * pzMother); + if (pMother < 1e-6f) + return -999.f; + + float versorX = pxMother / pMother; + float versorY = pyMother / pMother; + float versorZ = pzMother / pMother; + + // Calculate daughter energy + float ePi = std::sqrt(massPion * massPion + pxDaughter * pxDaughter + pyDaughter * pyDaughter + pzDaughter * pzDaughter); + + // Scalar product of versor with daughter momentum + float a = versorX * pxDaughter + versorY * pyDaughter + versorZ * pzDaughter; + + // Solve quadratic equation for momentum magnitude + float K = massSigmaMinus * massSigmaMinus + massPion * massPion - massNeutron * massNeutron; + float A = 4.f * (ePi * ePi - a * a); + float B = -4.f * a * K; + float C = 4.f * ePi * ePi * massSigmaMinus * massSigmaMinus - K * K; + + if (std::abs(A) < 1e-6f) + return -999.f; + + float D = B * B - 4.f * A * C; + if (D < 0.f) + return -999.f; + + float sqrtD = std::sqrt(D); + float P1 = (-B + sqrtD) / (2.f * A); + float P2 = (-B - sqrtD) / (2.f * A); + + // Pick physical solution: prefer P2 if positive, otherwise P1 + if (P2 < 0.f && P1 < 0.f) + return -999.f; + if (P2 < 0.f) + return P1; + + // Choose solution closest to original momentum + float p1Diff = std::abs(P1 - pMother); + float p2Diff = std::abs(P2 - pMother); + float P = (p1Diff < p2Diff) ? P1 : P2; + + // Calculate pT from recalibrated momentum + float pxS = versorX * P; + float pyS = versorY * P; + return std::sqrt(pxS * pxS + pyS * pyS); +} + +/// Helper function to calculate recalculated pT for kink particles (Sigma/SigmaPlus) +template +float getRecalculatedPtForKink(const TParticle& particle, const TTrackTable& trackTable) +{ + // Check if particle has chaDau index + if constexpr (requires { particle.has_chaDau(); }) { + if (particle.has_chaDau()) { + try { + auto chaDaughter = trackTable.rawIteratorAt(particle.chaDauId() - trackTable.offset()); + + // Extract momentum components directly from dynamic columns + float pxDaug = chaDaughter.px(); + float pyDaug = chaDaughter.py(); + float pzDaug = chaDaughter.pz(); + + // Get momentum components from dynamic columns + float pxMoth = particle.px(); + float pyMoth = particle.py(); + float pzMoth = particle.pz(); + + // Recalculate pT using kinematic constraints + float ptRecalc = calcPtnew(pxMoth, pyMoth, pzMoth, pxDaug, pyDaug, pzDaug); + if (ptRecalc > 0) { + return ptRecalc; + } + } catch (const std::exception& e) { + return -1.0f; + } + } + } + return -1.0f; +} + inline bool enableTable(const char* tableName, int userSetting, o2::framework::InitContext& initContext) { if (userSetting == 1) { diff --git a/PWGCF/Femto/Core/pairHistManager.h b/PWGCF/Femto/Core/pairHistManager.h index 30c0916b67e..10ff4eb916b 100644 --- a/PWGCF/Femto/Core/pairHistManager.h +++ b/PWGCF/Femto/Core/pairHistManager.h @@ -334,12 +334,17 @@ class PairHistManager } template - void setPair(const T1& particle1, const T2& particle2) + void setPair(const T1& particle1, const T2& particle2, float pt1Recalc = -1.0f, float pt2Recalc = -1.0f) { // pt in track table is calculated from 1/signedPt from the original track table // in case of He with Z=2, we have to rescale the pt with the absolute charge - mParticle1 = ROOT::Math::PtEtaPhiMVector(mAbsCharge1 * particle1.pt(), particle1.eta(), particle1.phi(), mPdgMass1); - mParticle2 = ROOT::Math::PtEtaPhiMVector(mAbsCharge2 * particle2.pt(), particle2.eta(), particle2.phi(), mPdgMass2); + + // Use recalculated pT if provided (for recalculated kink pT), otherwise use particle pT + float pt1 = (pt1Recalc > 0.0f) ? pt1Recalc : particle1.pt(); + float pt2 = (pt2Recalc > 0.0f) ? pt2Recalc : particle2.pt(); + + mParticle1 = ROOT::Math::PtEtaPhiMVector(mAbsCharge1 * pt1, particle1.eta(), particle1.phi(), mPdgMass1); + mParticle2 = ROOT::Math::PtEtaPhiMVector(mAbsCharge2 * pt2, particle2.eta(), particle2.phi(), mPdgMass2); // set kT mKt = getKt(mParticle1, mParticle2); @@ -363,17 +368,17 @@ class PairHistManager } template - void setPair(const T1& particle1, const T2& particle2, const T3& col) + void setPair(const T1& particle1, const T2& particle2, const T3& col, float pt1Recalc = -1.0f, float pt2Recalc = -1.0f) { - setPair(particle1, particle2); + setPair(particle1, particle2, pt1Recalc, pt2Recalc); mMult = col.mult(); mCent = col.cent(); } template - void setPair(const T1& particle1, const T2& particle2, const T3& col1, const T4& col2) + void setPair(const T1& particle1, const T2& particle2, const T3& col1, const T4& col2, float pt1Recalc = -1.0f, float pt2Recalc = -1.0f) { - setPair(particle1, particle2); + setPair(particle1, particle2, pt1Recalc, pt2Recalc); mMult = 0.5f * (col1.mult() + col2.mult()); // if mixing with multiplicity, should be in the same mixing bin mCent = 0.5f * (col1.cent() + col2.cent()); // if mixing with centrality, should be in the same mixing bin } diff --git a/PWGCF/Femto/Core/pairProcessHelpers.h b/PWGCF/Femto/Core/pairProcessHelpers.h index 8a70283e9c6..a6b46a1c3a4 100644 --- a/PWGCF/Femto/Core/pairProcessHelpers.h +++ b/PWGCF/Femto/Core/pairProcessHelpers.h @@ -18,6 +18,7 @@ #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/DataModel/FemtoTables.h" +#include "PWGCF/Femto/Core/femtoUtils.h" #include "Framework/ASoAHelpers.h" @@ -62,16 +63,19 @@ void processSameEvent(T1 const& SliceParticle, if (CprManager.isClosePair()) { continue; } + // Calculate recalculated pT for kinks (if applicable) + float pt1Recalc = o2::analysis::femto::utils::getRecalculatedPtForKink(p1, TrackTable); + float pt2Recalc = o2::analysis::femto::utils::getRecalculatedPtForKink(p2, TrackTable); // Randomize pair order if enabled switch (pairOrder) { case kOrder12: - PairHistManager.setPair(p1, p2, Collision); + PairHistManager.setPair(p1, p2, Collision, pt1Recalc, pt2Recalc); break; case kOrder21: - PairHistManager.setPair(p2, p1, Collision); + PairHistManager.setPair(p2, p1, Collision, pt2Recalc, pt1Recalc); break; default: - PairHistManager.setPair(p1, p2, Collision); + PairHistManager.setPair(p1, p2, Collision, pt1Recalc, pt2Recalc); } // fill deta-dphi histograms with kstar cutoff CprManager.fill(PairHistManager.getKstar()); @@ -189,7 +193,10 @@ void processSameEvent(T1 const& SliceParticle1, if (CprManager.isClosePair()) { continue; } - PairHistManager.setPair(p1, p2, Collision); + // Calculate recalculated pT for kinks (if applicable) + float pt1Recalc = o2::analysis::femto::utils::getRecalculatedPtForKink(p1, TrackTable); + float pt2Recalc = o2::analysis::femto::utils::getRecalculatedPtForKink(p2, TrackTable); + PairHistManager.setPair(p1, p2, Collision, pt1Recalc, pt2Recalc); CprManager.fill(PairHistManager.getKstar()); if (PairHistManager.checkPairCuts()) { PairHistManager.template fill(); @@ -309,7 +316,10 @@ void processMixedEvent(T1 const& Collisions, if (CprManager.isClosePair()) { continue; } - PairHistManager.setPair(p1, p2, collision1, collision2); + // Calculate recalculated pT for kinks (if applicable) + float pt1Recalc = o2::analysis::femto::utils::getRecalculatedPtForKink(p1, TrackTable); + float pt2Recalc = o2::analysis::femto::utils::getRecalculatedPtForKink(p2, TrackTable); + PairHistManager.setPair(p1, p2, collision1, collision2, pt1Recalc, pt2Recalc); CprManager.fill(PairHistManager.getKstar()); if (PairHistManager.checkPairCuts()) { PairHistManager.template fill(); From 5b8ea7339c0f94703b0571a8cde4389455996c56 Mon Sep 17 00:00:00 2001 From: Henrik Fribert Date: Mon, 16 Feb 2026 23:01:48 +0100 Subject: [PATCH 2/5] Fix: Formatting --- PWGCF/Femto/Core/pairHistManager.h | 4 ++-- PWGCF/Femto/Core/pairProcessHelpers.h | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/PWGCF/Femto/Core/pairHistManager.h b/PWGCF/Femto/Core/pairHistManager.h index 10ff4eb916b..c53966eb204 100644 --- a/PWGCF/Femto/Core/pairHistManager.h +++ b/PWGCF/Femto/Core/pairHistManager.h @@ -338,11 +338,11 @@ class PairHistManager { // pt in track table is calculated from 1/signedPt from the original track table // in case of He with Z=2, we have to rescale the pt with the absolute charge - + // Use recalculated pT if provided (for recalculated kink pT), otherwise use particle pT float pt1 = (pt1Recalc > 0.0f) ? pt1Recalc : particle1.pt(); float pt2 = (pt2Recalc > 0.0f) ? pt2Recalc : particle2.pt(); - + mParticle1 = ROOT::Math::PtEtaPhiMVector(mAbsCharge1 * pt1, particle1.eta(), particle1.phi(), mPdgMass1); mParticle2 = ROOT::Math::PtEtaPhiMVector(mAbsCharge2 * pt2, particle2.eta(), particle2.phi(), mPdgMass2); diff --git a/PWGCF/Femto/Core/pairProcessHelpers.h b/PWGCF/Femto/Core/pairProcessHelpers.h index a6b46a1c3a4..b7cbc1d7b96 100644 --- a/PWGCF/Femto/Core/pairProcessHelpers.h +++ b/PWGCF/Femto/Core/pairProcessHelpers.h @@ -16,10 +16,9 @@ #ifndef PWGCF_FEMTO_CORE_PAIRPROCESSHELPERS_H_ #define PWGCF_FEMTO_CORE_PAIRPROCESSHELPERS_H_ +#include "PWGCF/Femto/Core/femtoUtils.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/DataModel/FemtoTables.h" -#include "PWGCF/Femto/Core/femtoUtils.h" - #include "Framework/ASoAHelpers.h" namespace o2::analysis::femto From 1a4f1ea0bf02a74e1056e8c01ae20f42611053d2 Mon Sep 17 00:00:00 2001 From: Henrik Fribert Date: Mon, 16 Feb 2026 23:04:16 +0100 Subject: [PATCH 3/5] Fix: Formatting --- PWGCF/Femto/Core/pairProcessHelpers.h | 1 + 1 file changed, 1 insertion(+) diff --git a/PWGCF/Femto/Core/pairProcessHelpers.h b/PWGCF/Femto/Core/pairProcessHelpers.h index b7cbc1d7b96..2dd28bd44b1 100644 --- a/PWGCF/Femto/Core/pairProcessHelpers.h +++ b/PWGCF/Femto/Core/pairProcessHelpers.h @@ -19,6 +19,7 @@ #include "PWGCF/Femto/Core/femtoUtils.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/DataModel/FemtoTables.h" + #include "Framework/ASoAHelpers.h" namespace o2::analysis::femto From d25ba5e27227fc50ef718449e7e4398871e06585 Mon Sep 17 00:00:00 2001 From: Henrik Fribert Date: Tue, 17 Feb 2026 13:53:08 +0100 Subject: [PATCH 4/5] Feature: Added a pT converter for less invasive code change --- PWGCF/Femto/Core/femtoUtils.h | 33 ------- PWGCF/Femto/Core/pairHistManager.h | 19 ++-- PWGCF/Femto/Core/pairProcessHelpers.h | 20 ++--- PWGCF/Femto/DataModel/FemtoTables.h | 19 +++- PWGCF/Femto/TableProducer/CMakeLists.txt | 5 ++ .../femtoProducerKinkPtConverter.cxx | 89 +++++++++++++++++++ 6 files changed, 124 insertions(+), 61 deletions(-) create mode 100644 PWGCF/Femto/TableProducer/femtoProducerKinkPtConverter.cxx diff --git a/PWGCF/Femto/Core/femtoUtils.h b/PWGCF/Femto/Core/femtoUtils.h index 2ec64564c96..d7d0a61f9aa 100644 --- a/PWGCF/Femto/Core/femtoUtils.h +++ b/PWGCF/Femto/Core/femtoUtils.h @@ -190,39 +190,6 @@ inline float calcPtnew(float pxMother, float pyMother, float pzMother, float pxD return std::sqrt(pxS * pxS + pyS * pyS); } -/// Helper function to calculate recalculated pT for kink particles (Sigma/SigmaPlus) -template -float getRecalculatedPtForKink(const TParticle& particle, const TTrackTable& trackTable) -{ - // Check if particle has chaDau index - if constexpr (requires { particle.has_chaDau(); }) { - if (particle.has_chaDau()) { - try { - auto chaDaughter = trackTable.rawIteratorAt(particle.chaDauId() - trackTable.offset()); - - // Extract momentum components directly from dynamic columns - float pxDaug = chaDaughter.px(); - float pyDaug = chaDaughter.py(); - float pzDaug = chaDaughter.pz(); - - // Get momentum components from dynamic columns - float pxMoth = particle.px(); - float pyMoth = particle.py(); - float pzMoth = particle.pz(); - - // Recalculate pT using kinematic constraints - float ptRecalc = calcPtnew(pxMoth, pyMoth, pzMoth, pxDaug, pyDaug, pzDaug); - if (ptRecalc > 0) { - return ptRecalc; - } - } catch (const std::exception& e) { - return -1.0f; - } - } - } - return -1.0f; -} - inline bool enableTable(const char* tableName, int userSetting, o2::framework::InitContext& initContext) { if (userSetting == 1) { diff --git a/PWGCF/Femto/Core/pairHistManager.h b/PWGCF/Femto/Core/pairHistManager.h index c53966eb204..30c0916b67e 100644 --- a/PWGCF/Femto/Core/pairHistManager.h +++ b/PWGCF/Femto/Core/pairHistManager.h @@ -334,17 +334,12 @@ class PairHistManager } template - void setPair(const T1& particle1, const T2& particle2, float pt1Recalc = -1.0f, float pt2Recalc = -1.0f) + void setPair(const T1& particle1, const T2& particle2) { // pt in track table is calculated from 1/signedPt from the original track table // in case of He with Z=2, we have to rescale the pt with the absolute charge - - // Use recalculated pT if provided (for recalculated kink pT), otherwise use particle pT - float pt1 = (pt1Recalc > 0.0f) ? pt1Recalc : particle1.pt(); - float pt2 = (pt2Recalc > 0.0f) ? pt2Recalc : particle2.pt(); - - mParticle1 = ROOT::Math::PtEtaPhiMVector(mAbsCharge1 * pt1, particle1.eta(), particle1.phi(), mPdgMass1); - mParticle2 = ROOT::Math::PtEtaPhiMVector(mAbsCharge2 * pt2, particle2.eta(), particle2.phi(), mPdgMass2); + mParticle1 = ROOT::Math::PtEtaPhiMVector(mAbsCharge1 * particle1.pt(), particle1.eta(), particle1.phi(), mPdgMass1); + mParticle2 = ROOT::Math::PtEtaPhiMVector(mAbsCharge2 * particle2.pt(), particle2.eta(), particle2.phi(), mPdgMass2); // set kT mKt = getKt(mParticle1, mParticle2); @@ -368,17 +363,17 @@ class PairHistManager } template - void setPair(const T1& particle1, const T2& particle2, const T3& col, float pt1Recalc = -1.0f, float pt2Recalc = -1.0f) + void setPair(const T1& particle1, const T2& particle2, const T3& col) { - setPair(particle1, particle2, pt1Recalc, pt2Recalc); + setPair(particle1, particle2); mMult = col.mult(); mCent = col.cent(); } template - void setPair(const T1& particle1, const T2& particle2, const T3& col1, const T4& col2, float pt1Recalc = -1.0f, float pt2Recalc = -1.0f) + void setPair(const T1& particle1, const T2& particle2, const T3& col1, const T4& col2) { - setPair(particle1, particle2, pt1Recalc, pt2Recalc); + setPair(particle1, particle2); mMult = 0.5f * (col1.mult() + col2.mult()); // if mixing with multiplicity, should be in the same mixing bin mCent = 0.5f * (col1.cent() + col2.cent()); // if mixing with centrality, should be in the same mixing bin } diff --git a/PWGCF/Femto/Core/pairProcessHelpers.h b/PWGCF/Femto/Core/pairProcessHelpers.h index 2dd28bd44b1..8a70283e9c6 100644 --- a/PWGCF/Femto/Core/pairProcessHelpers.h +++ b/PWGCF/Femto/Core/pairProcessHelpers.h @@ -16,7 +16,6 @@ #ifndef PWGCF_FEMTO_CORE_PAIRPROCESSHELPERS_H_ #define PWGCF_FEMTO_CORE_PAIRPROCESSHELPERS_H_ -#include "PWGCF/Femto/Core/femtoUtils.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/DataModel/FemtoTables.h" @@ -63,19 +62,16 @@ void processSameEvent(T1 const& SliceParticle, if (CprManager.isClosePair()) { continue; } - // Calculate recalculated pT for kinks (if applicable) - float pt1Recalc = o2::analysis::femto::utils::getRecalculatedPtForKink(p1, TrackTable); - float pt2Recalc = o2::analysis::femto::utils::getRecalculatedPtForKink(p2, TrackTable); // Randomize pair order if enabled switch (pairOrder) { case kOrder12: - PairHistManager.setPair(p1, p2, Collision, pt1Recalc, pt2Recalc); + PairHistManager.setPair(p1, p2, Collision); break; case kOrder21: - PairHistManager.setPair(p2, p1, Collision, pt2Recalc, pt1Recalc); + PairHistManager.setPair(p2, p1, Collision); break; default: - PairHistManager.setPair(p1, p2, Collision, pt1Recalc, pt2Recalc); + PairHistManager.setPair(p1, p2, Collision); } // fill deta-dphi histograms with kstar cutoff CprManager.fill(PairHistManager.getKstar()); @@ -193,10 +189,7 @@ void processSameEvent(T1 const& SliceParticle1, if (CprManager.isClosePair()) { continue; } - // Calculate recalculated pT for kinks (if applicable) - float pt1Recalc = o2::analysis::femto::utils::getRecalculatedPtForKink(p1, TrackTable); - float pt2Recalc = o2::analysis::femto::utils::getRecalculatedPtForKink(p2, TrackTable); - PairHistManager.setPair(p1, p2, Collision, pt1Recalc, pt2Recalc); + PairHistManager.setPair(p1, p2, Collision); CprManager.fill(PairHistManager.getKstar()); if (PairHistManager.checkPairCuts()) { PairHistManager.template fill(); @@ -316,10 +309,7 @@ void processMixedEvent(T1 const& Collisions, if (CprManager.isClosePair()) { continue; } - // Calculate recalculated pT for kinks (if applicable) - float pt1Recalc = o2::analysis::femto::utils::getRecalculatedPtForKink(p1, TrackTable); - float pt2Recalc = o2::analysis::femto::utils::getRecalculatedPtForKink(p2, TrackTable); - PairHistManager.setPair(p1, p2, collision1, collision2, pt1Recalc, pt2Recalc); + PairHistManager.setPair(p1, p2, collision1, collision2); CprManager.fill(PairHistManager.getKstar()); if (PairHistManager.checkPairCuts()) { PairHistManager.template fill(); diff --git a/PWGCF/Femto/DataModel/FemtoTables.h b/PWGCF/Femto/DataModel/FemtoTables.h index 66707be9e8b..4c890bdb4e6 100644 --- a/PWGCF/Femto/DataModel/FemtoTables.h +++ b/PWGCF/Femto/DataModel/FemtoTables.h @@ -529,7 +529,24 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmas_001, "FSIGMA", 1, femtobase::dynamic::Py, femtobase::dynamic::Pz, femtobase::dynamic::Theta); -using FSigmas = FSigmas_001; + +// table for basic sigma information +DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmas_002, "FSIGMA", 2, + o2::soa::Index<>, + femtobase::stored::FColId, // use sign to differentiate between sigma minus (-1) and anti sigma minus (+1) + femtobase::stored::SignedPt, + femtobase::stored::Eta, + femtobase::stored::Phi, + femtobase::stored::Mass, + femtokinks::ChaDauId, + femtobase::dynamic::Sign, + femtobase::dynamic::Pt, + femtobase::dynamic::P, + femtobase::dynamic::Px, + femtobase::dynamic::Py, + femtobase::dynamic::Pz, + femtobase::dynamic::Theta); +using FSigmas = FSigmas_002; DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaMasks_001, "FSIGMAMASKS", 1, femtokinks::Mask); diff --git a/PWGCF/Femto/TableProducer/CMakeLists.txt b/PWGCF/Femto/TableProducer/CMakeLists.txt index fc9a5f82013..666b21a839c 100644 --- a/PWGCF/Femto/TableProducer/CMakeLists.txt +++ b/PWGCF/Femto/TableProducer/CMakeLists.txt @@ -18,3 +18,8 @@ o2physics_add_dpl_workflow(femto-producer-derived-to-derived SOURCES ./femtoProducerDerivedToDerived.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-producer-kink-pt-converter + SOURCES ./femtoProducerKinkPtConverter.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/Femto/TableProducer/femtoProducerKinkPtConverter.cxx b/PWGCF/Femto/TableProducer/femtoProducerKinkPtConverter.cxx new file mode 100644 index 00000000000..5b6c054e549 --- /dev/null +++ b/PWGCF/Femto/TableProducer/femtoProducerKinkPtConverter.cxx @@ -0,0 +1,89 @@ +// Copyright 2019-2025 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 femtoProducerKinkPtConverter.cxx +/// \brief Task that converts FSigmas_001 to FSigmas_002 with recalculated pT +/// \author Henrik Fribert, TU München, henrik.fribert@tum.de + +#include "PWGCF/Femto/Core/femtoUtils.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include + +using namespace o2::analysis::femto; + +struct FemtoProducerKinkPtConverter { + + o2::framework::Produces producedSigmas; + + o2::framework::Configurable confUseRecalculatedPt{"confUseRecalculatedPt", true, "Use recalculated pT from kinematic constraints"}; + + o2::framework::HistogramRegistry mHistogramRegistry{"FemtoSigmaConverter", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + mHistogramRegistry.add("hPtOriginal", "Original pT;p_{T} (GeV/c);Counts", o2::framework::kTH1F, {{100, 0, 10}}); + mHistogramRegistry.add("hPtRecalculated", "Recalculated pT;p_{T} (GeV/c);Counts", o2::framework::kTH1F, {{100, 0, 10}}); + mHistogramRegistry.add("hPtRatio", "pT Ratio (recalc/orig);p_{T,recalc} / p_{T,orig};Counts", o2::framework::kTH1F, {{200, 0, 2}}); + mHistogramRegistry.add("hRecalcSuccess", "Recalculation Success;Success (0=fail, 1=success);Counts", o2::framework::kTH1I, {{2, -0.5, 1.5}}); + } + + void process(o2::aod::FSigmas_001 const& sigmasV1, + o2::aod::FTracks const& tracks) + { + for (const auto& sigma : sigmasV1) { + + float signedPtToUse = sigma.signedPt(); + + if (confUseRecalculatedPt) { + auto chaDaughter = tracks.rawIteratorAt(sigma.chaDauId() - tracks.offset()); + + float pxDaug = chaDaughter.pt() * std::cos(chaDaughter.phi()); + float pyDaug = chaDaughter.pt() * std::sin(chaDaughter.phi()); + float pzDaug = chaDaughter.pt() * std::sinh(chaDaughter.eta()); + + float pxMoth = sigma.pt() * std::cos(sigma.phi()); + float pyMoth = sigma.pt() * std::sin(sigma.phi()); + float pzMoth = sigma.pt() * std::sinh(sigma.eta()); + + float ptRecalc = utils::calcPtnew(pxMoth, pyMoth, pzMoth, pxDaug, pyDaug, pzDaug); + + if (ptRecalc > 0) { + signedPtToUse = ptRecalc * utils::signum(sigma.signedPt()); + + mHistogramRegistry.fill(HIST("hPtOriginal"), sigma.pt()); + mHistogramRegistry.fill(HIST("hPtRecalculated"), ptRecalc); + mHistogramRegistry.fill(HIST("hPtRatio"), ptRecalc / sigma.pt()); + mHistogramRegistry.fill(HIST("hRecalcSuccess"), 1); + } else { + mHistogramRegistry.fill(HIST("hRecalcSuccess"), 0); + } + } + + producedSigmas(sigma.fColId(), + signedPtToUse, + sigma.eta(), + sigma.phi(), + sigma.mass(), + sigma.chaDauId()); + } + } +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) +{ + o2::framework::WorkflowSpec workflow{adaptAnalysisTask(cfgc)}; + return workflow; +} From 9881d50cae1e03378f576ebac43e864b897d337f Mon Sep 17 00:00:00 2001 From: Henrik Fribert Date: Tue, 17 Feb 2026 14:42:57 +0100 Subject: [PATCH 5/5] Feature: Added 2D histogram --- .../femtoProducerKinkPtConverter.cxx | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/PWGCF/Femto/TableProducer/femtoProducerKinkPtConverter.cxx b/PWGCF/Femto/TableProducer/femtoProducerKinkPtConverter.cxx index 5b6c054e549..e8642fe53a4 100644 --- a/PWGCF/Femto/TableProducer/femtoProducerKinkPtConverter.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducerKinkPtConverter.cxx @@ -29,15 +29,21 @@ struct FemtoProducerKinkPtConverter { o2::framework::Produces producedSigmas; o2::framework::Configurable confUseRecalculatedPt{"confUseRecalculatedPt", true, "Use recalculated pT from kinematic constraints"}; + o2::framework::Configurable confFill1DHistos{"confFill1DHistos", true, "Fill 1D histograms"}; + o2::framework::Configurable confFill2DHistos{"confFill2DHistos", true, "Fill 2D histograms"}; o2::framework::HistogramRegistry mHistogramRegistry{"FemtoSigmaConverter", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; void init(o2::framework::InitContext&) { - mHistogramRegistry.add("hPtOriginal", "Original pT;p_{T} (GeV/c);Counts", o2::framework::kTH1F, {{100, 0, 10}}); - mHistogramRegistry.add("hPtRecalculated", "Recalculated pT;p_{T} (GeV/c);Counts", o2::framework::kTH1F, {{100, 0, 10}}); - mHistogramRegistry.add("hPtRatio", "pT Ratio (recalc/orig);p_{T,recalc} / p_{T,orig};Counts", o2::framework::kTH1F, {{200, 0, 2}}); - mHistogramRegistry.add("hRecalcSuccess", "Recalculation Success;Success (0=fail, 1=success);Counts", o2::framework::kTH1I, {{2, -0.5, 1.5}}); + if (confFill1DHistos) { + mHistogramRegistry.add("hPtOriginal", "Original pT;p_{T} (GeV/c);Counts", o2::framework::kTH1F, {{100, 0, 10}}); + mHistogramRegistry.add("hPtRecalculated", "Recalculated pT;p_{T} (GeV/c);Counts", o2::framework::kTH1F, {{100, 0, 10}}); + mHistogramRegistry.add("hRecalcSuccess", "Recalculation Success;Success (0=fail, 1=success);Counts", o2::framework::kTH1I, {{2, -0.5, 1.5}}); + } + if (confFill2DHistos) { + mHistogramRegistry.add("hPtOriginalVsRecalculated", "Original vs Recalculated pT;p_{T,orig} (GeV/c);p_{T,recalc} (GeV/c)", o2::framework::kTH2F, {{100, 0, 10}, {100, 0, 10}}); + } } void process(o2::aod::FSigmas_001 const& sigmasV1, @@ -60,15 +66,24 @@ struct FemtoProducerKinkPtConverter { float ptRecalc = utils::calcPtnew(pxMoth, pyMoth, pzMoth, pxDaug, pyDaug, pzDaug); - if (ptRecalc > 0) { - signedPtToUse = ptRecalc * utils::signum(sigma.signedPt()); + ROOT::Math::PtEtaPhiMVector recalcVec(ptRecalc, sigma.eta(), sigma.phi(), sigma.mass()); + float ptFrom4Vec = recalcVec.Pt(); + + if (ptFrom4Vec > 0) { + signedPtToUse = ptFrom4Vec * utils::signum(sigma.signedPt()); - mHistogramRegistry.fill(HIST("hPtOriginal"), sigma.pt()); - mHistogramRegistry.fill(HIST("hPtRecalculated"), ptRecalc); - mHistogramRegistry.fill(HIST("hPtRatio"), ptRecalc / sigma.pt()); - mHistogramRegistry.fill(HIST("hRecalcSuccess"), 1); + if (confFill1DHistos) { + mHistogramRegistry.fill(HIST("hPtOriginal"), sigma.pt()); + mHistogramRegistry.fill(HIST("hPtRecalculated"), ptFrom4Vec); + mHistogramRegistry.fill(HIST("hRecalcSuccess"), 1); + } + if (confFill2DHistos) { + mHistogramRegistry.fill(HIST("hPtOriginalVsRecalculated"), sigma.pt(), ptFrom4Vec); + } } else { - mHistogramRegistry.fill(HIST("hRecalcSuccess"), 0); + if (confFill1DHistos) { + mHistogramRegistry.fill(HIST("hRecalcSuccess"), 0); + } } }