Skip to content

Commit c5cbdc4

Browse files
committed
DCAFitterN: log-throttling for err.messages + user policy for bad CovMat
Due to the linearization errors the covariance matrix of the track propagated to some point may become non-positive defined. In this case an error will be logged (logarithmically throttled), the relevant correlation coefficient of the cov.matrix is redefined to cure the position part of the cov.matrix and further program flow depends on the user settings for DCAFitterN::setBadCovPolicy(v): DCAFitterN::setBadCovPolicy(DCAFitterN::Discard) : abandon fit (default) DCAFitterN::setBadCovPolicy(DCAFitterN::Override) : continue fit with overridden cov.matrix DCAFitterN::setBadCovPolicy(DCAFitterN::OverrideAnFlag): continue fit with overridden cov.matrix but set the propagation failure flag (can be checked using the isPropagationFailure(int cand = 0) method).
1 parent d06c2cf commit c5cbdc4

File tree

2 files changed

+114
-22
lines changed

2 files changed

+114
-22
lines changed

Common/DCAFitter/README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
\page refDetectorsVertexing DCAFitter
33
/doxy -->
44

5-
## DCAFitterN
5+
# DCAFitterN
66

77
Templated class to fit the Point of Closest Approach (PCA) of secondary vertex with N prongs. Allows minimization of either absolute or weighted Distances of Closest Approach (DCA) of N tracks to their common PCA.
88

@@ -74,7 +74,22 @@ Extra method `setWeightedFinalPCA(bool)` is provided for the "mixed" mode: if `s
7474
but the final V0 position will be calculated using weighted average. One can also recalculate the V0 position by the weighted average method by calling explicitly
7575
`ft.recalculatePCAWithErrors(int icand=0)`, w/o prior call of `setWeightedFinalPCA(true)`: this will update the position returned by the `getPCACandidate(int cand = 0)`.
7676

77-
The covariance matrix of the V0 position is calculated as an inversed sum of tracks inversed covariances at respective `X_dca` points.
77+
The covariance matrix of the V0 position is calculated as an inverted sum of tracks inversed covariances at respective `X_dca` points.
7878

7979
See ``O2/Common/DCAFitter/test/testDCAFitterN.cxx`` for more extended example.
8080
Currently only 2 and 3 prongs permitted, thought this can be changed by modifying ``DCAFitterN::NMax`` constant.
81+
82+
## Error handling
83+
84+
It may happen that the track propagation to the the proximity of the PCA fails at the various stage of the fit. In this case the fit is abandoned and the failure flag is set, it can be checked using
85+
isPropagationFailure(int cand = 0)` method.
86+
87+
Also, due to the linearization errors the covariance matrix of the track propagated to some point may become non-positive defined.
88+
In this case the relevant correlation coefficient of the cov.matrix is redefined to cure the position part of the cov.matrix and further program flow depends on the user settings for `DCAFitterN::setBadCovPolicy(v)`:
89+
90+
`DCAFitterN::setBadCovPolicy(DCAFitterN::Discard);` : abandon fit (default)
91+
92+
`DCAFitterN::setBadCovPolicy(DCAFitterN::Override);` : continue fit with overridden cov.matrix
93+
94+
`DCAFitterN::setBadCovPolicy(DCAFitterN::OverrideAnFlag);` continue fit with overridden cov.matrix but set the propagation failure flag (can be checked using the same `isPropagationFailure(int cand = 0)` method).
95+

Common/DCAFitter/include/DCAFitter/DCAFitterN.h

