From c9e008e5cf64e8bc7033a03356f34e3bb5216041 Mon Sep 17 00:00:00 2001 From: Francesco Mazzaschi Date: Fri, 11 Jul 2025 10:05:16 +0200 Subject: [PATCH] Add output tree to lambda1405 task --- PWGLF/DataModel/LFLambda1405Table.h | 81 +++++++++ PWGLF/Tasks/Resonances/lambda1405analysis.cxx | 171 +++++++++++++----- 2 files changed, 211 insertions(+), 41 deletions(-) create mode 100644 PWGLF/DataModel/LFLambda1405Table.h diff --git a/PWGLF/DataModel/LFLambda1405Table.h b/PWGLF/DataModel/LFLambda1405Table.h new file mode 100644 index 00000000000..704c2a78abf --- /dev/null +++ b/PWGLF/DataModel/LFLambda1405Table.h @@ -0,0 +1,81 @@ +// Copyright 2019-2020 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 LFLambda1405Tables.h +/// \brief Slim tables for Lambda(1405) candidates +/// \author Francesco Mazzaschi +/// + +#include "Common/Core/RecoDecay.h" + +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" + +#ifndef PWGLF_DATAMODEL_LFLAMBDA1405TABLES_H_ +#define PWGLF_DATAMODEL_LFLAMBDA1405TABLES_H_ + +namespace o2::aod +{ + +namespace lambda1405 +{ + +DECLARE_SOA_COLUMN(Px, px, float); //! Px of the candidate +DECLARE_SOA_COLUMN(Py, py, float); //! Py of the candidate +DECLARE_SOA_COLUMN(Pz, pz, float); //! Pz of the candidate +DECLARE_SOA_COLUMN(Mass, mass, float); //! Invariant mass of the candidate +DECLARE_SOA_COLUMN(SigmaMinusMass, sigmaMinusMass, float); //! Invariant mass of the Sigma- candidate +DECLARE_SOA_COLUMN(SigmaPlusMass, sigmaPlusMass, float); //! Invariant mass of the Sigma+ candidate +DECLARE_SOA_COLUMN(PtSigma, ptSigma, float); //! Signed pT of the Sigma daughter +DECLARE_SOA_COLUMN(AlphaAPSigma, alphaAPSigma, float); //! Alpha of the Sigma +DECLARE_SOA_COLUMN(QtAPSigma, qtAPSigma, float); //! qT of the Sigma +DECLARE_SOA_COLUMN(RadiusSigma, radiusSigma, float); //! Radius of the Sigma decay vertex +DECLARE_SOA_COLUMN(NSigmaTPCPiKink, nSigmaTPCPiKink, float); //! Number of sigmas for the pion candidate from Sigma kink in TPC +DECLARE_SOA_COLUMN(NSigmaTOFPiKink, nSigmaTOFPiKink, float); //! Number of sigmas for the pion candidate from Sigma kink in TOF +DECLARE_SOA_COLUMN(NSigmaTPCPrKink, nSigmaTPCPrKink, float); //! Number of sigmas for the proton candidate from Sigma kink in TPC +DECLARE_SOA_COLUMN(NSigmaTOFPrKink, nSigmaTOFPrKink, float); //! Number of sigmas for the proton candidate from Sigma kink in TOF +DECLARE_SOA_COLUMN(DCAKinkDauToPV, dcaKinkDauToPV, float); //! DCA of the kink daughter to the primary vertex +DECLARE_SOA_COLUMN(NSigmaTPCPiDau, nSigmaTPCPiDau, float); //! Number of sigmas for the lambda1405 pion daughter in TPC +DECLARE_SOA_COLUMN(NSigmaTOFPiDau, nSigmaTOFPiDau, float); //! Number of sigmas for the lambda1405 pion daughter in TOF + +// MC Columns +DECLARE_SOA_COLUMN(PtMC, ptMC, float); //! pT of the candidate in MC +DECLARE_SOA_COLUMN(MassMC, massMC, float); //! Invariant mass of the candidate in MC +DECLARE_SOA_COLUMN(SigmaPdgCode, sigmaPdgCode, int); //! PDG code of the Sigma daughter +DECLARE_SOA_COLUMN(KinkDauPdgCode, kinkDauPdgCode, int); //! PDG code of the kink daughter + +} // namespace lambda1405 + +DECLARE_SOA_TABLE(Lambda1405Cands, "AOD", "LAMBDA1405", + o2::soa::Index<>, + lambda1405::Px, lambda1405::Py, lambda1405::Pz, + lambda1405::Mass, lambda1405::SigmaMinusMass, lambda1405::SigmaPlusMass, + lambda1405::PtSigma, lambda1405::AlphaAPSigma, lambda1405::QtAPSigma, lambda1405::RadiusSigma, + lambda1405::NSigmaTPCPiKink, lambda1405::NSigmaTOFPiKink, + lambda1405::NSigmaTPCPrKink, lambda1405::NSigmaTOFPrKink, + lambda1405::DCAKinkDauToPV, + lambda1405::NSigmaTPCPiDau, lambda1405::NSigmaTOFPiDau); + +DECLARE_SOA_TABLE(Lambda1405CandsMC, "AOD", "MCLAMBDA1405", + o2::soa::Index<>, + lambda1405::Px, lambda1405::Py, lambda1405::Pz, + lambda1405::Mass, lambda1405::SigmaMinusMass, lambda1405::SigmaPlusMass, + lambda1405::PtSigma, lambda1405::AlphaAPSigma, lambda1405::QtAPSigma, lambda1405::RadiusSigma, + lambda1405::NSigmaTPCPiKink, lambda1405::NSigmaTOFPiKink, + lambda1405::NSigmaTPCPrKink, lambda1405::NSigmaTOFPrKink, + lambda1405::DCAKinkDauToPV, + lambda1405::NSigmaTPCPiDau, lambda1405::NSigmaTOFPiDau, + lambda1405::PtMC, lambda1405::MassMC, lambda1405::SigmaPdgCode, lambda1405::KinkDauPdgCode); + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFLAMBDA1405TABLES_H_ diff --git a/PWGLF/Tasks/Resonances/lambda1405analysis.cxx b/PWGLF/Tasks/Resonances/lambda1405analysis.cxx index e221eab6da9..fec9b582901 100644 --- a/PWGLF/Tasks/Resonances/lambda1405analysis.cxx +++ b/PWGLF/Tasks/Resonances/lambda1405analysis.cxx @@ -14,6 +14,7 @@ /// \author Francesco Mazzaschi #include "PWGLF/DataModel/LFKinkDecayTables.h" +#include "PWGLF/DataModel/LFLambda1405Table.h" #include "Common/Core/PID/PIDTOF.h" #include "Common/DataModel/EventSelection.h" @@ -33,25 +34,40 @@ using CollisionsFullMC = soa::Join outputDataTable; // Output table for Lambda(1405) candidates + Produces outputDataTableMC; // Output table for Lambda(1405) candidates in MC // Histograms are defined with HistogramRegistry HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry rLambda1405{"lambda1405", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; @@ -61,6 +77,7 @@ struct lambda1405analysis { Configurable cutDCAtoPVSigma{"cutDCAtoPVSigma", 0.1f, "Max DCA to primary vertex for Sigma candidates (cm)"}; Configurable cutDCAtoPVPiFromSigma{"cutDCAtoPVPiFromSigma", 2., "Min DCA to primary vertex for pion from Sigma candidates (cm)"}; + Configurable cutUpperMass{"cutUpperMass", 1.6f, "Upper mass cut for Lambda(1405) candidates (GeV/c^2)"}; Configurable cutSigmaRadius{"cutSigmaRadius", 20.f, "Minimum radius for Sigma candidates (cm)"}; Configurable cutSigmaMass{"cutSigmaMass", 0.1, "Sigma mass window (MeV/c^2)"}; Configurable cutNITSClusPi{"cutNITSClusPi", 5, "Minimum number of ITS clusters for pion candidate"}; @@ -68,6 +85,7 @@ struct lambda1405analysis { Configurable cutNSigmaTPC{"cutNSigmaTPC", 3, "NSigmaTPCPion"}; Configurable cutNSigmaTOF{"cutNSigmaTOF", 3, "NSigmaTOFPion"}; + Configurable fillOutputTree{"fillOutputTree", true, "If true, fill the output tree with Lambda(1405) candidates"}; Configurable doLSBkg{"doLikeSignBkg", false, "Use like-sign background"}; Configurable useTOF{"useTOF", false, "Use TOF for PID for pion candidates"}; @@ -114,6 +132,22 @@ struct lambda1405analysis { } } + float alphaAP(const std::array& momMother, const std::array& momKink) + { + std::array momMissing = {momMother[0] - momKink[0], momMother[1] - momKink[1], momMother[2] - momKink[2]}; + float lQlP = std::inner_product(momMother.begin(), momMother.end(), momKink.begin(), 0.f); + float lQlN = std::inner_product(momMother.begin(), momMother.end(), momMissing.begin(), 0.f); + return (lQlP - lQlN) / (lQlP + lQlN); + } + + float qtAP(const std::array& momMother, const std::array& momKink) + { + float dp = std::inner_product(momMother.begin(), momMother.end(), momKink.begin(), 0.f); + float p2V0 = std::inner_product(momMother.begin(), momMother.end(), momMother.begin(), 0.f); + float p2A = std::inner_product(momKink.begin(), momKink.end(), momKink.begin(), 0.f); + return std::sqrt(p2A - dp * dp / p2V0); + } + template bool selectPiTrack(const Ttrack& candidate, bool piFromSigma) { @@ -198,26 +232,42 @@ struct lambda1405analysis { continue; } } + if (!selectPiTrack(piTrack, false)) { continue; } + + auto kinkDauMom = std::array{sigmaCand.pxDaug(), sigmaCand.pyDaug(), sigmaCand.pzDaug()}; auto sigmaMom = std::array{sigmaCand.pxMoth(), sigmaCand.pyMoth(), sigmaCand.pzMoth()}; auto piMom = std::array{piTrack.px(), piTrack.py(), piTrack.pz()}; - float pt = std::hypot(sigmaMom[0] + piMom[0], sigmaMom[1] + piMom[1]); double massSigma = lambda1405Cand.isSigmaMinus ? sigmaCand.mSigmaMinus() : sigmaCand.mSigmaPlus(); float invMass = RecoDecay::m(std::array{sigmaMom, piMom}, std::array{massSigma, o2::constants::physics::MassPiPlus}); - if (invMass < 1.3 || invMass > 1.5) { + if (invMass > cutUpperMass) { continue; } + lambda1405Cand.kinkDauID = kinkDauTrack.globalIndex(); lambda1405Cand.sigmaID = sigmaCand.globalIndex(); lambda1405Cand.piID = piTrack.globalIndex(); + + lambda1405Cand.px = sigmaMom[0] + piMom[0]; + lambda1405Cand.py = sigmaMom[1] + piMom[1]; + lambda1405Cand.pz = sigmaMom[2] + piMom[2]; lambda1405Cand.mass = invMass; + lambda1405Cand.sigmaMinusMass = sigmaCand.mSigmaMinus(); lambda1405Cand.sigmaPlusMass = sigmaCand.mSigmaPlus(); lambda1405Cand.sigmaSign = sigmaCand.mothSign(); - lambda1405Cand.pt = pt; + lambda1405Cand.sigmaAlphaAP = alphaAP(sigmaMom, kinkDauMom); + lambda1405Cand.sigmaQtAP = qtAP(sigmaMom, kinkDauMom); lambda1405Cand.sigmaPt = sigmaCand.ptMoth(); + lambda1405Cand.sigmaRadius = sigmaRad; + lambda1405Cand.kinkTPCNSigmaPi = kinkDauTrack.tpcNSigmaPi(); + lambda1405Cand.kinkTOFNSigmaPi = kinkDauTrack.tofNSigmaPi(); + lambda1405Cand.kinkTPCNSigmaPr = kinkDauTrack.tpcNSigmaPr(); + lambda1405Cand.kinkTOFNSigmaPr = kinkDauTrack.tofNSigmaPr(); + lambda1405Cand.dcaKinkDauToPV = sigmaCand.dcaDaugPv(); + lambda1405Cand.piPt = piTrack.pt(); lambda1405Cand.nSigmaTPCPi = piTrack.tpcNSigmaPi(); if (useTOF) { @@ -230,6 +280,26 @@ struct lambda1405analysis { return false; // No valid pion track found } + template + bool checkSigmaKinkMC(const mcTrack& mcTrackSigma, const mcTrack& mcTrackKinkDau, float sigmaAbsPDG, float kinkAbsPDG, aod::McParticles const&) + { + if (std::abs(mcTrackSigma.pdgCode()) != sigmaAbsPDG || std::abs(mcTrackKinkDau.pdgCode()) != kinkAbsPDG) { + return false; // Not a valid Sigma kink decay + } + if (!mcTrackKinkDau.has_mothers()) { + return false; // No mothers found + } + // Check if the kink comes from the Sigma + bool isKinkFromSigma = false; + for (const auto& mcMother : mcTrackKinkDau.template mothers_as()) { + if (mcMother.globalIndex() == mcTrackSigma.globalIndex()) { + isKinkFromSigma = true; + break; + } + } + return isKinkFromSigma; // Return true if the kink comes from the Sigma + } + void processData(CollisionsFull::iterator const& collision, aod::KinkCands const& kinkCands, TracksFull const& tracks) { if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8()) { @@ -239,17 +309,26 @@ struct lambda1405analysis { for (const auto& sigmaCand : kinkCands) { if (selectCandidate(sigmaCand, tracks)) { if (lambda1405Cand.isSigmaMinus) { - rLambda1405.fill(HIST("h2PtMass_0"), lambda1405Cand.sigmaSign * lambda1405Cand.pt, lambda1405Cand.mass); + rLambda1405.fill(HIST("h2PtMass_0"), lambda1405Cand.sigmaSign * lambda1405Cand.pt(), lambda1405Cand.mass); rLambda1405.fill(HIST("h2PtMassSigma_0"), lambda1405Cand.sigmaSign * lambda1405Cand.sigmaPt, lambda1405Cand.sigmaMinusMass); rLambda1405.fill(HIST("h2SigmaMassVsMass_0"), lambda1405Cand.mass, lambda1405Cand.sigmaMinusMass); rLambda1405.fill(HIST("h2PtPiNSigmaTOF_0"), lambda1405Cand.sigmaSign * lambda1405Cand.piPt, lambda1405Cand.nSigmaTOFPi); } if (lambda1405Cand.isSigmaPlus) { - rLambda1405.fill(HIST("h2PtMass_1"), lambda1405Cand.sigmaSign * lambda1405Cand.pt, lambda1405Cand.mass); + rLambda1405.fill(HIST("h2PtMass_1"), lambda1405Cand.sigmaSign * lambda1405Cand.pt(), lambda1405Cand.mass); rLambda1405.fill(HIST("h2PtMassSigma_1"), lambda1405Cand.sigmaSign * lambda1405Cand.sigmaPt, lambda1405Cand.sigmaPlusMass); rLambda1405.fill(HIST("h2SigmaMassVsMass_1"), lambda1405Cand.mass, lambda1405Cand.sigmaPlusMass); rLambda1405.fill(HIST("h2PtPiNSigmaTOF_1"), lambda1405Cand.sigmaSign * lambda1405Cand.piPt, lambda1405Cand.nSigmaTOFPi); } + if (fillOutputTree) { + outputDataTable(lambda1405Cand.px, lambda1405Cand.py, lambda1405Cand.pz, + lambda1405Cand.mass, lambda1405Cand.sigmaMinusMass, lambda1405Cand.sigmaPlusMass, + lambda1405Cand.sigmaPt, lambda1405Cand.sigmaAlphaAP, lambda1405Cand.sigmaQtAP, lambda1405Cand.sigmaRadius, + lambda1405Cand.kinkTPCNSigmaPi, lambda1405Cand.kinkTOFNSigmaPi, + lambda1405Cand.kinkTPCNSigmaPr, lambda1405Cand.kinkTOFNSigmaPr, + lambda1405Cand.dcaKinkDauToPV, + lambda1405Cand.nSigmaTPCPi, lambda1405Cand.nSigmaTOFPi); + } } } } @@ -273,26 +352,26 @@ struct lambda1405analysis { if (!mcLabSigma.has_mcParticle() || mcLabPiKink.has_mcParticle() || mcLabPi.has_mcParticle()) { continue; // Skip if no valid MC association } - auto mcTrackPiKink = mcLabPiKink.mcParticle_as(); + auto mcTrackKink = mcLabPiKink.mcParticle_as(); auto mcTrackSigma = mcLabSigma.mcParticle_as(); auto mcTrackPi = mcLabPi.mcParticle_as(); - if (std::abs(mcTrackPiKink.pdgCode()) != 211 || std::abs(mcTrackSigma.pdgCode()) != 3122 || std::abs(mcTrackPi.pdgCode()) != 211) { - continue; // Skip if not a valid pion or Sigma candidate - } - if (!mcTrackPiKink.has_mothers() || !mcTrackSigma.has_mothers() || !mcTrackPi.has_mothers()) { - continue; // Skip if no mothers found + + bool isSigmaMinusKink = checkSigmaKinkMC(mcTrackSigma, mcTrackKink, 3122, 211, particlesMC); + bool isSigmaPlusToPiKink = checkSigmaKinkMC(mcTrackSigma, mcTrackKink, 3222, 211, particlesMC); + bool isSigmaPlusToPrKink = checkSigmaKinkMC(mcTrackSigma, mcTrackKink, 3222, 2212, particlesMC); + + if (!isSigmaMinusKink && !isSigmaPlusToPiKink && !isSigmaPlusToPrKink) { + continue; // Skip if not a valid Sigma kink decay } - // check if kink pi comes from the sigma - bool isPiFromSigma = false; - for (const auto& piMother : mcTrackPiKink.mothers_as()) { - if (piMother.globalIndex() == mcTrackSigma.globalIndex()) { - isPiFromSigma = true; - break; // Found the mother, exit loop - } + + if (std::abs(mcTrackPi.pdgCode()) != 211) { + continue; // Skip if not a valid pion candidate } - if (!isPiFromSigma) { - continue; // Skip if the pion does not come from the Sigma + + if (!mcTrackSigma.has_mothers() || !mcTrackPi.has_mothers()) { + continue; // Skip if no mothers found } + // check that labpi and labsigma have the same mother (a lambda1405 candidate) int lambda1405Id = -1; for (const auto& piMother : mcTrackPi.mothers_as()) { @@ -307,23 +386,33 @@ struct lambda1405analysis { continue; // Skip if the Sigma and pion do not share the same lambda1405 candidate } auto lambda1405Mother = particlesMC.rawIteratorAt(lambda1405Id); - LOG(info) << "Particle selected!"; float lambda1405Mass = std::sqrt(lambda1405Mother.e() * lambda1405Mother.e() - lambda1405Mother.p() * lambda1405Mother.p()); if (lambda1405Cand.isSigmaMinus) { - rLambda1405.fill(HIST("h2PtMass_0"), lambda1405Cand.sigmaSign * lambda1405Cand.pt, lambda1405Cand.mass); + rLambda1405.fill(HIST("h2PtMass_0"), lambda1405Cand.sigmaSign * lambda1405Cand.pt(), lambda1405Cand.mass); rLambda1405.fill(HIST("h2PtMassSigma_0"), lambda1405Cand.sigmaSign * lambda1405Cand.sigmaPt, lambda1405Cand.sigmaMinusMass); rLambda1405.fill(HIST("h2SigmaMassVsMass_0"), lambda1405Cand.mass, lambda1405Cand.sigmaMinusMass); rLambda1405.fill(HIST("h2PtPiNSigma_0"), lambda1405Cand.piPt, lambda1405Cand.nSigmaTPCPi); rLambda1405.fill(HIST("h2MassResolution_0"), lambda1405Mass, lambda1405Mass - lambda1405Cand.mass); - rLambda1405.fill(HIST("h2PtResolution_0"), lambda1405Cand.pt, lambda1405Cand.pt - lambda1405Mother.pt()); + rLambda1405.fill(HIST("h2PtResolution_0"), lambda1405Cand.pt(), lambda1405Cand.pt() - lambda1405Mother.pt()); } if (lambda1405Cand.isSigmaPlus) { - rLambda1405.fill(HIST("h2PtMass_1"), lambda1405Cand.sigmaSign * lambda1405Cand.pt, lambda1405Cand.mass); + rLambda1405.fill(HIST("h2PtMass_1"), lambda1405Cand.sigmaSign * lambda1405Cand.pt(), lambda1405Cand.mass); rLambda1405.fill(HIST("h2PtMassSigma_1"), lambda1405Cand.sigmaSign * lambda1405Cand.sigmaPt, lambda1405Cand.sigmaPlusMass); rLambda1405.fill(HIST("h2SigmaMassVsMass_1"), lambda1405Cand.mass, lambda1405Cand.sigmaPlusMass); rLambda1405.fill(HIST("h2PtPiNSigma_1"), lambda1405Cand.piPt, lambda1405Cand.nSigmaTPCPi); rLambda1405.fill(HIST("h2MassResolution_1"), lambda1405Mass, lambda1405Mass - lambda1405Cand.mass); - rLambda1405.fill(HIST("h2PtResolution_1"), lambda1405Cand.pt, lambda1405Cand.pt - lambda1405Mother.pt()); + rLambda1405.fill(HIST("h2PtResolution_1"), lambda1405Cand.pt(), lambda1405Cand.pt() - lambda1405Mother.pt()); + } + + if (fillOutputTree) { + outputDataTableMC(lambda1405Cand.px, lambda1405Cand.py, lambda1405Cand.pz, + lambda1405Cand.mass, lambda1405Cand.sigmaMinusMass, lambda1405Cand.sigmaPlusMass, + lambda1405Cand.sigmaPt, lambda1405Cand.sigmaAlphaAP, lambda1405Cand.sigmaQtAP, lambda1405Cand.sigmaRadius, + lambda1405Cand.kinkTPCNSigmaPi, lambda1405Cand.kinkTOFNSigmaPi, + lambda1405Cand.kinkTPCNSigmaPr, lambda1405Cand.kinkTOFNSigmaPr, + lambda1405Cand.dcaKinkDauToPV, + lambda1405Cand.nSigmaTPCPi, lambda1405Cand.nSigmaTOFPi, + lambda1405Mother.pt(), lambda1405Mass, mcTrackSigma.pdgCode(), mcTrackKink.pdgCode()); } } }