From 738b7979b78dfb93988a97326aa319e35734f34c Mon Sep 17 00:00:00 2001 From: jesgum Date: Mon, 20 Jul 2026 10:11:14 +0000 Subject: [PATCH 1/4] Tag particles from otf decayer properly --- ALICE3/Core/OTFParticle.h | 11 ++-- ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx | 1 + ALICE3/TableProducer/OTF/onTheFlyTracker.cxx | 66 +++++++++++++++++--- 3 files changed, 61 insertions(+), 17 deletions(-) diff --git a/ALICE3/Core/OTFParticle.h b/ALICE3/Core/OTFParticle.h index 95c6c78c492..b96bc051a10 100644 --- a/ALICE3/Core/OTFParticle.h +++ b/ALICE3/Core/OTFParticle.h @@ -55,7 +55,7 @@ class OTFParticle mVt = particle.vt(); mFlag = particle.flags(); mStatusCode = particle.statusCode(); - mIsFromMcParticles = true; + setBitOff(DecayerBits::ProducedByDecayer); if (particle.has_mothers()) { mIndicesMother = {particle.mothersIds().front(), particle.mothersIds().back()}; } @@ -72,7 +72,6 @@ class OTFParticle } // Setters - void setIsPrimary(const bool isPrimary) { mIsPrimary = isPrimary; } void setCollisionId(const int collisionId) { mCollisionId = collisionId; } void setPDG(const int pdg) { mPdgCode = pdg; } void setIndicesMother(const int start, const int stop) { mIndicesMother = {start, stop}; } @@ -105,9 +104,9 @@ class OTFParticle int pdgCode() const { return mPdgCode; } int globalIndex() const { return mGlobalIndex; } int collisionId() const { return mCollisionId; } - bool isAlive() const { return mIsAlive; } - bool isPrimary() const { return mIsPrimary; } - bool isFromMcParticles() const { return mIsFromMcParticles; } + bool isAlive() const { return checkBit(DecayerBits::IsAlive); } + bool isPrimary() const { return checkBit(DecayerBits::IsPrimary); } + bool isFromMcParticles() const { return !checkBit(DecayerBits::ProducedByDecayer); } float weight() const { static constexpr float Weight = 1.f; @@ -186,8 +185,6 @@ class OTFParticle int mCollisionId{-1}; float mVx{}, mVy{}, mVz{}, mVt{}; float mPx{}, mPy{}, mPz{}, mE{}; - bool mIsAlive{}, mIsFromMcParticles{false}; - bool mIsPrimary{}; int mStatusCode{}; uint8_t mFlag{}; diff --git a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx index a1c62ae29b9..4340bf9bc33 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx @@ -164,6 +164,7 @@ struct OnTheFlyDecayer { for (auto& daughter : decayStack) { daughter.setIndicesMother(particlesInDataframe - indexOffset + i, particlesInDataframe - indexOffset + i); daughter.setCollisionId(particle.collisionId()); + daughter.setBitOn(o2::upgrade::DecayerBits::ProducedByDecayer); daughter.setBitOn(o2::upgrade::DecayerBits::IsAlive); daughter.setBitOff(o2::upgrade::DecayerBits::IsPrimary); daughter.setProductionTime(particle.vt() + trackTimeNS); diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index 9b54eb9f648..23d5c85640a 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -125,6 +125,8 @@ enum TrackType { kGenCasc, kRecoCascDaug, kGenCascDaug, + kRecoSecondary, + kGhostSecondary, kNTrackTypes, }; @@ -587,6 +589,19 @@ struct OnTheFlyTracker { insertHist(histPath + "h2dBRPtResAbs", "h2dPtResAbs;Gen p_{T};#Delta p_{T}", {kTH2D, {{axes.axisMomentum, axes.axisPtRes}}}); } + if (doprocessDecayer) { + insertHist(histPath + "h2dPrimaryPtRes", "h2dPrimaryPtRes;Gen p_{T};#Delta p_{T} / Reco p_{T}", {kTH2D, {{axes.axisMomentum, axes.axisPtRes}}}); + insertHist(histPath + "h2dSecondaryPtRes", "h2dSecondaryPtRes;Gen p_{T};#Delta p_{T} / Reco p_{T}", {kTH2D, {{axes.axisMomentum, axes.axisPtRes}}}); + insertHist(histPath + "h2dPrimaryElPtRes", "h2dPrimaryElPtRes;Gen p_{T};#Delta p_{T} / Reco p_{T}", {kTH2D, {{axes.axisMomentum, axes.axisPtRes}}}); + insertHist(histPath + "h2dSecondaryElPtRes", "h2dSecondaryElPtRes;Gen p_{T};#Delta p_{T} / Reco p_{T}", {kTH2D, {{axes.axisMomentum, axes.axisPtRes}}}); + insertHist(histPath + "h2dPrimaryPiPtRes", "h2dPrimaryPiPtRes;Gen p_{T};#Delta p_{T} / Reco p_{T}", {kTH2D, {{axes.axisMomentum, axes.axisPtRes}}}); + insertHist(histPath + "h2dSecondaryPiPtRes", "h2dSecondaryPiPtRes;Gen p_{T};#Delta p_{T} / Reco p_{T}", {kTH2D, {{axes.axisMomentum, axes.axisPtRes}}}); + insertHist(histPath + "h2dPrimaryKaPtRes", "h2dPrimaryKaPtRes;Gen p_{T};#Delta p_{T} / Reco p_{T}", {kTH2D, {{axes.axisMomentum, axes.axisPtRes}}}); + insertHist(histPath + "h2dSecondaryKaPtRes", "h2dSecondaryKaPtRes;Gen p_{T};#Delta p_{T} / Reco p_{T}", {kTH2D, {{axes.axisMomentum, axes.axisPtRes}}}); + insertHist(histPath + "h2dPrimaryPrPtRes", "h2dPrimaryPrPtRes;Gen p_{T};#Delta p_{T} / Reco p_{T}", {kTH2D, {{axes.axisMomentum, axes.axisPtRes}}}); + insertHist(histPath + "h2dSecondaryPrPtRes", "h2dSecondaryPrPtRes;Gen p_{T};#Delta p_{T} / Reco p_{T}", {kTH2D, {{axes.axisMomentum, axes.axisPtRes}}}); + } + } // end config loop // Basic QA @@ -2043,6 +2058,7 @@ struct OnTheFlyTracker { const bool pdgsToBeHandled = longLivedToBeHandled || (enableNucleiSmearing && nucleiToBeHandled); o2::upgrade::OTFParticle otfParticle(mcParticle); + otfParticle.setBits(mcParticle.decayerBits_raw()); if (otfParticle.hasNaN()) { continue; } @@ -2080,17 +2096,16 @@ struct OnTheFlyTracker { multiplicityCounter++; o2::track::TrackParCov trackParCov; - const bool isDecayDaughter = (mcParticle.getProcess() == TMCProcess::kPDecay); const float time = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; bool reconstructed = false; int nTrkHits = 0; - if (enablePrimarySmearing && otfParticle.checkBit(o2::upgrade::DecayerBits::IsPrimary)) { + const bool isSecondary = !otfParticle.isPrimary() && otfParticle.checkBit(o2::upgrade::DecayerBits::ProducedByDecayer) && otfParticle.isAlive(); + if (enablePrimarySmearing && otfParticle.isPrimary()) { o2::upgrade::convertMCParticleToO2Track(mcParticle, trackParCov, pdgDB); computeBremsstrahlungLoss(icfg, mcParticle, trackParCov); reconstructed = mSmearer[icfg]->smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); - nTrkHits = fastTrackerSettings.minSiliconHits; - } else if (enableSecondarySmearing && !otfParticle.checkBit(o2::upgrade::DecayerBits::IsPrimary) && otfParticle.checkBit(o2::upgrade::DecayerBits::ProducedByDecayer) && otfParticle.checkBit(o2::upgrade::DecayerBits::IsAlive)) { + } else if (enableSecondarySmearing && isSecondary) { o2::track::TrackParCov perfectTrackParCov; o2::upgrade::convertMCParticleToO2Track(mcParticle, perfectTrackParCov, pdgDB); computeBremsstrahlungLoss(icfg, mcParticle, perfectTrackParCov); @@ -2114,21 +2129,52 @@ struct OnTheFlyTracker { histos.fill(HIST("hNaNBookkeeping"), 0.0f, 1.0f); if (enablePrimarySmearing) { + const float ptResolution = (trackParCov.getPt() - mcParticle.pt()) / trackParCov.getPt(); getHist(TH1, histPath + "hPtReconstructed")->Fill(trackParCov.getPt()); - if (std::abs(mcParticle.pdgCode()) == kElectron) + if (otfParticle.isPrimary()) { + getHist(TH2, histPath + "h2dPrimaryPtRes")->Fill(trackParCov.getPt(), ptResolution); + } else { + getHist(TH2, histPath + "h2dSecondaryPtRes")->Fill(trackParCov.getPt(), ptResolution); + } + if (std::abs(mcParticle.pdgCode()) == kElectron) { getHist(TH1, histPath + "hPtReconstructedEl")->Fill(trackParCov.getPt()); - if (std::abs(mcParticle.pdgCode()) == kPiPlus) + if (otfParticle.isPrimary()) { + getHist(TH2, histPath + "h2dPrimaryElPtRes")->Fill(trackParCov.getPt(), ptResolution); + } else { + getHist(TH2, histPath + "h2dSecondaryElPtRes")->Fill(trackParCov.getPt(), ptResolution); + } + } + if (std::abs(mcParticle.pdgCode()) == kPiPlus) { getHist(TH1, histPath + "hPtReconstructedPi")->Fill(trackParCov.getPt()); - if (std::abs(mcParticle.pdgCode()) == kKPlus) + if (otfParticle.isPrimary()) { + getHist(TH2, histPath + "h2dPrimaryPiPtRes")->Fill(trackParCov.getPt(), ptResolution); + } else { + getHist(TH2, histPath + "h2dSecondaryPiPtRes")->Fill(trackParCov.getPt(), ptResolution); + } + } + if (std::abs(mcParticle.pdgCode()) == kKPlus) { getHist(TH1, histPath + "hPtReconstructedKa")->Fill(trackParCov.getPt()); - if (std::abs(mcParticle.pdgCode()) == kProton) + if (otfParticle.isPrimary()) { + getHist(TH2, histPath + "h2dPrimaryKaPtRes")->Fill(trackParCov.getPt(), ptResolution); + } else { + getHist(TH2, histPath + "h2dSecondaryKaPtRes")->Fill(trackParCov.getPt(), ptResolution); + } + } + if (std::abs(mcParticle.pdgCode()) == kProton) { getHist(TH1, histPath + "hPtReconstructedPr")->Fill(trackParCov.getPt()); + if (otfParticle.isPrimary()) { + getHist(TH2, histPath + "h2dPrimaryPrPtRes")->Fill(trackParCov.getPt(), ptResolution); + } else { + getHist(TH2, histPath + "h2dSecondaryPrPtRes")->Fill(trackParCov.getPt(), ptResolution); + } + } } if (reconstructed) { - tracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isDecayDaughter, false, 0, nTrkHits, kRecoPrimary}); + tracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isSecondary, false, 0, nTrkHits, kRecoPrimary}); + getHist(TH1, histPath + "hPtReconstructedPr")->Fill(trackParCov.getPt()); } else { - ghostTracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isDecayDaughter, false, 0, nTrkHits, kGhostPrimary}); + ghostTracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isSecondary, false, 0, nTrkHits, kGhostPrimary}); } } From e9efc83ad532e02569a82887ed7847ce469c8bb6 Mon Sep 17 00:00:00 2001 From: jesgum Date: Mon, 20 Jul 2026 10:16:26 +0000 Subject: [PATCH 2/4] update --- ALICE3/TableProducer/OTF/onTheFlyTracker.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index 23d5c85640a..7d23c47b5a2 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -125,8 +125,6 @@ enum TrackType { kGenCasc, kRecoCascDaug, kGenCascDaug, - kRecoSecondary, - kGhostSecondary, kNTrackTypes, }; From ec9bb003907030d0df503fba2e3b1a7f46f66ed5 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Mon, 20 Jul 2026 10:17:44 +0000 Subject: [PATCH 3/4] Please consider the following formatting changes --- ALICE3/TableProducer/OTF/onTheFlyTracker.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index 7d23c47b5a2..c97a6d17bc7 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -2170,7 +2170,7 @@ struct OnTheFlyTracker { if (reconstructed) { tracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isSecondary, false, 0, nTrkHits, kRecoPrimary}); - getHist(TH1, histPath + "hPtReconstructedPr")->Fill(trackParCov.getPt()); + getHist(TH1, histPath + "hPtReconstructedPr")->Fill(trackParCov.getPt()); } else { ghostTracksAlice3.push_back(TrackAlice3{trackParCov, mcParticle.globalIndex(), time, timeResolutionUs, isSecondary, false, 0, nTrkHits, kGhostPrimary}); } From 14d05e15589d86a7e5cd73ba4b8e327cc9925126 Mon Sep 17 00:00:00 2001 From: Jesper Karlsson Gumprecht <113693781+jesgum@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:27:34 +0200 Subject: [PATCH 4/4] Fix megalinter --- ALICE3/Core/OTFParticle.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ALICE3/Core/OTFParticle.h b/ALICE3/Core/OTFParticle.h index b96bc051a10..a1c611b99c2 100644 --- a/ALICE3/Core/OTFParticle.h +++ b/ALICE3/Core/OTFParticle.h @@ -153,8 +153,8 @@ class OTFParticle int getMotherIndexStop() const { return mIndicesMother[1]; } int getDaughterIndexStart() const { return mIndicesDaughter[0]; } int getDaughterIndexStop() const { return mIndicesDaughter[1]; } - std::array getMothers() const { return mIndicesMother; } - std::array getDaughters() const { return mIndicesDaughter; } + const std::array& getMothers() const { return mIndicesMother; } + const std::array& getDaughters() const { return mIndicesDaughter; } std::span getMotherSpan() const { return hasMothers() ? std::span(mIndicesMother.data(), 2) : std::span(); } // Checks @@ -176,7 +176,7 @@ class OTFParticle void setBitOn(DecayerBits bit) { mBits.set(static_cast(bit), true); } void setBitOff(DecayerBits bit) { mBits.set(static_cast(bit), false); } - std::bitset<8> getBits() const { return mBits; } + const std::bitset<8>& getBits() const { return mBits; } uint8_t getBitsValue() const { return static_cast(mBits.to_ulong()); } void setBits(std::bitset<8> bits) { mBits = bits; }