Project
Loading...
Searching...
No Matches
DCAFitterN.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
16
17#ifndef _ALICEO2_DCA_FITTERN_
18#define _ALICEO2_DCA_FITTERN_
19
22#include "MathUtils/Cartesian.h"
24
25namespace o2
26{
27namespace vertexing
28{
29
32struct TrackCovI {
33 float sxx, syy, syz, szz;
34
35 GPUdDefault() TrackCovI() = default;
36
37 GPUd() bool set(const o2::track::TrackParCov& trc, float xerrFactor = 1.f)
38 {
39 // we assign Y error to X for DCA calculation
40 // (otherwise for quazi-collinear tracks the X will not be constrained)
41 float cyy = trc.getSigmaY2(), czz = trc.getSigmaZ2(), cyz = trc.getSigmaZY(), cxx = cyy * xerrFactor;
42 float detYZ = cyy * czz - cyz * cyz;
43 bool res = true;
44 if (detYZ <= 0.) {
45 cyz = o2::gpu::GPUCommonMath::Sqrt(cyy * czz) * (cyz > 0 ? 0.98f : -0.98f);
46 detYZ = cyy * czz - cyz * cyz;
47 res = false;
48 }
49 auto detYZI = 1. / detYZ;
50 sxx = 1. / cxx;
51 syy = czz * detYZI;
52 syz = -cyz * detYZI;
53 szz = cyy * detYZI;
54 return res;
55 }
56};
57
60struct TrackDeriv {
62 GPUdDefault() TrackDeriv() = default;
63 GPUd() TrackDeriv(const o2::track::TrackPar& trc, float bz) { set(trc, bz); }
64 GPUd() void set(const o2::track::TrackPar& trc, float bz)
65 {
66 float snp = trc.getSnp(), csp = o2::gpu::GPUCommonMath::Sqrt((1. - snp) * (1. + snp)), cspI = 1. / csp, crv2c = trc.getCurvature(bz) * cspI;
67 dydx = snp * cspI; // = snp/csp
68 dzdx = trc.getTgl() * cspI; // = tgl/csp
69 d2ydx2 = crv2c * cspI * cspI; // = crv/csp^3
70 d2zdx2 = crv2c * dzdx * dydx; // = crv*tgl*snp/csp^3
71 }
72};
73
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
93};
94
95template <int N, typename... Args>
97{
98 static constexpr double NMin = 2;
99 static constexpr double NMax = 4;
100 static constexpr double NInv = 1. / N;
101 static constexpr int MAXHYP = 2;
102 static constexpr float XerrFactor = 5.; // factor for conversion of track covYY to dummy covXX
103 using Track = o2::track::TrackParCov;
106
113 using TrackCoefVtx = MatStd3D;
114 using ArrTrack = o2::gpu::gpustd::array<Track, N>; // container for prongs (tracks) at single vertex cand.
115 using ArrTrackCovI = o2::gpu::gpustd::array<TrackCovI, N>; // container for inv.cov.matrices at single vertex cand.
116 using ArrTrCoef = o2::gpu::gpustd::array<TrackCoefVtx, N>; // container of TrackCoefVtx coefficients at single vertex cand.
117 using ArrTrDer = o2::gpu::gpustd::array<TrackDeriv, N>; // container of Track 1st and 2nd derivative over their X param
118 using ArrTrPos = o2::gpu::gpustd::array<Vec3D, N>; // container of Track positions
119
120 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
127 static constexpr int getNProngs() { return N; }
128
129 DCAFitterN() = default;
130 DCAFitterN(float bz, bool useAbsDCA, bool prop2DCA) : mBz(bz), mUseAbsDCA(useAbsDCA), mPropagateToPCA(prop2DCA)
131 {
132 static_assert(N >= NMin && N <= NMax, "N prongs outside of allowed range");
133 }
134
135 //=========================================================================
137 GPUd() const Vec3D& getPCACandidate(int cand = 0) const { return mPCA[mOrder[cand]]; }
138 GPUd() const auto getPCACandidatePos(int cand = 0) const
139 {
140 const auto& vd = mPCA[mOrder[cand]];
141 return o2::gpu::gpustd::array<float, 3>{static_cast<float>(vd[0]), static_cast<float>(vd[1]), static_cast<float>(vd[2])};
142 }
143
145 int getCandidatePosition(int cand = 0) const { return mOrder[cand]; }
146
148 float getChi2AtPCACandidate(int cand = 0) const { return mChi2[mOrder[cand]]; }
149
152 GPUd() bool propagateTracksToVertex(int cand = 0);
153
155 GPUd() bool isPropagateTracksToVertexDone(int cand = 0) const { return mTrPropDone[mOrder[cand]]; }
156
158 bool isPropagationFailure(int cand = 0) const { return mPropFailed[mOrder[cand]]; }
159
162 Track& getTrack(int i, int cand = 0)
163 {
164 if (!mTrPropDone[mOrder[cand]]) {
165#ifndef GPUCA_GPUCODE_DEVICE
166 throw std::runtime_error("propagateTracksToVertex was not called yet");
167#endif
168 }
169 return mCandTr[mOrder[cand]][i];
170 }
171
172 const Track& getTrack(int i, int cand = 0) const
173 {
174 if (!mTrPropDone[mOrder[cand]]) {
175#ifndef GPUCA_GPUCODE_DEVICE
176 throw std::runtime_error("propagateTracksToVertex was not called yet");
177#endif
178 }
179 return mCandTr[mOrder[cand]][i];
180 }
181
183 GPUd() o2::track::TrackParCov createParentTrackParCov(int cand = 0, bool sectorAlpha = true) const;
184
186 GPUd() o2::track::TrackPar createParentTrackPar(int cand = 0, bool sectorAlpha = true) const;
187
189 GPUd() o2::track::TrackPar getTrackParamAtPCA(int i, int cand = 0);
190
192 GPUd() bool recalculatePCAWithErrors(int cand = 0);
193
194 GPUd() MatSym3D calcPCACovMatrix(int cand = 0) const;
195
196 o2::gpu::gpustd::array<float, 6> calcPCACovMatrixFlat(int cand = 0) const
197 {
198 auto m = calcPCACovMatrix(cand);
199 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))};
200 }
201
202 const Track* getOrigTrackPtr(int i) const { return mOrigTrPtr[i]; }
203
205 GPUdi() int getNIterations(int cand = 0) const { return mNIters[mOrder[cand]]; }
206 GPUdi() void setPropagateToPCA(bool v = true) { mPropagateToPCA = v; }
207 GPUdi() void setMaxIter(int n = 20) { mMaxIter = n > 2 ? n : 2; }
208 GPUdi() void setMaxR(float r = 200.) { mMaxR2 = r * r; }
209 GPUdi() void setMaxDZIni(float d = 4.) { mMaxDZIni = d; }
210 GPUdi() void setMaxDXYIni(float d = 4.) { mMaxDXYIni = d > 0 ? d : 1e9; }
211 GPUdi() void setMaxChi2(float chi2 = 999.) { mMaxChi2 = chi2; }
212 GPUdi() void setBz(float bz) { mBz = o2::gpu::GPUCommonMath::Abs(bz) > o2::constants::math::Almost0 ? bz : 0.f; }
213 GPUdi() void setMinParamChange(float x = 1e-3) { mMinParamChange = x > 1e-4 ? x : 1.e-4; }
214 GPUdi() void setMinRelChi2Change(float r = 0.9) { mMinRelChi2Change = r > 0.1 ? r : 999.; }
215 GPUdi() void setUseAbsDCA(bool v) { mUseAbsDCA = v; }
216 GPUdi() void setWeightedFinalPCA(bool v) { mWeightedFinalPCA = v; }
217 GPUdi() void setMaxDistance2ToMerge(float v) { mMaxDist2ToMergeSeeds = v; }
218 GPUdi() void setMatCorrType(o2::base::Propagator::MatCorrType m = o2::base::Propagator::MatCorrType::USEMatCorrLUT) { mMatCorr = m; }
219 GPUdi() void setUsePropagator(bool v) { mUsePropagator = v; }
220 GPUdi() void setRefitWithMatCorr(bool v) { mRefitWithMatCorr = v; }
221 GPUdi() void setMaxSnp(float s) { mMaxSnp = s; }
222 GPUdi() void setMaxStep(float s) { mMaxStep = s; }
223 GPUdi() void setMinXSeed(float x) { mMinXSeed = x; }
224 GPUdi() void setCollinear(bool isCollinear) { mIsCollinear = isCollinear; }
225
226 GPUdi() int getNCandidates() const { return mCurHyp; }
227 GPUdi() int getMaxIter() const { return mMaxIter; }
228 GPUdi() float getMaxR() const { return o2::gpu::GPUCommonMath::Sqrt(mMaxR2); }
229 GPUdi() float getMaxDZIni() const { return mMaxDZIni; }
230 GPUdi() float getMaxDXYIni() const { return mMaxDXYIni; }
231 GPUdi() float getMaxChi2() const { return mMaxChi2; }
232 GPUdi() float getMinParamChange() const { return mMinParamChange; }
233 GPUdi() float getBz() const { return mBz; }
234 GPUdi() float getMaxDistance2ToMerge() const { return mMaxDist2ToMergeSeeds; }
235 GPUdi() bool getUseAbsDCA() const { return mUseAbsDCA; }
236 GPUdi() bool getWeightedFinalPCA() const { return mWeightedFinalPCA; }
237 GPUdi() bool getPropagateToPCA() const { return mPropagateToPCA; }
238 GPUdi() o2::base::Propagator::MatCorrType getMatCorrType() const { return mMatCorr; }
239 GPUdi() bool getUsePropagator() const { return mUsePropagator; }
240 GPUdi() bool getRefitWithMatCorr() const { return mRefitWithMatCorr; }
241 GPUdi() float getMaxSnp() const { return mMaxSnp; }
242 GPUdi() float getMasStep() const { return mMaxStep; }
243 GPUdi() float getMinXSeed() const { return mMinXSeed; }
244
245 template <class... Tr>
246 GPUd() int process(const Tr&... args);
247 GPUd() void print() const;
248
249 GPUdi() int getFitterID() const { return mFitterID; }
250 GPUdi() void setFitterID(int i) { mFitterID = i; }
251 GPUdi() size_t getCallID() const { return mCallID; }
252
253 protected:
254 GPUd() bool calcPCACoefs();
255 GPUd() bool calcInverseWeight();
256 GPUd() void calcResidDerivatives();
257 GPUd() void calcResidDerivativesNoErr();
258 GPUd() void calcRMatrices();
259 GPUd() void calcChi2Derivatives();
260 GPUd() void calcChi2DerivativesNoErr();
261 GPUd() void calcPCA();
262 GPUd() void calcPCANoErr();
263 GPUd() void calcTrackResiduals();
264 GPUd() void calcTrackDerivatives();
265 GPUd() double calcChi2() const;
266 GPUd() double calcChi2NoErr() const;
267 GPUd() bool correctTracks(const VecND& corrX);
268 GPUd() bool minimizeChi2();
269 GPUd() bool minimizeChi2NoErr();
270 GPUd() bool roughDZCut() const;
271 GPUd() bool closerToAlternative() const;
272 GPUd() bool propagateToX(o2::track::TrackParCov& t, float x);
273 GPUd() bool propagateParamToX(o2::track::TrackPar& t, float x);
274
275 GPUd() static double getAbsMax(const VecND& v);
277 GPUdi() const Vec3D& getTrackPos(int i, int cand = 0) const { return mTrPos[mOrder[cand]][i]; }
278
280 GPUd() float getTrackX(int i, int cand = 0) const { return getTrackPos(i, cand)[0]; }
281
282 GPUd() MatStd3D getTrackRotMatrix(int i) const // generate 3D matrix for track rotation to global frame
283 {
284 MatStd3D mat;
285 mat(2, 2) = 1;
286 mat(0, 0) = mat(1, 1) = mTrAux[i].c;
287 mat(0, 1) = -mTrAux[i].s;
288 mat(1, 0) = mTrAux[i].s;
289 return mat;
290 }
291
292 GPUd() MatSym3D getTrackCovMatrix(int i, int cand = 0) const // generate covariance matrix of track position, adding fake X error
293 {
294 const auto& trc = mCandTr[mOrder[cand]][i];
295 MatSym3D mat;
296 mat(0, 0) = trc.getSigmaY2() * XerrFactor;
297 mat(1, 1) = trc.getSigmaY2();
298 mat(2, 2) = trc.getSigmaZ2();
299 mat(2, 1) = trc.getSigmaZY();
300 return mat;
301 }
302
303 GPUd() void assign(int) {}
304 template <class T, class... Tr>
305 GPUd() void assign(int i, const T& t, const Tr&... args)
306 {
307#ifndef GPUCA_GPUCODE_DEVICE
308 static_assert(std::is_convertible<T, Track>(), "Wrong track type");
309#endif
311 assign(i + 1, args...);
312 }
313
315 {
316 mCurHyp = 0;
317 mAllowAltPreference = true;
318 }
319
320 GPUdi() static void setTrackPos(Vec3D& pnt, const Track& tr)
321 {
322 pnt[0] = tr.getX();
323 pnt[1] = tr.getY();
324 pnt[2] = tr.getZ();
325 }
326
327 GPUdi() void clearLogThrottlers()
328 {
329 mLoggerBadCov.clear();
330 mLoggerBadInv.clear();
331 mLoggerBadProp.clear();
332 }
333
334 void setBadCovPolicy(BadCovPolicy v) { mBadCovPolicy = v; }
335 BadCovPolicy getBadCovPolicy() const { return mBadCovPolicy; }
336
337 private:
338 // vectors of 1st derivatives of track local residuals over X parameters
340 // vectors of 1nd derivatives of track local residuals over X parameters
341 // (cross-derivatives DR/(dx_j*dx_k) = 0 for j!=k, therefore the hessian is diagonal)
343 VecND mDChi2Dx; // 1st derivatives of chi2 over tracks X params
344 MatSymND mD2Chi2Dx2; // 2nd derivatives of chi2 over tracks X params (symmetric matrix)
345 MatSymND mCosDif; // matrix with cos(alp_j-alp_i) for j<i
346 MatSymND mSinDif; // matrix with sin(alp_j-alp_i) for j<i
348 o2::gpu::gpustd::array<TrackAuxPar, N> mTrAux; // Aux track info for each track at each cand. vertex
349 CrossInfo mCrossings; // info on track crossing
350
351 o2::gpu::gpustd::array<ArrTrackCovI, MAXHYP> mTrcEInv; // errors for each track at each cand. vertex
352 o2::gpu::gpustd::array<ArrTrack, MAXHYP> mCandTr; // tracks at each cond. vertex (Note: Errors are at seed XY point)
353 o2::gpu::gpustd::array<ArrTrCoef, MAXHYP> mTrCFVT; // TrackCoefVtx for each track at each cand. vertex
354 o2::gpu::gpustd::array<ArrTrDer, MAXHYP> mTrDer; // Track derivativse
355 o2::gpu::gpustd::array<ArrTrPos, MAXHYP> mTrPos; // Track positions
356 o2::gpu::gpustd::array<ArrTrPos, MAXHYP> mTrRes; // Track residuals
357 o2::gpu::gpustd::array<Vec3D, MAXHYP> mPCA; // PCA for each vertex candidate
358 o2::gpu::gpustd::array<float, MAXHYP> mChi2 = {0}; // Chi2 at PCA candidate
359 o2::gpu::gpustd::array<int, MAXHYP> mNIters; // number of iterations for each seed
360 o2::gpu::gpustd::array<bool, MAXHYP> mTrPropDone{}; // Flag that the tracks are fully propagated to PCA
361 o2::gpu::gpustd::array<bool, MAXHYP> mPropFailed{}; // Flag that some propagation failed for this PCA candidate
362 LogLogThrottler mLoggerBadCov{};
363 LogLogThrottler mLoggerBadInv{};
364 LogLogThrottler mLoggerBadProp{};
365 MatSym3D mWeightInv; // inverse weight of single track, [sum{M^T E M}]^-1 in EQ.T
367 int mCurHyp = 0;
368 int mCrossIDCur = 0;
369 int mCrossIDAlt = -1;
370 BadCovPolicy mBadCovPolicy{BadCovPolicy::Discard}; // what to do in case of non-pos-def. cov. matrix, see BadCovPolicy enum
371 bool mAllowAltPreference = true; // if the fit converges to alternative PCA seed, abandon the current one
372 bool mUseAbsDCA = false; // use abs. distance minimization rather than chi2
373 bool mWeightedFinalPCA = false; // recalculate PCA as a cov-matrix weighted mean, even if absDCA method was used
374 bool mPropagateToPCA = true; // create tracks version propagated to PCA
375 bool mUsePropagator = false; // use propagator with 3D B-field, set automatically if material correction is requested
376 bool mRefitWithMatCorr = false; // when doing propagateTracksToVertex, propagate tracks to V0 with material corrections and rerun minimization again
377 bool mIsCollinear = false; // use collinear fits when there 2 crossing points
378 o2::base::Propagator::MatCorrType mMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; // material corrections type
379 int mMaxIter = 20; // max number of iterations
380 float mBz = 0; // bz field, to be set by user
381 float mMaxR2 = 200. * 200.; // reject PCA's above this radius
382 float mMinXSeed = -50.; // reject seed if it corresponds to X-param < mMinXSeed for one of candidates (e.g. X becomes strongly negative)
383 float mMaxDZIni = 4.; // reject (if>0) PCA candidate if tracks DZ exceeds threshold
384 float mMaxDXYIni = 4.; // reject (if>0) PCA candidate if tracks dXY exceeds threshold
385 float mMinParamChange = 1e-3; // stop iterations if largest change of any X is smaller than this
386 float mMinRelChi2Change = 0.9; // stop iterations is chi2/chi2old > this
387 float mMaxChi2 = 100; // abs cut on chi2 or abs distance
388 float mMaxDist2ToMergeSeeds = 1.; // merge 2 seeds to their average if their distance^2 is below the threshold
389 float mMaxSnp = 0.95; // Max snp for propagation with Propagator
390 float mMaxStep = 2.0; // Max step for propagation with Propagator
391 int mFitterID = 0; // locat fitter ID (mostly for debugging)
392 size_t mCallID = 0;
393 ClassDefNV(DCAFitterN, 2);
394};
395
397template <int N, typename... Args>
398template <class... Tr>
399GPUd() int DCAFitterN<N, Args...>::process(const Tr&... args)
400{
401 // This is a main entry point: fit PCA of N tracks
402 mCallID++;
403 static_assert(sizeof...(args) == N, "incorrect number of input tracks");
404 assign(0, args...);
405 clear();
406 for (int i = 0; i < N; i++) {
407 mTrAux[i].set(*mOrigTrPtr[i], mBz);
408 }
409 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;
414 }
415 if (mUseAbsDCA) {
416 calcRMatrices(); // needed for fast residuals derivatives calculation in case of abs. distance minimization
417 }
418 if (mCrossings.nDCA == MAXHYP) { // if there are 2 candidates and they are too close, chose their mean as a starting point
419 auto dst2 = (mCrossings.xDCA[0] - mCrossings.xDCA[1]) * (mCrossings.xDCA[0] - mCrossings.xDCA[1]) +
420 (mCrossings.yDCA[0] - mCrossings.yDCA[1]) * (mCrossings.yDCA[0] - mCrossings.yDCA[1]);
421 if (dst2 < mMaxDist2ToMergeSeeds) {
422 mCrossings.nDCA = 1;
423 mCrossings.xDCA[0] = 0.5 * (mCrossings.xDCA[0] + mCrossings.xDCA[1]);
424 mCrossings.yDCA[0] = 0.5 * (mCrossings.yDCA[0] + mCrossings.yDCA[1]);
425 }
426 }
427 // check all crossings
428 for (int ic = 0; ic < mCrossings.nDCA; ic++) {
429 // check if radius is acceptable
430 if (mCrossings.xDCA[ic] * mCrossings.xDCA[ic] + mCrossings.yDCA[ic] * mCrossings.yDCA[ic] > mMaxR2) {
431 continue;
432 }
433 mCrossIDCur = ic;
434 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.;
438 mPCA[mCurHyp][0] = mCrossings.xDCA[ic];
439 mPCA[mCurHyp][1] = mCrossings.yDCA[ic];
440
441 if (mUseAbsDCA ? minimizeChi2NoErr() : minimizeChi2()) {
442 mOrder[mCurHyp] = mCurHyp;
443 if (mPropagateToPCA && !propagateTracksToVertex(mCurHyp)) {
444 continue; // discard candidate if failed to propagate to it
445 }
446 mCurHyp++;
447 }
448 }
449
450 for (int i = mCurHyp; i--;) { // order in quality
451 for (int j = i; j--;) {
452 if (mChi2[mOrder[i]] < mChi2[mOrder[j]]) {
453 o2::gpu::GPUCommonMath::Swap(mOrder[i], mOrder[j]);
454 }
455 }
456 }
457 if (mUseAbsDCA && mWeightedFinalPCA) {
458 for (int i = mCurHyp; i--;) {
459 recalculatePCAWithErrors(i);
460 }
461 }
462 return mCurHyp;
463}
464
465//__________________________________________________________________________
466template <int N, typename... Args>
467GPUd() bool DCAFitterN<N, Args...>::calcPCACoefs()
468{
469 //< calculate Ti matrices for global vertex decomposition to V = sum_{0<i<N} Ti pi, see EQ.T in the ref
470 if (!calcInverseWeight()) {
471 return false;
472 }
473 for (int i = N; i--;) { // build Mi*Ei matrix
474 const auto& taux = mTrAux[i];
475 const auto& tcov = mTrcEInv[mCurHyp][i];
476 MatStd3D miei;
477 miei[0][0] = taux.c * tcov.sxx;
478 miei[0][1] = -taux.s * tcov.syy;
479 miei[0][2] = -taux.s * tcov.syz;
480 miei[1][0] = taux.s * tcov.sxx;
481 miei[1][1] = taux.c * tcov.syy;
482 miei[1][2] = taux.c * tcov.syz;
483 miei[2][0] = 0;
484 miei[2][1] = tcov.syz;
485 miei[2][2] = tcov.szz;
486 mTrCFVT[mCurHyp][i] = mWeightInv * miei;
487 }
488 return true;
489}
490
491//__________________________________________________________________________
492template <int N, typename... Args>
493GPUd() bool DCAFitterN<N, Args...>::calcInverseWeight()
494{
495 //< calculate [sum_{0<j<N} M_j*E_j*M_j^T]^-1 used for Ti matrices, see EQ.T
496 auto* arrmat = mWeightInv.Array();
497 memset(arrmat, 0, sizeof(mWeightInv));
498 enum { XX,
499 XY,
500 YY,
501 XZ,
502 YZ,
503 ZZ };
504 for (int i = N; i--;) {
505 const auto& taux = mTrAux[i];
506 const auto& tcov = mTrcEInv[mCurHyp][i];
507 arrmat[XX] += taux.cc * tcov.sxx + taux.ss * tcov.syy;
508 arrmat[XY] += taux.cs * (tcov.sxx - tcov.syy);
509 arrmat[XZ] += -taux.s * tcov.syz;
510 arrmat[YY] += taux.cc * tcov.syy + taux.ss * tcov.sxx;
511 arrmat[YZ] += taux.c * tcov.syz;
512 arrmat[ZZ] += tcov.szz;
513 }
514 // invert 3x3 symmetrix matrix
515 return mWeightInv.Invert();
516}
517
518//__________________________________________________________________________
519template <int N, typename... Args>
520GPUd() void DCAFitterN<N, Args...>::calcResidDerivatives()
521{
522 //< calculate matrix of derivatives for weighted chi2: residual i vs parameter X of track j
523 MatStd3D matMT;
524 for (int i = N; i--;) { // residual being differentiated
525 const auto& taux = mTrAux[i];
526 for (int j = N; j--;) { // track over which we differentiate
527 const auto& matT = mTrCFVT[mCurHyp][j]; // coefficient matrix for track J
528 const auto& trDx = mTrDer[mCurHyp][j]; // track point derivs over track X param
529 auto& dr1 = mDResidDx[i][j];
530 auto& dr2 = mD2ResidDx2[i][j];
531 // calculate M_i^tr * T_j
532 matMT[0][0] = taux.c * matT[0][0] + taux.s * matT[1][0];
533 matMT[0][1] = taux.c * matT[0][1] + taux.s * matT[1][1];
534 matMT[0][2] = taux.c * matT[0][2] + taux.s * matT[1][2];
535 matMT[1][0] = -taux.s * matT[0][0] + taux.c * matT[1][0];
536 matMT[1][1] = -taux.s * matT[0][1] + taux.c * matT[1][1];
537 matMT[1][2] = -taux.s * matT[0][2] + taux.c * matT[1][2];
538 matMT[2][0] = matT[2][0];
539 matMT[2][1] = matT[2][1];
540 matMT[2][2] = matT[2][2];
541
542 // calculate DResid_i/Dx_j = (delta_ij - M_i^tr * T_j) * DTrack_k/Dx_k
543 dr1[0] = -(matMT[0][0] + matMT[0][1] * trDx.dydx + matMT[0][2] * trDx.dzdx);
544 dr1[1] = -(matMT[1][0] + matMT[1][1] * trDx.dydx + matMT[1][2] * trDx.dzdx);
545 dr1[2] = -(matMT[2][0] + matMT[2][1] * trDx.dydx + matMT[2][2] * trDx.dzdx);
546
547 // calculate D2Resid_I/(Dx_J Dx_K) = (delta_ijk - M_i^tr * T_j * delta_jk) * D2Track_k/dx_k^2
548 dr2[0] = -(matMT[0][1] * trDx.d2ydx2 + matMT[0][2] * trDx.d2zdx2);
549 dr2[1] = -(matMT[1][1] * trDx.d2ydx2 + matMT[1][2] * trDx.d2zdx2);
550 dr2[2] = -(matMT[2][1] * trDx.d2ydx2 + matMT[2][2] * trDx.d2zdx2);
551
552 if (i == j) {
553 dr1[0] += 1.;
554 dr1[1] += trDx.dydx;
555 dr1[2] += trDx.dzdx;
556
557 dr2[1] += trDx.d2ydx2;
558 dr2[2] += trDx.d2zdx2;
559 }
560 } // track over which we differentiate
561 } // residual being differentiated
562}
563
564//__________________________________________________________________________
565template <int N, typename... Args>
566GPUd() void DCAFitterN<N, Args...>::calcResidDerivativesNoErr()
567{
568 //< calculate matrix of derivatives for absolute distance chi2: residual i vs parameter X of track j
569 constexpr double NInv1 = 1. - NInv; // profit from Rii = I/Ninv
570 for (int i = N; i--;) { // residual being differentiated
571 const auto& trDxi = mTrDer[mCurHyp][i]; // track point derivs over track X param
572 auto& dr1ii = mDResidDx[i][i];
573 auto& dr2ii = mD2ResidDx2[i][i];
574 dr1ii[0] = NInv1;
575 dr1ii[1] = NInv1 * trDxi.dydx;
576 dr1ii[2] = NInv1 * trDxi.dzdx;
577
578 dr2ii[0] = 0;
579 dr2ii[1] = NInv1 * trDxi.d2ydx2;
580 dr2ii[2] = NInv1 * trDxi.d2zdx2;
581
582 for (int j = i; j--;) { // track over which we differentiate
583 auto& dr1ij = mDResidDx[i][j];
584 auto& dr1ji = mDResidDx[j][i];
585 const auto& trDxj = mTrDer[mCurHyp][j]; // track point derivs over track X param
586 auto cij = mCosDif[i][j], sij = mSinDif[i][j]; // M_i^T*M_j / N matrices non-trivial elements = {ci*cj+si*sj , si*cj-ci*sj }, see 5 in ref.
587
588 // calculate DResid_i/Dx_j = (delta_ij - R_ij) * DTrack_j/Dx_j for j<i
589 dr1ij[0] = -(cij + sij * trDxj.dydx);
590 dr1ij[1] = -(-sij + cij * trDxj.dydx);
591 dr1ij[2] = -trDxj.dzdx * NInv;
592
593 // calculate DResid_j/Dx_i = (delta_ij - R_ji) * DTrack_i/Dx_i for j<i
594 dr1ji[0] = -(cij - sij * trDxi.dydx);
595 dr1ji[1] = -(sij + cij * trDxi.dydx);
596 dr1ji[2] = -trDxi.dzdx * NInv;
597
598 auto& dr2ij = mD2ResidDx2[i][j];
599 auto& dr2ji = mD2ResidDx2[j][i];
600 // calculate D2Resid_I/(Dx_J Dx_K) = (delta_ij - Rij) * D2Track_j/dx_j^2 * delta_jk for j<i
601 dr2ij[0] = -sij * trDxj.d2ydx2;
602 dr2ij[1] = -cij * trDxj.d2ydx2;
603 dr2ij[2] = -trDxj.d2zdx2 * NInv;
604
605 // calculate D2Resid_j/(Dx_i Dx_k) = (delta_ij - Rji) * D2Track_i/dx_i^2 * delta_ik for j<i
606 dr2ji[0] = sij * trDxi.d2ydx2;
607 dr2ji[1] = -cij * trDxi.d2ydx2;
608 dr2ji[2] = -trDxi.d2zdx2 * NInv;
609
610 } // track over which we differentiate
611 } // residual being differentiated
612}
613
614//__________________________________________________________________________
615template <int N, typename... Args>
616GPUd() void DCAFitterN<N, Args...>::calcRMatrices()
617{
618 //< calculate Rij = 1/N M_i^T * M_j matrices (rotation from j-th track to i-th track frame)
619 for (int i = N; i--;) {
620 const auto& mi = mTrAux[i];
621 for (int j = i; j--;) {
622 const auto& mj = mTrAux[j];
623 mCosDif[i][j] = (mi.c * mj.c + mi.s * mj.s) * NInv; // cos(alp_i-alp_j) / N
624 mSinDif[i][j] = (mi.s * mj.c - mi.c * mj.s) * NInv; // sin(alp_i-alp_j) / N
625 }
626 }
627}
628
629//__________________________________________________________________________
630template <int N, typename... Args>
631GPUd() void DCAFitterN<N, Args...>::calcChi2Derivatives()
632{
633 //< calculate 1st and 2nd derivatives of wighted DCA (chi2) over track parameters X, see EQ.Chi2 in the ref
634 o2::gpu::gpustd::array<o2::gpu::gpustd::array<Vec3D, N>, N> covIDrDx; // tempory vectors of covI_j * dres_j/dx_i
635
636 // chi2 1st derivative
637 for (int i = N; i--;) {
638 auto& dchi1 = mDChi2Dx[i]; // DChi2/Dx_i = sum_j { res_j * covI_j * Dres_j/Dx_i }
639 dchi1 = 0;
640 for (int j = N; j--;) {
641 const auto& res = mTrRes[mCurHyp][j]; // vector of residuals of track j
642 const auto& covI = mTrcEInv[mCurHyp][j]; // inverse cov matrix of track j
643 const auto& dr1 = mDResidDx[j][i]; // vector of j-th residuals 1st derivative over X param of track i
644 auto& cidr = covIDrDx[i][j]; // vector covI_j * dres_j/dx_i, save for 2nd derivative calculation
645 cidr[0] = covI.sxx * dr1[0];
646 cidr[1] = covI.syy * dr1[1] + covI.syz * dr1[2];
647 cidr[2] = covI.syz * dr1[1] + covI.szz * dr1[2];
648 // calculate res_i * covI_j * dres_j/dx_i
649 dchi1 += o2::math_utils::Dot(res, cidr);
650 }
651 }
652 // chi2 2nd derivative
653 for (int i = N; i--;) {
654 for (int j = i + 1; j--;) { // symmetric matrix
655 auto& dchi2 = mD2Chi2Dx2[i][j]; // D2Chi2/Dx_i/Dx_j = sum_k { Dres_k/Dx_j * covI_k * Dres_k/Dx_i + res_k * covI_k * D2res_k/Dx_i/Dx_j }
656 dchi2 = 0;
657 for (int k = N; k--;) {
658 const auto& dr1j = mDResidDx[k][j]; // vector of k-th residuals 1st derivative over X param of track j
659 const auto& cidrkj = covIDrDx[i][k]; // vector covI_k * dres_k/dx_i
660 dchi2 += o2::math_utils::Dot(dr1j, cidrkj);
661 if (k == j) {
662 const auto& res = mTrRes[mCurHyp][k]; // vector of residuals of track k
663 const auto& covI = mTrcEInv[mCurHyp][k]; // inverse cov matrix of track k
664 const auto& dr2ij = mD2ResidDx2[k][j]; // vector of k-th residuals 2nd derivative over X params of track j
665 dchi2 += res[0] * covI.sxx * dr2ij[0] + res[1] * (covI.syy * dr2ij[1] + covI.syz * dr2ij[2]) + res[2] * (covI.syz * dr2ij[1] + covI.szz * dr2ij[2]);
666 }
667 }
668 }
669 }
670}
671
672//__________________________________________________________________________
673template <int N, typename... Args>
674GPUd() void DCAFitterN<N, Args...>::calcChi2DerivativesNoErr()
675{
676 //< calculate 1st and 2nd derivatives of abs DCA (chi2) over track parameters X, see (6) in the ref
677 for (int i = N; i--;) {
678 auto& dchi1 = mDChi2Dx[i]; // DChi2/Dx_i = sum_j { res_j * Dres_j/Dx_i }
679 dchi1 = 0; // chi2 1st derivative
680 for (int j = N; j--;) {
681 const auto& res = mTrRes[mCurHyp][j]; // vector of residuals of track j
682 const auto& dr1 = mDResidDx[j][i]; // vector of j-th residuals 1st derivative over X param of track i
683 dchi1 += o2::math_utils::Dot(res, dr1);
684 if (i >= j) { // symmetrix matrix
685 // chi2 2nd derivative
686 auto& dchi2 = mD2Chi2Dx2[i][j]; // D2Chi2/Dx_i/Dx_j = sum_k { Dres_k/Dx_j * covI_k * Dres_k/Dx_i + res_k * covI_k * D2res_k/Dx_i/Dx_j }
687 dchi2 = o2::math_utils::Dot(mTrRes[mCurHyp][i], mD2ResidDx2[i][j]);
688 for (int k = N; k--;) {
689 dchi2 += o2::math_utils::Dot(mDResidDx[k][i], mDResidDx[k][j]);
690 }
691 }
692 }
693 }
694}
695
696//___________________________________________________________________
697template <int N, typename... Args>
698GPUd() void DCAFitterN<N, Args...>::calcPCA()
699{
700 // calculate point of closest approach for N prongs
701 mPCA[mCurHyp] = mTrCFVT[mCurHyp][N - 1] * mTrPos[mCurHyp][N - 1];
702 for (int i = N - 1; i--;) {
703 mPCA[mCurHyp] += mTrCFVT[mCurHyp][i] * mTrPos[mCurHyp][i];
704 }
705}
706
707//___________________________________________________________________
708template <int N, typename... Args>
709GPUd() bool DCAFitterN<N, Args...>::recalculatePCAWithErrors(int cand)
710{
711 // recalculate PCA as a cov-matrix weighted mean, even if absDCA method was used
712 if (isPropagateTracksToVertexDone(cand) && !propagateTracksToVertex(cand)) {
713 return false;
714 }
715 int saveCurHyp = mCurHyp;
716 mCurHyp = mOrder[cand];
717 if (mUseAbsDCA) {
718 for (int i = N; i--;) {
719 if (!mTrcEInv[mCurHyp][i].set(mCandTr[mCurHyp][i], XerrFactor)) { // prepare inverse cov.matrices at starting point
720 if (mLoggerBadCov.needToLog()) {
721#ifndef GPUCA_GPUCODE
722 printf("fitter %d: error (%ld muted): overrode invalid track covariance from %s\n",
723 mFitterID, mLoggerBadCov.getNMuted(), mCandTr[mCurHyp][i].asString().c_str());
724#else
725 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());
727#endif
728 mLoggerBadCov.evCountPrev = mLoggerBadCov.evCount;
729 }
730 if (mBadCovPolicy == Discard) {
731 return false;
732 } else if (mBadCovPolicy == OverrideAndFlag) {
733 mPropFailed[mCurHyp] = true;
734 } // otherwise, just use overridden errors w/o flagging
735 }
736 }
737 if (!calcPCACoefs()) {
738 mCurHyp = saveCurHyp;
739 return false;
740 }
741 }
742 auto oldPCA = mPCA[mOrder[cand]];
743 calcPCA();
744 mCurHyp = saveCurHyp;
745 return true;
746}
747
748//___________________________________________________________________
749template <int N, typename... Args>
750GPUd() void DCAFitterN<N, Args...>::calcPCANoErr()
751{
752 // calculate point of closest approach for N prongs w/o errors
753 auto& pca = mPCA[mCurHyp];
754 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);
755 // RRRR mTrAux[N-1].loc2glo(mTrPos[mCurHyp][N-1][0], mTrPos[mCurHyp][N-1][1], pca[0], pca[1] );
756 pca[2] = mTrPos[mCurHyp][N - 1][2];
757 for (int i = N - 1; i--;) {
758 double x, y;
759 o2::math_utils::rotateZd(mTrPos[mCurHyp][i][0], mTrPos[mCurHyp][i][1], x, y, mTrAux[i].s, mTrAux[i].c);
760 // RRRR mTrAux[i].loc2glo(mTrPos[mCurHyp][i][0], mTrPos[mCurHyp][i][1], x, y );
761 pca[0] += x;
762 pca[1] += y;
763 pca[2] += mTrPos[mCurHyp][i][2];
764 }
765 pca[0] *= NInv;
766 pca[1] *= NInv;
767 pca[2] *= NInv;
768}
769
770//___________________________________________________________________
771template <int N, typename... Args>
772GPUd() o2::math_utils::SMatrix<double, 3, 3, o2::math_utils::MatRepSym<double, 3>> DCAFitterN<N, Args...>::calcPCACovMatrix(int cand) const
773{
774 // calculate covariance matrix for the point of closest approach
775 MatSym3D covm;
776 int nAdded = 0;
777 for (int i = N; i--;) { // calculate sum of inverses
778 // MatSym3D covTr = o2::math_utils::Similarity(mUseAbsDCA ? getTrackRotMatrix(i) : mTrCFVT[mOrder[cand]][i], getTrackCovMatrix(i, cand));
779 // RS by using Similarity(mTrCFVT[mOrder[cand]][i], getTrackCovMatrix(i, cand)) we underestimate the error, use simple rotation
780 MatSym3D covTr = o2::math_utils::Similarity(getTrackRotMatrix(i), getTrackCovMatrix(i, cand));
781 if (covTr.Invert()) {
782 covm += covTr;
783 nAdded++;
784 }
785 }
786 if (nAdded && covm.Invert()) {
787 return covm;
788 }
789 // correct way has failed, use simple sum
790 MatSym3D covmSum;
791 for (int i = N; i--;) {
792 MatSym3D covTr = o2::math_utils::Similarity(getTrackRotMatrix(i), getTrackCovMatrix(i, cand));
793 }
794 return covmSum;
795}
796
797//___________________________________________________________________
798template <int N, typename... Args>
799GPUd() void DCAFitterN<N, Args...>::calcTrackResiduals()
800{
801 // calculate residuals
802 Vec3D vtxLoc;
803 for (int i = N; i--;) {
804 mTrRes[mCurHyp][i] = mTrPos[mCurHyp][i];
805 vtxLoc = mPCA[mCurHyp];
806 o2::math_utils::rotateZInvd(vtxLoc[0], vtxLoc[1], vtxLoc[0], vtxLoc[1], mTrAux[i].s, mTrAux[i].c); // glo->loc
807 mTrRes[mCurHyp][i] -= vtxLoc;
808 }
809}
810
811//___________________________________________________________________
812template <int N, typename... Args>
813GPUdi() void DCAFitterN<N, Args...>::calcTrackDerivatives()
814{
815 // calculate track derivatives over X param
816 for (int i = N; i--;) {
817 mTrDer[mCurHyp][i].set(mCandTr[mCurHyp][i], mBz);
818 }
819}
820
821//___________________________________________________________________
822template <int N, typename... Args>
823GPUdi() double DCAFitterN<N, Args...>::calcChi2() const
824{
825 // calculate current chi2
826 double chi2 = 0;
827 for (int i = N; i--;) {
828 const auto& res = mTrRes[mCurHyp][i];
829 const auto& covI = mTrcEInv[mCurHyp][i];
830 chi2 += res[0] * res[0] * covI.sxx + res[1] * res[1] * covI.syy + res[2] * res[2] * covI.szz + 2. * res[1] * res[2] * covI.syz;
831 }
832 return chi2;
833}
834
835//___________________________________________________________________
836template <int N, typename... Args>
837GPUdi() double DCAFitterN<N, Args...>::calcChi2NoErr() const
838{
839 // calculate current chi2 of abs. distance minimization
840 double chi2 = 0;
841 for (int i = N; i--;) {
842 const auto& res = mTrRes[mCurHyp][i];
843 chi2 += res[0] * res[0] + res[1] * res[1] + res[2] * res[2];
844 }
845 return chi2;
846}
847
848//___________________________________________________________________
849template <int N, typename... Args>
850GPUd() bool DCAFitterN<N, Args...>::correctTracks(const VecND& corrX)
851{
852 // propagate tracks to updated X
853 for (int i = N; i--;) {
854 const auto& trDer = mTrDer[mCurHyp][i];
855 auto dx2h = 0.5 * corrX[i] * corrX[i];
856 mTrPos[mCurHyp][i][0] -= corrX[i];
857 mTrPos[mCurHyp][i][1] -= trDer.dydx * corrX[i] - dx2h * trDer.d2ydx2;
858 mTrPos[mCurHyp][i][2] -= trDer.dzdx * corrX[i] - dx2h * trDer.d2zdx2;
859 }
860 return true;
861}
862
863//___________________________________________________________________
864template <int N, typename... Args>
865GPUd() bool DCAFitterN<N, Args...>::propagateTracksToVertex(int icand)
866{
867 // propagate tracks to current vertex
868 int ord = mOrder[icand];
869 if (mTrPropDone[ord]) {
870 return true;
871 }
872
873 // need to refit taking as a seed already found vertex
874 if (mRefitWithMatCorr) {
875 int curHypSav = mCurHyp, curCrosIDAlt = mCrossIDAlt; // save
876 mCurHyp = ord;
877 mCrossIDAlt = -1; // disable alternative check
878 auto restore = [this, curHypSav, curCrosIDAlt]() { this->mCurHyp = curHypSav; this->mCrossIDAlt = curCrosIDAlt; };
879 if (!(mUseAbsDCA ? minimizeChi2NoErr() : minimizeChi2())) { // do final propagation
880 restore();
881 return false;
882 }
883 restore();
884 }
885
886 for (int i = N; i--;) {
887 if (mUseAbsDCA || mUsePropagator || mMatCorr != o2::base::Propagator::MatCorrType::USEMatCorrNONE) {
888 mCandTr[ord][i] = *mOrigTrPtr[i]; // fetch the track again, as mCandTr might have been propagated w/o errors or material corrections might be wrong
889 }
890 auto x = mTrAux[i].c * mPCA[ord][0] + mTrAux[i].s * mPCA[ord][1]; // X of PCA in the track frame
891 if (!propagateToX(mCandTr[ord][i], x)) {
892 return false;
893 }
894 }
895
896 mTrPropDone[ord] = true;
897 return true;
898}
899
900//___________________________________________________________________
901template <int N, typename... Args>
902GPUdi() o2::track::TrackPar DCAFitterN<N, Args...>::getTrackParamAtPCA(int i, int icand)
903{
904 // propagate tracks param only to current vertex (if not already done)
905 int ord = mOrder[icand];
906 o2::track::TrackPar trc(mCandTr[ord][i]);
907 if (!mTrPropDone[ord]) {
908 auto x = mTrAux[i].c * mPCA[ord][0] + mTrAux[i].s * mPCA[ord][1]; // X of PCA in the track frame
909 if (!propagateParamToX(trc, x)) {
910 trc.invalidate();
911 }
912 }
913 return trc;
914}
915
916//___________________________________________________________________
917template <int N, typename... Args>
918GPUdi() double DCAFitterN<N, Args...>::getAbsMax(const VecND& v)
919{
920 double mx = -1;
921 for (int i = N; i--;) {
922 auto vai = o2::gpu::GPUCommonMath::Abs(v[i]);
923 if (mx < vai) {
924 mx = vai;
925 }
926 }
927 return mx;
928}
929
930//___________________________________________________________________
931template <int N, typename... Args>
932GPUd() bool DCAFitterN<N, Args...>::minimizeChi2()
933{
934 // find best chi2 (weighted DCA) of N tracks in the vicinity of the seed PCA
935 for (int i = N; i--;) {
936 mCandTr[mCurHyp][i] = *mOrigTrPtr[i];
937 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)) {
939 return false;
940 }
941 setTrackPos(mTrPos[mCurHyp][i], mCandTr[mCurHyp][i]); // prepare positions
942 if (!mTrcEInv[mCurHyp][i].set(mCandTr[mCurHyp][i], XerrFactor)) { // prepare inverse cov.matrices at starting point
943 if (mLoggerBadCov.needToLog()) {
944#ifndef GPUCA_GPUCODE
945 printf("fitter %d: error (%ld muted): overrode invalid track covariance from %s\n",
946 mFitterID, mLoggerBadCov.getNMuted(), mCandTr[mCurHyp][i].asString().c_str());
947#else
948 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());
950#endif
951 mLoggerBadCov.evCountPrev = mLoggerBadCov.evCount;
952 }
953 if (mBadCovPolicy == Discard) {
954 return false;
955 } else if (mBadCovPolicy == OverrideAndFlag) {
956 mPropFailed[mCurHyp] = true;
957 } // otherwise, just use overridden errors w/o flagging
958 }
959 }
960
961 if (mMaxDZIni > 0 && !roughDZCut()) { // apply rough cut on tracks Z difference
962 return false;
963 }
964
965 if (!calcPCACoefs()) { // prepare tracks contribution matrices to the global PCA
966 return false;
967 }
968 calcPCA(); // current PCA
969 calcTrackResiduals(); // current track residuals
970 float chi2Upd, chi2 = calcChi2();
971 do {
972 calcTrackDerivatives(); // current track derivatives (1st and 2nd)
973 calcResidDerivatives(); // current residals derivatives (1st and 2nd)
974 calcChi2Derivatives(); // current chi2 derivatives (1st and 2nd)
975
976 // do Newton-Rapson iteration with corrections = - dchi2/d{x0..xN} * [ d^2chi2/d{x0..xN}^2 ]^-1
977 if (!mD2Chi2Dx2.Invert()) {
978 if (mLoggerBadInv.needToLog()) {
979 printf("fitter %d: error (%ld muted): Inversion failed\n", mFitterID, mLoggerBadCov.getNMuted());
980 mLoggerBadInv.evCountPrev = mLoggerBadInv.evCount;
981 }
982 return false;
983 }
984 VecND dx = mD2Chi2Dx2 * mDChi2Dx;
985 if (!correctTracks(dx)) {
986 return false;
987 }
988 calcPCA(); // updated PCA
989 if (mCrossIDAlt >= 0 && closerToAlternative()) {
990 mAllowAltPreference = false;
991 return false;
992 }
993 calcTrackResiduals(); // updated residuals
994 chi2Upd = calcChi2(); // updated chi2
995 if (getAbsMax(dx) < mMinParamChange || chi2Upd > chi2 * mMinRelChi2Change) {
996 chi2 = chi2Upd;
997 break; // converged
998 }
999 chi2 = chi2Upd;
1000 } while (++mNIters[mCurHyp] < mMaxIter);
1001 //
1002 mChi2[mCurHyp] = chi2 * NInv;
1003 return mChi2[mCurHyp] < mMaxChi2;
1004}
1005
1006//___________________________________________________________________
1007template <int N, typename... Args>
1008GPUd() bool DCAFitterN<N, Args...>::minimizeChi2NoErr()
1009{
1010 // find best chi2 (absolute DCA) of N tracks in the vicinity of the PCA seed
1011
1012 for (int i = N; i--;) {
1013 mCandTr[mCurHyp][i] = *mOrigTrPtr[i];
1014 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)) {
1016 return false;
1017 }
1018 setTrackPos(mTrPos[mCurHyp][i], mCandTr[mCurHyp][i]); // prepare positions
1019 }
1020 if (mMaxDZIni > 0 && !roughDZCut()) { // apply rough cut on tracks Z difference
1021 return false;
1022 }
1023
1024 calcPCANoErr(); // current PCA
1025 calcTrackResiduals(); // current track residuals
1026 float chi2Upd, chi2 = calcChi2NoErr();
1027 do {
1028 calcTrackDerivatives(); // current track derivatives (1st and 2nd)
1029 calcResidDerivativesNoErr(); // current residals derivatives (1st and 2nd)
1030 calcChi2DerivativesNoErr(); // current chi2 derivatives (1st and 2nd)
1031
1032 // do Newton-Rapson iteration with corrections = - dchi2/d{x0..xN} * [ d^2chi2/d{x0..xN}^2 ]^-1
1033 if (!mD2Chi2Dx2.Invert()) {
1034 if (mLoggerBadInv.needToLog()) {
1035 printf("itter %d: error (%ld muted): Inversion failed\n", mFitterID, mLoggerBadCov.getNMuted());
1036 mLoggerBadInv.evCountPrev = mLoggerBadInv.evCount;
1037 }
1038 return false;
1039 }
1040 VecND dx = mD2Chi2Dx2 * mDChi2Dx;
1041 if (!correctTracks(dx)) {
1042 return false;
1043 }
1044 calcPCANoErr(); // updated PCA
1045 if (mCrossIDAlt >= 0 && closerToAlternative()) {
1046 mAllowAltPreference = false;
1047 return false;
1048 }
1049 calcTrackResiduals(); // updated residuals
1050 chi2Upd = calcChi2NoErr(); // updated chi2
1051 if (getAbsMax(dx) < mMinParamChange || chi2Upd > chi2 * mMinRelChi2Change) {
1052 chi2 = chi2Upd;
1053 break; // converged
1054 }
1055 chi2 = chi2Upd;
1056 } while (++mNIters[mCurHyp] < mMaxIter);
1057 //
1058 mChi2[mCurHyp] = chi2 * NInv;
1059 return mChi2[mCurHyp] < mMaxChi2;
1060}
1061
1062//___________________________________________________________________
1063template <int N, typename... Args>
1064GPUd() bool DCAFitterN<N, Args...>::roughDZCut() const
1065{
1066 // apply rough cut on DZ between the tracks in the seed point
1067 bool accept = true;
1068 for (int i = N; accept && i--;) {
1069 for (int j = i; j--;) {
1070 if (o2::gpu::GPUCommonMath::Abs(mCandTr[mCurHyp][i].getZ() - mCandTr[mCurHyp][j].getZ()) > mMaxDZIni) {
1071 accept = false;
1072 break;
1073 }
1074 }
1075 }
1076 return accept;
1077}
1078
1079//___________________________________________________________________
1080template <int N, typename... Args>
1081GPUd() bool DCAFitterN<N, Args...>::closerToAlternative() const
1082{
1083 // check if the point current PCA point is closer to the seeding XY point being tested or to alternative see (if any)
1084 auto dxCur = mPCA[mCurHyp][0] - mCrossings.xDCA[mCrossIDCur], dyCur = mPCA[mCurHyp][1] - mCrossings.yDCA[mCrossIDCur];
1085 auto dxAlt = mPCA[mCurHyp][0] - mCrossings.xDCA[mCrossIDAlt], dyAlt = mPCA[mCurHyp][1] - mCrossings.yDCA[mCrossIDAlt];
1086 return dxCur * dxCur + dyCur * dyCur > dxAlt * dxAlt + dyAlt * dyAlt;
1087}
1088
1089//___________________________________________________________________
1090template <int N, typename... Args>
1091GPUd() void DCAFitterN<N, Args...>::print() const
1092{
1093#ifndef GPUCA_GPUCODE_DEVICE
1094 LOG(info) << N << "-prong vertex fitter in " << (mUseAbsDCA ? "abs." : "weighted") << " distance minimization mode, collinear tracks mode: " << (mIsCollinear ? "ON" : "OFF");
1095 LOG(info) << "Bz: " << mBz << " MaxIter: " << mMaxIter << " MaxChi2: " << mMaxChi2 << " MatCorrType: " << int(mMatCorr);
1096 LOG(info) << "Stopping condition: Max.param change < " << mMinParamChange << " Rel.Chi2 change > " << mMinRelChi2Change;
1097 LOG(info) << "Discard candidates for : Rvtx > " << getMaxR() << " DZ between tracks > " << mMaxDZIni;
1098 LOG(info) << "PropagateToPCA:" << mPropagateToPCA << " WeightedFinalPCA:" << mWeightedFinalPCA << " UsePropagator:" << mUsePropagator << " RefitWithMatCorr:" << mRefitWithMatCorr;
1099 std::string rep{};
1100 for (int i = 0; i < mCrossings.nDCA; i++) {
1101 rep += fmt::format("seed{}:{}/{} ", i, mTrPropDone[i], mPropFailed[i]);
1102 }
1103 LOG(info) << "Last call: NCand:" << mCurHyp << " from " << mCrossings.nDCA << " seeds, prop.done/failed: " << rep;
1104#else
1105 if (mUseAbsDCA) {
1106 printf("%d-prong vertex fitter in abs. distance minimization mode\n", N);
1107 } else {
1108 printf("%d-prong vertex fitter in weighted distance minimization mode\n", N);
1109 }
1110 printf("Bz: %1.f MaxIter: %3.d MaxChi2: %2.3f\n", mBz, mMaxIter, mMaxChi2);
1111 printf("Stopping condition: Max.param change < %2.3f Rel.Chi2 change > %2.3f\n", mMinParamChange, mMinRelChi2Change);
1112 printf("Discard candidates for : Rvtx > %2.3f DZ between tracks > %2.3f\n", getMaxR(), mMaxDZIni);
1113#endif
1114}
1115
1116//___________________________________________________________________
1117template <int N, typename... Args>
1118GPUd() o2::track::TrackParCov DCAFitterN<N, Args...>::createParentTrackParCov(int cand, bool sectorAlpha) const
1119{
1120 const auto& trP = getTrack(0, cand);
1121 const auto& trN = getTrack(1, cand);
1124 int q = 0;
1125 for (int it = 0; it < N; it++) {
1126 const auto& trc = getTrack(it, cand);
1129 trc.getPxPyPzGlo(pvecT);
1130 trc.getCovXYZPxPyPzGlo(covT);
1131 constexpr int MomInd[6] = {9, 13, 14, 18, 19, 20}; // cov matrix elements for momentum component
1132 for (int i = 0; i < 6; i++) {
1133 covV[MomInd[i]] += covT[MomInd[i]];
1134 }
1135 for (int i = 0; i < 3; i++) {
1136 pvecV[i] += pvecT[i];
1137 }
1138 q += trc.getCharge();
1139 }
1140 auto covVtxV = calcPCACovMatrix(cand);
1141 covV[0] = covVtxV(0, 0);
1142 covV[1] = covVtxV(1, 0);
1143 covV[2] = covVtxV(1, 1);
1144 covV[3] = covVtxV(2, 0);
1145 covV[4] = covVtxV(2, 1);
1146 covV[5] = covVtxV(2, 2);
1147 return o2::track::TrackParCov(getPCACandidatePos(cand), pvecV, covV, q, sectorAlpha);
1148}
1149
1150//___________________________________________________________________
1151template <int N, typename... Args>
1152GPUd() o2::track::TrackPar DCAFitterN<N, Args...>::createParentTrackPar(int cand, bool sectorAlpha) const
1153{
1154 const auto& trP = getTrack(0, cand);
1155 const auto& trN = getTrack(1, cand);
1156 const auto& wvtx = getPCACandidate(cand);
1158 int q = 0;
1159 for (int it = 0; it < N; it++) {
1160 const auto& trc = getTrack(it, cand);
1162 trc.getPxPyPzGlo(pvecT);
1163 for (int i = 0; i < 3; i++) {
1164 pvecV[i] += pvecT[i];
1165 }
1166 q += trc.getCharge();
1167 }
1168 const o2::gpu::gpustd::array<float, 3> vertex = {(float)wvtx[0], (float)wvtx[1], (float)wvtx[2]};
1169 return o2::track::TrackPar(vertex, pvecV, q, sectorAlpha);
1170}
1171
1172//___________________________________________________________________
1173template <int N, typename... Args>
1174GPUdi() bool DCAFitterN<N, Args...>::propagateParamToX(o2::track::TrackPar& t, float x)
1175{
1176 bool res = true;
1177 if (mUsePropagator || mMatCorr != o2::base::Propagator::MatCorrType::USEMatCorrNONE) {
1178#ifndef GPUCA_GPUCODE
1179 res = o2::base::Propagator::Instance()->PropagateToXBxByBz(t, x, mMaxSnp, mMaxStep, mMatCorr);
1180#endif
1181 } else {
1182 res = t.propagateParamTo(x, mBz);
1183 }
1184 if (!res) {
1185 mPropFailed[mCurHyp] = true;
1186 if (mLoggerBadProp.needToLog()) {
1187#ifndef GPUCA_GPUCODE
1188 printf("fitter %d: error (%ld muted): propagation failed for %s\n", mFitterID, mLoggerBadProp.getNMuted(), t.asString().c_str());
1189#else
1190 printf("fitter %d: error (%ld muted): propagation failed\n", mFitterID, mLoggerBadProp.getNMuted());
1191#endif
1192 mLoggerBadProp.evCountPrev = mLoggerBadProp.evCount;
1193 }
1194 }
1195 return res;
1196}
1197
1198//___________________________________________________________________
1199template <int N, typename... Args>
1200GPUdi() bool DCAFitterN<N, Args...>::propagateToX(o2::track::TrackParCov& t, float x)
1201{
1202 bool res = true;
1203 if (mUsePropagator || mMatCorr != o2::base::Propagator::MatCorrType::USEMatCorrNONE) {
1204#ifndef GPUCA_GPUCODE
1205 res = o2::base::Propagator::Instance()->PropagateToXBxByBz(t, x, mMaxSnp, mMaxStep, mMatCorr);
1206#endif
1207 } else {
1208 res = t.propagateTo(x, mBz);
1209 }
1210 if (!res) {
1211 mPropFailed[mCurHyp] = true;
1212 if (mLoggerBadProp.needToLog()) {
1213#ifndef GPUCA_GPUCODE
1214 printf("fitter %d: error (%ld muted): propagation failed for %s\n", mFitterID, mLoggerBadProp.getNMuted(), t.asString().c_str());
1215#else
1216 printf("fitter %d: error (%ld muted): propagation failed\n", mFitterID, mLoggerBadProp.getNMuted());
1217#endif
1218 mLoggerBadProp.evCountPrev = mLoggerBadProp.evCount;
1219 }
1220 }
1221 return res;
1222}
1223
1226
1227namespace device
1228{
1229template <typename Fitter>
1230void print(const int nBlocks, const int nThreads, Fitter& ft);
1231
1232template <typename Fitter, class... Tr>
1233int process(const int nBlocks, const int nThreads, Fitter&, Tr&... args);
1234
1235template <class Fitter, class... Tr>
1236void processBulk(const int nBlocks, const int nThreads, const int nBatches, std::vector<Fitter>& fitters, std::vector<int>& results, std::vector<Tr>&... args);
1237} // namespace device
1238
1239} // namespace vertexing
1240} // namespace o2
1241#endif // _ALICEO2_DCA_FITTERN_
Helper classes for helical tracks manipulations.
Base track model for the Barrel, params only, w/o covariance.
uint64_t vertex
Definition RawEventData.h:9
void print() const
int32_t i
uint32_t j
Definition RawData.h:0
uint32_t res
Definition RawData.h:0
uint32_t c
Definition RawData.h:2
o2::track::TrackParCov TrackParCov
Definition Recon.h:39
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:143
const Track & getTrack(int i, int cand=0) const
create parent track param with errors for decay vertex
Definition DCAFitterN.h:172
GPUd() const auto getPCACandidatePos(int cand=0) const
return position of quality-ordered candidate in the internal structures
Definition DCAFitterN.h:138
const Track * getOrigTrackPtr(int i) const
return number of iterations during minimization (no check for its validity)
Definition DCAFitterN.h:202
int class Tr const T & t
Definition DCAFitterN.h:305
void setBadCovPolicy(BadCovPolicy v)
Definition DCAFitterN.h:334
GPUd() bool calcPCACoefs()
GPUdi() size_t getCallID() const
Definition DCAFitterN.h:251
GPUdi() void setFitterID(int i)
Definition DCAFitterN.h:250
int cand
track X-param at V0 candidate (no check for the candidate validity)
Definition DCAFitterN.h:277
GPUdi() int getNIterations(int cand=0) const
Definition DCAFitterN.h:205
GPUd() const Vec3D &getPCACandidate(int cand=0) const
< return PCA candidate, by default best on is provided (no check for the index validity)
Definition DCAFitterN.h:137
GPUdi() void clearLogThrottlers()
Definition DCAFitterN.h:327
int getCandidatePosition(int cand=0) const
return Chi2 at PCA candidate (no check for its validity)
Definition DCAFitterN.h:145
static constexpr int getNProngs()
Definition DCAFitterN.h:127
bool isPropagationFailure(int cand=0) const
Definition DCAFitterN.h:158
DCAFitterN(float bz, bool useAbsDCA, bool prop2DCA)
Definition DCAFitterN.h:130
GPUdi() void setPropagateToPCA(bool v
o2::gpu::gpustd::array< float, 6 > calcPCACovMatrixFlat(int cand=0) const
Definition DCAFitterN.h:196
Track & getTrack(int i, int cand=0)
Definition DCAFitterN.h:162
GPUdi() static void setTrackPos(Vec3D &pnt
float getChi2AtPCACandidate(int cand=0) const
Definition DCAFitterN.h:148
GPUd() bool propagateTracksToVertex(int cand=0)
check if propagation of tracks to candidate vertex was done
BadCovPolicy getBadCovPolicy() const
Definition DCAFitterN.h:335
int class Tr const T const Tr & args
Definition DCAFitterN.h:306
GLdouble n
Definition glcorearb.h:1982
GLint GLenum GLint x
Definition glcorearb.h:403
const GLfloat * m
Definition glcorearb.h:4066
const GLdouble * v
Definition glcorearb.h:832
GLenum array
Definition glcorearb.h:4274
GLdouble f
Definition glcorearb.h:310
GLint y
Definition glcorearb.h:270
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLboolean r
Definition glcorearb.h:1233
void set(T *h, size_t v)
Definition PageParser.h:107
constexpr float Almost0
std::array< T, N > array
std::tuple< double, double > rotateZd(double xL, double yL, double snAlp, double csAlp)
Definition Utils.h:167
std::tuple< double, double > rotateZInvd(double xG, double yG, double snAlp, double csAlp)
Definition Utils.h:147
SMatrix< T, D1, D1, MatRepSym< T, D1 > > Similarity(const SMatrix< T, D1, D2, R > &lhs, const SMatrix< T, D2, D2, MatRepSym< T, D2 > > &rhs)
Definition Cartesian.h:263
T Dot(const SVector< T, D > &lhs, const SVector< T, D > &rhs)
Definition Cartesian.h:257
TrackParCovF TrackParCov
Definition Track.h:33
TrackParF TrackPar
Definition Track.h:29
void processBulk(const int nBlocks, const int nThreads, const int nBatches, std::vector< Fitter > &fitters, std::vector< int > &results, std::vector< Tr > &... args)
GPUd() int DCAFitterN< N
ROOT::Math::SVector< double, 3 > Vec3D
GPUdi() void DCAFitterN< N
Definition DCAFitterN.h:902
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
GPUdi() size_t getNMuted() const
Definition DCAFitterN.h:90
GPUdi() bool needToLog()
Definition DCAFitterN.h:81
GPUd() bool set(const o2
Definition DCAFitterN.h:37
GPUdDefault() TrackCovI()=default
GPUd() TrackDeriv(const o2
Definition DCAFitterN.h:63
GPUd() void set(const o2
Definition DCAFitterN.h:64
GPUdDefault() TrackDeriv()=default
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
vec clear()