From 8ad6e3d692abd18c04094bb8be8712797b7fdc7d Mon Sep 17 00:00:00 2001 From: Christian Sonnabend Date: Wed, 5 Mar 2025 18:41:31 +0100 Subject: [PATCH 1/2] Fixing handling of edge clusters Adapting edge correction Fixing edge handling Please consider the following formatting changes Fix for right edge check --- GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.cxx | 7 ++++++- GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.h | 2 +- GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.cxx | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.cxx b/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.cxx index d145aaed705d9..a826cdf71f575 100644 --- a/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.cxx @@ -97,7 +97,7 @@ GPUd() Charge ClusterAccumulator::updateOuter(PackedCharge charge, Delta2 d) return q; } -GPUd() void ClusterAccumulator::finalize(const ChargePos& pos, Charge q, TPCTime timeOffset, const GPUTPCGeometry& geo) +GPUd() void ClusterAccumulator::finalize(const ChargePos& pos, Charge q, TPCTime timeOffset, const GPUTPCGeometry& geo, Charge* padBoundaryCharges) { mQtot += q; @@ -116,6 +116,11 @@ GPUd() void ClusterAccumulator::finalize(const ChargePos& pos, Charge q, TPCTime if (CfUtils::isAtEdge(pos, geo.NPads(pos.row()))) { bool leftEdge = (pad < 2); bool correct = (leftEdge) ? (pad < mPadMean) : (pad > mPadMean); + if (leftEdge && pad == 1) { // only check charge at boundary if maximum is at least one pad away from boundary + correct = correct && (padBoundaryCharges[0] > 0); // Only correct if cluster is asymmetric with charge > 0 towards sector boundary, otherwise all charge is found + } else if (!leftEdge && pad == (geo.NPads(pos.row()) - 2)) { + correct = correct && (padBoundaryCharges[1] > 0); + } mPadMean = (correct) ? pad : mPadMean; } } diff --git a/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.h b/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.h index 26decbf0a5b14..c409a6cced3a5 100644 --- a/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.h +++ b/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.h @@ -40,7 +40,7 @@ class ClusterAccumulator GPUd() tpccf::Charge updateInner(PackedCharge, tpccf::Delta2); GPUd() tpccf::Charge updateOuter(PackedCharge, tpccf::Delta2); - GPUd() void finalize(const ChargePos&, tpccf::Charge, tpccf::TPCTime, const GPUTPCGeometry&); + GPUd() void finalize(const ChargePos&, tpccf::Charge, tpccf::TPCTime, const GPUTPCGeometry&, tpccf::Charge*); GPUd() bool toNative(const ChargePos&, tpccf::Charge, tpc::ClusterNative&, const GPUParam&) const; private: diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.cxx index 1aeae812f5193..f28e80aa08201 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.cxx @@ -58,6 +58,8 @@ GPUdii() void GPUTPCCFClusterizer::computeClustersImpl(int32_t nBlocks, int32_t ChargePos pos = filteredPeakPositions[CAMath::Min(idx, clusternum - 1)]; Charge charge = chargeMap[pos].unpack(); + Charge padBoundaryCharges[2] = {chargeMap[pos.delta({-1, 0})].unpack(), chargeMap[pos.delta({1, 0})].unpack()}; + ClusterAccumulator pc; CPU_ONLY(labelAcc->collect(pos, charge)); @@ -80,7 +82,7 @@ GPUdii() void GPUTPCCFClusterizer::computeClustersImpl(int32_t nBlocks, int32_t } return; } - pc.finalize(pos, charge, fragment.start, clusterer.Param().tpcGeometry); + pc.finalize(pos, charge, fragment.start, clusterer.Param().tpcGeometry, padBoundaryCharges); tpc::ClusterNative myCluster; bool rejectCluster = !pc.toNative(pos, charge, myCluster, clusterer.Param()); From 43290ba172c892e014323c6ace45e1c94ecc6b76 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 12 Mar 2025 19:26:48 +0100 Subject: [PATCH 2/2] GPU TPC CF: Use corrected check also for edge cluster tagging --- GPU/GPUTracking/TPCClusterFinder/CfUtils.h | 5 -- .../TPCClusterFinder/ClusterAccumulator.cxx | 89 +++++++++---------- .../TPCClusterFinder/ClusterAccumulator.h | 4 +- .../TPCClusterFinder/GPUTPCCFClusterizer.cxx | 6 +- 4 files changed, 45 insertions(+), 59 deletions(-) diff --git a/GPU/GPUTracking/TPCClusterFinder/CfUtils.h b/GPU/GPUTracking/TPCClusterFinder/CfUtils.h index 4504b8288aee0..75dcc166abd9b 100644 --- a/GPU/GPUTracking/TPCClusterFinder/CfUtils.h +++ b/GPU/GPUTracking/TPCClusterFinder/CfUtils.h @@ -27,11 +27,6 @@ class CfUtils { public: - static GPUdi() bool isAtEdge(const ChargePos& pos, tpccf::GlobalPad padsPerRow) - { - return (pos.pad() < 2 || pos.pad() >= padsPerRow - 2); - } - static GPUdi() bool innerAboveThreshold(uint8_t aboveThreshold, uint16_t outerIdx) { return aboveThreshold & (1 << cfconsts::OuterToInner[outerIdx]); diff --git a/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.cxx b/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.cxx index a826cdf71f575..77dc6e119df7d 100644 --- a/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.cxx @@ -21,45 +21,6 @@ using namespace o2::gpu; using namespace o2::gpu::tpccf; -GPUd() bool ClusterAccumulator::toNative(const ChargePos& pos, Charge q, tpc::ClusterNative& cn, const GPUParam& param) const -{ - cn.qTot = CAMath::Float2UIntRn(mQtot); - if (cn.qTot <= param.rec.tpc.cfQTotCutoff) { - return false; - } - cn.qMax = q; - if (cn.qMax <= param.rec.tpc.cfQMaxCutoff) { - return false; - } - if (mTimeMean < param.rec.tpc.clustersShiftTimebinsClusterizer) { - return false; - } - if (q <= param.rec.tpc.cfQMaxCutoffSingleTime && mTimeSigma == 0) { - return false; - } - if (q <= param.rec.tpc.cfQMaxCutoffSinglePad && mPadSigma == 0) { - return false; - } - - bool isEdgeCluster = CfUtils::isAtEdge(pos, param.tpcGeometry.NPads(pos.row())); - bool wasSplitInTime = mSplitInTime >= param.rec.tpc.cfMinSplitNum; - bool wasSplitInPad = mSplitInPad >= param.rec.tpc.cfMinSplitNum; - bool isSingleCluster = (mPadSigma == 0) || (mTimeSigma == 0); - - uint8_t flags = 0; - flags |= (isEdgeCluster) ? tpc::ClusterNative::flagEdge : 0; - flags |= (wasSplitInTime) ? tpc::ClusterNative::flagSplitTime : 0; - flags |= (wasSplitInPad) ? tpc::ClusterNative::flagSplitPad : 0; - flags |= (isSingleCluster) ? tpc::ClusterNative::flagSingle : 0; - - cn.setTimeFlags(mTimeMean - param.rec.tpc.clustersShiftTimebinsClusterizer, flags); - cn.setPad(mPadMean); - cn.setSigmaTime(mTimeSigma); - cn.setSigmaPad(mPadSigma); - - return true; -} - GPUd() void ClusterAccumulator::update(Charge splitCharge, Delta2 d) { mQtot += splitCharge; @@ -97,7 +58,7 @@ GPUd() Charge ClusterAccumulator::updateOuter(PackedCharge charge, Delta2 d) return q; } -GPUd() void ClusterAccumulator::finalize(const ChargePos& pos, Charge q, TPCTime timeOffset, const GPUTPCGeometry& geo, Charge* padBoundaryCharges) +GPUd() bool ClusterAccumulator::toNative(const ChargePos& pos, Charge q, tpc::ClusterNative& cn, const GPUParam& param, TPCTime timeOffset, const Array2D& chargeMap) { mQtot += q; @@ -113,14 +74,48 @@ GPUd() void ClusterAccumulator::finalize(const ChargePos& pos, Charge q, TPCTime mPadMean += pad; mTimeMean += timeOffset + pos.time(); - if (CfUtils::isAtEdge(pos, geo.NPads(pos.row()))) { + bool isEdgeCluster = pos.pad() < 2 || pos.pad() >= param.tpcGeometry.NPads(pos.row()) - 2; // Geometrical edge check, peak within 2 pads of sector edge + if (isEdgeCluster) { bool leftEdge = (pad < 2); - bool correct = (leftEdge) ? (pad < mPadMean) : (pad > mPadMean); - if (leftEdge && pad == 1) { // only check charge at boundary if maximum is at least one pad away from boundary - correct = correct && (padBoundaryCharges[0] > 0); // Only correct if cluster is asymmetric with charge > 0 towards sector boundary, otherwise all charge is found - } else if (!leftEdge && pad == (geo.NPads(pos.row()) - 2)) { - correct = correct && (padBoundaryCharges[1] > 0); + if (leftEdge ? (pad == 1 && chargeMap[pos.delta({-1, 0})].unpack() < 1) : (pad == (param.tpcGeometry.NPads(pos.row()) - 2) && chargeMap[pos.delta({1, 0})].unpack() < 1)) { + isEdgeCluster = false; // No edge cluster if peak is close to edge but no charge at the edge. + } else if (leftEdge ? (pad < mPadMean) : (pad > mPadMean)) { + mPadMean = pad; // Correct to peak position if COG is close to middle of pad than peak } - mPadMean = (correct) ? pad : mPadMean; } + + cn.qTot = CAMath::Float2UIntRn(mQtot); + if (cn.qTot <= param.rec.tpc.cfQTotCutoff) { + return false; + } + cn.qMax = q; + if (cn.qMax <= param.rec.tpc.cfQMaxCutoff) { + return false; + } + if (mTimeMean < param.rec.tpc.clustersShiftTimebinsClusterizer) { + return false; + } + if (q <= param.rec.tpc.cfQMaxCutoffSingleTime && mTimeSigma == 0) { + return false; + } + if (q <= param.rec.tpc.cfQMaxCutoffSinglePad && mPadSigma == 0) { + return false; + } + + bool wasSplitInTime = mSplitInTime >= param.rec.tpc.cfMinSplitNum; + bool wasSplitInPad = mSplitInPad >= param.rec.tpc.cfMinSplitNum; + bool isSingleCluster = (mPadSigma == 0) || (mTimeSigma == 0); + + uint8_t flags = 0; + flags |= (isEdgeCluster) ? tpc::ClusterNative::flagEdge : 0; + flags |= (wasSplitInTime) ? tpc::ClusterNative::flagSplitTime : 0; + flags |= (wasSplitInPad) ? tpc::ClusterNative::flagSplitPad : 0; + flags |= (isSingleCluster) ? tpc::ClusterNative::flagSingle : 0; + + cn.setTimeFlags(mTimeMean - param.rec.tpc.clustersShiftTimebinsClusterizer, flags); + cn.setPad(mPadMean); + cn.setSigmaTime(mTimeSigma); + cn.setSigmaPad(mPadSigma); + + return true; } diff --git a/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.h b/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.h index c409a6cced3a5..73f7cb439775a 100644 --- a/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.h +++ b/GPU/GPUTracking/TPCClusterFinder/ClusterAccumulator.h @@ -17,6 +17,7 @@ #include "clusterFinderDefs.h" #include "PackedCharge.h" +#include "Array2D.h" namespace o2 { @@ -40,8 +41,7 @@ class ClusterAccumulator GPUd() tpccf::Charge updateInner(PackedCharge, tpccf::Delta2); GPUd() tpccf::Charge updateOuter(PackedCharge, tpccf::Delta2); - GPUd() void finalize(const ChargePos&, tpccf::Charge, tpccf::TPCTime, const GPUTPCGeometry&, tpccf::Charge*); - GPUd() bool toNative(const ChargePos&, tpccf::Charge, tpc::ClusterNative&, const GPUParam&) const; + GPUd() bool toNative(const ChargePos&, tpccf::Charge, tpc::ClusterNative&, const GPUParam&, tpccf::TPCTime, const Array2D&); private: float mQtot = 0; diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.cxx index f28e80aa08201..407deb6a588d0 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.cxx @@ -58,8 +58,6 @@ GPUdii() void GPUTPCCFClusterizer::computeClustersImpl(int32_t nBlocks, int32_t ChargePos pos = filteredPeakPositions[CAMath::Min(idx, clusternum - 1)]; Charge charge = chargeMap[pos].unpack(); - Charge padBoundaryCharges[2] = {chargeMap[pos.delta({-1, 0})].unpack(), chargeMap[pos.delta({1, 0})].unpack()}; - ClusterAccumulator pc; CPU_ONLY(labelAcc->collect(pos, charge)); @@ -82,10 +80,8 @@ GPUdii() void GPUTPCCFClusterizer::computeClustersImpl(int32_t nBlocks, int32_t } return; } - pc.finalize(pos, charge, fragment.start, clusterer.Param().tpcGeometry, padBoundaryCharges); - tpc::ClusterNative myCluster; - bool rejectCluster = !pc.toNative(pos, charge, myCluster, clusterer.Param()); + bool rejectCluster = !pc.toNative(pos, charge, myCluster, clusterer.Param(), fragment.start, chargeMap); if (rejectCluster) { if (clusterPosInRow) {