251 GPUd()
bool recalculatePCAWithErrors(
int cand = 0);
253 GPUd()
double calcCollinearInflation(
int cand) const;
258 auto m = calcPCACovMatrix(
cand);
259 return {
static_cast<float>(
m(0, 0)),
static_cast<float>(
m(1, 0)),
static_cast<float>(
m(1, 1)),
static_cast<float>(
m(2, 0)),
static_cast<float>(
m(2, 1)),
static_cast<float>(
m(2, 2))};
268 GPUdi()
void setPropagateToPCA(
bool v = true) { mPropagateToPCA =
v; }
269 GPUdi()
void setMaxIter(
int n = 20) { mMaxIter =
n > 2 ?
n : 2; }
270 GPUdi()
void setMaxR(
float r = 200.) { mMaxR2 =
r *
r; }
271 GPUdi()
void setMaxDZIni(
float d = 4.) { mMaxDZIni = d; }
272 GPUdi()
void setMaxDXYIni(
float d = 4.) { mMaxDXYIni = d > 0 ? d : 1e9; }
273 GPUdi()
void setMaxChi2(
float chi2 = 999.) { mMaxChi2 = chi2; }
275 GPUdi()
void setMinParamChange(
float x = 1e-3) { mMinParamChange =
x > 1e-4 ?
x : 1.e-4; }
276 GPUdi()
void setMinRelChi2Change(
float r = 0.9) { mMinRelChi2Change =
r > 0.1 ?
r : 999.; }
277 GPUdi()
void setUseAbsDCA(
bool v) { mUseAbsDCA =
v; }
278 GPUdi()
void setWeightedFinalPCA(
bool v) { mWeightedFinalPCA =
v; }
279 GPUdi()
void setMaxDistance2ToMerge(
float v) { mMaxDist2ToMergeSeeds =
v; }
281 GPUdi()
void setUsePropagator(
bool v) { mUsePropagator =
v; }
282 GPUdi()
void setRefitWithMatCorr(
bool v) { mRefitWithMatCorr =
v; }
283 GPUdi()
void setMaxSnp(
float s) { mMaxSnp =
s; }
284 GPUdi()
void setMaxStep(
float s) { mMaxStep =
s; }
285 GPUdi()
void setMinXSeed(
float x) { mMinXSeed =
x; }
286 GPUdi()
void setCollinear(
bool isCollinear) { mIsCollinear = isCollinear; }
288 GPUdi()
int getNCandidates()
const {
return mCurHyp; }
289 GPUdi()
int getMaxIter()
const {
return mMaxIter; }
290 GPUdi() float getMaxR()
const {
return o2::gpu::GPUCommonMath::Sqrt(mMaxR2); }
291 GPUdi() float getMaxDZIni()
const {
return mMaxDZIni; }
292 GPUdi() float getMaxDXYIni()
const {
return mMaxDXYIni; }
293 GPUdi() float getMaxChi2()
const {
return mMaxChi2; }
294 GPUdi() float getMinParamChange()
const {
return mMinParamChange; }
295 GPUdi() float getBz()
const {
return mBz; }
296 GPUdi() float getMaxDistance2ToMerge()
const {
return mMaxDist2ToMergeSeeds; }
297 GPUdi() bool getUseAbsDCA()
const {
return mUseAbsDCA; }
298 GPUdi() bool getWeightedFinalPCA()
const {
return mWeightedFinalPCA; }
299 GPUdi() bool getPropagateToPCA()
const {
return mPropagateToPCA; }
301 GPUdi() bool getUsePropagator()
const {
return mUsePropagator; }
302 GPUdi() bool getRefitWithMatCorr()
const {
return mRefitWithMatCorr; }
303 GPUdi() float getMaxSnp()
const {
return mMaxSnp; }
304 GPUdi() float getMasStep()
const {
return mMaxStep; }
305 GPUdi() float getMinXSeed()
const {
return mMinXSeed; }
307 template <
class... Tr>
311 GPUdi()
int getFitterID()
const {
return mFitterID; }
313 GPUdi() size_t getCallID()
const {
return mCallID; }
317 GPUd()
bool calcInverseWeight();
318 GPUd()
void calcResidDerivatives();
319 GPUd()
void calcResidDerivativesNoErr();
321 GPUd()
void calcChi2Derivatives();
322 GPUd()
void calcChi2DerivativesNoErr();
325 GPUd()
void calcTrackResiduals();
326 GPUd()
void calcTrackDerivatives();
327 GPUd()
double calcChi2() const;
328 GPUd()
double calcChi2NoErr() const;
331 GPUd()
bool minimizeChi2NoErr();
332 GPUd()
bool roughDZCut() const;
333 GPUd()
bool closerToAlternative() const;
335 GPUd()
bool propagateParamToX(
o2::track::TrackPar&
t,
float x);
342 GPUd() float getTrackX(
int i,
int cand = 0)
const {
return getTrackPos(
i,
cand)[0]; }
347 GPUd() static
void addRotatedTrackInfo(
double* arrmat, const TrackAuxPar& taux, const TrackCovI& tcov)
355 arrmat[XX] += taux.cc * tcov.sxx - 2. * taux.cs * tcov.sxy + taux.ss * tcov.syy;
356 arrmat[XY] += taux.cs * (tcov.sxx - tcov.syy) + (taux.cc - taux.ss) * tcov.sxy;
357 arrmat[XZ] += taux.c * tcov.sxz - taux.s * tcov.syz;
358 arrmat[YY] += taux.ss * tcov.sxx + 2. * taux.cs * tcov.sxy + taux.cc * tcov.syy;
359 arrmat[YZ] += taux.s * tcov.sxz + taux.c * tcov.syz;
360 arrmat[ZZ] += tcov.szz;
364 GPUd() MatStd3D getTrackRotMatrix(
int i)
const
368 mat(0, 0) = mat(1, 1) = mTrAux[
i].c;
369 mat(0, 1) = -mTrAux[
i].s;
370 mat(1, 0) = mTrAux[
i].s;
375 GPUd() MatSym3D getTrackCovMatrix(
int i,
int cand = 0)
const
377 const auto& trc = mCandTr[mOrder[
cand]][
i];
380 mat(1, 1) = trc.getSigmaY2();
381 mat(2, 2) = trc.getSigmaZ2();
382 mat(2, 1) = trc.getSigmaZY();
387 template <
class T,
class... Tr>
390#ifndef GPUCA_GPUCODE_DEVICE
391 static_assert(std::is_convertible<T, Track>(),
"Wrong track type");
400 mAllowAltPreference =
true;
402 mPropFailed.fill(
false);
403 mTrPropDone.fill(
false);
418 mLoggerBadCov.clear();
419 mLoggerBadInv.clear();
420 mLoggerBadProp.clear();
428 std::array<std::array<Vec3D, N>, N> mDResidDx;
431 std::array<std::array<Vec3D, N>, N> mD2ResidDx2;
437 std::array<TrackAuxPar, N> mTrAux;
438 CrossInfo mCrossings;
440 std::array<ArrTrackCovI, MAXHYP> mTrcEInv;
441 std::array<ArrTrack, MAXHYP> mCandTr;
442 std::array<ArrTrCoef, MAXHYP> mTrCFVT;
443 std::array<ArrTrDer, MAXHYP> mTrDer;
444 std::array<ArrTrPos, MAXHYP> mTrPos;
445 std::array<ArrTrPos, MAXHYP> mTrRes;
446 std::array<Vec3D, MAXHYP> mPCA;
447 std::array<float, MAXHYP> mChi2 = {0};
448 std::array<int, MAXHYP> mNIters;
449 std::array<bool, MAXHYP> mTrPropDone{};
450 std::array<bool, MAXHYP> mPropFailed{};
451 mutable LogLogThrottler mLoggerBadCov{};
452 mutable LogLogThrottler mLoggerBadInv{};
453 mutable LogLogThrottler mLoggerBadProp{};
454 mutable LogLogThrottler mLoggerBadPCACov{};
456 std::array<int, MAXHYP> mOrder{0};
459 int mCrossIDAlt = -1;
461 std::array<FitStatus, MAXHYP> mFitStatus{};
462 bool mAllowAltPreference =
true;
463 bool mUseAbsDCA =
false;
464 bool mWeightedFinalPCA =
false;
465 bool mPropagateToPCA =
true;
466 bool mUsePropagator =
false;
467 bool mRefitWithMatCorr =
false;
468 bool mIsCollinear =
false;
472 float mMaxR2 = 200. * 200.;
473 float mMinXSeed = -50.;
474 float mMaxDZIni = 4.;
475 float mMaxDXYIni = 4.;
476 float mMinParamChange = 1e-3;
477 float mMinRelChi2Change = 0.9;
478 float mMaxChi2 = 100;
479 float mMaxDist2ToMergeSeeds = 1.;
480 float mMaxSnp = 0.95;
481 float mMaxStep = 2.0;
494 bool mOldMode =
true;
500template <
int N,
typename... Args>
501template <
class... Tr>
506 static_assert(
sizeof...(args) == N,
"incorrect number of input tracks");
509 for (
int i = 0;
i < N;
i++) {
510 mTrAux[
i].set(*mOrigTrPtr[
i], mBz);
512 if (!mCrossings.set(mTrAux[0], *mOrigTrPtr[0], mTrAux[1], *mOrigTrPtr[1], mMaxDXYIni, mIsCollinear)) {
513 mFitStatus[mCurHyp] = FitStatus::NoCrossing;
519 if (mCrossings.nDCA == MAXHYP) {
520 auto dst2 = (mCrossings.xDCA[0] - mCrossings.xDCA[1]) * (mCrossings.xDCA[0] - mCrossings.xDCA[1]) +
521 (mCrossings.yDCA[0] - mCrossings.yDCA[1]) * (mCrossings.yDCA[0] - mCrossings.yDCA[1]);
522 if (dst2 < mMaxDist2ToMergeSeeds) {
524 mCrossings.xDCA[0] = 0.5 * (mCrossings.xDCA[0] + mCrossings.xDCA[1]);
525 mCrossings.yDCA[0] = 0.5 * (mCrossings.yDCA[0] + mCrossings.yDCA[1]);
529 for (
int ic = 0; ic < mCrossings.nDCA; ic++) {
531 if (mCrossings.xDCA[ic] * mCrossings.xDCA[ic] + mCrossings.yDCA[ic] * mCrossings.yDCA[ic] > mMaxR2) {
532 mFitStatus[mCurHyp] = FitStatus::RejRadius;
536 mCrossIDAlt = (mCrossings.nDCA == 2 && mAllowAltPreference) ? 1 - ic : -1;
537 mPCA[mCurHyp][0] = mCrossings.xDCA[ic];
538 mPCA[mCurHyp][1] = mCrossings.yDCA[ic];
540 if (mUseAbsDCA ? minimizeChi2NoErr() : minimizeChi2()) {
541 mOrder[mCurHyp] = mCurHyp;
542 if (mPropagateToPCA && !propagateTracksToVertex(mCurHyp)) {
549 for (
int i = mCurHyp;
i--;) {
550 for (
int j =
i;
j--;) {
551 if (mChi2[mOrder[
i]] < mChi2[mOrder[
j]]) {
552 o2::gpu::GPUCommonMath::Swap(mOrder[
i], mOrder[
j]);
556 if (mUseAbsDCA && mWeightedFinalPCA) {
557 for (
int i = mCurHyp;
i--;) {
558 recalculatePCAWithErrors(
i);
565template <
int N,
typename... Args>
566GPUd() bool DCAFitterN<N, Args...>::calcPCACoefs()
569 if (!calcInverseWeight()) {
570 mFitStatus[mCurHyp] = FitStatus::FailInvWeight;
573 for (
int i = N;
i--;) {
574 const auto& taux = mTrAux[
i];
575 const auto& tcov = mTrcEInv[mCurHyp][
i];
577 miei[0][0] = taux.c * tcov.sxx - taux.s * tcov.sxy;
578 miei[0][1] = taux.c * tcov.sxy - taux.s * tcov.syy;
579 miei[0][2] = taux.c * tcov.sxz - taux.s * tcov.syz;
580 miei[1][0] = taux.s * tcov.sxx + taux.c * tcov.sxy;
581 miei[1][1] = taux.s * tcov.sxy + taux.c * tcov.syy;
582 miei[1][2] = taux.s * tcov.sxz + taux.c * tcov.syz;
583 miei[2][0] = tcov.sxz;
584 miei[2][1] = tcov.syz;
585 miei[2][2] = tcov.szz;
586 mTrCFVT[mCurHyp][
i] = mWeightInv * miei;
592template <
int N,
typename... Args>
593GPUd() bool DCAFitterN<N, Args...>::calcInverseWeight()
596 auto* arrmat = mWeightInv.Array();
597 memset(arrmat, 0,
sizeof(mWeightInv));
598 for (
int i = N;
i--;) {
599 addRotatedTrackInfo(arrmat, mTrAux[
i], mTrcEInv[mCurHyp][
i]);
602 return mWeightInv.Invert();
606template <
int N,
typename... Args>
607GPUd()
void DCAFitterN<N, Args...>::calcResidDerivatives()
611 for (
int i = N;
i--;) {
612 const auto& taux = mTrAux[
i];
613 for (
int j = N;
j--;) {
614 const auto& matT = mTrCFVT[mCurHyp][
j];
615 const auto& trDx = mTrDer[mCurHyp][
j];
616 auto& dr1 = mDResidDx[
i][
j];
617 auto& dr2 = mD2ResidDx2[
i][
j];
619 matMT[0][0] = taux.c * matT[0][0] + taux.s * matT[1][0];
620 matMT[0][1] = taux.c * matT[0][1] + taux.s * matT[1][1];
621 matMT[0][2] = taux.c * matT[0][2] + taux.s * matT[1][2];
622 matMT[1][0] = -taux.s * matT[0][0] + taux.c * matT[1][0];
623 matMT[1][1] = -taux.s * matT[0][1] + taux.c * matT[1][1];
624 matMT[1][2] = -taux.s * matT[0][2] + taux.c * matT[1][2];
625 matMT[2][0] = matT[2][0];
626 matMT[2][1] = matT[2][1];
627 matMT[2][2] = matT[2][2];
630 dr1[0] = -(matMT[0][0] + matMT[0][1] * trDx.dydx + matMT[0][2] * trDx.dzdx);
631 dr1[1] = -(matMT[1][0] + matMT[1][1] * trDx.dydx + matMT[1][2] * trDx.dzdx);
632 dr1[2] = -(matMT[2][0] + matMT[2][1] * trDx.dydx + matMT[2][2] * trDx.dzdx);
635 dr2[0] = -(matMT[0][1] * trDx.d2ydx2 + matMT[0][2] * trDx.d2zdx2);
636 dr2[1] = -(matMT[1][1] * trDx.d2ydx2 + matMT[1][2] * trDx.d2zdx2);
637 dr2[2] = -(matMT[2][1] * trDx.d2ydx2 + matMT[2][2] * trDx.d2zdx2);
644 dr2[1] += trDx.d2ydx2;
645 dr2[2] += trDx.d2zdx2;
652template <
int N,
typename... Args>
653GPUd()
void DCAFitterN<N, Args...>::calcResidDerivativesNoErr()
656 constexpr double NInv1 = 1. - NInv;
657 for (
int i = N;
i--;) {
658 const auto& trDxi = mTrDer[mCurHyp][
i];
659 auto& dr1ii = mDResidDx[
i][
i];
660 auto& dr2ii = mD2ResidDx2[
i][
i];
662 dr1ii[1] = NInv1 * trDxi.dydx;
663 dr1ii[2] = NInv1 * trDxi.dzdx;
666 dr2ii[1] = NInv1 * trDxi.d2ydx2;
667 dr2ii[2] = NInv1 * trDxi.d2zdx2;
669 for (
int j =
i;
j--;) {
670 auto& dr1ij = mDResidDx[
i][
j];
671 auto& dr1ji = mDResidDx[
j][
i];
672 const auto& trDxj = mTrDer[mCurHyp][
j];
673 auto cij = mCosDif[
i][
j], sij = mSinDif[
i][
j];
676 dr1ij[0] = -(cij + sij * trDxj.dydx);
677 dr1ij[1] = -(-sij + cij * trDxj.dydx);
678 dr1ij[2] = -trDxj.dzdx * NInv;
681 dr1ji[0] = -(cij - sij * trDxi.dydx);
682 dr1ji[1] = -(sij + cij * trDxi.dydx);
683 dr1ji[2] = -trDxi.dzdx * NInv;
685 auto& dr2ij = mD2ResidDx2[
i][
j];
686 auto& dr2ji = mD2ResidDx2[
j][
i];
688 dr2ij[0] = -sij * trDxj.d2ydx2;
689 dr2ij[1] = -cij * trDxj.d2ydx2;
690 dr2ij[2] = -trDxj.d2zdx2 * NInv;
693 dr2ji[0] = sij * trDxi.d2ydx2;
694 dr2ji[1] = -cij * trDxi.d2ydx2;
695 dr2ji[2] = -trDxi.d2zdx2 * NInv;
702template <
int N,
typename... Args>
703GPUd()
void DCAFitterN<N, Args...>::calcRMatrices()
706 for (
int i = N;
i--;) {
707 const auto& mi = mTrAux[
i];
708 for (
int j =
i;
j--;) {
709 const auto& mj = mTrAux[
j];
710 mCosDif[
i][
j] = (mi.c * mj.c + mi.s * mj.s) * NInv;
711 mSinDif[
i][
j] = (mi.s * mj.c - mi.c * mj.s) * NInv;
717template <
int N,
typename... Args>
718GPUd()
void DCAFitterN<N, Args...>::calcChi2Derivatives()
721 std::array<std::array<Vec3D, N>, N> covIDrDx;
724 for (
int i = N;
i--;) {
725 auto& dchi1 = mDChi2Dx[
i];
727 for (
int j = N;
j--;) {
728 const auto&
res = mTrRes[mCurHyp][
j];
729 const auto& covI = mTrcEInv[mCurHyp][
j];
730 const auto& dr1 = mDResidDx[
j][
i];
731 auto& cidr = covIDrDx[
i][
j];
732 cidr[0] = covI.sxx * dr1[0] + covI.sxy * dr1[1] + covI.sxz * dr1[2];
733 cidr[1] = covI.sxy * dr1[0] + covI.syy * dr1[1] + covI.syz * dr1[2];
734 cidr[2] = covI.sxz * dr1[0] + covI.syz * dr1[1] + covI.szz * dr1[2];
740 for (
int i = N;
i--;) {
741 for (
int j =
i + 1;
j--;) {
742 auto& dchi2 = mD2Chi2Dx2[
i][
j];
744 for (
int k = N; k--;) {
745 const auto& dr1j = mDResidDx[k][
j];
746 const auto& cidrkj = covIDrDx[
i][k];
751 if (mOldMode ? (k ==
j) : (
i ==
j)) {
752 const auto&
res = mTrRes[mCurHyp][k];
753 const auto& covI = mTrcEInv[mCurHyp][k];
754 const auto& dr2ij = mD2ResidDx2[k][mOldMode ?
j :
i];
755 dchi2 +=
res[0] * (covI.sxx * dr2ij[0] + covI.sxy * dr2ij[1] + covI.sxz * dr2ij[2]) +
756 res[1] * (covI.sxy * dr2ij[0] + covI.syy * dr2ij[1] + covI.syz * dr2ij[2]) +
757 res[2] * (covI.sxz * dr2ij[0] + covI.syz * dr2ij[1] + covI.szz * dr2ij[2]);
765template <
int N,
typename... Args>
766GPUd()
void DCAFitterN<N, Args...>::calcChi2DerivativesNoErr()
769 for (
int i = N;
i--;) {
770 auto& dchi1 = mDChi2Dx[
i];
772 for (
int k = N; k--;) {
773 const auto&
res = mTrRes[mCurHyp][k];
774 const auto& dr1 = mDResidDx[k][
i];
778 for (
int i = N;
i--;) {
779 for (
int j =
i + 1;
j--;) {
780 auto& dchi2 = mD2Chi2Dx2[
i][
j];
785 for (
int k = N; k--;) {
788 if (!mOldMode &&
i ==
j) {
797template <
int N,
typename... Args>
798GPUd()
void DCAFitterN<N, Args...>::calcPCA()
801 mPCA[mCurHyp] = mTrCFVT[mCurHyp][N - 1] * mTrPos[mCurHyp][N - 1];
802 for (
int i = N - 1;
i--;) {
803 mPCA[mCurHyp] += mTrCFVT[mCurHyp][
i] * mTrPos[mCurHyp][
i];
808template <
int N,
typename... Args>
809GPUd() bool DCAFitterN<N, Args...>::recalculatePCAWithErrors(
int cand)
812 if (isPropagateTracksToVertexDone(cand) && !propagateTracksToVertex(cand)) {
815 int saveCurHyp = mCurHyp;
816 mCurHyp = mOrder[cand];
818 for (
int i = N;
i--;) {
820 if (mLoggerBadCov.needToLog()) {
822 printf(
"fitter %d: error (%ld muted): overrode invalid track covariance from %s\n",
823 mFitterID, mLoggerBadCov.evCount, mCandTr[mCurHyp][
i].asString().c_str());
825 printf(
"fitter %d: error (%ld muted): overrode invalid track covariance cyy:%e czz:%e cyz:%e\n",
826 mFitterID, mLoggerBadCov.evCount, mCandTr[mCurHyp][
i].getSigmaY2(), mCandTr[mCurHyp][
i].getSigmaZ2(), mCandTr[mCurHyp][
i].getSigmaZY());
829 mFitStatus[mCurHyp] = FitStatus::FailInvCov;
830 if (mBadCovPolicy == Discard) {
832 }
else if (mBadCovPolicy == OverrideAndFlag) {
833 mPropFailed[mCurHyp] =
true;
837 if (!calcPCACoefs()) {
838 mCurHyp = saveCurHyp;
842 auto oldPCA = mPCA[mOrder[cand]];
844 mCurHyp = saveCurHyp;
849template <
int N,
typename... Args>
850GPUd()
void DCAFitterN<N, Args...>::calcPCANoErr()
853 auto& pca = mPCA[mCurHyp];
854 o2::math_utils::rotateZd(mTrPos[mCurHyp][N - 1][0], mTrPos[mCurHyp][N - 1][1], pca[0], pca[1], mTrAux[N - 1].s, mTrAux[N - 1].
c);
856 pca[2] = mTrPos[mCurHyp][N - 1][2];
857 for (
int i = N - 1;
i--;) {
863 pca[2] += mTrPos[mCurHyp][
i][2];
871template <
int N,
typename... Args>
872GPUd() double DCAFitterN<N, Args...>::calcCollinearInflation(
int cand)
const
876 std::array<std::array<double, 3>, N> u{};
879 for (
int i = 0;
i < N; ++
i) {
880 std::array<float, 3>
p{};
881 if (!getTrack(
i, cand).getPxPyPzGlo(p)) {
884 const float p2 =
p[0] *
p[0] +
p[1] *
p[1] +
p[2] *
p[2];
888 const double pI = 1. / o2::gpu::GPUCommonMath::Sqrt(
p2);
889 u[nu++] = {
p[0] * pI,
p[1] * pI,
p[2] * pI};
896 double sin2Mean = 0.;
898 for (
int i = 0;
i < nu; ++
i) {
899 for (
int j =
i + 1;
j < nu; ++
j) {
900 double cij = u[
i][0] * u[
j][0] + u[
i][1] * u[
j][1] + u[
i][2] * u[
j][2];
901 cij = o2::gpu::GPUCommonMath::Clamp(cij, -1., 1.);
902 sin2Mean += o2::gpu::GPUCommonMath::Max(0., 1. - cij * cij);
908 constexpr double Sin2Ref = 1.e-5;
909 constexpr double MaxInflation = 1.e4;
910 if (sin2Mean <= 0.) {
913 return sin2Mean < Sin2Ref ? o2::gpu::GPUCommonMath::Min(MaxInflation, Sin2Ref / sin2Mean) : 1.;
917template <
int N,
typename... Args>
918GPUd()
o2::math_utils::SMatrix<
double, 3, 3,
o2::math_utils::MatRepSym<
double, 3>>
DCAFitterN<N, Args...>::calcPCACovMatrix(
int cand)
const
931 for (
int i = N;
i--;) {
934 if (covTr.Invert()) {
939 if (nAdded && covm.Invert()) {
944 for (
int i = N;
i--;) {
950 auto* arrmat = info.Array();
951 memset(arrmat, 0,
sizeof(info));
952 const int ord = mOrder[cand];
953 for (
int i = N;
i--;) {
956 addRotatedTrackInfo(arrmat, mTrAux[
i], tcov);
958 const double maxDiag = o2::gpu::GPUCommonMath::Max(o2::gpu::GPUCommonMath::Max(info(0, 0), info(1, 1)), info(2, 2));
959 const double det2 = info(0, 0) * info(1, 1) - info(1, 0) * info(1, 0);
960 const double det3 = info(0, 0) * (info(1, 1) * info(2, 2) - info(2, 1) * info(2, 1)) -
961 info(1, 0) * (info(1, 0) * info(2, 2) - info(2, 1) * info(2, 0)) +
962 info(2, 0) * (info(1, 0) * info(2, 1) - info(1, 1) * info(2, 0));
963 constexpr double MinRelDet = 1.e-12;
964 const bool isWellConditionedInfo = maxDiag > 0. && info(0, 0) > 0. && det2 > 0. && det3 > MinRelDet * maxDiag * maxDiag * maxDiag;
965 if (isWellConditionedInfo) {
967 if (cov.Invert() && cov(0, 0) > 0. && cov(1, 1) > 0. && cov(2, 2) > 0.) {
977 if (mLoggerBadPCACov.needToLog()) {
978 printf(
"fitter %d: error (%ld muted): override ill-conditioned PCACovMatrix by dummy matrix\n", mFitterID, mLoggerBadPCACov.evCount);
983 memset(arrmat, 0,
sizeof(info));
991template <
int N,
typename... Args>
992GPUd()
void DCAFitterN<N, Args...>::calcTrackResiduals()
996 for (
int i = N;
i--;) {
997 mTrRes[mCurHyp][
i] = mTrPos[mCurHyp][
i];
998 vtxLoc = mPCA[mCurHyp];
1000 mTrRes[mCurHyp][
i] -= vtxLoc;
1005template <
int N,
typename... Args>
1006GPUdi()
void DCAFitterN<N, Args...>::calcTrackDerivatives()
1009 for (
int i = N;
i--;) {
1010 mTrDer[mCurHyp][
i].set(mCandTr[mCurHyp][
i], mBz);
1015template <
int N,
typename... Args>
1016GPUdi() double DCAFitterN<N, Args...>::calcChi2()
const
1020 for (
int i = N;
i--;) {
1021 const auto&
res = mTrRes[mCurHyp][
i];
1022 const auto& covI = mTrcEInv[mCurHyp][
i];
1023 chi2 +=
res[0] *
res[0] * covI.sxx +
res[1] *
res[1] * covI.syy +
res[2] *
res[2] * covI.szz +
1024 2. * (
res[0] *
res[1] * covI.sxy +
res[0] *
res[2] * covI.sxz +
res[1] *
res[2] * covI.syz);
1030template <
int N,
typename... Args>
1031GPUdi() double DCAFitterN<N, Args...>::calcChi2NoErr()
const
1035 for (
int i = N;
i--;) {
1036 const auto&
res = mTrRes[mCurHyp][
i];
1043template <
int N,
typename... Args>
1044GPUd() bool DCAFitterN<N, Args...>::correctTracks(const VecND& corrX)
1055 for (
int i = N;
i--;) {
1056 const auto& trDer = mTrDer[mCurHyp][
i];
1057 auto dx2h = 0.5 * corrX[
i] * corrX[
i];
1058 mTrPos[mCurHyp][
i][0] -= corrX[
i];
1059 mTrPos[mCurHyp][
i][1] -= trDer.dydx * corrX[
i] - dx2h * trDer.d2ydx2;
1060 mTrPos[mCurHyp][
i][2] -= trDer.dzdx * corrX[
i] - dx2h * trDer.d2zdx2;
1064 for (
int i = N;
i--;) {
1065 auto& trc = mCandTr[mCurHyp][
i];
1066 const float x =
static_cast<float>(mTrPos[mCurHyp][
i][0] - corrX[
i]);
1067 const bool propagated = mUseAbsDCA ? trc.propagateParamTo(
x, mBz) : trc.propagateTo(
x, mBz);
1069 mPropFailed[mCurHyp] =
true;
1070 if (mLoggerBadProp.needToLog()) {
1071#ifndef GPUCA_GPUCODE
1072 printf(
"fitter %d: error (%ld muted): Newton step propagation to %.4f failed for %s\n", mFitterID, mLoggerBadProp.evCount,
x, trc.asString().c_str());
1074 printf(
"fitter %d: error (%ld muted): Newton step propagation to %.4f failed\n", mFitterID, mLoggerBadProp.evCount,
x);
1079 setTrackPos(mTrPos[mCurHyp][
i], trc);
1085template <
int N,
typename... Args>
1086GPUd() bool DCAFitterN<N, Args...>::propagateTracksToVertex(
int icand)
1089 int ord = mOrder[icand];
1090 if (mTrPropDone[ord]) {
1095 if (mRefitWithMatCorr) {
1096 int curHypSav = mCurHyp, curCrosIDAlt = mCrossIDAlt;
1099 auto restore = [
this, curHypSav, curCrosIDAlt]() { this->mCurHyp = curHypSav; this->mCrossIDAlt = curCrosIDAlt; };
1100 if (!(mUseAbsDCA ? minimizeChi2NoErr() : minimizeChi2())) {
1107 for (
int i = N;
i--;) {
1108 if (mUseAbsDCA || mUsePropagator || mMatCorr != o2::base::Propagator::MatCorrType::USEMatCorrNONE) {
1109 mCandTr[ord][
i] = *mOrigTrPtr[
i];
1111 auto x = mTrAux[
i].c * mPCA[ord][0] + mTrAux[
i].s * mPCA[ord][1];
1112 if (!propagateToX(mCandTr[ord][
i],
x)) {
1117 mTrPropDone[ord] =
true;
1122template <
int N,
typename... Args>
1126 int ord = mOrder[icand];
1128 if (!mTrPropDone[ord]) {
1129 auto x = mTrAux[
i].c * mPCA[ord][0] + mTrAux[
i].s * mPCA[ord][1];
1130 if (!propagateParamToX(trc,
x)) {
1138template <
int N,
typename... Args>
1139GPUdi() double DCAFitterN<N, Args...>::getAbsMax(const VecND&
v)
1142 for (
int i = N;
i--;) {
1143 auto vai = o2::gpu::GPUCommonMath::Abs(
v[
i]);
1152template <
int N,
typename... Args>
1153GPUd() bool DCAFitterN<N, Args...>::minimizeChi2()
1156 for (
int i = N;
i--;) {
1157 mCandTr[mCurHyp][
i] = *mOrigTrPtr[
i];
1158 auto x = mTrAux[
i].c * mPCA[mCurHyp][0] + mTrAux[
i].s * mPCA[mCurHyp][1];
1159 if (
x < mMinXSeed) {
1160 mFitStatus[mCurHyp] = FitStatus::RejTrackX;
1163 if (!propagateToX(mCandTr[mCurHyp][
i],
x)) {
1166 setTrackPos(mTrPos[mCurHyp][
i], mCandTr[mCurHyp][
i]);
1168 if (mLoggerBadCov.needToLog()) {
1169#ifndef GPUCA_GPUCODE
1170 printf(
"fitter %d: error (%ld muted): overrode invalid track covariance from %s\n",
1171 mFitterID, mLoggerBadCov.evCount, mCandTr[mCurHyp][
i].asString().c_str());
1173 printf(
"fitter %d: error (%ld muted): overrode invalid track covariance cyy:%e czz:%e cyz:%e\n",
1174 mFitterID, mLoggerBadCov.evCount, mCandTr[mCurHyp][
i].getSigmaY2(), mCandTr[mCurHyp][
i].getSigmaZ2(), mCandTr[mCurHyp][
i].getSigmaZY());
1177 mFitStatus[mCurHyp] = FitStatus::FailInvCov;
1178 if (mBadCovPolicy == Discard) {
1180 }
else if (mBadCovPolicy == OverrideAndFlag) {
1181 mPropFailed[mCurHyp] =
true;
1186 if (mMaxDZIni > 0 && !roughDZCut()) {
1187 mFitStatus[mCurHyp] = FitStatus::RejTrackRoughZ;
1191 if (!calcPCACoefs()) {
1195 calcTrackResiduals();
1196 float chi2Upd, chi2 = calcChi2();
1198 calcTrackDerivatives();
1199 calcResidDerivatives();
1200 calcChi2Derivatives();
1203 if (!mD2Chi2Dx2.Invert()) {
1204 if (mLoggerBadInv.needToLog()) {
1205 printf(
"fitter %d: error (%ld muted): Inversion failed\n", mFitterID, mLoggerBadCov.evCount);
1207 mFitStatus[mCurHyp] = FitStatus::FailInv2ndDeriv;
1210 VecND dx = mD2Chi2Dx2 * mDChi2Dx;
1211 if (!correctTracks(dx)) {
1212 mFitStatus[mCurHyp] = FitStatus::FailCorrTracks;
1216 if (mCrossIDAlt >= 0 && closerToAlternative()) {
1217 mFitStatus[mCurHyp] = FitStatus::FailCloserAlt;
1218 mAllowAltPreference =
false;
1221 calcTrackResiduals();
1222 chi2Upd = calcChi2();
1223 if (getAbsMax(dx) < mMinParamChange || chi2Upd > chi2 * mMinRelChi2Change) {
1225 mFitStatus[mCurHyp] = FitStatus::Converged;
1229 }
while (++mNIters[mCurHyp] < mMaxIter);
1230 if (mNIters[mCurHyp] == mMaxIter) {
1231 mFitStatus[mCurHyp] = FitStatus::MaxIter;
1234 mChi2[mCurHyp] = chi2 * NInv;
1235 if (mChi2[mCurHyp] >= mMaxChi2) {
1236 mFitStatus[mCurHyp] = FitStatus::RejChi2Max;
1243template <
int N,
typename... Args>
1244GPUd() bool DCAFitterN<N, Args...>::minimizeChi2NoErr()
1248 for (
int i = N;
i--;) {
1249 mCandTr[mCurHyp][
i] = *mOrigTrPtr[
i];
1250 auto x = mTrAux[
i].c * mPCA[mCurHyp][0] + mTrAux[
i].s * mPCA[mCurHyp][1];
1251 if (
x < mMinXSeed) {
1252 mFitStatus[mCurHyp] = FitStatus::RejTrackX;
1255 if (!propagateParamToX(mCandTr[mCurHyp][
i],
x)) {
1258 setTrackPos(mTrPos[mCurHyp][
i], mCandTr[mCurHyp][
i]);
1260 if (mMaxDZIni > 0 && !roughDZCut()) {
1261 mFitStatus[mCurHyp] = FitStatus::RejTrackRoughZ;
1266 calcTrackResiduals();
1267 float chi2Upd, chi2 = calcChi2NoErr();
1269 calcTrackDerivatives();
1270 calcResidDerivativesNoErr();
1271 calcChi2DerivativesNoErr();
1274 if (!mD2Chi2Dx2.Invert()) {
1275 if (mLoggerBadInv.needToLog()) {
1276 printf(
"fitter %d: error (%ld muted): Inversion failed\n", mFitterID, mLoggerBadCov.evCount);
1278 mFitStatus[mCurHyp] = FitStatus::FailInv2ndDeriv;
1281 VecND dx = mD2Chi2Dx2 * mDChi2Dx;
1282 if (!correctTracks(dx)) {
1283 mFitStatus[mCurHyp] = FitStatus::FailCorrTracks;
1287 if (mCrossIDAlt >= 0 && closerToAlternative()) {
1288 mFitStatus[mCurHyp] = FitStatus::FailCloserAlt;
1289 mAllowAltPreference =
false;
1292 calcTrackResiduals();
1293 chi2Upd = calcChi2NoErr();
1294 if (getAbsMax(dx) < mMinParamChange || chi2Upd > chi2 * mMinRelChi2Change) {
1296 mFitStatus[mCurHyp] = FitStatus::Converged;
1300 }
while (++mNIters[mCurHyp] < mMaxIter);
1301 if (mNIters[mCurHyp] == mMaxIter) {
1302 mFitStatus[mCurHyp] = FitStatus::MaxIter;
1305 mChi2[mCurHyp] = chi2 * NInv;
1306 if (mChi2[mCurHyp] >= mMaxChi2) {
1307 mFitStatus[mCurHyp] = FitStatus::RejChi2Max;
1314template <
int N,
typename... Args>
1315GPUd() bool DCAFitterN<N, Args...>::roughDZCut()
const
1319 for (
int i = N; accept &&
i--;) {
1320 for (
int j =
i;
j--;) {
1321 if (o2::gpu::GPUCommonMath::Abs(mCandTr[mCurHyp][
i].getZ() - mCandTr[mCurHyp][
j].getZ()) > mMaxDZIni) {
1331template <
int N,
typename... Args>
1332GPUd() bool DCAFitterN<N, Args...>::closerToAlternative()
const
1335 auto dxCur = mPCA[mCurHyp][0] - mCrossings.xDCA[mCrossIDCur], dyCur = mPCA[mCurHyp][1] - mCrossings.yDCA[mCrossIDCur];
1336 auto dxAlt = mPCA[mCurHyp][0] - mCrossings.xDCA[mCrossIDAlt], dyAlt = mPCA[mCurHyp][1] - mCrossings.yDCA[mCrossIDAlt];
1337 return dxCur * dxCur + dyCur * dyCur > dxAlt * dxAlt + dyAlt * dyAlt;
1341template <
int N,
typename... Args>
1344#ifndef GPUCA_GPUCODE_DEVICE
1345 LOG(info) << N <<
"-prong vertex fitter in " << (mUseAbsDCA ?
"abs." :
"weighted") <<
" distance minimization mode, collinear tracks mode: " << (mIsCollinear ?
"ON" :
"OFF");
1346 LOG(info) <<
"Bz: " << mBz <<
" MaxIter: " << mMaxIter <<
" MaxChi2: " << mMaxChi2 <<
" MatCorrType: " <<
int(mMatCorr);
1347 LOG(info) <<
"Stopping condition: Max.param change < " << mMinParamChange <<
" Rel.Chi2 change > " << mMinRelChi2Change;
1348 LOG(info) <<
"Discard candidates for : Rvtx > " << getMaxR() <<
" DZ between tracks > " << mMaxDZIni;
1349 LOG(info) <<
"PropagateToPCA:" << mPropagateToPCA <<
" WeightedFinalPCA:" << mWeightedFinalPCA <<
" UsePropagator:" << mUsePropagator <<
" RefitWithMatCorr:" << mRefitWithMatCorr;
1351 for (
int i = 0;
i < mCrossings.nDCA;
i++) {
1352 rep += fmt::format(
"seed{}:{}/{} ",
i, mTrPropDone[
i], mPropFailed[
i]);
1354 LOG(info) <<
"Last call: NCand:" << mCurHyp <<
" from " << mCrossings.nDCA <<
" seeds, prop.done/failed: " << rep;
1357 printf(
"%d-prong vertex fitter in abs. distance minimization mode\n", N);
1359 printf(
"%d-prong vertex fitter in weighted distance minimization mode\n", N);
1361 printf(
"Bz: %1.f MaxIter: %3.d MaxChi2: %2.3f\n", mBz, mMaxIter, mMaxChi2);
1362 printf(
"Stopping condition: Max.param change < %2.3f Rel.Chi2 change > %2.3f\n", mMinParamChange, mMinRelChi2Change);
1363 printf(
"Discard candidates for : Rvtx > %2.3f DZ between tracks > %2.3f\n", getMaxR(), mMaxDZIni);
1368template <
int N,
typename... Args>
1369GPUd()
o2::track::
TrackParCov DCAFitterN<N, Args...>::createParentTrackParCov(
int cand,
bool sectorAlpha)
const
1371 std::array<float, o2::track::kLabCovMatSize> covV = {0.};
1372 std::array<float, 3> pvecV = {0.};
1374 for (
int it = 0; it < N; it++) {
1375 const auto& trc = getTrack(it, cand);
1376 std::array<float, 3> pvecT = {0.};
1377 std::array<float, o2::track::kLabCovMatSize> covT = {0.};
1378 trc.getPxPyPzGlo(pvecT);
1384 trc.getCovXYZPxPyPzGlo(covT);
1385 constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20};
1386 for (
int i = 0;
i < 6;
i++) {
1387 covV[MomInd[
i]] += covT[MomInd[
i]];
1389 for (
int i = 0;
i < 3;
i++) {
1390 pvecV[
i] += pvecT[
i];
1392 q += trc.getCharge();
1394 auto covVtxV = calcPCACovMatrix(cand);
1395 covV[0] = covVtxV(0, 0);
1396 covV[1] = covVtxV(1, 0);
1397 covV[2] = covVtxV(1, 1);
1398 covV[3] = covVtxV(2, 0);
1399 covV[4] = covVtxV(2, 1);
1400 covV[5] = covVtxV(2, 2);
1405template <
int N,
typename... Args>
1406GPUd()
o2::track::TrackPar DCAFitterN<N, Args...>::createParentTrackPar(
int cand,
bool sectorAlpha)
const
1408 const auto& trP = getTrack(0, cand);
1409 const auto& trN = getTrack(1, cand);
1410 const auto& wvtx = getPCACandidate(cand);
1411 std::array<float, 3> pvecV = {0.};
1413 for (
int it = 0; it < N; it++) {
1414 const auto& trc = getTrack(it, cand);
1415 std::array<float, 3> pvecT = {0.};
1416 trc.getPxPyPzGlo(pvecT);
1417 for (
int i = 0;
i < 3;
i++) {
1418 pvecV[
i] += pvecT[
i];
1420 q += trc.getCharge();
1422 const std::array<float, 3>
vertex = {(float)wvtx[0], (
float)wvtx[1], (float)wvtx[2]};
1427template <
int N,
typename... Args>
1428GPUdi() bool DCAFitterN<N, Args...>::propagateParamToX(
o2::track::TrackPar& t,
float x)
1431 if (mUsePropagator || mMatCorr != o2::base::Propagator::MatCorrType::USEMatCorrNONE) {
1432#ifndef GPUCA_GPUCODE
1436 res = t.propagateParamTo(
x, mBz);
1439 mFitStatus[mCurHyp] = FitStatus::FailProp;
1440 mPropFailed[mCurHyp] =
true;
1441 if (mLoggerBadProp.needToLog()) {
1442#ifndef GPUCA_GPUCODE
1443 printf(
"fitter %d: error (%ld muted): propagation to %.4f failed for %s\n", mFitterID, mLoggerBadProp.evCount,
x, t.asString().c_str());
1445 printf(
"fitter %d: error (%ld muted): propagation to %.4f failed\n", mFitterID, mLoggerBadProp.evCount,
x);
1453template <
int N,
typename... Args>
1457 if (mUsePropagator || mMatCorr != o2::base::Propagator::MatCorrType::USEMatCorrNONE) {
1458#ifndef GPUCA_GPUCODE
1462 res = t.propagateTo(
x, mBz);
1465 mFitStatus[mCurHyp] = FitStatus::FailProp;
1466 mPropFailed[mCurHyp] =
true;
1467 if (mLoggerBadProp.needToLog()) {
1468#ifndef GPUCA_GPUCODE
1469 printf(
"fitter %d: error (%ld muted): propagation to %.4f failed for %s\n", mFitterID, mLoggerBadProp.evCount,
x, t.asString().c_str());
1471 printf(
"fitter %d: error (%ld muted): propagation to %.4f failed\n", mFitterID, mLoggerBadProp.evCount,
x);
1483template <
typename Fitter>
1484void print(
const int nBlocks,
const int nThreads, Fitter& ft);
1486template <
typename Fitter,
class... Tr>
1487int process(
const int nBlocks,
const int nThreads, Fitter&, Tr&... args);
1489template <
class Fitter,
class... Tr>
1490void processBulk(
const int nBlocks,
const int nThreads,
const int nBatches, std::vector<Fitter>& fitters, std::vector<int>& results, std::vector<Tr>&... args);