Lines changed: 97 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,35 +26,32 @@ namespace o2
2626
{
2727
namespace vertexing
2828
{
29+
2930
///__________________________________________________________________________________
3031
///< Inverse cov matrix (augmented by a dummy X error) of the point defined by the track
3132
struct TrackCovI {
3233
float sxx, syy, syz, szz;
3334

34-
GPUd() TrackCovI(const o2::track::TrackParCov& trc, float xerrFactor = 1.) { set(trc, xerrFactor); }
35-
3635
GPUdDefault() TrackCovI() = default;
3736

38-
GPUd() void set(const o2::track::TrackParCov& trc, float xerrFactor = 1)
37+
GPUd() bool set(const o2::track::TrackParCov& trc, float xerrFactor = 1.f)
3938
{
4039
// we assign Y error to X for DCA calculation
4140
// (otherwise for quazi-collinear tracks the X will not be constrained)
4241
float cyy = trc.getSigmaY2(), czz = trc.getSigmaZ2(), cyz = trc.getSigmaZY(), cxx = cyy * xerrFactor;
4342
float detYZ = cyy * czz - cyz * cyz;
43+
bool res = true;
4444
if (detYZ <= 0.) {
45-
#ifndef GPUCA_GPUCODE
46-
printf("overriding invalid track covariance from %s\n", trc.asString().c_str());
47-
#else
48-
printf("overriding invalid track covariance cyy:%e czz:%e cyz:%e\n", cyy, czz, cyz);
49-
#endif
5045
cyz = o2::gpu::GPUCommonMath::Sqrt(cyy * czz) * (cyz > 0 ? 0.98f : -0.98f);
5146
detYZ = cyy * czz - cyz * cyz;
47+
res = false;
5248
}
5349
auto detYZI = 1. / detYZ;
5450
sxx = 1. / cxx;
5551
syy = czz * detYZI;
5652
syz = -cyz * detYZI;
5753
szz = cyy * detYZI;
54+
return res;
5855
}
5956
};
6057

@@ -74,6 +71,27 @@ struct TrackDeriv {
7471
}
7572
};
7673

74+
///__________________________________________________________________________
75+
///< Log log-throttling helper
76+
struct LogLogThrottler {
77+
size_t evCount{0};
78+
size_t evCountPrev{0};
79+
size_t logCount{0};
80+
81+
GPUdi() bool needToLog()
82+
{
83+
if (size_t(o2::gpu::GPUCommonMath::Log(++evCount)) + 1 > logCount) {
84+
logCount++;
85+
return true;
86+
}
87+
return false;
88+
}
89+
90+
GPUdi() size_t getNMuted() const { return evCount - evCountPrev - 1; }
91+
92+
GPUdi() void clear() { evCount = evCountPrev = logCount = 0; }
93+
};
94+
7795
template <int N, typename... Args>
7896
class DCAFitterN
7997
{
@@ -100,6 +118,12 @@ class DCAFitterN
100118
using ArrTrPos = o2::gpu::gpustd::array<Vec3D, N>; // container of Track positions
101119

102120
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)
125+
};
126+
103127
static constexpr int getNProngs() { return N; }
104128

105129
DCAFitterN() = default;
@@ -300,6 +324,9 @@ class DCAFitterN
300324
pnt[2] = tr.getZ();
301325
}
302326

