From c4d8fed73785f9a6128f564bfaf2c7ce141e52e1 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Mon, 6 Jul 2026 18:10:55 +0200 Subject: [PATCH 01/14] treeCreatorPidTpcQa: start dev --- DPG/Tasks/AOTTrack/PID/TPC/CMakeLists.txt | 5 + .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx | 229 ++++++++++++++++++ .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.h | 63 +++++ 3 files changed, 297 insertions(+) create mode 100644 DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx create mode 100644 DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h diff --git a/DPG/Tasks/AOTTrack/PID/TPC/CMakeLists.txt b/DPG/Tasks/AOTTrack/PID/TPC/CMakeLists.txt index 01d69f64386..2e764bde532 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/CMakeLists.txt +++ b/DPG/Tasks/AOTTrack/PID/TPC/CMakeLists.txt @@ -24,3 +24,8 @@ o2physics_add_dpl_workflow(pid-tpc-qa-mc SOURCES qaPIDTPCMC.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(tree-creator-pid-tpc-qa + SOURCES treeCreatorPidTpcQa.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx new file mode 100644 index 00000000000..b6d6bf2218a --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx @@ -0,0 +1,229 @@ +// 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 treeCreatorPidTpcQa.cxx +/// \brief Task to produce table with clean selections for TPC PID calibration +/// +/// \author Ana Marin +/// \author Oleksii Lubynets + +#include "treeCreatorPidTpcQa.h" + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "DPG/Tasks/TPC/tpcSkimsTableCreator.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::track; +using namespace o2::dpg_pidtpcqa; + +struct treeCreatorPidTpcQa { + Produces rowPidTpcQa; + + Configurable applyEvSel{"applyEvSel", 2, "Flag to apply event selection: 0 -> no event selection, 1 -> Run 2 event selection, 2 -> Run 3 event selection"}; + Configurable cutVtxZ{"cutVtxZ", 10.f, "Cut on vertex Z position [cm]. Set negative value to switch this cut off"}; + Configurable trackSelection{"trackSelection", 1, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; + Configurable requireGlobalTrack{"requireGlobalTrack", true, "Skip non-global tracks"}; + Configurable requireIts{"requireIts", true, "Skip tracks without ITS"}; + Configurable cutMinTPCNcls{"cutMinTPCNcls", 0, "Minimum number or TPC Clusters for tracks"}; + Configurable cutRapidity{"cutRapidity", 0.5, "Rapidity cut. Set negative value to switch this cut off"}; + Configurable nClNorm{"nClNorm", 152., "Number of cluster normalization. Run 2: 159, Run 3 152"}; + + using CollisionsExtra = soa::Join; + using TrackCandidates = soa::Join; + + Preslice perCollisionTracks = aod::track::collisionId; + + int mEnabledParticles{0}; + + // Track selection + template + bool isTrackSelected(const TrackType& track) + { + bool isSelected{false}; + isSelected |= trackSelection == TrackSelectionNoCut; + isSelected |= (trackSelection == TrackSelectionGlobalTrack) && track.isGlobalTrack(); + isSelected |= (trackSelection == TrackSelectionTrackWoPtEta) && track.isGlobalTrackWoPtEta(); + isSelected |= (trackSelection == TrackSelectionGlobalTrackWoDCA) && track.isGlobalTrackWoDCA(); + isSelected |= (trackSelection == TrackSelectionQualityTracks) && track.isQualityTrack(); + isSelected |= (trackSelection == TrackSelectionInAcceptanceTracks) && track.isInAcceptanceTrack(); + isSelected &= (!requireGlobalTrack || track.isGlobalTrack()); + isSelected &= (!requireIts || track.hasITS()); + isSelected &= track.hasTPC(); + isSelected &= (track.tpcNClsFound() >= cutMinTPCNcls); + + return isSelected; + } + + template + bool initPerParticle() + { + static_assert(Id >= 0 && Id <= PID::Alpha && "Particle index outside limits"); + int enabledProcesses{0}; + + switch (Id) { +#define PARTICLE_CASE(ParticleId) \ + case PID::ParticleId: \ + if (!doprocess##ParticleId && !doprocessFull##ParticleId && !doprocessFullWithTOF##ParticleId) { \ + return false; \ + } \ + if (doprocess##ParticleId) { \ + ++enabledProcesses; \ + } \ + if (doprocessFull##ParticleId) { \ + ++enabledProcesses; \ + } \ + if (doprocessFullWithTOF##ParticleId) { \ + ++enabledProcesses; \ + } \ + LOG(info) << "Enabled TPC QA for " << #ParticleId; \ + break; + + PARTICLE_CASE(Electron); + PARTICLE_CASE(Muon); + PARTICLE_CASE(Pion); + PARTICLE_CASE(Kaon); + PARTICLE_CASE(Proton); + PARTICLE_CASE(Deuteron); + PARTICLE_CASE(Triton); + PARTICLE_CASE(Helium3); + PARTICLE_CASE(Alpha); +#undef PARTICLE_CASE + } + if (enabledProcesses != 1) { + LOG(fatal) << "Cannot enable more than one process function per particle, check and retry!"; + } + return true; + } + + void init(o2::framework::InitContext&) + { + static_for<0, PID::Alpha>([&](auto Id) { + mEnabledParticles += static_cast(initPerParticle()); + }); + } + + template + void processSingleParticle(CollisionsExtra const& collisions, + TrackType const& tracks) + { + rowPidTpcQa.reserve(tracks.size() * mEnabledParticles); + + for (const auto& collision : collisions) { + if (!isEventSelected(collision, applyEvSel) || ((cutVtxZ > 0.f) && std::abs(collision.posZ()) > cutVtxZ)) { + continue; + } + + const float ft0Occ = collision.ft0cOccupancyInTimeRange(); + const float multTPC = collision.multTPC() / dpg_tpcskimstablecreator::MultiplicityNorm; + + const auto tracksFromCollision = tracks.sliceBy(perCollisionTracks, static_cast(collision.globalIndex())); + + for (const auto& track : tracksFromCollision) { + if (!isTrackSelected(track)) { + continue; + } + const float rapidity = track.rapidity(PID::getMass(Id)); + if (cutRapidity > 0.f && std::fabs(rapidity) > cutRapidity) { + continue; + } + + const int nClNormalized = std::sqrt(nClNorm / track.tpcNClsFound()); + const float phi = track.phi(); + const float tgl = track.tgl(); + const float tpcInnerParam = track.tpcInnerParam(); + + rowPidTpcQa(Id, ft0Occ, multTPC, nClNormalized, phi, tgl, tpcInnerParam, rapidity); + } // tracks + } // collisions + } + + // QA of nsigma only tables +#define MAKE_PROCESS_FUNCTION(PidTableTPC, ParticleId) \ + void process##ParticleId(CollisionsExtra const& collisions, \ + soa::Join const& tracks) \ + { \ + processSingleParticle(collisions, tracks); \ + } \ + PROCESS_SWITCH(treeCreatorPidTpcQa, process##ParticleId, Form("Process for the %s hypothesis for TPC NSigma QA", #ParticleId), false); + + MAKE_PROCESS_FUNCTION(aod::pidTPCEl, Electron); + MAKE_PROCESS_FUNCTION(aod::pidTPCMu, Muon); + MAKE_PROCESS_FUNCTION(aod::pidTPCPi, Pion); + MAKE_PROCESS_FUNCTION(aod::pidTPCKa, Kaon); + MAKE_PROCESS_FUNCTION(aod::pidTPCPr, Proton); + MAKE_PROCESS_FUNCTION(aod::pidTPCDe, Deuteron); + MAKE_PROCESS_FUNCTION(aod::pidTPCTr, Triton); + MAKE_PROCESS_FUNCTION(aod::pidTPCHe, Helium3); + MAKE_PROCESS_FUNCTION(aod::pidTPCAl, Alpha); +#undef MAKE_PROCESS_FUNCTION + +// QA of full tables +#define MAKE_PROCESS_FUNCTION(PidTableTPC, ParticleId) \ + void processFull##ParticleId(CollisionsExtra const& collisions, \ + soa::Join const& tracks) \ + { \ + processSingleParticle(collisions, tracks); \ + } \ + PROCESS_SWITCH(treeCreatorPidTpcQa, processFull##ParticleId, Form("Process for the %s hypothesis for full TPC PID QA", #ParticleId), false); + + MAKE_PROCESS_FUNCTION(aod::pidTPCFullEl, Electron); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullMu, Muon); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullPi, Pion); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullKa, Kaon); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullPr, Proton); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullDe, Deuteron); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullTr, Triton); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullHe, Helium3); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullAl, Alpha); +#undef MAKE_PROCESS_FUNCTION + + // QA of full tables with TOF information +#define MAKE_PROCESS_FUNCTION(PidTableTPC, PidTableTOF, ParticleId) \ + void processFullWithTOF##ParticleId(CollisionsExtra const& collisions, \ + soa::Join const& tracks) \ + { \ + processSingleParticle(collisions, tracks); \ + } \ + PROCESS_SWITCH(treeCreatorPidTpcQa, processFullWithTOF##ParticleId, Form("Process for the %s hypothesis for full TPC PID QA with the TOF info added", #ParticleId), false); + + MAKE_PROCESS_FUNCTION(aod::pidTPCFullEl, aod::pidTOFFullEl, Electron); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullMu, aod::pidTOFFullMu, Muon); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullPi, aod::pidTOFFullPi, Pion); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullKa, aod::pidTOFFullKa, Kaon); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullPr, aod::pidTOFFullPr, Proton); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullDe, aod::pidTOFFullDe, Deuteron); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullTr, aod::pidTOFFullTr, Triton); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullHe, aod::pidTOFFullHe, Helium3); + MAKE_PROCESS_FUNCTION(aod::pidTPCFullAl, aod::pidTOFFullAl, Alpha); +#undef MAKE_PROCESS_FUNCTION +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h new file mode 100644 index 00000000000..d5a357bea06 --- /dev/null +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h @@ -0,0 +1,63 @@ +// 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 treeCreatorPidTpcQa.h +/// \author Ana Marin +/// \author Oleksii Lubynets +/// \brief Creates trees with PID QA variables along with variables used for NN training + +#include "DPG/Tasks/TPC/tpcSkimsTableCreator.h" + +#include + +#ifndef DPG_TASKS_AOTTRACK_PID_TPC_TREECREATORPIDTPCQA_H_ +#define DPG_TASKS_AOTTRACK_PID_TPC_TREECREATORPIDTPCQA_H_ + +namespace o2::aod +{ +DECLARE_SOA_TABLE(QaPidTpc, "AOD", "QAPIDTPC", + tpcskims::PidIndex, + tpcskims::Ft0Occ, + tpcskims::NormMultTPC, + tpcskims::NormNClustersTPC, + o2::aod::track::Phi, + o2::aod::track::Tgl, + o2::aod::track::TPCInnerParam, + o2::aod::track::Y) +} // namespace o2::aod + +namespace o2::dpg_pidtpcqa +{ +enum { + TrackSelectionNoCut = 0, + TrackSelectionGlobalTrack, + TrackSelectionTrackWoPtEta, + TrackSelectionGlobalTrackWoDCA, + TrackSelectionQualityTracks, + TrackSelectionInAcceptanceTracks +}; + +enum { + EventSelectionNo = 0, + EventSelectionRun2, + EventSelectionRun3 +}; + +/// Event selection +template +bool isEventSelected(const CollisionType& collision, const int applyEvSel) +{ + return ((applyEvSel == EventSelectionRun2 && !collision.sel7()) || (applyEvSel == EventSelectionRun3 && !collision.sel8())); +} + +}; // namespace o2::dpg_pidtpcqa + +#endif // DPG_TASKS_AOTTRACK_PID_TPC_TREECREATORPIDTPCQA_H_ From 89be51e08e4db9e4f2b43dfa8fb09981815f77a1 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Wed, 8 Jul 2026 18:04:38 +0200 Subject: [PATCH 02/14] add CCDB-driven info --- DPG/Tasks/AOTTrack/PID/TPC/CMakeLists.txt | 2 +- .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx | 67 +++++++++++-------- .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.h | 34 ++-------- 3 files changed, 46 insertions(+), 57 deletions(-) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/CMakeLists.txt b/DPG/Tasks/AOTTrack/PID/TPC/CMakeLists.txt index 2e764bde532..f804cea4c51 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/CMakeLists.txt +++ b/DPG/Tasks/AOTTrack/PID/TPC/CMakeLists.txt @@ -27,5 +27,5 @@ o2physics_add_dpl_workflow(pid-tpc-qa-mc o2physics_add_dpl_workflow(tree-creator-pid-tpc-qa SOURCES treeCreatorPidTpcQa.cxx - PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx index b6d6bf2218a..9b33d5db016 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx @@ -17,13 +17,16 @@ #include "treeCreatorPidTpcQa.h" +#include "Common/CCDB/ctpRateFetcher.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" #include "DPG/Tasks/TPC/tpcSkimsTableCreator.h" +#include "DPG/Tasks/TPC/utilsTpcSkimsTableCreator.h" +#include #include #include #include @@ -35,11 +38,12 @@ #include #include +#include using namespace o2; using namespace o2::framework; using namespace o2::track; -using namespace o2::dpg_pidtpcqa; +using namespace o2::dpg_tpcskimstablecreator; struct treeCreatorPidTpcQa { Produces rowPidTpcQa; @@ -52,6 +56,12 @@ struct treeCreatorPidTpcQa { Configurable cutMinTPCNcls{"cutMinTPCNcls", 0, "Minimum number or TPC Clusters for tracks"}; Configurable cutRapidity{"cutRapidity", 0.5, "Rapidity cut. Set negative value to switch this cut off"}; Configurable nClNorm{"nClNorm", 152., "Number of cluster normalization. Run 2: 159, Run 3 152"}; + // Configurable for the path of CCDB General Run Parameters LHC Interface information + Configurable ccdbPathGrpLhcIf{"ccdbPathGrpLhcIf", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; + + Service ccdb{}; + + ctpRateFetcher mRateFetcher{}; using CollisionsExtra = soa::Join; using TrackCandidates = soa::Join; @@ -60,25 +70,6 @@ struct treeCreatorPidTpcQa { int mEnabledParticles{0}; - // Track selection - template - bool isTrackSelected(const TrackType& track) - { - bool isSelected{false}; - isSelected |= trackSelection == TrackSelectionNoCut; - isSelected |= (trackSelection == TrackSelectionGlobalTrack) && track.isGlobalTrack(); - isSelected |= (trackSelection == TrackSelectionTrackWoPtEta) && track.isGlobalTrackWoPtEta(); - isSelected |= (trackSelection == TrackSelectionGlobalTrackWoDCA) && track.isGlobalTrackWoDCA(); - isSelected |= (trackSelection == TrackSelectionQualityTracks) && track.isQualityTrack(); - isSelected |= (trackSelection == TrackSelectionInAcceptanceTracks) && track.isInAcceptanceTrack(); - isSelected &= (!requireGlobalTrack || track.isGlobalTrack()); - isSelected &= (!requireIts || track.hasITS()); - isSelected &= track.hasTPC(); - isSelected &= (track.tpcNClsFound() >= cutMinTPCNcls); - - return isSelected; - } - template bool initPerParticle() { @@ -125,6 +116,10 @@ struct treeCreatorPidTpcQa { static_for<0, PID::Alpha>([&](auto Id) { mEnabledParticles += static_cast(initPerParticle()); }); + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); } template @@ -133,20 +128,35 @@ struct treeCreatorPidTpcQa { { rowPidTpcQa.reserve(tracks.size() * mEnabledParticles); + std::string irSource{}; + float sqrtSNN{}; // placeholder to satisfy evaluateIrSourceAndSqrtSnn's signature + bool isFirstCollision{true}; for (const auto& collision : collisions) { if (!isEventSelected(collision, applyEvSel) || ((cutVtxZ > 0.f) && std::abs(collision.posZ()) > cutVtxZ)) { continue; } + const auto bc = collision.bc_as(); + if (isFirstCollision) { + evaluateIrSourceAndSqrtSnn(ccdb, ccdbPathGrpLhcIf, bc.timestamp(), irSource, sqrtSNN); + } + isFirstCollision = false; const float ft0Occ = collision.ft0cOccupancyInTimeRange(); - const float multTPC = collision.multTPC() / dpg_tpcskimstablecreator::MultiplicityNorm; + const float multTPC = collision.multTPC() / MultiplicityNorm; + const auto hadronicRate = !irSource.empty() ? mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource) * OneToKilo : 0.; const auto tracksFromCollision = tracks.sliceBy(perCollisionTracks, static_cast(collision.globalIndex())); for (const auto& track : tracksFromCollision) { - if (!isTrackSelected(track)) { + bool isGoodTrack = isTrackSelected(track, trackSelection); + isGoodTrack &= (!requireGlobalTrack || track.isGlobalTrack()); + isGoodTrack &= (!requireIts || track.hasITS()); + isGoodTrack &= track.hasTPC(); + isGoodTrack &= (track.tpcNClsFound() >= cutMinTPCNcls); + if (!isGoodTrack) { continue; } + const float rapidity = track.rapidity(PID::getMass(Id)); if (cutRapidity > 0.f && std::fabs(rapidity) > cutRapidity) { continue; @@ -157,15 +167,16 @@ struct treeCreatorPidTpcQa { const float tgl = track.tgl(); const float tpcInnerParam = track.tpcInnerParam(); - rowPidTpcQa(Id, ft0Occ, multTPC, nClNormalized, phi, tgl, tpcInnerParam, rapidity); - } // tracks + rowPidTpcQa(Id, ft0Occ, hadronicRate, multTPC, nClNormalized, phi, tgl, tpcInnerParam, rapidity); + } // tracksFromCollision } // collisions } // QA of nsigma only tables #define MAKE_PROCESS_FUNCTION(PidTableTPC, ParticleId) \ void process##ParticleId(CollisionsExtra const& collisions, \ - soa::Join const& tracks) \ + soa::Join const& tracks, \ + aod::BCsWithTimestamps const&) \ { \ processSingleParticle(collisions, tracks); \ } \ @@ -185,7 +196,8 @@ struct treeCreatorPidTpcQa { // QA of full tables #define MAKE_PROCESS_FUNCTION(PidTableTPC, ParticleId) \ void processFull##ParticleId(CollisionsExtra const& collisions, \ - soa::Join const& tracks) \ + soa::Join const& tracks, \ + aod::BCsWithTimestamps const&) \ { \ processSingleParticle(collisions, tracks); \ } \ @@ -205,7 +217,8 @@ struct treeCreatorPidTpcQa { // QA of full tables with TOF information #define MAKE_PROCESS_FUNCTION(PidTableTPC, PidTableTOF, ParticleId) \ void processFullWithTOF##ParticleId(CollisionsExtra const& collisions, \ - soa::Join const& tracks) \ + soa::Join const& tracks, \ + aod::BCsWithTimestamps const&) \ { \ processSingleParticle(collisions, tracks); \ } \ diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h index d5a357bea06..dd9338cfe55 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h @@ -14,18 +14,20 @@ /// \author Oleksii Lubynets /// \brief Creates trees with PID QA variables along with variables used for NN training +#ifndef DPG_TASKS_AOTTRACK_PID_TPC_TREECREATORPIDTPCQA_H_ +#define DPG_TASKS_AOTTRACK_PID_TPC_TREECREATORPIDTPCQA_H_ + #include "DPG/Tasks/TPC/tpcSkimsTableCreator.h" #include - -#ifndef DPG_TASKS_AOTTRACK_PID_TPC_TREECREATORPIDTPCQA_H_ -#define DPG_TASKS_AOTTRACK_PID_TPC_TREECREATORPIDTPCQA_H_ +#include namespace o2::aod { DECLARE_SOA_TABLE(QaPidTpc, "AOD", "QAPIDTPC", tpcskims::PidIndex, tpcskims::Ft0Occ, + tpcskims::HadronicRate, tpcskims::NormMultTPC, tpcskims::NormNClustersTPC, o2::aod::track::Phi, @@ -34,30 +36,4 @@ DECLARE_SOA_TABLE(QaPidTpc, "AOD", "QAPIDTPC", o2::aod::track::Y) } // namespace o2::aod -namespace o2::dpg_pidtpcqa -{ -enum { - TrackSelectionNoCut = 0, - TrackSelectionGlobalTrack, - TrackSelectionTrackWoPtEta, - TrackSelectionGlobalTrackWoDCA, - TrackSelectionQualityTracks, - TrackSelectionInAcceptanceTracks -}; - -enum { - EventSelectionNo = 0, - EventSelectionRun2, - EventSelectionRun3 -}; - -/// Event selection -template -bool isEventSelected(const CollisionType& collision, const int applyEvSel) -{ - return ((applyEvSel == EventSelectionRun2 && !collision.sel7()) || (applyEvSel == EventSelectionRun3 && !collision.sel8())); -} - -}; // namespace o2::dpg_pidtpcqa - #endif // DPG_TASKS_AOTTRACK_PID_TPC_TREECREATORPIDTPCQA_H_ From d614c3576b052a40e404f743272db75d4e0576d9 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Thu, 9 Jul 2026 18:32:53 +0200 Subject: [PATCH 03/14] treeCreatorPidTpcQa: mainly working version --- .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx | 31 +++++++++++++++---- .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.h | 20 +++++++++++- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx index 9b33d5db016..1d350bf83aa 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx @@ -38,6 +38,7 @@ #include #include +#include #include using namespace o2; @@ -122,7 +123,7 @@ struct treeCreatorPidTpcQa { ccdb->setFatalWhenNull(false); } - template + template void processSingleParticle(CollisionsExtra const& collisions, TrackType const& tracks) { @@ -162,12 +163,30 @@ struct treeCreatorPidTpcQa { continue; } - const int nClNormalized = std::sqrt(nClNorm / track.tpcNClsFound()); + const float nClNormalized = std::sqrt(nClNorm / track.tpcNClsFound()); const float phi = track.phi(); const float tgl = track.tgl(); const float tpcInnerParam = track.tpcInnerParam(); + const int16_t trackSign = track.sign(); + const float nSigmaTpc = o2::aod::pidutils::tpcNSigma(track); - rowPidTpcQa(Id, ft0Occ, hadronicRate, multTPC, nClNormalized, phi, tgl, tpcInnerParam, rapidity); + float dedxDiff{UndefValueFloat}; + float dedxExpected{UndefValueFloat}; + float expSigma{UndefValueFloat}; + + if constexpr (IsFullTable) { + dedxDiff = o2::aod::pidutils::tpcExpSignalDiff(track); + dedxExpected = track.tpcSignal() - dedxDiff; + expSigma = o2::aod::pidutils::tpcExpSigma(track); + } + + float nSigmaTof{UndefValueFloat}; + + if constexpr (IsTofTable) { + nSigmaTof = o2::aod::pidutils::tofNSigma(track); + } + + rowPidTpcQa(Id, ft0Occ, hadronicRate, multTPC, nClNormalized, phi, tgl, tpcInnerParam, rapidity, trackSign, nSigmaTpc, dedxExpected, dedxDiff, expSigma, nSigmaTof); } // tracksFromCollision } // collisions } @@ -178,7 +197,7 @@ struct treeCreatorPidTpcQa { soa::Join const& tracks, \ aod::BCsWithTimestamps const&) \ { \ - processSingleParticle(collisions, tracks); \ + processSingleParticle(collisions, tracks); \ } \ PROCESS_SWITCH(treeCreatorPidTpcQa, process##ParticleId, Form("Process for the %s hypothesis for TPC NSigma QA", #ParticleId), false); @@ -199,7 +218,7 @@ struct treeCreatorPidTpcQa { soa::Join const& tracks, \ aod::BCsWithTimestamps const&) \ { \ - processSingleParticle(collisions, tracks); \ + processSingleParticle(collisions, tracks); \ } \ PROCESS_SWITCH(treeCreatorPidTpcQa, processFull##ParticleId, Form("Process for the %s hypothesis for full TPC PID QA", #ParticleId), false); @@ -220,7 +239,7 @@ struct treeCreatorPidTpcQa { soa::Join const& tracks, \ aod::BCsWithTimestamps const&) \ { \ - processSingleParticle(collisions, tracks); \ + processSingleParticle(collisions, tracks); \ } \ PROCESS_SWITCH(treeCreatorPidTpcQa, processFullWithTOF##ParticleId, Form("Process for the %s hypothesis for full TPC PID QA with the TOF info added", #ParticleId), false); diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h index dd9338cfe55..20f64294a76 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h @@ -22,8 +22,20 @@ #include #include +#include + namespace o2::aod { +namespace dpg_tpcpidqa +{ +DECLARE_SOA_COLUMN(Sign, sign, int16_t); +DECLARE_SOA_COLUMN(NSigmaTpc, nSigmaTpc, float); +DECLARE_SOA_COLUMN(DedxExpected, dedxTpc, float); +DECLARE_SOA_COLUMN(DedxDiff, dedxDiff, float); +DECLARE_SOA_COLUMN(ExpSigma, expSigma, float); +DECLARE_SOA_COLUMN(NSigmaTof, nSigmaTof, float); +} // namespace dpg_tpcpidqa + DECLARE_SOA_TABLE(QaPidTpc, "AOD", "QAPIDTPC", tpcskims::PidIndex, tpcskims::Ft0Occ, @@ -33,7 +45,13 @@ DECLARE_SOA_TABLE(QaPidTpc, "AOD", "QAPIDTPC", o2::aod::track::Phi, o2::aod::track::Tgl, o2::aod::track::TPCInnerParam, - o2::aod::track::Y) + o2::aod::track::Y, + dpg_tpcpidqa::Sign, + dpg_tpcpidqa::NSigmaTpc, + dpg_tpcpidqa::DedxExpected, + dpg_tpcpidqa::DedxDiff, + dpg_tpcpidqa::ExpSigma, + dpg_tpcpidqa::NSigmaTof) } // namespace o2::aod #endif // DPG_TASKS_AOTTRACK_PID_TPC_TREECREATORPIDTPCQA_H_ From 5eee6046840394d1884ce7fbdfd157570c4d9028 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Mon, 13 Jul 2026 22:22:20 +0200 Subject: [PATCH 04/14] change DataModel --- DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx | 6 ++++-- DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h | 7 +++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx index 1d350bf83aa..8a8ae8200ec 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx @@ -162,12 +162,14 @@ struct treeCreatorPidTpcQa { if (cutRapidity > 0.f && std::fabs(rapidity) > cutRapidity) { continue; } + const float momentum = track.p(); const float nClNormalized = std::sqrt(nClNorm / track.tpcNClsFound()); + const float nclPID = static_cast(track.tpcNClsPID()); const float phi = track.phi(); const float tgl = track.tgl(); const float tpcInnerParam = track.tpcInnerParam(); - const int16_t trackSign = track.sign(); + const float signed1Pt = track.signed1Pt(); const float nSigmaTpc = o2::aod::pidutils::tpcNSigma(track); float dedxDiff{UndefValueFloat}; @@ -186,7 +188,7 @@ struct treeCreatorPidTpcQa { nSigmaTof = o2::aod::pidutils::tofNSigma(track); } - rowPidTpcQa(Id, ft0Occ, hadronicRate, multTPC, nClNormalized, phi, tgl, tpcInnerParam, rapidity, trackSign, nSigmaTpc, dedxExpected, dedxDiff, expSigma, nSigmaTof); + rowPidTpcQa(Id, ft0Occ, hadronicRate, multTPC, nClNormalized, nclPID, phi, tgl, tpcInnerParam, rapidity, momentum, signed1Pt, nSigmaTpc, dedxExpected, dedxDiff, expSigma, nSigmaTof); } // tracksFromCollision } // collisions } diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h index 20f64294a76..3c76cec6484 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h @@ -22,13 +22,10 @@ #include #include -#include - namespace o2::aod { namespace dpg_tpcpidqa { -DECLARE_SOA_COLUMN(Sign, sign, int16_t); DECLARE_SOA_COLUMN(NSigmaTpc, nSigmaTpc, float); DECLARE_SOA_COLUMN(DedxExpected, dedxTpc, float); DECLARE_SOA_COLUMN(DedxDiff, dedxDiff, float); @@ -42,11 +39,13 @@ DECLARE_SOA_TABLE(QaPidTpc, "AOD", "QAPIDTPC", tpcskims::HadronicRate, tpcskims::NormMultTPC, tpcskims::NormNClustersTPC, + tpcskims::NormNClustersTPCPID, o2::aod::track::Phi, o2::aod::track::Tgl, o2::aod::track::TPCInnerParam, o2::aod::track::Y, - dpg_tpcpidqa::Sign, + o2::aod::track::P, + o2::aod::track::Signed1Pt, dpg_tpcpidqa::NSigmaTpc, dpg_tpcpidqa::DedxExpected, dpg_tpcpidqa::DedxDiff, From 9eabb7c81c6ffca873fe9968a633b39bb6f087d4 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Tue, 14 Jul 2026 17:32:03 +0200 Subject: [PATCH 05/14] introduce PARTICLE_LIST for DRY particle-wise code, init cuts --- .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx | 144 ++++++++---------- 1 file changed, 66 insertions(+), 78 deletions(-) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx index 8a8ae8200ec..0da50414ca8 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx @@ -46,6 +46,17 @@ using namespace o2::framework; using namespace o2::track; using namespace o2::dpg_tpcskimstablecreator; +#define PARTICLE_LIST(MACRO_ARG) \ + MACRO_ARG(El, Electron) \ + MACRO_ARG(Mu, Muon) \ + MACRO_ARG(Pi, Pion) \ + MACRO_ARG(Ka, Kaon) \ + MACRO_ARG(Pr, Proton) \ + MACRO_ARG(De, Deuteron) \ + MACRO_ARG(Tr, Triton) \ + MACRO_ARG(He, Helium3) \ + MACRO_ARG(Al, Alpha) + struct treeCreatorPidTpcQa { Produces rowPidTpcQa; @@ -60,6 +71,14 @@ struct treeCreatorPidTpcQa { // Configurable for the path of CCDB General Run Parameters LHC Interface information Configurable ccdbPathGrpLhcIf{"ccdbPathGrpLhcIf", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; +#define DECLARE_PARTICLE_WISE_CONFIGURABLES(ParticleNameShort, ParticleNameLong) \ + Configurable cutTpcInnerParameterMin##ParticleNameLong{"cutTpcInnerParameterMin" #ParticleNameLong, -1., "Lower-value cut on tpcInnerParam for " #ParticleNameLong}; \ + Configurable cutTpcInnerParameterMax##ParticleNameLong{"cutTpcInnerParameterMax" #ParticleNameLong, -1., "Upper-value cut on tpcInnerParam for " #ParticleNameLong}; \ + Configurable cutNSigmaTpcAbs##ParticleNameLong{"cutNSigmaTpcAbs" #ParticleNameLong, -1., "Cut on absolute value of nSigmaTpc for " #ParticleNameLong}; + + PARTICLE_LIST(DECLARE_PARTICLE_WISE_CONFIGURABLES) +#undef DECLARE_PARTICLE_WISE_CONFIGURABLES + Service ccdb{}; ctpRateFetcher mRateFetcher{}; @@ -78,32 +97,24 @@ struct treeCreatorPidTpcQa { int enabledProcesses{0}; switch (Id) { -#define PARTICLE_CASE(ParticleId) \ - case PID::ParticleId: \ - if (!doprocess##ParticleId && !doprocessFull##ParticleId && !doprocessFullWithTOF##ParticleId) { \ - return false; \ - } \ - if (doprocess##ParticleId) { \ - ++enabledProcesses; \ - } \ - if (doprocessFull##ParticleId) { \ - ++enabledProcesses; \ - } \ - if (doprocessFullWithTOF##ParticleId) { \ - ++enabledProcesses; \ - } \ - LOG(info) << "Enabled TPC QA for " << #ParticleId; \ +#define PARTICLE_CASE(ParticleNameShort, ParticleNameLong) \ + case PID::ParticleNameLong: \ + if (!doprocess##ParticleNameLong && !doprocessFull##ParticleNameLong && !doprocessFullWithTOF##ParticleNameLong) { \ + return false; \ + } \ + if (doprocess##ParticleNameLong) { \ + ++enabledProcesses; \ + } \ + if (doprocessFull##ParticleNameLong) { \ + ++enabledProcesses; \ + } \ + if (doprocessFullWithTOF##ParticleNameLong) { \ + ++enabledProcesses; \ + } \ + LOG(info) << "Enabled TPC QA for " << #ParticleNameLong; \ break; - PARTICLE_CASE(Electron); - PARTICLE_CASE(Muon); - PARTICLE_CASE(Pion); - PARTICLE_CASE(Kaon); - PARTICLE_CASE(Proton); - PARTICLE_CASE(Deuteron); - PARTICLE_CASE(Triton); - PARTICLE_CASE(Helium3); - PARTICLE_CASE(Alpha); + PARTICLE_LIST(PARTICLE_CASE) #undef PARTICLE_CASE } if (enabledProcesses != 1) { @@ -194,66 +205,42 @@ struct treeCreatorPidTpcQa { } // QA of nsigma only tables -#define MAKE_PROCESS_FUNCTION(PidTableTPC, ParticleId) \ - void process##ParticleId(CollisionsExtra const& collisions, \ - soa::Join const& tracks, \ - aod::BCsWithTimestamps const&) \ - { \ - processSingleParticle(collisions, tracks); \ - } \ - PROCESS_SWITCH(treeCreatorPidTpcQa, process##ParticleId, Form("Process for the %s hypothesis for TPC NSigma QA", #ParticleId), false); - - MAKE_PROCESS_FUNCTION(aod::pidTPCEl, Electron); - MAKE_PROCESS_FUNCTION(aod::pidTPCMu, Muon); - MAKE_PROCESS_FUNCTION(aod::pidTPCPi, Pion); - MAKE_PROCESS_FUNCTION(aod::pidTPCKa, Kaon); - MAKE_PROCESS_FUNCTION(aod::pidTPCPr, Proton); - MAKE_PROCESS_FUNCTION(aod::pidTPCDe, Deuteron); - MAKE_PROCESS_FUNCTION(aod::pidTPCTr, Triton); - MAKE_PROCESS_FUNCTION(aod::pidTPCHe, Helium3); - MAKE_PROCESS_FUNCTION(aod::pidTPCAl, Alpha); +#define MAKE_PROCESS_FUNCTION(ParticleNameShort, ParticleNameLong) \ + void process##ParticleNameLong(CollisionsExtra const& collisions, \ + soa::Join const& tracks, \ + aod::BCsWithTimestamps const&) \ + { \ + processSingleParticle(collisions, tracks); \ + } \ + PROCESS_SWITCH(treeCreatorPidTpcQa, process##ParticleNameLong, Form("Process for the %s hypothesis for TPC NSigma QA ", #ParticleNameLong), false); + + PARTICLE_LIST(MAKE_PROCESS_FUNCTION) #undef MAKE_PROCESS_FUNCTION // QA of full tables -#define MAKE_PROCESS_FUNCTION(PidTableTPC, ParticleId) \ - void processFull##ParticleId(CollisionsExtra const& collisions, \ - soa::Join const& tracks, \ - aod::BCsWithTimestamps const&) \ - { \ - processSingleParticle(collisions, tracks); \ - } \ - PROCESS_SWITCH(treeCreatorPidTpcQa, processFull##ParticleId, Form("Process for the %s hypothesis for full TPC PID QA", #ParticleId), false); - - MAKE_PROCESS_FUNCTION(aod::pidTPCFullEl, Electron); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullMu, Muon); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullPi, Pion); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullKa, Kaon); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullPr, Proton); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullDe, Deuteron); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullTr, Triton); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullHe, Helium3); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullAl, Alpha); +#define MAKE_PROCESS_FUNCTION(ParticleNameShort, ParticleNameLong) \ + void processFull##ParticleNameLong(CollisionsExtra const& collisions, \ + soa::Join const& tracks, \ + aod::BCsWithTimestamps const&) \ + { \ + processSingleParticle(collisions, tracks); \ + } \ + PROCESS_SWITCH(treeCreatorPidTpcQa, processFull##ParticleNameLong, Form("Process for the %s hypothesis for full TPC PID QA ", #ParticleNameLong), false); + + PARTICLE_LIST(MAKE_PROCESS_FUNCTION) #undef MAKE_PROCESS_FUNCTION // QA of full tables with TOF information -#define MAKE_PROCESS_FUNCTION(PidTableTPC, PidTableTOF, ParticleId) \ - void processFullWithTOF##ParticleId(CollisionsExtra const& collisions, \ - soa::Join const& tracks, \ - aod::BCsWithTimestamps const&) \ - { \ - processSingleParticle(collisions, tracks); \ - } \ - PROCESS_SWITCH(treeCreatorPidTpcQa, processFullWithTOF##ParticleId, Form("Process for the %s hypothesis for full TPC PID QA with the TOF info added", #ParticleId), false); - - MAKE_PROCESS_FUNCTION(aod::pidTPCFullEl, aod::pidTOFFullEl, Electron); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullMu, aod::pidTOFFullMu, Muon); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullPi, aod::pidTOFFullPi, Pion); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullKa, aod::pidTOFFullKa, Kaon); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullPr, aod::pidTOFFullPr, Proton); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullDe, aod::pidTOFFullDe, Deuteron); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullTr, aod::pidTOFFullTr, Triton); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullHe, aod::pidTOFFullHe, Helium3); - MAKE_PROCESS_FUNCTION(aod::pidTPCFullAl, aod::pidTOFFullAl, Alpha); +#define MAKE_PROCESS_FUNCTION(ParticleNameShort, ParticleNameLong) \ + void processFullWithTOF##ParticleNameLong(CollisionsExtra const& collisions, \ + soa::Join const& tracks, \ + aod::BCsWithTimestamps const&) \ + { \ + processSingleParticle(collisions, tracks); \ + } \ + PROCESS_SWITCH(treeCreatorPidTpcQa, processFullWithTOF##ParticleNameLong, Form("Process for the %s hypothesis for full TPC PID QA with the TOF info added ", #ParticleNameLong), false); + + PARTICLE_LIST(MAKE_PROCESS_FUNCTION) #undef MAKE_PROCESS_FUNCTION }; @@ -261,3 +248,4 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } +#undef PARTICLE_LIST From 7f161ec55dff7223685802d27c072bd966994d4a Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Wed, 15 Jul 2026 10:33:20 +0200 Subject: [PATCH 06/14] fix (and silence) linter errors --- .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx | 20 +++++++++---------- .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx index 0da50414ca8..24ed18b4434 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file treeCreatorPidTpcQa.cxx +/// \file TreeCreatorPidTpcQa.cxx /// \brief Task to produce table with clean selections for TPC PID calibration /// /// \author Ana Marin @@ -57,7 +57,7 @@ using namespace o2::dpg_tpcskimstablecreator; MACRO_ARG(He, Helium3) \ MACRO_ARG(Al, Alpha) -struct treeCreatorPidTpcQa { +struct TreeCreatorPidTpcQa { Produces rowPidTpcQa; Configurable applyEvSel{"applyEvSel", 2, "Flag to apply event selection: 0 -> no event selection, 1 -> Run 2 event selection, 2 -> Run 3 event selection"}; @@ -71,10 +71,10 @@ struct treeCreatorPidTpcQa { // Configurable for the path of CCDB General Run Parameters LHC Interface information Configurable ccdbPathGrpLhcIf{"ccdbPathGrpLhcIf", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; -#define DECLARE_PARTICLE_WISE_CONFIGURABLES(ParticleNameShort, ParticleNameLong) \ - Configurable cutTpcInnerParameterMin##ParticleNameLong{"cutTpcInnerParameterMin" #ParticleNameLong, -1., "Lower-value cut on tpcInnerParam for " #ParticleNameLong}; \ - Configurable cutTpcInnerParameterMax##ParticleNameLong{"cutTpcInnerParameterMax" #ParticleNameLong, -1., "Upper-value cut on tpcInnerParam for " #ParticleNameLong}; \ - Configurable cutNSigmaTpcAbs##ParticleNameLong{"cutNSigmaTpcAbs" #ParticleNameLong, -1., "Cut on absolute value of nSigmaTpc for " #ParticleNameLong}; +#define DECLARE_PARTICLE_WISE_CONFIGURABLES(ParticleNameShort, ParticleNameLong) \ + Configurable cutTpcInnerParameterMin##ParticleNameLong{"cutTpcInnerParameterMin" #ParticleNameLong, -1., "Lower-value cut on tpcInnerParam for " #ParticleNameLong}; /* o2-linter: disable=name/configurable (Configurable defined in macro)*/ \ + Configurable cutTpcInnerParameterMax##ParticleNameLong{"cutTpcInnerParameterMax" #ParticleNameLong, -1., "Upper-value cut on tpcInnerParam for " #ParticleNameLong}; /* o2-linter: disable=name/configurable (Configurable defined in macro)*/ \ + Configurable cutNSigmaTpcAbs##ParticleNameLong{"cutNSigmaTpcAbs" #ParticleNameLong, -1., "Cut on absolute value of nSigmaTpc for " #ParticleNameLong}; // o2-linter: disable=name/configurable (Configurable defined in macro) PARTICLE_LIST(DECLARE_PARTICLE_WISE_CONFIGURABLES) #undef DECLARE_PARTICLE_WISE_CONFIGURABLES @@ -212,7 +212,7 @@ struct treeCreatorPidTpcQa { { \ processSingleParticle(collisions, tracks); \ } \ - PROCESS_SWITCH(treeCreatorPidTpcQa, process##ParticleNameLong, Form("Process for the %s hypothesis for TPC NSigma QA ", #ParticleNameLong), false); + PROCESS_SWITCH(TreeCreatorPidTpcQa, process##ParticleNameLong, Form("Process for the %s hypothesis for TPC NSigma QA", #ParticleNameLong), false); PARTICLE_LIST(MAKE_PROCESS_FUNCTION) #undef MAKE_PROCESS_FUNCTION @@ -225,7 +225,7 @@ struct treeCreatorPidTpcQa { { \ processSingleParticle(collisions, tracks); \ } \ - PROCESS_SWITCH(treeCreatorPidTpcQa, processFull##ParticleNameLong, Form("Process for the %s hypothesis for full TPC PID QA ", #ParticleNameLong), false); + PROCESS_SWITCH(TreeCreatorPidTpcQa, processFull##ParticleNameLong, Form("Process for the %s hypothesis for full TPC PID QA", #ParticleNameLong), false); PARTICLE_LIST(MAKE_PROCESS_FUNCTION) #undef MAKE_PROCESS_FUNCTION @@ -238,7 +238,7 @@ struct treeCreatorPidTpcQa { { \ processSingleParticle(collisions, tracks); \ } \ - PROCESS_SWITCH(treeCreatorPidTpcQa, processFullWithTOF##ParticleNameLong, Form("Process for the %s hypothesis for full TPC PID QA with the TOF info added ", #ParticleNameLong), false); + PROCESS_SWITCH(TreeCreatorPidTpcQa, processFullWithTOF##ParticleNameLong, Form("Process for the %s hypothesis for full TPC PID QA with the TOF info added", #ParticleNameLong), false); PARTICLE_LIST(MAKE_PROCESS_FUNCTION) #undef MAKE_PROCESS_FUNCTION @@ -246,6 +246,6 @@ struct treeCreatorPidTpcQa { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } #undef PARTICLE_LIST diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h index 3c76cec6484..c026f45fb5a 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h @@ -27,7 +27,7 @@ namespace o2::aod namespace dpg_tpcpidqa { DECLARE_SOA_COLUMN(NSigmaTpc, nSigmaTpc, float); -DECLARE_SOA_COLUMN(DedxExpected, dedxTpc, float); +DECLARE_SOA_COLUMN(DedxExpected, dedxExpected, float); DECLARE_SOA_COLUMN(DedxDiff, dedxDiff, float); DECLARE_SOA_COLUMN(ExpSigma, expSigma, float); DECLARE_SOA_COLUMN(NSigmaTof, nSigmaTof, float); From e0bb705c95ee98870fb4e38ef9531b1fd76158f4 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Wed, 15 Jul 2026 16:15:07 +0200 Subject: [PATCH 07/14] apply previously decalred cuts --- .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx index 24ed18b4434..ec4490b2cd2 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx @@ -61,24 +61,39 @@ struct TreeCreatorPidTpcQa { Produces rowPidTpcQa; Configurable applyEvSel{"applyEvSel", 2, "Flag to apply event selection: 0 -> no event selection, 1 -> Run 2 event selection, 2 -> Run 3 event selection"}; - Configurable cutVtxZ{"cutVtxZ", 10.f, "Cut on vertex Z position [cm]. Set negative value to switch this cut off"}; + Configurable cutVtxZ{"cutVtxZ", 10.f, "Cut on vertex Z position [cm]"}; Configurable trackSelection{"trackSelection", 1, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; Configurable requireGlobalTrack{"requireGlobalTrack", true, "Skip non-global tracks"}; Configurable requireIts{"requireIts", true, "Skip tracks without ITS"}; Configurable cutMinTPCNcls{"cutMinTPCNcls", 0, "Minimum number or TPC Clusters for tracks"}; - Configurable cutRapidity{"cutRapidity", 0.5, "Rapidity cut. Set negative value to switch this cut off"}; + Configurable cutRapidity{"cutRapidity", 999.f, "Rapidity cut"}; Configurable nClNorm{"nClNorm", 152., "Number of cluster normalization. Run 2: 159, Run 3 152"}; // Configurable for the path of CCDB General Run Parameters LHC Interface information Configurable ccdbPathGrpLhcIf{"ccdbPathGrpLhcIf", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; -#define DECLARE_PARTICLE_WISE_CONFIGURABLES(ParticleNameShort, ParticleNameLong) \ - Configurable cutTpcInnerParameterMin##ParticleNameLong{"cutTpcInnerParameterMin" #ParticleNameLong, -1., "Lower-value cut on tpcInnerParam for " #ParticleNameLong}; /* o2-linter: disable=name/configurable (Configurable defined in macro)*/ \ - Configurable cutTpcInnerParameterMax##ParticleNameLong{"cutTpcInnerParameterMax" #ParticleNameLong, -1., "Upper-value cut on tpcInnerParam for " #ParticleNameLong}; /* o2-linter: disable=name/configurable (Configurable defined in macro)*/ \ - Configurable cutNSigmaTpcAbs##ParticleNameLong{"cutNSigmaTpcAbs" #ParticleNameLong, -1., "Cut on absolute value of nSigmaTpc for " #ParticleNameLong}; // o2-linter: disable=name/configurable (Configurable defined in macro) +#define DECLARE_PARTICLE_WISE_CONFIGURABLES(ParticleNameShort, ParticleNameLong) \ + Configurable cutTpcInnerParameterMin##ParticleNameLong{"cutTpcInnerParameterMin" #ParticleNameLong, 0.f, "Lower-value cut on tpcInnerParam for " #ParticleNameLong}; /* o2-linter: disable=name/configurable (Configurable defined in macro)*/ \ + Configurable cutTpcInnerParameterMax##ParticleNameLong{"cutTpcInnerParameterMax" #ParticleNameLong, 999.f, "Upper-value cut on tpcInnerParam for " #ParticleNameLong}; /* o2-linter: disable=name/configurable (Configurable defined in macro)*/ \ + Configurable cutNSigmaTpcAbs##ParticleNameLong{"cutNSigmaTpcAbs" #ParticleNameLong, 999.f, "Cut on absolute value of nSigmaTpc for " #ParticleNameLong}; // o2-linter: disable=name/configurable (Configurable defined in macro) PARTICLE_LIST(DECLARE_PARTICLE_WISE_CONFIGURABLES) #undef DECLARE_PARTICLE_WISE_CONFIGURABLES +#define PACK_CONFIGURABLES_TO_ARRAY(ParticleNameShort, ParticleNameLong) &cutTpcInnerParameterMin##ParticleNameLong, + std::array*, PID::Alpha + 1> cutTpcInnerParameterMin{ + PARTICLE_LIST(PACK_CONFIGURABLES_TO_ARRAY)}; +#undef PACK_CONFIGURABLES_TO_ARRAY + +#define PACK_CONFIGURABLES_TO_ARRAY(ParticleNameShort, ParticleNameLong) &cutTpcInnerParameterMax##ParticleNameLong, + std::array*, PID::Alpha + 1> cutTpcInnerParameterMax{ + PARTICLE_LIST(PACK_CONFIGURABLES_TO_ARRAY)}; +#undef PACK_CONFIGURABLES_TO_ARRAY + +#define PACK_CONFIGURABLES_TO_ARRAY(ParticleNameShort, ParticleNameLong) &cutNSigmaTpcAbs##ParticleNameLong, + std::array*, PID::Alpha + 1> cutNSigmaTpcAbs{ + PARTICLE_LIST(PACK_CONFIGURABLES_TO_ARRAY)}; +#undef PACK_CONFIGURABLES_TO_ARRAY + Service ccdb{}; ctpRateFetcher mRateFetcher{}; @@ -144,7 +159,7 @@ struct TreeCreatorPidTpcQa { float sqrtSNN{}; // placeholder to satisfy evaluateIrSourceAndSqrtSnn's signature bool isFirstCollision{true}; for (const auto& collision : collisions) { - if (!isEventSelected(collision, applyEvSel) || ((cutVtxZ > 0.f) && std::abs(collision.posZ()) > cutVtxZ)) { + if (!isEventSelected(collision, applyEvSel) || (std::abs(collision.posZ()) > cutVtxZ)) { continue; } @@ -165,16 +180,9 @@ struct TreeCreatorPidTpcQa { isGoodTrack &= (!requireIts || track.hasITS()); isGoodTrack &= track.hasTPC(); isGoodTrack &= (track.tpcNClsFound() >= cutMinTPCNcls); - if (!isGoodTrack) { - continue; - } const float rapidity = track.rapidity(PID::getMass(Id)); - if (cutRapidity > 0.f && std::fabs(rapidity) > cutRapidity) { - continue; - } const float momentum = track.p(); - const float nClNormalized = std::sqrt(nClNorm / track.tpcNClsFound()); const float nclPID = static_cast(track.tpcNClsPID()); const float phi = track.phi(); @@ -183,6 +191,15 @@ struct TreeCreatorPidTpcQa { const float signed1Pt = track.signed1Pt(); const float nSigmaTpc = o2::aod::pidutils::tpcNSigma(track); + isGoodTrack &= (std::fabs(rapidity) <= cutRapidity); + isGoodTrack &= (tpcInnerParam >= *cutTpcInnerParameterMin.at(Id)); + isGoodTrack &= (tpcInnerParam <= *cutTpcInnerParameterMax.at(Id)); + isGoodTrack &= (std::fabs(nSigmaTpc) <= *cutNSigmaTpcAbs.at(Id)); + + if (!isGoodTrack) { + continue; + } + float dedxDiff{UndefValueFloat}; float dedxExpected{UndefValueFloat}; float expSigma{UndefValueFloat}; From 9d6c36008a09919ab1e2c5f47635de8a5ccf7ac4 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Wed, 15 Jul 2026 16:35:17 +0200 Subject: [PATCH 08/14] rename macros --- .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx index ec4490b2cd2..6be7fb8eb67 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -46,16 +47,16 @@ using namespace o2::framework; using namespace o2::track; using namespace o2::dpg_tpcskimstablecreator; -#define PARTICLE_LIST(MACRO_ARG) \ - MACRO_ARG(El, Electron) \ - MACRO_ARG(Mu, Muon) \ - MACRO_ARG(Pi, Pion) \ - MACRO_ARG(Ka, Kaon) \ - MACRO_ARG(Pr, Proton) \ - MACRO_ARG(De, Deuteron) \ - MACRO_ARG(Tr, Triton) \ - MACRO_ARG(He, Helium3) \ - MACRO_ARG(Al, Alpha) +#define DO_FOR_ALL_PARTICLES(MACRO) \ + MACRO(El, Electron) \ + MACRO(Mu, Muon) \ + MACRO(Pi, Pion) \ + MACRO(Ka, Kaon) \ + MACRO(Pr, Proton) \ + MACRO(De, Deuteron) \ + MACRO(Tr, Triton) \ + MACRO(He, Helium3) \ + MACRO(Al, Alpha) struct TreeCreatorPidTpcQa { Produces rowPidTpcQa; @@ -76,22 +77,22 @@ struct TreeCreatorPidTpcQa { Configurable cutTpcInnerParameterMax##ParticleNameLong{"cutTpcInnerParameterMax" #ParticleNameLong, 999.f, "Upper-value cut on tpcInnerParam for " #ParticleNameLong}; /* o2-linter: disable=name/configurable (Configurable defined in macro)*/ \ Configurable cutNSigmaTpcAbs##ParticleNameLong{"cutNSigmaTpcAbs" #ParticleNameLong, 999.f, "Cut on absolute value of nSigmaTpc for " #ParticleNameLong}; // o2-linter: disable=name/configurable (Configurable defined in macro) - PARTICLE_LIST(DECLARE_PARTICLE_WISE_CONFIGURABLES) + DO_FOR_ALL_PARTICLES(DECLARE_PARTICLE_WISE_CONFIGURABLES) #undef DECLARE_PARTICLE_WISE_CONFIGURABLES #define PACK_CONFIGURABLES_TO_ARRAY(ParticleNameShort, ParticleNameLong) &cutTpcInnerParameterMin##ParticleNameLong, std::array*, PID::Alpha + 1> cutTpcInnerParameterMin{ - PARTICLE_LIST(PACK_CONFIGURABLES_TO_ARRAY)}; + DO_FOR_ALL_PARTICLES(PACK_CONFIGURABLES_TO_ARRAY)}; #undef PACK_CONFIGURABLES_TO_ARRAY #define PACK_CONFIGURABLES_TO_ARRAY(ParticleNameShort, ParticleNameLong) &cutTpcInnerParameterMax##ParticleNameLong, std::array*, PID::Alpha + 1> cutTpcInnerParameterMax{ - PARTICLE_LIST(PACK_CONFIGURABLES_TO_ARRAY)}; + DO_FOR_ALL_PARTICLES(PACK_CONFIGURABLES_TO_ARRAY)}; #undef PACK_CONFIGURABLES_TO_ARRAY #define PACK_CONFIGURABLES_TO_ARRAY(ParticleNameShort, ParticleNameLong) &cutNSigmaTpcAbs##ParticleNameLong, std::array*, PID::Alpha + 1> cutNSigmaTpcAbs{ - PARTICLE_LIST(PACK_CONFIGURABLES_TO_ARRAY)}; + DO_FOR_ALL_PARTICLES(PACK_CONFIGURABLES_TO_ARRAY)}; #undef PACK_CONFIGURABLES_TO_ARRAY Service ccdb{}; @@ -112,7 +113,7 @@ struct TreeCreatorPidTpcQa { int enabledProcesses{0}; switch (Id) { -#define PARTICLE_CASE(ParticleNameShort, ParticleNameLong) \ +#define INIT_PARTICLE(ParticleNameShort, ParticleNameLong) \ case PID::ParticleNameLong: \ if (!doprocess##ParticleNameLong && !doprocessFull##ParticleNameLong && !doprocessFullWithTOF##ParticleNameLong) { \ return false; \ @@ -129,8 +130,8 @@ struct TreeCreatorPidTpcQa { LOG(info) << "Enabled TPC QA for " << #ParticleNameLong; \ break; - PARTICLE_LIST(PARTICLE_CASE) -#undef PARTICLE_CASE + DO_FOR_ALL_PARTICLES(INIT_PARTICLE) +#undef INIT_PARTICLE } if (enabledProcesses != 1) { LOG(fatal) << "Cannot enable more than one process function per particle, check and retry!"; @@ -231,7 +232,7 @@ struct TreeCreatorPidTpcQa { } \ PROCESS_SWITCH(TreeCreatorPidTpcQa, process##ParticleNameLong, Form("Process for the %s hypothesis for TPC NSigma QA", #ParticleNameLong), false); - PARTICLE_LIST(MAKE_PROCESS_FUNCTION) + DO_FOR_ALL_PARTICLES(MAKE_PROCESS_FUNCTION) #undef MAKE_PROCESS_FUNCTION // QA of full tables @@ -244,7 +245,7 @@ struct TreeCreatorPidTpcQa { } \ PROCESS_SWITCH(TreeCreatorPidTpcQa, processFull##ParticleNameLong, Form("Process for the %s hypothesis for full TPC PID QA", #ParticleNameLong), false); - PARTICLE_LIST(MAKE_PROCESS_FUNCTION) + DO_FOR_ALL_PARTICLES(MAKE_PROCESS_FUNCTION) #undef MAKE_PROCESS_FUNCTION // QA of full tables with TOF information @@ -257,7 +258,7 @@ struct TreeCreatorPidTpcQa { } \ PROCESS_SWITCH(TreeCreatorPidTpcQa, processFullWithTOF##ParticleNameLong, Form("Process for the %s hypothesis for full TPC PID QA with the TOF info added", #ParticleNameLong), false); - PARTICLE_LIST(MAKE_PROCESS_FUNCTION) + DO_FOR_ALL_PARTICLES(MAKE_PROCESS_FUNCTION) #undef MAKE_PROCESS_FUNCTION }; @@ -265,4 +266,4 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } -#undef PARTICLE_LIST +#undef DO_FOR_ALL_PARTICLES From bf7ac08b1bcc6d56a2bed96cb3f15acd22a52d1a Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Thu, 16 Jul 2026 10:29:12 +0200 Subject: [PATCH 09/14] make table size reservation settable --- .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx index 6be7fb8eb67..8012c023ae9 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include #include @@ -68,9 +70,12 @@ struct TreeCreatorPidTpcQa { Configurable requireIts{"requireIts", true, "Skip tracks without ITS"}; Configurable cutMinTPCNcls{"cutMinTPCNcls", 0, "Minimum number or TPC Clusters for tracks"}; Configurable cutRapidity{"cutRapidity", 999.f, "Rapidity cut"}; - Configurable nClNorm{"nClNorm", 152., "Number of cluster normalization. Run 2: 159, Run 3 152"}; + Configurable nClNorm{"nClNorm", 152.f, "Number of cluster normalization. Run 2: 159, Run 3 152"}; // Configurable for the path of CCDB General Run Parameters LHC Interface information Configurable ccdbPathGrpLhcIf{"ccdbPathGrpLhcIf", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; + // Configurables for output tables reservation size + Configurable reserveRatio{"reserveRatio", 1.f, "Ratio of how many rows expected in the output table to the input Tracks table size"}; + Configurable saveReserveQaHisto{"saveReserveQaHisto", true, "Flag to save the DF-wise ratio of output table size to that of input table"}; #define DECLARE_PARTICLE_WISE_CONFIGURABLES(ParticleNameShort, ParticleNameLong) \ Configurable cutTpcInnerParameterMin##ParticleNameLong{"cutTpcInnerParameterMin" #ParticleNameLong, 0.f, "Lower-value cut on tpcInnerParam for " #ParticleNameLong}; /* o2-linter: disable=name/configurable (Configurable defined in macro)*/ \ @@ -95,6 +100,8 @@ struct TreeCreatorPidTpcQa { DO_FOR_ALL_PARTICLES(PACK_CONFIGURABLES_TO_ARRAY)}; #undef PACK_CONFIGURABLES_TO_ARRAY + HistogramRegistry registry{"registry", {}}; + Service ccdb{}; ctpRateFetcher mRateFetcher{}; @@ -105,6 +112,7 @@ struct TreeCreatorPidTpcQa { Preslice perCollisionTracks = aod::track::collisionId; int mEnabledParticles{0}; + int mProcessedParticles{0}; template bool initPerParticle() @@ -148,13 +156,19 @@ struct TreeCreatorPidTpcQa { ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); ccdb->setFatalWhenNull(false); + + if (saveReserveQaHisto) { + registry.add("hOutputRatio", "Table out/in ratio;Table out/in ratio;Entries", {HistType::kTH1F, {{100, 0, reserveRatio}}}); + } } template void processSingleParticle(CollisionsExtra const& collisions, TrackType const& tracks) { - rowPidTpcQa.reserve(tracks.size() * mEnabledParticles); + if (mProcessedParticles == 0) { + rowPidTpcQa.reserve(tracks.size() * reserveRatio); + } std::string irSource{}; float sqrtSNN{}; // placeholder to satisfy evaluateIrSourceAndSqrtSnn's signature @@ -220,6 +234,13 @@ struct TreeCreatorPidTpcQa { rowPidTpcQa(Id, ft0Occ, hadronicRate, multTPC, nClNormalized, nclPID, phi, tgl, tpcInnerParam, rapidity, momentum, signed1Pt, nSigmaTpc, dedxExpected, dedxDiff, expSigma, nSigmaTof); } // tracksFromCollision } // collisions + ++mProcessedParticles; + if (mProcessedParticles == mEnabledParticles) { + mProcessedParticles = 0; + if (saveReserveQaHisto) { + registry.fill(HIST("hOutputRatio"), static_cast((rowPidTpcQa.lastIndex() + 1)) / tracks.size()); + } + } } // QA of nsigma only tables From c7ff68d23b783b6451bf7078c344e16599aa7d18 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Thu, 16 Jul 2026 10:40:04 +0200 Subject: [PATCH 10/14] fix file description --- DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx index 8012c023ae9..4acd11b8c65 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx @@ -9,8 +9,8 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file TreeCreatorPidTpcQa.cxx -/// \brief Task to produce table with clean selections for TPC PID calibration +/// \file treeCreatorPidTpcQa.cxx +/// \brief Creates trees with PID QA variables along with variables used for NN training /// /// \author Ana Marin /// \author Oleksii Lubynets From 6463e9186b1feb398b1d2e6d506405ccd7571cc6 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Thu, 16 Jul 2026 11:03:33 +0200 Subject: [PATCH 11/14] DRY MAKE_PROCESS_FUNCTIONS --- .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx | 49 +++++++------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx index 4acd11b8c65..c98942c938a 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx @@ -243,34 +243,23 @@ struct TreeCreatorPidTpcQa { } } - // QA of nsigma only tables -#define MAKE_PROCESS_FUNCTION(ParticleNameShort, ParticleNameLong) \ - void process##ParticleNameLong(CollisionsExtra const& collisions, \ - soa::Join const& tracks, \ - aod::BCsWithTimestamps const&) \ - { \ - processSingleParticle(collisions, tracks); \ - } \ - PROCESS_SWITCH(TreeCreatorPidTpcQa, process##ParticleNameLong, Form("Process for the %s hypothesis for TPC NSigma QA", #ParticleNameLong), false); - - DO_FOR_ALL_PARTICLES(MAKE_PROCESS_FUNCTION) -#undef MAKE_PROCESS_FUNCTION - -// QA of full tables -#define MAKE_PROCESS_FUNCTION(ParticleNameShort, ParticleNameLong) \ - void processFull##ParticleNameLong(CollisionsExtra const& collisions, \ - soa::Join const& tracks, \ - aod::BCsWithTimestamps const&) \ - { \ - processSingleParticle(collisions, tracks); \ - } \ - PROCESS_SWITCH(TreeCreatorPidTpcQa, processFull##ParticleNameLong, Form("Process for the %s hypothesis for full TPC PID QA", #ParticleNameLong), false); - - DO_FOR_ALL_PARTICLES(MAKE_PROCESS_FUNCTION) -#undef MAKE_PROCESS_FUNCTION - - // QA of full tables with TOF information -#define MAKE_PROCESS_FUNCTION(ParticleNameShort, ParticleNameLong) \ +#define MAKE_PROCESS_FUNCTIONS(ParticleNameShort, ParticleNameLong) \ + void process##ParticleNameLong(CollisionsExtra const& collisions, \ + soa::Join const& tracks, \ + aod::BCsWithTimestamps const&) \ + { \ + processSingleParticle(collisions, tracks); \ + } \ + PROCESS_SWITCH(TreeCreatorPidTpcQa, process##ParticleNameLong, Form("Process for the %s hypothesis for TPC NSigma QA", #ParticleNameLong), false); \ + \ + void processFull##ParticleNameLong(CollisionsExtra const& collisions, \ + soa::Join const& tracks, \ + aod::BCsWithTimestamps const&) \ + { \ + processSingleParticle(collisions, tracks); \ + } \ + PROCESS_SWITCH(TreeCreatorPidTpcQa, processFull##ParticleNameLong, Form("Process for the %s hypothesis for full TPC PID QA", #ParticleNameLong), false); \ + \ void processFullWithTOF##ParticleNameLong(CollisionsExtra const& collisions, \ soa::Join const& tracks, \ aod::BCsWithTimestamps const&) \ @@ -279,8 +268,8 @@ struct TreeCreatorPidTpcQa { } \ PROCESS_SWITCH(TreeCreatorPidTpcQa, processFullWithTOF##ParticleNameLong, Form("Process for the %s hypothesis for full TPC PID QA with the TOF info added", #ParticleNameLong), false); - DO_FOR_ALL_PARTICLES(MAKE_PROCESS_FUNCTION) -#undef MAKE_PROCESS_FUNCTION + DO_FOR_ALL_PARTICLES(MAKE_PROCESS_FUNCTIONS) +#undef MAKE_PROCESS_FUNCTIONS }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) From 688c9d28fbfb0ce2673d0bcf4e64406b634c1a1f Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Thu, 16 Jul 2026 12:17:37 +0200 Subject: [PATCH 12/14] add RCT check --- .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx | 17 ++++++++++++++++- .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.h | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx index c98942c938a..9322163b9fe 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx @@ -17,6 +17,7 @@ #include "treeCreatorPidTpcQa.h" +#include "Common/CCDB/RCTSelectionFlags.h" #include "Common/CCDB/ctpRateFetcher.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" @@ -76,6 +77,11 @@ struct TreeCreatorPidTpcQa { // Configurables for output tables reservation size Configurable reserveRatio{"reserveRatio", 1.f, "Ratio of how many rows expected in the output table to the input Tracks table size"}; Configurable saveReserveQaHisto{"saveReserveQaHisto", true, "Flag to save the DF-wise ratio of output table size to that of input table"}; + // Configurables for run condtion table + Configurable rctLabel{"rctLabel", "CBT_hadronPID", "select 1 [CBT, CBT_hadronPID, CBT_muon_glo] see O2Physics/Common/CCDB/RCTSelectionFlags.h"}; + Configurable checkZdc{"checkZdc", false, "set ZDC flag for PbPb"}; + Configurable treatLimitedAcceptanceAsBad{"treatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + Configurable requireGoodRct{"requireGoodRct", false, "require good detector flag in run condtion table"}; #define DECLARE_PARTICLE_WISE_CONFIGURABLES(ParticleNameShort, ParticleNameLong) \ Configurable cutTpcInnerParameterMin##ParticleNameLong{"cutTpcInnerParameterMin" #ParticleNameLong, 0.f, "Lower-value cut on tpcInnerParam for " #ParticleNameLong}; /* o2-linter: disable=name/configurable (Configurable defined in macro)*/ \ @@ -106,6 +112,8 @@ struct TreeCreatorPidTpcQa { ctpRateFetcher mRateFetcher{}; + o2::aod::rctsel::RCTFlagsChecker rctChecker{}; + using CollisionsExtra = soa::Join; using TrackCandidates = soa::Join; @@ -157,6 +165,8 @@ struct TreeCreatorPidTpcQa { ccdb->setCaching(true); ccdb->setFatalWhenNull(false); + rctChecker.init(rctLabel, checkZdc, treatLimitedAcceptanceAsBad); + if (saveReserveQaHisto) { registry.add("hOutputRatio", "Table out/in ratio;Table out/in ratio;Entries", {HistType::kTH1F, {{100, 0, reserveRatio}}}); } @@ -178,6 +188,11 @@ struct TreeCreatorPidTpcQa { continue; } + const bool isGoodRctEvent = rctChecker.checkTable(collision); + if (requireGoodRct && !isGoodRctEvent) { + continue; + } + const auto bc = collision.bc_as(); if (isFirstCollision) { evaluateIrSourceAndSqrtSnn(ccdb, ccdbPathGrpLhcIf, bc.timestamp(), irSource, sqrtSNN); @@ -231,7 +246,7 @@ struct TreeCreatorPidTpcQa { nSigmaTof = o2::aod::pidutils::tofNSigma(track); } - rowPidTpcQa(Id, ft0Occ, hadronicRate, multTPC, nClNormalized, nclPID, phi, tgl, tpcInnerParam, rapidity, momentum, signed1Pt, nSigmaTpc, dedxExpected, dedxDiff, expSigma, nSigmaTof); + rowPidTpcQa(isGoodRctEvent, Id, ft0Occ, hadronicRate, multTPC, nClNormalized, nclPID, phi, tgl, tpcInnerParam, rapidity, momentum, signed1Pt, nSigmaTpc, dedxExpected, dedxDiff, expSigma, nSigmaTof); } // tracksFromCollision } // collisions ++mProcessedParticles; diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h index c026f45fb5a..f34a4c52a8f 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.h @@ -34,6 +34,7 @@ DECLARE_SOA_COLUMN(NSigmaTof, nSigmaTof, float); } // namespace dpg_tpcpidqa DECLARE_SOA_TABLE(QaPidTpc, "AOD", "QAPIDTPC", + tpcskims::IsGoodRct, tpcskims::PidIndex, tpcskims::Ft0Occ, tpcskims::HadronicRate, From 100c69aa3277c681a4ba01cba4565df2424a7921 Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Thu, 16 Jul 2026 12:23:40 +0200 Subject: [PATCH 13/14] rename Id->ParticleId --- .../AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx index 9322163b9fe..ec56ec2b2c9 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx @@ -122,13 +122,13 @@ struct TreeCreatorPidTpcQa { int mEnabledParticles{0}; int mProcessedParticles{0}; - template + template bool initPerParticle() { - static_assert(Id >= 0 && Id <= PID::Alpha && "Particle index outside limits"); + static_assert(ParticleId >= 0 && ParticleId <= PID::Alpha && "Particle index outside limits"); int enabledProcesses{0}; - switch (Id) { + switch (ParticleId) { #define INIT_PARTICLE(ParticleNameShort, ParticleNameLong) \ case PID::ParticleNameLong: \ if (!doprocess##ParticleNameLong && !doprocessFull##ParticleNameLong && !doprocessFullWithTOF##ParticleNameLong) { \ @@ -157,8 +157,8 @@ struct TreeCreatorPidTpcQa { void init(o2::framework::InitContext&) { - static_for<0, PID::Alpha>([&](auto Id) { - mEnabledParticles += static_cast(initPerParticle()); + static_for<0, PID::Alpha>([&](auto ParticleId) { + mEnabledParticles += static_cast(initPerParticle()); }); ccdb->setURL("http://alice-ccdb.cern.ch"); @@ -172,7 +172,7 @@ struct TreeCreatorPidTpcQa { } } - template + template void processSingleParticle(CollisionsExtra const& collisions, TrackType const& tracks) { @@ -211,7 +211,7 @@ struct TreeCreatorPidTpcQa { isGoodTrack &= track.hasTPC(); isGoodTrack &= (track.tpcNClsFound() >= cutMinTPCNcls); - const float rapidity = track.rapidity(PID::getMass(Id)); + const float rapidity = track.rapidity(PID::getMass(ParticleId)); const float momentum = track.p(); const float nClNormalized = std::sqrt(nClNorm / track.tpcNClsFound()); const float nclPID = static_cast(track.tpcNClsPID()); @@ -219,12 +219,12 @@ struct TreeCreatorPidTpcQa { const float tgl = track.tgl(); const float tpcInnerParam = track.tpcInnerParam(); const float signed1Pt = track.signed1Pt(); - const float nSigmaTpc = o2::aod::pidutils::tpcNSigma(track); + const float nSigmaTpc = o2::aod::pidutils::tpcNSigma(track); isGoodTrack &= (std::fabs(rapidity) <= cutRapidity); - isGoodTrack &= (tpcInnerParam >= *cutTpcInnerParameterMin.at(Id)); - isGoodTrack &= (tpcInnerParam <= *cutTpcInnerParameterMax.at(Id)); - isGoodTrack &= (std::fabs(nSigmaTpc) <= *cutNSigmaTpcAbs.at(Id)); + isGoodTrack &= (tpcInnerParam >= *cutTpcInnerParameterMin.at(ParticleId)); + isGoodTrack &= (tpcInnerParam <= *cutTpcInnerParameterMax.at(ParticleId)); + isGoodTrack &= (std::fabs(nSigmaTpc) <= *cutNSigmaTpcAbs.at(ParticleId)); if (!isGoodTrack) { continue; @@ -235,18 +235,18 @@ struct TreeCreatorPidTpcQa { float expSigma{UndefValueFloat}; if constexpr (IsFullTable) { - dedxDiff = o2::aod::pidutils::tpcExpSignalDiff(track); + dedxDiff = o2::aod::pidutils::tpcExpSignalDiff(track); dedxExpected = track.tpcSignal() - dedxDiff; - expSigma = o2::aod::pidutils::tpcExpSigma(track); + expSigma = o2::aod::pidutils::tpcExpSigma(track); } float nSigmaTof{UndefValueFloat}; if constexpr (IsTofTable) { - nSigmaTof = o2::aod::pidutils::tofNSigma(track); + nSigmaTof = o2::aod::pidutils::tofNSigma(track); } - rowPidTpcQa(isGoodRctEvent, Id, ft0Occ, hadronicRate, multTPC, nClNormalized, nclPID, phi, tgl, tpcInnerParam, rapidity, momentum, signed1Pt, nSigmaTpc, dedxExpected, dedxDiff, expSigma, nSigmaTof); + rowPidTpcQa(isGoodRctEvent, ParticleId, ft0Occ, hadronicRate, multTPC, nClNormalized, nclPID, phi, tgl, tpcInnerParam, rapidity, momentum, signed1Pt, nSigmaTpc, dedxExpected, dedxDiff, expSigma, nSigmaTof); } // tracksFromCollision } // collisions ++mProcessedParticles; From 7a6c7323d91561b31b11bc6b2846d1bb7b81067f Mon Sep 17 00:00:00 2001 From: Oleksii Lubynets Date: Thu, 16 Jul 2026 13:21:26 +0200 Subject: [PATCH 14/14] fix (part of) O2Physics-code-check errors --- DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx index ec56ec2b2c9..130e275ec17 100644 --- a/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx +++ b/DPG/Tasks/AOTTrack/PID/TPC/treeCreatorPidTpcQa.cxx @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -40,6 +41,8 @@ #include #include +#include + #include #include #include @@ -214,7 +217,7 @@ struct TreeCreatorPidTpcQa { const float rapidity = track.rapidity(PID::getMass(ParticleId)); const float momentum = track.p(); const float nClNormalized = std::sqrt(nClNorm / track.tpcNClsFound()); - const float nclPID = static_cast(track.tpcNClsPID()); + const auto nclPID = static_cast(track.tpcNClsPID()); const float phi = track.phi(); const float tgl = track.tgl(); const float tpcInnerParam = track.tpcInnerParam();