From e983304769e09d540e4c19236a0cb7cbb1d58f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrea=20Tavira=20Garc=C3=ADa?= <118979672+atavirag@users.noreply.github.com> Date: Mon, 21 Sep 2026 15:45:15 +0000 Subject: [PATCH 01/21] First commit --- PWGUD/Tasks/CMakeLists.txt | 5 + PWGUD/Tasks/upcTrackVertexingQA.cxx | 244 ++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+) create mode 100644 PWGUD/Tasks/upcTrackVertexingQA.cxx diff --git a/PWGUD/Tasks/CMakeLists.txt b/PWGUD/Tasks/CMakeLists.txt index bfe050bbe04..6a81401f3b4 100644 --- a/PWGUD/Tasks/CMakeLists.txt +++ b/PWGUD/Tasks/CMakeLists.txt @@ -14,6 +14,11 @@ o2physics_add_dpl_workflow(upc-polarisation-jpsi-incoh PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(upc-track-vertexing-qa + SOURCES upcTrackVertexingQA.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(upc-analysis SOURCES upcAnalysis.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx new file mode 100644 index 00000000000..885a0e4a1ff --- /dev/null +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -0,0 +1,244 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file upcTrackVertexingQA.cxx +/// \brief task to study the performance of vertexing for low-multiplicity UPC collisions +/// + +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#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; + +struct UpcTrackVertexingQA { + // Configurables + Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; + Configurable ptCandMin{"ptCandMin", 0., "min. cand. pT (GeV/c)"}; + Configurable ptTrackMin{"ptTrackMin", 0.1, "min. track pT (GeV/c)"}; + Configurable etaTrackMax{"etaTrackMax", 0.9, "max. |eta| of tracks"}; + Configurable nSigmaTpcMax{"nSigmaTpcMax", 3.f, "max. TPC N_sigma (pion)"}; + Configurable nMinTpcClusters{"nMinTpcClusters", 60, "min. number of TPC clusters"}; + Configurable massMin{"massMin", 0.5, "min. inv. mass (GeV/c^2)"}; + Configurable massMax{"massMax", 1.3, "max. inv. mass (GeV/c^2)"}; + + // Name shortenings + // passed* columns are in TrackSelectionExtension; isGlobalTrack* and trackCutFlag in TrackSelection + using TracksExtraWPidPi = soa::Join; + + static constexpr float MassPion = o2::constants::physics::MassPionCharged; + + // Ordered list of cuts. The cumulative cut flow follows this order, + // so reorder CutLabels and getCutResults together to change what "tighter" means. + static constexpr int NCuts = 8; + static constexpr std::array CutLabels = { + "all tracks", "hasTPC", "passedEtaRange", + "passedTPCNCls", "passedTPCChi2NDF", "passedITSNCls", + "passedITSChi2NDF", "hasITS"}; + + // Axes + ConfigurableAxis axisMass{"axisMass", {160, 0.4, 1.2}, "m_{#pi#pi} (GeV/#it{c}^{2})"}; + ConfigurableAxis axisPt{"axisPt", {200, 0., 2.}, "#it{p}_{T} (GeV/#it{c})"}; + + HistogramRegistry registry{ + "registry", + {// candidate level + {"Cand/hMass", ";m_{#pi#pi} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}}, + {"Cand/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}}, + {"Cand/hRapidity", ";#it{y};entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + + // collision level + {"Coll/hNContrib", ";N_{PV contributors};entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}}, + + // track level (prongs of the candidate) + {"Trk/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}}, + {"Trk/hEta", ";#eta;entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"Trk/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, + {"Trk/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}}, + {"Trk/hNSigmaPiVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}_{#pi}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, + {"Trk/hHasIts", ";has ITS;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, + {"Trk/hIsPvContrib", ";is PV contributor;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, + {"Trk/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{160, 0., 160.}}}}, + {"Trk/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 40.}}}}, + {"Trk/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, + {"Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{200, -2., 2.}}}}, + {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -5., 5.}}}}}}; + + void init(InitContext&) + { + // Cut flows: cumulative, single cut, and tracks per collision vs. cut step + registry.add("Cut/hCutFlowCumulative", "tracks surviving cuts applied in sequence;;entries", + HistType::kTH1F, {{NCuts, -0.5, NCuts - 0.5}}); + registry.add("Cut/hCutFlowSingle", "tracks passing each cut individually;;entries", + HistType::kTH1F, {{NCuts, -0.5, NCuts - 0.5}}); + registry.add("Cut/h2NTracksPerCollVsCut", "tracks per collision after each cumulative cut;;N_{tracks} / collision", + HistType::kTH2F, {{NCuts, -0.5, NCuts - 0.5}, {10, -0.5, 9.5}}); + + auto hCum = registry.get(HIST("Cut/hCutFlowCumulative")); + auto hSingle = registry.get(HIST("Cut/hCutFlowSingle")); + auto hPerColl = registry.get(HIST("Cut/h2NTracksPerCollVsCut")); + for (int i = 0; i < NCuts; ++i) { + hCum->GetXaxis()->SetBinLabel(i + 1, CutLabels[i]); + hSingle->GetXaxis()->SetBinLabel(i + 1, CutLabels[i]); + hPerColl->GetXaxis()->SetBinLabel(i + 1, CutLabels[i]); + } + } + + // Result of every cut for one track (same order as CutLabels) + template + std::array getCutResults(TTrack const& track) + { + return {true, + track.hasTPC(), + track.passedTPCNCls(), + track.passedEtaRange(), + track.passedTPCChi2NDF(), + track.passedITSNCls(), + track.passedITSChi2NDF(), + track.hasITS()}; + } + + // Fills the cut flows for all tracks of one collision + template + void fillCutFlow(TTracks const& tracks) + { + std::array nSurvivors{}; // tracks of this collision surviving up to step i + + for (auto const& track : tracks) { + auto passed = getCutResults(track); + bool passedSoFar = true; + for (int i = 0; i < NCuts; ++i) { + if (passed[i]) { + registry.fill(HIST("Cut/hCutFlowSingle"), i); + } + passedSoFar = passedSoFar && passed[i]; + if (passedSoFar) { + registry.fill(HIST("Cut/hCutFlowCumulative"), i); + ++nSurvivors[i]; + } + } + } + + for (int i = 0; i < NCuts; ++i) { + registry.fill(HIST("Cut/h2NTracksPerCollVsCut"), i, nSurvivors[i]); + } + } + + // Basic kinematic / TPC properties of a candidate prong + template + void checkTpcTrackProperties(TTrack const& track) + { + registry.fill(HIST("Trk/hPt"), track.pt()); + registry.fill(HIST("Trk/hEta"), track.eta()); + registry.fill(HIST("Trk/hChi2NCl"), track.tpcChi2NCl()); + registry.fill(HIST("Trk/hTpcSignalVsP"), track.p(), track.tpcSignal()); + registry.fill(HIST("Trk/hNSigmaPiVsP"), track.p(), track.tpcNSigmaPi()); + registry.fill(HIST("Trk/hHasIts"), static_cast(track.hasITS())); + registry.fill(HIST("Trk/hIsPvContrib"), static_cast(track.isPVContributor())); + registry.fill(HIST("Trk/hTpcNClsFound"), track.tpcNClsFound()); + registry.fill(HIST("Trk/hItsChi2NCl"), track.itsChi2NCl()); + registry.fill(HIST("Trk/hItsNCls"), track.itsNCls()); + registry.fill(HIST("Trk/hDcaXY"), track.dcaXY()); + registry.fill(HIST("Trk/hDcaZ"), track.dcaZ()); + + // TODO: ambiguity (aod::AmbiguousTracks), ... + } + + // Basic single-track selection used to build the rho candidate + template + bool isGoodTrack(TTrack const& track) + { + if (!track.hasTPC()) { + return false; + } + if (track.tpcNClsFound() < nMinTpcClusters) { + return false; + } + if (track.pt() < ptTrackMin || std::abs(track.eta()) > etaTrackMax) { + return false; + } + return std::abs(track.tpcNSigmaPi()) <= nSigmaTpcMax; + } + + // Tracks are grouped by collision automatically + void processRhoCand(aod::Collision const& collision, TracksExtraWPidPi const& tracks) + { + registry.fill(HIST("Coll/hNContrib"), collision.numContrib()); + + // Sequential ITS/TPC cuts on ALL tracks of the collision + fillCutFlow(tracks); + + // Select tracks for the rho candidate + std::vector goodTracks; + for (auto const& track : tracks) { + if (isGoodTrack(track)) { + goodTracks.push_back(track); + } + } + + // Exactly two tracks with opposite charge -> rho candidate + if (goodTracks.size() != 2) { + return; + } + auto const& track0 = goodTracks[0]; + auto const& track1 = goodTracks[1]; + if (track0.sign() * track1.sign() >= 0) { + return; + } + + ROOT::Math::PxPyPzMVector p0(track0.px(), track0.py(), track0.pz(), MassPion); + ROOT::Math::PxPyPzMVector p1(track1.px(), track1.py(), track1.pz(), MassPion); + auto rho = p0 + p1; + + if (rho.M() < massMin || rho.M() > massMax) { + return; + } + if (rho.Pt() < ptCandMin || std::abs(rho.Rapidity()) > yCandMax) { + return; + } + + registry.fill(HIST("Cand/hMass"), rho.M()); + registry.fill(HIST("Cand/hPt"), rho.Pt()); + registry.fill(HIST("Cand/hRapidity"), rho.Rapidity()); + + checkTpcTrackProperties(track0); + checkTpcTrackProperties(track1); + } + PROCESS_SWITCH(UpcTrackVertexingQA, processRhoCand, "Rho -> pi pi candidates and track QA", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} From 36186ed268fa17d527d49b1719fa5326faac8e9d Mon Sep 17 00:00:00 2001 From: ariffero Date: Tue, 22 Sep 2026 17:25:31 +0200 Subject: [PATCH 02/21] Add authors --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index 885a0e4a1ff..ae158355d71 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -11,6 +11,9 @@ /// \file upcTrackVertexingQA.cxx /// \brief task to study the performance of vertexing for low-multiplicity UPC collisions +/// \author Andrea Tavira Garcia a.tavira@cern.ch +/// \author Andrea Giovanni Riffero andrea.giovanni.riffero@cern.ch + /// #include "Common/DataModel/PIDResponseTPC.h" From 02e438926a14822e7e5b30dc050dfd3c235b058a Mon Sep 17 00:00:00 2001 From: ariffero Date: Tue, 22 Sep 2026 17:29:18 +0200 Subject: [PATCH 03/21] Add N cluster in ITS inner barrel --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index ae158355d71..ad15b5a75ef 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -95,6 +95,7 @@ struct UpcTrackVertexingQA { {"Trk/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{160, 0., 160.}}}}, {"Trk/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 40.}}}}, {"Trk/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, + {"Trk/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, {"Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{200, -2., 2.}}}}, {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -5., 5.}}}}}}; @@ -172,6 +173,7 @@ struct UpcTrackVertexingQA { registry.fill(HIST("Trk/hTpcNClsFound"), track.tpcNClsFound()); registry.fill(HIST("Trk/hItsChi2NCl"), track.itsChi2NCl()); registry.fill(HIST("Trk/hItsNCls"), track.itsNCls()); + registry.fill(HIST("Trk/hItsNClsInnerBarrel"), track.itsNClsInnerBarrel()); registry.fill(HIST("Trk/hDcaXY"), track.dcaXY()); registry.fill(HIST("Trk/hDcaZ"), track.dcaZ()); From 7206a9d87ae38db4da6ea6c9ef5731c529dd2004 Mon Sep 17 00:00:00 2001 From: ariffero Date: Wed, 23 Sep 2026 11:51:26 +0200 Subject: [PATCH 04/21] Add collision info --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index ad15b5a75ef..bc8542d8086 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -83,6 +83,11 @@ struct UpcTrackVertexingQA { // collision level {"Coll/hNContrib", ";N_{PV contributors};entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}}, + {"Coll/hBCid", ";BCid;entries", {HistType::kTH1F, {{1000, 0., 1000.}}}}, + {"Coll/hVtxZ", ";#it{z}_{vtx} (cm);entries", {HistType::kTH1F, {{200, -20., 20.}}}}, + {"Coll/hVtxX", ";#it{x}_{vtx} (cm);entries", {HistType::kTH1F, {{200, -0.05, 0.05}}}}, + {"Coll/hVtxY", ";#it{y}_{vtx} (cm);entries", {HistType::kTH1F, {{200, -0.05, 0.05}}}}, + {"Coll/hVtxChi2", ";#chi^{2} vtx;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, // track level (prongs of the candidate) {"Trk/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}}, @@ -97,7 +102,9 @@ struct UpcTrackVertexingQA { {"Trk/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, {"Trk/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, {"Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{200, -2., 2.}}}}, - {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -5., 5.}}}}}}; + {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -5., 5.}}}}} + }; + void init(InitContext&) { @@ -200,6 +207,11 @@ struct UpcTrackVertexingQA { void processRhoCand(aod::Collision const& collision, TracksExtraWPidPi const& tracks) { registry.fill(HIST("Coll/hNContrib"), collision.numContrib()); + registry.fill(HIST("Coll/hBCid"), collision.bcId()); + registry.fill(HIST("Coll/hVtxZ"), collision.posZ()); + registry.fill(HIST("Coll/hVtxX"), collision.posX()); + registry.fill(HIST("Coll/hVtxY"), collision.posY()); + registry.fill(HIST("Coll/hVtxChi2"), collision.chi2()); // Sequential ITS/TPC cuts on ALL tracks of the collision fillCutFlow(tracks); From 30e9595ad4b4ea2ceae8432092a95566a689919e Mon Sep 17 00:00:00 2001 From: ariffero Date: Wed, 23 Sep 2026 12:18:55 +0200 Subject: [PATCH 05/21] Change trk histo ranges --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index bc8542d8086..a02edc9c2aa 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -101,8 +101,8 @@ struct UpcTrackVertexingQA { {"Trk/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 40.}}}}, {"Trk/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, {"Trk/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, - {"Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{200, -2., 2.}}}}, - {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -5., 5.}}}}} + {"Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{200, -0.1, 0.1}}}}, + {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.5, 0.5}}}}} }; From a8373d2ffe823846c36ab91aafd8a178710da027 Mon Sep 17 00:00:00 2001 From: ariffero Date: Wed, 23 Sep 2026 12:30:25 +0200 Subject: [PATCH 06/21] Fix indentation --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 57 +++++++++++++++-------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index a02edc9c2aa..5649e4ed8ca 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -50,7 +50,7 @@ struct UpcTrackVertexingQA { Configurable ptTrackMin{"ptTrackMin", 0.1, "min. track pT (GeV/c)"}; Configurable etaTrackMax{"etaTrackMax", 0.9, "max. |eta| of tracks"}; Configurable nSigmaTpcMax{"nSigmaTpcMax", 3.f, "max. TPC N_sigma (pion)"}; - Configurable nMinTpcClusters{"nMinTpcClusters", 60, "min. number of TPC clusters"}; + Configurable nMinTpcClusters{"nMinTpcClusters", 60, "min. number of TPC clusters"}; Configurable massMin{"massMin", 0.5, "min. inv. mass (GeV/c^2)"}; Configurable massMax{"massMax", 1.3, "max. inv. mass (GeV/c^2)"}; @@ -77,33 +77,34 @@ struct UpcTrackVertexingQA { HistogramRegistry registry{ "registry", {// candidate level - {"Cand/hMass", ";m_{#pi#pi} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}}, - {"Cand/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}}, - {"Cand/hRapidity", ";#it{y};entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - - // collision level - {"Coll/hNContrib", ";N_{PV contributors};entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}}, - {"Coll/hBCid", ";BCid;entries", {HistType::kTH1F, {{1000, 0., 1000.}}}}, - {"Coll/hVtxZ", ";#it{z}_{vtx} (cm);entries", {HistType::kTH1F, {{200, -20., 20.}}}}, - {"Coll/hVtxX", ";#it{x}_{vtx} (cm);entries", {HistType::kTH1F, {{200, -0.05, 0.05}}}}, - {"Coll/hVtxY", ";#it{y}_{vtx} (cm);entries", {HistType::kTH1F, {{200, -0.05, 0.05}}}}, - {"Coll/hVtxChi2", ";#chi^{2} vtx;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - - // track level (prongs of the candidate) - {"Trk/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}}, - {"Trk/hEta", ";#eta;entries", {HistType::kTH1F, {{100, -1., 1.}}}}, - {"Trk/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - {"Trk/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}}, - {"Trk/hNSigmaPiVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}_{#pi}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, - {"Trk/hHasIts", ";has ITS;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, - {"Trk/hIsPvContrib", ";is PV contributor;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, - {"Trk/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{160, 0., 160.}}}}, - {"Trk/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 40.}}}}, - {"Trk/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, - {"Trk/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, - {"Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{200, -0.1, 0.1}}}}, - {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.5, 0.5}}}}} - }; + {"Cand/hMass", ";m_{#pi#pi} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}}, + {"Cand/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}}, + {"Cand/hRapidity", ";#it{y};entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + + // collision level + {"Coll/hNContrib", ";N_{PV contributors};entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}}, + {"Coll/hBCid", ";BCid;entries", {HistType::kTH1F, {{1000, 0., 1000.}}}}, + {"Coll/hVtxZ", ";#it{z}_{vtx} (cm);entries", {HistType::kTH1F, {{200, -20., 20.}}}}, + {"Coll/hVtxX", ";#it{x}_{vtx} (cm);entries", {HistType::kTH1F, {{200, -0.05, 0.05}}}}, + {"Coll/hVtxY", ";#it{y}_{vtx} (cm);entries", {HistType::kTH1F, {{200, -0.05, 0.05}}}}, + {"Coll/hVtxChi2", ";#chi^{2} vtx;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, + + // track level (prongs of the candidate) + {"Trk/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}}, + {"Trk/hEta", ";#eta;entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"Trk/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, + {"Trk/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}}, + {"Trk/hNSigmaPiVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}_{#pi}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, + {"Trk/hHasIts", ";has ITS;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, + {"Trk/hIsPvContrib", ";is PV contributor;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, + {"Trk/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{160, 0., 160.}}}}, + {"Trk/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 40.}}}}, + {"Trk/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, + {"Trk/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, + {"Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{200, -0.1, 0.1}}}}, + {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.5, 0.5}}}} + } + }; void init(InitContext&) From 550db68efeb4cf19454a66c847ec2de25effd46d Mon Sep 17 00:00:00 2001 From: ariffero Date: Wed, 23 Sep 2026 12:31:14 +0200 Subject: [PATCH 07/21] Add tracks histos after collision match --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 70 +++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index 5649e4ed8ca..b9e5765d1e5 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -102,7 +102,22 @@ struct UpcTrackVertexingQA { {"Trk/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, {"Trk/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, {"Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{200, -0.1, 0.1}}}}, - {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.5, 0.5}}}} + {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.5, 0.5}}}}, + + // track level after collision matching + {"TrkColl/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}}, + {"TrkColl/hEta", ";#eta;entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"TrkColl/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, + {"TrkColl/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}}, + {"TrkColl/hNSigmaPiVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}_{#pi}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, + {"TrkColl/hHasIts", ";has ITS;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, + {"TrkColl/hIsPvContrib", ";is PV contributor;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, + {"TrkColl/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{160, 0., 160.}}}}, + {"TrkColl/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 40.}}}}, + {"TrkColl/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, + {"TrkColl/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, + {"TrkColl/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{200, -0.1, 0.1}}}}, + {"TrkColl/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.5, 0.5}}}} } }; @@ -171,19 +186,19 @@ struct UpcTrackVertexingQA { template void checkTpcTrackProperties(TTrack const& track) { - registry.fill(HIST("Trk/hPt"), track.pt()); - registry.fill(HIST("Trk/hEta"), track.eta()); - registry.fill(HIST("Trk/hChi2NCl"), track.tpcChi2NCl()); - registry.fill(HIST("Trk/hTpcSignalVsP"), track.p(), track.tpcSignal()); - registry.fill(HIST("Trk/hNSigmaPiVsP"), track.p(), track.tpcNSigmaPi()); - registry.fill(HIST("Trk/hHasIts"), static_cast(track.hasITS())); - registry.fill(HIST("Trk/hIsPvContrib"), static_cast(track.isPVContributor())); - registry.fill(HIST("Trk/hTpcNClsFound"), track.tpcNClsFound()); - registry.fill(HIST("Trk/hItsChi2NCl"), track.itsChi2NCl()); - registry.fill(HIST("Trk/hItsNCls"), track.itsNCls()); - registry.fill(HIST("Trk/hItsNClsInnerBarrel"), track.itsNClsInnerBarrel()); - registry.fill(HIST("Trk/hDcaXY"), track.dcaXY()); - registry.fill(HIST("Trk/hDcaZ"), track.dcaZ()); + registry.fill(HIST("TrkColl/hPt"), track.pt()); + registry.fill(HIST("TrkColl/hEta"), track.eta()); + registry.fill(HIST("TrkColl/hChi2NCl"), track.tpcChi2NCl()); + registry.fill(HIST("TrkColl/hTpcSignalVsP"), track.p(), track.tpcSignal()); + registry.fill(HIST("TrkColl/hNSigmaPiVsP"), track.p(), track.tpcNSigmaPi()); + registry.fill(HIST("TrkColl/hHasIts"), static_cast(track.hasITS())); + registry.fill(HIST("TrkColl/hIsPvContrib"), static_cast(track.isPVContributor())); + registry.fill(HIST("TrkColl/hTpcNClsFound"), track.tpcNClsFound()); + registry.fill(HIST("TrkColl/hItsChi2NCl"), track.itsChi2NCl()); + registry.fill(HIST("TrkColl/hItsNCls"), track.itsNCls()); + registry.fill(HIST("TrkColl/hItsNClsInnerBarrel"), track.itsNClsInnerBarrel()); + registry.fill(HIST("TrkColl/hDcaXY"), track.dcaXY()); + registry.fill(HIST("TrkColl/hDcaZ"), track.dcaZ()); // TODO: ambiguity (aod::AmbiguousTracks), ... } @@ -203,6 +218,33 @@ struct UpcTrackVertexingQA { } return std::abs(track.tpcNSigmaPi()) <= nSigmaTpcMax; } + + // loop on tracks before grouping by collision + void processTracks(TracksExtraWPidPi const& tracks) + { + + for (auto const& track : tracks) { + // select good tracks for the rho + //LOGF(info, "Track pT: %f,", track.pt()); + if(!isGoodTrack(track)) + continue; + + registry.fill(HIST("Trk/hPt"), track.pt()); + registry.fill(HIST("Trk/hEta"), track.eta()); + registry.fill(HIST("Trk/hChi2NCl"), track.tpcChi2NCl()); + registry.fill(HIST("Trk/hTpcSignalVsP"), track.p(), track.tpcSignal()); + registry.fill(HIST("Trk/hNSigmaPiVsP"), track.p(), track.tpcNSigmaPi()); + registry.fill(HIST("Trk/hHasIts"), static_cast(track.hasITS())); + registry.fill(HIST("Trk/hIsPvContrib"), static_cast(track.isPVContributor())); + registry.fill(HIST("Trk/hTpcNClsFound"), track.tpcNClsFound()); + registry.fill(HIST("Trk/hItsChi2NCl"), track.itsChi2NCl()); + registry.fill(HIST("Trk/hItsNCls"), track.itsNCls()); + registry.fill(HIST("Trk/hItsNClsInnerBarrel"), track.itsNClsInnerBarrel()); + registry.fill(HIST("Trk/hDcaXY"), track.dcaXY()); + registry.fill(HIST("Trk/hDcaZ"), track.dcaZ()); + } + } + PROCESS_SWITCH(UpcTrackVertexingQA, processTracks, "Process tracks before asking for collisions", true); // Tracks are grouped by collision automatically void processRhoCand(aod::Collision const& collision, TracksExtraWPidPi const& tracks) From ce1def83f9e2c5ff2d1deaa0041c0cd16f0eba3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrea=20Tavira=20Garc=C3=ADa?= <118979672+atavirag@users.noreply.github.com> Date: Thu, 24 Sep 2026 09:24:37 +0000 Subject: [PATCH 08/21] Add Jpsi --> mu mu process functions --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 113 +++++++++++++++++++--------- 1 file changed, 79 insertions(+), 34 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index b9e5765d1e5..862a517e731 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -43,6 +43,11 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; +enum class CandSpecies { + kRho = 0, + kJpsi = 1 +}; + struct UpcTrackVertexingQA { // Configurables Configurable yCandMax{"yCandMax", 0.8, "max. cand. rapidity"}; @@ -56,22 +61,24 @@ struct UpcTrackVertexingQA { // Name shortenings // passed* columns are in TrackSelectionExtension; isGlobalTrack* and trackCutFlag in TrackSelection - using TracksExtraWPidPi = soa::Join; + using TracksExtraSels = soa::Join; + using TracksExtraWPidPi = soa::Join; + using TracksExtraWPidMu = soa::Join; static constexpr float MassPion = o2::constants::physics::MassPionCharged; + static constexpr float MassMuon = o2::constants::physics::MassMuon; // Ordered list of cuts. The cumulative cut flow follows this order, // so reorder CutLabels and getCutResults together to change what "tighter" means. static constexpr int NCuts = 8; static constexpr std::array CutLabels = { - "all tracks", "hasTPC", "passedEtaRange", - "passedTPCNCls", "passedTPCChi2NDF", "passedITSNCls", + "all tracks", "hasTPC", "passedTPCNCls", + "passedEtaRange", "passedTPCChi2NDF", "passedITSNCls", "passedITSChi2NDF", "hasITS"}; // Axes - ConfigurableAxis axisMass{"axisMass", {160, 0.4, 1.2}, "m_{#pi#pi} (GeV/#it{c}^{2})"}; + ConfigurableAxis axisMass{"axisMass", {200, 2.0, 4.0}, "m_{#pi#pi} (GeV/#it{c}^{2})"}; ConfigurableAxis axisPt{"axisPt", {200, 0., 2.}, "#it{p}_{T} (GeV/#it{c})"}; HistogramRegistry registry{ @@ -94,7 +101,7 @@ struct UpcTrackVertexingQA { {"Trk/hEta", ";#eta;entries", {HistType::kTH1F, {{100, -1., 1.}}}}, {"Trk/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, {"Trk/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}}, - {"Trk/hNSigmaPiVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}_{#pi}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, + {"Trk/hNSigmaVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, {"Trk/hHasIts", ";has ITS;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, {"Trk/hIsPvContrib", ";is PV contributor;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, {"Trk/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{160, 0., 160.}}}}, @@ -109,7 +116,7 @@ struct UpcTrackVertexingQA { {"TrkColl/hEta", ";#eta;entries", {HistType::kTH1F, {{100, -1., 1.}}}}, {"TrkColl/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, {"TrkColl/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}}, - {"TrkColl/hNSigmaPiVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}_{#pi}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, + {"TrkColl/hNSigmaVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, {"TrkColl/hHasIts", ";has ITS;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, {"TrkColl/hIsPvContrib", ";is PV contributor;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, {"TrkColl/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{160, 0., 160.}}}}, @@ -120,7 +127,6 @@ struct UpcTrackVertexingQA { {"TrkColl/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.5, 0.5}}}} } }; - void init(InitContext&) { @@ -142,6 +148,16 @@ struct UpcTrackVertexingQA { } } + template + float getNSigma(TTrack const& track) + { + if constexpr (species == CandSpecies::kRho) { + return track.tpcNSigmaPi(); + } else { + return track.tpcNSigmaMu(); + } + } + // Result of every cut for one track (same order as CutLabels) template std::array getCutResults(TTrack const& track) @@ -183,14 +199,14 @@ struct UpcTrackVertexingQA { } // Basic kinematic / TPC properties of a candidate prong - template + template void checkTpcTrackProperties(TTrack const& track) { registry.fill(HIST("TrkColl/hPt"), track.pt()); registry.fill(HIST("TrkColl/hEta"), track.eta()); registry.fill(HIST("TrkColl/hChi2NCl"), track.tpcChi2NCl()); registry.fill(HIST("TrkColl/hTpcSignalVsP"), track.p(), track.tpcSignal()); - registry.fill(HIST("TrkColl/hNSigmaPiVsP"), track.p(), track.tpcNSigmaPi()); + registry.fill(HIST("TrkColl/hNSigmaVsP"), track.p(), getNSigma(track)); registry.fill(HIST("TrkColl/hHasIts"), static_cast(track.hasITS())); registry.fill(HIST("TrkColl/hIsPvContrib"), static_cast(track.isPVContributor())); registry.fill(HIST("TrkColl/hTpcNClsFound"), track.tpcNClsFound()); @@ -204,7 +220,7 @@ struct UpcTrackVertexingQA { } // Basic single-track selection used to build the rho candidate - template + template bool isGoodTrack(TTrack const& track) { if (!track.hasTPC()) { @@ -216,24 +232,25 @@ struct UpcTrackVertexingQA { if (track.pt() < ptTrackMin || std::abs(track.eta()) > etaTrackMax) { return false; } - return std::abs(track.tpcNSigmaPi()) <= nSigmaTpcMax; + return std::abs(getNSigma(track)) <= nSigmaTpcMax; } - + // loop on tracks before grouping by collision - void processTracks(TracksExtraWPidPi const& tracks) + template + void fillTrackPlotsBeforeGrouping(TTrack const& tracks) { - + for (auto const& track : tracks) { - // select good tracks for the rho + // select good tracks for the candidate //LOGF(info, "Track pT: %f,", track.pt()); - if(!isGoodTrack(track)) + if(!isGoodTrack(track)) continue; registry.fill(HIST("Trk/hPt"), track.pt()); registry.fill(HIST("Trk/hEta"), track.eta()); registry.fill(HIST("Trk/hChi2NCl"), track.tpcChi2NCl()); registry.fill(HIST("Trk/hTpcSignalVsP"), track.p(), track.tpcSignal()); - registry.fill(HIST("Trk/hNSigmaPiVsP"), track.p(), track.tpcNSigmaPi()); + registry.fill(HIST("Trk/hNSigmaVsP"), track.p(), getNSigma(track)); registry.fill(HIST("Trk/hHasIts"), static_cast(track.hasITS())); registry.fill(HIST("Trk/hIsPvContrib"), static_cast(track.isPVContributor())); registry.fill(HIST("Trk/hTpcNClsFound"), track.tpcNClsFound()); @@ -244,10 +261,22 @@ struct UpcTrackVertexingQA { registry.fill(HIST("Trk/hDcaZ"), track.dcaZ()); } } - PROCESS_SWITCH(UpcTrackVertexingQA, processTracks, "Process tracks before asking for collisions", true); + + void processRhoTracksBeforeGrouping(TracksExtraWPidPi const& tracks) + { + fillTrackPlotsBeforeGrouping(tracks); + } + PROCESS_SWITCH(UpcTrackVertexingQA, processRhoTracksBeforeGrouping, "Process rho tracks before asking for collisions", true); + + void processJpsiTracksBeforeGrouping(TracksExtraWPidMu const& tracks) + { + fillTrackPlotsBeforeGrouping(tracks); + } + PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiTracksBeforeGrouping, "Process J/Psi tracks before asking for collisions", false); // Tracks are grouped by collision automatically - void processRhoCand(aod::Collision const& collision, TracksExtraWPidPi const& tracks) + template + void checkCandidateTracks(aod::Collision const& collision, TTrack const& tracks, float candMass) { registry.fill(HIST("Coll/hNContrib"), collision.numContrib()); registry.fill(HIST("Coll/hBCid"), collision.bcId()); @@ -259,15 +288,15 @@ struct UpcTrackVertexingQA { // Sequential ITS/TPC cuts on ALL tracks of the collision fillCutFlow(tracks); - // Select tracks for the rho candidate + // Select tracks for the candidate std::vector goodTracks; for (auto const& track : tracks) { - if (isGoodTrack(track)) { + if (isGoodTrack(track)) { goodTracks.push_back(track); } } - // Exactly two tracks with opposite charge -> rho candidate + // Exactly two tracks with opposite charge -> candidate if (goodTracks.size() != 2) { return; } @@ -277,25 +306,41 @@ struct UpcTrackVertexingQA { return; } - ROOT::Math::PxPyPzMVector p0(track0.px(), track0.py(), track0.pz(), MassPion); - ROOT::Math::PxPyPzMVector p1(track1.px(), track1.py(), track1.pz(), MassPion); - auto rho = p0 + p1; + ROOT::Math::PxPyPzMVector p0(track0.px(), track0.py(), track0.pz(), candMass); + ROOT::Math::PxPyPzMVector p1(track1.px(), track1.py(), track1.pz(), candMass); + auto candidate = p0 + p1; - if (rho.M() < massMin || rho.M() > massMax) { + LOGF(info, "Candidate pT: %f,", candidate.pt()); + LOGF(info, "Candidate mass: %f,", candidate.M()); + LOGF(info, "Candidate rapidity: %f,", candidate.Rapidity()); + + if (candidate.M() < massMin || candidate.M() > massMax) { return; } - if (rho.Pt() < ptCandMin || std::abs(rho.Rapidity()) > yCandMax) { + if (candidate.Pt() < ptCandMin || std::abs(candidate.Rapidity()) > yCandMax) { return; } - registry.fill(HIST("Cand/hMass"), rho.M()); - registry.fill(HIST("Cand/hPt"), rho.Pt()); - registry.fill(HIST("Cand/hRapidity"), rho.Rapidity()); + registry.fill(HIST("Cand/hMass"), candidate.M()); + registry.fill(HIST("Cand/hPt"), candidate.Pt()); + registry.fill(HIST("Cand/hRapidity"), candidate.Rapidity()); - checkTpcTrackProperties(track0); - checkTpcTrackProperties(track1); + checkTpcTrackProperties(track0); + checkTpcTrackProperties(track1); + } + + // Tracks are grouped by collision automatically + void processRhoCand(aod::Collision const& collision, TracksExtraWPidPi const& tracks) + { + checkCandidateTracks(collision, tracks, MassPion); } PROCESS_SWITCH(UpcTrackVertexingQA, processRhoCand, "Rho -> pi pi candidates and track QA", true); + + void processJpsiCand(aod::Collision const& collision, TracksExtraWPidMu const& tracks) + { + checkCandidateTracks(collision, tracks, MassMuon); + } + PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiCand, "J/Psi -> mu mu candidates and track QA", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) From 6ae76aa3f793acd93c98589f298797cfc07b3b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrea=20Tavira=20Garc=C3=ADa?= <118979672+atavirag@users.noreply.github.com> Date: Wed, 30 Sep 2026 08:43:58 +0000 Subject: [PATCH 09/21] Add MC info --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 269 +++++++++++++++++++++++----- 1 file changed, 222 insertions(+), 47 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index 862a517e731..0411a62a88e 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -14,8 +14,6 @@ /// \author Andrea Tavira Garcia a.tavira@cern.ch /// \author Andrea Giovanni Riffero andrea.giovanni.riffero@cern.ch -/// - #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -32,11 +30,11 @@ #include #include #include +#include #include -#include #include -#include +#include #include using namespace o2; @@ -55,16 +53,19 @@ struct UpcTrackVertexingQA { Configurable ptTrackMin{"ptTrackMin", 0.1, "min. track pT (GeV/c)"}; Configurable etaTrackMax{"etaTrackMax", 0.9, "max. |eta| of tracks"}; Configurable nSigmaTpcMax{"nSigmaTpcMax", 3.f, "max. TPC N_sigma (pion)"}; - Configurable nMinTpcClusters{"nMinTpcClusters", 60, "min. number of TPC clusters"}; + Configurable nMinTpcClusters{"nMinTpcClusters", 60, "min. number of TPC clusters"}; Configurable massMin{"massMin", 0.5, "min. inv. mass (GeV/c^2)"}; Configurable massMax{"massMax", 1.3, "max. inv. mass (GeV/c^2)"}; // Name shortenings // passed* columns are in TrackSelectionExtension; isGlobalTrack* and trackCutFlag in TrackSelection - using TracksExtraSels = soa::Join; + using TracksExtraSels = soa::Join; using TracksExtraWPidPi = soa::Join; using TracksExtraWPidMu = soa::Join; + using TracksExtraWPidPiMc = soa::Join; + using TracksExtraWPidMuMc = soa::Join; + using CollisionsWithMc = soa::Join; static constexpr float MassPion = o2::constants::physics::MassPionCharged; static constexpr float MassMuon = o2::constants::physics::MassMuon; @@ -77,28 +78,33 @@ struct UpcTrackVertexingQA { "passedEtaRange", "passedTPCChi2NDF", "passedITSNCls", "passedITSChi2NDF", "hasITS"}; - // Axes - ConfigurableAxis axisMass{"axisMass", {200, 2.0, 4.0}, "m_{#pi#pi} (GeV/#it{c}^{2})"}; + // Axes (the mass axis matches the default rho window; override it for the J/psi) + ConfigurableAxis axisMass{"axisMass", {200, 0.5, 1.3}, "m_{#pi#pi} (GeV/#it{c}^{2})"}; ConfigurableAxis axisPt{"axisPt", {200, 0., 2.}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis axisY{"axisY", {100, -1., 1.}, "Rapidity"}; + + HistogramConfigSpec hVtxZ{HistType::kTH1F, {{200, -20., 20.}}}; + HistogramConfigSpec hVtxXY{HistType::kTH1F, {{200, -0.05, 0.05}}}; HistogramRegistry registry{ "registry", {// candidate level {"Cand/hMass", ";m_{#pi#pi} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}}, {"Cand/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}}, - {"Cand/hRapidity", ";#it{y};entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"Cand/hRapidity", ";#it{y};entries", {HistType::kTH1F, {axisY}}}, + {"Cand/hPtVsRapidity", ";#it{p}_{T} (GeV/#it{c});#it{y}", {HistType::kTH2F, {axisPt, axisY}}}, // collision level {"Coll/hNContrib", ";N_{PV contributors};entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}}, {"Coll/hBCid", ";BCid;entries", {HistType::kTH1F, {{1000, 0., 1000.}}}}, - {"Coll/hVtxZ", ";#it{z}_{vtx} (cm);entries", {HistType::kTH1F, {{200, -20., 20.}}}}, - {"Coll/hVtxX", ";#it{x}_{vtx} (cm);entries", {HistType::kTH1F, {{200, -0.05, 0.05}}}}, - {"Coll/hVtxY", ";#it{y}_{vtx} (cm);entries", {HistType::kTH1F, {{200, -0.05, 0.05}}}}, + {"Coll/hVtxZ", ";#it{z}_{vtx} (cm);entries", hVtxZ}, + {"Coll/hVtxX", ";#it{x}_{vtx} (cm);entries", hVtxXY}, + {"Coll/hVtxY", ";#it{y}_{vtx} (cm);entries", hVtxXY}, {"Coll/hVtxChi2", ";#chi^{2} vtx;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - // track level (prongs of the candidate) + // track level (all good tracks, before grouping by collision) {"Trk/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}}, - {"Trk/hEta", ";#eta;entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"Trk/hEta", ";#eta;entries", {HistType::kTH1F, {axisY}}}, {"Trk/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, {"Trk/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}}, {"Trk/hNSigmaVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, @@ -111,7 +117,7 @@ struct UpcTrackVertexingQA { {"Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{200, -0.1, 0.1}}}}, {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.5, 0.5}}}}, - // track level after collision matching + // track level (prongs of the candidate, after collision matching) {"TrkColl/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}}, {"TrkColl/hEta", ";#eta;entries", {HistType::kTH1F, {{100, -1., 1.}}}}, {"TrkColl/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, @@ -146,6 +152,48 @@ struct UpcTrackVertexingQA { hSingle->GetXaxis()->SetBinLabel(i + 1, CutLabels[i]); hPerColl->GetXaxis()->SetBinLabel(i + 1, CutLabels[i]); } + + // MC histograms are only booked if at least one MC process function is enabled + const bool needMc = doprocessRhoTracksBeforeGroupingMcInfo || doprocessJpsiTracksBeforeGroupingMcInfo || + doprocessRhoCandMcInfo || doprocessJpsiCandMcInfo || doprocessMcGenRho || doprocessMcGenJpsi; + if (!needMc) { + return; + } + + // MC reco matched plots + registry.add("Matched/Cand/hMass", ";m_{#pi#pi}^{MC} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}); + registry.add("Matched/Cand/hMcPt", ";#it{p}_{T}^{MC} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Matched/Cand/hMcRapidity", ";#it{y}^{MC};entries", {HistType::kTH1F, {axisY}}); + registry.add("Matched/Cand/hPtVsRapidity", ";#it{p}_{T}^{MC matched} (GeV/#it{c});#it{y}^{MC}", {HistType::kTH2F, {axisPt, axisY}}); + + registry.add("Matched/Coll/hNContrib", ";N_{PV contributors}^{MC matched};entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}); + registry.add("Matched/Coll/hVtxX", ";#it{x}_{vtx}^{MC matched} (cm);entries", hVtxXY); + registry.add("Matched/Coll/hVtxY", ";#it{y}_{vtx}^{MC matched} (cm);entries", hVtxXY); + registry.add("Matched/Coll/hVtxZ", ";#it{z}_{vtx}^{MC matched} (cm);entries", hVtxZ); + + registry.add("Matched/Trk/hPt", ";#it{p}_{T}^{MC matched} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Matched/Trk/hEta", ";#eta^{MC};entries", {HistType::kTH1F, {axisY}}); + registry.add("Matched/Trk/hMcIsPhysicalPrimary", ";is physical primary;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); + registry.add("Matched/Trk/hMotherPdg", ";mother PDG code;entries", {HistType::kTH1F, {{1001, 0.5, 1000.5}}}); + + registry.add("Matched/TrkColl/hPt", ";#it{p}_{T}^{MC matched} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Matched/TrkColl/hEta", ";#eta^{MC};entries", {HistType::kTH1F, {axisY}}); + registry.add("Matched/TrkColl/hMcIsPhysicalPrimary", ";is physical primary;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); + registry.add("Matched/TrkColl/hMotherPdg", ";mother PDG code;entries", {HistType::kTH1F, {{1001, 0.5, 1000.5}}}); + + // MC generated plots + registry.add("McGen/Coll/hVtxX", ";#it{x}_{vtx}^{MC} (cm);entries", hVtxXY); + registry.add("McGen/Coll/hVtxY", ";#it{y}_{vtx}^{MC} (cm);entries", hVtxXY); + registry.add("McGen/Coll/hVtxZ", ";#it{z}_{vtx}^{MC} (cm);entries", hVtxZ); + + registry.add("McGen/Part/hPt", ";#it{p}_{T}^{MC} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("McGen/Part/hEta", ";#eta^{MC};entries", {HistType::kTH1F, {axisY}}); + registry.add("McGen/Part/hMcIsPhysicalPrimary", ";is physical primary;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); + + registry.add("McGen/MotherPart/hMotherPdg", ";mother PDG code;entries", {HistType::kTH1F, {{1001, 0.5, 1000.5}}}); + registry.add("McGen/MotherPart/hPt", ";#it{p}_{T}^{MC} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("McGen/MotherPart/hRapidity", ";#it{y}^{MC};entries", {HistType::kTH1F, {axisY}}); + registry.add("McGen/MotherPart/hPtVsRapidity", ";#it{p}_{T}^{MC} (GeV/#it{c});#it{y}^{MC}", {HistType::kTH2F, {axisPt, axisY}}); } template @@ -198,8 +246,8 @@ struct UpcTrackVertexingQA { } } - // Basic kinematic / TPC properties of a candidate prong - template + // Basic kinematic / TPC / ITS properties of a candidate prong + template void checkTpcTrackProperties(TTrack const& track) { registry.fill(HIST("TrkColl/hPt"), track.pt()); @@ -216,10 +264,25 @@ struct UpcTrackVertexingQA { registry.fill(HIST("TrkColl/hDcaXY"), track.dcaXY()); registry.fill(HIST("TrkColl/hDcaZ"), track.dcaZ()); + if constexpr (isMc) { + if (!track.has_mcParticle()) { + return; + } + auto mcPart = track.mcParticle(); + registry.fill(HIST("Matched/TrkColl/hPt"), mcPart.pt()); + registry.fill(HIST("Matched/TrkColl/hEta"), mcPart.eta()); + registry.fill(HIST("Matched/TrkColl/hMcIsPhysicalPrimary"), static_cast(mcPart.isPhysicalPrimary())); + if (mcPart.has_mothers()) { + for (auto const& mcMother : mcPart.template mothers_as()) { + registry.fill(HIST("Matched/TrkColl/hMotherPdg"), std::abs(mcMother.pdgCode())); + } + } + } + // TODO: ambiguity (aod::AmbiguousTracks), ... } - // Basic single-track selection used to build the rho candidate + // Basic single-track selection used to build the candidate template bool isGoodTrack(TTrack const& track) { @@ -235,16 +298,15 @@ struct UpcTrackVertexingQA { return std::abs(getNSigma(track)) <= nSigmaTpcMax; } - // loop on tracks before grouping by collision - template + // Loop on tracks before grouping by collision + template void fillTrackPlotsBeforeGrouping(TTrack const& tracks) { - for (auto const& track : tracks) { // select good tracks for the candidate - //LOGF(info, "Track pT: %f,", track.pt()); - if(!isGoodTrack(track)) + if (!isGoodTrack(track)) { continue; + } registry.fill(HIST("Trk/hPt"), track.pt()); registry.fill(HIST("Trk/hEta"), track.eta()); @@ -259,24 +321,27 @@ struct UpcTrackVertexingQA { registry.fill(HIST("Trk/hItsNClsInnerBarrel"), track.itsNClsInnerBarrel()); registry.fill(HIST("Trk/hDcaXY"), track.dcaXY()); registry.fill(HIST("Trk/hDcaZ"), track.dcaZ()); - } - } - void processRhoTracksBeforeGrouping(TracksExtraWPidPi const& tracks) - { - fillTrackPlotsBeforeGrouping(tracks); - } - PROCESS_SWITCH(UpcTrackVertexingQA, processRhoTracksBeforeGrouping, "Process rho tracks before asking for collisions", true); - - void processJpsiTracksBeforeGrouping(TracksExtraWPidMu const& tracks) - { - fillTrackPlotsBeforeGrouping(tracks); + if constexpr (isMc) { + if (!track.has_mcParticle()) { + continue; + } + auto mcPart = track.mcParticle(); + registry.fill(HIST("Matched/Trk/hPt"), mcPart.pt()); + registry.fill(HIST("Matched/Trk/hEta"), mcPart.eta()); + registry.fill(HIST("Matched/Trk/hMcIsPhysicalPrimary"), static_cast(mcPart.isPhysicalPrimary())); + if (mcPart.has_mothers()) { + for (auto const& mcMother : mcPart.template mothers_as()) { + registry.fill(HIST("Matched/Trk/hMotherPdg"), std::abs(mcMother.pdgCode())); + } + } + } + } } - PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiTracksBeforeGrouping, "Process J/Psi tracks before asking for collisions", false); // Tracks are grouped by collision automatically - template - void checkCandidateTracks(aod::Collision const& collision, TTrack const& tracks, float candMass) + template + void checkCandidateTracks(TCollision const& collision, TTrack const& tracks, float candMass) { registry.fill(HIST("Coll/hNContrib"), collision.numContrib()); registry.fill(HIST("Coll/hBCid"), collision.bcId()); @@ -284,6 +349,15 @@ struct UpcTrackVertexingQA { registry.fill(HIST("Coll/hVtxX"), collision.posX()); registry.fill(HIST("Coll/hVtxY"), collision.posY()); registry.fill(HIST("Coll/hVtxChi2"), collision.chi2()); + if constexpr (isMc) { + if (collision.has_mcCollision()) { + auto mcColl = collision.mcCollision(); + registry.fill(HIST("Matched/Coll/hNContrib"), collision.numContrib()); + registry.fill(HIST("Matched/Coll/hVtxX"), mcColl.posX()); + registry.fill(HIST("Matched/Coll/hVtxY"), mcColl.posY()); + registry.fill(HIST("Matched/Coll/hVtxZ"), mcColl.posZ()); + } + } // Sequential ITS/TPC cuts on ALL tracks of the collision fillCutFlow(tracks); @@ -310,10 +384,6 @@ struct UpcTrackVertexingQA { ROOT::Math::PxPyPzMVector p1(track1.px(), track1.py(), track1.pz(), candMass); auto candidate = p0 + p1; - LOGF(info, "Candidate pT: %f,", candidate.pt()); - LOGF(info, "Candidate mass: %f,", candidate.M()); - LOGF(info, "Candidate rapidity: %f,", candidate.Rapidity()); - if (candidate.M() < massMin || candidate.M() > massMax) { return; } @@ -324,23 +394,128 @@ struct UpcTrackVertexingQA { registry.fill(HIST("Cand/hMass"), candidate.M()); registry.fill(HIST("Cand/hPt"), candidate.Pt()); registry.fill(HIST("Cand/hRapidity"), candidate.Rapidity()); + registry.fill(HIST("Cand/hPtVsRapidity"), candidate.Pt(), candidate.Rapidity()); + + if constexpr (isMc) { + if (track0.has_mcParticle() && track1.has_mcParticle()) { + auto mcPart0 = track0.mcParticle(); + auto mcPart1 = track1.mcParticle(); + ROOT::Math::PxPyPzMVector mcP0(mcPart0.px(), mcPart0.py(), mcPart0.pz(), candMass); + ROOT::Math::PxPyPzMVector mcP1(mcPart1.px(), mcPart1.py(), mcPart1.pz(), candMass); + auto mcCandidate = mcP0 + mcP1; + registry.fill(HIST("Matched/Cand/hMass"), mcCandidate.M()); + registry.fill(HIST("Matched/Cand/hMcPt"), mcCandidate.Pt()); + registry.fill(HIST("Matched/Cand/hMcRapidity"), mcCandidate.Rapidity()); + registry.fill(HIST("Matched/Cand/hPtVsRapidity"), mcCandidate.Pt(), mcCandidate.Rapidity()); + } + } - checkTpcTrackProperties(track0); - checkTpcTrackProperties(track1); + checkTpcTrackProperties(track0); + checkTpcTrackProperties(track1); } - // Tracks are grouped by collision automatically + // Generated (MC truth) level: daughters and their mothers + template + void checkMcGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + { + using o2::constants::physics::Pdg; + constexpr int DaughterPdg = (species == CandSpecies::kRho) ? static_cast(PDG_t::kPiPlus) + : static_cast(PDG_t::kMuonMinus); + constexpr int MotherPdg = (species == CandSpecies::kRho) ? static_cast(PDG_t::kRho770_0) + : static_cast(o2::constants::physics::Pdg::kJPsi); + + registry.fill(HIST("McGen/Coll/hVtxX"), mcCollision.posX()); + registry.fill(HIST("McGen/Coll/hVtxY"), mcCollision.posY()); + registry.fill(HIST("McGen/Coll/hVtxZ"), mcCollision.posZ()); + + for (auto const& mcPart : mcParticles) { + if (std::abs(mcPart.pdgCode()) != DaughterPdg) { + continue; + } + if (mcPart.pt() < ptTrackMin || std::abs(mcPart.eta()) > etaTrackMax) { + continue; + } + + registry.fill(HIST("McGen/Part/hPt"), mcPart.pt()); + registry.fill(HIST("McGen/Part/hEta"), mcPart.eta()); + registry.fill(HIST("McGen/Part/hMcIsPhysicalPrimary"), static_cast(mcPart.isPhysicalPrimary())); + + if (!mcPart.has_mothers()) { + continue; + } + for (auto const& mcMother : mcPart.template mothers_as()) { + registry.fill(HIST("McGen/MotherPart/hMotherPdg"), std::abs(mcMother.pdgCode())); + + // fill the mother once, not once per daughter: only via the positive-PDG prong + if (std::abs(mcMother.pdgCode()) == MotherPdg && mcPart.pdgCode() > 0) { + registry.fill(HIST("McGen/MotherPart/hPt"), mcMother.pt()); + registry.fill(HIST("McGen/MotherPart/hRapidity"), mcMother.y()); + registry.fill(HIST("McGen/MotherPart/hPtVsRapidity"), mcMother.pt(), mcMother.y()); + } + } + } + } + + // Process functions + void processRhoTracksBeforeGrouping(TracksExtraWPidPi const& tracks) + { + fillTrackPlotsBeforeGrouping(tracks); + } + PROCESS_SWITCH(UpcTrackVertexingQA, processRhoTracksBeforeGrouping, "Process rho tracks before asking for collisions", true); + + void processJpsiTracksBeforeGrouping(TracksExtraWPidMu const& tracks) + { + fillTrackPlotsBeforeGrouping(tracks); + } + PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiTracksBeforeGrouping, "Process J/Psi tracks before asking for collisions", false); + + void processRhoTracksBeforeGroupingMcInfo(TracksExtraWPidPiMc const& tracks, aod::McParticles const&) + { + fillTrackPlotsBeforeGrouping(tracks); + } + PROCESS_SWITCH(UpcTrackVertexingQA, processRhoTracksBeforeGroupingMcInfo, "Process rho tracks before asking for collisions, ask for MC info", false); + + void processJpsiTracksBeforeGroupingMcInfo(TracksExtraWPidMuMc const& tracks, aod::McParticles const&) + { + fillTrackPlotsBeforeGrouping(tracks); + } + PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiTracksBeforeGroupingMcInfo, "Process J/Psi tracks before asking for collisions, ask for MC info", false); + void processRhoCand(aod::Collision const& collision, TracksExtraWPidPi const& tracks) { - checkCandidateTracks(collision, tracks, MassPion); + checkCandidateTracks(collision, tracks, MassPion); } PROCESS_SWITCH(UpcTrackVertexingQA, processRhoCand, "Rho -> pi pi candidates and track QA", true); void processJpsiCand(aod::Collision const& collision, TracksExtraWPidMu const& tracks) { - checkCandidateTracks(collision, tracks, MassMuon); + checkCandidateTracks(collision, tracks, MassMuon); } PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiCand, "J/Psi -> mu mu candidates and track QA", false); + + void processRhoCandMcInfo(CollisionsWithMc::iterator const& collision, aod::McCollisions const&, TracksExtraWPidPiMc const& tracks, aod::McParticles const&) + { + checkCandidateTracks(collision, tracks, MassPion); + } + PROCESS_SWITCH(UpcTrackVertexingQA, processRhoCandMcInfo, "Rho -> pi pi candidates and track QA, ask for MC info", false); + + void processJpsiCandMcInfo(CollisionsWithMc::iterator const& collision, aod::McCollisions const&, TracksExtraWPidMuMc const& tracks, aod::McParticles const&) + { + checkCandidateTracks(collision, tracks, MassMuon); + } + PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiCandMcInfo, "J/Psi -> mu mu candidates and track QA, ask for MC info", false); + + void processMcGenRho(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + { + checkMcGen(mcCollision, mcParticles); + } + PROCESS_SWITCH(UpcTrackVertexingQA, processMcGenRho, "Generated rho -> pi pi", false); + + void processMcGenJpsi(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + { + checkMcGen(mcCollision, mcParticles); + } + PROCESS_SWITCH(UpcTrackVertexingQA, processMcGenJpsi, "Generated J/Psi -> mu mu", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) From f5c90d160867f74111a5b107ac24daa901792880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrea=20Tavira=20Garc=C3=ADa?= <118979672+atavirag@users.noreply.github.com> Date: Wed, 30 Sep 2026 13:39:34 +0000 Subject: [PATCH 10/21] Fix histogram axes --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 35 ++++++++++++++++------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index 0411a62a88e..1ca1b98c900 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -85,15 +85,12 @@ struct UpcTrackVertexingQA { HistogramConfigSpec hVtxZ{HistType::kTH1F, {{200, -20., 20.}}}; HistogramConfigSpec hVtxXY{HistType::kTH1F, {{200, -0.05, 0.05}}}; + HistogramConfigSpec hPtTrk{HistType::kTH1F, {{200, 0.0, 2.0}}}; + HistogramConfigSpec hEtaTrk{HistType::kTH1F, {{100, -1.0, 1.0}}}; HistogramRegistry registry{ "registry", - {// candidate level - {"Cand/hMass", ";m_{#pi#pi} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}}, - {"Cand/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}}, - {"Cand/hRapidity", ";#it{y};entries", {HistType::kTH1F, {axisY}}}, - {"Cand/hPtVsRapidity", ";#it{p}_{T} (GeV/#it{c});#it{y}", {HistType::kTH2F, {axisPt, axisY}}}, - + { // collision level {"Coll/hNContrib", ";N_{PV contributors};entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}}, {"Coll/hBCid", ";BCid;entries", {HistType::kTH1F, {{1000, 0., 1000.}}}}, @@ -103,8 +100,8 @@ struct UpcTrackVertexingQA { {"Coll/hVtxChi2", ";#chi^{2} vtx;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, // track level (all good tracks, before grouping by collision) - {"Trk/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}}, - {"Trk/hEta", ";#eta;entries", {HistType::kTH1F, {axisY}}}, + {"Trk/hPt", ";#it{p}_{T} (GeV/#it{c});entries", hPtTrk}, + {"Trk/hEta", ";#eta;entries", hEtaTrk}, {"Trk/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, {"Trk/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}}, {"Trk/hNSigmaVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, @@ -118,8 +115,8 @@ struct UpcTrackVertexingQA { {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.5, 0.5}}}}, // track level (prongs of the candidate, after collision matching) - {"TrkColl/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}}, - {"TrkColl/hEta", ";#eta;entries", {HistType::kTH1F, {{100, -1., 1.}}}}, + {"TrkColl/hPt", ";#it{p}_{T} (GeV/#it{c});entries", hPtTrk}, + {"TrkColl/hEta", ";#eta;entries", hEtaTrk}, {"TrkColl/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, {"TrkColl/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}}, {"TrkColl/hNSigmaVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, @@ -152,6 +149,12 @@ struct UpcTrackVertexingQA { hSingle->GetXaxis()->SetBinLabel(i + 1, CutLabels[i]); hPerColl->GetXaxis()->SetBinLabel(i + 1, CutLabels[i]); } + + // candidate level plots + registry.add("Cand/hMass", ";m_{#pi#pi} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}); + registry.add("Cand/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); + registry.add("Cand/hRapidity", ";#it{y};entries", {HistType::kTH1F, {axisY}}); + registry.add("Cand/hPtVsRapidity", ";#it{p}_{T} (GeV/#it{c});#it{y}", {HistType::kTH2F, {axisPt, axisY}}); // MC histograms are only booked if at least one MC process function is enabled const bool needMc = doprocessRhoTracksBeforeGroupingMcInfo || doprocessJpsiTracksBeforeGroupingMcInfo || @@ -171,13 +174,13 @@ struct UpcTrackVertexingQA { registry.add("Matched/Coll/hVtxY", ";#it{y}_{vtx}^{MC matched} (cm);entries", hVtxXY); registry.add("Matched/Coll/hVtxZ", ";#it{z}_{vtx}^{MC matched} (cm);entries", hVtxZ); - registry.add("Matched/Trk/hPt", ";#it{p}_{T}^{MC matched} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); - registry.add("Matched/Trk/hEta", ";#eta^{MC};entries", {HistType::kTH1F, {axisY}}); + registry.add("Matched/Trk/hPt", ";#it{p}_{T}^{MC matched} (GeV/#it{c});entries", hPtTrk); + registry.add("Matched/Trk/hEta", ";#eta^{MC};entries", hEtaTrk); registry.add("Matched/Trk/hMcIsPhysicalPrimary", ";is physical primary;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); registry.add("Matched/Trk/hMotherPdg", ";mother PDG code;entries", {HistType::kTH1F, {{1001, 0.5, 1000.5}}}); - registry.add("Matched/TrkColl/hPt", ";#it{p}_{T}^{MC matched} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); - registry.add("Matched/TrkColl/hEta", ";#eta^{MC};entries", {HistType::kTH1F, {axisY}}); + registry.add("Matched/TrkColl/hPt", ";#it{p}_{T}^{MC matched} (GeV/#it{c});entries", hPtTrk); + registry.add("Matched/TrkColl/hEta", ";#eta^{MC};entries", hEtaTrk); registry.add("Matched/TrkColl/hMcIsPhysicalPrimary", ";is physical primary;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); registry.add("Matched/TrkColl/hMotherPdg", ";mother PDG code;entries", {HistType::kTH1F, {{1001, 0.5, 1000.5}}}); @@ -186,8 +189,8 @@ struct UpcTrackVertexingQA { registry.add("McGen/Coll/hVtxY", ";#it{y}_{vtx}^{MC} (cm);entries", hVtxXY); registry.add("McGen/Coll/hVtxZ", ";#it{z}_{vtx}^{MC} (cm);entries", hVtxZ); - registry.add("McGen/Part/hPt", ";#it{p}_{T}^{MC} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); - registry.add("McGen/Part/hEta", ";#eta^{MC};entries", {HistType::kTH1F, {axisY}}); + registry.add("McGen/Part/hPt", ";#it{p}_{T}^{MC} (GeV/#it{c});entries", hPtTrk); + registry.add("McGen/Part/hEta", ";#eta^{MC};entries", hEtaTrk); registry.add("McGen/Part/hMcIsPhysicalPrimary", ";is physical primary;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); registry.add("McGen/MotherPart/hMotherPdg", ";mother PDG code;entries", {HistType::kTH1F, {{1001, 0.5, 1000.5}}}); From 3c37b3025eccbc161c425bec1cc5389937fe6e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrea=20Tavira=20Garc=C3=ADa?= <118979672+atavirag@users.noreply.github.com> Date: Wed, 30 Sep 2026 14:25:02 +0000 Subject: [PATCH 11/21] more axis fixes --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index 1ca1b98c900..6efe8162c17 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -80,7 +80,7 @@ struct UpcTrackVertexingQA { // Axes (the mass axis matches the default rho window; override it for the J/psi) ConfigurableAxis axisMass{"axisMass", {200, 0.5, 1.3}, "m_{#pi#pi} (GeV/#it{c}^{2})"}; - ConfigurableAxis axisPt{"axisPt", {200, 0., 2.}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.00, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.175, 0.20, 0.25, 0.30, 0.40, 0.50}, "#it{p}_{T} (GeV/#it{c})"}; ConfigurableAxis axisY{"axisY", {100, -1., 1.}, "Rapidity"}; HistogramConfigSpec hVtxZ{HistType::kTH1F, {{200, -20., 20.}}}; From f592dea2f95a868da44f3786122daf99d26f4db6 Mon Sep 17 00:00:00 2001 From: ariffero Date: Thu, 1 Oct 2026 10:22:21 +0200 Subject: [PATCH 12/21] Change histo binning and ranges. Make ptTrk axis configurable --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 49 +++++++++++++++-------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index 6efe8162c17..97edcc67e77 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -82,10 +82,11 @@ struct UpcTrackVertexingQA { ConfigurableAxis axisMass{"axisMass", {200, 0.5, 1.3}, "m_{#pi#pi} (GeV/#it{c}^{2})"}; ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.00, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.175, 0.20, 0.25, 0.30, 0.40, 0.50}, "#it{p}_{T} (GeV/#it{c})"}; ConfigurableAxis axisY{"axisY", {100, -1., 1.}, "Rapidity"}; + ConfigurableAxis axisPtTrk{"axisPtTrk", {80, 0.0, 0.8}, "#it{p}_{T} (GeV/#it{c})"}; - HistogramConfigSpec hVtxZ{HistType::kTH1F, {{200, -20., 20.}}}; - HistogramConfigSpec hVtxXY{HistType::kTH1F, {{200, -0.05, 0.05}}}; - HistogramConfigSpec hPtTrk{HistType::kTH1F, {{200, 0.0, 2.0}}}; + HistogramConfigSpec hVtxZ{HistType::kTH1F, {{80, -20., 20.}}}; + HistogramConfigSpec hVtxX{HistType::kTH1F, {{50, -0.04, -0.015}}}; + HistogramConfigSpec hVtxY{HistType::kTH1F, {{60, -0.015, 0.015}}}; HistogramConfigSpec hEtaTrk{HistType::kTH1F, {{100, -1.0, 1.0}}}; HistogramRegistry registry{ @@ -95,39 +96,39 @@ struct UpcTrackVertexingQA { {"Coll/hNContrib", ";N_{PV contributors};entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}}, {"Coll/hBCid", ";BCid;entries", {HistType::kTH1F, {{1000, 0., 1000.}}}}, {"Coll/hVtxZ", ";#it{z}_{vtx} (cm);entries", hVtxZ}, - {"Coll/hVtxX", ";#it{x}_{vtx} (cm);entries", hVtxXY}, - {"Coll/hVtxY", ";#it{y}_{vtx} (cm);entries", hVtxXY}, + {"Coll/hVtxX", ";#it{x}_{vtx} (cm);entries", hVtxX}, + {"Coll/hVtxY", ";#it{y}_{vtx} (cm);entries", hVtxY}, {"Coll/hVtxChi2", ";#chi^{2} vtx;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, // track level (all good tracks, before grouping by collision) - {"Trk/hPt", ";#it{p}_{T} (GeV/#it{c});entries", hPtTrk}, + {"Trk/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtTrk}}}, {"Trk/hEta", ";#eta;entries", hEtaTrk}, - {"Trk/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, + {"Trk/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{50, 0., 5.}}}}, {"Trk/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}}, {"Trk/hNSigmaVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, {"Trk/hHasIts", ";has ITS;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, {"Trk/hIsPvContrib", ";is PV contributor;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, - {"Trk/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{160, 0., 160.}}}}, - {"Trk/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 40.}}}}, + {"Trk/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{90, 60, 150.}}}}, + {"Trk/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, {"Trk/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, {"Trk/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, - {"Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{200, -0.1, 0.1}}}}, - {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.5, 0.5}}}}, + {"Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{140, -0.035, 0.035}}}}, + {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{60, -0.15, 0.15}}}}, // track level (prongs of the candidate, after collision matching) - {"TrkColl/hPt", ";#it{p}_{T} (GeV/#it{c});entries", hPtTrk}, + {"TrkColl/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtTrk}}}, {"TrkColl/hEta", ";#eta;entries", hEtaTrk}, - {"TrkColl/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, + {"TrkColl/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{50, 0., 5.}}}}, {"TrkColl/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}}, {"TrkColl/hNSigmaVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, {"TrkColl/hHasIts", ";has ITS;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, {"TrkColl/hIsPvContrib", ";is PV contributor;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, - {"TrkColl/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{160, 0., 160.}}}}, - {"TrkColl/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 40.}}}}, + {"TrkColl/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{90, 60, 150.}}}}, + {"TrkColl/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, {"TrkColl/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, {"TrkColl/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, - {"TrkColl/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{200, -0.1, 0.1}}}}, - {"TrkColl/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.5, 0.5}}}} + {"TrkColl/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{140, -0.035, 0.035}}}}, + {"TrkColl/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{60, -0.15, 0.15}}}} } }; @@ -170,26 +171,26 @@ struct UpcTrackVertexingQA { registry.add("Matched/Cand/hPtVsRapidity", ";#it{p}_{T}^{MC matched} (GeV/#it{c});#it{y}^{MC}", {HistType::kTH2F, {axisPt, axisY}}); registry.add("Matched/Coll/hNContrib", ";N_{PV contributors}^{MC matched};entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}); - registry.add("Matched/Coll/hVtxX", ";#it{x}_{vtx}^{MC matched} (cm);entries", hVtxXY); - registry.add("Matched/Coll/hVtxY", ";#it{y}_{vtx}^{MC matched} (cm);entries", hVtxXY); + registry.add("Matched/Coll/hVtxX", ";#it{x}_{vtx}^{MC matched} (cm);entries", hVtxX); + registry.add("Matched/Coll/hVtxY", ";#it{y}_{vtx}^{MC matched} (cm);entries", hVtxY); registry.add("Matched/Coll/hVtxZ", ";#it{z}_{vtx}^{MC matched} (cm);entries", hVtxZ); - registry.add("Matched/Trk/hPt", ";#it{p}_{T}^{MC matched} (GeV/#it{c});entries", hPtTrk); + registry.add("Matched/Trk/hPt", ";#it{p}_{T}^{MC matched} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtTrk}}); registry.add("Matched/Trk/hEta", ";#eta^{MC};entries", hEtaTrk); registry.add("Matched/Trk/hMcIsPhysicalPrimary", ";is physical primary;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); registry.add("Matched/Trk/hMotherPdg", ";mother PDG code;entries", {HistType::kTH1F, {{1001, 0.5, 1000.5}}}); - registry.add("Matched/TrkColl/hPt", ";#it{p}_{T}^{MC matched} (GeV/#it{c});entries", hPtTrk); + registry.add("Matched/TrkColl/hPt", ";#it{p}_{T}^{MC matched} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtTrk}}); registry.add("Matched/TrkColl/hEta", ";#eta^{MC};entries", hEtaTrk); registry.add("Matched/TrkColl/hMcIsPhysicalPrimary", ";is physical primary;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); registry.add("Matched/TrkColl/hMotherPdg", ";mother PDG code;entries", {HistType::kTH1F, {{1001, 0.5, 1000.5}}}); // MC generated plots - registry.add("McGen/Coll/hVtxX", ";#it{x}_{vtx}^{MC} (cm);entries", hVtxXY); - registry.add("McGen/Coll/hVtxY", ";#it{y}_{vtx}^{MC} (cm);entries", hVtxXY); + registry.add("McGen/Coll/hVtxX", ";#it{x}_{vtx}^{MC} (cm);entries", hVtxX); + registry.add("McGen/Coll/hVtxY", ";#it{y}_{vtx}^{MC} (cm);entries", hVtxY); registry.add("McGen/Coll/hVtxZ", ";#it{z}_{vtx}^{MC} (cm);entries", hVtxZ); - registry.add("McGen/Part/hPt", ";#it{p}_{T}^{MC} (GeV/#it{c});entries", hPtTrk); + registry.add("McGen/Part/hPt", ";#it{p}_{T}^{MC} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtTrk}}); registry.add("McGen/Part/hEta", ";#eta^{MC};entries", hEtaTrk); registry.add("McGen/Part/hMcIsPhysicalPrimary", ";is physical primary;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); From 13ae1a3cb369443dfd7027277b81caa62b625bf4 Mon Sep 17 00:00:00 2001 From: ariffero Date: Thu, 1 Oct 2026 10:53:42 +0200 Subject: [PATCH 13/21] Define all histos in init --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 81 ++++++++++++++--------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index 97edcc67e77..21bb2b63b95 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -89,51 +89,48 @@ struct UpcTrackVertexingQA { HistogramConfigSpec hVtxY{HistType::kTH1F, {{60, -0.015, 0.015}}}; HistogramConfigSpec hEtaTrk{HistType::kTH1F, {{100, -1.0, 1.0}}}; - HistogramRegistry registry{ - "registry", - { - // collision level - {"Coll/hNContrib", ";N_{PV contributors};entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}}, - {"Coll/hBCid", ";BCid;entries", {HistType::kTH1F, {{1000, 0., 1000.}}}}, - {"Coll/hVtxZ", ";#it{z}_{vtx} (cm);entries", hVtxZ}, - {"Coll/hVtxX", ";#it{x}_{vtx} (cm);entries", hVtxX}, - {"Coll/hVtxY", ";#it{y}_{vtx} (cm);entries", hVtxY}, - {"Coll/hVtxChi2", ";#chi^{2} vtx;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - - // track level (all good tracks, before grouping by collision) - {"Trk/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtTrk}}}, - {"Trk/hEta", ";#eta;entries", hEtaTrk}, - {"Trk/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{50, 0., 5.}}}}, - {"Trk/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}}, - {"Trk/hNSigmaVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, - {"Trk/hHasIts", ";has ITS;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, - {"Trk/hIsPvContrib", ";is PV contributor;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, - {"Trk/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{90, 60, 150.}}}}, - {"Trk/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - {"Trk/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, - {"Trk/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, - {"Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{140, -0.035, 0.035}}}}, - {"Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{60, -0.15, 0.15}}}}, - - // track level (prongs of the candidate, after collision matching) - {"TrkColl/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtTrk}}}, - {"TrkColl/hEta", ";#eta;entries", hEtaTrk}, - {"TrkColl/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{50, 0., 5.}}}}, - {"TrkColl/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}}, - {"TrkColl/hNSigmaVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}}, - {"TrkColl/hHasIts", ";has ITS;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, - {"TrkColl/hIsPvContrib", ";is PV contributor;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, - {"TrkColl/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{90, 60, 150.}}}}, - {"TrkColl/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 10.}}}}, - {"TrkColl/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, - {"TrkColl/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}}, - {"TrkColl/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{140, -0.035, 0.035}}}}, - {"TrkColl/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{60, -0.15, 0.15}}}} - } - }; + HistogramRegistry registry{"registry"}; void init(InitContext&) { + // collision level + registry.add("Coll/hNContrib", ";N_{PV contributors};entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}); + registry.add("Coll/hBCid", ";BCid;entries", {HistType::kTH1F, {{1000, 0., 1000.}}}); + registry.add("Coll/hVtxZ", ";#it{z}_{vtx} (cm);entries", hVtxZ); + registry.add("Coll/hVtxX", ";#it{x}_{vtx} (cm);entries", hVtxX); + registry.add("Coll/hVtxY", ";#it{y}_{vtx} (cm);entries", hVtxY); + registry.add("Coll/hVtxChi2", ";#chi^{2} vtx;entries", {HistType::kTH1F, {{100, 0., 10.}}}); + + // track level (all good tracks, before grouping by collision) + registry.add("Trk/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtTrk}}); + registry.add("Trk/hEta", ";#eta;entries", hEtaTrk); + registry.add("Trk/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{50, 0., 5.}}}); + registry.add("Trk/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}); + registry.add("Trk/hNSigmaVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}); + registry.add("Trk/hHasIts", ";has ITS;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); + registry.add("Trk/hIsPvContrib", ";is PV contributor;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); + registry.add("Trk/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{90, 60, 150.}}}); + registry.add("Trk/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry.add("Trk/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); + registry.add("Trk/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); + registry.add("Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{140, -0.035, 0.035}}}); + registry.add("Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{60, -0.15, 0.15}}}); + + // track level (prongs of the candidate, after collision matching) + registry.add("TrkColl/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtTrk}}); + registry.add("TrkColl/hEta", ";#eta;entries", hEtaTrk); + registry.add("TrkColl/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{50, 0., 5.}}}); + registry.add("TrkColl/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}); + registry.add("TrkColl/hNSigmaVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}); + registry.add("TrkColl/hHasIts", ";has ITS;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); + registry.add("TrkColl/hIsPvContrib", ";is PV contributor;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); + registry.add("TrkColl/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{90, 60, 150.}}}); + registry.add("TrkColl/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 10.}}}); + registry.add("TrkColl/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); + registry.add("TrkColl/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); + registry.add("TrkColl/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{140, -0.035, 0.035}}}); + registry.add("TrkColl/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{60, -0.15, 0.15}}}); + // Cut flows: cumulative, single cut, and tracks per collision vs. cut step registry.add("Cut/hCutFlowCumulative", "tracks surviving cuts applied in sequence;;entries", HistType::kTH1F, {{NCuts, -0.5, NCuts - 0.5}}); From 31f248d19b17bb00ada1d4690e442ae66527141b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrea=20Tavira=20Garc=C3=ADa?= <118979672+atavirag@users.noreply.github.com> Date: Thu, 1 Oct 2026 13:31:38 +0000 Subject: [PATCH 14/21] Fix DCAz axis and binning --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index 21bb2b63b95..f7dff5e442d 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -114,7 +114,7 @@ struct UpcTrackVertexingQA { registry.add("Trk/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); registry.add("Trk/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); registry.add("Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{140, -0.035, 0.035}}}); - registry.add("Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{60, -0.15, 0.15}}}); + registry.add("Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.05, 0.05}}}); // track level (prongs of the candidate, after collision matching) registry.add("TrkColl/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtTrk}}); @@ -129,7 +129,7 @@ struct UpcTrackVertexingQA { registry.add("TrkColl/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); registry.add("TrkColl/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); registry.add("TrkColl/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{140, -0.035, 0.035}}}); - registry.add("TrkColl/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{60, -0.15, 0.15}}}); + registry.add("TrkColl/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.05, 0.05}}}); // Cut flows: cumulative, single cut, and tracks per collision vs. cut step registry.add("Cut/hCutFlowCumulative", "tracks surviving cuts applied in sequence;;entries", From 3fdefe13a0fd846f325aff28c3802076991c268f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrea=20Tavira=20Garc=C3=ADa?= <118979672+atavirag@users.noreply.github.com> Date: Wed, 7 Oct 2026 15:00:51 +0000 Subject: [PATCH 15/21] Dca cut to remove DCA == 999 --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index f7dff5e442d..5616d357ef1 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -52,10 +52,7 @@ struct UpcTrackVertexingQA { Configurable ptCandMin{"ptCandMin", 0., "min. cand. pT (GeV/c)"}; Configurable ptTrackMin{"ptTrackMin", 0.1, "min. track pT (GeV/c)"}; Configurable etaTrackMax{"etaTrackMax", 0.9, "max. |eta| of tracks"}; - Configurable nSigmaTpcMax{"nSigmaTpcMax", 3.f, "max. TPC N_sigma (pion)"}; Configurable nMinTpcClusters{"nMinTpcClusters", 60, "min. number of TPC clusters"}; - Configurable massMin{"massMin", 0.5, "min. inv. mass (GeV/c^2)"}; - Configurable massMax{"massMax", 1.3, "max. inv. mass (GeV/c^2)"}; // Name shortenings // passed* columns are in TrackSelectionExtension; isGlobalTrack* and trackCutFlag in TrackSelection @@ -296,7 +293,10 @@ struct UpcTrackVertexingQA { if (track.pt() < ptTrackMin || std::abs(track.eta()) > etaTrackMax) { return false; } - return std::abs(getNSigma(track)) <= nSigmaTpcMax; + if (std::abs(track.dcaZ()) >= 999 || std::abs(track.dcaXY()) >= 999) { + return false; + } + return true; } // Loop on tracks before grouping by collision @@ -309,6 +309,9 @@ struct UpcTrackVertexingQA { continue; } + //LOGF(info, "Track DCA z: %f", track.dcaZ()); + //LOGF(info, "Track DCA xy: %f", track.dcaXY()); + registry.fill(HIST("Trk/hPt"), track.pt()); registry.fill(HIST("Trk/hEta"), track.eta()); registry.fill(HIST("Trk/hChi2NCl"), track.tpcChi2NCl()); @@ -385,9 +388,6 @@ struct UpcTrackVertexingQA { ROOT::Math::PxPyPzMVector p1(track1.px(), track1.py(), track1.pz(), candMass); auto candidate = p0 + p1; - if (candidate.M() < massMin || candidate.M() > massMax) { - return; - } if (candidate.Pt() < ptCandMin || std::abs(candidate.Rapidity()) > yCandMax) { return; } From aa5d700d85f45647c83e8e70ee8ca51de8a2af2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrea=20Tavira=20Garc=C3=ADa?= <118979672+atavirag@users.noreply.github.com> Date: Thu, 8 Oct 2026 12:47:01 +0000 Subject: [PATCH 16/21] Fix particle association -- DIRTY *This code needs to be cleaned* - Physics-inspired cuts removed - Track association done before creating the candidate or asking for exactly two tracks - New process function: processTracksIU - New control plots --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 55 +++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index 5616d357ef1..648343388d9 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -64,6 +64,9 @@ struct UpcTrackVertexingQA { using TracksExtraWPidMuMc = soa::Join; using CollisionsWithMc = soa::Join; + using TracksExtraIU = soa::Join; + static constexpr float MassPion = o2::constants::physics::MassPionCharged; static constexpr float MassMuon = o2::constants::physics::MassMuon; @@ -109,7 +112,7 @@ struct UpcTrackVertexingQA { registry.add("Trk/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{90, 60, 150.}}}); registry.add("Trk/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 10.}}}); registry.add("Trk/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); - registry.add("Trk/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); + registry.add("Trk/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{4, -0.5, 3.5}}}); registry.add("Trk/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{140, -0.035, 0.035}}}); registry.add("Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.05, 0.05}}}); @@ -124,10 +127,15 @@ struct UpcTrackVertexingQA { registry.add("TrkColl/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{90, 60, 150.}}}); registry.add("TrkColl/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 10.}}}); registry.add("TrkColl/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); - registry.add("TrkColl/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); + registry.add("TrkColl/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{4, -0.5, 3.5}}}); registry.add("TrkColl/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{140, -0.035, 0.035}}}); registry.add("TrkColl/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.05, 0.05}}}); + registry.add("TrkColl/hTrackSizePerEvent", ";#it{N}_{tracks} per event;entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}); + + // collision Id counter + registry.add("Coll/hCollIdCounter", ";collision ID;entries", {HistType::kTH1F, {{3, -1.5, 1.5}}}); + // Cut flows: cumulative, single cut, and tracks per collision vs. cut step registry.add("Cut/hCutFlowCumulative", "tracks surviving cuts applied in sequence;;entries", HistType::kTH1F, {{NCuts, -0.5, NCuts - 0.5}}); @@ -281,7 +289,7 @@ struct UpcTrackVertexingQA { } // Basic single-track selection used to build the candidate - template + template bool isGoodTrack(TTrack const& track) { if (!track.hasTPC()) { @@ -305,7 +313,7 @@ struct UpcTrackVertexingQA { { for (auto const& track : tracks) { // select good tracks for the candidate - if (!isGoodTrack(track)) { + if (!isGoodTrack(track)) { continue; } @@ -369,11 +377,17 @@ struct UpcTrackVertexingQA { // Select tracks for the candidate std::vector goodTracks; for (auto const& track : tracks) { - if (isGoodTrack(track)) { + if (isGoodTrack(track)) { goodTracks.push_back(track); + if (!track.has_collision()) { + continue; + } + checkTpcTrackProperties(track); } } + registry.fill(HIST("TrkColl/hTrackSizePerEvent"), goodTracks.size()); + // Exactly two tracks with opposite charge -> candidate if (goodTracks.size() != 2) { return; @@ -411,8 +425,8 @@ struct UpcTrackVertexingQA { } } - checkTpcTrackProperties(track0); - checkTpcTrackProperties(track1); + //checkTpcTrackProperties(track0); + //checkTpcTrackProperties(track1); } // Generated (MC truth) level: daughters and their mothers @@ -517,6 +531,33 @@ struct UpcTrackVertexingQA { checkMcGen(mcCollision, mcParticles); } PROCESS_SWITCH(UpcTrackVertexingQA, processMcGenJpsi, "Generated J/Psi -> mu mu", false); + + + + + void processTracksIU(TracksExtraIU const& tracks) { + // track loop + for (const auto& track : tracks) { + + if (!isGoodTrack(track)) { + continue; + } + + int32_t collId = track.collisionId(); + + if (collId < 0) { + registry.fill(HIST("Coll/hCollIdCounter"), -1); + } + else if (collId > 0) { + registry.fill(HIST("Coll/hCollIdCounter"), 1); + } else { + registry.fill(HIST("Coll/hCollIdCounter"), 0); + } + } + } + + PROCESS_SWITCH(UpcTrackVertexingQA, processTracksIU, "Track QA for IU tracks", false); + }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) From fe1c94aca9384ba2017c5b434be429b11224de4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrea=20Tavira=20Garc=C3=ADa?= <118979672+atavirag@users.noreply.github.com> Date: Fri, 9 Oct 2026 12:22:25 +0000 Subject: [PATCH 17/21] Add tf and collision info --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 69 ++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index 648343388d9..29f6e812c8e 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -14,10 +14,13 @@ /// \author Andrea Tavira Garcia a.tavira@cern.ch /// \author Andrea Giovanni Riffero andrea.giovanni.riffero@cern.ch +#include "Common/CCDB/EventSelectionParams.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" #include +#include +#include #include #include #include @@ -54,6 +57,19 @@ struct UpcTrackVertexingQA { Configurable etaTrackMax{"etaTrackMax", 0.9, "max. |eta| of tracks"}; Configurable nMinTpcClusters{"nMinTpcClusters", 60, "min. number of TPC clusters"}; + // services + Service ccdb; // access to database + + // variables to store run info + int runNumberBc = 0; // run number used to process BCs + int runNumberCol = 0; // run number used to process collisions + int64_t sor = 0; // best known timestamp for the start of run + int64_t orbitsPerTF = 0; // number of orbits per TF + int64_t bcSOR = 0; // first bc of the first orbit + int64_t nBCsPerTF = 0; // duration of TF in bcs + int64_t currentTF = -1; // current time frame being looked at + int64_t nTF = 0; // number of time frames in run + // Name shortenings // passed* columns are in TrackSelectionExtension; isGlobalTrack* and trackCutFlag in TrackSelection using TracksExtraSels = soa::Joininstance(), run); + sor = runInfo.sor; // in ms + auto orbitSOR = runInfo.orbitSOR; + auto orbitEOR = runInfo.orbitEOR; + orbitsPerTF = runInfo.orbitsPerTF; + bcSOR = orbitSOR * o2::constants::lhc::LHCMaxBunches; // first bc of the first orbit + nBCsPerTF = orbitsPerTF * o2::constants::lhc::LHCMaxBunches; // duration of TF in bcs + nTF = std::ceil((orbitEOR - orbitSOR) / orbitsPerTF); + } // end getRunInfo() + + //-------------------------------------------------------------------------------- + // compute Bc within the orbit + int64_t getBcWithinOrbit(int64_t globalBC) + { + return (globalBC % o2::constants::lhc::LHCMaxBunches); + } + + //-------------------------------------------------------------------------------- + // compute TF for this BC + int64_t getTimeFrame(int64_t globalBC) + { + return (globalBC - bcSOR) / nBCsPerTF; + } + // Result of every cut for one track (same order as CutLabels) template std::array getCutResults(TTrack const& track) @@ -434,8 +477,8 @@ struct UpcTrackVertexingQA { void checkMcGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) { using o2::constants::physics::Pdg; - constexpr int DaughterPdg = (species == CandSpecies::kRho) ? static_cast(PDG_t::kPiPlus) - : static_cast(PDG_t::kMuonMinus); + //constexpr int DaughterPdg = (species == CandSpecies::kRho) ? static_cast(PDG_t::kPiPlus) + // : static_cast(PDG_t::kMuonMinus); constexpr int MotherPdg = (species == CandSpecies::kRho) ? static_cast(PDG_t::kRho770_0) : static_cast(o2::constants::physics::Pdg::kJPsi); @@ -444,9 +487,9 @@ struct UpcTrackVertexingQA { registry.fill(HIST("McGen/Coll/hVtxZ"), mcCollision.posZ()); for (auto const& mcPart : mcParticles) { - if (std::abs(mcPart.pdgCode()) != DaughterPdg) { - continue; - } + //if (std::abs(mcPart.pdgCode()) != DaughterPdg) { + //continue; + //} if (mcPart.pt() < ptTrackMin || std::abs(mcPart.eta()) > etaTrackMax) { continue; } @@ -535,7 +578,7 @@ struct UpcTrackVertexingQA { - void processTracksIU(TracksExtraIU const& tracks) { + void processTracksIU(TracksExtraIU const& tracks, aod::Collisions const&, aod::BCs const&) { // track loop for (const auto& track : tracks) { @@ -553,6 +596,18 @@ struct UpcTrackVertexingQA { } else { registry.fill(HIST("Coll/hCollIdCounter"), 0); } + + if (collId < 0) { + continue; + } + + auto collision = track.collision(); + auto bc = collision.bc(); + + getRunInfo(bc.runNumber()); + //LOGF(info, "TF %ld", getTimeFrame(bc.globalBC())); + + registry.fill(HIST("Coll/hnTF"), getTimeFrame(bc.globalBC())); } } From 2eebba04f41ed4a9728e0902a810f66f6da3f71a Mon Sep 17 00:00:00 2001 From: ariffero Date: Fri, 9 Oct 2026 16:17:19 +0200 Subject: [PATCH 18/21] Clean task - use addClone to create similar hostos - use the same function to fill Trk and Trk/Coll histos - delete the cut flow and the cut flow histograms --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 456 ++++++++++------------------ 1 file changed, 167 insertions(+), 289 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index 29f6e812c8e..edad47dfcd5 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -57,6 +58,19 @@ struct UpcTrackVertexingQA { Configurable etaTrackMax{"etaTrackMax", 0.9, "max. |eta| of tracks"}; Configurable nMinTpcClusters{"nMinTpcClusters", 60, "min. number of TPC clusters"}; + // Axes (the mass axis matches the default rho window; override it for the J/psi) + ConfigurableAxis axisMass{"axisMass", {200, 0.5, 1.3}, "m_{#pi#pi} (GeV/#it{c}^{2})"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.00, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.175, 0.20, 0.25, 0.30, 0.40, 0.50}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis axisY{"axisY", {100, -1., 1.}, "Rapidity"}; + ConfigurableAxis axisPtTrk{"axisPtTrk", {80, 0.0, 0.8}, "#it{p}_{T} (GeV/#it{c})"}; + + HistogramConfigSpec hVtxZ{HistType::kTH1F, {{80, -20., 20.}}}; + HistogramConfigSpec hVtxX{HistType::kTH1F, {{50, -0.04, -0.015}}}; + HistogramConfigSpec hVtxY{HistType::kTH1F, {{60, -0.015, 0.015}}}; + HistogramConfigSpec hEtaTrk{HistType::kTH1F, {{100, -1.0, 1.0}}}; + + HistogramRegistry registry{"registry"}; + // services Service ccdb; // access to database @@ -70,6 +84,12 @@ struct UpcTrackVertexingQA { int64_t currentTF = -1; // current time frame being looked at int64_t nTF = 0; // number of time frames in run + static constexpr float MassPion = o2::constants::physics::MassPionCharged; + static constexpr float MassMuon = o2::constants::physics::MassMuon; + + // folders that contains plots for all tracks and associated tracks + static constexpr std::array TrackFolders = {"Trk/", "TrkColl/"}; + // Name shortenings // passed* columns are in TrackSelectionExtension; isGlobalTrack* and trackCutFlag in TrackSelection using TracksExtraSels = soa::Join; using TracksExtraWPidMuMc = soa::Join; using CollisionsWithMc = soa::Join; - using TracksExtraIU = soa::Join; - - static constexpr float MassPion = o2::constants::physics::MassPionCharged; - static constexpr float MassMuon = o2::constants::physics::MassMuon; - - // Ordered list of cuts. The cumulative cut flow follows this order, - // so reorder CutLabels and getCutResults together to change what "tighter" means. - static constexpr int NCuts = 8; - static constexpr std::array CutLabels = { - "all tracks", "hasTPC", "passedTPCNCls", - "passedEtaRange", "passedTPCChi2NDF", "passedITSNCls", - "passedITSChi2NDF", "hasITS"}; - - // Axes (the mass axis matches the default rho window; override it for the J/psi) - ConfigurableAxis axisMass{"axisMass", {200, 0.5, 1.3}, "m_{#pi#pi} (GeV/#it{c}^{2})"}; - ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.00, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.175, 0.20, 0.25, 0.30, 0.40, 0.50}, "#it{p}_{T} (GeV/#it{c})"}; - ConfigurableAxis axisY{"axisY", {100, -1., 1.}, "Rapidity"}; - ConfigurableAxis axisPtTrk{"axisPtTrk", {80, 0.0, 0.8}, "#it{p}_{T} (GeV/#it{c})"}; - - HistogramConfigSpec hVtxZ{HistType::kTH1F, {{80, -20., 20.}}}; - HistogramConfigSpec hVtxX{HistType::kTH1F, {{50, -0.04, -0.015}}}; - HistogramConfigSpec hVtxY{HistType::kTH1F, {{60, -0.015, 0.015}}}; - HistogramConfigSpec hEtaTrk{HistType::kTH1F, {{100, -1.0, 1.0}}}; - - HistogramRegistry registry{"registry"}; + aod::TrackSelection, aod::TrackSelectionExtension>; void init(InitContext&) { @@ -134,42 +129,12 @@ struct UpcTrackVertexingQA { registry.add("Trk/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.05, 0.05}}}); // track level (prongs of the candidate, after collision matching) - registry.add("TrkColl/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtTrk}}); - registry.add("TrkColl/hEta", ";#eta;entries", hEtaTrk); - registry.add("TrkColl/hChi2NCl", ";#chi^{2}/N_{cls} TPC;entries", {HistType::kTH1F, {{50, 0., 5.}}}); - registry.add("TrkColl/hTpcSignalVsP", ";#it{p} (GeV/#it{c});TPC d#it{E}/d#it{x}", {HistType::kTH2F, {{200, 0., 2.}, {300, 0., 300.}}}); - registry.add("TrkColl/hNSigmaVsP", ";#it{p} (GeV/#it{c});n#sigma^{TPC}", {HistType::kTH2F, {{200, 0., 2.}, {100, -10., 10.}}}); - registry.add("TrkColl/hHasIts", ";has ITS;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); - registry.add("TrkColl/hIsPvContrib", ";is PV contributor;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); - registry.add("TrkColl/hTpcNClsFound", ";N_{cls} TPC;entries", {HistType::kTH1F, {{90, 60, 150.}}}); - registry.add("TrkColl/hItsChi2NCl", ";#chi^{2}/N_{cls} ITS;entries", {HistType::kTH1F, {{100, 0., 10.}}}); - registry.add("TrkColl/hItsNCls", ";N_{cls} ITS;entries", {HistType::kTH1F, {{8, -0.5, 7.5}}}); - registry.add("TrkColl/hItsNClsInnerBarrel", ";N_{cls} ITS Inner Barrel;entries", {HistType::kTH1F, {{4, -0.5, 3.5}}}); - registry.add("TrkColl/hDcaXY", ";DCA_{xy} (cm);entries", {HistType::kTH1F, {{140, -0.035, 0.035}}}); - registry.add("TrkColl/hDcaZ", ";DCA_{z} (cm);entries", {HistType::kTH1F, {{200, -0.05, 0.05}}}); - + registry.addClone("Trk/", "TrkColl/"); registry.add("TrkColl/hTrackSizePerEvent", ";#it{N}_{tracks} per event;entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}); // collision Id counter registry.add("Coll/hCollIdCounter", ";collision ID;entries", {HistType::kTH1F, {{3, -1.5, 1.5}}}); - // Cut flows: cumulative, single cut, and tracks per collision vs. cut step - registry.add("Cut/hCutFlowCumulative", "tracks surviving cuts applied in sequence;;entries", - HistType::kTH1F, {{NCuts, -0.5, NCuts - 0.5}}); - registry.add("Cut/hCutFlowSingle", "tracks passing each cut individually;;entries", - HistType::kTH1F, {{NCuts, -0.5, NCuts - 0.5}}); - registry.add("Cut/h2NTracksPerCollVsCut", "tracks per collision after each cumulative cut;;N_{tracks} / collision", - HistType::kTH2F, {{NCuts, -0.5, NCuts - 0.5}, {10, -0.5, 9.5}}); - - auto hCum = registry.get(HIST("Cut/hCutFlowCumulative")); - auto hSingle = registry.get(HIST("Cut/hCutFlowSingle")); - auto hPerColl = registry.get(HIST("Cut/h2NTracksPerCollVsCut")); - for (int i = 0; i < NCuts; ++i) { - hCum->GetXaxis()->SetBinLabel(i + 1, CutLabels[i]); - hSingle->GetXaxis()->SetBinLabel(i + 1, CutLabels[i]); - hPerColl->GetXaxis()->SetBinLabel(i + 1, CutLabels[i]); - } - // candidate level plots registry.add("Cand/hMass", ";m_{#pi#pi} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}); registry.add("Cand/hPt", ";#it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); @@ -184,51 +149,36 @@ struct UpcTrackVertexingQA { } // MC reco matched plots - registry.add("Matched/Cand/hMass", ";m_{#pi#pi}^{MC} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {axisMass}}); - registry.add("Matched/Cand/hMcPt", ";#it{p}_{T}^{MC} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); - registry.add("Matched/Cand/hMcRapidity", ";#it{y}^{MC};entries", {HistType::kTH1F, {axisY}}); - registry.add("Matched/Cand/hPtVsRapidity", ";#it{p}_{T}^{MC matched} (GeV/#it{c});#it{y}^{MC}", {HistType::kTH2F, {axisPt, axisY}}); + registry.addClone("Cand/", "Matched/Cand/"); - registry.add("Matched/Coll/hNContrib", ";N_{PV contributors}^{MC matched};entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}); - registry.add("Matched/Coll/hVtxX", ";#it{x}_{vtx}^{MC matched} (cm);entries", hVtxX); - registry.add("Matched/Coll/hVtxY", ";#it{y}_{vtx}^{MC matched} (cm);entries", hVtxY); - registry.add("Matched/Coll/hVtxZ", ";#it{z}_{vtx}^{MC matched} (cm);entries", hVtxZ); + registry.addClone("Coll/hNContrib", "Matched/Coll/hNContrib"); + registry.addClone("Coll/hVtxZ", "Matched/Coll/hVtxZ"); + registry.addClone("Coll/hVtxX", "Matched/Coll/hVtxX"); + registry.addClone("Coll/hVtxY", "Matched/Coll/hVtxY"); registry.add("Matched/Trk/hPt", ";#it{p}_{T}^{MC matched} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtTrk}}); registry.add("Matched/Trk/hEta", ";#eta^{MC};entries", hEtaTrk); registry.add("Matched/Trk/hMcIsPhysicalPrimary", ";is physical primary;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); registry.add("Matched/Trk/hMotherPdg", ";mother PDG code;entries", {HistType::kTH1F, {{1001, 0.5, 1000.5}}}); - registry.add("Matched/TrkColl/hPt", ";#it{p}_{T}^{MC matched} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtTrk}}); - registry.add("Matched/TrkColl/hEta", ";#eta^{MC};entries", hEtaTrk); - registry.add("Matched/TrkColl/hMcIsPhysicalPrimary", ";is physical primary;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); - registry.add("Matched/TrkColl/hMotherPdg", ";mother PDG code;entries", {HistType::kTH1F, {{1001, 0.5, 1000.5}}}); - + registry.addClone("Matched/Trk/", "Matched/TrkColl/"); + // MC generated plots - registry.add("McGen/Coll/hVtxX", ";#it{x}_{vtx}^{MC} (cm);entries", hVtxX); - registry.add("McGen/Coll/hVtxY", ";#it{y}_{vtx}^{MC} (cm);entries", hVtxY); - registry.add("McGen/Coll/hVtxZ", ";#it{z}_{vtx}^{MC} (cm);entries", hVtxZ); + registry.addClone("Matched/Coll/", "McGen/Coll/"); - registry.add("McGen/Part/hPt", ";#it{p}_{T}^{MC} (GeV/#it{c});entries", {HistType::kTH1F, {axisPtTrk}}); - registry.add("McGen/Part/hEta", ";#eta^{MC};entries", hEtaTrk); - registry.add("McGen/Part/hMcIsPhysicalPrimary", ";is physical primary;entries", {HistType::kTH1F, {{2, -0.5, 1.5}}}); + registry.addClone("Matched/Trk/", "McGen/Part/"); registry.add("McGen/MotherPart/hMotherPdg", ";mother PDG code;entries", {HistType::kTH1F, {{1001, 0.5, 1000.5}}}); registry.add("McGen/MotherPart/hPt", ";#it{p}_{T}^{MC} (GeV/#it{c});entries", {HistType::kTH1F, {axisPt}}); registry.add("McGen/MotherPart/hRapidity", ";#it{y}^{MC};entries", {HistType::kTH1F, {axisY}}); registry.add("McGen/MotherPart/hPtVsRapidity", ";#it{p}_{T}^{MC} (GeV/#it{c});#it{y}^{MC}", {HistType::kTH2F, {axisPt, axisY}}); - } - template - float getNSigma(TTrack const& track) - { - if constexpr (species == CandSpecies::kRho) { - return track.tpcNSigmaPi(); - } else { - return track.tpcNSigmaMu(); - } - } + } // end init() + // FUNCTIONS: all functions defined here + + //-------------------------------------------------------------------------------- + // get info on the run, given the run number. Fills info needed to use getTimeFrame() void getRunInfo(int run) { auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(ccdb->instance(), run); @@ -239,99 +189,17 @@ struct UpcTrackVertexingQA { bcSOR = orbitSOR * o2::constants::lhc::LHCMaxBunches; // first bc of the first orbit nBCsPerTF = orbitsPerTF * o2::constants::lhc::LHCMaxBunches; // duration of TF in bcs nTF = std::ceil((orbitEOR - orbitSOR) / orbitsPerTF); - } // end getRunInfo() - - //-------------------------------------------------------------------------------- - // compute Bc within the orbit - int64_t getBcWithinOrbit(int64_t globalBC) - { - return (globalBC % o2::constants::lhc::LHCMaxBunches); } //-------------------------------------------------------------------------------- - // compute TF for this BC + // compute and return the TF for the given BC int64_t getTimeFrame(int64_t globalBC) { return (globalBC - bcSOR) / nBCsPerTF; } - // Result of every cut for one track (same order as CutLabels) - template - std::array getCutResults(TTrack const& track) - { - return {true, - track.hasTPC(), - track.passedTPCNCls(), - track.passedEtaRange(), - track.passedTPCChi2NDF(), - track.passedITSNCls(), - track.passedITSChi2NDF(), - track.hasITS()}; - } - - // Fills the cut flows for all tracks of one collision - template - void fillCutFlow(TTracks const& tracks) - { - std::array nSurvivors{}; // tracks of this collision surviving up to step i - - for (auto const& track : tracks) { - auto passed = getCutResults(track); - bool passedSoFar = true; - for (int i = 0; i < NCuts; ++i) { - if (passed[i]) { - registry.fill(HIST("Cut/hCutFlowSingle"), i); - } - passedSoFar = passedSoFar && passed[i]; - if (passedSoFar) { - registry.fill(HIST("Cut/hCutFlowCumulative"), i); - ++nSurvivors[i]; - } - } - } - - for (int i = 0; i < NCuts; ++i) { - registry.fill(HIST("Cut/h2NTracksPerCollVsCut"), i, nSurvivors[i]); - } - } - - // Basic kinematic / TPC / ITS properties of a candidate prong - template - void checkTpcTrackProperties(TTrack const& track) - { - registry.fill(HIST("TrkColl/hPt"), track.pt()); - registry.fill(HIST("TrkColl/hEta"), track.eta()); - registry.fill(HIST("TrkColl/hChi2NCl"), track.tpcChi2NCl()); - registry.fill(HIST("TrkColl/hTpcSignalVsP"), track.p(), track.tpcSignal()); - registry.fill(HIST("TrkColl/hNSigmaVsP"), track.p(), getNSigma(track)); - registry.fill(HIST("TrkColl/hHasIts"), static_cast(track.hasITS())); - registry.fill(HIST("TrkColl/hIsPvContrib"), static_cast(track.isPVContributor())); - registry.fill(HIST("TrkColl/hTpcNClsFound"), track.tpcNClsFound()); - registry.fill(HIST("TrkColl/hItsChi2NCl"), track.itsChi2NCl()); - registry.fill(HIST("TrkColl/hItsNCls"), track.itsNCls()); - registry.fill(HIST("TrkColl/hItsNClsInnerBarrel"), track.itsNClsInnerBarrel()); - registry.fill(HIST("TrkColl/hDcaXY"), track.dcaXY()); - registry.fill(HIST("TrkColl/hDcaZ"), track.dcaZ()); - - if constexpr (isMc) { - if (!track.has_mcParticle()) { - return; - } - auto mcPart = track.mcParticle(); - registry.fill(HIST("Matched/TrkColl/hPt"), mcPart.pt()); - registry.fill(HIST("Matched/TrkColl/hEta"), mcPart.eta()); - registry.fill(HIST("Matched/TrkColl/hMcIsPhysicalPrimary"), static_cast(mcPart.isPhysicalPrimary())); - if (mcPart.has_mothers()) { - for (auto const& mcMother : mcPart.template mothers_as()) { - registry.fill(HIST("Matched/TrkColl/hMotherPdg"), std::abs(mcMother.pdgCode())); - } - } - } - - // TODO: ambiguity (aod::AmbiguousTracks), ... - } - - // Basic single-track selection used to build the candidate + //-------------------------------------------------------------------------------- + // Basic single-track selection template bool isGoodTrack(TTrack const& track) { @@ -350,53 +218,73 @@ struct UpcTrackVertexingQA { return true; } - // Loop on tracks before grouping by collision - template - void fillTrackPlotsBeforeGrouping(TTrack const& tracks) + //-------------------------------------------------------------------------------- + // Select the PID column at compile time + template + float getNSigma(TTrack const& track) { - for (auto const& track : tracks) { - // select good tracks for the candidate - if (!isGoodTrack(track)) { - continue; - } + if constexpr (species == CandSpecies::kRho) { + return track.tpcNSigmaPi(); + } else { + return track.tpcNSigmaMu(); + } + } - //LOGF(info, "Track DCA z: %f", track.dcaZ()); - //LOGF(info, "Track DCA xy: %f", track.dcaXY()); - - registry.fill(HIST("Trk/hPt"), track.pt()); - registry.fill(HIST("Trk/hEta"), track.eta()); - registry.fill(HIST("Trk/hChi2NCl"), track.tpcChi2NCl()); - registry.fill(HIST("Trk/hTpcSignalVsP"), track.p(), track.tpcSignal()); - registry.fill(HIST("Trk/hNSigmaVsP"), track.p(), getNSigma(track)); - registry.fill(HIST("Trk/hHasIts"), static_cast(track.hasITS())); - registry.fill(HIST("Trk/hIsPvContrib"), static_cast(track.isPVContributor())); - registry.fill(HIST("Trk/hTpcNClsFound"), track.tpcNClsFound()); - registry.fill(HIST("Trk/hItsChi2NCl"), track.itsChi2NCl()); - registry.fill(HIST("Trk/hItsNCls"), track.itsNCls()); - registry.fill(HIST("Trk/hItsNClsInnerBarrel"), track.itsNClsInnerBarrel()); - registry.fill(HIST("Trk/hDcaXY"), track.dcaXY()); - registry.fill(HIST("Trk/hDcaZ"), track.dcaZ()); - - if constexpr (isMc) { - if (!track.has_mcParticle()) { - continue; - } - auto mcPart = track.mcParticle(); - registry.fill(HIST("Matched/Trk/hPt"), mcPart.pt()); - registry.fill(HIST("Matched/Trk/hEta"), mcPart.eta()); - registry.fill(HIST("Matched/Trk/hMcIsPhysicalPrimary"), static_cast(mcPart.isPhysicalPrimary())); - if (mcPart.has_mothers()) { - for (auto const& mcMother : mcPart.template mothers_as()) { - registry.fill(HIST("Matched/Trk/hMotherPdg"), std::abs(mcMother.pdgCode())); - } + //-------------------------------------------------------------------------------- + // fills the histograms with info on track properties + // works for both all and associated tracks, and if MC is available or not + template + void fillTrackHistograms(TTrack const& track) + { + // fill the histos only for good tracks + if (!isGoodTrack(track)) { + return; + } + + registry.fill(HIST(TrackFolders[folder]) + HIST("hPt"), track.pt()); + registry.fill(HIST(TrackFolders[folder]) + HIST("hEta"), track.eta()); + registry.fill(HIST(TrackFolders[folder]) + HIST("hChi2NCl"), track.tpcChi2NCl()); + registry.fill(HIST(TrackFolders[folder]) + HIST("hTpcSignalVsP"), track.p(), track.tpcSignal()); + registry.fill(HIST(TrackFolders[folder]) + HIST("hNSigmaVsP"), track.p(), getNSigma(track)); + registry.fill(HIST(TrackFolders[folder]) + HIST("hHasIts"), static_cast(track.hasITS())); + registry.fill(HIST(TrackFolders[folder]) + HIST("hIsPvContrib"), static_cast(track.isPVContributor())); + registry.fill(HIST(TrackFolders[folder]) + HIST("hTpcNClsFound"), track.tpcNClsFound()); + registry.fill(HIST(TrackFolders[folder]) + HIST("hItsChi2NCl"), track.itsChi2NCl()); + registry.fill(HIST(TrackFolders[folder]) + HIST("hItsNCls"), track.itsNCls()); + registry.fill(HIST(TrackFolders[folder]) + HIST("hItsNClsInnerBarrel"), track.itsNClsInnerBarrel()); + registry.fill(HIST(TrackFolders[folder]) + HIST("hDcaXY"), track.dcaXY()); + registry.fill(HIST(TrackFolders[folder]) + HIST("hDcaZ"), track.dcaZ()); + + // if the MC info are available, fill the corresponding histograms + if constexpr (isMc) { + if (!track.has_mcParticle()) { + return; + } + auto mcPart = track.template mcParticle_as(); + registry.fill(HIST("Matched/") + HIST(TrackFolders[folder]) + HIST("hPt"), mcPart.pt()); + registry.fill(HIST("Matched/") + HIST(TrackFolders[folder]) + HIST("hEta"), mcPart.eta()); + registry.fill(HIST("Matched/") + HIST(TrackFolders[folder]) + HIST("hMcIsPhysicalPrimary"), static_cast(mcPart.isPhysicalPrimary())); + if (mcPart.has_mothers()) { + for (auto const& mcMother : mcPart.template mothers_as()) { + registry.fill(HIST("Matched/") + HIST(TrackFolders[folder]) + HIST("hMotherPdg"), std::abs(mcMother.pdgCode())); } } } } - // Tracks are grouped by collision automatically + //-------------------------------------------------------------------------------- + // loop over tracks and fill the histograms with info on track properties + template + void loopOverTracksBeforeGrouping(TTrack const& tracks){ + for (auto const& track : tracks) { + fillTrackHistograms(track); + } + } + + //-------------------------------------------------------------------------------- + // fills the histograms with info on candidate properties template - void checkCandidateTracks(TCollision const& collision, TTrack const& tracks, float candMass) + void fillCandidateHistograms(TCollision const& collision, TTrack const& tracks, float candMass) { registry.fill(HIST("Coll/hNContrib"), collision.numContrib()); registry.fill(HIST("Coll/hBCid"), collision.bcId()); @@ -406,7 +294,7 @@ struct UpcTrackVertexingQA { registry.fill(HIST("Coll/hVtxChi2"), collision.chi2()); if constexpr (isMc) { if (collision.has_mcCollision()) { - auto mcColl = collision.mcCollision(); + auto mcColl = collision.template mcCollision_as(); registry.fill(HIST("Matched/Coll/hNContrib"), collision.numContrib()); registry.fill(HIST("Matched/Coll/hVtxX"), mcColl.posX()); registry.fill(HIST("Matched/Coll/hVtxY"), mcColl.posY()); @@ -414,9 +302,6 @@ struct UpcTrackVertexingQA { } } - // Sequential ITS/TPC cuts on ALL tracks of the collision - fillCutFlow(tracks); - // Select tracks for the candidate std::vector goodTracks; for (auto const& track : tracks) { @@ -425,13 +310,14 @@ struct UpcTrackVertexingQA { if (!track.has_collision()) { continue; } - checkTpcTrackProperties(track); + // use TrkColl directory + fillTrackHistograms(track); } } registry.fill(HIST("TrkColl/hTrackSizePerEvent"), goodTracks.size()); - // Exactly two tracks with opposite charge -> candidate + // build UPC candidates using events with exactly two opposite sign good tracks if (goodTracks.size() != 2) { return; } @@ -445,10 +331,6 @@ struct UpcTrackVertexingQA { ROOT::Math::PxPyPzMVector p1(track1.px(), track1.py(), track1.pz(), candMass); auto candidate = p0 + p1; - if (candidate.Pt() < ptCandMin || std::abs(candidate.Rapidity()) > yCandMax) { - return; - } - registry.fill(HIST("Cand/hMass"), candidate.M()); registry.fill(HIST("Cand/hPt"), candidate.Pt()); registry.fill(HIST("Cand/hRapidity"), candidate.Rapidity()); @@ -456,40 +338,31 @@ struct UpcTrackVertexingQA { if constexpr (isMc) { if (track0.has_mcParticle() && track1.has_mcParticle()) { - auto mcPart0 = track0.mcParticle(); - auto mcPart1 = track1.mcParticle(); + auto mcPart0 = track0.template mcParticle_as(); + auto mcPart1 = track1.template mcParticle_as(); ROOT::Math::PxPyPzMVector mcP0(mcPart0.px(), mcPart0.py(), mcPart0.pz(), candMass); ROOT::Math::PxPyPzMVector mcP1(mcPart1.px(), mcPart1.py(), mcPart1.pz(), candMass); auto mcCandidate = mcP0 + mcP1; registry.fill(HIST("Matched/Cand/hMass"), mcCandidate.M()); - registry.fill(HIST("Matched/Cand/hMcPt"), mcCandidate.Pt()); - registry.fill(HIST("Matched/Cand/hMcRapidity"), mcCandidate.Rapidity()); + registry.fill(HIST("Matched/Cand/hPt"), mcCandidate.Pt()); + registry.fill(HIST("Matched/Cand/hRapidity"), mcCandidate.Rapidity()); registry.fill(HIST("Matched/Cand/hPtVsRapidity"), mcCandidate.Pt(), mcCandidate.Rapidity()); } } - - //checkTpcTrackProperties(track0); - //checkTpcTrackProperties(track1); } - // Generated (MC truth) level: daughters and their mothers + //-------------------------------------------------------------------------------- + // generated (MC truth) level: daughters and their mothers template void checkMcGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) { - using o2::constants::physics::Pdg; - //constexpr int DaughterPdg = (species == CandSpecies::kRho) ? static_cast(PDG_t::kPiPlus) - // : static_cast(PDG_t::kMuonMinus); - constexpr int MotherPdg = (species == CandSpecies::kRho) ? static_cast(PDG_t::kRho770_0) - : static_cast(o2::constants::physics::Pdg::kJPsi); + constexpr int MotherPdg = species == CandSpecies::kRho ? 113 : 443; registry.fill(HIST("McGen/Coll/hVtxX"), mcCollision.posX()); registry.fill(HIST("McGen/Coll/hVtxY"), mcCollision.posY()); registry.fill(HIST("McGen/Coll/hVtxZ"), mcCollision.posZ()); for (auto const& mcPart : mcParticles) { - //if (std::abs(mcPart.pdgCode()) != DaughterPdg) { - //continue; - //} if (mcPart.pt() < ptTrackMin || std::abs(mcPart.eta()) > etaTrackMax) { continue; } @@ -514,55 +387,97 @@ struct UpcTrackVertexingQA { } } - // Process functions + //-------------------------------------------------------------------------------- + // PROCESS FUNCTIONS + //-------------------------------------------------------------------------------- + + //-------------------------------------------------------------------------------- + // check collisionId and TF + void processTracksIU(TracksExtraIU const& tracks, aod::Collisions const&, aod::BCs const&) { + // track loop + for (const auto& track : tracks) { + + if (!isGoodTrack(track)) { + continue; + } + + int32_t collId = track.collisionId(); + + if (collId < 0) { + registry.fill(HIST("Coll/hCollIdCounter"), -1); + } + else if (collId > 0) { + registry.fill(HIST("Coll/hCollIdCounter"), 1); + } else { + registry.fill(HIST("Coll/hCollIdCounter"), 0); + } + + if (collId < 0) { + continue; + } + + auto collision = track.collision(); + auto bc = collision.bc(); + + getRunInfo(bc.runNumber()); + + registry.fill(HIST("Coll/hnTF"), getTimeFrame(bc.globalBC())); + } + } + + // look at all tracks void processRhoTracksBeforeGrouping(TracksExtraWPidPi const& tracks) { - fillTrackPlotsBeforeGrouping(tracks); + loopOverTracksBeforeGrouping(tracks); } PROCESS_SWITCH(UpcTrackVertexingQA, processRhoTracksBeforeGrouping, "Process rho tracks before asking for collisions", true); void processJpsiTracksBeforeGrouping(TracksExtraWPidMu const& tracks) { - fillTrackPlotsBeforeGrouping(tracks); + loopOverTracksBeforeGrouping(tracks); } PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiTracksBeforeGrouping, "Process J/Psi tracks before asking for collisions", false); void processRhoTracksBeforeGroupingMcInfo(TracksExtraWPidPiMc const& tracks, aod::McParticles const&) { - fillTrackPlotsBeforeGrouping(tracks); + loopOverTracksBeforeGrouping(tracks); } - PROCESS_SWITCH(UpcTrackVertexingQA, processRhoTracksBeforeGroupingMcInfo, "Process rho tracks before asking for collisions, ask for MC info", false); + PROCESS_SWITCH(UpcTrackVertexingQA, processRhoTracksBeforeGroupingMcInfo, "Process rho tracks before asking for collisions", false); void processJpsiTracksBeforeGroupingMcInfo(TracksExtraWPidMuMc const& tracks, aod::McParticles const&) { - fillTrackPlotsBeforeGrouping(tracks); + loopOverTracksBeforeGrouping(tracks); } - PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiTracksBeforeGroupingMcInfo, "Process J/Psi tracks before asking for collisions, ask for MC info", false); + PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiTracksBeforeGroupingMcInfo, "Process J/Psi tracks before asking for collisions", false); + // look at matched tracks void processRhoCand(aod::Collision const& collision, TracksExtraWPidPi const& tracks) { - checkCandidateTracks(collision, tracks, MassPion); + fillCandidateHistograms(collision, tracks, MassPion); } PROCESS_SWITCH(UpcTrackVertexingQA, processRhoCand, "Rho -> pi pi candidates and track QA", true); void processJpsiCand(aod::Collision const& collision, TracksExtraWPidMu const& tracks) { - checkCandidateTracks(collision, tracks, MassMuon); + fillCandidateHistograms(collision, tracks, MassMuon); } PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiCand, "J/Psi -> mu mu candidates and track QA", false); - void processRhoCandMcInfo(CollisionsWithMc::iterator const& collision, aod::McCollisions const&, TracksExtraWPidPiMc const& tracks, aod::McParticles const&) + void processRhoCandMcInfo(CollisionsWithMc::iterator const& collision, TracksExtraWPidPiMc const& tracks, + aod::McParticles const&, aod::McCollisions const&) { - checkCandidateTracks(collision, tracks, MassPion); + fillCandidateHistograms(collision, tracks, MassPion); } - PROCESS_SWITCH(UpcTrackVertexingQA, processRhoCandMcInfo, "Rho -> pi pi candidates and track QA, ask for MC info", false); + PROCESS_SWITCH(UpcTrackVertexingQA, processRhoCandMcInfo, "Rho -> pi pi candidates and track QA", false); - void processJpsiCandMcInfo(CollisionsWithMc::iterator const& collision, aod::McCollisions const&, TracksExtraWPidMuMc const& tracks, aod::McParticles const&) + void processJpsiCandMcInfo(CollisionsWithMc::iterator const& collision, TracksExtraWPidMuMc const& tracks, + aod::McParticles const&, aod::McCollisions const&) { - checkCandidateTracks(collision, tracks, MassMuon); + fillCandidateHistograms(collision, tracks, MassMuon); } - PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiCandMcInfo, "J/Psi -> mu mu candidates and track QA, ask for MC info", false); + PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiCandMcInfo, "J/Psi -> mu mu candidates and track QA", false); + // look at gen MC void processMcGenRho(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) { checkMcGen(mcCollision, mcParticles); @@ -575,47 +490,10 @@ struct UpcTrackVertexingQA { } PROCESS_SWITCH(UpcTrackVertexingQA, processMcGenJpsi, "Generated J/Psi -> mu mu", false); - - - - void processTracksIU(TracksExtraIU const& tracks, aod::Collisions const&, aod::BCs const&) { - // track loop - for (const auto& track : tracks) { - - if (!isGoodTrack(track)) { - continue; - } - - int32_t collId = track.collisionId(); - - if (collId < 0) { - registry.fill(HIST("Coll/hCollIdCounter"), -1); - } - else if (collId > 0) { - registry.fill(HIST("Coll/hCollIdCounter"), 1); - } else { - registry.fill(HIST("Coll/hCollIdCounter"), 0); - } - - if (collId < 0) { - continue; - } - - auto collision = track.collision(); - auto bc = collision.bc(); - - getRunInfo(bc.runNumber()); - //LOGF(info, "TF %ld", getTimeFrame(bc.globalBC())); - - registry.fill(HIST("Coll/hnTF"), getTimeFrame(bc.globalBC())); - } - } - PROCESS_SWITCH(UpcTrackVertexingQA, processTracksIU, "Track QA for IU tracks", false); - }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} +} \ No newline at end of file From 642a45e2c5c23a79dfd4542e8747ed68036698f0 Mon Sep 17 00:00:00 2001 From: ariffero Date: Tue, 13 Oct 2026 11:24:19 +0200 Subject: [PATCH 19/21] Fix McGen process function + cleaning - change function for gen MC, now process functions are different for embedded and exclusive MC - fix o2linter warnings --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 88 +++++++++++++++++++---------- 1 file changed, 57 insertions(+), 31 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index edad47dfcd5..955b5d018e5 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -84,6 +84,10 @@ struct UpcTrackVertexingQA { int64_t currentTF = -1; // current time frame being looked at int64_t nTF = 0; // number of time frames in run + // constants + const unsigned int twoTracks = 2; + const int unassignedDCA = 999; + static constexpr float MassPion = o2::constants::physics::MassPionCharged; static constexpr float MassMuon = o2::constants::physics::MassMuon; @@ -143,7 +147,7 @@ struct UpcTrackVertexingQA { // MC histograms are only booked if at least one MC process function is enabled const bool needMc = doprocessRhoTracksBeforeGroupingMcInfo || doprocessJpsiTracksBeforeGroupingMcInfo || - doprocessRhoCandMcInfo || doprocessJpsiCandMcInfo || doprocessMcGenRho || doprocessMcGenJpsi; + doprocessRhoCandMcInfo || doprocessJpsiCandMcInfo || doprocessMcGenExclusive || doprocessMcGenEmbedded; if (!needMc) { return; } @@ -173,6 +177,8 @@ struct UpcTrackVertexingQA { registry.add("McGen/MotherPart/hRapidity", ";#it{y}^{MC};entries", {HistType::kTH1F, {axisY}}); registry.add("McGen/MotherPart/hPtVsRapidity", ";#it{p}_{T}^{MC} (GeV/#it{c});#it{y}^{MC}", {HistType::kTH2F, {axisPt, axisY}}); + registry.addClone("TrkColl/hTrackSizePerEvent", "McGen/Part/hTrackSizePerEvent"); + } // end init() // FUNCTIONS: all functions defined here @@ -212,7 +218,7 @@ struct UpcTrackVertexingQA { if (track.pt() < ptTrackMin || std::abs(track.eta()) > etaTrackMax) { return false; } - if (std::abs(track.dcaZ()) >= 999 || std::abs(track.dcaXY()) >= 999) { + if (std::abs(track.dcaZ()) >= unassignedDCA || std::abs(track.dcaXY()) >= unassignedDCA) { return false; } return true; @@ -307,9 +313,6 @@ struct UpcTrackVertexingQA { for (auto const& track : tracks) { if (isGoodTrack(track)) { goodTracks.push_back(track); - if (!track.has_collision()) { - continue; - } // use TrkColl directory fillTrackHistograms(track); } @@ -318,7 +321,7 @@ struct UpcTrackVertexingQA { registry.fill(HIST("TrkColl/hTrackSizePerEvent"), goodTracks.size()); // build UPC candidates using events with exactly two opposite sign good tracks - if (goodTracks.size() != 2) { + if (goodTracks.size() != twoTracks) { return; } auto const& track0 = goodTracks[0]; @@ -353,38 +356,61 @@ struct UpcTrackVertexingQA { //-------------------------------------------------------------------------------- // generated (MC truth) level: daughters and their mothers - template - void checkMcGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) - { - constexpr int MotherPdg = species == CandSpecies::kRho ? 113 : 443; + template + void checkMcGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles){ registry.fill(HIST("McGen/Coll/hVtxX"), mcCollision.posX()); registry.fill(HIST("McGen/Coll/hVtxY"), mcCollision.posY()); registry.fill(HIST("McGen/Coll/hVtxZ"), mcCollision.posZ()); + std::vector goodMcGenParticles; for (auto const& mcPart : mcParticles) { - if (mcPart.pt() < ptTrackMin || std::abs(mcPart.eta()) > etaTrackMax) { - continue; + + if (!mcPart.isPhysicalPrimary() || mcPart.pt() < ptTrackMin || std::abs(mcPart.eta()) > etaTrackMax) { + continue; } - registry.fill(HIST("McGen/Part/hPt"), mcPart.pt()); registry.fill(HIST("McGen/Part/hEta"), mcPart.eta()); - registry.fill(HIST("McGen/Part/hMcIsPhysicalPrimary"), static_cast(mcPart.isPhysicalPrimary())); + + goodMcGenParticles.push_back(mcPart); + } + registry.fill(HIST("McGen/Part/hTrackSizePerEvent"), goodMcGenParticles.size()); - if (!mcPart.has_mothers()) { - continue; + // consider only j/psi->mumu and rho->pipi events + auto genId = mcCollision.getGeneratorId(); + LOGF(info, "Gen Id: {%d}", genId); + auto sourceId = mcCollision.getSourceId(); + LOGF(info, "Source Id: {%d}", sourceId); + + if constexpr (isEmbedded) { + if (!sourceId) { + return; } - for (auto const& mcMother : mcPart.template mothers_as()) { - registry.fill(HIST("McGen/MotherPart/hMotherPdg"), std::abs(mcMother.pdgCode())); - - // fill the mother once, not once per daughter: only via the positive-PDG prong - if (std::abs(mcMother.pdgCode()) == MotherPdg && mcPart.pdgCode() > 0) { - registry.fill(HIST("McGen/MotherPart/hPt"), mcMother.pt()); - registry.fill(HIST("McGen/MotherPart/hRapidity"), mcMother.y()); - registry.fill(HIST("McGen/MotherPart/hPtVsRapidity"), mcMother.pt(), mcMother.y()); - } + } else { + if (sourceId) { + LOGF(fatal, "Source Id: {%d} is not zero for non-embedded MC", sourceId); + return; } } + + if (goodMcGenParticles.size() != twoTracks) { + return; + } + + // we have 2 good tracks, with the same mother, taking it from the first one + auto mothers = goodMcGenParticles[0].template mothers_as(); + + if (mothers.empty()) { + LOGF(fatal, "Selected particle has no mother: pdgCode=%d", goodMcGenParticles[0].pdgCode()); + return; + } + auto motherPart = mothers[0]; + + registry.fill(HIST("McGen/MotherPart/hMotherPdg"), std::abs(motherPart.pdgCode())); + registry.fill(HIST("McGen/MotherPart/hPt"), motherPart.pt()); + registry.fill(HIST("McGen/MotherPart/hRapidity"), motherPart.y()); + registry.fill(HIST("McGen/MotherPart/hPtVsRapidity"), motherPart.pt(), motherPart.y()); + } //-------------------------------------------------------------------------------- @@ -478,17 +504,17 @@ struct UpcTrackVertexingQA { PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiCandMcInfo, "J/Psi -> mu mu candidates and track QA", false); // look at gen MC - void processMcGenRho(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + void processMcGenEmbedded(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) { - checkMcGen(mcCollision, mcParticles); + checkMcGen(mcCollision, mcParticles); } - PROCESS_SWITCH(UpcTrackVertexingQA, processMcGenRho, "Generated rho -> pi pi", false); + PROCESS_SWITCH(UpcTrackVertexingQA, processMcGenEmbedded, "Generated embedded events", false); - void processMcGenJpsi(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + void processMcGenExclusive(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) { - checkMcGen(mcCollision, mcParticles); + checkMcGen(mcCollision, mcParticles); } - PROCESS_SWITCH(UpcTrackVertexingQA, processMcGenJpsi, "Generated J/Psi -> mu mu", false); + PROCESS_SWITCH(UpcTrackVertexingQA, processMcGenExclusive, "Generated exclusive events", false); PROCESS_SWITCH(UpcTrackVertexingQA, processTracksIU, "Track QA for IU tracks", false); }; From ea055e842a63f48e501d33d26dd20ca06f4d3cb5 Mon Sep 17 00:00:00 2001 From: ariffero Date: Tue, 13 Oct 2026 16:59:28 +0200 Subject: [PATCH 20/21] Add plots for ambiguous tracks --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index 955b5d018e5..78287aa4832 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -92,7 +92,7 @@ struct UpcTrackVertexingQA { static constexpr float MassMuon = o2::constants::physics::MassMuon; // folders that contains plots for all tracks and associated tracks - static constexpr std::array TrackFolders = {"Trk/", "TrkColl/"}; + static constexpr std::array TrackFolders = {"Trk/", "TrkColl/", "TrkAmb/"}; // Name shortenings // passed* columns are in TrackSelectionExtension; isGlobalTrack* and trackCutFlag in TrackSelection @@ -136,6 +136,9 @@ struct UpcTrackVertexingQA { registry.addClone("Trk/", "TrkColl/"); registry.add("TrkColl/hTrackSizePerEvent", ";#it{N}_{tracks} per event;entries", {HistType::kTH1F, {{10, -0.5, 9.5}}}); + // track level plots for ambiguous tracks + registry.addClone("Trk/", "TrkAmb/"); + // collision Id counter registry.add("Coll/hCollIdCounter", ";collision ID;entries", {HistType::kTH1F, {{3, -1.5, 1.5}}}); @@ -280,10 +283,14 @@ struct UpcTrackVertexingQA { //-------------------------------------------------------------------------------- // loop over tracks and fill the histograms with info on track properties - template + template void loopOverTracksBeforeGrouping(TTrack const& tracks){ for (auto const& track : tracks) { - fillTrackHistograms(track); + int32_t collId = track.collisionId(); + fillTrackHistograms(track); + if (collId < 0) { + fillTrackHistograms(track); // isMc always false here since it fills Matched/.. histos + } } } @@ -454,25 +461,25 @@ struct UpcTrackVertexingQA { // look at all tracks void processRhoTracksBeforeGrouping(TracksExtraWPidPi const& tracks) { - loopOverTracksBeforeGrouping(tracks); + loopOverTracksBeforeGrouping(tracks); } PROCESS_SWITCH(UpcTrackVertexingQA, processRhoTracksBeforeGrouping, "Process rho tracks before asking for collisions", true); void processJpsiTracksBeforeGrouping(TracksExtraWPidMu const& tracks) { - loopOverTracksBeforeGrouping(tracks); + loopOverTracksBeforeGrouping(tracks); } PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiTracksBeforeGrouping, "Process J/Psi tracks before asking for collisions", false); void processRhoTracksBeforeGroupingMcInfo(TracksExtraWPidPiMc const& tracks, aod::McParticles const&) { - loopOverTracksBeforeGrouping(tracks); + loopOverTracksBeforeGrouping(tracks); } PROCESS_SWITCH(UpcTrackVertexingQA, processRhoTracksBeforeGroupingMcInfo, "Process rho tracks before asking for collisions", false); void processJpsiTracksBeforeGroupingMcInfo(TracksExtraWPidMuMc const& tracks, aod::McParticles const&) { - loopOverTracksBeforeGrouping(tracks); + loopOverTracksBeforeGrouping(tracks); } PROCESS_SWITCH(UpcTrackVertexingQA, processJpsiTracksBeforeGroupingMcInfo, "Process J/Psi tracks before asking for collisions", false); From 09834011dc0a88c586938604dcf23091124e1bf4 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Tue, 13 Oct 2026 15:27:01 +0000 Subject: [PATCH 21/21] Please consider the following formatting changes --- PWGUD/Tasks/upcTrackVertexingQA.cxx | 33 +++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/PWGUD/Tasks/upcTrackVertexingQA.cxx b/PWGUD/Tasks/upcTrackVertexingQA.cxx index 78287aa4832..7dc4be7bbc6 100644 --- a/PWGUD/Tasks/upcTrackVertexingQA.cxx +++ b/PWGUD/Tasks/upcTrackVertexingQA.cxx @@ -18,8 +18,8 @@ #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include #include +#include #include #include #include @@ -36,8 +36,8 @@ #include #include -#include #include +#include #include #include @@ -169,7 +169,7 @@ struct UpcTrackVertexingQA { registry.add("Matched/Trk/hMotherPdg", ";mother PDG code;entries", {HistType::kTH1F, {{1001, 0.5, 1000.5}}}); registry.addClone("Matched/Trk/", "Matched/TrkColl/"); - + // MC generated plots registry.addClone("Matched/Coll/", "McGen/Coll/"); @@ -284,7 +284,8 @@ struct UpcTrackVertexingQA { //-------------------------------------------------------------------------------- // loop over tracks and fill the histograms with info on track properties template - void loopOverTracksBeforeGrouping(TTrack const& tracks){ + void loopOverTracksBeforeGrouping(TTrack const& tracks) + { for (auto const& track : tracks) { int32_t collId = track.collisionId(); fillTrackHistograms(track); @@ -364,7 +365,8 @@ struct UpcTrackVertexingQA { //-------------------------------------------------------------------------------- // generated (MC truth) level: daughters and their mothers template - void checkMcGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles){ + void checkMcGen(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + { registry.fill(HIST("McGen/Coll/hVtxX"), mcCollision.posX()); registry.fill(HIST("McGen/Coll/hVtxY"), mcCollision.posY()); @@ -372,13 +374,13 @@ struct UpcTrackVertexingQA { std::vector goodMcGenParticles; for (auto const& mcPart : mcParticles) { - + if (!mcPart.isPhysicalPrimary() || mcPart.pt() < ptTrackMin || std::abs(mcPart.eta()) > etaTrackMax) { - continue; + continue; } registry.fill(HIST("McGen/Part/hPt"), mcPart.pt()); registry.fill(HIST("McGen/Part/hEta"), mcPart.eta()); - + goodMcGenParticles.push_back(mcPart); } registry.fill(HIST("McGen/Part/hTrackSizePerEvent"), goodMcGenParticles.size()); @@ -399,12 +401,12 @@ struct UpcTrackVertexingQA { return; } } - + if (goodMcGenParticles.size() != twoTracks) { return; } - // we have 2 good tracks, with the same mother, taking it from the first one + // we have 2 good tracks, with the same mother, taking it from the first one auto mothers = goodMcGenParticles[0].template mothers_as(); if (mothers.empty()) { @@ -417,7 +419,6 @@ struct UpcTrackVertexingQA { registry.fill(HIST("McGen/MotherPart/hPt"), motherPart.pt()); registry.fill(HIST("McGen/MotherPart/hRapidity"), motherPart.y()); registry.fill(HIST("McGen/MotherPart/hPtVsRapidity"), motherPart.pt(), motherPart.y()); - } //-------------------------------------------------------------------------------- @@ -426,7 +427,8 @@ struct UpcTrackVertexingQA { //-------------------------------------------------------------------------------- // check collisionId and TF - void processTracksIU(TracksExtraIU const& tracks, aod::Collisions const&, aod::BCs const&) { + void processTracksIU(TracksExtraIU const& tracks, aod::Collisions const&, aod::BCs const&) + { // track loop for (const auto& track : tracks) { @@ -438,8 +440,7 @@ struct UpcTrackVertexingQA { if (collId < 0) { registry.fill(HIST("Coll/hCollIdCounter"), -1); - } - else if (collId > 0) { + } else if (collId > 0) { registry.fill(HIST("Coll/hCollIdCounter"), 1); } else { registry.fill(HIST("Coll/hCollIdCounter"), 0); @@ -451,7 +452,7 @@ struct UpcTrackVertexingQA { auto collision = track.collision(); auto bc = collision.bc(); - + getRunInfo(bc.runNumber()); registry.fill(HIST("Coll/hnTF"), getTimeFrame(bc.globalBC())); @@ -529,4 +530,4 @@ struct UpcTrackVertexingQA { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; -} \ No newline at end of file +}