@@ -118,10 +118,26 @@ class DCAFitterN
118118 using ArrTrPos = o2::gpu::gpustd::array<Vec3D, N>; // container of Track positions
119119
120120 public:
121- enum BadCovPolicy { // if encountering non-positive defined cov. matrix, the choice is:
122- Discard = 0 , // stop evaluation
123- Override = 1 , // override correlation coef. to have cov.matrix pos.def and continue
124- OverrideAndFlag = 2 // override correlation coef. to have cov.matrix pos.def, set mPropFailed flag of corresponding candidate to true and continue (up to the user to check the flag)
121+ enum BadCovPolicy : uint8_t { // if encountering non-positive defined cov. matrix, the choice is:
122+ Discard = 0 , // stop evaluation
123+ Override = 1 , // override correlation coef. to have cov.matrix pos.def and continue
124+ OverrideAndFlag = 2 // override correlation coef. to have cov.matrix pos.def, set mPropFailed flag of corresponding candidate to true and continue (up to the user to check the flag)
125+ };
126+
127+ enum FitStatus : uint8_t { // fit status of crossing hypothesis
128+ None = 0 , // no status set
129+ Converged = 1 , // fit converged
130+ NoCrossing = 2 , // no reasaonable crossing was found
131+ RejRadius = 3 , // radius of crossing was not acceptable
132+ RejTrackX = 4 , // one candidate track x was below the mimimum required radius
133+ RejTrackRoughZ = 5 , // rejected by rough cut on tracks Z difference
134+ RejChi2Max = 6 , // rejected by maximum chi2 cut
135+ FailProp = 7 , // propagation of at least prong to PCA failed
136+ FailInvCov = 8 , // inversion of cov.-matrix failed
137+ FailInvWeight = 9 , // inversion of Ti weight matrix failed
138+ FailInv2ndDeriv = 10 , // inversion of 2nd derivatives failed
139+ FailCorrTracks = 11 , // correction of tracks to updated x failed
140+ FailCloserAlt = 12 , // alternative PCA is closer
125141 };
126142
127143 static constexpr int getNProngs () { return N; }
@@ -154,7 +170,7 @@ class DCAFitterN
154170 // /< check if propagation of tracks to candidate vertex was done
155171 GPUd () bool isPropagateTracksToVertexDone (int cand = 0 ) const { return mTrPropDone [mOrder [cand]]; }
156172
157- // /< check if propagation of tracks to candidate vertex was done
173+ // /< check if propagation of tracks to candidate vertex failed
158174 bool isPropagationFailure (int cand = 0 ) const { return mPropFailed [mOrder [cand]]; }
159175
160176 // /< track param propagated to V0 candidate (no check for the candidate validity)
@@ -201,6 +217,8 @@ class DCAFitterN
201217
202218 const Track* getOrigTrackPtr (int i) const { return mOrigTrPtr [i]; }
203219
220+ GPUdi () FitStatus getFitStatus (int cand = 0 ) const noexcept { return mFitStatus [mOrder [cand]]; }
221+
204222 // /< return number of iterations during minimization (no check for its validity)
205223 GPUdi () int getNIterations (int cand = 0 ) const { return mNIters [mOrder [cand]]; }
206224 GPUdi () void setPropagateToPCA (bool v = true ) { mPropagateToPCA = v; }
@@ -315,6 +333,8 @@ class DCAFitterN
315333 {
316334 mCurHyp = 0 ;
317335 mAllowAltPreference = true ;
336+ mOrder .fill (0 );
337+ mFitStatus .fill (FitStatus::None);
318338 }
319339
320340 GPUdi () static void setTrackPos (Vec3D& pnt, const Track& tr)
@@ -362,12 +382,13 @@ class DCAFitterN
362382 LogLogThrottler mLoggerBadCov {};
363383 LogLogThrottler mLoggerBadInv {};
364384 LogLogThrottler mLoggerBadProp {};
365- MatSym3D mWeightInv ; // inverse weight of single track, [sum{M^T E M}]^-1 in EQ.T
385+ MatSym3D mWeightInv ; // inverse weight of single track, [sum{M^T E M}]^-1 in EQ.T
366386 o2::gpu::gpustd::array<int , MAXHYP> mOrder {0 };
367387 int mCurHyp = 0 ;
368388 int mCrossIDCur = 0 ;
369389 int mCrossIDAlt = -1 ;
370390 BadCovPolicy mBadCovPolicy {BadCovPolicy::Discard}; // what to do in case of non-pos-def. cov. matrix, see BadCovPolicy enum
391+ o2::gpu::gpustd::array<FitStatus, MAXHYP> mFitStatus {}; // fit status of each hypothesis fit
371392 bool mAllowAltPreference = true ; // if the fit converges to alternative PCA seed, abandon the current one
372393 bool mUseAbsDCA = false ; // use abs. distance minimization rather than chi2
373394 bool mWeightedFinalPCA = false ; // recalculate PCA as a cov-matrix weighted mean, even if absDCA method was used
@@ -390,7 +411,7 @@ class DCAFitterN
390411 float mMaxStep = 2.0 ; // Max step for propagation with Propagator
391412 int mFitterID = 0 ; // locat fitter ID (mostly for debugging)
392413 size_t mCallID = 0 ;
393- ClassDefNV (DCAFitterN, 2 );
414+ ClassDefNV (DCAFitterN, 3 );
394415};
395416
396417// /_________________________________________________________________________
@@ -407,7 +428,8 @@ GPUd() int DCAFitterN<N, Args...>::process(const Tr&... args)
407428 mTrAux [i].set (*mOrigTrPtr [i], mBz );
408429 }
409430 if (!mCrossings .set (mTrAux [0 ], *mOrigTrPtr [0 ], mTrAux [1 ], *mOrigTrPtr [1 ], mMaxDXYIni , mIsCollinear )) { // even for N>2 it should be enough to test just 1 loop
410- return 0 ; // no crossing
431+ mFitStatus [mCurHyp ] = FitStatus::NoCrossing;
432+ return 0 ;
411433 }
412434 for (int ih = 0 ; ih < MAXHYP; ih++) {
413435 mPropFailed [ih] = false ;
@@ -428,6 +450,7 @@ GPUd() int DCAFitterN<N, Args...>::process(const Tr&... args)
428450 for (int ic = 0 ; ic < mCrossings .nDCA ; ic++) {
429451 // check if radius is acceptable
430452 if (mCrossings .xDCA [ic] * mCrossings .xDCA [ic] + mCrossings .yDCA [ic] * mCrossings .yDCA [ic] > mMaxR2 ) {
453+ mFitStatus [mCurHyp ] = FitStatus::RejRadius;
431454 continue ;
432455 }
433456 mCrossIDCur = ic;
@@ -468,6 +491,7 @@ GPUd() bool DCAFitterN<N, Args...>::calcPCACoefs()
468491{
469492 // < calculate Ti matrices for global vertex decomposition to V = sum_{0<i<N} Ti pi, see EQ.T in the ref
470493 if (!calcInverseWeight ()) {
494+ mFitStatus [mCurHyp ] = FitStatus::FailInvWeight;
471495 return false ;
472496 }
473497 for (int i = N; i--;) { // build Mi*Ei matrix
@@ -558,7 +582,7 @@ GPUd() void DCAFitterN<N, Args...>::calcResidDerivatives()
558582 dr2[2 ] += trDx.d2zdx2 ;
559583 }
560584 } // track over which we differentiate
561- } // residual being differentiated
585+ } // residual being differentiated
562586}
563587
564588// __________________________________________________________________________
@@ -608,7 +632,7 @@ GPUd() void DCAFitterN<N, Args...>::calcResidDerivativesNoErr()
608632 dr2ji[2 ] = -trDxi.d2zdx2 * NInv;
609633
610634 } // track over which we differentiate
611- } // residual being differentiated
635+ } // residual being differentiated
612636}
613637
614638// __________________________________________________________________________
@@ -727,6 +751,7 @@ GPUd() bool DCAFitterN<N, Args...>::recalculatePCAWithErrors(int cand)
727751#endif
728752 mLoggerBadCov .evCountPrev = mLoggerBadCov .evCount ;
729753 }
754+ mFitStatus [mCurHyp ] = FitStatus::FailInvCov;
730755 if (mBadCovPolicy == Discard) {
731756 return false ;
732757 } else if (mBadCovPolicy == OverrideAndFlag) {
@@ -935,10 +960,14 @@ GPUd() bool DCAFitterN<N, Args...>::minimizeChi2()
935960 for (int i = N; i--;) {
936961 mCandTr [mCurHyp ][i] = *mOrigTrPtr [i];
937962 auto x = mTrAux [i].c * mPCA [mCurHyp ][0 ] + mTrAux [i].s * mPCA [mCurHyp ][1 ]; // X of PCA in the track frame
938- if (x < mMinXSeed || !propagateToX (mCandTr [mCurHyp ][i], x)) {
963+ if (x < mMinXSeed ) {
964+ mFitStatus [mCurHyp ] = FitStatus::RejTrackX;
939965 return false ;
940966 }
941- setTrackPos (mTrPos [mCurHyp ][i], mCandTr [mCurHyp ][i]); // prepare positions
967+ if (!propagateToX (mCandTr [mCurHyp ][i], x)) {
968+ return false ;
969+ }
970+ setTrackPos (mTrPos [mCurHyp ][i], mCandTr [mCurHyp ][i]); // prepare positions
942971 if (!mTrcEInv [mCurHyp ][i].set (mCandTr [mCurHyp ][i], XerrFactor)) { // prepare inverse cov.matrices at starting point
943972 if (mLoggerBadCov .needToLog ()) {
944973#ifndef GPUCA_GPUCODE
@@ -950,6 +979,7 @@ GPUd() bool DCAFitterN<N, Args...>::minimizeChi2()
950979#endif
951980 mLoggerBadCov .evCountPrev = mLoggerBadCov .evCount ;
952981 }
982+ mFitStatus [mCurHyp ] = FitStatus::FailInvCov;
953983 if (mBadCovPolicy == Discard) {
954984 return false ;
955985 } else if (mBadCovPolicy == OverrideAndFlag) {
@@ -959,6 +989,7 @@ GPUd() bool DCAFitterN<N, Args...>::minimizeChi2()
959989 }
960990
961991 if (mMaxDZIni > 0 && !roughDZCut ()) { // apply rough cut on tracks Z difference
992+ mFitStatus [mCurHyp ] = FitStatus::RejTrackX;
962993 return false ;
963994 }
964995
@@ -979,28 +1010,36 @@ GPUd() bool DCAFitterN<N, Args...>::minimizeChi2()
9791010 printf (" fitter %d: error (%ld muted): Inversion failed\n " , mFitterID , mLoggerBadCov .getNMuted ());
9801011 mLoggerBadInv .evCountPrev = mLoggerBadInv .evCount ;
9811012 }
1013+ mFitStatus [mCurHyp ] = FitStatus::FailInv2ndDeriv;
9821014 return false ;
9831015 }
9841016 VecND dx = mD2Chi2Dx2 * mDChi2Dx ;
9851017 if (!correctTracks (dx)) {
1018+ mFitStatus [mCurHyp ] = FitStatus::FailCorrTracks;
9861019 return false ;
9871020 }
9881021 calcPCA (); // updated PCA
9891022 if (mCrossIDAlt >= 0 && closerToAlternative ()) {
1023+ mFitStatus [mCurHyp ] = FitStatus::FailCloserAlt;
9901024 mAllowAltPreference = false ;
9911025 return false ;
9921026 }
9931027 calcTrackResiduals (); // updated residuals
9941028 chi2Upd = calcChi2 (); // updated chi2
9951029 if (getAbsMax (dx) < mMinParamChange || chi2Upd > chi2 * mMinRelChi2Change ) {
9961030 chi2 = chi2Upd;
1031+ mFitStatus [mCurHyp ] = FitStatus::Converged;
9971032 break ; // converged
9981033 }
9991034 chi2 = chi2Upd;
10001035 } while (++mNIters [mCurHyp ] < mMaxIter );
10011036 //
10021037 mChi2 [mCurHyp ] = chi2 * NInv;
1003- return mChi2 [mCurHyp ] < mMaxChi2 ;
1038+ if (mChi2 [mCurHyp ] >= mMaxChi2 ) {
1039+ mFitStatus [mCurHyp ] = FitStatus::RejChi2Max;
1040+ return false ;
1041+ }
1042+ return true ;
10041043}
10051044
10061045// ___________________________________________________________________
@@ -1012,12 +1051,17 @@ GPUd() bool DCAFitterN<N, Args...>::minimizeChi2NoErr()
10121051 for (int i = N; i--;) {
10131052 mCandTr [mCurHyp ][i] = *mOrigTrPtr [i];
10141053 auto x = mTrAux [i].c * mPCA [mCurHyp ][0 ] + mTrAux [i].s * mPCA [mCurHyp ][1 ]; // X of PCA in the track frame
1015- if (x < mMinXSeed || !propagateParamToX (mCandTr [mCurHyp ][i], x)) {
1054+ if (x < mMinXSeed ) {
1055+ mFitStatus [mCurHyp ] = FitStatus::RejTrackX;
1056+ return false ;
1057+ }
1058+ if (!propagateParamToX (mCandTr [mCurHyp ][i], x)) {
10161059 return false ;
10171060 }
10181061 setTrackPos (mTrPos [mCurHyp ][i], mCandTr [mCurHyp ][i]); // prepare positions
10191062 }
10201063 if (mMaxDZIni > 0 && !roughDZCut ()) { // apply rough cut on tracks Z difference
1064+ mFitStatus [mCurHyp ] = FitStatus::RejTrackX;
10211065 return false ;
10221066 }
10231067
@@ -1035,28 +1079,36 @@ GPUd() bool DCAFitterN<N, Args...>::minimizeChi2NoErr()
10351079 printf (" itter %d: error (%ld muted): Inversion failed\n " , mFitterID , mLoggerBadCov .getNMuted ());
10361080 mLoggerBadInv .evCountPrev = mLoggerBadInv .evCount ;
10371081 }
1082+ mFitStatus [mCurHyp ] = FitStatus::FailInv2ndDeriv;
10381083 return false ;
10391084 }
10401085 VecND dx = mD2Chi2Dx2 * mDChi2Dx ;
10411086 if (!correctTracks (dx)) {
1087+ mFitStatus [mCurHyp ] = FitStatus::FailCorrTracks;
10421088 return false ;
10431089 }
10441090 calcPCANoErr (); // updated PCA
10451091 if (mCrossIDAlt >= 0 && closerToAlternative ()) {
1092+ mFitStatus [mCurHyp ] = FitStatus::FailCloserAlt;
10461093 mAllowAltPreference = false ;
10471094 return false ;
10481095 }
10491096 calcTrackResiduals (); // updated residuals
10501097 chi2Upd = calcChi2NoErr (); // updated chi2
10511098 if (getAbsMax (dx) < mMinParamChange || chi2Upd > chi2 * mMinRelChi2Change ) {
10521099 chi2 = chi2Upd;
1100+ mFitStatus [mCurHyp ] = FitStatus::Converged;
10531101 break ; // converged
10541102 }
10551103 chi2 = chi2Upd;
10561104 } while (++mNIters [mCurHyp ] < mMaxIter );
10571105 //
10581106 mChi2 [mCurHyp ] = chi2 * NInv;
1059- return mChi2 [mCurHyp ] < mMaxChi2 ;
1107+ if (mChi2 [mCurHyp ] >= mMaxChi2 ) {
1108+ mFitStatus [mCurHyp ] = FitStatus::RejChi2Max;
1109+ return false ;
1110+ }
1111+ return true ;
10601112}
10611113
10621114// ___________________________________________________________________
@@ -1182,6 +1234,7 @@ GPUdi() bool DCAFitterN<N, Args...>::propagateParamToX(o2::track::TrackPar& t, f
11821234 res = t.propagateParamTo (x, mBz );
11831235 }
11841236 if (!res) {
1237+ mFitStatus [mCurHyp ] = FitStatus::FailProp;
11851238 mPropFailed [mCurHyp ] = true ;
11861239 if (mLoggerBadProp .needToLog ()) {
11871240#ifndef GPUCA_GPUCODE
@@ -1208,6 +1261,7 @@ GPUdi() bool DCAFitterN<N, Args...>::propagateToX(o2::track::TrackParCov& t, flo
12081261 res = t.propagateTo (x, mBz );
12091262 }
12101263 if (!res) {
1264+ mFitStatus [mCurHyp ] = FitStatus::FailProp;
12111265 mPropFailed [mCurHyp ] = true ;
12121266 if (mLoggerBadProp .needToLog ()) {
12131267#ifndef GPUCA_GPUCODE
0 commit comments