Skip to content

Commit cfb5a4b

Browse files
TPC SCD: round instead of truncate when packing the unbinned residuals (#16046)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent f2a8c28 commit cfb5a4b

2 files changed

Lines changed: 20 additions & 8 deletions

File tree

‎Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#define ALICEO2_TPC_TRACKINTERPOLATION_H_
1919

2020
#include <gsl/span>
21+
#include <algorithm>
22+
#include <cmath>
2123
#include "CommonDataFormat/EvIndex.h"
2224
#include "CommonDataFormat/RangeReference.h"
2325
#include "ReconstructionDataFormats/Track.h"
@@ -77,11 +79,11 @@ struct TPCClusterResiduals {
7779
struct UnbinnedResid {
7880
UnbinnedResid() = default;
7981
UnbinnedResid(float dyIn, float dzIn, float tgSlpIn, float yIn, float zIn,
80-
unsigned char rowIn, unsigned char secIn, short chanIn = -1, bool rejFlag = false) : dy(static_cast<short>(dyIn * 0x7fff / param::MaxResid)),
81-
dz(static_cast<short>(dzIn * 0x7fff / param::MaxResid)),
82-
tgSlp(static_cast<short>(tgSlpIn * 0x7fff / param::MaxTgSlp)),
83-
y(static_cast<short>(yIn * 0x7fff / param::MaxY)),
84-
z(static_cast<short>(zIn * 0x7fff / param::MaxZ)),
82+
unsigned char rowIn, unsigned char secIn, short chanIn = -1, bool rejFlag = false) : dy(packToShort(dyIn, param::MaxResid)),
83+
dz(packToShort(dzIn, param::MaxResid)),
84+
tgSlp(packToShort(tgSlpIn, param::MaxTgSlp, std::abs(tgSlpIn) < param::MaxTgSlp ? 0x7fff - 1 : 0x7fff)),
85+
y(packToShort(yIn, param::MaxY)),
86+
z(packToShort(zIn, param::MaxZ)),
8587
row(rowIn),
8688
sec(secIn),
8789
channel(chanIn),
@@ -96,6 +98,16 @@ struct UnbinnedResid {
9698
short channel{-1}; ///< extra channel info (ITS chip ID, TRD chamber, TOF main pad within the sector)
9799
bool rejected{false}; ///< residual is flagged as rejected in the validateTrack
98100

101+
/// value (|value| <= maximum) packed into a signed short, rounded to the nearest step. The scale is fixed at 0x7fff steps per maximum
102+
/// (decoded everywhere as short * maximum / 0x7fff); limit only clips the result to +-limit (e.g. 0x7fff - 1 for an unclamped tgSlp, to
103+
/// keep 0x7fff as the clamp marker), it does not change the scale. A plain cast would truncate towards zero, i.e. move every value
104+
/// towards zero by up to one step: the decoded cluster position y + dy then depends on the sign of dy below the step size, which
105+
/// biases residuals binned by the cluster position on sub-pad scales
106+
static short packToShort(float value, float maximum, int limit = 0x7fff)
107+
{
108+
return static_cast<short>(std::clamp<long>(std::lround(value * 0x7fff / maximum), -limit, limit));
109+
}
110+
99111
/// true if tgSlp was saturated at +-param::MaxTgSlp (scdcalib.clampTgSlp): unclamped values have |tgSlp| <= 0x7fff - 1
100112
bool isTgSlpClamped() const { return tgSlp == 0x7fff || tgSlp == -0x7fff; }
101113
/// tgSlp marker of a position-only TPC cluster (scdcalib.keepClustersOnPropFail): no reference track at this cluster,

‎Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,7 @@ void TrackInterpolation::interpolateTrack(int iSeed)
913913
auto dy = yv - trkWorkITS.getY();
914914
auto dz = zv - trkWorkITS.getZ();
915915
if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWorkITS.getY()) < param::MaxY) && (std::abs(trkWorkITS.getZ()) < param::MaxZ) && std::abs(xv) < param::MaxVtxX) {
916-
short compXV = static_cast<short>(xv * 0x7fff / param::MaxVtxX);
916+
short compXV = UnbinnedResid::packToShort(xv, param::MaxVtxX);
917917
mClRes.emplace_back(dy, dz, alpha / TMath::Pi(), trkWorkITS.getY(), trkWorkITS.getZ(), 190, -1, compXV);
918918
if (!gidTable[GTrackID::ITSTPC].isIndexSet()) {
919919
LOGP(fatal, "ITS-TPC seed index is not set for TOF track");
@@ -985,7 +985,7 @@ int TrackInterpolation::processTRDLayer(const o2::trd::TrackTRD& trkTRD, int iLa
985985
if (trkData) {
986986
auto slope = trdSP.getDy();
987987
if (std::abs(slope) < param::MaxTRDSlope) {
988-
trkData->TRDTrkltSlope[iLayer] = slope * 0x7fff / param::MaxTRDSlope;
988+
trkData->TRDTrkltSlope[iLayer] = UnbinnedResid::packToShort(slope, param::MaxTRDSlope);
989989
}
990990
}
991991
if (trk64) {
@@ -1308,7 +1308,7 @@ void TrackInterpolation::extrapolateTrack(int iSeed)
13081308
auto dy = yv - trkWorkITS.getY();
13091309
auto dz = zv - trkWorkITS.getZ();
13101310
if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWorkITS.getY()) < param::MaxY) && (std::abs(trkWorkITS.getZ()) < param::MaxZ) && std::abs(xv) < param::MaxVtxX) {
1311-
short compXV = static_cast<short>(xv * 0x7fff / param::MaxVtxX);
1311+
short compXV = UnbinnedResid::packToShort(xv, param::MaxVtxX);
13121312
mClRes.emplace_back(dy, dz, alpha / TMath::Pi(), trkWorkITS.getY(), trkWorkITS.getZ(), 190, -1, compXV);
13131313
if (!gidTableFull[GTrackID::ITSTPC].isIndexSet()) {
13141314
LOGP(fatal, "ITS-TPC seed index is not set for TOF track");

0 commit comments

Comments
 (0)