@@ -75,21 +75,20 @@ struct TrackDeriv {
7575// /< Log log-throttling helper
7676struct LogLogThrottler {
7777 size_t evCount{0 };
78- size_t evCountPrev{0 };
79- size_t logCount{0 };
80-
78+ size_t nextLog{1 };
8179 GPUdi () bool needToLog ()
8280 {
83- if (size_t ( o2::gpu::GPUCommonMath::Log ( ++evCount)) + 1 > logCount ) {
84- logCount++ ;
81+ if (++evCount > nextLog ) {
82+ nextLog *= 2 ;
8583 return true ;
8684 }
8785 return false ;
8886 }
89-
90- GPUdi () size_t getNMuted () const { return evCount - evCountPrev - 1 ; }
91-
92- GPUdi () void clear () { evCount = evCountPrev = logCount = 0 ; }
87+ GPUdi () void clear ()
88+ {
89+ evCount = 0 ;
90+ nextLog = 1 ;
91+ }
9392};
9493
9594template <int N, typename ... Args>
@@ -118,10 +117,31 @@ class DCAFitterN
118117 using ArrTrPos = o2::gpu::gpustd::array<Vec3D, N>; // container of Track positions
119118
120119 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)
120+ enum BadCovPolicy : uint8_t { // if encountering non-positive defined cov. matrix, the choice is:
121+ Discard = 0 , // stop evaluation
122+ Override = 1 , // override correlation coef. to have cov.matrix pos.def and continue
123+ 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)
124+ };
125+
126+ enum FitStatus : uint8_t { // fit status of crossing hypothesis
127+ None, // no status set (should not be possible!)
128+
129+ /* Good Conditions */
130+ Converged, // fit converged
131+ MaxIter, // max iterations reached before fit convergence
132+
133+ /* Error Conditions */
134+ NoCrossing, // no reasaonable crossing was found
135+ RejRadius, // radius of crossing was not acceptable
136+ RejTrackX, // one candidate track x was below the mimimum required radius
137+ RejTrackRoughZ, // rejected by rough cut on tracks Z difference
138+ RejChi2Max, // rejected by maximum chi2 cut
139+ FailProp, // propagation of at least prong to PCA failed
140+ FailInvCov, // inversion of cov.-matrix failed
141+ FailInvWeight, // inversion of Ti weight matrix failed
142+ FailInv2ndDeriv, // inversion of 2nd derivatives failed
143+ FailCorrTracks, // correction of tracks to updated x failed
144+ FailCloserAlt, // alternative PCA is closer
125145 };
126146
127147 static constexpr int getNProngs () { return N; }
@@ -154,7 +174,7 @@ class DCAFitterN
154174 // /< check if propagation of tracks to candidate vertex was done
155175 GPUd () bool isPropagateTracksToVertexDone (int cand = 0 ) const { return mTrPropDone [mOrder [cand]]; }
156176
157- // /< check if propagation of tracks to candidate vertex was done
177+ // /< check if propagation of tracks to candidate vertex failed
158178 bool isPropagationFailure (int cand = 0 ) const { return mPropFailed [mOrder [cand]]; }
159179
160180 // /< track param propagated to V0 candidate (no check for the candidate validity)
@@ -201,6 +221,8 @@ class DCAFitterN
201221
202222 const Track* getOrigTrackPtr (int i) const { return mOrigTrPtr [i]; }
203223
224+ GPUdi () FitStatus getFitStatus (int cand = 0 ) const noexcept { return mFitStatus [mOrder [cand]]; }
225+
204226 // /< return number of iterations during minimization (no check for its validity)
205227 GPUdi () int getNIterations (int cand = 0 ) const { return mNIters [mOrder [cand]]; }
206228 GPUdi () void setPropagateToPCA (bool v = true ) { mPropagateToPCA = v; }
@@ -315,6 +337,12 @@ class DCAFitterN
315337 {
316338 mCurHyp = 0 ;
317339 mAllowAltPreference = true ;
340+ mOrder .fill (0 );
341+ mPropFailed .fill (false );
342+ mTrPropDone .fill (false );
343+ mNIters .fill (0 );
344+ mChi2 .fill (-1 );
345+ mFitStatus .fill (FitStatus::None);
318346 }
319347
320348 GPUdi () static void setTrackPos (Vec3D& pnt, const Track& tr)
@@ -362,12 +390,13 @@ class DCAFitterN
362390 LogLogThrottler mLoggerBadCov {};
363391 LogLogThrottler mLoggerBadInv {};
364392 LogLogThrottler mLoggerBadProp {};
365- MatSym3D mWeightInv ; // inverse weight of single track, [sum{M^T E M}]^-1 in EQ.T
393+ MatSym3D mWeightInv ; // inverse weight of single track, [sum{M^T E M}]^-1 in EQ.T
366394 o2::gpu::gpustd::array<int , MAXHYP> mOrder {0 };
367395 int mCurHyp = 0 ;
368396 int mCrossIDCur = 0 ;
369397 int mCrossIDAlt = -1 ;
370398 BadCovPolicy mBadCovPolicy {BadCovPolicy::Discard}; // what to do in case of non-pos-def. cov. matrix, see BadCovPolicy enum
399+ o2::gpu::gpustd::array<FitStatus, MAXHYP> mFitStatus {}; // fit status of each hypothesis fit
371400 bool mAllowAltPreference = true ; // if the fit converges to alternative PCA seed, abandon the current one
372401 bool mUseAbsDCA = false ; // use abs. distance minimization rather than chi2
373402 bool mWeightedFinalPCA = false ; // recalculate PCA as a cov-matrix weighted mean, even if absDCA method was used
@@ -390,7 +419,7 @@ class DCAFitterN
390419 float mMaxStep = 2.0 ; // Max step for propagation with Propagator
391420 int mFitterID = 0 ; // locat fitter ID (mostly for debugging)
392421 size_t mCallID = 0 ;
393- ClassDefNV (DCAFitterN, 2 );
422+ ClassDefNV (DCAFitterN, 3 );
394423};
395424
396425// /_________________________________________________________________________
@@ -407,10 +436,8 @@ GPUd() int DCAFitterN<N, Args...>::process(const Tr&... args)
407436 mTrAux [i].set (*mOrigTrPtr [i], mBz );
408437 }
409438 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
411- }
412- for (int ih = 0 ; ih < MAXHYP; ih++) {
413- mPropFailed [ih] = false ;
439+ mFitStatus [mCurHyp ] = FitStatus::NoCrossing;
440+ return 0 ;
414441 }
415442 if (mUseAbsDCA ) {
416443 calcRMatrices (); // needed for fast residuals derivatives calculation in case of abs. distance minimization
@@ -428,13 +455,11 @@ GPUd() int DCAFitterN<N, Args...>::process(const Tr&... args)
428455 for (int ic = 0 ; ic < mCrossings .nDCA ; ic++) {
429456 // check if radius is acceptable
430457 if (mCrossings .xDCA [ic] * mCrossings .xDCA [ic] + mCrossings .yDCA [ic] * mCrossings .yDCA [ic] > mMaxR2 ) {
458+ mFitStatus [mCurHyp ] = FitStatus::RejRadius;
431459 continue ;
432460 }
433461 mCrossIDCur = ic;
434462 mCrossIDAlt = (mCrossings .nDCA == 2 && mAllowAltPreference ) ? 1 - ic : -1 ; // works for max 2 crossings
435- mNIters [mCurHyp ] = 0 ;
436- mTrPropDone [mCurHyp ] = false ;
437- mChi2 [mCurHyp ] = -1 .;
438463 mPCA [mCurHyp ][0 ] = mCrossings .xDCA [ic];
439464 mPCA [mCurHyp ][1 ] = mCrossings .yDCA [ic];
440465
@@ -468,6 +493,7 @@ GPUd() bool DCAFitterN<N, Args...>::calcPCACoefs()
468493{
469494 // < calculate Ti matrices for global vertex decomposition to V = sum_{0<i<N} Ti pi, see EQ.T in the ref
470495 if (!calcInverseWeight ()) {
496+ mFitStatus [mCurHyp ] = FitStatus::FailInvWeight;
471497 return false ;
472498 }
473499 for (int i = N; i--;) { // build Mi*Ei matrix
@@ -720,13 +746,13 @@ GPUd() bool DCAFitterN<N, Args...>::recalculatePCAWithErrors(int cand)
720746 if (mLoggerBadCov .needToLog ()) {
721747#ifndef GPUCA_GPUCODE
722748 printf (" fitter %d: error (%ld muted): overrode invalid track covariance from %s\n " ,
723- mFitterID , mLoggerBadCov .getNMuted () , mCandTr [mCurHyp ][i].asString ().c_str ());
749+ mFitterID , mLoggerBadCov .evCount , mCandTr [mCurHyp ][i].asString ().c_str ());
724750#else
725751 printf (" fitter %d: error (%ld muted): overrode invalid track covariance cyy:%e czz:%e cyz:%e\n " ,
726- mFitterID , mLoggerBadCov .getNMuted () , mCandTr [mCurHyp ][i].getSigmaY2 (), mCandTr [mCurHyp ][i].getSigmaZ2 (), mCandTr [mCurHyp ][i].getSigmaZY ());
752+ mFitterID , mLoggerBadCov .evCount , mCandTr [mCurHyp ][i].getSigmaY2 (), mCandTr [mCurHyp ][i].getSigmaZ2 (), mCandTr [mCurHyp ][i].getSigmaZY ());
727753#endif
728- mLoggerBadCov .evCountPrev = mLoggerBadCov .evCount ;
729754 }
755+ mFitStatus [mCurHyp ] = FitStatus::FailInvCov;
730756 if (mBadCovPolicy == Discard) {
731757 return false ;
732758 } else if (mBadCovPolicy == OverrideAndFlag) {
@@ -935,21 +961,25 @@ GPUd() bool DCAFitterN<N, Args...>::minimizeChi2()
935961 for (int i = N; i--;) {
936962 mCandTr [mCurHyp ][i] = *mOrigTrPtr [i];
937963 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)) {
964+ if (x < mMinXSeed ) {
965+ mFitStatus [mCurHyp ] = FitStatus::RejTrackX;
939966 return false ;
940967 }
941- setTrackPos (mTrPos [mCurHyp ][i], mCandTr [mCurHyp ][i]); // prepare positions
968+ if (!propagateToX (mCandTr [mCurHyp ][i], x)) {
969+ return false ;
970+ }
971+ setTrackPos (mTrPos [mCurHyp ][i], mCandTr [mCurHyp ][i]); // prepare positions
942972 if (!mTrcEInv [mCurHyp ][i].set (mCandTr [mCurHyp ][i], XerrFactor)) { // prepare inverse cov.matrices at starting point
943973 if (mLoggerBadCov .needToLog ()) {
944974#ifndef GPUCA_GPUCODE
945975 printf (" fitter %d: error (%ld muted): overrode invalid track covariance from %s\n " ,
946- mFitterID , mLoggerBadCov .getNMuted () , mCandTr [mCurHyp ][i].asString ().c_str ());
976+ mFitterID , mLoggerBadCov .evCount , mCandTr [mCurHyp ][i].asString ().c_str ());
947977#else
948978 printf (" fitter %d: error (%ld muted): overrode invalid track covariance cyy:%e czz:%e cyz:%e\n " ,
949- mFitterID , mLoggerBadCov .getNMuted () , mCandTr [mCurHyp ][i].getSigmaY2 (), mCandTr [mCurHyp ][i].getSigmaZ2 (), mCandTr [mCurHyp ][i].getSigmaZY ());
979+ mFitterID , mLoggerBadCov .evCount , mCandTr [mCurHyp ][i].getSigmaY2 (), mCandTr [mCurHyp ][i].getSigmaZ2 (), mCandTr [mCurHyp ][i].getSigmaZY ());
950980#endif
951- 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
@@ -976,31 +1007,41 @@ GPUd() bool DCAFitterN<N, Args...>::minimizeChi2()
9761007 // do Newton-Rapson iteration with corrections = - dchi2/d{x0..xN} * [ d^2chi2/d{x0..xN}^2 ]^-1
9771008 if (!mD2Chi2Dx2 .Invert ()) {
9781009 if (mLoggerBadInv .needToLog ()) {
979- printf (" fitter %d: error (%ld muted): Inversion failed\n " , mFitterID , mLoggerBadCov .getNMuted ());
980- mLoggerBadInv .evCountPrev = mLoggerBadInv .evCount ;
1010+ printf (" fitter %d: error (%ld muted): Inversion failed\n " , mFitterID , mLoggerBadCov .evCount );
9811011 }
1012+ mFitStatus [mCurHyp ] = FitStatus::FailInv2ndDeriv;
9821013 return false ;
9831014 }
9841015 VecND dx = mD2Chi2Dx2 * mDChi2Dx ;
9851016 if (!correctTracks (dx)) {
1017+ mFitStatus [mCurHyp ] = FitStatus::FailCorrTracks;
9861018 return false ;
9871019 }
9881020 calcPCA (); // updated PCA
9891021 if (mCrossIDAlt >= 0 && closerToAlternative ()) {
1022+ mFitStatus [mCurHyp ] = FitStatus::FailCloserAlt;
9901023 mAllowAltPreference = false ;
9911024 return false ;
9921025 }
9931026 calcTrackResiduals (); // updated residuals
9941027 chi2Upd = calcChi2 (); // updated chi2
9951028 if (getAbsMax (dx) < mMinParamChange || chi2Upd > chi2 * mMinRelChi2Change ) {
9961029 chi2 = chi2Upd;
1030+ mFitStatus [mCurHyp ] = FitStatus::Converged;
9971031 break ; // converged
9981032 }
9991033 chi2 = chi2Upd;
10001034 } while (++mNIters [mCurHyp ] < mMaxIter );
1035+ if (mNIters [mCurHyp ] == mMaxIter ) {
1036+ mFitStatus [mCurHyp ] = FitStatus::MaxIter;
1037+ }
10011038 //
10021039 mChi2 [mCurHyp ] = chi2 * NInv;
1003- return mChi2 [mCurHyp ] < mMaxChi2 ;
1040+ if (mChi2 [mCurHyp ] >= mMaxChi2 ) {
1041+ mFitStatus [mCurHyp ] = FitStatus::RejChi2Max;
1042+ return false ;
1043+ }
1044+ return true ;
10041045}
10051046
10061047// ___________________________________________________________________
@@ -1012,12 +1053,17 @@ GPUd() bool DCAFitterN<N, Args...>::minimizeChi2NoErr()
10121053 for (int i = N; i--;) {
10131054 mCandTr [mCurHyp ][i] = *mOrigTrPtr [i];
10141055 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)) {
1056+ if (x < mMinXSeed ) {
1057+ mFitStatus [mCurHyp ] = FitStatus::RejTrackX;
1058+ return false ;
1059+ }
1060+ if (!propagateParamToX (mCandTr [mCurHyp ][i], x)) {
10161061 return false ;
10171062 }
10181063 setTrackPos (mTrPos [mCurHyp ][i], mCandTr [mCurHyp ][i]); // prepare positions
10191064 }
10201065 if (mMaxDZIni > 0 && !roughDZCut ()) { // apply rough cut on tracks Z difference
1066+ mFitStatus [mCurHyp ] = FitStatus::RejTrackX;
10211067 return false ;
10221068 }
10231069
@@ -1032,31 +1078,41 @@ GPUd() bool DCAFitterN<N, Args...>::minimizeChi2NoErr()
10321078 // do Newton-Rapson iteration with corrections = - dchi2/d{x0..xN} * [ d^2chi2/d{x0..xN}^2 ]^-1
10331079 if (!mD2Chi2Dx2 .Invert ()) {
10341080 if (mLoggerBadInv .needToLog ()) {
1035- printf (" itter %d: error (%ld muted): Inversion failed\n " , mFitterID , mLoggerBadCov .getNMuted ());
1036- mLoggerBadInv .evCountPrev = mLoggerBadInv .evCount ;
1081+ printf (" fitter %d: error (%ld muted): Inversion failed\n " , mFitterID , mLoggerBadCov .evCount );
10371082 }
1083+ mFitStatus [mCurHyp ] = FitStatus::FailInv2ndDeriv;
10381084 return false ;
10391085 }
10401086 VecND dx = mD2Chi2Dx2 * mDChi2Dx ;
10411087 if (!correctTracks (dx)) {
1088+ mFitStatus [mCurHyp ] = FitStatus::FailCorrTracks;
10421089 return false ;
10431090 }
10441091 calcPCANoErr (); // updated PCA
10451092 if (mCrossIDAlt >= 0 && closerToAlternative ()) {
1093+ mFitStatus [mCurHyp ] = FitStatus::FailCloserAlt;
10461094 mAllowAltPreference = false ;
10471095 return false ;
10481096 }
10491097 calcTrackResiduals (); // updated residuals
10501098 chi2Upd = calcChi2NoErr (); // updated chi2
10511099 if (getAbsMax (dx) < mMinParamChange || chi2Upd > chi2 * mMinRelChi2Change ) {
10521100 chi2 = chi2Upd;
1101+ mFitStatus [mCurHyp ] = FitStatus::Converged;
10531102 break ; // converged
10541103 }
10551104 chi2 = chi2Upd;
10561105 } while (++mNIters [mCurHyp ] < mMaxIter );
1106+ if (mNIters [mCurHyp ] == mMaxIter ) {
1107+ mFitStatus [mCurHyp ] = FitStatus::MaxIter;
1108+ }
10571109 //
10581110 mChi2 [mCurHyp ] = chi2 * NInv;
1059- return mChi2 [mCurHyp ] < mMaxChi2 ;
1111+ if (mChi2 [mCurHyp ] >= mMaxChi2 ) {
1112+ mFitStatus [mCurHyp ] = FitStatus::RejChi2Max;
1113+ return false ;
1114+ }
1115+ return true ;
10601116}
10611117
10621118// ___________________________________________________________________
@@ -1182,14 +1238,14 @@ GPUdi() bool DCAFitterN<N, Args...>::propagateParamToX(o2::track::TrackPar& t, f
11821238 res = t.propagateParamTo (x, mBz );
11831239 }
11841240 if (!res) {
1241+ mFitStatus [mCurHyp ] = FitStatus::FailProp;
11851242 mPropFailed [mCurHyp ] = true ;
11861243 if (mLoggerBadProp .needToLog ()) {
11871244#ifndef GPUCA_GPUCODE
1188- printf (" fitter %d: error (%ld muted): propagation failed for %s\n " , mFitterID , mLoggerBadProp .getNMuted () , t.asString ().c_str ());
1245+ printf (" fitter %d: error (%ld muted): propagation failed for %s\n " , mFitterID , mLoggerBadProp .evCount , t.asString ().c_str ());
11891246#else
1190- printf (" fitter %d: error (%ld muted): propagation failed\n " , mFitterID , mLoggerBadProp .getNMuted () );
1247+ printf (" fitter %d: error (%ld muted): propagation failed\n " , mFitterID , mLoggerBadProp .evCount );
11911248#endif
1192- mLoggerBadProp .evCountPrev = mLoggerBadProp .evCount ;
11931249 }
11941250 }
11951251 return res;
@@ -1208,14 +1264,14 @@ GPUdi() bool DCAFitterN<N, Args...>::propagateToX(o2::track::TrackParCov& t, flo
12081264 res = t.propagateTo (x, mBz );
12091265 }
12101266 if (!res) {
1267+ mFitStatus [mCurHyp ] = FitStatus::FailProp;
12111268 mPropFailed [mCurHyp ] = true ;
12121269 if (mLoggerBadProp .needToLog ()) {
12131270#ifndef GPUCA_GPUCODE
1214- printf (" fitter %d: error (%ld muted): propagation failed for %s\n " , mFitterID , mLoggerBadProp .getNMuted () , t.asString ().c_str ());
1271+ printf (" fitter %d: error (%ld muted): propagation failed for %s\n " , mFitterID , mLoggerBadProp .evCount , t.asString ().c_str ());
12151272#else
1216- printf (" fitter %d: error (%ld muted): propagation failed\n " , mFitterID , mLoggerBadProp .getNMuted () );
1273+ printf (" fitter %d: error (%ld muted): propagation failed\n " , mFitterID , mLoggerBadProp .evCount );
12171274#endif
1218- mLoggerBadProp .evCountPrev = mLoggerBadProp .evCount ;
12191275 }
12201276 }
12211277 return res;
0 commit comments