225 GPUd()
bool recalculatePCAWithErrors(
int cand = 0);
227 GPUd()
double calcCollinearInflation(
int cand) const;
232 auto m = calcPCACovMatrix(
cand);
233 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))};
242 GPUdi()
void setPropagateToPCA(
bool v = true) { mPropagateToPCA =
v; }
243 GPUdi()
void setMaxIter(
int n = 20) { mMaxIter =
n > 2 ?
n : 2; }
244 GPUdi()
void setMaxR(
float r = 200.) { mMaxR2 =
r *
r; }
245 GPUdi()
void setMaxDZIni(
float d = 4.) { mMaxDZIni = d; }
246 GPUdi()
void setMaxDXYIni(
float d = 4.) { mMaxDXYIni = d > 0 ? d : 1e9; }
247 GPUdi()
void setMaxChi2(
float chi2 = 999.) { mMaxChi2 = chi2; }
249 GPUdi()
void setMinParamChange(
float x = 1e-3) { mMinParamChange =
x > 1e-4 ?
x : 1.e-4; }
250 GPUdi()
void setMinRelChi2Change(
float r = 0.9) { mMinRelChi2Change =
r > 0.1 ?
r : 999.; }
251 GPUdi()
void setUseAbsDCA(
bool v) { mUseAbsDCA =
v; }
252 GPUdi()
void setWeightedFinalPCA(
bool v) { mWeightedFinalPCA =
v; }
253 GPUdi()
void setMaxDistance2ToMerge(
float v) { mMaxDist2ToMergeSeeds =
v; }
255 GPUdi()
void setUsePropagator(
bool v) { mUsePropagator =
v; }
256 GPUdi()
void setRefitWithMatCorr(
bool v) { mRefitWithMatCorr =
v; }
257 GPUdi()
void setMaxSnp(
float s) { mMaxSnp =
s; }
258 GPUdi()
void setMaxStep(
float s) { mMaxStep =
s; }
259 GPUdi()
void setMinXSeed(
float x) { mMinXSeed =
x; }
260 GPUdi()
void setCollinear(
bool isCollinear) { mIsCollinear = isCollinear; }
262 GPUdi()
int getNCandidates()
const {
return mCurHyp; }
263 GPUdi()
int getMaxIter()
const {
return mMaxIter; }
264 GPUdi() float getMaxR()
const {
return o2::gpu::GPUCommonMath::Sqrt(mMaxR2); }
265 GPUdi() float getMaxDZIni()
const {
return mMaxDZIni; }
266 GPUdi() float getMaxDXYIni()
const {
return mMaxDXYIni; }
267 GPUdi() float getMaxChi2()
const {
return mMaxChi2; }
268 GPUdi() float getMinParamChange()
const {
return mMinParamChange; }
269 GPUdi() float getBz()
const {
return mBz; }
270 GPUdi() float getMaxDistance2ToMerge()
const {
return mMaxDist2ToMergeSeeds; }
271 GPUdi() bool getUseAbsDCA()
const {
return mUseAbsDCA; }
272 GPUdi() bool getWeightedFinalPCA()
const {
return mWeightedFinalPCA; }
273 GPUdi() bool getPropagateToPCA()
const {
return mPropagateToPCA; }
275 GPUdi() bool getUsePropagator()
const {
return mUsePropagator; }
276 GPUdi() bool getRefitWithMatCorr()
const {
return mRefitWithMatCorr; }
277 GPUdi() float getMaxSnp()
const {
return mMaxSnp; }
278 GPUdi() float getMasStep()
const {
return mMaxStep; }
279 GPUdi() float getMinXSeed()
const {
return mMinXSeed; }
281 template <
class... Tr>
285 GPUdi()
int getFitterID()
const {
return mFitterID; }
287 GPUdi() size_t getCallID()
const {
return mCallID; }
291 GPUd()
bool calcInverseWeight();
292 GPUd()
void calcResidDerivatives();
293 GPUd()
void calcResidDerivativesNoErr();
295 GPUd()
void calcChi2Derivatives();
296 GPUd()
void calcChi2DerivativesNoErr();
299 GPUd()
void calcTrackResiduals();
300 GPUd()
void calcTrackDerivatives();
301 GPUd()
double calcChi2() const;
302 GPUd()
double calcChi2NoErr() const;
305 GPUd()
bool minimizeChi2NoErr();
306 GPUd()
bool roughDZCut() const;
307 GPUd()
bool closerToAlternative() const;
309 GPUd()
bool propagateParamToX(
o2::track::TrackPar&
t,
float x);
316 GPUd() float getTrackX(
int i,
int cand = 0)
const {
return getTrackPos(
i,
cand)[0]; }
318 GPUd() MatStd3D getTrackRotMatrix(
int i) const
322 mat(0, 0) = mat(1, 1) = mTrAux[
i].c;
323 mat(0, 1) = -mTrAux[
i].s;
324 mat(1, 0) = mTrAux[
i].s;
329 template <
class T,
class... Tr>
332#ifndef GPUCA_GPUCODE_DEVICE
333 static_assert(std::is_convertible<T, Track>(),
"Wrong track type");
342 mAllowAltPreference =
true;
344 mPropFailed.fill(
false);
345 mTrPropDone.fill(
false);
360 mLoggerBadCov.clear();
361 mLoggerBadInv.clear();
362 mLoggerBadProp.clear();
370 std::array<std::array<Vec3D, N>, N> mDResidDx;
373 std::array<std::array<Vec3D, N>, N> mD2ResidDx2;
379 std::array<TrackAuxPar, N> mTrAux;
380 CrossInfo mCrossings;
382 std::array<ArrTrackCovI, MAXHYP> mTrcEInv;
383 std::array<ArrTrack, MAXHYP> mCandTr;
384 std::array<ArrTrCoef, MAXHYP> mTrCFVT;
385 std::array<ArrTrDer, MAXHYP> mTrDer;
386 std::array<ArrTrPos, MAXHYP> mTrPos;
387 std::array<ArrTrPos, MAXHYP> mTrRes;
388 std::array<Vec3D, MAXHYP> mPCA;
389 std::array<float, MAXHYP> mChi2 = {0};
390 std::array<int, MAXHYP> mNIters;
391 std::array<bool, MAXHYP> mTrPropDone{};
392 std::array<bool, MAXHYP> mPropFailed{};
393 mutable LogLogThrottler mLoggerBadCov{};
394 mutable LogLogThrottler mLoggerBadInv{};
395 mutable LogLogThrottler mLoggerBadProp{};
396 mutable LogLogThrottler mLoggerBadPCACov{};
398 std::array<int, MAXHYP> mOrder{0};
401 int mCrossIDAlt = -1;
403 std::array<FitStatus, MAXHYP> mFitStatus{};
404 bool mAllowAltPreference =
true;
405 bool mUseAbsDCA =
false;
406 bool mWeightedFinalPCA =
false;
407 bool mPropagateToPCA =
true;
408 bool mUsePropagator =
false;
409 bool mRefitWithMatCorr =
false;
410 bool mIsCollinear =
false;
414 float mMaxR2 = 200. * 200.;
415 float mMinXSeed = -50.;
416 float mMaxDZIni = 4.;
417 float mMaxDXYIni = 4.;
418 float mMinParamChange = 1e-3;
419 float mMinRelChi2Change = 0.9;
420 float mMaxChi2 = 100;
421 float mMaxDist2ToMergeSeeds = 1.;
422 float mMaxSnp = 0.95;
423 float mMaxStep = 2.0;
430template <
int N,
typename... Args>
431template <
class... Tr>
436 static_assert(
sizeof...(args) == N,
"incorrect number of input tracks");
439 for (
int i = 0;
i < N;
i++) {
440 mTrAux[
i].set(*mOrigTrPtr[
i], mBz);
442 if (!mCrossings.set(mTrAux[0], *mOrigTrPtr[0], mTrAux[1], *mOrigTrPtr[1], mMaxDXYIni, mIsCollinear)) {
443 mFitStatus[mCurHyp] = FitStatus::NoCrossing;
449 if (mCrossings.nDCA == MAXHYP) {
450 auto dst2 = (mCrossings.xDCA[0] - mCrossings.xDCA[1]) * (mCrossings.xDCA[0] - mCrossings.xDCA[1]) +
451 (mCrossings.yDCA[0] - mCrossings.yDCA[1]) * (mCrossings.yDCA[0] - mCrossings.yDCA[1]);
452 if (dst2 < mMaxDist2ToMergeSeeds) {
454 mCrossings.xDCA[0] = 0.5 * (mCrossings.xDCA[0] + mCrossings.xDCA[1]);
455 mCrossings.yDCA[0] = 0.5 * (mCrossings.yDCA[0] + mCrossings.yDCA[1]);
459 for (
int ic = 0; ic < mCrossings.nDCA; ic++) {
461 if (mCrossings.xDCA[ic] * mCrossings.xDCA[ic] + mCrossings.yDCA[ic] * mCrossings.yDCA[ic] > mMaxR2) {
462 mFitStatus[mCurHyp] = FitStatus::RejRadius;
466 mCrossIDAlt = (mCrossings.nDCA == 2 && mAllowAltPreference) ? 1 - ic : -1;
467 mPCA[mCurHyp][0] = mCrossings.xDCA[ic];
468 mPCA[mCurHyp][1] = mCrossings.yDCA[ic];
470 if (mUseAbsDCA ? minimizeChi2NoErr() : minimizeChi2()) {
471 mOrder[mCurHyp] = mCurHyp;
472 if (mPropagateToPCA && !propagateTracksToVertex(mCurHyp)) {
479 for (
int i = mCurHyp;
i--;) {
480 for (
int j =
i;
j--;) {
481 if (mChi2[mOrder[
i]] < mChi2[mOrder[
j]]) {
482 o2::gpu::GPUCommonMath::Swap(mOrder[
i], mOrder[
j]);
486 if (mUseAbsDCA && mWeightedFinalPCA) {
487 for (
int i = mCurHyp;
i--;) {
488 recalculatePCAWithErrors(
i);
495template <
int N,
typename... Args>
496GPUd() bool DCAFitterN<N, Args...>::calcPCACoefs()
499 if (!calcInverseWeight()) {
500 mFitStatus[mCurHyp] = FitStatus::FailInvWeight;
503 for (
int i = N;
i--;) {
504 const auto& taux = mTrAux[
i];
505 const auto& tcov = mTrcEInv[mCurHyp][
i];
507 miei[0][0] = taux.c * tcov.sxx - taux.s * tcov.sxy;
508 miei[0][1] = taux.c * tcov.sxy - taux.s * tcov.syy;
509 miei[0][2] = taux.c * tcov.sxz - taux.s * tcov.syz;
510 miei[1][0] = taux.s * tcov.sxx + taux.c * tcov.sxy;
511 miei[1][1] = taux.s * tcov.sxy + taux.c * tcov.syy;
512 miei[1][2] = taux.s * tcov.sxz + taux.c * tcov.syz;
513 miei[2][0] = tcov.sxz;
514 miei[2][1] = tcov.syz;
515 miei[2][2] = tcov.szz;
516 mTrCFVT[mCurHyp][
i] = mWeightInv * miei;
522template <
int N,
typename... Args>
523GPUd() bool DCAFitterN<N, Args...>::calcInverseWeight()
526 auto* arrmat = mWeightInv.Array();
527 memset(arrmat, 0,
sizeof(mWeightInv));
534 for (
int i = N;
i--;) {
535 const auto& taux = mTrAux[
i];
536 const auto& tcov = mTrcEInv[mCurHyp][
i];
537 arrmat[XX] += taux.cc * tcov.sxx - 2. * taux.cs * tcov.sxy + taux.ss * tcov.syy;
538 arrmat[XY] += taux.cs * (tcov.sxx - tcov.syy) + (taux.cc - taux.ss) * tcov.sxy;
539 arrmat[XZ] += taux.c * tcov.sxz - taux.s * tcov.syz;
540 arrmat[YY] += taux.ss * tcov.sxx + 2. * taux.cs * tcov.sxy + taux.cc * tcov.syy;
541 arrmat[YZ] += taux.s * tcov.sxz + taux.c * tcov.syz;
542 arrmat[ZZ] += tcov.szz;
545 return mWeightInv.Invert();
549template <
int N,
typename... Args>
550GPUd()
void DCAFitterN<N, Args...>::calcResidDerivatives()
554 for (
int i = N;
i--;) {
555 const auto& taux = mTrAux[
i];
556 for (
int j = N;
j--;) {
557 const auto& matT = mTrCFVT[mCurHyp][
j];
558 const auto& trDx = mTrDer[mCurHyp][
j];
559 auto& dr1 = mDResidDx[
i][
j];
560 auto& dr2 = mD2ResidDx2[
i][
j];
562 matMT[0][0] = taux.c * matT[0][0] + taux.s * matT[1][0];
563 matMT[0][1] = taux.c * matT[0][1] + taux.s * matT[1][1];
564 matMT[0][2] = taux.c * matT[0][2] + taux.s * matT[1][2];
565 matMT[1][0] = -taux.s * matT[0][0] + taux.c * matT[1][0];
566 matMT[1][1] = -taux.s * matT[0][1] + taux.c * matT[1][1];
567 matMT[1][2] = -taux.s * matT[0][2] + taux.c * matT[1][2];
568 matMT[2][0] = matT[2][0];
569 matMT[2][1] = matT[2][1];
570 matMT[2][2] = matT[2][2];
573 dr1[0] = -(matMT[0][0] + matMT[0][1] * trDx.dydx + matMT[0][2] * trDx.dzdx);
574 dr1[1] = -(matMT[1][0] + matMT[1][1] * trDx.dydx + matMT[1][2] * trDx.dzdx);
575 dr1[2] = -(matMT[2][0] + matMT[2][1] * trDx.dydx + matMT[2][2] * trDx.dzdx);
578 dr2[0] = -(matMT[0][1] * trDx.d2ydx2 + matMT[0][2] * trDx.d2zdx2);
579 dr2[1] = -(matMT[1][1] * trDx.d2ydx2 + matMT[1][2] * trDx.d2zdx2);
580 dr2[2] = -(matMT[2][1] * trDx.d2ydx2 + matMT[2][2] * trDx.d2zdx2);
587 dr2[1] += trDx.d2ydx2;
588 dr2[2] += trDx.d2zdx2;
595template <
int N,
typename... Args>
596GPUd()
void DCAFitterN<N, Args...>::calcResidDerivativesNoErr()
599 constexpr double NInv1 = 1. - NInv;
600 for (
int i = N;
i--;) {
601 const auto& trDxi = mTrDer[mCurHyp][
i];
602 auto& dr1ii = mDResidDx[
i][
i];
603 auto& dr2ii = mD2ResidDx2[
i][
i];
605 dr1ii[1] = NInv1 * trDxi.dydx;
606 dr1ii[2] = NInv1 * trDxi.dzdx;
609 dr2ii[1] = NInv1 * trDxi.d2ydx2;
610 dr2ii[2] = NInv1 * trDxi.d2zdx2;
612 for (
int j =
i;
j--;) {
613 auto& dr1ij = mDResidDx[
i][
j];
614 auto& dr1ji = mDResidDx[
j][
i];
615 const auto& trDxj = mTrDer[mCurHyp][
j];
616 auto cij = mCosDif[
i][
j], sij = mSinDif[
i][
j];
619 dr1ij[0] = -(cij + sij * trDxj.dydx);
620 dr1ij[1] = -(-sij + cij * trDxj.dydx);
621 dr1ij[2] = -trDxj.dzdx * NInv;
624 dr1ji[0] = -(cij - sij * trDxi.dydx);
625 dr1ji[1] = -(sij + cij * trDxi.dydx);
626 dr1ji[2] = -trDxi.dzdx * NInv;
628 auto& dr2ij = mD2ResidDx2[
i][
j];
629 auto& dr2ji = mD2ResidDx2[
j][
i];
631 dr2ij[0] = -sij * trDxj.d2ydx2;
632 dr2ij[1] = -cij * trDxj.d2ydx2;
633 dr2ij[2] = -trDxj.d2zdx2 * NInv;
636 dr2ji[0] = sij * trDxi.d2ydx2;
637 dr2ji[1] = -cij * trDxi.d2ydx2;
638 dr2ji[2] = -trDxi.d2zdx2 * NInv;
645template <
int N,
typename... Args>
646GPUd()
void DCAFitterN<N, Args...>::calcRMatrices()
649 for (
int i = N;
i--;) {
650 const auto& mi = mTrAux[
i];
651 for (
int j =
i;
j--;) {
652 const auto& mj = mTrAux[
j];
653 mCosDif[
i][
j] = (mi.c * mj.c + mi.s * mj.s) * NInv;
654 mSinDif[
i][
j] = (mi.s * mj.c - mi.c * mj.s) * NInv;
660template <
int N,
typename... Args>
661GPUd()
void DCAFitterN<N, Args...>::calcChi2Derivatives()
664 std::array<std::array<Vec3D, N>, N> covIDrDx;
667 for (
int i = N;
i--;) {
668 auto& dchi1 = mDChi2Dx[
i];
670 for (
int j = N;
j--;) {
671 const auto&
res = mTrRes[mCurHyp][
j];
672 const auto& covI = mTrcEInv[mCurHyp][
j];
673 const auto& dr1 = mDResidDx[
j][
i];
674 auto& cidr = covIDrDx[
i][
j];
675 cidr[0] = covI.sxx * dr1[0] + covI.sxy * dr1[1] + covI.sxz * dr1[2];
676 cidr[1] = covI.sxy * dr1[0] + covI.syy * dr1[1] + covI.syz * dr1[2];
677 cidr[2] = covI.sxz * dr1[0] + covI.syz * dr1[1] + covI.szz * dr1[2];
683 for (
int i = N;
i--;) {
684 for (
int j =
i + 1;
j--;) {
685 auto& dchi2 = mD2Chi2Dx2[
i][
j];
687 for (
int k = N; k--;) {
688 const auto& dr1j = mDResidDx[k][
j];
689 const auto& cidrkj = covIDrDx[
i][k];
692 const auto&
res = mTrRes[mCurHyp][k];
693 const auto& covI = mTrcEInv[mCurHyp][k];
694 const auto& dr2ij = mD2ResidDx2[k][
i];
695 dchi2 +=
res[0] * (covI.sxx * dr2ij[0] + covI.sxy * dr2ij[1] + covI.sxz * dr2ij[2]) +
696 res[1] * (covI.sxy * dr2ij[0] + covI.syy * dr2ij[1] + covI.syz * dr2ij[2]) +
697 res[2] * (covI.sxz * dr2ij[0] + covI.syz * dr2ij[1] + covI.szz * dr2ij[2]);
705template <
int N,
typename... Args>
706GPUd()
void DCAFitterN<N, Args...>::calcChi2DerivativesNoErr()
709 for (
int i = N;
i--;) {
710 auto& dchi1 = mDChi2Dx[
i];
712 for (
int k = N; k--;) {
713 const auto&
res = mTrRes[mCurHyp][k];
714 const auto& dr1 = mDResidDx[k][
i];
718 for (
int i = N;
i--;) {
719 for (
int j =
i + 1;
j--;) {
720 auto& dchi2 = mD2Chi2Dx2[
i][
j];
722 for (
int k = N; k--;) {
736template <
int N,
typename... Args>
737GPUd()
void DCAFitterN<N, Args...>::calcPCA()
740 mPCA[mCurHyp] = mTrCFVT[mCurHyp][N - 1] * mTrPos[mCurHyp][N - 1];
741 for (
int i = N - 1;
i--;) {
742 mPCA[mCurHyp] += mTrCFVT[mCurHyp][
i] * mTrPos[mCurHyp][
i];
747template <
int N,
typename... Args>
748GPUd() bool DCAFitterN<N, Args...>::recalculatePCAWithErrors(
int cand)
751 if (isPropagateTracksToVertexDone(cand) && !propagateTracksToVertex(cand)) {
754 int saveCurHyp = mCurHyp;
755 mCurHyp = mOrder[cand];
757 for (
int i = N;
i--;) {
758 if (!mTrcEInv[mCurHyp][
i].set(mCandTr[mCurHyp][
i])) {
759 if (mLoggerBadCov.needToLog()) {
761 printf(
"fitter %d: error (%ld muted): overrode invalid track covariance from %s\n",
762 mFitterID, mLoggerBadCov.evCount, mCandTr[mCurHyp][
i].asString().c_str());
764 printf(
"fitter %d: error (%ld muted): overrode invalid track covariance cyy:%e czz:%e cyz:%e\n",
765 mFitterID, mLoggerBadCov.evCount, mCandTr[mCurHyp][
i].getSigmaY2(), mCandTr[mCurHyp][
i].getSigmaZ2(), mCandTr[mCurHyp][
i].getSigmaZY());
768 mFitStatus[mCurHyp] = FitStatus::FailInvCov;
769 if (mBadCovPolicy == Discard) {
771 }
else if (mBadCovPolicy == OverrideAndFlag) {
772 mPropFailed[mCurHyp] =
true;
776 if (!calcPCACoefs()) {
777 mCurHyp = saveCurHyp;
781 auto oldPCA = mPCA[mOrder[cand]];
783 mCurHyp = saveCurHyp;
788template <
int N,
typename... Args>
789GPUd()
void DCAFitterN<N, Args...>::calcPCANoErr()
792 auto& pca = mPCA[mCurHyp];
793 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);
795 pca[2] = mTrPos[mCurHyp][N - 1][2];
796 for (
int i = N - 1;
i--;) {
802 pca[2] += mTrPos[mCurHyp][
i][2];
810template <
int N,
typename... Args>
811GPUd() double DCAFitterN<N, Args...>::calcCollinearInflation(
int cand)
const
813 std::array<std::array<double, 3>, N> u{};
816 for (
int i = 0;
i < N; ++
i) {
817 std::array<float, 3>
p{};
818 if (!getTrack(
i, cand).getPxPyPzGlo(p)) {
821 const double p2 =
p[0] *
p[0] +
p[1] *
p[1] +
p[2] *
p[2];
825 const double pI = 1. / std::sqrt(
p2);
826 u[nu++] = {
p[0] * pI,
p[1] * pI,
p[2] * pI};
833 double sin2Mean = 0.;
835 for (
int i = 0;
i < nu; ++
i) {
836 for (
int j =
i + 1;
j < nu; ++
j) {
837 double cij = u[
i][0] * u[
j][0] + u[
i][1] * u[
j][1] + u[
i][2] * u[
j][2];
838 cij = std::clamp(cij, -1., 1.);
839 sin2Mean += std::max(0., 1. - cij * cij);
845 constexpr double Sin2Ref = 1.e-5;
846 constexpr double MaxInflation = 1.e4;
847 if (sin2Mean <= 0.) {
850 return sin2Mean < Sin2Ref ? std::min(MaxInflation, Sin2Ref / sin2Mean) : 1.;
854template <
int N,
typename... Args>
855GPUd()
o2::math_utils::SMatrix<
double, 3, 3,
o2::math_utils::MatRepSym<
double, 3>>
DCAFitterN<N, Args...>::calcPCACovMatrix(
int cand)
const
862 auto* arrmat = info.Array();
863 memset(arrmat, 0,
sizeof(info));
870 const int ord = mOrder[cand];
871 for (
int i = N;
i--;) {
872 const auto& taux = mTrAux[
i];
874 tcov.set(mCandTr[ord][
i]);
875 arrmat[XX] += taux.cc * tcov.
sxx - 2. * taux.cs * tcov.
sxy + taux.ss * tcov.
syy;
876 arrmat[XY] += taux.cs * (tcov.
sxx - tcov.
syy) + (taux.cc - taux.ss) * tcov.
sxy;
877 arrmat[XZ] += taux.c * tcov.
sxz - taux.s * tcov.
syz;
878 arrmat[YY] += taux.ss * tcov.
sxx + 2. * taux.cs * tcov.
sxy + taux.cc * tcov.
syy;
879 arrmat[YZ] += taux.s * tcov.
sxz + taux.c * tcov.
syz;
880 arrmat[ZZ] += tcov.
szz;
882 const double maxDiag = o2::gpu::GPUCommonMath::Max(o2::gpu::GPUCommonMath::Max(info(0, 0), info(1, 1)), info(2, 2));
883 const double det2 = info(0, 0) * info(1, 1) - info(1, 0) * info(1, 0);
884 const double det3 = info(0, 0) * (info(1, 1) * info(2, 2) - info(2, 1) * info(2, 1)) -
885 info(1, 0) * (info(1, 0) * info(2, 2) - info(2, 1) * info(2, 0)) +
886 info(2, 0) * (info(1, 0) * info(2, 1) - info(1, 1) * info(2, 0));
887 constexpr double MinRelDet = 1.e-12;
888 constexpr double InflateRelDet = 1.e-6;
889 constexpr double MaxInflation = 1.e4;
890 const bool isWellConditionedInfo = maxDiag > 0. && info(0, 0) > 0. && det2 > 0. && det3 > MinRelDet * maxDiag * maxDiag * maxDiag;
891 if (isWellConditionedInfo) {
893 if (cov.Invert() && cov(0, 0) > 0. && cov(1, 1) > 0. && cov(2, 2) > 0.) {
900 if (mLoggerBadPCACov.needToLog()) {
901 printf(
"fitter %d: error (%ld muted): override ill-conditioned PCACovMatrix by dummy matrix", mFitterID, mLoggerBadPCACov.evCount);
906 memset(arrmat, 0,
sizeof(info));
914template <
int N,
typename... Args>
915GPUd()
void DCAFitterN<N, Args...>::calcTrackResiduals()
919 for (
int i = N;
i--;) {
920 mTrRes[mCurHyp][
i] = mTrPos[mCurHyp][
i];
921 vtxLoc = mPCA[mCurHyp];
923 mTrRes[mCurHyp][
i] -= vtxLoc;
928template <
int N,
typename... Args>
929GPUdi()
void DCAFitterN<N, Args...>::calcTrackDerivatives()
932 for (
int i = N;
i--;) {
933 mTrDer[mCurHyp][
i].set(mCandTr[mCurHyp][
i], mBz);
938template <
int N,
typename... Args>
939GPUdi() double DCAFitterN<N, Args...>::calcChi2()
const
943 for (
int i = N;
i--;) {
944 const auto&
res = mTrRes[mCurHyp][
i];
945 const auto& covI = mTrcEInv[mCurHyp][
i];
946 chi2 +=
res[0] *
res[0] * covI.sxx +
res[1] *
res[1] * covI.syy +
res[2] *
res[2] * covI.szz +
947 2. * (
res[0] *
res[1] * covI.sxy +
res[0] *
res[2] * covI.sxz +
res[1] *
res[2] * covI.syz);
953template <
int N,
typename... Args>
954GPUdi() double DCAFitterN<N, Args...>::calcChi2NoErr()
const
958 for (
int i = N;
i--;) {
959 const auto&
res = mTrRes[mCurHyp][
i];
966template <
int N,
typename... Args>
967GPUd() bool DCAFitterN<N, Args...>::correctTracks(const VecND& corrX)
972 for (
int i = N;
i--;) {
982 auto& trc = mCandTr[mCurHyp][
i];
983 const float x =
static_cast<float>(mTrPos[mCurHyp][
i][0] - corrX[
i]);
984 const bool propagated = mUseAbsDCA ? trc.propagateParamTo(
x, mBz) : trc.propagateTo(
x, mBz);
988 setTrackPos(mTrPos[mCurHyp][
i], trc);
994template <
int N,
typename... Args>
995GPUd() bool DCAFitterN<N, Args...>::propagateTracksToVertex(
int icand)
998 int ord = mOrder[icand];
999 if (mTrPropDone[ord]) {
1004 if (mRefitWithMatCorr) {
1005 int curHypSav = mCurHyp, curCrosIDAlt = mCrossIDAlt;
1008 auto restore = [
this, curHypSav, curCrosIDAlt]() { this->mCurHyp = curHypSav; this->mCrossIDAlt = curCrosIDAlt; };
1009 if (!(mUseAbsDCA ? minimizeChi2NoErr() : minimizeChi2())) {
1016 for (
int i = N;
i--;) {
1017 if (mUseAbsDCA || mUsePropagator || mMatCorr != o2::base::Propagator::MatCorrType::USEMatCorrNONE) {
1018 mCandTr[ord][
i] = *mOrigTrPtr[
i];
1020 auto x = mTrAux[
i].c * mPCA[ord][0] + mTrAux[
i].s * mPCA[ord][1];
1021 if (!propagateToX(mCandTr[ord][
i],
x)) {
1026 mTrPropDone[ord] =
true;
1031template <
int N,
typename... Args>
1035 int ord = mOrder[icand];
1037 if (!mTrPropDone[ord]) {
1038 auto x = mTrAux[
i].c * mPCA[ord][0] + mTrAux[
i].s * mPCA[ord][1];
1039 if (!propagateParamToX(trc,
x)) {
1047template <
int N,
typename... Args>
1048GPUdi() double DCAFitterN<N, Args...>::getAbsMax(const VecND&
v)
1051 for (
int i = N;
i--;) {
1052 auto vai = o2::gpu::GPUCommonMath::Abs(
v[
i]);
1061template <
int N,
typename... Args>
1062GPUd() bool DCAFitterN<N, Args...>::minimizeChi2()
1065 for (
int i = N;
i--;) {
1066 mCandTr[mCurHyp][
i] = *mOrigTrPtr[
i];
1067 auto x = mTrAux[
i].c * mPCA[mCurHyp][0] + mTrAux[
i].s * mPCA[mCurHyp][1];
1068 if (
x < mMinXSeed) {
1069 mFitStatus[mCurHyp] = FitStatus::RejTrackX;
1072 if (!propagateToX(mCandTr[mCurHyp][
i],
x)) {
1075 setTrackPos(mTrPos[mCurHyp][
i], mCandTr[mCurHyp][
i]);
1076 if (!mTrcEInv[mCurHyp][
i].set(mCandTr[mCurHyp][
i])) {
1077 if (mLoggerBadCov.needToLog()) {
1078#ifndef GPUCA_GPUCODE
1079 printf(
"fitter %d: error (%ld muted): overrode invalid track covariance from %s\n",
1080 mFitterID, mLoggerBadCov.evCount, mCandTr[mCurHyp][
i].asString().c_str());
1082 printf(
"fitter %d: error (%ld muted): overrode invalid track covariance cyy:%e czz:%e cyz:%e\n",
1083 mFitterID, mLoggerBadCov.evCount, mCandTr[mCurHyp][
i].getSigmaY2(), mCandTr[mCurHyp][
i].getSigmaZ2(), mCandTr[mCurHyp][
i].getSigmaZY());
1086 mFitStatus[mCurHyp] = FitStatus::FailInvCov;
1087 if (mBadCovPolicy == Discard) {
1089 }
else if (mBadCovPolicy == OverrideAndFlag) {
1090 mPropFailed[mCurHyp] =
true;
1095 if (mMaxDZIni > 0 && !roughDZCut()) {
1096 mFitStatus[mCurHyp] = FitStatus::RejTrackRoughZ;
1100 if (!calcPCACoefs()) {
1104 calcTrackResiduals();
1105 float chi2Upd, chi2 = calcChi2();
1107 calcTrackDerivatives();
1108 calcResidDerivatives();
1109 calcChi2Derivatives();
1112 if (!mD2Chi2Dx2.Invert()) {
1113 if (mLoggerBadInv.needToLog()) {
1114 printf(
"fitter %d: error (%ld muted): Inversion failed\n", mFitterID, mLoggerBadCov.evCount);
1116 mFitStatus[mCurHyp] = FitStatus::FailInv2ndDeriv;
1119 VecND dx = mD2Chi2Dx2 * mDChi2Dx;
1120 if (!correctTracks(dx)) {
1121 mFitStatus[mCurHyp] = FitStatus::FailCorrTracks;
1125 if (mCrossIDAlt >= 0 && closerToAlternative()) {
1126 mFitStatus[mCurHyp] = FitStatus::FailCloserAlt;
1127 mAllowAltPreference =
false;
1130 calcTrackResiduals();
1131 chi2Upd = calcChi2();
1132 if (getAbsMax(dx) < mMinParamChange || chi2Upd > chi2 * mMinRelChi2Change) {
1134 mFitStatus[mCurHyp] = FitStatus::Converged;
1138 }
while (++mNIters[mCurHyp] < mMaxIter);
1139 if (mNIters[mCurHyp] == mMaxIter) {
1140 mFitStatus[mCurHyp] = FitStatus::MaxIter;
1143 mChi2[mCurHyp] = chi2 * NInv;
1144 if (mChi2[mCurHyp] >= mMaxChi2) {
1145 mFitStatus[mCurHyp] = FitStatus::RejChi2Max;
1152template <
int N,
typename... Args>
1153GPUd() bool DCAFitterN<N, Args...>::minimizeChi2NoErr()
1157 for (
int i = N;
i--;) {
1158 mCandTr[mCurHyp][
i] = *mOrigTrPtr[
i];
1159 auto x = mTrAux[
i].c * mPCA[mCurHyp][0] + mTrAux[
i].s * mPCA[mCurHyp][1];
1160 if (
x < mMinXSeed) {
1161 mFitStatus[mCurHyp] = FitStatus::RejTrackX;
1164 if (!propagateParamToX(mCandTr[mCurHyp][
i],
x)) {
1167 setTrackPos(mTrPos[mCurHyp][
i], mCandTr[mCurHyp][
i]);
1169 if (mMaxDZIni > 0 && !roughDZCut()) {
1170 mFitStatus[mCurHyp] = FitStatus::RejTrackRoughZ;
1175 calcTrackResiduals();
1176 float chi2Upd, chi2 = calcChi2NoErr();
1178 calcTrackDerivatives();
1179 calcResidDerivativesNoErr();
1180 calcChi2DerivativesNoErr();
1183 if (!mD2Chi2Dx2.Invert()) {
1184 if (mLoggerBadInv.needToLog()) {
1185 printf(
"fitter %d: error (%ld muted): Inversion failed\n", mFitterID, mLoggerBadCov.evCount);
1187 mFitStatus[mCurHyp] = FitStatus::FailInv2ndDeriv;
1190 VecND dx = mD2Chi2Dx2 * mDChi2Dx;
1191 if (!correctTracks(dx)) {
1192 mFitStatus[mCurHyp] = FitStatus::FailCorrTracks;
1196 if (mCrossIDAlt >= 0 && closerToAlternative()) {
1197 mFitStatus[mCurHyp] = FitStatus::FailCloserAlt;
1198 mAllowAltPreference =
false;
1201 calcTrackResiduals();
1202 chi2Upd = calcChi2NoErr();
1203 if (getAbsMax(dx) < mMinParamChange || chi2Upd > chi2 * mMinRelChi2Change) {
1205 mFitStatus[mCurHyp] = FitStatus::Converged;
1209 }
while (++mNIters[mCurHyp] < mMaxIter);
1210 if (mNIters[mCurHyp] == mMaxIter) {
1211 mFitStatus[mCurHyp] = FitStatus::MaxIter;
1214 mChi2[mCurHyp] = chi2 * NInv;
1215 if (mChi2[mCurHyp] >= mMaxChi2) {
1216 mFitStatus[mCurHyp] = FitStatus::RejChi2Max;
1223template <
int N,
typename... Args>
1224GPUd() bool DCAFitterN<N, Args...>::roughDZCut()
const
1228 for (
int i = N; accept &&
i--;) {
1229 for (
int j =
i;
j--;) {
1230 if (o2::gpu::GPUCommonMath::Abs(mCandTr[mCurHyp][
i].getZ() - mCandTr[mCurHyp][
j].getZ()) > mMaxDZIni) {
1240template <
int N,
typename... Args>
1241GPUd() bool DCAFitterN<N, Args...>::closerToAlternative()
const
1244 auto dxCur = mPCA[mCurHyp][0] - mCrossings.xDCA[mCrossIDCur], dyCur = mPCA[mCurHyp][1] - mCrossings.yDCA[mCrossIDCur];
1245 auto dxAlt = mPCA[mCurHyp][0] - mCrossings.xDCA[mCrossIDAlt], dyAlt = mPCA[mCurHyp][1] - mCrossings.yDCA[mCrossIDAlt];
1246 return dxCur * dxCur + dyCur * dyCur > dxAlt * dxAlt + dyAlt * dyAlt;
1250template <
int N,
typename... Args>
1253#ifndef GPUCA_GPUCODE_DEVICE
1254 LOG(info) << N <<
"-prong vertex fitter in " << (mUseAbsDCA ?
"abs." :
"weighted") <<
" distance minimization mode, collinear tracks mode: " << (mIsCollinear ?
"ON" :
"OFF");
1255 LOG(info) <<
"Bz: " << mBz <<
" MaxIter: " << mMaxIter <<
" MaxChi2: " << mMaxChi2 <<
" MatCorrType: " <<
int(mMatCorr);
1256 LOG(info) <<
"Stopping condition: Max.param change < " << mMinParamChange <<
" Rel.Chi2 change > " << mMinRelChi2Change;
1257 LOG(info) <<
"Discard candidates for : Rvtx > " << getMaxR() <<
" DZ between tracks > " << mMaxDZIni;
1258 LOG(info) <<
"PropagateToPCA:" << mPropagateToPCA <<
" WeightedFinalPCA:" << mWeightedFinalPCA <<
" UsePropagator:" << mUsePropagator <<
" RefitWithMatCorr:" << mRefitWithMatCorr;
1260 for (
int i = 0;
i < mCrossings.nDCA;
i++) {
1261 rep += fmt::format(
"seed{}:{}/{} ",
i, mTrPropDone[
i], mPropFailed[
i]);
1263 LOG(info) <<
"Last call: NCand:" << mCurHyp <<
" from " << mCrossings.nDCA <<
" seeds, prop.done/failed: " << rep;
1266 printf(
"%d-prong vertex fitter in abs. distance minimization mode\n", N);
1268 printf(
"%d-prong vertex fitter in weighted distance minimization mode\n", N);
1270 printf(
"Bz: %1.f MaxIter: %3.d MaxChi2: %2.3f\n", mBz, mMaxIter, mMaxChi2);
1271 printf(
"Stopping condition: Max.param change < %2.3f Rel.Chi2 change > %2.3f\n", mMinParamChange, mMinRelChi2Change);
1272 printf(
"Discard candidates for : Rvtx > %2.3f DZ between tracks > %2.3f\n", getMaxR(), mMaxDZIni);
1277template <
int N,
typename... Args>
1278GPUd()
o2::track::
TrackParCov DCAFitterN<N, Args...>::createParentTrackParCov(
int cand,
bool sectorAlpha)
const
1280 std::array<float, 21> covV = {0.};
1281 std::array<float, 3> pvecV = {0.};
1283 for (
int it = 0; it < N; it++) {
1284 const auto& trc = getTrack(it, cand);
1285 std::array<float, 3> pvecT = {0.};
1286 const bool hasMomentum = trc.getPxPyPzGlo(pvecT);
1292 const double snp = trc.getSnp();
1293 const double csp = trc.getCsp();
1294 const double pt = trc.getPt();
1295 const double alpha = trc.getAlpha();
1296 double sna = 0., csa = 0.;
1297 o2::math_utils::detail::sincos(
alpha, sna, csa);
1298 const double dPxdSnp = -pt * (snp * csa / csp + sna);
1299 const double dPydSnp = pt * (csa - snp * sna / csp);
1300 const double dPzdTgl = pt;
1301 const double q2ptI = 1. / trc.getQ2Pt();
1302 const double dPxdQ = -pvecT[0] * q2ptI;
1303 const double dPydQ = -pvecT[1] * q2ptI;
1304 const double dPzdQ = -pvecT[2] * q2ptI;
1305 const double cSnpSnp = trc.getSigmaSnp2();
1306 const double cTglSnp = trc.getSigmaTglSnp();
1307 const double cTglTgl = trc.getSigmaTgl2();
1308 const double cQSnp = trc.getSigma1PtSnp();
1309 const double cQTgl = trc.getSigma1PtTgl();
1310 const double cQQ = trc.getSigma1Pt2();
1311 covV[9] += dPxdSnp * dPxdSnp * cSnpSnp + 2. * dPxdSnp * dPxdQ * cQSnp + dPxdQ * dPxdQ * cQQ;
1312 covV[13] += dPydSnp * (dPxdSnp * cSnpSnp + dPxdQ * cQSnp) + dPydQ * (dPxdSnp * cQSnp + dPxdQ * cQQ);
1313 covV[14] += dPydSnp * dPydSnp * cSnpSnp + 2. * dPydSnp * dPydQ * cQSnp + dPydQ * dPydQ * cQQ;
1314 covV[18] += dPzdTgl * (dPxdSnp * cTglSnp + dPxdQ * cQTgl) + dPzdQ * (dPxdSnp * cQSnp + dPxdQ * cQQ);
1315 covV[19] += dPzdTgl * (dPydSnp * cTglSnp + dPydQ * cQTgl) + dPzdQ * (dPydSnp * cQSnp + dPydQ * cQQ);
1316 covV[20] += dPzdTgl * dPzdTgl * cTglTgl + 2. * dPzdTgl * dPzdQ * cQTgl + dPzdQ * dPzdQ * cQQ;
1319 for (
int i = 0;
i < 3;
i++) {
1320 pvecV[
i] += pvecT[
i];
1322 q += trc.getCharge();
1324 auto covVtxV = calcPCACovMatrix(cand);
1325 covV[0] = covVtxV(0, 0);
1326 covV[1] = covVtxV(1, 0);
1327 covV[2] = covVtxV(1, 1);
1328 covV[3] = covVtxV(2, 0);
1329 covV[4] = covVtxV(2, 1);
1330 covV[5] = covVtxV(2, 2);
1335template <
int N,
typename... Args>
1336GPUd()
o2::track::TrackPar DCAFitterN<N, Args...>::createParentTrackPar(
int cand,
bool sectorAlpha)
const
1338 const auto& trP = getTrack(0, cand);
1339 const auto& trN = getTrack(1, cand);
1340 const auto& wvtx = getPCACandidate(cand);
1341 std::array<float, 3> pvecV = {0.};
1343 for (
int it = 0; it < N; it++) {
1344 const auto& trc = getTrack(it, cand);
1345 std::array<float, 3> pvecT = {0.};
1346 trc.getPxPyPzGlo(pvecT);
1347 for (
int i = 0;
i < 3;
i++) {
1348 pvecV[
i] += pvecT[
i];
1350 q += trc.getCharge();
1352 const std::array<float, 3>
vertex = {(float)wvtx[0], (
float)wvtx[1], (float)wvtx[2]};
1357template <
int N,
typename... Args>
1358GPUdi() bool DCAFitterN<N, Args...>::propagateParamToX(
o2::track::TrackPar& t,
float x)
1361 if (mUsePropagator || mMatCorr != o2::base::Propagator::MatCorrType::USEMatCorrNONE) {
1362#ifndef GPUCA_GPUCODE
1366 res = t.propagateParamTo(
x, mBz);
1369 mFitStatus[mCurHyp] = FitStatus::FailProp;
1370 mPropFailed[mCurHyp] =
true;
1371 if (mLoggerBadProp.needToLog()) {
1372#ifndef GPUCA_GPUCODE
1373 printf(
"fitter %d: error (%ld muted): propagation to %.4f failed for %s\n", mFitterID, mLoggerBadProp.evCount,
x, t.asString().c_str());
1375 printf(
"fitter %d: error (%ld muted): propagation to %.4f failed\n", mFitterID, mLoggerBadProp.evCount,
x);
1383template <
int N,
typename... Args>
1387 if (mUsePropagator || mMatCorr != o2::base::Propagator::MatCorrType::USEMatCorrNONE) {
1388#ifndef GPUCA_GPUCODE
1392 res = t.propagateTo(
x, mBz);
1395 mFitStatus[mCurHyp] = FitStatus::FailProp;
1396 mPropFailed[mCurHyp] =
true;
1397 if (mLoggerBadProp.needToLog()) {
1398#ifndef GPUCA_GPUCODE
1399 printf(
"fitter %d: error (%ld muted): propagation to %.4f failed for %s\n", mFitterID, mLoggerBadProp.evCount,
x, t.asString().c_str());
1401 printf(
"fitter %d: error (%ld muted): propagation to %.4f failed\n", mFitterID, mLoggerBadProp.evCount,
x);
1413template <
typename Fitter>
1414void print(
const int nBlocks,
const int nThreads, Fitter& ft);
1416template <
typename Fitter,
class... Tr>
1417int process(
const int nBlocks,
const int nThreads, Fitter&, Tr&... args);
1419template <
class Fitter,
class... Tr>
1420void processBulk(
const int nBlocks,
const int nThreads,
const int nBatches, std::vector<Fitter>& fitters, std::vector<int>& results, std::vector<Tr>&... args);