@@ -59,6 +59,10 @@ struct TrackCovI {
5959 sxy = -(syy * dydx + syz * dzdx);
6060 sxz = -(syz * dydx + szz * dzdx);
6161 sxx = dydx * dydx * syy + 2 .f * dydx * dzdx * syz + dzdx * dzdx * szz;
62+ // The matrix is degenerate by construction, regularize sxx term to preserve the original YZ block exactly
63+ constexpr float XRegErrFactor = 10 .f ;
64+ const float sigmaX2 = cyy * XRegErrFactor;
65+ sxx += 1 .f / sigmaX2;
6266 return res;
6367 }
6468};
@@ -220,6 +224,7 @@ class DCAFitterN
220224 // /< recalculate PCA as a cov-matrix weighted mean, even if absDCA method was used
221225 GPUd () bool recalculatePCAWithErrors (int cand = 0 );
222226
227+ GPUd () double calcCollinearInflation (int cand) const ;
223228 GPUd () MatSym3D calcPCACovMatrix (int cand = 0 ) const ;
224229
225230 std::array<float , 6 > calcPCACovMatrixFlat (int cand = 0 ) const
@@ -385,9 +390,10 @@ class DCAFitterN
385390 std::array<int , MAXHYP > mNIters ; // number of iterations for each seed
386391 std::array<bool , MAXHYP > mTrPropDone {}; // Flag that the tracks are fully propagated to PCA
387392 std::array<bool , MAXHYP > mPropFailed {}; // Flag that some propagation failed for this PCA candidate
388- LogLogThrottler mLoggerBadCov {};
389- LogLogThrottler mLoggerBadInv {};
390- LogLogThrottler mLoggerBadProp {};
393+ mutable LogLogThrottler mLoggerBadCov {};
394+ mutable LogLogThrottler mLoggerBadInv {};
395+ mutable LogLogThrottler mLoggerBadProp {};
396+ mutable LogLogThrottler mLoggerBadPCACov {};
391397 MatSym3D mWeightInv ; // inverse weight of single track, [sum{M^T E M}]^-1 in EQ.T
392398 std::array<int , MAXHYP > mOrder {0 };
393399 int mCurHyp = 0 ;
@@ -800,6 +806,50 @@ GPUd() void DCAFitterN<N, Args...>::calcPCANoErr()
800806 pca[2 ] *= NInv;
801807}
802808
809+ // ___________________________________________________________________
810+ template <int N, typename ... Args>
811+ GPUd () double DCAFitterN<N, Args...>::calcCollinearInflation(int cand) const
812+ {
813+ std::array<std::array<double , 3 >, N> u{};
814+ int nu = 0 ;
815+
816+ for (int i = 0 ; i < N; ++i) {
817+ std::array<float , 3 > p{};
818+ if (!getTrack (i, cand).getPxPyPzGlo (p)) {
819+ continue ;
820+ }
821+ const double p2 = p[0 ] * p[0 ] + p[1 ] * p[1 ] + p[2 ] * p[2 ];
822+ if (p2 <= 0 .) {
823+ continue ;
824+ }
825+ const double pI = 1 . / std::sqrt (p2);
826+ u[nu++] = {p[0 ] * pI, p[1 ] * pI, p[2 ] * pI};
827+ }
828+
829+ if (nu < 2 ) {
830+ return 1 .;
831+ }
832+
833+ double sin2Mean = 0 .;
834+ int npairs = 0 ;
835+ for (int i = 0 ; i < nu; ++i) {
836+ for (int j = i + 1 ; j < nu; ++j) {
837+ double cij = u[i][0 ] * u[j][0 ] + u[i][1 ] * u[j][1 ] + u[i][2 ] * u[j][2 ];
838+ cij = std::clamp (cij, -1 ., 1 .);
839+ sin2Mean += std::max (0 ., 1 . - cij * cij);
840+ ++npairs;
841+ }
842+ }
843+ sin2Mean /= npairs;
844+
845+ constexpr double Sin2Ref = 1 .e -5 ;
846+ constexpr double MaxInflation = 1 .e4 ;
847+ if (sin2Mean <= 0 .) {
848+ return MaxInflation;
849+ }
850+ return sin2Mean < Sin2Ref ? std::min (MaxInflation, Sin2Ref / sin2Mean) : 1 .;
851+ }
852+
803853// ___________________________________________________________________
804854template <int N, typename ... Args>
805855GPUd () o2::math_utils::SMatrix<double , 3 , 3 , o2::math_utils::MatRepSym<double , 3 >> DCAFitterN<N, Args...>::calcPCACovMatrix(int cand) const
@@ -829,14 +879,34 @@ GPUd() o2::math_utils::SMatrix<double, 3, 3, o2::math_utils::MatRepSym<double, 3
829879 arrmat[YZ ] += taux.s * tcov.sxz + taux.c * tcov.syz ;
830880 arrmat[ZZ ] += tcov.szz ;
831881 }
832- if (info.Invert ()) {
833- return info;
882+ const double maxDiag = o2::gpu::GPUCommonMath::Max (o2::gpu::GPUCommonMath::Max (info (0 , 0 ), info (1 , 1 )), info (2 , 2 ));
883+ const double det2 = info (0 , 0 ) * info (1 , 1 ) - info (1 , 0 ) * info (1 , 0 );
884+ const double det3 = info (0 , 0 ) * (info (1 , 1 ) * info (2 , 2 ) - info (2 , 1 ) * info (2 , 1 )) -
885+ info (1 , 0 ) * (info (1 , 0 ) * info (2 , 2 ) - info (2 , 1 ) * info (2 , 0 )) +
886+ info (2 , 0 ) * (info (1 , 0 ) * info (2 , 1 ) - info (1 , 1 ) * info (2 , 0 ));
887+ constexpr double MinRelDet = 1 .e -12 ;
888+ constexpr double InflateRelDet = 1 .e -6 ;
889+ constexpr double MaxInflation = 1 .e4 ;
890+ const bool isWellConditionedInfo = maxDiag > 0 . && info (0 , 0 ) > 0 . && det2 > 0 . && det3 > MinRelDet * maxDiag * maxDiag * maxDiag;
891+ if (isWellConditionedInfo) {
892+ auto cov = info;
893+ if (cov.Invert () && cov (0 , 0 ) > 0 . && cov (1 , 1 ) > 0 . && cov (2 , 2 ) > 0 .) {
894+ // if (mIsCollinear) {
895+ // cov *= calcCollinearInflation(cand);
896+ // }
897+ return cov;
898+ }
899+ }
900+ if (mLoggerBadPCACov .needToLog ()) {
901+ printf (" fitter %d: error (%ld muted): override ill-conditioned PCACovMatrix by dummy matrix" , mFitterID , mLoggerBadPCACov .evCount );
834902 }
835- // Fall back on identity diagonal matrix with 1 cm error.
903+ // Fall back on a deliberately loose vertex covariance. Returning a tight
904+ // identity covariance for a singular or ill-conditioned information matrix
905+ // would shrink the uncertainty in the weakly constrained direction.
836906 memset (arrmat, 0 , sizeof (info));
837- info (0 , 0 ) = 1 .;
838- info (1 , 1 ) = 1 .;
839- info (2 , 2 ) = 1 .;
907+ info (0 , 0 ) = 4 .;
908+ info (1 , 1 ) = 4 .;
909+ info (2 , 2 ) = 4 .;
840910 return info;
841911}
842912
@@ -900,6 +970,15 @@ GPUd() bool DCAFitterN<N, Args...>::correctTracks(const VecND& corrX)
900970 // constant-Bz transport here: Newton corrections are small, but the track
901971 // state must stay synchronized with mTrPos for the next derivative update.
902972 for (int i = N; i--;) {
973+ /*
974+ // Updating only mTrPos by Taylor expansion leaves mCandTr at the previous X,
975+ // leaving calcTrackDerivatives() insensitive to the update. Use full fast propagation instead.
976+ const auto& trDer = mTrDer[mCurHyp][i];
977+ auto dx2h = 0.5 * corrX[i] * corrX[i];
978+ mTrPos[mCurHyp][i][0] -= corrX[i];
979+ mTrPos[mCurHyp][i][1] -= trDer.dydx * corrX[i] - dx2h * trDer.d2ydx2;
980+ mTrPos[mCurHyp][i][2] -= trDer.dzdx * corrX[i] - dx2h * trDer.d2zdx2;
981+ */
903982 auto & trc = mCandTr [mCurHyp ][i];
904983 const float x = static_cast <float >(mTrPos [mCurHyp ][i][0 ] - corrX[i]);
905984 const bool propagated = mUseAbsDCA ? trc.propagateParamTo (x, mBz ) : trc.propagateTo (x, mBz );
@@ -1291,9 +1370,9 @@ GPUdi() bool DCAFitterN<N, Args...>::propagateParamToX(o2::track::TrackPar& t, f
12911370 mPropFailed [mCurHyp ] = true ;
12921371 if (mLoggerBadProp .needToLog ()) {
12931372#ifndef GPUCA_GPUCODE
1294- printf (" fitter %d: error (%ld muted): propagation failed for %s\n " , mFitterID , mLoggerBadProp .evCount , t.asString ().c_str ());
1373+ printf (" fitter %d: error (%ld muted): propagation to %.4f failed for %s\n " , mFitterID , mLoggerBadProp .evCount , x , t.asString ().c_str ());
12951374#else
1296- printf (" fitter %d: error (%ld muted): propagation failed\n " , mFitterID , mLoggerBadProp .evCount );
1375+ printf (" fitter %d: error (%ld muted): propagation to %.4f failed\n " , mFitterID , mLoggerBadProp .evCount , x );
12971376#endif
12981377 }
12991378 }
@@ -1317,9 +1396,9 @@ GPUdi() bool DCAFitterN<N, Args...>::propagateToX(o2::track::TrackParCov& t, flo
13171396 mPropFailed [mCurHyp ] = true ;
13181397 if (mLoggerBadProp .needToLog ()) {
13191398#ifndef GPUCA_GPUCODE
1320- printf (" fitter %d: error (%ld muted): propagation failed for %s\n " , mFitterID , mLoggerBadProp .evCount , t.asString ().c_str ());
1399+ printf (" fitter %d: error (%ld muted): propagation to %.4f failed for %s\n " , mFitterID , mLoggerBadProp .evCount , x , t.asString ().c_str ());
13211400#else
1322- printf (" fitter %d: error (%ld muted): propagation failed\n " , mFitterID , mLoggerBadProp .evCount );
1401+ printf (" fitter %d: error (%ld muted): propagation to %.4f failed\n " , mFitterID , mLoggerBadProp .evCount , x );
13231402#endif
13241403 }
13251404 }
0 commit comments