From 3fa8600d5442e26b946361d48a69b81c32479752 Mon Sep 17 00:00:00 2001 From: Subhadeep Roy Date: Mon, 12 Oct 2026 20:42:07 +0530 Subject: [PATCH 1/5] [PWGCF] Add LambdaSpinPolarizationDerived.h --- .../DataModel/LambdaSpinPolarizationDerived.h | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 PWGCF/TwoParticleCorrelations/DataModel/LambdaSpinPolarizationDerived.h diff --git a/PWGCF/TwoParticleCorrelations/DataModel/LambdaSpinPolarizationDerived.h b/PWGCF/TwoParticleCorrelations/DataModel/LambdaSpinPolarizationDerived.h new file mode 100644 index 00000000000..6bb0dc95acc --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/DataModel/LambdaSpinPolarizationDerived.h @@ -0,0 +1,110 @@ +// 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 LambdaSpinPolarizationDerived.h +/// +/// \brief Derived tables of Lambda candidates with loose selections, input of lambdaSpinPolarization +/// \author Subhadeep Roy + +#ifndef PWGCF_TWOPARTICLECORRELATIONS_DATAMODEL_LAMBDASPINPOLARIZATIONDERIVED_H_ +#define PWGCF_TWOPARTICLECORRELATIONS_DATAMODEL_LAMBDASPINPOLARIZATIONDERIVED_H_ + +#include +#include + +#include + +namespace o2::aod +{ +namespace lambdaloosecollision +{ +DECLARE_SOA_COLUMN(Cent, cent, float); +DECLARE_SOA_COLUMN(Mult, mult, float); +DECLARE_SOA_COLUMN(PosX, posX, float); +DECLARE_SOA_COLUMN(PosY, posY, float); +DECLARE_SOA_COLUMN(PosZ, posZ, float); +DECLARE_SOA_COLUMN(TimeStamp, timeStamp, uint64_t); +} // namespace lambdaloosecollision + +DECLARE_SOA_TABLE(LambdaLooseCollisions, "AOD", "LAMBDALOOSECOLS", + o2::soa::Index<>, + lambdaloosecollision::Cent, + lambdaloosecollision::Mult, + lambdaloosecollision::PosX, + lambdaloosecollision::PosY, + lambdaloosecollision::PosZ, + lambdaloosecollision::TimeStamp); +using LambdaLooseCollision = LambdaLooseCollisions::iterator; + +namespace lambdaloosetrack +{ +DECLARE_SOA_INDEX_COLUMN(LambdaLooseCollision, lambdaLooseCollision); +DECLARE_SOA_COLUMN(Px, px, float); +DECLARE_SOA_COLUMN(Py, py, float); +DECLARE_SOA_COLUMN(Pz, pz, float); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Rap, rap, float); +DECLARE_SOA_COLUMN(Mass, mass, float); +DECLARE_SOA_COLUMN(MassOther, massOther, float); +DECLARE_SOA_COLUMN(PrPx, prPx, float); +DECLARE_SOA_COLUMN(PrPy, prPy, float); +DECLARE_SOA_COLUMN(PrPz, prPz, float); +DECLARE_SOA_COLUMN(PosTrackId, posTrackId, int32_t); +DECLARE_SOA_COLUMN(NegTrackId, negTrackId, int32_t); +DECLARE_SOA_COLUMN(V0Type, v0Type, int8_t); +DECLARE_SOA_COLUMN(CosPA, cosPA, float); +DECLARE_SOA_COLUMN(DcaDau, dcaDau, float); +DECLARE_SOA_COLUMN(DcaV0ToPV, dcaV0ToPV, float); +DECLARE_SOA_COLUMN(CTau, cTau, float); +DECLARE_SOA_COLUMN(MK0Short, mK0Short, float); +DECLARE_SOA_COLUMN(PosNSigmaPr, posNSigmaPr, float); +DECLARE_SOA_COLUMN(PosNSigmaPi, posNSigmaPi, float); +DECLARE_SOA_COLUMN(NegNSigmaPr, negNSigmaPr, float); +DECLARE_SOA_COLUMN(NegNSigmaPi, negNSigmaPi, float); +DECLARE_SOA_COLUMN(PosTpcCrossedRows, posTpcCrossedRows, int16_t); +DECLARE_SOA_COLUMN(NegTpcCrossedRows, negTpcCrossedRows, int16_t); +} // namespace lambdaloosetrack + +DECLARE_SOA_TABLE(LambdaLooseTracks, "AOD", "LAMBDALOOSETRKS", + o2::soa::Index<>, + lambdaloosetrack::LambdaLooseCollisionId, + lambdaloosetrack::Px, + lambdaloosetrack::Py, + lambdaloosetrack::Pz, + lambdaloosetrack::Pt, + lambdaloosetrack::Eta, + lambdaloosetrack::Phi, + lambdaloosetrack::Rap, + lambdaloosetrack::Mass, + lambdaloosetrack::MassOther, + lambdaloosetrack::PrPx, + lambdaloosetrack::PrPy, + lambdaloosetrack::PrPz, + lambdaloosetrack::PosTrackId, + lambdaloosetrack::NegTrackId, + lambdaloosetrack::V0Type, + lambdaloosetrack::CosPA, + lambdaloosetrack::DcaDau, + lambdaloosetrack::DcaV0ToPV, + lambdaloosetrack::CTau, + lambdaloosetrack::MK0Short, + lambdaloosetrack::PosNSigmaPr, + lambdaloosetrack::PosNSigmaPi, + lambdaloosetrack::NegNSigmaPr, + lambdaloosetrack::NegNSigmaPi, + lambdaloosetrack::PosTpcCrossedRows, + lambdaloosetrack::NegTpcCrossedRows); +using LambdaLooseTrack = LambdaLooseTracks::iterator; +} // namespace o2::aod + +#endif // PWGCF_TWOPARTICLECORRELATIONS_DATAMODEL_LAMBDASPINPOLARIZATIONDERIVED_H_ From 225ee753e8207ac268b0e4143ddc1587b56cc3fd Mon Sep 17 00:00:00 2001 From: Subhadeep Roy Date: Mon, 12 Oct 2026 20:47:03 +0530 Subject: [PATCH 2/5] [PWGCF] Add lambdaSpinPolarizationLooseProducer.cxx Derived data producer for the lambdaSpinPolarization.cxx --- .../lambdaSpinPolarizationLooseProducer.cxx | 482 ++++++++++++++++++ 1 file changed, 482 insertions(+) create mode 100644 PWGCF/TwoParticleCorrelations/TableProducer/lambdaSpinPolarizationLooseProducer.cxx diff --git a/PWGCF/TwoParticleCorrelations/TableProducer/lambdaSpinPolarizationLooseProducer.cxx b/PWGCF/TwoParticleCorrelations/TableProducer/lambdaSpinPolarizationLooseProducer.cxx new file mode 100644 index 00000000000..7c2b10e88b5 --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/TableProducer/lambdaSpinPolarizationLooseProducer.cxx @@ -0,0 +1,482 @@ +// 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 lambdaSpinPolarizationLooseProducer.cxx +/// \brief Lambda candidates with loose selections, written as derived data for lambdaSpinPolarization +/// \author Subhadeep Roy + +#include "PWGCF/TwoParticleCorrelations/DataModel/LambdaSpinPolarizationDerived.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::constants::physics; + +enum LooseEventCutFlow { kLeAll = 1, + kLeTrigger, + kLeTvx, + kLeTFBorder, + kLeItsRofBorder, + kLeItsTpcVtx, + kLeNoSameBunchPileup, + kLeGoodZvtxFT0vsPV, + kLeGoodItsLayers, + kLeCentrality, + kLeVz, + kLeOneV0, + kLeTwoV0, + kLeWritten, + kNLooseEventCutFlow }; + +enum LooseV0Count { kLvAll = 1, + kLvV0Type, + kLvAmbiguousTracks, + kLvKShortRejected, + kLvKinematics, + kLvTopology, + kLvNoHypothesis, + kLvLambdaRow, + kLvAntiLambdaRow, + kLvBothRows, + kNLooseV0Count }; + +enum LooseHypothesis { kLooseLambda = 0, + kLooseAntiLambda, + kNLooseHypotheses }; + +static constexpr std::size_t NV0ForPair = 2; + +enum LooseCentEstimator { kLooseCentFT0M = 0, + kLooseCentFT0C }; + +struct LambdaSpinPolarizationLooseProducer { + + Produces lambdaLooseCollisionTable; + Produces lambdaLooseTrackTable; + + Configurable cCentEstimator{"cCentEstimator", 0, "Centrality Estimator: 0=FT0M, 1=FT0C"}; + Configurable cMinZVtx{"cMinZVtx", -10.0, "Min VtxZ (cm)"}; + Configurable cMaxZVtx{"cMaxZVtx", 10.0, "Max VtxZ (cm)"}; + Configurable cMinMult{"cMinMult", 0.0, "Min centrality percentile"}; + Configurable cMaxMult{"cMaxMult", 100.0, "Max centrality percentile"}; + Configurable cSel8Trig{"cSel8Trig", true, "Sel8 (T0A+T0C) Run3"}; + Configurable cTriggerTvxSel{"cTriggerTvxSel", false, "TVX Trigger Selection"}; + Configurable cTFBorder{"cTFBorder", false, "Timeframe Border Selection"}; + Configurable cNoItsROBorder{"cNoItsROBorder", false, "No ITSRO Border Cut"}; + Configurable cItsTpcVtx{"cItsTpcVtx", false, "ITS+TPC Vertex Selection"}; + Configurable cPileupReject{"cPileupReject", false, "Pileup rejection"}; + Configurable cZVtxTimeDiff{"cZVtxTimeDiff", false, "z-vtx time diff selection"}; + Configurable cIsGoodITSLayers{"cIsGoodITSLayers", false, "Good ITS Layers All"}; + + Configurable cTrackMinPt{"cTrackMinPt", 0.15, "p_{T} minimum"}; + Configurable cTrackMaxPt{"cTrackMaxPt", 999.0, "p_{T} maximum"}; + Configurable cTrackEtaCut{"cTrackEtaCut", 0.8, "Pseudorapidity cut"}; + Configurable cMinTpcCrossedRows{"cMinTpcCrossedRows", 50, "TPC Min Crossed Rows (loosest of the variations)"}; + Configurable cMinTpcCROverCls{"cMinTpcCROverCls", -999, "TPC Min CR/Findable Cls"}; + Configurable cMaxTpcSharedClusters{"cMaxTpcSharedClusters", 999, "TPC Max Shared Clusters"}; + Configurable cMaxChi2Tpc{"cMaxChi2Tpc", 999, "Max TPC Chi2/ndf"}; + Configurable cTpcNsigmaCut{"cTpcNsigmaCut", 5.0, "TPC nSigma PID cut (loosest of the variations)"}; + Configurable cRemoveAmbiguousTracks{"cRemoveAmbiguousTracks", false, "Remove Ambiguous Tracks"}; + + Configurable cMinDcaProtonToPV{"cMinDcaProtonToPV", 0.05, "Min proton DCA to PV (cm)"}; + Configurable cMinDcaPionToPV{"cMinDcaPionToPV", 0.1, "Min pion DCA to PV (cm)"}; + Configurable cMinV0DcaDaughters{"cMinV0DcaDaughters", 0., "Min DCA between V0 daughters"}; + Configurable cMaxV0DcaDaughters{"cMaxV0DcaDaughters", 1.4, "Max DCA between V0 daughters"}; + Configurable cMinDcaV0ToPV{"cMinDcaV0ToPV", 0.0, "Min DCA V0 to PV"}; + Configurable cMaxDcaV0ToPV{"cMaxDcaV0ToPV", 0.2, "Max DCA V0 to PV (loosest of the variations)"}; + Configurable cMinV0TransRadius{"cMinV0TransRadius", 0.5, "Min V0 decay radius (cm)"}; + Configurable cMaxV0TransRadius{"cMaxV0TransRadius", 999.0, "Max V0 decay radius (cm)"}; + Configurable cMinV0CTau{"cMinV0CTau", 0.0, "Min cTau (cm)"}; + Configurable cMaxV0CTau{"cMaxV0CTau", 36.0, "Max cTau (cm) (loosest of the variations)"}; + Configurable cMinV0CosPA{"cMinV0CosPA", 0.98, "Min V0 cos(PA) (loosest of the variations)"}; + Configurable cKshortRejMassWindow{"cKshortRejMassWindow", 0.001, "K0s mass rejection window (narrowest of the variations)"}; + Configurable cKshortRejFlag{"cKshortRejFlag", true, "K0s mass rejection flag"}; + + Configurable cMinV0Mass{"cMinV0Mass", 1.09, "V0 Mass Min"}; + Configurable cMaxV0Mass{"cMaxV0Mass", 1.14, "V0 Mass Max"}; + Configurable cMinV0Pt{"cMinV0Pt", 0.6, "Minimum V0 pT"}; + Configurable cMaxV0Pt{"cMaxV0Pt", 3.0, "Maximum V0 pT"}; + Configurable cMaxV0Rap{"cMaxV0Rap", 0.5, "|rap| cut"}; + Configurable cDoEtaAnalysis{"cDoEtaAnalysis", false, "Do Eta Analysis"}; + Configurable cV0TypeSelFlag{"cV0TypeSelFlag", true, "V0 Type Selection Flag"}; + Configurable cV0TypeSelection{"cV0TypeSelection", 1, "V0 Type Selection"}; + + Configurable cMinV0PerEvent{"cMinV0PerEvent", 2, "Collisions with fewer V0s passing the loose selection are not written"}; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + struct LooseCandidate { + float px, py, pz, pt, eta, phi, rap, mass, massOther, prPx, prPy, prPz; + int32_t posTrackId, negTrackId; + int8_t v0Type; + float cosPA, dcaDau, dcaV0ToPV, cTau, mK0Short; + float posNSigmaPr, posNSigmaPi, negNSigmaPr, negNSigmaPi; + int16_t posTpcCrossedRows, negTpcCrossedRows; + }; + std::vector candidates; + + float cent = 0., mult = 0.; + + void init(InitContext const&) + { + if (cMinV0PerEvent.value < 1) { + LOGF(fatal, "cMinV0PerEvent must be at least 1, it is %d", cMinV0PerEvent.value); + } + const AxisSpec axisV0Mass(200, 1.08, 1.18, "M_{p#pi} (GeV/#it{c}^{2})"); + const AxisSpec axisV0Pt(100., 0., 10., "p_{T} (GeV/#it{c})"); + const AxisSpec axisNV0(20, -0.5, 19.5, "V0s written per collision"); + + auto hCutFlow = histos.add("Events/hEventCutFlow", "event cut flow;;collisions", kTH1D, {{kNLooseEventCutFlow - 1, 0.5, static_cast(kNLooseEventCutFlow) - 0.5}}); + hCutFlow->GetXaxis()->SetBinLabel(kLeAll, "all"); + hCutFlow->GetXaxis()->SetBinLabel(kLeTrigger, "trigger (sel8)"); + hCutFlow->GetXaxis()->SetBinLabel(kLeTvx, "TVX"); + hCutFlow->GetXaxis()->SetBinLabel(kLeTFBorder, "no TF border"); + hCutFlow->GetXaxis()->SetBinLabel(kLeItsRofBorder, "no ITS ROF border"); + hCutFlow->GetXaxis()->SetBinLabel(kLeItsTpcVtx, "ITS-TPC vertex"); + hCutFlow->GetXaxis()->SetBinLabel(kLeNoSameBunchPileup, "no same-bunch pileup"); + hCutFlow->GetXaxis()->SetBinLabel(kLeGoodZvtxFT0vsPV, "good z_{vtx} FT0 vs PV"); + hCutFlow->GetXaxis()->SetBinLabel(kLeGoodItsLayers, "good ITS layers"); + hCutFlow->GetXaxis()->SetBinLabel(kLeCentrality, "centrality range"); + hCutFlow->GetXaxis()->SetBinLabel(kLeVz, "V_{z} range"); + hCutFlow->GetXaxis()->SetBinLabel(kLeOneV0, "#geq 1 V0 with a loose candidate"); + hCutFlow->GetXaxis()->SetBinLabel(kLeTwoV0, "#geq 2 V0s with a loose candidate"); + hCutFlow->GetXaxis()->SetBinLabel(kLeWritten, "written"); + + auto hV0 = histos.add("Tracks/hV0Count", "V0s;;V0s", kTH1D, {{kNLooseV0Count - 1, 0.5, static_cast(kNLooseV0Count) - 0.5}}); + hV0->GetXaxis()->SetBinLabel(kLvAll, "all"); + hV0->GetXaxis()->SetBinLabel(kLvV0Type, "rejected: V0 type"); + hV0->GetXaxis()->SetBinLabel(kLvAmbiguousTracks, "rejected: ambiguous tracks"); + hV0->GetXaxis()->SetBinLabel(kLvKShortRejected, "rejected: K^{0}_{S} mass"); + hV0->GetXaxis()->SetBinLabel(kLvKinematics, "rejected: p_{T} / y"); + hV0->GetXaxis()->SetBinLabel(kLvTopology, "rejected: topology"); + hV0->GetXaxis()->SetBinLabel(kLvNoHypothesis, "rejected: no hypothesis"); + hV0->GetXaxis()->SetBinLabel(kLvLambdaRow, "#Lambda candidate"); + hV0->GetXaxis()->SetBinLabel(kLvAntiLambdaRow, "#bar{#Lambda} candidate"); + hV0->GetXaxis()->SetBinLabel(kLvBothRows, "both candidates"); + + histos.add("Tracks/hLambdaMassVsPt", "#Lambda candidates", kTH2F, {axisV0Mass, axisV0Pt}); + histos.add("Tracks/hAntiLambdaMassVsPt", "#bar{#Lambda} candidates", kTH2F, {axisV0Mass, axisV0Pt}); + histos.add("Events/hNV0Written", "written collisions", kTH1F, {axisNV0}); + } + + template + bool selCollision(C const& col) + { + histos.fill(HIST("Events/hEventCutFlow"), kLeAll); + if (cCentEstimator == kLooseCentFT0M) { + cent = col.centFT0M(); + } else if (cCentEstimator == kLooseCentFT0C) { + cent = col.centFT0C(); + } + if (cSel8Trig && !col.sel8()) { + return false; + } + histos.fill(HIST("Events/hEventCutFlow"), kLeTrigger); + + if (cTriggerTvxSel && !col.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + histos.fill(HIST("Events/hEventCutFlow"), kLeTvx); + if (cTFBorder && !col.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + histos.fill(HIST("Events/hEventCutFlow"), kLeTFBorder); + if (cNoItsROBorder && !col.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + histos.fill(HIST("Events/hEventCutFlow"), kLeItsRofBorder); + if (cItsTpcVtx && !col.selection_bit(aod::evsel::kIsVertexITSTPC)) { + return false; + } + histos.fill(HIST("Events/hEventCutFlow"), kLeItsTpcVtx); + if (cPileupReject && !col.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + histos.fill(HIST("Events/hEventCutFlow"), kLeNoSameBunchPileup); + if (cZVtxTimeDiff && !col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + histos.fill(HIST("Events/hEventCutFlow"), kLeGoodZvtxFT0vsPV); + if (cIsGoodITSLayers && !col.selection_bit(aod::evsel::kIsGoodITSLayersAll)) { + return false; + } + histos.fill(HIST("Events/hEventCutFlow"), kLeGoodItsLayers); + + if (cent <= cMinMult || cent >= cMaxMult) { + return false; + } + histos.fill(HIST("Events/hEventCutFlow"), kLeCentrality); + if (col.posZ() <= cMinZVtx || col.posZ() >= cMaxZVtx) { + return false; + } + histos.fill(HIST("Events/hEventCutFlow"), kLeVz); + + mult = col.multNTracksPV(); + return true; + } + + bool kinCutSelection(float const& pt, float const& rap, float const& ptMin, float const& ptMax, float const& rapMax) + { + return pt > ptMin && pt < ptMax && rap < rapMax; + } + + template + bool selTrack(T const& track) + { + if (!kinCutSelection(track.pt(), std::abs(track.eta()), cTrackMinPt, cTrackMaxPt, cTrackEtaCut)) { + return false; + } + if (track.tpcNClsCrossedRows() <= cMinTpcCrossedRows) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < cMinTpcCROverCls) { + return false; + } + if (track.tpcNClsShared() > cMaxTpcSharedClusters) { + return false; + } + if (track.tpcChi2NCl() > cMaxChi2Tpc) { + return false; + } + return true; + } + + template + bool selDaughterTracks(V const& v0, T const&, LooseHypothesis const& v0Type) + { + auto posTrack = v0.template posTrack_as(); + auto negTrack = v0.template negTrack_as(); + if (!selTrack(posTrack) || !selTrack(negTrack)) { + return false; + } + + float dcaProton = 0., dcaPion = 0.; + if (v0Type == kLooseLambda) { + dcaProton = std::abs(v0.dcapostopv()); + dcaPion = std::abs(v0.dcanegtopv()); + } else if (v0Type == kLooseAntiLambda) { + dcaPion = std::abs(v0.dcapostopv()); + dcaProton = std::abs(v0.dcanegtopv()); + } + if (dcaProton < cMinDcaProtonToPV || dcaPion < cMinDcaPionToPV) { + return false; + } + return true; + } + + template + bool topoCutSelection(C const& col, V const& v0, T const&) + { + if (v0.dcaV0daughters() <= cMinV0DcaDaughters || v0.dcaV0daughters() >= cMaxV0DcaDaughters) { + return false; + } + if (v0.dcav0topv() <= cMinDcaV0ToPV || v0.dcav0topv() >= cMaxDcaV0ToPV) { + return false; + } + if (v0.v0radius() <= cMinV0TransRadius || v0.v0radius() >= cMaxV0TransRadius) { + return false; + } + + float ctau = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * MassLambda0; + if (ctau <= cMinV0CTau || ctau >= cMaxV0CTau) { + return false; + } + if (v0.v0cosPA() <= cMinV0CosPA) { + return false; + } + return true; + } + + template + bool selLambdaDauWithTpcPid(T const& postrack, T const& negtrack) + { + float tpcNSigmaPr = 0., tpcNSigmaPi = 0.; + if constexpr (part == kLooseLambda) { + tpcNSigmaPr = postrack.tpcNSigmaPr(); + tpcNSigmaPi = negtrack.tpcNSigmaPi(); + } else { + tpcNSigmaPr = negtrack.tpcNSigmaPr(); + tpcNSigmaPi = postrack.tpcNSigmaPi(); + } + return (std::abs(tpcNSigmaPr) < cTpcNsigmaCut && std::abs(tpcNSigmaPi) < cTpcNsigmaCut); + } + + template + bool hasAmbiguousDaughters(V const& v0, T const&) + { + auto posTrack = v0.template posTrack_as(); + auto negTrack = v0.template negTrack_as(); + auto posCC = posTrack.compatibleCollIds(); + auto negCC = negTrack.compatibleCollIds(); + if (posCC.size() > 1 || negCC.size() > 1) { + return true; + } + if ((posCC.size() != 0 && posCC[0] != posTrack.collisionId()) || + (negCC.size() != 0 && negCC[0] != negTrack.collisionId())) { + return true; + } + return false; + } + + using CollisionsRun3 = soa::Join; + using Tracks = soa::Join; + + void processData(CollisionsRun3::iterator const& collision, aod::BCsWithTimestamps const&, aod::V0Datas const& V0s, Tracks const& tracks) + { + if (!selCollision(collision)) { + return; + } + + candidates.clear(); + std::size_t nV0 = 0; + for (auto const& v0 : V0s) { + histos.fill(HIST("Tracks/hV0Count"), kLvAll); + if (cV0TypeSelFlag && v0.v0Type() != cV0TypeSelection) { + histos.fill(HIST("Tracks/hV0Count"), kLvV0Type); + continue; + } + if (cRemoveAmbiguousTracks && hasAmbiguousDaughters(v0, tracks)) { + histos.fill(HIST("Tracks/hV0Count"), kLvAmbiguousTracks); + continue; + } + if (cKshortRejFlag && (std::abs(v0.mK0Short() - MassK0Short) <= cKshortRejMassWindow)) { + histos.fill(HIST("Tracks/hV0Count"), kLvKShortRejected); + continue; + } + const float rap = cDoEtaAnalysis ? std::abs(v0.eta()) : std::abs(v0.yLambda()); + if (!kinCutSelection(v0.pt(), rap, cMinV0Pt, cMaxV0Pt, cMaxV0Rap)) { + histos.fill(HIST("Tracks/hV0Count"), kLvKinematics); + continue; + } + if (!topoCutSelection(collision, v0, tracks)) { + histos.fill(HIST("Tracks/hV0Count"), kLvTopology); + continue; + } + + auto postrack = v0.posTrack_as(); + auto negtrack = v0.negTrack_as(); + const std::array masses = {v0.mLambda(), v0.mAntiLambda()}; + const std::array pid = {selLambdaDauWithTpcPid(postrack, negtrack), selLambdaDauWithTpcPid(postrack, negtrack)}; + const float ctau = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * MassLambda0; + + std::size_t nRows = 0; + for (auto const& hyp : {kLooseLambda, kLooseAntiLambda}) { + const bool inMassWindow = masses[hyp] > cMinV0Mass && masses[hyp] < cMaxV0Mass; + if (!inMassWindow || !pid[hyp]) { + continue; + } + if (!selDaughterTracks(v0, tracks, hyp)) { + continue; + } + const bool isLambda = hyp == kLooseLambda; + candidates.push_back(LooseCandidate{.px = v0.px(), + .py = v0.py(), + .pz = v0.pz(), + .pt = v0.pt(), + .eta = v0.eta(), + .phi = v0.phi(), + .rap = v0.yLambda(), + .mass = masses[hyp], + .massOther = masses[isLambda ? kLooseAntiLambda : kLooseLambda], + .prPx = isLambda ? v0.pxpos() : v0.pxneg(), + .prPy = isLambda ? v0.pypos() : v0.pyneg(), + .prPz = isLambda ? v0.pzpos() : v0.pzneg(), + .posTrackId = static_cast(postrack.index()), + .negTrackId = static_cast(negtrack.index()), + .v0Type = static_cast(hyp), + .cosPA = v0.v0cosPA(), + .dcaDau = v0.dcaV0daughters(), + .dcaV0ToPV = v0.dcav0topv(), + .cTau = ctau, + .mK0Short = v0.mK0Short(), + .posNSigmaPr = postrack.tpcNSigmaPr(), + .posNSigmaPi = postrack.tpcNSigmaPi(), + .negNSigmaPr = negtrack.tpcNSigmaPr(), + .negNSigmaPi = negtrack.tpcNSigmaPi(), + .posTpcCrossedRows = postrack.tpcNClsCrossedRows(), + .negTpcCrossedRows = negtrack.tpcNClsCrossedRows()}); + if (isLambda) { + histos.fill(HIST("Tracks/hV0Count"), kLvLambdaRow); + histos.fill(HIST("Tracks/hLambdaMassVsPt"), masses[hyp], v0.pt()); + } else { + histos.fill(HIST("Tracks/hV0Count"), kLvAntiLambdaRow); + histos.fill(HIST("Tracks/hAntiLambdaMassVsPt"), masses[hyp], v0.pt()); + } + ++nRows; + } + if (nRows == 0) { + histos.fill(HIST("Tracks/hV0Count"), kLvNoHypothesis); + continue; + } + if (nRows == kNLooseHypotheses) { + histos.fill(HIST("Tracks/hV0Count"), kLvBothRows); + } + ++nV0; + } + + if (nV0 >= 1) { + histos.fill(HIST("Events/hEventCutFlow"), kLeOneV0); + } + if (nV0 >= NV0ForPair) { + histos.fill(HIST("Events/hEventCutFlow"), kLeTwoV0); + } + if (std::cmp_less(nV0, cMinV0PerEvent.value)) { + return; + } + histos.fill(HIST("Events/hEventCutFlow"), kLeWritten); + histos.fill(HIST("Events/hNV0Written"), nV0); + + auto bc = collision.bc_as(); + lambdaLooseCollisionTable(cent, mult, collision.posX(), collision.posY(), collision.posZ(), bc.timestamp()); + for (auto const& c : candidates) { + lambdaLooseTrackTable(lambdaLooseCollisionTable.lastIndex(), c.px, c.py, c.pz, c.pt, c.eta, c.phi, c.rap, c.mass, c.massOther, c.prPx, c.prPy, c.prPz, + c.posTrackId, c.negTrackId, c.v0Type, c.cosPA, c.dcaDau, c.dcaV0ToPV, c.cTau, c.mK0Short, + c.posNSigmaPr, c.posNSigmaPi, c.negNSigmaPr, c.negNSigmaPi, c.posTpcCrossedRows, c.negTpcCrossedRows); + } + } + PROCESS_SWITCH(LambdaSpinPolarizationLooseProducer, processData, "Run 3 data (or MC reconstructed as data)", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} From 55ceca4da4e4acfda804fcf5182bdf4e35d42f3e Mon Sep 17 00:00:00 2001 From: Subhadeep Roy Date: Mon, 12 Oct 2026 20:50:15 +0530 Subject: [PATCH 3/5] [PWGCF] Add the lambda-spin-polarization-loose-producer workflow --- PWGCF/TwoParticleCorrelations/TableProducer/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/PWGCF/TwoParticleCorrelations/TableProducer/CMakeLists.txt b/PWGCF/TwoParticleCorrelations/TableProducer/CMakeLists.txt index 0669a351d1e..f50a766cf82 100644 --- a/PWGCF/TwoParticleCorrelations/TableProducer/CMakeLists.txt +++ b/PWGCF/TwoParticleCorrelations/TableProducer/CMakeLists.txt @@ -33,3 +33,8 @@ o2physics_add_dpl_workflow(longrange-maker SOURCES longrangeMaker.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::TwoPartCorrCore O2Physics::SGCutParHolder COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lambda-spin-polarization-loose-producer + SOURCES lambdaSpinPolarizationLooseProducer.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) From 64d1fd16ce41a884a7b119ee3bc7134b48addcbd Mon Sep 17 00:00:00 2001 From: Subhadeep Roy Date: Mon, 12 Oct 2026 20:51:42 +0530 Subject: [PATCH 4/5] [PWGCF] lambdaSpinPolarization: processDerivedData --- .../Tasks/lambdaSpinPolarization.cxx | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/PWGCF/TwoParticleCorrelations/Tasks/lambdaSpinPolarization.cxx b/PWGCF/TwoParticleCorrelations/Tasks/lambdaSpinPolarization.cxx index 8906ab8532b..44daf7bc633 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/lambdaSpinPolarization.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/lambdaSpinPolarization.cxx @@ -14,6 +14,7 @@ ///\author Subhadeep Roy /// \author Yash Patley , +#include "PWGCF/TwoParticleCorrelations/DataModel/LambdaSpinPolarizationDerived.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "Common/CCDB/EventSelectionParams.h" @@ -1237,6 +1238,112 @@ struct LambdaTableProducer { analyzeMcRecoGen(mcCollision, collisions, bcts, V0s, tracks, mcParticles); } PROCESS_SWITCH(LambdaTableProducer, processMCRun3, "Process for Run3 MC RecoGen", false); + + template + bool selLooseCandidate(T const& cand) + { + if (cKshortRejFlag && (std::abs(cand.mK0Short() - MassK0Short) <= cKshortRejMassWindow)) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kV0KShortMassRej); + return false; + } + + auto passMassAndPid = [&](float mass, float tpcNSigmaPr, float tpcNSigmaPi) { + return (mass > cMinV0Mass && mass < cMaxV0Mass) && (std::abs(tpcNSigmaPr) < cTpcNsigmaCut && std::abs(tpcNSigmaPi) < cTpcNsigmaCut); + }; + const bool isLambda = cand.v0Type() == kLambda; + const bool ownFlag = isLambda ? passMassAndPid(cand.mass(), cand.posNSigmaPr(), cand.negNSigmaPi()) : passMassAndPid(cand.mass(), cand.negNSigmaPr(), cand.posNSigmaPi()); + const bool otherFlag = isLambda ? passMassAndPid(cand.massOther(), cand.negNSigmaPr(), cand.posNSigmaPi()) : passMassAndPid(cand.massOther(), cand.posNSigmaPr(), cand.negNSigmaPi()); + if (!ownFlag) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kNotLambdaNotAntiLambda); + return false; + } + if (otherFlag) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kV0IsBothLambdaAntiLambda); + return false; + } + histos.fill(HIST("Tracks/h1f_tracks_info"), kV0IsLambdaOrAntiLambda); + + if (cand.posTpcCrossedRows() <= cMinTpcCrossedRows || cand.negTpcCrossedRows() <= cMinTpcCrossedRows) { + return false; + } + histos.fill(HIST("Tracks/h1f_tracks_info"), kPassV0DauTrackSel); + + float rap = cDoEtaAnalysis ? std::abs(cand.eta()) : std::abs(cand.rap()); + if (!kinCutSelection(cand.pt(), rap, cMinV0Pt, cMaxV0Pt, cMaxV0Rap)) { + return false; + } + histos.fill(HIST("Tracks/h1f_tracks_info"), kPassV0KinCuts); + + if (cand.dcaDau() <= cMinV0DcaDaughters || cand.dcaDau() >= cMaxV0DcaDaughters) { + return false; + } + if (cand.dcaV0ToPV() <= cMinDcaV0ToPV || cand.dcaV0ToPV() >= cMaxDcaV0ToPV) { + return false; + } + if (cand.cTau() <= cMinV0CTau || cand.cTau() >= cMaxV0CTau) { + return false; + } + if (cand.cosPA() <= cMinV0CosPA) { + return false; + } + histos.fill(HIST("Tracks/h1f_tracks_info"), kPassV0TopoSel); + return true; + } + + void processDerivedData(aod::LambdaLooseCollisions::iterator const& collision, aod::LambdaLooseTracks const& looseTracks) + { + histos.fill(HIST("Events/h1f_collisions_info"), kTotCol); + cent = collision.cent(); + mult = collision.mult(); + if (cent <= cMinMult || cent >= cMaxMult) { + return; + } + histos.fill(HIST("Events/hEventCutFlow"), kEvCentrality); + if (collision.posZ() <= cMinZVtx || collision.posZ() >= cMaxZVtx) { + return; + } + histos.fill(HIST("Events/hEventCutFlow"), kEvVz); + + histos.fill(HIST("Events/h1f_collisions_info"), kPassSelCol); + histos.fill(HIST("Events/h1f_collision_posZ"), collision.posZ()); + histos.fill(HIST("Events/h1f_collision_cent"), cent); + + lambdaCollisionTable(cent, mult, collision.posX(), collision.posY(), collision.posZ(), collision.timeStamp()); + + std::size_t nWritten = 0; + for (auto const& cand : looseTracks) { + histos.fill(HIST("Tracks/h1f_tracks_info"), kAllV0Tracks); + if (!selLooseCandidate(cand)) { + continue; + } + histos.fill(HIST("Tracks/h1f_tracks_info"), kAllSelPassed); + + if (cand.v0Type() == kLambda) { + histos.fill(HIST("Tracks/h1f_lambda_pt_vs_invm"), cand.mass(), cand.pt()); + fillKinematicHists(cand.pt(), cand.eta(), cand.rap(), cand.phi()); + } else { + histos.fill(HIST("Tracks/h1f_antilambda_pt_vs_invm"), cand.mass(), cand.pt()); + fillKinematicHists(cand.pt(), cand.eta(), cand.rap(), cand.phi()); + } + + lambdaTrackTable(lambdaCollisionTable.lastIndex(), cand.px(), cand.py(), + cand.pz(), cand.pt(), cand.eta(), cand.phi(), cand.rap(), cand.mass(), + cand.prPx(), cand.prPy(), cand.prPz(), + static_cast(cand.posTrackId()), + static_cast(cand.negTrackId()), + cand.cosPA(), cand.dcaDau(), cand.v0Type(), + static_cast(kPrimary), 1.f); + ++nWritten; + } + + if (nWritten >= 1) { + histos.fill(HIST("Events/hEventCutFlow"), kEvOneV0); + } + if (nWritten >= NCandidatesForPair) { + histos.fill(HIST("Events/hEventCutFlow"), kEvTwoV0); + } + } + PROCESS_SWITCH(LambdaTableProducer, processDerivedData, "Process the derived data of lambda-spin-polarization-loose-producer", false); }; struct LambdaTracksExtProducer { From ee75ecac7709f5e5abb283f6b0386c9fc4c5f94b Mon Sep 17 00:00:00 2001 From: Subhadeep Roy Date: Mon, 12 Oct 2026 21:08:30 +0530 Subject: [PATCH 5/5] [PWGCF] Remove trailing whitespace in CMakeLists.txt --- PWGCF/TwoParticleCorrelations/TableProducer/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PWGCF/TwoParticleCorrelations/TableProducer/CMakeLists.txt b/PWGCF/TwoParticleCorrelations/TableProducer/CMakeLists.txt index f50a766cf82..919a0c205e9 100644 --- a/PWGCF/TwoParticleCorrelations/TableProducer/CMakeLists.txt +++ b/PWGCF/TwoParticleCorrelations/TableProducer/CMakeLists.txt @@ -33,7 +33,7 @@ o2physics_add_dpl_workflow(longrange-maker SOURCES longrangeMaker.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::TwoPartCorrCore O2Physics::SGCutParHolder COMPONENT_NAME Analysis) - + o2physics_add_dpl_workflow(lambda-spin-polarization-loose-producer SOURCES lambdaSpinPolarizationLooseProducer.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore