Skip to content

Commit aecea1d

Browse files
committed
TRK: add fast getPredictedChi2
Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch>
1 parent 14d295c commit aecea1d

3 files changed

Lines changed: 73 additions & 9 deletions

File tree

DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ class TrackParametrizationWithError : public TrackParametrization<value_T>
114114
GPUd() void buildCombinedCovMatrix(const TrackParametrizationWithError& rhs, MatrixDSym5& cov) const;
115115
GPUd() value_t getPredictedChi2(const TrackParametrizationWithError& rhs, MatrixDSym5& covToSet) const;
116116
GPUd() value_t getPredictedChi2(const TrackParametrizationWithError& rhs) const;
117+
GPUd() value_t getPredictedChi2Fast(const TrackParametrizationWithError& rhs) const;
117118
GPUd() value_t getPredictedChi2Quiet(const TrackParametrizationWithError& rhs) const;
118119
GPUd() bool update(const TrackParametrizationWithError& rhs, const MatrixDSym5& covInv);
119120
GPUd() bool update(const TrackParametrizationWithError& rhs);

DataFormats/Reconstruction/src/TrackParametrization.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ GPUd() bool TrackParametrization<value_T>::propagateParamTo(value_t xk, value_t
364364
if (gpu::CAMath::Abs(r2) < constants::math::Almost0) {
365365
return false;
366366
}
367-
double dy2dx = (f1 + f2) / (r1 + r2);
367+
value_t dy2dx = (f1 + f2) / (r1 + r2);
368368
bool arcz = gpu::CAMath::Abs(x2r) > 0.05f;
369369
if (arcz) {
370370
// for small dx/R the linear apporximation of the arc by the segment is OK,

DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ GPUd() bool TrackParametrizationWithError<value_T>::propagateTo(value_t xk, valu
6969
}
7070
double r1pr2Inv = 1. / (r1 + r2);
7171
double dy2dx = (f1 + f2) * r1pr2Inv;
72+
const auto dy2dxF = static_cast<value_t>(dy2dx); // the parameter update does not need the double
7273
bool arcz = gpu::CAMath::Abs(x2r) > 0.05f;
7374
params_t dP{0.f};
7475
if (arcz) {
@@ -94,10 +95,10 @@ GPUd() bool TrackParametrizationWithError<value_T>::propagateTo(value_t xk, valu
9495
}
9596
dP[kZ] = this->getTgl() / crv * rot;
9697
} else {
97-
dP[kZ] = dx * (r2 + f2 * dy2dx) * this->getTgl();
98+
dP[kZ] = dx * (r2 + f2 * dy2dxF) * this->getTgl();
9899
}
99100
this->setX(xk);
100-
dP[kY] = dx * dy2dx;
101+
dP[kY] = dx * dy2dxF;
101102
dP[kSnp] = x2r;
102103

103104
this->updateParams(dP); // apply corrections
@@ -711,12 +712,12 @@ GPUd() bool TrackParametrizationWithError<value_T>::propagateTo(value_t xk, cons
711712
sintet = bt / bb;
712713
}
713714
std::array<value_t, 7> vect{costet * cosphi * vecLab[0] + costet * sinphi * vecLab[1] - sintet * vecLab[2],
714-
-sinphi * vecLab[0] + cosphi * vecLab[1],
715-
sintet * cosphi * vecLab[0] + sintet * sinphi * vecLab[1] + costet * vecLab[2],
716-
costet * cosphi * vecLab[3] + costet * sinphi * vecLab[4] - sintet * vecLab[5],
717-
-sinphi * vecLab[3] + cosphi * vecLab[4],
718-
sintet * cosphi * vecLab[3] + sintet * sinphi * vecLab[4] + costet * vecLab[5],
719-
vecLab[6]};
715+
-sinphi * vecLab[0] + cosphi * vecLab[1],
716+
sintet * cosphi * vecLab[0] + sintet * sinphi * vecLab[1] + costet * vecLab[2],
717+
costet * cosphi * vecLab[3] + costet * sinphi * vecLab[4] - sintet * vecLab[5],
718+
-sinphi * vecLab[3] + cosphi * vecLab[4],
719+
sintet * cosphi * vecLab[3] + sintet * sinphi * vecLab[4] + costet * vecLab[5],
720+
vecLab[6]};
720721

721722
// Do the helix step
722723
value_t q = this->getCharge();
@@ -1120,6 +1121,68 @@ GPUd() auto TrackParametrizationWithError<value_T>::getPredictedChi2(const Track
11201121
return getPredictedChi2(rhs, cov);
11211122
}
11221123

1124+
//______________________________________________
1125+
template <typename value_T>
1126+
GPUd() auto TrackParametrizationWithError<value_T>::getPredictedChi2Fast(const TrackParametrizationWithError<value_T>& rhs) const -> value_t
1127+
{
1128+
// get chi2 wrt other track, which must be defined at the same parameters X,alpha.
1129+
// Cheap variant for the cases where only the chi2 is needed and the inverted combined
1130+
// covariance is discarded: chi2 = d^T C^-1 d does not need the inverse, the LDL^T
1131+
// factorization of C = C_this + C_rhs plus one forward substitution suffice, at a
1132+
// fraction of the cost of the pivoted Bunch-Kaufman inversion used by getPredictedChi2().
1133+
// C is a sum of two covariance matrices, hence positive definite in any sane case. If the
1134+
// factorization does run into a non-positive pivot the combined covariance is numerically
1135+
// broken and no meaningful chi2 can be formed from it, so a rejecting value is returned:
1136+
// callers of this overload use the chi2 as a quality cut. Use getPredictedChi2() instead if
1137+
// the pivoted Bunch-Kaufman treatment of an indefinite matrix is really wanted.
1138+
1139+
if (gpu::CAMath::Abs(this->getAlpha() - rhs.getAlpha()) > o2::constants::math::Epsilon) {
1140+
LOG(error) << "The reference Alpha of the tracks differ: " << this->getAlpha() << " : " << rhs.getAlpha();
1141+
return 2.f * HugeF;
1142+
}
1143+
if (gpu::CAMath::Abs(this->getX() - rhs.getX()) > o2::constants::math::Epsilon) {
1144+
LOG(error) << "The reference X of the tracks differ: " << this->getX() << " : " << rhs.getX();
1145+
return 2.f * HugeF;
1146+
}
1147+
MatrixDSym5 cov; // perform matrix operations in double!
1148+
buildCombinedCovMatrix(rhs, cov);
1149+
1150+
// Factorize cov = L * D * L^T with L unit lower triangular. The strictly lower triangle of
1151+
// lmat holds L, its strictly upper triangle holds the transpose of L * D, so that the inner
1152+
// products below need no extra multiplication by D. dInv holds the inverted diagonal of D.
1153+
double lmat[kNParams][kNParams], dInv[kNParams];
1154+
for (int j = 0; j < kNParams; j++) {
1155+
double djj = cov(j, j);
1156+
for (int k = 0; k < j; k++) {
1157+
djj -= lmat[j][k] * lmat[k][j];
1158+
}
1159+
if (!(djj > 0.)) { // not positive definite (or NaN): the combined covariance is broken
1160+
return 2.f * HugeF;
1161+
}
1162+
dInv[j] = 1. / djj;
1163+
for (int i = j + 1; i < kNParams; i++) {
1164+
double s = cov(i, j);
1165+
for (int k = 0; k < j; k++) {
1166+
s -= lmat[i][k] * lmat[k][j];
1167+
}
1168+
lmat[i][j] = s * dInv[j];
1169+
lmat[j][i] = s;
1170+
}
1171+
}
1172+
1173+
// chi2 = d^T C^-1 d = sum_i y_i^2 / D_i with y from the forward substitution L y = d
1174+
double chi2 = 0., y[kNParams];
1175+
for (int i = 0; i < kNParams; i++) {
1176+
double s = double(this->getParam(i)) - double(rhs.getParam(i));
1177+
for (int k = 0; k < i; k++) {
1178+
s -= lmat[i][k] * y[k];
1179+
}
1180+
y[i] = s;
1181+
chi2 += s * s * dInv[i];
1182+
}
1183+
return chi2;
1184+
}
1185+
11231186
//______________________________________________
11241187
template <typename value_T>
11251188
GPUd() void TrackParametrizationWithError<value_T>::buildCombinedCovMatrix(const TrackParametrizationWithError<value_T>& rhs, MatrixDSym5& cov) const

0 commit comments

Comments
 (0)