From 4cd13f8d813857b8a878d7c6e1e7f66fd4bf01a5 Mon Sep 17 00:00:00 2001 From: Kangkan Goswami Date: Tue, 14 Oct 2025 10:22:05 +0530 Subject: [PATCH 1/8] Add TRD support and local gain/noise handling in AODProducerWorkflowSpec This commit enables the workflow to process TRD-specific calibration and noise information, allowing for more accurate reconstruction and analysis of TRD signals in AOD production. --- .../AODProducerWorkflowSpec.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h index 2c58db42ed856..077dbb358b1aa 100644 --- a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h +++ b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h @@ -19,6 +19,8 @@ #include "DataFormatsGlobalTracking/RecoContainer.h" #include "DataFormatsPHOS/Cell.h" #include "DataFormatsTRD/TrackTRD.h" +#include "TRDBase/PadCalibrationsAliases.h" +#include "DataFormatsTRD/NoiseCalibration.h" #include "DetectorsBase/GRPGeomHelper.h" #include "DetectorsBase/Propagator.h" #include "Framework/DataProcessorSpec.h" @@ -215,7 +217,7 @@ enum struct AODProducerStreamerFlags : uint8_t { class AODProducerWorkflowDPL : public Task { public: - AODProducerWorkflowDPL(GID::mask_t src, std::shared_ptr dataRequest, std::shared_ptr gr, bool enableSV, bool useMC = true, bool enableFITextra = false) : mUseMC(useMC), mEnableSV(enableSV), mEnableFITextra(enableFITextra), mInputSources(src), mDataRequest(dataRequest), mGGCCDBRequest(gr) {} + AODProducerWorkflowDPL(GID::mask_t src, std::shared_ptr dataRequest, std::shared_ptr gr, bool enableSV, bool useMC = true, bool enableFITextra = false, bool enableTRDextra = false) : mUseMC(useMC), mEnableSV(enableSV), mEnableFITextra(enableFITextra), mEnableTRDextra(enableTRDextra), mInputSources(src), mDataRequest(dataRequest), mGGCCDBRequest(gr) {} ~AODProducerWorkflowDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -250,6 +252,9 @@ class AODProducerWorkflowDPL : public Task o2::dataformats::MeanVertexObject mVtx; float mMaxPropXiu{5.0f}; // max X_IU for which track is to be propagated if mPropTracks is true. (other option: o2::constants::geom::XTPCInnerRef + 0.1f) + const o2::trd::LocalGainFactor* mTRDLocalGain; // TRD local gain factors from krypton calibration + const o2::trd::NoiseStatusMCM* mTRDNoiseMap; // TRD noise map + std::unordered_set mGIDUsedBySVtx; std::unordered_set mGIDUsedByStr; @@ -261,6 +266,7 @@ class AODProducerWorkflowDPL : public Task bool mUseSigFiltMC = false; // enable signal filtering for MC with embedding bool mEnableSV = true; // enable secondary vertices bool mEnableFITextra = false; + bool mEnableTRDextra = false; bool mFieldON = false; const float cSpeed = 0.029979246f; // speed of light in TOF units @@ -525,6 +531,9 @@ class AODProducerWorkflowDPL : public Task template void addToTracksQATable(TracksQACursorType& tracksQACursor, TrackQA& trackQAInfoHolder); + template + void addToTRDsExtra(const o2::globaltracking::RecoContainer& recoData, TRDsExtraCursorType& trdExtraCursor, const GIndex& trkIdx, int trkTableIdx); + template void addToMFTTracksTable(mftTracksCursorType& mftTracksCursor, AmbigMFTTracksCursorType& ambigMFTTracksCursor, GIndex trackID, const o2::globaltracking::RecoContainer& data, int collisionID, @@ -544,7 +553,7 @@ class AODProducerWorkflowDPL : public Task // helper for track tables // * fills tables collision by collision // * interaction time is for TOF information - template void fillTrackTablesPerCollision(int collisionID, @@ -556,6 +565,7 @@ class AODProducerWorkflowDPL : public Task TracksCovCursorType& tracksCovCursor, TracksExtraCursorType& tracksExtraCursor, TracksQACursorType& tracksQACursor, + TRDsExtraCursorType& trdsExtraCursor, AmbigTracksCursorType& ambigTracksCursor, MFTTracksCursorType& mftTracksCursor, MFTTracksCovCursorType& mftTracksCovCursor, @@ -680,7 +690,7 @@ class AODProducerWorkflowDPL : public Task }; /// create a processor spec -framework::DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, bool enableST, bool useMC, bool CTPConfigPerRun, bool enableFITextra); +framework::DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, bool enableST, bool useMC, bool CTPConfigPerRun, bool enableFITextra, bool enableTRDextra); // helper interface for calo cells to "befriend" emcal and phos cells class CellHelper From 1c64317a20de4ec9b1fbbf2d530dfe59a1399aa7 Mon Sep 17 00:00:00 2001 From: Kangkan Goswami Date: Tue, 14 Oct 2025 10:26:20 +0530 Subject: [PATCH 2/8] Implement TRD extra data processing in AODProducerWorkflowSpec.cxx This commit enables the workflow to generate TRD-specific extra tables in the AOD, applying calibration and noise corrections to improve reconstruction fidelity for TRD tracks. --- Detectors/AOD/src/AODProducerWorkflowSpec.cxx | 109 ++++++++++++++++-- 1 file changed, 101 insertions(+), 8 deletions(-) diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index 852419a9895eb..5867a2d3bf1f4 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -33,7 +33,6 @@ #include "DataFormatsPHOS/TriggerRecord.h" #include "DataFormatsPHOS/EventHandler.h" #include "DataFormatsTPC/TrackTPC.h" -#include "DataFormatsTRD/TriggerRecord.h" #include "DataFormatsZDC/BCRecData.h" #include "DataFormatsZDC/ZDCEnergy.h" #include "DataFormatsZDC/ZDCTDCData.h" @@ -45,6 +44,9 @@ #include "CommonDataFormat/InteractionRecord.h" #include "DataFormatsTRD/TrackTRD.h" #include "DataFormatsTRD/TrackTriggerRecord.h" +#include "DataFormatsTRD/CalibratedTracklet.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Tracklet64.h" #include "DataFormatsGlobalTracking/RecoContainer.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ConfigParamRegistry.h" @@ -390,6 +392,79 @@ void AODProducerWorkflowDPL::addToTracksQATable(TracksQACursorType& tracksQACurs mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dTofdZ); } +template +void AODProducerWorkflowDPL::addToTRDsExtra(const o2::globaltracking::RecoContainer& recoData, TRDsExtraCursorType& trdExtraCursor, const GIndex& trkIdx, int trkTableIdx) +{ + int q0s[6] = {-1}, q1s[6] = {-1}, q2s[6] = {-1}; + float q0sCor[6] = {-1}, q1sCor[6] = {-1}, q2sCor[6] = {-1}; + float ttgls[6] = {-999}, tphis[6] = {-999}; + + auto contributorsGID = recoData.getSingleDetectorRefs(trkIdx); + if (!contributorsGID[GIndex::Source::TRD].isIndexSet()) { // should be redunant + return; + } + const auto& trk = recoData.getTrack(contributorsGID[GIndex::Source::TRD]); + o2::track::TrackPar trkC{contributorsGID[GIndex::Source::ITSTPC].isIndexSet() ? recoData.getTPCITSTrack(contributorsGID[GIndex::Source::ITSTPC]).getParamOut() : recoData.getTPCTrack(contributorsGID[GIndex::Source::TPC]).getParamOut() }; + const auto& trklets = recoData.getTRDTracklets(); + const auto& ctrklets = recoData.getTRDCalibratedTracklets(); + for (int iLay{0}; iLay < 6; ++iLay) { + q0s[iLay] = q1s[iLay] = q2s[iLay] = -1; + q0sCor[iLay] = q1sCor[iLay] = q2sCor[iLay] = -1; + tphis[iLay] = ttgls[iLay] = -999; + auto trkltId = trk.getTrackletIndex(iLay); + if (trkltId < 0) { + continue; + } + const auto& tracklet = trklets[trkltId]; + if (mTRDNoiseMap->isTrackletFromNoisyMCM(tracklet)) { + continue; + } + // we need to propagate into TRD local system + int trkltDet = tracklet.getDetector(); + int trkltSec = trkltDet / 30; + if (trkltSec != o2::math_utils::angle2Sector(trkC.getAlpha())) { + if (!trkC.rotate(o2::math_utils::sector2Angle(trkltSec))) { + break; + } + } + if (!o2::base::Propagator::Instance()->PropagateToXBxByBz(trkC, ctrklets[trkltId].getX(), o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, mMatCorr)) { + break; + } + + auto tphi = trkC.getSnp() / std::sqrt((1.f - trkC.getSnp()) * (1.f + trkC.getSnp())); + auto trackletLength = std::sqrt(1.f + tphi * tphi + trkC.getTgl() * trkC.getTgl()); + float cor = mTRDLocalGain->getValue(tracklet.getHCID() / 2, tracklet.getPadCol(), tracklet.getPadRow()) * trackletLength; + q0s[iLay] = tracklet.getQ0(); + q1s[iLay] = tracklet.getQ1(); + q2s[iLay] = tracklet.getQ2(); + q0sCor[iLay] = (float)tracklet.getQ0() / cor; + q1sCor[iLay] = (float)tracklet.getQ1() / cor; + q2sCor[iLay] = (float)tracklet.getQ2() / cor; + ttgls[iLay] = trkC.getTgl(); + tphis[iLay] = tphi; + + // z-row merging + if (trk.getIsCrossingNeighbor(iLay) && trk.getHasNeighbor()) { + for (const auto& trklt : trklets) { + if (tracklet.getTrackletWord() == trklt.getTrackletWord()) { + continue; + } + if (std::abs(tracklet.getPadCol() - trklt.getPadCol()) <= 1 && std::abs(tracklet.getPadRow() - trklt.getPadRow()) == 1) { + cor = mTRDLocalGain->getValue(trklt.getHCID() / 2, trklt.getPadCol(), trklt.getPadRow()) * trackletLength; + q0s[iLay] += trklt.getQ0(); + q1s[iLay] += trklt.getQ1(); + q2s[iLay] += trklt.getQ2(); + q0sCor[iLay] += (float)trklt.getQ0() / cor; + q1sCor[iLay] += (float)trklt.getQ1() / cor; + q2sCor[iLay] += (float)trklt.getQ2() / cor; + } + } + } + } + + trdExtraCursor(trkTableIdx, q0s, q1s, q2s, q0sCor, q1sCor, q2sCor, ttgls, tphis); +} + template void AODProducerWorkflowDPL::addToMFTTracksTable(mftTracksCursorType& mftTracksCursor, AmbigMFTTracksCursorType& ambigMFTTracksCursor, GIndex trackID, const o2::globaltracking::RecoContainer& data, int collisionID, @@ -430,8 +505,7 @@ void AODProducerWorkflowDPL::addToMFTTracksTable(mftTracksCursorType& mftTracksC ambigMFTTracksCursor(mTableTrMFTID, bcSlice); } } - -template void AODProducerWorkflowDPL::fillTrackTablesPerCollision(int collisionID, @@ -443,6 +517,7 @@ void AODProducerWorkflowDPL::fillTrackTablesPerCollision(int collisionID, TracksCovCursorType& tracksCovCursor, TracksExtraCursorType& tracksExtraCursor, TracksQACursorType& tracksQACursor, + TRDsExtraCursor& trdsExtraCursor, AmbigTracksCursorType& ambigTracksCursor, MFTTracksCursorType& mftTracksCursor, MFTTracksCovCursorType& mftTracksCovCursor, @@ -553,7 +628,9 @@ void AODProducerWorkflowDPL::fillTrackTablesPerCollision(int collisionID, addToTracksTable(tracksCursor, tracksCovCursor, trOrig, collisionID, aod::track::TrackIU); } addToTracksExtraTable(tracksExtraCursor, extraInfoHolder); - + if (mEnableTRDextra && trackIndex.includesDet(GIndex::Source::TRD)) { + addToTRDsExtra(data, trdsExtraCursor, trackIndex, mTableTrID); + } // collecting table indices of barrel tracks for V0s table if (extraInfoHolder.bcSlice[0] >= 0 && collisionID < 0) { ambigTracksCursor(mTableTrID, extraInfoHolder.bcSlice); @@ -1934,6 +2011,12 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) auto cpvClustersCursor = createTableCursor(pc); auto originCursor = createTableCursor(pc); + /// Extra tables + o2::framework::Produces trdExtraCursor; + if (mEnableTRDextra) { + trdExtraCursor = createTableCursor(pc); + } + // Declare MC cursors type without adding the output for a table o2::framework::Produces mcColLabelsCursor; o2::framework::Produces mcCollisionsCursor; @@ -2298,7 +2381,7 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) // so that all unassigned tracks are stored in the beginning of the table together auto& trackRef = primVer2TRefs.back(); // references to unassigned tracks are at the end // fixme: interaction time is undefined for unassigned tracks (?) - fillTrackTablesPerCollision(-1, std::uint64_t(-1), trackRef, primVerGIs, recoData, tracksCursor, tracksCovCursor, tracksExtraCursor, tracksQACursor, + fillTrackTablesPerCollision(-1, std::uint64_t(-1), trackRef, primVerGIs, recoData, tracksCursor, tracksCovCursor, tracksExtraCursor, tracksQACursor, trdExtraCursor, ambigTracksCursor, mftTracksCursor, mftTracksCovCursor, ambigMFTTracksCursor, fwdTracksCursor, fwdTracksCovCursor, ambigFwdTracksCursor, fwdTrkClsCursor, bcsMap); @@ -2340,7 +2423,7 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) auto& trackRef = primVer2TRefs[collisionID]; // passing interaction time in [ps] - fillTrackTablesPerCollision(collisionID, globalBC, trackRef, primVerGIs, recoData, tracksCursor, tracksCovCursor, tracksExtraCursor, tracksQACursor, ambigTracksCursor, + fillTrackTablesPerCollision(collisionID, globalBC, trackRef, primVerGIs, recoData, tracksCursor, tracksCovCursor, tracksExtraCursor, tracksQACursor, trdExtraCursor, ambigTracksCursor, mftTracksCursor, mftTracksCovCursor, ambigMFTTracksCursor, fwdTracksCursor, fwdTracksCovCursor, ambigFwdTracksCursor, fwdTrkClsCursor, bcsMap); collisionID++; @@ -3011,6 +3094,10 @@ void AODProducerWorkflowDPL::updateTimeDependentParams(ProcessingContext& pc) mFieldON = std::abs(o2::base::Propagator::Instance()->getNominalBz()) > 0.01; pc.inputs().get("ctpconfig"); + if (mEnableTRDextra) { + mTRDLocalGain = pc.inputs().get("trdlocalgainfactors").get(); + mTRDNoiseMap = pc.inputs().get("trdnoisemap").get(); + } } if (mPropTracks) { pc.inputs().get("meanvtx"); @@ -3222,7 +3309,7 @@ void AODProducerWorkflowDPL::endOfStream(EndOfStreamContext& /*ec*/) mStreamer.reset(); } -DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, bool enableStrangenessTracking, bool useMC, bool CTPConfigPerRun, bool enableFITextra) +DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, bool enableStrangenessTracking, bool useMC, bool CTPConfigPerRun, bool enableFITextra, bool enableTRDextra) { auto dataRequest = std::make_shared(); dataRequest->inputs.emplace_back("ctpconfig", "CTP", "CTPCONFIG", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/Config", CTPConfigPerRun)); @@ -3313,6 +3400,12 @@ DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, boo OutputSpec{"TFF", "TFFilename"}, OutputSpec{"AMD", "AODMetadataKeys"}, OutputSpec{"AMD", "AODMetadataVals"}}; + /// Extra tables + if (enableTRDextra) { + outputs.push_back(OutputForTable::spec()); + dataRequest->inputs.emplace_back("trdlocalgainfactors", "TRD", "LOCALGAINFACTORS", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/LocalGainFactor")); + dataRequest->inputs.emplace_back("trdnoisemap", "TRD", "NOISEMAP", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/NoiseMapMCM")); + } if (useMC) { outputs.insert(outputs.end(), @@ -3336,7 +3429,7 @@ DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, boo "aod-producer-workflow", dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask(src, dataRequest, ggRequest, enableSV, useMC, enableFITextra)}, + AlgorithmSpec{adaptFromTask(src, dataRequest, ggRequest, enableSV, useMC, enableFITextra, enableTRDextra)}, Options{ ConfigParamSpec{"run-number", VariantType::Int64, -1L, {"The run-number. If left default we try to get it from DPL header."}}, ConfigParamSpec{"aod-timeframe-id", VariantType::Int64, -1L, {"Set timeframe number"}}, From a6ec8333ce42de5c5b5041010dbabc502e0986c5 Mon Sep 17 00:00:00 2001 From: Kangkan Goswami Date: Tue, 14 Oct 2025 10:28:50 +0530 Subject: [PATCH 3/8] Add TRD extra configuration option to AOD producer workflow This change allows users to enable or disable TRD extra output at runtime via workflow configuration, integrating TRD processing into the AOD production workflow. --- Detectors/AOD/src/aod-producer-workflow.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Detectors/AOD/src/aod-producer-workflow.cxx b/Detectors/AOD/src/aod-producer-workflow.cxx index 81e178642e403..f6bfaae170bbd 100644 --- a/Detectors/AOD/src/aod-producer-workflow.cxx +++ b/Detectors/AOD/src/aod-producer-workflow.cxx @@ -38,6 +38,7 @@ void customize(std::vector& workflowOptions) {"disable-secondary-vertices", o2::framework::VariantType::Bool, false, {"disable filling secondary vertices"}}, {"disable-strangeness-tracker", o2::framework::VariantType::Bool, false, {"disable filling strangeness tracking"}}, {"enable-FIT-extra", o2::framework::VariantType::Bool, false, {"enable FIT extra output"}}, + {"enable-TRD-extra", o2::framework::VariantType::Bool, false, {"enable TRD extra output"}}, {"info-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}, {"combine-source-devices", o2::framework::VariantType::Bool, false, {"merge DPL source devices"}}, @@ -56,6 +57,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) bool enableST = !configcontext.options().get("disable-strangeness-tracker"); bool ctpcfgperrun = !configcontext.options().get("ctpconfig-run-independent"); bool enableFITextra = configcontext.options().get("enable-FIT-extra"); + bool enableTRDextra = configcontext.options().get("enable-TRD-extra"); GID::mask_t allowedSrc = GID::getSourcesMask("ITS,MFT,MCH,MID,MCH-MID,TPC,TRD,ITS-TPC,TPC-TOF,TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD,TPC-TRD-TOF,ITS-TPC-TRD-TOF,MFT-MCH,FT0,FV0,FDD,ZDC,EMC,CTP,PHS,CPV,HMP"); GID::mask_t src = allowedSrc & GID::getSourcesMask(configcontext.options().get("info-sources")); @@ -66,7 +68,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) } WorkflowSpec specs; - specs.emplace_back(o2::aodproducer::getAODProducerWorkflowSpec(src, enableSV, enableST, useMC, ctpcfgperrun, enableFITextra)); + specs.emplace_back(o2::aodproducer::getAODProducerWorkflowSpec(src, enableSV, enableST, useMC, ctpcfgperrun, enableFITextra, enableTRDextra)); auto srcCls = src & ~(GID::getSourceMask(GID::MCH) | GID::getSourceMask(GID::MID)); // Don't read global MID and MCH clusters (those attached to tracks are always read) auto srcMtc = src; From ab3b2281eb12747c8848d2d506e28de981ea07ad Mon Sep 17 00:00:00 2001 From: Kangkan Goswami Date: Tue, 14 Oct 2025 10:30:41 +0530 Subject: [PATCH 4/8] Refactor TRD dynamic columns and define TRDsExtra SOA table in AnalysisDataModel.h This update to AnalysisDataModel.h standardizes TRD-related naming and introduces a dedicated SOA table for TRD extra data, allowing calibrated and corrected TRD quantities to be stored within the AOD framework. --- .../include/Framework/AnalysisDataModel.h | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/Framework/Core/include/Framework/AnalysisDataModel.h b/Framework/Core/include/Framework/AnalysisDataModel.h index e3032830beaac..9f48685820634 100644 --- a/Framework/Core/include/Framework/AnalysisDataModel.h +++ b/Framework/Core/include/Framework/AnalysisDataModel.h @@ -470,13 +470,13 @@ DECLARE_SOA_DYNAMIC_COLUMN(TPCFractionSharedCls, tpcFractionSharedCls, //! Fract return (float)tpcNClsShared / (float)tpcNClsFound; }); -DECLARE_SOA_DYNAMIC_COLUMN(TRDHasNeighbor, trdPattern, //! Flag to check if at least one tracklet of a TRD Track has a neighboring tracklet +DECLARE_SOA_DYNAMIC_COLUMN(TRDHasNeighbor, trdHasNeighbor, //! Flag to check if at least one tracklet of a TRD Track has a neighboring tracklet [](uint8_t trdPattern) -> bool { return trdPattern & o2::aod::track::HasNeighbor; }); -DECLARE_SOA_DYNAMIC_COLUMN(TRDHasCrossing, trdPattern, //! Flag to check if at least one tracklet of a TRD Track crossed a padrow +DECLARE_SOA_DYNAMIC_COLUMN(TRDHasCrossing, trdHasCrossing, //! Flag to check if at least one tracklet of a TRD Track crossed a padrow [](uint8_t trdPattern) -> bool { return trdPattern & o2::aod::track::HasCrossing; }); -DECLARE_SOA_DYNAMIC_COLUMN(TRDNLayers, trdPattern, //! Number of TRD tracklets in a Track +DECLARE_SOA_DYNAMIC_COLUMN(TRDNTracklets, trdNTracklets, //! Number of TRD tracklets in a Track [](uint8_t trdPattern) -> std::size_t { return std::bitset<6>(trdPattern).count(); }); } // namespace track @@ -589,6 +589,7 @@ DECLARE_SOA_TABLE_FULL(StoredTracksExtra_000, "TracksExtra", "AOD", "TRACKEXTRA" track::TPCCrossedRowsOverFindableCls, track::TPCFoundOverFindableCls, track::TPCFractionSharedCls, + track::TRDHasCrossing, track::TRDHasNeighbor, track::TRDNTracklets, track::TrackEtaEMCAL, track::TrackPhiEMCAL, track::TrackTime, track::TrackTimeRes); DECLARE_SOA_TABLE_FULL_VERSIONED(StoredTracksExtra_001, "TracksExtra", "AOD", "TRACKEXTRA", 1, // On disk version of TracksExtra, version 1 @@ -618,6 +619,7 @@ DECLARE_SOA_TABLE_FULL_VERSIONED(StoredTracksExtra_001, "TracksExtra", "AOD", "T track::TPCCrossedRowsOverFindableCls, track::TPCFoundOverFindableCls, track::TPCFractionSharedCls, + track::TRDHasCrossing, track::TRDHasNeighbor, track::TRDNTracklets, track::TrackEtaEMCAL, track::TrackPhiEMCAL, track::TrackTime, track::TrackTimeRes); DECLARE_SOA_TABLE_FULL_VERSIONED(StoredTracksExtra_002, "TracksExtra", "AOD", "TRACKEXTRA", 2, // On disk version of TracksExtra, version 2 @@ -648,6 +650,7 @@ DECLARE_SOA_TABLE_FULL_VERSIONED(StoredTracksExtra_002, "TracksExtra", "AOD", "T track::TPCCrossedRowsOverFindableCls, track::TPCFoundOverFindableCls, track::TPCFractionSharedCls, + track::TRDHasCrossing, track::TRDHasNeighbor, track::TRDNTracklets, track::TrackEtaEMCAL, track::TrackPhiEMCAL, track::TrackTime, track::TrackTimeRes); DECLARE_SOA_EXTENDED_TABLE(TracksExtra_000, StoredTracksExtra_000, "EXTRACKEXTRA", 0, //! Additional track information (clusters, PID, etc.) @@ -1610,6 +1613,26 @@ DECLARE_SOA_TABLE(FDDsExtra, "AOD", "FDDEXTRA", //! FDDsExtra table fdd::TimeFDDA, fdd::TimeFDDC); using FDDExtra = FDDsExtra::iterator; +namespace trd +{ +DECLARE_SOA_INDEX_COLUMN(Track, track); //! Track index +DECLARE_SOA_COLUMN(TRDQ0s, trdQ0s, int[6]); //! Q0 charge (un-corrected) +DECLARE_SOA_COLUMN(TRDQ1s, trdQ1s, int[6]); //! Q1 charge (un-corrected) +DECLARE_SOA_COLUMN(TRDQ2s, trdQ2s, int[6]); //! Q2 charge (un-corrected) +DECLARE_SOA_COLUMN(TRDQ0sCorrected, trdQ0sCorrected, float[6]); //! Q0 charge (corrected) +DECLARE_SOA_COLUMN(TRDQ1sCorrected, trdQ1sCorrected, float[6]); //! Q1 charge (corrected) +DECLARE_SOA_COLUMN(TRDQ2sCorrected, trdQ2sCorrected, float[6]); //! Q2 charge (corrected) +DECLARE_SOA_COLUMN(TRDTgls, trdTgls, float[6]); //! Local tracklet TgL +DECLARE_SOA_COLUMN(TRDPhis, trdPhis, float[6]); //! Local tracklet phi +} // namespace trd + +DECLARE_SOA_TABLE(TRDsExtra, "AOD", "TRDEXTRA", //! TRDExtra table + o2::soa::Index<>, trd::TrackId, + trd::TRDQ0s, trd::TRDQ1s, trd::TRDQ2s, + trd::TRDQ0sCorrected, trd::TRDQ1sCorrected, trd::TRDQ2sCorrected, + trd::TRDTgls, trd::TRDPhis); +using TRDExtra = TRDsExtra::iterator; + namespace v0 { DECLARE_SOA_INDEX_COLUMN_FULL(PosTrack, posTrack, int, Tracks, "_Pos"); //! Positive track From 666ca5adb59a50e03f1beccd63138e7ad3f1f13b Mon Sep 17 00:00:00 2001 From: Gauthier Legras Date: Wed, 25 Feb 2026 20:03:55 +0100 Subject: [PATCH 5/8] fix TRD extra information --- .../AODProducerWorkflowSpec.h | 4 ++ Detectors/AOD/src/AODProducerWorkflowSpec.cxx | 65 ++++++++++++++++--- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h index 077dbb358b1aa..588cd575ee7f5 100644 --- a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h +++ b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h @@ -21,6 +21,8 @@ #include "DataFormatsTRD/TrackTRD.h" #include "TRDBase/PadCalibrationsAliases.h" #include "DataFormatsTRD/NoiseCalibration.h" +#include "DataFormatsTRD/CalGain.h" +#include "DataFormatsTRD/Constants.h" #include "DetectorsBase/GRPGeomHelper.h" #include "DetectorsBase/Propagator.h" #include "Framework/DataProcessorSpec.h" @@ -253,6 +255,7 @@ class AODProducerWorkflowDPL : public Task float mMaxPropXiu{5.0f}; // max X_IU for which track is to be propagated if mPropTracks is true. (other option: o2::constants::geom::XTPCInnerRef + 0.1f) const o2::trd::LocalGainFactor* mTRDLocalGain; // TRD local gain factors from krypton calibration + const o2::trd::CalGain* mTRDGainCalib; // TRD time-dependent gain calib at chamber level const o2::trd::NoiseStatusMCM* mTRDNoiseMap; // TRD noise map std::unordered_set mGIDUsedBySVtx; @@ -284,6 +287,7 @@ class AODProducerWorkflowDPL : public Task TStopwatch mTimer; bool mEMCselectLeading{false}; uint64_t mEMCALTrgClassMask = 0; + size_t mCurrentTRDTrigID = 0; // current index of the TRD trigger record, to speed up search // unordered map connects global indices and table indices of barrel tracks std::unordered_map mGIDToTableID; diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index 5867a2d3bf1f4..037b922733f6b 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -433,7 +433,7 @@ void AODProducerWorkflowDPL::addToTRDsExtra(const o2::globaltracking::RecoContai auto tphi = trkC.getSnp() / std::sqrt((1.f - trkC.getSnp()) * (1.f + trkC.getSnp())); auto trackletLength = std::sqrt(1.f + tphi * tphi + trkC.getTgl() * trkC.getTgl()); - float cor = mTRDLocalGain->getValue(tracklet.getHCID() / 2, tracklet.getPadCol(), tracklet.getPadRow()) * trackletLength; + float cor = mTRDLocalGain->getValue(tracklet.getHCID() / 2, tracklet.getPadCol(), tracklet.getPadRow()) * mTRDGainCalib->getMPVdEdx(tracklet.getDetector()) / o2::trd::constants::MPVDEDXDEFAULT * trackletLength; q0s[iLay] = tracklet.getQ0(); q1s[iLay] = tracklet.getQ1(); q2s[iLay] = tracklet.getQ2(); @@ -443,20 +443,66 @@ void AODProducerWorkflowDPL::addToTRDsExtra(const o2::globaltracking::RecoContai ttgls[iLay] = trkC.getTgl(); tphis[iLay] = tphi; - // z-row merging + // z-row merging, we want to merge only with tracklets from the same trigger record if (trk.getIsCrossingNeighbor(iLay) && trk.getHasNeighbor()) { - for (const auto& trklt : trklets) { - if (tracklet.getTrackletWord() == trklt.getTrackletWord()) { + // find the trigger the tracklet belongs to + auto trigsTRD = recoData.getTRDTriggerRecords(); + size_t trdSelID = -1; + + const auto& trig = trigsTRD[mCurrentTRDTrigID]; + bool foundTRDTrigger = false; + // first check current trigger + if (trkltId >= trig.getFirstTracklet() && trkltId < trig.getFirstTracklet() + trig.getNumberOfTracklets()) { + trdSelID = mCurrentTRDTrigID; + foundTRDTrigger = true; + } + else { + // then check next trigger + if (mCurrentTRDTrigID < trigsTRD.size() - 1) { + const auto& trig = trigsTRD[mCurrentTRDTrigID+1]; + if (trkltId >= trig.getFirstTracklet() && trkltId < trig.getFirstTracklet() + trig.getNumberOfTracklets()) { + trdSelID = mCurrentTRDTrigID+1; + foundTRDTrigger = true; + } + } + } + + size_t low = 0, up = trigsTRD.size() - 1; + + // otherwise binary search + while (low <= up && !foundTRDTrigger) { + trdSelID = low + std::floor( (up - low)/2 ); + const auto& trig = trigsTRD[trdSelID]; + if (trig.getFirstTracklet() > trkltId) { + up = trdSelID - 1; + } + else { + if (trig.getFirstTracklet() + trig.getNumberOfTracklets() <= trkltId) { + low = trdSelID + 1; + } + else { + foundTRDTrigger = true; + } + } + } + //------------------- + mCurrentTRDTrigID = trdSelID; + const auto& trigSel = trigsTRD[trdSelID]; + + // loop on other tracklets from the same trigger record + for (const auto& trklt : trklets.subspan(trigSel.getFirstTracklet(), trigSel.getNumberOfTracklets())) { + if (tracklet.getTrackletWord() == trklt.getTrackletWord() || tracklet.getDetector() != trklt.getDetector()) { continue; } if (std::abs(tracklet.getPadCol() - trklt.getPadCol()) <= 1 && std::abs(tracklet.getPadRow() - trklt.getPadRow()) == 1) { - cor = mTRDLocalGain->getValue(trklt.getHCID() / 2, trklt.getPadCol(), trklt.getPadRow()) * trackletLength; + cor = mTRDLocalGain->getValue(trklt.getHCID() / 2, trklt.getPadCol(), trklt.getPadRow()) * mTRDGainCalib->getMPVdEdx(tracklet.getDetector()) / o2::trd::constants::MPVDEDXDEFAULT * trackletLength; q0s[iLay] += trklt.getQ0(); q1s[iLay] += trklt.getQ1(); q2s[iLay] += trklt.getQ2(); q0sCor[iLay] += (float)trklt.getQ0() / cor; q1sCor[iLay] += (float)trklt.getQ1() / cor; q2sCor[iLay] += (float)trklt.getQ2() / cor; + } } } @@ -2376,7 +2422,8 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) mGIDUsedByStr.emplace(sTrk.mITSRef, GIndex::ITS); } } - + + mCurrentTRDTrigID = 0; // reinitialize index for TRD trigger record search // filling unassigned tracks first // so that all unassigned tracks are stored in the beginning of the table together auto& trackRef = primVer2TRefs.back(); // references to unassigned tracks are at the end @@ -2385,6 +2432,7 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) ambigTracksCursor, mftTracksCursor, mftTracksCovCursor, ambigMFTTracksCursor, fwdTracksCursor, fwdTracksCovCursor, ambigFwdTracksCursor, fwdTrkClsCursor, bcsMap); + mCurrentTRDTrigID = 0; // reinitialize index for TRD trigger record search // filling collisions and tracks into tables collisionID = 0; collisionsCursor.reserve(primVertices.size()); @@ -3097,6 +3145,7 @@ void AODProducerWorkflowDPL::updateTimeDependentParams(ProcessingContext& pc) if (mEnableTRDextra) { mTRDLocalGain = pc.inputs().get("trdlocalgainfactors").get(); mTRDNoiseMap = pc.inputs().get("trdnoisemap").get(); + mTRDGainCalib = pc.inputs().get("trdgaincalib").get(); // time dependent gain } } if (mPropTracks) { @@ -3369,11 +3418,8 @@ DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, boo OutputForTable::spec(), OutputForTable::spec(), OutputForTable::spec(), - OutputForTable::spec(), OutputForTable::spec(), - OutputForTable::spec(), OutputForTable::spec(), - OutputForTable::spec(), OutputForTable::spec(), OutputForTable::spec(), OutputForTable::spec(), @@ -3405,6 +3451,7 @@ DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, boo outputs.push_back(OutputForTable::spec()); dataRequest->inputs.emplace_back("trdlocalgainfactors", "TRD", "LOCALGAINFACTORS", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/LocalGainFactor")); dataRequest->inputs.emplace_back("trdnoisemap", "TRD", "NOISEMAP", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/NoiseMapMCM")); + dataRequest->inputs.emplace_back("trdgaincalib", "TRD", "CALGAIN", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/CalGain")); } if (useMC) { From 30f24af1d61efa97b77041b95bf6915e8f8849fc Mon Sep 17 00:00:00 2001 From: Gauthier Legras Date: Wed, 25 Feb 2026 20:05:09 +0100 Subject: [PATCH 6/8] clang format --- Detectors/AOD/src/AODProducerWorkflowSpec.cxx | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index 037b922733f6b..f55ff4656d332 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -455,32 +455,29 @@ void AODProducerWorkflowDPL::addToTRDsExtra(const o2::globaltracking::RecoContai if (trkltId >= trig.getFirstTracklet() && trkltId < trig.getFirstTracklet() + trig.getNumberOfTracklets()) { trdSelID = mCurrentTRDTrigID; foundTRDTrigger = true; - } - else { + } else { // then check next trigger if (mCurrentTRDTrigID < trigsTRD.size() - 1) { - const auto& trig = trigsTRD[mCurrentTRDTrigID+1]; + const auto& trig = trigsTRD[mCurrentTRDTrigID + 1]; if (trkltId >= trig.getFirstTracklet() && trkltId < trig.getFirstTracklet() + trig.getNumberOfTracklets()) { - trdSelID = mCurrentTRDTrigID+1; + trdSelID = mCurrentTRDTrigID + 1; foundTRDTrigger = true; } } } - size_t low = 0, up = trigsTRD.size() - 1; + size_t low = 0, up = trigsTRD.size() - 1; // otherwise binary search while (low <= up && !foundTRDTrigger) { - trdSelID = low + std::floor( (up - low)/2 ); + trdSelID = low + std::floor((up - low) / 2); const auto& trig = trigsTRD[trdSelID]; if (trig.getFirstTracklet() > trkltId) { up = trdSelID - 1; - } - else { + } else { if (trig.getFirstTracklet() + trig.getNumberOfTracklets() <= trkltId) { low = trdSelID + 1; - } - else { + } else { foundTRDTrigger = true; } } @@ -502,7 +499,6 @@ void AODProducerWorkflowDPL::addToTRDsExtra(const o2::globaltracking::RecoContai q0sCor[iLay] += (float)trklt.getQ0() / cor; q1sCor[iLay] += (float)trklt.getQ1() / cor; q2sCor[iLay] += (float)trklt.getQ2() / cor; - } } } @@ -2422,7 +2418,7 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) mGIDUsedByStr.emplace(sTrk.mITSRef, GIndex::ITS); } } - + mCurrentTRDTrigID = 0; // reinitialize index for TRD trigger record search // filling unassigned tracks first // so that all unassigned tracks are stored in the beginning of the table together From e52a85c06aaaebe73d68ec14dc3ed1f8e2a976b7 Mon Sep 17 00:00:00 2001 From: KangkanGoswami Date: Fri, 27 Feb 2026 19:22:52 +0530 Subject: [PATCH 7/8] Adjust TRD logic after rebase --- Detectors/AOD/src/AODProducerWorkflowSpec.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index f55ff4656d332..d7a8098337f51 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -3414,8 +3414,11 @@ DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, boo OutputForTable::spec(), OutputForTable::spec(), OutputForTable::spec(), + OutputForTable::spec(), OutputForTable::spec(), + OutputForTable::spec(), OutputForTable::spec(), + OutputForTable::spec(), OutputForTable::spec(), OutputForTable::spec(), OutputForTable::spec(), From 91c00586bb73d05dffe27ffb0faeabcd365d13f6 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Fri, 27 Feb 2026 13:57:06 +0000 Subject: [PATCH 8/8] Please consider the following formatting changes --- Detectors/AOD/src/AODProducerWorkflowSpec.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index d7a8098337f51..fcb419d6c441b 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -404,7 +404,7 @@ void AODProducerWorkflowDPL::addToTRDsExtra(const o2::globaltracking::RecoContai return; } const auto& trk = recoData.getTrack(contributorsGID[GIndex::Source::TRD]); - o2::track::TrackPar trkC{contributorsGID[GIndex::Source::ITSTPC].isIndexSet() ? recoData.getTPCITSTrack(contributorsGID[GIndex::Source::ITSTPC]).getParamOut() : recoData.getTPCTrack(contributorsGID[GIndex::Source::TPC]).getParamOut() }; + o2::track::TrackPar trkC{contributorsGID[GIndex::Source::ITSTPC].isIndexSet() ? recoData.getTPCITSTrack(contributorsGID[GIndex::Source::ITSTPC]).getParamOut() : recoData.getTPCTrack(contributorsGID[GIndex::Source::TPC]).getParamOut()}; const auto& trklets = recoData.getTRDTracklets(); const auto& ctrklets = recoData.getTRDCalibratedTracklets(); for (int iLay{0}; iLay < 6; ++iLay) {