From 4dd5374ac1e205a9aadfd03af52cb64ca1c22f09 Mon Sep 17 00:00:00 2001 From: Anton Riedel Date: Tue, 11 Aug 2026 09:04:26 +0200 Subject: [PATCH 1/4] Feat: add FLiteColShapes table --- PWGCF/Femto/Core/femtoUtils.h | 54 +++++++++---------- PWGCF/Femto/Core/partitions.h | 4 +- PWGCF/Femto/DataModel/FemtoTables.h | 37 ++++++++++++- .../femtoProducerLiteConverter.cxx | 11 ++++ 4 files changed, 76 insertions(+), 30 deletions(-) diff --git a/PWGCF/Femto/Core/femtoUtils.h b/PWGCF/Femto/Core/femtoUtils.h index 50b2e030ccb..d4c9ff2e3f3 100644 --- a/PWGCF/Femto/Core/femtoUtils.h +++ b/PWGCF/Femto/Core/femtoUtils.h @@ -243,7 +243,7 @@ inline int signum(T x) } template -inline T binLinear(float value, float lo, float hi, float step) +T binLinear(float value, float lo, float hi, float step) { float v = std::clamp(value, lo, hi); auto idx = static_cast(std::round((v - lo) / step)); @@ -253,46 +253,46 @@ inline T binLinear(float value, float lo, float hi, float step) } template -inline float unBinLinear(T binned, float lo, float step) +float unBinLinear(T binned, float lo, float step) { auto idx = static_cast(binned) - static_cast(std::numeric_limits::min()); return lo + static_cast(idx) * step; } template -inline T binLogSigned(float signedValue, float magMin, float magMax) +T binLogSigned(float signedValue, float magMin, float magMax) { static_assert(std::is_unsigned_v, "binLogSigned requires an unsigned storage type"); - constexpr uint32_t TotalBits = sizeof(T) * 8; - constexpr uint32_t HalfLevels = 1u << (TotalBits - 1); - uint32_t sign = (signedValue < 0.f) ? 1u : 0u; - float mag = std::clamp(std::fabs(signedValue), magMin, magMax); - float logLo = std::log(magMin); - float logHi = std::log(magMax); - float step = (logHi - logLo) / static_cast(HalfLevels - 1); - auto idx = static_cast(std::round((std::log(mag) - logLo) / step)); - idx = std::clamp(idx, 0u, HalfLevels - 1); - return static_cast((sign << (TotalBits - 1)) | idx); + constexpr uint64_t TotalBits = sizeof(T) * 8; + constexpr uint64_t HalfLevels = uint64_t{1} << (TotalBits - 1); + const uint64_t sign = (signedValue < 0.f) ? uint64_t{1} : uint64_t{0}; + const float mag = std::clamp(std::fabs(signedValue), magMin, magMax); + const float logLo = std::log(magMin); + const float logHi = std::log(magMax); + const float step = (logHi - logLo) / static_cast(HalfLevels - 1); + auto idx = static_cast(std::round((std::log(mag) - logLo) / step)); + idx = std::clamp(idx, int64_t{0}, static_cast(HalfLevels - 1)); + return static_cast((sign << (TotalBits - 1)) | static_cast(idx)); } template -inline float unBinLogSigned(T binned, float magMin, float magMax) +float unBinLogSigned(T binned, float magMin, float magMax) { - constexpr uint32_t TotalBits = sizeof(T) * 8; - constexpr uint32_t HalfLevels = 1u << (TotalBits - 1); - constexpr T SignMask = static_cast(1u << (TotalBits - 1)); + static_assert(std::is_unsigned_v, "unBinLogSigned requires an unsigned storage type"); + constexpr uint64_t TotalBits = sizeof(T) * 8; + constexpr uint64_t HalfLevels = uint64_t{1} << (TotalBits - 1); + constexpr T SignMask = static_cast(uint64_t{1} << (TotalBits - 1)); constexpr T MagMask = static_cast(SignMask - 1); - float sign = (binned & SignMask) ? -1.f : 1.f; - uint32_t idx = binned & MagMask; - float logLo = std::log(magMin); - float logHi = std::log(magMax); - float step = (logHi - logLo) / static_cast(HalfLevels - 1); - float mag = std::exp(logLo + static_cast(idx) * step); - return sign * mag; + const float sign = (binned & SignMask) ? -1.f : 1.f; + const auto idx = static_cast(binned & MagMask); + const float logLo = std::log(magMin); + const float logHi = std::log(magMax); + const float step = (logHi - logLo) / static_cast(HalfLevels - 1); + return sign * std::exp(logLo + static_cast(idx) * step); } template -inline int unBinSign(T binned) +int unBinSign(T binned) { static_assert(std::is_unsigned_v, "unBinSign requires an unsigned storage type"); constexpr uint64_t TotalBits = sizeof(T) * 8; @@ -301,7 +301,7 @@ inline int unBinSign(T binned) } template -inline T binLogUnsigned(float value, float magMin, float magMax) +T binLogUnsigned(float value, float magMin, float magMax) { static_assert(std::is_unsigned_v, "binLogUnsigned requires an unsigned storage type"); constexpr uint64_t TotalBits = sizeof(T) * 8; @@ -316,7 +316,7 @@ inline T binLogUnsigned(float value, float magMin, float magMax) } template -inline float unBinLogUnsigned(T binned, float magMin, float magMax) +float unBinLogUnsigned(T binned, float magMin, float magMax) { constexpr uint64_t TotalBits = sizeof(T) * 8; constexpr uint64_t Levels = uint64_t{1} << TotalBits; diff --git a/PWGCF/Femto/Core/partitions.h b/PWGCF/Femto/Core/partitions.h index 68508aa4c70..9d53da4587a 100644 --- a/PWGCF/Femto/Core/partitions.h +++ b/PWGCF/Femto/Core/partitions.h @@ -22,8 +22,8 @@ (o2::aod::femtocollisions::posZ >= (selection).vtxZMin && o2::aod::femtocollisions::posZ <= (selection).vtxZMax) && \ (o2::aod::femtocollisions::mult >= (selection).multMin && o2::aod::femtocollisions::mult <= (selection).multMax) && \ (o2::aod::femtocollisions::cent >= (selection).centMin && o2::aod::femtocollisions::cent <= (selection).centMax) && \ - (o2::aod::femtocollisions::magField >= o2::framework::expressions::as((selection).magFieldMin) && \ - o2::aod::femtocollisions::magField <= o2::framework::expressions::as((selection).magFieldMax)) && \ + (o2::aod::femtocollisions::magField >= o2::framework::expressions::as((selection).magFieldMin)) && \ + (o2::aod::femtocollisions::magField <= o2::framework::expressions::as((selection).magFieldMax)) && \ ncheckbit(o2::aod::femtocollisions::mask, (selection).collisionMask) // macro for track momentum, i.e. ||q|*pT/q| * cosh(eta) diff --git a/PWGCF/Femto/DataModel/FemtoTables.h b/PWGCF/Femto/DataModel/FemtoTables.h index 000e9430469..efd1aae4789 100644 --- a/PWGCF/Femto/DataModel/FemtoTables.h +++ b/PWGCF/Femto/DataModel/FemtoTables.h @@ -52,11 +52,20 @@ namespace lite constexpr float PosZMin = -20.f; constexpr float PosZMax = 20.f; constexpr float PosZStep = 0.5f; // bin vtz in 0.5cm steps + constexpr float CentMin = 0.f; constexpr float CentMax = 100.f; constexpr float CentStep = 0.5f; // bin centrality in 0.5% steps + constexpr float MultStep = 1.f; // round multiplicity to nearest integer +constexpr float QvecMin = 1e-3f; // close to 0, but not 0 due to log +constexpr float QvecMax = 1e3f; // usual range for qvector + +constexpr float EventPlaneAngleMin = 0.f; +constexpr float EventPlaneAngleMax = o2::constants::math::TwoPI; // angle bound in [0,2pi) +constexpr float EventPlaneAngleStep = (EventPlaneAngleMax - EventPlaneAngleMin) / 65536.f; + inline uint8_t binPosZ(float posZ) { return o2::analysis::femto::utils::binLinear(posZ, PosZMin, PosZMax, PosZStep); } inline float unBinPosZ(uint8_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, PosZMin, PosZStep); } @@ -66,9 +75,17 @@ inline float unBinCent(uint8_t binned) { return o2::analysis::femto::utils::unBi inline uint16_t binMult(float mult) { return o2::analysis::femto::utils::binLinear(mult, 0.f, 65535.f, MultStep); } // use full range of uint16_t inline float unBinMult(uint16_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, 0.f, MultStep); } +inline uint16_t binQvec(float qvec) { return o2::analysis::femto::utils::binLogUnsigned(qvec, QvecMin, QvecMax); } +inline float unBinQvec(uint16_t binned) { return o2::analysis::femto::utils::unBinLogUnsigned(binned, QvecMin, QvecMax); } + +inline uint16_t binEventPlaneAngle(float eventPlaneAngle) { return o2::analysis::femto::utils::binLinear(eventPlaneAngle, EventPlaneAngleMin, EventPlaneAngleMax, EventPlaneAngleStep); } +inline float unBinEventPlaneAngle(uint16_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, EventPlaneAngleMin, EventPlaneAngleStep); } + DECLARE_SOA_COLUMN(BinnedPosZ, binnedPosZ, uint8_t); DECLARE_SOA_COLUMN(BinnedMult, binnedMult, uint16_t); DECLARE_SOA_COLUMN(BinnedCent, binnedCent, uint8_t); +DECLARE_SOA_COLUMN(BinnedQvec, binnedQvec, uint16_t); +DECLARE_SOA_COLUMN(BinnedEventPlaneAngle, binnedEventPlaneAngle, uint16_t); DECLARE_SOA_DYNAMIC_COLUMN(PosZ, posZ, [](uint8_t binnedPosZ) -> float { @@ -82,6 +99,14 @@ DECLARE_SOA_DYNAMIC_COLUMN(Cent, cent, [](uint8_t binnedCent) -> float { return unBinCent(binnedCent); }); +DECLARE_SOA_DYNAMIC_COLUMN(Qvec, qvec, + [](uint16_t binnedQvec) -> float { + return unBinQvec(binnedQvec); + }); +DECLARE_SOA_DYNAMIC_COLUMN(EventPlaneAngle, eventPlaneAngle, + [](uint16_t binnedEventPlaneAngle) -> float { + return unBinEventPlaneAngle(binnedEventPlaneAngle); + }); } // namespace lite } // namespace femtocollisions @@ -120,11 +145,21 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FColSphericities_001, "FCOLSPHERICITY", 1, // femtocollisions::Sphericity); using FColSphericities = FColSphericities_001; -// table for qn values +// table for event shape analysis DECLARE_SOA_TABLE_STAGED_VERSIONED(FColShapes_001, "FCOLSHAPE", 1, //! event shape femtocollisions::Qvec, femtocollisions::EventPlaneAngle); using FColShapes = FColShapes_001; +using StoredFColShapes = StoredFColShapes_001; + +// lite table for event shape analysis +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteColShapes_001, "FLITECOLSHAPE", 1, //! event shape + femtocollisions::lite::BinnedQvec, + femtocollisions::lite::BinnedEventPlaneAngle, + femtocollisions::lite::Qvec, + femtocollisions::lite::EventPlaneAngle); +using FLiteColShapes = FLiteColShapes_001; +using StoredFLiteColShapes = StoredFLiteColShapes_001; // table for primary vertex location DECLARE_SOA_TABLE_STAGED_VERSIONED(FColPos_001, "FCOLPOS", 1, //! full vertex position diff --git a/PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx b/PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx index 3a5add169c1..3d2c5fe0eef 100644 --- a/PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx @@ -26,6 +26,7 @@ using namespace o2::analysis::femto; struct FemtoProducerLiteConverter { o2::framework::Produces producedCols; + o2::framework::Produces producedColShapes; o2::framework::Produces producedTracks; o2::framework::Produces producedLambdas; o2::framework::Produces producedK0shorts; @@ -36,6 +37,9 @@ struct FemtoProducerLiteConverter { void init(o2::framework::InitContext&) { + if (!doprocessLiteCols) { + LOG(fatal) << "At least processLiteCols needs to be enabled, otherwise the collision index points no where!"; + } } void processLiteCols(o2::aod::FLiteCols::iterator const& liteCol) @@ -47,6 +51,13 @@ struct FemtoProducerLiteConverter { } PROCESS_SWITCH(FemtoProducerLiteConverter, processLiteCols, "Convert FLiteCols to FCols", true); + void processLiteColShapes(o2::aod::FLiteColShapes::iterator const& liteColShape) + { + producedColShapes(liteColShape.qvec(), + liteColShape.eventPlaneAngle()); + } + PROCESS_SWITCH(FemtoProducerLiteConverter, processLiteColShapes, "Convert FLiteColShapes to FColShapes", false); + void processLiteTracks(o2::aod::FLiteTracks::iterator const& liteTrack) { producedTracks(liteTrack.fLiteColId(), From 9b2f986b4d94dc730f4ef160099b2289f74c93d1 Mon Sep 17 00:00:00 2001 From: Anton Riedel Date: Tue, 11 Aug 2026 13:30:23 +0200 Subject: [PATCH 2/4] Feat: cleanup derived to derived builder/producer --- PWGCF/Femto/Core/cascadeBuilder.h | 70 ++++++++++++------- PWGCF/Femto/Core/kinkBuilder.h | 56 +++++++++++---- PWGCF/Femto/Core/partitions.h | 4 +- PWGCF/Femto/Core/trackBuilder.h | 52 +++++++------- PWGCF/Femto/Core/v0Builder.h | 60 +++++++++++----- PWGCF/Femto/DataModel/FemtoTables.h | 1 + .../femtoProducerDerivedToDerived.cxx | 19 +++-- 7 files changed, 170 insertions(+), 92 deletions(-) diff --git a/PWGCF/Femto/Core/cascadeBuilder.h b/PWGCF/Femto/Core/cascadeBuilder.h index 84fd8ddbd41..1ca053b9392 100644 --- a/PWGCF/Femto/Core/cascadeBuilder.h +++ b/PWGCF/Femto/Core/cascadeBuilder.h @@ -793,15 +793,15 @@ struct CascadeBuilderDerivedToDerivedProducts : o2::framework::ProducesGroup { class CascadeBuilderDerivedToDerived { public: - CascadeBuilderDerivedToDerived() = default; - ~CascadeBuilderDerivedToDerived() = default; - template void init(T& config) { mLimitXi = config.limitXi.value; mLimitOmega = config.limitOmega.value; + if (mLimitXi < 0 || mLimitOmega < 0) { + LOG(fatal) << "Cascade limits must be non-negative (got " << mLimitXi << " and " << mLimitOmega << "). Breaking..."; + } if (mLimitXi == 0 && mLimitOmega == 0) { LOG(fatal) << "Both xi limit and omega limit are 0. Breaking..."; } @@ -810,34 +810,40 @@ class CascadeBuilderDerivedToDerived template bool collisionHasTooFewXis(T1 const& col, T2 const& /*xiTable*/, T3& partitionXi, T4& cache) { + if (mLimitXi == 0) { // xis disabled, cannot reject on them + return false; + } auto xiSlice = partitionXi->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); - return xiSlice.size() < mLimitXi; + return xiSlice.size() < static_cast(mLimitXi); } template bool collisionHasTooFewOmegas(T1 const& col, T2 const& /*omegaTable*/, T3& partitionOmega, T4& cache) { + if (mLimitOmega == 0) { // omegas disabled, cannot reject on them + return false; + } auto omegaSlice = partitionOmega->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); - return omegaSlice.size() < mLimitOmega; + return omegaSlice.size() < static_cast(mLimitOmega); } template void processXis(T1 const& col, T2 const& /*xiTable*/, T3 const& oldTrackTable, T4& partitionXi, T5& trackBuilder, T6& cache, T7& newXiTable, T8& newTrackTable, T9& newCollisionTable) { + if (mLimitXi == 0) { // xis disabled + return; + } + auto xiSlice = partitionXi->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); for (auto const& xi : xiSlice) { + auto bachelor = oldTrackTable.rawIteratorAt(this->daughterRow(xi.bachelorId(), oldTrackTable)); + auto posDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(xi.posDauId(), oldTrackTable)); + auto negDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(xi.negDauId(), oldTrackTable)); - // auto bachelor = xi.template bachelor_as(); - // auto posDaughter = xi.template posDau_as(); - // auto negDaughter = xi.template negDau_as(); - auto bachelor = oldTrackTable.rawIteratorAt(xi.bachelorId() - oldTrackTable.offset()); - auto posDaughter = oldTrackTable.rawIteratorAt(xi.posDauId() - oldTrackTable.offset()); - auto negDaughter = oldTrackTable.rawIteratorAt(xi.negDauId() - oldTrackTable.offset()); - - int bachelorIndex = trackBuilder.getDaughterIndex(bachelor, newTrackTable, newCollisionTable); - int posDaughterIndex = trackBuilder.getDaughterIndex(posDaughter, newTrackTable, newCollisionTable); - int negDaughterIndex = trackBuilder.getDaughterIndex(negDaughter, newTrackTable, newCollisionTable); + int64_t bachelorIndex = trackBuilder.getDaughterIndex(bachelor, newTrackTable, newCollisionTable); + int64_t posDaughterIndex = trackBuilder.getDaughterIndex(posDaughter, newTrackTable, newCollisionTable); + int64_t negDaughterIndex = trackBuilder.getDaughterIndex(negDaughter, newTrackTable, newCollisionTable); newXiTable.producedXis(newCollisionTable.producedCollision.lastIndex(), xi.signedPt(), @@ -854,20 +860,20 @@ class CascadeBuilderDerivedToDerived template void processOmegas(T1 const& col, T2 const& /*omegaTable*/, T3 const& oldTrackTable, T4& partitionOmega, T5& trackBuilder, T6& cache, T7& newOmegaTable, T8& newTrackTable, T9& newCollisionTable) { + if (mLimitOmega == 0) { // omegas disabled + return; + } + auto omegaSlice = partitionOmega->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); for (auto const& omega : omegaSlice) { + auto bachelor = oldTrackTable.rawIteratorAt(this->daughterRow(omega.bachelorId(), oldTrackTable)); + auto posDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(omega.posDauId(), oldTrackTable)); + auto negDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(omega.negDauId(), oldTrackTable)); - // auto bachelor = omega.template bachelor_as(); - // auto posDaughter = omega.template posDau_as(); - // auto negDaughter = omega.template negDau_as(); - auto bachelor = oldTrackTable.rawIteratorAt(omega.bachelorId() - oldTrackTable.offset()); - auto posDaughter = oldTrackTable.rawIteratorAt(omega.posDauId() - oldTrackTable.offset()); - auto negDaughter = oldTrackTable.rawIteratorAt(omega.negDauId() - oldTrackTable.offset()); - - int bachelorIndex = trackBuilder.getDaughterIndex(bachelor, newTrackTable, newCollisionTable); - int posDaughterIndex = trackBuilder.getDaughterIndex(posDaughter, newTrackTable, newCollisionTable); - int negDaughterIndex = trackBuilder.getDaughterIndex(negDaughter, newTrackTable, newCollisionTable); + int64_t bachelorIndex = trackBuilder.getDaughterIndex(bachelor, newTrackTable, newCollisionTable); + int64_t posDaughterIndex = trackBuilder.getDaughterIndex(posDaughter, newTrackTable, newCollisionTable); + int64_t negDaughterIndex = trackBuilder.getDaughterIndex(negDaughter, newTrackTable, newCollisionTable); newOmegaTable.producedOmegas(newCollisionTable.producedCollision.lastIndex(), omega.signedPt(), @@ -882,6 +888,20 @@ class CascadeBuilderDerivedToDerived } private: + /// Translate a global daughter index into a row of the current track table frame. + /// Aborts if the index does not fall inside the frame, which would otherwise + /// silently produce an out-of-range iterator. + template + int64_t daughterRow(int64_t daughterId, T const& trackTable) const + { + const int64_t row = daughterId - trackTable.offset(); + if (daughterId < 0 || row < 0 || row >= static_cast(trackTable.size())) { + LOG(fatal) << "Daughter index " << daughterId << " out of range for track table (offset " + << trackTable.offset() << ", size " << trackTable.size() << "). Breaking..."; + } + return row; + } + int mLimitXi = 0; int mLimitOmega = 0; }; diff --git a/PWGCF/Femto/Core/kinkBuilder.h b/PWGCF/Femto/Core/kinkBuilder.h index b90fa2248f9..db3857eae98 100644 --- a/PWGCF/Femto/Core/kinkBuilder.h +++ b/PWGCF/Femto/Core/kinkBuilder.h @@ -730,24 +730,24 @@ struct ConfKinkTablesDerivedToDerived : o2::framework::ConfigurableGroup { }; struct KinkBuilderDerivedToDerivedProducts : o2::framework::ProducesGroup { - o2::framework::Produces producedSigmas; - o2::framework::Produces producedSigmaMasks; - o2::framework::Produces producedSigmaPluses; - o2::framework::Produces producedSigmaPlusMasks; + o2::framework::Produces producedSigmas; + o2::framework::Produces producedSigmaMasks; + o2::framework::Produces producedSigmaPluses; + o2::framework::Produces producedSigmaPlusMasks; }; class KinkBuilderDerivedToDerived { public: - KinkBuilderDerivedToDerived() = default; - ~KinkBuilderDerivedToDerived() = default; - template void init(T& config) { mLimitSigma = config.limitSigma.value; mLimitSigmaPlus = config.limitSigmaPlus.value; + if (mLimitSigma < 0 || mLimitSigmaPlus < 0) { + LOG(fatal) << "Kink limits must be non-negative (got " << mLimitSigma << " and " << mLimitSigmaPlus << "). Breaking..."; + } if (mLimitSigma == 0 && mLimitSigmaPlus == 0) { LOG(fatal) << "Both sigma limit and sigmaplus limit are 0. Breaking..."; } @@ -756,27 +756,36 @@ class KinkBuilderDerivedToDerived template bool collisionHasTooFewSigma(T1 const& col, T2 const& /*sigmaTable*/, T3& partitionSigma, T4& cache) { + if (mLimitSigma == 0) { // sigmas disabled, cannot reject on them + return false; + } auto sigmaSlice = partitionSigma->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); - return sigmaSlice.size() < mLimitSigma; + return sigmaSlice.size() < static_cast(mLimitSigma); } template bool collisionHasTooFewSigmaPlus(T1 const& col, T2 const& /*sigmaPlusTable*/, T3& partitionSigmaPlus, T4& cache) { + if (mLimitSigmaPlus == 0) { // sigma pluses disabled, cannot reject on them + return false; + } auto sigmaPlusSlice = partitionSigmaPlus->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); - return sigmaPlusSlice.size() < mLimitSigmaPlus; + return sigmaPlusSlice.size() < static_cast(mLimitSigmaPlus); } template void processSigma(T1 const& col, T2 const& /*sigmaTable*/, T3 const& oldTrackTable, T4& partitionSigma, T5& trackBuilder, T6& cache, T7& newSigmaTable, T8& newTrackTable, T9& newCollisionTable) { + if (mLimitSigma == 0) { // sigmas disabled + return; + } + auto sigmaSlice = partitionSigma->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); for (auto const& sigma : sigmaSlice) { + auto chaDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(sigma.chaDauId(), oldTrackTable)); - auto chaDaughter = oldTrackTable.rawIteratorAt(sigma.chaDauId() - oldTrackTable.offset()); - - int chaDaughterIndex = trackBuilder.getDaughterIndex(chaDaughter, newTrackTable, newCollisionTable); + int64_t chaDaughterIndex = trackBuilder.getDaughterIndex(chaDaughter, newTrackTable, newCollisionTable); newSigmaTable.producedSigmas(newCollisionTable.producedCollision.lastIndex(), sigma.signedPt(), @@ -791,13 +800,16 @@ class KinkBuilderDerivedToDerived template void processSigmaPlus(T1 const& col, T2 const& /*sigmaPlusTable*/, T3 const& oldTrackTable, T4& partitionSigmaPlus, T5& trackBuilder, T6& cache, T7& newSigmaPlusTable, T8& newTrackTable, T9& newCollisionTable) { + if (mLimitSigmaPlus == 0) { // sigma pluses disabled + return; + } + auto sigmaPlusSlice = partitionSigmaPlus->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); for (auto const& sigmaPlus : sigmaPlusSlice) { + auto chaDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(sigmaPlus.chaDauId(), oldTrackTable)); - auto chaDaughter = oldTrackTable.rawIteratorAt(sigmaPlus.chaDauId() - oldTrackTable.offset()); - - int chaDaughterIndex = trackBuilder.getDaughterIndex(chaDaughter, newTrackTable, newCollisionTable); + int64_t chaDaughterIndex = trackBuilder.getDaughterIndex(chaDaughter, newTrackTable, newCollisionTable); newSigmaPlusTable.producedSigmaPluses(newCollisionTable.producedCollision.lastIndex(), sigmaPlus.signedPt(), @@ -810,6 +822,20 @@ class KinkBuilderDerivedToDerived } private: + /// Translate a global daughter index into a row of the current track table frame. + /// Aborts if the index does not fall inside the frame, which would otherwise + /// silently produce an out-of-range iterator. + template + int64_t daughterRow(int64_t daughterId, T const& trackTable) const + { + const int64_t row = daughterId - trackTable.offset(); + if (daughterId < 0 || row < 0 || row >= static_cast(trackTable.size())) { + LOG(fatal) << "Daughter index " << daughterId << " out of range for track table (offset " + << trackTable.offset() << ", size " << trackTable.size() << "). Breaking..."; + } + return row; + } + int mLimitSigma = 0; int mLimitSigmaPlus = 0; }; diff --git a/PWGCF/Femto/Core/partitions.h b/PWGCF/Femto/Core/partitions.h index 9d53da4587a..68508aa4c70 100644 --- a/PWGCF/Femto/Core/partitions.h +++ b/PWGCF/Femto/Core/partitions.h @@ -22,8 +22,8 @@ (o2::aod::femtocollisions::posZ >= (selection).vtxZMin && o2::aod::femtocollisions::posZ <= (selection).vtxZMax) && \ (o2::aod::femtocollisions::mult >= (selection).multMin && o2::aod::femtocollisions::mult <= (selection).multMax) && \ (o2::aod::femtocollisions::cent >= (selection).centMin && o2::aod::femtocollisions::cent <= (selection).centMax) && \ - (o2::aod::femtocollisions::magField >= o2::framework::expressions::as((selection).magFieldMin)) && \ - (o2::aod::femtocollisions::magField <= o2::framework::expressions::as((selection).magFieldMax)) && \ + (o2::aod::femtocollisions::magField >= o2::framework::expressions::as((selection).magFieldMin) && \ + o2::aod::femtocollisions::magField <= o2::framework::expressions::as((selection).magFieldMax)) && \ ncheckbit(o2::aod::femtocollisions::mask, (selection).collisionMask) // macro for track momentum, i.e. ||q|*pT/q| * cosh(eta) diff --git a/PWGCF/Femto/Core/trackBuilder.h b/PWGCF/Femto/Core/trackBuilder.h index c7a6f711faf..f2b5a5a4f84 100644 --- a/PWGCF/Femto/Core/trackBuilder.h +++ b/PWGCF/Femto/Core/trackBuilder.h @@ -848,15 +848,15 @@ struct ConfTrackTablesDerivedToDerived : o2::framework::ConfigurableGroup { class TrackBuilderDerivedToDerived { public: - TrackBuilderDerivedToDerived() = default; - ~TrackBuilderDerivedToDerived() = default; - template void init(T& config) { mLimitTrack1 = config.limitTrack1.value; mLimitTrack2 = config.limitTrack2.value; + if (mLimitTrack1 < 0 || mLimitTrack2 < 0) { + LOG(fatal) << "Track limits must be non-negative (got " << mLimitTrack1 << " and " << mLimitTrack2 << "). Breaking..."; + } if (mLimitTrack1 == 0 && mLimitTrack2 == 0) { LOG(fatal) << "Both track limits are 0. Breaking..."; } @@ -867,13 +867,15 @@ class TrackBuilderDerivedToDerived { auto trackSlice1 = partitionTrack1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto trackSlice2 = partitionTrack2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); - return trackSlice1.size() < mLimitTrack1 || trackSlice2.size() < mLimitTrack2; + + const bool tooFew1 = (mLimitTrack1 > 0) && (trackSlice1.size() < static_cast(mLimitTrack1)); + const bool tooFew2 = (mLimitTrack2 > 0) && (trackSlice2.size() < static_cast(mLimitTrack2)); + return tooFew1 || tooFew2; } template void processTracks(T1& col, T2& /*trackTable*/, T3& partitionTrack1, T4& partitionTrack2, T5& cache, T6& newTrackTable, T7& newCollisionTable) { - if (mLimitTrack1 > 0) { auto trackSlice1 = partitionTrack1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); for (auto const& track : trackSlice1) { @@ -889,32 +891,34 @@ class TrackBuilderDerivedToDerived } } + /// Fill a track into the output table, or return its index if it was already filled. + /// \return index of the track in the produced track table template - void fillTrack(T1 const& track, T2& trackProducts, T3& collisionProducts) + int64_t fillTrack(T1 const& track, T2& trackProducts, T3& collisionProducts) { - if (indexMap.find(track.globalIndex()) == indexMap.end()) { // protect against double filling - trackProducts.producedTracks(collisionProducts.producedCollision.lastIndex(), - track.signedPt(), - track.eta(), - track.phi()); - trackProducts.producedTrackMasks(track.mask()); - if constexpr (utils::HasMass) { - trackProducts.producedTrackMass(track.mass()); - } - indexMap.emplace(track.globalIndex(), trackProducts.producedTracks.lastIndex()); + auto index = utils::getIndex(track.globalIndex(), indexMap); + if (index) { // protect against double filling + return index.value(); + } + + trackProducts.producedTracks(collisionProducts.producedCollision.lastIndex(), + track.signedPt(), + track.eta(), + track.phi()); + trackProducts.producedTrackMasks(track.mask()); + if constexpr (utils::HasMass) { + trackProducts.producedTrackMass(track.mass()); } + + const int64_t idx = trackProducts.producedTracks.lastIndex(); + indexMap.emplace(track.globalIndex(), idx); + return idx; } template int64_t getDaughterIndex(const T1& daughter, T2& trackProducts, T3& collisionProducts) { - auto result = utils::getIndex(daughter.globalIndex(), indexMap); - if (result) { - return result.value(); - } - this->fillTrack(daughter, trackProducts, collisionProducts); - int64_t idx = trackProducts.producedTracks.lastIndex(); - return idx; + return this->fillTrack(daughter, trackProducts, collisionProducts); } template @@ -928,7 +932,7 @@ class TrackBuilderDerivedToDerived int mLimitTrack1 = 0; int mLimitTrack2 = 0; - std::unordered_map indexMap; // for mapping tracks to daughers of lambdas, cascades and resonances ... + std::unordered_map indexMap; // for mapping tracks to daughters of lambdas, cascades and resonances ... }; } // namespace o2::analysis::femto::trackbuilder diff --git a/PWGCF/Femto/Core/v0Builder.h b/PWGCF/Femto/Core/v0Builder.h index 8fcdb65bbdb..9b59f46a258 100644 --- a/PWGCF/Femto/Core/v0Builder.h +++ b/PWGCF/Femto/Core/v0Builder.h @@ -784,15 +784,15 @@ struct V0BuilderDerivedToDerivedProducts : o2::framework::ProducesGroup { class V0BuilderDerivedToDerived { public: - V0BuilderDerivedToDerived() = default; - ~V0BuilderDerivedToDerived() = default; - template void init(T& config) { mLimitLambda = config.limitLambda.value; mLimitK0short = config.limitK0short.value; + if (mLimitLambda < 0 || mLimitK0short < 0) { + LOG(fatal) << "V0 limits must be non-negative (got " << mLimitLambda << " and " << mLimitK0short << "). Breaking..."; + } if (mLimitLambda == 0 && mLimitK0short == 0) { LOG(fatal) << "Both lambda limit and k0short limit are 0. Breaking..."; } @@ -801,31 +801,38 @@ class V0BuilderDerivedToDerived template bool collisionHasTooFewLambdas(T1 const& col, T2 const& /*lambdaTable*/, T3& partitionLambda, T4& cache) { + if (mLimitLambda == 0) { // lambdas disabled, cannot reject on them + return false; + } auto lambdaSlice = partitionLambda->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); - return lambdaSlice.size() < mLimitLambda; + return lambdaSlice.size() < static_cast(mLimitLambda); } template bool collisionHasTooFewK0shorts(T1 const& col, T2 const& /*k0shortTable*/, T3& partitionK0short, T4& cache) { + if (mLimitK0short == 0) { // k0shorts disabled, cannot reject on them + return false; + } auto k0shortSlice = partitionK0short->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); - return k0shortSlice.size() < mLimitK0short; + return k0shortSlice.size() < static_cast(mLimitK0short); } template void processLambdas(T1 const& col, T2 const& /*lambdaTable*/, T3 const& oldTrackTable, T4& partitionLambda, T5& trackBuilder, T6& cache, T7& newLambdaTable, T8& newTrackTable, T9& newCollisionTable) { + if (mLimitLambda == 0) { // lambdas disabled + return; + } + auto lambdaSlice = partitionLambda->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); for (auto const& lambda : lambdaSlice) { + auto posDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(lambda.posDauId(), oldTrackTable)); + auto negDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(lambda.negDauId(), oldTrackTable)); - // auto posDaughter = lambda.template posDau_as(); - // auto negDaughter = lambda.template negDau_as(); - auto posDaughter = oldTrackTable.rawIteratorAt(lambda.posDauId() - oldTrackTable.offset()); - auto negDaughter = oldTrackTable.rawIteratorAt(lambda.negDauId() - oldTrackTable.offset()); - - int posDaughterIndex = trackBuilder.getDaughterIndex(posDaughter, newTrackTable, newCollisionTable); - int negDaughterIndex = trackBuilder.getDaughterIndex(negDaughter, newTrackTable, newCollisionTable); + int64_t posDaughterIndex = trackBuilder.getDaughterIndex(posDaughter, newTrackTable, newCollisionTable); + int64_t negDaughterIndex = trackBuilder.getDaughterIndex(negDaughter, newTrackTable, newCollisionTable); newLambdaTable.producedLambdas(newCollisionTable.producedCollision.lastIndex(), lambda.signedPt(), @@ -841,17 +848,18 @@ class V0BuilderDerivedToDerived template void processK0shorts(T1 const& col, T2 const& /*k0shortTable*/, T3 const& oldTrackTable, T4& partitionK0short, T5& trackBuilder, T6& cache, T7& newK0shortTable, T8& newTrackTable, T9& newCollisionTable) { + if (mLimitK0short == 0) { // k0shorts disabled + return; + } + auto k0shortSlice = partitionK0short->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); for (auto const& k0short : k0shortSlice) { + auto posDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(k0short.posDauId(), oldTrackTable)); + auto negDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(k0short.negDauId(), oldTrackTable)); - // auto posDaughter = k0short.template posDau_as(); - // auto negDaughter = k0short.template negDau_as(); - auto posDaughter = oldTrackTable.rawIteratorAt(k0short.posDauId() - oldTrackTable.offset()); - auto negDaughter = oldTrackTable.rawIteratorAt(k0short.negDauId() - oldTrackTable.offset()); - - int posDaughterIndex = trackBuilder.getDaughterIndex(posDaughter, newTrackTable, newCollisionTable); - int negDaughterIndex = trackBuilder.getDaughterIndex(negDaughter, newTrackTable, newCollisionTable); + int64_t posDaughterIndex = trackBuilder.getDaughterIndex(posDaughter, newTrackTable, newCollisionTable); + int64_t negDaughterIndex = trackBuilder.getDaughterIndex(negDaughter, newTrackTable, newCollisionTable); newK0shortTable.producedK0shorts(newCollisionTable.producedCollision.lastIndex(), k0short.pt(), @@ -865,6 +873,20 @@ class V0BuilderDerivedToDerived } private: + /// Translate a global daughter index into a row of the current track table frame. + /// Aborts if the index does not fall inside the frame, which would otherwise + /// silently produce an out-of-range iterator. + template + int64_t daughterRow(int64_t daughterId, T const& trackTable) const + { + const int64_t row = daughterId - trackTable.offset(); + if (daughterId < 0 || row < 0 || row >= static_cast(trackTable.size())) { + LOG(fatal) << "Daughter index " << daughterId << " out of range for track table (offset " + << trackTable.offset() << ", size " << trackTable.size() << "). Breaking..."; + } + return row; + } + int mLimitLambda = 0; int mLimitK0short = 0; }; diff --git a/PWGCF/Femto/DataModel/FemtoTables.h b/PWGCF/Femto/DataModel/FemtoTables.h index efd1aae4789..d7aa6003e6d 100644 --- a/PWGCF/Femto/DataModel/FemtoTables.h +++ b/PWGCF/Femto/DataModel/FemtoTables.h @@ -932,6 +932,7 @@ using StoredFLiteSigmaPlus = StoredFLiteSigmaPlus_001; DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaPlusMasks_001, "FSIGMAPLUSMASKS", 1, femtokinks::Mask); using FSigmaPlusMasks = FSigmaPlusMasks_001; +using StoredFSigmaPlusMasks = StoredFSigmaPlusMasks_001; DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaPlusExtras_001, "FSIGMAPLUSEXTRAS", 1, femtokinks::KinkAngle, diff --git a/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx b/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx index bde9713d72e..27c196bc87c 100644 --- a/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx @@ -35,7 +35,6 @@ struct FemtoProducerDerivedToDerived { // setup tables using FemtoCollisions = o2::soa::Join; - using FemtoCollision = FemtoCollisions::iterator; using FilteredFemtoCollisions = o2::soa::Filtered; using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; @@ -109,17 +108,23 @@ struct FemtoProducerDerivedToDerived { void init(o2::framework::InitContext& /*context*/) { + const int activeProcesses = + static_cast(doprocessTracks) + static_cast(doprocessTracksWithMass) + + static_cast(doprocessTracksLambdas) + static_cast(doprocessLambdas) + + static_cast(doprocessTracksXis) + static_cast(doprocessTracksOmegas) + + static_cast(doprocessTracksK0shorts) + static_cast(doprocessTracksSigma) + + static_cast(doprocessTracksSigmaPlus); + if (activeProcesses != 1) { + LOG(fatal) << "Exactly one process function must be activated (got " << activeProcesses << ")."; + } + trackBuilder.init(confTrackBuilder); v0Builder.init(confV0Builder); cascadeBuilder.init(confCascadeBuilder); kinkBuilder.init(confKinkBuilder); - - if ((static_cast(doprocessTracks) + static_cast(doprocessTracksWithMass) + static_cast(doprocessTracksLambdas) + static_cast(doprocessLambdas) + static_cast(doprocessTracksXis) + static_cast(doprocessTracksOmegas) + static_cast(doprocessTracksK0shorts) + static_cast(doprocessTracksSigma) + static_cast(doprocessTracksSigmaPlus)) > 1) { - LOG(fatal) << "Only one proccess function can be activated!"; - } } - // proccess functions + // process functions void processTracks(FilteredFemtoCollision const& col, FemtoTracks const& tracks) { if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache)) { @@ -163,7 +168,7 @@ struct FemtoProducerDerivedToDerived { collisionBuilder.processCollision(col, collisionBuilderProducts); v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); } - PROCESS_SWITCH(FemtoProducerDerivedToDerived, processLambdas, "Process lambdas", false); + PROCESS_SWITCH(FemtoProducerDerivedToDerived, processLambdas, "Process lambdas only (produced track table contains daughers only)", false); void processTracksXis(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoXis const& xis) { From 0484b3dace0ca27e7daf86e35b4e976a3ae7185c Mon Sep 17 00:00:00 2001 From: Anton Riedel Date: Tue, 11 Aug 2026 13:45:16 +0200 Subject: [PATCH 3/4] Feat: use common daughterRow function --- PWGCF/Femto/Core/cascadeBuilder.h | 26 ++++++-------------------- PWGCF/Femto/Core/femtoUtils.h | 14 ++++++++++++++ PWGCF/Femto/Core/kinkBuilder.h | 18 ++---------------- PWGCF/Femto/Core/v0Builder.h | 22 ++++------------------ 4 files changed, 26 insertions(+), 54 deletions(-) diff --git a/PWGCF/Femto/Core/cascadeBuilder.h b/PWGCF/Femto/Core/cascadeBuilder.h index 1ca053b9392..8e278388adf 100644 --- a/PWGCF/Femto/Core/cascadeBuilder.h +++ b/PWGCF/Femto/Core/cascadeBuilder.h @@ -837,9 +837,9 @@ class CascadeBuilderDerivedToDerived auto xiSlice = partitionXi->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); for (auto const& xi : xiSlice) { - auto bachelor = oldTrackTable.rawIteratorAt(this->daughterRow(xi.bachelorId(), oldTrackTable)); - auto posDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(xi.posDauId(), oldTrackTable)); - auto negDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(xi.negDauId(), oldTrackTable)); + auto bachelor = oldTrackTable.rawIteratorAt(utils::daughterRow(xi.bachelorId(), oldTrackTable)); + auto posDaughter = oldTrackTable.rawIteratorAt(utils::daughterRow(xi.posDauId(), oldTrackTable)); + auto negDaughter = oldTrackTable.rawIteratorAt(utils::daughterRow(xi.negDauId(), oldTrackTable)); int64_t bachelorIndex = trackBuilder.getDaughterIndex(bachelor, newTrackTable, newCollisionTable); int64_t posDaughterIndex = trackBuilder.getDaughterIndex(posDaughter, newTrackTable, newCollisionTable); @@ -867,9 +867,9 @@ class CascadeBuilderDerivedToDerived auto omegaSlice = partitionOmega->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); for (auto const& omega : omegaSlice) { - auto bachelor = oldTrackTable.rawIteratorAt(this->daughterRow(omega.bachelorId(), oldTrackTable)); - auto posDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(omega.posDauId(), oldTrackTable)); - auto negDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(omega.negDauId(), oldTrackTable)); + auto bachelor = oldTrackTable.rawIteratorAt(utils::daughterRow(omega.bachelorId(), oldTrackTable)); + auto posDaughter = oldTrackTable.rawIteratorAt(utils::daughterRow(omega.posDauId(), oldTrackTable)); + auto negDaughter = oldTrackTable.rawIteratorAt(utils::daughterRow(omega.negDauId(), oldTrackTable)); int64_t bachelorIndex = trackBuilder.getDaughterIndex(bachelor, newTrackTable, newCollisionTable); int64_t posDaughterIndex = trackBuilder.getDaughterIndex(posDaughter, newTrackTable, newCollisionTable); @@ -888,20 +888,6 @@ class CascadeBuilderDerivedToDerived } private: - /// Translate a global daughter index into a row of the current track table frame. - /// Aborts if the index does not fall inside the frame, which would otherwise - /// silently produce an out-of-range iterator. - template - int64_t daughterRow(int64_t daughterId, T const& trackTable) const - { - const int64_t row = daughterId - trackTable.offset(); - if (daughterId < 0 || row < 0 || row >= static_cast(trackTable.size())) { - LOG(fatal) << "Daughter index " << daughterId << " out of range for track table (offset " - << trackTable.offset() << ", size " << trackTable.size() << "). Breaking..."; - } - return row; - } - int mLimitXi = 0; int mLimitOmega = 0; }; diff --git a/PWGCF/Femto/Core/femtoUtils.h b/PWGCF/Femto/Core/femtoUtils.h index d4c9ff2e3f3..fa4b9a23466 100644 --- a/PWGCF/Femto/Core/femtoUtils.h +++ b/PWGCF/Femto/Core/femtoUtils.h @@ -47,6 +47,20 @@ inline std::optional getIndex(const T1& index, const std::unordered_map +int64_t daughterRow(int64_t daughterId, T const& trackTable) +{ + const int64_t row = daughterId - trackTable.offset(); + if (daughterId < 0 || row < 0 || row >= static_cast(trackTable.size())) { + LOG(fatal) << "Daughter index " << daughterId << " out of range for track table (offset " + << trackTable.offset() << ", size " << trackTable.size() << "). Breaking..."; + } + return row; +} + template float itsSignal(T const& track) { diff --git a/PWGCF/Femto/Core/kinkBuilder.h b/PWGCF/Femto/Core/kinkBuilder.h index db3857eae98..5b794be7773 100644 --- a/PWGCF/Femto/Core/kinkBuilder.h +++ b/PWGCF/Femto/Core/kinkBuilder.h @@ -783,7 +783,7 @@ class KinkBuilderDerivedToDerived auto sigmaSlice = partitionSigma->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); for (auto const& sigma : sigmaSlice) { - auto chaDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(sigma.chaDauId(), oldTrackTable)); + auto chaDaughter = oldTrackTable.rawIteratorAt(utils::daughterRow(sigma.chaDauId(), oldTrackTable)); int64_t chaDaughterIndex = trackBuilder.getDaughterIndex(chaDaughter, newTrackTable, newCollisionTable); @@ -807,7 +807,7 @@ class KinkBuilderDerivedToDerived auto sigmaPlusSlice = partitionSigmaPlus->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); for (auto const& sigmaPlus : sigmaPlusSlice) { - auto chaDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(sigmaPlus.chaDauId(), oldTrackTable)); + auto chaDaughter = oldTrackTable.rawIteratorAt(utils::daughterRow(sigmaPlus.chaDauId(), oldTrackTable)); int64_t chaDaughterIndex = trackBuilder.getDaughterIndex(chaDaughter, newTrackTable, newCollisionTable); @@ -822,20 +822,6 @@ class KinkBuilderDerivedToDerived } private: - /// Translate a global daughter index into a row of the current track table frame. - /// Aborts if the index does not fall inside the frame, which would otherwise - /// silently produce an out-of-range iterator. - template - int64_t daughterRow(int64_t daughterId, T const& trackTable) const - { - const int64_t row = daughterId - trackTable.offset(); - if (daughterId < 0 || row < 0 || row >= static_cast(trackTable.size())) { - LOG(fatal) << "Daughter index " << daughterId << " out of range for track table (offset " - << trackTable.offset() << ", size " << trackTable.size() << "). Breaking..."; - } - return row; - } - int mLimitSigma = 0; int mLimitSigmaPlus = 0; }; diff --git a/PWGCF/Femto/Core/v0Builder.h b/PWGCF/Femto/Core/v0Builder.h index 9b59f46a258..618d6a1856d 100644 --- a/PWGCF/Femto/Core/v0Builder.h +++ b/PWGCF/Femto/Core/v0Builder.h @@ -828,8 +828,8 @@ class V0BuilderDerivedToDerived auto lambdaSlice = partitionLambda->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); for (auto const& lambda : lambdaSlice) { - auto posDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(lambda.posDauId(), oldTrackTable)); - auto negDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(lambda.negDauId(), oldTrackTable)); + auto posDaughter = oldTrackTable.rawIteratorAt(utils::daughterRow(lambda.posDauId(), oldTrackTable)); + auto negDaughter = oldTrackTable.rawIteratorAt(utils::daughterRow(lambda.negDauId(), oldTrackTable)); int64_t posDaughterIndex = trackBuilder.getDaughterIndex(posDaughter, newTrackTable, newCollisionTable); int64_t negDaughterIndex = trackBuilder.getDaughterIndex(negDaughter, newTrackTable, newCollisionTable); @@ -855,8 +855,8 @@ class V0BuilderDerivedToDerived auto k0shortSlice = partitionK0short->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); for (auto const& k0short : k0shortSlice) { - auto posDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(k0short.posDauId(), oldTrackTable)); - auto negDaughter = oldTrackTable.rawIteratorAt(this->daughterRow(k0short.negDauId(), oldTrackTable)); + auto posDaughter = oldTrackTable.rawIteratorAt(utils::daughterRow(k0short.posDauId(), oldTrackTable)); + auto negDaughter = oldTrackTable.rawIteratorAt(utils::daughterRow(k0short.negDauId(), oldTrackTable)); int64_t posDaughterIndex = trackBuilder.getDaughterIndex(posDaughter, newTrackTable, newCollisionTable); int64_t negDaughterIndex = trackBuilder.getDaughterIndex(negDaughter, newTrackTable, newCollisionTable); @@ -873,20 +873,6 @@ class V0BuilderDerivedToDerived } private: - /// Translate a global daughter index into a row of the current track table frame. - /// Aborts if the index does not fall inside the frame, which would otherwise - /// silently produce an out-of-range iterator. - template - int64_t daughterRow(int64_t daughterId, T const& trackTable) const - { - const int64_t row = daughterId - trackTable.offset(); - if (daughterId < 0 || row < 0 || row >= static_cast(trackTable.size())) { - LOG(fatal) << "Daughter index " << daughterId << " out of range for track table (offset " - << trackTable.offset() << ", size " << trackTable.size() << "). Breaking..."; - } - return row; - } - int mLimitLambda = 0; int mLimitK0short = 0; }; From ce4dc92984685f7a9232b19792b63d862ff24433 Mon Sep 17 00:00:00 2001 From: Anton Riedel Date: Tue, 11 Aug 2026 13:59:55 +0200 Subject: [PATCH 4/4] Feat: add FLiteColShapes in collisionBuilder --- PWGCF/Femto/Core/collisionBuilder.h | 38 ++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/PWGCF/Femto/Core/collisionBuilder.h b/PWGCF/Femto/Core/collisionBuilder.h index ab8d5e311d6..6b2660ae66b 100644 --- a/PWGCF/Femto/Core/collisionBuilder.h +++ b/PWGCF/Femto/Core/collisionBuilder.h @@ -291,7 +291,7 @@ class CollisionSelection : public baseselection::BaseSelection @@ -320,7 +320,7 @@ class CollisionSelection : public baseselection::BaseSelectionassembleBitmask(); - }; + } protected: template float computeSphericity(T const& tracks) { - int minNumberTracks = 2; - double maxSphericity = 2.f; + const int64_t minNumberTracks = 2; + const double maxSphericity = 2.f; if (tracks.size() <= minNumberTracks) { return maxSphericity; } @@ -529,7 +529,7 @@ class CollisionSelection : public baseselection::BaseSelection producedMultiplicityEstimators; o2::framework::Produces producedCentralityEstimators; o2::framework::Produces producedShapes; + o2::framework::Produces producedLiteShapes; }; struct ConfCollisionTables : o2::framework::ConfigurableGroup { @@ -580,6 +581,7 @@ struct ConfCollisionTables : o2::framework::ConfigurableGroup { o2::framework::Configurable produceMults{"produceMults", -1, "Produce Multiplicities (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceCents{"produceCents", -1, "Produce Centralities (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceShapes{"produceShapes", -1, "Produce Event shape variables (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLiteShapes{"produceLiteShapes", -1, "Produce Lite Event shape variables (-1: auto; 0 off; 1 on)"}; }; template @@ -606,16 +608,22 @@ class CollisionBuilder mProducedMultiplicities = utils::enableTable("FColMults_001", confTable.produceMults.value, initContext); mProducedCentralities = utils::enableTable("FColCents_001", confTable.produceCents.value, initContext); mProducedShapes = utils::enableTable("FColShapes_001", confTable.produceShapes.value, initContext); + mProducedLiteShapes = utils::enableTable("FLiteColShapes_001", confTable.produceLiteShapes.value, initContext); if (mProducedCollisions && mProducedLiteCollisions) { LOG(fatal) << "FCols and FLiteCols are mutually exclusive -- enable only one. " << "FLiteCols is meant to only replace FCols at the producer stage (for better compression in derived data); " << "use the dedicated converter task to reconstruct FCols from FLiteCols downstream."; } + if (mProducedShapes && mProducedLiteShapes) { + LOG(fatal) << "FColShapes and FLiteColShapes are mutually exclusive -- enable only one. " + << "FLiteColShapes is meant to only replace FColShapes at the producer stage (for better compression in derived data); " + << "use the dedicated converter task to reconstruct FColShapes from FLiteColShapes downstream."; + } if (mProducedCollisions || mProducedLiteCollisions || mProducedCollisionMasks || mProducedPositions || mProducedSphericities || mProducedMultiplicities || - mProducedCentralities) { + mProducedCentralities || mProducedShapes || mProducedLiteShapes) { mFillAnyTable = true; } else { LOG(info) << "No tables configured, Selection object will not be configured..."; @@ -634,15 +642,14 @@ class CollisionBuilder if (mRunNumber != bc.runNumber()) { mRunNumber = bc.runNumber(); if (mMagFieldForced == 0) { - static o2::parameters::GRPMagField* grpo = nullptr; - LOG(info) << "Get magentic field with Path: " << mGrpPath << "; Run number: " << mRunNumber; - grpo = ccdb->template getForRun(mGrpPath, mRunNumber); + o2::parameters::GRPMagField* grpo = ccdb->template getForRun(mGrpPath, mRunNumber); + LOG(info) << "Get magnetic field with Path: " << mGrpPath << "; Run number: " << mRunNumber; if (grpo == nullptr) { LOG(fatal) << "GRP object not found for Run " << mRunNumber; } mMagField = static_cast(grpo->getNominalL3Field()); // get magnetic field in kG } else { - LOG(info) << "Force magentic field to " << mMagFieldForced << "kG"; + LOG(info) << "Force magnetic field to " << mMagFieldForced << "kG"; mMagField = mMagFieldForced; } @@ -752,6 +759,12 @@ class CollisionBuilder mCollisionSelection.getEventPlane()); } + if (mProducedLiteShapes) { + collisionProducts.producedLiteShapes( + o2::aod::femtocollisions::lite::binQvec(mCollisionSelection.getQvector()), + o2::aod::femtocollisions::lite::binEventPlaneAngle(mCollisionSelection.getEventPlane())); + } + mCollisionAlreadyFilled = true; } @@ -795,6 +808,7 @@ class CollisionBuilder bool mProducedMultiplicities = false; bool mProducedCentralities = false; bool mProducedShapes = false; + bool mProducedLiteShapes = false; }; struct CollisionBuilderDerivedToDerivedProducts : o2::framework::ProducesGroup {