327+
void setBadCovPolicy(BadCovPolicy v) { mBadCovPolicy = v; }
328+
BadCovPolicy getBadCovPolicy() const { return mBadCovPolicy; }
329+
303330
private:
304331
// vectors of 1st derivatives of track local residuals over X parameters
305332
o2::gpu::gpustd::array<o2::gpu::gpustd::array<Vec3D, N>, N> mDResidDx;
@@ -325,11 +352,15 @@ class DCAFitterN
325352
o2::gpu::gpustd::array<int, MAXHYP> mNIters; // number of iterations for each seed
326353
o2::gpu::gpustd::array<bool, MAXHYP> mTrPropDone{}; // Flag that the tracks are fully propagated to PCA
327354
o2::gpu::gpustd::array<bool, MAXHYP> mPropFailed{}; // Flag that some propagation failed for this PCA candidate
355+
LogLogThrottler mLoggerBadCov{};
356+
LogLogThrottler mLoggerBadInv{};
357+
LogLogThrottler mLoggerBadProp{};
328358
MatSym3D mWeightInv; // inverse weight of single track, [sum{M^T E M}]^-1 in EQ.T
329359
o2::gpu::gpustd::array<int, MAXHYP> mOrder{0};
330360
int mCurHyp = 0;
331361
int mCrossIDCur = 0;
332362
int mCrossIDAlt = -1;
363+
BadCovPolicy mBadCovPolicy{BadCovPolicy::Discard}; // what to do in case of non-pos-def. cov. matrix, see BadCovPolicy enum
333364
bool mAllowAltPreference = true; // if the fit converges to alternative PCA seed, abandon the current one
334365
bool mUseAbsDCA = false; // use abs. distance minimization rather than chi2
335366
bool mWeightedFinalPCA = false; // recalculate PCA as a cov-matrix weighted mean, even if absDCA method was used
@@ -678,7 +709,23 @@ GPUd() bool DCAFitterN<N, Args...>::recalculatePCAWithErrors(int cand)
678709
mCurHyp = mOrder[cand];
679710
if (mUseAbsDCA) {
680711
for (int i = N; i--;) {
681-
mTrcEInv[mCurHyp][i].set(mCandTr[mCurHyp][i], XerrFactor); // prepare inverse cov.matrices at starting point
712+
if (!mTrcEInv[mCurHyp][i].set(mCandTr[mCurHyp][i], XerrFactor)) { // prepare inverse cov.matrices at starting point
713+
if (mLoggerBadCov.needToLog()) {
714+
#ifndef GPUCA_GPUCODE
715+
printf("fitter %d: error (%ld muted): overrode invalid track covariance from %s\n",
716+
mFitterID, mLoggerBadCov.getNMuted(), mCandTr[mCurHyp][i].asString().c_str());
717+
#else
718+
printf("fitter %d: error (%ld muted): overrode invalid track covariance cyy:%e czz:%e cyz:%e\n",
719+
mFitterID, mLoggerBadCov.getNMuted(), mCandTr[mCurHyp][i].getSigmaY2(), mCandTr[mCurHyp][i].getSigmaZ2(), mCandTr[mCurHyp][i].getSigmaZY());
720+
#endif
721+
mLoggerBadCov.evCountPrev = mLoggerBadCov.evCount;
722+
}
723+
if (mBadCovPolicy == Discard) {
724+
return false;
725+
} else if (mBadCovPolicy == OverrideAndFlag) {
726+
mPropFailed[mCurHyp] = true;
727+
} // otherwise, just use overridden errors w/o flagging
728+
}
682729
}
683730
if (!calcPCACoefs()) {
684731
mCurHyp = saveCurHyp;
@@ -885,7 +932,23 @@ GPUd() bool DCAFitterN<N, Args...>::minimizeChi2()
885932
return false;
886933
}
887934
setTrackPos(mTrPos[mCurHyp][i], mCandTr[mCurHyp][i]); // prepare positions
888-
mTrcEInv[mCurHyp][i].set(mCandTr[mCurHyp][i], XerrFactor); // prepare inverse cov.matrices at starting point
935+
if (!mTrcEInv[mCurHyp][i].set(mCandTr[mCurHyp][i], XerrFactor)) { // prepare inverse cov.matrices at starting point
936+
if (mLoggerBadCov.needToLog()) {
937+
#ifndef GPUCA_GPUCODE
938+
printf("fitter %d: error (%ld muted): overrode invalid track covariance from %s\n",
939+
mFitterID, mLoggerBadCov.getNMuted(), mCandTr[mCurHyp][i].asString().c_str());
940+
#else
941+
printf("fitter %d: error (%ld muted): overrode invalid track covariance cyy:%e czz:%e cyz:%e\n",
942+
mFitterID, mLoggerBadCov.getNMuted(), mCandTr[mCurHyp][i].getSigmaY2(), mCandTr[mCurHyp][i].getSigmaZ2(), mCandTr[mCurHyp][i].getSigmaZY());
943+
#endif
944+
mLoggerBadCov.evCountPrev = mLoggerBadCov.evCount;
945+
}
946+
if (mBadCovPolicy == Discard) {
947+
return false;
948+
} else if (mBadCovPolicy == OverrideAndFlag) {
949+
mPropFailed[mCurHyp] = true;
950+
} // otherwise, just use overridden errors w/o flagging
951+
}
889952
}
890953

