|
| 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 studyPnch.cxx |
| 13 | +/// |
| 14 | +/// \brief task for analysis of charged-particle multiplicity distributions |
| 15 | +/// \author Abhi Modak (abhi.modak@cern.ch) |
| 16 | +/// \since September 10, 2025 |
| 17 | + |
| 18 | +#include "PWGLF/DataModel/LFStrangenessTables.h" |
| 19 | +#include "PWGMM/Mult/DataModel/Index.h" |
| 20 | +#include "PWGMM/Mult/DataModel/bestCollisionTable.h" |
| 21 | + |
| 22 | +#include "Common/CCDB/EventSelectionParams.h" |
| 23 | +#include "Common/Core/TrackSelection.h" |
| 24 | +#include "Common/Core/trackUtilities.h" |
| 25 | +#include "Common/DataModel/Centrality.h" |
| 26 | +#include "Common/DataModel/EventSelection.h" |
| 27 | +#include "Common/DataModel/Multiplicity.h" |
| 28 | +#include "Common/DataModel/PIDResponse.h" |
| 29 | +#include "Common/DataModel/TrackSelectionTables.h" |
| 30 | + |
| 31 | +#include "CCDB/BasicCCDBManager.h" |
| 32 | +#include "CommonConstants/MathConstants.h" |
| 33 | +#include "Framework/ASoAHelpers.h" |
| 34 | +#include "Framework/AnalysisDataModel.h" |
| 35 | +#include "Framework/AnalysisTask.h" |
| 36 | +#include "Framework/Configurable.h" |
| 37 | +#include "Framework/O2DatabasePDGPlugin.h" |
| 38 | +#include "Framework/runDataProcessing.h" |
| 39 | +#include "ReconstructionDataFormats/GlobalTrackID.h" |
| 40 | +#include "ReconstructionDataFormats/Track.h" |
| 41 | + |
| 42 | +#include <TPDGCode.h> |
| 43 | + |
| 44 | +#include <cmath> |
| 45 | +#include <cstdlib> |
| 46 | +#include <vector> |
| 47 | + |
| 48 | +using namespace o2; |
| 49 | +using namespace o2::framework; |
| 50 | +using namespace o2::framework::expressions; |
| 51 | +using namespace o2::aod::track; |
| 52 | +using namespace o2::aod::evsel; |
| 53 | + |
| 54 | +using ColDataTable = soa::Join<aod::Collisions, aod::EvSels, aod::Mults, aod::PVMults>; |
| 55 | +using TrackDataTable = soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA, aod::TrackSelection>; |
| 56 | +using FilTrackDataTable = soa::Filtered<TrackDataTable>; |
| 57 | +using ColMCTrueTable = aod::McCollisions; |
| 58 | +using TrackMCTrueTable = aod::McParticles; |
| 59 | +using ColMCRecTable = soa::SmallGroups<soa::Join<aod::McCollisionLabels, aod::Collisions, aod::EvSels, aod::Mults, aod::PVMults>>; |
| 60 | +using TrackMCRecTable = soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA, aod::McTrackLabels, aod::TrackSelection>; |
| 61 | +using FilTrackMCRecTable = soa::Filtered<TrackMCRecTable>; |
| 62 | + |
| 63 | +static constexpr TrackSelectionFlags::flagtype TrackSelectionIts = |
| 64 | + TrackSelectionFlags::kITSNCls | TrackSelectionFlags::kITSChi2NDF | |
| 65 | + TrackSelectionFlags::kITSHits; |
| 66 | +static constexpr TrackSelectionFlags::flagtype TrackSelectionTpc = |
| 67 | + TrackSelectionFlags::kTPCNCls | |
| 68 | + TrackSelectionFlags::kTPCCrossedRowsOverNCls | |
| 69 | + TrackSelectionFlags::kTPCChi2NDF; |
| 70 | +static constexpr TrackSelectionFlags::flagtype TrackSelectionDca = |
| 71 | + TrackSelectionFlags::kDCAz | TrackSelectionFlags::kDCAxy; |
| 72 | +static constexpr TrackSelectionFlags::flagtype TrackSelectionDcaxyOnly = |
| 73 | + TrackSelectionFlags::kDCAxy; |
| 74 | + |
| 75 | +AxisSpec axisEvent{10, 0.5, 10.5, "#Event", "EventAxis"}; |
| 76 | +AxisSpec axisVtxZ{40, -20, 20, "Vertex Z", "VzAxis"}; |
| 77 | +AxisSpec axisEta{40, -2, 2, "#eta", "EtaAxis"}; |
| 78 | +AxisSpec axisPhi{629, 0, o2::constants::math::TwoPI, "#phi"}; |
| 79 | +auto static constexpr kMinCharge = 3.f; |
| 80 | + |
| 81 | +struct StudyPnch { |
| 82 | + |
| 83 | + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; |
| 84 | + Service<o2::framework::O2DatabasePDG> pdg; |
| 85 | + Preslice<TrackMCRecTable> perCollision = aod::track::collisionId; |
| 86 | + |
| 87 | + Configurable<float> etaRange{"etaRange", 1.0f, "Eta range to consider"}; |
| 88 | + Configurable<float> vtxRange{"vtxRange", 10.0f, "Vertex Z range to consider"}; |
| 89 | + Configurable<float> dcaZ{"dcaZ", 0.2f, "Custom DCA Z cut (ignored if negative)"}; |
| 90 | + Configurable<float> extraphicut1{"extraphicut1", 3.07666f, "Extra Phi cut 1"}; |
| 91 | + Configurable<float> extraphicut2{"extraphicut2", 3.12661f, "Extra Phi cut 2"}; |
| 92 | + Configurable<float> extraphicut3{"extraphicut3", 0.03f, "Extra Phi cut 3"}; |
| 93 | + Configurable<float> extraphicut4{"extraphicut4", 6.253f, "Extra Phi cut 4"}; |
| 94 | + ConfigurableAxis multHistBin{"multHistBin", {501, -0.5, 500.5}, ""}; |
| 95 | + ConfigurableAxis pvHistBin{"pvHistBin", {501, -0.5, 500.5}, ""}; |
| 96 | + ConfigurableAxis fv0aMultHistBin{"fv0aMultHistBin", {501, -0.5, 500.5}, ""}; |
| 97 | + ConfigurableAxis ft0aMultHistBin{"ft0aMultHistBin", {501, -0.5, 500.5}, ""}; |
| 98 | + ConfigurableAxis ft0cMultHistBin{"ft0cMultHistBin", {501, -0.5, 500.5}, ""}; |
| 99 | + ConfigurableAxis ptHistBin{"ptHistBin", {200, 0., 20.}, ""}; |
| 100 | + |
| 101 | + Configurable<bool> isApplyTFcut{"isApplyTFcut", true, "Enable TimeFrameBorder cut"}; |
| 102 | + Configurable<bool> isApplyITSROcut{"isApplyITSROcut", true, "Enable ITS ReadOutFrameBorder cut"}; |
| 103 | + Configurable<bool> isApplySameBunchPileup{"isApplySameBunchPileup", true, "Enable SameBunchPileup cut"}; |
| 104 | + Configurable<bool> isApplyInelgt0{"isApplyInelgt0", false, "Enable INEL > 0 condition"}; |
| 105 | + Configurable<bool> isApplyExtraPhiCut{"isApplyExtraPhiCut", false, "Enable extra phi cut"}; |
| 106 | + |
| 107 | + void init(InitContext const&) |
| 108 | + { |
| 109 | + AxisSpec axisMult = {multHistBin, "Mult", "MultAxis"}; |
| 110 | + AxisSpec axisPV = {pvHistBin, "PV", "PVAxis"}; |
| 111 | + AxisSpec axisFv0aMult = {fv0aMultHistBin, "fv0a", "FV0AMultAxis"}; |
| 112 | + AxisSpec axisFt0aMult = {ft0aMultHistBin, "ft0a", "FT0AMultAxis"}; |
| 113 | + AxisSpec axisFt0cMult = {ft0cMultHistBin, "ft0c", "FT0CMultAxis"}; |
| 114 | + AxisSpec axisPt = {ptHistBin, "pT", "pTAxis"}; |
| 115 | + |
| 116 | + histos.add("EventHist", "EventHist", kTH1D, {axisEvent}, false); |
| 117 | + histos.add("VtxZHist", "VtxZHist", kTH1D, {axisVtxZ}, false); |
| 118 | + |
| 119 | + auto hstat = histos.get<TH1>(HIST("EventHist")); |
| 120 | + auto* x = hstat->GetXaxis(); |
| 121 | + x->SetBinLabel(1, "All events"); |
| 122 | + x->SetBinLabel(2, "kIsTriggerTVX"); |
| 123 | + x->SetBinLabel(3, "kNoTimeFrameBorder"); |
| 124 | + x->SetBinLabel(4, "kNoITSROFrameBorder"); |
| 125 | + x->SetBinLabel(5, "kNoSameBunchPileup"); // reject collisions in case of pileup with another collision in the same foundBC |
| 126 | + x->SetBinLabel(6, "INEL > 0"); |
| 127 | + x->SetBinLabel(7, "|vz| < 10"); |
| 128 | + |
| 129 | + if (doprocessData || doprocessCorrelation || doprocessMonteCarlo) { |
| 130 | + histos.add("PhiVsEtaHist", "PhiVsEtaHist", kTH2F, {axisPhi, axisEta}, false); |
| 131 | + } |
| 132 | + if (doprocessData) { |
| 133 | + histos.add("hMultiplicityData", "hMultiplicityData", kTH1F, {axisMult}, true); |
| 134 | + } |
| 135 | + if (doprocessCorrelation) { |
| 136 | + histos.add("GlobalMult_vs_FT0A", "GlobalMult_vs_FT0A", kTH2F, {axisMult, axisFt0aMult}, true); |
| 137 | + histos.add("GlobalMult_vs_FT0C", "GlobalMult_vs_FT0C", kTH2F, {axisMult, axisFt0cMult}, true); |
| 138 | + histos.add("GlobalMult_vs_FV0A", "GlobalMult_vs_FV0A", kTH2F, {axisMult, axisFv0aMult}, true); |
| 139 | + histos.add("NPVtracks_vs_FT0C", "NPVtracks_vs_FT0C", kTH2F, {axisPV, axisFt0cMult}, true); |
| 140 | + histos.add("NPVtracks_vs_GlobalMult", "NPVtracks_vs_GlobalMult", kTH2F, {axisPV, axisMult}, true); |
| 141 | + } |
| 142 | + if (doprocessMonteCarlo) { |
| 143 | + histos.add("hMultiplicityMCrec", "hMultiplicityMCrec", kTH1F, {axisMult}, true); |
| 144 | + histos.add("hMultiplicityMCgen", "hMultiplicityMCgen", kTH1F, {axisMult}, true); |
| 145 | + histos.add("hResponseMatrix", "hResponseMatrix", kTH2F, {axisMult, axisMult}, true); |
| 146 | + } |
| 147 | + if (doprocessEvtLossSigLossMC) { |
| 148 | + histos.add("MCEventHist", "MCEventHist", kTH1F, {axisEvent}, false); |
| 149 | + auto hstat = histos.get<TH1>(HIST("MCEventHist")); |
| 150 | + auto* x = hstat->GetXaxis(); |
| 151 | + x->SetBinLabel(1, "All MC events"); |
| 152 | + x->SetBinLabel(2, "MC events with atleast one reco event"); |
| 153 | + histos.add("hMultiplicityMCgenAll", "hMultiplicityMCgenAll", kTH1F, {axisMult}, true); |
| 154 | + histos.add("hMultiplicityMCgenSel", "hMultiplicityMCgenSel", kTH1F, {axisMult}, true); |
| 155 | + } |
| 156 | + } |
| 157 | + |
| 158 | + template <typename CheckCol> |
| 159 | + bool isEventSelected(CheckCol const& col) |
| 160 | + { |
| 161 | + histos.fill(HIST("EventHist"), 1); |
| 162 | + if (!col.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { |
| 163 | + return false; |
| 164 | + } |
| 165 | + histos.fill(HIST("EventHist"), 2); |
| 166 | + if (isApplyTFcut && !col.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { |
| 167 | + return false; |
| 168 | + } |
| 169 | + histos.fill(HIST("EventHist"), 3); |
| 170 | + if (isApplyITSROcut && !col.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { |
| 171 | + return false; |
| 172 | + } |
| 173 | + histos.fill(HIST("EventHist"), 4); |
| 174 | + if (isApplySameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { |
| 175 | + return false; |
| 176 | + } |
| 177 | + histos.fill(HIST("EventHist"), 5); |
| 178 | + if (isApplyInelgt0 && !col.isInelGt0()) { |
| 179 | + return false; |
| 180 | + } |
| 181 | + histos.fill(HIST("EventHist"), 6); |
| 182 | + if (std::abs(col.posZ()) >= vtxRange) { |
| 183 | + return false; |
| 184 | + } |
| 185 | + histos.fill(HIST("EventHist"), 7); |
| 186 | + histos.fill(HIST("VtxZHist"), col.posZ()); |
| 187 | + return true; |
| 188 | + } |
| 189 | + |
| 190 | + template <typename CheckTrack> |
| 191 | + bool isTrackSelected(CheckTrack const& track) |
| 192 | + { |
| 193 | + if (std::abs(track.eta()) >= etaRange) { |
| 194 | + return false; |
| 195 | + } |
| 196 | + if (isApplyExtraPhiCut && ((track.phi() > extraphicut1 && track.phi() < extraphicut2) || track.phi() <= extraphicut3 || track.phi() >= extraphicut4)) { |
| 197 | + return false; |
| 198 | + } |
| 199 | + return true; |
| 200 | + } |
| 201 | + |
| 202 | + template <typename CheckGenTrack> |
| 203 | + bool isGenTrackSelected(CheckGenTrack const& track) |
| 204 | + { |
| 205 | + if (!track.isPhysicalPrimary()) { |
| 206 | + return false; |
| 207 | + } |
| 208 | + if (!track.producedByGenerator()) { |
| 209 | + return false; |
| 210 | + } |
| 211 | + auto pdgTrack = pdg->GetParticle(track.pdgCode()); |
| 212 | + if (pdgTrack == nullptr) { |
| 213 | + return false; |
| 214 | + } |
| 215 | + if (std::abs(pdgTrack->Charge()) < kMinCharge) { |
| 216 | + return false; |
| 217 | + } |
| 218 | + if (std::abs(track.eta()) >= etaRange) { |
| 219 | + return false; |
| 220 | + } |
| 221 | + if (isApplyExtraPhiCut && ((track.phi() > extraphicut1 && track.phi() < extraphicut2) || track.phi() <= extraphicut3 || track.phi() >= extraphicut4)) { |
| 222 | + return false; |
| 223 | + } |
| 224 | + return true; |
| 225 | + } |
| 226 | + |
| 227 | + template <typename countTrk> |
| 228 | + int countNTracks(countTrk const& tracks) |
| 229 | + { |
| 230 | + auto nTrk = 0; |
| 231 | + for (const auto& track : tracks) { |
| 232 | + if (!isTrackSelected(track)) { |
| 233 | + continue; |
| 234 | + } |
| 235 | + histos.fill(HIST("PhiVsEtaHist"), track.phi(), track.eta()); |
| 236 | + nTrk++; |
| 237 | + } |
| 238 | + return nTrk; |
| 239 | + } |
| 240 | + |
| 241 | + template <typename countTrk> |
| 242 | + int countGenTracks(countTrk const& tracks) |
| 243 | + { |
| 244 | + auto nTrk = 0; |
| 245 | + for (const auto& track : tracks) { |
| 246 | + if (!isGenTrackSelected(track)) { |
| 247 | + continue; |
| 248 | + } |
| 249 | + histos.fill(HIST("PhiVsEtaHist"), track.phi(), track.eta()); |
| 250 | + nTrk++; |
| 251 | + } |
| 252 | + return nTrk; |
| 253 | + } |
| 254 | + |
| 255 | + Filter fTrackSelectionITS = ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) && |
| 256 | + ncheckbit(aod::track::trackCutFlag, TrackSelectionIts); |
| 257 | + Filter fTrackSelectionTPC = ifnode(ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC), |
| 258 | + ncheckbit(aod::track::trackCutFlag, TrackSelectionTpc), true); |
| 259 | + Filter fTrackSelectionDCA = ifnode(dcaZ.node() > 0.f, nabs(aod::track::dcaZ) <= dcaZ && ncheckbit(aod::track::trackCutFlag, TrackSelectionDcaxyOnly), |
| 260 | + ncheckbit(aod::track::trackCutFlag, TrackSelectionDca)); |
| 261 | + |
| 262 | + void processData(ColDataTable::iterator const& cols, FilTrackDataTable const& tracks) |
| 263 | + { |
| 264 | + if (!isEventSelected(cols)) { |
| 265 | + return; |
| 266 | + } |
| 267 | + auto mult = countNTracks(tracks); |
| 268 | + histos.fill(HIST("hMultiplicityData"), mult); |
| 269 | + } |
| 270 | + |
| 271 | + void processCorrelation(ColDataTable::iterator const& cols, FilTrackDataTable const& tracks) |
| 272 | + { |
| 273 | + if (!isEventSelected(cols)) { |
| 274 | + return; |
| 275 | + } |
| 276 | + auto mult = countNTracks(tracks); |
| 277 | + histos.fill(HIST("GlobalMult_vs_FT0A"), mult, cols.multFT0A()); |
| 278 | + histos.fill(HIST("GlobalMult_vs_FT0C"), mult, cols.multFT0C()); |
| 279 | + histos.fill(HIST("GlobalMult_vs_FV0A"), mult, cols.multFV0A()); |
| 280 | + histos.fill(HIST("NPVtracks_vs_FT0C"), cols.multNTracksPV(), cols.multFT0C()); |
| 281 | + histos.fill(HIST("NPVtracks_vs_GlobalMult"), cols.multNTracksPV(), mult); |
| 282 | + } |
| 283 | + |
| 284 | + void processMonteCarlo(ColMCTrueTable::iterator const&, ColMCRecTable const& RecCols, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks) |
| 285 | + { |
| 286 | + for (const auto& RecCol : RecCols) { |
| 287 | + if (!isEventSelected(RecCol)) { |
| 288 | + continue; |
| 289 | + } |
| 290 | + auto recTracksPart = RecTracks.sliceBy(perCollision, RecCol.globalIndex()); |
| 291 | + auto multrec = countNTracks(recTracksPart); |
| 292 | + histos.fill(HIST("hMultiplicityMCrec"), multrec); |
| 293 | + auto multgen = countGenTracks(GenParticles); |
| 294 | + histos.fill(HIST("hMultiplicityMCgen"), multgen); |
| 295 | + histos.fill(HIST("hResponseMatrix"), multrec, multgen); |
| 296 | + } |
| 297 | + } |
| 298 | + |
| 299 | + void processEvtLossSigLossMC(soa::Join<ColMCTrueTable, aod::MultMCExtras>::iterator const& mcCollision, ColMCRecTable const& RecCols, TrackMCTrueTable const& GenParticles) |
| 300 | + { |
| 301 | + if (isApplyInelgt0 && !mcCollision.isInelGt0()) { |
| 302 | + return; |
| 303 | + } |
| 304 | + if (std::abs(mcCollision.posZ()) >= vtxRange) { |
| 305 | + return; |
| 306 | + } |
| 307 | + // All generated events |
| 308 | + histos.fill(HIST("MCEventHist"), 1); |
| 309 | + auto multAll = countGenTracks(GenParticles); |
| 310 | + histos.fill(HIST("hMultiplicityMCgenAll"), multAll); |
| 311 | + |
| 312 | + bool atLeastOne = false; |
| 313 | + auto numcontributors = -999; |
| 314 | + for (const auto& RecCol : RecCols) { |
| 315 | + if (!isEventSelected(RecCol)) { |
| 316 | + continue; |
| 317 | + } |
| 318 | + if (RecCol.numContrib() <= numcontributors) { |
| 319 | + continue; |
| 320 | + } else { |
| 321 | + numcontributors = RecCol.numContrib(); |
| 322 | + } |
| 323 | + atLeastOne = true; |
| 324 | + } |
| 325 | + |
| 326 | + if (atLeastOne) { |
| 327 | + histos.fill(HIST("MCEventHist"), 2); |
| 328 | + auto multSel = countGenTracks(GenParticles); |
| 329 | + histos.fill(HIST("hMultiplicityMCgenSel"), multSel); |
| 330 | + } |
| 331 | + } |
| 332 | + |
| 333 | + PROCESS_SWITCH(StudyPnch, processData, "process data CentFT0C", false); |
| 334 | + PROCESS_SWITCH(StudyPnch, processCorrelation, "do correlation study in data", false); |
| 335 | + PROCESS_SWITCH(StudyPnch, processMonteCarlo, "process MC CentFT0C", false); |
| 336 | + PROCESS_SWITCH(StudyPnch, processEvtLossSigLossMC, "process Signal Loss, Event Loss", false); |
| 337 | +}; |
| 338 | + |
| 339 | +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) |
| 340 | +{ |
| 341 | + return WorkflowSpec{adaptAnalysisTask<StudyPnch>(cfgc)}; |
| 342 | +} |
0 commit comments