diff --git a/PWGLF/DataModel/LFSlimHeLambda.h b/PWGLF/DataModel/LFSlimHeLambda.h index 6b3ae954cd9..a0737effbbb 100644 --- a/PWGLF/DataModel/LFSlimHeLambda.h +++ b/PWGLF/DataModel/LFSlimHeLambda.h @@ -54,12 +54,18 @@ DECLARE_SOA_COLUMN(DCAPVProton, dcaPVProton, float); DECLARE_SOA_COLUMN(DCAPVPion, dcaPVPion, float); DECLARE_SOA_COLUMN(V0Radius, v0Radius, float); DECLARE_SOA_COLUMN(Sign, sign, int8_t); +DECLARE_SOA_COLUMN(Ct, ct, float); +DECLARE_SOA_COLUMN(DCAPVPos, dcaPVPos, float); +DECLARE_SOA_COLUMN(DCAPVNeg, dcaPVNeg, float); +DECLARE_SOA_COLUMN(NsigmaTPCPosPion, nSigmaTPCPosPion, float); +DECLARE_SOA_COLUMN(NsigmaTPCNegPion, nSigmaTPCNegPion, float); } // namespace lfv0he3 DECLARE_SOA_TABLE_VERSIONED(LFHe3_000, "AOD", "LFHE3V0", 0, lfv0he3::LFEventId, lfv0he3::Pt, lfv0he3::Eta, lfv0he3::Phi, lfv0he3::DCAxy, lfv0he3::DCAz, lfv0he3::TPCnCls, lfv0he3::ITSClusterSizes, lfv0he3::NsigmaTPC, lfv0he3::Sign); DECLARE_SOA_TABLE_VERSIONED(LFLambda_000, "AOD", "LFLAMBDA", 0, lfv0he3::LFEventId, lfv0he3::Pt, lfv0he3::Eta, lfv0he3::Phi, lfv0he3::Mass, lfv0he3::CosPA, lfv0he3::DCAdaughters, lfv0he3::DCAPVProton, lfv0he3::DCAPVPion, lfv0he3::V0Radius, lfv0he3::Sign); DECLARE_SOA_TABLE_VERSIONED(LFHe3_001, "AOD", "LFHE3V0", 1, lfv0he3::LFEventId, lfv0he3::Pt, lfv0he3::Eta, lfv0he3::Phi, lfv0he3::DCAxy, lfv0he3::DCAz, lfv0he3::TPCnCls, lfv0he3::TPCnClsPID, lfv0he3::ITSClusterSizes, lfv0he3::NsigmaTPC, lfv0he3::Sign); DECLARE_SOA_TABLE_VERSIONED(LFLambda_001, "AOD", "LFLAMBDA", 1, lfv0he3::LFEventId, lfv0he3::Pt, lfv0he3::Eta, lfv0he3::Phi, lfv0he3::Mass, lfv0he3::CosPA, lfv0he3::DCAdaughters, lfv0he3::DCAPVProton, lfv0he3::DCAPVPion, lfv0he3::V0Radius, lfv0he3::NsigmaTPCProton, lfv0he3::NsigmaTPCPion, lfv0he3::Sign); +DECLARE_SOA_TABLE(LFK0s, "AOD", "LFK0S", lfv0he3::LFEventId, lfv0he3::Pt, lfv0he3::Eta, lfv0he3::Phi, lfv0he3::Mass, lfv0he3::Ct, lfv0he3::CosPA, lfv0he3::DCAdaughters, lfv0he3::DCAPVPos, lfv0he3::DCAPVNeg, lfv0he3::V0Radius, lfv0he3::NsigmaTPCPosPion, lfv0he3::NsigmaTPCNegPion); } // namespace o2::aod struct he3Candidate { @@ -87,4 +93,17 @@ struct lambdaCandidate { int8_t sign = 0; // Charge sign of the Lambda candidate }; +struct k0sCandidate { + ROOT::Math::LorentzVector> momentum; + float mass = -1.f; + float ct = -1.f; // Proper decay length in cm + float cosPA = -2.f; + float dcaV0Daughters = -999.f; + float dcaPosToPV = -999.f; + float dcaNegToPV = -999.f; + float v0Radius = -1.f; + float posPionNSigmaTPC = -999.f; + float negPionNSigmaTPC = -999.f; +}; + #endif // PWGLF_DATAMODEL_LFSLIMHELAMBDA_H_ diff --git a/PWGLF/TableProducer/Nuspex/he3LambdaAnalysis.cxx b/PWGLF/TableProducer/Nuspex/he3LambdaAnalysis.cxx index 01411e4e566..293733ad9c5 100644 --- a/PWGLF/TableProducer/Nuspex/he3LambdaAnalysis.cxx +++ b/PWGLF/TableProducer/Nuspex/he3LambdaAnalysis.cxx @@ -56,7 +56,7 @@ using namespace o2::framework::expressions; using namespace o2::constants::physics; namespace { -constexpr double betheBlochDefault[1][6]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}; +constexpr std::array betheBlochDefault[1]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}; static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; static const std::vector particleName{"He3"}; o2::base::MatLayerCylSet* matLUT = nullptr; @@ -101,6 +101,9 @@ struct he3LambdaAnalysis { Produces lfHe3V0Collision; Produces lfHe3; Produces lfLambda; + Produces lfK0s; + + Configurable cfgStoreK0s{"cfgStoreK0s", false, "Select and store K0s candidates, including He3-K0s events without a selected Lambda"}; // Configurables for event selection struct : ConfigurableGroup { @@ -122,7 +125,7 @@ struct he3LambdaAnalysis { Configurable dcazMax{"dcazMax", 0.5f, "Maximum He3 DCA z"}; Configurable tpcClusMin{"tpcClusMin", 100, "Minimum He3 TPC clusters"}; Configurable itsClusMin{"itsClusMin", 5, "Minimum He3 ITS clusters"}; - Configurable> betheBlochParams{"betheBlochParams", {betheBlochDefault[0], 1, 6, particleName, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for He3"}; + Configurable> betheBlochParams{"betheBlochParams", {betheBlochDefault[0].data(), 1, 6, particleName, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for He3"}; } cfgHe3; // Lambda selection criteria @@ -131,6 +134,8 @@ struct he3LambdaAnalysis { Configurable ptMin{"ptMin", 0.5f, "Minimum Lambda pT"}; Configurable ptMax{"ptMax", 10.0f, "Maximum Lambda pT"}; Configurable massWindow{"massWindow", 0.015f, "Lambda mass window"}; + Configurable ctMin{"ctMin", 0.f, "Minimum Lambda proper decay length (cm)"}; + Configurable ctMax{"ctMax", 30.f, "Maximum Lambda proper decay length (cm)"}; Configurable cosPAMin{"cosPAMin", 0.99f, "Minimum Lambda cosPA"}; Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.5f, "Maximum Lambda DCA V0 daughters"}; Configurable v0RadiusMin{"v0RadiusMin", 0.5f, "Minimum Lambda V0 radius"}; @@ -140,6 +145,22 @@ struct he3LambdaAnalysis { Configurable pionNSigmaTPCMax{"pionNSigmaTPCMax", 4.0f, "Maximum pion TPC nSigma"}; } cfgLambda; + // K0s selection criteria + struct : ConfigurableGroup { + std::string prefix = "cfgK0s"; + Configurable ptMin{"ptMin", 0.5f, "Minimum K0s pT"}; + Configurable ptMax{"ptMax", 10.f, "Maximum K0s pT"}; + Configurable massWindow{"massWindow", 0.015f, "K0s mass window"}; + Configurable ctMin{"ctMin", 0.f, "Minimum K0s proper decay length (cm)"}; + Configurable ctMax{"ctMax", 20.f, "Maximum K0s proper decay length (cm)"}; + Configurable cosPAMin{"cosPAMin", 0.99f, "Minimum K0s cosPA"}; + Configurable dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.5f, "Maximum K0s DCA V0 daughters"}; + Configurable v0RadiusMin{"v0RadiusMin", 0.5f, "Minimum K0s V0 radius"}; + Configurable v0RadiusMax{"v0RadiusMax", 35.f, "Maximum K0s V0 radius"}; + Configurable tpcNClsMin{"tpcNClsMin", 70, "Minimum TPC clusters for K0s daughters"}; + Configurable pionNSigmaTPCMax{"pionNSigmaTPCMax", 4.f, "Maximum pion TPC nSigma"}; + } cfgK0s; + // Pair selection criteria struct : ConfigurableGroup { std::string prefix = "cfgPair"; @@ -156,7 +177,7 @@ struct he3LambdaAnalysis { Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; } ccdbOptions; - std::array mBBparamsHe; + std::array mBBparamsHe = betheBlochDefault[0]; float mBz = 0.0f; // Magnetic field in T HistogramRegistry mRegistry{"He3LambdaAnalysis"}; int mRunNumber = 0; // Current run number @@ -186,7 +207,7 @@ struct he3LambdaAnalysis { zorroSummary.setObject(zorro.getZorroSummary()); mRegistry.add("hEventSelection", "Event Selection", {HistType::kTH1L, {{6, -.5, 5.5}}}); - std::vector labels{"Total Events", "Sel8 Events", "Z-Vertex OK", "Additional Event Selections", "He3 Candidates Found", "He3 and Lambda Candidates Found"}; + std::vector labels{"Total Events", "Sel8 Events", "Z-Vertex OK", "Additional Event Selections", "He3 Candidates Found", "He3 and V0 Candidates Found"}; for (size_t i = 1; i <= labels.size(); ++i) { mRegistry.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(i, labels[i - 1].c_str()); } @@ -203,6 +224,8 @@ struct he3LambdaAnalysis { hArmenterosPodolanskiAll = mRegistry.add("hArmenterosPodolanskiAll", "Armenteros-Podolanski All", {HistType::kTH2D, {{100, -1., 1.}, {100, 0., 0.5}}}); hArmenterosPodolanskiSelected = mRegistry.add("hArmenterosPodolanskiSelected", "Armenteros-Podolanski Selected", {HistType::kTH2D, {{100, -1., 1.}, {100, 0., 0.5}}}); + mRegistry.add("hMassK0s", "Selected K0s;pT (GeV/c);mass (GeV/c^{2})", {HistType::kTH2F, {{100, 0., 10.}, {100, MassK0Short - 0.025, MassK0Short + 0.025}}}); + constexpr double ConstituentsMass = o2::constants::physics::MassProton + o2::constants::physics::MassNeutron * 2 + o2::constants::physics::MassSigmaPlus; hInvariantMassUS = mRegistry.add("hInvariantMassUS", "Invariant Mass", {HistType::kTH2D, {{45, 1., 10}, {100, ConstituentsMass - 0.05, ConstituentsMass + 0.05}}}); hInvariantMassLS = mRegistry.add("hInvariantMassLS", "Invariant Mass", {HistType::kTH2D, {{45, 1., 10}, {100, ConstituentsMass - 0.05, ConstituentsMass + 0.05}}}); @@ -298,8 +321,9 @@ struct he3LambdaAnalysis { } mRegistry.get(HIST("hEventSelection"))->Fill(4); // He3 candidates found - // Process Lambda candidates + // Fit each V0 once and evaluate the K0s and Lambda hypotheses independently. std::vector lambdaCandidates; + std::vector k0sCandidates; for (auto const& v0 : v0s) { if (v0.v0Type() != 1) { continue; @@ -307,7 +331,9 @@ struct he3LambdaAnalysis { const auto posTrack = v0.posTrack_as(); const auto negTrack = v0.negTrack_as(); - if (posTrack.tpcNClsFound() < cfgLambda.tpcNClsMin || negTrack.tpcNClsFound() < cfgLambda.tpcNClsMin) { + const bool lambdaTrackQuality = posTrack.tpcNClsFound() >= cfgLambda.tpcNClsMin && negTrack.tpcNClsFound() >= cfgLambda.tpcNClsMin; + const bool k0sTrackQuality = cfgStoreK0s && posTrack.tpcNClsFound() >= cfgK0s.tpcNClsMin && negTrack.tpcNClsFound() >= cfgK0s.tpcNClsMin; + if (!lambdaTrackQuality && !k0sTrackQuality) { continue; // Skip V0s with insufficient TPC clusters } auto trackParPos = getTrackParCov(posTrack); @@ -332,6 +358,49 @@ struct he3LambdaAnalysis { float qt = qtAP(momV0, momPos); hArmenterosPodolanskiAll->Fill(alpha, qt); + const auto sv = fitter.getPCACandidate(0); + const float decayLength = std::hypot(sv[0] - collVtx.x(), sv[1] - collVtx.y(), sv[2] - collVtx.z()); + const float momentum = std::hypot(momV0[0], momV0[1], momV0[2]); + if (momentum <= 0.f || decayLength <= 0.f) { + continue; + } + const float cosPA = ((sv[0] - collVtx.x()) * momV0[0] + (sv[1] - collVtx.y()) * momV0[1] + (sv[2] - collVtx.z()) * momV0[2]) / (decayLength * momentum); + const float dcaDaughters = std::sqrt(fitter.getChi2AtPCACandidate(0)); + const float radius = std::hypot(sv[0], sv[1]); + std::array dcaInfoPos{}, dcaInfoNeg{}; + if (!o2::base::Propagator::Instance()->propagateToDCA(collVtx, trackParPos, mBz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dcaInfoPos) || + !o2::base::Propagator::Instance()->propagateToDCA(collVtx, trackParNeg, mBz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dcaInfoNeg)) { + continue; + } + + ROOT::Math::LorentzVector> posPionMom4D(momPos[0], momPos[1], momPos[2], MassPionCharged); + ROOT::Math::LorentzVector> negPionMom4D(momNeg[0], momNeg[1], momNeg[2], MassPionCharged); + const auto k0sMom4D = posPionMom4D + negPionMom4D; + const float ctK0s = decayLength * MassK0Short / momentum; + if (k0sTrackQuality && std::abs(posTrack.tpcNSigmaPi()) <= cfgK0s.pionNSigmaTPCMax && std::abs(negTrack.tpcNSigmaPi()) <= cfgK0s.pionNSigmaTPCMax && + std::abs(k0sMom4D.M() - MassK0Short) <= cfgK0s.massWindow && k0sMom4D.Pt() >= cfgK0s.ptMin && k0sMom4D.Pt() <= cfgK0s.ptMax && + ctK0s >= cfgK0s.ctMin && ctK0s <= cfgK0s.ctMax && cosPA >= cfgK0s.cosPAMin && dcaDaughters <= cfgK0s.dcaV0DaughtersMax && + radius >= cfgK0s.v0RadiusMin && radius <= cfgK0s.v0RadiusMax) { + k0sCandidate candidate; + candidate.momentum.SetCoordinates(k0sMom4D.Pt(), k0sMom4D.Eta(), k0sMom4D.Phi(), MassK0Short); + candidate.mass = k0sMom4D.M(); + candidate.ct = ctK0s; + candidate.cosPA = cosPA; + candidate.dcaV0Daughters = dcaDaughters; + candidate.dcaPosToPV = std::hypot(dcaInfoPos[0], dcaInfoPos[1]); + candidate.dcaNegToPV = std::hypot(dcaInfoNeg[0], dcaInfoNeg[1]); + candidate.v0Radius = radius; + candidate.posPionNSigmaTPC = posTrack.tpcNSigmaPi(); + candidate.negPionNSigmaTPC = negTrack.tpcNSigmaPi(); + k0sCandidates.push_back(candidate); + mRegistry.fill(HIST("hMassK0s"), k0sMom4D.Pt(), candidate.mass); + } + + const float ctLambda = decayLength * MassLambda0 / momentum; + if (!lambdaTrackQuality || ctLambda < cfgLambda.ctMin || ctLambda > cfgLambda.ctMax || cosPA < cfgLambda.cosPAMin || + dcaDaughters > cfgLambda.dcaV0DaughtersMax || radius < cfgLambda.v0RadiusMin || radius > cfgLambda.v0RadiusMax) { + continue; + } bool matter = alpha > 0; const auto& protonTrack = matter ? posTrack : negTrack; const auto& pionTrack = matter ? negTrack : posTrack; @@ -347,37 +416,30 @@ struct he3LambdaAnalysis { auto lambdaMom4D = protonMom4D + pionMom4D; float massLambda = lambdaMom4D.M(); - if (std::abs(massLambda - o2::constants::physics::MassLambda0) > cfgLambda.massWindow) { + if (std::abs(massLambda - o2::constants::physics::MassLambda0) > cfgLambda.massWindow || lambdaMom4D.Pt() < cfgLambda.ptMin || lambdaMom4D.Pt() > cfgLambda.ptMax) { continue; // Skip V0s outside mass window } hArmenterosPodolanskiSelected->Fill(alpha, qt); - std::array dcaInfoProton, dcaInfoPion; - o2::base::Propagator::Instance()->propagateToDCA(collVtx, matter ? trackParPos : trackParNeg, mBz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dcaInfoProton); - o2::base::Propagator::Instance()->propagateToDCA(collVtx, matter ? trackParNeg : trackParPos, mBz, 2.f, o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dcaInfoPion); - - const auto sv = fitter.getPCACandidate(0); - + const auto& dcaInfoProton = matter ? dcaInfoPos : dcaInfoNeg; + const auto& dcaInfoPion = matter ? dcaInfoNeg : dcaInfoPos; lambdaCandidate candidate; - candidate.momentum.SetCoordinates(lambdaMom4D.Pt(), lambdaMom4D.Eta(), lambdaMom4D.Phi(), o2::constants::physics::MassLambda0); + candidate.momentum.SetCoordinates(lambdaMom4D.Pt(), lambdaMom4D.Eta(), lambdaMom4D.Phi(), MassLambda0); candidate.mass = massLambda; - candidate.cosPA = (sv[0] - collVtx.x()) * lambdaMom4D.Px() + - (sv[1] - collVtx.y()) * lambdaMom4D.Py() + - (sv[2] - collVtx.z()) * lambdaMom4D.Pz(); - candidate.cosPA /= std::hypot(sv[0] - collVtx.x(), sv[1] - collVtx.y(), sv[2] - collVtx.z()) * lambdaMom4D.P(); - candidate.dcaV0Daughters = std::sqrt(fitter.getChi2AtPCACandidate(0)); + candidate.cosPA = cosPA; + candidate.dcaV0Daughters = dcaDaughters; candidate.dcaProtonToPV = std::hypot(dcaInfoProton[0], dcaInfoProton[1]); candidate.dcaPionToPV = std::hypot(dcaInfoPion[0], dcaInfoPion[1]); - candidate.v0Radius = std::hypot(sv[0], sv[1]); + candidate.v0Radius = radius; candidate.protonNSigmaTPC = protonTrack.tpcNSigmaPr(); candidate.pionNSigmaTPC = pionTrack.tpcNSigmaPi(); candidate.sign = matter ? 1 : -1; // Positive sign for Lambda, negative for anti-Lambda lambdaCandidates.push_back(candidate); } - if (lambdaCandidates.empty()) { - return; // No valid Lambda candidates found + if (lambdaCandidates.empty() && (!cfgStoreK0s || k0sCandidates.empty())) { + return; // Require a Lambda, or a K0s when cfgStoreK0s is enabled } - mRegistry.get(HIST("hEventSelection"))->Fill(5); // He3 and Lambda candidates found + mRegistry.get(HIST("hEventSelection"))->Fill(5); // He3 and V0 candidates found mRegistry.get(HIST("hCentralitySelected"))->Fill(collision.centFT0C()); // Fill output tables @@ -386,6 +448,10 @@ struct he3LambdaAnalysis { lfHe3(lfHe3V0Collision.lastIndex(), he3.momentum.Pt(), he3.momentum.Eta(), he3.momentum.Phi(), he3.dcaXY, he3.dcaZ, he3.tpcNClsFound, he3.tpcNClsPID, he3.itsClusterSizes, he3.nSigmaTPC, he3.sign); } + for (const auto& k0s : k0sCandidates) { + lfK0s(lfHe3V0Collision.lastIndex(), k0s.momentum.Pt(), k0s.momentum.Eta(), k0s.momentum.Phi(), + k0s.mass, k0s.ct, k0s.cosPA, k0s.dcaV0Daughters, k0s.dcaPosToPV, k0s.dcaNegToPV, k0s.v0Radius, k0s.posPionNSigmaTPC, k0s.negPionNSigmaTPC); + } for (const auto& lambda : lambdaCandidates) { lfLambda(lfHe3V0Collision.lastIndex(), lambda.momentum.Pt(), lambda.momentum.Eta(), lambda.momentum.Phi(), lambda.mass, lambda.cosPA, lambda.dcaV0Daughters, lambda.dcaProtonToPV, lambda.dcaPionToPV, lambda.v0Radius, lambda.protonNSigmaTPC, lambda.pionNSigmaTPC, lambda.sign); diff --git a/PWGLF/Tasks/Nuspex/he3LambdaDerivedAnalysis.cxx b/PWGLF/Tasks/Nuspex/he3LambdaDerivedAnalysis.cxx index afe3814afd9..52b0e7cc552 100644 --- a/PWGLF/Tasks/Nuspex/he3LambdaDerivedAnalysis.cxx +++ b/PWGLF/Tasks/Nuspex/he3LambdaDerivedAnalysis.cxx @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -42,6 +43,11 @@ std::shared_ptr hInvariantMassLambda[2]; std::shared_ptr hCosPALambda; std::shared_ptr hNsigmaHe3; std::shared_ptr hNsigmaProton; +std::shared_ptr hInvariantMassHe3K0s[2]; // 0: anti-He3, 1: He3 +std::shared_ptr hRotationInvariantMassHe3K0s[2]; +std::shared_ptr hInvariantMassK0s[2]; // Before and after selection +std::shared_ptr hCosPAK0s; +std::shared_ptr hCtK0s; }; // namespace using namespace o2; @@ -59,6 +65,15 @@ struct he3LambdaDerivedAnalysis { Configurable cfgMinLambdaPt{"cfgMinLambdaPt", 0.4, "Minimum pT for Lambda candidates"}; Configurable cfgMaxLambdaDeltaM{"cfgMaxLambdaDeltaM", 10.0e-3, "Maximum deltaM for Lambda candidates"}; + Configurable cfgMinK0sPt{"cfgMinK0sPt", 0.5f, "Minimum K0s pT"}; + Configurable cfgMaxK0sPt{"cfgMaxK0sPt", 10.f, "Maximum K0s pT"}; + Configurable cfgMinK0sCt{"cfgMinK0sCt", 0.f, "Minimum K0s proper decay length (cm)"}; + Configurable cfgMaxK0sCt{"cfgMaxK0sCt", 20.f, "Maximum K0s proper decay length (cm)"}; + Configurable cfgMinK0sCosPA{"cfgMinK0sCosPA", 0.99f, "Minimum K0s cosPA"}; + Configurable cfgMaxK0sDeltaM{"cfgMaxK0sDeltaM", 10.e-3f, "Maximum K0s mass deviation (GeV/c^2)"}; + Configurable cfgMaxNSigmaTPCPionK0s{"cfgMaxNSigmaTPCPionK0s", 4.f, "Maximum daughter pion TPC nSigma for K0s"}; + ConfigurableAxis cfgHe3K0sMassAxis{"cfgHe3K0sMassAxis", {200, MassHelium3 + MassK0Short, MassHelium3 + MassK0Short + 1.}, "He3-K0s pair invariant mass (GeV/c^2)"}; + void init(InitContext const&) { constexpr double ConstituentsMass = o2::constants::physics::MassProton + o2::constants::physics::MassNeutron * 2 + o2::constants::physics::MassSigmaPlus; @@ -70,12 +85,26 @@ struct he3LambdaDerivedAnalysis { hInvariantMassLambda[i] = mRegistry.add(Form("hInvariantMassLambda%i", i), "Invariant Mass Lambda", {HistType::kTH2D, {{50, 0., 10.}, {30, o2::constants::physics::MassLambda0 - 0.015, o2::constants::physics::MassLambda0 + 0.015}}}); hRotationInvariantMassAntiLSeta[i] = mRegistry.add(Form("hRotationInvariantMassAntiLSeta%i", i), "Rotation Invariant Mass Anti-Lambda", {HistType::kTH2D, {{45, 1., 10}, {100, ConstituentsMass - 0.05, ConstituentsMass + 0.05}}}); } + if (doprocessSameEvent && doprocessSameEventLegacy) { + LOG(fatal) << "Enable only one Lambda table version: processSameEvent or processSameEventLegacy"; + } + if (doprocessK0s) { + const AxisSpec pairMassAxis{cfgHe3K0sMassAxis, "m(He3 K0s) (GeV/c^{2})"}; + for (int i = 0; i < 2; ++i) { + hInvariantMassHe3K0s[i] = mRegistry.add(Form("hInvariantMassHe3K0s%i", i), "Same-event He3-K0s", {HistType::kTH2D, {{45, 1., 10.}, pairMassAxis}}); + hRotationInvariantMassHe3K0s[i] = mRegistry.add(Form("hRotationInvariantMassHe3K0s%i", i), "Rotated He3-K0s", {HistType::kTH2D, {{45, 1., 10.}, pairMassAxis}}); + hInvariantMassK0s[i] = mRegistry.add(Form("hInvariantMassK0s%i", i), "K0s;pT (GeV/c);mass (GeV/c^{2})", {HistType::kTH2D, {{50, 0., 10.}, {100, MassK0Short - 0.015, MassK0Short + 0.015}}}); + } + hCosPAK0s = mRegistry.add("hCosPAK0s", "K0s;pT (GeV/c);cosPA", {HistType::kTH2D, {{50, 0., 10.}, {500, 0.9, 1.}}}); + hCtK0s = mRegistry.add("hCtK0s", "K0s;pT (GeV/c);ct (cm)", {HistType::kTH2D, {{50, 0., 10.}, {100, 0., 30.}}}); + } hCosPALambda = mRegistry.add("hCosPALambda", "Cosine of Pointing Angle for Lambda", {HistType::kTH2D, {{50, 0., 10.}, {500, 0.9, 1.}}}); hNsigmaHe3 = mRegistry.add("hNsigmaHe3", "nSigma TPC for He3", {HistType::kTH2D, {{100, -10., 10.}, {200, -5, 5.}}}); hNsigmaProton = mRegistry.add("hNsigmaProton", "nSigma TPC for Proton", {HistType::kTH2D, {{100, -10., 10.}, {200, -5, 5.}}}); } - void processSameEvent(o2::aod::LFEvents::iterator const& collision, o2::aod::LFHe3_000 const& he3s, o2::aod::LFLambda_000 const& lambdas) + template + void analyseLambda(o2::aod::LFEvents::iterator const& collision, He3Table const& he3s, LambdaTable const& lambdas) { std::vector he3Candidates; he3Candidates.reserve(he3s.size()); @@ -111,6 +140,7 @@ struct he3LambdaDerivedAnalysis { candidate.mass = lambda.mass(); candidate.cosPA = lambda.cosPA(); candidate.dcaV0Daughters = lambda.dcaDaughters(); + candidate.sign = lambda.sign(); hCosPALambda->Fill(lambda.pt(), candidate.cosPA); // hNsigmaProton->Fill(lambda.pt() * lambda.sign(), lambda.protonNSigmaTPC()); hInvariantMassLambda[0]->Fill(lambda.pt(), lambda.mass()); @@ -128,7 +158,7 @@ struct he3LambdaDerivedAnalysis { (he3.sign * lambda.sign > 0 ? hInvariantMassLS : hInvariantMassUS)[he3.sign > 0]->Fill(pairMomentum.Pt(), pairMomentum.M()); } for (int iEta{0}; iEta <= cfgMirrorEta; ++iEta) { - for (int iR{0}; iR <= cfgNrotations; ++iR) { + for (int iR{0}; cfgNrotations > 0 && iR <= cfgNrotations; ++iR) { auto he3Momentum = ROOT::Math::LorentzVector>(he3.momentum.Pt(), (1. - iEta * 2.) * he3.momentum.Eta(), he3.momentum.Phi() + TMath::Pi() * (0.75 + 0.5 * iR / cfgNrotations), he3.momentum.M()); for (const auto& lambda : lambdaCandidates) { auto pairMomentum = lambda.momentum + he3Momentum; // Calculate invariant mass @@ -141,7 +171,63 @@ struct he3LambdaDerivedAnalysis { } } } - PROCESS_SWITCH(he3LambdaDerivedAnalysis, processSameEvent, "Process same event", true); + void processSameEvent(o2::aod::LFEvents::iterator const& collision, o2::aod::LFHe3_001 const& he3s, o2::aod::LFLambda_001 const& lambdas) + { + analyseLambda(collision, he3s, lambdas); + } + PROCESS_SWITCH(he3LambdaDerivedAnalysis, processSameEvent, "Process same-event He3-Lambda pairs (version 001)", true); + + void processSameEventLegacy(o2::aod::LFEvents::iterator const& collision, o2::aod::LFHe3_000 const& he3s, o2::aod::LFLambda_000 const& lambdas) + { + analyseLambda(collision, he3s, lambdas); + } + PROCESS_SWITCH(he3LambdaDerivedAnalysis, processSameEventLegacy, "Process same-event He3-Lambda pairs (version 000)", false); + + void processK0s(o2::aod::LFEvents::iterator const&, o2::aod::LFHe3_001 const& he3s, o2::aod::LFK0s const& k0ss) + { + std::vector k0sCandidates; + k0sCandidates.reserve(k0ss.size()); + for (const auto& k0s : k0ss) { + hInvariantMassK0s[0]->Fill(k0s.pt(), k0s.mass()); + hCosPAK0s->Fill(k0s.pt(), k0s.cosPA()); + hCtK0s->Fill(k0s.pt(), k0s.ct()); + if (k0s.pt() < cfgMinK0sPt || k0s.pt() > cfgMaxK0sPt || k0s.ct() < cfgMinK0sCt || k0s.ct() > cfgMaxK0sCt || + k0s.cosPA() < cfgMinK0sCosPA || std::abs(k0s.mass() - MassK0Short) > cfgMaxK0sDeltaM || + std::abs(k0s.nSigmaTPCPosPion()) > cfgMaxNSigmaTPCPionK0s || std::abs(k0s.nSigmaTPCNegPion()) > cfgMaxNSigmaTPCPionK0s) { + continue; + } + k0sCandidate candidate; + // Use the nominal K0s mass for pair kinematics, as for Lambda. + candidate.momentum.SetCoordinates(k0s.pt(), k0s.eta(), k0s.phi(), MassK0Short); + k0sCandidates.push_back(candidate); + hInvariantMassK0s[1]->Fill(k0s.pt(), k0s.mass()); + } + for (const auto& he3 : he3s) { + if (!doprocessSameEvent && !doprocessSameEventLegacy) { + hNsigmaHe3->Fill(he3.pt() * he3.sign(), he3.nSigmaTPC()); + } + if (std::abs(he3.nSigmaTPC()) > cfgMaxNSigmaTPCHe3) { + continue; + } + const ROOT::Math::LorentzVector> he3Momentum(he3.pt(), he3.eta(), he3.phi(), MassHelium3); + const int signIndex = he3.sign() > 0; + for (const auto& k0s : k0sCandidates) { + const auto pairMomentum = he3Momentum + k0s.momentum; + hInvariantMassHe3K0s[signIndex]->Fill(pairMomentum.Pt(), pairMomentum.M()); + } + // Match the Lambda background's rotation angles and optional eta mirroring. + for (int iEta = 0; iEta <= cfgMirrorEta; ++iEta) { + for (int iR = 0; cfgNrotations > 0 && iR <= cfgNrotations; ++iR) { + const ROOT::Math::LorentzVector> rotatedHe3(he3.pt(), (1. - iEta * 2.) * he3.eta(), he3.phi() + TMath::Pi() * (0.75 + 0.5 * iR / cfgNrotations), MassHelium3); + for (const auto& k0s : k0sCandidates) { + const auto pairMomentum = rotatedHe3 + k0s.momentum; + hRotationInvariantMassHe3K0s[signIndex]->Fill(pairMomentum.Pt(), pairMomentum.M()); + } + } + } + } + } + PROCESS_SWITCH(he3LambdaDerivedAnalysis, processK0s, "Process same-event He3-K0s pairs (version 001)", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)