From 24383a4ec3698d930f568375ac8ec86cc1091ac5 Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 23 Apr 2026 17:40:17 +0200 Subject: [PATCH] Fixes in processCosmics, allow pipelining Only cosmic tracks with at least one TRD or TOF contribution will be accepted in the tpc-refitter. Added options for cosmics processing: --ignore-legs-wo-outer-det will skip cosmic legs w/o TRD or TOF constraint even if other leg is well constrained --use-cosmic-leg-timing will prefer the timestamp of each leg to (if available) for the refit, otherwise use cosmic track timestamp. When the workflow is run with >1 lane, the streamer output XX.root of each lane will appear with suffix: XX_.root --- Detectors/TPC/workflow/src/TPCRefitter.cxx | 67 +++++++++++-------- .../workflow/src/tpc-refitter-workflow.cxx | 7 +- 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/Detectors/TPC/workflow/src/TPCRefitter.cxx b/Detectors/TPC/workflow/src/TPCRefitter.cxx index fbab4500fde5c..4b877f56c90fd 100644 --- a/Detectors/TPC/workflow/src/TPCRefitter.cxx +++ b/Detectors/TPC/workflow/src/TPCRefitter.cxx @@ -22,6 +22,7 @@ #include "DetectorsBase/Propagator.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" +#include "Framework/DeviceSpec.h" #include "Framework/Task.h" #include "MathUtils/Tsallis.h" #include "DetectorsCommonDataFormats/DetID.h" @@ -96,6 +97,8 @@ class TPCRefitterSpec final : public Task int mWriteTrackClusters = 0; ///< bitmask of which cluster information to dump to the tree: 0x1 = cluster native, 0x2 = corrected cluster positions, 0x4 = uncorrected cluster positions, 0x8 occupancy info bool mDoSampling{false}; ///< perform sampling of unbinned data bool mDoRefit{true}; ///< perform refit of TPC track + bool mIgnorLegsWOGoodTime{false}; ///< ignore cosmic legs w/o TRD or TOF constraint instead of using the time of other constraned leg + bool mUseCosmicLegTiming{false}; ///< use the timestamp from the cosmic track leg instead of using cosmic track timestamp std::vector mClusterOccupancy; ///< binned occupancy of all clusters std::vector mITSTPCTrackOccupanyTPCTime; ///< binned occupancy for ITS-TPC matched tracks using the TPC track time std::vector mITSTPCTrackOccupanyCombinedTime; ///< binned occupancy for ITS-TPC matched tracks using the combined track time @@ -152,6 +155,9 @@ void TPCRefitterSpec::init(InitContext& ic) mStudyType = ic.options().get("study-type"); mWriterType = ic.options().get("writer-type"); mWriteTrackClusters = ic.options().get("write-track-clusters"); + mIgnorLegsWOGoodTime = ic.options().get("ignore-legs-wo-outer-det"); + mUseCosmicLegTiming = ic.options().get("use-cosmic-leg-timing"); + const auto occBinsPerDrift = ic.options().get("occupancy-bins-per-drift"); mTimeBinsPerTF = (o2::raw::HBFUtils::Instance().nHBFPerTF * o2::constants::lhc::LHCMaxBunches) / 8 + 2 * mTimeBinsPerDrift; // add one drift before and after the TF mOccupancyBinsPerTF = static_cast(std::ceil(float(mTimeBinsPerTF * occBinsPerDrift) / mTimeBinsPerDrift)); @@ -160,19 +166,23 @@ void TPCRefitterSpec::init(InitContext& ic) mITSTPCTrackOccupanyCombinedTime.resize(mOccupancyBinsPerTF); LOGP(info, "Using {} bins for the occupancy per TF", mOccupancyBinsPerTF); + int lane = ic.services().get().inputTimesliceId; + int maxLanes = ic.services().get().maxInputTimeslices; + auto composeName = [maxLanes, lane](const std::string& seed) { return maxLanes > 1 ? fmt::format("{}_{}.root", seed, lane) : fmt::format("{}.root", seed); }; + if ((mWriterType & WriterType::Streamer) == WriterType::Streamer) { if ((mStudyType & StudyType::TPC) == StudyType::TPC) { - mDBGOutTPC = std::make_unique("tpctracks-study-streamer.root", "recreate"); + mDBGOutTPC = std::make_unique(composeName("tpctracks-study-streamer").c_str(), "recreate"); } if ((mStudyType & StudyType::ITSTPC) == StudyType::ITSTPC) { - mDBGOutITSTPC = std::make_unique("itstpctracks-study-streamer.root", "recreate"); + mDBGOutITSTPC = std::make_unique(composeName("itstpctracks-study-streamer").c_str(), "recreate"); } if ((mStudyType & StudyType::Cosmics) == StudyType::Cosmics) { - mDBGOutCosmics = std::make_unique("cosmics-study-streamer.root", "recreate"); + mDBGOutCosmics = std::make_unique(composeName("cosmics-study-streamer").c_str(), "recreate"); } } if (ic.options().get("dump-clusters")) { - mDBGOutCl = std::make_unique("tpc-trackStudy-cl.root", "recreate"); + mDBGOutCl = std::make_unique(composeName("tpc-trackStudy-cl").c_str(), "recreate"); } if (mXRef < 0.) { @@ -677,35 +687,36 @@ bool TPCRefitterSpec::processTPCTrack(o2::tpc::TrackTPC tr, o2::MCCompLabel lbl, void TPCRefitterSpec::processCosmics(o2::globaltracking::RecoContainer& recoData) { - auto tof = recoData.getTOFClusters(); const auto& par = o2::tpc::ParameterElectronics::Instance(); const auto invBinWidth = 1.f / par.ZbinWidth; for (const auto& cosmic : mCosmics) { // - const auto& gidtop = cosmic.getRefTop(); - const auto& gidbot = cosmic.getRefBottom(); - - // LOGP(info, "Sources: {} - {}", o2::dataformats::GlobalTrackID::getSourceName(gidtop.getSource()), o2::dataformats::GlobalTrackID::getSourceName(gidbot.getSource())); - - std::array contributorsGID[2] = {recoData.getSingleDetectorRefs(cosmic.getRefTop()), recoData.getSingleDetectorRefs(cosmic.getRefBottom())}; - const auto trackTime = cosmic.getTimeMUS().getTimeStamp() * invBinWidth; - - // check if track has TPC & TOF for top and bottom part - // loop over both parts - for (const auto& comsmicInfo : contributorsGID) { - auto& tpcGlobal = comsmicInfo[GTrackID::TPC]; - auto& tofGlobal = comsmicInfo[GTrackID::TOF]; - if (tpcGlobal.isIndexSet() && tofGlobal.isIndexSet()) { - const auto itrTPC = tpcGlobal.getIndex(); - const auto itrTOF = tofGlobal.getIndex(); - const auto& tofCl = tof[itrTOF]; - const auto tofTime = tofCl.getTime() * 1e-6 * invBinWidth; // ps -> us -> time bins - const auto tofTimeRaw = tofCl.getTimeRaw() * 1e-6 * invBinWidth; // ps -> us -> time bins - const auto& trackTPC = mTPCTracksArray[itrTPC]; - // LOGP(info, "Cosmic time: {}, TOF time: {}, TOF time raw: {}, TPC time: {}", trackTime, tofTime, tofTimeRaw, trackTPC.getTime0()); - processTPCTrack(trackTPC, mUseMC ? mTPCTrkLabels[itrTPC] : o2::MCCompLabel{}, mDBGOutCosmics.get(), nullptr, nullptr, false, tofTime); + const GTrackID gidTopBot[] = {cosmic.getRefTop(), cosmic.getRefBottom()}; + // LOGP(info, "Sources: {} - {}", o2::dataformats::GlobalTrackID::getSourceName(gidTopBot[0].getSource()), o2::dataformats::GlobalTrackID::getSourceName(gidTopBot[1].getSource())); + // Wequire at least one TRD of TOF contribution to constrain the timestamp + bool hasGoodTime[2] = {false, false}; + std::array contributorsGID[2]; + for (int i = 0; i < 2; i++) { + contributorsGID[i] = recoData.getSingleDetectorRefs(gidTopBot[i]); + hasGoodTime[i] = gidTopBot[i].includesDet(DetID::TOF) || gidTopBot[i].includesDet(DetID::TRD); + } + if (!hasGoodTime[0] && !hasGoodTime[1]) { + continue; + } + float trackTime = cosmic.getTimeMUS().getTimeStamp() * invBinWidth; // this time corresponds to the center of top/bottom legs time-brackers intersection, i.e. should be the most precise one + + for (int i = 0; i < 2; i++) { + if (!contributorsGID[i][GTrackID::TPC].isSourceSet() || (mIgnorLegsWOGoodTime && !hasGoodTime[i])) { + continue; + } + const auto& trackTPC = mTPCTracksArray[contributorsGID[i][GTrackID::TPC]]; + float useTrackTime = trackTime, dummyError = 0.f; + if (mUseCosmicLegTiming && hasGoodTime[i]) { // track out time was requested (if available) + recoData.getTrackTime(gidTopBot[i], useTrackTime, dummyError); + useTrackTime *= invBinWidth; } + processTPCTrack(trackTPC, mUseMC ? mTPCTrkLabels[contributorsGID[i][GTrackID::TPC]] : o2::MCCompLabel{}, mDBGOutCosmics.get(), nullptr, nullptr, false, useTrackTime); } } } @@ -731,6 +742,8 @@ DataProcessorSpec getTPCRefitterSpec(GTrackID::mask_t srcTracks, GTrackID::mask_ {"study-type", VariantType::Int, 1, {"Bitmask of study type: 0x1 = TPC only, 0x2 = TPC + ITS, 0x4 = Cosmics"}}, {"writer-type", VariantType::Int, 1, {"Bitmask of writer type: 0x1 = per track streamer, 0x2 = per TF vectors"}}, {"occupancy-bins-per-drift", VariantType::UInt32, 31u, {"number of bin for occupancy histogram per drift time (500tb)"}}, + {"ignore-legs-wo-outer-det", VariantType::Bool, false, {"Ignore cosmic legs w/o TRD or TOF constraint even if other leg is well constrained"}}, + {"use-cosmic-leg-timing", VariantType::Bool, false, {"Use leg-specific timestamp instead of cosmic track final timestamp"}}, }; auto dataRequest = std::make_shared(); diff --git a/Detectors/TPC/workflow/src/tpc-refitter-workflow.cxx b/Detectors/TPC/workflow/src/tpc-refitter-workflow.cxx index 61c589512d1ce..567d9caf14bc6 100644 --- a/Detectors/TPC/workflow/src/tpc-refitter-workflow.cxx +++ b/Detectors/TPC/workflow/src/tpc-refitter-workflow.cxx @@ -66,11 +66,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto sclOpt = o2::tpc::CorrectionMapsOptions::parseGlobalOptions(configcontext.options()); const auto enableCosmics = configcontext.options().get("enable-cosmics"); - GID::mask_t allowedSourcesTrc = GID::getSourcesMask("ITS,TPC,ITS-TPC,TPC-TOF"); - GID::mask_t allowedSourcesClus = GID::getSourcesMask("TPC,TOF"); - if (enableCosmics) { - allowedSourcesTrc = allowedSourcesTrc | GID::getSourcesMask("ITS-TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD-TOF"); - } + GID::mask_t allowedSourcesTrc = GID::getSourcesMask("TPC,ITS-TPC,TPC-TOF,TPC-TRD,ITS-TPC-TRD,TPC-TRD-TOF,ITS-TPC-TOF,ITS-TPC-TRD-TOF"); + GID::mask_t allowedSourcesClus = GID::getSourcesMask("TPC"); GID::mask_t srcTrc = allowedSourcesTrc & GID::getSourcesMask(configcontext.options().get("track-sources")); GID::mask_t srcCls = allowedSourcesClus & GID::getSourcesMask(configcontext.options().get("cluster-sources"));