|
| 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 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 | + |
| 17 | +#include "PWGLF/DataModel/LFStrangenessTables.h" |
| 18 | + |
| 19 | +#include "Common/DataModel/EventSelection.h" |
| 20 | +#include "Common/DataModel/PIDResponseTOF.h" |
| 21 | +#include "Common/DataModel/PIDResponseTPC.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> |
| 28 | + |
| 29 | +#include <algorithm> |
| 30 | + |
| 31 | +using namespace o2; |
| 32 | +using namespace o2::framework; |
| 33 | + |
| 34 | +struct SystematicsMapping { |
| 35 | + // Returns a unique index for the combination of cuts |
| 36 | + ConfigurableAxis ptBins{"ptBins", {100, 0.f, 10.f}, "Binning for pT (GeV/c)"}; |
| 37 | + ConfigurableAxis etaBins{"etaBins", {40, -1.0f, 1.0f}, "Binning for #eta"}; |
| 38 | + ConfigurableAxis phiBins{"phiBins", {36, 0.f, o2::constants::math::TwoPI}, "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 | + // Selection configurables |
| 46 | + Configurable<float> selectionPosZ{"selectionPosZ", 10.f, "Max |z| of the primary vertex"}; |
| 47 | + |
| 48 | + HistogramRegistry registry{"registry"}; |
| 49 | + |
| 50 | + template <typename T> |
| 51 | + bool isCollisionSelected(T const& collision) |
| 52 | + { |
| 53 | + return collision.sel8() && std::abs(collision.posZ()) <= selectionPosZ; |
| 54 | + } |
| 55 | + |
| 56 | + void init(InitContext const&) |
| 57 | + { |
| 58 | + const AxisSpec ptAxis{ptBins, "#it{p}_{T} (GeV/c)"}; |
| 59 | + const AxisSpec etaAxis{etaBins, "#eta"}; |
| 60 | + const AxisSpec phiAxis{phiBins, "#phi (rad)"}; |
| 61 | + |
| 62 | + if (doprocessData) { |
| 63 | + |
| 64 | + // First we define the histograms on which we are cutting (tpc clusters, its clusters, ..) |
| 65 | + registry.add("K/hTPCClusters", "", HistType::kTH1F, {{100, 0, 200}}); |
| 66 | + registry.add("K/hITSClusters", "", HistType::kTH1F, {{10, 0, 10}}); |
| 67 | + registry.addClone("K/", "K0s/"); |
| 68 | + |
| 69 | + // Add the signal histograms |
| 70 | + registry.add("K/SignalPositive", "", HistType::kTHnSparseF, {ptBins, etaBins, phiBins, nsigmaBins, tpcClusterBins, itsClustersBins}); |
| 71 | + registry.add("K/SignalNegative", "", HistType::kTHnSparseF, {ptBins, etaBins, phiBins, nsigmaBins, tpcClusterBins, itsClustersBins}); |
| 72 | + registry.add("K0s/Signal", "", HistType::kTHnSparseF, {ptBins, etaBins, phiBins, invariantMassBins, tpcClusterBins, itsClustersBins}); |
| 73 | + } |
| 74 | + |
| 75 | + if (doprocessMc) { |
| 76 | + registry.add("K/GeneratedPositive", "", HistType::kTHnSparseF, {ptBins, etaBins, phiBins}); |
| 77 | + registry.add("K/GeneratedNegative", "", HistType::kTHnSparseF, {ptBins, etaBins, phiBins}); |
| 78 | + registry.add("K0s/Generated", "", HistType::kTHnSparseF, {ptBins, etaBins, phiBins}); |
| 79 | + } |
| 80 | + } |
| 81 | + |
| 82 | + using TrackType = soa::Join<aod::Tracks, aod::TracksExtra, aod::pidTPCFullKa, aod::pidTOFFullPi>; |
| 83 | + using CollisionType = soa::Join<aod::Collisions, aod::EvSels>; |
| 84 | + |
| 85 | + void processData(CollisionType const& collisions, |
| 86 | + TrackType const& tracks, |
| 87 | + aod::V0Datas const& v0s) |
| 88 | + { |
| 89 | + for (const auto& collision : collisions) { |
| 90 | + if (isCollisionSelected(collision)) |
| 91 | + continue; // MB selection |
| 92 | + |
| 93 | + // Kaon loop |
| 94 | + for (const auto& track : tracks) { |
| 95 | + if (track.collisionId() != collision.globalIndex()) |
| 96 | + continue; |
| 97 | + registry.fill(HIST("hTPCClusters"), track.tpcNClsFound()); |
| 98 | + registry.fill(HIST("hITSClusters"), track.itsNCls()); |
| 99 | + if (track.sign() > 0) |
| 100 | + registry.fill(HIST("K/SignalPositive"), track.pt(), track.eta(), track.phi(), track.tpcNSigmaKa(), track.tpcNClsFound(), track.itsNCls()); |
| 101 | + else |
| 102 | + registry.fill(HIST("K/SignalNegative"), track.pt(), track.eta(), track.phi(), track.tpcNSigmaKa(), track.tpcNClsFound(), track.itsNCls()); |
| 103 | + } |
| 104 | + |
| 105 | + // K0s loop |
| 106 | + for (const auto& v0 : v0s) { |
| 107 | + if (v0.collisionId() != collision.globalIndex()) |
| 108 | + continue; |
| 109 | + const auto& posTrack = v0.posTrack_as<TrackType>(); |
| 110 | + const auto& negTrack = v0.negTrack_as<TrackType>(); |
| 111 | + 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())); |
| 112 | + } |
| 113 | + } |
| 114 | + } |
| 115 | + PROCESS_SWITCH(SystematicsMapping, processData, "Systematics study for K0s and charged Kaons", true); |
| 116 | + |
| 117 | + void processMc(soa::Join<CollisionType, aod::McCollisionLabels> const& collisions, |
| 118 | + aod::McParticles const& particles, |
| 119 | + aod::McCollisions const&) |
| 120 | + { |
| 121 | + for (const auto& collision : collisions) { |
| 122 | + if (!isCollisionSelected(collision)) |
| 123 | + continue; // MB selection |
| 124 | + if (!collision.has_mcCollision()) |
| 125 | + continue; |
| 126 | + const auto& mcCollision = collision.mcCollision(); |
| 127 | + |
| 128 | + for (const auto& particle : particles) { |
| 129 | + if (particle.mcCollisionId() != mcCollision.globalIndex()) |
| 130 | + continue; |
| 131 | + if (!particle.isPhysicalPrimary()) |
| 132 | + continue; |
| 133 | + switch (particle.pdgCode()) { |
| 134 | + case 321: // K+ |
| 135 | + registry.fill(HIST("K/GeneratedPositive"), particle.pt(), particle.eta(), particle.phi()); |
| 136 | + break; |
| 137 | + case -321: // K- |
| 138 | + registry.fill(HIST("K/GeneratedNegative"), particle.pt(), particle.eta(), particle.phi()); |
| 139 | + break; |
| 140 | + case 310: // K0s |
| 141 | + registry.fill(HIST("K0s/Generated"), particle.pt(), particle.eta(), particle.phi()); |
| 142 | + break; |
| 143 | + default: |
| 144 | + break; |
| 145 | + } |
| 146 | + } |
| 147 | + } |
| 148 | + } |
| 149 | + PROCESS_SWITCH(SystematicsMapping, processMc, "Systematics study for K0s and charged Kaons on MC", false); |
| 150 | +}; |
| 151 | + |
| 152 | +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask<SystematicsMapping>(cfgc)}; } |
0 commit comments