From c5d18d8c7e9f78086adc2e4cc8b69bb65b3367b4 Mon Sep 17 00:00:00 2001 From: Henrik Fribert Date: Mon, 9 Nov 2026 14:45:14 +0100 Subject: [PATCH 1/3] Fix wrong phi calculation for Sigmas --- PWGCF/Femto/Core/femtoUtils.h | 18 ++++++ PWGCF/Femto/TableProducer/femtoProducer.cxx | 64 ++++++++++++++++++++- 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/PWGCF/Femto/Core/femtoUtils.h b/PWGCF/Femto/Core/femtoUtils.h index 22dc4fa37e9..d4816a882e6 100644 --- a/PWGCF/Femto/Core/femtoUtils.h +++ b/PWGCF/Femto/Core/femtoUtils.h @@ -18,6 +18,7 @@ #include "Common/Core/TableHelper.h" +#include #include #include #include @@ -173,6 +174,23 @@ concept HasEventShapeRow = requires(T row) { template concept HasEventShape = HasEventShapeRow> || (requires { typename std::decay_t::iterator; } && HasEventShapeRow::iterator>); +/// Azimuth of the momentum of a charged particle at the primary vertex, from its azimuth at the decay vertex. +/// The decay vertex (xDecay, yDecay) has to be given relative to the primary vertex. In a solenoidal field the transverse +/// trajectory is a circle through both points, and the tangents at the two ends of a chord make the same angle with it: +/// phiPV = 2*phiChord - phiDecay (independent of polarity). +inline float phiAtPrimaryVertex(float phiDecay, float xDecay, float yDecay) +{ + constexpr float TwoPi = o2::constants::math::TwoPI; + if (xDecay == 0.f && yDecay == 0.f) { + return phiDecay; + } + float phi = std::fmod(2.f * std::atan2(yDecay, xDecay) - phiDecay, TwoPi); + if (phi < 0.f) { + phi += TwoPi; + } + return phi; +} + /// Recalculate the pT of a kink mother from its direction and the charged daughter momentum inline float calcPtnew(float pxMother, float pyMother, float pzMother, float pxDaughter, float pyDaughter, float pzDaughter, float massMother, float massChargedDaughter, float massNeutralDaughter) diff --git a/PWGCF/Femto/TableProducer/femtoProducer.cxx b/PWGCF/Femto/TableProducer/femtoProducer.cxx index 711183d7327..7ca55f69bed 100644 --- a/PWGCF/Femto/TableProducer/femtoProducer.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducer.cxx @@ -270,11 +270,13 @@ struct FemtoProducer { } if ((builders.sigmaBuilder.fillAnyTable() || builders.sigmaPlusBuilder.fillAnyTable()) && (!doprocessTracksKinksRun3pp && !doprocessTracksV0sCascadesKinksRun3pp && !doprocessTracksV0sCascadesKinksPhotonsRun3pp && - !doprocessTracksKinksRun3ppMc && !doprocessTracksV0sKinksRun3ppMc)) { + !doprocessTracksKinksRun3ppMc && !doprocessTracksV0sKinksRun3ppMc && + !doprocessTracksKinksSigmaPlusPcmsRun3pp && !doprocessTracksKinksSigmaPlusPcmsRun3ppMc)) { LOG(fatal) << "At least one kink table is enabled, but wrong process function is enabled. Breaking..."; } if (builders.sigmaPlusPcmBuilder.fillAnyTable() && - (!doprocessTracksSigmaPlusPcmsRun3pp && !doprocessTracksSigmaPlusPcmsRun3ppMc)) { + (!doprocessTracksSigmaPlusPcmsRun3pp && !doprocessTracksSigmaPlusPcmsRun3ppMc && + !doprocessTracksKinksSigmaPlusPcmsRun3pp && !doprocessTracksKinksSigmaPlusPcmsRun3ppMc)) { LOG(fatal) << "At least one sigma plus (PCM) table is enabled, but wrong process function is enabled. Breaking..."; } if ((builders.d0Builder.fillAnyTable() || builders.d0barBuilder.fillAnyTable()) && @@ -292,7 +294,7 @@ struct FemtoProducer { !doprocessTracksV0sRun3ppMc && !doprocessTracksV0sRun3PbPbMc && !doprocessTracksV0sCascadesRun3ppMc && !doprocessTracksV0sCascadesRun3PbPbMc && !doprocessTracksKinksRun3ppMc && !doprocessTracksV0sKinksRun3ppMc && - !doprocessTracksSigmaPlusPcmsRun3ppMc && + !doprocessTracksSigmaPlusPcmsRun3ppMc && !doprocessTracksKinksSigmaPlusPcmsRun3ppMc && !doprocessTracksD0sRun3ppMc && !doprocessTracksD0sRun3PbPbMc && !doprocessTracksLcsRun3ppMc && !doprocessTracksLcsRun3PbPbMc && !doprocessMcOnly)) { @@ -379,6 +381,7 @@ struct FemtoProducer { static_cast(doprocessTracksV0sCascadesKinksRun3pp) + static_cast(doprocessTracksV0sCascadesKinksPhotonsRun3pp) + static_cast(doprocessTracksSigmaPlusPcmsRun3pp) + + static_cast(doprocessTracksKinksSigmaPlusPcmsRun3pp) + static_cast(doprocessTracksD0sRun3pp) + static_cast(doprocessTracksD0sRun3PbPb) + static_cast(doprocessTracksRun3ppMc) + @@ -390,6 +393,7 @@ struct FemtoProducer { static_cast(doprocessTracksKinksRun3ppMc) + static_cast(doprocessTracksV0sKinksRun3ppMc) + static_cast(doprocessTracksSigmaPlusPcmsRun3ppMc) + + static_cast(doprocessTracksKinksSigmaPlusPcmsRun3ppMc) + static_cast(doprocessTracksD0sRun3ppMc) + static_cast(doprocessTracksD0sRun3PbPbMc) + static_cast(doprocessTracksLcsRun3pp) + @@ -833,6 +837,29 @@ struct FemtoProducer { } PROCESS_SWITCH(FemtoProducer, processTracksSigmaPlusPcmsRun3pp, "Provide tracks and sigma plus reconstructed with a PCM photon", false); + void processTracksKinksSigmaPlusPcmsRun3pp(rawinputs::Run3PpCollisions const& cols, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3FullPidTracks const& tracks, + rawinputs::Run3Kinks const& kinks, + rawinputs::Run3SigmaPlusPcms const& sigmaPlusPcms) + { + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto kinksThisCol = kinks.sliceBy(preslices.perColRecoKinks, col.globalIndex()); + processKinks(col, tracksThisCol, kinksThisCol); + auto sigmaPlusPcmsThisCol = sigmaPlusPcms.sliceBy(preslices.perColSigmaPlusPcms, col.globalIndex()); + processSigmaPlusPcms(col, tracksThisCol, sigmaPlusPcmsThisCol); + } + } + PROCESS_SWITCH(FemtoProducer, processTracksKinksSigmaPlusPcmsRun3pp, "Provide tracks, kinks and sigma plus reconstructed with a PCM photon", false); + void processTracksV0sCascadesKinksRun3pp(rawinputs::Run3PpCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, @@ -1168,6 +1195,37 @@ struct FemtoProducer { } PROCESS_SWITCH(FemtoProducer, processTracksSigmaPlusPcmsRun3ppMc, "Provide reconstructed and generated tracks and sigma plus reconstructed with a PCM photon", false); + void processTracksKinksSigmaPlusPcmsRun3ppMc(rawinputs::Run3PpMcGenCollisions const& mcCols, + rawinputs::Run3PpMcRecoCollisions const& cols, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3McRecoTracks const& tracks, + rawinputs::Run3Kinks const& kinks, + rawinputs::Run3RecoSigmaPlusPcms const& sigmaPlusPcms, + rawinputs::Run3McGenParticles const& mcParticles) + { + builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); + if (builders.mcBuilder.isPassThrough()) { + builders.mcBuilder.fillMcPassThrough(mcCols, mcParticles, preslices.perMcCollision, mcProducts); + } + + for (const auto& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColRecoTracks, col.globalIndex()); + if (!processMcCollisions(col, mcCols, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processMcTracks(col, mcCols, tracksThisCol, tracksWithItsPid, mcParticles); + + auto kinksThisCol = kinks.sliceBy(preslices.perColRecoKinks, col.globalIndex()); + processMcKinks(col, mcCols, tracks, kinksThisCol, mcParticles); + auto sigmaPlusPcmsThisCol = sigmaPlusPcms.sliceBy(preslices.perColRecoSigmaPlusPcms, col.globalIndex()); + processMcSigmaPlusPcms(col, mcCols, tracks, sigmaPlusPcmsThisCol, mcParticles); + } + } + PROCESS_SWITCH(FemtoProducer, processTracksKinksSigmaPlusPcmsRun3ppMc, "Provide reconstructed and generated tracks, kinks and sigma plus reconstructed with a PCM photon", false); + void processTracksV0sKinksRun3ppMc(rawinputs::Run3PpMcGenCollisions const& mcCols, rawinputs::Run3PpMcRecoCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, From 5b0caceb3d6bace80eb893108d1c15e3507d58f2 Mon Sep 17 00:00:00 2001 From: Henrik Fribert Date: Mon, 9 Nov 2026 14:50:44 +0100 Subject: [PATCH 2/3] Include kinkBuilder.h changes --- PWGCF/Femto/Core/kinkBuilder.h | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/PWGCF/Femto/Core/kinkBuilder.h b/PWGCF/Femto/Core/kinkBuilder.h index 34728fbdcec..a56f5b0ac28 100644 --- a/PWGCF/Femto/Core/kinkBuilder.h +++ b/PWGCF/Femto/Core/kinkBuilder.h @@ -53,6 +53,7 @@ struct ConfKinkFilters : o2::framework::ConfigurableGroup { o2::framework::Configurable etaMax{"etaMax", 10.f, "Maximum eta"}; o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; + o2::framework::Configurable kinkPhiAtPv{"kinkPhiAtPv", true, "Kinks and PCM SigmaPlus: store the azimuth of the Sigma momentum at the primary vertex"}; o2::framework::Configurable massMinSigma{"massMinSigma", 1.1f, "Minimum mass for Sigma hypothesis"}; o2::framework::Configurable massMaxSigma{"massMaxSigma", 1.3f, "Maximum mass for Sigma hypothesis"}; o2::framework::Configurable massMinSigmaPlus{"massMinSigmaPlus", 1.1f, "Minimum mass for SigmaPlus hypothesis"}; @@ -272,6 +273,7 @@ class KinkSelection : public baseselection::BaseSelection - void computeKinematics(T const& sigmaPlusPcmCand) + template + void computeKinematics(T1 const& sigmaPlusPcmCand, T2 const& col) { std::array momMother = {sigmaPlusPcmCand.pxSigmaPlus(), sigmaPlusPcmCand.pySigmaPlus(), sigmaPlusPcmCand.pzSigmaPlus()}; mPt = RecoDecay::pt(momMother); mEta = RecoDecay::eta(momMother); mPhi = RecoDecay::phi(momMother); + if (mPhiAtPv) { + mPhi = utils::phiAtPrimaryVertex(mPhi, sigmaPlusPcmCand.xDecVtx() - col.posX(), sigmaPlusPcmCand.yDecVtx() - col.posY()); + } mMass = sigmaPlusPcmCand.massSigmaPlus(); mMlScore = sigmaPlusPcmCand.mlScore(); } @@ -951,6 +961,7 @@ class SigmaPlusPcmSelection : public baseselection::BaseSelection Date: Mon, 9 Nov 2026 15:16:43 +0100 Subject: [PATCH 3/3] Fix: Use epsilon and reco decay + add PhiAtPv in KinkFilters --- PWGCF/Femto/Core/femtoUtils.h | 10 +++------- PWGCF/Femto/Core/kinkBuilder.h | 9 +++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/PWGCF/Femto/Core/femtoUtils.h b/PWGCF/Femto/Core/femtoUtils.h index d4816a882e6..9b9c16c4884 100644 --- a/PWGCF/Femto/Core/femtoUtils.h +++ b/PWGCF/Femto/Core/femtoUtils.h @@ -16,6 +16,7 @@ #ifndef PWGCF_FEMTO_CORE_FEMTOUTILS_H_ #define PWGCF_FEMTO_CORE_FEMTOUTILS_H_ +#include "Common/Core/RecoDecay.h" #include "Common/Core/TableHelper.h" #include @@ -180,15 +181,10 @@ concept HasEventShape = HasEventShapeRow> || (requires { typenam /// phiPV = 2*phiChord - phiDecay (independent of polarity). inline float phiAtPrimaryVertex(float phiDecay, float xDecay, float yDecay) { - constexpr float TwoPi = o2::constants::math::TwoPI; - if (xDecay == 0.f && yDecay == 0.f) { + if (std::abs(xDecay) < o2::constants::math::Epsilon && std::abs(yDecay) < o2::constants::math::Epsilon) { return phiDecay; } - float phi = std::fmod(2.f * std::atan2(yDecay, xDecay) - phiDecay, TwoPi); - if (phi < 0.f) { - phi += TwoPi; - } - return phi; + return RecoDecay::constrainAngle(2.f * std::atan2(yDecay, xDecay) - phiDecay); } /// Recalculate the pT of a kink mother from its direction and the charged daughter momentum diff --git a/PWGCF/Femto/Core/kinkBuilder.h b/PWGCF/Femto/Core/kinkBuilder.h index a56f5b0ac28..84d518dbe15 100644 --- a/PWGCF/Femto/Core/kinkBuilder.h +++ b/PWGCF/Femto/Core/kinkBuilder.h @@ -235,6 +235,7 @@ enum KinkFilters { kPhiMax, kMassMin, kMassMax, + kPhiAtPv, kMlScoreMin, kKinkFiltersMax }; @@ -251,6 +252,7 @@ const std::unordered_map kinkFilterNames = { {kPhiMax, "phiMax"}, {kMassMin, "massMin"}, {kMassMax, "massMax"}, + {kPhiAtPv, "kinkPhiAtPv"}, {kMlScoreMin, "mlScoreMin"}}; /// \class KinkCuts @@ -319,6 +321,7 @@ class KinkSelection : public baseselection::BaseSelection(mKinkPhiAtPv)}, }); } if constexpr (modes::isEqual(kinkType, modes::Kink::kSigmaPlus)) { @@ -333,6 +336,7 @@ class KinkSelection : public baseselection::BaseSelection(mKinkPhiAtPv)}, }); } }; @@ -473,6 +477,8 @@ class KinkSelection : public baseselection::BaseSelectiontemplate fillFilter(kPhiMax, p); pass &= p; + this->template fillFilter(kPhiAtPv, mKinkPhiAtPv); + if constexpr (modes::isEqual(kinkType, modes::Kink::kSigma)) { float sigmaMass = kinkCand.mSigmaMinus(); @@ -859,6 +865,7 @@ class SigmaPlusPcmSelection : public baseselection::BaseSelection(mPhiAtPv)}, {kinkFilterNames.at(kMlScoreMin), mMlScoreMin}, }); }; @@ -907,6 +914,8 @@ class SigmaPlusPcmSelection : public baseselection::BaseSelectiontemplate fillFilter(kPhiMax, p); pass &= p; + this->template fillFilter(kPhiAtPv, mPhiAtPv); + p = mMass > mMassLowerLimit; this->template fillFilter(kMassMin, p); pass &= p;