Skip to content

Commit cadc5fa

Browse files
authored
Common: DCAFitter add fit status code (#14132)
* Common: DCAFitter add fit status code * Common: DCAFitter add test/summary of stats Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch> * Common: DCAFitter catch maxIter reached Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch> * Common: DCAFitter fix spell Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch> * Common: DCAFitter simplify exp.-backoff of logging Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch> --------- Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch>
1 parent 436c0b0 commit cadc5fa

File tree

2 files changed

+148
-45
lines changed

2 files changed

+148
-45
lines changed

Common/DCAFitter/include/DCAFitter/DCAFitterN.h

Lines changed: 100 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -75,21 +75,20 @@ struct TrackDeriv {
7575
///< Log log-throttling helper
7676
struct 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

9594
template <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

Comments
 (0)