|
14 | 14 |
|
15 | 15 | #include <CCDB/BasicCCDBManager.h> |
16 | 16 | #include <CommonConstants/LHCConstants.h> |
| 17 | +#include <CommonUtils/ConfigurableParam.h> |
| 18 | +#include <CommonUtils/ConfigurableParamHelper.h> |
17 | 19 | #include <DataFormatsTPC/VDriftCorrFact.h> |
18 | 20 | #include <Framework/DataTypes.h> |
19 | 21 | #include <Framework/Logger.h> |
|
26 | 28 | namespace o2::aod::common |
27 | 29 | { |
28 | 30 |
|
| 31 | +struct TPCVDriftManagerParam : public o2::conf::ConfigurableParamHelper<TPCVDriftManagerParam> { |
| 32 | + // Use the TPC side flags (with legacy-data fallback) instead of the tgl-sign-based correction. |
| 33 | + // Off by default so that existing analyses see no change in results until this is explicitly |
| 34 | + // enabled for testing. |
| 35 | + bool useSideBasedCorrection = false; |
| 36 | + |
| 37 | + O2ParamDef(TPCVDriftManagerParam, "TPCVDriftManager"); |
| 38 | +}; |
| 39 | + |
29 | 40 | // Thin wrapper for vdrift ccdb queries should partially mirror VDriftHelper class. |
30 | 41 | // Allows to move TPC standalone tracks under the assumption of a different |
31 | 42 | // collision than the track is associated to. |
@@ -131,48 +142,53 @@ class TPCVDriftManager |
131 | 142 | } |
132 | 143 |
|
133 | 144 | // impose new Z coordinate |
134 | | - const auto sides = (trackExtra.flags() & (o2::aod::track::TrackFlags::TPCSideA | o2::aod::track::TrackFlags::TPCSideC)); |
135 | 145 | float zShift = 0.f; |
136 | | - if (sides == o2::aod::track::TrackFlags::TPCSideA) { |
137 | | - zShift = dDrift; |
138 | | - } else if (sides == o2::aod::track::TrackFlags::TPCSideC) { |
139 | | - zShift = -dDrift; |
140 | | - } else if (sides == 0) { |
141 | | - // Fallback for datasets produced before the TPC side flags were introduced (Feb. 2026). |
142 | | - o2::aod::track::extensions::TPCTimeErrEncoding tEnc; |
143 | | - tEnc.encoding.timeErr = trackExtra.trackTimeRes(); |
144 | | - const float dFwd = tEnc.getDeltaTFwd(); |
145 | | - const float dBwd = tEnc.getDeltaTBwd(); |
146 | | - // Equal, small forward/backward margins mean the track is bounded on both ends, |
147 | | - // i.e. it crosses the CE: it cannot be moved and is already corrected elsewhere. |
148 | | - const bool crossesCE = (dFwd == dBwd) && (dFwd < mMaxCECrossingDeltaTNS); |
149 | | - if (!crossesCE) { |
150 | | - const bool zPositive = track.getZ() > 0.f; |
151 | | - const bool tglPositive = track.getTgl() > 0.f; |
152 | | - int side = 0; // +1 = A, -1 = C, 0 = undetermined -> leave uncorrected |
153 | | - if (zPositive == tglPositive) { |
154 | | - // Consistent sign: the track converges to Z=0 at the beamline by construction. |
155 | | - side = tglPositive ? 1 : -1; |
156 | | - } else if (dBwd == 0.f && dFwd > 0.f) { |
157 | | - // Bounded backward at the CE with room forward: no clusters on the opposite |
158 | | - // side, so trust the measured Z rather than the (here inverted) tgl. |
159 | | - side = zPositive ? 1 : -1; |
160 | | - } else if (dBwd > 0.f) { |
161 | | - // Large tgl track bounded at the readout side instead: trust tgl. |
162 | | - side = tglPositive ? 1 : -1; |
163 | | - } |
164 | | - // else: degenerate case, track touches both CE and readout -> cannot be deduced/moved. |
165 | | - // (in practice unreachable here: dFwd==dBwd==0 would already satisfy crossesCE above, |
166 | | - // since dFwd/dBwd are always >= 0; kept explicit to mirror the reference logic 1:1.) |
167 | | - |
168 | | - if (side > 0) { |
169 | | - zShift = dDrift; |
170 | | - } else if (side < 0) { |
171 | | - zShift = -dDrift; |
| 146 | + if (!TPCVDriftManagerParam::Instance().useSideBasedCorrection) { |
| 147 | + // Legacy behaviour (default): infer the side from tgl alone. |
| 148 | + zShift = (track.getTgl() < 0.f) ? -dDrift : dDrift; |
| 149 | + } else { |
| 150 | + const auto sides = (trackExtra.flags() & (o2::aod::track::TrackFlags::TPCSideA | o2::aod::track::TrackFlags::TPCSideC)); |
| 151 | + if (sides == o2::aod::track::TrackFlags::TPCSideA) { |
| 152 | + zShift = dDrift; |
| 153 | + } else if (sides == o2::aod::track::TrackFlags::TPCSideC) { |
| 154 | + zShift = -dDrift; |
| 155 | + } else if (sides == 0) { |
| 156 | + // Fallback for datasets produced before the TPC side flags were introduced (Feb. 2026). |
| 157 | + o2::aod::track::extensions::TPCTimeErrEncoding tEnc; |
| 158 | + tEnc.encoding.timeErr = trackExtra.trackTimeRes(); |
| 159 | + const float dFwd = tEnc.getDeltaTFwd(); |
| 160 | + const float dBwd = tEnc.getDeltaTBwd(); |
| 161 | + // Equal, small forward/backward margins mean the track is bounded on both ends, |
| 162 | + // i.e. it crosses the CE: it cannot be moved and is already corrected elsewhere. |
| 163 | + const bool crossesCE = (dFwd == dBwd) && (dFwd < mMaxCECrossingDeltaTNS); |
| 164 | + if (!crossesCE) { |
| 165 | + const bool zPositive = track.getZ() > 0.f; |
| 166 | + const bool tglPositive = track.getTgl() > 0.f; |
| 167 | + int side = 0; // +1 = A, -1 = C, 0 = undetermined -> leave uncorrected |
| 168 | + if (zPositive == tglPositive) { |
| 169 | + // Consistent sign: the track converges to Z=0 at the beamline by construction. |
| 170 | + side = tglPositive ? 1 : -1; |
| 171 | + } else if (dBwd == 0.f && dFwd > 0.f) { |
| 172 | + // Bounded backward at the CE with room forward: no clusters on the opposite |
| 173 | + // side, so trust the measured Z rather than the (here inverted) tgl. |
| 174 | + side = zPositive ? 1 : -1; |
| 175 | + } else if (dBwd > 0.f) { |
| 176 | + // Large tgl track bounded at the readout side instead: trust tgl. |
| 177 | + side = tglPositive ? 1 : -1; |
| 178 | + } |
| 179 | + // else: degenerate case, track touches both CE and readout -> cannot be deduced/moved. |
| 180 | + // (in practice unreachable here: dFwd==dBwd==0 would already satisfy crossesCE above, |
| 181 | + // since dFwd/dBwd are always >= 0; kept explicit to mirror the reference logic 1:1.) |
| 182 | + |
| 183 | + if (side > 0) { |
| 184 | + zShift = dDrift; |
| 185 | + } else if (side < 0) { |
| 186 | + zShift = -dDrift; |
| 187 | + } |
172 | 188 | } |
173 | 189 | } |
| 190 | + // else: track has clusters on both sides (crossed the CE) and is already corrected elsewhere |
174 | 191 | } |
175 | | - // else: track has clusters on both sides (crossed the CE) and is already corrected elsewhere |
176 | 192 | track.setZ(track.getZ() + zShift); |
177 | 193 | if constexpr (std::is_base_of_v<o2::track::TrackParCov, Track>) { |
178 | 194 | track.setCov(track.getSigmaZ2() + dDriftErr * dDriftErr, o2::track::kSigZ2); |
|
0 commit comments