From f41cbc66fbb68d3ce5de240120f118c3e24f716b Mon Sep 17 00:00:00 2001 From: ariedel-cern <85537041+ariedel-cern@users.noreply.github.com> Date: Mon, 27 Jul 2026 13:08:45 +0200 Subject: [PATCH 01/71] [PWGCF] Add pt getters to lite femto tables (#17209) Co-authored-by: ALICE Action Bot --- PWGCF/Femto/Core/femtoUtils.h | 2 -- PWGCF/Femto/DataModel/FemtoTables.h | 30 +++++++++++++++---- .../femtoProducerLiteConverter.cxx | 3 +- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/PWGCF/Femto/Core/femtoUtils.h b/PWGCF/Femto/Core/femtoUtils.h index bab26c453e5..aae51de32c9 100644 --- a/PWGCF/Femto/Core/femtoUtils.h +++ b/PWGCF/Femto/Core/femtoUtils.h @@ -24,8 +24,6 @@ #include -#include - #include #include #include diff --git a/PWGCF/Femto/DataModel/FemtoTables.h b/PWGCF/Femto/DataModel/FemtoTables.h index 3e0ed2911ad..d8c30322a49 100644 --- a/PWGCF/Femto/DataModel/FemtoTables.h +++ b/PWGCF/Femto/DataModel/FemtoTables.h @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -234,10 +233,6 @@ DECLARE_SOA_DYNAMIC_COLUMN(SignedPt, signedPt, [](uint16_t signedBinnedPt) -> float { return unBinSignedPt(signedBinnedPt); }); -DECLARE_SOA_DYNAMIC_COLUMN(UnsignedPt, unsignedPt, - [](uint16_t unsignedBinnedPt) -> float { - return unBinUnsignedPt(unsignedBinnedPt); - }); DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](uint16_t binnedEta) -> float { return unBinEta(binnedEta); @@ -246,6 +241,23 @@ DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, [](uint16_t binnedPhi) -> float { return unBinPhi(binnedPhi); }); + +namespace signedpt +{ +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, + [](uint16_t signedBinnedPt) -> float { + return std::fabs(unBinSignedPt(signedBinnedPt)); + }); +} // namespace signedpt + +namespace unsignedpt +{ +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, + [](uint16_t unsignedBinnedPt) -> float { + return unBinUnsignedPt(unsignedBinnedPt); + }); +} // namespace unsignedpt + } // namespace lite } // namespace femtobase @@ -355,6 +367,7 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteTracks_001, "FLITETRACK", 1, //! femto t femtobase::lite::BinnedPhi, femtobase::lite::Sign, femtobase::lite::SignedPt, + femtobase::lite::signedpt::Pt, femtobase::lite::Eta, femtobase::lite::Phi); using FLiteTracks = FLiteTracks_001; @@ -628,6 +641,7 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteLambdas_001, "FLITELAMBDA", 1, femtov0s::lite::NegDauId, femtobase::lite::Sign, femtobase::lite::SignedPt, + femtobase::lite::signedpt::Pt, femtobase::lite::Eta, femtobase::lite::Phi, femtov0s::lite::LambdaMass); @@ -681,7 +695,7 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteK0shorts_001, "FLITEK0SHORT", 1, femtov0s::lite::BinnedK0shortMass, femtov0s::lite::PosDauId, femtov0s::lite::NegDauId, - femtobase::lite::UnsignedPt, + femtobase::lite::unsignedpt::Pt, femtobase::lite::Eta, femtobase::lite::Phi, femtov0s::lite::K0shortMass); @@ -795,6 +809,7 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteSigmas_001, "FLITESIGMA", 1, femtokinks::lite::ChaDauId, femtobase::lite::Sign, femtobase::lite::SignedPt, + femtobase::lite::signedpt::Pt, femtobase::lite::Eta, femtobase::lite::Phi, femtokinks::lite::SigmaMass); @@ -850,6 +865,7 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteSigmaPlus_001, "FLITESIGMAPLUS", 1, femtokinks::lite::ChaDauId, femtobase::lite::Sign, femtobase::lite::SignedPt, + femtobase::lite::signedpt::Pt, femtobase::lite::Eta, femtobase::lite::Phi, femtokinks::lite::SigmaMass); @@ -963,6 +979,7 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteXis_001, "FLITEXI", 1, femtov0s::lite::NegDauId, femtobase::lite::Sign, femtobase::lite::SignedPt, + femtobase::lite::signedpt::Pt, femtobase::lite::Eta, femtobase::lite::Phi, femtocascades::lite::XiMass); @@ -1021,6 +1038,7 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteOmegas_001, "FLITEOMEGA", 1, femtov0s::lite::NegDauId, femtobase::lite::Sign, femtobase::lite::SignedPt, + femtobase::lite::signedpt::Pt, femtobase::lite::Eta, femtobase::lite::Phi, femtocascades::lite::OmegaMass); diff --git a/PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx b/PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx index 5f4ca499cb1..3a5add169c1 100644 --- a/PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -70,7 +71,7 @@ struct FemtoProducerLiteConverter { void processLiteK0shorts(o2::aod::FLiteK0shorts::iterator const& liteK0short) { producedK0shorts(liteK0short.fLiteColId(), - liteK0short.unsignedPt(), + liteK0short.pt(), liteK0short.eta(), liteK0short.phi(), liteK0short.k0shortMass(), From 09f22687615a267ba33ea07e7ad45d0ce14ee3db Mon Sep 17 00:00:00 2001 From: abmodak <67369858+abmodak@users.noreply.github.com> Date: Mon, 27 Jul 2026 19:18:05 +0530 Subject: [PATCH 02/71] [PWGLF] Fix histogram name (#17218) --- PWGLF/Tasks/GlobalEventProperties/nchStudypp.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PWGLF/Tasks/GlobalEventProperties/nchStudypp.cxx b/PWGLF/Tasks/GlobalEventProperties/nchStudypp.cxx index 0518ebe9f9f..ddd61749b7e 100644 --- a/PWGLF/Tasks/GlobalEventProperties/nchStudypp.cxx +++ b/PWGLF/Tasks/GlobalEventProperties/nchStudypp.cxx @@ -257,7 +257,7 @@ struct NchStudypp { histos.add("hgendndetaVsMultEta05BeforeEvtSel", "hgendndetaBeforeEvtSel vs multiplicity in eta<0.5", kTH2F, {axisEta, multAxis}); histos.add("hgendndetaVsMultEta05AfterEvtSel", "hgendndetaAfterEvtSel vs multiplicity in eta<0.5", kTH2F, {axisEta, multAxis}); histos.add("hGenCent", "Centrality of generated MC events", kTH1F, {axisCent}); - histos.add("hGenAssoRecCent", "Centrality of selected MC events", kTH1F, {axisCent}); + histos.add("hGenAssocRecCent", "Centrality of selected MC events", kTH1F, {axisCent}); histos.add("hgendndetaBeforeEvtSel", "Eta of all generated particles", kTH1F, {axisEta}); histos.add("hgendndetaAfterEvtSel", "Eta of generated particles after EvtSel", kTH1F, {axisEta}); histos.add("hgendndetaVscentBeforeEvtSel", "hgendndetaBeforeEvtSel vs centrality", kTH2F, {axisEta, centAxis}); From 77adbd617128c90bebe9d206347b9541ba17c5c4 Mon Sep 17 00:00:00 2001 From: Giorgio Alberto Lucia <87222843+GiorgioAlbertoLucia@users.noreply.github.com> Date: Mon, 27 Jul 2026 16:28:57 +0200 Subject: [PATCH 03/71] [PWGLF] kstar histogram now filling, solved several linter issues (#17222) --- PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx | 81 +++++++++++-------- 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx b/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx index ea949a1f889..9c6f3726235 100644 --- a/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx +++ b/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx @@ -150,13 +150,13 @@ constexpr std::array, static_cast(Species::kAllSpecie {-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}, // He3 {-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32} // hadron }}; -static const std::vector kItsParNames{"p0", "p1", "p2", "res0", "res1", "res2"}; +const std::vector kItsParNames{"p0", "p1", "p2", "res0", "res1", "res2"}; constexpr std::array, 1> kBetheBlochDefault = {{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}}; -static const std::vector kBetheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; +const std::vector kBetheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; constexpr std::array, 1> kBetheBlochCorrectionDefault = {{{0.0, -1.e32, -1.e32, 0.0, -1.e32, -1.e32}}}; -static const std::vector kBetheBlochCorrectionParNames{"p0", "p1", "p2", "p3", "p4", "p5"}; +const std::vector kBetheBlochCorrectionParNames{"p0", "p1", "p2", "p3", "p4", "p5"}; constexpr std::array, static_cast(Species::kAllSpecies)> kDCAxyResDefault = {{ {1.09e-4, 0.0011, 0.0065, 1.0399}, // He3 @@ -166,7 +166,7 @@ constexpr std::array, static_cast(Species::kAllSpecie {9.36e-5, 0.0019, 0.0080, 1.416}, // He3 {1.18e-4, 0.0020, 0.0025, 1.3460} // Pr }}; -static const std::vector kDCAResParNames{"res0", "res1", "res2", "mean"}; +const std::vector kDCAResParNames{"res0", "res1", "res2", "mean"}; constexpr std::array kHePidTrkPtParamsHeDefault = {0.3101, -0.1759, 0.0262}; constexpr std::array kHePidTrkPParamsHeDefault = {0., 0., 0.}; @@ -175,12 +175,14 @@ constexpr std::array kHePidTrkPParamsHeDefault = {0., 0., 0.}; struct He3HadCandidate { - float recoPtHe3() const { return signHe3 * std::hypot(momHe3[0], momHe3[1]); } - float recoPhiHe3() const { return std::atan2(momHe3[1], momHe3[0]); } - float recoEtaHe3() const { return std::asinh(momHe3[2] / std::abs(recoPtHe3())); } - float recoPtHad() const { return signHad * std::hypot(momHad[0], momHad[1]); } - float recoPhiHad() const { return std::atan2(momHad[1], momHad[0]); } - float recoEtaHad() const { return std::asinh(momHad[2] / std::abs(recoPtHad())); } + [[nodiscard]] float recoPtHe3() const { return signHe3 * std::hypot(momHe3[0], momHe3[1]); } + [[nodiscard]] float recoPhiHe3() const { return std::atan2(momHe3[1], momHe3[0]); } + [[nodiscard]] float recoEtaHe3() const { return std::asinh(momHe3[2] / std::abs(recoPtHe3())); } + [[nodiscard]] float recoPtHad() const { return signHad * std::hypot(momHad[0], momHad[1]); } + [[nodiscard]] float recoPhiHad() const { return std::atan2(momHad[1], momHad[0]); } + [[nodiscard]] float recoEtaHad() const { return std::asinh(momHad[2] / std::abs(recoPtHad())); } + [[nodiscard]] float recoKstar() const { return getkstar(recoPtHe3(), recoEtaHe3(), recoPhiHe3(), constants::physics::MassHelium3, 1.f, + recoPtHad(), recoEtaHad(), recoPhiHad(), constants::physics::MassProton, 1.f); } std::array momHe3 = {99.f, 99.f, 99.f}; std::array momHad = {99.f, 99.f, 99.f}; @@ -335,13 +337,13 @@ struct he3HadronFemto { SameKindPair mPair{binningPolicy, settingNoMixedEvents, -1, &cache}; struct He3HadronParams { - std::array betheBlochParams = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; - std::array betheBlochCorrectionParams = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; - std::array, static_cast(Species::kAllSpecies)> itsParams; - std::array, static_cast(Species::kAllSpecies)> dcaxyResParams; - std::array, static_cast(Species::kAllSpecies)> dcazResParams; - std::array hePidTrkPtParams = {0.0f, 0.0f, 0.0f}; - std::array hePidTrkPParams = {0.0f, 0.0f, 0.0f}; + std::array betheBlochParams{}; + std::array betheBlochCorrectionParams{}; + std::array, static_cast(Species::kAllSpecies)> itsParams{}; + std::array, static_cast(Species::kAllSpecies)> dcaxyResParams{}; + std::array, static_cast(Species::kAllSpecies)> dcazResParams{}; + std::array hePidTrkPtParams{}; + std::array hePidTrkPParams{}; } mHe3HadronParams; o2::aod::ITSResponse mResponseITS; @@ -497,8 +499,8 @@ struct he3HadronFemto { mRunNumber = bc.runNumber(); const float defaultBzValue = -999.0f; auto run3GrpTimestamp = bc.timestamp(); - o2::parameters::GRPObject* grpo = mCcdb->getForTimeStamp(settingGrpPath, run3GrpTimestamp); - o2::parameters::GRPMagField* grpmag = 0x0; + auto grpo = mCcdb->getForTimeStamp(settingGrpPath, run3GrpTimestamp); + o2::parameters::GRPMagField* grpmag = nullptr; if (grpo) { o2::base::Propagator::initFieldFromGRP(grpo); if (settingDbz < defaultBzValue) { @@ -575,8 +577,9 @@ struct he3HadronFemto { float correctPtHe3TrackedAsTriton(const float pt, const uint32_t pidForTracking) { - if (pt < 2.5 && pidForTracking == o2::track::PID::Triton) + if (pt < 2.5 && pidForTracking == o2::track::PID::Triton) { return pt * (1. - mHe3HadronParams.hePidTrkPtParams[0] - mHe3HadronParams.hePidTrkPtParams[1] * pt - mHe3HadronParams.hePidTrkPtParams[2] * pt * pt); + } return pt; } @@ -587,8 +590,9 @@ struct he3HadronFemto { float correctedTPCinnerParam = (heliumPID && settingCompensatePIDinTracking) ? tpcInnerParam / 2.f : tpcInnerParam; correctedTPCinnerParam *= 2.f; // rigidity to momentum - if (correctedTPCinnerParam < 2.5 && pidForTracking == o2::track::PID::Triton) + if (correctedTPCinnerParam < 2.5 && pidForTracking == o2::track::PID::Triton) { return correctedTPCinnerParam * (1. - mHe3HadronParams.hePidTrkPParams[0] - mHe3HadronParams.hePidTrkPParams[1] * correctedTPCinnerParam - mHe3HadronParams.hePidTrkPParams[2] * correctedTPCinnerParam * correctedTPCinnerParam); + } return correctedTPCinnerParam; } @@ -596,7 +600,7 @@ struct he3HadronFemto { float computeNsigmaDCA(const float pt, const float dca, const int iSpecies, const char* dcaType = "xy") { - std::array parameters; + std::array parameters{{0., 0., 0., 0.}}; if (std::strcmp(dcaType, "xy") == 0) { parameters = mHe3HadronParams.dcaxyResParams[iSpecies]; } else if (std::strcmp(dcaType, "z") == 0) { @@ -616,8 +620,9 @@ struct he3HadronFemto { const float nsigmaDcaZ = computeNsigmaDCA(pt, dcaZ, ispecies, "z"); if (std::abs(nsigmaDcaXy) > cutSettings.settingCutNsigmaDcaXy || - std::abs(nsigmaDcaZ) > cutSettings.settingCutNsigmaDcaZ) + std::abs(nsigmaDcaZ) > cutSettings.settingCutNsigmaDcaZ) { return false; + } return true; } @@ -787,8 +792,9 @@ struct he3HadronFemto { std::array collisionVertex = getCollisionVertex(collisions, he3Hadcand.collisionID); he3Hadcand.momHe3 = std::array{trackHe3.px(), trackHe3.py(), trackHe3.pz()}; - for (int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { he3Hadcand.momHe3[i] = he3Hadcand.momHe3[i] * 2; + } he3Hadcand.momHad = std::array{trackHad.px(), trackHad.py(), trackHad.pz()}; float invMass = CommonInite; if (settingHadPDGCode == PDG_t::kPiPlus) { @@ -817,7 +823,7 @@ struct he3HadronFemto { } else { auto trackCovHe3 = getTrackParCov(trackHe3); auto trackCovHad = getTrackParCov(trackHad); - std::array dcaInfo; + std::array dcaInfo{{-999., -999.}}; o2::base::Propagator::Instance()->propagateToDCABxByBz({collisionVertex[0], collisionVertex[1], collisionVertex[2]}, trackCovHe3, 2.f, mFitter.getMatCorrType(), &dcaInfo); he3Hadcand.dcaxyHe3 = dcaInfo[0]; he3Hadcand.dcazHe3 = dcaInfo[1]; @@ -1009,6 +1015,7 @@ struct he3HadronFemto { mQaRegistry.fill(HIST("He3/hHe3Pt"), he3Hadcand.recoPtHe3()); mQaRegistry.fill(HIST("Had/hHadronPt"), he3Hadcand.recoPtHad()); mQaRegistry.fill(HIST("hhe3HadtInvMass"), he3Hadcand.invMass); + mQaRegistry.fill(HIST("hhe3HadKstar"), he3Hadcand.recoKstar()); mQaRegistry.fill(HIST("He3/hDCAxyHe3"), he3Hadcand.dcaxyHe3); mQaRegistry.fill(HIST("He3/hDCAzHe3"), he3Hadcand.dcazHe3); mQaRegistry.fill(HIST("Had/hDCAxyHad"), he3Hadcand.dcaxyHad); @@ -1167,7 +1174,7 @@ struct he3HadronFemto { pairTracksSameEvent(trackTableThisCollision, collision); - if (mTrackPairs.size() == 0) { + if (mTrackPairs.empty()) { continue; } @@ -1248,14 +1255,14 @@ struct he3HadronFemto { he3Hadcand.flags |= Flags::kBothPrimaries; isMixedPair = false; - } else if ((he3Hadcand.flagsHe3 & ParticleFlags::kFromLi4) && (he3Hadcand.flagsHad & ParticleFlags::kFromLi4)) { + } else if (static_cast(he3Hadcand.flagsHe3 & ParticleFlags::kFromLi4) && static_cast(he3Hadcand.flagsHad & ParticleFlags::kFromLi4)) { searchForCommonMotherTrack(motherHe3Idxs, motherHadIdxs, mcParticles, motherParticle, he3Hadcand, isMixedPair, Li4PDG); if (!isMixedPair) { he3Hadcand.flags |= Flags::kBothFromLi4; } - } else if ((he3Hadcand.flagsHe3 & ParticleFlags::kFromHypertriton) && (he3Hadcand.flagsHad & ParticleFlags::kFromHypertriton)) { + } else if (static_cast(he3Hadcand.flagsHe3 & ParticleFlags::kFromHypertriton) && static_cast(he3Hadcand.flagsHad & ParticleFlags::kFromHypertriton)) { searchForCommonMotherTrack(motherHe3Idxs, motherHadIdxs, mcParticles, motherParticle, he3Hadcand, isMixedPair, H3LPDG); if (!isMixedPair) { @@ -1306,8 +1313,9 @@ struct he3HadronFemto { for (const auto& track : tracks) { - if (!selectTrack(track, Species::kHad)) + if (!selectTrack(track, Species::kHad)) { continue; + } const float itsNSigmaHad = settingHadPDGCode == PDG_t::kProton ? mResponseITS.nSigmaITS(track.itsClusterSizes(), track.p(), track.eta()) : mResponseITS.nSigmaITS(track.itsClusterSizes(), track.p(), track.eta()); mQaRegistry.fill(HIST("Had/h2NsigmaHadronITS_preselection"), track.sign() * track.pt(), itsNSigmaHad, collision.centFT0C()); @@ -1332,8 +1340,9 @@ struct he3HadronFemto { const float itsNSigmaHe3 = mResponseITS.nSigmaITS(track.itsClusterSizes(), 2 * track.p(), track.eta()); mQaRegistry.fill(HIST("He3/h2NsigmaHe3ITS_preselection"), ptHe3Corrected, itsNSigmaHe3, collision.centFT0C()); - if (!selectTrack(track, Species::kHe3) || !selectDcaNsigmaCut(ptHe3Corrected, track.dcaXY(), track.dcaZ(), Species::kHe3) || (itsNSigmaHe3 < cutSettings.settingCutNsigmaITSHe3)) + if (!selectTrack(track, Species::kHe3) || !selectDcaNsigmaCut(ptHe3Corrected, track.dcaXY(), track.dcaZ(), Species::kHe3) || (itsNSigmaHe3 < cutSettings.settingCutNsigmaITSHe3)) { continue; + } mQaRegistry.fill(HIST("He3/hHe3Pt"), track.sign() * ptHe3Corrected); mQaRegistry.fill(HIST("He3/hDCAxyHe3"), track.dcaXY()); @@ -1353,17 +1362,20 @@ struct he3HadronFemto { void processPurityMc(const CollisionsFullMC::iterator& collision, const TrackCandidatesMC& tracks, const aod::BCsWithTimestamps& bcs, const aod::McParticles& /*mcParticles*/, const aod::McTrackLabels& /*mcTrackLabels*/) { - if (!selectCollision(collision, bcs)) + if (!selectCollision(collision, bcs)) { return; + } for (const auto& track : tracks) { - if (!track.has_mcParticle()) + if (!track.has_mcParticle()) { continue; + } const auto& particle = track.mcParticle_as(); - if (!selectTrack(track, Species::kHad)) + if (!selectTrack(track, Species::kHad)) { continue; + } if (selectDcaNsigmaCut(track.pt(), track.dcaXY(), track.dcaZ(), Species::kHad)) { mQaRegistry.fill(HIST("Had/hHadronPt"), track.pt()); @@ -1390,8 +1402,9 @@ struct he3HadronFemto { } const float ptHe3Corrected = correctPtHe3TrackedAsTriton(track.pt(), track.pidForTracking()); - if (!selectTrack(track, Species::kHe3) || !selectDcaNsigmaCut(ptHe3Corrected, track.dcaXY(), track.dcaZ(), Species::kHe3)) + if (!selectTrack(track, Species::kHe3) || !selectDcaNsigmaCut(ptHe3Corrected, track.dcaXY(), track.dcaZ(), Species::kHe3)) { continue; + } mQaRegistry.fill(HIST("He3/hHe3Pt"), ptHe3Corrected); mQaRegistry.fill(HIST("He3/hDCAxyHe3"), track.dcaXY()); From f09298bae58b322114c6bf13b33a38077829857d Mon Sep 17 00:00:00 2001 From: dyx-11 <1260971129@qq.com> Date: Tue, 28 Jul 2026 00:03:32 +0800 Subject: [PATCH 04/71] [PWGUD] add various gap option for POI and Ol region (#17212) --- PWGUD/Tasks/flowCumulantsUpc.cxx | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/PWGUD/Tasks/flowCumulantsUpc.cxx b/PWGUD/Tasks/flowCumulantsUpc.cxx index 52df93c8f24..4b7b11b8106 100644 --- a/PWGUD/Tasks/flowCumulantsUpc.cxx +++ b/PWGUD/Tasks/flowCumulantsUpc.cxx @@ -341,10 +341,24 @@ struct FlowCumulantsUpc { fGFW->AddRegion("refP", 0.4, maxEta, 1, 1); fGFW->AddRegion("refM", -0.4, 0.4, 1, 1); fGFW->AddRegion("poiN", minEta, -0.4, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN00", minEta, 0., 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN02", minEta, -0.1, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN04", minEta, -0.2, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN06", minEta, -0.3, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN08", minEta, -0.4, 1 + fPtAxis->GetNbins(), 2); fGFW->AddRegion("poiN10", minEta, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN12", minEta, -0.6, 1 + fPtAxis->GetNbins(), 2); + fGFW->AddRegion("poiN14", minEta, -0.7, 1 + fPtAxis->GetNbins(), 2); fGFW->AddRegion("poifull", minEta, maxEta, 1 + fPtAxis->GetNbins(), 2); fGFW->AddRegion("olN", minEta, -0.4, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN00", minEta, 0., 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN02", minEta, -0.1, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN04", minEta, -0.2, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN06", minEta, -0.3, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN08", minEta, -0.4, 1 + fPtAxis->GetNbins(), 4); fGFW->AddRegion("olN10", minEta, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN12", minEta, -0.6, 1 + fPtAxis->GetNbins(), 4); + fGFW->AddRegion("olN14", minEta, -0.7, 1 + fPtAxis->GetNbins(), 4); fGFW->AddRegion("olfull", minEta, maxEta, 1 + fPtAxis->GetNbins(), 4); // eta region for MC, can be different from data to study the effect of acceptance @@ -369,10 +383,24 @@ struct FlowCumulantsUpc { fGFWMC->AddRegion("refP", 0.4, maxEta, 1, 1); fGFWMC->AddRegion("refM", -0.4, 0.4, 1, 1); fGFWMC->AddRegion("poiN", minEta, -0.4, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN00", minEta, 0., 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN02", minEta, -0.1, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN04", minEta, -0.2, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN06", minEta, -0.3, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN08", minEta, -0.4, 1 + fPtAxis->GetNbins(), 2); fGFWMC->AddRegion("poiN10", minEta, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN12", minEta, -0.6, 1 + fPtAxis->GetNbins(), 2); + fGFWMC->AddRegion("poiN14", minEta, -0.7, 1 + fPtAxis->GetNbins(), 2); fGFWMC->AddRegion("poifull", minEta, maxEta, 1 + fPtAxis->GetNbins(), 2); fGFWMC->AddRegion("olN", minEta, -0.4, 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN00", minEta, 0., 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN02", minEta, -0.1, 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN04", minEta, -0.2, 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN06", minEta, -0.3, 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN08", minEta, -0.4, 1 + fPtAxis->GetNbins(), 4); fGFWMC->AddRegion("olN10", minEta, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN12", minEta, -0.6, 1 + fPtAxis->GetNbins(), 4); + fGFWMC->AddRegion("olN14", minEta, -0.7, 1 + fPtAxis->GetNbins(), 4); fGFWMC->AddRegion("olfull", minEta, maxEta, 1 + fPtAxis->GetNbins(), 4); corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); From 85847df908c75812d63ffee4f6a81180f9b94d61 Mon Sep 17 00:00:00 2001 From: Stefanie Mrozinski <63045530+Steffimro@users.noreply.github.com> Date: Mon, 27 Jul 2026 18:11:17 +0200 Subject: [PATCH 05/71] [PWGEM] add switchable crossed-pair (leg-swap) veto with QA (#17215) --- PWGEM/PhotonMeson/Tasks/photonhbt.cxx | 130 +++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 2 deletions(-) diff --git a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx index b621516b429..f5c0536d734 100644 --- a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx +++ b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx @@ -149,6 +149,11 @@ struct Photonhbt { float u{999.f}; }; + struct CrossObs { + std::array mee{999.f, 999.f}; // crossed m(e+e-) per combo + std::array dist{999.f, 999.f}; // crossed line-line distance (cm) + }; + struct TruthGamma { int id = -1, posId = -1, negId = -1; float eta = 0.f, phi = 0.f, pt = 0.f; @@ -336,6 +341,15 @@ struct Photonhbt { Configurable cfgUCut{"cfgUCut", 0.f, "min u (sigma units); pairs with u < cut rejected in SE AND ME"}; } pairsep; + struct : ConfigurableGroup { + std::string prefix = "crosspair_group"; + Configurable cfgDoCrossPairQA{"cfgDoCrossPairQA", false, "fill crossed-hypothesis QA (mee_cross, dist_cross vs qinv) for pairs passing all other pair cuts; SE and ME"}; + Configurable cfgDoCrossPairCut{"cfgDoCrossPairCut", false, "reject pairs with a photon-like crossed combination; applied to SE AND ME"}; + Configurable cfgCrossMaxMee{"cfgCrossMaxMee", 0.04f, "veto: crossed m_ee below this (GeV/c^2)"}; + Configurable cfgCrossMaxDist{"cfgCrossMaxDist", 1.0f, "veto: crossed line-line distance below this (cm)"}; + Configurable cfgCrossMaxQinvQA{"cfgCrossMaxQinvQA", 0.3f, "fill crossed QA sparses only below this qinv"}; + } crosspair; + struct : ConfigurableGroup { std::string prefix = "eventcut_group"; Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; @@ -656,6 +670,7 @@ struct Photonhbt { addEventHistograms(); addPairCFHistograms(); addPairSepHistograms(); + addCrossPairHistograms(); addSinglePhotonQAHistograms(); addPairQAHistograms(); @@ -704,8 +719,6 @@ struct Photonhbt { fRegistryCF.add("Pair/mix/hDiffBC", "diff. global BC in mixed event;|BC_{current}-BC_{mixed}|", kTH1D, {{10001, -0.5, 10000.5}}, true); } - - // ─── CF: PairSep ──────────────────────── // ─── CF: PairSep ──────────────────────── void addPairSepHistograms() { @@ -717,6 +730,21 @@ struct Photonhbt { } } + void addCrossPairHistograms() + { + if (!(crosspair.cfgDoCrossPairQA.value || crosspair.cfgDoCrossPairCut.value)) { + return; + } + for (const auto& sm : {std::string("Pair/same/CrossPair/"), std::string("Pair/mix/CrossPair/")}) { + fRegistryCF.add((sm + "hSparse_Mee_Dist_Qinv").c_str(), + "crossed-hypothesis QA;m_{ee}^{cross} (GeV/c^{2});crossed line distance (cm);q_{inv} (GeV/c)", + kTHnSparseF, {{100, 0.f, 0.1f}, {100, 0.f, 10.f}, {60, 0.f, 0.3f}}, true); + auto h = fRegistryCF.add((sm + "hVetoCounter").c_str(), "crossed-pair veto;;pairs", kTH1D, {{2, -0.5f, 1.5f}}, true); + h->GetXaxis()->SetBinLabel(1, "evaluated"); + h->GetXaxis()->SetBinLabel(2, "vetoed"); + } + } + // ─── pairQA: single-photon QA per cut step ───────────────────────────────── void addSinglePhotonQAHistograms() { @@ -1246,6 +1274,72 @@ struct Photonhbt { return s.u > pairsep.cfgUCut.value; } + [[nodiscard]] static float lineLineDistance(std::array const& o1, std::array const& d1, + std::array const& o2, std::array const& d2) + { + const std::array w = {o2[0] - o1[0], o2[1] - o1[1], o2[2] - o1[2]}; + const std::array n = {d1[1] * d2[2] - d1[2] * d2[1], + d1[2] * d2[0] - d1[0] * d2[2], + d1[0] * d2[1] - d1[1] * d2[0]}; + const float nMag = std::sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]); + const float d1Mag2 = d1[0] * d1[0] + d1[1] * d1[1] + d1[2] * d1[2]; + if (nMag < 1e-6f * d1Mag2) { // o2-linter: disable=magic-number (near-parallel: point-to-line distance) + const float wDotD = (w[0] * d1[0] + w[1] * d1[1] + w[2] * d1[2]) / d1Mag2; + const std::array perp = {w[0] - wDotD * d1[0], w[1] - wDotD * d1[1], w[2] - wDotD * d1[2]}; + return std::sqrt(perp[0] * perp[0] + perp[1] * perp[1] + perp[2] * perp[2]); + } + return std::fabs(w[0] * n[0] + w[1] * n[1] + w[2] * n[2]) / nMag; + } + + [[nodiscard]] CrossObs computeCrossObs(PhotonWithLegs const& a, PhotonWithLegs const& b) const + { + constexpr float kMe = 0.000510999f; // electron mass, GeV/c^2 + CrossObs c; + auto legVec = [](PhotonWithLegs const& p, int i) { + return ROOT::Math::PtEtaPhiMVector(p.fLegPt[i], p.fLegEta[i], p.fLegPhi[i], kMe); + }; + auto legDir = [](PhotonWithLegs const& p, int i) -> std::array { + return {p.fLegPt[i] * std::cos(p.fLegPhi[i]), p.fLegPt[i] * std::sin(p.fLegPhi[i]), + p.fLegPt[i] * std::sinh(p.fLegEta[i])}; + }; + // Leg index 0 = e+, 1 = e- (makePhotonWithLegs filling order). + // Combo 0: a's e+ with b's e-. Combo 1: b's e+ with a's e-. + for (int combo = 0; combo < 2; ++combo) { // o2-linter: disable=magic-number (combinations of fake photons) + PhotonWithLegs const& pPos = (combo == 0) ? a : b; + PhotonWithLegs const& pEle = (combo == 0) ? b : a; + c.mee[combo] = static_cast((legVec(pPos, 0) + legVec(pEle, 1)).M()); + c.dist[combo] = lineLineDistance({pPos.fVx, pPos.fVy, pPos.fVz}, legDir(pPos, 0), + {pEle.fVx, pEle.fVy, pEle.fVz}, legDir(pEle, 1)); + } + return c; + } + + [[nodiscard]] inline bool passCrossPairVeto(CrossObs const& c) const + { + if (!crosspair.cfgDoCrossPairCut.value) { + return true; + } + for (int i = 0; i < 2; ++i) { // o2-linter: disable=magic-number (combinations of fake photons) + if (c.mee[i] < crosspair.cfgCrossMaxMee.value && c.dist[i] < crosspair.cfgCrossMaxDist.value) { + return false; + } + } + return true; + } + + template + inline void fillCrossPair(CrossObs const& c, float qinv, bool vetoed) + { + constexpr auto dir = (ev_id == 0) ? "Pair/same/CrossPair/" : "Pair/mix/CrossPair/"; + fRegistryCF.fill(HIST(dir) + HIST("hVetoCounter"), vetoed ? 1.0 : 0.0); + if (qinv > crosspair.cfgCrossMaxQinvQA.value) { + return; + } + for (int i = 0; i < 2; ++i) { // o2-linter: disable=magic-number (combinations of fake photons) + fRegistryCF.fill(HIST(dir) + HIST("hSparse_Mee_Dist_Qinv"), c.mee[i], c.dist[i], qinv); + } + } + [[nodiscard]] float uTrue(TruthGamma const& g1, TruthGamma const& g2) const { const float sE = pairsep.cfgUSigEta.value, sP = pairsep.cfgUSigPhi.value; @@ -1913,6 +2007,14 @@ struct Photonhbt { if (isInsideEllipse(obs.deta, obs.dphi)) { continue; } + if (crosspair.cfgDoCrossPairQA.value || crosspair.cfgDoCrossPairCut.value) { + const auto cross = computeCrossObs(pwl1, pwl2); + const bool vetoed = !passCrossPairVeto(cross); + fillCrossPair<0>(cross, obs.qinv, vetoed); + if (vetoed) { + continue; + } + } // ───after pair cuts ────────────────────────────────────── fillPairSep<0, true>(sep, obs); @@ -2000,6 +2102,14 @@ struct Photonhbt { if (isInsideEllipse(obs.deta, obs.dphi)) { continue; } + if (crosspair.cfgDoCrossPairQA.value || crosspair.cfgDoCrossPairCut.value) { + const auto cross = computeCrossObs(g1, g2); + const bool vetoed = !passCrossPairVeto(cross); + fillCrossPair<1>(cross, obs.qinv, vetoed); + if (vetoed) { + continue; + } + } fillPairSep<1, true>(sep, obs); if (doQA) { @@ -2122,6 +2232,14 @@ struct Photonhbt { if (isInsideEllipse(obs.deta, obs.dphi)) { continue; } + if (crosspair.cfgDoCrossPairQA.value || crosspair.cfgDoCrossPairCut.value) { + const auto cross = computeCrossObs(pwl1, pwl2); + const bool vetoed = !passCrossPairVeto(cross); + fillCrossPair<0>(cross, obs.qinv, vetoed); + if (vetoed) { + continue; + } + } // ─── after pair cuts ────────────────────────────────────── fillPairSep<0, true>(sep, obs); @@ -2260,6 +2378,14 @@ struct Photonhbt { if (isInsideEllipse(obs.deta, obs.dphi)) { continue; } + if (crosspair.cfgDoCrossPairQA.value || crosspair.cfgDoCrossPairCut.value) { + const auto cross = computeCrossObs(g1, g2); + const bool vetoed = !passCrossPairVeto(cross); + fillCrossPair<1>(cross, obs.qinv, vetoed); + if (vetoed) { + continue; + } + } // ─after pair cuts ────────────────────────────────── fillPairSep<1, true>(sep, obs); From c33f338fbff065125fc0b63c55586a264571f744 Mon Sep 17 00:00:00 2001 From: Maximiliano Puccio Date: Mon, 27 Jul 2026 19:00:59 +0200 Subject: [PATCH 06/71] [PWGLF] remove daughter indices (#17224) --- PWGLF/DataModel/Vtx3BodyTables.h | 16 ++------------ .../Nuspex/nucleiThreeBodyBuilder.cxx | 21 +++---------------- 2 files changed, 5 insertions(+), 32 deletions(-) diff --git a/PWGLF/DataModel/Vtx3BodyTables.h b/PWGLF/DataModel/Vtx3BodyTables.h index d9070875778..e0714108b5f 100644 --- a/PWGLF/DataModel/Vtx3BodyTables.h +++ b/PWGLF/DataModel/Vtx3BodyTables.h @@ -337,11 +337,6 @@ using Vtx3BodyDatasCovsIndexed = soa::Join, NUCLEI_THREE_BODY_RECO_COLUMNS, - nuclei3body::McLabelHe3, nuclei3body::McLabelDaughter1, nuclei3body::McLabelDaughter2, nuclei3body::McPdgHe3, nuclei3body::McPdgDaughter1, nuclei3body::McPdgDaughter2, - nuclei3body::McMatchStatus, nuclei3body::McMotherLabel, nuclei3body::McMotherPdg, + nuclei3body::McMatchStatus, nuclei3body::McMotherPdg, nuclei3body::GenMotherPt, nuclei3body::GenMotherEta, nuclei3body::GenMotherPhi, nuclei3body::GenDecayLength); diff --git a/PWGLF/TableProducer/Nuspex/nucleiThreeBodyBuilder.cxx b/PWGLF/TableProducer/Nuspex/nucleiThreeBodyBuilder.cxx index a3ce4fb2d1a..154747598cc 100644 --- a/PWGLF/TableProducer/Nuspex/nucleiThreeBodyBuilder.cxx +++ b/PWGLF/TableProducer/Nuspex/nucleiThreeBodyBuilder.cxx @@ -195,8 +195,6 @@ struct NucleiThreeBodyBuilder { std::vector preselectedTracks; struct RecoCandidate { - std::array trackIds{InvalidLabel, InvalidLabel, InvalidLabel}; - int collisionId = InvalidLabel; std::array signs{}; float pt = 0.f; float eta = 0.f; @@ -218,10 +216,8 @@ struct NucleiThreeBodyBuilder { }; struct MCInfo { - std::array labels{InvalidLabel, InvalidLabel, InvalidLabel}; std::array pdgs{}; uint8_t matchStatus = MissingDaughterLabel; - int motherLabel = InvalidLabel; int motherPdg = 0; float motherPt = InvalidFloat; float motherEta = InvalidFloat; @@ -472,10 +468,6 @@ struct NucleiThreeBodyBuilder { } registry.fill(HIST("triplets"), 1.); - out.trackIds = {static_cast(he3Track.globalIndex()), - static_cast(daughter1Track.globalIndex()), - static_cast(daughter2Track.globalIndex())}; - out.collisionId = collision.globalIndex(); out.signs = {static_cast(he3Track.sign() > 0 ? 1 : -1), static_cast(daughter1Track.sign() > 0 ? 1 : -1), static_cast(daughter2Track.sign() > 0 ? 1 : -1)}; @@ -546,8 +538,7 @@ struct NucleiThreeBodyBuilder { void fillDataTable(RecoCandidate const& c) { - outputData(c.trackIds[0], c.trackIds[1], c.trackIds[2], c.collisionId, - c.signs[0], c.signs[1], c.signs[2], + outputData(c.signs[0], c.signs[1], c.signs[2], c.pt, c.eta, c.phi, c.daughterMomentum[0], c.daughterMomentum[1], c.daughterMomentum[2], c.chi2, c.dcaDaughters, c.cosPA, c.decayLength, @@ -575,9 +566,6 @@ struct NucleiThreeBodyBuilder { const auto he3Particle = he3Track.template mcParticle_as(); const auto daughter1Particle = daughter1Track.template mcParticle_as(); const auto daughter2Particle = daughter2Track.template mcParticle_as(); - info.labels = {static_cast(he3Particle.globalIndex()), - static_cast(daughter1Particle.globalIndex()), - static_cast(daughter2Particle.globalIndex())}; info.pdgs = {he3Particle.pdgCode(), daughter1Particle.pdgCode(), daughter2Particle.pdgCode()}; info.matchStatus = NoCommonImmediateMother; @@ -601,7 +589,6 @@ struct NucleiThreeBodyBuilder { const auto selectedMother = mcParticles.rawIteratorAt(commonMotherLabel); info.matchStatus = CommonImmediateMother; - info.motherLabel = commonMotherLabel; info.motherPdg = selectedMother.pdgCode(); const int he3Sign = he3Track.sign() > 0 ? 1 : -1; const bool expectedDaughters = info.pdgs[0] == he3Sign * He3Pdg && @@ -627,8 +614,7 @@ struct NucleiThreeBodyBuilder { void fillMCTable(RecoCandidate const& c, MCInfo const& m) { - outputMC(c.trackIds[0], c.trackIds[1], c.trackIds[2], c.collisionId, - c.signs[0], c.signs[1], c.signs[2], + outputMC(c.signs[0], c.signs[1], c.signs[2], c.pt, c.eta, c.phi, c.daughterMomentum[0], c.daughterMomentum[1], c.daughterMomentum[2], c.chi2, c.dcaDaughters, c.cosPA, c.decayLength, @@ -643,9 +629,8 @@ struct NucleiThreeBodyBuilder { c.tpcNCls[0], c.tpcNCls[1], c.tpcNCls[2], c.tpcCrossedRows[0], c.tpcCrossedRows[1], c.tpcCrossedRows[2], c.itsNCls[0], c.itsNCls[1], c.itsNCls[2], - m.labels[0], m.labels[1], m.labels[2], m.pdgs[0], m.pdgs[1], m.pdgs[2], - m.matchStatus, m.motherLabel, m.motherPdg, + m.matchStatus, m.motherPdg, m.motherPt, m.motherEta, m.motherPhi, m.decayLength); } From 8b24142a5ac768d9b2fd5969399ae3f0d63aa8e4 Mon Sep 17 00:00:00 2001 From: prottayCMT <61418725+prottayCMT@users.noreply.github.com> Date: Mon, 27 Jul 2026 20:52:21 +0200 Subject: [PATCH 07/71] [PWGLF] added LOCC (#17226) Co-authored-by: Prottay Das --- PWGLF/Tasks/Resonances/phiflowder.cxx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/PWGLF/Tasks/Resonances/phiflowder.cxx b/PWGLF/Tasks/Resonances/phiflowder.cxx index 4b6b044ce7f..956dc39356b 100644 --- a/PWGLF/Tasks/Resonances/phiflowder.cxx +++ b/PWGLF/Tasks/Resonances/phiflowder.cxx @@ -84,6 +84,10 @@ struct phiflowder { histos.add("hpQypvscent", "hpQypvscent", HistType::kTHnSparseF, {axisCent, axisV1}, true); histos.add("hpQytvscent", "hpQytvscent", HistType::kTHnSparseF, {axisCent, axisV1}, true); histos.add("hMixpairs", "hMixpairs", HistType::kTHnSparseF, {axisNPairs}, true); + histos.add("hSparseSameUx", "Same-event #Sigma u_{x};M;pT;centrality;eta", kTHnSparseF, {axisInvMass, axisPhiPt, axisCent, axisEta, axisV1}, true); + histos.add("hSparseSameUy", "Same-event #Sigma u_{y};M;pT;centrality;eta", kTHnSparseF, {axisInvMass, axisPhiPt, axisCent, axisEta, axisV1}, true); + histos.add("hSparseSameUQA", "Same-event #Sigma u#upoint Q_{A};M;pT;centrality;eta", kTHnSparseF, {axisInvMass, axisPhiPt, axisCent, axisEta, axisV1}, true); + histos.add("hSparseSameUQC", "Same-event #Sigma u#upoint Q_{C};M;pT;centrality;eta", kTHnSparseF, {axisInvMass, axisPhiPt, axisCent, axisEta, axisV1}, true); } uint8_t getRequiredPidBit() const @@ -291,12 +295,18 @@ struct phiflowder { auto uy = sinNPhi; // imaginary part of candidate q vector auto oddv1 = ux * (qxZDCA - qxZDCC) + uy * (qyZDCA - qyZDCC); // auto evenv1 = ux * (qxZDCA + qxZDCC) + uy * (qyZDCA + qyZDCC); + auto uQA = ux * qxZDCA + uy * qyZDCA; + auto uQC = ux * qxZDCC + uy * qyZDCC; if (phiMass < massMin || phiMass > massMax) { continue; } histos.fill(HIST("hSparseSame"), phiMass, phiPt, centrality, etaCand, oddv1); + histos.fill(HIST("hSparseSameUx"), phiMass, phiPt, centrality, etaCand, ux); + histos.fill(HIST("hSparseSameUy"), phiMass, phiPt, centrality, etaCand, uy); + histos.fill(HIST("hSparseSameUQA"), phiMass, phiPt, centrality, etaCand, uQA); + histos.fill(HIST("hSparseSameUQC"), phiMass, phiPt, centrality, etaCand, uQC); // nPhiSame++; } } From f48d2a13fba854e6b253050fc24330a9cf06514c Mon Sep 17 00:00:00 2001 From: navneetkumar231295 <71565461+navneetkumar231295@users.noreply.github.com> Date: Tue, 28 Jul 2026 01:36:20 +0530 Subject: [PATCH 08/71] [PWGLF] To add the THnSparse for MC closure (#17217) Co-authored-by: Navneet --- .../Tasks/Resonances/chargedkstaranalysis.cxx | 335 ++++++++++++------ 1 file changed, 222 insertions(+), 113 deletions(-) diff --git a/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx b/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx index 8caa58152ca..987e164063f 100644 --- a/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx +++ b/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx @@ -94,6 +94,7 @@ struct Chargedkstaranalysis { Preslice perCollision = aod::track::collisionId; Preslice perMCCollision = o2::aod::mcparticle::mcCollisionId; bool currentIsGen = false; + bool mcClosure = false; struct : ConfigurableGroup { ConfigurableAxis cfgvtxbins{"cfgvtxbins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; ConfigurableAxis cfgmultbins{"cfgmultbins", {VARIABLE_WIDTH, 0., 1., 5., 10., 30., 50., 70., 100., 110.}, "Mixing bins - multiplicity"}; @@ -155,8 +156,8 @@ struct Chargedkstaranalysis { // Event Mixing Configurable nEvtMixing{"nEvtMixing", 5, "Number of events to mix"}; - Service ccdb; - Service pdg; + Service ccdb{}; + Service pdg{}; o2::ccdb::CcdbApi ccdbApi; Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; @@ -226,6 +227,7 @@ struct Chargedkstaranalysis { // MC configurables struct : ConfigurableGroup { Configurable doBkgMc{"doBkgMc", false, "Apply rotation in MC"}; + Configurable doMcClosure{"doMcClosure", true, "Do MC Closure Study in MC"}; } mcCfgs; /// Track selections @@ -300,7 +302,7 @@ struct Chargedkstaranalysis { } kstarCutCfgs; Configurable isQaRequired{"isQaRequired", false, "Fill QA plots"}; - float centrality; + float centrality = 0.f; // PDG code int kPDGK0s = kK0Short; @@ -562,9 +564,12 @@ struct Chargedkstaranalysis { if (!helicityCfgs.qAOptimisation) { histosMc.add("h3ChaKstarInvMassDSMcGen", "h3ChaKstarInvMassDSMcGen", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); histosMc.add("h3ChaKstarInvMassDSMcRec", "h3ChaKstarInvMassDSMcRec", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); + histosMc.add("h3ChaKstarInvMassDSMcRecClosure", "h3ChaKstarInvMassDSMcRecClosure", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); + if (mcCfgs.doBkgMc) { histosMc.add("h3ChaKstarInvMassRotMcGen", "h3ChaKstarInvMassRotMcGen", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); histosMc.add("h3ChaKstarInvMassRotMcRec", "h3ChaKstarInvMassRotMcRec", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); + histosMc.add("h3ChaKstarInvMassRotMcRecClosure", "h3ChaKstarInvMassRotMcRecClosure", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); } } @@ -602,7 +607,7 @@ struct Chargedkstaranalysis { std::unordered_map centTruthByAllowed; std::unordered_set refClassIds; std::unordered_map refCentByMcId; - float lMultiplicity; + float lMultiplicity = 0.f; template float getCentrality(CollisionType const& collision) { @@ -624,76 +629,100 @@ struct Chargedkstaranalysis { int ibin = 1; auto applyCut = [&](bool condition) -> bool { - if (!condition) + if (!condition) { return false; - if (!doprocessMC && isQaRequired) + } + if (!doprocessMC && isQaRequired) { histos.fill(HIST("QA/hTrackCutFlow"), ibin); + } ibin++; return true; }; // First bin (before any cuts) - if (!doprocessMC && isQaRequired) + if (!doprocessMC && isQaRequired) { histos.fill(HIST("QA/hTrackCutFlow"), ibin++); + } // Cuts - if (!applyCut(std::abs(track.pt()) >= trackCutCfgs.cMinPtcut)) + if (!applyCut(std::abs(track.pt()) >= trackCutCfgs.cMinPtcut)) { return false; - if (!applyCut(std::abs(track.eta()) <= trackCutCfgs.cMaxEtacut)) + } + if (!applyCut(std::abs(track.eta()) <= trackCutCfgs.cMaxEtacut)) { return false; - if (!applyCut(track.itsNCls() >= trackCutCfgs.cfgITScluster)) + } + if (!applyCut(track.itsNCls() >= trackCutCfgs.cfgITScluster)) { return false; - if (!applyCut(track.tpcNClsFound() >= trackCutCfgs.cfgTPCcluster)) + } + if (!applyCut(track.tpcNClsFound() >= trackCutCfgs.cfgTPCcluster)) { return false; - if (!applyCut(track.tpcCrossedRowsOverFindableCls() >= trackCutCfgs.cfgRatioTPCRowsOverFindableCls)) + } + if (!applyCut(track.tpcCrossedRowsOverFindableCls() >= trackCutCfgs.cfgRatioTPCRowsOverFindableCls)) { return false; - if (!applyCut(track.itsChi2NCl() < trackCutCfgs.cfgITSChi2NCl)) + } + if (!applyCut(track.itsChi2NCl() < trackCutCfgs.cfgITSChi2NCl)) { return false; - if (!applyCut(track.tpcChi2NCl() < trackCutCfgs.cfgTPCChi2NCl)) + } + if (!applyCut(track.tpcChi2NCl() < trackCutCfgs.cfgTPCChi2NCl)) { return false; - - if (!applyCut(!trackCutCfgs.cfgHasITS || track.hasITS())) + } + if (!applyCut(!trackCutCfgs.cfgHasITS || track.hasITS())) { return false; - if (!applyCut(!trackCutCfgs.cfgHasTPC || track.hasTPC())) + } + if (!applyCut(!trackCutCfgs.cfgHasTPC || track.hasTPC())) { return false; - if (!applyCut(!trackCutCfgs.cfgHasTOF || track.hasTOF())) + } + if (!applyCut(!trackCutCfgs.cfgHasTOF || track.hasTOF())) { return false; + } - if (!applyCut(!trackCutCfgs.cfgUseITSRefit || track.passedITSRefit())) + if (!applyCut(!trackCutCfgs.cfgUseITSRefit || track.passedITSRefit())) { return false; - if (!applyCut(!trackCutCfgs.cfgUseTPCRefit || track.passedTPCRefit())) + } + if (!applyCut(!trackCutCfgs.cfgUseTPCRefit || track.passedTPCRefit())) { return false; + } - if (!applyCut(!trackCutCfgs.cfgPVContributor || track.isPVContributor())) + if (!applyCut(!trackCutCfgs.cfgPVContributor || track.isPVContributor())) { return false; - if (!applyCut(!trackCutCfgs.cfgGlobalWoDCATrack || track.isGlobalTrackWoDCA())) + } + if (!applyCut(!trackCutCfgs.cfgGlobalWoDCATrack || track.isGlobalTrackWoDCA())) { return false; - if (!applyCut(!trackCutCfgs.cfgGlobalTrack || track.isGlobalTrack())) + } + if (!applyCut(!trackCutCfgs.cfgGlobalTrack || track.isGlobalTrack())) { return false; - if (!applyCut(!trackCutCfgs.cfgPrimaryTrack || track.isPrimaryTrack())) + } + if (!applyCut(!trackCutCfgs.cfgPrimaryTrack || track.isPrimaryTrack())) { return false; + } - if (!applyCut(std::abs(track.dcaXY()) <= trackCutCfgs.cMaxbDCArToPVcut)) + if (!applyCut(std::abs(track.dcaXY()) <= trackCutCfgs.cMaxbDCArToPVcut)) { return false; - if (!applyCut(std::abs(track.dcaZ()) <= trackCutCfgs.cMaxbDCAzToPVcut)) + } + if (!applyCut(std::abs(track.dcaZ()) <= trackCutCfgs.cMaxbDCAzToPVcut)) { return false; + } // pT dependent DCA XY if (trackCutCfgs.cfgpTdepDCAxyCut) { - if (!applyCut(std::abs(track.dcaXY()) <= (0.004 + (0.013 / track.pt())))) + if (!applyCut(std::abs(track.dcaXY()) <= (0.004 + (0.013 / track.pt())))) { return false; + } } else { - if (!applyCut(std::abs(track.dcaXY()) <= trackCutCfgs.cfgMaxbDCArToPVcut)) + if (!applyCut(std::abs(track.dcaXY()) <= trackCutCfgs.cfgMaxbDCArToPVcut)) { return false; + } } // pT dependent DCA Z if (trackCutCfgs.cfgpTdepDCAzCut) { - if (!applyCut(std::abs(track.dcaZ()) <= (0.004 + (0.013 / track.pt())))) + if (!applyCut(std::abs(track.dcaZ()) <= (0.004 + (0.013 / track.pt())))) { return false; + } } else { - if (!applyCut(std::abs(track.dcaZ()) <= trackCutCfgs.cfgMaxbDCAzToPVcut)) + if (!applyCut(std::abs(track.dcaZ()) <= trackCutCfgs.cfgMaxbDCAzToPVcut)) { return false; + } } return true; @@ -702,13 +731,15 @@ struct Chargedkstaranalysis { template bool selectionPIDPion(TrackType const& candidate) { - if (std::abs(candidate.tpcNSigmaPi()) >= pidCutCfgs.cfgMaxTPCnSigmaPion) + if (std::abs(candidate.tpcNSigmaPi()) >= pidCutCfgs.cfgMaxTPCnSigmaPion) { return false; - if (pidCutCfgs.cfgTPConly) + } + if (pidCutCfgs.cfgTPConly) { return true; - if (candidate.pt() <= pidCutCfgs.cfgTOFMinPt) + } + if (candidate.pt() <= pidCutCfgs.cfgTOFMinPt) { return true; - + } if (candidate.hasTOF()) { const bool tofPIDPassed = std::abs(candidate.tofNSigmaPi()) < pidCutCfgs.cfgMaxTOFnSigmaPion; const bool combo = (pidCutCfgs.cfgNsigmaCutCombinedPion > 0) && @@ -716,9 +747,8 @@ struct Chargedkstaranalysis { candidate.tofNSigmaPi() * candidate.tofNSigmaPi() < pidCutCfgs.cfgNsigmaCutCombinedPion * pidCutCfgs.cfgNsigmaCutCombinedPion); return tofPIDPassed || combo; - } else { - return pidCutCfgs.cfgTOFVeto; } + return pidCutCfgs.cfgTOFVeto; } template @@ -751,8 +781,9 @@ struct Chargedkstaranalysis { auto mLambda = candidate.mLambda(); auto mALambda = candidate.mAntiLambda(); - if (!doprocessMC && isQaRequired) + if (!doprocessMC && isQaRequired) { histos.fill(HIST("QA/K0sCutCheck"), ibin); + } applyCut(dauDCA <= secondaryCutsCfgs.cSecondaryDauDCAMax); applyCut(dauPosDCAtoPV >= secondaryCutsCfgs.cSecondaryDauPosDCAtoPVMin); @@ -774,26 +805,38 @@ struct Chargedkstaranalysis { template void fillKstarHist(bool isRot, float multiplicity, const T& mother, double cosTheta) { + // 1. Data Path if (!doprocessMC) { - if (isRot) { hChaKstar.fill(HIST("h3ChaKstarInvMassRot"), multiplicity, mother.Pt(), mother.M(), cosTheta); } else { hChaKstar.fill(HIST("h3ChaKstarInvMassDS"), multiplicity, mother.Pt(), mother.M(), cosTheta); } + return; + } + + // 2. MC Generated Path + if (currentIsGen) { + if (isRot) { + histosMc.fill(HIST("h3ChaKstarInvMassRotMcGen"), multiplicity, mother.Pt(), mother.M(), cosTheta); + } else { + histosMc.fill(HIST("h3ChaKstarInvMassDSMcGen"), multiplicity, mother.Pt(), mother.M(), cosTheta); + } + return; + } + + // 3. MC Reconstructed Path + if (isRot) { + if (!mcClosure) { + histosMc.fill(HIST("h3ChaKstarInvMassRotMcRec"), multiplicity, mother.Pt(), mother.M(), cosTheta); + } else { + histosMc.fill(HIST("h3ChaKstarInvMassRotMcRecClosure"), multiplicity, mother.Pt(), mother.M(), cosTheta); + } } else { - if (currentIsGen) { - if (isRot) { - histosMc.fill(HIST("h3ChaKstarInvMassRotMcGen"), multiplicity, mother.Pt(), mother.M(), cosTheta); - } else { - histosMc.fill(HIST("h3ChaKstarInvMassDSMcGen"), multiplicity, mother.Pt(), mother.M(), cosTheta); - } + if (!mcClosure) { + histosMc.fill(HIST("h3ChaKstarInvMassDSMcRec"), multiplicity, mother.Pt(), mother.M(), cosTheta); } else { - if (isRot) { - histosMc.fill(HIST("h3ChaKstarInvMassRotMcRec"), multiplicity, mother.Pt(), mother.M(), cosTheta); - } else { - histosMc.fill(HIST("h3ChaKstarInvMassDSMcRec"), multiplicity, mother.Pt(), mother.M(), cosTheta); - } + histosMc.fill(HIST("h3ChaKstarInvMassDSMcRecClosure"), multiplicity, mother.Pt(), mother.M(), cosTheta); } } } @@ -801,14 +844,14 @@ struct Chargedkstaranalysis { template void fillInvMass(const T& mother, float multiplicity, const T& daughter1, const T& daughter2, bool isMix) { - TRandom* rn = new TRandom(); + auto* rn = new TRandom(); rn->SetSeed(0); // Variable declarations ROOT::Math::PxPyPzMVector fourVecDauCM, daughterRot, motherRot, daughterRotCM; ROOT::Math::XYZVectorF beam1CM, beam2CM, zAxisCS, yAxisCS, xAxisCS; ROOT::Math::XYZVectorF v1CM, zaxisHE, yaxisHE, xaxisHE; ROOT::Math::XYZVector randomVec, beamVec, normalVec, normalVecRot, randomVecRot; - float theta2; + float theta2 = 0.0f; // //polarization calculations // zBeam = ROOT::Math::XYZVector(0.f, 0.f, 1.f); // ẑ: beam direction in lab frame @@ -844,7 +887,7 @@ struct Chargedkstaranalysis { auto phiCS = std::atan2(yAxisCS.Dot(v1CM), xAxisCS.Dot(v1CM)); phiCS = RecoDecay::constrainAngle(phiCS, 0.0); - bool doRotation = (!doprocessMC) || (doprocessMC && mcCfgs.doBkgMc); + bool doRotation = !doprocessMC || mcCfgs.doBkgMc; // if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { if (helicityCfgs.activateHelicityFrame) { // helicityVec = mother.Vect(); // 3 vector of mother in COM frame @@ -867,10 +910,11 @@ struct Chargedkstaranalysis { motherRot = daughterRot + daughter2; } ROOT::Math::Boost boost2{motherRot.BoostToCM()}; - if (helicityCfgs.cCosWithKShot) + if (helicityCfgs.cCosWithKShot) { daughterRotCM = boost2(daughter1); - else + } else { daughterRotCM = boost2(daughterRot); + } auto cosThetaStarHelicityRot = motherRot.Vect().Dot(daughterRotCM.Vect()) / (std::sqrt(daughterRotCM.Vect().Mag2()) * std::sqrt(motherRot.Vect().Mag2())); auto phiHelicityRot = std::atan2(yaxisHE.Dot(daughterRotCM.Vect().Unit()), xaxisHE.Dot(daughterRotCM.Vect().Unit())); @@ -934,10 +978,11 @@ struct Chargedkstaranalysis { motherRot = daughterRot + daughter2; } ROOT::Math::Boost boost2{motherRot.BoostToCM()}; - if (helicityCfgs.cCosWithKShot) + if (helicityCfgs.cCosWithKShot) { daughterRotCM = boost2(daughter1); - else + } else { daughterRotCM = boost2(daughterRot); + } normalVecRot = ROOT::Math::XYZVector(motherRot.Py(), -motherRot.Px(), 0.f); auto cosThetaProductionRot = normalVecRot.Dot(daughterRotCM.Vect()) / (std::sqrt(daughterRotCM.Vect().Mag2()) * std::sqrt(normalVecRot.Mag2())); @@ -1002,10 +1047,11 @@ struct Chargedkstaranalysis { } ROOT::Math::Boost boost2{motherRot.BoostToCM()}; - if (helicityCfgs.cCosWithKShot) + if (helicityCfgs.cCosWithKShot) { daughterRotCM = boost2(daughter1); - else + } else { daughterRotCM = boost2(daughterRot); + } auto cosThetaStarRandomRot = randomVecRot.Dot(daughterRotCM.Vect()) / std::sqrt(daughterRotCM.Vect().Mag2()); if (std::abs(motherRot.Rapidity()) < helicityCfgs.rapidityMotherData) { @@ -1057,8 +1103,9 @@ struct Chargedkstaranalysis { } } - if (!trackCut(bTrack) || !selectionPIDPion(bTrack)) + if (!trackCut(bTrack) || !selectionPIDPion(bTrack)) { continue; + } if constexpr (!IsMix) { if (!doprocessMC && isQaRequired) { @@ -1140,8 +1187,9 @@ struct Chargedkstaranalysis { if ((!secondaryCutsCfgs.cfgByPassDauPIDSelection && (!selectionPIDPion(pos) || !selectionPIDPion(neg))) || - !selectionK0s(collision, K0scand)) + !selectionK0s(collision, K0scand)) { continue; + } if constexpr (!IsMix) { if (!doprocessMC && isQaRequired) { @@ -1175,7 +1223,6 @@ struct Chargedkstaranalysis { k0sIndicies.push_back(K0scand.index()); } - // ========================= // Pairing // ========================= @@ -1197,8 +1244,9 @@ struct Chargedkstaranalysis { } if (lResoKstar.Rapidity() > kstarCutCfgs.cKstarMaxRap || - lResoKstar.Rapidity() < kstarCutCfgs.cKstarMinRap) + lResoKstar.Rapidity() < kstarCutCfgs.cKstarMinRap) { continue; + } if constexpr (!IsMix) { if (!doprocessMC && isQaRequired) { @@ -1227,8 +1275,9 @@ struct Chargedkstaranalysis { aod::BCsWithTimestamps const&) { histos.fill(HIST("hEvtSelInfo"), 0.5); - if (!colCuts.isSelected(collision)) // Default event selection + if (!colCuts.isSelected(collision)) { // Default event selection return; + } histos.fill(HIST("hEvtSelInfo"), 1.5); if (rctCut.requireRCTFlagChecker && !rctCut.rctChecker(collision)) { return; @@ -1236,11 +1285,13 @@ struct Chargedkstaranalysis { histos.fill(HIST("hEvtSelInfo"), 2.5); lMultiplicity = getCentrality(collision); - if (lMultiplicity < eventCutCfgs.cfgEventCentralityMin || lMultiplicity > eventCutCfgs.cfgEventCentralityMax) + if (lMultiplicity < eventCutCfgs.cfgEventCentralityMin || lMultiplicity > eventCutCfgs.cfgEventCentralityMax) { return; + } histos.fill(HIST("hEvtSelInfo"), 3.5); - if (!collision.isInelGt0()) + if (!collision.isInelGt0()) { return; + } histos.fill(HIST("hEvtSelInfo"), 4.5); colCuts.fillQA(collision); fillHistograms(collision, tracks, v0s); @@ -1265,27 +1316,33 @@ struct Chargedkstaranalysis { for (const auto& [t1, t2] : o2::soa::combinations( o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { // Here t1 corressponds to bachelor track and t2 corressponds to v0s. - if (!trackCut(t1)) + if (!trackCut(t1)) { continue; - if (!selectionPIDPion(t1)) + } + if (!selectionPIDPion(t1)) { continue; + } auto posDauTrack = t2.template posTrack_as(); auto negDauTrack = t2.template negTrack_as(); - if (!secondaryCutsCfgs.cfgByPassDauPIDSelection && !selectionPIDPion(posDauTrack)) // Perhaps it's already applied in trackCut (need to check QA plots) + if (!secondaryCutsCfgs.cfgByPassDauPIDSelection && !selectionPIDPion(posDauTrack)) { // Perhaps it's already applied in trackCut (need to check QA plots) continue; - if (!secondaryCutsCfgs.cfgByPassDauPIDSelection && !selectionPIDPion(negDauTrack)) + } + if (!secondaryCutsCfgs.cfgByPassDauPIDSelection && !selectionPIDPion(negDauTrack)) { continue; - if (!selectionK0s(c2, t2)) + } + if (!selectionK0s(c2, t2)) { continue; + } ROOT::Math::PxPyPzMVector lResoSecondary, lDecayDaughter_bach, lResoKstar; lDecayDaughter_bach = ROOT::Math::PxPyPzMVector(t1.px(), t1.py(), t1.pz(), MassPionCharged); lResoSecondary = ROOT::Math::PxPyPzMVector(t2.px(), t2.py(), t2.pz(), MassK0Short); lResoKstar = lResoSecondary + lDecayDaughter_bach; - if (lResoKstar.Rapidity() > kstarCutCfgs.cKstarMaxRap || lResoKstar.Rapidity() < kstarCutCfgs.cKstarMinRap) + if (lResoKstar.Rapidity() > kstarCutCfgs.cKstarMaxRap || lResoKstar.Rapidity() < kstarCutCfgs.cKstarMinRap) { continue; + } histos.fill(HIST("hInvmass_KstarME"), c1.centFT0M(), lResoKstar.Pt(), lResoKstar.M()); } } @@ -1301,8 +1358,9 @@ struct Chargedkstaranalysis { // To apply event selection and store the collision IDs of reconstructed events that pass the selection criteria for (const auto& coll : events) { - if (!coll.has_mcCollision()) + if (!coll.has_mcCollision()) { continue; + } const auto mcid = coll.mcCollisionId(); @@ -1313,12 +1371,15 @@ struct Chargedkstaranalysis { histos.fill(HIST("QA/MC/QACent_woCut"), lCentrality); histos.fill(HIST("QA/MC/QAvtxz_woCut"), coll.posZ()); } - if (!colCuts.isSelected(coll)) + if (!colCuts.isSelected(coll)) { continue; - if (rctCut.requireRCTFlagChecker && !rctCut.rctChecker(coll)) + } + if (rctCut.requireRCTFlagChecker && !rctCut.rctChecker(coll)) { continue; - if (!coll.isInelGt0()) + } + if (!coll.isInelGt0()) { continue; + } colCuts.fillQA(coll); if (doprocessMC && isQaRequired) { @@ -1326,8 +1387,9 @@ struct Chargedkstaranalysis { histos.fill(HIST("QA/MC/QAvtxz_wVtxzCut"), coll.posZ()); } - if (lCentrality < eventCutCfgs.cfgEventCentralityMin || lCentrality > eventCutCfgs.cfgEventCentralityMax) + if (lCentrality < eventCutCfgs.cfgEventCentralityMin || lCentrality > eventCutCfgs.cfgEventCentralityMax) { continue; + } if (doprocessMC && isQaRequired) { histos.fill(HIST("QA/MC/QACent_wCentCut"), lCentrality); @@ -1340,18 +1402,21 @@ struct Chargedkstaranalysis { for (const auto& coll : mccolls) { bool pass = true; - if (cfgTruthIncludeZvtx && std::abs(coll.posZ()) >= eventCutCfgs.confEvtZvtx) + if (cfgTruthIncludeZvtx && std::abs(coll.posZ()) >= eventCutCfgs.confEvtZvtx) { pass = false; + } if (pass && cfgTruthUseInelGt0) { auto partsThisMc = mcParticles.sliceBy(perMCCollision, coll.globalIndex()); // This is to slice all MC particles belonging to the current MC collision. // To check the INEL > 0 - if (!pwglf::isINELgtNmc(partsThisMc, 0, pdg)) + if (!pwglf::isINELgtNmc(partsThisMc, 0, pdg)) { pass = false; + } } - if (!pass) + if (!pass) { continue; + } const auto mcid = coll.globalIndex(); refClassIds.insert(mcid); @@ -1362,12 +1427,15 @@ struct Chargedkstaranalysis { // Calculating the generated Kstar for (const auto& part : mcParticles) { currentIsGen = true; - if (!part.has_mcCollision()) + if (!part.has_mcCollision()) { continue; - if (std::abs(part.pdgCode()) != kKstarPlus) + } + if (std::abs(part.pdgCode()) != kKstarPlus) { continue; - if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) + } + if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) { continue; + } LorentzVectorSetXYZM lResoSecondary, lDecayDaughter_bach, lResoKstar, lDaughterRot; lResoKstar = LorentzVectorSetXYZM(part.px(), part.py(), part.pz(), MassKPlusStar892); @@ -1384,10 +1452,11 @@ struct Chargedkstaranalysis { if (std::abs(d2.pdgCode()) == kPDGK0s) { bool seenPip = false, seenPim = false; for (const auto& d3 : d2.template daughters_as()) { - if (d3.pdgCode() == +kPiPlus) + if (d3.pdgCode() == +kPiPlus) { seenPip = true; - else if (d3.pdgCode() == -kPiPlus) + } else if (d3.pdgCode() == -kPiPlus) { seenPim = true; + } } if (seenPip && seenPim) { lResoSecondary = LorentzVectorSetXYZM(d2.px(), d2.py(), d2.pz(), MassK0Short); @@ -1397,20 +1466,24 @@ struct Chargedkstaranalysis { } } } - if (hasRightPion && hasK0sToPipi) + if (hasRightPion && hasK0sToPipi) { break; + } } - if (!(hasRightPion && hasK0sToPipi)) + if (!(hasRightPion && hasK0sToPipi)) { continue; + } const auto mcid = part.mcCollisionId(); - if (allowedMcIds.count(mcid) == 0) + if (!allowedMcIds.contains(mcid)) { continue; + } auto iter = centTruthByAllowed.find(mcid); - if (iter == centTruthByAllowed.end()) + if (iter == centTruthByAllowed.end()) { continue; + } const float lCentrality = iter->second; @@ -1429,11 +1502,13 @@ struct Chargedkstaranalysis { currentIsGen = false; auto coll = v0.template collision_as(); - if (!coll.has_mcCollision()) + if (!coll.has_mcCollision()) { continue; + } const auto mcid = coll.mcCollisionId(); - if (allowedMcIds.count(mcid) == 0) + if (!allowedMcIds.contains(mcid)) { continue; // To check the event is allowed or not + } const auto mccoll = coll.template mcCollision_as>(); const float lCentrality = mccoll.centFT0M(); @@ -1441,21 +1516,27 @@ struct Chargedkstaranalysis { if (!secondaryCutsCfgs.cfgByPassDauPIDSelection) { auto posDauTrack = v0.template posTrack_as(); auto negDauTrack = v0.template negTrack_as(); - if (!selectionPIDPion(posDauTrack)) + if (!selectionPIDPion(posDauTrack)) { continue; - if (!selectionPIDPion(negDauTrack)) + } + if (!selectionPIDPion(negDauTrack)) { continue; + } } - if (!selectionK0s(coll, v0)) + if (!selectionK0s(coll, v0)) { continue; + } auto trks = tracks.sliceBy(perCollision, v0.collisionId()); // Grouping the tracks with the v0s, means only those tracks that belong to the same collision as v0 for (const auto& bTrack : trks) { - if (bTrack.collisionId() != v0.collisionId()) + if (bTrack.collisionId() != v0.collisionId()) { continue; - if (!trackCut(bTrack)) + } + if (!trackCut(bTrack)) { continue; - if (!selectionPIDPion(bTrack)) + } + if (!selectionPIDPion(bTrack)) { continue; + } LorentzVectorSetXYZM lResoSecondary, lDecayDaughter_bach, lResoKstar, lDaughterRot; lResoSecondary = LorentzVectorSetXYZM(v0.px(), v0.py(), v0.pz(), MassK0Short); @@ -1464,17 +1545,32 @@ struct Chargedkstaranalysis { const double ptreco = lResoKstar.Pt(); const double yreco = lResoKstar.Rapidity(); - if (std::abs(yreco) > kstarCutCfgs.cKstarMaxRap) + if (std::abs(yreco) > kstarCutCfgs.cKstarMaxRap) { continue; + } + + if (mcCfgs.doMcClosure) { + // For MC clousre test + mcClosure = true; + if (helicityCfgs.cCosWithKShot) { + fillInvMass(lResoKstar, lCentrality, lResoSecondary, lDecayDaughter_bach, eventCutCfgs.confIsMix); + } else { + fillInvMass(lResoKstar, lCentrality, lDecayDaughter_bach, lResoSecondary, eventCutCfgs.confIsMix); + } + } + mcClosure = false; // Since we are doing the MC study and we know about the PDG code of each particle let's try to check the things which we have - if (!v0.has_mcParticle() || !bTrack.has_mcParticle()) + if (!v0.has_mcParticle() || !bTrack.has_mcParticle()) { continue; + } auto mcK0s = v0.template mcParticle_as(); // To get the MC truth particle corressponds to the V0 candidate auto mcPi = bTrack.template mcParticle_as(); - if (std::abs(mcK0s.pdgCode()) != kPDGK0s) + if (std::abs(mcK0s.pdgCode()) != kPDGK0s) { continue; - if (std::abs(mcPi.pdgCode()) != kPiPlus) + } + if (std::abs(mcPi.pdgCode()) != kPiPlus) { continue; + } MCTrueTrackCandidates::iterator kstarFromPi; bool havePiKstar = false; // Loops over all the mother's of pions and check if this pion comming from a kstar @@ -1498,8 +1594,9 @@ struct Chargedkstaranalysis { break; } } - if (shareSameKstar) + if (shareSameKstar) { break; + } } } if (!shareSameKstar) { @@ -1517,20 +1614,25 @@ struct Chargedkstaranalysis { } // To calculate the event losses to store the generated KstartPlus --> To check the number of events remains after passing all the event selection criteria for chk892 for (auto const& part : mcParticles) { - if (!part.has_mcCollision()) + if (!part.has_mcCollision()) { continue; - if (std::abs(part.pdgCode()) != kKstarPlus) + } + if (std::abs(part.pdgCode()) != kKstarPlus) { continue; - if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) + } + if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) { continue; + } const auto mcid = part.mcCollisionId(); - if (allowedMcIds.count(mcid) == 0) + if (!allowedMcIds.contains(mcid)) { continue; + } auto iter = centTruthByAllowed.find(mcid); - if (iter == centTruthByAllowed.end()) + if (iter == centTruthByAllowed.end()) { continue; + } const float lCentrality = iter->second; @@ -1541,20 +1643,25 @@ struct Chargedkstaranalysis { } // To calculate the denominator -> To check the all the events have chk892 for (auto const& part : mcParticles) { - if (!part.has_mcCollision()) + if (!part.has_mcCollision()) { continue; - if (std::abs(part.pdgCode()) != kKstarPlus) + } + if (std::abs(part.pdgCode()) != kKstarPlus) { continue; - if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) + } + if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) { continue; + } const auto mcid = part.mcCollisionId(); - if (refClassIds.count(mcid) == 0) + if (!refClassIds.contains(mcid)) { continue; + } auto iter = refCentByMcId.find(mcid); - if (iter == refCentByMcId.end()) + if (iter == refCentByMcId.end()) { continue; + } const float lCentrality = iter->second; @@ -1569,8 +1676,9 @@ struct Chargedkstaranalysis { } for (const auto& mcid : allowedMcIds) { auto iter = centTruthByAllowed.find(mcid); - if (iter == centTruthByAllowed.end()) + if (iter == centTruthByAllowed.end()) { continue; + } const float lCentrality = iter->second; histos.fill(HIST("Correction/EF_num"), lCentrality); @@ -1593,13 +1701,14 @@ struct Chargedkstaranalysis { histos.fill(HIST("Correction/hNEventsMCTruth"), 3.0); } } - if (allowedMcIds.count(mcid)) { + if (allowedMcIds.contains(mcid)) { histos.fill(HIST("Correction/hNEventsMCTruth"), 4.0); } } } PROCESS_SWITCH(Chargedkstaranalysis, processMC, "Process Event for MC", false); }; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; From 746e6d733569e55d4f6997350fc296f90d2de614 Mon Sep 17 00:00:00 2001 From: Lucia Anna Tarasovicova Date: Mon, 27 Jul 2026 22:09:43 +0200 Subject: [PATCH 09/71] [PWGLF] New developments in h-Strangeness analysis (#17220) Co-authored-by: Lucia Anna Tarasovicova --- PWGLF/DataModel/LFHStrangeCorrelationTables.h | 6 +- .../Strangeness/hStrangeCorrelationFilter.cxx | 421 ++++--- .../Tasks/Strangeness/hStrangeCorrelation.cxx | 1096 +++++++++++------ 3 files changed, 950 insertions(+), 573 deletions(-) diff --git a/PWGLF/DataModel/LFHStrangeCorrelationTables.h b/PWGLF/DataModel/LFHStrangeCorrelationTables.h index 34404079cbc..ac0ec907db9 100644 --- a/PWGLF/DataModel/LFHStrangeCorrelationTables.h +++ b/PWGLF/DataModel/LFHStrangeCorrelationTables.h @@ -43,8 +43,9 @@ DECLARE_SOA_COLUMN(MCPhysicalPrimary, mcPhysicalPrimary, bool); // true ph DECLARE_SOA_INDEX_COLUMN_FULL(Track, track, int, Tracks, "_Trigger"); //! DECLARE_SOA_COLUMN(MCOriginalPt, mcOriginalPt, float); // true generated pt DECLARE_SOA_COLUMN(IsLeading, isLeading, bool); // is leading track in the event +DECLARE_SOA_COLUMN(MCMask, mcMask, uint16_t); // MC mask of the MC particle } // namespace triggerTracks -DECLARE_SOA_TABLE(TriggerTracks, "AOD", "TRIGGERTRACKS", o2::soa::Index<>, triggerTracks::CollisionId, triggerTracks::MCPhysicalPrimary, triggerTracks::TrackId, triggerTracks::MCOriginalPt, triggerTracks::IsLeading); +DECLARE_SOA_TABLE(TriggerTracks, "AOD", "TRIGGERTRACKS", o2::soa::Index<>, triggerTracks::CollisionId, triggerTracks::MCPhysicalPrimary, triggerTracks::TrackId, triggerTracks::MCOriginalPt, triggerTracks::IsLeading, triggerTracks::MCMask); namespace triggerTrackExtras { DECLARE_SOA_COLUMN(Extra, extra, int); // true physical primary flag @@ -59,8 +60,9 @@ DECLARE_SOA_COLUMN(MCPhysicalPrimary, mcPhysicalPrimary, bool); // true phys DECLARE_SOA_INDEX_COLUMN_FULL(Track, track, int, Tracks, "_Assoc"); //! DECLARE_SOA_COLUMN(MCOriginalPt, mcOriginalPt, float); // true generated pt DECLARE_SOA_COLUMN(PDGCode, pdgCode, float); // pdg code of the MC particle +DECLARE_SOA_COLUMN(MCMask, mcMask, uint16_t); // MC mask of the MC particle } // namespace assocHadrons -DECLARE_SOA_TABLE(AssocHadrons, "AOD", "ASSOCHADRONS", o2::soa::Index<>, assocHadrons::CollisionId, assocHadrons::MCPhysicalPrimary, assocHadrons::TrackId, assocHadrons::MCOriginalPt, assocHadrons::PDGCode); +DECLARE_SOA_TABLE(AssocHadrons, "AOD", "ASSOCHADRONS", o2::soa::Index<>, assocHadrons::CollisionId, assocHadrons::MCPhysicalPrimary, assocHadrons::TrackId, assocHadrons::MCOriginalPt, assocHadrons::PDGCode, assocHadrons::MCMask); /// _________________________________________ /// Table for storing assoc track PID namespace assocPID diff --git a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx index ecd50c6dd54..b405d3855d5 100644 --- a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx +++ b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx @@ -59,12 +59,9 @@ using namespace o2::constants::math; using namespace o2::framework; using namespace o2::framework::expressions; -#define BIT_SET(var, nbit) ((var) |= (1 << (nbit))) -#define BIT_CHECK(var, nbit) ((var) & (1 << (nbit))) - struct HStrangeCorrelationFilter { - const float ctauxi = 4.91; // from PDG - const float ctauomega = 2.461; // from PDG + static constexpr float Xictau = 4.91; // from PDG + static constexpr float Omegactau = 2.461; // from PDG Service ccdb; @@ -249,14 +246,14 @@ struct HStrangeCorrelationFilter { TF1* fXiWidth = new TF1("fXiWidth", "[0]+[1]*x+[2]*std::exp(-[3]*x)"); TF1* fOmegaMean = new TF1("fomegaMean", "[0]+[1]*x+[2]*std::exp(-[3]*x)"); TF1* fOmegaWidth = new TF1("fomegaWidth", "[0]+[1]*x+[2]*std::exp(-[3]*x)"); - TH1F* hK0ShortMean; - TH1F* hK0ShortWidth; - TH1F* hLambdaMean; - TH1F* hLambdaWidth; - TH1F* hXiMean; - TH1F* hXiWidth; - TH1F* hOmegaMean; - TH1F* hOmegaWidth; + TH1F* hK0ShortMean = nullptr; + TH1F* hK0ShortWidth = nullptr; + TH1F* hLambdaMean = nullptr; + TH1F* hLambdaWidth = nullptr; + TH1F* hXiMean = nullptr; + TH1F* hXiWidth = nullptr; + TH1F* hOmegaMean = nullptr; + TH1F* hOmegaWidth = nullptr; Zorro zorro; OutputObj zorroSummary{"zorroSummary"}; int mRunNumber; @@ -267,6 +264,7 @@ struct HStrangeCorrelationFilter { int trackId; bool isPhysicalPrimary; float origPt; + uint16_t mcMask; }; TriggCandidate thisTrigg; @@ -286,14 +284,14 @@ struct HStrangeCorrelationFilter { fOmegaMean->SetParameters(parameters.massParsOmegaMean->at(0), parameters.massParsOmegaMean->at(1), parameters.massParsOmegaMean->at(2), parameters.massParsOmegaMean->at(3)); fOmegaWidth->SetParameters(parameters.massParsOmegaWidth->at(0), parameters.massParsOmegaWidth->at(1), parameters.massParsOmegaWidth->at(2), parameters.massParsOmegaWidth->at(3)); } else { - hK0ShortMean = 0x0; - hK0ShortWidth = 0x0; - hLambdaMean = 0x0; - hLambdaWidth = 0x0; - hXiMean = 0x0; - hXiWidth = 0x0; - hOmegaMean = 0x0; - hOmegaWidth = 0x0; + hK0ShortMean = nullptr; + hK0ShortWidth = nullptr; + hLambdaMean = nullptr; + hLambdaWidth = nullptr; + hXiMean = nullptr; + hXiWidth = nullptr; + hOmegaMean = nullptr; + hOmegaWidth = nullptr; } if (doprocessV0s || doprocessV0sMC) { histos.add("h3dMassK0Short", "h3dMassK0Short", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisK0ShortMass, axesConfigurations.axisMult}); @@ -329,22 +327,22 @@ struct HStrangeCorrelationFilter { LOG(info) << "Loading mean and sigma from CCDB for run " << mRunNumber << " now..."; auto timeStamp = bc.timestamp(); - TList* listParameters = ccdb->getForTimeStamp(parameterCCDBPath, timeStamp); + auto listParameters = ccdb->getForTimeStamp(parameterCCDBPath, timeStamp); if (!listParameters) { LOG(fatal) << "Problem getting TList object with parameters!"; } if (doprocessV0s || doprocessV0sMC) { - hK0ShortMean = static_cast(listParameters->FindObject("hK0ShortMean")); - hK0ShortWidth = static_cast(listParameters->FindObject("hK0ShortWidth")); - hLambdaMean = static_cast(listParameters->FindObject("hLambdaMean")); - hLambdaWidth = static_cast(listParameters->FindObject("hLambdaWidth")); + hK0ShortMean = dynamic_cast(listParameters->FindObject("hK0ShortMean")); + hK0ShortWidth = dynamic_cast(listParameters->FindObject("hK0ShortWidth")); + hLambdaMean = dynamic_cast(listParameters->FindObject("hLambdaMean")); + hLambdaWidth = dynamic_cast(listParameters->FindObject("hLambdaWidth")); } if (doprocessCascades || doprocessCascadesMC) { - hXiMean = static_cast(listParameters->FindObject("hXiMean")); - hXiWidth = static_cast(listParameters->FindObject("hXiWidth")); - hOmegaMean = static_cast(listParameters->FindObject("hOmegaMean")); - hOmegaWidth = static_cast(listParameters->FindObject("hOmegaWidth")); + hXiMean = dynamic_cast(listParameters->FindObject("hXiMean")); + hXiWidth = dynamic_cast(listParameters->FindObject("hXiWidth")); + hOmegaMean = dynamic_cast(listParameters->FindObject("hOmegaMean")); + hOmegaWidth = dynamic_cast(listParameters->FindObject("hOmegaWidth")); } LOG(info) << "parameters now loaded for " << mRunNumber; } @@ -383,29 +381,36 @@ struct HStrangeCorrelationFilter { // more event selections in Pb-Pb template - bool isCollisionSelectedPbPb(TCollision collision) + bool isCollisionSelectedPbPb(TCollision const& collision) { - if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) && eventSelections.requireGoodTriggerTVX) /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */ + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) && eventSelections.requireGoodTriggerTVX) { /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */ return false; - if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) && eventSelections.requireAllGoodITSLayers) // cut time intervals with dead ITS staves + } + if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll) && eventSelections.requireAllGoodITSLayers) { // cut time intervals with dead ITS staves return false; - if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) && eventSelections.requireGoodZvtxFT0vsPV) // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + } + if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) && eventSelections.requireGoodZvtxFT0vsPV) { // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference return false; + } auto occupancy = collision.trackOccupancyInTimeRange(); - if (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh) /* Below min occupancy and Above max occupancy*/ + if (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh) { /* Below min occupancy and Above max occupancy*/ return false; - if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) // reject collisions close to Time Frame borders + } + if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { // reject collisions close to Time Frame borders return false; - if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) // reject events affected by the ITS ROF border + } + if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { // reject events affected by the ITS ROF border return false; - if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) // rejects collisions which are associated with the same "found-by-T0" bunch crossing + } + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { // rejects collisions which are associated with the same "found-by-T0" bunch crossing return false; + } return true; } // reco-level trigger quality checks (N.B.: DCA is filtered, not selected) template - bool isValidTrigger(TTrack track) + bool isValidTrigger(TTrack const& track) { if (track.eta() > generalSelections.triggerEtaMax || track.eta() < generalSelections.triggerEtaMin) { return false; @@ -423,13 +428,13 @@ struct HStrangeCorrelationFilter { if (track.tpcNClsShared() > trackSelections.triggerMaxTPCSharedClusters) { return false; // skip, has shared clusters } - if (!(BIT_CHECK(track.itsClusterMap(), 0)) && trackSelections.triggerRequireL0) { + if (!(TESTBIT(track.itsClusterMap(), 0)) && trackSelections.triggerRequireL0) { return false; // skip, doesn't have cluster in ITS L0 } return true; } template - bool isValidAssocTrack(TTrack assoc) + bool isValidAssocTrack(TTrack const& assoc) { if (assoc.eta() > generalSelections.assocEtaMax || assoc.eta() < generalSelections.assocEtaMin) { return false; @@ -445,30 +450,38 @@ struct HStrangeCorrelationFilter { } // do this only if information is available - float nSigmaTPCTOF[8] = {-10, -10, -10, -10, -10, -10, -10, -10}; + std::array nSigmaTPCTOF = {-10, -10, -10, -10, -10, -10, -10, -10}; if constexpr (requires { assoc.tofSignal(); } && !requires { assoc.mcParticle(); }) { if (assoc.tofSignal() > 0) { - if (std::sqrt(assoc.tofNSigmaPi() * assoc.tofNSigmaPi() + assoc.tpcNSigmaPi() * assoc.tpcNSigmaPi()) > trackSelections.assocPionNSigmaTPCFOF) + if (std::sqrt(assoc.tofNSigmaPi() * assoc.tofNSigmaPi() + assoc.tpcNSigmaPi() * assoc.tpcNSigmaPi()) > trackSelections.assocPionNSigmaTPCFOF) { return false; - if (assoc.tofNSigmaPr() < trackSelections.rejectSigma) + } + if (assoc.tofNSigmaPr() < trackSelections.rejectSigma) { return false; - if (assoc.tpcNSigmaPr() < trackSelections.rejectSigma) + } + if (assoc.tpcNSigmaPr() < trackSelections.rejectSigma) { return false; - if (assoc.tofNSigmaKa() < trackSelections.rejectSigma) + } + if (assoc.tofNSigmaKa() < trackSelections.rejectSigma) { return false; - if (assoc.tpcNSigmaKa() < trackSelections.rejectSigma) + } + if (assoc.tpcNSigmaKa() < trackSelections.rejectSigma) { return false; + } nSigmaTPCTOF[4] = assoc.tofNSigmaPi(); nSigmaTPCTOF[5] = assoc.tofNSigmaKa(); nSigmaTPCTOF[6] = assoc.tofNSigmaPr(); nSigmaTPCTOF[7] = assoc.tofNSigmaEl(); } else { - if (assoc.tpcNSigmaPi() > trackSelections.assocPionNSigmaTPCFOF) + if (assoc.tpcNSigmaPi() > trackSelections.assocPionNSigmaTPCFOF) { return false; - if (assoc.tpcNSigmaPr() < trackSelections.rejectSigma) + } + if (assoc.tpcNSigmaPr() < trackSelections.rejectSigma) { return false; - if (assoc.tpcNSigmaKa() < trackSelections.rejectSigma) + } + if (assoc.tpcNSigmaKa() < trackSelections.rejectSigma) { return false; + } } nSigmaTPCTOF[0] = assoc.tpcNSigmaPi(); nSigmaTPCTOF[1] = assoc.tpcNSigmaKa(); @@ -479,12 +492,14 @@ struct HStrangeCorrelationFilter { bool physicalPrimary = false; float origPt = -1; float code = -9999; + uint16_t mcMask = 0; if constexpr (requires { assoc.mcParticle(); }) { if (assoc.has_mcParticle()) { auto mcParticle = assoc.mcParticle(); physicalPrimary = mcParticle.isPhysicalPrimary(); origPt = mcParticle.pt(); code = mcParticle.pdgCode(); + mcMask = assoc.mcMask(); } } @@ -493,7 +508,8 @@ struct HStrangeCorrelationFilter { physicalPrimary, assoc.globalIndex(), origPt, - code); + code, + mcMask); assocPID( nSigmaTPCTOF[0], nSigmaTPCTOF[1], @@ -508,43 +524,54 @@ struct HStrangeCorrelationFilter { // cascadeselection in PbPb template - bool cascadeSelectedPbPb(TCascade casc, float pvx, float pvy, float pvz) + bool cascadeSelectedPbPb(TCascade const& casc, float pvx, float pvy, float pvz) { // bachBaryonCosPA - if (casc.bachBaryonCosPA() < cascSelection.bachBaryonCosPA) + if (casc.bachBaryonCosPA() < cascSelection.bachBaryonCosPA) { return false; + } // bachBaryonDCAxyToPV - if (std::abs(casc.bachBaryonDCAxyToPV()) > cascSelection.bachBaryonDCAxyToPV) + if (std::abs(casc.bachBaryonDCAxyToPV()) > cascSelection.bachBaryonDCAxyToPV) { return false; + } // casccosPA - if (casc.casccosPA(pvx, pvy, pvz) < cascSelection.cascCospa) + if (casc.casccosPA(pvx, pvy, pvz) < cascSelection.cascCospa) { return false; + } // dcacascdaughters float ptDepCut = cascSelection.dcaCacsDauPar0; - if (casc.pt() > cascSelection.lowPtForCascDaugPtDep && casc.pt() < cascSelection.highPtForCascDaugPtDep) + if (casc.pt() > cascSelection.lowPtForCascDaugPtDep && casc.pt() < cascSelection.highPtForCascDaugPtDep) { ptDepCut = cascSelection.dcaCacsDauPar1; - else if (casc.pt() > cascSelection.highPtForCascDaugPtDep) + } else if (casc.pt() > cascSelection.highPtForCascDaugPtDep) { ptDepCut = cascSelection.dcaCacsDauPar2; - if (casc.dcacascdaughters() > ptDepCut) + } + if (casc.dcacascdaughters() > ptDepCut) { return false; + } // dcaV0daughters - if (casc.dcaV0daughters() > cascSelection.cascdcaV0dau) + if (casc.dcaV0daughters() > cascSelection.cascdcaV0dau) { return false; + } // dcav0topv - if (std::abs(casc.dcav0topv(pvx, pvy, pvz)) < cascSelection.cascMindcav0topv) + if (std::abs(casc.dcav0topv(pvx, pvy, pvz)) < cascSelection.cascMindcav0topv) { return false; + } // cascradius - if (casc.cascradius() < cascSelection.cascRadius) + if (casc.cascradius() < cascSelection.cascRadius) { return false; + } // v0radius - if (casc.v0radius() < cascSelection.cascv0RadiusMin) + if (casc.v0radius() < cascSelection.cascv0RadiusMin) { return false; + } // v0cosPA - if (casc.v0cosPA(casc.x(), casc.y(), casc.z()) < cascSelection.cascv0cospa) + if (casc.v0cosPA(casc.x(), casc.y(), casc.z()) < cascSelection.cascv0cospa) { return false; + } // lambdaMassWin - if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.lambdaMassWin) + if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.lambdaMassWin) { return false; + } return true; } @@ -561,8 +588,9 @@ struct HStrangeCorrelationFilter { double leadingPt = -1.; int leadingId = -1; for (auto const& track : tracks) { - if (!isValidTrigger(track)) + if (!isValidTrigger(track)) { continue; + } thisTrigg.pt = track.pt(); thisTrigg.trackId = track.globalIndex(); thisTrigg.collisionId = track.collisionId(); @@ -581,7 +609,8 @@ struct HStrangeCorrelationFilter { TriggCandidate.isPhysicalPrimary, TriggCandidate.trackId, TriggCandidate.origPt, - isLeading); + isLeading, + 0); triggerTrackExtra(1); } } @@ -599,8 +628,9 @@ struct HStrangeCorrelationFilter { double leadingPt = -1.; int leadingId = -1; for (auto const& track : tracks) { - if (!isValidTrigger(track)) + if (!isValidTrigger(track)) { continue; + } thisTrigg.pt = track.pt(); thisTrigg.trackId = track.globalIndex(); thisTrigg.collisionId = track.collisionId(); @@ -608,6 +638,7 @@ struct HStrangeCorrelationFilter { auto mcParticle = track.mcParticle(); thisTrigg.isPhysicalPrimary = mcParticle.isPhysicalPrimary(); thisTrigg.origPt = mcParticle.pt(); + thisTrigg.mcMask = track.mcMask(); } triggerCandidates.push_back(thisTrigg); if (track.pt() > leadingPt) { @@ -623,7 +654,8 @@ struct HStrangeCorrelationFilter { TriggCandidate.isPhysicalPrimary, TriggCandidate.trackId, TriggCandidate.origPt, - isLeading); + isLeading, + TriggCandidate.mcMask); triggerTrackExtra(1); } } @@ -651,8 +683,9 @@ struct HStrangeCorrelationFilter { /// _________________________________________________ /// Step 1: Populate table with trigger tracks for (auto const& track : tracks) { - if (!isValidAssocTrack(track)) + if (!isValidAssocTrack(track)) { continue; + } } } @@ -679,8 +712,9 @@ struct HStrangeCorrelationFilter { /// _________________________________________________ /// Step 1: Populate table with trigger tracks for (auto const& track : tracks) { - if (!isValidAssocTrack(track)) + if (!isValidAssocTrack(track)) { continue; + } } } @@ -707,8 +741,9 @@ struct HStrangeCorrelationFilter { /// _________________________________________________ /// Step 1: Populate table with trigger tracks for (auto const& track : tracks) { - if (!isValidAssocTrack(track)) + if (!isValidAssocTrack(track)) { continue; + } } } void processAssocHadronsMC(soa::Join::iterator const& collision, soa::Filtered const& tracks, aod::McParticles const&, aod::BCsWithTimestamps const&) @@ -734,8 +769,9 @@ struct HStrangeCorrelationFilter { /// _________________________________________________ /// Step 1: Populate table with trigger tracks for (auto const& track : tracks) { - if (!isValidAssocTrack(track)) + if (!isValidAssocTrack(track)) { continue; + } } } @@ -756,19 +792,22 @@ struct HStrangeCorrelationFilter { continue; } // check dE/dx compatibility - int compatibleK0Short = 0; - int compatibleLambda = 0; - int compatibleAntiLambda = 0; + int compatibleK0Short = -1; + int compatibleLambda = -1; + int compatibleAntiLambda = -1; auto posdau = v0.posTrack_as(); auto negdau = v0.negTrack_as(); - if (negdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + if (negdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (posdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + } + if (posdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (trackSelections.requireClusterInITS && (posdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) + } + if (trackSelections.requireClusterInITS && (posdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) { continue; + } float dcaDauCutForK0s = v0Selection.dcaDaugToPVForK0s == 0 ? v0Selection.dcaMesonToPV : v0Selection.dcaDaugToPVForK0s; bool isGoodK0Short = (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S && @@ -780,48 +819,48 @@ struct HStrangeCorrelationFilter { std::abs(v0.dcapostopv()) > v0Selection.dcaMesonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaBaryonToPV); if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { if (doPPAnalysis || isGoodK0Short) { - BIT_SET(compatibleK0Short, 0); + SETBIT(compatibleK0Short, 0); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { if (doPPAnalysis || isGoodK0Short) { - BIT_SET(compatibleK0Short, 1); + SETBIT(compatibleK0Short, 1); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { if (doPPAnalysis || isGoodK0Short) { - BIT_SET(compatibleK0Short, 2); + SETBIT(compatibleK0Short, 2); } } if (v0.v0cosPA() > v0Selection.lambdaCospa) { if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { if (doPPAnalysis || isGoodLambda) { - BIT_SET(compatibleLambda, 0); + SETBIT(compatibleLambda, 0); } } if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { if (doPPAnalysis || isGoodLambda) { - BIT_SET(compatibleLambda, 1); + SETBIT(compatibleLambda, 1); } } if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { if (doPPAnalysis || isGoodLambda) { - BIT_SET(compatibleLambda, 2); + SETBIT(compatibleLambda, 2); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose) { if (doPPAnalysis || isGoodAntiLambda) { - BIT_SET(compatibleAntiLambda, 0); + SETBIT(compatibleAntiLambda, 0); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigma) { if (doPPAnalysis || isGoodAntiLambda) { - BIT_SET(compatibleAntiLambda, 1); + SETBIT(compatibleAntiLambda, 1); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaTight) { if (doPPAnalysis || isGoodAntiLambda) { - BIT_SET(compatibleAntiLambda, 2); + SETBIT(compatibleAntiLambda, 2); } } } @@ -846,12 +885,15 @@ struct HStrangeCorrelationFilter { massNSigmaAntiLambda = (v0.mAntiLambda() - hLambdaMean->Interpolate(v0.pt())) / (hLambdaWidth->Interpolate(v0.pt()) + 1e-6); } } - if (compatibleK0Short) + if (compatibleK0Short > 0) { histos.fill(HIST("h3dMassK0Short"), v0.pt(), v0.mK0Short(), cent); - if (compatibleLambda) + } + if (compatibleLambda > 0) { histos.fill(HIST("h3dMassLambda"), v0.pt(), v0.mLambda(), cent); - if (compatibleAntiLambda) + } + if (compatibleAntiLambda > 0) { histos.fill(HIST("h3dMassAntiLambda"), v0.pt(), v0.mAntiLambda(), cent); + } if (!fillTableOnlyWithCompatible || ( // start major condition check @@ -885,19 +927,22 @@ struct HStrangeCorrelationFilter { continue; } // check dE/dx compatibility - int compatibleK0Short = 0; - int compatibleLambda = 0; - int compatibleAntiLambda = 0; + int compatibleK0Short = -1; + int compatibleLambda = -1; + int compatibleAntiLambda = -1; auto posdau = v0.posTrack_as(); auto negdau = v0.negTrack_as(); - if (negdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + if (negdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (posdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + } + if (posdau.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (trackSelections.requireClusterInITS && (posdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) + } + if (trackSelections.requireClusterInITS && (posdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) { continue; + } float dcaDauCutForK0s = v0Selection.dcaDaugToPVForK0s == 0 ? v0Selection.dcaMesonToPV : v0Selection.dcaDaugToPVForK0s; bool isGoodK0Short = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S && @@ -909,49 +954,49 @@ struct HStrangeCorrelationFilter { std::abs(v0.dcapostopv()) > v0Selection.dcaMesonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaBaryonToPV; if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { if (doPPAnalysis || isGoodK0Short) { - BIT_SET(compatibleK0Short, 0); + SETBIT(compatibleK0Short, 0); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { if (doPPAnalysis || isGoodK0Short) { - BIT_SET(compatibleK0Short, 1); + SETBIT(compatibleK0Short, 1); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { if (doPPAnalysis || isGoodK0Short) { - BIT_SET(compatibleK0Short, 2); + SETBIT(compatibleK0Short, 2); } } if (v0.v0cosPA() > v0Selection.lambdaCospa) { if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose) { if (doPPAnalysis || isGoodLambda) { - BIT_SET(compatibleLambda, 0); + SETBIT(compatibleLambda, 0); } } if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigma) { if (doPPAnalysis || isGoodLambda) { - BIT_SET(compatibleLambda, 1); + SETBIT(compatibleLambda, 1); } } if (std::abs(posdau.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPi()) < strangedEdxNSigmaTight) { if (doPPAnalysis || isGoodLambda) { - BIT_SET(compatibleLambda, 2); + SETBIT(compatibleLambda, 2); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaLoose) { if (doPPAnalysis || isGoodAntiLambda) { - BIT_SET(compatibleAntiLambda, 0); + SETBIT(compatibleAntiLambda, 0); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigma) { if (doPPAnalysis || isGoodAntiLambda) { - BIT_SET(compatibleAntiLambda, 1); + SETBIT(compatibleAntiLambda, 1); } } if (std::abs(posdau.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negdau.tpcNSigmaPr()) < strangedEdxNSigmaTight) { if (doPPAnalysis || isGoodAntiLambda) { - BIT_SET(compatibleAntiLambda, 2); + SETBIT(compatibleAntiLambda, 2); } } } @@ -982,18 +1027,24 @@ struct HStrangeCorrelationFilter { bool trueLambda = false; bool trueAntiLambda = false; v0PhysicalPrimary = v0.isPhysicalPrimary(); - if (v0.pdgCode() == PDG_t::kK0Short) + if (v0.pdgCode() == PDG_t::kK0Short) { trueK0Short = true; - if (v0.pdgCode() == PDG_t::kLambda0) + } + if (v0.pdgCode() == PDG_t::kLambda0) { trueLambda = true; - if (v0.pdgCode() == PDG_t::kLambda0Bar) + } + if (v0.pdgCode() == PDG_t::kLambda0Bar) { trueAntiLambda = true; - if (compatibleK0Short && (!doTrueSelectionInMass || (trueK0Short && v0PhysicalPrimary))) + } + if (compatibleK0Short > 0 && (!doTrueSelectionInMass || (trueK0Short && v0PhysicalPrimary))) { histos.fill(HIST("h3dMassK0Short"), v0.pt(), v0.mK0Short(), cent); - if (compatibleLambda && (!doTrueSelectionInMass || (trueLambda && v0PhysicalPrimary))) + } + if (compatibleLambda > 0 && (!doTrueSelectionInMass || (trueLambda && v0PhysicalPrimary))) { histos.fill(HIST("h3dMassLambda"), v0.pt(), v0.mLambda(), cent); - if (compatibleAntiLambda && (!doTrueSelectionInMass || (trueAntiLambda && v0PhysicalPrimary))) + } + if (compatibleAntiLambda > 0 && (!doTrueSelectionInMass || (trueAntiLambda && v0PhysicalPrimary))) { histos.fill(HIST("h3dMassAntiLambda"), v0.pt(), v0.mAntiLambda(), cent); + } if (!fillTableOnlyWithCompatible || ( // start major condition check @@ -1029,37 +1080,43 @@ struct HStrangeCorrelationFilter { casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascSelection.cascCospa || casc.cascradius() < cascSelection.cascRadius || std::abs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cascSelection.cascMindcav0topv || - std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.cascV0masswindow)) + std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.cascV0masswindow)) { continue; + } auto bachTrackCast = casc.bachelor_as(); auto posTrackCast = casc.posTrack_as(); auto negTrackCast = casc.negTrack_as(); // minimum TPC crossed rows - if (bachTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + if (bachTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (posTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + } + if (posTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (negTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + } + if (negTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (!doPPAnalysis && !cascadeSelectedPbPb(casc, collision.posX(), collision.posY(), collision.posZ())) + } + if (!doPPAnalysis && !cascadeSelectedPbPb(casc, collision.posX(), collision.posY(), collision.posZ())) { continue; - if (trackSelections.requireClusterInITS && (posTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || bachTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) + } + if (trackSelections.requireClusterInITS && (posTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || bachTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) { continue; + } bool isGoodNegCascadePbPb = std::abs(casc.dcabachtopv()) > cascSelection.dcaBachToPV && std::abs(casc.dcapostopv()) > cascSelection.cascDcaBaryonToPV && std::abs(casc.dcanegtopv()) > cascSelection.cascDcaMesonToPV; bool isGoodPosCascadePbPb = std::abs(casc.dcabachtopv()) > cascSelection.dcaBachToPV && std::abs(casc.dcapostopv()) > cascSelection.cascDcaMesonToPV && std::abs(casc.dcanegtopv()) > cascSelection.cascDcaBaryonToPV; // check dE/dx compatibility - int compatibleXiMinus = 0; - int compatibleXiPlus = 0; - int compatibleOmegaMinus = 0; - int compatibleOmegaPlus = 0; + int compatibleXiMinus = -1; + int compatibleXiPlus = -1; + int compatibleOmegaMinus = -1; + int compatibleOmegaPlus = -1; float cascpos = std::hypot(casc.x() - collision.posX(), casc.y() - collision.posY(), casc.z() - collision.posZ()); float cascptotmom = std::hypot(casc.px(), casc.py(), casc.pz()); - float ctauXi = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * ctauxi); - float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * ctauomega); + float ctauXi = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * Xictau); + float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * Omegactau); bool isGoodXiPbPb = std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascSelection.rejcomp && ctauXi < cascSelection.proplifetime && std::abs(casc.yXi()) < cascSelection.rapCut; @@ -1067,65 +1124,65 @@ struct HStrangeCorrelationFilter { ctauOmega < cascSelection.proplifetime && std::abs(casc.yOmega()) < cascSelection.rapCut; if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodXiPbPb)) { - BIT_SET(compatibleXiMinus, 0); + SETBIT(compatibleXiMinus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodXiPbPb)) { - BIT_SET(compatibleXiMinus, 1); + SETBIT(compatibleXiMinus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodXiPbPb)) { - BIT_SET(compatibleXiMinus, 2); + SETBIT(compatibleXiMinus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodXiPbPb)) { - BIT_SET(compatibleXiPlus, 0); + SETBIT(compatibleXiPlus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodXiPbPb)) { - BIT_SET(compatibleXiPlus, 1); + SETBIT(compatibleXiPlus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodXiPbPb)) { - BIT_SET(compatibleXiPlus, 2); + SETBIT(compatibleXiPlus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaMinus, 0); + SETBIT(compatibleOmegaMinus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaMinus, 1); + SETBIT(compatibleOmegaMinus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaMinus, 2); + SETBIT(compatibleOmegaMinus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaPlus, 0); + SETBIT(compatibleOmegaPlus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaPlus, 1); + SETBIT(compatibleOmegaPlus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaPlus, 2); + SETBIT(compatibleOmegaPlus, 2); } } float massNSigmaXi = -20.0f; @@ -1144,14 +1201,18 @@ struct HStrangeCorrelationFilter { massNSigmaOmega = (casc.mOmega() - hOmegaMean->Interpolate(casc.pt())) / (hOmegaWidth->Interpolate(casc.pt()) + 1e-6); } } - if (compatibleXiMinus) + if (compatibleXiMinus > 0) { histos.fill(HIST("h3dMassXiMinus"), casc.pt(), casc.mXi(), cent); - if (compatibleXiPlus) + } + if (compatibleXiPlus > 0) { histos.fill(HIST("h3dMassXiPlus"), casc.pt(), casc.mXi(), cent); - if (compatibleOmegaMinus && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) + } + if (compatibleOmegaMinus > 0 && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) { histos.fill(HIST("h3dMassOmegaMinus"), casc.pt(), casc.mOmega(), cent); - if (compatibleOmegaPlus && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) + } + if (compatibleOmegaPlus > 0 && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) { histos.fill(HIST("h3dMassOmegaPlus"), casc.pt(), casc.mOmega(), cent); + } if (!fillTableOnlyWithCompatible || ( // start major condition check @@ -1187,37 +1248,43 @@ struct HStrangeCorrelationFilter { casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascSelection.cascCospa || casc.cascradius() < cascSelection.cascRadius || std::abs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cascSelection.cascMindcav0topv || - std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.cascV0masswindow)) + std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSelection.cascV0masswindow)) { continue; + } auto bachTrackCast = casc.bachelor_as(); auto posTrackCast = casc.posTrack_as(); auto negTrackCast = casc.negTrack_as(); // minimum TPC crossed rows - if (bachTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + if (bachTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (posTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + } + if (posTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (negTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) + } + if (negTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; - if (!doPPAnalysis && !cascadeSelectedPbPb(casc, collision.posX(), collision.posY(), collision.posZ())) + } + if (!doPPAnalysis && !cascadeSelectedPbPb(casc, collision.posX(), collision.posY(), collision.posZ())) { continue; - if (trackSelections.requireClusterInITS && (posTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || bachTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) + } + if (trackSelections.requireClusterInITS && (posTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks || bachTrackCast.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) { continue; + } bool isGoodNegCascadePbPb = (std::abs(casc.dcabachtopv()) > cascSelection.dcaBachToPV && std::abs(casc.dcapostopv()) > cascSelection.cascDcaBaryonToPV && std::abs(casc.dcanegtopv()) > cascSelection.cascDcaMesonToPV); bool isGoodPosCascadePbPb = (std::abs(casc.dcabachtopv()) > cascSelection.dcaBachToPV && std::abs(casc.dcapostopv()) > cascSelection.cascDcaMesonToPV && std::abs(casc.dcanegtopv()) > cascSelection.cascDcaBaryonToPV); // check dE/dx compatibility - int compatibleXiMinus = 0; - int compatibleXiPlus = 0; - int compatibleOmegaMinus = 0; - int compatibleOmegaPlus = 0; + int compatibleXiMinus = -1; + int compatibleXiPlus = -1; + int compatibleOmegaMinus = -1; + int compatibleOmegaPlus = -1; float cascpos = std::hypot(casc.x() - collision.posX(), casc.y() - collision.posY(), casc.z() - collision.posZ()); float cascptotmom = std::hypot(casc.px(), casc.py(), casc.pz()); - float ctauXi = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * ctauxi); - float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * ctauomega); + float ctauXi = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * Xictau); + float ctauOmega = o2::constants::physics::MassOmegaMinus * cascpos / ((cascptotmom + 1e-13) * Omegactau); bool iGoodXiPbPb = std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascSelection.rejcomp && ctauXi < cascSelection.proplifetime && std::abs(casc.yXi()) < cascSelection.rapCut; @@ -1225,65 +1292,65 @@ struct HStrangeCorrelationFilter { ctauOmega < cascSelection.proplifetime && std::abs(casc.yOmega()) < cascSelection.rapCut; if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && iGoodXiPbPb)) { - BIT_SET(compatibleXiMinus, 0); + SETBIT(compatibleXiMinus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && iGoodXiPbPb)) { - BIT_SET(compatibleXiMinus, 1); + SETBIT(compatibleXiMinus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && iGoodXiPbPb)) { - BIT_SET(compatibleXiMinus, 2); + SETBIT(compatibleXiMinus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && iGoodXiPbPb)) { - BIT_SET(compatibleXiPlus, 0); + SETBIT(compatibleXiPlus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && iGoodXiPbPb)) { - BIT_SET(compatibleXiPlus, 1); + SETBIT(compatibleXiPlus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && iGoodXiPbPb)) { - BIT_SET(compatibleXiPlus, 2); + SETBIT(compatibleXiPlus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaMinus, 0); + SETBIT(compatibleOmegaMinus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaMinus, 1); + SETBIT(compatibleOmegaMinus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() < 0) { if (doPPAnalysis || (isGoodNegCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaMinus, 2); + SETBIT(compatibleOmegaMinus, 2); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaLoose && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaLoose && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaLoose && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaPlus, 0); + SETBIT(compatibleOmegaPlus, 0); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigma && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigma && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigma && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaPlus, 1); + SETBIT(compatibleOmegaPlus, 1); } } if (std::abs(posTrackCast.tpcNSigmaPi()) < strangedEdxNSigmaTight && std::abs(negTrackCast.tpcNSigmaPr()) < strangedEdxNSigmaTight && std::abs(bachTrackCast.tpcNSigmaKa()) < strangedEdxNSigmaTight && casc.sign() > 0) { if (doPPAnalysis || (isGoodPosCascadePbPb && isGoodOmegaPbPb)) { - BIT_SET(compatibleOmegaPlus, 2); + SETBIT(compatibleOmegaPlus, 2); } } float massNSigmaXi = 20.0f; @@ -1309,22 +1376,30 @@ struct HStrangeCorrelationFilter { bool trueOmegaMinus = false; bool trueOmegaPlus = false; cascPhysicalPrimary = casc.isPhysicalPrimary(); - if (casc.pdgCode() == PDG_t::kXiMinus) + if (casc.pdgCode() == PDG_t::kXiMinus) { trueXiMinus = true; - if (casc.pdgCode() == PDG_t::kXiPlusBar) + } + if (casc.pdgCode() == PDG_t::kXiPlusBar) { trueXiPlus = true; - if (casc.pdgCode() == PDG_t::kOmegaMinus) + } + if (casc.pdgCode() == PDG_t::kOmegaMinus) { trueOmegaMinus = true; - if (casc.pdgCode() == PDG_t::kOmegaPlusBar) + } + if (casc.pdgCode() == PDG_t::kOmegaPlusBar) { trueOmegaPlus = true; - if (compatibleXiMinus && (!doTrueSelectionInMass || (trueXiMinus && cascPhysicalPrimary))) + } + if (compatibleXiMinus > 0 && (!doTrueSelectionInMass || (trueXiMinus && cascPhysicalPrimary))) { histos.fill(HIST("h3dMassXiMinus"), casc.pt(), casc.mXi(), cent); - if (compatibleXiPlus && (!doTrueSelectionInMass || (trueXiPlus && cascPhysicalPrimary))) + } + if (compatibleXiPlus > 0 && (!doTrueSelectionInMass || (trueXiPlus && cascPhysicalPrimary))) { histos.fill(HIST("h3dMassXiPlus"), casc.pt(), casc.mXi(), cent); - if (compatibleOmegaMinus && (!doTrueSelectionInMass || (trueOmegaMinus && cascPhysicalPrimary)) && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) + } + if (compatibleOmegaMinus > 0 && (!doTrueSelectionInMass || (trueOmegaMinus && cascPhysicalPrimary)) && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) { histos.fill(HIST("h3dMassOmegaMinus"), casc.pt(), casc.mOmega(), cent); - if (compatibleOmegaPlus && (!doTrueSelectionInMass || (trueOmegaPlus && cascPhysicalPrimary)) && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) + } + if (compatibleOmegaPlus > 0 && (!doTrueSelectionInMass || (trueOmegaPlus && cascPhysicalPrimary)) && std::abs(massNSigmaXi) > nSigmaNearXiMassCenter) { histos.fill(HIST("h3dMassOmegaPlus"), casc.pt(), casc.mOmega(), cent); + } if (!fillTableOnlyWithCompatible || ( // start major condition check @@ -1352,8 +1427,8 @@ struct HStrangeCorrelationFilter { PROCESS_SWITCH(HStrangeCorrelationFilter, processAssocHadronsMC, "Produce associated Hadron tables for MC", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(context)}; } diff --git a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx index c6a99dab433..3fb2f60415d 100644 --- a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx +++ b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx @@ -66,6 +66,7 @@ #include +#include #include #include #include @@ -128,6 +129,7 @@ struct HStrangeCorrelation { Configurable useCentralityinPrediction{"useCentralityinPrediction", false, "if true, use centrality instead of multiplisity"}; Configurable doMirroringInDelataEta{"doMirroringInDelataEta", false, "if true, fill only positive delta eta and mirror the negative side in post processing, Adjust the delta axis!"}; Configurable doMassSpectrumCheck{"doMassSpectrumCheck", false, "if true, add and fill invariant-mass spectrum"}; + Configurable doCorrelationsHadronV0daughter{"doCorrelationsHadronV0daughter", false, "if true, do correlations of hadrons with V0 daughters"}; } masterConfigurations; // master analysis switches @@ -209,7 +211,8 @@ struct HStrangeCorrelation { Configurable requireClusterInITS{"requireClusterInITS", false, "require cluster in ITS for V0 and cascade daughter tracks"}; Configurable minITSClustersForDaughterTracks{"minITSClustersForDaughterTracks", 1, "Minimum number of ITS clusters for V0 daughter tracks"}; Configurable requireDCAzCut{"requireDCAzCut", false, "require DCAz cut for trigger and associated primary tracks"}; - + Configurable doITSChi2Selection{"doITSChi2Selection", false, "require ITS chi2 cut for trigger and associated primary tracks"}; + Configurable checkForITSTPCMissmatchMC{"checkForITSTPCMissmatchMC", false, "if true, reject tracks with MC mask 13 (ITS-TPC mismatch) for trigger and associated primary tracks"}; // --- Trigger: DCA variation from basic formula: |DCAxy| < 0.004f + (0.013f / pt) Configurable dcaXYconstant{"dcaXYconstant", 0.004, "[0] in |DCAxy| < [0]+[1]/pT"}; Configurable dcaXYpTdep{"dcaXYpTdep", 0.013, "[1] in |DCAxy| < [0]+[1]/pT"}; @@ -222,6 +225,8 @@ struct HStrangeCorrelation { Configurable dcaZconstantAssoc{"dcaZconstantAssoc", 0.004, "[0] in |DCAz| < [0]+[1]/pT"}; Configurable dcaZpTdepAssoc{"dcaZpTdepAssoc", 0.013, "[1] in |DCAz| < [0]+[1]/pT"}; Configurable dEdxCompatibility{"dEdxCompatibility", 1, "0: loose, 1: normal, 2: tight. Defined in HStrangeCorrelationFilter"}; + Configurable chi2ITSfit{"chi2ITSfit", 36, "chi2 ITS fit for trigger and associated primary tracks"}; + } trackSelection; struct : ConfigurableGroup { std::string prefix = "v0Selection"; @@ -278,7 +283,7 @@ struct HStrangeCorrelation { // Configurable bachBaryonDCAxyToPV{"bachBaryonDCAxyToPV", 0.08, "DCA bachelor baryon to PV"}; // // on the fly correction instead of mixingParameter - Configurable doOnTheFlyFlattening{"doOnTheFlyFlattening", 0, "enable an on-the-fly correction instead of using mixing"}; + Configurable doOnTheFlyFlattening{"doOnTheFlyFlattening", false, "enable an on-the-fly correction instead of using mixing"}; // delta eta ranges for toward and transverse checks Configurable transwerseDeltaEtaRangeMin{"transwerseDeltaEtaRangeMin", 1.0, "minimum delta eta for transverse region"}; @@ -297,13 +302,13 @@ struct HStrangeCorrelation { float efficiencyError; int type; }; - float pvz; - float mult; + float pvz = 0.0f; + float mult = 0.0f; std::vector trigParticles; std::vector assocParticles; void addValidParticle(float eta, float phi, float pt, int region, float efficiency, float efficiencyError, int type) { - ValidParticle particle{eta, phi, pt, region, efficiency, efficiencyError, type}; + ValidParticle particle{.eta = eta, .phi = phi, .pt = pt, .region = region, .efficiency = efficiency, .efficiencyError = efficiencyError, .type = type}; if (type == -1) { trigParticles.push_back(particle); @@ -317,43 +322,43 @@ struct HStrangeCorrelation { ValidCollisions validCollisions; // objects to use for efficiency corrections - TH2F* hEfficiencyTrigger; - TH3F* hEfficiencyTriggerMult; - THnF* hEfficiencyTriggerMultVsPhi; - TH2F* hEfficiencyPion; - TH2F* hEfficiencyK0Short; - THnF* hEfficiencyK0ShortMultVsPhi; - TH2F* hEfficiencyLambda; - THnF* hEfficiencyLambdaMultVsPhi; - TH2F* hEfficiencyAntiLambda; - THnF* hEfficiencyAntiLambdaMultVsPhi; - TH2F* hEfficiencyXiMinus; - THnF* hEfficiencyXiMinusMultVsPhi; - TH2F* hEfficiencyXiPlus; - THnF* hEfficiencyXiPlusMultVsPhi; - TH2F* hEfficiencyOmegaMinus; - THnF* hEfficiencyOmegaMinusMultVsPhi; - TH2F* hEfficiencyOmegaPlus; - THnF* hEfficiencyOmegaPlusMultVsPhi; - TH2F* hEfficiencyHadron; - TH3F* hEfficiencyHadronMult; - TH1F* hPurityHadron; - TH2F* hPurityHadronMult; + TH2F* hEfficiencyTrigger = nullptr; + TH3F* hEfficiencyTriggerMult = nullptr; + THnF* hEfficiencyTriggerMultVsPhi = nullptr; + TH2F* hEfficiencyPion = nullptr; + TH2F* hEfficiencyK0Short = nullptr; + THnF* hEfficiencyK0ShortMultVsPhi = nullptr; + TH2F* hEfficiencyLambda = nullptr; + THnF* hEfficiencyLambdaMultVsPhi = nullptr; + TH2F* hEfficiencyAntiLambda = nullptr; + THnF* hEfficiencyAntiLambdaMultVsPhi = nullptr; + TH2F* hEfficiencyXiMinus = nullptr; + THnF* hEfficiencyXiMinusMultVsPhi = nullptr; + TH2F* hEfficiencyXiPlus = nullptr; + THnF* hEfficiencyXiPlusMultVsPhi = nullptr; + TH2F* hEfficiencyOmegaMinus = nullptr; + THnF* hEfficiencyOmegaMinusMultVsPhi = nullptr; + TH2F* hEfficiencyOmegaPlus = nullptr; + THnF* hEfficiencyOmegaPlusMultVsPhi = nullptr; + TH2F* hEfficiencyHadron = nullptr; + TH3F* hEfficiencyHadronMult = nullptr; + TH1F* hPurityHadron = nullptr; + TH2F* hPurityHadronMult = nullptr; // objects to propagate the efficiency uncertainty - TH2F* hEfficiencyUncertaintyTrigger; - TH3F* hEfficiencyUncertaintyTriggerMult; - TH2F* hEfficiencyUncertaintyPion; - TH2F* hEfficiencyUncertaintyK0Short; - TH2F* hEfficiencyUncertaintyLambda; - TH2F* hEfficiencyUncertaintyAntiLambda; - TH2F* hEfficiencyUncertaintyXiMinus; - TH2F* hEfficiencyUncertaintyXiPlus; - TH2F* hEfficiencyUncertaintyOmegaMinus; - TH2F* hEfficiencyUncertaintyOmegaPlus; - TH2F* hEfficiencyUncertaintyHadron; - TH3F* hEfficiencyUncertaintyHadronMult; - TH1F* hPurityUncertaintyHadron; - TH2F* hPurityUncertaintyHadronMult; + TH2F* hEfficiencyUncertaintyTrigger = nullptr; + TH3F* hEfficiencyUncertaintyTriggerMult = nullptr; + TH2F* hEfficiencyUncertaintyPion = nullptr; + TH2F* hEfficiencyUncertaintyK0Short = nullptr; + TH2F* hEfficiencyUncertaintyLambda = nullptr; + TH2F* hEfficiencyUncertaintyAntiLambda = nullptr; + TH2F* hEfficiencyUncertaintyXiMinus = nullptr; + TH2F* hEfficiencyUncertaintyXiPlus = nullptr; + TH2F* hEfficiencyUncertaintyOmegaMinus = nullptr; + TH2F* hEfficiencyUncertaintyOmegaPlus = nullptr; + TH2F* hEfficiencyUncertaintyHadron = nullptr; + TH3F* hEfficiencyUncertaintyHadronMult = nullptr; + TH1F* hPurityUncertaintyHadron = nullptr; + TH2F* hPurityUncertaintyHadronMult = nullptr; using BinningTypePP = ColumnBinningPolicy; using BinningTypePbPb = ColumnBinningPolicy; @@ -366,10 +371,10 @@ struct HStrangeCorrelation { Preslice collisionSliceHadrons = aod::assocHadrons::collisionId; Preslice perCollision = aod::mcparticle::mcCollisionId; - static constexpr std::string_view V0names[] = {"K0Short", "Lambda", "AntiLambda"}; - static constexpr std::string_view Cascadenames[] = {"XiMinus", "XiPlus", "OmegaMinus", "OmegaPlus"}; - static constexpr std::string_view Particlenames[] = {"K0Short", "Lambda", "AntiLambda", "XiMinus", "XiPlus", "OmegaMinus", "OmegaPlus", "Pion", "Hadron"}; - static constexpr int PdgCodes[] = {310, 3122, -3122, 3312, -3312, 3334, -3334, 211}; + static constexpr std::array V0names = {"K0Short", "Lambda", "AntiLambda"}; + static constexpr std::array Cascadenames = {"XiMinus", "XiPlus", "OmegaMinus", "OmegaPlus"}; + static constexpr std::array Particlenames = {"K0Short", "Lambda", "AntiLambda", "XiMinus", "XiPlus", "OmegaMinus", "OmegaPlus", "Pion", "Hadron"}; + static constexpr std::array PdgCodes = {310, 3122, -3122, 3312, -3312, 3334, -3334, 211}; static constexpr int IndexPion = 7; static constexpr int IndexXiMinus = 0; @@ -399,8 +404,8 @@ struct HStrangeCorrelation { std::vector> axisRanges; - const float ctauxi = 4.91; // from PDG - const float ctauomega = 2.461; // from PDG + static constexpr float ctauxi = 4.91; // from PDG + static constexpr float ctauomega = 2.461; // from PDG static constexpr float MinRadiusTPC = 0.8; static constexpr float MaxRadiusTPC = 2.5; @@ -409,6 +414,8 @@ struct HStrangeCorrelation { static constexpr int AssocParticleTypes = 9; // K0S, Lambda, AntiLambda, Xi-, Xi+, Omega-, Omega+, Pion, Hadron static constexpr int AssocParticleTypesNoHadron = 8; // K0S, Lambda, AntiLambda, Xi-, Xi+, Omega-, Omega+, Pion + static constexpr int AssocV0Types = 3; // K0S, Lambda, AntiLambda, + static constexpr int AssocCascadeTypes = 4; // Xi-, Xi+, Omega-, Omega+ /// Function to aid in calculating delta-phi /// \param phi1 first phi value @@ -445,91 +452,99 @@ struct HStrangeCorrelation { LOG(info) << "Loading efficiencies from CCDB for run " << mRunNumber << " now..."; auto timeStamp = bc.timestamp(); - TList* listEfficiencies = ccdb->getForTimeStamp(efficiencyCCDBPath, timeStamp); + auto* listEfficiencies = ccdb->getForTimeStamp(efficiencyCCDBPath, timeStamp); if (!listEfficiencies) { LOG(fatal) << "Problem getting TList object with efficiencies!"; } - hEfficiencyTrigger = static_cast(listEfficiencies->FindObject("hEfficiencyTrigger")); - hEfficiencyTriggerMult = static_cast(listEfficiencies->FindObject("hEfficiencyTriggerMult")); - hEfficiencyTriggerMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyTriggerMultVsPhi")); - hEfficiencyK0Short = static_cast(listEfficiencies->FindObject("hEfficiencyK0Short")); - hEfficiencyK0ShortMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyK0ShortMultVsPhi")); - hEfficiencyLambda = static_cast(listEfficiencies->FindObject("hEfficiencyLambda")); - hEfficiencyLambdaMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyLambdaMultVsPhi")); - hEfficiencyAntiLambda = static_cast(listEfficiencies->FindObject("hEfficiencyAntiLambda")); - hEfficiencyAntiLambdaMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyAntiLambdaMultVsPhi")); - hEfficiencyXiMinus = static_cast(listEfficiencies->FindObject("hEfficiencyXiMinus")); - hEfficiencyXiMinusMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyXiMinusMultVsPhi")); - hEfficiencyXiPlus = static_cast(listEfficiencies->FindObject("hEfficiencyXiPlus")); - hEfficiencyXiPlusMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyXiPlusMultVsPhi")); - hEfficiencyOmegaMinus = static_cast(listEfficiencies->FindObject("hEfficiencyOmegaMinus")); - hEfficiencyOmegaMinusMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyOmegaMinusMultVsPhi")); - hEfficiencyOmegaPlus = static_cast(listEfficiencies->FindObject("hEfficiencyOmegaPlus")); - hEfficiencyOmegaPlusMultVsPhi = static_cast(listEfficiencies->FindObject("hEfficiencyOmegaPlusMultVsPhi")); - hEfficiencyHadron = static_cast(listEfficiencies->FindObject("hEfficiencyHadron")); - hEfficiencyHadronMult = static_cast(listEfficiencies->FindObject("hEfficiencyHadronMult")); - hEfficiencyPion = static_cast(listEfficiencies->FindObject("hEfficiencyPion")); - hPurityHadron = static_cast(listEfficiencies->FindObject("hPurityHadron")); - hPurityHadronMult = static_cast(listEfficiencies->FindObject("hPurityHadronMult")); - hEfficiencyUncertaintyTrigger = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyTrigger")); - hEfficiencyUncertaintyTriggerMult = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyTriggerMult")); - hEfficiencyUncertaintyK0Short = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyK0Short")); - hEfficiencyUncertaintyLambda = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyLambda")); - hEfficiencyUncertaintyAntiLambda = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyAntiLambda")); - hEfficiencyUncertaintyXiMinus = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyXiMinus")); - hEfficiencyUncertaintyXiPlus = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyXiPlus")); - hEfficiencyUncertaintyOmegaMinus = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyOmegaMinus")); - hEfficiencyUncertaintyOmegaPlus = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyOmegaPlus")); - hEfficiencyUncertaintyPion = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyPion")); - hEfficiencyUncertaintyHadron = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyHadron")); - hEfficiencyUncertaintyHadronMult = static_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyHadronMult")); - hPurityUncertaintyHadron = static_cast(listEfficiencies->FindObject("hPurityUncertaintyHadron")); - hPurityUncertaintyHadronMult = static_cast(listEfficiencies->FindObject("hPurityUncertaintyHadronMult")); - if (efficiencyFlags.applyEfficiencyPropagation && !efficiencyFlags.applyEffAsFunctionOfMultAndPhi && !hEfficiencyUncertaintyTrigger) + hEfficiencyTrigger = dynamic_cast(listEfficiencies->FindObject("hEfficiencyTrigger")); + hEfficiencyTriggerMult = dynamic_cast(listEfficiencies->FindObject("hEfficiencyTriggerMult")); + hEfficiencyTriggerMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyTriggerMultVsPhi")); + hEfficiencyK0Short = dynamic_cast(listEfficiencies->FindObject("hEfficiencyK0Short")); + hEfficiencyK0ShortMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyK0ShortMultVsPhi")); + hEfficiencyLambda = dynamic_cast(listEfficiencies->FindObject("hEfficiencyLambda")); + hEfficiencyLambdaMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyLambdaMultVsPhi")); + hEfficiencyAntiLambda = dynamic_cast(listEfficiencies->FindObject("hEfficiencyAntiLambda")); + hEfficiencyAntiLambdaMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyAntiLambdaMultVsPhi")); + hEfficiencyXiMinus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyXiMinus")); + hEfficiencyXiMinusMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyXiMinusMultVsPhi")); + hEfficiencyXiPlus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyXiPlus")); + hEfficiencyXiPlusMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyXiPlusMultVsPhi")); + hEfficiencyOmegaMinus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyOmegaMinus")); + hEfficiencyOmegaMinusMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyOmegaMinusMultVsPhi")); + hEfficiencyOmegaPlus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyOmegaPlus")); + hEfficiencyOmegaPlusMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyOmegaPlusMultVsPhi")); + hEfficiencyHadron = dynamic_cast(listEfficiencies->FindObject("hEfficiencyHadron")); + hEfficiencyHadronMult = dynamic_cast(listEfficiencies->FindObject("hEfficiencyHadronMult")); + hEfficiencyPion = dynamic_cast(listEfficiencies->FindObject("hEfficiencyPion")); + hPurityHadron = dynamic_cast(listEfficiencies->FindObject("hPurityHadron")); + hPurityHadronMult = dynamic_cast(listEfficiencies->FindObject("hPurityHadronMult")); + hEfficiencyUncertaintyTrigger = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyTrigger")); + hEfficiencyUncertaintyTriggerMult = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyTriggerMult")); + hEfficiencyUncertaintyK0Short = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyK0Short")); + hEfficiencyUncertaintyLambda = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyLambda")); + hEfficiencyUncertaintyAntiLambda = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyAntiLambda")); + hEfficiencyUncertaintyXiMinus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyXiMinus")); + hEfficiencyUncertaintyXiPlus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyXiPlus")); + hEfficiencyUncertaintyOmegaMinus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyOmegaMinus")); + hEfficiencyUncertaintyOmegaPlus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyOmegaPlus")); + hEfficiencyUncertaintyPion = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyPion")); + hEfficiencyUncertaintyHadron = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyHadron")); + hEfficiencyUncertaintyHadronMult = dynamic_cast(listEfficiencies->FindObject("hEfficiencyUncertaintyHadronMult")); + hPurityUncertaintyHadron = dynamic_cast(listEfficiencies->FindObject("hPurityUncertaintyHadron")); + hPurityUncertaintyHadronMult = dynamic_cast(listEfficiencies->FindObject("hPurityUncertaintyHadronMult")); + if (efficiencyFlags.applyEfficiencyPropagation && !efficiencyFlags.applyEffAsFunctionOfMultAndPhi && !hEfficiencyUncertaintyTrigger) { LOG(fatal) << "Problem getting hEfficiencyUncertaintyTrigger!"; - if (efficiencyFlags.applyEffAsFunctionOfMult && !hEfficiencyTriggerMult) + } + if (efficiencyFlags.applyEffAsFunctionOfMult && !hEfficiencyTriggerMult) { LOG(fatal) << "Problem getting hEfficiencyTriggerMult!"; + } LOG(info) << "Efficiencies now loaded for " << mRunNumber; } template - uint64_t v0selectionBitmap(TV0 v0, float pvx, float pvy, float pvz) + uint64_t v0selectionBitmap(TV0 const& v0, float pvx, float pvy, float pvz) // precalculate this information so that a check is one mask operation, not many { uint64_t bitMap = 0; // proper lifetime , DCA daughter to prim.vtx if (masterConfigurations.doCorrelationK0Short) { // proper lifetime - if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S) + if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S) { SETBIT(bitMap, 0); + } // DCA daughter to prim.vtx and armenteros float dcaCut = v0Selection.dcaDaugToPVForK0s == 0 ? v0Selection.dcaMesonToPV : v0Selection.dcaDaugToPVForK0s; - if (std::abs(v0.dcapostopv()) > dcaCut && std::abs(v0.dcanegtopv()) > dcaCut && v0.qtarm() * v0Selection.armPodCut > std::abs(v0.alpha())) + if (std::abs(v0.dcapostopv()) > dcaCut && std::abs(v0.dcanegtopv()) > dcaCut && v0.qtarm() * v0Selection.armPodCut > std::abs(v0.alpha())) { SETBIT(bitMap, 3); + } } if (masterConfigurations.doCorrelationLambda) { // proper lifetime - if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassLambda0 < v0Selection.lifetimecutLambda) + if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassLambda0 < v0Selection.lifetimecutLambda) { SETBIT(bitMap, 1); + } // DCA daughter to prim.vtx - if (std::abs(v0.dcapostopv()) > v0Selection.dcaBaryonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaMesonToPV) + if (std::abs(v0.dcapostopv()) > v0Selection.dcaBaryonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaMesonToPV) { SETBIT(bitMap, 4); + } } if (masterConfigurations.doCorrelationAntiLambda) { // proper lifetime - if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassLambda0 < v0Selection.lifetimecutLambda) + if (v0.distovertotmom(pvx, pvy, pvz) * o2::constants::physics::MassLambda0 < v0Selection.lifetimecutLambda) { SETBIT(bitMap, 2); + } // DCA daughter to prim.vtx - if (std::abs(v0.dcapostopv()) > v0Selection.dcaMesonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaBaryonToPV) + if (std::abs(v0.dcapostopv()) > v0Selection.dcaMesonToPV && std::abs(v0.dcanegtopv()) > v0Selection.dcaBaryonToPV) { SETBIT(bitMap, 5); + } } return bitMap; } template - uint64_t cascadeselectionBitmap(TCascade casc, float pvx, float pvy, float pvz) + uint64_t cascadeselectionBitmap(TCascade const& casc, float pvx, float pvy, float pvz) { uint64_t bitMap = 0; float cascpos = std::hypot(casc.x() - pvx, casc.y() - pvy, casc.z() - pvz); @@ -544,64 +559,80 @@ struct HStrangeCorrelation { // TPC PID and DCA daughter to prim.vtx and comopeting casc.rej and life time if (masterConfigurations.doCorrelationXiMinus) { // DCA daughter to prim.vtx - if (isGoodDCANegCasc) + if (isGoodDCANegCasc) { SETBIT(bitMap, 0); + } // comopeting casc.rej - if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascadeSelections.rejcomp) + if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascadeSelections.rejcomp) { SETBIT(bitMap, 4); - if (ctauXi < cascadeSelections.proplifetime) + } + if (ctauXi < cascadeSelections.proplifetime) { SETBIT(bitMap, 8); + } // y cut - if (std::abs(casc.yXi()) < cascadeSelections.rapCut) + if (std::abs(casc.yXi()) < cascadeSelections.rapCut) { SETBIT(bitMap, 12); + } } if (masterConfigurations.doCorrelationXiPlus) { // DCA daughter to prim.vtx - if (isGoodDCAPosCasc) + if (isGoodDCAPosCasc) { SETBIT(bitMap, 1); + } // comopeting casc.rej - if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascadeSelections.rejcomp) + if (std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) > cascadeSelections.rejcomp) { SETBIT(bitMap, 5); + } // life time - if (ctauXi < cascadeSelections.proplifetime) + if (ctauXi < cascadeSelections.proplifetime) { SETBIT(bitMap, 9); + } // y cut - if (std::abs(casc.yXi()) > cascadeSelections.rapCut) + if (std::abs(casc.yXi()) > cascadeSelections.rapCut) { SETBIT(bitMap, 13); + } } if (masterConfigurations.doCorrelationOmegaMinus) { // DCA daughter to prim.vtx - if (isGoodDCANegCasc) + if (isGoodDCANegCasc) { SETBIT(bitMap, 2); + } // comopeting casc.rej - if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > cascadeSelections.rejcomp) + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > cascadeSelections.rejcomp) { SETBIT(bitMap, 6); + } // life time - if (ctauOmega < cascadeSelections.proplifetime) + if (ctauOmega < cascadeSelections.proplifetime) { SETBIT(bitMap, 10); + } // y cut - if (std::abs(casc.yOmega()) < cascadeSelections.rapCut) + if (std::abs(casc.yOmega()) < cascadeSelections.rapCut) { SETBIT(bitMap, 14); + } } if (masterConfigurations.doCorrelationOmegaPlus) { // DCA daughter to prim.vtx - if (isGoodDCAPosCasc) + if (isGoodDCAPosCasc) { SETBIT(bitMap, 3); + } // comopeting casc.rej - if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > cascadeSelections.rejcomp) + if (std::abs(casc.mXi() - o2::constants::physics::MassXiMinus) > cascadeSelections.rejcomp) { SETBIT(bitMap, 7); + } // life time - if (ctauOmega < cascadeSelections.proplifetime) + if (ctauOmega < cascadeSelections.proplifetime) { SETBIT(bitMap, 11); + } // y cut - if (std::abs(casc.yOmega()) > cascadeSelections.rapCut) + if (std::abs(casc.yOmega()) > cascadeSelections.rapCut) { SETBIT(bitMap, 15); + } } return bitMap; } template - bool isValidTrigger(TTrack track, bool isLeading) + bool isValidTrigger(TTrack const& track, bool isLeading) { if (track.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsTrigger) { return false; // crossed rows @@ -635,10 +666,13 @@ struct HStrangeCorrelation { if (useTheLeadingParticleAsTrigger && !isLeading) { return false; } + if (trackSelection.doITSChi2Selection && track.itsChi2NCl() > trackSelection.chi2ITSfit) { + return false; + } return true; } template - bool isValidAssocHadron(TTrack track) + bool isValidAssocHadron(TTrack const& track) { if (track.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { return false; // crossed rows @@ -663,68 +697,86 @@ struct HStrangeCorrelation { if (track.pt() > axisRanges[2][1] || track.pt() < axisRanges[2][0]) { return false; } + if (trackSelection.doITSChi2Selection && track.itsChi2NCl() > trackSelection.chi2ITSfit) { + return false; + } return true; } // V0selection in PbPb template - bool v0SelectedPbPb(TV0 v0) + bool v0SelectedPbPb(TV0 const& v0) { // v0radius - if (v0.v0radius() < v0Selection.v0RadiusMin) + if (v0.v0radius() < v0Selection.v0RadiusMin) { return false; - if (v0.v0radius() > v0Selection.v0RadiusMax) + } + if (v0.v0radius() > v0Selection.v0RadiusMax) { return false; + } // v0cosPA - if (v0.v0cosPA() < v0Selection.v0cospa) + if (v0.v0cosPA() < v0Selection.v0cospa) { return false; + } // dcaV0daughters - if (v0.dcaV0daughters() > v0Selection.dcaV0dau) + if (v0.dcaV0daughters() > v0Selection.dcaV0dau) { return false; + } return true; } // cascadeselection in PbPb template - bool cascadeSelectedPbPb(TCascade casc, float pvx, float pvy, float pvz) + bool cascadeSelectedPbPb(TCascade const& casc, float pvx, float pvy, float pvz) { // bachBaryonCosPA - if (casc.bachBaryonCosPA() < cascadeSelections.bachBaryonCosPA) + if (casc.bachBaryonCosPA() < cascadeSelections.bachBaryonCosPA) { return false; + } // bachBaryonDCAxyToPV - if (std::abs(casc.bachBaryonDCAxyToPV()) > cascadeSelections.bachBaryonDCAxyToPV) + if (std::abs(casc.bachBaryonDCAxyToPV()) > cascadeSelections.bachBaryonDCAxyToPV) { return false; + } // casccosPA - if (casc.casccosPA(pvx, pvy, pvz) < cascadeSelections.cascCospa) + if (casc.casccosPA(pvx, pvy, pvz) < cascadeSelections.cascCospa) { return false; + } // dcacascdaughters float ptDepCut = cascadeSelections.dcaCacsDauPar0; - if (casc.pt() > cascadeSelections.lowPtForCascDaugPtDep && casc.pt() < cascadeSelections.highPtForCascDaugPtDep) + if (casc.pt() > cascadeSelections.lowPtForCascDaugPtDep && casc.pt() < cascadeSelections.highPtForCascDaugPtDep) { ptDepCut = cascadeSelections.dcaCacsDauPar1; - else if (casc.pt() > cascadeSelections.highPtForCascDaugPtDep) + } else if (casc.pt() > cascadeSelections.highPtForCascDaugPtDep) { ptDepCut = cascadeSelections.dcaCacsDauPar2; - if (casc.dcacascdaughters() > ptDepCut) + } + if (casc.dcacascdaughters() > ptDepCut) { return false; + } // dcaV0daughters - if (casc.dcaV0daughters() > cascadeSelections.cascdcaV0dau) + if (casc.dcaV0daughters() > cascadeSelections.cascdcaV0dau) { return false; + } // dcav0topv - if (std::abs(casc.dcav0topv(pvx, pvy, pvz)) < cascadeSelections.cascdcaV0ToPV) + if (std::abs(casc.dcav0topv(pvx, pvy, pvz)) < cascadeSelections.cascdcaV0ToPV) { return false; + } // cascradius - if (casc.cascradius() < cascadeSelections.cascRadius) + if (casc.cascradius() < cascadeSelections.cascRadius) { return false; + } // v0radius - if (casc.v0radius() < cascadeSelections.cascv0RadiusMin) + if (casc.v0radius() < cascadeSelections.cascv0RadiusMin) { return false; + } // v0cosPA - if (casc.v0cosPA(casc.x(), casc.y(), casc.z()) < cascadeSelections.cascv0cospa) + if (casc.v0cosPA(pvx, pvy, pvz) < cascadeSelections.cascv0cospa) { return false; + } // lambdaMassWin - if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow) + if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow) { return false; + } return true; } - double calculateAverageDeltaPhiStar(double* trigg, double* assoc, double B) + double calculateAverageDeltaPhiStar(std::array const& trigg, std::array const& assoc, double B) { double dPhiStar = 0; double dPhiStarMean = 0; @@ -740,7 +792,7 @@ struct HStrangeCorrelation { return dPhiStarMean; } - void fillTriggerHistogram(std::shared_ptr hist, double pt, double mult, float eff, float effUncert, float purity, float purityErr) + void fillTriggerHistogram(std::shared_ptr const& hist, double pt, double mult, float eff, float effUncert, float purity, float purityErr) { int binx = hist->GetXaxis()->FindBin(pt); int biny = hist->GetYaxis()->FindBin(mult); @@ -751,10 +803,10 @@ struct HStrangeCorrelation { hist->SetBinContent(binx, biny, newContent); hist->SetBinError(binx, biny, newUncert); } - void fillCorrelationHistogram(std::shared_ptr hist, double binFillThn[], float etaWeight, float efficiency, float totalEffUncert, float purity, float totalPurityUncert) + void fillCorrelationHistogram(std::shared_ptr const& hist, std::array const& binFillThn, float etaWeight, float efficiency, float totalEffUncert, float purity, float totalPurityUncert) { - float previousContent, previousError2, currentContent, currentError2; - int bin = hist->GetBin(binFillThn); + float previousContent = 0.0f, previousError2 = 0.0f, currentContent = 0.0f, currentError2 = 0.0f; + int bin = hist->GetBin(binFillThn.data()); previousContent = hist->GetBinContent(bin); previousError2 = hist->GetBinError2(bin); currentContent = previousContent + etaWeight * purity / (efficiency); @@ -779,30 +831,37 @@ struct HStrangeCorrelation { } bool firstLoop = false; for (auto const& triggerTrack : triggers) { - if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { continue; + } auto trigg = triggerTrack.track_as(); - if (!isValidTrigger(trigg, triggerTrack.isLeading())) + if (!isValidTrigger(trigg, triggerTrack.isLeading())) { + continue; + } + if (trackSelection.checkForITSTPCMissmatchMC && triggerTrack.mcMask() == 13) { continue; + } float efficiencyTrigg = 1.0f; float efficiencyTriggError = 0.0f; float purityTrigg = 1.0f; float purityTriggErr = 0.0; - double bintrig[4] = {trigg.pt(), trigg.eta(), trigg.phi(), mult}; + std::array bintrig = {trigg.pt(), trigg.eta(), trigg.phi(), mult}; if (efficiencyFlags.applyEfficiencyForTrigger) { if (!efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { efficiencyTrigg = hEfficiencyTrigger->Interpolate(trigg.pt(), trigg.eta()); - if (efficiencyFlags.applyPurityTrigger) + if (efficiencyFlags.applyPurityTrigger) { purityTrigg = hPurityHadron->Interpolate(trigg.pt()); + } if (efficiencyFlags.applyEfficiencyPropagation) { efficiencyTriggError = hEfficiencyUncertaintyTrigger->Interpolate(trigg.pt(), trigg.eta()); - if (efficiencyFlags.applyPurityTrigger) + if (efficiencyFlags.applyPurityTrigger) { purityTriggErr = hPurityHadron->Interpolate(trigg.pt()); + } } } else { - efficiencyTrigg = hEfficiencyTriggerMultVsPhi->GetBinContent(hEfficiencyTriggerMultVsPhi->GetBin(bintrig)); + efficiencyTrigg = hEfficiencyTriggerMultVsPhi->GetBinContent(hEfficiencyTriggerMultVsPhi->GetBin(bintrig.data())); if (efficiencyFlags.applyEfficiencyPropagation) { - efficiencyTriggError = hEfficiencyTriggerMultVsPhi->GetBinError(hEfficiencyTriggerMultVsPhi->GetBin(bintrig)); + efficiencyTriggError = hEfficiencyTriggerMultVsPhi->GetBinError(hEfficiencyTriggerMultVsPhi->GetBin(bintrig.data())); } } if (efficiencyTrigg == 0) { // check for zero efficiency, do not apply if the case @@ -816,12 +875,13 @@ struct HStrangeCorrelation { } double triggSign = trigg.sign(); - double triggForDeltaPhiStar[] = {trigg.phi(), trigg.pt(), triggSign}; + std::array triggForDeltaPhiStar = {trigg.phi(), trigg.pt(), triggSign}; if (mixingInBf) { currentCollision.addValidParticle(trigg.eta(), trigg.phi(), trigg.pt(), -1, efficiencyTrigg, efficiencyTriggError, -1); - if (firstLoop) + if (firstLoop) { continue; + } } for (auto const& assocCandidate : assocs) { firstLoop = true; @@ -830,11 +890,13 @@ struct HStrangeCorrelation { //---] syst cuts [--- if ((masterConfigurations.doPPAnalysis && (assoc.v0radius() < v0Selection.v0RadiusMin || assoc.v0radius() > v0Selection.v0RadiusMax || std::abs(assoc.dcapostopv()) < v0Selection.dcapostopv || std::abs(assoc.dcanegtopv()) < v0Selection.dcanegtopv || - assoc.v0cosPA() < v0Selection.v0cospa || assoc.dcaV0daughters() > v0Selection.dcaV0dau))) + assoc.v0cosPA() < v0Selection.v0cospa || assoc.dcaV0daughters() > v0Selection.dcaV0dau))) { continue; + } - if (!masterConfigurations.doPPAnalysis && !v0SelectedPbPb(assoc)) + if (!masterConfigurations.doPPAnalysis && !v0SelectedPbPb(assoc)) { continue; + } uint64_t selMap = v0selectionBitmap(assoc, pvx, pvy, pvz); @@ -853,12 +915,15 @@ struct HStrangeCorrelation { } //---] track quality check [--- - if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { continue; - if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) + } + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) { continue; - if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) + } + if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) { continue; + } float deltaphi = computeDeltaPhi(trigg.phi(), assoc.phi()); float deltaeta = trigg.eta() - assoc.eta(); @@ -869,16 +934,19 @@ struct HStrangeCorrelation { float pttrigger = trigg.pt(); // skip if basic ranges not met - if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) + if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) { continue; - if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) + } + if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) { continue; - if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) + } + if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) { continue; + } - TH2F* hEfficiencyV0[3]; - TH2F* hEfficiencyUncertaintyV0[3]; - THnF* hEfficiencyV0MultVsPhi[3]; + std::array hEfficiencyV0{nullptr, nullptr, nullptr}; + std::array hEfficiencyUncertaintyV0{nullptr, nullptr, nullptr}; + std::array hEfficiencyV0MultVsPhi{nullptr, nullptr, nullptr}; if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { hEfficiencyV0MultVsPhi[0] = hEfficiencyK0ShortMultVsPhi; hEfficiencyV0MultVsPhi[1] = hEfficiencyLambdaMultVsPhi; @@ -906,14 +974,19 @@ struct HStrangeCorrelation { double ptProton = postrack.pt(); double ptPion = negtrack.pt(); double signProton = postrack.sign(); + double signPion = negtrack.sign(); if (assocCandidate.compatible(2, trackSelection.dEdxCompatibility)) { phiProton = negtrack.phi(); etaProton = negtrack.eta(); ptProton = negtrack.pt(); signProton = negtrack.sign(); + phiPion = postrack.phi(); + etaPion = postrack.eta(); + ptPion = postrack.pt(); + signPion = postrack.sign(); } - double assocForDeltaPhiStar[] = {phiProton, ptProton, signProton}; - double assocForDeltaPhiStarPion[] = {phiPion, ptPion, -1}; + std::array assocForDeltaPhiStar = {phiProton, ptProton, signProton}; + std::array assocForDeltaPhiStarPion = {phiPion, ptPion, signPion}; static_for<0, 2>([&](auto i) { constexpr int Index = i.value; @@ -922,14 +995,16 @@ struct HStrangeCorrelation { float efficiencyError = 0.0f; if (efficiencyFlags.applyEfficiencyCorrection) { if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { - double bin[4] = {ptassoc, assoc.eta(), assoc.phi(), mult}; - efficiency = hEfficiencyV0MultVsPhi[Index]->GetBinContent(hEfficiencyV0MultVsPhi[Index]->GetBin(bin)); - if (efficiencyFlags.applyEfficiencyPropagation) - efficiencyError = hEfficiencyV0MultVsPhi[Index]->GetBinError(hEfficiencyV0MultVsPhi[Index]->GetBin(bin)); + std::array bin = {ptassoc, assoc.eta(), assoc.phi(), mult}; + efficiency = hEfficiencyV0MultVsPhi[Index]->GetBinContent(hEfficiencyV0MultVsPhi[Index]->GetBin(bin.data())); + if (efficiencyFlags.applyEfficiencyPropagation) { + efficiencyError = hEfficiencyV0MultVsPhi[Index]->GetBinError(hEfficiencyV0MultVsPhi[Index]->GetBin(bin.data())); + } } else { efficiency = hEfficiencyV0[Index]->Interpolate(ptassoc, assoc.eta()); - if (efficiencyFlags.applyEfficiencyPropagation) + if (efficiencyFlags.applyEfficiencyPropagation) { efficiencyError = hEfficiencyUncertaintyV0[Index]->Interpolate(ptassoc, assoc.eta()); + } } } if (efficiency == 0) { // check for zero efficiency, do not apply if the case @@ -940,9 +1015,25 @@ struct HStrangeCorrelation { totalEffUncert = std::sqrt(std::pow(efficiencyTrigg * efficiencyError, 2) + std::pow(efficiencyTriggError * efficiency, 2)); } - double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + std::array binFillThnOppositeSignDaugher = {computeDeltaPhi(trigg.phi(), phiPion), trigg.eta() - etaPion, ptPion, pttrigger, pvz, mult}; + std::array binFillThnSameSignDaugher = {computeDeltaPhi(trigg.phi(), phiProton), trigg.eta() - etaProton, ptProton, pttrigger, pvz, mult}; + if ((triggSign < Neutral && !assocCandidate.compatible(2, trackSelection.dEdxCompatibility)) || (triggSign > Neutral && assocCandidate.compatible(2, trackSelection.dEdxCompatibility))) { + std::swap(binFillThnOppositeSignDaugher[1], binFillThnSameSignDaugher[1]); + std::swap(binFillThnOppositeSignDaugher[0], binFillThnSameSignDaugher[0]); + std::swap(binFillThnOppositeSignDaugher[2], binFillThnSameSignDaugher[2]); + } + std::array binFillThn = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; if (TESTBIT(doCorrelation, Index) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0) && (masterConfigurations.doPPAnalysis || (TESTBIT(selMap, Index) && TESTBIT(selMap, Index + 3)))) { if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { + if (std::abs(deltaphi) < 0.5) { + histos.fill(HIST("sameEvent/") + HIST(V0names[Index]) + HIST("/hInvariantMassNearSide"), ptassoc, pttrigger, getV0InvariantMass(assoc)); + } + if (std::abs(PI - deltaphi) < 0.5) { + histos.fill(HIST("sameEvent/") + HIST(V0names[Index]) + HIST("/hInvariantMassAwaySide"), ptassoc, pttrigger, getV0InvariantMass(assoc)); + } + if (deltaphi > 1.0 && deltaphi < 1.5) { + histos.fill(HIST("sameEvent/") + HIST(V0names[Index]) + HIST("/hInvariantMassUE"), ptassoc, pttrigger, getV0InvariantMass(assoc)); + } fillCorrelationHistogram(histos.get(HIST("sameEvent/LeftBg/") + HIST(V0names[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); @@ -960,7 +1051,11 @@ struct HStrangeCorrelation { } } } - if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && ((-massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma))) { + if (masterConfigurations.doCorrelationsHadronV0daughter) { + fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(V0names[Index]) + HIST("/hSameSign")), binFillThnSameSignDaugher, 1, 1, 1, 1, 1); + fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(V0names[Index]) + HIST("/hOppositeSign")), binFillThnOppositeSignDaugher, 1, 1, 1, 1, 1); + } fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(V0names[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (std::abs(deltaphi) < checks.towardDeltaEtaRange && doITSClustersQA) { histos.fill(HIST("hITSClusters") + HIST(V0names[Index]) + HIST("NegativeDaughterToward"), ptassoc, negtrack.itsNCls(), assoc.v0radius()); @@ -1017,6 +1112,10 @@ struct HStrangeCorrelation { } else { fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(V0names[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); } + if (masterConfigurations.doCorrelationsHadronV0daughter) { + fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(V0names[Index]) + HIST("/hSameSign")), binFillThnSameSignDaugher, 1, 1, 1, 1, 1); + fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(V0names[Index]) + HIST("/hOppositeSign")), binFillThnOppositeSignDaugher, 1, 1, 1, 1, 1); + } } if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) { if (mixingInBf) { @@ -1029,15 +1128,17 @@ struct HStrangeCorrelation { }); } } - if (!mixingInBf || binVtxZ < 0 || binVtxZ > nBinsVtxZ - 1 || binMult < 0 || binMult > nBinsMult - 1) + if (!mixingInBf || binVtxZ < 0 || binVtxZ > nBinsVtxZ - 1 || binMult < 0 || binMult > nBinsMult - 1) { return; + } int binnumb = binMult * nBinsVtxZ + binVtxZ; int hastirgorassoc = masterConfigurations.collisionHasTriggOrAssoc; if ((hastirgorassoc == 1 && currentCollision.trigParticles.empty()) || (hastirgorassoc == 2 && currentCollision.assocParticles.empty()) || (hastirgorassoc == 3 && currentCollision.trigParticles.empty() && currentCollision.assocParticles.empty()) || - (hastirgorassoc == 4 && (currentCollision.trigParticles.empty() || currentCollision.assocParticles.empty()))) + (hastirgorassoc == 4 && (currentCollision.trigParticles.empty() || currentCollision.assocParticles.empty()))) { return; + } for (const auto& collision : validCollisions[binnumb]) { BinningTypePP colBinning{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}; // When 'collisionHasTriggOrAssoc' = 0: @@ -1063,7 +1164,7 @@ struct HStrangeCorrelation { if (masterConfigurations.doMirroringInDelataEta) { deltaeta = std::abs(deltaeta); } - double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + std::array binFillThn = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; static_for<0, 2>([&](auto i) { constexpr int Index = i.value; if (Index == assoc.type && assoc.region == 0) { @@ -1082,8 +1183,9 @@ struct HStrangeCorrelation { if (validCollisions[binnumb].size() >= static_cast(masterConfigurations.mixingParameter)) { validCollisions[binnumb].erase(validCollisions[binnumb].begin()); } - if (!currentCollision.trigParticles.empty()) + if (!currentCollision.trigParticles.empty()) { validCollisions[binnumb].push_back(currentCollision); + } } void fillCorrelationsCascade(aod::TriggerTracks const& triggers, aod::AssocCascades const& assocs, bool mixing, bool mixingInBf, float pvx, float pvy, float pvz, float mult, double bField) @@ -1103,43 +1205,48 @@ struct HStrangeCorrelation { } bool firstLoop = false; for (auto const& triggerTrack : triggers) { - if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { continue; + } auto trigg = triggerTrack.track_as(); - if (!isValidTrigger(trigg, triggerTrack.isLeading())) + if (!isValidTrigger(trigg, triggerTrack.isLeading())) { continue; + } float efficiencyTrigg = 1.0f; float efficiencyTriggError = 0.0f; float purityTrigg = 1.0f; float purityTriggErr = 0.0f; if (efficiencyFlags.applyEfficiencyForTrigger) { - double bintrig[4] = {trigg.pt(), trigg.eta(), trigg.phi(), mult}; + std::array bintrig = {trigg.pt(), trigg.eta(), trigg.phi(), mult}; if (efficiencyFlags.applyEffAsFunctionOfMult) { efficiencyTrigg = hEfficiencyTriggerMult->Interpolate(trigg.pt(), trigg.eta(), mult); } else if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { - efficiencyTrigg = hEfficiencyTriggerMultVsPhi->GetBinContent(hEfficiencyTriggerMultVsPhi->GetBin(bintrig)); + efficiencyTrigg = hEfficiencyTriggerMultVsPhi->GetBinContent(hEfficiencyTriggerMultVsPhi->GetBin(bintrig.data())); } else { efficiencyTrigg = hEfficiencyTrigger->Interpolate(trigg.pt(), trigg.eta()); } if (efficiencyFlags.applyPurityTrigger) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { purityTrigg = hPurityHadronMult->Interpolate(trigg.pt(), mult); - else + } else { purityTrigg = hPurityHadron->Interpolate(trigg.pt()); + } } if (efficiencyFlags.applyEfficiencyPropagation) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { efficiencyTriggError = hEfficiencyUncertaintyTriggerMult->Interpolate(trigg.pt(), trigg.eta(), mult); - else if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) - efficiencyTriggError = hEfficiencyTriggerMultVsPhi->GetBinError(hEfficiencyTriggerMultVsPhi->GetBin(bintrig)); - else + } else if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { + efficiencyTriggError = hEfficiencyTriggerMultVsPhi->GetBinError(hEfficiencyTriggerMultVsPhi->GetBin(bintrig.data())); + } else { efficiencyTriggError = hEfficiencyUncertaintyTrigger->Interpolate(trigg.pt(), trigg.eta()); + } if (efficiencyFlags.applyPurityTrigger) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { purityTriggErr = hPurityUncertaintyHadronMult->Interpolate(trigg.pt(), mult); - else + } else { purityTriggErr = hPurityUncertaintyHadron->Interpolate(trigg.pt()); + } } } if (efficiencyTrigg == 0) { // check for zero efficiency, do not apply if the case @@ -1151,12 +1258,13 @@ struct HStrangeCorrelation { fillTriggerHistogram(histos.get(HIST("sameEvent/TriggerParticlesCascade")), trigg.pt(), mult, efficiencyTrigg, efficiencyTriggError, purityTrigg, purityTriggErr); } double triggSign = trigg.sign(); - double triggForDeltaPhiStar[] = {trigg.phi(), trigg.pt(), triggSign}; + std::array triggForDeltaPhiStar = {trigg.phi(), trigg.pt(), triggSign}; if (mixingInBf) { currentCollision.addValidParticle(trigg.eta(), trigg.phi(), trigg.pt(), -1, efficiencyTrigg, efficiencyTriggError, -1); - if (firstLoop) + if (firstLoop) { continue; + } } for (auto const& assocCandidate : assocs) { firstLoop = true; @@ -1172,10 +1280,12 @@ struct HStrangeCorrelation { assoc.casccosPA(pvx, pvy, pvz) < cascadeSelections.cascCospa || assoc.cascradius() < cascadeSelections.cascRadius || std::abs(assoc.dcav0topv(pvx, pvy, pvz)) < cascadeSelections.cascdcaV0ToPV || - std::abs(assoc.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow)) + std::abs(assoc.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow)) { continue; - if (!masterConfigurations.doPPAnalysis && !cascadeSelectedPbPb(assoc, pvx, pvy, pvz)) + } + if (!masterConfigurations.doPPAnalysis && !cascadeSelectedPbPb(assoc, pvx, pvy, pvz)) { continue; + } uint64_t cascselMap = cascadeselectionBitmap(assoc, pvx, pvy, pvz); //---] removing autocorrelations [--- auto postrack = assoc.posTrack_as(); @@ -1206,14 +1316,17 @@ struct HStrangeCorrelation { ptProton = negtrack.pt(); signProton = negtrack.sign(); } - double assocForDeltaPhiStar[] = {phiProton, ptProton, signProton}; + std::array assocForDeltaPhiStar = {phiProton, ptProton, signProton}; //---] track quality check [--- - if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { continue; - if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || bachtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) + } + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || bachtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) { continue; - if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || bachtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) + } + if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || bachtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) { continue; + } float deltaphi = computeDeltaPhi(trigg.phi(), assoc.phi()); float deltaeta = trigg.eta() - assoc.eta(); @@ -1224,15 +1337,18 @@ struct HStrangeCorrelation { float pttrigger = trigg.pt(); // skip if basic ranges not met - if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) + if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) { continue; - if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) + } + if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) { continue; - if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) + } + if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) { continue; + } - TH2F* hEfficiencyCascade[4]; - THnF* hEfficiencyCascadeMultVsPhi[4]; + std::array hEfficiencyCascade{nullptr, nullptr, nullptr, nullptr}; + std::array hEfficiencyCascadeMultVsPhi{nullptr, nullptr, nullptr, nullptr}; if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { hEfficiencyCascadeMultVsPhi[0] = hEfficiencyXiMinusMultVsPhi; hEfficiencyCascadeMultVsPhi[1] = hEfficiencyXiPlusMultVsPhi; @@ -1245,7 +1361,7 @@ struct HStrangeCorrelation { hEfficiencyCascade[3] = hEfficiencyOmegaPlus; } - TH2F* hEfficiencyUncertaintyCascade[4]; + std::array hEfficiencyUncertaintyCascade{nullptr, nullptr, nullptr, nullptr}; hEfficiencyUncertaintyCascade[0] = hEfficiencyUncertaintyXiMinus; hEfficiencyUncertaintyCascade[1] = hEfficiencyUncertaintyXiPlus; hEfficiencyUncertaintyCascade[2] = hEfficiencyUncertaintyOmegaMinus; @@ -1267,14 +1383,16 @@ struct HStrangeCorrelation { float efficiencyError = 0.0f; if (efficiencyFlags.applyEfficiencyCorrection) { if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { - double bin[4] = {ptassoc, assoc.eta(), assoc.phi(), mult}; - efficiency = hEfficiencyCascadeMultVsPhi[Index]->GetBinContent(hEfficiencyCascadeMultVsPhi[Index]->GetBin(bin)); - if (efficiencyFlags.applyEfficiencyPropagation) - efficiencyError = hEfficiencyCascadeMultVsPhi[Index]->GetBinError(hEfficiencyCascadeMultVsPhi[Index]->GetBin(bin)); + std::array bin = {ptassoc, assoc.eta(), assoc.phi(), mult}; + efficiency = hEfficiencyCascadeMultVsPhi[Index]->GetBinContent(hEfficiencyCascadeMultVsPhi[Index]->GetBin(bin.data())); + if (efficiencyFlags.applyEfficiencyPropagation) { + efficiencyError = hEfficiencyCascadeMultVsPhi[Index]->GetBinError(hEfficiencyCascadeMultVsPhi[Index]->GetBin(bin.data())); + } } else { efficiency = hEfficiencyCascade[Index]->Interpolate(ptassoc, assoc.eta()); - if (efficiencyFlags.applyEfficiencyPropagation) + if (efficiencyFlags.applyEfficiencyPropagation) { efficiencyError = hEfficiencyUncertaintyCascade[Index]->Interpolate(ptassoc, assoc.eta()); + } } } if (efficiency == 0) { // check for zero efficiency, do not apply if the case @@ -1285,36 +1403,39 @@ struct HStrangeCorrelation { totalEffUncert = std::sqrt(std::pow(efficiencyTrigg * efficiencyError, 2) + std::pow(efficiencyTriggError * efficiency, 2)); } - double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + std::array binFillThn = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; if (TESTBIT(doCorrelation, Index + 3) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0) && (masterConfigurations.doPPAnalysis || (TESTBIT(cascselMap, Index) && TESTBIT(cascselMap, Index + 4) && TESTBIT(cascselMap, Index + 8) && TESTBIT(cascselMap, Index + 12)))) { if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/LeftBg/") + HIST(Cascadenames[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); - if ((Index == IndexXiMinus && triggSign > Neutral) || (Index == IndexXiPlus && triggSign < Neutral) || (Index == IndexOmegaMinus && triggSign > Neutral) || (Index == IndexOmegaPlus && triggSign < 0)) + if ((Index == IndexXiMinus && triggSign > Neutral) || (Index == IndexXiPlus && triggSign < Neutral) || (Index == IndexOmegaMinus && triggSign > Neutral) || (Index == IndexOmegaPlus && triggSign < 0)) { histos.fill(HIST("sameEvent/LeftBg/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, 0.5); - else + } else { histos.fill(HIST("sameEvent/LeftBg/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); + } } } if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(Cascadenames[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); - if ((Index == IndexXiMinus && triggSign > Neutral) || (Index == IndexXiPlus && triggSign < Neutral) || (Index == IndexOmegaMinus && triggSign > Neutral) || (Index == IndexOmegaPlus && triggSign < 0)) + if ((Index == IndexXiMinus && triggSign > Neutral) || (Index == IndexXiPlus && triggSign < Neutral) || (Index == IndexOmegaMinus && triggSign > Neutral) || (Index == IndexOmegaPlus && triggSign < 0)) { histos.fill(HIST("sameEvent/Signal/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, 0.5); - else + } else { histos.fill(HIST("sameEvent/Signal/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); + } } } if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/RightBg/") + HIST(Cascadenames[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); - if ((Index == IndexXiMinus && triggSign > Neutral) || (Index == IndexXiPlus && triggSign < Neutral) || (Index == IndexOmegaMinus && triggSign > Neutral) || (Index == IndexOmegaPlus && triggSign < 0)) + if ((Index == IndexXiMinus && triggSign > Neutral) || (Index == IndexXiPlus && triggSign < Neutral) || (Index == IndexOmegaMinus && triggSign > Neutral) || (Index == IndexOmegaPlus && triggSign < 0)) { histos.fill(HIST("sameEvent/RightBg/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, 0.5); - else + } else { histos.fill(HIST("sameEvent/RightBg/") + HIST(Cascadenames[Index]) + HIST("DeltaPhiStar"), deltaPhiStar, trigg.eta() - etaProton, -0.5); + } } } if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { @@ -1342,15 +1463,17 @@ struct HStrangeCorrelation { }); } } - if (!mixingInBf || binVtxZ < 0 || binVtxZ > nBinsVtxZ - 1 || binMult < 0 || binMult > nBinsMult - 1) + if (!mixingInBf || binVtxZ < 0 || binVtxZ > nBinsVtxZ - 1 || binMult < 0 || binMult > nBinsMult - 1) { return; + } int binnumb = binMult * nBinsVtxZ + binVtxZ; int hastirgorassoc = masterConfigurations.collisionHasTriggOrAssoc; if ((hastirgorassoc == 1 && currentCollision.trigParticles.empty()) || (hastirgorassoc == 2 && currentCollision.assocParticles.empty()) || (hastirgorassoc == 3 && currentCollision.trigParticles.empty() && currentCollision.assocParticles.empty()) || - (hastirgorassoc == 4 && (currentCollision.trigParticles.empty() || currentCollision.assocParticles.empty()))) + (hastirgorassoc == 4 && (currentCollision.trigParticles.empty() || currentCollision.assocParticles.empty()))) { return; + } for (const auto& collision : validCollisions[binnumb]) { BinningTypePP colBinning{{axesConfigurations.axisVtxZ, axesConfigurations.axisMult}, true}; histos.fill(HIST("MixingQA/hMECollisionBins"), colBinning.getBin({collision.pvz, collision.mult})); @@ -1371,7 +1494,7 @@ struct HStrangeCorrelation { if (masterConfigurations.doMirroringInDelataEta) { deltaeta = std::abs(deltaeta); } - double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + std::array binFillThn = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; static_for<0, 3>([&](auto i) { constexpr int Index = i.value; if (Index == assoc.type && assoc.region == 0) { @@ -1390,45 +1513,52 @@ struct HStrangeCorrelation { if (validCollisions[binnumb].size() >= static_cast(masterConfigurations.mixingParameter)) { validCollisions[binnumb].erase(validCollisions[binnumb].begin()); } - if (!currentCollision.trigParticles.empty()) + if (!currentCollision.trigParticles.empty()) { validCollisions[binnumb].push_back(currentCollision); + } } template void fillCorrelationsHadron(TTriggers const& triggers, THadrons const& assocs, bool mixing, float pvz, float mult, double bField) { for (auto const& triggerTrack : triggers) { - if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { continue; + } auto trigg = triggerTrack.template track_as(); - if (!isValidTrigger(trigg, triggerTrack.isLeading())) + if (!isValidTrigger(trigg, triggerTrack.isLeading())) { continue; + } float efficiencyTrigger = 1.0f; float efficiencyTriggerError = 0.0f; float purityTrigger = 1.0f; float purityTriggerError = 0.0f; if (efficiencyFlags.applyEfficiencyForTrigger) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { efficiencyTrigger = hEfficiencyTriggerMult->Interpolate(trigg.pt(), trigg.eta(), mult); - else + } else { efficiencyTrigger = hEfficiencyTrigger->Interpolate(trigg.pt(), trigg.eta()); + } if (efficiencyFlags.applyPurityTrigger) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { purityTrigger = hPurityHadronMult->Interpolate(trigg.pt(), mult); - else + } else { purityTrigger = hPurityHadron->Interpolate(trigg.pt()); + } } if (efficiencyFlags.applyEfficiencyPropagation) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { efficiencyTriggerError = hEfficiencyUncertaintyTriggerMult->Interpolate(trigg.pt(), trigg.eta(), mult); - else + } else { efficiencyTriggerError = hEfficiencyUncertaintyTrigger->Interpolate(trigg.pt(), trigg.eta()); + } if (efficiencyFlags.applyPurityTrigger) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { purityTriggerError = hPurityUncertaintyHadronMult->Interpolate(trigg.pt(), mult); - else + } else { purityTriggerError = hPurityUncertaintyHadron->Interpolate(trigg.pt()); + } } } if (efficiencyTrigger == 0) { // check for zero efficiency, do not apply if the case @@ -1437,29 +1567,32 @@ struct HStrangeCorrelation { } } if (!mixing) { - if constexpr (requires { triggerTrack.extra(); }) + if constexpr (requires { triggerTrack.extra(); }) { fillTriggerHistogram(histos.get(HIST("sameEvent/TriggerParticlesPion")), trigg.pt(), mult, efficiencyTrigger, efficiencyTriggerError, purityTrigger, purityTriggerError); - else + } else { fillTriggerHistogram(histos.get(HIST("sameEvent/TriggerParticlesHadron")), trigg.pt(), mult, efficiencyTrigger, efficiencyTriggerError, purityTrigger, purityTriggerError); + } } double triggSign = trigg.sign(); - double triggForDeltaPhiStar[] = {trigg.phi(), trigg.pt(), triggSign}; + std::array triggForDeltaPhiStar = {trigg.phi(), trigg.pt(), triggSign}; for (auto const& assocTrack : assocs) { auto assoc = assocTrack.template track_as(); //---] removing autocorrelations [--- if (doAutocorrelationRejection) { if (trigg.globalIndex() == assoc.globalIndex()) { - if constexpr (requires { assocTrack.nSigmaTPCPi(); }) + if constexpr (requires { assocTrack.nSigmaTPCPi(); }) { histos.fill(HIST("hNumberOfRejectedPairsPion"), 0.5); - else + } else { histos.fill(HIST("hNumberOfRejectedPairsHadron"), 0.5); + } continue; } } //---] track quality check [--- - if (!isValidAssocHadron(assoc)) + if (!isValidAssocHadron(assoc)) { continue; + } if (doAssocPhysicalPrimary && !assocTrack.mcPhysicalPrimary()) { continue; } @@ -1472,7 +1605,7 @@ struct HStrangeCorrelation { float pttrigger = trigg.pt(); double assocSign = assoc.sign(); - double assocForDeltaPhiStar[] = {assoc.phi(), assoc.pt(), assocSign}; + std::array assocForDeltaPhiStar = {assoc.phi(), assoc.pt(), assocSign}; float etaWeight = 1.; if (checks.doOnTheFlyFlattening) { @@ -1481,12 +1614,15 @@ struct HStrangeCorrelation { } // skip if basic ranges not met - if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) + if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) { continue; - if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) + } + if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) { continue; - if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) + } + if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) { continue; + } float efficiency = 1; float purity = 1.0f; @@ -1497,29 +1633,34 @@ struct HStrangeCorrelation { if (efficiencyFlags.applyEfficiencyCorrection) { if constexpr (requires { assocTrack.nSigmaTPCPi(); }) { efficiency = hEfficiencyPion->Interpolate(ptassoc, assoc.eta()); - if (efficiencyFlags.applyEfficiencyPropagation) + if (efficiencyFlags.applyEfficiencyPropagation) { efficiencyUncertainty = hEfficiencyUncertaintyPion->Interpolate(ptassoc, assoc.eta()); + } } else { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { efficiency = hEfficiencyHadronMult->Interpolate(ptassoc, assoc.eta(), mult); - else + } else { efficiency = hEfficiencyHadron->Interpolate(ptassoc, assoc.eta()); + } if (efficiencyFlags.applyPurityHadron) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { purity = hPurityHadronMult->Interpolate(ptassoc, mult); - else + } else { purity = hPurityHadron->Interpolate(ptassoc); + } } if (efficiencyFlags.applyEfficiencyPropagation) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { efficiencyUncertainty = hEfficiencyUncertaintyHadronMult->Interpolate(ptassoc, assoc.eta(), mult); - else + } else { efficiencyUncertainty = hEfficiencyUncertaintyHadron->Interpolate(ptassoc, assoc.eta()); + } if (efficiencyFlags.applyPurityHadron) { - if (efficiencyFlags.applyEffAsFunctionOfMult) + if (efficiencyFlags.applyEffAsFunctionOfMult) { purityUncertainty = hPurityUncertaintyHadronMult->Interpolate(ptassoc, mult); - else + } else { purityUncertainty = hPurityUncertaintyHadron->Interpolate(ptassoc); + } } } } @@ -1533,7 +1674,7 @@ struct HStrangeCorrelation { totalPurityUncert = std::sqrt(std::pow(purityTrigger * purityUncertainty, 2) + std::pow(purity * purityTriggerError, 2)); } - double binFillThn[6] = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; + std::array binFillThn = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); if (!mixing) { if constexpr (requires { assocTrack.nSigmaTPCPi(); }) { @@ -1567,49 +1708,58 @@ struct HStrangeCorrelation { zorroSummary.setObject(zorro.getZorroSummary()); mRunNumber = 0; mRunNumberZorro = 0; - hEfficiencyPion = 0x0; - hEfficiencyK0Short = 0x0; - hEfficiencyLambda = 0x0; - hEfficiencyAntiLambda = 0x0; - hEfficiencyXiMinus = 0x0; - hEfficiencyXiPlus = 0x0; - hEfficiencyOmegaMinus = 0x0; - hEfficiencyOmegaPlus = 0x0; - hEfficiencyUncertaintyTrigger = 0x0; - hEfficiencyUncertaintyXiMinus = 0x0; - hEfficiencyUncertaintyXiPlus = 0x0; - hEfficiencyUncertaintyOmegaMinus = 0x0; - hEfficiencyUncertaintyOmegaPlus = 0x0; - hEfficiencyUncertaintyPion = 0x0; - hEfficiencyUncertaintyK0Short = 0x0; - hEfficiencyUncertaintyLambda = 0x0; - hEfficiencyUncertaintyAntiLambda = 0x0; - - hEfficiencyHadron = 0x0; - hPurityHadron = 0x0; - hPurityUncertaintyHadron = 0x0; - hEfficiencyUncertaintyHadron = 0x0; + hEfficiencyPion = nullptr; + hEfficiencyK0Short = nullptr; + hEfficiencyLambda = nullptr; + hEfficiencyAntiLambda = nullptr; + hEfficiencyXiMinus = nullptr; + hEfficiencyXiPlus = nullptr; + hEfficiencyOmegaMinus = nullptr; + hEfficiencyOmegaPlus = nullptr; + hEfficiencyUncertaintyTrigger = nullptr; + hEfficiencyUncertaintyXiMinus = nullptr; + hEfficiencyUncertaintyXiPlus = nullptr; + hEfficiencyUncertaintyOmegaMinus = nullptr; + hEfficiencyUncertaintyOmegaPlus = nullptr; + hEfficiencyUncertaintyPion = nullptr; + hEfficiencyUncertaintyK0Short = nullptr; + hEfficiencyUncertaintyLambda = nullptr; + hEfficiencyUncertaintyAntiLambda = nullptr; + + hEfficiencyHadron = nullptr; + hPurityHadron = nullptr; + hPurityUncertaintyHadron = nullptr; + hEfficiencyUncertaintyHadron = nullptr; // set bitmap for convenience doCorrelation = 0; - if (masterConfigurations.doCorrelationK0Short) + if (masterConfigurations.doCorrelationK0Short) { SETBIT(doCorrelation, 0); - if (masterConfigurations.doCorrelationLambda) + } + if (masterConfigurations.doCorrelationLambda) { SETBIT(doCorrelation, 1); - if (masterConfigurations.doCorrelationAntiLambda) + } + if (masterConfigurations.doCorrelationAntiLambda) { SETBIT(doCorrelation, 2); - if (masterConfigurations.doCorrelationXiMinus) + } + if (masterConfigurations.doCorrelationXiMinus) { SETBIT(doCorrelation, 3); - if (masterConfigurations.doCorrelationXiPlus) + } + if (masterConfigurations.doCorrelationXiPlus) { SETBIT(doCorrelation, 4); - if (masterConfigurations.doCorrelationOmegaMinus) + } + if (masterConfigurations.doCorrelationOmegaMinus) { SETBIT(doCorrelation, 5); - if (masterConfigurations.doCorrelationOmegaPlus) + } + if (masterConfigurations.doCorrelationOmegaPlus) { SETBIT(doCorrelation, 6); - if (masterConfigurations.doCorrelationPion) + } + if (masterConfigurations.doCorrelationPion) { SETBIT(doCorrelation, 7); - if (masterConfigurations.doCorrelationHadron) + } + if (masterConfigurations.doCorrelationHadron) { SETBIT(doCorrelation, 8); + } // Store axis ranges to prevent spurious filling // axis status: @@ -1685,86 +1835,100 @@ struct HStrangeCorrelation { // ===] delta-phi [=== if (!preAxisDeltaPhi.nBins.has_value()) { // variable binning, use bins provided - for (int i = offset; i < static_cast(edgesDeltaPhiOrig.size()) - offset; i++) + for (int i = offset; i < static_cast(edgesDeltaPhiOrig.size()) - offset; i++) { edgesDeltaPhi.emplace_back(edgesDeltaPhiOrig[i]); + } } else { // fixed binning, generate the bin edges on-the-spot double min = edgesDeltaPhiOrig[0]; double delta = (edgesDeltaPhiOrig[1] - edgesDeltaPhiOrig[0]) / preAxisDeltaPhi.nBins.value(); - for (int i = offset; i < preAxisDeltaPhi.nBins.value() + 1 - offset; i++) + for (int i = offset; i < preAxisDeltaPhi.nBins.value() + 1 - offset; i++) { edgesDeltaPhi.emplace_back(min + static_cast(i) * delta); + } } // ===] delta-eta [=== if (!preAxisDeltaEta.nBins.has_value()) { // variable binning, use bins provided - for (int i = offset; i < static_cast(edgesDeltaEtaOrig.size()) - offset; i++) + for (int i = offset; i < static_cast(edgesDeltaEtaOrig.size()) - offset; i++) { edgesDeltaEta.emplace_back(edgesDeltaEtaOrig[i]); + } } else { // fixed binning, generate the bin edges on-the-spot double min = edgesDeltaEtaOrig[0]; double delta = (edgesDeltaEtaOrig[1] - edgesDeltaEtaOrig[0]) / preAxisDeltaEta.nBins.value(); - for (int i = offset; i < preAxisDeltaEta.nBins.value() + 1 - offset; i++) + for (int i = offset; i < preAxisDeltaEta.nBins.value() + 1 - offset; i++) { edgesDeltaEta.emplace_back(min + static_cast(i) * delta); + } } // ===] pt assoc [=== if (!preAxisPtAssoc.nBins.has_value()) { // variable binning, use bins provided - for (int i = offset; i < static_cast(edgesPtAssocOrig.size()) - offset; i++) + for (int i = offset; i < static_cast(edgesPtAssocOrig.size()) - offset; i++) { edgesPtAssoc.emplace_back(edgesPtAssocOrig[i]); + } } else { // fixed binning, generate the bin edges on-the-spot double min = edgesPtAssocOrig[0]; double delta = (edgesPtAssocOrig[1] - edgesPtAssocOrig[0]) / preAxisPtAssoc.nBins.value(); - for (int i = offset; i < preAxisPtAssoc.nBins.value() + 1 - offset; i++) + for (int i = offset; i < preAxisPtAssoc.nBins.value() + 1 - offset; i++) { edgesPtAssoc.emplace_back(min + static_cast(i) * delta); + } } // ===] pt trigger [=== if (!preAxisPtTrigger.nBins.has_value()) { // variable binning, use bins provided - for (int i = offset; i < static_cast(edgesPtTriggerOrig.size()) - offset; i++) + for (int i = offset; i < static_cast(edgesPtTriggerOrig.size()) - offset; i++) { edgesPtTrigger.emplace_back(edgesPtTriggerOrig[i]); + } } else { // fixed binning, generate the bin edges on-the-spot double min = edgesPtTriggerOrig[0]; double delta = (edgesPtTriggerOrig[1] - edgesPtTriggerOrig[0]) / preAxisPtTrigger.nBins.value(); - for (int i = offset; i < preAxisPtTrigger.nBins.value() + 1 - offset; i++) + for (int i = offset; i < preAxisPtTrigger.nBins.value() + 1 - offset; i++) { edgesPtTrigger.emplace_back(min + static_cast(i) * delta); + } } // ===] vtx Z [=== if (!preAxisVtxZ.nBins.has_value()) { // variable binning, use bins provided - for (int i = offset; i < static_cast(edgesVtxZOrig.size()) - offset; i++) + for (int i = offset; i < static_cast(edgesVtxZOrig.size()) - offset; i++) { edgesVtxZ.emplace_back(edgesVtxZOrig[i]); + } } else { // fixed binning, generate the bin edges on-the-spot double min = edgesVtxZOrig[0]; double delta = (edgesVtxZOrig[1] - edgesVtxZOrig[0]) / preAxisVtxZ.nBins.value(); - for (int i = offset; i < preAxisVtxZ.nBins.value() + 1 - offset; i++) + for (int i = offset; i < preAxisVtxZ.nBins.value() + 1 - offset; i++) { edgesVtxZ.emplace_back(min + static_cast(i) * delta); + } } // ===] mult percentile [=== if (!preAxisMult.nBins.has_value()) { // variable binning, use bins provided - for (int i = offset; i < static_cast(edgesMultOrig.size()) - offset; i++) + for (int i = offset; i < static_cast(edgesMultOrig.size()) - offset; i++) { edgesMult.emplace_back(edgesMultOrig[i]); + } } else { // fixed binning, generate the bin edges on-the-spot double min = edgesMultOrig[0]; double delta = (edgesMultOrig[1] - edgesMultOrig[0]) / preAxisMult.nBins.value(); - for (int i = offset; i < preAxisMult.nBins.value() + 1 - offset; i++) + for (int i = offset; i < preAxisMult.nBins.value() + 1 - offset; i++) { edgesMult.emplace_back(min + static_cast(i) * delta); + } } // ===] multiplicity count [=== if (!preAxisMultiplicity.nBins.has_value()) { // variable binning, use bins provided - for (int i = offset; i < static_cast(edgesMultiplicityOrig.size()) - offset; i++) + for (int i = offset; i < static_cast(edgesMultiplicityOrig.size()) - offset; i++) { edgesMultiplicity.emplace_back(edgesMultiplicityOrig[i]); + } } else { // fixed binning, generate the bin edges on-the-spot double min = edgesMultiplicityOrig[0]; double delta = (edgesMultiplicityOrig[1] - edgesMultiplicityOrig[0]) / preAxisMultiplicity.nBins.value(); - for (int i = offset; i < preAxisMultiplicity.nBins.value() + 1 - offset; i++) + for (int i = offset; i < preAxisMultiplicity.nBins.value() + 1 - offset; i++) { edgesMultiplicity.emplace_back(min + static_cast(i) * delta); + } } LOGF(info, "Initialized THnF axis delta-phi with %i bins.", edgesDeltaPhi.size() - 1); @@ -1792,9 +1956,9 @@ struct HStrangeCorrelation { if (!masterConfigurations.doPPAnalysis) { // event selections in Pb-Pb histos.add("hEventSelection", "hEventSelection", kTH1F, {{10, 0, 10}}); - TString eventSelLabel[] = {"all", "sel8", "kIsTriggerTVX", "PV_{z}", "kIsGoodITSLayersAll", "kIsGoodZvtxFT0vsPV", "OccupCut", "kNoTimeFrameBorder", "kNoITSROFrameBorder", "kNoSameBunchPileup "}; + std::array eventSelLabel = {"all", "sel8", "kIsTriggerTVX", "PV_{z}", "kIsGoodITSLayersAll", "kIsGoodZvtxFT0vsPV", "OccupCut", "kNoTimeFrameBorder", "kNoITSROFrameBorder", "kNoSameBunchPileup "}; for (int i = 1; i <= histos.get(HIST("hEventSelection"))->GetNbinsX(); i++) { - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(i, eventSelLabel[i - 1]); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(i, eventSelLabel[i - 1].Data()); } } // Some QA plots @@ -1857,8 +2021,9 @@ struct HStrangeCorrelation { bool hStrange = false; for (int i = 0; i < AssocParticleTypes; i++) { if (TESTBIT(doCorrelation, i)) { - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { histos.add(fmt::format("sameEvent/Signal/{}", Particlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + } if (doDeltaPhiStarCheck && masterConfigurations.doFullCorrelationStudy) { histos.add(fmt::format("sameEvent/Signal/{}DeltaPhiStar", Particlenames[i]).c_str(), "", kTH3F, {{100, -0.3, 0.3}, {50, -0.05, 0.05}, {2, -1, 1}}); // -1 oposite charge, 1 same charge } @@ -1899,6 +2064,34 @@ struct HStrangeCorrelation { histos.addClone("sameEvent/Signal/", "sameEvent/LeftBg/"); histos.addClone("sameEvent/Signal/", "sameEvent/RightBg/"); } + + if (masterConfigurations.doFullCorrelationStudy && doprocessSameEventHV0s) { + if (TESTBIT(doCorrelation, 0)) { + histos.add("sameEvent/K0Short/hInvariantMassNearSide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisK0ShortMass}); + histos.add("sameEvent/K0Short/hInvariantMassAwaySide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisK0ShortMass}); + histos.add("sameEvent/K0Short/hInvariantMassUE", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisK0ShortMass}); + if (masterConfigurations.doCorrelationsHadronV0daughter) { + histos.add("sameEvent/Signal/K0Short/hSameSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + histos.add("sameEvent/Signal/K0Short/hOppositeSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + } + } + if (TESTBIT(doCorrelation, 1)) { + histos.add("sameEvent/Lambda/hInvariantMassNearSide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + histos.add("sameEvent/Lambda/hInvariantMassAwaySide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + histos.add("sameEvent/Lambda/hInvariantMassUE", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + if (masterConfigurations.doCorrelationsHadronV0daughter) { + histos.add("sameEvent/Signal/Lambda/hSameSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + histos.add("sameEvent/Signal/Lambda/hOppositeSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + } + } + if (TESTBIT(doCorrelation, 2)) { + histos.addClone("sameEvent/Lambda/", "sameEvent/AntiLambda/"); + if (masterConfigurations.doCorrelationsHadronV0daughter) { + histos.add("sameEvent/Signal/AntiLambda/hSameSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + histos.add("sameEvent/Signal/AntiLambda/hOppositeSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + } + } + } if (TESTBIT(doCorrelation, 0) && doprocessSameEventHV0s && masterConfigurations.doMassSpectrumCheck) { histos.add("hK0ShortPtVsMass", "", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisK0ShortMass}); } @@ -1913,14 +2106,18 @@ struct HStrangeCorrelation { if ((doprocessMixedEventHV0sInBuffer || doprocessMixedEventHCascadesInBuffer || doprocessMixedEventHV0s || doprocessMixedEventHCascades || doprocessMixedEventHPions || doprocessMixedEventHHadrons) && masterConfigurations.doFullCorrelationStudy) { histos.addClone("sameEvent/", "mixedEvent/"); } - if (doprocessSameEventHHadrons && masterConfigurations.doFullCorrelationStudy) + if (doprocessSameEventHHadrons && masterConfigurations.doFullCorrelationStudy) { histos.add("sameEvent/TriggerParticlesHadron", "TriggersHadron", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); - if (doprocessSameEventHV0s && masterConfigurations.doFullCorrelationStudy) + } + if (doprocessSameEventHV0s && masterConfigurations.doFullCorrelationStudy) { histos.add("sameEvent/TriggerParticlesV0", "TriggersV0", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); - if (doprocessSameEventHCascades && masterConfigurations.doFullCorrelationStudy) + } + if (doprocessSameEventHCascades && masterConfigurations.doFullCorrelationStudy) { histos.add("sameEvent/TriggerParticlesCascade", "TriggersCascade", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); - if (doprocessSameEventHPions && masterConfigurations.doFullCorrelationStudy) + } + if (doprocessSameEventHPions && masterConfigurations.doFullCorrelationStudy) { histos.add("sameEvent/TriggerParticlesPion", "TriggersPion", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); + } // MC generated plots if (doprocessMCGenerated) { @@ -1952,10 +2149,16 @@ struct HStrangeCorrelation { } if (doprocessClosureTest) { for (int i = 0; i < AssocParticleTypes; i++) { - if (TESTBIT(doCorrelation, i)) + if (TESTBIT(doCorrelation, i)) { histos.add(fmt::format("ClosureTest/sameEvent/{}", Particlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - if (TESTBIT(doCorrelation, i)) + if (masterConfigurations.doCorrelationsHadronV0daughter) { + histos.add(fmt::format("ClosureTest/sameEvent/{}_SameSignDaughter", Particlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + histos.add(fmt::format("ClosureTest/sameEvent/{}_OppSignDaughter", Particlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + } + } + if (TESTBIT(doCorrelation, i)) { histos.add(fmt::format("ClosureTest/h{}", Particlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + } } histos.add("ClosureTest/hTrigger", "Trigger Tracks", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisMult}); } @@ -1979,7 +2182,7 @@ struct HStrangeCorrelation { mCounter.mPdgDatabase = pdgDB.service; mCounter.mSelectPrimaries = doAssocPhysicalPrimary.value; histos.add("Prediction/hEventSelection", "hEventSelection", kTH1F, {{3, 0, 3}}); - TString eventSelLabel[] = {"Read", "INELgt0", "|Z|<10"}; + std::array eventSelLabel = {"Read", "INELgt0", "|Z|<10"}; for (int i = 1; i <= histos.get(HIST("Prediction/hEventSelection"))->GetNbinsX(); i++) { histos.get(HIST("Prediction/hEventSelection"))->GetXaxis()->SetBinLabel(i, eventSelLabel[i - 1]); } @@ -2003,14 +2206,17 @@ struct HStrangeCorrelation { histos.add("Prediction/hFT0MvsNchEta05", "Nch in 0.5 vs FT0M multiplicity", kTH2F, {axesConfigurations.axisMultiplicity, axesConfigurations.axisMidrapidityMultiplicity}); } for (int i = 0; i < AssocParticleTypes; i++) { - if (TESTBIT(doCorrelation, i)) + if (TESTBIT(doCorrelation, i)) { histos.add(fmt::format("Prediction/h{}", Particlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + } if (masterConfigurations.useCentralityinPrediction) { - if (TESTBIT(doCorrelation, i)) + if (TESTBIT(doCorrelation, i)) { histos.add(fmt::format("Prediction/sameEvent/{}", Particlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + } } else { - if (TESTBIT(doCorrelation, i)) + if (TESTBIT(doCorrelation, i)) { histos.add(fmt::format("Prediction/sameEvent/{}", Particlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultiplicityNDim}); + } } } if (masterConfigurations.doSeparateFT0Prediction) { @@ -2065,50 +2271,58 @@ struct HStrangeCorrelation { // event selections in Pb-Pb template - bool isCollisionSelectedPbPb(TCollision collision, bool fillHists) + bool isCollisionSelectedPbPb(TCollision const& collision, bool fillHists) { - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 0.5 /* all collisions */); + } // Perform basic event selection if (!collision.sel8()) { return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 1.5 /* collisions after sel8*/); + } if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) && masterConfigurations.requireGoodTriggerTVX) { return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 2.5 /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */); + } if (std::abs(collision.posZ()) > masterConfigurations.zVertexCut) { return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 3.5 /* collisions after sel pvz sel*/); + } if (!collision.selection_bit(aod::evsel::kIsGoodITSLayersAll) && masterConfigurations.requireAllGoodITSLayers) { // cut time intervals with dead ITS staves return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 4.5 /* collisions after cut time intervals with dead ITS staves*/); + } if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) && masterConfigurations.requireGoodZvtxFT0vsPV) { // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference // use this cut at low multiplicities with caution return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 5.5 /* removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference*/); + } auto occupancy = collision.trackOccupancyInTimeRange(); - if (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh) + if (occupancy < cfgCutOccupancyLow || occupancy > cfgCutOccupancyHigh) { return false; - if (fillHists) + } + if (fillHists) { histos.fill(HIST("hEventSelection"), 6.5 /* Below min occupancy and Above max occupancy*/); + } /* if (collision.alias_bit(kTVXinTRD)) { @@ -2122,24 +2336,27 @@ struct HStrangeCorrelation { // O2-4623 return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 7.5 /* reject collisions close to Time Frame borders*/); + } if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { // reject events affected by the ITS ROF border // O2-4309 return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 8.5 /* reject events affected by the ITS ROF border*/); + } if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { // rejects collisions which are associated with the same "found-by-T0" bunch crossing // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 9.5 /* rejects collisions which are associated with the same "found-by-T0" bunch crossing*/); + } return true; } @@ -2227,8 +2444,9 @@ struct HStrangeCorrelation { if (!doprocessSameEventHCascades && !doprocessSameEventHV0s && !doprocessSameEventHPions) { for (auto const& triggerTrack : triggerTracks) { auto track = triggerTrack.track_as(); - if (!isValidTrigger(track, triggerTrack.isLeading())) + if (!isValidTrigger(track, triggerTrack.isLeading())) { continue; + } histos.fill(HIST("hDCAzTriggerHadron"), track.dcaZ(), track.pt()); histos.fill(HIST("hDCAxyTriggerHadron"), track.dcaXY(), track.pt()); float efficiency = 1.0f; @@ -2241,24 +2459,27 @@ struct HStrangeCorrelation { float weight = efficiencyFlags.applyEfficiencyCorrection ? 1. / efficiency : 1.0f; histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); - if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { continue; + } histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); histos.fill(HIST("hTrackEtaVsPtVsPhi"), track.pt(), track.eta(), track.phi(), weight); } } for (auto const& assocTrack : assocHadrons) { auto assoc = assocTrack.track_as(); - if (!isValidAssocHadron(assoc)) + if (!isValidAssocHadron(assoc)) { continue; + } float efficiency = 1.0f; float purity = 1.0f; histos.fill(HIST("hDCAzAssociatedHadron"), assoc.dcaZ(), assoc.pt()); histos.fill(HIST("hDCAxyAssociatedHadron"), assoc.dcaXY(), assoc.pt()); if (efficiencyFlags.applyEfficiencyCorrection) { efficiency = hEfficiencyHadron->Interpolate(assoc.pt(), assoc.eta()); - if (efficiencyFlags.applyPurityHadron) + if (efficiencyFlags.applyPurityHadron) { purity = hPurityHadron->Interpolate(assoc.pt()); + } } if (efficiency == 0) { // check for zero efficiency, do not apply if the case efficiency = 1; @@ -2266,16 +2487,18 @@ struct HStrangeCorrelation { float weight = efficiencyFlags.applyEfficiencyCorrection ? purity / efficiency : 1.0f; histos.fill(HIST("hAssocHadronsAllSelectedEtaVsPt"), assoc.pt(), assoc.eta(), collision.centFT0M(), weight); histos.fill(HIST("hAssocPtResolution"), assoc.pt(), assocTrack.mcOriginalPt()); - if (doAssocPhysicalPrimary && !assocTrack.mcPhysicalPrimary()) + if (doAssocPhysicalPrimary && !assocTrack.mcPhysicalPrimary()) { continue; + } histos.fill(HIST("hAssocPrimaryEtaVsPt"), assoc.pt(), assoc.eta(), collision.centFT0M()); histos.fill(HIST("hAsssocTrackEtaVsPtVsPhi"), assoc.pt(), assoc.eta(), assoc.phi(), weight); } // ________________________________________________ // Do hadron - hadron correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsHadron(triggerTracks, assocHadrons, false, collision.posZ(), collision.centFT0M(), bField); + } } void processSameEventHV0s(soa::Join::iterator const& collision, @@ -2316,8 +2539,8 @@ struct HStrangeCorrelation { if (efficiencyFlags.applyEfficiencyCorrection) { initEfficiencyFromCCDB(bc); } - TH2F* hEfficiencyV0[3]; - THnF* hEfficiencyV0MultVsPhi[3]; + std::array hEfficiencyV0{nullptr, nullptr, nullptr}; + std::array hEfficiencyV0MultVsPhi{nullptr, nullptr, nullptr}; if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { hEfficiencyV0MultVsPhi[0] = hEfficiencyK0ShortMultVsPhi; hEfficiencyV0MultVsPhi[1] = hEfficiencyLambdaMultVsPhi; @@ -2334,19 +2557,24 @@ struct HStrangeCorrelation { //---] track quality check [--- auto postrack = v0Data.posTrack_as(); auto negtrack = v0Data.negTrack_as(); - if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { continue; - if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) + } + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) { continue; - if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) + } + if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) { continue; + } //---] syst cuts [--- if (masterConfigurations.doPPAnalysis && (v0Data.v0radius() < v0Selection.v0RadiusMin || v0Data.v0radius() > v0Selection.v0RadiusMax || std::abs(v0Data.dcapostopv()) < v0Selection.dcapostopv || std::abs(v0Data.dcanegtopv()) < v0Selection.dcanegtopv || - v0Data.v0cosPA() < v0Selection.v0cospa || v0Data.dcaV0daughters() > v0Selection.dcaV0dau)) + v0Data.v0cosPA() < v0Selection.v0cospa || v0Data.dcaV0daughters() > v0Selection.dcaV0dau)) { continue; - if (!masterConfigurations.doPPAnalysis && !v0SelectedPbPb(v0Data)) + } + if (!masterConfigurations.doPPAnalysis && !v0SelectedPbPb(v0Data)) { continue; + } uint64_t selMap = v0selectionBitmap(v0Data, collision.posX(), collision.posY(), collision.posZ()); static_for<0, 2>([&](auto i) { @@ -2354,8 +2582,8 @@ struct HStrangeCorrelation { float efficiency = 1.0f; if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { if (efficiencyFlags.applyEfficiencyCorrection) { - double bin[4] = {v0Data.pt(), v0Data.eta(), v0Data.phi(), cent}; - efficiency = hEfficiencyV0MultVsPhi[Index]->GetBinContent(hEfficiencyV0MultVsPhi[Index]->GetBin(bin)); + std::array bin = {v0Data.pt(), v0Data.eta(), v0Data.phi(), cent}; + efficiency = hEfficiencyV0MultVsPhi[Index]->GetBinContent(hEfficiencyV0MultVsPhi[Index]->GetBin(bin.data())); } } else { if (efficiencyFlags.applyEfficiencyCorrection) { @@ -2397,12 +2625,14 @@ struct HStrangeCorrelation { if (!doprocessSameEventHCascades) { for (auto const& triggerTrack : triggerTracks) { auto track = triggerTrack.track_as(); - if (!isValidTrigger(track, triggerTrack.isLeading())) + if (!isValidTrigger(track, triggerTrack.isLeading())) { continue; + } histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), cent); histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); - if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { continue; + } if (!efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), cent); } else { @@ -2414,8 +2644,9 @@ struct HStrangeCorrelation { // ________________________________________________ // Do hadron - V0 correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsV0(triggerTracks, associatedV0s, false, false, collision.posX(), collision.posY(), collision.posZ(), cent, bField); + } } void processSameEventHCascades(soa::Join::iterator const& collision, @@ -2455,8 +2686,8 @@ struct HStrangeCorrelation { if (efficiencyFlags.applyEfficiencyCorrection) { initEfficiencyFromCCDB(bc); } - TH2F* hEfficiencyCascade[4]; - THnF* hEfficiencyCascadeMultVsPhi[4]; + std::array hEfficiencyCascade{nullptr, nullptr, nullptr, nullptr}; + std::array hEfficiencyCascadeMultVsPhi{nullptr, nullptr, nullptr, nullptr}; if (efficiencyFlags.applyEfficiencyCorrection) { if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { hEfficiencyCascadeMultVsPhi[0] = hEfficiencyXiMinusMultVsPhi; @@ -2483,21 +2714,26 @@ struct HStrangeCorrelation { cascData.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < cascadeSelections.cascCospa || cascData.cascradius() < cascadeSelections.cascRadius || std::abs(cascData.dcav0topv(collision.posX(), collision.posY(), collision.posZ())) < cascadeSelections.cascdcaV0ToPV || - std::abs(cascData.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow)) + std::abs(cascData.mLambda() - o2::constants::physics::MassLambda0) > cascadeSelections.cascV0masswindow)) { continue; - if (!masterConfigurations.doPPAnalysis && !cascadeSelectedPbPb(cascData, collision.posX(), collision.posY(), collision.posZ())) + } + if (!masterConfigurations.doPPAnalysis && !cascadeSelectedPbPb(cascData, collision.posX(), collision.posY(), collision.posZ())) { continue; + } uint64_t cascselMap = cascadeselectionBitmap(cascData, collision.posX(), collision.posY(), collision.posZ()); //---] track quality check [--- auto postrack = cascData.posTrack_as(); auto negtrack = cascData.negTrack_as(); auto bachtrack = cascData.bachelor_as(); - if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { continue; - if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || bachtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) + } + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || bachtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) { continue; - if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) + } + if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) { continue; + } static_for<0, 3>([&](auto i) { constexpr int Index = i.value; @@ -2507,8 +2743,8 @@ struct HStrangeCorrelation { float efficiency = 1.0f; if (efficiencyFlags.applyEfficiencyCorrection) { if (efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { - double bin[4] = {cascData.pt(), cascData.eta(), cascData.phi(), cent}; - efficiency = hEfficiencyCascadeMultVsPhi[Index]->GetBinContent(hEfficiencyCascadeMultVsPhi[Index]->GetBin(bin)); + std::array bin = {cascData.pt(), cascData.eta(), cascData.phi(), cent}; + efficiency = hEfficiencyCascadeMultVsPhi[Index]->GetBinContent(hEfficiencyCascadeMultVsPhi[Index]->GetBin(bin.data())); } else { efficiency = hEfficiencyCascade[Index]->Interpolate(cascData.pt(), cascData.eta()); } @@ -2544,28 +2780,32 @@ struct HStrangeCorrelation { } for (auto const& triggerTrack : triggerTracks) { auto track = triggerTrack.track_as(); - if (!isValidTrigger(track, triggerTrack.isLeading())) + if (!isValidTrigger(track, triggerTrack.isLeading())) { continue; + } histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), cent); histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); - if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { continue; + } if (!efficiencyFlags.applyEffAsFunctionOfMultAndPhi) { histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), cent); } else { histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), track.phi(), cent); } - if (track.sign() > 0) + if (track.sign() > 0) { histos.fill(HIST("hPositiveTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), cent); - else + } else { histos.fill(HIST("hNegativeTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), cent); + } histos.fill(HIST("hTrackEtaVsPtVsPhi"), track.pt(), track.eta(), track.phi()); } // ________________________________________________ // Do hadron - cascade correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsCascade(triggerTracks, associatedCascades, false, false, collision.posX(), collision.posY(), collision.posZ(), cent, bField); + } } void processSameEventHPions(soa::Join::iterator const& collision, soa::Join const& associatedPions, soa::Join const& triggerTracks, @@ -2598,29 +2838,35 @@ struct HStrangeCorrelation { // Do basic QA for (auto const& pion : associatedPions) { auto pionTrack = pion.track_as(); - if (!isValidAssocHadron(pionTrack)) + if (!isValidAssocHadron(pionTrack)) { continue; + } histos.fill(HIST("hPionEtaVsPtAllSelected"), pionTrack.pt(), pionTrack.eta(), collision.centFT0M()); - if (doAssocPhysicalPrimary && !pion.mcPhysicalPrimary()) + if (doAssocPhysicalPrimary && !pion.mcPhysicalPrimary()) { continue; - if (masterConfigurations.doMCassociation && std::abs(pion.pdgCode()) != PdgCodes[IndexPion]) + } + if (masterConfigurations.doMCassociation && std::abs(pion.pdgCode()) != PdgCodes[IndexPion]) { continue; + } histos.fill(HIST("hPionEtaVsPt"), pionTrack.pt(), pionTrack.eta(), collision.centFT0M()); - if (pionTrack.sign() > 0) + if (pionTrack.sign() > 0) { histos.fill(HIST("hPositivePionEtaVsPt"), pionTrack.pt(), pionTrack.eta(), collision.centFT0M()); - else + } else { histos.fill(HIST("hNegativePionEtaVsPt"), pionTrack.pt(), pionTrack.eta(), collision.centFT0M()); + } } if (!doprocessSameEventHCascades && !doprocessSameEventHV0s) { for (auto const& triggerTrack : triggerTracks) { auto track = triggerTrack.track_as(); - if (!isValidTrigger(track, triggerTrack.isLeading())) + if (!isValidTrigger(track, triggerTrack.isLeading())) { continue; + } histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); - if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) + if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { continue; + } histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); histos.fill(HIST("hTrackEtaVsPtVsPhi"), track.pt(), track.eta(), track.phi()); } @@ -2628,8 +2874,9 @@ struct HStrangeCorrelation { // ________________________________________________ // Do hadron - Pion correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsHadron(triggerTracks, associatedPions, false, collision.posZ(), collision.centFT0M(), bField); + } } void processMixedEventHHadrons(soa::Join const& collisions, @@ -2655,10 +2902,12 @@ struct HStrangeCorrelation { if (!isCollisionSelected(collision1) || !isCollisionSelected(collision2)) { continue; } - if (collision1.centFT0M() > axisRanges[5][1] || collision1.centFT0M() < axisRanges[5][0]) + if (collision1.centFT0M() > axisRanges[5][1] || collision1.centFT0M() < axisRanges[5][0]) { continue; - if (collision2.centFT0M() > axisRanges[5][1] || collision2.centFT0M() < axisRanges[5][0]) + } + if (collision2.centFT0M() > axisRanges[5][1] || collision2.centFT0M() < axisRanges[5][0]) { continue; + } if (doMixingQAandEventQA) { if (collision1.globalIndex() == collision2.globalIndex()) { histos.fill(HIST("MixingQA/hMixingQA"), 0.0f); // same-collision pair counting @@ -2673,8 +2922,9 @@ struct HStrangeCorrelation { auto slicedAssocHadrons = assocHadrons.sliceBy(collisionSliceHadrons, collision2.globalIndex()); // ________________________________________________ // Do hadron - hadron correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsHadron(slicedTriggerTracks, slicedAssocHadrons, true, collision1.posZ(), collision1.centFT0M(), bField); + } } } @@ -2708,10 +2958,12 @@ struct HStrangeCorrelation { if ((masterConfigurations.doPPAnalysis && (!isCollisionSelected(collision1) || !isCollisionSelected(collision2))) || (!masterConfigurations.doPPAnalysis && (!isCollisionSelectedPbPb(collision1, false) || (!isCollisionSelectedPbPb(collision2, false))))) { continue; } - if (cent1 > axisRanges[5][1] || cent1 < axisRanges[5][0]) + if (cent1 > axisRanges[5][1] || cent1 < axisRanges[5][0]) { continue; - if (cent2 > axisRanges[5][1] || cent2 < axisRanges[5][0]) + } + if (cent2 > axisRanges[5][1] || cent2 < axisRanges[5][0]) { continue; + } if (!doprocessMixedEventHCascades && doMixingQAandEventQA) { if (collision1.globalIndex() == collision2.globalIndex()) { @@ -2727,8 +2979,9 @@ struct HStrangeCorrelation { auto slicedAssocV0s = associatedV0s.sliceBy(collisionSliceV0s, collision2.globalIndex()); // ________________________________________________ // Do hadron - V0 correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsV0(slicedTriggerTracks, slicedAssocV0s, true, false, collision1.posX(), collision1.posY(), collision1.posZ(), cent1, bField); + } } }, colBinning); @@ -2764,10 +3017,12 @@ struct HStrangeCorrelation { if ((masterConfigurations.doPPAnalysis && (!isCollisionSelected(collision1) || !isCollisionSelected(collision2))) || (!masterConfigurations.doPPAnalysis && (!isCollisionSelectedPbPb(collision1, false) || (!isCollisionSelectedPbPb(collision2, false))))) { continue; } - if (cent1 > axisRanges[5][1] || cent1 < axisRanges[5][0]) + if (cent1 > axisRanges[5][1] || cent1 < axisRanges[5][0]) { continue; - if (cent2 > axisRanges[5][1] || cent2 < axisRanges[5][0]) + } + if (cent2 > axisRanges[5][1] || cent2 < axisRanges[5][0]) { continue; + } if (doMixingQAandEventQA) { if (collision1.globalIndex() == collision2.globalIndex()) { histos.fill(HIST("MixingQA/hMixingQA"), 0.0f); // same-collision pair counting @@ -2782,8 +3037,9 @@ struct HStrangeCorrelation { auto slicedAssocCascades = associatedCascades.sliceBy(collisionSliceCascades, collision2.globalIndex()); // ________________________________________________ // Do hadron - cascade correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsCascade(slicedTriggerTracks, slicedAssocCascades, true, false, collision1.posX(), collision1.posY(), collision1.posZ(), cent1, bField); + } } }, colBinning); @@ -2812,10 +3068,12 @@ struct HStrangeCorrelation { if (!isCollisionSelected(collision1) || !isCollisionSelected(collision2)) { continue; } - if (collision1.centFT0M() > axisRanges[5][1] || collision1.centFT0M() < axisRanges[5][0]) + if (collision1.centFT0M() > axisRanges[5][1] || collision1.centFT0M() < axisRanges[5][0]) { continue; - if (collision2.centFT0M() > axisRanges[5][1] || collision2.centFT0M() < axisRanges[5][0]) + } + if (collision2.centFT0M() > axisRanges[5][1] || collision2.centFT0M() < axisRanges[5][0]) { continue; + } if (doMixingQAandEventQA) { if (collision1.globalIndex() == collision2.globalIndex()) { histos.fill(HIST("MixingQA/hMixingQA"), 0.0f); // same-collision pair counting @@ -2830,8 +3088,9 @@ struct HStrangeCorrelation { auto slicedAssocPions = assocPions.sliceBy(collisionSliceHadrons, collision2.globalIndex()); // ________________________________________________ // Do hadron - cascade correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsHadron(slicedTriggerTracks, slicedAssocPions, true, collision1.posZ(), collision1.centFT0M(), bField); + } } } @@ -2859,8 +3118,9 @@ struct HStrangeCorrelation { } for (auto const& mcParticle : mcParticles) { - if (doAssocPhysicalPrimaryInGen && !mcParticle.isPhysicalPrimary()) + if (doAssocPhysicalPrimaryInGen && !mcParticle.isPhysicalPrimary()) { continue; + } static_for<0, 7>([&](auto i) { constexpr int Index = i.value; if (i == IndexPion && mcParticle.pdgCode() > Neutral) { @@ -2876,13 +3136,14 @@ struct HStrangeCorrelation { } }); } - if (collisions.size() < 1) + if (collisions.size() < 1) { return; + } // determine best collision properties int biggestNContribs = -1; - int bestCollisionFT0Mpercentile = -1; - int bestCollisionFT0Cpercentile = -1; + float bestCollisionFT0Mpercentile = -1; + float bestCollisionFT0Cpercentile = -1; float bestCollisionVtxZ = 0.0f; bool bestCollisionSel8 = false; bool bestCollisionINELgtZERO = false; @@ -2901,22 +3162,26 @@ struct HStrangeCorrelation { bestCollisionVtxZ = collision.posZ(); bestCollisionINELgtZERO = collision.isInelGt0(); } - if (triggerPresenceMap.size() > 0) + if (triggerPresenceMap.size() > 0) { bestCollisionTriggerPresenceMap = triggerPresenceMap[collision.globalIndex()]; + } } } if (collisions.size() > 1) { for (auto const& mcParticle : mcParticles) { - if (doAssocPhysicalPrimaryInGen && !mcParticle.isPhysicalPrimary()) + if (doAssocPhysicalPrimaryInGen && !mcParticle.isPhysicalPrimary()) { continue; - if (std::abs(mcParticle.y()) > ySel) + } + if (std::abs(mcParticle.y()) > ySel) { continue; + } static_for<0, 7>([&](auto i) { constexpr int Index = i.value; - if (mcParticle.pdgCode() == PdgCodes[i]) + if (mcParticle.pdgCode() == PdgCodes[i]) { histos.fill(HIST("GeneratedWithPV/h") + HIST(Particlenames[Index]) + HIST("_MidYVsMult_TwoPVsOrMore"), mcParticle.pt(), bestCollisionFT0Mpercentile); + } }); } } @@ -2931,15 +3196,19 @@ struct HStrangeCorrelation { return; } if (masterConfigurations.applyNewMCSelection) { - if (!isCollisionSelect) + if (!isCollisionSelect) { return; + } } else { - if (!bestCollisionSel8) + if (!bestCollisionSel8) { return; - if (std::abs(bestCollisionVtxZ) > masterConfigurations.zVertexCut) + } + if (std::abs(bestCollisionVtxZ) > masterConfigurations.zVertexCut) { return; - if (!bestCollisionINELgtZERO) + } + if (!bestCollisionINELgtZERO) { return; + } } histos.fill(HIST("hClosureTestEventCounter"), 3.5f); @@ -2975,10 +3244,11 @@ struct HStrangeCorrelation { } else { histos.fill(HIST("GeneratedWithPV/hTrigger"), gpt, geta, bestCollisionFT0Mpercentile); } - if (mcParticle.pdgCode() > 0) + if (mcParticle.pdgCode() > 0) { histos.fill(HIST("GeneratedWithPV/hPositiveTrigger"), gpt, geta, bestCollisionFT0Mpercentile); - else + } else { histos.fill(HIST("GeneratedWithPV/hNegativeTrigger"), gpt, geta, bestCollisionFT0Mpercentile); + } } if (mcParticle.pdgCode() == PDG_t::kLambda0 && !doAssocPhysicalPrimaryInGen && !mcParticle.isPhysicalPrimary()) { @@ -3036,8 +3306,9 @@ struct HStrangeCorrelation { } else { histos.fill(HIST("GeneratedWithPV/h") + HIST(Particlenames[Index]), gpt, geta, bestCollisionFT0Mpercentile); } - if (std::abs(mcParticle.y()) < ySel) + if (std::abs(mcParticle.y()) < ySel) { histos.fill(HIST("GeneratedWithPV/h") + HIST(Particlenames[Index]) + HIST("_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); + } } }); } @@ -3078,7 +3349,7 @@ struct HStrangeCorrelation { histos.fill(HIST("hClosureTestEventCounter"), 0.5f); - int bestCollisionCentpercentile = -1; + float bestCollisionCentpercentile = -1; float bestCollisionVtxZ = 0.0f; bool bestCollisionSel8 = false; bool bestCollisionINELgtZERO = false; @@ -3097,8 +3368,9 @@ struct HStrangeCorrelation { bestCollisionVtxZ = recCollision.posZ(); bestCollisionINELgtZERO = recCollision.isInelGt0(); } - if (triggerPresenceMap.size() > 0) + if (triggerPresenceMap.size() > 0) { bestCollisionTriggerPresenceMap = triggerPresenceMap[recCollision.globalIndex()]; + } } } // ________________________________________________ @@ -3106,17 +3378,22 @@ struct HStrangeCorrelation { if (triggerPresenceMap.size() > 0 && !TESTBIT(bestCollisionTriggerPresenceMap, triggerBinToSelect)) { return; } + if (masterConfigurations.applyNewMCSelection) { - if (!isCollisionSelect) + if (!isCollisionSelect) { return; + } } else { if (masterConfigurations.doGenEventSelection) { - if (!bestCollisionSel8) + if (!bestCollisionSel8) { return; - if (std::abs(bestCollisionVtxZ) > masterConfigurations.zVertexCut) + } + if (std::abs(bestCollisionVtxZ) > masterConfigurations.zVertexCut) { return; - if (!bestCollisionINELgtZERO) + } + if (!bestCollisionINELgtZERO) { return; + } if (bestCollisionCentpercentile > axisRanges[5][1] || bestCollisionCentpercentile < axisRanges[5][0]) { return; } @@ -3233,14 +3510,28 @@ struct HStrangeCorrelation { double deltaeta = getatrigger - getaassoc; // skip if basic ranges not met - if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) + if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) { continue; - if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) + } + if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) { continue; - if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) + } + if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) { continue; - if (TESTBIT(doCorrelation, i)) + } + if (TESTBIT(doCorrelation, i)) { histos.fill(HIST("ClosureTest/sameEvent/") + HIST(Particlenames[Index]), computeDeltaPhi(gphitrigger, gphiassoc), deltaeta, ptassoc, pttrigger, bestCollisionVtxZ, bestCollisionCentpercentile); + } + if (i < 3 && TESTBIT(doCorrelation, i) && masterConfigurations.doCorrelationsHadronV0daughter) { + auto assocParticleDaugters = assocParticle.daughters_as(); + for (const auto& assocParticleDaugter : assocParticleDaugters) { + if (((assocParticleDaugter.pdgCode() == PDG_t::kPiPlus || assocParticleDaugter.pdgCode() == PDG_t::kProton) && (triggerParticle.pdgCode() > 0)) || ((assocParticleDaugter.pdgCode() == PDG_t::kPiMinus || assocParticleDaugter.pdgCode() == PDG_t::kProtonBar) && (triggerParticle.pdgCode() < 0))) { + histos.fill(HIST("ClosureTest/sameEvent/") + HIST(Particlenames[Index]) + HIST("_SameSignDaughter"), computeDeltaPhi(gphitrigger, assocParticleDaugter.phi()), getatrigger - assocParticleDaugter.eta(), assocParticleDaugter.pt(), pttrigger, bestCollisionVtxZ, bestCollisionCentpercentile); + } else { + histos.fill(HIST("ClosureTest/sameEvent/") + HIST(Particlenames[Index]) + HIST("_OppSignDaughter"), computeDeltaPhi(gphitrigger, assocParticleDaugter.phi()), getatrigger - assocParticleDaugter.eta(), assocParticleDaugter.pt(), pttrigger, bestCollisionVtxZ, bestCollisionCentpercentile); + } + } + } } } }); @@ -3262,14 +3553,16 @@ struct HStrangeCorrelation { //---] track quality check [--- auto postrack = v0Data.posTrack_as(); auto negtrack = v0Data.negTrack_as(); - if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) + if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { continue; + } //---] syst cuts [--- if (v0Data.v0radius() < v0Selection.v0RadiusMin || v0Data.v0radius() > v0Selection.v0RadiusMax || std::abs(v0Data.dcapostopv()) < v0Selection.dcapostopv || std::abs(v0Data.dcanegtopv()) < v0Selection.dcanegtopv || - v0Data.v0cosPA() < v0Selection.v0cospa || v0Data.dcaV0daughters() > v0Selection.dcaV0dau) + v0Data.v0cosPA() < v0Selection.v0cospa || v0Data.dcaV0daughters() > v0Selection.dcaV0dau) { continue; + } if (v0Data.has_mcParticle()) { auto v0mcParticle = v0Data.mcParticle_as(); @@ -3349,12 +3642,14 @@ struct HStrangeCorrelation { if (((masterConfigurations.doPPAnalysis && !isCollisionSelected(collision))) || (!masterConfigurations.doPPAnalysis && !isCollisionSelectedPbPb(collision, false))) { return; } - if (cent > axisRanges[5][1] || cent < axisRanges[5][0]) + if (cent > axisRanges[5][1] || cent < axisRanges[5][0]) { return; + } // ________________________________________________ - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsV0(triggerTracks, associatedV0s, true, true, collision.posX(), collision.posY(), collision.posZ(), cent, bField); + } } void processMixedEventHCascadesInBuffer(soa::Join::iterator const& collision, aod::AssocV0s const&, aod::AssocCascades const& associatedCascades, aod::TriggerTracks const& triggerTracks, @@ -3376,12 +3671,14 @@ struct HStrangeCorrelation { if ((masterConfigurations.doPPAnalysis && !isCollisionSelected(collision)) || (!masterConfigurations.doPPAnalysis && (!isCollisionSelectedPbPb(collision, false)))) { return; } - if (cent > axisRanges[5][1] || cent < axisRanges[5][0]) + if (cent > axisRanges[5][1] || cent < axisRanges[5][0]) { return; + } // ________________________________________________ // Do hadron - cascade correlations - if (masterConfigurations.doFullCorrelationStudy) + if (masterConfigurations.doFullCorrelationStudy) { fillCorrelationsCascade(triggerTracks, associatedCascades, true, true, collision.posX(), collision.posY(), collision.posZ(), cent, bField); + } } void processPrediction(soa::Join::iterator const& mcCollision, aod::McParticles const& mcParticles) { @@ -3535,12 +3832,15 @@ struct HStrangeCorrelation { double deltaeta = getatrigger - getaassoc; // skip if basic ranges not met - if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) + if (deltaphi < axisRanges[0][0] || deltaphi > axisRanges[0][1]) { continue; - if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) + } + if (deltaeta < axisRanges[1][0] || deltaeta > axisRanges[1][1]) { continue; - if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) + } + if (ptassoc < axisRanges[2][0] || ptassoc > axisRanges[2][1]) { continue; + } if (TESTBIT(doCorrelation, i)) { if (masterConfigurations.useCentralityinPrediction) { histos.fill(HIST("Prediction/sameEvent/") + HIST(Particlenames[Index]), computeDeltaPhi(gphitrigger, gphiassoc), deltaeta, ptassoc, pttrigger, mcCollision.posZ(), centMultFT0M); @@ -3580,8 +3880,8 @@ struct HStrangeCorrelation { PROCESS_SWITCH(HStrangeCorrelation, processPrediction, "process model prediction", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(context)}; } From f8565ec976d3d621330af889a3fc37e5652ae96b Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Tue, 28 Jul 2026 07:27:19 +0200 Subject: [PATCH 10/71] [PWGLF,PWGMM] Update for the latest data model (#17221) --- PWGMM/Mult/Tasks/dndeta.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/PWGMM/Mult/Tasks/dndeta.cxx b/PWGMM/Mult/Tasks/dndeta.cxx index df1ebc63cd8..ae99e5f8205 100644 --- a/PWGMM/Mult/Tasks/dndeta.cxx +++ b/PWGMM/Mult/Tasks/dndeta.cxx @@ -842,7 +842,10 @@ struct MultiplicityCounter { using LabeledTracksEx = soa::Join; using FiLTracks = soa::Filtered; using ParticlesI = soa::Filtered>; - expressions::Filter primaries = ncheckbit(aod::mcparticle::flags, (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary); + expressions::Filter primaries = + ifnode(nsqrt(aod::mcparticle::vx * aod::mcparticle::vx + aod::mcparticle::vy * aod::mcparticle::vy) > 5.f, + false, + ncheckbit(aod::mcparticle_v2::storedFlags, (uint8_t)o2::aod::mcparticle::enums::PhysicalPrimary)); bool isChargedParticle(int code) { From d95df4062f5a659a9ec0d1f69e836ff7fd3242f0 Mon Sep 17 00:00:00 2001 From: suyoupeng <109774812+15071832337@users.noreply.github.com> Date: Tue, 28 Jul 2026 17:51:02 +0800 Subject: [PATCH 11/71] [PWGLF] Updated the Table producer and Task for uncertainty analysis (#17213) --- PWGLF/DataModel/LFSpincorrelationTables.h | 9 ++- .../Strangeness/lambdaspincorrelation.cxx | 13 +++- .../Strangeness/lambdaspincorrderived.cxx | 63 +++++++++++++------ 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/PWGLF/DataModel/LFSpincorrelationTables.h b/PWGLF/DataModel/LFSpincorrelationTables.h index 571a3413549..d4fdffd2442 100644 --- a/PWGLF/DataModel/LFSpincorrelationTables.h +++ b/PWGLF/DataModel/LFSpincorrelationTables.h @@ -52,6 +52,8 @@ DECLARE_SOA_COLUMN(ProtonEta, protonEta, float); //! Proton Et DECLARE_SOA_COLUMN(ProtonPhi, protonPhi, float); //! Proton Phi DECLARE_SOA_COLUMN(ProtonIndex, protonIndex, int); //! Proton index DECLARE_SOA_COLUMN(PionIndex, pionIndex, int); //! Pion index +DECLARE_SOA_COLUMN(DcaV0ToPV, dcaV0ToPV, float); //! DCA of V0 to primary vertex + } // namespace lambdapair DECLARE_SOA_TABLE(LambdaPairs, "AOD", "LAMBDAPAIR", o2::soa::Index<>, @@ -71,7 +73,8 @@ DECLARE_SOA_TABLE(LambdaPairs, "AOD", "LAMBDAPAIR", lambdapair::ProtonEta, lambdapair::ProtonPhi, lambdapair::ProtonIndex, - lambdapair::PionIndex); + lambdapair::PionIndex, + lambdapair::DcaV0ToPV); using LambdaPair = LambdaPairs::iterator; @@ -105,6 +108,7 @@ DECLARE_SOA_COLUMN(ProtonEtamc, protonEtamc, float); //! Proto DECLARE_SOA_COLUMN(ProtonPhimc, protonPhimc, float); //! Proton Phi in montecarlo DECLARE_SOA_COLUMN(ProtonIndexmc, protonIndexmc, int); //! Proton index in montecarlo DECLARE_SOA_COLUMN(PionIndexmc, pionIndexmc, int); //! Pion index in montecarlo +DECLARE_SOA_COLUMN(DcaV0ToPVmc, dcaV0ToPVmc, float); //! DCA of V0 to primary vertex } // namespace lambdapairmc DECLARE_SOA_TABLE(LambdaPairmcs, "AOD", "LAMBDAPAIRMC", o2::soa::Index<>, @@ -124,7 +128,8 @@ DECLARE_SOA_TABLE(LambdaPairmcs, "AOD", "LAMBDAPAIRMC", lambdapairmc::ProtonEtamc, lambdapairmc::ProtonPhimc, lambdapairmc::ProtonIndexmc, - lambdapairmc::PionIndexmc); + lambdapairmc::PionIndexmc, + lambdapairmc::DcaV0ToPVmc); using LambdaPairmc = LambdaPairmcs::iterator; diff --git a/PWGLF/TableProducer/Strangeness/lambdaspincorrelation.cxx b/PWGLF/TableProducer/Strangeness/lambdaspincorrelation.cxx index b557053295c..fcb3bf21aff 100644 --- a/PWGLF/TableProducer/Strangeness/lambdaspincorrelation.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdaspincorrelation.cxx @@ -298,6 +298,7 @@ struct lambdaspincorrelation { std::vector positiveIndex = {}; std::vector negativeIndex = {}; std::vector dcaBetweenDaughter = {}; + std::vector dcaV0ToPV = {}; int numbV0 = 0; // LOGF(info, "event collisions: (%d)", collision.index()); auto centrality = collision.centFT0C(); @@ -355,6 +356,7 @@ struct lambdaspincorrelation { positiveIndex.push_back(postrack1.globalIndex()); negativeIndex.push_back(negtrack1.globalIndex()); v0Cospa.push_back(v0.v0cosPA()); + dcaV0ToPV.push_back(std::abs(v0.dcav0topv())); v0Radius.push_back(v0.v0radius()); dcaPositive.push_back(std::abs(v0.dcapostopv())); dcaNegative.push_back(std::abs(v0.dcanegtopv())); @@ -391,7 +393,7 @@ struct lambdaspincorrelation { lambdaDummy = lambdaMother.at(i5); protonDummy = protonDaughter.at(i5); pionDummy = pionDaughter.at(i5); - lambdaPair(indexEvent, v0Status.at(i5), doubleStatus.at(i5), v0Cospa.at(i5), v0Radius.at(i5), dcaPositive.at(i5), dcaNegative.at(i5), dcaBetweenDaughter.at(i5), lambdaDummy.Pt(), lambdaDummy.Eta(), lambdaDummy.Phi(), lambdaDummy.M(), protonDummy.Pt(), protonDummy.Eta(), protonDummy.Phi(), positiveIndex.at(i5), negativeIndex.at(i5)); + lambdaPair(indexEvent, v0Status.at(i5), doubleStatus.at(i5), v0Cospa.at(i5), v0Radius.at(i5), dcaPositive.at(i5), dcaNegative.at(i5), dcaBetweenDaughter.at(i5), lambdaDummy.Pt(), lambdaDummy.Eta(), lambdaDummy.Phi(), lambdaDummy.M(), protonDummy.Pt(), protonDummy.Eta(), protonDummy.Phi(), positiveIndex.at(i5), negativeIndex.at(i5), dcaV0ToPV.at(i5)); } } } @@ -410,6 +412,7 @@ struct lambdaspincorrelation { std::vector positiveIndex = {}; std::vector negativeIndex = {}; std::vector dcaBetweenDaughter = {}; + std::vector dcaV0ToPV = {}; int numbV0 = 0; // LOGF(info, "event collisions: (%d)", collision.index()); auto centrality = collision.centFT0C(); @@ -470,6 +473,7 @@ struct lambdaspincorrelation { dcaPositive.push_back(std::abs(v0.dcapostopv())); dcaNegative.push_back(std::abs(v0.dcanegtopv())); dcaBetweenDaughter.push_back(std::abs(v0.dcaV0daughters())); + dcaV0ToPV.push_back(std::abs(v0.dcav0topv())); if (lambdaTag) { v0Status.push_back(0); proton = ROOT::Math::PxPyPzMVector(v0.pxpos(), v0.pypos(), v0.pzpos(), o2::constants::physics::MassProton); @@ -502,7 +506,7 @@ struct lambdaspincorrelation { lambdaDummy = lambdaMother.at(i5); protonDummy = protonDaughter.at(i5); pionDummy = pionDaughter.at(i5); - lambdaPairmc(indexEvent, v0Status.at(i5), doubleStatus.at(i5), v0Cospa.at(i5), v0Radius.at(i5), dcaPositive.at(i5), dcaNegative.at(i5), dcaBetweenDaughter.at(i5), lambdaDummy.Pt(), lambdaDummy.Eta(), lambdaDummy.Phi(), lambdaDummy.M(), protonDummy.Pt(), protonDummy.Eta(), protonDummy.Phi(), positiveIndex.at(i5), negativeIndex.at(i5)); + lambdaPairmc(indexEvent, v0Status.at(i5), doubleStatus.at(i5), v0Cospa.at(i5), v0Radius.at(i5), dcaPositive.at(i5), dcaNegative.at(i5), dcaBetweenDaughter.at(i5), lambdaDummy.Pt(), lambdaDummy.Eta(), lambdaDummy.Phi(), lambdaDummy.M(), protonDummy.Pt(), protonDummy.Eta(), protonDummy.Phi(), positiveIndex.at(i5), negativeIndex.at(i5), dcaV0ToPV.at(i5)); } } } @@ -530,6 +534,7 @@ struct lambdaspincorrelation { std::vector positiveIndex = {}; std::vector negativeIndex = {}; std::vector dcaBetweenDaughter = {}; + std::vector dcaV0ToPV = {}; int numbV0 = 0; auto centrality = collision.centFT0C(); @@ -610,6 +615,7 @@ struct lambdaspincorrelation { negativeIndex.push_back(negtrack1.globalIndex()); v0Cospa.push_back(v0.v0cosPA()); + dcaV0ToPV.push_back(std::abs(v0.dcav0topv())); v0Radius.push_back(v0.v0radius()); dcaPositive.push_back(std::abs(v0.dcapostopv())); dcaNegative.push_back(std::abs(v0.dcanegtopv())); @@ -695,7 +701,8 @@ struct lambdaspincorrelation { protonDummy.Eta(), protonDummy.Phi(), positiveIndex.at(i5), - negativeIndex.at(i5)); + negativeIndex.at(i5), + dcaV0ToPV.at(i5)); } } } diff --git a/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx b/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx index d923663c5ce..e3eba198d51 100644 --- a/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx +++ b/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx @@ -168,6 +168,13 @@ static inline int piIdx(const T& t) { return t.pionIndexmc(); } + +template +static inline float dcaV0ToPVMC(const T& t) +{ + return t.dcaV0ToPVmc(); +} + } // namespace mcacc // Optional fixed-leg correction pointers kept outside the task struct. @@ -261,22 +268,28 @@ struct lambdaspincorrderived { Configurable fillWeightQAHistos{"fillWeightQAHistos", false, "Fill weighted/final-weighted REP/FIX QA maps"}; Configurable fillAnalysisSparses{"fillAnalysisSparses", false, "Fill extra deltaR/deltaRap/deltaPhi Analysis THnSparse objects"}; Configurable fillAdditionalSparses{"fillAdditionalSparses", false, "Fill extra rapidity/dphi/pair-mass THnSparse objects"}; - Configurable checkDoubleStatus{"checkDoubleStatus", 0, "Check Double status"}; - Configurable cosPA{"cosPA", 0.995, "Cosine Pointing Angle"}; - Configurable radiusMin{"radiusMin", 3, "Minimum V0 radius"}; - Configurable radiusMax{"radiusMax", 30, "Maximum V0 radius"}; - Configurable dcaProton{"dcaProton", 0.1, "DCA Proton"}; - Configurable dcaPion{"dcaPion", 0.2, "DCA Pion"}; - Configurable dcaDaughters{"dcaDaughters", 1.0, "DCA between daughters"}; + Configurable ptMin{"ptMin", 0.5, "V0 Pt minimum"}; Configurable ptMax{"ptMax", 3.0, "V0 Pt maximum"}; Configurable MassMin{"MassMin", 1.09, "V0 Mass minimum"}; Configurable MassMax{"MassMax", 1.14, "V0 Mass maximum"}; - Configurable rapidity{"rapidity", 0.5, "Rapidity cut on lambda"}; Configurable v0etaMixBuffer{"v0etaMixBuffer", 0.8, "Eta cut on mix event buffer"}; + Configurable rapidity{"rapidity", 0.5, "Rapidity cut on lambda"}; Configurable v0eta{"v0eta", 0.8, "Eta cut on lambda"}; + struct : ConfigurableGroup { + std::string prefix = "v0Configuration"; + Configurable cosPA{"cosPA", 0.995, "Cosine Pointing Angle"}; + Configurable radiusMin{"radiusMin", 3, "Minimum V0 radius"}; + Configurable radiusMax{"radiusMax", 30, "Maximum V0 radius"}; + Configurable dcaProton{"dcaProton", 0.1, "DCA Proton"}; + Configurable dcaPion{"dcaPion", 0.2, "DCA Pion"}; + Configurable dcaDaughters{"dcaDaughters", 1.0, "DCA between daughters"}; + Configurable dcaV0ToPV{"dcaV0ToPV", 1.2, "DCA V0 to PV cut on lambda"}; + + } v0Configurations; + // Event Mixing Configurable cosDef{"cosDef", 1, "Defination of cos"}; @@ -573,25 +586,30 @@ struct lambdaspincorrderived { if (candidate.lambdaMass() < MassMin || candidate.lambdaMass() > MassMax) { return false; } - if (candidate.v0Cospa() < cosPA) { + if (candidate.v0Cospa() < v0Configurations.cosPA) { return false; } if (checkDoubleStatus && candidate.doubleStatus()) { return false; } - if (candidate.v0Radius() > radiusMax) { + if (candidate.v0Radius() > v0Configurations.radiusMax) { return false; } - if (candidate.v0Radius() < radiusMin) { + if (candidate.v0Radius() < v0Configurations.radiusMin) { return false; } - if (candidate.dcaBetweenDaughter() > dcaDaughters) { + if (candidate.dcaBetweenDaughter() > v0Configurations.dcaDaughters) { + return false; + } + + if (candidate.dcaV0ToPV() > v0Configurations.dcaV0ToPV) { return false; } - if (candidate.v0Status() == 0 && (std::abs(candidate.dcaPositive()) < dcaProton || std::abs(candidate.dcaNegative()) < dcaPion)) { + + if (candidate.v0Status() == 0 && (std::abs(candidate.dcaPositive()) < v0Configurations.dcaProton || std::abs(candidate.dcaNegative()) < v0Configurations.dcaPion)) { return false; } - if (candidate.v0Status() == 1 && (std::abs(candidate.dcaPositive()) < dcaPion || std::abs(candidate.dcaNegative()) < dcaProton)) { + if (candidate.v0Status() == 1 && (std::abs(candidate.dcaPositive()) < v0Configurations.dcaPion || std::abs(candidate.dcaNegative()) < v0Configurations.dcaProton)) { return false; } if (candidate.lambdaPt() < ptMin) { @@ -1836,25 +1854,30 @@ struct lambdaspincorrderived { if (mcacc::lamMass(candidate) < MassMin || mcacc::lamMass(candidate) > MassMax) { return false; } - if (mcacc::v0CosPA(candidate) < cosPA) { + if (mcacc::v0CosPA(candidate) < v0Configurations.cosPA) { return false; } if (checkDoubleStatus && mcacc::doubleStatus(candidate)) { return false; } - if (mcacc::v0Radius(candidate) > radiusMax) { + if (mcacc::v0Radius(candidate) > v0Configurations.radiusMax) { return false; } - if (mcacc::v0Radius(candidate) < radiusMin) { + if (mcacc::v0Radius(candidate) < v0Configurations.radiusMin) { return false; } - if (mcacc::dcaDau(candidate) > dcaDaughters) { + if (mcacc::dcaDau(candidate) > v0Configurations.dcaDaughters) { return false; } - if (mcacc::v0Status(candidate) == 0 && (std::abs(mcacc::dcaPos(candidate)) < dcaProton || std::abs(mcacc::dcaNeg(candidate)) < dcaPion)) { + + if (mcacc::dcaV0ToPVMC(candidate) > v0Configurations.dcaV0ToPV) { + return false; + } + + if (mcacc::v0Status(candidate) == 0 && (std::abs(mcacc::dcaPos(candidate)) < v0Configurations.dcaProton || std::abs(mcacc::dcaNeg(candidate)) < v0Configurations.dcaPion)) { return false; } - if (mcacc::v0Status(candidate) == 1 && (std::abs(mcacc::dcaPos(candidate)) < dcaPion || std::abs(mcacc::dcaNeg(candidate)) < dcaProton)) { + if (mcacc::v0Status(candidate) == 1 && (std::abs(mcacc::dcaPos(candidate)) < v0Configurations.dcaPion || std::abs(mcacc::dcaNeg(candidate)) < v0Configurations.dcaProton)) { return false; } if (mcacc::lamPt(candidate) < ptMin) { From ec2c083055e59a9a402945f437f8813f61d1494e Mon Sep 17 00:00:00 2001 From: "M. Monalisa Melo Paulino" <71565863+monamelop@users.noreply.github.com> Date: Tue, 28 Jul 2026 11:54:16 +0200 Subject: [PATCH 12/71] [PWGJE] remove unused MC jet angularity histograms (#17225) --- PWGJE/Tasks/jetDsSpecSubs.cxx | 40 ++++++++++++----------------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/PWGJE/Tasks/jetDsSpecSubs.cxx b/PWGJE/Tasks/jetDsSpecSubs.cxx index 68b90850fc2..e324f752374 100644 --- a/PWGJE/Tasks/jetDsSpecSubs.cxx +++ b/PWGJE/Tasks/jetDsSpecSubs.cxx @@ -132,7 +132,8 @@ struct JetDsSpecSubs { {"h_ds_jet_mass_data", ";m_{jet}^{ch} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{300, 0., 25.}}}}, {"h_ds_jet_lambda11_data", ";#lambda_{1}^{1};entries", {HistType::kTH1F, {{100, 0., 1.0}}}}, {"h_ds_jet_lambda12_data", ";#lambda_{2}^{1};entries", {HistType::kTH1F, {{100, 0., 1.0}}}}, - {"hSparse_ds_data", ";m_{D_{S}};#it{p}_{T,D_{S}};#it{p}_{T,jet};z^{D_{S},jet}_{||};#DeltaR_{D_{S},jet}", {HistType::kTHnSparseF, {{60, 1.7, 2.15}, {60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {20, 0., 1.0}}}}, + + {"hSparse_ds_data", ";m_{D_{S}};#it{p}_{T,D_{S}};#it{p}_{T,jet};z^{D_{S},jet}_{||};#DeltaR_{D_{S},jet}", {HistType::kTHnSparseF, {{60, 1.6, 2.3}, {60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {20, 0., 1.0}}}}, // MC general histograms {"McEffJet", "N_{jet};", {HistType::kTH1F, {{4, 0., 4.0}}}}, @@ -143,16 +144,14 @@ struct JetDsSpecSubs { {"h_jet_eta_mcd", "detector-level jet #eta;#eta_{jet}^{det};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, {"h_jet_phi_mcd", "detector-level jet #phi;#phi_{jet}^{det};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, - {"h_ds_pt_mcd", ";#it{p}_{T,D_{S} jet}^{det} (GeV/#it{c});entries", {HistType::kTH1F, {{250, 0., 100.}}}}, - {"h_ds_eta_mcd", ";#eta_{D_{S} jet}^{det};entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"h_ds_pt_mcd", ";#it{p}_{T,D_{S} jet}^{det} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 100.}}}}, + {"h_ds_eta_mcd", ";#eta_{D_{S} jet}^{det};entries", {HistType::kTH1F, {{60, -1., 1.}}}}, {"h_ds_phi_mcd", ";#phi_{D_{S} jet}^{det};entries", {HistType::kTH1F, {{80, -1., 7.}}}}, - {"h_ds_mass_mcd", ";m_{D_{S}}^{det} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{300, 1.7, 2.15}}}}, - - {"h_ds_jet_lambda11_mcd", ";#lambda_{1}^{1, det};entries", {HistType::kTH1F, {{100, 0., 1.0}}}}, - {"h_ds_jet_lambda12_mcd", ";#lambda_{2}^{1, det};entries", {HistType::kTH1F, {{100, 0., 1.0}}}}, + {"h_ds_mass_mcd", ";m_{D_{S}}^{det} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{200, 1.7, 2.15}}}}, // MCD - Sparse 1: mass, p_{T,Ds}, p_{T,jet}, z|| and prompt/non-prompt - {"hSparse_ds_mcd1", ";m_{D_{S}}^{rec};#it{p}_{T,D_{S}}^{det};#it{p}_{T,jet}^{det};z^{D_{S},jet}_{||, det};Origin(D_{S})", {HistType::kTHnSparseF, {{60, 1.7, 2.15}, {60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {2, -0.5, 1.5}}}}, + {"hSparse_ds_mcd1", ";m_{D_{S}}^{rec};#it{p}_{T,D_{S}}^{det};#it{p}_{T,jet}^{det};z^{D_{S},jet}_{||, det};Origin(D_{S})", {HistType::kTHnSparseF, {{60, 1.6, 2.3}, {60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {2, -0.5, 1.5}}}}, + // MCD - Sparse 2: p_{T,Ds}, p_{T,jet}, and DeltaR {"hSparse_ds_mcd2", ";#it{p}_{T,D_{S}}^{det};#it{p}_{T,jet}^{det};#DeltaR_{D_{S},jet}^{det}", {HistType::kTHnSparseF, {{60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.0}}}}, // MCD - Sparse 3: p_{T,jet}, z|| and DeltaR @@ -163,13 +162,10 @@ struct JetDsSpecSubs { {"h_jet_eta_mcp", "particle-level jet #eta;#eta_{jet}^{part};entries", {HistType::kTH1F, {{100, -1.0, 1.0}}}}, {"h_jet_phi_mcp", "particle-level jet #phi;#phi_{jet}^{part};entries", {HistType::kTH1F, {{80, -1.0, 7.}}}}, - {"h_ds_pt_mcp", ";#it{p}_{T,D_{S} jet}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{250, 0., 100.}}}}, - {"h_ds_eta_mcp", ";#eta_{D_{S} jet}^{part};entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"h_ds_pt_mcp", ";#it{p}_{T,D_{S} jet}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 100.}}}}, + {"h_ds_eta_mcp", ";#eta_{D_{S} jet}^{part};entries", {HistType::kTH1F, {{60, -1., 1.}}}}, {"h_ds_phi_mcp", ";#phi_{D_{S} jet}^{part};entries", {HistType::kTH1F, {{80, -1., 7.}}}}, - {"h_ds_jet_lambda11_mcp", ";#lambda_{1}^{1, part};entries", {HistType::kTH1F, {{100, 0., 1.0}}}}, - {"h_ds_jet_lambda12_mcp", ";#lambda_{2}^{1, part};entries", {HistType::kTH1F, {{100, 0., 1.0}}}}, - // MCP - Sparse: p_{T,Ds}, p_{T,jet}, z|| and DeltaR {"hSparse_ds_mcp", ";#it{p}_{T,D_{S}}^{part};#it{p}_{T,jet}^{part};z^{D_{S},jet}_{||, part};#DeltaR_{D_{S},jet}^{part}", {HistType::kTHnSparseF, {{60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {20, 0., 1.0}}}}, }}; @@ -381,8 +377,7 @@ struct JetDsSpecSubs { FilteredDsMCDJets const& mcdjets, FilteredDsMCPJets const& mcpjets, DsCandidatesMCD const& /*mcdCandidates*/, - DsCandidatesMCP const& /*mcpCandidates*/, - aod::JetTracks const& tracks) + DsCandidatesMCP const& /*mcpCandidates*/) { for (const auto& mccollision : mccollisions) { // Count all generated MC collisions @@ -434,15 +429,12 @@ struct JetDsSpecSubs { float mcd_zParallel = (mcd_jetvector * mcd_candvector) / (mcd_jetvector * mcd_jetvector); // Axis distance Delta_R float mcd_deltaR = jetutilities::deltaR(mcdjet, mcdDscand); - float mcd_lambda11 = computeLambda(mcdjet, tracks, 1.f, 1.f); - float mcd_lambda12 = computeLambda(mcdjet, tracks, 2.f, 1.f); // Detector-level Jet Histograms registry.fill(HIST("h_jet_pt_mcd"), mcdjet.pt()); registry.fill(HIST("h_jet_eta_mcd"), mcdjet.eta()); registry.fill(HIST("h_jet_phi_mcd"), mcdjet.phi()); - registry.fill(HIST("h_ds_jet_lambda11_mcd"), mcd_lambda11); - registry.fill(HIST("h_ds_jet_lambda12_mcd"), mcd_lambda12); + // Detector-level Ds Histgrams registry.fill(HIST("h_ds_pt_mcd"), mcdDscand.pt()); registry.fill(HIST("h_ds_mass_mcd"), mcdDscand.m()); @@ -487,16 +479,12 @@ struct JetDsSpecSubs { float mcp_zParallel = (mcp_jetvector * mcp_candvector) / (mcp_jetvector * mcp_jetvector); // Axis distance Delta_R float mcp_deltaR = jetutilities::deltaR(mcpjet, mcpDscand); - float mcp_lambda11 = computeLambda(mcpjet, tracks, 1.f, 1.f); - float mcp_lambda12 = computeLambda(mcpjet, tracks, 2.f, 1.f); // Particle-level Jet Histograms registry.fill(HIST("h_jet_pt_mcp"), mcpjet.pt()); registry.fill(HIST("h_jet_eta_mcp"), mcpjet.eta()); registry.fill(HIST("h_jet_phi_mcp"), mcpjet.phi()); - registry.fill(HIST("h_ds_jet_lambda11_mcp"), mcp_lambda11); - registry.fill(HIST("h_ds_jet_lambda12_mcp"), mcp_lambda12); // Particle-level Ds Histgrams registry.fill(HIST("h_ds_pt_mcp"), mcpDscand.pt()); registry.fill(HIST("h_ds_eta_mcp"), mcpDscand.eta()); @@ -520,8 +508,7 @@ struct JetDsSpecSubs { FilteredDsMCDJets const& mcdjets, FilteredDsMCPJets const& mcpjets, DsCandidatesMCD const& mcdDscand, - DsCandidatesMCP const& mcpDscand, - aod::JetTracks const& jettracks) + DsCandidatesMCP const& mcpDscand) { analyseMonteCarloEfficiency, Preslice, @@ -535,8 +522,7 @@ struct JetDsSpecSubs { mcdjets, mcpjets, mcdDscand, - mcpDscand, - jettracks); + mcpDscand); } PROCESS_SWITCH(JetDsSpecSubs, processMonteCarloEfficiencyDs, "Non-matched and matched MC Ds and jets", false); }; From 76ce3c0e5a648bf990a7a1363f531ad91e831904 Mon Sep 17 00:00:00 2001 From: Hirak Koley Date: Tue, 28 Jul 2026 16:45:34 +0530 Subject: [PATCH 13/71] [PWGLF] lambda1520analysisinpp: Implement manual calibration for centrality estimation (#17210) --- .../Resonances/lambda1520analysisinpp.cxx | 364 +++++++++++++----- 1 file changed, 268 insertions(+), 96 deletions(-) diff --git a/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx b/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx index 9ecfda3ff5e..a9ffd4f6082 100644 --- a/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx +++ b/PWGLF/Tasks/Resonances/lambda1520analysisinpp.cxx @@ -95,7 +95,7 @@ struct Lambda1520analysisinpp { HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - Service pdg; + Service pdg{}; RCTFlagsChecker rctChecker; struct : ConfigurableGroup { @@ -203,6 +203,13 @@ struct Lambda1520analysisinpp { Configurable cFill1DQAs{"cFill1DQAs", false, "Invariant mass 1D"}; Configurable centEstimator{"centEstimator", 0, "Select centrality estimator: 0 - FT0M, 1 - FT0A, 2 - FT0C"}; + // calibration + Configurable> cfgGenMultCuts{"cfgGenMultCuts", std::vector{500, 300, 200, 120, 80, 50, 30, 10, 0}, "Generated multiplicity lower cuts"}; + Configurable> cfgCentBinCentres{"cfgCentBinCentres", std::vector{2.5f, 7.5f, 15.0f, 25.0f, 35.0f, 45.0f, 55.0f, 75.0f, 95.0f}, "Reco centrality bin centres"}; + Configurable cfgGenMultEtaMax{"cfgGenMultEtaMax", 0.5f, "Max Eta for generated mid-rapidity multiplicity"}; + Configurable cfgGenMultEtaMin{"cfgGenMultEtaMin", -0.5f, "Min Eta for generated mid-rapidity multiplicity"}; + Configurable useManualCalibration{"useManualCalibration", false, "Use Manual generated multiplicity for centrality estimation"}; + TRandom* rn = new TRandom(); // Pre-filters for efficient process @@ -487,12 +494,13 @@ struct Lambda1520analysisinpp { float massKa = MassKaonCharged; float massPr = MassProton; + static constexpr float kInvalidCentrality = -999.0f; // Centralicity estimator selection template - float centEst(Coll collisions) + float centEst(const Coll& collisions) { - float returnValue = -999.0f; + float returnValue = kInvalidCentrality; switch (centEstimator) { case 0: returnValue = collisions.centFT0M(); @@ -514,68 +522,89 @@ struct Lambda1520analysisinpp { bool isSelected(const Coll& collision, bool fillHist = true) { auto applyCut = [&](bool enabled, bool condition, int bin) { - if (!enabled) + if (!enabled) { return true; - if (!condition) + } + if (!condition) { return false; - if (fillHist) + } + if (fillHist) { histos.fill(HIST("CollCutCounts"), bin); + } return true; }; - if (fillHist) + if (fillHist) { histos.fill(HIST("CollCutCounts"), 0); + } - if (!applyCut(true, std::abs(collision.posZ()) <= configEvents.cfgEvtZvtx, 1)) + if (!applyCut(true, std::abs(collision.posZ()) <= configEvents.cfgEvtZvtx, 1)) { return false; + } if (!applyCut(configEvents.cfgEvtTriggerTVXSel, - collision.selection_bit(aod::evsel::kIsTriggerTVX), 2)) + collision.selection_bit(aod::evsel::kIsTriggerTVX), 2)) { return false; + } if (!applyCut(configEvents.cfgEvtNoTFBorderCut, - collision.selection_bit(aod::evsel::kNoTimeFrameBorder), 3)) + collision.selection_bit(aod::evsel::kNoTimeFrameBorder), 3)) { return false; + } if (!applyCut(configEvents.cfgEvtNoITSROFrameBorderCut, - collision.selection_bit(aod::evsel::kNoITSROFrameBorder), 4)) + collision.selection_bit(aod::evsel::kNoITSROFrameBorder), 4)) { return false; + } - if (!applyCut(configEvents.cfgEvtIsRCTFlagpassed, rctChecker(collision), 5)) + if (!applyCut(configEvents.cfgEvtIsRCTFlagpassed, rctChecker(collision), 5)) { return false; + } - if (!applyCut(configEvents.cfgEvtSel8, collision.sel8(), 6)) + if (!applyCut(configEvents.cfgEvtSel8, collision.sel8(), 6)) { return false; + } - if (!applyCut(configEvents.cfgEvtIsINELgt0, collision.isInelGt0(), 7)) + if (!applyCut(configEvents.cfgEvtIsINELgt0, collision.isInelGt0(), 7)) { return false; + } - if (fillHist) + if (fillHist) { histos.fill(HIST("CollCutCounts"), 8); + } return true; } template - bool trackCut(const TrackType track) + bool trackCut(const TrackType& track) { // basic track cuts if (configTracks.cDCAr7SigCut && std::abs(track.dcaXY()) > (0.004f + 0.013f / (track.pt()))) // 7 - Sigma cut + { return false; - if (configTracks.cTPCNClsFound && (track.tpcNClsFound() < configTracks.cMinTPCNClsFound)) + } + if (configTracks.cTPCNClsFound && (track.tpcNClsFound() < configTracks.cMinTPCNClsFound)) { return false; - if (track.tpcNClsCrossedRows() < configTracks.cfgMinCrossedRows) + } + if (track.tpcNClsCrossedRows() < configTracks.cfgMinCrossedRows) { return false; - if (configTracks.cfgHasTOF && !track.hasTOF()) + } + if (configTracks.cfgHasTOF && !track.hasTOF()) { return false; - if (configTracks.cfgPrimaryTrack && !track.isPrimaryTrack()) + } + if (configTracks.cfgPrimaryTrack && !track.isPrimaryTrack()) { return false; - if (configTracks.cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + } + if (configTracks.cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) { return false; - if (configTracks.cfgPVContributor && !track.isPVContributor()) + } + if (configTracks.cfgPVContributor && !track.isPVContributor()) { return false; - if (configTracks.cfgGlobalTrack && !track.isGlobalTrack()) + } + if (configTracks.cfgGlobalTrack && !track.isGlobalTrack()) { return false; + } return true; } @@ -604,14 +633,17 @@ struct Lambda1520analysisinpp { // TPC PID (interval check) for (size_t i = 0; i < vProtonTPCPIDpTintv.size() - 1; ++i) { if (pt > vProtonTPCPIDpTintv[i] && pt < vProtonTPCPIDpTintv[i + 1]) { - if (std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts[i]) + if (std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts[i]) { tpcPIDPassed = true; + } } } // TOF bypass option (for QA or MC) if (configPID.cByPassTOF) { - return std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts.back(); + { + return std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts.back(); + } } // Case 1: No TOF and pt ≤ threshold → accept only via TPC PID @@ -631,8 +663,9 @@ struct Lambda1520analysisinpp { for (size_t i = 0; i < vProtonTOFPIDpTintv.size(); ++i) { if (pt < vProtonTOFPIDpTintv[i]) { if (std::abs(tofNsigmaPr) < vProtonTOFPIDcuts[i] && - std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts.back()) + std::abs(tpcNsigmaPr) < vProtonTPCPIDcuts.back()) { return true; + } } } } else if (configPID.cPIDcutType == CircularType) { @@ -642,8 +675,9 @@ struct Lambda1520analysisinpp { float combinedSigma2 = tpcNsigmaPr * tpcNsigmaPr + tofNsigmaPr * tofNsigmaPr; - if (combinedSigma2 < vProtonTPCTOFCombinedPIDcuts[i] * vProtonTPCTOFCombinedPIDcuts[i]) + if (combinedSigma2 < vProtonTPCTOFCombinedPIDcuts[i] * vProtonTPCTOFCombinedPIDcuts[i]) { return true; + } } } } @@ -731,10 +765,7 @@ struct Lambda1520analysisinpp { template bool rejectPion(const T& candidate) { - if (candidate.pt() > MinPtforPionRejection && candidate.pt() < MaxPtforPionRejection && !candidate.hasTOF() && candidate.tpcNSigmaPi() < MaxnSigmaforPionRejection) { - return false; - } - return true; + return !(candidate.pt() > MinPtforPionRejection && candidate.pt() < MaxPtforPionRejection && !candidate.hasTOF() && candidate.tpcNSigmaPi() < MaxnSigmaforPionRejection); } auto static constexpr MaxNoLambda1520Daughters = 2; @@ -767,12 +798,14 @@ struct Lambda1520analysisinpp { for (const auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks1, dTracks2))) { // Full index policy is needed to consider all possible combinations - if (trk1.index() == trk2.index()) - continue; // We need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. + if (trk1.index() == trk2.index()) { + continue; + } // We need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. // apply the track cut - if (!trackCut(trk1) || !trackCut(trk2)) + if (!trackCut(trk1) || !trackCut(trk2)) { continue; + } //// Initialize variables // Trk1: Proton @@ -798,10 +831,12 @@ struct Lambda1520analysisinpp { deltaEta = std::abs(trk1etaPr - trk2etaKa); deltaPhi = std::abs(trk1phiPr - trk2phiKa); deltaPhi = (deltaPhi > o2::constants::math::PI) ? (o2::constants::math::TwoPI - deltaPhi) : deltaPhi; - if (deltaEta >= cMaxDeltaEtaCut) + if (deltaEta >= cMaxDeltaEtaCut) { continue; - if (deltaPhi >= cMaxDeltaPhiCut) + } + if (deltaPhi >= cMaxDeltaPhiCut) { continue; + } } //// QA plots before the selection @@ -839,10 +874,13 @@ struct Lambda1520analysisinpp { //// Apply the pid selection if (crejectPion && rejectPion(trk2)) // to remove pion contamination from the kaon track + { continue; + } - if (!ptDependentPidProton(trk1) || !ptDependentPidKaon(trk2)) + if (!ptDependentPidProton(trk1) || !ptDependentPidKaon(trk2)) { continue; + } //// QA plots after the selection if constexpr (IsData) { // --- PID QA Proton @@ -896,8 +934,9 @@ struct Lambda1520analysisinpp { auto v1 = lDecayDaughter1.Vect(); auto v2 = lDecayDaughter2.Vect(); float alpha = std::acos(v1.Dot(v2) / (v1.R() * v2.R())); - if (alpha > cMinOpeningAngle && alpha < cMaxOpeningAngle) + if (alpha > cMinOpeningAngle && alpha < cMaxOpeningAngle) { continue; + } } lResonance = lDecayDaughter1 + lDecayDaughter2; @@ -908,15 +947,20 @@ struct Lambda1520analysisinpp { if constexpr (IsData || IsMix) { // Rapidity cut - if (std::abs(resonanceRapidity) > configTracks.cfgCutRapidity) + if (std::abs(resonanceRapidity) > configTracks.cfgCutRapidity) { continue; + } } if (cfgUseCutsOnMother) { if (resonancePt >= cMaxPtMotherCut) // excluding candidates in overflow + { continue; + } if (resonanceMass >= cMaxMinvMotherCut) // excluding candidates in overflow + { continue; + } } if (cFilladditionalQAeventPlots) { @@ -943,14 +987,19 @@ struct Lambda1520analysisinpp { auto resonanceRotPt = lResonanceRot.Pt(); // Rapidity cut - if (std::abs(lResonanceRot.Rapidity()) >= configTracks.cfgCutRapidity) + if (std::abs(lResonanceRot.Rapidity()) >= configTracks.cfgCutRapidity) { continue; + } if (cfgUseCutsOnMother) { if (resonanceRotPt >= cMaxPtMotherCut) // excluding candidates in overflow + { continue; + } if (resonanceRotMass >= cMaxMinvMotherCut) // excluding candidates in overflow + { continue; + } } if (trk1.sign() < 0) { if (cFill1DQAs) { @@ -1040,22 +1089,30 @@ struct Lambda1520analysisinpp { mothersPDGtrk2.pop_back(); } - if (std::abs(mctrk1.pdgCode()) != kProton || std::abs(mctrk2.pdgCode()) != kKPlus) + if (std::abs(mctrk1.pdgCode()) != kProton || std::abs(mctrk2.pdgCode()) != kKPlus) { continue; + } if (motherstrk1[0] != motherstrk2[0]) // Same mother + { continue; + } - if (std::abs(mothersPDGtrk1[0]) != Pdg::kLambda1520_Py) + if (std::abs(mothersPDGtrk1[0]) != Pdg::kLambda1520_Py) { continue; + } // LOGF(info, "mother trk1 id: %d, mother trk1: %d, trk1 id: %d, trk1 pdgcode: %d, mother trk2 id: %d, mother trk2: %d, trk2 id: %d, trk2 pdgcode: %d", motherstrk1[0], mothersPDGtrk1[0], trk1.globalIndex(), mctrk1.pdgCode(), motherstrk2[0], mothersPDGtrk2[0], trk2.globalIndex(), mctrk2.pdgCode()); if (cUseEtacutMC && std::abs(lResonance.Eta()) > cEtacutMC) // eta cut + { continue; + } if (cUseRapcutMC && std::abs(resonanceRapidity) > configTracks.cfgCutRapidity) // rapidity cut + { continue; + } histos.fill(HIST("QA/MC/h2RecoEtaPt_after"), lResonance.Eta(), resonancePt); histos.fill(HIST("QA/MC/h2RecoPhiRapidity_after"), lResonance.Phi(), resonanceRapidity); @@ -1116,11 +1173,47 @@ struct Lambda1520analysisinpp { } } + // Helper 1: Calculate generated mid-rapidity multiplicity + template + int getGenMidRapMultiplicity(McPartsT const& partsThisMc) + { + int nCh = 0; + for (auto const& part : partsThisMc) { + if (!part.isPhysicalPrimary()) { + continue; + } + if (part.eta() > cfgGenMultEtaMax || part.eta() < cfgGenMultEtaMin) { + continue; + } + auto pdgParticle = pdg->GetParticle(part.pdgCode()); + if (!pdgParticle || pdgParticle->Charge() == 0) { + continue; + } + nCh++; + } + return nCh; + } + + // Helper 2: Map multiplicity count to a specific centrality bin + float getCentClassFromGenMult(int nCh) + { + const auto& cuts = cfgGenMultCuts.value; + const auto& centres = cfgCentBinCentres.value; + for (size_t i = 0; i < cuts.size(); ++i) { + if (nCh >= cuts[i]) { + return centres[i]; + } + } + return kInvalidCentrality; // Invalid centrality + } + void processData(EventCandidates::iterator const& collision, TrackCandidates const& tracks) { if (!isSelected(collision)) // Default event selection + { return; + } auto centrality = centEst(collision); @@ -1134,10 +1227,14 @@ struct Lambda1520analysisinpp { void processRotational(EventCandidates::iterator const& collision, TrackCandidates const& tracks) { if (!isSelected(collision, false)) // Default event selection + { return; + } if (!collision.isInelGt0()) // <-- + { return; + } fillHistograms(collision, tracks, tracks); } @@ -1162,16 +1259,24 @@ struct Lambda1520analysisinpp { // } if (!isSelected(collision1, false)) // Default event selection + { continue; + } if (!isSelected(collision2, false)) // Default event selection + { continue; + } if (!collision1.isInelGt0()) // <-- + { continue; + } if (!collision2.isInelGt0()) // <-- + { continue; + } if (cFilladditionalQAeventPlots) { // Fill histograms for the characteristics of the *mixed* events (collision1 and collision2) @@ -1196,11 +1301,13 @@ struct Lambda1520analysisinpp { aod::McCollisions const&, MCTrackCandidates const& tracks, aod::McParticles const&) { - if (!collision.has_mcCollision()) + if (!collision.has_mcCollision()) { return; + } - if (!isSelected(collision)) + if (!isSelected(collision)) { return; + } auto centrality = centEst(collision); @@ -1215,11 +1322,12 @@ struct Lambda1520analysisinpp { void processMCGen(MCEventCandidates::iterator const& collision, aod::McCollisions const&, aod::McParticles const& mcParticles) { - if (!collision.has_mcCollision()) + if (!collision.has_mcCollision()) { return; + } bool isInAfterAllCuts = isSelected(collision, false); - bool inVtx10 = (std::abs(collision.mcCollision().posZ()) > configEvents.cfgEvtZvtx) ? false : true; + bool inVtx10 = std::abs(collision.mcCollision().posZ()) <= configEvents.cfgEvtZvtx; bool isTriggerTVX = collision.selection_bit(aod::evsel::kIsTriggerTVX); bool isSel8 = collision.sel8(); @@ -1247,8 +1355,9 @@ struct Lambda1520analysisinpp { bool pass2 = std::abs(daughterPDGs[0]) == kProton || std::abs(daughterPDGs[1]) == kProton; // At least one decay to Proton // Checking if we have both decay products - if (!pass1 || !pass2) + if (!pass1 || !pass2) { continue; + } // LOGF(info, "Part PDG: %d", part.pdgCode(), "DAU_ID1: %d", pass1, "DAU_ID2: %d", pass2); @@ -1256,12 +1365,15 @@ struct Lambda1520analysisinpp { histos.fill(HIST("QA/MC/h2GenPhiRapidity_beforeanycut"), part.phi(), part.y()); if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) // rapidity cut + { continue; + } if (cfgUseDaughterEtaCutMC) { for (auto const& daughters : part.daughters_as()) { - if (std::fabs(daughters.eta()) > configTracks.cfgCutEta) - continue; // eta cut for daughters + if (std::fabs(daughters.eta()) > configTracks.cfgCutEta) { + continue; + } // eta cut for daughters } // loop over daughters } @@ -1269,64 +1381,74 @@ struct Lambda1520analysisinpp { histos.fill(HIST("QA/MC/h2GenPhiRapidity_afterRapcut"), part.phi(), part.y()); if (cUseEtacutMC && std::abs(part.eta()) > cEtacutMC) // eta cut + { continue; + } histos.fill(HIST("QA/MC/h2GenEtaPt_afterEtaRapCut"), part.eta(), part.pt()); histos.fill(HIST("QA/MC/h2GenPhiRapidity_afterEtaRapCut"), part.phi(), part.y()); histos.fill(HIST("QA/Gen"), 1); if (part.pdgCode() > 0) // without any event selection + { histos.fill(HIST("Result/MC/Genlambda1520pt"), 0, part.pt(), centrality); - else + } else { histos.fill(HIST("Result/MC/Genantilambda1520pt"), 0, part.pt(), centrality); + } if (inVtx10) // vtx10 { histos.fill(HIST("QA/Gen"), 2); - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("Result/MC/Genlambda1520pt"), 1, part.pt(), centrality); - else + } else { histos.fill(HIST("Result/MC/Genantilambda1520pt"), 1, part.pt(), centrality); + } } if (inVtx10 && isSel8) // vtx10, sel8 { histos.fill(HIST("QA/Gen"), 3); - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("Result/MC/Genlambda1520pt"), 2, part.pt(), centrality); - else + } else { histos.fill(HIST("Result/MC/Genantilambda1520pt"), 2, part.pt(), centrality); + } } if (inVtx10 && isTriggerTVX) // vtx10, TriggerTVX { histos.fill(HIST("QA/Gen"), 4); - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("Result/MC/Genlambda1520pt"), 3, part.pt(), centrality); - else + } else { histos.fill(HIST("Result/MC/Genantilambda1520pt"), 3, part.pt(), centrality); + } } if (inVtx10 && isTrueINELgt0) // vtx10, INEL>0 { histos.fill(HIST("QA/Gen"), 5); - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("Result/MC/Genlambda1520pt"), 4, part.pt(), centrality); - else + } else { histos.fill(HIST("Result/MC/Genantilambda1520pt"), 4, part.pt(), centrality); + } } if (isInAfterAllCuts) // after all event selection { histos.fill(HIST("QA/Gen"), 6); - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("Result/MC/Genlambda1520pt"), 5, part.pt(), centrality); - else + } else { histos.fill(HIST("Result/MC/Genantilambda1520pt"), 5, part.pt(), centrality); + } } if (isInAfterAllCuts && isTrueINELgt0) // after all event selection && INEL>0 { histos.fill(HIST("QA/Gen"), 7); - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("Result/MC/Genlambda1520pt"), 6, part.pt(), centrality); - else + } else { histos.fill(HIST("Result/MC/Genantilambda1520pt"), 6, part.pt(), centrality); + } } } } @@ -1345,27 +1467,44 @@ struct Lambda1520analysisinpp { bool isTrueINELgt0 = pwglf::isINELgt0mc(particlesInCollision, pdg); bool isInAfterAllCuts = isSelected(collision, false); - float centrality = mcCollision.centFT0M(); + float centrality = useManualCalibration + ? getCentClassFromGenMult(getGenMidRapMultiplicity(particlesInCollision)) + : mcCollision.centFT0M(); - if (isTrueINELgt0 && isInAfterAllCuts) + if (centrality == kInvalidCentrality) { + continue; + } + + if (isTrueINELgt0 && isInAfterAllCuts) { histos.fill(HIST("Event/MultiplicityRecoEv"), centrality); + } } // Loop on generated collisions to fill the event factor for the INEL>0 correction for (const auto& mccolls : mcCollisions) { - float centrality = mccolls.centFT0M(); - bool inVtx10 = std::abs(mccolls.posZ()) <= configEvents.cfgEvtZvtx; - const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mccolls.globalIndex(), cacheMC); + + float centrality = useManualCalibration + ? getCentClassFromGenMult(getGenMidRapMultiplicity(particlesInCollision)) + : mccolls.centFT0M(); + + if (centrality == kInvalidCentrality) { + continue; + } + + bool inVtx10 = std::abs(mccolls.posZ()) <= configEvents.cfgEvtZvtx; bool isTrueINELgt0 = pwglf::isINELgt0mc(particlesInCollision, pdg); // QA for Trigger efficiency histos.fill(HIST("Event/hMCEventIndices"), centrality, Inel); - if (inVtx10) + if (inVtx10) { histos.fill(HIST("Event/hMCEventIndices"), centrality, Inel10); - if (isTrueINELgt0) + } + if (isTrueINELgt0) { histos.fill(HIST("Event/hMCEventIndices"), centrality, Inelg0); - if (inVtx10 && isTrueINELgt0) + } + if (inVtx10 && isTrueINELgt0) { histos.fill(HIST("Event/hMCEventIndices"), centrality, Inelg010); + } } } PROCESS_SWITCH(Lambda1520analysisinpp, processEventFactor, "Process Event factor", false); @@ -1384,7 +1523,13 @@ struct Lambda1520analysisinpp { bool isInAfterAllCuts = isSelected(collision, false); bool inVtx10 = std::abs(mcCollision.posZ()) <= configEvents.cfgEvtZvtx; - float centrality = mcCollision.centFT0M(); + float centrality = useManualCalibration + ? getCentClassFromGenMult(getGenMidRapMultiplicity(particlesInCollision)) + : mcCollision.centFT0M(); + + if (centrality == kInvalidCentrality) { + continue; + } auto computePtL = [&](float pt, float m_ref) { float ptL2 = pt * pt + m_ref * m_ref - MassLambda1520 * MassLambda1520; @@ -1392,22 +1537,27 @@ struct Lambda1520analysisinpp { }; // ===== NUM ===== - if (!(inVtx10 && isTrueINELgt0)) + if (!(inVtx10 && isTrueINELgt0)) { continue; + } - if (!isInAfterAllCuts) + if (!isInAfterAllCuts) { continue; + } for (const auto& part : particlesInCollision) { - if (!part.isPhysicalPrimary()) + if (!part.isPhysicalPrimary()) { continue; + } - if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) + if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) { continue; + } - if (cUseEtacutMC && std::abs(part.eta()) > cEtacutMC) + if (cUseEtacutMC && std::abs(part.eta()) > cEtacutMC) { continue; + } float pt = part.pt(); @@ -1470,15 +1620,22 @@ struct Lambda1520analysisinpp { // Loop on generated collisions to fill the event factor for the INEL>0 correction for (const auto& mccolls : mcCollisions) { - float centrality = mccolls.centFT0M(); + const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mccolls.globalIndex(), cacheMC); - bool inVtx10 = std::abs(mccolls.posZ()) <= configEvents.cfgEvtZvtx; + float centrality = useManualCalibration + ? getCentClassFromGenMult(getGenMidRapMultiplicity(particlesInCollision)) + : mccolls.centFT0M(); - const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mccolls.globalIndex(), cacheMC); + if (centrality == kInvalidCentrality) { + continue; + } + + bool inVtx10 = std::abs(mccolls.posZ()) <= configEvents.cfgEvtZvtx; bool isTrueINELgt0 = pwglf::isINELgt0mc(particlesInCollision, pdg); - if (!(inVtx10 && isTrueINELgt0)) + if (!(inVtx10 && isTrueINELgt0)) { continue; + } auto computePtL = [&](float pt, float m_ref) { float ptL2 = pt * pt + m_ref * m_ref - MassLambda1520 * MassLambda1520; @@ -1487,11 +1644,13 @@ struct Lambda1520analysisinpp { for (const auto& part : particlesInCollision) { - if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) + if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) { continue; + } - if (cUseEtacutMC && std::abs(part.eta()) > cEtacutMC) + if (cUseEtacutMC && std::abs(part.eta()) > cEtacutMC) { continue; + } // ========================= // ===== LAMBDA(1520) ====== @@ -1511,17 +1670,20 @@ struct Lambda1520analysisinpp { bool pass2 = std::abs(daughterPDGs[0]) == kProton || std::abs(daughterPDGs[1]) == kProton; // At least one decay to Proton // Checking if we have both decay products - if (!pass1 || !pass2) + if (!pass1 || !pass2) { continue; + } - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("Result/SignalLoss/GenTruelambda1520pt_den"), part.pt(), centrality); - else + } else { histos.fill(HIST("Result/SignalLoss/GenTrueantilambda1520pt_den"), part.pt(), centrality); + } } - if (!part.isPhysicalPrimary()) + if (!part.isPhysicalPrimary()) { continue; + } float pt = part.pt(); float weight = 1.f; @@ -1535,11 +1697,13 @@ struct Lambda1520analysisinpp { histos.fill(HIST("Result/SignalLoss/GenTruekaonpt_den"), pt, centrality); float ptL = computePtL(pt, massKa); - if (ptL < 0) + if (ptL < 0) { continue; + } - if (useWeight) + if (useWeight) { weight = ptL / pt; + } histos.fill(HIST("Result/SignalLoss/Genkaonpt_den"), ptL, centrality, weight); } @@ -1553,11 +1717,13 @@ struct Lambda1520analysisinpp { histos.fill(HIST("Result/SignalLoss/GenTrueprotonpt_den"), pt, centrality); float ptL = computePtL(pt, massPr); - if (ptL < 0) + if (ptL < 0) { continue; + } - if (useWeight) + if (useWeight) { weight = ptL / pt; + } histos.fill(HIST("Result/SignalLoss/Genprotonpt_den"), ptL, centrality, weight); } @@ -1570,11 +1736,13 @@ struct Lambda1520analysisinpp { histos.fill(HIST("Result/SignalLoss/GenTruelambdapt_den"), pt, centrality); float ptL = computePtL(pt, MassLambda0); - if (ptL < 0) + if (ptL < 0) { continue; + } - if (useWeight) + if (useWeight) { weight = ptL / pt; + } histos.fill(HIST("Result/SignalLoss/Genlambdapt_den"), ptL, centrality, weight); } @@ -1587,11 +1755,13 @@ struct Lambda1520analysisinpp { histos.fill(HIST("Result/SignalLoss/GenTruexipt_den"), pt, centrality); float ptL = computePtL(pt, MassXiMinus); - if (ptL < 0) + if (ptL < 0) { continue; + } - if (useWeight) + if (useWeight) { weight = ptL / pt; + } histos.fill(HIST("Result/SignalLoss/Genxipt_den"), ptL, centrality, weight); } @@ -1604,11 +1774,13 @@ struct Lambda1520analysisinpp { histos.fill(HIST("Result/SignalLoss/GenTrueomegapt_den"), pt, centrality); float ptL = computePtL(pt, MassOmegaMinus); - if (ptL < 0) + if (ptL < 0) { continue; + } - if (useWeight) + if (useWeight) { weight = ptL / pt; + } histos.fill(HIST("Result/SignalLoss/Genomegapt_den"), ptL, centrality, weight); } From e3a0518f29b38632e346935b4e0d0006ba292c79 Mon Sep 17 00:00:00 2001 From: Shiqi Wang <3326561594@qq.com> Date: Tue, 28 Jul 2026 19:30:41 +0800 Subject: [PATCH 14/71] [PWGCF] Add q2-group QA histograms to flow ESE task (#17211) Co-authored-by: Shiqi Wang --- PWGCF/Flow/Tasks/flowEseTask.cxx | 118 +++++++++++++++++++++++++------ 1 file changed, 96 insertions(+), 22 deletions(-) diff --git a/PWGCF/Flow/Tasks/flowEseTask.cxx b/PWGCF/Flow/Tasks/flowEseTask.cxx index b7c8b5cb96d..e36ad406927 100644 --- a/PWGCF/Flow/Tasks/flowEseTask.cxx +++ b/PWGCF/Flow/Tasks/flowEseTask.cxx @@ -82,7 +82,7 @@ struct FlowEseTask { "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; Configurable ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "Latest acceptable timestamp of creation for the object"}; } cfgCcdbParam; - Service ccdb; + Service ccdb{}; o2::ccdb::CcdbApi ccdbApi; Configurable cfgCentSel{"cfgCentSel", 80., "Centrality selection"}; @@ -204,7 +204,7 @@ struct FlowEseTask { int currentRunNumber = -999; int lastRunNumber = -999; - std::vector shiftprofile{}; + std::vector shiftprofile; TProfile2D* effMap = nullptr; TProfile2D* accMap = nullptr; @@ -213,23 +213,25 @@ struct FlowEseTask { template int getDetId(const T& name) { - if (name.value == "FT0C") { - return 0; - } else if (name.value == "FT0A") { + if (name.value == "FT0A") { return 1; - } else if (name.value == "FT0M") { + } + if (name.value == "FT0M") { return 2; - } else if (name.value == "FV0A") { + } + if (name.value == "FV0A") { return 3; - } else if (name.value == "TPCpos") { + } + if (name.value == "TPCpos") { return 4; - } else if (name.value == "TPCneg") { + } + if (name.value == "TPCneg") { return 5; - } else if (name.value == "TPCall") { + } + if (name.value == "TPCall") { return 6; - } else { - return 0; } + return 0; } int q2CentBin(float cent) const @@ -242,7 +244,7 @@ struct FlowEseTask { const char* q2GroupSuffix(int group) const { - static constexpr const char* Q2GroupSuffixes[] = { + static constexpr std::array Q2GroupSuffixes = { "q2p00_10", "q2p10_20", "q2p20_30", "q2p30_40", "q2p40_50", "q2p50_60", "q2p60_70", "q2p70_80", "q2p80_90", "q2p90_100"}; if (group < 0 || group >= NQ2Groups) { @@ -269,10 +271,10 @@ struct FlowEseTask { template double getQ2(TCollision const& collision) { - if (cfgMultCor) + if (cfgMultCor) { return std::sqrt(collision.qvecFT0CReVec()[0] * collision.qvecFT0CReVec()[0] + collision.qvecFT0CImVec()[0] * collision.qvecFT0CImVec()[0]) * collision.sumAmplFT0C() / std::sqrt(collision.multFT0C()); - else - return std::sqrt(collision.qvecFT0CReVec()[0] * collision.qvecFT0CReVec()[0] + collision.qvecFT0CImVec()[0] * collision.qvecFT0CImVec()[0]) * std::sqrt(collision.sumAmplFT0C()); + } + return std::sqrt(collision.qvecFT0CReVec()[0] * collision.qvecFT0CReVec()[0] + collision.qvecFT0CImVec()[0] * collision.qvecFT0CImVec()[0]) * std::sqrt(collision.sumAmplFT0C()); } void init(o2::framework::InitContext&) @@ -300,8 +302,10 @@ struct FlowEseTask { AxisSpec shiftAxis = {10, 0, 10, "shift"}; AxisSpec basisAxis = {20, 0, 20, "basis"}; + AxisSpec q2GroupAxis = {10, 0.0, 10.0, "q_{2} percentile group"}; histos.add("histQvecCent", "", {HistType::kTH2F, {q2QaAxis, centQaAxis}}); + histos.add("histEventCountQ2Group", "", {HistType::kTH2F, {centQaAxis, q2GroupAxis}}); histos.add(Form("histVertex"), "", {HistType::kTHnSparseF, {vertexAxis, vertexAxis, vertexAxis, centAxis}}); for (int iGroup = 0; iGroup < NQ2Groups; ++iGroup) { histos.add(Form("histV2_%s", q2GroupSuffix(iGroup)), "", {HistType::kTHnSparseF, {centAxis, ptAxis, cosAxis}}); @@ -434,6 +438,13 @@ struct FlowEseTask { histos.add(Form("psi%d/QA/EPRes_Det_RefA", i), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); histos.add(Form("psi%d/QA/EPRes_Det_RefB", i), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); histos.add(Form("psi%d/QA/EPRes_RefA_RefB", i), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + if (i == CorrLevel[0]) { + for (int iGroup = 0; iGroup < NQ2Groups; ++iGroup) { + histos.add(Form("psi2/QA/EPRes_Det_RefA_%s", q2GroupSuffix(iGroup)), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + histos.add(Form("psi2/QA/EPRes_Det_RefB_%s", q2GroupSuffix(iGroup)), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + histos.add(Form("psi2/QA/EPRes_RefA_RefB_%s", q2GroupSuffix(iGroup)), "", {HistType::kTH2F, {centQaAxis, cosAxis}}); + } + } histos.add(Form("psi%d/QA/EP_FT0C_shifted", i), "", {HistType::kTH2F, {centQaAxis, epQaAxis}}); histos.add(Form("psi%d/QA/EP_FT0A_shifted", i), "", {HistType::kTH2F, {centQaAxis, epQaAxis}}); histos.add(Form("psi%d/QA/EP_FV0A_shifted", i), "", {HistType::kTH2F, {centQaAxis, epQaAxis}}); @@ -490,7 +501,7 @@ struct FlowEseTask { ROOT::Math::PxPyPzMVector protonVec, pionVec, LambdaVec, protonBoostedVec, pionBoostedVec; template - bool eventSelected(TCollision collision) + bool eventSelected(TCollision const& collision) { if (!collision.sel8()) { return 0; @@ -582,14 +593,16 @@ struct FlowEseTask { double safeATan2(double y, double x) { - if (x != 0) + if (x != 0) { return std::atan2(y, x); - if (y == 0) + } + if (y == 0) { return 0; - if (y > 0) + } + if (y > 0) { return o2::constants::math::PIHalf; - else - return -o2::constants::math::PIHalf; + } + return -o2::constants::math::PIHalf; } template @@ -682,6 +695,63 @@ struct FlowEseTask { histos.fill(HIST("psi2/QA/EPRes_Det_RefA"), centrality, std::cos(std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) - std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]))); histos.fill(HIST("psi2/QA/EPRes_Det_RefB"), centrality, std::cos(std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) - std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]))); histos.fill(HIST("psi2/QA/EPRes_RefA_RefB"), centrality, std::cos(std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) - std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd]))); + const double epResDetRefA = std::cos(std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) - std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd])); + const double epResDetRefB = std::cos(std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) - std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd])); + const double epResRefARefB = std::cos(std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) - std::atan2(collision.qvecIm()[qvecRefBInd], collision.qvecRe()[qvecRefBInd])); + switch (q2Group(centrality, getQ2(collision))) { + case 0: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p00_10"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p00_10"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p00_10"), centrality, epResRefARefB); + break; + case 1: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p10_20"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p10_20"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p10_20"), centrality, epResRefARefB); + break; + case 2: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p20_30"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p20_30"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p20_30"), centrality, epResRefARefB); + break; + case 3: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p30_40"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p30_40"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p30_40"), centrality, epResRefARefB); + break; + case 4: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p40_50"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p40_50"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p40_50"), centrality, epResRefARefB); + break; + case 5: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p50_60"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p50_60"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p50_60"), centrality, epResRefARefB); + break; + case 6: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p60_70"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p60_70"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p60_70"), centrality, epResRefARefB); + break; + case 7: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p70_80"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p70_80"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p70_80"), centrality, epResRefARefB); + break; + case 8: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p80_90"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p80_90"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p80_90"), centrality, epResRefARefB); + break; + case 9: + histos.fill(HIST("psi2/QA/EPRes_Det_RefA_q2p90_100"), centrality, epResDetRefA); + histos.fill(HIST("psi2/QA/EPRes_Det_RefB_q2p90_100"), centrality, epResDetRefB); + histos.fill(HIST("psi2/QA/EPRes_RefA_RefB_q2p90_100"), centrality, epResRefARefB); + break; + default: + break; + } } else if (nmode == CorrLevel[1]) { histos.fill(HIST("psi3/QA/EP_Det"), centrality, std::atan2(collision.qvecIm()[qvecDetInd], collision.qvecRe()[qvecDetInd]) / static_cast(nmode)); histos.fill(HIST("psi3/QA/EP_RefA"), centrality, std::atan2(collision.qvecIm()[qvecRefAInd], collision.qvecRe()[qvecRefAInd]) / static_cast(nmode)); @@ -1212,6 +1282,10 @@ struct FlowEseTask { histos.fill(HIST("QA/CentDist"), centrality, 1.0); histos.fill(HIST("QA/PVzDist"), collision.posZ(), 1.0); histos.fill(HIST("histQvecCent"), getQ2(collision), centrality); + const int q2PercentileGroup = q2Group(centrality, getQ2(collision)); + if (q2PercentileGroup >= 0) { + histos.fill(HIST("histEventCountQ2Group"), centrality, q2PercentileGroup + 0.5); + } if (cfgShiftCorr) { auto bc = collision.bc_as(); From a3556ab2a82fef05d4191d0f2c86416f0629de86 Mon Sep 17 00:00:00 2001 From: "Q.Y. Xia" <91366503+huinaibing@users.noreply.github.com> Date: Tue, 28 Jul 2026 19:32:25 +0800 Subject: [PATCH 15/71] [PWGCF] Add addition axis for NUA; Add pt range for POI (#17227) --- PWGCF/Flow/Tasks/pidFlowPtCorr.cxx | 223 ++++++++++++++++++++++------- 1 file changed, 174 insertions(+), 49 deletions(-) diff --git a/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx b/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx index 0e7d84b607b..018bd326a9a 100644 --- a/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx +++ b/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx @@ -85,6 +85,12 @@ struct PidFlowPtCorr { Configurable cfgRangeEta{"cfgRangeEta", 0.4f, "Eta range for mean Pt"}; Configurable cfgCutPtMin{"cfgCutPtMin", 0.2f, "Minimal pT for ref tracks"}; Configurable cfgCutPtMax{"cfgCutPtMax", 10.0f, "Maximal pT for ref tracks"}; + Configurable cfgCutPtMinPi{"cfgCutPtMinPi", 0.2f, "Minimal pT for pion POI, used only in processData"}; + Configurable cfgCutPtMaxPi{"cfgCutPtMaxPi", 10.0f, "Maximal pT for pion POI, used only in processData"}; + Configurable cfgCutPtMinKa{"cfgCutPtMinKa", 0.2f, "Minimal pT for kaon POI, used only in processData"}; + Configurable cfgCutPtMaxKa{"cfgCutPtMaxKa", 10.0f, "Maximal pT for kaon POI, used only in processData"}; + Configurable cfgCutPtMinPr{"cfgCutPtMinPr", 0.2f, "Minimal pT for proton POI, used only in processData"}; + Configurable cfgCutPtMaxPr{"cfgCutPtMaxPr", 10.0f, "Maximal pT for proton POI, used only in processData"}; // track quality selections for daughter track Configurable cfgITSNCls{"cfgITSNCls", 5, "check minimum number of ITS clusters"}; Configurable cfgTPCNCls{"cfgTPCNCls", 50, "check minimum number of TPC hits"}; @@ -124,6 +130,8 @@ struct PidFlowPtCorr { std::string prefix = "correctionPathOpts"; Configurable> cfgAcceptancePath{"cfgAcceptancePath", (std::vector{"Users/f/fcui/NUA/NUAREFPartical", "Users/f/fcui/NUA/NUAK0s", "Users/f/fcui/NUA/NUALambda", "Users/f/fcui/NUA/NUAXi", "Users/f/fcui/NUA/NUAOmega"}), "CCDB path to acceptance object"}; + Configurable> cfgAcceptancePathWithPt{"cfgAcceptancePathWithPt", (std::vector{"Users/f/fcui/NUA/NUAREFParticalWithPt"}), "CCDB path to acceptance THnSparse(phi,eta,vz,pt) object, same content as cfgAcceptancePath but with an extra pt axis"}; + Configurable> cfgEfficiencyPath{"cfgEfficiencyPath", (std::vector{"PathtoRef"}), "CCDB path to efficiency object"}; } correctionPathOpts; @@ -145,6 +153,7 @@ struct PidFlowPtCorr { Configurable cfgOutPutMC1D{"cfgOutPutMC1D", true, "Fill MC graphs, note that if the processMCgen is open,this MUST be open"}; Configurable cfgProcessQAOutput{"cfgProcessQAOutput", false, "QA plots for processQA"}; + Configurable cfgUseNUAWithPt{"cfgUseNUAWithPt", false, "false: use original GFWWeights (phi,eta,vz) NUA; true: use THnSparse (phi,eta,vz,pt) NUA loaded from cfgAcceptancePathWithPt"}; } switchsOpts; /** @@ -274,6 +283,7 @@ struct PidFlowPtCorr { std::vector corrconfigs; std::vector cfgAcceptance; + std::vector cfgAcceptanceWithPt; std::vector cfgMultPVCutPara; std::vector cfgNSigma; @@ -324,6 +334,8 @@ struct PidFlowPtCorr { // graphs for NUE / NUA std::vector mAcceptance; std::vector mEfficiency; + // NUA with extra pt axis: THnSparse(phi, eta, vz, pt), same content as mAcceptance but pt-differential + std::vector mAcceptanceWithPt; bool correctionsLoaded = false; @@ -366,6 +378,7 @@ struct PidFlowPtCorr { ccdb->setCreatedNotAfter(cfgnolaterthan.value); cfgAcceptance = correctionPathOpts.cfgAcceptancePath.value; + cfgAcceptanceWithPt = correctionPathOpts.cfgAcceptancePathWithPt.value; cfgNSigma = cfgNSigmapid; cfgMultPVCutPara = evtSeleOpts.cfgMultPVCut; @@ -387,6 +400,10 @@ struct PidFlowPtCorr { registry.add("hPhicorrKa", "", {HistType::kTH1D, {cfgaxisPhi}}); registry.add("hPhiPr", "", {HistType::kTH1D, {cfgaxisPhi}}); registry.add("hPhicorrPr", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiCorrNUANUE", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiCorrNUANUEPi", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiCorrNUANUEKa", "", {HistType::kTH1D, {cfgaxisPhi}}); + registry.add("hPhiCorrNUANUEPr", "", {HistType::kTH1D, {cfgaxisPhi}}); registry.add("hEta", "", {HistType::kTH1D, {cfgaxisEta}}); registry.add("hVtxZ", "", {HistType::kTH1D, {cfgaxisVertex}}); registry.add("hMult", "", {HistType::kTH1D, {cfgaxisNch}}); @@ -485,10 +502,10 @@ struct PidFlowPtCorr { if (switchsOpts.cfgOutputrunbyrun.value) { // hist for NUA - registry.add("correction/hRunNumberPhiEtaVertex", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex}}); - registry.add("correction/hRunNumberPhiEtaVertexPion", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex}}); - registry.add("correction/hRunNumberPhiEtaVertexKaon", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex}}); - registry.add("correction/hRunNumberPhiEtaVertexProton", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex}}); + registry.add("correction/hRunNumberPhiEtaVertex", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex, cfgaxisPt}}); + registry.add("correction/hRunNumberPhiEtaVertexPion", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex, cfgaxisPt}}); + registry.add("correction/hRunNumberPhiEtaVertexKaon", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex, cfgaxisPt}}); + registry.add("correction/hRunNumberPhiEtaVertexProton", "", {HistType::kTHnSparseF, {cfgaxisRun, cfgaxisPhi, cfgaxisEta, cfgaxisVertex, cfgaxisPt}}); // set "correction/hRunNumberPhiEtaVertex" axis0 label for (uint64_t idx = 1; idx <= runNumbers.size(); idx++) { @@ -1432,6 +1449,33 @@ struct PidFlowPtCorr { // end load NUA + // load NUA with pt axis (THnSparse: phi, eta, vz, pt), only if cfgUseNUAWithPt is enabled + // same convention as the GFWWeights NUA above: 1 path -> charged only, 4 paths -> charged, pi, ka, pr + if (switchsOpts.cfgUseNUAWithPt.value) { + if (cfgAcceptanceWithPt.size() == static_cast(nspecies)) { + for (int i = 0; i < nspecies; i++) { + mAcceptanceWithPt.push_back(ccdb->getForTimeStamp(cfgAcceptanceWithPt[i], timestamp)); + } + if (mAcceptanceWithPt.size() == static_cast(nspecies)) { + LOGF(info, "Loaded acceptance weights with pt axis"); + } else { + LOGF(warning, "Could not load acceptance weights with pt axis"); + } + } + + if (cfgAcceptanceWithPt.size() == static_cast(totalSpecies)) { + for (int i = 0; i <= totalSpecies - 1; i++) { + mAcceptanceWithPt.push_back(ccdb->getForTimeStamp(cfgAcceptanceWithPt[i], timestamp)); + } + if (mAcceptanceWithPt.size() == static_cast(totalSpecies)) { + LOGF(info, "Loaded acceptance weights with pt axis * 4"); + } else { + LOGF(warning, "Could not load acceptance weights with pt axis * 4"); + } + } + } + // end load NUA with pt axis + /// @note dont modify load NUA!, just modify NUE // here needs to load 2 NUE graph selected from 6 ccdb path /// @note when using eff 2D, convert TH1* to (TH2D *) @@ -1466,9 +1510,34 @@ struct PidFlowPtCorr { correctionsLoaded = true; } + /** + * @brief get NUA weight from a THnSparse(phi, eta, vz, pt), same convention as GFWWeights::getNUA + * (bin content is the normalized acceptance, 0-1, so the correction weight is 1/content) + * + * @param hist THnSparse with axes (phi, eta, vz, pt), may be nullptr + */ + float getNUAFromTHn(THnSparse* hist, float phi, float eta, float vz, float pt) + { + if (!hist) { + return 1; + } + int bins[4]; + bins[0] = hist->GetAxis(0)->FindBin(phi); + bins[1] = hist->GetAxis(1)->FindBin(eta); + bins[2] = hist->GetAxis(2)->FindBin(vz); + bins[3] = hist->GetAxis(3)->FindBin(pt); + double weight = hist->GetBinContent(bins); + if (weight != 0) { + return 1. / weight; + } + return 1; + } + /** * @brief Set the Particle NUA, note that it works only when macceptance size >= 1, * macceptance size can only be 1 or 4 + * @note controlled by switchsOpts.cfgUseNUAWithPt: false uses the original GFWWeights + * (phi,eta,vz) NUA (mAcceptance); true uses the THnSparse (phi,eta,vz,pt) NUA (mAcceptanceWithPt) * * @tparam TrackObject * @param weight_nua @@ -1480,6 +1549,14 @@ struct PidFlowPtCorr { template bool setParticleNUAWeight(float& weight_nua, TrackObject& track, float vtxz) { + if (switchsOpts.cfgUseNUAWithPt.value) { + if (mAcceptanceWithPt.size() == static_cast(1) || mAcceptanceWithPt.size() == static_cast(4)) { + weight_nua = getNUAFromTHn(mAcceptanceWithPt[0], track.phi(), track.eta(), vtxz, track.pt()); + } else { + weight_nua = 1; + } + return true; + } if (mAcceptance.size() == static_cast(1) || mAcceptance.size() == static_cast(4)) { weight_nua = mAcceptance[0]->getNUA(track.phi(), track.eta(), vtxz); } else { @@ -1491,6 +1568,28 @@ struct PidFlowPtCorr { template bool setParticleNUAWeight(float& weight_nua, TrackObject& track, float vtxz, int pid) { + if (switchsOpts.cfgUseNUAWithPt.value) { + if (mAcceptanceWithPt.size() == static_cast(4)) { + switch (pid) { + case MyParticleType::kPion: + weight_nua = getNUAFromTHn(mAcceptanceWithPt[1], track.phi(), track.eta(), vtxz, track.pt()); + break; + case MyParticleType::kKaon: + weight_nua = getNUAFromTHn(mAcceptanceWithPt[2], track.phi(), track.eta(), vtxz, track.pt()); + break; + case MyParticleType::kProton: + weight_nua = getNUAFromTHn(mAcceptanceWithPt[3], track.phi(), track.eta(), vtxz, track.pt()); + break; + + default: + weight_nua = 1; + break; + } + } else { + weight_nua = 1; + } + return true; + } if (mAcceptance.size() == static_cast(4)) { switch (pid) { @@ -1618,11 +1717,13 @@ struct PidFlowPtCorr { * * @tparam TTrack * @param track + * @param checkPt if false, skip the internal ref-pt cut (cfgCutPtMin/cfgCutPtMax); needed + * so callers can apply an independent POI pt range instead (e.g. processData) * @return true pass selection * @return false reject track */ template - bool trackSelectedGlobal(TTrack& track) + bool trackSelectedGlobal(TTrack& track, bool checkPt = true) { // dca xy cut // note that z cut is in filter @@ -1631,7 +1732,7 @@ struct PidFlowPtCorr { } // pt - if (!((track.pt() > trkQualityOpts.cfgCutPtMin.value) && (track.pt() < trkQualityOpts.cfgCutPtMax.value))) { + if (checkPt && !((track.pt() > trkQualityOpts.cfgCutPtMin.value) && (track.pt() < trkQualityOpts.cfgCutPtMax.value))) { return false; } @@ -2010,7 +2111,9 @@ struct PidFlowPtCorr { float weff = 1; // track cut ITS only - if (!trackSelectedGlobal(track)) { + // note: pt cut is deferred (checked separately below per ref/POI species), + // since ref and POI (pi/ka/pr) may have independent pt ranges + if (!trackSelectedGlobal(track, false)) { continue; } if (!track.hasITS()) { @@ -2033,13 +2136,18 @@ struct PidFlowPtCorr { // end do nue // calculate ncharged(nch with weight) and pt - if (std::fabs(track.eta()) < trkQualityOpts.cfgRangeEta.value) { + bool withinPtRef = (track.pt() > trkQualityOpts.cfgCutPtMin.value) && (track.pt() < trkQualityOpts.cfgCutPtMax.value); + if (withinPtRef && std::fabs(track.eta()) < trkQualityOpts.cfgRangeEta.value) { nch += weff; nchSquare += weff * weff; ptSum += weff * track.pt(); ptSumw2 += weff * weff * track.pt(); ptSquareSum += weff * weff * track.pt() * track.pt(); + } + // end calculate nch and pt + // calculate POI (pi/ka/pr) sums, each with its own independent pt range + if (std::fabs(track.eta()) < trkQualityOpts.cfgRangeEta.value) { // ------------------------------ // Unified PID logic (configurable) // ------------------------------ @@ -2051,30 +2159,38 @@ struct PidFlowPtCorr { // Fill PID variables based on unified result if (pid == MyParticleType::kPion) { - nPionWeighted += weffPid; - nPionSquare += weffPid * weffPid; - pionPtSum += weffPid * track.pt(); - pionPtSumw2 += weffPid * weffPid * track.pt(); - pionPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); + if (track.pt() > trkQualityOpts.cfgCutPtMinPi.value && track.pt() < trkQualityOpts.cfgCutPtMaxPi.value) { + nPionWeighted += weffPid; + nPionSquare += weffPid * weffPid; + pionPtSum += weffPid * track.pt(); + pionPtSumw2 += weffPid * weffPid * track.pt(); + pionPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); + } } else if (pid == MyParticleType::kKaon) { - nKaonWeighted += weffPid; - nKaonSquare += weffPid * weffPid; - kaonPtSum += weffPid * track.pt(); - kaonPtSumw2 += weffPid * weffPid * track.pt(); - kaonPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); + if (track.pt() > trkQualityOpts.cfgCutPtMinKa.value && track.pt() < trkQualityOpts.cfgCutPtMaxKa.value) { + nKaonWeighted += weffPid; + nKaonSquare += weffPid * weffPid; + kaonPtSum += weffPid * track.pt(); + kaonPtSumw2 += weffPid * weffPid * track.pt(); + kaonPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); + } } else if (pid == MyParticleType::kProton) { - nProtonWeighted += weffPid; - nProtonSquare += weffPid * weffPid; - protonPtSum += weffPid * track.pt(); - protonPtSumw2 += weffPid * weffPid * track.pt(); - protonPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); + if (track.pt() > trkQualityOpts.cfgCutPtMinPr.value && track.pt() < trkQualityOpts.cfgCutPtMaxPr.value) { + nProtonWeighted += weffPid; + nProtonSquare += weffPid * weffPid; + protonPtSum += weffPid * track.pt(); + protonPtSumw2 += weffPid * weffPid * track.pt(); + protonPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); + } } // else: do nothing (ambiguous or not identified) } - // end calculate nch and pt + // end calculate POI sums - nchCorrectedPassed += weff; - nchPassedSelection += 1; + if (withinPtRef) { + nchCorrectedPassed += weff; + nchPassedSelection += 1; + } } // end pt calculation using ITS only @@ -2112,7 +2228,9 @@ struct PidFlowPtCorr { } // cfgDoLocDenCorr // track cut, global + ITS + TPC - if (!trackSelectedGlobal(track)) { + // note: pt cut is deferred (checked separately below per ref/POI species), + // since ref and POI (pi/ka/pr) may have independent pt ranges + if (!trackSelectedGlobal(track, false)) { continue; } if (!track.hasITS()) { @@ -2139,23 +2257,27 @@ struct PidFlowPtCorr { LOGF(info, "wacc for global track is 1, if NUA is open and this appears alot, check!"); } - // fill QA hist - registry.fill(HIST("hPhi"), track.phi()); - registry.fill(HIST("hPhicorr"), track.phi(), wacc); - registry.fill(HIST("hEta"), track.eta()); - registry.fill(HIST("hPt"), track.pt()); - registry.fill(HIST("hPtCorr"), track.pt(), weff); - // end fill QA hist + bool withinPtRefGlobal = (track.pt() > trkQualityOpts.cfgCutPtMin.value) && (track.pt() < trkQualityOpts.cfgCutPtMax.value); + if (withinPtRefGlobal) { + // fill QA hist + registry.fill(HIST("hPhi"), track.phi()); + registry.fill(HIST("hPhicorr"), track.phi(), wacc); + registry.fill(HIST("hPhiCorrNUANUE"), track.phi(), wacc * weff); + registry.fill(HIST("hEta"), track.eta()); + registry.fill(HIST("hPt"), track.pt()); + registry.fill(HIST("hPtCorr"), track.pt(), weff); + // end fill QA hist + + // pt spectra + if (switchsOpts.cfgOutPutPtSpectra.value) { + registry.fill(HIST("ptSpectra/hPtCentData"), track.pt(), cent); + } - // pt spectra - if (switchsOpts.cfgOutPutPtSpectra.value) { - registry.fill(HIST("ptSpectra/hPtCentData"), track.pt(), cent); + // fill GFW + // bit mask 1: fill CHARGED PARTICLES + fGFW->Fill(track.eta(), 0, track.phi(), wacc * weff, 1); //(eta, ptbin, phi, wacc*weff, bitmask) } - // fill GFW - // bit mask 1: fill CHARGED PARTICLES - fGFW->Fill(track.eta(), 0, track.phi(), wacc * weff, 1); //(eta, ptbin, phi, wacc*weff, bitmask) - // ------------------------------ // Unified PID logic (configurable) // ------------------------------ @@ -2166,35 +2288,38 @@ struct PidFlowPtCorr { this->setParticleNUEWeight(weffPid, track, cent, pid); // Fill GFW and counters based on unified result - if (pid == MyParticleType::kPion) { + if (pid == MyParticleType::kPion && track.pt() > trkQualityOpts.cfgCutPtMinPi.value && track.pt() < trkQualityOpts.cfgCutPtMaxPi.value) { // bitmask 18: 0010010 fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 2); fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 16, wacc * weff); registry.fill(HIST("hPhiPi"), track.phi()); registry.fill(HIST("hPhicorrPi"), track.phi(), waccPid); + registry.fill(HIST("hPhiCorrNUANUEPi"), track.phi(), waccPid * weffPid); registry.fill(HIST("hPtPi"), track.pt()); registry.fill(HIST("hPtCorrPi"), track.pt(), weffPid); numOfPi++; - } else if (pid == MyParticleType::kKaon) { + } else if (pid == MyParticleType::kKaon && track.pt() > trkQualityOpts.cfgCutPtMinKa.value && track.pt() < trkQualityOpts.cfgCutPtMaxKa.value) { // bitmask 36: 0100100 fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 4); fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 32, wacc * weff); registry.fill(HIST("hPhiKa"), track.phi()); registry.fill(HIST("hPhicorrKa"), track.phi(), waccPid); + registry.fill(HIST("hPhiCorrNUANUEKa"), track.phi(), waccPid * weffPid); registry.fill(HIST("hPtKa"), track.pt()); registry.fill(HIST("hPtCorrKa"), track.pt(), weffPid); numOfKa++; - } else if (pid == MyParticleType::kProton) { + } else if (pid == MyParticleType::kProton && track.pt() > trkQualityOpts.cfgCutPtMinPr.value && track.pt() < trkQualityOpts.cfgCutPtMaxPr.value) { // bitmask 72: 1001000 fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 8); fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 64, wacc * weff); registry.fill(HIST("hPhiPr"), track.phi()); registry.fill(HIST("hPhicorrPr"), track.phi(), waccPid); + registry.fill(HIST("hPhiCorrNUANUEPr"), track.phi(), waccPid * weffPid); registry.fill(HIST("hPtPr"), track.pt()); registry.fill(HIST("hPtCorrPr"), track.pt(), weffPid); numOfPr++; } - // else: do nothing (ambiguous or not identified) + // else: do nothing (ambiguous, not identified, or outside POI pt range) // end fill GFW } // end track loop for v2 calculation @@ -2516,20 +2641,20 @@ struct PidFlowPtCorr { // end track cut // fill the THn - registry.fill(HIST("correction/hRunNumberPhiEtaVertex"), matchedPosition, track.phi(), track.eta(), collision.posZ()); + registry.fill(HIST("correction/hRunNumberPhiEtaVertex"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); int pid = this->getPidConfigurable(track); switch (pid) { case MyParticleType::kPion: - registry.fill(HIST("correction/hRunNumberPhiEtaVertexPion"), matchedPosition, track.phi(), track.eta(), collision.posZ()); + registry.fill(HIST("correction/hRunNumberPhiEtaVertexPion"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); break; case MyParticleType::kKaon: - registry.fill(HIST("correction/hRunNumberPhiEtaVertexKaon"), matchedPosition, track.phi(), track.eta(), collision.posZ()); + registry.fill(HIST("correction/hRunNumberPhiEtaVertexKaon"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); break; case MyParticleType::kProton: - registry.fill(HIST("correction/hRunNumberPhiEtaVertexProton"), matchedPosition, track.phi(), track.eta(), collision.posZ()); + registry.fill(HIST("correction/hRunNumberPhiEtaVertexProton"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); break; default: From 72664a5e964d098000ed99572521ed93c029018b Mon Sep 17 00:00:00 2001 From: Stefanie Mrozinski <63045530+Steffimro@users.noreply.github.com> Date: Tue, 28 Jul 2026 13:46:08 +0200 Subject: [PATCH 16/71] [PWGEM] add adjustable QA settings + qinv gate for mixed pairs + fix headers (#17228) --- PWGEM/PhotonMeson/Tasks/photonhbt.cxx | 71 +++++++++++++++++++++------ 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx index f5c0536d734..425a7097ec5 100644 --- a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx +++ b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ #include #include // IWYU pragma: keep #include +#include #include #include @@ -222,6 +224,9 @@ struct Photonhbt { Configurable cfgMaxQinvForQA{"cfgMaxQinvForQA", 0.1f, "fill per-step pair QA histograms only when q_inv < this value"}; Configurable cfgMaxQinvForFullRange{"cfgMaxQinvForFullRange", 0.3f, "fill full-range histograms only when q_inv < this value"}; Configurable cfgMaxQinvForMCQA{"cfgMaxQinvForMCQA", 0.3f, "fill MC truth 1D histograms only when q_inv < this value"}; + Configurable cfgQaLevel{"cfgQaLevel", 2, "QA: 0 no QA, 1 standard, 2 full diagnostics with leg information etc."}; + Configurable cfgFillDRDZSparse{"cfgFillDRDZSparse", true, "book/fill the FullRange |R1-R2|-Deltaz-qinv sparse (large; needs cfgQaLevel>=2)"}; + Configurable cfgMaxQinvForProcessing{"cfgMaxQinvForProcessing", 0.5, "skip mixed pairs with q_inv above this before building observables"}; } qaflags; // ─── HBT analysis mode ─────────────────────────────────────────────────────────── @@ -507,9 +512,20 @@ struct Photonhbt { // INITS /*************************************************/ + bool mDoPairQa{true}, mDoSinglePhotonQa{true}, mDoLegPairQA{true}; + bool mDoPairSepQA{true}, mFillDRDZSparse{true}; + void init(InitContext& context) { isMC = context.mOptions.get("processMC"); + const int qaLevel = qaflags.cfgQaLevel.value; + mDoPairQa = qaflags.doPairQa.value && qaLevel >= 1; // o2-linter: disable=magic-number (QA set-up) + mDoSinglePhotonQa = qaflags.doSinglePhotonQa.value && qaLevel >= 1; // o2-linter: disable=magic-number (QA set-up) + mDoLegPairQA = qaflags.doLegPairQA.value && qaLevel >= 2; // o2-linter: disable=magic-number (QA set-up) + mDoPairSepQA = pairsep.cfgDoPairSepQA.value && qaLevel >= 2; // o2-linter: disable=magic-number (QA set-up) + mFillDRDZSparse = qaflags.cfgFillDRDZSparse.value && qaLevel >= 2; // o2-linter: disable=magic-number (QA set-up) + LOGF(info, "photonhbt QA level %d -> pairQA %d, singlePhotonQA %d, legPairQA %d, pairSep %d, dRdZ sparse %d", + qaLevel, mDoPairQa, mDoSinglePhotonQa, mDoLegPairQA, mDoPairSepQA, mFillDRDZSparse); mRunNumber = 0; parseBins(mixing.confVtxBins, ztxBinEdges); parseBins(mixing.confCentBins, centBinEdges); @@ -676,7 +692,7 @@ struct Photonhbt { if (isMC) { addPairMCHistograms(); - if (qaflags.doLegPairQA) { + if (mDoLegPairQA) { addLegPairMCHistograms(); } addTruthMCHistograms(); @@ -763,8 +779,10 @@ struct Photonhbt { } fRegistryPairQA.addClone("Pair/same/QA/", "Pair/mix/QA/"); - addLegPairQAForStep("Pair/same/QA/Before/"); - addLegPairQAForStep("Pair/same/QA/AfterPairCuts/"); + if (mDoLegPairQA) { + addLegPairQAForStep("Pair/same/QA/Before/"); + addLegPairQAForStep("Pair/same/QA/AfterPairCuts/"); + } } void addPairMCHistograms() @@ -1005,7 +1023,9 @@ struct Photonhbt { fRegistryCF.add((path + "hDeltaR3DVsQinv").c_str(), "#Delta r_{3D} vs q_{inv};q_{inv} (GeV/c);#Delta r_{3D} (cm)", kTH2D, {axisQinv, axisDeltaR3D}, true); fRegistryCF.add((path + "hQinvVsCent").c_str(), "q_{inv} vs centrality;centrality (%);q_{inv} (GeV/c)", kTH2D, {axisCentQA, axisQinv}, true); fRegistryCF.add((path + "hQinvVsOccupancy").c_str(), "q_{inv} vs occupancy;occupancy;q_{inv} (GeV/c)", kTH2D, {axisOccupancy, axisQinv}, true); - fRegistryCF.add((path + "hSparseDeltaRDeltaZQinv").c_str(), "|R_{1}-R_{2}|,#Delta z,q_{inv}", kTHnSparseD, {axisDeltaR, axisDeltaZ, axisQinv}, true); + if (mFillDRDZSparse) { + fRegistryCF.add((path + "hSparseDeltaRDeltaZQinv").c_str(), "|R_{1}-R_{2}|,#Delta z,q_{inv}", kTHnSparseD, {axisDeltaR, axisDeltaZ, axisQinv}, true); + } fRegistryCF.add((path + "hDeltaRCosOAVsQinv").c_str(), "#Delta r/cos(#theta_{op}/2) vs q_{inv};q_{inv} (GeV/c);#Delta r/cos(#theta_{op}/2) (cm)", kTH2D, {axisQinv, {100, 0, 100}}, true); } @@ -1266,6 +1286,19 @@ struct Photonhbt { return s; } + template + [[nodiscard]] inline bool passFastQinvGate(TG1 const& g1, TG2 const& g2) const + { + const float qMax = qaflags.cfgMaxQinvForProcessing.value; + if (qMax > 1e9f) { // o2-linter: disable=magic-number (skip if non-sensical value is chosen) + return true; + } + const float dEta = g1.eta() - g2.eta(); + const float dPhi = RecoDecay::constrainAngle(g1.phi() - g2.phi(), -o2::constants::math::PI); + const float q2 = 2.f * g1.pt() * g2.pt() * (std::cosh(dEta) - std::cos(dPhi)); + return q2 <= qMax * qMax; + } + [[nodiscard]] inline bool passLegSepCut(PairSep const& s) const { if (!pairsep.cfgDoLegSepCut.value) { @@ -1386,13 +1419,15 @@ struct Photonhbt { fRegistryCF.fill(HIST(base) + HIST("hDeltaR3DVsQinv"), obs.qinv, obs.deltaR3D); fRegistryCF.fill(HIST(base) + HIST("hQinvVsCent"), cent, obs.qinv); fRegistryCF.fill(HIST(base) + HIST("hQinvVsOccupancy"), occupancy, obs.qinv); - fRegistryCF.fill(HIST(base) + HIST("hSparseDeltaRDeltaZQinv"), obs.deltaR, obs.deltaZ, obs.qinv); + if (mFillDRDZSparse) { + fRegistryCF.fill(HIST(base) + HIST("hSparseDeltaRDeltaZQinv"), obs.deltaR, obs.deltaZ, obs.qinv); + } } template inline void fillPairSep(PairSep const& s, PairQAObservables const& obs) { - if (!pairsep.cfgDoPairSepQA.value) { + if (!mDoPairSepQA) { return; } const float limit = pairsep.cfgPairSepMaxQinv.value; @@ -1422,7 +1457,7 @@ struct Photonhbt { template inline void fillSinglePhotonQAStep(TPhoton const& g) { - if (!qaflags.doSinglePhotonQa) { + if (!mDoSinglePhotonQa) { return; } constexpr auto base = singlePhotonQAPrefix(); @@ -1519,7 +1554,7 @@ struct Photonhbt { template inline void fillPairQAStep(PairQAObservables const& o, float /*cent*/, float /*occupancy*/) { - if (!qaflags.doPairQa) { + if (!mDoPairQa) { return; } constexpr auto base = qaPrefix(); @@ -1559,7 +1594,7 @@ struct Photonhbt { template inline void fillLegPairQAStep(LegPairObservables const& lo, float kt) { - if (!qaflags.doPairQa) { + if (!mDoLegPairQA) { return; } constexpr auto base = qaPrefix<0, step_id>(); @@ -1948,7 +1983,7 @@ struct Photonhbt { auto keyDFCollision = std::make_pair(ndf, collision.globalIndex()); auto photons1Coll = photons1.sliceBy(perCollision1, collision.globalIndex()); auto photons2Coll = photons2.sliceBy(perCollision2, collision.globalIndex()); - if (qaflags.doSinglePhotonQa) { + if (mDoSinglePhotonQa) { for (const auto& g : photons1Coll) { if (cut1.template IsSelected(g)) { fillSinglePhotonQAStep<0>(g); @@ -2039,7 +2074,7 @@ struct Photonhbt { addToPool(g1, pwl1); addToPool(g2, pwl2); } - if (qaflags.doSinglePhotonQa) { + if (mDoSinglePhotonQa) { for (const auto& g : photons1Coll) { if (cut1.template IsSelected(g)) { if (idsAfterPairCuts.contains(g.globalIndex())) { @@ -2070,6 +2105,9 @@ struct Photonhbt { if (!passAsymmetryCut(g1.pt(), g2.pt())) { continue; } + if (!passFastQinvGate(g1, g2)) { + continue; + } auto obs = buildPairQAObservables(g1, g2); if (!obs.valid) { continue; @@ -2170,7 +2208,7 @@ struct Photonhbt { auto keyBin = std::make_tuple(zbin, centbin, epbin, occbin); auto keyDFCollision = std::make_pair(ndf, collision.globalIndex()); auto photonsColl = photons.sliceBy(perCollision, collision.globalIndex()); - if (qaflags.doSinglePhotonQa) { + if (mDoSinglePhotonQa) { for (const auto& g : photonsColl) { if (cut.template IsSelected(g)) { fillSinglePhotonQAStep<0>(g); @@ -2265,7 +2303,9 @@ struct Photonhbt { } else { const bool doMCQA = passQinvMCQAGate(obs.qinv); fillMCPairQA(truthType, obs, doQA, doMCQA); - fillLegPairMC(truthType, legObs, obs.kt); + if (mDoLegPairQA) { + fillLegPairMC(truthType, legObs, obs.kt); + } if (doFR) { fillMCPairQAFullRange(truthType, obs); } @@ -2318,7 +2358,7 @@ struct Photonhbt { addToPool(g1, pwl1); addToPool(g2, pwl2); } - if (qaflags.doSinglePhotonQa) { + if (mDoSinglePhotonQa) { for (const auto& g : photonsColl) { if (cut.template IsSelected(g)) { if (idsAfterPairCuts.contains(g.globalIndex())) { @@ -2349,6 +2389,9 @@ struct Photonhbt { if (!passAsymmetryCut(g1.pt(), g2.pt())) { continue; } + if (!passFastQinvGate(g1, g2)) { + continue; + } auto obs = buildPairQAObservables(g1, g2); if (!obs.valid) { continue; From 78b02eafb6056e1b4a75be9c84b891689e164e4f Mon Sep 17 00:00:00 2001 From: Gyula Bencedi Date: Tue, 28 Jul 2026 14:58:57 +0200 Subject: [PATCH 17/71] [PWGLF] Add flattenicity response (#17231) --- PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx b/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx index f1fa21206b1..e4cbd6bcd3f 100644 --- a/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx +++ b/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx @@ -75,6 +75,7 @@ #include #include #include +#include #include using std::string; @@ -784,6 +785,8 @@ struct FlattenictyPikp { // Event loss registryMC.add("Events/hNchVsFlatGenINELgt0", "Gen Nch w/o Evt sel; Gen Nch (|#eta|<0.8); flat", {kTH2F, {nChAxis, flatAxis}}); registryMC.add("Events/hNchVsFlatGenINELgt0wRecEvtSel", "Gen Nch w/ Nrec > 0 + Evt sel; Gen Nch (|#eta|<0.8); flat", {kTH2F, {nChAxis, flatAxis}}); + // Response + registryMC.add("Events/hFlatResponse", "Flattenicity response; flat ture; flat measured", {kTH2F, {flatAxis, flatAxis}}); // Event split registryMC.add("Events/hCentVsFlatRecINELgt0", "Gen evt w/o Evt sel; mult; flat", {kTH2F, {multAxis, flatAxis}}); registryMC.add("Events/hCentVsFlatRecINELgt0wRecEvt", "Gen evt w/ Nrec > 0; mult; flat", {kTH2F, {multAxis, flatAxis}}); @@ -2410,6 +2413,7 @@ struct FlattenictyPikp { registryMC.fill(HIST("Events/hCentVsFlatRecINELgt0wRecEvtSel"), multRecGt1, flatRec); // Evt split num, w/ Nrec > 0 + Evt. sel registryMC.fill(HIST("Events/hNchGenVsCent"), multMC, multRecGt1); registryMC.fill(HIST("Events/hNchVsFlatGenINELgt0wRecEvtSel"), multMC, flatMC); // Evt loss num, w/ Nrec > 0 + Evt. sel + registryMC.fill(HIST("Events/hFlatResponse"), flatMC, flatRec); // Obtain here: Denominator of tracking efficiency; Numerator event and signal loss for (const auto& particle : particles) { From 4de5503a960e0ab5202f074d13d1856cdec6f509 Mon Sep 17 00:00:00 2001 From: ariedel-cern <85537041+ariedel-cern@users.noreply.github.com> Date: Tue, 28 Jul 2026 15:15:44 +0200 Subject: [PATCH 18/71] [PWGCF] Small fixes in pair cleaner (#17234) --- PWGCF/Femto/Core/pairCleaner.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/PWGCF/Femto/Core/pairCleaner.h b/PWGCF/Femto/Core/pairCleaner.h index bb795a6332f..3bf2daf45c0 100644 --- a/PWGCF/Femto/Core/pairCleaner.h +++ b/PWGCF/Femto/Core/pairCleaner.h @@ -29,11 +29,11 @@ class BasePairCleaner virtual ~BasePairCleaner() = default; template - void init(T const& PairCuts) + void init(T const& pairCuts) { if constexpr (modes::isFlagSet(mode, modes::Mode::kMc)) { - mMixPairsWithCommonAncestor = PairCuts.mixOnlyCommonAncestor.value; - mMixPairsWithNonCommonAncestor = PairCuts.mixOnlyNonCommonAncestor.value; + mMixPairsWithCommonAncestor = pairCuts.mixOnlyCommonAncestor.value; + mMixPairsWithNonCommonAncestor = pairCuts.mixOnlyNonCommonAncestor.value; if (mMixPairsWithCommonAncestor && mMixPairsWithNonCommonAncestor) { LOG(fatal) << "Both mixing with common and non-common ancestor is activated. Breaking..."; } @@ -147,14 +147,14 @@ class V0V0PairCleaner : public BasePairCleaner // also works for particles decay public: V0V0PairCleaner() = default; template - bool isCleanPair(const T1& v01, const T2& v02, const T3& trackTable) const + bool isCleanPair(T1 const& v01, T2 const& v02, T3 const& trackTable) const { auto posDaughter1 = trackTable.rawIteratorAt(v01.posDauId() - trackTable.offset()); auto negDaughter1 = trackTable.rawIteratorAt(v01.negDauId() - trackTable.offset()); auto posDaughter2 = trackTable.rawIteratorAt(v02.posDauId() - trackTable.offset()); auto negDaughter2 = trackTable.rawIteratorAt(v02.negDauId() - trackTable.offset()); - // check all charge combinations - return this->isCleanParticlePair(posDaughter1, posDaughter2) && this->isCleanParticlePair(negDaughter1, negDaughter2) && + return this->isCleanParticlePair(v01, v02) && + this->isCleanParticlePair(posDaughter1, posDaughter2) && this->isCleanParticlePair(negDaughter1, negDaughter2) && this->isCleanParticlePair(posDaughter1, negDaughter2) && this->isCleanParticlePair(negDaughter1, posDaughter2); } @@ -181,7 +181,7 @@ class TrackV0PairCleaner : public BasePairCleaner // also works for particles de public: TrackV0PairCleaner() = default; template - bool isCleanPair(const T1& track, const T2& v0, const T3& trackTable) const + bool isCleanPair(T1 const& track, T2 const& v0, T3 const& trackTable) const { auto posDaughter = trackTable.rawIteratorAt(v0.posDauId() - trackTable.offset()); auto negDaughter = trackTable.rawIteratorAt(v0.negDauId() - trackTable.offset()); @@ -211,7 +211,7 @@ class TrackKinkPairCleaner : public BasePairCleaner public: TrackKinkPairCleaner() = default; template - bool isCleanPair(const T1& track, const T2& kink, const T3& trackTable) const + bool isCleanPair(T1 const& track, T2 const& kink, T3 const& trackTable) const { auto chaDaughter = trackTable.rawIteratorAt(kink.chaDauId() - trackTable.offset()); return this->isCleanParticlePair(chaDaughter, track); @@ -240,7 +240,7 @@ class TrackCascadePairCleaner : public BasePairCleaner public: TrackCascadePairCleaner() = default; template - bool isCleanPair(const T1& track, const T2& cascade, const T3& trackTable) const + bool isCleanPair(T1 const& track, T2 const& cascade, T3 const& trackTable) const { auto bachelor = trackTable.rawIteratorAt(cascade.bachelorId() - trackTable.offset()); auto posDaughter = trackTable.rawIteratorAt(cascade.posDauId() - trackTable.offset()); From e89b3de2731bd9acd77a3ee44509545055beadae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Tiek=C3=B6tter?= Date: Tue, 28 Jul 2026 15:50:08 +0200 Subject: [PATCH 19/71] [ALICE3] Fix JSON cut usage (#17235) --- ALICE3/Tasks/alice3-dq-efficiency.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ALICE3/Tasks/alice3-dq-efficiency.cxx b/ALICE3/Tasks/alice3-dq-efficiency.cxx index ca4c117cabe..b93d9039035 100644 --- a/ALICE3/Tasks/alice3-dq-efficiency.cxx +++ b/ALICE3/Tasks/alice3-dq-efficiency.cxx @@ -331,7 +331,7 @@ struct AnalysisTrackSelection { if (addTrackCutsStr != "") { std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); for (const auto& t : addTrackCuts) { - fTrackCuts.push_back(dynamic_cast(t)); + fTrackCuts.push_back(static_cast(t)); } } VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill @@ -1610,7 +1610,7 @@ struct AnalysisAsymmetricPairing { if (addPairCutsStr != "") { std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); for (const auto& t : addPairCuts) { - fPairCuts.push_back(dynamic_cast(t)); + fPairCuts.push_back(static_cast(t)); cutNamesStr += Form(",%s", t->GetName()); } } From 8b0b48a469556bb92d69d1c28ae718968bb0c76f Mon Sep 17 00:00:00 2001 From: Hirak Koley Date: Tue, 28 Jul 2026 19:34:28 +0530 Subject: [PATCH 20/71] [PWGLF] phi1020analysis: Change combination policy to UpperIndexPolicy (#17120) --- PWGLF/Tasks/Resonances/phi1020analysis.cxx | 185 ++++++++++++++------- 1 file changed, 126 insertions(+), 59 deletions(-) diff --git a/PWGLF/Tasks/Resonances/phi1020analysis.cxx b/PWGLF/Tasks/Resonances/phi1020analysis.cxx index c50093c91c2..9aee9ebd3e1 100644 --- a/PWGLF/Tasks/Resonances/phi1020analysis.cxx +++ b/PWGLF/Tasks/Resonances/phi1020analysis.cxx @@ -88,7 +88,7 @@ struct Phi1020analysis { HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - Service pdg; + Service pdg{}; RCTFlagsChecker rctChecker; struct : ConfigurableGroup { @@ -202,12 +202,6 @@ struct Phi1020analysis { using MCEventCandidates = soa::Join; using MCTrackCandidates = soa::Filtered>; - Partition posKaon = aod::track::signed1Pt > static_cast(0); - Partition negKaon = aod::track::signed1Pt < static_cast(0); - - Partition PosKaon_MC = aod::track::signed1Pt > static_cast(0); - Partition NegKaon_MC = aod::track::signed1Pt < static_cast(0); - /// Figures ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.12f, 0.14f, 0.16f, 0.18f, 0.2f, 0.25f, 0.3f, 0.35f, 0.4f, 0.45f, 0.5f, 0.55f, 0.6f, 0.65f, 0.7f, 0.75f, 0.8f, 0.85f, 0.9f, 0.95f, 1.0f, 1.1f, 1.2f, 1.25f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.75f, 1.8f, 1.9f, 2.0f, 2.1f, 2.2f, 2.3f, 2.4f, 2.5f, 2.6f, 2.7f, 2.8f, 2.9f, 3.0f, 3.1f, 3.2f, 3.3f, 3.4f, 3.6f, 3.7f, 3.8f, 3.9f, 4.0f, 4.1f, 4.2f, 4.5f, 4.6f, 4.8f, 4.9f, 5.0f, 5.5f, 5.6f, 6.0f, 6.4f, 6.5f, 7.0f, 7.2f, 8.0f, 9.0f, 9.5f, 9.6f, 10.0f, 11.0f, 11.5f, 12.0f, 13.0f, 14.0f, 14.4f, 15.0f, 16.0f, 18.0f, 19.2f, 20.0f}, "Binning of the pT axis"}; ConfigurableAxis binsEta{"binsEta", {150, -1.5f, 1.5f}, ""}; @@ -415,7 +409,7 @@ struct Phi1020analysis { // Centralicity estimator selection template - float centEst(Coll collisions) + float centEst(const Coll& collisions) { float returnValue = -999.0f; switch (centEstimator) { @@ -439,68 +433,89 @@ struct Phi1020analysis { bool isSelected(const Coll& collision, bool fillHist = true) { auto applyCut = [&](bool enabled, bool condition, int bin) { - if (!enabled) + if (!enabled) { return true; - if (!condition) + } + if (!condition) { return false; - if (fillHist) + } + if (fillHist) { histos.fill(HIST("CollCutCounts"), bin); + } return true; }; - if (fillHist) + if (fillHist) { histos.fill(HIST("CollCutCounts"), 0); + } - if (!applyCut(true, std::abs(collision.posZ()) <= configEvents.cfgEvtZvtx, 1)) + if (!applyCut(true, std::abs(collision.posZ()) <= configEvents.cfgEvtZvtx, 1)) { return false; + } if (!applyCut(configEvents.cfgEvtTriggerTVXSel, - collision.selection_bit(aod::evsel::kIsTriggerTVX), 2)) + collision.selection_bit(aod::evsel::kIsTriggerTVX), 2)) { return false; + } if (!applyCut(configEvents.cfgEvtNoTFBorderCut, - collision.selection_bit(aod::evsel::kNoTimeFrameBorder), 3)) + collision.selection_bit(aod::evsel::kNoTimeFrameBorder), 3)) { return false; + } if (!applyCut(configEvents.cfgEvtNoITSROFrameBorderCut, - collision.selection_bit(aod::evsel::kNoITSROFrameBorder), 4)) + collision.selection_bit(aod::evsel::kNoITSROFrameBorder), 4)) { return false; + } - if (!applyCut(configEvents.cfgEvtIsRCTFlagpassed, rctChecker(collision), 5)) + if (!applyCut(configEvents.cfgEvtIsRCTFlagpassed, rctChecker(collision), 5)) { return false; + } - if (!applyCut(configEvents.cfgEvtSel8, collision.sel8(), 6)) + if (!applyCut(configEvents.cfgEvtSel8, collision.sel8(), 6)) { return false; + } - if (!applyCut(configEvents.cfgEvtIsINELgt0, collision.isInelGt0(), 7)) + if (!applyCut(configEvents.cfgEvtIsINELgt0, collision.isInelGt0(), 7)) { return false; + } - if (fillHist) + if (fillHist) { histos.fill(HIST("CollCutCounts"), 8); + } return true; } template - bool trackCut(const TrackType track) + bool trackCut(const TrackType& track) { // basic track cuts if (configTracks.cDCAr7SigCut && std::abs(track.dcaXY()) > (0.004f + 0.013f / (track.pt()))) // 7 - Sigma cut + { return false; - if (configTracks.cTPCNClsFound && (track.tpcNClsFound() < configTracks.cMinTPCNClsFound)) + } + if (configTracks.cTPCNClsFound && (track.tpcNClsFound() < configTracks.cMinTPCNClsFound)) { return false; - if (track.tpcNClsCrossedRows() < configTracks.cfgMinCrossedRows) + } + if (track.tpcNClsCrossedRows() < configTracks.cfgMinCrossedRows) { return false; - if (configTracks.cfgHasTOF && !track.hasTOF()) + } + if (configTracks.cfgHasTOF && !track.hasTOF()) { return false; - if (configTracks.cfgPrimaryTrack && !track.isPrimaryTrack()) + } + if (configTracks.cfgPrimaryTrack && !track.isPrimaryTrack()) { return false; - if (configTracks.cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) + } + if (configTracks.cfgGlobalWoDCATrack && !track.isGlobalTrackWoDCA()) { return false; - if (configTracks.cfgPVContributor && !track.isPVContributor()) + } + if (configTracks.cfgPVContributor && !track.isPVContributor()) { return false; - if (configTracks.cfgGlobalTrack && !track.isGlobalTrack()) + } + if (configTracks.cfgGlobalTrack && !track.isGlobalTrack()) { return false; + } return true; } @@ -602,10 +617,7 @@ struct Phi1020analysis { template bool rejectPion(const T& candidate) { - if (candidate.pt() > MinPtforPionRejection && candidate.pt() < MaxPtforPionRejection && !candidate.hasTOF() && candidate.tpcNSigmaPi() < MaxnSigmaforPionRejection) { - return false; - } - return true; + return !(candidate.pt() > MinPtforPionRejection && candidate.pt() < MaxPtforPionRejection && !candidate.hasTOF() && candidate.tpcNSigmaPi() < MaxnSigmaforPionRejection); } auto static constexpr MaxNophi1020Daughters = 2; @@ -637,13 +649,18 @@ struct Phi1020analysis { LorentzVectorPtEtaPhiMass lDecayDaughter1, lDecayDaughter2, lResonance, ldaughterRot, lResonanceRot; for (const auto& [trk1, trk2] : combinations(CombinationsFullIndexPolicy(dTracks1, dTracks2))) { - // Full index policy is needed to consider all possible combinations - if (trk1.index() == trk2.index()) - continue; // We need to run (0,1), (1,0) pairs as well. but same id pairs are not needed. + LOG(info) << "Before pass, Track1 index:" << trk1.index() << ",Track2 index:" << trk2.index(); + + if (trk2.index() <= trk1.index()) { + continue; + } + + LOG(info) << "After pass, Track1 index:" << trk1.index() << ",Track2 index:" << trk2.index(); // apply the track cut - if (!trackCut(trk1) || !trackCut(trk2)) + if (!trackCut(trk1) || !trackCut(trk2)) { continue; + } //// Initialize variables // Trk1: Proton @@ -669,10 +686,12 @@ struct Phi1020analysis { deltaEta = std::abs(trk1eta - trk2eta); deltaPhi = std::abs(trk1phi - trk2phi); deltaPhi = (deltaPhi > o2::constants::math::PI) ? (o2::constants::math::TwoPI - deltaPhi) : deltaPhi; - if (deltaEta >= cMaxDeltaEtaCut) + if (deltaEta >= cMaxDeltaEtaCut) { continue; - if (deltaPhi >= cMaxDeltaPhiCut) + } + if (deltaPhi >= cMaxDeltaPhiCut) { continue; + } } //// QA plots before the selection @@ -702,13 +721,17 @@ struct Phi1020analysis { //// Apply the pid selection if (crejectPion && rejectPion(trk2)) // to remove pion contamination from the kaon track + { continue; + } - if (configPID.ispTdepPID && (!ptDependentPidKaon(trk1) || !ptDependentPidKaon(trk2))) + if (configPID.ispTdepPID && (!ptDependentPidKaon(trk1) || !ptDependentPidKaon(trk2))) { continue; + } - if (!configPID.ispTdepPID && (!selectionPID(trk1) || !selectionPID(trk2))) + if (!configPID.ispTdepPID && (!selectionPID(trk1) || !selectionPID(trk2))) { continue; + } //// QA plots after the selection if constexpr (IsData) { // --- PID QA Proton @@ -762,8 +785,9 @@ struct Phi1020analysis { auto v1 = lDecayDaughter1.Vect(); auto v2 = lDecayDaughter2.Vect(); float alpha = std::acos(v1.Dot(v2) / (v1.R() * v2.R())); - if (alpha > cMinOpeningAngle && alpha < cMaxOpeningAngle) + if (alpha > cMinOpeningAngle && alpha < cMaxOpeningAngle) { continue; + } } lResonance = lDecayDaughter1 + lDecayDaughter2; @@ -773,14 +797,19 @@ struct Phi1020analysis { auto resonanceRapidity = lResonance.Rapidity(); // Rapidity cut - if (std::abs(resonanceRapidity) > configTracks.cfgCutRapidity) + if (std::abs(resonanceRapidity) > configTracks.cfgCutRapidity) { continue; + } if (cfgUseCutsOnMother) { if (resonancePt >= cMaxPtMotherCut) // excluding candidates in overflow + { continue; + } if (resonanceMass >= cMaxMinvMotherCut) // excluding candidates in overflow + { continue; + } } if (cFilladditionalQAeventPlots) { @@ -807,14 +836,19 @@ struct Phi1020analysis { auto resonanceRotPt = lResonanceRot.Pt(); // Rapidity cut - if (std::abs(lResonanceRot.Rapidity()) >= configTracks.cfgCutRapidity) + if (std::abs(lResonanceRot.Rapidity()) >= configTracks.cfgCutRapidity) { continue; + } if (cfgUseCutsOnMother) { if (resonanceRotPt >= cMaxPtMotherCut) // excluding candidates in overflow + { continue; + } if (resonanceRotMass >= cMaxMinvMotherCut) // excluding candidates in overflow + { continue; + } } if (cFill1DQAs) { histos.fill(HIST("Result/Data/phi1020InvMassRotation"), resonanceRotMass); @@ -883,14 +917,18 @@ struct Phi1020analysis { mothersPDGtrk2.pop_back(); } - if (std::abs(mctrk1.pdgCode()) != kKPlus || std::abs(mctrk2.pdgCode()) != kKPlus) + if (std::abs(mctrk1.pdgCode()) != kKPlus || std::abs(mctrk2.pdgCode()) != kKPlus) { continue; + } if (motherstrk1[0] != motherstrk2[0]) // Same mother + { continue; + } - if (std::abs(mothersPDGtrk1[0]) != Pdg::kPhi) + if (std::abs(mothersPDGtrk1[0]) != Pdg::kPhi) { continue; + } // LOGF(info, "mother trk1 id: %d, mother trk1: %d, trk1 id: %d, trk1 pdgcode: %d, mother trk2 id: %d, mother trk2: %d, trk2 id: %d, trk2 pdgcode: %d", motherstrk1[0], mothersPDGtrk1[0], trk1.globalIndex(), mctrk1.pdgCode(), motherstrk2[0], mothersPDGtrk2[0], trk2.globalIndex(), mctrk2.pdgCode()); @@ -953,7 +991,9 @@ struct Phi1020analysis { TrackCandidates const& tracks) { if (!isSelected(collision)) // Default event selection + { return; + } auto centrality = centEst(collision); @@ -967,10 +1007,14 @@ struct Phi1020analysis { void processRotational(EventCandidates::iterator const& collision, TrackCandidates const& tracks) { if (!isSelected(collision, false)) // Default event selection + { return; + } if (!collision.isInelGt0()) // <-- + { return; + } fillHistograms(collision, tracks, tracks); } @@ -995,16 +1039,24 @@ struct Phi1020analysis { // } if (!isSelected(collision1, false)) // Default event selection + { continue; + } if (!isSelected(collision2, false)) // Default event selection + { continue; + } if (!collision1.isInelGt0()) // <-- + { continue; + } if (!collision2.isInelGt0()) // <-- + { continue; + } if (cFilladditionalQAeventPlots) { // Fill histograms for the characteristics of the *mixed* events (collision1 and collision2) @@ -1029,11 +1081,13 @@ struct Phi1020analysis { aod::McCollisions const&, MCTrackCandidates const& tracks, aod::McParticles const&) { - if (!collision.has_mcCollision()) + if (!collision.has_mcCollision()) { return; + } - if (!isSelected(collision)) + if (!isSelected(collision)) { return; + } auto centrality = centEst(collision); @@ -1048,8 +1102,9 @@ struct Phi1020analysis { void processMCGen(MCEventCandidates::iterator const& collision, aod::McCollisions const&, aod::McParticles const& mcParticles) { - if (!collision.has_mcCollision()) + if (!collision.has_mcCollision()) { return; + } bool isInAfterAllCuts = isSelected(collision, false); @@ -1083,20 +1138,24 @@ struct Phi1020analysis { histos.fill(HIST("QA/MC/h2GenPhiRapidity_beforeanycut"), part.phi(), part.y()); if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) // rapidity cut + { continue; + } if (cfgUseDaughterEtaCutMC) { for (auto const& daughters : part.daughters_as()) { - if (std::fabs(daughters.eta()) > configTracks.cfgCutEta) - continue; // eta cut for daughters + if (std::fabs(daughters.eta()) > configTracks.cfgCutEta) { + continue; + } // eta cut for daughters } // loop over daughters } histos.fill(HIST("QA/MC/h2GenEtaPt_afterRapcut"), part.eta(), part.pt()); histos.fill(HIST("QA/MC/h2GenPhiRapidity_afterRapcut"), part.phi(), part.y()); - if (isInAfterAllCuts && isTrueINELgt0) // after all event selection && INEL>0 + if (isInAfterAllCuts && isTrueINELgt0) { // after all event selection && INEL>0 histos.fill(HIST("Result/MC/Genphi1020pt"), part.pt(), centrality); + } } } PROCESS_SWITCH(Phi1020analysis, processMCGen, "Process Event for MC only", false); @@ -1116,8 +1175,9 @@ struct Phi1020analysis { float centrality = mcCollision.centFT0M(); - if (isTrueINELgt0 && isInAfterAllCuts) + if (isTrueINELgt0 && isInAfterAllCuts) { histos.fill(HIST("Event/MultiplicityRecoEv"), centrality); + } } // Loop on generated collisions to fill the event factor for the INEL>0 correction @@ -1128,8 +1188,9 @@ struct Phi1020analysis { const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mccolls.globalIndex(), cacheMC); bool isTrueINELgt0 = pwglf::isINELgt0mc(particlesInCollision, pdg); // QA for Trigger efficiency - if (inVtx10 && isTrueINELgt0) + if (inVtx10 && isTrueINELgt0) { histos.fill(HIST("Event/MultiplicityGenEv"), centrality); + } } } PROCESS_SWITCH(Phi1020analysis, processEventFactor, "Process Event factor", false); @@ -1151,22 +1212,26 @@ struct Phi1020analysis { float centrality = mcCollision.centFT0M(); // ===== NUM ===== - if (!(inVtx10 && isTrueINELgt0)) + if (!(inVtx10 && isTrueINELgt0)) { continue; + } - if (!isInAfterAllCuts) + if (!isInAfterAllCuts) { continue; + } for (const auto& part : particlesInCollision) { - if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) + if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) { continue; + } float pt = part.pt(); // phi - if (std::abs(part.pdgCode()) == Pdg::kPhi) + if (std::abs(part.pdgCode()) == Pdg::kPhi) { histos.fill(HIST("Result/SignalLoss/GenTruephi1020pt_num"), pt, centrality); + } } } @@ -1179,13 +1244,15 @@ struct Phi1020analysis { const auto& particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mccolls.globalIndex(), cacheMC); bool isTrueINELgt0 = pwglf::isINELgt0mc(particlesInCollision, pdg); - if (!(inVtx10 && isTrueINELgt0)) + if (!(inVtx10 && isTrueINELgt0)) { continue; + } for (const auto& part : particlesInCollision) { - if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) + if (cUseRapcutMC && std::abs(part.y()) > configTracks.cfgCutRapidity) { continue; + } // ========================= // ===== PHI(1020) ====== From f93e4e14ba4eea6175d371622d480b036bb5665f Mon Sep 17 00:00:00 2001 From: alicja-pp <101565842+alicja-pp@users.noreply.github.com> Date: Tue, 28 Jul 2026 16:18:12 +0200 Subject: [PATCH 21/71] [PWGCF] FemtoUniverse: Add additional cuts in V0 task (#17223) --- .../femtoUniverseProducerTask.cxx | 4 +- ...iversePairTaskTrackTrackMultKtExtended.cxx | 4 +- .../femtoUniversePairTaskTrackV0Extended.cxx | 386 ++++++++++++------ 3 files changed, 264 insertions(+), 130 deletions(-) diff --git a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx index f3f3c82f65f..4de102546a0 100644 --- a/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx +++ b/PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx @@ -1419,7 +1419,7 @@ struct FemtoUniverseProducerTask { aod::femtouniverseparticle::ParticleType::kV0Child, cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kPosCuts), confIsUseCutculator ? cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kPosPID) : pidBitmask(postrack), - 0., + postrack.dcaXY(), childIDs, 0, postrack.sign()); @@ -1439,7 +1439,7 @@ struct FemtoUniverseProducerTask { aod::femtouniverseparticle::ParticleType::kV0Child, cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegCuts), confIsUseCutculator ? cutContainerV0.at(femto_universe_v0_selection::V0ContainerPosition::kNegPID) : pidBitmask(negtrack), - 0., + negtrack.dcaXY(), childIDs, 0, negtrack.sign()); diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx index 81642eda36d..25e08090728 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx @@ -87,8 +87,8 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { } twotracksconfigs; struct : o2::framework::ConfigurableGroup { - Configurable confTrkTPCnclsMin{"confTrkTPCnclsMin", 0, "Track selection: "}; - Configurable confTrkTPCcRowsMin{"confTrkTPCcRowsMin", 0, "Track selection: "}; + Configurable confTrkTPCnclsMin{"confTrkTPCnclsMin", 0, "Min. TPC clusters"}; + Configurable confTrkTPCcRowsMin{"confTrkTPCcRowsMin", 0, "Min. TPC crossed rows"}; Configurable confDcaXYCustom1FilterCut{"confDcaXYCustom1FilterCut", 10, "Value for [1] custom DCAxy cut -> |DCAxy| < [1] + [2]/pT"}; Configurable confDcaXYCustom2FilterCut{"confDcaXYCustom2FilterCut", 0, "Value for [2] custom DCAxy cut -> |DCAxy| < [1] + [2]/pT"}; } additionalcuts; diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx index 7db9bd0aae5..ce5a0cc8934 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx @@ -25,8 +25,10 @@ #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" #include +#include #include #include #include @@ -49,7 +51,6 @@ #include #include -#include #include #include #include @@ -71,9 +72,9 @@ using namespace o2::aod::pidutils; using namespace o2::track; using namespace o2::analysis::femto_universe::efficiency_correction; -struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-type-member-init) +struct FemtoUniversePairTaskTrackV0Extended { - Service pdgMC; + Service pdgMC{}; SliceCache cache; using FemtoFullParticles = soa::Join; @@ -97,12 +98,15 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty Configurable confChargePart1{"confChargePart1", 0, "sign of particle 1"}; Configurable confHPtPart1{"confHPtPart1", 4.0f, "higher limit for pt of particle 1"}; Configurable confLPtPart1{"confLPtPart1", 0.3f, "lower limit for pt of particle 1"}; + Configurable confTrkTPCnclsMin{"confTrkTPCnclsMin", 0, "Min. TPC clusters (if stricter than in Producer)"}; + Configurable confTrkTPCcRowsMin{"confTrkTPCcRowsMin", 0, "Min. TPC crossed rows (if stricter than in Producer)"}; + Configurable confDcaXYCustom1FilterCut{"confDcaXYCustom1FilterCut", 10, "Value for [1] custom DCAxy cut -> |DCAxy| < [1] + [2]/pT (if stricter than in Producer)"}; + Configurable confDcaXYCustom2FilterCut{"confDcaXYCustom2FilterCut", 0, "Value for [2] custom DCAxy cut -> |DCAxy| < [1] + [2]/pT (if stricter than in Producer)"}; } ConfTrkSelection; Configurable confmom{"confmom", 0.5, "momentum threshold for particle identification using TOF"}; Configurable confNsigmaTPCParticle{"confNsigmaTPCParticle", 3.0, "TPC Sigma for particle momentum < confmom"}; Configurable confNsigmaTPCDaughter{"confNsigmaTPCDaughter", 3.0, "TPC Sigma for daughter"}; - Configurable confNsigmaTOFParticle{"confNsigmaTOFParticle", 3.0, "TOF Sigma for particle (daugh & bach) momentum > Confmom"}; Configurable confNsigmaCombinedParticle{"confNsigmaCombinedParticle", 3.0, "TPC and TOF Sigma (combined) for particle momentum > confmom"}; @@ -111,7 +115,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty using FilteredFDCollision = FilteredFDCollisions::iterator; /// Partition for particle 1 using extended table (track) - Partition partsOneFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == as(ConfTrkSelection.confChargePart1)) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < ConfTrkSelection.confHPtPart1) && (aod::femtouniverseparticle::pt > ConfTrkSelection.confLPtPart1); + Partition partsOneFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == as(ConfTrkSelection.confChargePart1)) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < ConfTrkSelection.confHPtPart1) && (aod::femtouniverseparticle::pt > ConfTrkSelection.confLPtPart1) && (nabs(aod::track::dcaXY) < (ConfTrkSelection.confDcaXYCustom1FilterCut + ConfTrkSelection.confDcaXYCustom2FilterCut / aod::femtouniverseparticle::pt)) && (aod::femtouniverseparticle::tpcNClsFound) > as(ConfTrkSelection.confTrkTPCnclsMin) && (aod::femtouniverseparticle::tpcNClsCrossedRows) > as(ConfTrkSelection.confTrkTPCcRowsMin); Partition partsOneMCFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < ConfTrkSelection.confHPtPart1) && (aod::femtouniverseparticle::pt > ConfTrkSelection.confLPtPart1); Partition partsOneMCRecoFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == as(ConfTrkSelection.confChargePart1)) && (nabs(aod::femtouniverseparticle::eta) < confEta) && (aod::femtouniverseparticle::pt < ConfTrkSelection.confHPtPart1) && (aod::femtouniverseparticle::pt > ConfTrkSelection.confLPtPart1); @@ -146,8 +150,20 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty Configurable confSeparateInvMassCheck{"confSeparateInvMassCheck", false, "Apply additional cut separate for mLambda and mAntiLambda"}; } ConfV0Selection; + struct : o2::framework::ConfigurableGroup { + Configurable confV0MinCosPA{"confV0MinCosPA", 0, "Min. V0 cosine of piontinh angle (if stricter than in Producer)"}; + Configurable confV0DaughMaxDCA{"confV0DaughMaxDCA", 1000, "Max. DCA of V0 daughters (if stricter than in Producer)"}; + Configurable confV0MinTransRadius{"confV0MinTransRadius", 0, "Min. transverse radius of V0 (if stricter than in Producer)"}; + Configurable confV0MaxRadius{"confV0MaxRadius", 1000, "Max. decay radius of V0 (if stricter than in Producer)"}; + Configurable confV0DaughMinPvDCAxy{"confV0DaughMinPvDCAxy", 0, "Min. DCAxy to primary vertex of V0 daughters (if stricter than in Producer)"}; // to już w córkach, nie da się dać w partycji niestety + Configurable confV0DaughMinTPCCls{"confV0DaughMinTPCCls", 0, "Min. number of TPC clusters for V0 daughters (if stricter than in Producer)"}; + } additionalcutsV0; + /// Partition for particle 2 using extended table - Partition partsTwoFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) && (aod::femtouniverseparticle::pt < ConfV0Selection.confHPtPart2) && (aod::femtouniverseparticle::pt > ConfV0Selection.confLPtPart2); + Partition + partsTwoFull = (aod::femtouniverseparticle::decayVtxX < additionalcutsV0.confV0MaxRadius && aod::femtouniverseparticle::decayVtxY < additionalcutsV0.confV0MaxRadius && aod::femtouniverseparticle::decayVtxZ < additionalcutsV0.confV0MaxRadius && + aod::femtouniverseparticle::transRadius > additionalcutsV0.confV0MinTransRadius && aod::femtouniverseparticle::daughDCA < additionalcutsV0.confV0DaughMaxDCA && aod::femtouniverseparticle::tempFitVar > additionalcutsV0.confV0MinCosPA && + aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0) && (aod::femtouniverseparticle::pt < ConfV0Selection.confHPtPart2) && (aod::femtouniverseparticle::pt > ConfV0Selection.confLPtPart2)); Partition partsTwoMCFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (aod::femtouniverseparticle::pt < ConfV0Selection.confHPtPart2) && (aod::femtouniverseparticle::pt > ConfV0Selection.confLPtPart2); Partition partsTwoMCRecoFull = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kV0)) && (aod::femtouniverseparticle::pt < ConfV0Selection.confHPtPart2) && (aod::femtouniverseparticle::pt > ConfV0Selection.confLPtPart2); @@ -213,8 +229,8 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty EffCorConfigurableGroup effCorConfGroup; EfficiencyCorrection effCorrection{&effCorConfGroup}; - static constexpr std::array, 3> V0ChildTable = {{{0, 1}, {1, 0}, {1, 1}}}; // Table to select the V0 children - static constexpr std::array v0InvMass = {1.115, 1.115, 0.497}; // Table to select invariant mass of V0s + static constexpr std::array, 3> V0ChildTable = {{{0, 1}, {1, 0}, {1, 1}}}; // Table to select the V0 children + static constexpr std::array V0InvMass = {o2::constants::physics::MassLambda0, o2::constants::physics::MassLambda0Bar, o2::constants::physics::MassK0}; // Table to select invariant mass of V0s FemtoUniverseContainer sameEventCont; FemtoUniverseContainer mixedEventCont; @@ -233,7 +249,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty std::unique_ptr plocalEffFile; std::unique_ptr pEffHistp1; std::unique_ptr pEffHistp2; - Service ccdb; + Service ccdb{}; TRandom2* randgen = 0; @@ -430,8 +446,9 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty if (!ccdbEffLoader.confLocalEfficiency.value.empty()) { plocalEffFile = std::unique_ptr(TFile::Open(ccdbEffLoader.confLocalEfficiency.value.c_str(), "read")); - if (!plocalEffFile || plocalEffFile.get()->IsZombie()) + if (!plocalEffFile || plocalEffFile.get()->IsZombie()) { LOGF(fatal, "Could not load efficiency histogram from %s", ccdbEffLoader.confLocalEfficiency.value.c_str()); + } if (doprocessSameEvent || doprocessSameEventBitmask || doprocessMixedEvent || doprocessMixedEventBitmask) { pEffHistp1 = (ConfTrkSelection.confChargePart1 > 0) ? std::unique_ptr(plocalEffFile.get()->Get("PrPlus")) : std::unique_ptr(plocalEffFile.get()->Get("PrMinus")); // note: works only for protons pEffHistp2 = (ConfV0Selection.confV0Type1 == 0) ? std::unique_ptr(plocalEffFile.get()->Get("Lambda")) : std::unique_ptr(plocalEffFile.get()->Get("AntiLambda")); @@ -461,8 +478,17 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty effCorrection.init(&qaRegistry, {static_cast(ConfV0Selection.confV0TempFitVarpTBins), {confEtaBins, -2, 2}, confMultBins}); } + template + bool checkDaughter(PartType const& posChild, PartType const& negChild) + { + if (std::abs(posChild.dcaXY()) < additionalcutsV0.confV0DaughMinPvDCAxy || std::abs(negChild.dcaXY()) < additionalcutsV0.confV0DaughMinPvDCAxy) { + return false; + } + return (posChild.tpcNClsFound() > additionalcutsV0.confV0DaughMinTPCCls && negChild.tpcNClsFound() > additionalcutsV0.confV0DaughMinTPCCls); + } + template - using hasSigma = decltype(std::declval().tpcNSigmaStorePr()); + using HasSigma = decltype(std::declval().tpcNSigmaStorePr()); /// This function processes the same event for track - V0 template @@ -473,7 +499,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - const int multCol = confUseCent ? static_cast(col.multV0M()) : static_cast(col.multNtr()); + const int multCol = confUseCent ? static_cast(col.multV0M()) : col.multNtr(); eventHisto.fillQA(col); @@ -482,8 +508,9 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty /// Histogramming same event for (const auto& part : groupPartsTwo) { - if (!invMLambda(part.mLambda(), part.mAntiLambda(), ConfV0Selection.confV0Type1)) + if (!invMLambda(part.mLambda(), part.mAntiLambda(), ConfV0Selection.confV0Type1)) { continue; + } const auto& posChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); const auto& negChild = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); @@ -492,27 +519,34 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if constexpr (std::experimental::is_detected::value) { - if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; - - if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + } + if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { + continue; + } + if (!checkDaughter(posChild, negChild)) { continue; + } trackHistoPartTwo.fillQA(part); posChildHistos.fillQA(posChild); negChildHistos.fillQA(negChild); } else { - if ((posChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } if (ConfV0Selection.confUseStrangenessTOF) { - if (((ConfV0Selection.confV0Type1 == 0) && (part.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (part.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (part.pidCut() & 48) != 48)) + if (((ConfV0Selection.confV0Type1 == 0) && (part.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (part.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (part.pidCut() & 48) != 48)) { continue; + } } else { - if ((posChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } } trackHistoPartTwo.fillQA(part); posChildHistos.fillQA(posChild); @@ -521,13 +555,14 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } for (const auto& part : groupPartsOne) { - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { /// PID plot for particle 1 const std::array tpcNSigmas = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; const std::array tofNSigmas = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; - if (!isNSigmaCombined(part.p(), tpcNSigmas[ConfTrkSelection.confTrackChoicePartOne], tofNSigmas[ConfTrkSelection.confTrackChoicePartOne], (part.pidCut() & 512u) != 0)) + if (!isNSigmaCombined(part.p(), tpcNSigmas[ConfTrkSelection.confTrackChoicePartOne], tofNSigmas[ConfTrkSelection.confTrackChoicePartOne], (part.pidCut() & 512u) != 0)) { continue; + } if (part.sign() > 0) { qaRegistry.fill(HIST("Tracks_pos/nSigmaTPC"), part.p(), tpcNSigmas[ConfTrkSelection.confTrackChoicePartOne]); qaRegistry.fill(HIST("Tracks_pos/nSigmaTOF"), part.p(), tofNSigmas[ConfTrkSelection.confTrackChoicePartOne]); @@ -538,27 +573,33 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty trackHistoPartOneNeg.fillQA(part); } } else { - if (!isNSigmaCombinedBitmask(part.p(), part)) + if (!isNSigmaCombinedBitmask(part.p(), part)) { continue; - if (ConfTrkSelection.confChargePart1 > 0) + } + if (ConfTrkSelection.confChargePart1 > 0) { trackHistoPartOnePos.fillQA(part); - if (ConfTrkSelection.confChargePart1 < 0) + } + if (ConfTrkSelection.confChargePart1 < 0) { trackHistoPartOnePos.fillQA(part); + } } } /// Now build the combinations for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { // Lambda invariant mass cut - if (!invMLambda(p2.mLambda(), p2.mAntiLambda(), ConfV0Selection.confV0Type1)) + if (!invMLambda(p2.mLambda(), p2.mAntiLambda(), ConfV0Selection.confV0Type1)) { continue; + } /// PID using stored binned nsigma - if constexpr (std::experimental::is_detected::value) { - if (!isParticleCombined(p1, ConfTrkSelection.confTrackChoicePartOne)) + if constexpr (std::experimental::is_detected::value) { + if (!isParticleCombined(p1, ConfTrkSelection.confTrackChoicePartOne)) { continue; + } } else { - if (!isNSigmaCombinedBitmask(p1.p(), p1)) + if (!isNSigmaCombinedBitmask(p1.p(), p1)) { continue; + } } // track cleaning if (!pairCleaner.isCleanPair(p1, p2, parts)) { @@ -572,23 +613,32 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if constexpr (std::experimental::is_detected::value) { - if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { + continue; + } + + if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; + } - if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if (!checkDaughter(posChild, negChild)) { continue; + } } else { - if ((posChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } if (ConfV0Selection.confUseStrangenessTOF) { - if (((ConfV0Selection.confV0Type1 == 0) && (p2.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (p2.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (p2.pidCut() & 48) != 48)) + if (((ConfV0Selection.confV0Type1 == 0) && (p2.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (p2.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (p2.pidCut() & 48) != 48)) { continue; + } } else { - if ((posChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } } } @@ -599,12 +649,14 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } float weight = 1.0f; - if (pEffHistp1) + if (pEffHistp1) { weight = pEffHistp1.get()->GetBinContent(pEffHistp1->FindBin(p1.pt(), p1.eta())) * pEffHistp2.get()->GetBinContent(pEffHistp2->FindBin(p2.pt(), p2.eta())); - if constexpr (std::is_same::value) + } + if constexpr (std::is_same::value) { sameEventCont.setPair(p1, p2, multCol, confUse3D, weight); - else + } else { sameEventCont.setPair(p1, p2, multCol, confUse3D, weight); + } } } /// This function processes the same event for V0 - V0 @@ -613,7 +665,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty { const auto& magFieldTesla = col.magField(); - const int multCol = confUseCent ? static_cast(col.multV0M()) : static_cast(col.multNtr()); + const int multCol = confUseCent ? static_cast(col.multV0M()) : col.multNtr(); eventHisto.fillQA(col); @@ -632,13 +684,16 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Check daughters of first V0 particle - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; } if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; } + if (!checkDaughter(posChild, negChild)) { + continue; + } trackHistoV0Type1.fillQABase(part, HIST("V0Type1")); posChildV0Type1.fillQABase(posChild, HIST("posChildV0Type1")); @@ -679,13 +734,16 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Check daughters of second V0 particle - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type2][1])) { continue; } if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type2][1])) { continue; } + if (!checkDaughter(posChild, negChild)) { + continue; + } trackHistoV0Type2.fillQABase(part, HIST("V0Type2")); posChildV0Type2.fillQABase(posChild, HIST("posChildV0Type2")); @@ -728,7 +786,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty if (!pairCleanerV0.isCleanPair(p1, p2, parts)) { // mark for rejection the v0 that shares a daughter with another v0 and has an invariant mass further from default value. Set confV0DuplCosPA as TRUE to do the same check with cosPA instead. if (!ConfV0Selection.confV0DuplCosPA) { - if (std::abs(p1.mLambda() - v0InvMass[ConfV0Selection.confV0Type1]) < std::abs(p2.mLambda() - v0InvMass[ConfV0Selection.confV0Type2])) { + if (std::abs(p1.mLambda() - V0InvMass[ConfV0Selection.confV0Type1]) < std::abs(p2.mLambda() - V0InvMass[ConfV0Selection.confV0Type2])) { v0Duplicates.insert(p2.globalIndex()); } else { v0Duplicates.insert(p1.globalIndex()); @@ -763,13 +821,16 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// p1 daughters that do not pass this condition are not selected - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isParticleTPC(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) { return false; } if (!isParticleTOF(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) { return false; } + if (!checkDaughter(posChild1, negChild1)) { + return false; + } } else { if ((posChild1.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild1.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { return false; @@ -792,13 +853,16 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// p2 daughters that do not pass this condition are not selected - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isParticleTPC(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) { return false; } if (!isParticleTOF(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTOF(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) { return false; } + if (!checkDaughter(posChild2, negChild2)) { + return false; + } } else { if ((posChild2.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type2][0])) == 0 || (negChild2.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type2][1])) == 0) { return false; @@ -818,12 +882,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty double rand = 0.0; auto part1 = p1; auto part2 = p2; + double randomizationValue = 0.5; if (ConfCPR.confRandomizeCPR) { randgen = new TRandom2(0); rand = randgen->Rndm(); - if (rand > 0.5) { + if (rand > randomizationValue) { part1 = p2; part2 = p1; } @@ -837,10 +902,11 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } } - if constexpr (std::is_same::value) + if constexpr (std::is_same::value) { sameEventCont.setPair(p1, p2, multCol, confUse3D); - else + } else { sameEventCont.setPair(p1, p2, multCol, confUse3D); + } return true; }; @@ -921,22 +987,24 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty auto groupPartsOne = partsOneMCFull->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); auto groupPartsTwo = partsTwoMCFull->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - const int multCol = confUseCent ? static_cast(col.multV0M()) : static_cast(col.multNtr()); + const int multCol = confUseCent ? static_cast(col.multV0M()) : col.multNtr(); eventHisto.fillQA(col); /// Histogramming same event for (const auto& part : groupPartsTwo) { int pdgCode = static_cast(part.pidCut()); - if ((ConfV0Selection.confV0Type1 == 0 && pdgCode != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode != kLambda0Bar)) + if ((ConfV0Selection.confV0Type1 == 0 && pdgCode != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode != kLambda0Bar)) { continue; + } trackHistoPartTwo.fillQA(part); } for (const auto& part : groupPartsOne) { int pdgCode = static_cast(part.pidCut()); - if (pdgCode != ConfTrkSelection.confTrkPDGCodePartOne) + if (pdgCode != ConfTrkSelection.confTrkPDGCodePartOne) { continue; + } const auto& pdgParticle = pdgMC->GetParticle(pdgCode); if (!pdgParticle) { continue; @@ -951,11 +1019,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty /// Now build the combinations for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { - if (static_cast(p1.pidCut()) != ConfTrkSelection.confTrkPDGCodePartOne) + if (static_cast(p1.pidCut()) != ConfTrkSelection.confTrkPDGCodePartOne) { continue; + } int pdgCode2 = static_cast(p2.pidCut()); - if ((ConfV0Selection.confV0Type1 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode2 != kLambda0Bar)) + if ((ConfV0Selection.confV0Type1 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode2 != kLambda0Bar)) { continue; + } // track cleaning if (ConfCPR.confIsCPR.value) { if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla, femto_universe_container::EventType::same)) { @@ -972,7 +1042,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty void processMCSameEventV0(FilteredFDCollision const& col, FemtoFullParticles const& parts) { auto groupPartsTwo = partsTwoMCFull->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); - const int multCol = confUseCent ? static_cast(col.multV0M()) : static_cast(col.multNtr()); + const int multCol = confUseCent ? static_cast(col.multV0M()) : col.multNtr(); eventHisto.fillQA(col); @@ -1037,7 +1107,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty std::array, 3> v0DaughPtHighTable = {{{ConfV0Selection.confHPtChildProton, ConfV0Selection.confHPtChildPion}, {ConfV0Selection.confHPtChildPion, ConfV0Selection.confHPtChildProton}, {ConfV0Selection.confHPtChildPion, ConfV0Selection.confHPtChildPion}}}; auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { - const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); + const int multCol = confUseCent ? static_cast(collision1.multV0M()) : collision1.multNtr(); auto groupPartsOne = partsOne->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); @@ -1051,15 +1121,18 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { // Lambda invariant mass cut - if (!invMLambda(p2.mLambda(), p2.mAntiLambda(), ConfV0Selection.confV0Type1)) + if (!invMLambda(p2.mLambda(), p2.mAntiLambda(), ConfV0Selection.confV0Type1)) { continue; + } /// PID using stored binned nsigma - if constexpr (std::experimental::is_detected::value) { - if (!isParticleCombined(p1, ConfTrkSelection.confTrackChoicePartOne)) + if constexpr (std::experimental::is_detected::value) { + if (!isParticleCombined(p1, ConfTrkSelection.confTrackChoicePartOne)) { continue; + } } else { - if (!isNSigmaCombinedBitmask(p1.p(), p1)) + if (!isNSigmaCombinedBitmask(p1.p(), p1)) { continue; + } } const auto& posChild = parts.iteratorAt(p2.globalIndex() - 2 - parts.begin().globalIndex()); @@ -1069,20 +1142,28 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if constexpr (std::experimental::is_detected::value) { - if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { + continue; + } + if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; - if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + } + if (!checkDaughter(posChild, negChild)) { continue; + } } else { - if ((posChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } if (ConfV0Selection.confUseStrangenessTOF) { - if (((ConfV0Selection.confV0Type1 == 0) && (p2.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (p2.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (p2.pidCut() & 48) != 48)) + if (((ConfV0Selection.confV0Type1 == 0) && (p2.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (p2.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (p2.pidCut() & 48) != 48)) { continue; + } } else { - if ((posChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } } } @@ -1096,13 +1177,14 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } } float weight = 1.0f; - if (pEffHistp1) + if (pEffHistp1) { weight = pEffHistp1.get()->GetBinContent(pEffHistp1->FindBin(p1.pt(), p1.eta())) * pEffHistp2.get()->GetBinContent(pEffHistp2->FindBin(p2.pt(), p2.eta())); - - if constexpr (std::is_same::value) + } + if constexpr (std::is_same::value) { mixedEventCont.setPair(p1, p2, multCol, confUse3D, weight); - else + } else { mixedEventCont.setPair(p1, p2, multCol, confUse3D, weight); + } } }; @@ -1130,7 +1212,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty std::array, 3> v0DaughPtHighTable = {{{ConfV0Selection.confHPtChildProton, ConfV0Selection.confHPtChildPion}, {ConfV0Selection.confHPtChildPion, ConfV0Selection.confHPtChildProton}, {ConfV0Selection.confHPtChildPion, ConfV0Selection.confHPtChildPion}}}; auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { - const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); + const int multCol = confUseCent ? static_cast(collision1.multV0M()) : collision1.multNtr(); auto groupPartsOne = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); auto groupPartsTwo = partsTwo->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); @@ -1160,20 +1242,28 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if constexpr (std::experimental::is_detected::value) { - if (!isParticleTPC(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) { + continue; + } + if (!isParticleTOF(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; - if (!isParticleTOF(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) + } + if (!checkDaughter(posChild1, negChild1)) { continue; + } } else { - if ((posChild1.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild1.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild1.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild1.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } if (ConfV0Selection.confUseStrangenessTOF) { - if (((ConfV0Selection.confV0Type1 == 0) && (p1.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (p1.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (p1.pidCut() & 48) != 48)) + if (((ConfV0Selection.confV0Type1 == 0) && (p1.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type1 == 1) && (p1.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type1 == 2) && (p1.pidCut() & 48) != 48)) { continue; + } } else { - if ((posChild1.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild1.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) + if ((posChild1.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][0])) == 0 || (negChild1.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type1][1])) == 0) { continue; + } } } @@ -1184,20 +1274,28 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if constexpr (std::experimental::is_detected::value) { - if (!isParticleTPC(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) + if constexpr (std::experimental::is_detected::value) { + if (!isParticleTPC(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) { continue; - if (!isParticleTOF(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTOF(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) + } + if (!isParticleTOF(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTOF(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) { + continue; + } + if (!checkDaughter(posChild2, negChild2)) { continue; + } } else { - if ((posChild2.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type2][0])) == 0 || (negChild2.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type2][1])) == 0) + if ((posChild2.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type2][0])) == 0 || (negChild2.pidCut() & (1u << V0ChildTable[ConfV0Selection.confV0Type2][1])) == 0) { continue; + } if (ConfV0Selection.confUseStrangenessTOF) { - if (((ConfV0Selection.confV0Type2 == 0) && (p2.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type2 == 1) && (p2.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type2 == 2) && (p2.pidCut() & 48) != 48)) + if (((ConfV0Selection.confV0Type2 == 0) && (p2.pidCut() & 3) != 3) || ((ConfV0Selection.confV0Type2 == 1) && (p2.pidCut() & 12) != 12) || ((ConfV0Selection.confV0Type2 == 2) && (p2.pidCut() & 48) != 48)) { continue; + } } else { - if ((posChild2.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type2][0])) == 0 || (negChild2.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type2][1])) == 0) + if ((posChild2.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type2][0])) == 0 || (negChild2.pidCut() & (8u << V0ChildTable[ConfV0Selection.confV0Type2][1])) == 0) { continue; + } } } @@ -1209,12 +1307,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty double rand = 0.0; auto part1 = p1; auto part2 = p2; + double randomizationValue = 0.5; if (ConfCPR.confRandomizeCPR) { randgen = new TRandom2(0); rand = randgen->Rndm(); - if (rand > 0.5) { + if (rand > randomizationValue) { part1 = p2; part2 = p1; } @@ -1228,10 +1327,11 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } } - if constexpr (std::is_same::value) + if constexpr (std::is_same::value) { mixedEventCont.setPair(p1, p2, multCol, confUse3D); - else + } else { mixedEventCont.setPair(p1, p2, multCol, confUse3D); + } } }; @@ -1291,7 +1391,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty ColumnBinningPolicy colBinningCent{{confVtxBins, confMultBins}, true}; auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { - const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); + const int multCol = confUseCent ? static_cast(collision1.multV0M()) : collision1.multNtr(); auto groupPartsOne = partsOneMCFull->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); auto groupPartsTwo = partsTwoMCFull->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); @@ -1303,11 +1403,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty return; } for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { - if (static_cast(p1.pidCut()) != ConfTrkSelection.confTrkPDGCodePartOne) + if (static_cast(p1.pidCut()) != ConfTrkSelection.confTrkPDGCodePartOne) { continue; + } int pdgCode2 = static_cast(p2.pidCut()); - if ((ConfV0Selection.confV0Type1 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode2 != kLambda0Bar)) + if ((ConfV0Selection.confV0Type1 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode2 != kLambda0Bar)) { continue; + } if (ConfCPR.confIsCPR.value) { if (pairCloseRejection.isClosePair(p1, p2, parts, magFieldTesla1, femto_universe_container::EventType::mixed)) { continue; @@ -1339,18 +1441,20 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty ColumnBinningPolicy colBinningCent{{confVtxBins, confMultBins}, true}; auto mixedCollProcessFunc = [&](auto& collision1, auto& collision2) -> void { - const int multCol = confUseCent ? collision1.multV0M() : collision1.multNtr(); + const int multCol = confUseCent ? static_cast(collision1.multV0M()) : collision1.multNtr(); auto groupPartsOne = partsTwoMCFull->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision1.globalIndex(), cache); auto groupPartsTwo = partsTwoMCFull->sliceByCached(aod::femtouniverseparticle::fdCollisionId, collision2.globalIndex(), cache); for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { int pdgCode1 = static_cast(p1.pidCut()); - if ((ConfV0Selection.confV0Type1 == 0 && pdgCode1 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode1 != kLambda0Bar)) + if ((ConfV0Selection.confV0Type1 == 0 && pdgCode1 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode1 != kLambda0Bar)) { continue; + } int pdgCode2 = static_cast(p2.pidCut()); - if ((ConfV0Selection.confV0Type2 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && pdgCode2 != kLambda0Bar)) + if ((ConfV0Selection.confV0Type2 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && pdgCode2 != kLambda0Bar)) { continue; + } mixedEventCont.setPair(p1, p2, multCol, confUse3D); } }; @@ -1376,8 +1480,9 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty void processMCTruth(aod::FDParticles const& parts) { for (const auto& part : parts) { - if (part.partType() != uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) + if (part.partType() != uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) { continue; + } int pdgCode = static_cast(part.pidCut()); const auto& pdgParticle = pdgMC->GetParticle(pdgCode); @@ -1443,11 +1548,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { // Lambda invariant mass cut - if (!invMLambda(p2.mLambda(), p2.mAntiLambda(), ConfV0Selection.confV0Type1)) + if (!invMLambda(p2.mLambda(), p2.mAntiLambda(), ConfV0Selection.confV0Type1)) { continue; + } /// PID using stored binned nsigma - if (!isParticleCombined(p1, ConfTrkSelection.confTrackChoicePartOne)) + if (!isParticleCombined(p1, ConfTrkSelection.confTrackChoicePartOne)) { continue; + } const auto& posChild = parts.iteratorAt(p2.globalIndex() - 2 - parts.begin().globalIndex()); const auto& negChild = parts.iteratorAt(p2.globalIndex() - 1 - parts.begin().globalIndex()); @@ -1456,10 +1563,12 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; - if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + } + if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; + } // track cleaning if (!pairCleaner.isCleanPair(p1, p2, parts)) { @@ -1473,11 +1582,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty registryMCreco.fill(HIST("mothersReco/motherParticle"), p1.motherPDG(), p2.motherPDG()); auto mcPartId1 = p1.fdMCParticleId(); - if (mcPartId1 == -1) + if (mcPartId1 == -1) { continue; + } auto mcPartId2 = p2.fdMCParticleId(); - if (mcPartId2 == -1) + if (mcPartId2 == -1) { continue; + } const auto& mcParticle1 = mcparts.iteratorAt(mcPartId1); const auto& mcParticle2 = mcparts.iteratorAt(mcPartId2); if (mcParticle1.pdgMCTruth() == ConfTrkSelection.confTrkPDGCodePartOne && mcParticle2.pdgMCTruth() == ConfV0Selection.confV0PDGCodePartTwo) { @@ -1528,10 +1639,12 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if (!isParticleTPC(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if (!isParticleTPC(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; - if (!isParticleTOF(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) + } + if (!isParticleTOF(posChild1, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild1, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; + } const auto& posChild2 = parts.iteratorAt(p2.globalIndex() - 2 - parts.begin().globalIndex()); const auto& negChild2 = parts.iteratorAt(p2.globalIndex() - 1 - parts.begin().globalIndex()); @@ -1540,10 +1653,12 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } /// Daughters that do not pass this condition are not selected - if (!isParticleTPC(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) + if (!isParticleTPC(posChild2, V0ChildTable[ConfV0Selection.confV0Type2][0]) || !isParticleTPC(negChild2, V0ChildTable[ConfV0Selection.confV0Type2][1])) { continue; - if (!isParticleTOF(negChild2, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild2, V0ChildTable[ConfV0Selection.confV0Type1][1])) + } + if (!isParticleTOF(negChild2, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild2, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; + } // track cleaning if (!pairCleanerV0.isCleanPair(p1, p2, parts)) { @@ -1553,12 +1668,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty double rand = 0.0; auto part1 = p1; auto part2 = p2; + double randomizationValue = 0.5; if (ConfCPR.confRandomizeCPR) { randgen = new TRandom2(0); rand = randgen->Rndm(); - if (rand > 0.5) { + if (rand > randomizationValue) { part1 = p2; part2 = p1; } @@ -1571,17 +1687,21 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty registryMCreco.fill(HIST("mothersReco/motherParticle"), p1.motherPDG(), p2.motherPDG()); auto mcPartId1 = p1.fdMCParticleId(); - if (mcPartId1 == -1) + if (mcPartId1 == -1) { continue; + } auto mcPartId2 = p2.fdMCParticleId(); - if (mcPartId2 == -1) + if (mcPartId2 == -1) { continue; + } const auto& mcParticle1 = mcparts.iteratorAt(mcPartId1); const auto& mcParticle2 = mcparts.iteratorAt(mcPartId2); - if ((ConfV0Selection.confV0Type1 == 0 && mcParticle1.pdgMCTruth() != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && mcParticle1.pdgMCTruth() != kLambda0Bar)) + if ((ConfV0Selection.confV0Type1 == 0 && mcParticle1.pdgMCTruth() != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && mcParticle1.pdgMCTruth() != kLambda0Bar)) { continue; - if ((ConfV0Selection.confV0Type2 == 0 && mcParticle2.pdgMCTruth() != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && mcParticle2.pdgMCTruth() != kLambda0Bar)) + } + if ((ConfV0Selection.confV0Type2 == 0 && mcParticle2.pdgMCTruth() != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && mcParticle2.pdgMCTruth() != kLambda0Bar)) { continue; + } registryMCreco.fill(HIST("mothersReco/motherParticlePDGCheck"), p1.motherPDG(), p2.motherPDG()); } @@ -1612,10 +1732,12 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty int pdgCode1 = static_cast(p1.pidCut()); int pdgCode2 = static_cast(p2.pidCut()); - if (pdgCode1 != ConfTrkSelection.confTrkPDGCodePartOne) + if (pdgCode1 != ConfTrkSelection.confTrkPDGCodePartOne) { continue; - if (pdgCode2 != ConfV0Selection.confV0PDGCodePartTwo) + } + if (pdgCode2 != ConfV0Selection.confV0PDGCodePartTwo) { continue; + } registryMCtruth.fill(HIST("mothersTruth/motherParticle"), p1.tempFitVar(), p2.tempFitVar()); registryMCtruth.fill(HIST("mothersTruth/mcProcess"), p1.cut(), p2.cut()); @@ -1645,11 +1767,13 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty for (const auto& [p1, p2] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { int pdgCode1 = static_cast(p1.pidCut()); - if ((ConfV0Selection.confV0Type1 == 0 && pdgCode1 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode1 != kLambda0Bar)) + if ((ConfV0Selection.confV0Type1 == 0 && pdgCode1 != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && pdgCode1 != kLambda0Bar)) { continue; + } int pdgCode2 = static_cast(p2.pidCut()); - if ((ConfV0Selection.confV0Type2 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && pdgCode2 != kLambda0Bar)) + if ((ConfV0Selection.confV0Type2 == 0 && pdgCode2 != kLambda0) || (ConfV0Selection.confV0Type2 == 1 && pdgCode2 != kLambda0Bar)) { continue; + } registryMCtruth.fill(HIST("mothersTruth/motherParticle"), p1.tempFitVar(), p2.tempFitVar()); registryMCtruth.fill(HIST("mothersTruth/mcProcess"), p1.cut(), p2.cut()); @@ -1677,8 +1801,9 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty std::array, 3> v0DaughPtHighTable = {{{ConfV0Selection.confHPtChildProton, ConfV0Selection.confHPtChildPion}, {ConfV0Selection.confHPtChildPion, ConfV0Selection.confHPtChildProton}, {ConfV0Selection.confHPtChildPion, ConfV0Selection.confHPtChildPion}}}; for (const auto& part : groupPartsTwo) { - if (!invMLambda(part.mLambda(), part.mAntiLambda(), ConfV0Selection.confV0Type1)) + if (!invMLambda(part.mLambda(), part.mAntiLambda(), ConfV0Selection.confV0Type1)) { continue; + } const auto& posChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); const auto& negChild = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); @@ -1686,19 +1811,23 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty continue; } - if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if (!isParticleTPC(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTPC(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; + } - if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) + if (!isParticleTOF(posChild, V0ChildTable[ConfV0Selection.confV0Type1][0]) || !isParticleTOF(negChild, V0ChildTable[ConfV0Selection.confV0Type1][1])) { continue; + } registryMCreco.fill(HIST("mothersReco/motherParticleV0"), part.motherPDG()); auto mcPartId1 = part.fdMCParticleId(); - if (mcPartId1 == -1) + if (mcPartId1 == -1) { continue; + } const auto& mcParticle1 = mcparts.iteratorAt(mcPartId1); - if ((ConfV0Selection.confV0Type1 == 0 && mcParticle1.pdgMCTruth() != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && mcParticle1.pdgMCTruth() != kLambda0Bar)) + if ((ConfV0Selection.confV0Type1 == 0 && mcParticle1.pdgMCTruth() != kLambda0) || (ConfV0Selection.confV0Type1 == 1 && mcParticle1.pdgMCTruth() != kLambda0Bar)) { continue; + } registryMCreco.fill(HIST("mothersReco/motherParticleV0PDGCheck"), part.motherPDG()); } @@ -1706,15 +1835,18 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty const std::array tpcNSigmas = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; const std::array tofNSigmas = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; - if (!isNSigmaCombined(part.p(), tpcNSigmas[ConfTrkSelection.confTrackChoicePartOne], tofNSigmas[ConfTrkSelection.confTrackChoicePartOne], (part.pidCut() & 512u) != 0)) + if (!isNSigmaCombined(part.p(), tpcNSigmas[ConfTrkSelection.confTrackChoicePartOne], tofNSigmas[ConfTrkSelection.confTrackChoicePartOne], (part.pidCut() & 512u) != 0)) { continue; + } registryMCreco.fill(HIST("mothersReco/motherParticleTrack"), part.motherPDG()); auto mcPartId1 = part.fdMCParticleId(); - if (mcPartId1 == -1) + if (mcPartId1 == -1) { continue; + } const auto& mcParticle1 = mcparts.iteratorAt(mcPartId1); - if (mcParticle1.pdgMCTruth() != ConfTrkSelection.confTrkPDGCodePartOne) + if (mcParticle1.pdgMCTruth() != ConfTrkSelection.confTrkPDGCodePartOne) { continue; + } registryMCreco.fill(HIST("mothersReco/motherParticleTrackPDGCheck"), part.motherPDG()); } } @@ -1727,15 +1859,17 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty // MC truth for (const auto& part : groupPartsOne) { int pdgCode1 = static_cast(part.pidCut()); - if (pdgCode1 != ConfTrkSelection.confTrkPDGCodePartOne) + if (pdgCode1 != ConfTrkSelection.confTrkPDGCodePartOne) { continue; + } registryMCtruth.fill(HIST("mothersTruth/motherParticleTrack"), part.tempFitVar()); registryMCtruth.fill(HIST("mothersTruth/mcProcessTrack"), part.cut()); } for (const auto& part : groupPartsTwo) { int pdgCode2 = static_cast(part.pidCut()); - if (pdgCode2 != ConfV0Selection.confV0PDGCodePartTwo) + if (pdgCode2 != ConfV0Selection.confV0PDGCodePartTwo) { continue; + } registryMCtruth.fill(HIST("mothersTruth/motherParticleV0"), part.tempFitVar()); registryMCtruth.fill(HIST("mothersTruth/mcProcessV0"), part.cut()); } @@ -1759,7 +1893,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } const auto& posChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); const auto& negChild = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { /// Daughters that do not pass this condition are not selected if (!isParticleTPC(posChild, 0) || !isParticleTPC(negChild, 1)) { continue; @@ -1792,7 +1926,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } const auto& posChild = parts.iteratorAt(part.globalIndex() - 2 - parts.begin().globalIndex()); const auto& negChild = parts.iteratorAt(part.globalIndex() - 1 - parts.begin().globalIndex()); - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { /// Daughters that do not pass this condition are not selected if (!isParticleTPC(posChild, 1) || !isParticleTPC(negChild, 0)) { continue; @@ -1823,7 +1957,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty if (part.mAntiLambda() > 0) { // mAntiLambda is the sign here registryMCreco.fill(HIST("plus/MCrecoAllPt"), mcpart.pt()); if (mcpart.pdgMCTruth() == kPiPlus) { - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), (part.pidCut() & 512u) != 0)) { continue; } @@ -1839,7 +1973,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty registryMCreco.fill(HIST("plus/MCrecoPi"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("plus/MCrecoPiPt"), mcpart.pt()); } else if (mcpart.pdgMCTruth() == kProton) { - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), (part.pidCut() & 512u) != 0)) { continue; } @@ -1854,7 +1988,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty } else if (part.mAntiLambda() < 0) { registryMCreco.fill(HIST("minus/MCrecoAllPt"), mcpart.pt()); if (mcpart.pdgMCTruth() == kPiMinus) { - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), (part.pidCut() & 512u) != 0)) { continue; } @@ -1870,7 +2004,7 @@ struct FemtoUniversePairTaskTrackV0Extended { // NOLINT(cppcoreguidelines-pro-ty registryMCreco.fill(HIST("minus/MCrecoPi"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("minus/MCrecoPiPt"), mcpart.pt()); } else if (mcpart.pdgMCTruth() == kProtonBar) { - if constexpr (std::experimental::is_detected::value) { + if constexpr (std::experimental::is_detected::value) { if (!isNSigmaCombined(part.p(), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), (part.pidCut() & 512u) != 0)) { continue; } From 1151e2598218a01c786d8a177627c4e86ad82caf Mon Sep 17 00:00:00 2001 From: Fabrizio Date: Tue, 28 Jul 2026 18:39:19 +0200 Subject: [PATCH 22/71] [PWGHF] Fix mismatch between axes definition and filling of THnSparse for MC (#17233) --- PWGHF/D2H/Tasks/taskD0.cxx | 75 +++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index ac7cc895058..e40d15a7c57 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -345,7 +345,6 @@ struct HfTaskD0 { if (doprocessMcWithDCAFitterN || doprocessMcWithDCAFitterNCent || doprocessMcWithKFParticle || doprocessMcWithDCAFitterNMl || doprocessMcWithDCAFitterNMlCent || doprocessMcWithKFParticleMl) { axes.push_back(thnAxisPtB); axes.push_back(thnAxisOrigin); - axes.push_back(thnAxisNumPvContr); } if (storeCentrality) { axes.push_back(thnAxisCent); @@ -1125,27 +1124,27 @@ struct HfTaskD0 { registry.fill(HIST("hMassSigD0"), massD0, ptCandidate, rapidityCandidate); if constexpr (ApplyMl) { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), occ, ir); } else if (storeTrackQuality) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), minItsClustersOfProngs, minTpcCrossedRowsOfProngs); } else { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec()); } } else { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), occ, ir); } else if (storeTrackQuality) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), minItsClustersOfProngs, minTpcCrossedRowsOfProngs); } else { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, SigD0, candidate.ptBhadMotherPart(), candidate.originMcRec()); } } } else { @@ -1167,27 +1166,27 @@ struct HfTaskD0 { registry.fill(HIST("hMassReflBkgD0"), massD0, ptCandidate, rapidityCandidate); if constexpr (ApplyMl) { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), occ, ir); } else if (storeTrackQuality) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), minItsClustersOfProngs, minTpcCrossedRowsOfProngs); } else { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec()); } } else { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), occ, ir); } else if (storeTrackQuality) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), minItsClustersOfProngs, minTpcCrossedRowsOfProngs); } else { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, rapidityCandidate, ReflectedD0, candidate.ptBhadMotherPart(), candidate.originMcRec()); } } } @@ -1199,27 +1198,27 @@ struct HfTaskD0 { registry.fill(HIST("hMassSigD0bar"), massD0bar, ptCandidate, rapidityCandidate); if constexpr (ApplyMl) { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), occ, ir); } else if (storeTrackQuality) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), minItsClustersOfProngs, minTpcCrossedRowsOfProngs); } else { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec()); } } else { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), occ, ir); } else if (storeTrackQuality) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), minItsClustersOfProngs, minTpcCrossedRowsOfProngs); } else { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, SigD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec()); } } } else { @@ -1228,9 +1227,9 @@ struct HfTaskD0 { registry.fill(HIST("hMassReflBkgD0bar"), massD0bar, ptCandidate, rapidityCandidate); if constexpr (ApplyMl) { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0bar()[0], candidate.mlProbD0bar()[1], candidate.mlProbD0bar()[2], massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); } else if (storeTrackQuality) { @@ -1240,15 +1239,15 @@ struct HfTaskD0 { } } else { if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors, occ, ir); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, cent); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), cent, numPvContributors); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, occ, ir); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), occ, ir); } else if (storeTrackQuality) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors, minItsClustersOfProngs, minTpcCrossedRowsOfProngs); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), minItsClustersOfProngs, minTpcCrossedRowsOfProngs); } else { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec(), numPvContributors); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, rapidityCandidate, ReflectedD0bar, candidate.ptBhadMotherPart(), candidate.originMcRec()); } } } From dddd07ee3d16e5c48a74d715deb342997c42a023 Mon Sep 17 00:00:00 2001 From: Marcello Di Costanzo <96481191+Marcellocosti@users.noreply.github.com> Date: Tue, 28 Jul 2026 18:43:57 +0200 Subject: [PATCH 23/71] [PWGLF] Efficiency studies for Sigma kink + Event Mixing in L1405 task (#17107) Co-authored-by: ALICE Action Bot --- PWGLF/DataModel/LFLambda1405Table.h | 89 ++- PWGLF/Tasks/Resonances/lambda1405analysis.cxx | 678 ++++++++++++------ 2 files changed, 530 insertions(+), 237 deletions(-) diff --git a/PWGLF/DataModel/LFLambda1405Table.h b/PWGLF/DataModel/LFLambda1405Table.h index 103065146c6..44339682b7c 100644 --- a/PWGLF/DataModel/LFLambda1405Table.h +++ b/PWGLF/DataModel/LFLambda1405Table.h @@ -9,11 +9,10 @@ // 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 /// +/// \author Francesco Mazzaschi #ifndef PWGLF_DATAMODEL_LFLAMBDA1405TABLE_H_ #define PWGLF_DATAMODEL_LFLAMBDA1405TABLE_H_ @@ -44,13 +43,15 @@ DECLARE_SOA_COLUMN(NSigmaTPCPiKink, nSigmaTPCPiKink, float); //! Number of sigma 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(DcaKinkDauToPv, dcaKinkDauToPv, float); //! DCA of the kink daughter to the primary vertex +DECLARE_SOA_COLUMN(DcaSigmaToPv, dcaSigmaToPv, float); //! DCA of the sigma 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 // Event properties DECLARE_SOA_COLUMN(Centrality, centrality, float); //! Centrality of the candidate DECLARE_SOA_COLUMN(Occupancy, occupancy, float); //! Occupancy of the candidate +DECLARE_SOA_COLUMN(PvContrib, pvContrib, float); //! Number of primary vertex contributors // Flow columns DECLARE_SOA_COLUMN(ScalarProd, scalarProd, float); //! Scalar product of the candidate @@ -61,6 +62,44 @@ DECLARE_SOA_COLUMN(MassMC, massMC, float); //! Invariant mass of t DECLARE_SOA_COLUMN(SigmaPdgCode, sigmaPdgCode, int); //! PDG code of the Sigma daughter DECLARE_SOA_COLUMN(KinkDauPdgCode, kinkDauPdgCode, int); //! PDG code of the kink daughter +// Sigma efficiency MC columns +DECLARE_SOA_COLUMN(PxSigma, pxSigma, float); //! Px of the sigma candidate +DECLARE_SOA_COLUMN(PySigma, pySigma, float); //! Py of the sigma candidate +DECLARE_SOA_COLUMN(PzSigma, pzSigma, float); //! Pz of the sigma candidate +DECLARE_SOA_COLUMN(MassSigma, massSigma, float); //! Mass of the sigma candidate +DECLARE_SOA_COLUMN(DeltaPxSigma, deltaPxSigma, float); //! Gen-reco diff of sigma p_x +DECLARE_SOA_COLUMN(DeltaPySigma, deltaPySigma, float); //! Gen-reco diff of sigma p_y +DECLARE_SOA_COLUMN(DeltaPzSigma, deltaPzSigma, float); //! Gen-reco diff of sigma p_z +DECLARE_SOA_COLUMN(DeltaPtSigma, deltaPtSigma, float); //! Gen-reco diff of sigma p_z +DECLARE_SOA_COLUMN(DeltaRadiusSigma, deltaRadiusSigma, float); //! Gen-reco diff of sigma radius +DECLARE_SOA_COLUMN(DeltaMassSigma, deltaMassSigma, float); //! Gen-reco diff of sigma mass +DECLARE_SOA_COLUMN(GenPhiSigma, genPhiSigma, float); //! Gen-reco diff of sigma phi +DECLARE_SOA_COLUMN(GenEtaSigma, genEtaSigma, float); //! Gen-reco diff of sigma eta +DECLARE_SOA_COLUMN(DeltaPxSigmaRecalc, deltaPxSigmaRecalc, float); //! reco recalc-original diff of sigma p_x +DECLARE_SOA_COLUMN(DeltaPySigmaRecalc, deltaPySigmaRecalc, float); //! reco recalc-original diff of sigma p_y +DECLARE_SOA_COLUMN(DeltaPzSigmaRecalc, deltaPzSigmaRecalc, float); //! reco recalc-original diff of sigma p_z +DECLARE_SOA_COLUMN(AlphaAPSigmaRecalc, alphaAPSigmaRecalc, float); //! Alpha of the Sigma +DECLARE_SOA_COLUMN(QtAPSigmaRecalc, qtAPSigmaRecalc, float); //! qT of the Sigma +DECLARE_SOA_COLUMN(PxKinkDaug, pxKinkDaug, float); //! Px of the sigma candidate +DECLARE_SOA_COLUMN(PyKinkDaug, pyKinkDaug, float); //! Py of the sigma candidate +DECLARE_SOA_COLUMN(PzKinkDaug, pzKinkDaug, float); //! Pz of the sigma candidate +DECLARE_SOA_COLUMN(PtKinkDaug, ptKinkDaug, float); //! Pt of the sigma candidate +DECLARE_SOA_COLUMN(DeltaPxKinkDaug, deltaPxKinkDaug, float); //! Gen-reco diff of kink daughter p_x +DECLARE_SOA_COLUMN(DeltaPyKinkDaug, deltaPyKinkDaug, float); //! Gen-reco diff of kink daughter p_y +DECLARE_SOA_COLUMN(DeltaPzKinkDaug, deltaPzKinkDaug, float); //! Gen-reco diff of kink daughter p_z +DECLARE_SOA_COLUMN(DeltaPtKinkDaug, deltaPtKinkDaug, float); //! Gen-reco diff of kink daughter p_t +DECLARE_SOA_COLUMN(GenPhiKinkDaug, genPhiKinkDaug, float); //! Gen-reco diff of kink daughter phi +DECLARE_SOA_COLUMN(GenEtaKinkDaug, genEtaKinkDaug, float); //! Gen-reco diff of kink daughter eta +DECLARE_SOA_COLUMN(XKinkVtx, xKinkVtx, float); //! X of kink vertex +DECLARE_SOA_COLUMN(YKinkVtx, yKinkVtx, float); //! Y of kink vertex +DECLARE_SOA_COLUMN(ZKinkVtx, zKinkVtx, float); //! Z of kink vertex +DECLARE_SOA_COLUMN(DeltaXKinkVtx, deltaXKinkVtx, float); //! Gen-reco diff of X of kink vertex +DECLARE_SOA_COLUMN(DeltaYKinkVtx, deltaYKinkVtx, float); //! Gen-reco diff of Y of kink vertex +DECLARE_SOA_COLUMN(DeltaZKinkVtx, deltaZKinkVtx, float); //! Gen-reco diff of Z of kink vertex + +// Event mixing +DECLARE_SOA_COLUMN(PoolBin, poolBin, int); //! Signed pT of the Sigma daughter for mixed events + } // namespace lambda1405 DECLARE_SOA_TABLE(Lambda1405Cands, "AOD", "LAMBDA1405", @@ -72,21 +111,10 @@ DECLARE_SOA_TABLE(Lambda1405Cands, "AOD", "LAMBDA1405", lambda1405::PtKink, lambda1405::NSigmaTPCPiKink, lambda1405::NSigmaTOFPiKink, lambda1405::NSigmaTPCPrKink, lambda1405::NSigmaTOFPrKink, - lambda1405::DCAKinkDauToPV, + lambda1405::DcaKinkDauToPv, lambda1405::NSigmaTPCPiDau, lambda1405::NSigmaTOFPiDau, - lambda1405::Centrality, lambda1405::Occupancy); - -DECLARE_SOA_TABLE(Lambda1405Flow, "AOD", "LAMBDA1405FLOW", - o2::soa::Index<>, - lambda1405::Pt, lambda1405::Mass, - lambda1405::PtSigma, - lambda1405::SigmaMinusMass, lambda1405::SigmaPlusMass, - lambda1405::AlphaAPSigma, lambda1405::QtAPSigma, - lambda1405::NSigmaTPCPiKink, lambda1405::NSigmaTOFPiKink, - lambda1405::NSigmaTPCPrKink, lambda1405::NSigmaTOFPrKink, - lambda1405::DCAKinkDauToPV, - lambda1405::NSigmaTPCPiDau, lambda1405::NSigmaTOFPiDau, - lambda1405::ScalarProd, lambda1405::Centrality); + lambda1405::ScalarProd, + lambda1405::Centrality, lambda1405::Occupancy, lambda1405::PoolBin); DECLARE_SOA_TABLE(Lambda1405CandsMC, "AOD", "MCLAMBDA1405", o2::soa::Index<>, @@ -97,11 +125,36 @@ DECLARE_SOA_TABLE(Lambda1405CandsMC, "AOD", "MCLAMBDA1405", lambda1405::PtKink, lambda1405::NSigmaTPCPiKink, lambda1405::NSigmaTOFPiKink, lambda1405::NSigmaTPCPrKink, lambda1405::NSigmaTOFPrKink, - lambda1405::DCAKinkDauToPV, + lambda1405::DcaKinkDauToPv, lambda1405::NSigmaTPCPiDau, lambda1405::NSigmaTOFPiDau, lambda1405::PtMC, lambda1405::MassMC, lambda1405::SigmaPdgCode, lambda1405::KinkDauPdgCode, lambda1405::Centrality, lambda1405::Occupancy); +DECLARE_SOA_TABLE(Lambda1405SigmaEffMC, "AOD", "MCL1405SIGEFF", + o2::soa::Index<>, + lambda1405::PxSigma, lambda1405::DeltaPxSigma, + lambda1405::PySigma, lambda1405::DeltaPySigma, + lambda1405::PzSigma, lambda1405::DeltaPzSigma, + lambda1405::MassSigma, lambda1405::DeltaMassSigma, + lambda1405::DeltaPxSigmaRecalc, + lambda1405::DeltaPySigmaRecalc, + lambda1405::DeltaPzSigmaRecalc, + lambda1405::GenPhiSigma, + lambda1405::GenEtaSigma, + lambda1405::PxKinkDaug, lambda1405::DeltaPxKinkDaug, + lambda1405::PyKinkDaug, lambda1405::DeltaPyKinkDaug, + lambda1405::PzKinkDaug, lambda1405::DeltaPzKinkDaug, + lambda1405::GenPhiKinkDaug, + lambda1405::GenEtaKinkDaug, + lambda1405::XKinkVtx, lambda1405::DeltaXKinkVtx, + lambda1405::YKinkVtx, lambda1405::DeltaYKinkVtx, + lambda1405::ZKinkVtx, lambda1405::DeltaZKinkVtx, + lambda1405::AlphaAPSigma, lambda1405::QtAPSigma, + lambda1405::AlphaAPSigmaRecalc, lambda1405::QtAPSigmaRecalc, + lambda1405::DcaKinkDauToPv, lambda1405::DcaSigmaToPv, + lambda1405::SigmaPdgCode, lambda1405::KinkDauPdgCode, + lambda1405::Centrality, lambda1405::Occupancy, lambda1405::PvContrib); + } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFLAMBDA1405TABLE_H_ diff --git a/PWGLF/Tasks/Resonances/lambda1405analysis.cxx b/PWGLF/Tasks/Resonances/lambda1405analysis.cxx index e8771cbb8a6..10b85c03f2b 100644 --- a/PWGLF/Tasks/Resonances/lambda1405analysis.cxx +++ b/PWGLF/Tasks/Resonances/lambda1405analysis.cxx @@ -24,6 +24,7 @@ #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/Qvectors.h" +#include "Common/DataModel/TrackSelectionTables.h" #include #include @@ -61,11 +62,14 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -using TracksFull = soa::Join; -using CollisionsFull = soa::Join; -using CollisionsFullWCentQVecs = soa::Join; -using CollisionsFullMc = soa::Join; -using CollisionsFullMcWCent = soa::Join; +using TracksFull = soa::Join; +using CollisionsFull = soa::Join; +using CollisionsFullWQVecs = soa::Join; +using CollisionsFullMc = soa::Join; +// using CollisionsFullMcWCent = soa::Join; + +using BinningCentPosZ = ColumnBinningPolicy; +using BinningMultPosZ = ColumnBinningPolicy, aod::collision::PosZ>; enum L1405DecayType { kSigmaMinusPiToPiPiNeutron = 0, kSigmaPlusPiToPiPiNeutron, @@ -113,13 +117,15 @@ struct lambda1405candidate { float occupancy = -1; // Occupancy of the collision float scalarProd = -1; // Scalar product for flow analysis + + int poolBin = -1; // Pool bin for event mixing }; struct lambda1405analysis { - int lambda1405PdgCode = 102132; // PDG code for Lambda(1405) + int lambda1405PdgCode = 102132; // o2-linter: disable=pdg/explicit-code Produces outputDataTable; // Output table for Lambda(1405) candidates - Produces outputDataFlowTable; // Output table for Lambda(1405) flow analysis Produces outputDataTableMC; // Output table for Lambda(1405) candidates in MC + Produces outputSigmaEffMC; // Output table for Lambda(1405) sigma efficiency in MC Service ccdb; @@ -130,44 +136,51 @@ struct lambda1405analysis { HistogramRegistry rSigmaPlus{"sigmaPlus", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry rSelections{"selections", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; // Configurable for event selection - Configurable cutZVertex{"cutZVertex", 10.0f, "Accepted z-vertex range (cm)"}; - Configurable cutEtaDaughter{"cutEtaDaughter", 0.8f, "Eta cut for daughter tracks"}; - 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 cutMinPtL1405{"cutMinPtL1405", 2.0f, "Minimum pT cut for Lambda(1405) candidates (GeV/c)"}; - 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 cutItsNClusKinkMin{"cutItsNClusKinkMin", 1, "Minimum number of ITS clusters for kink daughter"}; - Configurable cutItsNClusKinkMax{"cutItsNClusKinkMax", 3, "Maximum number of ITS clusters for kink daughter"}; - Configurable cutNTpcClus{"cutNTpcClus", 90, "Minimum number of Tpc clusters for pion candidate"}; - Configurable cutNSigTpc{"cutNSigTpc", 3, "NSigTpcPion"}; - Configurable cutNSigTof{"cutNSigTof", 3, "NSigTofPion"}; - Configurable cutMaxDcaZBach{"cutMaxDcaZBach", 0.1, "Maximum DcaZ for bachelor pion (cm)"}; - Configurable dcaXYBachNSigmaMax{"dcaXYBachNSigmaMax", 7, "Cut on number of sigma deviations from expected DCA in the transverse direction"}; - Configurable dcaXYPtBachFunc{"dcaXYPtBachFunc", "(0.0026+0.005/(x^1.01))", "Functional form of pt-dependent DCAxy cut"}; - Configurable cutSigmaQtAPMin{"cutSigmaQtAPMin", "0.17", "Functional form of minimum qT(alpha) selection"}; - Configurable cutSigmaQtAPMax{"cutSigmaQtAPMax", "0.2", "Functional form of minimum qT(alpha) selection"}; - Configurable cutMinBachPiPtVsL1405Pt{"cutMinBachPiPtVsL1405Pt", "0", "Functional form of minimum qT(alpha) selection"}; - Configurable cutMaxBachPiPtVsL1405Pt{"cutMaxBachPiPtVsL1405Pt", "10", "Functional form of minimum qT(alpha) selection"}; - Configurable cutMinSigmaPtVsL1405Pt{"cutMinSigmaPtVsL1405Pt", "0", "Functional form of minimum qT(alpha) selection"}; - Configurable cutMaxSigmaPtVsL1405Pt{"cutMaxSigmaPtVsL1405Pt", "10", "Functional form of minimum qT(alpha) selection"}; + struct : o2::framework::ConfigurableGroup { + Configurable cutZVertex{"cutZVertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable centMultMin{"centMultMin", 0., "Minimum collision centrality/multiplicity accepted"}; + Configurable centMultMax{"centMultMax", 100., "Maximum collision centrality/multiplicity accepted"}; + Configurable occupancyMax{"occupancyMax", 3000000., "Maximum collision occupancy accepted"}; + } eventSelection; + + struct : o2::framework::ConfigurableGroup { + Configurable cutEtaDaughter{"cutEtaDaughter", 0.8f, "Eta cut for daughter tracks"}; + 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 cutMinPtL1405{"cutMinPtL1405", 2.0f, "Minimum pT cut for Lambda(1405) candidates (GeV/c)"}; + 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 cutItsNClusKinkMin{"cutItsNClusKinkMin", 1, "Minimum number of ITS clusters for kink daughter"}; + Configurable cutItsNClusKinkMax{"cutItsNClusKinkMax", 3, "Maximum number of ITS clusters for kink daughter"}; + Configurable cutNTpcClus{"cutNTpcClus", 90, "Minimum number of Tpc clusters for pion candidate"}; + Configurable cutNSigTpc{"cutNSigTpc", 3, "NSigTpcPion"}; + Configurable cutNSigTof{"cutNSigTof", 3, "NSigTofPion"}; + Configurable cutMaxDcaZBach{"cutMaxDcaZBach", 0.1, "Maximum DcaZ for bachelor pion (cm)"}; + Configurable dcaXYBachNSigmaMax{"dcaXYBachNSigmaMax", 7, "Cut on number of sigma deviations from expected DCA in the transverse direction"}; + Configurable dcaXYPtBachFunc{"dcaXYPtBachFunc", "(0.0026+0.005/(x^1.01))", "Functional form of pt-dependent DCAxy cut"}; + Configurable cutSigmaQtAPMin{"cutSigmaQtAPMin", "0.17", "Functional form of minimum qT(alpha) selection"}; + Configurable cutSigmaQtAPMax{"cutSigmaQtAPMax", "0.2", "Functional form of minimum qT(alpha) selection"}; + Configurable cutMinBachPiPtVsL1405Pt{"cutMinBachPiPtVsL1405Pt", "0", "Functional form of minimum qT(alpha) selection"}; + Configurable cutMaxBachPiPtVsL1405Pt{"cutMaxBachPiPtVsL1405Pt", "10", "Functional form of minimum qT(alpha) selection"}; + Configurable cutMinSigmaPtVsL1405Pt{"cutMinSigmaPtVsL1405Pt", "0", "Functional form of minimum qT(alpha) selection"}; + Configurable cutMaxSigmaPtVsL1405Pt{"cutMaxSigmaPtVsL1405Pt", "10", "Functional form of minimum qT(alpha) selection"}; + } selections; // Configurables for flow analysis - Configurable centMultMin{"centMultMin", 0., "Minimum collision centrality/multiplicity accepted"}; - Configurable centMultMax{"centMultMax", 100., "Maximum collision centrality/multiplicity accepted"}; - Configurable occupancyMax{"occupancyMax", 3000000., "Maximum collision occupancy accepted"}; Configurable minDEta{"minDEta", -1., "Minimum delta eta between L1405-track pairs"}; Configurable assTrkMinPt{"assTrkMinPt", 0., "Minimum pT of associated track for 2PC"}; Configurable assTrkMaxPt{"assTrkMaxPt", 10., "Maximum pT of associated track for 2PC"}; Configurable saveDEtaDPhi{"saveDEtaDPhi", false, "If true, save the dEta and dPhi distributions for Lambda(1405) candidates"}; Configurable fillFlowTree{"fillFlowTree", false, "If true, fill the output tree with Lambda(1405) candidates"}; + Configurable useCentrality{"useCentrality", true, "If true, use centrality for binning"}; + Configurable numberEventsMixed{"numberEventsMixed", 5, "Number of events mixed in ME process"}; // Downsample for table filling Configurable downSampleFactor{"downSampleFactor", 1., "Fraction of candidates to keep in TTree"}; Configurable ptDownSampleMax{"ptDownSampleMax", 10., "Maximum pt for the application of the downsampling factor"}; + Configurable skipBkgSigmas{"skipBkgSigmas", true, "If true, skip un-matched sigmas in efficiency process function"}; Configurable fillOutputTree{"fillOutputTree", true, "If true, fill the output tree with Lambda(1405) candidates"}; Configurable doLikeSignBkg{"doLikeSignBkg", false, "Use like-sign background"}; Configurable useTof{"useTof", false, "Use Tof for PID for pion candidates"}; @@ -182,19 +195,24 @@ struct lambda1405analysis { TF1 funcMinQtAlphaAP, funcMaxQtAlphaAP, funcMinBachPiPtVsL1405Pt, funcMaxBachPiPtVsL1405Pt, funcMinSigmaPtVsL1405Pt, funcMaxSigmaPtVsL1405Pt, funcDcaXYPtCutBachPi; - using CollisionsCentSel = soa::Filtered; - using McRecoCollisionsCentSel = soa::Filtered; + using CollisionsSel = soa::Filtered; + using CollisionsSelWQVecs = soa::Filtered; + using McRecoCollisionsSel = soa::Filtered; - Filter filterOccupancy = aod::evsel::ft0cOccupancyInTimeRange <= occupancyMax; + Filter filterOccupancy = aod::evsel::ft0cOccupancyInTimeRange <= eventSelection.occupancyMax; PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + SliceCache cache; + + int poolBins{0}; + // Needed for DCA propagation of bachelor tracks - int mRunNumber; - float mBz; o2::base::MatLayerCylSet* lut = nullptr; // Configurable axes + ConfigurableAxis zPoolBins{"zPoolBins", {VARIABLE_WIDTH, -10.0, -2.5, 2.5, 10.0}, "Z vertex position pools"}; + ConfigurableAxis centMultPoolBins{"centMultPoolBins", {VARIABLE_WIDTH, 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100}, "Event cent/mult pools"}; ConfigurableAxis axisPvContrib{"axisPvContrib", {5000, 0., 5000.}, ""}; ConfigurableAxis axisCent{"axisCent", {100, 0., 100.}, ""}; ConfigurableAxis axisOccupancy{"axisOccupancy", {100, 0., 140000.}, ""}; @@ -224,6 +242,10 @@ struct lambda1405analysis { void init(InitContext const&) { + // Define pool bins + poolBins = (centMultPoolBins->size() - 2) * (zPoolBins->size() - 2); + const AxisSpec axisPoolBin = {poolBins, -0.5, static_cast(poolBins) - 0.5, "PoolBin"}; + // Axes const AxisSpec ptAxis{axisPtL1405, "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec pCompAxisL1405{axisPCompsL1405, "#it{p}_{comp} (GeV/#it{c})"}; @@ -253,6 +275,10 @@ struct lambda1405analysis { rEventSelection.add("hCentMultVsPvContrib", "hCentMultVsPvContrib", {HistType::kTH2F, {centMultAxis, pvContribAxis}}); rEventSelection.add("hOccVsPvContrib", "hOccVsPvContrib", {HistType::kTH2F, {occAxis, pvContribAxis}}); rEventSelection.add("hCentVsOcc", "hCentVsOcc", {HistType::kTH2F, {centMultAxis, occAxis}}); + rEventSelection.add("hCentPoolBin", "Centrality pool bin", {HistType::kTH2F, {{axisCent}, {axisPoolBin}}}); + rEventSelection.add("hZVtxPoolBin", "Z vtx pool bin", {HistType::kTH2F, {{vertexZAxis}, {axisPoolBin}}}); + rEventSelection.add("hMultPoolBin", "Multiplicity pool bin", {HistType::kTH2F, {{axisCent}, {axisPoolBin}}}); + rEventSelection.add("hPoolBins", "Pool bins", {HistType::kTH1F, {{102, -1.5, 100.5}}}); // Sigma- candidate properties rSigmaMinus.add("hMassXiMinusSigmaMinus", "hMassXiMinusSigmaMinus", {HistType::kTH2F, {xiMassAxis, sigmaMassAxis}}); @@ -319,18 +345,18 @@ struct lambda1405analysis { rLambda1405.add("h3BachPiDcaXYVsPt", "h3BachPiDcaXYVsPt", {HistType::kTH3F, {ptKinkDaugAxis, dcaBachPiAxis, centMultAxis}}); rLambda1405.add("h3BachPiDcaZVsPt", "h3BachPiDcaZVsPt", {HistType::kTH3F, {ptKinkDaugAxis, dcaBachPiAxis, centMultAxis}}); // Sparse histograms - std::vector axesMass = {lambda1405MassAxis, ptAxis, sigmaMassAxis, dcaSigmaToPvAxis, dcaKinkToPvAxis}; - if (doprocessMc || doprocessMcWCentSel) { + std::vector axesMass = {axisPoolBin, lambda1405MassAxis, ptAxis, sigmaMassAxis, dcaSigmaToPvAxis, dcaKinkToPvAxis}; + if (doprocessMc) { axesMass.push_back(pvContribAxis); } else { axesMass.push_back(centMultAxis); } rLambda1405.add("hSparseL1405", "THn for mass peak", HistType::kTHnSparseF, axesMass); - std::vector axesScalarProd = {lambda1405MassAxis, ptAxis, sigmaMassAxis, dcaSigmaToPvAxis, dcaKinkToPvAxis, centMultAxis, scalarProdAxis}; - if (doprocessDataWCentQVecs) { + std::vector axesScalarProd = {axisPoolBin, lambda1405MassAxis, ptAxis, sigmaMassAxis, dcaSigmaToPvAxis, dcaKinkToPvAxis, centMultAxis, scalarProdAxis}; + if (doprocessDataWQVecsSameEvent || doprocessDataWQVecsMixedEvent) { rLambda1405.add("hSparseL1405ScalProd", "THn for SP", HistType::kTHnSparseF, axesScalarProd); } - std::vector axesCorrel = {lambda1405MassAxis, ptAxis, deltaEtaAxis, deltaPhiAxis}; + std::vector axesCorrel = {axisPoolBin, lambda1405MassAxis, ptAxis, deltaEtaAxis, deltaPhiAxis}; if (saveDEtaDPhi) { rLambda1405.add("hSparseL1405Correl", "THn for 2PC", HistType::kTHnSparseF, axesCorrel); } @@ -397,14 +423,14 @@ struct lambda1405analysis { rSelections.get(HIST("hSelectionsKinkPr"))->GetXaxis()->SetBinLabel(6, "has TOF"); rSelections.get(HIST("hSelectionsKinkPr"))->GetXaxis()->SetBinLabel(7, "N#sigma TOF"); - if (doprocessDataWCentQVecs) { + if (doprocessDataWQVecsSameEvent || doprocessDataWQVecsMixedEvent) { rLambda1405.add("hScalarProd", "hScalarProd", {HistType::kTH2F, {scalarProdAxis, ptAxis}}); std::vector axesFlow = {lambda1405MassAxis, ptAxis, centMultAxis, scalarProdAxis}; rLambda1405.add("hSparseFlowL1405", "THn for SP", HistType::kTHnSparseF, axesFlow); } // Add MC histograms - if (doprocessMc || doprocessMcWCentSel) { + if (doprocessMc) { rSelections.add("hRecoNotMatchedCounter", "hRecoNotMatchedCounter", {HistType::kTH1D, {{4, -0.5, 3.5f}}}); rSelections.get(HIST("hRecoNotMatchedCounter"))->GetXaxis()->SetBinLabel(1, "#Lambda(1405)"); @@ -446,22 +472,29 @@ struct lambda1405analysis { rLambda1405.add("h2PtMassMC", "h2PtMassMC", {HistType::kTH2F, {ptAxis, lambda1405MassAxis}}); } + if (doprocessMcSigmasCentSel) { + rSigmaPlus.add("hSparseGenFromRecoSigmaPlus", "THn for generated Sigma plus", {HistType::kTHnSparseF, {sigmaMassAxis, ptAxis, alphaAxis, qtAxis, sigmaRadiusAxis, centMultAxis, occAxis, pvContribAxis}}); + rSigmaPlus.add("hSparseGenSigmaPlus", "THn for generated Sigma plus", {HistType::kTHnSparseF, {sigmaMassAxis, ptAxis, alphaAxis, qtAxis, sigmaRadiusAxis, centMultAxis, occAxis, pvContribAxis}}); + rSigmaMinus.add("hSparseGenFromRecoSigmaMinus", "THn for generated Sigma minus", {HistType::kTHnSparseF, {sigmaMassAxis, ptAxis, alphaAxis, qtAxis, sigmaRadiusAxis, centMultAxis, occAxis, pvContribAxis}}); + rSigmaMinus.add("hSparseGenSigmaMinus", "THn for generated Sigma minus", {HistType::kTHnSparseF, {sigmaMassAxis, ptAxis, alphaAxis, qtAxis, sigmaRadiusAxis, centMultAxis, occAxis, pvContribAxis}}); + } + // Functional selections - funcMinQtAlphaAP = TF1("funcMinQtAlphaAP", Form("%s", cutSigmaQtAPMin.value.data()), -1, 1); - LOGF(info, "funcMinQtAlphaAP: %s", Form("%s", cutSigmaQtAPMin.value.data())); - funcMaxQtAlphaAP = TF1("funcMaxQtAlphaAP", Form("%s", cutSigmaQtAPMax.value.data()), -1, 1); - LOGF(info, "funcMaxQtAlphaAP: %s", Form("%s", cutSigmaQtAPMax.value.data())); - funcMinBachPiPtVsL1405Pt = TF1("funcMinBachPiPtVsL1405Pt", Form("%s", cutMinBachPiPtVsL1405Pt.value.data()), 0., 100); - LOGF(info, "funcMinBachPiPtVsL1405Pt: %s", Form("%s", cutMinBachPiPtVsL1405Pt.value.data())); - funcMaxBachPiPtVsL1405Pt = TF1("funcMaxBachPiPtVsL1405Pt", Form("%s", cutMaxBachPiPtVsL1405Pt.value.data()), 0., 100); - LOGF(info, "funcMaxBachPiPtVsL1405Pt: %s", Form("%s", cutMaxBachPiPtVsL1405Pt.value.data())); - funcMinSigmaPtVsL1405Pt = TF1("funcMinSigmaPtVsL1405Pt", Form("%s", cutMinSigmaPtVsL1405Pt.value.data()), 0., 100); - LOGF(info, "funcMinSigmaPtVsL1405Pt: %s", Form("%s", cutMinSigmaPtVsL1405Pt.value.data())); - funcMaxSigmaPtVsL1405Pt = TF1("funcMaxSigmaPtVsL1405Pt", Form("%s", cutMaxSigmaPtVsL1405Pt.value.data()), 0., 100); - LOGF(info, "funcMaxSigmaPtVsL1405Pt: %s", Form("%s", cutMaxSigmaPtVsL1405Pt.value.data())); - funcDcaXYPtCutBachPi = TF1("funcDcaXYPtCutBachPi", Form("[0]*%s", dcaXYPtBachFunc.value.data()), 0.001, 100); - funcDcaXYPtCutBachPi.SetParameter(0, dcaXYBachNSigmaMax); - LOGF(info, "DCAxy pt-dependence function: %s", Form("[0]*%s", dcaXYPtBachFunc.value.data())); + funcMinQtAlphaAP = TF1("funcMinQtAlphaAP", Form("%s", selections.cutSigmaQtAPMin.value.data()), -1, 1); + LOGF(info, "funcMinQtAlphaAP: %s", Form("%s", selections.cutSigmaQtAPMin.value.data())); + funcMaxQtAlphaAP = TF1("funcMaxQtAlphaAP", Form("%s", selections.cutSigmaQtAPMax.value.data()), -1, 1); + LOGF(info, "funcMaxQtAlphaAP: %s", Form("%s", selections.cutSigmaQtAPMax.value.data())); + funcMinBachPiPtVsL1405Pt = TF1("funcMinBachPiPtVsL1405Pt", Form("%s", selections.cutMinBachPiPtVsL1405Pt.value.data()), 0., 100); + LOGF(info, "funcMinBachPiPtVsL1405Pt: %s", Form("%s", selections.cutMinBachPiPtVsL1405Pt.value.data())); + funcMaxBachPiPtVsL1405Pt = TF1("funcMaxBachPiPtVsL1405Pt", Form("%s", selections.cutMaxBachPiPtVsL1405Pt.value.data()), 0., 100); + LOGF(info, "funcMaxBachPiPtVsL1405Pt: %s", Form("%s", selections.cutMaxBachPiPtVsL1405Pt.value.data())); + funcMinSigmaPtVsL1405Pt = TF1("funcMinSigmaPtVsL1405Pt", Form("%s", selections.cutMinSigmaPtVsL1405Pt.value.data()), 0., 100); + LOGF(info, "funcMinSigmaPtVsL1405Pt: %s", Form("%s", selections.cutMinSigmaPtVsL1405Pt.value.data())); + funcMaxSigmaPtVsL1405Pt = TF1("funcMaxSigmaPtVsL1405Pt", Form("%s", selections.cutMaxSigmaPtVsL1405Pt.value.data()), 0., 100); + LOGF(info, "funcMaxSigmaPtVsL1405Pt: %s", Form("%s", selections.cutMaxSigmaPtVsL1405Pt.value.data())); + funcDcaXYPtCutBachPi = TF1("funcDcaXYPtCutBachPi", Form("[0]*%s", selections.dcaXYPtBachFunc.value.data()), 0.001, 100); + funcDcaXYPtCutBachPi.SetParameter(0, selections.dcaXYBachNSigmaMax); + LOGF(info, "DCAxy pt-dependence function: %s", Form("[0]*%s", selections.dcaXYPtBachFunc.value.data())); rSelections.print(); rSigmaMinus.print(); @@ -469,20 +502,37 @@ struct lambda1405analysis { rLambda1405.print(); // Info for DCA propagation of bachelor tracks - mRunNumber = 0; - mBz = 0; ccdb->setURL(ccdbPath); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); } + /// Get the binning pool associated to the collision + /// \param collision is the collision + /// \param binPolicy is the binning policy for the correlation + template + int getPoolBin(const TColl& collision, const TBinningType& binPolicy) + { + int poolBin{0}; + float centMult = getCentMult(collision); + poolBin = binPolicy.getBin(std::make_tuple(centMult, collision.posZ())); + if constexpr (std::is_same_v) { + rEventSelection.fill(HIST("hCentPoolBin"), centMult, poolBin); + } else if constexpr (std::is_same_v) { + rEventSelection.fill(HIST("hMultPoolBin"), centMult, poolBin); + } + rEventSelection.fill(HIST("hZVtxPoolBin"), collision.posZ(), poolBin); + rEventSelection.fill(HIST("hPoolBins"), poolBin); + return poolBin; + } + template float getCentMult(const TCollision& collision) { - if constexpr (requires { collision.centFT0C(); }) { + if (useCentrality) { return collision.centFT0C(); } else { - return collision.multFT0C(); + return collision.multFT0M(); } } @@ -517,8 +567,9 @@ struct lambda1405analysis { double massSigma = isSigmaMinus ? o2::constants::physics::MassSigmaMinus : o2::constants::physics::MassSigmaPlus; double pMother = std::sqrt(sigmaPx * sigmaPx + sigmaPy * sigmaPy + sigmaPz * sigmaPz); - if (pMother < 1e-12f) { - LOG(info) << "Recalculation of Sigma momentum failed: mother momentum is zero " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz; + float zeroValTolerance{1e-12f}; + if (pMother < zeroValTolerance) { + LOG(debug) << "Recalculation of Sigma momentum failed: mother momentum is zero " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz; return -999.f; } if (isSigmaMinus) { @@ -537,8 +588,8 @@ struct lambda1405analysis { double B = -4.0 * a * K; double C = 4.0 * eChDau * eChDau * massSigma * massSigma - K * K; - if (std::abs(A) < 1e-6f) { - LOG(info) << "Recalculation of Sigma momentum failed: A is zero " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz << ", A = " << A << ", B = " << B << ", C = " << C; + if (std::abs(A) < zeroValTolerance) { + LOG(debug) << "Recalculation of Sigma momentum failed: A is zero " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz << ", A = " << A << ", B = " << B << ", C = " << C; return -999.f; } if (isSigmaMinus) { @@ -547,22 +598,22 @@ struct lambda1405analysis { rSelections.fill(HIST("hRecalcSigmaPlusMom"), 2); // Non-zero A } - double D = B * B - 4.0 * A * C; - if (D < 0.0) { - LOG(info) << "Recalculation of Sigma momentum failed: D is negative " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz << ", A = " << A << ", B = " << B << ", C = " << C << ", D = " << D; + double det = B * B - 4.0 * A * C; + if (det < 0.0) { + LOG(debug) << "Recalculation of Sigma momentum failed: determinant is negative " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz << ", A = " << A << ", B = " << B << ", C = " << C << ", determinant = " << det; return -999.f; } if (isSigmaMinus) { - rSelections.fill(HIST("hRecalcSigmaMinusMom"), 3); // Positive D + rSelections.fill(HIST("hRecalcSigmaMinusMom"), 3); // Positive determinant } else { - rSelections.fill(HIST("hRecalcSigmaPlusMom"), 3); // Positive D + rSelections.fill(HIST("hRecalcSigmaPlusMom"), 3); // Positive determinant } - double sqrtD = std::sqrt(D); - double P1 = (-B + sqrtD) / (2.0 * A); - double P2 = (-B - sqrtD) / (2.0 * A); - if (P2 < 0.0 && P1 < 0.0) { - LOG(info) << "Recalculation of Sigma momentum failed: both solutions are negative " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz << ", P1: " << P1 << ", P2: " << P2; + double sqrtDet = std::sqrt(det); + double p1 = (-B + sqrtDet) / (2.0 * A); + double p2 = (-B - sqrtDet) / (2.0 * A); + if (p2 < 0.0 && p1 < 0.0) { + LOG(debug) << "Recalculation of Sigma momentum failed: both solutions are negative " << sigmaPx << ", " << sigmaPy << ", " << sigmaPz << ", p1: " << p1 << ", p2: " << p2; return -999.f; } if (isSigmaMinus) { @@ -572,43 +623,40 @@ struct lambda1405analysis { } success = true; - if (P2 < 0.0) { - return static_cast(P1); + if (p2 < 0.0) { + return static_cast(p1); } - if (P1 < 0.0) { - return static_cast(P2); + if (p1 < 0.0) { + return static_cast(p2); } - double p1Diff = std::abs(P1 - pMother); - double p2Diff = std::abs(P2 - pMother); - return static_cast((p1Diff < p2Diff) ? P1 : P2); + double p1Diff = std::abs(p1 - pMother); + double p2Diff = std::abs(p2 - pMother); + return static_cast((p1Diff < p2Diff) ? p1 : p2); } template - bool selectPiBach(const TTrack& candidate, const o2::dataformats::VertexBase& vtx, float centMult) + bool selectPiBach(const TTrack& candidate, float centMult) { - if (std::abs(candidate.tpcNSigmaPi()) > cutNSigTpc) { + if (std::abs(candidate.tpcNSigmaPi()) > selections.cutNSigTpc) { return false; } rSelections.fill(HIST("hSelectionsBachPi"), 2); // Nsigma Tpc - if (candidate.tpcNClsFound() < cutNTpcClus) { + if (candidate.tpcNClsFound() < selections.cutNTpcClus) { return false; } rSelections.fill(HIST("hSelectionsBachPi"), 3); // Tpc clusters - if (std::abs(candidate.eta()) > cutEtaDaughter) { + if (std::abs(candidate.eta()) > selections.cutEtaDaughter) { return false; } rSelections.fill(HIST("hSelectionsBachPi"), 4); // Eta selection - o2::track::TrackParCov trackParCovTrack = getTrackParCov(candidate); - std::array dcaInfoMoth; - o2::base::Propagator::Instance()->propagateToDCABxByBz({vtx.getX(), vtx.getY(), vtx.getZ()}, - trackParCovTrack, 2.f, static_cast(cfgMaterialCorrection.value), - &dcaInfoMoth); - rLambda1405.fill(HIST("h3BachPiDcaXYVsPt"), candidate.pt(), dcaInfoMoth[0], centMult); - rLambda1405.fill(HIST("h3BachPiDcaZVsPt"), candidate.pt(), dcaInfoMoth[1], centMult); - if (std::abs(dcaInfoMoth[0]) > funcDcaXYPtCutBachPi.Eval(candidate.pt()) || std::abs(dcaInfoMoth[1]) > cutMaxDcaZBach) { + std::array dcaInfoBachPi{candidate.dcaXY(), candidate.dcaZ()}; + rLambda1405.fill(HIST("h3BachPiDcaXYVsPt"), candidate.pt(), dcaInfoBachPi[0], centMult); + rLambda1405.fill(HIST("h3BachPiDcaZVsPt"), candidate.pt(), dcaInfoBachPi[1], centMult); + if (std::abs(dcaInfoBachPi[0]) > funcDcaXYPtCutBachPi.Eval(candidate.pt()) || + std::abs(dcaInfoBachPi[1]) > selections.cutMaxDcaZBach) { return false; } rSelections.fill(HIST("hSelectionsBachPi"), 5); // DCA selection @@ -621,22 +669,22 @@ struct lambda1405analysis { { rSelections.fill(HIST("hSelectionsKinkPi"), 0); // All pion kink candidates - if (std::abs(candidate.tpcNSigmaPi()) > cutNSigTpc) { + if (std::abs(candidate.tpcNSigmaPi()) > selections.cutNSigTpc) { return false; } rSelections.fill(HIST("hSelectionsKinkPi"), 1); // Nsigma Tpc - if (candidate.tpcNClsFound() < cutNTpcClus) { + if (candidate.tpcNClsFound() < selections.cutNTpcClus) { return false; } rSelections.fill(HIST("hSelectionsKinkPi"), 2); // Tpc clusters - if (std::abs(candidate.eta()) > cutEtaDaughter) { + if (std::abs(candidate.eta()) > selections.cutEtaDaughter) { return false; } rSelections.fill(HIST("hSelectionsKinkPi"), 3); // Eta selection - if (candidate.itsNCls() < cutItsNClusKinkMin || candidate.itsNCls() > cutItsNClusKinkMax) { + if (candidate.itsNCls() < selections.cutItsNClusKinkMin || candidate.itsNCls() > selections.cutItsNClusKinkMax) { return false; } rSelections.fill(HIST("hSelectionsKinkPi"), 4); // ITS clusters @@ -646,7 +694,7 @@ struct lambda1405analysis { } rSelections.fill(HIST("hSelectionsKinkPi"), 5); // has Tof - if (useTof && std::abs(candidate.tofNSigmaPi()) > cutNSigTof) { + if (useTof && std::abs(candidate.tofNSigmaPi()) > selections.cutNSigTof) { return false; } rSelections.fill(HIST("hSelectionsKinkPi"), 6); // Nsigma Tof @@ -659,22 +707,22 @@ struct lambda1405analysis { { rSelections.fill(HIST("hSelectionsKinkPr"), 0); // All proton kink candidates - if (std::abs(candidate.tpcNSigmaPr()) > cutNSigTpc) { + if (std::abs(candidate.tpcNSigmaPr()) > selections.cutNSigTpc) { return false; } rSelections.fill(HIST("hSelectionsKinkPr"), 1); // Nsigma Tpc - if (candidate.tpcNClsFound() < cutNTpcClus) { + if (candidate.tpcNClsFound() < selections.cutNTpcClus) { return false; } rSelections.fill(HIST("hSelectionsKinkPr"), 2); // Tpc clusters - if (std::abs(candidate.eta()) > cutEtaDaughter) { + if (std::abs(candidate.eta()) > selections.cutEtaDaughter) { return false; } rSelections.fill(HIST("hSelectionsKinkPr"), 3); // eta selection - if (candidate.itsNCls() < cutItsNClusKinkMin || candidate.itsNCls() > cutItsNClusKinkMax) { + if (candidate.itsNCls() < selections.cutItsNClusKinkMin || candidate.itsNCls() > selections.cutItsNClusKinkMax) { return false; } rSelections.fill(HIST("hSelectionsKinkPr"), 4); // ITS clusters @@ -684,7 +732,7 @@ struct lambda1405analysis { } rSelections.fill(HIST("hSelectionsKinkPr"), 5); // has Tof - if (useTof && std::abs(candidate.tofNSigmaPr()) > cutNSigTof) { + if (useTof && std::abs(candidate.tofNSigmaPr()) > selections.cutNSigTof) { return false; } rSelections.fill(HIST("hSelectionsKinkPr"), 6); // Nsigma Tof @@ -744,24 +792,8 @@ struct lambda1405analysis { rLambda1405.fill(HIST("h2BachPiPtNSigTpc"), cand.bachPiPt, cand.bachPiNSigTpc); rLambda1405.fill(HIST("h2BachPiPtNSigTof"), cand.bachPiPt, cand.bachPiNSigTof); - // std::vector axesMass = {lambda1405MassAxis, ptAxis, sigmaMassAxis, dcaSigmaToPvAxis, dcaKinkToPvAxis}; - // if (doprocessMc || doprocessMcWCentSel) { - // axesMass.push_back(pvContribAxis); - // } else { - // axesMass.push_back(centMultAxis); - // } - // rLambda1405.add("hSparseL1405", "THn for mass peak", HistType::kTHnSparseF, axes); - // std::vector axesScalarProd = {lambda1405MassAxis, ptAxis, sigmaMassAxis, dcaSigmaToPvAxis, dcaKinkToPvAxis, centMultAxis, scalarProdAxis}; - // if (doprocessDataWCentQVecs) { - // rLambda1405.add("hSparseL1405ScalProd", "THn for SP", HistType::kTHnSparseF, axesScalarProd); - // } - // std::vector axesCorrel = {lambda1405MassAxis, ptAxis, deltaEtaAxis, deltaPhiAxis}; - // if (saveDEtaDPhi) { - // rLambda1405.add("hSparseL1405Correl", "THn for 2PC", HistType::kTHnSparseF, axesCorrel); - // } - auto hSparseMass = rLambda1405.get(HIST("hSparseL1405")); - std::vector sparseMassEntry = {cand.massL1405, cand.pt(), cand.sigmaMinusMass, cand.dcaSigmaToPv, cand.kinkDcaDauToPv}; + std::vector sparseMassEntry = {static_cast(cand.poolBin), cand.massL1405, cand.pt(), cand.sigmaMinusMass, cand.dcaSigmaToPv, cand.kinkDcaDauToPv}; if constexpr (IsMC) { sparseMassEntry.push_back(cand.pvContrib); } else { @@ -769,14 +801,14 @@ struct lambda1405analysis { } hSparseMass->Fill(sparseMassEntry.data()); if constexpr (FillQVectors) { - std::vector sparseScalProdEntry = {cand.massL1405, cand.pt(), cand.sigmaMinusMass, cand.dcaSigmaToPv, cand.kinkDcaDauToPv}; + std::vector sparseScalProdEntry = {static_cast(cand.poolBin), cand.massL1405, cand.pt(), cand.sigmaMinusMass, cand.dcaSigmaToPv, cand.kinkDcaDauToPv}; sparseScalProdEntry.push_back(cand.centMult); sparseScalProdEntry.push_back(cand.scalarProd); auto hSparseScalProd = rLambda1405.get(HIST("hSparseL1405ScalProd")); hSparseScalProd->Fill(sparseScalProdEntry.data()); } if constexpr (FillCorrelations) { - std::vector sparseCorrelEntry = {cand.massL1405, cand.pt(), cand.sigmaMinusMass, cand.dcaSigmaToPv, cand.kinkDcaDauToPv}; + std::vector sparseCorrelEntry = {static_cast(cand.poolBin), cand.massL1405, cand.pt()}; auto hSparseCorrel = rLambda1405.get(HIST("hSparseL1405Correl")); sparseCorrelEntry.push_back(0.0); // Δη sparseCorrelEntry.push_back(0.0); // Δφ @@ -804,37 +836,22 @@ struct lambda1405analysis { } } - void initCCDB(aod::BCs::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - mRunNumber = bc.runNumber(); - LOG(info) << "Initializing CCDB for run " << mRunNumber; - o2::parameters::GRPMagField* grpmag = ccdb->getForRun(grpmagPath, mRunNumber); - o2::base::Propagator::initFieldFromGRP(grpmag); - mBz = grpmag->getNominalL3Field(); - - if (!lut) { - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); - } - o2::base::Propagator::Instance()->setMatLUT(lut); - LOG(info) << "Task initialized for run " << mRunNumber << " with magnetic field " << mBz << " kZG"; - } - - template - void constructCollCandidates(const TColl& collision, aod::KinkCands::iterator const& sigmaCand, TracksFull const& tracks, std::vector& selectedCandidates) + template + void constructCollCandidates(const TColl& collision, + aod::KinkCands::iterator const& sigmaCand, + TracksFull const& tracks, + std::vector& selectedCandidates, + TBinningType binPolicy) { - // Retrieve primary vertex, once for all candidates in the collision - auto const& bc = collision.template bc_as(); - initCCDB(bc); - o2::dataformats::VertexBase primaryVertex; - primaryVertex.setPos({collision.posX(), collision.posY(), collision.posZ()}); - primaryVertex.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); - lambda1405candidate lambda1405Cand{}; + if constexpr (!IsMc) { + // Set pool bin + int const poolBin = getPoolBin(collision, binPolicy); + lambda1405Cand.poolBin = poolBin; + } + rSelections.fill(HIST("hSelectionsL1405"), 0); // All candidates rSelections.fill(HIST("hSelectionsSigmaMinus"), 0); // All Sigma- candidates rSelections.fill(HIST("hSelectionsSigmaPlus"), 0); // All Sigma+ candidates @@ -907,12 +924,12 @@ struct lambda1405analysis { rSigmaPlus.fill(HIST("h2PtPrKinkNSigBeforeCuts"), kinkDauTrack.pt(), kinkDauTrack.tpcNSigmaPr()); } - if (lambda1405Cand.isSigmaMinus && (sigmaCand.mSigmaMinus() < o2::constants::physics::MassSigmaMinus - cutSigmaMass || - sigmaCand.mSigmaMinus() > o2::constants::physics::MassSigmaMinus + cutSigmaMass)) { + if (lambda1405Cand.isSigmaMinus && (sigmaCand.mSigmaMinus() < o2::constants::physics::MassSigmaMinus - selections.cutSigmaMass || + sigmaCand.mSigmaMinus() > o2::constants::physics::MassSigmaMinus + selections.cutSigmaMass)) { return; } - if (lambda1405Cand.isSigmaPlus && (sigmaCand.mSigmaPlus() < o2::constants::physics::MassSigmaPlus - cutSigmaMass || - sigmaCand.mSigmaPlus() > o2::constants::physics::MassSigmaPlus + cutSigmaMass)) { + if (lambda1405Cand.isSigmaPlus && (sigmaCand.mSigmaPlus() < o2::constants::physics::MassSigmaPlus - selections.cutSigmaMass || + sigmaCand.mSigmaPlus() > o2::constants::physics::MassSigmaPlus + selections.cutSigmaMass)) { return; } if (lambda1405Cand.isSigmaMinus) { @@ -921,7 +938,7 @@ struct lambda1405analysis { rSelections.fill(HIST("hSelectionsSigmaPlus"), 3); // Passed mass sel } - if (std::abs(sigmaCand.dcaMothPv()) > cutDcaToPvSigma) { + if (std::abs(sigmaCand.dcaMothPv()) > selections.cutDcaToPvSigma) { return; } if (lambda1405Cand.isSigmaMinus) { @@ -930,7 +947,7 @@ struct lambda1405analysis { rSelections.fill(HIST("hSelectionsSigmaPlus"), 4); // Passed cutDcaToPvSigma } - if (std::abs(sigmaCand.dcaDaugPv()) < cutDcaToPvPiFromSigma) { + if (std::abs(sigmaCand.dcaDaugPv()) < selections.cutDcaToPvPiFromSigma) { return; } if (lambda1405Cand.isSigmaMinus) { @@ -940,7 +957,7 @@ struct lambda1405analysis { } float sigmaRad = std::hypot(sigmaCand.xDecVtx(), sigmaCand.yDecVtx()); - if (sigmaRad < cutSigmaRadius) { + if (sigmaRad < selections.cutSigmaRadius) { return; } if (lambda1405Cand.isSigmaMinus) { @@ -1010,7 +1027,7 @@ struct lambda1405analysis { } rSelections.fill(HIST("hSelectionsBachPi"), 1); - if (!selectPiBach(piTrack, primaryVertex, lambda1405Cand.centMult)) { + if (!selectPiBach(piTrack, lambda1405Cand.centMult)) { continue; } rSelections.fill(HIST("hSelectionsL1405"), 2); // Bach Pi selection @@ -1022,7 +1039,7 @@ struct lambda1405analysis { } else if (lambda1405Cand.isSigmaPlus) { invMass = RecoDecay::m(std::array{sigmaMom, piMom}, std::array{o2::constants::physics::MassSigmaPlus, o2::constants::physics::MassPiMinus}); } - if (invMass > cutUpperMass) { + if (invMass > selections.cutUpperMass) { continue; } rSelections.fill(HIST("hSelectionsL1405"), 3); // Upper mass selection @@ -1065,7 +1082,7 @@ struct lambda1405analysis { } rSelections.fill(HIST("hSelectionsL1405"), 4); // Pt correlations - if (lambda1405Cand.pt() < cutMinPtL1405) { + if (lambda1405Cand.pt() < selections.cutMinPtL1405) { continue; } rSelections.fill(HIST("hSelectionsL1405"), 5); // Accepted @@ -1079,20 +1096,16 @@ struct lambda1405analysis { template bool checkSigmaKinkMC(const mcTrack& mcTrackSigma, const mcTrack& mcTrackKinkDau, float sigmaAbsPDG, float kinkAbsPDG, aod::McParticles const&) { - LOG(info) << "Checking Sigma kink decay for MC tracks: Sigma PDG = " << mcTrackSigma.pdgCode() << ", Kink daughter PDG = " << mcTrackKinkDau.pdgCode(); if (std::abs(mcTrackSigma.pdgCode()) != sigmaAbsPDG || std::abs(mcTrackKinkDau.pdgCode()) != kinkAbsPDG) { - LOG(info) << "PDG codes do not match expected values: Sigma PDG = " << sigmaAbsPDG << ", Kink daughter PDG = " << kinkAbsPDG; return false; // Not a valid Sigma kink decay } if (!mcTrackKinkDau.has_mothers()) { - LOG(info) << "Kink daughter has no 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()) { - LOG(info) << "Kink daughter comes from the Sigma"; isKinkFromSigma = true; break; } @@ -1100,15 +1113,15 @@ struct lambda1405analysis { return isKinkFromSigma; // Return true if the kink comes from the Sigma } - template - void fillOutputData(const TCollision& collision, const TCand& sigmaCands, const TTrack& tracks) + template + void fillOutputData(const TCollision& collision, const TCand& sigmaCands, const TTrack& tracks, TBinningType binPolicy) { - if (std::abs(collision.posZ()) > cutZVertex || !collision.sel8()) { + if (std::abs(collision.posZ()) > eventSelection.cutZVertex || !collision.sel8()) { return; } rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); float centMult = getCentMult(collision); - if (centMult < centMultMin || centMult > centMultMax) { + if (centMult < eventSelection.centMultMin || centMult > eventSelection.centMultMax) { return; } rEventSelection.fill(HIST("hCentMultVsPvContrib"), centMult, collision.numContrib()); @@ -1117,7 +1130,7 @@ struct lambda1405analysis { for (const auto& sigmaCand : sigmaCands) { std::vector selectedCandidates; - constructCollCandidates(collision, sigmaCand, tracks, selectedCandidates); + constructCollCandidates(collision, sigmaCand, tracks, selectedCandidates, binPolicy); for (const auto& lambda1405Cand : selectedCandidates) { if (lambda1405Cand.isSigmaMinus) { rLambda1405.fill(HIST("h2SigmaMinusMassVsLambdaMass"), lambda1405Cand.massL1405, lambda1405Cand.sigmaMinusMass); @@ -1142,17 +1155,8 @@ struct lambda1405analysis { lambda1405Cand.kinkPrNSigTpc, lambda1405Cand.kinkPrNSigTof, lambda1405Cand.kinkDcaDauToPv, lambda1405Cand.bachPiNSigTpc, lambda1405Cand.bachPiNSigTof, - lambda1405Cand.centMult, lambda1405Cand.occupancy); - } else { - outputDataFlowTable(ptCand, lambda1405Cand.massL1405, - lambda1405Cand.sigmaPt, - lambda1405Cand.sigmaMinusMass, lambda1405Cand.sigmaPlusMass, - lambda1405Cand.sigmaAlphaAP, lambda1405Cand.sigmaQtAP, - lambda1405Cand.kinkPiNSigTpc, lambda1405Cand.kinkPiNSigTof, - lambda1405Cand.kinkPrNSigTpc, lambda1405Cand.kinkPrNSigTof, - lambda1405Cand.kinkDcaDauToPv, - lambda1405Cand.bachPiNSigTpc, lambda1405Cand.bachPiNSigTof, - lambda1405Cand.scalarProd, lambda1405Cand.centMult); + lambda1405Cand.scalarProd, + lambda1405Cand.centMult, lambda1405Cand.occupancy, lambda1405Cand.poolBin); // 24 } } @@ -1174,23 +1178,93 @@ struct lambda1405analysis { } } - void processData(CollisionsFull::iterator const& collision, - aod::KinkCands const& kinkCands, - TracksFull const& tracks, - const aod::BCs&) + void processDataSameEvent(CollisionsSel::iterator const& collision, + aod::KinkCands const& kinkCands, + TracksFull const& tracks, + const aod::BCs&) + { + if (useCentrality) { + BinningCentPosZ binPolicy{{centMultPoolBins, zPoolBins}, true}; + fillOutputData(collision, kinkCands, tracks, binPolicy); + } else { + BinningMultPosZ binPolicy{{centMultPoolBins, zPoolBins}, true}; + fillOutputData(collision, kinkCands, tracks, binPolicy); + } + } + PROCESS_SWITCH(lambda1405analysis, processDataSameEvent, "Data processing", true); + + void processDataWQVecsSameEvent(CollisionsSelWQVecs::iterator const& collision, + aod::KinkCands const& kinkCands, + TracksFull const& tracks, + const aod::BCs&) { - fillOutputData(collision, kinkCands, tracks); + BinningCentPosZ binPolicy{{centMultPoolBins, zPoolBins}, true}; + fillOutputData(collision, kinkCands, tracks, binPolicy); } - PROCESS_SWITCH(lambda1405analysis, processData, "Data processing", true); + PROCESS_SWITCH(lambda1405analysis, processDataWQVecsSameEvent, "Data processing with centrality and Q vectors info", false); - void processDataWCentQVecs(CollisionsCentSel::iterator const& collision, + void processDataMixedEvent(CollisionsFull const& collisions, aod::KinkCands const& kinkCands, TracksFull const& tracks, const aod::BCs&) { - fillOutputData(collision, kinkCands, tracks); + auto pairsTuple = std::make_tuple(kinkCands, tracks); + if (useCentrality) { + BinningCentPosZ binPolicy{{centMultPoolBins, zPoolBins}, true}; + Pair const pairs{binPolicy, numberEventsMixed, -1, collisions, pairsTuple, &cache}; + for (const auto& [sigmasColl, sigmas, bachPisColl, bachPis] : pairs) { + if (sigmas.size() == 0 || bachPis.size() == 0) { + continue; + } + int const poolBinSigma = getPoolBin(sigmasColl, binPolicy); + int const poolBinBachPi = getPoolBin(bachPisColl, binPolicy); + if (poolBinBachPi != poolBinSigma) { + LOG(debug) << "Different poolBins for sigma and bachelor pi: " << poolBinSigma << " vs " << poolBinBachPi; + continue; + } + fillOutputData(sigmasColl, sigmas, bachPis, binPolicy); + } + } else { + BinningMultPosZ binPolicy{{centMultPoolBins, zPoolBins}, true}; + Pair const pairs{binPolicy, numberEventsMixed, -1, collisions, pairsTuple, &cache}; + for (const auto& [sigmasColl, sigmas, bachPisColl, bachPis] : pairs) { + if (sigmas.size() == 0 || bachPis.size() == 0) { + continue; + } + int const poolBinSigma = getPoolBin(sigmasColl, binPolicy); + int const poolBinBachPi = getPoolBin(bachPisColl, binPolicy); + if (poolBinBachPi != poolBinSigma) { + LOG(debug) << "Different poolBins for sigma and bachelor pi: " << poolBinSigma << " vs " << poolBinBachPi; + continue; + } + fillOutputData(sigmasColl, sigmas, bachPis, binPolicy); + } + } } - PROCESS_SWITCH(lambda1405analysis, processDataWCentQVecs, "Data processing with centrality and Q vectors info", false); + PROCESS_SWITCH(lambda1405analysis, processDataMixedEvent, "Data event mixing processing", false); + + void processDataWQVecsMixedEvent(CollisionsSelWQVecs const& collisions, + aod::KinkCands const& kinkCands, + TracksFull const& tracks, + const aod::BCs&) + { + auto pairsTuple = std::make_tuple(kinkCands, tracks); + BinningCentPosZ binPolicy{{centMultPoolBins, zPoolBins}, true}; + Pair const pairs{binPolicy, numberEventsMixed, -1, collisions, pairsTuple, &cache}; + for (const auto& [sigmasColl, sigmas, bachPisColl, bachPis] : pairs) { + if (sigmas.size() == 0 || bachPis.size() == 0) { + continue; + } + int const poolBinSigma = getPoolBin(sigmasColl, binPolicy); + int const poolBinBachPi = getPoolBin(bachPisColl, binPolicy); + if (poolBinBachPi != poolBinSigma) { + LOG(debug) << "Different poolBins for sigma and bachelor pi: " << poolBinSigma << " vs " << poolBinBachPi; + continue; + } + fillOutputData(sigmasColl, sigmas, bachPis, binPolicy); + } + } + PROCESS_SWITCH(lambda1405analysis, processDataWQVecsMixedEvent, "Data event mixing with centrality and Q vectors info", false); template int matchGenDecay(const TMother& motherPart, const aod::McParticles& mcParticles, std::array& daugsIdxs) @@ -1271,42 +1345,31 @@ struct lambda1405analysis { const TTrack& tracks, const aod::McParticles& particlesMC) { - LOG(info) << "Filling output MC for " << recoCollisions.size() << " collisions, " << sigmaCands.size() << " Sigma candidates, and " << tracks.size() << " tracks"; for (const auto& collision : recoCollisions) { - LOG(info) << "\n\nProcessing collision with global index: " << collision.globalIndex() << " and " << sigmaCands.size() << " Sigma candidates, and " << tracks.size() << " tracks"; - if (std::abs(collision.posZ()) > cutZVertex) { // || !collision.sel8()) { - LOG(info) << "Collision failed Z vertex cut: " << collision.posZ(); + if (std::abs(collision.posZ()) > eventSelection.cutZVertex) { // || !collision.sel8()) { continue; } - LOG(info) << "Collision passed Z vertex cut: " << collision.posZ(); rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); float centMult = getCentMult(collision); - LOG(info) << "Collision centrality: " << centMult; - if (centMult < centMultMin || centMult > centMultMax) { - LOG(info) << "Collision failed centrality cut: " << centMult; + if (centMult < eventSelection.centMultMin || centMult > eventSelection.centMultMax) { continue; } - LOG(info) << "Collision passed centrality cut: " << centMult; rEventSelection.fill(HIST("hCentMultVsPvContrib"), centMult, collision.numContrib()); rEventSelection.fill(HIST("hOccVsPvContrib"), collision.ft0cOccupancyInTimeRange(), collision.numContrib()); rEventSelection.fill(HIST("hCentVsOcc"), centMult, collision.ft0cOccupancyInTimeRange()); auto sigmaCandsPerCol = sigmaCands.sliceBy(mKinkPerCol, collision.globalIndex()); auto tracksPerCol = tracks.sliceBy(mPerColTracks, collision.globalIndex()); - LOG(info) << "Start loop on " << sigmaCandsPerCol.size() << " Sigma candidates ... "; for (const auto& sigmaCand : sigmaCandsPerCol) { - LOG(info) << "Processing Sigma candidate with global index: " << sigmaCand.globalIndex(); // Perform the sigma matching here, so sigma histograms // can be used for efficiency studies on the sigma auto labelSigma = trackLabelsMC.rawIteratorAt(sigmaCand.trackMothId()); auto labelKinkDaug = trackLabelsMC.rawIteratorAt(sigmaCand.trackDaugId()); if (!labelSigma.has_mcParticle()) { - LOG(info) << "Sigma candidate with global index: " << sigmaCand.globalIndex() << " is not matched to MC particle"; rSelections.fill(HIST("hRecoNotMatchedCounter"), 1); // Sigma not matched } if (!labelKinkDaug.has_mcParticle()) { - LOG(info) << "Kink daughter candidate with global index: " << sigmaCand.globalIndex() << " is not matched to MC particle"; rSelections.fill(HIST("hRecoNotMatchedCounter"), 2); // Kink daughter not matched } auto genSigma = labelSigma.template mcParticle_as(); @@ -1317,21 +1380,17 @@ struct lambda1405analysis { bool isSigmaPlusToPrKink = checkSigmaKinkMC(genSigma, genKinkDaug, PDG_t::kSigmaPlus, PDG_t::kProton, particlesMC); if (!isSigmaMinusKink && !isSigmaPlusToPiKink && !isSigmaPlusToPrKink) { - LOG(info) << "Candidate is not a valid Sigma kink decay, skipping ..."; continue; // Skip if not a valid Sigma kink decay } if (isSigmaMinusKink) { - LOG(info) << "Filling h2DeltaGenRecoPtSigmaMinus with: " << sigmaCand.ptMoth() - genSigma.pt() << ", " << sigmaCand.ptMoth(); rSigmaMinus.fill(HIST("h2DeltaGenRecoPtSigmaMinus"), sigmaCand.ptMoth() - genSigma.pt(), sigmaCand.ptMoth()); } if (isSigmaPlusToPiKink || isSigmaPlusToPrKink) { - LOG(info) << "Filling h2DeltaGenRecoPtSigmaPlus with: " << sigmaCand.ptMoth() - genSigma.pt() << ", " << sigmaCand.ptMoth(); rSigmaPlus.fill(HIST("h2DeltaGenRecoPtSigmaPlus"), sigmaCand.ptMoth() - genSigma.pt(), sigmaCand.ptMoth()); } - std::vector selectedCandidates; - LOG(info) << "Constructing Lambda(1405) candidates from Sigma candidate with global index: " << sigmaCand.globalIndex(); - constructCollCandidates(collision, sigmaCand, tracksPerCol, selectedCandidates); + const int dummyPoolBin{-1}; // Not used in MC, but required by the function signature + constructCollCandidates(collision, sigmaCand, tracksPerCol, selectedCandidates, dummyPoolBin); for (const auto& lambda1405Cand : selectedCandidates) { rLambda1405.fill(HIST("hRecoL1405"), 0., lambda1405Cand.pt()); // All reconstructed @@ -1476,16 +1535,197 @@ struct lambda1405analysis { } PROCESS_SWITCH(lambda1405analysis, processMc, "MC processing", false); - void processMcWCentSel(McRecoCollisionsCentSel const& recoCollisions, - aod::KinkCands const& kinkCands, - aod::McTrackLabels const& trackLabelsMC, - aod::McParticles const& particlesMC, - TracksFull const& tracks, - const aod::BCs&) + void processMcSigmasCentSel(McRecoCollisionsSel const& recoCollisions, + aod::KinkCands const& sigmaCands, + aod::McTrackLabels const& trackLabelsMC, + aod::McParticles const& particlesMC, + aod::McCollisions const&, + const aod::BCs&) { - fillOutputMc(recoCollisions, kinkCands, trackLabelsMC, tracks, particlesMC); + // Loop over kink candidates to fill Sigma efficiency histograms + for (const auto& collision : recoCollisions) { + if (std::abs(collision.posZ()) > eventSelection.cutZVertex) { // || !collision.sel8()) { + continue; + } + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); + float centMult = getCentMult(collision); + if (centMult < eventSelection.centMultMin || centMult > eventSelection.centMultMax) { + continue; + } + + rEventSelection.fill(HIST("hCentMultVsPvContrib"), centMult, collision.numContrib()); + rEventSelection.fill(HIST("hOccVsPvContrib"), collision.ft0cOccupancyInTimeRange(), collision.numContrib()); + rEventSelection.fill(HIST("hCentVsOcc"), centMult, collision.ft0cOccupancyInTimeRange()); + + // Compute occupancy and pv contrib of the generated collision + const auto& recoCollsPerMcColl = recoCollisions.sliceBy(colPerMcCollision, collision.mcCollisionId()); + if (recoCollsPerMcColl.size() == 0) { + continue; // Skip if no reconstructed collisions associated with this MC collision + } + unsigned genNumContrib = 0; + float genOcc{0.f}; + float genCentMult{0.f}; + for (const auto& recCol : recoCollsPerMcColl) { + genNumContrib = recCol.numContrib() > genNumContrib ? recCol.numContrib() : genNumContrib; + genOcc = recCol.ft0cOccupancyInTimeRange() > genOcc ? recCol.ft0cOccupancyInTimeRange() : genOcc; + genCentMult = getCentMult(collision) > genCentMult ? getCentMult(collision) : genCentMult; + } + + auto sigmaCandsPerCol = sigmaCands.sliceBy(mKinkPerCol, collision.globalIndex()); + for (const auto& sigmaCand : sigmaCandsPerCol) { + + auto labelSigma = trackLabelsMC.rawIteratorAt(sigmaCand.trackMothId()); + auto labelKinkDaug = trackLabelsMC.rawIteratorAt(sigmaCand.trackDaugId()); + if (!labelSigma.has_mcParticle() || !labelKinkDaug.has_mcParticle()) { + continue; // No generated particles + } + auto genSigma = labelSigma.template mcParticle_as(); + auto genKinkDaug = labelKinkDaug.template mcParticle_as(); + + bool isSigmaMinusKink = checkSigmaKinkMC(genSigma, genKinkDaug, PDG_t::kSigmaMinus, PDG_t::kPiPlus, particlesMC); + bool isSigmaPlusToPiKink = checkSigmaKinkMC(genSigma, genKinkDaug, PDG_t::kSigmaPlus, PDG_t::kPiPlus, particlesMC); + bool isSigmaPlusToPrKink = checkSigmaKinkMC(genSigma, genKinkDaug, PDG_t::kSigmaPlus, PDG_t::kProton, particlesMC); + + if (skipBkgSigmas && (!isSigmaMinusKink && !isSigmaPlusToPiKink && !isSigmaPlusToPrKink)) { + continue; // Skip if not a valid Sigma kink decay + } + + float sigmaPt = sigmaCand.ptMoth(); + if (downSampleFactor < 1.) { + float const pseudoRndm = sigmaPt * 1000. - static_cast(sigmaPt * 1000); + if (sigmaPt < ptDownSampleMax && pseudoRndm >= downSampleFactor) { + continue; + } + } + + std::array sigmaMomReco{sigmaCand.pxMoth(), sigmaCand.pyMoth(), sigmaCand.pzMoth()}; + std::array kinkMomReco{sigmaCand.pxDaug(), sigmaCand.pyDaug(), sigmaCand.pzDaug()}; + float recoSigmaAlphaAP = alphaAP(sigmaMomReco, kinkMomReco); + float recoSigmaQtAP = qtAP(sigmaMomReco, kinkMomReco); + + // Recompute the sigma momentum + bool success{false}; + float sigmaPRecalc = recalcSigmaMom(success, isSigmaMinusKink, + sigmaCand.pxMoth(), sigmaCand.pyMoth(), sigmaCand.pzMoth(), + sigmaCand.pxDaug(), sigmaCand.pyDaug(), sigmaCand.pzDaug()); + if (!success && skipSigmasFailedRecompMom) { + return; + } + if (success) { + float sigmaPOriginal = std::sqrt(sigmaCand.pxMoth() * sigmaCand.pxMoth() + + sigmaCand.pyMoth() * sigmaCand.pyMoth() + + sigmaCand.pzMoth() * sigmaCand.pzMoth()); + if (sigmaPRecalc > 0.f && sigmaPOriginal > 0.f) { + float scale = sigmaPRecalc / sigmaPOriginal; + sigmaMomReco[0] *= scale; + sigmaMomReco[1] *= scale; + sigmaMomReco[2] *= scale; + + sigmaPt = std::sqrt(sigmaMomReco[0] * sigmaMomReco[0] + sigmaMomReco[1] * sigmaMomReco[1]); + if (isSigmaMinusKink) { + rSigmaMinus.fill(HIST("hDeltaPxRecalcSigmaMinus"), sigmaMomReco[0] - sigmaCand.pxMoth(), sigmaCand.pxMoth()); + rSigmaMinus.fill(HIST("hDeltaPyRecalcSigmaMinus"), sigmaMomReco[1] - sigmaCand.pyMoth(), sigmaCand.pyMoth()); + rSigmaMinus.fill(HIST("hDeltaPzRecalcSigmaMinus"), sigmaMomReco[2] - sigmaCand.pzMoth(), sigmaCand.pzMoth()); + rSigmaMinus.fill(HIST("hRecalcPtFactorSigmaMinus"), scale, sigmaPOriginal); + } else { + rSigmaPlus.fill(HIST("hDeltaPxRecalcSigmaPlus"), sigmaMomReco[0] - sigmaCand.pxMoth(), sigmaCand.pxMoth()); + rSigmaPlus.fill(HIST("hDeltaPyRecalcSigmaPlus"), sigmaMomReco[1] - sigmaCand.pyMoth(), sigmaCand.pyMoth()); + rSigmaPlus.fill(HIST("hDeltaPzRecalcSigmaPlus"), sigmaMomReco[2] - sigmaCand.pzMoth(), sigmaCand.pzMoth()); + rSigmaPlus.fill(HIST("hRecalcPtFactorSigmaPlus"), scale, sigmaPOriginal); + } + } + } + + float recoRecalcPtSigmaAlphaAP = alphaAP(sigmaMomReco, kinkMomReco); + float recoRecalcPtSigmaQtAP = qtAP(sigmaMomReco, kinkMomReco); + float massSigma = isSigmaMinusKink ? sigmaCand.mSigmaMinus() : sigmaCand.mSigmaPlus(); + + // Generated properties + float genMassSigma{-1.f}; + if (isSigmaMinusKink || isSigmaPlusToPiKink || isSigmaPlusToPrKink) { + genMassSigma = std::sqrt(genSigma.e() * genSigma.e() - genSigma.p() * genSigma.p()); + std::array sigmaMomGen{sigmaCand.pxMoth(), sigmaCand.pyMoth(), sigmaCand.pzMoth()}; + std::array kinkMomGen{sigmaCand.pxDaug(), sigmaCand.pyDaug(), sigmaCand.pzDaug()}; + float genSigmaAlphaAP = alphaAP(sigmaMomGen, kinkMomGen); + float genSigmaQtAP = qtAP(sigmaMomGen, kinkMomGen); + float sigmaRadius = std::hypot(genKinkDaug.vx(), genKinkDaug.vy()); + if (isSigmaMinusKink) { + rSigmaMinus.fill(HIST("hSparseGenFromRecoSigmaMinus"), genMassSigma, genSigma.pt(), genSigmaAlphaAP, genSigmaQtAP, sigmaRadius, genCentMult, genNumContrib, genOcc); + } else if (isSigmaPlusToPiKink || isSigmaPlusToPrKink) { + rSigmaPlus.fill(HIST("hSparseGenFromRecoSigmaPlus"), genMassSigma, genSigma.pt(), genSigmaAlphaAP, genSigmaQtAP, sigmaRadius, genCentMult, genNumContrib, genOcc); + } + } + + // Fill table with sigma properties for efficiency studies + outputSigmaEffMC( + sigmaCand.pxMoth(), sigmaCand.pxMoth() - genSigma.px(), + sigmaCand.pyMoth(), sigmaCand.pyMoth() - genSigma.py(), + sigmaCand.pzMoth(), sigmaCand.pzMoth() - genSigma.pz(), + massSigma, massSigma - genMassSigma, + sigmaCand.pxMoth() - sigmaMomReco[0], + sigmaCand.pyMoth() - sigmaMomReco[1], + sigmaCand.pzMoth() - sigmaMomReco[2], + genSigma.phi(), + genSigma.eta(), + sigmaCand.pxDaug(), sigmaCand.pxDaug() - genKinkDaug.px(), + sigmaCand.pyDaug(), sigmaCand.pyDaug() - genKinkDaug.py(), + sigmaCand.pzDaug(), sigmaCand.pzDaug() - genKinkDaug.pz(), + genKinkDaug.phi(), + genKinkDaug.eta(), + sigmaCand.xDecVtx(), sigmaCand.xDecVtx() - genKinkDaug.vx(), + sigmaCand.yDecVtx(), sigmaCand.yDecVtx() - genKinkDaug.vy(), + sigmaCand.zDecVtx(), sigmaCand.zDecVtx() - genKinkDaug.vz(), + recoSigmaAlphaAP, recoSigmaQtAP, + recoRecalcPtSigmaAlphaAP, recoRecalcPtSigmaQtAP, + sigmaCand.dcaDaugPv(), sigmaCand.dcaMothPv(), + genSigma.pdgCode(), genKinkDaug.pdgCode(), + centMult, collision.ft0cOccupancyInTimeRange(), collision.numContrib()); + } + } + + // generated sigmas + for (const auto& genSigma : particlesMC) { + if (std::abs(genSigma.pdgCode()) != PDG_t::kSigmaMinus && std::abs(genSigma.pdgCode()) != PDG_t::kSigmaPlus) { + continue; // Only consider Sigma candidates + } + + const auto& recoCollsPerMcColl = recoCollisions.sliceBy(colPerMcCollision, genSigma.mcCollision().globalIndex()); + if (recoCollsPerMcColl.size() == 0) { + continue; // Skip if no reconstructed collisions associated with this MC collision + } + + unsigned genNumContrib = 0; + float genOcc{0.f}; + float genCentMult{0.f}; + for (const auto& recCol : recoCollsPerMcColl) { + genNumContrib = recCol.numContrib() > genNumContrib ? recCol.numContrib() : genNumContrib; + genOcc = recCol.ft0cOccupancyInTimeRange() > genOcc ? recCol.ft0cOccupancyInTimeRange() : genOcc; + genCentMult = getCentMult(recCol) > genCentMult ? getCentMult(recCol) : genCentMult; + } + + // Check the sigma daughter of the kink decay + std::vector arrSigmaDaugs = {}; + RecoDecay::getDaughters(genSigma, &arrSigmaDaugs, std::array{0}, 1); + for (auto iProng = 0u; iProng < arrSigmaDaugs.size(); ++iProng) { + auto daughSigma = particlesMC.rawIteratorAt(arrSigmaDaugs[iProng]); + float genMassSigma = std::sqrt(genSigma.e() * genSigma.e() - genSigma.p() * genSigma.p()); + std::array sigmaMomGen{genSigma.px(), genSigma.py(), genSigma.pz()}; + std::array kinkMomGen{daughSigma.px(), daughSigma.py(), daughSigma.pz()}; + float genSigmaAlphaAP = alphaAP(sigmaMomGen, kinkMomGen); + float genSigmaQtAP = qtAP(sigmaMomGen, kinkMomGen); + float sigmaRadius = std::hypot(daughSigma.vx(), daughSigma.vy()); + + if (std::abs(daughSigma.pdgCode()) == PDG_t::kPiPlus && std::abs(genSigma.pdgCode()) == PDG_t::kSigmaMinus) { + rSigmaMinus.fill(HIST("hSparseGenSigmaMinus"), genMassSigma, genSigma.pt(), genSigmaAlphaAP, genSigmaQtAP, sigmaRadius, genCentMult, genNumContrib, genOcc); + } else if (std::abs(daughSigma.pdgCode()) == PDG_t::kPiPlus && std::abs(genSigma.pdgCode()) == PDG_t::kSigmaPlus) { + rSigmaPlus.fill(HIST("hSparseGenSigmaPlus"), genMassSigma, genSigma.pt(), genSigmaAlphaAP, genSigmaQtAP, sigmaRadius, genCentMult, genNumContrib, genOcc); + } else if (std::abs(daughSigma.pdgCode()) == PDG_t::kProton && std::abs(genSigma.pdgCode()) == PDG_t::kSigmaPlus) { + rSigmaPlus.fill(HIST("hSparseGenSigmaPlus"), genMassSigma, genSigma.pt(), genSigmaAlphaAP, genSigmaQtAP, sigmaRadius, genCentMult, genNumContrib, genOcc); + } + } + } } - PROCESS_SWITCH(lambda1405analysis, processMcWCentSel, "MC processing with centrality selection", false); + PROCESS_SWITCH(lambda1405analysis, processMcSigmasCentSel, "MC processing for sigma efficiency studies", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { From 83a780bb4e6a9378816907019a7e48d92eb68c42 Mon Sep 17 00:00:00 2001 From: Stefanie Mrozinski <63045530+Steffimro@users.noreply.github.com> Date: Tue, 28 Jul 2026 19:32:23 +0200 Subject: [PATCH 24/71] [PWGEM] fix MC truth information + cross-pair ratio (#17236) --- PWGEM/PhotonMeson/Tasks/photonhbt.cxx | 75 +++++++++------------------ 1 file changed, 24 insertions(+), 51 deletions(-) diff --git a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx index 425a7097ec5..f4ede2de706 100644 --- a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx +++ b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx @@ -152,8 +152,8 @@ struct Photonhbt { }; struct CrossObs { - std::array mee{999.f, 999.f}; // crossed m(e+e-) per combo - std::array dist{999.f, 999.f}; // crossed line-line distance (cm) + std::array mee{999.f, 999.f}; + float meeOverQ{999.f}; }; struct TruthGamma { @@ -350,8 +350,7 @@ struct Photonhbt { std::string prefix = "crosspair_group"; Configurable cfgDoCrossPairQA{"cfgDoCrossPairQA", false, "fill crossed-hypothesis QA (mee_cross, dist_cross vs qinv) for pairs passing all other pair cuts; SE and ME"}; Configurable cfgDoCrossPairCut{"cfgDoCrossPairCut", false, "reject pairs with a photon-like crossed combination; applied to SE AND ME"}; - Configurable cfgCrossMaxMee{"cfgCrossMaxMee", 0.04f, "veto: crossed m_ee below this (GeV/c^2)"}; - Configurable cfgCrossMaxDist{"cfgCrossMaxDist", 1.0f, "veto: crossed line-line distance below this (cm)"}; + Configurable cfgCrossMaxMeeRatio{"cfgCrossMaxMeeRatio", 0.2f, "veto: min(m_ee^cross)/q_inv below this; genuine pairs sit near 0.5, leg swaps near 0"}; Configurable cfgCrossMaxQinvQA{"cfgCrossMaxQinvQA", 0.3f, "fill crossed QA sparses only below this qinv"}; } crosspair; @@ -752,9 +751,9 @@ struct Photonhbt { return; } for (const auto& sm : {std::string("Pair/same/CrossPair/"), std::string("Pair/mix/CrossPair/")}) { - fRegistryCF.add((sm + "hSparse_Mee_Dist_Qinv").c_str(), - "crossed-hypothesis QA;m_{ee}^{cross} (GeV/c^{2});crossed line distance (cm);q_{inv} (GeV/c)", - kTHnSparseF, {{100, 0.f, 0.1f}, {100, 0.f, 10.f}, {60, 0.f, 0.3f}}, true); + fRegistryCF.add((sm + "hSparse_MeeRatio_dR_Qinv").c_str(), + "crossed-hypothesis QA;min(m_{ee}^{cross})/q_{inv};|R_{1}-R_{2}| (cm);q_{inv} (GeV/c)", + kTHnSparseF, {{100, 0.f, 2.f}, {80, 0.f, 80.f}, {60, 0.f, 0.3f}}, true); auto h = fRegistryCF.add((sm + "hVetoCounter").c_str(), "crossed-pair veto;;pairs", kTH1D, {{2, -0.5f, 1.5f}}, true); h->GetXaxis()->SetBinLabel(1, "evaluated"); h->GetXaxis()->SetBinLabel(2, "vetoed"); @@ -1307,42 +1306,22 @@ struct Photonhbt { return s.u > pairsep.cfgUCut.value; } - [[nodiscard]] static float lineLineDistance(std::array const& o1, std::array const& d1, - std::array const& o2, std::array const& d2) - { - const std::array w = {o2[0] - o1[0], o2[1] - o1[1], o2[2] - o1[2]}; - const std::array n = {d1[1] * d2[2] - d1[2] * d2[1], - d1[2] * d2[0] - d1[0] * d2[2], - d1[0] * d2[1] - d1[1] * d2[0]}; - const float nMag = std::sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]); - const float d1Mag2 = d1[0] * d1[0] + d1[1] * d1[1] + d1[2] * d1[2]; - if (nMag < 1e-6f * d1Mag2) { // o2-linter: disable=magic-number (near-parallel: point-to-line distance) - const float wDotD = (w[0] * d1[0] + w[1] * d1[1] + w[2] * d1[2]) / d1Mag2; - const std::array perp = {w[0] - wDotD * d1[0], w[1] - wDotD * d1[1], w[2] - wDotD * d1[2]}; - return std::sqrt(perp[0] * perp[0] + perp[1] * perp[1] + perp[2] * perp[2]); - } - return std::fabs(w[0] * n[0] + w[1] * n[1] + w[2] * n[2]) / nMag; - } - - [[nodiscard]] CrossObs computeCrossObs(PhotonWithLegs const& a, PhotonWithLegs const& b) const + [[nodiscard]] CrossObs computeCrossObs(PhotonWithLegs const& a, PhotonWithLegs const& b, float qinv) const { constexpr float kMe = 0.000510999f; // electron mass, GeV/c^2 CrossObs c; auto legVec = [](PhotonWithLegs const& p, int i) { return ROOT::Math::PtEtaPhiMVector(p.fLegPt[i], p.fLegEta[i], p.fLegPhi[i], kMe); }; - auto legDir = [](PhotonWithLegs const& p, int i) -> std::array { - return {p.fLegPt[i] * std::cos(p.fLegPhi[i]), p.fLegPt[i] * std::sin(p.fLegPhi[i]), - p.fLegPt[i] * std::sinh(p.fLegEta[i])}; - }; // Leg index 0 = e+, 1 = e- (makePhotonWithLegs filling order). // Combo 0: a's e+ with b's e-. Combo 1: b's e+ with a's e-. - for (int combo = 0; combo < 2; ++combo) { // o2-linter: disable=magic-number (combinations of fake photons) + for (int combo = 0; combo < 2; ++combo) { // o2-linter: disable=magic-number (the two leg-swap combinations) PhotonWithLegs const& pPos = (combo == 0) ? a : b; PhotonWithLegs const& pEle = (combo == 0) ? b : a; c.mee[combo] = static_cast((legVec(pPos, 0) + legVec(pEle, 1)).M()); - c.dist[combo] = lineLineDistance({pPos.fVx, pPos.fVy, pPos.fVz}, legDir(pPos, 0), - {pEle.fVx, pEle.fVy, pEle.fVz}, legDir(pEle, 1)); + } + if (qinv > 0.f) { + c.meeOverQ = std::min(c.mee[0], c.mee[1]) / qinv; } return c; } @@ -1352,25 +1331,19 @@ struct Photonhbt { if (!crosspair.cfgDoCrossPairCut.value) { return true; } - for (int i = 0; i < 2; ++i) { // o2-linter: disable=magic-number (combinations of fake photons) - if (c.mee[i] < crosspair.cfgCrossMaxMee.value && c.dist[i] < crosspair.cfgCrossMaxDist.value) { - return false; - } - } - return true; + // A photon-like crossed combination means the pairing is ambiguous. + return c.meeOverQ > crosspair.cfgCrossMaxMeeRatio.value; } template - inline void fillCrossPair(CrossObs const& c, float qinv, bool vetoed) + inline void fillCrossPair(CrossObs const& c, float qinv, float deltaR, bool vetoed) { constexpr auto dir = (ev_id == 0) ? "Pair/same/CrossPair/" : "Pair/mix/CrossPair/"; fRegistryCF.fill(HIST(dir) + HIST("hVetoCounter"), vetoed ? 1.0 : 0.0); if (qinv > crosspair.cfgCrossMaxQinvQA.value) { return; } - for (int i = 0; i < 2; ++i) { // o2-linter: disable=magic-number (combinations of fake photons) - fRegistryCF.fill(HIST(dir) + HIST("hSparse_Mee_Dist_Qinv"), c.mee[i], c.dist[i], qinv); - } + fRegistryCF.fill(HIST(dir) + HIST("hSparse_MeeRatio_dR_Qinv"), c.meeOverQ, deltaR, qinv); } [[nodiscard]] float uTrue(TruthGamma const& g1, TruthGamma const& g2) const @@ -2043,9 +2016,9 @@ struct Photonhbt { continue; } if (crosspair.cfgDoCrossPairQA.value || crosspair.cfgDoCrossPairCut.value) { - const auto cross = computeCrossObs(pwl1, pwl2); + const auto cross = computeCrossObs(pwl1, pwl2, obs.qinv); const bool vetoed = !passCrossPairVeto(cross); - fillCrossPair<0>(cross, obs.qinv, vetoed); + fillCrossPair<0>(cross, obs.qinv, obs.deltaR, vetoed); if (vetoed) { continue; } @@ -2141,9 +2114,9 @@ struct Photonhbt { continue; } if (crosspair.cfgDoCrossPairQA.value || crosspair.cfgDoCrossPairCut.value) { - const auto cross = computeCrossObs(g1, g2); + const auto cross = computeCrossObs(g1, g2, obs.qinv); const bool vetoed = !passCrossPairVeto(cross); - fillCrossPair<1>(cross, obs.qinv, vetoed); + fillCrossPair<1>(cross, obs.qinv, obs.deltaR, vetoed); if (vetoed) { continue; } @@ -2271,9 +2244,9 @@ struct Photonhbt { continue; } if (crosspair.cfgDoCrossPairQA.value || crosspair.cfgDoCrossPairCut.value) { - const auto cross = computeCrossObs(pwl1, pwl2); + const auto cross = computeCrossObs(pwl1, pwl2, obs.qinv); const bool vetoed = !passCrossPairVeto(cross); - fillCrossPair<0>(cross, obs.qinv, vetoed); + fillCrossPair<0>(cross, obs.qinv, obs.deltaR, vetoed); if (vetoed) { continue; } @@ -2422,9 +2395,9 @@ struct Photonhbt { continue; } if (crosspair.cfgDoCrossPairQA.value || crosspair.cfgDoCrossPairCut.value) { - const auto cross = computeCrossObs(g1, g2); + const auto cross = computeCrossObs(g1, g2, obs.qinv); const bool vetoed = !passCrossPairVeto(cross); - fillCrossPair<1>(cross, obs.qinv, vetoed); + fillCrossPair<1>(cross, obs.qinv, obs.deltaR, vetoed); if (vetoed) { continue; } @@ -2735,7 +2708,7 @@ struct Photonhbt { fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hQinvVsKt_all4LegsThisColl"), kt, qinv_true); fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hDEtaDPhi_all4LegsThisColl"), deta, dphi); } - if (g1Sel && g2Sel) { + if (g1Built && g2Built) { fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hSparse_DEtaDPhi_qinv_bothPhotonsBuilt"), deta, dphi, qinv_true); fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hSparse_DEtaDPhi_kT_bothPhotonsBuilt"), deta, dphi, kt); fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hQinvVsKt_bothPhotonsBuilt"), kt, qinv_true); From eb1043c668dcb69073fc4b82582040fa28a56328 Mon Sep 17 00:00:00 2001 From: Marvin Hemmer <53471402+mhemmer-cern@users.noreply.github.com> Date: Tue, 28 Jul 2026 23:33:12 +0200 Subject: [PATCH 25/71] [PWGEM] emcalPhotonMcTask overhaul TruthClass (#17239) --- PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx | 237 +++++++++++------- PWGEM/PhotonMeson/Utils/MCUtilities.h | 44 ++++ 2 files changed, 189 insertions(+), 92 deletions(-) diff --git a/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx b/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx index 2e8044eae82..3ee4a6e928d 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx @@ -46,6 +46,7 @@ #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include #include +#include #include #include #include @@ -63,6 +64,7 @@ using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::photon; using namespace o2::constants::physics; +using namespace o2::aod::pwgem::photonmeson::utils::mcutil; enum CentralityEstimator { None = 0, @@ -72,19 +74,32 @@ enum CentralityEstimator { NCentralityEstimators }; -enum class MapLevel { - kGood = 1, - kNoBad = 2, - kInEMC = 3, - kAll = 4 +enum class TruthClass { + Conversion = 0, // 1: true e+/e- pair from the same conversion + + PhotonPairSamePi0, // 2: two photon clusters, same Pi0 + PhotonPairDiffPi0, // 3: two photon clusters, different Pi0s + PhotonPairOnePi0, // 4: two photon clusters, only one from a Pi0 + + PhotonElectronSamePi0, // 5: photon + electron cluster, same Pi0 + PhotonElectronDiffPi0, // 6: photon + electron cluster, different Pi0s + PhotonElectronOnePi0, // 7: photon + electron cluster, only one from a Pi0 + + ElectronPairSamePi0, // 8: e+e cluster pair, same Pi0 (conversion and/or Dalitz) + ElectronPairDiffPi0, // 9: e+e cluster pair, different Pi0s + ElectronPairOnePi0, // 10: e+e cluster pair, only one from a Pi0 + + Background, // 11: else / uncorrelated + + NClasses }; -enum class TruthClass { - Conversion = 0, - Pi0, - Pi0Conversion, - Background, - Photon, +enum class ClusterTruthClass { + Photon = 0, // cluster is a true, unconverted photon + Conversion, // cluster is a leg of a true conversion + Pi0Conversion, // ...and that conversion's photon itself came from pi0/eta (excludes same-gamma-pair case) + Pi0, // cluster comes from the pi0/eta decay chain (not via the conversion-leg path above) + Background, // cluster is flagged as both meson-chain AND conversion -- ambiguous/contradictory NClasses }; @@ -94,6 +109,50 @@ enum class TagDecision { NTags }; +struct ClusterMcInfo { + bool isLepton = false; + bool isPhoton = false; + bool isFromConv = false; + bool isMergedConv = false; + bool isFromPi0 = false; + int convMotherId = -1; + int photonId = -1; +}; + +template +ClusterMcInfo classifyCluster(const TGroup& g, TIter& mcCluster, TIter& mcClusterLooper, TIter& mcClusterLooper2, McParticles const& mcParticles) +{ + ClusterMcInfo info; + mcCluster.setCursor(g.emmcparticleIds()[0]); + if (std::abs(mcCluster.pdgCode()) == PDG_t::kElectron) { + info.isLepton = true; + info.convMotherId = getMotherIndexFromChain(mcCluster, mcClusterLooper, PDG_t::kGamma); + info.isFromConv = info.convMotherId >= 0; + + if (mcCluster.mothersIds().size() > 0 && info.isFromConv) { + for (size_t i = 1; i < g.emmcparticleIds().size(); ++i) { + mcClusterLooper.setCursor(g.emmcparticleIds()[i]); + if (std::abs(mcClusterLooper.pdgCode()) == PDG_t::kElectron) { + int32_t otherConvMotherId = getMotherIndexFromChain(mcClusterLooper, mcClusterLooper2, PDG_t::kGamma); + if (otherConvMotherId == info.convMotherId) { + info.isMergedConv = true; + info.isLepton = false; + info.isPhoton = true; + break; + } + } + } + } + } + if (std::abs(mcCluster.pdgCode()) == PDG_t::kGamma) { + info.isPhoton = true; + } + + info.photonId = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta}); + info.isFromPi0 = info.photonId >= 0; + + return info; +} struct EmcalPhotonMcTask { static constexpr float EMCALRadius = 440.f; static constexpr float PhiVUndefined = -999.f; @@ -105,7 +164,7 @@ struct EmcalPhotonMcTask { Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; Configurable writeTable{"writeTable", true, "write table for ML."}; - Configurable bkgPrescale{"bkgPrescale", 1000, "keep 1 in N background pairs in the ML training table"}; + Configurable> classPrescale{"classPrescale", {1, 1, 700, 25, 1, 350, 15, 1, 35, 2, 1000}, "prescale factor per TruthClass, indexed 0..10 matching the enum order"}; Configurable bkgPrescaleSeed{"bkgPrescaleSeed", 42, "seed for the background-prescale RNG"}; // configurable axis @@ -188,7 +247,7 @@ struct EmcalPhotonMcTask { HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - int bTruthLabel{}; + int8_t bTruthLabel{}; Service ccdb{}; int mRunNumber{0}; @@ -270,14 +329,20 @@ struct EmcalPhotonMcTask { thnAxisCentOrMult = {thnConfigAxisMult, "FT0C Multiplicity"}; } - registry.add("EMCal/TrueConversion/hMassReco", "minv vs rConv vs E1 vs E2", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisrConvRec, thnAxisERec, thnAxisERec, thnAxisCentOrMult}); - registry.add("EMCal/TrueConversion/hrConvReco", "rConv vs true rConv vs E1 vs E2", HistType::kTHnSparseF, {thnAxisrConvRec, thnAxisrConvGen, thnAxisERec, thnAxisERec, thnAxisCentOrMult}); - registry.add("EMCal/TrueConversion/hDeltaEtaDeltaPhi", "EMCal Delta Eta vs Delta vs E1 vs E2", HistType::kTHnSparseF, {thnAxisDeltaEta, thnAxisDeltaPhi, thnAxisERec, thnAxisERec, thnAxisCentOrMult}); - registry.add("EMCal/TrueConversion/hEnergyReco", "energy vs cent", HistType::kTH2D, {thnAxisERec, thnAxisCentOrMult}); - - registry.addClone("EMCal/TrueConversion/", "EMCal/TrueConversionFromPi0/"); - registry.addClone("EMCal/TrueConversion/", "EMCal/TrueClusterFromPi0/"); - registry.addClone("EMCal/TrueConversion/", "EMCal/Background/"); + auto hTruthLabel = registry.add("hTruthLabel", "Truth label distribution;;Counts", HistType::kTH1D, {{static_cast(TruthClass::NClasses), -0.5, static_cast(TruthClass::NClasses) - 0.5}}); + + // set bin labels once at init, so histogram is human-readable without decoding the enum + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::Conversion) + 1, "Conversion"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonPairSamePi0) + 1, "PhotonPairSamePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonPairDiffPi0) + 1, "PhotonPairDiffPi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonPairOnePi0) + 1, "PhotonPairOnePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonElectronSamePi0) + 1, "PhotonElectronSamePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonElectronDiffPi0) + 1, "PhotonElectronDiffPi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonElectronOnePi0) + 1, "PhotonElectronOnePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::ElectronPairSamePi0) + 1, "ElectronPairSamePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::ElectronPairDiffPi0) + 1, "ElectronPairDiffPi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::ElectronPairOnePi0) + 1, "ElectronPairOnePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::Background) + 1, "Background"); auto hPi0BothResolvedLost = registry.add("EMCal/hPi0BothResolvedLost", "Confusion matrix for conversion tagging", HistType::kTH1D, {{2, -0.5, 1.5}}); hPi0BothResolvedLost->GetXaxis()->SetBinLabel(1, "both resolved (denominator)"); @@ -294,8 +359,6 @@ struct EmcalPhotonMcTask { hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(5, "#gamma"); mRandGen.seed(bkgPrescaleSeed.value); - mPrescaleDist = std::uniform_int_distribution(0, bkgPrescale.value - 1); - }; // end init template @@ -411,11 +474,13 @@ struct EmcalPhotonMcTask { if (clusters.size() > 0) { fEMCCut.AreSelectedRunning(emcFlags, clusters, matchedPrims, matchedSeconds, ®istry); } - auto mcCluster1 = mcParticles.begin(); - auto mcCluster2 = mcParticles.begin(); - auto mcPhoton1 = mcParticles.begin(); - auto mcPhoton2 = mcParticles.begin(); - auto mcMother = mcParticles.begin(); + auto mcCluster1 = mcParticles.begin(); // iterator of MC particle of highest contributor for first cluster + auto mcCluster2 = mcParticles.begin(); // iterator of MC particle of highest contributor for second cluster + auto mcClusterLooper = mcParticles.begin(); // iterator of MC particle of other contributor for both clusters + auto mcClusterLooper2 = mcParticles.begin(); // iterator of MC particle of other contributor for both clusters + auto mcPhoton1 = mcParticles.begin(); // iterator of MC particle of highest contributor for first cluster that is photon + auto mcPhoton2 = mcParticles.begin(); // iterator of MC particle of highest contributor for second cluster that is photon + auto mcMother = mcParticles.begin(); // iterator of MC particle of combined mother of both clusters for (const auto& collision : collisions) { initCCDB(collision); @@ -475,84 +540,77 @@ struct EmcalPhotonMcTask { mcCluster1.setCursor(g1.emmcparticleIds()[0]); mcCluster2.setCursor(g2.emmcparticleIds()[0]); - bool areLeptons = false; // both clusters are e+/e- + bool areFromSamePi0 = false; // both clusters are from same pi0 or eta bool areConversionLegs = false; // both clusters are e+ + e- from one photon - bool arePhotonFromPi0 = false; // both cluster come from the same gamma which is from pi0 or eta - bool areClusterFromPi0 = false; // both cluster come from the decay chain of a pi0 or eta excluding the same gamma case above - if (std::abs(mcCluster1.pdgCode()) == kElectron && std::abs(mcCluster2.pdgCode()) == kElectron) { - areLeptons = true; - } - if (o2::aod::pwgem::photonmeson::utils::mcutil::isMotherPDG(mcCluster1, kGamma) && o2::aod::pwgem::photonmeson::utils::mcutil::isMotherPDG(mcCluster2, kGamma)) { - // both cluster come from a photon - // reset the cursors to the legs! - mcCluster1.setCursor(g1.emmcparticleIds()[0]); - mcCluster2.setCursor(g2.emmcparticleIds()[0]); - if (mcCluster1.mothersIds().size() > 0 && mcCluster2.mothersIds().size() > 0 && mcCluster1.mothersIds()[0] == mcCluster2.mothersIds()[0]) { - // both cluster come from the same photon - emcFlagsFromTrueConversion.set(g1.globalIndex()); - emcFlagsFromTrueConversion.set(g2.globalIndex()); - areConversionLegs = true; - } - } - // reset the cursors to the legs! - mcCluster1.setCursor(g1.emmcparticleIds()[0]); - mcCluster2.setCursor(g2.emmcparticleIds()[0]); + auto c1 = classifyCluster(g1, mcCluster1, mcClusterLooper, mcClusterLooper2, mcParticles); + auto c2 = classifyCluster(g2, mcCluster2, mcClusterLooper, mcClusterLooper2, mcParticles); - // check if the clusters are coming from a chain product of a pi0 or eta decay and then get the first level daughter of the pi0 or eta meson - int photonid1 = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster1, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta}); - int photonid2 = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster2, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta}); + if (c1.isFromConv && c2.isFromConv && c1.convMotherId == c2.convMotherId) { + emcFlagsFromTrueConversion.set(g1.globalIndex()); + emcFlagsFromTrueConversion.set(g2.globalIndex()); + areConversionLegs = true; + } - if (photonid1 >= 0 && photonid2 >= 0) { + if (c1.isFromPi0 && c2.isFromPi0) { // set the cursors to the photonId - mcPhoton1.setCursor(photonid1); - mcPhoton2.setCursor(photonid2); + mcPhoton1.setCursor(c1.photonId); + mcPhoton2.setCursor(c2.photonId); mcMother.setCursor(mcPhoton1.mothersIds()[0]); if (mcMother.producedByGenerator()) { - if (photonid1 == photonid2) { - // the two clusters came from the same photon which came from a pi0 or eta. Most likely: pi0/eta -> γ + X -> e+e- + X + if (c1.photonId == c2.photonId) { + areFromSamePi0 = true; emcFlagsFromTrueMesonSameGamma.set(g1.globalIndex()); emcFlagsFromTrueMesonSameGamma.set(g2.globalIndex()); - arePhotonFromPi0 = true; } else if (mcPhoton1.mothersIds()[0] == mcPhoton2.mothersIds()[0]) { + areFromSamePi0 = true; emcFlagsFromTrueMeson.set(g1.globalIndex()); emcFlagsFromTrueMeson.set(g2.globalIndex()); - areClusterFromPi0 = true; } } } - - // do we have two conversions - if (areLeptons && areConversionLegs) { - registry.fill(HIST("EMCal/TrueConversion/hMassReco"), vMeson.M(), rConv, g1.e(), g2.e(), centOrMult); - registry.fill(HIST("EMCal/TrueConversion/hrConvReco"), rConv, std::hypot(mcCluster1.vx(), mcCluster1.vy()), g1.e(), g2.e(), centOrMult); - registry.fill(HIST("EMCal/TrueConversion/hDeltaEtaDeltaPhi"), deltaEta, deltaPhi, g1.e(), g2.e(), centOrMult); - if (arePhotonFromPi0) { - registry.fill(HIST("EMCal/TrueConversionFromPi0/hMassReco"), vMeson.M(), rConv, g1.e(), g2.e(), centOrMult); - registry.fill(HIST("EMCal/TrueConversionFromPi0/hrConvReco"), rConv, std::hypot(mcCluster1.vx(), mcCluster1.vy()), g1.e(), g2.e(), centOrMult); - registry.fill(HIST("EMCal/TrueConversionFromPi0/hDeltaEtaDeltaPhi"), deltaEta, deltaPhi, g1.e(), g2.e(), centOrMult); + bTruthLabel = static_cast(TruthClass::Background); + if (areConversionLegs) { + bTruthLabel = static_cast(TruthClass::Conversion); + } else { + if (areFromSamePi0) { + if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { + bTruthLabel = static_cast(TruthClass::PhotonElectronSamePi0); + } else if (c1.isPhoton && c2.isPhoton) { + bTruthLabel = static_cast(TruthClass::PhotonPairSamePi0); + } else if (c1.isLepton && c2.isLepton) { + bTruthLabel = static_cast(TruthClass::ElectronPairSamePi0); + } + } else if (c1.isFromPi0 && c2.isFromPi0) { + if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { + bTruthLabel = static_cast(TruthClass::PhotonElectronDiffPi0); + } else if (c1.isPhoton && c2.isPhoton) { + bTruthLabel = static_cast(TruthClass::PhotonPairDiffPi0); + } else if (c1.isLepton && c2.isLepton) { + bTruthLabel = static_cast(TruthClass::ElectronPairDiffPi0); + } + } else if ((c1.isFromPi0 && !c2.isFromPi0) || (!c1.isFromPi0 && c2.isFromPi0)) { + if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { + bTruthLabel = static_cast(TruthClass::PhotonElectronOnePi0); + } else if (c1.isPhoton && c2.isPhoton) { + bTruthLabel = static_cast(TruthClass::PhotonPairOnePi0); + } else if (c1.isLepton && c2.isLepton) { + bTruthLabel = static_cast(TruthClass::ElectronPairOnePi0); + } } } - if (areClusterFromPi0) { - registry.fill(HIST("EMCal/TrueClusterFromPi0/hMassReco"), vMeson.M(), rConv, g1.e(), g2.e(), centOrMult); - registry.fill(HIST("EMCal/TrueClusterFromPi0/hrConvReco"), rConv, std::hypot(mcCluster1.vx(), mcCluster1.vy()), g1.e(), g2.e(), centOrMult); - registry.fill(HIST("EMCal/TrueClusterFromPi0/hDeltaEtaDeltaPhi"), deltaEta, deltaPhi, g1.e(), g2.e(), centOrMult); - } - if (!areClusterFromPi0 && !areConversionLegs) { - registry.fill(HIST("EMCal/Background/hMassReco"), vMeson.M(), rConv, g1.e(), g2.e(), centOrMult); - registry.fill(HIST("EMCal/Background/hrConvReco"), rConv, std::hypot(mcCluster1.vx(), mcCluster1.vy()), g1.e(), g2.e(), centOrMult); - registry.fill(HIST("EMCal/Background/hDeltaEtaDeltaPhi"), deltaEta, deltaPhi, g1.e(), g2.e(), centOrMult); - } + + registry.fill(HIST("hTruthLabel"), bTruthLabel); // final tree values plus filling - bTruthLabel = (areLeptons && areConversionLegs) ? 0 : (areClusterFromPi0 ? 1 : 2); - const bool isConversionOrPi0 = (areLeptons && areConversionLegs) || areClusterFromPi0; - const bool keepThisRow = isConversionOrPi0 || (mPrescaleDist(mRandGen) == 0); + const int prescale = classPrescale.value[static_cast(bTruthLabel)]; + const bool keepThisRow = (prescale <= 1) || (std::uniform_int_distribution(0, prescale - 1)(mRandGen) == 0); if (writeTable.value && keepThisRow) { convTagCandidates(collision.globalIndex(), vMeson.M(), harmonicET, deltaEta, deltaPhi, phiV, g1.e(), g2.e(), g1.m02(), g2.m02(), g1.time(), g2.time(), g1.nCells(), g2.nCells(), bTruthLabel, centOrMult); } } // pair loop } // collision loop + std::vector photonSeen(mcParticles.size(), false); // this decay photon has >=1 resolved cluster std::vector photonTagged(mcParticles.size(), false); // >=1 of those clusters got conversion-tagged auto collision = collisions.begin(); @@ -567,7 +625,6 @@ struct EmcalPhotonMcTask { if (cluster.pmeventId() > collision.globalIndex()) { collision.setCursor(cluster.pmeventId()); } - float centOrMult = getCentralityOrMultiplicity(collision); mcCluster1.setCursor(cluster.emmcparticleIds()[0]); int photonid1 = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster1, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta}); @@ -586,23 +643,19 @@ struct EmcalPhotonMcTask { const bool alreadyCountedForMeson = (motherId > -1 && wasMeassured[static_cast(motherId)]); if (mcCluster1.pdgCode() == PDG_t::kGamma) { - registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(TruthClass::Photon)); + registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Photon)); } if (!emcFlagsFromTrueConversion.test(cluster.globalIndex())) { - registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(TruthClass::Conversion)); - registry.fill(HIST("EMCal/TrueConversion/hEnergyReco"), cluster.e(), centOrMult); + registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Conversion)); if (!emcFlagsFromTrueMesonSameGamma.test(cluster.globalIndex()) && !alreadyCountedForMeson) { - registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(TruthClass::Pi0Conversion)); - registry.fill(HIST("EMCal/TrueConversionFromPi0/hEnergyReco"), cluster.e(), centOrMult); + registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Pi0Conversion)); } } if (!emcFlagsFromTrueMeson.test(cluster.globalIndex()) && !alreadyCountedForMeson) { - registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(TruthClass::Pi0)); - registry.fill(HIST("EMCal/TrueClusterFromPi0/hEnergyReco"), cluster.e(), centOrMult); + registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Pi0)); } if (emcFlagsFromTrueMeson.test(cluster.globalIndex()) && emcFlagsFromTrueConversion.test(cluster.globalIndex())) { - registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(TruthClass::Background)); - registry.fill(HIST("EMCal/Background/hEnergyReco"), cluster.e(), centOrMult); + registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Background)); } if (motherId > -1 && !wasMeassured[static_cast(motherId)]) { wasMeassured[static_cast(motherId)] = true; diff --git a/PWGEM/PhotonMeson/Utils/MCUtilities.h b/PWGEM/PhotonMeson/Utils/MCUtilities.h index bb7b4309e29..dce6d127bf5 100644 --- a/PWGEM/PhotonMeson/Utils/MCUtilities.h +++ b/PWGEM/PhotonMeson/Utils/MCUtilities.h @@ -292,6 +292,28 @@ bool isMotherPDG(T& mcparticle, const int motherPDG, const int depth = 10) // o2 return isMotherPDG(mcparticle, motherPDG, depth - 1); } +//_______________________________________________________________________ +/// \brief Go up the decay chain of a mcparticle looking for a mother with the given pdg codes, if found return true else false +/// E.g. if electron cluster is coming from a photon return true, if primary electron return false +/// \param mcparticle iterator of mcparticle, NOT modified by this function +/// \param mcparticleWorking a second iterator of the SAME table, used as scratch space to walk up the chain -- caller must supply this so the function doesn't construct its own +/// \param motherPDG target mother PDG value +/// \param depth how many steps in the chain this check should go maximum before failing +template +bool isMotherPDG(const T& mcparticle, T& mcparticleWorking, const int motherPDG, const int depth = 10) // o2-linter: disable=pdg/explicit-code (false positive) +{ + if (!mcparticle.has_mothers() || depth < 1) { + return false; + } + + int motherid = mcparticle.mothersIds()[0]; + mcparticleWorking.setCursor(motherid); + if (mcparticleWorking.pdgCode() == motherPDG) { + return true; // The mother has the required pdg code. + } + return isMotherPDG(mcparticleWorking, mcparticleWorking, motherPDG, depth - 1); +} + //_______________________________________________________________________ /// \brief Go up the decay chain of a mcparticle looking for a mother with the given pdg codes, if found return id else -1 /// E.g. if electron cluster is coming from a photon return true, if primary electron return false @@ -313,6 +335,28 @@ int32_t getMotherIndexFromChain(T& mcparticle, const int motherPDG, const int de return getMotherIndexFromChain(mcparticle, motherPDG, depth - 1); } +//_______________________________________________________________________ +/// \brief Go up the decay chain of a mcparticle looking for a mother with the given pdg codes, if found return id else -1 +/// E.g. if electron cluster is coming from a photon return the photon's id, if primary electron return -1 +/// \param mcparticle iterator of mcparticle, NOT modified by this function +/// \param mcparticleWorking a second iterator of the SAME table, used as scratch space to walk up the chain -- caller must supply this so the function doesn't construct its own +/// \param motherPDG target mother PDG value +/// \param depth how many steps in the chain this check should go maximum before failing +template +int32_t getMotherIndexFromChain(const T& mcparticle, T& mcparticleWorking, const int motherPDG, const int depth = 10) // o2-linter: disable=pdg/explicit-code (false positive) +{ + if (!mcparticle.has_mothers() || depth < 1) { + return -1; + } + + int32_t motherid = mcparticle.mothersIds()[0]; + mcparticleWorking.setCursor(motherid); + if (mcparticleWorking.pdgCode() == motherPDG) { + return motherid; + } + return getMotherIndexFromChain(mcparticleWorking, mcparticleWorking, motherPDG, depth - 1); +} + //_______________________________________________________________________ } // namespace o2::aod::pwgem::photonmeson::utils::mcutil //_______________________________________________________________________ From a39145acbf1e904a1af4a4d0f56ee08b4ed1407f Mon Sep 17 00:00:00 2001 From: ariedel-cern <85537041+ariedel-cern@users.noreply.github.com> Date: Tue, 28 Jul 2026 23:48:40 +0200 Subject: [PATCH 26/71] [PWGCF] Fix DCA selections of daughter tracks (#17240) Co-authored-by: ALICE Action Bot --- PWGCF/Femto/Core/cascadeBuilder.h | 42 +++++++++++++++---------------- PWGCF/Femto/Core/v0Builder.h | 22 ++++++++-------- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/PWGCF/Femto/Core/cascadeBuilder.h b/PWGCF/Femto/Core/cascadeBuilder.h index ea63069aacc..01148794aca 100644 --- a/PWGCF/Femto/Core/cascadeBuilder.h +++ b/PWGCF/Femto/Core/cascadeBuilder.h @@ -63,19 +63,19 @@ struct ConfCascadeFilters : o2::framework::ConfigurableGroup { }; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define CASCADE_DEFAULT_BITS \ - o2::framework::Configurable passThrough{"passThrough", false, "If true, all Cascades are passed through. Bits for all selections are stored."}; \ - o2::framework::Configurable> cascadeCpaMin{"cascadeCpaMin", {0.95f}, "Minimum cosine of pointing angle"}; \ - o2::framework::Configurable> cascadeTransRadMin{"cascadeTransRadMin", {0.9f}, "Minimum transverse radius (cm)"}; \ - o2::framework::Configurable> cascadeDcaDauMax{"cascadeDcaDauMax", {0.25f}, "Maximum DCA between the daughters at decay vertex (cm)"}; \ - o2::framework::Configurable> lambdaCpaMin{"lambdaCpaMin", {0.78f}, "Minimum cosine of pointing angle"}; \ - o2::framework::Configurable> lambdaTransRadMin{"lambdaTransRadMin", {0.9f}, "Minimum transverse radius (cm)"}; \ - o2::framework::Configurable> lambdaDcaDauMax{"lambdaDcaDauMax", {0.5f}, "Maximum DCA between the daughters at decay vertex (cm)"}; \ - o2::framework::Configurable> lambdaDcaToPvMin{"lambdaDcaToPvMin", {0.3f}, "Minimum DCA between the lambda and primary vertex"}; \ - o2::framework::Configurable> dauAbsEtaMax{"dauAbsEtaMax", {0.8f}, "Maximum |eta| of all daughters"}; \ - o2::framework::Configurable> dauDcaMin{"dauDcaMin", {0.05f}, "Minimum DCA of the daughters from primary vertex (cm)"}; \ - o2::framework::Configurable> dauTpcClustersMin{"dauTpcClustersMin", {80.f}, "Minimum number of TPC clusters for daughter tracks"}; \ - o2::framework::Configurable> posDauTpc{"posDauTpc", {5.f}, "Maximum |nsimga_Pion/Proton| TPC for positive daughter tracks"}; \ +#define CASCADE_DEFAULT_BITS \ + o2::framework::Configurable passThrough{"passThrough", false, "If true, all Cascades are passed through. Bits for all selections are stored."}; \ + o2::framework::Configurable> cascadeCpaMin{"cascadeCpaMin", {0.95f}, "Minimum cosine of pointing angle"}; \ + o2::framework::Configurable> cascadeTransRadMin{"cascadeTransRadMin", {0.9f}, "Minimum transverse radius (cm)"}; \ + o2::framework::Configurable> cascadeDcaDauMax{"cascadeDcaDauMax", {0.25f}, "Maximum DCA between the daughters at decay vertex (cm)"}; \ + o2::framework::Configurable> lambdaCpaMin{"lambdaCpaMin", {0.78f}, "Minimum cosine of pointing angle"}; \ + o2::framework::Configurable> lambdaTransRadMin{"lambdaTransRadMin", {0.9f}, "Minimum transverse radius (cm)"}; \ + o2::framework::Configurable> lambdaDcaDauMax{"lambdaDcaDauMax", {0.5f}, "Maximum DCA between the daughters at decay vertex (cm)"}; \ + o2::framework::Configurable> lambdaDcaToPvMin{"lambdaDcaToPvMin", {0.3f}, "Minimum DCA between the lambda and primary vertex"}; \ + o2::framework::Configurable> dauAbsEtaMax{"dauAbsEtaMax", {0.8f}, "Maximum |eta| of all daughters"}; \ + o2::framework::Configurable> dauAbsDcaxyMin{"dauAbsDcaxyMin", {0.05f}, "Minimum |DCAxy| of the daughters and bachelor from primary vertex (cm)"}; \ + o2::framework::Configurable> dauTpcClustersMin{"dauTpcClustersMin", {80.f}, "Minimum number of TPC clusters for daughter tracks"}; \ + o2::framework::Configurable> posDauTpc{"posDauTpc", {5.f}, "Maximum |nsimga_Pion/Proton| TPC for positive daughter tracks"}; \ o2::framework::Configurable> negDauTpc{"negDauTpc", {5.f}, "Maximum |nsimga_Pion/Proton| TPC for negative daughter tracks"}; struct ConfXiBits : o2::framework::ConfigurableGroup { @@ -132,9 +132,9 @@ enum CascadeSels { kLambdaDcaToPvMin, ///< Min. DCA to primary vertex of daughter lambda // selection for bachelor/daugthers - kDauAbsEtaMax, ///< Min. DCA of the daughers/bachelor at primary vertex - kDauTpcClsMin, ///< Min. number of TPC clusters of daughters/bachelor - kDauDcaMin, ///< TPC Pion PID for negative daughter + kDauAbsEtaMax, ///< Max. |eta| of daughter tracks + kDauTpcClsMin, ///< Min. number of TPC clusters of daughters/bachelor + kDauAbsDcaxyMin, ///< Min. |DCAxy| of the daughers and bachelor from primary vertex // PID selection for cascade bachelor kBachelorTpcPion, ///< TPC Pion PID for bachelor @@ -162,7 +162,7 @@ const std::unordered_map cascadeSelectionNames = { {kDauAbsEtaMax, "Daughter Abs Eta Max"}, {kDauTpcClsMin, "Daughter TPC Clusters Min"}, - {kDauDcaMin, "Daughter DCA Min"}, + {kDauAbsDcaxyMin, "Daughter |DCAxy| Min"}, {kBachelorTpcPion, "Bachelor TPC Pion PID"}, {kBachelorTpcKaon, "Bachelor TPC Kaon PID"}, @@ -261,7 +261,7 @@ class CascadeSelection : public baseselection::BaseSelectionaddSelection(kLambdaDcaDauMax, cascadeSelectionNames.at(kLambdaDcaDauMax), config.lambdaDcaDauMax.value, limits::kUpperLimit, true, true, false); this->addSelection(kLambdaDcaToPvMin, cascadeSelectionNames.at(kLambdaDcaToPvMin), config.lambdaDcaToPvMin.value, limits::kLowerLimit, true, true, false); this->addSelection(kDauAbsEtaMax, cascadeSelectionNames.at(kDauAbsEtaMax), config.dauAbsEtaMax.value, limits::kAbsUpperLimit, true, true, false); - this->addSelection(kDauDcaMin, cascadeSelectionNames.at(kDauDcaMin), config.dauDcaMin.value, limits::kAbsLowerLimit, true, true, false); + this->addSelection(kDauAbsDcaxyMin, cascadeSelectionNames.at(kDauAbsDcaxyMin), config.dauAbsDcaxyMin.value, limits::kAbsLowerLimit, true, true, false); this->addSelection(kDauTpcClsMin, cascadeSelectionNames.at(kDauTpcClsMin), config.dauTpcClustersMin.value, limits::kLowerLimit, true, true, false); this->setupSelectionHistogram(registry); @@ -308,10 +308,8 @@ class CascadeSelection : public baseselection::BaseSelection etaDaughters = {std::fabs(bachelor.eta()), std::fabs(posDaughter.eta()), std::fabs(negDaughter.eta())}; this->evaluateObservable(kDauAbsEtaMax, *std::max_element(etaDaughters.begin(), etaDaughters.end())); - std::array dcaDaughters = {std::hypot(bachelor.dcaXY(), bachelor.dcaZ()), - std::hypot(posDaughter.dcaXY(), posDaughter.dcaZ()), - std::hypot(negDaughter.dcaXY(), negDaughter.dcaZ())}; - this->evaluateObservable(kDauDcaMin, *std::min_element(dcaDaughters.begin(), dcaDaughters.end())); + std::array dcaDaughters = {std::fabs(bachelor.dcaXY()), std::fabs(posDaughter.dcaXY()), std::fabs(negDaughter.dcaXY())}; + this->evaluateObservable(kDauAbsDcaxyMin, *std::min_element(dcaDaughters.begin(), dcaDaughters.end())); std::array clustersDaughters = {1.f * bachelor.tpcNClsFound(), 1.f * posDaughter.tpcNClsFound(), 1.f * negDaughter.tpcNClsFound()}; this->evaluateObservable(kDauTpcClsMin, *std::min_element(clustersDaughters.begin(), clustersDaughters.end())); diff --git a/PWGCF/Femto/Core/v0Builder.h b/PWGCF/Femto/Core/v0Builder.h index 777553740bb..ec2a03c1423 100644 --- a/PWGCF/Femto/Core/v0Builder.h +++ b/PWGCF/Femto/Core/v0Builder.h @@ -64,13 +64,13 @@ struct ConfV0Filters : o2::framework::ConfigurableGroup { // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define V0_DEFAULT_BITS \ o2::framework::Configurable passThrough{"passThrough", false, "If true, all V0s are passed through. Bits for all selections are stored."}; \ - o2::framework::Configurable> dcaDauMax{"dcaDauMax", {1.5f}, "Maximum DCA between the daughters at decay vertex (cm)"}; \ + o2::framework::Configurable> dcaDauMax{"dcaDauMax", {1.5f}, "Maximum DCA between the daughters at V0 decay vertex (cm)"}; \ o2::framework::Configurable> cpaMin{"cpaMin", {0.99f}, "Minimum cosine of pointing angle"}; \ o2::framework::Configurable> transRadMin{"transRadMin", {0.2f}, "Minimum transverse radius (cm)"}; \ o2::framework::Configurable> transRadMax{"transRadMax", {100.f}, "Maximum transverse radius (cm)"}; \ o2::framework::Configurable> decayVtxMax{"decayVtxMax", {100.f}, "Maximum distance in x,y,z of the decay vertex from primary vertex (cm)"}; \ o2::framework::Configurable> dauAbsEtaMax{"dauAbsEtaMax", {0.8f}, "Maximum |eta| for daughter tracks"}; \ - o2::framework::Configurable> dauDcaMin{"dauDcaMin", {0.05f}, "Minimum DCA of the daughters from primary vertex (cm)"}; \ + o2::framework::Configurable> dauAbsDcaxyMin{"dauAbsDcaxyMin", {0.05f}, "Minimum DCAxy of the daughters from primary vertex (cm)"}; \ o2::framework::Configurable> dauTpcClustersMin{"dauTpcClustersMin", {80.f}, "Minimum number of TPC clusters for daughter tracks"}; // derived selection bits for lambda @@ -144,9 +144,9 @@ enum V0Sels { kTransRadMax, ///< max. transverse radius // selection for daughter - kDauAbsEtaMax, ///< Max. absolute pseudo rapidity - kDauDcaMin, ///< Min. DCA of the daughters at primary vertex - kDauTpcClsMin, ///< Min. number of TPC clusters of daughter + kDauAbsEtaMax, ///< Max. absolute pseudo rapidity + kDauAbsDcaxyMin, ///< Min. |DCAxy| of the daughters from primary vertex + kDauTpcClsMin, ///< Min. number of TPC clusters of daughter // pid selection for daughters kPosDaughTpcPion, ///< TPC Pion PID for positive daughter @@ -169,7 +169,7 @@ const std::unordered_map v0SelectionNames = { {kTransRadMax, "Max. transverse radius"}, {kDauAbsEtaMax, "Max. absolute pseudo rapidity of daughters"}, - {kDauDcaMin, "Min. DCA of the daughters at primary vertex"}, + {kDauAbsDcaxyMin, "Min. |DCAxy| of the daughters from primary vertex"}, {kDauTpcClsMin, "Min. number of TPC clusters of daughters"}, {kPosDaughTpcPion, "TPC Pion PID for positive daughter"}, @@ -265,7 +265,7 @@ class V0Selection : public baseselection::BaseSelectionaddSelection(kTransRadMin, v0SelectionNames.at(kTransRadMin), config.transRadMin.value, limits::kLowerLimit, true, true, false); this->addSelection(kTransRadMax, v0SelectionNames.at(kTransRadMax), config.transRadMax.value, limits::kUpperLimit, true, true, false); this->addSelection(kDauAbsEtaMax, v0SelectionNames.at(kDauAbsEtaMax), config.dauAbsEtaMax.value, limits::kAbsUpperLimit, true, true, false); - this->addSelection(kDauDcaMin, v0SelectionNames.at(kDauDcaMin), config.dauDcaMin.value, limits::kAbsLowerLimit, true, true, false); + this->addSelection(kDauAbsDcaxyMin, v0SelectionNames.at(kDauAbsDcaxyMin), config.dauAbsDcaxyMin.value, limits::kAbsLowerLimit, true, true, false); this->addSelection(kDauTpcClsMin, v0SelectionNames.at(kDauTpcClsMin), config.dauTpcClustersMin.value, limits::kLowerLimit, true, true, false); this->setupSelectionHistogram(registry); @@ -307,11 +307,11 @@ class V0Selection : public baseselection::BaseSelection(); auto negDaughter = v0candidate.template negTrack_as(); - std::array etaDaughters = {std::fabs(posDaughter.eta()), std::fabs(negDaughter.eta())}; - this->evaluateObservable(kDauAbsEtaMax, *std::max_element(etaDaughters.begin(), etaDaughters.end())); + std::array etaAbsDaughters = {std::fabs(posDaughter.eta()), std::fabs(negDaughter.eta())}; + this->evaluateObservable(kDauAbsEtaMax, *std::max_element(etaAbsDaughters.begin(), etaAbsDaughters.end())); - std::array dcaDaughters = {std::hypot(posDaughter.dcaXY(), posDaughter.dcaZ()), std::hypot(negDaughter.dcaXY(), negDaughter.dcaZ())}; - this->evaluateObservable(kDauDcaMin, *std::min_element(dcaDaughters.begin(), dcaDaughters.end())); + std::array dcaxyAbsDaughters = {std::fabs(posDaughter.dcaXY()), std::fabs(negDaughter.dcaXY())}; + this->evaluateObservable(kDauAbsDcaxyMin, *std::min_element(dcaxyAbsDaughters.begin(), dcaxyAbsDaughters.end())); std::array clustersDaughters = {1.f * posDaughter.tpcNClsFound(), 1.f * negDaughter.tpcNClsFound()}; this->evaluateObservable(kDauTpcClsMin, *std::min_element(clustersDaughters.begin(), clustersDaughters.end())); From 534c83d701a4309cff5417946d884c87f349a9ec Mon Sep 17 00:00:00 2001 From: aferrero2707 Date: Wed, 29 Jul 2026 03:57:18 +0200 Subject: [PATCH 27/71] [PWGDQ] add match attempts in ML training data producer (#17216) --- PWGDQ/Tasks/mftMchMatcher.cxx | 103 +++++++++++++++++++++++++++------- 1 file changed, 84 insertions(+), 19 deletions(-) diff --git a/PWGDQ/Tasks/mftMchMatcher.cxx b/PWGDQ/Tasks/mftMchMatcher.cxx index 165488fcf7c..825e320f369 100644 --- a/PWGDQ/Tasks/mftMchMatcher.cxx +++ b/PWGDQ/Tasks/mftMchMatcher.cxx @@ -48,6 +48,7 @@ #include #include +#include #include #include #include @@ -143,6 +144,7 @@ DECLARE_SOA_COLUMN(Chi2Glob, chi2Glob, float); DECLARE_SOA_COLUMN(Chi2Match, chi2Match, float); DECLARE_SOA_COLUMN(IsAmbig, isAmbig, bool); DECLARE_SOA_COLUMN(MFTMult, mftMult, int); +DECLARE_SOA_COLUMN(MatchAttempts, matchAttempts, int); DECLARE_SOA_COLUMN(DCAX, dcaX, float); DECLARE_SOA_COLUMN(DCAY, dcaY, float); DECLARE_SOA_COLUMN(McMaskGlob, mcMaskGlob, int); @@ -207,6 +209,7 @@ DECLARE_SOA_TABLE(FwdMatchMLCandidates, "AOD", "FWDMLCAND", fwdmatchcandidates::DCAY, fwdmatchcandidates::IsAmbig, fwdmatchcandidates::MFTMult, + fwdmatchcandidates::MatchAttempts, fwdmatchcandidates::McMaskMCH, fwdmatchcandidates::McMaskMFT, fwdmatchcandidates::McMaskGlob, @@ -265,14 +268,13 @@ struct mftMchMatcher { kMatchTypeWrongNonLeading = 5, kMatchTypeDecayNonLeading = 6, kMatchTypeFakeNonLeading = 7, - kMatchTypeUndefined + kMatchTypeUndefined = 8 }; - double mBzAtMftCenter{0}; o2::globaltracking::MatchGlobalFwd mExtrap; int mRunNumber{0}; // needed to detect if the run changed and trigger update of magnetic field - Service ccdbManager; + Service ccdbManager{}; o2::ccdb::CcdbApi fCCDBApi; o2::parameters::GRPMagField* fGrpMag = nullptr; @@ -288,6 +290,22 @@ struct mftMchMatcher { HistogramRegistry registry{"registry", {}}; + template + o2::dataformats::GlobalFwdTrack trackToGlobalFwd(const T& track, const C& cov) + { + double chi2 = track.chi2(); + SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); + std::vector v1{cov.cXX(), cov.cXY(), cov.cYY(), cov.cPhiX(), cov.cPhiY(), + cov.cPhiPhi(), cov.cTglX(), cov.cTglY(), cov.cTglPhi(), cov.cTglTgl(), + cov.c1PtX(), cov.c1PtY(), cov.c1PtPhi(), cov.c1PtTgl(), cov.c1Pt21Pt2()}; + SMatrix55 tcovs(v1.begin(), v1.end()); + o2::track::TrackParCovFwd trackparCov{track.z(), tpars, tcovs, chi2}; + o2::dataformats::GlobalFwdTrack fwdtrack; + fwdtrack.setParameters(trackparCov.getParameters()); + fwdtrack.setCovariances(trackparCov.getCovariances()); + return fwdtrack; + } + template bool pDCACut(const T& mchTrack, const C& collision, double nSigmaPDCA) { @@ -316,11 +334,8 @@ struct mftMchMatcher { double pResEffect = sigmaPDCA / (1. - nrp / (1. + nrp)); double slopeResEffect = 535. * slopeRes * p; double sigmaPDCAWithRes = TMath::Sqrt(pResEffect * pResEffect + slopeResEffect * slopeResEffect); - if (pDCA > nSigmaPDCA * sigmaPDCAWithRes) { - return false; - } - return true; + return (pDCA <= nSigmaPDCA * sigmaPDCAWithRes); } template @@ -333,8 +348,9 @@ struct mftMchMatcher { double nSigmaPdcaCut) { // chi2 cut - if (mchTrack.chi2() > chi2Cut) + if (mchTrack.chi2() > chi2Cut) { return false; + } // momentum cut if (mchTrack.p() < pCut) { @@ -373,8 +389,9 @@ struct mftMchMatcher { std::array etaCut) { // chi2 cut - if (mftTrack.chi2() > chi2Cut) + if (mftTrack.chi2() > chi2Cut) { return false; + } // transverse momentum cut if (mftTrack.pt() < pTCut) { @@ -393,8 +410,9 @@ struct mftMchMatcher { template void initCCDB(BC const& bc) { - if (mRunNumber == bc.runNumber()) + if (mRunNumber == bc.runNumber()) { return; + } fGrpMag = ccdbManager->getForTimeStamp(grpmagPath, bc.timestamp()); @@ -470,7 +488,7 @@ struct mftMchMatcher { } } } - for (auto& pairCand : mCandidates) { + for (const auto& pairCand : mCandidates) { fBestMatch[pairCand.second.second] = true; } } @@ -522,8 +540,9 @@ struct mftMchMatcher { bool isPairedMuon(int64_t muonTrackId, const std::vector>& matchablePairs) { for (const auto& [id1, id2] : matchablePairs) { - if (muonTrackId == id1) + if (muonTrackId == id1) { return true; + } } return false; } @@ -542,8 +561,9 @@ struct mftMchMatcher { // search for an MFT track that is associated to the MCH mother particle for (const auto& mftTrack : mftTracks) { // skip tracks that do not have an associated MC particle - if (!mftTrack.has_mcParticle()) + if (!mftTrack.has_mcParticle()) { continue; + } if (mftTrack.mcParticle().globalIndex() == mchMotherParticle.globalIndex()) { return true; @@ -593,14 +613,50 @@ struct mftMchMatcher { return result; } + template + int getMftMchMatchAttempts(EVT const& collisions, + BC const& bcs, + TMUON const& mchTrack, + TMFTS const& mftTracks) + { + if (!mchTrack.has_collision()) { + return 0; + } + const auto& collMch = collisions.rawIteratorAt(mchTrack.collisionId()); + const auto& bcMch = bcs.rawIteratorAt(collMch.bcId()); + + int attempts{0}; + for (const auto& mftTrack : mftTracks) { + if (!mftTrack.has_collision()) { + continue; + } + + const auto& collMft = collisions.rawIteratorAt(mftTrack.collisionId()); + const auto& bcMft = bcs.rawIteratorAt(collMft.bcId()); + + int64_t deltaBc = static_cast(bcMft.globalBC()) - static_cast(bcMch.globalBC()); + double deltaBcNS = o2::constants::lhc::LHCBunchSpacingNS * deltaBc; + double deltaTrackTime = mftTrack.trackTime() - mchTrack.trackTime() + deltaBcNS; + double trackTimeResTot = mftTrack.trackTimeRes() + mchTrack.trackTimeRes(); + + if (std::fabs(deltaTrackTime) > trackTimeResTot) { + continue; + } + attempts += 1; + } + + return attempts; + } template void fillTable(TCOLLS const& collisions, - TBCS const& /*bcs*/, + TBCS const& bcs, TMUONS const& muonTracks, TMFTS const& mftTracks, TCOVS const& mftCovs) { + std::unordered_map matchAttemptsMap; + registry.get(HIST("acceptedEvents"))->Fill(0); // reject a randomly selected fraction of events if (fSamplingFraction < 1.0) { @@ -619,11 +675,11 @@ struct mftMchMatcher { } mftCovIndexes.clear(); - for (auto& mftTrackCov : mftCovs) { + for (const auto& mftTrackCov : mftCovs) { mftCovIndexes[mftTrackCov.matchMFTTrackId()] = mftTrackCov.globalIndex(); } - for (auto muon : muonTracks) { + for (const auto& muon : muonTracks) { // only consider global MFT-MCH-MID matches if (static_cast(muon.trackType()) != 0) { continue; @@ -650,7 +706,7 @@ struct mftMchMatcher { auto mftTime = mfttrack.trackTime() + bc_coll.globalBC() * o2::constants::lhc::LHCBunchSpacingNS; o2::track::TrackParCovFwd mftprop = VarManager::FwdToTrackPar(mfttrack, mfttrackcov); - o2::track::TrackParCovFwd muonprop = VarManager::FwdToTrackPar(muontrack, muontrack); + o2::dataformats::GlobalFwdTrack muonprop = trackToGlobalFwd(muontrack, muontrack); if (fzMatching.value < 0.) { mftprop = VarManager::PropagateFwd(mfttrack, mfttrackcov, fzMatching.value); muonprop = VarManager::PropagateMuon(muontrack, collision, VarManager::kToMatching); @@ -670,6 +726,14 @@ struct mftMchMatcher { bool IsAmbig = (muon.compatibleCollIds().size() != 1); int MFTMult = collision.mftNtracks(); + int matchAttempts = 0; + auto matchAttemptsIt = matchAttemptsMap.find(muontrack.globalIndex()); + if (matchAttemptsIt == matchAttemptsMap.end()) { + matchAttempts = getMftMchMatchAttempts(collisions, bcs, muontrack, mftTracks); + matchAttemptsMap.insert(std::make_pair(static_cast(muontrack.globalIndex()), matchAttempts)); + } else { + matchAttempts = matchAttemptsIt->second; + } auto matchType = kMatchTypeUndefined; if constexpr (isMc) { @@ -789,6 +853,7 @@ struct mftMchMatcher { muon.fwdDcaY(), IsAmbig, MFTMult, + matchAttempts, mcMaskMuon, mcMaskMft, ncMaskGlob, @@ -833,8 +898,8 @@ struct mftMchMatcher { PROCESS_SWITCH(mftMchMatcher, processRD, "process_RD", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(context)}; }; From 26b3bc5384ce75f97f84590aafa68f0c5b03ffda Mon Sep 17 00:00:00 2001 From: glegras <71757105+glegras@users.noreply.github.com> Date: Wed, 29 Jul 2026 03:59:15 +0200 Subject: [PATCH 28/71] [PWGDQ] add event mixing for Dalitz selection (#17165) --- PWGDQ/Tasks/DalitzSelection.cxx | 396 ++++++++++++++++++++++++++------ 1 file changed, 324 insertions(+), 72 deletions(-) diff --git a/PWGDQ/Tasks/DalitzSelection.cxx b/PWGDQ/Tasks/DalitzSelection.cxx index 76b01e073bf..4c3a6a7e581 100644 --- a/PWGDQ/Tasks/DalitzSelection.cxx +++ b/PWGDQ/Tasks/DalitzSelection.cxx @@ -21,6 +21,8 @@ #include "PWGDQ/Core/CutsLibrary.h" #include "PWGDQ/Core/HistogramManager.h" #include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/MixingHandler.h" +#include "PWGDQ/Core/MixingLibrary.h" #include "PWGDQ/Core/VarManager.h" #include "PWGDQ/DataModel/ReducedInfoTables.h" @@ -32,7 +34,9 @@ #include "Common/DataModel/TrackSelectionTables.h" #include +#include #include +#include #include #include #include @@ -98,11 +102,6 @@ struct DalitzSelection { Configurable fConfigTrackCutsJSON{"cfgTrackCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; Configurable fConfigTrackCutsProbeJSON{"cfgTrackCutsProbeJSON", "", "Additional list of barrel track cuts for the probe in JSON format"}; Configurable fConfigPairCutsJSON{"cfgPairCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; - Configurable fConfigPtLow{"cfgLowPt", 0.1f, "Low pt cut for Dalitz tracks in the barrel"}; - Configurable fConfigEtaCut{"cfgEtaCut", 0.9f, "Eta cut for Dalitz tracks in the barrel"}; - Configurable fConfigTPCNSigLow{"cfgTPCNSigElLow", -3.f, "Low TPCNSigEl cut for Dalitz tracks in the barrel"}; - Configurable fConfigTPCNSigHigh{"cfgTPCNSigElHigh", 3.f, "High TPCNsigEl cut for Dalitz tracks in the barrel"}; - Configurable fConfigTrackSel{"cfgTrackSel", 0, "track selection requirement: 0: all, 1: reject ITS only, 2: reject TPC only, 3: reject ITS only and TPC only"}; } fConfigCuts; // histograms @@ -118,20 +117,23 @@ struct DalitzSelection { Configurable fQA{"cfgQA", true, "QA histograms"}; Configurable fRemoveDoubleCounting{"cfgRemoveDoubleCounting", true, "If a track/pair is selected for several collisions, we still count it only once"}; // Configurables for TPC post-calibration maps + Configurable fRunEventMixing{"cfgRunEventMixing", false, "Whether or not run event mixing (across TFs)"}; + Configurable fConfigMixingDepth{"cfgMixingDepth", 100, "Number of Events stored for event mixing"}; + Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; + Configurable fConfigMixingVariablesJson{"cfgMixingVarsJSON", "", "Mixing configs in JSON format"}; Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable fConfigCcdbPathTPC{"ccdb-path-tpc", "Users/i/iarsene/Calib/TPCpostCalib", "base path to the ccdb object"}; Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; Configurable fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas"}; + Configurable fConfigShiftTPConly{"cfgShiftTPConly", true, "If true, shift the TPC only tracks in z for DCAz"}; Configurable fUseRemoteField{"cfgUseRemoteField", true, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; } fConfigOptions; - Service fCCDB; + Service fCCDB{}; o2::parameters::GRPMagField* grpmag = nullptr; - int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. - - Filter filterBarrelTrack = (o2::aod::track::pt >= fConfigCuts.fConfigPtLow) && (nabs(o2::aod::track::eta) <= fConfigCuts.fConfigEtaCut) && ((o2::aod::pidtpc::tpcNSigmaEl <= fConfigCuts.fConfigTPCNSigHigh && o2::aod::pidtpc::tpcNSigmaEl >= fConfigCuts.fConfigTPCNSigLow) || ((o2::aod::track::v001::detectorMap & 2) == 0)) && ((fConfigCuts.fConfigTrackSel != 1 && fConfigCuts.fConfigTrackSel != 3) || ((o2::aod::track::v001::detectorMap & 2) != 0)) && ((fConfigCuts.fConfigTrackSel != 2 && fConfigCuts.fConfigTrackSel != 3) || ((o2::aod::track::v001::detectorMap & 1) != 0)); + int fCurrentRun = -1; // needed to detect if the run changed and trigger update of calibrations etc. OutputObj fOutputList{"output"}; //! the histogram manager output list OutputObj fStatsList{"Statistics"}; //! skimming statistics @@ -146,16 +148,23 @@ struct DalitzSelection { std::map fDalitzmapProbeAmbiguity; std::map, uint8_t> fAmbiguousPairs; - AnalysisCompositeCut* fEventCut; + AnalysisCompositeCut* fEventCut = nullptr; std::vector fTrackCuts; std::vector fTrackCutsProbe; std::vector fPairCuts; - bool fIsTagAndProbe; // whether we are doing tag and probe, or just symmetric cuts - bool fIsOutputRequested; - bool fSkipEvent; // speed up by skipping next step of event if no track/pair is selected + bool fIsTagAndProbe = false; // whether we are doing tag and probe, or just symmetric cuts + bool fIsOutputRequested = false; + bool fSkipEvent = false; // speed up by skipping next step of event if no track/pair is selected + + MixingHandler fMixingHandler; + MixingHandler::MixingEvent* fMixingEvent = nullptr; + + HistogramManager* fHistMan = nullptr; - HistogramManager* fHistMan; + float fVdrift = -1.; // TPC drift velocity + int64_t fFirstTime = 0; // validity time for the v drift, granularity is smaller than one run + int64_t fLastTime = 0; void init(o2::framework::InitContext& context) { @@ -226,7 +235,7 @@ struct DalitzSelection { } // CCDB configuration - if (fConfigOptions.fConfigComputeTPCpostCalib) { + if (fConfigOptions.fConfigComputeTPCpostCalib || fConfigOptions.fUseRemoteField || fConfigOptions.fConfigShiftTPConly) { fCCDB->setURL(fConfigOptions.fConfigCcdbUrl.value); fCCDB->setCaching(true); fCCDB->setLocalObjectValidityChecking(); @@ -238,7 +247,7 @@ struct DalitzSelection { fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + fHistMan->SetDefaultVarNames(static_cast(VarManager::fgVariableNames), static_cast(VarManager::fgVariableUnits)); // Create the histogram class names to be added to the histogram manager TString histClasses = ""; @@ -254,36 +263,44 @@ struct DalitzSelection { if (fConfigOptions.fConfigEnableLikeSign) { histClasses += Form("PairLS_%s_%s_%s;", (*trackCut).GetName(), fTrackCutsProbe.at(iCut).GetName(), (*pairCut).GetName()); } + if (fConfigOptions.fRunEventMixing) { + histClasses += Form("PairME_%s_%s_%s;", (*trackCut).GetName(), fTrackCutsProbe.at(iCut).GetName(), (*pairCut).GetName()); + histClasses += Form("PairMELS_%s_%s_%s;", (*trackCut).GetName(), fTrackCutsProbe.at(iCut).GetName(), (*pairCut).GetName()); + } } else { histClasses += Form("TrackBarrel_%s_%s;", (*trackCut).GetName(), (*pairCut).GetName()); histClasses += Form("Pair_%s_%s;", (*trackCut).GetName(), (*pairCut).GetName()); if (fConfigOptions.fConfigEnableLikeSign) { histClasses += Form("PairLS_%s_%s;", (*trackCut).GetName(), (*pairCut).GetName()); } + if (fConfigOptions.fRunEventMixing) { + histClasses += Form("PairME_%s_%s;", (*trackCut).GetName(), (*pairCut).GetName()); + histClasses += Form("PairMELS_%s_%s;", (*trackCut).GetName(), (*pairCut).GetName()); + } } } } // Define histograms - std::unique_ptr objArray(histClasses.Tokenize(";")); - for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { - TString classStr = objArray->At(iclass)->GetName(); + std::unique_ptr histArray(histClasses.Tokenize(";")); + for (Int_t iclass = 0; iclass < histArray->GetEntries(); ++iclass) { + TString classStr = histArray->At(iclass)->GetName(); fHistMan->AddHistClass(classStr.Data()); if (classStr.Contains("Event")) { - dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "event", ""); + dqhistograms::DefineHistograms(fHistMan, histArray->At(iclass)->GetName(), "event", ""); } TString histTrackName = fConfigHistograms.fConfigAddTrackHistogram.value; if (classStr.Contains("Track")) { - dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "track", histTrackName); - dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "software-trigger", histTrackName); + dqhistograms::DefineHistograms(fHistMan, histArray->At(iclass)->GetName(), "track", histTrackName); + dqhistograms::DefineHistograms(fHistMan, histArray->At(iclass)->GetName(), "software-trigger", histTrackName); } TString histPairName = fConfigHistograms.fConfigAddPairHistogram.value; if (classStr.Contains("Pair")) { - dqhistograms::DefineHistograms(fHistMan, objArray->At(iclass)->GetName(), "pair", histPairName); + dqhistograms::DefineHistograms(fHistMan, histArray->At(iclass)->GetName(), "pair", histPairName); } } @@ -297,7 +314,7 @@ struct DalitzSelection { fStatsList->SetOwner(kTRUE); // Dalitz selection statistics: one bin for each (track,pair) selection - TH1I* histTracks = new TH1I("TrackStats", "Dalitz selection statistics", fPairCuts.size() * (1 + fIsTagAndProbe) + 1, -0.5, fPairCuts.size() * (1 + fIsTagAndProbe) + 0.5); + TH1I* histTracks = new TH1I("TrackStats", "Dalitz selection statistics", fPairCuts.size() * (1 + static_cast(fIsTagAndProbe)) + 1, -0.5, fPairCuts.size() * (1 + static_cast(fIsTagAndProbe)) + 0.5); histTracks->GetXaxis()->SetBinLabel(1, "Events selected"); auto trackCut = fTrackCuts.begin(); int icut = 1; @@ -318,7 +335,7 @@ struct DalitzSelection { // autodetect whether the dalitz bits are requested fIsOutputRequested = false; - auto& workflows = context.services().template get(); + const auto& workflows = context.services().template get(); // autodetect this table in other devices for (o2::framework::DeviceSpec const& device : workflows.devices) { // Check if this device subscribed to the dalitz table @@ -332,37 +349,64 @@ struct DalitzSelection { } } } + + // setup mixing handler + if (fConfigOptions.fRunEventMixing) { + TString mixVarsString = fConfigOptions.fConfigMixingVariables.value; + TString mixVarsJsonString = fConfigOptions.fConfigMixingVariablesJson.value; + std::unique_ptr objArray(mixVarsString.Tokenize(",")); + if (objArray->GetEntries() > 0 || mixVarsJsonString != "") { + if (objArray->GetEntries() > 0) { + for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { + dqmixing::SetUpMixing(&fMixingHandler, objArray->At(iVar)->GetName()); + } + } + } + if (mixVarsJsonString != "") { + dqmixing::SetUpMixingFromJSON(&fMixingHandler, mixVarsJsonString.Data()); + } + fMixingHandler.SetPoolDepth(fConfigOptions.fConfigMixingDepth); + fMixingHandler.Init(); + } } template void runTrackSelection(TTracks const& tracksBarrel, TEvent const& collision) { - fSkipEvent = true; for (const auto& track1 : tracksBarrel) { - uint8_t filterMap = uint8_t(0); - uint8_t filterMapProbe = uint8_t(0); + auto filterMap = uint8_t(0); + auto filterMapProbe = uint8_t(0); int fullTrackIdx = 0; if constexpr (isReassoc) { auto const& fullTrack = track1.template track_as(); - // Basic filter cuts which cannot be applied directly in case of reassoc - if (fullTrack.pt() < fConfigCuts.fConfigPtLow) { - continue; - } - if (std::fabs(fullTrack.eta()) > fConfigCuts.fConfigEtaCut) { - continue; - } - if (fullTrack.hasTPC() && (fullTrack.tpcNSigmaEl() < fConfigCuts.fConfigTPCNSigLow || fullTrack.tpcNSigmaEl() > fConfigCuts.fConfigTPCNSigHigh)) { - continue; - } - if ((fConfigCuts.fConfigTrackSel == 1 || fConfigCuts.fConfigTrackSel == 3) && !fullTrack.hasTPC()) { - continue; - } - if ((fConfigCuts.fConfigTrackSel == 2 || fConfigCuts.fConfigTrackSel == 3) && !fullTrack.hasITS()) { - continue; - } VarManager::FillTrack(fullTrack); VarManager::FillTrackCollision(fullTrack, collision); + // if the track is TPC only, we shift it in z to be compatible with vertex time + if (!fullTrack.hasITS() && !fullTrack.hasTOF() && !fullTrack.hasTRD() && fVdrift > 0. && fConfigOptions.fConfigShiftTPConly) { + float tTB = 0.; + if (collision.collisionTimeRes() < 0.f || fullTrack.collisionId() < 0) { // use track data + tTB = fullTrack.trackTime(); + } else { + // The TPC track can be associated to a different BC than the one the collision under assumption is; + // we need to calculate the difference and subtract this from the trackTime() + const auto trackBC = fullTrack.template collision_as().template bc_as().globalBC(); + const auto colBC = collision.template foundBC_as().globalBC(); + float sign{1.f}; + uint64_t diffBC{0}; + if (colBC < trackBC) { + sign = -1.f; + diffBC = (trackBC - colBC); + } else { + diffBC = (colBC - trackBC); + } + float diffBCNS = sign * static_cast(diffBC) * static_cast(o2::constants::lhc::LHCBunchSpacingNS); + tTB = collision.collisionTime() + diffBCNS; + } + float dTime = tTB - fullTrack.trackTime(); + float dDrift = dTime * fVdrift; + VarManager::fgValues[VarManager::kTrackDCAz] += ((fullTrack.tgl() < 0.) ? -dDrift : dDrift); + } fullTrackIdx = fullTrack.globalIndex(); } else { VarManager::FillTrack(track1); @@ -370,7 +414,7 @@ struct DalitzSelection { } int i = 0; for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); ++cut, ++i) { - if ((*cut).IsSelected(VarManager::fgValues)) { + if ((*cut).IsSelected(static_cast(VarManager::fgValues))) { filterMap |= (uint8_t(1) << i); fSkipEvent = false; } @@ -378,7 +422,7 @@ struct DalitzSelection { if (fIsTagAndProbe) { i = 0; for (auto cut = fTrackCutsProbe.begin(); cut != fTrackCutsProbe.end(); ++cut, ++i) { - if ((*cut).IsSelected(VarManager::fgValues)) { + if ((*cut).IsSelected(static_cast(VarManager::fgValues))) { filterMapProbe |= (uint8_t(1) << i); } } @@ -389,11 +433,39 @@ struct DalitzSelection { if (filterMapProbe) { fTrackmapProbe[fullTrackIdx] = filterMapProbe; } + + if (fConfigOptions.fRunEventMixing && (filterMap || filterMapProbe)) { + // add the track to event mixing, the track1 array is used for the tag and the track2 array is used for the probe + if constexpr (isReassoc) { + auto const& fullTrack = track1.template track_as(); + if (filterMap) { + // we use the 8th bit to keep track of the track sign + MixingHandler::MixingTrack mixingTrack(fullTrack.pt(), fullTrack.eta(), fullTrack.phi(), fullTrack.sign() > 0 ? (static_cast(filterMap) | (static_cast(1) << 8)) : static_cast(filterMap)); + fMixingEvent->AddTrack1(mixingTrack); + } + if (filterMapProbe) { + // we use the 8th bit to keep track of the track sign + MixingHandler::MixingTrack mixingTrack(fullTrack.pt(), fullTrack.eta(), fullTrack.phi(), fullTrack.sign() > 0 ? (static_cast(filterMapProbe) | (static_cast(1) << 8)) : static_cast(filterMapProbe)); + fMixingEvent->AddTrack2(mixingTrack); + } + } else { + if (filterMap) { + // we use the 8th bit to keep track of the track sign + MixingHandler::MixingTrack mixingTrack(track1.pt(), track1.eta(), track1.phi(), track1.sign() > 0 ? (static_cast(filterMap) | (static_cast(1) << 8)) : static_cast(filterMap)); + fMixingEvent->AddTrack1(mixingTrack); + } + if (filterMapProbe) { + // we use the 8th bit to keep track of the track sign + MixingHandler::MixingTrack mixingTrack(track1.pt(), track1.eta(), track1.phi(), track1.sign() > 0 ? (static_cast(filterMapProbe) | (static_cast(1) << 8)) : static_cast(filterMapProbe)); + fMixingEvent->AddTrack2(mixingTrack); + } + } + } } // end loop over tracks } template - void runDalitzPairing(TTracks const& tracks1, TTracks const& tracks2, TEvent collision) + void runDalitzPairing(TTracks const& tracks1, TTracks const& tracks2, TEvent const& collision) { if (isReassoc & fConfigOptions.fRemoveDoubleCounting) { fDalitzmapAmbiguity.clear(); @@ -402,8 +474,8 @@ struct DalitzSelection { fSkipEvent = true; for (const auto& track1 : tracks1) { - int trackIdx1; - bool isTrack1P; + int trackIdx1 = 0; + bool isTrack1P = false; if constexpr (isReassoc) { auto const& fullTrack1 = track1.template track_as(); @@ -419,8 +491,8 @@ struct DalitzSelection { } for (const auto& track2 : tracks2) { - int trackIdx2; - bool isLikeSign; + int trackIdx2 = 0; + bool isLikeSign = false; if constexpr (isReassoc) { auto const& fullTrack2 = track2.template track_as(); trackIdx2 = fullTrack2.globalIndex(); @@ -461,13 +533,13 @@ struct DalitzSelection { if (!(twoTracksFilterMap & (uint8_t(1) << icut))) { continue; } - if ((*pairCut).IsSelected(VarManager::fgValues)) { + if ((*pairCut).IsSelected(static_cast(VarManager::fgValues))) { fSkipEvent = false; bool isPairAlreadySelected = false; if (isReassoc & fConfigOptions.fRemoveDoubleCounting) { // if we remove double counting and the pair is already selected, we don't fill the histograms std::pair iPair(trackIdx1, trackIdx2); - if (fAmbiguousPairs.find(iPair) != fAmbiguousPairs.end()) { + if (fAmbiguousPairs.contains(iPair)) { if (fAmbiguousPairs[iPair] & (static_cast(1) << icut)) { // if this pair is already stored with this cut isPairAlreadySelected = true; } else { @@ -486,26 +558,26 @@ struct DalitzSelection { } if (fIsTagAndProbe) { if (isReassoc & fConfigOptions.fRemoveDoubleCounting) { - fDalitzmapProbeAmbiguity[trackIdx1] |= (uint8_t(1) << icut); + fDalitzmapProbeAmbiguity[trackIdx2] |= (uint8_t(1) << icut); } else { fDalitzmapProbe[trackIdx2] |= (uint8_t(1) << icut); } if (fConfigOptions.fQA && !isPairAlreadySelected) { - fHistMan->FillHistClass(Form("Pair_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("Pair_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()), static_cast(VarManager::fgValues)); } } else { if (isReassoc & fConfigOptions.fRemoveDoubleCounting) { - fDalitzmapAmbiguity[trackIdx1] |= (uint8_t(1) << icut); + fDalitzmapAmbiguity[trackIdx2] |= (uint8_t(1) << icut); } else { fDalitzmap[trackIdx2] |= (uint8_t(1) << icut); } if (fConfigOptions.fQA && !isPairAlreadySelected) { - fHistMan->FillHistClass(Form("Pair_%s_%s", (*trackCut).GetName(), (*pairCut).GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("Pair_%s_%s", (*trackCut).GetName(), (*pairCut).GetName()), static_cast(VarManager::fgValues)); } } } else { if (fConfigOptions.fQA && !isPairAlreadySelected) { - fHistMan->FillHistClass(fIsTagAndProbe ? Form("PairLS_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()) : Form("PairLS_%s_%s", (*trackCut).GetName(), (*pairCut).GetName()), VarManager::fgValues); + fHistMan->FillHistClass(fIsTagAndProbe ? Form("PairLS_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()) : Form("PairLS_%s_%s", (*trackCut).GetName(), (*pairCut).GetName()), static_cast(VarManager::fgValues)); } } // end if like-sign } // end if isSelected @@ -516,12 +588,12 @@ struct DalitzSelection { // Fill Hists if (fConfigOptions.fQA && !fSkipEvent) { for (const auto& track : tracks1) { - uint8_t filterMap; - uint8_t filterMapProbe; + auto filterMap = uint8_t(0); + auto filterMapProbe = uint8_t(0); if constexpr (isReassoc) { auto const& fullTrack = track.template track_as(); - filterMap = fDalitzmap[fullTrack.globalIndex()]; - filterMapProbe = fDalitzmapProbe[fullTrack.globalIndex()]; + filterMap = fDalitzmap[fullTrack.globalIndex()]; // cppcheck-suppress redundantInitialization + filterMapProbe = fDalitzmapProbe[fullTrack.globalIndex()]; // cppcheck-suppress redundantInitialization if (fConfigOptions.fRemoveDoubleCounting) { // we remove track selections which were already selected before uint8_t currentFilterMap = fDalitzmapAmbiguity[fullTrack.globalIndex()]; @@ -540,6 +612,31 @@ struct DalitzSelection { VarManager::FillTrack(fullTrack); // The caveat here is that we only fill the DCA to the first selected collision VarManager::FillTrackCollision(fullTrack, collision); + // if the track is TPC only, we shift it in z to be compatible with vertex time + if (!fullTrack.hasITS() && !fullTrack.hasTOF() && !fullTrack.hasTRD() && fVdrift > 0. && fConfigOptions.fConfigShiftTPConly) { + float tTB = 0.; + if (collision.collisionTimeRes() < 0.f || fullTrack.collisionId() < 0) { // use track data + tTB = fullTrack.trackTime(); + } else { + // The TPC track can be associated to a different BC than the one the collision under assumption is; + // we need to calculate the difference and subtract this from the trackTime() + const auto trackBC = fullTrack.template collision_as().template bc_as().globalBC(); + const auto colBC = collision.template foundBC_as().globalBC(); + float sign{1.f}; + uint64_t diffBC{0}; + if (colBC < trackBC) { + sign = -1.f; + diffBC = (trackBC - colBC); + } else { + diffBC = (colBC - trackBC); + } + float diffBCNS = sign * static_cast(diffBC) * static_cast(o2::constants::lhc::LHCBunchSpacingNS); + tTB = collision.collisionTime() + diffBCNS; + } + float dTime = tTB - fullTrack.trackTime(); + float dDrift = dTime * fVdrift; + VarManager::fgValues[VarManager::kTrackDCAz] += ((fullTrack.tgl() < 0.) ? -dDrift : dDrift); + } } else { filterMap = fDalitzmap[track.globalIndex()]; filterMapProbe = fDalitzmapProbe[track.globalIndex()]; @@ -555,18 +652,103 @@ struct DalitzSelection { auto trackCut = fTrackCuts.begin(); for (auto pairCut = fPairCuts.begin(); pairCut != fPairCuts.end(); pairCut++, trackCut++, icut++) { if (filterMap & (uint8_t(1) << icut)) { - reinterpret_cast(fStatsList->At(0))->Fill(fIsTagAndProbe ? 2 * icut + 1 : icut + 1); - fHistMan->FillHistClass(fIsTagAndProbe ? Form("TrackBarrelTag_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()) : Form("TrackBarrel_%s_%s", (*trackCut).GetName(), (*pairCut).GetName()), VarManager::fgValues); + static_cast(fStatsList->At(0))->Fill(fIsTagAndProbe ? 2 * icut + 1 : icut + 1); + fHistMan->FillHistClass(fIsTagAndProbe ? Form("TrackBarrelTag_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()) : Form("TrackBarrel_%s_%s", (*trackCut).GetName(), (*pairCut).GetName()), static_cast(VarManager::fgValues)); } if (filterMapProbe & (uint8_t(1) << icut)) { - reinterpret_cast(fStatsList->At(0))->Fill(2 * icut + 2); - fHistMan->FillHistClass(Form("TrackBarrelProbe_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()), VarManager::fgValues); + static_cast(fStatsList->At(0))->Fill(2 * icut + 2); + fHistMan->FillHistClass(Form("TrackBarrelProbe_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()), static_cast(VarManager::fgValues)); } } } } } + void runMixing() + { + // run the mixing with the events in the pool corresponding to this event + auto& pool = fMixingHandler.GetPool(fMixingHandler.FindEventCategory(static_cast(VarManager::fgValues))); + + // Bit 8 is a special bit in this case (keeping track sign), so we don't want it to be erased, except when everything else is empty + uint32_t bitMask = (static_cast(1) << 8); + fMixingEvent->ClearFilteringMask(bitMask); + + for (auto& poolEvent : pool.events) { + if ((poolEvent.filteringMask & static_cast(255)) == 0) { + // all other bits have been erased, so we can also mark bit 8 for deletion + poolEvent.filteringMask |= bitMask; + poolEvent.counters[8] = fMixingHandler.GetPoolDepth(); + } + for (auto const& t1 : fMixingEvent->tracks1) { + // tag from event 1 and probe from event 2. If not tag and probe method, all tracks are in tracks1 array + for (auto const& t2 : (fIsTagAndProbe ? poolEvent.tracks2 : poolEvent.tracks1)) { + // check the two-track filter for the mixed pair + auto mixedTwoTrackFilter = static_cast(t1.filteringFlags & t2.filteringFlags & static_cast(255)); // we keep only first 8 bits + if (mixedTwoTrackFilter == 0) { + continue; + } + VarManager::FillPairMEAcrossTFs(t1, t2); + if (fIsTagAndProbe) { + // if we run with tag-and-probe method, we often want quantities as a function of kinematics of the probe, so they need to be filled + // (They are not filled by default in the FillPairMEAcrossTFs) to keep it light + VarManager::fgValues[VarManager::kPt2] = t2.pt; + VarManager::fgValues[VarManager::kEta2] = t2.eta; + VarManager::fgValues[VarManager::kPhi2] = t2.phi; + } + bool isLS = (t1.filteringFlags & (static_cast(1) << 8)) == (t2.filteringFlags & (static_cast(1) << 8)); + for (uint32_t icut = 0; icut < fPairCuts.size(); icut++) { + if (((mixedTwoTrackFilter & (static_cast(1) << icut)) != 0) && fPairCuts.at(icut).IsSelected(static_cast(VarManager::fgValues))) { + if (fIsTagAndProbe) { + if (!isLS) { + fHistMan->FillHistClass(Form("PairME_%s_%s_%s", fTrackCuts.at(icut).GetName(), fTrackCutsProbe.at(icut).GetName(), fPairCuts.at(icut).GetName()), static_cast(VarManager::fgValues)); + } else { + fHistMan->FillHistClass(Form("PairMELS_%s_%s_%s", fTrackCuts.at(icut).GetName(), fTrackCutsProbe.at(icut).GetName(), fPairCuts.at(icut).GetName()), static_cast(VarManager::fgValues)); + } + } else { + if (!isLS) { + fHistMan->FillHistClass(Form("PairME_%s_%s", fTrackCuts.at(icut).GetName(), fPairCuts.at(icut).GetName()), static_cast(VarManager::fgValues)); + } else { + fHistMan->FillHistClass(Form("PairMELS_%s_%s", fTrackCuts.at(icut).GetName(), fPairCuts.at(icut).GetName()), static_cast(VarManager::fgValues)); + } + } + } + } + } + } + if (fIsTagAndProbe) { + for (auto const& t2 : fMixingEvent->tracks2) { + // tag from event 2 and probe from event 1 + for (auto const& t1 : poolEvent.tracks1) { + auto mixedTwoTrackFilter = static_cast(t1.filteringFlags & t2.filteringFlags & static_cast(255)); // we keep only first 8 bits + if (mixedTwoTrackFilter == 0) { + continue; + } + VarManager::FillPairMEAcrossTFs(t1, t2); + if (fIsTagAndProbe) { + // if we run with tag-and-probe method, we often want quantities as a function of kinematics of the probe, so they need to be filled + // (They are not filled by default in the FillPairMEAcrossTFs to keep it light) + VarManager::fgValues[VarManager::kPt2] = t2.pt; + VarManager::fgValues[VarManager::kEta2] = t2.eta; + VarManager::fgValues[VarManager::kPhi2] = t2.phi; + } + bool isLS = (t1.filteringFlags & (static_cast(1) << 8)) == (t2.filteringFlags & (static_cast(1) << 8)); + for (uint32_t icut = 0; icut < fPairCuts.size(); icut++) { + if (((mixedTwoTrackFilter & (static_cast(1) << icut)) != 0) && fPairCuts.at(icut).IsSelected(static_cast(VarManager::fgValues))) { + if (!isLS) { + fHistMan->FillHistClass(Form("PairME_%s_%s_%s", fTrackCuts.at(icut).GetName(), fTrackCutsProbe.at(icut).GetName(), fPairCuts.at(icut).GetName()), static_cast(VarManager::fgValues)); + } else { + fHistMan->FillHistClass(Form("PairMELS_%s_%s_%s", fTrackCuts.at(icut).GetName(), fTrackCutsProbe.at(icut).GetName(), fPairCuts.at(icut).GetName()), static_cast(VarManager::fgValues)); + } + } + } + } // end loop on tracks of event 1 + } // end loop on tracks of event 2 + } // end if tag and probe + } // end loop on events from the pool + // add the current event to the pool + pool.UpdatePool(*fMixingEvent, fMixingHandler.GetPoolDepth()); + } + void initNewRun(int64_t timestamp) { @@ -601,21 +783,36 @@ struct DalitzSelection { } } + void initNewDF(int64_t timestamp) + { + if (fConfigOptions.fConfigShiftTPConly && (timestamp < fFirstTime || timestamp > fLastTime)) { + std::map headers; + const auto& vd = fCCDB->getForTimeStamp("TPC/Calib/VDriftTgl", timestamp, &headers); + fVdrift = vd->refVDrift * vd->corrFact * 1e-3; + fFirstTime = stol(headers["Valid-From"]); + fLastTime = stol(headers["Valid-Until"]); + headers.clear(); + LOGF(info, "updated v drift with %f cm/ns, valid from %d to %d, current timestamp: %d", fVdrift, fFirstTime, fLastTime, timestamp); + } + } + void processFullTracks(MyEventsWithCent const& collisions, aod::BCsWithTimestamps const&, soa::Filtered const& filteredTracks, MyBarrelTracks const& tracks) { const int pairType = VarManager::kDecayToEE; fDalitzmap.clear(); fDalitzmapProbe.clear(); + bool initDFDone = false; // some quantities might need to be updated for each dataframe + for (const auto& collision : collisions) { fTrackmap.clear(); fTrackmapProbe.clear(); VarManager::ResetValues(VarManager::kNRunWiseVariables, VarManager::kNBarrelTrackVariables); VarManager::FillEvent(collision); - bool isEventSelected = fEventCut->IsSelected(VarManager::fgValues); + bool isEventSelected = fEventCut->IsSelected(static_cast(VarManager::fgValues)); if (isEventSelected) { - reinterpret_cast(fStatsList->At(0))->Fill(0); + static_cast(fStatsList->At(0))->Fill(0); auto bc = collision.template bc_as(); @@ -624,11 +821,28 @@ struct DalitzSelection { fCurrentRun = bc.runNumber(); } + if (!initDFDone) { + initNewDF(bc.timestamp()); + initDFDone = true; + } + + if (fConfigOptions.fRunEventMixing) { + fMixingEvent = new MixingHandler::MixingEvent(); + } + auto groupedFilteredTracks = filteredTracks.sliceBy(perCollision, collision.globalIndex()); runTrackSelection(groupedFilteredTracks, nullptr); if (!fSkipEvent) { runDalitzPairing(groupedFilteredTracks, groupedFilteredTracks, nullptr); } + + if (fConfigOptions.fRunEventMixing) { + if (!fMixingEvent->tracks1.empty()) { + // we require that there is at least one tag track in the event to avoid having the pool full of events with only probe tracks which become useless for mixing + runMixing(); + } + delete fMixingEvent; + } } } @@ -649,16 +863,18 @@ struct DalitzSelection { fDalitzmapProbeAmbiguity.clear(); fAmbiguousPairs.clear(); + bool initDFDone = false; // some quantities might need to be updated for each dataframe + for (const auto& collision : collisions) { fTrackmap.clear(); fTrackmapProbe.clear(); VarManager::ResetValues(VarManager::kNRunWiseVariables, VarManager::kNBarrelTrackVariables); VarManager::FillEvent(collision); - bool isEventSelected = fEventCut->IsSelected(VarManager::fgValues); + bool isEventSelected = fEventCut->IsSelected(static_cast(VarManager::fgValues)); if (isEventSelected) { - reinterpret_cast(fStatsList->At(0))->Fill(0); + static_cast(fStatsList->At(0))->Fill(0); auto bc = collision.template bc_as(); @@ -667,11 +883,28 @@ struct DalitzSelection { fCurrentRun = bc.runNumber(); } + if (!initDFDone) { + initNewDF(bc.timestamp()); + initDFDone = true; + } + + if (fConfigOptions.fRunEventMixing) { + fMixingEvent = new MixingHandler::MixingEvent(); + } + auto groupedTracksAssoc = trackAssocs.sliceBy(trackIndicesPerCollision, collision.globalIndex()); runTrackSelection(groupedTracksAssoc, collision); if (!fSkipEvent) { runDalitzPairing(groupedTracksAssoc, groupedTracksAssoc, collision); } + if (fConfigOptions.fRunEventMixing) { + if (!fMixingEvent->tracks1.empty()) { + // we require that there is at least one tag track in the event to avoid having the pool full of events with only probe tracks which are then useless + // In addition, this allows to avoid mixing events which are too close in time, which could contain tracks from the same event due to track-to-collision reassociation + runMixing(); + } + delete fMixingEvent; + } } } @@ -692,16 +925,18 @@ struct DalitzSelection { fDalitzmapProbeAmbiguity.clear(); fAmbiguousPairs.clear(); + bool initDFDone = false; // some quantities might need to be updated for each dataframe + for (const auto& collision : collisions) { fTrackmap.clear(); fTrackmapProbe.clear(); VarManager::ResetValues(VarManager::kNRunWiseVariables, VarManager::kNBarrelTrackVariables); VarManager::FillEvent(collision); - bool isEventSelected = fEventCut->IsSelected(VarManager::fgValues); + bool isEventSelected = fEventCut->IsSelected(static_cast(VarManager::fgValues)); if (isEventSelected) { - reinterpret_cast(fStatsList->At(0))->Fill(0); + static_cast(fStatsList->At(0))->Fill(0); auto bc = collision.template bc_as(); @@ -710,11 +945,28 @@ struct DalitzSelection { fCurrentRun = bc.runNumber(); } + if (!initDFDone) { + initNewDF(bc.timestamp()); + initDFDone = true; + } + + if (fConfigOptions.fRunEventMixing) { + fMixingEvent = new MixingHandler::MixingEvent(); + } + auto groupedTracksAssoc = trackAssocs.sliceBy(trackIndicesPerCollision, collision.globalIndex()); runTrackSelection(groupedTracksAssoc, collision); if (!fSkipEvent) { runDalitzPairing(groupedTracksAssoc, groupedTracksAssoc, collision); } + if (fConfigOptions.fRunEventMixing) { + if (!fMixingEvent->tracks1.empty()) { + // we require that there is at least one tag track in the event to avoid having the pool full of events with only probe tracks which are then useless + // In addition, this allows to avoid mixing events which are too close in time, which could contain tracks from the same event due to track-to-collision reassociation + runMixing(); + } + delete fMixingEvent; + } } } From c5313c8c8ed4c928165ee31647f13c178f9d6a21 Mon Sep 17 00:00:00 2001 From: Paola Vargas Torres <88360333+PaolaVT@users.noreply.github.com> Date: Tue, 28 Jul 2026 20:53:32 -0600 Subject: [PATCH 29/71] [PWGLF] Add GoodITSLayersAll event cut and adjust myTrackSelection cuts (#17238) Co-authored-by: Paola Vargas Torres --- PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx b/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx index 2186703599f..aa012ec3dd6 100644 --- a/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx +++ b/PWGLF/Tasks/Nuspex/dedxPidAnalysis.cxx @@ -140,6 +140,7 @@ struct DedxPidAnalysis { ZVtxCut, NoSameBunchPileup, GoodZvtxFT0vsPV, + GoodITS, INELgt }; @@ -204,7 +205,7 @@ struct DedxPidAnalysis { "max z distance to IP"}; Configurable etaMin{"etaMin", -0.8f, "etaMin"}; Configurable etaMax{"etaMax", +0.8f, "etaMax"}; - Configurable minNCrossedRowsOverFindableClustersTPC{"minNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; + // Configurable minNCrossedRowsOverFindableClustersTPC{"minNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; Configurable nSigmaDCAxy{"nSigmaDCAxy", 3.0, "nSigma DCAxy selection"}; Configurable dcaXYp0{"dcaXYp0", 0.0105f, "DCAxy formula: p0 + p1/pt^p2"}; Configurable dcaXYp1{"dcaXYp1", 0.0350f, "DCAxy p1 parameter"}; @@ -250,6 +251,7 @@ struct DedxPidAnalysis { Configurable nGoodZvtx{"nGoodZvtx", true, "Rejects events with no vertex match between FT0 and PV"}; // Configurable nPileUp{"nPileUp", true, "Rejects events with pileup in the same bunch crossing"}; Configurable nINELSelectionMode{"nINELSelectionMode", 2, "INEL event selection: 1 no sel, 2 INEL>0, 3 INEL>1"}; + Configurable nGoodITS{"nGoodITS", true, "Numbers of inactive chips on all ITS layers are below maximum allowed values"}; Configurable v0SelectionMode{"v0SelectionMode", 3, "V0 Selection base on TPC: 1, TOF:2 ,Both:3"}; Configurable momentumMode{"momentumMode", 2, "1: TPC inner param, 2: Total momentum p"}; Configurable v0TypeSelection{"v0TypeSelection", 1, "select on a certain V0 type (leave negative if no selection desired)"}; @@ -281,10 +283,10 @@ struct DedxPidAnalysis { TrackSelection selectedTracks; selectedTracks.SetPtRange(0.1f, 1e10f); selectedTracks.SetEtaRange(etaMin, etaMax); - selectedTracks.SetRequireITSRefit(true); - selectedTracks.SetRequireTPCRefit(true); + // selectedTracks.SetRequireITSRefit(true); + // selectedTracks.SetRequireTPCRefit(true); selectedTracks.SetMinNCrossedRowsTPC(static_cast(minNCrossedRowsTPC.value)); - selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(minNCrossedRowsOverFindableClustersTPC); + // selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(minNCrossedRowsOverFindableClustersTPC); selectedTracks.SetMaxChi2PerClusterTPC(maxChi2TPC); selectedTracks.SetRequireHitsInITSLayers(1, {0, 1, 2}); selectedTracks.SetMaxChi2PerClusterITS(maxChi2ITS); @@ -310,6 +312,11 @@ struct DedxPidAnalysis { } else { LOGF(info, "GoodZvtxFT0vsPV cut disabled"); } + if (nGoodITS) { + LOGF(info, "Applying GoodITSLayersAll cut"); + } else { + LOGF(info, "GoodITSLayersAll cut disabled"); + } if (nINELSelectionMode == NoSelINEL) { LOGF(info, "Applying just INEL"); label = "INEL"; @@ -760,7 +767,7 @@ struct DedxPidAnalysis { HistType::kTH2F, {{ptAxis}, {dcaAxis}}); // Event Counter - registryDeDx.add("evsel", "events selected", HistType::kTH1F, {{6, 0.5, 6.5, ""}}); + registryDeDx.add("evsel", "events selected", HistType::kTH1F, {{7, 0.5, 7.5, ""}}); auto hstat = registryDeDx.get(HIST("evsel")); auto* x = hstat->GetXaxis(); x->SetBinLabel(AllEv, "AllEv"); @@ -769,6 +776,7 @@ struct DedxPidAnalysis { x->SetBinLabel(NoSameBunchPileup, "NoSameBunchPileup"); x->SetBinLabel(GoodZvtxFT0vsPV, "GoodZvtxFT0vsPV"); x->SetBinLabel(INELgt, label); + x->SetBinLabel(GoodITS, "GoodITSLayersAll"); // Track Prim Counter registryDeDx.add("trackselAll", "track selected all particles", HistType::kTH1F, {{5, 0.5, 5.5, ""}}); @@ -1438,6 +1446,12 @@ struct DedxPidAnalysis { registryDeDx.fill(HIST("evsel"), EvCutLabel::GoodZvtxFT0vsPV); } + if (nGoodITS) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + return; + registryDeDx.fill(HIST("evsel"), EvCutLabel::GoodITS); + } + if (nINELSelectionMode == NoSelINEL) { registryDeDx.fill(HIST("evsel"), EvCutLabel::INELgt); } else if (nINELSelectionMode == SelINELgt0) { From 78c1280640cc0fbd01514dc6f1d72dbc6a519415 Mon Sep 17 00:00:00 2001 From: Giorgio Alberto Lucia <87222843+GiorgioAlbertoLucia@users.noreply.github.com> Date: Wed, 29 Jul 2026 11:11:03 +0200 Subject: [PATCH 30/71] [PWGLF] changes in the tree creator for cluster size studies (#17237) --- .../Nuspex/LFTreeCreatorClusterStudies.cxx | 74 ++++++++++++++----- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx b/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx index 729ab2a6981..0dfed02c7f6 100644 --- a/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx +++ b/PWGLF/TableProducer/Nuspex/LFTreeCreatorClusterStudies.cxx @@ -111,9 +111,10 @@ enum V0Selections { enum CascSelections { kCascNoCut = 0, kCascTopology, + kNSigmaTPCV0Daughters, kRejectedXi, - kAcceptedOmega, kNSigmaTPC, + kAcceptedOmega, kCascAll }; @@ -274,12 +275,12 @@ struct LfTreeCreatorClusterStudies { {"photon_conversion_position", "Photon conversion position; #it{x} (cm); #it{y} (cm)", {HistType::kTH2F, {{250, -5.f, 5.f}, {250, -5.f, 5.f}}}}, {"photon_conversion_position_layer", "Photon conversion position (ITS layers); #it{x} (cm); #it{y} (cm)", {HistType::kTH2F, {{100, -5.f, 5.f}, {100, -5.f, 5.f}}}}, {"casc_dca_daughter_pairs", "DCA (xy) for cascade daughter pairs; DCA_{#it{xy}} (cm); counts", {HistType::kTH1F, {{100, -0.1, 0.1}}}}, - {"Xi_vs_Omega", "Mass Xi vs Omega; mass Omega (GeV/#it{c}^{2}); #it{m}_#Xi (GeV/#it{c}^{2})", {HistType::kTH2F, {{50, 1.f, 2.f}, {50, 1.f, 2.f}}}}, + {"Xi_vs_Omega", "Mass Xi vs Omega; #it{m}_{#Omega} (GeV/#it{c}^{2}); #it{m}_{#Xi} (GeV/#it{c}^{2})", {HistType::kTH2F, {{60, 1.5f, 2.1f}, {50, 1.1f, 1.6f}}}}, {"massOmega", "Mass #Omega; signed #it{p}_{T} (GeV/#it{c}); #it{m}_{#Omega} (GeV/#it{c}^{2})", {HistType::kTH2F, {{100, -5.f, 5.f}, {400, 1.62f, 1.72f}}}}, {"massOmegaMc", "Mass #Omega (MC); signed #it{p}_{T} (GeV/#it{c}); #it{m}_{#Omega} (GeV/#it{c}^{2})", {HistType::kTH2F, {{100, -5.f, 5.f}, {400, 1.62f, 1.72f}}}}, - {"massPi0", "Mass #pi^{0}; #it{m}_{#pi^{0}} (GeV/#it{c}^{2})", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, - {"massPi0Mc", "Mass #pi^{0} (MC); #it{m}_{#pi^{0}} (GeV/#it{c}^{2})", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, - {"massPi0WithBkg", "Mass #pi^{0} with Background; #it{m}_{#pi^{0}} (GeV/#it{c}^{2}); counts", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, + {"massPi0", "Mass #pi^{0}; #it{m}_{ee} (GeV/#it{c}^{2})", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, + {"massPi0Mc", "Mass #pi^{0} (MC); #it{m}_{ee} (GeV/#it{c}^{2})", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, + {"massPi0WithBkg", "Mass #pi^{0} with Background; #it{m}_{ee} (GeV/#it{c}^{2}); counts", {HistType::kTH1F, {{100, 0.0f, 0.200f}}}}, {"zVtx", "Binning for the vertex z in cm; #it{z}_{vertex} (cm)", {HistType::kTH1F, {{100, -20.f, 20.f}}}}, {"isPositive", "is the candidate positive?; isPositive; counts", {HistType::kTH1F, {{2, -0.5f, 1.5f}}}}, @@ -472,6 +473,23 @@ struct LfTreeCreatorClusterStudies { return true; } + template + bool selectPidV0Daughters(const Track& posTrack, const Track& negTrack, uint8_t v0Bitmask) + { + if (TESTBIT(v0Bitmask, Lambda)) { + if (std::abs(posTrack.tpcNSigmaPr()) > v0settingNsigmatpcPr || std::abs(negTrack.tpcNSigmaPi()) > v0settingNsigmatpcPi) { + return false; + } + } else if (TESTBIT(v0Bitmask, AntiLambda)) { + if (std::abs(posTrack.tpcNSigmaPi()) > v0settingNsigmatpcPi || std::abs(negTrack.tpcNSigmaPr()) > v0settingNsigmatpcPr) { + return false; + } + } else { + return false; + } + return true; + } + /** * Fill the histograms for the V0 candidate and return the mass of the V0 */ @@ -585,8 +603,9 @@ struct LfTreeCreatorClusterStudies { mHistograms.fill(HIST(cNames[partID]) + HIST("/nSigmaTPC"), track.p() * track.sign(), nsigmaTpc); mHistograms.fill(HIST(cNames[partID]) + HIST("/nSigmaITS"), track.p() * track.sign(), nsigmaIts); mHistograms.fill(HIST(cNames[partID]) + HIST("/nSigmaTOF"), track.p() * track.sign(), nsigmaTof); - if (partID == static_cast(PartID::de) || partID == static_cast(PartID::he)) + if (partID == static_cast(PartID::de) || partID == static_cast(PartID::he)) { mHistograms.fill(HIST(cNames[partID]) + HIST("/TOFmass"), track.p() * track.sign(), massTof); + } mHistograms.fill(HIST(cNames[partID]) + HIST("/pmatching"), correctedTpcInnerParam * track.sign(), (correctedTpcInnerParam - track.p()) / correctedTpcInnerParam); } @@ -740,7 +759,7 @@ struct LfTreeCreatorClusterStudies { } const auto& timestamp = bc.timestamp(); - o2::parameters::GRPMagField* grpmag = 0x0; + o2::parameters::GRPMagField* grpmag = nullptr; auto grpmagPath{"GLO/Config/GRPMagField"}; grpmag = mccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); @@ -805,24 +824,29 @@ struct LfTreeCreatorClusterStudies { LOG(info) << "resolution: " << mBBparamsDe[5]; std::vector collisionSelectionLabels = {"All", "sel8", "z_{VTX} < 10 cm"}; - for (int i = 0; i < Selections::kAll; i++) + for (int i = 0; i < Selections::kAll; i++) { mHistograms.get(HIST("collision_selections"))->GetXaxis()->SetBinLabel(i + 1, collisionSelectionLabels[i].c_str()); + } std::vector V0selectionLabels = {"All", "daughter track quality", "V0 topology", "V0 mass selection"}; - for (int i = 0; i < V0Selections::kV0All; i++) + for (int i = 0; i < V0Selections::kV0All; i++) { mHistograms.get(HIST("v0_selections"))->GetXaxis()->SetBinLabel(i + 1, V0selectionLabels[i].c_str()); + } - std::vector CascSelectionLabels = {"All", "Topology", "Veto Xi", "Accepted Omega", "n#sigma_{TPC} K"}; - for (int i = 0; i < CascSelections::kCascAll; i++) + std::vector CascSelectionLabels = {"All", "Topology", "n#sigma_{TPC} V0 daughters", "Veto Xi", "n#sigma_{TPC} K", "Accepted Omega"}; + for (int i = 0; i < CascSelections::kCascAll; i++) { mHistograms.get(HIST("casc_selections"))->GetXaxis()->SetBinLabel(i + 1, CascSelectionLabels[i].c_str()); + } std::vector ESelectionLabels = {"All", "Track quality", "Primary", "Pid", "#pi^{0}"}; - for (int i = 0; i < ESelections::kEAll; i++) + for (int i = 0; i < ESelections::kEAll; i++) { mHistograms.get(HIST("e_selections"))->GetXaxis()->SetBinLabel(i + 1, ESelectionLabels[i].c_str()); + } std::vector V0TypeLabels = {"K0s", "#Lambda", "#bar{#Lambda}", "Photon"}; - for (int i = 0; i < V0Type::V0TypeAll; i++) + for (int i = 0; i < V0Type::V0TypeAll; i++) { mHistograms.get(HIST("v0_type"))->GetXaxis()->SetBinLabel(i + 1, V0TypeLabels[i].c_str()); + } } template @@ -879,7 +903,6 @@ struct LfTreeCreatorClusterStudies { const auto& posMcParticle = posTrack.mcParticle(); const auto& negMcParticle = negTrack.mcParticle(); - candidatePos.pdgCode = posMcParticle.pdgCode(); candidateNeg.pdgCode = negMcParticle.pdgCode(); @@ -906,6 +929,15 @@ struct LfTreeCreatorClusterStudies { } mHistograms.fill(HIST("casc_selections"), CascSelections::kCascTopology); + const auto& posTrack = cascade.template posTrack_as(); + const auto& negTrack = cascade.template negTrack_as(); + uint8_t v0Bitmask = 0; + SETBIT(v0Bitmask, bachelorTrack.sign() < 0 ? V0Type::Lambda : V0Type::AntiLambda); + if (!selectPidV0Daughters(posTrack, negTrack, v0Bitmask)) { + return; + } + mHistograms.fill(HIST("casc_selections"), CascSelections::kNSigmaTPCV0Daughters); + const float& massXi = cascade.mXi(); const float& massOmega = cascade.mOmega(); mHistograms.fill(HIST("Xi_vs_Omega"), massOmega, massXi); @@ -914,6 +946,10 @@ struct LfTreeCreatorClusterStudies { return; } mHistograms.fill(HIST("casc_selections"), CascSelections::kRejectedXi); + if (std::abs(bachelorTrack.tpcNSigmaKa()) > cascsettingNsigmatpc) { + return; + } + mHistograms.fill(HIST("casc_selections"), CascSelections::kNSigmaTPC); mHistograms.fill(HIST("massOmega"), cascade.pt() * bachelorTrack.sign(), massOmega); if (std::abs(massOmega - o2::constants::physics::MassOmegaMinus) > cascsettingMassWindowOmega) { @@ -921,10 +957,6 @@ struct LfTreeCreatorClusterStudies { } mHistograms.fill(HIST("casc_selections"), CascSelections::kAcceptedOmega); - if (std::abs(bachelorTrack.tpcNSigmaKa()) > cascsettingNsigmatpc) { - return; - } - mHistograms.fill(HIST("casc_selections"), CascSelections::kNSigmaTPC); fillHistogramsParticle(bachelorTrack); mClusterStudiesTable( @@ -973,8 +1005,9 @@ struct LfTreeCreatorClusterStudies { } mHistograms.fill(HIST(cNames[kPartID]) + HIST("/trackSelections"), NucleiSelections::kNucleiNoCut); - if (track.itsNCls() < desettingNclsIts) + if (track.itsNCls() < desettingNclsIts) { return; + } mHistograms.fill(HIST(cNames[kPartID]) + HIST("/trackSelections"), NucleiSelections::kNucleiNClsIts); const float tpcNsigma = kPartID == static_cast(PartID::de) ? track.tpcNSigmaDe() : computeNSigmaTPCHe3(track); @@ -1415,8 +1448,9 @@ struct LfTreeCreatorClusterStudies { const auto& negTracks_thisCollision = negTracksMc.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), mcache); for (const auto& [posTrack, negTrack] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(posTracks_thisCollision, negTracks_thisCollision))) { - if (!posTrack.has_mcParticle() || !negTrack.has_mcParticle()) + if (!posTrack.has_mcParticle() || !negTrack.has_mcParticle()) { continue; + } fillElectronTableFromPi0Dalitz(posTrack, negTrack); } From 23dbf701190a1dcbc5bbb2014075c193f4a6bd8e Mon Sep 17 00:00:00 2001 From: Barbara Gawlik <132619264+allesgrau@users.noreply.github.com> Date: Wed, 29 Jul 2026 13:06:18 +0200 Subject: [PATCH 31/71] [PWGCF] Add kKstarVsKtVsCent histogram to pairHistManager (#17247) --- PWGCF/Femto/Core/pairHistManager.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/PWGCF/Femto/Core/pairHistManager.h b/PWGCF/Femto/Core/pairHistManager.h index ed8f6054c4f..9b5aa99ffc7 100644 --- a/PWGCF/Femto/Core/pairHistManager.h +++ b/PWGCF/Femto/Core/pairHistManager.h @@ -69,6 +69,8 @@ enum PairHist { kKstarVsMt, kKstarVsMult, kKstarVsCent, + // 3D: k* vs kT vs centrality + kKstarVsKtVsCent, // 2D with mass kKstarVsMass1, kKstarVsMass2, @@ -184,6 +186,7 @@ struct ConfPairBinning : o2::framework::ConfigurableGroup { o2::framework::Configurable usePdgMass{"usePdgMass", true, "(Reco) Use PDF masses for 4-vectors. If false, use reconstructed mass (if available). Not consulted for pure mc-truth pairs, which always use PDG mass"}; o2::framework::Configurable plot1D{"plot1D", true, "(Reco/Mc) Enable 1D histograms"}; o2::framework::Configurable plot2D{"plot2D", true, "(Reco/Mc) Enable 2D histograms"}; + o2::framework::Configurable plotKstarVsKtVsCent{"plotKstarVsKtVsCent", false, "(Reco/Mc) Enable 3D histogram (Kstar Vs Kt Vs Cent)"}; o2::framework::Configurable plotKstarVsMtVsMult{"plotKstarVsMtVsMult", false, "(Reco/Mc) Enable 3D histogram (Kstar Vs Mt Vs Mult)"}; o2::framework::Configurable plotKstarVsMtVsMultVsCent{"plotKstarVsMtVsMultVsCent", false, "(Reco/Mc) Enable 4D histogram (Kstar Vs Mt Vs Mult Vs Cent)"}; o2::framework::Configurable plotKstarVsMtVsPt1VsPt2{"plotKstarVsMtVsPt1VsPt2", false, "(Reco/Mc) Enable 4D histogram (Kstar Vs Mt Vs Pt1 Vs Pt2)"}; @@ -277,6 +280,7 @@ constexpr std::array, kPairHistogramLast> {kPt1VsMinv, o2::framework::HistType::kTH2F, "hPt1VsMinv", "p_{T,1} vs m_{Inv}; p_{T,1} (GeV/#it{c}); m_{Inv} (GeV/#it{c}^{2})"}, {kPt2VsMinv, o2::framework::HistType::kTH2F, "hPt2VsMinv", "p_{T,2} vs m_{Inv}; p_{T,2} (GeV/#it{c}); m_{Inv} (GeV/#it{c}^{2})"}, // n-D + {kKstarVsKtVsCent, o2::framework::HistType::kTHnSparseF, "hKstarVsKtVsCent", "k* vs k_{T} vs centrality; k* (GeV/#it{c}); k_{T} (GeV/#it{c}); Centrality (%);"}, {kKstarVsMtVsMult, o2::framework::HistType::kTHnSparseF, "hKstarVsMtVsMult", "k* vs m_{T} vs multiplicity; k* (GeV/#it{c}); m_{T} (GeV/#it{c}^{2}); Multiplicity;"}, {kKstarVsMtVsMultVsCent, o2::framework::HistType::kTHnSparseF, "hKstarVsMtVsMultVsCent", "k* vs m_{T} vs multiplicity vs centrality; k* (GeV/#it{c}); m_{T} (GeV/#it{c}^{2}); Multiplicity; Centrality (%);"}, // n-D with pt @@ -367,6 +371,7 @@ constexpr std::array, kPairHistogramLast> {kKstarVsMt, {(confAnalysis).kstar, (confAnalysis).mt}}, \ {kKstarVsMult, {(confAnalysis).kstar, (confAnalysis).multiplicity}}, \ {kKstarVsCent, {(confAnalysis).kstar, (confAnalysis).centrality}}, \ + {kKstarVsKtVsCent, {(confAnalysis).kstar, (confAnalysis).kt, (confAnalysis).centrality}}, \ {kKstarVsMass1, {(confAnalysis).kstar, (confAnalysis).mass1}}, \ {kKstarVsMass2, {(confAnalysis).kstar, (confAnalysis).mass2}}, \ {kMass1VsMass2, {(confAnalysis).mass1, (confAnalysis).mass2}}, \ @@ -536,6 +541,7 @@ class PairHistManager // flags for histograms mPlot1d = ConfPairBinning.plot1D.value; mPlot2d = ConfPairBinning.plot2D.value; + mPlotKstarVsKtVsCent = ConfPairBinning.plotKstarVsKtVsCent.value; mPlotKstarVsMtVsMult = ConfPairBinning.plotKstarVsMtVsMult.value; mPlotKstarVsMtVsMultVsCent = ConfPairBinning.plotKstarVsMtVsMultVsCent.value; @@ -936,6 +942,9 @@ class PairHistManager } // higher dimensional histograms + if (mPlotKstarVsKtVsCent) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsKtVsCent, HistTable), getHistDesc(kKstarVsKtVsCent, HistTable), getHistType(kKstarVsKtVsCent, HistTable), {Specs.at(kKstarVsKtVsCent)}); + } if (mPlotKstarVsMtVsMult) { mHistogramRegistry->add(analysisDir + getHistNameV2(kKstarVsMtVsMult, HistTable), getHistDesc(kKstarVsMtVsMult, HistTable), getHistType(kKstarVsMtVsMult, HistTable), {Specs.at(kKstarVsMtVsMult)}); } @@ -1218,6 +1227,9 @@ class PairHistManager // n-D histograms are only filled if enabled // if "mass" getter does not exist for particle, it will be just set to 0 // the user has to make sure that in this case the bin number of this dimension is set to 1 + if (mPlotKstarVsKtVsCent) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsKtVsCent, HistTable)), mKstar, mKt, mCent); + } if (mPlotKstarVsMtVsMult) { mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstarVsMtVsMult, HistTable)), mKstar, mMt, mMult); } @@ -1627,6 +1639,7 @@ class PairHistManager bool mPlot1d = true; bool mPlot2d = true; + bool mPlotKstarVsKtVsCent = false; bool mPlotKstarVsMtVsMult = false; bool mPlotKstarVsMtVsMultVsCent = false; From 8049196b0a0b617072631810d4063df1fca94225 Mon Sep 17 00:00:00 2001 From: Kai Cui <129373281+kcui1@users.noreply.github.com> Date: Wed, 29 Jul 2026 13:19:11 +0200 Subject: [PATCH 32/71] [PWGLF] Bug Fix in h-Strangeness analysis (#17243) --- .../Strangeness/hStrangeCorrelationFilter.cxx | 59 +++++++-------- .../Tasks/Strangeness/hStrangeCorrelation.cxx | 74 ++++++++++--------- 2 files changed, 71 insertions(+), 62 deletions(-) diff --git a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx index b405d3855d5..6f755288dc6 100644 --- a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx +++ b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx @@ -256,24 +256,23 @@ struct HStrangeCorrelationFilter { TH1F* hOmegaWidth = nullptr; Zorro zorro; OutputObj zorroSummary{"zorroSummary"}; - int mRunNumber; + int mRunNumberZorro = -1; + int mRunNumberParameters = -1; struct TriggCandidate { - float pt; - int collisionId; - int trackId; - bool isPhysicalPrimary; - float origPt; - uint16_t mcMask; + float pt = 0.f; + int collisionId = -1; + int trackId = -1; + bool isPhysicalPrimary = false; + float origPt = 0.f; + uint16_t mcMask = 0; }; - TriggCandidate thisTrigg; std::vector triggerCandidates; void init(InitContext const&) { zorroSummary.setObject(zorro.getZorroSummary()); - mRunNumber = -1; if (useParameterization) { fK0Mean->SetParameters(parameters.massParsK0Mean->at(0), parameters.massParsK0Mean->at(1), parameters.massParsK0Mean->at(2), parameters.massParsK0Mean->at(3)); fK0Width->SetParameters(parameters.massParsK0Width->at(0), parameters.massParsK0Width->at(1), parameters.massParsK0Width->at(2), parameters.massParsK0Width->at(3)); @@ -308,23 +307,23 @@ struct HStrangeCorrelationFilter { void initCCDB(aod::BCsWithTimestamps::iterator const& bc) { - if (mRunNumber == bc.runNumber()) { + if (mRunNumberZorro == bc.runNumber()) { return; } zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), zorroMask.value); zorro.populateHistRegistry(histos, bc.runNumber()); - mRunNumber = bc.runNumber(); + mRunNumberZorro = bc.runNumber(); } void initParametersFromCCDB(aod::BCsWithTimestamps::iterator const& bc) { - if (mRunNumber == bc.runNumber()) { + if (mRunNumberParameters == bc.runNumber()) { return; } - mRunNumber = bc.runNumber(); - LOG(info) << "Loading mean and sigma from CCDB for run " << mRunNumber << " now..."; + mRunNumberParameters = bc.runNumber(); + LOG(info) << "Loading mean and sigma from CCDB for run " << mRunNumberParameters << " now..."; auto timeStamp = bc.timestamp(); auto listParameters = ccdb->getForTimeStamp(parameterCCDBPath, timeStamp); @@ -344,7 +343,7 @@ struct HStrangeCorrelationFilter { hOmegaMean = dynamic_cast(listParameters->FindObject("hOmegaMean")); hOmegaWidth = dynamic_cast(listParameters->FindObject("hOmegaWidth")); } - LOG(info) << "parameters now loaded for " << mRunNumber; + LOG(info) << "parameters now loaded for " << mRunNumberParameters; } // this function allows for all event selections to be done in a modular way @@ -591,6 +590,7 @@ struct HStrangeCorrelationFilter { if (!isValidTrigger(track)) { continue; } + TriggCandidate thisTrigg{}; thisTrigg.pt = track.pt(); thisTrigg.trackId = track.globalIndex(); thisTrigg.collisionId = track.collisionId(); @@ -631,6 +631,7 @@ struct HStrangeCorrelationFilter { if (!isValidTrigger(track)) { continue; } + TriggCandidate thisTrigg{}; thisTrigg.pt = track.pt(); thisTrigg.trackId = track.globalIndex(); thisTrigg.collisionId = track.collisionId(); @@ -792,9 +793,9 @@ struct HStrangeCorrelationFilter { continue; } // check dE/dx compatibility - int compatibleK0Short = -1; - int compatibleLambda = -1; - int compatibleAntiLambda = -1; + int compatibleK0Short = 0; + int compatibleLambda = 0; + int compatibleAntiLambda = 0; auto posdau = v0.posTrack_as(); auto negdau = v0.negTrack_as(); @@ -927,9 +928,9 @@ struct HStrangeCorrelationFilter { continue; } // check dE/dx compatibility - int compatibleK0Short = -1; - int compatibleLambda = -1; - int compatibleAntiLambda = -1; + int compatibleK0Short = 0; + int compatibleLambda = 0; + int compatibleAntiLambda = 0; auto posdau = v0.posTrack_as(); auto negdau = v0.negTrack_as(); @@ -1109,10 +1110,10 @@ struct HStrangeCorrelationFilter { bool isGoodPosCascadePbPb = std::abs(casc.dcabachtopv()) > cascSelection.dcaBachToPV && std::abs(casc.dcapostopv()) > cascSelection.cascDcaMesonToPV && std::abs(casc.dcanegtopv()) > cascSelection.cascDcaBaryonToPV; // check dE/dx compatibility - int compatibleXiMinus = -1; - int compatibleXiPlus = -1; - int compatibleOmegaMinus = -1; - int compatibleOmegaPlus = -1; + int compatibleXiMinus = 0; + int compatibleXiPlus = 0; + int compatibleOmegaMinus = 0; + int compatibleOmegaPlus = 0; float cascpos = std::hypot(casc.x() - collision.posX(), casc.y() - collision.posY(), casc.z() - collision.posZ()); float cascptotmom = std::hypot(casc.px(), casc.py(), casc.pz()); float ctauXi = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * Xictau); @@ -1277,10 +1278,10 @@ struct HStrangeCorrelationFilter { bool isGoodPosCascadePbPb = (std::abs(casc.dcabachtopv()) > cascSelection.dcaBachToPV && std::abs(casc.dcapostopv()) > cascSelection.cascDcaMesonToPV && std::abs(casc.dcanegtopv()) > cascSelection.cascDcaBaryonToPV); // check dE/dx compatibility - int compatibleXiMinus = -1; - int compatibleXiPlus = -1; - int compatibleOmegaMinus = -1; - int compatibleOmegaPlus = -1; + int compatibleXiMinus = 0; + int compatibleXiPlus = 0; + int compatibleOmegaMinus = 0; + int compatibleOmegaPlus = 0; float cascpos = std::hypot(casc.x() - collision.posX(), casc.y() - collision.posY(), casc.z() - collision.posZ()); float cascptotmom = std::hypot(casc.px(), casc.py(), casc.pz()); float ctauXi = o2::constants::physics::MassXiMinus * cascpos / ((cascptotmom + 1e-13) * Xictau); diff --git a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx index 3fb2f60415d..d5d7d52e9fd 100644 --- a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx +++ b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx @@ -73,6 +73,7 @@ #include #include #include +#include #include #include @@ -398,9 +399,9 @@ struct HStrangeCorrelation { } } - uint16_t doCorrelation; - int mRunNumber; - int mRunNumberZorro; + uint16_t doCorrelation = 0; + int mRunNumber = -1; + int mRunNumberZorro = -1; std::vector> axisRanges; @@ -1024,16 +1025,21 @@ struct HStrangeCorrelation { } std::array binFillThn = {deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult}; if (TESTBIT(doCorrelation, Index) && (!efficiencyFlags.applyEfficiencyCorrection || efficiency != 0) && (masterConfigurations.doPPAnalysis || (TESTBIT(selMap, Index) && TESTBIT(selMap, Index + 3)))) { - if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && + ((-massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) || + (-massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) || + (+massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma))) { if (std::abs(deltaphi) < 0.5) { - histos.fill(HIST("sameEvent/") + HIST(V0names[Index]) + HIST("/hInvariantMassNearSide"), ptassoc, pttrigger, getV0InvariantMass(assoc)); + histos.fill(HIST("sameEvent/InvariantMass/") + HIST(V0names[Index]) + HIST("/hNearSide"), ptassoc, pttrigger, getV0InvariantMass(assoc)); } if (std::abs(PI - deltaphi) < 0.5) { - histos.fill(HIST("sameEvent/") + HIST(V0names[Index]) + HIST("/hInvariantMassAwaySide"), ptassoc, pttrigger, getV0InvariantMass(assoc)); + histos.fill(HIST("sameEvent/InvariantMass/") + HIST(V0names[Index]) + HIST("/hAwaySide"), ptassoc, pttrigger, getV0InvariantMass(assoc)); } if (deltaphi > 1.0 && deltaphi < 1.5) { - histos.fill(HIST("sameEvent/") + HIST(V0names[Index]) + HIST("/hInvariantMassUE"), ptassoc, pttrigger, getV0InvariantMass(assoc)); + histos.fill(HIST("sameEvent/InvariantMass/") + HIST(V0names[Index]) + HIST("/hUnderlyingEvent"), ptassoc, pttrigger, getV0InvariantMass(assoc)); } + } + if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && -massWindowConfigurations.maxBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) { fillCorrelationHistogram(histos.get(HIST("sameEvent/LeftBg/") + HIST(V0names[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (doDeltaPhiStarCheck) { double deltaPhiStar = calculateAverageDeltaPhiStar(triggForDeltaPhiStar, assocForDeltaPhiStar, bField); @@ -1053,8 +1059,8 @@ struct HStrangeCorrelation { } if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && !mixing && ((-massWindowConfigurations.maxPeakNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma))) { if (masterConfigurations.doCorrelationsHadronV0daughter) { - fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(V0names[Index]) + HIST("/hSameSign")), binFillThnSameSignDaugher, 1, 1, 1, 1, 1); - fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(V0names[Index]) + HIST("/hOppositeSign")), binFillThnOppositeSignDaugher, 1, 1, 1, 1, 1); + fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(V0names[Index]) + HIST("_hSameSign")), binFillThnSameSignDaugher, 1, 1, 1, 1, 1); + fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(V0names[Index]) + HIST("_hOppositeSign")), binFillThnOppositeSignDaugher, 1, 1, 1, 1, 1); } fillCorrelationHistogram(histos.get(HIST("sameEvent/Signal/") + HIST(V0names[Index])), binFillThn, etaWeight, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); if (std::abs(deltaphi) < checks.towardDeltaEtaRange && doITSClustersQA) { @@ -1113,8 +1119,8 @@ struct HStrangeCorrelation { fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(V0names[Index])), binFillThn, 1, efficiency * efficiencyTrigg, totalEffUncert, purityTrigg, purityTriggErr); } if (masterConfigurations.doCorrelationsHadronV0daughter) { - fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(V0names[Index]) + HIST("/hSameSign")), binFillThnSameSignDaugher, 1, 1, 1, 1, 1); - fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(V0names[Index]) + HIST("/hOppositeSign")), binFillThnOppositeSignDaugher, 1, 1, 1, 1, 1); + fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(V0names[Index]) + HIST("_hSameSign")), binFillThnSameSignDaugher, 1, 1, 1, 1, 1); + fillCorrelationHistogram(histos.get(HIST("mixedEvent/Signal/") + HIST(V0names[Index]) + HIST("_hOppositeSign")), binFillThnOppositeSignDaugher, 1, 1, 1, 1, 1); } } if (assocCandidate.compatible(Index, trackSelection.dEdxCompatibility) && (!masterConfigurations.doMCassociation || assocCandidate.mcTrue(Index)) && (!doAssocPhysicalPrimary || assocCandidate.mcPhysicalPrimary()) && mixing && +massWindowConfigurations.minBgNSigma < assocCandidate.invMassNSigma(Index) && assocCandidate.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma) { @@ -1706,8 +1712,6 @@ struct HStrangeCorrelation { void init(InitContext const&) { zorroSummary.setObject(zorro.getZorroSummary()); - mRunNumber = 0; - mRunNumberZorro = 0; hEfficiencyPion = nullptr; hEfficiencyK0Short = nullptr; hEfficiencyLambda = nullptr; @@ -2065,31 +2069,18 @@ struct HStrangeCorrelation { histos.addClone("sameEvent/Signal/", "sameEvent/RightBg/"); } - if (masterConfigurations.doFullCorrelationStudy && doprocessSameEventHV0s) { + if (masterConfigurations.doFullCorrelationStudy && doprocessSameEventHV0s && masterConfigurations.doCorrelationsHadronV0daughter) { if (TESTBIT(doCorrelation, 0)) { - histos.add("sameEvent/K0Short/hInvariantMassNearSide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisK0ShortMass}); - histos.add("sameEvent/K0Short/hInvariantMassAwaySide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisK0ShortMass}); - histos.add("sameEvent/K0Short/hInvariantMassUE", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisK0ShortMass}); - if (masterConfigurations.doCorrelationsHadronV0daughter) { - histos.add("sameEvent/Signal/K0Short/hSameSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - histos.add("sameEvent/Signal/K0Short/hOppositeSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - } + histos.add("sameEvent/Signal/K0Short_hSameSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + histos.add("sameEvent/Signal/K0Short_hOppositeSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); } if (TESTBIT(doCorrelation, 1)) { - histos.add("sameEvent/Lambda/hInvariantMassNearSide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); - histos.add("sameEvent/Lambda/hInvariantMassAwaySide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); - histos.add("sameEvent/Lambda/hInvariantMassUE", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); - if (masterConfigurations.doCorrelationsHadronV0daughter) { - histos.add("sameEvent/Signal/Lambda/hSameSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - histos.add("sameEvent/Signal/Lambda/hOppositeSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - } + histos.add("sameEvent/Signal/Lambda_hSameSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + histos.add("sameEvent/Signal/Lambda_hOppositeSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); } if (TESTBIT(doCorrelation, 2)) { - histos.addClone("sameEvent/Lambda/", "sameEvent/AntiLambda/"); - if (masterConfigurations.doCorrelationsHadronV0daughter) { - histos.add("sameEvent/Signal/AntiLambda/hSameSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - histos.add("sameEvent/Signal/AntiLambda/hOppositeSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); - } + histos.add("sameEvent/Signal/AntiLambda_hSameSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); + histos.add("sameEvent/Signal/AntiLambda_hOppositeSign", "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); } } if (TESTBIT(doCorrelation, 0) && doprocessSameEventHV0s && masterConfigurations.doMassSpectrumCheck) { @@ -2106,6 +2097,23 @@ struct HStrangeCorrelation { if ((doprocessMixedEventHV0sInBuffer || doprocessMixedEventHCascadesInBuffer || doprocessMixedEventHV0s || doprocessMixedEventHCascades || doprocessMixedEventHPions || doprocessMixedEventHHadrons) && masterConfigurations.doFullCorrelationStudy) { histos.addClone("sameEvent/", "mixedEvent/"); } + if (masterConfigurations.doFullCorrelationStudy && doprocessSameEventHV0s) { + if (TESTBIT(doCorrelation, 0)) { + histos.add("sameEvent/InvariantMass/K0Short/hNearSide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisK0ShortMass}); + histos.add("sameEvent/InvariantMass/K0Short/hAwaySide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisK0ShortMass}); + histos.add("sameEvent/InvariantMass/K0Short/hUnderlyingEvent", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisK0ShortMass}); + } + if (TESTBIT(doCorrelation, 1)) { + histos.add("sameEvent/InvariantMass/Lambda/hNearSide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + histos.add("sameEvent/InvariantMass/Lambda/hAwaySide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + histos.add("sameEvent/InvariantMass/Lambda/hUnderlyingEvent", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + } + if (TESTBIT(doCorrelation, 2)) { + histos.add("sameEvent/InvariantMass/AntiLambda/hNearSide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + histos.add("sameEvent/InvariantMass/AntiLambda/hAwaySide", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + histos.add("sameEvent/InvariantMass/AntiLambda/hUnderlyingEvent", "", kTH3F, {axesConfigurations.axisPtAssoc, axesConfigurations.axisPtTrigger, axesConfigurations.axisLambdaMass}); + } + } if (doprocessSameEventHHadrons && masterConfigurations.doFullCorrelationStudy) { histos.add("sameEvent/TriggerParticlesHadron", "TriggersHadron", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); } From e041e77d603e2cf460a13fff82cd8e2d0a1f7b18 Mon Sep 17 00:00:00 2001 From: Maximiliano Puccio Date: Wed, 29 Jul 2026 14:45:34 +0200 Subject: [PATCH 33/71] [PWGLF] Remove stale duplicate nucleitpcpbpb.cxx index entry (#17232) --- PWGLF/Tasks/Nuspex/nucleitpcpbpb.cxx | 1416 -------------------------- 1 file changed, 1416 deletions(-) delete mode 100644 PWGLF/Tasks/Nuspex/nucleitpcpbpb.cxx diff --git a/PWGLF/Tasks/Nuspex/nucleitpcpbpb.cxx b/PWGLF/Tasks/Nuspex/nucleitpcpbpb.cxx deleted file mode 100644 index 52dd21fdeef..00000000000 --- a/PWGLF/Tasks/Nuspex/nucleitpcpbpb.cxx +++ /dev/null @@ -1,1416 +0,0 @@ -// 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 nucleitpcpbpb.cxx -/// \brief nuclei analysis -/// \note under work -/// -/// \author Jaideep Tanwar , Panjab University - -#include "Common/CCDB/EventSelectionParams.h" -#include "Common/Core/PID/PIDTOF.h" -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponseITS.h" -#include "Common/DataModel/PIDResponseTOF.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 -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using CollisionsFull = soa::Join; -using TracksFull = soa::Join; -using CollisionsFullMC = soa::Join; -//--------------------------------------------------------------------------------------------------------------------------------- -namespace -{ -static const int nParticles = 6; -static const std::vector particleNames{"pion", "proton", "deuteron", "triton", "helion", "alpha"}; -static const std::vector correctedparticleNames{"helion", "antihelion", "alpha", "antialpha"}; -static const std::vector particlePdgCodes{211, 2212, o2::constants::physics::kDeuteron, o2::constants::physics::kTriton, o2::constants::physics::kHelium3, o2::constants::physics::kAlpha}; -static const std::vector particleMasses{o2::constants::physics::MassPionCharged, o2::constants::physics::MassProton, o2::constants::physics::MassDeuteron, o2::constants::physics::MassTriton, o2::constants::physics::MassHelium3, o2::constants::physics::MassAlpha}; -static const std::vector particleCharge{1, 1, 1, 1, 2, 2}; -const int nBetheParams = 6; -std::vector hfMothCodes = {511, 521, 531, 541, 5122}; // b-mesons + Lambda_b -static const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; -constexpr double kBetheBlochDefault[nParticles][nBetheParams]{ - {13.611469, 3.598765, -0.021138, 2.039562, 0.651040, 0.09}, // pion - {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // proton - {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // deuteron - {5.393020, 7.859534, 0.004048, 2.323197, 1.609307, 0.09}, // triton - {-126.557359, -0.858569, 1.111643, 1.210323, 2.656374, 0.09}, // helion - {-126.557359, -0.858569, 1.111643, 1.210323, 2.656374, 0.09}}; // alpha -const int nTrkSettings = 13; -static const std::vector trackPIDsettingsNames{"useBBparams", "minITSnCls", "minITSnClscos", "minTPCnCls", "maxTPCchi2", "minTPCchi2", "maxITSchi2", "maxTPCnSigma", "maxDcaXY", "maxDcaZ", "minITSclsSize", "minTPCnClsCrossedRows", "minReqClusterITSib"}; -constexpr double kTrackPIDSettings[nParticles][nTrkSettings]{ - {0, 0, 4, 60, 4.0, 0.5, 100, 2.5, 2., 2., 0., 70, 1}, - {1, 0, 4, 70, 4.0, 0.5, 100, 3.0, 2., 2., 0., 70, 1}, - {1, 0, 4, 70, 4.0, 0.5, 100, 3.0, 2., 2., 0., 70, 1}, - {1, 0, 4, 70, 4.0, 0.5, 100, 3.0, 2., 2., 0., 70, 1}, - {1, 0, 4, 75, 4.0, 0.5, 100, 5.0, 2., 2., 0., 70, 1}, - {1, 0, 4, 70, 4.0, 0.5, 100, 5.0, 2., 2., 0., 70, 1}}; - -const int nTrkSettings2 = 7; -static const std::vector trackPIDsettingsNames2{"useITSnsigma", "minITSnsigma", "maxITSnsigma", "fillsparsh", "useTPCnsigmaTOF", "maxTPCnsigmaTOF", "maxTOFnsigma"}; -constexpr double kTrackPIDSettings2[nParticles][nTrkSettings2]{ - {1, -5, 4, 0, 1, 2, 2}, - {1, -5, 4, 0, 1, 2, 2}, - {1, -5, 4, 0, 1, 2, 2}, - {1, -5, 4, 1, 1, 2, 2}, - {1, -5, 4, 1, 1, 2, 2}, - {1, -5, 4, 1, 1, 2, 2}}; - -static const int nfittingparticle = 4; -const int nfittingparameters = 4; -static const std::vector trackcorrectionNames{"a", "b", "c", "d"}; -constexpr double ktrackcorrection[nfittingparticle][nfittingparameters]{ - {0.464215, 0.195771, 0.0183111, 0.0}, // He3 - {0.464215, 0.195771, 0.0183111, 0.0}, // anti-He3 - {0.00765, 0.503791, -1.10517, 0.0}, // He4 - {0.00765, 0.503791, -1.10517, 0.0}}; // anti-He4 - -// DCA parameters - simple 2x3 array (DCAxy, DCAz) with p0, p1, p2 -static const int nDCAtypes = 2; -const int nDCAparameters = 3; -static const std::vector dcaNames{"p0", "p1", "p2"}; -static const std::vector dcaTypeNames{"DCAxy", "DCAz"}; -constexpr double kDCAcorrection[nDCAtypes][nDCAparameters]{ - {0.0118, -0.6889, 0.0017}, // DCAxy: p0*exp(p1*pt) + p2 - {0.1014, 1.7512, 0.0024}}; // DCAz: p0*exp(-p1*pt) + p2 - -struct PrimParticles { - TString name; - int pdgCode, charge; - double mass, resolution; - std::vector betheParams; - bool active; - PrimParticles(std::string name_, int pdgCode_, double mass_, int charge_, LabeledArray bethe) : name(name_), pdgCode(pdgCode_), charge(charge_), mass(mass_), active(false) - { - resolution = bethe.get(name, "resolution"); - betheParams.clear(); - constexpr unsigned int kNSpecies = 5; - for (unsigned int i = 0; i < kNSpecies; i++) - betheParams.push_back(bethe.get(name, i)); - } -}; // struct PrimParticles - -//---------------------------------------------------------------------------------------------------------------- -std::vector> hmass; -std::vector> hmassnsigma; -} // namespace -//---------------------------------------------------------------------------------------------------------------- -struct NucleitpcPbPb { - - Preslice tracksPerCollision = aod::track::collisionId; - - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry histomc{"histomc", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - - // Event Selection Configurables - Configurable removeNoSameBunchPileup{"removeNoSameBunchPileup", false, "Remove no same bunch pileup"}; - Configurable requireIsGoodZvtxFT0vsPV{"requireIsGoodZvtxFT0vsPV", false, "Require is good Zvtx FT0 vs PV"}; - Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "Require is vertex ITS TPC"}; - Configurable removeNoTimeFrameBorder{"removeNoTimeFrameBorder", false, "Remove no time frame border"}; - Configurable cfgsel8Require{"cfgsel8Require", true, "sel8 cut require"}; - Configurable cfgZvertex{"cfgZvertex", 10, "Min Z Vertex"}; - - // Track Selection Configurables - Configurable cfgUsePVcontributors{"cfgUsePVcontributors", true, "use tracks that are PV contibutors"}; - Configurable cfgPassedITSRefit{"cfgPassedITSRefit", true, "Require ITS refit"}; - Configurable cfgPassedTPCRefit{"cfgPassedTPCRefit", true, "Require TPC refit"}; - Configurable cfgetaRequire{"cfgetaRequire", true, "eta cut require"}; - Configurable cfgetaRequireMC{"cfgetaRequireMC", true, "eta cut require for generated particles"}; - Configurable cfgRapidityRequire{"cfgRapidityRequire", true, "Require Rapidity cut"}; - Configurable cfgRapidityRequireMC{"cfgRapidityRequireMC", true, "rapidity cut require for generated particles"}; - Configurable cfgCutEta{"cfgCutEta", 0.9f, "Eta range for tracks"}; - Configurable cfgCutRapiditymin{"cfgCutRapiditymin", -0.5f, "min Rapidity range"}; - Configurable cfgCutRapiditymax{"cfgCutRapiditymax", 0.5f, "max Rapidity range"}; - Configurable cfgtpcNClsFindable{"cfgtpcNClsFindable", 0.8f, "tpcNClsFindable over crossedRows"}; - Configurable centcut{"centcut", 80.0f, "centrality cut"}; - Configurable cfgZvertexRequireMC{"cfgZvertexRequireMC", true, "Pos Z cut in MC"}; - - // Track Cut Configurables - Configurable cfgTPCNClsCrossedRowsRequire{"cfgTPCNClsCrossedRowsRequire", true, "Require TPCNClsCrossedRows Cut"}; - Configurable cfgmaxTPCchi2Require{"cfgmaxTPCchi2Require", true, "Require maxTPCchi2 Cut"}; - Configurable cfgminTPCchi2Require{"cfgminTPCchi2Require", true, "Require minTPCchi2 Cut"}; - Configurable cfgminITSnClsRequire{"cfgminITSnClsRequire", false, "Require minITSnCls Cut"}; - Configurable cfgminITSnClscosRequire{"cfgminITSnClscosRequire", true, "Require minITSnCls / cosh(eta) Cut"}; - Configurable cfgminReqClusterITSibRequire{"cfgminReqClusterITSibRequire", true, " Require min number of clusters required in ITS inner barrel"}; - Configurable cfgmaxITSchi2Require{"cfgmaxITSchi2Require", true, "Require maxITSchi2 Cut"}; - Configurable cfgmaxTPCnSigmaRequire{"cfgmaxTPCnSigmaRequire", true, "Require maxTPCnSigma Cut"}; - Configurable cfgminGetMeanItsClsSizeRequire{"cfgminGetMeanItsClsSizeRequire", true, "Require minGetMeanItsClsSize Cut"}; - Configurable cfgmaxGetMeanItsClsSizeRequire{"cfgmaxGetMeanItsClsSizeRequire", true, "Require maxGetMeanItsClsSize Cut"}; - - // He4 Configurables - Configurable cfghe3massrejreq{"cfghe3massrejreq", true, "Require mass cut on He4 particles"}; - Configurable cfgminmassrejection{"cfgminmassrejection", 6.5, "Min side of He3 particle rejection"}; - Configurable cfgmaxmassrejection{"cfgmaxmassrejection", 9.138, "Max side of He3 particle rejection"}; - Configurable deuteronsigmarejection{"deuteronsigmarejection", 2.0f, "Deuteron TPC nsigma rejection for He4"}; - - // MC Configurables - Configurable cfgmccorrectionhe4Require{"cfgmccorrectionhe4Require", true, "MC correction for pp he4 particle"}; - - // DCA Configurables - booleans to enable/disable pT-dependent cuts - Configurable cfgUseDCAxyCorrection{"cfgUseDCAxyCorrection", true, "Use pT-dependent DCAxy cut"}; - Configurable cfgUseDCAzCorrection{"cfgUseDCAzCorrection", true, "Use pT-dependent DCAz cut"}; - - Configurable cfgDebug{"cfgDebug", 1, "debug level"}; - Configurable cfgRigidityCorrection{"cfgRigidityCorrection", false, "apply rigidity correction"}; - Configurable cfgRequirebetaplot{"cfgRequirebetaplot", true, "Require beta plot"}; - Configurable cfgmass2{"cfgmass2", true, "Fill mass square difference"}; - Configurable cfgFillmass{"cfgFillmass", false, "Fill mass histograms"}; - Configurable cfgFillmassnsigma{"cfgFillmassnsigma", true, "Fill mass vs nsigma histograms"}; - - Configurable> cfgBetheBlochParams{"cfgBetheBlochParams", {kBetheBlochDefault[0], nParticles, nBetheParams, particleNames, betheBlochParNames}, "TPC Bethe-Bloch parameterisation for light nuclei"}; - Configurable> cfgTrackPIDsettings{"cfgTrackPIDsettings", {kTrackPIDSettings[0], nParticles, nTrkSettings, particleNames, trackPIDsettingsNames}, "track selection and PID criteria"}; - Configurable> cfgTrackPIDsettings2{"cfgTrackPIDsettings2", {kTrackPIDSettings2[0], nParticles, nTrkSettings2, particleNames, trackPIDsettingsNames2}, "track selection and PID criteria"}; - Configurable> cfgktrackcorrection{"cfgktrackcorrection", {ktrackcorrection[0], nfittingparticle, nfittingparameters, correctedparticleNames, trackcorrectionNames}, "fitting parameters"}; - - // DCA correction parameters - simple 2x3 array - Configurable> cfgDCAcorrection{"cfgDCAcorrection", {kDCAcorrection[0], nDCAtypes, nDCAparameters, dcaTypeNames, dcaNames}, "DCA parameters: DCAxy: p0*exp(p1*pt)+p2, DCAz: p0*exp(-p1*pt)+p2"}; - - o2::track::TrackParametrizationWithError mTrackParCov; - // Binning configuration - ConfigurableAxis axisMagField{"axisMagField", {10, -10., 10.}, "magnetic field"}; - ConfigurableAxis axisNev{"axisNev", {10, 0., 10.}, "Number of events"}; - ConfigurableAxis axisRigidity{"axisRigidity", {4000, -10., 10.}, "#it{p}^{TPC}/#it{z}"}; - ConfigurableAxis axisdEdx{"axisdEdx", {4000, 0, 4000}, "d#it{E}/d#it{x}"}; - ConfigurableAxis axisCent{"axisCent", {100, 0, 100}, "centrality"}; - ConfigurableAxis axisOccupancy{"axisOccupancy", {5000, 0, 50000}, "axis for Occupancy of event"}; - ConfigurableAxis axisVtxZ{"axisVtxZ", {120, -20, 20}, "z"}; - ConfigurableAxis ptAxis{"ptAxis", {200, 0, 10}, "#it{p}_{T} (GeV/#it{c})"}; - ConfigurableAxis axiseta{"axiseta", {100, -1, 1}, "eta"}; - ConfigurableAxis axisrapidity{"axisrapidity", {100, -2, 2}, "rapidity"}; - ConfigurableAxis axismass{"axismass", {1200, 0, 12}, "mass"}; - ConfigurableAxis axismassnsigma{"axismassnsigma", {1200, 0, 12}, "nsigma mass"}; - ConfigurableAxis nsigmaAxis{"nsigmaAxis", {160, -10, 10}, "n#sigma_{#pi^{+}}"}; - ConfigurableAxis axisDCA{"axisDCA", {400, -10., 10.}, "DCA axis"}; - ConfigurableAxis particleAntiAxis{"particleAntiAxis", {2, -0.5, 1.5}, "Particle/Anti-particle"}; // 0 = particle, 1 = anti-particle - ConfigurableAxis decayTypeAxis{"decayTypeAxis", {3, -0.5, 2.5}, "Decay type"}; // 0 = primary, 1 = from decay, 2 = material - - // CCDB - Service ccdb; - Configurable bField{"bField", -999, "bz field, -999 is automatic"}; - Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - Configurable pidPath{"pidPath", "", "Path to the PID response object"}; - - std::vector primaryParticles; - std::vector primVtx, cents; - bool collHasCandidate = false; - bool collPassedEvSel = false; - int mRunNumber = 0; - int occupancy = 0; - float dBz = 0.0f; - TRandom3 rand; - float proton = 1; - float de = 2; - float triton = 3; - float he3 = 4; - float he4 = 5; - - //---------------------------------------------------------------------------------------------------------------- - void init(InitContext const&) - { - mRunNumber = 0; - dBz = 0; - rand.SetSeed(0); - ccdb->setURL(ccdbUrl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - for (int i = 0; i < nParticles; i++) { // create primaryParticles - primaryParticles.push_back(PrimParticles(particleNames.at(i), particlePdgCodes.at(i), particleMasses.at(i), particleCharge.at(i), cfgBetheBlochParams)); - } - // create histograms - if (doprocessData) { - histos.add("histNev", "histNev", kTH1F, {axisNev}); - histos.add("histVtxZ", "histVtxZ", kTH1F, {axisVtxZ}); - histos.add("histCentFT0C", "histCentFT0C", kTH1F, {axisCent}); - histos.add("histCentFT0M", "histCentFT0M", kTH1F, {axisCent}); - histos.add("histCentFTOC_cut", "histCentFTOC_cut", kTH1F, {axisCent}); - histos.add("hSpectra", " ", HistType::kTHnSparseF, {ptAxis, nsigmaAxis, {5, -2.5, 2.5}, axisCent}); - histos.add("hSpectratof", " ", HistType::kTHnSparseF, {ptAxis, nsigmaAxis, {5, -2.5, 2.5}, axisCent}); - histos.add("DCAxy_vs_pT_data", "DCA_{xy} vs p_{T} for He3 (Data);p_{T} (GeV/c);DCA_{xy} (cm)", - {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); - histos.add("DCAxy_vs_pT_anti_data", "DCA_{xy} vs p_{T} for anti-He3 (Data);p_{T} (GeV/c);DCA_{xy} (cm)", - {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); - - hmass.resize(2 * nParticles + 2); - hmassnsigma.resize(2 * nParticles + 2); - - for (int i = 0; i < nParticles; i++) { - TString histName = primaryParticles[i].name; - if (cfgFillmass) { - hmass[2 * i] = histos.add(Form("histmass_pt/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}; centrality(%)", HistType::kTH3F, {ptAxis, axismass, axisCent}); - hmass[2 * i + 1] = histos.add(Form("histmass_ptanti/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}; centrality(%)", HistType::kTH3F, {ptAxis, axismass, axisCent}); - } - } - for (int i = 0; i < nParticles; i++) { - TString histName = primaryParticles[i].name; - if (cfgFillmassnsigma) { - hmassnsigma[2 * i] = histos.add(Form("histmass_nsigma/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}/z^{2}; Centrality(%)", HistType::kTH3F, {ptAxis, axismassnsigma, axisCent}); - hmassnsigma[2 * i + 1] = histos.add(Form("histmass_nsigmaanti/histmass_%s", histName.Data()), ";p_T{TPC} (GeV/#it{c}); mass^{2}/z^{2}; centrality(%)", HistType::kTH3F, {ptAxis, axismassnsigma, axisCent}); - } - } - - histos.add("histeta", "histeta", kTH1F, {axiseta}); - - histos.add("histEvents", "histEvents", kTH2F, {axisCent, axisOccupancy}); - } - - histos.add("dcaZ", "dcaZ", kTH2F, {ptAxis, axisDCA}); - histos.add("dcaXY", "dcaXY", kTH2F, {ptAxis, axisDCA}); - histos.add("Tofsignal", "Tofsignal", kTH2F, {axisRigidity, {4000, 0.2, 1.2, "#beta"}}); - histos.add("Tpcsignal", "Tpcsignal", kTH2F, {axisRigidity, axisdEdx}); - - if (doprocessMC) { - histomc.add("hSpectramc", " ", HistType::kTHnSparseF, {{5, -2.5, 2.5}, axisCent, ptAxis, ptAxis}); - - // Efficiency x Acceptance - histomc.add("hDenomEffAcc", "Denominator for Efficiency x Acceptance", - {HistType::kTHnSparseF, {ptAxis, axisCent, particleAntiAxis, decayTypeAxis}}); - histomc.add("hNumerEffAcc", "Numerator for Efficiency x Acceptance", - {HistType::kTHnSparseF, {ptAxis, axisCent, particleAntiAxis, decayTypeAxis}}); - - // The Signal loss correction - histomc.add("hSignalLossDenom", "Signal Loss Denominator", kTH2F, {axisCent, ptAxis}); - histomc.add("hSignalLossNumer", "Signal Loss Numerator", kTH2F, {axisCent, ptAxis}); - - histomc.add("haSignalLossDenom", "anti particle Signal Loss Denominator", kTH2F, {axisCent, ptAxis}); - histomc.add("haSignalLossNumer", "antiparticle Signal Loss Numerator", kTH2F, {axisCent, ptAxis}); - - // The event loss correction - histomc.add("hEventLossDenom", "Event loss denominator", kTH1F, {axisCent}); - histomc.add("hEventLossNumer", "Event loss numerator", kTH1F, {axisCent}); - - histomc.add("histVtxZgen", "histVtxZgen", kTH1F, {axisVtxZ}); - histomc.add("histVtxZReco", "histVtxZReco", kTH1F, {axisVtxZ}); - - histomc.add("histDeltaPtVsPtGenanti", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10}, {1000, -0.5, 0.5, "p_{T}(reco) - p_{T}(gen);p_{T}(reco)"}}); - histomc.add("histDeltaPtVsPtGen", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10}, {1000, -0.5, 0.5, "p_{T}(reco) - p_{T}(gen);p_{T}(reco)"}}); - histomc.add("histPIDtrack", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10, "p_{T}(reco)"}, {9, -0.5, 8.5, "p_{T}(reco) - p_{T}(gen)"}}); - histomc.add("histPIDtrackanti", " delta pt vs pt rec", HistType::kTH2F, {{1000, 0, 10, "p_{T}(reco)"}, {9, -0.5, 8.5, "p_{T}(reco) - p_{T}(gen)"}}); - - // Mass²/z² 3D plots for MC (pT, mass²/z², centrality) - separate for particles and anti-particles - histomc.add("hMassVsPtMC", "mass^{2}/z^{2} vs p_{T} (MC Particles);p_{T} (GeV/c);mass^{2}/z^{2};Centrality", - {HistType::kTH3F, {ptAxis, axismassnsigma, axisCent}}); - histomc.add("hMassVsPtAntiMC", "mass^{2}/z^{2} vs p_{T} (MC Anti-particles);p_{T} (GeV/c);mass^{2}/z^{2};Centrality", - {HistType::kTH3F, {ptAxis, axismassnsigma, axisCent}}); - } - - if (doprocessDCA) { - - // NEW: Add DCAxy vs pT histograms for MC - histomc.add("DCAxy_vs_pT_transport", "DCA_{xy} vs p_{T} (Transport);p_{T} (GeV/c);DCA_{xy} (cm)", - {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); - histomc.add("DCAxy_vs_pT_primary", "DCA_{xy} vs p_{T} (primary);p_{T} (GeV/c);DCA_{xy} (cm)", - {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); - histomc.add("DCAxy_vs_pT_weakdecay", "DCA_{xy} vs p_{T} (Weak Decay);p_{T} (GeV/c);DCA_{xy} (cm)", - {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); - histomc.add("DCAxy_vs_pT_total", "DCA_{xy} vs p_{T} (Total);p_{T} (GeV/c);DCA_{xy} (cm)", - {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); - histomc.add("DCAxy_vs_pT_anti_total", "DCA_{xy} vs p_{T} for anti (Total);p_{T} (GeV/c);DCA_{xy} (cm)", - {HistType::kTH3F, {ptAxis, axisDCA, axisCent}}); - } - } - //---------------------------------------------------------------------------------------------------------------- - void processData(CollisionsFull const& collisions, - TracksFull const& tracks, - aod::BCsWithTimestamps const&) - { - // Get DCA parameters from configurable - double dcaXY_p0 = cfgDCAcorrection->get(0U, "p0"); - double dcaXY_p1 = cfgDCAcorrection->get(0U, "p1"); - double dcaXY_p2 = cfgDCAcorrection->get(0U, "p2"); - double dcaZ_p0 = cfgDCAcorrection->get(1U, "p0"); - double dcaZ_p1 = cfgDCAcorrection->get(1U, "p1"); - double dcaZ_p2 = cfgDCAcorrection->get(1U, "p2"); - - for (const auto& collision : collisions) { - auto bc = collision.bc_as(); - initCCDB(bc); - initCollision(collision); - - if (!collPassedEvSel) - continue; - if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) - continue; - histos.fill(HIST("histNev"), 2.5); - - if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) - continue; - histos.fill(HIST("histNev"), 3.5); - if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) - continue; - - histos.fill(HIST("histNev"), 4.5); - if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) - continue; - histos.fill(HIST("histNev"), 5.5); - histos.fill(HIST("histEvents"), collision.centFT0C(), occupancy); - histos.fill(HIST("histVtxZ"), collision.posZ()); - histos.fill(HIST("histCentFT0C"), collision.centFT0C()); - histos.fill(HIST("histCentFT0M"), collision.centFT0M()); - if (collision.centFT0C() > centcut) - continue; - histos.fill(HIST("histNev"), 6.5); - histos.fill(HIST("histCentFTOC_cut"), collision.centFT0C()); - // new slicing - auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); - // loop over sliced tracks - for (const auto& track : tracksInColl) { - if (!track.isPVContributor() && cfgUsePVcontributors) - continue; - if (!track.hasTPC()) - continue; - if (!track.passedITSRefit() && cfgPassedITSRefit) - continue; - if (!track.passedTPCRefit() && cfgPassedTPCRefit) - continue; - if (std::abs(track.eta()) > cfgCutEta && cfgetaRequire) - continue; - for (size_t i = 0; i < primaryParticles.size(); i++) { - if (cfgTrackPIDsettings2->get(i, "fillsparsh") != 1) - continue; - float ptMomn; - setTrackParCov(track, mTrackParCov); - mTrackParCov.setPID(track.pidForTracking()); - ptMomn = (i == he3 || i == he4) ? 2 * mTrackParCov.getPt() : mTrackParCov.getPt(); - float tpcNsigma = getTPCnSigma(track, primaryParticles.at(i)); - if ((std::abs(tpcNsigma) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) && cfgmaxTPCnSigmaRequire) - continue; - int sign = (track.sign() > 0) ? 1 : ((track.sign() < 0) ? -1 : 0); - float rapidity = getRapidity(track, i); - if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequire) - continue; - if (track.tpcNClsFound() < cfgTrackPIDsettings->get(i, "minTPCnCls")) - continue; - if (((track.tpcNClsCrossedRows() < cfgTrackPIDsettings->get(i, "minTPCnClsCrossedRows")) || - track.tpcNClsCrossedRows() < cfgtpcNClsFindable * track.tpcNClsFindable()) && - cfgTPCNClsCrossedRowsRequire) - continue; - if (track.tpcChi2NCl() > cfgTrackPIDsettings->get(i, "maxTPCchi2") && cfgmaxTPCchi2Require) - continue; - if (track.tpcChi2NCl() < cfgTrackPIDsettings->get(i, "minTPCchi2") && cfgminTPCchi2Require) - continue; - if (track.itsNCls() < cfgTrackPIDsettings->get(i, "minITSnCls") && cfgminITSnClsRequire) - continue; - double cosheta = std::cosh(track.eta()); - if ((track.itsNCls() / cosheta) < cfgTrackPIDsettings->get(i, "minITSnClscos") && cfgminITSnClscosRequire) - continue; - if ((track.itsNClsInnerBarrel() < cfgTrackPIDsettings->get(i, "minReqClusterITSib")) && cfgminReqClusterITSibRequire) - continue; - if (track.itsChi2NCl() > cfgTrackPIDsettings->get(i, "maxITSchi2") && cfgmaxITSchi2Require) - continue; - if (getMeanItsClsSize(track) < cfgTrackPIDsettings->get(i, "minITSclsSize") && cfgminGetMeanItsClsSizeRequire) - continue; - - // DCAxy cut - bool insideDCAxy = false; - if (cfgUseDCAxyCorrection) { - // Use pT-dependent DCAxy cut - double sigmaFactor = cfgTrackPIDsettings->get(i, "maxDcaXY"); - double sigma_base = dcaXY_p0 * std::exp(dcaXY_p1 * ptMomn) + dcaXY_p2; - double sigma_new = sigmaFactor * sigma_base; - insideDCAxy = (std::abs(track.dcaXY()) <= sigma_new); - } else { - // Use simple DCAxy cut (no pT dependence) - insideDCAxy = (std::abs(track.dcaXY()) <= cfgTrackPIDsettings->get(i, "maxDcaXY")); - } - - // DCAz cut - bool insideDCAz = false; - if (cfgUseDCAzCorrection) { - // Use pT-dependent DCAz cut - double sigmaFactorZ = cfgTrackPIDsettings->get(i, "maxDcaZ"); - double sigma_base_z = dcaZ_p0 * std::exp(-dcaZ_p1 * ptMomn) + dcaZ_p2; - double sigma_new_z = sigmaFactorZ * sigma_base_z; - insideDCAz = (std::abs(track.dcaZ()) <= sigma_new_z); - } else { - // Use simple DCAz cut (no pT dependence) - insideDCAz = (std::abs(track.dcaZ()) <= cfgTrackPIDsettings->get(i, "maxDcaZ")); - } - - if ((!insideDCAxy || !insideDCAz)) { - continue; - } - - float itsSigma = getITSnSigma(track, primaryParticles.at(i)); - if (itsSigma < cfgTrackPIDsettings2->get(i, "minITSnsigma") && cfgTrackPIDsettings2->get(i, "useITSnsigma") < 1) - continue; - if (itsSigma > cfgTrackPIDsettings2->get(i, "maxITSnsigma") && cfgTrackPIDsettings2->get(i, "useITSnsigma") < 1) - continue; - - histos.fill(HIST("Tpcsignal"), getRigidity(track) * track.sign(), track.tpcSignal()); - histos.fill(HIST("dcaXY"), ptMomn, track.dcaXY()); - histos.fill(HIST("dcaZ"), ptMomn, track.dcaZ()); - float tofnsigma = -999; - if (i == proton) { - tofnsigma = track.tofNSigmaPr(); - } - if (track.sign() > 0) { - histos.fill(HIST("DCAxy_vs_pT_data"), ptMomn, track.dcaXY(), collision.centFT0C()); - } else if (track.sign() < 0) { - histos.fill(HIST("DCAxy_vs_pT_anti_data"), ptMomn, track.dcaXY(), collision.centFT0C()); - } - // Get deuteron TPC nsigma for He4 selection - float tpcNsigmaDe = -999; - tpcNsigmaDe = track.tpcNSigmaDe(); - - if (i != he4) { - histos.fill(HIST("hSpectra"), ptMomn, tpcNsigma, sign, collision.centFT0C()); - if (track.hasTOF() && i == proton) { - histos.fill(HIST("hSpectratof"), ptMomn, tofnsigma, sign, collision.centFT0C()); - } - } else { - - if (!track.hasTOF()) { - if (std::abs(tpcNsigmaDe) > deuteronsigmarejection) { - histos.fill(HIST("hSpectra"), ptMomn, tpcNsigma, sign, collision.centFT0C()); - } - } else { - // Has TOF - apply mass cut - float beta = o2::pid::tof::Beta::GetBeta(track); - const float eps = 1e-6f; - if (beta < eps || beta > 1.0f - eps) - continue; - - float charge = 2.f; // he4 has charge 2 - float p = getRigidity(track); - float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); - - // Apply mass cut for he4 (mass^2 around 3.73^2 = 13.9) - if (cfghe3massrejreq && (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection)) { - continue; // Skip if mass cut fails - } - if (std::abs(tpcNsigmaDe) > deuteronsigmarejection) { - histos.fill(HIST("hSpectra"), ptMomn, tpcNsigma, sign, collision.centFT0C()); - } - } - } - - if ((std::abs(tpcNsigma) > cfgTrackPIDsettings2->get(i, "maxTPCnsigmaTOF"))) { - if (i == he4) { - if (std::abs(tpcNsigmaDe) > deuteronsigmarejection) { - fillhmassnsigma(track, i, collision.centFT0C()); - } - } else { - fillhmassnsigma(track, i, collision.centFT0C()); - } - } - - if ((std::abs(tpcNsigma) > cfgTrackPIDsettings2->get(i, "maxTPCnsigmaTOF")) && cfgTrackPIDsettings2->get(i, "useTPCnsigmaTOF") < 1) - continue; - - if (i == he4) { - if (std::abs(tpcNsigmaDe) > deuteronsigmarejection) { - fillhmass(track, i, collision.centFT0C()); - } - } else { - if (i == proton && (std::abs(tofnsigma) < cfgTrackPIDsettings2->get(i, "maxTOFnsigma"))) { - fillhmassnsigma(track, i, collision.centFT0C()); - } else { - fillhmass(track, i, collision.centFT0C()); - } - } - - if (cfgRequirebetaplot) { - histos.fill(HIST("Tofsignal"), getRigidity(track) * track.sign(), o2::pid::tof::Beta::GetBeta(track)); - } - } // loop primaryParticles - - histos.fill(HIST("histeta"), track.eta()); - } // loop sliced tracks - } // collision loop - } - PROCESS_SWITCH(NucleitpcPbPb, processData, "data analysis", false); - - //---------------------------------------------------------------------------------------------------------------- - // MC particles - Efficiency x Acceptance and Signal Loss calculations - //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - struct McCollInfo { - bool passedEvSel = false; - float centrality = -1.0f; - bool passedEvSelVtZ = false; - }; - std::vector mcCollInfos; - - void processMC(CollisionsFullMC const& collisions, - aod::McCollisions const& mcCollisions, - soa::Join const& tracks, - aod::McParticles const& particlesMC, - aod::BCsWithTimestamps const&) - - { - // Get DCA parameters from configurable - double dcaXY_p0 = cfgDCAcorrection->get(0U, "p0"); - double dcaXY_p1 = cfgDCAcorrection->get(0U, "p1"); - double dcaXY_p2 = cfgDCAcorrection->get(0U, "p2"); - double dcaZ_p0 = cfgDCAcorrection->get(1U, "p0"); - double dcaZ_p1 = cfgDCAcorrection->get(1U, "p1"); - double dcaZ_p2 = cfgDCAcorrection->get(1U, "p2"); - - mcCollInfos.clear(); - mcCollInfos.resize(mcCollisions.size()); - - // First pass: Store centrality and apply event selection - for (auto const& collision : collisions) { - int mcCollIdx = collision.mcCollisionId(); - if (mcCollIdx < 0 || mcCollIdx >= static_cast(mcCollisions.size())) { - continue; - } - - // STORE CENTRALITY WITHOUt CUTS - mcCollInfos[mcCollIdx].centrality = collision.centFT0C(); - - if (!collision.sel8() && cfgsel8Require) - continue; - if (collision.centFT0C() > centcut) - continue; - - if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) - continue; - if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) - continue; - if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) - continue; - if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) - continue; - - // Mark this MC collision as passing event selection - mcCollInfos[mcCollIdx].passedEvSel = true; - - // Apply event selection cuts - if (std::abs(collision.posZ()) > cfgZvertex && cfgZvertexRequireMC) - continue; - - mcCollInfos[mcCollIdx].passedEvSelVtZ = true; - } - - // FILL EVENT LOSS AND SIGNAL LOSS: Combined loop per MC collision - for (size_t i = 0; i < mcCollInfos.size(); i++) { - if (mcCollInfos[i].centrality >= 0) { // Only if we found a matching collision - // Event loss denominator (always filled regardless of fillsparsh) - histomc.fill(HIST("hEventLossDenom"), mcCollInfos[i].centrality); - - // Event loss numerator (if passed selection) - if (mcCollInfos[i].passedEvSel) { - histomc.fill(HIST("hEventLossNumer"), mcCollInfos[i].centrality); - } - - // Fill signal loss for all primary particles in this MC collision - for (auto const& mcParticle : particlesMC) { - if (mcParticle.mcCollisionId() != static_cast(i)) { - continue; - } - if (!mcParticle.isPhysicalPrimary()) { - continue; - } - - // Check if this particle type has fillsparsh enabled - int particleType = -1; - for (size_t j = 0; j < primaryParticles.size(); j++) { - if (std::abs(mcParticle.pdgCode()) == std::abs(particlePdgCodes.at(j))) { - particleType = j; - break; - } - } - - // Skip if fillsparsh is not enabled for this particle - if (particleType < 0 || cfgTrackPIDsettings2->get(particleType, "fillsparsh") != 1) - continue; - - // Signal loss denominator - if (mcParticle.pdgCode() == particlePdgCodes.at(particleType)) { // particle - histomc.fill(HIST("hSignalLossDenom"), mcCollInfos[i].centrality, mcParticle.pt()); - } else if (mcParticle.pdgCode() == -particlePdgCodes.at(particleType)) { // anti-particle - histomc.fill(HIST("haSignalLossDenom"), mcCollInfos[i].centrality, mcParticle.pt()); - } - // Signal loss numerator (if event passed selection) - if (mcCollInfos[i].passedEvSel) { - if (mcParticle.pdgCode() == particlePdgCodes.at(particleType)) { // particle - histomc.fill(HIST("hSignalLossNumer"), mcCollInfos[i].centrality, mcParticle.pt()); - } else if (mcParticle.pdgCode() == -particlePdgCodes.at(particleType)) { // anti-particle - histomc.fill(HIST("haSignalLossNumer"), mcCollInfos[i].centrality, mcParticle.pt()); - } - } - } - } - } - - // Process MC collisions for efficiency and reconstructed collisions - for (auto const& mcCollision : mcCollisions) { - size_t idx = mcCollision.globalIndex(); - if (idx >= mcCollInfos.size()) - continue; - - float centrality = mcCollInfos[idx].centrality; - bool passedEvSelVtZ = mcCollInfos[idx].passedEvSelVtZ; - - // Process generated particles for efficiency denominators - histomc.fill(HIST("histVtxZgen"), mcCollision.posZ()); - - for (auto const& mcParticle : particlesMC) { - if (mcParticle.mcCollisionId() != mcCollision.globalIndex()) - continue; - - int pdgCode = mcParticle.pdgCode(); - - // Check which particle type this is - int particleType = -1; - for (size_t j = 0; j < primaryParticles.size(); j++) { - if (std::abs(pdgCode) == std::abs(particlePdgCodes.at(j))) { - particleType = j; - break; - } - } - - // Only process if this particle type has fillsparsh enabled - if (particleType < 0 || cfgTrackPIDsettings2->get(particleType, "fillsparsh") != 1) - continue; - - if (std::abs(mcParticle.eta()) > cfgCutEta && cfgetaRequireMC) - continue; - float rapidity = mcParticle.y(); - if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequireMC) - continue; - - int decayType = 0; - int particleAnti = (pdgCode > 0) ? 0 : 1; - - if (mcParticle.isPhysicalPrimary()) { - decayType = 0; - if (mcParticle.has_mothers()) { - for (const auto& motherparticle : mcParticle.mothers_as()) { - if (std::find(hfMothCodes.begin(), hfMothCodes.end(), - std::abs(motherparticle.pdgCode())) != hfMothCodes.end()) { - decayType = 1; - break; - } - } - } - } else if (mcParticle.has_mothers()) { - decayType = 1; - } else { - decayType = 2; - continue; - } - - // Efficiency x Acceptance histograms - Denominator - if (passedEvSelVtZ) { - histomc.fill(HIST("hDenomEffAcc"), mcParticle.pt(), centrality, particleAnti, decayType); - } - } - - // Process reconstructed collisions for this MC collision - if (passedEvSelVtZ) { - // Find the corresponding reconstructed collision - for (auto const& collision : collisions) { - if (collision.mcCollisionId() != static_cast(idx)) - continue; - - auto bc = collision.bc_as(); - initCCDB(bc); - - histomc.fill(HIST("histVtxZReco"), collision.posZ()); - - auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); - - for (auto const& track : tracksInColl) { - if (!track.has_mcParticle()) - continue; // skip un-matched reco tracks - - auto const& matchedMCParticle = track.mcParticle_as(); - - // Only process particles from this MC collision - if (matchedMCParticle.mcCollisionId() != mcCollision.globalIndex()) - continue; - - int pdg = matchedMCParticle.pdgCode(); - - int decayType = 0; - - if (matchedMCParticle.isPhysicalPrimary()) { - decayType = 0; - if (matchedMCParticle.has_mothers()) { - for (const auto& motherparticle : matchedMCParticle.mothers_as()) { - if (std::find(hfMothCodes.begin(), hfMothCodes.end(), - std::abs(motherparticle.pdgCode())) != hfMothCodes.end()) { - decayType = 1; - break; - } - } - } - } else if (matchedMCParticle.has_mothers()) { - decayType = 1; - } else { - decayType = 2; - } - - if (!track.isPVContributor() && cfgUsePVcontributors) - continue; - - if (!track.hasTPC()) - continue; - if (!track.passedITSRefit() && cfgPassedITSRefit) - continue; - if (!track.passedTPCRefit() && cfgPassedTPCRefit) - continue; - if (std::abs(track.eta()) > cfgCutEta && cfgetaRequire) - continue; - - for (size_t i = 0; i < primaryParticles.size(); i++) { - if (std::abs(pdg) != std::abs(particlePdgCodes.at(i))) - continue; - - // CRITICAL: Only process if fillsparsh is enabled for this particle - if (cfgTrackPIDsettings2->get(i, "fillsparsh") != 1) - continue; - - float ptReco; - setTrackParCov(track, mTrackParCov); - mTrackParCov.setPID(track.pidForTracking()); - - ptReco = (std::abs(pdg) == particlePdgCodes.at(4) || std::abs(pdg) == particlePdgCodes.at(5)) ? 2 * mTrackParCov.getPt() : mTrackParCov.getPt(); - - int particleAnti = (pdg > 0) ? 0 : 1; - - double a = 0, b = 0, c = 0; - - int param = -1; - if (i == he3) { - param = (pdg > 0) ? 0 : 1; - } else if (i == he4) { - param = (pdg > 0) ? 2 : 3; - } - - if (param >= 0) { - a = cfgktrackcorrection->get(param, "a"); - b = cfgktrackcorrection->get(param, "b"); - c = cfgktrackcorrection->get(param, "c"); - } - - if (std::abs(pdg) == particlePdgCodes.at(5) && cfgmccorrectionhe4Require) { - ptReco = ptReco + a + b * std::exp(c * ptReco); - } - - if (std::abs(pdg) == particlePdgCodes.at(4) && cfgmccorrectionhe4Require) { - int pidGuess = track.pidForTracking(); - int antitriton = 6; - if (pidGuess == antitriton) { - ptReco = ptReco - a + b * ptReco - c * ptReco * ptReco; - } - } - - float rapidity = getRapidity(track, i); - if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequire) - continue; - - if (track.tpcNClsFound() < cfgTrackPIDsettings->get(i, "minTPCnCls")) - continue; - if (((track.tpcNClsCrossedRows() < cfgTrackPIDsettings->get(i, "minTPCnClsCrossedRows")) || track.tpcNClsCrossedRows() < cfgtpcNClsFindable * track.tpcNClsFindable()) && cfgTPCNClsCrossedRowsRequire) - continue; - if (track.tpcChi2NCl() > cfgTrackPIDsettings->get(i, "maxTPCchi2") && cfgmaxTPCchi2Require) - continue; - if (track.tpcChi2NCl() < cfgTrackPIDsettings->get(i, "minTPCchi2") && cfgminTPCchi2Require) - continue; - if (track.itsNCls() < cfgTrackPIDsettings->get(i, "minITSnCls") && cfgminITSnClsRequire) - continue; - double cosheta = std::cosh(track.eta()); - if ((track.itsNCls() / cosheta) < cfgTrackPIDsettings->get(i, "minITSnClscos") && cfgminITSnClscosRequire) - continue; - if ((track.itsNClsInnerBarrel() < cfgTrackPIDsettings->get(i, "minReqClusterITSib")) && cfgminReqClusterITSibRequire) - continue; - if (track.itsChi2NCl() > cfgTrackPIDsettings->get(i, "maxITSchi2") && cfgmaxITSchi2Require) - continue; - if (getMeanItsClsSize(track) < cfgTrackPIDsettings->get(i, "minITSclsSize") && cfgminGetMeanItsClsSizeRequire) - continue; - - // DCAxy cut - bool insideDCAxy = false; - if (cfgUseDCAxyCorrection) { - // Use pT-dependent DCAxy cut - double sigmaFactor = cfgTrackPIDsettings->get(i, "maxDcaXY"); - double sigma_base = dcaXY_p0 * std::exp(dcaXY_p1 * ptReco) + dcaXY_p2; - double sigma_new = sigmaFactor * sigma_base; - insideDCAxy = (std::abs(track.dcaXY()) <= sigma_new); - } else { - // Use simple DCAxy cut (no pT dependence) - insideDCAxy = (std::abs(track.dcaXY()) <= cfgTrackPIDsettings->get(i, "maxDcaXY")); - } - - // DCAz cut - bool insideDCAz = false; - if (cfgUseDCAzCorrection) { - // Use pT-dependent DCAz cut - double sigmaFactorZ = cfgTrackPIDsettings->get(i, "maxDcaZ"); - double sigma_base_z = dcaZ_p0 * std::exp(-dcaZ_p1 * ptReco) + dcaZ_p2; - double sigma_new_z = sigmaFactorZ * sigma_base_z; - insideDCAz = (std::abs(track.dcaZ()) <= sigma_new_z); - } else { - // Use simple DCAz cut (no pT dependence) - insideDCAz = (std::abs(track.dcaZ()) <= cfgTrackPIDsettings->get(i, "maxDcaZ")); - } - - if ((!insideDCAxy || !insideDCAz)) { - continue; - } - - float tpcNsigma = getTPCnSigma(track, primaryParticles.at(i)); - if ((std::abs(tpcNsigma) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) && cfgmaxTPCnSigmaRequire) - continue; - - // Efficiency x Acceptance - Numerator - histomc.fill(HIST("hNumerEffAcc"), ptReco, collision.centFT0C(), particleAnti, decayType); - - // Sparse histogram - float ptTOF = -1.0; - if (track.hasTOF()) { - ptTOF = ptReco; - } - histomc.fill(HIST("hSpectramc"), particleAnti, collision.centFT0C(), ptReco, ptTOF); - - // Basic track histograms - if (decayType == 0) { - histos.fill(HIST("dcaXY"), ptReco, track.dcaXY()); - histos.fill(HIST("dcaZ"), ptReco, track.dcaZ()); - histos.fill(HIST("Tpcsignal"), getRigidity(track) * track.sign(), track.tpcSignal()); - } - // Delta Pt histograms - float ptGen = matchedMCParticle.pt(); - float deltaPt = ptReco - ptGen; - - if (pdg == -particlePdgCodes.at(i) && decayType == 0) { // Anti-particle - histomc.fill(HIST("histDeltaPtVsPtGenanti"), ptReco, deltaPt); - histomc.fill(HIST("histPIDtrackanti"), ptReco, track.pidForTracking()); - } - - if (pdg == particlePdgCodes.at(i) && decayType == 0) { // Particle - histomc.fill(HIST("histDeltaPtVsPtGen"), ptReco, deltaPt); - histomc.fill(HIST("histPIDtrack"), ptReco, track.pidForTracking()); - } - - // Fill mass²/z² for MC - separate for particles and anti-particles - if (track.hasTOF()) { - float beta = o2::pid::tof::Beta::GetBeta(track); - const float eps = 1e-6f; - if (beta >= eps && beta <= 1.0f - eps) { - float charge = (i == he3 || i == he4) ? 2.f : 1.f; - float p = getRigidity(track); - float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); - float massSquareOverChargeSquare = (massTOF * massTOF) / (charge * charge); - - // Apply He4 rejection if needed (to match data selection) - bool skipHe4 = false; - if (std::abs(pdg) == particlePdgCodes.at(5)) { // He4 - if (cfghe3massrejreq && (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection)) { - skipHe4 = true; - } - } - - if (!skipHe4 && decayType == 0) { - if (pdg > 0) { - histomc.fill(HIST("hMassVsPtMC"), ptReco, massSquareOverChargeSquare, collision.centFT0C()); - } else { - histomc.fill(HIST("hMassVsPtAntiMC"), ptReco, massSquareOverChargeSquare, collision.centFT0C()); - } - } - } - } - } - } - break; // Found the matching collision, break out of collision loop - } - } - } - } - PROCESS_SWITCH(NucleitpcPbPb, processMC, "MC reco+gen analysis with efficiency corrections", false); - //=-=-=-==-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - void processDCA(CollisionsFullMC const& collisions, - aod::McCollisions const& mcCollisions, - aod::McParticles const& particlesMC, - soa::Join const& tracks, - aod::BCsWithTimestamps const&) - - { - (void)particlesMC; - mcCollInfos.clear(); - mcCollInfos.resize(mcCollisions.size()); - - // First pass: Store centrality and apply event selection - for (auto const& collision : collisions) { - int mcCollIdx = collision.mcCollisionId(); - if (mcCollIdx < 0 || mcCollIdx >= static_cast(mcCollisions.size())) { - continue; - } - - // STORE CENTRALITY WITHOUT CUTS - mcCollInfos[mcCollIdx].centrality = collision.centFT0C(); - - if (!collision.sel8() && cfgsel8Require) - continue; - if (collision.centFT0C() > centcut) - continue; - - if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) - continue; - if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) - continue; - if (requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) - continue; - if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) - continue; - - // Mark this MC collision as passing event selection - mcCollInfos[mcCollIdx].passedEvSel = true; - - // Apply event selection cuts - if (std::abs(collision.posZ()) > cfgZvertex && cfgZvertexRequireMC) - continue; - - mcCollInfos[mcCollIdx].passedEvSelVtZ = true; - } - - // Process MC collisions for efficiency and reconstructed collisions - for (auto const& mcCollision : mcCollisions) { - size_t idx = mcCollision.globalIndex(); - if (idx >= mcCollInfos.size()) - continue; - - bool passedEvSelVtZ = mcCollInfos[idx].passedEvSelVtZ; - - // Process reconstructed collisions for this MC collision - if (passedEvSelVtZ) { - // Find the corresponding reconstructed collision - for (auto const& collision : collisions) { - if (collision.mcCollisionId() != static_cast(idx)) - continue; - - auto bc = collision.bc_as(); - initCCDB(bc); - auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); - - for (auto const& track : tracksInColl) { - if (!track.has_mcParticle()) - continue; // skip un-matched reco tracks - - auto const& matchedMCParticle = track.mcParticle_as(); - - // Only process particles from this MC collision - if (matchedMCParticle.mcCollisionId() != mcCollision.globalIndex()) - continue; - - int pdg = matchedMCParticle.pdgCode(); - - if (!track.isPVContributor() && cfgUsePVcontributors) - continue; - - if (!track.hasTPC()) - continue; - if (!track.passedITSRefit() && cfgPassedITSRefit) - continue; - if (!track.passedTPCRefit() && cfgPassedTPCRefit) - continue; - if (std::abs(track.eta()) > cfgCutEta && cfgetaRequire) - continue; - - for (size_t i = 0; i < primaryParticles.size(); i++) { - if (std::abs(pdg) != std::abs(particlePdgCodes.at(i))) - continue; - - if (cfgTrackPIDsettings2->get(i, "fillsparsh") != 1) - continue; - - float ptReco; - setTrackParCov(track, mTrackParCov); - mTrackParCov.setPID(track.pidForTracking()); - - ptReco = (std::abs(pdg) == particlePdgCodes.at(4) || std::abs(pdg) == particlePdgCodes.at(5)) ? 2 * mTrackParCov.getPt() : mTrackParCov.getPt(); - - double a = 0, b = 0, c = 0; - - int param = -1; - if (i == he3) { - param = (pdg > 0) ? 0 : 1; - } else if (i == he4) { - param = (pdg > 0) ? 2 : 3; - } - - if (param >= 0) { - a = cfgktrackcorrection->get(param, "a"); - b = cfgktrackcorrection->get(param, "b"); - c = cfgktrackcorrection->get(param, "c"); - } - - if (std::abs(pdg) == particlePdgCodes.at(5) && cfgmccorrectionhe4Require) { - ptReco = ptReco + a + b * std::exp(c * ptReco); - } - - if (std::abs(pdg) == particlePdgCodes.at(4) && cfgmccorrectionhe4Require) { - int pidGuess = track.pidForTracking(); - int antitriton = 6; - if (pidGuess == antitriton) { - ptReco = ptReco - a + b * ptReco - c * ptReco * ptReco; - } - } - - float rapidity = getRapidity(track, i); - if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequire) - continue; - - if (track.tpcNClsFound() < cfgTrackPIDsettings->get(i, "minTPCnCls")) - continue; - if (((track.tpcNClsCrossedRows() < cfgTrackPIDsettings->get(i, "minTPCnClsCrossedRows")) || track.tpcNClsCrossedRows() < cfgtpcNClsFindable * track.tpcNClsFindable()) && cfgTPCNClsCrossedRowsRequire) - continue; - if (track.tpcChi2NCl() > cfgTrackPIDsettings->get(i, "maxTPCchi2") && cfgmaxTPCchi2Require) - continue; - if (track.tpcChi2NCl() < cfgTrackPIDsettings->get(i, "minTPCchi2") && cfgminTPCchi2Require) - continue; - if (track.itsNCls() < cfgTrackPIDsettings->get(i, "minITSnCls") && cfgminITSnClsRequire) - continue; - double cosheta = std::cosh(track.eta()); - if ((track.itsNCls() / cosheta) < cfgTrackPIDsettings->get(i, "minITSnClscos") && cfgminITSnClscosRequire) - continue; - if ((track.itsNClsInnerBarrel() < cfgTrackPIDsettings->get(i, "minReqClusterITSib")) && cfgminReqClusterITSibRequire) - continue; - if (track.itsChi2NCl() > cfgTrackPIDsettings->get(i, "maxITSchi2") && cfgmaxITSchi2Require) - continue; - if (getMeanItsClsSize(track) < cfgTrackPIDsettings->get(i, "minITSclsSize") && cfgminGetMeanItsClsSizeRequire) - continue; - float tpcNsigma = getTPCnSigma(track, primaryParticles.at(i)); - if ((std::abs(tpcNsigma) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) && cfgmaxTPCnSigmaRequire) - continue; - - int decayType = -999; // 0 = primary, 1 = weak decay, 2 = material - if (matchedMCParticle.isPhysicalPrimary()) { - // ---- Primary particles ---- - decayType = 0; - if (matchedMCParticle.has_mothers()) { - for (auto& motherparticle : matchedMCParticle.mothers_as()) { - if (std::find(hfMothCodes.begin(), hfMothCodes.end(), std::abs(motherparticle.pdgCode())) != hfMothCodes.end()) { - decayType = 1; - break; - } - } - } - } else if (matchedMCParticle.getProcess() == TMCProcess::kPDecay) { - // ---- Secondary from weak decay ---- - if (!matchedMCParticle.has_mothers()) { - continue; // skip secondaries from weak decay without mothers - } - decayType = 1; - - // Check if it's from HF decay - for (auto& motherparticle : matchedMCParticle.mothers_as()) { - if (std::find(hfMothCodes.begin(), hfMothCodes.end(), std::abs(motherparticle.pdgCode())) != hfMothCodes.end()) { - break; - } - } - } else { - // ---- Secondary from material interaction ---- - decayType = 2; - } - - float ptDCA; - - if (i == he3 || i == he4) { - ptDCA = ptReco; - } else { - ptDCA = 2 * ptReco; - } - - if (pdg == particlePdgCodes.at(i)) { // He3 - histomc.fill(HIST("DCAxy_vs_pT_total"), ptDCA, track.dcaXY(), collision.centFT0C()); - if (matchedMCParticle.isPhysicalPrimary()) { - histomc.fill(HIST("DCAxy_vs_pT_primary"), ptDCA, track.dcaXY(), collision.centFT0C()); - } - if (decayType == 2) { // Transport/Material - histomc.fill(HIST("DCAxy_vs_pT_transport"), ptDCA, track.dcaXY(), collision.centFT0C()); - } else if (decayType == 1) { // Weak decay (including HF) - histomc.fill(HIST("DCAxy_vs_pT_weakdecay"), ptDCA, track.dcaXY(), collision.centFT0C()); - } - } else if (pdg == -particlePdgCodes.at(i)) { // anti-He3 - histomc.fill(HIST("DCAxy_vs_pT_anti_total"), ptDCA, track.dcaXY(), collision.centFT0C()); - } - } - } - break; // Found the matching collision, break out of collision loop - } - } - } - } - PROCESS_SWITCH(NucleitpcPbPb, processDCA, "MC DCA analysis For secondary correction", false); - //=-=-=-==-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - constexpr float kInvalidBField = -990.f; - auto run3grpTimestamp = bc.timestamp(); - dBz = 0; - o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grpTimestamp); - o2::parameters::GRPMagField* grpmag = 0x0; - if (grpo) { - o2::base::Propagator::initFieldFromGRP(grpo); - if (bField < kInvalidBField) { - // Fetch magnetic field from ccdb for current collision - dBz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grpTimestamp << " with magnetic field of " << dBz << " kZG"; - } else { - dBz = bField; - } - } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3grpTimestamp); - if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grpTimestamp; - } - o2::base::Propagator::initFieldFromGRP(grpmag); - if (bField < kInvalidBField) { - // Fetch magnetic field from ccdb for current collision - dBz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - LOG(info) << "Retrieved GRP for timestamp " << run3grpTimestamp << " with magnetic field of " << dBz << " kZG"; - } else { - dBz = bField; - } - } - mRunNumber = bc.runNumber(); - } - //---------------------------------------------------------------------------------------------------------------- - template - void initCollision(const T& collision) - { - collHasCandidate = false; - histos.fill(HIST("histNev"), 0.5); - collPassedEvSel = collision.sel8() && std::abs(collision.posZ()) < cfgZvertex; - occupancy = collision.trackOccupancyInTimeRange(); - if (collPassedEvSel) { - histos.fill(HIST("histNev"), 1.5); - } - primVtx.assign({collision.posX(), collision.posY(), collision.posZ()}); - cents.assign({collision.centFT0A(), collision.centFT0C(), collision.centFT0M()}); - } - //---------------------------------------------------------------------------------------------------------------- - template - void fillhmass(T const& track, int species, float cent) - { - if (!track.hasTOF() || !cfgFillmass) - return; - - float beta{o2::pid::tof::Beta::GetBeta(track)}; - const float eps = 1e-6f; - if (beta < eps || beta > 1.0f - eps) - return; - float charge = (species == he3 || species == he4) ? 2.f : 1.f; - float p = getRigidity(track); // assuming this is the momentum from inner TPC - float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); - float massDiff = 0.0; - if (species != he4) { - if (cfgmass2) { - // Compare squared masses - massDiff = (massTOF * massTOF) / (charge * charge); - } else { - // Compare linear masses - massDiff = massTOF / charge; - } - } - if (species == he4) { - if (cfghe3massrejreq && (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection)) - return; - if (cfgmass2) { - // Compare squared masses - massDiff = (massTOF * massTOF) / (charge * charge); - } else { - // Compare linear masses - massDiff = massTOF / charge; - } - } - - float ptMomn; - setTrackParCov(track, mTrackParCov); - mTrackParCov.setPID(track.pidForTracking()); - ptMomn = (species == he3 || species == he4) ? 2 * mTrackParCov.getPt() : mTrackParCov.getPt(); - if (track.sign() > 0) { - hmass[2 * species]->Fill(ptMomn, massDiff, cent); - } else if (track.sign() < 0) { - hmass[2 * species + 1]->Fill(ptMomn, massDiff, cent); - } - } - //---------------------------------------------------------------------------------------------------------------- - template - void fillhmassnsigma(T const& track, int species, float cent) - { - if (!track.hasTOF() || !cfgFillmassnsigma) - return; - - float beta{o2::pid::tof::Beta::GetBeta(track)}; - const float eps = 1e-6f; - if (beta < eps || beta > 1.0f - eps) - return; - - float charge = (species == he3 || species == he4) ? 2.f : 1.f; - float p = getRigidity(track); - float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); - - // Calculate mass²/z² - float massSquareOverChargeSquare = (massTOF * massTOF) / (charge * charge); - - // Apply helium-4 rejection if needed - if (species == he4) { - if (cfghe3massrejreq && (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection)) - return; - } - - float ptMomn; - setTrackParCov(track, mTrackParCov); - mTrackParCov.setPID(track.pidForTracking()); - ptMomn = (species == he3 || species == he4) ? 2 * mTrackParCov.getPt() : mTrackParCov.getPt(); - - // Fill histogram: mass²/z² vs pT vs centrality - if (track.sign() > 0) { - hmassnsigma[2 * species]->Fill(ptMomn, massSquareOverChargeSquare, cent); - } else if (track.sign() < 0) { - hmassnsigma[2 * species + 1]->Fill(ptMomn, massSquareOverChargeSquare, cent); - } - } - //---------------------------------------------------------------------------------------------------------------- - template - float getTPCnSigma(T const& track, PrimParticles& particle) - { - const float rigidity = getRigidity(track); - if (!track.hasTPC()) - return -999; - if (particle.name == "pion" && cfgTrackPIDsettings->get("pion", "useBBparams") < 1) - return cfgTrackPIDsettings->get("pion", "useBBparams") == 0 ? track.tpcNSigmaPi() : 0; - if (particle.name == "proton" && cfgTrackPIDsettings->get("proton", "useBBparams") < 1) - return cfgTrackPIDsettings->get("proton", "useBBparams") == 0 ? track.tpcNSigmaPr() : 0; - if (particle.name == "deuteron" && cfgTrackPIDsettings->get("deuteron", "useBBparams") < 1) - return cfgTrackPIDsettings->get("deuteron", "useBBparams") == 0 ? track.tpcNSigmaDe() : 0; - if (particle.name == "triton" && cfgTrackPIDsettings->get("triton", "useBBparams") < 1) - return cfgTrackPIDsettings->get("triton", "useBBparams") == 0 ? track.tpcNSigmaTr() : 0; - if (particle.name == "helion" && cfgTrackPIDsettings->get("helion", "useBBparams") < 1) - return cfgTrackPIDsettings->get("helion", "useBBparams") == 0 ? track.tpcNSigmaHe() : 0; - if (particle.name == "alpha" && cfgTrackPIDsettings->get("alpha", "useBBparams") < 1) - return cfgTrackPIDsettings->get("alpha", "useBBparams") == 0 ? track.tpcNSigmaAl() : 0; - - double expBethe{common::BetheBlochAleph(static_cast(particle.charge * rigidity / particle.mass), particle.betheParams[0], particle.betheParams[1], particle.betheParams[2], particle.betheParams[3], particle.betheParams[4])}; - double expSigma{expBethe * particle.resolution}; - float sigmaTPC = static_cast((track.tpcSignal() - expBethe) / expSigma); - return sigmaTPC; - } - //---------------------------------------------------------------------------------------------------------------- - template - float getITSnSigma(T const& track, PrimParticles& particle) - { - if (!track.hasITS()) - return -999; - o2::aod::ITSResponse itsResponse; - if (particle.name == "pion") - return itsResponse.nSigmaITS(track); - if (particle.name == "proton") - return itsResponse.nSigmaITS(track); - if (particle.name == "deuteron") - return itsResponse.nSigmaITS(track); - if (particle.name == "triton") - return itsResponse.nSigmaITS(track); - if (particle.name == "helion") - return itsResponse.nSigmaITS(track); - if (particle.name == "alpha") - return itsResponse.nSigmaITS(track); - return -999; // fallback if no match - } - //---------------------------------------------------------------------------------------------------------------- - template - float getMeanItsClsSize(T const& track) - { - int sum = 0, n = 0; - constexpr int kNITSLayers = 8; - for (int i = 0; i < kNITSLayers; i++) { - sum += (track.itsClusterSizes() >> (4 * i) & 15); - if (track.itsClusterSizes() >> (4 * i) & 15) - n++; - } - return n > 0 ? static_cast(sum) / n : 0.f; - } - //---------------------------------------------------------------------------------------------------------------- - template - float getRigidity(T const& track) - { - if (!cfgRigidityCorrection) - return track.tpcInnerParam(); - bool hePID = track.pidForTracking() == o2::track::PID::Helium3 || track.pidForTracking() == o2::track::PID::Alpha; - return hePID ? track.tpcInnerParam() / 2 : track.tpcInnerParam(); - } - - //---------------------------------------------------------------------------------------------------------------- - template - float getRapidity(T const& track, int species) - { - using PtEtaPhiMVector = ROOT::Math::LorentzVector>; - double momn; - int speciesHe3 = 4; - int speciesHe4 = 5; - if (species == speciesHe3 || species == speciesHe4) { - momn = 2 * track.pt(); - } else { - momn = track.pt(); - } - PtEtaPhiMVector lorentzVectorParticle(momn, track.eta(), track.phi(), particleMasses[species]); - return lorentzVectorParticle.Rapidity(); - } -}; // end of the task here -//---------------------------------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------------------------------- -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} From ff1ec04793e3dae1f3e94690b6986363004c1214 Mon Sep 17 00:00:00 2001 From: Nikita Gladin <72004465+AnalitikGnid@users.noreply.github.com> Date: Wed, 29 Jul 2026 15:01:38 +0200 Subject: [PATCH 34/71] [PWGLF] Add a workflow for (anti)triton analysis (#17151) --- PWGLF/Tasks/Nuspex/CMakeLists.txt | 5 + PWGLF/Tasks/Nuspex/antitritonAnalysis.cxx | 483 ++++++++++++++++++++++ 2 files changed, 488 insertions(+) create mode 100644 PWGLF/Tasks/Nuspex/antitritonAnalysis.cxx diff --git a/PWGLF/Tasks/Nuspex/CMakeLists.txt b/PWGLF/Tasks/Nuspex/CMakeLists.txt index 63264839eb3..b34ef39cf73 100644 --- a/PWGLF/Tasks/Nuspex/CMakeLists.txt +++ b/PWGLF/Tasks/Nuspex/CMakeLists.txt @@ -14,6 +14,11 @@ o2physics_add_dpl_workflow(nuclei-batask PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(antitriton-analysis + SOURCES antitritonAnalysis.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(hypertritonanalysis SOURCES hypertritonAnalysis.cxx PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2Physics::AnalysisCore diff --git a/PWGLF/Tasks/Nuspex/antitritonAnalysis.cxx b/PWGLF/Tasks/Nuspex/antitritonAnalysis.cxx new file mode 100644 index 00000000000..63bdfebde78 --- /dev/null +++ b/PWGLF/Tasks/Nuspex/antitritonAnalysis.cxx @@ -0,0 +1,483 @@ +// 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 antitritonAnalysis.cxx +/// \brief Analysis of (anti)tritons, based on PWGCF/Femto3D/DataModel/singletrackselector.h +/// \author Nikita Gladin + +#include "PWGCF/Femto3D/Core/femto3dPairTask.h" +#include "PWGCF/Femto3D/DataModel/PIDutils.h" +#include "PWGCF/Femto3D/DataModel/singletrackselector.h" + +#include "Common/DataModel/PIDResponseITS.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::soa; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct AntitritonAnalysis { + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry registryTrue{"registryTrue", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Service pdgDB{}; + float particleMass = 0.f; + + Configurable isMC{"isMC", false, ""}; + + Configurable removeSameBunchPileup{"removeSameBunchPileup", false, ""}; + Configurable requestGoodZvtxFT0vsPV{"requestGoodZvtxFT0vsPV", false, ""}; + Configurable requestVertexITSTPC{"requestVertexITSTPC", false, ""}; + Configurable requestVertexTOFmatched{"requestVertexTOFmatched", 0, "0 -> no selection; 1 -> vertex is matched to TOF or TRD; 2 -> matched to both;"}; + Configurable requestNoCollInTimeRangeStandard{"requestNoCollInTimeRangeStandard", false, ""}; + Configurable requestIsGoodITSLayersAll{"requestIsGoodITSLayersAll", false, "cut time intervals with dead ITS staves"}; + Configurable> irCut{"irCut", std::pair{0.f, 100.f}, "[min., max.] IR range to keep events within"}; + Configurable> occupancyCut{"occupancyCut", std::pair{0, 10000}, "[min., max.] occupancy range to keep events within"}; + + Configurable vertexZ{"vertexZ", 10.0, "abs vertexZ value limit"}; + Configurable minP{"minP", 0.0, "lower mometum limit"}; + Configurable maxP{"maxP", 100.0, "upper mometum limit"}; + Configurable eta{"eta", 100.0, "abs eta value limit"}; + Configurable y{"y", 100.0, "abs y value limit"}; + Configurable> dcaXY{"dcaXY", std::vector{0.3f, 0.0f, 0.0f}, "abs dcaXY value limit; formula: [0] + [1]*pT^[2]"}; + Configurable> dcaZ{"dcaZ", std::vector{0.3f, 0.0f, 0.0f}, "abs dcaZ value limit; formula: [0] + [1]*pT^[2]"}; + Configurable minTpcNClsFound{"minTpcNClsFound", 0, "minimum allowed number of TPC clasters"}; + Configurable tpcChi2NCl{"tpcChi2NCl", 100.0, "upper limit for chi2 value of a fit over TPC clasters"}; + Configurable tpcCrossedRowsOverFindableCls{"tpcCrossedRowsOverFindableCls", 0, "lower limit of TPC CrossedRows/FindableCls value"}; + Configurable maxTpcFractionSharedCls{"maxTpcFractionSharedCls", 0.4, "maximum fraction of TPC shared clasters"}; + Configurable minItsNCls{"minItsNCls", 0, "minimum allowed number of ITS clasters for a track"}; + Configurable itsChi2NCl{"itsChi2NCl", 100.0, "upper limit for chi2 value of a fit over ITS clasters for a track"}; + Configurable particlePDG{"particlePDG", o2::constants::physics::Pdg::kTriton, "PDG code of a particle to perform PID for"}; + Configurable> tpcNSigma{"tpcNSigma", std::vector{-4.0f, 4.0f}, "Nsigma range in TPC before the TOF is used"}; + Configurable> itsNSigma{"itsNSigma", std::vector{-10.0f, 10.0f}, "Nsigma range in ITS to use along with TPC"}; + Configurable pidTrshld{"pidTrshld", 0.0, "value of momentum from which the PID is done with TOF (before that only TPC is used)"}; + Configurable massCuttrshld{"massCuttrshld", 0.0, "value of momentum from which the mass cut is done with TOF"}; + Configurable> itsNsigNL{"itsNsigNL", std::vector{-100.0f, 100.0f}, "Nsigma p-dependent cut in ITS ; formula: [0] + [1]*pT"}; + + Configurable> tofNSigma{"tofNSigma", std::vector{-4.0f, 4.0f}, "Nsigma range in TOF"}; + Configurable> tpcNSigmaResidual{"tpcNSigmaResidual", std::vector{-5.0f, 5.0f}, "residual TPC Nsigma cut to use with the TOF"}; + + Configurable> particlePDGtoReject{"particlePDGtoReject", std::vector{PDG_t::kProton}, "PDG codes of perticles that will be rejected with TPC"}; + Configurable> rejectWithinNsigmaTOF{"rejectWithinNsigmaTOF", std::vector{-0.0f, 0.0f}, "TOF rejection Nsigma range for particles specified with PDG to be rejected"}; + Configurable> rejectWithinNsigmaTPC{"rejectWithinNsigmaTPC", std::vector{-0.0f, 0.0f}, "TPC rejection Nsigma range for particles specified with PDG to be rejected"}; + + Configurable> centCut{"centCut", std::pair{0.f, 100.f}, "[min., max.] centrality range to keep tracks within"}; + + Configurable> dcaBinning{"dcaBinning", std::vector{501, 0.5f, 1}, "setup for variable binning (geometric progression is used): 1st (int) -- N_bins (must be odd, otherwise will be increased by 1); 2nd (float) -- abs value of the edge of axises in histos (-2nd, +2nd); 3d (int) -- desired ratio between w_bin at the edges and at 0;"}; + Configurable> tofMass{"tofMass", std::vector{3.0f, 3.0f}, "TOF Mass bounds"}; + + std::pair> itsCuts; + std::pair> tpcCuts; + std::pair> tofCuts; + + Filter pFilter = o2::aod::singletrackselector::p > minP&& o2::aod::singletrackselector::p < maxP; + Filter etaFilter = nabs(o2::aod::singletrackselector::eta) < eta; + Filter tpcTrkFilter = o2::aod::singletrackselector::tpcNClsFound >= minTpcNClsFound && o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedTpcChi2NCl) < tpcChi2NCl && o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedTpcCrossedRowsOverFindableCls) > tpcCrossedRowsOverFindableCls; + Filter itsTrkFilter = o2::aod::singletrackselector::unPack(o2::aod::singletrackselector::storedItsChi2NCl) < itsChi2NCl; + Filter vertexFilter = nabs(o2::aod::singletrackselector::posZ) < vertexZ; + + struct HistSet { + std::shared_ptr eta; + std::shared_ptr etaToY; + std::shared_ptr y; + std::shared_ptr phi; + std::shared_ptr p; + std::shared_ptr pt; + std::shared_ptr dcaxyToP; + std::shared_ptr dcaxyToPt; + std::shared_ptr dcazToP; + std::shared_ptr dcazToPt; + std::shared_ptr tpcClusters; + std::shared_ptr itsClusters; + std::shared_ptr tpcSignal; + std::shared_ptr tofSignal; + std::shared_ptr massTOF; + std::shared_ptr nsigmaITS; + std::shared_ptr nsigmaTPC; + std::shared_ptr nsigmaTOF; + std::shared_ptr tofOverTPC; + std::shared_ptr innerParamToP; + std::shared_ptr ptGenPtRec; + std::shared_ptr dcaxyDcazToPt; + std::shared_ptr dcaxyToDcaz; + std::shared_ptr origin; + }; + + static inline const std::vector stageDirs = { + "init", + "No_Cuts", + "ITS_Cuts", + "TPC_Cuts", + "TOF_Cuts", + "ITSTPC_Cut", + "PID_Cuts", + "TOFmass_Cut", + "Rejection_Cut", + "TPCLinear_Cut", + }; + + // signDirs[0] = "t" for sign > 0 (triton), signDirs[1] = "at" for sign < 0 (antitriton). + static inline const std::array signDirs = {"t", "at"}; + + std::vector> hSets; + std::vector> hSetsTrue; + + HistSet makeHistSet(HistogramRegistry& reg, const std::string& dir, int pdgForPid = 0) + { + HistSet h; + + h.eta = reg.add((dir + "/eta").c_str(), "#eta;#eta;Entries", kTH1F, {{200, -2.5, 2.5}}); + h.y = reg.add((dir + "/y").c_str(), "y;y;Entries", kTH1F, {{200, -2.5, 2.5}}); + h.etaToY = reg.add((dir + "/eta_to_y").c_str(), "#eta;y;Entries", kTH2F, {{200, -2.5, 2.5}, {200, -2.5, 2.5}}); + h.phi = reg.add((dir + "/phi").c_str(), "#phi;#phi;Entries", kTH1F, {{200, 0., o2::constants::math::TwoPI}}); + h.p = reg.add((dir + "/p").c_str(), "p;p (GeV/#it{c});Entries", kTH1F, {{100, 0., 5.}}); + h.pt = reg.add((dir + "/pt").c_str(), "p_{T};p_{T} (GeV/#it{c});Entries", kTH1F, {{100, 0., 5.}}); + h.dcaxyToP = reg.add((dir + "/dcaxy_to_p").c_str(), "DCA_{xy} vs p;p (GeV/#it{c});DCA_{xy} (cm)", kTH2F, {{100, 0., 5.0}, {501, -0.5, 0.5}}); + h.dcaxyToPt = reg.add((dir + "/dcaxy_to_pt").c_str(), "DCA_{xy} vs p_{T};p_{T} (GeV/#it{c});DCA_{xy} (cm)", kTH2F, {{100, 0., 5.0}, {501, -0.5, 0.5}}); + h.dcazToP = reg.add((dir + "/dcaz_to_p").c_str(), "DCA_{z} vs p;p (GeV/#it{c});DCA_{z} (cm)", kTH2F, {{100, 0., 5.0}, {501, -0.5, 0.5}}); + h.dcazToPt = reg.add((dir + "/dcaz_to_pt").c_str(), "DCA_{z} vs p_{T};p_{T} (GeV/#it{c});DCA_{z} (cm)", kTH2F, {{100, 0., 5.0}, {501, -0.5, 0.5}}); + h.tpcClusters = reg.add((dir + "/TPCClusters").c_str(), "TPC Clusters;N_{TPC clusters};Entries", kTH1F, {{163, -0.5, 162.5}}); + h.itsClusters = reg.add((dir + "/ITSClusters").c_str(), "ITS Clusters;N_{ITS clusters};Entries", kTH1F, {{10, -0.5, 9.5}}); + h.tpcSignal = reg.add((dir + "/TPCSignal").c_str(), "TPC Signal;#it{p}_{inner} (GeV/#it{c});dE/dx in TPC (arbitrary units)", kTH2F, {{200, 0., 5.0}, {1000, 0., 1000.0}}); + h.tofSignal = reg.add((dir + "/TOFSignal").c_str(), "TOF Signal;#it{p} (GeV/#it{c});#beta", kTH2F, {{200, 0., 5.0}, {100, 0., 1.5}}); + h.massTOF = reg.add((dir + "/mTOF").c_str(), "m_{TOF};p_{T} (GeV/#it{c});m_{TOF}(GeV/#it{c}^{2})", kTH2F, {{120, 0., 6.}, {1000, -1.5, 5.0}}); + h.innerParamToP = reg.add((dir + "/ip_to_p").c_str(), ";#it{p} (GeV/#it{c});ip_to_p", kTH2F, {{100, 0., 5.0}, {100, 0.0, 2.0}}); + h.ptGenPtRec = reg.add((dir + "/ptgenptrec").c_str(), ";#it{p_{T, rec}} (GeV/#it{c});#it{p_{T, rec}} - #it{p_{T, gen}}(GeV/#it{c})", kTH2F, {{100, 0., 5.0}, {100, -2.5, 2.5}}); + h.dcaxyDcazToPt = reg.add( + (dir + "/dcaxy_dcaz_to_pt").c_str(), + "DCA_{xy} vs DCA_{z} vs p_{T};DCA_{xy} (cm);DCA_{z} (cm);p_{T} (GeV/#it{c})", + kTH3F, + { + {101, -0.5, 0.5}, // x axis: DCA_xy + {101, -0.5, 0.5}, // y axis: DCA_z + {20, 0., 5.0} // z axis: pT + }); + h.dcaxyToDcaz = reg.add( + (dir + "/dcaxy_to_dcaz").c_str(), + "DCA_{z} vs DCA_{xy};DCA_{xy} (cm);DCA_{z} (cm);Counts", + kTH2F, + { + {501, -0.5, 0.5}, // x axis: DCAxy + {501, -0.5, 0.5} // y axis: DCAz + }); + h.origin = reg.add((dir + "/origin").c_str(), "MC origin;origin (-1: unmatched, 0: primary, 1: weak decay, 2: material);Entries", kTH1F, {{4, -1.5, 2.5}}); + + if (pdgForPid != 0) { + h.tofOverTPC = reg.add((dir + Form("/TOFoverTPC_PDG%i", pdgForPid)).c_str(), "n#sigma_{TOF};n#sigma_{TPC};", kTH2F, {{100, -10., 10.}, {100, -10., 10.}}); + h.nsigmaITS = reg.add((dir + Form("/nsigmaITS_PDG%i", pdgForPid)).c_str(), Form("n#sigma_{ITS};p (GeV/#it{c});n#sigma_{ITS}"), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + h.nsigmaTPC = reg.add((dir + Form("/nsigmaTPC_PDG%i", pdgForPid)).c_str(), Form("n#sigma_{TPC};p (GeV/#it{c});n#sigma_{TPC}"), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + h.nsigmaTOF = reg.add((dir + Form("/nsigmaTOF_PDG%i", pdgForPid)).c_str(), Form("n#sigma_{TOF};p (GeV/#it{c});n#sigma_{TOF}"), kTH2F, {{100, 0., 5.}, {100, -10., 10.}}); + } + + return h; + } + + template + static float getMassTOF(const TrackType& track) + { + const float beta = track.beta(); + if (beta <= 0.f || beta >= 1.f) { + return -1.f; + } + return track.p() * std::sqrt(1.f / (beta * beta) - 1.f); + } + + template + void fillHistSet(HistSet& h, const TrackType& track, int pdg) + { + const auto rapidity = track.rapidity(particleMass); + h.eta->Fill(track.eta()); + h.etaToY->Fill(track.eta(), rapidity); + h.y->Fill(rapidity); + h.phi->Fill(track.phi()); + h.p->Fill(track.p()); + h.pt->Fill(track.pt()); + h.dcaxyToP->Fill(track.p(), track.dcaXY()); + h.dcaxyToPt->Fill(track.pt(), track.dcaXY()); + h.dcazToP->Fill(track.p(), track.dcaZ()); + h.dcazToPt->Fill(track.pt(), track.dcaZ()); + h.dcaxyDcazToPt->Fill(track.dcaXY(), track.dcaZ(), track.pt()); + h.dcaxyToDcaz->Fill(track.dcaXY(), track.dcaZ()); + h.tpcClusters->Fill(track.tpcNClsFound()); + h.itsClusters->Fill(track.itsNCls()); + h.nsigmaITS->Fill(track.p(), o2::aod::singletrackselector::getITSNsigma(track, pdg)); + h.nsigmaTPC->Fill(track.p(), o2::aod::singletrackselector::getTPCNsigma(track, pdg)); + h.nsigmaTOF->Fill(track.p(), o2::aod::singletrackselector::getTOFNsigma(track, pdg)); + h.tofOverTPC->Fill(o2::aod::singletrackselector::getTPCNsigma(track, pdg), o2::aod::singletrackselector::getTOFNsigma(track, pdg)); + } + + template + void fillHistSetExtra(HistSet& h, const TrackType& track) + { + h.tpcSignal->Fill(track.tpcInnerParam(), track.tpcSignal()); + h.tofSignal->Fill(track.p(), track.beta()); + h.massTOF->Fill(track.pt(), getMassTOF(track)); + h.innerParamToP->Fill(track.p(), track.tpcInnerParam() / track.p()); + if constexpr (HasMC) { + h.ptGenPtRec->Fill(track.pt(), track.pt() - track.pt_MC()); + } + } + + template + void fillSet(HistSet& set, HistSet& mcSet, const TrackType& track, int pdg) + { + fillHistSet(set, track, pdg); + if constexpr (FillExtra) { + fillHistSetExtra(set, track); + } + + if constexpr (HasMC) { + if ((std::abs(track.pdgCode()) == pdg) && (track.pdgCode() / std::abs(track.pdgCode()) == track.sign())) { + mcSet.origin->Fill(track.origin()); + fillHistSet(mcSet, track, pdg); + if constexpr (FillExtra) { + fillHistSetExtra(mcSet, track); + } + } + } + } + + void init(o2::framework::InitContext&) + { + + if (isMC.value) { + o2::aod::ITSResponse::setMCDefaultParameters(); // set MC parametrisation for the ITS PID + } + + particleMass = static_cast(pdgDB->Mass(particlePDG.value)); + + itsCuts = std::make_pair(particlePDG.value, itsNSigma); + tpcCuts = std::make_pair(particlePDG.value, tpcNSigma); + tofCuts = std::make_pair(particlePDG.value, tofNSigma); + + int nBins = static_cast(dcaBinning.value[0]); // number of bins -- must be odd otherwise will be increased by 1 + if ((nBins & 1) == 0) { // bin count must be odd + nBins += 1; + } + + auto dcaBins = (static_cast(dcaBinning.value[2]) != 1.0) + ? calc_var_bins(nBins + 1, dcaBinning.value[1], static_cast(dcaBinning.value[2])) + : calc_const_bins(nBins, -dcaBinning.value[1], dcaBinning.value[1]); + auto constBinsP = calc_const_bins(100, 0., 5.0); + + hSets.resize(stageDirs.size()); + hSetsTrue.resize(stageDirs.size()); + for (size_t i = 0; i < stageDirs.size(); i++) { + for (size_t s = 0; s < signDirs.size(); s++) { + const std::string dir = stageDirs[i] + "/" + signDirs[s]; + hSets[i][s] = makeHistSet(registry, dir, particlePDG.value); + hSetsTrue[i][s] = makeHistSet(registryTrue, dir + "/true", particlePDG.value); + } + } + + const AxisSpec axisMult{5001, -0.5, 5000.5, "mult."}; + const AxisSpec axisPerc{101, -0.5, 100.5, "percentile"}; + registry.add("posZ", "posZ", kTH1F, {{300, -16., 16., "posZ"}}); + registry.add("mult", "mult", kTH1F, {axisMult}); + registry.add("MultVsCent", "MultVsCent", kTH2F, {axisMult, axisPerc}); + registry.add("IRvsOccupancy", "IRvsOccupancy", kTH2I, {{10000, 0, 10000, "Occupancy"}, {50, 0, 50, "IR, kHz"}}); + } + + template + void fillHistograms(ColsType const& collisions, TracksType const& tracks) + { + for (const auto& track : tracks) { + const int signIdx = (-track.sign() + 1) / 2; // 0: triton, 1: antitriton + fillSet(hSets[1][signIdx], hSetsTrue[1][signIdx], track, particlePDG.value); // nocuts + } + for (const auto& collision : collisions) { + if (removeSameBunchPileup && !collision.isNoSameBunchPileup()) { + continue; + } + if (requestGoodZvtxFT0vsPV && !collision.isGoodZvtxFT0vsPV()) { + continue; + } + if (requestVertexITSTPC && !collision.isVertexITSTPC()) { + continue; + } + if (requestVertexTOFmatched > collision.isVertexTOForTRDmatched()) { + continue; + } + if (requestNoCollInTimeRangeStandard && !collision.noCollInTimeRangeStandard()) { + continue; + } + if (requestIsGoodITSLayersAll && !collision.isGoodITSLayersAll()) { + continue; + } + if (collision.multPerc() < centCut.value.first || collision.multPerc() >= centCut.value.second) { + continue; + } + if (collision.hadronicRate() < irCut.value.first || collision.hadronicRate() >= irCut.value.second) { + continue; + } + if (collision.occupancy() < occupancyCut.value.first || collision.occupancy() >= occupancyCut.value.second) { + continue; + } + + registry.fill(HIST("posZ"), collision.posZ()); + registry.fill(HIST("mult"), collision.mult()); + registry.fill(HIST("MultVsCent"), collision.mult(), collision.multPerc()); + registry.fill(HIST("IRvsOccupancy"), collision.occupancy(), collision.hadronicRate()); + } + + for (const auto& track : tracks) { + const auto& coll = track.template singleCollSel_as(); + const int signIdx = (-track.sign() + 1) / 2; // 0: triton, 1: antitriton + + if (removeSameBunchPileup && !coll.isNoSameBunchPileup()) { + continue; + } + if (requestGoodZvtxFT0vsPV && !coll.isGoodZvtxFT0vsPV()) { + continue; + } + if (requestVertexITSTPC && !coll.isVertexITSTPC()) { + continue; + } + if (requestVertexTOFmatched > coll.isVertexTOForTRDmatched()) { + continue; + } + if (requestNoCollInTimeRangeStandard && !coll.noCollInTimeRangeStandard()) { + continue; + } + if (requestIsGoodITSLayersAll && !coll.isGoodITSLayersAll()) { + continue; + } + if (std::fabs(coll.posZ()) > vertexZ) { + continue; + } + if (coll.multPerc() < centCut.value.first || coll.multPerc() >= centCut.value.second) { + continue; + } + if (coll.hadronicRate() < irCut.value.first || coll.hadronicRate() >= irCut.value.second) { + continue; + } + if (coll.occupancy() < occupancyCut.value.first || coll.occupancy() >= occupancyCut.value.second) { + continue; + } + if (track.tpcFractionSharedCls() > maxTpcFractionSharedCls) { + continue; + } + if (track.itsNCls() < minItsNCls) { + continue; + } + if (std::fabs(track.dcaXY()) > dcaXY.value[0] + dcaXY.value[1] * std::pow(track.pt(), dcaXY.value[2])) { + continue; + } + if (std::fabs(track.dcaZ()) > dcaZ.value[0] + dcaZ.value[1] * std::pow(track.pt(), dcaZ.value[2])) { + continue; + } + + if (o2::aod::singletrackselector::ITSselection(track, itsCuts)) { + fillSet(hSets[2][signIdx], hSetsTrue[2][signIdx], track, particlePDG.value); // ITSCuts + } + if (o2::aod::singletrackselector::TPCselection(track, tpcCuts, itsNSigma.value)) { + fillSet(hSets[3][signIdx], hSetsTrue[3][signIdx], track, particlePDG.value); // TPCCuts + } + if (o2::aod::singletrackselector::TOFselection(track, tofCuts, tpcNSigmaResidual.value)) { + fillSet(hSets[4][signIdx], hSetsTrue[4][signIdx], track, particlePDG.value); // TOFCuts + } + if (o2::aod::singletrackselector::TPCselection(track, tpcCuts, itsNSigma.value)) { + fillSet(hSets[5][signIdx], hSetsTrue[5][signIdx], track, particlePDG.value); // ITSTPC + } + + const bool pidOk = + (track.p() < pidTrshld) + ? o2::aod::singletrackselector::TPCselection(track, tpcCuts, itsNSigma.value) + : o2::aod::singletrackselector::TPCselection(track, std::make_pair(particlePDG.value, tpcNSigmaResidual.value), tpcNSigmaResidual.value); + if (!pidOk) { + continue; + } + if (std::fabs(track.rapidity(particleMass)) > y) { + continue; + } + + fillSet(hSets[6][signIdx], hSetsTrue[6][signIdx], track, particlePDG.value); // PIDcuts + if constexpr (FillExtra) { + if (track.p() >= massCuttrshld && (getMassTOF(track) <= tofMass.value[0] || getMassTOF(track) >= tofMass.value[1])) { + continue; + } + } + fillSet(hSets[7][signIdx], hSetsTrue[7][signIdx], track, particlePDG.value); // masscut + + bool rejectedByPDG = false; + for (const int& pdgToReject : particlePDGtoReject.value) { + if (o2::aod::singletrackselector::TPCselection(track, std::make_pair(pdgToReject, rejectWithinNsigmaTPC.value))) { + rejectedByPDG = true; + break; + } + } + if (rejectedByPDG) { + continue; + } + fillSet(hSets[8][signIdx], hSetsTrue[8][signIdx], track, particlePDG.value); // rd + + if (getITSNsigma(track, particlePDG.value) <= itsNsigNL.value[0] + itsNsigNL.value[1] * track.p()) { + continue; + } + fillSet(hSets[9][signIdx], hSetsTrue[9][signIdx], track, particlePDG.value); // nl + } + } + + void processDefault(soa::Filtered> const& collisions, soa::Filtered> const& tracks) + { + fillHistograms(collisions, tracks); + } + PROCESS_SWITCH(AntitritonAnalysis, processDefault, "process default", true); + + void processExtra(soa::Filtered> const& collisions, soa::Filtered> const& tracks) + { + fillHistograms(collisions, tracks); + } + PROCESS_SWITCH(AntitritonAnalysis, processExtra, "process extra", false); + + void processMC(soa::Filtered> const& collisions, soa::Filtered> const& tracks) + { + fillHistograms(collisions, tracks); + } + PROCESS_SWITCH(AntitritonAnalysis, processMC, "process MC", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} From 1da3606f3eefd7e6f6c017ce6ddcb4c63ce66c41 Mon Sep 17 00:00:00 2001 From: Giorgio Alberto Lucia <87222843+GiorgioAlbertoLucia@users.noreply.github.com> Date: Wed, 29 Jul 2026 16:44:12 +0200 Subject: [PATCH 35/71] [PWGLF] fixed typo in histogram names (#17250) --- PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx b/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx index 9c6f3726235..ec84cb4c179 100644 --- a/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx +++ b/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx @@ -370,8 +370,8 @@ struct he3HadronFemto { {"hNcontributor", "Number of primary vertex contributor", {HistType::kTH1F, {{2000, 0.0f, 2000.0f}}}}, {"hTrackSel", "Accepted tracks", {HistType::kTH1F, {{Selections::kAll, -0.5, static_cast(Selections::kAll) - 0.5}}}}, {"hEmptyPool", "svPoolCreator did not find track pairs false/true", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, - {"hhe3HadtInvMass", "; M(^{3}He + p) (GeV/#it{c}^{2})", {HistType::kTH1F, {{300, 3.74f, 4.34f}}}}, - {"hhe3HadtKstar", "; #it{k}* (GeV/#it{c})", {HistType::kTH1F, {{300, 0.f, 0.8f}}}}, + {"hhe3HadInvMass", "; M(^{3}He + p) (GeV/#it{c}^{2})", {HistType::kTH1F, {{300, 3.74f, 4.34f}}}}, + {"hhe3HadKstar", "; #it{k}* (GeV/#it{c})", {HistType::kTH1F, {{300, 0.f, 0.8f}}}}, {"hKstarRecVsKstarGen", "; #it{k}*_{gen} (GeV/#it{c}); #it{k}*_{rec} (GeV/#it{c})", {HistType::kTH2F, {{400, 0.f, 0.8f}, {400, 0.f, 0.8f}}}}, {"He3/hDCAxyHe3", "^{3}He;DCA_{xy} (cm)", {HistType::kTH1F, {{200, -0.5f, 0.5f}}}}, @@ -1014,7 +1014,7 @@ struct he3HadronFemto { { mQaRegistry.fill(HIST("He3/hHe3Pt"), he3Hadcand.recoPtHe3()); mQaRegistry.fill(HIST("Had/hHadronPt"), he3Hadcand.recoPtHad()); - mQaRegistry.fill(HIST("hhe3HadtInvMass"), he3Hadcand.invMass); + mQaRegistry.fill(HIST("hhe3HadInvMass"), he3Hadcand.invMass); mQaRegistry.fill(HIST("hhe3HadKstar"), he3Hadcand.recoKstar()); mQaRegistry.fill(HIST("He3/hDCAxyHe3"), he3Hadcand.dcaxyHe3); mQaRegistry.fill(HIST("He3/hDCAzHe3"), he3Hadcand.dcazHe3); From 9df1729663f3425792db0d31bc4a50434a651576 Mon Sep 17 00:00:00 2001 From: Chiara De Martin <39315597+ChiaraDeMartin95@users.noreply.github.com> Date: Wed, 29 Jul 2026 17:29:05 +0200 Subject: [PATCH 36/71] [PWGLF] Fix selection based on ctau of cascades (#17249) Co-authored-by: Chiara De Martin --- PWGLF/Tasks/QC/v0cascadesqa.cxx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/PWGLF/Tasks/QC/v0cascadesqa.cxx b/PWGLF/Tasks/QC/v0cascadesqa.cxx index ba6ddd38f84..99c7d37699c 100644 --- a/PWGLF/Tasks/QC/v0cascadesqa.cxx +++ b/PWGLF/Tasks/QC/v0cascadesqa.cxx @@ -126,6 +126,8 @@ struct v0cascadesQA { RCTFlagsChecker rctFlagsChecker{rctConfigurations.cfgRCTLabel.value}; static constexpr float DefaultLifetimeCuts[1][2] = {{30., 20.}}; + const float ctauxiPDG = 4.91; // from PDG + const float ctauomegaPDG = 2.461; // from PDG struct : ConfigurableGroup { std::string prefix = "v0Selections"; // JSON group name @@ -205,7 +207,7 @@ struct v0cascadesQA { Configurable dcabachtopv{"dcabachtopv", .05, "min DCA Bachelor To PV (cm)"}; Configurable cascradius{"cascradius", 0.5, "minimum Cascade radius (cm)"}; Configurable cascradiusMax{"cascradiusMax", 1E5, "maximum Cascade radius (cm)"}; - Configurable cascProperLifeTime{"cascProperLifeTime", 3, "maximum lifetime (ctau)"}; + Configurable cascProperLifeTime{"cascProperLifeTime", 3, "maximum lifetime (meanctau)"}; // invariant mass selection Configurable v0MassWindow{"v0MassWindow", 0.008, "#Lambda mass (GeV/#it{c}^{2})"}; @@ -877,9 +879,9 @@ struct v0cascadesQA { // // proper lifetime float distOverTotMom = std::sqrt(std::pow(casc.x() - collision.posX(), 2) + std::pow(casc.y() - collision.posY(), 2) + std::pow(casc.z() - collision.posZ(), 2)) / (casc.p() + 1E-10); - if ((cascType == kXiM || cascType == kXiP) && distOverTotMom * o2::constants::physics::MassXiMinus > cascSelections.cascProperLifeTime) + if ((cascType == kXiM || cascType == kXiP) && distOverTotMom * o2::constants::physics::MassXiMinus > (cascSelections.cascProperLifeTime * ctauxiPDG)) return false; - if ((cascType == kOmegaM || cascType == kOmegaP) && distOverTotMom * o2::constants::physics::MassOmegaMinus > cascSelections.cascProperLifeTime) + if ((cascType == kOmegaM || cascType == kOmegaP) && distOverTotMom * o2::constants::physics::MassOmegaMinus > (cascSelections.cascProperLifeTime * ctauomegaPDG)) return false; // rapidity From 6b23fc4a8d457fb2c7aa033db737055458f4fc24 Mon Sep 17 00:00:00 2001 From: Stefanie Mrozinski <63045530+Steffimro@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:07:58 +0200 Subject: [PATCH 37/71] [PWGEM] remove eta Cut + add new track distance cut (#17251) Co-authored-by: Stefanie Mrozinski --- PWGEM/PhotonMeson/Tasks/photonhbt.cxx | 796 ++++++++++++++++++++------ 1 file changed, 623 insertions(+), 173 deletions(-) diff --git a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx index f4ede2de706..f2fc28a8721 100644 --- a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx +++ b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include // IWYU pragma: keep #include #include +#include #include #include @@ -100,21 +102,100 @@ static constexpr float kMinMagnitude = 1e-12f; static constexpr float kMinCosine = 1e-12f; static constexpr float kMinSigma = 1e-9f; -static constexpr std::array kPhiStarRadiiM = {0.85f, 1.05f, 1.25f, 1.45f, 1.65f, - 1.85f, 2.05f, 2.25f, 2.45f}; +static constexpr std::array kPhiStarRadiiM = { + 0.85f, 0.95f, 1.05f, 1.15f, 1.25f, 1.35f, 1.45f, 1.55f, 1.65f, + 1.75f, 1.85f, 1.95f, 2.05f, 2.15f, 2.25f, 2.35f, 2.45f}; static constexpr float kPhiStarInvalid = -999.f; static constexpr float kCmPerM = 100.f; -[[nodiscard]] static float legPhiStar(float phi, float pt, int charge, float bzT, float radiusM) +struct LegHelix { + float phiStar = kPhiStarInvalid; // azimuth of the track at that radius + float sxy = -1.f; + int status = 3; // 0 ok, 1 below R_conv, 2 out of reach,3 bad input +}; + +[[nodiscard]] static LegHelix legHelixAt(float vxM, float vyM, float phiMom, float pt, int charge, float bzT, float radiusM) { - if (pt < kMinSigma) { - return kPhiStarInvalid; - } - const float arg = -0.3f * bzT * static_cast(charge) * radiusM / (2.f * pt); - if (std::fabs(arg) >= 1.f) { - return kPhiStarInvalid; // leg curls up before + LegHelix out; + if (pt < kMinSigma || std::fabs(bzT) < kMinSigma) { + out.status = 3; // o2-linter: disable=magic-number (status code) + return out; + } + const float rStart = std::hypot(vxM, vyM); + if (rStart < kMinSigma) { + out.status = 3; // o2-linter: disable=magic-number (status code) + return out; + } + if (radiusM < rStart) { + out.status = 1; + return out; + } + const float rho = pt / (0.3f * std::fabs(bzT)); // curvature radius, m + const float sgn = (bzT >= 0.f ? 1.f : -1.f) * static_cast(charge); + const float cx = vxM + sgn * rho * std::sin(phiMom); + const float cy = vyM - sgn * rho * std::cos(phiMom); + const float d = std::hypot(cx, cy); + if (d < kMinSigma) { + out.status = 3; // o2-linter: disable=magic-number (status code) + return out; + } + if (radiusM > d + rho || radiusM < std::fabs(d - rho)) { + out.status = 2; // o2-linter: disable=magic-number (status code) + return out; + } + const float phiC = std::atan2(cy, cx); + auto clamp1 = [](float x) { return std::max(-1.f, std::min(1.f, x)); }; + auto alphaAt = [&](float r) { return std::acos(clamp1((r * r + d * d - rho * rho) / (2.f * r * d))); }; + auto betaAt = [&](float r) { return std::acos(clamp1((d * d + rho * rho - r * r) / (2.f * d * rho))); }; + + const float phiVtx = std::atan2(vyM, vxM); + const float a0 = alphaAt(rStart); + const float resPlus = std::fabs(RecoDecay::constrainAngle(phiC + a0 - phiVtx, -o2::constants::math::PI)); + const float resMinus = std::fabs(RecoDecay::constrainAngle(phiC - a0 - phiVtx, -o2::constants::math::PI)); + const float branch = (resPlus < resMinus) ? 1.f : -1.f; + + out.phiStar = RecoDecay::constrainAngle(phiC + branch * alphaAt(radiusM), 0.f); + out.sxy = rho * std::fabs(betaAt(radiusM) - betaAt(rStart)); + out.status = 0; + return out; +} + +[[nodiscard]] inline float selfTestLegHelix() +{ + float worst = 0.f; + constexpr float eps = 1.e-5f; + + for (const auto& bz : {0.5f, -0.5f}) { + for (const auto& q : {+1, -1}) { + for (const auto& pt : {0.1f, 0.2f, 0.5f}) { + for (const auto& r : {0.85f, 1.45f, 2.45f}) { + for (const auto& phi : {0.f, 1.f, -2.f}) { + const auto h = legHelixAt(eps * std::cos(phi), eps * std::sin(phi), phi, pt, q, bz, r); + + if (h.status != 0) { + continue; + } + const float arg = + -0.3f * bz * static_cast(q) * r / (2.f * pt); + + if (std::fabs(arg) >= 1.f) { + continue; + } + const float referencePhi = + RecoDecay::constrainAngle(phi + std::asin(arg), 0.f); + + worst = std::max( + worst, + std::fabs(RecoDecay::constrainAngle( + h.phiStar - referencePhi, + -o2::constants::math::PI))); + } + } + } + } } - return RecoDecay::constrainAngle(phi + std::asin(arg), 0.f); + + return worst; } struct Photonhbt { @@ -147,11 +228,40 @@ struct Photonhbt { }; struct PairSep { - float dEtaPP{0}, dPhiPP{0}, dEtaNN{0}, dPhiNN{0}; - float u{999.f}; + float dMin3D{999.f}, dRPhiAtMin3D{999.f}, dZAtMin3D{999.f}; + float dMinRPhi{999.f}, dZAtMinRPhi{999.f}; + std::array fCloseRPhiThr{}; + std::array nCloseRPhiThr{}; + float fCloseRPhi{0.f}; // == fCloseRPhiThr[3] + int nCommon{0}; + int nSameSide{0}; // usable radii on the SAME TPC side + int criticalCharge{-1}; // 0 = e+e+, 1 = e-e-, chosen by d_3D + int rphiCharge{-1}; // chosen by d_rphi alone + std::array dMin3DPerCharge{999.f, 999.f}; + std::array fCloseRPhiPerCharge{0.f, 0.f}; + std::array dMinRPhiPerCharge{999.f, 999.f}; + std::array nSameSidePerCharge{}; + std::array, 2> nCloseRPhiThrPerCharge{}; + std::array, 2> fCloseRPhiThrPerCharge{}; + float dMinRPhiAll{999.f}, dPairMinAll{999.f}; + float dPairMin{999.f}; + float dRPhiAtDPairMin{999.f}, dZAtDPairMin{999.f}; + float rAtDPairMin{-1.f}, absZAtDPairMin{-1.f}, driftLen{-1.f}; + int nCloseScaled{0}; + std::array dPairMinPerCharge{999.f, 999.f}; + float dZGlobalAtDPairMin{999.f}; + float dZSignedLocalAtDPairMin{999.f}, dZSignedGlobalAtDPairMin{999.f}; + float dVtxZ{0.f}; + float fCloseScaled{0.f}; + float driftOldAtDPairMin{-1.f}; // kept only to show the difference + bool sameSideAtDPairMin{true}; + int nLegsITSTPC{0}; + std::array nPoints{}; + std::array, 2> ptDRPhi{}, ptDZ{}, ptDZSgnLocal{}, ptR{}, ptDrift{}, ptSameSide{}; }; struct CrossObs { + // m(e+e-) of the two leg-swapped combinations std::array mee{999.f, 999.f}; float meeOverQ{999.f}; }; @@ -170,8 +280,10 @@ struct Photonhbt { struct PhotonWithLegs { float fPt{0}, fEta{0}, fPhi{0}; float fVx{0}, fVy{0}, fVz{0}; + float fVtxZ{0}; std::array fLegPt{}, fLegEta{}, fLegPhi{}; std::array, 2> fLegPhiStar{}; + std::array, 2> fLegSxy{}; // transverse arc length since conversion (m) [[nodiscard]] float pt() const { return fPt; } [[nodiscard]] float eta() const { return fEta; } [[nodiscard]] float phi() const { return fPhi; } @@ -181,6 +293,7 @@ struct Photonhbt { [[nodiscard]] float legEta(int i) const { return fLegEta[i]; } [[nodiscard]] float legPhi(int i) const { return fLegPhi[i]; } [[nodiscard]] float legPt(int i) const { return fLegPt[i]; } + int fNITSTPC{0}; pairutil::V0PhotonLegCounts fLegCounts{}; [[nodiscard]] pairutil::V0PhotonLegCounts const& legCounts() const { return fLegCounts; } }; @@ -213,7 +326,8 @@ struct Photonhbt { Service ccdb{}; Configurable cfgCcdbUrl{"cfgCcdbUrl", "http://alice-ccdb.cern.ch", "CCDB url"}; Configurable cfgBzOverrideT{"cfgBzOverrideT", -999.f, "Bz in Tesla; used instead of CCDB if > -100"}; - float mBzT{0.f}; // signed, Tesla + float mBzT{0.f}; // signed, Tesla + float mVDriftCmPerNs{0.f}; // TPC drift velocity from CCDB; 0 = unavailable // ─── Configurables: QA flags ─────────────────────────────────────────────── struct : ConfigurableGroup { @@ -227,6 +341,8 @@ struct Photonhbt { Configurable cfgQaLevel{"cfgQaLevel", 2, "QA: 0 no QA, 1 standard, 2 full diagnostics with leg information etc."}; Configurable cfgFillDRDZSparse{"cfgFillDRDZSparse", true, "book/fill the FullRange |R1-R2|-Deltaz-qinv sparse (large; needs cfgQaLevel>=2)"}; Configurable cfgMaxQinvForProcessing{"cfgMaxQinvForProcessing", 0.5, "skip mixed pairs with q_inv above this before building observables"}; + Configurable cfgFillLegPairSparses{"cfgFillLegPairSparses", false, "book/fill the 4D leg-pair QA sparses (very large)"}; + Configurable cfgFillR1R2Sparse{"cfgFillR1R2Sparse", true, "book/fill the FullRange (R1, R2, q_inv) sparse: fix one conversion radius, see where the partner sits, per q_inv"}; } qaflags; // ─── HBT analysis mode ─────────────────────────────────────────────────────────── @@ -239,8 +355,7 @@ struct Photonhbt { // ----- Photon Leg Classification - Configurable cfgDoPhotonClassPairCut{"cfgDoPhotonClassPairCut", false, - "apply photon-class pair selection A x B (leg track composition)"}; + Configurable cfgDoPhotonClassPairCut{"cfgDoPhotonClassPairCut", false, "apply photon-class pair selection A x B (leg track composition)"}; struct : ConfigurableGroup { std::string prefix = "photonclassA_group"; @@ -338,12 +453,22 @@ struct Photonhbt { struct : ConfigurableGroup { std::string prefix = "pairsep_group"; Configurable cfgDoPairSepQA{"cfgDoPairSepQA", true, "fill SE/ME same-sign leg separation histograms"}; - Configurable cfgUSigEta{"cfgUSigEta", 0.02f, "eta scale defining u (axis units only, NOT a cut)"}; - Configurable cfgUSigPhi{"cfgUSigPhi", 0.02f, "phi(*) scale defining u (axis units only, NOT a cut)"}; Configurable cfgPairSepMaxQinv{"cfgPairSepMaxQinv", 0.5f, "fill PairSep histograms only for qinv < this value (<=0: no gate)"}; - Configurable cfgUsePhiStar{"cfgUsePhiStar", true, "compute u from phi* at TPC radii instead of vertex phi"}; - Configurable cfgDoLegSepCut{"cfgDoLegSepCut", false, "apply symmetric leg-separation cut u > cfgUCut to SE and ME"}; - Configurable cfgUCut{"cfgUCut", 0.f, "min u (sigma units); pairs with u < cut rejected in SE AND ME"}; + Configurable cfgSigRPhi{"cfgSigRPhi", 1.f, "rphi scale of the pair-merging metric (cm)"}; + Configurable cfgSigZ{"cfgSigZ", 1.f, "z scale of the pair-merging metric (cm)"}; + Configurable cfgSigZNs{"cfgSigZNs", -1.f, "z scale in ns of drift time; <=0 keeps cfgSigZ in cm"}; + Configurable cfgDPairClose{"cfgDPairClose", 1.f, "a sampled radius counts as close when D_pair < this"}; + Configurable> cfgCloseThrCm{"cfgCloseThrCm", {0.5f, 1.0f, 1.5f, 2.0f}, "four d_rphi thresholds (cm) for N_close/f_close"}; + Configurable cfgDoPairMergeCut{"cfgDoPairMergeCut", false, "apply the pair-merging cut to SE AND ME"}; + Configurable cfgDPairCut{"cfgDPairCut", 1.f, "reject pairs with min D_pair below this (needs cfgDoPairMergeCut)"}; + Configurable cfgNCloseCut{"cfgNCloseCut", 0, "reject pairs with at least this many close radii; 0 disables"}; + Configurable cfgTpcHalfLengthCm{"cfgTpcHalfLengthCm", 250.f, "TPC half length, used for drift length = halfLength - |z|"}; + Configurable cfgRegionEdge1{"cfgRegionEdge1", 132.f, "radius (cm) separating region 0 from 1 (approx. IROC / OROC1)"}; + Configurable cfgRegionEdge2{"cfgRegionEdge2", 171.f, "radius (cm) separating region 1 from 2"}; + Configurable cfgRegionEdge3{"cfgRegionEdge3", 208.f, "radius (cm) separating region 2 from 3"}; + Configurable cfgCondQinvMin{"cfgCondQinvMin", 0.10f, "control window for the (d_rphi, d_z) calibration map: min qinv"}; + Configurable cfgCondQinvMax{"cfgCondQinvMax", 0.30f, "control window for the (d_rphi, d_z) calibration map: max qinv"}; + Configurable cfgFillCalibSparse{"cfgFillCalibSparse", true, "fill the per-radius calibration sparse (d_rphi, d_z, region, drift, qinv)"}; } pairsep; struct : ConfigurableGroup { @@ -511,20 +636,44 @@ struct Photonhbt { // INITS /*************************************************/ - bool mDoPairQa{true}, mDoSinglePhotonQa{true}, mDoLegPairQA{true}; - bool mDoPairSepQA{true}, mFillDRDZSparse{true}; + struct QaGates { + bool pairQa{true}; + bool singlePhotonQa{true}; + bool legPairQa{true}; + bool pairSepQa{true}; + bool fillDRDZSparse{true}; + bool fillR1R2Sparse{true}; + bool pairSepAfterCut{true}; + } mQa; void init(InitContext& context) { isMC = context.mOptions.get("processMC"); + + if (pairsep.cfgCloseThrCm.value.size() != 4) { // o2-linter: disable=magic-number (four thresholds) + LOGF(fatal, "cfgCloseThrCm must contain exactly four thresholds, got %zu", + pairsep.cfgCloseThrCm.value.size()); + } + if (pairsep.cfgCloseThrCm.value.front() <= 0.f || + !std::is_sorted(pairsep.cfgCloseThrCm.value.begin(), pairsep.cfgCloseThrCm.value.end())) { + LOGF(fatal, "cfgCloseThrCm must be positive and sorted in ascending order"); + } const int qaLevel = qaflags.cfgQaLevel.value; - mDoPairQa = qaflags.doPairQa.value && qaLevel >= 1; // o2-linter: disable=magic-number (QA set-up) - mDoSinglePhotonQa = qaflags.doSinglePhotonQa.value && qaLevel >= 1; // o2-linter: disable=magic-number (QA set-up) - mDoLegPairQA = qaflags.doLegPairQA.value && qaLevel >= 2; // o2-linter: disable=magic-number (QA set-up) - mDoPairSepQA = pairsep.cfgDoPairSepQA.value && qaLevel >= 2; // o2-linter: disable=magic-number (QA set-up) - mFillDRDZSparse = qaflags.cfgFillDRDZSparse.value && qaLevel >= 2; // o2-linter: disable=magic-number (QA set-up) - LOGF(info, "photonhbt QA level %d -> pairQA %d, singlePhotonQA %d, legPairQA %d, pairSep %d, dRdZ sparse %d", - qaLevel, mDoPairQa, mDoSinglePhotonQa, mDoLegPairQA, mDoPairSepQA, mFillDRDZSparse); + mQa.pairQa = qaflags.doPairQa.value && qaLevel >= 1; // o2-linter: disable=magic-number (QA set-up) + mQa.singlePhotonQa = qaflags.doSinglePhotonQa.value && qaLevel >= 1; // o2-linter: disable=magic-number (QA set-up) + mQa.legPairQa = qaflags.doLegPairQA.value && qaLevel >= 2; // o2-linter: disable=magic-number (QA set-up) + mQa.pairSepQa = pairsep.cfgDoPairSepQA.value && qaLevel >= 2; // o2-linter: disable=magic-number (QA set-up) + mQa.fillDRDZSparse = qaflags.cfgFillDRDZSparse.value && qaLevel >= 2; // o2-linter: disable=magic-number (QA set-up) + mQa.fillR1R2Sparse = qaflags.cfgFillR1R2Sparse.value && qaLevel >= 2; // o2-linter: disable=magic-number (QA set-up) + // an AfterCut copy only differs from Before when a pair cut is active + mQa.pairSepAfterCut = + mQa.pairSepQa && + (ggpaircuts.cfgDoEllipseCut.value || ggpaircuts.cfgDoRCut.value || + ggpaircuts.cfgDoZCut.value || ggpaircuts.cfgMinDRCosOA.value > 0.f || + ggpaircuts.cfgMaxAsymmetry.value >= 0.f || pairsep.cfgDoPairMergeCut.value || + crosspair.cfgDoCrossPairCut.value || cfgDoPhotonClassPairCut.value); + LOGF(info, "photonhbt QA level %d -> pairQA %d, singlePhotonQA %d, legPairQA %d, pairSep %d, dRdZ sparse %d, R1R2 sparse %d, pairSep afterCut %d", + qaLevel, mQa.pairQa, mQa.singlePhotonQa, mQa.legPairQa, mQa.pairSepQa, mQa.fillDRDZSparse, mQa.fillR1R2Sparse, mQa.pairSepAfterCut); mRunNumber = 0; parseBins(mixing.confVtxBins, ztxBinEdges); parseBins(mixing.confCentBins, centBinEdges); @@ -543,6 +692,46 @@ struct Photonhbt { ccdb->setURL(cfgCcdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); + + const float worst = selfTestLegHelix(); + constexpr float kSelfTestTol = 1.e-4f; + if (worst < kSelfTestTol) { + LOGF(info, "photonhbt: leg-helix origin-limit self test PASSED (max |dphi| = %.2e rad)", worst); + } else { + LOGF(fatal, + "photonhbt: leg-helix origin-limit self test FAILED, max |dphi| = %.3e rad. " + "The helix-centre sign convention or the branch choice is wrong; every " + "leg-separation variable would be mirrored. Refusing to run.", + worst); + } + LOGF(info, "photonhbt: leg propagation sampled at %zu radii, %.0f-%.0f cm in %.0f cm steps", + kPhiStarRadiiM.size(), kPhiStarRadiiM.front() * kCmPerM, kPhiStarRadiiM.back() * kCmPerM, + (kPhiStarRadiiM.size() > 1) ? (kPhiStarRadiiM[1] - kPhiStarRadiiM[0]) * kCmPerM : 0.f); + LOGF(info, "photonhbt: PairSep QA %s", pairsep.cfgDoPairSepQA.value ? "on" : "off"); + LOGF(info, "photonhbt r-phi closeness thresholds: %.2f, %.2f, %.2f, %.2f cm", + pairsep.cfgCloseThrCm.value[0], pairsep.cfgCloseThrCm.value[1], + pairsep.cfgCloseThrCm.value[2], pairsep.cfgCloseThrCm.value[3]); + LOGF(info, "photonhbt pair merging: metric sigma_rphi = %.2f cm, sigma_z = %.2f cm (or %.1f ns if > 0), close at D_pair < %.2f", + pairsep.cfgSigRPhi.value, pairsep.cfgSigZ.value, pairsep.cfgSigZNs.value, pairsep.cfgDPairClose.value); + LOGF(info, + "photonhbt pair separation: all merging observables (d_rphi^min, D_pair^min, " + "N_close, f_close) use SAME-SIDE radii only; the pure r-phi quantities are " + "selected by d_rphi, not by d_3D"); + LOGF(info, + "photonhbt pair separation: d_z is vertex-LOCAL (each leg relative to its own primary vertex); " + "drift length uses global z. Check PairSep/mix/hDzLocal_vs_dVtxZ -- it must NOT be diagonal."); + LOGF(info, "photonhbt pair merging cut: %s, D_pair > %.2f, N_close < %d (0 = off); control window %.2f < q_inv < %.2f", + pairsep.cfgDoPairMergeCut.value ? "ON" : "off", pairsep.cfgDPairCut.value, + pairsep.cfgNCloseCut.value, pairsep.cfgCondQinvMin.value, pairsep.cfgCondQinvMax.value); + LOGF(info, "photonhbt: crossed-pair QA %s, cut %s (min(m_ee)/q_inv > %.2f)", + crosspair.cfgDoCrossPairQA.value ? "on" : "off", + crosspair.cfgDoCrossPairCut.value ? "ON" : "off", crosspair.cfgCrossMaxMeeRatio.value); + LOGF(info, "photonhbt: q_inv gates -- QA < %.3f, FullRange < %.3f, PairSep < %.3f", + qaflags.cfgMaxQinvForQA.value, qaflags.cfgMaxQinvForFullRange.value, + pairsep.cfgPairSepMaxQinv.value); + LOGF(info, + "photonhbt: check PairSep/hLegPropStatus after the run -- if 'propagated' is " + "not the dominant bin, the separation variables rest on a minority of legs"); } template @@ -552,6 +741,18 @@ struct Photonhbt { return; } mRunNumber = collision.runNumber(); + + auto vd = ccdb->getForRun("TPC/Calib/VDriftTgl", mRunNumber); + if (vd != nullptr) { + mVDriftCmPerNs = vd->refVDrift * vd->corrFact * 1e-3f; // o2-linter: disable=magic-number (cm/us -> cm/ns) + LOGF(info, "photonhbt: run %d, TPC vdrift = %.6f cm/ns (%.4f cm/us); 1 cm in z = %.0f ns", + mRunNumber, mVDriftCmPerNs, 1e3f * mVDriftCmPerNs, + (mVDriftCmPerNs > 0.f) ? 1.f / mVDriftCmPerNs : -1.f); + } else { + mVDriftCmPerNs = 0.f; + LOGF(warn, "photonhbt: no TPC VDrift object for run %d -- the z scale stays in cm", mRunNumber); + } + if (cfgBzOverrideT.value > -100.f) { // o2-linter: disable=magic-number (number in case B-field is overridden in case not fetched from CCDB) mBzT = cfgBzOverrideT.value; return; @@ -691,7 +892,7 @@ struct Photonhbt { if (isMC) { addPairMCHistograms(); - if (mDoLegPairQA) { + if (mQa.legPairQa) { addLegPairMCHistograms(); } addTruthMCHistograms(); @@ -726,7 +927,7 @@ struct Photonhbt { fRegistryCF.add("Pair/same/hSparse_DEtaDPhi_qinv_kT", "pair (#Delta#eta,#Delta#phi,q_{inv},k_{T}) for efficiency reweighting;" "#Delta#eta;#Delta#phi (rad);q_{inv} (GeV/c);k_{T} (GeV/c)", - kTHnSparseD, {axisDeltaEta, axisDeltaPhi, axisQinv, axisKt}, true); + kTHnSparseF, {axisDeltaEta, axisDeltaPhi, axisQinv, axisKt}, true); fRegistryCF.add("Pair/same/hPhi_lowerPtV0", "azimuthal angle of lower-p_{T} V0 in pair;#phi (rad);counts", kTH1D, {axisPhi}, true); addFullRangeHistograms("Pair/same/FullRange/"); @@ -737,11 +938,93 @@ struct Photonhbt { // ─── CF: PairSep ──────────────────────── void addPairSepHistograms() { - for (const auto& sm : {std::string("PairSep/same/"), std::string("PairSep/mix/"), std::string("PairSep/sameAfterCut/"), std::string("PairSep/mixAfterCut/")}) { - fRegistryCF.add((sm + "hDEtaDPhiKt_PP").c_str(), "e^{+}e^{+};#Delta#eta;#Delta#phi (rad);k_{T} (GeV/c)", kTHnSparseF, {{160, -0.4f, 0.4f}, {160, -0.4f, 0.4f}, axisKt}, true); - fRegistryCF.add((sm + "hDEtaDPhiKt_NN").c_str(), "e^{-}e^{-};#Delta#eta;#Delta#phi (rad);k_{T} (GeV/c)", kTHnSparseF, {{160, -0.4f, 0.4f}, {160, -0.4f, 0.4f}, axisKt}, true); - fRegistryCF.add((sm + "hU_Qinv_Kt").c_str(), ";u;q_{inv} (GeV/c);k_{T} (GeV/c)", kTHnSparseF, {{100, 0.f, 10.f}, {50, 0.f, 0.5f}, axisKt}, true); - fRegistryCF.add((sm + "hU_Qinv_dE").c_str(), ";u;q_{inv} (GeV/c);#DeltaE (GeV)", kTHnSparseF, {{100, 0.f, 10.f}, {50, 0.f, 0.5f}, {40, 0.f, 2.f}}, true); + + auto hs = fRegistryCF.add("PairSep/hLegPropStatus", "leg propagation;;legs", kTH1D, {{4, -0.5f, 3.5f}}, true); + hs->GetXaxis()->SetBinLabel(1, "propagated"); + hs->GetXaxis()->SetBinLabel(2, "below R_{conv}"); + hs->GetXaxis()->SetBinLabel(3, "out of reach"); + hs->GetXaxis()->SetBinLabel(4, "bad input"); + // low-pT legs curl up early, so N_valid differs between pairs + fRegistryCF.add("PairSep/hPropStatus_vs_LegPt", "propagation vs leg p_{T};status;p_{T}^{leg} (GeV/c)", + kTH2F, {{4, -0.5f, 3.5f}, {40, 0.f, 2.f}}, true); + fRegistryCF.add("PairSep/hPropStatus_vs_Rconv", "propagation vs conversion radius;status;R_{conv} (cm)", + kTH2F, {{4, -0.5f, 3.5f}, {50, 0.f, 100.f}}, true); + + const AxisSpec axisQcal4{{0.00, 0.01, 0.02, 0.04, 0.06, 0.10, 0.15, 0.20, 0.30, 0.50}}; + + // variable width: fine below 10 cm, coarse above + std::vector sepEdges; + for (int i = 0; i <= 20; ++i) { // o2-linter: disable=magic-number (axis definition) + sepEdges.push_back(0.25 * i); // 0 .. 5 cm in 0.25 cm + } + for (int i = 1; i <= 10; ++i) { // o2-linter: disable=magic-number (axis definition) + sepEdges.push_back(5.0 + 0.5 * i); // 5 .. 10 cm in 0.5 cm + } + for (int i = 1; i <= 10; ++i) { // o2-linter: disable=magic-number (axis definition) + sepEdges.push_back(10.0 + 1.0 * i); // 10 .. 20 cm in 1 cm + } + for (int i = 1; i <= 6; ++i) { // o2-linter: disable=magic-number (axis definition) + sepEdges.push_back(20.0 + 5.0 * i); // 20 .. 50 cm in 5 cm + } + const AxisSpec axisSep{sepEdges}; + + std::vector dirs = {"PairSep/same/", "PairSep/mix/"}; + if (mQa.pairSepAfterCut) { + dirs.push_back("PairSep/sameAfterCut/"); + dirs.push_back("PairSep/mixAfterCut/"); + } + + for (const auto& sm : dirs) { + fRegistryCF.add((sm + "hSparse_dRPhiAtMin3D_dZAtMin3D_Qinv").c_str(), "components at the closest 3D approach;d_{r#varphi} @ d^{min}_{3D} (cm);d_{z} @ d^{min}_{3D} (cm);q_{inv} (GeV/c)", + kTHnSparseF, {axisSep, axisSep, {50, 0.f, 0.5f}}, true); + fRegistryCF.add((sm + "hSparse_dMin3D_fClose_Qinv").c_str(), "closest approach vs how long they stay close;d^{min}_{3D} (cm);f_{close}^{r#varphi}(2 cm);q_{inv} (GeV/c)", + kTHnSparseF, {axisSep, {18, -0.028f, 1.028f}, {50, 0.f, 0.5f}}, true); + fRegistryCF.add((sm + "hSparse_dRPhiMin_fClose_Thr_Qinv").c_str(), "pure r#varphi;d_{r#varphi}^{min} (cm);f_{close}^{r#varphi};threshold index;q_{inv} (GeV/c)", + kTHnSparseF, {{40, 0.f, 10.f}, {18, -0.028f, 1.028f}, {4, -0.5f, 3.5f}, axisQcal4}, true); + fRegistryCF.add((sm + "hSparse_DPair_NClose_Qinv").c_str(), "scaled pair distance;D_{pair}^{min};N_{close};q_{inv} (GeV/c)", + kTHnSparseF, {{40, 0.f, 10.f}, {18, -0.5f, 17.5f}, {50, 0.f, 0.5f}}, true); + fRegistryCF.add((sm + "hSparse_dRPhi_dZ_Cond").c_str(), "control window;d_{r#varphi} @ D^{min}_{pair} (cm);d_{z} @ D^{min}_{pair} (cm);3#upoint region + drift bin", + kTHnSparseF, {axisSep, axisSep, {12, -0.5f, 11.5f}}, true); + fRegistryCF.add((sm + "hDzLocal_vs_dVtxZ").c_str(), "vertex-local;#Deltaz_{vtx} (cm);d_{z} @ D^{min}_{pair} (cm)", kTH2F, + {{80, -4.f, 4.f}, {100, 0.f, 20.f}}, true); + fRegistryCF.add((sm + "hDzGlobal_vs_dVtxZ").c_str(), "global z;#Deltaz_{vtx} (cm);|z_{1}-z_{2}| @ D^{min}_{pair} (cm)", kTH2F, + {{80, -4.f, 4.f}, {100, 0.f, 20.f}}, true); + fRegistryCF.add((sm + "hDzLocalSigned_vs_dVtxZ").c_str(), "vertex-local, signed;#Deltaz_{vtx} (cm);d_{z}^{signed} (cm)", kTH2F, + {{80, -4.f, 4.f}, {200, -20.f, 20.f}}, true); + fRegistryCF.add((sm + "hDzGlobalSigned_vs_dVtxZ").c_str(), "global z, signed;#Deltaz_{vtx} (cm);z_{1}-z_{2} (cm)", kTH2F, + {{80, -4.f, 4.f}, {200, -20.f, 20.f}}, true); + fRegistryCF.add((sm + "hDriftOld_vs_DriftNew").c_str(), "drift length, same side;L from mean z (cm);L from the two legs (cm)", kTH2F, + {{50, 0.f, 250.f}, {50, 0.f, 250.f}}, true); + fRegistryCF.add((sm + "hDriftOld_vs_DriftNew_opp").c_str(), "drift length, opposite side;L from mean z (cm);L from the two legs (cm)", kTH2F, + {{50, 0.f, 250.f}, {50, 0.f, 250.f}}, true); + fRegistryCF.add((sm + "hZ1_vs_Z2").c_str(), "leg z at D^{min}_{pair};z_{1} (cm);z_{2} (cm)", kTH2F, + {{100, -250.f, 250.f}, {100, -250.f, 250.f}}, true); + auto hss = fRegistryCF.add((sm + "hSameSide_vs_Qinv").c_str(), "TPC side;;q_{inv} (GeV/c)", kTH2F, {{2, -0.5f, 1.5f}, {50, 0.f, 0.5f}}, true); + hss->GetXaxis()->SetBinLabel(1, "opposite side"); + hss->GetXaxis()->SetBinLabel(2, "same side"); + fRegistryCF.add((sm + "hNCommon_vs_Qinv").c_str(), "usable radii;N_{valid};q_{inv} (GeV/c)", kTH2F, {{18, -0.5f, 17.5f}, {50, 0.f, 0.5f}}, true); + fRegistryCF.add((sm + "hNSameSide_vs_Qinv").c_str(), "usable radii on the same TPC side;N_{same side};q_{inv} (GeV/c)", kTH2F, {{18, -0.5f, 17.5f}, {50, 0.f, 0.5f}}, true); + fRegistryCF.add((sm + "hSparse_FClose_NClose_Qinv").c_str(), "scaled closeness;f_{close}^{D};N_{close}^{D};q_{inv} (GeV/c)", kTHnSparseF, {{18, -0.028f, 1.028f}, {18, -0.5f, 17.5f}, {50, 0.f, 0.5f}}, true); + if (pairsep.cfgFillCalibSparse.value) { + const AxisSpec axisQcal{{0.00, 0.01, 0.02, 0.04, 0.06, 0.10, 0.15, 0.20, 0.30, 0.50}}; + fRegistryCF.add((sm + "hSparse_Calib_dRPhi_dZ_R_L_C_Q").c_str(), "per-radius calibration;d_{r#varphi} (cm);d_{z} (cm);TPC region;drift bin;charge (0 = e^{+}e^{+});q_{inv} (GeV/c)", + kTHnSparseF, {{32, 0.f, 8.f}, {32, 0.f, 8.f}, {4, -0.5f, 3.5f}, {3, -0.5f, 2.5f}, {2, -0.5f, 1.5f}, axisQcal}, true); + fRegistryCF.add((sm + "hSparse_dRPhi_dZ_LegClass_L_Q").c_str(), "by leg type;d_{r#varphi} (cm);d_{z} (cm);leg class (0: <2, 1: #geq2 ITS-TPC legs);drift bin;q_{inv} (GeV/c)", + kTHnSparseF, {{32, 0.f, 8.f}, {32, 0.f, 8.f}, {2, -0.5f, 1.5f}, {3, -0.5f, 2.5f}, axisQcal}, true); + + fRegistryCF.add((sm + "hSparse_DzSignedLocal_dVtxZ_R").c_str(), "vertex QA, all radii;d_{z}^{signed,local} (cm);#Deltaz_{vtx} (cm);r (cm)", + kTHnSparseF, {{80, -20.f, 20.f}, {20, -4.f, 4.f}, {17, 82.5f, 252.5f}}, true); + fRegistryCF.add((sm + "hSparse_Calib_OppositeSide").c_str(), "opposite-side points;d_{r#varphi} (cm);d_{z} (cm)", kTH2F, + {{32, 0.f, 8.f}, {32, 0.f, 8.f}}, true); + } + fRegistryCF.add((sm + "hSparse_fCloseRPhi_dR_Qinv").c_str(), "fraction of TPC radii with transverse leg distance < 2 cm;f_{close}^{r#varphi}(2 cm);|R_{1}-R_{2}| (cm);q_{inv} (GeV/c)", + kTHnSparseF, {{18, -0.028f, 1.028f}, {90, 0.f, 180.f}, {50, 0.f, 0.5f}}, true); + fRegistryCF.add((sm + "hDRPhiMin_All_vs_SameSide").c_str(), "r#varphi minimum;d_{r#varphi}^{min}, all radii (cm);d_{r#varphi}^{min}, same side (cm)", + kTH2F, {{40, 0.f, 10.f}, {40, 0.f, 10.f}}, true); + fRegistryCF.add((sm + "hDMin3D_PP_vs_NN").c_str(), "d^{min}_{3D};e^{+}e^{+} (cm);e^{-}e^{-} (cm)", kTH2F, + {axisSep, axisSep}, true); + fRegistryCF.add((sm + "hFClose_PP_vs_NN").c_str(), "f_{close}^{r#varphi}(2 cm);e^{+}e^{+};e^{-}e^{-}", kTH2F, + {{18, -0.028f, 1.028f}, {18, -0.028f, 1.028f}}, true); } } @@ -778,7 +1061,7 @@ struct Photonhbt { } fRegistryPairQA.addClone("Pair/same/QA/", "Pair/mix/QA/"); - if (mDoLegPairQA) { + if (mQa.legPairQa) { addLegPairQAForStep("Pair/same/QA/Before/"); addLegPairQAForStep("Pair/same/QA/AfterPairCuts/"); } @@ -946,9 +1229,6 @@ struct Photonhbt { axisDeltaEta, axisDeltaPhi, axisKt); addStageHistos2D("hQinvVsKt", "q_{inv}^{true} vs k_{T};k_{T} (GeV/c);q_{inv}^{true} (GeV/c)", axisKt, axQinvMC); addStageHistos2D("hDEtaDPhi", "#Delta#eta vs #Delta#phi;#Delta#eta_{#gamma#gamma};#Delta#phi_{#gamma#gamma} (rad)", axisDeltaEta, axisDeltaPhi); - const AxisSpec axisUtrue{100, 0.f, 10.f, "u^{true}"}; - addStageHistos2D("hUtrueVsKt", "u^{true} vs k_{T};k_{T} (GeV/c);u^{true}", axisKt, axisUtrue); - addStageHistos2D("hUtrueVsQinv", "u^{true} vs q_{inv}^{true};q_{inv}^{true} (GeV/c);u^{true}", axQinvMC, axisUtrue); // ─── Rconv waterfall fRegistryTruthMC.add("MC/TruthAO2D/hRconv1_vs_Rconv2_truthConverted", "denominator: R_{conv,1} vs R_{conv,2};R_{conv,1}^{true} (cm);R_{conv,2}^{true} (cm)", kTH2D, {axRconv, axRconv}, true); @@ -957,12 +1237,8 @@ struct Photonhbt { fRegistryTruthMC.add("MC/TruthAO2D/hMinRconv_vs_kT_bothPhotonsSelected", "numerator: min(R_{conv}) vs k_{T};k_{T} (GeV/c);min(R_{conv}^{true}) (cm)", kTH2D, {axisKt, axRconv}, true); // ─── Stage summary - fRegistryTruthMC.add("MC/TruthAO2D/hStage_vs_kT", - "efficiency waterfall;k_{T} (GeV/c);stage (0=converted,1=all4legs,2=bothBuilt,3=bothSel)", - kTH2D, {axisKt, AxisSpec{4, -0.5f, 3.5f, "stage"}}, true); - fRegistryTruthMC.add("MC/TruthAO2D/hStageConsistency", - "stage consistency (expect all at 0);N(V0 built but legs not found);counts", - kTH1D, {AxisSpec{20, -0.5f, 19.5f, "N_{bad}"}}, true); + fRegistryTruthMC.add("MC/TruthAO2D/hStage_vs_kT", "efficiency waterfall;k_{T} (GeV/c);stage (0=converted,1=all4legs,2=bothBuilt,3=bothSel)", kTH2D, {axisKt, AxisSpec{4, -0.5f, 3.5f, "stage"}}, true); + fRegistryTruthMC.add("MC/TruthAO2D/hStageConsistency", "stage consistency (expect all at 0);N(V0 built but legs not found);counts", kTH1D, {AxisSpec{20, -0.5f, 19.5f, "N_{bad}"}}, true); // ─── Single-leg diagnostics ────────────────────────────────────────── fRegistryTruthMC.add("MC/LegDiag/hLegDRtrue_vs_pt_legFound", "leg found: #Delta R^{true} vs p_{T};p_{T,#gamma}^{true} (GeV/c);#Delta R_{e^{+}e^{-}}^{true}", kTH2D, {axisPt, axLegDR}, true); @@ -1001,8 +1277,11 @@ struct Photonhbt { const std::string base = std::string("Pair/same/MC/") + std::string(label) + "LegLS/"; fRegistryPairMC.add((base + "hSparse_DR_kT_minLegPt_PP").c_str(), "e^{+}e^{+} #DeltaR,k_{T},min(p_{T,leg})", kTHnSparseF, {axisLegDR, axisKt, axisLegPt}, false); fRegistryPairMC.add((base + "hSparse_DR_kT_minLegPt_NN").c_str(), "e^{-}e^{-} #DeltaR,k_{T},min(p_{T,leg})", kTHnSparseF, {axisLegDR, axisKt, axisLegPt}, false); - fRegistryPairMC.add((base + "hSparse_DEtaDPhi_PtG1_PtG2_PP").c_str(), "e^{+}e^{+} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2}", kTHnSparseF, {axisDeltaEta, axisDeltaPhi, axisPt, axisPt}, false); - fRegistryPairMC.add((base + "hSparse_DEtaDPhi_PtG1_PtG2_NN").c_str(), "e^{-}e^{-} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2}", kTHnSparseF, {axisDeltaEta, axisDeltaPhi, axisPt, axisPt}, false); + if (qaflags.cfgFillLegPairSparses.value) { + const AxisSpec axDE{80, -0.8f, 0.8f, "#Delta#eta"}, axDP{80, -0.8f, 0.8f, "#Delta#phi (rad)"}, axP{20, 0.f, 2.f, "p_{T} (GeV/c)"}; + fRegistryPairMC.add((base + "hSparse_DEtaDPhi_PtG1_PtG2_PP").c_str(), "e^{+}e^{+} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2}", kTHnSparseF, {axDE, axDP, axP, axP}, false); + fRegistryPairMC.add((base + "hSparse_DEtaDPhi_PtG1_PtG2_NN").c_str(), "e^{-}e^{-} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2}", kTHnSparseF, {axDE, axDP, axP, axP}, false); + } } const AxisSpec axisTruthType{{0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5}, "truth type"}; @@ -1022,9 +1301,13 @@ struct Photonhbt { fRegistryCF.add((path + "hDeltaR3DVsQinv").c_str(), "#Delta r_{3D} vs q_{inv};q_{inv} (GeV/c);#Delta r_{3D} (cm)", kTH2D, {axisQinv, axisDeltaR3D}, true); fRegistryCF.add((path + "hQinvVsCent").c_str(), "q_{inv} vs centrality;centrality (%);q_{inv} (GeV/c)", kTH2D, {axisCentQA, axisQinv}, true); fRegistryCF.add((path + "hQinvVsOccupancy").c_str(), "q_{inv} vs occupancy;occupancy;q_{inv} (GeV/c)", kTH2D, {axisOccupancy, axisQinv}, true); - if (mFillDRDZSparse) { + if (mQa.fillDRDZSparse) { fRegistryCF.add((path + "hSparseDeltaRDeltaZQinv").c_str(), "|R_{1}-R_{2}|,#Delta z,q_{inv}", kTHnSparseD, {axisDeltaR, axisDeltaZ, axisQinv}, true); } + // partner radius at fixed R1, differentially in q_inv + if (mQa.fillR1R2Sparse) { + fRegistryCF.add((path + "hSparseR1R2Qinv").c_str(), "R_{1},R_{2},q_{inv};R_{1} (cm);R_{2} (cm);q_{inv} (GeV/c)", kTHnSparseD, {axisR, axisR, axisQinv}, true); + } fRegistryCF.add((path + "hDeltaRCosOAVsQinv").c_str(), "#Delta r/cos(#theta_{op}/2) vs q_{inv};q_{inv} (GeV/c);#Delta r/cos(#theta_{op}/2) (cm)", kTH2D, {axisQinv, {100, 0, 100}}, true); } @@ -1058,16 +1341,25 @@ struct Photonhbt { void addLegPairQAForStep(const std::string& path) { + // local, not members: each member costs one of the 99 decomposable slots + const AxisSpec axisLegDEtaCoarse{80, -0.8f, 0.8f, "#Delta#eta"}; + const AxisSpec axisLegDPhiCoarse{80, -0.8f, 0.8f, "#Delta#phi (rad)"}; + const AxisSpec axisLegPtCoarse{20, 0.f, 2.f, "p_{T}^{leg} (GeV/c)"}; + const AxisSpec axisPtCoarse{20, 0.f, 2.f, "p_{T} (GeV/c)"}; // LS positive fRegistryPairQA.add((path + "LegLS/hDEtaDPhi_PP").c_str(), "e^{+}e^{+} #Delta#eta vs #Delta#phi;#Delta#eta;#Delta#phi (rad)", kTH2D, {axisDeltaEta, axisDeltaPhi}, true); - fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_kT_minLegPt_PP").c_str(), "e^{+}e^{+} #Delta#eta,#Delta#phi,k_{T},min(p_{T,leg})", kTHnSparseD, {axisDeltaEta, axisDeltaPhi, axisKt, axisLegPt}, true); + if (qaflags.cfgFillLegPairSparses.value) { + fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_kT_minLegPt_PP").c_str(), "e^{+}e^{+} #Delta#eta,#Delta#phi,k_{T},min(p_{T,leg})", kTHnSparseF, {axisLegDEtaCoarse, axisLegDPhiCoarse, axisKt, axisLegPtCoarse}, true); + } fRegistryPairQA.add((path + "LegLS/hDR_PP").c_str(), "e^{+}e^{+} #DeltaR;#DeltaR;counts", kTH1D, {axisLegDR}, true); fRegistryPairQA.add((path + "LegLS/hLegPtLow_vs_LegPtHigh_PP").c_str(), "e^{+}e^{+} p_{T,low} vs p_{T,high};p_{T,low}^{leg};p_{T,high}^{leg}", kTH2D, {axisLegPt, axisLegPt}, true); fRegistryPairQA.add((path + "LegLS/hDR_PP_vs_minLegPt").c_str(), "e^{+}e^{+} #DeltaR vs min(p_{T,leg});#DeltaR;min(p_{T,leg}) (GeV/c)", kTH2D, {axisLegDR, axisLegPt}, true); // LS negative fRegistryPairQA.add((path + "LegLS/hDEtaDPhi_NN").c_str(), "e^{-}e^{-} #Delta#eta vs #Delta#phi;#Delta#eta;#Delta#phi (rad)", kTH2D, {axisDeltaEta, axisDeltaPhi}, true); - fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_kT_minLegPt_NN").c_str(), "e^{-}e^{-} #Delta#eta,#Delta#phi,k_{T},min(p_{T,leg})", kTHnSparseD, {axisDeltaEta, axisDeltaPhi, axisKt, axisLegPt}, true); + if (qaflags.cfgFillLegPairSparses.value) { + fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_kT_minLegPt_NN").c_str(), "e^{-}e^{-} #Delta#eta,#Delta#phi,k_{T},min(p_{T,leg})", kTHnSparseF, {axisLegDEtaCoarse, axisLegDPhiCoarse, axisKt, axisLegPtCoarse}, true); + } fRegistryPairQA.add((path + "LegLS/hDR_NN").c_str(), "e^{-}e^{-} #DeltaR;#DeltaR;counts", kTH1D, {axisLegDR}, true); fRegistryPairQA.add((path + "LegLS/hLegPtLow_vs_LegPtHigh_NN").c_str(), "e^{-}e^{-} p_{T,low} vs p_{T,high};p_{T,low}^{leg};p_{T,high}^{leg}", kTH2D, {axisLegPt, axisLegPt}, true); fRegistryPairQA.add((path + "LegLS/hDR_NN_vs_minLegPt").c_str(), "e^{-}e^{-} #DeltaR vs min(p_{T,leg});#DeltaR;min(p_{T,leg}) (GeV/c)", kTH2D, {axisLegDR, axisLegPt}, true); @@ -1079,14 +1371,16 @@ struct Photonhbt { fRegistryPairQA.add((path + "LegUScross/hDEtaDPhi_NP12").c_str(), "ele1-pos2 #Delta#eta vs #Delta#phi;#Delta#eta;#Delta#phi (rad)", kTH2D, {axisDeltaEta, axisDeltaPhi}, true); // 4D Photon-pT diagnostics - fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_PtG1_PtG2_PP").c_str(), - "e^{+}e^{+} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2};" - "#Delta#eta;#Delta#phi (rad);p_{T,#gamma 1} (GeV/c);p_{T,#gamma 2} (GeV/c)", - kTHnSparseD, {axisDeltaEta, axisDeltaPhi, axisPt, axisPt}, true); - fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_PtG1_PtG2_NN").c_str(), - "e^{-}e^{-} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2};" - "#Delta#eta;#Delta#phi (rad);p_{T,#gamma 1} (GeV/c);p_{T,#gamma 2} (GeV/c)", - kTHnSparseD, {axisDeltaEta, axisDeltaPhi, axisPt, axisPt}, true); + if (qaflags.cfgFillLegPairSparses.value) { + fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_PtG1_PtG2_PP").c_str(), + "e^{+}e^{+} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2};" + "#Delta#eta;#Delta#phi (rad);p_{T,#gamma 1} (GeV/c);p_{T,#gamma 2} (GeV/c)", + kTHnSparseF, {axisLegDEtaCoarse, axisLegDPhiCoarse, axisPtCoarse, axisPtCoarse}, true); + fRegistryPairQA.add((path + "LegLS/hSparse_DEtaDPhi_PtG1_PtG2_NN").c_str(), + "e^{-}e^{-} #Delta#eta,#Delta#phi,p_{T,#gamma 1},p_{T,#gamma 2};" + "#Delta#eta;#Delta#phi (rad);p_{T,#gamma 1} (GeV/c);p_{T,#gamma 2} (GeV/c)", + kTHnSparseF, {axisLegDEtaCoarse, axisLegDPhiCoarse, axisPtCoarse, axisPtCoarse}, true); + } // Photon-pT Scatter fRegistryPairQA.add((path + "LegLS/hPtG1_vs_PtG2").c_str(), "p_{T,#gamma 1} vs p_{T,#gamma 2};p_{T,#gamma 1} (GeV/c);p_{T,#gamma 2} (GeV/c)", kTH2D, {axisPt, axisPt}, true); @@ -1127,10 +1421,8 @@ struct Photonhbt { static int binOf(const std::vector& edges, float val) { - const int b = static_cast( - std::lower_bound(edges.begin(), edges.end(), val) - edges.begin()) - - 1; - return clampBin(b, static_cast(edges.size()) - 2); // + const auto pos = static_cast(std::lower_bound(edges.begin(), edges.end(), val) - edges.begin()); + return clampBin(pos - 1, static_cast(edges.size()) - 2); } template @@ -1225,10 +1517,12 @@ struct Photonhbt { return o; } + // not const: fills the propagation-status histogram template - [[nodiscard]] PhotonWithLegs makePhotonWithLegs(TGamma const& g, TLeg const& pos, TLeg const& ele) const + [[nodiscard]] PhotonWithLegs makePhotonWithLegs(TGamma const& g, TLeg const& pos, TLeg const& ele, float vtxZ) { PhotonWithLegs p; + p.fVtxZ = vtxZ; p.fPt = g.pt(); p.fEta = g.eta(); p.fPhi = g.phi(); @@ -1239,15 +1533,18 @@ struct Photonhbt { p.fLegEta = {static_cast(pos.eta()), static_cast(ele.eta())}; p.fLegPhi = {static_cast(pos.phi()), static_cast(ele.phi())}; p.fLegCounts = pairutil::getV0PhotonLegCounts(pos, ele); - const float rConvCm = std::hypot(p.fVx, p.fVy); + p.fNITSTPC = p.fLegCounts.nITSTPC; + // legHelixAt itself rejects radii below the conversion point for (size_t ir = 0; ir < kPhiStarRadiiM.size(); ++ir) { - if (kPhiStarRadiiM[ir] * kCmPerM < rConvCm) { // leg does not exist below R_conv - p.fLegPhiStar[0][ir] = kPhiStarInvalid; - p.fLegPhiStar[1][ir] = kPhiStarInvalid; - continue; + for (int il = 0; il < 2; ++il) { // o2-linter: disable=magic-number (two legs) + const auto h = legHelixAt(p.fVx / kCmPerM, p.fVy / kCmPerM, p.fLegPhi[il], p.fLegPt[il], + (il == 0) ? +1 : -1, mBzT, kPhiStarRadiiM[ir]); + p.fLegPhiStar[il][ir] = h.phiStar; + p.fLegSxy[il][ir] = h.sxy; + fRegistryCF.fill(HIST("PairSep/hLegPropStatus"), static_cast(h.status)); + fRegistryCF.fill(HIST("PairSep/hPropStatus_vs_LegPt"), static_cast(h.status), p.fLegPt[il]); + fRegistryCF.fill(HIST("PairSep/hPropStatus_vs_Rconv"), static_cast(h.status), std::hypot(p.fVx, p.fVy)); } - p.fLegPhiStar[0][ir] = legPhiStar(p.fLegPhi[0], p.fLegPt[0], +1, mBzT, kPhiStarRadiiM[ir]); - p.fLegPhiStar[1][ir] = legPhiStar(p.fLegPhi[1], p.fLegPt[1], -1, mBzT, kPhiStarRadiiM[ir]); } return p; } @@ -1255,33 +1552,138 @@ struct Photonhbt { [[nodiscard]] PairSep computePairSep(PhotonWithLegs const& a, PhotonWithLegs const& b) const { PairSep s; - const float sE = pairsep.cfgUSigEta.value, sP = pairsep.cfgUSigPhi.value; - auto uSameSign = [&](int i, float& dEtaOut, float& dPhiOut) -> float { - dEtaOut = a.fLegEta[i] - b.fLegEta[i]; - if (!pairsep.cfgUsePhiStar.value) { - dPhiOut = RecoDecay::constrainAngle(a.fLegPhi[i] - b.fLegPhi[i], -o2::constants::math::PI); - return std::hypot(dEtaOut / sE, dPhiOut / sP); - } - float sumDp = 0.f; - int n = 0; + s.dVtxZ = a.fVtxZ - b.fVtxZ; + s.nLegsITSTPC = a.fNITSTPC + b.fNITSTPC; + + const float sigR = std::max(pairsep.cfgSigRPhi.value, kMinSigma); + const float sigZcm = (pairsep.cfgSigZNs.value > 0.f && mVDriftCmPerNs > 0.f) + ? pairsep.cfgSigZNs.value * mVDriftCmPerNs + : pairsep.cfgSigZ.value; + const float sigZ = std::max(sigZcm, kMinSigma); + const float dClose = pairsep.cfgDPairClose.value; + for (int i = 0; i < 2; ++i) { // o2-linter: disable=magic-number (PP and NN) + int nHere = 0, nSame = 0, nCloseD = 0; + std::array nCloseThr{}; + float best3 = 999.f, bestR = 999.f, bestD = 999.f; + float bestRAll = 999.f, bestDAll = 999.f; + float rphiAt3 = 999.f, zAt3 = 999.f, zAtR = 999.f; + float rphiAtD = 999.f, zAtD = 999.f, rAtD = -1.f, absZAtD = -1.f; + float zGlobAtD = 999.f, zSgnLocAtD = 999.f, zSgnGlobAtD = 999.f; + float driftAtD = -1.f, driftOldAtD = -1.f; for (size_t ir = 0; ir < kPhiStarRadiiM.size(); ++ir) { const float p1 = a.fLegPhiStar[i][ir], p2 = b.fLegPhiStar[i][ir]; - if (p1 < -100.f || p2 < -100.f) { // o2-linter: disable=magic-number (skip if non-sensical value is chosen) + if (p1 < -100.f || p2 < -100.f) { // o2-linter: disable=magic-number (invalid phi*) continue; } - sumDp += RecoDecay::constrainAngle(p1 - p2, -o2::constants::math::PI); - ++n; + const float rCm = kPhiStarRadiiM[ir] * kCmPerM; + const float dphi = RecoDecay::constrainAngle(p1 - p2, -o2::constants::math::PI); + const float dRPhi = 2.f * rCm * std::fabs(std::sin(0.5f * dphi)); + const float z1 = a.fVz + a.fLegSxy[i][ir] * kCmPerM * std::sinh(a.fLegEta[i]); + const float z2 = b.fVz + b.fLegSxy[i][ir] * kCmPerM * std::sinh(b.fLegEta[i]); + const float dZSignedLocal = (z1 - a.fVtxZ) - (z2 - b.fVtxZ); + const float dZSignedGlobal = z1 - z2; + const float dZ = std::fabs(dZSignedLocal); + const float dZGlobal = std::fabs(dZSignedGlobal); + const float d3 = std::hypot(dRPhi, dZ); + const float zMax = pairsep.cfgTpcHalfLengthCm.value; + const float l1 = std::max(0.f, zMax - std::fabs(z1)); + const float l2 = std::max(0.f, zMax - std::fabs(z2)); + const float driftHere = 0.5f * (l1 + l2); + const float driftOldHere = std::max(0.f, zMax - 0.5f * std::fabs(z1 + z2)); + const bool sameSide = (z1 * z2 >= 0.f); + const float dPair = std::hypot(dRPhi / sigR, dZ / sigZ); + ++nHere; + s.ptR[i][nHere - 1] = rCm; + s.ptDRPhi[i][nHere - 1] = dRPhi; + s.ptDZ[i][nHere - 1] = dZ; + s.ptDZSgnLocal[i][nHere - 1] = dZSignedLocal; + s.ptDrift[i][nHere - 1] = driftHere; + s.ptSameSide[i][nHere - 1] = sameSide ? 1.f : 0.f; + bestRAll = std::min(bestRAll, dRPhi); + bestDAll = std::min(bestDAll, dPair); + if (d3 < best3) { + best3 = d3; + rphiAt3 = dRPhi; + zAt3 = dZ; + } + if (!sameSide) { + continue; + } + ++nSame; + for (std::size_t t = 0; t < s.nCloseRPhiThr.size(); ++t) { + if (dRPhi < pairsep.cfgCloseThrCm.value[t]) { + ++nCloseThr[t]; + } + } + if (dPair < dClose) { + ++nCloseD; + } + if (dPair < bestD) { + bestD = dPair; + rphiAtD = dRPhi; + zAtD = dZ; + zGlobAtD = dZGlobal; + zSgnLocAtD = dZSignedLocal; + zSgnGlobAtD = dZSignedGlobal; + rAtD = rCm; + absZAtD = 0.5f * std::fabs(z1 + z2); + driftAtD = driftHere; + driftOldAtD = driftOldHere; + } + if (dRPhi < bestR) { + bestR = dRPhi; + zAtR = dZ; + } + } + if (nHere == 0) { + continue; } - if (n == 0) { - dPhiOut = 999.f; - return 999.f; + s.nPoints[i] = nHere; + s.nSameSidePerCharge[i] = nSame; + s.dMin3DPerCharge[i] = best3; + s.dPairMinPerCharge[i] = bestD; + s.dMinRPhiPerCharge[i] = bestR; + s.dMinRPhiAll = std::min(s.dMinRPhiAll, bestRAll); + s.dPairMinAll = std::min(s.dPairMinAll, bestDAll); + const float invS = (nSame > 0) ? 1.f / static_cast(nSame) : 0.f; + for (std::size_t t = 0; t < nCloseThr.size(); ++t) { + s.nCloseRPhiThrPerCharge[i][t] = nCloseThr[t]; + s.fCloseRPhiThrPerCharge[i][t] = static_cast(nCloseThr[t]) * invS; } - dPhiOut = sumDp / static_cast(n); - return std::hypot(dEtaOut / sE, dPhiOut / sP); - }; - const float uPP = uSameSign(0, s.dEtaPP, s.dPhiPP); - const float uNN = uSameSign(1, s.dEtaNN, s.dPhiNN); - s.u = std::min(uPP, uNN); + s.fCloseRPhiPerCharge[i] = s.fCloseRPhiThrPerCharge[i][3]; // o2-linter: disable=magic-number (last threshold) + if (bestD < s.dPairMin) { + s.dPairMin = bestD; + s.dRPhiAtDPairMin = rphiAtD; + s.dZAtDPairMin = zAtD; + s.dZGlobalAtDPairMin = zGlobAtD; + s.dZSignedLocalAtDPairMin = zSgnLocAtD; + s.dZSignedGlobalAtDPairMin = zSgnGlobAtD; + s.rAtDPairMin = rAtD; + s.absZAtDPairMin = absZAtD; + s.driftLen = driftAtD; + s.driftOldAtDPairMin = driftOldAtD; + s.nCloseScaled = nCloseD; + s.fCloseScaled = static_cast(nCloseD) * invS; + } + if (best3 < s.dMin3D) { + s.dMin3D = best3; + s.dRPhiAtMin3D = rphiAt3; + s.dZAtMin3D = zAt3; + s.criticalCharge = i; + } + if (bestR < s.dMinRPhi) { + s.dMinRPhi = bestR; + s.dZAtMinRPhi = zAtR; + s.nCloseRPhiThr = s.nCloseRPhiThrPerCharge[i]; + s.fCloseRPhiThr = s.fCloseRPhiThrPerCharge[i]; + s.fCloseRPhi = s.fCloseRPhiThr[3]; // o2-linter: disable=magic-number (last threshold) + s.nSameSide = nSame; + s.rphiCharge = i; + } + } + s.sameSideAtDPairMin = (s.nSameSidePerCharge[0] + s.nSameSidePerCharge[1]) > 0; + s.nCommon = (s.rphiCharge >= 0) ? s.nPoints[s.rphiCharge] + : std::max(s.nPoints[0], s.nPoints[1]); return s; } @@ -1298,12 +1700,46 @@ struct Photonhbt { return q2 <= qMax * qMax; } - [[nodiscard]] inline bool passLegSepCut(PairSep const& s) const + [[nodiscard]] inline bool passPairMergeCut(PairSep const& s) const { - if (!pairsep.cfgDoLegSepCut.value) { + if (!pairsep.cfgDoPairMergeCut.value) { return true; } - return s.u > pairsep.cfgUCut.value; + if (s.nCommon <= 0) { // nothing was propagated: no statement possible + return true; + } + if (s.dPairMin < pairsep.cfgDPairCut.value) { + return false; + } + const int nCut = pairsep.cfgNCloseCut.value; + // dipping close once is survivable, running alongside is not + return nCut <= 0 || s.nCloseScaled < nCut; + } + + [[nodiscard]] inline int tpcRegion(float rCm) const + { + if (rCm < pairsep.cfgRegionEdge1.value) { + return 0; + } + if (rCm < pairsep.cfgRegionEdge2.value) { + return 1; + } + if (rCm < pairsep.cfgRegionEdge3.value) { + return 2; // o2-linter: disable=magic-number (region index) + } + return 3; // o2-linter: disable=magic-number (region index) + } + + [[nodiscard]] inline int driftBin(float driftLen) const + { + const float third = pairsep.cfgTpcHalfLengthCm.value / 3.f; // o2-linter: disable=magic-number (three drift slices) + if (driftLen < third) { + return 0; + } + if (driftLen < 2.f * third) { // o2-linter: disable=magic-number (three drift slices) + return 1; + } + return 2; // o2-linter: disable=magic-number (three drift slices) } [[nodiscard]] CrossObs computeCrossObs(PhotonWithLegs const& a, PhotonWithLegs const& b, float qinv) const @@ -1313,7 +1749,6 @@ struct Photonhbt { auto legVec = [](PhotonWithLegs const& p, int i) { return ROOT::Math::PtEtaPhiMVector(p.fLegPt[i], p.fLegEta[i], p.fLegPhi[i], kMe); }; - // Leg index 0 = e+, 1 = e- (makePhotonWithLegs filling order). // Combo 0: a's e+ with b's e-. Combo 1: b's e+ with a's e-. for (int combo = 0; combo < 2; ++combo) { // o2-linter: disable=magic-number (the two leg-swap combinations) PhotonWithLegs const& pPos = (combo == 0) ? a : b; @@ -1331,7 +1766,6 @@ struct Photonhbt { if (!crosspair.cfgDoCrossPairCut.value) { return true; } - // A photon-like crossed combination means the pairing is ambiguous. return c.meeOverQ > crosspair.cfgCrossMaxMeeRatio.value; } @@ -1346,39 +1780,6 @@ struct Photonhbt { fRegistryCF.fill(HIST(dir) + HIST("hSparse_MeeRatio_dR_Qinv"), c.meeOverQ, deltaR, qinv); } - [[nodiscard]] float uTrue(TruthGamma const& g1, TruthGamma const& g2) const - { - const float sE = pairsep.cfgUSigEta.value, sP = pairsep.cfgUSigPhi.value; - auto uSameSign = [&](int i) -> float { - const float dEta = g1.legEtaTrue[i] - g2.legEtaTrue[i]; - if (!pairsep.cfgUsePhiStar.value) { - const float dp = RecoDecay::constrainAngle(g1.legPhiTrue[i] - g2.legPhiTrue[i], -o2::constants::math::PI); - return std::hypot(dEta / sE, dp / sP); - } - const int q = (i == 0) ? +1 : -1; - float sumDp = 0.f; - int n = 0; - for (const float& r : kPhiStarRadiiM) { - if ((g1.rTrue >= 0.f && r * kCmPerM < g1.rTrue) || - (g2.rTrue >= 0.f && r * kCmPerM < g2.rTrue)) { - continue; - } - const float p1 = legPhiStar(g1.legPhiTrue[i], g1.legPtTrue[i], q, mBzT, r); - const float p2 = legPhiStar(g2.legPhiTrue[i], g2.legPtTrue[i], q, mBzT, r); - if (p1 < -100.f || p2 < -100.f) { // o2-linter: disable=magic-number (skip if non-sensical value is chosen) - continue; - } - sumDp += RecoDecay::constrainAngle(p1 - p2, -o2::constants::math::PI); - ++n; - } - if (n == 0) { - return 999.f; - } - return std::hypot(dEta / sE, (sumDp / static_cast(n)) / sP); - }; - return std::min(uSameSign(0), uSameSign(1)); - } - /*************************************************/ // FILL HELPERS /*************************************************/ @@ -1392,26 +1793,82 @@ struct Photonhbt { fRegistryCF.fill(HIST(base) + HIST("hDeltaR3DVsQinv"), obs.qinv, obs.deltaR3D); fRegistryCF.fill(HIST(base) + HIST("hQinvVsCent"), cent, obs.qinv); fRegistryCF.fill(HIST(base) + HIST("hQinvVsOccupancy"), occupancy, obs.qinv); - if (mFillDRDZSparse) { + if (mQa.fillDRDZSparse) { fRegistryCF.fill(HIST(base) + HIST("hSparseDeltaRDeltaZQinv"), obs.deltaR, obs.deltaZ, obs.qinv); } + if (mQa.fillR1R2Sparse) { + // both orderings: the pair is unordered + fRegistryCF.fill(HIST(base) + HIST("hSparseR1R2Qinv"), obs.r1, obs.r2, obs.qinv); + fRegistryCF.fill(HIST(base) + HIST("hSparseR1R2Qinv"), obs.r2, obs.r1, obs.qinv); + } } template inline void fillPairSep(PairSep const& s, PairQAObservables const& obs) { - if (!mDoPairSepQA) { + if (!mQa.pairSepQa) { return; } + // the AfterCut directories only exist when a pair cut is active + if constexpr (after_cut) { + if (!mQa.pairSepAfterCut) { + return; + } + } const float limit = pairsep.cfgPairSepMaxQinv.value; if (limit > 0.f && obs.qinv >= limit) { return; } constexpr auto dir = pairSepPrefix(); - fRegistryCF.fill(HIST(dir) + HIST("hDEtaDPhiKt_PP"), s.dEtaPP, s.dPhiPP, obs.kt); - fRegistryCF.fill(HIST(dir) + HIST("hDEtaDPhiKt_NN"), s.dEtaNN, s.dPhiNN, obs.kt); - fRegistryCF.fill(HIST(dir) + HIST("hU_Qinv_Kt"), s.u, obs.qinv, obs.kt); - fRegistryCF.fill(HIST(dir) + HIST("hU_Qinv_dE"), s.u, obs.qinv, std::fabs(obs.v1.E() - obs.v2.E())); + if (s.nCommon > 0) { + fRegistryCF.fill(HIST(dir) + HIST("hSparse_dRPhiAtMin3D_dZAtMin3D_Qinv"), s.dRPhiAtMin3D, s.dZAtMin3D, obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hSparse_dMin3D_fClose_Qinv"), s.dMin3D, s.fCloseRPhi, obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hSparse_fCloseRPhi_dR_Qinv"), s.fCloseRPhi, obs.deltaR, obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hDRPhiMin_All_vs_SameSide"), s.dMinRPhiAll, s.dMinRPhi); + fRegistryCF.fill(HIST(dir) + HIST("hDMin3D_PP_vs_NN"), s.dMin3DPerCharge[0], s.dMin3DPerCharge[1]); + fRegistryCF.fill(HIST(dir) + HIST("hFClose_PP_vs_NN"), s.fCloseRPhiPerCharge[0], s.fCloseRPhiPerCharge[1]); + for (std::size_t t = 0; t < s.fCloseRPhiThr.size(); ++t) { + fRegistryCF.fill(HIST(dir) + HIST("hSparse_dRPhiMin_fClose_Thr_Qinv"), s.dMinRPhi, + s.fCloseRPhiThr[t], static_cast(t), obs.qinv); + } + fRegistryCF.fill(HIST(dir) + HIST("hSparse_DPair_NClose_Qinv"), s.dPairMin, static_cast(s.nCloseScaled), obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hDzLocal_vs_dVtxZ"), s.dVtxZ, s.dZAtDPairMin); + fRegistryCF.fill(HIST(dir) + HIST("hDzGlobal_vs_dVtxZ"), s.dVtxZ, s.dZGlobalAtDPairMin); + fRegistryCF.fill(HIST(dir) + HIST("hDzLocalSigned_vs_dVtxZ"), s.dVtxZ, s.dZSignedLocalAtDPairMin); + fRegistryCF.fill(HIST(dir) + HIST("hDzGlobalSigned_vs_dVtxZ"), s.dVtxZ, s.dZSignedGlobalAtDPairMin); + if (s.sameSideAtDPairMin) { + fRegistryCF.fill(HIST(dir) + HIST("hDriftOld_vs_DriftNew"), s.driftOldAtDPairMin, s.driftLen); + } else { + fRegistryCF.fill(HIST(dir) + HIST("hDriftOld_vs_DriftNew_opp"), s.driftOldAtDPairMin, s.driftLen); + } + fRegistryCF.fill(HIST(dir) + HIST("hSameSide_vs_Qinv"), s.sameSideAtDPairMin ? 1.f : 0.f, obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hNCommon_vs_Qinv"), static_cast(s.nCommon), obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hNSameSide_vs_Qinv"), static_cast(s.nSameSide), obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hSparse_FClose_NClose_Qinv"), s.fCloseScaled, static_cast(s.nCloseScaled), obs.qinv); + if (pairsep.cfgFillCalibSparse.value) { + for (int ic = 0; ic < 2; ++ic) { // o2-linter: disable=magic-number (PP and NN) + for (int k = 0; k < s.nPoints[ic]; ++k) { + fRegistryCF.fill(HIST(dir) + HIST("hSparse_DzSignedLocal_dVtxZ_R"), + s.ptDZSgnLocal[ic][k], s.dVtxZ, s.ptR[ic][k]); + if (s.ptSameSide[ic][k] < 0.5f) { // o2-linter: disable=magic-number (indication of side) + fRegistryCF.fill(HIST(dir) + HIST("hSparse_Calib_OppositeSide"), s.ptDRPhi[ic][k], s.ptDZ[ic][k]); + continue; // cannot merge: different endcap + } + fRegistryCF.fill(HIST(dir) + HIST("hSparse_Calib_dRPhi_dZ_R_L_C_Q"), s.ptDRPhi[ic][k], s.ptDZ[ic][k], + static_cast(tpcRegion(s.ptR[ic][k])), static_cast(driftBin(s.ptDrift[ic][k])), + static_cast(ic), obs.qinv); + fRegistryCF.fill(HIST(dir) + HIST("hSparse_dRPhi_dZ_LegClass_L_Q"), s.ptDRPhi[ic][k], s.ptDZ[ic][k], + (s.nLegsITSTPC >= 2) ? 1.f : 0.f, // o2-linter: disable=magic-number (two leg classes) + static_cast(driftBin(s.ptDrift[ic][k])), obs.qinv); + } + } + } + if (obs.qinv >= pairsep.cfgCondQinvMin.value && obs.qinv < pairsep.cfgCondQinvMax.value && + s.rAtDPairMin > 0.f) { + const auto cond = static_cast(3 * tpcRegion(s.rAtDPairMin) + driftBin(s.driftLen)); // o2-linter: disable=magic-number (three drift bins per region) + fRegistryCF.fill(HIST(dir) + HIST("hSparse_dRPhi_dZ_Cond"), s.dRPhiAtDPairMin, s.dZAtDPairMin, cond); + } + } } template @@ -1430,7 +1887,7 @@ struct Photonhbt { template inline void fillSinglePhotonQAStep(TPhoton const& g) { - if (!mDoSinglePhotonQa) { + if (!mQa.singlePhotonQa) { return; } constexpr auto base = singlePhotonQAPrefix(); @@ -1527,7 +1984,7 @@ struct Photonhbt { template inline void fillPairQAStep(PairQAObservables const& o, float /*cent*/, float /*occupancy*/) { - if (!mDoPairQa) { + if (!mQa.pairQa) { return; } constexpr auto base = qaPrefix(); @@ -1567,19 +2024,23 @@ struct Photonhbt { template inline void fillLegPairQAStep(LegPairObservables const& lo, float kt) { - if (!mDoLegPairQA) { + if (!mQa.legPairQa) { return; } constexpr auto base = qaPrefix<0, step_id>(); fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hDEtaDPhi_PP"), lo.dEtaPP, lo.dPhiPP); - fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_kT_minLegPt_PP"), lo.dEtaPP, lo.dPhiPP, kt, lo.minLegPt_PP); + if (qaflags.cfgFillLegPairSparses.value) { + fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_kT_minLegPt_PP"), lo.dEtaPP, lo.dPhiPP, kt, lo.minLegPt_PP); + } fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hDR_PP"), lo.dRPP); fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hLegPtLow_vs_LegPtHigh_PP"), lo.minLegPt_PP, lo.maxLegPt_PP); fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hDR_PP_vs_minLegPt"), lo.dRPP, lo.minLegPt_PP); fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hDEtaDPhi_NN"), lo.dEtaNN, lo.dPhiNN); - fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_kT_minLegPt_NN"), lo.dEtaNN, lo.dPhiNN, kt, lo.minLegPt_NN); + if (qaflags.cfgFillLegPairSparses.value) { + fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_kT_minLegPt_NN"), lo.dEtaNN, lo.dPhiNN, kt, lo.minLegPt_NN); + } fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hDR_NN"), lo.dRNN); fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hLegPtLow_vs_LegPtHigh_NN"), lo.minLegPt_NN, lo.maxLegPt_NN); fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hDR_NN_vs_minLegPt"), lo.dRNN, lo.minLegPt_NN); @@ -1589,8 +2050,10 @@ struct Photonhbt { fRegistryPairQA.fill(HIST(base) + HIST("LegUScross/hDEtaDPhi_PN12"), lo.dEtaPN12, lo.dPhiPN12); fRegistryPairQA.fill(HIST(base) + HIST("LegUScross/hDEtaDPhi_NP12"), lo.dEtaNP12, lo.dPhiNP12); - fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_PP"), lo.dEtaPP, lo.dPhiPP, lo.ptG1, lo.ptG2); - fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_NN"), lo.dEtaNN, lo.dPhiNN, lo.ptG1, lo.ptG2); + if (qaflags.cfgFillLegPairSparses.value) { + fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_PP"), lo.dEtaPP, lo.dPhiPP, lo.ptG1, lo.ptG2); + fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_NN"), lo.dEtaNN, lo.dPhiNN, lo.ptG1, lo.ptG2); + } fRegistryPairQA.fill(HIST(base) + HIST("LegLS/hPtG1_vs_PtG2"), lo.ptG1, lo.ptG2); } @@ -1600,8 +2063,10 @@ struct Photonhbt { constexpr auto base = mcDirPrefix(); fRegistryPairMC.fill(HIST(base) + HIST("LegLS/hSparse_DR_kT_minLegPt_PP"), lo.dRPP, kt, lo.minLegPt_PP); fRegistryPairMC.fill(HIST(base) + HIST("LegLS/hSparse_DR_kT_minLegPt_NN"), lo.dRNN, kt, lo.minLegPt_NN); - fRegistryPairMC.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_PP"), lo.dEtaPP, lo.dPhiPP, lo.ptG1, lo.ptG2); - fRegistryPairMC.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_NN"), lo.dEtaNN, lo.dPhiNN, lo.ptG1, lo.ptG2); + if (qaflags.cfgFillLegPairSparses.value) { + fRegistryPairMC.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_PP"), lo.dEtaPP, lo.dPhiPP, lo.ptG1, lo.ptG2); + fRegistryPairMC.fill(HIST(base) + HIST("LegLS/hSparse_DEtaDPhi_PtG1_PtG2_NN"), lo.dEtaNN, lo.dPhiNN, lo.ptG1, lo.ptG2); + } } inline void fillLegPairMC(PairTruthType t, LegPairObservables const& lo, float kt) @@ -1956,7 +2421,7 @@ struct Photonhbt { auto keyDFCollision = std::make_pair(ndf, collision.globalIndex()); auto photons1Coll = photons1.sliceBy(perCollision1, collision.globalIndex()); auto photons2Coll = photons2.sliceBy(perCollision2, collision.globalIndex()); - if (mDoSinglePhotonQa) { + if (mQa.singlePhotonQa) { for (const auto& g : photons1Coll) { if (cut1.template IsSelected(g)) { fillSinglePhotonQAStep<0>(g); @@ -1984,8 +2449,8 @@ struct Photonhbt { } const bool doQA = passQinvQAGate(obs.qinv), doFR = passQinvFullRangeGate(obs.qinv); const auto legObs = buildLegPairObservables(g1, g2, pos1, ele1, pos2, ele2); - const auto pwl1 = makePhotonWithLegs(g1, pos1, ele1); - const auto pwl2 = makePhotonWithLegs(g2, pos2, ele2); + const auto pwl1 = makePhotonWithLegs(g1, pos1, ele1, collision.posZ()); + const auto pwl2 = makePhotonWithLegs(g2, pos2, ele2, collision.posZ()); const auto sep = computePairSep(pwl1, pwl2); // ───before pair cuts ───────────────────────────────────── @@ -2005,7 +2470,7 @@ struct Photonhbt { if (obs.drOverCosOA < ggpaircuts.cfgMinDRCosOA) { continue; } - if (!passLegSepCut(sep)) { + if (!passPairMergeCut(sep)) { continue; } if (!passRZCut(obs.deltaR, obs.deltaZ)) { @@ -2047,7 +2512,7 @@ struct Photonhbt { addToPool(g1, pwl1); addToPool(g2, pwl2); } - if (mDoSinglePhotonQa) { + if (mQa.singlePhotonQa) { for (const auto& g : photons1Coll) { if (cut1.template IsSelected(g)) { if (idsAfterPairCuts.contains(g.globalIndex())) { @@ -2104,7 +2569,7 @@ struct Photonhbt { if (obs.drOverCosOA < ggpaircuts.cfgMinDRCosOA) { continue; } - if (!passLegSepCut(sep)) { + if (!passPairMergeCut(sep)) { continue; } if (!passRZCut(obs.deltaR, obs.deltaZ)) { @@ -2181,7 +2646,7 @@ struct Photonhbt { auto keyBin = std::make_tuple(zbin, centbin, epbin, occbin); auto keyDFCollision = std::make_pair(ndf, collision.globalIndex()); auto photonsColl = photons.sliceBy(perCollision, collision.globalIndex()); - if (mDoSinglePhotonQa) { + if (mQa.singlePhotonQa) { for (const auto& g : photonsColl) { if (cut.template IsSelected(g)) { fillSinglePhotonQAStep<0>(g); @@ -2214,8 +2679,8 @@ struct Photonhbt { } const bool doQA = passQinvQAGate(obs.qinv), doFR = passQinvFullRangeGate(obs.qinv); const auto legObs = buildLegPairObservables(g1, g2, pos1, ele1, pos2, ele2); - const auto pwl1 = makePhotonWithLegs(g1, pos1, ele1); - const auto pwl2 = makePhotonWithLegs(g2, pos2, ele2); + const auto pwl1 = makePhotonWithLegs(g1, pos1, ele1, collision.posZ()); + const auto pwl2 = makePhotonWithLegs(g2, pos2, ele2, collision.posZ()); const auto sep = computePairSep(pwl1, pwl2); // ──before pair cuts ───────────────────────────────────── @@ -2233,7 +2698,7 @@ struct Photonhbt { continue; } - if (!passLegSepCut(sep)) { + if (!passPairMergeCut(sep)) { continue; } @@ -2276,7 +2741,7 @@ struct Photonhbt { } else { const bool doMCQA = passQinvMCQAGate(obs.qinv); fillMCPairQA(truthType, obs, doQA, doMCQA); - if (mDoLegPairQA) { + if (mQa.legPairQa) { fillLegPairMC(truthType, legObs, obs.kt); } if (doFR) { @@ -2331,7 +2796,7 @@ struct Photonhbt { addToPool(g1, pwl1); addToPool(g2, pwl2); } - if (mDoSinglePhotonQa) { + if (mQa.singlePhotonQa) { for (const auto& g : photonsColl) { if (cut.template IsSelected(g)) { if (idsAfterPairCuts.contains(g.globalIndex())) { @@ -2385,7 +2850,7 @@ struct Photonhbt { if (obs.drOverCosOA < ggpaircuts.cfgMinDRCosOA) { continue; } - if (!passLegSepCut(sep)) { + if (!passPairMergeCut(sep)) { continue; } if (!passRZCut(obs.deltaR, obs.deltaZ)) { @@ -2727,21 +3192,6 @@ struct Photonhbt { fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hRconv1_vs_Rconv2_bothPhotonsSelected"), g1.rTrue, g2.rTrue); } } - const float ut = uTrue(g1, g2); - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsKt_truthConverted"), kt, ut); - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsQinv_truthConverted"), qinv_true, ut); - if (pairAll4LegsThisColl) { - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsKt_all4LegsThisColl"), kt, ut); - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsQinv_all4LegsThisColl"), qinv_true, ut); - } - if (g1Built && g2Built) { - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsKt_bothPhotonsBuilt"), kt, ut); - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsQinv_bothPhotonsBuilt"), qinv_true, ut); - } - if (g1Sel && g2Sel && pairClassSel) { - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsKt_bothPhotonsSelected"), kt, ut); - fRegistryTruthMC.fill(HIST("MC/TruthAO2D/hUtrueVsQinv_bothPhotonsSelected"), qinv_true, ut); - } const float minRconv = (g1.rTrue >= 0.f && g2.rTrue >= 0.f) ? std::min(g1.rTrue, g2.rTrue) : (g1.rTrue >= 0.f ? g1.rTrue : g2.rTrue); From cebee0da90928621745f6b2e5a0657d6eeaa86b2 Mon Sep 17 00:00:00 2001 From: prottayCMT <61418725+prottayCMT@users.noreply.github.com> Date: Wed, 29 Jul 2026 22:33:13 +0200 Subject: [PATCH 38/71] [PWGLF] Updated mixing (#17258) Co-authored-by: Prottay Das --- PWGLF/Tasks/Resonances/phiflowder.cxx | 126 ++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/PWGLF/Tasks/Resonances/phiflowder.cxx b/PWGLF/Tasks/Resonances/phiflowder.cxx index 956dc39356b..f415d00b1db 100644 --- a/PWGLF/Tasks/Resonances/phiflowder.cxx +++ b/PWGLF/Tasks/Resonances/phiflowder.cxx @@ -17,7 +17,9 @@ #include "PWGLF/DataModel/LFPhiFlowTables.h" #include +#include #include +#include #include #include #include @@ -27,9 +29,11 @@ #include +#include #include #include #include +#include using namespace o2; using namespace o2::framework; @@ -63,6 +67,7 @@ struct phiflowder { /*Configurable ptMix{"ptMix", 0.2f, "ME: pT bin width"}; Configurable etaMix{"etaMix", 0.2f, "ME: eta bin width"}; Configurable phiMix{"phiMix", 0.3f, "ME: phi bin width"};*/ + ConfigurableAxis cfgSPAngleBins{"cfgSPAngleBins", {12, 0.0, 2.0 * TMath::Pi()}, "Mixing bins - odd spectator-plane angle"}; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -476,6 +481,127 @@ struct phiflowder { } PROCESS_SWITCH(phiflowder, processMixedData, "Process mixed-event K+K- pairs", true); + + // Processing Event Mixing + void processMixedData2(EventCandidates const& collisions, + aod::KaonTracks const& /*kaontracks*/) + { + // Calculate the odd spectator-plane angle directly + // from the Q vectors already stored in KaonEvents. + auto getSPAngle = + [](EventCandidates::iterator const& collision) -> float { + const float qxOdd = + collision.qxA() - collision.qxC(); + + const float qyOdd = + collision.qyA() - collision.qyC(); + + float psiSP = + std::atan2(qyOdd, qxOdd); + + // Put first-harmonic angle in [0, 2pi). + if (psiSP < 0.f) { + psiSP += 2.f * TMath::Pi(); + } + + return psiSP; + }; + + using BinningTypeSP = + FlexibleBinningPolicy< + std::tuple, + aod::kaonevent::Posz, + aod::kaonevent::Cent, + decltype(getSPAngle)>; + + BinningTypeSP binningOnSPAngle{ + {getSPAngle}, + {cfgVtxBins, + cfgCentBins, + cfgSPAngleBins}, + true}; + + for (const auto& [collision1, collision2] : + selfCombinations(binningOnSPAngle, + nEvtMixing.value, + -1, + collisions, + collisions)) { + + if (collision1.globalIndex() == + collision2.globalIndex()) { + continue; + } + + const float centrality = + collision1.cent(); + + const float qxZDCA = + collision1.qxA(); + + const float qyZDCA = + collision1.qyA(); + + const float qxZDCC = + collision1.qxC(); + + const float qyZDCC = + collision1.qyC(); + + // K+ from event 1 and K- from event 2. + auto posGroup1 = + posKaons->sliceByCached( + aod::kaonpair::kaoneventId, + collision1.globalIndex(), + cache); + + auto negGroup2 = + negKaons->sliceByCached( + aod::kaonpair::kaoneventId, + collision2.globalIndex(), + cache); + + // K+ from event 2 and K- from event 1. + auto posGroup2 = + posKaons->sliceByCached( + aod::kaonpair::kaoneventId, + collision2.globalIndex(), + cache); + + auto negGroup1 = + negKaons->sliceByCached( + aod::kaonpair::kaoneventId, + collision1.globalIndex(), + cache); + + int nMixedPairs = 0; + + // Both combinations use centrality and Q vectors + // from collision1. + nMixedPairs += + fillMixedPairs(posGroup1, + negGroup2, + centrality, + qxZDCA, + qxZDCC, + qyZDCA, + qyZDCC); + + nMixedPairs += + fillMixedPairs(posGroup2, + negGroup1, + centrality, + qxZDCA, + qxZDCC, + qyZDCA, + qyZDCC); + + histos.fill(HIST("hMixpairs"), + nMixedPairs); + } + } + + PROCESS_SWITCH(phiflowder, processMixedData2, "Process mixed-event K+K- pairs in SP-angle bins", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) From 399f23cf82f1da92b781c5a1570f9ed40bf6c229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Tiek=C3=B6tter?= Date: Wed, 29 Jul 2026 23:11:46 +0200 Subject: [PATCH 39/71] [ALICE3] Fix ALICE 3 DQ datamodel naming (#17252) --- ALICE3/DataModel/ReducedTablesAlice3.h | 335 ++++++++++++++++++ .../TableProducer/alice3-dq-table-maker.cxx | 73 ++-- ALICE3/Tasks/alice3-dq-efficiency.cxx | 216 +++++------ 3 files changed, 477 insertions(+), 147 deletions(-) create mode 100644 ALICE3/DataModel/ReducedTablesAlice3.h diff --git a/ALICE3/DataModel/ReducedTablesAlice3.h b/ALICE3/DataModel/ReducedTablesAlice3.h new file mode 100644 index 00000000000..fdc9275842c --- /dev/null +++ b/ALICE3/DataModel/ReducedTablesAlice3.h @@ -0,0 +1,335 @@ +// 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 ReducedTablesAlice3.h +/// +/// \brief Reduced DQ table definitions for ALICE 3 +/// +/// \author Alexander Tiekoetter (atiekoet@cern.ch) University of Muenster + +#ifndef ALICE3_DATAMODEL_REDUCEDTABLESALICE3_H_ +#define ALICE3_DATAMODEL_REDUCEDTABLESALICE3_H_ + +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "ALICE3/DataModel/OTFPIDTrk.h" +#include "ALICE3/DataModel/OTFRICH.h" +#include "ALICE3/DataModel/OTFTOF.h" + +#include +#include +#include + +#include +#include + +namespace o2::aod +{ +namespace reducedeventalice3 +{ +DECLARE_SOA_COLUMN(MultDensity, multDensity, float); +DECLARE_SOA_COLUMN(MCPosX, mcPosX, float); //! MC event position X +DECLARE_SOA_COLUMN(MCPosY, mcPosY, float); //! MC event position Y +DECLARE_SOA_COLUMN(MCPosZ, mcPosZ, float); //! MC event position Z +} // namespace reducedeventalice3 + +namespace reducedeventmcalice3 +{ +DECLARE_SOA_COLUMN(MultMCNParticlesEta05, multMCNParticlesEta05, float); +DECLARE_SOA_COLUMN(MultMCNParticlesEta08, multMCNParticlesEta08, float); +DECLARE_SOA_COLUMN(MultMCNParticlesEta10, multMCNParticlesEta10, float); +DECLARE_SOA_COLUMN(MultMCNParticlesEta20, multMCNParticlesEta20, float); +DECLARE_SOA_COLUMN(MultMCNParticlesEta40, multMCNParticlesEta40, float); +} // namespace reducedeventmcalice3 + +DECLARE_SOA_TABLE_STAGED(ReA3Events, "REA3EVENT", //! Main event information table + o2::soa::Index<>, + collision::PosX, collision::PosY, collision::PosZ, collision::NumContrib, + collision::CollisionTime, collision::CollisionTimeRes, reducedeventalice3::MultDensity); + +DECLARE_SOA_TABLE(ReducedA3EventsVtxCov, "AOD", "REA3VTXCOV", //! Event vertex covariance matrix + collision::CovXX, collision::CovXY, collision::CovXZ, + collision::CovYY, collision::CovYZ, collision::CovZZ, collision::Chi2); + +DECLARE_SOA_TABLE(ReducedA3EventsInfo, "AOD", "REA3EVENTINFO", //! Main event index table + reducedevent::CollisionId); + +DECLARE_SOA_TABLE(ReA3MCEvents, "AOD", "REA3MCEVENT", //! Event level MC truth information + o2::soa::Index<>, + mccollision::GeneratorsID, reducedeventalice3::MCPosX, reducedeventalice3::MCPosY, reducedeventalice3::MCPosZ, + mccollision::T, mccollision::Weight, mccollision::ImpactParameter); + +using ReducedA3MCEvent = ReA3MCEvents::iterator; +using ReA3Event = ReA3Events::iterator; + +namespace reducedtrackalice3 +{ +// basic track information +DECLARE_SOA_INDEX_COLUMN(ReA3Event, rea3event); //! +DECLARE_SOA_INDEX_COLUMN(Track, track); //! +// ---- flags reserved for storing various information during filtering +DECLARE_SOA_BITMAP_COLUMN(FilteringFlags, filteringFlags, 64); //! +// ----------------------------------------------------- + +DECLARE_SOA_COLUMN(IsReconstructed, isReconstructed, bool); +DECLARE_SOA_COLUMN(NSiliconHits, nSiliconHits, int); +DECLARE_SOA_COLUMN(NTPCHits, nTPCHits, int); + +DECLARE_SOA_COLUMN(Pt, pt, float); //! +DECLARE_SOA_COLUMN(Eta, eta, float); //! +DECLARE_SOA_COLUMN(Phi, phi, float); //! +DECLARE_SOA_COLUMN(Sign, sign, int); //! +DECLARE_SOA_COLUMN(IsAmbiguous, isAmbiguous, int); //! +DECLARE_SOA_COLUMN(DcaXY, dcaXY, float); //! +DECLARE_SOA_COLUMN(DcaZ, dcaZ, float); //! +DECLARE_SOA_COLUMN(DetectorMap, detectorMap, uint8_t); //! Detector map: see enum DetectorMapEnum +DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! +DECLARE_SOA_DYNAMIC_COLUMN(HasITS, hasITS, //! Flag to check if track has a ITS match + [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::ITS; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTPC, hasTPC, //! Flag to check if track has a TPC match + [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TPC; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTRD, hasTRD, //! Flag to check if track has a TRD match + [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TRD; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTOF, hasTOF, //! Flag to check if track has a TOF measurement + [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TOF; }); +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! + [](float pt, float phi) -> float { return pt * std::cos(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! + [](float pt, float phi) -> float { return pt * std::sin(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! + [](float pt, float eta) -> float { return pt * std::sinh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! + [](float pt, float eta) -> float { return pt * std::cosh(eta); }); +} // namespace reducedtrackalice3 + +// basic track information +DECLARE_SOA_TABLE(ReA3Tracks, "AOD", "REA3TRACK", //! + o2::soa::Index<>, reducedtrackalice3::ReA3EventId, reducedtrackalice3::FilteringFlags, + reducedtrackalice3::Pt, reducedtrackalice3::Eta, reducedtrackalice3::Phi, reducedtrackalice3::Sign, reducedtrackalice3::IsAmbiguous, + reducedtrackalice3::Px, + reducedtrackalice3::Py, + reducedtrackalice3::Pz, + reducedtrackalice3::P); + +DECLARE_SOA_TABLE(ReducedA3TracksBarrelCov, "AOD", "REA3BARRELCOV", //! + track::CYY, track::CZY, track::CZZ, track::CSnpY, track::CSnpZ, + track::CSnpSnp, track::CTglY, track::CTglZ, track::CTglSnp, track::CTglTgl, + track::C1PtY, track::C1PtZ, track::C1PtSnp, track::C1PtTgl, track::C1Pt21Pt2); + +namespace reducedA3trackMC +{ +DECLARE_SOA_INDEX_COLUMN(ReA3MCEvent, reA3MCEvent); //! +DECLARE_SOA_COLUMN(McReducedFlags, mcReducedFlags, uint16_t); //! Flags to hold compressed MC selection information +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Mother0, mother0, int, "ReA3MCTracks_Mother0"); //! Track index of the first mother +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Mother1, mother1, int, "ReA3MCTracks_Mother1"); //! Track index of the last mother +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Daughter0, daughter0, int, "ReA3MCTracks_Daughter0"); //! Track index of the first daughter +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(Daughter1, daughter1, int, "ReA3MCTracks_Daughter1"); //! Track index of the last daughter +DECLARE_SOA_SELF_ARRAY_INDEX_COLUMN(Mothers, mothers); //! Mother tracks (possible empty) array. Iterate over mcParticle.mothers_as()) +DECLARE_SOA_SELF_SLICE_INDEX_COLUMN(Daughters, daughters); //! Daughter tracks (possibly empty) slice. Check for non-zero with mcParticle.has_daughters(). Iterate over mcParticle.daughters_as()) +DECLARE_SOA_COLUMN(Pt, pt, float); //! +DECLARE_SOA_COLUMN(Eta, eta, float); //! +DECLARE_SOA_COLUMN(Phi, phi, float); //! +DECLARE_SOA_COLUMN(E, e, float); //! +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! + [](float pt, float phi) -> float { return pt * std::cos(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, //! + [](float pt, float phi) -> float { return pt * std::sin(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! + [](float pt, float eta) -> float { return pt * std::sinh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, //! + [](float pt, float eta) -> float { return pt * std::cosh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(Y, y, //! Particle rapidity + [](float pt, float eta, float e) -> float { + float pz = pt * std::sinh(eta); + if ((e - pz) > static_cast(1e-7)) { + return 0.5f * std::log((e + pz) / (e - pz)); + } else { + return -999.0f; + } + }); +} // namespace reducedA3trackMC + +// NOTE: This table is nearly identical to the one from Framework (except that it points to the event ID, not the BC id) +// This table contains all MC truth tracks (both barrel and muon) +DECLARE_SOA_TABLE(ReA3MCTracks, "AOD", "REA3MCTRACK", //! MC track information (on disk) + o2::soa::Index<>, reducedA3trackMC::ReA3MCEventId, + mcparticle::PdgCode, mcparticle::StatusCode, mcparticle::Flags, + reducedA3trackMC::MothersIds, reducedA3trackMC::DaughtersIdSlice, + mcparticle::Weight, + reducedA3trackMC::Pt, reducedA3trackMC::Eta, reducedA3trackMC::Phi, reducedA3trackMC::E, + mcparticle::Vx, mcparticle::Vy, mcparticle::Vz, mcparticle::Vt, + reducedA3trackMC::McReducedFlags, + reducedA3trackMC::Px, + reducedA3trackMC::Py, + reducedA3trackMC::Pz, + reducedA3trackMC::P, + reducedA3trackMC::Y, + mcparticle::ProducedByGenerator, + mcparticle::FromBackgroundEvent, + mcparticle::GetGenStatusCode, + mcparticle::GetProcess, + mcparticle::GetHepMCStatusCode, + mcparticle::IsPhysicalPrimary); + +using ReA3MCTrack = ReA3MCTracks::iterator; + +namespace reduceda3barreltracklabel +{ +DECLARE_SOA_INDEX_COLUMN(ReA3MCTrack, reA3MCTrack); //! +DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); +} // namespace reduceda3barreltracklabel + +// NOTE: MC labels. This table has one entry for each reconstructed track (joinable with the track tables) +// The McParticleId points to the position of the MC truth track from the ReducedTracksMC table +DECLARE_SOA_TABLE(ReducedA3TracksBarrelLabels, "AOD", "REA3BARLA", //! + reduceda3barreltracklabel::ReA3MCTrackId, reduceda3barreltracklabel::McMask, reducedA3trackMC::McReducedFlags); + +using ReducedA3TrackBarrelLabel = ReducedA3TracksBarrelLabels::iterator; + +DECLARE_SOA_TABLE(ReducedA3TracksBarrel, "AOD", "REA3BARREL", + track::X, track::Alpha, track::IsWithinBeamPipe, + track::Y, track::Z, track::Snp, track::Tgl, track::Signed1Pt, + track::Flags, track::ITSClusterMap, track::ITSChi2NCl, + reducedtrackalice3::IsReconstructed, reducedtrackalice3::NSiliconHits, + reducedtrackalice3::NTPCHits, track::Length, reducedtrack::DcaXY, reducedtrack::DcaZ, + track::IsPVContributor); + +// barrel collision information (joined with ReducedTracks) allowing to connect different tables (cross PWGs) +DECLARE_SOA_TABLE(ReducedA3TracksBarrelInfo, "AOD", "REA3BARRELINFO", + reducedtrackalice3::CollisionId, collision::PosX, collision::PosY, collision::PosZ, reducedtrackalice3::TrackId); + +using ReducedA3Track = ReA3Tracks::iterator; +using ReducedA3TrackBarrel = ReducedA3TracksBarrel::iterator; +using ReducedA3TrackBarrelCov = ReducedA3TracksBarrelCov::iterator; +using ReducedA3TrackBarrelInfo = ReducedA3TracksBarrelInfo::iterator; + +namespace reducedeventlabela3 +{ +DECLARE_SOA_INDEX_COLUMN(ReA3MCEvent, reA3MCEvent); //! MC collision +DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); //! Bit mask to indicate collision mismatches (bit ON means mismatch). Bit 15: indicates negative label +} // namespace reducedeventlabela3 + +DECLARE_SOA_TABLE(ReducedA3MCEventLabels, "AOD", "REA3MCCOLLBL", //! Table joined to the ReducedEvents table containing the MC index + reducedeventlabela3::ReA3MCEventId, reducedeventlabela3::McMask); + +using ReducedA3MCEventLabel = ReducedA3MCEventLabels::iterator; + +namespace reducedA3track_association +{ +DECLARE_SOA_INDEX_COLUMN(ReA3Event, reA3event); //! ReducedEvent index +DECLARE_SOA_INDEX_COLUMN(ReA3Track, reA3track); //! ReducedTrack index +} // namespace reducedA3track_association + +DECLARE_SOA_TABLE(ReducedA3TracksAssoc, "AOD", "REA3ASSOC", //! Table for reducedtrack-to-reducedcollision association + reducedA3track_association::ReA3EventId, + reducedA3track_association::ReA3TrackId); + +DECLARE_SOA_TABLE(ReducedA3PIDTOF, "AOD", "REA3PIDTOF", + upgrade_tof::TOFEventTime, + upgrade_tof::TOFEventTimeErr, + upgrade_tof::NSigmaElectronInnerTOF, + upgrade_tof::NSigmaMuonInnerTOF, + upgrade_tof::NSigmaPionInnerTOF, + upgrade_tof::NSigmaKaonInnerTOF, + upgrade_tof::NSigmaProtonInnerTOF, + upgrade_tof::NSigmaDeuteronInnerTOF, + upgrade_tof::NSigmaTritonInnerTOF, + upgrade_tof::NSigmaHelium3InnerTOF, + upgrade_tof::NSigmaAlphaInnerTOF, + upgrade_tof::InnerTOFTrackTimeReco, + upgrade_tof::InnerTOFTrackLengthReco, + upgrade_tof::NSigmaElectronOuterTOF, + upgrade_tof::NSigmaMuonOuterTOF, + upgrade_tof::NSigmaPionOuterTOF, + upgrade_tof::NSigmaKaonOuterTOF, + upgrade_tof::NSigmaProtonOuterTOF, + upgrade_tof::NSigmaDeuteronOuterTOF, + upgrade_tof::NSigmaTritonOuterTOF, + upgrade_tof::NSigmaHelium3OuterTOF, + upgrade_tof::NSigmaAlphaOuterTOF, + upgrade_tof::OuterTOFTrackTimeReco, + upgrade_tof::OuterTOFTrackLengthReco, + upgrade_tof::NSigmaInnerTOF, + upgrade_tof::NSigmaOuterTOF); + +DECLARE_SOA_TABLE(ReducedA3PIDRich, "AOD", "REA3PIDRICH", + upgrade_rich::NSigmaElectronRich, + upgrade_rich::NSigmaMuonRich, + upgrade_rich::NSigmaPionRich, + upgrade_rich::NSigmaKaonRich, + upgrade_rich::NSigmaProtonRich, + upgrade_rich::NSigmaDeuteronRich, + upgrade_rich::NSigmaTritonRich, + upgrade_rich::NSigmaHelium3Rich, + upgrade_rich::NSigmaAlphaRich, + upgrade_rich::NSigmaRich); + +DECLARE_SOA_TABLE(ReducedA3PIDRichSignals, "AOD", "REA3PIDRICHSIG", + upgrade_rich::HasSig, + upgrade_rich::HasSigInGas, + upgrade_rich::HasSigEl, + upgrade_rich::HasSigMu, + upgrade_rich::HasSigPi, + upgrade_rich::HasSigKa, + upgrade_rich::HasSigPr, + upgrade_rich::HasSigDe, + upgrade_rich::HasSigTr, + upgrade_rich::HasSigHe3, + upgrade_rich::HasSigAl); + +DECLARE_SOA_TABLE(ReducedA3PIDOT, "AOD", "REA3PIDOT", + upgrade::trk::TimeOverThresholdBarrel, + upgrade::trk::NSigmaTrkEl, + upgrade::trk::NSigmaTrkMu, + upgrade::trk::NSigmaTrkPi, + upgrade::trk::NSigmaTrkKa, + upgrade::trk::NSigmaTrkPr, + upgrade::trk::NSigmaTrkDe, + upgrade::trk::NSigmaTrkTr, + upgrade::trk::NSigmaTrkHe, + upgrade::trk::NSigmaTrkAl, + upgrade::trk::NSigmaTrk); + +} // namespace o2::aod + +#endif // ALICE3_DATAMODEL_REDUCEDTABLESALICE3_H_ diff --git a/ALICE3/TableProducer/alice3-dq-table-maker.cxx b/ALICE3/TableProducer/alice3-dq-table-maker.cxx index a6f36151732..8099fb83f8c 100644 --- a/ALICE3/TableProducer/alice3-dq-table-maker.cxx +++ b/ALICE3/TableProducer/alice3-dq-table-maker.cxx @@ -22,10 +22,10 @@ #include "PWGDQ/Core/MCSignal.h" #include "PWGDQ/Core/MCSignalLibrary.h" #include "PWGDQ/Core/VarManager.h" -#include "PWGDQ/DataModel/ReducedTablesAlice3.h" #include "ALICE3/DataModel/OTFRICH.h" #include "ALICE3/DataModel/OTFTOF.h" +#include "ALICE3/DataModel/ReducedTablesAlice3.h" #include "ALICE3/DataModel/collisionAlice3.h" #include "ALICE3/DataModel/tracksAlice3.h" #include "Common/CCDB/EventSelectionParams.h" @@ -74,16 +74,14 @@ constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::Track | struct Alice3DQTableMaker { - Produces eventMC; - Produces trackMC; + Produces eventMC; + Produces trackMC; - Produces event; + Produces event; Produces eventVtxCov; - Produces eventInfo; Produces eventMClabels; - Produces trackBarrelInfo; - Produces trackBasic; + Produces trackBasic; Produces trackBarrel; Produces trackBarrelCov; Produces trackBarrelAssoc; @@ -96,7 +94,7 @@ struct Alice3DQTableMaker { OutputObj fOutputList{"output"}; OutputObj fStatsList{"Statistics"}; //! skimming statistics - HistogramManager* fHistMan; + HistogramManager* fHistMan = nullptr; // Event and track AnalysisCut configurables struct : ConfigurableGroup { @@ -120,9 +118,8 @@ struct Alice3DQTableMaker { Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; } fConfigHistOutput; - AnalysisCompositeCut* fEventCut; //! Event selection cut + AnalysisCompositeCut* fEventCut = nullptr; //! Event selection cut std::vector fTrackCuts; //! Barrel track cuts - std::vector fMuonCuts; //! Muon track cuts bool fDoDetailedQA = false; @@ -290,38 +287,38 @@ struct Alice3DQTableMaker { } } - // create statistics histograms (event, tracks, muons, MCsignals) + // create statistics histograms (event, tracks, MCsignals) fStatsList.setObject(new TList()); fStatsList->SetOwner(true); std::vector eventLabels{"Collisions before filtering", "Before cuts", "After cuts"}; TH2I* histEvents = new TH2I("EventStats", "Event statistics", eventLabels.size(), -0.5, eventLabels.size() - 0.5, o2::aod::evsel::kNsel + 1, -0.5, (float)o2::aod::evsel::kNsel + 0.5); - int ib = 1; - for (auto label = eventLabels.begin(); label != eventLabels.end(); label++, ib++) { - histEvents->GetXaxis()->SetBinLabel(ib, (*label).Data()); + int ibX = 1; + for (auto label = eventLabels.begin(); label != eventLabels.end(); label++, ibX++) { + histEvents->GetXaxis()->SetBinLabel(ibX, (*label).Data()); } - for (int ib = 1; ib <= o2::aod::evsel::kNsel; ib++) { - histEvents->GetYaxis()->SetBinLabel(ib, o2::aod::evsel::selectionLabels[ib - 1]); + for (int ibY = 1; ibY <= o2::aod::evsel::kNsel; ibY++) { + histEvents->GetYaxis()->SetBinLabel(ibY, o2::aod::evsel::selectionLabels[ibY - 1]); } histEvents->GetYaxis()->SetBinLabel(o2::aod::evsel::kNsel + 1, "Total"); fStatsList->Add(histEvents); // Track statistics: one bin for each track selection and 5 bins for V0 tags (gamma, K0s, Lambda, anti-Lambda, Omega) TH1I* histTracks = new TH1I("TrackStats", "Track statistics", fTrackCuts.size() + 5.0, -0.5, fTrackCuts.size() - 0.5 + 5.0); - ib = 1; - for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, ib++) { - histTracks->GetXaxis()->SetBinLabel(ib, (*cut)->GetName()); + ibX = 1; + for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, ibX++) { + histTracks->GetXaxis()->SetBinLabel(ibX, (*cut)->GetName()); } constexpr int nV0Tags = 5; const char* v0TagNames[nV0Tags] = {"Photon conversion", "K^{0}_{s}", "#Lambda", "#bar{#Lambda}", "#Omega"}; - for (int ib = 0; ib < nV0Tags; ib++) { - histTracks->GetXaxis()->SetBinLabel(fTrackCuts.size() + 1 + ib, v0TagNames[ib]); + for (int ibY = 0; ibY < nV0Tags; ibY++) { + histTracks->GetXaxis()->SetBinLabel(fTrackCuts.size() + 1 + ibY, v0TagNames[ibY]); } fStatsList->Add(histTracks); TH1I* histMCsignals = new TH1I("MCsignals", "MC signals", fMCSignals.size() + 1, -0.5, fMCSignals.size() - 0.5 + 1.0); - ib = 1; - for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); signal++, ib++) { - histMCsignals->GetXaxis()->SetBinLabel(ib, (*signal)->GetName()); + ibX = 1; + for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); signal++, ibX++) { + histMCsignals->GetXaxis()->SetBinLabel(ibX, (*signal)->GetName()); } histMCsignals->GetXaxis()->SetBinLabel(fMCSignals.size() + 1, "Others (matched to reco tracks)"); fStatsList->Add(histMCsignals); @@ -384,19 +381,22 @@ struct Alice3DQTableMaker { } // If this MC track was not already added to the map, add it now - if (fLabelsMap.find(mctrack.globalIndex()) == fLabelsMap.end()) { - fLabelsMap[mctrack.globalIndex()] = trackCounter; - fLabelsMapReversed[trackCounter] = mctrack.globalIndex(); - fMCFlags[mctrack.globalIndex()] = mcflags; - trackCounter++; + const auto mcTrackIndex = mctrack.globalIndex(); + const bool inserted = fLabelsMap.try_emplace(mcTrackIndex, trackCounter).second; + + if (inserted) { + fLabelsMapReversed.try_emplace(trackCounter, mcTrackIndex); + fMCFlags.try_emplace(mcTrackIndex, mcflags); + ++trackCounter; // fill histograms for each of the signals, if found if (fConfigHistOutput.fConfigQA) { VarManager::FillTrackMC(mcTracks, mctrack); auto mcCollision = mctrack.template mcCollision_as(); VarManager::FillEvent(mcCollision); + int j = 0; - for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); signal++, j++) { + for (auto signal = fMCSignals.begin(); signal != fMCSignals.end(); ++signal, ++j) { if (mcflags & (static_cast(1) << j)) { fHistMan->FillHistClass(Form("MCTruth_%s", (*signal)->GetName()), VarManager::fgValues); } @@ -444,7 +444,6 @@ struct Alice3DQTableMaker { eventVtxCov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); eventMClabels(collision.mcCollisionId(), collision.mcMask()); - eventInfo(collision.globalIndex()); // add an element for this collision into the map fCollIndexMap[collision.globalIndex()] = event.lastIndex(); @@ -484,14 +483,14 @@ struct Alice3DQTableMaker { fHistMan->FillHistClass("TrackBarrel_BeforeCuts", VarManager::fgValues); } - int i = 0; - for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, i++) { + int n = 0; + for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, n++) { if ((*cut)->IsSelected(VarManager::fgValues)) { - trackTempFilterMap |= (static_cast(1) << i); + trackTempFilterMap |= (static_cast(1) << n); if (fConfigHistOutput.fConfigQA) { fHistMan->FillHistClass(Form("TrackBarrel_%s", (*cut)->GetName()), VarManager::fgValues); } - (reinterpret_cast(fStatsList->At(1)))->Fill(static_cast(i)); + (reinterpret_cast(fStatsList->At(1)))->Fill(static_cast(n)); } } if (!trackTempFilterMap) { @@ -512,9 +511,6 @@ struct Alice3DQTableMaker { // In the case of Run2-like analysis, there will be no associations, so this ID will be the one originally assigned in the AO2Ds (updated for the skims) uint32_t reducedEventIdx = fCollIndexMap[track.collisionId()]; - // NOTE: trackBarrelInfo stores the index of the collision as in AO2D (for use in some cases where the analysis on skims is done - // in workflows where the original AO2Ds are also present) - // trackBarrelInfo(track.collisionId(), collision.posX(), collision.posY(), collision.posZ(), track.globalIndex()); trackBasic(reducedEventIdx, trackFilteringTag, track.pt(), track.eta(), track.phi(), track.sign(), 0); trackBarrel(track.x(), track.alpha(), track.y(), track.z(), track.snp(), track.tgl(), track.signed1Pt(), @@ -612,7 +608,6 @@ struct Alice3DQTableMaker { event.reserve(collisions.size()); eventVtxCov.reserve(collisions.size()); eventMClabels.reserve(collisions.size()); - eventInfo.reserve(collisions.size()); skimCollisions(collisions); diff --git a/ALICE3/Tasks/alice3-dq-efficiency.cxx b/ALICE3/Tasks/alice3-dq-efficiency.cxx index b93d9039035..0e2765cff34 100644 --- a/ALICE3/Tasks/alice3-dq-efficiency.cxx +++ b/ALICE3/Tasks/alice3-dq-efficiency.cxx @@ -24,8 +24,8 @@ #include "PWGDQ/Core/MixingLibrary.h" #include "PWGDQ/Core/VarManager.h" #include "PWGDQ/DataModel/ReducedInfoTables.h" -#include "PWGDQ/DataModel/ReducedTablesAlice3.h" +#include "ALICE3/DataModel/ReducedTablesAlice3.h" #include "Common/Core/TableHelper.h" #include @@ -111,23 +111,23 @@ DECLARE_SOA_TABLE(OniaMCTruth, "AOD", "MCTRUTHONIA", dqanalysisflags::OniaPt, dq // TODO: USE PROPER TABLES -using MyEvents = soa::Join; -using MyEventsSelected = soa::Join; -using MyEventsVtxCov = soa::Join; -using MyEventsVtxCovSelected = soa::Join; +using MyEvents = soa::Join; +using MyEventsSelected = soa::Join; +using MyEventsVtxCov = soa::Join; +using MyEventsVtxCovSelected = soa::Join; using MyBarrelAssocs = soa::Join; using MyBarrelAssocsPrefilter = soa::Join; -using MyBarrelTracks = soa::Join; -using MyBarrelTracksWithCov = soa::Join; -using MyBarrelTracksWithCovWithAmbiguities = soa::Join; @@ -218,7 +218,7 @@ struct AnalysisEventSelection { } } - void runEventSelection(MyEventsVtxCov const& events, ReducedA3MCEvents const& mcEvents) + void runEventSelection(MyEventsVtxCov const& events, ReA3MCEvents const& mcEvents) { fSelMap.clear(); @@ -226,8 +226,8 @@ struct AnalysisEventSelection { // Reset the fValues array and fill event observables VarManager::ResetValues(0, VarManager::kNEventWiseVariables); VarManager::FillEventAlice3(event); - if (event.has_reducedA3MCEvent()) { - VarManager::FillEventAlice3(event.reducedA3MCEvent()); + if (event.has_reA3MCEvent()) { + VarManager::FillEventAlice3(event.reA3MCEvent()); } bool decision = false; @@ -271,7 +271,7 @@ struct AnalysisEventSelection { } } - void processSkimmed(MyEventsVtxCov const& events, aod::ReducedA3MCEvents const& mcEvents) + void processSkimmed(MyEventsVtxCov const& events, aod::ReA3MCEvents const& mcEvents) { runEventSelection(events, mcEvents); publishSelections(events); @@ -392,7 +392,7 @@ struct AnalysisTrackSelection { } } - void runTrackSelection(ReducedA3TracksAssoc const& assocs, MyEventsVtxCovSelected const& /*events*/, MyBarrelTracksWithCov const& tracks, ReducedA3MCEvents const& /*eventsMC*/, ReducedA3MCTracks const& tracksMC) + void runTrackSelection(ReducedA3TracksAssoc const& assocs, MyEventsVtxCovSelected const& /*events*/, MyBarrelTracksWithCov const& tracks, ReA3MCEvents const& /*eventsMC*/, ReA3MCTracks const& tracksMC) { fNAssocsInBunch.clear(); fNAssocsOutOfBunch.clear(); @@ -402,7 +402,7 @@ struct AnalysisTrackSelection { // Loop over associations for (const auto& assoc : assocs) { - auto event = assoc.template reducedA3event_as(); + auto event = assoc.template reA3event_as(); if (!event.isEventSelected_bit(0)) { trackSel(0); continue; @@ -411,21 +411,21 @@ struct AnalysisTrackSelection { VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); // fill event information which might be needed in histograms/cuts that combine track and event properties VarManager::FillEventAlice3(event); - if (event.has_reducedA3MCEvent()) { - VarManager::FillEventAlice3(event.reducedA3MCEvent()); + if (event.has_reA3MCEvent()) { + VarManager::FillEventAlice3(event.reA3MCEvent()); } - auto track = assoc.template reducedA3track_as(); + auto track = assoc.template reA3track_as(); VarManager::FillTrackAlice3(track); // compute quantities which depend on the associated collision, such as DCA VarManager::FillTrackCollision(track, event); bool isCorrectAssoc = false; - if (track.has_reducedA3MCTrack()) { - auto trackMC = track.reducedA3MCTrack(); - auto eventMCfromTrack = trackMC.reducedA3MCEvent(); - if (event.has_reducedA3MCEvent()) { - isCorrectAssoc = (eventMCfromTrack.globalIndex() == event.reducedA3MCEvent().globalIndex()); + if (track.has_reA3MCTrack()) { + auto trackMC = track.reA3MCTrack(); + auto eventMCfromTrack = trackMC.reA3MCEvent(); + if (event.has_reA3MCEvent()) { + isCorrectAssoc = (eventMCfromTrack.globalIndex() == event.reA3MCEvent().globalIndex()); } VarManager::FillTrackMC(tracksMC, trackMC); VarManager::FillResolutions(trackMC, track); @@ -449,11 +449,11 @@ struct AnalysisTrackSelection { // compute MC matching decisions and fill histograms for matched associations int isig = 0; - if (filterMap > 0 && track.has_reducedA3MCTrack()) { + if (filterMap > 0 && track.has_reA3MCTrack()) { // loop over all MC signals for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { // check if this MC signal is matched - if ((*sig)->CheckSignal(true, track.reducedA3MCTrack())) { + if ((*sig)->CheckSignal(true, track.reA3MCTrack())) { // mcDecision |= (static_cast(1) << isig); // loop over cuts and fill histograms for the cuts that are fulfilled for (unsigned int icut = 0; icut < fTrackCuts.size(); icut++) { @@ -535,7 +535,7 @@ struct AnalysisTrackSelection { } } // end runTrackSelection() - void processSkimmedWithCov(ReducedA3TracksAssoc const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCov const& tracks, ReducedA3MCEvents const& eventsMC, ReducedA3MCTracks const& tracksMC) + void processSkimmedWithCov(ReducedA3TracksAssoc const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCov const& tracks, ReA3MCEvents const& eventsMC, ReA3MCTracks const& tracksMC) { runTrackSelection(assocs, events, tracks, eventsMC, tracksMC); } @@ -564,7 +564,7 @@ struct AnalysisPrefilterSelection { uint32_t fPrefilterMask = 0; int fPrefilterCutBit = -1; - PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reducedA3eventId; + PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; void init(o2::framework::InitContext& context) { @@ -651,8 +651,8 @@ struct AnalysisPrefilterSelection { } for (const auto& [assoc1, assoc2] : o2::soa::combinations(assocs, assocs)) { - auto track1 = assoc1.template reducedA3track_as(); - auto track2 = assoc2.template reducedA3track_as(); + auto track1 = assoc1.template reA3track_as(); + auto track2 = assoc2.template reA3track_as(); // NOTE: here we restrict to just pairs of opposite sign (conversions), but in principle this can be made // a configurable and check also same-sign pairs (track splitting) @@ -708,7 +708,7 @@ struct AnalysisPrefilterSelection { } else { for (const auto& assoc : assocs) { // TODO: just use the index from the assoc (no need to cast the whole track) - auto track = assoc.template reducedA3track_as(); + auto track = assoc.template reA3track_as(); mymap = -1; if (!fPrefilterMap.contains(track.globalIndex())) { // NOTE: publish the bitwise negated bits (~), so there will be zeroes for cuts that failed the prefiltering and 1 everywhere else @@ -795,7 +795,7 @@ struct AnalysisSameEventPairing { bool fEnableBarrelHistos = false; - PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reducedA3eventId; + PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; void init(o2::framework::InitContext& context) { @@ -809,9 +809,9 @@ struct AnalysisSameEventPairing { // Keep track of all the histogram class names to avoid composing strings in the pairing loop TString histNames = ""; - TString cutNamesStr = fConfigCuts.pair.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + TString pairCutNamesStr = fConfigCuts.pair.value; + if (!pairCutNamesStr.IsNull()) { + std::unique_ptr objArray(pairCutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { fPairCuts.push_back(*dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); } @@ -909,9 +909,9 @@ struct AnalysisSameEventPairing { // if there are pair cuts specified, assign hist directories for each barrel cut - pair cut combination // NOTE: This could possibly lead to large histogram outputs. It is strongly advised to use pair cuts only // if you know what you are doing. - TString pairCutNamesStr = fConfigCuts.pair.value; - if (!pairCutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(pairCutNamesStr.Tokenize(",")); + TString pairCutHistNamesStr = fConfigCuts.pair.value; + if (!pairCutHistNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(pairCutHistNamesStr.Tokenize(",")); fNPairCuts = objArrayPair->GetEntries(); for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts names = { @@ -1002,7 +1002,7 @@ struct AnalysisSameEventPairing { } // Template function to run same event pairing (barrel-barrel) - void runSameEventPairing(MyEventsVtxCovSelected const& events, PresliceUnsorted& preslice, MyBarrelAssocsPrefilter const& assocs, MyBarrelTracksWithCovWithAmbiguities const& /*tracks*/, ReducedA3MCEvents const& /*mcEvents*/, ReducedA3MCTracks const& /*mcTracks*/) + void runSameEventPairing(MyEventsVtxCovSelected const& events, PresliceUnsorted& preslice, MyBarrelAssocsPrefilter const& assocs, MyBarrelTracksWithCovWithAmbiguities const& /*tracks*/, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& /*mcTracks*/) { if (events.size() == 0) { LOG(warning) << "No events in this TF, going to the next one ..."; @@ -1049,7 +1049,7 @@ struct AnalysisSameEventPairing { // Reset the fValues array VarManager::ResetValues(0, VarManager::kNVars); VarManager::FillEventAlice3(event, dqefficiency_helpers::varValues()); - VarManager::FillEventAlice3(event.reducedA3MCEvent(), dqefficiency_helpers::varValues()); + VarManager::FillEventAlice3(event.reA3MCEvent(), dqefficiency_helpers::varValues()); auto groupedAssocs = assocs.sliceBy(preslice, event.globalIndex()); if (groupedAssocs.size() == 0) { @@ -1064,8 +1064,8 @@ struct AnalysisSameEventPairing { continue; } - auto t1 = a1.template reducedA3track_as(); - auto t2 = a2.template reducedA3track_as(); + auto t1 = a1.template reA3track_as(); + auto t2 = a2.template reA3track_as(); sign1 = t1.sign(); sign2 = t2.sign(); // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter @@ -1086,15 +1086,15 @@ struct AnalysisSameEventPairing { int iSigMc = 0; mcDecision = 0; for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, iSigMc++) { - if (t1.has_reducedA3MCTrack() && t2.has_reducedA3MCTrack()) { - if ((*sig)->CheckSignal(true, t1.reducedA3MCTrack(), t2.reducedA3MCTrack())) { + if (t1.has_reA3MCTrack() && t2.has_reA3MCTrack()) { + if ((*sig)->CheckSignal(true, t1.reA3MCTrack(), t2.reA3MCTrack())) { mcDecision |= (static_cast(1) << iSigMc); } } } // end loop over MC signals - if (t1.has_reducedA3MCTrack() && t2.has_reducedA3MCTrack()) { - isCorrectAssoc_leg1 = (t1.reducedA3MCTrack().reducedA3MCEvent() == event.reducedA3MCEvent()); - isCorrectAssoc_leg2 = (t2.reducedA3MCTrack().reducedA3MCEvent() == event.reducedA3MCEvent()); + if (t1.has_reA3MCTrack() && t2.has_reA3MCTrack()) { + isCorrectAssoc_leg1 = (t1.reA3MCTrack().reA3MCEvent() == event.reA3MCEvent()); + isCorrectAssoc_leg2 = (t2.reA3MCTrack().reA3MCEvent() == event.reA3MCEvent()); } VarManager::FillPairAlice3(t1, t2); @@ -1209,9 +1209,9 @@ struct AnalysisSameEventPairing { } // end loop over events } - PresliceUnsorted perReducedMcEvent = aod::reducedA3trackMC::reducedA3MCEventId; + PresliceUnsorted perReducedMcEvent = aod::reducedA3trackMC::reA3MCEventId; - void runMCGenWithGrouping(MyEventsVtxCovSelected const& events, ReducedA3MCEvents const& /*mcEvents*/, ReducedA3MCTracks const& mcTracks) + void runMCGenWithGrouping(MyEventsVtxCovSelected const& events, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& mcTracks) { for (const auto& mctrack : mcTracks) { VarManager::FillTrackMC(mcTracks, mctrack); @@ -1235,12 +1235,12 @@ struct AnalysisSameEventPairing { if (!event.isEventSelected_bit(0)) { continue; } - if (!event.has_reducedA3MCEvent()) { + if (!event.has_reA3MCEvent()) { continue; } for (const auto& track : mcTracks) { - if (track.reducedA3MCEventId() != event.reducedA3MCEventId()) { + if (track.reA3MCEventId() != event.reA3MCEventId()) { continue; } VarManager::FillTrackMC(mcTracks, track); @@ -1264,7 +1264,7 @@ struct AnalysisSameEventPairing { for (const auto& [t1, t2] : combinations(mcTracks, mcTracks)) { auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedA3MCEventId() == t2_raw.reducedA3MCEventId()) { + if (t1_raw.reA3MCEventId() == t2_raw.reA3MCEventId()) { for (const auto& sig : fGenMCSignals) { if (sig->GetNProngs() != TWO_PRONG) { // NOTE: 2-prong signals required here continue; @@ -1286,17 +1286,17 @@ struct AnalysisSameEventPairing { if (!event.isEventSelected_bit(0)) { continue; } - if (!event.has_reducedA3MCEvent()) { + if (!event.has_reA3MCEvent()) { continue; } // CURRENTLY ONLY FOR 1-GENERATION 2-PRONG SIGNALS if (fHasTwoProngGenMCsignals) { - auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedA3MCEventId()); + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reA3MCEventId()); groupedMCTracks.bindInternalIndicesTo(&mcTracks); for (const auto& [t1, t2] : combinations(groupedMCTracks, groupedMCTracks)) { auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedA3MCEventId() == t2_raw.reducedA3MCEventId()) { + if (t1_raw.reA3MCEventId() == t2_raw.reA3MCEventId()) { for (const auto& sig : fGenMCSignals) { if (sig->GetNProngs() != TWO_PRONG) { // NOTE: 2-prong signals required here continue; @@ -1319,15 +1319,15 @@ struct AnalysisSameEventPairing { void processBarrelOnlySkimmed(MyEventsVtxCovSelected const& events, MyBarrelAssocsPrefilter const& barrelAssocs, - MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, ReducedA3MCEvents const& mcEvents, ReducedA3MCTracks const& mcTracks) + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, ReA3MCEvents const& mcEvents, ReA3MCTracks const& mcTracks) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); runMCGenWithGrouping(events, mcEvents, mcTracks); } - PresliceUnsorted perReducedMcGenEvent = aod::reducedA3trackMC::reducedA3MCEventId; + PresliceUnsorted perReducedMcGenEvent = aod::reducedA3trackMC::reA3MCEventId; - void processMCGen(soa::Filtered const& events, ReducedA3MCEvents const& /*mcEvents*/, ReducedA3MCTracks const& mcTracks) + void processMCGen(soa::Filtered const& events, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& mcTracks) { for (const auto& mctrack : mcTracks) { VarManager::FillTrackMC(mcTracks, mctrack); @@ -1346,14 +1346,14 @@ struct AnalysisSameEventPairing { if (!event.isEventSelected_bit(0)) { continue; } - if (!event.has_reducedA3MCEvent()) { + if (!event.has_reA3MCEvent()) { continue; } VarManager::FillEventAlice3(event, dqefficiency_helpers::varValues()); - VarManager::FillEventAlice3(event.reducedA3MCEvent(), dqefficiency_helpers::varValues()); + VarManager::FillEventAlice3(event.reA3MCEvent(), dqefficiency_helpers::varValues()); for (const auto& track : mcTracks) { - if (track.reducedA3MCEventId() != event.reducedA3MCEventId()) { + if (track.reA3MCEventId() != event.reA3MCEventId()) { continue; } VarManager::FillTrackMC(mcTracks, track); @@ -1370,7 +1370,7 @@ struct AnalysisSameEventPairing { for (const auto& [t1, t2] : combinations(mcTracks, mcTracks)) { auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedA3MCEventId() == t2_raw.reducedA3MCEventId()) { + if (t1_raw.reA3MCEventId() == t2_raw.reA3MCEventId()) { for (const auto& sig : fGenMCSignals) { if (sig->GetNProngs() != TWO_PRONG) { // NOTE: 2-prong signals required here continue; @@ -1387,21 +1387,21 @@ struct AnalysisSameEventPairing { if (!event.isEventSelected_bit(0)) { continue; } - if (!event.has_reducedA3MCEvent()) { + if (!event.has_reA3MCEvent()) { continue; } if (fHasTwoProngGenMCsignals) { for (const auto& [t1, t2] : combinations(mcTracks, mcTracks)) { - if (t1.reducedA3MCEventId() != event.reducedA3MCEventId()) { + if (t1.reA3MCEventId() != event.reA3MCEventId()) { continue; } - if (t2.reducedA3MCEventId() != event.reducedA3MCEventId()) { + if (t2.reA3MCEventId() != event.reA3MCEventId()) { continue; } auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedA3MCEventId() == t2_raw.reducedA3MCEventId()) { + if (t1_raw.reA3MCEventId() == t2_raw.reA3MCEventId()) { for (const auto& sig : fGenMCSignals) { if (sig->GetNProngs() != TWO_PRONG) { // NOTE: 2-prong signals required here continue; @@ -1416,7 +1416,7 @@ struct AnalysisSameEventPairing { } // end loop over reconstructed events } - void processMCGenWithGrouping(soa::Filtered const& events, ReducedA3MCEvents const& /*mcEvents*/, ReducedA3MCTracks const& mcTracks) + void processMCGenWithGrouping(soa::Filtered const& events, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& mcTracks) { for (const auto& mctrack : mcTracks) { VarManager::FillTrackMC(mcTracks, mctrack); @@ -1434,12 +1434,12 @@ struct AnalysisSameEventPairing { if (!event.isEventSelected_bit(0)) { continue; } - if (!event.has_reducedA3MCEvent()) { + if (!event.has_reA3MCEvent()) { continue; } for (const auto& track : mcTracks) { - if (track.reducedA3MCEventId() != event.reducedA3MCEventId()) { + if (track.reA3MCEventId() != event.reA3MCEventId()) { continue; } VarManager::FillTrackMC(mcTracks, track); @@ -1456,7 +1456,7 @@ struct AnalysisSameEventPairing { for (const auto& [t1, t2] : combinations(mcTracks, mcTracks)) { auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedA3MCEventId() == t2_raw.reducedA3MCEventId()) { + if (t1_raw.reA3MCEventId() == t2_raw.reA3MCEventId()) { for (const auto& sig : fGenMCSignals) { if (sig->GetNProngs() != TWO_PRONG) { // NOTE: 2-prong signals required here continue; @@ -1472,17 +1472,17 @@ struct AnalysisSameEventPairing { if (!event.isEventSelected_bit(0)) { continue; } - if (!event.has_reducedA3MCEvent()) { + if (!event.has_reA3MCEvent()) { continue; } // CURRENTLY ONLY FOR 1-GENERATION 2-PRONG SIGNALS if (fHasTwoProngGenMCsignals) { - auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedA3MCEventId()); + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reA3MCEventId()); groupedMCTracks.bindInternalIndicesTo(&mcTracks); for (const auto& [t1, t2] : combinations(groupedMCTracks, groupedMCTracks)) { auto t1_raw = groupedMCTracks.rawIteratorAt(t1.globalIndex()); auto t2_raw = groupedMCTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedA3MCEventId() == t2_raw.reducedA3MCEventId()) { + if (t1_raw.reA3MCEventId() == t2_raw.reA3MCEventId()) { for (const auto& sig : fGenMCSignals) { if (sig->GetNProngs() != TWO_PRONG) { // NOTE: 2-prong signals required here continue; @@ -1569,8 +1569,8 @@ struct AnalysisAsymmetricPairing { Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); - PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reducedA3eventId; - // PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reducedA3eventId; + PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; + // PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; // Partitions for triplets and asymmetric pairs Partition legACandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegAFilterMask) > static_cast(0); @@ -1598,9 +1598,9 @@ struct AnalysisAsymmetricPairing { fLegCFilterMask = fConfigLegCFilterMask.value; // Get the pair cuts - TString cutNamesStr = fConfigPairCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + TString pairCutNamesStr = fConfigPairCuts.value; + if (!pairCutNamesStr.IsNull()) { + std::unique_ptr objArray(pairCutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { fPairCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); } @@ -1611,10 +1611,10 @@ struct AnalysisAsymmetricPairing { std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); for (const auto& t : addPairCuts) { fPairCuts.push_back(static_cast(t)); - cutNamesStr += Form(",%s", t->GetName()); + pairCutNamesStr += Form(",%s", t->GetName()); } } - std::unique_ptr objArrayPairCuts(cutNamesStr.Tokenize(",")); + std::unique_ptr objArrayPairCuts(pairCutNamesStr.Tokenize(",")); fNPairCuts = objArrayPairCuts->GetEntries(); for (int j = 0; j < fNPairCuts; j++) { fPairCutNames.push_back(objArrayPairCuts->At(j)->GetName()); @@ -1757,9 +1757,9 @@ struct AnalysisAsymmetricPairing { DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName()), fConfigHistogramSubgroups.value.data()); } - TString cutNamesStr = fConfigPairCuts.value; - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + TString pairCutHistNamesStr = fConfigPairCuts.value; + if (!pairCutHistNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(pairCutHistNamesStr.Tokenize(",")); fNPairCuts = objArrayPair->GetEntries(); for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); @@ -1779,8 +1779,8 @@ struct AnalysisAsymmetricPairing { DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); } - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + if (!pairCutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(pairCutNamesStr.Tokenize(",")); for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { @@ -1819,8 +1819,8 @@ struct AnalysisAsymmetricPairing { } } - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + if (!pairCutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(pairCutNamesStr.Tokenize(",")); fNPairCuts = objArrayPair->GetEntries(); for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { @@ -1853,8 +1853,8 @@ struct AnalysisAsymmetricPairing { } } - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + if (!pairCutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(pairCutNamesStr.Tokenize(",")); for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { DefineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); @@ -1921,7 +1921,7 @@ struct AnalysisAsymmetricPairing { } // Function to run same event pairing with asymmetric pairs (e.g. kaon-pion) - void runAsymmetricPairing(MyEventsVtxCovSelected const& events, PresliceUnsorted& preslice, MyBarrelAssocs const& /*assocs*/, MyBarrelTracksWithCovWithAmbiguities const& /*tracks*/, ReducedA3MCEvents const& /*mcEvents*/, ReducedA3MCTracks const& /*mcTracks*/) + void runAsymmetricPairing(MyEventsVtxCovSelected const& events, PresliceUnsorted& preslice, MyBarrelAssocs const& /*assocs*/, MyBarrelTracksWithCovWithAmbiguities const& /*tracks*/, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& /*mcTracks*/) { fPairCount.clear(); @@ -1973,8 +1973,8 @@ struct AnalysisAsymmetricPairing { // Find common track cuts both candidates pass twoTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & fCommonTrackCutMask; - auto t1 = a1.template reducedA3track_as(); - auto t2 = a2.template reducedA3track_as(); + auto t1 = a1.template reA3track_as(); + auto t2 = a2.template reA3track_as(); // Avoid self-pairs if (t1.globalIndex() == t2.globalIndex()) { @@ -2007,9 +2007,9 @@ struct AnalysisAsymmetricPairing { int iSigMc = 0; mcDecision = 0; for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, iSigMc++) { - if (t1.has_reducedA3MCTrack() && t2.has_reducedA3MCTrack()) { - VarManager::FillPairMC(t1.reducedA3MCTrack(), t2.reducedA3MCTrack()); - if ((*sig)->CheckSignal(true, t1.reducedA3MCTrack(), t2.reducedA3MCTrack())) { + if (t1.has_reA3MCTrack() && t2.has_reA3MCTrack()) { + VarManager::FillPairMC(t1.reA3MCTrack(), t2.reA3MCTrack()); + if ((*sig)->CheckSignal(true, t1.reA3MCTrack(), t2.reA3MCTrack())) { mcDecision |= static_cast(1) << iSigMc; } } @@ -2166,7 +2166,7 @@ struct AnalysisAsymmetricPairing { // Function to run same event triplets (e.g. D+->K-pi+pi+) template - void runThreeProng(TEvents const& events, PresliceUnsorted& preslice, TTrackAssocs const& /*assocs*/, TTracks const& tracks, ReducedA3MCEvents const& /*mcEvents*/, ReducedA3MCTracks const& /*mcTracks*/, VarManager::PairCandidateType tripletType) + void runThreeProng(TEvents const& events, PresliceUnsorted& preslice, TTrackAssocs const& /*assocs*/, TTracks const& tracks, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& /*mcTracks*/, VarManager::PairCandidateType tripletType) { for (const auto& event : events) { if (!event.isEventSelected_bit(0)) { @@ -2242,9 +2242,9 @@ struct AnalysisAsymmetricPairing { // Find common track cuts all candidates pass threeTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a3.isBarrelSelected_raw() & fCommonTrackCutMask; - auto t1 = a1.template reducedA3track_as(); - auto t2 = a2.template reducedA3track_as(); - auto t3 = a3.template reducedA3track_as(); + auto t1 = a1.template reA3track_as(); + auto t2 = a2.template reA3track_as(); + auto t3 = a3.template reA3track_as(); // Avoid self-pairs if (t1 == t2 || t1 == t3 || t2 == t3) { @@ -2277,8 +2277,8 @@ struct AnalysisAsymmetricPairing { int iSigMc = 0; mcDecision = 0; for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, iSigMc++) { - if (t1.has_reducedA3MCTrack() && t2.has_reducedA3MCTrack() && t3.has_reducedA3MCTrack()) { - if ((*sig)->CheckSignal(true, t1.reducedA3MCTrack(), t2.reducedA3MCTrack(), t3.reducedA3MCTrack())) { + if (t1.has_reA3MCTrack() && t2.has_reA3MCTrack() && t3.has_reA3MCTrack()) { + if ((*sig)->CheckSignal(true, t1.reA3MCTrack(), t2.reA3MCTrack(), t3.reA3MCTrack())) { mcDecision |= (static_cast(1) << iSigMc); } } @@ -2344,7 +2344,7 @@ struct AnalysisAsymmetricPairing { void processKaonPionSkimmed(MyEventsVtxCovSelected const& events, MyBarrelAssocs const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, - ReducedA3MCEvents const& mcEvents, ReducedA3MCTracks const& mcTracks) + ReA3MCEvents const& mcEvents, ReA3MCTracks const& mcTracks) { runAsymmetricPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); } @@ -2352,7 +2352,7 @@ struct AnalysisAsymmetricPairing { void processKaonPionPionSkimmed(MyEventsVtxCovSelected const& events, MyBarrelAssocs const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, - ReducedA3MCEvents const& mcEvents, ReducedA3MCTracks const& mcTracks) + ReA3MCEvents const& mcEvents, ReA3MCTracks const& mcTracks) { runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks, VarManager::kTripleCandidateToKPiPi); } @@ -2360,16 +2360,16 @@ struct AnalysisAsymmetricPairing { void processProtonKaonPionSkimmed(MyEventsVtxCovSelected const& events, MyBarrelAssocs const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, - ReducedA3MCEvents const& mcEvents, ReducedA3MCTracks const& mcTracks) + ReA3MCEvents const& mcEvents, ReA3MCTracks const& mcTracks) { runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks, VarManager::kTripleCandidateToPKPi); } - void processMCGen(ReducedA3MCTracks const& mcTracks) + void processMCGen(ReA3MCTracks const& mcTracks) { // loop over mc stack and fill histograms for pure MC truth signals // group all the MC tracks which belong to the MC event corresponding to the current reconstructed event - // auto groupedMCTracks = tracksMC.sliceBy(aod::reducedA3trackMC::reducedA3MCEventId, event.reducedMCevent().globalIndex()); + // auto groupedMCTracks = tracksMC.sliceBy(aod::reducedA3trackMC::reA3MCEventId, event.reducedMCevent().globalIndex()); for (const auto& mctrack : mcTracks) { VarManager::FillTrackMC(mcTracks, mctrack); @@ -2384,20 +2384,20 @@ struct AnalysisAsymmetricPairing { } } - PresliceUnsorted perReducedMcEvent = aod::reducedA3trackMC::reducedA3MCEventId; + PresliceUnsorted perReducedMcEvent = aod::reducedA3trackMC::reA3MCEventId; void processMCGenWithEventSelection(soa::Filtered const& events, - ReducedA3MCEvents const& /*mcEvents*/, ReducedA3MCTracks const& mcTracks) + ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& mcTracks) { for (const auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; } - if (!event.has_reducedA3MCEvent()) { + if (!event.has_reA3MCEvent()) { continue; } - auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedA3MCEventId()); + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reA3MCEventId()); groupedMCTracks.bindInternalIndicesTo(&mcTracks); for (const auto& track : groupedMCTracks) { From fc680f64733a3419b7989513bf64c85bccfd4d7b Mon Sep 17 00:00:00 2001 From: nzardosh Date: Thu, 30 Jul 2026 00:39:27 +0200 Subject: [PATCH 40/71] [PWGJE] adding fix for DQ jet tables (#17244) --- PWGJE/DataModel/JetReducedDataDQ.h | 36 +++++++++---------- .../Tasks/jetSubstructureDielectronOutput.cxx | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/PWGJE/DataModel/JetReducedDataDQ.h b/PWGJE/DataModel/JetReducedDataDQ.h index 6246e4c808c..2f401108a87 100644 --- a/PWGJE/DataModel/JetReducedDataDQ.h +++ b/PWGJE/DataModel/JetReducedDataDQ.h @@ -154,29 +154,29 @@ namespace jdummydq DECLARE_SOA_COLUMN(DummyDQ, dummyDQ, bool); } // namespace jdummydq -DECLARE_SOA_TABLE(JDielectron1Dummys, "AOD", "JDIEL1DUMMY", - jdummydq::DummyDQ, - o2::soa::Marker<1>); +DECLARE_SOA_TABLE_STAGED(JDielectron1Dummys, "JDIEL1DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<1>); -DECLARE_SOA_TABLE(JDielectron2Dummys, "AOD", "JDIEL2DUMMY", - jdummydq::DummyDQ, - o2::soa::Marker<2>); +DECLARE_SOA_TABLE_STAGED(JDielectron2Dummys, "JDIEL2DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<2>); -DECLARE_SOA_TABLE(JDielectron3Dummys, "AOD", "JDIEL3DUMMY", - jdummydq::DummyDQ, - o2::soa::Marker<3>); +DECLARE_SOA_TABLE_STAGED(JDielectron3Dummys, "JDIEL3DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<3>); -DECLARE_SOA_TABLE(JDielectron4Dummys, "AOD", "JDIEL4DUMMY", - jdummydq::DummyDQ, - o2::soa::Marker<4>); +DECLARE_SOA_TABLE_STAGED(JDielectron4Dummys, "JDIEL4DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<4>); -DECLARE_SOA_TABLE(JDielectron5Dummys, "AOD", "JDIEL5DUMMY", - jdummydq::DummyDQ, - o2::soa::Marker<5>); +DECLARE_SOA_TABLE_STAGED(JDielectron5Dummys, "JDIEL5DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<5>); -DECLARE_SOA_TABLE(JDielectron6Dummys, "AOD", "JDIEL6DUMMY", - jdummydq::DummyDQ, - o2::soa::Marker<6>); +DECLARE_SOA_TABLE_STAGED(JDielectron6Dummys, "JDIEL6DUMMY", + jdummydq::DummyDQ, + o2::soa::Marker<6>); } // namespace o2::aod diff --git a/PWGJE/Tasks/jetSubstructureDielectronOutput.cxx b/PWGJE/Tasks/jetSubstructureDielectronOutput.cxx index 4f403b404ea..9be92a9434b 100644 --- a/PWGJE/Tasks/jetSubstructureDielectronOutput.cxx +++ b/PWGJE/Tasks/jetSubstructureDielectronOutput.cxx @@ -32,7 +32,7 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -using JetSubstructureOutputDielectron = JetSubstructureHFOutputTask, aod::McCollisionsDielectron, aod::CandidatesDielectronData, aod::CandidatesDielectronMCD, aod::CandidatesDielectronMCP, aod::BkgDielectronRhos, aod::BkgDielectronMcRhos, aod::JTrackDielectronSubs, soa::Join, soa::Join, aod::DielectronCJetRs, soa::Join, soa::Join, aod::DielectronCJetCOs, aod::DielectronCJetOs, aod::DielectronCJetSSOs, aod::DielectronCJetMOs, aod::DielectronCJetROs, soa::Join, aod::DielectronCMCDJetRs, soa::Join, soa::Join, aod::DielectronCMCDJetCOs, aod::DielectronCMCDJetOs, aod::DielectronCMCDJetSSOs, aod::DielectronCMCDJetMOs, aod::DielectronCMCDJetROs, aod::DielectronCMCDJetRMOs, soa::Join, soa::Join, aod::DielectronCMCPJetRs, soa::Join, soa::Join, aod::DielectronCMCPJetCOs, aod::DielectronCMCPJetMCCOs, aod::DielectronCMCPJetOs, aod::DielectronCMCPJetSSOs, aod::DielectronCMCPJetMOs, aod::DielectronCMCPJetROs, aod::DielectronCMCPJetRMOs, soa::Join, soa::Join, soa::Join, aod::DielectronCEWSJetCOs, aod::DielectronCEWSJetOs, aod::DielectronCEWSJetSSOs, aod::DielectronCEWSJetMOs, aod::StoredReducedEvents, aod::StoredDielectrons, aod::StoredDielectronsAll, aod::JDielectron1Dummys, aod::JDielectron2Dummys, aod::JDielectron3Dummys, aod::JDielectron4Dummys, aod::JDielectron5Dummys, aod::JDielectron6Dummys, aod::StoredJDielectronMcCollisions, aod::JDielectronMcRCollDummys, aod::StoredJDielectronMcs>; +using JetSubstructureOutputDielectron = JetSubstructureHFOutputTask, aod::McCollisionsDielectron, aod::CandidatesDielectronData, aod::CandidatesDielectronMCD, aod::CandidatesDielectronMCP, aod::BkgDielectronRhos, aod::BkgDielectronMcRhos, aod::JTrackDielectronSubs, soa::Join, soa::Join, aod::DielectronCJetRs, soa::Join, soa::Join, aod::DielectronCJetCOs, aod::DielectronCJetOs, aod::DielectronCJetSSOs, aod::DielectronCJetMOs, aod::DielectronCJetROs, soa::Join, aod::DielectronCMCDJetRs, soa::Join, soa::Join, aod::DielectronCMCDJetCOs, aod::DielectronCMCDJetOs, aod::DielectronCMCDJetSSOs, aod::DielectronCMCDJetMOs, aod::DielectronCMCDJetROs, aod::DielectronCMCDJetRMOs, soa::Join, soa::Join, aod::DielectronCMCPJetRs, soa::Join, soa::Join, aod::DielectronCMCPJetCOs, aod::DielectronCMCPJetMCCOs, aod::DielectronCMCPJetOs, aod::DielectronCMCPJetSSOs, aod::DielectronCMCPJetMOs, aod::DielectronCMCPJetROs, aod::DielectronCMCPJetRMOs, soa::Join, soa::Join, soa::Join, aod::DielectronCEWSJetCOs, aod::DielectronCEWSJetOs, aod::DielectronCEWSJetSSOs, aod::DielectronCEWSJetMOs, aod::StoredReducedEvents, aod::StoredDielectrons, aod::StoredDielectronsAll, aod::StoredJDielectron1Dummys, aod::StoredJDielectron2Dummys, aod::StoredJDielectron3Dummys, aod::StoredJDielectron4Dummys, aod::StoredJDielectron5Dummys, aod::StoredJDielectron6Dummys, aod::StoredJDielectronMcCollisions, aod::StoredJDielectronMcRCollDummys, aod::StoredJDielectronMcs>; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { From 3f5c239f408bb0dc49ae9dba4c3667cb751645af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E6=99=93=E5=AE=87=28Xiaoyu=20Hu=29?= <13971168438@163.com> Date: Thu, 30 Jul 2026 10:48:54 +0800 Subject: [PATCH 41/71] [PWGDQ] Apply phi-dependent correction to track rotation (#17245) Co-authored-by: ayatsuji <13807650+asakuratou@user.noreply.gitee.com> --- PWGDQ/Core/VarManager.cxx | 75 ++++++++++++++++++++++++++- PWGDQ/Core/VarManager.h | 9 +++- PWGDQ/Tasks/tableReader_withAssoc.cxx | 14 +++++ 3 files changed, 95 insertions(+), 3 deletions(-) diff --git a/PWGDQ/Core/VarManager.cxx b/PWGDQ/Core/VarManager.cxx index 588a49caf66..a92a0ce6f40 100644 --- a/PWGDQ/Core/VarManager.cxx +++ b/PWGDQ/Core/VarManager.cxx @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -75,7 +76,9 @@ int VarManager::fgCalibrationType = 0; // 0 - no calibration, 1 - bool VarManager::fgUseInterpolatedCalibration = true; // use interpolated calibration histograms (default: true) int VarManager::fgEfficiencyType = 0; // type of efficiency to be applied, default is no efficiency TObject* VarManager::fgEfficiencyHist = nullptr; // histogram for efficiency - +TObject* VarManager::fgPosiPhiMap = nullptr; +TObject* VarManager::fgNegaPhiMap = nullptr; +bool VarManager::fgUsePhiCorrection = false; //__________________________________________________________________ VarManager::VarManager() : TObject() { @@ -453,6 +456,76 @@ void VarManager::FillEfficiency(float* values) } } +void VarManager::SetPhiMap(TObject* hposi, TObject* hnega, bool option) +{ + fgPosiPhiMap = hposi; + fgNegaPhiMap = hnega; + fgUsePhiCorrection = option; +} + +double VarManager::SampleRotationPhi(double pt, double eta, int charge) +{ + // each type only alarm once + static bool warnedEmptyPhi = false; + + if (!fgUsePhiCorrection) { + return gRandom->Uniform(0., o2::constants::math::TwoPI); + } else { + + TH3D* hMap = nullptr; + if (charge > 0) { + hMap = dynamic_cast(fgPosiPhiMap); + } else { + hMap = dynamic_cast(fgNegaPhiMap); + } + + if (!hMap) { + LOGF(fatal, "Phi map is not a TH3D"); + } + // TH3 axes: X=pT, Y=phi, Z=eta + int ptBin = hMap->GetXaxis()->FindBin(pt); + int etaBin = hMap->GetZaxis()->FindBin(eta); + + ptBin = std::clamp(ptBin, 1, hMap->GetNbinsX()); + etaBin = std::clamp(etaBin, 1, hMap->GetNbinsZ()); + + TH1D* hPhi = hMap->ProjectionY( + Form("hTRPhi_tmp_charge%d_ptbin%d_etabin%d", + charge, ptBin, etaBin), + ptBin, + ptBin, + etaBin, + etaBin); + + if (!hPhi || hPhi->Integral(1, hPhi->GetNbinsX()) <= 0.) { + if (!warnedEmptyPhi) { + LOGF(warn, + "Empty phi distribution for " + "pt=%f, eta=%f, charge=%d, ptBin=%d, etaBin=%d. " + "Falling back to uniform phi sampling.", + pt, + eta, + charge, + ptBin, + etaBin); + + warnedEmptyPhi = true; + } + + delete hPhi; + + return gRandom->Uniform( + 0., o2::constants::math::TwoPI); + } + + const double phi = + RecoDecay::constrainAngle(hPhi->GetRandom()); + + delete hPhi; + return phi; + } +} + //__________________________________________________________________ std::tuple VarManager::BimodalityCoefficientUnbinned(const std::vector& data) { diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index 3bdd863c5e4..71c6c7a299e 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -1534,6 +1534,8 @@ class VarManager : public TObject static void SetEfficiencyObject(int type, TObject* obj); static void FillEfficiency(float* values = nullptr); + static void SetPhiMap(TObject* h1, TObject* h2, bool option); + static double SampleRotationPhi(double pT, double eta, int charge); static TObject* GetCalibrationObject(CalibObjects calib) { auto obj = fgCalibs.find(calib); @@ -1618,6 +1620,10 @@ class VarManager : public TObject static int fgEfficiencyType; // type of efficiency correction to apply static TObject* fgEfficiencyHist; // histogram for efficiency correction + static TObject* fgPosiPhiMap; // phi map to correct track rotation + static TObject* fgNegaPhiMap; + static bool fgUsePhiCorrection; + VarManager& operator=(const VarManager& c); VarManager(const VarManager& c); }; @@ -3960,8 +3966,7 @@ void VarManager::FillPairRotation(T1 const& t1, T2 const& t2, float* values) m2 = o2::constants::physics::MassMuon; } - double dphi = gRandom->Uniform(0., o2::constants::math::TwoPI); - double rotationphi2 = RecoDecay::constrainAngle(t2.phi() + dphi); + double rotationphi2 = SampleRotationPhi(t2.pt(), t2.eta(), t2.sign()); values[kCharge] = t1.sign() + t2.sign(); values[kCharge1] = t1.sign(); diff --git a/PWGDQ/Tasks/tableReader_withAssoc.cxx b/PWGDQ/Tasks/tableReader_withAssoc.cxx index aba3686f2e8..7bc5d77d76f 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc.cxx @@ -1362,6 +1362,7 @@ struct AnalysisSameEventPairing { Configurable GrpLhcIfPath{"grplhcif", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; Configurable efficiencyPath{"effHistPath", "Users/z/zhxiong/efficiency", "Path on the CCDB for the efficiency histograms"}; Configurable flowPath{"flowPath", "Users/y/yiping/FlowResolution", "Path to the flow resolution object"}; + Configurable phiPath{"phiPath", "Users/h/hxiaoyu/TrackPhi/LHC23", "Path to load phi distribution for track rotation"}; } fConfigCCDB; struct : ConfigurableGroup { @@ -1381,6 +1382,7 @@ struct AnalysisSameEventPairing { Configurable useEfficiencyWeighting{"cfgUseEfficiencyWeighting", false, "Apply efficiency weighting to the pairs from CCDB"}; Configurable efficiencyType{"cfgEfficiencyType", 0, "Type of efficiency to apply from CCDB: 0 no efficiency, 1 pt-cent-costhetastar"}; Configurable useFlowReso{"cfgUseFlowReso", false, "Use remote flow information from CCDB"}; + Configurable usePhiDistribution{"cfgUsePhiDistribution", false, "Use phi distribution to correct track rotation"}; } fConfigOptions; struct : ConfigurableGroup { Configurable applyBDT{"applyBDT", false, "Flag to apply ML selections"}; @@ -1855,6 +1857,18 @@ struct AnalysisSameEventPairing { LOGF(fatal, "Flow resolution histograms not available in CCDB at timestamp=%llu", timestamp); } } + + if (fConfigOptions.usePhiDistribution) { + TString PathPhi = fConfigCCDB.phiPath.value; + TString ccdbPathPhiPosi = Form("%s/hPtPhiPositive", PathPhi.Data()); + TString ccdbPathPhiNega = Form("%s/hPtPhiNegative", PathPhi.Data()); + auto phiPosi = fCCDB->getForTimeStamp(ccdbPathPhiPosi.Data(), timestamp); + auto phiNega = fCCDB->getForTimeStamp(ccdbPathPhiNega.Data(), timestamp); + if (phiPosi == nullptr || phiNega == nullptr) { + LOGF(fatal, "Phi distribution histograms not available in CCDB at timestamp=%llu", timestamp); + } + VarManager::SetPhiMap(phiPosi, phiNega, fConfigOptions.usePhiDistribution.value); + } } // Template function to run same event pairing (barrel-barrel, muon-muon, barrel-muon) From 932361bab19c989e4dacf3d777176404c190cf07 Mon Sep 17 00:00:00 2001 From: alicja-pp <101565842+alicja-pp@users.noreply.github.com> Date: Thu, 30 Jul 2026 09:47:04 +0200 Subject: [PATCH 42/71] [PWGCF] FemtoUniverse: Add kaon and pion Nsigma rejection in proton selection (#17256) --- ...iversePairTaskTrackTrackMultKtExtended.cxx | 31 +++++++++++- .../femtoUniversePairTaskTrackV0Extended.cxx | 47 ++++++++++++------- 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx index 25e08090728..24cd5ab2610 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackTrackMultKtExtended.cxx @@ -76,6 +76,9 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { Configurable isNsigmaRectangular{"isNsigmaRectangular", false, "Apply rectangular TPC and TOF nSigma cut, instead of a combined one (TPC confNsigmaCombined{"confNsigmaCombined", 3.0f, "TPC and TOF Pion Sigma (combined) for momentum > confTOFpMin"}; Configurable confNsigmaTPC{"confNsigmaTPC", 3.0f, "TPC Pion Sigma for momentum < confTOFpMin"}; + Configurable confNsigmaKaonRejection{"confNsigmaKaonRejection", 0, "In proton selection reject tracks with combined Nsigma confNsigmaPionRejection{"confNsigmaPionRejection", 0, "In proton selection reject tracks with combined Nsigma confTOFpMin{"confTOFpMin", 0.5f, "Min. momentum for which TOF is required for PID."}; Configurable confEtaMax{"confEtaMax", 0.8f, "Higher limit for |Eta| (the same for both particles)"}; @@ -280,6 +283,30 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { return std::hypot(nsigmaTOF, nsigmaTPC) < twotracksconfigs.confNsigmaCombined; } + bool isNSigmaProton(float mom, float nsigmaTPC, float nsigmaTOF, float nsigmaTPCkaon, float nsigmaTOFkaon, float nsigmaTPCpion, float nsigmaTOFpion) + { + // with additional nSigma kaon and pion rejection + if (mom < twotracksconfigs.confTOFpMin) { + if (std::abs(nsigmaTPCkaon) < twotracksconfigs.confNsigmaKaonRejection || std::abs(nsigmaTPCpion) < twotracksconfigs.confNsigmaPionRejection) { + return false; + } + } else if (std::hypot(nsigmaTOFkaon, nsigmaTPCkaon) < twotracksconfigs.confNsigmaKaonRejection || std::hypot(nsigmaTOFpion, nsigmaTPCpion) < twotracksconfigs.confNsigmaPionRejection) { + return false; + } + + if (twotracksconfigs.isNsigmaRectangular) { + if (mom < twotracksconfigs.confTOFpMin) { + return std::abs(nsigmaTPC) < twotracksconfigs.confNsigmaTPC; + } + return (std::abs(nsigmaTPC) < twotracksconfigs.confNsigmaTPC && std::abs(nsigmaTOF) < twotracksconfigs.confNsigmaCombined); + } + + if (mom < twotracksconfigs.confTOFpMin) { + return std::abs(nsigmaTPC) < twotracksconfigs.confNsigmaTPC; + } + return std::hypot(nsigmaTOF, nsigmaTPC) < twotracksconfigs.confNsigmaCombined; + } + /// TPC Kaon Sigma selection (stricter cuts for K+ and K-) -- based on Run2 results bool isKaonNsigma(float mom, float nsigmaTPCK, float nsigmaTOFK) { @@ -313,7 +340,7 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { switch (trackonefilter.confPDGCodePartOne) { case kProton: case kProtonBar: - return isNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + return isNSigmaProton(mom, nsigmaTPCPr, nsigmaTOFPr, nsigmaTPCK, nsigmaTOFK, nsigmaTPCPi, nsigmaTOFPi); case kPiPlus: case kPiMinus: case kPi0: @@ -331,7 +358,7 @@ struct FemtoUniversePairTaskTrackTrackMultKtExtended { switch (tracktwofilter.confPDGCodePartTwo) { case kProton: case kProtonBar: - return isNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); + return isNSigmaProton(mom, nsigmaTPCPr, nsigmaTOFPr, nsigmaTPCK, nsigmaTOFK, nsigmaTPCPi, nsigmaTOFPi); case kPiPlus: case kPiMinus: case kPi0: diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx index ce5a0cc8934..a3ec2c9f607 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackV0Extended.cxx @@ -104,11 +104,15 @@ struct FemtoUniversePairTaskTrackV0Extended { Configurable confDcaXYCustom2FilterCut{"confDcaXYCustom2FilterCut", 0, "Value for [2] custom DCAxy cut -> |DCAxy| < [1] + [2]/pT (if stricter than in Producer)"}; } ConfTrkSelection; - Configurable confmom{"confmom", 0.5, "momentum threshold for particle identification using TOF"}; - Configurable confNsigmaTPCParticle{"confNsigmaTPCParticle", 3.0, "TPC Sigma for particle momentum < confmom"}; - Configurable confNsigmaTPCDaughter{"confNsigmaTPCDaughter", 3.0, "TPC Sigma for daughter"}; - Configurable confNsigmaTOFParticle{"confNsigmaTOFParticle", 3.0, "TOF Sigma for particle (daugh & bach) momentum > Confmom"}; - Configurable confNsigmaCombinedParticle{"confNsigmaCombinedParticle", 3.0, "TPC and TOF Sigma (combined) for particle momentum > confmom"}; + struct : o2::framework::ConfigurableGroup { + Configurable confmom{"confmom", 0.5, "momentum threshold for particle identification using TOF"}; + Configurable confNsigmaTPCParticle{"confNsigmaTPCParticle", 3.0, "TPC Sigma for particle momentum < ConfNSigmaSelection.confmom"}; + Configurable confNsigmaTPCDaughter{"confNsigmaTPCDaughter", 3.0, "TPC Sigma for daughter"}; + Configurable confNsigmaTOFParticle{"confNsigmaTOFParticle", 3.0, "TOF Sigma for particle (daugh & bach) momentum > ConfNSigmaSelection.confmom"}; + Configurable confNsigmaCombinedParticle{"confNsigmaCombinedParticle", 3.0, "TPC and TOF Sigma (combined) for particle momentum > ConfNSigmaSelection.confmom"}; + Configurable confNsigmaKaonRejection{"confNsigmaKaonRejection", 0, "In proton selection reject tracks with kaon Nsigma confNsigmaPionRejection{"confNsigmaPionRejection", 0, "In proton selection reject tracks with pion Nsigma ; @@ -255,11 +259,11 @@ struct FemtoUniversePairTaskTrackV0Extended { bool isNSigmaCombined(float mom, float nsigmaTPCParticle, float nsigmaTOFParticle, bool hasTOF) { - if (mom <= confmom) { - return (std::abs(nsigmaTPCParticle) < confNsigmaTPCParticle); + if (mom <= ConfNSigmaSelection.confmom) { + return (std::abs(nsigmaTPCParticle) < ConfNSigmaSelection.confNsigmaTPCParticle); } if (hasTOF) { - return (std::hypot(nsigmaTOFParticle, nsigmaTPCParticle) < confNsigmaCombinedParticle); + return (std::hypot(nsigmaTOFParticle, nsigmaTPCParticle) < ConfNSigmaSelection.confNsigmaCombinedParticle); } return false; } @@ -267,7 +271,7 @@ struct FemtoUniversePairTaskTrackV0Extended { template bool isNSigmaCombinedBitmask(float mom, const T& part) { - if (mom <= confmom) { + if (mom <= ConfNSigmaSelection.confmom) { return ((part.pidCut() & (1u << ConfTrkSelection.confTrackChoicePartOne)) != 0); } if ((part.pidCut() & 512u) != 0) { @@ -293,14 +297,14 @@ struct FemtoUniversePairTaskTrackV0Extended { bool isNSigmaTPC(float nsigmaTPCParticle) { - return std::abs(nsigmaTPCParticle) < confNsigmaTPCDaughter; + return std::abs(nsigmaTPCParticle) < ConfNSigmaSelection.confNsigmaTPCDaughter; } bool isNSigmaTOF(float mom, float nsigmaTOFParticle, bool hasTOF) { // Cut only on daughter tracks, that have TOF signal - if (mom > confmom && hasTOF) { - return std::abs(nsigmaTOFParticle) < confNsigmaTOFParticle; + if (mom > ConfNSigmaSelection.confmom && hasTOF) { + return std::abs(nsigmaTOFParticle) < ConfNSigmaSelection.confNsigmaTOFParticle; } return true; } @@ -310,7 +314,19 @@ struct FemtoUniversePairTaskTrackV0Extended { { const std::array tpcNSigmas = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; const std::array tofNSigmas = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; + enum particleID { protonId, + pionId, + kaonId }; + if (id == protonId) { + if (part.p() < ConfNSigmaSelection.confmom) { + if (std::abs(tpcNSigmas[kaonId]) < ConfNSigmaSelection.confNsigmaKaonRejection || std::abs(tpcNSigmas[pionId]) < ConfNSigmaSelection.confNsigmaPionRejection) { + return false; + } + } else if (std::hypot(tofNSigmas[kaonId], tpcNSigmas[kaonId]) < ConfNSigmaSelection.confNsigmaKaonRejection || std::hypot(tofNSigmas[pionId], tpcNSigmas[pionId]) < ConfNSigmaSelection.confNsigmaPionRejection) { + return false; + } + } return isNSigmaCombined(part.p(), tpcNSigmas[id], tofNSigmas[id], (part.pidCut() & 512u) != 0); } @@ -560,7 +576,7 @@ struct FemtoUniversePairTaskTrackV0Extended { const std::array tpcNSigmas = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; const std::array tofNSigmas = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; - if (!isNSigmaCombined(part.p(), tpcNSigmas[ConfTrkSelection.confTrackChoicePartOne], tofNSigmas[ConfTrkSelection.confTrackChoicePartOne], (part.pidCut() & 512u) != 0)) { + if (!isParticleCombined(part, ConfTrkSelection.confTrackChoicePartOne)) { continue; } if (part.sign() > 0) { @@ -1832,10 +1848,7 @@ struct FemtoUniversePairTaskTrackV0Extended { } for (const auto& part : groupPartsOne) { - const std::array tpcNSigmas = {aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePr()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStorePi()), aod::pidtpc_tiny::binning::unPackInTable(part.tpcNSigmaStoreKa())}; - const std::array tofNSigmas = {aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePr()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStorePi()), aod::pidtof_tiny::binning::unPackInTable(part.tofNSigmaStoreKa())}; - - if (!isNSigmaCombined(part.p(), tpcNSigmas[ConfTrkSelection.confTrackChoicePartOne], tofNSigmas[ConfTrkSelection.confTrackChoicePartOne], (part.pidCut() & 512u) != 0)) { + if (!isParticleCombined(part, ConfTrkSelection.confTrackChoicePartOne)) { continue; } registryMCreco.fill(HIST("mothersReco/motherParticleTrack"), part.motherPDG()); From ff34c7213644c46ff2175425baa650ade3919d29 Mon Sep 17 00:00:00 2001 From: Katarzyna <116073883+kgwizdzi@users.noreply.github.com> Date: Thu, 30 Jul 2026 10:03:00 +0200 Subject: [PATCH 43/71] [PWGCF] FemtoUniverse D0 task: adding function for purity estimation with full nSigma (#17257) --- .../Tasks/femtoUniversePairTaskTrackD0.cxx | 123 ++++++++++++------ 1 file changed, 80 insertions(+), 43 deletions(-) diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx index 03baec4f934..31901da383b 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx @@ -94,8 +94,10 @@ struct FemtoUniversePairTaskTrackD0 { Service pdgMC{}; using FemtoFullParticles = soa::Join; + using FemtoFullSigmaParticles = soa::Join; SliceCache cache; Preslice perCol = aod::femtouniverseparticle::fdCollisionId; + Preslice perColFullSigma = aod::femtouniverseparticle::fdCollisionId; using FemtoMcRecoParticles = soa::Join; Preslice perColMc = aod::femtouniverseparticle::fdCollisionId; @@ -190,24 +192,25 @@ struct FemtoUniversePairTaskTrackD0 { /// Partitions for particle 1 Partition partsTrack = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == int8_t(ConfTrack.confTrackSign)) && (aod::femtouniverseparticle::pt > ConfTrack.confTrackLowPtCut) && (aod::femtouniverseparticle::pt < ConfTrack.confTrackHighPtCut) && (nabs(aod::femtouniverseparticle::eta) < ConfTrack.confTrackEtaMax); + Partition partsTrackFullSigma = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == int8_t(ConfTrack.confTrackSign)) && (aod::femtouniverseparticle::pt > ConfTrack.confTrackLowPtCut) && (aod::femtouniverseparticle::pt < ConfTrack.confTrackHighPtCut) && (nabs(aod::femtouniverseparticle::eta) < ConfTrack.confTrackEtaMax); Partition partsTrackMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && (aod::femtouniverseparticle::sign == int8_t(ConfTrack.confTrackSign)) && (aod::femtouniverseparticle::pt > ConfTrack.confTrackLowPtCut) && (aod::femtouniverseparticle::pt < ConfTrack.confTrackHighPtCut) && (nabs(aod::femtouniverseparticle::eta) < ConfTrack.confTrackEtaMax); Partition partsTrackMCTruth = (aod::femtouniverseparticle::partType == static_cast(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) && (aod::femtouniverseparticle::pidCut == static_cast(ConfTrack.confPDGCodeTrack)) && (aod::femtouniverseparticle::pt > ConfTrack.confTrackLowPtCut) && (aod::femtouniverseparticle::pt < ConfTrack.confTrackHighPtCut) && (nabs(aod::femtouniverseparticle::eta) < ConfTrack.confTrackEtaMax); /// Partitions for particle 2 /// Partition with all D0/D0bar mesons (which pass one and double mass hypothesis) - Partition partsAllDmesons = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mLambda > 0.0f) || (aod::femtouniverseparticle::mAntiLambda > 0.0f)) && (aod::femtouniverseparticle::decayVtxY < ConfMlProb.confMlProbNonPromptMax); + Partition partsAllDmesons = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mLambda > 0.0f) || (aod::femtouniverseparticle::mAntiLambda > 0.0f)) && (aod::femtouniverseparticle::decayVtxZ < ConfMlProb.confMlProbNonPromptMax); /// Partition with D0 mesons only (one and double mass hypothesis) - Partition partsAllD0s = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxY < ConfMlProb.confMlProbNonPromptMax); + Partition partsAllD0s = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxZ < ConfMlProb.confMlProbNonPromptMax); /// Partition with D0 mesons only (one mass hypothesis) - Partition partsD0s = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < 0.0f) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxY < ConfMlProb.confMlProbNonPromptMax); + Partition partsD0s = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < 0.0f) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxZ < ConfMlProb.confMlProbNonPromptMax); /// Partition with D0s selected from the side-band (SB) regions (candidates with double mass hypothesis included) - Partition partsD0sFromSB = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barLeftSB && aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barLeftSB) || (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barRightSB && aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barRightSB)) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxY < ConfMlProb.confMlProbNonPromptMax); + Partition partsD0sFromSB = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barLeftSB && aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barLeftSB) || (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barRightSB && aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barRightSB)) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxZ < ConfMlProb.confMlProbNonPromptMax); /// Partition with D0bar mesons only (one and double mass hypothesis) - Partition partsAllD0bars = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxY < ConfMlProb.confMlProbNonPromptMax); + Partition partsAllD0bars = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxZ < ConfMlProb.confMlProbNonPromptMax); /// Partition with D0bar mesons only (one mass hypothesis) - Partition partsD0bars = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda < 0.0f) && (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxY < ConfMlProb.confMlProbNonPromptMax); + Partition partsD0bars = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda < 0.0f) && (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxZ < ConfMlProb.confMlProbNonPromptMax); /// Partition with D0bars selected from the side-band (SB) regions (candidates with double mass hypothesis included) - Partition partsD0barsFromSB = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barLeftSB && aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barLeftSB) || (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barRightSB && aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barRightSB)) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxY < ConfMlProb.confMlProbNonPromptMax); + Partition partsD0barsFromSB = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && ((aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barLeftSB && aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barLeftSB) || (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barRightSB && aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barRightSB)) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::decayVtxZ < ConfMlProb.confMlProbNonPromptMax); /// Partition for MC Reco prompt D0/D0bar mesons Partition partsPromptD0MCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::tpcNClsFound == ConfDmesons.confD0OriginFlag); Partition partsPromptD0barMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kD0)) && (aod::femtouniverseparticle::mAntiLambda > ConfDmesons.minInvMassD0D0barSignal) && (aod::femtouniverseparticle::mAntiLambda < ConfDmesons.maxInvMassD0D0barSignal) && (aod::femtouniverseparticle::pt > ConfDmesons.confMinPtD0D0bar) && (aod::femtouniverseparticle::pt < ConfDmesons.confMaxPtD0D0bar) && (aod::femtouniverseparticle::tpcNClsFound == ConfDmesons.confD0OriginFlag); @@ -261,13 +264,15 @@ struct FemtoUniversePairTaskTrackD0 { ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {360, 0., 36.}, "Cand. pT bins"}; } ConfThnAxes; - Configurable confIsCPR{"confIsCPR", true, "Close Pair Rejection"}; - Configurable confCPRPlotPerRadii{"confCPRPlotPerRadii", false, "Plot CPR per radii"}; - Configurable confCPRdeltaPhiCutMax{"confCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; - Configurable confCPRdeltaPhiCutMin{"confCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; - Configurable confCPRdeltaEtaCutMax{"confCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; - Configurable confCPRdeltaEtaCutMin{"confCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; - Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + struct : o2::framework::ConfigurableGroup { + Configurable confIsCPR{"confIsCPR", true, "Close Pair Rejection"}; + Configurable confCPRPlotPerRadii{"confCPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable confCPRdeltaPhiCutMax{"confCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; + Configurable confCPRdeltaPhiCutMin{"confCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMax{"confCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMin{"confCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; + Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + } ConfCPR; Configurable confRemoveSoftPions{"confRemoveSoftPions", false, "Enable to remove soft pions from D* decays"}; Configurable confSoftPionD0Flag{"confSoftPionD0Flag", false, "Enable soft pion check for D0s"}; @@ -317,10 +322,7 @@ struct FemtoUniversePairTaskTrackD0 { if (mom <= ConfTrack.minMomPidTpcTofProton) { return std::abs(nsigmaTPCPr) < ConfTrack.confNsigmaTPCProton; } - if (mom > ConfTrack.minMomPidTpcTofProton) { - return std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfTrack.confNsigmaCombinedProton; - } - return false; + return std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfTrack.confNsigmaCombinedProton; } bool isProtonNSigmaRejected(float mom, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCKa, float nsigmaTOFKa) @@ -328,10 +330,7 @@ struct FemtoUniversePairTaskTrackD0 { if (mom <= ConfTrack.minMomPidTpcTofProton) { return std::abs(nsigmaTPCPi) < ConfTrack.confNsigmaTPCPrRejectPiNsigma || std::abs(nsigmaTPCKa) < ConfTrack.confNsigmaTPCPrRejectKaNsigma; } - if (mom > ConfTrack.minMomPidTpcTofProton) { - return std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfTrack.confNsigmaCombPrRejectPiNsigma || std::hypot(nsigmaTOFKa, nsigmaTPCKa) < ConfTrack.confNsigmaCombPrRejectKaNsigma; - } - return false; + return std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfTrack.confNsigmaCombPrRejectPiNsigma || std::hypot(nsigmaTOFKa, nsigmaTPCKa) < ConfTrack.confNsigmaCombPrRejectKaNsigma; } bool isKaonNSigma(float mom, float nsigmaTPCKa, float nsigmaTOFKa) @@ -339,10 +338,7 @@ struct FemtoUniversePairTaskTrackD0 { if (mom <= ConfTrack.minMomPidTpcTofKaon) { return std::abs(nsigmaTPCKa) < ConfTrack.confNsigmaTPCKaon; } - if (mom > ConfTrack.minMomPidTpcTofKaon) { - return std::hypot(nsigmaTOFKa, nsigmaTPCKa) < ConfTrack.confNsigmaCombinedKaon; - } - return false; + return std::hypot(nsigmaTOFKa, nsigmaTPCKa) < ConfTrack.confNsigmaCombinedKaon; } bool isKaonNSigmaRejected(float mom, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCPr, float nsigmaTOFPr) @@ -350,10 +346,7 @@ struct FemtoUniversePairTaskTrackD0 { if (mom <= ConfTrack.minMomPidTpcTofKaon) { return std::abs(nsigmaTPCPi) < ConfTrack.confNsigmaTPCKaRejectPiNsigma || std::abs(nsigmaTPCPr) < ConfTrack.confNsigmaTPCKaRejectPrNsigma; } - if (mom > ConfTrack.minMomPidTpcTofKaon) { - return std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfTrack.confNsigmaCombKaRejectPiNsigma || std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfTrack.confNsigmaCombKaRejectPrNsigma; - } - return false; + return std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfTrack.confNsigmaCombKaRejectPiNsigma || std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfTrack.confNsigmaCombKaRejectPrNsigma; } bool isPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) @@ -361,10 +354,7 @@ struct FemtoUniversePairTaskTrackD0 { if (mom <= ConfTrack.minMomPidTpcTofPion) { return std::abs(nsigmaTPCPi) < ConfTrack.confNsigmaTPCPion; } - if (mom > ConfTrack.minMomPidTpcTofPion) { - return std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfTrack.confNsigmaCombinedPion; - } - return false; + return std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfTrack.confNsigmaCombinedPion; } bool isPionNSigmaRejected(float mom, float nsigmaTPCKa, float nsigmaTOFKa, float nsigmaTPCPr, float nsigmaTOFPr) @@ -372,10 +362,7 @@ struct FemtoUniversePairTaskTrackD0 { if (mom <= ConfTrack.minMomPidTpcTofPion) { return std::abs(nsigmaTPCKa) < ConfTrack.confNsigmaTPCPiRejectKaNsigma || std::abs(nsigmaTPCPr) < ConfTrack.confNsigmaTPCPiRejectPrNsigma; } - if (mom > ConfTrack.minMomPidTpcTofPion) { - return std::hypot(nsigmaTOFKa, nsigmaTPCKa) < ConfTrack.confNsigmaCombPiRejectKaNsigma || std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfTrack.confNsigmaCombPiRejectPrNsigma; - } - return false; + return std::hypot(nsigmaTOFKa, nsigmaTPCKa) < ConfTrack.confNsigmaCombPiRejectKaNsigma || std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfTrack.confNsigmaCombPiRejectPrNsigma; } bool isParticleNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) @@ -468,6 +455,20 @@ struct FemtoUniversePairTaskTrackD0 { qaRegistry.add("Hadron/nSigmaTOFKa", "; #it{p} (GeV/#it{c}); n#sigma_{TOFKa}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaTPCTOFAxis}); qaRegistry.add("Hadron/nSigmaCombKa", "; #it{p} (GeV/#it{c}); n#sigma^{combined}_{Ka}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaCombAxis}); + if (doprocessPurityQA && std::abs(ConfTrack.confPDGCodeTrack) == PDG_t::kProton) { + qaRegistry.add("PurityQA/nSigmaFullTPCPr", "; #it{p} (GeV/#it{c}); n#sigma_{TPCPr}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaTPCTOFAxis}); + qaRegistry.add("PurityQA/nSigmaFullTOFPr", "; #it{p} (GeV/#it{c}); n#sigma_{TOFPr}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaTPCTOFAxis}); + qaRegistry.add("PurityQA/nSigmaFullCombPr", "; #it{p} (GeV/#it{c}); n#sigma^{combined}_{Pr}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaCombAxis}); + } else if (doprocessPurityQA && std::abs(ConfTrack.confPDGCodeTrack) == PDG_t::kPiPlus) { + qaRegistry.add("PurityQA/nSigmaFullTPCPi", "; #it{p} (GeV/#it{c}); n#sigma_{TPCPi}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaTPCTOFAxis}); + qaRegistry.add("PurityQA/nSigmaFullTOFPi", "; #it{p} (GeV/#it{c}); n#sigma_{TOFPi}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaTPCTOFAxis}); + qaRegistry.add("PurityQA/nSigmaFullCombPi", "; #it{p} (GeV/#it{c}); n#sigma^{combined}_{Pi}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaCombAxis}); + } else if (doprocessPurityQA && std::abs(ConfTrack.confPDGCodeTrack) == PDG_t::kKPlus) { + qaRegistry.add("PurityQA/nSigmaFullTPCKa", "; #it{p} (GeV/#it{c}); n#sigma_{TPCKa}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaTPCTOFAxis}); + qaRegistry.add("PurityQA/nSigmaFullTOFKa", "; #it{p} (GeV/#it{c}); n#sigma_{TOFKa}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaTPCTOFAxis}); + qaRegistry.add("PurityQA/nSigmaFullCombKa", "; #it{p} (GeV/#it{c}); n#sigma^{combined}_{Ka}", kTH2F, {{100, 0, 10}, ConfBothTracks.confNSigmaCombAxis}); + } + // D0/D0bar histograms auto vbins = (std::vector)binsPt; auto vFivePtBins = (std::vector)binsPtFive; @@ -476,7 +477,7 @@ struct FemtoUniversePairTaskTrackD0 { const AxisSpec thnAxisPromptScore{ConfThnAxes.thnConfigAxisPromptScore, "BDT score prompt"}; const AxisSpec thnAxisMass{ConfThnAxes.thnConfigAxisMass, "inv. mass (#pi K) (GeV/#it{c}^{2})"}; const AxisSpec thnAxisPt{ConfThnAxes.thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; - std::vector axesTHn = {thnAxisNonPromptScore, thnAxisPromptScore, thnAxisMass, thnAxisPt}; + std::vector axesTHn = {thnAxisPromptScore, thnAxisNonPromptScore, thnAxisMass, thnAxisPt}; if (doEfficiencyCorr) { registry.add("D0D0bar_oneMassHypo/hMassVsPtEffCorr", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); @@ -615,8 +616,8 @@ struct FemtoUniversePairTaskTrackD0 { softPionRemoval.init(&qaRegistry); pairCleaner.init(&qaRegistry); - if (confIsCPR.value) { - pairCloseRejection.init(&resultRegistry, &qaRegistry, ConfBothTracks.confDeltaEtaAxis, ConfBothTracks.confDeltaPhiStarAxis, confCPRdeltaPhiCutMin.value, confCPRdeltaPhiCutMax.value, confCPRdeltaEtaCutMin.value, confCPRdeltaEtaCutMax.value, confCPRChosenRadii.value, confCPRPlotPerRadii.value); + if (ConfCPR.confIsCPR.value) { + pairCloseRejection.init(&resultRegistry, &qaRegistry, ConfBothTracks.confDeltaEtaAxis, ConfBothTracks.confDeltaPhiStarAxis, ConfCPR.confCPRdeltaPhiCutMin.value, ConfCPR.confCPRdeltaPhiCutMax.value, ConfCPR.confCPRdeltaEtaCutMin.value, ConfCPR.confCPRdeltaEtaCutMax.value, ConfCPR.confCPRChosenRadii.value, ConfCPR.confCPRPlotPerRadii.value); } vPIDTrack = ConfTrack.confPIDTrack.value; @@ -836,7 +837,7 @@ struct FemtoUniversePairTaskTrackD0 { } } // // Close Pair Rejection - if (confIsCPR.value) { + if (ConfCPR.confIsCPR.value) { if (pairCloseRejection.isClosePair(track, d0candidate, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } @@ -1036,7 +1037,7 @@ struct FemtoUniversePairTaskTrackD0 { } } // // Close Pair Rejection - if (confIsCPR.value) { + if (ConfCPR.confIsCPR.value) { if (pairCloseRejection.isClosePair(track, d0candidate, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { continue; } @@ -1532,6 +1533,42 @@ struct FemtoUniversePairTaskTrackD0 { } } PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processMcTruth, "Process MC truth data", false); + + /// \param col subscribe to the collision table (Data) + /// \param parts subscribe to the femtoUniverseParticleTable + void processPurityQA(aod::FdCollision const& col, + FemtoFullSigmaParticles const&) + { + fillCollision(col); + + auto theGroupPartsOne = partsTrackFullSigma->sliceByCached(aod::femtouniverseparticle::fdCollisionId, col.globalIndex(), cache); + + for (const auto& part : theGroupPartsOne) { + + if (!isParticleNSigma(part.p(), part.tpcFullNSigmaPr(), part.tofFullNSigmaPr(), part.tpcFullNSigmaPi(), part.tofFullNSigmaPi(), part.tpcFullNSigmaKa(), part.tofFullNSigmaKa())) { + continue; + } + if (ConfTrack.confDoPartNsigmaRejection && isParticleNSigmaRejected(part.p(), part.tpcFullNSigmaPi(), part.tofFullNSigmaPi(), part.tpcFullNSigmaKa(), part.tofFullNSigmaKa(), part.tpcFullNSigmaPr(), part.tofFullNSigmaPr())) { + continue; + } + + trackHistoPartTrack.fillQA(part); + if (std::abs(ConfTrack.confPDGCodeTrack) == PDG_t::kProton) { + qaRegistry.fill(HIST("PurityQA/nSigmaFullTPCPr"), part.p(), part.tpcFullNSigmaPr()); + qaRegistry.fill(HIST("PurityQA/nSigmaFullTOFPr"), part.p(), part.tofFullNSigmaPr()); + qaRegistry.fill(HIST("PurityQA/nSigmaFullCombPr"), part.p(), std::hypot(part.tpcFullNSigmaPr(), part.tofFullNSigmaPr())); + } else if (std::abs(ConfTrack.confPDGCodeTrack) == PDG_t::kPiPlus) { + qaRegistry.fill(HIST("PurityQA/nSigmaFullTPCPi"), part.p(), part.tpcFullNSigmaPi()); + qaRegistry.fill(HIST("PurityQA/nSigmaFullTOFPi"), part.p(), part.tofFullNSigmaPi()); + qaRegistry.fill(HIST("PurityQA/nSigmaFullCombPi"), part.p(), std::hypot(part.tpcFullNSigmaPi(), part.tofFullNSigmaPi())); + } else if (std::abs(ConfTrack.confPDGCodeTrack) == PDG_t::kKPlus) { + qaRegistry.fill(HIST("PurityQA/nSigmaFullTPCKa"), part.p(), part.tpcFullNSigmaKa()); + qaRegistry.fill(HIST("PurityQA/nSigmaFullTOFKa"), part.p(), part.tofFullNSigmaKa()); + qaRegistry.fill(HIST("PurityQA/nSigmaFullCombKa"), part.p(), std::hypot(part.tpcFullNSigmaKa(), part.tofFullNSigmaKa())); + } + } + } + PROCESS_SWITCH(FemtoUniversePairTaskTrackD0, processPurityQA, "Enable processing QA for purity estimation", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) From c8c6eb7a6dc848d602691e7508b8508954c59076 Mon Sep 17 00:00:00 2001 From: ariedel-cern <85537041+ariedel-cern@users.noreply.github.com> Date: Thu, 30 Jul 2026 10:18:58 +0200 Subject: [PATCH 44/71] [PWGCF] Fix V0V0 processing in femto framework (#17255) --- PWGCF/Femto/Core/pairBuilder.h | 60 ++++-- PWGCF/Femto/Core/trackBuilder.h | 8 +- PWGCF/Femto/Core/trackHistManager.h | 24 ++- PWGCF/Femto/Core/v0Builder.h | 4 +- PWGCF/Femto/Core/v0HistManager.h | 4 + .../femtoProducerDerivedToDerived.cxx | 11 +- PWGCF/Femto/Tasks/femtoPairTrackV0.cxx | 4 +- .../Tasks/femtoPairV0TwoTrackResonance.cxx | 4 +- PWGCF/Femto/Tasks/femtoPairV0V0.cxx | 185 +++++++++++------- .../Femto/Tasks/femtoTripletTrackTrackV0.cxx | 4 +- PWGCF/Femto/Tasks/femtoV0Qa.cxx | 8 +- .../Tasks/femtoPairLambdaAntilambda.cxx | 90 ++++----- 12 files changed, 246 insertions(+), 160 deletions(-) diff --git a/PWGCF/Femto/Core/pairBuilder.h b/PWGCF/Femto/Core/pairBuilder.h index 879cd2486ba..1cc9cf94a39 100644 --- a/PWGCF/Femto/Core/pairBuilder.h +++ b/PWGCF/Femto/Core/pairBuilder.h @@ -323,8 +323,10 @@ class PairV0V0Builder typename T14, typename T15, typename T16, + typename T17, typename T18, - typename T17> + typename T19, + typename T20> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confV0Selection1, @@ -339,37 +341,55 @@ class PairV0V0Builder std::map> const& colHistSpec, std::map> const& V0HistSpec1, std::map> const& V0HistSpec2, - std::map> const& PosDauHistSpec, - std::map> const& NegDauHistSpec, - std::map> const& pairHistSpec, - std::map> const& cprHistSpecPos, - std::map> const& cprHistSpecNeg) + std::map> const& PosDauHistSpec1, + std::map> const& NegDauHistSpec1, + std::map> const& PosDauHistSpec2, + std::map> const& NegDauHistSpec2, + std::map> const& pairHistSpec, + std::map> const& cprHistSpecPos, + std::map> const& cprHistSpecNeg) { - - // check if correlate the same tracks or not mSameSpecies = confMixing.sameSpecies.value; + if constexpr (v0Type1 != v0Type2) { + // two different v0 species can never be identical particles + if (mSameSpecies) { + LOG(warn) << "sameSpecies=true is impossible for different v0 species (v0Type1=" + << static_cast(v0Type1) << ", v0Type2=" << static_cast(v0Type2) + << "). Overriding sameSpecies to false."; + mSameSpecies = false; + } + } else { + // same v0 species: both values are legitimate (e.g. lambda-lambda vs lambda-antilambda), + // but running as different species only makes sense if the two selections are disjoint + if (!mSameSpecies && confV0Selection1.sign.value == confV0Selection2.sign.value) { + LOG(warn) << "sameSpecies=false for identical v0 species with identical sign (" + << confV0Selection1.sign.value << "). If both selections match the same " + << "candidates, this produces self-pairs and double counting."; + } + } + mColHistManager.template init(registry, colHistSpec, confCollisionBinning); mPairHistManagerSe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); mPairHistManagerMe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); mPc.template init(confPairCuts); - if (mSameSpecies) { - mV0Cleaner1.init(confV0Cleaner1); - mV0HistManager1.template init(registry, V0HistSpec1, confV0Selection1, PosDauHistSpec, NegDauHistSpec); + mV0Cleaner1.init(confV0Cleaner1); + mV0Cleaner2.init(confV0Cleaner2); + // the first v0 (and its daughters) is always present + mV0HistManager1.template init(registry, V0HistSpec1, confV0Selection1, PosDauHistSpec1, NegDauHistSpec1); + + if (mSameSpecies) { mPairHistManagerSe.setMass(confV0Selection1.pdgCodeAbs.value, confV0Selection1.pdgCodeAbs.value); mPairHistManagerSe.setCharge(1, 1); - mCprSe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprPos); + mCprSe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprNeg); mPairHistManagerMe.setMass(confV0Selection1.pdgCodeAbs.value, confV0Selection1.pdgCodeAbs.value); mPairHistManagerMe.setCharge(1, 1); mCprMe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprNeg); } else { - mV0Cleaner1.init(confV0Cleaner1); - mV0Cleaner2.init(confV0Cleaner2); - mV0HistManager1.template init(registry, V0HistSpec1, confV0Selection1, PosDauHistSpec, NegDauHistSpec); - mV0HistManager2.template init(registry, V0HistSpec2, confV0Selection2, PosDauHistSpec, NegDauHistSpec); + mV0HistManager2.template init(registry, V0HistSpec2, confV0Selection2, PosDauHistSpec2, NegDauHistSpec2); mPairHistManagerSe.setMass(confV0Selection1.pdgCodeAbs.value, confV0Selection2.pdgCodeAbs.value); mPairHistManagerSe.setCharge(1, 1); @@ -385,6 +405,7 @@ class PairV0V0Builder mMixingDepth = confMixing.depth.value; // setup rng if necessary + // mDist is bounded at declaration, so it stays valid even if this branch is not taken if (confMixing.seed.value >= 0) { uint64_t randomSeed = 0; mMixIdenticalParticles = true; @@ -452,8 +473,8 @@ class PairV0V0Builder } } - template - void processMixedEvent(T1 const& cols, T2 const& trackTable, T3 const& /*v0table*/, T4& partition1, T5& partition2, T6& cache, T7& binsVtxMult, T8& binsVtxCent, T9& binsVtxMultCent) + template + void processMixedEvent(T1 const& cols, T2 const& trackTable, T3& partition1, T4& partition2, T5& cache, T6& binsVtxMult, T7& binsVtxCent, T8& binsVtxMultCent) { if (mSameSpecies) { @@ -537,7 +558,8 @@ class PairV0V0Builder int mMixingDepth = 5; bool mMixIdenticalParticles = false; std::mt19937 mRng; - std::uniform_int_distribution<> mDist; + std::uniform_int_distribution<> mDist{static_cast(pairprocesshelpers::kOrder12), + static_cast(pairprocesshelpers::kOrder21)}; }; template void processTracks(T1& col, T2& /*trackTable*/, T3& partitionTrack1, T4& partitionTrack2, T5& cache, T6& newTrackTable, T7& newCollisionTable) { - indexMap.clear(); if (mLimitTrack1 > 0) { auto trackSlice1 = partitionTrack1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -916,6 +915,13 @@ class TrackBuilderDerivedToDerived return idx; } + template + void reset(T const& tracks) + { + indexMap.clear(); + indexMap.reserve(tracks.size()); + } + private: int mLimitTrack1 = 0; int mLimitTrack2 = 0; diff --git a/PWGCF/Femto/Core/trackHistManager.h b/PWGCF/Femto/Core/trackHistManager.h index af36c02acf6..3086a015e3c 100644 --- a/PWGCF/Femto/Core/trackHistManager.h +++ b/PWGCF/Femto/Core/trackHistManager.h @@ -154,8 +154,10 @@ struct ConfTrackBinning : o2::framework::ConfigurableGroup { constexpr const char PrefixTrackBinning1[] = "TrackBinning1"; constexpr const char PrefixTrackBinning2[] = "TrackBinning2"; constexpr const char PrefixTrackBinning3[] = "TrackBinning3"; -constexpr const char PrefixV0PosDauBinning[] = "V0PosDauBinning"; -constexpr const char PrefixV0NegDauBinning[] = "V0NegDauBinning"; +constexpr const char PrefixV01PosDauBinning[] = "V01PosDauBinning"; +constexpr const char PrefixV01NegDauBinning[] = "V01NegDauBinning"; +constexpr const char PrefixV02PosDauBinning[] = "V02PosDauBinning"; +constexpr const char PrefixV02NegDauBinning[] = "V02NegDauBinning"; constexpr const char PrefixCascadePosDauBinning[] = "CascadePosDauBinning"; constexpr const char PrefixCascadeNegDauBinning[] = "CascadeNegDauBinning"; constexpr const char PrefixCascadeBachelorBinning[] = "CascadeBachelorBinning"; @@ -170,8 +172,10 @@ constexpr const char PrefixKaonMinusBinning[] = "KaonMinusBinning"; using ConfTrackBinning1 = ConfTrackBinning; using ConfTrackBinning2 = ConfTrackBinning; using ConfTrackBinning3 = ConfTrackBinning; -using ConfV0PosDauBinning = ConfTrackBinning; -using ConfV0NegDauBinning = ConfTrackBinning; +using ConfV01PosDauBinning = ConfTrackBinning; +using ConfV01NegDauBinning = ConfTrackBinning; +using ConfV02PosDauBinning = ConfTrackBinning; +using ConfV02NegDauBinning = ConfTrackBinning; using ConfCascadePosDauBinning = ConfTrackBinning; using ConfCascadeNegDauBinning = ConfTrackBinning; using ConfCascadeBachelorBinning = ConfTrackBinning; @@ -255,8 +259,10 @@ constexpr const char PrefixTrackQaBinning1[] = "TrackQaBinning1"; constexpr const char PrefixTrackQaBinning2[] = "TrackQaBinning2"; constexpr const char PrefixResonancePosDauQaBinning[] = "ResonancePosDauQaBinning"; constexpr const char PrefixResonanceNegDauQaBinning[] = "ResonanceNegDauQaBinning"; -constexpr const char PrefixV0PosDauQaBinning[] = "V0PosDauQaBinning"; -constexpr const char PrefixV0NegDauQaBinning[] = "V0NegDauQaBinning"; +constexpr const char PrefixV01PosDauQaBinning[] = "V01PosDauQaBinning"; +constexpr const char PrefixV01NegDauQaBinning[] = "V01NegDauQaBinning"; +constexpr const char PrefixV02PosDauQaBinning[] = "V02PosDauQaBinning"; +constexpr const char PrefixV02NegDauQaBinning[] = "V02NegDauQaBinning"; constexpr const char PrefixCascadePosDauQaBinning[] = "CascadePosDauQaBinning"; constexpr const char PrefixCascadeNegDauQaBinning[] = "CascadeNegDauQaBinning"; constexpr const char PrefixCascadeBachelorQaBinning[] = "CascadeBachelorQaBinning"; @@ -266,8 +272,10 @@ using ConfTrackQaBinning1 = ConfTrackQaBinning; using ConfTrackQaBinning2 = ConfTrackQaBinning; using ConfResonancePosDauQaBinning = ConfTrackQaBinning; using ConfResonanceNegDauQaBinning = ConfTrackQaBinning; -using ConfV0PosDauQaBinning = ConfTrackQaBinning; -using ConfV0NegDauQaBinning = ConfTrackQaBinning; +using ConfV01PosDauQaBinning = ConfTrackQaBinning; +using ConfV01NegDauQaBinning = ConfTrackQaBinning; +using ConfV02PosDauQaBinning = ConfTrackQaBinning; +using ConfV02NegDauQaBinning = ConfTrackQaBinning; using ConfCascadePosDauQaBinning = ConfTrackQaBinning; using ConfCascadeNegDauQaBinning = ConfTrackQaBinning; using ConfCascadeBachelorQaBinning = ConfTrackQaBinning; diff --git a/PWGCF/Femto/Core/v0Builder.h b/PWGCF/Femto/Core/v0Builder.h index ec2a03c1423..4dac03ed8ae 100644 --- a/PWGCF/Femto/Core/v0Builder.h +++ b/PWGCF/Femto/Core/v0Builder.h @@ -191,7 +191,7 @@ enum V0Filters { kRejectionLambdaMass, kLambdaMassMin, kLambdaMassMax, - kTrackFiltersMax + kV0FiltersMax }; constexpr char LambdaFilterHistName[] = "hLambdaFilters"; @@ -261,6 +261,7 @@ class V0Selection : public baseselection::BaseSelectionaddSelection(kDcaDaughMax, v0SelectionNames.at(kDcaDaughMax), config.dcaDauMax.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kDecayVtxMax, v0SelectionNames.at(kDecayVtxMax), config.decayVtxMax.value, limits::kUpperLimit, true, true, false); this->addSelection(kCpaMin, v0SelectionNames.at(kCpaMin), config.cpaMin.value, limits::kLowerLimit, true, true, false); this->addSelection(kTransRadMin, v0SelectionNames.at(kTransRadMin), config.transRadMin.value, limits::kLowerLimit, true, true, false); this->addSelection(kTransRadMax, v0SelectionNames.at(kTransRadMax), config.transRadMax.value, limits::kUpperLimit, true, true, false); @@ -316,7 +317,6 @@ class V0Selection : public baseselection::BaseSelection clustersDaughters = {1.f * posDaughter.tpcNClsFound(), 1.f * negDaughter.tpcNClsFound()}; this->evaluateObservable(kDauTpcClsMin, *std::min_element(clustersDaughters.begin(), clustersDaughters.end())); - // daughter pid selections this->evaluateObservable(kPosDaughTpcPion, posDaughter.tpcNSigmaPi()); this->evaluateObservable(kPosDaughTpcProton, posDaughter.tpcNSigmaPr()); this->evaluateObservable(kNegDaughTpcPion, negDaughter.tpcNSigmaPi()); diff --git a/PWGCF/Femto/Core/v0HistManager.h b/PWGCF/Femto/Core/v0HistManager.h index 9f7e7736d61..513862d6583 100644 --- a/PWGCF/Femto/Core/v0HistManager.h +++ b/PWGCF/Femto/Core/v0HistManager.h @@ -117,8 +117,12 @@ struct ConfK0shortBinning : o2::framework::ConfigurableGroup { constexpr const char PrefixLambdaBinning1[] = "LambdaBinning1"; using ConfLambdaBinning1 = ConfLambdaBinning; +constexpr const char PrefixLambdaBinning2[] = "LambdaBinning2"; +using ConfLambdaBinning2 = ConfLambdaBinning; constexpr const char PrefixK0shortBinning1[] = "K0shortBinning1"; using ConfK0shortBinning1 = ConfK0shortBinning; +constexpr const char PrefixK0shortBinning2[] = "K0shortBinning2"; +using ConfK0shortBinning2 = ConfK0shortBinning; template struct ConfV0QaBinning : o2::framework::ConfigurableGroup { diff --git a/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx b/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx index 128f4e4db02..bde9713d72e 100644 --- a/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx @@ -115,7 +115,7 @@ struct FemtoProducerDerivedToDerived { kinkBuilder.init(confKinkBuilder); if ((static_cast(doprocessTracks) + static_cast(doprocessTracksWithMass) + static_cast(doprocessTracksLambdas) + static_cast(doprocessLambdas) + static_cast(doprocessTracksXis) + static_cast(doprocessTracksOmegas) + static_cast(doprocessTracksK0shorts) + static_cast(doprocessTracksSigma) + static_cast(doprocessTracksSigmaPlus)) > 1) { - LOG(fatal) << "Only one proccess function can be activated"; + LOG(fatal) << "Only one proccess function can be activated!"; } } @@ -125,6 +125,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); } @@ -135,6 +136,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); } @@ -145,6 +147,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); @@ -156,6 +159,7 @@ struct FemtoProducerDerivedToDerived { if (v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); } @@ -166,6 +170,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || cascadeBuilder.collisionHasTooFewXis(col, xis, xiPartition, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); cascadeBuilder.processXis(col, xis, tracks, xiPartition, trackBuilder, cache, cascadeBuilderProducts, trackBuilderProducts, collisionBuilderProducts); @@ -177,6 +182,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || cascadeBuilder.collisionHasTooFewOmegas(col, omegas, omegaPartition, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); cascadeBuilder.processOmegas(col, omegas, tracks, omegaPartition, trackBuilder, cache, cascadeBuilderProducts, trackBuilderProducts, collisionBuilderProducts); @@ -188,6 +194,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || v0Builder.collisionHasTooFewK0shorts(col, k0shorts, k0shortPartition, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); v0Builder.processK0shorts(col, k0shorts, tracks, k0shortPartition, trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); @@ -199,6 +206,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || kinkBuilder.collisionHasTooFewSigma(col, sigma, sigmaPartition, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); kinkBuilder.processSigma(col, sigma, tracks, sigmaPartition, trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); @@ -210,6 +218,7 @@ struct FemtoProducerDerivedToDerived { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || kinkBuilder.collisionHasTooFewSigmaPlus(col, sigmaplus, sigmaPlusPartition, cache)) { return; } + trackBuilder.reset(tracks); collisionBuilder.processCollision(col, collisionBuilderProducts); trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); kinkBuilder.processSigmaPlus(col, sigmaplus, tracks, sigmaPlusPartition, trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); diff --git a/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx b/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx index 69087f58180..6974ed0b2c7 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx @@ -84,8 +84,8 @@ struct FemtoPairTrackV0 { o2::framework::Preslice perColtracksWithLabel = o2::aod::femtobase::stored::fColId; // setup for daughters - trackhistmanager::ConfV0PosDauBinning confPosDauBinning; - trackhistmanager::ConfV0NegDauBinning confNegDauBinning; + trackhistmanager::ConfV01PosDauBinning confPosDauBinning; + trackhistmanager::ConfV01NegDauBinning confNegDauBinning; // setup lambdas v0builder::ConfLambdaSelection1 lambdaSelection; diff --git a/PWGCF/Femto/Tasks/femtoPairV0TwoTrackResonance.cxx b/PWGCF/Femto/Tasks/femtoPairV0TwoTrackResonance.cxx index 6a0e25e40d2..d742aba5be4 100644 --- a/PWGCF/Femto/Tasks/femtoPairV0TwoTrackResonance.cxx +++ b/PWGCF/Femto/Tasks/femtoPairV0TwoTrackResonance.cxx @@ -70,8 +70,8 @@ struct FemtoPairV0TwoTrackResonance { colhistmanager::ConfCollisionBinning confCollisionBinning; // setup for daughters for v0s - trackhistmanager::ConfV0PosDauBinning confV0PosDauBinning; - trackhistmanager::ConfV0NegDauBinning confV0NegDauBinning; + trackhistmanager::ConfV01PosDauBinning confV0PosDauBinning; + trackhistmanager::ConfV01NegDauBinning confV0NegDauBinning; // setup lambdas v0builder::ConfLambdaSelection1 lambdaSelection; diff --git a/PWGCF/Femto/Tasks/femtoPairV0V0.cxx b/PWGCF/Femto/Tasks/femtoPairV0V0.cxx index 7ebc4f3c7fd..82ae5b62bb4 100644 --- a/PWGCF/Femto/Tasks/femtoPairV0V0.cxx +++ b/PWGCF/Femto/Tasks/femtoPairV0V0.cxx @@ -43,6 +43,13 @@ using namespace o2::analysis::femto; +// Each pair slot (1 and 2) has its own selection, cleaner, binning and partition, so that +// any combination of v0s can be correlated: +// lambda-lambda : LambdaSelection1 == LambdaSelection2, Mixing.sameSpecies = true +// lambda-antilambda : LambdaSelection1/2 differ only in sign, Mixing.sameSpecies = false +// k0short-k0short : K0shortSelection1 == K0shortSelection2, Mixing.sameSpecies = true +// lambda-k0short : LambdaSelection1 and K0shortSelection2, Mixing.sameSpecies = false +// Slot N always uses selection N, cleaner N, binning N and partition N. struct FemtoPairV0V0 { // setup tables @@ -72,30 +79,44 @@ struct FemtoPairV0V0 { colhistmanager::ConfCollisionBinning confCollisionBinning; // setup for daughters - trackhistmanager::ConfV0PosDauBinning confPosDauBinning; - trackhistmanager::ConfV0NegDauBinning confNegDauBinning; + // separate binning per v0 slot, so that e.g. lambda (proton/pion daughters) and + // k0short (pion/pion daughters) can be binned independently + trackhistmanager::ConfV01PosDauBinning confV01PosDauBinning; + trackhistmanager::ConfV01NegDauBinning confV01NegDauBinning; + trackhistmanager::ConfV02PosDauBinning confV02PosDauBinning; + trackhistmanager::ConfV02NegDauBinning confV02NegDauBinning; // setup lambdas - v0builder::ConfLambdaSelection1 confLambdaSelection; - particlecleaner::ConfLambdaCleaner1 confLambdaCleaner; - v0histmanager::ConfLambdaBinning1 confLambdaBinning; - - o2::framework::Partition lambdaPartition = MAKE_LAMBDA_PARTITION(confLambdaSelection); + v0builder::ConfLambdaSelection1 confLambdaSelection1; + v0builder::ConfLambdaSelection2 confLambdaSelection2; + particlecleaner::ConfLambdaCleaner1 confLambdaCleaner1; + particlecleaner::ConfLambdaCleaner2 confLambdaCleaner2; + v0histmanager::ConfLambdaBinning1 confLambdaBinning1; + v0histmanager::ConfLambdaBinning2 confLambdaBinning2; + + o2::framework::Partition lambdaPartition1 = MAKE_LAMBDA_PARTITION(confLambdaSelection1); + o2::framework::Partition lambdaPartition2 = MAKE_LAMBDA_PARTITION(confLambdaSelection2); o2::framework::Preslice perColLambdas = o2::aod::femtobase::stored::fColId; - o2::framework::Partition lambdaWithLabelPartition = MAKE_LAMBDA_PARTITION(confLambdaSelection); - o2::framework::Preslice perCollambdasWithLabel = o2::aod::femtobase::stored::fColId; + o2::framework::Partition lambdaWithLabelPartition1 = MAKE_LAMBDA_PARTITION(confLambdaSelection1); + o2::framework::Partition lambdaWithLabelPartition2 = MAKE_LAMBDA_PARTITION(confLambdaSelection2); + o2::framework::Preslice perColLambdasWithLabel = o2::aod::femtobase::stored::fColId; // setup k0shorts - v0builder::ConfK0shortSelection1 confK0shortSelection; - particlecleaner::ConfK0shortCleaner1 confK0shortCleaner; - v0histmanager::ConfK0shortBinning1 confK0shortBinning; + v0builder::ConfK0shortSelection1 confK0shortSelection1; + v0builder::ConfK0shortSelection2 confK0shortSelection2; + particlecleaner::ConfK0shortCleaner1 confK0shortCleaner1; + particlecleaner::ConfK0shortCleaner2 confK0shortCleaner2; + v0histmanager::ConfK0shortBinning1 confK0shortBinning1; + v0histmanager::ConfK0shortBinning2 confK0shortBinning2; - o2::framework::Partition k0shortPartition = MAKE_K0SHORT_PARTITION(confK0shortSelection); - o2::framework::Preslice perColk0shorts = o2::aod::femtobase::stored::fColId; + o2::framework::Partition k0shortPartition1 = MAKE_K0SHORT_PARTITION(confK0shortSelection1); + o2::framework::Partition k0shortPartition2 = MAKE_K0SHORT_PARTITION(confK0shortSelection2); + o2::framework::Preslice perColK0shorts = o2::aod::femtobase::stored::fColId; - o2::framework::Partition k0shortWithLabelPartition = MAKE_K0SHORT_PARTITION(confK0shortSelection); - o2::framework::Preslice perColk0shortsWithLabel = o2::aod::femtobase::stored::fColId; + o2::framework::Partition k0shortWithLabelPartition1 = MAKE_K0SHORT_PARTITION(confK0shortSelection1); + o2::framework::Partition k0shortWithLabelPartition2 = MAKE_K0SHORT_PARTITION(confK0shortSelection2); + o2::framework::Preslice perColK0shortsWithLabel = o2::aod::femtobase::stored::fColId; // setup pairs pairhistmanager::ConfPairBinning confPairBinning; @@ -169,16 +190,26 @@ struct FemtoPairV0V0 { void init(o2::framework::InitContext&) { - bool processData = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent || doprocessLambdaK0shortSameEvent || doprocessLambdaK0shortMixedEvent; - bool processMc = doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaMixedEventMc || doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortMixedEventMc || doprocessLambdaK0shortSameEventMc || doprocessLambdaK0shortMixedEventMc; + bool processData = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || + doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent || + doprocessLambdaK0shortSameEvent || doprocessLambdaK0shortMixedEvent; + bool processMc = doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaMixedEventMc || + doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortMixedEventMc || + doprocessLambdaK0shortSameEventMc || doprocessLambdaK0shortMixedEventMc; if (processData && processMc) { LOG(fatal) << "Both data and mc processing is enabled. Breaking..."; } + if (!processData && !processMc) { + LOG(fatal) << "Neither data nor mc processing is enabled. Breaking..."; + } - bool processLambdaLambda = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaMixedEventMc; - bool processK0shortK0short = doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent || doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortMixedEventMc; - bool processLambdaK0short = doprocessLambdaK0shortSameEvent || doprocessLambdaK0shortMixedEvent || doprocessLambdaK0shortSameEventMc || doprocessLambdaK0shortMixedEventMc; + bool processLambdaLambda = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || + doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaMixedEventMc; + bool processK0shortK0short = doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent || + doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortMixedEventMc; + bool processLambdaK0short = doprocessLambdaK0shortSameEvent || doprocessLambdaK0shortMixedEvent || + doprocessLambdaK0shortSameEventMc || doprocessLambdaK0shortMixedEventMc; if (static_cast(processLambdaLambda) + static_cast(processK0shortK0short) + static_cast(processLambdaK0short) > 1) { LOG(fatal) << "Only one of lambda-lambda, k0short-k0short or lambda-k0short processing can be enabled. Breaking..."; @@ -186,140 +217,146 @@ struct FemtoPairV0V0 { // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; // setup histograms std::map> colHistSpec; - std::map> posDauSpec; - std::map> negDauSpec; - std::map> lambdaHistSpec; - std::map> k0shortHistSpec; + std::map> posDauSpec1; + std::map> negDauSpec1; + std::map> posDauSpec2; + std::map> negDauSpec2; + std::map> lambdaHistSpec1; + std::map> lambdaHistSpec2; + std::map> k0shortHistSpec1; + std::map> k0shortHistSpec2; std::map> pairV0V0HistSpec; std::map> cprHistSpecPos = closepairrejection::makeCprHistSpecMap(confCprPos); std::map> cprHistSpecNeg = closepairrejection::makeCprHistSpecMap(confCprNeg); if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); - posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); - negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); + posDauSpec1 = trackhistmanager::makeTrackHistSpecMap(confV01PosDauBinning); + negDauSpec1 = trackhistmanager::makeTrackHistSpecMap(confV01NegDauBinning); + posDauSpec2 = trackhistmanager::makeTrackHistSpecMap(confV02PosDauBinning); + negDauSpec2 = trackhistmanager::makeTrackHistSpecMap(confV02NegDauBinning); + pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); + if (processLambdaLambda) { - lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); - pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + lambdaHistSpec1 = v0histmanager::makeV0HistSpecMap(confLambdaBinning1); + lambdaHistSpec2 = v0histmanager::makeV0HistSpecMap(confLambdaBinning2); + pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confLambdaSelection2, confLambdaCleaner1, confLambdaCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, lambdaHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } - // setup for k0short - if (doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent) { - k0shortHistSpec = v0histmanager::makeV0HistSpecMap(confK0shortBinning); - pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + if (processK0shortK0short) { + k0shortHistSpec1 = v0histmanager::makeV0HistSpecMap(confK0shortBinning1); + k0shortHistSpec2 = v0histmanager::makeV0HistSpecMap(confK0shortBinning2); + pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection1, confK0shortSelection2, confK0shortCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } - // setup for lambda-k0short - if (doprocessLambdaK0shortSameEvent || doprocessLambdaK0shortMixedEvent) { - lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); - k0shortHistSpec = v0histmanager::makeV0HistSpecMap(confK0shortBinning); - pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairLambdaK0shortBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confK0shortSelection, confLambdaCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + if (processLambdaK0short) { + lambdaHistSpec1 = v0histmanager::makeV0HistSpecMap(confLambdaBinning1); + k0shortHistSpec2 = v0histmanager::makeV0HistSpecMap(confK0shortBinning2); + pairLambdaK0shortBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confK0shortSelection2, confLambdaCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); - posDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confPosDauBinning); - negDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confNegDauBinning); + posDauSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confV01PosDauBinning); + negDauSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confV01NegDauBinning); + posDauSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confV02PosDauBinning); + negDauSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confV02NegDauBinning); + pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); + if (processLambdaLambda) { - lambdaHistSpec = v0histmanager::makeV0McHistSpecMap(confLambdaBinning); - pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + lambdaHistSpec1 = v0histmanager::makeV0McHistSpecMap(confLambdaBinning1); + lambdaHistSpec2 = v0histmanager::makeV0McHistSpecMap(confLambdaBinning2); + pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confLambdaSelection2, confLambdaCleaner1, confLambdaCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, lambdaHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } - // setup for k0short - if (doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent) { - k0shortHistSpec = v0histmanager::makeV0McHistSpecMap(confK0shortBinning); - pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + if (processK0shortK0short) { + k0shortHistSpec1 = v0histmanager::makeV0McHistSpecMap(confK0shortBinning1); + k0shortHistSpec2 = v0histmanager::makeV0McHistSpecMap(confK0shortBinning2); + pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection1, confK0shortSelection2, confK0shortCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } - // setup for lambda-k0short - if (doprocessLambdaK0shortSameEvent || doprocessLambdaK0shortMixedEvent) { - lambdaHistSpec = v0histmanager::makeV0McHistSpecMap(confLambdaBinning); - k0shortHistSpec = v0histmanager::makeV0McHistSpecMap(confK0shortBinning); - pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairLambdaK0shortBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confK0shortSelection, confLambdaCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + if (processLambdaK0short) { + lambdaHistSpec1 = v0histmanager::makeV0McHistSpecMap(confLambdaBinning1); + k0shortHistSpec2 = v0histmanager::makeV0McHistSpecMap(confK0shortBinning2); + pairLambdaK0shortBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confK0shortSelection2, confLambdaCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } } - }; + } void processLambdaLambdaSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoLambdas const& lambdas) { - pairLambdaLambdaBuilder.processSameEvent(col, tracks, lambdas, lambdaPartition, lambdaPartition, cache); + pairLambdaLambdaBuilder.processSameEvent(col, tracks, lambdas, lambdaPartition1, lambdaPartition2, cache); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaLambdaSameEvent, "Enable processing same event processing for lambda-lambda", true); void processLambdaLambdaSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& lambdas, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairLambdaLambdaBuilder.processSameEvent(col, mcCols, tracks, lambdas, lambdaWithLabelPartition, lambdaWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache); + pairLambdaLambdaBuilder.processSameEvent(col, mcCols, tracks, lambdas, lambdaWithLabelPartition1, lambdaWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaLambdaSameEventMc, "Enable processing same event processing for lambda-lambda with mc information", false); - void processLambdaLambdaMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoLambdas const& lambdas) + void processLambdaLambdaMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoLambdas const& /*lambdas*/) { - pairLambdaLambdaBuilder.processMixedEvent(cols, tracks, lambdas, lambdaPartition, lambdaPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairLambdaLambdaBuilder.processMixedEvent(cols, tracks, lambdaPartition1, lambdaPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaLambdaMixedEvent, "Enable processing mixed event processing for lambda-lambda", true); void processLambdaLambdaMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& /*lambdas*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairLambdaLambdaBuilder.processMixedEvent(cols, mcCols, tracks, lambdaWithLabelPartition, lambdaWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairLambdaLambdaBuilder.processMixedEvent(cols, mcCols, tracks, lambdaWithLabelPartition1, lambdaWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaLambdaMixedEventMc, "Enable processing mixed event processing for lambda-lambda with mc information", false); void processK0shortK0shortSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoK0shorts const& k0shorts) { - pairK0shortK0shortBuilder.processSameEvent(col, tracks, k0shorts, k0shortPartition, k0shortPartition, cache); + pairK0shortK0shortBuilder.processSameEvent(col, tracks, k0shorts, k0shortPartition1, k0shortPartition2, cache); } PROCESS_SWITCH(FemtoPairV0V0, processK0shortK0shortSameEvent, "Enable processing same event processing for k0short-k0short", false); void processK0shortK0shortSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoK0shortsWithLabel const& k0shorts, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairK0shortK0shortBuilder.processSameEvent(col, mcCols, tracks, k0shorts, k0shortWithLabelPartition, k0shortWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache); + pairK0shortK0shortBuilder.processSameEvent(col, mcCols, tracks, k0shorts, k0shortWithLabelPartition1, k0shortWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache); } PROCESS_SWITCH(FemtoPairV0V0, processK0shortK0shortSameEventMc, "Enable processing same event processing for k0short-k0short with mc information", false); - void processK0shortK0shortMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoK0shorts const& k0shorts) + void processK0shortK0shortMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoK0shorts const& /*k0shorts*/) { - pairK0shortK0shortBuilder.processMixedEvent(cols, tracks, k0shorts, k0shortPartition, k0shortPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairK0shortK0shortBuilder.processMixedEvent(cols, tracks, k0shortPartition1, k0shortPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairV0V0, processK0shortK0shortMixedEvent, "Enable processing mixed event processing for k0short-k0short", false); void processK0shortK0shortMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoK0shortsWithLabel const& /*k0shorts*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairK0shortK0shortBuilder.processMixedEvent(cols, mcCols, tracks, k0shortWithLabelPartition, k0shortWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairK0shortK0shortBuilder.processMixedEvent(cols, mcCols, tracks, k0shortWithLabelPartition1, k0shortWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairV0V0, processK0shortK0shortMixedEventMc, "Enable processing mixed event processing for k0short-k0short with mc information", false); void processLambdaK0shortSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoLambdas const& lambdas, FemtoK0shorts const& /*k0shorts*/) { - pairLambdaK0shortBuilder.processSameEvent(col, tracks, lambdas, lambdaPartition, k0shortPartition, cache); + pairLambdaK0shortBuilder.processSameEvent(col, tracks, lambdas, lambdaPartition1, k0shortPartition2, cache); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaK0shortSameEvent, "Enable processing same event processing for lambda-k0short", false); void processLambdaK0shortSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& lambdas, FemtoK0shortsWithLabel const& /*k0shorts*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairLambdaK0shortBuilder.processSameEvent(col, mcCols, tracks, lambdas, lambdaWithLabelPartition, k0shortWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache); + pairLambdaK0shortBuilder.processSameEvent(col, mcCols, tracks, lambdas, lambdaWithLabelPartition1, k0shortWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaK0shortSameEventMc, "Enable processing same event processing for lambda-k0short with mc information", false); - void processLambdaK0shortMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoLambdas const& lambdas, FemtoK0shorts const& /*k0shorts*/) + void processLambdaK0shortMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoLambdas const& /*lambdas*/, FemtoK0shorts const& /*k0shorts*/) { - pairLambdaK0shortBuilder.processMixedEvent(cols, tracks, lambdas, lambdaPartition, k0shortPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairLambdaK0shortBuilder.processMixedEvent(cols, tracks, lambdaPartition1, k0shortPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaK0shortMixedEvent, "Enable processing mixed event processing for lambda-k0short", false); void processLambdaK0shortMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& /*lambdas*/, FemtoK0shortsWithLabel const& /*k0shorts*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairLambdaK0shortBuilder.processMixedEvent(cols, mcCols, tracks, lambdaWithLabelPartition, k0shortWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairLambdaK0shortBuilder.processMixedEvent(cols, mcCols, tracks, lambdaWithLabelPartition1, k0shortWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairV0V0, processLambdaK0shortMixedEventMc, "Enable processing mixed event processing for lambda-k0short with mc information", false); }; diff --git a/PWGCF/Femto/Tasks/femtoTripletTrackTrackV0.cxx b/PWGCF/Femto/Tasks/femtoTripletTrackTrackV0.cxx index 5be5c5d372a..6fe9a688384 100644 --- a/PWGCF/Femto/Tasks/femtoTripletTrackTrackV0.cxx +++ b/PWGCF/Femto/Tasks/femtoTripletTrackTrackV0.cxx @@ -94,8 +94,8 @@ struct FemtoTripletTrackTrackV0 { o2::framework::Preslice perColtracksWithLabel = o2::aod::femtobase::stored::fColId; // setup for daughters - trackhistmanager::ConfV0PosDauBinning confPosDauBinning; - trackhistmanager::ConfV0NegDauBinning confNegDauBinning; + trackhistmanager::ConfV01PosDauBinning confPosDauBinning; + trackhistmanager::ConfV01NegDauBinning confNegDauBinning; // setup lambdas v0builder::ConfLambdaSelection1 confLambdaSelection; diff --git a/PWGCF/Femto/Tasks/femtoV0Qa.cxx b/PWGCF/Femto/Tasks/femtoV0Qa.cxx index bcd8aa7a246..5567532fcbc 100644 --- a/PWGCF/Femto/Tasks/femtoV0Qa.cxx +++ b/PWGCF/Femto/Tasks/femtoV0Qa.cxx @@ -112,11 +112,11 @@ struct FemtoV0Qa { k0shortHistManager; // setup for daughters - trackhistmanager::ConfV0PosDauBinning confV0PosDaughterBinning; - trackhistmanager::ConfV0PosDauQaBinning confV0PosDaughterQaBinning; + trackhistmanager::ConfV01PosDauBinning confV0PosDaughterBinning; + trackhistmanager::ConfV01PosDauQaBinning confV0PosDaughterQaBinning; - trackhistmanager::ConfV0NegDauBinning confV0NegDaughterBinning; - trackhistmanager::ConfV0NegDauQaBinning confV0NegDaughterQaBinning; + trackhistmanager::ConfV01NegDauBinning confV0NegDaughterBinning; + trackhistmanager::ConfV01NegDauQaBinning confV0NegDaughterQaBinning; o2::framework::HistogramRegistry hRegistry{"FemtoV0Qa", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; diff --git a/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx b/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx index 1257291a825..3fe9e5071d1 100644 --- a/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx +++ b/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx @@ -73,10 +73,14 @@ struct FemtoPairLambdaAntilambda { colhistmanager::ConfCollisionBinning confCollisionBinning; // setup for daughters - trackhistmanager::ConfV0PosDauBinning confPosDauBinning; - trackhistmanager::ConfV0NegDauBinning confNegDauBinning; + trackhistmanager::ConfV01PosDauBinning confV01PosDauBinning; + trackhistmanager::ConfV01NegDauBinning confV01NegDauBinning; + trackhistmanager::ConfV02PosDauBinning confV02PosDauBinning; + trackhistmanager::ConfV02NegDauBinning confV02NegDauBinning; // setup lambdas + // selection 1 and 2 are sign-separated (lambda / antilambda), so confMixing.sameSpecies + // has to be set to false when running lambda-antilambda v0builder::ConfLambdaSelection1 confLambdaSelection; v0builder::ConfLambdaSelection2 confLambdaSelection2; particlecleaner::ConfLambdaCleaner1 confLambdaCleaner; @@ -156,33 +160,27 @@ struct FemtoPairLambdaAntilambda { void init(o2::framework::InitContext&) { - // TODO: implement lambda-k0short - bool processData = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaSameEvent || doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortSameEvent; - bool processMc = doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaSameEventMc || doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortSameEventMc; - - if (processData && processMc) { - LOG(fatal) << "Both data and mc processing is enabled. Breaking..."; - } + bool processData = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || + doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent; - bool processLambdaLambda = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaMixedEventMc; - bool processK0shortK0short = doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent || doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortMixedEventMc; - - if (processLambdaLambda && processK0shortK0short) { - LOG(fatal) << "Both lambda-lambda and k0short-k0short processing is enabled. Breaking..."; - } + bool processLambdaLambda = doprocessLambdaLambdaSameEvent || doprocessLambdaLambdaMixedEvent || + doprocessLambdaLambdaSameEventMc || doprocessLambdaLambdaMixedEventMc; + bool processK0shortK0short = doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent || + doprocessK0shortK0shortSameEventMc || doprocessK0shortK0shortMixedEventMc; // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; // setup histograms std::map> colHistSpec; - std::map> trackHistSpec; - std::map> posDauSpec; - std::map> negDauSpec; + std::map> posDauSpec1; + std::map> negDauSpec1; + std::map> posDauSpec2; + std::map> negDauSpec2; std::map> lambdaHistSpec; std::map> k0shortHistSpec; std::map> pairV0V0HistSpec; @@ -191,62 +189,64 @@ struct FemtoPairLambdaAntilambda { if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); - posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); - negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); + posDauSpec1 = trackhistmanager::makeTrackHistSpecMap(confV01PosDauBinning); + negDauSpec1 = trackhistmanager::makeTrackHistSpecMap(confV01NegDauBinning); + posDauSpec2 = trackhistmanager::makeTrackHistSpecMap(confV02PosDauBinning); + negDauSpec2 = trackhistmanager::makeTrackHistSpecMap(confV02NegDauBinning); + pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); + if (processLambdaLambda) { lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); - pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection2, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection2, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } - // setup for k0short - if (doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent) { + if (processK0shortK0short) { k0shortHistSpec = v0histmanager::makeV0HistSpecMap(confK0shortBinning); - pairV0V0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); - posDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confPosDauBinning); - negDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confNegDauBinning); + posDauSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confV01PosDauBinning); + negDauSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confV01NegDauBinning); + posDauSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confV02PosDauBinning); + negDauSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confV02NegDauBinning); + pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); + if (processLambdaLambda) { lambdaHistSpec = v0histmanager::makeV0McHistSpecMap(confLambdaBinning); - pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection2, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection2, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } - // setup for k0short - if (doprocessK0shortK0shortSameEvent || doprocessK0shortK0shortMixedEvent) { + if (processK0shortK0short) { k0shortHistSpec = v0histmanager::makeV0McHistSpecMap(confK0shortBinning); - pairV0V0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); } } - }; + } void processLambdaLambdaSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoLambdas const& lambdas) { pairLambdaLambdaBuilder.processSameEvent(col, tracks, lambdas, lambdaPartition, lambdaPartition2, cache); } - PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaSameEvent, "Enable processing same event processing for lambda-lambda", true); + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaSameEvent, "Enable processing same event processing for lambda-antilambda", true); void processLambdaLambdaSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& lambdas, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { pairLambdaLambdaBuilder.processSameEvent(col, mcCols, tracks, lambdas, lambdaWithLabelPartition, lambdaWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache); } - PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaSameEventMc, "Enable processing same event processing for lambda-lambda with mc information", false); + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaSameEventMc, "Enable processing same event processing for lambda-antilambda with mc information", false); - void processLambdaLambdaMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoLambdas const& lambdas) + void processLambdaLambdaMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoLambdas const& /*lambdas*/) { - pairLambdaLambdaBuilder.processMixedEvent(cols, tracks, lambdas, lambdaPartition, lambdaPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairLambdaLambdaBuilder.processMixedEvent(cols, tracks, lambdaPartition, lambdaPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } - PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaMixedEvent, "Enable processing mixed event processing for lambda-lambda", true); + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaMixedEvent, "Enable processing mixed event processing for lambda-antilambda", true); void processLambdaLambdaMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLambdasWithLabel const& /*lambdas*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { pairLambdaLambdaBuilder.processMixedEvent(cols, mcCols, tracks, lambdaWithLabelPartition, lambdaWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } - PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaMixedEventMc, "Enable processing mixed event processing for lambda-lambda with mc information", false); + PROCESS_SWITCH(FemtoPairLambdaAntilambda, processLambdaLambdaMixedEventMc, "Enable processing mixed event processing for lambda-antilambda with mc information", false); void processK0shortK0shortSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoK0shorts const& k0shorts) { @@ -260,15 +260,15 @@ struct FemtoPairLambdaAntilambda { } PROCESS_SWITCH(FemtoPairLambdaAntilambda, processK0shortK0shortSameEventMc, "Enable processing same event processing for k0short-k0short with mc information", false); - void processK0shortK0shortMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoK0shorts const& k0shorts) + void processK0shortK0shortMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoK0shorts const& /*k0shorts*/) { - pairK0shortK0shortBuilder.processMixedEvent(cols, tracks, k0shorts, k0shortPartition, k0shortPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairK0shortK0shortBuilder.processMixedEvent(cols, tracks, k0shortPartition, k0shortPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairLambdaAntilambda, processK0shortK0shortMixedEvent, "Enable processing mixed event processing for k0short-k0short", false); void processK0shortK0shortMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoK0shortsWithLabel const& /*k0shorts*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairK0shortK0shortBuilder.processMixedEvent(cols, mcCols, tracks, k0shortWithLabelPartition, k0shortWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairK0shortK0shortBuilder.processMixedEvent(cols, mcCols, tracks, k0shortWithLabelPartition, k0shortWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairLambdaAntilambda, processK0shortK0shortMixedEventMc, "Enable processing mixed event processing for k0short-k0short with mc information", false); }; From 6c5b8e6895168cefc2362f8dd1c92de287d9b23e Mon Sep 17 00:00:00 2001 From: Jinhyun Park <125851562+jinhyunni@users.noreply.github.com> Date: Thu, 30 Jul 2026 19:07:10 +0900 Subject: [PATCH 45/71] [PWGHF] Xic0, Updated output table columns produced by treeCreatorToXiPiQa.cxx (#17242) Co-authored-by: Jinhyun Park Co-authored-by: ALICE Action Bot --- PWGHF/TableProducer/treeCreatorToXiPiQa.cxx | 74 +++++++++++++-------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/PWGHF/TableProducer/treeCreatorToXiPiQa.cxx b/PWGHF/TableProducer/treeCreatorToXiPiQa.cxx index a4c8f7e16db..ea8b6fbebb0 100644 --- a/PWGHF/TableProducer/treeCreatorToXiPiQa.cxx +++ b/PWGHF/TableProducer/treeCreatorToXiPiQa.cxx @@ -22,6 +22,7 @@ #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGLF/DataModel/mcCentrality.h" +#include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" @@ -224,7 +225,9 @@ DECLARE_SOA_COLUMN(ParticlePdg, particlePdg, int); DECLARE_SOA_COLUMN(PtGenB, ptGenB, float); DECLARE_SOA_COLUMN(NContribMax, nContribMax, int); DECLARE_SOA_COLUMN(NRecoColl, nRecoColl, int); -DECLARE_SOA_COLUMN(IsXic0WithRecoCollSel8, isXic0WithRecoCollSel8, bool); +DECLARE_SOA_COLUMN(HasRecoCollTVX, hasRecoCollTVX, bool); +DECLARE_SOA_COLUMN(HasRecoCollSel8, hasRecoCollSel8, bool); +DECLARE_SOA_COLUMN(HasRecoCollSel8Zvtx, hasRecoCollSel8Zvtx, bool); } // namespace full DECLARE_SOA_TABLE(HfToXiPiEvs, "AOD", "HFTOXIPIEV", @@ -328,7 +331,9 @@ DECLARE_SOA_TABLE(HfCandToXiPiGen, "AOD", "HFCANDTOXIPIGEN", full::PtGenB, full::NContribMax, full::NRecoColl, - full::IsXic0WithRecoCollSel8); + full::HasRecoCollTVX, + full::HasRecoCollSel8, + full::HasRecoCollSel8Zvtx); } // namespace o2::aod @@ -380,9 +385,9 @@ struct HfTreeCreatorToXiPiQa { ////////////////////////////////////////////////////// template - void fillEvent(const T& collision, float cutZPv) + void fillEvent(const T& collision) { - rowEv(collision.sel8(), std::abs(collision.posZ()) < cutZPv); + rowEv(collision.sel8(), std::abs(collision.posZ()) < zPvCut); } template @@ -660,18 +665,29 @@ struct HfTreeCreatorToXiPiQa { void fillParticle(const CandType& mcParticles, const CollType& collisions) { for (const auto& particle : mcParticles) { - // Mc.Gen + auto ptGen = particle.pt(); auto yGen = particle.rapidityCharmBaryonGen(); int nContribMax = 0; + bool recoCollPassedTvx = false; bool recoCollPassedSel8 = false; + bool recoCollPassedSel8Zvtx = false; + auto mcCollision = particle.template mcCollision_as(); const auto& recoCollsPerMcColl = collisions.sliceBy(colPerMcCollision, mcCollision.globalIndex()); + for (const auto& recoCol : recoCollsPerMcColl) { nContribMax = recoCol.numContrib() > nContribMax ? recoCol.numContrib() : nContribMax; - if (recoCol.sel8()) { - recoCollPassedSel8 = true; + if (recoCol.selection_bit(aod::evsel::kIsTriggerTVX)) { + recoCollPassedTvx = true; + if (recoCol.sel8()) { + recoCollPassedSel8 = true; + if (std::abs(recoCol.posZ()) < zPvCut) { + recoCollPassedSel8Zvtx = true; + break; + } + } } } @@ -688,7 +704,9 @@ struct HfTreeCreatorToXiPiQa { ptGenBhad, nContribMax, recoCollsPerMcColl.size(), - recoCollPassedSel8); + recoCollPassedTvx, + recoCollPassedSel8, + recoCollPassedSel8Zvtx); } } @@ -709,7 +727,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -726,7 +744,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -743,7 +761,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -760,7 +778,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -777,7 +795,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -803,7 +821,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -820,7 +838,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -837,7 +855,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -854,7 +872,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collisions.size()); for (const auto& collision : collisions) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -882,7 +900,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -907,7 +925,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -932,7 +950,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -957,7 +975,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -982,7 +1000,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -1007,7 +1025,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -1032,7 +1050,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -1068,7 +1086,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -1093,7 +1111,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -1118,7 +1136,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate properties @@ -1143,7 +1161,7 @@ struct HfTreeCreatorToXiPiQa { // Filling event properties rowEv.reserve(collsWithMcLable.size()); for (const auto& collision : collsWithMcLable) { - fillEvent(collision, zPvCut); + fillEvent(collision); } // Filling candidate table From aa64e136560c49cf8d1002c0bd8c2e9e52a57d9a Mon Sep 17 00:00:00 2001 From: Shunsuke-Kurita <135583712+Shunsuke-Kurita@users.noreply.github.com> Date: Thu, 30 Jul 2026 21:13:02 +0900 Subject: [PATCH 46/71] [PWGDQ] Add post-prefilter single-track QA task and fill electron-leg DCA for electron-muon pairs (#17254) Co-authored-by: Claude Fable 5 --- PWGDQ/Core/VarManager.h | 5 + PWGDQ/Tasks/dqEfficiency_withAssoc.cxx | 218 +++++++++++++++++++++++++ 2 files changed, 223 insertions(+) diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index 71c6c7a299e..e996fcdcf42 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -3929,6 +3929,11 @@ void VarManager::FillPair(T1 const& t1, T2 const& t2, float* values) values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2.); } } + if constexpr ((pairType == kElectronMuon) && ((fillMap & ReducedTrackBarrel) > 0)) { + // DCA of the barrel (electron) leg; not filled in FillPairME since the mixed-event barrel track type has no DCA columns + values[kDCAxy1] = t1.dcaXY(); + values[kDCAz1] = t1.dcaZ(); + } if (fgUsedVars[kPairPhiv]) { values[kPairPhiv] = calculatePhiV(t1, t2); } diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx index 42c42441774..fea3f19016f 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx @@ -1350,6 +1350,223 @@ struct AnalysisPrefilterSelection { PROCESS_SWITCH(AnalysisPrefilterSelection, processDummy, "Do nothing", true); }; +// Single-track selection on the barrel tracks after the prefilter decisions (which are not visible in the +// AnalysisTrackSelection histograms): fills track-level histograms separately for surviving and vetoed tracks, +// per track cut and per MC signal. +// NOTE: Histograms are filled per association, regardless of whether the association is the correct one. +struct AnalysisPostPrefilterTrackSelection { + OutputObj fOutputList{"output"}; + + Configurable fConfigTrackCuts{"cfgTrackCuts", "", "Comma separated list of track cuts (among those of analysis-track-selection) for which to fill histograms"}; + Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + Configurable fConfigMCSignals{"cfgTrackMCSignals", "", "Comma separated list of MC signals"}; + Configurable fConfigMCSignalsJSON{"cfgTrackMCsignalsJSON", "", "Additional list of MC signals via JSON"}; + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + + Service fCCDB{}; + + HistogramManager* fHistMan = nullptr; + std::vector fMCSignals; + std::vector fCutBits; // bit positions of the requested cuts in the track-selection task cut list + std::vector fHistNamesSurvived; // [icut] + std::vector fHistNamesVetoed; // [icut] + std::vector fHistNamesMCSurvived; // [icut * nSignals + isig] + std::vector fHistNamesMCVetoed; // [icut * nSignals + isig] + + int fCurrentRun = 0; // current run (needed to detect run changes for loading CCDB parameters) + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + VarManager::SetDefaultVarNames(); + + fCurrentRun = 0; + TString trackCutsStr = fConfigTrackCuts.value; + std::unique_ptr objArrayCuts(trackCutsStr.Tokenize(",")); + if (objArrayCuts == nullptr || objArrayCuts->GetEntries() == 0) { + LOG(fatal) << " No track cuts specified! Check the cfgTrackCuts configurable"; + } + // get the full list of cuts computed by the track-selection task and resolve the requested cuts to bit positions + std::string trackCuts; + getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", trackCuts, false); + TString allTrackCutsStr = trackCuts; + // check also the cuts added via JSON and add them to the string of cuts + getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", trackCuts, false); + TString addTrackCutsStr = trackCuts; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto const& t : addTrackCuts) { + allTrackCutsStr += Form(",%s", t->GetName()); + } + } + std::unique_ptr objArrayAllCuts(allTrackCutsStr.Tokenize(",")); + if (objArrayAllCuts == nullptr) { + LOG(fatal) << " Not getting any track cuts from the barrel-track-selection "; + } + std::vector cutNames; + for (int icut = 0; icut < objArrayCuts->GetEntries(); ++icut) { + TString cutName = objArrayCuts->At(icut)->GetName(); + if (objArrayAllCuts->FindObject(cutName.Data()) == nullptr) { + LOG(fatal) << " Track cut " << cutName << " not among the cuts calculated by the track-selection task! "; + } + for (int jcut = 0; jcut < objArrayAllCuts->GetEntries(); ++jcut) { + if (cutName.CompareTo(objArrayAllCuts->At(jcut)->GetName()) == 0) { + fCutBits.push_back(jcut); + } + } + cutNames.push_back(cutName); + } + + // Setting the MC signals + TString configSigNamesStr = fConfigMCSignals.value; + std::unique_ptr sigNamesArray(configSigNamesStr.Tokenize(",")); + for (int isig = 0; isig < sigNamesArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(sigNamesArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() != 1) { // NOTE: only 1 prong signals + continue; + } + fMCSignals.push_back(sig); + } + } + // Add the MCSignals from the JSON config + TString addMCSignalsStr = fConfigMCSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto const& mcIt : addMCSignals) { + if (mcIt->GetNProngs() != 1) { // NOTE: only 1 prong signals + continue; + } + fMCSignals.push_back(mcIt); + } + } + + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(dqefficiency_helpers::varNames(), dqefficiency_helpers::varUnits()); + + // Configure histogram classes for each track cut, separately for prefilter-surviving and prefilter-vetoed tracks, + // and for each requested MC signal (reconstructed tracks with MC truth) + TString histClasses = ""; + for (auto const& cutName : cutNames) { + TString nameStr = Form("TrackBarrelPostPrefilter_%s", cutName.Data()); + fHistNamesSurvived.push_back(nameStr); + histClasses += Form("%s;", nameStr.Data()); + nameStr = Form("TrackBarrelPrefilterVetoed_%s", cutName.Data()); + fHistNamesVetoed.push_back(nameStr); + histClasses += Form("%s;", nameStr.Data()); + for (auto const& sig : fMCSignals) { + TString nameStr2 = Form("TrackBarrelPostPrefilter_%s_%s", cutName.Data(), sig->GetName()); + fHistNamesMCSurvived.push_back(nameStr2); + histClasses += Form("%s;", nameStr2.Data()); + nameStr2 = Form("TrackBarrelPrefilterVetoed_%s_%s", cutName.Data(), sig->GetName()); + fHistNamesMCVetoed.push_back(nameStr2); + histClasses += Form("%s;", nameStr2.Data()); + } + } + + DefineHistograms(fHistMan, histClasses.Data(), fConfigAddTrackHistogram.value.data()); + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + } + + template + void runPostPrefilterTrackSelection(soa::Join const& assocs, + TEvents const& events, TTracks const& /*tracks*/, TTracksMC const& tracksMC) + { + // load the magnetic field (needed to recompute the DCA with respect to the associated collision) + if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { + auto grpmag = fCCDB->getForTimeStamp(grpmagPath, events.begin().timestamp()); + if (grpmag != nullptr) { + VarManager::SetMagneticField(grpmag->getNominalL3Field()); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); + } + fCurrentRun = events.begin().runNumber(); + } + + // Loop over associations + for (auto const& assoc : assocs) { + auto event = assoc.template reducedevent_as(); + if (!event.isEventSelected_bit(0)) { + continue; + } + + // check which of the requested cuts are fulfilled by this association and which of those are prefilter-vetoed + uint32_t selectedMap = 0; + uint32_t vetoMap = 0; + for (std::size_t icut = 0; icut < fCutBits.size(); ++icut) { + if (assoc.isBarrelSelected_bit(fCutBits[icut])) { + selectedMap |= (static_cast(1) << icut); + if (!assoc.isBarrelSelectedPrefilter_bit(fCutBits[icut])) { + vetoMap |= (static_cast(1) << icut); + } + } + } + if (selectedMap == 0) { + continue; + } + + VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); + // fill event information which might be needed in histograms that combine track and event properties + VarManager::FillEvent(event); + if (event.has_reducedMCevent()) { + VarManager::FillEvent(event.reducedMCevent()); + } + + auto track = assoc.template reducedtrack_as(); + VarManager::FillTrack(track); + // compute quantities which depend on the associated collision, such as DCA + VarManager::FillTrackCollision(track, event); + if (track.has_reducedMCTrack()) { + VarManager::FillTrackMC(tracksMC, track.reducedMCTrack()); + } + + for (std::size_t icut = 0; icut < fCutBits.size(); ++icut) { + if (!(selectedMap & (static_cast(1) << icut))) { + continue; + } + bool isVetoed = (vetoMap & (static_cast(1) << icut)) > 0; + fHistMan->FillHistClass((isVetoed ? fHistNamesVetoed[icut] : fHistNamesSurvived[icut]).Data(), dqefficiency_helpers::varValues()); + if (track.has_reducedMCTrack()) { + int isig = 0; + for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { + if ((*sig)->CheckSignal(true, track.reducedMCTrack())) { + fHistMan->FillHistClass((isVetoed ? fHistNamesMCVetoed : fHistNamesMCSurvived)[icut * fMCSignals.size() + isig].Data(), dqefficiency_helpers::varValues()); + } + } + } + } // end loop over cuts + } // end loop over associations + } + + void processSkimmed(soa::Join const& assocs, MyEventsSelected const& events, MyBarrelTracks const& tracks, ReducedMCEvents const& /*eventsMC*/, ReducedMCTracks const& tracksMC) + { + runPostPrefilterTrackSelection(assocs, events, tracks, tracksMC); + } + void processSkimmedWithCov(soa::Join const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCov const& tracks, ReducedMCEvents const& /*eventsMC*/, ReducedMCTracks const& tracksMC) + { + runPostPrefilterTrackSelection(assocs, events, tracks, tracksMC); + } + void processDummy(MyEvents const&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisPostPrefilterTrackSelection, processSkimmed, "Run barrel track post-prefilter selection on DQ skimmed track associations", false); + PROCESS_SWITCH(AnalysisPostPrefilterTrackSelection, processSkimmedWithCov, "Run barrel track post-prefilter selection on DQ skimmed track associations w/ cov matrix", false); + PROCESS_SWITCH(AnalysisPostPrefilterTrackSelection, processDummy, "Dummy function", true); +}; + // Run the same-event pairing // This task assumes that both legs of the resonance fulfill the same cuts (symmetric decay channel) // Runs combinatorics for barrel-barrel, muon-muon and barrel-muon combinations @@ -5183,6 +5400,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc), adaptAnalysisTask(cfgc)}; From 4a8230155b2496c36e319969e05ba7630677b22c Mon Sep 17 00:00:00 2001 From: Maxim Virta <84773378+MaximVirta@users.noreply.github.com> Date: Thu, 30 Jul 2026 14:50:10 +0200 Subject: [PATCH 47/71] [PWGCF] Added multiplicity study & pt correlations (#17261) Co-authored-by: Maxim Virta Co-authored-by: ALICE Action Bot --- PWGCF/GenericFramework/Tasks/flowGfwV02.cxx | 112 ++++++++++++++++++-- 1 file changed, 103 insertions(+), 9 deletions(-) diff --git a/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx b/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx index 505f486f2ad..c382cc6748c 100644 --- a/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx +++ b/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx @@ -92,7 +92,7 @@ float philow = 0.0; float phiup = o2::constants::math::TwoPI; int nchbins = 300; float nchlow = 0; -float nchup = 3000; +float nchup = 300; std::vector centbinning(90); int nBootstrap = 10; std::vector> etagapsPtPt; @@ -104,6 +104,7 @@ std::vector multGlobalPVCorrCutPars; } // namespace o2::analysis::gfw struct FlowGfwV02 { + O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples") O2_DEFINE_CONFIGURABLE(cfgMpar, int, 4, "Highest order of pt-pt correlations") O2_DEFINE_CONFIGURABLE(cfgCentEstimator, int, 0, "0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FT0A") @@ -124,6 +125,7 @@ struct FlowGfwV02 { O2_DEFINE_CONFIGURABLE(cfgNormalizeByCharged, bool, true, "Enable or disable the normalization by charged particles"); O2_DEFINE_CONFIGURABLE(cfgConsistentEventFlag, int, 15, "Flag for consistent event selection"); O2_DEFINE_CONFIGURABLE(cfgMultCut, bool, true, "Use additional event cut on mult correlations"); + O2_DEFINE_CONFIGURABLE(cfgUseV0, bool, false, "Use V0 analysis"); // Event selection cuts struct : ConfigurableGroup { @@ -139,6 +141,16 @@ struct FlowGfwV02 { O2_DEFINE_CONFIGURABLE(cfgIsVertexITSTPC, bool, true, "kIsVertexITSTPC - Selects collisions with at least one ITS-TPC track"); } cfgEventCutFlags; + // Event selection cuts + struct : ConfigurableGroup { + O2_DEFINE_CONFIGURABLE(cfgEtaSubAMin, float, -0.8, "Minimum eta for subevent A"); + O2_DEFINE_CONFIGURABLE(cfgEtaSubAMax, float, -0.5, "Maximum eta for subevent A"); + O2_DEFINE_CONFIGURABLE(cfgEtaSubBMin, float, 0.5, "Minimum eta for subevent B"); + O2_DEFINE_CONFIGURABLE(cfgEtaSubBMax, float, 0.8, "Maximum eta for subevent B"); + O2_DEFINE_CONFIGURABLE(cfgEtaSubCMin, float, -0.4, "Minimum eta for subevent C"); + O2_DEFINE_CONFIGURABLE(cfgEtaSubCMax, float, 0.4, "Maximum eta for subevent C"); + } cfgSubeventCuts; + struct : ConfigurableGroup { Configurable> cfgMultGlobalCutPars{"cfgMultGlobalCutPars", std::vector{2272.16, -76.6932, 1.01204, -0.00631545, 1.59868e-05, 136.336, -4.97006, 0.121199, -0.0015921, 7.66197e-06}, "Global vs FT0C multiplicity cut parameter values"}; Configurable> cfgMultPVCutPars{"cfgMultPVCutPars", std::vector{3074.43, -106.192, 1.46176, -0.00968364, 2.61923e-05, 182.128, -7.43492, 0.193901, -0.00256715, 1.22594e-05}, "PV vs FT0C multiplicity cut parameter values"}; @@ -253,6 +265,8 @@ struct FlowGfwV02 { std::array itsNsigmaCut; std::array tpcNsigmaCut; std::array, 4> hPtMid{}; + std::array, 4> hPtForward{}; + std::array, 4> hPtBackward{}; }; PIDState pidStates; @@ -275,7 +289,8 @@ struct FlowGfwV02 { PidCharged = 0, PidPions, PidKaons, - PidProtons + PidProtons, + PidTotal }; enum PiKpArrayIndex { IndPionUp = 0, @@ -378,6 +393,24 @@ struct FlowGfwV02 { pidStates.hPtMid[PidKaons]->SetDirectory(nullptr); pidStates.hPtMid[PidProtons]->SetDirectory(nullptr); + pidStates.hPtForward[PidCharged] = std::make_unique("hPtForward_charged", "hPtForward_charged", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); + pidStates.hPtForward[PidPions] = std::make_unique("hPtForward_pions", "hPtForward_pions", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); + pidStates.hPtForward[PidKaons] = std::make_unique("hPtForward_kaons", "hPtForward_kaons", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); + pidStates.hPtForward[PidProtons] = std::make_unique("hPtForward_protons", "hPtForward_protons", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); + pidStates.hPtForward[PidCharged]->SetDirectory(nullptr); + pidStates.hPtForward[PidPions]->SetDirectory(nullptr); + pidStates.hPtForward[PidKaons]->SetDirectory(nullptr); + pidStates.hPtForward[PidProtons]->SetDirectory(nullptr); + + pidStates.hPtBackward[PidCharged] = std::make_unique("hPtBackward_charged", "hPtBackward_charged", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); + pidStates.hPtBackward[PidPions] = std::make_unique("hPtBackward_pions", "hPtBackward_pions", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); + pidStates.hPtBackward[PidKaons] = std::make_unique("hPtBackward_kaons", "hPtBackward_kaons", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); + pidStates.hPtBackward[PidProtons] = std::make_unique("hPtBackward_protons", "hPtBackward_protons", o2::analysis::gfw::ptbinning.size() - 1, &o2::analysis::gfw::ptbinning[0]); + pidStates.hPtBackward[PidCharged]->SetDirectory(nullptr); + pidStates.hPtBackward[PidPions]->SetDirectory(nullptr); + pidStates.hPtBackward[PidKaons]->SetDirectory(nullptr); + pidStates.hPtBackward[PidProtons]->SetDirectory(nullptr); + AxisSpec phiAxis = {o2::analysis::gfw::phibins, o2::analysis::gfw::philow, o2::analysis::gfw::phiup, "#phi"}; AxisSpec etaAxis = {o2::analysis::gfw::etabins, -cfgTrackCuts.cfgEtaMax, cfgTrackCuts.cfgEtaMax, "#eta"}; AxisSpec vtxAxis = {o2::analysis::gfw::vtxZbins, -cfgEventCuts.cfgZvtxMax, cfgEventCuts.cfgZvtxMax, "Vtx_{z} (cm)"}; @@ -398,9 +431,19 @@ struct FlowGfwV02 { AxisSpec multpvAxis = {600, 0, 600, "N_{ch} (PV)"}; AxisSpec dcaZAxis = {200, -2, 2, "DCA_{z} (cm)"}; AxisSpec dcaXYAxis = {200, -0.5, 0.5, "DCA_{xy} (cm)"}; + AxisSpec pidAxis = {4, -0.5, 3.5, "PID"}; // 0 = not identified, 1 = pion, 2 = kaon, 3 = proton registry.add("v02pt", "", {HistType::kTProfile2D, {ptAxis, centAxis}}); - registry.add("nchMid", "", {HistType::kTProfile2D, {ptAxis, centAxis}}); + registry.add("nchMid", "", {HistType::kTProfile3D, {ptAxis, centAxis, nchAxis}}); + registry.add("v02centmult", "", {HistType::kTProfile2D, {centAxis, nchAxis}}); + + registry.add("analysis/v0AB", "", {HistType::kTProfile3D, {pidAxis, ptAxis, centAxis}}); + registry.add("analysis/v0BA", "", {HistType::kTProfile3D, {pidAxis, ptAxis, centAxis}}); + registry.add("analysis/nchA", "", {HistType::kTProfile3D, {pidAxis, ptAxis, centAxis}}); + registry.add("analysis/nchB", "", {HistType::kTProfile3D, {pidAxis, ptAxis, centAxis}}); + registry.add("analysis/ptA", "", {HistType::kTProfile3D, {pidAxis, centAxis, nchAxis}}); + registry.add("analysis/ptB", "", {HistType::kTProfile3D, {pidAxis, centAxis, nchAxis}}); + registry.add("analysis/ptAB", "", {HistType::kTProfile3D, {pidAxis, centAxis, nchAxis}}); ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); @@ -614,7 +657,7 @@ struct FlowGfwV02 { } if (cfgPIDEfficiency) { const std::array pidStrings = {"ch", "pi", "ka", "pr"}; - for (int i = 1; i < 4; i++) { + for (int i = 1; i < PidTotal; i++) { cfg.mEfficiency[i] = ccdb->getForTimeStamp(cfgEfficiency.value + pidStrings[i], timestamp); if (cfg.mEfficiency[i] == nullptr) { @@ -806,7 +849,7 @@ struct FlowGfwV02 { } template - void fillOutputContainers(const float& centmult, const double& rndm, const int& /*run*/ = 0) + void fillOutputContainers(const float& centmult, const int& multiplicity, const double& rndm, const int& /*run*/ = 0) { for (uint l_ind = 0; l_ind < corrconfigs.size(); ++l_ind) { if (!corrconfigs.at(l_ind).pTDif) { @@ -846,6 +889,32 @@ struct FlowGfwV02 { } } } + + if (cfgUseV0) { + double v0corrAB = 0; + double v0corrBA = 0; + double ptMeanForward = pidStates.hPtForward[PidCharged]->GetMean(); + double ptMeanBackward = pidStates.hPtBackward[PidCharged]->GetMean(); + double ptFractionForward = 0.; + double ptFractionBackward = 0.; + for (int pid = 0; pid < PidTotal; pid++) { + int normIndex = (cfgNormalizeByCharged) ? PidCharged : pid; + for (int i = 1; i <= fSecondAxis->GetNbins(); i++) { + ptFractionForward = pidStates.hPtForward[pid]->GetBinContent(i) / pidStates.hPtForward[normIndex]->Integral(); + ptFractionBackward = pidStates.hPtBackward[pid]->GetBinContent(i) / pidStates.hPtBackward[normIndex]->Integral(); + v0corrAB = ptFractionForward * ptMeanBackward; + v0corrBA = ptFractionBackward * ptMeanForward; + registry.fill(HIST("analysis/v0AB"), pid, fSecondAxis->GetBinCenter(i), centmult, v0corrAB); + registry.fill(HIST("analysis/v0BA"), pid, fSecondAxis->GetBinCenter(i), centmult, v0corrBA); + registry.fill(HIST("analysis/nchA"), pid, fSecondAxis->GetBinCenter(i), centmult, ptFractionForward); + registry.fill(HIST("analysis/nchB"), pid, fSecondAxis->GetBinCenter(i), centmult, ptFractionBackward); + } + registry.fill(HIST("analysis/ptA"), pid, centmult, multiplicity, ptMeanForward); + registry.fill(HIST("analysis/ptB"), pid, centmult, multiplicity, ptMeanBackward); + registry.fill(HIST("analysis/ptAB"), pid, centmult, multiplicity, ptMeanForward * ptMeanBackward); + } + } + // Fill the profiles for each pT bin auto dnx = fGFW->Calculate(corrconfigs.at(0), 0, kTRUE).real(); if (dnx == 0) @@ -857,9 +926,10 @@ struct FlowGfwV02 { ptFraction = pidStates.hPtMid[PidCharged]->GetBinContent(i) / pidStates.hPtMid[PidCharged]->Integral(); if (std::abs(val) < 1) registry.fill(HIST("v02pt"), fSecondAxis->GetBinCenter(i), centmult, val * ptFraction, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0); - registry.fill(HIST("nchMid"), fSecondAxis->GetBinCenter(i), centmult, ptFraction); + registry.fill(HIST("nchMid"), fSecondAxis->GetBinCenter(i), centmult, multiplicity, ptFraction); } } + registry.fill(HIST("v02centmult"), centmult, multiplicity, val); return; } @@ -891,6 +961,14 @@ struct FlowGfwV02 { pidStates.hPtMid[PidPions]->Reset(); pidStates.hPtMid[PidKaons]->Reset(); pidStates.hPtMid[PidProtons]->Reset(); + pidStates.hPtBackward[PidCharged]->Reset(); + pidStates.hPtBackward[PidPions]->Reset(); + pidStates.hPtBackward[PidKaons]->Reset(); + pidStates.hPtBackward[PidProtons]->Reset(); + pidStates.hPtForward[PidCharged]->Reset(); + pidStates.hPtForward[PidPions]->Reset(); + pidStates.hPtForward[PidKaons]->Reset(); + pidStates.hPtForward[PidProtons]->Reset(); float lRandom = fRndm->Rndm(); @@ -898,16 +976,32 @@ struct FlowGfwV02 { AcceptedTracks acceptedTracks{0, 0, 0, 0}; for (const auto& track : tracks) { processTrack(track, vtxz, xaxis.multiplicity, run, acceptedTracks); - if (track.eta() > -0.4 && track.eta() < 0.4) + if (track.eta() > cfgSubeventCuts.cfgEtaSubCMin && track.eta() < cfgSubeventCuts.cfgEtaSubCMax) pidStates.hPtMid[PidCharged]->Fill(track.pt(), getEfficiency(track, PidCharged)); + if (track.eta() > cfgSubeventCuts.cfgEtaSubAMin && track.eta() < cfgSubeventCuts.cfgEtaSubAMax) // add mean pT + pidStates.hPtBackward[PidCharged]->Fill(track.pt(), getEfficiency(track, PidCharged)); + if (track.eta() > cfgSubeventCuts.cfgEtaSubBMin && track.eta() < cfgSubeventCuts.cfgEtaSubBMax) // add mean pT + pidStates.hPtForward[PidCharged]->Fill(track.pt(), getEfficiency(track, PidCharged)); // If PID is identified, fill pt spectrum for the corresponding particle int pidInd = getNsigmaPID(track); - if (pidInd != -1 && track.eta() > -0.4 && track.eta() < 0.4) { + if (pidInd != -1 && track.eta() > cfgSubeventCuts.cfgEtaSubCMin && track.eta() < cfgSubeventCuts.cfgEtaSubCMax) { if (cfgPIDEfficiency) pidStates.hPtMid[pidInd]->Fill(track.pt(), getEfficiency(track, pidInd)); else pidStates.hPtMid[pidInd]->Fill(track.pt(), getEfficiency(track, PidCharged)); // Default to charged particles if PID efficiency is not used } + if (pidInd != -1 && track.eta() > cfgSubeventCuts.cfgEtaSubAMin && track.eta() < cfgSubeventCuts.cfgEtaSubAMax) { + if (cfgPIDEfficiency) + pidStates.hPtBackward[pidInd]->Fill(track.pt(), getEfficiency(track, pidInd)); + else + pidStates.hPtBackward[pidInd]->Fill(track.pt(), getEfficiency(track, PidCharged)); // Default to charged particles if PID efficiency is not used + } + if (pidInd != -1 && track.eta() > cfgSubeventCuts.cfgEtaSubBMin && track.eta() < cfgSubeventCuts.cfgEtaSubBMax) { + if (cfgPIDEfficiency) + pidStates.hPtForward[pidInd]->Fill(track.pt(), getEfficiency(track, pidInd)); + else + pidStates.hPtForward[pidInd]->Fill(track.pt(), getEfficiency(track, PidCharged)); // Default to charged particles if PID efficiency is not used + } } if (cfgConsistentEventFlag & 1) if (!acceptedTracks.nPos || !acceptedTracks.nNeg) @@ -922,7 +1016,7 @@ struct FlowGfwV02 { if (acceptedTracks.nPos < 2 || acceptedTracks.nMid < 2 || acceptedTracks.nNeg < 2) // o2-linter: disable=magic-number (at least two tracks in all three subevents) return; // Fill output containers - fillOutputContainers
(xaxis.centrality, lRandom, run); + fillOutputContainers
(xaxis.centrality, xaxis.multiplicity, lRandom, run); } template From 320491378c826bdc8f4f89514b2272f614e66d07 Mon Sep 17 00:00:00 2001 From: Rocco Liotino Date: Thu, 30 Jul 2026 15:16:59 +0200 Subject: [PATCH 48/71] [DPG] HMPID: new method to select primaries (#17248) --- .../AOTTrack/PID/HMPID/hmpidTableProducer.cxx | 186 ++++++++++++------ 1 file changed, 130 insertions(+), 56 deletions(-) diff --git a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx index 06c8f92b139..1074a071b60 100644 --- a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx +++ b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidTableProducer.cxx @@ -34,6 +34,8 @@ #include #include +#include +#include #include @@ -73,6 +75,12 @@ struct HmpidTableProducer { Configurable requireTPC{"requireTPC", true, "Require TPC track"}; Configurable requireTOF{"requireTOF", true, "Require TOF track"}; + Configurable useInAbsorberGeomMethod{"useInAbsorberGeomMethod", false, "Use geometrical method to check if daughters are born in absorber"}; + + // (reference) 473 cm - was the legacy value in run2 simulation + Configurable survivalThresholdRich2{"survivalThresholdRich2", 437.5f, "survivalThresholdRich2"}; + Configurable survivalThresholdRich4{"survivalThresholdRich4", 439.0f, "survivalThresholdRich4"}; + using CollisionCandidates = o2::soa::Join; using TrackCandidates = soa::JoinGLOBAL transform is built as: - // pMatrix->SetTranslation(T); - // pMatrix->RotateZ(theta); - // which yields, for a local point p: p_glob = Rz(theta) * p_loc + T. - // In particular the box CENTER in global coordinates is exactly T (the - // rotation does not affect T, since it is applied to p_loc only, not to - // the already-set translation). Only the box AXES are rotated by theta - // with respect to the global x,y axes. - // - // To test whether a global point lies inside the box we invert the - // transform: p_loc = Rz(-theta) * (p_glob - T), then compare component-wise - // against the box half-widths. - // ----------------------------------------------------------------------- + // (reference) HMPID Detector class in O2 static constexpr double AbsThetaDeg = 33.5; - const double mAbsCosT = std::cos(AbsThetaDeg * TMath::DegToRad()); - const double mAbsSinT = std::sin(AbsThetaDeg * TMath::DegToRad()); + double mAbsCosT = 0., mAbsSinT = 0.; // Rich2 absorber: trans2 = {435.5, 0., -155.}, thickness 40mm -> halfX = 2cm static constexpr double AbsRich2CenterX = 435.5, AbsRich2CenterZ = -155.; @@ -132,6 +119,9 @@ struct HmpidTableProducer { void init(o2::framework::InitContext&) { + mAbsCosT = std::cos(AbsThetaDeg * TMath::DegToRad()); + mAbsSinT = std::sin(AbsThetaDeg * TMath::DegToRad()); + ccdb->setURL(ccdbConfig.ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -159,6 +149,10 @@ struct HmpidTableProducer { kTH1F, {{4, -0.5, 3.5, ""}}); histos.add("hProdVertex", ";X (cm);Y (cm);Z (cm)", HistType::kTH3F, {{500, -500., 500.}, {500, -500., 500.}, {500, -500., 500.}}); + histos.add("hDaughterRCyl_Rich2", "hDaughterRCyl_Rich2", kTH1F, {{600, 0., 600.}}); + histos.add("hDaughterRCyl_Rich4", "hDaughterRCyl_Rich4", kTH1F, {{600, 0., 600.}}); + histos.add("hDaughterRSph_Rich2", "hDaughterRSph_Rich2", kTH1F, {{600, 0., 600.}}); + histos.add("hDaughterRSph_Rich4", "hDaughterRSph_Rich4", kTH1F, {{600, 0., 600.}}); } // ----------------------------------------------------------------------- @@ -274,8 +268,9 @@ struct HmpidTableProducer { (x[1] - planePoint[1]) * planeNormal[1] + (x[2] - planePoint[2]) * planeNormal[2]; - if (std::abs(dist) >= std::abs(distPrev)) + if (std::abs(dist) >= std::abs(distPrev)) { return false; + } distPrev = dist; s -= dist; @@ -318,14 +313,16 @@ struct HmpidTableProducer { // Intersection track - radiator plane std::array xRad{}, pAtRad{}; - if (!intersectHelixPlane(bz, charge, x, p, pRad, nRad, xRad, pAtRad)) + if (!intersectHelixPlane(bz, charge, x, p, pRad, nRad, xRad, pAtRad)) { continue; + } // Intersection track - PC plane std::array xPc{}, pAtPc{}; - if (!intersectHelixPlane(bz, charge, xRad, pAtRad, pPc, nPc, xPc, pAtPc)) + if (!intersectHelixPlane(bz, charge, xRad, pAtRad, pPc, nPc, xPc, pAtPc)) { continue; + } double theta = 0., phi = 0.; param->mars2LorsVec(ch, pAtRad.data(), theta, phi); @@ -334,8 +331,9 @@ struct HmpidTableProducer { param->mars2Lors(ch, xPc.data(), xL, yL); // Use isInside to check Chamber intersected - if (param->isInside(xL, yL, param->distCut())) + if (param->isInside(xL, yL, param->distCut())) { return ch; + } } // No chamber intersected @@ -361,17 +359,32 @@ struct HmpidTableProducer { return false; } - // subtract the box center (translation is not rotated, see geometry block above) - const double rx = vx * mAbsCosT + vy * mAbsSinT; - const double ry = -vx * mAbsSinT + vy * mAbsCosT; - const double rz = vz; + // translate to box center + const double lx = vx - centerX; + const double ly = vy; // centerY = 0 + const double lz = vz - centerZ; // rotate by -theta into the box local frame - const double lx = rx - centerX; - const double ly = ry; // centerY = 0 - const double lz = rz - centerZ; + const double rx = lx * mAbsCosT + ly * mAbsSinT; + const double ry = -lx * mAbsSinT + ly * mAbsCosT; + const double rz = lz; + + return std::abs(rx) <= halfX && std::abs(ry) <= AbsHalfY && std::abs(rz) <= AbsHalfZ; + } + + bool survivedAbsorber(double vx, double vy, int chamber) + { + float thresholdR = 0.; + if (chamber == Rich2) { + thresholdR = survivalThresholdRich2; + } else if (chamber == Rich4) { + thresholdR = survivalThresholdRich4; + } else { + return false; + } - return std::abs(lx) <= halfX && std::abs(ly) <= AbsHalfY && std::abs(lz) <= AbsHalfZ; + const float r = std::hypot(vx, vy); + return r > thresholdR; } void processEvent(CollisionCandidates::iterator const& col, @@ -397,8 +410,9 @@ struct HmpidTableProducer { const auto& globalTrack = t.template track_as(); - if (!globalTrack.has_collision()) + if (!globalTrack.has_collision()) { continue; + } const auto& col = globalTrack.template collision_as(); initCCDB(col.template bc_as()); @@ -406,17 +420,20 @@ struct HmpidTableProducer { if ((requireITS && !globalTrack.hasITS()) || (requireTPC && !globalTrack.hasTPC()) || - (requireTOF && !globalTrack.hasTOF())) + (requireTOF && !globalTrack.hasTOF())) { continue; + } - if (mCollisionsWithHmpid.insert(collId).second) + if (mCollisionsWithHmpid.insert(collId).second) { histos.fill(HIST("eventsHmpid"), 0.5); + } // clusSize diagnostics histos.fill(HIST("hClusSize"), t.hmpidClusSize()); bool isCorrupt = (t.hmpidClusSize() <= 0); - if (isCorrupt) + if (isCorrupt) { histos.fill(HIST("hClusSizeCorrupt"), t.hmpidClusSize()); + } // --- M2: clusSize encoding --- int chamberM2 = t.hmpidClusSize() / 1000000; @@ -464,20 +481,22 @@ struct HmpidTableProducer { // bin 2 = clusSize <= 0, M1 recovery (corrupt, M1 ok) // bin 3 = clusSize <= 0, M1 fails (corrupt, skipped) - if (!isCorrupt && chamberM3 >= 0) + if (!isCorrupt && chamberM3 >= 0) { histos.fill(HIST("hChamberAssignment"), 0.); - else if (!isCorrupt && chamberM3 < 0) + } else if (!isCorrupt && chamberM3 < 0) { histos.fill(HIST("hChamberAssignment"), 1.); - else if (isCorrupt && chamberM3 >= 0) + } else if (isCorrupt && chamberM3 >= 0) { histos.fill(HIST("hChamberAssignment"), 2.); - else + } else { histos.fill(HIST("hChamberAssignment"), 3.); + } histos.fill(HIST("hChamberM3"), chamberM3); histos.fill(HIST("hChamberM3vsM2"), chamberM2, chamberM3); - if (chamberM3 < 0) + if (chamberM3 < 0) { continue; + } std::vector hmpidPhotsCharge2(o2::aod::kDimPhotonsCharge, 0.f); @@ -514,23 +533,78 @@ struct HmpidTableProducer { if ((chamberM3 == Rich2 || chamberM3 == Rich4) && mc.has_daughters()) { auto dIds = mc.daughtersIds(); - - for (int32_t idx = dIds.front(); idx <= dIds.back(); ++idx) { - auto daughter = mcParticles.rawIteratorAt(idx); - - histos.fill(HIST("hProdVertex"), daughter.vx(), daughter.vy(), daughter.vz()); - - if (isInAbsorber(daughter.vx(), daughter.vy(), daughter.vz(), chamberM3)) { - interactionInAbsorber = true; - break; - } - } // end loop daughters + bool foundRelevantDaughter = false; // true if at least one non-delta/photon daughter was examined + + if (useInAbsorberGeomMethod) { + for (int32_t idx = dIds.front(); idx <= dIds.back(); ++idx) { + auto daughter = mcParticles.rawIteratorAt(idx); + + int absPdg = std::abs(daughter.pdgCode()); + if (absPdg == kElectron || absPdg == kGamma) { + continue; + } + + foundRelevantDaughter = true; + + // diagnostics on daughters distribution + histos.fill(HIST("hProdVertex"), daughter.vx(), daughter.vy(), daughter.vz()); + + double rCyl = std::hypot(daughter.vx(), daughter.vy()); + double rSph = std::hypot(daughter.vx(), daughter.vy(), daughter.vz()); + if (chamberM3 == Rich2) { + histos.fill(HIST("hDaughterRCyl_Rich2"), rCyl); + histos.fill(HIST("hDaughterRSph_Rich2"), rSph); + } else { + histos.fill(HIST("hDaughterRCyl_Rich4"), rCyl); + histos.fill(HIST("hDaughterRSph_Rich4"), rSph); + } + + if (isInAbsorber(daughter.vx(), daughter.vy(), daughter.vz(), chamberM3)) { + interactionInAbsorber = true; + } + } // end loop daughters + } else { + bool survived = false; + for (int32_t idx = dIds.front(); idx <= dIds.back(); ++idx) { + auto daughter = mcParticles.rawIteratorAt(idx); + + // skip delta rays (e-/e+), photons, and HMPID Cherenkov/feedback + int absPdg = std::abs(daughter.pdgCode()); + if (absPdg == kElectron || absPdg == kGamma) { + continue; + } + + foundRelevantDaughter = true; + + histos.fill(HIST("hProdVertex"), daughter.vx(), daughter.vy(), daughter.vz()); + + double rCyl = std::hypot(daughter.vx(), daughter.vy()); + double rSph = std::hypot(daughter.vx(), daughter.vy(), daughter.vz()); + if (chamberM3 == Rich2) { + histos.fill(HIST("hDaughterRCyl_Rich2"), rCyl); + histos.fill(HIST("hDaughterRSph_Rich2"), rSph); + } else { + histos.fill(HIST("hDaughterRCyl_Rich4"), rCyl); + histos.fill(HIST("hDaughterRSph_Rich4"), rSph); + } + + if (survivedAbsorber(daughter.vx(), daughter.vy(), chamberM3)) { + survived = true; + } + } // end loop daughters + + // No relevant daughter found (only delta rays/photons, or no + // daughters at all): no evidence of a genuine interaction -> treat + // as primary/survived, consistent with the "no daughters" case. + interactionInAbsorber = foundRelevantDaughter ? !survived : false; + } } // end if has_daughters hmpidAnalysisMC(mc.pdgCode(), mc.vx(), mc.vy(), mc.vz(), mc.isPhysicalPrimary(), mc.getProcess(), interactionInAbsorber); } else { - hmpidAnalysisMC(-1, 0.f, 0.f, 0.f, false, -100, false); + // No MC truth associated to this track + hmpidAnalysisMC(-999, -999.f, -999.f, -999.f, false, -100, false); } } // end if constexpr (isMC) From 32257cb4c5636c60643c588a9a719f113071f1ce Mon Sep 17 00:00:00 2001 From: Yiping Wang <142303052+ypwangg@users.noreply.github.com> Date: Thu, 30 Jul 2026 22:52:14 +0800 Subject: [PATCH 49/71] [PWGDQ] add some fgVarNamesMap related to A2 analysis (#17127) --- PWGDQ/Core/VarManager.cxx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/PWGDQ/Core/VarManager.cxx b/PWGDQ/Core/VarManager.cxx index a92a0ce6f40..0b320fa1ab2 100644 --- a/PWGDQ/Core/VarManager.cxx +++ b/PWGDQ/Core/VarManager.cxx @@ -2560,6 +2560,7 @@ void VarManager::SetDefaultVarNames() fgVarNamesMap["kDCATrackVtxProd"] = kDCATrackVtxProd; fgVarNamesMap["kV2SP"] = kV2SP; fgVarNamesMap["kV2EP"] = kV2EP; + fgVarNamesMap["kV2EP_FT0C"] = kV2EP_FT0C; fgVarNamesMap["kA2EP_TPC"] = kA2EP_TPC; fgVarNamesMap["kA2EP_FT0A"] = kA2EP_FT0A; fgVarNamesMap["kA2EP_FT0C"] = kA2EP_FT0C; @@ -2648,6 +2649,18 @@ void VarManager::SetDefaultVarNames() fgVarNamesMap["kCos2DeltaPhiMu1"] = kCos2DeltaPhiMu1; fgVarNamesMap["kCos2DeltaPhiMu2"] = kCos2DeltaPhiMu2; fgVarNamesMap["kCos3DeltaPhi"] = kCos3DeltaPhi; + fgVarNamesMap["kDeltaPhi_TPC"] = kDeltaPhi_TPC; + fgVarNamesMap["kDeltaPhi_FT0A"] = kDeltaPhi_FT0A; + fgVarNamesMap["kDeltaPhi_FT0C"] = kDeltaPhi_FT0C; + fgVarNamesMap["kCos2DeltaPhi_TPC"] = kCos2DeltaPhi_TPC; + fgVarNamesMap["kCos2DeltaPhi_FT0A"] = kCos2DeltaPhi_FT0A; + fgVarNamesMap["kCos2DeltaPhi_FT0C"] = kCos2DeltaPhi_FT0C; + fgVarNamesMap["kDeltaPhiME_TPC"] = kDeltaPhiME_TPC; + fgVarNamesMap["kDeltaPhiME_FT0A"] = kDeltaPhiME_FT0A; + fgVarNamesMap["kDeltaPhiME_FT0C"] = kDeltaPhiME_FT0C; + fgVarNamesMap["kCos2DeltaPhiME_TPC"] = kCos2DeltaPhiME_TPC; + fgVarNamesMap["kCos2DeltaPhiME_FT0A"] = kCos2DeltaPhiME_FT0A; + fgVarNamesMap["kCos2DeltaPhiME_FT0C"] = kCos2DeltaPhiME_FT0C; fgVarNamesMap["kDeltaPtotTracks"] = kDeltaPtotTracks; fgVarNamesMap["kVertexingLxyOverErr"] = kVertexingLxyOverErr; fgVarNamesMap["kVertexingLzOverErr"] = kVertexingLzOverErr; From 287abed93ad7c602a3f58ac014a37b31edbdc1a2 Mon Sep 17 00:00:00 2001 From: Jaehyeok Ryu <57662730+JaehyeokRyu@users.noreply.github.com> Date: Fri, 31 Jul 2026 01:19:00 +0900 Subject: [PATCH 50/71] [PWGJE] Add UPC jet QA task (#17161) Co-authored-by: jryu --- PWGJE/Tasks/CMakeLists.txt | 4 + PWGJE/Tasks/jetUpcQa.cxx | 942 +++++++++++++++++++++++++++++++++++++ 2 files changed, 946 insertions(+) create mode 100644 PWGJE/Tasks/jetUpcQa.cxx diff --git a/PWGJE/Tasks/CMakeLists.txt b/PWGJE/Tasks/CMakeLists.txt index 3fa812e1308..6a3e2c8bd9a 100644 --- a/PWGJE/Tasks/CMakeLists.txt +++ b/PWGJE/Tasks/CMakeLists.txt @@ -444,4 +444,8 @@ if(FastJet_FOUND) SOURCES jetHadronsPid.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(jet-upc-qa + SOURCES jetUpcQa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils O2Physics::SGCutParHolder + COMPONENT_NAME Analysis) endif() diff --git a/PWGJE/Tasks/jetUpcQa.cxx b/PWGJE/Tasks/jetUpcQa.cxx new file mode 100644 index 00000000000..c15e97e4d69 --- /dev/null +++ b/PWGJE/Tasks/jetUpcQa.cxx @@ -0,0 +1,942 @@ +// 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 jetUpcQa.cxx +/// \brief Standalone QA task for UPC event tagging and charged-jet information. +/// \author Jaehyeok Ryu + +#include + +namespace o2::aod +{ + +// ============================================================ +// DATA tables +// ============================================================ +namespace upcjetevent +{ +DECLARE_SOA_COLUMN(GapSide, gapSide, int); +DECLARE_SOA_COLUMN(PosZ, posZ, float); +DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); +DECLARE_SOA_COLUMN(EnergyCommonZNA, energyCommonZNA, float); +DECLARE_SOA_COLUMN(EnergyCommonZNC, energyCommonZNC, float); +DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); +DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); +DECLARE_SOA_COLUMN(NeutronClass, neutronClass, int); +DECLARE_SOA_COLUMN(IsGapTagged, isGapTagged, bool); +DECLARE_SOA_COLUMN(IsZDCTagged, isZDCTagged, bool); +} // namespace upcjetevent + +DECLARE_SOA_TABLE(UpcJetEvents, "AOD", "UPCJETEVENT", + upcjetevent::GapSide, + upcjetevent::PosZ, + upcjetevent::CentFT0M, + upcjetevent::EnergyCommonZNA, + upcjetevent::EnergyCommonZNC, + upcjetevent::TimeZNA, + upcjetevent::TimeZNC, + upcjetevent::NeutronClass, + upcjetevent::IsGapTagged, + upcjetevent::IsZDCTagged); +using UpcJetEvent = UpcJetEvents::iterator; + +namespace upcjet +{ +DECLARE_SOA_INDEX_COLUMN(UpcJetEvent, upcJetEvent); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Area, area, float); +DECLARE_SOA_COLUMN(NConstituents, nConstituents, int); +} // namespace upcjet + +DECLARE_SOA_TABLE(UpcJets, "AOD", "UPCJET", + upcjet::UpcJetEventId, + upcjet::Pt, + upcjet::Eta, + upcjet::Phi, + upcjet::Area, + upcjet::NConstituents); +using UpcJet = UpcJets::iterator; + +namespace upctrack +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetEvent, upcJetEvent, int32_t, UpcJetEvents, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +} // namespace upctrack + +DECLARE_SOA_TABLE(UpcTracks, "AOD", "UPCTRACK", + upctrack::UpcJetEventId, + upctrack::Pt, + upctrack::Eta, + upctrack::Phi); +using UpcTrack = UpcTracks::iterator; + +namespace upcjettrack +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJet, upcJet, int32_t, UpcJets, ""); +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetEvent, upcJetEvent, int32_t, UpcJetEvents, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +} // namespace upcjettrack + +DECLARE_SOA_TABLE(UpcJetTracks, "AOD", "UPCJETTRACK", + upcjettrack::UpcJetId, + upcjettrack::UpcJetEventId, + upcjettrack::Pt, + upcjettrack::Eta, + upcjettrack::Phi); +using UpcJetTrack = UpcJetTracks::iterator; + +// ============================================================ +// MCD tables +// ============================================================ +namespace upcjeteventmcd +{ +DECLARE_SOA_COLUMN(GapSide, gapSide, int); +DECLARE_SOA_COLUMN(PosZ, posZ, float); +DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); +DECLARE_SOA_COLUMN(EnergyCommonZNA, energyCommonZNA, float); +DECLARE_SOA_COLUMN(EnergyCommonZNC, energyCommonZNC, float); +DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); +DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); +DECLARE_SOA_COLUMN(NeutronClass, neutronClass, int); +DECLARE_SOA_COLUMN(IsGapTagged, isGapTagged, bool); +DECLARE_SOA_COLUMN(IsZDCTagged, isZDCTagged, bool); +} // namespace upcjeteventmcd + +DECLARE_SOA_TABLE(UpcJetEventsMCD, "AOD", "UPCJETEVENTMCD", + upcjeteventmcd::GapSide, + upcjeteventmcd::PosZ, + upcjeteventmcd::CentFT0M, + upcjeteventmcd::EnergyCommonZNA, + upcjeteventmcd::EnergyCommonZNC, + upcjeteventmcd::TimeZNA, + upcjeteventmcd::TimeZNC, + upcjeteventmcd::NeutronClass, + upcjeteventmcd::IsGapTagged, + upcjeteventmcd::IsZDCTagged); +using UpcJetEventMCD = UpcJetEventsMCD::iterator; + +namespace upctrackmcd +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetEventMCD, upcJetEventMCD, int32_t, UpcJetEventsMCD, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +} // namespace upctrackmcd + +DECLARE_SOA_TABLE(UpcTracksMCD, "AOD", "UPCTRACKMCD", + upctrackmcd::UpcJetEventMCDId, + upctrackmcd::Pt, + upctrackmcd::Eta, + upctrackmcd::Phi); +using UpcTrackMCD = UpcTracksMCD::iterator; + +namespace upcjetmcd +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetEventMCD, upcJetEventMCD, int32_t, UpcJetEventsMCD, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Area, area, float); +DECLARE_SOA_COLUMN(NConstituents, nConstituents, int); +} // namespace upcjetmcd + +DECLARE_SOA_TABLE(UpcJetsMCD, "AOD", "UPCJETMCD", + upcjetmcd::UpcJetEventMCDId, + upcjetmcd::Pt, + upcjetmcd::Eta, + upcjetmcd::Phi, + upcjetmcd::Area, + upcjetmcd::NConstituents); +using UpcJetMCD = UpcJetsMCD::iterator; + +namespace upcjettrackmcd +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetMCD, upcJetMCD, int32_t, UpcJetsMCD, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +} // namespace upcjettrackmcd + +DECLARE_SOA_TABLE(UpcJetTracksMCD, "AOD", "UPCJETTRACKMCD", + upcjettrackmcd::UpcJetMCDId, + upcjettrackmcd::Pt, + upcjettrackmcd::Eta, + upcjettrackmcd::Phi); +using UpcJetTrackMCD = UpcJetTracksMCD::iterator; + +// ============================================================ +// MCP tables +// ============================================================ +namespace upcjeteventmcp +{ +DECLARE_SOA_COLUMN(PosZ, posZ, float); +} // namespace upcjeteventmcp + +DECLARE_SOA_TABLE(UpcJetEventsMCP, "AOD", "UPCJETEVENTMCP", + upcjeteventmcp::PosZ); +using UpcJetEventMCP = UpcJetEventsMCP::iterator; + +namespace upctrackmcp +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetEventMCP, upcJetEventMCP, int32_t, UpcJetEventsMCP, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +} // namespace upctrackmcp + +DECLARE_SOA_TABLE(UpcTracksMCP, "AOD", "UPCTRACKMCP", + upctrackmcp::UpcJetEventMCPId, + upctrackmcp::Pt, + upctrackmcp::Eta, + upctrackmcp::Phi); +using UpcTrackMCP = UpcTracksMCP::iterator; + +namespace upcjetmcp +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetEventMCP, upcJetEventMCP, int32_t, UpcJetEventsMCP, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Area, area, float); +DECLARE_SOA_COLUMN(NConstituents, nConstituents, int); +} // namespace upcjetmcp + +DECLARE_SOA_TABLE(UpcJetsMCP, "AOD", "UPCJETMCP", + upcjetmcp::UpcJetEventMCPId, + upcjetmcp::Pt, + upcjetmcp::Eta, + upcjetmcp::Phi, + upcjetmcp::Area, + upcjetmcp::NConstituents); +using UpcJetMCP = UpcJetsMCP::iterator; + +namespace upcjettrackmcp +{ +DECLARE_SOA_INDEX_COLUMN_FULL(UpcJetMCP, upcJetMCP, int32_t, UpcJetsMCP, ""); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +} // namespace upcjettrackmcp + +DECLARE_SOA_TABLE(UpcJetTracksMCP, "AOD", "UPCJETTRACKMCP", + upcjettrackmcp::UpcJetMCPId, + upcjettrackmcp::Pt, + upcjettrackmcp::Eta, + upcjettrackmcp::Phi); +using UpcJetTrackMCP = UpcJetTracksMCP::iterator; + +} // namespace o2::aod + +#include "PWGUD/Core/SGCutParHolder.h" +#include "PWGUD/Core/SGSelector.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// Stand-alone QA task for validating UPC event tagging for charged-jet studies. +/// The tagging and QA developed here are intended to guide a future integration +/// of the required UPC information into the PWGJE derived-data workflow. +struct JetUpcQa { + static constexpr int RequiredSingleGapA = 1; + static constexpr int RequiredSingleGapC = 2; + static constexpr int RequiredDoubleGap = 3; + + // Output tables + Produces upcJetEventTable; + Produces upcJetTable; + Produces upcJetTrackTable; + + Produces upcJetEventTableMCD; + Produces upcJetTableMCD; + Produces upcJetTrackTableMCD; + + Produces upcJetEventTableMCP; + Produces upcJetTableMCP; + Produces upcJetTrackTableMCP; + + Produces upcTrackTable; + Produces upcTrackTableMCD; + Produces upcTrackTableMCP; + + // Type aliases + using BCsWithSel = soa::Join; + using CollisionsData = soa::Join; + using TracksData = soa::Join; + using CollisionsMC = soa::Join; + using TracksMC = soa::Join; + + // Preslices + // Preslice tracksPerCollision = aod::track::collisionId; + // Preslice tracksPerCollisionMC = aod::track::collisionId; + + // SGSelector buffers + std::vector amplitudesFV0; + std::vector amplitudesFT0A; + std::vector amplitudesFT0C; + std::vector amplitudesFDDA; + std::vector amplitudesFDDC; + + // Configurables + Configurable cfgFT0AMax{"cfgFT0AMax", 100.f, "FT0A amplitude threshold"}; + Configurable cfgFT0CMax{"cfgFT0CMax", 50.f, "FT0C amplitude threshold"}; + Configurable cfgFV0AMax{"cfgFV0AMax", 100.f, "FV0A amplitude threshold"}; + Configurable cfgFDDAMax{"cfgFDDAMax", -1.f, "FDDA amplitude (-1 = ignore)"}; + Configurable cfgFDDCMax{"cfgFDDCMax", -1.f, "FDDC amplitude (-1 = ignore)"}; + Configurable cfgFITTime{"cfgFITTime", 4.f, "FIT time window (ns)"}; + Configurable cfgMinNBCs{"cfgMinNBCs", 7, "Minimum number of BCs"}; + Configurable cfgNDtcoll{"cfgNDtcoll", 1, "Time resolution multiplier for compatible BCs"}; + Configurable cfgMinNTracks{"cfgMinNTracks", 0, "Min tracks"}; + Configurable cfgMaxNTracks{"cfgMaxNTracks", 100, "Max tracks"}; + + Configurable cfgTrackPtMin{"cfgTrackPtMin", 0.15f, "Min track pT (GeV/c)"}; + Configurable cfgTrackEtaMax{"cfgTrackEtaMax", 0.9f, "Max track |eta|"}; + Configurable cfgTrackSelection{"cfgTrackSelection", "kinematicsOnly", "Reconstructed-track selection: kinematicsOnly, globalTracks, or udDefault"}; + Configurable cfgTrackDCAZMax{"cfgTrackDCAZMax", 2.f, "Maximum |DCAz| for udDefault track selection (cm)"}; + Configurable cfgTrackDCAXYMax{"cfgTrackDCAXYMax", 0.f, "Maximum |DCAxy| for udDefault (cm); 0 uses the pT-dependent UD cut"}; + Configurable cfgTrackTPCChi2NClMax{"cfgTrackTPCChi2NClMax", 4.f, "Maximum TPC chi2 per cluster for udDefault"}; + Configurable cfgTrackTPCNClsFindableMin{"cfgTrackTPCNClsFindableMin", 70, "Minimum findable TPC clusters for udDefault"}; + Configurable cfgTrackITSChi2NClMax{"cfgTrackITSChi2NClMax", 36.f, "Maximum ITS chi2 per cluster for udDefault"}; + Configurable cfgJetR{"cfgJetR", 0.4f, "Jet radius"}; + Configurable cfgJetPtMin{"cfgJetPtMin", 5.0f, "Min jet pT (GeV/c)"}; + Configurable cfgJetEtaMax{"cfgJetEtaMax", 0.5f, "Max jet |eta|"}; + Configurable cfgZDCEnergyCut{"cfgZDCEnergyCut", 10.f, "ZDC common energy threshold for Xn tagging"}; + Configurable cfgZDCTimeCut{"cfgZDCTimeCut", 2.f, "ZDC time window for Xn tagging (ns)"}; + Configurable cfgUseGapTagging{"cfgUseGapTagging", true, "Require SGSelector gap tag for event selection"}; + Configurable cfgUseZDCTagging{"cfgUseZDCTagging", false, "Require ZDC neutron tag for event selection"}; + Configurable cfgRequiredGapSide{"cfgRequiredGapSide", 0, "Required gap side when gap tagging is enabled (0 = any selected gap, 1 = SingleGapA, 2 = SingleGapC, 3 = DoubleGap)"}; + Configurable cfgRequiredNeutronClass{"cfgRequiredNeutronClass", 0, "Required neutron class when ZDC tagging is enabled (0 = any valid class, 1 = XnXn, 2 = Xn0n, 3 = 0nXn, 4 = 0n0n)"}; + + struct ZDCTagInfo { + float energyCommonZNA = -999.f; + float energyCommonZNC = -999.f; + float timeZNA = -999.f; + float timeZNC = -999.f; + int neutronClass = 0; + }; + + struct GapSelectionInfo { + int gapSide = o2::aod::sgselector::NoGap; + ZDCTagInfo zdc; + }; + + SGSelector sgSelector; + SGCutParHolder sgCuts; + + HistogramRegistry registry{"registry"}; + enum class TrackSelectionMode { + KinematicsOnly, + GlobalTracks, + UDDefault + }; + TrackSelectionMode trackSelectionMode = TrackSelectionMode::KinematicsOnly; + + // Init + void init(InitContext&) + { + if (cfgTrackSelection.value == "kinematicsOnly") { + trackSelectionMode = TrackSelectionMode::KinematicsOnly; + } else if (cfgTrackSelection.value == "globalTracks") { + trackSelectionMode = TrackSelectionMode::GlobalTracks; + } else if (cfgTrackSelection.value == "udDefault") { + trackSelectionMode = TrackSelectionMode::UDDefault; + } else { + LOGP(fatal, "Unknown cfgTrackSelection '{}'. Choose kinematicsOnly, globalTracks, or udDefault.", cfgTrackSelection.value); + } + + sgCuts.SetNDtcoll(cfgNDtcoll); + sgCuts.SetMinNBCs(cfgMinNBCs); + sgCuts.SetNTracks(cfgMinNTracks, cfgMaxNTracks); + sgCuts.SetMaxFITtime(cfgFITTime); + sgCuts.SetFITAmpLimits({cfgFV0AMax, cfgFT0AMax, cfgFT0CMax, cfgFDDAMax, cfgFDDCMax}); + + // Event-level QA only + registry.add("hGapSide", "Gap Side (Data);Gap Side;Counts", {HistType::kTH1F, {{6, -1.5, 4.5}}}); + registry.add("hGapSideMCD", "Gap Side (MCD);Gap Side;Counts", {HistType::kTH1F, {{6, -1.5, 4.5}}}); + + registry.add("hPosZ", "Vertex Z (Data);z (cm);Counts", {HistType::kTH1F, {{100, -15., 15.}}}); + registry.add("hPosZMCD", "Vertex Z (MCD);z (cm);Counts", {HistType::kTH1F, {{100, -15., 15.}}}); + registry.add("hPosZMCP", "Vertex Z (MCP);z (cm);Counts", {HistType::kTH1F, {{100, -15., 15.}}}); + + registry.add("hCentralityFT0M", "Centrality FT0M (Data);Cent;Counts", {HistType::kTH1F, {{100, 0., 100.}}}); + registry.add("hCentMCD", "Centrality FT0M (MCD);Cent;Counts", {HistType::kTH1F, {{100, 0., 100.}}}); + + registry.add("hMCDFoundBC", "MCD has_foundBC;0=false 1=true;Counts", {HistType::kTH1F, {{2, -0.5, 1.5}}}); + registry.add("hMCPNCharged", "MCP N charged primaries;N;Counts", {HistType::kTH1F, {{200, -0.5, 199.5}}}); + + registry.add("hZNAEnergy", "ZNA common energy (Data);E;Counts", {HistType::kTH1F, {{400, -10., 390.}}}); + registry.add("hZNCEnergy", "ZNC common energy (Data);E;Counts", {HistType::kTH1F, {{400, -10., 390.}}}); + registry.add("hZNATime", "ZNA time (Data);t (ns);Counts", {HistType::kTH1F, {{200, -20., 20.}}}); + registry.add("hZNCTime", "ZNC time (Data);t (ns);Counts", {HistType::kTH1F, {{200, -20., 20.}}}); + registry.add("hNeutronClass", "Neutron class (Data);class;Counts", {HistType::kTH1F, {{5, -0.5, 4.5}}}); + registry.add("hZNAEnergyMCD", "ZNA common energy (MCD);E;Counts", {HistType::kTH1F, {{400, -10., 390.}}}); + registry.add("hZNCEnergyMCD", "ZNC common energy (MCD);E;Counts", {HistType::kTH1F, {{400, -10., 390.}}}); + registry.add("hZNATimeMCD", "ZNA time (MCD);t (ns);Counts", {HistType::kTH1F, {{200, -20., 20.}}}); + registry.add("hZNCTimeMCD", "ZNC time (MCD);t (ns);Counts", {HistType::kTH1F, {{200, -20., 20.}}}); + registry.add("hNeutronClassMCD", "Neutron class (MCD);class;Counts", {HistType::kTH1F, {{5, -0.5, 4.5}}}); + registry.add("hSelectionBits", "Selection bits (Data);0 all 1 gap 2 zdc 3 accepted;Counts", {HistType::kTH1F, {{4, -0.5, 3.5}}}); + registry.add("hSelectionBitsMCD", "Selection bits (MCD);0 all 1 gap 2 zdc 3 accepted;Counts", {HistType::kTH1F, {{4, -0.5, 3.5}}}); + } + + template + bool isSelectedTrack(TTrack const& track) const + { + if (std::abs(track.eta()) > cfgTrackEtaMax.value || track.pt() < cfgTrackPtMin.value) { + return false; + } + if (trackSelectionMode == TrackSelectionMode::KinematicsOnly) { + return true; + } + if (trackSelectionMode == TrackSelectionMode::GlobalTracks) { + return track.isGlobalTrack(); + } + if (!track.isPVContributor()) { + return false; + } + if (std::abs(track.dcaZ()) > cfgTrackDCAZMax.value) { + return false; + } + float maxDCAxy = cfgTrackDCAXYMax.value; + if (maxDCAxy <= 0.f) { + maxDCAxy = 0.0105f + 0.035f / std::pow(track.pt(), 1.1f); + } + if (std::abs(track.dcaXY()) > maxDCAxy) { + return false; + } + if (track.tpcChi2NCl() > cfgTrackTPCChi2NClMax.value || track.tpcNClsFindable() < cfgTrackTPCNClsFindableMin.value) { + return false; + } + if (track.itsChi2NCl() > cfgTrackITSChi2NClMax.value) { + return false; + } + return true; + } + + // Helper: event tagging and selection + bool isSelectedGap(int gapSide) const + { + if (cfgRequiredGapSide.value == RequiredSingleGapA) { + return gapSide == o2::aod::sgselector::SingleGapA; + } + if (cfgRequiredGapSide.value == RequiredSingleGapC) { + return gapSide == o2::aod::sgselector::SingleGapC; + } + if (cfgRequiredGapSide.value == RequiredDoubleGap) { + return gapSide == o2::aod::sgselector::DoubleGap; + } + return gapSide == o2::aod::sgselector::SingleGapA || + gapSide == o2::aod::sgselector::SingleGapC || + gapSide == o2::aod::sgselector::DoubleGap; + } + + int getNeutronClass(ZDCTagInfo const& zdc) + { + if (zdc.energyCommonZNA < 0.f || zdc.energyCommonZNC < 0.f) { + return 0; + } + + bool aXn = zdc.energyCommonZNA > cfgZDCEnergyCut && std::abs(zdc.timeZNA) < cfgZDCTimeCut; + bool cXn = zdc.energyCommonZNC > cfgZDCEnergyCut && std::abs(zdc.timeZNC) < cfgZDCTimeCut; + bool a0n = zdc.energyCommonZNA <= cfgZDCEnergyCut; + bool c0n = zdc.energyCommonZNC <= cfgZDCEnergyCut; + + if (aXn && cXn) { + return 1; // XnXn + } + if (aXn && c0n) { + return 2; // Xn0n + } + if (a0n && cXn) { + return 3; // 0nXn + } + if (a0n && c0n) { + return 4; // 0n0n + } + return 0; + } + + bool isSelectedZDC(ZDCTagInfo const& zdc) const + { + if (cfgRequiredNeutronClass.value > 0) { + return zdc.neutronClass == cfgRequiredNeutronClass.value; + } + return zdc.neutronClass > 0; + } + + bool isAcceptedEvent(bool isGapTagged, bool isZDCTagged) const + { + return (!cfgUseGapTagging.value || isGapTagged) && + (!cfgUseZDCTagging.value || isZDCTagged); + } + + void fillSelectionBits(bool isMCD, bool isGapTagged, bool isZDCTagged, bool isAccepted) + { + if (isMCD) { + registry.fill(HIST("hSelectionBitsMCD"), 0); + if (isGapTagged) { + registry.fill(HIST("hSelectionBitsMCD"), 1); + } + if (isZDCTagged) { + registry.fill(HIST("hSelectionBitsMCD"), 2); + } + if (isAccepted) { + registry.fill(HIST("hSelectionBitsMCD"), 3); + } + return; + } + + registry.fill(HIST("hSelectionBits"), 0); + if (isGapTagged) { + registry.fill(HIST("hSelectionBits"), 1); + } + if (isZDCTagged) { + registry.fill(HIST("hSelectionBits"), 2); + } + if (isAccepted) { + registry.fill(HIST("hSelectionBits"), 3); + } + } + + template + ZDCTagInfo getZDCTagInfo(TBC const& bc) + { + ZDCTagInfo zdcInfo; + if (!bc.has_zdc()) { + return zdcInfo; + } + + auto const& zdc = bc.zdc(); + zdcInfo.energyCommonZNA = zdc.energyCommonZNA(); + zdcInfo.energyCommonZNC = zdc.energyCommonZNC(); + zdcInfo.timeZNA = zdc.timeZNA(); + zdcInfo.timeZNC = zdc.timeZNC(); + zdcInfo.neutronClass = getNeutronClass(zdcInfo); + return zdcInfo; + } + + template + GapSelectionInfo getGapSide(TCollision const& collision, TBCs const& bcs) + { + amplitudesFV0.clear(); + amplitudesFT0A.clear(); + amplitudesFT0C.clear(); + amplitudesFDDA.clear(); + amplitudesFDDC.clear(); + + GapSelectionInfo selection; + + if (!collision.has_foundBC()) { + return selection; + } + + auto const bc = collision.template foundBC_as(); + auto const bcRange = udhelpers::compatibleBCs(collision, sgCuts.NDtcoll(), bcs, sgCuts.minNBCs()); + + auto const result = sgSelector.IsSelected(sgCuts, collision, bcRange, bc, + &litudesFV0, &litudesFT0A, &litudesFT0C, + &litudesFDDA, &litudesFDDC); + + selection.gapSide = result.value; + if (result.bc) { + selection.zdc = getZDCTagInfo(*result.bc); + } + + if (!isSelectedGap(selection.gapSide)) { + amplitudesFV0.clear(); + amplitudesFT0A.clear(); + amplitudesFT0C.clear(); + amplitudesFDDA.clear(); + amplitudesFDDC.clear(); + } + + return selection; + } + + // Helper: jet finding for detector-level tracks + template + void runJetFindingDet(TTracks const& tracks, + int evtIdx, + TJetTable& jetTable, + TTrkTable& trkTable) + { + std::vector fjInput; + fjInput.reserve(tracks.size()); + + for (auto const& t : tracks) { + if (!isSelectedTrack(t)) { + continue; + } + + fastjet::PseudoJet p; + p.reset_PtYPhiM(t.pt(), t.eta(), t.phi(), o2::constants::physics::MassPiPlus); + fjInput.push_back(p); + } + + if (fjInput.empty()) { + return; + } + + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, cfgJetR); + fastjet::AreaDefinition areaDef(fastjet::active_area_explicit_ghosts, + fastjet::GhostedAreaSpec(cfgTrackEtaMax + cfgJetR)); + fastjet::ClusterSequenceArea cs(fjInput, jetDef, areaDef); + auto jets = fastjet::sorted_by_pt(cs.inclusive_jets(cfgJetPtMin)); + + for (auto const& jet : jets) { + if (std::abs(jet.eta()) > cfgJetEtaMax) { + continue; + } + + auto constituents = jet.constituents(); + jetTable(evtIdx, jet.pt(), jet.eta(), jet.phi_std(), + jet.area(), static_cast(constituents.size())); + int jetIdx = jetTable.lastIndex(); + + for (auto const& c : constituents) { + trkTable(jetIdx, c.pt(), c.eta(), c.phi_std()); + } + } + } + + // Helper: jet finding for particle-level MC + template + void runJetFindingMCP(aod::McParticles const& particles, + int evtIdx, + TJetTable& jetTable, + TTrkTable& trkTable) + { + std::vector fjInput; + int nCharged = 0; + + for (auto const& p : particles) { + if (!p.isPhysicalPrimary()) { + continue; + } + if (std::abs(p.eta()) > cfgTrackEtaMax) { + continue; + } + if (p.pt() < cfgTrackPtMin) { + continue; + } + + auto pdg = std::abs(p.pdgCode()); + bool charged = (pdg == kPiPlus || pdg == kKPlus || pdg == kProton || pdg == kElectron || pdg == kMuonMinus); + if (!charged) { + continue; + } + + fastjet::PseudoJet fpp; + fpp.reset_PtYPhiM(p.pt(), p.eta(), p.phi(), o2::constants::physics::MassPiPlus); + fjInput.push_back(fpp); + ++nCharged; + } + + registry.fill(HIST("hMCPNCharged"), nCharged); + + if (fjInput.empty()) { + return; + } + + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, cfgJetR); + fastjet::AreaDefinition areaDef(fastjet::active_area_explicit_ghosts, + fastjet::GhostedAreaSpec(cfgTrackEtaMax + cfgJetR)); + fastjet::ClusterSequenceArea cs(fjInput, jetDef, areaDef); + auto jets = fastjet::sorted_by_pt(cs.inclusive_jets(cfgJetPtMin)); + + for (auto const& jet : jets) { + if (std::abs(jet.eta()) > cfgJetEtaMax) { + continue; + } + + auto constituents = jet.constituents(); + jetTable(evtIdx, jet.pt(), jet.eta(), jet.phi_std(), + jet.area(), static_cast(constituents.size())); + int jetIdx = jetTable.lastIndex(); + + for (auto const& c : constituents) { + trkTable(jetIdx, c.pt(), c.eta(), c.phi_std()); + } + } + } + + template + void fillEventTracksDet(TTracks const& tracks, int evtIdx, TTrackTable& trackTable) + { + int nAll = 0; + int nFilled = 0; + for (auto const& t : tracks) { + ++nAll; + if (!isSelectedTrack(t)) + continue; + trackTable(evtIdx, t.pt(), t.eta(), t.phi()); + ++nFilled; + } + LOGP(info, "fillEventTracksDet: evtIdx={} nAll={} nFilled={}", evtIdx, nAll, nFilled); + } + + template + void fillEventTracksMCP(aod::McParticles const& particles, int evtIdx, TTrackTable& trackTable) + { + for (auto const& p : particles) { + if (!p.isPhysicalPrimary()) + continue; + if (std::abs(p.eta()) > cfgTrackEtaMax) + continue; + if (p.pt() < cfgTrackPtMin) + continue; + + auto pdg = std::abs(p.pdgCode()); + bool charged = (pdg == kPiPlus || pdg == kKPlus || pdg == kProton || + pdg == kElectron || pdg == kMuonMinus); + if (!charged) + continue; + + trackTable(evtIdx, p.pt(), p.eta(), p.phi()); + } + } + + // Process: Data + void processData(CollisionsData::iterator const& collision, + BCsWithSel const& bcs, + aod::Zdcs const&, + aod::FT0s const&, aod::FV0As const&, aod::FDDs const&, + TracksData const& tracks) + { + auto gapInfo = getGapSide(collision, bcs); + int gapSide = gapInfo.gapSide; + bool isGapTagged = isSelectedGap(gapSide); + bool isZDCTagged = isSelectedZDC(gapInfo.zdc); + bool isAccepted = isAcceptedEvent(isGapTagged, isZDCTagged); + registry.fill(HIST("hGapSide"), gapSide); + registry.fill(HIST("hZNAEnergy"), gapInfo.zdc.energyCommonZNA); + registry.fill(HIST("hZNCEnergy"), gapInfo.zdc.energyCommonZNC); + registry.fill(HIST("hZNATime"), gapInfo.zdc.timeZNA); + registry.fill(HIST("hZNCTime"), gapInfo.zdc.timeZNC); + registry.fill(HIST("hNeutronClass"), gapInfo.zdc.neutronClass); + fillSelectionBits(false, isGapTagged, isZDCTagged, isAccepted); + + if (!isAccepted) { + return; + } + + registry.fill(HIST("hPosZ"), collision.posZ()); + registry.fill(HIST("hCentralityFT0M"), collision.centFT0M()); + + upcJetEventTable(gapSide, + collision.posZ(), + collision.centFT0M(), + gapInfo.zdc.energyCommonZNA, + gapInfo.zdc.energyCommonZNC, + gapInfo.zdc.timeZNA, + gapInfo.zdc.timeZNC, + gapInfo.zdc.neutronClass, + isGapTagged, + isZDCTagged); + int evtIdx = upcJetEventTable.lastIndex(); + + std::vector fjInput; + fjInput.reserve(256); + + for (auto const& t : tracks) { + if (t.collisionId() != collision.globalIndex()) { + continue; + } + if (!isSelectedTrack(t)) { + continue; + } + + // event-level track table + upcTrackTable(evtIdx, t.pt(), t.eta(), t.phi()); + + // jet finding input + fastjet::PseudoJet p; + p.reset_PtYPhiM(t.pt(), t.eta(), t.phi(), o2::constants::physics::MassPiPlus); + fjInput.push_back(p); + } + + if (fjInput.empty()) { + return; + } + + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, cfgJetR); + fastjet::AreaDefinition areaDef( + fastjet::active_area_explicit_ghosts, + fastjet::GhostedAreaSpec(cfgTrackEtaMax + cfgJetR)); + + fastjet::ClusterSequenceArea cs(fjInput, jetDef, areaDef); + auto jets = fastjet::sorted_by_pt(cs.inclusive_jets(cfgJetPtMin)); + + for (auto const& jet : jets) { + if (std::abs(jet.eta()) > cfgJetEtaMax) { + continue; + } + + auto constituents = jet.constituents(); + + upcJetTable(evtIdx, + jet.pt(), + jet.eta(), + jet.phi_std(), + jet.area(), + static_cast(constituents.size())); + + int jetIdx = upcJetTable.lastIndex(); + + for (auto const& c : constituents) { + upcJetTrackTable(jetIdx, evtIdx, c.pt(), c.eta(), c.phi_std()); + } + } + } + PROCESS_SWITCH(JetUpcQa, processData, "Process real data", false); + // Process: MCD + void processMCD(CollisionsMC::iterator const& collision, + BCsWithSel const& bcs, + aod::Zdcs const&, + aod::FT0s const&, aod::FV0As const&, aod::FDDs const&, + TracksMC const& tracks) + { + registry.fill(HIST("hMCDFoundBC"), collision.has_foundBC() ? 1 : 0); + + auto gapInfo = getGapSide(collision, bcs); + int gapSide = gapInfo.gapSide; + bool isGapTagged = isSelectedGap(gapSide); + bool isZDCTagged = isSelectedZDC(gapInfo.zdc); + bool isAccepted = isAcceptedEvent(isGapTagged, isZDCTagged); + registry.fill(HIST("hGapSideMCD"), gapSide); + registry.fill(HIST("hZNAEnergyMCD"), gapInfo.zdc.energyCommonZNA); + registry.fill(HIST("hZNCEnergyMCD"), gapInfo.zdc.energyCommonZNC); + registry.fill(HIST("hZNATimeMCD"), gapInfo.zdc.timeZNA); + registry.fill(HIST("hZNCTimeMCD"), gapInfo.zdc.timeZNC); + registry.fill(HIST("hNeutronClassMCD"), gapInfo.zdc.neutronClass); + fillSelectionBits(true, isGapTagged, isZDCTagged, isAccepted); + + if (!isAccepted) { + return; + } + + registry.fill(HIST("hPosZMCD"), collision.posZ()); + registry.fill(HIST("hCentMCD"), collision.centFT0M()); + + upcJetEventTableMCD(gapSide, + collision.posZ(), + collision.centFT0M(), + gapInfo.zdc.energyCommonZNA, + gapInfo.zdc.energyCommonZNC, + gapInfo.zdc.timeZNA, + gapInfo.zdc.timeZNC, + gapInfo.zdc.neutronClass, + isGapTagged, + isZDCTagged); + int evtIdx = upcJetEventTableMCD.lastIndex(); + + std::vector fjInput; + fjInput.reserve(256); + + for (auto const& t : tracks) { + if (t.collisionId() != collision.globalIndex()) { + continue; + } + if (!isSelectedTrack(t)) { + continue; + } + + upcTrackTableMCD(evtIdx, t.pt(), t.eta(), t.phi()); + + fastjet::PseudoJet p; + p.reset_PtYPhiM(t.pt(), t.eta(), t.phi(), o2::constants::physics::MassPiPlus); + fjInput.push_back(p); + } + + if (fjInput.empty()) { + return; + } + + fastjet::JetDefinition jetDef(fastjet::antikt_algorithm, cfgJetR); + fastjet::AreaDefinition areaDef( + fastjet::active_area_explicit_ghosts, + fastjet::GhostedAreaSpec(cfgTrackEtaMax + cfgJetR)); + + fastjet::ClusterSequenceArea cs(fjInput, jetDef, areaDef); + auto jets = fastjet::sorted_by_pt(cs.inclusive_jets(cfgJetPtMin)); + + for (auto const& jet : jets) { + if (std::abs(jet.eta()) > cfgJetEtaMax) { + continue; + } + + auto constituents = jet.constituents(); + + upcJetTableMCD(evtIdx, + jet.pt(), + jet.eta(), + jet.phi_std(), + jet.area(), + static_cast(constituents.size())); + + int jetIdx = upcJetTableMCD.lastIndex(); + + for (auto const& c : constituents) { + upcJetTrackTableMCD(jetIdx, c.pt(), c.eta(), c.phi_std()); + } + } + } + PROCESS_SWITCH(JetUpcQa, processMCD, "Process MC detector level", true); + + // Process: MCP + void processMCP(aod::McCollision const& mcCollision, + aod::McParticles const& particles) + { + registry.fill(HIST("hPosZMCP"), mcCollision.posZ()); + + upcJetEventTableMCP(mcCollision.posZ()); + int evtIdx = upcJetEventTableMCP.lastIndex(); + fillEventTracksMCP(particles, evtIdx, upcTrackTableMCP); + runJetFindingMCP(particles, evtIdx, upcJetTableMCP, upcJetTrackTableMCP); + } + PROCESS_SWITCH(JetUpcQa, processMCP, "Process MC particle level", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} From 624b326f51706b6108a25fe091ad7af99ac9f896 Mon Sep 17 00:00:00 2001 From: Meiyi Chen Date: Fri, 31 Jul 2026 01:14:48 +0800 Subject: [PATCH 51/71] [PWGCF] Add pi-triton femto in HadNucleiFemto.cxx and a new workflow in Tasks for pi-d systematics (#17260) --- PWGCF/Femto/FemtoNuclei/CMakeLists.txt | 2 + .../DataModel/HadronNucleiTables.h | 22 +- .../TableProducer/HadNucleiFemto.cxx | 354 +++++++- PWGCF/Femto/FemtoNuclei/Tasks/CMakeLists.txt | 15 + .../Tasks/piDeFemtoSystematics.cxx | 854 ++++++++++++++++++ 5 files changed, 1199 insertions(+), 48 deletions(-) create mode 100644 PWGCF/Femto/FemtoNuclei/Tasks/CMakeLists.txt create mode 100644 PWGCF/Femto/FemtoNuclei/Tasks/piDeFemtoSystematics.cxx diff --git a/PWGCF/Femto/FemtoNuclei/CMakeLists.txt b/PWGCF/Femto/FemtoNuclei/CMakeLists.txt index 27462d99baf..03068dcd4aa 100644 --- a/PWGCF/Femto/FemtoNuclei/CMakeLists.txt +++ b/PWGCF/Femto/FemtoNuclei/CMakeLists.txt @@ -10,3 +10,5 @@ # or submit itself to any jurisdiction. add_subdirectory(TableProducer) +add_subdirectory(Tasks) + diff --git a/PWGCF/Femto/FemtoNuclei/DataModel/HadronNucleiTables.h b/PWGCF/Femto/FemtoNuclei/DataModel/HadronNucleiTables.h index ce8e83575fe..30fd0d1c610 100644 --- a/PWGCF/Femto/FemtoNuclei/DataModel/HadronNucleiTables.h +++ b/PWGCF/Femto/FemtoNuclei/DataModel/HadronNucleiTables.h @@ -50,8 +50,15 @@ DECLARE_SOA_COLUMN(InnerParamTPCNu, innerParamTPCNu, float); DECLARE_SOA_COLUMN(SignalTPCHad, signalTPCHad, float); DECLARE_SOA_COLUMN(InnerParamTPCHad, innerParamTPCHad, float); DECLARE_SOA_COLUMN(NClsTPCNu, nClsTPCNu, uint8_t); +DECLARE_SOA_COLUMN(NClsTPCHad, nClsTPCHad, uint8_t); +DECLARE_SOA_COLUMN(NCrossedRowsTPCNu, nCrossedRowsTPCNu, uint8_t); +DECLARE_SOA_COLUMN(NCrossedRowsTPCHad, nCrossedRowsTPCHad, uint8_t); DECLARE_SOA_COLUMN(NSigmaTPCNu, nSigmaTPCNu, float); DECLARE_SOA_COLUMN(NSigmaTPCHad, nSigmaTPCHad, float); +DECLARE_SOA_COLUMN(NSigmaTOFNu, nSigmaTOFNu, float); +DECLARE_SOA_COLUMN(NSigmaITSNu, nSigmaITSNu, float); +DECLARE_SOA_COLUMN(NSigmaTOFHad, nSigmaTOFHad, float); +DECLARE_SOA_COLUMN(NSigmaITSHad, nSigmaITSHad, float); DECLARE_SOA_COLUMN(NSigmaTPCHadPi, nSigmaTPCHadPi, float); DECLARE_SOA_COLUMN(NSigmaTPCHadKa, nSigmaTPCHadKa, float); DECLARE_SOA_COLUMN(NSigmaTPCHadPr, nSigmaTPCHadPr, float); @@ -73,6 +80,9 @@ DECLARE_SOA_COLUMN(ItsClusterSizeHad, itsClusterSizeHad, uint32_t); DECLARE_SOA_COLUMN(SharedClustersNu, sharedClustersNu, uint8_t); DECLARE_SOA_COLUMN(SharedClustersHad, sharedClustersHad, uint8_t); +DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); + DECLARE_SOA_COLUMN(IsBkgUS, isBkgUS, bool); DECLARE_SOA_COLUMN(IsBkgEM, isBkgEM, bool); @@ -101,6 +111,9 @@ DECLARE_SOA_TABLE(HadronNucleiTable, "AOD", "HADNUCLEITABLE", hadron_nuclei_tables::SignalTPCHad, hadron_nuclei_tables::InnerParamTPCHad, hadron_nuclei_tables::NClsTPCNu, + hadron_nuclei_tables::NClsTPCHad, + hadron_nuclei_tables::NCrossedRowsTPCNu, + hadron_nuclei_tables::NCrossedRowsTPCHad, hadron_nuclei_tables::NSigmaTPCNu, hadron_nuclei_tables::NSigmaTPCHadPi, hadron_nuclei_tables::NSigmaTPCHadKa, @@ -117,7 +130,14 @@ DECLARE_SOA_TABLE(HadronNucleiTable, "AOD", "HADNUCLEITABLE", hadron_nuclei_tables::ItsClusterSizeNu, hadron_nuclei_tables::ItsClusterSizeHad, hadron_nuclei_tables::SharedClustersNu, - hadron_nuclei_tables::SharedClustersHad) + hadron_nuclei_tables::SharedClustersHad, + hadron_nuclei_tables::DeltaEta, + hadron_nuclei_tables::DeltaPhi, + hadron_nuclei_tables::NSigmaTPCHad, + hadron_nuclei_tables::NSigmaTOFNu, + hadron_nuclei_tables::NSigmaITSNu, + hadron_nuclei_tables::NSigmaTOFHad, + hadron_nuclei_tables::NSigmaITSHad) DECLARE_SOA_TABLE(HadronHyperTable, "AOD", "HADHYPERTABLE", hadron_nuclei_tables::PtHyp, hadron_nuclei_tables::EtaHyp, diff --git a/PWGCF/Femto/FemtoNuclei/TableProducer/HadNucleiFemto.cxx b/PWGCF/Femto/FemtoNuclei/TableProducer/HadNucleiFemto.cxx index 2d7b4310774..374984b2188 100644 --- a/PWGCF/Femto/FemtoNuclei/TableProducer/HadNucleiFemto.cxx +++ b/PWGCF/Femto/FemtoNuclei/TableProducer/HadNucleiFemto.cxx @@ -77,7 +77,7 @@ using std::array; using CollBracket = o2::math_utils::Bracket; using CollisionsFull = soa::Join; using CollisionsFullMC = soa::Join; -using TrackCandidates = soa::Join; +using TrackCandidates = soa::Join; namespace { @@ -87,12 +87,9 @@ const std::vector betheBlochParticleNames{"De", "He3"}; const std::vector betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; constexpr std::array tmpRadiiTPC{{85.f, 105.f, 125.f, 145.f, 165.f, 185.f, 205.f, 225.f, 245.f}}; constexpr int DeuteronPDG = o2::constants::physics::Pdg::kDeuteron; +constexpr int TritonPDG = o2::constants::physics::Pdg::kTriton; constexpr int He3PDG = o2::constants::physics::Pdg::kHelium3; -constexpr float He3RigidityMin = 0.8f; -constexpr int He3TPCNClsFoundMin = 110; constexpr float He3TPCChi2NClMin = 0.5f; -constexpr float He3TPCNSigmaMax = 3.0f; -constexpr float He3ITSNSigmaMin = -1.5f; using PairLorentzVector = ROOT::Math::LorentzVector>; enum Selections { @@ -132,12 +129,19 @@ struct HadNucandidate { float momNuTPC = -99.f; float momHadTPC = -99.f; uint8_t nTPCClustersNu = 0u; + uint8_t nTPCClustersHad = 0u; + uint8_t nTPCCrossedRowsNu = 0u; + uint8_t nTPCCrossedRowsHad = 0u; uint8_t sharedClustersNu = 0u; uint8_t sharedClustersHad = 0u; float chi2TPCNu = -10.f; float chi2TPCHad = -10.f; float nSigmaNu = -10.f; float nSigmaHad = -10.f; + float nSigmaTOFNu = -10.f; + float nSigmaITSNu = -10.f; + float nSigmaTOFHad = -10.f; + float nSigmaITSHad = -10.f; float nSigmaTPCHadPi = -10.f; float nSigmaTPCHadKa = -10.f; float nSigmaTPCHadPr = -10.f; @@ -162,6 +166,8 @@ struct HadNucandidate { int trackIDNu = -1; int trackIDHad = -1; + float deltaEta = -99.f; + float deltaPhi = -99.f; float kstar = 1.f; float mT = 1.f; @@ -247,6 +253,31 @@ struct HadNucleiFemto { Configurable settingUseProtonMassForKstarMt{"settingUseProtonMassForKstarMt", false, "If true, use proton mass instead of deuteron mass for kstar and mT"}; } deuteronPid; + struct : o2::framework::ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"helium3Pid"}; + Configurable settingRigidityMinHe3{"settingRigidityMinHe3", 0.8f, "Minimum He3 TPC rigidity"}; + Configurable settingTPCNClsFoundMinHe3{"settingTPCNClsFoundMinHe3", 110, "Minimum found TPC clusters for He3"}; + Configurable settingTPCCrossedRowsMinHe3{"settingTPCCrossedRowsMinHe3", 70, "Minimum crossed TPC rows for He3"}; + Configurable settingTPCNSigmaMaxHe3{"settingTPCNSigmaMaxHe3", 3.f, "Maximum absolute TPC n-sigma for He3"}; + Configurable settingITSNSigmaMinHe3{"settingITSNSigmaMinHe3", -1.5f, "Minimum ITS n-sigma for He3"}; + } helium3Pid; + + struct : o2::framework::ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"tritonPid"}; + // Triton track-quality, purity and PID cuts + Configurable settingPIDMomentumSplitTr{"settingPIDMomentumSplitTr", 2.f, "Momentum separating low- and high-momentum triton TPC PID"}; + Configurable settingCutTPCNsigmaLowPTr{"settingCutTPCNsigmaLowPTr", 3.f, "Maximum absolute TPC n-sigma for tritons below the momentum split"}; + Configurable settingCutITSNsigmaLowPTr{"settingCutITSNsigmaLowPTr", 3.f, "Maximum absolute ITS n-sigma for tritons below the momentum split"}; + Configurable settingCutTPCNsigmaHighPMinTr{"settingCutTPCNsigmaHighPMinTr", -2.f, "Minimum TPC n-sigma for tritons above the momentum split"}; + Configurable settingCutTPCNsigmaHighPMaxTr{"settingCutTPCNsigmaHighPMaxTr", 3.f, "Maximum TPC n-sigma for tritons above the momentum split"}; + Configurable settingTOFMassMomentumMinTr{"settingTOFMassMomentumMinTr", 1.2f, "Minimum momentum to apply the triton TOF mass cut"}; + Configurable settingTOFMassMinTr{"settingTOFMassMinTr", 2.5f, "Minimum triton TOF mass"}; + Configurable settingTOFMassMaxTr{"settingTOFMassMaxTr", 3.4f, "Maximum triton TOF mass"}; + Configurable settingTPCRejectNsig{"settingTPCRejectNsig", 3.f, "Minimum absolute TPC n-sigma from deuteron, proton and pion hypotheses"}; + } tritonPid; + struct : o2::framework::ConfigurableGroup { // cppcheck-suppress unusedStructMember std::string prefix{"CPR"}; @@ -271,8 +302,9 @@ struct HadNucleiFemto { std::string prefix{"output"}; // Output and QA controls Configurable settingFillTable{"settingFillTable", false, "Enable table filling"}; - Configurable settingFillTableLowKstarOnly{"settingFillTableLowKstarOnly", false, "If true, fill the output table only for pion-deuteron pairs below the kstar threshold"}; + Configurable settingFillTableLowKstarOnly{"settingFillTableLowKstarOnly", false, "If true, apply the configured low-kstar threshold to pion-deuteron and pion-triton pairs"}; Configurable settingFillTablePiDeKstarMax{"settingFillTablePiDeKstarMax", 0.1f, "Maximum kstar for pion-deuteron pairs written to the output table"}; + Configurable settingFillTablePiTrKstarMax{"settingFillTablePiTrKstarMax", 0.1f, "Maximum kstar for pion-triton pairs written to the output table"}; Configurable settingFillMultiplicity{"settingFillMultiplicity", false, "Fill multiplicity table"}; Configurable settingUseBBcomputeDeNsigma{"settingUseBBcomputeDeNsigma", false, "Use BB params to compute De TPC Nsigma"}; } output; @@ -363,8 +395,8 @@ struct HadNucleiFemto { {"hHadPin", "P distribution; #it{p} (GeV/#it{c})", {HistType::kTH1F, {{120, -4.0f, 4.0f}}}}, {"hHadEta", "eta distribution; #eta(had)", {HistType::kTH1F, {{200, -1.0f, 1.0f}}}}, {"hHadPhi", "phi distribution; phi(had)", {HistType::kTH1F, {{600, -4.0f, 4.0f}}}}, - {"h2CPRBefore", "Close pair rejection before cut; #Delta#eta; #Delta#phi^{*}", {HistType::kTH2F, {{160, -2.0f, 2.0f}, {160, -3.2f, 3.2f}}}}, - {"h2CPRAfter", "Close pair rejection after cut; #Delta#eta; #Delta#phi^{*}", {HistType::kTH2F, {{160, -2.0f, 2.0f}, {160, -3.2f, 3.2f}}}}, + {"h2CPRBefore", "Close pair rejection before cut; #Delta#eta; #Delta#phi^{*}", {HistType::kTH2F, {{300, -0.15f, 0.15f}, {400, -0.2f, 0.2f}}}}, + {"h2CPRAfter", "Close pair rejection after cut; #Delta#eta; #Delta#phi^{*}", {HistType::kTH2F, {{300, -0.15f, 0.15f}, {400, -0.2f, 0.2f}}}}, // dE/dx {"h2dEdxNucandidates", "dEdx distribution; #it{p} (GeV/#it{c}); dE/dx (a.u.)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {100, 0.0f, 2000.0f}}}}, @@ -380,6 +412,7 @@ struct HadNucleiFemto { {"h2NSigmaNuITS", "NsigmaNu ITS distribution; signed #it{p}_{T} (GeV/#it{c}); n#sigma_{ITS} Nu", {HistType::kTH2F, {{280, -7.0f, 7.0f}, {120, -3.0f, 3.0f}}}}, {"h2NsigmaNuTOF", "NsigmaNu TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(Nu)", {HistType::kTH2F, {{280, -7.0f, 7.0f}, {200, -5.0f, 5.0f}}}}, {"h2NsigmaNuTOF_preselection", "NsigmaNu TOF distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{TOF}(Nu)", {HistType::kTH2F, {{280, -7.0f, 7.0f}, {400, -10.0f, 10.0f}}}}, + {"h2MassTOFTr", "Triton TOF mass; signed #it{p} (GeV/#it{c}); m_{TOF} (GeV/#it{c}^{2})", {HistType::kTH2F, {{240, -6.0f, 6.0f}, {200, 0.0f, 5.0f}}}}, // Hadron PID {"h2NsigmaHadComb", "NsigmaHad TPCTOF comb distribution; #it{p}_{T} (GeV/#it{c}); n#sigma_{comb}(had)", {HistType::kTH2F, {{280, -7.0f, 7.0f}, {100, 0.0f, 5.0f}}}}, @@ -451,12 +484,14 @@ struct HadNucleiFemto { int mat{static_cast(pidCalibration.settingMaterialCorrection)}; mFitter.setMatCorrType(static_cast(mat)); - const int numParticles = 5; - const char* betheBlochLabel = nucleusBetheBlochLabel(); - for (int i = 0; i < numParticles; i++) { - mBBparamsNucleus[i] = pidCalibration.settingBetheBlochParams->get(betheBlochLabel, Form("p%i", i)); + if (!useTritonNucleus()) { + const int numParticles = 5; + const char* betheBlochLabel = nucleusBetheBlochLabel(); + for (int i = 0; i < numParticles; i++) { + mBBparamsNucleus[i] = pidCalibration.settingBetheBlochParams->get(betheBlochLabel, Form("p%i", i)); + } + mBBparamsNucleus[5] = pidCalibration.settingBetheBlochParams->get(betheBlochLabel, "resolution"); } - mBBparamsNucleus[5] = pidCalibration.settingBetheBlochParams->get(betheBlochLabel, "resolution"); std::vector selectionLabels = {"All", "Track selection", "PID"}; for (int i = 0; i < Selections::kAll; i++) { @@ -476,7 +511,7 @@ struct HadNucleiFemto { return; } if (zorro.settingSkimmedProcessing) { - mZorro.initCCDB(mCcdb.service, bc.runNumber(), bc.timestamp(), useHelium3Nucleus() ? "fHe" : "fDe"); + mZorro.initCCDB(mCcdb.service, bc.runNumber(), bc.timestamp(), zorroTriggerMask()); mZorro.populateHistRegistry(mQaRegistry, bc.runNumber()); } mRunNumber = bc.runNumber(); @@ -486,7 +521,7 @@ struct HadNucleiFemto { o2::parameters::GRPMagField* grpmag = nullptr; if (grpo) { o2::base::Propagator::initFieldFromGRP(grpo); - if (ccdb.settingDbz < defaultBzValue) { + if (ccdb.settingDbz <= defaultBzValue) { // Fetch magnetic field from ccdb for current collision mDbz = grpo->getNominalL3Field(); LOG(info) << "Retrieved GRP for timestamp " << run3GrpTimestamp << " with magnetic field of " << mDbz << " kZG"; @@ -499,7 +534,7 @@ struct HadNucleiFemto { LOG(fatal) << "Got nullptr from CCDB for path " << ccdb.settingGrpmagPath << " of object GRPMagField and " << ccdb.settingGrpPath << " of object GRPObject for timestamp " << run3GrpTimestamp; } o2::base::Propagator::initFieldFromGRP(grpmag); - if (ccdb.settingDbz < defaultBzValue) { + if (ccdb.settingDbz <= defaultBzValue) { // Fetch magnetic field from ccdb for current collision mDbz = std::lround(5.f * grpmag->getL3Current() / 30000.f); LOG(info) << "Retrieved GRP for timestamp " << run3GrpTimestamp << " with magnetic field of " << mDbz << " kZG"; @@ -528,10 +563,11 @@ struct HadNucleiFemto { return false; } if (zorro.settingSkimmedProcessing) { - bool zorroSelected = mZorro.isSelected(collision.template bc_as().globalBC()); - if (zorroSelected) { - mQaRegistry.fill(HIST("hEvents"), 2); + const bool zorroSelected = mZorro.isSelected(collision.template bc_as().globalBC()); + if (!zorroSelected) { + return false; } + mQaRegistry.fill(HIST("hEvents"), 2); } } @@ -649,16 +685,51 @@ struct HadNucleiFemto { candidate.itsNClsInnerBarrel() < minITSNClsInnerBarrel); } + template + bool selectTrackTr(const Ttrack& candidate) + { + constexpr float maxAbsEta = 0.8f; + constexpr float maxAbsDcaXY = 0.2f; + constexpr float maxAbsDcaZ = 0.2f; + constexpr int minTPCCrossedRows = 70; + constexpr float maxTPCChi2NCl = 5.f; + constexpr float maxTPCFractionSharedCls = 0.3f; + constexpr int minITSNCls = 5; + constexpr float maxITSChi2NCl = 10.f; + + return !(std::abs(candidate.eta()) >= maxAbsEta || + std::abs(candidate.dcaXY()) >= maxAbsDcaXY || + std::abs(candidate.dcaZ()) >= maxAbsDcaZ || + candidate.tpcNClsCrossedRows() < minTPCCrossedRows || + candidate.tpcChi2NCl() >= maxTPCChi2NCl || + candidate.tpcFractionSharedCls() >= maxTPCFractionSharedCls || + candidate.itsNCls() < minITSNCls || + candidate.itsChi2NCl() >= maxITSChi2NCl); + } + bool useDeuteronNucleus() const { return species.settingNuPDGCode.value == DeuteronPDG; } + bool useTritonNucleus() const + { + return species.settingNuPDGCode.value == TritonPDG; + } + bool useHelium3Nucleus() const { return species.settingNuPDGCode.value == He3PDG; } + const char* zorroTriggerMask() const + { + if (useTritonNucleus()) { + return "fTritonFemto"; + } + return useHelium3Nucleus() ? "fHe" : "fDe"; + } + const char* nucleusBetheBlochLabel() const { return useHelium3Nucleus() ? "He3" : "De"; @@ -674,6 +745,9 @@ struct HadNucleiFemto { if (useHelium3Nucleus()) { return static_cast(o2::constants::physics::MassHelium3); } + if (useTritonNucleus()) { + return static_cast(o2::constants::physics::MassTriton); + } return static_cast(o2::constants::physics::MassDeuteron); } @@ -684,11 +758,10 @@ struct HadNucleiFemto { return false; } - constexpr int minTPCNClsCrossedRows = 70; constexpr float crossedRowsToFindableRatio = 0.8f; return !(candidate.itsNCls() < trackCut.settingCutNCls || - candidate.tpcNClsFound() < He3TPCNClsFoundMin || - candidate.tpcNClsCrossedRows() < minTPCNClsCrossedRows || + candidate.tpcNClsFound() < helium3Pid.settingTPCNClsFoundMinHe3 || + candidate.tpcNClsCrossedRows() < helium3Pid.settingTPCCrossedRowsMinHe3 || candidate.tpcNClsCrossedRows() < crossedRowsToFindableRatio * candidate.tpcNClsFindable() || candidate.tpcChi2NCl() > trackCut.settingCutChi2tpcHigh || candidate.tpcChi2NCl() < He3TPCChi2NClMin || @@ -701,6 +774,9 @@ struct HadNucleiFemto { if (useHelium3Nucleus()) { return selectTrackHe3(candidate); } + if (useTritonNucleus()) { + return selectTrackTr(candidate); + } if (useDeuteronNucleus()) { return selectTrackDe(candidate); } @@ -723,12 +799,23 @@ struct HadNucleiFemto { return species.settingHadPDGCode.value == static_cast(PDG_t::kPiPlus) && useDeuteronNucleus(); } + bool isPionTritonPair() const + { + return species.settingHadPDGCode.value == static_cast(PDG_t::kPiPlus) && useTritonNucleus(); + } + bool shouldFillOutputTable(const HadNucandidate& hadNucand) const { - if (!output.settingFillTableLowKstarOnly.value || !isPionDeuteronPair()) { + if (!output.settingFillTableLowKstarOnly.value) { return true; } - return hadNucand.kstar < output.settingFillTablePiDeKstarMax.value; + if (isPionDeuteronPair()) { + return hadNucand.kstar < output.settingFillTablePiDeKstarMax.value; + } + if (isPionTritonPair()) { + return hadNucand.kstar < output.settingFillTablePiTrKstarMax.value; + } + return true; } template @@ -772,40 +859,62 @@ struct HadNucleiFemto { } template - bool isClosePair(const Ttrack1& firstTrack, const Ttrack2& secondTrack) + bool computeClosePairDeltas(const Ttrack1& firstTrack, const Ttrack2& secondTrack, float& deltaEta, float& deltaPhi) const { constexpr int closePairRadiusModePv = 0; constexpr int closePairRadiusModeSpecificTpc = 2; constexpr float invalidPhiStar = 999.f; + constexpr float invalidOutputDelta = -99.f; + + deltaEta = invalidOutputDelta; + deltaPhi = invalidOutputDelta; if (!CPR.settingEnableClosePairRejection.value) { return false; } - if (firstTrack.sign() != secondTrack.sign()) { + + float selectedDeltaPhi = averagePhiStar(firstTrack, secondTrack); + if (CPR.settingClosePairRadiusMode.value == closePairRadiusModePv) { + selectedDeltaPhi = wrapDeltaPhi(firstTrack.phi() - secondTrack.phi()); + } else if (CPR.settingClosePairRadiusMode.value == closePairRadiusModeSpecificTpc) { + const float firstPhi = phiAtSpecificRadiiTPC(firstTrack, CPR.settingClosePairSpecificRadius.value); + const float secondPhi = phiAtSpecificRadiiTPC(secondTrack, CPR.settingClosePairSpecificRadius.value); + if (firstPhi == invalidPhiStar || secondPhi == invalidPhiStar) { + return false; + } + selectedDeltaPhi = wrapDeltaPhi(firstPhi - secondPhi); + } + + if (selectedDeltaPhi == invalidPhiStar) { return false; } - const float deta = firstTrack.eta() - secondTrack.eta(); - const float dphiAtPV = wrapDeltaPhi(firstTrack.phi() - secondTrack.phi()); - const float dphiAtSpecificRadius = wrapDeltaPhi(phiAtSpecificRadiiTPC(firstTrack, CPR.settingClosePairSpecificRadius.value) - phiAtSpecificRadiiTPC(secondTrack, CPR.settingClosePairSpecificRadius.value)); - const float dphiAvg = averagePhiStar(firstTrack, secondTrack); + deltaEta = firstTrack.eta() - secondTrack.eta(); + deltaPhi = selectedDeltaPhi; + return true; + } - float dphiToCut = dphiAvg; - if (CPR.settingClosePairRadiusMode.value == closePairRadiusModePv) { - dphiToCut = dphiAtPV; - } else if (CPR.settingClosePairRadiusMode.value == closePairRadiusModeSpecificTpc) { - dphiToCut = dphiAtSpecificRadius; + template + bool isClosePair(const Ttrack1& firstTrack, const Ttrack2& secondTrack) + { + if (!CPR.settingEnableClosePairRejection.value) { + return false; + } + if (firstTrack.sign() != secondTrack.sign()) { + return false; } - if (dphiToCut == invalidPhiStar) { + float deltaEta = -99.f; + float deltaPhi = -99.f; + if (!computeClosePairDeltas(firstTrack, secondTrack, deltaEta, deltaPhi)) { return false; } - mQaRegistry.fill(HIST("h2CPRBefore"), deta, dphiToCut); - const bool isRejected = std::pow(dphiToCut, 2.f) / std::pow(CPR.settingClosePairDeltaPhiMax.value, 2.f) + - std::pow(deta, 2.f) / std::pow(CPR.settingClosePairDeltaEtaMax.value, 2.f) < + mQaRegistry.fill(HIST("h2CPRBefore"), deltaEta, deltaPhi); + const bool isRejected = std::pow(deltaPhi, 2.f) / std::pow(CPR.settingClosePairDeltaPhiMax.value, 2.f) + + std::pow(deltaEta, 2.f) / std::pow(CPR.settingClosePairDeltaEtaMax.value, 2.f) < 1.f; if (!isRejected) { - mQaRegistry.fill(HIST("h2CPRAfter"), deta, dphiToCut); + mQaRegistry.fill(HIST("h2CPRAfter"), deltaEta, deltaPhi); } return isRejected; } @@ -989,6 +1098,37 @@ struct HadNucleiFemto { return -10.f; } + template + float getHadronTOFNSigma(const Ttrack& candidate) const + { + if (species.settingHadPDGCode.value == static_cast(PDG_t::kPiPlus)) { + return candidate.tofNSigmaPi(); + } + if (species.settingHadPDGCode.value == static_cast(PDG_t::kKPlus)) { + return candidate.tofNSigmaKa(); + } + if (species.settingHadPDGCode.value == static_cast(PDG_t::kProton)) { + return candidate.tofNSigmaPr(); + } + return -10.f; + } + + template + float getHadronITSNSigma(const Ttrack& candidate) const + { + o2::aod::ITSResponse itsResponse; + if (species.settingHadPDGCode.value == static_cast(PDG_t::kPiPlus)) { + return itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); + } + if (species.settingHadPDGCode.value == static_cast(PDG_t::kKPlus)) { + return itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); + } + if (species.settingHadPDGCode.value == static_cast(PDG_t::kProton)) { + return itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); + } + return -10.f; + } + template float computeNSigmaDe(const Ttrack& candidate) { @@ -1085,20 +1225,20 @@ struct HadNucleiFemto { const float correctedTPCinnerParam = correctedTPCInnerParamHe3(candidate); mQaRegistry.fill(HIST("h2dEdx"), candidate.sign() * correctedTPCinnerParam, candidate.tpcSignal()); - if (correctedTPCinnerParam < He3RigidityMin) { + if (correctedTPCinnerParam < helium3Pid.settingRigidityMinHe3) { return false; } const float nSigmaHe3 = computeNSigmaHe3(candidate); mQaRegistry.fill(HIST("h2NsigmaNuTPC_preselection"), candidate.sign() * 2.f * candidate.pt(), nSigmaHe3); - if (std::abs(nSigmaHe3) > He3TPCNSigmaMax) { + if (std::abs(nSigmaHe3) > helium3Pid.settingTPCNSigmaMaxHe3) { return false; } o2::aod::ITSResponse itsResponse; - const float itsNsigmaHe3 = itsResponse.nSigmaITS(candidate.itsClusterSizes(), 2.f * candidate.p(), candidate.eta()); + const float itsNsigmaHe3 = itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); mQaRegistry.fill(HIST("h2NSigmaNuITS_preselection"), candidate.sign() * 2.f * candidate.pt(), itsNsigmaHe3); - if (itsNsigmaHe3 < He3ITSNSigmaMin) { + if (itsNsigmaHe3 < helium3Pid.settingITSNSigmaMinHe3) { return false; } @@ -1108,12 +1248,71 @@ struct HadNucleiFemto { return true; } + template + float computeTOFMass(const Ttrack& candidate) const + { + if (!candidate.hasTOF()) { + return -1.f; + } + float beta = o2::pid::tof::Beta::GetBeta(candidate); + beta = std::clamp(beta, 1.e-4f, 1.f - 1.e-6f); + return std::abs(candidate.tpcInnerParam()) * std::sqrt(1.f / (beta * beta) - 1.f); + } + + template + bool selectionPIDTr(const Ttrack& candidate) + { + const float tpcNSigmaTr = candidate.tpcNSigmaTr(); + const float absP = std::abs(candidate.p()); + o2::aod::ITSResponse itsResponse; + const float itsNSigmaTr = itsResponse.nSigmaITS(candidate.itsClusterSizes(), absP, candidate.eta()); + + mQaRegistry.fill(HIST("h2dEdx"), candidate.sign() * candidate.tpcInnerParam(), candidate.tpcSignal()); + mQaRegistry.fill(HIST("h2NsigmaNuTPC_preselection"), candidate.sign() * candidate.pt(), tpcNSigmaTr); + mQaRegistry.fill(HIST("h2NSigmaNuITS_preselection"), candidate.sign() * candidate.pt(), itsNSigmaTr); + + if (std::abs(candidate.tpcNSigmaDe()) < tritonPid.settingTPCRejectNsig || + std::abs(candidate.tpcNSigmaPr()) < tritonPid.settingTPCRejectNsig || + std::abs(candidate.tpcNSigmaPi()) < tritonPid.settingTPCRejectNsig) { + return false; + } + + if (absP < tritonPid.settingPIDMomentumSplitTr) { + if (std::abs(tpcNSigmaTr) >= tritonPid.settingCutTPCNsigmaLowPTr || + std::abs(itsNSigmaTr) >= tritonPid.settingCutITSNsigmaLowPTr) { + return false; + } + } else if (tpcNSigmaTr <= tritonPid.settingCutTPCNsigmaHighPMinTr || + tpcNSigmaTr >= tritonPid.settingCutTPCNsigmaHighPMaxTr) { + return false; + } + + if (absP > tritonPid.settingTOFMassMomentumMinTr) { + if (!candidate.hasTOF()) { + return false; + } + const float massTOFTr = computeTOFMass(candidate); + mQaRegistry.fill(HIST("h2MassTOFTr"), candidate.sign() * absP, massTOFTr); + if (massTOFTr <= tritonPid.settingTOFMassMinTr || massTOFTr >= tritonPid.settingTOFMassMaxTr) { + return false; + } + } + + mQaRegistry.fill(HIST("h2dEdxNucandidates"), candidate.sign() * candidate.tpcInnerParam(), candidate.tpcSignal()); + mQaRegistry.fill(HIST("h2NsigmaNuTPC"), candidate.sign() * candidate.pt(), tpcNSigmaTr); + mQaRegistry.fill(HIST("h2NSigmaNuITS"), candidate.sign() * candidate.pt(), itsNSigmaTr); + return true; + } + template bool selectionPIDNu(const Ttrack& candidate) { if (useHelium3Nucleus()) { return selectionPIDHe3(candidate); } + if (useTritonNucleus()) { + return selectionPIDTr(candidate); + } if (useDeuteronNucleus()) { return selectionPIDDe(candidate); } @@ -1126,9 +1325,43 @@ struct HadNucleiFemto { if (useHelium3Nucleus()) { return computeNSigmaHe3(candidate); } + if (useTritonNucleus()) { + return candidate.tpcNSigmaTr(); + } return computeNSigmaDe(candidate); } + template + float getNucleusTOFNSigma(const Ttrack& candidate) const + { + if (useHelium3Nucleus()) { + return candidate.tofNSigmaHe(); + } + if (useTritonNucleus()) { + return candidate.tofNSigmaTr(); + } + if (useDeuteronNucleus()) { + return candidate.tofNSigmaDe(); + } + return -10.f; + } + + template + float getNucleusITSNSigma(const Ttrack& candidate) const + { + o2::aod::ITSResponse itsResponse; + if (useHelium3Nucleus()) { + return itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); + } + if (useTritonNucleus()) { + return itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); + } + if (useDeuteronNucleus()) { + return itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); + } + return -10.f; + } + float averageClusterSizeCosl(uint32_t itsClusterSizes, float eta) { float average = 0; @@ -1256,6 +1489,7 @@ struct HadNucleiFemto { hadNucand.signNu = trackDe.sign(); hadNucand.signHad = trackHad.sign(); + computeClosePairDeltas(trackDe, trackHad, hadNucand.deltaEta, hadNucand.deltaPhi); hadNucand.dcaxyNu = trackDe.dcaXY(); hadNucand.dcaxyHad = trackHad.dcaXY(); @@ -1269,8 +1503,15 @@ struct HadNucleiFemto { hadNucand.momHadTPC = trackHad.tpcInnerParam(); hadNucand.nTPCClustersNu = trackDe.tpcNClsFound(); + hadNucand.nTPCClustersHad = trackHad.tpcNClsFound(); + hadNucand.nTPCCrossedRowsNu = trackDe.tpcNClsCrossedRows(); + hadNucand.nTPCCrossedRowsHad = trackHad.tpcNClsCrossedRows(); hadNucand.nSigmaNu = getNucleusTPCNSigma(trackDe); hadNucand.nSigmaHad = getHadronTPCNSigma(trackHad); + hadNucand.nSigmaTOFNu = getNucleusTOFNSigma(trackDe); + hadNucand.nSigmaITSNu = getNucleusITSNSigma(trackDe); + hadNucand.nSigmaTOFHad = getHadronTOFNSigma(trackHad); + hadNucand.nSigmaITSHad = getHadronITSNSigma(trackHad); hadNucand.nSigmaTPCHadPi = trackHad.tpcNSigmaPi(); hadNucand.nSigmaTPCHadKa = trackHad.tpcNSigmaKa(); hadNucand.nSigmaTPCHadPr = trackHad.tpcNSigmaPr(); @@ -1312,7 +1553,10 @@ struct HadNucleiFemto { hadNucand.massTOFHad = trackHad.tpcInnerParam() * std::sqrt(1.f / (beta * beta) - 1.f); } - const float massLightNucleusForKstarMt = useHelium3Nucleus() ? static_cast(o2::constants::physics::MassHelium3) : (deuteronPid.settingUseProtonMassForKstarMt ? static_cast(o2::constants::physics::MassProton) : static_cast(o2::constants::physics::MassDeuteron)); + float massLightNucleusForKstarMt = nucleusMass(); + if (useDeuteronNucleus() && deuteronPid.settingUseProtonMassForKstarMt) { + massLightNucleusForKstarMt = static_cast(o2::constants::physics::MassProton); + } hadNucand.kstar = computePairKstar(hadNucand.momHad, mMassHad, hadNucand.momNu, massLightNucleusForKstarMt); hadNucand.mT = computePairMT(hadNucand.momHad, mMassHad, hadNucand.momNu, massLightNucleusForKstarMt); @@ -1530,6 +1774,9 @@ struct HadNucleiFemto { hadNucand.tpcSignalHad, hadNucand.momHadTPC, hadNucand.nTPCClustersNu, + hadNucand.nTPCClustersHad, + hadNucand.nTPCCrossedRowsNu, + hadNucand.nTPCCrossedRowsHad, hadNucand.nSigmaNu, hadNucand.nSigmaTPCHadPi, hadNucand.nSigmaTPCHadKa, @@ -1546,7 +1793,14 @@ struct HadNucleiFemto { hadNucand.itsClSizeNu, hadNucand.itsClSizeHad, hadNucand.sharedClustersNu, - hadNucand.sharedClustersHad); + hadNucand.sharedClustersHad, + hadNucand.deltaEta, + hadNucand.deltaPhi, + hadNucand.nSigmaHad, + hadNucand.nSigmaTOFNu, + hadNucand.nSigmaITSNu, + hadNucand.nSigmaTOFHad, + hadNucand.nSigmaITSHad); if (output.settingFillMultiplicity) { mOutputMultiplicityTable( collision.globalIndex(), @@ -1863,8 +2117,14 @@ struct HadNucleiFemto { const float signedPtHe3 = track.sign() * 2.f * track.pt(); mQaRegistry.fill(HIST("purity/h2NsigmaNuTPC_preselection"), signedPtHe3, tpcNSigmaHe3); o2::aod::ITSResponse itsResponse; - const float itsNSigmaHe3 = itsResponse.nSigmaITS(track.itsClusterSizes(), 2.f * track.p(), track.eta()); + const float itsNSigmaHe3 = itsResponse.nSigmaITS(track.itsClusterSizes(), track.p(), track.eta()); mQaRegistry.fill(HIST("purity/h2NSigmaNuITS_preselection"), signedPtHe3, itsNSigmaHe3); + } else if (passTrackNu && useTritonNucleus()) { + const float tpcNSigmaTr = track.tpcNSigmaTr(); + o2::aod::ITSResponse itsResponse; + const float itsNSigmaTr = itsResponse.nSigmaITS(track.itsClusterSizes(), std::abs(track.p()), track.eta()); + mQaRegistry.fill(HIST("purity/h2NsigmaNuTPC_preselection"), track.sign() * track.pt(), tpcNSigmaTr); + mQaRegistry.fill(HIST("purity/h2NSigmaNuITS_preselection"), track.sign() * track.pt(), itsNSigmaTr); } const bool isHadronSelected = passTrackHad && selectionPIDHadron(track); diff --git a/PWGCF/Femto/FemtoNuclei/Tasks/CMakeLists.txt b/PWGCF/Femto/FemtoNuclei/Tasks/CMakeLists.txt new file mode 100644 index 00000000000..9709ae21578 --- /dev/null +++ b/PWGCF/Femto/FemtoNuclei/Tasks/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright 2019-2026 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. + +o2physics_add_dpl_workflow(pi-de-femto-systematics + SOURCES piDeFemtoSystematics.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) diff --git a/PWGCF/Femto/FemtoNuclei/Tasks/piDeFemtoSystematics.cxx b/PWGCF/Femto/FemtoNuclei/Tasks/piDeFemtoSystematics.cxx new file mode 100644 index 00000000000..c12af02d7d2 --- /dev/null +++ b/PWGCF/Femto/FemtoNuclei/Tasks/piDeFemtoSystematics.cxx @@ -0,0 +1,854 @@ +// Copyright 2019-2026 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 piDeFemtoSystematics.cxx +/// \brief Histogram-only pion-deuteron femtoscopy task for train subwagon cut variations +/// +/// The task intentionally produces no derived AOD tables. A train subwagon +/// supplies one complete set of cuts. The default wagon and every systematic +/// subwagon therefore run the same event and pair workflow, while a systematic +/// subwagon changes exactly one configurable cut. + +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseITS.h" +#include "Common/DataModel/PIDResponseTOF.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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +using CollisionsFull = soa::Join; +using TrackCandidates = soa::Join; + +namespace +{ +constexpr std::array BetheBlochDeDefault{-136.71, 0.441, 0.2269, 1.347, 0.8035, 0.09}; +const std::vector betheBlochParticleNames{"De"}; +const std::vector betheBlochParameterNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; +constexpr std::array tpcRadii{{85.f, 105.f, 125.f, 145.f, 165.f, 185.f, 205.f, 225.f, 245.f}}; +constexpr int NumberOfBetheBlochShapeParameters = 5; +constexpr int BetheBlochResolutionIndex = 5; +constexpr double AutomaticMagneticFieldThreshold = -998.; +constexpr float NominalL3Current = 30000.f; +constexpr float InvalidPhiStar = 999.f; +constexpr int ClosePairRadiusModeAtPV = 0; +constexpr int ClosePairRadiusModeAtSpecificRadius = 2; +using PairLorentzVector = ROOT::Math::LorentzVector>; + +enum SelectionStep { + kAllTracks = 0, + kTrackCuts, + kPidCuts, + kNSelectionSteps +}; + +enum PairChannel { + kLikeSignMatter = 0, + kLikeSignAntimatter, + kUnlikeSignMatter, + kUnlikeSignAntimatter, + kNPairChannels +}; +} // namespace + +struct PiDeFemtoSystematics { + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"event"}; + Configurable vertexZMax{"vertexZMax", 10.f, "Maximum absolute collision z vertex"}; + Configurable numberOfMixedEvents{"numberOfMixedEvents", 5, "Number of mixed events per event"}; + } eventCuts; + + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"pion"}; + Configurable ptMin{"ptMin", 0.14f, "Minimum pion pT"}; + Configurable ptMax{"ptMax", 4.0f, "Maximum pion pT"}; + Configurable etaMax{"etaMax", 0.8f, "Maximum absolute pion eta"}; + Configurable itsInnerBarrelClustersMin{"itsInnerBarrelClustersMin", 3, "Minimum pion ITS inner-barrel clusters"}; + Configurable itsClustersMin{"itsClustersMin", 7, "Minimum pion ITS clusters"}; + Configurable tpcClustersMin{"tpcClustersMin", 80, "Minimum pion found TPC clusters"}; + Configurable tpcCrossedRowsMin{"tpcCrossedRowsMin", 90, "Minimum pion crossed TPC rows"}; + Configurable dcaXYOffset{"dcaXYOffset", 0.004f, "Pion DCAxy cut offset"}; + Configurable dcaXYPtCoefficient{"dcaXYPtCoefficient", 0.013f, "Pion DCAxy inverse-pT coefficient"}; + Configurable dcaZOffset{"dcaZOffset", 0.004f, "Pion DCAz cut offset"}; + Configurable dcaZPtCoefficient{"dcaZPtCoefficient", 0.013f, "Pion DCAz inverse-pT coefficient"}; + Configurable combinedPidMomentumMin{"combinedPidMomentumMin", 0.5f, "Momentum above which pion TPC+TOF PID is required"}; + Configurable tpcNsigmaMax{"tpcNsigmaMax", 3.f, "Maximum absolute pion TPC n-sigma below the TOF threshold"}; + Configurable combinedNsigmaMax{"combinedNsigmaMax", 3.f, "Maximum pion combined TPC+TOF n-sigma"}; + } pionCuts; + + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"deuteron"}; + Configurable ptMin{"ptMin", 0.6f, "Minimum deuteron pT"}; + Configurable ptMax{"ptMax", 2.0f, "Maximum deuteron pT"}; + Configurable etaMax{"etaMax", 0.8f, "Maximum absolute deuteron eta"}; + Configurable tpcClustersMin{"tpcClustersMin", 110, "Minimum deuteron found TPC clusters"}; + Configurable tpcCrossedRowsMin{"tpcCrossedRowsMin", 100, "Minimum deuteron crossed TPC rows"}; + Configurable itsClustersMin{"itsClustersMin", 5, "Minimum deuteron ITS clusters"}; + Configurable itsInnerBarrelClustersMin{"itsInnerBarrelClustersMin", 1, "Minimum deuteron ITS inner-barrel clusters"}; + Configurable sharedTPCClustersMax{"sharedTPCClustersMax", 160, "Maximum deuteron shared TPC clusters"}; + Configurable sharedTPCFractionMax{"sharedTPCFractionMax", 1.f, "Maximum deuteron shared TPC-cluster fraction"}; + Configurable tpcInnerParamMin{"tpcInnerParamMin", 0.f, "Minimum deuteron TPC inner parameter"}; + Configurable tofMomentumMin{"tofMomentumMin", 1.2f, "TPC inner parameter above which combined TPC+TOF PID is required"}; + Configurable nsigmaMax{"nsigmaMax", 2.5f, "Common deuteron TPC, ITS and combined PID threshold"}; + Configurable requireIndividualNsigma{"requireIndividualNsigma", false, "Also apply individual TPC and TOF cuts in the combined PID branch"}; + Configurable dcaXYOffset{"dcaXYOffset", 0.004f, "Deuteron DCAxy cut offset"}; + Configurable dcaXYPtCoefficient{"dcaXYPtCoefficient", 0.013f, "Deuteron DCAxy inverse-pT coefficient"}; + Configurable dcaZOffset{"dcaZOffset", 0.004f, "Deuteron DCAz cut offset"}; + Configurable dcaZPtCoefficient{"dcaZPtCoefficient", 0.013f, "Deuteron DCAz inverse-pT coefficient"}; + } deuteronCuts; + + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"pair"}; + Configurable enableClosePairRejection{"enableClosePairRejection", true, "Enable pion-deuteron close-pair rejection"}; + Configurable closePairDeltaEtaMax{"closePairDeltaEtaMax", 0.01f, "CPR ellipse delta-eta radius"}; + Configurable closePairDeltaPhiMax{"closePairDeltaPhiMax", 0.01f, "CPR ellipse delta-phi-star radius"}; + Configurable closePairRadiusMode{"closePairRadiusMode", 1, "CPR mode: 0 PV, 1 average TPC phi-star, 2 one TPC radius"}; + Configurable closePairSpecificRadius{"closePairSpecificRadius", 85.f, "TPC radius in cm for CPR mode 2"}; + } pairCuts; + + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"analysis"}; + Configurable useBetheBlochDeuteronNsigma{"useBetheBlochDeuteronNsigma", false, "Compute deuteron TPC n-sigma from the configured Bethe-Bloch parameters"}; + Configurable lowKstarYieldMax{"lowKstarYieldMax", 0.3f, "Upper kstar used for the SE-yield stability check"}; + } analysisSettings; + + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"zorro"}; + Configurable skimmedProcessing{"skimmedProcessing", false, "Process a Zorro-selected deuteron skim"}; + } zorroSettings; + + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"ccdb"}; + Configurable magneticField{"magneticField", -999., "Magnetic field; -999 reads it from CCDB"}; + Configurable url{"url", "http://alice-ccdb.cern.ch", "CCDB URL"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "GRP object path"}; + Configurable grpMagPath{"grpMagPath", "GLO/Config/GRPMagField", "GRP magnetic-field object path"}; + Configurable materialCorrection{"materialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrNONE), "Material correction used by the optional pair DCA fitter"}; + } ccdbSettings; + + struct : ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"pidCalibration"}; + Configurable> betheBlochParameters{"betheBlochParameters", + {BetheBlochDeDefault.data(), 1, 6, betheBlochParticleNames, betheBlochParameterNames}, + "Deuteron TPC Bethe-Bloch parameters"}; + } pidCalibration; + + ConfigurableAxis mixingVertexAxis{"mixingVertexAxis", {30, -10., 10.}, "Event-mixing z-vertex bins"}; + ConfigurableAxis mixingCentralityAxis{"mixingCentralityAxis", {40, 0., 100.}, "Event-mixing centrality bins"}; + ConfigurableAxis kstarAxis{"kstarAxis", {300, 0., 3.}, "kstar axis"}; + ConfigurableAxis mtAxis{"mtAxis", {240, 0.8, 3.2}, "pair mT axis"}; + ConfigurableAxis centralityAxis{"centralityAxis", {100, 0., 100.}, "centrality axis"}; + + using MixingBinning = ColumnBinningPolicy; + MixingBinning mixingBinning{{mixingVertexAxis, mixingCentralityAxis}, true}; + SliceCache cache; + SameKindPair mixedEventPairs{ + mixingBinning, eventCuts.numberOfMixedEvents, -1, &cache}; + Preslice tracksPerCollision = aod::track::collisionId; + + HistogramRegistry registry{"PiDeFemtoSystematics", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + + Service ccdb{}; + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + o2::vertexing::DCAFitterN<2> pairFitter; + + std::array betheBlochDe{}; + int currentRunNumber{0}; + float magneticField{0.f}; + + void init(InitContext const&) + { + const AxisSpec channelAxis{kNPairChannels, -0.5, static_cast(kNPairChannels) - 0.5, "pair channel"}; + registry.add("Pairs/hSE", "Same-event pion-deuteron pairs", HistType::kTHnSparseF, + {kstarAxis, mtAxis, centralityAxis, channelAxis}); + registry.add("Pairs/hME", "Mixed-event pion-deuteron pairs", HistType::kTHnSparseF, + {kstarAxis, mtAxis, centralityAxis, channelAxis}); + registry.add("Pairs/hSELowKstarYield", "SE low-kstar yield;pair channel;Entries", + HistType::kTH1F, {channelAxis}); + registry.add("Pairs/hMELowKstarYield", "ME low-kstar yield;pair channel;Entries", + HistType::kTH1F, {channelAxis}); + registry.add("Pairs/hCPRBefore", "CPR before selection;#Delta#eta;#Delta#varphi^{*}", + HistType::kTH2F, {{300, -0.15, 0.15}, {400, -0.2, 0.2}}); + registry.add("Pairs/hCPRAfter", "CPR after selection;#Delta#eta;#Delta#varphi^{*}", + HistType::kTH2F, {{300, -0.15, 0.15}, {400, -0.2, 0.2}}); + registry.add("Event/hCounter", "Event selection;step;Entries", + HistType::kTH1F, {{3, -0.5, 2.5}}); + registry.add("Event/hVertexZ", "Selected collision vertex;z (cm);Entries", + HistType::kTH1F, {{200, -20., 20.}}); + registry.add("Event/hCentrality", "Selected collision centrality;FT0C percentile;Entries", + HistType::kTH1F, {{100, 0., 100.}}); + registry.add("Pion/hSelection", "Pion selection;step;Entries", + HistType::kTH1F, {{kNSelectionSteps, -0.5, static_cast(kNSelectionSteps) - 0.5}}); + registry.add("Pion/hPt", "Selected pions;signed p_{T} (GeV/#it{c});Entries", + HistType::kTH1F, {{400, -5., 5.}}); + registry.add("Pion/hEta", "Selected pions;#eta;Entries", + HistType::kTH1F, {{200, -1., 1.}}); + registry.add("Pion/hTPCNsigma", "Selected pions;signed p_{T} (GeV/#it{c});n#sigma_{TPC}", + HistType::kTH2F, {{400, -5., 5.}, {200, -5., 5.}}); + registry.add("Pion/hTOFNsigma", "Selected pions;signed p_{T} (GeV/#it{c});n#sigma_{TOF}", + HistType::kTH2F, {{280, -7., 7.}, {200, -5., 5.}}); + registry.add("Pion/hITSNsigma", "Selected pions;signed p_{T} (GeV/#it{c});n#sigma_{ITS}", + HistType::kTH2F, {{280, -7., 7.}, {120, -3., 3.}}); + registry.add("Pion/hTPCTOFNsigma", "Selected pions;signed p_{T} (GeV/#it{c});n#sigma_{TPC+TOF}", + HistType::kTH2F, {{280, -7., 7.}, {100, 0., 5.}}); + registry.add("Deuteron/hSelection", "Deuteron selection;step;Entries", + HistType::kTH1F, {{kNSelectionSteps, -0.5, static_cast(kNSelectionSteps) - 0.5}}); + registry.add("Deuteron/hPt", "Selected deuterons;signed p_{T} (GeV/#it{c});Entries", + HistType::kTH1F, {{400, -5., 5.}}); + registry.add("Deuteron/hEta", "Selected deuterons;#eta;Entries", + HistType::kTH1F, {{200, -1., 1.}}); + registry.add("Deuteron/hTPCNsigma", "Selected deuterons;signed p_{T} (GeV/#it{c});n#sigma_{TPC}", + HistType::kTH2F, {{400, -5., 5.}, {200, -5., 5.}}); + registry.add("Deuteron/hTOFNsigma", "Selected deuterons;signed p_{T} (GeV/#it{c});n#sigma_{TOF}", + HistType::kTH2F, {{280, -7., 7.}, {200, -5., 5.}}); + registry.add("Deuteron/hITSNsigma", "Selected deuterons;signed p_{T} (GeV/#it{c});n#sigma_{ITS}", + HistType::kTH2F, {{280, -7., 7.}, {120, -3., 3.}}); + registry.add("Deuteron/hTPCTOFNsigma", "Selected deuterons;signed p_{T} (GeV/#it{c});n#sigma_{TPC+TOF}", + HistType::kTH2F, {{280, -7., 7.}, {100, 0., 5.}}); + registry.add("Deuteron/hTPCClusters", "Selected deuterons;TPC clusters;Entries", + HistType::kTH1F, {{161, -0.5, 160.5}}); + registry.add("Deuteron/hTPCCrossedRows", "Selected deuterons;TPC crossed rows;Entries", + HistType::kTH1F, {{161, -0.5, 160.5}}); + + addCutConfigurationHistogram(); + setAxisLabels(); + + zorroSummary.setObject(zorro.getZorroSummary()); + ccdb->setURL(ccdbSettings.url.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + pairFitter.setPropagateToPCA(true); + pairFitter.setMaxR(200.); + pairFitter.setMinParamChange(1.e-3); + pairFitter.setMinRelChi2Change(0.9); + pairFitter.setMaxDZIni(1.e9); + pairFitter.setMaxChi2(1.e9); + pairFitter.setUseAbsDCA(true); + pairFitter.setMatCorrType( + static_cast(ccdbSettings.materialCorrection.value)); + + for (int i = 0; i < NumberOfBetheBlochShapeParameters; ++i) { + betheBlochDe[i] = pidCalibration.betheBlochParameters->get("De", Form("p%i", i)); + } + betheBlochDe[BetheBlochResolutionIndex] = pidCalibration.betheBlochParameters->get("De", "resolution"); + } + + void setAxisLabels() + { + const std::array channelLabels{ + "LS matter", "LS antimatter", "US matter", "US antimatter"}; + const auto setSparseChannelLabels = [&channelLabels](THnSparse* histogram) { + for (int channel = 0; channel < kNPairChannels; ++channel) { + histogram->GetAxis(3)->SetBinLabel(channel + 1, channelLabels[channel]); + } + }; + setSparseChannelLabels(registry.get(HIST("Pairs/hSE")).get()); + setSparseChannelLabels(registry.get(HIST("Pairs/hME")).get()); + + const auto setYieldChannelLabels = [&channelLabels](TH1* histogram) { + for (int channel = 0; channel < kNPairChannels; ++channel) { + histogram->GetXaxis()->SetBinLabel(channel + 1, channelLabels[channel]); + } + }; + setYieldChannelLabels(registry.get(HIST("Pairs/hSELowKstarYield")).get()); + setYieldChannelLabels(registry.get(HIST("Pairs/hMELowKstarYield")).get()); + + const std::array selectionLabels{"all", "track cuts", "PID"}; + const auto setSelectionLabels = [&selectionLabels](TH1* histogram) { + for (int step = 0; step < kNSelectionSteps; ++step) { + histogram->GetXaxis()->SetBinLabel(step + 1, selectionLabels[step]); + } + }; + setSelectionLabels(registry.get(HIST("Pion/hSelection")).get()); + setSelectionLabels(registry.get(HIST("Deuteron/hSelection")).get()); + auto eventCounter = registry.get(HIST("Event/hCounter")); + eventCounter->GetXaxis()->SetBinLabel(1, "all"); + eventCounter->GetXaxis()->SetBinLabel(2, "sel8 and vertex"); + eventCounter->GetXaxis()->SetBinLabel(3, "Zorro"); + } + + void addCutConfigurationHistogram() + { + const std::vector> cuts{ + {"pionPtMin", pionCuts.ptMin.value}, + {"pionPtMax", pionCuts.ptMax.value}, + {"pionEtaMax", pionCuts.etaMax.value}, + {"pionITSInnerBarrelClustersMin", pionCuts.itsInnerBarrelClustersMin.value}, + {"pionITSClustersMin", pionCuts.itsClustersMin.value}, + {"pionTPCClustersMin", pionCuts.tpcClustersMin.value}, + {"pionTPCCrossedRowsMin", pionCuts.tpcCrossedRowsMin.value}, + {"pionDCAxyOffset", pionCuts.dcaXYOffset.value}, + {"pionDCAxyPtCoefficient", pionCuts.dcaXYPtCoefficient.value}, + {"pionDCAzOffset", pionCuts.dcaZOffset.value}, + {"pionDCAzPtCoefficient", pionCuts.dcaZPtCoefficient.value}, + {"pionCombinedPidMomentumMin", pionCuts.combinedPidMomentumMin.value}, + {"pionTPCNsigmaMax", pionCuts.tpcNsigmaMax.value}, + {"pionCombinedNsigmaMax", pionCuts.combinedNsigmaMax.value}, + {"deuteronPtMin", deuteronCuts.ptMin.value}, + {"deuteronPtMax", deuteronCuts.ptMax.value}, + {"deuteronEtaMax", deuteronCuts.etaMax.value}, + {"deuteronTPCClustersMin", deuteronCuts.tpcClustersMin.value}, + {"deuteronTPCCrossedRowsMin", deuteronCuts.tpcCrossedRowsMin.value}, + {"deuteronITSClustersMin", deuteronCuts.itsClustersMin.value}, + {"deuteronITSInnerBarrelClustersMin", deuteronCuts.itsInnerBarrelClustersMin.value}, + {"deuteronSharedTPCClustersMax", deuteronCuts.sharedTPCClustersMax.value}, + {"deuteronSharedTPCFractionMax", deuteronCuts.sharedTPCFractionMax.value}, + {"deuteronTPCInnerParamMin", deuteronCuts.tpcInnerParamMin.value}, + {"deuteronTOFMomentumMin", deuteronCuts.tofMomentumMin.value}, + {"deuteronNsigmaMax", deuteronCuts.nsigmaMax.value}, + {"requireIndividualNsigma", deuteronCuts.requireIndividualNsigma.value}, + {"deuteronDCAxyOffset", deuteronCuts.dcaXYOffset.value}, + {"deuteronDCAxyPtCoefficient", deuteronCuts.dcaXYPtCoefficient.value}, + {"deuteronDCAzOffset", deuteronCuts.dcaZOffset.value}, + {"deuteronDCAzPtCoefficient", deuteronCuts.dcaZPtCoefficient.value}, + {"enableCPR", pairCuts.enableClosePairRejection.value}, + {"cprDeltaEtaMax", pairCuts.closePairDeltaEtaMax.value}, + {"cprDeltaPhiMax", pairCuts.closePairDeltaPhiMax.value}, + {"cprRadiusMode", pairCuts.closePairRadiusMode.value}, + {"cprSpecificRadius", pairCuts.closePairSpecificRadius.value}, + {"useBetheBlochDeuteronNsigma", analysisSettings.useBetheBlochDeuteronNsigma.value}, + {"skimmedProcessing", zorroSettings.skimmedProcessing.value}, + {"vertexZMax", eventCuts.vertexZMax.value}, + {"numberOfMixedEvents", eventCuts.numberOfMixedEvents.value}}; + + const AxisSpec cutAxis{static_cast(cuts.size()), -0.5, + static_cast(cuts.size()) - 0.5, "cut"}; + registry.add("Config/hCutValues", "Configured cut values;cut;value", + HistType::kTH1D, {cutAxis}); + auto histogram = registry.get(HIST("Config/hCutValues")); + for (std::size_t index = 0; index < cuts.size(); ++index) { + histogram->GetXaxis()->SetBinLabel(static_cast(index) + 1, cuts[index].first.c_str()); + histogram->SetBinContent(static_cast(index) + 1, cuts[index].second); + } + } + + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) + { + if (currentRunNumber == bc.runNumber()) { + return; + } + if (zorroSettings.skimmedProcessing.value) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fDe"); + zorro.populateHistRegistry(registry, bc.runNumber()); + } + + auto* grp = ccdb->getForTimeStamp( + ccdbSettings.grpPath.value, bc.timestamp()); + if (grp) { + o2::base::Propagator::initFieldFromGRP(grp); + magneticField = ccdbSettings.magneticField.value < AutomaticMagneticFieldThreshold ? grp->getNominalL3Field() + : ccdbSettings.magneticField.value; + } else { + auto* grpMag = ccdb->getForTimeStamp( + ccdbSettings.grpMagPath.value, bc.timestamp()); + if (!grpMag) { + LOG(fatal) << "Could not load magnetic field from " << ccdbSettings.grpPath.value + << " or " << ccdbSettings.grpMagPath.value; + } + o2::base::Propagator::initFieldFromGRP(grpMag); + magneticField = ccdbSettings.magneticField.value < AutomaticMagneticFieldThreshold + ? std::lround(5.f * grpMag->getL3Current() / NominalL3Current) + : ccdbSettings.magneticField.value; + } + currentRunNumber = bc.runNumber(); + } + + template + bool isCollisionSelected(Collision const& collision, bool fillQA) + { + if (fillQA) { + registry.fill(HIST("Event/hCounter"), 0.); + } + auto bc = collision.template bc_as(); + initCCDB(bc); + if (!collision.sel8() || std::abs(collision.posZ()) > eventCuts.vertexZMax.value) { + return false; + } + if (zorroSettings.skimmedProcessing.value) { + if (!zorro.isSelected(bc.globalBC())) { + return false; + } + if (fillQA) { + registry.fill(HIST("Event/hCounter"), 2.); + } + } + if (fillQA) { + registry.fill(HIST("Event/hCounter"), 1.); + registry.fill(HIST("Event/hVertexZ"), collision.posZ()); + registry.fill(HIST("Event/hCentrality"), collision.centFT0C()); + } + return true; + } + + template + bool passPionTrackCuts(Track const& track) const + { + const float absPt = std::abs(track.pt()); + if (absPt <= 0.f || absPt < pionCuts.ptMin.value || absPt > pionCuts.ptMax.value || + std::abs(track.eta()) > pionCuts.etaMax.value) { + return false; + } + if (track.itsNClsInnerBarrel() < pionCuts.itsInnerBarrelClustersMin.value || + track.itsNCls() < pionCuts.itsClustersMin.value || + track.tpcNClsFound() < pionCuts.tpcClustersMin.value || + track.tpcNClsCrossedRows() < pionCuts.tpcCrossedRowsMin.value) { + return false; + } + const float dcaXYMax = pionCuts.dcaXYOffset.value + + pionCuts.dcaXYPtCoefficient.value / absPt; + const float dcaZMax = pionCuts.dcaZOffset.value + + pionCuts.dcaZPtCoefficient.value / absPt; + return std::abs(track.dcaXY()) <= dcaXYMax && + std::abs(track.dcaZ()) <= dcaZMax; + } + + template + bool passPionPID(Track const& track) const + { + const float tpcNsigma = track.tpcNSigmaPi(); + if (std::abs(track.p()) <= pionCuts.combinedPidMomentumMin.value) { + return std::abs(tpcNsigma) <= pionCuts.tpcNsigmaMax.value; + } + if (!track.hasTOF()) { + return false; + } + const float tofNsigma = track.tofNSigmaPi(); + if (std::hypot(tpcNsigma, tofNsigma) > + pionCuts.combinedNsigmaMax.value) { + return false; + } + return !deuteronCuts.requireIndividualNsigma.value || + (std::abs(tpcNsigma) <= pionCuts.combinedNsigmaMax.value && + std::abs(tofNsigma) <= pionCuts.combinedNsigmaMax.value); + } + + template + bool passDeuteronTrackCuts(Track const& track) const + { + const float absPt = std::abs(track.pt()); + if (absPt <= 0.f || absPt < deuteronCuts.ptMin.value || + absPt > deuteronCuts.ptMax.value || + std::abs(track.eta()) > deuteronCuts.etaMax.value) { + return false; + } + if (track.tpcNClsFound() < deuteronCuts.tpcClustersMin.value || + track.tpcNClsCrossedRows() < deuteronCuts.tpcCrossedRowsMin.value || + track.tpcNClsShared() > deuteronCuts.sharedTPCClustersMax.value || + track.tpcFractionSharedCls() > deuteronCuts.sharedTPCFractionMax.value || + track.itsNCls() < deuteronCuts.itsClustersMin.value || + track.itsNClsInnerBarrel() < deuteronCuts.itsInnerBarrelClustersMin.value) { + return false; + } + const float dcaXYMax = deuteronCuts.dcaXYOffset.value + + deuteronCuts.dcaXYPtCoefficient.value / absPt; + const float dcaZMax = deuteronCuts.dcaZOffset.value + + deuteronCuts.dcaZPtCoefficient.value / absPt; + return std::abs(track.dcaXY()) <= dcaXYMax && + std::abs(track.dcaZ()) <= dcaZMax; + } + + template + float deuteronTPCNsigma(Track const& track) const + { + if (!analysisSettings.useBetheBlochDeuteronNsigma.value) { + return track.tpcNSigmaDe(); + } + const float expected = o2::common::BetheBlochAleph( + static_cast(track.tpcInnerParam() / + o2::constants::physics::MassDeuteron), + betheBlochDe[0], betheBlochDe[1], betheBlochDe[2], + betheBlochDe[3], betheBlochDe[4]); + return static_cast((track.tpcSignal() - expected) / + (expected * betheBlochDe[BetheBlochResolutionIndex])); + } + + template + bool passDeuteronPID(Track const& track) const + { + const float tpcInnerParam = track.tpcInnerParam(); + if (std::abs(tpcInnerParam) < deuteronCuts.tpcInnerParamMin.value) { + return false; + } + const float tpcNsigma = deuteronTPCNsigma(track); + if (track.hasTOF() && + tpcInnerParam > deuteronCuts.tofMomentumMin.value) { + const float tofNsigma = track.tofNSigmaDe(); + if (std::hypot(tpcNsigma, tofNsigma) > deuteronCuts.nsigmaMax.value) { + return false; + } + return !deuteronCuts.requireIndividualNsigma.value || + (std::abs(tpcNsigma) <= deuteronCuts.nsigmaMax.value && + std::abs(tofNsigma) <= deuteronCuts.nsigmaMax.value); + } + if (tpcInnerParam <= deuteronCuts.tofMomentumMin.value) { + if (std::abs(tpcNsigma) > deuteronCuts.nsigmaMax.value) { + return false; + } + o2::aod::ITSResponse itsResponse; + const float itsNsigma = + itsResponse.nSigmaITS( + track.itsClusterSizes(), track.p(), track.eta()); + return std::abs(itsNsigma) <= deuteronCuts.nsigmaMax.value; + } + return false; + } + + template + void fillSingleParticleQA(Tracks const& tracks) + { + for (auto const& track : tracks) { + registry.fill(HIST("Pion/hSelection"), static_cast(kAllTracks)); + if (passPionTrackCuts(track)) { + registry.fill(HIST("Pion/hSelection"), static_cast(kTrackCuts)); + if (passPionPID(track)) { + registry.fill(HIST("Pion/hSelection"), static_cast(kPidCuts)); + const float signedPt = track.sign() * track.pt(); + const float tpcNsigma = track.tpcNSigmaPi(); + registry.fill(HIST("Pion/hPt"), signedPt); + registry.fill(HIST("Pion/hEta"), track.eta()); + registry.fill(HIST("Pion/hTPCNsigma"), signedPt, tpcNsigma); + o2::aod::ITSResponse itsResponse; + const float itsNsigma = itsResponse.nSigmaITS( + track.itsClusterSizes(), track.p(), track.eta()); + registry.fill(HIST("Pion/hITSNsigma"), signedPt, itsNsigma); + if (track.hasTOF() && + std::abs(track.p()) > pionCuts.combinedPidMomentumMin.value) { + const float tofNsigma = track.tofNSigmaPi(); + registry.fill(HIST("Pion/hTOFNsigma"), signedPt, tofNsigma); + registry.fill(HIST("Pion/hTPCTOFNsigma"), signedPt, + std::hypot(tpcNsigma, tofNsigma)); + } + } + } + + registry.fill(HIST("Deuteron/hSelection"), + static_cast(kAllTracks)); + if (passDeuteronTrackCuts(track)) { + registry.fill(HIST("Deuteron/hSelection"), + static_cast(kTrackCuts)); + if (passDeuteronPID(track)) { + registry.fill(HIST("Deuteron/hSelection"), + static_cast(kPidCuts)); + const float signedPt = track.sign() * track.pt(); + const float tpcNsigma = deuteronTPCNsigma(track); + registry.fill(HIST("Deuteron/hPt"), signedPt); + registry.fill(HIST("Deuteron/hEta"), track.eta()); + registry.fill(HIST("Deuteron/hTPCNsigma"), signedPt, tpcNsigma); + if (track.tpcInnerParam() <= deuteronCuts.tofMomentumMin.value) { + o2::aod::ITSResponse itsResponse; + const float itsNsigma = + itsResponse.nSigmaITS( + track.itsClusterSizes(), track.p(), track.eta()); + registry.fill(HIST("Deuteron/hITSNsigma"), signedPt, itsNsigma); + } else if (track.hasTOF()) { + const float tofNsigma = track.tofNSigmaDe(); + registry.fill(HIST("Deuteron/hTOFNsigma"), signedPt, tofNsigma); + registry.fill(HIST("Deuteron/hTPCTOFNsigma"), signedPt, + std::hypot(tpcNsigma, tofNsigma)); + } + registry.fill(HIST("Deuteron/hTPCClusters"), + static_cast(track.tpcNClsFound())); + registry.fill(HIST("Deuteron/hTPCCrossedRows"), + static_cast(track.tpcNClsCrossedRows())); + } + } + } + } + + template + float phiAtRadius(Track const& track, float radius) const + { + const float absPt = std::abs(track.pt()); + if (absPt <= 0.f) { + return InvalidPhiStar; + } + const float argument = + 0.3f * static_cast(track.sign()) * 0.1f * magneticField * + radius * 0.01f / (2.f * absPt); + if (std::abs(argument) >= 1.f) { + return InvalidPhiStar; + } + return track.phi() - std::asin(argument); + } + + static float wrapDeltaPhi(float deltaPhi) + { + return std::atan2(std::sin(deltaPhi), std::cos(deltaPhi)); + } + + template + float averagePhiStar(FirstTrack const& first, + SecondTrack const& second) const + { + float sum = 0.f; + int entries = 0; + for (const auto& radius : tpcRadii) { + const float firstPhi = phiAtRadius(first, radius); + const float secondPhi = phiAtRadius(second, radius); + if (firstPhi == InvalidPhiStar || secondPhi == InvalidPhiStar) { + continue; + } + sum += wrapDeltaPhi(firstPhi - secondPhi); + ++entries; + } + return entries > 0 ? sum / static_cast(entries) : InvalidPhiStar; + } + + template + bool isClosePair(FirstTrack const& first, SecondTrack const& second, + bool fillQA) + { + if (!pairCuts.enableClosePairRejection.value || + first.sign() != second.sign()) { + return false; + } + const float deltaEta = first.eta() - second.eta(); + float deltaPhi = averagePhiStar(first, second); + if (pairCuts.closePairRadiusMode.value == ClosePairRadiusModeAtPV) { + deltaPhi = wrapDeltaPhi(first.phi() - second.phi()); + } else if (pairCuts.closePairRadiusMode.value == ClosePairRadiusModeAtSpecificRadius) { + const float firstPhi = + phiAtRadius(first, pairCuts.closePairSpecificRadius.value); + const float secondPhi = + phiAtRadius(second, pairCuts.closePairSpecificRadius.value); + if (firstPhi == InvalidPhiStar || secondPhi == InvalidPhiStar) { + return false; + } + deltaPhi = wrapDeltaPhi(firstPhi - secondPhi); + } + if (deltaPhi == InvalidPhiStar || + pairCuts.closePairDeltaEtaMax.value <= 0.f || + pairCuts.closePairDeltaPhiMax.value <= 0.f) { + return false; + } + if (fillQA) { + registry.fill(HIST("Pairs/hCPRBefore"), deltaEta, deltaPhi); + } + const bool rejected = + deltaEta * deltaEta / + (pairCuts.closePairDeltaEtaMax.value * pairCuts.closePairDeltaEtaMax.value) + + deltaPhi * deltaPhi / + (pairCuts.closePairDeltaPhiMax.value * pairCuts.closePairDeltaPhiMax.value) < + 1.f; + if (fillQA && !rejected) { + registry.fill(HIST("Pairs/hCPRAfter"), deltaEta, deltaPhi); + } + return rejected; + } + + template + bool hasValidPairFit(FirstTrack const& first, SecondTrack const& second) + { + try { + return pairFitter.process(getTrackParCov(first), + getTrackParCov(second)) > 0; + } catch (...) { + return false; + } + } + + float pairKstar(std::array const& pionMomentum, + std::array const& deuteronMomentum) const + { + const PairLorentzVector pion( + pionMomentum[0], pionMomentum[1], pionMomentum[2], + o2::constants::physics::MassPiPlus); + const PairLorentzVector deuteron( + deuteronMomentum[0], deuteronMomentum[1], deuteronMomentum[2], + o2::constants::physics::MassDeuteron); + const PairLorentzVector pair = pion + deuteron; + const float beta = pair.Beta(); + const ROOT::Math::Boost boost( + -beta * std::cos(pair.Phi()) * std::sin(pair.Theta()), + -beta * std::sin(pair.Phi()) * std::sin(pair.Theta()), + -beta * std::cos(pair.Theta())); + const PairLorentzVector relativeMomentum = + boost(pion) - boost(deuteron); + return 0.5f * relativeMomentum.P(); + } + + float pairMT(std::array const& pionMomentum, + std::array const& deuteronMomentum) const + { + const PairLorentzVector pion( + pionMomentum[0], pionMomentum[1], pionMomentum[2], + o2::constants::physics::MassPiPlus); + const PairLorentzVector deuteron( + deuteronMomentum[0], deuteronMomentum[1], deuteronMomentum[2], + o2::constants::physics::MassDeuteron); + const float kT = 0.5f * (pion + deuteron).Pt(); + const float averageMass = + 0.5f * (o2::constants::physics::MassPiPlus + + o2::constants::physics::MassDeuteron); + return std::hypot(kT, averageMass); + } + + static int pairChannel(int deuteronSign, int pionSign) + { + const bool unlikeSign = deuteronSign * pionSign < 0; + const bool antimatter = deuteronSign < 0; + return 2 * static_cast(unlikeSign) + + static_cast(antimatter); + } + + template + void fillPair(DeuteronTrack const& deuteron, PionTrack const& pion, + float centrality, bool mixedEvent) + { + const std::array deuteronMomentum{ + deuteron.px(), deuteron.py(), deuteron.pz()}; + const std::array pionMomentum{ + pion.px(), pion.py(), pion.pz()}; + const float kstar = pairKstar(pionMomentum, deuteronMomentum); + const float mt = pairMT(pionMomentum, deuteronMomentum); + const auto channel = static_cast( + pairChannel(deuteron.sign(), pion.sign())); + if (mixedEvent) { + registry.fill(HIST("Pairs/hME"), kstar, mt, centrality, channel); + if (kstar < analysisSettings.lowKstarYieldMax.value) { + registry.fill(HIST("Pairs/hMELowKstarYield"), channel); + } + } else { + registry.fill(HIST("Pairs/hSE"), kstar, mt, centrality, channel); + if (kstar < analysisSettings.lowKstarYieldMax.value) { + registry.fill(HIST("Pairs/hSELowKstarYield"), channel); + } + } + } + + template + void buildPairs(DeuteronTracks const& deuteronTracks, + PionTracks const& pionTracks, float centrality, + bool mixedEvent) + { + for (auto const& deuteron : deuteronTracks) { + if (!passDeuteronTrackCuts(deuteron) || + !passDeuteronPID(deuteron)) { + continue; + } + for (auto const& pion : pionTracks) { + if (!mixedEvent && deuteron.globalIndex() == pion.globalIndex()) { + continue; + } + if (!passPionTrackCuts(pion) || !passPionPID(pion)) { + continue; + } + if (isClosePair(deuteron, pion, !mixedEvent)) { + continue; + } + if (!mixedEvent && !hasValidPairFit(deuteron, pion)) { + continue; + } + fillPair(deuteron, pion, centrality, mixedEvent); + } + } + } + + void processSameEvent(CollisionsFull const& collisions, + TrackCandidates const& tracks, + aod::BCsWithTimestamps const&) + { + for (auto const& collision : collisions) { + if (!isCollisionSelected(collision, true)) { + continue; + } + auto collisionTracks = + tracks.sliceBy(tracksPerCollision, collision.globalIndex()); + collisionTracks.bindExternalIndices(&tracks); + fillSingleParticleQA(collisionTracks); + buildPairs(collisionTracks, collisionTracks, + collision.centFT0C(), false); + } + } + PROCESS_SWITCH(PiDeFemtoSystematics, processSameEvent, + "Fill same-event pion-deuteron pairs", true); + + void processMixedEvent(CollisionsFull const& /*collisions*/, + TrackCandidates const& /*tracks*/, + aod::BCsWithTimestamps const&) + { + for (auto const& [collision1, tracks1, collision2, tracks2] : + mixedEventPairs) { + if (!collision1.sel8() || !collision2.sel8()) { + continue; + } + auto bc1 = collision1.template bc_as(); + auto bc2 = collision2.template bc_as(); + initCCDB(bc1); + buildPairs(tracks1, tracks2, collision1.centFT0C(), true); + initCCDB(bc2); + buildPairs(tracks2, tracks1, collision2.centFT0C(), true); + } + } + PROCESS_SWITCH(PiDeFemtoSystematics, processMixedEvent, + "Fill mixed-event pion-deuteron pairs", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} From 6f14fea663f25d61d6cbe2275523dc644494342b Mon Sep 17 00:00:00 2001 From: Maximiliano Puccio Date: Thu, 30 Jul 2026 19:57:24 +0200 Subject: [PATCH 52/71] [PWGLF] Fix filling H3L absorption point (#17268) --- PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx index 6a26cbef2b4..b5dc7ca67f2 100644 --- a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx @@ -964,23 +964,26 @@ struct hyperRecoTask { // now we fill only the signal candidates that were not reconstructed for (const auto& mcPart : particlesMC) { - if (std::abs(mcPart.pdgCode()) != hyperPdg) + if (std::abs(mcPart.pdgCode()) != hyperPdg) { continue; - std::array secVtx; + } + std::array secVtx{0.f, 0.f, 0.f}; + std::array lastDaugVtx{0.f, 0.f, 0.f}; std::array primVtx = {mcPart.vx(), mcPart.vy(), mcPart.vz()}; std::array momMother = {mcPart.px(), mcPart.py(), mcPart.pz()}; - std::array momHe3; + std::array momHe3{0.f, 0.f, 0.f}; bool isHeFound = false; int mcProcess = {0}; for (const auto& mcDaught : mcPart.daughters_as()) { + if (mcDaught.pdgCode() != PDG_t::kElectron) { // we do not care about delta electrons + lastDaugVtx = {mcDaught.vx(), mcDaught.vy(), mcDaught.vz()}; + mcProcess = mcDaught.getProcess(); + } if (std::abs(mcDaught.pdgCode()) == heDauPdg) { - secVtx = {mcDaught.vx(), mcDaught.vy(), mcDaught.vz()}; + secVtx = lastDaugVtx; momHe3 = {mcDaught.px(), mcDaught.py(), mcDaught.pz()}; isHeFound = true; } - if (mcDaught.pdgCode() != PDG_t::kElectron) { // we do not care about delta electrons - mcProcess = mcDaught.getProcess(); - } } if (mcPart.pdgCode() > 0) { hIsMatterGen->Fill(0.); @@ -1005,7 +1008,7 @@ struct hyperRecoTask { hypCand.isSurvEvSelection = isSurvEvSelCollision[mcPart.mcCollisionId()]; int chargeFactor = -1 + 2 * (hypCand.pdgCode > 0); for (int i = 0; i < 3; i++) { - hypCand.gDecVtx[i] = secVtx[i] - primVtx[i]; + hypCand.gDecVtx[i] = (isHeFound ? secVtx[i] : lastDaugVtx[i]) - primVtx[i]; hypCand.gMom[i] = momMother[i]; hypCand.gMomHe3[i] = momHe3[i]; } From 8b434a492d34dbfe68dbb26bd2e39047c7f56cc0 Mon Sep 17 00:00:00 2001 From: Gyula Bencedi Date: Thu, 30 Jul 2026 22:17:59 +0200 Subject: [PATCH 53/71] [PWGLF] Add custom DCA selection + fix track selection in MC (#17270) --- .../GlobalEventProperties/flattenictyPikp.cxx | 748 +++++++++--------- 1 file changed, 386 insertions(+), 362 deletions(-) diff --git a/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx b/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx index e4cbd6bcd3f..40577807823 100644 --- a/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx +++ b/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx @@ -184,11 +184,11 @@ enum TrkSel { trkSelEta, trkSelPt, trkSelDCA, + trkSelCustomDCA, trkNRowsTPC, trkSelNClsFound, trkSelNClsPID, trkSelTPCBndr, - trkSelCustomDCA, nTrkSel }; @@ -240,51 +240,56 @@ struct FlattenictyPikp { int runNumber{-1}; o2::parameters::GRPMagField* grpmag = nullptr; - Configurable multEst{"multEst", 1, "0: without multiplicity; 1: MultFT0M; 2: MultTPC"}; - Configurable applyCalibGain{"applyCalibGain", false, "equalize detector amplitudes"}; - Configurable applyCalibVtx{"applyCalibVtx", false, "equalize Amp vs vtx"}; - Configurable applyCalibDeDx{"applyCalibDeDx", false, "calibration of dedx signal"}; - Configurable applyCalibDeDxFromCCDB{"applyCalibDeDxFromCCDB", true, "use CCDB-based calibration of dedx signal"}; - Configurable cfgFillTrackQaHist{"cfgFillTrackQaHist", false, "fill track QA histograms"}; - Configurable cfgFillNclVsPhiCutQaHist{"cfgFillNclVsPhiCutQaHist", false, "fill TPC cluster vs geometrical cut QA histograms"}; - Configurable cfgFilldEdxCalibHist{"cfgFilldEdxCalibHist", false, "fill dEdx calibration histograms"}; - Configurable cfgFilldEdxQaHist{"cfgFilldEdxQaHist", false, "fill dEdx QA histograms"}; - Configurable cfgFillDCAxyHist{"cfgFillDCAxyHist", false, "fill nsigma QA histograms"}; - Configurable cfgFillV0Hist{"cfgFillV0Hist", false, "fill V0 histograms"}; - Configurable cfgFillChrgType{"cfgFillChrgType", false, "fill histograms per charge types"}; - Configurable cfgFillChrgTypeV0s{"cfgFillChrgTypeV0s", false, "fill V0s histograms per charge types"}; - Configurable cfgCalibDeDxFunction{"cfgCalibDeDxFunction", "pol8", "Functional form for dEdx calibration"}; - Configurable> paramsFuncMIPposEtaP{"paramsFuncMIPposEtaP", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncMIPnegEtaP{"paramsFuncMIPnegEtaP", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncMIPallEtaP{"paramsFuncMIPallEtaP", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncMIPposEtaN{"paramsFuncMIPposEtaN", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncMIPnegEtaN{"paramsFuncMIPnegEtaN", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncMIPallEtaN{"paramsFuncMIPallEtaN", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncPlateaUposEtaP{"paramsFuncPlateaUposEtaP", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncPlateaUnegEtaP{"paramsFuncPlateaUnegEtaP", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncPlateaUallEtaP{"paramsFuncPlateaUallEtaP", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncPlateaUposEtaN{"paramsFuncPlateaUposEtaN", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncPlateaUnegEtaN{"paramsFuncPlateaUnegEtaN", std::vector{-1.f}, "function parameters"}; - Configurable> paramsFuncPlateaUallEtaN{"paramsFuncPlateaUallEtaN", std::vector{-1.f}, "function parameters"}; - Configurable cfgGainEqCcdbPath{"cfgGainEqCcdbPath", "Users/g/gbencedi/flattenicity/GainEq", "CCDB path for gain equalization constants"}; - Configurable cfgVtxEqCcdbPath{"cfgVtxEqCcdbPath", "Users/g/gbencedi/flattenicity/ZvtxEq", "CCDB path for z-vertex equalization constants"}; - Configurable cfgDeDxCalibCcdbPath{"cfgDeDxCalibCcdbPath", "Users/g/gbencedi/flattenicity/dEdxCalib", "CCDB path for dEdx calibration"}; - Configurable cfgStoreThnSparse{"cfgStoreThnSparse", true, "Store histograms as THnSparse"}; + struct : ConfigurableGroup { + Configurable multEst{"multEst", 1, "0: without multiplicity; 1: MultFT0M; 2: MultTPC"}; + Configurable applyCalibGainFromCCDB{"applyCalibGainFromCCDB", false, "equalize detector amplitudes"}; + Configurable applyCalibVtxFromCCDB{"applyCalibVtxFromCCDB", false, "equalize Amp vs vtx"}; + Configurable applyCalibDeDx{"applyCalibDeDx", false, "calibration of dedx signal"}; + Configurable applyCalibDeDxFromCCDB{"applyCalibDeDxFromCCDB", false, "use CCDB-based calibration of dedx signal"}; + Configurable applyDCAParam{"applyDCAParam", false, "use parametrization of DCAxy and DCAz"}; + Configurable applyDCAParamFromCCDB{"applyDCAParamFromCCDB", false, "use CCDB-based parametrization of DCAxy and DCAz"}; + Configurable fillTrackQaHist{"fillTrackQaHist", false, "fill track QA histograms"}; + Configurable fillNclVsPhiCutQaHist{"fillNclVsPhiCutQaHist", false, "fill TPC cluster vs geometrical cut QA histograms"}; + Configurable filldEdxCalibHist{"filldEdxCalibHist", false, "fill dEdx calibration histograms"}; + Configurable filldEdxQaHist{"filldEdxQaHist", false, "fill dEdx QA histograms"}; + Configurable fillDCAxyHist{"fillDCAxyHist", false, "fill nsigma QA histograms"}; + Configurable fillV0Hist{"fillV0Hist", false, "fill V0 histograms"}; + Configurable fillChrgType{"fillChrgType", false, "fill histograms per charge types"}; + Configurable fillChrgTypeV0s{"fillChrgTypeV0s", false, "fill V0s histograms per charge types"}; + Configurable calibDeDxFunction{"calibDeDxFunction", "pol8", "Functional form for dEdx calibration"}; + Configurable> paramsFuncMIPposEtaP{"paramsFuncMIPposEtaP", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncMIPnegEtaP{"paramsFuncMIPnegEtaP", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncMIPallEtaP{"paramsFuncMIPallEtaP", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncMIPposEtaN{"paramsFuncMIPposEtaN", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncMIPnegEtaN{"paramsFuncMIPnegEtaN", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncMIPallEtaN{"paramsFuncMIPallEtaN", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncPlateaUposEtaP{"paramsFuncPlateaUposEtaP", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncPlateaUnegEtaP{"paramsFuncPlateaUnegEtaP", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncPlateaUallEtaP{"paramsFuncPlateaUallEtaP", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncPlateaUposEtaN{"paramsFuncPlateaUposEtaN", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncPlateaUnegEtaN{"paramsFuncPlateaUnegEtaN", std::vector{-1.f}, "function parameters"}; + Configurable> paramsFuncPlateaUallEtaN{"paramsFuncPlateaUallEtaN", std::vector{-1.f}, "function parameters"}; + Configurable gainEqCcdbPath{"gainEqCcdbPath", "Users/g/gbencedi/flattenicity/GainEq", "CCDB path for gain equalization constants"}; + Configurable vtxEqCcdbPath{"vtxEqCcdbPath", "Users/g/gbencedi/flattenicity/ZvtxEq", "CCDB path for z-vertex equalization constants"}; + Configurable dEdxCalibCcdbPath{"dEdxCalibCcdbPath", "Users/g/gbencedi/flattenicity/dEdxCalib", "CCDB path for dEdx calibration"}; + Configurable dcaParamCcdbPath{"dcaParamCcdbPath", "Users/g/gbencedi/flattenicity/DCAParam", "CCDB path for DCAxy and DCAz parametrization"}; + Configurable storeThnSparse{"storeThnSparse", true, "Store histograms as THnSparse"}; + } defOpt; struct : ConfigurableGroup { - Configurable cfgCustomTVX{"cfgCustomTVX", false, "Ask for custom TVX instead of sel8"}; - Configurable cfgRemoveNoTimeFrameBorder{"cfgRemoveNoTimeFrameBorder", false, "Bunch crossing is far from Time Frame borders"}; - Configurable cfgRemoveITSROFrameBorder{"cfgRemoveITSROFrameBorder", false, "Bunch crossing is far from ITS RO Frame border"}; - Configurable cfgCutVtxZ{"cfgCutVtxZ", 10.0f, "Accepted z-vertex range"}; - Configurable useZVtxCutMC{"useZVtxCutMC", true, "use Zvtx cut in MC"}; + Configurable customTVX{"customTVX", false, "Ask for custom TVX instead of sel8"}; + Configurable removeNoTimeFrameBorder{"removeNoTimeFrameBorder", false, "Bunch crossing is far from Time Frame borders"}; + Configurable removeITSROFrameBorder{"removeITSROFrameBorder", false, "Bunch crossing is far from ITS RO Frame border"}; + Configurable cutVtxZ{"cutVtxZ", 10.0f, "Accepted z-vertex range"}; + Configurable zVtxCutMC{"zVtxCutMC", true, "use Zvtx cut in MC"}; Configurable useINELCutMC{"useINELCutMC", true, "use INEL>0 cut in MC"}; - Configurable cfgRemoveNoSameBunchPileup{"cfgRemoveNoSameBunchPileup", true, "Reject collisions in case of pileup with another collision in the same foundBC"}; - Configurable cfgRequireIsGoodZvtxFT0vsPV{"cfgRequireIsGoodZvtxFT0vsPV", true, "Small difference between z-vertex from PV and from FT0"}; - Configurable cfgRequireIsVertexITSTPC{"cfgRequireIsVertexITSTPC", false, "At least one ITS-TPC track (reject vertices built from ITS-only tracks)"}; - Configurable cfgRequirekIsVertexTOFmatched{"cfgRequirekIsVertexTOFmatched", false, "Require kIsVertexTOFmatched: at least one of vertex contributors is matched to TOF"}; + Configurable removeNoSameBunchPileup{"removeNoSameBunchPileup", true, "Reject collisions in case of pileup with another collision in the same foundBC"}; + Configurable requireIsGoodZvtxFT0vsPV{"requireIsGoodZvtxFT0vsPV", true, "Small difference between z-vertex from PV and from FT0"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "At least one ITS-TPC track (reject vertices built from ITS-only tracks)"}; + Configurable requirekIsVertexTOFmatched{"requirekIsVertexTOFmatched", false, "Require kIsVertexTOFmatched: at least one of vertex contributors is matched to TOF"}; Configurable useMultMCmidrap{"useMultMCmidrap", true, "use generated Nch in ∣eta∣ < 0.8"}; - Configurable cfgUseInelgt0wTVX{"cfgUseInelgt0wTVX", true, "Use INEL > 0 condition with TVX trigger, i.e. FT0A and FT0C acceptance"}; - Configurable cfgRemoveSplitVertex{"cfgRemoveSplitVertex", true, "Remove split vertices"}; + Configurable useInelgt0wTVX{"useInelgt0wTVX", true, "Use INEL > 0 condition with TVX trigger, i.e. FT0A and FT0C acceptance"}; + Configurable removeSplitVertex{"removeSplitVertex", true, "Remove split vertices"}; } evtSelOpt; struct : ConfigurableGroup { @@ -310,89 +315,91 @@ struct FlattenictyPikp { } binOpt; struct : ConfigurableGroup { - Configurable cfgTrkEtaMax{"cfgTrkEtaMax", 0.8f, "Eta range for tracks"}; - Configurable cfgRapMax{"cfgRapMax", 0.5f, "Maximum range of rapidity for tracks"}; - Configurable cfgTrkPtMin{"cfgTrkPtMin", 0.1f, "Minimum pT of tracks"}; - Configurable cfgApplyNcl{"cfgApplyNcl", false, "Apply cut on TPC clusters"}; - Configurable cfgNclTPCMin{"cfgNclTPCMin", 135.0f, "Minimum of number of TPC found clusters"}; - Configurable cfgApplyNclPID{"cfgApplyNclPID", true, "Apply cut on TPC PID clusters"}; - Configurable cfgNclPidTPCMin{"cfgNclPidTPCMin", 135.0f, "Minimum of number of TPC PID clusters"}; - Configurable cfgPhiCutPtMin{"cfgPhiCutPtMin", 2.0f, "Minimum pT for phi cut"}; - Configurable cfgTOFBetaPion{"cfgTOFBetaPion", 1.0f, "Minimum beta for TOF pions"}; - Configurable cfgTofBetaPiMax{"cfgTofBetaPiMax", 5E-5, "Maximum beta for TOF pion selection"}; - Configurable cfgRejectTrkAtTPCSector{"cfgRejectTrkAtTPCSector", true, "Reject tracks close to the TPC sector boundaries"}; - Configurable cfgGeoTrkCutMin{"cfgGeoTrkCutMin", "0.06/x+pi/18.0-0.06", "ROOT TF1 formula for minimum phi cut in TPC"}; - Configurable cfgGeoTrkCutMax{"cfgGeoTrkCutMax", "0.1/x+pi/18.0+0.06", "ROOT TF1 formula for maximum phi cut in TPC"}; - Configurable cfgMomMIPMax{"cfgMomMIPMax", 0.6f, "Maximum momentum of MIP pions"}; - Configurable cfgMomMIPMin{"cfgMomMIPMin", 0.4f, "Minimum momentum of MIP pions"}; - Configurable cfgDeDxMIPMax{"cfgDeDxMIPMax", 60.0f, "Maximum range of MIP dedx"}; - Configurable cfgDeDxMIPMin{"cfgDeDxMIPMin", 40.0f, "Maximum range of MIP dedx"}; - Configurable cfgNsigmaMax{"cfgNsigmaMax", 100.0f, "Maximum range of nsgima for tracks"}; - Configurable cfgDcaNsigmaCombinedMax{"cfgDcaNsigmaCombinedMax", 3.0f, "Maximum range of combined nsgima of tracks for DCA"}; - Configurable cfgMomSelPiTOF{"cfgMomSelPiTOF", 0.4f, "Minimum momentum cut for TOF pions"}; - Configurable cfgNsigSelKaTOF{"cfgNsigSelKaTOF", 3.0f, "Nsigma cut for TOF kaons"}; - Configurable cfgBetaPlateuMax{"cfgBetaPlateuMax", 0.1f, "Beta max for Plateau electrons"}; - Configurable cfgApplyCustomDCASel{"cfgApplyCustomDCASel", false, "Apply custom DCA selection"}; - Configurable> cfgDcaXY{"cfgDcaXY", std::vector{0.1f, 0.0f, 0.0f}, "abs dcaXY selection: [0] + [1] * pT^[2]"}; - Configurable> cfgDcaZ{"cfgDcaZ", std::vector{0.1f, 0.0f, 0.0f}, "abs dcaZ selection: [0] + [1] * pT^[2]"}; + Configurable trkEtaMax{"trkEtaMax", 0.8f, "Eta range for tracks"}; + Configurable rapMax{"rapMax", 0.5f, "Maximum range of rapidity for tracks"}; + Configurable trkPtMin{"trkPtMin", 0.1f, "Minimum pT of tracks"}; + Configurable applyNcl{"applyNcl", false, "Apply cut on TPC clusters"}; + Configurable nclTPCMin{"nclTPCMin", 135.0f, "Minimum of number of TPC found clusters"}; + Configurable applyNclPID{"applyNclPID", true, "Apply cut on TPC PID clusters"}; + Configurable nclPidTPCMin{"nclPidTPCMin", 135.0f, "Minimum of number of TPC PID clusters"}; + Configurable phiCutPtMin{"phiCutPtMin", 2.0f, "Minimum pT for phi cut"}; + Configurable tofBetaPion{"tofBetaPion", 1.0f, "Minimum beta for TOF pions"}; + Configurable tofBetaPiMax{"tofBetaPiMax", 5E-5, "Maximum beta for TOF pion selection"}; + Configurable rejectTrkAtTPCSector{"rejectTrkAtTPCSector", true, "Reject tracks close to the TPC sector boundaries"}; + Configurable geoTrkCutMin{"geoTrkCutMin", "0.06/x+pi/18.0-0.06", "ROOT TF1 formula for minimum phi cut in TPC"}; + Configurable geoTrkCutMax{"geoTrkCutMax", "0.1/x+pi/18.0+0.06", "ROOT TF1 formula for maximum phi cut in TPC"}; + Configurable dEdxMIPnominal{"dEdxMIPnominal", 50.0f, "Nominal value of MIP pions"}; + Configurable momMIPMax{"momMIPMax", 0.6f, "Maximum momentum of MIP pions"}; + Configurable momMIPMin{"momMIPMin", 0.4f, "Minimum momentum of MIP pions"}; + Configurable dEdxMIPMax{"dEdxMIPMax", 60.0f, "Maximum range of MIP dedx"}; + Configurable dEdxMIPMin{"dEdxMIPMin", 40.0f, "Maximum range of MIP dedx"}; + Configurable nsigmaMax{"nsigmaMax", 100.0f, "Maximum range of nsgima for tracks"}; + Configurable dcaNsigmaCombinedMax{"dcaNsigmaCombinedMax", 3.0f, "Maximum range of combined nsgima of tracks for DCA"}; + Configurable momSelPiTOF{"momSelPiTOF", 0.4f, "Minimum momentum cut for TOF pions"}; + Configurable nsigmaSelKaTOF{"nsigmaSelKaTOF", 3.0f, "Nsigma cut for TOF kaons"}; + Configurable betaPlateuMax{"betaPlateuMax", 0.1f, "Beta max for Plateau electrons"}; + Configurable> dcaXY{"dcaXY", std::vector{0.1f, 0.0f, 0.0f}, "abs dcaXY selection: [0] + [1] * pT^[2]"}; + Configurable> dcaZ{"dcaZ", std::vector{0.1f, 0.0f, 0.0f}, "abs dcaZ selection: [0] + [1] * pT^[2]"}; + Configurable nsigmaDCAxy{"nsigmaDCAxy", 1.0f, "Nsigma cut on DCAxy"}; + Configurable nsigmaDCAz{"nsigmaDCAz", 1.0f, "Nsigma cut on DCAz"}; } trkSelOpt; struct : ConfigurableGroup { // common selection - Configurable cfgV0TypeSel{"cfgV0TypeSel", 1, "select on a certain V0 type (leave negative if no selection desired)"}; - Configurable cfgV0Ymax{"cfgV0Ymax", 0.5f, "Maximum rapidity of V0s"}; - Configurable cfgRejectV0sAtTPCSector{"cfgRejectV0sAtTPCSector", true, "Reject V0s close to the TPC sector boundaries"}; - Configurable cfgRequireITS{"cfgRequireITS", true, "Additional cut on the ITS requirement"}; - Configurable cfgNsigmaElTPC{"cfgNsigmaElTPC", 5.0, "max nsigma of TPC for electorn"}; - Configurable cfgNsigmaPiTPC{"cfgNsigmaPiTPC", 5.0, "max nsigma of TPC for pion"}; - Configurable cfgNsigmaPrTPC{"cfgNsigmaPrTPC", 5.0, "max nsigma of TPC for proton"}; - Configurable cfgNsigmaElTOF{"cfgNsigmaElTOF", 3.0, "max nsigma of TOF for electorn"}; - Configurable cfgNsigmaPiTOF{"cfgNsigmaPiTOF", 3.0, "max nsigma of TOF for pion"}; - Configurable cfgNsigmaPrTOF{"cfgNsigmaPrTOF", 3.0, "max nsigma of TOF for proton"}; + Configurable v0TypeSel{"v0TypeSel", 1, "select on a certain V0 type (leave negative if no selection desired)"}; + Configurable v0Ymax{"v0Ymax", 0.5f, "Maximum rapidity of V0s"}; + Configurable rejectV0sAtTPCSector{"rejectV0sAtTPCSector", true, "Reject V0s close to the TPC sector boundaries"}; + Configurable v0requireITS{"v0requireITS", true, "Additional cut on the ITS requirement"}; + Configurable nsigmaElTPC{"nsigmaElTPC", 5.0, "max nsigma of TPC for electorn"}; + Configurable nsigmaPiTPC{"nsigmaPiTPC", 5.0, "max nsigma of TPC for pion"}; + Configurable nsigmaPrTPC{"nsigmaPrTPC", 5.0, "max nsigma of TPC for proton"}; + Configurable nsigmaElTOF{"nsigmaElTOF", 3.0, "max nsigma of TOF for electorn"}; + Configurable nsigmaPiTOF{"nsigmaPiTOF", 3.0, "max nsigma of TOF for pion"}; + Configurable nsigmaPrTOF{"nsigmaPrTOF", 3.0, "max nsigma of TOF for proton"}; ConfigurableAxis axisArmPodAlpha{"axisArmPodAlpha", {200, -1.0, 1.0}, "Armenteros-Podolanski alpha"}; ConfigurableAxis axisArmPodqT{"axisArmPodqT", {600, 0.0f, 0.3f}, "Armenteros-Podolanski qT"}; // standad parameters for V0 selection - Configurable cfgV0etamin{"cfgV0etamin", -0.8f, "min eta of V0s"}; - Configurable cfgV0etamax{"cfgV0etamax", +0.8f, "max eta of V0s"}; - Configurable cfgminNCrossedRowsTPC{"cfgminNCrossedRowsTPC", 70, "Additional cut on the minimum number of crossed rows in the TPC"}; - Configurable cfgApplyV0sNclFound{"cfgApplyV0sNclFound", false, "Apply cut on TPC Found clusters"}; - Configurable cfgV0NclTPCMin{"cfgV0NclTPCMin", 135.0f, "Minimum of number of TPC found clusters"}; - Configurable cfgApplyV0sNclPID{"cfgApplyV0sNclPID", true, "Apply cut on TPC PID clusters"}; - Configurable cfgV0NclPidTPCMin{"cfgV0NclPidTPCMin", 135.0f, "Minimum of number of TPC PID clusters"}; - Configurable cfgmaxChi2PerClusterTPC{"cfgmaxChi2PerClusterTPC", 4.f, "Additional cut on the maximum value of the chi2 per cluster in the TPC"}; - Configurable cfgmaxChi2PerClusterITS{"cfgmaxChi2PerClusterITS", 36.f, "Additional cut on the maximum value of the chi2 per cluster in the ITS"}; - Configurable cfgminITSnClusters{"cfgminITSnClusters", 4, "minimum number of found ITS clusters"}; - Configurable cfgminNCrossedRowsOverFindableClustersTPC{"cfgminNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; - Configurable cfgDCAv0daughter{"cfgDCAv0daughter", 1.0, "max DCA of V0 daughter tracks (cm)"}; - Configurable cfgv0cospa{"cfgv0cospa", 0.995, "min V0 CosPA"}; - Configurable cfgDCAposToPV{"cfgDCAposToPV", 0.05f, "min DCA Pos To PV (cm)"}; - Configurable cfgDCAnegToPV{"cfgDCAnegToPV", 0.05f, "min DCA Neg To PV (cm)"}; - Configurable cfgv0Rmin{"cfgv0Rmin", 1.2, "min V0 radius (cm)"}; - Configurable cfgv0Rmax{"cfgv0Rmax", 1E5, "max V0 radius (cm)"}; + Configurable v0etamin{"v0etamin", -0.8f, "min eta of V0s"}; + Configurable v0etamax{"v0etamax", +0.8f, "max eta of V0s"}; + Configurable v0minNCrossedRowsTPC{"v0minNCrossedRowsTPC", 70, "Additional cut on the minimum number of crossed rows in the TPC"}; + Configurable applyV0sNclFound{"applyV0sNclFound", false, "Apply cut on TPC Found clusters"}; + Configurable v0NclTPCMin{"v0NclTPCMin", 135.0f, "Minimum of number of TPC found clusters"}; + Configurable applyV0sNclPID{"applyV0sNclPID", true, "Apply cut on TPC PID clusters"}; + Configurable v0NclPidTPCMin{"v0NclPidTPCMin", 135.0f, "Minimum of number of TPC PID clusters"}; + Configurable v0maxChi2PerClusterTPC{"v0maxChi2PerClusterTPC", 4.f, "Additional cut on the maximum value of the chi2 per cluster in the TPC"}; + Configurable v0maxChi2PerClusterITS{"v0maxChi2PerClusterITS", 36.f, "Additional cut on the maximum value of the chi2 per cluster in the ITS"}; + Configurable v0minITSnClusters{"v0minITSnClusters", 4, "minimum number of found ITS clusters"}; + Configurable v0minNCrossedRowsOverFindableClustersTPC{"v0minNCrossedRowsOverFindableClustersTPC", 0.8f, "Additional cut on the minimum value of the ratio between crossed rows and findable clusters in the TPC"}; + Configurable dcaV0daughter{"dcaV0daughter", 1.0, "max DCA of V0 daughter tracks (cm)"}; + Configurable v0cospa{"v0cospa", 0.995, "min V0 CosPA"}; + Configurable dcaPosToPV{"dcaPosToPV", 0.05f, "min DCA Pos To PV (cm)"}; + Configurable dcaNegToPV{"dcaNegToPV", 0.05f, "min DCA Neg To PV (cm)"}; + Configurable v0Rmin{"v0Rmin", 1.2, "min V0 radius (cm)"}; + Configurable v0Rmax{"v0Rmax", 1E5, "max V0 radius (cm)"}; // parameters for selection KOs - Configurable cfgcTauK0s{"cfgcTauK0s", 20, "v0ctau for K0s"}; - Configurable cfgCosPAK0s{"cfgCosPAK0s", 0.995, "V0 CosPA for K0s"}; - Configurable cfgV0radiusK0s{"cfgV0radiusK0s", 0.5, "v0radius for K0s"}; - Configurable cfgdmassK{"cfgdmassK", 0.01f, "Competing Mass Rejection cut for K0s"}; - Configurable cfgArmPodK0s{"cfgArmPodK0s", 5.0f, "pT * (cut) > |alpha|, Armenteros-Podolanski cut for K0s"}; + Configurable cTauK0s{"cTauK0s", 20, "v0ctau for K0s"}; + Configurable cosPAK0s{"cosPAK0s", 0.995, "V0 CosPA for K0s"}; + Configurable v0radiusK0s{"v0radiusK0s", 0.5, "v0radius for K0s"}; + Configurable dmassK{"dmassK", 0.01f, "Competing Mass Rejection cut for K0s"}; + Configurable armPodK0s{"armPodK0s", 5.0f, "pT * (cut) > |alpha|, Armenteros-Podolanski cut for K0s"}; ConfigurableAxis axisK0sMass{"axisK0sMass", {200, 0.4f, 0.6f}, "K0Short mass binning"}; // parameters for selection Lambda / antiLambda - Configurable cfgcTauLambda{"cfgcTauLambda", 30, "v0ctau for Lambda"}; - Configurable cfgCosPALambda{"cfgCosPALambda", 0.995, "V0 CosPA for Lambda"}; - Configurable cfgV0radiusLambda{"cfgV0radiusLambda", 0.5, "v0radius for Lambda"}; - Configurable cfgdmassL{"cfgdmassL", 0.01f, "Competing Mass Rejection cut for Lambda"}; + Configurable cTauLambda{"cTauLambda", 30, "v0ctau for Lambda"}; + Configurable cosPALambda{"cosPALambda", 0.995, "V0 CosPA for Lambda"}; + Configurable v0radiusLambda{"v0radiusLambda", 0.5, "v0radius for Lambda"}; + Configurable dmassL{"dmassL", 0.01f, "Competing Mass Rejection cut for Lambda"}; ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.101f, 1.131f}, "Lambda mass binning"}; // parameters for selection Gamma - Configurable cfgdmassG{"cfgdmassG", 0.1f, "max mass for Gammas"}; - Configurable cfgArmPodGammasalpha{"cfgArmPodGammasalpha", 0.45f, "Armenteros-Podolanski alpha cut for Gammas"}; - Configurable cfgArmPodGammasqT{"cfgArmPodGammasqT", 0.01f, "Armenteros-Podolanski qT cut for Gammas"}; + Configurable dmassG{"dmassG", 0.1f, "max mass for Gammas"}; + Configurable armPodGammasalpha{"armPodGammasalpha", 0.45f, "Armenteros-Podolanski alpha cut for Gammas"}; + Configurable armPodGammasqT{"armPodGammasqT", 0.01f, "Armenteros-Podolanski qT cut for Gammas"}; ConfigurableAxis axisGammaMass{"axisGammaMass", {200, 0.0f, 0.5f}, "Gamma mass binning"}; - Configurable cfgdEdxPlateauSel{"cfgdEdxPlateauSel", 50, "dEdx selection sensitivity for electrons"}; + Configurable dEdxPlateauSel{"dEdxPlateauSel", 50, "dEdx selection sensitivity for electrons"}; } v0SelOpt; Service ccdb{}; struct : ConfigurableGroup { - Configurable cfgMagField{"cfgMagField", 99999, "Configurable magnetic field;default CCDB will be queried"}; + Configurable magField{"magField", 99999, "Configurable magnetic field;default CCDB will be queried"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; @@ -409,11 +416,18 @@ struct FlattenictyPikp { bool lCalibLoaded = false; } dedxcalib; + struct DCAParam { + TList* lCalibObjects = nullptr; + TH1F* hDCAxyParam = nullptr; + TH1F* hDCAzParam = nullptr; + bool lCalibLoaded = false; + } dcaparam; + struct : ConfigurableGroup { Configurable requireRCTFlagChecker{"requireRCTFlagChecker", false, "Check event quality in run condition table"}; - Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; - Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", false, "Evt sel: RCT flag checker ZDC check"}; - Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + Configurable evtRCTFlagCheckerLabel{"evtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; + Configurable evtRCTFlagCheckerZDCCheck{"evtRCTFlagCheckerZDCCheck", false, "Evt sel: RCT flag checker ZDC check"}; + Configurable evtRCTFlagCheckerLimitAcceptAsBad{"evtRCTFlagCheckerLimitAcceptAsBad", true, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; } rctCuts; RCTFlagsChecker rctChecker; @@ -480,19 +494,19 @@ struct FlattenictyPikp { void init(InitContext&) { - auto vecParamsMIPposEtaP = (std::vector)paramsFuncMIPposEtaP; - auto vecParamsMIPposEtaN = (std::vector)paramsFuncMIPposEtaN; - auto vecParamsMIPnegEtaP = (std::vector)paramsFuncMIPnegEtaP; - auto vecParamsMIPnegEtaN = (std::vector)paramsFuncMIPnegEtaN; - auto vecParamsMIPallEtaP = (std::vector)paramsFuncMIPallEtaP; - auto vecParamsMIPallEtaN = (std::vector)paramsFuncMIPallEtaN; - - auto vecParamsPLAposEtaP = (std::vector)paramsFuncPlateaUposEtaP; - auto vecParamsPLAposEtaN = (std::vector)paramsFuncPlateaUposEtaN; - auto vecParamsPLAnegEtaP = (std::vector)paramsFuncPlateaUnegEtaP; - auto vecParamsPLAnegEtaN = (std::vector)paramsFuncPlateaUnegEtaN; - auto vecParamsPLAallEtaP = (std::vector)paramsFuncPlateaUallEtaP; - auto vecParamsPLAallEtaN = (std::vector)paramsFuncPlateaUallEtaN; + auto vecParamsMIPposEtaP = (std::vector)defOpt.paramsFuncMIPposEtaP; + auto vecParamsMIPposEtaN = (std::vector)defOpt.paramsFuncMIPposEtaN; + auto vecParamsMIPnegEtaP = (std::vector)defOpt.paramsFuncMIPnegEtaP; + auto vecParamsMIPnegEtaN = (std::vector)defOpt.paramsFuncMIPnegEtaN; + auto vecParamsMIPallEtaP = (std::vector)defOpt.paramsFuncMIPallEtaP; + auto vecParamsMIPallEtaN = (std::vector)defOpt.paramsFuncMIPallEtaN; + + auto vecParamsPLAposEtaP = (std::vector)defOpt.paramsFuncPlateaUposEtaP; + auto vecParamsPLAposEtaN = (std::vector)defOpt.paramsFuncPlateaUposEtaN; + auto vecParamsPLAnegEtaP = (std::vector)defOpt.paramsFuncPlateaUnegEtaP; + auto vecParamsPLAnegEtaN = (std::vector)defOpt.paramsFuncPlateaUnegEtaN; + auto vecParamsPLAallEtaP = (std::vector)defOpt.paramsFuncPlateaUallEtaP; + auto vecParamsPLAallEtaN = (std::vector)defOpt.paramsFuncPlateaUallEtaN; auto addVec = [&](std::vector>& targetVec, const std::string& name, bool isMIP) { if (isMIP) { @@ -529,7 +543,7 @@ struct FlattenictyPikp { ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); ccdb->setFatalWhenNull(false); - rctChecker.init(rctCuts.cfgEvtRCTFlagCheckerLabel, rctCuts.cfgEvtRCTFlagCheckerZDCCheck, rctCuts.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + rctChecker.init(rctCuts.evtRCTFlagCheckerLabel, rctCuts.evtRCTFlagCheckerZDCCheck, rctCuts.evtRCTFlagCheckerLimitAcceptAsBad); if (isCustomTracks.value) { selTrkGlobal = getGlobalTrackSelectionRun3ITSMatch(setITSreq.value); @@ -577,7 +591,7 @@ struct FlattenictyPikp { AxisSpec multAxis{binOpt.axisMultPerc, "multiplicity estimator"}; - switch (multEst) { + switch (defOpt.multEst) { case MultE::CnoMult: break; case MultE::CmultFT0M: @@ -587,12 +601,12 @@ struct FlattenictyPikp { multAxis.name = "multTPC"; break; default: - LOG(fatal) << "No valid option for mult estimator " << multEst; + LOG(fatal) << "No valid option for mult estimator " << defOpt.multEst; } - if (trkSelOpt.cfgRejectTrkAtTPCSector || v0SelOpt.cfgRejectV0sAtTPCSector) { - fPhiCutLow = new TF1("fPhiCutLow", trkSelOpt.cfgGeoTrkCutMin.value.c_str(), 0, 100); - fPhiCutHigh = new TF1("fPhiCutHigh", trkSelOpt.cfgGeoTrkCutMax.value.c_str(), 0, 100); + if (trkSelOpt.rejectTrkAtTPCSector || v0SelOpt.rejectV0sAtTPCSector) { + fPhiCutLow = new TF1("fPhiCutLow", trkSelOpt.geoTrkCutMin.value.c_str(), 0, 100); + fPhiCutHigh = new TF1("fPhiCutHigh", trkSelOpt.geoTrkCutMax.value.c_str(), 0, 100); } registryQC.add("Events/hVtxZ", "Measured vertex z position", kTH1F, {vtxzAxis}); @@ -632,11 +646,11 @@ struct FlattenictyPikp { registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelEta + 1, "Eta"); registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelPt + 1, "Pt"); registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelDCA + 1, "DCA"); + registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelCustomDCA + 1, "Custom DCA sel."); registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkNRowsTPC + 1, "trkNRowsTPC"); registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelNClsFound + 1, "NClsTPCFound"); registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelNClsPID + 1, "NClsTPCPid"); registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelTPCBndr + 1, "TPC Boundary"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelCustomDCA + 1, "Custom DCA sel."); // V0 counter registryData.add("Tracks/V0qa/hV0Sel", "Number of V0s; Cut; #Tracks Passed Cut", {kTH1F, {{nV0Sel, 0, nV0Sel}}}); registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelAll + 1, "All"); @@ -650,8 +664,8 @@ struct FlattenictyPikp { registryData.add("Events/hFlatVsMultEst", "hFlatVsMultEst", kTH2F, {flatAxis, multAxis}); registryData.add("Tracks/postSel/hPVsPtEta", "; #it{p} (GeV/#it{c}); #it{p}_{T} (GeV/#it{c}); #eta;", {kTH3F, {pAxis, ptAxis, etaAxis}}); - if (cfgFillNclVsPhiCutQaHist || cfgFillTrackQaHist || cfgFilldEdxQaHist || cfgFillDCAxyHist) { - if (cfgFillNclVsPhiCutQaHist) { + if (defOpt.fillNclVsPhiCutQaHist || defOpt.fillTrackQaHist || defOpt.filldEdxQaHist || defOpt.fillDCAxyHist) { + if (defOpt.fillNclVsPhiCutQaHist) { registryData.add("Tracks/postSel/hPtPhi", "; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9)", {kTH2F, {ptAxis, phiAxisMod}}); registryData.add("Tracks/postSel/hPtPhiNclTPC", "; #{eta}; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{cluster}", {kTHnSparseF, {etaAxis, ptAxis, phiAxisMod, clTpcAxis}}); registryData.add("Tracks/postSel/hPtPhiNclPIDTPC", "; #{eta}; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{PID cluster}", {kTHnSparseF, {etaAxis, ptAxis, phiAxisMod, clTpcAxis}}); @@ -660,7 +674,7 @@ struct FlattenictyPikp { registryData.add("Tracks/postSel/hPtNclPIDTPC", "; #it{p}_{T} (GeV/#it{c}); N_{PID cluster}", {kTH2F, {ptAxis, clTpcAxis}}); registryData.add("Tracks/postSel/pPtNclPIDTPC", "; #it{p}_{T} (GeV/#it{c}); N_{PID cluster}", {kTProfile, {ptAxis}}); } - if (cfgFillTrackQaHist) { + if (defOpt.fillTrackQaHist) { registryData.add("Tracks/postSel/hShTpcClvsPt", "", {kTH2F, {ptAxis, shCluserAxis}}); registryData.add("Tracks/postSel/hNclTPCFoundvsPt", "", {kTH2F, {ptAxis, clTpcAxis}}); registryData.add("Tracks/postSel/hNClTPCPidvsPt", "", {kTH2F, {ptAxis, clTpcAxis}}); @@ -685,8 +699,8 @@ struct FlattenictyPikp { registryData.add("Tracks/postSel/hTOFPvsBeta", "Beta from TOF; #it{p} (GeV/#it{c}); #beta", {kTH2F, {pAxis, {120, 0.0, 1.2}}}); registryData.add("Tracks/postSel/hTOFpi", "Primary Pions from TOF; #eta; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, pAxis, dEdxAxis}}); } - if (cfgFilldEdxQaHist) { - if (cfgStoreThnSparse) { + if (defOpt.filldEdxQaHist) { + if (defOpt.storeThnSparse) { registryData.add("Tracks/postCalib/all/hMIP", "; mult; flat; #eta; #LT dE/dx #GT_{MIP, primary tracks};", {kTHnSparseF, {multAxis, flatAxis, etaAxis, dEdxAxis}}); registryData.add("Tracks/postCalib/all/hPlateau", "; mult; flat; #eta; #LT dE/dx #GT_{Plateau, primary tracks};", {kTHnSparseF, {multAxis, flatAxis, etaAxis, dEdxAxis}}); } else { @@ -702,14 +716,14 @@ struct FlattenictyPikp { registryData.add("Tracks/postCalib/all/hPlateauVsPhiVsEta", "; #varphi; #LT dE/dx #GT_{Plateau, primary tracks}; #eta;", {kTH3F, {phiAxis, dEdxAxis, etaAxis}}); registryData.add("Tracks/postCalib/all/hPlateauNClTPCPidvsEta", ";#eta; Ncl pid", {kTH2F, {etaAxis, clTpcAxis}}); registryData.addClone("Tracks/postCalib/all/", "Tracks/preCalib/all/"); - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { registryData.addClone("Tracks/postCalib/all/", "Tracks/postCalib/pos/"); registryData.addClone("Tracks/postCalib/all/", "Tracks/postCalib/neg/"); registryData.addClone("Tracks/preCalib/all/", "Tracks/preCalib/pos/"); registryData.addClone("Tracks/preCalib/all/", "Tracks/preCalib/neg/"); } } - if (cfgFillDCAxyHist) { + if (defOpt.fillDCAxyHist) { for (int i = 0; i < Npart; i++) { registryData.add({fmt::format(CpTvsDCAxyF.data(), CspeciesAll[i].data()).c_str(), "; mult; flat; #it{p} (GeV/#it{c}); DCA_{xy} (cm)", {kTHnSparseF, {multAxis, flatAxis, ptAxis, dcaXYAxis}}}); } @@ -738,8 +752,8 @@ struct FlattenictyPikp { // dEdx PID registryData.add({"Tracks/all/hdEdx", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); // Clean samples - if (cfgFillV0Hist) { - if (cfgStoreThnSparse) { + if (defOpt.fillV0Hist) { + if (defOpt.storeThnSparse) { registryData.add({"Tracks/CleanTof/all/hPiTof", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); registryData.add({"Tracks/CleanV0/all/hEV0", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); registryData.add({"Tracks/CleanV0/all/hPiV0", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); @@ -752,14 +766,14 @@ struct FlattenictyPikp { } registryData.add("Tracks/CleanTof/all/hBetaVsP", ";Momentum (GeV/#it{c}); #beta", kTH2F, {{{ptAxisV0s}, {120, 0., 1.2}}}); registryData.add("Tracks/CleanTof/all/hTofExpPi", ";Momentum (GeV/#it{c});#it{t}^{#pi}_{Exp}/#it{t}_{TOF}", kTH2F, {{{ptAxisV0s}, {100, 0.2, 1.2}}}); - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { registryData.addClone("Tracks/CleanTof/all/", "Tracks/CleanTof/pos/"); registryData.addClone("Tracks/CleanTof/all/", "Tracks/CleanTof/neg/"); registryData.addClone("Tracks/CleanV0/all/", "Tracks/CleanV0/pos/"); registryData.addClone("Tracks/CleanV0/all/", "Tracks/CleanV0/neg/"); } } - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { registryData.addClone("Tracks/all/", "Tracks/pos/"); registryData.addClone("Tracks/all/", "Tracks/neg/"); } @@ -799,7 +813,7 @@ struct FlattenictyPikp { registryMC.add({fmt::format(CpTmcClosureGenPrimF.data(), CspeciesAll[i].data()).c_str(), "Gen evt w/o Evt sel; Gen Nch (|#eta|<0.8); flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {nChAxis, flatAxis, ptAxis}}}); registryMC.add({fmt::format(CpTmcClosureRecF.data(), CspeciesAll[i].data()).c_str(), "Gen Nch w/ Nrec > 0 + Evt. sel; Gen Nch (|#eta|<0.8); flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {nChAxis, flatAxis, ptAxis}}}); } - if (cfgFillNclVsPhiCutQaHist) { + if (defOpt.fillNclVsPhiCutQaHist) { registryMC.add("Tracks/postSel/hPtPhi", "; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9)", {kTH2F, {ptAxis, phiAxisMod}}); registryMC.add("Tracks/postSel/hPtPhiNclTPC", "; #eta; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{cluster}", {kTHnSparseF, {etaAxis, ptAxis, phiAxisMod, clTpcAxis}}); registryMC.add("Tracks/postSel/hPtPhiNclPIDTPC", "; #eta; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{PID cluster}", {kTHnSparseF, {etaAxis, ptAxis, phiAxisMod, clTpcAxis}}); @@ -867,7 +881,7 @@ struct FlattenictyPikp { fv0AmplCorr = {}; auto runnumber = bc.runNumber(); - if (trkSelOpt.cfgRejectTrkAtTPCSector || v0SelOpt.cfgRejectV0sAtTPCSector) { + if (trkSelOpt.rejectTrkAtTPCSector || v0SelOpt.rejectV0sAtTPCSector) { grpmag = ccdb->getForRun(ccdbConf.grpmagPath, runnumber); if (!grpmag) { LOG(fatal) << "Got nullptr from CCDB for path " << ccdbConf.grpmagPath << " of object GRPMagField and " << ccdbConf.grpPath << " of object GRPObject for run " << runnumber; @@ -875,8 +889,8 @@ struct FlattenictyPikp { magField = std::lround(5.f * grpmag->getL3Current() / 30000.f); LOG(info) << "Retrieved GRP for run " << runnumber << " with magnetic field of " << magField << " kZG"; } - if (applyCalibGain) { - std::string fullPathCalibGain = cfgGainEqCcdbPath; + if (defOpt.applyCalibGainFromCCDB) { + std::string fullPathCalibGain = defOpt.gainEqCcdbPath; fullPathCalibGain += "/FV0"; const auto* objfv0Gain = ccdb->getForRun>(fullPathCalibGain, runnumber); if (!objfv0Gain) { @@ -888,18 +902,17 @@ struct FlattenictyPikp { fv0AmplCorr = *(objfv0Gain); } } - if (applyCalibVtx) { - std::string fullPathCalibVtx = cfgVtxEqCcdbPath; + if (defOpt.applyCalibVtxFromCCDB) { + std::string fullPathCalibVtx = defOpt.vtxEqCcdbPath; fullPathCalibVtx += "/FV0"; zVtxMap = ccdb->getForRun(fullPathCalibVtx, runnumber); } - - if (applyCalibDeDxFromCCDB) { - std::string fullPathCalibDeDxMip = cfgDeDxCalibCcdbPath; + if (defOpt.applyCalibDeDxFromCCDB) { + std::string fullPathCalibDeDxMip = defOpt.dEdxCalibCcdbPath; if (!fullPathCalibDeDxMip.empty()) { fullPathCalibDeDxMip += "/MIP"; } - std::string fullPathCalibDeDxPlateau = cfgDeDxCalibCcdbPath; + std::string fullPathCalibDeDxPlateau = defOpt.dEdxCalibCcdbPath; if (!fullPathCalibDeDxPlateau.empty()) { fullPathCalibDeDxPlateau += "/Plateau"; } @@ -933,13 +946,29 @@ struct FlattenictyPikp { LOGF(fatal, "Could not load hPlateauCalib from %s", fullPathCalibDeDxPlateau.c_str()); } } + if (defOpt.applyDCAParamFromCCDB) { + dcaparam.lCalibObjects = ccdb->getForRun(defOpt.dcaParamCcdbPath, runnumber); + if (dcaparam.lCalibObjects) { + LOG(info) << "CCDB objects loaded successfully"; + dcaparam.hDCAxyParam = dynamic_cast(dcaparam.lCalibObjects->FindObject("hfitDCAxyParams")); + dcaparam.hDCAzParam = dynamic_cast(dcaparam.lCalibObjects->FindObject("hfitDCAzParams")); + dcaparam.lCalibLoaded = true; + if (!dcaparam.hDCAxyParam || !dcaparam.hDCAzParam) { + LOGF(error, "Problem loading CCDB objects! Please check"); + dcaparam.lCalibLoaded = false; + } + } else { + LOGF(fatal, "Could not load DCAParam from %s", defOpt.dcaParamCcdbPath.value.c_str()); + dcaparam.lCalibLoaded = false; + } + } } template std::unique_ptr setFuncPars(T const& vecPars) { static_assert(!std::is_pointer::value, "Pointers to pointers not allowed here"); - std::unique_ptr fCalibDeDxFunc(new TF1("fCalibDeDxFunc", cfgCalibDeDxFunction.value.c_str(), -1., 1.)); + std::unique_ptr fCalibDeDxFunc(new TF1("fCalibDeDxFunc", defOpt.calibDeDxFunction.value.c_str(), -1., 1.)); if (vecPars.size() >= 1) { for (typename T::size_type i = 0; i < vecPars.size(); i++) { fCalibDeDxFunc->SetParameter(i, vecPars[i]); @@ -964,11 +993,11 @@ struct FlattenictyPikp { const float tTOF = track.tofSignal(); const float trkLength = track.length(); const float tExpPiTOF = track.tofExpSignalPi(tTOF); - if (track.p() >= trkSelOpt.cfgMomSelPiTOF && trkLength > Cnull && tTOF > Cnull) { + if (track.p() >= trkSelOpt.momSelPiTOF && trkLength > Cnull && tTOF > Cnull) { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[chrg]) + HIST("hTofExpPi"), track.p(), tExpPiTOF / tTOF); - if (std::abs((tExpPiTOF / tTOF) - Cone) < trkSelOpt.cfgTofBetaPiMax) { + if (std::abs((tExpPiTOF / tTOF) - Cone) < trkSelOpt.tofBetaPiMax) { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[chrg]) + HIST("hBetaVsP"), track.p(), track.beta()); - // if (std::abs(track.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC && std::abs(track.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF) { + // if (std::abs(track.tpcNSigmaPi()) < v0SelOpt.nsigmaPiTPC && std::abs(track.tofNSigmaPi()) < v0SelOpt.nsigmaPiTOF) { return true; // } } @@ -980,7 +1009,7 @@ struct FlattenictyPikp { template void fillDCA(T const& tracks, C const& collision, aod::BCsWithTimestamps const& /*bcs*/) { - if (trkSelOpt.cfgRejectTrkAtTPCSector) { + if (trkSelOpt.rejectTrkAtTPCSector) { auto bc = collision.template bc_as(); int currentRun = bc.runNumber(); if (runNumber != currentRun) { @@ -991,27 +1020,10 @@ struct FlattenictyPikp { const float mult = getMult(collision); const float flat = fillFlat(collision); for (const auto& track : tracks) { - if (std::abs(track.eta()) > trkSelOpt.cfgTrkEtaMax) { - continue; - } - if (track.pt() < trkSelOpt.cfgTrkPtMin) { - continue; - } - if (trkSelOpt.cfgApplyNcl && track.tpcNClsFound() < trkSelOpt.cfgNclTPCMin) { - continue; - } - if (trkSelOpt.cfgApplyNclPID && track.tpcNClsPID() < trkSelOpt.cfgNclPidTPCMin) { + if (!isGoodTrack(track, magField)) { continue; } - float phiModn = track.phi(); - phiMod(phiModn, magField, track.sign()); - if (trkSelOpt.cfgRejectTrkAtTPCSector && (track.pt() >= trkSelOpt.cfgPhiCutPtMin && phiModn < fPhiCutHigh->Eval(track.pt()) && phiModn > fPhiCutLow->Eval(track.pt()))) { - continue; - } - if (!isDCAxyWoCut(track)) { - continue; - } - if (track.hasTOF() && (std::sqrt(std::pow(std::fabs(o2::aod::pidutils::tpcNSigma(track)), 2) + std::pow(std::fabs(o2::aod::pidutils::tofNSigma(track)), 2) < trkSelOpt.cfgDcaNsigmaCombinedMax))) { + if (track.hasTOF() && (std::sqrt(std::pow(std::fabs(o2::aod::pidutils::tpcNSigma(track)), 2) + std::pow(std::fabs(o2::aod::pidutils::tofNSigma(track)), 2) < trkSelOpt.dcaNsigmaCombinedMax))) { registryData.fill(HIST(Cprefix) + HIST(CspeciesAll[id]) + HIST(CpTvsDCAxy), mult, flat, track.pt(), track.dcaXY()); } } @@ -1020,7 +1032,7 @@ struct FlattenictyPikp { template void filldEdx(T const& tracks, V const& v0s, C const& collision, aod::BCsWithTimestamps const& bcs) { - if (trkSelOpt.cfgRejectTrkAtTPCSector || v0SelOpt.cfgRejectV0sAtTPCSector || applyCalibGain || applyCalibVtx) { + if (trkSelOpt.rejectTrkAtTPCSector || v0SelOpt.rejectV0sAtTPCSector || defOpt.applyCalibGainFromCCDB || defOpt.applyCalibVtxFromCCDB) { auto bc = collision.template bc_as(); int currentRun = bc.runNumber(); if (runNumber != currentRun) { @@ -1037,17 +1049,17 @@ struct FlattenictyPikp { for (const auto& track : tracks) { float dEdx = track.tpcSignal(); - if (cfgFillTrackQaHist) { + if (defOpt.fillTrackQaHist) { fillTrackQA(track); } - if (!isGoodTrack(track, magField)) { + if (!isGoodTrack(track, magField)) { continue; } - if (cfgFillTrackQaHist) { + if (defOpt.fillTrackQaHist) { fillTrackQA(track); } - if (cfgFilldEdxCalibHist && cfgFilldEdxQaHist) { - if (cfgFillChrgType) { + if (defOpt.filldEdxCalibHist && defOpt.filldEdxQaHist) { + if (defOpt.fillChrgType) { if (track.sign() * track.p() > Cnull) { filldEdxQA(track, collision, dEdx); } else { @@ -1057,41 +1069,41 @@ struct FlattenictyPikp { filldEdxQA(track, collision, dEdx); } } - if (applyCalibDeDx) { - if (cfgFillChrgType) { + if (defOpt.applyCalibDeDx) { + if (defOpt.fillChrgType) { if (track.sign() * track.p() > Cnull) { - if (applyCalibDeDxFromCCDB) { - dEdx *= (50.0 / dedxcalib.hMIPcalibPos->GetBinContent(dedxcalib.hMIPcalibPos->FindBin(track.eta()))); + if (defOpt.applyCalibDeDxFromCCDB && dedxcalib.lCalibLoaded) { + dEdx *= (trkSelOpt.dEdxMIPnominal / dedxcalib.hMIPcalibPos->GetBinContent(dedxcalib.hMIPcalibPos->FindBin(track.eta()))); } else { - dEdx *= (50.0 / getCalibration(fDeDxVsEta, track)); + dEdx *= (trkSelOpt.dEdxMIPnominal / getCalibration(fDeDxVsEta, track)); } - if (cfgFilldEdxQaHist) { + if (defOpt.filldEdxQaHist) { filldEdxQA(track, collision, dEdx); } } else { - if (applyCalibDeDxFromCCDB) { - dEdx *= (50.0 / dedxcalib.hMIPcalibNeg->GetBinContent(dedxcalib.hMIPcalibNeg->FindBin(track.eta()))); + if (defOpt.applyCalibDeDxFromCCDB && dedxcalib.lCalibLoaded) { + dEdx *= (trkSelOpt.dEdxMIPnominal / dedxcalib.hMIPcalibNeg->GetBinContent(dedxcalib.hMIPcalibNeg->FindBin(track.eta()))); } else { - dEdx *= (50.0 / getCalibration(fDeDxVsEta, track)); + dEdx *= (trkSelOpt.dEdxMIPnominal / getCalibration(fDeDxVsEta, track)); } - if (cfgFilldEdxQaHist) { + if (defOpt.filldEdxQaHist) { filldEdxQA(track, collision, dEdx); } } } else { - if (applyCalibDeDxFromCCDB) { - dEdx *= (50.0 / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(track.eta()))); + if (defOpt.applyCalibDeDxFromCCDB && dedxcalib.lCalibLoaded) { + dEdx *= (trkSelOpt.dEdxMIPnominal / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(track.eta()))); } else { - dEdx *= (50.0 / getCalibration(fDeDxVsEta, track)); + dEdx *= (trkSelOpt.dEdxMIPnominal / getCalibration(fDeDxVsEta, track)); } - if (cfgFilldEdxQaHist) { + if (defOpt.filldEdxQaHist) { filldEdxQA(track, collision, dEdx); } } } // PID TPC dEdx - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { if (track.sign() * track.p() > Cnull) { registryData.fill(HIST(Cprefix) + HIST(Ccharge[kPos]) + HIST("hFlatVsPt"), track.eta(), mult, flat, track.p(), track.pt()); registryData.fill(HIST(Cprefix) + HIST(Ccharge[kPos]) + HIST("hdEdx"), track.eta(), mult, flat, track.p(), dEdx); @@ -1105,24 +1117,24 @@ struct FlattenictyPikp { } // TOF pions - if (cfgFillV0Hist) { + if (defOpt.fillV0Hist) { if (selTOFPi(track)) { - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { if (track.sign() * track.p() > Cnull) { - if (cfgStoreThnSparse) { + if (defOpt.storeThnSparse) { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kPos]) + HIST("hPiTof"), track.eta(), mult, flat, track.p(), dEdx); } else { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kPos]) + HIST("hPiTof"), track.eta(), track.p(), dEdx); } } else { - if (cfgStoreThnSparse) { + if (defOpt.storeThnSparse) { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kNeg]) + HIST("hPiTof"), track.eta(), mult, flat, track.p(), dEdx); } else { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kNeg]) + HIST("hPiTof"), track.eta(), track.p(), dEdx); } } } else { - if (cfgStoreThnSparse) { + if (defOpt.storeThnSparse) { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kAll]) + HIST("hPiTof"), track.eta(), mult, flat, track.p(), dEdx); } else { registryData.fill(HIST(CprefixCleanTof) + HIST(Ccharge[kAll]) + HIST("hPiTof"), track.eta(), track.p(), dEdx); @@ -1133,9 +1145,9 @@ struct FlattenictyPikp { } // V0s - if (cfgFillV0Hist) { + if (defOpt.fillV0Hist) { for (const auto& v0 : v0s) { - if (v0.v0Type() != v0SelOpt.cfgV0TypeSel && v0SelOpt.cfgV0TypeSel > -1) { + if (v0.v0Type() != v0SelOpt.v0TypeSel && v0SelOpt.v0TypeSel > -1) { continue; } if (!isGoodV0Track(v0, tracks, magField)) { @@ -1147,22 +1159,22 @@ struct FlattenictyPikp { float dEdxPos = posTrack.tpcSignal(); float dEdxNeg = negTrack.tpcSignal(); - if (applyCalibDeDx) { - if (cfgFillChrgTypeV0s) { - if (applyCalibDeDxFromCCDB) { - dEdxPos *= (50.0 / dedxcalib.hMIPcalibPos->GetBinContent(dedxcalib.hMIPcalibPos->FindBin(posTrack.eta()))); - dEdxNeg *= (50.0 / dedxcalib.hMIPcalibNeg->GetBinContent(dedxcalib.hMIPcalibNeg->FindBin(negTrack.eta()))); + if (defOpt.applyCalibDeDx) { + if (defOpt.fillChrgTypeV0s) { + if (defOpt.applyCalibDeDxFromCCDB && dedxcalib.lCalibLoaded) { + dEdxPos *= (trkSelOpt.dEdxMIPnominal / dedxcalib.hMIPcalibPos->GetBinContent(dedxcalib.hMIPcalibPos->FindBin(posTrack.eta()))); + dEdxNeg *= (trkSelOpt.dEdxMIPnominal / dedxcalib.hMIPcalibNeg->GetBinContent(dedxcalib.hMIPcalibNeg->FindBin(negTrack.eta()))); } else { - dEdxPos *= (50.0 / getCalibration(fDeDxVsEta, posTrack)); - dEdxNeg *= (50.0 / getCalibration(fDeDxVsEta, negTrack)); + dEdxPos *= (trkSelOpt.dEdxMIPnominal / getCalibration(fDeDxVsEta, posTrack)); + dEdxNeg *= (trkSelOpt.dEdxMIPnominal / getCalibration(fDeDxVsEta, negTrack)); } } else { - if (applyCalibDeDxFromCCDB) { - dEdxPos *= (50.0 / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(posTrack.eta()))); - dEdxNeg *= (50.0 / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(negTrack.eta()))); + if (defOpt.applyCalibDeDxFromCCDB && dedxcalib.lCalibLoaded) { + dEdxPos *= (trkSelOpt.dEdxMIPnominal / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(posTrack.eta()))); + dEdxNeg *= (trkSelOpt.dEdxMIPnominal / dedxcalib.hMIPcalibAll->GetBinContent(dedxcalib.hMIPcalibAll->FindBin(negTrack.eta()))); } else { - dEdxPos *= (50.0 / getCalibration(fDeDxVsEta, posTrack)); - dEdxNeg *= (50.0 / getCalibration(fDeDxVsEta, negTrack)); + dEdxPos *= (trkSelOpt.dEdxMIPnominal / getCalibration(fDeDxVsEta, posTrack)); + dEdxNeg *= (trkSelOpt.dEdxMIPnominal / getCalibration(fDeDxVsEta, negTrack)); } } } @@ -1171,39 +1183,39 @@ struct FlattenictyPikp { fillV0QA(v0, posTrack); fillV0QA(v0, negTrack); // float dEdxPosGa{-1.}, dEdxNegGa{-1.}; - if (applyCalibDeDx) { - if (cfgFillChrgTypeV0s) { - if (applyCalibDeDxFromCCDB) { + if (defOpt.applyCalibDeDx) { + if (defOpt.fillChrgTypeV0s) { + if (defOpt.applyCalibDeDxFromCCDB && dedxcalib.lCalibLoaded) { float dEdxPosGa = dedxcalib.hMIPcalibPos->GetBinContent(dedxcalib.hMIPcalibPos->FindBin(posTrack.eta())); float dEdxNegGa = dedxcalib.hMIPcalibNeg->GetBinContent(dedxcalib.hMIPcalibNeg->FindBin(negTrack.eta())); - if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.cfgdEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.cfgdEdxPlateauSel) { + if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.dEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.dEdxPlateauSel) { continue; } } else { float dEdxPosGa = getCalibration(fEDeDxVsEta, posTrack); float dEdxNegGa = getCalibration(fEDeDxVsEta, negTrack); - if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.cfgdEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.cfgdEdxPlateauSel) { + if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.dEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.dEdxPlateauSel) { continue; } } } else { - if (applyCalibDeDxFromCCDB) { + if (defOpt.applyCalibDeDxFromCCDB && dedxcalib.lCalibLoaded) { float dEdxPosGa = dedxcalib.hPlateauCalibAll->GetBinContent(dedxcalib.hPlateauCalibAll->FindBin(posTrack.eta())); float dEdxNegGa = dedxcalib.hPlateauCalibAll->GetBinContent(dedxcalib.hPlateauCalibAll->FindBin(negTrack.eta())); - if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.cfgdEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.cfgdEdxPlateauSel) { + if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.dEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.dEdxPlateauSel) { continue; } } else { float dEdxPosGa = getCalibration(fEDeDxVsEta, posTrack); float dEdxNegGa = getCalibration(fEDeDxVsEta, negTrack); - if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.cfgdEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.cfgdEdxPlateauSel) { + if (std::abs(dEdxPos - dEdxPosGa) >= v0SelOpt.dEdxPlateauSel || std::abs(dEdxNeg - dEdxNegGa) >= v0SelOpt.dEdxPlateauSel) { continue; } } } } - if (cfgStoreThnSparse) { - if (cfgFillChrgType) { + if (defOpt.storeThnSparse) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hEV0"), posTrack.eta(), mult, flat, posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hEV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1211,7 +1223,7 @@ struct FlattenictyPikp { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kAll]) + HIST("hEV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } } else { - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hEV0"), posTrack.eta(), posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hEV0"), negTrack.eta(), negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1223,8 +1235,8 @@ struct FlattenictyPikp { if (selectTypeV0s(collision, v0, posTrack, negTrack) == kKz) { // K0S -> pi + pi fillV0QA(v0, posTrack); fillV0QA(v0, negTrack); - if (cfgStoreThnSparse) { - if (cfgFillChrgType) { + if (defOpt.storeThnSparse) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPiV0"), posTrack.eta(), mult, flat, posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPiV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1232,7 +1244,7 @@ struct FlattenictyPikp { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kAll]) + HIST("hPiV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } } else { - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPiV0"), posTrack.eta(), posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPiV0"), negTrack.eta(), negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1244,8 +1256,8 @@ struct FlattenictyPikp { if (selectTypeV0s(collision, v0, posTrack, negTrack) == kLam) { // L -> p + pi- fillV0QA(v0, negTrack); fillV0QA(v0, posTrack); - if (cfgStoreThnSparse) { - if (cfgFillChrgType) { + if (defOpt.storeThnSparse) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPV0"), posTrack.eta(), mult, flat, posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPiV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1253,7 +1265,7 @@ struct FlattenictyPikp { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kAll]) + HIST("hPiV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } } else { - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPV0"), posTrack.eta(), posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPiV0"), negTrack.eta(), negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1265,8 +1277,8 @@ struct FlattenictyPikp { if (selectTypeV0s(collision, v0, posTrack, negTrack) == kaLam) { // antiLambda -> pbar + pi+ fillV0QA(v0, posTrack); fillV0QA(v0, negTrack); - if (cfgStoreThnSparse) { - if (cfgFillChrgType) { + if (defOpt.storeThnSparse) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPiV0"), posTrack.eta(), mult, flat, posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1274,7 +1286,7 @@ struct FlattenictyPikp { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kAll]) + HIST("hPV0"), negTrack.eta(), mult, flat, negTrack.sign() * negTrack.p(), dEdxNeg); } } else { - if (cfgFillChrgType) { + if (defOpt.fillChrgType) { registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kPos]) + HIST("hPiV0"), posTrack.eta(), posTrack.sign() * posTrack.p(), dEdxPos); registryData.fill(HIST(CprefixCleanV0) + HIST(Ccharge[kNeg]) + HIST("hPV0"), negTrack.eta(), negTrack.sign() * negTrack.p(), dEdxNeg); } else { @@ -1336,7 +1348,7 @@ struct FlattenictyPikp { if (!particle.isPhysicalPrimary()) { continue; } - if (std::abs(particle.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { continue; } nCharged++; @@ -1377,7 +1389,7 @@ struct FlattenictyPikp { template int countTracks(T const& tracks, C const& collision, aod::BCsWithTimestamps const& /*bcs*/, float mult) { - if (trkSelOpt.cfgRejectTrkAtTPCSector || v0SelOpt.cfgRejectV0sAtTPCSector || applyCalibGain || applyCalibVtx) { + if (trkSelOpt.rejectTrkAtTPCSector || v0SelOpt.rejectV0sAtTPCSector || defOpt.applyCalibGainFromCCDB || defOpt.applyCalibVtxFromCCDB) { auto bc = collision.template bc_as(); int currentRun = bc.runNumber(); if (runNumber != currentRun) { @@ -1388,7 +1400,7 @@ struct FlattenictyPikp { auto nTrk = 0; for (auto const& track : tracks) { - if (!isGoodTrack(track, magField)) { + if (!isGoodTrack(track, magField)) { continue; } nTrk++; @@ -1417,7 +1429,7 @@ struct FlattenictyPikp { template inline void fillNclVsPhiCutQaHist(T const& track, const float phimodn) { - if (cfgFillNclVsPhiCutQaHist) { + if (defOpt.fillNclVsPhiCutQaHist) { registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPtPhi"), track.pt(), phimodn); registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPtPhiNclTPC"), track.eta(), track.pt(), phimodn, track.tpcNClsFound()); registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPtPhiNclPIDTPC"), track.eta(), track.pt(), phimodn, track.tpcNClsPID()); @@ -1428,54 +1440,62 @@ struct FlattenictyPikp { } } - template - bool isGoodTrack(T const& track, const int magfield) + template + bool isGoodTrack(T const& track, const float magfield) { registryData.fill(HIST("Tracks/hTrkSel"), trkSelAll); - if (std::abs(track.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(track.eta()) > trkSelOpt.trkEtaMax) { return false; } registryData.fill(HIST("Tracks/hTrkSel"), trkSelEta); - if (track.pt() < trkSelOpt.cfgTrkPtMin) { + if (track.pt() < trkSelOpt.trkPtMin) { return false; } registryData.fill(HIST("Tracks/hTrkSel"), trkSelPt); - if (!isDCAxyCut(track)) { - return false; + if constexpr (selDCA) { + if (!isDCAxyCut(track)) { + return false; + } + registryData.fill(HIST("Tracks/hTrkSel"), trkSelDCA); + if (defOpt.applyDCAParam) { + if (defOpt.applyDCAParamFromCCDB) { + if (!isDCAParamCut(track)) { + return false; + } + } else { + if (std::fabs(track.dcaXY()) > trkSelOpt.dcaXY.value[0] + trkSelOpt.dcaXY.value[1] * std::pow(track.pt(), trkSelOpt.dcaXY.value[2]) || std::fabs(track.dcaZ()) > trkSelOpt.dcaZ.value[0] + trkSelOpt.dcaZ.value[1] * std::pow(track.pt(), trkSelOpt.dcaZ.value[2])) { + return false; + } + } + registryData.fill(HIST("Tracks/hTrkSel"), trkSelCustomDCA); + } } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelDCA); if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) { return false; } registryData.fill(HIST("Tracks/hTrkSel"), trkNRowsTPC); - if (trkSelOpt.cfgApplyNcl && track.tpcNClsFound() < trkSelOpt.cfgNclTPCMin) { + if (trkSelOpt.applyNcl && track.tpcNClsFound() < trkSelOpt.nclTPCMin) { return false; } registryData.fill(HIST("Tracks/hTrkSel"), trkSelNClsFound); - if (trkSelOpt.cfgApplyNclPID && track.tpcNClsPID() < trkSelOpt.cfgNclPidTPCMin) { + if (trkSelOpt.applyNclPID && track.tpcNClsPID() < trkSelOpt.nclPidTPCMin) { return false; } registryData.fill(HIST("Tracks/hTrkSel"), trkSelNClsPID); float phimodn = track.phi(); phiMod(phimodn, magfield, track.sign()); - if (cfgFillNclVsPhiCutQaHist) { + if (defOpt.fillNclVsPhiCutQaHist) { fillNclVsPhiCutQaHist(track, phimodn); } - if (trkSelOpt.cfgRejectTrkAtTPCSector && (track.pt() >= trkSelOpt.cfgPhiCutPtMin && phimodn < fPhiCutHigh->Eval(track.pt()) && phimodn > fPhiCutLow->Eval(track.pt()))) { + if (trkSelOpt.rejectTrkAtTPCSector && (track.pt() >= trkSelOpt.phiCutPtMin && phimodn < fPhiCutHigh->Eval(track.pt()) && phimodn > fPhiCutLow->Eval(track.pt()))) { return false; } - if (cfgFillNclVsPhiCutQaHist) { + if (defOpt.fillNclVsPhiCutQaHist) { fillNclVsPhiCutQaHist(track, phimodn); } registryData.fill(HIST("Tracks/hTrkSel"), trkSelTPCBndr); - if (trkSelOpt.cfgApplyCustomDCASel) { - if (std::fabs(track.dcaXY()) > trkSelOpt.cfgDcaXY.value[0] + trkSelOpt.cfgDcaXY.value[1] * std::pow(track.pt(), trkSelOpt.cfgDcaXY.value[2]) || std::fabs(track.dcaZ()) > trkSelOpt.cfgDcaZ.value[0] + trkSelOpt.cfgDcaZ.value[1] * std::pow(track.pt(), trkSelOpt.cfgDcaZ.value[2])) { - return false; - } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelCustomDCA); - } return true; } @@ -1496,30 +1516,30 @@ struct FlattenictyPikp { bool isMassL = false; bool isMassAL = false; - if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) > v0SelOpt.cfgdmassK && std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.cfgdmassL && std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.cfgdmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) < v0SelOpt.cfgdmassG) { + if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) > v0SelOpt.dmassK && std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.dmassL && std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.dmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) < v0SelOpt.dmassG) { isMassG = true; } - if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0SelOpt.cfgdmassK && std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.cfgdmassL && std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.cfgdmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) > v0SelOpt.cfgdmassG) { + if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) < v0SelOpt.dmassK && std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.dmassL && std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) > v0SelOpt.dmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) > v0SelOpt.dmassG) { isMassK0s = true; } - if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) > v0SelOpt.cfgdmassK && std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) < v0SelOpt.cfgdmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) > v0SelOpt.cfgdmassG) { + if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) > v0SelOpt.dmassK && std::abs(v0.mLambda() - o2::constants::physics::MassLambda0) < v0SelOpt.dmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) > v0SelOpt.dmassG) { isMassL = true; } - if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) > v0SelOpt.cfgdmassK && std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) < v0SelOpt.cfgdmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) > v0SelOpt.cfgdmassG) { + if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0Short) > v0SelOpt.dmassK && std::abs(v0.mAntiLambda() - o2::constants::physics::MassLambda0) < v0SelOpt.dmassL && std::abs(v0.mGamma() - o2::constants::physics::MassGamma) > v0SelOpt.dmassG) { isMassAL = true; } // Gamma selection if (isMassG) { - if (std::abs(RecoDecay::y(std::array{v0.px(), v0.py(), v0.pz()}, o2::constants::physics::MassGamma)) < v0SelOpt.cfgV0Ymax) { // rapidity cut - if (std::abs(v0.alpha()) < v0SelOpt.cfgArmPodGammasalpha && v0.qtarm() < v0SelOpt.cfgArmPodGammasqT) { // - if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaEl()) < v0SelOpt.cfgNsigmaElTPC) { - if (postrk.hasTOF() && std::abs(postrk.tofNSigmaEl()) < v0SelOpt.cfgNsigmaElTOF) { + if (std::abs(RecoDecay::y(std::array{v0.px(), v0.py(), v0.pz()}, o2::constants::physics::MassGamma)) < v0SelOpt.v0Ymax) { // rapidity cut + if (std::abs(v0.alpha()) < v0SelOpt.armPodGammasalpha && v0.qtarm() < v0SelOpt.armPodGammasqT) { // + if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaEl()) < v0SelOpt.nsigmaElTPC) { + if (postrk.hasTOF() && std::abs(postrk.tofNSigmaEl()) < v0SelOpt.nsigmaElTOF) { return kGa; } } - if (negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaEl()) < v0SelOpt.cfgNsigmaElTPC) { - if (negtrk.hasTOF() && std::abs(negtrk.tofNSigmaEl()) < v0SelOpt.cfgNsigmaElTOF) { + if (negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaEl()) < v0SelOpt.nsigmaElTPC) { + if (negtrk.hasTOF() && std::abs(negtrk.tofNSigmaEl()) < v0SelOpt.nsigmaElTOF) { return kGa; } } @@ -1528,16 +1548,16 @@ struct FlattenictyPikp { } // K0S selection, K0S -> pi + pi if (isMassK0s) { - if (std::abs(v0.yK0Short()) < v0SelOpt.cfgV0Ymax) { // rapidity cut - if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0SelOpt.cfgcTauK0s) { // ctau cut - if (v0.v0cosPA() >= v0SelOpt.cfgCosPAK0s && v0.v0radius() >= v0SelOpt.cfgV0radiusK0s && v0.qtarm() * v0SelOpt.cfgArmPodK0s > std::abs(v0.alpha())) { // - if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC) { - if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF) { + if (std::abs(v0.yK0Short()) < v0SelOpt.v0Ymax) { // rapidity cut + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0SelOpt.cTauK0s) { // ctau cut + if (v0.v0cosPA() >= v0SelOpt.cosPAK0s && v0.v0radius() >= v0SelOpt.v0radiusK0s && v0.qtarm() * v0SelOpt.armPodK0s > std::abs(v0.alpha())) { // + if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPi()) < v0SelOpt.nsigmaPiTPC) { + if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPi()) < v0SelOpt.nsigmaPiTOF) { return kKz; } } - if (negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC) { - if (negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF) { + if (negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPi()) < v0SelOpt.nsigmaPiTPC) { + if (negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPi()) < v0SelOpt.nsigmaPiTOF) { return kKz; } } @@ -1547,11 +1567,11 @@ struct FlattenictyPikp { } // Lambda selection, L -> p + pi- if (isMassL) { - if (std::abs(v0.yLambda()) < v0SelOpt.cfgV0Ymax) { // rapidity cut - if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < v0SelOpt.cfgcTauLambda) { // ctau cut - if (v0.v0cosPA() >= v0SelOpt.cfgCosPALambda && v0.v0radius() >= v0SelOpt.cfgV0radiusLambda) { // - if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPr()) < v0SelOpt.cfgNsigmaPrTPC && negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC) { - if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPr()) < v0SelOpt.cfgNsigmaPrTOF && negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF) { + if (std::abs(v0.yLambda()) < v0SelOpt.v0Ymax) { // rapidity cut + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < v0SelOpt.cTauLambda) { // ctau cut + if (v0.v0cosPA() >= v0SelOpt.cosPALambda && v0.v0radius() >= v0SelOpt.v0radiusLambda) { // + if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPr()) < v0SelOpt.nsigmaPrTPC && negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPi()) < v0SelOpt.nsigmaPiTPC) { + if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPr()) < v0SelOpt.nsigmaPrTOF && negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPi()) < v0SelOpt.nsigmaPiTOF) { return kLam; } } @@ -1561,11 +1581,11 @@ struct FlattenictyPikp { } // antiLambda -> pbar + pi+ if (isMassAL) { - if (std::abs(v0.yLambda()) < v0SelOpt.cfgV0Ymax) { // rapidity cut - if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < v0SelOpt.cfgcTauLambda) { // ctau cut - if (v0.v0cosPA() >= v0SelOpt.cfgCosPALambda && v0.v0radius() >= v0SelOpt.cfgV0radiusLambda) { // - if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPi()) < v0SelOpt.cfgNsigmaPiTPC && negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPr()) < v0SelOpt.cfgNsigmaPrTPC) { - if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPi()) < v0SelOpt.cfgNsigmaPiTOF && negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPr()) < v0SelOpt.cfgNsigmaPrTOF) { + if (std::abs(v0.yLambda()) < v0SelOpt.v0Ymax) { // rapidity cut + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0 < v0SelOpt.cTauLambda) { // ctau cut + if (v0.v0cosPA() >= v0SelOpt.cosPALambda && v0.v0radius() >= v0SelOpt.v0radiusLambda) { // + if (postrk.hasTPC() && std::abs(postrk.tpcNSigmaPi()) < v0SelOpt.nsigmaPiTPC && negtrk.hasTPC() && std::abs(negtrk.tpcNSigmaPr()) < v0SelOpt.nsigmaPrTPC) { + if (postrk.hasTOF() && std::abs(postrk.tofNSigmaPi()) < v0SelOpt.nsigmaPiTOF && negtrk.hasTOF() && std::abs(negtrk.tofNSigmaPr()) < v0SelOpt.nsigmaPrTOF) { return kaLam; } } @@ -1577,7 +1597,7 @@ struct FlattenictyPikp { } template - bool isGoodV0Track(T1 const& v0, T2 const& /*track*/, const int magfield) + bool isGoodV0Track(T1 const& v0, T2 const& /*track*/, const float magfield) { const auto& posTrack = v0.template posTrack_as(); const auto& negTrack = v0.template negTrack_as(); @@ -1592,22 +1612,22 @@ struct FlattenictyPikp { float negTrackPhiModn = negTrack.phi(); phiMod(posTrackPhiModn, magfield, posTrack.sign()); phiMod(negTrackPhiModn, magfield, negTrack.sign()); - if (v0SelOpt.cfgRejectV0sAtTPCSector) { - if ((posTrack.pt() >= trkSelOpt.cfgPhiCutPtMin && posTrackPhiModn < fPhiCutHigh->Eval(posTrack.pt()) && posTrackPhiModn > fPhiCutLow->Eval(posTrack.pt())) && (negTrack.pt() >= trkSelOpt.cfgPhiCutPtMin && negTrackPhiModn < fPhiCutHigh->Eval(negTrack.pt()) && negTrackPhiModn > fPhiCutLow->Eval(negTrack.pt()))) { + if (v0SelOpt.rejectV0sAtTPCSector) { + if ((posTrack.pt() >= trkSelOpt.phiCutPtMin && posTrackPhiModn < fPhiCutHigh->Eval(posTrack.pt()) && posTrackPhiModn > fPhiCutLow->Eval(posTrack.pt())) && (negTrack.pt() >= trkSelOpt.phiCutPtMin && negTrackPhiModn < fPhiCutHigh->Eval(negTrack.pt()) && negTrackPhiModn > fPhiCutLow->Eval(negTrack.pt()))) { return false; } } registryData.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelRejectV0sAtTPCSector); // V0 topological selections - if (v0.v0cosPA() < v0SelOpt.cfgv0cospa) { + if (v0.v0cosPA() < v0SelOpt.v0cospa) { return false; } registryData.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelCosPA); - if (v0.v0radius() < v0SelOpt.cfgv0Rmin || v0.v0radius() > v0SelOpt.cfgv0Rmax) { + if (v0.v0radius() < v0SelOpt.v0Rmin || v0.v0radius() > v0SelOpt.v0Rmax) { return false; } registryData.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelV0radius); - if (std::abs(v0.dcapostopv()) < v0SelOpt.cfgDCAposToPV || std::abs(v0.dcanegtopv()) < v0SelOpt.cfgDCAnegToPV) { + if (std::abs(v0.dcapostopv()) < v0SelOpt.dcaPosToPV || std::abs(v0.dcanegtopv()) < v0SelOpt.dcaNegToPV) { return false; } registryData.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelDCAposToPV); @@ -1616,7 +1636,7 @@ struct FlattenictyPikp { return false; } registryData.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelDaughters); - if (v0.dcaV0daughters() > v0SelOpt.cfgDCAv0daughter) { + if (v0.dcaV0daughters() > v0SelOpt.dcaV0daughter) { return false; } registryData.fill(HIST("Tracks/V0qa/hV0Sel"), v0SelDCAv0daughter); @@ -1630,38 +1650,38 @@ struct FlattenictyPikp { template bool isGoodV0DaughterTrack(const T& track) { - if (track.eta() < v0SelOpt.cfgV0etamin || track.eta() > v0SelOpt.cfgV0etamax) { + if (track.eta() < v0SelOpt.v0etamin || track.eta() > v0SelOpt.v0etamax) { return false; } if (!track.hasTPC()) { return false; } - if (track.tpcNClsCrossedRows() < v0SelOpt.cfgminNCrossedRowsTPC) { + if (track.tpcNClsCrossedRows() < v0SelOpt.v0minNCrossedRowsTPC) { return false; } - if (track.tpcCrossedRowsOverFindableCls() < v0SelOpt.cfgminNCrossedRowsOverFindableClustersTPC) { + if (track.tpcCrossedRowsOverFindableCls() < v0SelOpt.v0minNCrossedRowsOverFindableClustersTPC) { return false; } - if (v0SelOpt.cfgApplyV0sNclFound) { - if (track.tpcNClsFound() < v0SelOpt.cfgV0NclTPCMin) { + if (v0SelOpt.applyV0sNclFound) { + if (track.tpcNClsFound() < v0SelOpt.v0NclTPCMin) { return false; } } - if (v0SelOpt.cfgApplyV0sNclPID) { - if (track.tpcNClsPID() < v0SelOpt.cfgV0NclPidTPCMin) { + if (v0SelOpt.applyV0sNclPID) { + if (track.tpcNClsPID() < v0SelOpt.v0NclPidTPCMin) { return false; } } - if (track.tpcChi2NCl() > v0SelOpt.cfgmaxChi2PerClusterTPC) { + if (track.tpcChi2NCl() > v0SelOpt.v0maxChi2PerClusterTPC) { return false; } - if (v0SelOpt.cfgRequireITS && (!track.hasITS())) { + if (v0SelOpt.v0requireITS && (!track.hasITS())) { return false; } - if (v0SelOpt.cfgRequireITS && track.itsNCls() < v0SelOpt.cfgminITSnClusters) { + if (v0SelOpt.v0requireITS && track.itsNCls() < v0SelOpt.v0minITSnClusters) { return false; } - if (track.itsChi2NCl() > v0SelOpt.cfgmaxChi2PerClusterITS) { + if (track.itsChi2NCl() > v0SelOpt.v0maxChi2PerClusterITS) { return false; } return true; @@ -1693,11 +1713,11 @@ struct FlattenictyPikp { } registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hTOFPvsBeta"), track.p(), track.beta()); - if (track.beta() > trkSelOpt.cfgTOFBetaPion && track.beta() < trkSelOpt.cfgTOFBetaPion + 0.05) { // TOF pions + if (track.beta() > trkSelOpt.tofBetaPion && track.beta() < trkSelOpt.tofBetaPion + 0.05) { // TOF pions registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hTOFpi"), track.eta(), track.p(), track.tpcSignal()); } - if (std::abs(track.eta()) < trkSelOpt.cfgTrkEtaMax) { + if (std::abs(track.eta()) < trkSelOpt.trkEtaMax) { if (isDCAxyWoCut(track)) { registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPtVsWOcutDCA"), track.pt(), track.dcaXY()); } @@ -1712,9 +1732,9 @@ struct FlattenictyPikp { const float mult = getMult(collision); const float flat = fillFlat(collision); if constexpr (fillHist) { - if (track.p() >= trkSelOpt.cfgMomMIPMin && track.p() <= trkSelOpt.cfgMomMIPMax) { - if (dEdx > trkSelOpt.cfgDeDxMIPMin && dEdx < trkSelOpt.cfgDeDxMIPMax) { // MIP pions - if (cfgStoreThnSparse) { + if (track.p() >= trkSelOpt.momMIPMin && track.p() <= trkSelOpt.momMIPMax) { + if (dEdx > trkSelOpt.dEdxMIPMin && dEdx < trkSelOpt.dEdxMIPMax) { // MIP pions + if (defOpt.storeThnSparse) { registryData.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hMIP"), mult, flat, track.eta(), dEdx); } else { registryData.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hMIP"), track.eta(), dEdx); @@ -1724,9 +1744,9 @@ struct FlattenictyPikp { registryData.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hMIPVsPhiVsEta"), track.phi(), dEdx, track.eta()); registryData.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hMIPNClTPCPidvsEta"), track.eta(), track.tpcNClsPID()); } - if (dEdx > trkSelOpt.cfgDeDxMIPMax + 10. && dEdx < trkSelOpt.cfgDeDxMIPMax + 30.) { // Plateau electrons - if (std::abs(track.beta() - 1) < trkSelOpt.cfgBetaPlateuMax) { - if (cfgStoreThnSparse) { + if (dEdx > trkSelOpt.dEdxMIPMax + 10. && dEdx < trkSelOpt.dEdxMIPMax + 30.) { // Plateau electrons + if (std::abs(track.beta() - 1) < trkSelOpt.betaPlateuMax) { + if (defOpt.storeThnSparse) { registryData.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hPlateau"), mult, flat, track.eta(), dEdx); } else { registryData.fill(HIST(Cprefix) + HIST(CstatCalib[ft]) + HIST(Ccharge[chrg]) + HIST("hPlateau"), track.eta(), dEdx); @@ -1747,7 +1767,7 @@ struct FlattenictyPikp { if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelAll); } - if (evtSelOpt.cfgCustomTVX) { + if (evtSelOpt.customTVX) { if (!collision.selection_bit(aod::evsel::kIsTriggerTVX)) { return false; } @@ -1759,43 +1779,43 @@ struct FlattenictyPikp { if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelSel8); } - if (evtSelOpt.cfgRemoveITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + if (evtSelOpt.removeITSROFrameBorder && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { return false; } if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelNoITSROFrameBorder); } - if (evtSelOpt.cfgRemoveNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + if (evtSelOpt.removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { return false; } if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelkNoTimeFrameBorder); } - if (evtSelOpt.cfgRemoveNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + if (evtSelOpt.removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { return false; } if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelkNoSameBunchPileup); } - if (evtSelOpt.cfgRequireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + if (evtSelOpt.requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { return false; } if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelkIsGoodZvtxFT0vsPV); } - if (evtSelOpt.cfgRequireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) { + if (evtSelOpt.requireIsVertexITSTPC && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) { return false; } if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelkIsVertexITSTPC); } - if (evtSelOpt.cfgRequirekIsVertexTOFmatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { + if (evtSelOpt.requirekIsVertexTOFmatched && !collision.selection_bit(aod::evsel::kIsVertexTOFmatched)) { return false; } if constexpr (fillHist) { registryQC.fill(HIST("Events/hEvtSel"), evtSelkIsVertexTOFmatched); } - if (std::abs(collision.posZ()) > evtSelOpt.cfgCutVtxZ) { + if (std::abs(collision.posZ()) > evtSelOpt.cutVtxZ) { return false; } if constexpr (fillHist) { @@ -1917,7 +1937,7 @@ struct FlattenictyPikp { float getMult(C const& collision) { float val = -999.0; - switch (multEst) { + switch (defOpt.multEst) { case MultE::CnoMult: return val; break; @@ -1932,7 +1952,7 @@ struct FlattenictyPikp { if constexpr (!isMC) { return collision.multTPC(); } else { - LOG(fatal) << "No valid multiplicity estimator: " << multEst; + LOG(fatal) << "No valid multiplicity estimator: " << defOpt.multEst; return val; } break; @@ -1999,13 +2019,13 @@ struct FlattenictyPikp { if constexpr (fillHist) { registryQC.fill(HIST("FV0/hFV0amp"), chv0, amplCh); registryQC.fill(HIST("FV0/pFV0amp"), chv0, amplCh); - if (applyCalibGain) { + if (defOpt.applyCalibGainFromCCDB) { registryQC.fill(HIST("FV0/hFV0ampCorr"), chv0, amplCh / fv0AmplCorr[chv0]); registryQC.fill(HIST("FV0/pFV0ampCorr"), chv0, amplCh / fv0AmplCorr[chv0]); } } if (amplCh > Cnull) { - if (applyCalibGain) { // equalize gain channel-by-channel + if (defOpt.applyCalibGainFromCCDB) { // equalize gain channel-by-channel amplCh /= fv0AmplCorr[chv0]; } if (chv0phi > Cnull) { @@ -2021,7 +2041,7 @@ struct FlattenictyPikp { if constexpr (fillHist) { registryQC.fill(HIST("FV0/hFV0AmplvsVtxzWoCalib"), collision.posZ(), rhoLatticeFV0[chv0phi]); } - if (applyCalibVtx) { + if (defOpt.applyCalibVtxFromCCDB) { rhoLatticeFV0[chv0phi] *= zVtxMap->GetBinContent(zVtxMap->GetXaxis()->FindBin(chv0phi), zVtxMap->GetYaxis()->FindBin(collision.posZ())); if constexpr (fillHist) { registryQC.fill(HIST("FV0/hFV0AmplvsVtxzCalib"), collision.posZ(), rhoLatticeFV0[chv0phi]); @@ -2037,6 +2057,27 @@ struct FlattenictyPikp { return oneMinusFlat; } + template + bool isDCAParamCut(T const& track) const + { + const float dcaXY = track.dcaXY(); + const float dcaZ = track.dcaZ(); + const float pt = track.pt(); + float selDCAxy = 0.f; + float selDCAz = 0.f; + + if (dcaparam.lCalibLoaded) { + selDCAxy = dcaparam.hDCAxyParam->GetBinContent(1) + dcaparam.hDCAxyParam->GetBinContent(2) / std::pow(std::abs(pt), dcaparam.hDCAxyParam->GetBinContent(3)); + selDCAxy *= trkSelOpt.nsigmaDCAxy.value; + selDCAz = dcaparam.hDCAzParam->GetBinContent(1) + dcaparam.hDCAzParam->GetBinContent(2) / std::pow(std::abs(pt), dcaparam.hDCAzParam->GetBinContent(3)); + selDCAz *= trkSelOpt.nsigmaDCAz.value; + if (std::abs(dcaXY) > selDCAxy || std::abs(dcaZ) > selDCAz) { + return false; + } + } + return true; + } + template bool isDCAxyCut(T const& track) const { @@ -2091,7 +2132,7 @@ struct FlattenictyPikp { auto v0sPerCollision = v0s.sliceBy(perColV0s, collision.globalIndex()); v0sPerCollision.bindExternalIndices(&tracks); filldEdx(tracksPerCollision, v0sPerCollision, collision, bcs); - if (cfgFillDCAxyHist) { + if (defOpt.fillDCAxyHist) { static_for<0, 4>([&](auto i) { fillDCA(tracksPerCollision, collision, bcs); }); @@ -2251,10 +2292,10 @@ struct FlattenictyPikp { if (!isChrgParticle(mcParticle.pdgCode())) { return; } - if (std::abs(mcParticle.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(mcParticle.eta()) > trkSelOpt.trkEtaMax) { return; } - if (mcParticle.pt() < trkSelOpt.cfgTrkPtMin) { + if (mcParticle.pt() < trkSelOpt.trkPtMin) { return; } if (!isPID(mcParticle)) { @@ -2359,7 +2400,7 @@ struct FlattenictyPikp { { LOGP(debug, "MC col {} has {} reco cols", mcCollision.globalIndex(), collisions.size()); auto multMC = -1.; - if (evtSelOpt.useMultMCmidrap || multEst == CtwoInt) { // use generated Nch in ∣eta∣ < 0.8 + if (evtSelOpt.useMultMCmidrap || defOpt.multEst == CtwoInt) { // use generated Nch in ∣eta∣ < 0.8 multMC = countPart(particles); } else { multMC = getMultMC(mcCollision); // using McCentFT0Ms @@ -2370,7 +2411,7 @@ struct FlattenictyPikp { // Loop on rec collisions // Obtain here: Numerator of tracking efficiency; Secondary contamination correction for (const auto& collision : collisions) { - if (trkSelOpt.cfgRejectTrkAtTPCSector || applyCalibGain || applyCalibVtx) { + if (trkSelOpt.rejectTrkAtTPCSector || defOpt.applyCalibGainFromCCDB || defOpt.applyCalibVtxFromCCDB) { auto bc = collision.bc_as(); int currentRun = bc.runNumber(); if (runNumber != currentRun) { @@ -2379,7 +2420,7 @@ struct FlattenictyPikp { } } registryMC.fill(HIST("Events/hCentVsFlatRecINELgt0"), getMult(collision), fillFlat(collision)); // Evt split den - if (evtSelOpt.cfgRemoveSplitVertex && collision.globalIndex() != mcCollision.bestCollisionIndex()) { + if (evtSelOpt.removeSplitVertex && collision.globalIndex() != mcCollision.bestCollisionIndex()) { continue; } registryMC.fill(HIST("Events/hCentVsFlatRecINELgt0wRecEvt"), getMult(collision), fillFlat(collision)); // Evt split num, w/ Nrec > 0 @@ -2391,10 +2432,10 @@ struct FlattenictyPikp { if (!particle.isPhysicalPrimary()) { continue; } - if (std::abs(particle.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { continue; } - if (particle.pt() < trkSelOpt.cfgTrkPtMin) { + if (particle.pt() < trkSelOpt.trkPtMin) { continue; } static_for<0, 1>([&](auto pidSgn) { @@ -2423,10 +2464,10 @@ struct FlattenictyPikp { if (!particle.isPhysicalPrimary()) { continue; } - if (std::abs(particle.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { continue; } - if (particle.pt() < trkSelOpt.cfgTrkPtMin) { + if (particle.pt() < trkSelOpt.trkPtMin) { continue; } static_for<0, 1>([&](auto pidSgn) { @@ -2451,24 +2492,7 @@ struct FlattenictyPikp { if (!track.has_collision()) { continue; } - if (std::abs(track.eta()) > trkSelOpt.cfgTrkEtaMax) { - continue; - } - if (track.pt() < trkSelOpt.cfgTrkPtMin) { - continue; - } - if (trkSelOpt.cfgApplyNcl && track.tpcNClsFound() < trkSelOpt.cfgNclTPCMin) { - continue; - } - if (trkSelOpt.cfgApplyNclPID && track.tpcNClsPID() < trkSelOpt.cfgNclPidTPCMin) { - continue; - } - float phiModn = track.phi(); - phiMod(phiModn, magField, track.sign()); - if (trkSelOpt.cfgRejectTrkAtTPCSector && (track.pt() >= trkSelOpt.cfgPhiCutPtMin && phiModn < fPhiCutHigh->Eval(track.pt()) && phiModn > fPhiCutLow->Eval(track.pt()))) { - continue; - } - if (!isDCAxyWoCut(track)) { + if (!isGoodTrack(track, magField)) { continue; } if (!track.has_mcParticle()) { @@ -2482,10 +2506,10 @@ struct FlattenictyPikp { if (!isChrgParticle(particle.pdgCode())) { continue; } - if (std::abs(particle.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { continue; } - if (particle.pt() < trkSelOpt.cfgTrkPtMin) { + if (particle.pt() < trkSelOpt.trkPtMin) { continue; } static_for<0, 1>([&](auto pidSgn) { // for checking purposes only: use gen Nch, gen Flat @@ -2509,10 +2533,10 @@ struct FlattenictyPikp { registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTvsDCAxyAll), multRecGt1, flatRec, track.pt(), track.dcaXY()); } }); - if (isDCAxyCut(track)) { + if (isGoodTrack(track, magField)) { static_for<0, 4>([&](auto i) { constexpr int Cidx = i.value; - if (std::sqrt(std::pow(std::fabs(o2::aod::pidutils::tpcNSigma(track)), 2) + std::pow(std::fabs(o2::aod::pidutils::tofNSigma(track)), 2) < trkSelOpt.cfgDcaNsigmaCombinedMax)) { + if (std::sqrt(std::pow(std::fabs(o2::aod::pidutils::tpcNSigma(track)), 2) + std::pow(std::fabs(o2::aod::pidutils::tofNSigma(track)), 2) < trkSelOpt.dcaNsigmaCombinedMax)) { if (std::fabs(particle.pdgCode()) == pDGs[Cidx]) { if (particle.isPhysicalPrimary()) { registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CdEdxMcRecPrimSel), track.eta(), multRecGt1, flatRec, track.p(), track.tpcSignal()); @@ -2541,10 +2565,10 @@ struct FlattenictyPikp { if (!isChrgParticle(particle.pdgCode())) { continue; } - if (std::abs(particle.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { continue; } - if (particle.pt() < trkSelOpt.cfgTrkPtMin) { + if (particle.pt() < trkSelOpt.trkPtMin) { continue; } static_for<0, 1>([&](auto pidSgn) { @@ -2557,7 +2581,7 @@ struct FlattenictyPikp { // Obtain here: Denominator of signal loss and event loss; MC closure // registryMC.fill(HIST("Events/hEvtMcGen"), 0.5); - if (evtSelOpt.useZVtxCutMC && std::abs(mcCollision.posZ()) > evtSelOpt.cfgCutVtxZ) { + if (evtSelOpt.zVtxCutMC && std::abs(mcCollision.posZ()) > evtSelOpt.cutVtxZ) { return; } registryMC.fill(HIST("Events/hVtxZGen"), mcCollision.posZ()); @@ -2568,7 +2592,7 @@ struct FlattenictyPikp { } } registryMC.fill(HIST("Events/hEvtMcGen"), 2.5); - if (evtSelOpt.cfgUseInelgt0wTVX && !isInelGt0wTVX(particles)) { // TVX trigger: FT0A + FT0C acceptance + if (evtSelOpt.useInelgt0wTVX && !isInelGt0wTVX(particles)) { // TVX trigger: FT0A + FT0C acceptance return; } registryMC.fill(HIST("Events/hEvtMcGen"), 3.5); @@ -2578,10 +2602,10 @@ struct FlattenictyPikp { if (!isChrgParticle(particle.pdgCode())) { continue; } - if (std::abs(particle.eta()) > trkSelOpt.cfgTrkEtaMax) { + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { continue; } - if (particle.pt() < trkSelOpt.cfgTrkPtMin) { + if (particle.pt() < trkSelOpt.trkPtMin) { continue; } static_for<0, 1>([&](auto pidSgn) { From fbbe84842db067d1dc663e19a66f04b10f52e382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Thu, 30 Jul 2026 22:52:50 +0200 Subject: [PATCH 54/71] [Common et all] Fix includes (#17263) --- ALICE3/Tasks/alice3-dilepton.cxx | 9 ++++++--- ALICE3/Tasks/alice3-prefilterdilepton.cxx | 16 ++++++++++++---- ALICE3/Tasks/alice3Multicharm.cxx | 2 -- ALICE3/Utils/a3StrangenessTofPidHelper.h | 2 +- Common/Tasks/checkDataModelMC.cxx | 1 + Common/Tools/PID/pidTPCModule.h | 1 + DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx | 7 ++++++- .../femtoDreamTripletTaskTrackTrackCascade.cxx | 14 ++++++++++++-- PWGDQ/Core/VarManager.cxx | 9 +++++---- PWGDQ/Tasks/tableReader_withAssoc.cxx | 1 + PWGEM/Dilepton/Core/DileptonHadronMPC.h | 1 - PWGEM/Dilepton/Core/DileptonSV.h | 2 ++ PWGEM/Dilepton/Core/DileptonSVMC.h | 2 ++ PWGEM/Dilepton/DataModel/dileptonTables.h | 2 ++ .../TableProducer/Converters/muonConverter4.cxx | 2 ++ PWGEM/Dilepton/TableProducer/skimmerOTS.cxx | 2 ++ .../TableProducer/skimmerPrimaryMuon.cxx | 2 ++ PWGEM/Dilepton/Tasks/dimuonV1.cxx | 2 ++ PWGEM/PhotonMeson/Core/DalitzEECut.h | 1 + PWGEM/PhotonMeson/Core/EMCPhotonCut.h | 1 + PWGEM/PhotonMeson/Core/PHOSPhotonCut.h | 1 + PWGEM/PhotonMeson/Core/V0PhotonCut.h | 1 + .../TableProducer/associateMCinfoPhoton.cxx | 1 + .../TableProducer/bcWiseClusterSkimmer.cxx | 1 + .../PhotonMeson/TableProducer/nonLinProducer.cxx | 1 + PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx | 1 + PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx | 7 +++++++ PWGEM/PhotonMeson/Tasks/emcalPi0Qc.cxx | 1 + PWGEM/PhotonMeson/Tasks/emcalQC.cxx | 1 + PWGEM/PhotonMeson/Tasks/pcmQC.cxx | 1 + PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx | 1 + PWGEM/PhotonMeson/Tasks/photonResoTask.cxx | 1 + PWGEM/PhotonMeson/Tasks/photonhbt.cxx | 1 + PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx | 1 + PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx | 1 + PWGEM/PhotonMeson/Utils/ClusterHistograms.h | 1 + PWGEM/PhotonMeson/Utils/EventHistograms.h | 1 + PWGEM/PhotonMeson/Utils/HNMUtilities.h | 1 + PWGEM/PhotonMeson/Utils/MCUtilities.h | 1 + PWGEM/PhotonMeson/Utils/NMHistograms.h | 1 + PWGEM/PhotonMeson/Utils/PairUtilities.h | 2 +- PWGEM/PhotonMeson/Utils/TrackSelection.h | 1 + .../TableProducer/dataCreatorJpsiHadReduced.cxx | 1 + PWGHF/HFC/Tasks/taskFlow.cxx | 1 - .../candidateCreatorXicToXiPiPi.cxx | 1 + PWGLF/DataModel/LFHStrangeCorrelationTables.h | 2 ++ PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx | 1 + .../Nuspex/deuteronInTriggeredEvents.cxx | 1 - .../Nuspex/nucleiThreeBodyBuilder.cxx | 7 ++++++- .../Nuspex/trackedHypertritonRecoTask.cxx | 2 +- PWGLF/TableProducer/QC/nucleiQC.cxx | 1 - .../Resonances/cksspinalignment.cxx | 3 ++- .../TableProducer/Resonances/doublephitable.cxx | 7 ++++--- .../Converters/stradautrackstofpidconverter4.cxx | 3 +++ .../Strangeness/hStrangeCorrelationFilter.cxx | 3 +++ .../TableProducer/Strangeness/sigma0builder.cxx | 1 + .../Strangeness/strangederivedbuilder.cxx | 5 +++-- .../Strangeness/strangenessbuilder.cxx | 1 + PWGLF/Tasks/Nuspex/nucleitpcPbPb.cxx | 1 + PWGLF/Tasks/Resonances/cksspinalignder.cxx | 7 ++++--- PWGLF/Tasks/Resonances/lambda1405analysis.cxx | 12 +++++------- PWGLF/Tasks/Resonances/phiflowder.cxx | 9 +++++++-- .../Tasks/Strangeness/lambdaspincorrderived.cxx | 1 + PWGLF/Utils/decay3bodyBuilderHelper.h | 1 - PWGLF/Utils/strangenessBuilderModule.h | 1 + PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx | 1 + PWGUD/Tasks/flowCorrelationsUpc.cxx | 3 +-- 67 files changed, 139 insertions(+), 45 deletions(-) diff --git a/ALICE3/Tasks/alice3-dilepton.cxx b/ALICE3/Tasks/alice3-dilepton.cxx index 9efdb686f46..b258a2cff67 100644 --- a/ALICE3/Tasks/alice3-dilepton.cxx +++ b/ALICE3/Tasks/alice3-dilepton.cxx @@ -25,15 +25,18 @@ #include #include #include +#include #include #include #include +#include +#include #include +#include #include -#include -#include -#include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include #include #include #include diff --git a/ALICE3/Tasks/alice3-prefilterdilepton.cxx b/ALICE3/Tasks/alice3-prefilterdilepton.cxx index 7f800eeaf8f..4f45007107e 100644 --- a/ALICE3/Tasks/alice3-prefilterdilepton.cxx +++ b/ALICE3/Tasks/alice3-prefilterdilepton.cxx @@ -14,29 +14,37 @@ /// \author s.scheid@cern.ch, daiki.sekihata@cern.ch /// -#include "ALICE3/DataModel/OTFCollision.h" #include "ALICE3/DataModel/OTFRICH.h" #include "ALICE3/DataModel/OTFTOF.h" #include "ALICE3/DataModel/prefilterDilepton.h" #include "ALICE3/DataModel/tracksAlice3.h" #include "Common/Core/RecoDecay.h" -#include "Common/DataModel/TrackSelectionTables.h" #include #include #include +#include #include +#include #include +#include +#include #include +#include #include -#include #include -#include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include +#include +#include +#include #include #include +#include + using namespace o2; using namespace o2::aod; using namespace o2::soa; diff --git a/ALICE3/Tasks/alice3Multicharm.cxx b/ALICE3/Tasks/alice3Multicharm.cxx index fc4cd76c769..cbdbc95e691 100644 --- a/ALICE3/Tasks/alice3Multicharm.cxx +++ b/ALICE3/Tasks/alice3Multicharm.cxx @@ -23,10 +23,8 @@ #include "ALICE3/DataModel/OTFMulticharm.h" #include "Tools/ML/model.h" -#include #include #include -#include #include #include #include diff --git a/ALICE3/Utils/a3StrangenessTofPidHelper.h b/ALICE3/Utils/a3StrangenessTofPidHelper.h index b39a3fe011e..64620419f43 100644 --- a/ALICE3/Utils/a3StrangenessTofPidHelper.h +++ b/ALICE3/Utils/a3StrangenessTofPidHelper.h @@ -20,7 +20,7 @@ #include "ALICE3/Core/TrackUtilities.h" #include -#include +#include #include diff --git a/Common/Tasks/checkDataModelMC.cxx b/Common/Tasks/checkDataModelMC.cxx index 799cf68a8e2..8eb6efc03f2 100644 --- a/Common/Tasks/checkDataModelMC.cxx +++ b/Common/Tasks/checkDataModelMC.cxx @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/Common/Tools/PID/pidTPCModule.h b/Common/Tools/PID/pidTPCModule.h index e86ec6ea351..de97ef65eba 100644 --- a/Common/Tools/PID/pidTPCModule.h +++ b/Common/Tools/PID/pidTPCModule.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx index 38348abd7bd..caaf159c47d 100644 --- a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx +++ b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx @@ -12,13 +12,18 @@ #include "tableHMPID.h" #include +#include #include +#include +#include #include #include -#include #include +#include +#include + using namespace o2; using namespace o2::framework; diff --git a/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackCascade.cxx b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackCascade.cxx index 65a5e2d3824..7460651def8 100644 --- a/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackCascade.cxx +++ b/PWGCF/FemtoDream/Tasks/femtoDreamTripletTaskTrackTrackCascade.cxx @@ -16,21 +16,31 @@ #include "PWGCF/FemtoDream/Core/femtoDreamContainerThreeBody.h" #include "PWGCF/FemtoDream/Core/femtoDreamDetaDphiStar.h" #include "PWGCF/FemtoDream/Core/femtoDreamEventHisto.h" +#include "PWGCF/FemtoDream/Core/femtoDreamMath.h" #include "PWGCF/FemtoDream/Core/femtoDreamPairCleaner.h" #include "PWGCF/FemtoDream/Core/femtoDreamParticleHisto.h" #include "PWGCF/FemtoDream/Core/femtoDreamUtils.h" #include +#include +#include #include +#include +#include +#include +#include #include -#include +#include +#include +#include #include -#include +#include #include #include #include +#include #include #include using namespace o2; diff --git a/PWGDQ/Core/VarManager.cxx b/PWGDQ/Core/VarManager.cxx index 0b320fa1ab2..78446746c76 100644 --- a/PWGDQ/Core/VarManager.cxx +++ b/PWGDQ/Core/VarManager.cxx @@ -11,9 +11,11 @@ #include "PWGDQ/Core/VarManager.h" +#include "Common/Core/RecoDecay.h" #include "Tools/KFparticle/KFUtilities.h" #include +#include #include #include #include @@ -26,6 +28,7 @@ #include #include #include +#include #include #include @@ -514,12 +517,10 @@ double VarManager::SampleRotationPhi(double pt, double eta, int charge) delete hPhi; - return gRandom->Uniform( - 0., o2::constants::math::TwoPI); + return gRandom->Uniform(0., o2::constants::math::TwoPI); } - const double phi = - RecoDecay::constrainAngle(hPhi->GetRandom()); + const double phi = RecoDecay::constrainAngle(hPhi->GetRandom()); delete hPhi; return phi; diff --git a/PWGDQ/Tasks/tableReader_withAssoc.cxx b/PWGDQ/Tasks/tableReader_withAssoc.cxx index 7bc5d77d76f..fa4de63004d 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc.cxx @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/Dilepton/Core/DileptonHadronMPC.h b/PWGEM/Dilepton/Core/DileptonHadronMPC.h index ea1740e3ff6..38b45983fb5 100644 --- a/PWGEM/Dilepton/Core/DileptonHadronMPC.h +++ b/PWGEM/Dilepton/Core/DileptonHadronMPC.h @@ -58,7 +58,6 @@ #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include -#include #include #include diff --git a/PWGEM/Dilepton/Core/DileptonSV.h b/PWGEM/Dilepton/Core/DileptonSV.h index 4acaf0f6028..8e34fe9f1c6 100644 --- a/PWGEM/Dilepton/Core/DileptonSV.h +++ b/PWGEM/Dilepton/Core/DileptonSV.h @@ -48,6 +48,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/PWGEM/Dilepton/Core/DileptonSVMC.h b/PWGEM/Dilepton/Core/DileptonSVMC.h index 863cd3ca7d8..37c58fe8d53 100644 --- a/PWGEM/Dilepton/Core/DileptonSVMC.h +++ b/PWGEM/Dilepton/Core/DileptonSVMC.h @@ -45,6 +45,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/PWGEM/Dilepton/DataModel/dileptonTables.h b/PWGEM/Dilepton/DataModel/dileptonTables.h index 5c34d437ff9..4178d0c7b89 100644 --- a/PWGEM/Dilepton/DataModel/dileptonTables.h +++ b/PWGEM/Dilepton/DataModel/dileptonTables.h @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #ifndef PWGEM_DILEPTON_DATAMODEL_DILEPTONTABLES_H_ diff --git a/PWGEM/Dilepton/TableProducer/Converters/muonConverter4.cxx b/PWGEM/Dilepton/TableProducer/Converters/muonConverter4.cxx index 98035efe8e9..a2917c791e5 100644 --- a/PWGEM/Dilepton/TableProducer/Converters/muonConverter4.cxx +++ b/PWGEM/Dilepton/TableProducer/Converters/muonConverter4.cxx @@ -16,8 +16,10 @@ #include "PWGEM/Dilepton/DataModel/dileptonTables.h" +#include #include #include +#include #include using namespace o2; diff --git a/PWGEM/Dilepton/TableProducer/skimmerOTS.cxx b/PWGEM/Dilepton/TableProducer/skimmerOTS.cxx index e483a9a7404..19e42b98774 100644 --- a/PWGEM/Dilepton/TableProducer/skimmerOTS.cxx +++ b/PWGEM/Dilepton/TableProducer/skimmerOTS.cxx @@ -30,6 +30,8 @@ #include +#include + #include #include #include diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx index 210e41414cd..8706432f69d 100644 --- a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx @@ -54,6 +54,8 @@ #include #include +#include + using namespace o2; using namespace o2::soa; using namespace o2::framework; diff --git a/PWGEM/Dilepton/Tasks/dimuonV1.cxx b/PWGEM/Dilepton/Tasks/dimuonV1.cxx index 06f966053e5..747f4e54cd0 100644 --- a/PWGEM/Dilepton/Tasks/dimuonV1.cxx +++ b/PWGEM/Dilepton/Tasks/dimuonV1.cxx @@ -54,6 +54,8 @@ #include #include +#include + struct dimuonV1 { // // Configurables diff --git a/PWGEM/PhotonMeson/Core/DalitzEECut.h b/PWGEM/PhotonMeson/Core/DalitzEECut.h index 49e0397b661..09df413654a 100644 --- a/PWGEM/PhotonMeson/Core/DalitzEECut.h +++ b/PWGEM/PhotonMeson/Core/DalitzEECut.h @@ -21,6 +21,7 @@ #include #include +#include #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include diff --git a/PWGEM/PhotonMeson/Core/EMCPhotonCut.h b/PWGEM/PhotonMeson/Core/EMCPhotonCut.h index 37d1810ca92..86227bfe02c 100644 --- a/PWGEM/PhotonMeson/Core/EMCPhotonCut.h +++ b/PWGEM/PhotonMeson/Core/EMCPhotonCut.h @@ -21,6 +21,7 @@ #include #include +#include #include #include diff --git a/PWGEM/PhotonMeson/Core/PHOSPhotonCut.h b/PWGEM/PhotonMeson/Core/PHOSPhotonCut.h index 32f1b59d133..db448562f61 100644 --- a/PWGEM/PhotonMeson/Core/PHOSPhotonCut.h +++ b/PWGEM/PhotonMeson/Core/PHOSPhotonCut.h @@ -17,6 +17,7 @@ #define PWGEM_PHOTONMESON_CORE_PHOSPHOTONCUT_H_ #include +#include #include diff --git a/PWGEM/PhotonMeson/Core/V0PhotonCut.h b/PWGEM/PhotonMeson/Core/V0PhotonCut.h index d5c8e30e236..369d3a55521 100644 --- a/PWGEM/PhotonMeson/Core/V0PhotonCut.h +++ b/PWGEM/PhotonMeson/Core/V0PhotonCut.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx b/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx index 26d2f62bf6c..0034d0dc3b6 100644 --- a/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx +++ b/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/TableProducer/bcWiseClusterSkimmer.cxx b/PWGEM/PhotonMeson/TableProducer/bcWiseClusterSkimmer.cxx index 75838125d69..d8eae0d3617 100644 --- a/PWGEM/PhotonMeson/TableProducer/bcWiseClusterSkimmer.cxx +++ b/PWGEM/PhotonMeson/TableProducer/bcWiseClusterSkimmer.cxx @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/TableProducer/nonLinProducer.cxx b/PWGEM/PhotonMeson/TableProducer/nonLinProducer.cxx index 57a551a40c1..05695b42850 100644 --- a/PWGEM/PhotonMeson/TableProducer/nonLinProducer.cxx +++ b/PWGEM/PhotonMeson/TableProducer/nonLinProducer.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx b/PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx index 4d096927d6e..f6a6bad2c2e 100644 --- a/PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx +++ b/PWGEM/PhotonMeson/Tasks/calibTaskEmc.cxx @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx b/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx index 3ee4a6e928d..b83cc325bc7 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx @@ -27,12 +27,14 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -51,7 +53,12 @@ #include #include +#include + +#include #include +#include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/emcalPi0Qc.cxx b/PWGEM/PhotonMeson/Tasks/emcalPi0Qc.cxx index 04f1f09b6e7..98bcc1533fd 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalPi0Qc.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalPi0Qc.cxx @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/emcalQC.cxx b/PWGEM/PhotonMeson/Tasks/emcalQC.cxx index 411e46c9712..5a793f86aa9 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalQC.cxx @@ -27,6 +27,7 @@ #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx index 47052298f51..4f2740fed70 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx @@ -41,6 +41,7 @@ #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx index e7c1ce2a34b..bdcd338d4aa 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx @@ -45,6 +45,7 @@ #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx b/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx index 3ae919f990c..f7c80f9b6d1 100644 --- a/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx +++ b/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx index f2fc28a8721..7ea2cfab560 100644 --- a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx +++ b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx b/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx index c14add8b083..0918ba11d8b 100644 --- a/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx +++ b/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx index aa3745d9503..c8a097a79cf 100644 --- a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGEM/PhotonMeson/Utils/ClusterHistograms.h b/PWGEM/PhotonMeson/Utils/ClusterHistograms.h index 6e51d09ab40..9fb34e4daee 100644 --- a/PWGEM/PhotonMeson/Utils/ClusterHistograms.h +++ b/PWGEM/PhotonMeson/Utils/ClusterHistograms.h @@ -20,6 +20,7 @@ #include #include +#include #include #include diff --git a/PWGEM/PhotonMeson/Utils/EventHistograms.h b/PWGEM/PhotonMeson/Utils/EventHistograms.h index 6991e399625..ab77f0fcb6d 100644 --- a/PWGEM/PhotonMeson/Utils/EventHistograms.h +++ b/PWGEM/PhotonMeson/Utils/EventHistograms.h @@ -20,6 +20,7 @@ #include "Common/CCDB/TriggerAliases.h" #include +#include #include #include diff --git a/PWGEM/PhotonMeson/Utils/HNMUtilities.h b/PWGEM/PhotonMeson/Utils/HNMUtilities.h index 956529610a0..3dfcc4f2f87 100644 --- a/PWGEM/PhotonMeson/Utils/HNMUtilities.h +++ b/PWGEM/PhotonMeson/Utils/HNMUtilities.h @@ -24,6 +24,7 @@ #include #include +#include #include #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) diff --git a/PWGEM/PhotonMeson/Utils/MCUtilities.h b/PWGEM/PhotonMeson/Utils/MCUtilities.h index dce6d127bf5..94fceb68445 100644 --- a/PWGEM/PhotonMeson/Utils/MCUtilities.h +++ b/PWGEM/PhotonMeson/Utils/MCUtilities.h @@ -17,6 +17,7 @@ #define PWGEM_PHOTONMESON_UTILS_MCUTILITIES_H_ #include +#include #include diff --git a/PWGEM/PhotonMeson/Utils/NMHistograms.h b/PWGEM/PhotonMeson/Utils/NMHistograms.h index 288b9b9a23f..af9d74c61b0 100644 --- a/PWGEM/PhotonMeson/Utils/NMHistograms.h +++ b/PWGEM/PhotonMeson/Utils/NMHistograms.h @@ -19,6 +19,7 @@ #include "PWGEM/PhotonMeson/Utils/MCUtilities.h" #include +#include #include #include diff --git a/PWGEM/PhotonMeson/Utils/PairUtilities.h b/PWGEM/PhotonMeson/Utils/PairUtilities.h index e19b8db1458..0ae25250e0f 100644 --- a/PWGEM/PhotonMeson/Utils/PairUtilities.h +++ b/PWGEM/PhotonMeson/Utils/PairUtilities.h @@ -19,7 +19,7 @@ #include #include -#include +#include #include diff --git a/PWGEM/PhotonMeson/Utils/TrackSelection.h b/PWGEM/PhotonMeson/Utils/TrackSelection.h index 941a7ea2bc0..c511a00a0b0 100644 --- a/PWGEM/PhotonMeson/Utils/TrackSelection.h +++ b/PWGEM/PhotonMeson/Utils/TrackSelection.h @@ -17,6 +17,7 @@ #define PWGEM_PHOTONMESON_UTILS_TRACKSELECTION_H_ #include +#include #include diff --git a/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx index 53a7c7beb24..ca043a2adb6 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx @@ -65,6 +65,7 @@ #include #include +#include #include #include #include diff --git a/PWGHF/HFC/Tasks/taskFlow.cxx b/PWGHF/HFC/Tasks/taskFlow.cxx index 6ac799fff5d..b68e6a79f18 100644 --- a/PWGHF/HFC/Tasks/taskFlow.cxx +++ b/PWGHF/HFC/Tasks/taskFlow.cxx @@ -27,7 +27,6 @@ #include "Common/CCDB/EventSelectionParams.h" #include "Common/CCDB/RCTSelectionFlags.h" #include "Common/Core/RecoDecay.h" -#include "Common/Core/fwdtrackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/McCollisionExtra.h" diff --git a/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx b/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx index 871b6e06aa8..b9f23076f24 100644 --- a/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx +++ b/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx @@ -67,6 +67,7 @@ #include #include +#include #include #include #include diff --git a/PWGLF/DataModel/LFHStrangeCorrelationTables.h b/PWGLF/DataModel/LFHStrangeCorrelationTables.h index ac0ec907db9..fc44ef7a56f 100644 --- a/PWGLF/DataModel/LFHStrangeCorrelationTables.h +++ b/PWGLF/DataModel/LFHStrangeCorrelationTables.h @@ -29,6 +29,8 @@ #include #include +#include + // Simple checker #define bitcheck(var, nbit) ((var) & (1 << (nbit))) diff --git a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx index 31fb7c63a0f..dc6995d51f1 100644 --- a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx +++ b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGLF/TableProducer/Nuspex/deuteronInTriggeredEvents.cxx b/PWGLF/TableProducer/Nuspex/deuteronInTriggeredEvents.cxx index ba8c5baee07..8525881ff0e 100644 --- a/PWGLF/TableProducer/Nuspex/deuteronInTriggeredEvents.cxx +++ b/PWGLF/TableProducer/Nuspex/deuteronInTriggeredEvents.cxx @@ -90,7 +90,6 @@ #include #include #include -#include #include #include diff --git a/PWGLF/TableProducer/Nuspex/nucleiThreeBodyBuilder.cxx b/PWGLF/TableProducer/Nuspex/nucleiThreeBodyBuilder.cxx index 154747598cc..a78843606e5 100644 --- a/PWGLF/TableProducer/Nuspex/nucleiThreeBodyBuilder.cxx +++ b/PWGLF/TableProducer/Nuspex/nucleiThreeBodyBuilder.cxx @@ -32,21 +32,26 @@ #include #include #include +#include #include +#include #include #include +#include #include +#include #include #include #include #include +#include #include #include #include +#include #include -#include #include #include diff --git a/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx b/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx index bb15833d0e1..4e29bd71d05 100644 --- a/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx @@ -63,8 +63,8 @@ #include #include #include +#include #include -#include #include using namespace o2; diff --git a/PWGLF/TableProducer/QC/nucleiQC.cxx b/PWGLF/TableProducer/QC/nucleiQC.cxx index b92eac75b5d..c9c417b08eb 100644 --- a/PWGLF/TableProducer/QC/nucleiQC.cxx +++ b/PWGLF/TableProducer/QC/nucleiQC.cxx @@ -52,7 +52,6 @@ #include -#include #include #include #include diff --git a/PWGLF/TableProducer/Resonances/cksspinalignment.cxx b/PWGLF/TableProducer/Resonances/cksspinalignment.cxx index 296f7a93582..8d82f1016a5 100644 --- a/PWGLF/TableProducer/Resonances/cksspinalignment.cxx +++ b/PWGLF/TableProducer/Resonances/cksspinalignment.cxx @@ -40,7 +40,8 @@ #include #include -#include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include #include #include diff --git a/PWGLF/TableProducer/Resonances/doublephitable.cxx b/PWGLF/TableProducer/Resonances/doublephitable.cxx index b2819b76cef..2e04cd9be96 100644 --- a/PWGLF/TableProducer/Resonances/doublephitable.cxx +++ b/PWGLF/TableProducer/Resonances/doublephitable.cxx @@ -16,7 +16,6 @@ #include "PWGLF/DataModel/ReducedDoublePhiTables.h" -#include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/Zorro.h" #include "Common/Core/ZorroSummary.h" #include "Common/Core/trackUtilities.h" @@ -29,6 +28,7 @@ #include "Common/DataModel/TrackSelectionTables.h" #include +#include #include #include #include @@ -39,20 +39,21 @@ #include #include #include +#include #include #include #include #include -#include #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include -#include +#include #include #include #include #include +#include #include #include #include diff --git a/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter4.cxx b/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter4.cxx index b94dd91714d..e8f0d23ed0d 100644 --- a/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter4.cxx +++ b/PWGLF/TableProducer/Strangeness/Converters/stradautrackstofpidconverter4.cxx @@ -19,9 +19,12 @@ #include "PWGLF/DataModel/LFStrangenessTables.h" #include +#include #include #include +#include + using namespace o2; using namespace o2::framework; diff --git a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx index 6f755288dc6..1a4710576e1 100644 --- a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx +++ b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx @@ -50,7 +50,10 @@ #include #include +#include + #include +#include #include #include diff --git a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx index 6a363942d5f..73d4997f821 100644 --- a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx +++ b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx b/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx index b1c529c2880..94cf60e61d6 100644 --- a/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx @@ -58,6 +58,7 @@ #include #include +#include #include #include #include @@ -725,7 +726,7 @@ struct strangederivedbuilder { totalFDDAmplitudeA, totalFDDAmplitudeC, timeZNA, timeZNC, // ZDC info energyCommonZNA, energyCommonZNC); - } else { // We are in Run 2 + } else { // We are in Run 2 products.strangeCentsRun2(collision.centRun2V0M(), collision.centRun2V0A(), collision.centRun2SPDTracklets(), collision.centRun2SPDClusters()); products.strangeEvSelsRun2(collision.sel8(), collision.sel7(), collision.selection_raw(), @@ -809,7 +810,7 @@ struct strangederivedbuilder { collisionEventTime[collision.globalIndex()] /= static_cast(collisionNtracks[collision.globalIndex()]); collisionEventTimeErr[collision.globalIndex()] /= static_cast(collisionNtracks[collision.globalIndex()]); } else { - collisionEventTime[collision.globalIndex()] = -1e+6; // undefined + collisionEventTime[collision.globalIndex()] = -1e+6; // undefined collisionEventTimeErr[collision.globalIndex()] = -1e-6; // undefined } if (fillOnlySelectedCollisions && !isCollisionAccepted(collision, totalNbrCollisionsPerSelection)) { diff --git a/PWGLF/TableProducer/Strangeness/strangenessbuilder.cxx b/PWGLF/TableProducer/Strangeness/strangenessbuilder.cxx index 112c7d46a5c..14f37772f44 100644 --- a/PWGLF/TableProducer/Strangeness/strangenessbuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/strangenessbuilder.cxx @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGLF/Tasks/Nuspex/nucleitpcPbPb.cxx b/PWGLF/Tasks/Nuspex/nucleitpcPbPb.cxx index e3462081487..87799179ec4 100644 --- a/PWGLF/Tasks/Nuspex/nucleitpcPbPb.cxx +++ b/PWGLF/Tasks/Nuspex/nucleitpcPbPb.cxx @@ -43,6 +43,7 @@ #include #include #include +#include #include #include diff --git a/PWGLF/Tasks/Resonances/cksspinalignder.cxx b/PWGLF/Tasks/Resonances/cksspinalignder.cxx index 54d2958bbd9..c846369135f 100644 --- a/PWGLF/Tasks/Resonances/cksspinalignder.cxx +++ b/PWGLF/Tasks/Resonances/cksspinalignder.cxx @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -31,8 +30,10 @@ #include #include -#include -#include +#include // IWYU pragma: keep (do not replace with Math/Vector3Dfwd.h) +#include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include #include #include diff --git a/PWGLF/Tasks/Resonances/lambda1405analysis.cxx b/PWGLF/Tasks/Resonances/lambda1405analysis.cxx index 10b85c03f2b..83eb796ac94 100644 --- a/PWGLF/Tasks/Resonances/lambda1405analysis.cxx +++ b/PWGLF/Tasks/Resonances/lambda1405analysis.cxx @@ -17,7 +17,6 @@ #include "PWGLF/DataModel/LFLambda1405Table.h" #include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" @@ -29,21 +28,20 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include +#include #include #include #include #include #include -#include -#include #include #include @@ -122,9 +120,9 @@ struct lambda1405candidate { }; struct lambda1405analysis { - int lambda1405PdgCode = 102132; // o2-linter: disable=pdg/explicit-code - Produces outputDataTable; // Output table for Lambda(1405) candidates - Produces outputDataTableMC; // Output table for Lambda(1405) candidates in MC + int lambda1405PdgCode = 102132; // o2-linter: disable=pdg/explicit-code + Produces outputDataTable; // Output table for Lambda(1405) candidates + Produces outputDataTableMC; // Output table for Lambda(1405) candidates in MC Produces outputSigmaEffMC; // Output table for Lambda(1405) sigma efficiency in MC Service ccdb; diff --git a/PWGLF/Tasks/Resonances/phiflowder.cxx b/PWGLF/Tasks/Resonances/phiflowder.cxx index f415d00b1db..7ebe626ca24 100644 --- a/PWGLF/Tasks/Resonances/phiflowder.cxx +++ b/PWGLF/Tasks/Resonances/phiflowder.cxx @@ -18,20 +18,25 @@ #include #include +#include #include #include #include +#include #include #include #include #include +#include #include -#include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include +#include +#include #include #include -#include #include #include diff --git a/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx b/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx index e3eba198d51..668dd8f7541 100644 --- a/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx +++ b/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGLF/Utils/decay3bodyBuilderHelper.h b/PWGLF/Utils/decay3bodyBuilderHelper.h index 66646a38cad..7888def137a 100644 --- a/PWGLF/Utils/decay3bodyBuilderHelper.h +++ b/PWGLF/Utils/decay3bodyBuilderHelper.h @@ -31,7 +31,6 @@ #include #include -#include #include #include diff --git a/PWGLF/Utils/strangenessBuilderModule.h b/PWGLF/Utils/strangenessBuilderModule.h index 63ee3198b6d..563b75e6d95 100644 --- a/PWGLF/Utils/strangenessBuilderModule.h +++ b/PWGLF/Utils/strangenessBuilderModule.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx b/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx index f92319d5263..a4d5c6301b2 100644 --- a/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx +++ b/PWGMM/Mult/Tasks/dndetaMFTPbPb.cxx @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGUD/Tasks/flowCorrelationsUpc.cxx b/PWGUD/Tasks/flowCorrelationsUpc.cxx index 9159bb73607..55e70990f88 100644 --- a/PWGUD/Tasks/flowCorrelationsUpc.cxx +++ b/PWGUD/Tasks/flowCorrelationsUpc.cxx @@ -40,7 +40,6 @@ #include #include #include -#include #include #include @@ -161,7 +160,7 @@ struct FlowCorrelationsUpc { registry.add("Trig_hist", "", {HistType::kTHnSparseF, {{axisSample, axisVertex, axisIndependent, axisPtTrigger}}}); - registry.add("eventcont", "bin", {HistType::kTH1F, {{10, 0, 10, "bin"}}}); // histogram to see how many events are in the same and mixed event + registry.add("eventcont", "bin", {HistType::kTH1F, {{10, 0, 10, "bin"}}}); // histogram to see how many events are in the same and mixed event registry.get(HIST("eventcont"))->GetXaxis()->SetBinLabel(4, "same"); registry.get(HIST("eventcont"))->GetXaxis()->SetBinLabel(5, "mix pair"); registry.add("deltaPhi_deltaEta_same", "deltaphi-deltaeta", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); // histogram to check the delta eta and delta phi distribution From 8e899a62df36a2586e381901bc06deaba0252d2f Mon Sep 17 00:00:00 2001 From: Yongxi Du <1260971129@qq.com> Date: Fri, 31 Jul 2026 14:52:33 +0800 Subject: [PATCH 55/71] [PWGUD] add zdc time cut (#17259) --- PWGUD/Tasks/flowCorrelationsUpc.cxx | 62 +++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/PWGUD/Tasks/flowCorrelationsUpc.cxx b/PWGUD/Tasks/flowCorrelationsUpc.cxx index 55e70990f88..4ff477d25d0 100644 --- a/PWGUD/Tasks/flowCorrelationsUpc.cxx +++ b/PWGUD/Tasks/flowCorrelationsUpc.cxx @@ -91,6 +91,8 @@ struct FlowCorrelationsUpc { O2_DEFINE_CONFIGURABLE(cfgRctFlagEnabled, bool, false, "use run condition table flag") O2_DEFINE_CONFIGURABLE(cfgRctFlagIndex, int, 1, "1: isCBTOk; 2:isCBTZdcOk; 3: isCBTHadronOk; 4:isCBTHadronZdcOk ") O2_DEFINE_CONFIGURABLE(cfgIRMaxCut, double, 50, "maximum interaction rate for UPC events") + O2_DEFINE_CONFIGURABLE(cfgZdcTime, bool, false, "choose zdc time cut") + O2_DEFINE_CONFIGURABLE(cfgZdcTimeCut, float, 2.0, "zdc time cut") ConfigurableAxis axisVertex{"axisVertex", {10, -10, 10}, "vertex axis for histograms"}; ConfigurableAxis axisEta{"axisEta", {40, -1., 1.}, "eta axis for histograms"}; @@ -167,6 +169,9 @@ struct FlowCorrelationsUpc { registry.add("deltaPhi_deltaEta_mixed", "deltaphi-deltaeta", {HistType::kTH2D, {axisDeltaPhi, axisDeltaEta}}); // histogram to check the delta eta and delta phi distribution registry.add("Nch_raw_vs_independent", "Raw vs Independent", {HistType::kTH2D, {axisMultiplicity, axisIndependent}}); registry.add("interactionRate", "kHz", {HistType::kTH1F, {{50, 0, 50, "kHz"}}}); + registry.add("ZDCEnergy", "ZNA; ZNC; Count", {HistType::kTH2D, {{100, 0, 100}, {100, 0, 100}}}); + registry.add("ZDCTime", "ZNA; ZNC; Count", {HistType::kTH2D, {{100, -10, 10}, {100, -10, 10}}}); + registry.add("neutronClass", "ZNA; ZNC; Count", {HistType::kTH2D, {{2, 0, 2}, {2, 0, 2}}}); if (cfgUseNchRoughMCCorrected) { fnchRoughMCFunc = new TF1("fnchRoughMCFunc", cfgNchRoughMCFunction->c_str(), 0, 100); @@ -225,6 +230,59 @@ struct FlowCorrelationsUpc { } } + template + // zdc time cut + bool zdcTimeCut(const C& collision) + { + if (!cfgZdcTime) { + return true; + } + int neutronClass = -1; + float energyCommonZNA = collision.energyCommonZNA(), energyCommonZNC = collision.energyCommonZNC(); + float timeZNA = collision.timeZNA(), timeZNC = collision.timeZNC(); + if (std::isinf(energyCommonZNA)) + energyCommonZNA = -999; + if (std::isinf(energyCommonZNC)) + energyCommonZNC = -999; + if (std::isinf(timeZNA)) + timeZNA = -999; + if (std::isinf(timeZNC)) + timeZNC = -999; + registry.fill(HIST("ZDCEnergy"), energyCommonZNC, energyCommonZNA); + registry.fill(HIST("ZDCTime"), timeZNC, timeZNA); + if (std::abs(timeZNA) > cfgZdcTimeCut && std::abs(timeZNC) > cfgZdcTimeCut) { + neutronClass = 0; + registry.fill(HIST("neutronClass"), 0, 0); + } + if (std::abs(timeZNA) <= cfgZdcTimeCut && std::abs(timeZNC) > cfgZdcTimeCut) { + neutronClass = 1; + registry.fill(HIST("neutronClass"), 0, 1); + } + if (std::abs(timeZNA) > cfgZdcTimeCut && std::abs(timeZNC) <= cfgZdcTimeCut) { + neutronClass = 2; + registry.fill(HIST("neutronClass"), 1, 0); + } + if (std::abs(timeZNA) <= cfgZdcTimeCut && std::abs(timeZNC) <= cfgZdcTimeCut) { + neutronClass = 3; + registry.fill(HIST("neutronClass"), 1, 1); + } + if (cfgZdcTime) { + // reject 0n0n and XnXn + if (neutronClass == 0 || neutronClass == 3) { // o2-linter: disable=magic-number (ZDC time cut) + return false; + } + // if A or C gap is requested, keep corresponding neutron class + if (cfgGapSide == 0 || cfgGapSide == 1) { + if ((cfgGapSide == 0 && neutronClass == 1) || (cfgGapSide == 1 && neutronClass == 2)) { // o2-linter: disable=magic-number (ZDC time cut) + // accepted + } else { + return false; + } + } + } + return true; + } + template bool eventSelected(const C& collision) { @@ -256,6 +314,10 @@ struct FlowCorrelationsUpc { return false; } + if (!zdcTimeCut(collision)) { + return false; + } + return true; } From b459571dfcd586a13113215ca51d1fdc6b04bfb1 Mon Sep 17 00:00:00 2001 From: Maxim Virta <84773378+MaximVirta@users.noreply.github.com> Date: Fri, 31 Jul 2026 09:26:54 +0200 Subject: [PATCH 56/71] [PWGCF] Added bootsrapping, improved linter errors (#17264) Co-authored-by: Maxim Virta --- PWGCF/GenericFramework/Tasks/flowGfwV02.cxx | 106 ++++++++++++++------ 1 file changed, 76 insertions(+), 30 deletions(-) diff --git a/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx b/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx index c382cc6748c..6dd45ddd25c 100644 --- a/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx +++ b/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx @@ -211,7 +211,7 @@ struct FlowGfwV02 { TH1D* mEfficiency[4] = {nullptr, nullptr, nullptr, nullptr}; GFWWeights* mAcceptance; bool correctionsLoaded = false; - } cfg; + } cfg{}; // Define output OutputObj fFC{FlowContainer("FlowContainer")}; @@ -261,9 +261,9 @@ struct FlowGfwV02 { struct PIDState { o2::aod::ITSResponse itsResponse; - std::array tofNsigmaCut; - std::array itsNsigmaCut; - std::array tpcNsigmaCut; + std::array tofNsigmaCut{}; + std::array itsNsigmaCut{}; + std::array tpcNsigmaCut{}; std::array, 4> hPtMid{}; std::array, 4> hPtForward{}; std::array, 4> hPtBackward{}; @@ -276,10 +276,6 @@ struct FlowGfwV02 { std::unique_ptr fMultCutLow; std::unique_ptr fMultCutHigh; std::unique_ptr fMultPVGlobalCutHigh; - std::unique_ptr fMultGlobalV0ACutLow; - std::unique_ptr fMultGlobalV0ACutHigh; - std::unique_ptr fMultGlobalT0ACutLow; - std::unique_ptr fMultGlobalT0ACutHigh; std::unique_ptr fPtDepDCAxy; @@ -431,19 +427,23 @@ struct FlowGfwV02 { AxisSpec multpvAxis = {600, 0, 600, "N_{ch} (PV)"}; AxisSpec dcaZAxis = {200, -2, 2, "DCA_{z} (cm)"}; AxisSpec dcaXYAxis = {200, -0.5, 0.5, "DCA_{xy} (cm)"}; - AxisSpec pidAxis = {4, -0.5, 3.5, "PID"}; // 0 = not identified, 1 = pion, 2 = kaon, 3 = proton + AxisSpec bsAxis = {o2::analysis::gfw::nBootstrap, -0.5, o2::analysis::gfw::nBootstrap - 0.5, "Bootstrap Index"}; registry.add("v02pt", "", {HistType::kTProfile2D, {ptAxis, centAxis}}); registry.add("nchMid", "", {HistType::kTProfile3D, {ptAxis, centAxis, nchAxis}}); registry.add("v02centmult", "", {HistType::kTProfile2D, {centAxis, nchAxis}}); - registry.add("analysis/v0AB", "", {HistType::kTProfile3D, {pidAxis, ptAxis, centAxis}}); - registry.add("analysis/v0BA", "", {HistType::kTProfile3D, {pidAxis, ptAxis, centAxis}}); - registry.add("analysis/nchA", "", {HistType::kTProfile3D, {pidAxis, ptAxis, centAxis}}); - registry.add("analysis/nchB", "", {HistType::kTProfile3D, {pidAxis, ptAxis, centAxis}}); - registry.add("analysis/ptA", "", {HistType::kTProfile3D, {pidAxis, centAxis, nchAxis}}); - registry.add("analysis/ptB", "", {HistType::kTProfile3D, {pidAxis, centAxis, nchAxis}}); - registry.add("analysis/ptAB", "", {HistType::kTProfile3D, {pidAxis, centAxis, nchAxis}}); + registry.add("analysis/charged/v0AB", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); + registry.add("analysis/charged/v0BA", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); + registry.add("analysis/charged/nchA", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); + registry.add("analysis/charged/nchB", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); + registry.add("analysis/charged/ptA", "", {HistType::kTProfile3D, {bsAxis, centAxis, nchAxis}}); + registry.add("analysis/charged/ptB", "", {HistType::kTProfile3D, {bsAxis, centAxis, nchAxis}}); + registry.add("analysis/charged/ptAB", "", {HistType::kTProfile3D, {bsAxis, centAxis, nchAxis}}); + + registry.addClone("analysis/charged/", "analysis/pion/"); + registry.addClone("analysis/charged/", "analysis/kaon/"); + registry.addClone("analysis/charged/", "analysis/proton/"); ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); @@ -653,7 +653,7 @@ struct FlowGfwV02 { if (cfg.mEfficiency[PidCharged] == nullptr) { LOGF(fatal, "Could not load efficiency histogram from %s", cfgEfficiency.value.c_str()); } - LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEfficiency.value.c_str(), (void*)cfg.mEfficiency[PidCharged]); + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgEfficiency.value.c_str(), static_cast(cfg.mEfficiency[PidCharged])); } if (cfgPIDEfficiency) { const std::array pidStrings = {"ch", "pi", "ka", "pr"}; @@ -663,7 +663,7 @@ struct FlowGfwV02 { if (cfg.mEfficiency[i] == nullptr) { LOGF(fatal, "Could not load PID efficiency histogram from %s", cfgEfficiency.value + pidStrings[i].c_str()); } - LOGF(info, "Loaded PID efficiency histogram from %s (%p)", cfgEfficiency.value + pidStrings[i].c_str(), (void*)cfg.mEfficiency[i]); + LOGF(info, "Loaded PID efficiency histogram from %s (%p)", cfgEfficiency.value + pidStrings[i].c_str(), static_cast(cfg.mEfficiency[i])); } } cfg.correctionsLoaded = true; @@ -881,10 +881,11 @@ struct FlowGfwV02 { ebyeWeight *= pidStates.hPtMid[PidCharged]->Integral(); } double ptFraction = 0; + double threshhold = 1.01; int normIndex = (cfgNormalizeByCharged) ? PidCharged : pidInd; // Configured to normalize by charged particles or the selected particle if (pidStates.hPtMid[normIndex]->Integral() > 0) { ptFraction = pidStates.hPtMid[pidInd]->GetBinContent(i) / pidStates.hPtMid[normIndex]->Integral(); - if (std::abs(val) < 1.01) + if (std::abs(val) < threshhold) fFC->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val * ptFraction, ebyeWeight, rndm); } } @@ -897,6 +898,7 @@ struct FlowGfwV02 { double ptMeanBackward = pidStates.hPtBackward[PidCharged]->GetMean(); double ptFractionForward = 0.; double ptFractionBackward = 0.; + int bootstrap = fRndm->Integer(o2::analysis::gfw::nBootstrap); for (int pid = 0; pid < PidTotal; pid++) { int normIndex = (cfgNormalizeByCharged) ? PidCharged : pid; for (int i = 1; i <= fSecondAxis->GetNbins(); i++) { @@ -904,14 +906,59 @@ struct FlowGfwV02 { ptFractionBackward = pidStates.hPtBackward[pid]->GetBinContent(i) / pidStates.hPtBackward[normIndex]->Integral(); v0corrAB = ptFractionForward * ptMeanBackward; v0corrBA = ptFractionBackward * ptMeanForward; - registry.fill(HIST("analysis/v0AB"), pid, fSecondAxis->GetBinCenter(i), centmult, v0corrAB); - registry.fill(HIST("analysis/v0BA"), pid, fSecondAxis->GetBinCenter(i), centmult, v0corrBA); - registry.fill(HIST("analysis/nchA"), pid, fSecondAxis->GetBinCenter(i), centmult, ptFractionForward); - registry.fill(HIST("analysis/nchB"), pid, fSecondAxis->GetBinCenter(i), centmult, ptFractionBackward); + switch (pid) { + case PidCharged: + registry.fill(HIST("analysis/charged/v0AB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrAB); + registry.fill(HIST("analysis/charged/v0BA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrBA); + registry.fill(HIST("analysis/charged/nchA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionForward); + registry.fill(HIST("analysis/charged/nchB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionBackward); + break; + case PidPions: + registry.fill(HIST("analysis/pion/v0AB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrAB); + registry.fill(HIST("analysis/pion/v0BA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrBA); + registry.fill(HIST("analysis/pion/nchA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionForward); + registry.fill(HIST("analysis/pion/nchB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionBackward); + break; + case PidKaons: + registry.fill(HIST("analysis/kaon/v0AB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrAB); + registry.fill(HIST("analysis/kaon/v0BA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrBA); + registry.fill(HIST("analysis/kaon/nchA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionForward); + registry.fill(HIST("analysis/kaon/nchB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionBackward); + break; + case PidProtons: + registry.fill(HIST("analysis/proton/v0AB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrAB); + registry.fill(HIST("analysis/proton/v0BA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v0corrBA); + registry.fill(HIST("analysis/proton/nchA"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionForward); + registry.fill(HIST("analysis/proton/nchB"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionBackward); + break; + default: + break; + } + } + switch (pid) { + case PidCharged: + registry.fill(HIST("analysis/charged/ptA"), bootstrap, centmult, multiplicity, ptMeanForward); + registry.fill(HIST("analysis/charged/ptB"), bootstrap, centmult, multiplicity, ptMeanBackward); + registry.fill(HIST("analysis/charged/ptAB"), bootstrap, centmult, multiplicity, ptMeanForward * ptMeanBackward); + break; + case PidPions: + registry.fill(HIST("analysis/pion/ptA"), bootstrap, centmult, multiplicity, ptMeanForward); + registry.fill(HIST("analysis/pion/ptB"), bootstrap, centmult, multiplicity, ptMeanBackward); + registry.fill(HIST("analysis/pion/ptAB"), bootstrap, centmult, multiplicity, ptMeanForward * ptMeanBackward); + break; + case PidKaons: + registry.fill(HIST("analysis/kaon/ptA"), bootstrap, centmult, multiplicity, ptMeanForward); + registry.fill(HIST("analysis/kaon/ptB"), bootstrap, centmult, multiplicity, ptMeanBackward); + registry.fill(HIST("analysis/kaon/ptAB"), bootstrap, centmult, multiplicity, ptMeanForward * ptMeanBackward); + break; + case PidProtons: + registry.fill(HIST("analysis/proton/ptA"), bootstrap, centmult, multiplicity, ptMeanForward); + registry.fill(HIST("analysis/proton/ptB"), bootstrap, centmult, multiplicity, ptMeanBackward); + registry.fill(HIST("analysis/proton/ptAB"), bootstrap, centmult, multiplicity, ptMeanForward * ptMeanBackward); + break; + default: + break; } - registry.fill(HIST("analysis/ptA"), pid, centmult, multiplicity, ptMeanForward); - registry.fill(HIST("analysis/ptB"), pid, centmult, multiplicity, ptMeanBackward); - registry.fill(HIST("analysis/ptAB"), pid, centmult, multiplicity, ptMeanForward * ptMeanBackward); } } @@ -936,7 +983,6 @@ struct FlowGfwV02 { struct XAxis { float centrality; int64_t multiplicity; - double time; }; struct AcceptedTracks { @@ -1240,7 +1286,7 @@ struct FlowGfwV02 { registry.fill(HIST("eventQA/eventSel"), kSel8); registry.fill(HIST("eventQA/eventSel"), kOccupancy); // Add occupancy selection later - const XAxis xaxis{getCentrality(collision), tracks.size(), -1.0}; + const XAxis xaxis{getCentrality(collision), tracks.size()}; if (cfgFillQA) { fillEventQA(collision, xaxis); registry.fill(HIST("eventQA/before/centrality"), xaxis.centrality); @@ -1265,7 +1311,7 @@ struct FlowGfwV02 { LOGF(info, "run = %d", run); } loadCorrections(run); - const XAxis xaxis{collision.multiplicity(), tracks.size(), -1.0}; + const XAxis xaxis{collision.multiplicity(), tracks.size()}; registry.fill(HIST("eventQA/after/centrality"), xaxis.centrality); registry.fill(HIST("eventQA/after/multiplicity"), xaxis.multiplicity); @@ -1280,7 +1326,7 @@ struct FlowGfwV02 { lastRun = run; LOGF(info, "run = %d", run); } - const XAxis xaxis{collision.multiplicity(), tracks.size(), -1.0}; + const XAxis xaxis{collision.multiplicity(), tracks.size()}; registry.fill(HIST("eventQA/after/centrality"), xaxis.centrality); registry.fill(HIST("eventQA/after/multiplicity"), xaxis.multiplicity); // processCollision(collision, tracks, xaxis, run); From cb9b74806494a731e806fd33ee5a594cafe4e4ad Mon Sep 17 00:00:00 2001 From: Igor Ptak <62450343+IgorPtak@users.noreply.github.com> Date: Fri, 31 Jul 2026 11:11:58 +0200 Subject: [PATCH 57/71] [PWGCF] Femto: Add D0 meson support to the femto framework (#17253) --- PWGCF/Femto/Core/charmHadronBuilder.h | 448 ++++++++++++++++++ PWGCF/Femto/Core/charmHadronHistManager.h | 495 ++++++++++++++++++++ PWGCF/Femto/Core/closePairRejection.h | 4 + PWGCF/Femto/Core/dataTypes.h | 4 + PWGCF/Femto/Core/femtoUtils.h | 3 + PWGCF/Femto/Core/mcBuilder.h | 71 ++- PWGCF/Femto/Core/modes.h | 19 +- PWGCF/Femto/Core/pairBuilder.h | 166 +++++++ PWGCF/Femto/Core/pairHistManager.h | 5 +- PWGCF/Femto/Core/particleCleaner.h | 5 + PWGCF/Femto/Core/partitions.h | 16 + PWGCF/Femto/Core/trackHistManager.h | 13 + PWGCF/Femto/DataModel/FemtoTables.h | 73 +++ PWGCF/Femto/TableProducer/femtoProducer.cxx | 98 ++++ PWGCF/Femto/Tasks/CMakeLists.txt | 10 + PWGCF/Femto/Tasks/femtoD0Qa.cxx | 161 +++++++ PWGCF/Femto/Tasks/femtoPairTrackD0.cxx | 203 ++++++++ 17 files changed, 1789 insertions(+), 5 deletions(-) create mode 100644 PWGCF/Femto/Core/charmHadronBuilder.h create mode 100644 PWGCF/Femto/Core/charmHadronHistManager.h create mode 100644 PWGCF/Femto/Tasks/femtoD0Qa.cxx create mode 100644 PWGCF/Femto/Tasks/femtoPairTrackD0.cxx diff --git a/PWGCF/Femto/Core/charmHadronBuilder.h b/PWGCF/Femto/Core/charmHadronBuilder.h new file mode 100644 index 00000000000..1b139a7cb52 --- /dev/null +++ b/PWGCF/Femto/Core/charmHadronBuilder.h @@ -0,0 +1,448 @@ +// Copyright 2019-2026 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 charmHadronBuilder.h +/// \brief charm hadron builder +/// \author Igor Ptak, WUT, igor.tomasz.ptak@cern.ch + +#ifndef PWGCF_FEMTO_CORE_CHARMHADRONBUILDER_H_ +#define PWGCF_FEMTO_CORE_CHARMHADRONBUILDER_H_ + +#include "PWGCF/Femto/Core/baseSelection.h" +#include "PWGCF/Femto/Core/dataTypes.h" +#include "PWGCF/Femto/Core/femtoUtils.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/selectionContainer.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace o2::analysis::femto::charmhadronbuilder +{ +// number of ML probability classes (background, prompt, non-prompt) provided by the HF ML selector +constexpr std::size_t NSizeMLScore{3u}; + +// filter applied in the producer task +struct ConfD0Filters : o2::framework::ConfigurableGroup { + std::string prefix = std::string("D0Filters"); + // kinematic windows + o2::framework::Configurable ptMin{"ptMin", 0.f, "Minimum pT"}; + o2::framework::Configurable ptMax{"ptMax", 24.f, "Maximum pT"}; + o2::framework::Configurable etaMin{"etaMin", -0.8f, "Minimum eta"}; + o2::framework::Configurable etaMax{"etaMax", 0.8f, "Maximum eta"}; + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; + // rapidity acceptance (HF convention: y, not eta) + o2::framework::Configurable useYCut{"useYCut", true, "cut on y (true) or eta (false)"}; + o2::framework::Configurable yMin{"yMin", -0.8f, "Minimum rapidity"}; + o2::framework::Configurable yMax{"yMax", 0.8f, "Maximum rapidity"}; + // invariant-mass window + o2::framework::Configurable massMin{"massMin", 1.7f, "Minimum invariant mass for D0"}; + o2::framework::Configurable massMax{"massMax", 2.0f, "Maximum invariant mass for D0"}; +}; + +// derived selection bits for D0s +struct ConfD0Bits : o2::framework::ConfigurableGroup { + std::string prefix = std::string("D0Bits"); + o2::framework::Configurable passThrough{"passThrough", false, "If true, all D0s are passed through. Bits for all selections are stored."}; + o2::framework::Configurable> cpaMin{"cpaMin", {0.9f}, "Minimum cosine of pointing angle"}; + o2::framework::Configurable> decayLengthMin{"decayLengthMin", {0.02f}, "Minimum decay length (cm)"}; + o2::framework::Configurable> impactParameterProductMax{"impactParameterProductMax", {0.f}, "Maximum product of prong impact parameters d0*d0 (cm^2)"}; + o2::framework::Configurable> cosThetaStarMax{"cosThetaStarMax", {1.f}, "Maximum |cos(theta*)| of the decay"}; +}; + +// base selection for analysis task for D0s +struct ConfD0Selection : o2::framework::ConfigurableGroup { + std::string prefix = std::string("D0Selection"); + o2::framework::Configurable pdgCodeAbs{"pdgCodeAbs", o2::constants::physics::Pdg::kD0, "PDG code (D0)"}; + o2::framework::Configurable sign{"sign", 0, "Particle sign (+1: D0; -1: D0bar; 0: both)"}; + o2::framework::Configurable ptMin{"ptMin", 1.f, "Minimum pT"}; + o2::framework::Configurable ptMax{"ptMax", 3.f, "Maximum pT"}; + // acceptance is applied as a rapidity cut in the builder; the eta/phi windows + // are kept open and exist only to satisfy MAKE_D0_PARTITION + o2::framework::Configurable etaMin{"etaMin", -0.8f, "Minimum eta"}; + o2::framework::Configurable etaMax{"etaMax", 0.8f, "Maximum eta"}; + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; + // signal region; side-bands remain available in the derived data + o2::framework::Configurable massMin{"massMin", 1.81f, "Minimum invariant mass for D0"}; + o2::framework::Configurable massMax{"massMax", 1.922f, "Maximum invariant mass for D0"}; + o2::framework::Configurable mask{"mask", 0, "Bitmask for D0 selection"}; +}; + +/// The different selections for D0s +enum D0Sels { + // topological selections + kCpaMin, ///< Min. CPA (cosine pointing angle) + kDecayLengthMin, ///< Min. decay length + kImpactParameterProductMax, ///< Max. product of prong impact parameters (d0*d0) + kCosThetaStarMax, ///< Max. |cos(theta*)| of the decay + + kD0SelsMax +}; + +constexpr char D0SelHistName[] = "hD0Selection"; +constexpr char D0barSelHistName[] = "hD0barSelection"; +constexpr char D0SelsName[] = "D0 selection object"; +const std::unordered_map d0SelectionNames = { + {kCpaMin, "Min. CPA (cosine pointing angle)"}, + {kDecayLengthMin, "Min. decay length"}, + {kImpactParameterProductMax, "Max. product of prong impact parameters (d0*d0)"}, + {kCosThetaStarMax, "Max. |cos(theta*)| of the decay"}}; + +/// enum for all D0 filters (loose kinematic pre-selection, applied before the bit selections) +enum D0Filters { + kDecayChannel, + kHypothesis, + kPtMin, + kPtMax, + kEtaMin, + kEtaMax, + kPhiMin, + kPhiMax, + kYMin, + kYMax, + kMassMin, + kMassMax, + kD0FiltersMax +}; + +constexpr char D0FilterHistName[] = "hD0Filters"; +constexpr char D0barFilterHistName[] = "hD0barFilters"; +const std::unordered_map d0FilterNames = { + {kDecayChannel, "D0 -> K pi decay channel"}, + {kHypothesis, "D0/D0bar hypothesis"}, + {kPtMin, "Minimum pT"}, + {kPtMax, "Maximum pT"}, + {kEtaMin, "Minimum eta"}, + {kEtaMax, "Maximum eta"}, + {kPhiMin, "Minimum phi"}, + {kPhiMax, "Maximum phi"}, + {kYMin, "Minimum rapidity"}, + {kYMax, "Maximum rapidity"}, + {kMassMin, "Minimum invariant mass"}, + {kMassMax, "Maximum invariant mass"}}; + +template +class D0Selection : public baseselection::BaseSelection +{ + public: + D0Selection() = default; + ~D0Selection() override = default; + + template + void configure(o2::framework::HistogramRegistry* registry, T1& config, T2& filter) + { + this->init(config.passThrough.value); + + mPtMin = filter.ptMin.value; + mPtMax = filter.ptMax.value; + mEtaMin = filter.etaMin.value; + mEtaMax = filter.etaMax.value; + mPhiMin = filter.phiMin.value; + mPhiMax = filter.phiMax.value; + mMassMin = filter.massMin.value; + mMassMax = filter.massMax.value; + mUseYCut = filter.useYCut.value; + mYMin = filter.yMin.value; + mYMax = filter.yMax.value; + + this->addSelection(kCpaMin, d0SelectionNames.at(kCpaMin), config.cpaMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kDecayLengthMin, d0SelectionNames.at(kDecayLengthMin), config.decayLengthMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kImpactParameterProductMax, d0SelectionNames.at(kImpactParameterProductMax), config.impactParameterProductMax.value, limits::kUpperLimit, true, true, false); + this->addSelection(kCosThetaStarMax, d0SelectionNames.at(kCosThetaStarMax), config.cosThetaStarMax.value, limits::kAbsUpperLimit, true, true, false); + + this->template setupSelectionHistogram(registry); + this->template setupFilterHistogram( + registry, + { + {d0FilterNames.at(kDecayChannel), 1}, + {d0FilterNames.at(kHypothesis), 1}, + {d0FilterNames.at(kPtMin), mPtMin}, + {d0FilterNames.at(kPtMax), mPtMax}, + {d0FilterNames.at(kEtaMin), mEtaMin}, + {d0FilterNames.at(kEtaMax), mEtaMax}, + {d0FilterNames.at(kPhiMin), mPhiMin}, + {d0FilterNames.at(kPhiMax), mPhiMax}, + {d0FilterNames.at(kYMin), mYMin}, + {d0FilterNames.at(kYMax), mYMax}, + {d0FilterNames.at(kMassMin), mMassMin}, + {d0FilterNames.at(kMassMax), mMassMax}, + }); + } + + template + void applySelections(T1 const& d0candidate) + { + this->reset(); + this->evaluateObservable(kCpaMin, d0candidate.cpa()); + this->evaluateObservable(kDecayLengthMin, d0candidate.decayLength()); + this->evaluateObservable(kImpactParameterProductMax, d0candidate.impactParameter0() * d0candidate.impactParameter1()); + this->evaluateObservable(kCosThetaStarMax, mHfHelper.cosThetaStarD0(d0candidate)); + this->template assembleBitmask(); + } + + template + bool checkFilters(const T& d0candidate) const + { + bool pass = true; + bool p = false; + + // decay channel + p = (d0candidate.hfflag() & (1 << o2::aod::hf_cand_2prong::DecayType::D0ToPiK)) != 0; + this->template fillFilter(kDecayChannel, p); + pass &= p; + + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { + p = d0candidate.isSelD0(); + } else { + p = d0candidate.isSelD0bar(); + } + + this->template fillFilter(kHypothesis, p); + pass &= p; + + p = d0candidate.pt() > mPtMin; + this->template fillFilter(kPtMin, p); + pass &= p; + + p = d0candidate.pt() < mPtMax; + this->template fillFilter(kPtMax, p); + pass &= p; + + p = d0candidate.eta() > mEtaMin; + this->template fillFilter(kEtaMin, p); + pass &= p; + + p = d0candidate.eta() < mEtaMax; + this->template fillFilter(kEtaMax, p); + pass &= p; + + p = d0candidate.phi() > mPhiMin; + this->template fillFilter(kPhiMin, p); + pass &= p; + + p = d0candidate.phi() < mPhiMax; + this->template fillFilter(kPhiMax, p); + pass &= p; + + // rapidity + if (mUseYCut) { + const float y = mHfHelper.yD0(d0candidate); + p = y > mYMin; + this->template fillFilter(kYMin, p); + pass &= p; + + p = y < mYMax; + this->template fillFilter(kYMax, p); + pass &= p; + } + + this->template fillFilterSummary(pass); + return this->isPassThrough() || pass; + } + + [[nodiscard]] float getMassMin() const + { + return mMassMin; + } + + [[nodiscard]] float getMassMax() const + { + return mMassMax; + } + + private: + HfHelper mHfHelper; + float mPtMin = 0.f; + float mPtMax = 24.f; + float mEtaMin = -0.8f; + float mEtaMax = 0.8f; + float mPhiMin = 0.f; + float mPhiMax = o2::constants::math::TwoPI; + float mMassMin = 1.7f; + float mMassMax = 2.0f; + bool mUseYCut = true; + float mYMin = -0.8f; + float mYMax = 0.8f; +}; + +// tables produced by the D0 builder: kinematics, bitmask and QA +struct CharmHadronBuilderProducts : o2::framework::ProducesGroup { + o2::framework::Produces producedD0s; + o2::framework::Produces producedD0Masks; + o2::framework::Produces producedD0Extras; +}; + +// per-table produce switches (-1: auto = produce only if a downstream device subscribes; 0 off; 1 on) +struct ConfD0Tables : o2::framework::ConfigurableGroup { + std::string prefix = std::string("D0Tables"); + o2::framework::Configurable produceD0s{"produceD0s", -1, "Produce D0s (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceD0Masks{"produceD0Masks", -1, "Produce D0Masks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceD0Extras{"produceD0Extras", -1, "Produce D0Extras (-1: auto; 0 off; 1 on)"}; +}; + +template +class CharmHadronBuilder +{ + public: + CharmHadronBuilder() = default; + ~CharmHadronBuilder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext) + { + LOG(info) << "Initialize femto D0 builder..."; + mProduceD0s = utils::enableTable("FD0s_001", table.produceD0s.value, initContext); + mProduceD0Masks = utils::enableTable("FD0Masks_001", table.produceD0Masks.value, initContext); + mProduceD0Extras = utils::enableTable("FD0Extras_001", table.produceD0Extras.value, initContext); + + if (mProduceD0s || mProduceD0Masks || mProduceD0Extras) { + mFillAnyTable = true; + } else { + LOG(info) << "No D0 tables configured, selection object will not be configured..."; + return; + } + + mD0Selection.configure(registry, config, filter); + mD0Selection.printSelections(D0SelsName); + } + + template + void fillD0Tables(T1& collisionProducts, T2& d0Products, T3 const& candidate, + float signedPt, float mass, int64_t posDauIndex, int64_t negDauIndex) + { + if (mProduceD0s) { + d0Products.producedD0s(collisionProducts.producedCollision.lastIndex(), + signedPt, + candidate.eta(), + candidate.phi(), + mass, + posDauIndex, + negDauIndex); + } + if (mProduceD0Masks) { + d0Products.producedD0Masks(mD0Selection.getBitmask()); + } + if (mProduceD0Extras) { + d0Products.producedD0Extras( + mHfHelper.invMassD0ToPiK(candidate), + mHfHelper.invMassD0barToKPi(candidate), + candidate.cpa(), + candidate.cpaXY(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.impactParameter0() * candidate.impactParameter1(), + mHfHelper.cosThetaStarD0(candidate), + candidate.mlProbD0().size() < NSizeMLScore ? -1.f : candidate.mlProbD0()[0], + candidate.mlProbD0().size() < NSizeMLScore ? -1.f : candidate.mlProbD0()[1], + candidate.mlProbD0().size() < NSizeMLScore ? -1.f : candidate.mlProbD0()[2], + candidate.mlProbD0bar().size() < NSizeMLScore ? -1.f : candidate.mlProbD0bar()[0], + candidate.mlProbD0bar().size() < NSizeMLScore ? -1.f : candidate.mlProbD0bar()[1], + candidate.mlProbD0bar().size() < NSizeMLScore ? -1.f : candidate.mlProbD0bar()[2], + static_cast(candidate.isSelD0()), + static_cast(candidate.isSelD0bar())); + } + } + + template + void fillD0s(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4& trackProducts, + T5& d0Products, T6 const& candidates, T7 const& /*tracks*/, T8& trackBuilder) + { + if (!mFillAnyTable) { + return; + } + int64_t posDauIndex = 0; + int64_t negDauIndex = 0; + for (const auto& candidate : candidates) { + if (!mD0Selection.checkFilters(candidate)) { + continue; + } + mD0Selection.applySelections(candidate); + if (!mD0Selection.passesAllRequiredSelections()) { + continue; + } + + collisionBuilder.template fillCollision(collisionProducts, col); + + auto prong0 = candidate.template prong0_as(); + auto prong1 = candidate.template prong1_as(); + posDauIndex = trackBuilder.template getDaughterIndex(prong0, trackProducts, collisionBuilder); + negDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, collisionBuilder); + + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { + this->fillD0Tables(collisionProducts, d0Products, candidate, candidate.pt(), mHfHelper.invMassD0ToPiK(candidate), posDauIndex, negDauIndex); + } else { + this->fillD0Tables(collisionProducts, d0Products, candidate, -candidate.pt(), mHfHelper.invMassD0barToKPi(candidate), posDauIndex, negDauIndex); + } + } + } + + template + void fillMcD0s(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4 const& mcCols, T5& trackProducts, + T6& d0Products, T7 const& candidates, T8 const& tracks, T9& trackBuilder, T10 const& mcParticles, T11& mcBuilder, T12& mcProducts) + { + if (!mFillAnyTable) { + return; + } + int64_t posDauIndex = 0; + int64_t negDauIndex = 0; + for (const auto& candidate : candidates) { + if (!mD0Selection.checkFilters(candidate)) { + continue; + } + + mD0Selection.applySelections(candidate); + if (!mD0Selection.passesAllRequiredSelections()) { + continue; + } + + collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); + + auto prong0 = candidate.template prong0_as(); + auto prong1 = candidate.template prong1_as(); + posDauIndex = trackBuilder.template getDaughterIndex(col, collisionBuilder, mcCols, prong0, trackProducts, mcParticles, mcBuilder, mcProducts); + negDauIndex = trackBuilder.template getDaughterIndex(col, collisionBuilder, mcCols, prong1, trackProducts, mcParticles, mcBuilder, mcProducts); + + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { + this->fillD0Tables(collisionProducts, d0Products, candidate, candidate.pt(), mHfHelper.invMassD0ToPiK(candidate), posDauIndex, negDauIndex); + } else { + this->fillD0Tables(collisionProducts, d0Products, candidate, -candidate.pt(), mHfHelper.invMassD0barToKPi(candidate), posDauIndex, negDauIndex); + } + mcBuilder.template fillMcD0WithLabel(col, mcCols, candidate, tracks, mcParticles, mcProducts); + } + } + + private: + D0Selection mD0Selection; + HfHelper mHfHelper; + + bool mProduceD0s = false; + bool mProduceD0Masks = false; + bool mProduceD0Extras = false; + bool mFillAnyTable = false; +}; +} // namespace o2::analysis::femto::charmhadronbuilder + +#endif // PWGCF_FEMTO_CORE_CHARMHADRONBUILDER_H_ diff --git a/PWGCF/Femto/Core/charmHadronHistManager.h b/PWGCF/Femto/Core/charmHadronHistManager.h new file mode 100644 index 00000000000..6b839b90ca3 --- /dev/null +++ b/PWGCF/Femto/Core/charmHadronHistManager.h @@ -0,0 +1,495 @@ +// Copyright 2019-2026 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 charmHadronHistManager.h +/// \brief histogram manager for charm hadron histograms +/// \author Igor Ptak, WUT, igor.tomasz.ptak@cern.ch + +#ifndef PWGCF_FEMTO_CORE_CHARMHADRONHISTMANAGER_H_ +#define PWGCF_FEMTO_CORE_CHARMHADRONHISTMANAGER_H_ + +#include "PWGCF/Femto/Core/histManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/trackHistManager.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace o2::analysis::femto::charmhadronhistmanager +{ +enum CharmHadronHist { + kPt, + kEta, + kPhi, + kMass, + kSign, + kPtVsMass, + kPtVsEta, + kPtVsPhi, + kPhiVsEta, + kMassD0, + kMassD0bar, + kMlBkg, + kMlPrompt, + kMlNonPrompt, + kCpa, + kCpaXY, + kDecayLength, + kDecayLengthXY, + kImpactParameterProduct, + kCosThetaStar, + + // mc + kOrigin, + kPdg, + kPdgMother, + kTruePtVsPt, + kTrueEtaVsEta, + kTruePhiVsPhi, + kPtVsOrigin, + + kCharmHadronHistLast +}; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define CHARMHADRON_DEFAULT_BINNING(defaultMassMin, defaultMassMax) \ + o2::framework::ConfigurableAxis pt{"pt", {{600, 0, 6}}, "Pt"}; \ + o2::framework::ConfigurableAxis eta{"eta", {{300, -1.5, 1.5}}, "Eta"}; \ + o2::framework::ConfigurableAxis phi{"phi", {{720, 0, 1.f * o2::constants::math::TwoPI}}, "Phi"}; \ + o2::framework::ConfigurableAxis mass{"mass", {{200, (defaultMassMin), (defaultMassMax)}}, "Mass"}; \ + o2::framework::ConfigurableAxis sign{"sign", {{3, -1.5, 1.5}}, "Sign"}; \ + o2::framework::ConfigurableAxis charmHadrons{"charmHadrons", {{8001, -4000.5, 4000.5}}, "MC ONLY: CharmHadrons codes of reconstructed D0s"}; \ + o2::framework::ConfigurableAxis pt2d{"pt2d", {{240, 0, 6}}, "Pt for 2D QA"}; \ + o2::framework::ConfigurableAxis eta2d{"eta2d", {{200, -1.5, 1.5}}, "Eta for 2D QA"}; \ + o2::framework::ConfigurableAxis phi2d{"phi2d", {{200, 0, 1.f * o2::constants::math::TwoPI}}, "Phi for 2D QA"}; + +template +struct ConfD0Binning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + CHARMHADRON_DEFAULT_BINNING(1.7, 2.0) +}; + +#undef CHARMHADRON_DEFAULT_BINNING + +constexpr const char PrefixD0Binning1[] = "D0Binning1"; +using ConfD0Binning1 = ConfD0Binning; + +template +struct ConfD0QaBinning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + o2::framework::Configurable plotTopology{"plotTopology", true, "Generate topological QA plots (cpa, decayLength, impactParameterProduct, cosThetaStar)"}; + o2::framework::ConfigurableAxis massD0{"massD0", {{200, 1.7, 2.0}}, "Mass for D0 (Kpi) hypothesis"}; + o2::framework::ConfigurableAxis massD0bar{"massD0bar", {{200, 1.7, 2.0}}, "Mass for D0bar (piK) hypothesis"}; + o2::framework::ConfigurableAxis mlScore{"mlScore", {{100, 0.f, 1.f}}, "BDT ML score (bkg/prompt/non-prompt)"}; + o2::framework::ConfigurableAxis cpa{"cpa", {{100, 0.9f, 1.f}}, "Cosine of pointing angle"}; + o2::framework::ConfigurableAxis decayLength{"decayLength", {{200, 0.f, 0.2f}}, "Decay length (cm)"}; + o2::framework::ConfigurableAxis impactParameterProduct{"impactParameterProduct", {{200, -0.001f, 0.001f}}, "Product of daughter impact parameters (cm^2)"}; + o2::framework::ConfigurableAxis cosThetaStar{"cosThetaStar", {{100, -1.f, 1.f}}, "Cosine of decay angle in D0 rest frame"}; +}; + +constexpr const char PrefixD0QaBinning1[] = "D0QaBinning1"; +using ConfD0QaBinning1 = ConfD0QaBinning; + +// must be in sync with enum CharmHadronHist +// the enum gives the correct index in the array +constexpr std::array, kCharmHadronHistLast> HistTable = { + {{kPt, o2::framework::HistType::kTH1F, "hPt", "Transverse Momentum; p_{T} (GeV/#it{c}); Entries"}, + {kEta, o2::framework::HistType::kTH1F, "hEta", "Pseudorapdity; #eta; Entries"}, + {kPhi, o2::framework::HistType::kTH1F, "hPhi", "Azimuthal angle; #varphi; Entries"}, + {kMass, o2::framework::HistType::kTH1F, "hMass", "Invariant Mass; m_{Inv} (GeV/#it{c}^{2}); Entries"}, + {kSign, o2::framework::HistType::kTH1F, "hSign", "Sign (-1 -> D0bar, +1 -> D0); sign; Entries"}, + {kPtVsMass, o2::framework::HistType::kTH2F, "hPtVsMass", "Transverse momentum vs invariant mass; p_{T} (GeV/#it{c}); m_{Inv} (GeV/#it{c}^{2})"}, + {kPtVsEta, o2::framework::HistType::kTH2F, "hPtVsEta", "p_{T} vs #eta; p_{T} (GeV/#it{c}); #eta"}, + {kPtVsPhi, o2::framework::HistType::kTH2F, "hPtVsPhi", "p_{T} vs #varphi; p_{T} (GeV/#it{c}); #varphi"}, + {kPhiVsEta, o2::framework::HistType::kTH2F, "hPhiVsEta", "#varphi vs #eta; #varphi; #eta"}, + {kMassD0, o2::framework::HistType::kTH1F, "hMassD0", "D0 (K#pi) mass; m_{K#pi} (GeV/#it{c}^{2}); Entries"}, + {kMassD0bar, o2::framework::HistType::kTH1F, "hMassD0bar", "#bar{D0} (#piK) mass; m_{#piK} (GeV/#it{c}^{2}); Entries"}, + {kMlBkg, o2::framework::HistType::kTH1F, "hMlBkg", "BDT background score; ML score (bkg); Entries"}, + {kMlPrompt, o2::framework::HistType::kTH1F, "hMlPrompt", "BDT prompt score; ML score (prompt); Entries"}, + {kMlNonPrompt, o2::framework::HistType::kTH1F, "hMlNonPrompt", "BDT non-prompt score; ML score (non-prompt); Entries"}, + {kCpa, o2::framework::HistType::kTH1F, "hCpa", "Cosine of pointing angle; cos(#alpha); Entries"}, + {kCpaXY, o2::framework::HistType::kTH1F, "hCpaXY", "Cosine of pointing angle (XY); cos(#alpha)_{XY}; Entries"}, + {kDecayLength, o2::framework::HistType::kTH1F, "hDecayLength", "Decay length; L (cm); Entries"}, + {kDecayLengthXY, o2::framework::HistType::kTH1F, "hDecayLengthXY", "Decay length (XY); L_{XY} (cm); Entries"}, + {kImpactParameterProduct, o2::framework::HistType::kTH1F, "hImpactParameterProduct", "Product of daughter impact parameters; d_{0}^{K} #times d_{0}^{#pi} (cm^{2}); Entries"}, + {kCosThetaStar, o2::framework::HistType::kTH1F, "hCosThetaStar", "Cosine of decay angle in D0 rest frame; cos(#theta*); Entries"}, + {kOrigin, o2::framework::HistType::kTH1F, "hOrigin", "MC origin (prompt / non-prompt); origin; Entries"}, + {kPdg, o2::framework::HistType::kTH1F, "hPdg", "PDG code of matched generated particle; PDG code; Entries"}, + {kPdgMother, o2::framework::HistType::kTH1F, "hPdgMother", "PDG code of the mother; PDG code; Entries"}, + {kTruePtVsPt, o2::framework::HistType::kTH2F, "hTruePtVsPt", "True vs reconstructed p_{T}; p_{T,true} (GeV/#it{c}); p_{T} (GeV/#it{c})"}, + {kTrueEtaVsEta, o2::framework::HistType::kTH2F, "hTrueEtaVsEta", "True vs reconstructed #eta; #eta_{true}; #eta"}, + {kTruePhiVsPhi, o2::framework::HistType::kTH2F, "hTruePhiVsPhi", "True vs reconstructed #varphi; #varphi_{true}; #varphi"}, + {kPtVsOrigin, o2::framework::HistType::kTH2F, "hPtVsOrigin", "p_{T} vs MC origin; p_{T} (GeV/#it{c}); origin"}}, +}; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define CHARMHADRON_HIST_ANALYSIS_MAP(conf) \ + {kPt, {(conf).pt}}, \ + {kEta, {(conf).eta}}, \ + {kPhi, {(conf).phi}}, \ + {kMass, {(conf).mass}}, \ + {kSign, {(conf).sign}}, \ + {kPtVsMass, {(conf).pt, (conf).mass}}, \ + {kPtVsEta, {(conf).pt2d, (conf).eta2d}}, \ + {kPtVsPhi, {(conf).pt2d, (conf).phi2d}}, \ + {kPhiVsEta, {(conf).phi2d, (conf).eta2d}}, + +template +auto makeD0HistSpecMap(const T& confBinningAnalysis) +{ + return std::map>{ + CHARMHADRON_HIST_ANALYSIS_MAP(confBinningAnalysis)}; +} + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define CHARMHADRON_HIST_MC_MAP(conf) \ + {kPdg, {(conf).charmHadrons}}, \ + {kPdgMother, {(conf).charmHadrons}}, \ + {kTruePtVsPt, {(conf).pt, (conf).pt}}, \ + {kTrueEtaVsEta, {(conf).eta, (conf).eta}}, \ + {kTruePhiVsPhi, {(conf).phi, (conf).phi}}, \ + {kPtVsOrigin, {(conf).pt2d}}, + +template +auto makeD0McHistSpecMap(const T& confBinningAnalysis) +{ + return std::map>{ + CHARMHADRON_HIST_ANALYSIS_MAP(confBinningAnalysis) + CHARMHADRON_HIST_MC_MAP(confBinningAnalysis)}; +} + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define CHARMHADRON_HIST_QA_MAP(conf) \ + {kMassD0, {(conf).massD0}}, \ + {kMassD0bar, {(conf).massD0bar}}, \ + {kMlBkg, {(conf).mlScore}}, \ + {kMlPrompt, {(conf).mlScore}}, \ + {kMlNonPrompt, {(conf).mlScore}}, \ + {kCpa, {(conf).cpa}}, \ + {kCpaXY, {(conf).cpa}}, \ + {kDecayLength, {(conf).decayLength}}, \ + {kDecayLengthXY, {(conf).decayLength}}, \ + {kImpactParameterProduct, {(conf).impactParameterProduct}}, \ + {kCosThetaStar, {(conf).cosThetaStar}}, + +template +auto makeD0QaHistSpecMap(const T& confBinningQa) +{ + return std::map>{ + CHARMHADRON_HIST_QA_MAP(confBinningQa)}; +} + +template +auto makeD0McQaHistSpecMap(const T1& confBinningAnalysis, const T2& confBinningQa) +{ + return std::map>{ + CHARMHADRON_HIST_ANALYSIS_MAP(confBinningAnalysis) + CHARMHADRON_HIST_QA_MAP(confBinningQa) + CHARMHADRON_HIST_MC_MAP(confBinningAnalysis)}; +} + +#undef CHARMHADRON_HIST_ANALYSIS_MAP +#undef CHARMHADRON_HIST_MC_MAP +#undef CHARMHADRON_HIST_QA_MAP + +// prefixes for the output directories in the histogram registry +constexpr char PrefixD01[] = "D01/"; +constexpr char PrefixD02[] = "D02/"; +constexpr char PrefixD0Qa[] = "D0QA/"; +constexpr std::string_view AnalysisDir = "Analysis/"; +constexpr std::string_view McDir = "MC/"; +constexpr std::string_view QaDir = "QA/"; + +/// \class CharmHadronHistManager +/// \brief Class for histogramming charm hadron properties +template +class CharmHadronHistManager +{ + public: + CharmHadronHistManager() = default; + ~CharmHadronHistManager() = default; + + // init for analysis + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& CharmHadronSpecs, + T const& ConfCharmHadronSelection, + std::map> const& Prong0Specs, + std::map> const& Prong1Specs) + { + mHistogramRegistry = registry; + mPdgCode = std::abs(ConfCharmHadronSelection.pdgCodeAbs.value); + + auto [prong0PdgCodeAbs, prong1PdgCodeAbs] = this->resolveProngPdgCodes(ConfCharmHadronSelection.sign.value); + + mProng0Manager.template init(registry, Prong0Specs, AbsCharge, SignPlus, prong0PdgCodeAbs); + mProng1Manager.template init(registry, Prong1Specs, AbsCharge, SignMinus, prong1PdgCodeAbs); + + if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { + this->initAnalysis(CharmHadronSpecs); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kMc)) { + this->initMc(CharmHadronSpecs); + } + } + + // init for analysis and qa + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& CharmHadronSpecs, + std::map> const& CharmHadronQaSpecs, + T1 const& ConfCharmHadronSelection, + T2 const& ConfCharmHadronQaBinning, + std::map> const& Prong0Specs, + T3 const& ConfProng0BinningQa, + std::map> const& Prong1Specs, + T4 const& ConfProng1BinningQa) + { + mHistogramRegistry = registry; + mPdgCode = std::abs(ConfCharmHadronSelection.pdgCodeAbs.value); + this->enableOptionalHistograms(ConfCharmHadronQaBinning); + + auto [prong0PdgCodeAbs, prong1PdgCodeAbs] = this->resolveProngPdgCodes(ConfCharmHadronSelection.sign.value); + + mProng0Manager.template init(registry, Prong0Specs, AbsCharge, SignPlus, prong0PdgCodeAbs, ConfProng0BinningQa); + mProng1Manager.template init(registry, Prong1Specs, AbsCharge, SignMinus, prong1PdgCodeAbs, ConfProng1BinningQa); + + if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { + this->initAnalysis(CharmHadronSpecs); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { + this->initQa(CharmHadronQaSpecs); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kMc)) { + this->initMc(CharmHadronSpecs); + } + } + + template + void fill(T1 const& charmHadronCandidate, T2 const& tracks) + { + auto prong0 = tracks.rawIteratorAt(charmHadronCandidate.posDauId() - tracks.offset()); + mProng0Manager.template fill(prong0, tracks); + auto prong1 = tracks.rawIteratorAt(charmHadronCandidate.negDauId() - tracks.offset()); + mProng1Manager.template fill(prong1, tracks); + + if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { + this->fillAnalysis(charmHadronCandidate); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { + this->fillQa(charmHadronCandidate); + } + } + + template + void fill(T1 const& charmHadronCandidate, T2 const& tracks, T3 const& mcParticles, T4 const& mcMothers, T5 const& mcPartonicMothers) + { + auto prong0 = tracks.rawIteratorAt(charmHadronCandidate.posDauId() - tracks.offset()); + mProng0Manager.template fill(prong0, tracks, mcParticles, mcMothers, mcPartonicMothers); + auto prong1 = tracks.rawIteratorAt(charmHadronCandidate.negDauId() - tracks.offset()); + mProng1Manager.template fill(prong1, tracks, mcParticles, mcMothers, mcPartonicMothers); + + if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { + this->fillAnalysis(charmHadronCandidate); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kQa)) { + this->fillQa(charmHadronCandidate); + } + if constexpr (modes::isFlagSet(mode, modes::Mode::kMc)) { + this->fillMc(charmHadronCandidate, mcParticles, mcMothers, mcPartonicMothers); + } + } + + private: + static constexpr int AbsCharge = 1; + static constexpr int SignPlus = 1; + static constexpr int SignMinus = -1; + + // charge of the prongs is fixed by the PWGHF reconstruction: prong0 is the positive + // daughter, prong1 the negative one. The D0/D0bar hypothesis only swaps which prong is + // the pion and which is the kaon, not their charge. + std::pair resolveProngPdgCodes(int sign) + { + if (mPdgCode != o2::constants::physics::Pdg::kD0) { + LOG(fatal) << "PDG code for charm hadron has to be D0"; + } + if (sign > 0) { + // D0 -> pi+ K- + return {std::abs(PDG_t::kPiPlus), std::abs(PDG_t::kKMinus)}; + } + // D0bar -> K+ pi- + mPdgCode = -1 * mPdgCode; // switch sign for D0bar + return {std::abs(PDG_t::kKPlus), std::abs(PDG_t::kPiMinus)}; + } + + template + void enableOptionalHistograms(T const& ConfCharmHadronQaBinning) + { + mPlotTopology = ConfCharmHadronQaBinning.plotTopology.value; + } + + void initAnalysis(std::map> const& CharmHadronSpecs) + { + std::string analysisDir = std::string(charmHadronPrefix) + std::string(AnalysisDir); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPt, HistTable), getHistDesc(kPt, HistTable), getHistType(kPt, HistTable), {CharmHadronSpecs.at(kPt)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kEta, HistTable), getHistDesc(kEta, HistTable), getHistType(kEta, HistTable), {CharmHadronSpecs.at(kEta)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPhi, HistTable), getHistDesc(kPhi, HistTable), getHistType(kPhi, HistTable), {CharmHadronSpecs.at(kPhi)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kMass, HistTable), getHistDesc(kMass, HistTable), getHistType(kMass, HistTable), {CharmHadronSpecs.at(kMass)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kSign, HistTable), getHistDesc(kSign, HistTable), getHistType(kSign, HistTable), {CharmHadronSpecs.at(kSign)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPtVsMass, HistTable), getHistDesc(kPtVsMass, HistTable), getHistType(kPtVsMass, HistTable), {CharmHadronSpecs.at(kPtVsMass)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPtVsEta, HistTable), getHistDesc(kPtVsEta, HistTable), getHistType(kPtVsEta, HistTable), {CharmHadronSpecs.at(kPtVsEta)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPtVsPhi, HistTable), getHistDesc(kPtVsPhi, HistTable), getHistType(kPtVsPhi, HistTable), {CharmHadronSpecs.at(kPtVsPhi)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kPhiVsEta, HistTable), getHistDesc(kPhiVsEta, HistTable), getHistType(kPhiVsEta, HistTable), {CharmHadronSpecs.at(kPhiVsEta)}); + } + + template + void fillAnalysis(T const& charmHadronCandidate) + { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPt, HistTable)), charmHadronCandidate.pt()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kEta, HistTable)), charmHadronCandidate.eta()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPhi, HistTable)), charmHadronCandidate.phi()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kMass, HistTable)), charmHadronCandidate.mass()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kSign, HistTable)), charmHadronCandidate.sign()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPtVsMass, HistTable)), charmHadronCandidate.pt(), charmHadronCandidate.mass()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPtVsEta, HistTable)), charmHadronCandidate.pt(), charmHadronCandidate.eta()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPtVsPhi, HistTable)), charmHadronCandidate.pt(), charmHadronCandidate.phi()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPhiVsEta, HistTable)), charmHadronCandidate.phi(), charmHadronCandidate.eta()); + } + + void initQa(std::map> const& CharmHadronQaSpecs) + { + std::string qaDir = std::string(charmHadronPrefix) + std::string(QaDir); + mHistogramRegistry->add(qaDir + getHistNameV2(kMassD0, HistTable), getHistDesc(kMassD0, HistTable), getHistType(kMassD0, HistTable), {CharmHadronQaSpecs.at(kMassD0)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMassD0bar, HistTable), getHistDesc(kMassD0bar, HistTable), getHistType(kMassD0bar, HistTable), {CharmHadronQaSpecs.at(kMassD0bar)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMlBkg, HistTable), getHistDesc(kMlBkg, HistTable), getHistType(kMlBkg, HistTable), {CharmHadronQaSpecs.at(kMlBkg)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMlPrompt, HistTable), getHistDesc(kMlPrompt, HistTable), getHistType(kMlPrompt, HistTable), {CharmHadronQaSpecs.at(kMlPrompt)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMlNonPrompt, HistTable), getHistDesc(kMlNonPrompt, HistTable), getHistType(kMlNonPrompt, HistTable), {CharmHadronQaSpecs.at(kMlNonPrompt)}); + + if (mPlotTopology) { + mHistogramRegistry->add(qaDir + getHistNameV2(kCpa, HistTable), getHistDesc(kCpa, HistTable), getHistType(kCpa, HistTable), {CharmHadronQaSpecs.at(kCpa)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kCpaXY, HistTable), getHistDesc(kCpaXY, HistTable), getHistType(kCpaXY, HistTable), {CharmHadronQaSpecs.at(kCpaXY)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDecayLength, HistTable), getHistDesc(kDecayLength, HistTable), getHistType(kDecayLength, HistTable), {CharmHadronQaSpecs.at(kDecayLength)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kDecayLengthXY, HistTable), getHistDesc(kDecayLengthXY, HistTable), getHistType(kDecayLengthXY, HistTable), {CharmHadronQaSpecs.at(kDecayLengthXY)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kImpactParameterProduct, HistTable), getHistDesc(kImpactParameterProduct, HistTable), getHistType(kImpactParameterProduct, HistTable), {CharmHadronQaSpecs.at(kImpactParameterProduct)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kCosThetaStar, HistTable), getHistDesc(kCosThetaStar, HistTable), getHistType(kCosThetaStar, HistTable), {CharmHadronQaSpecs.at(kCosThetaStar)}); + } + } + + void initMc(std::map> const& CharmHadronSpecs) + { + std::string mcDir = std::string(charmHadronPrefix) + std::string(McDir); + + const o2::framework::AxisSpec axisOrigin = {static_cast(modes::McOrigin::kMcOriginLast), -0.5, static_cast(modes::McOrigin::kMcOriginLast) - 0.5}; + mHistogramRegistry->add(mcDir + getHistNameV2(kOrigin, HistTable), getHistDesc(kOrigin, HistTable), getHistType(kOrigin, HistTable), {axisOrigin}); + mHistogramRegistry->get(HIST(charmHadronPrefix) + HIST(McDir) + HIST(histmanager::getHistName(kOrigin, HistTable)))->GetXaxis()->SetBinLabel(1 + static_cast(modes::McOrigin::kPrompt), modes::mcOriginToString(modes::McOrigin::kPrompt)); + mHistogramRegistry->get(HIST(charmHadronPrefix) + HIST(McDir) + HIST(histmanager::getHistName(kOrigin, HistTable)))->GetXaxis()->SetBinLabel(1 + static_cast(modes::McOrigin::kNonPrompt), modes::mcOriginToString(modes::McOrigin::kNonPrompt)); + + mHistogramRegistry->add(mcDir + getHistNameV2(kPdg, HistTable), getHistDesc(kPdg, HistTable), getHistType(kPdg, HistTable), {CharmHadronSpecs.at(kPdg)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kPdgMother, HistTable), getHistDesc(kPdgMother, HistTable), getHistType(kPdgMother, HistTable), {CharmHadronSpecs.at(kPdgMother)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTruePtVsPt, HistTable), getHistDesc(kTruePtVsPt, HistTable), getHistType(kTruePtVsPt, HistTable), {CharmHadronSpecs.at(kTruePtVsPt)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTrueEtaVsEta, HistTable), getHistDesc(kTrueEtaVsEta, HistTable), getHistType(kTrueEtaVsEta, HistTable), {CharmHadronSpecs.at(kTrueEtaVsEta)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTruePhiVsPhi, HistTable), getHistDesc(kTruePhiVsPhi, HistTable), getHistType(kTruePhiVsPhi, HistTable), {CharmHadronSpecs.at(kTruePhiVsPhi)}); + std::vector ptVsOriginAxes = CharmHadronSpecs.at(kPtVsOrigin); + ptVsOriginAxes.push_back(axisOrigin); + mHistogramRegistry->add(mcDir + getHistNameV2(kPtVsOrigin, HistTable), getHistDesc(kPtVsOrigin, HistTable), getHistType(kPtVsOrigin, HistTable), ptVsOriginAxes); + } + + template + void fillQa(T const& charmHadronCandidate) + { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMassD0, HistTable)), charmHadronCandidate.massD0()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMassD0bar, HistTable)), charmHadronCandidate.massD0bar()); + + // BDT scores of the accepted hypothesis: D0 (sign > 0) or D0bar (sign < 0) + float mlBkg = 0.f; + float mlPrompt = 0.f; + float mlNonPrompt = 0.f; + if (charmHadronCandidate.sign() > 0) { + mlBkg = charmHadronCandidate.mlProbD0Bkg(); + mlPrompt = charmHadronCandidate.mlProbD0Prompt(); + mlNonPrompt = charmHadronCandidate.mlProbD0NonPrompt(); + } else { + mlBkg = charmHadronCandidate.mlProbD0barBkg(); + mlPrompt = charmHadronCandidate.mlProbD0barPrompt(); + mlNonPrompt = charmHadronCandidate.mlProbD0barNonPrompt(); + } + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMlBkg, HistTable)), mlBkg); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMlPrompt, HistTable)), mlPrompt); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMlNonPrompt, HistTable)), mlNonPrompt); + + // topological variables PWGHF selects on + if (mPlotTopology) { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kCpa, HistTable)), charmHadronCandidate.cpa()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kCpaXY, HistTable)), charmHadronCandidate.cpaXY()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kDecayLength, HistTable)), charmHadronCandidate.decayLength()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kDecayLengthXY, HistTable)), charmHadronCandidate.decayLengthXY()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kImpactParameterProduct, HistTable)), charmHadronCandidate.impactParameterProduct()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kCosThetaStar, HistTable)), charmHadronCandidate.cosThetaStar()); + } + } + + template + void fillMc(T1 const& charmHadronCandidate, T2 const& /*mcParticles*/, T3 const& /*mcMothers*/, T4 const& /*mcPartonicMothers*/) + { + // no matched generated particle: reconstructed, but not a true D0 + if (!charmHadronCandidate.has_fMcParticle()) { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kPdg, HistTable)), 0); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), static_cast(modes::McOrigin::kNoMcParticle)); + return; + } + + auto mcParticle = charmHadronCandidate.template fMcParticle_as(); + + // resolution: generated vs reconstructed kinematics + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kTruePtVsPt, HistTable)), mcParticle.pt(), charmHadronCandidate.pt()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kTrueEtaVsEta, HistTable)), mcParticle.eta(), charmHadronCandidate.eta()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kTruePhiVsPhi, HistTable)), mcParticle.phi(), charmHadronCandidate.phi()); + + // origin is resolved to prompt / non-prompt in the mc builder + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kOrigin, HistTable)), mcParticle.origin()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kPtVsOrigin, HistTable)), charmHadronCandidate.pt(), mcParticle.origin()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kPdg, HistTable)), mcParticle.pdgCode()); + + // pdg of the mother, i.e. the beauty hadron for non-prompt D0s + if (mcParticle.has_fMcMother()) { + auto mother = mcParticle.template fMcMother_as(); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kPdgMother, HistTable)), mother.pdgCode()); + } else { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(McDir) + HIST(getHistName(kPdgMother, HistTable)), 0); + } + } + + o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; + int mPdgCode = 0; + bool mPlotTopology = true; + + trackhistmanager::TrackHistManager mProng0Manager; + trackhistmanager::TrackHistManager mProng1Manager; +}; +}; // namespace o2::analysis::femto::charmhadronhistmanager +#endif // PWGCF_FEMTO_CORE_CHARMHADRONHISTMANAGER_H_ diff --git a/PWGCF/Femto/Core/closePairRejection.h b/PWGCF/Femto/Core/closePairRejection.h index 70b6a547be4..df8309dfba7 100644 --- a/PWGCF/Femto/Core/closePairRejection.h +++ b/PWGCF/Femto/Core/closePairRejection.h @@ -83,6 +83,7 @@ struct ConfCpr : o2::framework::ConfigurableGroup { constexpr const char PrefixCprTrackTrack[] = "CprTrackTrack"; constexpr const char PrefixCprTrackV0Daughter[] = "CprTrackV0Daughter"; +constexpr const char PrefixCprTrackD0Daughter[] = "CprTrackD0Daughter"; constexpr const char PrefixCprTrackResonanceDaughter[] = "CprTrackResonanceDaughter"; constexpr const char PrefixCprTrackKinkDaughter[] = "CprTrackKinkDaughter"; constexpr const char PrefixCprV0DaughterV0DaughterPos[] = "CprV0DaughterV0DaughterPos"; @@ -94,6 +95,7 @@ constexpr const char PrefixCprTrackCascadeBachelor[] = "CprTrackCascadeBachelor" // pairs using ConfCprTrackTrack = ConfCpr; using ConfCprTrackV0Daughter = ConfCpr; +using ConfCprTrackD0Daughter = ConfCpr; using ConfCprTrackResonanceDaughter = ConfCpr; using ConfCprTrackKinkDaughter = ConfCpr; using ConfCprV0DaugherV0DaughterPos = ConfCpr; @@ -111,6 +113,8 @@ constexpr char PrefixTrackTrackSe[] = "CPR_TrackTrack/SE/"; constexpr char PrefixTrackTrackMe[] = "CPR_TrackTrack/ME/"; constexpr char PrefixTrackV0DaughterSe[] = "CPR_TrackV0Dau/SE/"; constexpr char PrefixTrackV0DaughterMe[] = "CPR_TrackV0Dau/ME/"; +constexpr char PrefixTrackD0DaughterSe[] = "CPR_TrackD0Dau/SE/"; +constexpr char PrefixTrackD0DaughterMe[] = "CPR_TrackD0Dau/ME/"; constexpr char PrefixV0V0PosSe[] = "CPR_V0V0_PosDau/SE/"; constexpr char PrefixV0V0NegSe[] = "CPR_V0V0_NegDau/SE/"; constexpr char PrefixV0V0PosMe[] = "CPR_V0V0_PosDau/ME/"; diff --git a/PWGCF/Femto/Core/dataTypes.h b/PWGCF/Femto/Core/dataTypes.h index 19e39de5828..4a46191c0d4 100644 --- a/PWGCF/Femto/Core/dataTypes.h +++ b/PWGCF/Femto/Core/dataTypes.h @@ -57,6 +57,10 @@ using ParticleType = uint16_t; using MomentumType = uint16_t; using TransverseMassType = uint16_t; +// datatype for charm hadrons +using CharmHadronMaskType = uint32_t; +using CharmHadronType = uint16_t; + } // namespace o2::analysis::femto::datatypes #endif // PWGCF_FEMTO_CORE_DATATYPES_H_ diff --git a/PWGCF/Femto/Core/femtoUtils.h b/PWGCF/Femto/Core/femtoUtils.h index aae51de32c9..6182f91f2fd 100644 --- a/PWGCF/Femto/Core/femtoUtils.h +++ b/PWGCF/Femto/Core/femtoUtils.h @@ -99,6 +99,9 @@ inline double getPdgMass(int pdgCode) case o2::constants::physics::Pdg::kLambdaCPlus: mass = o2::constants::physics::MassLambdaCPlus; break; + case o2::constants::physics::Pdg::kD0: + mass = o2::constants::physics::MassD0; + break; case o2::constants::physics::Pdg::kDeuteron: mass = o2::constants::physics::MassDeuteron; break; diff --git a/PWGCF/Femto/Core/mcBuilder.h b/PWGCF/Femto/Core/mcBuilder.h index 1f584ec02bf..3fd1a86fdb7 100644 --- a/PWGCF/Femto/Core/mcBuilder.h +++ b/PWGCF/Femto/Core/mcBuilder.h @@ -21,13 +21,17 @@ #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/DataModel/FemtoTables.h" +#include "Common/Core/RecoDecay.h" + #include +#include #include #include #include #include +#include #include #include #include @@ -44,6 +48,7 @@ struct ConfMc : o2::framework::ConfigurableGroup { o2::framework::Configurable passThrough{"passThrough", false, "Passthrough all MC collisions and particles"}; o2::framework::Configurable findLastPartonicMother{"findLastPartonicMother", true, "If true, the partonic mother will be the first parton directly after the initial collision. If false, the partonic mother will be the last parton before hadronization"}; o2::framework::Configurable etaAcceptanceMcOnly{"etaAcceptanceMcOnly", 0.8, "For MC ONLY processing. |eta| acceptance for estimating primary track multiplicity"}; + o2::framework::Configurable charmYGenMax{"charmYGenMax", 0.8f, "Max |y| (rapidity) for generated charm hadrons (mc-only truth acceptance)"}; }; struct McBuilderProducts : o2::framework::ProducesGroup { @@ -57,6 +62,7 @@ struct McBuilderProducts : o2::framework::ProducesGroup { o2::framework::Produces producedTrackLabels; o2::framework::Produces producedLambdaLabels; o2::framework::Produces producedK0shortLabels; + o2::framework::Produces producedD0Labels; o2::framework::Produces producedSigmaLabels; o2::framework::Produces producedSigmaPlusLabels; o2::framework::Produces producedXiLabels; @@ -75,6 +81,7 @@ struct ConfMcTables : o2::framework::ConfigurableGroup { o2::framework::Configurable producedTrackLabels{"producedTrackLabels", -1, "Produce track labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedLambdaLabels{"producedLambdaLabels", -1, "Produce lambda labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedK0shortLabels{"producedK0shortLabels", -1, "Produce k0short labels (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable producedD0Labels{"producedD0Labels", -1, "Produce D0 labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedSigmaLabels{"producedSigmaLabels", -1, "Produce k0short labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedSigmaPlusLabels{"producedSigmaPlusLabels", -1, "Produce k0short labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedXiLabels{"producedXiLabels", -1, "Produce xi labels (-1: auto; 0 off; 1 on)"}; @@ -134,6 +141,7 @@ class McBuilder mProduceTrackLabels = utils::enableTable("FTrackLabels", table.producedTrackLabels.value, initContext); mProduceLambdaLabels = utils::enableTable("FLambdaLabels", table.producedLambdaLabels.value, initContext); mProduceK0shortLabels = utils::enableTable("FK0shortLabels", table.producedK0shortLabels.value, initContext); + mProduceD0Labels = utils::enableTable("FD0Labels", table.producedD0Labels.value, initContext); mProduceSigmaLabels = utils::enableTable("FSigmaLabels", table.producedSigmaLabels.value, initContext); mProduceSigmaPlusLabels = utils::enableTable("FSigmaPlusLabels", table.producedSigmaPlusLabels.value, initContext); mProduceXiLabels = utils::enableTable("FXiLabels", table.producedXiLabels.value, initContext); @@ -155,6 +163,7 @@ class McBuilder mPassThrough = config.passThrough.value; mEtaAcceptanceMcOnly = config.etaAcceptanceMcOnly.value; mFindLastPartonicMother = config.findLastPartonicMother.value; + mCharmYGenMax = config.charmYGenMax.value; LOG(info) << "Initialization done..."; } @@ -229,6 +238,19 @@ class McBuilder template void fillMcParticle(T1 const& mcParticle, T2 const& mcParticles, T3 const& mcCol, T4& mcProducts) { + // charm hadrons get a prompt/non-prompt origin, consistent with the reco-matched path; + // all other particles use the generic getOrigin inside getOrCreateMcParticleRow + if (std::abs(mcParticle.pdgCode()) == o2::constants::physics::Pdg::kD0) { + // truth-level acceptance for the efficiency denominator: keep only + // generated D0 -> K pi decays inside the rapidity acceptance + int8_t sign = 0; + if (!RecoDecay::isMatchedMCGen(mcParticles, mcParticle, o2::constants::physics::Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign)) { + return; + } + if (std::abs(mcParticle.y()) > mCharmYGenMax) { + return; + } + } this->getOrCreateMcParticleRow(mcParticle, mcParticles, mcCol, mcProducts); } @@ -262,6 +284,36 @@ class McBuilder fillMcLabelGeneric(col, mcCols, k0short, mcParticles, mcProducts, [](auto& prod, int64_t p) { prod.producedK0shortLabels(p); }); } + // D0 has no direct MC label (2-prong hypothesis built by PWGHF), so fillMcLabelGeneric + // cannot be reused. Both prongs are matched to a generated D0 -> K pi decay with + // RecoDecay::getMatchedMCRec, which returns the index of the generated mother; + // unmatched candidates get -1. + template + void fillMcD0WithLabel(T1 const& /*col*/, T2 const& /*mcCols*/, T3 const& d0candidate, T4 const& /*tracks*/, T5 const& mcParticles, T6& mcProducts) + { + if (!mProduceD0Labels) { + mcProducts.producedD0Labels(-1); + return; + } + + auto prong0 = d0candidate.template prong0_as(); + auto prong1 = d0candidate.template prong1_as(); + auto arrayDaughters = std::array{prong0, prong1}; + int8_t sign = 0; + const int indexMcRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, o2::constants::physics::Pdg::kD0, std::array{+kPiPlus, -kKPlus}, true, &sign); + + if (indexMcRec < 0) { + mcProducts.producedD0Labels(-1); + return; + } + + auto mcParticle = mcParticles.rawIteratorAt(indexMcRec); + auto mcCol = mcParticle.template mcCollision_as(); + int64_t mcParticleRow = this->getOrCreateMcParticleRow(mcParticle, mcParticles, mcCol, mcProducts); + + mcProducts.producedD0Labels(mcParticleRow); + } + template void fillMcSigmaWithLabel(T1 const& col, T2 const& mcCols, T3 const& sigmaDaughter, T4 const& mcParticles, T5& mcProducts) { @@ -331,6 +383,15 @@ class McBuilder } private: + // classify a charm hadron as prompt (charm from a c quark) or non-prompt (charm from a + // beauty decay) from the mc decay tree; shared by the reco-matched and generator-level paths + template + modes::McOrigin getHeavyFlavourOrigin(T1 const& mcParticle, T2 const& mcParticles) + { + const int charmOrigin = RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle); + return (charmOrigin == RecoDecay::OriginType::NonPrompt) ? modes::McOrigin::kNonPrompt : modes::McOrigin::kPrompt; + } + template modes::McOrigin getOrigin(T1 const& col, T2 const& /*mcCols*/, T3 const& mcParticle) { @@ -389,7 +450,9 @@ class McBuilder template int64_t getOrCreateMcParticleRow(T1 const& mcParticle, T2 const& mcParticles, T3 const& mcCol, T4& mcProducts) { - auto origin = this->getOrigin(mcParticle); + auto origin = std::abs(mcParticle.pdgCode()) == o2::constants::physics::Pdg::kD0 + ? this->getHeavyFlavourOrigin(mcParticle, mcParticles) + : this->getOrigin(mcParticle); return this->buildMcParticleRow(mcParticle, mcParticles, mcCol, origin, mcProducts); } @@ -398,7 +461,9 @@ class McBuilder template int64_t getOrCreateMcParticleRow(T1 const& col, T2 const& mcCols, T3 const& mcParticle, T4 const& mcParticles, T5 const& mcCol, T6& mcProducts) { - auto origin = this->getOrigin(col, mcCols, mcParticle); + auto origin = std::abs(mcParticle.pdgCode()) == o2::constants::physics::Pdg::kD0 + ? this->getHeavyFlavourOrigin(mcParticle, mcParticles) + : this->getOrigin(col, mcCols, mcParticle); return this->buildMcParticleRow(mcParticle, mcParticles, mcCol, origin, mcProducts); } @@ -612,11 +677,13 @@ class McBuilder bool mProduceTrackLabels = false; bool mProduceLambdaLabels = false; bool mProduceK0shortLabels = false; + bool mProduceD0Labels = false; bool mProduceSigmaLabels = false; bool mProduceSigmaPlusLabels = false; bool mProduceXiLabels = false; bool mProduceOmegaLabels = false; bool mProduceMcMotherLabels = false; + float mCharmYGenMax = 0.8; float mEtaAcceptanceMcOnly = 0.8; diff --git a/PWGCF/Femto/Core/modes.h b/PWGCF/Femto/Core/modes.h index e3694abbf53..c928e31b1d5 100644 --- a/PWGCF/Femto/Core/modes.h +++ b/PWGCF/Femto/Core/modes.h @@ -97,6 +97,7 @@ enum class Particle : o2::analysis::femto::datatypes::ParticleType { kV0 = 3, kKink = 4, kCascade = 5, + kCharmHadron = 6, }; enum class McOrigin : o2::analysis::femto::datatypes::McOriginType { @@ -106,7 +107,9 @@ enum class McOrigin : o2::analysis::femto::datatypes::McOriginType { kFromSecondaryDecay = 3, // particle from secondary decay kFromMaterial = 4, // partilce orginates from material kMissidentified = 5, // partilce was kMissidentified (also know as fake) - kMcOriginLast = 6 + kPrompt = 6, // HF only: charm hadron produced promptly (from c quark) + kNonPrompt = 7, // HF only: charm hadron from beauty decay + kMcOriginLast = 8 // kFromFakeRecoCollision, // kFromUnkown }; @@ -126,6 +129,10 @@ constexpr const char* mcOriginToString(McOrigin origin) return "FromMaterial"; case McOrigin::kMissidentified: return "Missidentified"; + case McOrigin::kPrompt: + return "Prompt"; + case McOrigin::kNonPrompt: + return "NonPrompt"; default: return "UnknownMcOrigin"; } @@ -136,7 +143,8 @@ enum class Track : o2::analysis::femto::datatypes::TrackType { kV0Daughter, kCascadeBachelor, kResonanceDaughter, - kKinkDaughter + kKinkDaughter, + kCharmDaughter }; enum class V0 : o2::analysis::femto::datatypes::V0Type { @@ -163,5 +171,12 @@ enum class TwoTrackResonance : o2::analysis::femto::datatypes::TwoTrackResonance kKstar0Bar }; +enum class CharmHadron : o2::analysis::femto::datatypes::CharmHadronType { + kD0, + kD0Bar, + kDplus, + kLc +}; + }; // namespace o2::analysis::femto::modes #endif // PWGCF_FEMTO_CORE_MODES_H_ diff --git a/PWGCF/Femto/Core/pairBuilder.h b/PWGCF/Femto/Core/pairBuilder.h index 1cc9cf94a39..b7a181ebca6 100644 --- a/PWGCF/Femto/Core/pairBuilder.h +++ b/PWGCF/Femto/Core/pairBuilder.h @@ -17,6 +17,7 @@ #define PWGCF_FEMTO_CORE_PAIRBUILDER_H_ #include "PWGCF/Femto/Core/cascadeHistManager.h" +#include "PWGCF/Femto/Core/charmHadronHistManager.h" #include "PWGCF/Femto/Core/closePairRejection.h" #include "PWGCF/Femto/Core/collisionHistManager.h" #include "PWGCF/Femto/Core/kinkHistManager.h" @@ -562,6 +563,171 @@ class PairV0V0Builder static_cast(pairprocesshelpers::kOrder21)}; }; +template +class PairTrackD0Builder +{ + public: + PairTrackD0Builder() = default; + ~PairTrackD0Builder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, + T1 const& confCollisionBinning, + T2 const& confTrackSelection, + T3 const& confTrackCleaner, + T4 const& confD0Selection, + T5 const& confD0Cleaner, + T6 const& confCpr, + T7 const& confMixing, + T8 const& confPairBinning, + T9 const& confPairCuts, + std::map>& colHistSpec, + std::map>& trackHistSpec, + std::map>& d0HistSpec, + std::map>& posDauHistSpec, + std::map>& negDauHistSpec, + std::map>& pairHistSpec, + std::map>& cprHistSpec) + { + mColHistManager.template init(registry, colHistSpec, confCollisionBinning); + + mTrackHistManager.template init(registry, trackHistSpec, confTrackSelection); + mD0HistManager.template init(registry, d0HistSpec, confD0Selection, posDauHistSpec, negDauHistSpec); + + mTrackCleaner.init(confTrackCleaner); + mD0Cleaner.init(confD0Cleaner); + + // pdg codes of the D0 prongs depend on the hypothesis: + // D0 -> pi+ K- => PosDau = pion, NegDau = kaon + // D0bar -> K+ pi- => PosDau = kaon, NegDau = pion + int posDauPdg = 0; + int negDauPdg = 0; + if (confD0Selection.sign.value > 0) { + posDauPdg = PDG_t::kPiPlus; + negDauPdg = PDG_t::kKMinus; + } else { + posDauPdg = PDG_t::kKPlus; + negDauPdg = PDG_t::kPiMinus; + } + + mPairHistManagerSe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); + mPairHistManagerSe.setMass(confTrackSelection.pdgCodeAbs.value, 0, 0, confD0Selection.pdgCodeAbs.value, posDauPdg, negDauPdg); + mPairHistManagerSe.setCharge(confTrackSelection.chargeAbs.value, 1); + mCprSe.init(registry, cprHistSpec, confCpr, confTrackSelection.chargeAbs.value); + + mPairHistManagerMe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); + mPairHistManagerMe.setMass(confTrackSelection.pdgCodeAbs.value, 0, 0, confD0Selection.pdgCodeAbs.value, posDauPdg, negDauPdg); + mPairHistManagerMe.setCharge(confTrackSelection.chargeAbs.value, 1); + mCprMe.init(registry, cprHistSpec, confCpr, confTrackSelection.chargeAbs.value); + mPc.template init(confPairCuts); + + // setup mixing + mMixingPolicy = static_cast(confMixing.policy.value); + mMixingDepth = confMixing.depth.value; + } + + template + void processSameEvent(T1 const& col, T2& trackTable, T3& trackPartition, T4& /*d0table*/, T5& d0Partition, T6& cache) + { + auto trackSlice = trackPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto d0Slice = d0Partition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (trackSlice.size() < nLimitPartitionParticles || d0Slice.size() < nLimitPartitionParticles) { + return; + } + mColHistManager.template fill(col); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(trackSlice, d0Slice, trackTable, col, mTrackHistManager, mD0HistManager, mPairHistManagerSe, mCprSe, mPc); + } + + template + void processMixedEvent(T1 const& cols, T2& trackTable, T3& trackPartition, T4& d0Partition, T5& cache, T6& binsVtxMult, T7& binsVtxCent, T8& binsVtxMultCent) + { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, trackPartition, d0Partition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, trackPartition, d0Partition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, trackPartition, d0Partition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + + template + void processSameEvent(T1 const& col, T2 const& mcCols, T3 const& trackTable, T4& trackPartition, T5 const& /*d0table*/, T6& d0Partition, T7 const& mcParticles, T8 const& mcMothers, T9 const& mcPartonicMothers, T10& cache) + { + auto trackSlice = trackPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto d0Slice = d0Partition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (trackSlice.size() < nLimitPartitionParticles || d0Slice.size() < nLimitPartitionParticles) { + return; + } + mColHistManager.template fill(col, mcCols); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(trackSlice, d0Slice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager, mD0HistManager, mPairHistManagerSe, mTrackCleaner, mD0Cleaner, mCprSe, mPc); + } + + template + void processMixedEvent(T1 const& cols, T2 const& mcCols, T3& trackTable, T4& trackPartition, T5& d0Partition, T6 const& mcParticles, T7 const& mcMothers, T8 const& mcPartonicMothers, T9& cache, T10& binsVtxMult, T11& binsVtxCent, T12& binsVtxMultCent) + { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, d0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mD0Cleaner, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, d0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mD0Cleaner, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, d0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mD0Cleaner, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + + private: + colhistmanager::CollisionHistManager mColHistManager; + trackhistmanager::TrackHistManager mTrackHistManager; + charmhadronhistmanager::CharmHadronHistManager mD0HistManager; + particlecleaner::ParticleCleaner mTrackCleaner; + particlecleaner::ParticleCleaner mD0Cleaner; + pairhistmanager::PairHistManager mPairHistManagerSe; + pairhistmanager::PairHistManager mPairHistManagerMe; + closepairrejection::ClosePairRejectionTrackV0 mCprSe; + closepairrejection::ClosePairRejectionTrackV0 mCprMe; + paircleaner::TrackV0PairCleaner mPc; + pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; + int mMixingDepth = 5; +}; + template ; using ConfLambdaCleaner2 = ConfParticleCleaner; +constexpr const char PrefixD0Cleaner1[] = "D0Cleaner1"; +constexpr const char PrefixD0Cleaner2[] = "D0Cleaner2"; +using ConfD0Cleaner1 = ConfParticleCleaner; +using ConfD0Cleaner2 = ConfParticleCleaner; + constexpr const char PrefixK0shortCleaner1[] = "K0shortCleaner1"; constexpr const char PrefixK0shortCleaner2[] = "K0shortCleaner2"; using ConfK0shortCleaner1 = ConfParticleCleaner; diff --git a/PWGCF/Femto/Core/partitions.h b/PWGCF/Femto/Core/partitions.h index cb32840b0d7..68508aa4c70 100644 --- a/PWGCF/Femto/Core/partitions.h +++ b/PWGCF/Femto/Core/partitions.h @@ -163,6 +163,22 @@ (o2::aod::femtobase::stored::mass < (selection).massMax) && \ ncheckbit(o2::aod::femtokinks::mask, (selection).mask) +// partition for D0 +// sign of signedPt encodes the hypothesis: D0 (+) / D0bar (-) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define MAKE_D0_PARTITION(selection) \ + ifnode((selection).sign.node() != 0, \ + ifnode((selection).sign.node() > 0, o2::aod::femtobase::stored::signedPt > 0.f, o2::aod::femtobase::stored::signedPt < 0.f), true) && \ + (nabs(o2::aod::femtobase::stored::signedPt) > (selection).ptMin) && \ + (nabs(o2::aod::femtobase::stored::signedPt) < (selection).ptMax) && \ + (o2::aod::femtobase::stored::eta > (selection).etaMin) && \ + (o2::aod::femtobase::stored::eta < (selection).etaMax) && \ + (o2::aod::femtobase::stored::phi > (selection).phiMin) && \ + (o2::aod::femtobase::stored::phi < (selection).phiMax) && \ + (o2::aod::femtobase::stored::mass > (selection).massMin) && \ + (o2::aod::femtobase::stored::mass < (selection).massMax) && \ + ncheckbit(o2::aod::femtocharmhadrons::mask, (selection).mask) + // macros for mc collisions (mc only) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define MAKE_MC_COLLISION_FILTER(selection) \ diff --git a/PWGCF/Femto/Core/trackHistManager.h b/PWGCF/Femto/Core/trackHistManager.h index 3086a015e3c..4c2e4011ce7 100644 --- a/PWGCF/Femto/Core/trackHistManager.h +++ b/PWGCF/Femto/Core/trackHistManager.h @@ -158,6 +158,8 @@ constexpr const char PrefixV01PosDauBinning[] = "V01PosDauBinning"; constexpr const char PrefixV01NegDauBinning[] = "V01NegDauBinning"; constexpr const char PrefixV02PosDauBinning[] = "V02PosDauBinning"; constexpr const char PrefixV02NegDauBinning[] = "V02NegDauBinning"; +constexpr const char PrefixD01PosDauBinning[] = "D01PosDauBinning"; +constexpr const char PrefixD01NegDauBinning[] = "D01NegDauBinning"; constexpr const char PrefixCascadePosDauBinning[] = "CascadePosDauBinning"; constexpr const char PrefixCascadeNegDauBinning[] = "CascadeNegDauBinning"; constexpr const char PrefixCascadeBachelorBinning[] = "CascadeBachelorBinning"; @@ -176,6 +178,8 @@ using ConfV01PosDauBinning = ConfTrackBinning; using ConfV01NegDauBinning = ConfTrackBinning; using ConfV02PosDauBinning = ConfTrackBinning; using ConfV02NegDauBinning = ConfTrackBinning; +using ConfD01PosDauBinning = ConfTrackBinning; +using ConfD01NegDauBinning = ConfTrackBinning; using ConfCascadePosDauBinning = ConfTrackBinning; using ConfCascadeNegDauBinning = ConfTrackBinning; using ConfCascadeBachelorBinning = ConfTrackBinning; @@ -263,6 +267,8 @@ constexpr const char PrefixV01PosDauQaBinning[] = "V01PosDauQaBinning"; constexpr const char PrefixV01NegDauQaBinning[] = "V01NegDauQaBinning"; constexpr const char PrefixV02PosDauQaBinning[] = "V02PosDauQaBinning"; constexpr const char PrefixV02NegDauQaBinning[] = "V02NegDauQaBinning"; +constexpr const char PrefixD01PosDauQaBinning[] = "D01PosDauQaBinning"; +constexpr const char PrefixD01NegDauQaBinning[] = "D01NegDauQaBinning"; constexpr const char PrefixCascadePosDauQaBinning[] = "CascadePosDauQaBinning"; constexpr const char PrefixCascadeNegDauQaBinning[] = "CascadeNegDauQaBinning"; constexpr const char PrefixCascadeBachelorQaBinning[] = "CascadeBachelorQaBinning"; @@ -276,6 +282,8 @@ using ConfV01PosDauQaBinning = ConfTrackQaBinning; using ConfV01NegDauQaBinning = ConfTrackQaBinning; using ConfV02PosDauQaBinning = ConfTrackQaBinning; using ConfV02NegDauQaBinning = ConfTrackQaBinning; +using ConfD01PosDauQaBinning = ConfTrackQaBinning; +using ConfD01NegDauQaBinning = ConfTrackQaBinning; using ConfCascadePosDauQaBinning = ConfTrackQaBinning; using ConfCascadeNegDauQaBinning = ConfTrackQaBinning; using ConfCascadeBachelorQaBinning = ConfTrackQaBinning; @@ -517,6 +525,11 @@ constexpr char PrefixResonanceNegDaughter[] = "ResonanceNegDau/"; constexpr char PrefixResonancePosDaughterQa[] = "ResonancePosDauQa/"; constexpr char PrefixResonanceNegDaughterQa[] = "ResonanceNegDauQa/"; +constexpr char PrefixD01PosDaughter[] = "D01PosDau/"; +constexpr char PrefixD01NegDaughter[] = "D01NegDau/"; +constexpr char PrefixD01PosDaughterQa[] = "D01PosDauQa/"; +constexpr char PrefixD01NegDaughterQa[] = "D01NegDauQa/"; + constexpr char PrefixV01PosDaughter[] = "V01PosDau/"; constexpr char PrefixV01NegDaughter[] = "V01NegDau/"; constexpr char PrefixV02PosDaughter[] = "V02PosDau/"; diff --git a/PWGCF/Femto/DataModel/FemtoTables.h b/PWGCF/Femto/DataModel/FemtoTables.h index d8c30322a49..483cf8c67a9 100644 --- a/PWGCF/Femto/DataModel/FemtoTables.h +++ b/PWGCF/Femto/DataModel/FemtoTables.h @@ -1147,6 +1147,8 @@ DECLARE_SOA_TABLE(FLambdaLabels, "AOD", "FLAMBDALABEL", femtolabels::FMcParticle DECLARE_SOA_TABLE(FK0shortLabels, "AOD", "FK0SHORTLABEL", femtolabels::FMcParticleId); +DECLARE_SOA_TABLE(FD0Labels, "AOD", "FD0LABEL", femtolabels::FMcParticleId); + DECLARE_SOA_TABLE(FSigmaLabels, "AOD", "FSIGMALABEL", femtolabels::FMcParticleId); DECLARE_SOA_TABLE(FSigmaPlusLabels, "AOD", "FSIGMAPLUSLABEL", femtolabels::FMcParticleId); @@ -1160,5 +1162,76 @@ DECLARE_SOA_TABLE(FMcMotherLabels, "AOD", "FMCMOTHERLABEL", femtolabels::FMcMotherId, femtolabels::FMcPartMothId); +namespace femtocharmhadrons +{ +// bitmask column +DECLARE_SOA_COLUMN(Mask, mask, o2::analysis::femto::datatypes::CharmHadronMaskType); //! selection bitmask + +// daughter links: row indices into the femto track table +DECLARE_SOA_INDEX_COLUMN_FULL(PosDau, posDau, int32_t, FTracks, "_PosDau"); //! + prong (pion in D0) +DECLARE_SOA_INDEX_COLUMN_FULL(NegDau, negDau, int32_t, FTracks, "_NegDau"); //! - prong (kaon in D0) + +// QA/debug columns +DECLARE_SOA_COLUMN(MassD0, massD0, float); //! Kpi-hypothesis mass +DECLARE_SOA_COLUMN(MassD0bar, massD0bar, float); //! piK-hypothesis mass +DECLARE_SOA_COLUMN(Cpa, cpa, float); +DECLARE_SOA_COLUMN(CpaXY, cpaXY, float); +DECLARE_SOA_COLUMN(DecayLength, decayLength, float); +DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); +DECLARE_SOA_COLUMN(ImpactParameterProduct, impactParameterProduct, float); //! d0*d0 of the two prongs +DECLARE_SOA_COLUMN(CosThetaStar, cosThetaStar, float); +// ML BDT scores: [0] background, [1] prompt (D0 from c), [2] non-prompt (D0 from b decay) +DECLARE_SOA_COLUMN(MlProbD0Bkg, mlProbD0Bkg, float); //! D0 hypothesis: background score +DECLARE_SOA_COLUMN(MlProbD0Prompt, mlProbD0Prompt, float); //! D0 hypothesis: prompt score +DECLARE_SOA_COLUMN(MlProbD0NonPrompt, mlProbD0NonPrompt, float); //! D0 hypothesis: non-prompt score +DECLARE_SOA_COLUMN(MlProbD0barBkg, mlProbD0barBkg, float); //! D0bar hypothesis: background +DECLARE_SOA_COLUMN(MlProbD0barPrompt, mlProbD0barPrompt, float); //! D0bar hypothesis: prompt +DECLARE_SOA_COLUMN(MlProbD0barNonPrompt, mlProbD0barNonPrompt, float); //! D0bar hypothesis: non-prompt +DECLARE_SOA_COLUMN(IsSelD0, isSelD0, int8_t); //! PWGHF selection flag +DECLARE_SOA_COLUMN(IsSelD0bar, isSelD0bar, int8_t); //! PWGHF selection flag +} // namespace femtocharmhadrons + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FD0s_001, "FD0", 1, //! femto D0/D0bar (kinematics only) + o2::soa::Index<>, + femtobase::stored::FColId, + femtobase::stored::SignedPt, //! sign encodes D0(+)/D0bar(-) + femtobase::stored::Eta, + femtobase::stored::Phi, + femtobase::stored::Mass, //! mass of the accepted hypothesis + femtocharmhadrons::PosDauId, + femtocharmhadrons::NegDauId, + femtobase::dynamic::Sign, + femtobase::dynamic::Pt, + femtobase::dynamic::P, + femtobase::dynamic::Px, + femtobase::dynamic::Py, + femtobase::dynamic::Pz, + femtobase::dynamic::Theta); +using FD0s = FD0s_001; +using StoredFD0s = StoredFD0s_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FD0Masks_001, "FD0MASK", 1, //! femto D0 selection bitmask + femtocharmhadrons::Mask); +using FD0Masks = FD0Masks_001; +using StoredFD0Masks = StoredFD0Masks_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FD0Extras_001, "FD0EXTRA", 1, //! femto D0 QA / debug + femtocharmhadrons::MassD0, // both hypotheses; the main + femtocharmhadrons::MassD0bar, // table only stores the accepted one + femtocharmhadrons::Cpa, + femtocharmhadrons::CpaXY, + femtocharmhadrons::DecayLength, + femtocharmhadrons::DecayLengthXY, + femtocharmhadrons::ImpactParameterProduct, + femtocharmhadrons::CosThetaStar, + femtocharmhadrons::MlProbD0Bkg, + femtocharmhadrons::MlProbD0Prompt, + femtocharmhadrons::MlProbD0NonPrompt, + femtocharmhadrons::MlProbD0barBkg, + femtocharmhadrons::MlProbD0barPrompt, + femtocharmhadrons::MlProbD0barNonPrompt, + femtocharmhadrons::IsSelD0, // raw PWGHF selection flags + femtocharmhadrons::IsSelD0bar); +using FD0Extras = FD0Extras_001; } // namespace o2::aod #endif // PWGCF_FEMTO_DATAMODEL_FEMTOTABLES_H_ diff --git a/PWGCF/Femto/TableProducer/femtoProducer.cxx b/PWGCF/Femto/TableProducer/femtoProducer.cxx index 359f6175abc..7a502163a49 100644 --- a/PWGCF/Femto/TableProducer/femtoProducer.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducer.cxx @@ -14,12 +14,15 @@ /// \author Anton Riedel, TU München, anton.riedel@tum.de #include "PWGCF/Femto/Core/cascadeBuilder.h" +#include "PWGCF/Femto/Core/charmHadronBuilder.h" #include "PWGCF/Femto/Core/collisionBuilder.h" #include "PWGCF/Femto/Core/kinkBuilder.h" #include "PWGCF/Femto/Core/mcBuilder.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/trackBuilder.h" #include "PWGCF/Femto/Core/v0Builder.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGLF/DataModel/LFKinkDecayTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/mcCentrality.h" @@ -69,6 +72,9 @@ using Run3McRecoTracks = soa::Join; using Run3Vzeros = o2::aod::V0Datas; using Run3RecoVzeros = o2::soa::Join; +using Run3D0Candidates = soa::Join; +using Run3McD0Candidates = soa::Join; + using Run3Cascades = o2::aod::CascDatas; using Run3RecoCascades = o2::soa::Join; @@ -110,6 +116,14 @@ struct FemtoProducer { v0builder::V0Builder lambdaBuilder; v0builder::V0Builder antilambdaBuilder; + // charm hadron builder + charmhadronbuilder::CharmHadronBuilderProducts charmHadronBuilderProducts; + charmhadronbuilder::ConfD0Filters confD0Filters; + charmhadronbuilder::ConfD0Bits confD0Bits; + charmhadronbuilder::ConfD0Tables confD0Tables; + charmhadronbuilder::CharmHadronBuilder d0Builder; + charmhadronbuilder::CharmHadronBuilder d0barBuilder; + // cascade builder cascadebuilder::CascadeBuilderProducts cascadeBuilderProducts; cascadebuilder::ConfCascadeTables confCascadeTables; @@ -192,6 +206,10 @@ struct FemtoProducer { lambdaBuilder.init(&hRegistry, confLambdaBits, confV0Filters, confV0Tables, context, trackBuilder); antilambdaBuilder.init(&hRegistry, confLambdaBits, confV0Filters, confV0Tables, context, trackBuilder); + // configure d0 builder + d0Builder.init(&hRegistry, confD0Bits, confD0Filters, confD0Tables, context); + d0barBuilder.init(&hRegistry, confD0Bits, confD0Filters, confD0Tables, context); + // configure kink builder sigmaBuilder.init(&hRegistry, confSigmaBits, confKinkFilters, confKinkTables, context, trackBuilder); sigmaPlusBuilder.init(&hRegistry, confSigmaPlusBits, confKinkFilters, confKinkTables, context, trackBuilder); @@ -260,6 +278,20 @@ struct FemtoProducer { k0shortBuilder.fillMcV0s(col, collisionBuilder, collisionBuilderProducts, mcCols, trackBuilderProducts, v0builderProducts, v0s, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts); } + // processing D0s + template + void processD0s(T1 const& col, T2 const& tracks, T3 const& candidates) + { + d0Builder.fillD0s(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder); + d0barBuilder.fillD0s(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder); + } + template + void processMcD0s(T1 const& col, T2 const& mcCols, T3 const& tracks, T4 const& candidates, T5 const& mcParticles) + { + d0Builder.fillMcD0s(col, collisionBuilder, collisionBuilderProducts, mcCols, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts); + d0barBuilder.fillMcD0s(col, collisionBuilder, collisionBuilderProducts, mcCols, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts); + } + // processing kinks template void processKinks(T1 const& col, T2 const& tracks, T3 const& kinks) @@ -348,6 +380,72 @@ struct FemtoProducer { }; PROCESS_SWITCH(FemtoProducer, processTracksV0sRun3PbPb, "Process tracks and v0s in PbPB collisions", false); + // process tracks and D0s + void processTracksD0sRun3pp(rawinputs::Run3PpCollisions::iterator const& col, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3FullPidTracks const& tracks, + rawinputs::Run3D0Candidates const& candidates) + { + if (!processCollisions(col, bcs, tracks)) { + return; + } + auto tracksWithItsPid = o2::soa::Attach(tracks); + processTracks(col, tracksWithItsPid); + processD0s(col, tracks, candidates); + } + PROCESS_SWITCH(FemtoProducer, processTracksD0sRun3pp, "Process tracks and D0s", false); + + void processTracksD0sRun3PbPb(rawinputs::Run3PbPbCollisions::iterator const& col, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3FullPidTracks const& tracks, + rawinputs::Run3D0Candidates const& candidates) + { + if (!processCollisions(col, bcs, tracks)) { + return; + } + auto tracksWithItsPid = o2::soa::Attach(tracks); + processTracks(col, tracksWithItsPid); + processD0s(col, tracks, candidates); + } + PROCESS_SWITCH(FemtoProducer, processTracksD0sRun3PbPb, "Process tracks and D0s", false); + + // process monte carlo tracks and D0s + void processTracksD0sRun3ppMc(rawinputs::Run3PpMcRecoCollisions::iterator const& col, + rawinputs::Run3PpMcGenCollisions const& mcCols, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3McRecoTracks const& tracks, + rawinputs::Run3McD0Candidates const& candidates, + rawinputs::Run3McGenParticles const& mcParticles) + { + if (!processMcCollisions(col, mcCols, bcs, tracks, mcParticles)) { + return; + } + auto tracksWithItsPid = o2::soa::Attach(tracks); + processMcTracks(col, mcCols, tracks, tracksWithItsPid, mcParticles); + processMcD0s(col, mcCols, tracks, candidates, mcParticles); + } + PROCESS_SWITCH(FemtoProducer, processTracksD0sRun3ppMc, "Provide reconstructed and generated tracks and D0s", false); + + void processTracksD0sRun3PbPbMc(rawinputs::Run3PbPbMcRecoCollisions::iterator const& col, + rawinputs::Run3PbPbMcGenCollisions const& mcCols, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3McRecoTracks const& tracks, + rawinputs::Run3McD0Candidates const& candidates, + rawinputs::Run3McGenParticles const& mcParticles) + { + if (!processMcCollisions(col, mcCols, bcs, tracks, mcParticles)) { + return; + } + auto tracksWithItsPid = o2::soa::Attach(tracks); + processMcTracks(col, mcCols, tracks, tracksWithItsPid, mcParticles); + processMcD0s(col, mcCols, tracks, candidates, mcParticles); + } + PROCESS_SWITCH(FemtoProducer, processTracksD0sRun3PbPbMc, "Provide reconstructed and generated tracks and D0s in PbPb collisions", false); + // process tracks and kinks void processTracksKinksRun3pp(rawinputs::Run3PpCollisions::iterator const& col, o2::aod::BCsWithTimestamps const& bcs, diff --git a/PWGCF/Femto/Tasks/CMakeLists.txt b/PWGCF/Femto/Tasks/CMakeLists.txt index 9e612ee28a4..6ca8f2cd90a 100644 --- a/PWGCF/Femto/Tasks/CMakeLists.txt +++ b/PWGCF/Femto/Tasks/CMakeLists.txt @@ -49,6 +49,16 @@ o2physics_add_dpl_workflow(femto-pair-track-v0 PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(femto-pair-track-d0 + SOURCES femtoPairTrackD0.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(femto-d0-qa + SOURCES femtoD0Qa.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(femto-pair-track-two-track-resonance SOURCES femtoPairTrackTwoTrackResonance.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore diff --git a/PWGCF/Femto/Tasks/femtoD0Qa.cxx b/PWGCF/Femto/Tasks/femtoD0Qa.cxx new file mode 100644 index 00000000000..fdc9ecc6873 --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoD0Qa.cxx @@ -0,0 +1,161 @@ +// Copyright 2019-2026 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 femtoD0Qa.cxx +/// \brief QA task for D0 mesons +/// \author Igor Ptak, WUT, igor.tomasz.ptak@cern.ch + +#include "PWGCF/Femto/Core/charmHadronBuilder.h" +#include "PWGCF/Femto/Core/charmHadronHistManager.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace o2::analysis::femto; + +struct FemtoD0Qa { + + // setup collisions + using FemtoCollisions = o2::soa::Join; + using FilteredFemtoCollisions = o2::soa::Filtered; + using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; + + // setup D0s, joined with the mask for the partition and the QA columns + using FemtoD0s = o2::soa::Join; + // setup tracks with full pid information for the daughter QA + using FemtoTracks = o2::soa::Join; + + // setup monte carlo, joining the labels that link reco to generated particles + using FemtoCollisionsWithLabel = o2::soa::Join; + using FilteredFemtoCollisionsWithLabel = o2::soa::Filtered; + using FilteredFemtoCollisionWithLabel = FilteredFemtoCollisionsWithLabel::iterator; + + using FemtoD0sWithLabel = o2::soa::Join; + using FemtoTracksWithLabel = o2::soa::Join; + using FemtoMcParticlesWithLabel = o2::soa::Join; + + o2::framework::SliceCache cache; + + // setup for collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + o2::framework::expressions::Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::CollisionHistManager colHistManager; + colhistmanager::ConfCollisionBinning confCollisionBinning; + colhistmanager::ConfCollisionQaBinning confCollisionQaBinning; + + // setup for D0s + charmhadronbuilder::ConfD0Selection confD0Selection; + + o2::framework::Partition d0Partition = MAKE_D0_PARTITION(confD0Selection); + o2::framework::Preslice perColD0s = o2::aod::femtobase::stored::fColId; + o2::framework::Partition d0WithLabelPartition = MAKE_D0_PARTITION(confD0Selection); + o2::framework::Preslice perColD0sWithLabel = o2::aod::femtobase::stored::fColId; + + charmhadronhistmanager::ConfD0Binning1 confD0Binning; + charmhadronhistmanager::ConfD0QaBinning1 confD0QaBinning; + charmhadronhistmanager::CharmHadronHistManager< + charmhadronhistmanager::PrefixD0Qa, + trackhistmanager::PrefixD01PosDaughterQa, + trackhistmanager::PrefixD01NegDaughterQa, + modes::CharmHadron::kD0> + d0HistManager; + + // setup for daughters + trackhistmanager::ConfD01PosDauBinning confD01PosDaughterBinning; + trackhistmanager::ConfD01PosDauQaBinning confD01PosDaughterQaBinning; + + trackhistmanager::ConfD01NegDauBinning confD01NegDaughterBinning; + trackhistmanager::ConfD01NegDauQaBinning confD01NegDaughterQaBinning; + + o2::framework::HistogramRegistry hRegistry{"FemtoD0Qa", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + bool processData = doprocessD0; + + std::map> colHistSpec; + std::map> posDaughterHistSpec; + std::map> negDaughterHistSpec; + std::map> d0HistSpec; + std::map> d0QaHistSpec; + + if (processData) { + colHistSpec = colhistmanager::makeColQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); + colHistManager.init(&hRegistry, colHistSpec, confCollisionBinning, confCollisionQaBinning); + posDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confD01PosDaughterBinning, confD01PosDaughterQaBinning); + negDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confD01NegDaughterBinning, confD01NegDaughterQaBinning); + d0HistSpec = charmhadronhistmanager::makeD0HistSpecMap(confD0Binning); + d0QaHistSpec = charmhadronhistmanager::makeD0QaHistSpecMap(confD0QaBinning); + d0HistManager.init(&hRegistry, d0HistSpec, d0QaHistSpec, confD0Selection, confD0QaBinning, posDaughterHistSpec, confD01PosDaughterQaBinning, negDaughterHistSpec, confD01NegDaughterQaBinning); + } else { + colHistSpec = colhistmanager::makeColMcQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); + colHistManager.init(&hRegistry, colHistSpec, confCollisionBinning, confCollisionQaBinning); + posDaughterHistSpec = trackhistmanager::makeTrackMcQaHistSpecMap(confD01PosDaughterBinning, confD01PosDaughterQaBinning); + negDaughterHistSpec = trackhistmanager::makeTrackMcQaHistSpecMap(confD01NegDaughterBinning, confD01NegDaughterQaBinning); + d0HistSpec = charmhadronhistmanager::makeD0McQaHistSpecMap(confD0Binning, confD0QaBinning); + d0QaHistSpec = charmhadronhistmanager::makeD0QaHistSpecMap(confD0QaBinning); + d0HistManager.init(&hRegistry, d0HistSpec, d0QaHistSpec, confD0Selection, confD0QaBinning, posDaughterHistSpec, confD01PosDaughterQaBinning, negDaughterHistSpec, confD01NegDaughterQaBinning); + } + + hRegistry.print(); + }; + + void processD0(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoD0s const& /*d0s*/) + { + auto d0Slice = d0Partition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (d0Slice.size() == 0) { + return; + } + colHistManager.fill(col); + for (auto const& d0 : d0Slice) { + d0HistManager.fill(d0, tracks); + } + } + PROCESS_SWITCH(FemtoD0Qa, processD0, "Process D0s", true); + + void processD0Mc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoD0sWithLabel const& /*d0s*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + auto d0Slice = d0WithLabelPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (d0Slice.size() == 0) { + return; + } + colHistManager.fill(col, mcCols); + for (auto const& d0 : d0Slice) { + d0HistManager.fill(d0, tracks, mcParticles, mcMothers, mcPartonicMothers); + } + } + PROCESS_SWITCH(FemtoD0Qa, processD0Mc, "Process D0s with MC information", false); +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) +{ + o2::framework::WorkflowSpec workflow{ + adaptAnalysisTask(context), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoPairTrackD0.cxx b/PWGCF/Femto/Tasks/femtoPairTrackD0.cxx new file mode 100644 index 00000000000..24f056a9659 --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoPairTrackD0.cxx @@ -0,0 +1,203 @@ +// Copyright 2019-2026 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 femtoPairTrackD0.cxx +/// \brief Tasks that computes correlation between tracks and D0 mesons +/// \author Igor Ptak, WUT, igor.tomasz.ptak@cern.ch + +#include "PWGCF/Femto/Core/charmHadronBuilder.h" +#include "PWGCF/Femto/Core/charmHadronHistManager.h" +#include "PWGCF/Femto/Core/closePairRejection.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairHistManager.h" +#include "PWGCF/Femto/Core/particleCleaner.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackBuilder.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace o2::analysis::femto; + +struct FemtoPairTrackD0 { + + // setup tables + using FemtoCollisions = o2::soa::Join; + using FilteredFemtoCollisions = o2::soa::Filtered; + using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; + + using FemtoTracks = o2::soa::Join; + using FemtoD0s = o2::soa::Join; + + using FemtoCollisionsWithLabel = o2::soa::Join; + using FilteredFemtoCollisionsWithLabel = o2::soa::Filtered; + using FilteredFemtoCollisionWithLabel = FilteredFemtoCollisionsWithLabel::iterator; + + using FemtoTracksWithLabel = o2::soa::Join; + using FemtoD0sWithLabel = o2::soa::Join; + using FemtoMcParticlesWithLabel = o2::soa::Join; + + o2::framework::SliceCache cache; + + // setup collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + o2::framework::expressions::Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::ConfCollisionBinning confCollisionBinning; + + // setup tracks + trackbuilder::ConfTrackSelection1 confTrackSelection; + trackhistmanager::ConfTrackBinning1 confTrackBinning; + particlecleaner::ConfTrackCleaner1 confTrackCleaner; + + o2::framework::Partition trackPartition = MAKE_TRACK_PARTITION(confTrackSelection); + o2::framework::Preslice perColTracks = o2::aod::femtobase::stored::fColId; + + o2::framework::Partition trackWithLabelPartition = MAKE_TRACK_PARTITION(confTrackSelection); + o2::framework::Preslice perColTracksWithLabel = o2::aod::femtobase::stored::fColId; + + // setup for D0 daughters + trackhistmanager::ConfD01PosDauBinning confPosDauBinning; + trackhistmanager::ConfD01NegDauBinning confNegDauBinning; + + // setup D0s + charmhadronbuilder::ConfD0Selection d0Selection; + charmhadronhistmanager::ConfD0Binning1 confD0Binning; + particlecleaner::ConfD0Cleaner1 confD0Cleaner; + + o2::framework::Partition d0Partition = MAKE_D0_PARTITION(d0Selection); + o2::framework::Preslice perColD0s = o2::aod::femtobase::stored::fColId; + + o2::framework::Partition d0WithLabelPartition = MAKE_D0_PARTITION(d0Selection); + o2::framework::Preslice perColD0sWithLabel = o2::aod::femtobase::stored::fColId; + + // setup pairs + pairhistmanager::ConfPairBinning confPairBinning; + pairhistmanager::ConfPairCuts confPairCuts; + + pairbuilder::PairTrackD0Builder< + trackhistmanager::PrefixTrack1, + charmhadronhistmanager::PrefixD01, + trackhistmanager::PrefixD01PosDaughter, + trackhistmanager::PrefixD01NegDaughter, + pairhistmanager::PrefixTrackD0Se, + pairhistmanager::PrefixTrackD0Me, + closepairrejection::PrefixTrackD0DaughterSe, + closepairrejection::PrefixTrackD0DaughterMe, + modes::CharmHadron::kD0> + pairTrackD0Builder; + + // setup mixing + std::vector defaultVtxBins{10, -10, 10}; + std::vector defaultMultBins{50, 0, 200}; + std::vector defaultCentBins{10, 0, 100}; + o2::framework::ColumnBinningPolicy mixBinsVtxMult{{defaultVtxBins, defaultMultBins}, true}; + o2::framework::ColumnBinningPolicy mixBinsVtxCent{{defaultVtxBins, defaultCentBins}, true}; + o2::framework::ColumnBinningPolicy mixBinsVtxMultCent{{defaultVtxBins, defaultMultBins, defaultCentBins}, true}; + pairhistmanager::ConfMixing confMixing; + + o2::framework::HistogramRegistry hRegistry{"FemtoTrackD0", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; + + // setup cpr + closepairrejection::ConfCprTrackD0Daughter confCpr; + + void init(o2::framework::InitContext&) + { + bool processData = doprocessSameEvent || doprocessMixedEvent; + bool processMc = doprocessSameEventMc || doprocessMixedEventMc; + + if (processData && processMc) { + LOG(fatal) << "Both data and mc processing is enabled. Breaking..."; + } + + // setup columnpolicy for binning + // default values are used during instantiation, so we need to explicity update them here + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; + mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; + mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; + + std::map> colHistSpec; + std::map> trackHistSpec; + std::map> posDauSpec; + std::map> negDauSpec; + std::map> d0HistSpec; + std::map> pairTrackD0HistSpec; + std::map> cprHistSpec = closepairrejection::makeCprHistSpecMap(confCpr); + + if (processData) { + colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); + trackHistSpec = trackhistmanager::makeTrackHistSpecMap(confTrackBinning); + posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); + negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); + d0HistSpec = charmhadronhistmanager::makeD0HistSpecMap(confD0Binning); + pairTrackD0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); + pairTrackD0Builder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, d0Selection, confD0Cleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, d0HistSpec, posDauSpec, negDauSpec, pairTrackD0HistSpec, cprHistSpec); + } else { + colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); + trackHistSpec = trackhistmanager::makeTrackMcHistSpecMap(confTrackBinning); + posDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confPosDauBinning); + negDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confNegDauBinning); + d0HistSpec = charmhadronhistmanager::makeD0McHistSpecMap(confD0Binning); + pairTrackD0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); + pairTrackD0Builder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, d0Selection, confD0Cleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, d0HistSpec, posDauSpec, negDauSpec, pairTrackD0HistSpec, cprHistSpec); + } + + hRegistry.print(); + }; + + void processSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoD0s const& d0s) + { + pairTrackD0Builder.processSameEvent(col, tracks, trackPartition, d0s, d0Partition, cache); + } + PROCESS_SWITCH(FemtoPairTrackD0, processSameEvent, "Enable processing same event processing for tracks and D0s", true); + + void processMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoD0s const& /*d0s*/) + { + pairTrackD0Builder.processMixedEvent(cols, tracks, trackPartition, d0Partition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackD0, processMixedEvent, "Enable processing mixed event processing for tracks and D0s", true); + + void processSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoD0sWithLabel const& d0s, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + pairTrackD0Builder.processSameEvent(col, mcCols, tracks, trackWithLabelPartition, d0s, d0WithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache); + } + PROCESS_SWITCH(FemtoPairTrackD0, processSameEventMc, "Enable processing same event processing for tracks and D0s with MC information", false); + + void processMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoD0sWithLabel const& /*d0s*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + pairTrackD0Builder.processMixedEvent(cols, mcCols, tracks, trackWithLabelPartition, d0WithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackD0, processMixedEventMc, "Enable processing mixed event processing for tracks and D0s with MC information", false); +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) +{ + o2::framework::WorkflowSpec workflow{ + adaptAnalysisTask(context), + }; + return workflow; +} From 9c840392c5e2e7e29364dc88f3e969cee4d0e8c2 Mon Sep 17 00:00:00 2001 From: Zuzanna Chochulska <87480906+zchochul@users.noreply.github.com> Date: Fri, 31 Jul 2026 12:19:04 +0200 Subject: [PATCH 58/71] [PWGCF] FemtoUniverse - Track-Phi - new PID for Phi (#17265) Co-authored-by: Zuzanna Chochulska <01150674@pw.edu.pl> --- .../Tasks/femtoUniversePairTaskTrackPhi.cxx | 393 ++++++++---------- 1 file changed, 174 insertions(+), 219 deletions(-) diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackPhi.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackPhi.cxx index 5fc9dd9c59a..3cd734acc13 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackPhi.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackPhi.cxx @@ -26,6 +26,7 @@ #include "PWGCF/FemtoUniverse/DataModel/FemtoDerived.h" #include +#include #include #include #include @@ -43,6 +44,8 @@ #include #include +#include + #include #include #include @@ -59,18 +62,30 @@ using namespace o2::soa; namespace { -// static constexpr int NPart = 2; -// static constexpr int NCuts = 5; -static const std::vector partNames{"PhiCandidate", "Track"}; -static const std::vector cutNames{"MaxPt", "PIDthr", "nSigmaTPC", "nSigmaTPCTOF", "MaxP"}; -// static const float cutsTable[NPart][NCuts]{ //unused variable -// {4.05f, 1.f, 3.f, 3.f, 100.f}, -// {4.05f, 1.f, 3.f, 3.f, 100.f}}; +const std::vector partNames{"PhiCandidate", "Track"}; +const std::vector cutNames{"MaxPt", "PIDthr", "nSigmaTPC", "nSigmaTPCTOF", "MaxP"}; + +// Constants for pT / momentum +constexpr float kMomCutLow = 0.5f; +constexpr float kMomCutKaonLow = 0.3f; +constexpr float kMomCutKaonMid = 0.45f; +constexpr float kMomCutKaonHigh = 0.55f; +constexpr float kMomCutKaonMax = 1.5f; + +// Constants for nSigma cuts +constexpr float kNSigmaStrict = 1.0f; +constexpr float kNSigmaMedium = 2.0f; +constexpr float kNSigmaStandard = 3.0f; + +// Helper constants and indices +constexpr int kInvalidMCPartId = -1; +constexpr int kPhiDaughterOffsetPos = 2; +constexpr int kPhiDaughterOffsetNeg = 1; } // namespace struct FemtoUniversePairTaskTrackPhi { - Service pdgMC; + Service pdgMC = {}; using FilteredFemtoFullParticles = soa::Join; @@ -80,73 +95,74 @@ struct FemtoUniversePairTaskTrackPhi { using FemtoRecoParticles = soa::Join; Preslice perColMC = aod::femtouniverseparticle::fdCollisionId; - Configurable ConfZVertexCut{"ConfZVertexCut", 10.f, "Event sel: Maximum z-Vertex (cm)"}; - Configurable ConfNEventsMix{"ConfNEventsMix", 5, "Number of events for mixing"}; - Filter collisionFilter = (nabs(aod::collision::posZ) < ConfZVertexCut); + Configurable confZVertexCut{"confZVertexCut", 10.f, "Event sel: Maximum z-Vertex (cm)"}; + // Configurable confNEventsMix{"confNEventsMix", 5, "Number of events for mixing"}; + Filter collisionFilter = (nabs(aod::collision::posZ) < confZVertexCut); using FilteredFDCollisions = soa::Filtered; using FilteredFDCollision = FilteredFDCollisions::iterator; - Configurable ConfCPRIsEnabled{"ConfCPRIsEnabled", false, "Close Pair Rejection"}; - Configurable ConfCPRPlotPerRadii{"ConfCPRPlotPerRadii", false, "Plot CPR per radii"}; - Configurable ConfCPRdeltaPhiCutMax{"ConfCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaPhiCutMin{"ConfCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaEtaCutMax{"ConfCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; - Configurable ConfCPRdeltaEtaCutMin{"ConfCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; - Configurable ConfCPRInvMassCutMin{"ConfCPRInvMassCutMin", 1.014, "Invariant mass (low) cut for Close Pair Rejection"}; - Configurable ConfCPRInvMassCutMax{"ConfCPRInvMassCutMax", 1.026, "Invariant mass (high) cut for Close Pair Rejection"}; - Configurable ConfCPRChosenRadii{"ConfCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; + Configurable confCPRIsEnabled{"confCPRIsEnabled", false, "Close Pair Rejection"}; + Configurable confCPRPlotPerRadii{"confCPRPlotPerRadii", false, "Plot CPR per radii"}; + Configurable confCPRdeltaPhiCutMax{"confCPRdeltaPhiCutMax", 0.0, "Delta Phi max cut for Close Pair Rejection"}; + Configurable confCPRdeltaPhiCutMin{"confCPRdeltaPhiCutMin", 0.0, "Delta Phi min cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMax{"confCPRdeltaEtaCutMax", 0.0, "Delta Eta max cut for Close Pair Rejection"}; + Configurable confCPRdeltaEtaCutMin{"confCPRdeltaEtaCutMin", 0.0, "Delta Eta min cut for Close Pair Rejection"}; + Configurable confCPRInvMassCutMin{"confCPRInvMassCutMin", 1.014, "Invariant mass (low) cut for Close Pair Rejection"}; + Configurable confCPRInvMassCutMax{"confCPRInvMassCutMax", 1.026, "Invariant mass (high) cut for Close Pair Rejection"}; + Configurable confCPRChosenRadii{"confCPRChosenRadii", 0.80, "Delta Eta cut for Close Pair Rejection"}; ConfigurableAxis confDeltaEtaAxis{"confDeltaEtaAxis", {100, -0.15, 0.15}, "DeltaEta"}; ConfigurableAxis confDeltaPhiStarAxis{"confDeltaPhiStarAxis", {100, -0.15, 0.15}, "DeltaPhiStar"}; /// Table for both particles - Configurable ConfPIDProtonNsigmaCombined{"ConfPIDProtonNsigmaCombined", 3.0, "TPC and TOF Proton Sigma (combined) for momentum > 0.5"}; - Configurable ConfPIDProtonNsigmaTPC{"ConfPIDProtonNsigmaTPC", 3.0, "TPC Proton Sigma for momentum < 0.5"}; - Configurable ConfPIDKaonNsigmaReject{"ConfPIDKaonNsigmaReject", 3.0, "Reject if particle could be a Kaon combined nsigma value."}; - Configurable ConfPIDPionNsigmaReject{"ConfPIDPionNsigmaReject", 3.0, "Reject if particle could be a Pion combined nsigma value."}; - Configurable ConfPIDProtonNsigmaReject{"ConfPIDProtonNsigmaReject", 3.0, "Reject if particle could be a Proton combined nsigma value."}; - Configurable ConfPIDPionNsigmaCombined{"ConfPIDPionNsigmaCombined", 3.0, "TPC and TOF Pion Sigma (combined) for momentum > 0.5"}; - Configurable ConfPIDPionNsigmaTPC{"ConfPIDPionNsigmaTPC", 3.0, "TPC Pion Sigma for momentum < 0.5"}; - Configurable ConfIsMC{"ConfIsMC", false, "Enable additional Histograms in the case of a MonteCarlo Run"}; - Configurable ConfUse3D{"ConfUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; - Configurable ConfBinsPhi{"ConfBinsPhi", 29, "Number of phi bins in deta dphi"}; - Configurable ConfBinsEta{"ConfBinsEta", 29, "Number of eta bins in deta dphi"}; + Configurable confPIDProtonNsigmaCombined{"confPIDProtonNsigmaCombined", 3.0, "TPC and TOF Proton Sigma (combined) for momentum > 0.5"}; + Configurable confPIDProtonNsigmaTPC{"confPIDProtonNsigmaTPC", 3.0, "TPC Proton Sigma for momentum < 0.5"}; + Configurable confPIDKaonNsigmaReject{"confPIDKaonNsigmaReject", 3.0, "Reject if particle could be a Kaon combined nsigma value."}; + Configurable confPIDPionNsigmaReject{"confPIDPionNsigmaReject", 3.0, "Reject if particle could be a Pion combined nsigma value."}; + Configurable confPIDProtonNsigmaReject{"confPIDProtonNsigmaReject", 3.0, "Reject if particle could be a Proton combined nsigma value."}; + Configurable confPIDPionNsigmaCombined{"confPIDPionNsigmaCombined", 3.0, "TPC and TOF Pion Sigma (combined) for momentum > 0.5"}; + Configurable confPIDPionNsigmaTPC{"confPIDPionNsigmaTPC", 3.0, "TPC Pion Sigma for momentum < 0.5"}; + Configurable confIsMC{"confIsMC", false, "Enable additional Histograms in the case of a MonteCarlo Run"}; + Configurable confUse3D{"confUse3D", false, "Enable three dimensional histogramms (to be used only for analysis with high statistics): k* vs mT vs multiplicity"}; + Configurable confBinsPhi{"confBinsPhi", 29, "Number of phi bins in deta dphi"}; + Configurable confBinsEta{"confBinsEta", 29, "Number of eta bins in deta dphi"}; /// Particle 1 --- IDENTIFIED TRACK - Configurable ConfTrackPDGCode{"ConfTrackPDGCode", 2212, "Particle 2 - PDG code"}; - Configurable ConfTrackSign{"ConfTrackSign", 1, "Track sign"}; - Configurable ConfTrackIsIdentified{"ConfTrackIsIdentified", true, "Enable PID for the track"}; - Configurable ConfTrackIsRejected{"ConfTrackIsRejected", true, "Enable PID rejection for the track other species than the identified one."}; - Configurable ConfTrackPtPIDLimit{"ConfTrackPtPIDLimit", 0.5, "Momentum threshold for change of the PID method (from using TPC to TPC and TOF)."}; - Configurable ConfTrackPtLow{"ConfTrackPtLow", 0.5, "Lower limit of the hadron pT."}; - Configurable ConfTrackPtHigh{"ConfTrackPtHigh", 2.5, "Higher limit of the hadron pT."}; + Configurable confTrackPDGCode{"confTrackPDGCode", 2212, "Particle 2 - PDG code"}; + Configurable confTrackSign{"confTrackSign", 1, "Track sign"}; + Configurable confTrackIsIdentified{"confTrackIsIdentified", true, "Enable PID for the track"}; + Configurable confTrackIsRejected{"confTrackIsRejected", true, "Enable PID rejection for the track other species than the identified one."}; + Configurable confTrackPtPIDLimit{"confTrackPtPIDLimit", 0.5, "Momentum threshold for change of the PID method (from using TPC to TPC and TOF)."}; + Configurable confTrackPtLow{"confTrackPtLow", 0.5, "Lower limit of the hadron pT."}; + Configurable confTrackPtHigh{"confTrackPtHigh", 2.5, "Higher limit of the hadron pT."}; + Configurable confTrackUseRun3PIDforKaons{"confTrackUseRun3PIDforKaons", true, "Use Run3 PID for kaons from Veronika Barbasova's AN (https://alice-notes.web.cern.ch/node/1758). If this is on the other PID methods are ignored for kaons."}; /// Partitions for the track (particle 1) Partition partsTrack = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && - (aod::femtouniverseparticle::sign == ConfTrackSign) && - (aod::femtouniverseparticle::pt > ConfTrackPtLow) && - (aod::femtouniverseparticle::pt < ConfTrackPtHigh); + (aod::femtouniverseparticle::sign == confTrackSign) && + (aod::femtouniverseparticle::pt > confTrackPtLow) && + (aod::femtouniverseparticle::pt < confTrackPtHigh); Partition partsTrackMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kTrack)) && - (aod::femtouniverseparticle::sign == ConfTrackSign) && - (aod::femtouniverseparticle::pt > ConfTrackPtLow) && - (aod::femtouniverseparticle::pt < ConfTrackPtHigh); + (aod::femtouniverseparticle::sign == confTrackSign) && + (aod::femtouniverseparticle::pt > confTrackPtLow) && + (aod::femtouniverseparticle::pt < confTrackPtHigh); /// Particle 2 --- PHI MESON - Configurable ConfPhiPtLow{"ConfPhiPtLow", 0.8, "Lower limit of the Phi pT."}; - Configurable ConfPhiPtHigh{"ConfPhiPtHigh", 4.0, "Higher limit of the Phi pT."}; + Configurable confPhiPtLow{"confPhiPtLow", 0.8, "Lower limit of the Phi pT."}; + Configurable confPhiPtHigh{"confPhiPtHigh", 4.0, "Higher limit of the Phi pT."}; Configurable confInvMassLowLimitPhi{"confInvMassLowLimitPhi", 1.011, "Lower limit of the Phi invariant mass"}; // change that to do invariant mass cut Configurable confInvMassUpLimitPhi{"confInvMassUpLimitPhi", 1.027, "Upper limit of the Phi invariant mass"}; /// Partitions for the Phi meson (particle 2) Partition partsPhi = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kPhi)) && - (aod::femtouniverseparticle::pt > ConfPhiPtLow) && - (aod::femtouniverseparticle::pt < ConfPhiPtHigh) && + (aod::femtouniverseparticle::pt > confPhiPtLow) && + (aod::femtouniverseparticle::pt < confPhiPtHigh) && (aod::femtouniverseparticle::tempFitVar > confInvMassLowLimitPhi) && (aod::femtouniverseparticle::tempFitVar < confInvMassUpLimitPhi); Partition partsPhiMCReco = (aod::femtouniverseparticle::partType == uint8_t(aod::femtouniverseparticle::ParticleType::kPhi)) && - (aod::femtouniverseparticle::pt > ConfPhiPtLow) && - (aod::femtouniverseparticle::pt < ConfPhiPtHigh) && + (aod::femtouniverseparticle::pt > confPhiPtLow) && + (aod::femtouniverseparticle::pt < confPhiPtHigh) && (aod::femtouniverseparticle::tempFitVar > confInvMassLowLimitPhi) && (aod::femtouniverseparticle::tempFitVar < confInvMassUpLimitPhi); @@ -169,21 +185,21 @@ struct FemtoUniversePairTaskTrackPhi { FemtoUniverseEventHisto eventHisto; /// particle part - ConfigurableAxis ConfBinsTempFitVar{"ConfBinsTempFitVar", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfBinsTempFitVarInvMass{"ConfBinsTempFitVarInvMass", {6000, 0.9, 4.0}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfBinsTempFitVarpT{"ConfBinsTempFitVarpT", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfBinsTempFitVarPDG{"ConfBinsTempFitVarPDG", {6000, -2300, 2300}, "Binning of the PDG code in the pT vs. TempFitVar plot"}; - ConfigurableAxis ConfBinsTempFitVarDCA{"ConfBinsTempFitVarDCA", {300, -3.0, 3.0}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confBinsTempFitVar{"confBinsTempFitVar", {300, -0.15, 0.15}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confBinsTempFitVarInvMass{"confBinsTempFitVarInvMass", {6000, 0.9, 4.0}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; + ConfigurableAxis confBinsTempFitVarpT{"confBinsTempFitVarpT", {20, 0.5, 4.05}, "pT binning of the pT vs. TempFitVar plot"}; + ConfigurableAxis confBinsTempFitVarPDG{"confBinsTempFitVarPDG", {6000, -2300, 2300}, "Binning of the PDG code in the pT vs. TempFitVar plot"}; + ConfigurableAxis confBinsTempFitVarDCA{"confBinsTempFitVarDCA", {300, -3.0, 3.0}, "binning of the TempFitVar in the pT vs. TempFitVar plot"}; /// Correlation part - ConfigurableAxis ConfBinsMult{"ConfBinsMult", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; // \todo to be obtained from the hash task - ConfigurableAxis ConfBinsVtx{"ConfBinsVtx", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; - ConfigurableAxis ConfBins3DmT{"ConfBins3DmT", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - ConfigurableAxis ConfBins3Dmult{"ConfBins3Dmult", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + ConfigurableAxis confBinsMult{"confBinsMult", {VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f, 99999.f}, "Mixing bins - multiplicity"}; // \todo to be obtained from the hash task + ConfigurableAxis confBinsVtx{"confBinsVtx", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + ConfigurableAxis confBins3DmT{"confBins3DmT", {VARIABLE_WIDTH, 1.02f, 1.14f, 1.20f, 1.26f, 1.38f, 1.56f, 1.86f, 4.50f}, "mT Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; + ConfigurableAxis confBins3Dmult{"confBins3Dmult", {VARIABLE_WIDTH, 0.0f, 20.0f, 30.0f, 40.0f, 99999.0f}, "multiplicity Binning for the 3Dimensional plot: k* vs multiplicity vs mT (set <> to true in order to use)"}; - ConfigurableAxis ConfBinskstar{"ConfBinskstar", {1500, 0., 6.}, "binning kstar"}; - ConfigurableAxis ConfBinskT{"ConfBinskT", {150, 0., 9.}, "binning kT"}; - ConfigurableAxis ConfBinsmT{"ConfBinsmT", {225, 0., 7.5}, "binning mT"}; + ConfigurableAxis confBinskstar{"confBinskstar", {1500, 0., 6.}, "binning kstar"}; + ConfigurableAxis confBinskT{"confBinskT", {150, 0., 9.}, "binning kT"}; + ConfigurableAxis confBinsmT{"confBinsmT", {225, 0., 7.5}, "binning mT"}; FemtoUniverseContainer sameEventCont; FemtoUniverseContainer mixedEventCont; @@ -201,158 +217,92 @@ struct FemtoUniversePairTaskTrackPhi { HistogramRegistry registryDCA{"registryDCA", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; HistogramRegistry registryMCpT{"registryMCpT", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; - ColumnBinningPolicy colBinning{{ConfBinsVtx, ConfBinsMult}, true}; + ColumnBinningPolicy colBinning{{confBinsVtx, confBinsMult}, true}; HistogramRegistry effCorrRegistry{"EfficiencyCorrection", {}, OutputObjHandlingPolicy::AnalysisObject}; EffCorConfigurableGroup effCorConfGroup; EfficiencyCorrection effCorrection{&effCorConfGroup}; - float weight = 1; + float mWeight = 1.0f; // PID for protons bool isProtonNSigma(float mom, float nsigmaTPCPr, float nsigmaTOFPr) // previous version from: https://github.com/alisw/AliPhysics/blob/master/PWGCF/FEMTOSCOPY/AliFemtoUser/AliFemtoMJTrackCut.cxx { - if (mom < ConfTrackPtPIDLimit) { - if (std::abs(nsigmaTPCPr) < ConfPIDProtonNsigmaTPC) { - return true; - } else { - return false; - } - } else if (mom > ConfTrackPtPIDLimit) { - if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfPIDProtonNsigmaCombined) { - return true; - } else { - return false; - } + if (mom < confTrackPtPIDLimit) { + return std::abs(nsigmaTPCPr) < confPIDProtonNsigmaTPC; } - return false; + return std::hypot(nsigmaTOFPr, nsigmaTPCPr) < confPIDProtonNsigmaCombined; } bool isProtonRejected(float mom, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) { - if (mom < 0.5) { + if (mom < kMomCutLow) { return true; } - if (mom > 0.5) { - if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfPIDPionNsigmaReject) { - return true; - } else if (std::hypot(nsigmaTOFK, nsigmaTPCK) < ConfPIDKaonNsigmaReject) { - return true; - } else { - return false; - } - } else { - return false; - } + return std::hypot(nsigmaTOFPi, nsigmaTPCPi) < confPIDPionNsigmaReject || std::hypot(nsigmaTOFK, nsigmaTPCK) < confPIDKaonNsigmaReject; } - bool isKaonNSigma(float mom, float nsigmaTPCK, float nsigmaTOFK) + bool isKaonNSigma(float mom, bool hasTOF, float nsigmaTPCK, float nsigmaTOFK) { - if (mom < 0.3) { // 0.0-0.3 - if (std::abs(nsigmaTPCK) < 3.0) { - return true; - } else { - return false; - } - } else if (mom < 0.45) { // 0.30 - 0.45 - if (std::abs(nsigmaTPCK) < 2.0) { - return true; - } else { - return false; - } - } else if (mom < 0.55) { // 0.45-0.55 - if (std::abs(nsigmaTPCK) < 1.0) { - return true; - } else { - return false; + if (confTrackUseRun3PIDforKaons) { + if (mom < kMomCutLow) { + return std::abs(nsigmaTPCK) < kNSigmaStandard; } - } else if (mom < 1.5) { // 0.55-1.5 (now we use TPC and TOF) - if ((std::abs(nsigmaTOFK) < 3.0) && (std::abs(nsigmaTPCK) < 3.0)) { - { - return true; - } - } else { - return false; + if (hasTOF) { // if TOF is available, use combine nsigma + return std::hypot(nsigmaTOFK, nsigmaTPCK) < kNSigmaStandard; } - } else if (mom > 1.5) { // 1.5 - - if ((std::abs(nsigmaTOFK) < 2.0) && (std::abs(nsigmaTPCK) < 3.0)) { - return true; - } else { - return false; - } - } else { - return false; + // if TOF is not available, use TPC nsigma + return std::abs(nsigmaTPCK) < kNSigmaStandard; + } + + if (mom < kMomCutKaonLow) { // 0.0-0.3 + return std::abs(nsigmaTPCK) < kNSigmaStandard; + } + if (mom < kMomCutKaonMid) { // 0.30 - 0.45 + return std::abs(nsigmaTPCK) < kNSigmaMedium; + } + if (mom < kMomCutKaonHigh) { // 0.45-0.55 + return std::abs(nsigmaTPCK) < kNSigmaStrict; } + if (mom < kMomCutKaonMax) { // 0.55-1.5 (now we use TPC and TOF) + return std::hypot(nsigmaTOFK, nsigmaTPCK) < kNSigmaStandard; + } + if (mom > kMomCutKaonMax) { // 1.5 - + return (std::abs(nsigmaTOFK) < kNSigmaMedium) && (std::abs(nsigmaTPCK) < kNSigmaStandard); + } + return false; } bool isKaonRejected(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi) { - if (mom < 0.5) { - if (std::abs(nsigmaTPCPi) < ConfPIDPionNsigmaReject) { - return true; - } else if (std::abs(nsigmaTPCPr) < ConfPIDProtonNsigmaReject) { - return true; - } - } - if (mom > 0.5) { - if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfPIDPionNsigmaReject) { - return true; - } else if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfPIDProtonNsigmaReject) { - return true; - } else { - return false; - } - } else { - return false; + if (mom < kMomCutLow) { + return (std::abs(nsigmaTPCPi) < confPIDPionNsigmaReject) || (std::abs(nsigmaTPCPr) < confPIDProtonNsigmaReject); } + return (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < confPIDPionNsigmaReject) || (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < confPIDProtonNsigmaReject); } bool isPionNSigma(float mom, float nsigmaTPCPi, float nsigmaTOFPi) { - if (true) { - if (mom < 0.5) { - if (std::abs(nsigmaTPCPi) < ConfPIDPionNsigmaTPC) { - return true; - } else { - return false; - } - } else if (mom > 0.5) { - if (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < ConfPIDPionNsigmaCombined) { - return true; - } else { - return false; - } - } + if (mom < kMomCutLow) { + return (std::abs(nsigmaTPCPi) < confPIDPionNsigmaTPC); } - return false; + return (std::hypot(nsigmaTOFPi, nsigmaTPCPi) < confPIDPionNsigmaCombined); } bool isPionRejected(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCK, float nsigmaTOFK) { - if (mom < 0.5) { - if (std::abs(nsigmaTPCK) < ConfPIDKaonNsigmaReject) { - return true; - } else if (std::abs(nsigmaTPCPr) < ConfPIDProtonNsigmaReject) { - return true; - } - } - if (mom > 0.5) { - if (std::hypot(nsigmaTOFK, nsigmaTPCK) < ConfPIDKaonNsigmaReject) { - return true; - } else if (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < ConfPIDProtonNsigmaReject) { - return true; - } else { - return false; - } - } else { - return false; + if (mom < kMomCutLow) { + return (std::abs(nsigmaTPCK) < confPIDKaonNsigmaReject) || (std::abs(nsigmaTPCPr) < confPIDProtonNsigmaReject); } + return (std::hypot(nsigmaTOFK, nsigmaTPCK) < confPIDKaonNsigmaReject) || (std::hypot(nsigmaTOFPr, nsigmaTPCPr) < confPIDProtonNsigmaReject); } bool isParticleNSigmaAccepted(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) { - switch (ConfTrackPDGCode) { + bool hasTOF = std::isfinite(nsigmaTOFPr) || std::isfinite(nsigmaTOFPi) || std::isfinite(nsigmaTOFK); + + switch (confTrackPDGCode) { case 2212: // Proton case -2212: // anty Proton return isProtonNSigma(mom, nsigmaTPCPr, nsigmaTOFPr); @@ -363,7 +313,7 @@ struct FemtoUniversePairTaskTrackPhi { break; case 321: // Kaon+ case -321: // Kaon- - return isKaonNSigma(mom, nsigmaTPCK, nsigmaTOFK); + return isKaonNSigma(mom, hasTOF, nsigmaTPCK, nsigmaTOFK); break; default: return false; @@ -372,7 +322,7 @@ struct FemtoUniversePairTaskTrackPhi { bool isParticleNSigmaRejected(float mom, float nsigmaTPCPr, float nsigmaTOFPr, float nsigmaTPCPi, float nsigmaTOFPi, float nsigmaTPCK, float nsigmaTOFK) { - switch (ConfTrackPDGCode) { + switch (confTrackPDGCode) { case 2212: // Proton case -2212: // anty Proton return isProtonRejected(mom, nsigmaTPCPi, nsigmaTOFPi, nsigmaTPCK, nsigmaTOFK); @@ -398,8 +348,8 @@ struct FemtoUniversePairTaskTrackPhi { void init(InitContext&) { - if (ConfIsMC) { - hTrackDCA.init(®istryDCA, ConfBinsTempFitVarpT, ConfBinsTempFitVarDCA, true, ConfTrackPDGCode, true); + if (confIsMC) { + hTrackDCA.init(®istryDCA, confBinsTempFitVarpT, confBinsTempFitVarDCA, true, confTrackPDGCode, true); registryMCpT.add("MCReco/C_phi_pT", "; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{100, 0, 10}}); registryMCpT.add("MCReco/NC_phi_pT", "; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{100, 0, 10}}); @@ -411,9 +361,9 @@ struct FemtoUniversePairTaskTrackPhi { effCorrection.init( &effCorrRegistry, { - static_cast(ConfBinsTempFitVarpT), - {ConfBinsEta, -1, 1}, - ConfBinsMult, + static_cast(confBinsTempFitVarpT), + {confBinsEta, -1, 1}, + confBinsMult, }); eventHisto.init(&qaRegistry); @@ -480,30 +430,30 @@ struct FemtoUniversePairTaskTrackPhi { registryMCreco.add("MCrecoPhi", "MC reco Phi;#it{p}_{T} (GeV/c); #eta", {HistType::kTH2F, {{500, 0, 5}, {400, -1.0, 1.0}}}); registryMCreco.add("MCrecoPhiPt", "MC reco Phi; #it{p_T} (GeV/#it{c}); Counts", kTH1F, {{500, 0, 5}}); - trackHistoPartPhi.init(&qaRegistry, ConfBinsTempFitVarpT, ConfBinsTempFitVarInvMass, ConfIsMC, 333); - trackHistoPartTrack.init(&qaRegistry, ConfBinsTempFitVarpT, ConfBinsTempFitVar, ConfIsMC, ConfTrackPDGCode); + trackHistoPartPhi.init(&qaRegistry, confBinsTempFitVarpT, confBinsTempFitVarInvMass, confIsMC, 333); + trackHistoPartTrack.init(&qaRegistry, confBinsTempFitVarpT, confBinsTempFitVar, confIsMC, confTrackPDGCode); mixQaRegistry.add("MixingQA/hSECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); mixQaRegistry.add("MixingQA/hMECollisionBins", ";bin;Entries", kTH1F, {{120, -0.5, 119.5}}); - sameEventCont.init(&resultRegistry, ConfBinskstar, ConfBinsMult, ConfBinskT, ConfBinsmT, ConfBins3Dmult, ConfBins3DmT, ConfBinsEta, ConfBinsPhi, ConfIsMC, ConfUse3D); - mixedEventCont.init(&resultRegistry, ConfBinskstar, ConfBinsMult, ConfBinskT, ConfBinsmT, ConfBins3Dmult, ConfBins3DmT, ConfBinsEta, ConfBinsPhi, ConfIsMC, ConfUse3D); + sameEventCont.init(&resultRegistry, confBinskstar, confBinsMult, confBinskT, confBinsmT, confBins3Dmult, confBins3DmT, confBinsEta, confBinsPhi, confIsMC, confUse3D); + mixedEventCont.init(&resultRegistry, confBinskstar, confBinsMult, confBinskT, confBinsmT, confBins3Dmult, confBins3DmT, confBinsEta, confBinsPhi, confIsMC, confUse3D); - sameEventCont.setPDGCodes(333, ConfTrackPDGCode); - mixedEventCont.setPDGCodes(333, ConfTrackPDGCode); + sameEventCont.setPDGCodes(333, confTrackPDGCode); + mixedEventCont.setPDGCodes(333, confTrackPDGCode); pairCleaner.init(&qaRegistry); - if (ConfCPRIsEnabled) { - pairCloseRejection.init(&resultRegistry, &qaRegistry, confDeltaEtaAxis, confDeltaPhiStarAxis, ConfCPRdeltaPhiCutMin, ConfCPRdeltaPhiCutMax, ConfCPRdeltaEtaCutMin, ConfCPRdeltaEtaCutMax, ConfCPRChosenRadii, ConfCPRPlotPerRadii, ConfCPRInvMassCutMin, ConfCPRInvMassCutMax); + if (confCPRIsEnabled) { + pairCloseRejection.init(&resultRegistry, &qaRegistry, confDeltaEtaAxis, confDeltaPhiStarAxis, confCPRdeltaPhiCutMin, confCPRdeltaPhiCutMax, confCPRdeltaEtaCutMin, confCPRdeltaEtaCutMax, confCPRChosenRadii, confCPRPlotPerRadii, confCPRInvMassCutMin, confCPRInvMassCutMax); } } template - void doSameEvent(PartitionType groupPartsTrack, PartitionType groupPartsPhi, PartType parts, float magFieldTesla, int multCol, [[maybe_unused]] MCParticles mcParts = nullptr) + void doSameEvent(const PartitionType& groupPartsTrack, const PartitionType& groupPartsPhi, const PartType& parts, float magFieldTesla, int multCol, [[maybe_unused]] const MCParticles& mcParts = nullptr) { for (auto const& phicandidate : groupPartsPhi) { // TODO: add phi meson minv cut here - const auto& posChild = parts.iteratorAt(phicandidate.index() - 2); + const auto& posChild = parts.iteratorAt(phicandidate.index() - kPhiDaughterOffsetPos); float tpcNSigmaKp = trackCuts.getNsigmaTPC(posChild, o2::track::PID::Kaon); float tofNSigmaKp = trackCuts.getNsigmaTOF(posChild, o2::track::PID::Kaon); qaRegistry.fill(HIST("PhiDaugh_pos/nSigmaTPC"), posChild.p(), tpcNSigmaKp); @@ -513,7 +463,7 @@ struct FemtoUniversePairTaskTrackPhi { qaRegistry.fill(HIST("PhiDaugh_pos/eta"), posChild.eta()); qaRegistry.fill(HIST("PhiDaugh_pos/phi"), posChild.phi()); - const auto& negChild = parts.iteratorAt(phicandidate.index() - 1); + const auto& negChild = parts.iteratorAt(phicandidate.index() - kPhiDaughterOffsetNeg); float tpcNSigmaKm = trackCuts.getNsigmaTPC(negChild, o2::track::PID::Kaon); float tofNSigmaKm = trackCuts.getNsigmaTOF(negChild, o2::track::PID::Kaon); qaRegistry.fill(HIST("PhiDaugh_neg/nSigmaTPC"), negChild.p(), tpcNSigmaKm); @@ -526,7 +476,7 @@ struct FemtoUniversePairTaskTrackPhi { trackHistoPartPhi.fillQA(phicandidate); if constexpr (isMC) { // reco - effCorrection.fillRecoHist(phicandidate, 333); + effCorrection.fillRecoHist(phicandidate, o2::constants::physics::Pdg::kPhi); } } @@ -538,11 +488,11 @@ struct FemtoUniversePairTaskTrackPhi { float tpcNSigmaPr = trackCuts.getNsigmaTPC(track, o2::track::PID::Proton); float tofNSigmaPr = trackCuts.getNsigmaTOF(track, o2::track::PID::Proton); - if (ConfTrackIsIdentified) { + if (confTrackIsIdentified) { if (!isParticleNSigmaAccepted(track.p(), tpcNSigmaPr, tofNSigmaPr, tpcNSigmaPi, tofNSigmaPi, tpcNSigmaKa, tofNSigmaKa)) { continue; } - if (ConfTrackIsRejected) { + if (confTrackIsRejected) { if (isParticleNSigmaRejected(track.p(), tpcNSigmaPr, tofNSigmaPr, tpcNSigmaPi, tofNSigmaPi, tpcNSigmaKa, tofNSigmaKa)) { continue; } @@ -566,26 +516,26 @@ struct FemtoUniversePairTaskTrackPhi { trackHistoPartTrack.fillQA(track); if constexpr (isMC) { - effCorrection.fillRecoHist(track, ConfTrackPDGCode); + effCorrection.fillRecoHist(track, confTrackPDGCode); } } /// Now build the combinations for (auto const& [track, phicandidate] : combinations(CombinationsFullIndexPolicy(groupPartsTrack, groupPartsPhi))) { - if (ConfTrackIsIdentified) { + if (confTrackIsIdentified) { if (!isParticleNSigmaAccepted(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { continue; } } - if (ConfTrackIsRejected) { + if (confTrackIsRejected) { if (isParticleNSigmaRejected(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { continue; } } // Close Pair Rejection - if (ConfCPRIsEnabled) { + if (confCPRIsEnabled) { if (pairCloseRejection.isClosePair(track, phicandidate, parts, magFieldTesla, femto_universe_container::EventType::same)) { continue; } @@ -595,8 +545,8 @@ struct FemtoUniversePairTaskTrackPhi { if (!pairCleaner.isCleanPair(track, phicandidate, parts)) { continue; } - weight = effCorrection.getWeight(ParticleNo::ONE, phicandidate) * effCorrection.getWeight(ParticleNo::TWO, track); - sameEventCont.setPair(track, phicandidate, multCol, ConfUse3D, weight); + mWeight = effCorrection.getWeight(ParticleNo::ONE, phicandidate) * effCorrection.getWeight(ParticleNo::TWO, track); + sameEventCont.setPair(track, phicandidate, multCol, confUse3D, mWeight); } // // Used for better fitting of invariant mass background. @@ -627,27 +577,27 @@ struct FemtoUniversePairTaskTrackPhi { } template - void doMixedEvent(PartitionType groupPartsTrack, PartitionType groupPartsPhi, PartType parts, float magFieldTesla, int multCol, [[maybe_unused]] MCParticles mcParts = nullptr) + void doMixedEvent(const PartitionType& groupPartsTrack, const PartitionType& groupPartsPhi, const PartType& parts, float magFieldTesla, int multCol, [[maybe_unused]] const MCParticles& mcParts = nullptr) { for (auto const& [track, phicandidate] : combinations(CombinationsFullIndexPolicy(groupPartsTrack, groupPartsPhi))) { - if (ConfTrackIsIdentified) { + if (confTrackIsIdentified) { if (!isParticleNSigmaAccepted(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { continue; } - if (ConfTrackIsRejected) { + if (confTrackIsRejected) { if (isParticleNSigmaRejected(track.p(), trackCuts.getNsigmaTPC(track, o2::track::PID::Proton), trackCuts.getNsigmaTOF(track, o2::track::PID::Proton), trackCuts.getNsigmaTPC(track, o2::track::PID::Pion), trackCuts.getNsigmaTOF(track, o2::track::PID::Pion), trackCuts.getNsigmaTPC(track, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(track, o2::track::PID::Kaon))) { continue; } } } - if (ConfCPRIsEnabled) { + if (confCPRIsEnabled) { if (pairCloseRejection.isClosePair(track, phicandidate, parts, magFieldTesla, femto_universe_container::EventType::mixed)) { continue; } } - weight = effCorrection.getWeight(ParticleNo::ONE, phicandidate) * effCorrection.getWeight(ParticleNo::TWO, track); - mixedEventCont.setPair(track, phicandidate, multCol, ConfUse3D, weight); + mWeight = effCorrection.getWeight(ParticleNo::ONE, phicandidate) * effCorrection.getWeight(ParticleNo::TWO, track); + mixedEventCont.setPair(track, phicandidate, multCol, confUse3D, mWeight); } } @@ -718,8 +668,9 @@ struct FemtoUniversePairTaskTrackPhi { void processMCTruth(aod::FDParticles const& parts) { for (auto const& part : parts) { - if (part.partType() != uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) + if (part.partType() != uint8_t(aod::femtouniverseparticle::ParticleType::kMCTruthTrack)) { continue; + } int pdgCode = static_cast(part.pidCut()); const auto& pdgParticle = pdgMC->GetParticle(pdgCode); @@ -727,25 +678,26 @@ struct FemtoUniversePairTaskTrackPhi { continue; } - if (pdgCode == ConfTrackPDGCode) { + if (pdgCode == confTrackPDGCode) { effCorrection.fillTruthHist(part); } // charge + if (pdgParticle->Charge() > 0.0) { registryMCtruth.fill(HIST("MCtruthAllPositivePt"), part.pt()); - if (pdgCode == 2212) { + if (pdgCode == kProton) { registryMCtruth.fill(HIST("MCtruthPpos"), part.pt(), part.eta()); registryMCtruth.fill(HIST("MCtruthPposPt"), part.pt()); continue; - } else if (pdgCode == 321) { + } + if (pdgCode == kKPlus) { registryMCtruth.fill(HIST("MCtruthKp"), part.pt(), part.eta()); registryMCtruth.fill(HIST("MCtruthKpPt"), part.pt()); continue; } } // charge 0 - if (pdgCode == 333) { + if (pdgCode == o2::constants::physics::Pdg::kPhi) { registryMCtruth.fill(HIST("MCtruthPhi"), part.pt(), part.eta()); registryMCtruth.fill(HIST("MCtruthPhiPt"), part.pt()); effCorrection.fillTruthHist(part); @@ -756,11 +708,12 @@ struct FemtoUniversePairTaskTrackPhi { if (pdgParticle->Charge() < 0.0) { registryMCtruth.fill(HIST("MCtruthAllNegativePt"), part.pt()); - if (pdgCode == -321) { + if (pdgCode == kKMinus) { registryMCtruth.fill(HIST("MCtruthKm"), part.pt(), part.eta()); registryMCtruth.fill(HIST("MCtruthKmPt"), part.pt()); continue; - } else if (pdgCode == -2212) { + } + if (pdgCode == kProtonBar) { registryMCtruth.fill(HIST("MCtruthPneg"), part.pt(), part.eta()); registryMCtruth.fill(HIST("MCtruthPnegPt"), part.pt()); continue; @@ -774,36 +727,38 @@ struct FemtoUniversePairTaskTrackPhi { { for (auto const& part : parts) { auto mcPartId = part.fdMCParticleId(); - if (mcPartId == -1) + if (mcPartId == kInvalidMCPartId) { continue; // no MC particle + } const auto& mcpart = mcparts.iteratorAt(mcPartId); - if (mcpart.pdgMCTruth() == ConfTrackPDGCode && (part.pt() > ConfTrackPtLow) && (part.pt() < ConfTrackPtHigh) && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + if (mcpart.pdgMCTruth() == confTrackPDGCode && (part.pt() > confTrackPtLow) && (part.pt() < confTrackPtHigh) && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { registryMCpT.fill(HIST("MCReco/NC_p_pT"), part.pt()); float weightTrack = effCorrection.getWeight(ParticleNo::TWO, part); registryMCpT.fill(HIST("MCReco/C_p_pT"), part.pt(), weightTrack); } - if ((mcpart.pdgMCTruth() == 333) && (part.partType() == aod::femtouniverseparticle::ParticleType::kPhi) && (part.pt() > ConfPhiPtLow) && (part.pt() < ConfPhiPtHigh)) { + if ((mcpart.pdgMCTruth() == o2::constants::physics::Pdg::kPhi) && (part.partType() == aod::femtouniverseparticle::ParticleType::kPhi) && (part.pt() > confPhiPtLow) && (part.pt() < confPhiPtHigh)) { registryMCpT.fill(HIST("MCReco/NC_phi_pT"), part.pt()); float weightPhi = effCorrection.getWeight(ParticleNo::ONE, part); registryMCpT.fill(HIST("MCReco/C_phi_pT"), part.pt(), weightPhi); } - if (isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) + if (isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { hTrackDCA.fillQA(part); - if ((part.partType() == aod::femtouniverseparticle::ParticleType::kPhi) && (mcpart.pdgMCTruth() == 333) && (mcpart.partOriginMCTruth() == aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary)) { + } + if ((part.partType() == aod::femtouniverseparticle::ParticleType::kPhi) && (mcpart.pdgMCTruth() == o2::constants::physics::Pdg::kPhi) && (mcpart.partOriginMCTruth() == aod::femtouniverse_mc_particle::ParticleOriginMCTruth::kPrimary)) { registryMCreco.fill(HIST("MCrecoPhi"), mcpart.pt(), mcpart.eta()); // phi registryMCreco.fill(HIST("MCrecoPhiPt"), mcpart.pt()); } else if (part.partType() == aod::femtouniverseparticle::ParticleType::kTrack) { if (part.sign() > 0) { registryMCreco.fill(HIST("MCrecoAllPositivePt"), mcpart.pt()); - if (mcpart.pdgMCTruth() == 2212 && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + if (mcpart.pdgMCTruth() == kProton && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { registryMCreco.fill(HIST("MCrecoPpos"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("MCrecoPposPt"), mcpart.pt()); } } else if (part.sign() < 0) { registryMCreco.fill(HIST("MCrecoAllNegativePt"), mcpart.pt()); - if (mcpart.pdgMCTruth() == -2212 && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { + if (mcpart.pdgMCTruth() == kProtonBar && isParticleNSigmaAccepted(part.p(), trackCuts.getNsigmaTPC(part, o2::track::PID::Proton), trackCuts.getNsigmaTOF(part, o2::track::PID::Proton), trackCuts.getNsigmaTPC(part, o2::track::PID::Pion), trackCuts.getNsigmaTOF(part, o2::track::PID::Pion), trackCuts.getNsigmaTPC(part, o2::track::PID::Kaon), trackCuts.getNsigmaTOF(part, o2::track::PID::Kaon))) { registryMCreco.fill(HIST("MCrecoPneg"), mcpart.pt(), mcpart.eta()); registryMCreco.fill(HIST("MCrecoPnegPt"), mcpart.pt()); } From a70296ce42162982f554fc18cb79605e63029498 Mon Sep 17 00:00:00 2001 From: ariedel-cern <85537041+ariedel-cern@users.noreply.github.com> Date: Fri, 31 Jul 2026 14:19:06 +0200 Subject: [PATCH 59/71] [PWGCF] Small fixes in femto framework (#17275) --- PWGCF/Femto/Core/pairHistManager.h | 6 ++++-- PWGCF/Femto/Tasks/femtoPairMcParticleMcParticle.cxx | 2 +- PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx | 2 +- PWGCF/Femto/Tasks/femtoPairTrackKink.cxx | 2 +- PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx | 2 +- PWGCF/Femto/Tasks/femtoPairTrackV0.cxx | 2 +- PWGCF/Femto/Tasks/femtoTrackQa.cxx | 4 ++-- PWGCF/Femto/Tasks/femtoTripletTrackTrackCascade.cxx | 2 +- PWGCF/Femto/Tasks/femtoTripletTrackTrackTrack.cxx | 2 +- 9 files changed, 13 insertions(+), 11 deletions(-) diff --git a/PWGCF/Femto/Core/pairHistManager.h b/PWGCF/Femto/Core/pairHistManager.h index e6336064f32..ce4e638f42b 100644 --- a/PWGCF/Femto/Core/pairHistManager.h +++ b/PWGCF/Femto/Core/pairHistManager.h @@ -216,7 +216,7 @@ struct ConfPairBinning : o2::framework::ConfigurableGroup { o2::framework::ConfigurableAxis pt2{"pt2", {{100, 0, 6}}, "Pt binning for particle 2"}; o2::framework::ConfigurableAxis mass1{"mass1", {{100, 0, 2}}, "Mass binning for particle 1 (if particle has mass getter, otherwise PDG mass)"}; o2::framework::ConfigurableAxis mass2{"mass2", {{100, 0, 2}}, "Mass binning for particle 2 (if particle has mass getter, otherwise PDG mass)"}; - o2::framework::ConfigurableAxis massInv{"massInv", {{100, 0, 2}}, "Invariant Mass binning"}; + o2::framework::ConfigurableAxis massInv{"massInv", {{100, 0, 5}}, "Invariant Mass binning"}; o2::framework::ConfigurableAxis dalitzMtot{"dalitzMtot", {{100, 0, 10}}, "Total invariant mass squared binning in darlitz plot"}; o2::framework::ConfigurableAxis dalitzM12{"dalitzM12", {{100, 0, 10}}, "Mass12 binning of darlitz plot"}; o2::framework::ConfigurableAxis dalitzM13{"dalitzM13", {{100, 0, 10}}, "Mass13 binning of darlitz plot"}; @@ -705,7 +705,9 @@ class PairHistManager } if (mPlotDalitz) { - if constexpr (modes::isEqual(particleType1, modes::Particle::kTrack) && (modes::isEqual(particleType2, modes::Particle::kV0) || modes::isEqual(particleType2, modes::Particle::kCharmHadron))) { + if constexpr (modes::isEqual(particleType1, modes::Particle::kTrack) && (modes::isEqual(particleType2, modes::Particle::kV0) || + modes::isEqual(particleType2, modes::Particle::kTwoTrackResonance) || + modes::isEqual(particleType2, modes::Particle::kCharmHadron))) { auto posDaughter = trackTable.rawIteratorAt(particle2.posDauId() - trackTable.offset()); auto negDaughter = trackTable.rawIteratorAt(particle2.negDauId() - trackTable.offset()); ROOT::Math::PtEtaPhiMVector posDau4v = ROOT::Math::PtEtaPhiMVector(posDaughter.pt(), posDaughter.eta(), posDaughter.phi(), mPdgMassPosDau2); diff --git a/PWGCF/Femto/Tasks/femtoPairMcParticleMcParticle.cxx b/PWGCF/Femto/Tasks/femtoPairMcParticleMcParticle.cxx index 0c0a4553359..01c25a60146 100644 --- a/PWGCF/Femto/Tasks/femtoPairMcParticleMcParticle.cxx +++ b/PWGCF/Femto/Tasks/femtoPairMcParticleMcParticle.cxx @@ -107,7 +107,7 @@ struct FemtoPairMcParticleMcParticle { { // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; diff --git a/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx b/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx index e9433fb4f2b..1c08e4b14a7 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx @@ -177,7 +177,7 @@ struct FemtoPairTrackCascade { // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; diff --git a/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx b/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx index dd7ac4bfbb1..3572e577537 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx @@ -167,7 +167,7 @@ struct FemtoPairTrackKink { // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; diff --git a/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx b/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx index ddf110af478..cb49fed5e8d 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx @@ -129,7 +129,7 @@ struct FemtoPairTrackTrack { // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; diff --git a/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx b/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx index 6974ed0b2c7..73cf010fb31 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx @@ -169,7 +169,7 @@ struct FemtoPairTrackV0 { // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; diff --git a/PWGCF/Femto/Tasks/femtoTrackQa.cxx b/PWGCF/Femto/Tasks/femtoTrackQa.cxx index 7a460bb3c15..88583914287 100644 --- a/PWGCF/Femto/Tasks/femtoTrackQa.cxx +++ b/PWGCF/Femto/Tasks/femtoTrackQa.cxx @@ -86,13 +86,13 @@ struct FemtoTrackQa { if ((static_cast(doprocessData) + static_cast(doprocessMc)) > 1) { LOG(fatal) << "More than 1 process function is activated. Breaking..."; } - bool processData = doprocessData; + bool processDataFlag = doprocessData; trackCleaner.init(confTrackCleaner); std::map> colHistSpec; std::map> trackHistSpec; - if (processData) { + if (processDataFlag) { colHistSpec = colhistmanager::makeColQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); colHistManager.init(&hRegistry, colHistSpec, confCollisionBinning, confCollisionQaBinning); trackHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confTrackBinning, confTrackQaBinning); diff --git a/PWGCF/Femto/Tasks/femtoTripletTrackTrackCascade.cxx b/PWGCF/Femto/Tasks/femtoTripletTrackTrackCascade.cxx index 6bddc62672e..fca9c8cad9f 100644 --- a/PWGCF/Femto/Tasks/femtoTripletTrackTrackCascade.cxx +++ b/PWGCF/Femto/Tasks/femtoTripletTrackTrackCascade.cxx @@ -198,7 +198,7 @@ struct FemtoTripletTrackTrackCascade { } // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; diff --git a/PWGCF/Femto/Tasks/femtoTripletTrackTrackTrack.cxx b/PWGCF/Femto/Tasks/femtoTripletTrackTrackTrack.cxx index 8b9db111c69..cbdbc3e2345 100644 --- a/PWGCF/Femto/Tasks/femtoTripletTrackTrackTrack.cxx +++ b/PWGCF/Femto/Tasks/femtoTripletTrackTrackTrack.cxx @@ -134,7 +134,7 @@ struct FemtoTripletTrackTrackTrack { // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here - mixBinsVtxMult = {{confMixing.vtxBins, confMixing.multBins.value}, true}; + mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; From 31c9e5d2f4ad83cc6043469608d5125f00f0ca8d Mon Sep 17 00:00:00 2001 From: Marvin Hemmer <53471402+mhemmer-cern@users.noreply.github.com> Date: Fri, 31 Jul 2026 14:28:00 +0200 Subject: [PATCH 60/71] [PWGEM] Add option to separate EMCal and DCal cluster pairing for flow task (#17246) --- .../PhotonMeson/DataModel/GammaTablesRedux.h | 2 +- PWGEM/PhotonMeson/DataModel/gammaTables.h | 25 +-- .../TableProducer/associateMCinfoPhoton.cxx | 37 ++-- .../TableProducer/skimmerGammaCalo.cxx | 13 +- PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx | 164 ++++++++++++------ PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx | 10 +- PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx | 32 +++- PWGEM/PhotonMeson/Tasks/testTaskEmc.cxx | 4 +- PWGEM/PhotonMeson/Utils/MCUtilities.h | 18 ++ 9 files changed, 209 insertions(+), 96 deletions(-) diff --git a/PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h b/PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h index d666265af2a..d9d2485206d 100644 --- a/PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h +++ b/PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h @@ -47,7 +47,7 @@ enum Observable { }; // Values in tables are stored in downscaled format to save disk space -const std::array downscalingFactors{ +constexpr std::array downscalingFactors{ 1E0, // Cluster definition 1E3, // Cluster energy 1E4, // Cluster eta diff --git a/PWGEM/PhotonMeson/DataModel/gammaTables.h b/PWGEM/PhotonMeson/DataModel/gammaTables.h index 9ef4b45727b..ca46c23329f 100644 --- a/PWGEM/PhotonMeson/DataModel/gammaTables.h +++ b/PWGEM/PhotonMeson/DataModel/gammaTables.h @@ -102,23 +102,31 @@ using V0LegMCLabel = V0LegMCLabels::iterator; // 3. EMEMCClusterMCLabels: Vector of EM MC particle ID of largest contributor to cluster namespace emcclustermclabel { -DECLARE_SOA_ARRAY_INDEX_COLUMN(McParticle, emmcparticle) //! +DECLARE_SOA_ARRAY_INDEX_COLUMN(McParticle, mcParticle) //! Array of indice of McParticles +DECLARE_SOA_COLUMN(Amplitude, amplitude, std::vector); //! vector of aplitudes stored in cluster. Ordering is identical to the ordering of EMMCParticleId } // namespace emcclustermclabel // NOTE: MC labels. This table has one vector of global mc particle ids for each reconstructed emc cluster (joinable with emccluster table) DECLARE_SOA_TABLE(EMCClusterMCLabels, "AOD", "EMCClsMCLABEL", //! emcclustermclabel::McParticleIds); -using EMCClusterMCLabel = EMCClusterMCLabels::iterator; + +DECLARE_SOA_TABLE_VERSIONED(EMCClusterMCLabels_001, "AOD", "EMCClsMCLABEL", 1, //! + emcclustermclabel::McParticleIds, emcclustermclabel::Amplitude); +using EMCClusterMCLabel = EMCClusterMCLabels_001::iterator; namespace ememcclustermclabel { -DECLARE_SOA_ARRAY_INDEX_COLUMN(EMMCParticle, emmcparticle); //! +DECLARE_SOA_ARRAY_INDEX_COLUMN(EMMCParticle, emmcparticle); //! Array of indice of EmMcParticles +DECLARE_SOA_COLUMN(Amplitude, amplitude, std::vector); //! vector of aplitudes stored in cluster. Ordering is identical to the ordering of EMMCParticleId } // namespace ememcclustermclabel // NOTE: MC labels. This table has a vector of entries for each reconstructed emc cluster (joinable with emccluster table) DECLARE_SOA_TABLE(EMEMCClusterMCLabels, "AOD", "EMEMCClsMCLABEL", //! ememcclustermclabel::EMMCParticleIds); -using EMEMCClusterMCLabel = EMEMCClusterMCLabels::iterator; + +DECLARE_SOA_TABLE_VERSIONED(EMEMCClusterMCLabels_001, "AOD", "EMEMCClsMCLABEL", 1, //! + ememcclustermclabel::EMMCParticleIds, ememcclustermclabel::Amplitude); +using EMEMCClusterMCLabel = EMEMCClusterMCLabels_001::iterator; namespace v0leg { @@ -146,9 +154,8 @@ DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITS, meanClusterSizeITS, [](uint32_t i } if (nl > 0) { return static_cast(total_cluster_size) / static_cast(nl); - } else { - return 0; } + return 0; }); DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSib, meanClusterSizeITSib, [](uint32_t itsClusterSizes) -> float { int total_cluster_size = 0, nl = 0; @@ -161,9 +168,8 @@ DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSib, meanClusterSizeITSib, [](uint32 } if (nl > 0) { return static_cast(total_cluster_size) / static_cast(nl); - } else { - return 0; } + return 0; }); DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSob, meanClusterSizeITSob, [](uint32_t itsClusterSizes) -> float { int total_cluster_size = 0, nl = 0; @@ -176,9 +182,8 @@ DECLARE_SOA_DYNAMIC_COLUMN(MeanClusterSizeITSob, meanClusterSizeITSob, [](uint32 } if (nl > 0) { return static_cast(total_cluster_size) / static_cast(nl); - } else { - return 0; } + return 0; }); } // namespace v0leg DECLARE_SOA_TABLE(V0Legs_000, "AOD", "V0LEG", //! diff --git a/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx b/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx index 0034d0dc3b6..7eb9d556d85 100644 --- a/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx +++ b/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx @@ -10,8 +10,8 @@ // or submit itself to any jurisdiction. /// \file associateMCinfoPhoton.cxx -/// \brief This code produces reduced events for photon analyses -/// \author Daiki Sekihata (daiki.sekihata@cern.ch) +/// \brief This code produces EmMc tables were the McParticleIds get reshuffled due to not storing all McParticles +/// \author Daiki Sekihata (daiki.sekihata@cern.ch), Marvin Hemmer (marvin.hemmer@cern.ch), Nicolas Strangmann (nicolas.strangmann@cern.ch) #include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -57,7 +58,7 @@ using namespace o2::constants::physics; using MyCollisionsMC = soa::Join; using TracksMC = soa::Join; using FwdTracksMC = soa::Join; -using MyEMCClusters = soa::Join; +using MyEMCClusters = soa::Join; struct Counter { int particles{0}; @@ -77,7 +78,7 @@ struct AssociateMCInfoPhoton { Produces emmcparticles; Produces v0legmclabels; Produces emprimaryelectronmclabels; - Produces ememcclustermclabels; + Produces ememcclustermclabels; Produces binnedGenPt; @@ -100,6 +101,7 @@ struct AssociateMCInfoPhoton { // !!Don't change pt,eta,y binning. These binnings have to be consistent with binned data at analysis.!! std::vector ptbins; + ptbins.reserve(72); for (int i = 0; i < 2; i++) { // o2-linter: disable=magic-number (just numbers for binning) ptbins.emplace_back(0.05 * (i - 0) + 0.0); // from 0 to 0.05 GeV/c, every 0.05 GeV/c } @@ -116,7 +118,7 @@ struct AssociateMCInfoPhoton { const AxisSpec axisRapidity{{0.0, +0.8, +0.9}, "rapidity |y|"}; static constexpr uint NParticleNames = 9; - static constexpr std::string_view ParticleNames[NParticleNames] = { + static constexpr std::array ParticleNames = { "Gamma", "Pi0", "Eta", "Omega", "Phi", "ChargedPion", "ChargedKaon", "K0S", "Lambda"}; @@ -267,8 +269,9 @@ struct AssociateMCInfoPhoton { genGamma[binNumber]++; break; case PDG_t::kPi0: - if (requireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) + if (requireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) { continue; + } registry.fill(HIST("Generated/h2PtY_Pi0"), mcParticle.pt(), std::fabs(mcParticle.y())); genPi0[binNumber]++; if (isMesonAccepted) { @@ -276,8 +279,9 @@ struct AssociateMCInfoPhoton { } break; case Pdg::kEta: - if (requireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) + if (requireGammaGammaDecay && !isGammaGammaDecay(mcParticle, mcParticles)) { continue; + } registry.fill(HIST("Generated/h2PtY_Eta"), mcParticle.pt(), std::fabs(mcParticle.y())); genEta[binNumber]++; if (isMesonAccepted) { @@ -291,7 +295,7 @@ struct AssociateMCInfoPhoton { } // end of mc track loop // make an entry for this MC event only if it was not already added to the table - if (!(fEventLabels.find(mcCollisionIter.globalIndex()) != fEventLabels.end())) { + if (!fEventLabels.contains(mcCollisionIter.globalIndex())) { mcevents(mcCollisionIter.globalIndex(), mcCollisionIter.generatorsID(), mcCollisionIter.posX(), mcCollisionIter.posY(), mcCollisionIter.posZ(), mcCollisionIter.impactParameter(), mcCollisionIter.eventPlaneAngle()); fEventLabels[mcCollisionIter.globalIndex()] = fCounter.events; fCounter.events++; @@ -438,15 +442,17 @@ struct AssociateMCInfoPhoton { mcCollisionIter.setCursor(collisionIter.mcCollisionId()); // TODO: test - if (emccluster.emmcparticleIds().size() <= 0) { + if (emccluster.mcParticleIds().size() <= 0) { continue; } std::vector vEmcMcParticleIds; + std::vector vAmplitudes; - vEmcMcParticleIds.reserve(emccluster.emmcparticleIds().size()); + vEmcMcParticleIds.reserve(emccluster.mcParticleIds().size()); + vAmplitudes.reserve(emccluster.mcParticleIds().size()); - for (const auto& emcParticleId : emccluster.emmcparticleIds()) { - mcPhoton.setCursor(emcParticleId); + for (size_t iCont = 0; iCont < emccluster.mcParticleIds().size(); iCont++) { + mcPhoton.setCursor(emccluster.mcParticleIds()[iCont]); // if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack auto [iter, isNew] = fNewLabels.try_emplace(mcPhoton.globalIndex(), fCounter.particles); @@ -456,6 +462,7 @@ struct AssociateMCInfoPhoton { fCounter.particles++; } vEmcMcParticleIds.emplace_back(iter->second); + vAmplitudes.emplace_back(emccluster.amplitude()[iCont]); // ememcclustermclabels(fNewLabels.find(mcPhoton.index())->second); // Next, store mother-chain of this reconstructed track. @@ -465,7 +472,7 @@ struct AssociateMCInfoPhoton { } selectMothersToStore(motherid, mcParticles.size(), motherParticle, daughterIter, mcCollisionIter, fNewLabels, fNewLabelsReversed, fEventIdx, fEventLabels, fCounter); } // end of loop over mc particles of the current emc cluster - ememcclustermclabels(vEmcMcParticleIds); + ememcclustermclabels(vEmcMcParticleIds, vAmplitudes); } // end of em emc cluster loop } @@ -625,8 +632,8 @@ struct AssociateMCInfoPhoton { PROCESS_SWITCH(AssociateMCInfoPhoton, processDummy, "processDummy", true); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"associate-mc-info-photon"})}; + adaptAnalysisTask(context, TaskName{"associate-mc-info-photon"})}; } diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx index 3c54a08a4bb..872df52551c 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx @@ -53,7 +53,7 @@ struct SkimmerGammaCalo { Preslice psMSperCluster = o2::aod::emcalclustercell::emcalclusterId; Produces tableGammaEMCReco; - Produces tableEMCClusterMCLabels; + Produces tableEMCClusterMCLabels; Produces tableCellEMCReco; Produces tableEmEmcClusters; @@ -331,15 +331,16 @@ struct SkimmerGammaCalo { continue; } std::vector mcLabels; + std::vector amplitudes; + mcLabels.reserve(emccluster.amplitudeA().size()); + amplitudes.reserve(emccluster.amplitudeA().size()); for (size_t iCont = 0; iCont < emccluster.amplitudeA().size(); iCont++) { mcLabels.push_back(emccluster.mcParticleIds()[iCont]); + amplitudes.push_back(emccluster.amplitudeA()[iCont]); } - // LOGF(info, "---- New Cluster ---"); - // for (unsigned long int iCont = 0; iCont < mcLabels.size(); iCont++) { - // LOGF(info, "iCont = %d, mcParticle = %d, amplitudeA = %.5f", iCont, mcLabels.at(iCont), emccluster.amplitudeA()[iCont]); - // } - tableEMCClusterMCLabels(mcLabels); + tableEMCClusterMCLabels(mcLabels, amplitudes); mcLabels.clear(); + amplitudes.clear(); } } PROCESS_SWITCH(SkimmerGammaCalo, processMC, "process MC info", false); // Run this in addition to processRec for MCs to copy the cluster mc labels from the EMCALMCClusters to the skimmed EMCClusterMCLabels table diff --git a/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx b/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx index b83cc325bc7..f1feeb608a8 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx @@ -73,6 +73,9 @@ using namespace o2::aod::pwgem::photon; using namespace o2::constants::physics; using namespace o2::aod::pwgem::photonmeson::utils::mcutil; +constexpr float MinAmpThreshold = 0.2f; // Minimum cluster amplitude threshold to count as significant +constexpr float MaxAmpDiff = 0.1f; // Maximum cluster amplitude difference to leading cluster contribution to count as significant + enum CentralityEstimator { None = 0, CFT0A, @@ -82,21 +85,25 @@ enum CentralityEstimator { }; enum class TruthClass { - Conversion = 0, // 1: true e+/e- pair from the same conversion + Conversion = 0, // 0: true e+/e- pair from the same conversion - PhotonPairSamePi0, // 2: two photon clusters, same Pi0 - PhotonPairDiffPi0, // 3: two photon clusters, different Pi0s - PhotonPairOnePi0, // 4: two photon clusters, only one from a Pi0 + PhotonPairSamePi0, // 1: two photon clusters, same Pi0 + PhotonPairDiffPi0, // 2: two photon clusters, different Pi0s + PhotonPairOnePi0, // 3: two photon clusters, only one from a Pi0 - PhotonElectronSamePi0, // 5: photon + electron cluster, same Pi0 - PhotonElectronDiffPi0, // 6: photon + electron cluster, different Pi0s - PhotonElectronOnePi0, // 7: photon + electron cluster, only one from a Pi0 + PhotonElectronSamePi0, // 4: photon + electron cluster, same Pi0 + PhotonElectronDiffPi0, // 5: photon + electron cluster, different Pi0s + PhotonElectronOnePi0, // 6: photon + electron cluster, only one from a Pi0 + PhotonElectronBS, // 7: photon + electron cluster, from Bremsstrahlung ElectronPairSamePi0, // 8: e+e cluster pair, same Pi0 (conversion and/or Dalitz) ElectronPairDiffPi0, // 9: e+e cluster pair, different Pi0s ElectronPairOnePi0, // 10: e+e cluster pair, only one from a Pi0 - Background, // 11: else / uncorrelated + SplitPhotonCluster, // 11: one photon producing two clusters + SplitLeptonCluster, // 12: one lepton producing two clusters + + Background, // 13: else / uncorrelated NClasses }; @@ -122,6 +129,7 @@ struct ClusterMcInfo { bool isFromConv = false; bool isMergedConv = false; bool isFromPi0 = false; + bool isFromBremsstrahlung = false; int convMotherId = -1; int photonId = -1; }; @@ -131,6 +139,8 @@ ClusterMcInfo classifyCluster(const TGroup& g, TIter& mcCluster, TIter& mcCluste { ClusterMcInfo info; mcCluster.setCursor(g.emmcparticleIds()[0]); + info.isFromBremsstrahlung = isFromBremsstrahlung(mcCluster, mcClusterLooper); + float leadingAmplitude = g.amplitude()[0]; if (std::abs(mcCluster.pdgCode()) == PDG_t::kElectron) { info.isLepton = true; info.convMotherId = getMotherIndexFromChain(mcCluster, mcClusterLooper, PDG_t::kGamma); @@ -139,12 +149,12 @@ ClusterMcInfo classifyCluster(const TGroup& g, TIter& mcCluster, TIter& mcCluste if (mcCluster.mothersIds().size() > 0 && info.isFromConv) { for (size_t i = 1; i < g.emmcparticleIds().size(); ++i) { mcClusterLooper.setCursor(g.emmcparticleIds()[i]); - if (std::abs(mcClusterLooper.pdgCode()) == PDG_t::kElectron) { + if (std::abs(mcClusterLooper.pdgCode()) == PDG_t::kElectron && mcClusterLooper.pdgCode() == -1 * mcCluster.pdgCode()) { int32_t otherConvMotherId = getMotherIndexFromChain(mcClusterLooper, mcClusterLooper2, PDG_t::kGamma); if (otherConvMotherId == info.convMotherId) { - info.isMergedConv = true; - info.isLepton = false; - info.isPhoton = true; + if (g.amplitude()[i] >= leadingAmplitude - MaxAmpDiff && g.amplitude()[i] > MinAmpThreshold) { + info.isMergedConv = true; + } break; } } @@ -155,14 +165,22 @@ ClusterMcInfo classifyCluster(const TGroup& g, TIter& mcCluster, TIter& mcCluste info.isPhoton = true; } - info.photonId = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta}); + info.photonId = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta, Pdg::kOmega, Pdg::kEtaPrime}); info.isFromPi0 = info.photonId >= 0; return info; } + struct EmcalPhotonMcTask { static constexpr float EMCALRadius = 440.f; static constexpr float PhiVUndefined = -999.f; + static constexpr float Epsilon = 1.e-6f; + + static constexpr std::array(TruthClass::NClasses)> kTruthClassNames = { + "Conversion", "PhotonPairSamePi0", "PhotonPairDiffPi0", "PhotonPairOnePi0", + "PhotonElectronSamePi0", "PhotonElectronDiffPi0", "PhotonElectronOnePi0", "PhotonElectronBS", + "ElectronPairSamePi0", "ElectronPairDiffPi0", "ElectronPairOnePi0", + "SplitPhotonCluster", "SplitLeptonCluster", "Background"}; Produces convTagCandidates; @@ -171,7 +189,7 @@ struct EmcalPhotonMcTask { Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; Configurable writeTable{"writeTable", true, "write table for ML."}; - Configurable> classPrescale{"classPrescale", {1, 1, 700, 25, 1, 350, 15, 1, 35, 2, 1000}, "prescale factor per TruthClass, indexed 0..10 matching the enum order"}; + Configurable> classPrescale{"classPrescale", {1, 1, 700, 25, 1, 350, 15, 1, 1, 35, 2, 1, 1, 1000}, "prescale factor per TruthClass, indexed 0..10 matching the enum order"}; Configurable bkgPrescaleSeed{"bkgPrescaleSeed", 42, "seed for the background-prescale RNG"}; // configurable axis @@ -181,7 +199,7 @@ struct EmcalPhotonMcTask { ConfigurableAxis thnConfigAxisMult{"thnConfigAxisMult", {60, 0., 60000.}, "multiplicity axis for the current event"}; ConfigurableAxis thnConfigAxisDeltaEta{"thnConfigAxisDeltaEta", {100, -1, 1}, "delta eta axis"}; ConfigurableAxis thnConfigAxisDeltaPhi{"thnConfigAxisDeltaPhi", {100, -1, 1}, "delta phi axis"}; - Configurable useCent{"useCent", 0, "flag to enable usage of centrality instead of multiplicity as axis."}; + Configurable useCent{"useCent", false, "flag to enable usage of centrality instead of multiplicity as axis."}; struct : ConfigurableGroup { std::string prefix = "conversiontagging"; @@ -241,14 +259,14 @@ struct EmcalPhotonMcTask { SliceCache cache; - using EMCalPhotons = soa::Join; + using EMCalPhotons = soa::Join; using Colls = soa::Join; using McColls = o2::soa::Join; using McParticles = EMMCParticles; - PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; + PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; PresliceOptional perEMCClusterMT = o2::aod::mintm::minClusterId; PresliceOptional perEMCClusterMS = o2::aod::mintm::minClusterId; @@ -346,9 +364,12 @@ struct EmcalPhotonMcTask { hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonElectronSamePi0) + 1, "PhotonElectronSamePi0"); hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonElectronDiffPi0) + 1, "PhotonElectronDiffPi0"); hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonElectronOnePi0) + 1, "PhotonElectronOnePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonElectronBS) + 1, "PhotonElectronBS"); hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::ElectronPairSamePi0) + 1, "ElectronPairSamePi0"); hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::ElectronPairDiffPi0) + 1, "ElectronPairDiffPi0"); hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::ElectronPairOnePi0) + 1, "ElectronPairOnePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::SplitPhotonCluster) + 1, "SplitPhotonCluster"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::SplitLeptonCluster) + 1, "SplitLeptonCluster"); hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::Background) + 1, "Background"); auto hPi0BothResolvedLost = registry.add("EMCal/hPi0BothResolvedLost", "Confusion matrix for conversion tagging", HistType::kTH1D, {{2, -0.5, 1.5}}); @@ -366,6 +387,16 @@ struct EmcalPhotonMcTask { hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(5, "#gamma"); mRandGen.seed(bkgPrescaleSeed.value); + + if (classPrescale.value.size() != kTruthClassNames.size()) { + LOG(fatal) << "classPrescale has " << classPrescale.value.size() << " entries, " + << "but TruthClass has " << kTruthClassNames.size() << " members -- update classPrescale!"; + } + + LOG(info) << "=== classPrescale configuration ==="; + for (size_t i = 0; i < kTruthClassNames.size(); ++i) { + LOG(info) << " [" << i << "] " << kTruthClassNames[i] << " -> prescale = " << classPrescale.value[i]; + } }; // end init template @@ -522,7 +553,7 @@ struct EmcalPhotonMcTask { ROOT::Math::XYZVector nRef = u.Cross(zAxis); // normal to the plane containing u and z float phiV = PhiVUndefined; // sentinel for degenerate geometry - if (nDecay.R() > 1e-6f && nRef.R() > 1e-6f) { + if (nDecay.R() > Epsilon && nRef.R() > Epsilon) { float cosPhiV = static_cast(nDecay.Unit().Dot(nRef.Unit())); cosPhiV = std::clamp(cosPhiV, -1.f, 1.f); phiV = std::acos(cosPhiV); @@ -547,28 +578,50 @@ struct EmcalPhotonMcTask { mcCluster1.setCursor(g1.emmcparticleIds()[0]); mcCluster2.setCursor(g2.emmcparticleIds()[0]); - bool areFromSamePi0 = false; // both clusters are from same pi0 or eta - bool areConversionLegs = false; // both clusters are e+ + e- from one photon + bool areFromSamePi0 = false; + bool areConversionLegs = false; + bool areSplitPhotonCluster = false; + bool areSplitLeptonCluster = false; + bool arePhotonElectronBS = false; auto c1 = classifyCluster(g1, mcCluster1, mcClusterLooper, mcClusterLooper2, mcParticles); auto c2 = classifyCluster(g2, mcCluster2, mcClusterLooper, mcClusterLooper2, mcParticles); - if (c1.isFromConv && c2.isFromConv && c1.convMotherId == c2.convMotherId) { + // split-cluster check MUST run first and take priority over everything else -- + // if both clusters share the same dominant MC particle, this is one physical + // shower reconstructed as two clusters, not a genuine pair of anything. + const bool isSameDominantParticle = (g1.emmcparticleIds()[0] == g2.emmcparticleIds()[0]); + if (isSameDominantParticle) { + if (c1.isPhoton) { + areSplitPhotonCluster = true; + } else if (c1.isLepton) { + areSplitLeptonCluster = true; + } + } + + // if they are not a split cluster check for proper conversion pair + if (!isSameDominantParticle && c1.isFromConv && c2.isFromConv && c1.convMotherId == c2.convMotherId) { emcFlagsFromTrueConversion.set(g1.globalIndex()); emcFlagsFromTrueConversion.set(g2.globalIndex()); areConversionLegs = true; } - if (c1.isFromPi0 && c2.isFromPi0) { - // set the cursors to the photonId + // if they are not a split cluster check for neutral meson connection + if (!isSameDominantParticle && c1.isFromPi0 && c2.isFromPi0) { mcPhoton1.setCursor(c1.photonId); mcPhoton2.setCursor(c2.photonId); mcMother.setCursor(mcPhoton1.mothersIds()[0]); if (mcMother.producedByGenerator()) { if (c1.photonId == c2.photonId) { - areFromSamePi0 = true; - emcFlagsFromTrueMesonSameGamma.set(g1.globalIndex()); - emcFlagsFromTrueMesonSameGamma.set(g2.globalIndex()); + // bremsstrahlung: one side is a photon born from the other side's lepton lineage + const bool photonIsBS = (c1.isPhoton && c1.isFromBremsstrahlung) || (c2.isPhoton && c2.isFromBremsstrahlung); + if (photonIsBS && ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton))) { + arePhotonElectronBS = true; + } else { + areFromSamePi0 = true; + emcFlagsFromTrueMesonSameGamma.set(g1.globalIndex()); + emcFlagsFromTrueMesonSameGamma.set(g2.globalIndex()); + } } else if (mcPhoton1.mothersIds()[0] == mcPhoton2.mothersIds()[0]) { areFromSamePi0 = true; emcFlagsFromTrueMeson.set(g1.globalIndex()); @@ -576,34 +629,39 @@ struct EmcalPhotonMcTask { } } } + bTruthLabel = static_cast(TruthClass::Background); - if (areConversionLegs) { + if (areSplitPhotonCluster) { + bTruthLabel = static_cast(TruthClass::SplitPhotonCluster); + } else if (areSplitLeptonCluster) { + bTruthLabel = static_cast(TruthClass::SplitLeptonCluster); + } else if (areConversionLegs) { bTruthLabel = static_cast(TruthClass::Conversion); - } else { - if (areFromSamePi0) { - if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { - bTruthLabel = static_cast(TruthClass::PhotonElectronSamePi0); - } else if (c1.isPhoton && c2.isPhoton) { - bTruthLabel = static_cast(TruthClass::PhotonPairSamePi0); - } else if (c1.isLepton && c2.isLepton) { - bTruthLabel = static_cast(TruthClass::ElectronPairSamePi0); - } - } else if (c1.isFromPi0 && c2.isFromPi0) { - if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { - bTruthLabel = static_cast(TruthClass::PhotonElectronDiffPi0); - } else if (c1.isPhoton && c2.isPhoton) { - bTruthLabel = static_cast(TruthClass::PhotonPairDiffPi0); - } else if (c1.isLepton && c2.isLepton) { - bTruthLabel = static_cast(TruthClass::ElectronPairDiffPi0); - } - } else if ((c1.isFromPi0 && !c2.isFromPi0) || (!c1.isFromPi0 && c2.isFromPi0)) { - if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { - bTruthLabel = static_cast(TruthClass::PhotonElectronOnePi0); - } else if (c1.isPhoton && c2.isPhoton) { - bTruthLabel = static_cast(TruthClass::PhotonPairOnePi0); - } else if (c1.isLepton && c2.isLepton) { - bTruthLabel = static_cast(TruthClass::ElectronPairOnePi0); - } + } else if (arePhotonElectronBS) { + bTruthLabel = static_cast(TruthClass::PhotonElectronBS); + } else if (areFromSamePi0) { + if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { + bTruthLabel = static_cast(TruthClass::PhotonElectronSamePi0); + } else if (c1.isPhoton && c2.isPhoton) { + bTruthLabel = static_cast(TruthClass::PhotonPairSamePi0); + } else if (c1.isLepton && c2.isLepton) { + bTruthLabel = static_cast(TruthClass::ElectronPairSamePi0); + } + } else if (c1.isFromPi0 && c2.isFromPi0) { + if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { + bTruthLabel = static_cast(TruthClass::PhotonElectronDiffPi0); + } else if (c1.isPhoton && c2.isPhoton) { + bTruthLabel = static_cast(TruthClass::PhotonPairDiffPi0); + } else if (c1.isLepton && c2.isLepton) { + bTruthLabel = static_cast(TruthClass::ElectronPairDiffPi0); + } + } else if ((c1.isFromPi0 && !c2.isFromPi0) || (!c1.isFromPi0 && c2.isFromPi0)) { + if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { + bTruthLabel = static_cast(TruthClass::PhotonElectronOnePi0); + } else if (c1.isPhoton && c2.isPhoton) { + bTruthLabel = static_cast(TruthClass::PhotonPairOnePi0); + } else if (c1.isLepton && c2.isLepton) { + bTruthLabel = static_cast(TruthClass::ElectronPairOnePi0); } } @@ -634,7 +692,7 @@ struct EmcalPhotonMcTask { } mcCluster1.setCursor(cluster.emmcparticleIds()[0]); - int photonid1 = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster1, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta}); + int photonid1 = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster1, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta, Pdg::kOmega, Pdg::kEtaPrime}); int motherId = -1; if (photonid1 >= 0) { mcPhoton1.setCursor(photonid1); diff --git a/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx b/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx index 0918ba11d8b..65b3ab804df 100644 --- a/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx +++ b/PWGEM/PhotonMeson/Tasks/taskFlowReso.cxx @@ -51,7 +51,7 @@ using namespace o2::aod::pwgem::photon; enum QvecEstimator { FT0M = 0, - FT0A = 1, + FT0A, FT0C, TPCPos, TPCNeg, @@ -61,7 +61,7 @@ enum QvecEstimator { enum CentralityEstimator { None = 0, - CFT0A = 1, + CFT0A, CFT0C, CFT0M, NCentralityEstimators @@ -383,7 +383,7 @@ struct TaskFlowReso { // no selection on the centrality is applied on purpose to allow for the resolution study in post-processing return; } - if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { + if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange()) || !(collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { return; } float cent = getCentrality(collision); @@ -531,7 +531,7 @@ struct TaskFlowReso { }; // End struct TaskFlowReso -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(context)}; } diff --git a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx index c8a097a79cf..af98c86de85 100644 --- a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx @@ -173,6 +173,7 @@ struct TaskPi0FlowEMC { Configurable cfgEMCUseTM{"cfgEMCUseTM", false, "flag to use EMCal track matching cut or not"}; Configurable emcUseSecondaryTM{"emcUseSecondaryTM", false, "flag to use EMCal secondary track matching cut or not"}; Configurable cfgEnableQA{"cfgEnableQA", false, "flag to turn QA plots on/off"}; + Configurable separateEMCalDCal{"separateEMCalDCal", false, "flag to only pair EMCal with EMCal and DCal with DCal clusters"}; } emccuts; V0PhotonCut fV0PhotonCut; @@ -252,6 +253,8 @@ struct TaskPi0FlowEMC { int runNow = 0; int runBefore = -1; + static constexpr float MaxPhiEMCal = 3.5f; + // Filter clusterFilter = aod::skimmedcluster::time >= emccuts.cfgEMCminTime && aod::skimmedcluster::time <= emccuts.cfgEMCmaxTime && aod::skimmedcluster::m02 >= emccuts.cfgEMCminM02 && aod::skimmedcluster::m02 <= emccuts.cfgEMCmaxM02 && aod::skimmedcluster::e >= emccuts.cfgEMCminE; Filter collisionFilter = (nabs(aod::collision::posZ) <= eventcuts.cfgZvtxMax) && (aod::evsel::ft0cOccupancyInTimeRange <= eventcuts.cfgFT0COccupancyMax) && (aod::evsel::ft0cOccupancyInTimeRange >= eventcuts.cfgFT0COccupancyMin); // using FilteredEMCalPhotons = soa::Filtered>; @@ -261,10 +264,13 @@ struct TaskPi0FlowEMC { using CollsWithQvecs = soa::Join; using Colls = soa::Join; + Partition emcalPhotons = aod::mincluster::storedPhi < std::lround(MaxPhiEMCal * emcdownscaling::downscalingFactors[emcdownscaling::kPhi]); + Partition dcalPhotons = aod::mincluster::storedPhi >= std::lround(MaxPhiEMCal * emcdownscaling::downscalingFactors[emcdownscaling::kPhi]); + static constexpr std::size_t NQVecEntries = 6; - PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; - PresliceOptional perCollisionPCM = aod::v0photonkf::pmeventId; + PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; + PresliceOptional perCollisionPCM = aod::v0photonkf::pmeventId; PresliceOptional perEMCClusterMT = o2::aod::mintm::minClusterId; PresliceOptional perEMCClusterMS = o2::aod::mintm::minClusterId; @@ -482,6 +488,13 @@ struct TaskPi0FlowEMC { }; // end init + /// \brief Check whether a photon (by its phi) falls in the EMCal or DCal acceptance + /// \param phi azimuthal angle of the photon + static bool isEMCalRegion(float phi) + { + return phi < MaxPhiEMCal; + } + /// Change radians to degree /// \param angle in radians /// \return angle in degree @@ -1048,7 +1061,7 @@ struct TaskPi0FlowEMC { continue; } if (rotationConfig.cfgDoRotation.value && nColl % rotationConfig.cfgDownsampling == 0) { - rotationBackground(vMeson, v1, v2, photons1, g1.globalIndex(), g2.globalIndex(), collision); + rotationBackground(vMeson, v1, v2, photons1, g1.globalIndex(), g2.globalIndex(), collision); } if (thnConfigAxisInvMass.value[1] > vMeson.M() || thnConfigAxisInvMass.value.back() < vMeson.M()) { registry.fill(HIST("hMesonCuts"), 3); @@ -1094,6 +1107,8 @@ struct TaskPi0FlowEMC { } auto photonsPerCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); + auto emcalPhotonsPerCollision = emcalPhotons.sliceBy(perCollisionEMC, collision.globalIndex()); + auto dcalPhotonsPerCollision = dcalPhotons.sliceBy(perCollisionEMC, collision.globalIndex()); if (emccuts.cfgEnableQA.value) { for (const auto& photon : photonsPerCollision) { @@ -1109,7 +1124,12 @@ struct TaskPi0FlowEMC { registry.fill(HIST("clusterQA/hClusterEtaPhiAfter"), photon.phi(), photon.eta()); // after cuts } } - runPairingLoop(collision, photonsPerCollision, photonsPerCollision, flags, flags); + if (emccuts.separateEMCalDCal.value) { + runPairingLoop(collision, emcalPhotonsPerCollision, emcalPhotonsPerCollision, flags, flags); + runPairingLoop(collision, dcalPhotonsPerCollision, dcalPhotonsPerCollision, flags, flags); + } else { + runPairingLoop(collision, photonsPerCollision, photonsPerCollision, flags, flags); + } if (rotationConfig.cfgDoRotation.value) { if (nColl % rotationConfig.cfgDownsampling == 0) { nColl = 1; // reset counter @@ -1164,6 +1184,10 @@ struct TaskPi0FlowEMC { if (!(flags.test(g1.globalIndex())) || !(flags.test(g2.globalIndex()))) { continue; } + if (emccuts.separateEMCalDCal.value && isEMCalRegion(g1.phi()) != isEMCalRegion(g2.phi())) { + continue; // only pair EMCal-EMCal or DCal-DCal + } + // Cut edge clusters away, similar to rotation method to ensure same acceptance is used if (cfgDistanceToEdge.value > 0) { if (checkEtaPhi1D(g1.eta(), RecoDecay::constrainAngle(g1.phi())) >= cfgEMCalMapLevelBackground.value) { diff --git a/PWGEM/PhotonMeson/Tasks/testTaskEmc.cxx b/PWGEM/PhotonMeson/Tasks/testTaskEmc.cxx index c10b30fc3a6..ad2b5594c15 100644 --- a/PWGEM/PhotonMeson/Tasks/testTaskEmc.cxx +++ b/PWGEM/PhotonMeson/Tasks/testTaskEmc.cxx @@ -172,7 +172,7 @@ struct TestTaskEmc { PROCESS_SWITCH(TestTaskEmc, processEMCalCalib, "Process EMCal calibration same event", true); }; // End struct TestTaskEmc -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(context)}; } diff --git a/PWGEM/PhotonMeson/Utils/MCUtilities.h b/PWGEM/PhotonMeson/Utils/MCUtilities.h index 94fceb68445..60557218784 100644 --- a/PWGEM/PhotonMeson/Utils/MCUtilities.h +++ b/PWGEM/PhotonMeson/Utils/MCUtilities.h @@ -315,6 +315,24 @@ bool isMotherPDG(const T& mcparticle, T& mcparticleWorking, const int motherPDG, return isMotherPDG(mcparticleWorking, mcparticleWorking, motherPDG, depth - 1); } +//_______________________________________________________________________ +/// \brief Check if given particle is from Bremsstrahlung +/// \param mcCursor iterator of mcparticle +/// \param iter shared iterator used to walk to the mother +template +bool isFromBremsstrahlung(TIter const& mcCursor, TIter& iter) +{ + if (!mcCursor.has_mothers()) { + return false; + } + if (mcCursor.pdgCode() != PDG_t::kGamma) { + return false; // only a photon can itself be a bremsstrahlung emission + } + const int motherId = mcCursor.mothersIds()[0]; + iter.setCursor(motherId); + return std::abs(iter.pdgCode()) == PDG_t::kElectron; +} + //_______________________________________________________________________ /// \brief Go up the decay chain of a mcparticle looking for a mother with the given pdg codes, if found return id else -1 /// E.g. if electron cluster is coming from a photon return true, if primary electron return false From 4d0c041832c0db8fedf38acf877844a126f367b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrea=20Tavira=20Garc=C3=ADa?= <118979672+atavirag@users.noreply.github.com> Date: Fri, 31 Jul 2026 15:41:32 +0200 Subject: [PATCH 61/71] [PWGHF] Add event mixing on data in correlatorDMesonPairs.cxx (#17214) Co-authored-by: ALICE Action Bot --- PWGHF/HFC/DataModel/DMesonPairsTables.h | 48 +++ .../TableProducer/correlatorDMesonPairs.cxx | 282 +++++++++++++++--- 2 files changed, 288 insertions(+), 42 deletions(-) diff --git a/PWGHF/HFC/DataModel/DMesonPairsTables.h b/PWGHF/HFC/DataModel/DMesonPairsTables.h index 35e12760919..67a352a46ae 100644 --- a/PWGHF/HFC/DataModel/DMesonPairsTables.h +++ b/PWGHF/HFC/DataModel/DMesonPairsTables.h @@ -32,6 +32,8 @@ DECLARE_SOA_COLUMN(PtCand1, ptCand1, float); //! Transverse momentum of first DECLARE_SOA_COLUMN(PtCand2, ptCand2, float); //! Transverse momentum of second candidate DECLARE_SOA_COLUMN(YCand1, yCand1, float); //! Rapidity of first candidate DECLARE_SOA_COLUMN(YCand2, yCand2, float); //! Rapidity of second candidate +DECLARE_SOA_COLUMN(EtaCand1, etaCand1, float); //! Azimuthal angle of first candidate +DECLARE_SOA_COLUMN(EtaCand2, etaCand2, float); //! Azimuthal angle of second candidate DECLARE_SOA_COLUMN(PhiCand1, phiCand1, float); //! Azimuthal angle of first candidate DECLARE_SOA_COLUMN(PhiCand2, phiCand2, float); //! Azimuthal angle of second candidate // Invariant mass @@ -55,12 +57,15 @@ DECLARE_SOA_COLUMN(MlProbD0barCand2, mlProbD0barCand2, std::vector); //! } // namespace hf_correlation_d_meson_pair // Definition of the D meson pair table. Contains the info needed at Data level. +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define DECLARE_DMESON_PAIR_TABLE(_pair_type_, _marker_value_, _description_) \ DECLARE_SOA_TABLE(_pair_type_, "AOD", _description_, o2::soa::Marker<_marker_value_>, \ hf_correlation_d_meson_pair::PtCand1, \ hf_correlation_d_meson_pair::PtCand2, \ hf_correlation_d_meson_pair::YCand1, \ hf_correlation_d_meson_pair::YCand2, \ + hf_correlation_d_meson_pair::EtaCand1, \ + hf_correlation_d_meson_pair::EtaCand2, \ hf_correlation_d_meson_pair::PhiCand1, \ hf_correlation_d_meson_pair::PhiCand2, \ hf_correlation_d_meson_pair::MDCand1, \ @@ -71,6 +76,7 @@ DECLARE_SOA_COLUMN(MlProbD0barCand2, mlProbD0barCand2, std::vector); //! hf_correlation_d_meson_pair::CandidateType1, \ hf_correlation_d_meson_pair::CandidateType2); // Definition of the D meson pair table with info at MC level. +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define DECLARE_DMESON_PAIR_MCINFO_TABLE(_pair_type_, _marker_value_, _description_) \ DECLARE_SOA_TABLE(_pair_type_, "AOD", _description_ "MCINFO", o2::soa::Marker<_marker_value_>, \ hf_correlation_d_meson_pair::Origin1, \ @@ -78,6 +84,7 @@ DECLARE_SOA_COLUMN(MlProbD0barCand2, mlProbD0barCand2, std::vector); //! hf_correlation_d_meson_pair::MatchedMc1, \ hf_correlation_d_meson_pair::MatchedMc2); // Definition of the table with the ML info of the D meson pair. +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define DECLARE_DMESON_PAIR_MLINFO_TABLE(_pair_type_, _marker_value_, _description_) \ DECLARE_SOA_TABLE(_pair_type_, "AOD", _description_ "ML", o2::soa::Marker<_marker_value_>, \ hf_correlation_d_meson_pair::MlProbD0Cand1, \ @@ -93,6 +100,47 @@ DECLARE_DMESON_PAIR_MLINFO_TABLE(D0PairMl, 1, "D0PAIR"); //! D0 pairs ML Inf DECLARE_DMESON_PAIR_TABLE(D0PairMcGen, 2, "D0PAIRGEN"); //! D0 pairs MC Gen Kinematic Info DECLARE_DMESON_PAIR_MCINFO_TABLE(D0PairMcGenInfo, 2, "D0PAIRGEN"); //! D0 pairs MC Gen Info +namespace hf_correlation_d_meson_had +{ +// D candidate +DECLARE_SOA_COLUMN(PtD, ptD, float); //! Transverse momentum of the D meson +DECLARE_SOA_COLUMN(YD, yD, float); //! Rapidity of the D meson +DECLARE_SOA_COLUMN(EtaD, etaD, float); //! Pseudorapidity of the D meson +DECLARE_SOA_COLUMN(PhiD, phiD, float); //! Azimuthal angle of the D meson +DECLARE_SOA_COLUMN(MD, mD, float); //! Invariant mass of the D meson +DECLARE_SOA_COLUMN(PoolBinD, poolBinD, int); //! Pool bin of the D meson +DECLARE_SOA_COLUMN(GIndexColD, gIndexColD, int); //! G-index column of the D meson +DECLARE_SOA_COLUMN(TimestampD, timestampD, int64_t); //! Timestamp of the D meson + +// Associated hadron +DECLARE_SOA_COLUMN(PtHad, ptHad, float); //! Transverse momentum of the associated hadron +DECLARE_SOA_COLUMN(YHad, yHad, float); //! Rapidity of the associated hadron +DECLARE_SOA_COLUMN(EtaHad, etaHad, float); //! Pseudorapidity of the associated hadron +DECLARE_SOA_COLUMN(PhiHad, phiHad, float); //! Azimuthal angle of the associated hadron +DECLARE_SOA_COLUMN(PoolBinHad, poolBinHad, int); //! Pool bin of the associated hadron +DECLARE_SOA_COLUMN(GIndexColHad, gIndexColHad, int); //! G-index column of the associated hadron +DECLARE_SOA_COLUMN(TimestampHad, timestampHad, int64_t); //! Timestamp of the associated hadron + +} // namespace hf_correlation_d_meson_had + +// Definition of the D meson table for D-had correlations. Contains the info needed at Data level. +DECLARE_SOA_TABLE(DMesonCandInfo, "AOD", "DMESONCANDINFO", + hf_correlation_d_meson_had::PtD, + hf_correlation_d_meson_had::EtaD, + hf_correlation_d_meson_had::PhiD, + hf_correlation_d_meson_had::MD, + hf_correlation_d_meson_had::PoolBinD, + hf_correlation_d_meson_had::GIndexColD, + hf_correlation_d_meson_had::TimestampD); + +DECLARE_SOA_TABLE(AssocHadInfo, "AOD", "ASSOCHADINFO", + hf_correlation_d_meson_had::PtHad, + hf_correlation_d_meson_had::EtaHad, + hf_correlation_d_meson_had::PhiHad, + hf_correlation_d_meson_had::PoolBinHad, + hf_correlation_d_meson_had::GIndexColHad, + hf_correlation_d_meson_had::TimestampHad); + } // namespace o2::aod #endif // PWGHF_HFC_DATAMODEL_DMESONPAIRSTABLES_H_ diff --git a/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx b/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx index 77e43224d52..cb91b184e64 100644 --- a/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx @@ -18,11 +18,18 @@ #include "PWGHF/Core/HfHelper.h" #include "PWGHF/Core/HfMlResponseD0ToKPi.h" #include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/HFC/DataModel/CorrelationTables.h" #include "PWGHF/HFC/DataModel/DMesonPairsTables.h" +#include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" #include #include @@ -32,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +51,8 @@ #include +#include +#include #include #include #include @@ -71,6 +81,57 @@ enum PairTypeOfSelMassSel { } // namespace using McParticlesPlus2Prong = soa::Join; +// definition of ME variables +using BinningType = ColumnBinningPolicy>; + +struct HfCorrelatorD0HadronsSelection { + Produces d0Sel; + + Configurable useSel8{"useSel8", true, "Flag for applying sel8 for collision selection"}; + Configurable selNoSameBunchPileUpColl{"selNoSameBunchPileUpColl", true, "Flag for rejecting the collisions associated with the same bunch crossing"}; + Configurable doSelD0Collision{"doSelD0Collision", true, "Select collisions with at least one D0"}; + Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; + Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; + Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; + Configurable ptCandMin{"ptCandMin", 1., "min. cand. pT"}; + + SliceCache cache; + + using SelCollisions = soa::Join; + using CandidatesD0Data = soa::Join; + + Partition selectedD0Candidates = + aod::hf_sel_candidate_d0::isSelD0 >= 1 || + aod::hf_sel_candidate_d0::isSelD0bar >= 1; + + // Process function to select collisions with at least one D0 candidate passing the selection criteria + void processD0SelectionData(SelCollisions::iterator const& collision, + CandidatesD0Data const&) + { + bool isSel8 = !useSel8 || collision.sel8(); + bool isNoSameBunchPileUp = !selNoSameBunchPileUpColl || + collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + bool isD0Found = !doSelD0Collision; + + if (doSelD0Collision) { + auto grouped = selectedD0Candidates.sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + for (const auto& candidate : grouped) { + + if (candidate.isSelD0() < selectionFlagD0 && candidate.isSelD0bar() < selectionFlagD0bar) { + continue; + } + if (std::abs(HfHelper::yD0(candidate)) > yCandMax || candidate.pt() < ptCandMin) { + continue; + } + isD0Found = true; + break; + } + } + + d0Sel(isD0Found && isSel8 && isNoSameBunchPileUp); + } + PROCESS_SWITCH(HfCorrelatorD0HadronsSelection, processD0SelectionData, "Process D0 Selection Data", true); +}; struct HfCorrelatorDMesonPairs { @@ -80,23 +141,38 @@ struct HfCorrelatorDMesonPairs { Produces entryD0PairMcGen; Produces entryD0PairMcGenInfo; + // Tables for event mixing + Produces entryDMesonCand; + Produces entryAssocHad; + Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; Configurable selectionFlagHf{"selectionFlagHf", 1, "Selection Flag for HF flagged candidates"}; - Configurable yCandMax{"yCandMax", 0.8, "maxmum |y| of D0 candidates"}; + Configurable yCandMax{"yCandMax", 0.8, "maximum |y| of D0 candidates"}; Configurable ptCandMin{"ptCandMin", -1., "minimum pT of D0 candidates"}; Configurable> binsPt{"binsPt", std::vector{o2::analysis::hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits for candidate mass plots"}; Configurable selectSignalRegionOnly{"selectSignalRegionOnly", false, "only use events close to PDG peak"}; Configurable massCut{"massCut", 0.05, "Maximum deviation from PDG peak allowed for signal region"}; - Configurable daughterTracksCutFlag{"daughterTracksCutFlag", false, "Flag to add cut on daughter tracks"}; Configurable removeAmbiguous{"removeAmbiguous", false, "Flag to remove ambiguous candidates"}; Configurable ptMaxRemoveAmbiguous{"ptMaxRemoveAmbiguous", 5.0, "Max. pT to remove the ambiguous candidates"}; + // Event mixing configurables + Configurable applyMixedEvent{"applyMixedEvent", false, "Flag to make the event mixing"}; + Configurable daughterTracksCutFlag{"daughterTracksCutFlag", false, "Flag to add cut on daughter tracks"}; + Configurable> binsPtHadron{"binsPtHadron", std::vector{0.3, 2., 4., 8., 12., 50.}, "pT bin limits for assoc particle"}; + Configurable etaTrackMax{"etaTrackMax", 0.8, "max. eta of tracks"}; + Configurable dcaXYTrackMax{"dcaXYTrackMax", 1., "max. DCA_xy of tracks"}; + Configurable dcaZTrackMax{"dcaZTrackMax", 1., "max. DCA_z of tracks"}; + Configurable ptTrackMin{"ptTrackMin", 0.3, "min. track pT"}; + Configurable ptTrackMax{"ptTrackMax", 100., "max. track pT"}; + Configurable multMin{"multMin", 0., "minimum multiplicity accepted"}; + Configurable multMax{"multMax", 10000., "maximum multiplicity accepted"}; + // ML inference Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; Configurable> binsPtMl{"binsPtMl", std::vector{hf_cuts_ml::vecBinsPt}, "pT bin limits for ML application"}; Configurable> cutDirMl{"cutDirMl", std::vector{hf_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; - Configurable> cutsMl{"cutsMl", {hf_cuts_ml::Cuts[0], hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable> cutsMl{"cutsMl", {static_cast(hf_cuts_ml::Cuts[0]), hf_cuts_ml::NBinsPt, hf_cuts_ml::NCutScores, hf_cuts_ml::labelsPt, hf_cuts_ml::labelsCutScore}, "ML selections per pT bin"}; Configurable nClassesMl{"nClassesMl", static_cast(hf_cuts_ml::NCutScores), "Number of classes in ML model"}; Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; @@ -108,7 +184,20 @@ struct HfCorrelatorDMesonPairs { Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; SliceCache cache; + + using SelCollisionsWithD0 = soa::Filtered>; + using CandidatesD0Data = soa::Join; + + using FilteredD0Candidates = soa::Filtered; + using TracksData = soa::Filtered>; // trackFilter applied + + Filter collisionFilter = aod::hf_selection_dmeson_collision::dmesonSel == true; + Filter d0Filter = (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK))) != static_cast(0); + Filter trackFilter = (nabs(aod::track::eta) < etaTrackMax) && (nabs(aod::track::pt) > ptTrackMin) && (nabs(aod::track::dcaXY) < dcaXYTrackMax) && (nabs(aod::track::dcaZ) < dcaZTrackMax); + Preslice perCol2Prong = aod::hf_cand::collisionId; + Preslice candsD0PerCollision = aod::hf_cand::collisionId; + Preslice trackIndicesPerCollision = aod::track::collisionId; o2::analysis::HfMlResponseD0ToKPi hfMlResponse; o2::ccdb::CcdbApi ccdbApi; @@ -141,6 +230,13 @@ struct HfCorrelatorDMesonPairs { HistogramConfigSpec hTH2Pid{HistType::kTH2F, {{500, 0., 10.}, {400, -20., 20.}}}; HistogramConfigSpec hTH3PtVsYVsNContrib{HistType::kTH3F, {{360, 0., 36.}, {20, -1., 1.}, {120, -0.5, 119.5}}}; + ConfigurableAxis binsMultiplicity{"binsMultiplicity", {VARIABLE_WIDTH, 0.0f, 2000.0f, 6000.0f, 100000.0f}, "Mixing bins - multiplicity"}; + ConfigurableAxis binsZVtx{"binsZVtx", {VARIABLE_WIDTH, -10.0f, -2.5f, 2.5f, 10.0f}, "Mixing bins - z-vertex"}; + ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; + ConfigurableAxis binsMultFT0M{"binsMultFT0M", {600, 0., 6000.}, "Multiplicity as FT0M signal amplitude"}; + ConfigurableAxis binsDcaXY{"binsDcaXY", {128, -0.2, 0.2}, "DCA xy"}; + BinningType corrBinning{{binsZVtx, binsMultiplicity}, true}; + HistogramRegistry registry{ "registry", {{"hPtCand", "D meson candidates;candidate #it{p}_{T} (GeV/#it{c});entries", hTH1Pt}, @@ -188,9 +284,9 @@ struct HfCorrelatorDMesonPairs { hfMlResponse.init(); } - auto vbins = (std::vector)binsPt; - constexpr int kNBinsSelStatus = 25; - std::string labels[kNBinsSelStatus]; + auto vbins = static_cast>(binsPt); + constexpr int NBinsSelStatus = 25; + std::array labels; labels[0] = "total # of Selected pairs"; // Cand1 analysis @@ -222,17 +318,17 @@ struct HfCorrelatorDMesonPairs { labels[23] = "# of True D+Dbar Pairs"; labels[24] = "# of True Dbar+D Pairs"; - AxisSpec const axisSelStatus = {kNBinsSelStatus, 0.5, kNBinsSelStatus + 0.5, ""}; + AxisSpec const axisSelStatus = {NBinsSelStatus, 0.5, NBinsSelStatus + 0.5, ""}; registry.add("hSelectionStatus", "D Meson candidates;selection status;entries", HistType::kTH1F, {axisSelStatus}); registry.add("hSelectionStatusMcGen", "D Meson candidates MC Gen;selection status;entries", HistType::kTH1F, {axisSelStatus}); - for (int iBin = 0; iBin < kNBinsSelStatus; iBin++) { + for (int iBin = 0; iBin < NBinsSelStatus; iBin++) { registry.get(HIST("hSelectionStatus"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); registry.get(HIST("hSelectionStatusMcGen"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); } - constexpr int kNBinsMatching = 8; - std::string labelsMatching[kNBinsMatching]; + constexpr int NBinsMatching = 8; + std::array labelsMatching; // Cand1 analysis labelsMatching[0] = "total # of Cand 1"; labelsMatching[1] = "# of matched D Cand 1"; @@ -244,17 +340,17 @@ struct HfCorrelatorDMesonPairs { labelsMatching[6] = "# of matched Dbar Cand 2"; labelsMatching[7] = "# of unmatched Cand 2"; - AxisSpec const axisMatching = {kNBinsMatching, 0.5, kNBinsMatching + 0.5, ""}; + AxisSpec const axisMatching = {NBinsMatching, 0.5, NBinsMatching + 0.5, ""}; registry.add("hMatchingMcRec", "D Meson candidates; MC matching status;entries", HistType::kTH1F, {axisMatching}); registry.add("hMatchingMcGen", "D Meson candidates; MC matching status;entries", HistType::kTH1F, {axisMatching}); - for (int iBin = 0; iBin < kNBinsMatching; iBin++) { + for (int iBin = 0; iBin < NBinsMatching; iBin++) { registry.get(HIST("hMatchingMcRec"))->GetXaxis()->SetBinLabel(iBin + 1, labelsMatching[iBin].data()); registry.get(HIST("hMatchingMcGen"))->GetXaxis()->SetBinLabel(iBin + 1, labelsMatching[iBin].data()); } - constexpr int kNBinsSinglePart = 6; - std::string labelsSinglePart[kNBinsSinglePart]; + constexpr int NBinsSinglePart = 6; + std::array labelsSinglePart; // Candidate analysis labelsSinglePart[0] = "total # of Candidates"; labelsSinglePart[1] = "# of selected D"; @@ -263,11 +359,11 @@ struct HfCorrelatorDMesonPairs { labelsSinglePart[4] = "# of true D"; labelsSinglePart[5] = "# of true Dbar"; - AxisSpec const axisSinglePart = {kNBinsSinglePart, 0.5, kNBinsSinglePart + 0.5, ""}; + AxisSpec const axisSinglePart = {NBinsSinglePart, 0.5, NBinsSinglePart + 0.5, ""}; registry.add("hStatusSinglePart", "D Meson candidates; MC matching status;entries", HistType::kTH1F, {axisSinglePart}); registry.add("hStatusSinglePartMcGen", "D Meson candidates; MC matching status;entries", HistType::kTH1F, {axisSinglePart}); - for (int iBin = 0; iBin < kNBinsSinglePart; iBin++) { + for (int iBin = 0; iBin < NBinsSinglePart; iBin++) { registry.get(HIST("hStatusSinglePart"))->GetXaxis()->SetBinLabel(iBin + 1, labelsSinglePart[iBin].data()); registry.get(HIST("hStatusSinglePartMcGen"))->GetXaxis()->SetBinLabel(iBin + 1, labelsSinglePart[iBin].data()); } @@ -309,6 +405,24 @@ struct HfCorrelatorDMesonPairs { registry.add("hnDMeson", "Thn for D0 candidates", HistType::kTHnSparseD, axes); registry.get(HIST("hnDMeson"))->Sumw2(); } + + // Event mixing + AxisSpec axisPtHadron = {(std::vector)binsPtHadron, "#it{p}_{T} Hadron (GeV/#it{c})"}; + AxisSpec const axisMultiplicity = {binsMultiplicity, "Multiplicity"}; + AxisSpec axisMultFT0M = {binsMultFT0M, "MultiplicityFT0M"}; + AxisSpec const axisPosZ = {binsZVtx, "PosZ"}; + AxisSpec const axisPoolBin = {binsPoolBin, "PoolBin"}; + AxisSpec const axisDcaXY = {binsDcaXY, "DCA xy"}; + + if (applyMixedEvent) { + registry.add("hMultiplicityPreSelection", "multiplicity prior to selection;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}); + registry.add("hMultiplicity", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}); + registry.add("hMultFT0M", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}); + registry.add("hZvtx", "z vertex;z vertex;entries", {HistType::kTH1F, {{200, -20., 20.}}}); + registry.add("hD0Bin", "D0 selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{9, 0., 9.}}}); + registry.add("hTracksBin", "Tracks selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{9, 0., 9.}}}); + registry.add("hDcaXYVsPt", "DCA xy vs pt", {HistType::kTH2F, {{axisDcaXY}, {axisPtHadron}}}); + } } /// Sets bits to select candidate type for D0 @@ -408,12 +522,12 @@ struct HfCorrelatorDMesonPairs { } /// Fill counters for D0 and D0bar - /// \param selectedD0Candidates contains all D0 candidates + /// \param d0Candidates contains all D0 candidates template - void getCountersPerEvent(const T& selectedD0Candidates) + void getCountersPerEvent(const T& d0Candidates) { int nDevent = 0, nDbarevent = 0, nDDbarevent = 0, nDorDbarevent = 0; - for (const auto& candidate : selectedD0Candidates) { + for (const auto& candidate : d0Candidates) { // Get counters per event bool const isSignalD0 = std::abs(HfHelper::invMassD0ToPiK(candidate) - MassD0) < massCut; bool const isSignalD0bar = std::abs(HfHelper::invMassD0barToKPi(candidate) - MassD0Bar) < massCut; @@ -470,7 +584,7 @@ struct HfCorrelatorDMesonPairs { /// Fill selection status histogram void fillEntry(const bool& isDCand1, const bool& isDbarCand1, const bool& isDCand2, const bool& isDbarCand2, - const uint8_t& candidateType1, const uint8_t& candidateType2, float yCand1, float yCand2, float phiCand1, float phiCand2, + const uint8_t candidateType1, const uint8_t candidateType2, float yCand1, float yCand2, float etaCand1, float etaCand2, float phiCand1, float phiCand2, double ptCand1, double ptCand2, float massDCand1, float massDbarCand1, float massDCand2, float massDbarCand2) { @@ -525,7 +639,7 @@ struct HfCorrelatorDMesonPairs { } } - entryD0Pair(ptCand1, ptCand2, yCand1, yCand2, phiCand1, phiCand2, massDCand1, massDbarCand1, massDCand2, massDbarCand2, pairType, candidateType1, candidateType2); + entryD0Pair(ptCand1, ptCand2, yCand1, yCand2, etaCand1, etaCand2, phiCand1, phiCand2, massDCand1, massDbarCand1, massDCand2, massDbarCand2, pairType, candidateType1, candidateType2); } void fillMcHistos(int8_t matchedRec1, int8_t matchedRec2, int8_t isTrueDCand1, int8_t isTrueDbarCand1, int8_t isTrueDCand2, int8_t isTrueDbarCand2) @@ -571,13 +685,41 @@ struct HfCorrelatorDMesonPairs { } /// D0(bar)-D0(bar) correlation pair builder - for real data and data-like analysis (i.e. reco-level w/o matching request via MC truth) - void processData(aod::Collision const& collision, - soa::Join const& candidates, aod::Tracks const&) + void processData(SelCollisionsWithD0::iterator const& collision, + CandidatesD0Data const& candidates, TracksData const& tracks, aod::BCsWithTimestamps const&) { + + auto bc = collision.bc_as(); + int gCollisionId = collision.globalIndex(); + int64_t timeStamp = bc.timestamp(); + + int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); + + int nTracks = 0; + if (collision.numContrib() > 1) { + for (const auto& track : tracks) { + if (std::abs(track.eta()) >= etaTrackMax || std::abs(track.dcaXY()) >= dcaXYTrackMax || std::abs(track.dcaZ()) >= dcaZTrackMax) { + continue; + } + nTracks++; + } + } + if (applyMixedEvent) { + registry.fill(HIST("hMultiplicityPreSelection"), nTracks); + } + if (nTracks < multMin || nTracks > multMax) { + return; + } + if (applyMixedEvent) { + registry.fill(HIST("hMultiplicity"), nTracks); + } + + int cntD0 = 0; + for (const auto& candidate : candidates) { analysePid(candidate); } - auto selectedD0CandidatesGrouped = selectedD0Candidates->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); + auto selectedD0CandidatesGrouped = selectedD0Candidates->sliceByCached(aod::hf_cand::collisionId, gCollisionId, cache); getCountersPerEvent(selectedD0CandidatesGrouped); // protection against empty tables to be sliced if (selectedD0Candidates.size() <= 1) { @@ -594,8 +736,8 @@ struct HfCorrelatorDMesonPairs { if (ptCandMin >= 0. && candidate1.pt() < ptCandMin) { continue; } - auto prong0Cand1 = candidate1.template prong0_as(); - auto prong1Cand1 = candidate1.template prong1_as(); + auto prong0Cand1 = candidate1.template prong0_as(); + auto prong1Cand1 = candidate1.template prong1_as(); bool const isSignalD0Cand1 = std::abs(HfHelper::invMassD0ToPiK(candidate1) - MassD0) < massCut; bool const isSignalD0barCand1 = std::abs(HfHelper::invMassD0barToKPi(candidate1) - MassD0Bar) < massCut; @@ -638,6 +780,9 @@ struct HfCorrelatorDMesonPairs { registry.fill(HIST("hY"), candidate1.y(MassD0)); registry.fill(HIST("hPtCandAfterCut"), candidate1.pt()); registry.fill(HIST("hPVContrib"), collision.numContrib()); + if (applyMixedEvent) { + registry.fill(HIST("hD0Bin"), poolBin); + } if (isDCand1) { registry.fill(HIST("hMass"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt()); @@ -646,6 +791,10 @@ struct HfCorrelatorDMesonPairs { } else { registry.fill(HIST("hnDMeson"), HfHelper::invMassD0ToPiK(candidate1), candidate1.pt(), candidate1.y(MassD0), collision.numContrib(), 0, candidateType1); } + // Fill D0 table for offline event mixing + if (applyMixedEvent) { + entryDMesonCand(candidate1.pt(), candidate1.eta(), candidate1.phi(), HfHelper::invMassD0ToPiK(candidate1), poolBin, gCollisionId, timeStamp); + } } if (isDbarCand1) { registry.fill(HIST("hMass"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt()); @@ -654,8 +803,49 @@ struct HfCorrelatorDMesonPairs { } else { registry.fill(HIST("hnDMeson"), HfHelper::invMassD0barToKPi(candidate1), candidate1.pt(), candidate1.y(MassD0), collision.numContrib(), 0, candidateType1); } + // Fill D0 table for offline event mixing + if (applyMixedEvent) { + entryDMesonCand(candidate1.pt(), candidate1.eta(), candidate1.phi(), HfHelper::invMassD0barToKPi(candidate1), poolBin, gCollisionId, timeStamp); + } + } + + if (applyMixedEvent) { + // Loop on the associated tracks for offline event mixing + for (const auto& track : tracks) { + // apply track selection + if (track.collisionId() != gCollisionId) { + continue; + } + + // Manual trackFilter check + if (std::abs(track.eta()) >= etaTrackMax) { + continue; + } + if (track.pt() <= ptTrackMin) { + continue; + } + if (std::abs(track.dcaXY()) >= dcaXYTrackMax) { + continue; + } + if (std::abs(track.dcaZ()) >= dcaZTrackMax) { + continue; + } + // Removing D0 daughters by checking track indices + if (daughterTracksCutFlag) { + if ((candidate1.prong0Id() == track.globalIndex()) || (candidate1.prong1Id() == track.globalIndex())) { + continue; + } + } + if (cntD0 == 0) { + entryAssocHad(track.pt(), track.eta(), track.phi(), poolBin, gCollisionId, timeStamp); + registry.fill(HIST("hTracksBin"), poolBin); + registry.fill(HIST("hDcaXYVsPt"), track.dcaXY(), track.pt()); + } + } // Hadron Tracks loop + cntD0++; } + // Loop on the second D0 candidate for (auto candidate2 = candidate1 + 1; candidate2 != selectedD0CandidatesGrouped.end(); ++candidate2) { outputMlD0Cand2.clear(); @@ -667,9 +857,9 @@ struct HfCorrelatorDMesonPairs { if (ptCandMin >= 0. && candidate2.pt() < ptCandMin) { continue; } - auto prong0Cand2 = candidate2.template prong0_as(); - auto prong1Cand2 = candidate2.template prong1_as(); - if (daughterTracksCutFlag && ((prong0Cand1 == prong0Cand2) || (prong1Cand1 == prong1Cand2) || (prong0Cand1 == prong1Cand2) || (prong1Cand1 == prong0Cand2))) { + auto prong0Cand2 = candidate2.template prong0_as(); + auto prong1Cand2 = candidate2.template prong1_as(); + if ((prong0Cand1 == prong0Cand2) || (prong1Cand1 == prong1Cand2) || (prong0Cand1 == prong1Cand2) || (prong1Cand1 == prong0Cand2)) { continue; } @@ -707,18 +897,25 @@ struct HfCorrelatorDMesonPairs { } fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, HfHelper::yD0(candidate1), HfHelper::yD0(candidate2), - candidate1.phi(), candidate2.phi(), candidate1.pt(), candidate2.pt(), HfHelper::invMassD0ToPiK(candidate1), HfHelper::invMassD0barToKPi(candidate1), + candidate1.eta(), candidate2.eta(), candidate1.phi(), candidate2.phi(), + candidate1.pt(), candidate2.pt(), HfHelper::invMassD0ToPiK(candidate1), HfHelper::invMassD0barToKPi(candidate1), HfHelper::invMassD0ToPiK(candidate2), HfHelper::invMassD0barToKPi(candidate2)); entryD0PairMl(outputMlD0Cand1, outputMlD0barCand1, outputMlD0Cand2, outputMlD0barCand2); } else { // Fill entries - fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, HfHelper::yD0(candidate1), HfHelper::yD0(candidate2), candidate1.phi(), candidate2.phi(), + fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, HfHelper::yD0(candidate1), HfHelper::yD0(candidate2), + candidate1.eta(), candidate2.eta(), candidate1.phi(), candidate2.phi(), candidate1.pt(), candidate2.pt(), HfHelper::invMassD0ToPiK(candidate1), HfHelper::invMassD0barToKPi(candidate1), HfHelper::invMassD0ToPiK(candidate2), HfHelper::invMassD0barToKPi(candidate2)); } } // end inner loop (Cand2) } // end outer loop (Cand1) + + if (applyMixedEvent) { + registry.fill(HIST("hZvtx"), collision.posZ()); + registry.fill(HIST("hMultFT0M"), collision.multFT0M()); + } } PROCESS_SWITCH(HfCorrelatorDMesonPairs, processData, "Process data mode", true); @@ -730,10 +927,6 @@ struct HfCorrelatorDMesonPairs { } auto selectedD0CandidatesGroupedMc = selectedD0CandidatesMc->sliceByCached(aod::hf_cand::collisionId, collision.globalIndex(), cache); getCountersPerEvent(selectedD0CandidatesGroupedMc); - // protection against empty tables to be sliced - if (selectedD0CandidatesMc.size() <= 1) { - return; - } for (const auto& candidate1 : selectedD0CandidatesGroupedMc) { outputMlD0Cand1.clear(); @@ -742,10 +935,11 @@ struct HfCorrelatorDMesonPairs { auto ptCandidate1 = candidate1.pt(); auto yCandidate1 = HfHelper::yD0(candidate1); auto phiCandidate1 = candidate1.phi(); + auto etaCandidate1 = candidate1.eta(); float const massD0Cand1 = HfHelper::invMassD0ToPiK(candidate1); float const massD0barCand1 = HfHelper::invMassD0barToKPi(candidate1); - auto prong0Cand1 = candidate1.template prong0_as(); - auto prong1Cand1 = candidate1.template prong1_as(); + auto prong0Cand1 = candidate1.template prong0_as(); + auto prong1Cand1 = candidate1.template prong1_as(); if (std::abs(HfHelper::yD0(candidate1)) > yCandMax) { continue; @@ -857,6 +1051,7 @@ struct HfCorrelatorDMesonPairs { auto ptCandidate2 = candidate2.pt(); auto yCandidate2 = HfHelper::yD0(candidate2); auto phiCandidate2 = candidate2.phi(); + auto etaCandidate2 = candidate2.eta(); float const massD0Cand2 = HfHelper::invMassD0ToPiK(candidate2); float const massD0barCand2 = HfHelper::invMassD0barToKPi(candidate2); auto prong0Cand2 = candidate2.template prong0_as(); @@ -876,7 +1071,7 @@ struct HfCorrelatorDMesonPairs { if (candidate2.isSelD0() < selectionFlagD0 && candidate2.isSelD0bar() < selectionFlagD0bar) { continue; } - if (daughterTracksCutFlag && ((prong0Cand1 == prong0Cand2) || (prong1Cand1 == prong1Cand2) || (prong0Cand1 == prong1Cand2) || (prong1Cand1 == prong0Cand2))) { + if ((prong0Cand1 == prong0Cand2) || (prong1Cand1 == prong1Cand2) || (prong0Cand1 == prong1Cand2) || (prong1Cand1 == prong0Cand2)) { continue; } auto candidateType2 = assignCandidateTypeD0(candidate2); // Candidate type attribution @@ -913,7 +1108,7 @@ struct HfCorrelatorDMesonPairs { } // Fill tables - fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, yCandidate1, yCandidate2, phiCandidate1, phiCandidate2, + fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, yCandidate1, yCandidate2, etaCandidate1, etaCandidate2, phiCandidate1, phiCandidate2, ptCandidate1, ptCandidate2, massD0Cand1, massD0barCand1, massD0Cand2, massD0barCand2); fillMcHistos(matchedRec1, matchedRec2, static_cast(isTrueDCand1), static_cast(isTrueDbarCand1), static_cast(isTrueDCand2), static_cast(isTrueDbarCand2)); entryD0PairMcInfo(originRec1, originRec2, matchedRec1, matchedRec2); @@ -921,7 +1116,7 @@ struct HfCorrelatorDMesonPairs { } else { // Fill tables - fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, yCandidate1, yCandidate2, phiCandidate1, phiCandidate2, + fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, yCandidate1, yCandidate2, etaCandidate1, etaCandidate2, phiCandidate1, phiCandidate2, ptCandidate1, ptCandidate2, massD0Cand1, massD0barCand1, massD0Cand2, massD0barCand2); fillMcHistos(matchedRec1, matchedRec2, static_cast(isTrueDCand1), static_cast(isTrueDbarCand1), static_cast(isTrueDCand2), static_cast(isTrueDbarCand2)); entryD0PairMcInfo(originRec1, originRec2, matchedRec1, matchedRec2); @@ -1109,7 +1304,7 @@ struct HfCorrelatorDMesonPairs { } // Fill pair Selection Status - entryD0PairMcGen(particle1.pt(), particle2.pt(), particle1.y(), particle2.y(), particle1.phi(), particle2.phi(), MassD0, MassD0Bar, MassD0, MassD0Bar, pairType, particleType1, particleType2); + entryD0PairMcGen(particle1.pt(), particle2.pt(), particle1.y(), particle2.y(), particle1.eta(), particle2.eta(), particle1.phi(), particle2.phi(), MassD0, MassD0Bar, MassD0, MassD0Bar, pairType, particleType1, particleType2); entryD0PairMcGenInfo(originGen1, originGen2, matchedGen1, matchedGen2); } // end inner loop @@ -1121,5 +1316,8 @@ struct HfCorrelatorDMesonPairs { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + }; } From dcc8d10dba3d3d0f1029140989e77f9864d813e9 Mon Sep 17 00:00:00 2001 From: Yongxi Du <1260971129@qq.com> Date: Fri, 31 Jul 2026 21:44:29 +0800 Subject: [PATCH 62/71] [PWGUD] fix ptdiff (#17274) --- PWGUD/Tasks/flowCumulantsUpc.cxx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/PWGUD/Tasks/flowCumulantsUpc.cxx b/PWGUD/Tasks/flowCumulantsUpc.cxx index 4b7b11b8106..42ce67577ee 100644 --- a/PWGUD/Tasks/flowCumulantsUpc.cxx +++ b/PWGUD/Tasks/flowCumulantsUpc.cxx @@ -304,9 +304,20 @@ struct FlowCumulantsUpc { oba->Add(new TNamed(Form("Ch10Gap24_pt_%i", i + 1), "Ch10Gap24_pTDiff")); std::vector userDefineGFWCorr = cfgUserDefineGFWCorr; std::vector userDefineGFWName = cfgUserDefineGFWName; + if (userDefineGFWName.size() != userDefineGFWCorr.size()) { + LOGF(fatal, "The GFWConfig names you provided are NOT matching with configurations. userDefineGFWName.size(): %d, userDefineGFWCorr.size(): %d", userDefineGFWName.size(), userDefineGFWCorr.size()); + } + LOGF(info, "User adding FlowContainer Array:"); if (!userDefineGFWCorr.empty() && !userDefineGFWName.empty()) { for (uint i = 0; i < userDefineGFWName.size(); i++) { - oba->Add(new TNamed(userDefineGFWName.at(i).c_str(), userDefineGFWName.at(i).c_str())); + if (userDefineGFWCorr.at(i).find("poi") != std::string::npos) { + LOGF(info, "%d: pT-diff array %s", i, userDefineGFWName.at(i).c_str()); + for (auto iPt = 0; iPt < fPtAxis->GetNbins(); iPt++) + oba->Add(new TNamed(Form("%s_pt_%i", userDefineGFWName.at(i).c_str(), iPt + 1), Form("%s_pTDiff", userDefineGFWName.at(i).c_str()))); + } else { + LOGF(info, "%d: %s", i, userDefineGFWName.at(i).c_str()); + oba->Add(new TNamed(userDefineGFWName.at(i).c_str(), userDefineGFWName.at(i).c_str())); + } } } fFC->SetName("FlowContainer"); From 5ae5f86cfaa4248941898b9a966698d5cf1df31a Mon Sep 17 00:00:00 2001 From: "Q.Y. Xia" <91366503+huinaibing@users.noreply.github.com> Date: Sat, 1 Aug 2026 03:47:39 +0800 Subject: [PATCH 63/71] [PWGCF] Add MC closure test (#17277) Co-authored-by: ALICE Action Bot --- PWGCF/Flow/Tasks/pidFlowPtCorr.cxx | 654 ++++++++++++++++++++++++----- 1 file changed, 550 insertions(+), 104 deletions(-) diff --git a/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx b/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx index 018bd326a9a..54c7912b6ab 100644 --- a/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx +++ b/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -58,6 +59,7 @@ #include #include +#include #include #include #include @@ -85,12 +87,12 @@ struct PidFlowPtCorr { Configurable cfgRangeEta{"cfgRangeEta", 0.4f, "Eta range for mean Pt"}; Configurable cfgCutPtMin{"cfgCutPtMin", 0.2f, "Minimal pT for ref tracks"}; Configurable cfgCutPtMax{"cfgCutPtMax", 10.0f, "Maximal pT for ref tracks"}; - Configurable cfgCutPtMinPi{"cfgCutPtMinPi", 0.2f, "Minimal pT for pion POI, used only in processData"}; - Configurable cfgCutPtMaxPi{"cfgCutPtMaxPi", 10.0f, "Maximal pT for pion POI, used only in processData"}; - Configurable cfgCutPtMinKa{"cfgCutPtMinKa", 0.2f, "Minimal pT for kaon POI, used only in processData"}; - Configurable cfgCutPtMaxKa{"cfgCutPtMaxKa", 10.0f, "Maximal pT for kaon POI, used only in processData"}; - Configurable cfgCutPtMinPr{"cfgCutPtMinPr", 0.2f, "Minimal pT for proton POI, used only in processData"}; - Configurable cfgCutPtMaxPr{"cfgCutPtMaxPr", 10.0f, "Maximal pT for proton POI, used only in processData"}; + Configurable cfgCutPtMinPi{"cfgCutPtMinPi", 0.2f, "Minimal pT for pion POI"}; + Configurable cfgCutPtMaxPi{"cfgCutPtMaxPi", 10.0f, "Maximal pT for pion POI"}; + Configurable cfgCutPtMinKa{"cfgCutPtMinKa", 0.2f, "Minimal pT for kaon POI"}; + Configurable cfgCutPtMaxKa{"cfgCutPtMaxKa", 10.0f, "Maximal pT for kaon POI"}; + Configurable cfgCutPtMinPr{"cfgCutPtMinPr", 0.2f, "Minimal pT for proton POI"}; + Configurable cfgCutPtMaxPr{"cfgCutPtMaxPr", 10.0f, "Maximal pT for proton POI"}; // track quality selections for daughter track Configurable cfgITSNCls{"cfgITSNCls", 5, "check minimum number of ITS clusters"}; Configurable cfgTPCNCls{"cfgTPCNCls", 50, "check minimum number of TPC hits"}; @@ -114,6 +116,7 @@ struct PidFlowPtCorr { Configurable cfgDoV0AT0Acut{"cfgDoV0AT0Acut", true, "do V0A-T0A cut"}; Configurable cfgCutminIR{"cfgCutminIR", -1, "cut min IR"}; Configurable cfgCutmaxIR{"cfgCutmaxIR", 3000, "cut max IR"}; + Configurable cfgIRSource{"cfgIRSource", "ZNC hadronic", "Interaction-rate source for CTP rate fetcher. Use T0VTX for pp/OO and ZNC hadronic for Pb-Pb; empty disables fetching"}; } evtSeleOpts; struct : ConfigurableGroup { @@ -151,6 +154,7 @@ struct PidFlowPtCorr { Configurable cfgCheck2MethodDiff{"cfgCheck2MethodDiff", false, "check difference between v2' && v2''"}; Configurable cfgClosureTest{"cfgClosureTest", 0, "choose (val) percent particle from charged to pass Pion PID selection"}; Configurable cfgOutPutMC1D{"cfgOutPutMC1D", true, "Fill MC graphs, note that if the processMCgen is open,this MUST be open"}; + Configurable cfgAddPidResponseMatrixHistograms{"cfgAddPidResponseMatrixHistograms", false, "Add PID response matrix histograms; enable together with processPidResponseMatrix"}; Configurable cfgProcessQAOutput{"cfgProcessQAOutput", false, "QA plots for processQA"}; Configurable cfgUseNUAWithPt{"cfgUseNUAWithPt", false, "false: use original GFWWeights (phi,eta,vz) NUA; true: use THnSparse (phi,eta,vz,pt) NUA loaded from cfgAcceptancePathWithPt"}; @@ -328,9 +332,18 @@ struct PidFlowPtCorr { funcProcessReco, funcProcessSim, funcProcessQA, + funcProcessPidResponseMatrix, funcNumber }; + enum PidResponseBin { + kPidRespPion = 0, + kPidRespKaon, + kPidRespProton, + kPidRespUnidentified, + kPidRespNRecoBins + }; + // graphs for NUE / NUA std::vector mAcceptance; std::vector mEfficiency; @@ -548,10 +561,30 @@ struct PidFlowPtCorr { registry.addClone("hEventCount/processData", "hEventCount/processReco"); // processSim registry.addClone("hEventCount/processData", "hEventCount/processSim"); + // processPidResponseMatrix + registry.addClone("hEventCount/processData", "hEventCount/processPidResponseMatrix"); registry.add("hInteractionRate", "", {HistType::kTH1D, {{1000, 0, 1000}}}); // end set bin label for eventcount + if (switchsOpts.cfgAddPidResponseMatrixHistograms.value) { + registry.add("pidResponseMatrix/hPidResponseMatrix", "PID response matrix;true PID;reconstructed PID", {HistType::kTH2D, {{3, -0.5, 2.5}, {4, -0.5, 3.5}}}); + registry.add("pidResponseMatrix/hPidResponseMatrixRecPtCent", "PID response matrix vs reconstructed pT and centrality;true PID;reconstructed PID;p_{T}^{rec} (GeV/#it{c});Centrality (%)", {HistType::kTHnSparseF, {{3, -0.5, 2.5}, {4, -0.5, 3.5}, cfgaxisPt, axisMultiplicity}}); + + auto setPidResponseLabels = [](TAxis* axis, bool includeUnidentified) { + axis->SetBinLabel(kPidRespPion + 1, "Pion"); + axis->SetBinLabel(kPidRespKaon + 1, "Kaon"); + axis->SetBinLabel(kPidRespProton + 1, "Proton"); + if (includeUnidentified) { + axis->SetBinLabel(kPidRespUnidentified + 1, "Unidentified"); + } + }; + setPidResponseLabels(registry.get(HIST("pidResponseMatrix/hPidResponseMatrix"))->GetXaxis(), false); + setPidResponseLabels(registry.get(HIST("pidResponseMatrix/hPidResponseMatrix"))->GetYaxis(), true); + setPidResponseLabels(registry.get(HIST("pidResponseMatrix/hPidResponseMatrixRecPtCent"))->GetAxis(0), false); + setPidResponseLabels(registry.get(HIST("pidResponseMatrix/hPidResponseMatrixRecPtCent"))->GetAxis(1), true); + } + // flow container setup // cumulant of flow // fill TObjArray for charged @@ -1051,6 +1084,53 @@ struct PidFlowPtCorr { return pid; } + bool isWithinRefPtRange(float pt) + { + return (pt > trkQualityOpts.cfgCutPtMin.value) && (pt < trkQualityOpts.cfgCutPtMax.value); + } + + bool isWithinPOIPtRange(int pid, float pt) + { + switch (pid) { + case MyParticleType::kPion: + return (pt > trkQualityOpts.cfgCutPtMinPi.value) && (pt < trkQualityOpts.cfgCutPtMaxPi.value); + case MyParticleType::kKaon: + return (pt > trkQualityOpts.cfgCutPtMinKa.value) && (pt < trkQualityOpts.cfgCutPtMaxKa.value); + case MyParticleType::kProton: + return (pt > trkQualityOpts.cfgCutPtMinPr.value) && (pt < trkQualityOpts.cfgCutPtMaxPr.value); + default: + return false; + } + } + + int getPidResponseTrueBin(int pdgCode) + { + switch (std::abs(pdgCode)) { + case PDG_t::kPiPlus: + return kPidRespPion; + case PDG_t::kKPlus: + return kPidRespKaon; + case PDG_t::kProton: + return kPidRespProton; + default: + return -1; + } + } + + int getPidResponseRecoBin(int recoPid) + { + switch (recoPid) { + case MyParticleType::kPion: + return kPidRespPion; + case MyParticleType::kKaon: + return kPidRespKaon; + case MyParticleType::kProton: + return kPidRespProton; + default: + return kPidRespUnidentified; + } + } + // pid util function // other utils @@ -1521,12 +1601,12 @@ struct PidFlowPtCorr { if (!hist) { return 1; } - int bins[4]; + std::array bins; bins[0] = hist->GetAxis(0)->FindBin(phi); bins[1] = hist->GetAxis(1)->FindBin(eta); bins[2] = hist->GetAxis(2)->FindBin(vz); bins[3] = hist->GetAxis(3)->FindBin(pt); - double weight = hist->GetBinContent(bins); + double weight = hist->GetBinContent(bins.data()); if (weight != 0) { return 1. / weight; } @@ -1805,6 +1885,12 @@ struct PidFlowPtCorr { return true; } + template + bool trackSelectedForFlow(TTrack& track) + { + return trackSelectedGlobal(track, false) && track.hasITS() && track.hasTPC() && trackSelected4ITS(track) && trackSelected4TPC(track); + } + // track cut // event selection functions @@ -1833,6 +1919,9 @@ struct PidFlowPtCorr { case MyFunctionName::funcProcessSim: registry.fill(HIST("hEventCount/processSim"), position); break; + case MyFunctionName::funcProcessPidResponseMatrix: + registry.fill(HIST("hEventCount/processPidResponseMatrix"), position); + break; default: // LOGF(warning, "could not find event count graph"); @@ -1985,11 +2074,11 @@ struct PidFlowPtCorr { fillEventCountHelper(funcName, 11.5); registry.fill(HIST("hInteractionRate"), interactionRate); - if (interactionRate > 0 && interactionRate < evtSeleOpts.cfgCutminIR.value) { + if (evtSeleOpts.cfgCutminIR.value >= 0 && interactionRate > 0 && interactionRate < evtSeleOpts.cfgCutminIR.value) { return false; } fillEventCountHelper(funcName, 12.5); - if (interactionRate > evtSeleOpts.cfgCutmaxIR.value) { + if (evtSeleOpts.cfgCutmaxIR.value >= 0 && interactionRate > evtSeleOpts.cfgCutmaxIR.value) { return false; } fillEventCountHelper(funcName, 13.5); @@ -1997,6 +2086,16 @@ struct PidFlowPtCorr { return true; } + double getInteractionRate(uint64_t timestamp, int runNumber) + { + const bool useMinIRCut = evtSeleOpts.cfgCutminIR.value >= 0; + const bool useMaxIRCut = evtSeleOpts.cfgCutmaxIR.value >= 0; + if ((!useMinIRCut && !useMaxIRCut) || evtSeleOpts.cfgIRSource.value.empty()) { + return -1.; + } + return rateFetcher.fetch(ccdb.service, timestamp, runNumber, evtSeleOpts.cfgIRSource.value) * 1.e-3; + } + // event selection // main functions @@ -2010,7 +2109,7 @@ struct PidFlowPtCorr { float nMultTPC = collision.multTPC(); auto bc = collision.bc_as(); int runNumber = bc.runNumber(); - double interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 1.e-3; + double interactionRate = getInteractionRate(bc.timestamp(), runNumber); // end init // collision cut @@ -2053,7 +2152,7 @@ struct PidFlowPtCorr { double q4x = 0, q4y = 0; for (const auto& track : tracks) { // pt cut - bool withinPtRef = (trkQualityOpts.cfgCutPtMin.value < track.pt()) && (track.pt() < trkQualityOpts.cfgCutPtMax.value); // within RF pT rang + bool withinPtRef = isWithinRefPtRange(track.pt()); if (withinPtRef) { q2x += std::cos(2 * track.phi()); q2y += std::sin(2 * track.phi()); @@ -2105,38 +2204,21 @@ struct PidFlowPtCorr { double protonPtSquareSum = 0; // end val for pid particles - /// @note calculate pt - /// use ITS only + // Calculate mean-pT moments and PID-particle sums. for (const auto& track : tracks) { float weff = 1; - // track cut ITS only - // note: pt cut is deferred (checked separately below per ref/POI species), - // since ref and POI (pi/ka/pr) may have independent pt ranges - if (!trackSelectedGlobal(track, false)) { - continue; - } - if (!track.hasITS()) { - continue; - } - if (!trackSelected4ITS(track)) { - continue; - } - if (!track.hasTPC()) { - continue; - } - if (!trackSelected4TPC(track)) { + // The reference and POI pT ranges are applied independently below. + if (!trackSelectedForFlow(track)) { continue; } - // end track cut its only - // do nue setParticleNUEWeight(weff, track, cent); // end do nue // calculate ncharged(nch with weight) and pt - bool withinPtRef = (track.pt() > trkQualityOpts.cfgCutPtMin.value) && (track.pt() < trkQualityOpts.cfgCutPtMax.value); + bool withinPtRef = isWithinRefPtRange(track.pt()); if (withinPtRef && std::fabs(track.eta()) < trkQualityOpts.cfgRangeEta.value) { nch += weff; nchSquare += weff * weff; @@ -2157,25 +2239,21 @@ struct PidFlowPtCorr { setParticleNUEWeight(weffPid, track, cent, pid); // end do nue - // Fill PID variables based on unified result - if (pid == MyParticleType::kPion) { - if (track.pt() > trkQualityOpts.cfgCutPtMinPi.value && track.pt() < trkQualityOpts.cfgCutPtMaxPi.value) { + // Apply the species-specific POI pT range before accumulating moments. + if (isWithinPOIPtRange(pid, track.pt())) { + if (pid == MyParticleType::kPion) { nPionWeighted += weffPid; nPionSquare += weffPid * weffPid; pionPtSum += weffPid * track.pt(); pionPtSumw2 += weffPid * weffPid * track.pt(); pionPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); - } - } else if (pid == MyParticleType::kKaon) { - if (track.pt() > trkQualityOpts.cfgCutPtMinKa.value && track.pt() < trkQualityOpts.cfgCutPtMaxKa.value) { + } else if (pid == MyParticleType::kKaon) { nKaonWeighted += weffPid; nKaonSquare += weffPid * weffPid; kaonPtSum += weffPid * track.pt(); kaonPtSumw2 += weffPid * weffPid * track.pt(); kaonPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); - } - } else if (pid == MyParticleType::kProton) { - if (track.pt() > trkQualityOpts.cfgCutPtMinPr.value && track.pt() < trkQualityOpts.cfgCutPtMaxPr.value) { + } else if (pid == MyParticleType::kProton) { nProtonWeighted += weffPid; nProtonSquare += weffPid * weffPid; protonPtSum += weffPid * track.pt(); @@ -2183,7 +2261,6 @@ struct PidFlowPtCorr { protonPtSquareSum += weffPid * weffPid * track.pt() * track.pt(); } } - // else: do nothing (ambiguous or not identified) } // end calculate POI sums @@ -2212,7 +2289,7 @@ struct PidFlowPtCorr { // end do NUE && NUA if (switchsOpts.cfgDoLocDenCorr.value) { - bool withinPtRef = (trkQualityOpts.cfgCutPtMin.value < track.pt()) && (track.pt() < trkQualityOpts.cfgCutPtMax.value); + bool withinPtRef = isWithinRefPtRange(track.pt()); if (withinPtRef) { double fphi = v2 * std::cos(2 * (track.phi() - psi2Est)) + v3 * std::cos(3 * (track.phi() - psi3Est)) + v4 * std::cos(4 * (track.phi() - psi4Est)); fphi = (1 + 2 * fphi); @@ -2227,26 +2304,10 @@ struct PidFlowPtCorr { } } // cfgDoLocDenCorr - // track cut, global + ITS + TPC - // note: pt cut is deferred (checked separately below per ref/POI species), - // since ref and POI (pi/ka/pr) may have independent pt ranges - if (!trackSelectedGlobal(track, false)) { - continue; - } - if (!track.hasITS()) { + // The reference and POI pT ranges are applied independently below. + if (!trackSelectedForFlow(track)) { continue; } - if (!track.hasTPC()) { - continue; - } - if (!trackSelected4ITS(track)) { - continue; - } - if (!trackSelected4TPC(track)) { - continue; - } - - // end track cut totalGlobalTrack++; if (switchsOpts.cfgDebugMyCode.value && weff == 1.) { @@ -2257,7 +2318,7 @@ struct PidFlowPtCorr { LOGF(info, "wacc for global track is 1, if NUA is open and this appears alot, check!"); } - bool withinPtRefGlobal = (track.pt() > trkQualityOpts.cfgCutPtMin.value) && (track.pt() < trkQualityOpts.cfgCutPtMax.value); + bool withinPtRefGlobal = isWithinRefPtRange(track.pt()); if (withinPtRefGlobal) { // fill QA hist registry.fill(HIST("hPhi"), track.phi()); @@ -2287,40 +2348,40 @@ struct PidFlowPtCorr { this->setParticleNUAWeight(waccPid, track, vtxz, pid); this->setParticleNUEWeight(weffPid, track, cent, pid); - // Fill GFW and counters based on unified result - if (pid == MyParticleType::kPion && track.pt() > trkQualityOpts.cfgCutPtMinPi.value && track.pt() < trkQualityOpts.cfgCutPtMaxPi.value) { - // bitmask 18: 0010010 - fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 2); - fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 16, wacc * weff); - registry.fill(HIST("hPhiPi"), track.phi()); - registry.fill(HIST("hPhicorrPi"), track.phi(), waccPid); - registry.fill(HIST("hPhiCorrNUANUEPi"), track.phi(), waccPid * weffPid); - registry.fill(HIST("hPtPi"), track.pt()); - registry.fill(HIST("hPtCorrPi"), track.pt(), weffPid); - numOfPi++; - } else if (pid == MyParticleType::kKaon && track.pt() > trkQualityOpts.cfgCutPtMinKa.value && track.pt() < trkQualityOpts.cfgCutPtMaxKa.value) { - // bitmask 36: 0100100 - fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 4); - fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 32, wacc * weff); - registry.fill(HIST("hPhiKa"), track.phi()); - registry.fill(HIST("hPhicorrKa"), track.phi(), waccPid); - registry.fill(HIST("hPhiCorrNUANUEKa"), track.phi(), waccPid * weffPid); - registry.fill(HIST("hPtKa"), track.pt()); - registry.fill(HIST("hPtCorrKa"), track.pt(), weffPid); - numOfKa++; - } else if (pid == MyParticleType::kProton && track.pt() > trkQualityOpts.cfgCutPtMinPr.value && track.pt() < trkQualityOpts.cfgCutPtMaxPr.value) { - // bitmask 72: 1001000 - fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 8); - fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 64, wacc * weff); - registry.fill(HIST("hPhiPr"), track.phi()); - registry.fill(HIST("hPhicorrPr"), track.phi(), waccPid); - registry.fill(HIST("hPhiCorrNUANUEPr"), track.phi(), waccPid * weffPid); - registry.fill(HIST("hPtPr"), track.pt()); - registry.fill(HIST("hPtCorrPr"), track.pt(), weffPid); - numOfPr++; - } - // else: do nothing (ambiguous, not identified, or outside POI pt range) - // end fill GFW + // Fill GFW and counters using the same species-specific POI pT range. + if (isWithinPOIPtRange(pid, track.pt())) { + if (pid == MyParticleType::kPion) { + // bitmask 18: 0010010 + fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 2); + fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 16, wacc * weff); + registry.fill(HIST("hPhiPi"), track.phi()); + registry.fill(HIST("hPhicorrPi"), track.phi(), waccPid); + registry.fill(HIST("hPhiCorrNUANUEPi"), track.phi(), waccPid * weffPid); + registry.fill(HIST("hPtPi"), track.pt()); + registry.fill(HIST("hPtCorrPi"), track.pt(), weffPid); + numOfPi++; + } else if (pid == MyParticleType::kKaon) { + // bitmask 36: 0100100 + fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 4); + fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 32, wacc * weff); + registry.fill(HIST("hPhiKa"), track.phi()); + registry.fill(HIST("hPhicorrKa"), track.phi(), waccPid); + registry.fill(HIST("hPhiCorrNUANUEKa"), track.phi(), waccPid * weffPid); + registry.fill(HIST("hPtKa"), track.pt()); + registry.fill(HIST("hPtCorrKa"), track.pt(), weffPid); + numOfKa++; + } else if (pid == MyParticleType::kProton) { + // bitmask 72: 1001000 + fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 8); + fGFW->Fill(track.eta(), 0, track.phi(), waccPid * weffPid, 64, wacc * weff); + registry.fill(HIST("hPhiPr"), track.phi()); + registry.fill(HIST("hPhicorrPr"), track.phi(), waccPid); + registry.fill(HIST("hPhiCorrNUANUEPr"), track.phi(), waccPid * weffPid); + registry.fill(HIST("hPtPr"), track.pt()); + registry.fill(HIST("hPtCorrPr"), track.pt(), weffPid); + numOfPr++; + } + } } // end track loop for v2 calculation // sub region, fill graphs after 2 loop on all tracks @@ -2573,6 +2634,316 @@ struct PidFlowPtCorr { } PROCESS_SWITCH(PidFlowPtCorr, processData, "", true); + /** + * @brief Run the flow calculation on generated MC particles for a closure test. + * @note Reconstructed collisions are only used to obtain the centrality. The selection is + * deliberately truth-level: MC vertex filter, physical-primary particles, kinematics, + * and PDG PID. No data event, track-quality, detector-PID, NUA, or NUE cuts are applied. + */ + void processMCClosure(FilteredMcCollisions::iterator const& mcCollision, + aod::BCsWithTimestamps const&, + soa::SmallGroups> const& collisions, + FilteredMcParticles const& mcParticles, + FilteredTracksWithMCLabel const&) + { + registry.fill(HIST("hEventCount/processData"), 0.5); + if (collisions.size() <= 0 || mcParticles.size() <= 0) { + return; + } + + for (const auto& collision : collisions) { + const float cent = getCentrality(collision); + const float vtxz = mcCollision.posZ(); + const float rndm = fRndm->Rndm(); + const int nTot = mcParticles.size(); + + fGFW->Clear(); + registry.fill(HIST("hEventCount/processData"), 1.5); + registry.fill(HIST("hVtxZ"), vtxz); + registry.fill(HIST("hMult"), nTot); + registry.fill(HIST("hCent"), cent); + if (switchsOpts.cfgOutPutPtSpectra.value) { + registry.fill(HIST("ptSpectra/hCentEventCountData"), cent); + } + + double ptSum = 0., ptSumw2 = 0., nch = 0., nchSquare = 0., ptSquareSum = 0.; + double pionPtSum = 0., kaonPtSum = 0., protonPtSum = 0.; + double nPionWeighted = 0., nKaonWeighted = 0., nProtonWeighted = 0.; + double pionPtSumw2 = 0., kaonPtSumw2 = 0., protonPtSumw2 = 0.; + double nPionSquare = 0., nKaonSquare = 0., nProtonSquare = 0.; + double pionPtSquareSum = 0., kaonPtSquareSum = 0., protonPtSquareSum = 0.; + int numOfPi = 0, numOfKa = 0, numOfPr = 0; + + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary() || !isStable(mcParticle.pdgCode()) || std::fabs(mcParticle.eta()) > trkQualityOpts.cfgCutEta.value) { + continue; + } + + const float pt = mcParticle.pt(); + const bool withinPtRef = pt > trkQualityOpts.cfgCutPtMin.value && pt < trkQualityOpts.cfgCutPtMax.value; + const bool withinMeanPtEta = std::fabs(mcParticle.eta()) < trkQualityOpts.cfgRangeEta.value; + const int absPdg = std::abs(mcParticle.pdgCode()); + int pid = -1; + if (absPdg == PDG_t::kPiPlus) { + pid = MyParticleType::kPion; + } else if (absPdg == PDG_t::kKPlus) { + pid = MyParticleType::kKaon; + } else if (absPdg == PDG_t::kProton) { + pid = MyParticleType::kProton; + } + + if (withinPtRef && withinMeanPtEta) { + nch += 1.; + nchSquare += 1.; + ptSum += pt; + ptSumw2 += pt; + ptSquareSum += pt * pt; + } + + if (withinMeanPtEta && isWithinPOIPtRange(pid, pt)) { + if (pid == MyParticleType::kPion) { + nPionWeighted += 1.; + nPionSquare += 1.; + pionPtSum += pt; + pionPtSumw2 += pt; + pionPtSquareSum += pt * pt; + } else if (pid == MyParticleType::kKaon) { + nKaonWeighted += 1.; + nKaonSquare += 1.; + kaonPtSum += pt; + kaonPtSumw2 += pt; + kaonPtSquareSum += pt * pt; + } else if (pid == MyParticleType::kProton) { + nProtonWeighted += 1.; + nProtonSquare += 1.; + protonPtSum += pt; + protonPtSumw2 += pt; + protonPtSquareSum += pt * pt; + } + } + + if (withinPtRef) { + registry.fill(HIST("hPhi"), mcParticle.phi()); + registry.fill(HIST("hPhicorr"), mcParticle.phi()); + registry.fill(HIST("hPhiCorrNUANUE"), mcParticle.phi()); + registry.fill(HIST("hEta"), mcParticle.eta()); + registry.fill(HIST("hPt"), pt); + registry.fill(HIST("hPtCorr"), pt); + if (switchsOpts.cfgOutPutPtSpectra.value) { + registry.fill(HIST("ptSpectra/hPtCentData"), pt, cent); + } + fGFW->Fill(mcParticle.eta(), 0, mcParticle.phi(), 1., 1); + } + + if (!isWithinPOIPtRange(pid, pt)) { + continue; + } + if (pid == MyParticleType::kPion) { + fGFW->Fill(mcParticle.eta(), 0, mcParticle.phi(), 1., 2); + fGFW->Fill(mcParticle.eta(), 0, mcParticle.phi(), 1., 16, 1.); + registry.fill(HIST("hPhiPi"), mcParticle.phi()); + registry.fill(HIST("hPhicorrPi"), mcParticle.phi()); + registry.fill(HIST("hPhiCorrNUANUEPi"), mcParticle.phi()); + registry.fill(HIST("hPtPi"), pt); + registry.fill(HIST("hPtCorrPi"), pt); + ++numOfPi; + } else if (pid == MyParticleType::kKaon) { + fGFW->Fill(mcParticle.eta(), 0, mcParticle.phi(), 1., 4); + fGFW->Fill(mcParticle.eta(), 0, mcParticle.phi(), 1., 32, 1.); + registry.fill(HIST("hPhiKa"), mcParticle.phi()); + registry.fill(HIST("hPhicorrKa"), mcParticle.phi()); + registry.fill(HIST("hPhiCorrNUANUEKa"), mcParticle.phi()); + registry.fill(HIST("hPtKa"), pt); + registry.fill(HIST("hPtCorrKa"), pt); + ++numOfKa; + } else if (pid == MyParticleType::kProton) { + fGFW->Fill(mcParticle.eta(), 0, mcParticle.phi(), 1., 8); + fGFW->Fill(mcParticle.eta(), 0, mcParticle.phi(), 1., 64, 1.); + registry.fill(HIST("hPhiPr"), mcParticle.phi()); + registry.fill(HIST("hPhicorrPr"), mcParticle.phi()); + registry.fill(HIST("hPhiCorrNUANUEPr"), mcParticle.phi()); + registry.fill(HIST("hPtPr"), pt); + registry.fill(HIST("hPtCorrPr"), pt); + ++numOfPr; + } + } + + if (particleAbundanceOpts.cfgOutPutAbundanceDis) { + registry.fill(HIST("abundance/hNumOfPiEventCount"), numOfPi); + registry.fill(HIST("abundance/hNumOfKaEventCount"), numOfKa); + registry.fill(HIST("abundance/hNumOfPrEventCount"), numOfPr); + } + registry.fill(HIST("hNchUnCorrectedVSNchCorrected"), nch, nch); + + if (nch <= 0.) { + continue; + } + + fillFC(MyParticleType::kCharged, corrconfigs.at(0), cent, rndm, "c22"); + fillFC(MyParticleType::kCharged, corrconfigs.at(1), cent, rndm, "c24"); + fillFC(MyParticleType::kCharged, corrconfigs.at(2), cent, rndm, "c22Full"); + fillFC(MyParticleType::kCharged, corrconfigs.at(3), cent, rndm, "c32"); + fillFC(MyParticleType::kCharged, corrconfigs.at(4), cent, rndm, "c34"); + + fillFC(MyParticleType::kPion, corrconfigs.at(35), cent, rndm, "c22Full"); + fillFC(MyParticleType::kPion, corrconfigs.at(36), cent, rndm, "c22Full"); + fillFC(MyParticleType::kKaon, corrconfigs.at(37), cent, rndm, "c22Full"); + fillFC(MyParticleType::kKaon, corrconfigs.at(38), cent, rndm, "c22Full"); + fillFC(MyParticleType::kProton, corrconfigs.at(39), cent, rndm, "c22Full"); + fillFC(MyParticleType::kProton, corrconfigs.at(40), cent, rndm, "c22Full"); + + fillFC(MyParticleType::kPion, corrconfigs.at(11), cent, rndm, "c24"); + fillFC(MyParticleType::kPion, corrconfigs.at(12), cent, rndm, "c24"); + fillFC(MyParticleType::kKaon, corrconfigs.at(13), cent, rndm, "c24"); + fillFC(MyParticleType::kKaon, corrconfigs.at(14), cent, rndm, "c24"); + fillFC(MyParticleType::kProton, corrconfigs.at(15), cent, rndm, "c24"); + fillFC(MyParticleType::kProton, corrconfigs.at(16), cent, rndm, "c24"); + + fillFC(MyParticleType::kPion, corrconfigs.at(17), cent, rndm, "c32"); + fillFC(MyParticleType::kPion, corrconfigs.at(18), cent, rndm, "c32"); + fillFC(MyParticleType::kKaon, corrconfigs.at(19), cent, rndm, "c32"); + fillFC(MyParticleType::kKaon, corrconfigs.at(20), cent, rndm, "c32"); + fillFC(MyParticleType::kProton, corrconfigs.at(21), cent, rndm, "c32"); + fillFC(MyParticleType::kProton, corrconfigs.at(22), cent, rndm, "c32"); + + fillFC(MyParticleType::kPion, corrconfigs.at(23), cent, rndm, "c34"); + fillFC(MyParticleType::kPion, corrconfigs.at(24), cent, rndm, "c34"); + fillFC(MyParticleType::kKaon, corrconfigs.at(25), cent, rndm, "c34"); + fillFC(MyParticleType::kKaon, corrconfigs.at(26), cent, rndm, "c34"); + fillFC(MyParticleType::kProton, corrconfigs.at(27), cent, rndm, "c34"); + fillFC(MyParticleType::kProton, corrconfigs.at(28), cent, rndm, "c34"); + + const bool filledPi = fillFC(MyParticleType::kPion, corrconfigs.at(29), cent, rndm, "c22pure"); + const bool filledKa = fillFC(MyParticleType::kKaon, corrconfigs.at(30), cent, rndm, "c22pure"); + const bool filledPr = fillFC(MyParticleType::kProton, corrconfigs.at(31), cent, rndm, "c22pure"); + fillFC(MyParticleType::kPion, corrconfigs.at(32), cent, rndm, "c32pure"); + fillFC(MyParticleType::kKaon, corrconfigs.at(33), cent, rndm, "c32pure"); + fillFC(MyParticleType::kProton, corrconfigs.at(34), cent, rndm, "c32pure"); + + if (filledPi || !switchsOpts.cfgCheck2MethodDiff.value) { + fillFC(MyParticleType::kPion, corrconfigs.at(5), cent, rndm, "c22"); + fillFC(MyParticleType::kPion, corrconfigs.at(6), cent, rndm, "c22"); + } + if (filledKa || !switchsOpts.cfgCheck2MethodDiff.value) { + fillFC(MyParticleType::kKaon, corrconfigs.at(7), cent, rndm, "c22"); + fillFC(MyParticleType::kKaon, corrconfigs.at(8), cent, rndm, "c22"); + } + if (filledPr || !switchsOpts.cfgCheck2MethodDiff.value) { + fillFC(MyParticleType::kProton, corrconfigs.at(9), cent, rndm, "c22"); + fillFC(MyParticleType::kProton, corrconfigs.at(10), cent, rndm, "c22"); + } + + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(0), cent, rndm, nch, nch, "c22TrackWeight"); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(0), cent, rndm, nch, nch, "c22TrackWeightOne", true); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(1), cent, rndm, nch, nch, "c24TrackWeight"); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(2), cent, rndm, nch, nch, "c22FullTrackWeight"); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(3), cent, rndm, nch, nch, "c32TrackWeight"); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(4), cent, rndm, nch, nch, "c34TrackWeight"); + fillFCvnpt(MyParticleType::kPion, corrconfigs.at(29), cent, rndm, nch, nch, "c22TrackWeight"); + fillFCvnpt(MyParticleType::kKaon, corrconfigs.at(30), cent, rndm, nch, nch, "c22TrackWeight"); + fillFCvnpt(MyParticleType::kProton, corrconfigs.at(31), cent, rndm, nch, nch, "c22TrackWeight"); + fillFCvnpt(MyParticleType::kPion, corrconfigs.at(32), cent, rndm, nch, nch, "c32TrackWeight"); + fillFCvnpt(MyParticleType::kKaon, corrconfigs.at(33), cent, rndm, nch, nch, "c32TrackWeight"); + fillFCvnpt(MyParticleType::kProton, corrconfigs.at(34), cent, rndm, nch, nch, "c32TrackWeight"); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(0), cent, rndm, ptSum, nch, "covV2Pt"); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(0), cent, rndm, ptSum, nch, "covV2PtWeightOne", true); + fillFCvnpt(MyParticleType::kPion, corrconfigs.at(29), cent, rndm, ptSum, nch, "covV2Pt"); + fillFCvnpt(MyParticleType::kKaon, corrconfigs.at(30), cent, rndm, ptSum, nch, "covV2Pt"); + fillFCvnpt(MyParticleType::kProton, corrconfigs.at(31), cent, rndm, ptSum, nch, "covV2Pt"); + fillFCvnpt(MyParticleType::kCharged, corrconfigs.at(3), cent, rndm, ptSum, nch, "covV3Pt"); + fillFCvnpt(MyParticleType::kPion, corrconfigs.at(32), cent, rndm, ptSum, nch, "covV3Pt"); + fillFCvnpt(MyParticleType::kKaon, corrconfigs.at(33), cent, rndm, ptSum, nch, "covV3Pt"); + fillFCvnpt(MyParticleType::kProton, corrconfigs.at(34), cent, rndm, ptSum, nch, "covV3Pt"); + + fillProfilePOIvnpt(corrconfigs.at(0), HIST("c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(5), HIST("pi/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(6), HIST("pi/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(7), HIST("ka/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(8), HIST("ka/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(9), HIST("pr/c22dmeanpt"), cent, ptSum, nch); + fillProfilePOIvnpt(corrconfigs.at(10), HIST("pr/c22dmeanpt"), cent, ptSum, nch); + + fillFC4PtC22(cent, ptSum, nch, rndm); + if (nPionWeighted > 0.) { + fillFC4PtC22(cent, rndm, MyParticleType::kPion, pionPtSum, nPionWeighted); + } + if (nKaonWeighted > 0.) { + fillFC4PtC22(cent, rndm, MyParticleType::kKaon, kaonPtSum, nKaonWeighted); + } + if (nProtonWeighted > 0.) { + fillFC4PtC22(cent, rndm, MyParticleType::kProton, protonPtSum, nProtonWeighted); + } + + fFCCh->FillProfile("hMeanPt", cent, ptSum / nch, nch, rndm); + fFCCh->FillProfile("hMeanPtWeightOne", cent, ptSum / nch, 1., rndm); + if (nPionWeighted > 0.) { + fFCPi->FillProfile("hMeanPt", cent, pionPtSum / nPionWeighted, nPionWeighted, rndm); + fFCPi->FillProfile("hMeanPtWeightOne", cent, pionPtSum / nPionWeighted, 1., rndm); + fillFCvnpt(MyParticleType::kPion, corrconfigs.at(29), cent, rndm, pionPtSum, nPionWeighted, "covV2PtPID"); + fillFCvnpt(MyParticleType::kPion, corrconfigs.at(29), cent, rndm, nPionWeighted, nPionWeighted, "c22TrackWeightPID"); + } + if (nKaonWeighted > 0.) { + fFCKa->FillProfile("hMeanPt", cent, kaonPtSum / nKaonWeighted, nKaonWeighted, rndm); + fFCKa->FillProfile("hMeanPtWeightOne", cent, kaonPtSum / nKaonWeighted, 1., rndm); + fillFCvnpt(MyParticleType::kKaon, corrconfigs.at(30), cent, rndm, kaonPtSum, nKaonWeighted, "covV2PtPID"); + fillFCvnpt(MyParticleType::kKaon, corrconfigs.at(30), cent, rndm, nKaonWeighted, nKaonWeighted, "c22TrackWeightPID"); + } + if (nProtonWeighted > 0.) { + fFCPr->FillProfile("hMeanPt", cent, protonPtSum / nProtonWeighted, nProtonWeighted, rndm); + fFCPr->FillProfile("hMeanPtWeightOne", cent, protonPtSum / nProtonWeighted, 1., rndm); + fillFCvnpt(MyParticleType::kProton, corrconfigs.at(31), cent, rndm, protonPtSum, nProtonWeighted, "covV2PtPID"); + fillFCvnpt(MyParticleType::kProton, corrconfigs.at(31), cent, rndm, nProtonWeighted, nProtonWeighted, "c22TrackWeightPID"); + } + + if (switchsOpts.cfgOutPutPtSpectra.value) { + const double nPairCharged = fGFW->Calculate(corrconfigs.at(0), 0, true).real(); + const double chargedC22 = nPairCharged > 0. ? fGFW->Calculate(corrconfigs.at(0), 0, false).real() / nPairCharged : 0.; + const double pidChargedC22Pi = getPidC22InOneEvent(corrconfigs.at(5), corrconfigs.at(6)); + const double pidKaonC22 = getPidC22InOneEvent(corrconfigs.at(7), corrconfigs.at(8)); + const double pidProtonC22 = getPidC22InOneEvent(corrconfigs.at(9), corrconfigs.at(10)); + if (pidChargedC22Pi > 0. && chargedC22 > 0.) { + registry.fill(HIST("c22PrimeVsc22/Pi"), pidChargedC22Pi, chargedC22); + } + if (pidKaonC22 > 0. && chargedC22 > 0.) { + registry.fill(HIST("c22PrimeVsc22/Ka"), pidKaonC22, chargedC22); + } + if (pidProtonC22 > 0. && chargedC22 > 0.) { + registry.fill(HIST("c22PrimeVsc22/Pr"), pidProtonC22, chargedC22); + } + } + + const double nchDiff = nch * nch - nchSquare; + if (nchDiff > minVal4Float) { + fFCCh->FillProfile("ptSquareAve", cent, (ptSum * ptSum - ptSquareSum) / nchDiff, nchDiff, rndm); + fFCCh->FillProfile("ptSquareAveWeightOne", cent, (ptSum * ptSum - ptSquareSum) / nchDiff, 1., rndm); + fFCCh->FillProfile("ptAve", cent, (nch * ptSum - ptSumw2) / nchDiff, nchDiff, rndm); + fFCCh->FillProfile("ptAveWeightOne", cent, (nch * ptSum - ptSumw2) / nchDiff, 1., rndm); + } + const double pionDiff = nPionWeighted * nPionWeighted - nPionSquare; + if (pionDiff > minVal4Float) { + fFCPi->FillProfile("ptSquareAve", cent, (pionPtSum * pionPtSum - pionPtSquareSum) / pionDiff, pionDiff, rndm); + fFCPi->FillProfile("ptSquareAveWeightOne", cent, (pionPtSum * pionPtSum - pionPtSquareSum) / pionDiff, 1., rndm); + fFCPi->FillProfile("ptAve", cent, (nPionWeighted * pionPtSum - pionPtSumw2) / pionDiff, pionDiff, rndm); + fFCPi->FillProfile("ptAveWeightOne", cent, (nPionWeighted * pionPtSum - pionPtSumw2) / pionDiff, 1., rndm); + } + const double kaonDiff = nKaonWeighted * nKaonWeighted - nKaonSquare; + if (kaonDiff > minVal4Float) { + fFCKa->FillProfile("ptSquareAve", cent, (kaonPtSum * kaonPtSum - kaonPtSquareSum) / kaonDiff, kaonDiff, rndm); + fFCKa->FillProfile("ptSquareAveWeightOne", cent, (kaonPtSum * kaonPtSum - kaonPtSquareSum) / kaonDiff, 1., rndm); + fFCKa->FillProfile("ptAve", cent, (nKaonWeighted * kaonPtSum - kaonPtSumw2) / kaonDiff, kaonDiff, rndm); + fFCKa->FillProfile("ptAveWeightOne", cent, (nKaonWeighted * kaonPtSum - kaonPtSumw2) / kaonDiff, 1., rndm); + } + const double protonDiff = nProtonWeighted * nProtonWeighted - nProtonSquare; + if (protonDiff > minVal4Float) { + fFCPr->FillProfile("ptSquareAve", cent, (protonPtSum * protonPtSum - protonPtSquareSum) / protonDiff, protonDiff, rndm); + fFCPr->FillProfile("ptSquareAveWeightOne", cent, (protonPtSum * protonPtSum - protonPtSquareSum) / protonDiff, 1., rndm); + fFCPr->FillProfile("ptAve", cent, (nProtonWeighted * protonPtSum - protonPtSumw2) / protonDiff, protonDiff, rndm); + fFCPr->FillProfile("ptAveWeightOne", cent, (nProtonWeighted * protonPtSum - protonPtSumw2) / protonDiff, 1., rndm); + } + } + } + PROCESS_SWITCH(PidFlowPtCorr, processMCClosure, "Run truth-level MC flow closure", false); + /** * @brief this function is used to fill THn hist for NUA correction and for NUE correction * @details hist THn: (runNumberIDX, phi, eta, Vz), note that different runNumber will be put in the same hist @@ -2586,7 +2957,7 @@ struct PidFlowPtCorr { int nTot = tracks.size(); auto bc = collision.bc_as(); int runNumber = bc.runNumber(); - double interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 1.e-3; + double interactionRate = getInteractionRate(bc.timestamp(), runNumber); // end init // collision cut @@ -2623,7 +2994,7 @@ struct PidFlowPtCorr { // loop all the track for (const auto& track : tracks) { // track cut - if (!trackSelectedGlobal(track)) { + if (!trackSelectedGlobal(track, false)) { continue; } if (!track.hasITS()) { @@ -2641,9 +3012,14 @@ struct PidFlowPtCorr { // end track cut // fill the THn - registry.fill(HIST("correction/hRunNumberPhiEtaVertex"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); + if (isWithinRefPtRange(track.pt())) { + registry.fill(HIST("correction/hRunNumberPhiEtaVertex"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); + } int pid = this->getPidConfigurable(track); + if (!isWithinPOIPtRange(pid, track.pt())) { + continue; + } switch (pid) { case MyParticleType::kPion: registry.fill(HIST("correction/hRunNumberPhiEtaVertexPion"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); @@ -2676,7 +3052,7 @@ struct PidFlowPtCorr { int nTot = tracks.size(); auto bc = collision.bc_as(); int runNumber = bc.runNumber(); - double interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 1.e-3; + double interactionRate = getInteractionRate(bc.timestamp(), runNumber); // end init /// @note collision cut @@ -2744,7 +3120,7 @@ struct PidFlowPtCorr { int nTot = tracks.size(); auto bc = collision.bc_as(); int runNumber = bc.runNumber(); - double interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 1.e-3; + double interactionRate = getInteractionRate(bc.timestamp(), runNumber); // end init // loop the vector, find the place to put @@ -2830,6 +3206,76 @@ struct PidFlowPtCorr { } PROCESS_SWITCH(PidFlowPtCorr, detectorPidQA, "", true); + /** + * @brief Fill PID response matrix with MC truth PID versus reconstructed PID. + * @note The reconstructed PID uses getPidConfigurable(), so it follows the same PID cuts + * as the flow and efficiency parts of this task. Reco bin Unidentified contains + * tracks that pass quality cuts but fail or ambiguously pass PID selection. + */ + void processPidResponseMatrix(FilteredCollisionsWithMCLabel::iterator const& collision, + aod::BCsWithTimestamps const&, + FilteredTracksWithMCLabel const& tracks, + aod::McParticles const&, + aod::McCollisions const&) + { + if (!switchsOpts.cfgAddPidResponseMatrixHistograms.value) { + return; + } + registry.fill(HIST("hEventCount/processPidResponseMatrix"), 0.5); + if (tracks.size() <= 0) { + return; + } + if (!collision.sel8()) { + return; + } + registry.fill(HIST("hEventCount/processPidResponseMatrix"), 1.5); + + const auto cent = getCentrality(collision); + auto bc = collision.bc_as(); + int runNumber = bc.runNumber(); + double interactionRate = getInteractionRate(bc.timestamp(), runNumber); + + if (!eventSelected(collision, cent, interactionRate, MyFunctionName::funcProcessPidResponseMatrix)) { + return; + } + + for (const auto& track : tracks) { + if (!trackSelectedGlobal(track)) { + continue; + } + if (!track.hasITS()) { + continue; + } + if (!track.hasTPC()) { + continue; + } + if (!trackSelected4ITS(track)) { + continue; + } + if (!trackSelected4TPC(track)) { + continue; + } + if (!track.has_mcParticle()) { + continue; + } + + auto mcParticle = track.mcParticle(); + if (!mcParticle.isPhysicalPrimary() || !particleSelected(mcParticle)) { + continue; + } + + const int truePidBin = getPidResponseTrueBin(mcParticle.pdgCode()); + if (truePidBin < 0) { + continue; + } + const int recoPidBin = getPidResponseRecoBin(getPidConfigurable(track)); + + registry.fill(HIST("pidResponseMatrix/hPidResponseMatrix"), truePidBin, recoPidBin); + registry.fill(HIST("pidResponseMatrix/hPidResponseMatrixRecPtCent"), truePidBin, recoPidBin, track.pt(), cent); + } + } + PROCESS_SWITCH(PidFlowPtCorr, processPidResponseMatrix, "Fill PID response matrix from MC truth and reconstructed PID", false); + /** * @brief this function is used to fill Reco particles in order to calculate pt eff * @note Efficiency = Efficiency(pt, cent) @@ -2856,7 +3302,7 @@ struct PidFlowPtCorr { const auto cent = getCentrality(collision); auto bc = collision.bc_as(); int runNumber = bc.runNumber(); - double interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 1.e-3; + double interactionRate = getInteractionRate(bc.timestamp(), runNumber); if (!eventSelected(collision, cent, interactionRate, MyFunctionName::funcProcessReco)) { return; @@ -2935,7 +3381,7 @@ struct PidFlowPtCorr { for (const auto& oneColl : collisions) { auto bc = oneColl.bc_as(); int runNumber = bc.runNumber(); - double interactionRate = rateFetcher.fetch(ccdb.service, bc.timestamp(), runNumber, "ZNC hadronic") * 1.e-3; + double interactionRate = getInteractionRate(bc.timestamp(), runNumber); double cent = getCentrality(oneColl); auto groupedTracks = tracks.sliceBy(perCollision, oneColl.globalIndex()); From 0f56e6d236c0f20795452dfba14cbd5a00c7a43a Mon Sep 17 00:00:00 2001 From: Gyula Bencedi Date: Fri, 31 Jul 2026 23:34:18 +0200 Subject: [PATCH 64/71] [PWGLF] Fix place of histogram filling (#17279) --- .../GlobalEventProperties/flattenictyPikp.cxx | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx b/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx index 40577807823..c81c941d864 100644 --- a/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx +++ b/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx @@ -624,6 +624,17 @@ struct FlattenictyPikp { registryQC.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelVtxZ + 1, "Vtx-z pos"); registryQC.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelINELgt0 + 1, "INEL>0"); registryQC.get(HIST("Events/hEvtSel"))->GetXaxis()->SetBinLabel(evtSelRCTFlagChecker + 1, "RCT Flag Checker"); + // Track counter + registryQC.add("Tracks/hTrkSel", "Number of tracks; Cut; #Tracks Passed Cut", {kTH1F, {{nTrkSel, 0, nTrkSel}}}); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelAll + 1, "All"); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelEta + 1, "Eta"); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelPt + 1, "Pt"); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelDCA + 1, "DCA"); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelCustomDCA + 1, "Custom DCA sel."); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkNRowsTPC + 1, "trkNRowsTPC"); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelNClsFound + 1, "NClsTPCFound"); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelNClsPID + 1, "NClsTPCPid"); + registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelTPCBndr + 1, "TPC Boundary"); // Number of tracks vs centrality registryQC.add("Events/hNchVsCent", "Measured Nch vs Cent; centrality; Nch (|#eta|<0.8)", {kTH2F, {nChAxis, multAxis}}); registryQC.add("Tracks/hPtRes", "#it{p}_{T} resolution;;(#it{p}_{T}_{rec} - #it{p}_{T}_{gen})/#it{p}_{T}_{gen};", kTH2F, {ptAxis, {100, -1.0, 1.0}}); @@ -640,17 +651,6 @@ struct FlattenictyPikp { registryQC.print(); if (doprocessFlat) { - // Track counter - registryData.add("Tracks/hTrkSel", "Number of tracks; Cut; #Tracks Passed Cut", {kTH1F, {{nTrkSel, 0, nTrkSel}}}); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelAll + 1, "All"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelEta + 1, "Eta"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelPt + 1, "Pt"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelDCA + 1, "DCA"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelCustomDCA + 1, "Custom DCA sel."); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkNRowsTPC + 1, "trkNRowsTPC"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelNClsFound + 1, "NClsTPCFound"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelNClsPID + 1, "NClsTPCPid"); - registryData.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelTPCBndr + 1, "TPC Boundary"); // V0 counter registryData.add("Tracks/V0qa/hV0Sel", "Number of V0s; Cut; #Tracks Passed Cut", {kTH1F, {{nV0Sel, 0, nV0Sel}}}); registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelAll + 1, "All"); @@ -1443,20 +1443,20 @@ struct FlattenictyPikp { template bool isGoodTrack(T const& track, const float magfield) { - registryData.fill(HIST("Tracks/hTrkSel"), trkSelAll); + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelAll); if (std::abs(track.eta()) > trkSelOpt.trkEtaMax) { return false; } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelEta); + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelEta); if (track.pt() < trkSelOpt.trkPtMin) { return false; } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelPt); + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelPt); if constexpr (selDCA) { if (!isDCAxyCut(track)) { return false; } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelDCA); + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelDCA); if (defOpt.applyDCAParam) { if (defOpt.applyDCAParamFromCCDB) { if (!isDCAParamCut(track)) { @@ -1467,22 +1467,22 @@ struct FlattenictyPikp { return false; } } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelCustomDCA); + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelCustomDCA); } } if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) { return false; } - registryData.fill(HIST("Tracks/hTrkSel"), trkNRowsTPC); + registryQC.fill(HIST("Tracks/hTrkSel"), trkNRowsTPC); if (trkSelOpt.applyNcl && track.tpcNClsFound() < trkSelOpt.nclTPCMin) { return false; } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelNClsFound); + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelNClsFound); if (trkSelOpt.applyNclPID && track.tpcNClsPID() < trkSelOpt.nclPidTPCMin) { return false; } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelNClsPID); + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelNClsPID); float phimodn = track.phi(); phiMod(phimodn, magfield, track.sign()); @@ -1495,7 +1495,7 @@ struct FlattenictyPikp { if (defOpt.fillNclVsPhiCutQaHist) { fillNclVsPhiCutQaHist(track, phimodn); } - registryData.fill(HIST("Tracks/hTrkSel"), trkSelTPCBndr); + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelTPCBndr); return true; } From 94478034e5de3eb37b8f3c06689431b948e58cf2 Mon Sep 17 00:00:00 2001 From: Kai Cui <129373281+kcui1@users.noreply.github.com> Date: Sat, 1 Aug 2026 01:52:52 +0200 Subject: [PATCH 65/71] [PWGLF] Fix MC mask bug hStrangeCorrelation.cxx (#17278) --- .../Tasks/Strangeness/hStrangeCorrelation.cxx | 52 ++++++++++++++++--- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx index d5d7d52e9fd..62f1cf8ab5a 100644 --- a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx +++ b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx @@ -213,7 +213,7 @@ struct HStrangeCorrelation { Configurable minITSClustersForDaughterTracks{"minITSClustersForDaughterTracks", 1, "Minimum number of ITS clusters for V0 daughter tracks"}; Configurable requireDCAzCut{"requireDCAzCut", false, "require DCAz cut for trigger and associated primary tracks"}; Configurable doITSChi2Selection{"doITSChi2Selection", false, "require ITS chi2 cut for trigger and associated primary tracks"}; - Configurable checkForITSTPCMissmatchMC{"checkForITSTPCMissmatchMC", false, "if true, reject tracks with MC mask 13 (ITS-TPC mismatch) for trigger and associated primary tracks"}; + Configurable checkForITSTPCMissmatchMC{"checkForITSTPCMissmatchMC", false, "if true, reject tracks with MC mask bit 13 (ITS-TPC mismatch) for trigger and associated primary tracks"}; // --- Trigger: DCA variation from basic formula: |DCAxy| < 0.004f + (0.013f / pt) Configurable dcaXYconstant{"dcaXYconstant", 0.004, "[0] in |DCAxy| < [0]+[1]/pT"}; Configurable dcaXYpTdep{"dcaXYpTdep", 0.013, "[1] in |DCAxy| < [0]+[1]/pT"}; @@ -839,7 +839,7 @@ struct HStrangeCorrelation { if (!isValidTrigger(trigg, triggerTrack.isLeading())) { continue; } - if (trackSelection.checkForITSTPCMissmatchMC && triggerTrack.mcMask() == 13) { + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { continue; } float efficiencyTrigg = 1.0f; @@ -1218,6 +1218,9 @@ struct HStrangeCorrelation { if (!isValidTrigger(trigg, triggerTrack.isLeading())) { continue; } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { + continue; + } float efficiencyTrigg = 1.0f; float efficiencyTriggError = 0.0f; @@ -1535,6 +1538,9 @@ struct HStrangeCorrelation { if (!isValidTrigger(trigg, triggerTrack.isLeading())) { continue; } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { + continue; + } float efficiencyTrigger = 1.0f; float efficiencyTriggerError = 0.0f; @@ -1599,6 +1605,9 @@ struct HStrangeCorrelation { if (!isValidAssocHadron(assoc)) { continue; } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(assocTrack.mcMask(), 13)) { + continue; + } if (doAssocPhysicalPrimary && !assocTrack.mcPhysicalPrimary()) { continue; } @@ -2411,6 +2420,9 @@ struct HStrangeCorrelation { if (!isValidTrigger(track, triggerTrack.isLeading())) { continue; } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { + continue; + } auto binNumber = histos.get(HIST("axes/hPtTriggerAxis"))->FindFixBin(track.pt()) - 1; SETBIT(triggerPresenceMap[collision.globalIndex()], binNumber); } @@ -2455,6 +2467,9 @@ struct HStrangeCorrelation { if (!isValidTrigger(track, triggerTrack.isLeading())) { continue; } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { + continue; + } histos.fill(HIST("hDCAzTriggerHadron"), track.dcaZ(), track.pt()); histos.fill(HIST("hDCAxyTriggerHadron"), track.dcaXY(), track.pt()); float efficiency = 1.0f; @@ -2479,6 +2494,9 @@ struct HStrangeCorrelation { if (!isValidAssocHadron(assoc)) { continue; } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(assocTrack.mcMask(), 13)) { + continue; + } float efficiency = 1.0f; float purity = 1.0f; histos.fill(HIST("hDCAzAssociatedHadron"), assoc.dcaZ(), assoc.pt()); @@ -2636,6 +2654,9 @@ struct HStrangeCorrelation { if (!isValidTrigger(track, triggerTrack.isLeading())) { continue; } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { + continue; + } histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), cent); histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { @@ -2791,6 +2812,9 @@ struct HStrangeCorrelation { if (!isValidTrigger(track, triggerTrack.isLeading())) { continue; } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { + continue; + } histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), cent); histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { @@ -2849,6 +2873,9 @@ struct HStrangeCorrelation { if (!isValidAssocHadron(pionTrack)) { continue; } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(pion.mcMask(), 13)) { + continue; + } histos.fill(HIST("hPionEtaVsPtAllSelected"), pionTrack.pt(), pionTrack.eta(), collision.centFT0M()); if (doAssocPhysicalPrimary && !pion.mcPhysicalPrimary()) { @@ -2870,6 +2897,9 @@ struct HStrangeCorrelation { if (!isValidTrigger(track, triggerTrack.isLeading())) { continue; } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerTrack.mcMask(), 13)) { + continue; + } histos.fill(HIST("hTriggerAllSelectedEtaVsPt"), track.pt(), track.eta(), collision.centFT0M()); histos.fill(HIST("hTriggerPtResolution"), track.pt(), triggerTrack.mcOriginalPt()); if (masterConfigurations.doTriggPhysicalPrimary && !triggerTrack.mcPhysicalPrimary()) { @@ -3504,6 +3534,8 @@ struct HStrangeCorrelation { double getatrigger = triggerParticle.eta(); double gphitrigger = triggerParticle.phi(); double pttrigger = triggerParticle.pt(); + auto const* triggerPdg = pdgDB->GetParticle(triggerParticle.pdgCode()); + const double triggerCharge = triggerPdg ? triggerPdg->Charge() : 0.; auto const& mother = triggerParticle.mothers_first_as(); auto globalIndex = mother.globalIndex(); static_for<0, 8>([&](auto i) { // associated loop @@ -3531,12 +3563,18 @@ struct HStrangeCorrelation { histos.fill(HIST("ClosureTest/sameEvent/") + HIST(Particlenames[Index]), computeDeltaPhi(gphitrigger, gphiassoc), deltaeta, ptassoc, pttrigger, bestCollisionVtxZ, bestCollisionCentpercentile); } if (i < 3 && TESTBIT(doCorrelation, i) && masterConfigurations.doCorrelationsHadronV0daughter) { - auto assocParticleDaugters = assocParticle.daughters_as(); - for (const auto& assocParticleDaugter : assocParticleDaugters) { - if (((assocParticleDaugter.pdgCode() == PDG_t::kPiPlus || assocParticleDaugter.pdgCode() == PDG_t::kProton) && (triggerParticle.pdgCode() > 0)) || ((assocParticleDaugter.pdgCode() == PDG_t::kPiMinus || assocParticleDaugter.pdgCode() == PDG_t::kProtonBar) && (triggerParticle.pdgCode() < 0))) { - histos.fill(HIST("ClosureTest/sameEvent/") + HIST(Particlenames[Index]) + HIST("_SameSignDaughter"), computeDeltaPhi(gphitrigger, assocParticleDaugter.phi()), getatrigger - assocParticleDaugter.eta(), assocParticleDaugter.pt(), pttrigger, bestCollisionVtxZ, bestCollisionCentpercentile); + auto const assocParticleDaughters = assocParticle.daughters_as(); + for (const auto& assocParticleDaughter : assocParticleDaughters) { + auto const* daughterPdg = pdgDB->GetParticle(assocParticleDaughter.pdgCode()); + const double daughterCharge = daughterPdg ? daughterPdg->Charge() : 0.; + // Neutral daughters, including pi0, do not correspond to reconstructed V0 daughter tracks. + if (triggerCharge == 0. || daughterCharge == 0.) { + continue; + } + if (triggerCharge * daughterCharge > 0.) { + histos.fill(HIST("ClosureTest/sameEvent/") + HIST(Particlenames[Index]) + HIST("_SameSignDaughter"), computeDeltaPhi(gphitrigger, assocParticleDaughter.phi()), getatrigger - assocParticleDaughter.eta(), assocParticleDaughter.pt(), pttrigger, bestCollisionVtxZ, bestCollisionCentpercentile); } else { - histos.fill(HIST("ClosureTest/sameEvent/") + HIST(Particlenames[Index]) + HIST("_OppSignDaughter"), computeDeltaPhi(gphitrigger, assocParticleDaugter.phi()), getatrigger - assocParticleDaugter.eta(), assocParticleDaugter.pt(), pttrigger, bestCollisionVtxZ, bestCollisionCentpercentile); + histos.fill(HIST("ClosureTest/sameEvent/") + HIST(Particlenames[Index]) + HIST("_OppSignDaughter"), computeDeltaPhi(gphitrigger, assocParticleDaughter.phi()), getatrigger - assocParticleDaughter.eta(), assocParticleDaughter.pt(), pttrigger, bestCollisionVtxZ, bestCollisionCentpercentile); } } } From 7372216a24032a315a028b523283beae12554d8a Mon Sep 17 00:00:00 2001 From: omvazque Date: Fri, 31 Jul 2026 18:05:23 -0600 Subject: [PATCH 66/71] [PWGLF] Adds MC QA hists. + selection on particle vertex (#17280) --- PWGLF/Tasks/Nuspex/piKpRAA.cxx | 267 ++++++++++++++++++++++++--------- 1 file changed, 199 insertions(+), 68 deletions(-) diff --git a/PWGLF/Tasks/Nuspex/piKpRAA.cxx b/PWGLF/Tasks/Nuspex/piKpRAA.cxx index 2ca5f0ec7e9..e1ed76e0779 100644 --- a/PWGLF/Tasks/Nuspex/piKpRAA.cxx +++ b/PWGLF/Tasks/Nuspex/piKpRAA.cxx @@ -143,6 +143,7 @@ struct PiKpRAA { Configurable maxPt{"maxPt", 10000000000.0, "maximum pt of the tracks"}; Configurable nSigmaDCAxy{"nSigmaDCAxy", 1.0, "nSigma DCAxy selection"}; Configurable nSigmaDCAz{"nSigmaDCAz", 1.0, "nSigma DCAz selection"}; + Configurable particleVtxSel{"particleVtxSel", 5.0, "selection on the distance between particle creation vtx"}; Configurable minNCrossedRows{"minNCrossedRows", 70, "minimum number of crossed rows"}; Configurable minNcl{"minNcl", 135, "minimum number of clusters for primary-particle selection"}; @@ -499,7 +500,14 @@ struct PiKpRAA { } if (doprocessSim) { + registry.add("EventCounterMC", ";;Events", kTH1F, {{5, 0, 5}}); registry.add("zPosMC", "Generated Events With at least One Rec. Collision + Sel. criteria;;Entries;", kTH1F, {axisZpos}); + registry.add("EtaMCParAllMCColl", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Pion", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Kaon", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Proton", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Electron", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Rest", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); registry.add("dcaVsPtPiDec", "Secondary pions from decays;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); registry.add("dcaVsPtPrDec", "Secondary protons from decays;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); registry.add("dcaVsPtPiMat", "Secondary pions from material interactions;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); @@ -508,11 +516,8 @@ struct PiKpRAA { registry.add("DCAzVsPtWithSelection", ";#it{p}_{T} (GeV/#it{c});DCA_{z} (cm);", kTH2F, {{axisPtFineFixedWidth}, {axisDCAxy}}); registry.add("CentralityVsBCVsFT0VsTVXVsEvSel", "All=1 | BC=2 | FT0=3 | TVX=4 | EvSel=5;;Status;", kTH2F, {{axisCent}, {5, 0.5, 5.5}}); - - // MC events passing the TVX requirement - registry.add("NchMCcentVsTVX", ";Passed(=1.5) NOT Passed(=0.5);", kTH2F, {axisNch, {2, 0, 2}}); - - registry.add("NumberOfRecoCollisions", "Number of times Gen. Coll.are reconstructed;N;Entries", kTH1F, {{10, -0.5, 9.5}}); + registry.add("NumOfRecColl", "Num. of times a MC evt. is reconstructed;N;Entries", kTH1F, {{5, -0.5, 4.5}}); + registry.add("NumOfRecCollVsNContributors", "Num. of times a MC evt. is reconstructed VS Num. of PV contributors;Number of times a MC event is reconstructed;Number of tracks used for the PV", kTH2F, {{5, -0.5, 4.5}, axisNch}); // Pt resolution registry.add("PtResolution", "p_{T} resolution;;(pt_{rec} - pt_{gen})/pt_{gen};", kTH2F, {axisPt, {100, -1.0, 1.0}}); @@ -535,8 +540,10 @@ struct PiKpRAA { registry.add("NchMCVsCent", "Generated Nch v.s. Centrality (At least Once Rec. Coll. + Sel. criteria);;Gen. Nch MC", kTH2F, {axisCent, axisNch}); // Needed to measure Event Loss - registry.add("NchMC_WithRecoEvt", "Generated Nch of Evts With at least one Rec. Coll. + Sel. criteria;Gen. Nch MC;Entries", kTH1F, {axisNch}); - registry.add("NchMC_AllGen", "Generated Nch of All Gen. Evts.;Gen. Nch;Entries", kTH1F, {axisNch}); + registry.add("NchMC_WithRecoEvt", "Gen Nch from MC event associated with the Rec. Coll (with largest Num. of contributors) + Evt. Sel.;Gen Nch MC;Entries", kTH1F, {axisNch}); + registry.add("NchMC_AllGen", "Gen Nch of ALL MC events;Gen. Nch;Entries", kTH1F, {axisNch}); + registry.add("NchMC_WithRecColl", "Gen Nch from MC event associated with a Rec. Coll (at least once);Gen. Nch;Entries", kTH1F, {axisNch}); + registry.add("NchMC_WithOnlyRecColl", "Gen Nch from MC event associated with a ONLY ONE Rec. Coll from last Num. of Contributors;Gen. Nch;Entries", kTH1F, {axisNch}); // Needed to measure Event Splitting registry.add("Centrality_WRecoEvt", "Generated Events With at least One Rec. Collision And NO Sel. criteria;;Entries", kTH1F, {axisCent}); @@ -560,6 +567,13 @@ struct PiKpRAA { registry.add("MCclosure_PtPiVsNchMC", "Gen Evts With at least one Rec. Coll. + Sel. criteria 4 MC closure;;Gen. Nch (|#eta|<0.8);", kTH2F, {axisPt, axisNch}); registry.add("MCclosure_PtKaVsNchMC", "Gen Evts With at least one Rec. Coll. + Sel. criteria 4 MC closure;;Gen. Nch (|#eta|<0.8);", kTH2F, {axisPt, axisNch}); registry.add("MCclosure_PtPrVsNchMC", "Gen Evts With at least one Rec. Coll. + Sel. criteria 4 MC closure;;Gen. Nch (|#eta|<0.8);", kTH2F, {axisPt, axisNch}); + + auto hMcCouter = registry.get(HIST("EventCounterMC")); + auto* xMcCounter = hMcCouter->GetXaxis(); + xMcCounter->SetBinLabel(1, "All MC Coll"); + xMcCounter->SetBinLabel(2, "Rec Coll with nContributors > 0"); + xMcCounter->SetBinLabel(3, "Rec Coll With largest nContributors"); + xMcCounter->SetBinLabel(4, "Rec TVX-triggered Coll"); } LOG(info) << "\trequireGoodRct=" << requireGoodRct.value; @@ -1228,15 +1242,16 @@ struct PiKpRAA { const auto& kLowEta = (std::vector)vecLowEta; const auto& kHighEta = (std::vector)vecUpEta; + registry.fill(HIST("EventCounterMC"), 0.5); //--------------------------- - // Only INEL > 0 generated collisions - // By counting number of primary charged particles in |eta| < 1 + // Nch counters in different pseudorapidity intervals //--------------------------- int nChMC{0}; int nChMCTPCAcc{0}; int nChFT0A{0}; int nChFT0C{0}; + for (const auto& particle : mcParticles) { auto charge{0.}; @@ -1266,7 +1281,28 @@ struct PiKpRAA { continue; } + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + const float eta{particle.eta()}; + registry.fill(HIST("EtaMCParAllMCColl"), eta); + + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("EtaMCParAllMCColl_Pion"), eta); + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("EtaMCParAllMCColl_Kaon"), eta); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("EtaMCParAllMCColl_Proton"), eta); + } else if (particle.pdgCode() == PDG_t::kElectron || particle.pdgCode() == PDG_t::kPositron) { + registry.fill(HIST("EtaMCParAllMCColl_Electron"), eta); + } else { + registry.fill(HIST("EtaMCParAllMCColl_Rest"), eta); + } // TVX requirement if (eta > KminFT0A && eta < KmaxFT0A) { @@ -1290,25 +1326,23 @@ struct PiKpRAA { } //--------------------------- - // Select only events with at least one charged particle in the FT0A and FT0C acceptances? + // Selects MC events with at least one charged particle in the FT0A & FT0C //--------------------------- if (selTVXMC) { if (!(nChFT0A > KzeroInt && nChFT0C > KzeroInt)) { - registry.fill(HIST("NchMCcentVsTVX"), nChMC, 0.5); return; } - registry.fill(HIST("NchMCcentVsTVX"), nChMC, 1.5); } //--------------------------- - // Select only MC events with |Vtx Z| < 10 cm? + // Selects MC events with |Zvtx| < zVtx_Cut //--------------------------- if (isZvtxPosSelMC && (std::fabs(mccollision.posZ()) > posZcut)) { return; } //--------------------------- - // Select only INEL > 0 generated events? + // Selects INEL > 0 MC evets //--------------------------- if (selINELgt0) { if (!(nChMC > KzeroInt)) { @@ -1318,9 +1352,9 @@ struct PiKpRAA { //--------------------------- // All Generated events irrespective of whether there is an associated reconstructed collision - // Consequently, the centrality being a reconstructed quantity, might not always be available + // Consequently, the centrality being a reconstructed quantity, is not always be available // Therefore it is expressed as a function of the generated pT and the generated Nch in ∣eta∣ < 0.8 - // This is used for the denominator of the signal loss correction + // This is used for the denominator of the SIGNAL LOSS correction // Also for MC closure: True Pt vs Generated Nch //--------------------------- for (const auto& particle : mcParticles) { @@ -1346,7 +1380,7 @@ struct PiKpRAA { continue; } - // Select particle based on its charge + // Selects particle based on its charge if (trackSelections.signCharge.value == "Positive" && charge < Kzero) { continue; } @@ -1354,39 +1388,44 @@ struct PiKpRAA { continue; } - // Is it a primary particle? - bool isPrimary{true}; + // Selects only primary particles if (!particle.isPhysicalPrimary()) { - isPrimary = false; - } - - if (isPrimary) { - if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { - registry.fill(HIST("PtPiVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); - registry.fill(HIST("MCclosure_PtMCPiVsNchMC"), particle.pt(), nChMCTPCAcc); - } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { - registry.fill(HIST("PtKaVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); - registry.fill(HIST("MCclosure_PtMCKaVsNchMC"), particle.pt(), nChMCTPCAcc); - } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { - registry.fill(HIST("PtPrVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); - registry.fill(HIST("MCclosure_PtMCPrVsNchMC"), particle.pt(), nChMCTPCAcc); - } else { - continue; - } + continue; + } + + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("PtPiVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); + registry.fill(HIST("MCclosure_PtMCPiVsNchMC"), particle.pt(), nChMCTPCAcc); + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("PtKaVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); + registry.fill(HIST("MCclosure_PtMCKaVsNchMC"), particle.pt(), nChMCTPCAcc); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("PtPrVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); + registry.fill(HIST("MCclosure_PtMCPrVsNchMC"), particle.pt(), nChMCTPCAcc); + } else { + continue; } } // Loop over Generated Particles //--------------------------- - // This is used for the denominator of the event loss correction + // This is used for the denominator of the EVENT LOSS correction // Only charge particles within tpcNchAcceptance and without pT selection //--------------------------- registry.fill(HIST("NchMC_AllGen"), nChMCTPCAcc); //--------------------------- - // How many times the Generated evet was reconstrued? + // How many times was the MC event reconstrued? //--------------------------- const auto& nRecColls{collisions.size()}; - registry.fill(HIST("NumberOfRecoCollisions"), nRecColls); + registry.fill(HIST("NumOfRecColl"), nRecColls); //--------------------------- // Only Generated evets with at least one reconstrued collision @@ -1394,8 +1433,8 @@ struct PiKpRAA { if (nRecColls > KzeroInt) { //--------------------------- - // Looks for the collision with the largest number of contributors - // The selected collisions is identified with its index (bestCollisionIndex) + // Looks for the collision with the largest number of tracks contributing to the primary vertex reconstruction + // The selected collision is identified by its global index (bestCollisionIndex) //--------------------------- int biggestNContribs{-1}; int bestCollisionIndex{-1}; @@ -1412,15 +1451,12 @@ struct PiKpRAA { centrality = -999.0; } + registry.fill(HIST("NumOfRecCollVsNContributors"), nRecColls, collision.numContrib()); + if (selHasFT0 && !collision.has_foundFT0()) { continue; } - if (biggestNContribs < collision.numContrib()) { - biggestNContribs = collision.numContrib(); - bestCollisionIndex = collision.globalIndex(); - } - if (selHasBC && !collision.has_foundBC()) { continue; } @@ -1457,12 +1493,89 @@ struct PiKpRAA { continue; } + // Gets the index of the collision with the largest number of contributors + if (biggestNContribs < collision.numContrib()) { + biggestNContribs = collision.numContrib(); + bestCollisionIndex = collision.globalIndex(); + } + //--------------------------- - // Needed to calculate denominator of the Event Splitting correction + // Needed to calculate denominator of the EVENT SPLITTING correction + // MC Collisions that are reconstructed more than one will be stored here //--------------------------- registry.fill(HIST("Centrality_AllRecoEvt"), centrality); } + //--------------------------- + // This is only for QA purposes + //--------------------------- + for (const auto& collision : collisions) { + + int mcNchInTPCAcc{0}; + for (const auto& particle : mcParticles) { + + auto charge{0.}; + // Get the MC particle + const auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < KminCharge) { + continue; + } + + // Is it a primary particle? + if (!particle.isPhysicalPrimary()) { + continue; + } + + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + + const float eta{particle.eta()}; + if (std::abs(eta) < tpcNchAcceptance) { + mcNchInTPCAcc++; + } + } + + //--------------------------- + // All collisions with N contributors > 0 + //--------------------------- + if (collision.numContrib() > KzeroInt) { + registry.fill(HIST("EventCounterMC"), 1.5); + // To calculate the amount of charged-primary MC particles (|eta|<0.5) + // that belongs to a MC event that was reconstructed at least once + registry.fill(HIST("NchMC_WithRecColl"), mcNchInTPCAcc); + } + + //--------------------------- + // Records only one collision with the largest number of contributors + //--------------------------- + if (bestCollisionIndex == collision.globalIndex()) { + registry.fill(HIST("EventCounterMC"), 2.5); + // To calculate the amount of charged-primary MC particles (|eta|<0.5) + // that belongs to a MC event that was reconstructed + // and only from the with the largest number of contributors + registry.fill(HIST("NchMC_WithOnlyRecColl"), mcNchInTPCAcc); + } + + //--------------------------- + // TVX-triggered collision + //--------------------------- + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + registry.fill(HIST("EventCounterMC"), 3.5); + } + } + //--------------------------- // Loop over the reconstructed collisions // Only that one with the largest number of contributors is considered @@ -1585,9 +1698,9 @@ struct PiKpRAA { return; } - registry.fill(HIST("Centrality_WRecoEvtWSelCri"), centrality); - registry.fill(HIST("NchMCVsCent"), centrality, nChMCTPCAcc); - registry.fill(HIST("NchMC_WithRecoEvt"), nChMCTPCAcc); // Numerator of event loss correction + registry.fill(HIST("Centrality_WRecoEvtWSelCri"), centrality); // To calculate numerator of EVENT SPLITTING + registry.fill(HIST("NchMCVsCent"), centrality, nChMCTPCAcc); // Needed for the mapping betwee MC Nch and centrality + registry.fill(HIST("NchMC_WithRecoEvt"), nChMCTPCAcc); // Numerator of EVENT LOSS correction registry.fill(HIST("zPos"), collision.posZ()); registry.fill(HIST("Centrality"), centrality); @@ -1644,24 +1757,29 @@ struct PiKpRAA { } // Is it a primary particle? - bool isPrimary{true}; if (!particle.isPhysicalPrimary()) { - isPrimary = false; + continue; } - if (isPrimary) { - if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { - registry.fill(HIST("PtPiVsCentMC_WithRecoEvt"), particle.pt(), centrality); // Denominator of tracking efficiency - registry.fill(HIST("PtPiVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); // Numerator of signal loss - } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { - registry.fill(HIST("PtKaVsCentMC_WithRecoEvt"), particle.pt(), centrality); - registry.fill(HIST("PtKaVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); - } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { - registry.fill(HIST("PtPrVsCentMC_WithRecoEvt"), particle.pt(), centrality); - registry.fill(HIST("PtPrVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); - } else { - continue; - } + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("PtPiVsCentMC_WithRecoEvt"), particle.pt(), centrality); // Denominator of tracking efficiency + registry.fill(HIST("PtPiVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); // Numerator of signal loss + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("PtKaVsCentMC_WithRecoEvt"), particle.pt(), centrality); + registry.fill(HIST("PtKaVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("PtPrVsCentMC_WithRecoEvt"), particle.pt(), centrality); + registry.fill(HIST("PtPrVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); + } else { + continue; } } // Loop over generated particles per generated collision @@ -1733,6 +1851,15 @@ struct PiKpRAA { } if (isPrimary && !isDecay && !isMaterial) { + + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + if (isPi && !isPr) { registry.fill(HIST("dcaVsPtPi"), track.pt(), track.dcaXY(), centrality); } @@ -1829,12 +1956,16 @@ struct PiKpRAA { registry.fill(HIST("NclVsEtaPID"), track.eta(), track.tpcNClsPID()); registry.fill(HIST("NclVsEtaPIDp"), track.eta(), track.tpcNClsPID()); - bool isPrimary{false}; - if (particle.isPhysicalPrimary()) { - isPrimary = true; + // Rejects non-physical primary particle + if (!particle.isPhysicalPrimary()) { + continue; } - if (!isPrimary) { + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { continue; } From 9c8d91e72ae98f77090fab237b7eaaac1861e7a2 Mon Sep 17 00:00:00 2001 From: Roman Lietava Date: Sat, 1 Aug 2026 04:29:58 +0200 Subject: [PATCH 67/71] [PWGLF] adding info for centrality cloures (#17267) --- PWGLF/DataModel/LFNonPromptCascadeTables.h | 11 +++- PWGLF/Tasks/Strangeness/nonPromptCascade.cxx | 57 +++++++++++++++----- 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/PWGLF/DataModel/LFNonPromptCascadeTables.h b/PWGLF/DataModel/LFNonPromptCascadeTables.h index 9b503213edf..6a69bc8016c 100644 --- a/PWGLF/DataModel/LFNonPromptCascadeTables.h +++ b/PWGLF/DataModel/LFNonPromptCascadeTables.h @@ -128,7 +128,10 @@ DECLARE_SOA_COLUMN(NoSameBunchPileup, noSameBunchPileup, bool); DECLARE_SOA_COLUMN(GlobalBC, globalBC, uint64_t); DECLARE_SOA_COLUMN(PtGen, ptGen, float); DECLARE_SOA_COLUMN(PtRec, ptRec, float); +DECLARE_SOA_COLUMN(EtaGen, etaGen, float); +DECLARE_SOA_COLUMN(EtaRec, etaRec, float); DECLARE_SOA_COLUMN(MultGen, multGen, int); +DECLARE_SOA_COLUMN(MultGenFT0, multGenFT0, int); } // namespace NPCascadeTable DECLARE_SOA_TABLE(NPCascTable, "AOD", "NPCASCTABLE", @@ -455,8 +458,11 @@ DECLARE_SOA_TABLE(NPCascTableGen, "AOD", "NPCASCTABLEGen", DECLARE_SOA_TABLE(NPMCChargedTable, "AOD", "NPMCChargedTABLE", NPCascadeTable::PtGen, NPCascadeTable::PtRec, + NPCascadeTable::EtaGen, + NPCascadeTable::EtaRec, NPCascadeTable::MultNTracksNP, - NPCascadeTable::MultGen); + NPCascadeTable::MultGen, + NPCascadeTable::MultGenFT0); DECLARE_SOA_TABLE(NPCollisionTable, "AOD", "NPCollisionTABLE", NPCascadeTable::RunNumber, NPCascadeTable::GlobalBC, @@ -469,7 +475,8 @@ DECLARE_SOA_TABLE(NPCollisionTable, "AOD", "NPCollisionTABLE", DECLARE_SOA_INDEX_COLUMN_FULL(NPCollision, npCollision, int32_t, NPCollisionTable, ""); DECLARE_SOA_TABLE(NPRecoChargedCand, "AOD", "NPRecoChargedCand", NPCollisionId, - NPCascadeTable::PtRec); + NPCascadeTable::PtRec, + NPCascadeTable::EtaRec); } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFNONPROMPTCASCADETABLES_H_ diff --git a/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx b/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx index 8d2790a38a0..5ef6d65cd3c 100644 --- a/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx +++ b/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx @@ -305,7 +305,6 @@ struct NonPromptCascadeTask { AxisSpec nTracksAxis = {100, 0., 100., "NTracksGlobal"}; AxisSpec nTracksAxisMC = {100, 0., 100., "NTracksMC"}; std::vector centBinning; - std::vector multBinning; std::vector trackBinning; std::vector runsBinning; double cent = -0.0; @@ -841,6 +840,29 @@ struct NonPromptCascadeTask { return q != 0; }; + static constexpr float MinEtaFT0A = 3.5f; + static constexpr float MaxEtaFT0A = 4.9f; + static constexpr float MinEtaFT0C = -3.3f; + static constexpr float MaxEtaFT0C = -2.1f; + static constexpr float InvalidEta = -999.f; + + auto isAcceptedMCParticleFT0 = [&](auto const& mcp) { + if (!mcp.isPhysicalPrimary()) { + return false; + } + + const float eta = mcp.eta(); + if (!((eta > MinEtaFT0A && eta < MaxEtaFT0A) || (eta > MinEtaFT0C && eta < MaxEtaFT0C))) { + return false; + } + + int q = 0; + if (auto pdg = pdgDB->GetParticle(mcp.pdgCode())) { + q = static_cast(std::round(pdg->Charge() / 3.0)); + } + return q != 0; + }; + // ------------------------------------------------------------ // Helper: accepted reconstructed track // Use same cuts as data. @@ -866,6 +888,7 @@ struct NonPromptCascadeTask { // mcid: mc collision row of mc particle // ------------------------------------------------------------ std::vector mcMult(mcCollisions.size(), 0); + std::vector mcMultFT0(mcCollisions.size(), 0); // std::cout << "mcCollisions size:" << mcCollisions.size() << std::endl; for (auto const& mcp : mcParticles) { const int mcid = mcp.mcCollisionId(); @@ -874,10 +897,12 @@ struct NonPromptCascadeTask { LOG(info) << "0 This should never happen ?"; continue; } - if (!isAcceptedMCParticle(mcp)) { - continue; + if (isAcceptedMCParticle(mcp)) { + ++mcMult[mcid]; + } + if (isAcceptedMCParticleFT0(mcp)) { + ++mcMultFT0[mcid]; } - ++mcMult[mcid]; } // ------------------------------------------------------------ @@ -990,11 +1015,12 @@ struct NonPromptCascadeTask { const int mcCollId = col.mcCollisionId(); const float multReco = recoMultDense[dIdx]; const float ptReco = trk.pt(); + const float etaReco = trk.eta(); if (mcCollId < 0 || static_cast(mcCollId) >= mcCollisions.size()) { if (writeRecoCollision[dIdx]) { // Fake: accepted reco track whose reconstructed collision has no valid MC collision label. - NPMCNTable(-1.f, ptReco, multReco, -1.f); + NPMCNTable(-1.f, ptReco, InvalidEta, etaReco, multReco, -1.f, -1.f); } continue; } @@ -1003,7 +1029,7 @@ struct NonPromptCascadeTask { if (mcPid < 0 || static_cast(mcPid) >= mcParticles.size()) { if (writeMcCollision[mcCollId]) { // Fake: accepted reco track with invalid or missing MC particle label. - NPMCNTable(-2.f, ptReco, multReco, -2.f); + NPMCNTable(-2.f, ptReco, InvalidEta, etaReco, multReco, -2.f, mcMultFT0[mcCollId]); } continue; } @@ -1014,7 +1040,7 @@ struct NonPromptCascadeTask { if (mcParCollId != mcCollId) { if (writeMcCollision[mcCollId]) { // Fake: reco collision and particle label point to different MC collisions. - NPMCNTable(-3.f, ptReco, multReco, -3.f); + NPMCNTable(-3.f, ptReco, InvalidEta, etaReco, multReco, -3.f, mcMultFT0[mcCollId]); } continue; } @@ -1022,7 +1048,7 @@ struct NonPromptCascadeTask { if (!isAcceptedMCParticle(mcPar)) { if (writeMcCollision[mcCollId]) { // Feed-in: accepted reco track matched to truth outside fiducial phase space. - NPMCNTable(-4.f, ptReco, multReco, -4.f); + NPMCNTable(-4.f, ptReco, mcPar.eta(), etaReco, multReco, -4.f, mcMultFT0[mcCollId]); } continue; } @@ -1031,6 +1057,7 @@ struct NonPromptCascadeTask { const float multMC = mcMult[mcCollId]; const float ptMC = mcPar.pt(); + const float etaMC = mcPar.eta(); mRegistrydNdeta.fill(HIST("hdNdetaRM/hdNdetaRM"), multMC, @@ -1040,7 +1067,7 @@ struct NonPromptCascadeTask { if (writeMcCollision[mcCollId]) { // Matched: accepted truth particle reconstructed inside the fiducial reco phase space. - NPMCNTable(ptMC, ptReco, multReco, multMC); + NPMCNTable(ptMC, ptReco, etaMC, etaReco, multReco, multMC, mcMultFT0[mcCollId]); } } @@ -1069,6 +1096,7 @@ struct NonPromptCascadeTask { } const float multMC = mcMult[mcid]; + const float multMCFT0 = mcMultFT0[mcid]; mRegistrydNdeta.fill(HIST("hdNdetaRM/hdNdetaRMNotInRecoTrk"), multMC, @@ -1076,7 +1104,7 @@ struct NonPromptCascadeTask { if (writeMcCollision[mcid]) { // Missed track: accepted truth particle in a reconstructed MC collision, but no accepted reco track. - NPMCNTable(mcp.pt(), -1.f, -1.f, multMC); + NPMCNTable(mcp.pt(), -1.f, mcp.eta(), InvalidEta, -1.f, multMC, multMCFT0); } } @@ -1089,6 +1117,7 @@ struct NonPromptCascadeTask { } const float multMC = mcMult[mcid]; + const float multMCFT0 = mcMultFT0[mcid]; for (auto const& mcp : mcParticles) { if (mcp.mcCollisionId() != mcid) { @@ -1105,7 +1134,7 @@ struct NonPromptCascadeTask { if (writeMcCollision[mcid]) { // Missed collision: accepted truth particle from an MC collision with no reconstructed collision. - NPMCNTable(mcp.pt(), -2.f, -2.f, multMC); + NPMCNTable(mcp.pt(), -2.f, mcp.eta(), InvalidEta, -2.f, multMC, multMCFT0); } } } @@ -1134,6 +1163,7 @@ struct NonPromptCascadeTask { auto tracksThisColl = tracks.sliceBy(perCollisionSel, coll.globalIndex()); int multreco = 0; std::vector recoPts; + std::vector recoEtas; // std::cout << "tracks:" << tracksThisColl.size() << std::endl; for (auto const& track : tracksThisColl) { // std::cout << track.pt() << " tracks " << track.isGlobalTrack() << std::endl; @@ -1141,6 +1171,7 @@ struct NonPromptCascadeTask { if (track.isGlobalTrack()) { multreco++; recoPts.push_back(track.pt()); + recoEtas.push_back(track.eta()); } } } @@ -1158,8 +1189,8 @@ struct NonPromptCascadeTask { coll.multFT0M(), coll.selection_bit(aod::evsel::kNoSameBunchPileup)); auto collIdx = NPCollsTable.lastIndex(); - for (auto const& pt : recoPts) { - NPRecoCandTable(collIdx, pt); + for (size_t i = 0; i < recoPts.size(); ++i) { + NPRecoCandTable(collIdx, recoPts[i], recoEtas[i]); } } } From c869cd37d5187039e2f1d522b31e3273947226d8 Mon Sep 17 00:00:00 2001 From: mcoquet642 <74600025+mcoquet642@users.noreply.github.com> Date: Sat, 1 Aug 2026 04:55:59 +0200 Subject: [PATCH 68/71] [Common] Adding function in fwdtrackUtilities to correct for 3D PV shifts (#17276) --- Common/Core/fwdtrackUtilities.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Common/Core/fwdtrackUtilities.h b/Common/Core/fwdtrackUtilities.h index 7265f1fe581..29a9db2c194 100644 --- a/Common/Core/fwdtrackUtilities.h +++ b/Common/Core/fwdtrackUtilities.h @@ -60,9 +60,9 @@ concept is_fwd_cov = requires(T t) { { t.sigmaX() } -> std::same_as; }; -/// Produce TrackParCovFwds for MFT and FwdTracks, w/ or w/o cov, with z shift +/// Produce TrackParCovFwds for MFT and FwdTracks, w/ or w/o cov, with x, y and z shifts template -o2::track::TrackParCovFwd getTrackParCovFwdShift(TFwdTrack const& track, float zshift, TCovariance const&... covOpt) +o2::track::TrackParCovFwd getTrackParCovFwd3DShift(TFwdTrack const& track, float xshift, float yshift, float zshift, TCovariance const&... covOpt) { double chi2 = track.chi2(); if constexpr (sizeof...(covOpt) == 0) { @@ -82,7 +82,7 @@ o2::track::TrackParCovFwd getTrackParCovFwdShift(TFwdTrack const& track, float z } } - SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); + SMatrix5 tpars(track.x() + xshift, track.y() + yshift, track.phi(), track.tgl(), track.signed1Pt()); SMatrix55 tcovs; if constexpr (sizeof...(covOpt) == 1) { @@ -101,6 +101,13 @@ o2::track::TrackParCovFwd getTrackParCovFwdShift(TFwdTrack const& track, float z return o2::track::TrackParCovFwd(track.z() + zshift, tpars, tcovs, chi2); } +/// Produce TrackParCovFwds for MFT and FwdTracks, w/ or w/o cov, with z shift +template +o2::track::TrackParCovFwd getTrackParCovFwdShift(TFwdTrack const& track, float zshift, TCovariance const&... covOpt) +{ + return getTrackParCovFwd3DShift(track, 0.f, 0.f, zshift, covOpt...); +} + inline o2::track::TrackParCovFwd getTrackParCovFwdShiftManual( const double x, const double y, const double phi, const double tgl, const double signed1Pt, const double cXX, From fb91ce8b6d4dc0e4a3b28c9ba7b86ac04af6e20c Mon Sep 17 00:00:00 2001 From: Dukhishyam Mallick <160018357+dmallick2@users.noreply.github.com> Date: Sat, 1 Aug 2026 04:56:18 +0200 Subject: [PATCH 69/71] [PWGDQ] Add and fix configurable tag options for optimize memory issue (#17272) --- PWGDQ/Core/HistogramsLibrary.cxx | 16 ++- PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx | 114 +++++++++++------- 2 files changed, 86 insertions(+), 44 deletions(-) diff --git a/PWGDQ/Core/HistogramsLibrary.cxx b/PWGDQ/Core/HistogramsLibrary.cxx index c15894fbb8b..83a75fde02b 100644 --- a/PWGDQ/Core/HistogramsLibrary.cxx +++ b/PWGDQ/Core/HistogramsLibrary.cxx @@ -1257,15 +1257,25 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Coschi", "", false, 25, coschiBins.data(), VarManager::kMCCosChi, 0, nullptr, -1, 0, nullptr, -1, "", "", "", -1, VarManager::kMCWeight); } - if (groupStr.CompareTo("polarization-pseudoproper-gen") == 0) { + if (groupStr.CompareTo("polarization-pseudoproper-midy-he-gen") == 0) { std::array varspTHE = {VarManager::kMCMass, VarManager::kMCPt, VarManager::kMCCosThetaHE, VarManager::kMCVertexingTauxyProjected}; - std::array varspTCS = {VarManager::kMCMass, VarManager::kMCPt, VarManager::kMCCosThetaCS, VarManager::kMCVertexingTauxyProjected}; - std::array varspTRM = {VarManager::kMCMass, VarManager::kMCPt, VarManager::kMCCosThetaRM, VarManager::kMCVertexingTauxyProjected}; std::array bins = {50, 20, 20, 1000}; std::array xmin = {2., 0., -1., -0.5}; std::array xmax = {4., 20., 1., 0.5}; hm->AddHistogram(histClass, "Mass_Pt_cosThetaHE_Tauxy", "", 4, varspTHE.data(), bins.data(), xmin.data(), xmax.data(), nullptr, -1, kFALSE); + } + if (groupStr.CompareTo("polarization-pseudoproper-midy-cs-gen") == 0) { + std::array varspTCS = {VarManager::kMCMass, VarManager::kMCPt, VarManager::kMCCosThetaCS, VarManager::kMCVertexingTauxyProjected}; + std::array bins = {50, 20, 20, 1000}; + std::array xmin = {2., 0., -1., -0.5}; + std::array xmax = {4., 20., 1., 0.5}; hm->AddHistogram(histClass, "Mass_Pt_cosThetaCS_Tauxy", "", 4, varspTCS.data(), bins.data(), xmin.data(), xmax.data(), nullptr, -1, kFALSE); + } + if (groupStr.CompareTo("polarization-pseudoproper-midy-rand-gen") == 0) { + std::array varspTRM = {VarManager::kMCMass, VarManager::kMCPt, VarManager::kMCCosThetaRM, VarManager::kMCVertexingTauxyProjected}; + std::array bins = {50, 20, 20, 1000}; + std::array xmin = {2., 0., -1., -0.5}; + std::array xmax = {4., 20., 1., 0.5}; hm->AddHistogram(histClass, "Mass_Pt_cosThetaRM_Tauxy", "", 4, varspTRM.data(), bins.data(), xmin.data(), xmax.data(), nullptr, -1, kFALSE); } if (groupStr.CompareTo("polarization-dielectron-pbpb-midy-he-gen") == 0) { diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx index a064a274bd3..d61bf37ea71 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx @@ -331,14 +331,14 @@ struct AnalysisEventSelection { HistogramManager* fHistMan = nullptr; - AnalysisCompositeCut* fEventCut; + AnalysisCompositeCut* fEventCut = nullptr; Service fCCDB; o2::ccdb::CcdbApi fCCDBApi; std::map fSelMap; // key: reduced event global index, value: event selection decision std::map> fBCCollMap; // key: global BC, value: vector of reduced event global indices - int fCurrentRun; + int fCurrentRun = 0; void init(o2::framework::InitContext& context) { @@ -595,13 +595,13 @@ struct AnalysisTrackSelection { Service fCCDB; Service fTofResponse; - HistogramManager* fHistMan; + HistogramManager* fHistMan = nullptr; std::vector fTrackCuts; std::vector fMCSignals; // list of signals to be checked std::vector fHistNamesReco; std::vector fHistNamesMCMatched; - int fCurrentRun; // current run (needed to detect run changes for loading CCDB parameters) + int fCurrentRun = 0; // current run (needed to detect run changes for loading CCDB parameters) std::map> fNAssocsInBunch; // key: track global index, value: vector of global index for events associated in-bunch (events that have in-bunch pileup or splitting) std::map> fNAssocsOutOfBunch; // key: track global index, value: vector of global index for events associated out-of-bunch (events that have no in-bunch pileup) @@ -938,9 +938,9 @@ struct AnalysisPrefilterSelection { Configurable fPropTrack{"cfgPropTrack", false, "Propagate tracks to associated collision to recalculate DCA and momentum vector"}; std::map fPrefilterMap; - AnalysisCompositeCut* fPairCut; - uint32_t fPrefilterMask; - int fPrefilterCutBit; + AnalysisCompositeCut* fPairCut = nullptr; + uint32_t fPrefilterMask = 0; + int fPrefilterCutBit = 0; Preslice trackAssocsPerCollision = aod::track_association::collisionId; @@ -1141,7 +1141,9 @@ struct AnalysisSameEventPairing { Configurable pair{"cfgPairCuts", "", "Comma separated list of pair cuts, !!! Use only if you know what you are doing, otherwise leave empty"}; Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; Configurable fConfigMCtruthQA{"cfgMCtruthQA", false, "If true, fill QA histograms with default"}; - Configurable fConfigPseudoQA{"cfgPseudoQA", false, "If true, fill QA histograms with pseudo-proper decay length analysis with polarization"}; + Configurable fConfigPseudoHEQA{"cfgPseudoHEQA", false, "If true, fill QA histograms with pseudo-proper decay length analysis with polarization HE"}; + Configurable fConfigPseudoCSQA{"cfgPseudoCSQA", false, "If true, fill QA histograms with pseudo-proper decay length analysis with polarization CS"}; + Configurable fConfigPseudoRMQA{"cfgPseudoRMQA", false, "If true, fill QA histograms with pseudo-proper decay length analysis with polarization RM"}; Configurable fConfigTruthPbPbMIDYHE{"cfgTruthPbPbmidyHE", false, "If true, fill QA histograms with dielectron pairs in helicity frame"}; Configurable fConfigTruthPbPbMIDYCS{"cfgTruthPbPbmidyCS", false, "If true, fill QA histograms with dielectron pairs in collion-soper frame"}; Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; @@ -1204,14 +1206,14 @@ struct AnalysisSameEventPairing { std::vector fMCGenAccCuts; bool fUseMCGenAccCut = false; - uint32_t fTrackFilterMask; // mask for the track cuts required in this task to be applied on the barrel cuts produced upstream - uint32_t fMuonFilterMask; // mask for the muon cuts required in this task to be applied on the muon cuts produced upstream - int fNCutsBarrel; - int fNCutsMuon; - int fNPairCuts; + uint32_t fTrackFilterMask = 0; // mask for the track cuts required in this task to be applied on the barrel cuts produced upstream + uint32_t fMuonFilterMask = 0; // mask for the muon cuts required in this task to be applied on the muon cuts produced upstream + int fNCutsBarrel = 0; + int fNCutsMuon = 0; + int fNPairCuts = 0; bool fHasTwoProngGenMCsignals = false; - bool fEnableBarrelHistos; + bool fEnableBarrelHistos = false; // bool fEnableMuonHistos; Preslice> trackAssocsPerCollision = aod::track_association::collisionId; @@ -1506,14 +1508,20 @@ struct AnalysisSameEventPairing { if (fConfigOptions.fConfigMCtruthQA.value) { histNames += Form("MCTruthGenPairSel_%s;", sig->GetName()); // after event selection } - if (fConfigOptions.fConfigPseudoQA.value) { - histNames += Form("MCTruthGenPseudoPolPairSel_%s;", sig->GetName()); + if (fConfigOptions.fConfigPseudoHEQA.value) { + histNames += Form("MCTruthGenPseudoPolPairHESel_%s;", sig->GetName()); + } + if (fConfigOptions.fConfigPseudoCSQA.value) { + histNames += Form("MCTruthGenPseudoPolPairCSSel_%s;", sig->GetName()); + } + if (fConfigOptions.fConfigPseudoRMQA.value) { + histNames += Form("MCTruthGenPseudoPolPairRMSel_%s;", sig->GetName()); } if (fConfigOptions.fConfigTruthPbPbMIDYHE.value) { - histNames += Form("MCTruthGenPseudoPolPairSel_%s;", sig->GetName()); + histNames += Form("MCTruthGenPoldielectronPbPbPairHESel_%s;", sig->GetName()); } if (fConfigOptions.fConfigTruthPbPbMIDYCS.value) { - histNames += Form("MCTruthGenPseudoPolPairSel_%s;", sig->GetName()); + histNames += Form("MCTruthGenPoldielectronPbPbPairCSSel_%s;", sig->GetName()); } fHasTwoProngGenMCsignals = true; } @@ -1523,14 +1531,20 @@ struct AnalysisSameEventPairing { if (fConfigOptions.fConfigMCtruthQA.value) { histNames += Form("MCTruthGenPairSel_%s_%s;", sig->GetName(), cut->GetName()); // after event selection and MCgenAcc cut } - if (fConfigOptions.fConfigPseudoQA.value) { - histNames += Form("MCTruthGenPseudoPolPairSel_%s_%s;", sig->GetName(), cut->GetName()); + if (fConfigOptions.fConfigPseudoHEQA.value) { + histNames += Form("MCTruthGenPseudoPolPairHESel_%s_%s;", sig->GetName(), cut->GetName()); + } + if (fConfigOptions.fConfigPseudoCSQA.value) { + histNames += Form("MCTruthGenPseudoPolPairCSSel_%s_%s;", sig->GetName(), cut->GetName()); + } + if (fConfigOptions.fConfigPseudoRMQA.value) { + histNames += Form("MCTruthGenPseudoPolPairRMSel_%s_%s;", sig->GetName(), cut->GetName()); } if (fConfigOptions.fConfigTruthPbPbMIDYHE.value) { histNames += Form("MCTruthGenPoldielectronPbPbPairHESel_%s_%s;", sig->GetName(), cut->GetName()); } if (fConfigOptions.fConfigTruthPbPbMIDYCS.value) { - histNames += Form("MCTruthGenPseudoPolPairCSSel_%s_%s;", sig->GetName(), cut->GetName()); + histNames += Form("MCTruthGenPoldielectronPbPbPairCSSel_%s_%s;", sig->GetName(), cut->GetName()); } } } @@ -2189,8 +2203,14 @@ struct AnalysisSameEventPairing { if (fConfigOptions.fConfigMCtruthQA.value) { fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); } - if (fConfigOptions.fConfigPseudoQA.value) { - fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairSel_%s", sig->GetName()), VarManager::fgValues); + if (fConfigOptions.fConfigPseudoHEQA.value) { + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairHESel_%s", sig->GetName()), VarManager::fgValues); + } + if (fConfigOptions.fConfigPseudoCSQA.value) { + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairCSSel_%s", sig->GetName()), VarManager::fgValues); + } + if (fConfigOptions.fConfigPseudoRMQA.value) { + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairRMSel_%s", sig->GetName()), VarManager::fgValues); } if (fConfigOptions.fConfigTruthPbPbMIDYHE.value) { fHistMan->FillHistClass(Form("MCTruthGenPoldielectronPbPbPairHESel_%s", sig->GetName()), VarManager::fgValues); @@ -2205,8 +2225,14 @@ struct AnalysisSameEventPairing { if (fConfigOptions.fConfigMCtruthQA.value) { fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); } - if (fConfigOptions.fConfigPseudoQA.value) { - fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairSel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + if (fConfigOptions.fConfigPseudoHEQA.value) { + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairHESel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + } + if (fConfigOptions.fConfigPseudoCSQA.value) { + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairCSSel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + } + if (fConfigOptions.fConfigPseudoRMQA.value) { + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairRMSel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); } if (fConfigOptions.fConfigTruthPbPbMIDYHE.value) { @@ -2311,13 +2337,13 @@ struct AnalysisDileptonTrack { Configurable fConfigMCGenSignalHadronJSON{"cfgMCGenSignalHadronJSON", "", "generator level hadron signal (JSON format), used for MC level combinatorics"}; } fConfigMCOptions; - int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. - int fNCuts; - int fNLegCuts; - int fNPairCuts; - int fNCommonTrackCuts; + int fCurrentRun = 0; // needed to detect if the run changed and trigger update of calibrations etc. + int fNCuts = 0; + int fNLegCuts = 0; + int fNPairCuts = 0; + int fNCommonTrackCuts = 0; std::map fCommonTrackCutMap; - uint32_t fTrackCutBitMap; // track cut bit mask to be used in the selection of tracks associated with dileptons + uint32_t fTrackCutBitMap = 0; // track cut bit mask to be used in the selection of tracks associated with dileptons // vector for single-lepton and track cut names for easy access when calling FillHistogramList() std::vector fTrackCutNames; std::vector fLegCutNames; @@ -2334,14 +2360,14 @@ struct AnalysisDileptonTrack { // Filter filterMuon = aod::dqanalysisflags::isMuonSelected > static_cast(0); // use two values array to avoid mixing up the quantities - float* fValuesDilepton; - float* fValuesHadron; - HistogramManager* fHistMan; + float* fValuesDilepton = nullptr; + float* fValuesHadron = nullptr; + HistogramManager* fHistMan = nullptr; std::vector fRecMCSignals; std::vector fGenMCSignals; - MCSignal* fDileptonLegSignal; - MCSignal* fHadronSignal; + MCSignal* fDileptonLegSignal = nullptr; + MCSignal* fHadronSignal = nullptr; void init(o2::framework::InitContext& context) { @@ -2353,7 +2379,7 @@ struct AnalysisDileptonTrack { bool isDummy = context.mOptions.get("processDummy"); if (isDummy) { - if (isBarrel || isMCGen /*|| isBarrelAsymmetric*/ /*|| isMuon*/) { + if (isBarrel || isMCGen) { LOG(fatal) << "Dummy function is enabled even if there are normal process functions running! Fix your config!" << endl; } else { LOG(info) << "Dummy function is enabled. Skipping the rest of the init function" << endl; @@ -2576,13 +2602,13 @@ struct AnalysisDileptonTrack { fNLegCuts = fNCuts; // loop over single lepton cuts - if (isBarrel /*|| isBarrelAsymmetric*/ /* || isMuon*/) { + if (isBarrel) { for (int icut = 0; icut < fNLegCuts; ++icut) { TString pairLegCutName; // here we check that this cut is one of those used for building the dileptons - if (isBarrel /*|| isMuon*/) { + if (isBarrel) { if (!cfgPairing_objArrayTrackCuts->FindObject(fTrackCutNames[icut].Data())) { continue; } @@ -3215,8 +3241,14 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char if (classStr.Contains("MCTruthGenPair")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_pair", histName); } - if (classStr.Contains("MCTruthGenPseudoPolPair")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "polarization-pseudoproper-gen", histName); + if (classStr.Contains("MCTruthGenPseudoPolPairHE")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "polarization-pseudoproper-midy-he-gen", histName); + } + if (classStr.Contains("MCTruthGenPseudoPolPairCS")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "polarization-pseudoproper-midy-cs-gen", histName); + } + if (classStr.Contains("MCTruthGenPseudoPolPairRM")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "polarization-pseudoproper-midy-rand-gen", histName); } if (classStr.Contains("MCTruthGenPoldielectronPbPbPairHE")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "polarization-dielectron-pbpb-midy-he-gen", histName); From 87069ec56d28c494004cacd0b5a73d1ef5ee4101 Mon Sep 17 00:00:00 2001 From: miedema-11 <1260971129@qq.com> Date: Sat, 1 Aug 2026 22:29:13 +0800 Subject: [PATCH 70/71] updated version for mc --- PWGUD/Tasks/flowMcUpc.cxx | 937 +++++++++++++++++++++++++++++++++----- 1 file changed, 817 insertions(+), 120 deletions(-) diff --git a/PWGUD/Tasks/flowMcUpc.cxx b/PWGUD/Tasks/flowMcUpc.cxx index 81805424e65..7f9addf3e59 100644 --- a/PWGUD/Tasks/flowMcUpc.cxx +++ b/PWGUD/Tasks/flowMcUpc.cxx @@ -10,15 +10,26 @@ // or submit itself to any jurisdiction. /// \file flowMcUpc.cxx -/// \author Zhiyong Lu (zhiyong.lu@cern.ch), Yongxi Du (yongxi.du@cern.ch) -/// \since Apr/2/2026 -/// \brief flow efficiency analysis on UPC MC - -#include "PWGUD/DataModel/UDTables.h" - +/// \author Zhiyong Lu (zhiyong.lu@cern.ch) +/// \since Feb/5/2025 +/// \brief QC of synthetic flow exercise + +#include "PWGCF/GenericFramework/Core/FlowContainer.h" +#include "PWGCF/GenericFramework/Core/GFW.h" +#include "PWGCF/GenericFramework/Core/GFWWeights.h" +#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/CCDB/ctpRateFetcher.h" #include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" #include +#include #include #include #include @@ -29,22 +40,35 @@ #include #include +#include #include +#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::framework::expressions; +using namespace o2::aod::rctsel; -#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, (DEFAULT), (HELP)}; // NOLINT(bugprone-macro-parentheses) struct FlowMcUpc { HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -52,21 +76,128 @@ struct FlowMcUpc { Configurable minB{"minB", 0.0f, "min impact parameter"}; Configurable maxB{"maxB", 20.0f, "max impact parameter"}; O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 1000.0f, "Maximal pT for tracks") O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") - O2_DEFINE_CONFIGURABLE(cfgPtCutMin, float, 0.1f, "Minimal pT for tracks") - O2_DEFINE_CONFIGURABLE(cfgPtCutMax, float, 1000.0f, "Maximal pT for tracks") + O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, false, "Fill and output NUA weights") + O2_DEFINE_CONFIGURABLE(cfgCutPtRefMin, float, 0.2f, "Minimal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtRefMax, float, 3.0f, "Maximal pT for ref tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "Minimal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks") + O2_DEFINE_CONFIGURABLE(cfgCutTPCclu, int, 50, "minimum TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutITSclu, int, 5, "minimum ITS clusters") + O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5f, "max chi2 per TPC clusters") + O2_DEFINE_CONFIGURABLE(cfgCutTPCcrossedrows, int, 70, "minimum TPC crossed rows") O2_DEFINE_CONFIGURABLE(cfgCutDCAxy, float, 0.2f, "DCAxy cut for tracks") - O2_DEFINE_CONFIGURABLE(cfgDcaxy, bool, true, "choose dcaxy") + O2_DEFINE_CONFIGURABLE(cfgDCAxyNSigma, float, 7, "Cut on number of sigma deviations from expected DCA in the transverse direction"); + O2_DEFINE_CONFIGURABLE(cfgDCAxyFunction, std::string, "(0.0015+0.005/(x^1.1))", "Functional form of pt-dependent DCAxy cut"); + O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2.0f, "DCAz cut for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutDCAzPtDepEnabled, bool, false, "switch of DCAz pt dependent cut") + O2_DEFINE_CONFIGURABLE(cfgDCAzFunction, std::string, "(0.0015+0.005/(x^1.1))", "Functional form of pt-dependent DCAz cut"); + O2_DEFINE_CONFIGURABLE(cfgDCAzNSigma, float, 7, "Cut on number of sigma deviations from expected DCA in the z direction"); + O2_DEFINE_CONFIGURABLE(cfgEnableITSCuts, bool, true, "switch of enabling ITS based track selection cuts") + O2_DEFINE_CONFIGURABLE(cfgTrkSelRun3ITSMatch, bool, false, "GlobalTrackRun3ITSMatching::Run3ITSall7Layers selection") + O2_DEFINE_CONFIGURABLE(cfgFlowAcceptance, std::string, "", "CCDB path to acceptance object") + O2_DEFINE_CONFIGURABLE(cfgFlowEfficiency, std::string, "", "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgCentVsIPTruth, std::string, "", "CCDB path to centrality vs IP truth") + O2_DEFINE_CONFIGURABLE(cfgIsGlobalTrack, bool, false, "Use global tracks instead of hasTPC&&hasITS") + O2_DEFINE_CONFIGURABLE(cfgK0Lambda0Enabled, bool, false, "Add K0 and Lambda0, for bulk particle efficiency please keep off") + O2_DEFINE_CONFIGURABLE(cfgAcceptSecondaries, bool, false, "Accept secondary particles produced from decays") + O2_DEFINE_CONFIGURABLE(cfgRequireTOF, bool, false, "Require that reconstructed tracks have TOF for resonance decays") + O2_DEFINE_CONFIGURABLE(cfgFlowCumulantEnabled, bool, false, "switch of calculating flow") + O2_DEFINE_CONFIGURABLE(cfgFlowCumulantNbootstrap, int, 30, "Number of subsamples") + O2_DEFINE_CONFIGURABLE(cfgTrackDensityCorrUse, bool, false, "Use track density efficiency correction") + O2_DEFINE_CONFIGURABLE(cfgTrackDensityCorrSlopeFactor, float, 1.0f, "A factor to scale the track density efficiency slope") + O2_DEFINE_CONFIGURABLE(cfgRecoEvRejectMC, bool, false, "reject both MC and Reco events when reco do not pass") + O2_DEFINE_CONFIGURABLE(cfgRecoEvSel8, bool, false, "require sel8 for reconstruction events") + O2_DEFINE_CONFIGURABLE(cfgRecoEvkIsGoodITSLayers, bool, true, "cut time intervals with dead ITS staves") + O2_DEFINE_CONFIGURABLE(cfgRecoEvkIsGoodITSLayersFlag, int, 0, "0: kIsGoodITSLayersAll; 1: kIsGoodITSLayer0123; 2: kIsGoodITSLayer3") + O2_DEFINE_CONFIGURABLE(cfgRecoEvkNoSameBunchPileup, bool, false, "require kNoSameBunchPileup for reconstruction events") + O2_DEFINE_CONFIGURABLE(cfgRecoEvSelkIsGoodZvtxFT0vsPV, bool, false, "removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference, use this cut at low multiplicities with caution") + O2_DEFINE_CONFIGURABLE(cfgRecoEvSelkNoITSROFrameBorder, bool, false, "reject events at ITS ROF border") + O2_DEFINE_CONFIGURABLE(cfgRecoEvSelkNoTimeFrameBorder, bool, false, "reject events at TF border") + O2_DEFINE_CONFIGURABLE(cfgRecoEvSelkNoCollInTimeRangeStandard, bool, false, "no collisions in specified time range") + O2_DEFINE_CONFIGURABLE(cfgRecoEvSelkNoCollInRofStandard, bool, false, "no other collisions in this Readout Frame with per-collision multiplicity above threshold") + O2_DEFINE_CONFIGURABLE(cfgITSTPCVertex, bool, false, "use ITS-TPC vertex") + O2_DEFINE_CONFIGURABLE(cfgRecoEvSelkNoHighMultCollInPrevRof, bool, false, "veto an event if FT0C amplitude in previous ITS ROF is above threshold") + O2_DEFINE_CONFIGURABLE(cfgEvSelRCTflags, std::string, "", "keep empty to disable, usage: 'CentralBarrelTracking', 'CBT_hadronPID' ") + O2_DEFINE_CONFIGURABLE(cfgIRFetch, bool, false, "Get interaction rate from CCDB") + O2_DEFINE_CONFIGURABLE(cfgIRCutEnabled, bool, false, "Use events with low interaction rate") + O2_DEFINE_CONFIGURABLE(cfgIRMax, float, 50.0f, "maximum interaction rate (kHz)") + O2_DEFINE_CONFIGURABLE(cfgIRMin, float, 0.0f, "minimum interaction rate (kHz)") + O2_DEFINE_CONFIGURABLE(cfgOccupancyEnabled, bool, true, "Occupancy cut") + O2_DEFINE_CONFIGURABLE(cfgOccupancyMax, int, 2000, "High cut on TPC occupancy") + O2_DEFINE_CONFIGURABLE(cfgOccupancyMin, int, 0, "Low cut on TPC occupancy") + + Configurable> cfgTrackDensityP0{"cfgTrackDensityP0", std::vector{0.6003720411, 0.6152630970, 0.6288860646, 0.6360694031, 0.6409494798, 0.6450540203, 0.6482117301, 0.6512592056, 0.6640008690, 0.6862631416, 0.7005738691, 0.7106567432, 0.7170728333}, "parameter 0 for track density efficiency correction"}; + Configurable> cfgTrackDensityP1{"cfgTrackDensityP1", std::vector{-1.007592e-05, -8.932635e-06, -9.114538e-06, -1.054818e-05, -1.220212e-05, -1.312304e-05, -1.376433e-05, -1.412813e-05, -1.289562e-05, -1.050065e-05, -8.635725e-06, -7.380821e-06, -6.201250e-06}, "parameter 1 for track density efficiency correction"}; ConfigurableAxis axisB{"axisB", {100, 0.0f, 20.0f}, ""}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "X axis for histograms"}; + ConfigurableAxis axisPhi{"axisPhi", {100, 0.0f, constants::math::TwoPI}, ""}; + ConfigurableAxis axisNch{"axisNch", {300, 0.0f, 3000.0f}, "Nch in |eta|<0.8"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f}, "pt axis"}; + + // Filter for MCcollisions + Filter mccollisionFilter = nabs(aod::mccollision::posZ) < cfgCutVertex; + using FilteredMcCollisions = soa::Filtered; + // Filter for MCParticle + Filter particleFilter = (nabs(aod::mcparticle::eta) < cfgCutEta) && (aod::mcparticle::pt > cfgCutPtMin) && (aod::mcparticle::pt < cfgCutPtMax); + using FilteredMcParticles = soa::Filtered>; + // Filter for reco tracks + Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && (aod::track::tpcChi2NCl < cfgCutChi2prTPCcls); + using FilteredTracks = soa::Filtered>; + + // using FilteredTracks = soa::Join; + + // Additional filters for tracks + TrackSelection myTrackSel; + TF1* fPtDepDCAxy = nullptr; + TF1* fPtDepDCAz = nullptr; + + // Cent vs IP + TH1D* mCentVsIPTruth = nullptr; + // bool centVsIPTruthLoaded = false; + + // Corrections + TH1D* mEfficiency = nullptr; + GFWWeights* mAcceptance = nullptr; + bool correctionsLoaded = false; + + std::vector funcEff; + TH1D* hFindPtBin = nullptr; + TF1* funcV2 = nullptr; + TF1* funcV3 = nullptr; + TF1* funcV4 = nullptr; + enum GoodITSLayersFlag { + kITSLayersAll, + kITSLayer0123, + kITSLayer3, + kCount_ITSLayersFlag + }; + // Connect to ccdb - Service ccdb; + Service ccdb{}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - double epsilon = 1e-6; - - // using McParts = soa::Join; + OutputObj fWeights{GFWWeights("weights")}; + OutputObj fFCTrue{FlowContainer("FlowContainerTrue")}; + OutputObj fFCReco{FlowContainer("FlowContainerReco")}; + GFW* fGFWTrue = new GFW(); + GFW* fGFWReco = new GFW(); + TAxis* fPtAxis = nullptr; + std::vector corrconfigsTruth; + std::vector corrconfigsReco; + TRandom3* fRndm = new TRandom3(0); + static constexpr double epsilon = 1e-6; + int mRunNumber{-1}; + uint64_t mSOR{0}; + double mMinSeconds{-1.}; + std::unordered_map gHadronicRate; + ctpRateFetcher mRateFetcher; + TH2* gCurrentHadronicRate = nullptr; + RCTFlagsChecker rctChecker{"CBT"}; void init(InitContext&) { @@ -80,150 +211,716 @@ struct FlowMcUpc { const AxisSpec axisCounter{1, 0, +1, ""}; // QA histograms histos.add("mcEventCounter", "Monte Carlo Truth EventCounter", HistType::kTH1F, {{5, 0, 5}}); + histos.add("numberOfRecoCollisions", "numberOfRecoCollisions", HistType::kTH1F, {{10, -1.5f, 8.5f}}); + histos.add("RecoEventCounter", "Reconstruction EventCounter", HistType::kTH1F, {{5, 0, 5}}); histos.add("RecoProcessEventCounter", "Reconstruction EventCounter", HistType::kTH1F, {{5, 0, 5}}); + histos.add("hnTPCClu", "Number of found TPC clusters", HistType::kTH1D, {{100, 40, 180}}); + histos.add("hnITSClu", "Number of found ITS clusters", HistType::kTH1D, {{100, 0, 20}}); + // pT histograms histos.add("hImpactParameter", "hImpactParameter", HistType::kTH1D, {axisB}); - histos.add("RecoProcessTrackCounter", "Reconstruction TrackCounter", HistType::kTH1F, {{5, 0, 5}}); - histos.add("numberOfRecoCollisions", "numberOfRecoCollisions", kTH1F, {{100, -0.5f, 99.5f}}); - + histos.add("hNchVsImpactParameter", "hNchVsImpactParameter", HistType::kTH2D, {axisB, axisNch}); + histos.add("hNchRecoVsNchGen", "hNchRecoVsNchGen; Recoconstucted Nch; Genenerated Nch", HistType::kTH2D, {axisNch, axisNch}); + histos.add("hEventPlaneAngle", "hEventPlaneAngle", HistType::kTH1D, {axisPhi}); + histos.add("hPtVsPhiGenerated", "hPtVsPhiGenerated", HistType::kTH2D, {axisPhi, axisPt}); + histos.add("hPtVsPhiGlobal", "hPtVsPhiGlobal", HistType::kTH2D, {axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGenerated", "hBVsPtVsPhiGenerated", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobal", "hBVsPtVsPhiGlobal", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiAny", "hBVsPtVsPhiAny", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiTPCTrack", "hBVsPtVsPhiTPCTrack", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiITSTrack", "hBVsPtVsPhiITSTrack", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiITSABTrack", "hBVsPtVsPhiITSABTrack", HistType::kTH3D, {axisB, axisPhi, axisPt}); + + histos.add("hBVsPtVsPhiGeneratedK0Short", "hBVsPtVsPhiGeneratedK0Short", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobalK0Short", "hBVsPtVsPhiGlobalK0Short", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGeneratedLambda", "hBVsPtVsPhiGeneratedLambda", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobalLambda", "hBVsPtVsPhiGlobalLambda", HistType::kTH3D, {axisB, axisPhi, axisPt}); + + histos.add("hBVsPtVsPhiGeneratedXi", "hBVsPtVsPhiGeneratedXi", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobalXi", "hBVsPtVsPhiGlobalXi", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGeneratedOmega", "hBVsPtVsPhiGeneratedOmega", HistType::kTH3D, {axisB, axisPhi, axisPt}); + histos.add("hBVsPtVsPhiGlobalOmega", "hBVsPtVsPhiGlobalOmega", HistType::kTH3D, {axisB, axisPhi, axisPt}); + + histos.add("hPhi", "#phi distribution", HistType::kTH1D, {axisPhi}); + histos.add("hPhiWeighted", "corrected #phi distribution", HistType::kTH1D, {axisPhi}); + histos.add("hEPVsPhiMC", "hEPVsPhiMC;Event Plane Angle; #varphi", HistType::kTH2D, {axisPhi, axisPhi}); + histos.add("hEPVsPhi", "hEPVsPhi;Event Plane Angle; #varphi", HistType::kTH2D, {axisPhi, axisPhi}); + histos.add("hPtNchGenerated", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobal", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGeneratedPion", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobalPion", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGeneratedKaon", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobalKaon", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGeneratedProton", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobalProton", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGeneratedK0", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobalK0", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGeneratedLambda", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobalLambda", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGeneratedK0Pions", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobalK0Pions", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGeneratedLambdaPions", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobalLambdaPions", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGeneratedLambdaProtons", "Reco production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); + histos.add("hPtNchGlobalLambdaProtons", "Global production; pT (GeV/c); multiplicity", HistType::kTH2D, {axisPt, axisNch}); histos.add("hPtMCGen", "Monte Carlo Truth; pT (GeV/c);", {HistType::kTH1D, {axisPt}}); histos.add("hEtaPtVtxzMCGen", "Monte Carlo Truth; #eta; p_{T} (GeV/c); V_{z} (cm);", {HistType::kTH3D, {axisEta, axisPt, axisVertex}}); + histos.add("hPtMCGlobal", "Monte Carlo Global; pT (GeV/c);", {HistType::kTH1D, {axisPt}}); histos.add("hPtReco", "Monte Carlo Reco Global; pT (GeV/c);", {HistType::kTH1D, {axisPt}}); - histos.add("hEtaPtVtxzMCReco", "Monte Carlo Global; #eta; p_{T} (GeV/c); V_{z} (cm);", {HistType::kTH3D, {axisEta, axisPt, axisVertex}}); + histos.add("hPtReco_PhysicalPrimary", "Monte Carlo Reco Global; pT (GeV/c);", {HistType::kTH1D, {axisPt}}); + histos.add("hEtaPtVtxzMCGlobal", "Monte Carlo Global; #eta; p_{T} (GeV/c); V_{z} (cm);", {HistType::kTH3D, {axisEta, axisPt, axisVertex}}); + histos.add("hPhiWeightedTrDen", "corrected #phi distribution, considering track density", {HistType::kTH1D, {axisPhi}}); + + o2::framework::AxisSpec axis = axisPt; + int nPtBins = axis.binEdges.size() - 1; + double* ptBins = axis.binEdges.data(); + fPtAxis = new TAxis(nPtBins, ptBins); + + if (cfgOutputNUAWeights) { + fWeights->setPtBins(nPtBins, ptBins); + fWeights->init(true, false); + } + + if (cfgFlowCumulantEnabled) { + auto oba = new TObjArray(); + oba->Add(new TNamed("ChFull22", "ChFull22")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) { + oba->Add(new TNamed(Form("ChFull22_pt_%i", i + 1), "ChFull22_pTDiff")); + } + oba->Add(new TNamed("Ch10Gap22", "Ch10Gap22")); + for (auto i = 0; i < fPtAxis->GetNbins(); i++) { + oba->Add(new TNamed(Form("Ch10Gap22_pt_%i", i + 1), "Ch10Gap22_pTDiff")); + } + fFCTrue->SetName("FlowContainerTrue"); + fFCTrue->SetXAxis(fPtAxis); + fFCTrue->Initialize(oba, axisCentrality, cfgFlowCumulantNbootstrap); + fFCReco->SetName("FlowContainerReco"); + fFCReco->SetXAxis(fPtAxis); + fFCReco->Initialize(oba, axisCentrality, cfgFlowCumulantNbootstrap); + delete oba; + + fGFWTrue->AddRegion("full", -0.8, 0.8, 1, 1); + fGFWTrue->AddRegion("refN10", -0.8, -0.5, 1, 1); + fGFWTrue->AddRegion("refP10", 0.5, 0.8, 1, 1); + fGFWTrue->AddRegion("poiN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFWTrue->AddRegion("poifull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 2); + fGFWTrue->AddRegion("olN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFWTrue->AddRegion("olfull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 4); + corrconfigsTruth.push_back(fGFWTrue->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); + corrconfigsTruth.push_back(fGFWTrue->GetCorrelatorConfig("poifull full | olfull {2 -2}", "ChFull22", kTRUE)); + corrconfigsTruth.push_back(fGFWTrue->GetCorrelatorConfig("refN10 {2} refP10 {-2}", "Ch10Gap22", kFALSE)); + corrconfigsTruth.push_back(fGFWTrue->GetCorrelatorConfig("poiN10 refN10 | olN10 {2} refP10 {-2}", "Ch10Gap22", kTRUE)); + fGFWTrue->CreateRegions(); + + fGFWReco->AddRegion("full", -0.8, 0.8, 1, 1); + fGFWReco->AddRegion("refN10", -0.8, -0.5, 1, 1); + fGFWReco->AddRegion("refP10", 0.5, 0.8, 1, 1); + fGFWReco->AddRegion("poiN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 2); + fGFWReco->AddRegion("poifull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 2); + fGFWReco->AddRegion("olN10", -0.8, -0.5, 1 + fPtAxis->GetNbins(), 4); + fGFWReco->AddRegion("olfull", -0.8, 0.8, 1 + fPtAxis->GetNbins(), 4); + corrconfigsReco.push_back(fGFWReco->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); + corrconfigsReco.push_back(fGFWReco->GetCorrelatorConfig("poifull full | olfull {2 -2}", "ChFull22", kTRUE)); + corrconfigsReco.push_back(fGFWReco->GetCorrelatorConfig("refN10 {2} refP10 {-2}", "Ch10Gap22", kFALSE)); + corrconfigsReco.push_back(fGFWReco->GetCorrelatorConfig("poiN10 refN10 | olN10 {2} refP10 {-2}", "Ch10Gap22", kTRUE)); + fGFWReco->CreateRegions(); + } + + if (cfgEnableITSCuts) { + if (cfgTrkSelRun3ITSMatch) { + myTrackSel = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSall7Layers, TrackSelection::GlobalTrackRun3DCAxyCut::Default); + } else { + myTrackSel = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default); + } + } + if (cfgCutDCAxy != 0.0) { + myTrackSel.SetMaxDcaXY(cfgCutDCAxy); + } else { + fPtDepDCAxy = new TF1("ptDepDCAxy", Form("[0]*%s", cfgDCAxyFunction->c_str()), 0.001, 100); + fPtDepDCAxy->SetParameter(0, cfgDCAxyNSigma); + LOGF(info, "DCAxy pt-dependence function: %s", Form("[0]*%s", cfgDCAxyFunction->c_str())); + myTrackSel.SetMaxDcaXYPtDep([fPtDepDCAxy = this->fPtDepDCAxy](float pt) { return fPtDepDCAxy->Eval(pt); }); + } + myTrackSel.SetMinNClustersTPC(cfgCutTPCclu); + myTrackSel.SetMinNCrossedRowsTPC(cfgCutTPCcrossedrows); + if (cfgEnableITSCuts) { + myTrackSel.SetMinNClustersITS(cfgCutITSclu); + } + if (!cfgCutDCAzPtDepEnabled) { + myTrackSel.SetMaxDcaZ(cfgCutDCAz); + } else { + fPtDepDCAz = new TF1("ptDepDCAxy", Form("[0]*%s", cfgDCAzFunction->c_str()), 0.001, 100); + fPtDepDCAz->SetParameter(0, cfgDCAzNSigma); + LOGF(info, "DCAz pt-dependence function: %s", Form("[0]*%s", cfgDCAzFunction->c_str())); + } + if (cfgTrackDensityCorrUse) { + std::vector pTEffBins = {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.4, 1.8, 2.2, 2.6, 3.0}; + hFindPtBin = new TH1D("hFindPtBin", "hFindPtBin", pTEffBins.size() - 1, pTEffBins.data()); + funcEff.resize(pTEffBins.size() - 1); + // LHC24g3 Eff + std::vector f1p0 = cfgTrackDensityP0; + std::vector f1p1 = cfgTrackDensityP1; + for (uint ifunc = 0; ifunc < pTEffBins.size() - 1; ifunc++) { + funcEff[ifunc] = new TF1(Form("funcEff%i", ifunc), "[0]+[1]*x", 0, 3000); + funcEff[ifunc]->SetParameters(f1p0[ifunc], f1p1[ifunc] * cfgTrackDensityCorrSlopeFactor); + } + funcV2 = new TF1("funcV2", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV2->SetParameters(0.0186111, 0.00351907, -4.38264e-05, 1.35383e-07, -3.96266e-10); + funcV3 = new TF1("funcV3", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV3->SetParameters(0.0174056, 0.000703329, -1.45044e-05, 1.91991e-07, -1.62137e-09); + funcV4 = new TF1("funcV4", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 100); + funcV4->SetParameters(0.008845, 0.000259668, -3.24435e-06, 4.54837e-08, -6.01825e-10); + } + if (!cfgEvSelRCTflags.value.empty()) { + rctChecker.init(cfgEvSelRCTflags.value); // override initialzation + } } - // template - // bool eventSelected(TCollision collision) - // { - // return true; - // } + void loadCorrections(uint64_t timestamp) + { + if (correctionsLoaded) { + return; + } + if (!cfgFlowAcceptance.value.empty()) { + mAcceptance = ccdb->getForTimeStamp(cfgFlowAcceptance, timestamp); + if (mAcceptance) { + LOGF(info, "Loaded acceptance weights from %s (%p)", cfgFlowAcceptance.value.c_str(), static_cast(mAcceptance)); + } else { + LOGF(warning, "Could not load acceptance weights from %s (%p)", cfgFlowAcceptance.value.c_str(), static_cast(mAcceptance)); + } + } + if (!cfgFlowEfficiency.value.empty()) { + mEfficiency = ccdb->getForTimeStamp(cfgFlowEfficiency, timestamp); + if (mEfficiency == nullptr) { + LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgFlowEfficiency.value.c_str()); + } + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgFlowEfficiency.value.c_str(), static_cast(mEfficiency)); + } + correctionsLoaded = true; + } - template - bool trackSelected(TTrack const& track) + bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, float phi, float eta, float pt, float vtxz) { - if (!track.hasTPC()) - return false; - if (!track.isPVContributor()) - return false; - // auto momentum = std::array{track.px(), track.py(), track.pz()}; - auto pt = track.pt(); - if (pt < cfgPtCutMin || pt > cfgPtCutMax) { - return false; + float eff = 1.; + if (mEfficiency) { + eff = mEfficiency->GetBinContent(mEfficiency->FindBin(pt)); + } else { + eff = 1.0; } - double dcaLimit = 0.0105 + 0.035 / std::pow(pt, 1.1); - if (cfgDcaxy && !(std::fabs(track.dcaXY()) < dcaLimit)) { + if (eff == 0) { return false; } + weight_nue = 1. / eff; + if (mAcceptance) { + weight_nua = mAcceptance->getNUA(phi, eta, vtxz); + } else { + weight_nua = 1; + } return true; } - PresliceUnsorted partPerMcCollision = aod::udmcparticle::udMcCollisionId; - - void processMCTrue(aod::UDMcCollisions const& mcCollisions, aod::UDMcParticles const& mcParts, aod::BCs const& bcs) + void fillFC(GFW* fGFW, bool isMCTruth, const GFW::CorrConfig& corrconf, const double& cent, const double& rndm) { - if (bcs.size() == 0) { + double dnx = 0, val = 0; + dnx = fGFW->Calculate(corrconf, 0, kTRUE).real(); + if (!corrconf.pTDif) { + if (dnx == 0) { + return; + } + val = fGFW->Calculate(corrconf, 0, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + if (isMCTruth) { + fFCTrue->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm); + } else { + fFCReco->FillProfile(corrconf.Head.c_str(), cent, val, dnx, rndm); + } + } return; } - for (const auto& mcCollision : mcCollisions) { - histos.fill(HIST("mcEventCounter"), 0.5); - float imp = mcCollision.impactParameter(); - float vtxz = mcCollision.posZ(); + for (auto i = 1; i <= fPtAxis->GetNbins(); i++) { + dnx = fGFW->Calculate(corrconf, i - 1, kTRUE).real(); + if (dnx == 0) { + continue; + } + val = fGFW->Calculate(corrconf, i - 1, kFALSE).real() / dnx; + if (std::fabs(val) < 1) { + if (isMCTruth) { + fFCTrue->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm); + } else { + fFCReco->FillProfile(Form("%s_pt_%i", corrconf.Head.c_str(), i), cent, val, dnx, rndm); + } + } + } + } - if (imp >= minB && imp <= maxB) { - // event within range - histos.fill(HIST("hImpactParameter"), imp); + void loadCentVsIPTruth(uint64_t timestamp) + { + if (mCentVsIPTruth != nullptr) { + return; + } + if (!cfgCentVsIPTruth.value.empty()) { + mCentVsIPTruth = ccdb->getForTimeStamp(cfgCentVsIPTruth, timestamp); + if (mCentVsIPTruth) { + LOGF(info, "Loaded CentVsIPTruth weights from %s (%p)", cfgCentVsIPTruth.value.c_str(), static_cast(mCentVsIPTruth)); + } else { + LOGF(fatal, "Failed to load CentVsIPTruth weights from %s", cfgCentVsIPTruth.value.c_str()); + } - auto const& tempParts = mcParts.sliceBy(partPerMcCollision, static_cast(mcCollision.globalIndex())); + } else { + LOGF(fatal, "when calculate flow, Cent Vs IP distribution must be provided"); + } + } - for (auto const& mcParticle : tempParts) { - auto momentum = std::array{mcParticle.px(), mcParticle.py(), mcParticle.pz()}; - int pdgCode = std::abs(mcParticle.pdgCode()); + void initHadronicRate(aod::BCsWithTimestamps::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + if (!gHadronicRate.contains(mRunNumber)) { + auto runDuration = ccdb->getRunDuration(mRunNumber); + mSOR = runDuration.first; + mMinSeconds = std::floor(mSOR * 1.e-3); /// round tsSOR to the highest integer lower than tsSOR + double maxSec = std::ceil(runDuration.second * 1.e-3); /// round tsEOR to the lowest integer higher than tsEOR + const AxisSpec axisSeconds{static_cast((maxSec - mMinSeconds) / 20.f), 0, maxSec - mMinSeconds, "Seconds since SOR"}; + gHadronicRate[mRunNumber] = histos.add(Form("HadronicRate/%i", mRunNumber), ";Time since SOR (s);Hadronic rate (kHz)", kTH2D, {axisSeconds, {510, 0., 51.}}).get(); + } + gCurrentHadronicRate = gHadronicRate[mRunNumber]; + } - double pt = RecoDecay::pt(momentum); - double eta = RecoDecay::eta(momentum); + template + bool eventSelected(const TCollision& collision) + { + if (std::fabs(collision.posZ()) > cfgCutVertex) { + return 0; + } + if (cfgRecoEvSel8 && !collision.sel8()) { + return 0; + } + if (cfgOccupancyEnabled) { + auto occupancy = collision.trackOccupancyInTimeRange(); + if (occupancy < cfgOccupancyMin || occupancy > cfgOccupancyMax) { + return 0; + } + } + if (!cfgEvSelRCTflags.value.empty() && !rctChecker(*collision)) { + return 0; + } + if (cfgRecoEvkNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof + return 0; + } + if (cfgRecoEvkIsGoodITSLayers) { + // from Jan 9 2025 AOT meeting + // cut time intervals with dead ITS staves + if (cfgRecoEvkIsGoodITSLayersFlag == kITSLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return 0; + } + if (cfgRecoEvkIsGoodITSLayersFlag == kITSLayer0123 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)) { + return 0; + } + if (cfgRecoEvkIsGoodITSLayersFlag == kITSLayer3 && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer3)) { + return 0; + } + } + if (cfgRecoEvSelkIsGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + // use this cut at low multiplicities with caution + return 0; + } + if (cfgRecoEvSelkNoITSROFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return 0; + } + if (cfgRecoEvSelkNoTimeFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return 0; + } + if (cfgRecoEvSelkNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + // no collisions in specified time range + return 0; + } + if (cfgRecoEvSelkNoCollInRofStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + // no other collisions in this Readout Frame with per-collision multiplicity above threshold + return 0; + } + if (cfgRecoEvSelkNoHighMultCollInPrevRof && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + // veto an event if FT0C amplitude in previous ITS ROF is above threshold + return 0; + } + if (cfgITSTPCVertex && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)){ + return 0; + } + return 1; + } - if (pdgCode != PDG_t::kElectron && pdgCode != PDG_t::kMuonMinus && pdgCode != PDG_t::kPiPlus && pdgCode != PDG_t::kKPlus && pdgCode != PDG_t::kProton) - continue; + template + bool trackSelected(const TTrack& track) + { + if (cfgCutDCAzPtDepEnabled && (std::fabs(track.dcaZ()) > fPtDepDCAz->Eval(track.pt()))) { + return false; + } + return myTrackSel.IsSelected(track); + } - if (!mcParticle.isPhysicalPrimary()) - continue; - if (std::fabs(eta) > cfgCutEta) // main acceptance - continue; + void processMCTrue(FilteredMcCollisions::iterator const& mcCollision, aod::BCsWithTimestamps const&, soa::SmallGroups> const& collisions, FilteredMcParticles const& mcParticles, FilteredTracks const&) + { + histos.fill(HIST("mcEventCounter"), 0.5); + float imp = mcCollision.impactParameter(); + float evPhi = mcCollision.eventPlaneAngle(); + float vtxz = mcCollision.posZ(); + evPhi = RecoDecay::constrainAngle(evPhi); + + int64_t nCh = 0; + int64_t nChGlobal = 0; + int64_t nChGen = 0; + float centrality = 0; + float lRandom = fRndm->Rndm(); + float weff = 1.; + float wacc = 1.; + auto bc = mcCollision.bc_as(); + if (cfgIRFetch) { + initHadronicRate(bc); + double hadronicRate = mRateFetcher.fetch(ccdb.service, bc.timestamp(), mRunNumber, "ZNC hadronic") * 1.e-3; // + double seconds = bc.timestamp() * 1.e-3 - mMinSeconds; + if (cfgIRCutEnabled && (hadronicRate < cfgIRMin || hadronicRate > cfgIRMax)) { // cut on hadronic rate + return; + } + gCurrentHadronicRate->Fill(seconds, hadronicRate); + } - histos.fill(HIST("hPtMCGen"), pt); - histos.fill(HIST("hEtaPtVtxzMCGen"), eta, pt, vtxz); + if (collisions.size() > -1) { + histos.fill(HIST("numberOfRecoCollisions"), collisions.size()); // number of times coll was reco-ed + histos.fill(HIST("RecoEventCounter"), 0.5); + if (cfgRecoEvRejectMC) { + if (collisions.size() != 1) { // only pass those have one reconstruction event + return; + } + histos.fill(HIST("RecoEventCounter"), 1.5); + for (auto const& collision : collisions) { + if (!eventSelected(collision)) { + return; + } } + histos.fill(HIST("RecoEventCounter"), 2.5); } } - } - PROCESS_SWITCH(FlowMcUpc, processMCTrue, "process pure simulation information", true); - - using MCRecoTracks = soa::Join; - using MCRecoCollisions = soa::Join; + histos.fill(HIST("RecoEventCounter"), 3.5); + + if (imp >= minB && imp <= maxB) { + // event within range + histos.fill(HIST("hImpactParameter"), imp); + histos.fill(HIST("hEventPlaneAngle"), evPhi); + if (cfgFlowCumulantEnabled) { + loadCentVsIPTruth(bc.timestamp()); + centrality = mCentVsIPTruth->GetBinContent(mCentVsIPTruth->GetXaxis()->FindBin(imp)); + fGFWTrue->Clear(); + fGFWReco->Clear(); + } - // PresliceUnsorted trackPerMcParticle = aod::udmctracklabel::udMcParticleId; - Preslice trackPerCollision = aod::udtrack::udCollisionId; // sorted preslice used because the pair track-collision is already sorted in processDataSG function + double psi2Est = 0, psi3Est = 0, psi4Est = 0; + float wEPeff = 1; + double v2 = 0, v3 = 0, v4 = 0; + double q2x = 0, q2y = 0; + double q3x = 0, q3y = 0; + double q4x = 0, q4y = 0; + for (auto const& mcParticle : mcParticles) { + int pdgCode = std::abs(mcParticle.pdgCode()); + if (pdgCode != PDG_t::kElectron && pdgCode != PDG_t::kMuonMinus && pdgCode != PDG_t::kPiPlus && pdgCode != kKPlus && pdgCode != PDG_t::kProton) { + continue; + } + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + if (std::fabs(mcParticle.eta()) > cfgCutEta) { // main acceptance + continue; + } + nChGen++; + if (mcParticle.has_tracks()) { + auto const& tracks = mcParticle.tracks_as(); + for (auto const& track : tracks) { + if (!trackSelected(track)) { + continue; + } + if (cfgIsGlobalTrack && track.isGlobalTrack()) { + nChGlobal++; + } + if (!cfgIsGlobalTrack && track.hasTPC() && track.hasITS()) { + nChGlobal++; + } + if (cfgTrackDensityCorrUse && cfgFlowCumulantEnabled) { + bool withinPtRef = (cfgCutPtRefMin < track.pt()) && (track.pt() < cfgCutPtRefMax); // within RF pT rang + if (withinPtRef) { + q2x += std::cos(2 * track.phi()); + q2y += std::sin(2 * track.phi()); + q3x += std::cos(3 * track.phi()); + q3y += std::sin(3 * track.phi()); + q4x += std::cos(4 * track.phi()); + q4y += std::sin(4 * track.phi()); + } + } + } + } + } + if (nChGlobal > 0 && nChGen > 0) { + // fill only when Nch is not zero + histos.fill(HIST("hNchRecoVsNchGen"), nChGlobal, nChGen); + } + if (cfgTrackDensityCorrUse && cfgFlowCumulantEnabled) { + psi2Est = std::atan2(q2y, q2x) / 2.; + psi3Est = std::atan2(q3y, q3x) / 3.; + psi4Est = std::atan2(q4y, q4x) / 4.; + v2 = funcV2->Eval(centrality); + v3 = funcV3->Eval(centrality); + v4 = funcV4->Eval(centrality); + } - void processReco(MCRecoCollisions const& collisions, MCRecoTracks const& tracks, aod::UDMcParticles const& mcParticles) - { - histos.fill(HIST("numberOfRecoCollisions"), mcParticles.size()); // number of times coll was reco-ed - // std::cout << "process reco" << std::endl; - for (const auto& collision : collisions) { - Partition pvContributors = aod::udtrack::isPVContributor == true; - pvContributors.bindTable(tracks); - // std::cout << "collision loop" << std::endl; - histos.fill(HIST("RecoProcessEventCounter"), 0.5); - // if (!eventSelected(collision)) - // return; - histos.fill(HIST("RecoProcessEventCounter"), 1.5); - // if (!collision.has_udMcCollision()) - // return; - histos.fill(HIST("RecoProcessEventCounter"), 2.5); - histos.fill(HIST("RecoProcessEventCounter"), 3.5); - - float vtxz = collision.posZ(); - - // auto const& tempTracks = tracks.sliceBy(trackPerCollision, static_cast(collision.globalIndex())); - // std::cout << "sliced" << std::endl; - - for (const auto& track : tracks) { - histos.fill(HIST("RecoProcessTrackCounter"), 0.5); - // std::cout << "track loop" << std::endl; + for (auto const& mcParticle : mcParticles) { // focus on bulk: e, mu, pi, k, p - auto momentum = std::array{track.px(), track.py(), track.pz()}; - double pt = RecoDecay::pt(momentum); - double eta = RecoDecay::eta(momentum); - // double phi = RecoDecay::phi(momentum); - if (!trackSelected(track) || (!track.has_udMcParticle())) - continue; - histos.fill(HIST("RecoProcessTrackCounter"), 1.5); - // std::cout << "track selected" << std::endl; - auto mcParticle = track.udMcParticle(); - // std::cout << "mc particle" << std::endl; int pdgCode = std::abs(mcParticle.pdgCode()); - // std::cout << "pdg code" << std::endl; + bool extraPDGType = true; + if (cfgK0Lambda0Enabled) { + extraPDGType = (pdgCode != PDG_t::kK0Short && pdgCode != PDG_t::kLambda0); + } + if (extraPDGType && pdgCode != PDG_t::kElectron && pdgCode != PDG_t::kMuonMinus && pdgCode != PDG_t::kPiPlus && pdgCode != kKPlus && pdgCode != PDG_t::kProton) { + continue; + } - // double pt = recoMC.Pt(); - // double eta = recoMC.Eta(); - if (pdgCode != PDG_t::kElectron && pdgCode != PDG_t::kMuonMinus && pdgCode != PDG_t::kPiPlus && pdgCode != PDG_t::kKPlus && pdgCode != PDG_t::kProton) { - // std::cout << "pdg code not in list" << std::endl; + bool isPhysicalPrimary = mcParticle.isPhysicalPrimary(); + const int producedByDecay = 4; + bool isSecondary = (mcParticle.has_mothers() && mcParticle.getProcess() == producedByDecay); + bool isAcceptedSecondary = (cfgAcceptSecondaries) ? isSecondary : false; + if (!isPhysicalPrimary && !isAcceptedSecondary) { continue; } - histos.fill(HIST("RecoProcessTrackCounter"), 2.5); - if (std::fabs(eta) > cfgCutEta) { - // std::cout << "cfgcuteta" << std::endl; + + if (std::fabs(mcParticle.eta()) > cfgCutEta) { // main acceptance continue; - } // main acceptance - histos.fill(HIST("RecoProcessTrackCounter"), 3.5); - if (!mcParticle.isPhysicalPrimary()) { - // std::cout << "not physical primary" << std::endl; + } + + float deltaPhi = mcParticle.phi() - mcCollision.eventPlaneAngle(); + deltaPhi = RecoDecay::constrainAngle(deltaPhi); + histos.fill(HIST("hPtVsPhiGenerated"), deltaPhi, mcParticle.pt()); + histos.fill(HIST("hBVsPtVsPhiGenerated"), imp, deltaPhi, mcParticle.pt()); + histos.fill(HIST("hPtNchGenerated"), mcParticle.pt(), nChGlobal); + histos.fill(HIST("hPtMCGen"), mcParticle.pt()); + histos.fill(HIST("hEtaPtVtxzMCGen"), mcParticle.eta(), mcParticle.pt(), vtxz); + if (pdgCode == PDG_t::kPiPlus) { + histos.fill(HIST("hPtNchGeneratedPion"), mcParticle.pt(), nChGlobal); + } + if (pdgCode == PDG_t::kKPlus) { + histos.fill(HIST("hPtNchGeneratedKaon"), mcParticle.pt(), nChGlobal); + } + if (pdgCode == PDG_t::kProton) { + histos.fill(HIST("hPtNchGeneratedProton"), mcParticle.pt(), nChGlobal); + } + if (pdgCode == PDG_t::kK0Short) { + histos.fill(HIST("hPtNchGeneratedK0"), mcParticle.pt(), nChGlobal); + } + if (pdgCode == PDG_t::kLambda0) { + histos.fill(HIST("hPtNchGeneratedLambda"), mcParticle.pt(), nChGlobal); + } + if (mcParticle.has_daughters()) { + for (const auto& d : mcParticle.template daughters_as()) { + if (std::abs(d.pdgCode()) == PDG_t::kPiPlus) { + if (pdgCode == PDG_t::kK0Short) { + histos.fill(HIST("hPtNchGeneratedK0Pions"), d.pt(), nChGlobal); + } + if (pdgCode == PDG_t::kLambda0) { + histos.fill(HIST("hPtNchGeneratedLambdaPions"), d.pt(), nChGlobal); + } + } + if (pdgCode == PDG_t::kLambda0 && std::abs(d.pdgCode()) == PDG_t::kProton) { + histos.fill(HIST("hPtNchGeneratedLambdaProtons"), d.pt(), nChGlobal); + } + } + } + nCh++; + + bool validGlobal = false; + bool validTrack = false; + bool validTOFTrack = false; + bool validTPCTrack = false; + bool validITSTrack = false; + bool validITSABTrack = false; + if (mcParticle.has_tracks()) { + auto const& tracks = mcParticle.tracks_as(); + for (auto const& track : tracks) { + if (!trackSelected(track)) { + continue; + } + histos.fill(HIST("hnTPCClu"), track.tpcNClsFound()); + histos.fill(HIST("hnITSClu"), track.itsNCls()); + if (cfgIsGlobalTrack && track.isGlobalTrack()) { + validGlobal = true; + } + if (!cfgIsGlobalTrack && track.hasTPC() && track.hasITS()) { + validGlobal = true; + } + if (track.hasTOF() && validGlobal) { + validTOFTrack = true; + } + if (track.hasTPC() || track.hasITS()) { + validTrack = true; + } + if (track.hasTPC()) { + validTPCTrack = true; + } + if (track.hasITS() && track.itsChi2NCl() > -1. * epsilon) { + validITSTrack = true; + } + if (track.hasITS() && track.itsChi2NCl() < -1. * epsilon) { + validITSABTrack = true; + } + } + } + bool withinPtRef = (cfgCutPtRefMin < mcParticle.pt()) && (mcParticle.pt() < cfgCutPtRefMax); // within RF pT range + bool withinPtPOI = (cfgCutPtPOIMin < mcParticle.pt()) && (mcParticle.pt() < cfgCutPtPOIMax); // within POI pT range + if (cfgOutputNUAWeights && withinPtRef) { + fWeights->fill(mcParticle.phi(), mcParticle.eta(), vtxz, mcParticle.pt(), 0, 0); + } + if (!setCurrentParticleWeights(weff, wacc, mcParticle.phi(), mcParticle.eta(), mcParticle.pt(), vtxz)) { continue; } - histos.fill(HIST("RecoProcessTrackCounter"), 4.5); + if (cfgTrackDensityCorrUse && cfgFlowCumulantEnabled && withinPtRef) { + double fphi = v2 * std::cos(2 * (mcParticle.phi() - psi2Est)) + v3 * std::cos(3 * (mcParticle.phi() - psi3Est)) + v4 * std::cos(4 * (mcParticle.phi() - psi4Est)); + fphi = (1 + 2 * fphi); + int pTBinForEff = hFindPtBin->FindBin(mcParticle.pt()); + if (pTBinForEff >= 1 && pTBinForEff <= hFindPtBin->GetNbinsX()) { + wEPeff = funcEff[pTBinForEff - 1]->Eval(fphi * nChGlobal); + if (wEPeff > 0.) { + wEPeff = 1. / wEPeff; + weff *= wEPeff; + histos.fill(HIST("hPhiWeightedTrDen"), mcParticle.phi(), wacc * wEPeff); + } + } + } + + if (cfgFlowCumulantEnabled) { + if (withinPtRef) { + fGFWTrue->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 1); + } + if (withinPtPOI) { + fGFWTrue->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 2); + } + if (withinPtPOI && withinPtRef) { + fGFWTrue->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 4); + } + + if (validGlobal) { + if (withinPtRef) { + fGFWReco->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 1); + } + if (withinPtPOI) { + fGFWReco->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 2); + } + if (withinPtPOI && withinPtRef) { + fGFWReco->Fill(mcParticle.eta(), fPtAxis->FindBin(mcParticle.pt()) - 1, mcParticle.phi(), wacc * weff, 4); + } + } + } - histos.fill(HIST("hPtReco"), pt); - histos.fill(HIST("hEtaPtVtxzMCReco"), eta, pt, vtxz); - // std::cout << "first loop end" << std::endl; + if (withinPtRef) { + histos.fill(HIST("hEPVsPhiMC"), evPhi, mcParticle.phi()); + } + + if (validGlobal && withinPtRef) { + histos.fill(HIST("hPhi"), mcParticle.phi()); + histos.fill(HIST("hPhiWeighted"), mcParticle.phi(), wacc); + histos.fill(HIST("hEPVsPhi"), evPhi, mcParticle.phi()); + } + + // if valid global, fill + if (validGlobal) { + histos.fill(HIST("hPtVsPhiGlobal"), deltaPhi, mcParticle.pt(), wacc * weff); + histos.fill(HIST("hBVsPtVsPhiGlobal"), imp, deltaPhi, mcParticle.pt(), wacc * weff); + histos.fill(HIST("hPtNchGlobal"), mcParticle.pt(), nChGlobal); + histos.fill(HIST("hPtMCGlobal"), mcParticle.pt()); + histos.fill(HIST("hEtaPtVtxzMCGlobal"), mcParticle.eta(), mcParticle.pt(), vtxz); + if (pdgCode == PDG_t::kPiPlus) { + histos.fill(HIST("hPtNchGlobalPion"), mcParticle.pt(), nChGlobal); + } + if (pdgCode == PDG_t::kKPlus) { + histos.fill(HIST("hPtNchGlobalKaon"), mcParticle.pt(), nChGlobal); + } + if (pdgCode == PDG_t::kProton) { + histos.fill(HIST("hPtNchGlobalProton"), mcParticle.pt(), nChGlobal); + } + if (pdgCode == PDG_t::kK0Short) { + histos.fill(HIST("hPtNchGlobalK0"), mcParticle.pt(), nChGlobal); + } + if (pdgCode == PDG_t::kLambda0) { + histos.fill(HIST("hPtNchGlobalLambda"), mcParticle.pt(), nChGlobal); + } + if (!cfgRequireTOF || validTOFTrack) { + if (mcParticle.has_mothers()) { + for (const auto& m : mcParticle.template mothers_as()) { + if (!m.isPhysicalPrimary()) { + continue; + } + if (pdgCode == PDG_t::kPiPlus) { + if (m.pdgCode() == PDG_t::kK0Short) { + histos.fill(HIST("hPtNchGlobalK0Pions"), mcParticle.pt(), nChGlobal); + } + if (m.pdgCode() == PDG_t::kLambda0) { + histos.fill(HIST("hPtNchGlobalLambdaPions"), mcParticle.pt(), nChGlobal); + } + } + if (pdgCode == PDG_t::kProton && m.pdgCode() == PDG_t::kLambda0) + histos.fill(HIST("hPtNchGlobalLambdaProtons"), mcParticle.pt(), nChGlobal); + } + } + } + } + // if any track present, fill + if (validTrack) + histos.fill(HIST("hBVsPtVsPhiAny"), imp, deltaPhi, mcParticle.pt(), wacc * weff); + if (validTPCTrack) + histos.fill(HIST("hBVsPtVsPhiTPCTrack"), imp, deltaPhi, mcParticle.pt(), wacc * weff); + if (validITSTrack) + histos.fill(HIST("hBVsPtVsPhiITSTrack"), imp, deltaPhi, mcParticle.pt(), wacc * weff); + if (validITSABTrack) + histos.fill(HIST("hBVsPtVsPhiITSABTrack"), imp, deltaPhi, mcParticle.pt(), wacc * weff); + } + + if (cfgFlowCumulantEnabled) { + for (uint l_ind = 0; l_ind < corrconfigsTruth.size(); l_ind++) { + fillFC(fGFWTrue, true, corrconfigsTruth.at(l_ind), centrality, lRandom); + } + for (uint l_ind = 0; l_ind < corrconfigsReco.size(); l_ind++) { + fillFC(fGFWReco, false, corrconfigsReco.at(l_ind), centrality, lRandom); + } + } + } + histos.fill(HIST("hNchVsImpactParameter"), imp, nCh); + } + PROCESS_SWITCH(FlowMcUpc, processMCTrue, "process pure simulation information", true); + + void processReco(soa::Join::iterator const& collision, aod::BCsWithTimestamps const&, FilteredTracks const& tracks, aod::McParticles const&, aod::McCollisions const&) + { + auto bc = collision.template foundBC_as(); + histos.fill(HIST("RecoProcessEventCounter"), 0.5); + if (!eventSelected(collision)) + return; + histos.fill(HIST("RecoProcessEventCounter"), 1.5); + if (tracks.size() < 1) + return; + histos.fill(HIST("RecoProcessEventCounter"), 2.5); + for (const auto& track : tracks) { + if (!trackSelected(track)) + continue; + histos.fill(HIST("hPtReco"), track.pt()); + auto mcParticle = track.mcParticle(); + int pdgCode = std::abs(mcParticle.pdgCode()); + bool extraPDGType = true; + if (cfgK0Lambda0Enabled) { + extraPDGType = (pdgCode != PDG_t::kK0Short && pdgCode != PDG_t::kLambda0); } + if (extraPDGType && pdgCode != PDG_t::kElectron && pdgCode != PDG_t::kMuonMinus && pdgCode != PDG_t::kPiPlus && pdgCode != kKPlus && pdgCode != PDG_t::kProton) + continue; + if (!mcParticle.isPhysicalPrimary()) + continue; + if (std::fabs(mcParticle.eta()) > cfgCutEta) // main acceptance + continue; + histos.fill(HIST("hPtReco_PhysicalPrimary"), track.pt()); } } PROCESS_SWITCH(FlowMcUpc, processReco, "process reconstructed information", true); @@ -233,4 +930,4 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ adaptAnalysisTask(cfgc)}; -} +} \ No newline at end of file From f1e5fd6bfc663a05fcb5a1d3858ce829916e127d Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Sat, 1 Aug 2026 14:59:27 +0000 Subject: [PATCH 71/71] Please consider the following formatting changes --- PWGUD/Tasks/flowMcUpc.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PWGUD/Tasks/flowMcUpc.cxx b/PWGUD/Tasks/flowMcUpc.cxx index 7f9addf3e59..0beea9ad785 100644 --- a/PWGUD/Tasks/flowMcUpc.cxx +++ b/PWGUD/Tasks/flowMcUpc.cxx @@ -546,7 +546,7 @@ struct FlowMcUpc { // veto an event if FT0C amplitude in previous ITS ROF is above threshold return 0; } - if (cfgITSTPCVertex && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)){ + if (cfgITSTPCVertex && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { return 0; } return 1; @@ -930,4 +930,4 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ adaptAnalysisTask(cfgc)}; -} \ No newline at end of file +}