Skip to content

Commit 7479fef

Browse files
MatchCosmics: energy-loss sign along the muon's flight; optional energy-loss sign in the TPC refit
The propagator applies the energy-loss correction along the direction of the track parameters (loss forward, gain backward), and refitWinners fits a cosmic from the bottom leg to the top one: after the inward refit of the bottom leg its parameters are inverted and carried up through the top leg, i.e. they describe a particle moving upward. A cosmic muon flies downward, from the top leg to the bottom leg, so only the inward refit of the bottom leg (backward along its parameters = backward along the flight) had the physical sign; the propagation of the inverted bottom leg to the top leg, the outward refit of the top leg, the inward refit of the top leg, its propagation to the bottom parameter and the propagation of the top seeds to the DCA had the opposite one. The sign is now imposed along the flight in all of them, with the propagator's signCorr argument. GPUO2InterfaceRefit / GPUTrackingRefit::RefitTrackAsTrackParCov (TrackParCov + cluster references) get the analogous optional last argument eLossSign, passed to their propagations (0 = along the parameters as before, +1 gain, -1 loss; flipped on the optional way to the reference X when that runs against the refit direction); the default keeps the behaviour for all other users. MC truth (cosmic MC, 1073 muons crossing the inner region; true parameters at the bottom TPC inner radius propagated back through the closest approach to the top one, compared to the true momentum there, q16 / q50 / q84 in MeV): true loss between the two 14.5 / 16.1 / 19.9 MeV (median for |z| at the closest approach 0-25 / 25-50 / 50-75 cm); predicted - true with the sign of the upward fit -14.5 / -15.2 / -18.6 MeV (as without material: the gain inward and the loss outward cancel), with the sign along the flight +1.2 / +2.1 / +1.0 MeV (spread q16-q84 about -2 ... +9 MeV). The matched cosmics hardly change because the two halves' errors cancel in their average: cosmic MC 7003 -> 7006 correct pairs (0 wrong), chi2Match median unchanged; cosmics run 562658 358 cosmics before and after; refitted q/pt within +-0.05 %. The halves themselves (e.g. the momentum at the TPC entrance) change by the full loss. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 1472e6a commit 7479fef

5 files changed

Lines changed: 39 additions & 19 deletions

File tree

‎Detectors/GlobalTracking/src/MatchCosmics.cxx‎

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ using namespace o2::globaltracking;
4545
using GTrackID = o2d::GlobalTrackID;
4646
using MatCorrType = o2::base::Propagator::MatCorrType;
4747

