Skip to content

Commit 4c3d33e

Browse files
shahor02chiarazampolli
authored andcommitted
account for TPC/ITS PID difference in propagation to ref.X
1 parent f4f68f2 commit 4c3d33e

3 files changed

Lines changed: 114 additions & 33 deletions

File tree

Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ enum TrackRejFlag : int {
113113
RejectOnTgl,
114114
RejectOnQ2Pt,
115115
RejectOnChi2,
116-
NSigmaShift = 10
116+
NSigmaShift = 10,
117+
RejectoOnPIDCorr = 20
117118
};
118119

119120
///< TPC track parameters propagated to reference X, with time bracket and index of
@@ -139,7 +140,7 @@ struct TrackLocTPC : public o2::track::TrackParCov {
139140
return constraint == Constrained ? 0. : (constraint == ASide ? dt : -dt);
140141
}
141142

142-
ClassDefNV(TrackLocTPC, 1);
143+
ClassDefNV(TrackLocTPC, 2);
143144
};
144145

145146
///< ITS track outward parameters propagated to reference X, with time bracket and index of
@@ -151,6 +152,8 @@ struct TrackLocITS : public o2::track::TrackParCov {
151152
int sourceID = 0; ///< track origin id
152153
int roFrame = MinusOne; ///< ITS readout frame assigned to this track
153154
int matchID = MinusOne; ///< entry (non if MinusOne) of its matchCand struct in the mMatchesITS
155+
float xrho = 0; ///< x*rho seen during propagation to reference X (as pion)
156+
float dL = 0; ///< distance integrated during propagation to reference X (as pion)
154157
bool hasCloneBefore() const { return getUserField() & CloneBefore; }
155158
bool hasCloneAfter() const { return getUserField() & CloneAfter; }
156159
int getCloneShift() const { return hasCloneBefore() ? -1 : (hasCloneAfter() ? 1 : 0); }
@@ -479,8 +482,8 @@ class MatchTPCITS
479482

480483
int compareTPCITSTracks(const TrackLocITS& tITS, const TrackLocTPC& tTPC, float& chi2) const;
481484
float getPredictedChi2NoZ(const o2::track::TrackParCov& trITS, const o2::track::TrackParCov& trTPC) const;
482-
bool propagateToRefX(o2::track::TrackParCov& trc);
483-
void addLastTrackCloneForNeighbourSector(int sector);
485+
bool propagateToRefX(o2::track::TrackParCov& trc, o2::track::TrackLTIntegral* lti = nullptr);
486+
void addLastTrackCloneForNeighbourSector(int sector, o2::track::TrackLTIntegral* trackLTInt = nullptr);
484487

485488
///------------------- manipulations with matches records ----------------------
486489
bool registerMatchRecordTPC(int iITS, int iTPC, float chi2, int candIC = MinusOne);
@@ -575,7 +578,7 @@ class MatchTPCITS
575578

576579
float YMaxAtXMatchingRef = 999.; ///< max Y in the sector at reference X
577580

578-
float mSectEdgeMargin2 = 0.; ///< crude check if ITS track should be matched also in neighbouring sector
581+
float mSectEdgeMargin = 0.; ///< crude check if ITS track should be matched also in neighbouring sector
579582

580583
///< safety margin in TPC time bins when estimating TPC track tMin and tMax from
581584
///< assigned time0 and its track Z position (converted from mTPCTimeEdgeZSafeMargin)

Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITSParams.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ struct MatchTPCITSParams : public o2::conf::ConfigurableParamHelper<MatchTPCITSP
4141
float crudeNSigma2Cut[o2::track::kNParams] = {49.f, 49.f, 49.f, 49.f, 49.f};
4242

4343
float XMatchingRef = 70.f; ///< reference radius to propagate tracks for matching
44+
float ITSStepEffFraction = 0.5; //< when correcting the ITS tracks for parameters difference between default PION and other PID hipothesis, use this fraction of propagated distance
45+
float minBetaGammaForPIDDiff = 1.2; // account for difference between ITS and TPC PIDs used in propagation if TPC beta*gamma is below this
4446

4547
float minTPCTrackR = 50.; ///< cut on minimal TPC tracks radius to consider for matching, 666*pt_gev*B_kgaus/5
4648
float minITSTrackR = 50.; ///< cut on minimal ITS tracks radius to consider for matching, 666*pt_gev*B_kgaus/5

Detectors/GlobalTracking/src/MatchTPCITS.cxx

Lines changed: 104 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ void MatchTPCITS::init()
220220
// make sure T2GRot matrices are loaded into ITS geometry helper
221221
o2::its::GeometryTGeo::Instance()->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot) | o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L));
222222

