From f5064829df1f3449c7576a7e6d162c2ed1a8df36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Tiek=C3=B6tter?= Date: Fri, 21 Aug 2026 13:58:43 +0200 Subject: [PATCH 1/5] Added Multiplicity estimator task for ALICE3 --- ALICE3/DataModel/tracksAlice3.h | 4 +- ALICE3/TableProducer/CMakeLists.txt | 5 + ALICE3/TableProducer/OTF/onTheFlyTracker.cxx | 2 +- ALICE3/TableProducer/alice3Multiplicity.cxx | 131 ++++++++++++++++++ .../alice3TrackingTranslator.cxx | 3 +- 5 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 ALICE3/TableProducer/alice3Multiplicity.cxx diff --git a/ALICE3/DataModel/tracksAlice3.h b/ALICE3/DataModel/tracksAlice3.h index b6ccc587d91..4b587f28e60 100644 --- a/ALICE3/DataModel/tracksAlice3.h +++ b/ALICE3/DataModel/tracksAlice3.h @@ -31,6 +31,7 @@ DECLARE_SOA_COLUMN(NSiliconHits, nSiliconHits, int); //! number of silico DECLARE_SOA_COLUMN(NTPCHits, nTPCHits, int); //! number of tpc hits DECLARE_SOA_COLUMN(PdgCode, pdgCode, int); //! PDG code of the linked truth MC particle DECLARE_SOA_COLUMN(TrackType, trackType, int); //! Type of the track +DECLARE_SOA_COLUMN(IsPVContributor, isPVContributor, bool); //! Has track contributed to the PV fit? } // namespace track_alice3 DECLARE_SOA_TABLE(TracksAlice3, "AOD", "TRACKSALICE3", track_alice3::IsReconstructed); @@ -43,7 +44,8 @@ using TrackAlice3Pdg = TracksAlice3Pdg::iterator; DECLARE_SOA_TABLE(TracksExtraA3, "AOD", "TracksExtraA3", track_alice3::NSiliconHits, track_alice3::NTPCHits, - track_alice3::TrackType); + track_alice3::TrackType, + track_alice3::IsPVContributor); using TrackExtraA3 = TracksExtraA3::iterator; namespace mcparticle_alice3 diff --git a/ALICE3/TableProducer/CMakeLists.txt b/ALICE3/TableProducer/CMakeLists.txt index c4494730197..ce2e49bea57 100644 --- a/ALICE3/TableProducer/CMakeLists.txt +++ b/ALICE3/TableProducer/CMakeLists.txt @@ -26,6 +26,11 @@ o2physics_add_dpl_workflow(alice3-centrality PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(alice3-multiplicity + SOURCES alice3Multiplicity.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(alice3-decaypreselector SOURCES alice3-decaypreselector.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index 45dee932571..f8c18ba2cb9 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -1776,7 +1776,7 @@ struct OnTheFlyTracker { trackParCov.getSigmaTgl2(), trackParCov.getSigma1PtY(), trackParCov.getSigma1PtZ(), trackParCov.getSigma1PtSnp(), trackParCov.getSigma1PtTgl(), trackParCov.getSigma1Pt2()); tableMcTrackLabels(trackParCov.mcLabel, 0); - tableTracksExtraA3(trackParCov.nSiliconHits, trackParCov.nTPCHits, trackParCov.trackType); + tableTracksExtraA3(trackParCov.nSiliconHits, trackParCov.nTPCHits, trackParCov.trackType, true); // populate extra tables if required to do so if (populateTracksExtra) { diff --git a/ALICE3/TableProducer/alice3Multiplicity.cxx b/ALICE3/TableProducer/alice3Multiplicity.cxx new file mode 100644 index 00000000000..005dada70c2 --- /dev/null +++ b/ALICE3/TableProducer/alice3Multiplicity.cxx @@ -0,0 +1,131 @@ +// Copyright 2019-2026 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. +// +/// \author Alexander Tiekoetter , Muenster +/// \brief Multiplicity task for ALICE3 +/// \file alice3Multiplicity.cxx + +#include "ALICE3/DataModel/tracksAlice3.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#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; + +using TracksAlice3 = soa::Join; + +constexpr float EtaHalf = 0.5; +constexpr float Eta1 = 1.0; + +struct Alice3Multiplicity { + Produces multPV; + Produces multGlobal; + + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + Configurable minEta{"minEta", -2.5f, "Minimum eta in range for global track counting"}; + Configurable maxEta{"maxEta", 2.5f, "Maximum eta in range for global track counting"}; + Configurable maxDCAxy{"maxDCAxy", 0.0025f, "Max DCAxy for global track counting"}; + Configurable maxDCAz{"maxDCAz", 0.0025f, "Max DCAz for global track counting"}; + Configurable minSiliconHits{"minSiliconHits", 5, "Minimum number of hits in silicon detector for global track counting"}; + Configurable requireReconstructed{"requireReconstructed", false, "Require track to be reconstructed for global track counting"}; + Configurable doQA{"doQA", true, "Fill QA histograms"}; + + ConfigurableAxis axisMult{"axisMult", {10000, 0, 10000}, "Reconstructed tracks"}; + + Filter trackFilter = (aod::track::eta >= minEta) && (aod::track::eta <= maxEta) && (nabs(aod::track::dcaXY) <= maxDCAxy) && (nabs(aod::track::dcaZ) <= maxDCAz) && (aod::track_alice3::nSiliconHits >= minSiliconHits) && (!requireReconstructed || aod::track_alice3::isReconstructed); + + void init(InitContext&) + { + if (doQA) { + histos.add("multiplicity/nTracksPV", "nTracksPV", kTH1D, {axisMult}); + histos.add("multiplicity/nTracksPVeta1", "nTracksPVeta1", kTH1D, {axisMult}); + histos.add("multiplicity/nTracksPVetaHalf", "nTracksPVetaHalf", kTH1D, {axisMult}); + histos.add("multiplicity/nTracksGlobal", "nTracksGlobal", kTH1D, {axisMult}); + histos.add("multiplicity/nTracksGlobalPV", "nTracksGlobalPV", kTH1D, {axisMult}); + } + } + + void processGlobalTracks(const aod::Collision& /*collision*/, const soa::Filtered& tracks) + { + int globalTracks = 0; + int globalTracksPV = 0; + + for (const auto& track : tracks) { + ++globalTracks; + if (track.isPVContributor()) + ++globalTracksPV; + } + + if (doQA) { + histos.fill(HIST("multiplicity/nTracksGlobal"), globalTracks); + histos.fill(HIST("multiplicity/nTracksGlobalPV"), globalTracksPV); + } + + multGlobal(globalTracks, globalTracksPV, 0, 0); + } + + void processPV(const aod::Collision& /*collision*/, const TracksAlice3& tracks) + { + int numTracksPV = 0; + int numTracksPVeta1 = 0; + int numTracksPVetaHalf = 0; + + for (const auto& track : tracks) { + if (track.isPVContributor()) { + ++numTracksPV; + if (std::abs(track.eta()) < Eta1) + ++numTracksPVeta1; + if (std::abs(track.eta()) < EtaHalf) + ++numTracksPVetaHalf; + } + } + + if (doQA) { + histos.fill(HIST("multiplicity/nTracksPV"), numTracksPV); + histos.fill(HIST("multiplicity/nTracksPVeta1"), numTracksPVeta1); + histos.fill(HIST("multiplicity/nTracksPVetaHalf"), numTracksPVetaHalf); + } + + multPV(numTracksPV, numTracksPVeta1, numTracksPVetaHalf); + } + + void processDummy(const aod::Collision&) + { + // do nothing + } + + PROCESS_SWITCH(Alice3Multiplicity, processGlobalTracks, "Process global track counter", false); + PROCESS_SWITCH(Alice3Multiplicity, processPV, "Process primary vertex contributor tracks", false); + PROCESS_SWITCH(Alice3Multiplicity, processDummy, "Dummy proccess function", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/ALICE3/TableProducer/alice3TrackingTranslator.cxx b/ALICE3/TableProducer/alice3TrackingTranslator.cxx index d9b2d3874f6..560e511e4f2 100644 --- a/ALICE3/TableProducer/alice3TrackingTranslator.cxx +++ b/ALICE3/TableProducer/alice3TrackingTranslator.cxx @@ -583,7 +583,8 @@ struct Alice3TrackingTranslator { tableTracksExtraA3(m_nMeasurements, // nSiliconHits (using m_nMeasurements as proxy) 0, // nTPCHits - 0); // trackType + 0, // trackType + false); // isPVContributor // Fill extra track info tableStoredTracksExtra(0.f, // TPCInnerParam From 46f0ac9c5f9e8a4fab27b160c86e74d2c79e4b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Tiek=C3=B6tter?= Date: Fri, 21 Aug 2026 14:35:28 +0200 Subject: [PATCH 2/5] Implemented MC estimator --- ALICE3/DataModel/collisionAlice3.h | 14 +++++ ALICE3/TableProducer/alice3Multiplicity.cxx | 59 +++++++++++++++++++-- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/ALICE3/DataModel/collisionAlice3.h b/ALICE3/DataModel/collisionAlice3.h index a1238e9e1d9..e0a9a2f7a76 100644 --- a/ALICE3/DataModel/collisionAlice3.h +++ b/ALICE3/DataModel/collisionAlice3.h @@ -32,6 +32,20 @@ DECLARE_SOA_TABLE(CollisionsAlice3, "AOD", "COLLALICE3", using CollisionAlice3 = CollisionsAlice3::iterator; +namespace mcmult_alice3 +{ +DECLARE_SOA_COLUMN(MultMC, multMC, int); //! Total MCTruth multiplicity +DECLARE_SOA_COLUMN(MultMC25, multMC25, int); //! MCTruth multiplicity in |eta| < 2.5 +DECLARE_SOA_COLUMN(MultMC125, multMC125, int); //! MCTruth multiplicity in |eta| < 1.25 +DECLARE_SOA_COLUMN(MultMC09, multMC09, int); //! MCTruth multiplicity in |eta| < 0.9 +} // namespace mcmult_alice3 +DECLARE_SOA_TABLE(MultsMCAlice3, "AOD", "MULTMCALICE3", + mcmult_alice3::MultMC, + mcmult_alice3::MultMC25, + mcmult_alice3::MultMC125, + mcmult_alice3::MultMC09); + +using MultMCAlice3 = MultsMCAlice3::iterator; } // namespace o2::aod #endif // ALICE3_DATAMODEL_COLLISIONALICE3_H_ diff --git a/ALICE3/TableProducer/alice3Multiplicity.cxx b/ALICE3/TableProducer/alice3Multiplicity.cxx index 005dada70c2..baa2fed178c 100644 --- a/ALICE3/TableProducer/alice3Multiplicity.cxx +++ b/ALICE3/TableProducer/alice3Multiplicity.cxx @@ -13,6 +13,7 @@ /// \brief Multiplicity task for ALICE3 /// \file alice3Multiplicity.cxx +#include "ALICE3/DataModel/collisionAlice3.h" #include "ALICE3/DataModel/tracksAlice3.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -26,6 +27,7 @@ #include #include #include +#include #include #include @@ -40,12 +42,10 @@ using namespace o2::framework::expressions; using TracksAlice3 = soa::Join; -constexpr float EtaHalf = 0.5; -constexpr float Eta1 = 1.0; - struct Alice3Multiplicity { Produces multPV; Produces multGlobal; + Produces multMC; HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; Configurable minEta{"minEta", -2.5f, "Minimum eta in range for global track counting"}; @@ -58,6 +58,8 @@ struct Alice3Multiplicity { ConfigurableAxis axisMult{"axisMult", {10000, 0, 10000}, "Reconstructed tracks"}; + Service pdg; + Filter trackFilter = (aod::track::eta >= minEta) && (aod::track::eta <= maxEta) && (nabs(aod::track::dcaXY) <= maxDCAxy) && (nabs(aod::track::dcaZ) <= maxDCAz) && (aod::track_alice3::nSiliconHits >= minSiliconHits) && (!requireReconstructed || aod::track_alice3::isReconstructed); void init(InitContext&) @@ -66,8 +68,14 @@ struct Alice3Multiplicity { histos.add("multiplicity/nTracksPV", "nTracksPV", kTH1D, {axisMult}); histos.add("multiplicity/nTracksPVeta1", "nTracksPVeta1", kTH1D, {axisMult}); histos.add("multiplicity/nTracksPVetaHalf", "nTracksPVetaHalf", kTH1D, {axisMult}); + histos.add("multiplicity/nTracksGlobal", "nTracksGlobal", kTH1D, {axisMult}); histos.add("multiplicity/nTracksGlobalPV", "nTracksGlobalPV", kTH1D, {axisMult}); + + histos.add("multiplicity/nTracksMC", "nTracksMC", kTH1D, {axisMult}); + histos.add("multiplicity/nTracksMCEta25", "nTracksMCEta25", kTH1D, {axisMult}); + histos.add("multiplicity/nTracksMCEta125", "nTracksMCEta125", kTH1D, {axisMult}); + histos.add("multiplicity/nTracksMCEta09", "nTracksMCEta09", kTH1D, {axisMult}); } } @@ -99,9 +107,9 @@ struct Alice3Multiplicity { for (const auto& track : tracks) { if (track.isPVContributor()) { ++numTracksPV; - if (std::abs(track.eta()) < Eta1) + if (std::abs(track.eta()) < 1.0) ++numTracksPVeta1; - if (std::abs(track.eta()) < EtaHalf) + if (std::abs(track.eta()) < 0.5) ++numTracksPVetaHalf; } } @@ -115,6 +123,46 @@ struct Alice3Multiplicity { multPV(numTracksPV, numTracksPVeta1, numTracksPVetaHalf); } + void processMC(aod::McCollision const& /*mcCollision*/, aod::McParticles const& mcParticles) + { + int numMCParticles = 0; + int numMCParticlesEta25 = 0; + int numMCParticlesEta125 = 0; + int numMCParticlesEta09 = 0; + + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + + auto charge = 0.; + auto* p = pdg->GetParticle(mcParticle.pdgCode()); + if (p != nullptr) { + charge = p->Charge(); + } + if (std::abs(charge) < 1e-3) { + continue; + } + + ++numMCParticles; + if (std::abs(mcParticle.eta()) < 2.5) + ++numMCParticlesEta25; + if (std::abs(mcParticle.eta()) < 1.25) + ++numMCParticlesEta125; + if (std::abs(mcParticle.eta()) < 0.9) + ++numMCParticlesEta09; + } + + if (doQA) { + histos.fill(HIST("multiplicity/nTracksMC"), numMCParticles); + histos.fill(HIST("multiplicity/nTracksMCEta25"), numMCParticlesEta25); + histos.fill(HIST("multiplicity/nTracksMCEta125"), numMCParticlesEta125); + histos.fill(HIST("multiplicity/nTracksMCEta09"), numMCParticlesEta09); + } + + multMC(numMCParticles, numMCParticlesEta25, numMCParticlesEta125, numMCParticlesEta09); + } + void processDummy(const aod::Collision&) { // do nothing @@ -122,6 +170,7 @@ struct Alice3Multiplicity { PROCESS_SWITCH(Alice3Multiplicity, processGlobalTracks, "Process global track counter", false); PROCESS_SWITCH(Alice3Multiplicity, processPV, "Process primary vertex contributor tracks", false); + PROCESS_SWITCH(Alice3Multiplicity, processMC, "Process MC truth information", false); PROCESS_SWITCH(Alice3Multiplicity, processDummy, "Dummy proccess function", true); }; From 427774c958d9cf7b14c62a7b68264d28a1dd3278 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Fri, 21 Aug 2026 12:39:03 +0000 Subject: [PATCH 3/5] Please consider the following formatting changes --- ALICE3/DataModel/tracksAlice3.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ALICE3/DataModel/tracksAlice3.h b/ALICE3/DataModel/tracksAlice3.h index 4b587f28e60..afd491ab4b2 100644 --- a/ALICE3/DataModel/tracksAlice3.h +++ b/ALICE3/DataModel/tracksAlice3.h @@ -31,7 +31,7 @@ DECLARE_SOA_COLUMN(NSiliconHits, nSiliconHits, int); //! number of silico DECLARE_SOA_COLUMN(NTPCHits, nTPCHits, int); //! number of tpc hits DECLARE_SOA_COLUMN(PdgCode, pdgCode, int); //! PDG code of the linked truth MC particle DECLARE_SOA_COLUMN(TrackType, trackType, int); //! Type of the track -DECLARE_SOA_COLUMN(IsPVContributor, isPVContributor, bool); //! Has track contributed to the PV fit? +DECLARE_SOA_COLUMN(IsPVContributor, isPVContributor, bool); //! Has track contributed to the PV fit? } // namespace track_alice3 DECLARE_SOA_TABLE(TracksAlice3, "AOD", "TRACKSALICE3", track_alice3::IsReconstructed); From b1549c86149bab903970ba1c33b8ee4214958f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Tiek=C3=B6tter?= Date: Mon, 24 Aug 2026 12:28:57 +0200 Subject: [PATCH 4/5] Actually check for track being PV contributor and set flag accordingly. --- ALICE3/TableProducer/OTF/onTheFlyTracker.cxx | 49 +++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index f8c18ba2cb9..1e0e89ac7e3 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -283,6 +283,7 @@ struct OnTheFlyTracker { const float time = 0, const float timeError = 1, bool decayDauInput = false, + bool isPVContributorInput = false, bool weakDecayDauInput = false, int isUsedInCascadingInput = 0, int nSiliconHitsInput = 0, @@ -291,6 +292,7 @@ struct OnTheFlyTracker { mcLabel{label}, timeEst{time, timeError}, isDecayDau(decayDauInput), + isPVContributor(isPVContributorInput), isWeakDecayDau(weakDecayDauInput), isUsedInCascading(isUsedInCascadingInput), nSiliconHits(nSiliconHitsInput), @@ -300,6 +302,7 @@ struct OnTheFlyTracker { int64_t mcLabel; TimeEst timeEst; ///< time estimate in ns bool isDecayDau; + bool isPVContributor; bool isWeakDecayDau; int isUsedInCascading; // 0: not at all, 1: is a cascade, 2: is a bachelor, 3: is a pion, 4: is a proton int nSiliconHits; @@ -992,13 +995,13 @@ struct OnTheFlyTracker { thisCascade.cascadeTrackId = trackTableOffset + 4; float trackTime = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; - tracksCascadeProngs.push_back(TrackAlice3{xiDaughterTrackParCovsPerfect[0], mcParticle.globalIndex(), trackTime, timeResolutionUs, true, true, 1, -1, -1, TrackType::kGenCascDaug}); + tracksCascadeProngs.push_back(TrackAlice3{xiDaughterTrackParCovsPerfect[0], mcParticle.globalIndex(), trackTime, timeResolutionUs, true, false, true, 1, -1, -1, TrackType::kGenCascDaug}); trackTime = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; - tracksCascadeProngs.push_back(TrackAlice3{xiDaughterTrackParCovsPerfect[1], mcParticle.globalIndex(), trackTime, timeResolutionUs, true, true, 2, -1, -1, TrackType::kGenCascDaug}); + tracksCascadeProngs.push_back(TrackAlice3{xiDaughterTrackParCovsPerfect[1], mcParticle.globalIndex(), trackTime, timeResolutionUs, true, false, true, 2, -1, -1, TrackType::kGenCascDaug}); trackTime = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; - tracksCascadeProngs.push_back(TrackAlice3{xiDaughterTrackParCovsPerfect[2], mcParticle.globalIndex(), trackTime, timeResolutionUs, true, true, 3, -1, -1, TrackType::kGenCascDaug}); + tracksCascadeProngs.push_back(TrackAlice3{xiDaughterTrackParCovsPerfect[2], mcParticle.globalIndex(), trackTime, timeResolutionUs, true, false, true, 3, -1, -1, TrackType::kGenCascDaug}); trackTime = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; - tracksCascadeProngs.push_back(TrackAlice3{perfectCascadeTrack, mcParticle.globalIndex(), trackTime, timeResolutionUs, true, true, 3, -1, -1, TrackType::kGenCascDaug}); + tracksCascadeProngs.push_back(TrackAlice3{perfectCascadeTrack, mcParticle.globalIndex(), trackTime, timeResolutionUs, true, false, true, 3, -1, -1, TrackType::kGenCascDaug}); for (int i = 0; i < kCascProngs; i++) { isReco[i] = false; @@ -1049,7 +1052,7 @@ struct OnTheFlyTracker { trackTime = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; // TODO: add flag for whether it's a ghost track or not, currently assuming all are reconstructed tracks if they pass the fast tracker requirements TrackType trackType = isReco[i] ? TrackType::kRecoCascDaug : TrackType::kGenCascDaug; - tracksCascadeProngs[i] = TrackAlice3{xiDaughterTrackParCovsTracked[i], mcParticle.globalIndex(), trackTime, timeResolutionUs, true, true, i + 2, nSiliconHitsCascadeProngs[i], nTPCHitsCascadeProngs[i], trackType}; + tracksCascadeProngs[i] = TrackAlice3{xiDaughterTrackParCovsTracked[i], mcParticle.globalIndex(), trackTime, timeResolutionUs, true, false, true, i + 2, nSiliconHitsCascadeProngs[i], nTPCHitsCascadeProngs[i], trackType}; } bool tryKinkReco = false; @@ -1260,7 +1263,7 @@ struct OnTheFlyTracker { return; // We didn't find enough hits for strangeness tracking } } - tracksCascadeProngs[kCascProngs] = TrackAlice3{cascadeTrack, mcParticle.globalIndex(), trackTime, timeResolutionUs, false, false, 1, thisCascade.foundClusters, TrackType::kGenCascDaug}; + tracksCascadeProngs[kCascProngs] = TrackAlice3{cascadeTrack, mcParticle.globalIndex(), trackTime, timeResolutionUs, false, false, false, 1, thisCascade.foundClusters, TrackType::kGenCascDaug}; fillCascadeTable = true; } } @@ -1331,7 +1334,7 @@ struct OnTheFlyTracker { newCascadeTrack.setPID(pdgCodeToPID(PDG_t::kXiMinus)); // FIXME: not OK for omegas float trackTime = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; if (reconstructedCascade) { - tracksCascadeProngs[kCascProngs + 1] = TrackAlice3{newCascadeTrack, mcParticle.globalIndex(), trackTime, timeResolutionUs, false, false, 1, thisCascade.foundClusters, TrackType::kRecoCascDaug}; + tracksCascadeProngs[kCascProngs + 1] = TrackAlice3{newCascadeTrack, mcParticle.globalIndex(), trackTime, timeResolutionUs, false, false, false, 1, thisCascade.foundClusters, TrackType::kRecoCascDaug}; } fillCascadeTable = true; } // end fitter OK @@ -1482,9 +1485,9 @@ struct OnTheFlyTracker { // Store not reconstructed daughters, will update them in case reconstruction is successful float trackTime = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; - tracksV0Daugs.push_back(TrackAlice3{v0DaughterTrackParCovsPerfect[0], mcParticle.globalIndex(), 0.f, timeResolutionUs, true, true, 1, TrackType::kGhostV0Daug}); + tracksV0Daugs.push_back(TrackAlice3{v0DaughterTrackParCovsPerfect[0], mcParticle.globalIndex(), 0.f, timeResolutionUs, true, false, true, 1, TrackType::kGhostV0Daug}); trackTime = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; - tracksV0Daugs.push_back(TrackAlice3{v0DaughterTrackParCovsPerfect[1], mcParticle.globalIndex(), 0.f, timeResolutionUs, true, true, 1, TrackType::kGhostV0Daug}); + tracksV0Daugs.push_back(TrackAlice3{v0DaughterTrackParCovsPerfect[1], mcParticle.globalIndex(), 0.f, timeResolutionUs, true, false, true, 1, TrackType::kGhostV0Daug}); bool fillV0Table{false}; for (int i = 0; i < kv0Prongs; i++) { @@ -1521,7 +1524,7 @@ struct OnTheFlyTracker { trackTime = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; // TODO: flag to separate ghost and reco tracks TrackType trackType = isV0Reco[i] ? TrackType::kRecoV0Daug : TrackType::kGhostV0Daug; - tracksV0Daugs[i] = TrackAlice3{v0DaughterTrackParCovsTracked[i], mcParticle.globalIndex(), trackTime, timeResolutionUs, true, true, i + 2, trackType}; + tracksV0Daugs[i] = TrackAlice3{v0DaughterTrackParCovsTracked[i], mcParticle.globalIndex(), trackTime, timeResolutionUs, true, false, true, i + 2, trackType}; } if (v0DecaySettings.doV0QA) { if (isV0Reco[0] && isV0Reco[1]) { @@ -1672,8 +1675,8 @@ struct OnTheFlyTracker { /// \param prmTrks the vector of tracks to be used for vertex reconstruction /// \param primaryVertex the output variable where the computed primary vertex will be stored /// \param icfg index of the current configuration, used for histogram filling - template - void computeVertex(McCollisionType& mcCollision, const std::vector& prmTrks, o2::vertexing::PVertex& primaryVertex, const int icfg) + template + void computeVertex(McCollisionType& mcCollision, std::vector& prmTrks, o2::vertexing::PVertex& primaryVertex, const int icfg) { if (!enablePrimaryVertexing) { @@ -1725,7 +1728,18 @@ struct OnTheFlyTracker { largestVertex = iv; } } + primaryVertex = vertices[largestVertex]; + + const auto& contributorRef = v2tRefs[largestVertex]; + const int first = contributorRef.getFirstEntry(); + const int end = first + contributorRef.getEntries(); + + for (int i = first; i < end; ++i) { + const auto trackIndex = vertexTrackIDs[i].getIndex(); + prmTrks[trackIndex].isPVContributor = true; + } + if (doExtraQA) { histos.fill(HIST("h2dVerticesVsContributors"), primaryVertex.getNContributors(), n_vertices); } @@ -1776,7 +1790,7 @@ struct OnTheFlyTracker { trackParCov.getSigmaTgl2(), trackParCov.getSigma1PtY(), trackParCov.getSigma1PtZ(), trackParCov.getSigma1PtSnp(), trackParCov.getSigma1PtTgl(), trackParCov.getSigma1Pt2()); tableMcTrackLabels(trackParCov.mcLabel, 0); - tableTracksExtraA3(trackParCov.nSiliconHits, trackParCov.nTPCHits, trackParCov.trackType, true); + tableTracksExtraA3(trackParCov.nSiliconHits, trackParCov.nTPCHits, trackParCov.trackType, trackParCov.isPVContributor); // populate extra tables if required to do so if (populateTracksExtra) { @@ -1969,10 +1983,11 @@ struct OnTheFlyTracker { // Time associated to the mcParticle: collision time + smearing float trackTime = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; TrackType trackType = reconstructed ? TrackType::kRecoPrimary : TrackType::kGhostPrimary; + bool isPVContributor = trackType == TrackType::kRecoPrimary; if (reconstructed) { - recoPrimaries.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), trackTime, timeResolutionUs, isDecayDaughter, false, 0, nTrkHits, trackType}); + recoPrimaries.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), trackTime, timeResolutionUs, isDecayDaughter, isPVContributor, false, 0, nTrkHits, trackType}); } else { - ghostPrimaries.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), trackTime, timeResolutionUs, isDecayDaughter, false, 0, nTrkHits, trackType}); + ghostPrimaries.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), trackTime, timeResolutionUs, isDecayDaughter, isPVContributor, false, 0, nTrkHits, trackType}); } } @@ -2194,10 +2209,10 @@ struct OnTheFlyTracker { } if (reconstructed) { - tracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isSecondary, false, 0, nTrkHits, kRecoPrimary}); + tracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isSecondary, false, true, false, 0, nTrkHits, kRecoPrimary}); getHist(TH1, histPath + "hPtReconstructedPr")->Fill(trackParCov.getPt()); } else { - ghostTracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isSecondary, false, 0, nTrkHits, kGhostPrimary}); + ghostTracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isSecondary, false, false, false, 0, nTrkHits, kGhostPrimary}); } } From 5cdbb84801adf3ad197b5eca9114e8d9936209d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Tiek=C3=B6tter?= Date: Mon, 24 Aug 2026 12:58:10 +0200 Subject: [PATCH 5/5] Resolve merging conflicts --- ALICE3/TableProducer/OTF/onTheFlyTracker.cxx | 4 +--- ALICE3/TableProducer/alice3TrackingTranslator.cxx | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index 8a1d261bc93..5cd2c72412f 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -2223,9 +2223,7 @@ struct OnTheFlyTracker { } if (reconstructed) { - tracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isSecondary, false, true, false, 0, nTrkHits, kRecoPrimary}); - getHist(TH1, histPath + "hPtReconstructedPr")->Fill(trackParCov.getPt()); - tracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isSecondary, false, false, 0, nTrkHits, kRecoPrimary}); + tracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isSecondary, true, false, 0, nTrkHits, kRecoPrimary}); getHist(histPath + "hPtReconstructedPr")->Fill(trackParCov.getPt()); } else { ghostTracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isSecondary, false, false, false, 0, nTrkHits, kGhostPrimary}); diff --git a/ALICE3/TableProducer/alice3TrackingTranslator.cxx b/ALICE3/TableProducer/alice3TrackingTranslator.cxx index 4a915de9fda..ccdcbcf2ac0 100644 --- a/ALICE3/TableProducer/alice3TrackingTranslator.cxx +++ b/ALICE3/TableProducer/alice3TrackingTranslator.cxx @@ -711,8 +711,7 @@ struct Alice3TrackingTranslator { tableTracksExtraA3(m_nMeasurements, // nSiliconHits (using m_nMeasurements as proxy) 0, // nTPCHits 0, // trackType - false, // isPVContributor - 0); // trackType + false); // isPVContributor std::cout << "Filling TracksExtraA3 table" << std::endl; // Fill extra track info tableStoredTracksExtra(0.f, // TPCInnerParam