48+
namespace
49+
{
50+
// energy-loss sign of the propagations: the propagator applies the loss along the direction of the track parameters, and the refit runs
51+
// from the bottom leg up through the top leg (parameters of an upward-moving particle); the cosmic muon flies from the top leg to the
52+
// bottom leg, so the sign is imposed along its flight
53+
constexpr int ELossGain = 1;
54+
constexpr int ELossLoss = -1;
55+
} // namespace
56+
4857
//________________________________________________________
4958
void MatchCosmics::process(const o2::globaltracking::RecoContainer& data)
5059
{
@@ -64,7 +73,12 @@ void MatchCosmics::process(const o2::globaltracking::RecoContainer& data)
6473
for (int i = 0; i < ntr; i++) {
6574
auto& trc = mSeeds[i];
6675
if (trc.matchID != Reject) {
67-
if (!prop->propagateToDCABxByBz(v, trc, mMatchParams->maxStep, mMatchParams->matCorr)) {
76+
// a cosmic muon flies downward: along a leg whose outward direction points up (top leg) the inward propagation follows the flight,
77+
// so the energy is lost; along the bottom leg it goes back in the flight, so the energy is gained
78+
std::array<float, 3> momentum{};
79+
trc.getPxPyPzGlo(momentum);
80+
const int eLossSign = momentum[1] > 0.f ? ELossLoss : ELossGain;
81+
if (!prop->propagateToDCABxByBz(v, trc, mMatchParams->maxStep, mMatchParams->matCorr, nullptr, nullptr, eLossSign)) {
6882
trc.matchID = Reject; // reject track
6983
continue;
7084
}
@@ -154,7 +168,7 @@ void MatchCosmics::refitWinners(const o2::globaltracking::RecoContainer& data)
154168
}
155169
}
156170

157-
auto refitITSTrack = [this, &data, &itsTracksROF, &itsClusters](o2::track::TrackParCov& trFit, GTrackID gidx, float& chi2, bool inward = false) {
171+
auto refitITSTrack = [this, &data, &itsTracksROF, &itsClusters](o2::track::TrackParCov& trFit, GTrackID gidx, float& chi2, bool inward, int eLossSign) {
158172
const auto& itsTrOrig = data.getITSTrack(gidx);
159173
int nclRefit = 0, ncl = itsTrOrig.getNumberOfClusters(), rof = itsTracksROF[gidx.getIndex()];
160174
const auto& itsTrackClusRefs = data.getITSTracksClusterRefs();
@@ -170,7 +184,7 @@ void MatchCosmics::refitWinners(const o2::globaltracking::RecoContainer& data)
170184
for (int icl = from; icl != to; icl += step) { // ITS clusters are referred in layer decreasing order
171185
const auto& clus = itsClusters[itsTrackClusRefs[clEntry + icl]];
172186
float alpha = geomITS->getSensorRefAlpha(clus.getSensorID()), x = clus.getX();
173-
if (!trFit.rotate(alpha) || !propagator->propagateToX(trFit, x, propagator->getNominalBz(), this->mMatchParams->maxSnp, this->mMatchParams->maxStep, this->mMatchParams->matCorr)) {
187+
if (!trFit.rotate(alpha) || !propagator->propagateToX(trFit, x, propagator->getNominalBz(), this->mMatchParams->maxSnp, this->mMatchParams->maxStep, this->mMatchParams->matCorr, nullptr, eLossSign)) {
174188
break;
175189
}
176190
chi2 += trFit.getPredictedChi2(clus);
@@ -221,7 +235,7 @@ void MatchCosmics::refitWinners(const o2::globaltracking::RecoContainer& data)
221235
if (!mFieldON) {
222236
trCosm.setQ2Pt(-o2::track::kMostProbablePt);
223237
}
224-
int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosm, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2, false, false); // inward refit, reset
238+
int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosm, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2, false, false, ELossGain); // inward refit, reset
225239
if (retVal < 0) { // refit failed
226240
LOG(debug) << "Inward refit of btm TPC track failed.";
227241
continue;
@@ -247,7 +261,7 @@ void MatchCosmics::refitWinners(const o2::globaltracking::RecoContainer& data)
247261
}
248262
trCosm.invert();
249263
if (!trCosm.rotate(mSeeds[poolEntryID[top]].getAlpha()) ||
250-
!o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosm, mSeeds[poolEntryID[top]].getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) {
264+
!o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosm, mSeeds[poolEntryID[top]].getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr, nullptr, ELossGain)) {
251265
LOG(debug) << "Rotation/propagation of btm-track to top-track frame failed.";
252266
continue;
253267
}
@@ -260,7 +274,7 @@ void MatchCosmics::refitWinners(const o2::globaltracking::RecoContainer& data)
260274

261275
// is there ITS sub-track?
262276
if (gidxListTop[GTrackID::ITS].isIndexSet()) {
263-
auto nclfit = refitITSTrack(trCosm, gidxListTop[GTrackID::ITS], chi2, false);
277+
auto nclfit = refitITSTrack(trCosm, gidxListTop[GTrackID::ITS], chi2, false, ELossGain);
264278
if (nclfit < 0) {
265279
continue;
266280
}
@@ -273,13 +287,13 @@ void MatchCosmics::refitWinners(const o2::globaltracking::RecoContainer& data)
273287
if (trCosm.getX() * trCosm.getX() + trCosm.getY() * trCosm.getY() <= o2::constants::geom::XTPCInnerRef * o2::constants::geom::XTPCInnerRef) {
274288
float xtogo = 0;
275289
if (!trCosm.getXatLabR(o2::constants::geom::XTPCInnerRef, xtogo, mBz, o2::track::DirOutward) ||
276-
!o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosm, xtogo, mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) {
290+
!o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosm, xtogo, mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr, nullptr, ELossGain)) {
277291
LOG(debug) << "Propagation to inner TPC boundary X=" << xtogo << " failed";
278292
continue;
279293
}
280294
}
281295
const auto& tpcTrOrig = data.getTPCTrack(gidxListTop[GTrackID::TPC]);
282-
int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosm, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2, true, false); // outward refit, no reset
296+
int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosm, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2, true, false, ELossGain); // outward refit, no reset
283297
if (retVal < 0) { // refit failed
284298
LOG(debug) << "Outward refit of top TPC track failed.";
285299
continue;
@@ -293,23 +307,23 @@ void MatchCosmics::refitWinners(const o2::globaltracking::RecoContainer& data)
293307
auto trCosmTop = outerLegs[top];
294308
if (gidxListTop[GTrackID::TPC].isIndexSet()) { // inward refit in TPC
295309
const auto& tpcTrOrig = data.getTPCTrack(gidxListTop[GTrackID::TPC]);
296-
int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosmTop, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2Dummy, false, true); // inward refit, reset
310+
int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosmTop, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2Dummy, false, true, ELossLoss); // inward refit, reset
297311
if (retVal < 0) { // refit failed
298-
LOG(debug) << "Outward refit of top TPC track failed.";
312+
LOG(debug) << "Inward refit of top TPC track failed.";
299313
continue;
300314
} // inward refit in TPC
301315
}
302316
// is there ITS sub-track ?
303317
if (gidxListTop[GTrackID::ITS].isIndexSet()) {
304-
auto nclfit = refitITSTrack(trCosmTop, gidxListTop[GTrackID::ITS], chi2Dummy, true);
318+
auto nclfit = refitITSTrack(trCosmTop, gidxListTop[GTrackID::ITS], chi2Dummy, true, ELossLoss);
305319
if (nclfit < 0) {
306320
continue;
307321
}
308322
nclTot += nclfit;
309323
} // ITS refit
310324
// propagate to bottom param
311325
if (!trCosmTop.rotate(trCosmBtm.getAlpha()) ||
312-
!o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosmTop, trCosmBtm.getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) {
326+
!o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosmTop, trCosmBtm.getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr, nullptr, ELossLoss)) {
313327
LOG(debug) << "Rotation/propagation of top-track to bottom-track frame failed.";
314328
continue;
315329
}