223-
mSectEdgeMargin2 = mParams->crudeAbsDiffCut[o2::track::kY] * mParams->crudeAbsDiffCut[o2::track::kY]; ///< precalculated ^2
223+
mSectEdgeMargin = mParams->crudeAbsDiffCut[o2::track::kY] / std::sqrt(Cos70I2);
224224

225225
#ifdef _ALLOW_DEBUG_TREES_
226226
// debug streamer
@@ -446,7 +446,6 @@ void MatchTPCITS::addTPCSeed(const o2::track::TrackParCov& _tr, float t0, float
446446
if (mMCTruthON) {
447447
mTPCLblWork.emplace_back(mTPCTrkLabels[tpcID]);
448448
}
449-
450449
// cache work track index
451450
mTPCSectIndexCache[o2::math_utils::angle2Sector(trc.getAlpha())].push_back(mTPCWork.size() - 1);
452451
}
@@ -638,6 +637,8 @@ bool MatchTPCITS::prepareITSData()
638637
}
639638
long nHBF = o2::base::GRPGeomHelper::getNHBFPerTF();
640639
long maxBCs = nHBF * long(o2::constants::lhc::LHCMaxBunches);
640+
o2::track::TrackLTIntegral trackLTInt;
641+
trackLTInt.setTimeNotNeeded();
641642

642643
for (int irof = 0; irof < nROFs; irof++) {
643644
const auto& rofRec = mITSTrackROFRec[irof];
@@ -685,10 +686,14 @@ bool MatchTPCITS::prepareITSData()
685686
continue;
686687
}
687688
// make sure the track is at the ref. radius
688-
if (!propagateToRefX(trc)) {
689+
trackLTInt.clearFast();
690+
if (!propagateToRefX(trc, &trackLTInt)) {
689691
mITSWork.pop_back(); // discard failed track
690692
continue; // add to cache only those ITS tracks which reached ref.X and have reasonable snp
691693
}
694+
trc.xrho = trackLTInt.getXRho(); // we collect seen x*rho and distance to the reference X for further PID correcrions
695+
trc.dL = trackLTInt.getL();
696+
692697
if (mMCTruthON) {
693698
mITSLblWork.emplace_back(mITSTrkLabels[it]);
694699
}
@@ -702,19 +707,16 @@ bool MatchTPCITS::prepareITSData()
702707
// when propagated to Xr (in this neighbouring sector) and the edge will be (neglecting the curvature)
703708
// [(Xr*tg(10)-Yr)/(tgPhir+tg70)]^2 / cos(70)^2 // for the next sector
704709
// [(Xr*tg(10)+Yr)/(tgPhir-tg70)]^2 / cos(70)^2 // for the prev sector
705-
// Distances to the sector edges in neighbourings sectors (at Xref in theit proper frames)
710+
// Distances to the sector edges in neighbourings sectors (at Xref in their proper frames)
706711
float trcY = trc.getY(), tgp = trc.getSnp();
707712
tgp /= std::sqrt((1.f - tgp) * (1.f + tgp)); // tan of track direction XY
708713

709-
// sector up
710-
float dy2Up = (YMaxAtXMatchingRef - trcY) / (tgp + Tan70);
711-
if ((dy2Up * dy2Up * Cos70I2) < mSectEdgeMargin2) { // need to check this track for matching in sector up
712-
addLastTrackCloneForNeighbourSector(sector < (o2::constants::math::NSectors - 1) ? sector + 1 : 0);
713-
}
714-
// sector down
715-
float dy2Dn = (YMaxAtXMatchingRef + trcY) / (tgp - Tan70);
716-
if ((dy2Dn * dy2Dn * Cos70I2) < mSectEdgeMargin2) { // need to check this track for matching in sector down
717-
addLastTrackCloneForNeighbourSector(sector > 1 ? sector - 1 : o2::constants::math::NSectors - 1);
714+
float dyUpDn[2] = {std::abs((YMaxAtXMatchingRef - trcY) / (tgp + Tan70)), std::abs((YMaxAtXMatchingRef + trcY) / (tgp - Tan70))}; // sector up, down edge distances
715+
// we do the cloning for closest edge only
716+
int sel = dyUpDn[0] < dyUpDn[1] ? 0 : 1;
717+
if (dyUpDn[sel] < mSectEdgeMargin) { // need to check this track for matching in sector up or down
718+
int sectNeib = sel == 0 ? (sector < (o2::constants::math::NSectors - 1) ? sector + 1 : 0) : (sector > 1 ? sector - 1 : o2::constants::math::NSectors - 1);
719+
addLastTrackCloneForNeighbourSector(sectNeib, &trackLTInt);
718720
}
719721
}
720722
}
@@ -1014,7 +1016,7 @@ bool MatchTPCITS::registerMatchRecordTPC(int iITS, int iTPC, float chi2, int can
10141016
}
10151017

