From 8a16f984c34182433233e49efc77682edf798f76 Mon Sep 17 00:00:00 2001 From: jesgum Date: Thu, 19 Feb 2026 20:55:34 +0100 Subject: [PATCH 1/2] Fix crashes from when decay products have NaN's --- ALICE3/DataModel/OTFMCParticle.h | 4 +- ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx | 79 ++++++++++--------- ALICE3/TableProducer/OTF/onTheFlyTracker.cxx | 6 +- ALICE3/Tasks/CMakeLists.txt | 2 +- ...lice3DecayerQA.cxx => alice3DecayerQa.cxx} | 14 ++-- 5 files changed, 56 insertions(+), 49 deletions(-) rename ALICE3/Tasks/{alice3DecayerQA.cxx => alice3DecayerQa.cxx} (93%) diff --git a/ALICE3/DataModel/OTFMCParticle.h b/ALICE3/DataModel/OTFMCParticle.h index 515693edfbe..987ed28b858 100644 --- a/ALICE3/DataModel/OTFMCParticle.h +++ b/ALICE3/DataModel/OTFMCParticle.h @@ -37,7 +37,7 @@ DECLARE_SOA_COLUMN(IsPrimary, isPrimary, bool); } // namespace otfmcparticle -DECLARE_SOA_TABLE_FULL(McParticlesWithDau, "McParticlesWithDau", "AOD", "MCPARTICLEWITHDAU", +DECLARE_SOA_TABLE_FULL(McPartsWithDau, "McPartsWithDau", "AOD", "MCPARTSWITHDAU", o2::soa::Index<>, mcparticle::McCollisionId, mcparticle::PdgCode, @@ -69,7 +69,7 @@ DECLARE_SOA_TABLE_FULL(McParticlesWithDau, "McParticlesWithDau", "AOD", "MCPARTI mcparticle::GetProcess, mcparticle::IsPhysicalPrimary); -using McParticleWithDau = McParticlesWithDau::iterator; +using McPartWithDau = McPartsWithDau::iterator; } // namespace o2::aod diff --git a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx index b365cd2f1fe..95b4a53e3c0 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx @@ -18,24 +18,13 @@ #include "ALICE3/Core/Decayer.h" #include "ALICE3/Core/TrackUtilities.h" #include "ALICE3/DataModel/OTFMCParticle.h" - -#include +#include #include #include -#include -#include -#include -#include -#include -#include #include #include #include #include -#include -#include -#include -#include #include @@ -69,7 +58,7 @@ static const std::vector pdgCodes{kK0Short, kOmegaPlusBar}; struct OnTheFlyDecayer { - Produces tableMcParticlesWithDau; + Produces tableMcParticlesWithDau; o2::upgrade::Decayer decayer; Service pdgDB; @@ -77,6 +66,7 @@ struct OnTheFlyDecayer { Configurable seed{"seed", 0, "Set seed for particle decayer"}; Configurable magneticField{"magneticField", 20., "Magnetic field (kG)"}; + Configurable maxEta{"maxEta", 2.5, "Only decay particles that appear within selected eta range"}; Configurable> enabledDecays{"enabledDecays", {DefaultParameters[0], NumDecays, NumParameters, particleNames, parameterNames}, "Enable option for particle to be decayed: 0 - no, 1 - yes"}; @@ -122,6 +112,15 @@ struct OnTheFlyDecayer { y(y), isAlive(isAlive), isPrimary(isPrimary) {} + + bool hasNaN() const + { + return std::isnan(px) || std::isnan(py) || std::isnan(pz) || std::isnan(e) || + std::isnan(vx) || std::isnan(vy) || std::isnan(vz) || std::isnan(vt) || + std::isnan(phi) || std::isnan(eta) || std::isnan(pt) || std::isnan(p) || + std::isnan(y) || std::isnan(weight); + } + int collisionId; int pdgCode; int statusCode; @@ -148,6 +147,10 @@ struct OnTheFlyDecayer { } } + auto hNaNBookkeeping = histos.add("hNaNBookkeeping", "hNaNBookkeeping", kTH1D, {{2, -0.5, 1.5}}); + hNaNBookkeeping->GetXaxis()->SetBinLabel(1, "OK"); + hNaNBookkeeping->GetXaxis()->SetBinLabel(2, "NaN"); + histos.add("K0S/hGenK0S", "hGenK0S", kTH1D, {axisPt}); histos.add("Lambda/hGenLambda", "hGenLambda", kTH1D, {axisPt}); histos.add("AntiLambda/hGenAntiLambda", "hGenAntiLambda", kTH1D, {axisPt}); @@ -175,30 +178,29 @@ struct OnTheFlyDecayer { mcParticlesAlice3.clear(); u_int64_t nStoredDaughters = 0; for (int index{0}; index < static_cast(mcParticles.size()); ++index) { - const auto& particle = mcParticles.iteratorAt(index); - std::vector decayDaughters; - static constexpr int MaxNestedDecays = 10; - int nDecays = 0; - if (canDecay(particle.pdgCode())) { + const auto& particle = mcParticles.rawIteratorAt(index); + std::vector decayDaughters, decayStack; + if (canDecay(particle.pdgCode()) && std::abs(particle.eta()) < maxEta) { o2::track::TrackParCov o2track; o2::upgrade::convertMCParticleToO2Track(particle, o2track, pdgDB); - decayDaughters = decayer.decayParticle(pdgDB, o2track, particle.pdgCode()); - for (size_t idau{0}; idau < decayDaughters.size(); ++idau) { - o2::upgrade::OTFParticle dau = decayDaughters[idau]; + decayStack = decayer.decayParticle(pdgDB, o2track, particle.pdgCode()); + while (!decayStack.empty()) { + o2::upgrade::OTFParticle otfParticle = decayStack.back(); + decayStack.pop_back(); + + const bool stable = !canDecay(otfParticle.pdgCode()); + otfParticle.setIsAlive(stable); + decayDaughters.push_back(otfParticle); + + if (stable) { + continue; + } + o2::track::TrackParCov dauTrack; - o2::upgrade::convertOTFParticleToO2Track(dau, dauTrack, pdgDB); - if (canDecay(dau.pdgCode())) { - dau.setIsAlive(false); - std::vector cascadingDaughers = decayer.decayParticle(pdgDB, dauTrack, dau.pdgCode()); - for (size_t idaudau{0}; idaudau < cascadingDaughers.size(); ++idaudau) { - o2::upgrade::OTFParticle daudau = cascadingDaughers[idaudau]; - decayDaughters.push_back(daudau); - if (MaxNestedDecays < ++nDecays) { - LOG(error) << "Seemingly stuck trying to perpetually decay products from pdg: " << particle.pdgCode(); - } - } - } else { - dau.setIsAlive(true); + o2::upgrade::convertOTFParticleToO2Track(otfParticle, dauTrack, pdgDB); + std::vector daughters = decayer.decayParticle(pdgDB, dauTrack, otfParticle.pdgCode()); + for (o2::upgrade::OTFParticle dau : daughters) { + decayStack.push_back(dau); } } @@ -338,7 +340,7 @@ struct OnTheFlyDecayer { // TODO: Particle status code // TODO: Expression columns // TODO: vt - auto mother = mcParticles.iteratorAt(index); + auto mother = mcParticles.rawIteratorAt(index); mcParticlesAlice3.push_back(McParticleAlice3{mother.mcCollisionId(), dau.pdgCode(), 1, -1, index, index, daughtersIdSlice[0], daughtersIdSlice[1], mother.weight(), dau.px(), dau.py(), dau.pz(), dau.e(), @@ -348,8 +350,13 @@ struct OnTheFlyDecayer { } for (const auto& particle : mcParticlesAlice3) { - std::span motherSpan(particle.mothersIds, 2); + if (particle.hasNaN()) { + histos.fill(HIST("hNaNBookkeeping"), 1); + continue; + } + histos.fill(HIST("hNaNBookkeeping"), 0); + std::span motherSpan(particle.mothersIds, 2); tableMcParticlesWithDau(particle.collisionId, particle.pdgCode, particle.statusCode, particle.flags, motherSpan, particle.daughtersIdSlice, particle.weight, particle.px, particle.py, particle.pz, particle.e, diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index c007748a04c..9e4ac40a76d 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -705,7 +705,7 @@ struct OnTheFlyTracker { float dNdEta = 0.f; // Charged particle multiplicity to use in the efficiency evaluation std::pair vertexReconstructionEfficiencyCounters = {0, 0}; // {nVerticesWithMoreThan2Contributors, nVerticesReconstructed} - void processWithLUTs(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles, int const& icfg) + void processWithLUTs(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles, const int icfg) { vertexReconstructionEfficiencyCounters.first += 1; const int lastTrackIndex = tableStoredTracksCov.lastIndex() + 1; // bookkeep the last added track @@ -1736,7 +1736,7 @@ struct OnTheFlyTracker { } } - void processConfigurationDev(aod::McCollision const& mcCollision, aod::McParticlesWithDau const& mcParticles, int const& icfg) + void processConfigurationDev(aod::McCollision const& mcCollision, aod::McPartsWithDau const& mcParticles, const int icfg) { // const int lastTrackIndex = tableStoredTracksCov.lastIndex() + 1; // bookkeep the last added track const std::string histPath = "Configuration_" + std::to_string(icfg) + "/"; @@ -1991,7 +1991,7 @@ struct OnTheFlyTracker { } } - void processDecayer(aod::McCollision const& mcCollision, aod::McParticlesWithDau const& mcParticles) + void processDecayer(aod::McCollision const& mcCollision, aod::McPartsWithDau const& mcParticles) { for (size_t icfg = 0; icfg < mSmearer.size(); ++icfg) { processConfigurationDev(mcCollision, mcParticles, static_cast(icfg)); diff --git a/ALICE3/Tasks/CMakeLists.txt b/ALICE3/Tasks/CMakeLists.txt index cf26d5bf743..822d407221f 100644 --- a/ALICE3/Tasks/CMakeLists.txt +++ b/ALICE3/Tasks/CMakeLists.txt @@ -95,6 +95,6 @@ o2physics_add_dpl_workflow(alice3-dq-efficiency COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(alice3-decayer-qa - SOURCES alice3DecayerQA.cxx + SOURCES alice3DecayerQa.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) diff --git a/ALICE3/Tasks/alice3DecayerQA.cxx b/ALICE3/Tasks/alice3DecayerQa.cxx similarity index 93% rename from ALICE3/Tasks/alice3DecayerQA.cxx rename to ALICE3/Tasks/alice3DecayerQa.cxx index 5009df9f437..7114bef6126 100644 --- a/ALICE3/Tasks/alice3DecayerQA.cxx +++ b/ALICE3/Tasks/alice3DecayerQa.cxx @@ -60,11 +60,11 @@ struct Alice3DecayerQA { Partition trueKa = aod::mcparticle::pdgCode == static_cast(kKMinus); Partition truePr = aod::mcparticle::pdgCode == static_cast(kProton); - Partition trueElWithDau = aod::mcparticle::pdgCode == static_cast(kElectron); - Partition trueMuWithDau = aod::mcparticle::pdgCode == static_cast(kMuonMinus); - Partition truePiWithDau = aod::mcparticle::pdgCode == static_cast(kPiPlus); - Partition trueKaWithDau = aod::mcparticle::pdgCode == static_cast(kKMinus); - Partition truePrWithDau = aod::mcparticle::pdgCode == static_cast(kProton); + Partition trueElWithDau = aod::mcparticle::pdgCode == static_cast(kElectron); + Partition trueMuWithDau = aod::mcparticle::pdgCode == static_cast(kMuonMinus); + Partition truePiWithDau = aod::mcparticle::pdgCode == static_cast(kPiPlus); + Partition trueKaWithDau = aod::mcparticle::pdgCode == static_cast(kKMinus); + Partition truePrWithDau = aod::mcparticle::pdgCode == static_cast(kProton); void init(o2::framework::InitContext&) { @@ -123,7 +123,7 @@ struct Alice3DecayerQA { } } - void processMCWithDau(const aod::McCollision&, const aod::McParticlesWithDau& particles) + void processMCWithDau(const aod::McCollision&, const aod::McPartsWithDau& particles) { for (const auto& particle : trueElWithDau) { histos.fill(HIST("MCWithDau/hElPt"), particle.pt()); @@ -155,7 +155,7 @@ struct Alice3DecayerQA { histos.fill(HIST("MCWithDau/hEta"), particle.eta()); histos.fill(HIST("MCWithDau/hRapidity"), particle.y()); histos.fill(HIST("MCWithDau/hIsAlive"), particle.isAlive()); - histos.fill(HIST("MCWithDau/hIsPrimary"), particle.isPrimary()); + histos.fill(HIST("MCWithDau/hIsPrimary"), particle.isPhysicalPrimary()); histos.fill(HIST("MCWithDau/hPx"), particle.px()); histos.fill(HIST("MCWithDau/hPy"), particle.py()); histos.fill(HIST("MCWithDau/hPz"), particle.pz()); From f3eb8469f574e5126787d35a21f3bf29838e5430 Mon Sep 17 00:00:00 2001 From: jesgum Date: Thu, 19 Feb 2026 20:57:51 +0100 Subject: [PATCH 2/2] formatting --- ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx | 9 +++++---- ALICE3/Tasks/alice3DecayerQa.cxx | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx index 95b4a53e3c0..366ffb6a290 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx @@ -18,13 +18,14 @@ #include "ALICE3/Core/Decayer.h" #include "ALICE3/Core/TrackUtilities.h" #include "ALICE3/DataModel/OTFMCParticle.h" -#include + #include #include #include #include #include #include +#include #include @@ -116,9 +117,9 @@ struct OnTheFlyDecayer { bool hasNaN() const { return std::isnan(px) || std::isnan(py) || std::isnan(pz) || std::isnan(e) || - std::isnan(vx) || std::isnan(vy) || std::isnan(vz) || std::isnan(vt) || - std::isnan(phi) || std::isnan(eta) || std::isnan(pt) || std::isnan(p) || - std::isnan(y) || std::isnan(weight); + std::isnan(vx) || std::isnan(vy) || std::isnan(vz) || std::isnan(vt) || + std::isnan(phi) || std::isnan(eta) || std::isnan(pt) || std::isnan(p) || + std::isnan(y) || std::isnan(weight); } int collisionId; diff --git a/ALICE3/Tasks/alice3DecayerQa.cxx b/ALICE3/Tasks/alice3DecayerQa.cxx index 7114bef6126..ea02c5cb29e 100644 --- a/ALICE3/Tasks/alice3DecayerQa.cxx +++ b/ALICE3/Tasks/alice3DecayerQa.cxx @@ -155,7 +155,7 @@ struct Alice3DecayerQA { histos.fill(HIST("MCWithDau/hEta"), particle.eta()); histos.fill(HIST("MCWithDau/hRapidity"), particle.y()); histos.fill(HIST("MCWithDau/hIsAlive"), particle.isAlive()); - histos.fill(HIST("MCWithDau/hIsPrimary"), particle.isPhysicalPrimary()); + histos.fill(HIST("MCWithDau/hIsPrimary"), particle.isPrimary()); histos.fill(HIST("MCWithDau/hPx"), particle.px()); histos.fill(HIST("MCWithDau/hPy"), particle.py()); histos.fill(HIST("MCWithDau/hPz"), particle.pz());