From a0dbc04b73575a3066d796a38750f875806eac11 Mon Sep 17 00:00:00 2001 From: Neelkamal Mallick Date: Thu, 26 Feb 2026 16:34:28 +0200 Subject: [PATCH 1/6] process MultSet and track selection bit check added --- PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx | 98 +++++++++++++++++++++++- 1 file changed, 96 insertions(+), 2 deletions(-) diff --git a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx index 111e1f8e92b..25e6609a247 100644 --- a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx +++ b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx @@ -17,6 +17,8 @@ #include #include #include +#include +#include // O2 headers. // // The first two are mandatory. @@ -46,6 +48,8 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + using MyCollisions = soa::Join().weightNUA()); template using HasWeightEff = decltype(std::declval().weightEff()); + template + using HasTrackType = decltype(std::declval().trackType()); + template + using HasMultSet = decltype(std::declval().multiplicities()); HistogramRegistry qaHistRegistry{"qaHistRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; FlowJHistManager histManager; @@ -84,12 +92,24 @@ struct flowJSPCAnalysis { Configurable cfgMultMin{"cfgMultMin", 10, "Minimum number of particles required for the event to have."}; } cfgEventCuts; + O2_DEFINE_CONFIGURABLE(cfgTrackBitMask, uint16_t, 0, "Track selection bitmask to use as defined in the filterCorrelations.cxx task"); + O2_DEFINE_CONFIGURABLE(cfgMultCorrelationsMask, uint16_t, 0, "Selection bitmask for the multiplicity correlations. This should match the filter selection cfgEstimatorBitMask.") + O2_DEFINE_CONFIGURABLE(cfgMultCutFormula, std::string, "", "Multiplicity correlations cut formula. A result greater than zero results in accepted event. Parameters: [cFT0C] FT0C centrality, [mFV0A] V0A multiplicity, [mGlob] global track multiplicity, [mPV] PV track multiplicity, [cFT0M] FT0M centrality") + + ConfigurableAxis axisMultCorrCent{"axisMultCorrCent", {100, 0, 100}, "multiplicity correlation axis for centralities"}; + ConfigurableAxis axisMultCorrV0{"axisMultCorrV0", {1000, 0, 100000}, "multiplicity correlation axis for V0 multiplicities"}; + ConfigurableAxis axisMultCorrMult{"axisMultCorrMult", {1000, 0, 1000}, "multiplicity correlation axis for track multiplicities"}; + // // Filters to be applied to the received data. // // The analysis assumes the data has been subjected to a QA of its selection, // // and thus only the final distributions of the data for analysis are saved. Filter collFilter = (nabs(aod::collision::posZ) < cfgEventCuts.cfgZvtxMax); + Filter trackFilter = (aod::track::pt > cfgTrackCuts.cfgPtMin) && (aod::track::pt < cfgTrackCuts.cfgPtMax) && (nabs(aod::track::eta) < cfgTrackCuts.cfgEtaMax); - Filter cftrackFilter = (aod::cftrack::pt > cfgTrackCuts.cfgPtMin) && (aod::cftrack::pt < cfgTrackCuts.cfgPtMax); // eta cuts done by jfluc + Filter cftrackFilter = (nabs(aod::cftrack::eta) < cfgTrackCuts.cfgEtaMax) && (aod::cftrack::pt > cfgTrackCuts.cfgPtMin) && (aod::cftrack::pt < cfgTrackCuts.cfgPtMax) && ncheckbit(aod::track::trackType, as(cfgTrackBitMask)); + + std::unique_ptr multCutFormula; + std::array multCutFormulaParamIndex; void init(InitContext const&) { @@ -103,6 +123,43 @@ struct flowJSPCAnalysis { histManager.setHistRegistryQA(&qaHistRegistry); histManager.setDebugLog(false); histManager.createHistQA(); + + if (doprocessCFDerivedMultSetCorrected) { + if (cfgMultCorrelationsMask == 0) + LOGF(fatal, "cfgMultCorrelationsMask can not be 0 when MultSet process functions are in use."); + std::vector multAxes; + if (cfgMultCorrelationsMask & aod::cfmultset::CentFT0C) + multAxes.emplace_back(axisMultCorrCent, "FT0C centrality"); + if (cfgMultCorrelationsMask & aod::cfmultset::MultFV0A) + multAxes.emplace_back(axisMultCorrV0, "V0A multiplicity"); + if (cfgMultCorrelationsMask & aod::cfmultset::MultNTracksPV) + multAxes.emplace_back(axisMultCorrMult, "Nch PV"); + if (cfgMultCorrelationsMask & aod::cfmultset::MultNTracksGlobal) + multAxes.emplace_back(axisMultCorrMult, "Nch Global"); + if (cfgMultCorrelationsMask & aod::cfmultset::CentFT0M) + multAxes.emplace_back(axisMultCorrCent, "FT0M centrality"); + qaHistRegistry.add("multCorrelations", "Multiplicity correlations", {HistType::kTHnSparseF, multAxes}); + } + + if (!cfgMultCutFormula.value.empty()) { + multCutFormula = std::make_unique("multCutFormula", cfgMultCutFormula.value.c_str()); + std::fill_n(multCutFormulaParamIndex.begin(), std::size(multCutFormulaParamIndex), ~0u); + std::array pars = {"cFT0C", "mFV0A", "mPV", "mGlob", "cFT0M"}; // must correspond the order of MultiplicityEstimators + for (uint i = 0, n = multCutFormula->GetNpar(); i < n; ++i) { + auto m = std::find(pars.begin(), pars.end(), multCutFormula->GetParName(i)); + if (m == pars.end()) { + LOGF(warning, "Unknown parameter in cfgMultCutFormula: %s", multCutFormula->GetParName(i)); + continue; + } + const uint estIdx = std::distance(pars.begin(), m); + if ((cfgMultCorrelationsMask.value & (1u << estIdx)) == 0) { + LOGF(warning, "The centrality/multiplicity estimator %s is not available to be used in cfgMultCutFormula. Ensure cfgMultCorrelationsMask is correct and matches the CFMultSets in derived data.", m->c_str()); + } else { + multCutFormulaParamIndex[estIdx] = i; + LOGF(info, "Multiplicity cut parameter %s in use.", m->c_str()); + } + } + } } template @@ -119,6 +176,14 @@ struct flowJSPCAnalysis { int cBin = histManager.getCentBin(cent); spcHistograms.fill(HIST("FullCentrality"), cent); int nTracks = tracks.size(); + + if (cfgFillQA) { + if constexpr (std::experimental::is_detected::value) { + std::vector v(collision.multiplicities().begin(), collision.multiplicities().end()); + qaHistRegistry.get(HIST("multCorrelations")).get()->Fill(v.data()); + } + } + double wNUA = 1.0; double wEff = 1.0; for (const auto& track : tracks) { @@ -135,6 +200,11 @@ struct flowJSPCAnalysis { if constexpr (std::experimental::is_detected::value) { spcAnalysis.fillQAHistograms(cBin, track.phi(), 1. / track.weightNUA()); } + if constexpr (std::experimental::is_detected::value) { + if (track.trackType() != cfgTrackBitMask.value) { + LOGF(warning, "trackType %d (expected %d) is passed to the analysis", track.trackType(), cfgTrackBitMask.value); + } + } } } @@ -146,6 +216,20 @@ struct flowJSPCAnalysis { spcAnalysis.calculateCorrelators(cBin); } + template + bool passOutlier(CollType const& collision) + { + if (cfgMultCutFormula.value.empty()) + return true; + for (uint i = 0; i < aod::cfmultset::NMultiplicityEstimators; ++i) { + if ((cfgMultCorrelationsMask.value & (1u << i)) == 0 || multCutFormulaParamIndex[i] == ~0u) + continue; + auto estIndex = std::popcount(static_cast(cfgMultCorrelationsMask.value & ((1u << i) - 1))); + multCutFormula->SetParameter(multCutFormulaParamIndex[i], collision.multiplicities()[estIndex]); + } + return multCutFormula->Eval() > 0.0f; + } + void processJDerived(aod::JCollision const& collision, soa::Filtered const& tracks) { analyze(collision, tracks); @@ -164,11 +248,21 @@ struct flowJSPCAnalysis { } PROCESS_SWITCH(flowJSPCAnalysis, processCFDerived, "Process CF derived data", false); - void processCFDerivedCorrected(aod::CFCollision const& collision, soa::Filtered> const& tracks) + void processCFDerivedCorrected(soa::Filtered::iterator const& collision, soa::Filtered> const& tracks) { analyze(collision, tracks); } PROCESS_SWITCH(flowJSPCAnalysis, processCFDerivedCorrected, "Process CF derived data with corrections", true); + + void processCFDerivedMultSetCorrected(soa::Filtered>::iterator const& collision, soa::Filtered> const& tracks) + { + if (std::popcount(static_cast(cfgMultCorrelationsMask.value)) != static_cast(collision.multiplicities().size())) + LOGF(fatal, "Multiplicity selections (cfgMultCorrelationsMask = 0x%x) do not match the size of the table column (%ld). The histogram filling relies on the preservation of order.", cfgMultCorrelationsMask.value, collision.multiplicities().size()); + if (!passOutlier(collision)) + return; + analyze(collision, tracks); + } + PROCESS_SWITCH(flowJSPCAnalysis, processCFDerivedMultSetCorrected, "Process CF derived data with corrections and multiplicity sets", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) From a6dd98d29fcc8a3c5209a06ab8c6bb68017bae0e Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Thu, 26 Feb 2026 14:37:32 +0000 Subject: [PATCH 2/6] Please consider the following formatting changes --- PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx index 25e6609a247..277aa874709 100644 --- a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx +++ b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx @@ -13,12 +13,13 @@ // \author Maxim Virta (maxim.virta@cern.ch), Cindy Mordasini (cindy.mordasini@cern.ch) // Standard headers. +#include +#include +#include + #include #include #include -#include -#include -#include // O2 headers. // // The first two are mandatory. @@ -104,7 +105,7 @@ struct flowJSPCAnalysis { // // The analysis assumes the data has been subjected to a QA of its selection, // // and thus only the final distributions of the data for analysis are saved. Filter collFilter = (nabs(aod::collision::posZ) < cfgEventCuts.cfgZvtxMax); - + Filter trackFilter = (aod::track::pt > cfgTrackCuts.cfgPtMin) && (aod::track::pt < cfgTrackCuts.cfgPtMax) && (nabs(aod::track::eta) < cfgTrackCuts.cfgEtaMax); Filter cftrackFilter = (nabs(aod::cftrack::eta) < cfgTrackCuts.cfgEtaMax) && (aod::cftrack::pt > cfgTrackCuts.cfgPtMin) && (aod::cftrack::pt < cfgTrackCuts.cfgPtMax) && ncheckbit(aod::track::trackType, as(cfgTrackBitMask)); From 2f0938913bf86baa9b165a19b8f0b42f53815a09 Mon Sep 17 00:00:00 2001 From: Neelkamal Mallick Date: Thu, 26 Feb 2026 17:00:36 +0200 Subject: [PATCH 3/6] author name added --- PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx index 277aa874709..a87ff36ea70 100644 --- a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx +++ b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx @@ -8,9 +8,10 @@ // 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. - -// \brief Task for the calculation of SPC with filtered data. -// \author Maxim Virta (maxim.virta@cern.ch), Cindy Mordasini (cindy.mordasini@cern.ch) +/// +/// \file flowJSPCAnalysis.cxx +/// \brief Task for the calculation of SPC with filtered data. +/// \author Maxim Virta (maxim.virta@cern.ch), Cindy Mordasini (cindy.mordasini@cern.ch), Neelkamal Mallick (neelkamal.mallick@cern.ch) // Standard headers. #include From 20123208446abdd0a8d9463d9dbe603c04b91c1c Mon Sep 17 00:00:00 2001 From: Neelkamal Mallick Date: Thu, 26 Feb 2026 17:07:51 +0200 Subject: [PATCH 4/6] Fix to megalinter error --- PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx index a87ff36ea70..23863118095 100644 --- a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx +++ b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx @@ -19,6 +19,7 @@ #include #include +#include #include #include From 713a34d75c3a6dcbe03c2ff772449584a1f44e68 Mon Sep 17 00:00:00 2001 From: Neelkamal Mallick Date: Thu, 26 Feb 2026 23:38:25 +0200 Subject: [PATCH 5/6] Histogram creation code is redundant: removed --- PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx | 32 +----------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx index 23863118095..fadfd978f16 100644 --- a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx +++ b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx @@ -15,7 +15,6 @@ // Standard headers. #include -#include #include #include @@ -70,8 +69,6 @@ struct flowJSPCAnalysis { using HasWeightEff = decltype(std::declval().weightEff()); template using HasTrackType = decltype(std::declval().trackType()); - template - using HasMultSet = decltype(std::declval().multiplicities()); HistogramRegistry qaHistRegistry{"qaHistRegistry", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; FlowJHistManager histManager; @@ -99,10 +96,6 @@ struct flowJSPCAnalysis { O2_DEFINE_CONFIGURABLE(cfgMultCorrelationsMask, uint16_t, 0, "Selection bitmask for the multiplicity correlations. This should match the filter selection cfgEstimatorBitMask.") O2_DEFINE_CONFIGURABLE(cfgMultCutFormula, std::string, "", "Multiplicity correlations cut formula. A result greater than zero results in accepted event. Parameters: [cFT0C] FT0C centrality, [mFV0A] V0A multiplicity, [mGlob] global track multiplicity, [mPV] PV track multiplicity, [cFT0M] FT0M centrality") - ConfigurableAxis axisMultCorrCent{"axisMultCorrCent", {100, 0, 100}, "multiplicity correlation axis for centralities"}; - ConfigurableAxis axisMultCorrV0{"axisMultCorrV0", {1000, 0, 100000}, "multiplicity correlation axis for V0 multiplicities"}; - ConfigurableAxis axisMultCorrMult{"axisMultCorrMult", {1000, 0, 1000}, "multiplicity correlation axis for track multiplicities"}; - // // Filters to be applied to the received data. // // The analysis assumes the data has been subjected to a QA of its selection, // // and thus only the final distributions of the data for analysis are saved. @@ -127,22 +120,6 @@ struct flowJSPCAnalysis { histManager.setDebugLog(false); histManager.createHistQA(); - if (doprocessCFDerivedMultSetCorrected) { - if (cfgMultCorrelationsMask == 0) - LOGF(fatal, "cfgMultCorrelationsMask can not be 0 when MultSet process functions are in use."); - std::vector multAxes; - if (cfgMultCorrelationsMask & aod::cfmultset::CentFT0C) - multAxes.emplace_back(axisMultCorrCent, "FT0C centrality"); - if (cfgMultCorrelationsMask & aod::cfmultset::MultFV0A) - multAxes.emplace_back(axisMultCorrV0, "V0A multiplicity"); - if (cfgMultCorrelationsMask & aod::cfmultset::MultNTracksPV) - multAxes.emplace_back(axisMultCorrMult, "Nch PV"); - if (cfgMultCorrelationsMask & aod::cfmultset::MultNTracksGlobal) - multAxes.emplace_back(axisMultCorrMult, "Nch Global"); - if (cfgMultCorrelationsMask & aod::cfmultset::CentFT0M) - multAxes.emplace_back(axisMultCorrCent, "FT0M centrality"); - qaHistRegistry.add("multCorrelations", "Multiplicity correlations", {HistType::kTHnSparseF, multAxes}); - } if (!cfgMultCutFormula.value.empty()) { multCutFormula = std::make_unique("multCutFormula", cfgMultCutFormula.value.c_str()); @@ -180,13 +157,6 @@ struct flowJSPCAnalysis { spcHistograms.fill(HIST("FullCentrality"), cent); int nTracks = tracks.size(); - if (cfgFillQA) { - if constexpr (std::experimental::is_detected::value) { - std::vector v(collision.multiplicities().begin(), collision.multiplicities().end()); - qaHistRegistry.get(HIST("multCorrelations")).get()->Fill(v.data()); - } - } - double wNUA = 1.0; double wEff = 1.0; for (const auto& track : tracks) { @@ -260,7 +230,7 @@ struct flowJSPCAnalysis { void processCFDerivedMultSetCorrected(soa::Filtered>::iterator const& collision, soa::Filtered> const& tracks) { if (std::popcount(static_cast(cfgMultCorrelationsMask.value)) != static_cast(collision.multiplicities().size())) - LOGF(fatal, "Multiplicity selections (cfgMultCorrelationsMask = 0x%x) do not match the size of the table column (%ld). The histogram filling relies on the preservation of order.", cfgMultCorrelationsMask.value, collision.multiplicities().size()); + LOGF(fatal, "Multiplicity selections (cfgMultCorrelationsMask = 0x%x) do not match the size of the table column (%ld).", cfgMultCorrelationsMask.value, collision.multiplicities().size()); if (!passOutlier(collision)) return; analyze(collision, tracks); From 3c3b40c98d8726ca7785a7913746680cf15cc476 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Thu, 26 Feb 2026 21:39:02 +0000 Subject: [PATCH 6/6] Please consider the following formatting changes --- PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx index fadfd978f16..380de913181 100644 --- a/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx +++ b/PWGCF/JCorran/Tasks/flowJSPCAnalysis.cxx @@ -120,7 +120,6 @@ struct flowJSPCAnalysis { histManager.setDebugLog(false); histManager.createHistQA(); - if (!cfgMultCutFormula.value.empty()) { multCutFormula = std::make_unique("multCutFormula", cfgMultCutFormula.value.c_str()); std::fill_n(multCutFormulaParamIndex.begin(), std::size(multCutFormulaParamIndex), ~0u);