10161018
//______________________________________________
1017-
void MatchTPCITS::registerMatchRecordITS(int iITS, int iTPC, float chi2, int candIC)
1019+
void MatchTPCITS::registerMatchRecordITS(const int iITS, int iTPC, float chi2, int candIC)
10181020
{
10191021
///< register TPC match in ITS tracks match records, ordering them in quality
10201022
auto& tITS = mITSWork[iITS];
@@ -1068,7 +1070,26 @@ int MatchTPCITS::compareTPCITSTracks(const TrackLocITS& tITS, const TrackLocTPC&
10681070
if ((rejFlag = roughCheckDif(diff, mParams->crudeNSigma2Cut[o2::track::kTgl], RejectOnTgl + NSigmaShift))) {
10691071
return rejFlag;
10701072
}
1071-
diff = tITS.getParam(o2::track::kY) - tTPC.getParam(o2::track::kY);
1073+
// do we need to account for different PID hypotheses used for ITS and TPC tracks propagation to ref. X?
1074+
bool testOtherPID = false;
1075+
float itsParam[5] = {tITS.getY(), tITS.getZ(), tITS.getSnp(), tITS.getTgl(), tITS.getQ2Pt()};
1076+
if (tTPC.getPID() > tITS.getPID() && tITS.dL > 0.f && tTPC.getP2() / tTPC.getPID().getMass2() < mParams->minBetaGammaForPIDDiff) {
1077+
o2::track::TrackPar tPID(mITSTracksArray[tITS.sourceID].getParamOut()); // clone original ITS track at highest update point
1078+
tPID.setPID(tTPC.getPID(), true);
1079+
if (!tPID.correctForELoss(tITS.xrho)) {
1080+
return RejectoOnPIDCorr;
1081+
}
1082+
float dCurv = (tPID.getQ2Pt() - tITS.getQ2Pt()) * mBz * o2::constants::math::B2C, dLEff = tITS.dL * mParams->ITSStepEffFraction, dCurvL = dCurv * dLEff;
1083+
itsParam[o2::track::kQ2Pt] = tPID.getQ2Pt();
1084+
itsParam[o2::track::kSnp] += dCurvL;
1085+
if (std::abs(itsParam[o2::track::kSnp]) >= 1.) {
1086+
itsParam[o2::track::kSnp] = std::copysign(0.99, itsParam[o2::track::kSnp]);
1087+
}
1088+
itsParam[o2::track::kY] += dCurvL * dLEff * 0.5;
1089+
testOtherPID = true;
1090+
}
1091+
1092+
diff = itsParam[o2::track::kY] - tTPC.getParam(o2::track::kY);
10721093
if ((rejFlag = roughCheckDif(diff, mParams->crudeAbsDiffCut[o2::track::kY], RejectOnY))) {
10731094
return rejFlag;
10741095
}
@@ -1078,7 +1099,7 @@ int MatchTPCITS::compareTPCITSTracks(const TrackLocITS& tITS, const TrackLocTPC&
10781099
}
10791100

10801101
if (tTPC.constraint == TrackLocTPC::Constrained) { // in continuous only constrained tracks can be compared in Z
1081-
diff = tITS.getParam(o2::track::kZ) - tTPC.getParam(o2::track::kZ);
1102+
diff = itsParam[o2::track::kZ] - tTPC.getParam(o2::track::kZ);
10821103
if ((rejFlag = roughCheckDif(diff, mParams->crudeAbsDiffCut[o2::track::kZ], RejectOnZ))) {
10831104
return rejFlag;
10841105
}
@@ -1088,7 +1109,7 @@ int MatchTPCITS::compareTPCITSTracks(const TrackLocITS& tITS, const TrackLocTPC&
10881109
}
10891110
}
10901111

1091-
diff = tITS.getParam(o2::track::kSnp) - tTPC.getParam(o2::track::kSnp);
1112+
diff = itsParam[o2::track::kSnp] - tTPC.getParam(o2::track::kSnp);
10921113
if ((rejFlag = roughCheckDif(diff, mParams->crudeAbsDiffCut[o2::track::kSnp], RejectOnSnp))) {
10931114
return rejFlag;
10941115
}
@@ -1097,17 +1118,26 @@ int MatchTPCITS::compareTPCITSTracks(const TrackLocITS& tITS, const TrackLocTPC&
10971118
return rejFlag;
10981119
}
10991120

1100-
diff = tITS.getParam(o2::track::kQ2Pt) - tTPC.getParam(o2::track::kQ2Pt);
1121+
diff = itsParam[o2::track::kQ2Pt] - tTPC.getParam(o2::track::kQ2Pt);
11011122
if ((rejFlag = roughCheckDif(diff, mParams->crudeAbsDiffCut[o2::track::kQ2Pt], RejectOnQ2Pt))) {
11021123
return rejFlag;
11031124
}
11041125
diff *= diff / (tITS.getDiagError2(o2::track::kQ2Pt) + tTPC.getDiagError2(o2::track::kQ2Pt));
11051126
if ((rejFlag = roughCheckDif(diff, mParams->crudeNSigma2Cut[o2::track::kQ2Pt], RejectOnQ2Pt + NSigmaShift))) {
11061127
return rejFlag;
11071128
}
1108-
// calculate mutual chi2 excluding Z in continuos mode
1109-
chi2 = getPredictedChi2NoZ(tITS, tTPC);
1110-
if (chi2 > mParams->cutMatchingChi2 || chi2 < 0.) { // sometime due to the numerical stability the chi2 is negative, reject it.
1129+
// calculate mutual chi2 excluding Z in continuous mode
1130+
if (testOtherPID) { // temporarily substitute pion params by alternative ones
1131+
auto tITSAlt = tITS;
1132+
tITSAlt.setPID(tTPC.getPID());
1133+
tITSAlt.setParam(itsParam[o2::track::kY], o2::track::kY);
1134+
tITSAlt.setParam(itsParam[o2::track::kSnp], o2::track::kSnp);
1135+
tITSAlt.setParam(itsParam[o2::track::kQ2Pt], o2::track::kQ2Pt);
1136+
chi2 = getPredictedChi2NoZ(tITSAlt, tTPC);
1137+
} else {
1138+
chi2 = getPredictedChi2NoZ(tITS, tTPC);
1139+
}
1140+
if (chi2 > mParams->cutMatchingChi2 || chi2 < 0.) { // sometimes due to the numerical stability the chi2 is negative, reject it.
11111141
return RejectOnChi2;
11121142
}
11131143

@@ -1206,19 +1236,23 @@ float MatchTPCITS::getPredictedChi2NoZ(const o2::track::TrackParCov& trITS, cons
12061236
}
12071237

12081238
//______________________________________________
1209-
void MatchTPCITS::addLastTrackCloneForNeighbourSector(int sector)
1239+
void MatchTPCITS::addLastTrackCloneForNeighbourSector(int sector, o2::track::TrackLTIntegral* trackLTInt)
12101240
{
12111241
// add clone of the src ITS track cache, propagate it to ref.X in requested sector
12121242
// and register its index in the sector cache. Used for ITS tracks which are so close
12131243
// to their setctor edge that their matching should be checked also in the neighbouring sector
12141244
mITSWork.push_back(mITSWork.back()); // clone the last track defined in given sector
12151245
auto& trc = mITSWork.back();
12161246
if (trc.rotate(o2::math_utils::sector2Angle(sector)) &&
1217-
o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, mParams->XMatchingRef, MaxSnp, 2., MatCorrType::USEMatCorrNONE)) {
1247+
o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, mParams->XMatchingRef, MaxSnp, 2., mUseMatCorrFlag, trackLTInt)) {
12181248
// TODO: use faster prop here, no 3d field, materials
12191249
mITSSectIndexCache[sector].push_back(mITSWork.size() - 1); // register track CLONE
12201250
// flag clone
12211251
mITSWork.back().setCloneBefore();
1252+
if (trackLTInt) {
1253+
mITSWork.back().xrho = trackLTInt->getXRho(); // we collect seen x*rho and distance to the reference X for further PID correcrions
1254+
mITSWork.back().dL = trackLTInt->getL();
1255+
}
12221256
mITSWork[mITSWork.size() - 2].setCloneAfter();
12231257
if (mMCTruthON) {
12241258
mITSLblWork.emplace_back(mITSTrkLabels[trc.sourceID]);
@@ -1229,14 +1263,14 @@ void MatchTPCITS::addLastTrackCloneForNeighbourSector(int sector)
12291263
}
12301264

12311265
//______________________________________________
1232-
bool MatchTPCITS::propagateToRefX(o2::track::TrackParCov& trc)
1266+
bool MatchTPCITS::propagateToRefX(o2::track::TrackParCov& trc, o2::track::TrackLTIntegral* lti)
12331267
{
12341268
// propagate track to matching reference X, making sure its assigned alpha
12351269
// is consistent with TPC sector
12361270
bool refReached = false;
12371271
refReached = mParams->XMatchingRef < 10.; // RS: tmp, to cover XMatchingRef~0
12381272
int trialsLeft = 2;
1239-
while (o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, mParams->XMatchingRef, MaxSnp, 2., mUseMatCorrFlag)) {
1273+
while (o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, mParams->XMatchingRef, MaxSnp, 2., mUseMatCorrFlag, lti)) {
12401274
if (refReached) {
12411275
break;
12421276
}
@@ -1421,10 +1455,30 @@ bool MatchTPCITS::refitTrackTPCITS(int iTPC, int& iITS, pmr::vector<o2::dataform
14211455
maxStep, MatCorrType::USEMatCorrNONE, nullptr, &trfit.getLTIntegralOut())) {
14221456
LOG(error) << "LTOF integral might be incorrect";
14231457
}
1458+
auto& tofL = trfit.getLTIntegralOut(); // this is TL integral calculated from the RefX to the DCA to the beamline, invert material integrals for outward propagation
1459+
tofL.setX2X0(-tofL.getX2X0());
1460+
tofL.setXRho(-tofL.getXRho());
14241461

14251462
// outward refit
1463+
#ifdef _ALLOW_DEBUG_TREES_
1464+
o2::track::TrackParCov itsRefAltPID;
1465+
#endif
14261466
auto& tracOut = trfit.getParamOut(); // this is a clone of ITS outward track already at the matching reference X
1427-
auto& tofL = trfit.getLTIntegralOut();
1467+
if (tTPC.getPID() > tITS.getPID() && tTPC.getP2() / tTPC.getPID().getMass2() < mParams->minBetaGammaForPIDDiff) {
1468+
// in case the TPC track hypothesis is not pion, we redo the outward propagation to ref.x with TPC PID
1469+
tracOut = mITSTracksArray[tITS.sourceID].getParamOut();
1470+
tracOut.setPID(tTPC.getPID(), true);
1471+
if (!tracOut.rotate(tTPC.getAlpha()) || !o2::base::Propagator::Instance()->PropagateToXBxByBz(tracOut, mParams->XMatchingRef, MaxSnp, 2., mUseMatCorrFlag)) {
1472+
LOGP(debug, "Failed to rotate ITSouter with imposed PID to TPC alpha {} or propagate to X={}: {:s}", tTPC.getAlpha(), mParams->XMatchingRef, tracOut.asString());
1473+
matchedTracks.pop_back(); // destroy failed track
1474+
return false;
1475+
}
1476+
#ifdef _ALLOW_DEBUG_TREES_
1477+
if (mDBGOut) {
1478+
itsRefAltPID = tracOut;
1479+
}
1480+
#endif
1481+
}
14281482
{
14291483
float xtogo = 0;
14301484
if (!tracOut.getXatLabR(o2::constants::geom::XTPCInnerRef, xtogo, mBz, o2::track::DirOutward) ||
@@ -1509,14 +1563,36 @@ bool MatchTPCITS::refitTrackTPCITS(int iTPC, int& iITS, pmr::vector<o2::dataform
15091563
}
15101564
#ifdef _ALLOW_DEBUG_TREES_
15111565
if (mDBGOut) {
1566+
o2::track::TrackPar itsRefPIDCorr(tITS);
1567+
itsRefPIDCorr.setX(0);
1568+
if (tTPC.getPID() > tITS.getPID() && tITS.dL > 0.f && tTPC.getP2() / tTPC.getPID().getMass2() < mParams->minBetaGammaForPIDDiff) {
1569+
itsRefPIDCorr = mITSTracksArray[tITS.sourceID].getParamOut(); // clone original ITS track at highest update point
1570+
itsRefPIDCorr.setPID(tTPC.getPID(), true);
1571+
if (!itsRefPIDCorr.correctForELoss(tITS.xrho)) {
1572+
itsRefPIDCorr.setX(-10);
1573+
} else {
1574+
float q2ptPID = itsRefPIDCorr.getQ2Pt();
1575+
float dCurv = (q2ptPID - tITS.getQ2Pt()) * mBz * o2::constants::math::B2C, dLEff = tITS.dL * mParams->ITSStepEffFraction, dCurvL = dCurv * dLEff;
1576+
itsRefPIDCorr = tITS;
1577+
itsRefPIDCorr.setPID(tTPC.getPID(), true);
1578+
itsRefPIDCorr.setQ2Pt(q2ptPID);
1579+
auto snp = tITS.getSnp() + dCurvL;
1580+
if (std::abs(snp) >= 1.) {
1581+
snp = std::copysign(0.99, snp);
1582+
}
1583+
itsRefPIDCorr.setSnp(snp);
1584+
itsRefPIDCorr.setY(tITS.getY() + dCurvL * dLEff * 0.5);
1585+
}
1586+
}
15121587
(*mDBGOut) << "refit"
1513-
<< "tpcOrig=" << mTPCTracksArray[tTPC.sourceID] << "itsOrig=" << itsTrOrig << "itsRef=" << tITS << "tpcRef=" << tTPC << "matchRefit=" << trfit << "timeCorr=" << timeC << "dTimeFT0=" << minDiffFT0 << "dTimes=" << dtimes;
1588+
<< "tpcOrig=" << mTPCTracksArray[tTPC.sourceID] << "itsOrig=" << itsTrOrig << "itsRef=" << tITS << "tpcRef=" << tTPC << "matchRefit=" << trfit << "timeCorr=" << timeC << "dTimeFT0=" << minDiffFT0 << "dTimes=" << dtimes
1589+
<< "itsRefAltPID=" << itsRefAltPID << "itsRefPIDCorr=" << itsRefPIDCorr;
15141590
if (mMCTruthON) {
15151591
(*mDBGOut) << "refit"
15161592
<< "itsLbl=" << mITSLblWork[iITS] << "tpcLbl=" << mTPCLblWork[iTPC];
15171593
}
15181594
(*mDBGOut) << "refit"
1519-
<< "\n";
1595+
<< "tf=" << mTFCount << "\n";
15201596
}
15211597
#endif
15221598

0 commit comments

Comments
 (0)