From a5181d2e760e7ad2e99ea1e3838bb691450561ec Mon Sep 17 00:00:00 2001 From: eranicern-qwer Date: Thu, 12 Nov 2026 16:02:02 +0500 Subject: [PATCH 1/4] Rework flattenicity task: MC truth vs reco, FT0 module geometry, pT vs flattenicity --- PWGMM/UE/Tasks/flattenicityTask.cxx | 710 ++++++++++++++++++---------- 1 file changed, 467 insertions(+), 243 deletions(-) diff --git a/PWGMM/UE/Tasks/flattenicityTask.cxx b/PWGMM/UE/Tasks/flattenicityTask.cxx index ec430c12479..8fd4f8eb828 100644 --- a/PWGMM/UE/Tasks/flattenicityTask.cxx +++ b/PWGMM/UE/Tasks/flattenicityTask.cxx @@ -10,61 +10,67 @@ // or submit itself to any jurisdiction. /// \file flattenicityTask.cxx -/// \brief Run-1 calibration task for FT0 flattenicity (fine-binned histograms for percentile extraction) +/// \brief Run-3 calibration task for FT0 flattenicity /// \author Eisha Rani /// \since September 2026 #include "Common/Core/RecoDecay.h" +#include "Common/Core/TrackSelection.h" +#include "Common/Core/TrackSelectionDefaults.h" #include "Common/DataModel/EventSelection.h" +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/TrackSelectionTables.h" +#include "PWGLF/Utils/inelGt.h" #include #include #include #include +#include #include #include +#include #include #include +#include +#include +#include +#include + #include #include #include #include +#include +#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; -using FullTracks = - soa::Join; +using FullTracks = soa::Join; -using CollisionsWithSelection = - soa::Join; +using CollisionsWithMult = soa::Join; +using CollisionsNoMult = soa::Join; +// Reco collisions grouped per MC collision +using ColMCRecTable = soa::SmallGroups>; struct FlattenicityTask { - // NOLINTNEXTLINE(misc-include-cleaner) - Service<> is provided by Framework/AnalysisTask.h; there is no separate standalone header for it in this O2 version. Service pdg{}; // ======================================================================== // FT0 geometry // ======================================================================== - - static constexpr int NPhiSectors = 8; static constexpr int NSectorsA = 24; static constexpr int NSectorsC = 28; - static constexpr int NSectorsCombined = NSectorsA + NSectorsC; // 52 + static constexpr int NSectorsCombined = NSectorsA + NSectorsC; static constexpr int ChannelsPerSector = 4; - static constexpr int NchA = NSectorsA * ChannelsPerSector; // 96 - static constexpr int NchC = NSectorsC * ChannelsPerSector; // 112 - static constexpr int NCell = NchA + NchC; // 208 - static constexpr int NEtaA = NchA / NPhiSectors; // 12 - static constexpr int NEtaC = NchC / NPhiSectors; // 14 + static constexpr int NchA = NSectorsA * ChannelsPerSector; + static constexpr int NchC = NSectorsC * ChannelsPerSector; static constexpr float FT0AEtaMin = 3.5; static constexpr float FT0AEtaMax = 4.9; static constexpr float FT0CEtaMin = -3.3; @@ -72,10 +78,58 @@ struct FlattenicityTask { static constexpr int NPhysicalPrimaryBit = 0x4; static constexpr float ChargeEpsilon = 1e-6f; - // ======================================================================== - // Run-1 fine binning - // ======================================================================== + // ------------------------------------------------------------------------ + // Real per-module (x, y[, z]) positions from the O2 FT0 geometry. All values + // verified against AliceO2 (dev): + // - x,y: Detectors/FIT/FT0/base/src/Geometry.cxx setAsideModules() (A) and + // setCsideModules() (C, ZdetC = 82 cm, compensated radius 82 + 5.5/2); + // ZdetA = 335.5 cm (Geometry.h). + // - Global placement, Detectors/FIT/FT0/simulation/src/Detector.cxx: + // A: translation only in x,y; z of the module centre is about 333.7 cm + // (frame at zdetA + 0.63, local z = -5 + 2.6). We use the nominal + // ZdetA = 335.5 cm; the eta difference is ~0.01-0.02 (negligible). + // C: module local z = zc2 - 80 (line 155, marked "fix later" by the + // authors), frame at z = -zdetC with rotC = axes (1,0,0),(0,1,0), + // (0,0,-1), i.e. a pure z -> -z reflection (x,y unchanged): + // global z = -82 - (zc2 - 80) = -(zc2 + 2) -> -84.8 ... -86.2 cm. + // - Detector.cxx also places both mother volumes with a +30 cm y + // translation (TGeoTranslation(0, 30., ...)). This is deliberately NOT + // applied here: applying it moves the eta coverage to A ~2.7-3.9 and + // C ~-2.7 to -1.3 (nominal: A 3.5-4.9, C -3.3 to -2.1), and a test with + // the shift applied lowered the truth-vs-reco correlation from + // r = 0.79 to 0.46 (Average) and 0.63 to 0.42 (Combined). + // Uncertainty: module-centre vs quartz-face depth is ~+-2 cm (eta shift + // < 0.03); the two odd/even C-module reflections give a mirror-symmetric + // set of positions, so flattenicity does not depend on module labelling. + // ------------------------------------------------------------------------ + // Strict mode (ON by default, cfgRequireModuleHit = true): only count a + // particle if its projected hit point lies on the module face (square, + // half-width = 2 x half-channel width = 2.65 cm, from + // calculateChannelCenter() in O2). Particles pointing into the gaps between + // modules are dropped. Set to false to assign every particle inside the eta + // window to its nearest module instead. + Configurable cfgRequireModuleHit{"cfgRequireModuleHit", true, "Require projected hit inside module face"}; + static constexpr float kModuleHalfWidth = 2.65f; + + static constexpr float kZDetA = 335.5f; + static constexpr float kModuleAx[NSectorsA] = {-12.2500f, -6.1500f, -0.0500f, 6.1500f, 12.2500f, -12.2500f, -6.1500f, -0.0500f, 6.1500f, 12.2500f, -13.5800f, -7.4800f, 7.4800f, 13.5800f, -12.2500f, -6.1500f, 0.0500f, 6.1500f, 12.2500f, -12.2500f, -6.1500f, 0.0500f, 6.1500f, 12.2500f}; + static constexpr float kModuleAy[NSectorsA] = {12.2000f, 12.2000f, 13.5300f, 12.2000f, 12.2000f, 6.1000f, 6.1000f, 7.4300f, 6.1000f, 6.1000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, -6.1000f, -6.1000f, -7.4300f, -6.1000f, -6.1000f, -12.2000f, -12.2000f, -13.5300f, -12.2000f, -12.2000f}; + static constexpr float kModuleCx[NSectorsC] = {-15.5426f, 15.5426f, -15.5069f, 15.5069f, -9.3296f, 9.3296f, -9.3296f, 9.3296f, -9.3296f, 9.3296f, -3.1011f, 3.1011f, -3.1286f, 3.1286f, 3.1010f, -3.1010f, 3.1286f, -3.1286f, 9.3295f, -9.3295f, 9.3296f, -9.3296f, 9.3296f, -9.3296f, 15.5425f, -15.5425f, 15.5068f, -15.5068f}; + static constexpr float kModuleCy[NSectorsC] = {3.2659f, -3.2659f, 9.4726f, -9.4726f, 3.2436f, -3.2436f, 9.4726f, -9.4726f, 15.6494f, -15.6494f, 9.4725f, -9.4725f, 15.6982f, -15.6982f, 9.4724f, -9.4724f, 15.6981f, -15.6981f, 3.2435f, -3.2435f, 9.4725f, -9.4725f, 15.6493f, -15.6493f, 3.2659f, -3.2659f, 9.4725f, -9.4725f}; + static constexpr float kModuleCz[NSectorsC] = {-85.2486f, -85.2486f, -84.7790f, -84.7790f, -86.1724f, -86.1724f, -85.7006f, -85.7006f, -84.7685f, -84.7685f, -86.1618f, -86.1618f, -85.2246f, -85.2246f, -86.1619f, -86.1619f, -85.2247f, -85.2247f, -86.1725f, -86.1725f, -85.7006f, -85.7006f, -84.7685f, -84.7685f, -85.2486f, -85.2486f, -84.7791f, -84.7791f}; + + // Official FT0 channel ID -> geometry module index, built by inverting + // localChannelOrder[] from AliceO2 Detectors/FIT/FT0/base/include/FT0Base/ + // Geometry.h (localChannelOrder[4*module + k] = official channel; A modules + // 0-23, C modules 24-51). Module index = same order as kModuleA*/kModuleC* + // above, so truth-level and reco-level sectors are the same physical + // modules. FT0-C table is indexed by (official channel - 96), i.e. the + // channelC() value stored in AO2D (see QA/hFT0ChannelC to confirm). + static constexpr int kChannelToModuleA[NchA] = {12, 12, 12, 12, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 11, 11, 11, 11, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 13, 13, 13, 13, 9, 9, 9, 9, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 5, 5, 5, 5, 10, 10, 10, 10, 14, 14, 14, 14, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 18, 18, 18, 18}; + static constexpr int kChannelToModuleC[NchC] = {18, 18, 18, 18, 20, 20, 20, 20, 14, 14, 14, 14, 10, 10, 10, 10, 6, 6, 6, 6, 4, 4, 4, 4, 19, 19, 19, 19, 21, 21, 21, 21, 15, 15, 15, 15, 11, 11, 11, 11, 7, 7, 7, 7, 5, 5, 5, 5, 24, 24, 24, 24, 26, 26, 26, 26, 22, 22, 22, 22, 16, 16, 16, 16, 12, 12, 12, 12, 8, 8, 8, 8, 2, 2, 2, 2, 0, 0, 0, 0, 25, 25, 25, 25, 27, 27, 27, 27, 23, 23, 23, 23, 17, 17, 17, 17, 13, 13, 13, 13, 9, 9, 9, 9, 3, 3, 3, 3, 1, 1, 1, 1}; + static constexpr int NFlatBins = 10000; + static constexpr int NCorrTitleUpdateInterval = 500; // refresh Pearson r in the titles every N filled events // ======================================================================== // Histograms @@ -86,69 +140,160 @@ struct FlattenicityTask { {"QA/hEvents", "Event selection;selection;Entries", {HistType::kTH1F, {{5, 0, 5}}}}, {"QA/hNchINEL", "INEL>0 multiplicity (|eta|<0.8);N_{ch};Entries", {HistType::kTH1F, {{100, -0.5, 99.5}}}}, - {"Truth/hFlattenicityTruthAverage_fine", "MC truth flattenicity - average of FT0A-like/FT0C-like grids;1-#rho;Entries", {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, - {"Truth/hFlattenicityTruthCombined_fine", "MC truth flattenicity - combined 208-cell grid;1-#rho;Entries", {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, - {"Reco/hFlattenicityFT0Average_fine", "FT0 flattenicity - average of FT0A and FT0C;1-#rho;Entries", {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, - {"Reco/hFlattenicityFT0Combined_fine", "FT0 flattenicity - combined FT0A+FT0C;1-#rho;Entries", {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, - {"Reco/hFT0Mraw_fine", "Raw FT0M amplitude sum;FT0A+FT0C amplitude;Entries", {HistType::kTH1F, {{NFlatBins, 0.0, 20000.0}}}}, - - {"Truth/hFlattenicityTruthAverage", "MC truth flattenicity - average definition;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"Truth/hFlattenicityTruthCombined", "MC truth flattenicity - combined definition;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"Reco/hFlattenicityFT0Average", "FT0 flattenicity - average definition;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"Reco/hFlattenicityFT0Combined", "FT0 flattenicity - combined definition;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"Reco/hFT0Mraw", "Raw FT0M amplitude sum;FT0A+FT0C amplitude;Entries", {HistType::kTH1F, {{200, 0.0, 20000.0}}}}, - - {"Truth/hCellOccupancy", "Truth FT0 cell occupancy;cell ID;Entries", {HistType::kTH1F, {{NCell, 0, NCell}}}}, - {"Truth/hCellOccupancyFT0A", "Truth FT0A cell occupancy;cell ID;Entries", {HistType::kTH1F, {{NchA, 0, NchA}}}}, - {"Truth/hCellOccupancyFT0C", "Truth FT0C cell occupancy;cell ID;Entries", {HistType::kTH1F, {{NchC, 0, NchC}}}}, + // ---- MC truth: 52-sector flattenicity only ---- + {"MCTruth/hFlattenicityAvgSector_fine", + "MC Truth - Average, 24+28 sectors;1-#rho;Entries", + {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, + {"MCTruth/hFlattenicityCombSector_fine", + "MC Truth - Combined, 52 sectors;1-#rho;Entries", + {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, + + + // ---- MC reco ---- + {"MCReco/hFlattenicityFT0Average_fine", + "MC Reco - FT0 Average of FT0A and FT0C;1-#rho;Entries", + {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, + {"MCReco/hFlattenicityFT0Combined_fine", + "MC Reco - FT0 Combined FT0A+FT0C;1-#rho;Entries", + {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, + + // ---- Data ---- + {"Data/hFlattenicityFT0Average_fine", + "Data - FT0 Average of FT0A and FT0C;1-#rho;Entries", + {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, + {"Data/hFlattenicityFT0Combined_fine", + "Data - FT0 Combined FT0A+FT0C;1-#rho;Entries", + {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, + + + // ---- Correlation matrices: x = measured (reco) 1-rho, y = true (MC particles) 1-rho ---- + {"MCReco/hTruthVsRecoCombined", + "Combined: reco vs truth;1-#rho (reco, FT0 amplitude);1-#rho (truth, MC particles)", + {HistType::kTH2F, {{200, 0.0, 1.0}, {200, 0.0, 1.0}}}}, + {"MCReco/hTruthVsRecoAverage", + "Average: reco vs truth;1-#rho (reco, FT0 amplitude);1-#rho (truth, MC particles)", + {HistType::kTH2F, {{200, 0.0, 1.0}, {200, 0.0, 1.0}}}}, }}; + // ------------------------------------------------------------------------ + // pT axis (GeV/c) built from segments: number of bins, first edge, bin width. + // The last edge is PtMax. + struct PtSegment { + int nBins; + double start; + double step; + }; + static constexpr PtSegment PtSegments[] = {{20, 0.0, 0.05}, {20, 1.0, 0.1}, {14, 3.0, 0.5}, {20, 10.0, 2.0}}; + static constexpr double PtMax = 50.0; + // pT vs flattenicity (flattenicity on x, finely binned; pT on y). The flattenicity + // class (e.g. 0-1%) is NOT fixed here: it is extracted offline from the event + // distribution of flattenicity (percentiles), see plotPtSpectraFlatClass.C. + std::shared_ptr hPtVsFlatTruthAvg; + std::shared_ptr hPtVsFlatTruthComb; + std::shared_ptr hPtVsFlatRecoAvg; + std::shared_ptr hPtVsFlatRecoComb; + // ======================================================================== // Configurables // ======================================================================== - - Configurable cfgPtMin{"cfgPtMin", 0.0, "Minimum pT for charged particles/tracks (GeV/c) - Antonio's instruction: require pT > 0, not a physical pT-threshold cut"}; + Configurable cfgPtMin{"cfgPtMin", 0.0, "Minimum pT (GeV/c) - require pT > 0"}; Configurable cfgEtaMax{"cfgEtaMax", 0.8, "Maximum |eta| for INEL>0 and track selection"}; Configurable cfgVzMax{"cfgVzMax", 10.0, "Maximum absolute collision vertex z (cm)"}; - Configurable cfgApplySel8{"cfgApplySel8", true, "Apply sel8 event selection (set to true for all samples)"}; + Configurable cfgApplySel8{"cfgApplySel8", true, "Apply sel8 event selection"}; + Configurable cfgApplyGoodITSLayersAll{"cfgApplyGoodITSLayersAll", true, "Apply kIsGoodITSLayersAll event selection"}; + Configurable cfgRequireInelGt0{"cfgRequireInelGt0", true, "Require INEL>0"}; + Configurable cfgPileupRejection{"cfgPileupRejection", true, "Reject same-bunch pileup (kNoSameBunchPileup)"}; + Configurable cfgGoodZvertex{"cfgGoodZvertex", true, "Require good z-vertex agreement PV-vs-FT0 (kIsGoodZvtxFT0vsPV)"}; + + Configurable cfgITSreq{"cfgITSreq", 0, "ITS requirement (0 = Run3ITSibAny)"}; + + Configurable cfgIsMCReco{"cfgIsMCReco", true, "true = fill MCReco/, false = fill Data/"}; + Configurable cfgNCrossedRowsTPC{"cfgNCrossedRowsTPC", 70, "Minimum TPC crossed rows"}; Configurable cfgChi2PerClusterTPC{"cfgChi2PerClusterTPC", 4.0, "Maximum TPC chi2 per cluster"}; Configurable cfgChi2PerClusterITS{"cfgChi2PerClusterITS", 36.0, "Maximum ITS chi2 per cluster"}; Configurable cfgDCAZ{"cfgDCAZ", 0.1, "Maximum absolute DCAz (cm)"}; - Configurable cfgRequireGoldenChi2{"cfgRequireGoldenChi2", true, "Require global/golden track selection"}; + Configurable cfgRequireGoldenChi2{"cfgRequireGoldenChi2", true, "Require golden chi2"}; + + TrackSelection myTrkSel; + + // Counter and helper to write the Pearson r into the truth-vs-reco titles. + // Called periodically during the job and again at the end of the stream, so the + // title is correct even if endOfStream runs after the histograms are written. + int nCorrFills = 0; + + void updateCorrTitles() { + auto hComb = histos.get(HIST("MCReco/hTruthVsRecoCombined")); + if (hComb && hComb->GetEntries() > 0) { + hComb->SetTitle(Form("Combined: reco vs truth (Pearson r = %.3f);1-#rho (reco, FT0);1-#rho (truth, MC)", hComb->GetCorrelationFactor())); + hComb->SetOption("COLZ"); + } + auto hAvg = histos.get(HIST("MCReco/hTruthVsRecoAverage")); + if (hAvg && hAvg->GetEntries() > 0) { + hAvg->SetTitle(Form("Average: reco vs truth (Pearson r = %.3f);1-#rho (reco, FT0);1-#rho (truth, MC)", hAvg->GetCorrelationFactor())); + hAvg->SetOption("COLZ"); + } + } // ======================================================================== - // PDG charge helper + // init // ======================================================================== - bool isChargedParticle(int pdgCode) - { - const auto* pdgParticle = pdg->GetParticle(pdgCode); - if (!pdgParticle) { - return false; - } - if (std::abs(pdgParticle->Charge()) < ChargeEpsilon) { - return false; + void init(InitContext&) { + gStyle->SetOptStat("em"); + auto itsMatching = static_cast(cfgITSreq.value); + myTrkSel = getGlobalTrackSelectionRun3ITSMatch(itsMatching); + + myTrkSel.SetPtRange(cfgPtMin.value, 1e10f); + myTrkSel.SetEtaRange(-cfgEtaMax.value, cfgEtaMax.value); + myTrkSel.SetRequireGoldenChi2(cfgRequireGoldenChi2.value); + myTrkSel.SetMaxChi2PerClusterTPC(cfgChi2PerClusterTPC.value); + myTrkSel.SetMaxChi2PerClusterITS(cfgChi2PerClusterITS.value); + myTrkSel.SetMinNCrossedRowsTPC(cfgNCrossedRowsTPC.value); + myTrkSel.SetMaxDcaZ(cfgDCAZ.value); + myTrkSel.SetMaxDcaXYPtDep([](float /*pt*/) { return 10000.f; }); + + myTrkSel.print(); + + // pT axis: 0-1 GeV/c in 0.05, 1-3 in 0.1, 3-10 in 0.5, 10-50 in 2 + std::vector ptEdges; + for (const auto& segment : PtSegments) { + for (int i = 0; i < segment.nBins; ++i) { + ptEdges.push_back(segment.start + segment.step * i); + } } - return true; + ptEdges.push_back(PtMax); + const AxisSpec ptAxisSpec{ptEdges, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec flatAxisSpecTruthAvg{NFlatBins, 0.0, 1.0, "flattenicity (MC truth, average)"}; + const AxisSpec flatAxisSpecTruthComb{NFlatBins, 0.0, 1.0, "flattenicity (MC truth, combined)"}; + const AxisSpec flatAxisSpecRecoAvg{NFlatBins, 0.0, 1.0, "flattenicity (reco, FT0 average)"}; + const AxisSpec flatAxisSpecRecoComb{NFlatBins, 0.0, 1.0, "flattenicity (reco, FT0 combined)"}; + hPtVsFlatTruthAvg = histos.add("MCTruth/hPtVsFlatTruthAvg", "MC truth: pT vs flattenicity (average);flattenicity;#it{p}_{T}", + HistType::kTH2F, {flatAxisSpecTruthAvg, ptAxisSpec}); + hPtVsFlatTruthComb = histos.add("MCTruth/hPtVsFlatTruthComb", "MC truth: pT vs flattenicity (combined);flattenicity;#it{p}_{T}", + HistType::kTH2F, {flatAxisSpecTruthComb, ptAxisSpec}); + hPtVsFlatRecoAvg = histos.add("MCReco/hPtVsFlatRecoAvg", "MC reco: pT vs flattenicity (FT0 average);flattenicity;#it{p}_{T}", + HistType::kTH2F, {flatAxisSpecRecoAvg, ptAxisSpec}); + hPtVsFlatRecoComb = histos.add("MCReco/hPtVsFlatRecoComb", "MC reco: pT vs flattenicity (FT0 combined);flattenicity;#it{p}_{T}", + HistType::kTH2F, {flatAxisSpecRecoComb, ptAxisSpec}); } // ======================================================================== - // Rho / flattenicity calculation + // Helpers // ======================================================================== + bool isChargedParticle(int pdgCode) { + const auto* pdgParticle = pdg->GetParticle(pdgCode); + if (!pdgParticle) return false; + if (std::abs(pdgParticle->Charge()) < ChargeEpsilon) return false; + return true; + } + template - float computeRho(const std::array& counts) - { + float computeRho(const std::array& counts) { float total = 0.0f; - for (std::size_t i = 0; i < N; ++i) { - total += counts[i]; - } - if (total <= 0.0f) { - return -1.0f; - } + for (std::size_t i = 0; i < N; ++i) total += counts[i]; + if (total <= 0.0f) return -1.0f; const float mean = total / static_cast(N); - if (mean <= 0.0f) { - return -1.0f; - } + if (mean <= 0.0f) return -1.0f; float sumSq = 0.0f; for (std::size_t i = 0; i < N; ++i) { const float diff = counts[i] - mean; @@ -158,77 +303,85 @@ struct FlattenicityTask { } template - float computeFlattenicity(const std::array& counts) - { + float computeFlattenicity(const std::array& counts) { const float rho = computeRho(counts); - if (rho < 0.0f) { - return -1.0f; - } + if (rho < 0.0f) return -1.0f; return 1.0f - rho; } - // ======================================================================== - // FT0 channel -> sector - // ======================================================================== - int getFT0ASector(int channel) - { - if (channel < 0 || channel >= NchA) { - return -1; - } - return channel / ChannelsPerSector; + // channel -> physical module (see kChannelToModule* above). Returns -1 for + // an out-of-range channel ID. + int getFT0ASector(int channel) { + if (channel < 0 || channel >= NchA) return -1; + return kChannelToModuleA[channel]; } - int getFT0CSector(int channel) - { - if (channel < 0 || channel >= NchC) { - return -1; - } - return channel / ChannelsPerSector; + int getFT0CSector(int channel) { + if (channel < 0 || channel >= NchC) return -1; + return kChannelToModuleC[channel]; } - // ======================================================================== - // Generator particle -> 208-cell grid - // ======================================================================== - int assignToFT0Cell(float eta, float phi, bool& isFT0A) - { + // Project a trajectory of given (eta, phi) from the IP onto the plane + // z = zPlane (signed - negative for FT0-C) and return the (x, y) it hits. + static void projectToPlane(float eta, float phi, float zPlane, float vz, float& x, float& y) { + // vz = z of the (MC) primary vertex: the particle flies from (0,0,vz). + const float theta = 2.0f * std::atan(std::exp(-eta)); + const float r = (zPlane - vz) * std::tan(theta); + x = r * std::cos(phi); + y = r * std::sin(phi); + } + + // Assign a primary charged particle to the FT0 module (real geometry + // module center, nearest-neighbour) whose face it actually points at, + // rather than an assumed uniform eta x phi grid. Returns the module + // index (0..NSectorsA-1 for FT0-A, 0..NSectorsC-1 for FT0-C) or -1 if + // outside both arrays' eta acceptance. isFT0A is set accordingly. + int assignToFT0Module(float eta, float phi, float vz, bool& isFT0A) { const bool inFT0A = (eta > FT0AEtaMin && eta < FT0AEtaMax); const bool inFT0C = (eta > FT0CEtaMin && eta < FT0CEtaMax); - if (!inFT0A && !inFT0C) { - return -1; - } + if (!inFT0A && !inFT0C) return -1; isFT0A = inFT0A; - // Wrap phi into [0, 2pi) using the O2-standard helper - avoids the - // manual +=/-= TwoPI pattern the linter flags (two-pi-add-subtract). - const float wrappedPhi = RecoDecay::constrainAngle(phi, 0.0f); - - const float phiWidth = o2::constants::math::TwoPI / static_cast(NPhiSectors); - int phiBin = static_cast(std::floor(wrappedPhi / phiWidth)); - phiBin = std::max(0, std::min(phiBin, NPhiSectors - 1)); - + float x = 0.0f, y = 0.0f; if (inFT0A) { - const float etaWidth = (FT0AEtaMax - FT0AEtaMin) / static_cast(NEtaA); - int etaBin = static_cast(std::floor((eta - FT0AEtaMin) / etaWidth)); - etaBin = std::max(0, std::min(etaBin, NEtaA - 1)); - return etaBin * NPhiSectors + phiBin; + projectToPlane(eta, phi, kZDetA, vz, x, y); + int best = -1; + float bestD2 = std::numeric_limits::max(); + for (int m = 0; m < NSectorsA; ++m) { + const float dx = x - kModuleAx[m]; + const float dy = y - kModuleAy[m]; + const float d2 = dx * dx + dy * dy; + if (d2 < bestD2) { bestD2 = d2; best = m; } + } + if (cfgRequireModuleHit && best >= 0 && + (std::abs(x - kModuleAx[best]) > kModuleHalfWidth || std::abs(y - kModuleAy[best]) > kModuleHalfWidth)) return -1; + return best; + } + // FT0-C: project using a representative plane z (module z varies by + // < 1.5 cm across the 84.8-86.2 cm concave support, negligible for the + // nearest-module search below). + projectToPlane(eta, phi, -85.6f, vz, x, y); + int best = -1; + float bestD2 = std::numeric_limits::max(); + for (int m = 0; m < NSectorsC; ++m) { + const float dx = x - kModuleCx[m]; + const float dy = y - kModuleCy[m]; + const float d2 = dx * dx + dy * dy; + if (d2 < bestD2) { bestD2 = d2; best = m; } } - const float etaWidth = (FT0CEtaMax - FT0CEtaMin) / static_cast(NEtaC); - int etaBin = static_cast(std::floor((eta - FT0CEtaMin) / etaWidth)); - etaBin = std::max(0, std::min(etaBin, NEtaC - 1)); - return NchA + etaBin * NPhiSectors + phiBin; + if (cfgRequireModuleHit && best >= 0 && + (std::abs(x - kModuleCx[best]) > kModuleHalfWidth || std::abs(y - kModuleCy[best]) > kModuleHalfWidth)) return -1; + return best; } - // ======================================================================== - // Compute both reco definitions - // ======================================================================== template - bool computeFT0Flattenicities(const FT0& ft0, float& flattenicityAverage, float& flattenicityCombined, float& sumAmplitude) - { + bool computeFT0Flattenicities(const FT0& ft0, float& flattenicityAverage, float& flattenicityCombined, float& sumAmplitude) { std::array countsA{}; std::array countsC{}; std::array countsCombined{}; sumAmplitude = 0.0f; + for (std::size_t i = 0; i < ft0.amplitudeA().size(); ++i) { - const int channel = ft0.channelA()[i]; + const int channel = static_cast(ft0.channelA()[i]); const int sector = getFT0ASector(channel); const float amplitude = ft0.amplitudeA()[i]; if (sector >= 0 && sector < NSectorsA) { @@ -238,7 +391,7 @@ struct FlattenicityTask { sumAmplitude += amplitude; } for (std::size_t i = 0; i < ft0.amplitudeC().size(); ++i) { - const int channel = ft0.channelC()[i]; + const int channel = static_cast(ft0.channelC()[i]); const int sector = getFT0CSector(channel); const float amplitude = ft0.amplitudeC()[i]; if (sector >= 0 && sector < NSectorsC) { @@ -247,187 +400,258 @@ struct FlattenicityTask { } sumAmplitude += amplitude; } + + // Both outputs default to -1 (= "not valid"); callers check >= 0 before filling. + flattenicityAverage = -1.0f; + flattenicityCombined = -1.0f; + + // Combined: all 52 modules pooled. Valid as soon as ANY module has signal + // (same behaviour as MC truth), so one-sided events are kept. + const float rhoCombined = computeRho(countsCombined); + if (rhoCombined >= 0.0f) { + flattenicityCombined = 1.0f - rhoCombined; + } + + // Average: needs both FT0-A and FT0-C valid (same behaviour as MC truth). const float rhoA = computeRho(countsA); const float rhoC = computeRho(countsC); - if (rhoA < 0.0f || rhoC < 0.0f) { - return false; + if (rhoA >= 0.0f && rhoC >= 0.0f) { + flattenicityAverage = 1.0f - 0.5f * (rhoA + rhoC); } - flattenicityAverage = 1.0f - 0.5f * (rhoA + rhoC); - const float rhoCombined = computeRho(countsCombined); - if (rhoCombined < 0.0f) { - return false; + + // Event is usable if at least one of the two estimators is valid. + return (flattenicityAverage >= 0.0f || flattenicityCombined >= 0.0f); + } + + template + bool isTrackSelected(const Track& track) { + if (track.pt() <= cfgPtMin) return false; + if (std::abs(track.eta()) > cfgEtaMax) return false; + + for (int i = 0; i < static_cast(TrackSelection::TrackCuts::kNCuts); ++i) { + if (i == static_cast(TrackSelection::TrackCuts::kDCAxy)) continue; + if (!myTrkSel.IsSelected(track, static_cast(i))) return false; + } + + const float dcaXyCut = 0.0105f + 0.0350f / std::pow(track.pt(), 1.1f); + return std::abs(track.dcaXY()) <= dcaXyCut; + } + + template + int countSelectedTracks(const Tracks& tracks, int64_t collIdx) { + int n = 0; + for (const auto& track : tracks) { + if (track.collisionId() != collIdx) continue; + if (!isTrackSelected(track)) continue; + ++n; + } + return n; + } + + // Fill reco-level pT (selected tracks of this collision) vs the event flattenicity. + // Same event conditions as the 1D fine flattenicity histograms, so the percentile + // classes taken from those histograms are consistent with these pT spectra. + template + void fillRecoPtVsFlat(const Tracks& tracks, int64_t collIdx, float flatAvg, float flatComb) { + const bool okAvg = (flatAvg >= 0.0f && flatAvg <= 1.0f); + const bool okComb = (flatComb >= 0.0f && flatComb <= 1.0f); + if (!okAvg && !okComb) return; + for (const auto& track : tracks) { + if (track.collisionId() != collIdx) continue; + if (!isTrackSelected(track)) continue; + if (okAvg) hPtVsFlatRecoAvg->Fill(flatAvg, track.pt()); + if (okComb) hPtVsFlatRecoComb->Fill(flatComb, track.pt()); } - flattenicityCombined = 1.0f - rhoCombined; - return true; } // ======================================================================== - // processMC + // processMC - MC truth per-module plots, truth flattenicity, and + // truth-vs-reco correlation. Selection criteria: + // truth uses only |vz| < cfgVzMax (no truth INEL>0, no both-sides + // requirement); the correlation uses the first reco collision of the MC + // collision with the standard reco event selection. Geometry: real FT0 + // module positions (see kModule* / kChannelToModule* above). // ======================================================================== - void processMC(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) - { - if (std::abs(mcCollision.posZ()) > cfgVzMax) { - return; - } - // Combined 208-cell truth grid (cells 0..NchA-1 = FT0A-like, NchA..NCell-1 - // = FT0C-like) AND the two separate sub-arrays, filled in parallel, so we - // can compute BOTH truth definitions - average and combined - the same - // way the reco side already does for the real FT0-A/FT0-C sectors. - std::array truthCounts{}; - std::array truthCountsA{}; - std::array truthCountsC{}; - int nChINEL = 0; - bool hasFT0A = false, hasFT0C = false; + void processMC(aod::McCollisions::iterator const& mcCollision, + ColMCRecTable const& recCols, + aod::McParticles const& mcParticles, + aod::FT0s const& ft0s) { + if (std::abs(mcCollision.posZ()) > cfgVzMax) return; + const float vzMC = mcCollision.posZ(); + std::array truthA{}; + std::array truthC{}; + std::array truthCombArr{}; + + int nChINEL = 0; + std::vector truthPt; // primary charged, |eta| < cfgEtaMax, pT > cfgPtMin for (const auto& particle : mcParticles) { - if ((particle.flags() & NPhysicalPrimaryBit) == 0) { - continue; - } - if (!isChargedParticle(particle.pdgCode())) { - continue; - } - if (particle.pt() <= cfgPtMin) { - continue; // Antonio: require pT > 0 - } + if (particle.mcCollisionId() != mcCollision.globalIndex()) continue; + if ((particle.flags() & NPhysicalPrimaryBit) == 0) continue; + if (!isChargedParticle(particle.pdgCode())) continue; + if (particle.pt() <= cfgPtMin) continue; if (std::abs(particle.eta()) < cfgEtaMax) { ++nChINEL; - } - - const bool inFT0A = (particle.eta() > FT0AEtaMin && particle.eta() < FT0AEtaMax); - const bool inFT0C = (particle.eta() > FT0CEtaMin && particle.eta() < FT0CEtaMax); - if (inFT0A) { - hasFT0A = true; - } - if (inFT0C) { - hasFT0C = true; + truthPt.push_back(particle.pt()); } bool isFT0A = false; - const int cellId = assignToFT0Cell(particle.eta(), particle.phi(), isFT0A); - if (cellId < 0 || cellId >= NCell) { - continue; - } - truthCounts[cellId] += 1.0f; - if (isFT0A) { - truthCountsA[cellId] += 1.0f; - } else { - truthCountsC[cellId - NchA] += 1.0f; - } + const int module = assignToFT0Module(particle.eta(), particle.phi(), vzMC, isFT0A); + if (module < 0) continue; - histos.fill(HIST("Truth/hCellOccupancy"), cellId); if (isFT0A) { - histos.fill(HIST("Truth/hCellOccupancyFT0A"), cellId); + truthA[module] += 1.0f; + truthCombArr[module] += 1.0f; } else { - histos.fill(HIST("Truth/hCellOccupancyFT0C"), cellId - NchA); + truthC[module] += 1.0f; + truthCombArr[NSectorsA + module] += 1.0f; } } - if (nChINEL == 0) { - return; - } histos.fill(HIST("QA/hEvents"), 1); histos.fill(HIST("QA/hNchINEL"), nChINEL); - // Require activity on BOTH sides of the detector (Antonio's instruction), - // for MC truth exactly as already required on the reco side. - if (!hasFT0A || !hasFT0C) { - return; - } - histos.fill(HIST("QA/hEvents"), 2); - - // Definition 1: average of two separately-normalized rho's (mirrors the - // reco "average" definition, using the truth-grid A/C sub-arrays). - const float rhoATruth = computeRho(truthCountsA); - const float rhoCTruth = computeRho(truthCountsC); - if (rhoATruth >= 0.0f && rhoCTruth >= 0.0f) { - const float flattenicityTruthAverage = 1.0f - 0.5f * (rhoATruth + rhoCTruth); - if (flattenicityTruthAverage >= 0.0f && flattenicityTruthAverage <= 1.0f) { - histos.fill(HIST("Truth/hFlattenicityTruthAverage_fine"), flattenicityTruthAverage); - histos.fill(HIST("Truth/hFlattenicityTruthAverage"), flattenicityTruthAverage); - } + const float rhoA_sec = computeRho(truthA); + const float rhoC_sec = computeRho(truthC); + const float truthAvg = (rhoA_sec >= 0.0f && rhoC_sec >= 0.0f) + ? 1.0f - 0.5f * (rhoA_sec + rhoC_sec) + : -1.0f; + const float truthCombined = computeFlattenicity(truthCombArr); + + if (truthAvg >= 0.0f && truthAvg <= 1.0f) + histos.fill(HIST("MCTruth/hFlattenicityAvgSector_fine"), truthAvg); + if (truthCombined >= 0.0f) + histos.fill(HIST("MCTruth/hFlattenicityCombSector_fine"), truthCombined); + + // pT vs truth flattenicity (same event conditions as the fine histograms above) + for (const auto& pt : truthPt) { + if (truthAvg >= 0.0f && truthAvg <= 1.0f) hPtVsFlatTruthAvg->Fill(truthAvg, pt); + if (truthCombined >= 0.0f) hPtVsFlatTruthComb->Fill(truthCombined, pt); } - // Definition 2: one combined rho over the full 208-cell truth grid. - const float flattenicityTruthCombined = computeFlattenicity(truthCounts); - if (flattenicityTruthCombined >= 0.0f) { - histos.fill(HIST("Truth/hFlattenicityTruthCombined_fine"), flattenicityTruthCombined); - histos.fill(HIST("Truth/hFlattenicityTruthCombined"), flattenicityTruthCombined); + // ---- correlation matrix: measured (reco) vs true ---- + if (recCols.size() == 0) return; + auto recCol = *recCols.begin(); + + if (cfgApplySel8 && !recCol.sel8()) return; + if (cfgPileupRejection && !recCol.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) return; + if (cfgGoodZvertex && !recCol.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) return; + if (std::abs(recCol.posZ()) > cfgVzMax) return; + if (cfgApplyGoodITSLayersAll && + !recCol.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) return; + + aod::FT0s::iterator ft0; + bool foundFT0 = false; + for (const auto& f : ft0s) { + if (f.bcId() == recCol.bcId()) { ft0 = f; foundFT0 = true; break; } } + if (!foundFT0) return; + + float flatAvg = -1.0f, flatComb = -1.0f, sumAmp = 0.0f; + if (!computeFT0Flattenicities(ft0, flatAvg, flatComb, sumAmp)) return; + + if (flatComb >= 0.0f && truthCombined >= 0.0f) + histos.fill(HIST("MCReco/hTruthVsRecoCombined"), flatComb, truthCombined); + if (flatAvg >= 0.0f && truthAvg >= 0.0f) + histos.fill(HIST("MCReco/hTruthVsRecoAverage"), flatAvg, truthAvg); + + if (++nCorrFills % NCorrTitleUpdateInterval == 0) updateCorrTitles(); } - PROCESS_SWITCH(FlattenicityTask, processMC, "Process MC truth for Run-1 calibration", true); + PROCESS_SWITCH(FlattenicityTask, processMC, "Process MC truth", true); // ======================================================================== - // processData + // processDataFull (Hyperloop production schema) // ======================================================================== - void processData(CollisionsWithSelection::iterator const& collision, - aod::FT0s const& ft0s, - FullTracks const& tracks) - { - if (cfgApplySel8 && !collision.sel8()) { - return; - } - if (std::abs(collision.posZ()) > cfgVzMax) { - return; - } - - int nChINEL = 0; - for (const auto& track : tracks) { - if (track.collisionId() != collision.globalIndex()) { - continue; - } - if (track.pt() <= cfgPtMin) { - continue; - } - if (std::abs(track.eta()) < cfgEtaMax) { - ++nChINEL; - } - } - if (nChINEL == 0) { - return; - } - + void processDataFull(CollisionsWithMult::iterator const& collision, + aod::FT0s const& ft0s, + FullTracks const& tracks) { + if (cfgRequireInelGt0 && !collision.isInelGt0()) return; + if (cfgApplySel8 && !collision.sel8()) return; + if (cfgPileupRejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) return; + if (cfgGoodZvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) return; + if (std::abs(collision.posZ()) > cfgVzMax) return; + if (cfgApplyGoodITSLayersAll && + !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) return; + + const int nChINEL = countSelectedTracks(tracks, collision.globalIndex()); histos.fill(HIST("QA/hEvents"), 3); histos.fill(HIST("QA/hNchINEL"), nChINEL); - bool foundFT0 = false; aod::FT0s::iterator ft0; + bool foundFT0 = false; for (const auto& f : ft0s) { - if (f.bcId() == collision.bcId()) { - ft0 = f; - foundFT0 = true; - break; - } + if (f.bcId() == collision.bcId()) { ft0 = f; foundFT0 = true; break; } } - if (!foundFT0) { - return; + if (!foundFT0) return; + + float flatAvg = -1.0f, flatComb = -1.0f, sumFT0M = 0.0f; + if (!computeFT0Flattenicities(ft0, flatAvg, flatComb, sumFT0M)) return; + + if (cfgIsMCReco.value) { + if (flatAvg >= 0.0f && flatAvg <= 1.0f) histos.fill(HIST("MCReco/hFlattenicityFT0Average_fine"), flatAvg); + if (flatComb >= 0.0f && flatComb <= 1.0f) histos.fill(HIST("MCReco/hFlattenicityFT0Combined_fine"), flatComb); + fillRecoPtVsFlat(tracks, collision.globalIndex(), flatAvg, flatComb); + } else { + if (flatAvg >= 0.0f && flatAvg <= 1.0f) histos.fill(HIST("Data/hFlattenicityFT0Average_fine"), flatAvg); + if (flatComb >= 0.0f && flatComb <= 1.0f) histos.fill(HIST("Data/hFlattenicityFT0Combined_fine"), flatComb); } + } - float flattenicityAverage = -1.0f, flattenicityCombined = -1.0f, sumFT0M = 0.0f; - if (!computeFT0Flattenicities(ft0, flattenicityAverage, flattenicityCombined, sumFT0M)) { - return; - } + PROCESS_SWITCH(FlattenicityTask, processDataFull, "Process data / MC-reco with full selection", false); - histos.fill(HIST("Reco/hFT0Mraw"), sumFT0M); - histos.fill(HIST("Reco/hFT0Mraw_fine"), sumFT0M); + // ======================================================================== + // processDataNoMult (local truth-only MC — no O2mult / O2pvmult) + // ======================================================================== + void processDataNoMult(CollisionsNoMult::iterator const& collision, + aod::FT0s const& ft0s, + FullTracks const& tracks) { + if (cfgApplySel8 && !collision.sel8()) return; + if (cfgPileupRejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) return; + if (cfgGoodZvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) return; + if (std::abs(collision.posZ()) > cfgVzMax) return; + if (cfgApplyGoodITSLayersAll && + !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) return; + // NOTE: collision.isInelGt0() intentionally not applied here — this + // reduced schema (CollisionsNoMult) has no aod::Mults/aod::PVMults. + + const int nChINEL = countSelectedTracks(tracks, collision.globalIndex()); + histos.fill(HIST("QA/hEvents"), 3); + histos.fill(HIST("QA/hNchINEL"), nChINEL); - if (flattenicityAverage >= 0.0f && flattenicityAverage <= 1.0f) { - histos.fill(HIST("Reco/hFlattenicityFT0Average_fine"), flattenicityAverage); - histos.fill(HIST("Reco/hFlattenicityFT0Average"), flattenicityAverage); + aod::FT0s::iterator ft0; + bool foundFT0 = false; + for (const auto& f : ft0s) { + if (f.bcId() == collision.bcId()) { ft0 = f; foundFT0 = true; break; } } - if (flattenicityCombined >= 0.0f && flattenicityCombined <= 1.0f) { - histos.fill(HIST("Reco/hFlattenicityFT0Combined_fine"), flattenicityCombined); - histos.fill(HIST("Reco/hFlattenicityFT0Combined"), flattenicityCombined); + if (!foundFT0) return; + + float flatAvg = -1.0f, flatComb = -1.0f, sumFT0M = 0.0f; + if (!computeFT0Flattenicities(ft0, flatAvg, flatComb, sumFT0M)) return; + + if (cfgIsMCReco.value) { + if (flatAvg >= 0.0f && flatAvg <= 1.0f) histos.fill(HIST("MCReco/hFlattenicityFT0Average_fine"), flatAvg); + if (flatComb >= 0.0f && flatComb <= 1.0f) histos.fill(HIST("MCReco/hFlattenicityFT0Combined_fine"), flatComb); + fillRecoPtVsFlat(tracks, collision.globalIndex(), flatAvg, flatComb); + } else { + if (flatAvg >= 0.0f && flatAvg <= 1.0f) histos.fill(HIST("Data/hFlattenicityFT0Average_fine"), flatAvg); + if (flatComb >= 0.0f && flatComb <= 1.0f) histos.fill(HIST("Data/hFlattenicityFT0Combined_fine"), flatComb); } } - PROCESS_SWITCH(FlattenicityTask, processData, "Process data / MC-reco for Run-1 calibration", true); + PROCESS_SWITCH(FlattenicityTask, processDataNoMult, "Process local truth-only MC (no O2mult)", true); + + // ======================================================================== + // endOfStream - runs once at the end of the analysis + // ======================================================================== + void endOfStream(EndOfStreamContext&) { + updateCorrTitles(); + } }; // ============================================================================ // Workflow // ============================================================================ -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } From bc2ec26d67dbba8ee1c1974a6146fc9f329064d2 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Thu, 12 Nov 2026 11:07:58 +0000 Subject: [PATCH 2/4] Please consider the following formatting changes --- PWGMM/UE/Tasks/flattenicityTask.cxx | 277 +++++++++++++++++++--------- 1 file changed, 187 insertions(+), 90 deletions(-) diff --git a/PWGMM/UE/Tasks/flattenicityTask.cxx b/PWGMM/UE/Tasks/flattenicityTask.cxx index 8fd4f8eb828..51b6498ae66 100644 --- a/PWGMM/UE/Tasks/flattenicityTask.cxx +++ b/PWGMM/UE/Tasks/flattenicityTask.cxx @@ -14,14 +14,15 @@ /// \author Eisha Rani /// \since September 2026 +#include "PWGLF/Utils/inelGt.h" + +#include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" #include "Common/DataModel/EventSelection.h" -#include "Common/CCDB/EventSelectionParams.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/TrackSelectionTables.h" -#include "PWGLF/Utils/inelGt.h" #include #include @@ -54,7 +55,7 @@ using namespace o2::soa; using FullTracks = soa::Join; using CollisionsWithMult = soa::Join; -using CollisionsNoMult = soa::Join; +using CollisionsNoMult = soa::Join; // Reco collisions grouped per MC collision using ColMCRecTable = soa::SmallGroups>; @@ -148,7 +149,6 @@ struct FlattenicityTask { "MC Truth - Combined, 52 sectors;1-#rho;Entries", {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, - // ---- MC reco ---- {"MCReco/hFlattenicityFT0Average_fine", "MC Reco - FT0 Average of FT0A and FT0C;1-#rho;Entries", @@ -165,7 +165,6 @@ struct FlattenicityTask { "Data - FT0 Combined FT0A+FT0C;1-#rho;Entries", {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, - // ---- Correlation matrices: x = measured (reco) 1-rho, y = true (MC particles) 1-rho ---- {"MCReco/hTruthVsRecoCombined", "Combined: reco vs truth;1-#rho (reco, FT0 amplitude);1-#rho (truth, MC particles)", @@ -222,7 +221,8 @@ struct FlattenicityTask { // title is correct even if endOfStream runs after the histograms are written. int nCorrFills = 0; - void updateCorrTitles() { + void updateCorrTitles() + { auto hComb = histos.get(HIST("MCReco/hTruthVsRecoCombined")); if (hComb && hComb->GetEntries() > 0) { hComb->SetTitle(Form("Combined: reco vs truth (Pearson r = %.3f);1-#rho (reco, FT0);1-#rho (truth, MC)", hComb->GetCorrelationFactor())); @@ -238,7 +238,8 @@ struct FlattenicityTask { // ======================================================================== // init // ======================================================================== - void init(InitContext&) { + void init(InitContext&) + { gStyle->SetOptStat("em"); auto itsMatching = static_cast(cfgITSreq.value); myTrkSel = getGlobalTrackSelectionRun3ITSMatch(itsMatching); @@ -280,20 +281,27 @@ struct FlattenicityTask { // ======================================================================== // Helpers // ======================================================================== - bool isChargedParticle(int pdgCode) { + bool isChargedParticle(int pdgCode) + { const auto* pdgParticle = pdg->GetParticle(pdgCode); - if (!pdgParticle) return false; - if (std::abs(pdgParticle->Charge()) < ChargeEpsilon) return false; + if (!pdgParticle) + return false; + if (std::abs(pdgParticle->Charge()) < ChargeEpsilon) + return false; return true; } template - float computeRho(const std::array& counts) { + float computeRho(const std::array& counts) + { float total = 0.0f; - for (std::size_t i = 0; i < N; ++i) total += counts[i]; - if (total <= 0.0f) return -1.0f; + for (std::size_t i = 0; i < N; ++i) + total += counts[i]; + if (total <= 0.0f) + return -1.0f; const float mean = total / static_cast(N); - if (mean <= 0.0f) return -1.0f; + if (mean <= 0.0f) + return -1.0f; float sumSq = 0.0f; for (std::size_t i = 0; i < N; ++i) { const float diff = counts[i] - mean; @@ -303,26 +311,33 @@ struct FlattenicityTask { } template - float computeFlattenicity(const std::array& counts) { + float computeFlattenicity(const std::array& counts) + { const float rho = computeRho(counts); - if (rho < 0.0f) return -1.0f; + if (rho < 0.0f) + return -1.0f; return 1.0f - rho; } // channel -> physical module (see kChannelToModule* above). Returns -1 for // an out-of-range channel ID. - int getFT0ASector(int channel) { - if (channel < 0 || channel >= NchA) return -1; + int getFT0ASector(int channel) + { + if (channel < 0 || channel >= NchA) + return -1; return kChannelToModuleA[channel]; } - int getFT0CSector(int channel) { - if (channel < 0 || channel >= NchC) return -1; + int getFT0CSector(int channel) + { + if (channel < 0 || channel >= NchC) + return -1; return kChannelToModuleC[channel]; } // Project a trajectory of given (eta, phi) from the IP onto the plane // z = zPlane (signed - negative for FT0-C) and return the (x, y) it hits. - static void projectToPlane(float eta, float phi, float zPlane, float vz, float& x, float& y) { + static void projectToPlane(float eta, float phi, float zPlane, float vz, float& x, float& y) + { // vz = z of the (MC) primary vertex: the particle flies from (0,0,vz). const float theta = 2.0f * std::atan(std::exp(-eta)); const float r = (zPlane - vz) * std::tan(theta); @@ -335,10 +350,12 @@ struct FlattenicityTask { // rather than an assumed uniform eta x phi grid. Returns the module // index (0..NSectorsA-1 for FT0-A, 0..NSectorsC-1 for FT0-C) or -1 if // outside both arrays' eta acceptance. isFT0A is set accordingly. - int assignToFT0Module(float eta, float phi, float vz, bool& isFT0A) { + int assignToFT0Module(float eta, float phi, float vz, bool& isFT0A) + { const bool inFT0A = (eta > FT0AEtaMin && eta < FT0AEtaMax); const bool inFT0C = (eta > FT0CEtaMin && eta < FT0CEtaMax); - if (!inFT0A && !inFT0C) return -1; + if (!inFT0A && !inFT0C) + return -1; isFT0A = inFT0A; float x = 0.0f, y = 0.0f; @@ -350,10 +367,14 @@ struct FlattenicityTask { const float dx = x - kModuleAx[m]; const float dy = y - kModuleAy[m]; const float d2 = dx * dx + dy * dy; - if (d2 < bestD2) { bestD2 = d2; best = m; } + if (d2 < bestD2) { + bestD2 = d2; + best = m; + } } if (cfgRequireModuleHit && best >= 0 && - (std::abs(x - kModuleAx[best]) > kModuleHalfWidth || std::abs(y - kModuleAy[best]) > kModuleHalfWidth)) return -1; + (std::abs(x - kModuleAx[best]) > kModuleHalfWidth || std::abs(y - kModuleAy[best]) > kModuleHalfWidth)) + return -1; return best; } // FT0-C: project using a representative plane z (module z varies by @@ -366,15 +387,20 @@ struct FlattenicityTask { const float dx = x - kModuleCx[m]; const float dy = y - kModuleCy[m]; const float d2 = dx * dx + dy * dy; - if (d2 < bestD2) { bestD2 = d2; best = m; } + if (d2 < bestD2) { + bestD2 = d2; + best = m; + } } if (cfgRequireModuleHit && best >= 0 && - (std::abs(x - kModuleCx[best]) > kModuleHalfWidth || std::abs(y - kModuleCy[best]) > kModuleHalfWidth)) return -1; + (std::abs(x - kModuleCx[best]) > kModuleHalfWidth || std::abs(y - kModuleCy[best]) > kModuleHalfWidth)) + return -1; return best; } template - bool computeFT0Flattenicities(const FT0& ft0, float& flattenicityAverage, float& flattenicityCombined, float& sumAmplitude) { + bool computeFT0Flattenicities(const FT0& ft0, float& flattenicityAverage, float& flattenicityCombined, float& sumAmplitude) + { std::array countsA{}; std::array countsC{}; std::array countsCombined{}; @@ -424,13 +450,18 @@ struct FlattenicityTask { } template - bool isTrackSelected(const Track& track) { - if (track.pt() <= cfgPtMin) return false; - if (std::abs(track.eta()) > cfgEtaMax) return false; + bool isTrackSelected(const Track& track) + { + if (track.pt() <= cfgPtMin) + return false; + if (std::abs(track.eta()) > cfgEtaMax) + return false; for (int i = 0; i < static_cast(TrackSelection::TrackCuts::kNCuts); ++i) { - if (i == static_cast(TrackSelection::TrackCuts::kDCAxy)) continue; - if (!myTrkSel.IsSelected(track, static_cast(i))) return false; + if (i == static_cast(TrackSelection::TrackCuts::kDCAxy)) + continue; + if (!myTrkSel.IsSelected(track, static_cast(i))) + return false; } const float dcaXyCut = 0.0105f + 0.0350f / std::pow(track.pt(), 1.1f); @@ -438,11 +469,14 @@ struct FlattenicityTask { } template - int countSelectedTracks(const Tracks& tracks, int64_t collIdx) { + int countSelectedTracks(const Tracks& tracks, int64_t collIdx) + { int n = 0; for (const auto& track : tracks) { - if (track.collisionId() != collIdx) continue; - if (!isTrackSelected(track)) continue; + if (track.collisionId() != collIdx) + continue; + if (!isTrackSelected(track)) + continue; ++n; } return n; @@ -452,15 +486,21 @@ struct FlattenicityTask { // Same event conditions as the 1D fine flattenicity histograms, so the percentile // classes taken from those histograms are consistent with these pT spectra. template - void fillRecoPtVsFlat(const Tracks& tracks, int64_t collIdx, float flatAvg, float flatComb) { + void fillRecoPtVsFlat(const Tracks& tracks, int64_t collIdx, float flatAvg, float flatComb) + { const bool okAvg = (flatAvg >= 0.0f && flatAvg <= 1.0f); const bool okComb = (flatComb >= 0.0f && flatComb <= 1.0f); - if (!okAvg && !okComb) return; + if (!okAvg && !okComb) + return; for (const auto& track : tracks) { - if (track.collisionId() != collIdx) continue; - if (!isTrackSelected(track)) continue; - if (okAvg) hPtVsFlatRecoAvg->Fill(flatAvg, track.pt()); - if (okComb) hPtVsFlatRecoComb->Fill(flatComb, track.pt()); + if (track.collisionId() != collIdx) + continue; + if (!isTrackSelected(track)) + continue; + if (okAvg) + hPtVsFlatRecoAvg->Fill(flatAvg, track.pt()); + if (okComb) + hPtVsFlatRecoComb->Fill(flatComb, track.pt()); } } @@ -475,8 +515,10 @@ struct FlattenicityTask { void processMC(aod::McCollisions::iterator const& mcCollision, ColMCRecTable const& recCols, aod::McParticles const& mcParticles, - aod::FT0s const& ft0s) { - if (std::abs(mcCollision.posZ()) > cfgVzMax) return; + aod::FT0s const& ft0s) + { + if (std::abs(mcCollision.posZ()) > cfgVzMax) + return; const float vzMC = mcCollision.posZ(); std::array truthA{}; @@ -486,10 +528,14 @@ struct FlattenicityTask { int nChINEL = 0; std::vector truthPt; // primary charged, |eta| < cfgEtaMax, pT > cfgPtMin for (const auto& particle : mcParticles) { - if (particle.mcCollisionId() != mcCollision.globalIndex()) continue; - if ((particle.flags() & NPhysicalPrimaryBit) == 0) continue; - if (!isChargedParticle(particle.pdgCode())) continue; - if (particle.pt() <= cfgPtMin) continue; + if (particle.mcCollisionId() != mcCollision.globalIndex()) + continue; + if ((particle.flags() & NPhysicalPrimaryBit) == 0) + continue; + if (!isChargedParticle(particle.pdgCode())) + continue; + if (particle.pt() <= cfgPtMin) + continue; if (std::abs(particle.eta()) < cfgEtaMax) { ++nChINEL; truthPt.push_back(particle.pt()); @@ -497,7 +543,8 @@ struct FlattenicityTask { bool isFT0A = false; const int module = assignToFT0Module(particle.eta(), particle.phi(), vzMC, isFT0A); - if (module < 0) continue; + if (module < 0) + continue; if (isFT0A) { truthA[module] += 1.0f; @@ -525,37 +572,52 @@ struct FlattenicityTask { // pT vs truth flattenicity (same event conditions as the fine histograms above) for (const auto& pt : truthPt) { - if (truthAvg >= 0.0f && truthAvg <= 1.0f) hPtVsFlatTruthAvg->Fill(truthAvg, pt); - if (truthCombined >= 0.0f) hPtVsFlatTruthComb->Fill(truthCombined, pt); + if (truthAvg >= 0.0f && truthAvg <= 1.0f) + hPtVsFlatTruthAvg->Fill(truthAvg, pt); + if (truthCombined >= 0.0f) + hPtVsFlatTruthComb->Fill(truthCombined, pt); } // ---- correlation matrix: measured (reco) vs true ---- - if (recCols.size() == 0) return; + if (recCols.size() == 0) + return; auto recCol = *recCols.begin(); - if (cfgApplySel8 && !recCol.sel8()) return; - if (cfgPileupRejection && !recCol.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) return; - if (cfgGoodZvertex && !recCol.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) return; - if (std::abs(recCol.posZ()) > cfgVzMax) return; + if (cfgApplySel8 && !recCol.sel8()) + return; + if (cfgPileupRejection && !recCol.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + return; + if (cfgGoodZvertex && !recCol.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return; + if (std::abs(recCol.posZ()) > cfgVzMax) + return; if (cfgApplyGoodITSLayersAll && - !recCol.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) return; + !recCol.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + return; aod::FT0s::iterator ft0; bool foundFT0 = false; for (const auto& f : ft0s) { - if (f.bcId() == recCol.bcId()) { ft0 = f; foundFT0 = true; break; } + if (f.bcId() == recCol.bcId()) { + ft0 = f; + foundFT0 = true; + break; + } } - if (!foundFT0) return; + if (!foundFT0) + return; float flatAvg = -1.0f, flatComb = -1.0f, sumAmp = 0.0f; - if (!computeFT0Flattenicities(ft0, flatAvg, flatComb, sumAmp)) return; + if (!computeFT0Flattenicities(ft0, flatAvg, flatComb, sumAmp)) + return; if (flatComb >= 0.0f && truthCombined >= 0.0f) histos.fill(HIST("MCReco/hTruthVsRecoCombined"), flatComb, truthCombined); if (flatAvg >= 0.0f && truthAvg >= 0.0f) histos.fill(HIST("MCReco/hTruthVsRecoAverage"), flatAvg, truthAvg); - if (++nCorrFills % NCorrTitleUpdateInterval == 0) updateCorrTitles(); + if (++nCorrFills % NCorrTitleUpdateInterval == 0) + updateCorrTitles(); } PROCESS_SWITCH(FlattenicityTask, processMC, "Process MC truth", true); @@ -565,14 +627,21 @@ struct FlattenicityTask { // ======================================================================== void processDataFull(CollisionsWithMult::iterator const& collision, aod::FT0s const& ft0s, - FullTracks const& tracks) { - if (cfgRequireInelGt0 && !collision.isInelGt0()) return; - if (cfgApplySel8 && !collision.sel8()) return; - if (cfgPileupRejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) return; - if (cfgGoodZvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) return; - if (std::abs(collision.posZ()) > cfgVzMax) return; + FullTracks const& tracks) + { + if (cfgRequireInelGt0 && !collision.isInelGt0()) + return; + if (cfgApplySel8 && !collision.sel8()) + return; + if (cfgPileupRejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + return; + if (cfgGoodZvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return; + if (std::abs(collision.posZ()) > cfgVzMax) + return; if (cfgApplyGoodITSLayersAll && - !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) return; + !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + return; const int nChINEL = countSelectedTracks(tracks, collision.globalIndex()); histos.fill(HIST("QA/hEvents"), 3); @@ -581,20 +650,30 @@ struct FlattenicityTask { aod::FT0s::iterator ft0; bool foundFT0 = false; for (const auto& f : ft0s) { - if (f.bcId() == collision.bcId()) { ft0 = f; foundFT0 = true; break; } + if (f.bcId() == collision.bcId()) { + ft0 = f; + foundFT0 = true; + break; + } } - if (!foundFT0) return; + if (!foundFT0) + return; float flatAvg = -1.0f, flatComb = -1.0f, sumFT0M = 0.0f; - if (!computeFT0Flattenicities(ft0, flatAvg, flatComb, sumFT0M)) return; + if (!computeFT0Flattenicities(ft0, flatAvg, flatComb, sumFT0M)) + return; if (cfgIsMCReco.value) { - if (flatAvg >= 0.0f && flatAvg <= 1.0f) histos.fill(HIST("MCReco/hFlattenicityFT0Average_fine"), flatAvg); - if (flatComb >= 0.0f && flatComb <= 1.0f) histos.fill(HIST("MCReco/hFlattenicityFT0Combined_fine"), flatComb); + if (flatAvg >= 0.0f && flatAvg <= 1.0f) + histos.fill(HIST("MCReco/hFlattenicityFT0Average_fine"), flatAvg); + if (flatComb >= 0.0f && flatComb <= 1.0f) + histos.fill(HIST("MCReco/hFlattenicityFT0Combined_fine"), flatComb); fillRecoPtVsFlat(tracks, collision.globalIndex(), flatAvg, flatComb); } else { - if (flatAvg >= 0.0f && flatAvg <= 1.0f) histos.fill(HIST("Data/hFlattenicityFT0Average_fine"), flatAvg); - if (flatComb >= 0.0f && flatComb <= 1.0f) histos.fill(HIST("Data/hFlattenicityFT0Combined_fine"), flatComb); + if (flatAvg >= 0.0f && flatAvg <= 1.0f) + histos.fill(HIST("Data/hFlattenicityFT0Average_fine"), flatAvg); + if (flatComb >= 0.0f && flatComb <= 1.0f) + histos.fill(HIST("Data/hFlattenicityFT0Combined_fine"), flatComb); } } @@ -605,13 +684,19 @@ struct FlattenicityTask { // ======================================================================== void processDataNoMult(CollisionsNoMult::iterator const& collision, aod::FT0s const& ft0s, - FullTracks const& tracks) { - if (cfgApplySel8 && !collision.sel8()) return; - if (cfgPileupRejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) return; - if (cfgGoodZvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) return; - if (std::abs(collision.posZ()) > cfgVzMax) return; + FullTracks const& tracks) + { + if (cfgApplySel8 && !collision.sel8()) + return; + if (cfgPileupRejection && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + return; + if (cfgGoodZvertex && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + return; + if (std::abs(collision.posZ()) > cfgVzMax) + return; if (cfgApplyGoodITSLayersAll && - !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) return; + !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + return; // NOTE: collision.isInelGt0() intentionally not applied here — this // reduced schema (CollisionsNoMult) has no aod::Mults/aod::PVMults. @@ -622,20 +707,30 @@ struct FlattenicityTask { aod::FT0s::iterator ft0; bool foundFT0 = false; for (const auto& f : ft0s) { - if (f.bcId() == collision.bcId()) { ft0 = f; foundFT0 = true; break; } + if (f.bcId() == collision.bcId()) { + ft0 = f; + foundFT0 = true; + break; + } } - if (!foundFT0) return; + if (!foundFT0) + return; float flatAvg = -1.0f, flatComb = -1.0f, sumFT0M = 0.0f; - if (!computeFT0Flattenicities(ft0, flatAvg, flatComb, sumFT0M)) return; + if (!computeFT0Flattenicities(ft0, flatAvg, flatComb, sumFT0M)) + return; if (cfgIsMCReco.value) { - if (flatAvg >= 0.0f && flatAvg <= 1.0f) histos.fill(HIST("MCReco/hFlattenicityFT0Average_fine"), flatAvg); - if (flatComb >= 0.0f && flatComb <= 1.0f) histos.fill(HIST("MCReco/hFlattenicityFT0Combined_fine"), flatComb); + if (flatAvg >= 0.0f && flatAvg <= 1.0f) + histos.fill(HIST("MCReco/hFlattenicityFT0Average_fine"), flatAvg); + if (flatComb >= 0.0f && flatComb <= 1.0f) + histos.fill(HIST("MCReco/hFlattenicityFT0Combined_fine"), flatComb); fillRecoPtVsFlat(tracks, collision.globalIndex(), flatAvg, flatComb); } else { - if (flatAvg >= 0.0f && flatAvg <= 1.0f) histos.fill(HIST("Data/hFlattenicityFT0Average_fine"), flatAvg); - if (flatComb >= 0.0f && flatComb <= 1.0f) histos.fill(HIST("Data/hFlattenicityFT0Combined_fine"), flatComb); + if (flatAvg >= 0.0f && flatAvg <= 1.0f) + histos.fill(HIST("Data/hFlattenicityFT0Average_fine"), flatAvg); + if (flatComb >= 0.0f && flatComb <= 1.0f) + histos.fill(HIST("Data/hFlattenicityFT0Combined_fine"), flatComb); } } @@ -644,7 +739,8 @@ struct FlattenicityTask { // ======================================================================== // endOfStream - runs once at the end of the analysis // ======================================================================== - void endOfStream(EndOfStreamContext&) { + void endOfStream(EndOfStreamContext&) + { updateCorrTitles(); } }; @@ -652,6 +748,7 @@ struct FlattenicityTask { // ============================================================================ // Workflow // ============================================================================ -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ return WorkflowSpec{adaptAnalysisTask(cfgc)}; } From a61bf9f78f2fab24dd0175507a2828ebb84aa668 Mon Sep 17 00:00:00 2001 From: eranicern-qwer Date: Thu, 12 Nov 2026 16:35:12 +0500 Subject: [PATCH 3/4] Remove unused kModuleCz --- PWGMM/UE/Tasks/flattenicityTask.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/PWGMM/UE/Tasks/flattenicityTask.cxx b/PWGMM/UE/Tasks/flattenicityTask.cxx index 51b6498ae66..0706fc3a019 100644 --- a/PWGMM/UE/Tasks/flattenicityTask.cxx +++ b/PWGMM/UE/Tasks/flattenicityTask.cxx @@ -117,7 +117,6 @@ struct FlattenicityTask { static constexpr float kModuleAy[NSectorsA] = {12.2000f, 12.2000f, 13.5300f, 12.2000f, 12.2000f, 6.1000f, 6.1000f, 7.4300f, 6.1000f, 6.1000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, -6.1000f, -6.1000f, -7.4300f, -6.1000f, -6.1000f, -12.2000f, -12.2000f, -13.5300f, -12.2000f, -12.2000f}; static constexpr float kModuleCx[NSectorsC] = {-15.5426f, 15.5426f, -15.5069f, 15.5069f, -9.3296f, 9.3296f, -9.3296f, 9.3296f, -9.3296f, 9.3296f, -3.1011f, 3.1011f, -3.1286f, 3.1286f, 3.1010f, -3.1010f, 3.1286f, -3.1286f, 9.3295f, -9.3295f, 9.3296f, -9.3296f, 9.3296f, -9.3296f, 15.5425f, -15.5425f, 15.5068f, -15.5068f}; static constexpr float kModuleCy[NSectorsC] = {3.2659f, -3.2659f, 9.4726f, -9.4726f, 3.2436f, -3.2436f, 9.4726f, -9.4726f, 15.6494f, -15.6494f, 9.4725f, -9.4725f, 15.6982f, -15.6982f, 9.4724f, -9.4724f, 15.6981f, -15.6981f, 3.2435f, -3.2435f, 9.4725f, -9.4725f, 15.6493f, -15.6493f, 3.2659f, -3.2659f, 9.4725f, -9.4725f}; - static constexpr float kModuleCz[NSectorsC] = {-85.2486f, -85.2486f, -84.7790f, -84.7790f, -86.1724f, -86.1724f, -85.7006f, -85.7006f, -84.7685f, -84.7685f, -86.1618f, -86.1618f, -85.2246f, -85.2246f, -86.1619f, -86.1619f, -85.2247f, -85.2247f, -86.1725f, -86.1725f, -85.7006f, -85.7006f, -84.7685f, -84.7685f, -85.2486f, -85.2486f, -84.7791f, -84.7791f}; // Official FT0 channel ID -> geometry module index, built by inverting // localChannelOrder[] from AliceO2 Detectors/FIT/FT0/base/include/FT0Base/ From 542e42b2a2c0b7f5007a4ff9455dbf614c311d0e Mon Sep 17 00:00:00 2001 From: eranicern-qwer Date: Thu, 12 Nov 2026 16:42:56 +0500 Subject: [PATCH 4/4] Add missing memory include --- PWGMM/UE/Tasks/flattenicityTask.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/PWGMM/UE/Tasks/flattenicityTask.cxx b/PWGMM/UE/Tasks/flattenicityTask.cxx index 0706fc3a019..e4e1836fb46 100644 --- a/PWGMM/UE/Tasks/flattenicityTask.cxx +++ b/PWGMM/UE/Tasks/flattenicityTask.cxx @@ -45,6 +45,7 @@ #include #include #include +#include #include using namespace o2;