From 572bd82cd28023fa275dbbcfa68ce736a18d43d1 Mon Sep 17 00:00:00 2001 From: jesgum Date: Tue, 9 Jun 2026 13:04:52 +0200 Subject: [PATCH 1/6] Fix indices bug in otf decayer --- ALICE3/Core/OTFParticle.h | 11 ++++++- ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx | 30 +++++++++++--------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/ALICE3/Core/OTFParticle.h b/ALICE3/Core/OTFParticle.h index 9f93ea59597..4088c39ac80 100644 --- a/ALICE3/Core/OTFParticle.h +++ b/ALICE3/Core/OTFParticle.h @@ -24,6 +24,7 @@ #include #include #include +#include #include namespace o2::upgrade @@ -88,6 +89,14 @@ class OTFParticle mPz = pz; mE = e; } + void setIndexOffset(const std::size_t offset) + { + static constexpr int NotFound = -1; + mIndicesMother[0] = (mIndicesMother[0] >= 0) ? mIndicesMother[0] + static_cast(offset) : NotFound; + mIndicesMother[1] = (mIndicesMother[1] >= 0) ? mIndicesMother[1] + static_cast(offset) : NotFound; + mIndicesDaughter[0] = (mIndicesDaughter[0] >= 0) ? mIndicesDaughter[0] + static_cast(offset) : NotFound; + mIndicesDaughter[1] = (mIndicesDaughter[1] >= 0) ? mIndicesDaughter[1] + static_cast(offset) : NotFound; + } // Getters int pdgCode() const { return mPdgCode; } @@ -171,7 +180,7 @@ class OTFParticle private: int mPdgCode{}, mGlobalIndex{-1}; - int mCollisionId{}; + int mCollisionId{-1}; float mVx{}, mVy{}, mVz{}, mVt{}; float mPx{}, mPy{}, mPz{}, mE{}; bool mIsAlive{}, mIsFromMcParticles{false}; diff --git a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx index b568364b80c..11ff0cd010b 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx @@ -79,6 +79,7 @@ struct OnTheFlyDecayer { o2::upgrade::Decayer decayer; Service pdgDB; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + std::vector> mcParticlesGrouped; Configurable seed{"seed", 0, "Set seed for particle decayer"}; Configurable magneticField{"magneticField", 20., "Magnetic field (kG)"}; @@ -86,9 +87,8 @@ struct OnTheFlyDecayer { {DefaultParameters[0], NumDecays, NumParameters, ParticleNames, ParameterNames}, "Enable option for particle to be decayed: 0 - no, 1 - yes"}; + std::size_t indexOffset = 0; static constexpr float PicoToNano = 1.e-3f; - int mCollisionId{-1}; - std::vector mEnabledDecays; void init(o2::framework::InitContext&) { @@ -154,7 +154,7 @@ struct OnTheFlyDecayer { particle.setIndicesDaughter(allParticles.size(), allParticles.size() + (decayStack.size() - 1)); for (o2::upgrade::OTFParticle daughter : decayStack) { daughter.setIndicesMother(i, i); - daughter.setCollisionId(mCollisionId); + daughter.setCollisionId(particle.collisionId()); daughter.setBitOn(o2::upgrade::DecayerBits::IsAlive); daughter.setBitOff(o2::upgrade::DecayerBits::IsPrimary); daughter.setProductionTime(trackTimeNS); @@ -173,18 +173,14 @@ struct OnTheFlyDecayer { void process(aod::McCollisions_001From>::iterator const& collision, aod::McParticles_001From> const& mcParticles) { allParticles.clear(); + if (collision.globalIndex() == 0) { + indexOffset = 0; + } // Reproduce collision table to have AOD origin - mCollisionId = collision.globalIndex(); - tableMcCollisions(collision.bcId(), - collision.generatorsID(), - collision.posX(), - collision.posY(), - collision.posZ(), - collision.t(), - collision.weight(), - collision.impactParameter(), - collision.eventPlaneAngle()); + tableMcCollisions(collision.bcId(), collision.generatorsID(), + collision.posX(), collision.posY(), collision.posZ(), collision.t(), + collision.weight(), collision.impactParameter(), collision.eventPlaneAngle()); // First we copy the particles from the table into a vector that is extendable for (const auto& particle : mcParticles) { @@ -195,7 +191,8 @@ struct OnTheFlyDecayer { decayParticles(0, allParticles.size()); // Fill output table - for (const auto& otfParticle : allParticles) { + for (auto& otfParticle : allParticles) { + otfParticle.setIndexOffset(indexOffset); if (otfParticle.hasNaN()) { histos.fill(HIST("hNaNBookkeeping"), 1); } else { @@ -208,6 +205,11 @@ struct OnTheFlyDecayer { otfParticle.px(), otfParticle.py(), otfParticle.pz(), otfParticle.e(), otfParticle.vx(), otfParticle.vy(), otfParticle.vz(), otfParticle.vt()); } + + // Particles for later collisions in df's needs to have thier mother + // and daughter indices adjusted since their global index will be + // shifted due to the appending of decay products + indexOffset += allParticles.size(); } }; From fac0b57aa9cd84ed2b320c944c1c5dfe75d3d78e Mon Sep 17 00:00:00 2001 From: jesgum Date: Tue, 9 Jun 2026 13:05:39 +0200 Subject: [PATCH 2/6] update --- ALICE3/Core/OTFParticle.h | 1 - 1 file changed, 1 deletion(-) diff --git a/ALICE3/Core/OTFParticle.h b/ALICE3/Core/OTFParticle.h index 4088c39ac80..4e600b99f62 100644 --- a/ALICE3/Core/OTFParticle.h +++ b/ALICE3/Core/OTFParticle.h @@ -24,7 +24,6 @@ #include #include #include -#include #include namespace o2::upgrade From da02d0c27d2547dfabc302f3642659fccae4655c Mon Sep 17 00:00:00 2001 From: jesgum Date: Tue, 9 Jun 2026 13:26:22 +0200 Subject: [PATCH 3/6] remove unused --- ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx index 11ff0cd010b..da010a889db 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx @@ -79,7 +79,6 @@ struct OnTheFlyDecayer { o2::upgrade::Decayer decayer; Service pdgDB; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - std::vector> mcParticlesGrouped; Configurable seed{"seed", 0, "Set seed for particle decayer"}; Configurable magneticField{"magneticField", 20., "Magnetic field (kG)"}; From bc39fbcb0a23179d6dcc75787b5b3b4f9f01da76 Mon Sep 17 00:00:00 2001 From: jesgum Date: Tue, 9 Jun 2026 14:03:52 +0200 Subject: [PATCH 4/6] fix offset --- ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx index da010a889db..fb6cd64fdc4 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx @@ -208,7 +208,7 @@ struct OnTheFlyDecayer { // Particles for later collisions in df's needs to have thier mother // and daughter indices adjusted since their global index will be // shifted due to the appending of decay products - indexOffset += allParticles.size(); + indexOffset += (allParticles.size() - mcParticles.size()); } }; From 2d572a0819bade859b3fe08334794051bd7a006c Mon Sep 17 00:00:00 2001 From: jesgum Date: Thu, 11 Jun 2026 09:26:54 +0200 Subject: [PATCH 5/6] fix const& in loops --- ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx index fb6cd64fdc4..81c717ab023 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx @@ -151,7 +151,7 @@ struct OnTheFlyDecayer { const float trackTimeNS = trackLength / trackVelocity * PicoToNano; particle.setIndicesDaughter(allParticles.size(), allParticles.size() + (decayStack.size() - 1)); - for (o2::upgrade::OTFParticle daughter : decayStack) { + for (const o2::upgrade::OTFParticle& daughter : decayStack) { daughter.setIndicesMother(i, i); daughter.setCollisionId(particle.collisionId()); daughter.setBitOn(o2::upgrade::DecayerBits::IsAlive); @@ -190,7 +190,7 @@ struct OnTheFlyDecayer { decayParticles(0, allParticles.size()); // Fill output table - for (auto& otfParticle : allParticles) { + for (const o2::upgrade::OTFParticle& otfParticle : allParticles) { otfParticle.setIndexOffset(indexOffset); if (otfParticle.hasNaN()) { histos.fill(HIST("hNaNBookkeeping"), 1); From c490e9017134f5f72204880987194b0dc902913e Mon Sep 17 00:00:00 2001 From: jesgum Date: Fri, 12 Jun 2026 15:00:17 +0200 Subject: [PATCH 6/6] anton's fixes --- ALICE3/Core/OTFParticle.h | 4 ++-- ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx | 24 ++++++++++++-------- ALICE3/Tasks/alice3DecayerQa.cxx | 17 +++++++------- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/ALICE3/Core/OTFParticle.h b/ALICE3/Core/OTFParticle.h index 4e600b99f62..0f2d85ac3d6 100644 --- a/ALICE3/Core/OTFParticle.h +++ b/ALICE3/Core/OTFParticle.h @@ -155,8 +155,8 @@ class OTFParticle std::span getMotherSpan() const { return hasMothers() ? std::span(mIndicesMother.data(), 2) : std::span(); } // Checks - bool hasDaughters() const { return (mIndicesDaughter[0] > 0); } - bool hasMothers() const { return (mIndicesMother[0] > 0); } + bool hasDaughters() const { return (mIndicesDaughter[0] >= 0); } + bool hasMothers() const { return (mIndicesMother[0] >= 0); } bool hasNaN() const { return std::isnan(mPx) || std::isnan(mPy) || std::isnan(mPz) || std::isnan(mE) || diff --git a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx index 81c717ab023..6af272e5d68 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx @@ -120,6 +120,10 @@ struct OnTheFlyDecayer { std::vector allParticles; void decayParticles(const int start, const int stop) { + if (start >= stop) { + return; + } + int ndau = 0; for (int i = start; i < stop; ++i) { o2::upgrade::OTFParticle& particle = allParticles[i]; @@ -134,6 +138,10 @@ struct OnTheFlyDecayer { particle.setBitOff(o2::upgrade::DecayerBits::IsAlive); std::vector decayStack = decayer.decayParticle(pdgDB, particle); + if (decayStack.empty()) { + continue; + } + const float decayRadius = decayer.getDecayRadius(); const float trackVelocity = o2::upgrade::computeParticleVelocity(particle.p(), pdgDB->GetParticle(particle.pdgCode())->Mass()); const int charge = pdgDB->GetParticle(particle.pdgCode())->Charge() / 3; @@ -151,19 +159,15 @@ struct OnTheFlyDecayer { const float trackTimeNS = trackLength / trackVelocity * PicoToNano; particle.setIndicesDaughter(allParticles.size(), allParticles.size() + (decayStack.size() - 1)); - for (const o2::upgrade::OTFParticle& daughter : decayStack) { + for (auto& daughter : decayStack) { daughter.setIndicesMother(i, i); daughter.setCollisionId(particle.collisionId()); daughter.setBitOn(o2::upgrade::DecayerBits::IsAlive); daughter.setBitOff(o2::upgrade::DecayerBits::IsPrimary); daughter.setProductionTime(trackTimeNS); allParticles.push_back(daughter); - ndau++; } - } - - if (start >= stop) { - return; + ndau += decayStack.size(); } decayParticles(stop, stop + ndau); @@ -172,6 +176,7 @@ struct OnTheFlyDecayer { void process(aod::McCollisions_001From>::iterator const& collision, aod::McParticles_001From> const& mcParticles) { allParticles.clear(); + allParticles.reserve(mcParticles.size() * 2); if (collision.globalIndex() == 0) { indexOffset = 0; } @@ -190,7 +195,8 @@ struct OnTheFlyDecayer { decayParticles(0, allParticles.size()); // Fill output table - for (const o2::upgrade::OTFParticle& otfParticle : allParticles) { + int id = indexOffset; + for (auto& otfParticle : allParticles) { otfParticle.setIndexOffset(indexOffset); if (otfParticle.hasNaN()) { histos.fill(HIST("hNaNBookkeeping"), 1); @@ -199,7 +205,7 @@ struct OnTheFlyDecayer { } tableOTFDecayerBits(otfParticle.getBitsValue()); - tableMcParticles(otfParticle.collisionId(), otfParticle.pdgCode(), otfParticle.statusCode(), otfParticle.flags(), + tableMcParticles(tableMcCollisions.lastIndex(), otfParticle.pdgCode(), otfParticle.statusCode(), otfParticle.flags(), otfParticle.getMotherSpan(), otfParticle.getDaughters().data(), otfParticle.weight(), otfParticle.px(), otfParticle.py(), otfParticle.pz(), otfParticle.e(), otfParticle.vx(), otfParticle.vy(), otfParticle.vz(), otfParticle.vt()); @@ -208,7 +214,7 @@ struct OnTheFlyDecayer { // Particles for later collisions in df's needs to have thier mother // and daughter indices adjusted since their global index will be // shifted due to the appending of decay products - indexOffset += (allParticles.size() - mcParticles.size()); + indexOffset += allParticles.size(); } }; diff --git a/ALICE3/Tasks/alice3DecayerQa.cxx b/ALICE3/Tasks/alice3DecayerQa.cxx index 7323e7f380b..5b6ae287c44 100644 --- a/ALICE3/Tasks/alice3DecayerQa.cxx +++ b/ALICE3/Tasks/alice3DecayerQa.cxx @@ -132,7 +132,6 @@ struct Alice3DecayerQa { void process(const aod::McCollision& collision, const aod::McParticles& particles) { - LOG(info) << particles.size(); // Group with collision auto trueElectronsGrouped = trueElectrons->sliceByCached(aod::mcparticle::mcCollisionId, collision.globalIndex(), cache); auto trueMuonsGrouped = trueMuons->sliceByCached(aod::mcparticle::mcCollisionId, collision.globalIndex(), cache); @@ -164,8 +163,8 @@ struct Alice3DecayerQa { histos.fill(HIST("K0S/hHasDecayed"), 1); auto daughters = particle.daughtersIds(); if (daughters.size() == NV0Daughters) { - auto dau0 = particles.rawIteratorAt(daughters.front()); - auto dau1 = particles.rawIteratorAt(daughters.back()); + auto dau0 = particles.rawIteratorAt(daughters.front() - particles.offset()); + auto dau1 = particles.rawIteratorAt(daughters.back() - particles.offset()); // K0S -> pi+ pi- const bool k0sDecay = (dau0.pdgCode() == PDG_t::kPiPlus && dau1.pdgCode() == PDG_t::kPiMinus) || @@ -188,8 +187,8 @@ struct Alice3DecayerQa { histos.fill(HIST("Lambda/hHasDecayed"), 1); auto daughters = particle.daughtersIds(); if (daughters.size() == NV0Daughters) { - auto dau0 = particles.rawIteratorAt(daughters[0]); - auto dau1 = particles.rawIteratorAt(daughters[1]); + auto dau0 = particles.rawIteratorAt(daughters[0] - particles.offset()); + auto dau1 = particles.rawIteratorAt(daughters[1] - particles.offset()); // Lambda -> p pi- const bool lambdaDecay = (dau0.pdgCode() == PDG_t::kProton && dau1.pdgCode() == PDG_t::kPiMinus) || @@ -212,8 +211,8 @@ struct Alice3DecayerQa { histos.fill(HIST("XiMinus/hHasDecayed"), 1); auto daughters = particle.daughtersIds(); if (daughters.size() == NCascadeDaughters) { - auto dau0 = particles.rawIteratorAt(daughters.front()); - auto dau1 = particles.rawIteratorAt(daughters.back()); + auto dau0 = particles.rawIteratorAt(daughters.front() - particles.offset()); + auto dau1 = particles.rawIteratorAt(daughters.back() - particles.offset()); // Xi- -> Lambda pi- const bool xiDecay = (dau0.pdgCode() == PDG_t::kLambda0 && dau1.pdgCode() == PDG_t::kPiMinus) || @@ -229,8 +228,8 @@ struct Alice3DecayerQa { if (v0.has_daughters()) { auto v0daughters = v0.daughtersIds(); if (v0daughters.size() == NV0Daughters) { - auto v0dau0 = particles.rawIteratorAt(v0daughters.front()); - auto v0dau1 = particles.rawIteratorAt(v0daughters.back()); + auto v0dau0 = particles.rawIteratorAt(v0daughters.front() - particles.offset()); + auto v0dau1 = particles.rawIteratorAt(v0daughters.back() - particles.offset()); const bool lambdaDecay = (v0dau0.pdgCode() == PDG_t::kProton && v0dau1.pdgCode() == PDG_t::kPiMinus) || (v0dau0.pdgCode() == PDG_t::kPiMinus && v0dau1.pdgCode() == PDG_t::kProton); if (lambdaDecay) {