|
8 | 8 | // In applying this license CERN does not waive the privileges and immunities |
9 | 9 | // granted to it by virtue of its status as an Intergovernmental Organization |
10 | 10 | // or submit itself to any jurisdiction. |
| 11 | + |
| 12 | +/// \file systematicsMapping.cxx |
| 13 | +/// \brief Task to perform a systematics study for K0s and charged Kaons |
| 14 | +/// \author Nicolò Jacazio, Universita del Piemonte Orientale (IT) |
| 15 | +/// \since September 22, 2025 |
| 16 | + |
11 | 17 | #include "PWGLF/DataModel/LFStrangenessTables.h" |
12 | 18 |
|
13 | 19 | #include "Common/DataModel/EventSelection.h" |
14 | | -#include "Common/DataModel/PIDResponse.h" |
| 20 | +#include "Common/DataModel/PIDResponseTPC.h" |
| 21 | +#include "Common/DataModel/PIDResponseTOF.h" |
| 22 | + |
| 23 | +#include <Framework/AnalysisDataModel.h> |
| 24 | +#include <Framework/AnalysisTask.h> |
| 25 | +#include <Framework/HistogramRegistry.h> |
| 26 | +#include <Framework/runDataProcessing.h> |
| 27 | +#include <ReconstructionDataFormats/Track.h> |
15 | 28 |
|
16 | | -#include "Framework/AnalysisDataModel.h" |
17 | | -#include "Framework/AnalysisTask.h" |
18 | | -#include "Framework/HistogramRegistry.h" |
19 | | -#include "ReconstructionDataFormats/Track.h" |
| 29 | +#include <algorithm> |
20 | 30 |
|
21 | 31 | using namespace o2; |
22 | 32 | using namespace o2::framework; |
23 | 33 |
|
24 | | -struct systematicsStudy { |
| 34 | +struct systematicsMapping { |
| 35 | + // Returns a unique index for the combination of cuts |
25 | 36 | ConfigurableAxis ptBins{"ptBins", {100, 0.f, 10.f}, "Binning for pT (GeV/c)"}; |
26 | | - Configurable<float> cutEta{"cutEta", 0.8f, "Max |eta| for tracks and V0s"}; |
27 | | - Configurable<int> cutTPCClusters{"cutTPCClusters", 70, "Min TPC clusters for tracks"}; |
28 | | - Configurable<float> cutKaonNSigma{"cutKaonNSigma", 3.f, "Max |nSigma| for kaon PID"}; |
29 | | - Configurable<float> cutK0sMassWindow{"cutK0sMassWindow", 0.01f, "K0s mass window (GeV/c^2)"}; |
30 | 37 | ConfigurableAxis etaBins{"etaBins", {40, -1.0f, 1.0f}, "Binning for #eta"}; |
31 | 38 | ConfigurableAxis phiBins{"phiBins", {36, 0.f, 2 * M_PI}, "Binning for #phi (rad)"}; |
| 39 | + // Define the Signal axis |
| 40 | + ConfigurableAxis invariantMassBins{"invariantMassBins", {100, -0.1f, 0.1f}, "Binning for the invariant mass (GeV/c^2)"}; |
| 41 | + ConfigurableAxis nsigmaBins{"nsigmaBins", {100, -10.f, 10.f}, "Binning for nSigma"}; |
| 42 | + // Selection bins |
| 43 | + ConfigurableAxis tpcClusterBins{"tpcClusterBins", {5, 70, 100, 120, 135, 150}, "Min TPC clusters for tracks"}; |
| 44 | + ConfigurableAxis itsClustersBins{"itsClustersBins", {5, 0, 6}, "Min ITS clusters for tracks"}; |
| 45 | + |
32 | 46 | HistogramRegistry registry{"registry"}; |
33 | 47 |
|
| 48 | + template <typename T> |
| 49 | + bool isCollisionSelected(T const& collision) |
| 50 | + { |
| 51 | + return collision.sel8() && std::abs(collision.posZ()) <= 10.f; |
| 52 | + } |
| 53 | + |
34 | 54 | void init(InitContext const&) |
35 | 55 | { |
36 | 56 | const AxisSpec ptAxis{ptBins, "#it{p}_{T} (GeV/c)"}; |
37 | 57 | const AxisSpec etaAxis{etaBins, "#eta"}; |
38 | 58 | const AxisSpec phiAxis{phiBins, "#phi (rad)"}; |
39 | | - registry.add("hKaonYieldData", "", HistType::kTH1F, {ptAxis}); |
40 | | - registry.add("hKaonYieldMC", "", HistType::kTH1F, {ptAxis}); |
41 | | - registry.add("hK0sYieldData", "", HistType::kTH1F, {ptAxis}); |
42 | | - registry.add("hK0sYieldMC", "", HistType::kTH1F, {ptAxis}); |
43 | | - registry.add("hKaonYieldMapData", "", HistType::kTH3F, {ptAxis, etaAxis, phiAxis}); |
44 | | - registry.add("hKaonYieldMapMC", "", HistType::kTH3F, {ptAxis, etaAxis, phiAxis}); |
45 | | - registry.add("hK0sYieldMapData", "", HistType::kTH3F, {ptAxis, etaAxis, phiAxis}); |
46 | | - registry.add("hK0sYieldMapMC", "", HistType::kTH3F, {ptAxis, etaAxis, phiAxis}); |
| 59 | + |
| 60 | + if (doprocessData) { |
| 61 | + |
| 62 | + // First we define the histograms on which we are cutting (tpc clusters, its clusters, ..) |
| 63 | + registry.add("K/hTPCClusters", "", HistType::kTH1F, {{100, 0, 200}}); |
| 64 | + registry.add("K/hITSClusters", "", HistType::kTH1F, {{10, 0, 10}}); |
| 65 | + registry.addClone("K/", "K0s/"); |
| 66 | + |
| 67 | + // Add the signal histograms |
| 68 | + registry.add("K/SignalPositive", "", HistType::kTHnSparseF, {ptBins, etaBins, phiBins, nsigmaBins, tpcClusterBins, itsClustersBins}); |
| 69 | + registry.add("K/SignalNegative", "", HistType::kTHnSparseF, {ptBins, etaBins, phiBins, nsigmaBins, tpcClusterBins, itsClustersBins}); |
| 70 | + registry.add("K0s/Signal", "", HistType::kTHnSparseF, {ptBins, etaBins, phiBins, invariantMassBins, tpcClusterBins, itsClustersBins}); |
| 71 | + } |
| 72 | + |
| 73 | + if (doprocessMc) { |
| 74 | + registry.add("K/GeneratedPositive", "", HistType::kTHnSparseF, {ptBins, etaBins, phiBins}); |
| 75 | + registry.add("K/GeneratedNegative", "", HistType::kTHnSparseF, {ptBins, etaBins, phiBins}); |
| 76 | + registry.add("K0s/Generated", "", HistType::kTHnSparseF, {ptBins, etaBins, phiBins}); |
| 77 | + } |
47 | 78 | } |
48 | 79 |
|
49 | | - void processData(aod::Collisions const& collisions, |
50 | | - aod::Tracks const& tracks, |
51 | | - aod::V0s const& v0s) |
| 80 | + using TrackType = soa::Join<aod::Tracks, aod::TracksExtra, aod::pidTPCFullKa, aod::pidTOFFullPi>; |
| 81 | + using CollisionType = soa::Join<aod::Collisions, aod::EvSels>; |
| 82 | + |
| 83 | + void processData(CollisionType const& collisions, |
| 84 | + TrackType const& tracks, |
| 85 | + aod::V0Datas const& v0s) |
52 | 86 | { |
53 | | - for (auto& collision : collisions) { |
54 | | - if (!collision.sel8() || std::abs(collision.posZ()) > 10) |
| 87 | + for (const auto& collision : collisions) { |
| 88 | + if (isCollisionSelected(collision)) |
55 | 89 | continue; // MB selection |
56 | | - if (collision.isMC()) |
57 | | - continue; |
58 | 90 |
|
59 | 91 | // Kaon loop |
60 | | - for (auto& track : tracks) { |
| 92 | + for (const auto& track : tracks) { |
61 | 93 | if (track.collisionId() != collision.globalIndex()) |
62 | 94 | continue; |
63 | | - if (std::abs(track.eta()) > cutEta) |
64 | | - continue; |
65 | | - if (track.tpcNClsFound() < cutTPCClusters) |
66 | | - continue; |
67 | | - // PID selection for kaons |
68 | | - if (std::abs(track.tpcNSigmaKa()) < cutKaonNSigma) { |
69 | | - registry.fill(HIST("hKaonYieldData"), track.pt()); |
70 | | - registry.fill(HIST("hKaonYieldMapData"), track.pt(), track.eta(), track.phi()); |
71 | | - } |
| 95 | + registry.fill(HIST("hTPCClusters"), track.tpcNClsFound()); |
| 96 | + registry.fill(HIST("hITSClusters"), track.itsNCls()); |
| 97 | + if (track.sign() > 0) |
| 98 | + registry.fill(HIST("K/SignalPositive"), track.pt(), track.eta(), track.phi(), track.tpcNSigmaKa(), track.tpcNClsFound(), track.itsNCls()); |
| 99 | + else |
| 100 | + registry.fill(HIST("K/SignalNegative"), track.pt(), track.eta(), track.phi(), track.tpcNSigmaKa(), track.tpcNClsFound(), track.itsNCls()); |
72 | 101 | } |
73 | 102 |
|
74 | 103 | // K0s loop |
75 | | - for (auto& v0 : v0s) { |
| 104 | + for (const auto& v0 : v0s) { |
76 | 105 | if (v0.collisionId() != collision.globalIndex()) |
77 | 106 | continue; |
78 | | - // Basic selection for K0s |
79 | | - if (std::abs(v0.eta()) > cutEta) |
80 | | - continue; |
81 | | - if (std::abs(v0.mass() - constants::physics::MassK0Short) > cutK0sMassWindow) |
82 | | - continue; |
83 | | - registry.fill(HIST("hK0sYieldData"), v0.pt()); |
84 | | - registry.fill(HIST("hK0sYieldMapData"), v0.pt(), v0.eta(), v0.phi()); |
| 107 | + const auto& posTrack = v0.posTrack_as<TrackType>(); |
| 108 | + const auto& negTrack = v0.negTrack_as<TrackType>(); |
| 109 | + registry.fill(HIST("K0s/Signal"), v0.pt(), v0.eta(), v0.phi(), v0.mK0Short() - constants::physics::MassK0Short, std::min(posTrack.tpcNClsFound(), negTrack.tpcNClsFound()), std::min(posTrack.itsNCls(), negTrack.itsNCls())); |
85 | 110 | } |
86 | 111 | } |
87 | 112 | } |
| 113 | + PROCESS_SWITCH(systematicsMapping, processData, "Systematics study for K0s and charged Kaons", true); |
88 | 114 |
|
89 | | - void processMC(aod::Collisions const& collisions, |
90 | | - aod::Tracks const& tracks, |
91 | | - aod::V0s const& v0s) |
| 115 | + void processMc(soa::Join<CollisionType, aod::McCollisionLabels> const& collisions, |
| 116 | + aod::McParticles const& particles, |
| 117 | + aod::McCollisions const&) |
92 | 118 | { |
93 | | - for (auto& collision : collisions) { |
94 | | - if (!collision.sel8() || std::abs(collision.posZ()) > 10) |
| 119 | + for (const auto& collision : collisions) { |
| 120 | + if (!isCollisionSelected(collision)) |
95 | 121 | continue; // MB selection |
96 | | - if (!collision.isMC()) |
| 122 | + if (!collision.has_mcCollision()) |
97 | 123 | continue; |
| 124 | + const auto& mcCollision = collision.mcCollision(); |
98 | 125 |
|
99 | | - // Kaon loop |
100 | | - for (auto& track : tracks) { |
101 | | - if (track.collisionId() != collision.globalIndex()) |
102 | | - continue; |
103 | | - if (std::abs(track.eta()) > cutEta) |
| 126 | + for (const auto& particle : particles) { |
| 127 | + if (particle.mcCollisionId() != mcCollision.globalIndex()) |
104 | 128 | continue; |
105 | | - if (track.tpcNClsFound() < cutTPCClusters) |
| 129 | + if (!particle.isPhysicalPrimary()) |
106 | 130 | continue; |
107 | | - // PID selection for kaons |
108 | | - if (std::abs(track.tpcNSigmaKa()) < cutKaonNSigma) { |
109 | | - registry.fill(HIST("hKaonYieldMC"), track.pt()); |
110 | | - registry.fill(HIST("hKaonYieldMapMC"), track.pt(), track.eta(), track.phi()); |
| 131 | + switch (particle.pdgCode()) { |
| 132 | + case 321: // K+ |
| 133 | + registry.fill(HIST("K/GeneratedPositive"), particle.pt(), particle.eta(), particle.phi()); |
| 134 | + break; |
| 135 | + case -321: // K- |
| 136 | + registry.fill(HIST("K/GeneratedNegative"), particle.pt(), particle.eta(), particle.phi()); |
| 137 | + break; |
| 138 | + case 310: // K0s |
| 139 | + registry.fill(HIST("K0s/Generated"), particle.pt(), particle.eta(), particle.phi()); |
| 140 | + break; |
| 141 | + default: |
| 142 | + break; |
111 | 143 | } |
112 | 144 | } |
113 | | - |
114 | | - // K0s loop |
115 | | - for (auto& v0 : v0s) { |
116 | | - if (v0.collisionId() != collision.globalIndex()) |
117 | | - continue; |
118 | | - // Basic selection for K0s |
119 | | - if (std::abs(v0.eta()) > cutEta) |
120 | | - continue; |
121 | | - if (std::abs(v0.mass() - constants::physics::MassK0Short) > cutK0sMassWindow) |
122 | | - continue; |
123 | | - registry.fill(HIST("hK0sYieldMC"), v0.pt()); |
124 | | - registry.fill(HIST("hK0sYieldMapMC"), v0.pt(), v0.eta(), v0.phi()); |
125 | | - } |
126 | 145 | } |
127 | 146 | } |
128 | | - |
129 | | - void process(aod::Collisions const& collisions, |
130 | | - aod::Tracks const& tracks, |
131 | | - aod::V0s const& v0s) |
132 | | - { |
133 | | - processData(collisions, tracks, v0s); |
134 | | - processMC(collisions, tracks, v0s); |
135 | | - } |
| 147 | + PROCESS_SWITCH(systematicsMapping, processMc, "Systematics study for K0s and charged Kaons on MC", false); |
136 | 148 | }; |
137 | 149 |
|
138 | | -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) |
139 | | -{ |
140 | | - return WorkflowSpec{ |
141 | | - adaptAnalysisTask<systematicsStudy>(cfgc)}; |
142 | | -} |
| 150 | +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask<systematicsMapping>(cfgc)}; } |
0 commit comments