891954
if (mMaxDZIni > 0 && !roughDZCut()) { // apply rough cut on tracks Z difference
@@ -905,11 +968,10 @@ GPUd() bool DCAFitterN<N, Args...>::minimizeChi2()
905968

906969
// do Newton-Rapson iteration with corrections = - dchi2/d{x0..xN} * [ d^2chi2/d{x0..xN}^2 ]^-1
907970
if (!mD2Chi2Dx2.Invert()) {
908-
#ifndef GPUCA_GPUCODE_DEVICE
909-
LOG(error) << "InversionFailed";
910-
#else
911-
printf("InversionFailed\n");
912-
#endif
971+
if (mLoggerBadInv.needToLog()) {
972+
printf("fitter %d: error (%ld muted): Inversion failed\n", mFitterID, mLoggerBadCov.getNMuted());
973+
mLoggerBadInv.evCountPrev = mLoggerBadInv.evCount;
974+
}
913975
return false;
914976
}
915977
VecND dx = mD2Chi2Dx2 * mDChi2Dx;
@@ -962,11 +1024,10 @@ GPUd() bool DCAFitterN<N, Args...>::minimizeChi2NoErr()
9621024

9631025
// do Newton-Rapson iteration with corrections = - dchi2/d{x0..xN} * [ d^2chi2/d{x0..xN}^2 ]^-1
9641026
if (!mD2Chi2Dx2.Invert()) {
965-
#ifndef GPUCA_GPUCODE_DEVICE
966-
LOG(error) << "InversionFailed";
967-
#else
968-
printf("InversionFailed\n");
969-
#endif
1027+
if (mLoggerBadInv.needToLog()) {
1028+
printf("itter %d: error (%ld muted): Inversion failed\n", mFitterID, mLoggerBadCov.getNMuted());
1029+
mLoggerBadInv.evCountPrev = mLoggerBadInv.evCount;
1030+
}
9701031
return false;
9711032
}
9721033
VecND dx = mD2Chi2Dx2 * mDChi2Dx;
@@ -1109,6 +1170,14 @@ GPUdi() bool DCAFitterN<N, Args...>::propagateParamToX(o2::track::TrackPar& t, f
11091170
}
11101171
if (!res) {
11111172
mPropFailed[mCurHyp] = true;
1173+
if (mLoggerBadProp.needToLog()) {
1174+
#ifndef GPUCA_GPUCODE
1175+
printf("fitter %d: error (%ld muted): propagation failed for %s\n", mFitterID, mLoggerBadProp.getNMuted(), t.asString().c_str());
1176+
#else
1177+
printf("fitter %d: error (%ld muted): propagation failed\n", mFitterID, mLoggerBadProp.getNMuted());
1178+
#endif
1179+
mLoggerBadProp.evCountPrev = mLoggerBadProp.evCount;
1180+
}
11121181
}
11131182
return res;
11141183
}
@@ -1127,6 +1196,14 @@ GPUdi() bool DCAFitterN<N, Args...>::propagateToX(o2::track::TrackParCov& t, flo
11271196
}
11281197
if (!res) {
11291198
mPropFailed[mCurHyp] = true;
1199+
if (mLoggerBadProp.needToLog()) {
1200+
#ifndef GPUCA_GPUCODE
1201+
printf("fitter %d: error (%ld muted): propagation failed for %s\n", mFitterID, mLoggerBadProp.getNMuted(), t.asString().c_str());
1202+
#else
1203+
printf("fitter %d: error (%ld muted): propagation failed\n", mFitterID, mLoggerBadProp.getNMuted());
1204+
#endif
1205+
mLoggerBadProp.evCountPrev = mLoggerBadProp.evCount;
1206+
}
11301207
}
11311208
return res;
11321209
}

0 commit comments

Comments
 (0)