From 0895ccf6972b15af0494f0f3c3441bdcf5508615 Mon Sep 17 00:00:00 2001 From: Henrik Fribert Date: Thu, 6 Aug 2026 17:05:09 +0200 Subject: [PATCH] sigmaplus-pcm-tables --- PWGLF/DataModel/LFKinkDecayTables.h | 34 +++++++++++++- .../Strangeness/sigmaplusbuilder.cxx | 47 ++++++++++++++----- 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/PWGLF/DataModel/LFKinkDecayTables.h b/PWGLF/DataModel/LFKinkDecayTables.h index 04dfc2f721f..0b9137d64b1 100644 --- a/PWGLF/DataModel/LFKinkDecayTables.h +++ b/PWGLF/DataModel/LFKinkDecayTables.h @@ -166,7 +166,9 @@ DECLARE_SOA_COLUMN(XDecVtx, xDecVtx, float); //! Decay vertex of t DECLARE_SOA_COLUMN(YDecVtx, yDecVtx, float); //! Decay vertex of the candidate (y direction) DECLARE_SOA_COLUMN(ZDecVtx, zDecVtx, float); //! Decay vertex of the candidate (z direction) DECLARE_SOA_COLUMN(Radius, radius, float); //! Decay radius of the candidate (cm) +DECLARE_SOA_COLUMN(FlightDistance, flightDistance, float); //! Flight distance of the candidate (PV to decay vertex, cm) DECLARE_SOA_COLUMN(DcaProtonGamma, dcaProtonGamma, float); //! DCA between proton and photon at the fitted vertex (cm) +DECLARE_SOA_COLUMN(Chi2, chi2, float); //! chi2 of the proton-photon vertex fit DECLARE_SOA_COLUMN(PxProton, pxProton, float); //! Px of the proton DECLARE_SOA_COLUMN(PyProton, pyProton, float); //! Py of the proton @@ -183,6 +185,24 @@ DECLARE_SOA_COLUMN(NSigmaTOFProton, nSigmaTOFProton, float); //! TOF nSigma of t DECLARE_SOA_COLUMN(NSigmaTPCElPos, nSigmaTPCElPos, float); //! TPC nSigma_el of the photon's positive daughter DECLARE_SOA_COLUMN(NSigmaTPCElNeg, nSigmaTPCElNeg, float); //! TPC nSigma_el of the photon's negative daughter +DECLARE_SOA_COLUMN(PhotonMass, photonMass, float); //! Invariant mass of the measured photon (V0) candidate (GeV/c^2) +DECLARE_SOA_COLUMN(PhotonAlpha, photonAlpha, float); //! Armenteros-Podolanski alpha of the measured photon +DECLARE_SOA_COLUMN(PhotonQt, photonQt, float); //! Armenteros-Podolanski qT of the measured photon (GeV/c) +DECLARE_SOA_COLUMN(PhotonConvRadius, photonConvRadius, float); //! Conversion radius of the measured photon (cm) +DECLARE_SOA_COLUMN(PhotonOpeningAngle, photonOpeningAngle, float); //! Opening angle between the photon's e+e- daughters (rad) +DECLARE_SOA_COLUMN(PhotonPointingAngle, photonPointingAngle, float); //! Angle between the photon momentum and the line from its conversion point to the candidate decay vertex (rad) +DECLARE_SOA_COLUMN(PhotonDcaToPV, photonDcaToPV, float); //! DCA of the photon's flight line to the primary vertex (cm) + +DECLARE_SOA_COLUMN(ProtonItsNCls, protonItsNCls, uint8_t); //! Number of ITS clusters of the proton track +DECLARE_SOA_COLUMN(ProtonTpcNCls, protonTpcNCls, int16_t); //! Number of found TPC clusters of the proton track +DECLARE_SOA_COLUMN(ProtonDcaXY, protonDcaXY, float); //! DCA of the proton track to the primary vertex, xy (cm) +DECLARE_SOA_COLUMN(ProtonDcaZ, protonDcaZ, float); //! DCA of the proton track to the primary vertex, z (cm) + +DECLARE_SOA_COLUMN(PhotonPosItsNCls, photonPosItsNCls, uint8_t); //! Number of ITS clusters of the photon's positive daughter +DECLARE_SOA_COLUMN(PhotonPosTpcNCls, photonPosTpcNCls, int16_t); //! Number of found TPC clusters of the photon's positive daughter +DECLARE_SOA_COLUMN(PhotonNegItsNCls, photonNegItsNCls, uint8_t); //! Number of ITS clusters of the photon's negative daughter +DECLARE_SOA_COLUMN(PhotonNegTpcNCls, photonNegTpcNCls, int16_t); //! Number of found TPC clusters of the photon's negative daughter + // MC columns DECLARE_SOA_COLUMN(IsSignal, isSignal, bool); //! True if proton and photon are MC-truth matched to the same Sigma+ @@ -228,12 +248,17 @@ DECLARE_SOA_DYNAMIC_COLUMN(MassSigmaPlus, massSigmaPlus, //! Invariant mass of t DECLARE_SOA_TABLE(SigmaPlusCands, "AOD", "SIGMAPLUSCANDS", sigmapluscand::XDecVtx, sigmapluscand::YDecVtx, sigmapluscand::ZDecVtx, - sigmapluscand::Radius, sigmapluscand::DcaProtonGamma, + sigmapluscand::Radius, sigmapluscand::FlightDistance, + sigmapluscand::DcaProtonGamma, sigmapluscand::Chi2, sigmapluscand::PxProton, sigmapluscand::PyProton, sigmapluscand::PzProton, sigmapluscand::PxGamma1, sigmapluscand::PyGamma1, sigmapluscand::PzGamma1, sigmapluscand::PxGamma2, sigmapluscand::PyGamma2, sigmapluscand::PzGamma2, sigmapluscand::NSigmaTPCProton, sigmapluscand::NSigmaTOFProton, sigmapluscand::NSigmaTPCElPos, sigmapluscand::NSigmaTPCElNeg, + sigmapluscand::PhotonMass, sigmapluscand::PhotonAlpha, sigmapluscand::PhotonQt, sigmapluscand::PhotonConvRadius, + sigmapluscand::PhotonOpeningAngle, sigmapluscand::PhotonPointingAngle, sigmapluscand::PhotonDcaToPV, + sigmapluscand::ProtonItsNCls, sigmapluscand::ProtonTpcNCls, sigmapluscand::ProtonDcaXY, sigmapluscand::ProtonDcaZ, + sigmapluscand::PhotonPosItsNCls, sigmapluscand::PhotonPosTpcNCls, sigmapluscand::PhotonNegItsNCls, sigmapluscand::PhotonNegTpcNCls, // dynamic columns sigmapluscand::PxSigmaPlus, @@ -244,12 +269,17 @@ DECLARE_SOA_TABLE(SigmaPlusCands, "AOD", "SIGMAPLUSCANDS", DECLARE_SOA_TABLE(SigmaPlusCandsMC, "AOD", "SIGMAPLUSMC", sigmapluscand::XDecVtx, sigmapluscand::YDecVtx, sigmapluscand::ZDecVtx, - sigmapluscand::Radius, sigmapluscand::DcaProtonGamma, + sigmapluscand::Radius, sigmapluscand::FlightDistance, + sigmapluscand::DcaProtonGamma, sigmapluscand::Chi2, sigmapluscand::PxProton, sigmapluscand::PyProton, sigmapluscand::PzProton, sigmapluscand::PxGamma1, sigmapluscand::PyGamma1, sigmapluscand::PzGamma1, sigmapluscand::PxGamma2, sigmapluscand::PyGamma2, sigmapluscand::PzGamma2, sigmapluscand::NSigmaTPCProton, sigmapluscand::NSigmaTOFProton, sigmapluscand::NSigmaTPCElPos, sigmapluscand::NSigmaTPCElNeg, + sigmapluscand::PhotonMass, sigmapluscand::PhotonAlpha, sigmapluscand::PhotonQt, sigmapluscand::PhotonConvRadius, + sigmapluscand::PhotonOpeningAngle, sigmapluscand::PhotonPointingAngle, sigmapluscand::PhotonDcaToPV, + sigmapluscand::ProtonItsNCls, sigmapluscand::ProtonTpcNCls, sigmapluscand::ProtonDcaXY, sigmapluscand::ProtonDcaZ, + sigmapluscand::PhotonPosItsNCls, sigmapluscand::PhotonPosTpcNCls, sigmapluscand::PhotonNegItsNCls, sigmapluscand::PhotonNegTpcNCls, sigmapluscand::IsSignal, sigmapluscand::ProtonPdgCode, sigmapluscand::ProtonMotherPdgCode, sigmapluscand::GammaPdgCode, sigmapluscand::GammaMotherPdgCode, sigmapluscand::GammaGMotherPdgCode, diff --git a/PWGLF/TableProducer/Strangeness/sigmaplusbuilder.cxx b/PWGLF/TableProducer/Strangeness/sigmaplusbuilder.cxx index b7efe3f8a12..cbd28655b99 100644 --- a/PWGLF/TableProducer/Strangeness/sigmaplusbuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/sigmaplusbuilder.cxx @@ -20,6 +20,7 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" #include #include @@ -47,7 +48,7 @@ using namespace o2; using namespace o2::framework; -using TracksFull = soa::Join; using TracksFullMC = soa::Join; using CollisionsFull = aod::Collisions; @@ -56,7 +57,7 @@ using CollisionsFullMC = soa::Join; struct Sigmaplusbuilder { // photon (PCM) selection - Configurable photonMaxMass{"photonMaxMass", 0.10, "Max photon mass (GeV/c^2)"}; + Configurable photonMaxMass{"photonMaxMass", 0.20, "Max photon mass (GeV/c^2)"}; Configurable photonMinRapidity{"photonMinRapidity", -0.8, "Min photon rapidity"}; Configurable photonMaxRapidity{"photonMaxRapidity", 0.8, "Max photon rapidity"}; Configurable photonDauEtaMin{"photonDauEtaMin", -0.8, "Min eta of photon daughter tracks"}; @@ -65,9 +66,9 @@ struct Sigmaplusbuilder { Configurable photonMaxRadius{"photonMaxRadius", 115., "Max photon conversion radius (cm)"}; Configurable photonMinV0cospa{"photonMinV0cospa", 0.80, "Min V0 CosPA"}; Configurable photonMaxDCAV0Dau{"photonMaxDCAV0Dau", 3.5, "Max DCA between photon daughters (cm)"}; - Configurable photonMaxQt{"photonMaxQt", 0.08, "Max Armenteros qT for photons (GeV/c)"}; + Configurable photonMaxQt{"photonMaxQt", 0.15, "Max Armenteros qT for photons (GeV/c)"}; Configurable photonMaxAlpha{"photonMaxAlpha", 1.0, "Max |Armenteros alpha| for photons"}; - Configurable photonMaxTPCNSigmaEl{"photonMaxTPCNSigmaEl", 7, "Max |TPC nSigma_el| for photon daughters"}; + Configurable photonMaxTPCNSigmaEl{"photonMaxTPCNSigmaEl", 15, "Max |TPC nSigma_el| for photon daughters"}; // proton selection Configurable protonMinPt{"protonMinPt", 0.3, "Minimum proton pT (GeV/c)"}; @@ -279,10 +280,6 @@ struct Sigmaplusbuilder { auto posTrack = v0.template posTrack_as(); auto negTrack = v0.template negTrack_as(); - // true if this V0's legs genuinely share a gamma mother whose mother is a - // pi0 whose mother is a Sigma+ -- regardless of whether it passes the - // selection below. Lets us see exactly which cut, if any, throws away - // genuine Sigma+ photons, instead of only knowing the final accept/reject. bool isSignal = false; if constexpr (IsMC) { if (posTrack.has_mcParticle() && negTrack.has_mcParticle()) { @@ -557,7 +554,8 @@ struct Sigmaplusbuilder { } fillCandStep(1); // Vertex fit - float dcaProtonGamma = std::sqrt(fitter.getChi2AtPCACandidate()); + float fitChi2 = fitter.getChi2AtPCACandidate(); + float dcaProtonGamma = std::sqrt(fitChi2); histos.fill(HIST("Candidate/hDcaProtonGamma"), dcaProtonGamma); if constexpr (IsMC) { if (isSignal) { @@ -587,6 +585,7 @@ struct Sigmaplusbuilder { // flight direction n and the decay-plane basis n, eIn, eOut std::array flightVec{secVtx[0] - pv[0], secVtx[1] - pv[1], secVtx[2] - pv[2]}; std::array nHat = normalize3(flightVec); + float flightDistance = std::sqrt(dot3(flightVec, flightVec)); std::array pProton; std::array pGamma1; @@ -725,14 +724,34 @@ struct Sigmaplusbuilder { } fillCandStep(6); // filled + // photon (V0) opening angle: angle between the e+/e- daughter momenta at their own reference point + std::array pPosDau{posTrack.px(), posTrack.py(), posTrack.pz()}; + std::array pNegDau{negTrack.px(), negTrack.py(), negTrack.pz()}; + float photonOpeningAngle = std::acos(std::clamp(dot3(pPosDau, pNegDau) / std::sqrt(dot3(pPosDau, pPosDau) * dot3(pNegDau, pNegDau)), -1.f, 1.f)); + + // photon pointing angle: angle between the fitted photon momentum and the line from its conversion point to the p-gamma decay vertex + std::array convToDecVtx{secVtx[0] - photon.x(), secVtx[1] - photon.y(), secVtx[2] - photon.z()}; + float photonPointingAngle = std::acos(std::clamp(dot3(pGamma1, convToDecVtx) / std::sqrt(dot3(pGamma1, pGamma1) * dot3(convToDecVtx, convToDecVtx)), -1.f, 1.f)); + + // photon DCA to PV: distance from the PV to the line through the conversion point along the photon momentum direction + std::array convPoint{photon.x(), photon.y(), photon.z()}; + std::array photonDir = normalize3({photon.px(), photon.py(), photon.pz()}); + std::array pvToConv{pv[0] - convPoint[0], pv[1] - convPoint[1], pv[2] - convPoint[2]}; + std::array pvToConvCrossDir = cross3(pvToConv, photonDir); + float photonDcaToPV = std::sqrt(dot3(pvToConvCrossDir, pvToConvCrossDir)); + if constexpr (IsMC) { sigmaPlusCandsMC(secVtx[0], secVtx[1], secVtx[2], - radius, dcaProtonGamma, + radius, flightDistance, dcaProtonGamma, fitChi2, pProton[0], pProton[1], pProton[2], pGamma1[0], pGamma1[1], pGamma1[2], bestMomGamma2[0], bestMomGamma2[1], bestMomGamma2[2], protonTrack.tpcNSigmaPr(), protonTrack.tofNSigmaPr(), posTrack.tpcNSigmaEl(), negTrack.tpcNSigmaEl(), + photon.mGamma(), photon.alpha(), photon.qtarm(), photon.v0radius(), + photonOpeningAngle, photonPointingAngle, photonDcaToPV, + protonTrack.itsNCls(), protonTrack.tpcNClsFound(), protonTrack.dcaXY(), protonTrack.dcaZ(), + posTrack.itsNCls(), posTrack.tpcNClsFound(), negTrack.itsNCls(), negTrack.tpcNClsFound(), isSignal, protonPdgCode, protonMotherPdgCode, gammaPdgCode, gammaMotherPdgCode, gammaGMotherPdgCode, @@ -741,12 +760,16 @@ struct Sigmaplusbuilder { mcTrueMomGamma[0], mcTrueMomGamma[1], mcTrueMomGamma[2]); } else { sigmaPlusCands(secVtx[0], secVtx[1], secVtx[2], - radius, dcaProtonGamma, + radius, flightDistance, dcaProtonGamma, fitChi2, pProton[0], pProton[1], pProton[2], pGamma1[0], pGamma1[1], pGamma1[2], bestMomGamma2[0], bestMomGamma2[1], bestMomGamma2[2], protonTrack.tpcNSigmaPr(), protonTrack.tofNSigmaPr(), - posTrack.tpcNSigmaEl(), negTrack.tpcNSigmaEl()); + posTrack.tpcNSigmaEl(), negTrack.tpcNSigmaEl(), + photon.mGamma(), photon.alpha(), photon.qtarm(), photon.v0radius(), + photonOpeningAngle, photonPointingAngle, photonDcaToPV, + protonTrack.itsNCls(), protonTrack.tpcNClsFound(), protonTrack.dcaXY(), protonTrack.dcaZ(), + posTrack.itsNCls(), posTrack.tpcNClsFound(), negTrack.itsNCls(), negTrack.tpcNClsFound()); } }