‎GPU/GPUTracking/Interface/GPUO2InterfaceRefit.cxx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ void GPUO2InterfaceRefit::updateCalib(const TPCFastTransformPOD* trans, float bz
136136
int32_t GPUO2InterfaceRefit::RefitTrackAsGPU(o2::tpc::TrackTPC& trk, bool outward, bool resetCov) { return mRefit->RefitTrackAsGPU(trk, outward, resetCov); }
137137
int32_t GPUO2InterfaceRefit::RefitTrackAsTrackParCov(o2::tpc::TrackTPC& trk, bool outward, bool resetCov) { return mRefit->RefitTrackAsTrackParCov(trk, outward, resetCov); }
138138
int32_t GPUO2InterfaceRefit::RefitTrackAsGPU(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2, bool outward, bool resetCov) { return mRefit->RefitTrackAsGPU(trk, clusRef, time0, chi2, outward, resetCov); }
139-
int32_t GPUO2InterfaceRefit::RefitTrackAsTrackParCov(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2, bool outward, bool resetCov) { return mRefit->RefitTrackAsTrackParCov(trk, clusRef, time0, chi2, outward, resetCov); }
139+
int32_t GPUO2InterfaceRefit::RefitTrackAsTrackParCov(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2, bool outward, bool resetCov, int32_t eLossSign) { return mRefit->RefitTrackAsTrackParCov(trk, clusRef, time0, chi2, outward, resetCov, eLossSign); }
140140
void GPUO2InterfaceRefit::setIgnoreErrorsAtTrackEnds(bool v) { mRefit->mIgnoreErrorsOnTrackEnds = v; }
141141
void GPUO2InterfaceRefit::setTrackReferenceX(float v) { mParam->rec.tpc.trackReferenceX = v; }
142142

‎GPU/GPUTracking/Interface/GPUO2InterfaceRefit.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ class GPUO2InterfaceRefit
6767
int32_t RefitTrackAsGPU(o2::tpc::TrackTPC& trk, bool outward = false, bool resetCov = false);
6868
int32_t RefitTrackAsTrackParCov(o2::tpc::TrackTPC& trk, bool outward = false, bool resetCov = false);
6969
int32_t RefitTrackAsGPU(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2 = nullptr, bool outward = false, bool resetCov = false);
70-
int32_t RefitTrackAsTrackParCov(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2 = nullptr, bool outward = false, bool resetCov = false);
70+
// eLossSign: energy-loss sign of the propagations, 0 along the track parameters (loss forward, gain backward), +1 gain, -1 loss
71+
int32_t RefitTrackAsTrackParCov(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2 = nullptr, bool outward = false, bool resetCov = false, int32_t eLossSign = 0);
7172
void setTrackReferenceX(float v);
7273
void setIgnoreErrorsAtTrackEnds(bool v);
7374
void updateCalib(const o2::gpu::TPCFastTransformPOD* trans, float bzNominalGPU);

‎GPU/GPUTracking/Refit/GPUTrackingRefit.cxx‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ GPUd() int32_t GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov
221221
convertTrack<S, T, typename internal::refitTrackTypes<S>::propagator>(trk, trkX, prop, &TrackParCovChi2);
222222
int32_t begin = 0, count;
223223
float tOffset;
224+
[[maybe_unused]] int32_t eLossSign = 0; // energy-loss sign of the TrackParCov propagations (0: from the direction, outward = loss)
224225
if constexpr (std::is_same_v<T, GPUTPCGMMergedTrack>) {
225226
count = trkX.NClusters();
226227
tOffset = trkX.GetParam().GetTOffset();
@@ -230,6 +231,7 @@ GPUd() int32_t GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov
230231
} else if constexpr (std::is_same_v<T, TrackParCovWithArgs>) {
231232
count = trkX.clusRef.getEntries();
232233
tOffset = trkX.time0;
234+
eLossSign = trkX.eLossSign;
233235
} else {
234236
static_assert("Invalid template");
235237
}
@@ -357,7 +359,7 @@ GPUd() int32_t GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov
357359
IgnoreErrors(trk.getSnp());
358360
return -1;
359361
}
360-
if (!prop->PropagateToXBxByBz(trk, x, constants::MAX_SIN_PHI_LOW)) {
362+
if (!prop->PropagateToXBxByBz(trk, x, constants::MAX_SIN_PHI_LOW, Propagator::MAX_STEP, Propagator::MatCorrType::USEMatCorrLUT, nullptr, eLossSign)) {
361363
IgnoreErrors(trk.getSnp());
362364
return -2;
363365
}
@@ -401,11 +403,13 @@ GPUd() int32_t GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov
401403
constexpr float kDeg2Rad = M_PI / 180.f;
402404
constexpr float kSectAngle = 2 * M_PI / 18.f;
403405
if (mPparam->rec.tpc.trackReferenceX <= 500) {
404-
if (prop->PropagateToXBxByBz(trk, mPparam->rec.tpc.trackReferenceX)) {
406+
// a forced energy-loss sign holds along the refit direction: the way to the reference X can run against it
407+
const int32_t eLossSignRef = (mPparam->rec.tpc.trackReferenceX > trk.getX()) == outward ? eLossSign : -eLossSign;
408+
if (prop->PropagateToXBxByBz(trk, mPparam->rec.tpc.trackReferenceX, Propagator::MAX_SIN_PHI, Propagator::MAX_STEP, Propagator::MatCorrType::USEMatCorrLUT, nullptr, eLossSignRef)) {
405409
if (CAMath::Abs(trk.getY()) > trk.getX() * CAMath::Tan(kSectAngle / 2.f)) {
406410
float newAlpha = trk.getAlpha() + CAMath::Round(CAMath::ATan2(trk.getY(), trk.getX()) / kDeg2Rad / 20.f) * kSectAngle;
407411
GPUTPCGMTrackParam::NormalizeAlpha(newAlpha);
408-
trk.rotate(newAlpha) && prop->PropagateToXBxByBz(trk, mPparam->rec.tpc.trackReferenceX);
412+
trk.rotate(newAlpha) && prop->PropagateToXBxByBz(trk, mPparam->rec.tpc.trackReferenceX, Propagator::MAX_SIN_PHI, Propagator::MAX_STEP, Propagator::MatCorrType::USEMatCorrLUT, nullptr, eLossSignRef);
409413
}
410414
}
411415
}

‎GPU/GPUTracking/Refit/GPUTrackingRefit.h‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,16 @@ class GPUTrackingRefit
7373
const o2::tpc::TrackTPCClusRef& clusRef;
7474
float time0;
7575
float* chi2;
76+
int32_t eLossSign = 0; // energy-loss sign of the TrackParCov propagations: 0 along the track parameters (loss forward), +1 gain, -1 loss
7677
};
7778
GPUd() int32_t RefitTrackAsGPU(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2 = nullptr, bool outward = false, bool resetCov = false)
7879
{
7980
TrackParCovWithArgs x{trk, clusRef, time0, chi2};
8081
return RefitTrack<TrackParCovWithArgs, GPUTPCGMTrackParam>(x, outward, resetCov);
8182
}
82-
GPUd() int32_t RefitTrackAsTrackParCov(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2 = nullptr, bool outward = false, bool resetCov = false)
83+
GPUd() int32_t RefitTrackAsTrackParCov(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2 = nullptr, bool outward = false, bool resetCov = false, int32_t eLossSign = 0)
8384
{
84-
TrackParCovWithArgs x{trk, clusRef, time0, chi2};
85+
TrackParCovWithArgs x{trk, clusRef, time0, chi2, eLossSign};
8586
return RefitTrack<TrackParCovWithArgs, o2::track::TrackParCov>(x, outward, resetCov);
8687
}
8788

0 commit comments

Comments
 (0)