From 33f3a50c950e35bc652758337b58bcacaf971739 Mon Sep 17 00:00:00 2001 From: Evgeny Kryshen Date: Sun, 15 Nov 2026 23:07:24 +0300 Subject: [PATCH 1/2] Added flags and occupancy in MC table --- PWGUD/TableProducer/upcCandProducerBarrel.cxx | 224 +++++++++--------- 1 file changed, 111 insertions(+), 113 deletions(-) diff --git a/PWGUD/TableProducer/upcCandProducerBarrel.cxx b/PWGUD/TableProducer/upcCandProducerBarrel.cxx index 583fc4b788a..545f6f62d24 100644 --- a/PWGUD/TableProducer/upcCandProducerBarrel.cxx +++ b/PWGUD/TableProducer/upcCandProducerBarrel.cxx @@ -209,6 +209,8 @@ DECLARE_SOA_TABLE(UPCBarrelCands, "AOD", "UPCBARRELCANDS", DECLARE_SOA_TABLE(UPCBarrelMcColls, "AOD", "UPCBMCCOLL", upc_cand_prod_bar::TfId, upc_cand_prod_bar::GlobalBC, + upc_cand_prod_bar::Flags, + upc_cand_prod_bar::OccupancyFT0C, upc_cand_prod_bar::PosX, upc_cand_prod_bar::PosY, upc_cand_prod_bar::PosZ, @@ -343,8 +345,6 @@ struct UpcCandProducerBarrel { registry.add("hTF", "TF counts", HistType::kTH1D, {axisTFs}); registry.add("hTVX", "TVX counts", HistType::kTH2D, {axisBCs, axisTFs}); registry.add("hTVXRCT", "TVX counts after RCT selection", HistType::kTH2D, {axisBCs, axisTFs}); - registry.add("hTVXupc", "TVX counts in upc ROFs", HistType::kTH2D, {axisBCs, axisTFs}); - registry.add("hTVXRCTupc", "TVX counts after RCT selection in upc ROFs", HistType::kTH2D, {axisBCs, axisTFs}); registry.add("hVetoT00", "no RCT selection", HistType::kTH3D, {axisBCs, axisTFs, axisVeto}); registry.add("hVetoTV0", "no RCT selection", HistType::kTH3D, {axisBCs, axisTFs, axisVeto}); @@ -429,81 +429,37 @@ struct UpcCandProducerBarrel { } LOGP(info, "Starting new DF. Number of TFs = {}", tfIDs.size()); - std::unordered_map signalParticleRefs; - if constexpr (isMC) { - std::unordered_set ambiguousTrackIds; - ambiguousTrackIds.reserve(ambiguousTracks->size()); - for (const auto& ambiguousTrack : *ambiguousTracks) { - ambiguousTrackIds.insert(ambiguousTrack.trackId()); - } + std::vector bcsWithFT0, bcsWithFV0, bcsWithFDD; + bcsWithFT0.reserve(ft0s.size()); + bcsWithFV0.reserve(fv0s.size()); + bcsWithFDD.reserve(fdds.size()); - std::vector bcsWithMCCollision; - bcsWithMCCollision.reserve(mcCollisions->size()); - // Use collisions from every source and retain same-BC pile-up - for (const auto& mcCollision : *mcCollisions) { - bcsWithMCCollision.push_back(static_cast(mcCollision.template bc_as().globalBC())); + LOGP(debug, "Filling FT0 activity arrays"); + for (const auto& ft0 : ft0s) { + const float sumAmpFT0A = ft0.sumAmpA(); + const float sumAmpFT0C = ft0.sumAmpC(); + if ((ft0.timeA() < MaxFITTime && sumAmpFT0A >= minAmpFT0A) || (ft0.timeC() < MaxFITTime && sumAmpFT0C >= minAmpFT0C)) { + bcsWithFT0.push_back(ft0.bc_as().globalBC()); } - const auto minDistanceMC = buildMinimumDistanceMap(tfIDs, bcSOR, nBCsPerTF, bcsWithMCCollision, maxStoredDistance, true); - - for (const auto& mcCollision : *mcCollisions) { - const auto bc = mcCollision.template bc_as(); - const auto globalBC = bc.globalBC(); - const auto iTF = localTFIndex[bc.globalIndex()]; - const auto bcInTF = (static_cast(globalBC) - bcSOR) % nBCsPerTF; - const auto particles = mcParticles->sliceBy(particlesPerMCCollision, mcCollision.globalIndex()); - const bool isSignal = mcCollision.getSourceId() == signalSourceId.value; + } - std::vector px, py, pz; - std::vector pdg, recoCollisionIds; - std::vector recoFlags; - int32_t mult = 0; - // Output rows follow input MC collisions, making this the compact collision label - const auto newMCCollisionId = static_cast(selectedMCCollisions.lastIndex() + 1); - for (const auto& particle : particles) { - mult += particle.isPhysicalPrimary(); - // Background rows keep only collision metadata and physical-primary multiplicity - if (!isSignal) { - continue; - } - const auto newMCParticleId = static_cast(pdg.size()); - px.push_back(particle.px()); - py.push_back(particle.py()); - pz.push_back(particle.pz()); - pdg.push_back(particle.pdgCode()); + LOGP(debug, "Filling FV0 activity arrays"); + for (const auto& fv0 : fv0s) { + const float sumAmpFV0A = std::accumulate(fv0.amplitude().begin(), fv0.amplitude().end(), 0.f); + if (fv0.time() < MaxFITTime && sumAmpFV0A >= minAmpFV0A) { + bcsWithFV0.push_back(fv0.bc_as().globalBC()); + } + } - uint8_t flags = particle.isPhysicalPrimary() ? kPhysicalPrimary : kNoFlags; - int32_t recoCollisionId = NoRecoCollision; - int nRecoTracks = 0; - // Inspect only reconstructed tracks matched to this signal particle - for (const auto& track : tracks.sliceBy(tracksPerMCParticle, particle.globalIndex())) { - if ((track.mcMask() & MCTrackFakeMask) != 0u) { - continue; - } - ++nRecoTracks; - flags |= kHasRecoTrack; - flags |= track.isPVContributor() ? kHasPVContributor : kNoFlags; - flags |= ambiguousTrackIds.contains(track.globalIndex()) ? kHasAmbiguousTrack : kNoFlags; - if (track.has_collision()) { - recoCollisionId = track.collisionId(); - flags |= collisions.iteratorAt(recoCollisionId).numContrib() > nTracks ? kHighMultiplicityCollision : kNoFlags; - } - } - // A single collision label is meaningful only for exactly one reconstructed track - if (nRecoTracks > 1) { - recoCollisionId = MultipleRecoTracks; - } - recoFlags.push_back(flags); - recoCollisionIds.push_back(recoCollisionId); - // Remap original particle IDs to output index for candidate labels - signalParticleRefs.emplace(particle.globalIndex(), SignalRef{newMCCollisionId, newMCParticleId}); - } - selectedMCCollisions(tfIDs[iTF], globalBC, mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), - px, py, pz, pdg, mult, minDistanceMC[iTF][bcInTF], - recoFlags, recoCollisionIds, isSignal); + LOGP(debug, "Filling FDD activity arrays"); + for (const auto& fdd : fdds) { + const float sumAmpFDDA = std::accumulate(std::begin(fdd.chargeA()), std::end(fdd.chargeA()), 0.f); + const float sumAmpFDDC = std::accumulate(std::begin(fdd.chargeC()), std::end(fdd.chargeC()), 0.f); + if ((fdd.timeA() < MaxFITTime && sumAmpFDDA >= minAmpFDDA) || (fdd.timeC() < MaxFITTime && sumAmpFDDC >= minAmpFDDC)) { + bcsWithFDD.push_back(fdd.bc_as().globalBC()); } } - // collect number of all collisions and upc-mode collisions per ROF LOGP(debug, "Collect number of all collisions and upc-mode collisions per ROF"); std::vector> vMultTracks(tfIDs.size(), std::map()); std::vector> vCollisionsPerROF(tfIDs.size(), std::vector(nRofPerTF, 0)); @@ -524,16 +480,7 @@ struct UpcCandProducerBarrel { auto hTVX = registry.get(HIST("hTVX")); auto hTVXRCT = registry.get(HIST("hTVXRCT")); - auto hTVXupc = registry.get(HIST("hTVXupc")); - auto hTVXRCTupc = registry.get(HIST("hTVXRCTupc")); - - std::vector bcsWithFT0, bcsWithFV0, bcsWithFDD; - bcsWithFT0.reserve(ft0s.size()); - bcsWithFV0.reserve(fv0s.size()); - bcsWithFDD.reserve(fdds.size()); - LOGP(debug, "Starting lumi accounting"); - // lumi accounting std::vector> vMultFT0C(tfIDs.size(), std::map()); for (const auto& ft0 : ft0s) { const auto bc = ft0.bc_as(); @@ -542,8 +489,6 @@ struct UpcCandProducerBarrel { const int32_t bcInTF = (globalBC - bcSOR) % nBCsPerTF; const auto iTF = localTFIndex[bc.globalIndex()]; const auto tfID = tfIDs[iTF]; - const int32_t rofInTF = getRofInTF(bcInTF); - bool upcMode = vCollisionsPerROF[iTF][rofInTF] == 0 || vUpcModePerROF[iTF][rofInTF] > 0; // Multiplicity for FT0C-based occupancy estimates if (ft0.timeC() < MaxFITTime && ft0.sumAmpC() >= minAmpFT0C) { @@ -559,44 +504,12 @@ struct UpcCandProducerBarrel { } hTVX->Fill(bcInOrbit, tfID); - if (upcMode) { - hTVXupc->Fill(bcInOrbit, tfID); - } if (!bc.selection_bit(aod::evsel::kNoTimeFrameBorder) || !rctChecker(bc)) { continue; } hTVXRCT->Fill(bcInOrbit, tfID); - if (upcMode) { - hTVXRCTupc->Fill(bcInOrbit, tfID); - } - } - - LOGP(debug, "Filling FT0 activity arrays"); - for (const auto& ft0 : ft0s) { - const float sumAmpFT0A = ft0.sumAmpA(); - const float sumAmpFT0C = ft0.sumAmpC(); - if ((ft0.timeA() < MaxFITTime && sumAmpFT0A >= minAmpFT0A) || (ft0.timeC() < MaxFITTime && sumAmpFT0C >= minAmpFT0C)) { - bcsWithFT0.push_back(ft0.bc_as().globalBC()); - } - } - - LOGP(debug, "Filling FV0 activity arrays"); - for (const auto& fv0 : fv0s) { - const float sumAmpFV0A = std::accumulate(fv0.amplitude().begin(), fv0.amplitude().end(), 0.f); - if (fv0.time() < MaxFITTime && sumAmpFV0A >= minAmpFV0A) { - bcsWithFV0.push_back(fv0.bc_as().globalBC()); - } - } - - LOGP(debug, "Filling FDD activity arrays"); - for (const auto& fdd : fdds) { - const float sumAmpFDDA = std::accumulate(std::begin(fdd.chargeA()), std::end(fdd.chargeA()), 0.f); - const float sumAmpFDDC = std::accumulate(std::begin(fdd.chargeC()), std::end(fdd.chargeC()), 0.f); - if ((fdd.timeA() < MaxFITTime && sumAmpFDDA >= minAmpFDDA) || (fdd.timeC() < MaxFITTime && sumAmpFDDC >= minAmpFDDC)) { - bcsWithFDD.push_back(fdd.bc_as().globalBC()); - } } LOGP(debug, "Starting occupancy calculation"); @@ -620,6 +533,91 @@ struct UpcCandProducerBarrel { } } + std::unordered_map signalParticleRefs; + if constexpr (isMC) { + LOGP(debug, "Collecting MC info. Number of MC collisions = {}", mcCollisions->size()); + std::unordered_set ambiguousTrackIds; + ambiguousTrackIds.reserve(ambiguousTracks->size()); + for (const auto& ambiguousTrack : *ambiguousTracks) { + ambiguousTrackIds.insert(ambiguousTrack.trackId()); + } + + std::vector bcsWithMCCollision; + bcsWithMCCollision.reserve(mcCollisions->size()); + // Use collisions from every source and retain same-BC pile-up + for (const auto& mcCollision : *mcCollisions) { + bcsWithMCCollision.push_back(static_cast(mcCollision.template bc_as().globalBC())); + } + const auto minDistanceMC = buildMinimumDistanceMap(tfIDs, bcSOR, nBCsPerTF, bcsWithMCCollision, maxStoredDistance, true); + + for (const auto& mcCollision : *mcCollisions) { + const auto bc = mcCollision.template bc_as(); + const int64_t globalBC = bc.globalBC(); + const auto iTF = localTFIndex[bc.globalIndex()]; + const int64_t bcInTF = (globalBC - bcSOR) % nBCsPerTF; + LOGP(debug, "setting flags for MC collision"); + const int32_t rofInTF = getRofInTF(bcInTF); + const bool upcMode = vCollisionsPerROF[iTF][rofInTF] == 0 || vUpcModePerROF[iTF][rofInTF] > 0; + const bool noPileupInRof = vCollisionsPerROF[iTF][rofInTF] <= 1; + uint8_t flags = 0; + flags |= upcMode << 0; + flags |= noPileupInRof << 1; + const auto occupancyFT0C = vOccupancyFT0C[iTF][bcInTF]; + + const auto particles = mcParticles->sliceBy(particlesPerMCCollision, mcCollision.globalIndex()); + const bool isSignal = mcCollision.getSourceId() == signalSourceId.value; + LOGP(debug, "sourceId = {}", mcCollision.getSourceId()); + std::vector px, py, pz; + std::vector pdg, recoCollisionIds; + std::vector recoFlags; + int32_t mult = 0; + // Output rows follow input MC collisions, making this the compact collision label + const auto newMCCollisionId = static_cast(selectedMCCollisions.lastIndex() + 1); + for (const auto& particle : particles) { + mult += particle.isPhysicalPrimary(); + // Background rows keep only collision metadata and physical-primary multiplicity + if (!isSignal) { + continue; + } + const auto newMCParticleId = static_cast(pdg.size()); + px.push_back(particle.px()); + py.push_back(particle.py()); + pz.push_back(particle.pz()); + pdg.push_back(particle.pdgCode()); + + uint8_t flags = particle.isPhysicalPrimary() ? kPhysicalPrimary : kNoFlags; + int32_t recoCollisionId = NoRecoCollision; + int nRecoTracks = 0; + // Inspect only reconstructed tracks matched to this signal particle + for (const auto& track : tracks.sliceBy(tracksPerMCParticle, particle.globalIndex())) { + if ((track.mcMask() & MCTrackFakeMask) != 0u) { + continue; + } + ++nRecoTracks; + flags |= kHasRecoTrack; + flags |= track.isPVContributor() ? kHasPVContributor : kNoFlags; + flags |= ambiguousTrackIds.contains(track.globalIndex()) ? kHasAmbiguousTrack : kNoFlags; + if (track.has_collision()) { + recoCollisionId = track.collisionId(); + flags |= collisions.iteratorAt(recoCollisionId).numContrib() > nTracks ? kHighMultiplicityCollision : kNoFlags; + } + } + // A single collision label is meaningful only for exactly one reconstructed track + if (nRecoTracks > 1) { + recoCollisionId = MultipleRecoTracks; + } + recoFlags.push_back(flags); + recoCollisionIds.push_back(recoCollisionId); + // Remap original particle IDs to output index for candidate labels + signalParticleRefs.emplace(particle.globalIndex(), SignalRef{newMCCollisionId, newMCParticleId}); + } + selectedMCCollisions(tfIDs[iTF], globalBC, flags, occupancyFT0C, + mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), + px, py, pz, pdg, mult, minDistanceMC[iTF][bcInTF], + recoFlags, recoCollisionIds, isSignal); + } + } + LOGP(debug, "Building minimum distance maps"); const uint32_t scanDistance = std::max(maxStoredDistance.value, vetoBCWindow.value); const DistanceMap minDistanceFT0 = buildMinimumDistanceMap(tfIDs, bcSOR, nBCsPerTF, bcsWithFT0, scanDistance); From 7ff91b408b8f32c5799b0b4b730bc7fba731d66c Mon Sep 17 00:00:00 2001 From: Evgeny Kryshen Date: Sun, 15 Nov 2026 23:19:10 +0300 Subject: [PATCH 2/2] Megalinter fix: renamed flags to bcFlags --- PWGUD/TableProducer/upcCandProducerBarrel.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PWGUD/TableProducer/upcCandProducerBarrel.cxx b/PWGUD/TableProducer/upcCandProducerBarrel.cxx index 545f6f62d24..b27bd804808 100644 --- a/PWGUD/TableProducer/upcCandProducerBarrel.cxx +++ b/PWGUD/TableProducer/upcCandProducerBarrel.cxx @@ -559,9 +559,9 @@ struct UpcCandProducerBarrel { const int32_t rofInTF = getRofInTF(bcInTF); const bool upcMode = vCollisionsPerROF[iTF][rofInTF] == 0 || vUpcModePerROF[iTF][rofInTF] > 0; const bool noPileupInRof = vCollisionsPerROF[iTF][rofInTF] <= 1; - uint8_t flags = 0; - flags |= upcMode << 0; - flags |= noPileupInRof << 1; + uint8_t bcFlags = 0; + bcFlags |= upcMode << 0; + bcFlags |= noPileupInRof << 1; const auto occupancyFT0C = vOccupancyFT0C[iTF][bcInTF]; const auto particles = mcParticles->sliceBy(particlesPerMCCollision, mcCollision.globalIndex()); @@ -611,7 +611,7 @@ struct UpcCandProducerBarrel { // Remap original particle IDs to output index for candidate labels signalParticleRefs.emplace(particle.globalIndex(), SignalRef{newMCCollisionId, newMCParticleId}); } - selectedMCCollisions(tfIDs[iTF], globalBC, flags, occupancyFT0C, + selectedMCCollisions(tfIDs[iTF], globalBC, bcFlags, occupancyFT0C, mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), px, py, pz, pdg, mult, minDistanceMC[iTF][bcInTF], recoFlags, recoCollisionIds, isSignal);