@@ -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// ______________________________________________
11241187template <typename value_T>
11251188GPUd () void TrackParametrizationWithError<value_T>::buildCombinedCovMatrix(const TrackParametrizationWithError<value_T>& rhs, MatrixDSym5& cov) const
0 commit comments