From 629d2f533528ef80e1fbd0132b6a3635aaa9b620 Mon Sep 17 00:00:00 2001 From: Anton Riedel Date: Thu, 23 Jul 2026 21:55:31 +0200 Subject: [PATCH] Feat: add lite track and collision tables --- PWGCF/Femto/Core/cascadeBuilder.h | 12 +- PWGCF/Femto/Core/collisionBuilder.h | 33 ++++- PWGCF/Femto/Core/femtoUtils.h | 52 ++++++++ PWGCF/Femto/Core/kinkBuilder.h | 4 +- PWGCF/Femto/Core/mcBuilder.h | 3 + PWGCF/Femto/Core/trackBuilder.h | 73 +++++++---- PWGCF/Femto/Core/v0Builder.h | 8 +- PWGCF/Femto/DataModel/FemtoTables.h | 121 +++++++++++++++++- PWGCF/Femto/TableProducer/CMakeLists.txt | 7 +- PWGCF/Femto/TableProducer/femtoProducer.cxx | 1 - .../femtoProducerLiteConverter.cxx | 57 +++++++++ 11 files changed, 324 insertions(+), 47 deletions(-) create mode 100644 PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx diff --git a/PWGCF/Femto/Core/cascadeBuilder.h b/PWGCF/Femto/Core/cascadeBuilder.h index 9e3a73ae2c5..dd1d2d4b15b 100644 --- a/PWGCF/Femto/Core/cascadeBuilder.h +++ b/PWGCF/Femto/Core/cascadeBuilder.h @@ -517,13 +517,13 @@ class CascadeBuilder collisionBuilder.template fillCollision(collisionProducts, col); auto bachelor = cascade.template bachelor_as(); - bachelorIndex = trackBuilder.template getDaughterIndex(bachelor, trackProducts, collisionProducts); + bachelorIndex = trackBuilder.template getDaughterIndex(bachelor, trackProducts, collisionBuilder); auto posDaughter = cascade.template posTrack_as(); - posDaughterIndex = trackBuilder.template getDaughterIndex(posDaughter, trackProducts, collisionProducts); + posDaughterIndex = trackBuilder.template getDaughterIndex(posDaughter, trackProducts, collisionBuilder); auto negDaughter = cascade.template negTrack_as(); - negDaughterIndex = trackBuilder.template getDaughterIndex(negDaughter, trackProducts, collisionProducts); + negDaughterIndex = trackBuilder.template getDaughterIndex(negDaughter, trackProducts, collisionBuilder); fillCascade(collisionProducts, cascadeProducts, cascade, col, bachelorIndex, posDaughterIndex, negDaughterIndex); } @@ -551,13 +551,13 @@ class CascadeBuilder collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); auto bachelor = cascade.template bachelor_as(); - bachelorIndex = trackBuilder.template getDaughterIndex(col, collisionProducts, mcCols, bachelor, trackProducts, mcParticles, mcBuilder, mcProducts); + bachelorIndex = trackBuilder.template getDaughterIndex(col, collisionBuilder, mcCols, bachelor, trackProducts, mcParticles, mcBuilder, mcProducts); auto posDaughter = cascade.template posTrack_as(); - posDaughterIndex = trackBuilder.template getDaughterIndex(col, collisionProducts, mcCols, posDaughter, trackProducts, mcParticles, mcBuilder, mcProducts); + posDaughterIndex = trackBuilder.template getDaughterIndex(col, collisionBuilder, mcCols, posDaughter, trackProducts, mcParticles, mcBuilder, mcProducts); auto negDaughter = cascade.template negTrack_as(); - negDaughterIndex = trackBuilder.template getDaughterIndex(col, collisionProducts, mcCols, negDaughter, trackProducts, mcParticles, mcBuilder, mcProducts); + negDaughterIndex = trackBuilder.template getDaughterIndex(col, collisionBuilder, mcCols, negDaughter, trackProducts, mcParticles, mcBuilder, mcProducts); fillCascade(collisionProducts, cascadeProducts, cascade, col, bachelorIndex, posDaughterIndex, negDaughterIndex); if constexpr (modes::isEqual(cascadeType, modes::Cascade::kXi)) { diff --git a/PWGCF/Femto/Core/collisionBuilder.h b/PWGCF/Femto/Core/collisionBuilder.h index 7080ed19286..4fd4d499d60 100644 --- a/PWGCF/Femto/Core/collisionBuilder.h +++ b/PWGCF/Femto/Core/collisionBuilder.h @@ -500,6 +500,7 @@ class CollisionSelection : public baseselection::BaseSelection producedCollision; + o2::framework::Produces producedLiteCollision; o2::framework::Produces producedCollisionMask; o2::framework::Produces producedPositions; o2::framework::Produces producedSphericities; @@ -511,6 +512,7 @@ struct CollisionBuilderProducts : o2::framework::ProducesGroup { struct ConfCollisionTables : o2::framework::ConfigurableGroup { std::string prefix = std::string("CollisionTables"); o2::framework::Configurable produceCollisions{"produceCollisions", -1, "Produce Collisions (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLiteCollisions{"produceLiteCollisions", -1, "Produce Lite Collisions (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceCollisionMasks{"produceCollisionMasks", -1, "Produce Collision Masks (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producePositions{"producePositions", -1, "Produce Positions (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceSphericities{"produceSphericities", -1, "Produce Sphericity (-1: auto; 0 off; 1 on)"}; @@ -536,13 +538,21 @@ class CollisionBuilder mSubGeneratorId = confFilter.subGeneratorId.value; mProducedCollisions = utils::enableTable("FCols_001", confTable.produceCollisions.value, initContext); + mProducedLiteCollisions = utils::enableTable("FLiteCols_001", confTable.produceLiteCollisions.value, initContext); mProducedCollisionMasks = utils::enableTable("FColMasks_001", confTable.produceCollisionMasks.value, initContext); mProducedPositions = utils::enableTable("FColPos_001", confTable.producePositions.value, initContext); mProducedSphericities = utils::enableTable("FColSphericities_001", confTable.produceSphericities.value, initContext); mProducedMultiplicities = utils::enableTable("FColMults_001", confTable.produceMults.value, initContext); mProducedCentralities = utils::enableTable("FColCents_001", confTable.produceCents.value, initContext); mProduceQns = utils::enableTable("FColQnBins_001", confTable.produceQns.value, initContext); - if (mProducedCollisions || mProducedCollisionMasks || mProducedPositions || mProducedSphericities || mProducedMultiplicities || mProducedCentralities) { + + 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 (mProducedCollisions || mProducedLiteCollisions || mProducedCollisionMasks || mProducedPositions || mProducedSphericities || mProducedMultiplicities || mProducedCentralities) { mFillAnyTable = true; } else { LOG(info) << "No tables configured, Selection object will not be configured..."; @@ -616,17 +626,25 @@ class CollisionBuilder if (!mFillAnyTable) { return; } - if (mCollisionAlreadyFilled) { return; } - if (mProducedCollisions) { collisionProducts.producedCollision(col.posZ(), col.multNTracksPV(), mCollisionSelection.getCentrality(), static_cast(mCollisionSelection.getMagneticField())); + + mCurrentCollisionIndex = collisionProducts.producedCollision.lastIndex(); + } + if (mProducedLiteCollisions) { + collisionProducts.producedLiteCollision(o2::aod::femtocollisions::lite::binPosZ(col.posZ()), + o2::aod::femtocollisions::lite::binMult(col.multNTracksPV()), + o2::aod::femtocollisions::lite::binCent(mCollisionSelection.getCentrality()), + static_cast(mCollisionSelection.getMagneticField())); + mCurrentCollisionIndex = collisionProducts.producedLiteCollision.lastIndex(); } + if (mProducedCollisionMasks) { collisionProducts.producedCollisionMask(mCollisionSelection.getBitmask()); } @@ -673,11 +691,17 @@ class CollisionBuilder mcBuilder.template fillMcCollisionWithLabel(mcProducts, col, mcCols); } - void reset() { mCollisionAlreadyFilled = false; } + [[nodiscard]] int64_t collisionIndex() const { return mCurrentCollisionIndex; } + void reset() + { + mCollisionAlreadyFilled = false; + mCurrentCollisionIndex = -1; + } private: CollisionSelection mCollisionSelection; bool mCollisionAlreadyFilled = false; + int64_t mCurrentCollisionIndex = -1; int mRunNumber = -1; std::string mGrpPath = std::string(""); int mMagFieldForced = 0; @@ -685,6 +709,7 @@ class CollisionBuilder int mSubGeneratorId = -1; bool mFillAnyTable = false; bool mProducedCollisions = false; + bool mProducedLiteCollisions = false; bool mProducedCollisionMasks = false; bool mProducedPositions = false; bool mProducedSphericities = false; diff --git a/PWGCF/Femto/Core/femtoUtils.h b/PWGCF/Femto/Core/femtoUtils.h index 1e0e87fb4e3..de8b24d3da9 100644 --- a/PWGCF/Femto/Core/femtoUtils.h +++ b/PWGCF/Femto/Core/femtoUtils.h @@ -24,9 +24,11 @@ #include +#include #include #include #include +#include #include #include @@ -228,6 +230,56 @@ inline int signum(T x) return (T(0) < x) - (x < T(0)); } +template +inline 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)); + auto maxIdx = static_cast(std::numeric_limits::max()) - static_cast(std::numeric_limits::min()); + idx = std::clamp(idx, static_cast(0), maxIdx); + return static_cast(idx + std::numeric_limits::min()); +} + +template +inline 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) +{ + 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); +} + +template +inline 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)); + 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; +} + }; // namespace utils }; // namespace o2::analysis::femto +// #endif // PWGCF_FEMTO_CORE_FEMTOUTILS_H_ diff --git a/PWGCF/Femto/Core/kinkBuilder.h b/PWGCF/Femto/Core/kinkBuilder.h index 3584726eabf..58664220674 100644 --- a/PWGCF/Femto/Core/kinkBuilder.h +++ b/PWGCF/Femto/Core/kinkBuilder.h @@ -547,7 +547,7 @@ class KinkBuilder collisionBuilder.template fillCollision(collisionProducts, col); auto daughter = kink.template trackDaug_as(); - daughterIndex = trackBuilder.template getDaughterIndex(daughter, trackProducts, collisionProducts); + daughterIndex = trackBuilder.template getDaughterIndex(daughter, trackProducts, collisionBuilder); if constexpr (modes::isEqual(kinkType, modes::Kink::kSigma)) { fillSigma(collisionProducts, kinkProducts, kink, daughterIndex); } @@ -581,7 +581,7 @@ class KinkBuilder collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); auto daughter = kink.template trackDaug_as(); - daughterIndex = trackBuilder.template getDaughterIndex(col, collisionProducts, mcCols, daughter, trackProducts, mcParticles, mcBuilder, mcProducts); + daughterIndex = trackBuilder.template getDaughterIndex(col, collisionBuilder, mcCols, daughter, trackProducts, mcParticles, mcBuilder, mcProducts); if constexpr (modes::isEqual(kinkType, modes::Kink::kSigma)) { fillSigma(collisionProducts, kinkProducts, kink, daughterIndex); diff --git a/PWGCF/Femto/Core/mcBuilder.h b/PWGCF/Femto/Core/mcBuilder.h index d37f09c36ab..1f584ec02bf 100644 --- a/PWGCF/Femto/Core/mcBuilder.h +++ b/PWGCF/Femto/Core/mcBuilder.h @@ -162,6 +162,7 @@ class McBuilder void fillMcCollisionWithLabel(T1& mcProducts, T2 const& col, T3 const& /*mcCols*/) { if (!mProduceCollisionLabels) { + mcProducts.producedCollisionLabels(-1); return; } // Case: This reconstructed collision has an MC collision @@ -265,6 +266,7 @@ class McBuilder void fillMcSigmaWithLabel(T1 const& col, T2 const& mcCols, T3 const& sigmaDaughter, T4 const& mcParticles, T5& mcProducts) { if (!mProduceSigmaLabels) { + mcProducts.producedSigmaLabels(-1); return; } fillMcLabelGeneric(col, mcCols, sigmaDaughter, mcParticles, mcProducts, [](auto& prod, int64_t p) { prod.producedSigmaLabels(p); }, true); @@ -274,6 +276,7 @@ class McBuilder void fillMcSigmaPlusWithLabel(T1 const& col, T2 const& mcCols, T3 const& sigmaPlusDaughter, T4 const& mcParticles, T5& mcProducts) { if (!mProduceSigmaPlusLabels) { + mcProducts.producedSigmaPlusLabels(-1); return; } fillMcLabelGeneric(col, mcCols, sigmaPlusDaughter, mcParticles, mcProducts, [](auto& prod, int64_t p) { prod.producedSigmaPlusLabels(p); }, true); diff --git a/PWGCF/Femto/Core/trackBuilder.h b/PWGCF/Femto/Core/trackBuilder.h index ab25867c8c9..fcb8bc763c4 100644 --- a/PWGCF/Femto/Core/trackBuilder.h +++ b/PWGCF/Femto/Core/trackBuilder.h @@ -530,6 +530,7 @@ class TrackSelection : public baseselection::BaseSelection producedTracks; + o2::framework::Produces producedLiteTracks; o2::framework::Produces producedTrackMass; o2::framework::Produces producedTrackMasks; o2::framework::Produces producedTrackDcas; @@ -546,6 +547,7 @@ struct TrackBuilderProducts : o2::framework::ProducesGroup { struct ConfTrackTables : o2::framework::ConfigurableGroup { std::string prefix = std::string("TrackTables"); o2::framework::Configurable produceTracks{"produceTracks", -1, "Produce Tracks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLiteTracks{"produceLiteTracks", -1, "Produce LiteTracks (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceTrackMasks{"produceTrackMasks", -1, "Produce TrackMasks (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceTrackMass{"produceTrackMass", -1, "Produce TrackMass (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceTrackDcas{"produceTrackDcas", -1, "Produce TrackDcas (-1: auto; 0 off; 1 on)"}; @@ -572,6 +574,7 @@ class TrackBuilder LOG(info) << "Initialize femto track builder..."; mProduceTracks = utils::enableTable("FTracks_001", table.produceTracks.value, initContext); + mProduceLiteTracks = utils::enableTable("FLiteTracks_001", table.produceLiteTracks.value, initContext); // new mProduceTrackMasks = utils::enableTable("FTrackMasks_001", table.produceTrackMasks.value, initContext); mProduceTrackMass = utils::enableTable("FTrackMass_001", table.produceTrackMass.value, initContext); mProduceTrackDcas = utils::enableTable("FTrackDcas_001", table.produceTrackDcas.value, initContext); @@ -584,7 +587,13 @@ class TrackBuilder mProduceTritonPids = utils::enableTable("FTritonPids_001", table.produceTritonPids.value, initContext); mProduceHeliumPids = utils::enableTable("FHeliumPids_001", table.produceHeliumPids.value, initContext); - if (mProduceTracks || mProduceTrackMasks || mProduceTrackMass || mProduceTrackDcas || mProduceTrackExtras || mProduceElectronPids || mProducePionPids || mProduceKaonPids || mProduceProtonPids || mProduceDeuteronPids || mProduceTritonPids || mProduceHeliumPids) { + if (mProduceTracks && mProduceLiteTracks) { + LOG(fatal) << "FTracks and FLiteTracks are mutually exclusive -- enable only one. " + << "FLiteTracks is meant to replace FTracks at the producer stage (for better compression in derived data); " + << "use the dedicated converter task to reconstruct FTracks from FLiteTracks downstream."; + } + + if (mProduceTracks || mProduceLiteTracks || mProduceTrackMasks || mProduceTrackMass || mProduceTrackDcas || mProduceTrackExtras || mProduceElectronPids || mProducePionPids || mProduceKaonPids || mProduceProtonPids || mProduceDeuteronPids || mProduceTritonPids || mProduceHeliumPids) { mFillAnyTable = true; } else { LOG(info) << "No tables configured, Selection object will not be configured..."; @@ -612,22 +621,33 @@ class TrackBuilder } collisionBuilder.template fillCollision(collisionProducts, col); - this->fillTrack(track, trackProducts, collisionProducts); + this->fillTrack(track, trackProducts, collisionBuilder); } } template - bool fillTrack(T1 const& track, T2& trackProducts, T3& collisionProducts) + bool fillTrack(T1 const& track, T2& trackProducts, T3& collisionBuilder) { - if (!mProduceTracks) { + if (!mProduceTracks && !mProduceLiteTracks) { return false; } + int64_t lastIndex = 0; + if (mProduceTracks) { + trackProducts.producedTracks(collisionBuilder.collisionIndex(), + track.pt() * track.sign(), + track.eta(), + track.phi()); + lastIndex = trackProducts.producedTracks.lastIndex(); + } - trackProducts.producedTracks(collisionProducts.producedCollision.lastIndex(), - track.pt() * track.sign(), - track.eta(), - track.phi()); - indexMap.emplace(track.globalIndex(), trackProducts.producedTracks.lastIndex()); + if (mProduceLiteTracks) { + trackProducts.producedLiteTracks(collisionBuilder.collisionIndex(), + o2::aod::femtobase::lite::binPt(track.pt() * track.sign()), + o2::aod::femtobase::lite::binEta(track.eta()), + o2::aod::femtobase::lite::binPhi(track.phi())); + lastIndex = trackProducts.producedLiteTracks.lastIndex(); + } + indexMap.emplace(track.globalIndex(), lastIndex); if (mProduceTrackMasks) { if constexpr (type == modes::Track::kTrack) { @@ -724,52 +744,50 @@ class TrackBuilder collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); // get track from the track table so we can dereference mc particle properly auto track = tracks.iteratorAt(trackWithItsPid.index()); - this->template fillMcTrack(col, collisionProducts, mcCols, track, trackWithItsPid, trackProducts, mcParticles, mcBuilder, mcProducts); + this->template fillMcTrack(col, collisionBuilder, mcCols, track, trackWithItsPid, trackProducts, mcParticles, mcBuilder, mcProducts); } } template - bool fillMcTrack(T1 const& col, T2& collisionProducts, T3 const& mcCols, T4 const& track, T5 const& trackWithItsPid, T6& trackProducts, T7 const& mcParticles, T8& mcBuilder, T9& mcProducts) + bool fillMcTrack(T1 const& col, T2& collisionBuilder, T3 const& mcCols, T4 const& track, T5 const& trackWithItsPid, T6& trackProducts, T7 const& mcParticles, T8& mcBuilder, T9& mcProducts) { - // return value added, mirroring fillTrack(), so getDaughterIndex can detect - // whether a row was actually added before trusting lastIndex(). - if (!mProduceTracks) { + if (!mProduceTracks && !mProduceLiteTracks) { return false; } - this->template fillTrack(trackWithItsPid, trackProducts, collisionProducts); + this->template fillTrack(trackWithItsPid, trackProducts, collisionBuilder); mcBuilder.template fillMcTrackWithLabel(col, mcCols, track, mcParticles, mcProducts); return true; } template - int64_t getDaughterIndex(const T1& daughter, T2& trackProducts, T3& collisionProducts) + int64_t getDaughterIndex(const T1& daughter, T2& trackProducts, T3& collisionBuilder) { auto result = utils::getIndex(daughter.globalIndex(), indexMap); if (result) { return result.value(); } - if (!this->template fillTrack(daughter, trackProducts, collisionProducts)) { - LOG(fatal) << "Trying to register a daughter track, but FTracks table is disabled. " - << "Enable TrackTables.produceTracks when V0/Cascade/Kink tables that need daughter indices are enabled."; + if (!this->template fillTrack(daughter, trackProducts, collisionBuilder)) { + LOG(fatal) << "Trying to register a daughter track, but FTracks or FLiteTrack table is disabled. " + << "Enable TrackTables.produceTracks/produceLiteTracks when V0/Cascade/Kink tables that need daughter indices are enabled."; } - // daughter is last track which was added added - return trackProducts.producedTracks.lastIndex(); + // fillTrack already inserted the correct index (FTracks or FLiteTracks) into indexMap + return indexMap.at(daughter.globalIndex()); } template - int64_t getDaughterIndex(const T1& col, T2& collisionProducts, T3 const& mcCols, const T4& daughter, T5& trackProducts, T6 const& mcParticles, T7& mcBuilder, T8& mcProducts) + int64_t getDaughterIndex(const T1& col, T2& collisionBuilder, T3 const& mcCols, const T4& daughter, T5& trackProducts, T6 const& mcParticles, T7& mcBuilder, T8& mcProducts) { auto result = utils::getIndex(daughter.globalIndex(), indexMap); if (result) { // daugher already in track table return result.value(); } - if (!this->template fillMcTrack(col, collisionProducts, mcCols, daughter, daughter, trackProducts, mcParticles, mcBuilder, mcProducts)) { - LOG(fatal) << "Trying to register a MC daughter track, but FTracks table is disabled. " - << "Enable TrackTables.produceTracks when V0/Cascade/Kink tables that need daughter indices are enabled."; + if (!this->template fillMcTrack(col, collisionBuilder, mcCols, daughter, daughter, trackProducts, mcParticles, mcBuilder, mcProducts)) { + LOG(fatal) << "Trying to register a daughter track, but FTracks or FLiteTrack table is disabled. " + << "Enable TrackTables.produceTracks/produceLiteTracks when V0/Cascade/Kink tables that need daughter indices are enabled."; } - // daughter is last track which was added added - return trackProducts.producedTracks.lastIndex(); + // fillTrack already inserted the correct index (FTracks or FLiteTracks) into indexMap + return indexMap.at(daughter.globalIndex()); } template @@ -783,6 +801,7 @@ class TrackBuilder TrackSelection mTrackSelection; bool mFillAnyTable = false; bool mProduceTracks = false; + bool mProduceLiteTracks = false; bool mProduceTrackMasks = false; bool mProduceTrackMass = false; bool mProduceTrackDcas = false; diff --git a/PWGCF/Femto/Core/v0Builder.h b/PWGCF/Femto/Core/v0Builder.h index ba19d2abc9b..1e2cb7453c4 100644 --- a/PWGCF/Femto/Core/v0Builder.h +++ b/PWGCF/Femto/Core/v0Builder.h @@ -505,8 +505,8 @@ class V0Builder auto posDaughter = v0.template posTrack_as(); auto negDaughter = v0.template negTrack_as(); - posDaughterIndex = trackBuilder.template getDaughterIndex(posDaughter, trackProducts, collisionProducts); - negDaughterIndex = trackBuilder.template getDaughterIndex(negDaughter, trackProducts, collisionProducts); + posDaughterIndex = trackBuilder.template getDaughterIndex(posDaughter, trackProducts, collisionBuilder); + negDaughterIndex = trackBuilder.template getDaughterIndex(negDaughter, trackProducts, collisionBuilder); if constexpr (modes::isEqual(v0Type, modes::V0::kLambda)) { fillLambda(collisionProducts, v0Products, v0, 1.f, posDaughterIndex, negDaughterIndex); @@ -541,10 +541,10 @@ class V0Builder collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); auto posDaughter = v0.template posTrack_as(); - posDaughterIndex = trackBuilder.template getDaughterIndex(col, collisionProducts, mcCols, posDaughter, trackProducts, mcParticles, mcBuilder, mcProducts); + posDaughterIndex = trackBuilder.template getDaughterIndex(col, collisionBuilder, mcCols, posDaughter, trackProducts, mcParticles, mcBuilder, mcProducts); auto negDaughter = v0.template negTrack_as(); - negDaughterIndex = trackBuilder.template getDaughterIndex(col, collisionProducts, mcCols, negDaughter, trackProducts, mcParticles, mcBuilder, mcProducts); + negDaughterIndex = trackBuilder.template getDaughterIndex(col, collisionBuilder, mcCols, negDaughter, trackProducts, mcParticles, mcBuilder, mcProducts); if constexpr (modes::isEqual(v0Type, modes::V0::kLambda)) { fillLambda(collisionProducts, v0Products, v0, 1.f, posDaughterIndex, negDaughterIndex); diff --git a/PWGCF/Femto/DataModel/FemtoTables.h b/PWGCF/Femto/DataModel/FemtoTables.h index d60c5a3ce49..ef5b66c6cb0 100644 --- a/PWGCF/Femto/DataModel/FemtoTables.h +++ b/PWGCF/Femto/DataModel/FemtoTables.h @@ -17,11 +17,13 @@ #define PWGCF_FEMTO_DATAMODEL_FEMTOTABLES_H_ #include "PWGCF/Femto/Core/dataTypes.h" +#include "PWGCF/Femto/Core/femtoUtils.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" +#include #include #include #include @@ -44,6 +46,43 @@ DECLARE_SOA_COLUMN(Cent, cent, float); //! Centrality (~= multiplici DECLARE_SOA_COLUMN(MagField, magField, int8_t); //! Magnetic field in kG (5 kG at normal configuration and 2kG in low B field configuration) DECLARE_SOA_COLUMN(Sphericity, sphericity, float); //! Sphericity of the event DECLARE_SOA_COLUMN(Qn, qn, float); //! qn bins for dividing eventsfemtab + +namespace lite +{ +constexpr float PosZMin = -20.f; +constexpr float PosZMax = 20.f; +constexpr float PosZStep = 0.5f; // cm +constexpr float CentMin = 0.f; +constexpr float CentMax = 100.f; +constexpr float CentStep = 0.5f; // percent +constexpr float MultStep = 1.f; // rounded to nearest integer + +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); } + +inline uint8_t binCent(float cent) { return o2::analysis::femto::utils::binLinear(cent, CentMin, CentMax, CentStep); } +inline float unBinCent(uint8_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, CentMin, CentStep); } + +inline uint16_t binMult(float mult) { return o2::analysis::femto::utils::binLinear(mult, 0.f, 65535.f, MultStep); } // use full range of uint16_6 +inline float unBinMult(uint16_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, 0.f, MultStep); } + +DECLARE_SOA_COLUMN(BinnedPosZ, binnedPosZ, uint8_t); +DECLARE_SOA_COLUMN(BinnedMult, binnedMult, uint16_t); +DECLARE_SOA_COLUMN(BinnedCent, binnedCent, uint8_t); + +DECLARE_SOA_DYNAMIC_COLUMN(PosZ, posZ, + [](uint8_t binnedPosZ) -> float { + return unBinPosZ(binnedPosZ); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Mult, mult, + [](uint16_t binnedMult) -> float { + return unBinMult(binnedMult); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Cent, cent, + [](uint8_t binnedCent) -> float { + return unBinCent(binnedCent); + }); +} // namespace lite } // namespace femtocollisions // table for basic collision information @@ -57,6 +96,20 @@ using FCols = FCols_001; using FCol = FCols::iterator; using StoredFCols = StoredFCols_001; +// table for basic collision information, compressed/binned information +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteCols_001, "FLITECOLS", 1, //! femto collisions, binned information + o2::soa::Index<>, + femtocollisions::lite::BinnedPosZ, + femtocollisions::lite::BinnedMult, + femtocollisions::lite::BinnedCent, + femtocollisions::MagField, + femtocollisions::lite::PosZ, + femtocollisions::lite::Mult, + femtocollisions::lite::Cent); +using FLiteCols = FLiteCols_001; +using FLiteCol = FLiteCols::iterator; +using StoredFLiteCols = StoredFLiteCols_001; + // table for collisions selections DECLARE_SOA_TABLE_STAGED_VERSIONED(FColMasks_001, "FCOLMASK", 1, //! collision masks femtocollisions::Mask); @@ -95,7 +148,7 @@ using FColCents = FColCents_001; namespace femtobase // all "basic" information to perform femto analysis, i.e. collision index and kinematics -// split kinematics in stored, i.e. stored in derived data, and dynmaic, i.e. can be computed on the fly +// split kinematics in stored, i.e. stored in derived data, and dynamic, i.e. can be computed on the fly { namespace stored { @@ -119,7 +172,6 @@ DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, //! transverse momentum [](float signedPt) -> float { return std::fabs(signedPt); }); -// use fabs for pt so it can also be used with signed pt DECLARE_SOA_DYNAMIC_COLUMN(Px, px, //! momentum in x [](float pt, float phi) -> float { return std::fabs(pt) * std::sin(phi); @@ -141,6 +193,55 @@ DECLARE_SOA_DYNAMIC_COLUMN(Theta, theta, //! theta return 2.f * std::atan(std::exp(-eta)); }); } // namespace dynamic + +namespace lite +{ + +constexpr float EtaMin = -1.f; +constexpr float EtaMax = 1.f; +constexpr float EtaStep = (EtaMax - EtaMin) / 65536.f; + +constexpr float PhiMin = 0.f; +constexpr float PhiMax = constants::math::TwoPI; +constexpr float PhiStep = (PhiMax - PhiMin) / 65536.f; + +constexpr float PtMagMin = 0.1f; +constexpr float PtMagMax = 6.f; + +inline uint16_t binEta(float eta) { return o2::analysis::femto::utils::binLinear(eta, EtaMin, EtaMax, EtaStep); } +inline float unBinEta(uint16_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, EtaMin, EtaStep); } + +inline uint16_t binPhi(float phi) { return o2::analysis::femto::utils::binLinear(phi, PhiMin, PhiMax, PhiStep); } +inline float unBinPhi(uint16_t binned) { return o2::analysis::femto::utils::unBinLinear(binned, PhiMin, PhiStep); } + +inline uint16_t binPt(float signedPt) { return o2::analysis::femto::utils::binLogSigned(signedPt, PtMagMin, PtMagMax); } +inline float unBinPt(uint16_t binned) { return o2::analysis::femto::utils::unBinLogSigned(binned, PtMagMin, PtMagMax); } + +DECLARE_SOA_COLUMN(SignedBinnedPt, signedBinnedPt, uint16_t); +DECLARE_SOA_COLUMN(BinnedEta, binnedEta, uint16_t); +DECLARE_SOA_COLUMN(BinnedPhi, binnedPhi, uint16_t); + +DECLARE_SOA_DYNAMIC_COLUMN(Sign, sign, + [](uint16_t signedBinnedPt) -> int { + return (signedBinnedPt & 0x8000u) ? -1 : 1; // top bit, matches binLogSigned + }); +DECLARE_SOA_DYNAMIC_COLUMN(SignedPt, signedPt, + [](uint16_t signedBinnedPt) -> float { + return unBinPt(signedBinnedPt); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, + [](uint16_t signedBinnedPt) -> float { + return std::fabs(unBinPt(signedBinnedPt)); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, + [](uint16_t binnedEta) -> float { + return unBinEta(binnedEta); + }); +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, + [](uint16_t binnedPhi) -> float { + return unBinPhi(binnedPhi); + }); +} // namespace lite } // namespace femtobase namespace femtotracks @@ -240,6 +341,22 @@ using FTracks = FTracks_001; using FTrack = FTracks::iterator; using StoredFTracks = StoredFTracks_001; +// table for basic track information, compressed/binned kinematics +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLiteTracks_001, "FLITETRACKS", 1, //! femto tracks, binned kinematics + o2::soa::Index<>, + femtobase::stored::FColId, + femtobase::lite::SignedBinnedPt, + femtobase::lite::BinnedEta, + femtobase::lite::BinnedPhi, + femtobase::lite::Sign, + femtobase::lite::Pt, + femtobase::lite::SignedPt, + femtobase::lite::Eta, + femtobase::lite::Phi); +using FLiteTracks = FLiteTracks_001; +using FLiteTrack = FLiteTracks::iterator; +using StoredFLiteTracks = StoredFLiteTracks_001; + // table for track selections and PID selections DECLARE_SOA_TABLE_STAGED_VERSIONED(FTrackMasks_001, "FTRACKMASK", 1, //! track masks femtotracks::Mask); diff --git a/PWGCF/Femto/TableProducer/CMakeLists.txt b/PWGCF/Femto/TableProducer/CMakeLists.txt index 8fb76cfc5fb..adacb9a473e 100644 --- a/PWGCF/Femto/TableProducer/CMakeLists.txt +++ b/PWGCF/Femto/TableProducer/CMakeLists.txt @@ -10,7 +10,7 @@ # or submit itself to any jurisdiction. o2physics_add_dpl_workflow(femto-producer - SOURCES femtoProducer.cxx + SOURCES ./femtoProducer.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) @@ -19,6 +19,11 @@ o2physics_add_dpl_workflow(femto-producer-derived-to-derived PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(femto-producer-lite-converter + SOURCES ./femtoProducerLiteConverter.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(femto-producer-kink-pt-converter SOURCES ./femtoProducerKinkPtConverter.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore diff --git a/PWGCF/Femto/TableProducer/femtoProducer.cxx b/PWGCF/Femto/TableProducer/femtoProducer.cxx index 328e2f61bc1..72fa5d15a8c 100644 --- a/PWGCF/Femto/TableProducer/femtoProducer.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducer.cxx @@ -56,7 +56,6 @@ using Run3PpMcRecoCollisions = o2::soa::Join; using Run3PbPbCollisions = o2::soa::Join; - using Run3PbPbMcRecoCollisions = o2::soa::Join; using Run3PbPbMcGenCollisions = o2::soa::Join; diff --git a/PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx b/PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx new file mode 100644 index 00000000000..0a43ae21e98 --- /dev/null +++ b/PWGCF/Femto/TableProducer/femtoProducerLiteConverter.cxx @@ -0,0 +1,57 @@ +// Copyright 2019-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file femtoProducerLiteConverter.cxx +/// \brief Task that converts FLiteTracks (binned kinematics) back to FTracks (float kinematics) +/// \author Anton Riedel, TU München, anton.riedel@cern.ch + +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include +#include +#include +#include +#include + +using namespace o2::analysis::femto; + +struct FemtoProducerLiteConverter { + o2::framework::Produces producedCols; + o2::framework::Produces producedTracks; + + void init(o2::framework::InitContext&) + { + } + + void processLiteCols(o2::aod::FLiteCols::iterator const& liteCols) + { + producedCols(liteCols.posZ(), + liteCols.mult(), + liteCols.cent(), + liteCols.magField()); + } + PROCESS_SWITCH(FemtoProducerLiteConverter, processLiteCols, "Convert FLiteCols to FCols", true); + + void processLiteTracks(o2::aod::FLiteTracks::iterator const& liteTrack) + { + producedTracks(liteTrack.fColId(), + liteTrack.signedPt(), + liteTrack.eta(), + liteTrack.phi()); + } + PROCESS_SWITCH(FemtoProducerLiteConverter, processLiteTracks, "Convert FLiteTracks to FTracks", true); +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) +{ + o2::framework::WorkflowSpec workflow{o2::framework::adaptAnalysisTask(context)}; + return workflow; +}