From d785d187942a5d5b3428bbe95d3ad6e8e3d05a84 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Thu, 30 Oct 2025 13:21:51 +0100 Subject: [PATCH 01/48] [PWGHF] Add UPC process function and QA hists to taskDplus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds support for analyzing Ultra-Peripheral Collisions (UPC) in the D± → π± K∓ π± analysis, following the implementation in taskLc. Changes include: - Added UPC-related library dependencies in CMakeLists.txt - Added CCDB manager and UPC helper includes - Implemented GapType enum for gap classification - Added QA histograms for FT0 and ZDC detectors - Implemented determineGapType() function for event classification - Added runAnalysisPerCollisionDataWithUpc() template function - Added processDataWithMlWithUpc() process function - Added candDplusPerCollision Preslice for efficient candidate slicing The UPC analysis uses FT0 and ZDC detector information to classify events into Gap A, Gap C, or Double Gap categories based on detector thresholds, enabling studies of diffractive processes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/CMakeLists.txt | 2 +- PWGHF/D2H/Tasks/taskDplus.cxx | 114 ++++++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/PWGHF/D2H/Tasks/CMakeLists.txt b/PWGHF/D2H/Tasks/CMakeLists.txt index 76caf26673f..dca9fd09e21 100644 --- a/PWGHF/D2H/Tasks/CMakeLists.txt +++ b/PWGHF/D2H/Tasks/CMakeLists.txt @@ -81,7 +81,7 @@ o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons o2physics_add_dpl_workflow(task-dplus SOURCES taskDplus.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::SGCutParHolder O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-ds diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 5948f00d1f1..629c31f61c4 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -16,6 +16,7 @@ /// \author Fabio Catalano , Politecnico and INFN Torino /// \author Vít Kučera , CERN /// \author Luca Aglietta , University and INFN Torino +/// \author Minjung Kim , Inha University #include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/Core/DecayChannels.h" @@ -26,11 +27,13 @@ #include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsAnalysis.h" #include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGUD/Core/UPCHelpers.h" #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include #include #include #include @@ -50,6 +53,7 @@ #include #include #include +#include #include using namespace o2; @@ -58,6 +62,13 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::hf_centrality; using namespace o2::hf_occupancy; +using namespace o2::hf_evsel; + +enum class GapType { + GapA = 0, + GapC = 1, + DoubleGap = 2, +}; /// D± analysis task struct HfTaskDplus { @@ -73,6 +84,13 @@ struct HfTaskDplus { Configurable storeOccupancy{"storeOccupancy", false, "Flag to store occupancy information"}; Configurable storePvContributors{"storePvContributors", false, "Flag to store number of PV contributors information"}; Configurable fillMcBkgHistos{"fillMcBkgHistos", false, "Flag to fill and store histograms for MC background"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + + HfEventSelection hfEvSel; // event selection and monitoring + + Service ccdb; using CandDplusData = soa::Filtered>; using CandDplusDataWithMl = soa::Filtered>; @@ -85,6 +103,7 @@ struct HfTaskDplus { Filter filterDplusFlag = (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi))) != static_cast(0); + Preslice candDplusPerCollision = aod::hf_cand::collisionId; Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; PresliceUnsorted recoColPerMcCollision = aod::mccollisionlabel::mcCollisionId; @@ -122,9 +141,11 @@ struct HfTaskDplus { {"hEtaRecBg", "3-prong candidates (unmatched);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, {"hEtaGen", "MC particles (matched);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}}}; + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + void init(InitContext&) { - std::array doprocess{doprocessData, doprocessDataWithMl, doprocessMc, doprocessMcWithMl}; + std::array doprocess{doprocessData, doprocessDataWithMl, doprocessMc, doprocessMcWithMl, doprocessDataWithMlWithUpc}; if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { LOGP(fatal, "Only one process function should be enabled! Please check your configuration!"); } @@ -239,6 +260,19 @@ struct HfTaskDplus { registry.add("hSparseMassGenPrompt", "THn for gen Prompt Dplus", HistType::kTHnSparseF, axesGenPrompt); registry.add("hSparseMassGenFD", "THn for gen FD Dplus", HistType::kTHnSparseF, axesGenFD); } + + qaRegistry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); + qaRegistry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); + qaRegistry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}); + qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapA) + 1, "A"); + qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapC) + 1, "C"); + qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::DoubleGap) + 1, "Double"); + + hfEvSel.addHistograms(qaRegistry); // collision monitoring + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); } // Fill histograms of quantities for the reconstructed Dplus candidates @@ -646,6 +680,71 @@ struct HfTaskDplus { } } + GapType determineGapType(float FT0A, float FT0C, float ZNA, float ZNC) + { + constexpr float FT0AThreshold = 100.0; + constexpr float FT0CThreshold = 50.0; + constexpr float ZDCThreshold = 1.0; + if (FT0A < FT0AThreshold && FT0C > FT0CThreshold && ZNA < ZDCThreshold && ZNC > ZDCThreshold) { + return GapType::GapA; + } + if (FT0A > FT0AThreshold && FT0C < FT0CThreshold && ZNA > ZDCThreshold && ZNC < ZDCThreshold) { + return GapType::GapC; + } + return GapType::DoubleGap; + } + + template + void runAnalysisPerCollisionDataWithUpc(CollType const& collisions, + CandType const& candidates, + BCsType const& bcs, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds) + { + for (const auto& collision : collisions) { + uint32_t rejectionMask{0}; // 32 bits, in case new ev. selections will be added + float centrality{-1.f}; + rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, qaRegistry, bcs); + if (rejectionMask != 0) { + /// at least one event selection not satisfied --> reject the candidate + continue; + } + auto bc = collision.template bc_as(); + upchelpers::FITInfo fitInfo{}; + udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); + + GapType gap = GapType::DoubleGap; + if (bc.has_zdc()) { + auto zdc = bc.zdc(); + qaRegistry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); + qaRegistry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); + gap = determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC()); + qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), static_cast(gap)); + } + if (gap == GapType::GapA || gap == GapType::GapC) { + // Use the candidates from this collision + const auto thisCollId = collision.globalIndex(); + const auto& groupedDplusCandidates = candidates.sliceBy(candDplusPerCollision, thisCollId); + float cent{-1.f}; + float occ{-1.f}; + float numPvContr{-1.f}; + float ptBhad{-1.f}; + int const flagBHad{-1}; + + for (const auto& candidate : groupedDplusCandidates) { + if ((yCandRecoMax >= 0. && std::abs(HfHelper::yDplus(candidate)) > yCandRecoMax)) { + continue; + } + fillHisto(candidate); + if constexpr (fillMl) { + fillSparseML(candidate, ptBhad, flagBHad, cent, occ, numPvContr); + } + } + } + } + } + // process functions void processData(CandDplusData const& candidates, CollisionsCent const& collisions) { @@ -678,6 +777,19 @@ struct HfTaskDplus { runAnalysisMcGen(mcGenCollisions, mcRecoCollisions, mcGenParticles); } PROCESS_SWITCH(HfTaskDplus, processMcWithMl, "Process MC with ML", false); + + void processDataWithMlWithUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + CandDplusDataWithMl const& selectedDplusCandidatesMl, + aod::Tracks const&, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds, + aod::Zdcs const& /*zdcs*/) + { + runAnalysisPerCollisionDataWithUpc(collisions, selectedDplusCandidatesMl, bcs, ft0s, fv0as, fdds); + } + PROCESS_SWITCH(HfTaskDplus, processDataWithMlWithUpc, "Process real data with the ML method with UPC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) From db90b42f312ab91c8e4c27735ddba97d9b0a0c22 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Thu, 30 Oct 2025 13:37:20 +0100 Subject: [PATCH 02/48] [PWGHF] Add UPC process function and QA hists to taskD0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds support for analyzing Ultra-Peripheral Collisions (UPC) in the D0 → K- π+ analysis, following the implementation in taskLc and taskDplus. Changes include: - Added UPC-related library dependencies in CMakeLists.txt - Added CCDB manager and UPC helper includes - Implemented GapType enum for gap classification - Added QA histograms for FT0 and ZDC detectors - Implemented determineGapType() function for event classification - Added runAnalysisPerCollisionDataWithUpc() template function - Added processDataWithDCAFitterNMlWithUpc() process function - Added candD0PerCollision Preslice for efficient candidate slicing The UPC analysis uses FT0 and ZDC detector information to classify events into Gap A, Gap C, or Double Gap categories based on detector thresholds, enabling studies of diffractive processes in D0 production. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/CMakeLists.txt | 2 +- PWGHF/D2H/Tasks/taskD0.cxx | 134 ++++++++++++++++++++++++++++++++- 2 files changed, 134 insertions(+), 2 deletions(-) diff --git a/PWGHF/D2H/Tasks/CMakeLists.txt b/PWGHF/D2H/Tasks/CMakeLists.txt index dca9fd09e21..6e6ab7bf096 100644 --- a/PWGHF/D2H/Tasks/CMakeLists.txt +++ b/PWGHF/D2H/Tasks/CMakeLists.txt @@ -71,7 +71,7 @@ o2physics_add_dpl_workflow(task-charm-reso-to-d-trk-reduced o2physics_add_dpl_workflow(task-d0 SOURCES taskD0.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 3f74a0b4efa..51288d52c8b 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -14,6 +14,7 @@ /// /// \author Gian Michele Innocenti , CERN /// \author Vít Kučera , CERN +/// \author Minjung Kim , CERN #include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/Core/DecayChannels.h" @@ -24,6 +25,7 @@ #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGUD/Core/UPCHelpers.h" #include "Common/CCDB/ctpRateFetcher.h" #include "Common/Core/RecoDecay.h" @@ -58,6 +60,13 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::hf_centrality; using namespace o2::hf_occupancy; +using namespace o2::hf_evsel; + +enum class GapType { + GapA = 0, + GapC = 1, + DoubleGap = 2, +}; /// D0 analysis task namespace @@ -89,8 +98,12 @@ struct HfTaskD0 { // ML inference Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + HfEventSelection hfEvSel; // event selection and monitoring + ctpRateFetcher mRateFetcher; SliceCache cache; @@ -111,6 +124,8 @@ struct HfTaskD0 { using CollisionsWithMcLabels = soa::Join; using CollisionsWithMcLabelsCent = soa::Join; using TracksSelQuality = soa::Join; + + Preslice candD0PerCollision = aod::hf_cand::collisionId; PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; PresliceUnsorted colPerMcCollisionCent = aod::mccollisionlabel::mcCollisionId; @@ -219,9 +234,11 @@ struct HfTaskD0 { {"hMassReflBkgD0bar", "2-prong candidates (matched);#it{m}_{inv} (GeV/#it{c}^{2}); #it{p}_{T}; #it{y}", {HistType::kTH3F, {{120, 1.5848, 2.1848}, {150, 0., 30.}, {20, -5., 5.}}}}, {"hMassSigBkgD0bar", "2-prong candidates (not checked);#it{m}_{inv} (GeV/#it{c}^{2}); #it{p}_{T}; #it{y}", {HistType::kTH3F, {{120, 1.5848, 2.1848}, {150, 0., 30.}, {20, -5., 5.}}}}}}; + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + void init(InitContext&) { - std::array doprocess{doprocessDataWithDCAFitterN, doprocessDataWithDCAFitterNCent, doprocessDataWithKFParticle, doprocessMcWithDCAFitterN, doprocessMcWithDCAFitterNCent, doprocessMcWithKFParticle, doprocessDataWithDCAFitterNMl, doprocessDataWithDCAFitterNMlCent, doprocessDataWithKFParticleMl, doprocessMcWithDCAFitterNMl, doprocessMcWithDCAFitterNMlCent, doprocessMcWithKFParticleMl}; + std::array doprocess{doprocessDataWithDCAFitterN, doprocessDataWithDCAFitterNCent, doprocessDataWithKFParticle, doprocessMcWithDCAFitterN, doprocessMcWithDCAFitterNCent, doprocessMcWithKFParticle, doprocessDataWithDCAFitterNMl, doprocessDataWithDCAFitterNMlCent, doprocessDataWithKFParticleMl, doprocessMcWithDCAFitterNMl, doprocessMcWithDCAFitterNMlCent, doprocessMcWithKFParticleMl, doprocessDataWithDCAFitterNMlWithUpc}; if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) == 0) { LOGP(fatal, "At least one process function should be enabled at a time."); } @@ -333,6 +350,15 @@ struct HfTaskD0 { registry.get(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"))->Sumw2(); } + qaRegistry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); + qaRegistry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); + qaRegistry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}); + qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapA) + 1, "A"); + qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapC) + 1, "C"); + qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::DoubleGap) + 1, "Double"); + + hfEvSel.addHistograms(qaRegistry); + ccdb->setURL(ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -517,6 +543,99 @@ struct HfTaskD0 { } } } + + GapType determineGapType(float FT0A, float FT0C, float ZNA, float ZNC) + { + constexpr float FT0AThreshold = 100.0; + constexpr float FT0CThreshold = 50.0; + constexpr float ZDCThreshold = 1.0; + if (FT0A < FT0AThreshold && FT0C > FT0CThreshold && ZNA < ZDCThreshold && ZNC > ZDCThreshold) { + return GapType::GapA; + } + if (FT0A > FT0AThreshold && FT0C < FT0CThreshold && ZNA > ZDCThreshold && ZNC < ZDCThreshold) { + return GapType::GapC; + } + return GapType::DoubleGap; + } + + template + void runAnalysisPerCollisionDataWithUpc(CollType const& collisions, + CandType const& candidates, + BCsType const& bcs, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds) + { + for (const auto& collision : collisions) { + uint32_t rejectionMask{0}; + float centrality{-1.f}; + rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, qaRegistry, bcs); + if (rejectionMask != 0) { + continue; + } + auto bc = collision.template bc_as(); + upchelpers::FITInfo fitInfo{}; + udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); + + GapType gap = GapType::DoubleGap; + if (bc.has_zdc()) { + auto zdc = bc.zdc(); + qaRegistry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); + qaRegistry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); + gap = determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC()); + qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), static_cast(gap)); + } + if (gap == GapType::GapA || gap == GapType::GapC) { + const auto thisCollId = collision.globalIndex(); + const auto& groupedD0Candidates = candidates.sliceBy(candD0PerCollision, thisCollId); + + for (const auto& candidate : groupedD0Candidates) { + if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { + continue; + } + if (yCandRecoMax >= 0. && std::abs(HfHelper::yD0(candidate)) > yCandRecoMax) { + continue; + } + + float massD0 = HfHelper::invMassD0ToPiK(candidate); + float massD0bar = HfHelper::invMassD0barToKPi(candidate); + auto ptCandidate = candidate.pt(); + + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hMass"), massD0, ptCandidate); + registry.fill(HIST("hMassFinerBinning"), massD0, ptCandidate); + registry.fill(HIST("hMassVsPhi"), massD0, ptCandidate, candidate.phi()); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hMass"), massD0bar, ptCandidate); + registry.fill(HIST("hMassFinerBinning"), massD0bar, ptCandidate); + registry.fill(HIST("hMassVsPhi"), massD0bar, ptCandidate, candidate.phi()); + } + + if constexpr (fillMl) { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), SigD0); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); + } + } else { + if (candidate.isSelD0() >= selectionFlagD0) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), SigD0); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); + } + } + } + } + } + } + void processDataWithDCAFitterN(D0Candidates const&, Collisions const& collisions, aod::TracksWExtra const& tracks, aod::BcFullInfos const& bcs) { processData(selectedD0Candidates, collisions, tracks, bcs); @@ -978,6 +1097,19 @@ struct HfTaskD0 { } PROCESS_SWITCH(HfTaskD0, processMcWithKFParticleMl, "Process MC with KFParticle and ML selections", false); // TODO: add the processMcWithKFParticleMlCent + + void processDataWithDCAFitterNMlWithUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + D0CandidatesMl const&, + aod::TracksWExtra const& tracks, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds, + aod::Zdcs const& /*zdcs*/) + { + runAnalysisPerCollisionDataWithUpc(collisions, selectedD0CandidatesMl, bcs, ft0s, fv0as, fdds); + } + PROCESS_SWITCH(HfTaskD0, processDataWithDCAFitterNMlWithUpc, "Process real data with DCAFitterN and ML with UPC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) From 52a31bd1d01bcc45fa5aba04b9610657b41247f8 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Thu, 30 Oct 2025 13:58:58 +0100 Subject: [PATCH 03/48] Fix author affiliation in taskDplus --- PWGHF/D2H/Tasks/taskDplus.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 629c31f61c4..bb1b4ba3363 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -16,7 +16,7 @@ /// \author Fabio Catalano , Politecnico and INFN Torino /// \author Vít Kučera , CERN /// \author Luca Aglietta , University and INFN Torino -/// \author Minjung Kim , Inha University +/// \author Minjung Kim , CERN #include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/Core/DecayChannels.h" From 3257fd4ac1e797234941ce0791d4cbf7b3cb58e1 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Thu, 30 Oct 2025 13:48:48 +0000 Subject: [PATCH 04/48] Please consider the following formatting changes --- PWGHF/D2H/Tasks/taskD0.cxx | 2 +- PWGHF/D2H/Tasks/taskDplus.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 51288d52c8b..9c1c490ddb4 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -14,7 +14,7 @@ /// /// \author Gian Michele Innocenti , CERN /// \author Vít Kučera , CERN -/// \author Minjung Kim , CERN +/// \author Minjung Kim , CERN #include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/Core/DecayChannels.h" diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index bb1b4ba3363..fea4b761760 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -16,7 +16,7 @@ /// \author Fabio Catalano , Politecnico and INFN Torino /// \author Vít Kučera , CERN /// \author Luca Aglietta , University and INFN Torino -/// \author Minjung Kim , CERN +/// \author Minjung Kim , CERN #include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/Core/DecayChannels.h" From 940159c32fd83008fc0c5c89db9fd065a124a1d0 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Fri, 7 Nov 2025 14:29:10 +0100 Subject: [PATCH 05/48] [PWGHF] Refactor UPC code: move utilities to utilsUpcHf.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add new utility header PWGHF/Utils/utilsUpcHf.h with: - GapType enum for UPC gap classification - determineGapType() function with configurable thresholds - Helper functions: isSingleSidedGap(), gapTypeToInt(), getGapTypeName() - UpcQaHistoConfig struct for consistent histogram binning - Refactor taskD0.cxx and taskDplus.cxx to use shared utilities - Remove duplicate GapType enum and determineGapType() from both tasks - Add gap type axis to THnSparse histograms for UPC analysis - Improve code maintainability and reusability across HF UPC tasks 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskD0.cxx | 50 ++++++-------- PWGHF/D2H/Tasks/taskDplus.cxx | 76 +++++++++++---------- PWGHF/Utils/utilsUpcHf.h | 123 ++++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+), 67 deletions(-) create mode 100644 PWGHF/Utils/utilsUpcHf.h diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 9c1c490ddb4..4d25aefe2c1 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -25,6 +25,7 @@ #include "PWGHF/DataModel/CandidateSelectionTables.h" #include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsUpcHf.h" #include "PWGUD/Core/UPCHelpers.h" #include "Common/CCDB/ctpRateFetcher.h" @@ -61,12 +62,7 @@ using namespace o2::framework::expressions; using namespace o2::hf_centrality; using namespace o2::hf_occupancy; using namespace o2::hf_evsel; - -enum class GapType { - GapA = 0, - GapC = 1, - DoubleGap = 2, -}; +using namespace o2::analysis::hf_upc; /// D0 analysis task namespace @@ -157,6 +153,7 @@ struct HfTaskD0 { ConfigurableAxis thnConfigAxisMinItsNCls{"thnConfigAxisMinItsNCls", {5, 3, 8}, "axis for minimum ITS NCls of candidate prongs"}; ConfigurableAxis thnConfigAxisMinTpcNCrossedRows{"thnConfigAxisMinTpcNCrossedRows", {10, 70, 180}, "axis for minimum TPC NCls crossed rows of candidate prongs"}; ConfigurableAxis thnConfigAxisIR{"thnConfigAxisIR", {5000, 0, 500}, "Interaction rate (kHz)"}; + ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {3, -0.5, 2.5}, "axis for UPC gap type (0=GapA, 1=GapC, 2=DoubleGap)"}; HistogramRegistry registry{ "registry", @@ -301,6 +298,7 @@ struct HfTaskD0 { const AxisSpec thnAxisMinItsNCls{thnConfigAxisMinItsNCls, "Minimum ITS cluster found"}; const AxisSpec thnAxisMinTpcNCrossedRows{thnConfigAxisMinTpcNCrossedRows, "Minimum TPC crossed rows"}; const AxisSpec thnAxisIR{thnConfigAxisIR, "Interaction rate"}; + const AxisSpec thnAxisGapType{thnConfigAxisGapType, "Gap type"}; if (doprocessMcWithDCAFitterN || doprocessMcWithDCAFitterNCent || doprocessMcWithKFParticle || doprocessMcWithDCAFitterNMl || doprocessMcWithDCAFitterNMlCent || doprocessMcWithKFParticleMl) { std::vector axesAcc = {thnAxisGenPtD, thnAxisGenPtB, thnAxisY, thnAxisOrigin, thnAxisNumPvContr}; @@ -334,6 +332,9 @@ struct HfTaskD0 { axes.push_back(thnAxisMinItsNCls); axes.push_back(thnAxisMinTpcNCrossedRows); } + if (doprocessDataWithDCAFitterNMlWithUpc) { + axes.push_back(thnAxisGapType); + } if (applyMl) { const AxisSpec thnAxisBkgScore{thnConfigAxisBkgScore, "BDT score bkg."}; const AxisSpec thnAxisNonPromptScore{thnConfigAxisNonPromptScore, "BDT score non-prompt."}; @@ -544,20 +545,6 @@ struct HfTaskD0 { } } - GapType determineGapType(float FT0A, float FT0C, float ZNA, float ZNC) - { - constexpr float FT0AThreshold = 100.0; - constexpr float FT0CThreshold = 50.0; - constexpr float ZDCThreshold = 1.0; - if (FT0A < FT0AThreshold && FT0C > FT0CThreshold && ZNA < ZDCThreshold && ZNC > ZDCThreshold) { - return GapType::GapA; - } - if (FT0A > FT0AThreshold && FT0C < FT0CThreshold && ZNA > ZDCThreshold && ZNC < ZDCThreshold) { - return GapType::GapC; - } - return GapType::DoubleGap; - } - template void runAnalysisPerCollisionDataWithUpc(CollType const& collisions, CandType const& candidates, @@ -582,10 +569,11 @@ struct HfTaskD0 { auto zdc = bc.zdc(); qaRegistry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); qaRegistry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); - gap = determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC()); - qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), static_cast(gap)); + gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC()); + qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } - if (gap == GapType::GapA || gap == GapType::GapC) { + if (hf_upc::isSingleSidedGap(gap)) { + int const gapTypeInt = hf_upc::gapTypeToInt(gap); const auto thisCollId = collision.globalIndex(); const auto& groupedD0Candidates = candidates.sliceBy(candD0PerCollision, thisCollId); @@ -614,21 +602,21 @@ struct HfTaskD0 { if constexpr (fillMl) { if (candidate.isSelD0() >= selectionFlagD0) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), SigD0); - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), SigD0, static_cast(gapTypeInt)); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, static_cast(gapTypeInt)); } if (candidate.isSelD0bar() >= selectionFlagD0bar) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar); - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar, static_cast(gapTypeInt)); + registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, static_cast(gapTypeInt)); } } else { if (candidate.isSelD0() >= selectionFlagD0) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), SigD0); - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), SigD0, static_cast(gapTypeInt)); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, static_cast(gapTypeInt)); } if (candidate.isSelD0bar() >= selectionFlagD0bar) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar); - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar, static_cast(gapTypeInt)); + registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, static_cast(gapTypeInt)); } } } diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index fea4b761760..1346d65da63 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -27,6 +27,7 @@ #include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsAnalysis.h" #include "PWGHF/Utils/utilsEvSelHf.h" +#include "PWGHF/Utils/utilsUpcHf.h" #include "PWGUD/Core/UPCHelpers.h" #include "Common/Core/RecoDecay.h" @@ -63,12 +64,7 @@ using namespace o2::framework::expressions; using namespace o2::hf_centrality; using namespace o2::hf_occupancy; using namespace o2::hf_evsel; - -enum class GapType { - GapA = 0, - GapC = 1, - DoubleGap = 2, -}; +using namespace o2::analysis::hf_upc; /// D± analysis task struct HfTaskDplus { @@ -128,6 +124,7 @@ struct HfTaskDplus { ConfigurableAxis thnConfigAxisMlScore0{"thnConfigAxisMlScore0", {100, 0., 1.}, "axis for ML output score 0"}; ConfigurableAxis thnConfigAxisMlScore1{"thnConfigAxisMlScore1", {100, 0., 1.}, "axis for ML output score 1"}; ConfigurableAxis thnConfigAxisMlScore2{"thnConfigAxisMlScore2", {100, 0., 1.}, "axis for ML output score 2"}; + ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {3, -0.5, 2.5}, "axis for UPC gap type (0=GapA, 1=GapC, 2=DoubleGap)"}; HistogramRegistry registry{ "registry", @@ -161,6 +158,7 @@ struct HfTaskDplus { AxisSpec const thnAxisCent{thnConfigAxisCent, "Centrality"}; AxisSpec const thnAxisOccupancy{thnConfigAxisOccupancy, "Occupancy"}; AxisSpec const thnAxisPvContributors{thnConfigAxisPvContributors, "PV contributors"}; + AxisSpec const thnAxisGapType{thnConfigAxisGapType, "Gap type"}; registry.add("hMass", "3-prong candidates;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{350, 1.7, 2.05}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("hEta", "3-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); @@ -200,10 +198,10 @@ struct HfTaskDplus { registry.add("hPtVsYGenPrompt", "MC particles (matched, prompt);#it{p}_{T}^{gen.}; #it{y}", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); registry.add("hPtVsYGenNonPrompt", "MC particles (matched, non-prompt);#it{p}_{T}^{gen.}; #it{y}", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}}); - if (doprocessDataWithMl || doprocessData) { + if (doprocessDataWithMl || doprocessData || doprocessDataWithMlWithUpc) { std::vector axes = {thnAxisMass, thnAxisPt}; - if (doprocessDataWithMl) { + if (doprocessDataWithMl || doprocessDataWithMlWithUpc) { axes.push_back(thnAxisMlScore0); axes.push_back(thnAxisMlScore1); axes.push_back(thnAxisMlScore2); @@ -214,6 +212,9 @@ struct HfTaskDplus { if (storeOccupancy) { axes.push_back(thnAxisOccupancy); } + if (doprocessDataWithMlWithUpc) { + axes.push_back(thnAxisGapType); + } registry.add("hSparseMass", "THn for Dplus", HistType::kTHnSparseF, axes); } @@ -313,13 +314,15 @@ struct HfTaskDplus { /// \param centrality collision centrality /// \param occupancy collision occupancy /// \param numPvContributors contributors to the PV + /// \param gapType UPC gap type (-1 for non-UPC) template void fillSparseML(const T1& candidate, float ptbhad, int flagBHad, float centrality, float occupancy, - float numPvContributors) + float numPvContributors, + int gapType = -1) { std::vector outputMl = {-999., -999., -999.}; for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { @@ -384,16 +387,30 @@ struct HfTaskDplus { } } } else { // Data - if (storeCentrality && storeOccupancy) { - registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, occupancy); - } else if (storeCentrality && !storeOccupancy) { - registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality); - } else if (!storeCentrality && storeOccupancy) { - registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], occupancy); - } else if (!storeCentrality && !storeOccupancy && storePvContributors) { - registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], numPvContributors); + if (gapType >= 0) { + // UPC mode: always include gap type + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, occupancy, static_cast(gapType)); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, static_cast(gapType)); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], occupancy, static_cast(gapType)); + } else { + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], static_cast(gapType)); + } } else { - registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); + // Non-UPC mode: original behavior + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, occupancy); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], occupancy); + } else if (!storeCentrality && !storeOccupancy && storePvContributors) { + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], numPvContributors); + } else { + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); + } } } } @@ -680,20 +697,6 @@ struct HfTaskDplus { } } - GapType determineGapType(float FT0A, float FT0C, float ZNA, float ZNC) - { - constexpr float FT0AThreshold = 100.0; - constexpr float FT0CThreshold = 50.0; - constexpr float ZDCThreshold = 1.0; - if (FT0A < FT0AThreshold && FT0C > FT0CThreshold && ZNA < ZDCThreshold && ZNC > ZDCThreshold) { - return GapType::GapA; - } - if (FT0A > FT0AThreshold && FT0C < FT0CThreshold && ZNA > ZDCThreshold && ZNC < ZDCThreshold) { - return GapType::GapC; - } - return GapType::DoubleGap; - } - template void runAnalysisPerCollisionDataWithUpc(CollType const& collisions, CandType const& candidates, @@ -719,10 +722,10 @@ struct HfTaskDplus { auto zdc = bc.zdc(); qaRegistry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); qaRegistry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); - gap = determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC()); - qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), static_cast(gap)); + gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC()); + qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } - if (gap == GapType::GapA || gap == GapType::GapC) { + if (hf_upc::isSingleSidedGap(gap)) { // Use the candidates from this collision const auto thisCollId = collision.globalIndex(); const auto& groupedDplusCandidates = candidates.sliceBy(candDplusPerCollision, thisCollId); @@ -731,6 +734,7 @@ struct HfTaskDplus { float numPvContr{-1.f}; float ptBhad{-1.f}; int const flagBHad{-1}; + int const gapTypeInt = hf_upc::gapTypeToInt(gap); for (const auto& candidate : groupedDplusCandidates) { if ((yCandRecoMax >= 0. && std::abs(HfHelper::yDplus(candidate)) > yCandRecoMax)) { @@ -738,7 +742,7 @@ struct HfTaskDplus { } fillHisto(candidate); if constexpr (fillMl) { - fillSparseML(candidate, ptBhad, flagBHad, cent, occ, numPvContr); + fillSparseML(candidate, ptBhad, flagBHad, cent, occ, numPvContr, gapTypeInt); } } } diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h new file mode 100644 index 00000000000..f721743ef59 --- /dev/null +++ b/PWGHF/Utils/utilsUpcHf.h @@ -0,0 +1,123 @@ +// 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 utilsUpcHf.h +/// \brief Utility functions for Ultra-Peripheral Collision (UPC) analysis in Heavy Flavor physics +/// +/// \author Minjung Kim , CERN + +#ifndef PWGHF_UTILS_UTILSUPCHF_H_ +#define PWGHF_UTILS_UTILSUPCHF_H_ + +#include + +namespace o2::analysis::hf_upc +{ + +/// \brief Gap type classification for UPC events +enum class GapType : uint8_t { + GapA = 0, ///< Gap on A-side (C-side active) + GapC = 1, ///< Gap on C-side (A-side active) + DoubleGap = 2 ///< Double gap (both sides empty) +}; + +/// \brief Default thresholds for gap determination +namespace defaults +{ +constexpr float FT0AThreshold = 100.0f; ///< FT0-A amplitude threshold (a.u.) +constexpr float FT0CThreshold = 50.0f; ///< FT0-C amplitude threshold (a.u.) +constexpr float ZDCThreshold = 1.0f; ///< ZDC energy threshold (a.u.) +} // namespace defaults + +/// \brief Determine gap type based on FIT and ZDC signals +/// \param ft0A FT0-A amplitude +/// \param ft0C FT0-C amplitude +/// \param zdcA ZDC-A (ZNA) common energy +/// \param zdcC ZDC-C (ZNC) common energy +/// \param ft0AThreshold Threshold for FT0-A (default: 100.0) +/// \param ft0CThreshold Threshold for FT0-C (default: 50.0) +/// \param zdcThreshold Threshold for ZDC (default: 1.0) +/// \return Gap type classification +inline GapType determineGapType(float ft0A, float ft0C, float zdcA, float zdcC, + float ft0AThreshold = defaults::FT0AThreshold, + float ft0CThreshold = defaults::FT0CThreshold, + float zdcThreshold = defaults::ZDCThreshold) +{ + // Gap on A-side: FT0-A empty, FT0-C active, ZNA empty, ZNC active + if (ft0A < ft0AThreshold && ft0C > ft0CThreshold && + zdcA < zdcThreshold && zdcC > zdcThreshold) { + return GapType::GapA; + } + + // Gap on C-side: FT0-A active, FT0-C empty, ZNA active, ZNC empty + if (ft0A > ft0AThreshold && ft0C < ft0CThreshold && + zdcA > zdcThreshold && zdcC < zdcThreshold) { + return GapType::GapC; + } + + // Default: Double gap (or no clear gap) + return GapType::DoubleGap; +} + +/// \brief Check if the gap type is a single-sided gap (GapA or GapC) +/// \param gap Gap type +/// \return true if single-sided gap, false otherwise +inline bool isSingleSidedGap(GapType gap) +{ + return (gap == GapType::GapA || gap == GapType::GapC); +} + +/// \brief Get gap type name as string +/// \param gap Gap type +/// \return String representation of gap type +inline const char* getGapTypeName(GapType gap) +{ + switch (gap) { + case GapType::GapA: + return "GapA"; + case GapType::GapC: + return "GapC"; + case GapType::DoubleGap: + return "DoubleGap"; + default: + return "Unknown"; + } +} + +/// \brief Convert gap type to integer for histogram filling +/// \param gap Gap type +/// \return Integer representation (0=GapA, 1=GapC, 2=DoubleGap) +inline int gapTypeToInt(GapType gap) +{ + return static_cast(gap); +} + +/// \brief Struct to hold UPC QA histogram configuration +struct UpcQaHistoConfig { + // FT0 histogram configuration + int ft0Nbins = 1500; + float ft0Min = 0.f; + float ft0Max = 1500.f; + + // ZDC histogram configuration + int zdcNbins = 200; + float zdcMin = 0.f; + float zdcMax = 20.f; + + // Gap type histogram configuration + int gapNbins = 3; + float gapMin = -0.5f; + float gapMax = 2.5f; +}; + +} // namespace o2::analysis::hf_upc + +#endif // PWGHF_UTILS_UTILSUPCHF_H_ From 03673b566667e93f5e5c5f452094dd1b60ceb48d Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Fri, 7 Nov 2025 14:43:01 +0100 Subject: [PATCH 06/48] [PWGHF] Refactor UPC THnSparse filling: use vectorized approach with lambda MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Refactor both taskD0 and taskDplus to use consistent vector-based filling - Add lambda function fillTHnData for cleaner, more maintainable code - Build valuesToFill vector dynamically and push gap type - Revert fillSparseML modifications in taskDplus (remove gapType param) - Replace explicit registry.fill() calls with THnSparse->Fill(vector) - Consistent with taskLc implementation pattern - Reduces code duplication and improves readability 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskD0.cxx | 32 +++++++++++++++------ PWGHF/D2H/Tasks/taskDplus.cxx | 54 ++++++++++++++++------------------- 2 files changed, 49 insertions(+), 37 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 4d25aefe2c1..ff841046bbc 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -600,23 +600,39 @@ struct HfTaskD0 { registry.fill(HIST("hMassVsPhi"), massD0bar, ptCandidate, candidate.phi()); } + // Fill THnSparse with gap type using vectorized approach similar to taskDplus if constexpr (fillMl) { + auto fillTHnData = [&](float mass, int d0Type) { + std::vector valuesToFill{candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], + static_cast(mass), static_cast(ptCandidate), + static_cast(HfHelper::yD0(candidate)), static_cast(d0Type)}; + valuesToFill.push_back(static_cast(gapTypeInt)); + registry.get(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); + }; + if (candidate.isSelD0() >= selectionFlagD0) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), SigD0, static_cast(gapTypeInt)); - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, static_cast(gapTypeInt)); + fillTHnData(massD0, SigD0); + fillTHnData(massD0, candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); } if (candidate.isSelD0bar() >= selectionFlagD0bar) { - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar, static_cast(gapTypeInt)); - registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, static_cast(gapTypeInt)); + fillTHnData(massD0bar, SigD0bar); + fillTHnData(massD0bar, candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); } } else { + auto fillTHnData = [&](float mass, int d0Type) { + std::vector valuesToFill{static_cast(mass), static_cast(ptCandidate), + static_cast(HfHelper::yD0(candidate)), static_cast(d0Type)}; + valuesToFill.push_back(static_cast(gapTypeInt)); + registry.get(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); + }; + if (candidate.isSelD0() >= selectionFlagD0) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), SigD0, static_cast(gapTypeInt)); - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, static_cast(gapTypeInt)); + fillTHnData(massD0, SigD0); + fillTHnData(massD0, candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); } if (candidate.isSelD0bar() >= selectionFlagD0bar) { - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar, static_cast(gapTypeInt)); - registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, static_cast(gapTypeInt)); + fillTHnData(massD0bar, SigD0bar); + fillTHnData(massD0bar, candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); } } } diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 1346d65da63..43893aad8b3 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -314,15 +314,13 @@ struct HfTaskDplus { /// \param centrality collision centrality /// \param occupancy collision occupancy /// \param numPvContributors contributors to the PV - /// \param gapType UPC gap type (-1 for non-UPC) template void fillSparseML(const T1& candidate, float ptbhad, int flagBHad, float centrality, float occupancy, - float numPvContributors, - int gapType = -1) + float numPvContributors) { std::vector outputMl = {-999., -999., -999.}; for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { @@ -387,30 +385,16 @@ struct HfTaskDplus { } } } else { // Data - if (gapType >= 0) { - // UPC mode: always include gap type - if (storeCentrality && storeOccupancy) { - registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, occupancy, static_cast(gapType)); - } else if (storeCentrality && !storeOccupancy) { - registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, static_cast(gapType)); - } else if (!storeCentrality && storeOccupancy) { - registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], occupancy, static_cast(gapType)); - } else { - registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], static_cast(gapType)); - } + if (storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, occupancy); + } else if (storeCentrality && !storeOccupancy) { + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality); + } else if (!storeCentrality && storeOccupancy) { + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], occupancy); + } else if (!storeCentrality && !storeOccupancy && storePvContributors) { + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], numPvContributors); } else { - // Non-UPC mode: original behavior - if (storeCentrality && storeOccupancy) { - registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, occupancy); - } else if (storeCentrality && !storeOccupancy) { - registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality); - } else if (!storeCentrality && storeOccupancy) { - registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], occupancy); - } else if (!storeCentrality && !storeOccupancy && storePvContributors) { - registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], numPvContributors); - } else { - registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); - } + registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); } } } @@ -732,8 +716,6 @@ struct HfTaskDplus { float cent{-1.f}; float occ{-1.f}; float numPvContr{-1.f}; - float ptBhad{-1.f}; - int const flagBHad{-1}; int const gapTypeInt = hf_upc::gapTypeToInt(gap); for (const auto& candidate : groupedDplusCandidates) { @@ -742,7 +724,21 @@ struct HfTaskDplus { } fillHisto(candidate); if constexpr (fillMl) { - fillSparseML(candidate, ptBhad, flagBHad, cent, occ, numPvContr, gapTypeInt); + // Fill THn with gap type using lambda function similar to taskLc + std::vector outputMl = {-999., -999., -999.}; + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { + outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMl->at(iclass)]; + } + + std::vector valuesToFill{HfHelper::invMassDplusToPiKPi(candidate), static_cast(candidate.pt()), outputMl[0], outputMl[1], outputMl[2]}; + if (storeCentrality) { + valuesToFill.push_back(cent); + } + if (storeOccupancy) { + valuesToFill.push_back(occ); + } + valuesToFill.push_back(static_cast(gapTypeInt)); + registry.get(HIST("hSparseMass"))->Fill(valuesToFill.data()); } } } From ff52550ad5b27724fe41929a1b0d4f62b5d17ae6 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Fri, 7 Nov 2025 14:49:04 +0100 Subject: [PATCH 07/48] [PWGHF] Add FT0A and FT0C axes to taskD0 UPC THnSparse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add ConfigurableAxis for FT0A and FT0C (1001 bins, -1.5 to 999.5) - Bin centers at -1, 0, 1, 2, ..., 999 for integer amplitude values - Add axes to THnSparse when doprocessDataWithDCAFitterNMlWithUpc is enabled - Include FT0A and FT0C amplitudes in fillTHnData lambda function - Enables detailed analysis of forward detector signals in UPC events - Complements gap type classification with raw detector information 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskD0.cxx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index ff841046bbc..63dd859661a 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -154,6 +154,8 @@ struct HfTaskD0 { ConfigurableAxis thnConfigAxisMinTpcNCrossedRows{"thnConfigAxisMinTpcNCrossedRows", {10, 70, 180}, "axis for minimum TPC NCls crossed rows of candidate prongs"}; ConfigurableAxis thnConfigAxisIR{"thnConfigAxisIR", {5000, 0, 500}, "Interaction rate (kHz)"}; ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {3, -0.5, 2.5}, "axis for UPC gap type (0=GapA, 1=GapC, 2=DoubleGap)"}; + ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; HistogramRegistry registry{ "registry", @@ -299,6 +301,8 @@ struct HfTaskD0 { const AxisSpec thnAxisMinTpcNCrossedRows{thnConfigAxisMinTpcNCrossedRows, "Minimum TPC crossed rows"}; const AxisSpec thnAxisIR{thnConfigAxisIR, "Interaction rate"}; const AxisSpec thnAxisGapType{thnConfigAxisGapType, "Gap type"}; + const AxisSpec thnAxisFT0A{thnConfigAxisFT0A, "FT0-A amplitude"}; + const AxisSpec thnAxisFT0C{thnConfigAxisFT0C, "FT0-C amplitude"}; if (doprocessMcWithDCAFitterN || doprocessMcWithDCAFitterNCent || doprocessMcWithKFParticle || doprocessMcWithDCAFitterNMl || doprocessMcWithDCAFitterNMlCent || doprocessMcWithKFParticleMl) { std::vector axesAcc = {thnAxisGenPtD, thnAxisGenPtB, thnAxisY, thnAxisOrigin, thnAxisNumPvContr}; @@ -334,6 +338,8 @@ struct HfTaskD0 { } if (doprocessDataWithDCAFitterNMlWithUpc) { axes.push_back(thnAxisGapType); + axes.push_back(thnAxisFT0A); + axes.push_back(thnAxisFT0C); } if (applyMl) { const AxisSpec thnAxisBkgScore{thnConfigAxisBkgScore, "BDT score bkg."}; @@ -600,13 +606,15 @@ struct HfTaskD0 { registry.fill(HIST("hMassVsPhi"), massD0bar, ptCandidate, candidate.phi()); } - // Fill THnSparse with gap type using vectorized approach similar to taskDplus + // Fill THnSparse with gap type and FIT signals using vectorized approach if constexpr (fillMl) { auto fillTHnData = [&](float mass, int d0Type) { std::vector valuesToFill{candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], static_cast(mass), static_cast(ptCandidate), static_cast(HfHelper::yD0(candidate)), static_cast(d0Type)}; valuesToFill.push_back(static_cast(gapTypeInt)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); registry.get(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); }; @@ -623,6 +631,8 @@ struct HfTaskD0 { std::vector valuesToFill{static_cast(mass), static_cast(ptCandidate), static_cast(HfHelper::yD0(candidate)), static_cast(d0Type)}; valuesToFill.push_back(static_cast(gapTypeInt)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); registry.get(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); }; From b91499ac8ae06e43cb70cfc7b42fea867c01b66e Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Fri, 7 Nov 2025 14:51:32 +0100 Subject: [PATCH 08/48] [PWGHF] Add FT0A and FT0C axes to taskDplus UPC THnSparse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add ConfigurableAxis for FT0A and FT0C (1001 bins, -1.5 to 999.5) - Bin centers at -1, 0, 1, 2, ..., 999 for integer amplitude values - Add axes to THnSparse when doprocessDataWithMlWithUpc is enabled - Include FT0A and FT0C amplitudes in valuesToFill vector - Consistent with taskD0 implementation - Enables detailed analysis of forward detector signals in UPC events 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskDplus.cxx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 43893aad8b3..c7cd631af2d 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -125,6 +125,8 @@ struct HfTaskDplus { ConfigurableAxis thnConfigAxisMlScore1{"thnConfigAxisMlScore1", {100, 0., 1.}, "axis for ML output score 1"}; ConfigurableAxis thnConfigAxisMlScore2{"thnConfigAxisMlScore2", {100, 0., 1.}, "axis for ML output score 2"}; ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {3, -0.5, 2.5}, "axis for UPC gap type (0=GapA, 1=GapC, 2=DoubleGap)"}; + ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; HistogramRegistry registry{ "registry", @@ -159,6 +161,8 @@ struct HfTaskDplus { AxisSpec const thnAxisOccupancy{thnConfigAxisOccupancy, "Occupancy"}; AxisSpec const thnAxisPvContributors{thnConfigAxisPvContributors, "PV contributors"}; AxisSpec const thnAxisGapType{thnConfigAxisGapType, "Gap type"}; + AxisSpec const thnAxisFT0A{thnConfigAxisFT0A, "FT0-A amplitude"}; + AxisSpec const thnAxisFT0C{thnConfigAxisFT0C, "FT0-C amplitude"}; registry.add("hMass", "3-prong candidates;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{350, 1.7, 2.05}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("hEta", "3-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); @@ -214,6 +218,8 @@ struct HfTaskDplus { } if (doprocessDataWithMlWithUpc) { axes.push_back(thnAxisGapType); + axes.push_back(thnAxisFT0A); + axes.push_back(thnAxisFT0C); } registry.add("hSparseMass", "THn for Dplus", HistType::kTHnSparseF, axes); @@ -724,7 +730,7 @@ struct HfTaskDplus { } fillHisto(candidate); if constexpr (fillMl) { - // Fill THn with gap type using lambda function similar to taskLc + // Fill THn with gap type and FIT signals std::vector outputMl = {-999., -999., -999.}; for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMl->at(iclass)]; @@ -738,6 +744,8 @@ struct HfTaskDplus { valuesToFill.push_back(occ); } valuesToFill.push_back(static_cast(gapTypeInt)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); registry.get(HIST("hSparseMass"))->Fill(valuesToFill.data()); } } From 1c10742d55b7def3e27207e2649e54081b073343 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Fri, 7 Nov 2025 14:57:37 +0100 Subject: [PATCH 09/48] [PWGHF] Unify taskD0 THnSparse structure with taskDplus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Reorder axes to match taskDplus: [mass, pt, mlScores, y, d0Type, cent, occ, gapType, FT0A, FT0C] - Insert ML scores after pt (position 2) instead of at the beginning - Add centrality and occupancy support in UPC filling function - Conditional filling based on storeCentrality and storeOccupancyAndIR flags - Consistent THnSparse structure across both D0 and Dplus tasks - Enables flexible analysis with optional centrality/occupancy axes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskD0.cxx | 45 ++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 63dd859661a..d95d1458ba6 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -336,20 +336,29 @@ struct HfTaskD0 { axes.push_back(thnAxisMinItsNCls); axes.push_back(thnAxisMinTpcNCrossedRows); } - if (doprocessDataWithDCAFitterNMlWithUpc) { - axes.push_back(thnAxisGapType); - axes.push_back(thnAxisFT0A); - axes.push_back(thnAxisFT0C); - } if (applyMl) { const AxisSpec thnAxisBkgScore{thnConfigAxisBkgScore, "BDT score bkg."}; const AxisSpec thnAxisNonPromptScore{thnConfigAxisNonPromptScore, "BDT score non-prompt."}; const AxisSpec thnAxisPromptScore{thnConfigAxisPromptScore, "BDT score prompt."}; - axes.insert(axes.begin(), thnAxisPromptScore); - axes.insert(axes.begin(), thnAxisNonPromptScore); - axes.insert(axes.begin(), thnAxisBkgScore); + // Insert ML scores after pt (position 2) to match taskDplus structure: [mass, pt, mlScores, ...] + if (doprocessDataWithDCAFitterNMlWithUpc) { + axes.insert(axes.begin() + 2, thnAxisPromptScore); + axes.insert(axes.begin() + 2, thnAxisNonPromptScore); + axes.insert(axes.begin() + 2, thnAxisBkgScore); + } else { + axes.insert(axes.begin(), thnAxisPromptScore); + axes.insert(axes.begin(), thnAxisNonPromptScore); + axes.insert(axes.begin(), thnAxisBkgScore); + } + } + if (doprocessDataWithDCAFitterNMlWithUpc) { + axes.push_back(thnAxisGapType); + axes.push_back(thnAxisFT0A); + axes.push_back(thnAxisFT0C); + } + if (applyMl) { registry.add("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type", "Thn for D0 candidates", HistType::kTHnSparseD, axes); registry.get(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"))->Sumw2(); } else { @@ -582,6 +591,8 @@ struct HfTaskD0 { int const gapTypeInt = hf_upc::gapTypeToInt(gap); const auto thisCollId = collision.globalIndex(); const auto& groupedD0Candidates = candidates.sliceBy(candD0PerCollision, thisCollId); + float cent{centrality}; + float occ{-1.f}; for (const auto& candidate : groupedD0Candidates) { if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { @@ -606,12 +617,18 @@ struct HfTaskD0 { registry.fill(HIST("hMassVsPhi"), massD0bar, ptCandidate, candidate.phi()); } - // Fill THnSparse with gap type and FIT signals using vectorized approach + // Fill THnSparse with structure matching taskDplus: [mass, pt, mlScores, cent, occ, gapType, FT0A, FT0C] if constexpr (fillMl) { auto fillTHnData = [&](float mass, int d0Type) { - std::vector valuesToFill{candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], - static_cast(mass), static_cast(ptCandidate), + std::vector valuesToFill{static_cast(mass), static_cast(ptCandidate), + candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], static_cast(HfHelper::yD0(candidate)), static_cast(d0Type)}; + if (storeCentrality) { + valuesToFill.push_back(cent); + } + if (storeOccupancyAndIR) { + valuesToFill.push_back(occ); + } valuesToFill.push_back(static_cast(gapTypeInt)); valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); @@ -630,6 +647,12 @@ struct HfTaskD0 { auto fillTHnData = [&](float mass, int d0Type) { std::vector valuesToFill{static_cast(mass), static_cast(ptCandidate), static_cast(HfHelper::yD0(candidate)), static_cast(d0Type)}; + if (storeCentrality) { + valuesToFill.push_back(cent); + } + if (storeOccupancyAndIR) { + valuesToFill.push_back(occ); + } valuesToFill.push_back(static_cast(gapTypeInt)); valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); From 9d0c94272e9199b0f5a1dc121ca0eb2ddf04aa25 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Fri, 7 Nov 2025 16:30:46 +0100 Subject: [PATCH 10/48] [PWGHF] Add configurable UPC gap thresholds and enable occupancy storage This commit introduces configurable thresholds for UPC gap determination and enables occupancy/IR storage for UPC processes in taskD0 and taskDplus. Changes: - Add configurable parameters for FT0A, FT0C, and ZDC thresholds in taskD0 and taskDplus, with defaults from utilsUpcHf.h - Update determineGapType calls to use configurable thresholds instead of hardcoded values - Enable storeOccupancyAndIR for UPC process in taskD0 by updating validation check to include doprocessDataWithDCAFitterNMlWithUpc - Add occupancy calculation in taskDplus UPC process to properly store occupancy values when storeOccupancy is enabled Benefits: - Allows users to optimize gap selection criteria via configuration files - Enables occupancy and interaction rate studies in UPC analyses - Maintains consistency with taskLc approach for occupancy handling - Provides flexibility for different beam conditions and physics requirements Default threshold values (defined in utilsUpcHf.h): - FT0A: 100.0 a.u. - FT0C: 50.0 a.u. - ZDC: 1.0 a.u. --- PWGHF/D2H/Tasks/taskD0.cxx | 12 +++++++++--- PWGHF/D2H/Tasks/taskDplus.cxx | 11 ++++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index d95d1458ba6..ab967b5b29c 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -157,6 +157,11 @@ struct HfTaskD0 { ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; + // UPC gap determination thresholds + Configurable upcFT0AThreshold{"upcFT0AThreshold", hf_upc::defaults::FT0AThreshold, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcFT0CThreshold{"upcFT0CThreshold", hf_upc::defaults::FT0CThreshold, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcZDCThreshold{"upcZDCThreshold", hf_upc::defaults::ZDCThreshold, "ZDC energy threshold for UPC gap determination (a.u.)"}; + HistogramRegistry registry{ "registry", {{"hPtCand", "2-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, @@ -244,8 +249,8 @@ struct HfTaskD0 { if ((doprocessDataWithDCAFitterN || doprocessDataWithDCAFitterNCent || doprocessMcWithDCAFitterN || doprocessMcWithDCAFitterNCent || doprocessDataWithDCAFitterNMl || doprocessDataWithDCAFitterNMlCent || doprocessMcWithDCAFitterNMl || doprocessMcWithDCAFitterNMlCent) && (doprocessDataWithKFParticle || doprocessMcWithKFParticle || doprocessDataWithKFParticleMl || doprocessMcWithKFParticleMl)) { LOGP(fatal, "DCAFitterN and KFParticle can not be enabled at a time."); } - if ((storeCentrality || storeOccupancyAndIR) && !(doprocessDataWithDCAFitterNCent || doprocessMcWithDCAFitterNCent || doprocessDataWithDCAFitterNMlCent || doprocessMcWithDCAFitterNMlCent)) { - LOGP(fatal, "Can't enable the storeCentrality and storeOccupancu without cent process"); + if ((storeCentrality || storeOccupancyAndIR) && !(doprocessDataWithDCAFitterNCent || doprocessMcWithDCAFitterNCent || doprocessDataWithDCAFitterNMlCent || doprocessMcWithDCAFitterNMlCent || doprocessDataWithDCAFitterNMlWithUpc)) { + LOGP(fatal, "Can't enable the storeCentrality and storeOccupancu without cent process or UPC process"); } auto vbins = (std::vector)binsPt; registry.add("hMass", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{500, 0., 5.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); @@ -584,7 +589,8 @@ struct HfTaskD0 { auto zdc = bc.zdc(); qaRegistry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); qaRegistry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); - gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC()); + gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC(), + upcFT0AThreshold, upcFT0CThreshold, upcZDCThreshold); qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } if (hf_upc::isSingleSidedGap(gap)) { diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index c7cd631af2d..06bc2318c9c 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -128,6 +128,11 @@ struct HfTaskDplus { ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; + // UPC gap determination thresholds + Configurable upcFT0AThreshold{"upcFT0AThreshold", hf_upc::defaults::FT0AThreshold, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcFT0CThreshold{"upcFT0CThreshold", hf_upc::defaults::FT0CThreshold, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcZDCThreshold{"upcZDCThreshold", hf_upc::defaults::ZDCThreshold, "ZDC energy threshold for UPC gap determination (a.u.)"}; + HistogramRegistry registry{ "registry", {{"hPt", "3-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, @@ -712,7 +717,8 @@ struct HfTaskDplus { auto zdc = bc.zdc(); qaRegistry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); qaRegistry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); - gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC()); + gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC(), + upcFT0AThreshold, upcFT0CThreshold, upcZDCThreshold); qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } if (hf_upc::isSingleSidedGap(gap)) { @@ -721,6 +727,9 @@ struct HfTaskDplus { const auto& groupedDplusCandidates = candidates.sliceBy(candDplusPerCollision, thisCollId); float cent{-1.f}; float occ{-1.f}; + if (storeOccupancy && occEstimator != OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + } float numPvContr{-1.f}; int const gapTypeInt = hf_upc::gapTypeToInt(gap); From 45b7d1016e0304962d690d10b2015a0614af8f09 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Fri, 7 Nov 2025 16:49:22 +0100 Subject: [PATCH 11/48] [PWGHF] Fix linting errors: struct member order and naming - Move HfHelper, HfEventSelection, and ccdb declarations after all Configurable members in taskD0 and taskDplus (PWGHF struct member order) - Rename UpcQaHistoConfig to HfUpcQaHistoConfig to comply with PWGHF naming convention (structs must start with Hf) --- PWGHF/D2H/Tasks/taskD0.cxx | 8 ++++++++ PWGHF/Utils/utilsUpcHf.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index ab967b5b29c..80bcbe3b45a 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -162,6 +162,14 @@ struct HfTaskD0 { Configurable upcFT0CThreshold{"upcFT0CThreshold", hf_upc::defaults::FT0CThreshold, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcZDCThreshold{"upcZDCThreshold", hf_upc::defaults::ZDCThreshold, "ZDC energy threshold for UPC gap determination (a.u.)"}; + HfEventSelection hfEvSel; // event selection and monitoring + + HfHelper hfHelper; + ctpRateFetcher mRateFetcher; + + SliceCache cache; + Service ccdb; + HistogramRegistry registry{ "registry", {{"hPtCand", "2-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h index f721743ef59..4080464b971 100644 --- a/PWGHF/Utils/utilsUpcHf.h +++ b/PWGHF/Utils/utilsUpcHf.h @@ -101,7 +101,7 @@ inline int gapTypeToInt(GapType gap) } /// \brief Struct to hold UPC QA histogram configuration -struct UpcQaHistoConfig { +struct HfUpcQaHistoConfig { // FT0 histogram configuration int ft0Nbins = 1500; float ft0Min = 0.f; From e6c3308b4462742f73de7c756e90386929724ff0 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Fri, 7 Nov 2025 16:53:01 +0100 Subject: [PATCH 12/48] [PWGHF] Fix struct member order: move using declarations after Service - Move all using type alias declarations to after Service<> declarations - Complies with PWGHF struct member order: Configurables, then other members, then Service, then using declarations --- PWGHF/D2H/Tasks/taskD0.cxx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 80bcbe3b45a..ce0ccbb2480 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -170,6 +170,22 @@ struct HfTaskD0 { SliceCache cache; Service ccdb; + using D0Candidates = soa::Join; + using D0CandidatesMc = soa::Join; + using D0CandidatesKF = soa::Join; + using D0CandidatesMcKF = soa::Join; + + using D0CandidatesMl = soa::Join; + using D0CandidatesMlMc = soa::Join; + using D0CandidatesMlKF = soa::Join; + using D0CandidatesMlMcKF = soa::Join; + + using Collisions = soa::Join; + using CollisionsCent = soa::Join; + using CollisionsWithMcLabels = soa::Join; + using CollisionsWithMcLabelsCent = soa::Join; + using TracksSelQuality = soa::Join; + HistogramRegistry registry{ "registry", {{"hPtCand", "2-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, From 4cef76decd87a75b610313dbf167b1d19b1afe33 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Mon, 10 Nov 2025 20:30:47 +0100 Subject: [PATCH 13/48] Fix PWGHF struct member order: move ConfigurableAxis after Partition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to PWGHF coding guidelines, ConfigurableAxis must appear AFTER Partition declarations. The correct order is: 1. Configurable 2. Other members (HfHelper, HfEventSelection, ctpRateFetcher, SliceCache) 3. Service<> 4. using declarations 5. Filter, Preslice, PresliceUnsorted 6. Partition 7. ConfigurableAxis 8. HistogramRegistry Changes: - taskD0.cxx: Moved all ConfigurableAxis declarations to after Partition declarations - taskDplus.cxx: Moved all ConfigurableAxis declarations to after Partition declarations This resolves the linting errors: - "ConfigurableAxis appears too early (before end of Partition<)" Reference: https://aliceo2group.github.io/analysis-framework/docs/advanced-specifics/pwghf.html#contribute 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskDplus.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 06bc2318c9c..43783f620c7 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -84,6 +84,11 @@ struct HfTaskDplus { Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + // UPC gap determination thresholds + Configurable upcFT0AThreshold{"upcFT0AThreshold", hf_upc::defaults::FT0AThreshold, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcFT0CThreshold{"upcFT0CThreshold", hf_upc::defaults::FT0CThreshold, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcZDCThreshold{"upcZDCThreshold", hf_upc::defaults::ZDCThreshold, "ZDC energy threshold for UPC gap determination (a.u.)"}; + HfEventSelection hfEvSel; // event selection and monitoring Service ccdb; @@ -128,11 +133,6 @@ struct HfTaskDplus { ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; - // UPC gap determination thresholds - Configurable upcFT0AThreshold{"upcFT0AThreshold", hf_upc::defaults::FT0AThreshold, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcFT0CThreshold{"upcFT0CThreshold", hf_upc::defaults::FT0CThreshold, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcZDCThreshold{"upcZDCThreshold", hf_upc::defaults::ZDCThreshold, "ZDC energy threshold for UPC gap determination (a.u.)"}; - HistogramRegistry registry{ "registry", {{"hPt", "3-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, From 22d9e2f2631198854a2d0ab57f81327a9ce9656d Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Mon, 10 Nov 2025 20:38:05 +0100 Subject: [PATCH 14/48] Address code review comments: rename thresholds and remove unnecessary copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes based on code review feedback from vkucera: 1. Rename threshold constants to follow "quantity + object" naming pattern: - FT0AThreshold → AmplitudeThresholdFT0A - FT0CThreshold → AmplitudeThresholdFT0C - ZDCThreshold → EnergyThresholdZDC Updated function parameters and all usages in utilsUpcHf.h. 2. Remove unnecessary centrality copy in UPC process function: - Removed `float cent{centrality};` declaration - Use `centrality` variable directly throughout the function This eliminates redundant variable and improves code clarity. 3. Use literal values for Configurable defaults: - Configurables require literal values, not constexpr references - Changed from using defaults namespace to 100.0f, 50.0f, 1.0f 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskDplus.cxx | 6 +++--- PWGHF/Utils/utilsUpcHf.h | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 43783f620c7..9e8bb86156d 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -85,9 +85,9 @@ struct HfTaskDplus { Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; // UPC gap determination thresholds - Configurable upcFT0AThreshold{"upcFT0AThreshold", hf_upc::defaults::FT0AThreshold, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcFT0CThreshold{"upcFT0CThreshold", hf_upc::defaults::FT0CThreshold, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcZDCThreshold{"upcZDCThreshold", hf_upc::defaults::ZDCThreshold, "ZDC energy threshold for UPC gap determination (a.u.)"}; + Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcFT0CThreshold{"upcFT0CThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; HfEventSelection hfEvSel; // event selection and monitoring diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h index 4080464b971..a3add09a983 100644 --- a/PWGHF/Utils/utilsUpcHf.h +++ b/PWGHF/Utils/utilsUpcHf.h @@ -32,9 +32,9 @@ enum class GapType : uint8_t { /// \brief Default thresholds for gap determination namespace defaults { -constexpr float FT0AThreshold = 100.0f; ///< FT0-A amplitude threshold (a.u.) -constexpr float FT0CThreshold = 50.0f; ///< FT0-C amplitude threshold (a.u.) -constexpr float ZDCThreshold = 1.0f; ///< ZDC energy threshold (a.u.) +constexpr float AmplitudeThresholdFT0A = 100.0f; ///< Amplitude threshold for FT0-A (a.u.) +constexpr float AmplitudeThresholdFT0C = 50.0f; ///< Amplitude threshold for FT0-C (a.u.) +constexpr float EnergyThresholdZDC = 1.0f; ///< Energy threshold for ZDC (a.u.) } // namespace defaults /// \brief Determine gap type based on FIT and ZDC signals @@ -42,24 +42,24 @@ constexpr float ZDCThreshold = 1.0f; ///< ZDC energy threshold (a.u.) /// \param ft0C FT0-C amplitude /// \param zdcA ZDC-A (ZNA) common energy /// \param zdcC ZDC-C (ZNC) common energy -/// \param ft0AThreshold Threshold for FT0-A (default: 100.0) -/// \param ft0CThreshold Threshold for FT0-C (default: 50.0) -/// \param zdcThreshold Threshold for ZDC (default: 1.0) +/// \param amplitudeThresholdFT0A Threshold for FT0-A (default: 100.0) +/// \param amplitudeThresholdFT0C Threshold for FT0-C (default: 50.0) +/// \param energyThresholdZDC Threshold for ZDC (default: 1.0) /// \return Gap type classification inline GapType determineGapType(float ft0A, float ft0C, float zdcA, float zdcC, - float ft0AThreshold = defaults::FT0AThreshold, - float ft0CThreshold = defaults::FT0CThreshold, - float zdcThreshold = defaults::ZDCThreshold) + float amplitudeThresholdFT0A = defaults::AmplitudeThresholdFT0A, + float amplitudeThresholdFT0C = defaults::AmplitudeThresholdFT0C, + float energyThresholdZDC = defaults::EnergyThresholdZDC) { // Gap on A-side: FT0-A empty, FT0-C active, ZNA empty, ZNC active - if (ft0A < ft0AThreshold && ft0C > ft0CThreshold && - zdcA < zdcThreshold && zdcC > zdcThreshold) { + if (ft0A < amplitudeThresholdFT0A && ft0C > amplitudeThresholdFT0C && + zdcA < energyThresholdZDC && zdcC > energyThresholdZDC) { return GapType::GapA; } // Gap on C-side: FT0-A active, FT0-C empty, ZNA active, ZNC empty - if (ft0A > ft0AThreshold && ft0C < ft0CThreshold && - zdcA > zdcThreshold && zdcC < zdcThreshold) { + if (ft0A > amplitudeThresholdFT0A && ft0C < amplitudeThresholdFT0C && + zdcA > energyThresholdZDC && zdcC < energyThresholdZDC) { return GapType::GapC; } From d0626ee1caff01a1024c2579fdeeba6128d5ec6e Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Mon, 10 Nov 2025 20:54:08 +0100 Subject: [PATCH 15/48] Add Filter for D0 hfflag check similar to taskDplus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following the pattern used in taskDplus, add a Filter to automatically filter D0 candidates by decay type flag at the framework level. Changes: 1. Add Filter filterD0Flag to check hfflag for D0ToPiK decay type 2. Wrap all D0 candidate types with soa::Filtered<> to apply the filter 3. Remove manual hfflag check in UPC process loop (now redundant) This ensures the hfflag filtering is applied consistently across all process functions and removes the need for manual checks in loops. The Filter is placed after using declarations and before Preslice declarations, following PWGHF struct member ordering guidelines. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/CMakeLists.txt | 4 ++-- PWGHF/D2H/Tasks/taskD0.cxx | 21 ++++++++++----------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/PWGHF/D2H/Tasks/CMakeLists.txt b/PWGHF/D2H/Tasks/CMakeLists.txt index 6e6ab7bf096..76caf26673f 100644 --- a/PWGHF/D2H/Tasks/CMakeLists.txt +++ b/PWGHF/D2H/Tasks/CMakeLists.txt @@ -71,7 +71,7 @@ o2physics_add_dpl_workflow(task-charm-reso-to-d-trk-reduced o2physics_add_dpl_workflow(task-d0 SOURCES taskD0.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons @@ -81,7 +81,7 @@ o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons o2physics_add_dpl_workflow(task-dplus SOURCES taskDplus.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::SGCutParHolder O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-ds diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index ce0ccbb2480..408b5f94938 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -105,15 +105,15 @@ struct HfTaskD0 { SliceCache cache; Service ccdb; - using D0Candidates = soa::Join; - using D0CandidatesMc = soa::Join; - using D0CandidatesKF = soa::Join; - using D0CandidatesMcKF = soa::Join; + using D0Candidates = soa::Filtered>; + using D0CandidatesMc = soa::Filtered>; + using D0CandidatesKF = soa::Filtered>; + using D0CandidatesMcKF = soa::Filtered>; - using D0CandidatesMl = soa::Join; - using D0CandidatesMlMc = soa::Join; - using D0CandidatesMlKF = soa::Join; - using D0CandidatesMlMcKF = soa::Join; + using D0CandidatesMl = soa::Filtered>; + using D0CandidatesMlMc = soa::Filtered>; + using D0CandidatesMlKF = soa::Filtered>; + using D0CandidatesMlMcKF = soa::Filtered>; using Collisions = soa::Join; using CollisionsCent = soa::Join; @@ -121,6 +121,8 @@ struct HfTaskD0 { using CollisionsWithMcLabelsCent = soa::Join; using TracksSelQuality = soa::Join; + Filter filterD0Flag = (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK))) != static_cast(0); + Preslice candD0PerCollision = aod::hf_cand::collisionId; PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; PresliceUnsorted colPerMcCollisionCent = aod::mccollisionlabel::mcCollisionId; @@ -625,9 +627,6 @@ struct HfTaskD0 { float occ{-1.f}; for (const auto& candidate : groupedD0Candidates) { - if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(HfHelper::yD0(candidate)) > yCandRecoMax) { continue; } From 7d077483776c4e665f0bc91531a534d4902252fe Mon Sep 17 00:00:00 2001 From: minjungkim12 <21147605+minjungkim12@users.noreply.github.com> Date: Wed, 12 Nov 2025 16:51:47 +0100 Subject: [PATCH 16/48] Remove unused configurable parameters Removed configurable parameters for ccdbPathGrp and ccdbPathGrpMag. --- PWGHF/D2H/Tasks/taskD0.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 408b5f94938..2b2e5a8ff48 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -94,8 +94,6 @@ struct HfTaskD0 { // ML inference Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; - Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; HfEventSelection hfEvSel; // event selection and monitoring From f73e925f1710da6ede0132a94b1153ffe1abda36 Mon Sep 17 00:00:00 2001 From: minjungkim12 <21147605+minjungkim12@users.noreply.github.com> Date: Wed, 12 Nov 2025 16:52:51 +0100 Subject: [PATCH 17/48] Remove unused ccdbPathGrp and ccdbPathGrpMag parameters Removed configurable parameters for ccdbPathGrp and ccdbPathGrpMag. --- PWGHF/D2H/Tasks/taskDplus.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 9e8bb86156d..40effd948ce 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -81,8 +81,6 @@ struct HfTaskDplus { Configurable storePvContributors{"storePvContributors", false, "Flag to store number of PV contributors information"}; Configurable fillMcBkgHistos{"fillMcBkgHistos", false, "Flag to fill and store histograms for MC background"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; - Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; // UPC gap determination thresholds Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; From 6d12fc59a0315c337afb45b8692904a777350e42 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Wed, 12 Nov 2025 22:28:04 +0100 Subject: [PATCH 18/48] Code quality improvements addressing all review comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit addresses all code review feedback from @vkucera in PR #13603. Changes are relative to commit f3ce844 and incorporate optimizations from commit 3fea4f12d with custom GapType modifications. **1. Template Parameter Naming Convention** - Renamed `fillMl` → `FillMl` (CapitalCase) throughout: * taskD0.cxx: template declarations and all usage sites * taskDplus.cxx: template declarations and all usage sites - Follows O2Physics coding standards for template parameters **2. Const Correctness (taskD0.cxx)** - Added `const` to mass variable declarations: ```cpp const float massD0 = HfHelper::invMassD0ToPiK(candidate); const float massD0bar = HfHelper::invMassD0barToKPi(candidate); ``` - Improves code safety by marking immutable values **3. Lambda Function Optimization (taskD0.cxx, taskDplus.cxx)** - Merged multiple lambda functions into unified `fillTHnData` lambda - Reduces code duplication and improves maintainability - Handles both ML and non-ML cases in single function **4. Memory Allocation Optimization** - Pre-calculate vector size to avoid reallocations: ```cpp valuesToFill.reserve(nAxesTotal); ``` - Improves performance by preventing dynamic resizing **5. THnSparse Structure Documentation** - Added comprehensive comment documenting axis structure: ``` [mass, pt, (mlScores if FillMl), rapidity, d0Type, (cent if storeCentrality), (occ, ir if storeOccupancyAndIR), gapType, FT0A, FT0C] ``` - Makes histogram structure explicit and verifiable **6. Code Cleanup (utilsUpcHf.h)** - Removed unused `HfUpcQaHistoConfig` struct (19 lines) - Eliminates dead code from utility header **Modified Files:** - PWGHF/D2H/Tasks/taskD0.cxx: All above improvements - PWGHF/D2H/Tasks/taskDplus.cxx: Template naming + lambda optimization - PWGHF/Utils/utilsUpcHf.h: Remove unused struct Total changes: +137 insertions, -121 deletions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskD0.cxx | 168 +++++++++++++++------------------- PWGHF/D2H/Tasks/taskDplus.cxx | 104 +++++++++++++-------- PWGHF/Utils/utilsUpcHf.h | 18 ---- 3 files changed, 140 insertions(+), 150 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 2b2e5a8ff48..6afc300ca51 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -96,6 +96,11 @@ struct HfTaskD0 { Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + // UPC gap determination thresholds + Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcFT0CThreshold{"upcFT0CThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; + HfEventSelection hfEvSel; // event selection and monitoring ctpRateFetcher mRateFetcher; @@ -157,35 +162,6 @@ struct HfTaskD0 { ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; - // UPC gap determination thresholds - Configurable upcFT0AThreshold{"upcFT0AThreshold", hf_upc::defaults::FT0AThreshold, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcFT0CThreshold{"upcFT0CThreshold", hf_upc::defaults::FT0CThreshold, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcZDCThreshold{"upcZDCThreshold", hf_upc::defaults::ZDCThreshold, "ZDC energy threshold for UPC gap determination (a.u.)"}; - - HfEventSelection hfEvSel; // event selection and monitoring - - HfHelper hfHelper; - ctpRateFetcher mRateFetcher; - - SliceCache cache; - Service ccdb; - - using D0Candidates = soa::Join; - using D0CandidatesMc = soa::Join; - using D0CandidatesKF = soa::Join; - using D0CandidatesMcKF = soa::Join; - - using D0CandidatesMl = soa::Join; - using D0CandidatesMlMc = soa::Join; - using D0CandidatesMlKF = soa::Join; - using D0CandidatesMlMcKF = soa::Join; - - using Collisions = soa::Join; - using CollisionsCent = soa::Join; - using CollisionsWithMcLabels = soa::Join; - using CollisionsWithMcLabelsCent = soa::Join; - using TracksSelQuality = soa::Join; - HistogramRegistry registry{ "registry", {{"hPtCand", "2-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, @@ -262,8 +238,6 @@ struct HfTaskD0 { {"hMassReflBkgD0bar", "2-prong candidates (matched);#it{m}_{inv} (GeV/#it{c}^{2}); #it{p}_{T}; #it{y}", {HistType::kTH3F, {{120, 1.5848, 2.1848}, {150, 0., 30.}, {20, -5., 5.}}}}, {"hMassSigBkgD0bar", "2-prong candidates (not checked);#it{m}_{inv} (GeV/#it{c}^{2}); #it{p}_{T}; #it{y}", {HistType::kTH3F, {{120, 1.5848, 2.1848}, {150, 0., 30.}, {20, -5., 5.}}}}}}; - HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; - void init(InitContext&) { std::array doprocess{doprocessDataWithDCAFitterN, doprocessDataWithDCAFitterNCent, doprocessDataWithKFParticle, doprocessMcWithDCAFitterN, doprocessMcWithDCAFitterNCent, doprocessMcWithKFParticle, doprocessDataWithDCAFitterNMl, doprocessDataWithDCAFitterNMlCent, doprocessDataWithKFParticleMl, doprocessMcWithDCAFitterNMl, doprocessMcWithDCAFitterNMlCent, doprocessMcWithKFParticleMl, doprocessDataWithDCAFitterNMlWithUpc}; @@ -395,14 +369,14 @@ struct HfTaskD0 { registry.get(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"))->Sumw2(); } - qaRegistry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); - qaRegistry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); - qaRegistry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}); - qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapA) + 1, "A"); - qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapC) + 1, "C"); - qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::DoubleGap) + 1, "Double"); + registry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); + registry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); + registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}); + registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapA) + 1, "A"); + registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapC) + 1, "C"); + registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::DoubleGap) + 1, "Double"); - hfEvSel.addHistograms(qaRegistry); + hfEvSel.addHistograms(registry); ccdb->setURL(ccdbUrl); ccdb->setCaching(true); @@ -589,7 +563,7 @@ struct HfTaskD0 { } } - template + template void runAnalysisPerCollisionDataWithUpc(CollType const& collisions, CandType const& candidates, BCsType const& bcs, @@ -598,40 +572,45 @@ struct HfTaskD0 { aod::FDDs const& fdds) { for (const auto& collision : collisions) { - uint32_t rejectionMask{0}; float centrality{-1.f}; - rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, qaRegistry, bcs); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, registry, bcs); if (rejectionMask != 0) { continue; } - auto bc = collision.template bc_as(); + const auto& bc = collision.template bc_as(); upchelpers::FITInfo fitInfo{}; udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); GapType gap = GapType::DoubleGap; if (bc.has_zdc()) { - auto zdc = bc.zdc(); - qaRegistry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); - qaRegistry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); + const auto& zdc = bc.zdc(); + registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); + registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC(), upcFT0AThreshold, upcFT0CThreshold, upcZDCThreshold); - qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); + registry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } if (hf_upc::isSingleSidedGap(gap)) { int const gapTypeInt = hf_upc::gapTypeToInt(gap); const auto thisCollId = collision.globalIndex(); const auto& groupedD0Candidates = candidates.sliceBy(candD0PerCollision, thisCollId); - float cent{centrality}; + + // Calculate occupancy and interaction rate if needed float occ{-1.f}; + float ir{-1.f}; + if (storeOccupancyAndIR && occEstimator != OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource, true) * 1.e-3; // kHz + } for (const auto& candidate : groupedD0Candidates) { if (yCandRecoMax >= 0. && std::abs(HfHelper::yD0(candidate)) > yCandRecoMax) { continue; } - float massD0 = HfHelper::invMassD0ToPiK(candidate); - float massD0bar = HfHelper::invMassD0barToKPi(candidate); - auto ptCandidate = candidate.pt(); + const float massD0 = HfHelper::invMassD0ToPiK(candidate); + const float massD0bar = HfHelper::invMassD0barToKPi(candidate); + const auto ptCandidate = candidate.pt(); if (candidate.isSelD0() >= selectionFlagD0) { registry.fill(HIST("hMass"), massD0, ptCandidate); @@ -644,56 +623,53 @@ struct HfTaskD0 { registry.fill(HIST("hMassVsPhi"), massD0bar, ptCandidate, candidate.phi()); } - // Fill THnSparse with structure matching taskDplus: [mass, pt, mlScores, cent, occ, gapType, FT0A, FT0C] - if constexpr (fillMl) { - auto fillTHnData = [&](float mass, int d0Type) { - std::vector valuesToFill{static_cast(mass), static_cast(ptCandidate), - candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], - static_cast(HfHelper::yD0(candidate)), static_cast(d0Type)}; - if (storeCentrality) { - valuesToFill.push_back(cent); - } - if (storeOccupancyAndIR) { - valuesToFill.push_back(occ); - } - valuesToFill.push_back(static_cast(gapTypeInt)); - valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); - valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); - registry.get(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); - }; - - if (candidate.isSelD0() >= selectionFlagD0) { - fillTHnData(massD0, SigD0); - fillTHnData(massD0, candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); + // Fill THnSparse with structure matching histogram axes: [mass, pt, (mlScores if FillMl), rapidity, d0Type, (cent if storeCentrality), (occ, ir if storeOccupancyAndIR), gapType, FT0A, FT0C] + auto fillTHnData = [&](float mass, int d0Type) { + // Pre-calculate vector size to avoid reallocations + constexpr int nAxesBase = 7; // mass, pt, rapidity, d0Type, gapType, FT0A, FT0C + constexpr int nAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl + int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality + int const nAxesOccIR = storeOccupancyAndIR ? 2 : 0; // occupancy and IR if storeOccupancyAndIR + int const nAxesTotal = nAxesBase + nAxesMl + nAxesCent + nAxesOccIR; + + std::vector valuesToFill; + valuesToFill.reserve(nAxesTotal); + + // Fill values in order matching histogram axes + valuesToFill.push_back(static_cast(mass)); + valuesToFill.push_back(static_cast(ptCandidate)); + if constexpr (FillMl) { + valuesToFill.push_back(candidate.mlProbD0()[0]); + valuesToFill.push_back(candidate.mlProbD0()[1]); + valuesToFill.push_back(candidate.mlProbD0()[2]); } - if (candidate.isSelD0bar() >= selectionFlagD0bar) { - fillTHnData(massD0bar, SigD0bar); - fillTHnData(massD0bar, candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); + valuesToFill.push_back(static_cast(HfHelper::yD0(candidate))); + valuesToFill.push_back(static_cast(d0Type)); + if (storeCentrality) { + valuesToFill.push_back(centrality); } - } else { - auto fillTHnData = [&](float mass, int d0Type) { - std::vector valuesToFill{static_cast(mass), static_cast(ptCandidate), - static_cast(HfHelper::yD0(candidate)), static_cast(d0Type)}; - if (storeCentrality) { - valuesToFill.push_back(cent); - } - if (storeOccupancyAndIR) { - valuesToFill.push_back(occ); - } - valuesToFill.push_back(static_cast(gapTypeInt)); - valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); - valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); - registry.get(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); - }; - - if (candidate.isSelD0() >= selectionFlagD0) { - fillTHnData(massD0, SigD0); - fillTHnData(massD0, candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); + if (storeOccupancyAndIR) { + valuesToFill.push_back(occ); + valuesToFill.push_back(ir); } - if (candidate.isSelD0bar() >= selectionFlagD0bar) { - fillTHnData(massD0bar, SigD0bar); - fillTHnData(massD0bar, candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); + valuesToFill.push_back(static_cast(gapTypeInt)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); + + if constexpr (FillMl) { + registry.get(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); + } else { + registry.get(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); } + }; + + if (candidate.isSelD0() >= selectionFlagD0) { + fillTHnData(massD0, SigD0); + fillTHnData(massD0, candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + fillTHnData(massD0bar, SigD0bar); + fillTHnData(massD0bar, candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); } } } diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 40effd948ce..13b389182c0 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -30,6 +30,7 @@ #include "PWGHF/Utils/utilsUpcHf.h" #include "PWGUD/Core/UPCHelpers.h" +#include "Common/CCDB/ctpRateFetcher.h" #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" @@ -78,16 +79,19 @@ struct HfTaskDplus { Configurable> classMl{"classMl", {0, 1, 2}, "Indexes of ML scores to be stored. Three indexes max."}; Configurable storeCentrality{"storeCentrality", false, "Flag to store centrality information"}; Configurable storeOccupancy{"storeOccupancy", false, "Flag to store occupancy information"}; + Configurable storeIR{"storeIR", false, "Flag to store interaction rate information"}; Configurable storePvContributors{"storePvContributors", false, "Flag to store number of PV contributors information"}; Configurable fillMcBkgHistos{"fillMcBkgHistos", false, "Flag to fill and store histograms for MC background"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; // UPC gap determination thresholds Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcFT0CThreshold{"upcFT0CThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; - HfEventSelection hfEvSel; // event selection and monitoring + HfEventSelection hfEvSel; // event selection and monitoring + ctpRateFetcher mRateFetcher; // interaction rate fetcher Service ccdb; @@ -121,6 +125,7 @@ struct HfTaskDplus { ConfigurableAxis thnConfigAxisY{"thnConfigAxisY", {40, -1, 1}, "Cand. rapidity bins"}; ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {110, 0., 110.}, "axis for centrality"}; ConfigurableAxis thnConfigAxisOccupancy{"thnConfigAxisOccupancy", {14, 0, 14000}, "axis for occupancy"}; + ConfigurableAxis thnConfigAxisIR{"thnConfigAxisIR", {5000, 0, 500}, "Interaction rate (kHz)"}; ConfigurableAxis thnConfigAxisPvContributors{"thnConfigAxisPvContributors", {100, 0., 100.}, "axis for PV contributors"}; ConfigurableAxis thnConfigAxisPtBHad{"thnConfigAxisPtBHad", {25, 0., 50}, "axis for pt of B hadron decayed into D candidate"}; ConfigurableAxis thnConfigAxisFlagBHad{"thnConfigAxisFlagBHad", {5, 0., 5}, "axis for PDG of B hadron"}; @@ -143,8 +148,6 @@ struct HfTaskDplus { {"hEtaRecBg", "3-prong candidates (unmatched);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, {"hEtaGen", "MC particles (matched);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}}}; - HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; - void init(InitContext&) { std::array doprocess{doprocessData, doprocessDataWithMl, doprocessMc, doprocessMcWithMl, doprocessDataWithMlWithUpc}; @@ -162,6 +165,7 @@ struct HfTaskDplus { AxisSpec const thnAxisFlagBHad{thnConfigAxisFlagBHad, "B Hadron flag"}; AxisSpec const thnAxisCent{thnConfigAxisCent, "Centrality"}; AxisSpec const thnAxisOccupancy{thnConfigAxisOccupancy, "Occupancy"}; + AxisSpec const thnAxisIR{thnConfigAxisIR, "Interaction rate (kHz)"}; AxisSpec const thnAxisPvContributors{thnConfigAxisPvContributors, "PV contributors"}; AxisSpec const thnAxisGapType{thnConfigAxisGapType, "Gap type"}; AxisSpec const thnAxisFT0A{thnConfigAxisFT0A, "FT0-A amplitude"}; @@ -219,6 +223,9 @@ struct HfTaskDplus { if (storeOccupancy) { axes.push_back(thnAxisOccupancy); } + if (storeIR) { + axes.push_back(thnAxisIR); + } if (doprocessDataWithMlWithUpc) { axes.push_back(thnAxisGapType); axes.push_back(thnAxisFT0A); @@ -271,14 +278,14 @@ struct HfTaskDplus { registry.add("hSparseMassGenFD", "THn for gen FD Dplus", HistType::kTHnSparseF, axesGenFD); } - qaRegistry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); - qaRegistry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); - qaRegistry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}); - qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapA) + 1, "A"); - qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapC) + 1, "C"); - qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::DoubleGap) + 1, "Double"); + registry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); + registry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); + registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}); + registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapA) + 1, "A"); + registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapC) + 1, "C"); + registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::DoubleGap) + 1, "Double"); - hfEvSel.addHistograms(qaRegistry); // collision monitoring + hfEvSel.addHistograms(registry); // collision monitoring ccdb->setURL(ccdbUrl); ccdb->setCaching(true); @@ -690,7 +697,7 @@ struct HfTaskDplus { } } - template + template void runAnalysisPerCollisionDataWithUpc(CollType const& collisions, CandType const& candidates, BCsType const& bcs, @@ -699,25 +706,24 @@ struct HfTaskDplus { aod::FDDs const& fdds) { for (const auto& collision : collisions) { - uint32_t rejectionMask{0}; // 32 bits, in case new ev. selections will be added float centrality{-1.f}; - rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, qaRegistry, bcs); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, registry, bcs); if (rejectionMask != 0) { /// at least one event selection not satisfied --> reject the candidate continue; } - auto bc = collision.template bc_as(); + const auto& bc = collision.template bc_as(); upchelpers::FITInfo fitInfo{}; udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); GapType gap = GapType::DoubleGap; if (bc.has_zdc()) { - auto zdc = bc.zdc(); - qaRegistry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); - qaRegistry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); + const auto& zdc = bc.zdc(); + registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); + registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC(), upcFT0AThreshold, upcFT0CThreshold, upcZDCThreshold); - qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); + registry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } if (hf_upc::isSingleSidedGap(gap)) { // Use the candidates from this collision @@ -725,36 +731,62 @@ struct HfTaskDplus { const auto& groupedDplusCandidates = candidates.sliceBy(candDplusPerCollision, thisCollId); float cent{-1.f}; float occ{-1.f}; + float ir{-1.f}; if (storeOccupancy && occEstimator != OccupancyEstimator::None) { occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); } + if (storeIR) { + ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource, true) * 1.e-3; // kHz + } float numPvContr{-1.f}; int const gapTypeInt = hf_upc::gapTypeToInt(gap); - for (const auto& candidate : groupedDplusCandidates) { - if ((yCandRecoMax >= 0. && std::abs(HfHelper::yDplus(candidate)) > yCandRecoMax)) { - continue; - } - fillHisto(candidate); - if constexpr (fillMl) { - // Fill THn with gap type and FIT signals + // Lambda function to fill THn - handles both ML and non-ML cases + auto fillTHnData = [&](const auto& candidate) { + // Pre-calculate vector size to avoid reallocations + constexpr int nAxesBase = 5; // mass, pt, gapType, FT0A, FT0C + constexpr int nAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl + int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality + int const nAxesOcc = storeOccupancy ? 1 : 0; // occupancy if storeOccupancy + int const nAxesIR = storeIR ? 1 : 0; // IR if storeIR + int const nAxesTotal = nAxesBase + nAxesMl + nAxesCent + nAxesOcc + nAxesIR; + + std::vector valuesToFill; + valuesToFill.reserve(nAxesTotal); + + // Fill values in order matching histogram axes + valuesToFill.push_back(HfHelper::invMassDplusToPiKPi(candidate)); + valuesToFill.push_back(static_cast(candidate.pt())); + if constexpr (FillMl) { std::vector outputMl = {-999., -999., -999.}; for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMl->at(iclass)]; } + valuesToFill.push_back(outputMl[0]); + valuesToFill.push_back(outputMl[1]); + valuesToFill.push_back(outputMl[2]); + } + if (storeCentrality) { + valuesToFill.push_back(cent); + } + if (storeOccupancy) { + valuesToFill.push_back(occ); + } + if (storeIR) { + valuesToFill.push_back(ir); + } + valuesToFill.push_back(static_cast(gapTypeInt)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); + registry.get(HIST("hSparseMass"))->Fill(valuesToFill.data()); + }; - std::vector valuesToFill{HfHelper::invMassDplusToPiKPi(candidate), static_cast(candidate.pt()), outputMl[0], outputMl[1], outputMl[2]}; - if (storeCentrality) { - valuesToFill.push_back(cent); - } - if (storeOccupancy) { - valuesToFill.push_back(occ); - } - valuesToFill.push_back(static_cast(gapTypeInt)); - valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); - valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); - registry.get(HIST("hSparseMass"))->Fill(valuesToFill.data()); + for (const auto& candidate : groupedDplusCandidates) { + if ((yCandRecoMax >= 0. && std::abs(HfHelper::yDplus(candidate)) > yCandRecoMax)) { + continue; } + fillHisto(candidate); + fillTHnData(candidate); } } } diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h index a3add09a983..2fcf4edacf6 100644 --- a/PWGHF/Utils/utilsUpcHf.h +++ b/PWGHF/Utils/utilsUpcHf.h @@ -100,24 +100,6 @@ inline int gapTypeToInt(GapType gap) return static_cast(gap); } -/// \brief Struct to hold UPC QA histogram configuration -struct HfUpcQaHistoConfig { - // FT0 histogram configuration - int ft0Nbins = 1500; - float ft0Min = 0.f; - float ft0Max = 1500.f; - - // ZDC histogram configuration - int zdcNbins = 200; - float zdcMin = 0.f; - float zdcMax = 20.f; - - // Gap type histogram configuration - int gapNbins = 3; - float gapMin = -0.5f; - float gapMax = 2.5f; -}; - } // namespace o2::analysis::hf_upc #endif // PWGHF_UTILS_UTILSUPCHF_H_ From aca23b5d868bfda158f7905f3a1c6689992df0c0 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Thu, 13 Nov 2025 00:04:33 +0100 Subject: [PATCH 19/48] Migrate UPC gap classification to SGSelector with BC range checking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates the UPC (Ultra-Peripheral Collision) gap determination in taskD0 and taskDplus to use SGSelector from PWGUD/Core instead of custom gap classification logic. Key changes: - Migrate from custom GapType enum to SGSelector's TrueGap enum in utilsUpcHf.h - Update gap type classification to support 7 categories: NoGap (-1), SingleGapA (0), SingleGapC (1), DoubleGap (2), NoUpc (3), TrkOutOfRange (4), BadDoubleGap (5) - Add SGSelector instance to taskD0 and taskDplus for gap determination - Add FV0-A amplitude threshold configurable for more comprehensive gap classification - Remove unused energyThresholdZDC parameter as SGCutParHolder only supports FIT amplitudes - Add BC range checking via udhelpers::compatibleBCs for improved gap classification accuracy - Update histogram axes from 3 bins to 7 bins to accommodate new gap types - Add required library dependencies (SGCutParHolder, EventFilteringUtils) to CMakeLists.txt Technical details: - SGSelector uses SGCutParHolder to configure thresholds for FIT detectors (FV0A, FT0A, FT0C) - BC range checking examines multiple BCs around collision using NDtColl=1000ns and MinNBCs=7 - Gap determination now uses SGSelector::IsSelected() with proper BC range instead of simple threshold comparison - This aligns PWGHF UPC analysis with standard gap classification used in PWGUD 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/CMakeLists.txt | 4 +- PWGHF/D2H/Tasks/taskD0.cxx | 23 +++---- PWGHF/D2H/Tasks/taskDplus.cxx | 23 +++---- PWGHF/Utils/utilsUpcHf.h | 111 ++++++++++++++++++++------------- 4 files changed, 92 insertions(+), 69 deletions(-) diff --git a/PWGHF/D2H/Tasks/CMakeLists.txt b/PWGHF/D2H/Tasks/CMakeLists.txt index 76caf26673f..99bad681b88 100644 --- a/PWGHF/D2H/Tasks/CMakeLists.txt +++ b/PWGHF/D2H/Tasks/CMakeLists.txt @@ -71,7 +71,7 @@ o2physics_add_dpl_workflow(task-charm-reso-to-d-trk-reduced o2physics_add_dpl_workflow(task-d0 SOURCES taskD0.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons @@ -81,7 +81,7 @@ o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons o2physics_add_dpl_workflow(task-dplus SOURCES taskDplus.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-ds diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 6afc300ca51..09f7735f855 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -97,11 +97,13 @@ struct HfTaskD0 { Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; // UPC gap determination thresholds + Configurable upcFV0AThreshold{"upcFV0AThreshold", 100.0f, "FV0-A amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcFT0CThreshold{"upcFT0CThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; HfEventSelection hfEvSel; // event selection and monitoring + SGSelector sgSelector; // UPC gap selector ctpRateFetcher mRateFetcher; @@ -158,7 +160,7 @@ struct HfTaskD0 { ConfigurableAxis thnConfigAxisMinItsNCls{"thnConfigAxisMinItsNCls", {5, 3, 8}, "axis for minimum ITS NCls of candidate prongs"}; ConfigurableAxis thnConfigAxisMinTpcNCrossedRows{"thnConfigAxisMinTpcNCrossedRows", {10, 70, 180}, "axis for minimum TPC NCls crossed rows of candidate prongs"}; ConfigurableAxis thnConfigAxisIR{"thnConfigAxisIR", {5000, 0, 500}, "Interaction rate (kHz)"}; - ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {3, -0.5, 2.5}, "axis for UPC gap type (0=GapA, 1=GapC, 2=DoubleGap)"}; + ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap)"}; ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; @@ -371,10 +373,7 @@ struct HfTaskD0 { registry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); registry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); - registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}); - registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapA) + 1, "A"); - registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapC) + 1, "C"); - registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::DoubleGap) + 1, "Double"); + registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap type;Counts", {HistType::kTH1F, {{7, -1.5, 5.5}}}); hfEvSel.addHistograms(registry); @@ -581,15 +580,17 @@ struct HfTaskD0 { upchelpers::FITInfo fitInfo{}; udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); - GapType gap = GapType::DoubleGap; + // Determine gap type using SGSelector with BC range checking + int gap = hf_upc::determineGapType(collision, bcs, sgSelector, + upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + if (bc.has_zdc()) { const auto& zdc = bc.zdc(); registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); - gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC(), - upcFT0AThreshold, upcFT0CThreshold, upcZDCThreshold); registry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } + if (hf_upc::isSingleSidedGap(gap)) { int const gapTypeInt = hf_upc::gapTypeToInt(gap); const auto thisCollId = collision.globalIndex(); @@ -626,11 +627,11 @@ struct HfTaskD0 { // Fill THnSparse with structure matching histogram axes: [mass, pt, (mlScores if FillMl), rapidity, d0Type, (cent if storeCentrality), (occ, ir if storeOccupancyAndIR), gapType, FT0A, FT0C] auto fillTHnData = [&](float mass, int d0Type) { // Pre-calculate vector size to avoid reallocations - constexpr int nAxesBase = 7; // mass, pt, rapidity, d0Type, gapType, FT0A, FT0C - constexpr int nAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl + constexpr int NAxesBase = 7; // mass, pt, rapidity, d0Type, gapType, FT0A, FT0C + constexpr int NAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality int const nAxesOccIR = storeOccupancyAndIR ? 2 : 0; // occupancy and IR if storeOccupancyAndIR - int const nAxesTotal = nAxesBase + nAxesMl + nAxesCent + nAxesOccIR; + int const nAxesTotal = NAxesBase + NAxesMl + nAxesCent + nAxesOccIR; std::vector valuesToFill; valuesToFill.reserve(nAxesTotal); diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 13b389182c0..95e01f1050d 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -22,6 +22,7 @@ #include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.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" @@ -86,11 +87,13 @@ struct HfTaskDplus { Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; // UPC gap determination thresholds + Configurable upcFV0AThreshold{"upcFV0AThreshold", 100.0f, "FV0-A amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcFT0CThreshold{"upcFT0CThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; HfEventSelection hfEvSel; // event selection and monitoring + SGSelector sgSelector; // UPC gap selector ctpRateFetcher mRateFetcher; // interaction rate fetcher Service ccdb; @@ -132,7 +135,7 @@ struct HfTaskDplus { ConfigurableAxis thnConfigAxisMlScore0{"thnConfigAxisMlScore0", {100, 0., 1.}, "axis for ML output score 0"}; ConfigurableAxis thnConfigAxisMlScore1{"thnConfigAxisMlScore1", {100, 0., 1.}, "axis for ML output score 1"}; ConfigurableAxis thnConfigAxisMlScore2{"thnConfigAxisMlScore2", {100, 0., 1.}, "axis for ML output score 2"}; - ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {3, -0.5, 2.5}, "axis for UPC gap type (0=GapA, 1=GapC, 2=DoubleGap)"}; + ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap)"}; ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; @@ -280,10 +283,7 @@ struct HfTaskDplus { registry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); registry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); - registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}); - registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapA) + 1, "A"); - registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapC) + 1, "C"); - registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::DoubleGap) + 1, "Double"); + registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap type;Counts", {HistType::kTH1F, {{7, -1.5, 5.5}}}); hfEvSel.addHistograms(registry); // collision monitoring @@ -716,13 +716,14 @@ struct HfTaskDplus { upchelpers::FITInfo fitInfo{}; udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); - GapType gap = GapType::DoubleGap; + // Determine gap type using SGSelector with BC range checking + int gap = hf_upc::determineGapType(collision, bcs, sgSelector, + upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + if (bc.has_zdc()) { const auto& zdc = bc.zdc(); registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); - gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC(), - upcFT0AThreshold, upcFT0CThreshold, upcZDCThreshold); registry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } if (hf_upc::isSingleSidedGap(gap)) { @@ -744,12 +745,12 @@ struct HfTaskDplus { // Lambda function to fill THn - handles both ML and non-ML cases auto fillTHnData = [&](const auto& candidate) { // Pre-calculate vector size to avoid reallocations - constexpr int nAxesBase = 5; // mass, pt, gapType, FT0A, FT0C - constexpr int nAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl + constexpr int NAxesBase = 5; // mass, pt, gapType, FT0A, FT0C + constexpr int NAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality int const nAxesOcc = storeOccupancy ? 1 : 0; // occupancy if storeOccupancy int const nAxesIR = storeIR ? 1 : 0; // IR if storeIR - int const nAxesTotal = nAxesBase + nAxesMl + nAxesCent + nAxesOcc + nAxesIR; + int const nAxesTotal = NAxesBase + NAxesMl + nAxesCent + nAxesOcc + nAxesIR; std::vector valuesToFill; valuesToFill.reserve(nAxesTotal); diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h index 2fcf4edacf6..82dddde729a 100644 --- a/PWGHF/Utils/utilsUpcHf.h +++ b/PWGHF/Utils/utilsUpcHf.h @@ -17,87 +17,108 @@ #ifndef PWGHF_UTILS_UTILSUPCHF_H_ #define PWGHF_UTILS_UTILSUPCHF_H_ -#include +#include "PWGUD/Core/SGCutParHolder.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UDHelpers.h" namespace o2::analysis::hf_upc { -/// \brief Gap type classification for UPC events -enum class GapType : uint8_t { - GapA = 0, ///< Gap on A-side (C-side active) - GapC = 1, ///< Gap on C-side (A-side active) - DoubleGap = 2 ///< Double gap (both sides empty) -}; +/// \brief Use TrueGap enum from SGSelector for gap type classification +using o2::aod::sgselector::TrueGap; /// \brief Default thresholds for gap determination namespace defaults { +constexpr float AmplitudeThresholdFV0A = 100.0f; ///< Amplitude threshold for FV0-A (a.u.) constexpr float AmplitudeThresholdFT0A = 100.0f; ///< Amplitude threshold for FT0-A (a.u.) constexpr float AmplitudeThresholdFT0C = 50.0f; ///< Amplitude threshold for FT0-C (a.u.) -constexpr float EnergyThresholdZDC = 1.0f; ///< Energy threshold for ZDC (a.u.) +constexpr float MaxFITTime = 4.0f; ///< Maximum FIT time (ns) +constexpr int NDtColl = 1000; ///< Time window for BC range (ns) +constexpr int MinNBCs = 7; ///< Minimum number of BCs to check +constexpr int MinNTracks = 0; ///< Minimum number of tracks +constexpr int MaxNTracks = 100; ///< Maximum number of tracks } // namespace defaults -/// \brief Determine gap type based on FIT and ZDC signals -/// \param ft0A FT0-A amplitude -/// \param ft0C FT0-C amplitude -/// \param zdcA ZDC-A (ZNA) common energy -/// \param zdcC ZDC-C (ZNC) common energy +/// \brief Determine gap type using SGSelector with BC range checking +/// \tparam TCollision Collision type +/// \tparam TBCs BC table type +/// \param collision Collision object +/// \param bcs BC table +/// \param sgSelector SGSelector instance +/// \param amplitudeThresholdFV0A Threshold for FV0-A (default: 100.0) /// \param amplitudeThresholdFT0A Threshold for FT0-A (default: 100.0) /// \param amplitudeThresholdFT0C Threshold for FT0-C (default: 50.0) -/// \param energyThresholdZDC Threshold for ZDC (default: 1.0) -/// \return Gap type classification -inline GapType determineGapType(float ft0A, float ft0C, float zdcA, float zdcC, - float amplitudeThresholdFT0A = defaults::AmplitudeThresholdFT0A, - float amplitudeThresholdFT0C = defaults::AmplitudeThresholdFT0C, - float energyThresholdZDC = defaults::EnergyThresholdZDC) +/// \return TrueGap enum value (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap) +template +inline int determineGapType(TCollision const& collision, + TBCs const& bcs, + SGSelector& sgSelector, + float amplitudeThresholdFV0A = defaults::AmplitudeThresholdFV0A, + float amplitudeThresholdFT0A = defaults::AmplitudeThresholdFT0A, + float amplitudeThresholdFT0C = defaults::AmplitudeThresholdFT0C) { - // Gap on A-side: FT0-A empty, FT0-C active, ZNA empty, ZNC active - if (ft0A < amplitudeThresholdFT0A && ft0C > amplitudeThresholdFT0C && - zdcA < energyThresholdZDC && zdcC > energyThresholdZDC) { - return GapType::GapA; - } + // Configure SGSelector thresholds + SGCutParHolder sgCuts; + sgCuts.SetNDtcoll(defaults::NDtColl); + sgCuts.SetMinNBCs(defaults::MinNBCs); + sgCuts.SetNTracks(defaults::MinNTracks, defaults::MaxNTracks); + sgCuts.SetMaxFITtime(defaults::MaxFITTime); + sgCuts.SetFITAmpLimits({amplitudeThresholdFV0A, amplitudeThresholdFT0A, amplitudeThresholdFT0C}); - // Gap on C-side: FT0-A active, FT0-C empty, ZNA active, ZNC empty - if (ft0A > amplitudeThresholdFT0A && ft0C < amplitudeThresholdFT0C && - zdcA > energyThresholdZDC && zdcC < energyThresholdZDC) { - return GapType::GapC; + // Get BC and BC range + if (!collision.has_foundBC()) { + return TrueGap::NoGap; } - // Default: Double gap (or no clear gap) - return GapType::DoubleGap; + const auto bc = collision.template foundBC_as(); + const auto bcRange = udhelpers::compatibleBCs(collision, sgCuts.NDtcoll(), bcs, sgCuts.minNBCs()); + + // Use SGSelector to determine gap type with BC range checking + const auto sgResult = sgSelector.IsSelected(sgCuts, collision, bcRange, bc); + + return sgResult.value; } -/// \brief Check if the gap type is a single-sided gap (GapA or GapC) -/// \param gap Gap type +/// \brief Check if the gap type is a single-sided gap (SingleGapA or SingleGapC) +/// \param gap TrueGap enum value /// \return true if single-sided gap, false otherwise -inline bool isSingleSidedGap(GapType gap) +inline bool isSingleSidedGap(int gap) { - return (gap == GapType::GapA || gap == GapType::GapC); + return (gap == TrueGap::SingleGapA || gap == TrueGap::SingleGapC); } /// \brief Get gap type name as string -/// \param gap Gap type +/// \param gap TrueGap enum value /// \return String representation of gap type -inline const char* getGapTypeName(GapType gap) +inline const char* getGapTypeName(int gap) { switch (gap) { - case GapType::GapA: - return "GapA"; - case GapType::GapC: - return "GapC"; - case GapType::DoubleGap: + case TrueGap::NoGap: + return "NoGap"; + case TrueGap::SingleGapA: + return "SingleGapA"; + case TrueGap::SingleGapC: + return "SingleGapC"; + case TrueGap::DoubleGap: return "DoubleGap"; + case TrueGap::NoUpc: + return "NoUpc"; + case TrueGap::TrkOutOfRange: + return "TrkOutOfRange"; + case TrueGap::BadDoubleGap: + return "BadDoubleGap"; default: return "Unknown"; } } /// \brief Convert gap type to integer for histogram filling -/// \param gap Gap type -/// \return Integer representation (0=GapA, 1=GapC, 2=DoubleGap) -inline int gapTypeToInt(GapType gap) +/// \param gap TrueGap enum value +/// \return Integer representation (-1, 0, 1, 2, 3, 4, 5) +inline int gapTypeToInt(int gap) { - return static_cast(gap); + return gap; } } // namespace o2::analysis::hf_upc From 15c799b5bb68e57ca69ecfce2e1ac533c13bb6fc Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Thu, 13 Nov 2025 21:04:41 +0100 Subject: [PATCH 20/48] Add UPC detector amplitudes and optimize taskD0/taskDplus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add FV0A, FDDA, FDDC, ZNA, ZNC axes to THnSparse histograms - Optimize detector binning: unified FT0/FDD/ZN for A/C sides - Optimize utilsUpcHf.h: add constexpr/noexcept to utility functions - Optimize ZDC access: eliminate duplicate calls to bcForUPC.zdc() - Remove EventFilteringUtils dependency from CMakeLists.txt - Add const qualifiers for improved code clarity Binning configuration: - FT0: {1001, -1.5, 999.5} - FV0A: {2001, -1.5, 1999.5} - FDD: {200, 0., 4000.} - ZN: {510, -1.5, 49.5} 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/CMakeLists.txt | 4 +- PWGHF/D2H/Tasks/taskD0.cxx | 68 ++++++++++++++++++++++++--------- PWGHF/D2H/Tasks/taskDplus.cxx | 69 +++++++++++++++++++++++++--------- PWGHF/Utils/utilsUpcHf.h | 30 ++++++++------- 4 files changed, 121 insertions(+), 50 deletions(-) diff --git a/PWGHF/D2H/Tasks/CMakeLists.txt b/PWGHF/D2H/Tasks/CMakeLists.txt index 99bad681b88..a6bab371fde 100644 --- a/PWGHF/D2H/Tasks/CMakeLists.txt +++ b/PWGHF/D2H/Tasks/CMakeLists.txt @@ -71,7 +71,7 @@ o2physics_add_dpl_workflow(task-charm-reso-to-d-trk-reduced o2physics_add_dpl_workflow(task-d0 SOURCES taskD0.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons @@ -81,7 +81,7 @@ o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons o2physics_add_dpl_workflow(task-dplus SOURCES taskDplus.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-ds diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 09f7735f855..0cd85faf600 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -103,8 +103,6 @@ struct HfTaskD0 { Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; HfEventSelection hfEvSel; // event selection and monitoring - SGSelector sgSelector; // UPC gap selector - ctpRateFetcher mRateFetcher; SliceCache cache; @@ -161,8 +159,10 @@ struct HfTaskD0 { ConfigurableAxis thnConfigAxisMinTpcNCrossedRows{"thnConfigAxisMinTpcNCrossedRows", {10, 70, 180}, "axis for minimum TPC NCls crossed rows of candidate prongs"}; ConfigurableAxis thnConfigAxisIR{"thnConfigAxisIR", {5000, 0, 500}, "Interaction rate (kHz)"}; ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap)"}; - ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; - ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFT0{"thnConfigAxisFT0", {1001, -1.5, 999.5}, "axis for FT0 amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFV0A{"thnConfigAxisFV0A", {2001, -1.5, 1999.5}, "axis for FV0-A amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFDD{"thnConfigAxisFDD", {200, 0., 4000.}, "axis for FDD amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisZN{"thnConfigAxisZN", {510, -1.5, 49.5}, "axis for ZN energy (a.u.)"}; HistogramRegistry registry{ "registry", @@ -306,8 +306,13 @@ struct HfTaskD0 { const AxisSpec thnAxisMinTpcNCrossedRows{thnConfigAxisMinTpcNCrossedRows, "Minimum TPC crossed rows"}; const AxisSpec thnAxisIR{thnConfigAxisIR, "Interaction rate"}; const AxisSpec thnAxisGapType{thnConfigAxisGapType, "Gap type"}; - const AxisSpec thnAxisFT0A{thnConfigAxisFT0A, "FT0-A amplitude"}; - const AxisSpec thnAxisFT0C{thnConfigAxisFT0C, "FT0-C amplitude"}; + const AxisSpec thnAxisFT0A{thnConfigAxisFT0, "FT0-A amplitude"}; + const AxisSpec thnAxisFT0C{thnConfigAxisFT0, "FT0-C amplitude"}; + const AxisSpec thnAxisFV0A{thnConfigAxisFV0A, "FV0-A amplitude"}; + const AxisSpec thnAxisFDDA{thnConfigAxisFDD, "FDD-A amplitude"}; + const AxisSpec thnAxisFDDC{thnConfigAxisFDD, "FDD-C amplitude"}; + const AxisSpec thnAxisZNA{thnConfigAxisZN, "ZNA energy"}; + const AxisSpec thnAxisZNC{thnConfigAxisZN, "ZNC energy"}; if (doprocessMcWithDCAFitterN || doprocessMcWithDCAFitterNCent || doprocessMcWithKFParticle || doprocessMcWithDCAFitterNMl || doprocessMcWithDCAFitterNMlCent || doprocessMcWithKFParticleMl) { std::vector axesAcc = {thnAxisGenPtD, thnAxisGenPtB, thnAxisY, thnAxisOrigin, thnAxisNumPvContr}; @@ -361,6 +366,11 @@ struct HfTaskD0 { axes.push_back(thnAxisGapType); axes.push_back(thnAxisFT0A); axes.push_back(thnAxisFT0C); + axes.push_back(thnAxisFV0A); + axes.push_back(thnAxisFDDA); + axes.push_back(thnAxisFDDC); + axes.push_back(thnAxisZNA); + axes.push_back(thnAxisZNC); } if (applyMl) { @@ -576,23 +586,42 @@ struct HfTaskD0 { if (rejectionMask != 0) { continue; } - const auto& bc = collision.template bc_as(); - upchelpers::FITInfo fitInfo{}; - udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); + auto bc = collision.template bc_as(); // Determine gap type using SGSelector with BC range checking - int gap = hf_upc::determineGapType(collision, bcs, sgSelector, - upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + const auto gapResult = hf_upc::determineGapType(collision, bcs, + upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + const int gap = gapResult.value; + + // Use the BC with FIT activity if available from SGSelector + auto bcForUPC = bc; + if (gapResult.bc) { + bcForUPC = *(gapResult.bc); + } + + // Get FIT information from the UPC BC + upchelpers::FITInfo fitInfo{}; + udhelpers::getFITinfo(fitInfo, bcForUPC, bcs, ft0s, fv0as, fdds); + + // Get ZDC energies if available (extract once and reuse) + const bool hasZdc = bcForUPC.has_zdc(); + float zdcEnergyZNA = -1.f; + float zdcEnergyZNC = -1.f; + if (hasZdc) { + const auto& zdc = bcForUPC.zdc(); + zdcEnergyZNA = zdc.energyCommonZNA(); + zdcEnergyZNC = zdc.energyCommonZNC(); + } - if (bc.has_zdc()) { - const auto& zdc = bc.zdc(); + // Fill QA histograms using the UPC BC for both FIT and ZDC + if (hasZdc) { registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); - registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); + registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdcEnergyZNA, zdcEnergyZNC); registry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } if (hf_upc::isSingleSidedGap(gap)) { - int const gapTypeInt = hf_upc::gapTypeToInt(gap); + const int gapTypeInt = hf_upc::gapTypeToInt(gap); const auto thisCollId = collision.globalIndex(); const auto& groupedD0Candidates = candidates.sliceBy(candD0PerCollision, thisCollId); @@ -624,10 +653,10 @@ struct HfTaskD0 { registry.fill(HIST("hMassVsPhi"), massD0bar, ptCandidate, candidate.phi()); } - // Fill THnSparse with structure matching histogram axes: [mass, pt, (mlScores if FillMl), rapidity, d0Type, (cent if storeCentrality), (occ, ir if storeOccupancyAndIR), gapType, FT0A, FT0C] + // Fill THnSparse with structure matching histogram axes: [mass, pt, (mlScores if FillMl), rapidity, d0Type, (cent if storeCentrality), (occ, ir if storeOccupancyAndIR), gapType, FT0A, FT0C, FV0A, FDDA, FDDC, ZNA, ZNC] auto fillTHnData = [&](float mass, int d0Type) { // Pre-calculate vector size to avoid reallocations - constexpr int NAxesBase = 7; // mass, pt, rapidity, d0Type, gapType, FT0A, FT0C + constexpr int NAxesBase = 12; // mass, pt, rapidity, d0Type, gapType, FT0A, FT0C, FV0A, FDDA, FDDC, ZNA, ZNC constexpr int NAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality int const nAxesOccIR = storeOccupancyAndIR ? 2 : 0; // occupancy and IR if storeOccupancyAndIR @@ -656,6 +685,11 @@ struct HfTaskD0 { valuesToFill.push_back(static_cast(gapTypeInt)); valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); + valuesToFill.push_back(static_cast(fitInfo.ampFV0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFDDA)); + valuesToFill.push_back(static_cast(fitInfo.ampFDDC)); + valuesToFill.push_back(static_cast(zdcEnergyZNA)); + valuesToFill.push_back(static_cast(zdcEnergyZNC)); if constexpr (FillMl) { registry.get(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 95e01f1050d..77c91d621f8 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -93,7 +93,6 @@ struct HfTaskDplus { Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; HfEventSelection hfEvSel; // event selection and monitoring - SGSelector sgSelector; // UPC gap selector ctpRateFetcher mRateFetcher; // interaction rate fetcher Service ccdb; @@ -136,8 +135,10 @@ struct HfTaskDplus { ConfigurableAxis thnConfigAxisMlScore1{"thnConfigAxisMlScore1", {100, 0., 1.}, "axis for ML output score 1"}; ConfigurableAxis thnConfigAxisMlScore2{"thnConfigAxisMlScore2", {100, 0., 1.}, "axis for ML output score 2"}; ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap)"}; - ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; - ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFT0{"thnConfigAxisFT0", {1001, -1.5, 999.5}, "axis for FT0 amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFV0A{"thnConfigAxisFV0A", {2001, -1.5, 1999.5}, "axis for FV0-A amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFDD{"thnConfigAxisFDD", {200, 0., 4000.}, "axis for FDD amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisZN{"thnConfigAxisZN", {510, -1.5, 49.5}, "axis for ZN energy (a.u.)"}; HistogramRegistry registry{ "registry", @@ -171,8 +172,13 @@ struct HfTaskDplus { AxisSpec const thnAxisIR{thnConfigAxisIR, "Interaction rate (kHz)"}; AxisSpec const thnAxisPvContributors{thnConfigAxisPvContributors, "PV contributors"}; AxisSpec const thnAxisGapType{thnConfigAxisGapType, "Gap type"}; - AxisSpec const thnAxisFT0A{thnConfigAxisFT0A, "FT0-A amplitude"}; - AxisSpec const thnAxisFT0C{thnConfigAxisFT0C, "FT0-C amplitude"}; + AxisSpec const thnAxisFT0A{thnConfigAxisFT0, "FT0-A amplitude"}; + AxisSpec const thnAxisFT0C{thnConfigAxisFT0, "FT0-C amplitude"}; + AxisSpec const thnAxisFV0A{thnConfigAxisFV0A, "FV0-A amplitude"}; + AxisSpec const thnAxisFDDA{thnConfigAxisFDD, "FDD-A amplitude"}; + AxisSpec const thnAxisFDDC{thnConfigAxisFDD, "FDD-C amplitude"}; + AxisSpec const thnAxisZNA{thnConfigAxisZN, "ZNA energy"}; + AxisSpec const thnAxisZNC{thnConfigAxisZN, "ZNC energy"}; registry.add("hMass", "3-prong candidates;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{350, 1.7, 2.05}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("hEta", "3-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); @@ -233,6 +239,11 @@ struct HfTaskDplus { axes.push_back(thnAxisGapType); axes.push_back(thnAxisFT0A); axes.push_back(thnAxisFT0C); + axes.push_back(thnAxisFV0A); + axes.push_back(thnAxisFDDA); + axes.push_back(thnAxisFDDC); + axes.push_back(thnAxisZNA); + axes.push_back(thnAxisZNC); } registry.add("hSparseMass", "THn for Dplus", HistType::kTHnSparseF, axes); @@ -712,24 +723,45 @@ struct HfTaskDplus { /// at least one event selection not satisfied --> reject the candidate continue; } - const auto& bc = collision.template bc_as(); - upchelpers::FITInfo fitInfo{}; - udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); + auto bc = collision.template bc_as(); // Determine gap type using SGSelector with BC range checking - int gap = hf_upc::determineGapType(collision, bcs, sgSelector, - upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + const auto gapResult = hf_upc::determineGapType(collision, bcs, + upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + const int gap = gapResult.value; + + // Use the BC with FIT activity if available from SGSelector + auto bcForUPC = bc; + if (gapResult.bc) { + bcForUPC = *(gapResult.bc); + } - if (bc.has_zdc()) { - const auto& zdc = bc.zdc(); + // Get FIT information from the UPC BC + upchelpers::FITInfo fitInfo{}; + udhelpers::getFITinfo(fitInfo, bcForUPC, bcs, ft0s, fv0as, fdds); + + // Get ZDC energies if available (extract once and reuse) + const bool hasZdc = bcForUPC.has_zdc(); + float zdcEnergyZNA = -1.f; + float zdcEnergyZNC = -1.f; + if (hasZdc) { + const auto& zdc = bcForUPC.zdc(); + zdcEnergyZNA = zdc.energyCommonZNA(); + zdcEnergyZNC = zdc.energyCommonZNC(); + } + + // Fill QA histograms using the UPC BC for both FIT and ZDC + if (hasZdc) { registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); - registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); + registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdcEnergyZNA, zdcEnergyZNC); registry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } + if (hf_upc::isSingleSidedGap(gap)) { - // Use the candidates from this collision + const int gapTypeInt = hf_upc::gapTypeToInt(gap); const auto thisCollId = collision.globalIndex(); const auto& groupedDplusCandidates = candidates.sliceBy(candDplusPerCollision, thisCollId); + float cent{-1.f}; float occ{-1.f}; float ir{-1.f}; @@ -739,13 +771,11 @@ struct HfTaskDplus { if (storeIR) { ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource, true) * 1.e-3; // kHz } - float numPvContr{-1.f}; - int const gapTypeInt = hf_upc::gapTypeToInt(gap); // Lambda function to fill THn - handles both ML and non-ML cases auto fillTHnData = [&](const auto& candidate) { // Pre-calculate vector size to avoid reallocations - constexpr int NAxesBase = 5; // mass, pt, gapType, FT0A, FT0C + constexpr int NAxesBase = 10; // mass, pt, gapType, FT0A, FT0C, FV0A, FDDA, FDDC, ZNA, ZNC constexpr int NAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality int const nAxesOcc = storeOccupancy ? 1 : 0; // occupancy if storeOccupancy @@ -779,6 +809,11 @@ struct HfTaskDplus { valuesToFill.push_back(static_cast(gapTypeInt)); valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); + valuesToFill.push_back(static_cast(fitInfo.ampFV0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFDDA)); + valuesToFill.push_back(static_cast(fitInfo.ampFDDC)); + valuesToFill.push_back(static_cast(zdcEnergyZNA)); + valuesToFill.push_back(static_cast(zdcEnergyZNC)); registry.get(HIST("hSparseMass"))->Fill(valuesToFill.data()); }; diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h index 82dddde729a..1d22ee9003b 100644 --- a/PWGHF/Utils/utilsUpcHf.h +++ b/PWGHF/Utils/utilsUpcHf.h @@ -45,19 +45,19 @@ constexpr int MaxNTracks = 100; ///< Maximum number of tracks /// \tparam TBCs BC table type /// \param collision Collision object /// \param bcs BC table -/// \param sgSelector SGSelector instance /// \param amplitudeThresholdFV0A Threshold for FV0-A (default: 100.0) /// \param amplitudeThresholdFT0A Threshold for FT0-A (default: 100.0) /// \param amplitudeThresholdFT0C Threshold for FT0-C (default: 50.0) -/// \return TrueGap enum value (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap) +/// \return SelectionResult with gap type value and BC pointer template -inline int determineGapType(TCollision const& collision, - TBCs const& bcs, - SGSelector& sgSelector, - float amplitudeThresholdFV0A = defaults::AmplitudeThresholdFV0A, - float amplitudeThresholdFT0A = defaults::AmplitudeThresholdFT0A, - float amplitudeThresholdFT0C = defaults::AmplitudeThresholdFT0C) +inline auto determineGapType(TCollision const& collision, + TBCs const& bcs, + float amplitudeThresholdFV0A = defaults::AmplitudeThresholdFV0A, + float amplitudeThresholdFT0A = defaults::AmplitudeThresholdFT0A, + float amplitudeThresholdFT0C = defaults::AmplitudeThresholdFT0C) { + using BCType = std::decay_t())>; + // Configure SGSelector thresholds SGCutParHolder sgCuts; sgCuts.SetNDtcoll(defaults::NDtColl); @@ -68,22 +68,23 @@ inline int determineGapType(TCollision const& collision, // Get BC and BC range if (!collision.has_foundBC()) { - return TrueGap::NoGap; + return SelectionResult{TrueGap::NoGap, nullptr}; } const auto bc = collision.template foundBC_as(); const auto bcRange = udhelpers::compatibleBCs(collision, sgCuts.NDtcoll(), bcs, sgCuts.minNBCs()); - // Use SGSelector to determine gap type with BC range checking + // Create SGSelector instance and determine gap type with BC range checking + SGSelector sgSelector; const auto sgResult = sgSelector.IsSelected(sgCuts, collision, bcRange, bc); - return sgResult.value; + return sgResult; } /// \brief Check if the gap type is a single-sided gap (SingleGapA or SingleGapC) /// \param gap TrueGap enum value /// \return true if single-sided gap, false otherwise -inline bool isSingleSidedGap(int gap) +constexpr bool isSingleSidedGap(int gap) noexcept { return (gap == TrueGap::SingleGapA || gap == TrueGap::SingleGapC); } @@ -91,7 +92,7 @@ inline bool isSingleSidedGap(int gap) /// \brief Get gap type name as string /// \param gap TrueGap enum value /// \return String representation of gap type -inline const char* getGapTypeName(int gap) +constexpr const char* getGapTypeName(int gap) noexcept { switch (gap) { case TrueGap::NoGap: @@ -116,7 +117,8 @@ inline const char* getGapTypeName(int gap) /// \brief Convert gap type to integer for histogram filling /// \param gap TrueGap enum value /// \return Integer representation (-1, 0, 1, 2, 3, 4, 5) -inline int gapTypeToInt(int gap) +/// \note This is a pass-through function for consistency with other utility functions +constexpr int gapTypeToInt(int gap) noexcept { return gap; } From 2f23121b490facce3587c73b75de98f1ea301fca Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Fri, 14 Nov 2025 14:42:35 +0100 Subject: [PATCH 21/48] [PWGHF] Add process functions without ML for UPC analysis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add processDataWithUpc to taskDplus for UPC analysis without ML - Add processDataWithDCAFitterNWithUpc to taskD0 for UPC analysis without ML - Both functions use template parameter false to disable ML selections - Addresses colleague's request for non-ML UPC processing options 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskD0.cxx | 13 +++++++++++++ PWGHF/D2H/Tasks/taskDplus.cxx | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 0cd85faf600..3b8578712c2 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -1173,6 +1173,19 @@ struct HfTaskD0 { PROCESS_SWITCH(HfTaskD0, processMcWithKFParticleMl, "Process MC with KFParticle and ML selections", false); // TODO: add the processMcWithKFParticleMlCent + void processDataWithDCAFitterNWithUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + D0Candidates const&, + aod::TracksWExtra const& tracks, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds, + aod::Zdcs const& /*zdcs*/) + { + runAnalysisPerCollisionDataWithUpc(collisions, selectedD0Candidates, bcs, ft0s, fv0as, fdds); + } + PROCESS_SWITCH(HfTaskD0, processDataWithDCAFitterNWithUpc, "Process real data with DCAFitterN w/o ML with UPC", false); + void processDataWithDCAFitterNMlWithUpc(soa::Join const& collisions, aod::BcFullInfos const& bcs, D0CandidatesMl const&, diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 77c91d621f8..1770388b016 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -861,6 +861,19 @@ struct HfTaskDplus { } PROCESS_SWITCH(HfTaskDplus, processMcWithMl, "Process MC with ML", false); + void processDataWithUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + CandDplusData const& selectedDplusCandidates, + aod::Tracks const&, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds, + aod::Zdcs const& /*zdcs*/) + { + runAnalysisPerCollisionDataWithUpc(collisions, selectedDplusCandidates, bcs, ft0s, fv0as, fdds); + } + PROCESS_SWITCH(HfTaskDplus, processDataWithUpc, "Process real data w/o ML with UPC", false); + void processDataWithMlWithUpc(soa::Join const& collisions, aod::BcFullInfos const& bcs, CandDplusDataWithMl const& selectedDplusCandidatesMl, From 488109c3b576e95f0a277a5b034cacca4e036f41 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Fri, 14 Nov 2025 19:11:05 +0100 Subject: [PATCH 22/48] Refactor UPC gap determination thresholds using ConfigurableGroup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add HfUpcGapThresholds ConfigurableGroup in utilsUpcHf.h - Includes fv0aThreshold, ft0aThreshold, ft0cThreshold, zdcThreshold - Enables reusability across multiple HF tasks - Uses "upc" as JSON group name prefix - Add determineGapType() overload accepting HfUpcGapThresholds - Simplifies function calls by passing threshold group directly - Improves code readability and maintainability - Replace individual Configurables in taskD0.cxx and taskDplus.cxx - Remove 4 separate threshold Configurables per task - Replace with single HfUpcGapThresholds member - Simplify determineGapType() calls from 3 parameters to 1 - Update thnConfigAxisGapType description to reference TrueGap enum - Change from hardcoded values to enum reference - Improves documentation clarity 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskD0.cxx | 14 ++++---------- PWGHF/D2H/Tasks/taskDplus.cxx | 16 +++++----------- PWGHF/Utils/utilsUpcHf.h | 31 +++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 3b8578712c2..b961f39c4cc 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -96,13 +96,8 @@ struct HfTaskD0 { Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; - // UPC gap determination thresholds - Configurable upcFV0AThreshold{"upcFV0AThreshold", 100.0f, "FV0-A amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcFT0CThreshold{"upcFT0CThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; - - HfEventSelection hfEvSel; // event selection and monitoring + HfEventSelection hfEvSel; // event selection and monitoring + HfUpcGapThresholds upcThresholds; // UPC gap determination thresholds ctpRateFetcher mRateFetcher; SliceCache cache; @@ -158,7 +153,7 @@ struct HfTaskD0 { ConfigurableAxis thnConfigAxisMinItsNCls{"thnConfigAxisMinItsNCls", {5, 3, 8}, "axis for minimum ITS NCls of candidate prongs"}; ConfigurableAxis thnConfigAxisMinTpcNCrossedRows{"thnConfigAxisMinTpcNCrossedRows", {10, 70, 180}, "axis for minimum TPC NCls crossed rows of candidate prongs"}; ConfigurableAxis thnConfigAxisIR{"thnConfigAxisIR", {5000, 0, 500}, "Interaction rate (kHz)"}; - ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap)"}; + ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (see TrueGap enum in o2::aod::sgselector)"}; ConfigurableAxis thnConfigAxisFT0{"thnConfigAxisFT0", {1001, -1.5, 999.5}, "axis for FT0 amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFV0A{"thnConfigAxisFV0A", {2001, -1.5, 1999.5}, "axis for FV0-A amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFDD{"thnConfigAxisFDD", {200, 0., 4000.}, "axis for FDD amplitude (a.u.)"}; @@ -589,8 +584,7 @@ struct HfTaskD0 { auto bc = collision.template bc_as(); // Determine gap type using SGSelector with BC range checking - const auto gapResult = hf_upc::determineGapType(collision, bcs, - upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + const auto gapResult = hf_upc::determineGapType(collision, bcs, upcThresholds); const int gap = gapResult.value; // Use the BC with FIT activity if available from SGSelector diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 1770388b016..4fa73bb6c56 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -86,14 +86,9 @@ struct HfTaskDplus { Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; - // UPC gap determination thresholds - Configurable upcFV0AThreshold{"upcFV0AThreshold", 100.0f, "FV0-A amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcFT0CThreshold{"upcFT0CThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; - - HfEventSelection hfEvSel; // event selection and monitoring - ctpRateFetcher mRateFetcher; // interaction rate fetcher + HfEventSelection hfEvSel; // event selection and monitoring + HfUpcGapThresholds upcThresholds; // UPC gap determination thresholds + ctpRateFetcher mRateFetcher; // interaction rate fetcher Service ccdb; @@ -134,7 +129,7 @@ struct HfTaskDplus { ConfigurableAxis thnConfigAxisMlScore0{"thnConfigAxisMlScore0", {100, 0., 1.}, "axis for ML output score 0"}; ConfigurableAxis thnConfigAxisMlScore1{"thnConfigAxisMlScore1", {100, 0., 1.}, "axis for ML output score 1"}; ConfigurableAxis thnConfigAxisMlScore2{"thnConfigAxisMlScore2", {100, 0., 1.}, "axis for ML output score 2"}; - ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap)"}; + ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (see TrueGap enum in o2::aod::sgselector)"}; ConfigurableAxis thnConfigAxisFT0{"thnConfigAxisFT0", {1001, -1.5, 999.5}, "axis for FT0 amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFV0A{"thnConfigAxisFV0A", {2001, -1.5, 1999.5}, "axis for FV0-A amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFDD{"thnConfigAxisFDD", {200, 0., 4000.}, "axis for FDD amplitude (a.u.)"}; @@ -726,8 +721,7 @@ struct HfTaskDplus { auto bc = collision.template bc_as(); // Determine gap type using SGSelector with BC range checking - const auto gapResult = hf_upc::determineGapType(collision, bcs, - upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + const auto gapResult = hf_upc::determineGapType(collision, bcs, upcThresholds); const int gap = gapResult.value; // Use the BC with FIT activity if available from SGSelector diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h index 1d22ee9003b..acfca5042d1 100644 --- a/PWGHF/Utils/utilsUpcHf.h +++ b/PWGHF/Utils/utilsUpcHf.h @@ -21,12 +21,25 @@ #include "PWGUD/Core/SGSelector.h" #include "PWGUD/Core/UDHelpers.h" +#include + +#include + namespace o2::analysis::hf_upc { /// \brief Use TrueGap enum from SGSelector for gap type classification using o2::aod::sgselector::TrueGap; +/// \brief Configurable group for UPC gap determination thresholds +struct HfUpcGapThresholds : o2::framework::ConfigurableGroup { + std::string prefix = "upc"; // JSON group name + o2::framework::Configurable fv0aThreshold{"fv0aThreshold", 100.0f, "FV0-A amplitude threshold for UPC gap determination (a.u.)"}; + o2::framework::Configurable ft0aThreshold{"ft0aThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; + o2::framework::Configurable ft0cThreshold{"ft0cThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; + o2::framework::Configurable zdcThreshold{"zdcThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; +}; + /// \brief Default thresholds for gap determination namespace defaults { @@ -81,6 +94,24 @@ inline auto determineGapType(TCollision const& collision, return sgResult; } +/// \brief Determine gap type using SGSelector with BC range checking and HfUpcGapThresholds +/// \tparam TCollision Collision type +/// \tparam TBCs BC table type +/// \param collision Collision object +/// \param bcs BC table +/// \param thresholds HfUpcGapThresholds object containing all UPC thresholds +/// \return SelectionResult with gap type value and BC pointer +template +inline auto determineGapType(TCollision const& collision, + TBCs const& bcs, + HfUpcGapThresholds const& thresholds) +{ + return determineGapType(collision, bcs, + thresholds.fv0aThreshold.value, + thresholds.ft0aThreshold.value, + thresholds.ft0cThreshold.value); +} + /// \brief Check if the gap type is a single-sided gap (SingleGapA or SingleGapC) /// \param gap TrueGap enum value /// \return true if single-sided gap, false otherwise From 65df4bb00b4691163ae69965a72ead8aa5be6c1b Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Mon, 10 Nov 2025 20:30:47 +0100 Subject: [PATCH 23/48] Fix PWGHF struct member order: move ConfigurableAxis after Partition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to PWGHF coding guidelines, ConfigurableAxis must appear AFTER Partition declarations. The correct order is: 1. Configurable 2. Other members (HfHelper, HfEventSelection, ctpRateFetcher, SliceCache) 3. Service<> 4. using declarations 5. Filter, Preslice, PresliceUnsorted 6. Partition 7. ConfigurableAxis 8. HistogramRegistry Changes: - taskD0.cxx: Moved all ConfigurableAxis declarations to after Partition declarations - taskDplus.cxx: Moved all ConfigurableAxis declarations to after Partition declarations This resolves the linting errors: - "ConfigurableAxis appears too early (before end of Partition<)" Reference: https://aliceo2group.github.io/analysis-framework/docs/advanced-specifics/pwghf.html#contribute 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskDplus.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 06bc2318c9c..43783f620c7 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -84,6 +84,11 @@ struct HfTaskDplus { Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + // UPC gap determination thresholds + Configurable upcFT0AThreshold{"upcFT0AThreshold", hf_upc::defaults::FT0AThreshold, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcFT0CThreshold{"upcFT0CThreshold", hf_upc::defaults::FT0CThreshold, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcZDCThreshold{"upcZDCThreshold", hf_upc::defaults::ZDCThreshold, "ZDC energy threshold for UPC gap determination (a.u.)"}; + HfEventSelection hfEvSel; // event selection and monitoring Service ccdb; @@ -128,11 +133,6 @@ struct HfTaskDplus { ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; - // UPC gap determination thresholds - Configurable upcFT0AThreshold{"upcFT0AThreshold", hf_upc::defaults::FT0AThreshold, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcFT0CThreshold{"upcFT0CThreshold", hf_upc::defaults::FT0CThreshold, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcZDCThreshold{"upcZDCThreshold", hf_upc::defaults::ZDCThreshold, "ZDC energy threshold for UPC gap determination (a.u.)"}; - HistogramRegistry registry{ "registry", {{"hPt", "3-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, From d098cace1ba51808e170c9499f6850ea3751d9a3 Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Mon, 10 Nov 2025 20:38:05 +0100 Subject: [PATCH 24/48] Address code review comments: rename thresholds and remove unnecessary copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes based on code review feedback from vkucera: 1. Rename threshold constants to follow "quantity + object" naming pattern: - FT0AThreshold → AmplitudeThresholdFT0A - FT0CThreshold → AmplitudeThresholdFT0C - ZDCThreshold → EnergyThresholdZDC Updated function parameters and all usages in utilsUpcHf.h. 2. Remove unnecessary centrality copy in UPC process function: - Removed `float cent{centrality};` declaration - Use `centrality` variable directly throughout the function This eliminates redundant variable and improves code clarity. 3. Use literal values for Configurable defaults: - Configurables require literal values, not constexpr references - Changed from using defaults namespace to 100.0f, 50.0f, 1.0f 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskDplus.cxx | 6 +++--- PWGHF/Utils/utilsUpcHf.h | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 43783f620c7..9e8bb86156d 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -85,9 +85,9 @@ struct HfTaskDplus { Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; // UPC gap determination thresholds - Configurable upcFT0AThreshold{"upcFT0AThreshold", hf_upc::defaults::FT0AThreshold, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcFT0CThreshold{"upcFT0CThreshold", hf_upc::defaults::FT0CThreshold, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcZDCThreshold{"upcZDCThreshold", hf_upc::defaults::ZDCThreshold, "ZDC energy threshold for UPC gap determination (a.u.)"}; + Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcFT0CThreshold{"upcFT0CThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; HfEventSelection hfEvSel; // event selection and monitoring diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h index 4080464b971..a3add09a983 100644 --- a/PWGHF/Utils/utilsUpcHf.h +++ b/PWGHF/Utils/utilsUpcHf.h @@ -32,9 +32,9 @@ enum class GapType : uint8_t { /// \brief Default thresholds for gap determination namespace defaults { -constexpr float FT0AThreshold = 100.0f; ///< FT0-A amplitude threshold (a.u.) -constexpr float FT0CThreshold = 50.0f; ///< FT0-C amplitude threshold (a.u.) -constexpr float ZDCThreshold = 1.0f; ///< ZDC energy threshold (a.u.) +constexpr float AmplitudeThresholdFT0A = 100.0f; ///< Amplitude threshold for FT0-A (a.u.) +constexpr float AmplitudeThresholdFT0C = 50.0f; ///< Amplitude threshold for FT0-C (a.u.) +constexpr float EnergyThresholdZDC = 1.0f; ///< Energy threshold for ZDC (a.u.) } // namespace defaults /// \brief Determine gap type based on FIT and ZDC signals @@ -42,24 +42,24 @@ constexpr float ZDCThreshold = 1.0f; ///< ZDC energy threshold (a.u.) /// \param ft0C FT0-C amplitude /// \param zdcA ZDC-A (ZNA) common energy /// \param zdcC ZDC-C (ZNC) common energy -/// \param ft0AThreshold Threshold for FT0-A (default: 100.0) -/// \param ft0CThreshold Threshold for FT0-C (default: 50.0) -/// \param zdcThreshold Threshold for ZDC (default: 1.0) +/// \param amplitudeThresholdFT0A Threshold for FT0-A (default: 100.0) +/// \param amplitudeThresholdFT0C Threshold for FT0-C (default: 50.0) +/// \param energyThresholdZDC Threshold for ZDC (default: 1.0) /// \return Gap type classification inline GapType determineGapType(float ft0A, float ft0C, float zdcA, float zdcC, - float ft0AThreshold = defaults::FT0AThreshold, - float ft0CThreshold = defaults::FT0CThreshold, - float zdcThreshold = defaults::ZDCThreshold) + float amplitudeThresholdFT0A = defaults::AmplitudeThresholdFT0A, + float amplitudeThresholdFT0C = defaults::AmplitudeThresholdFT0C, + float energyThresholdZDC = defaults::EnergyThresholdZDC) { // Gap on A-side: FT0-A empty, FT0-C active, ZNA empty, ZNC active - if (ft0A < ft0AThreshold && ft0C > ft0CThreshold && - zdcA < zdcThreshold && zdcC > zdcThreshold) { + if (ft0A < amplitudeThresholdFT0A && ft0C > amplitudeThresholdFT0C && + zdcA < energyThresholdZDC && zdcC > energyThresholdZDC) { return GapType::GapA; } // Gap on C-side: FT0-A active, FT0-C empty, ZNA active, ZNC empty - if (ft0A > ft0AThreshold && ft0C < ft0CThreshold && - zdcA > zdcThreshold && zdcC < zdcThreshold) { + if (ft0A > amplitudeThresholdFT0A && ft0C < amplitudeThresholdFT0C && + zdcA > energyThresholdZDC && zdcC < energyThresholdZDC) { return GapType::GapC; } From e61700cd4d0875bb88b621d4e016d8eecf8b8821 Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Mon, 10 Nov 2025 20:54:08 +0100 Subject: [PATCH 25/48] Add Filter for D0 hfflag check similar to taskDplus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following the pattern used in taskDplus, add a Filter to automatically filter D0 candidates by decay type flag at the framework level. Changes: 1. Add Filter filterD0Flag to check hfflag for D0ToPiK decay type 2. Wrap all D0 candidate types with soa::Filtered<> to apply the filter 3. Remove manual hfflag check in UPC process loop (now redundant) This ensures the hfflag filtering is applied consistently across all process functions and removes the need for manual checks in loops. The Filter is placed after using declarations and before Preslice declarations, following PWGHF struct member ordering guidelines. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/CMakeLists.txt | 4 ++-- PWGHF/D2H/Tasks/taskD0.cxx | 21 ++++++++++----------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/PWGHF/D2H/Tasks/CMakeLists.txt b/PWGHF/D2H/Tasks/CMakeLists.txt index 6e6ab7bf096..76caf26673f 100644 --- a/PWGHF/D2H/Tasks/CMakeLists.txt +++ b/PWGHF/D2H/Tasks/CMakeLists.txt @@ -71,7 +71,7 @@ o2physics_add_dpl_workflow(task-charm-reso-to-d-trk-reduced o2physics_add_dpl_workflow(task-d0 SOURCES taskD0.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons @@ -81,7 +81,7 @@ o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons o2physics_add_dpl_workflow(task-dplus SOURCES taskDplus.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::SGCutParHolder O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-ds diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index ce0ccbb2480..408b5f94938 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -105,15 +105,15 @@ struct HfTaskD0 { SliceCache cache; Service ccdb; - using D0Candidates = soa::Join; - using D0CandidatesMc = soa::Join; - using D0CandidatesKF = soa::Join; - using D0CandidatesMcKF = soa::Join; + using D0Candidates = soa::Filtered>; + using D0CandidatesMc = soa::Filtered>; + using D0CandidatesKF = soa::Filtered>; + using D0CandidatesMcKF = soa::Filtered>; - using D0CandidatesMl = soa::Join; - using D0CandidatesMlMc = soa::Join; - using D0CandidatesMlKF = soa::Join; - using D0CandidatesMlMcKF = soa::Join; + using D0CandidatesMl = soa::Filtered>; + using D0CandidatesMlMc = soa::Filtered>; + using D0CandidatesMlKF = soa::Filtered>; + using D0CandidatesMlMcKF = soa::Filtered>; using Collisions = soa::Join; using CollisionsCent = soa::Join; @@ -121,6 +121,8 @@ struct HfTaskD0 { using CollisionsWithMcLabelsCent = soa::Join; using TracksSelQuality = soa::Join; + Filter filterD0Flag = (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_2prong::DecayType::D0ToPiK))) != static_cast(0); + Preslice candD0PerCollision = aod::hf_cand::collisionId; PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; PresliceUnsorted colPerMcCollisionCent = aod::mccollisionlabel::mcCollisionId; @@ -625,9 +627,6 @@ struct HfTaskD0 { float occ{-1.f}; for (const auto& candidate : groupedD0Candidates) { - if (!(candidate.hfflag() & 1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) { - continue; - } if (yCandRecoMax >= 0. && std::abs(HfHelper::yD0(candidate)) > yCandRecoMax) { continue; } From 27c9583cb34d31d89d27c51001b8dbb6ff84c7df Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Wed, 12 Nov 2025 16:51:47 +0100 Subject: [PATCH 26/48] Remove unused configurable parameters Removed configurable parameters for ccdbPathGrp and ccdbPathGrpMag. --- PWGHF/D2H/Tasks/taskD0.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 408b5f94938..2b2e5a8ff48 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -94,8 +94,6 @@ struct HfTaskD0 { // ML inference Configurable applyMl{"applyMl", false, "Flag to apply ML selections"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; - Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; HfEventSelection hfEvSel; // event selection and monitoring From fdee2bb01de3b7c7e62903272dcf2f03e24436d4 Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Wed, 12 Nov 2025 16:52:51 +0100 Subject: [PATCH 27/48] Remove unused ccdbPathGrp and ccdbPathGrpMag parameters Removed configurable parameters for ccdbPathGrp and ccdbPathGrpMag. --- PWGHF/D2H/Tasks/taskDplus.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 9e8bb86156d..40effd948ce 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -81,8 +81,6 @@ struct HfTaskDplus { Configurable storePvContributors{"storePvContributors", false, "Flag to store number of PV contributors information"}; Configurable fillMcBkgHistos{"fillMcBkgHistos", false, "Flag to fill and store histograms for MC background"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; - Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; // UPC gap determination thresholds Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; From 5dc87762f56863465d4a54353f88449f0a045fe8 Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Wed, 12 Nov 2025 22:28:04 +0100 Subject: [PATCH 28/48] Code quality improvements addressing all review comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit addresses all code review feedback from @vkucera in PR #13603. Changes are relative to commit f3ce844 and incorporate optimizations from commit 3fea4f12d with custom GapType modifications. **1. Template Parameter Naming Convention** - Renamed `fillMl` → `FillMl` (CapitalCase) throughout: * taskD0.cxx: template declarations and all usage sites * taskDplus.cxx: template declarations and all usage sites - Follows O2Physics coding standards for template parameters **2. Const Correctness (taskD0.cxx)** - Added `const` to mass variable declarations: ```cpp const float massD0 = HfHelper::invMassD0ToPiK(candidate); const float massD0bar = HfHelper::invMassD0barToKPi(candidate); ``` - Improves code safety by marking immutable values **3. Lambda Function Optimization (taskD0.cxx, taskDplus.cxx)** - Merged multiple lambda functions into unified `fillTHnData` lambda - Reduces code duplication and improves maintainability - Handles both ML and non-ML cases in single function **4. Memory Allocation Optimization** - Pre-calculate vector size to avoid reallocations: ```cpp valuesToFill.reserve(nAxesTotal); ``` - Improves performance by preventing dynamic resizing **5. THnSparse Structure Documentation** - Added comprehensive comment documenting axis structure: ``` [mass, pt, (mlScores if FillMl), rapidity, d0Type, (cent if storeCentrality), (occ, ir if storeOccupancyAndIR), gapType, FT0A, FT0C] ``` - Makes histogram structure explicit and verifiable **6. Code Cleanup (utilsUpcHf.h)** - Removed unused `HfUpcQaHistoConfig` struct (19 lines) - Eliminates dead code from utility header **Modified Files:** - PWGHF/D2H/Tasks/taskD0.cxx: All above improvements - PWGHF/D2H/Tasks/taskDplus.cxx: Template naming + lambda optimization - PWGHF/Utils/utilsUpcHf.h: Remove unused struct Total changes: +137 insertions, -121 deletions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskD0.cxx | 168 +++++++++++++++------------------- PWGHF/D2H/Tasks/taskDplus.cxx | 104 +++++++++++++-------- PWGHF/Utils/utilsUpcHf.h | 18 ---- 3 files changed, 140 insertions(+), 150 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 2b2e5a8ff48..6afc300ca51 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -96,6 +96,11 @@ struct HfTaskD0 { Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + // UPC gap determination thresholds + Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcFT0CThreshold{"upcFT0CThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; + Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; + HfEventSelection hfEvSel; // event selection and monitoring ctpRateFetcher mRateFetcher; @@ -157,35 +162,6 @@ struct HfTaskD0 { ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; - // UPC gap determination thresholds - Configurable upcFT0AThreshold{"upcFT0AThreshold", hf_upc::defaults::FT0AThreshold, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcFT0CThreshold{"upcFT0CThreshold", hf_upc::defaults::FT0CThreshold, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcZDCThreshold{"upcZDCThreshold", hf_upc::defaults::ZDCThreshold, "ZDC energy threshold for UPC gap determination (a.u.)"}; - - HfEventSelection hfEvSel; // event selection and monitoring - - HfHelper hfHelper; - ctpRateFetcher mRateFetcher; - - SliceCache cache; - Service ccdb; - - using D0Candidates = soa::Join; - using D0CandidatesMc = soa::Join; - using D0CandidatesKF = soa::Join; - using D0CandidatesMcKF = soa::Join; - - using D0CandidatesMl = soa::Join; - using D0CandidatesMlMc = soa::Join; - using D0CandidatesMlKF = soa::Join; - using D0CandidatesMlMcKF = soa::Join; - - using Collisions = soa::Join; - using CollisionsCent = soa::Join; - using CollisionsWithMcLabels = soa::Join; - using CollisionsWithMcLabelsCent = soa::Join; - using TracksSelQuality = soa::Join; - HistogramRegistry registry{ "registry", {{"hPtCand", "2-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, @@ -262,8 +238,6 @@ struct HfTaskD0 { {"hMassReflBkgD0bar", "2-prong candidates (matched);#it{m}_{inv} (GeV/#it{c}^{2}); #it{p}_{T}; #it{y}", {HistType::kTH3F, {{120, 1.5848, 2.1848}, {150, 0., 30.}, {20, -5., 5.}}}}, {"hMassSigBkgD0bar", "2-prong candidates (not checked);#it{m}_{inv} (GeV/#it{c}^{2}); #it{p}_{T}; #it{y}", {HistType::kTH3F, {{120, 1.5848, 2.1848}, {150, 0., 30.}, {20, -5., 5.}}}}}}; - HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; - void init(InitContext&) { std::array doprocess{doprocessDataWithDCAFitterN, doprocessDataWithDCAFitterNCent, doprocessDataWithKFParticle, doprocessMcWithDCAFitterN, doprocessMcWithDCAFitterNCent, doprocessMcWithKFParticle, doprocessDataWithDCAFitterNMl, doprocessDataWithDCAFitterNMlCent, doprocessDataWithKFParticleMl, doprocessMcWithDCAFitterNMl, doprocessMcWithDCAFitterNMlCent, doprocessMcWithKFParticleMl, doprocessDataWithDCAFitterNMlWithUpc}; @@ -395,14 +369,14 @@ struct HfTaskD0 { registry.get(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"))->Sumw2(); } - qaRegistry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); - qaRegistry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); - qaRegistry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}); - qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapA) + 1, "A"); - qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapC) + 1, "C"); - qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::DoubleGap) + 1, "Double"); + registry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); + registry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); + registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}); + registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapA) + 1, "A"); + registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapC) + 1, "C"); + registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::DoubleGap) + 1, "Double"); - hfEvSel.addHistograms(qaRegistry); + hfEvSel.addHistograms(registry); ccdb->setURL(ccdbUrl); ccdb->setCaching(true); @@ -589,7 +563,7 @@ struct HfTaskD0 { } } - template + template void runAnalysisPerCollisionDataWithUpc(CollType const& collisions, CandType const& candidates, BCsType const& bcs, @@ -598,40 +572,45 @@ struct HfTaskD0 { aod::FDDs const& fdds) { for (const auto& collision : collisions) { - uint32_t rejectionMask{0}; float centrality{-1.f}; - rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, qaRegistry, bcs); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, registry, bcs); if (rejectionMask != 0) { continue; } - auto bc = collision.template bc_as(); + const auto& bc = collision.template bc_as(); upchelpers::FITInfo fitInfo{}; udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); GapType gap = GapType::DoubleGap; if (bc.has_zdc()) { - auto zdc = bc.zdc(); - qaRegistry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); - qaRegistry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); + const auto& zdc = bc.zdc(); + registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); + registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC(), upcFT0AThreshold, upcFT0CThreshold, upcZDCThreshold); - qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); + registry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } if (hf_upc::isSingleSidedGap(gap)) { int const gapTypeInt = hf_upc::gapTypeToInt(gap); const auto thisCollId = collision.globalIndex(); const auto& groupedD0Candidates = candidates.sliceBy(candD0PerCollision, thisCollId); - float cent{centrality}; + + // Calculate occupancy and interaction rate if needed float occ{-1.f}; + float ir{-1.f}; + if (storeOccupancyAndIR && occEstimator != OccupancyEstimator::None) { + occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); + ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource, true) * 1.e-3; // kHz + } for (const auto& candidate : groupedD0Candidates) { if (yCandRecoMax >= 0. && std::abs(HfHelper::yD0(candidate)) > yCandRecoMax) { continue; } - float massD0 = HfHelper::invMassD0ToPiK(candidate); - float massD0bar = HfHelper::invMassD0barToKPi(candidate); - auto ptCandidate = candidate.pt(); + const float massD0 = HfHelper::invMassD0ToPiK(candidate); + const float massD0bar = HfHelper::invMassD0barToKPi(candidate); + const auto ptCandidate = candidate.pt(); if (candidate.isSelD0() >= selectionFlagD0) { registry.fill(HIST("hMass"), massD0, ptCandidate); @@ -644,56 +623,53 @@ struct HfTaskD0 { registry.fill(HIST("hMassVsPhi"), massD0bar, ptCandidate, candidate.phi()); } - // Fill THnSparse with structure matching taskDplus: [mass, pt, mlScores, cent, occ, gapType, FT0A, FT0C] - if constexpr (fillMl) { - auto fillTHnData = [&](float mass, int d0Type) { - std::vector valuesToFill{static_cast(mass), static_cast(ptCandidate), - candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], - static_cast(HfHelper::yD0(candidate)), static_cast(d0Type)}; - if (storeCentrality) { - valuesToFill.push_back(cent); - } - if (storeOccupancyAndIR) { - valuesToFill.push_back(occ); - } - valuesToFill.push_back(static_cast(gapTypeInt)); - valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); - valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); - registry.get(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); - }; - - if (candidate.isSelD0() >= selectionFlagD0) { - fillTHnData(massD0, SigD0); - fillTHnData(massD0, candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); + // Fill THnSparse with structure matching histogram axes: [mass, pt, (mlScores if FillMl), rapidity, d0Type, (cent if storeCentrality), (occ, ir if storeOccupancyAndIR), gapType, FT0A, FT0C] + auto fillTHnData = [&](float mass, int d0Type) { + // Pre-calculate vector size to avoid reallocations + constexpr int nAxesBase = 7; // mass, pt, rapidity, d0Type, gapType, FT0A, FT0C + constexpr int nAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl + int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality + int const nAxesOccIR = storeOccupancyAndIR ? 2 : 0; // occupancy and IR if storeOccupancyAndIR + int const nAxesTotal = nAxesBase + nAxesMl + nAxesCent + nAxesOccIR; + + std::vector valuesToFill; + valuesToFill.reserve(nAxesTotal); + + // Fill values in order matching histogram axes + valuesToFill.push_back(static_cast(mass)); + valuesToFill.push_back(static_cast(ptCandidate)); + if constexpr (FillMl) { + valuesToFill.push_back(candidate.mlProbD0()[0]); + valuesToFill.push_back(candidate.mlProbD0()[1]); + valuesToFill.push_back(candidate.mlProbD0()[2]); } - if (candidate.isSelD0bar() >= selectionFlagD0bar) { - fillTHnData(massD0bar, SigD0bar); - fillTHnData(massD0bar, candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); + valuesToFill.push_back(static_cast(HfHelper::yD0(candidate))); + valuesToFill.push_back(static_cast(d0Type)); + if (storeCentrality) { + valuesToFill.push_back(centrality); } - } else { - auto fillTHnData = [&](float mass, int d0Type) { - std::vector valuesToFill{static_cast(mass), static_cast(ptCandidate), - static_cast(HfHelper::yD0(candidate)), static_cast(d0Type)}; - if (storeCentrality) { - valuesToFill.push_back(cent); - } - if (storeOccupancyAndIR) { - valuesToFill.push_back(occ); - } - valuesToFill.push_back(static_cast(gapTypeInt)); - valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); - valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); - registry.get(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); - }; - - if (candidate.isSelD0() >= selectionFlagD0) { - fillTHnData(massD0, SigD0); - fillTHnData(massD0, candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); + if (storeOccupancyAndIR) { + valuesToFill.push_back(occ); + valuesToFill.push_back(ir); } - if (candidate.isSelD0bar() >= selectionFlagD0bar) { - fillTHnData(massD0bar, SigD0bar); - fillTHnData(massD0bar, candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); + valuesToFill.push_back(static_cast(gapTypeInt)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); + + if constexpr (FillMl) { + registry.get(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); + } else { + registry.get(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); } + }; + + if (candidate.isSelD0() >= selectionFlagD0) { + fillTHnData(massD0, SigD0); + fillTHnData(massD0, candidate.isSelD0bar() ? ReflectedD0 : PureSigD0); + } + if (candidate.isSelD0bar() >= selectionFlagD0bar) { + fillTHnData(massD0bar, SigD0bar); + fillTHnData(massD0bar, candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar); } } } diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 40effd948ce..13b389182c0 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -30,6 +30,7 @@ #include "PWGHF/Utils/utilsUpcHf.h" #include "PWGUD/Core/UPCHelpers.h" +#include "Common/CCDB/ctpRateFetcher.h" #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" @@ -78,16 +79,19 @@ struct HfTaskDplus { Configurable> classMl{"classMl", {0, 1, 2}, "Indexes of ML scores to be stored. Three indexes max."}; Configurable storeCentrality{"storeCentrality", false, "Flag to store centrality information"}; Configurable storeOccupancy{"storeOccupancy", false, "Flag to store occupancy information"}; + Configurable storeIR{"storeIR", false, "Flag to store interaction rate information"}; Configurable storePvContributors{"storePvContributors", false, "Flag to store number of PV contributors information"}; Configurable fillMcBkgHistos{"fillMcBkgHistos", false, "Flag to fill and store histograms for MC background"}; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; // UPC gap determination thresholds Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcFT0CThreshold{"upcFT0CThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; - HfEventSelection hfEvSel; // event selection and monitoring + HfEventSelection hfEvSel; // event selection and monitoring + ctpRateFetcher mRateFetcher; // interaction rate fetcher Service ccdb; @@ -121,6 +125,7 @@ struct HfTaskDplus { ConfigurableAxis thnConfigAxisY{"thnConfigAxisY", {40, -1, 1}, "Cand. rapidity bins"}; ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {110, 0., 110.}, "axis for centrality"}; ConfigurableAxis thnConfigAxisOccupancy{"thnConfigAxisOccupancy", {14, 0, 14000}, "axis for occupancy"}; + ConfigurableAxis thnConfigAxisIR{"thnConfigAxisIR", {5000, 0, 500}, "Interaction rate (kHz)"}; ConfigurableAxis thnConfigAxisPvContributors{"thnConfigAxisPvContributors", {100, 0., 100.}, "axis for PV contributors"}; ConfigurableAxis thnConfigAxisPtBHad{"thnConfigAxisPtBHad", {25, 0., 50}, "axis for pt of B hadron decayed into D candidate"}; ConfigurableAxis thnConfigAxisFlagBHad{"thnConfigAxisFlagBHad", {5, 0., 5}, "axis for PDG of B hadron"}; @@ -143,8 +148,6 @@ struct HfTaskDplus { {"hEtaRecBg", "3-prong candidates (unmatched);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, {"hEtaGen", "MC particles (matched);#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}}}; - HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; - void init(InitContext&) { std::array doprocess{doprocessData, doprocessDataWithMl, doprocessMc, doprocessMcWithMl, doprocessDataWithMlWithUpc}; @@ -162,6 +165,7 @@ struct HfTaskDplus { AxisSpec const thnAxisFlagBHad{thnConfigAxisFlagBHad, "B Hadron flag"}; AxisSpec const thnAxisCent{thnConfigAxisCent, "Centrality"}; AxisSpec const thnAxisOccupancy{thnConfigAxisOccupancy, "Occupancy"}; + AxisSpec const thnAxisIR{thnConfigAxisIR, "Interaction rate (kHz)"}; AxisSpec const thnAxisPvContributors{thnConfigAxisPvContributors, "PV contributors"}; AxisSpec const thnAxisGapType{thnConfigAxisGapType, "Gap type"}; AxisSpec const thnAxisFT0A{thnConfigAxisFT0A, "FT0-A amplitude"}; @@ -219,6 +223,9 @@ struct HfTaskDplus { if (storeOccupancy) { axes.push_back(thnAxisOccupancy); } + if (storeIR) { + axes.push_back(thnAxisIR); + } if (doprocessDataWithMlWithUpc) { axes.push_back(thnAxisGapType); axes.push_back(thnAxisFT0A); @@ -271,14 +278,14 @@ struct HfTaskDplus { registry.add("hSparseMassGenFD", "THn for gen FD Dplus", HistType::kTHnSparseF, axesGenFD); } - qaRegistry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); - qaRegistry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); - qaRegistry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}); - qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapA) + 1, "A"); - qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapC) + 1, "C"); - qaRegistry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::DoubleGap) + 1, "Double"); + registry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); + registry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); + registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}); + registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapA) + 1, "A"); + registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapC) + 1, "C"); + registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::DoubleGap) + 1, "Double"); - hfEvSel.addHistograms(qaRegistry); // collision monitoring + hfEvSel.addHistograms(registry); // collision monitoring ccdb->setURL(ccdbUrl); ccdb->setCaching(true); @@ -690,7 +697,7 @@ struct HfTaskDplus { } } - template + template void runAnalysisPerCollisionDataWithUpc(CollType const& collisions, CandType const& candidates, BCsType const& bcs, @@ -699,25 +706,24 @@ struct HfTaskDplus { aod::FDDs const& fdds) { for (const auto& collision : collisions) { - uint32_t rejectionMask{0}; // 32 bits, in case new ev. selections will be added float centrality{-1.f}; - rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, qaRegistry, bcs); + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc(collision, centrality, ccdb, registry, bcs); if (rejectionMask != 0) { /// at least one event selection not satisfied --> reject the candidate continue; } - auto bc = collision.template bc_as(); + const auto& bc = collision.template bc_as(); upchelpers::FITInfo fitInfo{}; udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); GapType gap = GapType::DoubleGap; if (bc.has_zdc()) { - auto zdc = bc.zdc(); - qaRegistry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); - qaRegistry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); + const auto& zdc = bc.zdc(); + registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); + registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC(), upcFT0AThreshold, upcFT0CThreshold, upcZDCThreshold); - qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); + registry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } if (hf_upc::isSingleSidedGap(gap)) { // Use the candidates from this collision @@ -725,36 +731,62 @@ struct HfTaskDplus { const auto& groupedDplusCandidates = candidates.sliceBy(candDplusPerCollision, thisCollId); float cent{-1.f}; float occ{-1.f}; + float ir{-1.f}; if (storeOccupancy && occEstimator != OccupancyEstimator::None) { occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); } + if (storeIR) { + ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource, true) * 1.e-3; // kHz + } float numPvContr{-1.f}; int const gapTypeInt = hf_upc::gapTypeToInt(gap); - for (const auto& candidate : groupedDplusCandidates) { - if ((yCandRecoMax >= 0. && std::abs(HfHelper::yDplus(candidate)) > yCandRecoMax)) { - continue; - } - fillHisto(candidate); - if constexpr (fillMl) { - // Fill THn with gap type and FIT signals + // Lambda function to fill THn - handles both ML and non-ML cases + auto fillTHnData = [&](const auto& candidate) { + // Pre-calculate vector size to avoid reallocations + constexpr int nAxesBase = 5; // mass, pt, gapType, FT0A, FT0C + constexpr int nAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl + int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality + int const nAxesOcc = storeOccupancy ? 1 : 0; // occupancy if storeOccupancy + int const nAxesIR = storeIR ? 1 : 0; // IR if storeIR + int const nAxesTotal = nAxesBase + nAxesMl + nAxesCent + nAxesOcc + nAxesIR; + + std::vector valuesToFill; + valuesToFill.reserve(nAxesTotal); + + // Fill values in order matching histogram axes + valuesToFill.push_back(HfHelper::invMassDplusToPiKPi(candidate)); + valuesToFill.push_back(static_cast(candidate.pt())); + if constexpr (FillMl) { std::vector outputMl = {-999., -999., -999.}; for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMl->at(iclass)]; } + valuesToFill.push_back(outputMl[0]); + valuesToFill.push_back(outputMl[1]); + valuesToFill.push_back(outputMl[2]); + } + if (storeCentrality) { + valuesToFill.push_back(cent); + } + if (storeOccupancy) { + valuesToFill.push_back(occ); + } + if (storeIR) { + valuesToFill.push_back(ir); + } + valuesToFill.push_back(static_cast(gapTypeInt)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); + registry.get(HIST("hSparseMass"))->Fill(valuesToFill.data()); + }; - std::vector valuesToFill{HfHelper::invMassDplusToPiKPi(candidate), static_cast(candidate.pt()), outputMl[0], outputMl[1], outputMl[2]}; - if (storeCentrality) { - valuesToFill.push_back(cent); - } - if (storeOccupancy) { - valuesToFill.push_back(occ); - } - valuesToFill.push_back(static_cast(gapTypeInt)); - valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); - valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); - registry.get(HIST("hSparseMass"))->Fill(valuesToFill.data()); + for (const auto& candidate : groupedDplusCandidates) { + if ((yCandRecoMax >= 0. && std::abs(HfHelper::yDplus(candidate)) > yCandRecoMax)) { + continue; } + fillHisto(candidate); + fillTHnData(candidate); } } } diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h index a3add09a983..2fcf4edacf6 100644 --- a/PWGHF/Utils/utilsUpcHf.h +++ b/PWGHF/Utils/utilsUpcHf.h @@ -100,24 +100,6 @@ inline int gapTypeToInt(GapType gap) return static_cast(gap); } -/// \brief Struct to hold UPC QA histogram configuration -struct HfUpcQaHistoConfig { - // FT0 histogram configuration - int ft0Nbins = 1500; - float ft0Min = 0.f; - float ft0Max = 1500.f; - - // ZDC histogram configuration - int zdcNbins = 200; - float zdcMin = 0.f; - float zdcMax = 20.f; - - // Gap type histogram configuration - int gapNbins = 3; - float gapMin = -0.5f; - float gapMax = 2.5f; -}; - } // namespace o2::analysis::hf_upc #endif // PWGHF_UTILS_UTILSUPCHF_H_ From 8bd44f72ddb09aa6f905476b708f7e738d1476f1 Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Thu, 13 Nov 2025 00:04:33 +0100 Subject: [PATCH 29/48] Migrate UPC gap classification to SGSelector with BC range checking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates the UPC (Ultra-Peripheral Collision) gap determination in taskD0 and taskDplus to use SGSelector from PWGUD/Core instead of custom gap classification logic. Key changes: - Migrate from custom GapType enum to SGSelector's TrueGap enum in utilsUpcHf.h - Update gap type classification to support 7 categories: NoGap (-1), SingleGapA (0), SingleGapC (1), DoubleGap (2), NoUpc (3), TrkOutOfRange (4), BadDoubleGap (5) - Add SGSelector instance to taskD0 and taskDplus for gap determination - Add FV0-A amplitude threshold configurable for more comprehensive gap classification - Remove unused energyThresholdZDC parameter as SGCutParHolder only supports FIT amplitudes - Add BC range checking via udhelpers::compatibleBCs for improved gap classification accuracy - Update histogram axes from 3 bins to 7 bins to accommodate new gap types - Add required library dependencies (SGCutParHolder, EventFilteringUtils) to CMakeLists.txt Technical details: - SGSelector uses SGCutParHolder to configure thresholds for FIT detectors (FV0A, FT0A, FT0C) - BC range checking examines multiple BCs around collision using NDtColl=1000ns and MinNBCs=7 - Gap determination now uses SGSelector::IsSelected() with proper BC range instead of simple threshold comparison - This aligns PWGHF UPC analysis with standard gap classification used in PWGUD 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/CMakeLists.txt | 4 +- PWGHF/D2H/Tasks/taskD0.cxx | 23 +++---- PWGHF/D2H/Tasks/taskDplus.cxx | 23 +++---- PWGHF/Utils/utilsUpcHf.h | 111 ++++++++++++++++++++------------- 4 files changed, 92 insertions(+), 69 deletions(-) diff --git a/PWGHF/D2H/Tasks/CMakeLists.txt b/PWGHF/D2H/Tasks/CMakeLists.txt index 76caf26673f..99bad681b88 100644 --- a/PWGHF/D2H/Tasks/CMakeLists.txt +++ b/PWGHF/D2H/Tasks/CMakeLists.txt @@ -71,7 +71,7 @@ o2physics_add_dpl_workflow(task-charm-reso-to-d-trk-reduced o2physics_add_dpl_workflow(task-d0 SOURCES taskD0.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons @@ -81,7 +81,7 @@ o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons o2physics_add_dpl_workflow(task-dplus SOURCES taskDplus.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-ds diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 6afc300ca51..09f7735f855 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -97,11 +97,13 @@ struct HfTaskD0 { Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; // UPC gap determination thresholds + Configurable upcFV0AThreshold{"upcFV0AThreshold", 100.0f, "FV0-A amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcFT0CThreshold{"upcFT0CThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; HfEventSelection hfEvSel; // event selection and monitoring + SGSelector sgSelector; // UPC gap selector ctpRateFetcher mRateFetcher; @@ -158,7 +160,7 @@ struct HfTaskD0 { ConfigurableAxis thnConfigAxisMinItsNCls{"thnConfigAxisMinItsNCls", {5, 3, 8}, "axis for minimum ITS NCls of candidate prongs"}; ConfigurableAxis thnConfigAxisMinTpcNCrossedRows{"thnConfigAxisMinTpcNCrossedRows", {10, 70, 180}, "axis for minimum TPC NCls crossed rows of candidate prongs"}; ConfigurableAxis thnConfigAxisIR{"thnConfigAxisIR", {5000, 0, 500}, "Interaction rate (kHz)"}; - ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {3, -0.5, 2.5}, "axis for UPC gap type (0=GapA, 1=GapC, 2=DoubleGap)"}; + ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap)"}; ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; @@ -371,10 +373,7 @@ struct HfTaskD0 { registry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); registry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); - registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}); - registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapA) + 1, "A"); - registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapC) + 1, "C"); - registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::DoubleGap) + 1, "Double"); + registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap type;Counts", {HistType::kTH1F, {{7, -1.5, 5.5}}}); hfEvSel.addHistograms(registry); @@ -581,15 +580,17 @@ struct HfTaskD0 { upchelpers::FITInfo fitInfo{}; udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); - GapType gap = GapType::DoubleGap; + // Determine gap type using SGSelector with BC range checking + int gap = hf_upc::determineGapType(collision, bcs, sgSelector, + upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + if (bc.has_zdc()) { const auto& zdc = bc.zdc(); registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); - gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC(), - upcFT0AThreshold, upcFT0CThreshold, upcZDCThreshold); registry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } + if (hf_upc::isSingleSidedGap(gap)) { int const gapTypeInt = hf_upc::gapTypeToInt(gap); const auto thisCollId = collision.globalIndex(); @@ -626,11 +627,11 @@ struct HfTaskD0 { // Fill THnSparse with structure matching histogram axes: [mass, pt, (mlScores if FillMl), rapidity, d0Type, (cent if storeCentrality), (occ, ir if storeOccupancyAndIR), gapType, FT0A, FT0C] auto fillTHnData = [&](float mass, int d0Type) { // Pre-calculate vector size to avoid reallocations - constexpr int nAxesBase = 7; // mass, pt, rapidity, d0Type, gapType, FT0A, FT0C - constexpr int nAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl + constexpr int NAxesBase = 7; // mass, pt, rapidity, d0Type, gapType, FT0A, FT0C + constexpr int NAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality int const nAxesOccIR = storeOccupancyAndIR ? 2 : 0; // occupancy and IR if storeOccupancyAndIR - int const nAxesTotal = nAxesBase + nAxesMl + nAxesCent + nAxesOccIR; + int const nAxesTotal = NAxesBase + NAxesMl + nAxesCent + nAxesOccIR; std::vector valuesToFill; valuesToFill.reserve(nAxesTotal); diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 13b389182c0..95e01f1050d 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -22,6 +22,7 @@ #include "PWGHF/Core/DecayChannels.h" #include "PWGHF/Core/HfHelper.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" @@ -86,11 +87,13 @@ struct HfTaskDplus { Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; // UPC gap determination thresholds + Configurable upcFV0AThreshold{"upcFV0AThreshold", 100.0f, "FV0-A amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcFT0CThreshold{"upcFT0CThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; HfEventSelection hfEvSel; // event selection and monitoring + SGSelector sgSelector; // UPC gap selector ctpRateFetcher mRateFetcher; // interaction rate fetcher Service ccdb; @@ -132,7 +135,7 @@ struct HfTaskDplus { ConfigurableAxis thnConfigAxisMlScore0{"thnConfigAxisMlScore0", {100, 0., 1.}, "axis for ML output score 0"}; ConfigurableAxis thnConfigAxisMlScore1{"thnConfigAxisMlScore1", {100, 0., 1.}, "axis for ML output score 1"}; ConfigurableAxis thnConfigAxisMlScore2{"thnConfigAxisMlScore2", {100, 0., 1.}, "axis for ML output score 2"}; - ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {3, -0.5, 2.5}, "axis for UPC gap type (0=GapA, 1=GapC, 2=DoubleGap)"}; + ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap)"}; ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; @@ -280,10 +283,7 @@ struct HfTaskDplus { registry.add("Data/fitInfo/ampFT0A_vs_ampFT0C", "FT0-A vs FT0-C amplitude;FT0-A amplitude (a.u.);FT0-C amplitude (a.u.)", {HistType::kTH2F, {{2500, 0., 250}, {2500, 0., 250}}}); registry.add("Data/zdc/energyZNA_vs_energyZNC", "ZNA vs ZNC common energy;E_{ZNA}^{common} (a.u.);E_{ZNC}^{common} (a.u.)", {HistType::kTH2F, {{200, 0., 20}, {200, 0., 20}}}); - registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap side;Counts", {HistType::kTH1F, {{3, -0.5, 2.5}}}); - registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapA) + 1, "A"); - registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::GapC) + 1, "C"); - registry.get(HIST("Data/hUpcGapAfterSelection"))->GetXaxis()->SetBinLabel(static_cast(GapType::DoubleGap) + 1, "Double"); + registry.add("Data/hUpcGapAfterSelection", "UPC gap type after selection;Gap type;Counts", {HistType::kTH1F, {{7, -1.5, 5.5}}}); hfEvSel.addHistograms(registry); // collision monitoring @@ -716,13 +716,14 @@ struct HfTaskDplus { upchelpers::FITInfo fitInfo{}; udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); - GapType gap = GapType::DoubleGap; + // Determine gap type using SGSelector with BC range checking + int gap = hf_upc::determineGapType(collision, bcs, sgSelector, + upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + if (bc.has_zdc()) { const auto& zdc = bc.zdc(); registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); - gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC(), - upcFT0AThreshold, upcFT0CThreshold, upcZDCThreshold); registry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } if (hf_upc::isSingleSidedGap(gap)) { @@ -744,12 +745,12 @@ struct HfTaskDplus { // Lambda function to fill THn - handles both ML and non-ML cases auto fillTHnData = [&](const auto& candidate) { // Pre-calculate vector size to avoid reallocations - constexpr int nAxesBase = 5; // mass, pt, gapType, FT0A, FT0C - constexpr int nAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl + constexpr int NAxesBase = 5; // mass, pt, gapType, FT0A, FT0C + constexpr int NAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality int const nAxesOcc = storeOccupancy ? 1 : 0; // occupancy if storeOccupancy int const nAxesIR = storeIR ? 1 : 0; // IR if storeIR - int const nAxesTotal = nAxesBase + nAxesMl + nAxesCent + nAxesOcc + nAxesIR; + int const nAxesTotal = NAxesBase + NAxesMl + nAxesCent + nAxesOcc + nAxesIR; std::vector valuesToFill; valuesToFill.reserve(nAxesTotal); diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h index 2fcf4edacf6..82dddde729a 100644 --- a/PWGHF/Utils/utilsUpcHf.h +++ b/PWGHF/Utils/utilsUpcHf.h @@ -17,87 +17,108 @@ #ifndef PWGHF_UTILS_UTILSUPCHF_H_ #define PWGHF_UTILS_UTILSUPCHF_H_ -#include +#include "PWGUD/Core/SGCutParHolder.h" +#include "PWGUD/Core/SGSelector.h" +#include "PWGUD/Core/UDHelpers.h" namespace o2::analysis::hf_upc { -/// \brief Gap type classification for UPC events -enum class GapType : uint8_t { - GapA = 0, ///< Gap on A-side (C-side active) - GapC = 1, ///< Gap on C-side (A-side active) - DoubleGap = 2 ///< Double gap (both sides empty) -}; +/// \brief Use TrueGap enum from SGSelector for gap type classification +using o2::aod::sgselector::TrueGap; /// \brief Default thresholds for gap determination namespace defaults { +constexpr float AmplitudeThresholdFV0A = 100.0f; ///< Amplitude threshold for FV0-A (a.u.) constexpr float AmplitudeThresholdFT0A = 100.0f; ///< Amplitude threshold for FT0-A (a.u.) constexpr float AmplitudeThresholdFT0C = 50.0f; ///< Amplitude threshold for FT0-C (a.u.) -constexpr float EnergyThresholdZDC = 1.0f; ///< Energy threshold for ZDC (a.u.) +constexpr float MaxFITTime = 4.0f; ///< Maximum FIT time (ns) +constexpr int NDtColl = 1000; ///< Time window for BC range (ns) +constexpr int MinNBCs = 7; ///< Minimum number of BCs to check +constexpr int MinNTracks = 0; ///< Minimum number of tracks +constexpr int MaxNTracks = 100; ///< Maximum number of tracks } // namespace defaults -/// \brief Determine gap type based on FIT and ZDC signals -/// \param ft0A FT0-A amplitude -/// \param ft0C FT0-C amplitude -/// \param zdcA ZDC-A (ZNA) common energy -/// \param zdcC ZDC-C (ZNC) common energy +/// \brief Determine gap type using SGSelector with BC range checking +/// \tparam TCollision Collision type +/// \tparam TBCs BC table type +/// \param collision Collision object +/// \param bcs BC table +/// \param sgSelector SGSelector instance +/// \param amplitudeThresholdFV0A Threshold for FV0-A (default: 100.0) /// \param amplitudeThresholdFT0A Threshold for FT0-A (default: 100.0) /// \param amplitudeThresholdFT0C Threshold for FT0-C (default: 50.0) -/// \param energyThresholdZDC Threshold for ZDC (default: 1.0) -/// \return Gap type classification -inline GapType determineGapType(float ft0A, float ft0C, float zdcA, float zdcC, - float amplitudeThresholdFT0A = defaults::AmplitudeThresholdFT0A, - float amplitudeThresholdFT0C = defaults::AmplitudeThresholdFT0C, - float energyThresholdZDC = defaults::EnergyThresholdZDC) +/// \return TrueGap enum value (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap) +template +inline int determineGapType(TCollision const& collision, + TBCs const& bcs, + SGSelector& sgSelector, + float amplitudeThresholdFV0A = defaults::AmplitudeThresholdFV0A, + float amplitudeThresholdFT0A = defaults::AmplitudeThresholdFT0A, + float amplitudeThresholdFT0C = defaults::AmplitudeThresholdFT0C) { - // Gap on A-side: FT0-A empty, FT0-C active, ZNA empty, ZNC active - if (ft0A < amplitudeThresholdFT0A && ft0C > amplitudeThresholdFT0C && - zdcA < energyThresholdZDC && zdcC > energyThresholdZDC) { - return GapType::GapA; - } + // Configure SGSelector thresholds + SGCutParHolder sgCuts; + sgCuts.SetNDtcoll(defaults::NDtColl); + sgCuts.SetMinNBCs(defaults::MinNBCs); + sgCuts.SetNTracks(defaults::MinNTracks, defaults::MaxNTracks); + sgCuts.SetMaxFITtime(defaults::MaxFITTime); + sgCuts.SetFITAmpLimits({amplitudeThresholdFV0A, amplitudeThresholdFT0A, amplitudeThresholdFT0C}); - // Gap on C-side: FT0-A active, FT0-C empty, ZNA active, ZNC empty - if (ft0A > amplitudeThresholdFT0A && ft0C < amplitudeThresholdFT0C && - zdcA > energyThresholdZDC && zdcC < energyThresholdZDC) { - return GapType::GapC; + // Get BC and BC range + if (!collision.has_foundBC()) { + return TrueGap::NoGap; } - // Default: Double gap (or no clear gap) - return GapType::DoubleGap; + const auto bc = collision.template foundBC_as(); + const auto bcRange = udhelpers::compatibleBCs(collision, sgCuts.NDtcoll(), bcs, sgCuts.minNBCs()); + + // Use SGSelector to determine gap type with BC range checking + const auto sgResult = sgSelector.IsSelected(sgCuts, collision, bcRange, bc); + + return sgResult.value; } -/// \brief Check if the gap type is a single-sided gap (GapA or GapC) -/// \param gap Gap type +/// \brief Check if the gap type is a single-sided gap (SingleGapA or SingleGapC) +/// \param gap TrueGap enum value /// \return true if single-sided gap, false otherwise -inline bool isSingleSidedGap(GapType gap) +inline bool isSingleSidedGap(int gap) { - return (gap == GapType::GapA || gap == GapType::GapC); + return (gap == TrueGap::SingleGapA || gap == TrueGap::SingleGapC); } /// \brief Get gap type name as string -/// \param gap Gap type +/// \param gap TrueGap enum value /// \return String representation of gap type -inline const char* getGapTypeName(GapType gap) +inline const char* getGapTypeName(int gap) { switch (gap) { - case GapType::GapA: - return "GapA"; - case GapType::GapC: - return "GapC"; - case GapType::DoubleGap: + case TrueGap::NoGap: + return "NoGap"; + case TrueGap::SingleGapA: + return "SingleGapA"; + case TrueGap::SingleGapC: + return "SingleGapC"; + case TrueGap::DoubleGap: return "DoubleGap"; + case TrueGap::NoUpc: + return "NoUpc"; + case TrueGap::TrkOutOfRange: + return "TrkOutOfRange"; + case TrueGap::BadDoubleGap: + return "BadDoubleGap"; default: return "Unknown"; } } /// \brief Convert gap type to integer for histogram filling -/// \param gap Gap type -/// \return Integer representation (0=GapA, 1=GapC, 2=DoubleGap) -inline int gapTypeToInt(GapType gap) +/// \param gap TrueGap enum value +/// \return Integer representation (-1, 0, 1, 2, 3, 4, 5) +inline int gapTypeToInt(int gap) { - return static_cast(gap); + return gap; } } // namespace o2::analysis::hf_upc From 902369cde7dc576b4a32c6f85ccbe406cf130639 Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Thu, 13 Nov 2025 21:04:41 +0100 Subject: [PATCH 30/48] Add UPC detector amplitudes and optimize taskD0/taskDplus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add FV0A, FDDA, FDDC, ZNA, ZNC axes to THnSparse histograms - Optimize detector binning: unified FT0/FDD/ZN for A/C sides - Optimize utilsUpcHf.h: add constexpr/noexcept to utility functions - Optimize ZDC access: eliminate duplicate calls to bcForUPC.zdc() - Remove EventFilteringUtils dependency from CMakeLists.txt - Add const qualifiers for improved code clarity Binning configuration: - FT0: {1001, -1.5, 999.5} - FV0A: {2001, -1.5, 1999.5} - FDD: {200, 0., 4000.} - ZN: {510, -1.5, 49.5} 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/CMakeLists.txt | 4 +- PWGHF/D2H/Tasks/taskD0.cxx | 68 ++++++++++++++++++++++++--------- PWGHF/D2H/Tasks/taskDplus.cxx | 69 +++++++++++++++++++++++++--------- PWGHF/Utils/utilsUpcHf.h | 30 ++++++++------- 4 files changed, 121 insertions(+), 50 deletions(-) diff --git a/PWGHF/D2H/Tasks/CMakeLists.txt b/PWGHF/D2H/Tasks/CMakeLists.txt index 99bad681b88..a6bab371fde 100644 --- a/PWGHF/D2H/Tasks/CMakeLists.txt +++ b/PWGHF/D2H/Tasks/CMakeLists.txt @@ -71,7 +71,7 @@ o2physics_add_dpl_workflow(task-charm-reso-to-d-trk-reduced o2physics_add_dpl_workflow(task-d0 SOURCES taskD0.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons @@ -81,7 +81,7 @@ o2physics_add_dpl_workflow(task-directed-flow-charm-hadrons o2physics_add_dpl_workflow(task-dplus SOURCES taskDplus.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder O2Physics::EventFilteringUtils + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::SGCutParHolder COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(task-ds diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 09f7735f855..0cd85faf600 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -103,8 +103,6 @@ struct HfTaskD0 { Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; HfEventSelection hfEvSel; // event selection and monitoring - SGSelector sgSelector; // UPC gap selector - ctpRateFetcher mRateFetcher; SliceCache cache; @@ -161,8 +159,10 @@ struct HfTaskD0 { ConfigurableAxis thnConfigAxisMinTpcNCrossedRows{"thnConfigAxisMinTpcNCrossedRows", {10, 70, 180}, "axis for minimum TPC NCls crossed rows of candidate prongs"}; ConfigurableAxis thnConfigAxisIR{"thnConfigAxisIR", {5000, 0, 500}, "Interaction rate (kHz)"}; ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap)"}; - ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; - ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFT0{"thnConfigAxisFT0", {1001, -1.5, 999.5}, "axis for FT0 amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFV0A{"thnConfigAxisFV0A", {2001, -1.5, 1999.5}, "axis for FV0-A amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFDD{"thnConfigAxisFDD", {200, 0., 4000.}, "axis for FDD amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisZN{"thnConfigAxisZN", {510, -1.5, 49.5}, "axis for ZN energy (a.u.)"}; HistogramRegistry registry{ "registry", @@ -306,8 +306,13 @@ struct HfTaskD0 { const AxisSpec thnAxisMinTpcNCrossedRows{thnConfigAxisMinTpcNCrossedRows, "Minimum TPC crossed rows"}; const AxisSpec thnAxisIR{thnConfigAxisIR, "Interaction rate"}; const AxisSpec thnAxisGapType{thnConfigAxisGapType, "Gap type"}; - const AxisSpec thnAxisFT0A{thnConfigAxisFT0A, "FT0-A amplitude"}; - const AxisSpec thnAxisFT0C{thnConfigAxisFT0C, "FT0-C amplitude"}; + const AxisSpec thnAxisFT0A{thnConfigAxisFT0, "FT0-A amplitude"}; + const AxisSpec thnAxisFT0C{thnConfigAxisFT0, "FT0-C amplitude"}; + const AxisSpec thnAxisFV0A{thnConfigAxisFV0A, "FV0-A amplitude"}; + const AxisSpec thnAxisFDDA{thnConfigAxisFDD, "FDD-A amplitude"}; + const AxisSpec thnAxisFDDC{thnConfigAxisFDD, "FDD-C amplitude"}; + const AxisSpec thnAxisZNA{thnConfigAxisZN, "ZNA energy"}; + const AxisSpec thnAxisZNC{thnConfigAxisZN, "ZNC energy"}; if (doprocessMcWithDCAFitterN || doprocessMcWithDCAFitterNCent || doprocessMcWithKFParticle || doprocessMcWithDCAFitterNMl || doprocessMcWithDCAFitterNMlCent || doprocessMcWithKFParticleMl) { std::vector axesAcc = {thnAxisGenPtD, thnAxisGenPtB, thnAxisY, thnAxisOrigin, thnAxisNumPvContr}; @@ -361,6 +366,11 @@ struct HfTaskD0 { axes.push_back(thnAxisGapType); axes.push_back(thnAxisFT0A); axes.push_back(thnAxisFT0C); + axes.push_back(thnAxisFV0A); + axes.push_back(thnAxisFDDA); + axes.push_back(thnAxisFDDC); + axes.push_back(thnAxisZNA); + axes.push_back(thnAxisZNC); } if (applyMl) { @@ -576,23 +586,42 @@ struct HfTaskD0 { if (rejectionMask != 0) { continue; } - const auto& bc = collision.template bc_as(); - upchelpers::FITInfo fitInfo{}; - udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); + auto bc = collision.template bc_as(); // Determine gap type using SGSelector with BC range checking - int gap = hf_upc::determineGapType(collision, bcs, sgSelector, - upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + const auto gapResult = hf_upc::determineGapType(collision, bcs, + upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + const int gap = gapResult.value; + + // Use the BC with FIT activity if available from SGSelector + auto bcForUPC = bc; + if (gapResult.bc) { + bcForUPC = *(gapResult.bc); + } + + // Get FIT information from the UPC BC + upchelpers::FITInfo fitInfo{}; + udhelpers::getFITinfo(fitInfo, bcForUPC, bcs, ft0s, fv0as, fdds); + + // Get ZDC energies if available (extract once and reuse) + const bool hasZdc = bcForUPC.has_zdc(); + float zdcEnergyZNA = -1.f; + float zdcEnergyZNC = -1.f; + if (hasZdc) { + const auto& zdc = bcForUPC.zdc(); + zdcEnergyZNA = zdc.energyCommonZNA(); + zdcEnergyZNC = zdc.energyCommonZNC(); + } - if (bc.has_zdc()) { - const auto& zdc = bc.zdc(); + // Fill QA histograms using the UPC BC for both FIT and ZDC + if (hasZdc) { registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); - registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); + registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdcEnergyZNA, zdcEnergyZNC); registry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } if (hf_upc::isSingleSidedGap(gap)) { - int const gapTypeInt = hf_upc::gapTypeToInt(gap); + const int gapTypeInt = hf_upc::gapTypeToInt(gap); const auto thisCollId = collision.globalIndex(); const auto& groupedD0Candidates = candidates.sliceBy(candD0PerCollision, thisCollId); @@ -624,10 +653,10 @@ struct HfTaskD0 { registry.fill(HIST("hMassVsPhi"), massD0bar, ptCandidate, candidate.phi()); } - // Fill THnSparse with structure matching histogram axes: [mass, pt, (mlScores if FillMl), rapidity, d0Type, (cent if storeCentrality), (occ, ir if storeOccupancyAndIR), gapType, FT0A, FT0C] + // Fill THnSparse with structure matching histogram axes: [mass, pt, (mlScores if FillMl), rapidity, d0Type, (cent if storeCentrality), (occ, ir if storeOccupancyAndIR), gapType, FT0A, FT0C, FV0A, FDDA, FDDC, ZNA, ZNC] auto fillTHnData = [&](float mass, int d0Type) { // Pre-calculate vector size to avoid reallocations - constexpr int NAxesBase = 7; // mass, pt, rapidity, d0Type, gapType, FT0A, FT0C + constexpr int NAxesBase = 12; // mass, pt, rapidity, d0Type, gapType, FT0A, FT0C, FV0A, FDDA, FDDC, ZNA, ZNC constexpr int NAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality int const nAxesOccIR = storeOccupancyAndIR ? 2 : 0; // occupancy and IR if storeOccupancyAndIR @@ -656,6 +685,11 @@ struct HfTaskD0 { valuesToFill.push_back(static_cast(gapTypeInt)); valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); + valuesToFill.push_back(static_cast(fitInfo.ampFV0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFDDA)); + valuesToFill.push_back(static_cast(fitInfo.ampFDDC)); + valuesToFill.push_back(static_cast(zdcEnergyZNA)); + valuesToFill.push_back(static_cast(zdcEnergyZNC)); if constexpr (FillMl) { registry.get(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"))->Fill(valuesToFill.data()); diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 95e01f1050d..77c91d621f8 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -93,7 +93,6 @@ struct HfTaskDplus { Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; HfEventSelection hfEvSel; // event selection and monitoring - SGSelector sgSelector; // UPC gap selector ctpRateFetcher mRateFetcher; // interaction rate fetcher Service ccdb; @@ -136,8 +135,10 @@ struct HfTaskDplus { ConfigurableAxis thnConfigAxisMlScore1{"thnConfigAxisMlScore1", {100, 0., 1.}, "axis for ML output score 1"}; ConfigurableAxis thnConfigAxisMlScore2{"thnConfigAxisMlScore2", {100, 0., 1.}, "axis for ML output score 2"}; ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap)"}; - ConfigurableAxis thnConfigAxisFT0A{"thnConfigAxisFT0A", {1001, -1.5, 999.5}, "axis for FT0-A amplitude (a.u.)"}; - ConfigurableAxis thnConfigAxisFT0C{"thnConfigAxisFT0C", {1001, -1.5, 999.5}, "axis for FT0-C amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFT0{"thnConfigAxisFT0", {1001, -1.5, 999.5}, "axis for FT0 amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFV0A{"thnConfigAxisFV0A", {2001, -1.5, 1999.5}, "axis for FV0-A amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisFDD{"thnConfigAxisFDD", {200, 0., 4000.}, "axis for FDD amplitude (a.u.)"}; + ConfigurableAxis thnConfigAxisZN{"thnConfigAxisZN", {510, -1.5, 49.5}, "axis for ZN energy (a.u.)"}; HistogramRegistry registry{ "registry", @@ -171,8 +172,13 @@ struct HfTaskDplus { AxisSpec const thnAxisIR{thnConfigAxisIR, "Interaction rate (kHz)"}; AxisSpec const thnAxisPvContributors{thnConfigAxisPvContributors, "PV contributors"}; AxisSpec const thnAxisGapType{thnConfigAxisGapType, "Gap type"}; - AxisSpec const thnAxisFT0A{thnConfigAxisFT0A, "FT0-A amplitude"}; - AxisSpec const thnAxisFT0C{thnConfigAxisFT0C, "FT0-C amplitude"}; + AxisSpec const thnAxisFT0A{thnConfigAxisFT0, "FT0-A amplitude"}; + AxisSpec const thnAxisFT0C{thnConfigAxisFT0, "FT0-C amplitude"}; + AxisSpec const thnAxisFV0A{thnConfigAxisFV0A, "FV0-A amplitude"}; + AxisSpec const thnAxisFDDA{thnConfigAxisFDD, "FDD-A amplitude"}; + AxisSpec const thnAxisFDDC{thnConfigAxisFDD, "FDD-C amplitude"}; + AxisSpec const thnAxisZNA{thnConfigAxisZN, "ZNA energy"}; + AxisSpec const thnAxisZNC{thnConfigAxisZN, "ZNC energy"}; registry.add("hMass", "3-prong candidates;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{350, 1.7, 2.05}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); registry.add("hEta", "3-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); @@ -233,6 +239,11 @@ struct HfTaskDplus { axes.push_back(thnAxisGapType); axes.push_back(thnAxisFT0A); axes.push_back(thnAxisFT0C); + axes.push_back(thnAxisFV0A); + axes.push_back(thnAxisFDDA); + axes.push_back(thnAxisFDDC); + axes.push_back(thnAxisZNA); + axes.push_back(thnAxisZNC); } registry.add("hSparseMass", "THn for Dplus", HistType::kTHnSparseF, axes); @@ -712,24 +723,45 @@ struct HfTaskDplus { /// at least one event selection not satisfied --> reject the candidate continue; } - const auto& bc = collision.template bc_as(); - upchelpers::FITInfo fitInfo{}; - udhelpers::getFITinfo(fitInfo, bc, bcs, ft0s, fv0as, fdds); + auto bc = collision.template bc_as(); // Determine gap type using SGSelector with BC range checking - int gap = hf_upc::determineGapType(collision, bcs, sgSelector, - upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + const auto gapResult = hf_upc::determineGapType(collision, bcs, + upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + const int gap = gapResult.value; + + // Use the BC with FIT activity if available from SGSelector + auto bcForUPC = bc; + if (gapResult.bc) { + bcForUPC = *(gapResult.bc); + } - if (bc.has_zdc()) { - const auto& zdc = bc.zdc(); + // Get FIT information from the UPC BC + upchelpers::FITInfo fitInfo{}; + udhelpers::getFITinfo(fitInfo, bcForUPC, bcs, ft0s, fv0as, fdds); + + // Get ZDC energies if available (extract once and reuse) + const bool hasZdc = bcForUPC.has_zdc(); + float zdcEnergyZNA = -1.f; + float zdcEnergyZNC = -1.f; + if (hasZdc) { + const auto& zdc = bcForUPC.zdc(); + zdcEnergyZNA = zdc.energyCommonZNA(); + zdcEnergyZNC = zdc.energyCommonZNC(); + } + + // Fill QA histograms using the UPC BC for both FIT and ZDC + if (hasZdc) { registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); - registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC()); + registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdcEnergyZNA, zdcEnergyZNC); registry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); } + if (hf_upc::isSingleSidedGap(gap)) { - // Use the candidates from this collision + const int gapTypeInt = hf_upc::gapTypeToInt(gap); const auto thisCollId = collision.globalIndex(); const auto& groupedDplusCandidates = candidates.sliceBy(candDplusPerCollision, thisCollId); + float cent{-1.f}; float occ{-1.f}; float ir{-1.f}; @@ -739,13 +771,11 @@ struct HfTaskDplus { if (storeIR) { ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource, true) * 1.e-3; // kHz } - float numPvContr{-1.f}; - int const gapTypeInt = hf_upc::gapTypeToInt(gap); // Lambda function to fill THn - handles both ML and non-ML cases auto fillTHnData = [&](const auto& candidate) { // Pre-calculate vector size to avoid reallocations - constexpr int NAxesBase = 5; // mass, pt, gapType, FT0A, FT0C + constexpr int NAxesBase = 10; // mass, pt, gapType, FT0A, FT0C, FV0A, FDDA, FDDC, ZNA, ZNC constexpr int NAxesMl = FillMl ? 3 : 0; // 3 ML scores if FillMl int const nAxesCent = storeCentrality ? 1 : 0; // centrality if storeCentrality int const nAxesOcc = storeOccupancy ? 1 : 0; // occupancy if storeOccupancy @@ -779,6 +809,11 @@ struct HfTaskDplus { valuesToFill.push_back(static_cast(gapTypeInt)); valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); + valuesToFill.push_back(static_cast(fitInfo.ampFV0A)); + valuesToFill.push_back(static_cast(fitInfo.ampFDDA)); + valuesToFill.push_back(static_cast(fitInfo.ampFDDC)); + valuesToFill.push_back(static_cast(zdcEnergyZNA)); + valuesToFill.push_back(static_cast(zdcEnergyZNC)); registry.get(HIST("hSparseMass"))->Fill(valuesToFill.data()); }; diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h index 82dddde729a..1d22ee9003b 100644 --- a/PWGHF/Utils/utilsUpcHf.h +++ b/PWGHF/Utils/utilsUpcHf.h @@ -45,19 +45,19 @@ constexpr int MaxNTracks = 100; ///< Maximum number of tracks /// \tparam TBCs BC table type /// \param collision Collision object /// \param bcs BC table -/// \param sgSelector SGSelector instance /// \param amplitudeThresholdFV0A Threshold for FV0-A (default: 100.0) /// \param amplitudeThresholdFT0A Threshold for FT0-A (default: 100.0) /// \param amplitudeThresholdFT0C Threshold for FT0-C (default: 50.0) -/// \return TrueGap enum value (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap) +/// \return SelectionResult with gap type value and BC pointer template -inline int determineGapType(TCollision const& collision, - TBCs const& bcs, - SGSelector& sgSelector, - float amplitudeThresholdFV0A = defaults::AmplitudeThresholdFV0A, - float amplitudeThresholdFT0A = defaults::AmplitudeThresholdFT0A, - float amplitudeThresholdFT0C = defaults::AmplitudeThresholdFT0C) +inline auto determineGapType(TCollision const& collision, + TBCs const& bcs, + float amplitudeThresholdFV0A = defaults::AmplitudeThresholdFV0A, + float amplitudeThresholdFT0A = defaults::AmplitudeThresholdFT0A, + float amplitudeThresholdFT0C = defaults::AmplitudeThresholdFT0C) { + using BCType = std::decay_t())>; + // Configure SGSelector thresholds SGCutParHolder sgCuts; sgCuts.SetNDtcoll(defaults::NDtColl); @@ -68,22 +68,23 @@ inline int determineGapType(TCollision const& collision, // Get BC and BC range if (!collision.has_foundBC()) { - return TrueGap::NoGap; + return SelectionResult{TrueGap::NoGap, nullptr}; } const auto bc = collision.template foundBC_as(); const auto bcRange = udhelpers::compatibleBCs(collision, sgCuts.NDtcoll(), bcs, sgCuts.minNBCs()); - // Use SGSelector to determine gap type with BC range checking + // Create SGSelector instance and determine gap type with BC range checking + SGSelector sgSelector; const auto sgResult = sgSelector.IsSelected(sgCuts, collision, bcRange, bc); - return sgResult.value; + return sgResult; } /// \brief Check if the gap type is a single-sided gap (SingleGapA or SingleGapC) /// \param gap TrueGap enum value /// \return true if single-sided gap, false otherwise -inline bool isSingleSidedGap(int gap) +constexpr bool isSingleSidedGap(int gap) noexcept { return (gap == TrueGap::SingleGapA || gap == TrueGap::SingleGapC); } @@ -91,7 +92,7 @@ inline bool isSingleSidedGap(int gap) /// \brief Get gap type name as string /// \param gap TrueGap enum value /// \return String representation of gap type -inline const char* getGapTypeName(int gap) +constexpr const char* getGapTypeName(int gap) noexcept { switch (gap) { case TrueGap::NoGap: @@ -116,7 +117,8 @@ inline const char* getGapTypeName(int gap) /// \brief Convert gap type to integer for histogram filling /// \param gap TrueGap enum value /// \return Integer representation (-1, 0, 1, 2, 3, 4, 5) -inline int gapTypeToInt(int gap) +/// \note This is a pass-through function for consistency with other utility functions +constexpr int gapTypeToInt(int gap) noexcept { return gap; } From 00e9971dc36ff17c8243007aa55e88bd80f9583a Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Fri, 14 Nov 2025 14:42:35 +0100 Subject: [PATCH 31/48] [PWGHF] Add process functions without ML for UPC analysis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add processDataWithUpc to taskDplus for UPC analysis without ML - Add processDataWithDCAFitterNWithUpc to taskD0 for UPC analysis without ML - Both functions use template parameter false to disable ML selections - Addresses colleague's request for non-ML UPC processing options 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskD0.cxx | 13 +++++++++++++ PWGHF/D2H/Tasks/taskDplus.cxx | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 0cd85faf600..3b8578712c2 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -1173,6 +1173,19 @@ struct HfTaskD0 { PROCESS_SWITCH(HfTaskD0, processMcWithKFParticleMl, "Process MC with KFParticle and ML selections", false); // TODO: add the processMcWithKFParticleMlCent + void processDataWithDCAFitterNWithUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + D0Candidates const&, + aod::TracksWExtra const& tracks, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds, + aod::Zdcs const& /*zdcs*/) + { + runAnalysisPerCollisionDataWithUpc(collisions, selectedD0Candidates, bcs, ft0s, fv0as, fdds); + } + PROCESS_SWITCH(HfTaskD0, processDataWithDCAFitterNWithUpc, "Process real data with DCAFitterN w/o ML with UPC", false); + void processDataWithDCAFitterNMlWithUpc(soa::Join const& collisions, aod::BcFullInfos const& bcs, D0CandidatesMl const&, diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 77c91d621f8..1770388b016 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -861,6 +861,19 @@ struct HfTaskDplus { } PROCESS_SWITCH(HfTaskDplus, processMcWithMl, "Process MC with ML", false); + void processDataWithUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + CandDplusData const& selectedDplusCandidates, + aod::Tracks const&, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds, + aod::Zdcs const& /*zdcs*/) + { + runAnalysisPerCollisionDataWithUpc(collisions, selectedDplusCandidates, bcs, ft0s, fv0as, fdds); + } + PROCESS_SWITCH(HfTaskDplus, processDataWithUpc, "Process real data w/o ML with UPC", false); + void processDataWithMlWithUpc(soa::Join const& collisions, aod::BcFullInfos const& bcs, CandDplusDataWithMl const& selectedDplusCandidatesMl, From f1241939149699f538b67d4997eeb759d2f52831 Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Fri, 14 Nov 2025 19:11:05 +0100 Subject: [PATCH 32/48] Refactor UPC gap determination thresholds using ConfigurableGroup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add HfUpcGapThresholds ConfigurableGroup in utilsUpcHf.h - Includes fv0aThreshold, ft0aThreshold, ft0cThreshold, zdcThreshold - Enables reusability across multiple HF tasks - Uses "upc" as JSON group name prefix - Add determineGapType() overload accepting HfUpcGapThresholds - Simplifies function calls by passing threshold group directly - Improves code readability and maintainability - Replace individual Configurables in taskD0.cxx and taskDplus.cxx - Remove 4 separate threshold Configurables per task - Replace with single HfUpcGapThresholds member - Simplify determineGapType() calls from 3 parameters to 1 - Update thnConfigAxisGapType description to reference TrueGap enum - Change from hardcoded values to enum reference - Improves documentation clarity 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskD0.cxx | 14 ++++---------- PWGHF/D2H/Tasks/taskDplus.cxx | 16 +++++----------- PWGHF/Utils/utilsUpcHf.h | 31 +++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 3b8578712c2..b961f39c4cc 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -96,13 +96,8 @@ struct HfTaskD0 { Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; - // UPC gap determination thresholds - Configurable upcFV0AThreshold{"upcFV0AThreshold", 100.0f, "FV0-A amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcFT0CThreshold{"upcFT0CThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; - - HfEventSelection hfEvSel; // event selection and monitoring + HfEventSelection hfEvSel; // event selection and monitoring + HfUpcGapThresholds upcThresholds; // UPC gap determination thresholds ctpRateFetcher mRateFetcher; SliceCache cache; @@ -158,7 +153,7 @@ struct HfTaskD0 { ConfigurableAxis thnConfigAxisMinItsNCls{"thnConfigAxisMinItsNCls", {5, 3, 8}, "axis for minimum ITS NCls of candidate prongs"}; ConfigurableAxis thnConfigAxisMinTpcNCrossedRows{"thnConfigAxisMinTpcNCrossedRows", {10, 70, 180}, "axis for minimum TPC NCls crossed rows of candidate prongs"}; ConfigurableAxis thnConfigAxisIR{"thnConfigAxisIR", {5000, 0, 500}, "Interaction rate (kHz)"}; - ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap)"}; + ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (see TrueGap enum in o2::aod::sgselector)"}; ConfigurableAxis thnConfigAxisFT0{"thnConfigAxisFT0", {1001, -1.5, 999.5}, "axis for FT0 amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFV0A{"thnConfigAxisFV0A", {2001, -1.5, 1999.5}, "axis for FV0-A amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFDD{"thnConfigAxisFDD", {200, 0., 4000.}, "axis for FDD amplitude (a.u.)"}; @@ -589,8 +584,7 @@ struct HfTaskD0 { auto bc = collision.template bc_as(); // Determine gap type using SGSelector with BC range checking - const auto gapResult = hf_upc::determineGapType(collision, bcs, - upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + const auto gapResult = hf_upc::determineGapType(collision, bcs, upcThresholds); const int gap = gapResult.value; // Use the BC with FIT activity if available from SGSelector diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 1770388b016..4fa73bb6c56 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -86,14 +86,9 @@ struct HfTaskDplus { Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable irSource{"irSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; - // UPC gap determination thresholds - Configurable upcFV0AThreshold{"upcFV0AThreshold", 100.0f, "FV0-A amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcFT0AThreshold{"upcFT0AThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcFT0CThreshold{"upcFT0CThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; - Configurable upcZDCThreshold{"upcZDCThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; - - HfEventSelection hfEvSel; // event selection and monitoring - ctpRateFetcher mRateFetcher; // interaction rate fetcher + HfEventSelection hfEvSel; // event selection and monitoring + HfUpcGapThresholds upcThresholds; // UPC gap determination thresholds + ctpRateFetcher mRateFetcher; // interaction rate fetcher Service ccdb; @@ -134,7 +129,7 @@ struct HfTaskDplus { ConfigurableAxis thnConfigAxisMlScore0{"thnConfigAxisMlScore0", {100, 0., 1.}, "axis for ML output score 0"}; ConfigurableAxis thnConfigAxisMlScore1{"thnConfigAxisMlScore1", {100, 0., 1.}, "axis for ML output score 1"}; ConfigurableAxis thnConfigAxisMlScore2{"thnConfigAxisMlScore2", {100, 0., 1.}, "axis for ML output score 2"}; - ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (-1=NoGap, 0=SingleGapA, 1=SingleGapC, 2=DoubleGap, 3=NoUpc, 4=TrkOutOfRange, 5=BadDoubleGap)"}; + ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {7, -1.5, 5.5}, "axis for UPC gap type (see TrueGap enum in o2::aod::sgselector)"}; ConfigurableAxis thnConfigAxisFT0{"thnConfigAxisFT0", {1001, -1.5, 999.5}, "axis for FT0 amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFV0A{"thnConfigAxisFV0A", {2001, -1.5, 1999.5}, "axis for FV0-A amplitude (a.u.)"}; ConfigurableAxis thnConfigAxisFDD{"thnConfigAxisFDD", {200, 0., 4000.}, "axis for FDD amplitude (a.u.)"}; @@ -726,8 +721,7 @@ struct HfTaskDplus { auto bc = collision.template bc_as(); // Determine gap type using SGSelector with BC range checking - const auto gapResult = hf_upc::determineGapType(collision, bcs, - upcFV0AThreshold, upcFT0AThreshold, upcFT0CThreshold); + const auto gapResult = hf_upc::determineGapType(collision, bcs, upcThresholds); const int gap = gapResult.value; // Use the BC with FIT activity if available from SGSelector diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h index 1d22ee9003b..acfca5042d1 100644 --- a/PWGHF/Utils/utilsUpcHf.h +++ b/PWGHF/Utils/utilsUpcHf.h @@ -21,12 +21,25 @@ #include "PWGUD/Core/SGSelector.h" #include "PWGUD/Core/UDHelpers.h" +#include + +#include + namespace o2::analysis::hf_upc { /// \brief Use TrueGap enum from SGSelector for gap type classification using o2::aod::sgselector::TrueGap; +/// \brief Configurable group for UPC gap determination thresholds +struct HfUpcGapThresholds : o2::framework::ConfigurableGroup { + std::string prefix = "upc"; // JSON group name + o2::framework::Configurable fv0aThreshold{"fv0aThreshold", 100.0f, "FV0-A amplitude threshold for UPC gap determination (a.u.)"}; + o2::framework::Configurable ft0aThreshold{"ft0aThreshold", 100.0f, "FT0-A amplitude threshold for UPC gap determination (a.u.)"}; + o2::framework::Configurable ft0cThreshold{"ft0cThreshold", 50.0f, "FT0-C amplitude threshold for UPC gap determination (a.u.)"}; + o2::framework::Configurable zdcThreshold{"zdcThreshold", 1.0f, "ZDC energy threshold for UPC gap determination (a.u.)"}; +}; + /// \brief Default thresholds for gap determination namespace defaults { @@ -81,6 +94,24 @@ inline auto determineGapType(TCollision const& collision, return sgResult; } +/// \brief Determine gap type using SGSelector with BC range checking and HfUpcGapThresholds +/// \tparam TCollision Collision type +/// \tparam TBCs BC table type +/// \param collision Collision object +/// \param bcs BC table +/// \param thresholds HfUpcGapThresholds object containing all UPC thresholds +/// \return SelectionResult with gap type value and BC pointer +template +inline auto determineGapType(TCollision const& collision, + TBCs const& bcs, + HfUpcGapThresholds const& thresholds) +{ + return determineGapType(collision, bcs, + thresholds.fv0aThreshold.value, + thresholds.ft0aThreshold.value, + thresholds.ft0cThreshold.value); +} + /// \brief Check if the gap type is a single-sided gap (SingleGapA or SingleGapC) /// \param gap TrueGap enum value /// \return true if single-sided gap, false otherwise From 591dc752c5639b1ecd4d1a000643d155ca2a69b6 Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Thu, 13 Nov 2025 14:36:57 -0600 Subject: [PATCH 33/48] [PWGLF] Add updated track efficiency estimation (#13820) --- .../heavyionMultiplicity.cxx | 182 +++++++++++++++++- 1 file changed, 173 insertions(+), 9 deletions(-) diff --git a/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx b/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx index b5801fc5248..804085b9682 100644 --- a/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx +++ b/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx @@ -92,6 +92,31 @@ enum { kSpeciesend }; +enum { + kGenTrkTypebegin = 0, + kGenAll = 1, + kGenPion, + kGenKaon, + kGenProton, + kGenOther, + kGenTrkTypeend +}; + +enum { + kRecTrkTypebegin = 0, + kRecoAll = 1, + kRecoPrimary, + kRecoPion, + kRecoKaon, + kRecoProton, + kRecoOther, + kRecoSecondary, + kRecoWeakDecay, + kRecoFake, + kRecoBkg, + kRecTrkTypeend +}; + static constexpr TrackSelectionFlags::flagtype TrackSelectionIts = TrackSelectionFlags::kITSNCls | TrackSelectionFlags::kITSChi2NDF | TrackSelectionFlags::kITSHits; @@ -113,12 +138,15 @@ AxisSpec axisCent{100, 0, 100, "#Cent"}; AxisSpec axisTrackType = {kTrackTypeend - 1, +kTrackTypebegin + 0.5, +kTrackTypeend - 0.5, "", "TrackTypeAxis"}; AxisSpec axisGenPtVary = {kGenpTend - 1, +kGenpTbegin + 0.5, +kGenpTend - 0.5, "", "GenpTVaryAxis"}; AxisSpec axisSpecies = {kSpeciesend - 1, +kSpeciesbegin + 0.5, +kSpeciesend - 0.5, "", "SpeciesAxis"}; +AxisSpec axisGenTrkType = {kGenTrkTypeend - 1, +kGenTrkTypebegin + 0.5, +kGenTrkTypeend - 0.5, "", "GenTrackTypeAxis"}; +AxisSpec axisRecTrkType = {kRecTrkTypeend - 1, +kRecTrkTypebegin + 0.5, +kRecTrkTypeend - 0.5, "", "RecTrackTypeAxis"}; AxisSpec axisMassK0s = {200, 0.4, 0.6, "K0sMass", "K0sMass"}; AxisSpec axisMassLambda = {200, 1.07, 1.17, "Lambda/AntiLamda Mass", "Lambda/AntiLamda Mass"}; AxisSpec axisTracks{9, 0.5, 9.5, "#tracks", "TrackAxis"}; -auto static constexpr kMinCharge = 3.f; -auto static constexpr kMinpTcut = 0.1f; -auto static constexpr kNItslayers = 7; +AxisSpec axisDeltaEta{50, -1.0, +1.0, "#Delta(#eta)"}; +auto static constexpr KminCharge = 3.f; +auto static constexpr KminPtCut = 0.1f; +auto static constexpr KnItsLayers = 7; struct HeavyionMultiplicity { @@ -229,7 +257,7 @@ struct HeavyionMultiplicity { auto* x2 = htrack->GetAxis(1); x2->SetBinLabel(1, "All tracks"); x2->SetBinLabel(2, "Non-fake tracks"); - for (int i = 0; i < kNItslayers; i++) { + for (int i = 0; i < KnItsLayers; i++) { x2->SetBinLabel(i + 3, Form("layer %d", i)); } } @@ -293,6 +321,22 @@ struct HeavyionMultiplicity { histos.add("hgendndetaVscentBeforeEvtSel", "hgendndetaBeforeEvtSel vs centrality", kTH2F, {axisEta, impactParAxis}); histos.add("hgendndetaVscentAfterEvtSel", "hgendndetaAfterEvtSel vs centrality", kTH2F, {axisEta, impactParAxis}); } + + if (doprocessMCeff) { + histos.add("hGenMCvertexZ", "hGenMCvertexZ", kTH1D, {axisVtxZ}, false); + histos.add("hGenMCvtxzcent", "hGenMCvtxzcent", kTH3D, {axisVtxZ, centAxis, axisOccupancy}, false); + histos.add("hGenMCAssoRecvertexZ", "hGenMCAssoRecvertexZ", kTH1D, {axisVtxZ}, false); + histos.add("hGenMCAssoRecvtxzcent", "hGenMCAssoRecvtxzcent", kTH3D, {axisVtxZ, centAxis, axisOccupancy}, false); + histos.add("hGenMCdndeta", "hGenMCdndeta", kTHnSparseD, {axisVtxZ, centAxis, axisOccupancy, axisEta, axisPhi}, false); + histos.add("hGenMCAssoRecdndeta", "hGenMCAssoRecdndeta", kTHnSparseD, {axisVtxZ, centAxis, axisOccupancy, axisEta, axisPhi, axisGenTrkType, axisGenPtVary}, false); + + histos.add("hRecMCvertexZ", "hRecMCvertexZ", kTH1D, {axisVtxZ}, false); + histos.add("hRecMCvtxzcent", "hRecMCvtxzcent", kTH3D, {axisVtxZ, centAxis, axisOccupancy}, false); + histos.add("hRecMCcentrality", "hRecMCcentrality", kTH1D, {axisCent}, false); + histos.add("hRecMCphivseta", "hRecMCphivseta", kTH2D, {axisPhi2, axisEta}, false); + histos.add("hRecMCdndeta", "hRecMCdndeta", kTHnSparseD, {axisVtxZ, centAxis, axisOccupancy, axisEta, axisPhi, axisRecTrkType}, false); + histos.add("etaResolution", "etaResolution", kTH2D, {axisEta, axisDeltaEta}); + } } template @@ -402,7 +446,7 @@ struct HeavyionMultiplicity { if (pdgTrack == nullptr) { return false; } - if (std::abs(pdgTrack->Charge()) < kMinCharge) { + if (std::abs(pdgTrack->Charge()) < KminCharge) { return false; } if (std::abs(track.eta()) >= etaRange) { @@ -543,7 +587,7 @@ struct HeavyionMultiplicity { continue; } histos.fill(HIST("hmcgendndeta"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(kSpAll), kNoGenpTVar); - if (particle.pt() < kMinpTcut) { + if (particle.pt() < KminPtCut) { histos.fill(HIST("hmcgendndeta"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTup, -10.0 * particle.pt() + 2); histos.fill(HIST("hmcgendndeta"), RecCol.posZ(), selColCent(RecCol), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTdown, 5.0 * particle.pt() + 0.5); } else { @@ -607,7 +651,7 @@ struct HeavyionMultiplicity { continue; } histos.fill(HIST("hmcgendndpt"), selColCent(RecCol), particle.pt(), kNoGenpTVar); - if (particle.pt() < kMinpTcut) { + if (particle.pt() < KminPtCut) { histos.fill(HIST("hmcgendndpt"), selColCent(RecCol), particle.pt(), kGenpTup, -10.0 * particle.pt() + 2); histos.fill(HIST("hmcgendndpt"), selColCent(RecCol), particle.pt(), kGenpTdown, 5.0 * particle.pt() + 0.5); } else { @@ -641,7 +685,7 @@ struct HeavyionMultiplicity { } histos.fill(HIST("hTracksCount"), selColCent(RecCol), 1); bool isFakeItsTracks = false; - for (int i = 0; i < kNItslayers; i++) { + for (int i = 0; i < KnItsLayers; i++) { if (Rectrack.mcMask() & 1 << i) { isFakeItsTracks = true; histos.fill(HIST("hTracksCount"), selColCent(RecCol), i + 3); @@ -793,7 +837,7 @@ struct HeavyionMultiplicity { continue; } histos.fill(HIST("hmcgendndetapp"), RecCol.posZ(), RecCol.centFT0M(), particle.eta(), particle.phi(), static_cast(kSpAll), kNoGenpTVar); - if (particle.pt() < kMinpTcut) { + if (particle.pt() < KminPtCut) { histos.fill(HIST("hmcgendndetapp"), RecCol.posZ(), RecCol.centFT0M(), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTup, -10.0 * particle.pt() + 2); histos.fill(HIST("hmcgendndetapp"), RecCol.posZ(), RecCol.centFT0M(), particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTdown, 5.0 * particle.pt() + 0.5); } else { @@ -916,6 +960,125 @@ struct HeavyionMultiplicity { } } + void processMCeff(soa::Join::iterator const& mcCollision, CollisionMCRecTable const& RecCols, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) + { + auto gencent = -999; + auto genoccu = -999; + bool atLeastOne = false; + + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + if (RecCol.globalIndex() != mcCollision.bestCollisionIndex()) { + continue; + } + atLeastOne = true; + gencent = selColCent(RecCol); + genoccu = selColOccu(RecCol); + } + + histos.fill(HIST("hGenMCvertexZ"), mcCollision.posZ()); + histos.fill(HIST("hGenMCvtxzcent"), mcCollision.posZ(), gencent, genoccu); + + if (atLeastOne) { + histos.fill(HIST("hGenMCAssoRecvertexZ"), mcCollision.posZ()); + histos.fill(HIST("hGenMCAssoRecvtxzcent"), mcCollision.posZ(), gencent, genoccu); + } + + for (const auto& particle : GenParticles) { + if (!isGenTrackSelected(particle)) { + continue; + } + histos.fill(HIST("hGenMCdndeta"), mcCollision.posZ(), gencent, genoccu, particle.eta(), particle.phi()); + if (atLeastOne) { + histos.fill(HIST("hGenMCAssoRecdndeta"), mcCollision.posZ(), gencent, genoccu, particle.eta(), particle.phi(), static_cast(kGenAll), kNoGenpTVar); + if (particle.pt() < KminPtCut) { + histos.fill(HIST("hGenMCAssoRecdndeta"), mcCollision.posZ(), gencent, genoccu, particle.eta(), particle.phi(), static_cast(kGenAll), kGenpTup, -10.0 * particle.pt() + 2); + histos.fill(HIST("hGenMCAssoRecdndeta"), mcCollision.posZ(), gencent, genoccu, particle.eta(), particle.phi(), static_cast(kGenAll), kGenpTdown, 5.0 * particle.pt() + 0.5); + } else { + histos.fill(HIST("hGenMCAssoRecdndeta"), mcCollision.posZ(), gencent, genoccu, particle.eta(), particle.phi(), static_cast(kSpAll), kGenpTup); + histos.fill(HIST("hGenMCAssoRecdndeta"), mcCollision.posZ(), gencent, genoccu, particle.eta(), particle.phi(), static_cast(kGenAll), kGenpTdown); + } + int pid = 0; + switch (std::abs(particle.pdgCode())) { + case PDG_t::kPiPlus: + pid = kGenPion; + break; + case PDG_t::kKPlus: + pid = kGenKaon; + break; + case PDG_t::kProton: + pid = kGenProton; + break; + default: + pid = kGenOther; + break; + } + histos.fill(HIST("hGenMCAssoRecdndeta"), mcCollision.posZ(), gencent, genoccu, particle.eta(), particle.phi(), static_cast(pid), kNoGenpTVar); + } // Associated with reco col + } // track (mcgen) loop + + for (const auto& RecCol : RecCols) { + if (!isEventSelected(RecCol)) { + continue; + } + if (RecCol.globalIndex() != mcCollision.bestCollisionIndex()) { + continue; + } + histos.fill(HIST("hRecMCvertexZ"), RecCol.posZ()); + histos.fill(HIST("hRecMCcentrality"), selColCent(RecCol)); + histos.fill(HIST("hRecMCvtxzcent"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol)); + + auto recTracksPart = RecTracks.sliceBy(perCollision, RecCol.globalIndex()); + std::vector mclabels; + for (const auto& Rectrack : recTracksPart) { + if (!isTrackSelected(Rectrack)) { + continue; + } + histos.fill(HIST("hRecMCphivseta"), Rectrack.phi(), Rectrack.eta()); + histos.fill(HIST("hRecMCdndeta"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol), Rectrack.eta(), Rectrack.phi(), static_cast(kRecoAll)); + if (Rectrack.has_mcParticle()) { + int pid = 0; + auto mcpart = Rectrack.mcParticle(); + histos.fill(HIST("etaResolution"), Rectrack.eta(), Rectrack.eta() - mcpart.eta()); + if (mcpart.isPhysicalPrimary()) { + pid = kRecoPrimary; + switch (std::abs(mcpart.pdgCode())) { + case PDG_t::kPiPlus: + pid = kRecoPion; + break; + case PDG_t::kKPlus: + pid = kRecoKaon; + break; + case PDG_t::kProton: + pid = kRecoProton; + break; + default: + pid = kRecoOther; + break; + } + } else { + pid = kRecoSecondary; + } + if (mcpart.has_mothers()) { + auto mcpartMother = mcpart.template mothers_as().front(); + if (mcpartMother.pdgCode() == PDG_t::kK0Short || std::abs(mcpartMother.pdgCode()) == PDG_t::kLambda0) { + pid = kRecoWeakDecay; + } + } + if (find(mclabels.begin(), mclabels.end(), Rectrack.mcParticleId()) != mclabels.end()) { + pid = kRecoFake; + } + mclabels.push_back(Rectrack.mcParticleId()); + histos.fill(HIST("hRecMCdndeta"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol), mcpart.eta(), mcpart.phi(), static_cast(pid)); + } else { + histos.fill(HIST("hRecMCdndeta"), RecCol.posZ(), selColCent(RecCol), selColOccu(RecCol), Rectrack.eta(), Rectrack.phi(), static_cast(kRecoBkg)); + } + } // track (mcrec) loop + } // collision loop + } + PROCESS_SWITCH(HeavyionMultiplicity, processData, "process data CentFT0C", false); PROCESS_SWITCH(HeavyionMultiplicity, processCorrelation, "do correlation study in data", false); PROCESS_SWITCH(HeavyionMultiplicity, processMonteCarlo, "process MC CentFT0C", false); @@ -926,6 +1089,7 @@ struct HeavyionMultiplicity { PROCESS_SWITCH(HeavyionMultiplicity, processppMonteCarlo, "process pp MC", false); PROCESS_SWITCH(HeavyionMultiplicity, processGen, "process pure MC gen", false); PROCESS_SWITCH(HeavyionMultiplicity, processEvtLossSigLossMC, "process Signal Loss, Event Loss", false); + PROCESS_SWITCH(HeavyionMultiplicity, processMCeff, "process extra efficiency function", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) From 5047346c2db59768f9ba93a66a1d9e12f9696eb9 Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Fri, 14 Nov 2025 00:46:03 +0100 Subject: [PATCH 34/48] [PWGCF] Update: PWGCF/EbyEFluctuations/Tasks/PartNumFluc.cxx (#13804) --- PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx | 1655 ++++++++++-------- 1 file changed, 935 insertions(+), 720 deletions(-) diff --git a/PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx b/PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx index 481c16388a7..80b033234d7 100644 --- a/PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx @@ -442,19 +442,44 @@ class FluctuationCalculatorTrack std::array mQs; }; -struct QuantityHolderEvent { +struct HolderCcdb { + std::vector runNumbers; + std::vector runNumbersBad; + + std::vector pCentralityPtEtaEfficiencyTpcPiP; + std::vector pCentralityPtEtaEfficiencyTpcPiM; + std::vector pCentralityPtEtaEfficiencyTpcKaP; + std::vector pCentralityPtEtaEfficiencyTpcKaM; + std::vector pCentralityPtEtaEfficiencyTpcPrP; + std::vector pCentralityPtEtaEfficiencyTpcPrM; + std::vector pCentralityPtEtaEfficiencyTpcTofPiP; + std::vector pCentralityPtEtaEfficiencyTpcTofPiM; + std::vector pCentralityPtEtaEfficiencyTpcTofKaP; + std::vector pCentralityPtEtaEfficiencyTpcTofKaM; + std::vector pCentralityPtEtaEfficiencyTpcTofPrP; + std::vector pCentralityPtEtaEfficiencyTpcTofPrM; +}; + +struct HolderEvent { std::int32_t runNumber = 0; std::int32_t runIndex = 0; + double vz = 0.; + std::int32_t vzBinIndex = 0; std::int32_t nGlobalTracks = 0; std::int32_t nPvContributors = 0; - std::int32_t nTofBeta = 0; double meanDcaXy = 0.; double meanSquareDcaXy = 0.; double meanDcaZ = 0.; double meanSquareDcaZ = 0.; - double vz = 0.; + std::int32_t nTofBeta = 0; double centrality = 0.; std::int32_t subgroupIndex = 0; + std::int32_t nChPGenerated = 0; + std::int32_t nChMGenerated = 0; + std::int32_t nKaPGenerated = 0; + std::int32_t nKaMGenerated = 0; + std::int32_t nPrPGenerated = 0; + std::int32_t nPrMGenerated = 0; std::int32_t nChP = 0; std::int32_t nChM = 0; std::int32_t nKaP = 0; @@ -476,9 +501,31 @@ struct QuantityHolderEvent { void clear() { - runNumber = runIndex = nGlobalTracks = nPvContributors = nTofBeta = 0; - meanDcaXy = meanSquareDcaXy = meanDcaZ = meanSquareDcaZ = vz = centrality = 0.; - subgroupIndex = nChP = nChM = nKaP = nKaM = nPrP = nPrM = 0; + runNumber = 0; + runIndex = 0; + vz = 0.; + vzBinIndex = 0; + nGlobalTracks = 0; + nPvContributors = 0; + meanDcaXy = 0.; + meanSquareDcaXy = 0.; + meanDcaZ = 0.; + meanSquareDcaZ = 0.; + nTofBeta = 0; + centrality = 0.; + subgroupIndex = 0; + nChPGenerated = 0; + nChMGenerated = 0; + nKaPGenerated = 0; + nKaMGenerated = 0; + nPrPGenerated = 0; + nPrMGenerated = 0; + nChP = 0; + nChM = 0; + nKaP = 0; + nKaM = 0; + nPrP = 0; + nPrM = 0; mcParticleIndicesMatchedTpcPiP.clear(); mcParticleIndicesMatchedTpcPiM.clear(); mcParticleIndicesMatchedTpcKaP.clear(); @@ -494,7 +541,7 @@ struct QuantityHolderEvent { } }; -struct QuantityHolderTrack { +struct HolderTrack { static constexpr double TruncationAbsNSigmaPid = 999.; static constexpr double truncateNSigmaPid(const double value) { return (!(std::abs(value) < TruncationAbsNSigmaPid) ? -TruncationAbsNSigmaPid : value); } @@ -523,16 +570,30 @@ struct QuantityHolderTrack { void clear() { sign = 0; - pt = eta = phi = ptOverQ = pOverQ = rapidityPi = rapidityKa = rapidityPr = 0.; + pt = 0.; + eta = 0.; + phi = 0.; + ptOverQ = 0.; + pOverQ = 0.; + rapidityPi = 0.; + rapidityKa = 0.; + rapidityPr = 0.; hasTpcPid = false; - tpcNSigmaPi = tpcNSigmaKa = tpcNSigmaPr = 0.; + tpcNSigmaPi = 0.; + tpcNSigmaKa = 0.; + tpcNSigmaPr = 0.; hasTofPid = false; - tofNSigmaPi = tofNSigmaKa = tofNSigmaPr = tpcTofNSigmaPi = tpcTofNSigmaKa = tpcTofNSigmaPr = 0.; + tofNSigmaPi = 0.; + tofNSigmaKa = 0.; + tofNSigmaPr = 0.; + tpcTofNSigmaPi = 0.; + tpcTofNSigmaKa = 0.; + tpcTofNSigmaPr = 0.; mcParticleId = 0; } }; -struct QuantityHolderMcParticle { +struct HolderMcParticle { std::int32_t globalIndex = 0; std::int32_t pdgCode = 0; double pt = 0.; @@ -540,12 +601,20 @@ struct QuantityHolderMcParticle { void clear() { - globalIndex = pdgCode = 0; - pt = eta = 0.; + globalIndex = 0; + pdgCode = 0; + pt = 0.; + eta = 0.; } }; struct PartNumFluc { + enum class CentralityDefinitionIndices { kFV0A = 0, + kFT0M, + kFT0A, + kFT0C, + kNIndices }; + Configurable cfgCcdbPath{"cfgCcdbPath", "Users/f/fasi/test", "Path in CCDB"}; Configurable cfgFlagQaRun{"cfgFlagQaRun", false, "Run QA flag"}; @@ -554,19 +623,21 @@ struct PartNumFluc { Configurable cfgFlagQaTrack{"cfgFlagQaTrack", false, "Track QA flag"}; Configurable cfgFlagQaAcceptance{"cfgFlagQaAcceptance", false, "Acceptance QA flag"}; Configurable cfgFlagQaPid{"cfgFlagQaPid", false, "PID QA flag"}; - Configurable cfgFlagAnalysisFluctuationCh{"cfgFlagAnalysisFluctuationCh", false, "Charge number fLuctuation analysis flag"}; - Configurable cfgFlagAnalysisFluctuationKa{"cfgFlagAnalysisFluctuationKa", false, "Kaon number fLuctuation analysis flag"}; - Configurable cfgFlagAnalysisFluctuationPr{"cfgFlagAnalysisFluctuationPr", false, "(Anti)proton number fLuctuation analysis flag"}; Configurable cfgFlagCalculationPurityPi{"cfgFlagCalculationPurityPi", false, "Pion purity calculation flag"}; Configurable cfgFlagCalculationPurityKa{"cfgFlagCalculationPurityKa", false, "Kaon purity calculation flag"}; Configurable cfgFlagCalculationPurityPr{"cfgFlagCalculationPurityPr", false, "(Anti)proton purity calculation flag"}; Configurable cfgFlagCalculationEfficiencyPi{"cfgFlagCalculationEfficiencyPi", false, "Pion efficiency calculation flag"}; Configurable cfgFlagCalculationEfficiencyKa{"cfgFlagCalculationEfficiencyKa", false, "Kaon efficiency calculation flag"}; Configurable cfgFlagCalculationEfficiencyPr{"cfgFlagCalculationEfficiencyPr", false, "(Anti)proton efficiency calculation flag"}; + Configurable cfgFlagCalculationFluctuationCh{"cfgFlagCalculationFluctuationCh", false, "Charge number fluctuation calculation flag"}; + Configurable cfgFlagCalculationFluctuationKa{"cfgFlagCalculationFluctuationKa", false, "Kaon number fluctuation calculation flag"}; + Configurable cfgFlagCalculationFluctuationPr{"cfgFlagCalculationFluctuationPr", false, "(Anti)proton number fluctuation calculation flag"}; + Configurable cfgFlagRejectionRunBad{"cfgFlagRejectionRunBad", true, "Bad run rejection flag"}; Configurable cfgFlagSelectionEvent{"cfgFlagSelectionEvent", 0b00000000001111110100000000000000000000000000000000ULL, "Event selection flag"}; Configurable cfgCutMaxAbsVertexZ{"cfgCutMaxAbsVertexZ", 6., "Maximum absolute vertex z position (cm)"}; - Configurable cfgCutMinNPvContributorsDeviation{"cfgCutMinNPvContributorsDeviation", -4, "Minimum nPvContributors deviation from nGlobalTracks"}; + Configurable cfgCutMinDeviationNPvContributors{"cfgCutMinDeviationNPvContributors", -4, "Minimum nPvContributors deviation from nGlobalTracks"}; + Configurable cfgIndexDefinitionCentrality{"cfgIndexDefinitionCentrality", 1, "Centrality definition index"}; Configurable cfgFlagPvContributor{"cfgFlagPvContributor", true, "Flag of requiring PV contributor"}; Configurable cfgCutMinItsNCls{"cfgCutMinItsNCls", 5, "Minimum number of clusters ITS"}; @@ -587,30 +658,28 @@ struct PartNumFluc { Configurable cfgThresholdPtTofPr{"cfgThresholdPtTofPr", 0.8, "pT (GeV/c) threshold for TOF (anti)protons"}; Configurable cfgCutMaxAbsNSigmaPid{"cfgCutMaxAbsNSigmaPid", 2., "Maximum absolute nSigma for PID"}; // 1.5, 2.5 - Configurable cfgNCentralityBins{"cfgNCentralityBins", 20, "Number of centrality bins in fluctuation analysis"}; - Configurable cfgNSubgroups{"cfgNSubgroups", 20, "Number of subgroups in fluctuation analysis"}; + Configurable cfgNCentralityBins{"cfgNCentralityBins", 20, "Number of centrality bins in fluctuation calculation"}; + Configurable cfgNSubgroups{"cfgNSubgroups", 20, "Number of subgroups in fluctuation calculation"}; Service ccdb; - std::vector runNumbers; - std::vector runNumbersBad; - - const TProfile3D* pVzPtEtaEfficiencyTpcPiP = nullptr; - const TProfile3D* pVzPtEtaEfficiencyTpcPiM = nullptr; - const TProfile3D* pVzPtEtaEfficiencyTpcKaP = nullptr; - const TProfile3D* pVzPtEtaEfficiencyTpcKaM = nullptr; - const TProfile3D* pVzPtEtaEfficiencyTpcPrP = nullptr; - const TProfile3D* pVzPtEtaEfficiencyTpcPrM = nullptr; - const TProfile3D* pVzPtEtaEfficiencyTpcTofPiP = nullptr; - const TProfile3D* pVzPtEtaEfficiencyTpcTofPiM = nullptr; - const TProfile3D* pVzPtEtaEfficiencyTpcTofKaP = nullptr; - const TProfile3D* pVzPtEtaEfficiencyTpcTofKaM = nullptr; - const TProfile3D* pVzPtEtaEfficiencyTpcTofPrP = nullptr; - const TProfile3D* pVzPtEtaEfficiencyTpcTofPrM = nullptr; - - QuantityHolderEvent quantityHolderEvent; - QuantityHolderTrack quantityHolderTrack; - QuantityHolderMcParticle quantityHolderMcParticle; + HolderCcdb holderCcdb; + HolderEvent holderEvent; + HolderTrack holderTrack; + HolderMcParticle holderMcParticle; + + std::vector> pCentralityPtEtaEfficiencyTpcPiP; + std::vector> pCentralityPtEtaEfficiencyTpcPiM; + std::vector> pCentralityPtEtaEfficiencyTpcKaP; + std::vector> pCentralityPtEtaEfficiencyTpcKaM; + std::vector> pCentralityPtEtaEfficiencyTpcPrP; + std::vector> pCentralityPtEtaEfficiencyTpcPrM; + std::vector> pCentralityPtEtaEfficiencyTpcTofPiP; + std::vector> pCentralityPtEtaEfficiencyTpcTofPiM; + std::vector> pCentralityPtEtaEfficiencyTpcTofKaP; + std::vector> pCentralityPtEtaEfficiencyTpcTofKaM; + std::vector> pCentralityPtEtaEfficiencyTpcTofPrP; + std::vector> pCentralityPtEtaEfficiencyTpcTofPrM; std::unique_ptr fluctuationCalculatorTrackChP; std::unique_ptr fluctuationCalculatorTrackChM; @@ -625,9 +694,9 @@ struct PartNumFluc { std::unique_ptr fluctuationCalculatorTrackPrT; std::unique_ptr fluctuationCalculatorTrackPrN; + HistogramRegistry hrCalculationFluctuation{"hrCalculationFluctuation", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry hrCalculationEfficiency{"hrCalculationEfficiency", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry hrCalculationPurity{"hrCalculationPurity", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry hrAnalysisFluctuation{"hrAnalysisFluctuation", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry hrQaAcceptance{"hrQaAcceptance", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry hrQaPid{"hrQaPid", {}, OutputObjHandlingPolicy::AnalysisObject}; HistogramRegistry hrQaTrack{"hrQaTrack", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -642,8 +711,122 @@ struct PartNumFluc { Preslice presliceTracksPerCollision = aod::track::collisionId; + template + void initCalculationFluctuation(const TList* const ccdbObject) + { + HistogramConfigSpec hcsCalculationFluctuation(HistType::kTH3F, {{cfgNCentralityBins.value, 0., 100., "Centrality (%)"}, {50, -0.5, 49.5}, {50, -0.5, 49.5}}); + HistogramConfigSpec hcsFluctuationCalculator(HistType::kTH3D, {{cfgNCentralityBins.value, 0., 100., "Centrality (%)"}, {cfgNSubgroups.value, -0.5, cfgNSubgroups.value - 0.5, "Subgroup Index"}, {fluctuation_calculator_base::NOrderVectors, -0.5, fluctuation_calculator_base::NOrderVectors - 0.5, "Order Vector Index"}}); + + if (cfgFlagCalculationFluctuationCh.value) { + holderCcdb.pCentralityPtEtaEfficiencyTpcPiP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcPiM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + for (std::int32_t const& iVzBin : std::views::iota(0, static_cast(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2))) { + holderCcdb.pCentralityPtEtaEfficiencyTpcPiP[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcPiP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcPiP[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcPiP[iVzBin]->IsA() == TProfile3D::Class()); + holderCcdb.pCentralityPtEtaEfficiencyTpcPiM[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcPiM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcPiM[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcPiM[iVzBin]->IsA() == TProfile3D::Class()); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiP[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcTofPiP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiP[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiP[iVzBin]->IsA() == TProfile3D::Class()); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiM[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcTofPiM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiM[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiM[iVzBin]->IsA() == TProfile3D::Class()); + } + } + + if (cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value) { + holderCcdb.pCentralityPtEtaEfficiencyTpcKaP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcKaM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + for (std::int32_t const& iVzBin : std::views::iota(0, static_cast(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2))) { + holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcKaP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[iVzBin]->IsA() == TProfile3D::Class()); + holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcKaM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[iVzBin]->IsA() == TProfile3D::Class()); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcTofKaP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[iVzBin]->IsA() == TProfile3D::Class()); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcTofKaM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[iVzBin]->IsA() == TProfile3D::Class()); + } + } + + if (cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationPr.value) { + holderCcdb.pCentralityPtEtaEfficiencyTpcPrP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcPrM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + for (std::int32_t const& iVzBin : std::views::iota(0, static_cast(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2))) { + holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcPrP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[iVzBin]->IsA() == TProfile3D::Class()); + holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcPrM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[iVzBin]->IsA() == TProfile3D::Class()); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcTofPrP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[iVzBin]->IsA() == TProfile3D::Class()); + holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[iVzBin] = static_cast(ccdbObject->FindObject(Form("pCentralityPtEtaEfficiencyTpcTofPrM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1))); + assert(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[iVzBin] && holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[iVzBin]->IsA() == TProfile3D::Class()); + } + } + + if (cfgFlagCalculationFluctuationCh.value) { + LOG(info) << "Enabling charge number fluctuation calculation."; + + fluctuationCalculatorTrackChP = std::make_unique(); + fluctuationCalculatorTrackChM = std::make_unique(); + fluctuationCalculatorTrackChT = std::make_unique(); + fluctuationCalculatorTrackChN = std::make_unique(); + + if constexpr (doProcessingMc) { + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNChPNChM_generated", ";;No. of h^{+};No. of h^{#minus}", hcsCalculationFluctuation); + } + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNChPNChM", ";;No. of h^{+};No. of h^{#minus}", hcsCalculationFluctuation); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChP", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChM", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChT", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorChN", "", hcsFluctuationCalculator); + } + + if (cfgFlagCalculationFluctuationKa.value) { + LOG(info) << "Enabling kaon number fluctuation calculation."; + + fluctuationCalculatorTrackKaP = std::make_unique(); + fluctuationCalculatorTrackKaM = std::make_unique(); + fluctuationCalculatorTrackKaT = std::make_unique(); + fluctuationCalculatorTrackKaN = std::make_unique(); + + if constexpr (doProcessingMc) { + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNKaPNKaM_generated", ";;No. of K^{+};No. of K^{#minus}", hcsCalculationFluctuation); + } + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNKaPNKaM", ";;No. of K^{+};No. of K^{#minus}", hcsCalculationFluctuation); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaP", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaM", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaT", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorKaN", "", hcsFluctuationCalculator); + } + + if (cfgFlagCalculationFluctuationPr.value) { + LOG(info) << "Enabling (anti)proton number fluctuation calculation."; + + fluctuationCalculatorTrackPrP = std::make_unique(); + fluctuationCalculatorTrackPrM = std::make_unique(); + fluctuationCalculatorTrackPrT = std::make_unique(); + fluctuationCalculatorTrackPrN = std::make_unique(); + + if constexpr (doProcessingMc) { + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNPrPNPrM_generated", ";;No. of p;No. of #bar{p}", hcsCalculationFluctuation); + } + hrCalculationFluctuation.add("CalculationFluctuation/hCentralityNPrPNPrM", ";;No. of p;No. of #bar{p}", hcsCalculationFluctuation); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrP", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrM", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrT", "", hcsFluctuationCalculator); + hrCalculationFluctuation.add("CalculationFluctuation/hFluctuationCalculatorPrN", "", hcsFluctuationCalculator); + } + } + void init(InitContext&) { + gRandom->SetSeed(0); + assert(doprocessRaw ^ doprocessMc); ccdb->setURL("https://alice-ccdb.cern.ch"); @@ -656,22 +839,24 @@ struct PartNumFluc { const TGraph* const gRunNumberIsBad = static_cast(ccdbObject->FindObject("gRunNumberIsBad")); assert(gRunNumberIsBad && gRunNumberIsBad->IsA() == TGraph::Class()); - runNumbers.reserve(gRunNumberIsBad->GetN()); - runNumbersBad.reserve(gRunNumberIsBad->GetN()); + holderCcdb.runNumbers.reserve(gRunNumberIsBad->GetN()); + holderCcdb.runNumbersBad.reserve(gRunNumberIsBad->GetN()); for (std::int32_t const& iRun : std::views::iota(0, gRunNumberIsBad->GetN())) { - runNumbers.push_back(static_cast(std::llrint(gRunNumberIsBad->GetX()[iRun]))); - if (gRunNumberIsBad->GetY()[iRun]) { - runNumbersBad.push_back(static_cast(std::llrint(gRunNumberIsBad->GetX()[iRun]))); + holderCcdb.runNumbers.push_back(static_cast(std::llrint(gRunNumberIsBad->GetX()[iRun]))); + if (cfgFlagRejectionRunBad.value && gRunNumberIsBad->GetY()[iRun]) { + holderCcdb.runNumbersBad.push_back(static_cast(std::llrint(gRunNumberIsBad->GetX()[iRun]))); } } - hrCounter.add("hNEvents", ";;No. of Events", {HistType::kTH1D, {{10 + aod::evsel::kNsel, -0.5, 9.5 + static_cast(aod::evsel::kNsel), "Selection"}}}); + hrCounter.add("hNEvents", ";;No. of Events", {HistType::kTH1D, {{10 + aod::evsel::EventSelectionFlags::kNsel, -0.5, 9.5 + static_cast(aod::evsel::EventSelectionFlags::kNsel), "Selection"}}}); if (doprocessRaw) { + LOG(info) << "Enabling raw data process."; + if (cfgFlagQaRun.value) { LOG(info) << "Enabling run QA."; - HistogramConfigSpec hcsQaRun(HistType::kTProfile, {{static_cast(runNumbers.size()), -0.5, runNumbers.size() - 0.5, "Run Index"}}); + HistogramConfigSpec hcsQaRun(HistType::kTProfile, {{static_cast(holderCcdb.runNumbers.size()), -0.5, holderCcdb.runNumbers.size() - 0.5, "Run Index"}}); hrQaRun.add("QaRun/pRunIndexVx", ";;#LT#it{V}_{#it{x}}#GT (cm)", hcsQaRun); hrQaRun.add("QaRun/pRunIndexVy", ";;#LT#it{V}_{#it{y}}#GT (cm)", hcsQaRun); hrQaRun.add("QaRun/pRunIndexVz", ";;#LT#it{V}_{#it{z}}#GT (cm)", hcsQaRun); @@ -680,11 +865,11 @@ struct PartNumFluc { hrQaRun.add("QaRun/pRunIndexMultFt0c", ";;FT0C #LTMultiplicity#GT", hcsQaRun); hrQaRun.add("QaRun/pRunIndexNGlobalTracks", ";;#LTnGlobalTracks#GT", hcsQaRun); hrQaRun.add("QaRun/pRunIndexNPvContributors", ";;#LTnPvContributors#GT", hcsQaRun); - hrQaRun.add("QaRun/pRunIndexNTofBeta", ";;#LTnTofBeta#GT", hcsQaRun); hrQaRun.add("QaRun/pRunIndexMeanDcaXy", ";;#LT#LTDCA_{#it{xy}}#GT_{event}#GT (cm)", hcsQaRun); hrQaRun.add("QaRun/pRunIndexSigmaDcaXy", ";;#LT#it{#sigma}(DCA_{#it{xy}})_{event}#GT (cm)", hcsQaRun); hrQaRun.add("QaRun/pRunIndexMeanDcaZ", ";;#LT#LTDCA_{#it{z}}#GT_{event}#GT (cm)", hcsQaRun); hrQaRun.add("QaRun/pRunIndexSigmaDcaZ", ";;#LT#it{#sigma}(DCA_{#it{z}})_{event}#GT (cm)", hcsQaRun); + hrQaRun.add("QaRun/pRunIndexNTofBeta", ";;#LTnTofBeta#GT", hcsQaRun); hrQaRun.add("QaRun/pRunIndexItsNCls", ";;ITS #LTnClusters#GT", hcsQaRun); hrQaRun.add("QaRun/pRunIndexItsChi2NCls", ";;ITS #LT#it{#chi}^{2}/nClusters#GT", hcsQaRun); hrQaRun.add("QaRun/pRunIndexTpcNCls", ";;TPC #LTnClusters#GT", hcsQaRun); @@ -710,16 +895,17 @@ struct PartNumFluc { if (cfgFlagQaEvent.value) { LOG(info) << "Enabling event QA."; - AxisSpec asRunIndex(static_cast(runNumbers.size()), -0.5, runNumbers.size() - 0.5, "Run Index"); + AxisSpec asRunIndex(static_cast(holderCcdb.runNumbers.size()), -0.5, holderCcdb.runNumbers.size() - 0.5, "Run Index"); AxisSpec asNGlobalTracks(180, -0.5, 179.5, "nGlobalTracks"); hrQaEvent.add("QaEvent/hRunIndexVxVy", "", {HistType::kTHnSparseF, {asRunIndex, {150, -0.15, 0.15, "#it{V}_{#it{x}} (cm)"}, {150, -0.15, 0.15, "#it{V}_{#it{y}} (cm)"}}}); hrQaEvent.add("QaEvent/hRunIndexVz", "", {HistType::kTH2F, {asRunIndex, {300, -15., 15., "#it{V}_{#it{z}} (cm)"}}}); - hrQaEvent.add("QaEvent/hRunIndexNTofBetaNGlobalTracks", "", {HistType::kTHnSparseF, {asRunIndex, {60, -0.5, 59.5, "nTofBeta"}, asNGlobalTracks}}); hrQaEvent.add("QaEvent/hRunIndexNPvContributorsNGlobalTracks", "", {HistType::kTHnSparseF, {asRunIndex, {180, -0.5, 179.5, "nPvContributors"}, asNGlobalTracks}}); hrQaEvent.add("QaEvent/hRunIndexNGlobalTracksMeanDcaXy", "", {HistType::kTHnSparseF, {asRunIndex, asNGlobalTracks, {200, -0.5, 0.5, "#LTDCA_{#it{xy}}#GT_{event} (cm)"}}}); hrQaEvent.add("QaEvent/hRunIndexNGlobalTracksMeanDcaXy_nPvContributorsCut", "", {HistType::kTHnSparseF, {asRunIndex, asNGlobalTracks, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); hrQaEvent.add("QaEvent/hRunIndexNGlobalTracksMeanDcaZ", "", {HistType::kTHnSparseF, {asRunIndex, asNGlobalTracks, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); hrQaEvent.add("QaEvent/hRunIndexNGlobalTracksMeanDcaZ_nPvContributorsCut", "", {HistType::kTHnSparseF, {asRunIndex, asNGlobalTracks, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); + hrQaEvent.add("QaEvent/hRunIndexNTofBetaNGlobalTracks", "", {HistType::kTHnSparseF, {asRunIndex, {60, -0.5, 59.5, "nTofBeta"}, asNGlobalTracks}}); + hrQaEvent.add("QaEvent/hRunIndexNTofBetaNGlobalTracks_nPvContributorsCut", "", {HistType::kTHnSparseF, {asRunIndex, {60, -0.5, 59.5, "nTofBeta"}, asNGlobalTracks}}); } if (cfgFlagQaCentrality.value) { @@ -768,300 +954,253 @@ struct PartNumFluc { if (cfgFlagQaPid.value) { LOG(info) << "Enabling PID QA."; - AxisSpec asPOverQ(140, -3.5, 3.5, "#it{p}/#it{q} (GeV/#it{c})"); + AxisSpec asQaCentrality(20, 0., 100., "Centrality (%)"); + AxisSpec asPOverQ(350, -3.5, 3.5, "#it{p}/#it{q} (GeV/#it{c})"); AxisSpec asPtOverQ(80, -2., 2., "#it{p}_{T}/#it{q} (GeV/#it{c})"); AxisSpec asEta(48, -1.2, 1.2, "#it{#eta}"); - HistogramConfigSpec hcsQaPid(HistType::kTH3F, {asPtOverQ, asEta, {200, -10., 10.}}); - hrQaPid.add("QaPid/hPOverQEtaTpcLnDeDx", "", {HistType::kTH3F, {asPOverQ, asEta, {240, 3., 9., "TPC ln(d#it{E}/d#it{x} (a.u.))"}}}); - hrQaPid.add("QaPid/hPtOverQEtaTpcNSigmaPi", ";;;TPC #it{n}#it{#sigma}_{#pi}", hcsQaPid); - hrQaPid.add("QaPid/hPtOverQEtaTpcNSigmaPi_tofPi", ";;;TPC #it{n}#it{#sigma}_{#pi}", hcsQaPid); - hrQaPid.add("QaPid/hPtOverQEtaTpcNSigmaKa", ";;;TPC #it{n}#it{#sigma}_{K}", hcsQaPid); - hrQaPid.add("QaPid/hPtOverQEtaTpcNSigmaKa_tofKa", ";;;TPC #it{n}#it{#sigma}_{K}", hcsQaPid); - hrQaPid.add("QaPid/hPtOverQEtaTpcNSigmaPr", ";;;TPC #it{n}#it{#sigma}_{p}", hcsQaPid); - hrQaPid.add("QaPid/hPtOverQEtaTpcNSigmaPr_tofPr", ";;;TPC #it{n}#it{#sigma}_{p}", hcsQaPid); - hrQaPid.add("QaPid/hPOverQEtaTofInverseBeta", "", {HistType::kTH3F, {asPOverQ, asEta, {120, 0.5, 3.5, "TOF 1/#it{#beta}"}}}); - hrQaPid.add("QaPid/hPtOverQEtaTofNSigmaPi_tpcPi", ";;;TOF #it{n}#it{#sigma}_{#pi}", hcsQaPid); - hrQaPid.add("QaPid/hPtOverQEtaTofNSigmaKa_tpcKa", ";;;TOF #it{n}#it{#sigma}_{K}", hcsQaPid); - hrQaPid.add("QaPid/hPtOverQEtaTofNSigmaPr_tpcPr", ";;;TOF #it{n}#it{#sigma}_{p}", hcsQaPid); - hrQaPid.add("QaPid/hPtOverQEtaTpcTofNSigmaPi", ";;;TPC-TOF #it{n}#it{#sigma}_{#pi}", hcsQaPid); - hrQaPid.add("QaPid/hPtOverQEtaTpcTofNSigmaKa", ";;;TPC-TOF #it{n}#it{#sigma}_{K}", hcsQaPid); - hrQaPid.add("QaPid/hPtOverQEtaTpcTofNSigmaPr", ";;;TPC-TOF #it{n}#it{#sigma}_{p}", hcsQaPid); + HistogramConfigSpec hcsQaPid(HistType::kTHnSparseF, {asQaCentrality, asPtOverQ, asEta, {200, -10., 10.}}); + hrQaPid.add("QaPid/hCentralityPOverQEtaTpcLnDeDx", "", {HistType::kTHnSparseF, {asQaCentrality, asPOverQ, asEta, {240, 3., 9., "TPC ln(d#it{E}/d#it{x} (a.u.))"}}}); + hrQaPid.add("QaPid/hCentralityPtOverQEtaTpcNSigmaPi_tofPi", ";;;TPC #it{n}#it{#sigma}_{#pi}", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtOverQEtaTpcNSigmaKa_tofKa", ";;;TPC #it{n}#it{#sigma}_{K}", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtOverQEtaTpcNSigmaPr_tofPr", ";;;TPC #it{n}#it{#sigma}_{p}", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPOverQEtaTofInverseBeta", "", {HistType::kTHnSparseF, {asQaCentrality, asPOverQ, asEta, {120, 0.5, 3.5, "TOF 1/#it{#beta}"}}}); + hrQaPid.add("QaPid/hCentralityPtOverQEtaTofNSigmaPi_tpcPi", ";;;TOF #it{n}#it{#sigma}_{#pi}", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtOverQEtaTofNSigmaKa_tpcKa", ";;;TOF #it{n}#it{#sigma}_{K}", hcsQaPid); + hrQaPid.add("QaPid/hCentralityPtOverQEtaTofNSigmaPr_tpcPr", ";;;TOF #it{n}#it{#sigma}_{p}", hcsQaPid); } - if (cfgFlagAnalysisFluctuationCh.value || cfgFlagAnalysisFluctuationKa.value || cfgFlagAnalysisFluctuationPr.value) { - gRandom->SetSeed(0); - - HistogramConfigSpec hcsAnalysisFluctuation(HistType::kTH3F, {{cfgNCentralityBins.value, 0., 100., "Centrality (%)"}, {60, -0.5, 59.5}, {60, -0.5, 59.5}}); - HistogramConfigSpec hcsFluctuationCalculator(HistType::kTH3D, {{cfgNCentralityBins.value, 0., 100., "Centrality (%)"}, {cfgNSubgroups.value, -0.5, cfgNSubgroups.value - 0.5, "Subgroup Index"}, {fluctuation_calculator_base::NOrderVectors, -0.5, fluctuation_calculator_base::NOrderVectors - 0.5, "Order Vector Index"}}); - - if (cfgFlagAnalysisFluctuationCh.value) { - pVzPtEtaEfficiencyTpcPiP = static_cast(ccdbObject->FindObject("pVzPtEtaEfficiencyTpcPiP")); - assert(pVzPtEtaEfficiencyTpcPiP && pVzPtEtaEfficiencyTpcPiP->IsA() == TProfile3D::Class()); - pVzPtEtaEfficiencyTpcPiM = static_cast(ccdbObject->FindObject("pVzPtEtaEfficiencyTpcPiM")); - assert(pVzPtEtaEfficiencyTpcPiM && pVzPtEtaEfficiencyTpcPiM->IsA() == TProfile3D::Class()); - pVzPtEtaEfficiencyTpcTofPiP = static_cast(ccdbObject->FindObject("pVzPtEtaEfficiencyTpcTofPiP")); - assert(pVzPtEtaEfficiencyTpcTofPiP && pVzPtEtaEfficiencyTpcTofPiP->IsA() == TProfile3D::Class()); - pVzPtEtaEfficiencyTpcTofPiM = static_cast(ccdbObject->FindObject("pVzPtEtaEfficiencyTpcTofPiM")); - assert(pVzPtEtaEfficiencyTpcTofPiM && pVzPtEtaEfficiencyTpcTofPiM->IsA() == TProfile3D::Class()); - } - - if (cfgFlagAnalysisFluctuationCh.value || cfgFlagAnalysisFluctuationKa.value) { - pVzPtEtaEfficiencyTpcKaP = static_cast(ccdbObject->FindObject("pVzPtEtaEfficiencyTpcKaP")); - assert(pVzPtEtaEfficiencyTpcKaP && pVzPtEtaEfficiencyTpcKaP->IsA() == TProfile3D::Class()); - pVzPtEtaEfficiencyTpcKaM = static_cast(ccdbObject->FindObject("pVzPtEtaEfficiencyTpcKaM")); - assert(pVzPtEtaEfficiencyTpcKaM && pVzPtEtaEfficiencyTpcKaM->IsA() == TProfile3D::Class()); - pVzPtEtaEfficiencyTpcTofKaP = static_cast(ccdbObject->FindObject("pVzPtEtaEfficiencyTpcTofKaP")); - assert(pVzPtEtaEfficiencyTpcTofKaP && pVzPtEtaEfficiencyTpcTofKaP->IsA() == TProfile3D::Class()); - pVzPtEtaEfficiencyTpcTofKaM = static_cast(ccdbObject->FindObject("pVzPtEtaEfficiencyTpcTofKaM")); - assert(pVzPtEtaEfficiencyTpcTofKaM && pVzPtEtaEfficiencyTpcTofKaM->IsA() == TProfile3D::Class()); - } - - if (cfgFlagAnalysisFluctuationCh.value || cfgFlagAnalysisFluctuationPr.value) { - pVzPtEtaEfficiencyTpcPrP = static_cast(ccdbObject->FindObject("pVzPtEtaEfficiencyTpcPrP")); - assert(pVzPtEtaEfficiencyTpcPrP && pVzPtEtaEfficiencyTpcPrP->IsA() == TProfile3D::Class()); - pVzPtEtaEfficiencyTpcPrM = static_cast(ccdbObject->FindObject("pVzPtEtaEfficiencyTpcPrM")); - assert(pVzPtEtaEfficiencyTpcPrM && pVzPtEtaEfficiencyTpcPrM->IsA() == TProfile3D::Class()); - pVzPtEtaEfficiencyTpcTofPrP = static_cast(ccdbObject->FindObject("pVzPtEtaEfficiencyTpcTofPrP")); - assert(pVzPtEtaEfficiencyTpcTofPrP && pVzPtEtaEfficiencyTpcTofPrP->IsA() == TProfile3D::Class()); - pVzPtEtaEfficiencyTpcTofPrM = static_cast(ccdbObject->FindObject("pVzPtEtaEfficiencyTpcTofPrM")); - assert(pVzPtEtaEfficiencyTpcTofPrM && pVzPtEtaEfficiencyTpcTofPrM->IsA() == TProfile3D::Class()); - } - - if (cfgFlagAnalysisFluctuationCh.value) { - LOG(info) << "Enabling charge number fluctuation analysis."; - - fluctuationCalculatorTrackChP = std::make_unique(); - fluctuationCalculatorTrackChM = std::make_unique(); - fluctuationCalculatorTrackChT = std::make_unique(); - fluctuationCalculatorTrackChN = std::make_unique(); - - hrAnalysisFluctuation.add("AnalysisFluctuation/hCentralityNChPNChM", ";;No. of h^{+};No. of h^{#minus}", hcsAnalysisFluctuation); - hrAnalysisFluctuation.add("AnalysisFluctuation/hFluctuationCalculatorChP", "", hcsFluctuationCalculator); - hrAnalysisFluctuation.add("AnalysisFluctuation/hFluctuationCalculatorChM", "", hcsFluctuationCalculator); - hrAnalysisFluctuation.add("AnalysisFluctuation/hFluctuationCalculatorChT", "", hcsFluctuationCalculator); - hrAnalysisFluctuation.add("AnalysisFluctuation/hFluctuationCalculatorChN", "", hcsFluctuationCalculator); - } - - if (cfgFlagAnalysisFluctuationKa.value) { - LOG(info) << "Enabling kaon number fluctuation analysis."; - - fluctuationCalculatorTrackKaP = std::make_unique(); - fluctuationCalculatorTrackKaM = std::make_unique(); - fluctuationCalculatorTrackKaT = std::make_unique(); - fluctuationCalculatorTrackKaN = std::make_unique(); - - hrAnalysisFluctuation.add("AnalysisFluctuation/hCentralityNKaPNKaM", ";;No. of K^{+};No. of K^{#minus}", hcsAnalysisFluctuation); - hrAnalysisFluctuation.add("AnalysisFluctuation/hFluctuationCalculatorKaP", "", hcsFluctuationCalculator); - hrAnalysisFluctuation.add("AnalysisFluctuation/hFluctuationCalculatorKaM", "", hcsFluctuationCalculator); - hrAnalysisFluctuation.add("AnalysisFluctuation/hFluctuationCalculatorKaT", "", hcsFluctuationCalculator); - hrAnalysisFluctuation.add("AnalysisFluctuation/hFluctuationCalculatorKaN", "", hcsFluctuationCalculator); - } - - if (cfgFlagAnalysisFluctuationPr.value) { - LOG(info) << "Enabling (anti)proton number fluctuation analysis."; - - fluctuationCalculatorTrackPrP = std::make_unique(); - fluctuationCalculatorTrackPrM = std::make_unique(); - fluctuationCalculatorTrackPrT = std::make_unique(); - fluctuationCalculatorTrackPrN = std::make_unique(); - - hrAnalysisFluctuation.add("AnalysisFluctuation/hCentralityNPrPNPrM", ";;No. of p;No. of #bar{p}", hcsAnalysisFluctuation); - hrAnalysisFluctuation.add("AnalysisFluctuation/hFluctuationCalculatorPrP", "", hcsFluctuationCalculator); - hrAnalysisFluctuation.add("AnalysisFluctuation/hFluctuationCalculatorPrM", "", hcsFluctuationCalculator); - hrAnalysisFluctuation.add("AnalysisFluctuation/hFluctuationCalculatorPrT", "", hcsFluctuationCalculator); - hrAnalysisFluctuation.add("AnalysisFluctuation/hFluctuationCalculatorPrN", "", hcsFluctuationCalculator); - } + if (cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value) { + initCalculationFluctuation(ccdbObject); } } else if (doprocessMc) { + LOG(info) << "Enabling MC data process."; + if (cfgFlagCalculationPurityPi.value || cfgFlagCalculationPurityKa.value || cfgFlagCalculationPurityPr.value) { - HistogramConfigSpec hcsCalculationPurity(HistType::kTProfile2D, {{20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {24, -1.2, 1.2, "#it{#eta}"}}); + HistogramConfigSpec hcsCalculationPurity(HistType::kTProfile3D, {{20, 0., 100., "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {24, -1.2, 1.2, "#it{#eta}"}}); if (cfgFlagCalculationPurityPi.value) { LOG(info) << "Enabling pion purity calculation."; - hrCalculationPurity.add("CalculationPurity/pPtEtaPurityTpcPiP", "", hcsCalculationPurity); - hrCalculationPurity.add("CalculationPurity/pPtEtaPurityTpcPiM", "", hcsCalculationPurity); - hrCalculationPurity.add("CalculationPurity/pPtEtaPurityTpcTofPiP", "", hcsCalculationPurity); - hrCalculationPurity.add("CalculationPurity/pPtEtaPurityTpcTofPiM", "", hcsCalculationPurity); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcPiP", "", hcsCalculationPurity); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcPiM", "", hcsCalculationPurity); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcTofPiP", "", hcsCalculationPurity); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcTofPiM", "", hcsCalculationPurity); } if (cfgFlagCalculationPurityKa.value) { LOG(info) << "Enabling kaon purity calculation."; - hrCalculationPurity.add("CalculationPurity/pPtEtaPurityTpcKaP", "", hcsCalculationPurity); - hrCalculationPurity.add("CalculationPurity/pPtEtaPurityTpcKaM", "", hcsCalculationPurity); - hrCalculationPurity.add("CalculationPurity/pPtEtaPurityTpcTofKaP", "", hcsCalculationPurity); - hrCalculationPurity.add("CalculationPurity/pPtEtaPurityTpcTofKaM", "", hcsCalculationPurity); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcKaP", "", hcsCalculationPurity); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcKaM", "", hcsCalculationPurity); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcTofKaP", "", hcsCalculationPurity); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcTofKaM", "", hcsCalculationPurity); } if (cfgFlagCalculationPurityPr.value) { LOG(info) << "Enabling (anti)proton purity calculation."; - hrCalculationPurity.add("CalculationPurity/pPtEtaPurityTpcPrP", "", hcsCalculationPurity); - hrCalculationPurity.add("CalculationPurity/pPtEtaPurityTpcPrM", "", hcsCalculationPurity); - hrCalculationPurity.add("CalculationPurity/pPtEtaPurityTpcTofPrP", "", hcsCalculationPurity); - hrCalculationPurity.add("CalculationPurity/pPtEtaPurityTpcTofPrM", "", hcsCalculationPurity); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcPrP", "", hcsCalculationPurity); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcPrM", "", hcsCalculationPurity); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcTofPrP", "", hcsCalculationPurity); + hrCalculationPurity.add("CalculationPurity/pCentralityPtEtaPurityTpcTofPrM", "", hcsCalculationPurity); } } if (cfgFlagCalculationEfficiencyPi.value || cfgFlagCalculationEfficiencyKa.value || cfgFlagCalculationEfficiencyPr.value) { - HistogramConfigSpec hcsCalculationEfficiency(HistType::kTProfile3D, {{static_cast(std::llrint(cfgCutMaxAbsVertexZ.value * 2.)), -cfgCutMaxAbsVertexZ.value, cfgCutMaxAbsVertexZ.value, "#it{V}_{#it{z}} (cm)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {24, -1.2, 1.2, "#it{#eta}"}}); + HistogramConfigSpec hcsCalculationEfficiency(HistType::kTProfile3D, {{20, 0., 100., "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {24, -1.2, 1.2, "#it{#eta}"}}); if (cfgFlagCalculationEfficiencyPi.value) { LOG(info) << "Enabling pion efficiency calculation."; - quantityHolderEvent.mcParticleIndicesMatchedTpcPiP.reserve(60); - quantityHolderEvent.mcParticleIndicesMatchedTpcPiM.reserve(60); - quantityHolderEvent.mcParticleIndicesMatchedTpcTofPiP.reserve(40); - quantityHolderEvent.mcParticleIndicesMatchedTpcTofPiM.reserve(40); - - hrCalculationEfficiency.add("CalculationEfficiency/pVzPtEtaEfficiencyTpcPiP", "", hcsCalculationEfficiency); - hrCalculationEfficiency.add("CalculationEfficiency/pVzPtEtaEfficiencyTpcPiM", "", hcsCalculationEfficiency); - hrCalculationEfficiency.add("CalculationEfficiency/pVzPtEtaEfficiencyTpcTofPiP", "", hcsCalculationEfficiency); - hrCalculationEfficiency.add("CalculationEfficiency/pVzPtEtaEfficiencyTpcTofPiM", "", hcsCalculationEfficiency); + holderEvent.mcParticleIndicesMatchedTpcPiP.reserve(60); + holderEvent.mcParticleIndicesMatchedTpcPiM.reserve(60); + holderEvent.mcParticleIndicesMatchedTpcTofPiP.reserve(40); + holderEvent.mcParticleIndicesMatchedTpcTofPiM.reserve(40); + + pCentralityPtEtaEfficiencyTpcPiP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcPiM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcTofPiP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcTofPiM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + for (std::int32_t const& iVzBin : std::views::iota(0, static_cast(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2))) { + pCentralityPtEtaEfficiencyTpcPiP[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcPiP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcPiM[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcPiM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcTofPiP[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcTofPiP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcTofPiM[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcTofPiM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + } } if (cfgFlagCalculationEfficiencyKa.value) { LOG(info) << "Enabling kaon efficiency calculation."; - quantityHolderEvent.mcParticleIndicesMatchedTpcKaP.reserve(30); - quantityHolderEvent.mcParticleIndicesMatchedTpcKaM.reserve(30); - quantityHolderEvent.mcParticleIndicesMatchedTpcTofKaP.reserve(20); - quantityHolderEvent.mcParticleIndicesMatchedTpcTofKaM.reserve(20); - - hrCalculationEfficiency.add("CalculationEfficiency/pVzPtEtaEfficiencyTpcKaP", "", hcsCalculationEfficiency); - hrCalculationEfficiency.add("CalculationEfficiency/pVzPtEtaEfficiencyTpcKaM", "", hcsCalculationEfficiency); - hrCalculationEfficiency.add("CalculationEfficiency/pVzPtEtaEfficiencyTpcTofKaP", "", hcsCalculationEfficiency); - hrCalculationEfficiency.add("CalculationEfficiency/pVzPtEtaEfficiencyTpcTofKaM", "", hcsCalculationEfficiency); + holderEvent.mcParticleIndicesMatchedTpcKaP.reserve(30); + holderEvent.mcParticleIndicesMatchedTpcKaM.reserve(30); + holderEvent.mcParticleIndicesMatchedTpcTofKaP.reserve(20); + holderEvent.mcParticleIndicesMatchedTpcTofKaM.reserve(20); + + pCentralityPtEtaEfficiencyTpcKaP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcKaM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcTofKaP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcTofKaM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + for (std::int32_t const& iVzBin : std::views::iota(0, static_cast(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2))) { + pCentralityPtEtaEfficiencyTpcKaP[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcKaP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcKaM[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcKaM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcTofKaP[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcTofKaP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcTofKaM[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcTofKaM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + } } if (cfgFlagCalculationEfficiencyPr.value) { LOG(info) << "Enabling (anti)proton efficiency calculation."; - quantityHolderEvent.mcParticleIndicesMatchedTpcPrP.reserve(30); - quantityHolderEvent.mcParticleIndicesMatchedTpcPrM.reserve(30); - quantityHolderEvent.mcParticleIndicesMatchedTpcTofPrP.reserve(20); - quantityHolderEvent.mcParticleIndicesMatchedTpcTofPrM.reserve(20); - - hrCalculationEfficiency.add("CalculationEfficiency/pVzPtEtaEfficiencyTpcPrP", "", hcsCalculationEfficiency); - hrCalculationEfficiency.add("CalculationEfficiency/pVzPtEtaEfficiencyTpcPrM", "", hcsCalculationEfficiency); - hrCalculationEfficiency.add("CalculationEfficiency/pVzPtEtaEfficiencyTpcTofPrP", "", hcsCalculationEfficiency); - hrCalculationEfficiency.add("CalculationEfficiency/pVzPtEtaEfficiencyTpcTofPrM", "", hcsCalculationEfficiency); + holderEvent.mcParticleIndicesMatchedTpcPrP.reserve(30); + holderEvent.mcParticleIndicesMatchedTpcPrM.reserve(30); + holderEvent.mcParticleIndicesMatchedTpcTofPrP.reserve(20); + holderEvent.mcParticleIndicesMatchedTpcTofPrM.reserve(20); + + pCentralityPtEtaEfficiencyTpcPrP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcPrM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcTofPrP.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + pCentralityPtEtaEfficiencyTpcTofPrM.resize(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2); + for (std::int32_t const& iVzBin : std::views::iota(0, static_cast(std::llrint(std::ceil(cfgCutMaxAbsVertexZ.value)) * 2))) { + pCentralityPtEtaEfficiencyTpcPrP[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcPrP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcPrM[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcPrM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcTofPrP[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcTofPrP_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + pCentralityPtEtaEfficiencyTpcTofPrM[iVzBin] = hrCalculationEfficiency.add(Form("CalculationEfficiency/pCentralityPtEtaEfficiencyTpcTofPrM_vz%gto%g", std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin, std::floor(-cfgCutMaxAbsVertexZ.value) + iVzBin + 1), "", hcsCalculationEfficiency); + } } } + + if (cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value) { + initCalculationFluctuation(ccdbObject); + } } - if (runNumbers.empty()) { + if (holderCcdb.runNumbers.empty()) { LOG(info) << "No run process enabled."; } else { - for (std::int32_t const& runNumber : runNumbers) { + for (std::int32_t const& runNumber : holderCcdb.runNumbers) { LOG(info) << "Enabling processing run: " << runNumber; } } - if (runNumbersBad.empty()) { + if (holderCcdb.runNumbersBad.empty()) { LOG(info) << "No run rejection enabled."; } else { - for (std::int32_t const& runNumberBad : runNumbersBad) { + for (std::int32_t const& runNumberBad : holderCcdb.runNumbersBad) { LOG(info) << "Enabling rejecting run: " << runNumberBad; } } - if ((cfgFlagSelectionEvent.value & ((1ULL << aod::evsel::kNsel) - 1)) == 0) { + if ((cfgFlagSelectionEvent.value & ((1ULL << aod::evsel::EventSelectionFlags::kNsel) - 1)) == 0) { LOG(info) << "No event selection bit enabled."; } else { - for (std::int32_t const& iEvSel : std::views::iota(0, aod::evsel::kNsel)) { + for (std::int32_t const& iEvSel : std::views::iota(0, aod::evsel::EventSelectionFlags::kNsel)) { if ((cfgFlagSelectionEvent.value >> iEvSel) & 1) { LOG(info) << "Enabling event selection bit: " << aod::evsel::selectionLabels[iEvSel]; } } } + + switch (cfgIndexDefinitionCentrality) { + default: + LOG(info) << "Enabling centrality definition: FV0A"; + break; + case static_cast(CentralityDefinitionIndices::kFT0M): + LOG(info) << "Enabling centrality definition: FT0M"; + break; + case static_cast(CentralityDefinitionIndices::kFT0A): + LOG(info) << "Enabling centrality definition: FT0A"; + break; + case static_cast(CentralityDefinitionIndices::kFT0C): + LOG(info) << "Enabling centrality definition: FT0C"; + break; + } } template std::int32_t isPi() { if constexpr (doRequiringTof && doRejectingOthers) { - if (!(std::fabs(quantityHolderTrack.tpcTofNSigmaPi) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(quantityHolderTrack.tpcTofNSigmaKa), std::fabs(quantityHolderTrack.tpcTofNSigmaPr))))) { + if (!(std::fabs(holderTrack.tpcTofNSigmaPi) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(holderTrack.tpcTofNSigmaKa), std::fabs(holderTrack.tpcTofNSigmaPr))))) { return 0; } } if constexpr (doRequiringTof && !doRejectingOthers) { - if (!(std::fabs(quantityHolderTrack.tpcTofNSigmaPi) < cfgCutMaxAbsNSigmaPid.value)) { + if (!(std::fabs(holderTrack.tpcTofNSigmaPi) < cfgCutMaxAbsNSigmaPid.value)) { return 0; } } if constexpr (!doRequiringTof && doRejectingOthers) { - if (!(std::fabs(quantityHolderTrack.tpcNSigmaPi) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(quantityHolderTrack.tpcNSigmaKa), std::fabs(quantityHolderTrack.tpcNSigmaPr))))) { + if (!(std::fabs(holderTrack.tpcNSigmaPi) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(holderTrack.tpcNSigmaKa), std::fabs(holderTrack.tpcNSigmaPr))))) { return 0; } } if constexpr (!doRequiringTof && !doRejectingOthers) { - if (!(std::fabs(quantityHolderTrack.tpcNSigmaPi) < cfgCutMaxAbsNSigmaPid.value)) { + if (!(std::fabs(holderTrack.tpcNSigmaPi) < cfgCutMaxAbsNSigmaPid.value)) { return 0; } } - return quantityHolderTrack.sign; + return holderTrack.sign; } template std::int32_t isKa() { if constexpr (doRequiringTof && doRejectingOthers) { - if (!(std::fabs(quantityHolderTrack.tpcTofNSigmaKa) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(quantityHolderTrack.tpcTofNSigmaPi), std::fabs(quantityHolderTrack.tpcTofNSigmaPr))))) { + if (!(std::fabs(holderTrack.tpcTofNSigmaKa) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(holderTrack.tpcTofNSigmaPi), std::fabs(holderTrack.tpcTofNSigmaPr))))) { return 0; } } if constexpr (doRequiringTof && !doRejectingOthers) { - if (!(std::fabs(quantityHolderTrack.tpcTofNSigmaKa) < cfgCutMaxAbsNSigmaPid.value)) { + if (!(std::fabs(holderTrack.tpcTofNSigmaKa) < cfgCutMaxAbsNSigmaPid.value)) { return 0; } } if constexpr (!doRequiringTof && doRejectingOthers) { - if (!(std::fabs(quantityHolderTrack.tpcNSigmaKa) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(quantityHolderTrack.tpcNSigmaPi), std::fabs(quantityHolderTrack.tpcNSigmaPr))))) { + if (!(std::fabs(holderTrack.tpcNSigmaKa) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(holderTrack.tpcNSigmaPi), std::fabs(holderTrack.tpcNSigmaPr))))) { return 0; } } if constexpr (!doRequiringTof && !doRejectingOthers) { - if (!(std::fabs(quantityHolderTrack.tpcNSigmaKa) < cfgCutMaxAbsNSigmaPid.value)) { + if (!(std::fabs(holderTrack.tpcNSigmaKa) < cfgCutMaxAbsNSigmaPid.value)) { return 0; } } - return quantityHolderTrack.sign; + return holderTrack.sign; } template std::int32_t isPr() { if constexpr (doRequiringTof && doRejectingOthers) { - if (!(std::fabs(quantityHolderTrack.tpcTofNSigmaPr) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(quantityHolderTrack.tpcTofNSigmaPi), std::fabs(quantityHolderTrack.tpcTofNSigmaKa))))) { + if (!(std::fabs(holderTrack.tpcTofNSigmaPr) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(holderTrack.tpcTofNSigmaPi), std::fabs(holderTrack.tpcTofNSigmaKa))))) { return 0; } } if constexpr (doRequiringTof && !doRejectingOthers) { - if (!(std::fabs(quantityHolderTrack.tpcTofNSigmaPr) < cfgCutMaxAbsNSigmaPid.value)) { + if (!(std::fabs(holderTrack.tpcTofNSigmaPr) < cfgCutMaxAbsNSigmaPid.value)) { return 0; } } if constexpr (!doRequiringTof && doRejectingOthers) { - if (!(std::fabs(quantityHolderTrack.tpcNSigmaPr) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(quantityHolderTrack.tpcNSigmaPi), std::fabs(quantityHolderTrack.tpcNSigmaKa))))) { + if (!(std::fabs(holderTrack.tpcNSigmaPr) < std::min(cfgCutMaxAbsNSigmaPid.value, std::min(std::fabs(holderTrack.tpcNSigmaPi), std::fabs(holderTrack.tpcNSigmaKa))))) { return 0; } } if constexpr (!doRequiringTof && !doRejectingOthers) { - if (!(std::fabs(quantityHolderTrack.tpcNSigmaPr) < cfgCutMaxAbsNSigmaPid.value)) { + if (!(std::fabs(holderTrack.tpcNSigmaPr) < cfgCutMaxAbsNSigmaPid.value)) { return 0; } } - return quantityHolderTrack.sign; + return holderTrack.sign; } bool isGoodMomentum() { - if (!(cfgCutMinPt.value < quantityHolderTrack.pt && quantityHolderTrack.pt < cfgCutMaxPt.value)) { + if (!(cfgCutMinPt.value < holderTrack.pt && holderTrack.pt < cfgCutMaxPt.value)) { return false; } - if (!(std::fabs(quantityHolderTrack.eta) < cfgCutMaxAbsEta.value)) { + if (!(std::fabs(holderTrack.eta) < cfgCutMaxAbsEta.value)) { return false; } return true; @@ -1103,16 +1242,25 @@ struct PartNumFluc { return true; } + template + bool isGoodMcParticle(const MP& mcParticle) + { + if (!mcParticle.isPhysicalPrimary()) { + return false; + } + return true; + } + template bool initMcParticle(const MP& mcParticle) { - quantityHolderMcParticle.clear(); - quantityHolderMcParticle.globalIndex = mcParticle.globalIndex(); - quantityHolderMcParticle.pdgCode = mcParticle.pdgCode(); - quantityHolderMcParticle.pt = mcParticle.pt(); - quantityHolderMcParticle.eta = mcParticle.eta(); + holderMcParticle.clear(); + holderMcParticle.globalIndex = mcParticle.globalIndex(); + holderMcParticle.pdgCode = mcParticle.pdgCode(); + holderMcParticle.pt = mcParticle.pt(); + holderMcParticle.eta = mcParticle.eta(); - if (!mcParticle.isPhysicalPrimary()) { + if (!isGoodMcParticle(mcParticle)) { return false; } @@ -1122,81 +1270,81 @@ struct PartNumFluc { template bool initTrack(const T& track) { - quantityHolderTrack.clear(); - quantityHolderTrack.sign = track.sign(); - quantityHolderTrack.pt = track.pt(); - quantityHolderTrack.eta = track.eta(); - quantityHolderTrack.phi = track.phi(); - quantityHolderTrack.ptOverQ = quantityHolderTrack.pt / quantityHolderTrack.sign; - quantityHolderTrack.pOverQ = track.p() / quantityHolderTrack.sign; - quantityHolderTrack.rapidityPi = track.rapidity(constants::physics::MassPiPlus); - quantityHolderTrack.rapidityKa = track.rapidity(constants::physics::MassKPlus); - quantityHolderTrack.rapidityPr = track.rapidity(constants::physics::MassProton); - quantityHolderTrack.hasTpcPid = (track.hasTPC() && track.tpcSignal() > 0.); - quantityHolderTrack.tpcNSigmaPi = QuantityHolderTrack::truncateNSigmaPid(track.tpcNSigmaPi()); - quantityHolderTrack.tpcNSigmaKa = QuantityHolderTrack::truncateNSigmaPid(track.tpcNSigmaKa()); - quantityHolderTrack.tpcNSigmaPr = QuantityHolderTrack::truncateNSigmaPid(track.tpcNSigmaPr()); - quantityHolderTrack.hasTofPid = (track.hasTOF() && track.beta() > 0.); - quantityHolderTrack.tofNSigmaPi = QuantityHolderTrack::truncateNSigmaPid(track.tofNSigmaPi()); - quantityHolderTrack.tofNSigmaKa = QuantityHolderTrack::truncateNSigmaPid(track.tofNSigmaKa()); - quantityHolderTrack.tofNSigmaPr = QuantityHolderTrack::truncateNSigmaPid(track.tofNSigmaPr()); - quantityHolderTrack.tpcTofNSigmaPi = QuantityHolderTrack::truncateNSigmaPid(std::sqrt(std::pow(quantityHolderTrack.tpcNSigmaPi, 2.) + std::pow(quantityHolderTrack.tofNSigmaPi, 2.))); - quantityHolderTrack.tpcTofNSigmaKa = QuantityHolderTrack::truncateNSigmaPid(std::sqrt(std::pow(quantityHolderTrack.tpcNSigmaKa, 2.) + std::pow(quantityHolderTrack.tofNSigmaKa, 2.))); - quantityHolderTrack.tpcTofNSigmaPr = QuantityHolderTrack::truncateNSigmaPid(std::sqrt(std::pow(quantityHolderTrack.tpcNSigmaPr, 2.) + std::pow(quantityHolderTrack.tofNSigmaPr, 2.))); + holderTrack.clear(); + holderTrack.sign = track.sign(); + holderTrack.pt = track.pt(); + holderTrack.eta = track.eta(); + holderTrack.phi = track.phi(); + holderTrack.ptOverQ = holderTrack.pt / holderTrack.sign; + holderTrack.pOverQ = track.p() / holderTrack.sign; + holderTrack.rapidityPi = track.rapidity(constants::physics::MassPiPlus); + holderTrack.rapidityKa = track.rapidity(constants::physics::MassKPlus); + holderTrack.rapidityPr = track.rapidity(constants::physics::MassProton); + holderTrack.hasTpcPid = (track.hasTPC() && track.tpcSignal() > 0.); + holderTrack.tpcNSigmaPi = HolderTrack::truncateNSigmaPid(track.tpcNSigmaPi()); + holderTrack.tpcNSigmaKa = HolderTrack::truncateNSigmaPid(track.tpcNSigmaKa()); + holderTrack.tpcNSigmaPr = HolderTrack::truncateNSigmaPid(track.tpcNSigmaPr()); + holderTrack.hasTofPid = (track.hasTOF() && track.beta() > 0.); + holderTrack.tofNSigmaPi = HolderTrack::truncateNSigmaPid(track.tofNSigmaPi()); + holderTrack.tofNSigmaKa = HolderTrack::truncateNSigmaPid(track.tofNSigmaKa()); + holderTrack.tofNSigmaPr = HolderTrack::truncateNSigmaPid(track.tofNSigmaPr()); + holderTrack.tpcTofNSigmaPi = HolderTrack::truncateNSigmaPid(std::sqrt(std::pow(holderTrack.tpcNSigmaPi, 2.) + std::pow(holderTrack.tofNSigmaPi, 2.))); + holderTrack.tpcTofNSigmaKa = HolderTrack::truncateNSigmaPid(std::sqrt(std::pow(holderTrack.tpcNSigmaKa, 2.) + std::pow(holderTrack.tofNSigmaKa, 2.))); + holderTrack.tpcTofNSigmaPr = HolderTrack::truncateNSigmaPid(std::sqrt(std::pow(holderTrack.tpcNSigmaPr, 2.) + std::pow(holderTrack.tofNSigmaPr, 2.))); if constexpr (doProcessingMc) { - quantityHolderTrack.mcParticleId = track.mcParticleId(); + holderTrack.mcParticleId = track.mcParticleId(); } if constexpr (doInitingEvent) { - quantityHolderEvent.nGlobalTracks++; + holderEvent.nGlobalTracks++; if (track.isPVContributor()) { - quantityHolderEvent.nPvContributors++; + holderEvent.nPvContributors++; } - if (quantityHolderTrack.hasTofPid) { - quantityHolderEvent.nTofBeta++; + holderEvent.meanDcaXy += track.dcaXY(); + holderEvent.meanSquareDcaXy += std::pow(track.dcaXY(), 2.); + holderEvent.meanDcaZ += track.dcaZ(); + holderEvent.meanSquareDcaZ += std::pow(track.dcaZ(), 2.); + if (holderTrack.hasTofPid) { + holderEvent.nTofBeta++; } - quantityHolderEvent.meanDcaXy += track.dcaXY(); - quantityHolderEvent.meanSquareDcaXy += std::pow(track.dcaXY(), 2.); - quantityHolderEvent.meanDcaZ += track.dcaZ(); - quantityHolderEvent.meanSquareDcaZ += std::pow(track.dcaZ(), 2.); } if constexpr (!doProcessingMc && doInitingEvent) { if (cfgFlagQaRun.value) { - hrQaRun.fill(HIST("QaRun/pRunIndexItsNCls"), quantityHolderEvent.runIndex, track.itsNCls()); - hrQaRun.fill(HIST("QaRun/pRunIndexItsChi2NCls"), quantityHolderEvent.runIndex, track.itsChi2NCl()); - hrQaRun.fill(HIST("QaRun/pRunIndexTpcNCls"), quantityHolderEvent.runIndex, track.tpcNClsFound()); - hrQaRun.fill(HIST("QaRun/pRunIndexTpcChi2NCls"), quantityHolderEvent.runIndex, track.tpcChi2NCl()); - hrQaRun.fill(HIST("QaRun/pRunIndexTpcNClsSharedRatio"), quantityHolderEvent.runIndex, track.tpcFractionSharedCls()); - hrQaRun.fill(HIST("QaRun/pRunIndexTpcNClsCrossedRows"), quantityHolderEvent.runIndex, track.tpcNClsCrossedRows()); - hrQaRun.fill(HIST("QaRun/pRunIndexTpcNClsCrossedRowsRatio"), quantityHolderEvent.runIndex, track.tpcCrossedRowsOverFindableCls()); - hrQaRun.fill(HIST("QaRun/pRunIndexDcaXy"), quantityHolderEvent.runIndex, track.dcaXY()); - hrQaRun.fill(HIST("QaRun/pRunIndexDcaZ"), quantityHolderEvent.runIndex, track.dcaZ()); - hrQaRun.fill(HIST("QaRun/pRunIndexPt"), quantityHolderEvent.runIndex, quantityHolderTrack.pt); - hrQaRun.fill(HIST("QaRun/pRunIndexEta"), quantityHolderEvent.runIndex, quantityHolderTrack.eta); - hrQaRun.fill(HIST("QaRun/pRunIndexPhi"), quantityHolderEvent.runIndex, quantityHolderTrack.phi); - if (quantityHolderTrack.hasTpcPid) { - hrQaRun.fill(HIST("QaRun/pRunIndexTpcDeDx"), quantityHolderEvent.runIndex, track.tpcSignal()); - if (std::fabs(quantityHolderTrack.tpcNSigmaPi) < QuantityHolderTrack::TruncationAbsNSigmaPid) { - hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaPi"), quantityHolderEvent.runIndex, quantityHolderTrack.tpcNSigmaPi); + hrQaRun.fill(HIST("QaRun/pRunIndexItsNCls"), holderEvent.runIndex, track.itsNCls()); + hrQaRun.fill(HIST("QaRun/pRunIndexItsChi2NCls"), holderEvent.runIndex, track.itsChi2NCl()); + hrQaRun.fill(HIST("QaRun/pRunIndexTpcNCls"), holderEvent.runIndex, track.tpcNClsFound()); + hrQaRun.fill(HIST("QaRun/pRunIndexTpcChi2NCls"), holderEvent.runIndex, track.tpcChi2NCl()); + hrQaRun.fill(HIST("QaRun/pRunIndexTpcNClsSharedRatio"), holderEvent.runIndex, track.tpcFractionSharedCls()); + hrQaRun.fill(HIST("QaRun/pRunIndexTpcNClsCrossedRows"), holderEvent.runIndex, track.tpcNClsCrossedRows()); + hrQaRun.fill(HIST("QaRun/pRunIndexTpcNClsCrossedRowsRatio"), holderEvent.runIndex, track.tpcCrossedRowsOverFindableCls()); + hrQaRun.fill(HIST("QaRun/pRunIndexDcaXy"), holderEvent.runIndex, track.dcaXY()); + hrQaRun.fill(HIST("QaRun/pRunIndexDcaZ"), holderEvent.runIndex, track.dcaZ()); + hrQaRun.fill(HIST("QaRun/pRunIndexPt"), holderEvent.runIndex, holderTrack.pt); + hrQaRun.fill(HIST("QaRun/pRunIndexEta"), holderEvent.runIndex, holderTrack.eta); + hrQaRun.fill(HIST("QaRun/pRunIndexPhi"), holderEvent.runIndex, holderTrack.phi); + if (holderTrack.hasTpcPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTpcDeDx"), holderEvent.runIndex, track.tpcSignal()); + if (std::fabs(holderTrack.tpcNSigmaPi) < HolderTrack::TruncationAbsNSigmaPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaPi"), holderEvent.runIndex, holderTrack.tpcNSigmaPi); } - if (std::fabs(quantityHolderTrack.tpcNSigmaKa) < QuantityHolderTrack::TruncationAbsNSigmaPid) { - hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaKa"), quantityHolderEvent.runIndex, quantityHolderTrack.tpcNSigmaKa); + if (std::fabs(holderTrack.tpcNSigmaKa) < HolderTrack::TruncationAbsNSigmaPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaKa"), holderEvent.runIndex, holderTrack.tpcNSigmaKa); } - if (std::fabs(quantityHolderTrack.tpcNSigmaPr) < QuantityHolderTrack::TruncationAbsNSigmaPid) { - hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaPr"), quantityHolderEvent.runIndex, quantityHolderTrack.tpcNSigmaPr); + if (std::fabs(holderTrack.tpcNSigmaPr) < HolderTrack::TruncationAbsNSigmaPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTpcNSigmaPr"), holderEvent.runIndex, holderTrack.tpcNSigmaPr); } } - if (quantityHolderTrack.hasTofPid) { - hrQaRun.fill(HIST("QaRun/pRunIndexTofInverseBeta"), quantityHolderEvent.runIndex, 1. / track.beta()); - if (std::fabs(quantityHolderTrack.tofNSigmaPi) < QuantityHolderTrack::TruncationAbsNSigmaPid) { - hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaPi"), quantityHolderEvent.runIndex, quantityHolderTrack.tofNSigmaPi); + if (holderTrack.hasTofPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTofInverseBeta"), holderEvent.runIndex, 1. / track.beta()); + if (std::fabs(holderTrack.tofNSigmaPi) < HolderTrack::TruncationAbsNSigmaPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaPi"), holderEvent.runIndex, holderTrack.tofNSigmaPi); } - if (std::fabs(quantityHolderTrack.tofNSigmaKa) < QuantityHolderTrack::TruncationAbsNSigmaPid) { - hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaKa"), quantityHolderEvent.runIndex, quantityHolderTrack.tofNSigmaKa); + if (std::fabs(holderTrack.tofNSigmaKa) < HolderTrack::TruncationAbsNSigmaPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaKa"), holderEvent.runIndex, holderTrack.tofNSigmaKa); } - if (std::fabs(quantityHolderTrack.tofNSigmaPr) < QuantityHolderTrack::TruncationAbsNSigmaPid) { - hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaPr"), quantityHolderEvent.runIndex, quantityHolderTrack.tofNSigmaPr); + if (std::fabs(holderTrack.tofNSigmaPr) < HolderTrack::TruncationAbsNSigmaPid) { + hrQaRun.fill(HIST("QaRun/pRunIndexTofNSigmaPr"), holderEvent.runIndex, holderTrack.tofNSigmaPr); } } } @@ -1208,11 +1356,11 @@ struct PartNumFluc { hrQaTrack.fill(HIST("QaTrack/hItsChi2NCls"), track.itsChi2NCl()); hrQaTrack.fill(HIST("QaTrack/hTpcNClsNClsSharedNClsFindableNClsCrossedRows"), track.tpcNClsFound(), track.tpcNClsShared(), track.tpcNClsFindable(), track.tpcNClsCrossedRows()); hrQaTrack.fill(HIST("QaTrack/hTpcChi2NCls"), track.tpcChi2NCl()); - hrQaTrack.fill(HIST("QaTrack/hPtDcaXy"), quantityHolderTrack.pt, track.dcaXY()); - hrQaTrack.fill(HIST("QaTrack/hPtDcaZ"), quantityHolderTrack.pt, track.dcaZ()); + hrQaTrack.fill(HIST("QaTrack/hPtDcaXy"), holderTrack.pt, track.dcaXY()); + hrQaTrack.fill(HIST("QaTrack/hPtDcaZ"), holderTrack.pt, track.dcaZ()); if (track.isPVContributor()) { - hrQaTrack.fill(HIST("QaTrack/hPtDcaXy_pvContributor"), quantityHolderTrack.pt, track.dcaXY()); - hrQaTrack.fill(HIST("QaTrack/hPtDcaZ_pvContributor"), quantityHolderTrack.pt, track.dcaZ()); + hrQaTrack.fill(HIST("QaTrack/hPtDcaXy_pvContributor"), holderTrack.pt, track.dcaXY()); + hrQaTrack.fill(HIST("QaTrack/hPtDcaZ_pvContributor"), holderTrack.pt, track.dcaZ()); } } } @@ -1222,16 +1370,14 @@ struct PartNumFluc { } if constexpr (doProcessingMc && doInitingEvent) { - if ((cfgFlagCalculationEfficiencyPi.value || cfgFlagCalculationEfficiencyKa.value || cfgFlagCalculationEfficiencyPr.value) && quantityHolderTrack.hasTpcPid) { + if ((cfgFlagCalculationEfficiencyPi.value || cfgFlagCalculationEfficiencyKa.value || cfgFlagCalculationEfficiencyPr.value) && holderTrack.hasTpcPid) { if (cfgFlagCalculationEfficiencyPi.value) { switch (isPi()) { case 1: - quantityHolderEvent.mcParticleIndicesMatchedTpcPiP.push_back(quantityHolderTrack.mcParticleId); + holderEvent.mcParticleIndicesMatchedTpcPiP.push_back(holderTrack.mcParticleId); break; case -1: - quantityHolderEvent.mcParticleIndicesMatchedTpcPiM.push_back(quantityHolderTrack.mcParticleId); - break; - default: + holderEvent.mcParticleIndicesMatchedTpcPiM.push_back(holderTrack.mcParticleId); break; } } @@ -1239,12 +1385,10 @@ struct PartNumFluc { if (cfgFlagCalculationEfficiencyKa.value) { switch (isKa()) { case 1: - quantityHolderEvent.mcParticleIndicesMatchedTpcKaP.push_back(quantityHolderTrack.mcParticleId); + holderEvent.mcParticleIndicesMatchedTpcKaP.push_back(holderTrack.mcParticleId); break; case -1: - quantityHolderEvent.mcParticleIndicesMatchedTpcKaM.push_back(quantityHolderTrack.mcParticleId); - break; - default: + holderEvent.mcParticleIndicesMatchedTpcKaM.push_back(holderTrack.mcParticleId); break; } } @@ -1252,26 +1396,22 @@ struct PartNumFluc { if (cfgFlagCalculationEfficiencyPr.value) { switch (isPr()) { case 1: - quantityHolderEvent.mcParticleIndicesMatchedTpcPrP.push_back(quantityHolderTrack.mcParticleId); + holderEvent.mcParticleIndicesMatchedTpcPrP.push_back(holderTrack.mcParticleId); break; case -1: - quantityHolderEvent.mcParticleIndicesMatchedTpcPrM.push_back(quantityHolderTrack.mcParticleId); - break; - default: + holderEvent.mcParticleIndicesMatchedTpcPrM.push_back(holderTrack.mcParticleId); break; } } - if (quantityHolderTrack.hasTofPid) { + if (holderTrack.hasTofPid) { if (cfgFlagCalculationEfficiencyPi.value) { switch (isPi()) { case 1: - quantityHolderEvent.mcParticleIndicesMatchedTpcTofPiP.push_back(quantityHolderTrack.mcParticleId); + holderEvent.mcParticleIndicesMatchedTpcTofPiP.push_back(holderTrack.mcParticleId); break; case -1: - quantityHolderEvent.mcParticleIndicesMatchedTpcTofPiM.push_back(quantityHolderTrack.mcParticleId); - break; - default: + holderEvent.mcParticleIndicesMatchedTpcTofPiM.push_back(holderTrack.mcParticleId); break; } } @@ -1279,12 +1419,10 @@ struct PartNumFluc { if (cfgFlagCalculationEfficiencyKa.value) { switch (isKa()) { case 1: - quantityHolderEvent.mcParticleIndicesMatchedTpcTofKaP.push_back(quantityHolderTrack.mcParticleId); + holderEvent.mcParticleIndicesMatchedTpcTofKaP.push_back(holderTrack.mcParticleId); break; case -1: - quantityHolderEvent.mcParticleIndicesMatchedTpcTofKaM.push_back(quantityHolderTrack.mcParticleId); - break; - default: + holderEvent.mcParticleIndicesMatchedTpcTofKaM.push_back(holderTrack.mcParticleId); break; } } @@ -1292,12 +1430,10 @@ struct PartNumFluc { if (cfgFlagCalculationEfficiencyPr.value) { switch (isPr()) { case 1: - quantityHolderEvent.mcParticleIndicesMatchedTpcTofPrP.push_back(quantityHolderTrack.mcParticleId); + holderEvent.mcParticleIndicesMatchedTpcTofPrP.push_back(holderTrack.mcParticleId); break; case -1: - quantityHolderEvent.mcParticleIndicesMatchedTpcTofPrM.push_back(quantityHolderTrack.mcParticleId); - break; - default: + holderEvent.mcParticleIndicesMatchedTpcTofPrM.push_back(holderTrack.mcParticleId); break; } } @@ -1306,61 +1442,55 @@ struct PartNumFluc { } if constexpr (!doProcessingMc && !doInitingEvent) { - if (cfgFlagQaAcceptance.value && ((quantityHolderTrack.eta > 0. && quantityHolderEvent.vz > cfgCutMaxAbsVertexZ.value - 0.5) || (quantityHolderTrack.eta < 0. && quantityHolderEvent.vz < -cfgCutMaxAbsVertexZ.value + 0.5)) && quantityHolderTrack.hasTpcPid) { - hrQaAcceptance.fill(HIST("QaAcceptance/hEtaPt_tpc"), quantityHolderTrack.eta, quantityHolderTrack.pt); - hrQaAcceptance.fill(HIST("QaAcceptance/hPhi_tpc"), quantityHolderTrack.phi); + if (cfgFlagQaAcceptance.value && ((holderTrack.eta > 0. && holderEvent.vz > cfgCutMaxAbsVertexZ.value - 0.5) || (holderTrack.eta < 0. && holderEvent.vz < -cfgCutMaxAbsVertexZ.value + 0.5)) && holderTrack.hasTpcPid) { + hrQaAcceptance.fill(HIST("QaAcceptance/hEtaPt_tpc"), holderTrack.eta, holderTrack.pt); + hrQaAcceptance.fill(HIST("QaAcceptance/hPhi_tpc"), holderTrack.phi); if (std::abs(isPi()) == 1) { - hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcPi"), quantityHolderTrack.rapidityPi, quantityHolderTrack.pt); + hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcPi"), holderTrack.rapidityPi, holderTrack.pt); } if (std::abs(isKa()) == 1) { - hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcKa"), quantityHolderTrack.rapidityKa, quantityHolderTrack.pt); + hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcKa"), holderTrack.rapidityKa, holderTrack.pt); } if (std::abs(isPr()) == 1) { - hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcPr"), quantityHolderTrack.rapidityPr, quantityHolderTrack.pt); + hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcPr"), holderTrack.rapidityPr, holderTrack.pt); } - if (quantityHolderTrack.hasTofPid) { - hrQaAcceptance.fill(HIST("QaAcceptance/hEtaPt_tpcTof"), quantityHolderTrack.eta, quantityHolderTrack.pt); - hrQaAcceptance.fill(HIST("QaAcceptance/hPhi_tpcTof"), quantityHolderTrack.phi); + if (holderTrack.hasTofPid) { + hrQaAcceptance.fill(HIST("QaAcceptance/hEtaPt_tpcTof"), holderTrack.eta, holderTrack.pt); + hrQaAcceptance.fill(HIST("QaAcceptance/hPhi_tpcTof"), holderTrack.phi); if (std::abs(isPi()) == 1) { - hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcTofPi"), quantityHolderTrack.rapidityPi, quantityHolderTrack.pt); + hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcTofPi"), holderTrack.rapidityPi, holderTrack.pt); } if (std::abs(isKa()) == 1) { - hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcTofKa"), quantityHolderTrack.rapidityKa, quantityHolderTrack.pt); + hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcTofKa"), holderTrack.rapidityKa, holderTrack.pt); } if (std::abs(isPr()) == 1) { - hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcTofPr"), quantityHolderTrack.rapidityPr, quantityHolderTrack.pt); + hrQaAcceptance.fill(HIST("QaAcceptance/hYPt_tpcTofPr"), holderTrack.rapidityPr, holderTrack.pt); } } } - if (cfgFlagQaPid.value && quantityHolderTrack.hasTpcPid) { - hrQaPid.fill(HIST("QaPid/hPOverQEtaTpcLnDeDx"), quantityHolderTrack.pOverQ, quantityHolderTrack.eta, std::log(track.tpcSignal())); - hrQaPid.fill(HIST("QaPid/hPtOverQEtaTpcNSigmaPi"), quantityHolderTrack.ptOverQ, quantityHolderTrack.eta, quantityHolderTrack.tpcNSigmaPi); - if (std::fabs(quantityHolderTrack.tofNSigmaPi) < cfgCutMaxAbsNSigmaPid.value) { - hrQaPid.fill(HIST("QaPid/hPtOverQEtaTpcNSigmaPi_tofPi"), quantityHolderTrack.ptOverQ, quantityHolderTrack.eta, quantityHolderTrack.tpcNSigmaPi); + if (cfgFlagQaPid.value && holderTrack.hasTpcPid) { + hrQaPid.fill(HIST("QaPid/hCentralityPOverQEtaTpcLnDeDx"), holderEvent.centrality, holderTrack.pOverQ, holderTrack.eta, std::log(track.tpcSignal())); + if (std::fabs(holderTrack.tofNSigmaPi) < cfgCutMaxAbsNSigmaPid.value) { + hrQaPid.fill(HIST("QaPid/hCentralityPtOverQEtaTpcNSigmaPi_tofPi"), holderEvent.centrality, holderTrack.ptOverQ, holderTrack.eta, holderTrack.tpcNSigmaPi); } - hrQaPid.fill(HIST("QaPid/hPtOverQEtaTpcNSigmaKa"), quantityHolderTrack.ptOverQ, quantityHolderTrack.eta, quantityHolderTrack.tpcNSigmaKa); - if (std::fabs(quantityHolderTrack.tofNSigmaKa) < cfgCutMaxAbsNSigmaPid.value) { - hrQaPid.fill(HIST("QaPid/hPtOverQEtaTpcNSigmaKa_tofKa"), quantityHolderTrack.ptOverQ, quantityHolderTrack.eta, quantityHolderTrack.tpcNSigmaKa); + if (std::fabs(holderTrack.tofNSigmaKa) < cfgCutMaxAbsNSigmaPid.value) { + hrQaPid.fill(HIST("QaPid/hCentralityPtOverQEtaTpcNSigmaKa_tofKa"), holderEvent.centrality, holderTrack.ptOverQ, holderTrack.eta, holderTrack.tpcNSigmaKa); } - hrQaPid.fill(HIST("QaPid/hPtOverQEtaTpcNSigmaPr"), quantityHolderTrack.ptOverQ, quantityHolderTrack.eta, quantityHolderTrack.tpcNSigmaPr); - if (std::fabs(quantityHolderTrack.tofNSigmaPr) < cfgCutMaxAbsNSigmaPid.value) { - hrQaPid.fill(HIST("QaPid/hPtOverQEtaTpcNSigmaPr_tofPr"), quantityHolderTrack.ptOverQ, quantityHolderTrack.eta, quantityHolderTrack.tpcNSigmaPr); + if (std::fabs(holderTrack.tofNSigmaPr) < cfgCutMaxAbsNSigmaPid.value) { + hrQaPid.fill(HIST("QaPid/hCentralityPtOverQEtaTpcNSigmaPr_tofPr"), holderEvent.centrality, holderTrack.ptOverQ, holderTrack.eta, holderTrack.tpcNSigmaPr); } if (track.beta() > 0.) { - hrQaPid.fill(HIST("QaPid/hPOverQEtaTofInverseBeta"), quantityHolderTrack.pOverQ, quantityHolderTrack.eta, 1. / track.beta()); - if (std::fabs(quantityHolderTrack.tpcNSigmaPi) < cfgCutMaxAbsNSigmaPid.value) { - hrQaPid.fill(HIST("QaPid/hPtOverQEtaTofNSigmaPi_tpcPi"), quantityHolderTrack.ptOverQ, quantityHolderTrack.eta, quantityHolderTrack.tofNSigmaPi); + hrQaPid.fill(HIST("QaPid/hCentralityPOverQEtaTofInverseBeta"), holderEvent.centrality, holderTrack.pOverQ, holderTrack.eta, 1. / track.beta()); + if (std::fabs(holderTrack.tpcNSigmaPi) < cfgCutMaxAbsNSigmaPid.value) { + hrQaPid.fill(HIST("QaPid/hCentralityPtOverQEtaTofNSigmaPi_tpcPi"), holderEvent.centrality, holderTrack.ptOverQ, holderTrack.eta, holderTrack.tofNSigmaPi); } - if (std::fabs(quantityHolderTrack.tpcNSigmaKa) < cfgCutMaxAbsNSigmaPid.value) { - hrQaPid.fill(HIST("QaPid/hPtOverQEtaTofNSigmaKa_tpcKa"), quantityHolderTrack.ptOverQ, quantityHolderTrack.eta, quantityHolderTrack.tofNSigmaKa); + if (std::fabs(holderTrack.tpcNSigmaKa) < cfgCutMaxAbsNSigmaPid.value) { + hrQaPid.fill(HIST("QaPid/hCentralityPtOverQEtaTofNSigmaKa_tpcKa"), holderEvent.centrality, holderTrack.ptOverQ, holderTrack.eta, holderTrack.tofNSigmaKa); } - if (std::fabs(quantityHolderTrack.tpcNSigmaPr) < cfgCutMaxAbsNSigmaPid.value) { - hrQaPid.fill(HIST("QaPid/hPtOverQEtaTofNSigmaPr_tpcPr"), quantityHolderTrack.ptOverQ, quantityHolderTrack.eta, quantityHolderTrack.tofNSigmaPr); + if (std::fabs(holderTrack.tpcNSigmaPr) < cfgCutMaxAbsNSigmaPid.value) { + hrQaPid.fill(HIST("QaPid/hCentralityPtOverQEtaTofNSigmaPr_tpcPr"), holderEvent.centrality, holderTrack.ptOverQ, holderTrack.eta, holderTrack.tofNSigmaPr); } - hrQaPid.fill(HIST("QaPid/hPtOverQEtaTpcTofNSigmaPi"), quantityHolderTrack.ptOverQ, quantityHolderTrack.eta, quantityHolderTrack.tpcTofNSigmaPi); - hrQaPid.fill(HIST("QaPid/hPtOverQEtaTpcTofNSigmaKa"), quantityHolderTrack.ptOverQ, quantityHolderTrack.eta, quantityHolderTrack.tpcTofNSigmaKa); - hrQaPid.fill(HIST("QaPid/hPtOverQEtaTpcTofNSigmaPr"), quantityHolderTrack.ptOverQ, quantityHolderTrack.eta, quantityHolderTrack.tpcTofNSigmaPr); } } } @@ -1371,7 +1501,23 @@ struct PartNumFluc { template bool initEvent(const C& collision, const Ts& tracks) { - quantityHolderEvent.clear(); + holderEvent.clear(); + holderEvent.vz = collision.posZ(); + holderEvent.vzBinIndex = std::llrint(std::floor(holderEvent.vz - std::floor(-cfgCutMaxAbsVertexZ.value))); + switch (cfgIndexDefinitionCentrality) { + default: + holderEvent.centrality = collision.centFV0A(); + break; + case static_cast(CentralityDefinitionIndices::kFT0M): + holderEvent.centrality = collision.centFT0M(); + break; + case static_cast(CentralityDefinitionIndices::kFT0A): + holderEvent.centrality = collision.centFT0A(); + break; + case static_cast(CentralityDefinitionIndices::kFT0C): + holderEvent.centrality = collision.centFT0C(); + break; + } hrCounter.fill(HIST("hNEvents"), 0.); @@ -1381,15 +1527,15 @@ struct PartNumFluc { } const auto& bc = collision.template bc_as(); - quantityHolderEvent.runNumber = bc.runNumber(); - quantityHolderEvent.runIndex = std::distance(runNumbers.begin(), std::ranges::find(runNumbers, quantityHolderEvent.runNumber)); + holderEvent.runNumber = bc.runNumber(); + holderEvent.runIndex = std::distance(holderCcdb.runNumbers.begin(), std::ranges::find(holderCcdb.runNumbers, holderEvent.runNumber)); - if (std::ranges::find(runNumbers, quantityHolderEvent.runNumber) == runNumbers.end() || std::ranges::find(runNumbersBad, quantityHolderEvent.runNumber) != runNumbersBad.end()) { + if (std::ranges::find(holderCcdb.runNumbers, holderEvent.runNumber) == holderCcdb.runNumbers.end() || std::ranges::find(holderCcdb.runNumbersBad, holderEvent.runNumber) != holderCcdb.runNumbersBad.end()) { hrCounter.fill(HIST("hNEvents"), 2.); return false; } - for (std::int32_t const& iEvSel : std::views::iota(0, aod::evsel::kNsel)) { + for (std::int32_t const& iEvSel : std::views::iota(0, aod::evsel::EventSelectionFlags::kNsel)) { if (((cfgFlagSelectionEvent.value >> iEvSel) & 1) && !collision.selection_bit(iEvSel)) { hrCounter.fill(HIST("hNEvents"), 3); hrCounter.fill(HIST("hNEvents"), 10 + iEvSel); @@ -1397,67 +1543,69 @@ struct PartNumFluc { } } - quantityHolderEvent.vz = collision.posZ(); - if constexpr (!doProcessingMc) { if (cfgFlagQaEvent.value) { - hrQaEvent.fill(HIST("QaEvent/hRunIndexVxVy"), quantityHolderEvent.runIndex, collision.posX(), collision.posY()); - hrQaEvent.fill(HIST("QaEvent/hRunIndexVz"), quantityHolderEvent.runIndex, quantityHolderEvent.vz); + hrQaEvent.fill(HIST("QaEvent/hRunIndexVxVy"), holderEvent.runIndex, collision.posX(), collision.posY()); + hrQaEvent.fill(HIST("QaEvent/hRunIndexVz"), holderEvent.runIndex, holderEvent.vz); } } - if (!(std::fabs(quantityHolderEvent.vz) < cfgCutMaxAbsVertexZ.value)) { + if (!(std::fabs(holderEvent.vz) < cfgCutMaxAbsVertexZ.value)) { hrCounter.fill(HIST("hNEvents"), 4); return false; } if constexpr (!doProcessingMc) { if (cfgFlagQaRun.value) { - hrQaRun.fill(HIST("QaRun/pRunIndexVx"), quantityHolderEvent.runIndex, collision.posX()); - hrQaRun.fill(HIST("QaRun/pRunIndexVy"), quantityHolderEvent.runIndex, collision.posY()); - hrQaRun.fill(HIST("QaRun/pRunIndexVz"), quantityHolderEvent.runIndex, quantityHolderEvent.vz); - hrQaRun.fill(HIST("QaRun/pRunIndexMultFv0a"), quantityHolderEvent.runIndex, collision.multZeqFV0A()); - hrQaRun.fill(HIST("QaRun/pRunIndexMultFt0a"), quantityHolderEvent.runIndex, collision.multZeqFT0A()); - hrQaRun.fill(HIST("QaRun/pRunIndexMultFt0c"), quantityHolderEvent.runIndex, collision.multZeqFT0C()); + hrQaRun.fill(HIST("QaRun/pRunIndexVx"), holderEvent.runIndex, collision.posX()); + hrQaRun.fill(HIST("QaRun/pRunIndexVy"), holderEvent.runIndex, collision.posY()); + hrQaRun.fill(HIST("QaRun/pRunIndexVz"), holderEvent.runIndex, holderEvent.vz); + hrQaRun.fill(HIST("QaRun/pRunIndexMultFv0a"), holderEvent.runIndex, collision.multZeqFV0A()); + hrQaRun.fill(HIST("QaRun/pRunIndexMultFt0a"), holderEvent.runIndex, collision.multZeqFT0A()); + hrQaRun.fill(HIST("QaRun/pRunIndexMultFt0c"), holderEvent.runIndex, collision.multZeqFT0C()); } } for (const auto& track : tracks) { + if (!track.has_collision()) { + continue; + } + initTrack(track); } - if (quantityHolderEvent.nGlobalTracks > 0.) { - quantityHolderEvent.meanDcaXy /= quantityHolderEvent.nGlobalTracks; - quantityHolderEvent.meanSquareDcaXy /= quantityHolderEvent.nGlobalTracks; - quantityHolderEvent.meanDcaZ /= quantityHolderEvent.nGlobalTracks; - quantityHolderEvent.meanSquareDcaZ /= quantityHolderEvent.nGlobalTracks; + if (holderEvent.nGlobalTracks > 0.) { + holderEvent.meanDcaXy /= holderEvent.nGlobalTracks; + holderEvent.meanSquareDcaXy /= holderEvent.nGlobalTracks; + holderEvent.meanDcaZ /= holderEvent.nGlobalTracks; + holderEvent.meanSquareDcaZ /= holderEvent.nGlobalTracks; } if constexpr (!doProcessingMc) { if (cfgFlagQaRun.value) { - hrQaRun.fill(HIST("QaRun/pRunIndexNGlobalTracks"), quantityHolderEvent.runIndex, quantityHolderEvent.nGlobalTracks); - hrQaRun.fill(HIST("QaRun/pRunIndexNPvContributors"), quantityHolderEvent.runIndex, quantityHolderEvent.nPvContributors); - hrQaRun.fill(HIST("QaRun/pRunIndexNTofBeta"), quantityHolderEvent.runIndex, quantityHolderEvent.nTofBeta); - if (quantityHolderEvent.nGlobalTracks > 0) { - hrQaRun.fill(HIST("QaRun/pRunIndexMeanDcaXy"), quantityHolderEvent.runIndex, quantityHolderEvent.meanDcaXy); - hrQaRun.fill(HIST("QaRun/pRunIndexSigmaDcaXy"), quantityHolderEvent.runIndex, std::sqrt(quantityHolderEvent.meanSquareDcaXy - std::pow(quantityHolderEvent.meanDcaXy, 2.))); - hrQaRun.fill(HIST("QaRun/pRunIndexMeanDcaZ"), quantityHolderEvent.runIndex, quantityHolderEvent.meanDcaZ); - hrQaRun.fill(HIST("QaRun/pRunIndexSigmaDcaZ"), quantityHolderEvent.runIndex, std::sqrt(quantityHolderEvent.meanSquareDcaZ - std::pow(quantityHolderEvent.meanDcaZ, 2.))); + hrQaRun.fill(HIST("QaRun/pRunIndexNGlobalTracks"), holderEvent.runIndex, holderEvent.nGlobalTracks); + hrQaRun.fill(HIST("QaRun/pRunIndexNPvContributors"), holderEvent.runIndex, holderEvent.nPvContributors); + if (holderEvent.nGlobalTracks > 0) { + hrQaRun.fill(HIST("QaRun/pRunIndexMeanDcaXy"), holderEvent.runIndex, holderEvent.meanDcaXy); + hrQaRun.fill(HIST("QaRun/pRunIndexSigmaDcaXy"), holderEvent.runIndex, std::sqrt(holderEvent.meanSquareDcaXy - std::pow(holderEvent.meanDcaXy, 2.))); + hrQaRun.fill(HIST("QaRun/pRunIndexMeanDcaZ"), holderEvent.runIndex, holderEvent.meanDcaZ); + hrQaRun.fill(HIST("QaRun/pRunIndexSigmaDcaZ"), holderEvent.runIndex, std::sqrt(holderEvent.meanSquareDcaZ - std::pow(holderEvent.meanDcaZ, 2.))); } + hrQaRun.fill(HIST("QaRun/pRunIndexNTofBeta"), holderEvent.runIndex, holderEvent.nTofBeta); } } if constexpr (!doProcessingMc) { if (cfgFlagQaEvent.value) { - hrQaEvent.fill(HIST("QaEvent/hRunIndexNTofBetaNGlobalTracks"), quantityHolderEvent.runIndex, quantityHolderEvent.nTofBeta, quantityHolderEvent.nGlobalTracks); - hrQaEvent.fill(HIST("QaEvent/hRunIndexNPvContributorsNGlobalTracks"), quantityHolderEvent.runIndex, quantityHolderEvent.nPvContributors, quantityHolderEvent.nGlobalTracks); - if (quantityHolderEvent.nGlobalTracks > 0) { - hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaXy"), quantityHolderEvent.runIndex, quantityHolderEvent.nGlobalTracks, quantityHolderEvent.meanDcaXy); - hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaZ"), quantityHolderEvent.runIndex, quantityHolderEvent.nGlobalTracks, quantityHolderEvent.meanDcaZ); + hrQaEvent.fill(HIST("QaEvent/hRunIndexNPvContributorsNGlobalTracks"), holderEvent.runIndex, holderEvent.nPvContributors, holderEvent.nGlobalTracks); + if (holderEvent.nGlobalTracks > 0) { + hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaXy"), holderEvent.runIndex, holderEvent.nGlobalTracks, holderEvent.meanDcaXy); + hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaZ"), holderEvent.runIndex, holderEvent.nGlobalTracks, holderEvent.meanDcaZ); } + hrQaEvent.fill(HIST("QaEvent/hRunIndexNTofBetaNGlobalTracks"), holderEvent.runIndex, holderEvent.nTofBeta, holderEvent.nGlobalTracks); } } - if (!(quantityHolderEvent.nPvContributors - quantityHolderEvent.nGlobalTracks > cfgCutMinNPvContributorsDeviation.value)) { + if (!(holderEvent.nPvContributors - holderEvent.nGlobalTracks > cfgCutMinDeviationNPvContributors.value)) { hrCounter.fill(HIST("hNEvents"), 5); return false; } @@ -1466,335 +1614,322 @@ struct PartNumFluc { if constexpr (!doProcessingMc) { if (cfgFlagQaEvent.value) { - if (quantityHolderEvent.nGlobalTracks > 0) { - hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaXy_nPvContributorsCut"), quantityHolderEvent.runIndex, quantityHolderEvent.nGlobalTracks, quantityHolderEvent.meanDcaXy); - hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaZ_nPvContributorsCut"), quantityHolderEvent.runIndex, quantityHolderEvent.nGlobalTracks, quantityHolderEvent.meanDcaZ); + if (holderEvent.nGlobalTracks > 0) { + hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaXy_nPvContributorsCut"), holderEvent.runIndex, holderEvent.nGlobalTracks, holderEvent.meanDcaXy); + hrQaEvent.fill(HIST("QaEvent/hRunIndexNGlobalTracksMeanDcaZ_nPvContributorsCut"), holderEvent.runIndex, holderEvent.nGlobalTracks, holderEvent.meanDcaZ); } + hrQaEvent.fill(HIST("QaEvent/hRunIndexNTofBetaNGlobalTracks_nPvContributorsCut"), holderEvent.runIndex, holderEvent.nTofBeta, holderEvent.nGlobalTracks); } } - quantityHolderEvent.centrality = collision.centFT0M(); - if constexpr (!doProcessingMc) { if (cfgFlagQaCentrality.value) { hrQaCentrality.fill(HIST("QaCentrality/hCentralityFv0a"), collision.centFV0A(), collision.multZeqFV0A()); hrQaCentrality.fill(HIST("QaCentrality/hCentralityFt0a"), collision.centFT0A(), collision.multZeqFT0A()); hrQaCentrality.fill(HIST("QaCentrality/hCentralityFt0c"), collision.centFT0C(), collision.multZeqFT0C()); - hrQaCentrality.fill(HIST("QaCentrality/hCentralityFt0m"), quantityHolderEvent.centrality, collision.multZeqFT0A() + collision.multZeqFT0C()); + hrQaCentrality.fill(HIST("QaCentrality/hCentralityFt0m"), collision.centFT0M(), collision.multZeqFT0A() + collision.multZeqFT0C()); } } return true; } - void processRaw(const soa::Filtered::iterator& collision, const soa::Filtered& tracks, const aod::BCsWithTimestamps&) + void calculateFluctuation() { - if (!initEvent(collision, tracks)) { - return; - } - - if (!cfgFlagQaTrack.value && !cfgFlagQaAcceptance.value && !cfgFlagQaPid.value && !cfgFlagAnalysisFluctuationCh.value && !cfgFlagAnalysisFluctuationKa.value && !cfgFlagAnalysisFluctuationPr.value) { - return; - } - - if (cfgFlagAnalysisFluctuationCh.value || cfgFlagAnalysisFluctuationKa.value || cfgFlagAnalysisFluctuationPr.value) { - quantityHolderEvent.subgroupIndex = gRandom->Integer(cfgNSubgroups.value); - if (cfgFlagAnalysisFluctuationCh.value) { - fluctuationCalculatorTrackChP->init(); - fluctuationCalculatorTrackChM->init(); - fluctuationCalculatorTrackChT->init(); - fluctuationCalculatorTrackChN->init(); - } - if (cfgFlagAnalysisFluctuationKa.value) { - fluctuationCalculatorTrackKaP->init(); - fluctuationCalculatorTrackKaM->init(); - fluctuationCalculatorTrackKaT->init(); - fluctuationCalculatorTrackKaN->init(); - } - if (cfgFlagAnalysisFluctuationPr.value) { - fluctuationCalculatorTrackPrP->init(); - fluctuationCalculatorTrackPrM->init(); - fluctuationCalculatorTrackPrT->init(); - fluctuationCalculatorTrackPrN->init(); - } - } - for (const auto& track : tracks) { - if (!initTrack(track)) { - continue; - } - - if ((cfgFlagAnalysisFluctuationCh.value || cfgFlagAnalysisFluctuationKa.value || cfgFlagAnalysisFluctuationPr.value) && isGoodMomentum() && quantityHolderTrack.hasTpcPid) { - if (cfgFlagAnalysisFluctuationCh.value) { - if (quantityHolderTrack.pt < cfgThresholdPtTofPi.value) { - switch (isPi()) { - case 1: { - quantityHolderEvent.nChP++; - - const double efficiency = pVzPtEtaEfficiencyTpcPiP->GetBinContent(pVzPtEtaEfficiencyTpcPiP->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcPiP->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcPiP->GetZaxis()->FindBin(quantityHolderTrack.eta)); - - fluctuationCalculatorTrackChP->fill(1., efficiency); - fluctuationCalculatorTrackChT->fill(1., efficiency); - fluctuationCalculatorTrackChN->fill(1., efficiency); - } break; - case -1: { - quantityHolderEvent.nChM++; - - const double efficiency = pVzPtEtaEfficiencyTpcPiM->GetBinContent(pVzPtEtaEfficiencyTpcPiM->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcPiM->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcPiM->GetZaxis()->FindBin(quantityHolderTrack.eta)); - - fluctuationCalculatorTrackChM->fill(1., efficiency); - fluctuationCalculatorTrackChT->fill(1., efficiency); - fluctuationCalculatorTrackChN->fill(-1., efficiency); - } break; - default: - break; - } - } else if (quantityHolderTrack.hasTofPid) { - switch (isPi()) { - case 1: { - quantityHolderEvent.nChP++; + if (isGoodMomentum() && holderTrack.hasTpcPid) { + if (cfgFlagCalculationFluctuationCh.value) { + if (holderTrack.pt < cfgThresholdPtTofPi.value) { + switch (isPi()) { + case 1: { + holderEvent.nChP++; - const double efficiency = pVzPtEtaEfficiencyTpcTofPiP->GetBinContent(pVzPtEtaEfficiencyTpcTofPiP->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcTofPiP->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcTofPiP->GetZaxis()->FindBin(quantityHolderTrack.eta)); + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcPiP[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcPiP[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcPiP[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcPiP[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); - fluctuationCalculatorTrackChP->fill(1., efficiency); - fluctuationCalculatorTrackChT->fill(1., efficiency); - fluctuationCalculatorTrackChN->fill(1., efficiency); - } break; - case -1: { - quantityHolderEvent.nChM++; + fluctuationCalculatorTrackChP->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nChM++; - const double efficiency = pVzPtEtaEfficiencyTpcTofPiM->GetBinContent(pVzPtEtaEfficiencyTpcTofPiM->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcTofPiM->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcTofPiM->GetZaxis()->FindBin(quantityHolderTrack.eta)); + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcPiM[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcPiM[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcPiM[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcPiM[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); - fluctuationCalculatorTrackChM->fill(1., efficiency); - fluctuationCalculatorTrackChT->fill(1., efficiency); - fluctuationCalculatorTrackChN->fill(-1., efficiency); - } break; - default: - break; - } + fluctuationCalculatorTrackChM->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(-1., efficiency); + } break; } - if (quantityHolderTrack.pt < cfgThresholdPtTofKa.value) { - switch (isKa()) { - case 1: { - quantityHolderEvent.nChP++; - - const double efficiency = pVzPtEtaEfficiencyTpcKaP->GetBinContent(pVzPtEtaEfficiencyTpcKaP->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcKaP->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcKaP->GetZaxis()->FindBin(quantityHolderTrack.eta)); - - fluctuationCalculatorTrackChP->fill(1., efficiency); - fluctuationCalculatorTrackChT->fill(1., efficiency); - fluctuationCalculatorTrackChN->fill(1., efficiency); - } break; - case -1: { - quantityHolderEvent.nChM++; - - const double efficiency = pVzPtEtaEfficiencyTpcKaM->GetBinContent(pVzPtEtaEfficiencyTpcKaM->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcKaM->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcKaM->GetZaxis()->FindBin(quantityHolderTrack.eta)); - - fluctuationCalculatorTrackChM->fill(1., efficiency); - fluctuationCalculatorTrackChT->fill(1., efficiency); - fluctuationCalculatorTrackChN->fill(-1., efficiency); - } break; - default: - break; - } - } else if (quantityHolderTrack.hasTofPid) { - switch (isKa()) { - case 1: { - quantityHolderEvent.nChP++; - - const double efficiency = pVzPtEtaEfficiencyTpcTofKaP->GetBinContent(pVzPtEtaEfficiencyTpcTofKaP->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcTofKaP->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcTofKaP->GetZaxis()->FindBin(quantityHolderTrack.eta)); - - fluctuationCalculatorTrackChP->fill(1., efficiency); - fluctuationCalculatorTrackChT->fill(1., efficiency); - fluctuationCalculatorTrackChN->fill(1., efficiency); - } break; - case -1: { - quantityHolderEvent.nChM++; - - const double efficiency = pVzPtEtaEfficiencyTpcTofKaM->GetBinContent(pVzPtEtaEfficiencyTpcTofKaM->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcTofKaM->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcTofKaM->GetZaxis()->FindBin(quantityHolderTrack.eta)); - - fluctuationCalculatorTrackChM->fill(1., efficiency); - fluctuationCalculatorTrackChT->fill(1., efficiency); - fluctuationCalculatorTrackChN->fill(-1., efficiency); - } break; - default: - break; - } + } else if (holderTrack.hasTofPid) { + switch (isPi()) { + case 1: { + holderEvent.nChP++; + + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiP[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiP[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiP[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiP[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); + + fluctuationCalculatorTrackChP->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nChM++; + + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiM[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiM[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiM[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcTofPiM[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); + + fluctuationCalculatorTrackChM->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(-1., efficiency); + } break; } - if (quantityHolderTrack.pt < cfgThresholdPtTofPr.value) { - switch (isPr()) { - case 1: { - quantityHolderEvent.nChP++; - - const double efficiency = pVzPtEtaEfficiencyTpcPrP->GetBinContent(pVzPtEtaEfficiencyTpcPrP->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcPrP->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcPrP->GetZaxis()->FindBin(quantityHolderTrack.eta)); - - fluctuationCalculatorTrackChP->fill(1., efficiency); - fluctuationCalculatorTrackChT->fill(1., efficiency); - fluctuationCalculatorTrackChN->fill(1., efficiency); - } break; - case -1: { - quantityHolderEvent.nChM++; - - const double efficiency = pVzPtEtaEfficiencyTpcPrM->GetBinContent(pVzPtEtaEfficiencyTpcPrM->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcPrM->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcPrM->GetZaxis()->FindBin(quantityHolderTrack.eta)); - - fluctuationCalculatorTrackChM->fill(1., efficiency); - fluctuationCalculatorTrackChT->fill(1., efficiency); - fluctuationCalculatorTrackChN->fill(-1., efficiency); - } break; - default: - break; - } - } else if (quantityHolderTrack.hasTofPid) { - switch (isPr()) { - case 1: { - quantityHolderEvent.nChP++; + } + if (holderTrack.pt < cfgThresholdPtTofKa.value) { + switch (isKa()) { + case 1: { + holderEvent.nChP++; - const double efficiency = pVzPtEtaEfficiencyTpcTofPrP->GetBinContent(pVzPtEtaEfficiencyTpcTofPrP->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcTofPrP->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcTofPrP->GetZaxis()->FindBin(quantityHolderTrack.eta)); + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); - fluctuationCalculatorTrackChP->fill(1., efficiency); - fluctuationCalculatorTrackChT->fill(1., efficiency); - fluctuationCalculatorTrackChN->fill(1., efficiency); - } break; - case -1: { - quantityHolderEvent.nChM++; + fluctuationCalculatorTrackChP->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nChM++; - const double efficiency = pVzPtEtaEfficiencyTpcTofPrM->GetBinContent(pVzPtEtaEfficiencyTpcTofPrM->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcTofPrM->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcTofPrM->GetZaxis()->FindBin(quantityHolderTrack.eta)); + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); - fluctuationCalculatorTrackChM->fill(1., efficiency); - fluctuationCalculatorTrackChT->fill(1., efficiency); - fluctuationCalculatorTrackChN->fill(-1., efficiency); - } break; - default: - break; - } + fluctuationCalculatorTrackChM->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(-1., efficiency); + } break; + } + } else if (holderTrack.hasTofPid) { + switch (isKa()) { + case 1: { + holderEvent.nChP++; + + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); + + fluctuationCalculatorTrackChP->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nChM++; + + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); + + fluctuationCalculatorTrackChM->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(-1., efficiency); + } break; } } + if (holderTrack.pt < cfgThresholdPtTofPr.value) { + switch (isPr()) { + case 1: { + holderEvent.nChP++; - if (cfgFlagAnalysisFluctuationKa.value) { - if (quantityHolderTrack.pt < cfgThresholdPtTofKa.value) { - switch (isKa()) { - case 1: { - quantityHolderEvent.nKaP++; + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); - const double efficiency = pVzPtEtaEfficiencyTpcKaP->GetBinContent(pVzPtEtaEfficiencyTpcKaP->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcKaP->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcKaP->GetZaxis()->FindBin(quantityHolderTrack.eta)); + fluctuationCalculatorTrackChP->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nChM++; - fluctuationCalculatorTrackKaP->fill(1., efficiency); - fluctuationCalculatorTrackKaT->fill(1., efficiency); - fluctuationCalculatorTrackKaN->fill(1., efficiency); - } break; - case -1: { - quantityHolderEvent.nKaM++; + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); - const double efficiency = pVzPtEtaEfficiencyTpcKaM->GetBinContent(pVzPtEtaEfficiencyTpcKaM->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcKaM->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcKaM->GetZaxis()->FindBin(quantityHolderTrack.eta)); + fluctuationCalculatorTrackChM->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(-1., efficiency); + } break; + } + } else if (holderTrack.hasTofPid) { + switch (isPr()) { + case 1: { + holderEvent.nChP++; + + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); + + fluctuationCalculatorTrackChP->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nChM++; + + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); + + fluctuationCalculatorTrackChM->fill(1., efficiency); + fluctuationCalculatorTrackChT->fill(1., efficiency); + fluctuationCalculatorTrackChN->fill(-1., efficiency); + } break; + } + } + } - fluctuationCalculatorTrackKaM->fill(1., efficiency); - fluctuationCalculatorTrackKaT->fill(1., efficiency); - fluctuationCalculatorTrackKaN->fill(-1., efficiency); - } break; - default: - break; - } - } else if (quantityHolderTrack.hasTofPid) { - switch (isKa()) { - case 1: { - quantityHolderEvent.nKaP++; + if (cfgFlagCalculationFluctuationKa.value) { + if (holderTrack.pt < cfgThresholdPtTofKa.value) { + switch (isKa()) { + case 1: { + holderEvent.nKaP++; - const double efficiency = pVzPtEtaEfficiencyTpcTofKaP->GetBinContent(pVzPtEtaEfficiencyTpcTofKaP->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcTofKaP->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcTofKaP->GetZaxis()->FindBin(quantityHolderTrack.eta)); + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcKaP[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); - fluctuationCalculatorTrackKaP->fill(1., efficiency); - fluctuationCalculatorTrackKaT->fill(1., efficiency); - fluctuationCalculatorTrackKaN->fill(1., efficiency); - } break; - case -1: { - quantityHolderEvent.nKaM++; + fluctuationCalculatorTrackKaP->fill(1., efficiency); + fluctuationCalculatorTrackKaT->fill(1., efficiency); + fluctuationCalculatorTrackKaN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nKaM++; - const double efficiency = pVzPtEtaEfficiencyTpcTofKaM->GetBinContent(pVzPtEtaEfficiencyTpcTofKaM->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcTofKaM->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcTofKaM->GetZaxis()->FindBin(quantityHolderTrack.eta)); + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcKaM[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); - fluctuationCalculatorTrackKaM->fill(1., efficiency); - fluctuationCalculatorTrackKaT->fill(1., efficiency); - fluctuationCalculatorTrackKaN->fill(-1., efficiency); - } break; - default: - break; - } + fluctuationCalculatorTrackKaM->fill(1., efficiency); + fluctuationCalculatorTrackKaT->fill(1., efficiency); + fluctuationCalculatorTrackKaN->fill(-1., efficiency); + } break; + } + } else if (holderTrack.hasTofPid) { + switch (isKa()) { + case 1: { + holderEvent.nKaP++; + + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaP[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); + + fluctuationCalculatorTrackKaP->fill(1., efficiency); + fluctuationCalculatorTrackKaT->fill(1., efficiency); + fluctuationCalculatorTrackKaN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nKaM++; + + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcTofKaM[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); + + fluctuationCalculatorTrackKaM->fill(1., efficiency); + fluctuationCalculatorTrackKaT->fill(1., efficiency); + fluctuationCalculatorTrackKaN->fill(-1., efficiency); + } break; } } + } - if (cfgFlagAnalysisFluctuationPr.value) { - if (quantityHolderTrack.pt < cfgThresholdPtTofPr.value) { - switch (isPr()) { - case 1: { - quantityHolderEvent.nPrP++; + if (cfgFlagCalculationFluctuationPr.value) { + if (holderTrack.pt < cfgThresholdPtTofPr.value) { + switch (isPr()) { + case 1: { + holderEvent.nPrP++; - const double efficiency = pVzPtEtaEfficiencyTpcPrP->GetBinContent(pVzPtEtaEfficiencyTpcPrP->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcPrP->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcPrP->GetZaxis()->FindBin(quantityHolderTrack.eta)); + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcPrP[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); - fluctuationCalculatorTrackPrP->fill(1., efficiency); - fluctuationCalculatorTrackPrT->fill(1., efficiency); - fluctuationCalculatorTrackPrN->fill(1., efficiency); - } break; - case -1: { - quantityHolderEvent.nPrM++; + fluctuationCalculatorTrackPrP->fill(1., efficiency); + fluctuationCalculatorTrackPrT->fill(1., efficiency); + fluctuationCalculatorTrackPrN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nPrM++; - const double efficiency = pVzPtEtaEfficiencyTpcPrM->GetBinContent(pVzPtEtaEfficiencyTpcPrM->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcPrM->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcPrM->GetZaxis()->FindBin(quantityHolderTrack.eta)); + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcPrM[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); - fluctuationCalculatorTrackPrM->fill(1., efficiency); - fluctuationCalculatorTrackPrT->fill(1., efficiency); - fluctuationCalculatorTrackPrN->fill(-1., efficiency); - } break; - default: - break; - } - } else if (quantityHolderTrack.hasTofPid) { - switch (isPr()) { - case 1: { - quantityHolderEvent.nPrP++; + fluctuationCalculatorTrackPrM->fill(1., efficiency); + fluctuationCalculatorTrackPrT->fill(1., efficiency); + fluctuationCalculatorTrackPrN->fill(-1., efficiency); + } break; + } + } else if (holderTrack.hasTofPid) { + switch (isPr()) { + case 1: { + holderEvent.nPrP++; + + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrP[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); + + fluctuationCalculatorTrackPrP->fill(1., efficiency); + fluctuationCalculatorTrackPrT->fill(1., efficiency); + fluctuationCalculatorTrackPrN->fill(1., efficiency); + } break; + case -1: { + holderEvent.nPrM++; + + const double efficiency = holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[holderEvent.vzBinIndex]->GetBinContent(holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[holderEvent.vzBinIndex]->GetXaxis()->FindBin(holderEvent.centrality), holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[holderEvent.vzBinIndex]->GetYaxis()->FindBin(holderTrack.pt), holderCcdb.pCentralityPtEtaEfficiencyTpcTofPrM[holderEvent.vzBinIndex]->GetZaxis()->FindBin(holderTrack.eta)); + + fluctuationCalculatorTrackPrM->fill(1., efficiency); + fluctuationCalculatorTrackPrT->fill(1., efficiency); + fluctuationCalculatorTrackPrN->fill(-1., efficiency); + } break; + } + } + } + } + } - const double efficiency = pVzPtEtaEfficiencyTpcTofPrP->GetBinContent(pVzPtEtaEfficiencyTpcTofPrP->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcTofPrP->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcTofPrP->GetZaxis()->FindBin(quantityHolderTrack.eta)); + void processRaw(const soa::Filtered::iterator& collision, const soa::Filtered& tracks, const aod::BCsWithTimestamps&) + { + if (!initEvent(collision, tracks)) { + return; + } - fluctuationCalculatorTrackPrP->fill(1., efficiency); - fluctuationCalculatorTrackPrT->fill(1., efficiency); - fluctuationCalculatorTrackPrN->fill(1., efficiency); - } break; - case -1: { - quantityHolderEvent.nPrM++; + if (!cfgFlagQaTrack.value && !cfgFlagQaAcceptance.value && !cfgFlagQaPid.value && !cfgFlagCalculationFluctuationCh.value && !cfgFlagCalculationFluctuationKa.value && !cfgFlagCalculationFluctuationPr.value) { + return; + } + + if (cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value) { + holderEvent.subgroupIndex = gRandom->Integer(cfgNSubgroups.value); + if (cfgFlagCalculationFluctuationCh.value) { + fluctuationCalculatorTrackChP->init(); + fluctuationCalculatorTrackChM->init(); + fluctuationCalculatorTrackChT->init(); + fluctuationCalculatorTrackChN->init(); + } + if (cfgFlagCalculationFluctuationKa.value) { + fluctuationCalculatorTrackKaP->init(); + fluctuationCalculatorTrackKaM->init(); + fluctuationCalculatorTrackKaT->init(); + fluctuationCalculatorTrackKaN->init(); + } + if (cfgFlagCalculationFluctuationPr.value) { + fluctuationCalculatorTrackPrP->init(); + fluctuationCalculatorTrackPrM->init(); + fluctuationCalculatorTrackPrT->init(); + fluctuationCalculatorTrackPrN->init(); + } + } - const double efficiency = pVzPtEtaEfficiencyTpcTofPrM->GetBinContent(pVzPtEtaEfficiencyTpcTofPrM->GetXaxis()->FindBin(quantityHolderEvent.vz), pVzPtEtaEfficiencyTpcTofPrM->GetYaxis()->FindBin(quantityHolderTrack.pt), pVzPtEtaEfficiencyTpcTofPrM->GetZaxis()->FindBin(quantityHolderTrack.eta)); + for (const auto& track : tracks) { + if (!track.has_collision() || !initTrack(track)) { + continue; + } - fluctuationCalculatorTrackPrM->fill(1., efficiency); - fluctuationCalculatorTrackPrT->fill(1., efficiency); - fluctuationCalculatorTrackPrN->fill(-1., efficiency); - } break; - default: - break; - } - } - } + if (cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value) { + calculateFluctuation(); } } - if (cfgFlagAnalysisFluctuationCh.value) { - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hCentralityNChPNChM"), quantityHolderEvent.centrality, quantityHolderEvent.nChP, quantityHolderEvent.nChM); + if (cfgFlagCalculationFluctuationCh.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNChPNChM"), holderEvent.centrality, holderEvent.nChP, holderEvent.nChM); for (std::int32_t const& iOrderVector : std::views::iota(0, static_cast(fluctuation_calculator_base::NOrderVectors))) { - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hFluctuationCalculatorChP"), quantityHolderEvent.centrality, quantityHolderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChP->getProductFast(iOrderVector)); - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hFluctuationCalculatorChM"), quantityHolderEvent.centrality, quantityHolderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChM->getProductFast(iOrderVector)); - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hFluctuationCalculatorChT"), quantityHolderEvent.centrality, quantityHolderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChT->getProductFast(iOrderVector)); - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hFluctuationCalculatorChN"), quantityHolderEvent.centrality, quantityHolderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChN->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChP"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChP->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChM"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChM->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChT"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChT->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChN"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChN->getProductFast(iOrderVector)); } } - if (cfgFlagAnalysisFluctuationKa.value) { - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hCentralityNKaPNKaM"), quantityHolderEvent.centrality, quantityHolderEvent.nKaP, quantityHolderEvent.nKaM); + if (cfgFlagCalculationFluctuationKa.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNKaPNKaM"), holderEvent.centrality, holderEvent.nKaP, holderEvent.nKaM); for (std::int32_t const& iOrderVector : std::views::iota(0, static_cast(fluctuation_calculator_base::NOrderVectors))) { - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hFluctuationCalculatorKaP"), quantityHolderEvent.centrality, quantityHolderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaP->getProductFast(iOrderVector)); - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hFluctuationCalculatorKaM"), quantityHolderEvent.centrality, quantityHolderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaM->getProductFast(iOrderVector)); - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hFluctuationCalculatorKaT"), quantityHolderEvent.centrality, quantityHolderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaT->getProductFast(iOrderVector)); - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hFluctuationCalculatorKaN"), quantityHolderEvent.centrality, quantityHolderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaN->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaP"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaP->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaM"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaM->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaT"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaT->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaN"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaN->getProductFast(iOrderVector)); } } - if (cfgFlagAnalysisFluctuationPr.value) { - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hCentralityNPrPNPrM"), quantityHolderEvent.centrality, quantityHolderEvent.nPrP, quantityHolderEvent.nPrM); + if (cfgFlagCalculationFluctuationPr.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNPrPNPrM"), holderEvent.centrality, holderEvent.nPrP, holderEvent.nPrM); for (std::int32_t const& iOrderVector : std::views::iota(0, static_cast(fluctuation_calculator_base::NOrderVectors))) { - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hFluctuationCalculatorPrP"), quantityHolderEvent.centrality, quantityHolderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrP->getProductFast(iOrderVector)); - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hFluctuationCalculatorPrM"), quantityHolderEvent.centrality, quantityHolderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrM->getProductFast(iOrderVector)); - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hFluctuationCalculatorPrT"), quantityHolderEvent.centrality, quantityHolderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrT->getProductFast(iOrderVector)); - hrAnalysisFluctuation.fill(HIST("AnalysisFluctuation/hFluctuationCalculatorPrN"), quantityHolderEvent.centrality, quantityHolderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrN->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrP"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrP->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrM"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrM->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrT"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrT->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrN"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrN->getProductFast(iOrderVector)); } } } @@ -1813,29 +1948,140 @@ struct PartNumFluc { continue; } - if ((cfgFlagCalculationPurityPi.value || cfgFlagCalculationPurityKa.value || cfgFlagCalculationPurityPr.value)) { + if (cfgFlagCalculationEfficiencyPi.value || cfgFlagCalculationEfficiencyKa.value || cfgFlagCalculationEfficiencyPr.value || cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value) { + for (const auto& mcParticle : mcParticles) { + if (!initMcParticle(mcParticle)) { + continue; + } + + switch (holderMcParticle.pdgCode) { + case PDG_t::kPiPlus: + if (cfgFlagCalculationEfficiencyPi.value) { + pCentralityPtEtaEfficiencyTpcPiP[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcPiP, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcPiP.end() ? 1. : 0.); + pCentralityPtEtaEfficiencyTpcTofPiP[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcTofPiP, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcTofPiP.end() ? 1. : 0.); + } + if (cfgFlagCalculationFluctuationCh.value) { + holderEvent.nChPGenerated++; + } + break; + case PDG_t::kPiMinus: + if (cfgFlagCalculationEfficiencyPi.value) { + pCentralityPtEtaEfficiencyTpcPiM[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcPiM, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcPiM.end() ? 1. : 0.); + pCentralityPtEtaEfficiencyTpcTofPiM[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcTofPiM, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcTofPiM.end() ? 1. : 0.); + } + if (cfgFlagCalculationFluctuationCh.value) { + holderEvent.nChMGenerated++; + } + break; + case PDG_t::kKPlus: + if (cfgFlagCalculationEfficiencyKa.value) { + pCentralityPtEtaEfficiencyTpcKaP[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcKaP, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcKaP.end() ? 1. : 0.); + pCentralityPtEtaEfficiencyTpcTofKaP[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcTofKaP, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcTofKaP.end() ? 1. : 0.); + } + if (cfgFlagCalculationFluctuationCh.value) { + holderEvent.nChPGenerated++; + } + if (cfgFlagCalculationFluctuationKa.value) { + holderEvent.nKaPGenerated++; + } + break; + case PDG_t::kKMinus: + if (cfgFlagCalculationEfficiencyKa.value) { + pCentralityPtEtaEfficiencyTpcKaM[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcKaM, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcKaM.end() ? 1. : 0.); + pCentralityPtEtaEfficiencyTpcTofKaM[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcTofKaM, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcTofKaM.end() ? 1. : 0.); + } + if (cfgFlagCalculationFluctuationCh.value) { + holderEvent.nChMGenerated++; + } + if (cfgFlagCalculationFluctuationKa.value) { + holderEvent.nKaMGenerated++; + } + break; + case PDG_t::kProton: + if (cfgFlagCalculationEfficiencyPr.value) { + pCentralityPtEtaEfficiencyTpcPrP[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcPrP, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcPrP.end() ? 1. : 0.); + pCentralityPtEtaEfficiencyTpcTofPrP[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcTofPrP, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcTofPrP.end() ? 1. : 0.); + } + if (cfgFlagCalculationFluctuationCh.value) { + holderEvent.nChPGenerated++; + } + if (cfgFlagCalculationFluctuationPr.value) { + holderEvent.nPrPGenerated++; + } + break; + case PDG_t::kProtonBar: + if (cfgFlagCalculationEfficiencyPr.value) { + pCentralityPtEtaEfficiencyTpcPrM[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcPrM, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcPrM.end() ? 1. : 0.); + pCentralityPtEtaEfficiencyTpcTofPrM[holderEvent.vzBinIndex]->Fill(holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta, std::ranges::find(holderEvent.mcParticleIndicesMatchedTpcTofPrM, holderMcParticle.globalIndex) != holderEvent.mcParticleIndicesMatchedTpcTofPrM.end() ? 1. : 0.); + } + if (cfgFlagCalculationFluctuationCh.value) { + holderEvent.nChMGenerated++; + } + if (cfgFlagCalculationFluctuationPr.value) { + holderEvent.nPrMGenerated++; + } + break; + } + } + + if (cfgFlagCalculationFluctuationCh.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNChPNChM_generated"), holderEvent.centrality, holderEvent.nChPGenerated, holderEvent.nChMGenerated); + } + if (cfgFlagCalculationFluctuationKa.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNKaPNKaM_generated"), holderEvent.centrality, holderEvent.nKaPGenerated, holderEvent.nKaMGenerated); + } + if (cfgFlagCalculationFluctuationPr.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNPrPNPrM_generated"), holderEvent.centrality, holderEvent.nPrPGenerated, holderEvent.nPrMGenerated); + } + } + + if ((cfgFlagCalculationPurityPi.value || cfgFlagCalculationPurityKa.value || cfgFlagCalculationPurityPr.value || cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value)) { + if (cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value) { + holderEvent.subgroupIndex = gRandom->Integer(cfgNSubgroups.value); + if (cfgFlagCalculationFluctuationCh.value) { + fluctuationCalculatorTrackChP->init(); + fluctuationCalculatorTrackChM->init(); + fluctuationCalculatorTrackChT->init(); + fluctuationCalculatorTrackChN->init(); + } + if (cfgFlagCalculationFluctuationKa.value) { + fluctuationCalculatorTrackKaP->init(); + fluctuationCalculatorTrackKaM->init(); + fluctuationCalculatorTrackKaT->init(); + fluctuationCalculatorTrackKaN->init(); + } + if (cfgFlagCalculationFluctuationPr.value) { + fluctuationCalculatorTrackPrP->init(); + fluctuationCalculatorTrackPrM->init(); + fluctuationCalculatorTrackPrT->init(); + fluctuationCalculatorTrackPrN->init(); + } + } + for (const auto& track : tracks) { - if (!track.has_mcParticle()) { + if (!track.has_collision() || !track.has_mcParticle()) { continue; } const auto& mcParticle = track.template mcParticle_as(); + if (!mcParticle.has_mcCollision()) { + continue; + } + initMcParticle(mcParticle); if (!initTrack(track)) { continue; } - if (quantityHolderTrack.hasTpcPid) { + if ((cfgFlagCalculationPurityPi.value || cfgFlagCalculationPurityKa.value || cfgFlagCalculationPurityPr.value) && holderTrack.hasTpcPid) { if (cfgFlagCalculationPurityPi.value) { switch (isPi()) { case 1: - hrCalculationPurity.fill(HIST("CalculationPurity/pPtEtaPurityTpcPiP"), quantityHolderTrack.pt, quantityHolderTrack.eta, quantityHolderMcParticle.pdgCode == PDG_t::kPiPlus ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcPiP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kPiPlus ? 1. : 0.); break; case -1: - hrCalculationPurity.fill(HIST("CalculationPurity/pPtEtaPurityTpcPiM"), quantityHolderTrack.pt, quantityHolderTrack.eta, quantityHolderMcParticle.pdgCode == PDG_t::kPiMinus ? 1. : 0.); - break; - default: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcPiM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kPiMinus ? 1. : 0.); break; } } @@ -1843,12 +2089,10 @@ struct PartNumFluc { if (cfgFlagCalculationPurityKa.value) { switch (isKa()) { case 1: - hrCalculationPurity.fill(HIST("CalculationPurity/pPtEtaPurityTpcKaP"), quantityHolderTrack.pt, quantityHolderTrack.eta, quantityHolderMcParticle.pdgCode == PDG_t::kKPlus ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcKaP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kKPlus ? 1. : 0.); break; case -1: - hrCalculationPurity.fill(HIST("CalculationPurity/pPtEtaPurityTpcKaM"), quantityHolderTrack.pt, quantityHolderTrack.eta, quantityHolderMcParticle.pdgCode == PDG_t::kKMinus ? 1. : 0.); - break; - default: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcKaM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kKMinus ? 1. : 0.); break; } } @@ -1856,26 +2100,22 @@ struct PartNumFluc { if (cfgFlagCalculationPurityPr.value) { switch (isPr()) { case 1: - hrCalculationPurity.fill(HIST("CalculationPurity/pPtEtaPurityTpcPrP"), quantityHolderTrack.pt, quantityHolderTrack.eta, quantityHolderMcParticle.pdgCode == PDG_t::kProton ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcPrP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kProton ? 1. : 0.); break; case -1: - hrCalculationPurity.fill(HIST("CalculationPurity/pPtEtaPurityTpcPrM"), quantityHolderTrack.pt, quantityHolderTrack.eta, quantityHolderMcParticle.pdgCode == PDG_t::kProtonBar ? 1. : 0.); - break; - default: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcPrM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kProtonBar ? 1. : 0.); break; } } - if (quantityHolderTrack.hasTofPid) { + if (holderTrack.hasTofPid) { if (cfgFlagCalculationPurityPi.value) { switch (isPi()) { case 1: - hrCalculationPurity.fill(HIST("CalculationPurity/pPtEtaPurityTpcTofPiP"), quantityHolderTrack.pt, quantityHolderTrack.eta, quantityHolderMcParticle.pdgCode == PDG_t::kPiPlus ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcTofPiP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kPiPlus ? 1. : 0.); break; case -1: - hrCalculationPurity.fill(HIST("CalculationPurity/pPtEtaPurityTpcTofPiM"), quantityHolderTrack.pt, quantityHolderTrack.eta, quantityHolderMcParticle.pdgCode == PDG_t::kPiMinus ? 1. : 0.); - break; - default: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcTofPiM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kPiMinus ? 1. : 0.); break; } } @@ -1883,12 +2123,10 @@ struct PartNumFluc { if (cfgFlagCalculationPurityKa.value) { switch (isKa()) { case 1: - hrCalculationPurity.fill(HIST("CalculationPurity/pPtEtaPurityTpcTofKaP"), quantityHolderTrack.pt, quantityHolderTrack.eta, quantityHolderMcParticle.pdgCode == PDG_t::kKPlus ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcTofKaP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kKPlus ? 1. : 0.); break; case -1: - hrCalculationPurity.fill(HIST("CalculationPurity/pPtEtaPurityTpcTofKaM"), quantityHolderTrack.pt, quantityHolderTrack.eta, quantityHolderMcParticle.pdgCode == PDG_t::kKMinus ? 1. : 0.); - break; - default: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcTofKaM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kKMinus ? 1. : 0.); break; } } @@ -1896,69 +2134,46 @@ struct PartNumFluc { if (cfgFlagCalculationPurityPr.value) { switch (isPr()) { case 1: - hrCalculationPurity.fill(HIST("CalculationPurity/pPtEtaPurityTpcTofPrP"), quantityHolderTrack.pt, quantityHolderTrack.eta, quantityHolderMcParticle.pdgCode == PDG_t::kProton ? 1. : 0.); + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcTofPrP"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kProton ? 1. : 0.); break; case -1: - hrCalculationPurity.fill(HIST("CalculationPurity/pPtEtaPurityTpcTofPrM"), quantityHolderTrack.pt, quantityHolderTrack.eta, quantityHolderMcParticle.pdgCode == PDG_t::kProtonBar ? 1. : 0.); - break; - default: + hrCalculationPurity.fill(HIST("CalculationPurity/pCentralityPtEtaPurityTpcTofPrM"), holderEvent.centrality, holderTrack.pt, holderTrack.eta, holderMcParticle.pdgCode == PDG_t::kProtonBar ? 1. : 0.); break; } } } } - } - } - if (cfgFlagCalculationEfficiencyPi.value || cfgFlagCalculationEfficiencyKa.value || cfgFlagCalculationEfficiencyPr.value) { - for (const auto& mcParticle : mcParticles) { - if (!initMcParticle(mcParticle)) { - continue; + if ((cfgFlagCalculationFluctuationCh.value || cfgFlagCalculationFluctuationKa.value || cfgFlagCalculationFluctuationPr.value) && isGoodMcParticle(mcParticle)) { + calculateFluctuation(); } + } - if (cfgFlagCalculationEfficiencyPi.value) { - switch (quantityHolderMcParticle.pdgCode) { - case PDG_t::kPiPlus: - hrCalculationEfficiency.fill(HIST("CalculationEfficiency/pVzPtEtaEfficiencyTpcPiP"), quantityHolderEvent.vz, quantityHolderMcParticle.pt, quantityHolderMcParticle.eta, std::ranges::find(quantityHolderEvent.mcParticleIndicesMatchedTpcPiP, quantityHolderMcParticle.globalIndex) != quantityHolderEvent.mcParticleIndicesMatchedTpcPiP.end() ? 1. : 0.); - hrCalculationEfficiency.fill(HIST("CalculationEfficiency/pVzPtEtaEfficiencyTpcTofPiP"), quantityHolderEvent.vz, quantityHolderMcParticle.pt, quantityHolderMcParticle.eta, std::ranges::find(quantityHolderEvent.mcParticleIndicesMatchedTpcTofPiP, quantityHolderMcParticle.globalIndex) != quantityHolderEvent.mcParticleIndicesMatchedTpcTofPiP.end() ? 1. : 0.); - break; - case PDG_t::kPiMinus: - hrCalculationEfficiency.fill(HIST("CalculationEfficiency/pVzPtEtaEfficiencyTpcPiM"), quantityHolderEvent.vz, quantityHolderMcParticle.pt, quantityHolderMcParticle.eta, std::ranges::find(quantityHolderEvent.mcParticleIndicesMatchedTpcPiM, quantityHolderMcParticle.globalIndex) != quantityHolderEvent.mcParticleIndicesMatchedTpcPiM.end() ? 1. : 0.); - hrCalculationEfficiency.fill(HIST("CalculationEfficiency/pVzPtEtaEfficiencyTpcTofPiM"), quantityHolderEvent.vz, quantityHolderMcParticle.pt, quantityHolderMcParticle.eta, std::ranges::find(quantityHolderEvent.mcParticleIndicesMatchedTpcTofPiM, quantityHolderMcParticle.globalIndex) != quantityHolderEvent.mcParticleIndicesMatchedTpcTofPiM.end() ? 1. : 0.); - break; - default: - break; - } + if (cfgFlagCalculationFluctuationCh.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNChPNChM"), holderEvent.centrality, holderEvent.nChP, holderEvent.nChM); + for (std::int32_t const& iOrderVector : std::views::iota(0, static_cast(fluctuation_calculator_base::NOrderVectors))) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChP"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChP->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChM"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChM->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChT"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChT->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorChN"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackChN->getProductFast(iOrderVector)); } - - if (cfgFlagCalculationEfficiencyKa.value) { - switch (quantityHolderMcParticle.pdgCode) { - case PDG_t::kKPlus: - hrCalculationEfficiency.fill(HIST("CalculationEfficiency/pVzPtEtaEfficiencyTpcKaP"), quantityHolderEvent.vz, quantityHolderMcParticle.pt, quantityHolderMcParticle.eta, std::ranges::find(quantityHolderEvent.mcParticleIndicesMatchedTpcKaP, quantityHolderMcParticle.globalIndex) != quantityHolderEvent.mcParticleIndicesMatchedTpcKaP.end() ? 1. : 0.); - hrCalculationEfficiency.fill(HIST("CalculationEfficiency/pVzPtEtaEfficiencyTpcTofKaP"), quantityHolderEvent.vz, quantityHolderMcParticle.pt, quantityHolderMcParticle.eta, std::ranges::find(quantityHolderEvent.mcParticleIndicesMatchedTpcTofKaP, quantityHolderMcParticle.globalIndex) != quantityHolderEvent.mcParticleIndicesMatchedTpcTofKaP.end() ? 1. : 0.); - break; - case PDG_t::kKMinus: - hrCalculationEfficiency.fill(HIST("CalculationEfficiency/pVzPtEtaEfficiencyTpcKaM"), quantityHolderEvent.vz, quantityHolderMcParticle.pt, quantityHolderMcParticle.eta, std::ranges::find(quantityHolderEvent.mcParticleIndicesMatchedTpcKaM, quantityHolderMcParticle.globalIndex) != quantityHolderEvent.mcParticleIndicesMatchedTpcKaM.end() ? 1. : 0.); - hrCalculationEfficiency.fill(HIST("CalculationEfficiency/pVzPtEtaEfficiencyTpcTofKaM"), quantityHolderEvent.vz, quantityHolderMcParticle.pt, quantityHolderMcParticle.eta, std::ranges::find(quantityHolderEvent.mcParticleIndicesMatchedTpcTofKaM, quantityHolderMcParticle.globalIndex) != quantityHolderEvent.mcParticleIndicesMatchedTpcTofKaM.end() ? 1. : 0.); - break; - default: - break; - } + } + if (cfgFlagCalculationFluctuationKa.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNKaPNKaM"), holderEvent.centrality, holderEvent.nKaP, holderEvent.nKaM); + for (std::int32_t const& iOrderVector : std::views::iota(0, static_cast(fluctuation_calculator_base::NOrderVectors))) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaP"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaP->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaM"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaM->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaT"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaT->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorKaN"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackKaN->getProductFast(iOrderVector)); } - - if (cfgFlagCalculationEfficiencyPr.value) { - switch (quantityHolderMcParticle.pdgCode) { - case PDG_t::kProton: - hrCalculationEfficiency.fill(HIST("CalculationEfficiency/pVzPtEtaEfficiencyTpcPrP"), quantityHolderEvent.vz, quantityHolderMcParticle.pt, quantityHolderMcParticle.eta, std::ranges::find(quantityHolderEvent.mcParticleIndicesMatchedTpcPrP, quantityHolderMcParticle.globalIndex) != quantityHolderEvent.mcParticleIndicesMatchedTpcPrP.end() ? 1. : 0.); - hrCalculationEfficiency.fill(HIST("CalculationEfficiency/pVzPtEtaEfficiencyTpcTofPrP"), quantityHolderEvent.vz, quantityHolderMcParticle.pt, quantityHolderMcParticle.eta, std::ranges::find(quantityHolderEvent.mcParticleIndicesMatchedTpcTofPrP, quantityHolderMcParticle.globalIndex) != quantityHolderEvent.mcParticleIndicesMatchedTpcTofPrP.end() ? 1. : 0.); - break; - case PDG_t::kProtonBar: - hrCalculationEfficiency.fill(HIST("CalculationEfficiency/pVzPtEtaEfficiencyTpcPrM"), quantityHolderEvent.vz, quantityHolderMcParticle.pt, quantityHolderMcParticle.eta, std::ranges::find(quantityHolderEvent.mcParticleIndicesMatchedTpcPrM, quantityHolderMcParticle.globalIndex) != quantityHolderEvent.mcParticleIndicesMatchedTpcPrM.end() ? 1. : 0.); - hrCalculationEfficiency.fill(HIST("CalculationEfficiency/pVzPtEtaEfficiencyTpcTofPrM"), quantityHolderEvent.vz, quantityHolderMcParticle.pt, quantityHolderMcParticle.eta, std::ranges::find(quantityHolderEvent.mcParticleIndicesMatchedTpcTofPrM, quantityHolderMcParticle.globalIndex) != quantityHolderEvent.mcParticleIndicesMatchedTpcTofPrM.end() ? 1. : 0.); - break; - default: - break; - } + } + if (cfgFlagCalculationFluctuationPr.value) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hCentralityNPrPNPrM"), holderEvent.centrality, holderEvent.nPrP, holderEvent.nPrM); + for (std::int32_t const& iOrderVector : std::views::iota(0, static_cast(fluctuation_calculator_base::NOrderVectors))) { + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrP"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrP->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrM"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrM->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrT"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrT->getProductFast(iOrderVector)); + hrCalculationFluctuation.fill(HIST("CalculationFluctuation/hFluctuationCalculatorPrN"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderVector, fluctuationCalculatorTrackPrN->getProductFast(iOrderVector)); } } } From 28c35504d7950819e1468461f682f13e2887fdfa Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Fri, 14 Nov 2025 03:02:45 +0100 Subject: [PATCH 35/48] [PWGLF] Add run number information (#13806) Co-authored-by: Francesco Mazzaschi --- PWGLF/DataModel/LFHypernucleiTables.h | 9 +++++---- PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx | 10 +++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/PWGLF/DataModel/LFHypernucleiTables.h b/PWGLF/DataModel/LFHypernucleiTables.h index 35a1f7ba51c..ca389cf928b 100644 --- a/PWGLF/DataModel/LFHypernucleiTables.h +++ b/PWGLF/DataModel/LFHypernucleiTables.h @@ -36,6 +36,7 @@ DECLARE_SOA_COLUMN(PsiTPC, psiTPC, float); // Psi with TPC estim DECLARE_SOA_COLUMN(MultTPC, multTPC, float); // Multiplicity with TPC estimator DECLARE_SOA_COLUMN(CollisionId, collisionId, int64_t); // CollisionID +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); // Run number DECLARE_SOA_COLUMN(IsMatter, isMatter, bool); // bool: true for matter DECLARE_SOA_COLUMN(PtHe3, ptHe3, float); // Pt of the He daughter DECLARE_SOA_COLUMN(PhiHe3, phiHe3, float); // Phi of the He daughter @@ -93,7 +94,7 @@ DECLARE_SOA_TABLE(DataHypCands, "AOD", "HYPCANDS", hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, - hyperrec::IsMatter, + hyperrec::RunNumber, hyperrec::IsMatter, hyperrec::PtHe3, hyperrec::PhiHe3, hyperrec::EtaHe3, hyperrec::PtPi, hyperrec::PhiPi, hyperrec::EtaPi, hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, @@ -112,7 +113,7 @@ DECLARE_SOA_TABLE(DataHypCandsFlow, "AOD", "HYPCANDSFLOW", hyperrec::PsiTPC, hyperrec::MultTPC, hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, - hyperrec::IsMatter, + hyperrec::RunNumber, hyperrec::IsMatter, hyperrec::PtHe3, hyperrec::PhiHe3, hyperrec::EtaHe3, hyperrec::PtPi, hyperrec::PhiPi, hyperrec::EtaPi, hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, @@ -128,7 +129,7 @@ DECLARE_SOA_TABLE(MCHypCands, "AOD", "MCHYPCANDS", hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, - hyperrec::IsMatter, + hyperrec::RunNumber, hyperrec::IsMatter, hyperrec::PtHe3, hyperrec::PhiHe3, hyperrec::EtaHe3, hyperrec::PtPi, hyperrec::PhiPi, hyperrec::EtaPi, hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, @@ -157,7 +158,7 @@ DECLARE_SOA_TABLE(DataHypCandsWColl, "AOD", "HYPCANDSWCOLL", hyperrec::CollisionId, hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, - hyperrec::IsMatter, + hyperrec::RunNumber, hyperrec::IsMatter, hyperrec::PtHe3, hyperrec::PhiHe3, hyperrec::EtaHe3, hyperrec::PtPi, hyperrec::PhiPi, hyperrec::EtaPi, hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, diff --git a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx index ba4b925f7d9..eaf10bb9bbd 100644 --- a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx @@ -687,7 +687,7 @@ struct hyperRecoTask { float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; outputDataTable(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), collision.posX(), collision.posY(), collision.posZ(), - hypCand.isMatter, + mRunNumber, hypCand.isMatter, hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), hypCand.recoPtPi(), hypCand.recoPhiPi(), hypCand.recoEtaPi(), hypCand.decVtx[0], hypCand.decVtx[1], hypCand.decVtx[2], @@ -722,7 +722,7 @@ struct hyperRecoTask { collision.psiFT0C(), collision.multFT0C(), collision.qFT0C(), collision.psiTPC(), collision.multTPC(), collision.posX(), collision.posY(), collision.posZ(), - hypCand.isMatter, + mRunNumber, hypCand.isMatter, hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), hypCand.recoPtPi(), hypCand.recoPhiPi(), hypCand.recoEtaPi(), hypCand.decVtx[0], hypCand.decVtx[1], hypCand.decVtx[2], @@ -750,7 +750,7 @@ struct hyperRecoTask { float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; outputDataTableWithCollID(hypCand.collisionID, collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), collision.posX(), collision.posY(), collision.posZ(), - hypCand.isMatter, + mRunNumber, hypCand.isMatter, hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), hypCand.recoPtPi(), hypCand.recoPhiPi(), hypCand.recoEtaPi(), hypCand.decVtx[0], hypCand.decVtx[1], hypCand.decVtx[2], @@ -786,7 +786,7 @@ struct hyperRecoTask { float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; outputMCTable(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), collision.posX(), collision.posY(), collision.posZ(), - hypCand.isMatter, + mRunNumber, hypCand.isMatter, hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), hypCand.recoPtPi(), hypCand.recoPhiPi(), hypCand.recoEtaPi(), hypCand.decVtx[0], hypCand.decVtx[1], hypCand.decVtx[2], @@ -861,7 +861,7 @@ struct hyperRecoTask { } outputMCTable(centFT0A, centFT0C, centFT0M, - -1, -1, -1, + mRunNumber, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, From 4b999136f3be3f3e834cf830b8edc4a3c8fb6fc3 Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Fri, 14 Nov 2025 05:58:44 +0100 Subject: [PATCH 36/48] [PWGLF] namespace correction (#13807) Co-authored-by: nkaratze --- PWGLF/Tasks/Strangeness/v0ptinvmassplots.cxx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/PWGLF/Tasks/Strangeness/v0ptinvmassplots.cxx b/PWGLF/Tasks/Strangeness/v0ptinvmassplots.cxx index 656cc9350d8..bd3d20a1a0f 100644 --- a/PWGLF/Tasks/Strangeness/v0ptinvmassplots.cxx +++ b/PWGLF/Tasks/Strangeness/v0ptinvmassplots.cxx @@ -39,6 +39,11 @@ This analysis includes three processes, one for Real Data and two for MC at the #include #include +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + // namespace to be used for pt plots and bins namespace pthistos { @@ -52,10 +57,6 @@ std::vector> kaonSplit; std::vector> lambdaSplit; std::vector> antilambdaSplit; } // namespace pthistos -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::constants::physics; struct V0PtInvMassPlots { // Histogram Registries @@ -673,7 +674,7 @@ struct V0PtInvMassPlots { // Defining the type of the daughter tracks using DaughterTracks = soa::Join; - o2::framework::Service pdgDB; + Service pdgDB; void genMCProcess( aod::McCollisions::iterator const& mcCollisions, From 552eb7b604ba18fb3c0de2d7492223f83a6cb550 Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Fri, 14 Nov 2025 08:16:27 +0100 Subject: [PATCH 37/48] [PWGHF] taskFlowCharmHadrons: Separate trees (#13800) Co-authored-by: ALICE Action Bot --- PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx | 46 +++++++++++++----------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx b/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx index 615437bb6b6..a42089754dc 100644 --- a/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx +++ b/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx @@ -66,15 +66,24 @@ namespace full { DECLARE_SOA_COLUMN(M, m, float); //! Invariant mass of candidate (GeV/c2) DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of candidate (GeV/c) -// ML scores DECLARE_SOA_COLUMN(MlScore0, mlScore0, float); //! ML score of the first configured index DECLARE_SOA_COLUMN(MlScore1, mlScore1, float); //! ML score of the second configured index +DECLARE_SOA_COLUMN(ScalarProd, scalarProd, float); //! Scalar product +DECLARE_SOA_COLUMN(Cent, cent, float); //! Centrality } // namespace full -DECLARE_SOA_TABLE(HfCandPtCent, "AOD", "HFCANDPTCENT", +DECLARE_SOA_TABLE(HfCandMPtInfos, "AOD", "HFCANDMPTINFO", full::M, full::Pt, full::MlScore0, full::MlScore1); + +DECLARE_SOA_TABLE(HfCandFlowInfos, "AOD", "HFCANDFLOWINFO", + full::M, + full::Pt, + full::MlScore0, + full::MlScore1, + full::ScalarProd, + full::Cent); } // namespace o2::aod enum DecayChannel { DplusToPiKPi = 0, @@ -98,7 +107,8 @@ enum QvecEstimator { FV0A = 0, TPCTot }; struct HfTaskFlowCharmHadrons { - Produces rowCandidateMassPtMlScores; + Produces rowCandMassPtMl; + Produces rowCandMassPtMlSpCent; Configurable harmonic{"harmonic", 2, "harmonic number"}; Configurable qvecDetector{"qvecDetector", 3, "Detector for Q vector estimation (FV0A: 0, FT0M: 1, FT0A: 2, FT0C: 3, TPC Pos: 4, TPC Neg: 5, TPC Tot: 6)"}; @@ -108,7 +118,9 @@ struct HfTaskFlowCharmHadrons { Configurable centralityMax{"centralityMax", 100., "Maximum centrality accepted in SP/EP computation (not applied in resolution process)"}; Configurable storeEP{"storeEP", false, "Flag to store EP-related axis"}; Configurable storeMl{"storeMl", false, "Flag to store ML scores"}; - Configurable fillMassPtMlTree{"fillMassPtMlTree", false, "Flag to fill mass and pt tree"}; + Configurable fillMassPtMlTree{"fillMassPtMlTree", false, "Flag to fill mass, pt and ML scores tree"}; + Configurable fillMassPtMlSpCentTree{"fillMassPtMlSpCentTree", false, "Flag to fill mass, pt, ML scores, SP and centrality tree"}; + Configurable fillSparse{"fillSparse", true, "Flag to fill sparse"}; 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 storeResoOccu{"storeResoOccu", false, "Flag to store Occupancy in resolution ThnSparse"}; @@ -296,20 +308,6 @@ struct HfTaskFlowCharmHadrons { } }; // end init - /// Fill the mass, pt and ML scores of a candidate - /// \param mass is the candidate mass - /// \param pt is the candidate transverse momentum - /// \param mlscore0 is the first ML score - /// \param mlscore1 is the second ML score - void fillMassPt(const float mass, const float pt, const float mlscore0, const float mlscore1) - { - rowCandidateMassPtMlScores( - mass, - pt, - mlscore0, - mlscore1); - } - /// Compute the Q vector for the candidate's tracks /// \param cand is the candidate /// \param tracksQx is the X component of the Q vector for the tracks @@ -697,15 +695,21 @@ struct HfTaskFlowCharmHadrons { float const scalprodCand = cosNPhi * xQVec + sinNPhi * yQVec; float const cosDeltaPhi = std::cos(harmonic * (phiCand - evtPl)); - if (fillMassPtMlTree && storeMl) { + if (fillMassPtMlTree || fillMassPtMlSpCentTree) { if (downSampleFactor < 1.) { float const pseudoRndm = ptCand * 1000. - static_cast(ptCand * 1000); if (ptCand < ptDownSampleMax && pseudoRndm >= downSampleFactor) { continue; } } - fillMassPt(massCand, ptCand, outputMl[0], outputMl[1]); - } else { + if (fillMassPtMlTree) { + rowCandMassPtMl(massCand, ptCand, outputMl[0], outputMl[1]); + } + if (fillMassPtMlSpCentTree) { + rowCandMassPtMlSpCent(massCand, ptCand, outputMl[0], outputMl[1], scalprodCand, cent); + } + } + if (fillSparse) { fillThn(massCand, ptCand, cent, cosNPhi, sinNPhi, cosDeltaPhi, scalprodCand, outputMl, occupancy, hfevflag); } } From b3cef222641c73c70d51bd184e8bd7c659c85d2d Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Fri, 14 Nov 2025 10:34:14 +0100 Subject: [PATCH 38/48] [PWGHF] Bugfix taskLc: check mlProb vector size for correct PKPi/PiKP hypothesis (#13808) --- PWGHF/D2H/Tasks/taskLc.cxx | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskLc.cxx b/PWGHF/D2H/Tasks/taskLc.cxx index 3ed467d6d98..6445108a71d 100644 --- a/PWGHF/D2H/Tasks/taskLc.cxx +++ b/PWGHF/D2H/Tasks/taskLc.cxx @@ -462,18 +462,18 @@ struct HfTaskLc { if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); } - double massLc(-1); double outputBkg(-1), outputPrompt(-1), outputFD(-1); const float properLifetime = HfHelper::ctLc(candidate) * CtToProperLifetimePs; auto fillTHnRecSig = [&](bool isPKPi) { - massLc = isPKPi ? HfHelper::invMassLcToPKPi(candidate) : HfHelper::invMassLcToPiKP(candidate); + const auto massLc = isPKPi ? HfHelper::invMassLcToPKPi(candidate) : HfHelper::invMassLcToPiKP(candidate); if constexpr (FillMl) { - if (candidate.mlProbLcToPKPi().size() == NumberOfMlClasses) { - outputBkg = isPKPi ? candidate.mlProbLcToPKPi()[MlClassBackground] : candidate.mlProbLcToPiKP()[MlClassBackground]; /// bkg score - outputPrompt = isPKPi ? candidate.mlProbLcToPKPi()[MlClassPrompt] : candidate.mlProbLcToPiKP()[MlClassPrompt]; /// prompt score - outputFD = isPKPi ? candidate.mlProbLcToPKPi()[MlClassNonPrompt] : candidate.mlProbLcToPiKP()[MlClassNonPrompt]; /// non-prompt score + const auto& mlProb = isPKPi ? candidate.mlProbLcToPKPi() : candidate.mlProbLcToPiKP(); + if (mlProb.size() == NumberOfMlClasses) { + outputBkg = mlProb[MlClassBackground]; /// bkg score + outputPrompt = mlProb[MlClassPrompt]; /// prompt score + outputFD = mlProb[MlClassNonPrompt]; /// non-prompt score } /// Fill the ML outputScores and variables of candidate std::vector valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast(numPvContributors), ptRecB, static_cast(originType)}; @@ -655,18 +655,18 @@ struct HfTaskLc { if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); } - double massLc(-1); double outputBkg(-1), outputPrompt(-1), outputFD(-1); const float properLifetime = HfHelper::ctLc(candidate) * CtToProperLifetimePs; auto fillTHnData = [&](bool isPKPi) { - massLc = isPKPi ? HfHelper::invMassLcToPKPi(candidate) : HfHelper::invMassLcToPiKP(candidate); + const auto massLc = isPKPi ? HfHelper::invMassLcToPKPi(candidate) : HfHelper::invMassLcToPiKP(candidate); if constexpr (FillMl) { - if (candidate.mlProbLcToPKPi().size() == NumberOfMlClasses) { - outputBkg = isPKPi ? candidate.mlProbLcToPKPi()[MlClassBackground] : candidate.mlProbLcToPiKP()[MlClassBackground]; /// bkg score - outputPrompt = isPKPi ? candidate.mlProbLcToPKPi()[MlClassPrompt] : candidate.mlProbLcToPiKP()[MlClassPrompt]; /// prompt score - outputFD = isPKPi ? candidate.mlProbLcToPKPi()[MlClassNonPrompt] : candidate.mlProbLcToPiKP()[MlClassNonPrompt]; /// non-prompt score + const auto& mlProb = isPKPi ? candidate.mlProbLcToPKPi() : candidate.mlProbLcToPiKP(); + if (mlProb.size() == NumberOfMlClasses) { + outputBkg = mlProb[MlClassBackground]; /// bkg score + outputPrompt = mlProb[MlClassPrompt]; /// prompt score + outputFD = mlProb[MlClassNonPrompt]; /// non-prompt score } /// Fill the ML outputScores and variables of candidate std::vector valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast(numPvContributors)}; From 9c4217fdd01c3122e615bbaff361eaa952f03848 Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Fri, 14 Nov 2025 11:18:55 +0100 Subject: [PATCH 39/48] [PWGJE] Fix event selection bits and added histograms for MC particles (#13810) Co-authored-by: Arvind Khuntia --- PWGJE/Tasks/nucleiInJets.cxx | 133 ++++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 50 deletions(-) diff --git a/PWGJE/Tasks/nucleiInJets.cxx b/PWGJE/Tasks/nucleiInJets.cxx index cea25efdae7..deb07124d3c 100644 --- a/PWGJE/Tasks/nucleiInJets.cxx +++ b/PWGJE/Tasks/nucleiInJets.cxx @@ -117,6 +117,7 @@ struct nucleiInJets { Configurable centralityType{"centralityType", 0, "0: FT0M, 1: FT0C, 2: FV0A"}; Configurable> cfgOccupancyRange{"cfgOccupancyRange", {0, 1000}, "Occupancy selection"}; Configurable useOccupancy{"useOccupancy", true, "Events with custom occupancy selection"}; + Configurable useEtaSelForEffDen{"useEtaSelForEffDen", false, "eta selection for gen particles"}; Configurable cfgtrkMinPt{"cfgtrkMinPt", 0.15, "set track min pT"}; Configurable cfgtrkMaxEta{"cfgtrkMaxEta", 0.8, "set track max Eta"}; @@ -158,6 +159,7 @@ struct nucleiInJets { Configurable useTOFVeto{"useTOFVeto", false, "true: use TOF veto, false: no TOF veto"}; Configurable isRequireHitsInITSLayers{"isRequireHitsInITSLayers", true, "true: at least one hit in the its inner layes"}; Configurable useMcC{"useMcC", true, "use mcC"}; + Configurable useRapidityCutForPID{"useRapidityCutForPID", false, "true: use rapidity cut for PID, false: no rapidity cut for PID"}; Configurable addpik{"addpik", true, "add pion and kaon hist"}; ConfigurableAxis binsDCA{"binsDCA", {400, -1.f, 1.f}, ""}; @@ -1380,8 +1382,8 @@ struct nucleiInJets { jetHist.fill(HIST("hNEventsInc"), 0.5); bool isSel8 = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("sel8")); - bool isSelNoSameBunchPileup = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("selNoSameBunchPileup")); - bool isSelIsGoodZvtxFT0vsPV = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("selIsGoodZvtxFT0vsPV")); + bool isSelNoSameBunchPileup = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("NoSameBunchPileup")); + bool isSelIsGoodZvtxFT0vsPV = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("IsGoodZvtxFT0vsPV")); if (sel8Coll && !isSel8) return; @@ -1421,51 +1423,72 @@ struct nucleiInJets { if (!isTrackSelected(trk)) { continue; } + + auto rapidityData = [&](float m2z) { + const float rap = trk.rapidity(m2z); + return rap > std::abs(cfgtrkMaxRap); + }; + + auto prRapidityWithinRange = rapidityData(o2::constants::physics::MassProton); + auto deRapidityWithinRange = rapidityData(o2::constants::physics::MassDeuteron); + if (std::fabs(trk.eta()) > cfgtrkMaxEta) continue; if (trk.sign() > 0) { // particle info if (useTOFNsigmaPreSel && trk.hasTOF()) { - if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF && (!useRapidityCutForPID || prRapidityWithinRange)) { jetHist.fill(HIST("tracksInc/proton/h3PtVsProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); - if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) + } + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF && (!useRapidityCutForPID || deRapidityWithinRange)) { jetHist.fill(HIST("tracksInc/deuteron/h3PtVsDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); + } } else if (!useTOFNsigmaPreSel && !useTOFVeto) { - jetHist.fill(HIST("tracksInc/proton/h3PtVsProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); - jetHist.fill(HIST("tracksInc/deuteron/h3PtVsDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); - + if (!useRapidityCutForPID || prRapidityWithinRange) { + jetHist.fill(HIST("tracksInc/proton/h3PtVsProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); + } + if (!useRapidityCutForPID || deRapidityWithinRange) { + jetHist.fill(HIST("tracksInc/deuteron/h3PtVsDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); + } } else if (!useTOFNsigmaPreSel && useTOFVeto) { if (trk.hasTOF()) { if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) { - jetHist.fill(HIST("tracksInc/proton/h3PtVsProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); + if (!useRapidityCutForPID || prRapidityWithinRange) + jetHist.fill(HIST("tracksInc/proton/h3PtVsProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); } } else { - jetHist.fill(HIST("tracksInc/proton/h3PtVsProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); + if (!useRapidityCutForPID || prRapidityWithinRange) + jetHist.fill(HIST("tracksInc/proton/h3PtVsProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); } if (trk.hasTOF()) { if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) { - jetHist.fill(HIST("tracksInc/deuteron/h3PtVsDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); + if (!useRapidityCutForPID || deRapidityWithinRange) + jetHist.fill(HIST("tracksInc/deuteron/h3PtVsDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); } } else { - jetHist.fill(HIST("tracksInc/deuteron/h3PtVsDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); + if (!useRapidityCutForPID || deRapidityWithinRange) + jetHist.fill(HIST("tracksInc/deuteron/h3PtVsDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); } } if (addTOFplots && trk.hasTOF()) { float massTOF = trk.p() * std::sqrt(1.f / (trk.beta() * trk.beta()) - 1.f); if (!useTPCpreSel) { - jetHist.fill(HIST("tracksInc/proton/h2TOFmassProtonVsPt"), massTOF, trk.pt(), centrality); - jetHist.fill(HIST("tracksInc/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - MassProton * MassProton, trk.pt(), centrality); - jetHist.fill(HIST("tracksInc/proton/h2TofNsigmaProtonVsPt"), trk.tofNSigmaPr(), trk.pt(), centrality); - - jetHist.fill(HIST("tracksInc/deuteron/h2TOFmassDeuteronVsPt"), massTOF, trk.pt(), centrality); - jetHist.fill(HIST("tracksInc/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), centrality); - jetHist.fill(HIST("tracksInc/deuteron/h2TofNsigmaDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt(), centrality); + if (!useRapidityCutForPID || prRapidityWithinRange) { + jetHist.fill(HIST("tracksInc/proton/h2TOFmassProtonVsPt"), massTOF, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - MassProton * MassProton, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/proton/h2TofNsigmaProtonVsPt"), trk.tofNSigmaPr(), trk.pt(), centrality); + } + if (!useRapidityCutForPID || deRapidityWithinRange) { + jetHist.fill(HIST("tracksInc/deuteron/h2TOFmassDeuteronVsPt"), massTOF, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/deuteron/h2TofNsigmaDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt(), centrality); + } } else { - if (std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr) { + if (std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr && (!useRapidityCutForPID || prRapidityWithinRange)) { jetHist.fill(HIST("tracksInc/proton/h2TOFmassProtonVsPt"), massTOF, trk.pt(), centrality); jetHist.fill(HIST("tracksInc/proton/h2TOFmass2ProtonVsPt"), massTOF * massTOF - MassProton * MassProton, trk.pt(), centrality); jetHist.fill(HIST("tracksInc/proton/h2TofNsigmaProtonVsPt"), trk.tofNSigmaPr(), trk.pt(), centrality); } - if (std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe) { + if (std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe && (!useRapidityCutForPID || deRapidityWithinRange)) { jetHist.fill(HIST("tracksInc/deuteron/h2TOFmassDeuteronVsPt"), massTOF, trk.pt(), centrality); jetHist.fill(HIST("tracksInc/deuteron/h2TOFmass2DeuteronVsPt"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), centrality); jetHist.fill(HIST("tracksInc/deuteron/h2TofNsigmaDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt(), centrality); @@ -1473,61 +1496,64 @@ struct nucleiInJets { } } - if (cEnableProtonQA && std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr) { + if (cEnableProtonQA && std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr && (!useRapidityCutForPID || prRapidityWithinRange)) { jetHist.fill(HIST("tracksInc/proton/dca/after/hDCAxyVsPtProton"), trk.dcaXY(), trk.pt(), centrality); jetHist.fill(HIST("tracksInc/proton/dca/after/hDCAzVsPtProton"), trk.dcaZ(), trk.pt(), centrality); } - if (cEnableDeuteronQA && std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe) { + if (cEnableDeuteronQA && std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe && (!useRapidityCutForPID || deRapidityWithinRange)) { jetHist.fill(HIST("tracksInc/deuteron/dca/after/hDCAxyVsPtDeuteron"), trk.dcaXY(), trk.pt(), centrality); jetHist.fill(HIST("tracksInc/deuteron/dca/after/hDCAzVsPtDeuteron"), trk.dcaZ(), trk.pt(), centrality); } } else { // anti-particle info if (useTOFNsigmaPreSel && trk.hasTOF()) { - if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF && (!useRapidityCutForPID || prRapidityWithinRange)) jetHist.fill(HIST("tracksInc/antiProton/h3PtVsantiProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); - if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF && (!useRapidityCutForPID || deRapidityWithinRange)) jetHist.fill(HIST("tracksInc/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); } else if (!useTOFNsigmaPreSel && !useTOFVeto) { - jetHist.fill(HIST("tracksInc/antiProton/h3PtVsantiProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); - jetHist.fill(HIST("tracksInc/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); + if (!useRapidityCutForPID || prRapidityWithinRange) + jetHist.fill(HIST("tracksInc/antiProton/h3PtVsantiProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); + if (!useRapidityCutForPID || deRapidityWithinRange) + jetHist.fill(HIST("tracksInc/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); } else if (!useTOFNsigmaPreSel && useTOFVeto) { if (trk.hasTOF()) { - if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF) { + if (std::abs(trk.tofNSigmaPr()) < cfgnTPCPIDPrTOF && (!useRapidityCutForPID || prRapidityWithinRange)) { jetHist.fill(HIST("tracksInc/antiProton/h3PtVsantiProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); } } else { - jetHist.fill(HIST("tracksInc/antiProton/h3PtVsantiProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); + if (!useRapidityCutForPID || prRapidityWithinRange) + jetHist.fill(HIST("tracksInc/antiProton/h3PtVsantiProtonNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaPr(), centrality); } if (trk.hasTOF()) { - if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF) { + if (std::abs(trk.tofNSigmaDe()) < cfgnTPCPIDDeTOF && (!useRapidityCutForPID || deRapidityWithinRange)) { jetHist.fill(HIST("tracksInc/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); } } else { - jetHist.fill(HIST("tracksInc/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); + if (!useRapidityCutForPID || deRapidityWithinRange) + jetHist.fill(HIST("tracksInc/antiDeuteron/h3PtVsantiDeuteronNSigmaTPCVsPt"), trk.pt(), trk.tpcNSigmaDe(), centrality); } } if (addTOFplots && trk.hasTOF()) { float massTOF = trk.p() * std::sqrt(1.f / (trk.beta() * trk.beta()) - 1.f); if (!useTPCpreSel) { - jetHist.fill(HIST("tracksInc/antiProton/h2TOFmassantiProtonVsPt"), massTOF, trk.pt(), centrality); - jetHist.fill(HIST("tracksInc/antiProton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProton * MassProton, trk.pt(), centrality); - jetHist.fill(HIST("tracksInc/antiProton/h2TofNsigmaantiProtonVsPt"), trk.tofNSigmaPr(), trk.pt(), centrality); - - jetHist.fill(HIST("tracksInc/antiDeuteron/h2TOFmassantiDeuteronVsPt"), massTOF, trk.pt(), centrality); - jetHist.fill(HIST("tracksInc/antiDeuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), centrality); - jetHist.fill(HIST("tracksInc/antiDeuteron/h2TofNsigmaantiDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt(), centrality); - } else { - if (std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr) { + if (!useRapidityCutForPID || prRapidityWithinRange) { jetHist.fill(HIST("tracksInc/antiProton/h2TOFmassantiProtonVsPt"), massTOF, trk.pt(), centrality); jetHist.fill(HIST("tracksInc/antiProton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProton * MassProton, trk.pt(), centrality); jetHist.fill(HIST("tracksInc/antiProton/h2TofNsigmaantiProtonVsPt"), trk.tofNSigmaPr(), trk.pt(), centrality); } - if (std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe) { + if (!useRapidityCutForPID || deRapidityWithinRange) { jetHist.fill(HIST("tracksInc/antiDeuteron/h2TOFmassantiDeuteronVsPt"), massTOF, trk.pt(), centrality); jetHist.fill(HIST("tracksInc/antiDeuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), centrality); jetHist.fill(HIST("tracksInc/antiDeuteron/h2TofNsigmaantiDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt(), centrality); - } else { + } + } else { + if (std::abs(trk.tpcNSigmaPr()) < cfgnTPCPIDPr && (!useRapidityCutForPID || prRapidityWithinRange)) { + jetHist.fill(HIST("tracksInc/antiProton/h2TOFmassantiProtonVsPt"), massTOF, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/antiProton/h2TOFmass2antiProtonVsPt"), massTOF * massTOF - MassProton * MassProton, trk.pt(), centrality); + jetHist.fill(HIST("tracksInc/antiProton/h2TofNsigmaantiProtonVsPt"), trk.tofNSigmaPr(), trk.pt(), centrality); + } + if (std::abs(trk.tpcNSigmaDe()) < cfgnTPCPIDDe && (!useRapidityCutForPID || deRapidityWithinRange)) { jetHist.fill(HIST("tracksInc/antiDeuteron/h2TOFmassantiDeuteronVsPt"), massTOF, trk.pt(), centrality); jetHist.fill(HIST("tracksInc/antiDeuteron/h2TOFmass2antiDeuteronVsPt"), massTOF * massTOF - MassDeuteron * MassDeuteron, trk.pt(), centrality); jetHist.fill(HIST("tracksInc/antiDeuteron/h2TofNsigmaantiDeuteronVsPt"), trk.tofNSigmaDe(), trk.pt(), centrality); @@ -2011,8 +2037,8 @@ struct nucleiInJets { jetHist.fill(HIST("recInc/eventStat"), 0.5); bool isSel8 = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("sel8")); - bool isSelNoSameBunchPileup = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("selNoSameBunchPileup")); - bool isSelIsGoodZvtxFT0vsPV = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("selIsGoodZvtxFT0vsPV")); + bool isSelNoSameBunchPileup = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("NoSameBunchPileup")); + bool isSelIsGoodZvtxFT0vsPV = jetderiveddatautilities::selectCollision(coll, jetderiveddatautilities::initialiseEventSelectionBits("IsGoodZvtxFT0vsPV")); if (sel8Coll && !isSel8) return; @@ -2065,13 +2091,20 @@ struct nucleiInJets { // require mc getProcess to get Decay and Material secondaries int particleOriginType = 0; auto isMcPrimary = false; - // auto isMcTransport = false; // auto isMcSecondaryFromMaterial = false; auto isMcSecondaryFromWeakDecay = false; - if (mcTrack.isPhysicalPrimary()) { - isMcPrimary = true; + auto isProdByGen = false; + auto isFromWeakDecay = false; + + isMcPrimary = mcTrack.isPhysicalPrimary(); + isProdByGen = mcTrack.producedByGenerator(); + isFromWeakDecay = mcTrack.getProcess() == TMCProcess::kPDecay; + + if (isMcPrimary) { particleOriginType = 1; - } else if (mcTrack.getGenStatusCode() == -1) { - // isMcTransport = true; - particleOriginType = 2; + } else if (!isProdByGen) { + particleOriginType = 2; // from transport + if (isFromWeakDecay) { + particleOriginType = 3; // from weak decay + } } // Fill DCAxy histograms @@ -2171,7 +2204,7 @@ struct nucleiInJets { for (const auto& mcParticle : mcParticles_per_coll) { if (!mcParticle.isPhysicalPrimary()) continue; - if (std::fabs(mcParticle.eta()) > cfgtrkMaxEta) + if (std::fabs(mcParticle.eta()) > cfgtrkMaxEta && useEtaSelForEffDen) continue; if (std::fabs(mcParticle.y()) > cfgtrkMaxRap) continue; From 79fe37a0a1dfbeecb8e4065f9458a1d48bb822c9 Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Fri, 14 Nov 2025 18:22:51 +0800 Subject: [PATCH 40/48] [PWGHF] Remove Cent from hCorrel2DVsPtGlobalRegion (#13826) --- .../HFC/Tasks/.taskCorrelationLcHadrons.cxx.swp | Bin 0 -> 16384 bytes PWGHF/HFC/Tasks/taskCorrelationLcHadrons.cxx | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 PWGHF/HFC/Tasks/.taskCorrelationLcHadrons.cxx.swp diff --git a/PWGHF/HFC/Tasks/.taskCorrelationLcHadrons.cxx.swp b/PWGHF/HFC/Tasks/.taskCorrelationLcHadrons.cxx.swp new file mode 100644 index 0000000000000000000000000000000000000000..5c31952e020cfeffffe2ed9ff3f1100befb63fde GIT binary patch literal 16384 zcmeHOYm8(?6~4$r0TG0R1Tj+dBI%Kt?%CNypl5bqw|8Dk_fBWKcUQn=sJ^$lyO`Ve z-rUFR^bDgh1b(UEj|s#GKYYYQu~7nwy_3&d-*M4eBj>MIWDK z+jW^qeQsM7eV!VwZFvQKb# z$X{3T8&&zE8To5Uezhw9MMnOrl3%0BU&zS+rQ}zs^2^i!qH+9F$*)uLk&OHwN}f~l zYDWHwl20qSosqw+wPSWJdm?lHaQ2 zPiN#WDEYjSUw&@*5cU68C7)CBJ2G-rJp46eV93CbfguA!28Ij_85lA!WMIg^kbxls z|Dz00L(`7J_8*Ew5a0ht`Tut>)wC`!3ETwy4d8vi zOYhdS7l9uGUjZHfP6IjM&lhXj6Tp2y0~iBFfj2JFv}b_Ff%||Oun3F-=Kw#wP}9B+ zd>Uv2W#Ag%<#%b?Q^4cEg8&DP0@nfrxD@HFrg@EzbW;9=kafC7uaL0}5V z1Lp$IT%c*+0v-e?a5wNF;JNcP?eoAoPzGK(PtzU+?gsV)uOn~%3Ge`L3-B89@NWXE zz>UC%f#<=s;QI$r@_p96qvKkHPq^h1tL7i(mY2FW;gN&nrb(?>BnE47i;KGy#BPxl zru(+*k(TWe&!?6_U4uA&lUoFTK-mg)IfcqD^*n+eTD%>&v}rO=)4~oLb>HPy8_mV9 zsy@eXOJmkRhq-E*w3#(ZEZZ7$T)XS|WM74Ln+9FdCv%en6dY%|ozmdq&%LUUHq^o% zQ+DjthCU6U9eY!uNDxiQSTgp}@DdBr!7(?e&pa}ajT&`*u7mG{(5+NCQMEz5*15r& zVot$_r=GpRmD^TT%($%Fj-5f2ZP$jHQ42h|tPL+4R6V-MBO1g`v3p{UFw>{C4wucj zzrGKS>U8+VUF#vY8)N(WO5-jzNZzH!$RM+%-Wi|9dYMnNO2eW=;~-rTgVm*V=eB(g zN7r-gWKkHV-!-u@(1tn(Taz{?pxT@(6tj@JKM2dm-?Np zDotwIK5pq|U@$TjZl=?zl8~!(NtbnPw>M2Bkw&THb*RgXCC7JD&2-N0PIP`|8fce}O)d&T+g z8~4i^toT-z+;sfzWiCMa>2T-bRrHoMqxslHriCgKjP--e7N z3Z2|`O{#(Ea|d@txsU1Cw(86Zv;0{5mX#3{v7!hujxe2WtxpW6*sltwFzsS?a;deD z3-79)@VV&~1MwM6cz?&qmDW_%bZj=Ldcs<&_EwaIJtWm7$qSajR_n{W+r`@4O{;Pg zjl=}*sg>XqKIR4kXEtl*A(K;Ya36A}LR)ON9Qcy{cw^%Cu~{oV7?rA5*uM30>n|bc*OmPn~#(wZpTJi0jS>?+h&SF_SN|QBu{%1hX<6 z$1@^ZRT~kww64WXCfi}81FlJ9tRlV-nq7_r!S|TiBEC@BBliR@_Y5xQtRV6O9NySQ z4IxM6W{<3J*AH-Hw?s>kB=~_xDE?Vw0X5yWy#ltnSa=xKqT8kxUz2yWg|-D)>o{gl z9REIo10t?`TOK3jnd8TZVI!=yY@eK=d&ecKgDyxtttiLzv>(E&mKoUxH^t zZ1%hvh>-_aIIe7o(RDpBa$(uru@eOBGZ(|G1x*YD_6U;>nTU0Hy90K_SX6Xk_F^hU z9|%~OyTT0FeVsAV@qNcD6~jyLWA;Sh3~LsY-xV>Eo>VD=Dgyy0c9+PIMA)%SnCeNL z<+#bj`2L&6CdMbmLy`rJo0$M4o>? za1-z>^823y_XA_VHNX|X?~&U-477lYfnOn~e-ijU@LAyf!1s{HKLI=jd;xd__#Ds! zjsoWaFCwS^Bk(m~9Vi07MGpT<;7Q;!zyk0p^79vf=Yi{h%Ylo4hmfC-10Mjc1pb8l z{1d=cz%$6r8E`f5Bjn}Z1{~mO;8Ngx;C1BYuK+IrI&e3z1mpk${0tlko}T)Th9R1AFd!r<$IwW|rAYNJE|C{K6_@5!zUgBgL15cksgvAPSqohSmkBta>1Vzzj z@;m+1|11bqF(GyoGe5sjZ{%}{b;VB27xq?l?AOO^3#Q_QM^5ZZD3xh`!SVAWvUAb3 z_~9**PsBFXJh!BR{0KRCkcgdMo?WHVqLejy4l9*n?IUDelX~PwIHKt9Jy`oTni{I^ zx3eQ?3g3H-P0tE0m*WzVEJy*=J)i;Fd}8S`C4?-hn^BfrMuu zXEsCt8)nb2cA#K1 zU@H)mO3N7?fir?pMy`!0%}z`d=0@&Q@LAWv@@I*7iF#9>O-rStHn*mz=tS5fM~4>` zvOo+FtOK3nlhN}OiIsSKje&k8x#5Py*8UBW zdzh-k3Nn3=#GW;aWm3_TmdV(Xr`?Yd%jLgdl+ucAM=AHT@Ws;B2#}f&%*T?o3 zMoIJ`k72QL6GFCH)5-D@n;6{C3C}fz)9}!YbUKnI8>TpzvGm245n|~g3W(M#DJ9Qd zG*gJ6<$*0TM|ewI8_9xgtHb$5I4A(%fx1H|pjm1m7Os=IphzJ2pq zO~}s2K%~&?KfN+)v&UCT9GzbhSD&+e{AC_j~Ye7Mhsd^cvW-bl>tCiygXGN#a2)$4y==(HIST("hCorrel2DVsPtSidebandLeft"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtSidebandRight"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtSignalRegion"))->Sumw2(); @@ -516,7 +516,7 @@ struct HfTaskCorrelationLcHadrons { } // check if correlation entry belongs to signal region, sidebands or is outside both, and fill correlation plots if (storeMass) { - registry.fill(HIST("hCorrel2DVsPtGlobalRegion"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, cent, massLc, efficiencyWeight); + registry.fill(HIST("hCorrel2DVsPtGlobalRegion"), deltaPhi, deltaEta, ptLc, ptHadron, poolBin, massLc, efficiencyWeight); continue; } if (massLc > signalRegionInner->at(ptBinLc) && massLc < signalRegionOuter->at(ptBinLc)) { From 651af9d2f4a9ba22f9d97f1205f492230d1263ba Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Fri, 14 Nov 2025 12:51:47 +0100 Subject: [PATCH 41/48] [PWGLF] Fix event mixing bug for two daughter mixing (#13809) --- .../Strangeness/lambdaspincorrderived.cxx | 181 +++++++++--------- 1 file changed, 94 insertions(+), 87 deletions(-) diff --git a/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx b/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx index 00916c9c709..19f5d11e333 100644 --- a/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx +++ b/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx @@ -531,7 +531,6 @@ struct lambdaspincorrderived { const ROOT::Math::PtEtaPhiMVector& daughpart1, const ROOT::Math::PtEtaPhiMVector& daughpart2, int datatype, float mixpairweight, int mixedLeg) { - auto lambda1Mass = 0.0; auto lambda2Mass = 0.0; if (!usePDGM) { @@ -622,35 +621,29 @@ struct lambdaspincorrderived { double epsWeightMixedLeg = 1.0; if (useweight && datatype == 1) { // only for ME if (mixedLeg == 1) { - // Only leg 1 is from the mixing pool double w1 = 1.0; - if (tag1 == 0) { // Λ - if (hweight1) { - w1 = hweight1->GetBinContent(hweight1->FindBin(dphi1, deta1, pt1)); - } - } else { // Λbar - if (hweight4) { - w1 = hweight4->GetBinContent(hweight4->FindBin(dphi1, deta1, pt1)); - } - } - if (w1 > 0.0 && std::isfinite(w1)) { - epsWeightMixedLeg = w1; + if (tag1 == 0 && tag2 == 0) { + w1 = hweight1->GetBinContent(hweight1->FindBin(dphi1, deta1, pt1)); + } else if (tag1 == 0 && tag2 == 1) { + w1 = hweight2->GetBinContent(hweight2->FindBin(dphi1, deta1, pt1)); + } else if (tag1 == 1 && tag2 == 0) { + w1 = hweight3->GetBinContent(hweight3->FindBin(dphi1, deta1, pt1)); + } else if (tag1 == 1 && tag2 == 1) { + w1 = hweight4->GetBinContent(hweight4->FindBin(dphi1, deta1, pt1)); } + epsWeightMixedLeg = w1; } else if (mixedLeg == 2) { - // Only leg 2 is from the mixing pool double w2 = 1.0; - if (tag2 == 0) { // Λ - if (hweight12) { - w2 = hweight12->GetBinContent(hweight12->FindBin(dphi2, deta2, pt2)); - } - } else { // Λbar - if (hweight42) { - w2 = hweight42->GetBinContent(hweight42->FindBin(dphi2, deta2, pt2)); - } - } - if (w2 > 0.0 && std::isfinite(w2)) { - epsWeightMixedLeg = w2; + if (tag1 == 0 && tag2 == 0) { + w2 = hweight12->GetBinContent(hweight12->FindBin(dphi2, deta1, pt2)); + } else if (tag1 == 0 && tag2 == 1) { + w2 = hweight22->GetBinContent(hweight22->FindBin(dphi2, deta1, pt2)); + } else if (tag1 == 1 && tag2 == 0) { + w2 = hweight32->GetBinContent(hweight32->FindBin(dphi2, deta1, pt2)); + } else if (tag1 == 1 && tag2 == 1) { + w2 = hweight42->GetBinContent(hweight42->FindBin(dphi2, deta2, pt2)); } + epsWeightMixedLeg = w2; } } @@ -697,19 +690,19 @@ struct lambdaspincorrderived { } else if (datatype == 1) { double weight = mixpairweight; if (useweight) { - if (usebothweight) { - weight = mixpairweight / (epsWeightMixedLeg); - } else { - weight = mixpairweight / (epsWeightMixedLeg); - } + weight = mixpairweight / (epsWeightMixedLeg); } if (weight <= 0.0) { weight = 1.0; } + // LOGF(info, Form("Getting alignment offsets from the CCDB...%2.2f",epsWeightMixedLeg)); histos.fill(HIST("hPtYMix"), particle1.Pt(), particle1.Rapidity(), weight); if (tag1 == 0 && tag2 == 0) { - histos.fill(HIST("ME_LL"), dphi1, deta1, pt1, mixpairweight); - histos.fill(HIST("ME_LL2"), dphi2, deta2, pt2, mixpairweight); + if (mixedLeg == 1) { + histos.fill(HIST("ME_LL"), dphi1, deta1, pt1, weight); + } else if (mixedLeg == 2) { + histos.fill(HIST("ME_LL2"), dphi2, deta2, pt2, weight); + } histos.fill(HIST("hSparseLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); if (useAdditionalHisto) { histos.fill(HIST("hSparseRapLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, weight); @@ -717,8 +710,11 @@ struct lambdaspincorrderived { histos.fill(HIST("hSparsePairMassLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), weight); } } else if (tag1 == 0 && tag2 == 1) { - histos.fill(HIST("ME_LAL"), dphi1, deta1, pt1, mixpairweight); - histos.fill(HIST("ME_LAL2"), dphi2, deta2, pt2, mixpairweight); + if (mixedLeg == 1) { + histos.fill(HIST("ME_LAL"), dphi1, deta1, pt1, weight); + } else if (mixedLeg == 2) { + histos.fill(HIST("ME_LAL2"), dphi2, deta2, pt2, weight); + } histos.fill(HIST("hSparseLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); if (useAdditionalHisto) { histos.fill(HIST("hSparseRapLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, weight); @@ -726,8 +722,11 @@ struct lambdaspincorrderived { histos.fill(HIST("hSparsePairMassLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), weight); } } else if (tag1 == 1 && tag2 == 0) { - histos.fill(HIST("ME_ALL"), dphi1, deta1, pt1, mixpairweight); - histos.fill(HIST("ME_ALL2"), dphi2, deta2, pt2, mixpairweight); + if (mixedLeg == 1) { + histos.fill(HIST("ME_ALL"), dphi1, deta1, pt1, weight); + } else if (mixedLeg == 2) { + histos.fill(HIST("ME_ALL2"), dphi2, deta2, pt2, weight); + } histos.fill(HIST("hSparseAntiLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); if (useAdditionalHisto) { histos.fill(HIST("hSparseRapAntiLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, weight); @@ -735,8 +734,11 @@ struct lambdaspincorrderived { histos.fill(HIST("hSparsePairMassAntiLambdaLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, pairDummy.M(), weight); } } else if (tag1 == 1 && tag2 == 1) { - histos.fill(HIST("ME_ALAL"), dphi1, deta1, pt1, mixpairweight); - histos.fill(HIST("ME_ALAL2"), dphi2, deta2, pt2, mixpairweight); + if (mixedLeg == 1) { + histos.fill(HIST("ME_ALAL"), dphi1, deta1, pt1, weight); + } else if (mixedLeg == 2) { + histos.fill(HIST("ME_ALAL2"), dphi2, deta2, pt2, weight); + } histos.fill(HIST("hSparseAntiLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, weight); if (useAdditionalHisto) { histos.fill(HIST("hSparseRapAntiLambdaAntiLambdaMixed"), particle1.M(), particle2.M(), cosThetaDiff, deltaRap, weight); @@ -1064,17 +1066,17 @@ struct lambdaspincorrderived { } PROCESS_SWITCH(lambdaspincorrderived, processMEV3, "Process data ME (first-leg, pair-3D maps)", false); + // ---------------------- minimal helpers you already use ---------------------- static constexpr int N_STATUS = 2; // v0Status ∈ {0,1} struct MixBinner { - // constructed from the task's configurables; φ is assumed already constrained into [0, 2π) float ptMin, ptMax, ptStep; float etaMin, etaMax, etaStep; float phiMin, phiMax, phiStep; - // Mass binning: [1.09, 1.14) with 50 bins (1e-3 GeV/c^2) + // if you want 1 mass bin (effectively “on/off”), keep nM_=1 static constexpr float mMin = 1.09f; - static constexpr float mMax = 1.14f; // exclusive + static constexpr float mMax = 1.14f; static constexpr int nM_ = 1; static constexpr float mStep = (mMax - mMin) / nM_; @@ -1088,7 +1090,6 @@ struct lambdaspincorrderived { ptStep = (ptStep > 0.f ? ptStep : 0.1f); etaStep = (etaStep > 0.f ? etaStep : 0.1f); phiStep = (phiStep > 0.f ? phiStep : 0.1f); - nPt_ = std::max(1, static_cast(std::floor((ptMax - ptMin) / ptStep + 0.5f))); nEta_ = std::max(1, static_cast(std::floor((etaMax - etaMin) / etaStep + 0.5f))); nPhi_ = std::max(1, static_cast(std::ceil((phiMax - phiMin) / phiStep))); @@ -1108,19 +1109,18 @@ struct lambdaspincorrderived { if (b < 0) return -1; if (b >= nBins) - b = nBins - 1; // clamp exact-top edge + b = nBins - 1; return b; } - inline int ptBin(float pt) const { return binFromValue(pt, ptMin, ptStep, nPt_); } - inline int etaBin(float eta) const { return binFromValue(eta, etaMin, etaStep, nEta_); } - inline int phiBin(float phi) const { return binFromValue(phi, phiMin, phiStep, nPhi_); } // φ already constrained upstream + inline int etaBin(float e) const { return binFromValue(e, etaMin, etaStep, nEta_); } + inline int phiBin(float ph) const { return binFromValue(ph, phiMin, phiStep, nPhi_); } inline int massBin(float m) const { return binFromValue(m, mMin, mStep, nM_); } }; struct BufferCand { - int64_t collisionIdx; // from col.index() - int64_t rowIndex; // global row id in V0s + int64_t collisionIdx; + int64_t rowIndex; uint8_t v0Status; uint16_t ptBin, etaBin, phiBin, mBin; }; @@ -1130,16 +1130,16 @@ struct lambdaspincorrderived { int64_t rowIndex; }; - // 6D key: (colBin, status, pt, eta, phi, mass) static inline size_t linearKey(int colBin, int statBin, int ptBin, int etaBin, int phiBin, int mBin, int nStatus, int nPt, int nEta, int nPhi, int nM) { return ((((((static_cast(colBin) * nStatus + statBin) * nPt + ptBin) * nEta + etaBin) * nPhi + phiBin) * nM + mBin)); } + + // ================================ processMEV4 ================================ void processMEV4(EventCandidates const& collisions, AllTrackCandidates const& V0s) { - // Build binner from your existing configurables MixBinner mb{ ptMin.value, ptMax.value, ptMix.value, // pT range & step v0eta.value, etaMix.value, // |eta| max & step @@ -1156,9 +1156,7 @@ struct lambdaspincorrderived { const size_t nKeys = static_cast(nCol) * nStat * nPt * nEta * nPhi * nM; std::vector> buffer(nKeys); - // ========================= - // PASS 1: fill 6D buffer - // ========================= + // ---------------- PASS 1: fill the 6D buffer ---------------- for (auto const& col : collisions) { const int colBin = colBinning.getBin(std::make_tuple(col.posz(), col.cent())); auto slice = V0s.sliceBy(tracksPerCollisionV0, col.index()); @@ -1178,9 +1176,7 @@ struct lambdaspincorrderived { if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0) continue; - const size_t key = linearKey(colBin, status, ptB, etaB, phiB, mB, - nStat, nPt, nEta, nPhi, nM); - + const size_t key = linearKey(colBin, status, ptB, etaB, phiB, mB, nStat, nPt, nEta, nPhi, nM); buffer[key].push_back(BufferCand{ .collisionIdx = static_cast(col.index()), .rowIndex = static_cast(t.globalIndex()), @@ -1192,7 +1188,7 @@ struct lambdaspincorrderived { } } - // Helper: get matches for a given candidate (for mixing one leg) + // small helper (kept local) to fetch matches for a given candidate from the same 6D bin auto makeMatchesFor = [&](auto const& cand, int colBinLocal, int64_t curColIdx) -> std::vector { @@ -1209,8 +1205,7 @@ struct lambdaspincorrderived { if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0) return matches; - const size_t key = linearKey(colBinLocal, status, ptB, etaB, phiB, mB, - nStat, nPt, nEta, nPhi, nM); + const size_t key = linearKey(colBinLocal, status, ptB, etaB, phiB, mB, nStat, nPt, nEta, nPhi, nM); auto const& binVec = buffer[key]; if (binVec.empty()) return matches; @@ -1218,24 +1213,13 @@ struct lambdaspincorrderived { matches.reserve(binVec.size()); for (const auto& bc : binVec) { if (bc.collisionIdx == curColIdx) - continue; // ensure different event + continue; // different event matches.push_back(MatchRef{bc.collisionIdx, bc.rowIndex}); } - - // Optionally cap number of matches by nEvtMixing - const int cap = nEvtMixing.value; - const int n = static_cast(matches.size()); - if (cap > 0 && n > cap) { - std::shuffle(matches.begin(), matches.end(), rng); - matches.resize(cap); - } - return matches; }; - // ========================= - // PASS 2: mixing over SE pairs (mix both legs) - // ========================= + // ---------------- PASS 2: loop over SE pairs and mix both legs ---------------- for (auto const& collision1 : collisions) { const int colBin = colBinning.getBin(std::make_tuple(collision1.posz(), collision1.cent())); auto poolA = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); @@ -1259,20 +1243,38 @@ struct lambdaspincorrderived { if (t1.pionIndex() == t2.protonIndex()) continue; - // matches for replacing leg 1 and leg 2 - auto matches1 = makeMatchesFor(t1, colBin, curColId); // t1 -> tX - auto matches2 = makeMatchesFor(t2, colBin, curColId); // t2 -> tY + // gather matches for both legs from the same 6D bin + auto matches1 = makeMatchesFor(t1, colBin, curColId); // candidates to replace leg-1 + auto matches2 = makeMatchesFor(t2, colBin, curColId); // candidates to replace leg-2 - const int n1 = static_cast(matches1.size()); - const int n2 = static_cast(matches2.size()); - if (n1 == 0 && n2 == 0) + const int n1Eff = static_cast(matches1.size()); + const int n2Eff = static_cast(matches2.size()); + if (n1Eff == 0 && n2Eff == 0) continue; - // Split "unit" weight between the two modes - const float w1 = (n1 > 0 ? 0.5f / static_cast(n1) : 0.f); - const float w2 = (n2 > 0 ? 0.5f / static_cast(n2) : 0.f); + // per-leg depth (configurable) + int depth = nEvtMixing.value; + if (depth <= 0) + depth = 1; + + const int n1Take = std::min(depth, n1Eff); + const int n2Take = std::min(depth, n2Eff); - // --- Type A: replace leg 1 → (tX, t2) --- + // split unit weight between legs if both have mixes; else single leg gets full + const float w1 = (n1Take > 0 ? ((n2Take > 0 ? 0.5f : 1.0f) / static_cast(n1Take)) : 0.0f); + const float w2 = (n2Take > 0 ? ((n1Take > 0 ? 0.5f : 1.0f) / static_cast(n2Take)) : 0.0f); + + // randomize & truncate per-leg matches to requested depth + if (n1Take > 0) { + std::shuffle(matches1.begin(), matches1.end(), rng); + matches1.resize(n1Take); + } + if (n2Take > 0) { + std::shuffle(matches2.begin(), matches2.end(), rng); + matches2.resize(n2Take); + } + + // --- Type A: replace leg 1 (t1 -> tX), keep t2 for (const auto& m : matches1) { auto tX = V0s.iteratorAt(m.rowIndex); if (!selectionV0(tX)) @@ -1289,10 +1291,13 @@ struct lambdaspincorrderived { const float dPhi = std::fabs(RecoDecay::constrainAngle(lambda1.Phi() - lambda2.Phi(), 0.0F, harmonicDphi)); histos.fill(HIST("deltaPhiMix"), dPhi, w1); - fillHistograms2(tX.v0Status(), t2.v0Status(), lambda1, lambda2, proton1, proton2, 1, w1, 1); + // datatype=1 (ME), mixedLeg=1 + fillHistograms2(tX.v0Status(), t2.v0Status(), + lambda1, lambda2, proton1, proton2, + /*datatype=*/1, /*weight=*/w1, /*mixedLeg=*/1); } - // --- Type B: replace leg 2 → (t1, tY) --- + // --- Type B: replace leg 2 (t2 -> tY), keep t1 for (const auto& m : matches2) { auto tY = V0s.iteratorAt(m.rowIndex); if (!selectionV0(tY)) @@ -1309,13 +1314,15 @@ struct lambdaspincorrderived { const float dPhi = std::fabs(RecoDecay::constrainAngle(lambda1.Phi() - lambda2.Phi(), 0.0F, harmonicDphi)); histos.fill(HIST("deltaPhiMix"), dPhi, w2); - fillHistograms2(t1.v0Status(), tY.v0Status(), lambda1, lambda2, proton1, proton2, 1, w2, 2); + // datatype=1 (ME), mixedLeg=2 + fillHistograms2(t1.v0Status(), tY.v0Status(), + lambda1, lambda2, proton1, proton2, + /*datatype=*/1, /*weight=*/w2, /*mixedLeg=*/2); } } } } - - PROCESS_SWITCH(lambdaspincorrderived, processMEV4, "Process data ME (5d buffer)", false); + PROCESS_SWITCH(lambdaspincorrderived, processMEV4, "Process data ME (6D buffer, both legs mixed, depth-capped)", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { From 37a78b10cfed350041ac4bd13497dd451414f1ac Mon Sep 17 00:00:00 2001 From: Minjung Kim Date: Sun, 16 Nov 2025 19:01:06 +0100 Subject: [PATCH 42/48] Fix D0 UPC: Add UPC axes for non-ML UPC process --- PWGHF/D2H/Tasks/taskD0.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index b961f39c4cc..67f5733d924 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -357,7 +357,7 @@ struct HfTaskD0 { axes.insert(axes.begin(), thnAxisBkgScore); } } - if (doprocessDataWithDCAFitterNMlWithUpc) { + if (doprocessDataWithDCAFitterNMlWithUpc || doprocessDataWithDCAFitterNWithUpc) { axes.push_back(thnAxisGapType); axes.push_back(thnAxisFT0A); axes.push_back(thnAxisFT0C); From b2ba9513cafa329538ff45c73b44f096e42e455f Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Mon, 17 Nov 2025 17:37:38 +0100 Subject: [PATCH 43/48] [PWGHF] Add UPC w/o ML process functions to validation checks - taskD0: Add doprocessDataWithDCAFitterNWithUpc to both doprocess array and centrality/occupancy check - taskDplus: Add doprocessDataWithUpc to doprocess array validation This ensures both UPC process functions (with and without ML) are properly validated in the init() checks. Addresses review comments from @zhangbiao-phy on PR #13603 --- PWGHF/D2H/Tasks/taskD0.cxx | 4 ++-- PWGHF/D2H/Tasks/taskDplus.cxx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 67f5733d924..6e3f2102b53 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -237,14 +237,14 @@ struct HfTaskD0 { void init(InitContext&) { - std::array doprocess{doprocessDataWithDCAFitterN, doprocessDataWithDCAFitterNCent, doprocessDataWithKFParticle, doprocessMcWithDCAFitterN, doprocessMcWithDCAFitterNCent, doprocessMcWithKFParticle, doprocessDataWithDCAFitterNMl, doprocessDataWithDCAFitterNMlCent, doprocessDataWithKFParticleMl, doprocessMcWithDCAFitterNMl, doprocessMcWithDCAFitterNMlCent, doprocessMcWithKFParticleMl, doprocessDataWithDCAFitterNMlWithUpc}; + std::array doprocess{doprocessDataWithDCAFitterN, doprocessDataWithDCAFitterNCent, doprocessDataWithKFParticle, doprocessMcWithDCAFitterN, doprocessMcWithDCAFitterNCent, doprocessMcWithKFParticle, doprocessDataWithDCAFitterNMl, doprocessDataWithDCAFitterNMlCent, doprocessDataWithKFParticleMl, doprocessMcWithDCAFitterNMl, doprocessMcWithDCAFitterNMlCent, doprocessMcWithKFParticleMl, doprocessDataWithDCAFitterNWithUpc, doprocessDataWithDCAFitterNMlWithUpc}; if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) == 0) { LOGP(fatal, "At least one process function should be enabled at a time."); } if ((doprocessDataWithDCAFitterN || doprocessDataWithDCAFitterNCent || doprocessMcWithDCAFitterN || doprocessMcWithDCAFitterNCent || doprocessDataWithDCAFitterNMl || doprocessDataWithDCAFitterNMlCent || doprocessMcWithDCAFitterNMl || doprocessMcWithDCAFitterNMlCent) && (doprocessDataWithKFParticle || doprocessMcWithKFParticle || doprocessDataWithKFParticleMl || doprocessMcWithKFParticleMl)) { LOGP(fatal, "DCAFitterN and KFParticle can not be enabled at a time."); } - if ((storeCentrality || storeOccupancyAndIR) && !(doprocessDataWithDCAFitterNCent || doprocessMcWithDCAFitterNCent || doprocessDataWithDCAFitterNMlCent || doprocessMcWithDCAFitterNMlCent || doprocessDataWithDCAFitterNMlWithUpc)) { + if ((storeCentrality || storeOccupancyAndIR) && !(doprocessDataWithDCAFitterNCent || doprocessMcWithDCAFitterNCent || doprocessDataWithDCAFitterNMlCent || doprocessMcWithDCAFitterNMlCent || doprocessDataWithDCAFitterNWithUpc || doprocessDataWithDCAFitterNMlWithUpc)) { LOGP(fatal, "Can't enable the storeCentrality and storeOccupancu without cent process or UPC process"); } auto vbins = (std::vector)binsPt; diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 4fa73bb6c56..3c2832bd4fa 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -149,7 +149,7 @@ struct HfTaskDplus { void init(InitContext&) { - std::array doprocess{doprocessData, doprocessDataWithMl, doprocessMc, doprocessMcWithMl, doprocessDataWithMlWithUpc}; + std::array doprocess{doprocessData, doprocessDataWithMl, doprocessMc, doprocessMcWithMl, doprocessDataWithUpc, doprocessDataWithMlWithUpc}; if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { LOGP(fatal, "Only one process function should be enabled! Please check your configuration!"); } From 25a16151a97b00bbc59a090b9dba2ba94d367298 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Mon, 17 Nov 2025 19:33:15 +0100 Subject: [PATCH 44/48] [PWGHF] Remove useless gapTypeToInt function and fix unused parameter warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove gapTypeToInt pass-through function from utilsUpcHf.h - Replace hf_upc::gapTypeToInt(gap) calls with gap directly in taskD0 and taskDplus - Add /*tracks*/ comment to suppress unused parameter warnings in UPC process functions The gapTypeToInt function was a no-op that simply returned its input unchanged. As noted by @vkucera, this function serves no purpose since gap is already an int. 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude --- PWGHF/D2H/Tasks/taskD0.cxx | 9 ++++----- PWGHF/D2H/Tasks/taskDplus.cxx | 5 ++--- PWGHF/Utils/utilsUpcHf.h | 9 --------- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 6e3f2102b53..067a2df207a 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -611,11 +611,10 @@ struct HfTaskD0 { if (hasZdc) { registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdcEnergyZNA, zdcEnergyZNC); - registry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); + registry.fill(HIST("Data/hUpcGapAfterSelection"), gap); } if (hf_upc::isSingleSidedGap(gap)) { - const int gapTypeInt = hf_upc::gapTypeToInt(gap); const auto thisCollId = collision.globalIndex(); const auto& groupedD0Candidates = candidates.sliceBy(candD0PerCollision, thisCollId); @@ -676,7 +675,7 @@ struct HfTaskD0 { valuesToFill.push_back(occ); valuesToFill.push_back(ir); } - valuesToFill.push_back(static_cast(gapTypeInt)); + valuesToFill.push_back(static_cast(gap)); valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); valuesToFill.push_back(static_cast(fitInfo.ampFV0A)); @@ -1170,7 +1169,7 @@ struct HfTaskD0 { void processDataWithDCAFitterNWithUpc(soa::Join const& collisions, aod::BcFullInfos const& bcs, D0Candidates const&, - aod::TracksWExtra const& tracks, + aod::TracksWExtra const& /*tracks*/, aod::FT0s const& ft0s, aod::FV0As const& fv0as, aod::FDDs const& fdds, @@ -1183,7 +1182,7 @@ struct HfTaskD0 { void processDataWithDCAFitterNMlWithUpc(soa::Join const& collisions, aod::BcFullInfos const& bcs, D0CandidatesMl const&, - aod::TracksWExtra const& tracks, + aod::TracksWExtra const& /*tracks*/, aod::FT0s const& ft0s, aod::FV0As const& fv0as, aod::FDDs const& fdds, diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 3c2832bd4fa..988d6806fb7 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -748,11 +748,10 @@ struct HfTaskDplus { if (hasZdc) { registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); registry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdcEnergyZNA, zdcEnergyZNC); - registry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap)); + registry.fill(HIST("Data/hUpcGapAfterSelection"), gap); } if (hf_upc::isSingleSidedGap(gap)) { - const int gapTypeInt = hf_upc::gapTypeToInt(gap); const auto thisCollId = collision.globalIndex(); const auto& groupedDplusCandidates = candidates.sliceBy(candDplusPerCollision, thisCollId); @@ -800,7 +799,7 @@ struct HfTaskDplus { if (storeIR) { valuesToFill.push_back(ir); } - valuesToFill.push_back(static_cast(gapTypeInt)); + valuesToFill.push_back(static_cast(gap)); valuesToFill.push_back(static_cast(fitInfo.ampFT0A)); valuesToFill.push_back(static_cast(fitInfo.ampFT0C)); valuesToFill.push_back(static_cast(fitInfo.ampFV0A)); diff --git a/PWGHF/Utils/utilsUpcHf.h b/PWGHF/Utils/utilsUpcHf.h index acfca5042d1..45190185c74 100644 --- a/PWGHF/Utils/utilsUpcHf.h +++ b/PWGHF/Utils/utilsUpcHf.h @@ -145,15 +145,6 @@ constexpr const char* getGapTypeName(int gap) noexcept } } -/// \brief Convert gap type to integer for histogram filling -/// \param gap TrueGap enum value -/// \return Integer representation (-1, 0, 1, 2, 3, 4, 5) -/// \note This is a pass-through function for consistency with other utility functions -constexpr int gapTypeToInt(int gap) noexcept -{ - return gap; -} - } // namespace o2::analysis::hf_upc #endif // PWGHF_UTILS_UTILSUPCHF_H_ From d602110cf4b4895c3aecfe81b0743e5e4cd1b5a9 Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Tue, 18 Nov 2025 13:34:13 +0100 Subject: [PATCH 45/48] fix handling unused paramemeter --- PWGHF/D2H/Tasks/taskD0.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 067a2df207a..2e35a66cc3e 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -1169,7 +1169,7 @@ struct HfTaskD0 { void processDataWithDCAFitterNWithUpc(soa::Join const& collisions, aod::BcFullInfos const& bcs, D0Candidates const&, - aod::TracksWExtra const& /*tracks*/, + aod::TracksWExtra const&, aod::FT0s const& ft0s, aod::FV0As const& fv0as, aod::FDDs const& fdds, @@ -1182,7 +1182,7 @@ struct HfTaskD0 { void processDataWithDCAFitterNMlWithUpc(soa::Join const& collisions, aod::BcFullInfos const& bcs, D0CandidatesMl const&, - aod::TracksWExtra const& /*tracks*/, + aod::TracksWExtra const&, aod::FT0s const& ft0s, aod::FV0As const& fv0as, aod::FDDs const& fdds, From 5bfc554e991075f96d5c0bfaec08c3d6c5c5123d Mon Sep 17 00:00:00 2001 From: minjungkim12 Date: Tue, 18 Nov 2025 16:39:36 +0100 Subject: [PATCH 46/48] fix auto to const auto & --- PWGHF/D2H/Tasks/taskD0.cxx | 2 +- PWGHF/D2H/Tasks/taskDplus.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index 2e35a66cc3e..219142f3d78 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -581,7 +581,7 @@ struct HfTaskD0 { if (rejectionMask != 0) { continue; } - auto bc = collision.template bc_as(); + const auto& bc = collision.template bc_as(); // Determine gap type using SGSelector with BC range checking const auto gapResult = hf_upc::determineGapType(collision, bcs, upcThresholds); diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 988d6806fb7..fb30cb871fc 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -718,7 +718,7 @@ struct HfTaskDplus { /// at least one event selection not satisfied --> reject the candidate continue; } - auto bc = collision.template bc_as(); + const auto& bc = collision.template bc_as(); // Determine gap type using SGSelector with BC range checking const auto gapResult = hf_upc::determineGapType(collision, bcs, upcThresholds); From 5baf9abd41c6d76fa1dea61a3b724a38a10a1ecd Mon Sep 17 00:00:00 2001 From: minjungkim12 <21147605+minjungkim12@users.noreply.github.com> Date: Tue, 18 Nov 2025 23:11:20 +0000 Subject: [PATCH 47/48] Fix HIST macro usage in lambda by moving to constexpr variable --- PWGHF/D2H/Tasks/taskDplus.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index fb30cb871fc..2e59a76516c 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -764,7 +764,7 @@ struct HfTaskDplus { if (storeIR) { ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource, true) * 1.e-3; // kHz } - + static constexpr auto kHSparseMass = HIST("hSparseMass"); // Lambda function to fill THn - handles both ML and non-ML cases auto fillTHnData = [&](const auto& candidate) { // Pre-calculate vector size to avoid reallocations @@ -807,7 +807,7 @@ struct HfTaskDplus { valuesToFill.push_back(static_cast(fitInfo.ampFDDC)); valuesToFill.push_back(static_cast(zdcEnergyZNA)); valuesToFill.push_back(static_cast(zdcEnergyZNC)); - registry.get(HIST("hSparseMass"))->Fill(valuesToFill.data()); + registry.get(kHSparseMass)->Fill(valuesToFill.data()); }; for (const auto& candidate : groupedDplusCandidates) { From b6d19c985f61976e14c89c125c8a218522525b7c Mon Sep 17 00:00:00 2001 From: minjungkim12 <21147605+minjungkim12@users.noreply.github.com> Date: Wed, 19 Nov 2025 13:46:30 +0100 Subject: [PATCH 48/48] Rename kHSparseMass to HSparseMass satisfies the naming guidelines --- PWGHF/D2H/Tasks/taskDplus.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index 2e59a76516c..2e3ceec0884 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -764,7 +764,7 @@ struct HfTaskDplus { if (storeIR) { ir = mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource, true) * 1.e-3; // kHz } - static constexpr auto kHSparseMass = HIST("hSparseMass"); + static constexpr auto HSparseMass = HIST("hSparseMass"); // Lambda function to fill THn - handles both ML and non-ML cases auto fillTHnData = [&](const auto& candidate) { // Pre-calculate vector size to avoid reallocations @@ -807,7 +807,7 @@ struct HfTaskDplus { valuesToFill.push_back(static_cast(fitInfo.ampFDDC)); valuesToFill.push_back(static_cast(zdcEnergyZNA)); valuesToFill.push_back(static_cast(zdcEnergyZNC)); - registry.get(kHSparseMass)->Fill(valuesToFill.data()); + registry.get(HSparseMass)->Fill(valuesToFill.data()); }; for (const auto& candidate : groupedDplusCandidates) {