Skip to content

Commit da7c51b

Browse files
PaolaVTPaolaVT
authored andcommitted
replace Framework/Constants.h with CommonConstants/MathConstants.h for fattenicity task
1 parent 45438cf commit da7c51b

1 file changed

Lines changed: 321 additions & 0 deletions

File tree

Lines changed: 321 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
/// \file flattenicityTask.cxx
13+
/// \brief Flattenicity analysis task for UE studies
14+
/// \author Eisha Rani
15+
/// \since August 2026
16+
17+
#include "Common/Core/TrackSelection.h"
18+
#include "Common/Core/TrackSelectionDefaults.h"
19+
#include "Common/DataModel/EventSelection.h"
20+
#include "Common/DataModel/Multiplicity.h"
21+
#include "Common/DataModel/TrackSelectionTables.h"
22+
23+
#include <CommonConstants/MathConstants.h>
24+
#include <Framework/ASoAHelpers.h>
25+
#include <Framework/AnalysisDataModel.h>
26+
#include <Framework/AnalysisTask.h>
27+
#include <Framework/Configurable.h>
28+
#include <Framework/HistogramRegistry.h>
29+
#include <Framework/InitContext.h>
30+
#include <Framework/O2DatabasePDGPlugin.h>
31+
#include <Framework/runDataProcessing.h>
32+
#include <ReconstructionDataFormats/Track.h>
33+
34+
#include <cmath>
35+
#include <vector>
36+
37+
using namespace o2;
38+
using namespace o2::framework;
39+
using namespace o2::framework::expressions;
40+
41+
struct FlattenicityTask {
42+
43+
// --- Flattenicity constants ---
44+
static constexpr int NCH_A = 96;
45+
static constexpr int NCH_C = 112;
46+
static constexpr int NCELL = NCH_A + NCH_C;
47+
static constexpr int NPHISECTORS = 8;
48+
static constexpr int NETA_A = NCH_A / NPHISECTORS;
49+
static constexpr int NETA_C = NCH_C / NPHISECTORS;
50+
51+
// FT0 acceptance
52+
static constexpr float FT0A_ETA_MIN = 3.5f;
53+
static constexpr float FT0A_ETA_MAX = 4.9f;
54+
static constexpr float FT0C_ETA_MIN = -3.3f;
55+
static constexpr float FT0C_ETA_MAX = -2.1f;
56+
57+
// --- Event selection constants ---
58+
static constexpr float VERTEX_CUT = 10.0f;
59+
static constexpr float FLAT_MIN = 0.0f;
60+
static constexpr float INEL_ETA_CUT = 1.0f;
61+
static constexpr float MIDRAP_ETA_CUT = 0.8f;
62+
63+
// --- Configurables ---
64+
Configurable<float> cfgTrkEtaCut{"cfgTrkEtaCut", 0.8f, "Eta range for tracks"};
65+
Configurable<float> cfgTrkLowPtCut{"cfgTrkLowPtCut", 0.15f, "Minimum pT"};
66+
67+
Configurable<bool> isRun3{"isRun3", true, "is Run3 dataset"};
68+
Configurable<bool> timeEvsel{"timeEvsel", true, "TPC Time frame boundary cut"};
69+
Configurable<bool> piluprejection{"piluprejection", true, "Pileup rejection"};
70+
Configurable<bool> goodzvertex{"goodzvertex", true, "Good Z vertex"};
71+
72+
// --- Track selection ---
73+
TrackSelection mySelectionPrim;
74+
75+
// --- Histograms ---
76+
HistogramRegistry registry;
77+
78+
// --- Init ---
79+
void init(InitContext const&) override
80+
{
81+
// Initialize track selection
82+
mySelectionPrim = myTrackSelectionPrim();
83+
84+
// Define histograms
85+
AxisSpec flatBins = {40, 0.0, 1.0, "#rho"};
86+
AxisSpec nchBins = {100, -0.5, 99.5, "N_{ch}"};
87+
88+
registry.add("hFlattenicityTruth", "Truth flattenicity; 1-#rho; Events",
89+
HistType::kTH1D, {flatBins});
90+
registry.add("hFlattenicityReco", "Reco flattenicity; 1-#rho; Events",
91+
HistType::kTH1D, {flatBins});
92+
registry.add("hFlattenicityCorrelation", "Truth vs Reco; 1-#rho_{truth}; 1-#rho_{reco}",
93+
HistType::kTH2D, {flatBins, flatBins});
94+
registry.add("hNch", "Reco Nch distribution; N_{ch}; Events",
95+
HistType::kTH1D, {nchBins});
96+
registry.add("hNchTruth", "Truth Nch distribution; N_{ch}; Events",
97+
HistType::kTH1D, {nchBins});
98+
}
99+
100+
// --- Track selection function ---
101+
TrackSelection myTrackSelectionPrim()
102+
{
103+
TrackSelection selectedTracks;
104+
selectedTracks.SetPtRange(0.1f, 1e10f);
105+
selectedTracks.SetEtaRange(-0.8f, 0.8f);
106+
selectedTracks.SetRequireITSRefit(true);
107+
selectedTracks.SetRequireTPCRefit(true);
108+
selectedTracks.SetMinNCrossedRowsTPC(70);
109+
selectedTracks.SetMinNCrossedRowsOverFindableClustersTPC(0.4f);
110+
selectedTracks.SetMaxChi2PerClusterTPC(4.0f);
111+
selectedTracks.SetRequireHitsInITSLayers(1, {0, 1});
112+
selectedTracks.SetMaxChi2PerClusterITS(36.0f);
113+
selectedTracks.SetMaxDcaXYPtDep([](float pt) { return 0.0105f + 0.0350f / std::pow(pt, 1.1f); });
114+
selectedTracks.SetMaxDcaZ(2.0f);
115+
return selectedTracks;
116+
}
117+
118+
// --- Helper: Get cell ID for a particle in FT0 acceptance ---
119+
int getCellId(float eta, float phi)
120+
{
121+
// Check if in FT0-A acceptance
122+
if (eta > FT0A_ETA_MIN && eta < FT0A_ETA_MAX) {
123+
int phiBin = static_cast<int>(std::floor(phi / (2.0f * o2::constants::math::PI / static_cast<float>(NPHISECTORS))));
124+
phiBin = std::clamp(phiBin, 0, NPHISECTORS - 1);
125+
int etaBin = static_cast<int>(std::floor((eta - FT0A_ETA_MIN) / ((FT0A_ETA_MAX - FT0A_ETA_MIN) / static_cast<float>(NETA_A))));
126+
etaBin = std::clamp(etaBin, 0, NETA_A - 1);
127+
return etaBin * NPHISECTORS + phiBin;
128+
}
129+
130+
// Check if in FT0-C acceptance
131+
if (eta > FT0C_ETA_MIN && eta < FT0C_ETA_MAX) {
132+
int phiBin = static_cast<int>(std::floor(phi / (2.0f * o2::constants::math::PI / static_cast<float>(NPHISECTORS))));
133+
phiBin = std::clamp(phiBin, 0, NPHISECTORS - 1);
134+
int etaBin = static_cast<int>(std::floor((eta - FT0C_ETA_MIN) / ((FT0C_ETA_MAX - FT0C_ETA_MIN) / static_cast<float>(NETA_C))));
135+
etaBin = std::clamp(etaBin, 0, NETA_C - 1);
136+
return NCH_A + etaBin * NPHISECTORS + phiBin;
137+
}
138+
139+
return -1; // Not in FT0 acceptance
140+
}
141+
142+
// --- Flattenicity calculation ---
143+
float calculateFlattenicity(const std::vector<float>& counts)
144+
{
145+
if (counts.size() != static_cast<size_t>(NCELL)) {
146+
return -1.0f;
147+
}
148+
149+
float total = 0.0f;
150+
for (const auto& c : counts) {
151+
total += c;
152+
}
153+
if (total <= 0.0f) {
154+
return -1.0f;
155+
}
156+
157+
float mean = total / static_cast<float>(NCELL);
158+
if (mean <= 0.0f) {
159+
return -1.0f;
160+
}
161+
162+
float sumSq = 0.0f;
163+
for (const auto& c : counts) {
164+
sumSq += (c - mean) * (c - mean);
165+
}
166+
167+
float rho = std::sqrt(sumSq / (static_cast<float>(NCELL) * static_cast<float>(NCELL))) / mean;
168+
return 1.0f - rho;
169+
}
170+
171+
// --- Process Data ---
172+
void processData(aod::Collision const& collision,
173+
soa::Filtered<aod::Tracks> const& tracks,
174+
aod::FT0s const& ft0s)
175+
{
176+
// Event selection (Paola/Jesus)
177+
if (!collision.sel8()) {
178+
return;
179+
}
180+
if (std::abs(collision.posZ()) >= VERTEX_CUT) {
181+
return;
182+
}
183+
184+
// Track loop for Nch
185+
int nch = 0;
186+
for (const auto& track : tracks) {
187+
if (!mySelectionPrim.IsSelected(track)) {
188+
continue;
189+
}
190+
nch++;
191+
}
192+
registry.fill(HIST("hNch"), nch);
193+
194+
// FT0 flattenicity
195+
auto ft0 = collision.ft0();
196+
if (ft0.hasAmplitudeA() && ft0.hasAmplitudeC()) {
197+
auto ampA = ft0.amplitudeA();
198+
auto ampC = ft0.amplitudeC();
199+
200+
std::vector<float> counts(NCELL, 0.0f);
201+
for (int i = 0; i < static_cast<int>(ampA.size()) && i < NCH_A; ++i) {
202+
counts[i] = ampA[i];
203+
}
204+
for (int i = 0; i < static_cast<int>(ampC.size()) && i < NCH_C; ++i) {
205+
counts[NCH_A + i] = ampC[i];
206+
}
207+
208+
float flat = calculateFlattenicity(counts);
209+
if (flat >= FLAT_MIN) {
210+
registry.fill(HIST("hFlattenicityReco"), flat);
211+
}
212+
}
213+
}
214+
PROCESS_SWITCH(FlattenicityTask, processData, "Process data", true);
215+
216+
// --- Process MC ---
217+
void processMC(aod::McCollision const& mcCollision,
218+
aod::McParticles const& particles,
219+
soa::SmallGroups<soa::Join<aod::McCollisionLabels, aod::Collisions>> const& collisions,
220+
aod::FT0s const& ft0s,
221+
aod::BCs const& /*bcs*/)
222+
{
223+
// ---- Truth-level processing ----
224+
bool inel = false;
225+
int nchTruth = 0;
226+
std::vector<float> truthCounts(NCELL, 0.0f);
227+
228+
for (const auto& particle : particles) {
229+
// Check if physical primary
230+
if (!particle.isPhysicalPrimary()) {
231+
continue;
232+
}
233+
234+
// Check if charged
235+
if (std::abs(particle.pdgCode()) == 0) {
236+
continue;
237+
}
238+
239+
// Check pT > 0
240+
if (particle.pt() <= 0.0f) {
241+
continue;
242+
}
243+
244+
// INEL>0 check: primary charged with |eta| < INEL_ETA_CUT
245+
if (std::abs(particle.eta()) < INEL_ETA_CUT) {
246+
inel = true;
247+
}
248+
249+
// Nch at midrapidity: |eta| < MIDRAP_ETA_CUT, pT > cfgTrkLowPtCut
250+
if (std::abs(particle.eta()) < MIDRAP_ETA_CUT && particle.pt() > cfgTrkLowPtCut) {
251+
nchTruth++;
252+
}
253+
254+
// Flattenicity: particles in FT0 acceptance
255+
int cellId = getCellId(particle.eta(), particle.phi());
256+
if (cellId >= 0 && cellId < NCELL) {
257+
truthCounts[cellId] += 1.0f;
258+
}
259+
}
260+
261+
// Apply truth-level event selection (Paola/Jesus)
262+
if (!inel) {
263+
return;
264+
}
265+
if (std::abs(mcCollision.posZ()) >= VERTEX_CUT) {
266+
return;
267+
}
268+
269+
// Fill truth multiplicity
270+
registry.fill(HIST("hNchTruth"), nchTruth);
271+
registry.fill(HIST("hNch"), nchTruth);
272+
273+
// Calculate truth flattenicity
274+
float truthFlat = calculateFlattenicity(truthCounts);
275+
if (truthFlat >= FLAT_MIN) {
276+
registry.fill(HIST("hFlattenicityTruth"), truthFlat);
277+
}
278+
279+
// ---- Reconstructed-level processing for matched collisions ----
280+
for (const auto& collision : collisions) {
281+
// Apply reconstruction-level event selection
282+
if (!collision.sel8()) {
283+
continue;
284+
}
285+
if (std::abs(collision.posZ()) >= VERTEX_CUT) {
286+
continue;
287+
}
288+
289+
// Get FT0 flattenicity for this collision
290+
auto ft0 = collision.ft0();
291+
if (!ft0.hasAmplitudeA() || !ft0.hasAmplitudeC()) {
292+
continue;
293+
}
294+
295+
auto ampA = ft0.amplitudeA();
296+
auto ampC = ft0.amplitudeC();
297+
298+
std::vector<float> recoCounts(NCELL, 0.0f);
299+
for (int i = 0; i < static_cast<int>(ampA.size()) && i < NCH_A; ++i) {
300+
recoCounts[i] = ampA[i];
301+
}
302+
for (int i = 0; i < static_cast<int>(ampC.size()) && i < NCH_C; ++i) {
303+
recoCounts[NCH_A + i] = ampC[i];
304+
}
305+
306+
float recoFlat = calculateFlattenicity(recoCounts);
307+
if (recoFlat >= FLAT_MIN && truthFlat >= FLAT_MIN) {
308+
registry.fill(HIST("hFlattenicityReco"), recoFlat);
309+
registry.fill(HIST("hFlattenicityCorrelation"), truthFlat, recoFlat);
310+
}
311+
}
312+
}
313+
PROCESS_SWITCH(FlattenicityTask, processMC, "Process MC", true);
314+
};
315+
316+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
317+
{
318+
WorkflowSpec workflow{};
319+
workflow.push_back(adaptAnalysisTask<FlattenicityTask>(cfgc));
320+
return workflow;
321+
}

0 commit comments

Comments
 (0)