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
17
18#ifndef _ALICEO2_DCA_FITTERN_
19#define _ALICEO2_DCA_FITTERN_
20
23#include "MathUtils/Cartesian.h"
25
26namespace o2
27{
28namespace vertexing
29{
30
33struct TrackCovI {
34 // Independent elements of the symmetric 3D information matrix
35 // H^T Cyz^{-1} H. A track constrains Y and Z at a given X through
36 // H = {{-dY/dX, 1, 0}, {-dZ/dX, 0, 1}}.
37 float sxx, sxy, sxz, syy, syz, szz;
38
39 GPUdDefault() TrackCovI() = default;
40
41 GPUd() bool set(const o2::track::TrackParCov& trc)
42 {
43 // Invert the 2D covariance of the measured track position (Y,Z).
44 float cyy = trc.getSigmaY2(), czz = trc.getSigmaZ2(), cyz = trc.getSigmaZY();
45 float detYZ = cyy * czz - cyz * cyz;
46 bool res = true;
47 if (detYZ <= 0.) {
48 cyz = o2::gpu::GPUCommonMath::Sqrt(cyy * czz) * (cyz > 0 ? 0.98f : -0.98f);
49 detYZ = cyy * czz - cyz * cyz;
50 res = false;
51 }
52 auto detYZI = 1. / detYZ;
53 syy = czz * detYZI;
54 syz = -cyz * detYZI;
55 szz = cyy * detYZI;
56 const float cspI = 1.f / trc.getCsp();
57 const float dydx = trc.getSnp() * cspI;
58 const float dzdx = trc.getTgl() * cspI;
59 sxy = -(syy * dydx + syz * dzdx);
60 sxz = -(syz * dydx + szz * dzdx);
61 sxx = dydx * dydx * syy + 2.f * dydx * dzdx * syz + dzdx * dzdx * szz;
62 // The matrix is degenerate by construction, regularize sxx term to preserve the original YZ block exactly
63 constexpr float XRegErrFactor = 10.f;
64 const float sigmaX2 = cyy * XRegErrFactor;
65 sxx += 1.f / sigmaX2;
66 return res;
67 }
68};
69
72struct TrackDeriv {
74 GPUdDefault() TrackDeriv() = default;
75 GPUd() TrackDeriv(const o2::track::TrackPar& trc, float bz) { set(trc, bz); }
76 GPUd() void set(const o2::track::TrackPar& trc, float bz)
77 {
78 float snp = trc.getSnp(), csp = o2::gpu::GPUCommonMath::Sqrt((1. - snp) * (1. + snp)), cspI = 1. / csp, crv2c = trc.getCurvature(bz) * cspI;
79 dydx = snp * cspI; // = snp/csp
80 dzdx = trc.getTgl() * cspI; // = tgl/csp
81 d2ydx2 = crv2c * cspI * cspI; // = crv/csp^3
82 d2zdx2 = crv2c * dzdx * dydx; // = crv*tgl*snp/csp^3
83 }
84};
85
89 size_t evCount{0};
90 size_t nextLog{1};
91 GPUdi() bool needToLog()
92 {
93 if (++evCount > nextLog) {
94 nextLog *= 2;
95 return true;
96 }
97 return false;
98 }
100 {
101 evCount = 0;
102 nextLog = 1;
103 }
104};
105
106template <int N, typename... Args>
108{
109 static constexpr double NMin = 2;
110 static constexpr double NMax = 4;
111 static constexpr double NInv = 1. / N;
112 static constexpr int MAXHYP = 2;
113 using Track = o2::track::TrackParCov;
116
123 using TrackCoefVtx = MatStd3D;
124 using ArrTrack = std::array<Track, N>; // container for prongs (tracks) at single vertex cand.
125 using ArrTrackCovI = std::array<TrackCovI, N>; // container for inv.cov.matrices at single vertex cand.
126 using ArrTrCoef = std::array<TrackCoefVtx, N>; // container of TrackCoefVtx coefficients at single vertex cand.
127 using ArrTrDer = std::array<TrackDeriv, N>; // container of Track 1st and 2nd derivative over their X param
128 using ArrTrPos = std::array<Vec3D, N>; // container of Track positions
129
130 public:
131 enum BadCovPolicy : uint8_t { // if encountering non-positive defined cov. matrix, the choice is:
132 Discard = 0, // stop evaluation
133 Override = 1, // override correlation coef. to have cov.matrix pos.def and continue
134 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)
135 };
136
137 enum FitStatus : uint8_t { // fit status of crossing hypothesis
138 None, // no status set (should not be possible!)
139
140 /* Good Conditions */
141 Converged, // fit converged
142 MaxIter, // max iterations reached before fit convergence
143
144 /* Error Conditions */
145 NoCrossing, // no reasaonable crossing was found
146 RejRadius, // radius of crossing was not acceptable
147 RejTrackX, // one candidate track x was below the mimimum required radius
148 RejTrackRoughZ, // rejected by rough cut on tracks Z difference
149 RejChi2Max, // rejected by maximum chi2 cut
150 FailProp, // propagation of at least prong to PCA failed
151 FailInvCov, // inversion of cov.-matrix failed
152 FailInvWeight, // inversion of Ti weight matrix failed
153 FailInv2ndDeriv, // inversion of 2nd derivatives failed
154 FailCorrTracks, // correction of tracks to updated x failed
155 FailCloserAlt, // alternative PCA is closer
156 //
158 };
159
160 static constexpr int getNProngs() { return N; }
161
162 DCAFitterN() = default;
163 DCAFitterN(float bz, bool useAbsDCA, bool prop2DCA) : mBz(bz), mUseAbsDCA(useAbsDCA), mPropagateToPCA(prop2DCA)
164 {
165 static_assert(N >= NMin && N <= NMax, "N prongs outside of allowed range");
166 }
167
168 //=========================================================================
170 GPUd() const Vec3D& getPCACandidate(int cand = 0) const { return mPCA[mOrder[cand]]; }
171 GPUd() const auto getPCACandidatePos(int cand = 0) const
172 {
173 const auto& vd = mPCA[mOrder[cand]];
174 return std::array<float, 3>{static_cast<float>(vd[0]), static_cast<float>(vd[1]), static_cast<float>(vd[2])};
175 }
176
178 int getCandidatePosition(int cand = 0) const { return mOrder[cand]; }
179
181 float getChi2AtPCACandidate(int cand = 0) const { return mChi2[mOrder[cand]]; }
182
185 GPUd() bool propagateTracksToVertex(int cand = 0);
186
188 GPUd() bool isPropagateTracksToVertexDone(int cand = 0) const { return mTrPropDone[mOrder[cand]]; }
189
191 bool isPropagationFailure(int cand = 0) const { return mPropFailed[mOrder[cand]]; }
192
195 Track& getTrack(int i, int cand = 0)
196 {
197 if (!mTrPropDone[mOrder[cand]]) {
198#ifndef GPUCA_GPUCODE_DEVICE
199 throw std::runtime_error("propagateTracksToVertex was not called yet");
200#endif
201 }
202 return mCandTr[mOrder[cand]][i];
203 }
204
205 const Track& getTrack(int i, int cand = 0) const
206 {
207 if (!mTrPropDone[mOrder[cand]]) {
208#ifndef GPUCA_GPUCODE_DEVICE
209 throw std::runtime_error("propagateTracksToVertex was not called yet");
210#endif
211 }
212 return mCandTr[mOrder[cand]][i];
213 }
214
216 GPUd() o2::track::TrackParCov createParentTrackParCov(int cand = 0, bool sectorAlpha = true) const;
217
219 GPUd() o2::track::TrackPar createParentTrackPar(int cand = 0, bool sectorAlpha = true) const;
220
222 GPUd() o2::track::TrackPar getTrackParamAtPCA(int i, int cand = 0);
223
225 GPUd() bool recalculatePCAWithErrors(int cand = 0);
226
227 GPUd() double calcCollinearInflation(int cand) const;
228 GPUd() MatSym3D calcPCACovMatrix(int cand = 0) const;
229
230 std::array<float, 6> calcPCACovMatrixFlat(int cand = 0) const
231 {
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))};
234 }
235
236 const Track* getOrigTrackPtr(int i) const { return mOrigTrPtr[i]; }
237
238 GPUdi() FitStatus getFitStatus(int cand = 0) const noexcept { return mFitStatus[mOrder[cand]]; }
239
241 GPUdi() int getNIterations(int cand = 0) const { return mNIters[mOrder[cand]]; }
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; }
248 GPUdi() void setBz(float bz) { mBz = o2::gpu::GPUCommonMath::Abs(bz) > o2::constants::math::Almost0 ? bz : 0.f; }
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; }
254 GPUdi() void setMatCorrType(o2::base::Propagator::MatCorrType m = o2::base::Propagator::MatCorrType::USEMatCorrLUT) { mMatCorr = m; }
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; }
261
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; }
274 GPUdi() o2::base::Propagator::MatCorrType getMatCorrType() const { return mMatCorr; }
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; }
280
281 template <class... Tr>
282 GPUd() int process(const Tr&... args);
283 GPUd() void print() const;
284
285 GPUdi() int getFitterID() const { return mFitterID; }
286 GPUdi() void setFitterID(int i) { mFitterID = i; }
287 GPUdi() size_t getCallID() const { return mCallID; }
288
289 protected:
290 GPUd() bool calcPCACoefs();
291 GPUd() bool calcInverseWeight();
292 GPUd() void calcResidDerivatives();
293 GPUd() void calcResidDerivativesNoErr();
294 GPUd() void calcRMatrices();
295 GPUd() void calcChi2Derivatives();
296 GPUd() void calcChi2DerivativesNoErr();
297 GPUd() void calcPCA();
298 GPUd() void calcPCANoErr();
299 GPUd() void calcTrackResiduals();
300 GPUd() void calcTrackDerivatives();
301 GPUd() double calcChi2() const;
302 GPUd() double calcChi2NoErr() const;
303 GPUd() bool correctTracks(const VecND& corrX);
304 GPUd() bool minimizeChi2();
305 GPUd() bool minimizeChi2NoErr();
306 GPUd() bool roughDZCut() const;
307 GPUd() bool closerToAlternative() const;
308 GPUd() bool propagateToX(o2::track::TrackParCov& t, float x);
309 GPUd() bool propagateParamToX(o2::track::TrackPar& t, float x);
310
311 GPUd() static double getAbsMax(const VecND& v);
313 GPUdi() const Vec3D& getTrackPos(int i, int cand = 0) const { return mTrPos[mOrder[cand]][i]; }
314
316 GPUd() float getTrackX(int i, int cand = 0) const { return getTrackPos(i, cand)[0]; }
317
318 GPUd() MatStd3D getTrackRotMatrix(int i) const // generate 3D matrix for track rotation to global frame
319 {
320 MatStd3D mat;
321 mat(2, 2) = 1;
322 mat(0, 0) = mat(1, 1) = mTrAux[i].c;
323 mat(0, 1) = -mTrAux[i].s;
324 mat(1, 0) = mTrAux[i].s;
325 return mat;
326 }
327
328 GPUd() void assign(int) {}
329 template <class T, class... Tr>
330 GPUd() void assign(int i, const T& t, const Tr&... args)
331 {
332#ifndef GPUCA_GPUCODE_DEVICE
333 static_assert(std::is_convertible<T, Track>(), "Wrong track type");
334#endif
336 assign(i + 1, args...);
337 }
338
340 {
341 mCurHyp = 0;
342 mAllowAltPreference = true;
343 mOrder.fill(0);
344 mPropFailed.fill(false);
345 mTrPropDone.fill(false);
346 mNIters.fill(0);
347 mChi2.fill(-1);
348 mFitStatus.fill(FitStatus::None);
349 }
350
351 GPUdi() static void setTrackPos(Vec3D& pnt, const Track& tr)
352 {
353 pnt[0] = tr.getX();
354 pnt[1] = tr.getY();
355 pnt[2] = tr.getZ();
356 }
357
358 GPUdi() void clearLogThrottlers()
359 {
360 mLoggerBadCov.clear();
361 mLoggerBadInv.clear();
362 mLoggerBadProp.clear();
363 }
364
365 void setBadCovPolicy(BadCovPolicy v) { mBadCovPolicy = v; }
366 BadCovPolicy getBadCovPolicy() const { return mBadCovPolicy; }
367
368 private:
369 // vectors of 1st derivatives of track local residuals over X parameters
370 std::array<std::array<Vec3D, N>, N> mDResidDx;
371 // vectors of 1nd derivatives of track local residuals over X parameters
372 // (cross-derivatives DR/(dx_j*dx_k) = 0 for j!=k, therefore the hessian is diagonal)
373 std::array<std::array<Vec3D, N>, N> mD2ResidDx2;
374 VecND mDChi2Dx; // 1st derivatives of chi2 over tracks X params
375 MatSymND mD2Chi2Dx2; // 2nd derivatives of chi2 over tracks X params (symmetric matrix)
376 MatSymND mCosDif; // matrix with cos(alp_j-alp_i) for j<i
377 MatSymND mSinDif; // matrix with sin(alp_j-alp_i) for j<i
378 std::array<const Track*, N> mOrigTrPtr;
379 std::array<TrackAuxPar, N> mTrAux; // Aux track info for each track at each cand. vertex
380 CrossInfo mCrossings; // info on track crossing
381
382 std::array<ArrTrackCovI, MAXHYP> mTrcEInv; // errors for each track at each cand. vertex
383 std::array<ArrTrack, MAXHYP> mCandTr; // tracks at each cond. vertex (Note: Errors are at seed XY point)
384 std::array<ArrTrCoef, MAXHYP> mTrCFVT; // TrackCoefVtx for each track at each cand. vertex
385 std::array<ArrTrDer, MAXHYP> mTrDer; // Track derivativse
386 std::array<ArrTrPos, MAXHYP> mTrPos; // Track positions
387 std::array<ArrTrPos, MAXHYP> mTrRes; // Track residuals
388 std::array<Vec3D, MAXHYP> mPCA; // PCA for each vertex candidate
389 std::array<float, MAXHYP> mChi2 = {0}; // Chi2 at PCA candidate
390 std::array<int, MAXHYP> mNIters; // number of iterations for each seed
391 std::array<bool, MAXHYP> mTrPropDone{}; // Flag that the tracks are fully propagated to PCA
392 std::array<bool, MAXHYP> mPropFailed{}; // Flag that some propagation failed for this PCA candidate
393 mutable LogLogThrottler mLoggerBadCov{};
394 mutable LogLogThrottler mLoggerBadInv{};
395 mutable LogLogThrottler mLoggerBadProp{};
396 mutable LogLogThrottler mLoggerBadPCACov{};
397 MatSym3D mWeightInv; // inverse weight of single track, [sum{M^T E M}]^-1 in EQ.T
398 std::array<int, MAXHYP> mOrder{0};
399 int mCurHyp = 0;
400 int mCrossIDCur = 0;
401 int mCrossIDAlt = -1;
402 BadCovPolicy mBadCovPolicy{BadCovPolicy::Discard}; // what to do in case of non-pos-def. cov. matrix, see BadCovPolicy enum
403 std::array<FitStatus, MAXHYP> mFitStatus{}; // fit status of each hypothesis fit
404 bool mAllowAltPreference = true; // if the fit converges to alternative PCA seed, abandon the current one
405 bool mUseAbsDCA = false; // use abs. distance minimization rather than chi2
406 bool mWeightedFinalPCA = false; // recalculate PCA as a cov-matrix weighted mean, even if absDCA method was used
407 bool mPropagateToPCA = true; // create tracks version propagated to PCA
408 bool mUsePropagator = false; // use propagator with 3D B-field, set automatically if material correction is requested
409 bool mRefitWithMatCorr = false; // when doing propagateTracksToVertex, propagate tracks to V0 with material corrections and rerun minimization again
410 bool mIsCollinear = false; // use collinear fits when there 2 crossing points
411 o2::base::Propagator::MatCorrType mMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; // material corrections type
412 int mMaxIter = 20; // max number of iterations
413 float mBz = 0; // bz field, to be set by user
414 float mMaxR2 = 200. * 200.; // reject PCA's above this radius
415 float mMinXSeed = -50.; // reject seed if it corresponds to X-param < mMinXSeed for one of candidates (e.g. X becomes strongly negative)
416 float mMaxDZIni = 4.; // reject (if>0) PCA candidate if tracks DZ exceeds threshold
417 float mMaxDXYIni = 4.; // reject (if>0) PCA candidate if tracks dXY exceeds threshold
418 float mMinParamChange = 1e-3; // stop iterations if largest change of any X is smaller than this
419 float mMinRelChi2Change = 0.9; // stop iterations is chi2/chi2old > this
420 float mMaxChi2 = 100; // abs cut on chi2 or abs distance
421 float mMaxDist2ToMergeSeeds = 1.; // merge 2 seeds to their average if their distance^2 is below the threshold
422 float mMaxSnp = 0.95; // Max snp for propagation with Propagator
423 float mMaxStep = 2.0; // Max step for propagation with Propagator
424 int mFitterID = 0; // locat fitter ID (mostly for debugging)
425 size_t mCallID = 0;
426 ClassDefNV(DCAFitterN, 3);
427};
428
430template <int N, typename... Args>
431template <class... Tr>
432GPUd() int DCAFitterN<N, Args...>::process(const Tr&... args)
433{
434 // This is a main entry point: fit PCA of N tracks
435 mCallID++;
436 static_assert(sizeof...(args) == N, "incorrect number of input tracks");
437 assign(0, args...);
438 clear();
439 for (int i = 0; i < N; i++) {
440 mTrAux[i].set(*mOrigTrPtr[i], mBz);
441 }
442 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
443 mFitStatus[mCurHyp] = FitStatus::NoCrossing;
444 return 0;
445 }
446 if (mUseAbsDCA) {
447 calcRMatrices(); // needed for fast residuals derivatives calculation in case of abs. distance minimization
448 }
449 if (mCrossings.nDCA == MAXHYP) { // if there are 2 candidates and they are too close, chose their mean as a starting point
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) {
453 mCrossings.nDCA = 1;
454 mCrossings.xDCA[0] = 0.5 * (mCrossings.xDCA[0] + mCrossings.xDCA[1]);
455 mCrossings.yDCA[0] = 0.5 * (mCrossings.yDCA[0] + mCrossings.yDCA[1]);
456 }
457 }
458 // check all crossings
459 for (int ic = 0; ic < mCrossings.nDCA; ic++) {
460 // check if radius is acceptable
461 if (mCrossings.xDCA[ic] * mCrossings.xDCA[ic] + mCrossings.yDCA[ic] * mCrossings.yDCA[ic] > mMaxR2) {
462 mFitStatus[mCurHyp] = FitStatus::RejRadius;
463 continue;
464 }
465 mCrossIDCur = ic;
466 mCrossIDAlt = (mCrossings.nDCA == 2 && mAllowAltPreference) ? 1 - ic : -1; // works for max 2 crossings
467 mPCA[mCurHyp][0] = mCrossings.xDCA[ic];
468 mPCA[mCurHyp][1] = mCrossings.yDCA[ic];
469
470 if (mUseAbsDCA ? minimizeChi2NoErr() : minimizeChi2()) {
471 mOrder[mCurHyp] = mCurHyp;
472 if (mPropagateToPCA && !propagateTracksToVertex(mCurHyp)) {
473 continue; // discard candidate if failed to propagate to it
474 }
475 mCurHyp++;
476 }
477 }
478
479 for (int i = mCurHyp; i--;) { // order in quality
480 for (int j = i; j--;) {
481 if (mChi2[mOrder[i]] < mChi2[mOrder[j]]) {
482 o2::gpu::GPUCommonMath::Swap(mOrder[i], mOrder[j]);
483 }
484 }
485 }
486 if (mUseAbsDCA && mWeightedFinalPCA) {
487 for (int i = mCurHyp; i--;) {
488 recalculatePCAWithErrors(i);
489 }
490 }
491 return mCurHyp;
492}
493
494//__________________________________________________________________________
495template <int N, typename... Args>
496GPUd() bool DCAFitterN<N, Args...>::calcPCACoefs()
497{
498 //< calculate Ti matrices for global vertex decomposition to V = sum_{0<i<N} Ti pi, see EQ.T in the ref
499 if (!calcInverseWeight()) {
500 mFitStatus[mCurHyp] = FitStatus::FailInvWeight;
501 return false;
502 }
503 for (int i = N; i--;) { // build Mi*Ei matrix
504 const auto& taux = mTrAux[i];
505 const auto& tcov = mTrcEInv[mCurHyp][i];
506 MatStd3D miei;
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;
517 }
518 return true;
519}
520
521//__________________________________________________________________________
522template <int N, typename... Args>
523GPUd() bool DCAFitterN<N, Args...>::calcInverseWeight()
524{
525 //< calculate [sum_{0<j<N} M_j*E_j*M_j^T]^-1 used for Ti matrices, see EQ.T
526 auto* arrmat = mWeightInv.Array();
527 memset(arrmat, 0, sizeof(mWeightInv));
528 enum { XX,
529 XY,
530 YY,
531 XZ,
532 YZ,
533 ZZ };
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;
543 }
544 // invert 3x3 symmetrix matrix
545 return mWeightInv.Invert();
546}
547
548//__________________________________________________________________________
549template <int N, typename... Args>
550GPUd() void DCAFitterN<N, Args...>::calcResidDerivatives()
551{
552 //< calculate matrix of derivatives for weighted chi2: residual i vs parameter X of track j
553 MatStd3D matMT;
554 for (int i = N; i--;) { // residual being differentiated
555 const auto& taux = mTrAux[i];
556 for (int j = N; j--;) { // track over which we differentiate
557 const auto& matT = mTrCFVT[mCurHyp][j]; // coefficient matrix for track J
558 const auto& trDx = mTrDer[mCurHyp][j]; // track point derivs over track X param
559 auto& dr1 = mDResidDx[i][j];
560 auto& dr2 = mD2ResidDx2[i][j];
561 // calculate M_i^tr * T_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];
571
572 // calculate DResid_i/Dx_j = (delta_ij - M_i^tr * T_j) * DTrack_k/Dx_k
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);
576
577 // calculate D2Resid_I/(Dx_J Dx_K) = (delta_ijk - M_i^tr * T_j * delta_jk) * D2Track_k/dx_k^2
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);
581
582 if (i == j) {
583 dr1[0] += 1.;
584 dr1[1] += trDx.dydx;
585 dr1[2] += trDx.dzdx;
586
587 dr2[1] += trDx.d2ydx2;
588 dr2[2] += trDx.d2zdx2;
589 }
590 } // track over which we differentiate
591 } // residual being differentiated
592}
593
594//__________________________________________________________________________
595template <int N, typename... Args>
596GPUd() void DCAFitterN<N, Args...>::calcResidDerivativesNoErr()
597{
598 //< calculate matrix of derivatives for absolute distance chi2: residual i vs parameter X of track j
599 constexpr double NInv1 = 1. - NInv; // profit from Rii = I/Ninv
600 for (int i = N; i--;) { // residual being differentiated
601 const auto& trDxi = mTrDer[mCurHyp][i]; // track point derivs over track X param
602 auto& dr1ii = mDResidDx[i][i];
603 auto& dr2ii = mD2ResidDx2[i][i];
604 dr1ii[0] = NInv1;
605 dr1ii[1] = NInv1 * trDxi.dydx;
606 dr1ii[2] = NInv1 * trDxi.dzdx;
607
608 dr2ii[0] = 0;
609 dr2ii[1] = NInv1 * trDxi.d2ydx2;
610 dr2ii[2] = NInv1 * trDxi.d2zdx2;
611
612 for (int j = i; j--;) { // track over which we differentiate
613 auto& dr1ij = mDResidDx[i][j];
614 auto& dr1ji = mDResidDx[j][i];
615 const auto& trDxj = mTrDer[mCurHyp][j]; // track point derivs over track X param
616 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.
617
618 // calculate DResid_i/Dx_j = (delta_ij - R_ij) * DTrack_j/Dx_j for j<i
619 dr1ij[0] = -(cij + sij * trDxj.dydx);
620 dr1ij[1] = -(-sij + cij * trDxj.dydx);
621 dr1ij[2] = -trDxj.dzdx * NInv;
622
623 // calculate DResid_j/Dx_i = (delta_ij - R_ji) * DTrack_i/Dx_i for j<i
624 dr1ji[0] = -(cij - sij * trDxi.dydx);
625 dr1ji[1] = -(sij + cij * trDxi.dydx);
626 dr1ji[2] = -trDxi.dzdx * NInv;
627
628 auto& dr2ij = mD2ResidDx2[i][j];
629 auto& dr2ji = mD2ResidDx2[j][i];
630 // calculate D2Resid_I/(Dx_J Dx_K) = (delta_ij - Rij) * D2Track_j/dx_j^2 * delta_jk for j<i
631 dr2ij[0] = -sij * trDxj.d2ydx2;
632 dr2ij[1] = -cij * trDxj.d2ydx2;
633 dr2ij[2] = -trDxj.d2zdx2 * NInv;
634
635 // calculate D2Resid_j/(Dx_i Dx_k) = (delta_ij - Rji) * D2Track_i/dx_i^2 * delta_ik for j<i
636 dr2ji[0] = sij * trDxi.d2ydx2;
637 dr2ji[1] = -cij * trDxi.d2ydx2;
638 dr2ji[2] = -trDxi.d2zdx2 * NInv;
639
640 } // track over which we differentiate
641 } // residual being differentiated
642}
643
644//__________________________________________________________________________
645template <int N, typename... Args>
646GPUd() void DCAFitterN<N, Args...>::calcRMatrices()
647{
648 //< calculate Rij = 1/N M_i^T * M_j matrices (rotation from j-th track to i-th track frame)
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; // cos(alp_i-alp_j) / N
654 mSinDif[i][j] = (mi.s * mj.c - mi.c * mj.s) * NInv; // sin(alp_i-alp_j) / N
655 }
656 }
657}
658
659//__________________________________________________________________________
660template <int N, typename... Args>
661GPUd() void DCAFitterN<N, Args...>::calcChi2Derivatives()
662{
663 //< calculate 1st and 2nd derivatives of wighted DCA (chi2) over track parameters X, see EQ.Chi2 in the ref
664 std::array<std::array<Vec3D, N>, N> covIDrDx; // tempory vectors of covI_j * dres_j/dx_i
665
666 // chi2 1st derivative
667 for (int i = N; i--;) {
668 auto& dchi1 = mDChi2Dx[i]; // DChi2/Dx_i = sum_j { res_j * covI_j * Dres_j/Dx_i }
669 dchi1 = 0;
670 for (int j = N; j--;) {
671 const auto& res = mTrRes[mCurHyp][j]; // vector of residuals of track j
672 const auto& covI = mTrcEInv[mCurHyp][j]; // inverse cov matrix of track j
673 const auto& dr1 = mDResidDx[j][i]; // vector of j-th residuals 1st derivative over X param of track i
674 auto& cidr = covIDrDx[i][j]; // vector covI_j * dres_j/dx_i, save for 2nd derivative calculation
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];
678 // calculate res_i * covI_j * dres_j/dx_i
679 dchi1 += o2::math_utils::Dot(res, cidr);
680 }
681 }
682 // chi2 2nd derivative
683 for (int i = N; i--;) {
684 for (int j = i + 1; j--;) { // symmetric matrix
685 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 }
686 dchi2 = 0;
687 for (int k = N; k--;) {
688 const auto& dr1j = mDResidDx[k][j]; // vector of k-th residuals 1st derivative over X param of track j
689 const auto& cidrkj = covIDrDx[i][k]; // vector covI_k * dres_k/dx_i
690 dchi2 += o2::math_utils::Dot(dr1j, cidrkj);
691 if (i == j) {
692 const auto& res = mTrRes[mCurHyp][k]; // vector of residuals of track k
693 const auto& covI = mTrcEInv[mCurHyp][k]; // inverse cov matrix of track k
694 const auto& dr2ij = mD2ResidDx2[k][i]; // vector of k-th residuals 2nd derivative over X param 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]);
698 }
699 }
700 }
701 }
702}
703
704//__________________________________________________________________________
705template <int N, typename... Args>
706GPUd() void DCAFitterN<N, Args...>::calcChi2DerivativesNoErr()
707{
708 //< calculate 1st and 2nd derivatives of abs DCA (chi2) over track parameters X, see (6) in the ref
709 for (int i = N; i--;) {
710 auto& dchi1 = mDChi2Dx[i]; // DChi2/Dx_i = sum_j { res_j * Dres_j/Dx_i }
711 dchi1 = 0; // chi2 1st derivative
712 for (int k = N; k--;) {
713 const auto& res = mTrRes[mCurHyp][k]; // vector of residuals of track k
714 const auto& dr1 = mDResidDx[k][i]; // vector of k-th residuals 1st derivative over X param of track i
715 dchi1 += o2::math_utils::Dot(res, dr1);
716 }
717 }
718 for (int i = N; i--;) {
719 for (int j = i + 1; j--;) {
720 auto& dchi2 = mD2Chi2Dx2[i][j];
721 dchi2 = 0.;
722 for (int k = N; k--;) {
723 // Gauss-Newton term, present for diagonal and mixed elements.
724 dchi2 += o2::math_utils::Dot(mDResidDx[k][i], mDResidDx[k][j]);
725 // A trajectory has a second derivative only with respect to its own
726 // X parameter, hence the curvature term contributes only to H_ii.
727 if (i == j) {
728 dchi2 += o2::math_utils::Dot(mTrRes[mCurHyp][k], mD2ResidDx2[k][i]);
729 }
730 }
731 }
732 }
733}
734
735//___________________________________________________________________
736template <int N, typename... Args>
737GPUd() void DCAFitterN<N, Args...>::calcPCA()
738{
739 // calculate point of closest approach for N prongs
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];
743 }
744}
745
746//___________________________________________________________________
747template <int N, typename... Args>
748GPUd() bool DCAFitterN<N, Args...>::recalculatePCAWithErrors(int cand)
749{
750 // recalculate PCA as a cov-matrix weighted mean, even if absDCA method was used
751 if (isPropagateTracksToVertexDone(cand) && !propagateTracksToVertex(cand)) {
752 return false;
753 }
754 int saveCurHyp = mCurHyp;
755 mCurHyp = mOrder[cand];
756 if (mUseAbsDCA) {
757 for (int i = N; i--;) {
758 if (!mTrcEInv[mCurHyp][i].set(mCandTr[mCurHyp][i])) { // prepare inverse cov.matrices at starting point
759 if (mLoggerBadCov.needToLog()) {
760#ifndef GPUCA_GPUCODE
761 printf("fitter %d: error (%ld muted): overrode invalid track covariance from %s\n",
762 mFitterID, mLoggerBadCov.evCount, mCandTr[mCurHyp][i].asString().c_str());
763#else
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());
766#endif
767 }
768 mFitStatus[mCurHyp] = FitStatus::FailInvCov;
769 if (mBadCovPolicy == Discard) {
770 return false;
771 } else if (mBadCovPolicy == OverrideAndFlag) {
772 mPropFailed[mCurHyp] = true;
773 } // otherwise, just use overridden errors w/o flagging
774 }
775 }
776 if (!calcPCACoefs()) {
777 mCurHyp = saveCurHyp;
778 return false;
779 }
780 }
781 auto oldPCA = mPCA[mOrder[cand]];
782 calcPCA();
783 mCurHyp = saveCurHyp;
784 return true;
785}
786
787//___________________________________________________________________
788template <int N, typename... Args>
789GPUd() void DCAFitterN<N, Args...>::calcPCANoErr()
790{
791 // calculate point of closest approach for N prongs w/o errors
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);
794 // RRRR mTrAux[N-1].loc2glo(mTrPos[mCurHyp][N-1][0], mTrPos[mCurHyp][N-1][1], pca[0], pca[1] );
795 pca[2] = mTrPos[mCurHyp][N - 1][2];
796 for (int i = N - 1; i--;) {
797 double x, y;
798 o2::math_utils::rotateZd(mTrPos[mCurHyp][i][0], mTrPos[mCurHyp][i][1], x, y, mTrAux[i].s, mTrAux[i].c);
799 // RRRR mTrAux[i].loc2glo(mTrPos[mCurHyp][i][0], mTrPos[mCurHyp][i][1], x, y );
800 pca[0] += x;
801 pca[1] += y;
802 pca[2] += mTrPos[mCurHyp][i][2];
803 }
804 pca[0] *= NInv;
805 pca[1] *= NInv;
806 pca[2] *= NInv;
807}
808
809//___________________________________________________________________
810template <int N, typename... Args>
811GPUd() double DCAFitterN<N, Args...>::calcCollinearInflation(int cand) const
812{
813 std::array<std::array<double, 3>, N> u{};
814 int nu = 0;
815
816 for (int i = 0; i < N; ++i) {
817 std::array<float, 3> p{};
818 if (!getTrack(i, cand).getPxPyPzGlo(p)) {
819 continue;
820 }
821 const double p2 = p[0] * p[0] + p[1] * p[1] + p[2] * p[2];
822 if (p2 <= 0.) {
823 continue;
824 }
825 const double pI = 1. / std::sqrt(p2);
826 u[nu++] = {p[0] * pI, p[1] * pI, p[2] * pI};
827 }
828
829 if (nu < 2) {
830 return 1.;
831 }
832
833 double sin2Mean = 0.;
834 int npairs = 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);
840 ++npairs;
841 }
842 }
843 sin2Mean /= npairs;
844
845 constexpr double Sin2Ref = 1.e-5;
846 constexpr double MaxInflation = 1.e4;
847 if (sin2Mean <= 0.) {
848 return MaxInflation;
849 }
850 return sin2Mean < Sin2Ref ? std::min(MaxInflation, Sin2Ref / sin2Mean) : 1.;
851}
852
853//___________________________________________________________________
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
856{
857 // Each track measures Y and Z at the vertex X. With the local slopes
858 // sy = dY/dX and sz = dZ/dX, its vertex measurement matrix is
859 // H = {{-sy, 1, 0}, {-sz, 0, 1}}. The longitudinal information must come
860 // from the track geometry, not from a dummy X variance.
861 MatSym3D info;
862 auto* arrmat = info.Array();
863 memset(arrmat, 0, sizeof(info));
864 enum { XX,
865 XY,
866 YY,
867 XZ,
868 YZ,
869 ZZ };
870 const int ord = mOrder[cand];
871 for (int i = N; i--;) {
872 const auto& taux = mTrAux[i];
873 TrackCovI tcov;
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;
881 }
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) {
892 auto cov = info;
893 if (cov.Invert() && cov(0, 0) > 0. && cov(1, 1) > 0. && cov(2, 2) > 0.) {
894 // if (mIsCollinear) {
895 // cov *= calcCollinearInflation(cand);
896 // }
897 return cov;
898 }
899 }
900 if (mLoggerBadPCACov.needToLog()) {
901 printf("fitter %d: error (%ld muted): override ill-conditioned PCACovMatrix by dummy matrix", mFitterID, mLoggerBadPCACov.evCount);
902 }
903 // Fall back on a deliberately loose vertex covariance. Returning a tight
904 // identity covariance for a singular or ill-conditioned information matrix
905 // would shrink the uncertainty in the weakly constrained direction.
906 memset(arrmat, 0, sizeof(info));
907 info(0, 0) = 4.;
908 info(1, 1) = 4.;
909 info(2, 2) = 4.;
910 return info;
911}
912
913//___________________________________________________________________
914template <int N, typename... Args>
915GPUd() void DCAFitterN<N, Args...>::calcTrackResiduals()
916{
917 // calculate residuals
918 Vec3D vtxLoc;
919 for (int i = N; i--;) {
920 mTrRes[mCurHyp][i] = mTrPos[mCurHyp][i];
921 vtxLoc = mPCA[mCurHyp];
922 o2::math_utils::rotateZInvd(vtxLoc[0], vtxLoc[1], vtxLoc[0], vtxLoc[1], mTrAux[i].s, mTrAux[i].c); // glo->loc
923 mTrRes[mCurHyp][i] -= vtxLoc;
924 }
925}
926
927//___________________________________________________________________
928template <int N, typename... Args>
929GPUdi() void DCAFitterN<N, Args...>::calcTrackDerivatives()
930{
931 // calculate track derivatives over X param
932 for (int i = N; i--;) {
933 mTrDer[mCurHyp][i].set(mCandTr[mCurHyp][i], mBz);
934 }
935}
936
937//___________________________________________________________________
938template <int N, typename... Args>
939GPUdi() double DCAFitterN<N, Args...>::calcChi2() const
940{
941 // calculate current chi2
942 double chi2 = 0;
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);
948 }
949 return chi2;
950}
951
952//___________________________________________________________________
953template <int N, typename... Args>
954GPUdi() double DCAFitterN<N, Args...>::calcChi2NoErr() const
955{
956 // calculate current chi2 of abs. distance minimization
957 double chi2 = 0;
958 for (int i = N; i--;) {
959 const auto& res = mTrRes[mCurHyp][i];
960 chi2 += res[0] * res[0] + res[1] * res[1] + res[2] * res[2];
961 }
962 return chi2;
963}
964
965//___________________________________________________________________
966template <int N, typename... Args>
967GPUd() bool DCAFitterN<N, Args...>::correctTracks(const VecND& corrX)
968{
969 // Propagate the actual candidate tracks to the updated X. Use the analytic
970 // constant-Bz transport here: Newton corrections are small, but the track
971 // state must stay synchronized with mTrPos for the next derivative update.
972 for (int i = N; i--;) {
973 /*
974 // Updating only mTrPos by Taylor expansion leaves mCandTr at the previous X,
975 // leaving calcTrackDerivatives() insensitive to the update. Use full fast propagation instead.
976 const auto& trDer = mTrDer[mCurHyp][i];
977 auto dx2h = 0.5 * corrX[i] * corrX[i];
978 mTrPos[mCurHyp][i][0] -= corrX[i];
979 mTrPos[mCurHyp][i][1] -= trDer.dydx * corrX[i] - dx2h * trDer.d2ydx2;
980 mTrPos[mCurHyp][i][2] -= trDer.dzdx * corrX[i] - dx2h * trDer.d2zdx2;
981 */
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);
985 if (!propagated) {
986 return false;
987 }
988 setTrackPos(mTrPos[mCurHyp][i], trc);
989 }
990 return true;
991}
992
993//___________________________________________________________________
994template <int N, typename... Args>
995GPUd() bool DCAFitterN<N, Args...>::propagateTracksToVertex(int icand)
996{
997 // propagate tracks to current vertex
998 int ord = mOrder[icand];
999 if (mTrPropDone[ord]) {
1000 return true;
1001 }
1002
1003 // need to refit taking as a seed already found vertex
1004 if (mRefitWithMatCorr) {
1005 int curHypSav = mCurHyp, curCrosIDAlt = mCrossIDAlt; // save
1006 mCurHyp = ord;
1007 mCrossIDAlt = -1; // disable alternative check
1008 auto restore = [this, curHypSav, curCrosIDAlt]() { this->mCurHyp = curHypSav; this->mCrossIDAlt = curCrosIDAlt; };
1009 if (!(mUseAbsDCA ? minimizeChi2NoErr() : minimizeChi2())) { // do final propagation
1010 restore();
1011 return false;
1012 }
1013 restore();
1014 }
1015
1016 for (int i = N; i--;) {
1017 if (mUseAbsDCA || mUsePropagator || mMatCorr != o2::base::Propagator::MatCorrType::USEMatCorrNONE) {
1018 mCandTr[ord][i] = *mOrigTrPtr[i]; // fetch the track again, as mCandTr might have been propagated w/o errors or material corrections might be wrong
1019 }
1020 auto x = mTrAux[i].c * mPCA[ord][0] + mTrAux[i].s * mPCA[ord][1]; // X of PCA in the track frame
1021 if (!propagateToX(mCandTr[ord][i], x)) {
1022 return false;
1023 }
1024 }
1025
1026 mTrPropDone[ord] = true;
1027 return true;
1028}
1029
1030//___________________________________________________________________
1031template <int N, typename... Args>
1032GPUdi() o2::track::TrackPar DCAFitterN<N, Args...>::getTrackParamAtPCA(int i, int icand)
1033{
1034 // propagate tracks param only to current vertex (if not already done)
1035 int ord = mOrder[icand];
1036 o2::track::TrackPar trc(mCandTr[ord][i]);
1037 if (!mTrPropDone[ord]) {
1038 auto x = mTrAux[i].c * mPCA[ord][0] + mTrAux[i].s * mPCA[ord][1]; // X of PCA in the track frame
1039 if (!propagateParamToX(trc, x)) {
1040 trc.invalidate();
1041 }
1042 }
1043 return trc;
1044}
1045
1046//___________________________________________________________________
1047template <int N, typename... Args>
1048GPUdi() double DCAFitterN<N, Args...>::getAbsMax(const VecND& v)
1049{
1050 double mx = -1;
1051 for (int i = N; i--;) {
1052 auto vai = o2::gpu::GPUCommonMath::Abs(v[i]);
1053 if (mx < vai) {
1054 mx = vai;
1055 }
1056 }
1057 return mx;
1058}
1059
1060//___________________________________________________________________
1061template <int N, typename... Args>
1062GPUd() bool DCAFitterN<N, Args...>::minimizeChi2()
1063{
1064 // find best chi2 (weighted DCA) of N tracks in the vicinity of the seed PCA
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]; // X of PCA in the track frame
1068 if (x < mMinXSeed) {
1069 mFitStatus[mCurHyp] = FitStatus::RejTrackX;
1070 return false;
1071 }
1072 if (!propagateToX(mCandTr[mCurHyp][i], x)) {
1073 return false;
1074 }
1075 setTrackPos(mTrPos[mCurHyp][i], mCandTr[mCurHyp][i]); // prepare positions
1076 if (!mTrcEInv[mCurHyp][i].set(mCandTr[mCurHyp][i])) { // prepare inverse cov.matrices at starting point
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());
1081#else
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());
1084#endif
1085 }
1086 mFitStatus[mCurHyp] = FitStatus::FailInvCov;
1087 if (mBadCovPolicy == Discard) {
1088 return false;
1089 } else if (mBadCovPolicy == OverrideAndFlag) {
1090 mPropFailed[mCurHyp] = true;
1091 } // otherwise, just use overridden errors w/o flagging
1092 }
1093 }
1094
1095 if (mMaxDZIni > 0 && !roughDZCut()) { // apply rough cut on tracks Z difference
1096 mFitStatus[mCurHyp] = FitStatus::RejTrackRoughZ;
1097 return false;
1098 }
1099
1100 if (!calcPCACoefs()) { // prepare tracks contribution matrices to the global PCA
1101 return false;
1102 }
1103 calcPCA(); // current PCA
1104 calcTrackResiduals(); // current track residuals
1105 float chi2Upd, chi2 = calcChi2();
1106 do {
1107 calcTrackDerivatives(); // current track derivatives (1st and 2nd)
1108 calcResidDerivatives(); // current residals derivatives (1st and 2nd)
1109 calcChi2Derivatives(); // current chi2 derivatives (1st and 2nd)
1110
1111 // do Newton-Rapson iteration with corrections = - dchi2/d{x0..xN} * [ d^2chi2/d{x0..xN}^2 ]^-1
1112 if (!mD2Chi2Dx2.Invert()) {
1113 if (mLoggerBadInv.needToLog()) {
1114 printf("fitter %d: error (%ld muted): Inversion failed\n", mFitterID, mLoggerBadCov.evCount);
1115 }
1116 mFitStatus[mCurHyp] = FitStatus::FailInv2ndDeriv;
1117 return false;
1118 }
1119 VecND dx = mD2Chi2Dx2 * mDChi2Dx;
1120 if (!correctTracks(dx)) {
1121 mFitStatus[mCurHyp] = FitStatus::FailCorrTracks;
1122 return false;
1123 }
1124 calcPCA(); // updated PCA
1125 if (mCrossIDAlt >= 0 && closerToAlternative()) {
1126 mFitStatus[mCurHyp] = FitStatus::FailCloserAlt;
1127 mAllowAltPreference = false;
1128 return false;
1129 }
1130 calcTrackResiduals(); // updated residuals
1131 chi2Upd = calcChi2(); // updated chi2
1132 if (getAbsMax(dx) < mMinParamChange || chi2Upd > chi2 * mMinRelChi2Change) {
1133 chi2 = chi2Upd;
1134 mFitStatus[mCurHyp] = FitStatus::Converged;
1135 break; // converged
1136 }
1137 chi2 = chi2Upd;
1138 } while (++mNIters[mCurHyp] < mMaxIter);
1139 if (mNIters[mCurHyp] == mMaxIter) {
1140 mFitStatus[mCurHyp] = FitStatus::MaxIter;
1141 }
1142 //
1143 mChi2[mCurHyp] = chi2 * NInv;
1144 if (mChi2[mCurHyp] >= mMaxChi2) {
1145 mFitStatus[mCurHyp] = FitStatus::RejChi2Max;
1146 return false;
1147 }
1148 return true;
1149}
1150
1151//___________________________________________________________________
1152template <int N, typename... Args>
1153GPUd() bool DCAFitterN<N, Args...>::minimizeChi2NoErr()
1154{
1155 // find best chi2 (absolute DCA) of N tracks in the vicinity of the PCA seed
1156
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]; // X of PCA in the track frame
1160 if (x < mMinXSeed) {
1161 mFitStatus[mCurHyp] = FitStatus::RejTrackX;
1162 return false;
1163 }
1164 if (!propagateParamToX(mCandTr[mCurHyp][i], x)) {
1165 return false;
1166 }
1167 setTrackPos(mTrPos[mCurHyp][i], mCandTr[mCurHyp][i]); // prepare positions
1168 }
1169 if (mMaxDZIni > 0 && !roughDZCut()) { // apply rough cut on tracks Z difference
1170 mFitStatus[mCurHyp] = FitStatus::RejTrackRoughZ;
1171 return false;
1172 }
1173
1174 calcPCANoErr(); // current PCA
1175 calcTrackResiduals(); // current track residuals
1176 float chi2Upd, chi2 = calcChi2NoErr();
1177 do {
1178 calcTrackDerivatives(); // current track derivatives (1st and 2nd)
1179 calcResidDerivativesNoErr(); // current residals derivatives (1st and 2nd)
1180 calcChi2DerivativesNoErr(); // current chi2 derivatives (1st and 2nd)
1181
1182 // do Newton-Rapson iteration with corrections = - dchi2/d{x0..xN} * [ d^2chi2/d{x0..xN}^2 ]^-1
1183 if (!mD2Chi2Dx2.Invert()) {
1184 if (mLoggerBadInv.needToLog()) {
1185 printf("fitter %d: error (%ld muted): Inversion failed\n", mFitterID, mLoggerBadCov.evCount);
1186 }
1187 mFitStatus[mCurHyp] = FitStatus::FailInv2ndDeriv;
1188 return false;
1189 }
1190 VecND dx = mD2Chi2Dx2 * mDChi2Dx;
1191 if (!correctTracks(dx)) {
1192 mFitStatus[mCurHyp] = FitStatus::FailCorrTracks;
1193 return false;
1194 }
1195 calcPCANoErr(); // updated PCA
1196 if (mCrossIDAlt >= 0 && closerToAlternative()) {
1197 mFitStatus[mCurHyp] = FitStatus::FailCloserAlt;
1198 mAllowAltPreference = false;
1199 return false;
1200 }
1201 calcTrackResiduals(); // updated residuals
1202 chi2Upd = calcChi2NoErr(); // updated chi2
1203 if (getAbsMax(dx) < mMinParamChange || chi2Upd > chi2 * mMinRelChi2Change) {
1204 chi2 = chi2Upd;
1205 mFitStatus[mCurHyp] = FitStatus::Converged;
1206 break; // converged
1207 }
1208 chi2 = chi2Upd;
1209 } while (++mNIters[mCurHyp] < mMaxIter);
1210 if (mNIters[mCurHyp] == mMaxIter) {
1211 mFitStatus[mCurHyp] = FitStatus::MaxIter;
1212 }
1213 //
1214 mChi2[mCurHyp] = chi2 * NInv;
1215 if (mChi2[mCurHyp] >= mMaxChi2) {
1216 mFitStatus[mCurHyp] = FitStatus::RejChi2Max;
1217 return false;
1218 }
1219 return true;
1220}
1221
1222//___________________________________________________________________
1223template <int N, typename... Args>
1224GPUd() bool DCAFitterN<N, Args...>::roughDZCut() const
1225{
1226 // apply rough cut on DZ between the tracks in the seed point
1227 bool accept = true;
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) {
1231 accept = false;
1232 break;
1233 }
1234 }
1235 }
1236 return accept;
1237}
1238
1239//___________________________________________________________________
1240template <int N, typename... Args>
1241GPUd() bool DCAFitterN<N, Args...>::closerToAlternative() const
1242{
1243 // check if the point current PCA point is closer to the seeding XY point being tested or to alternative see (if any)
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;
1247}
1248
1249//___________________________________________________________________
1250template <int N, typename... Args>
1251GPUd() void DCAFitterN<N, Args...>::print() const
1252{
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;
1259 std::string rep{};
1260 for (int i = 0; i < mCrossings.nDCA; i++) {
1261 rep += fmt::format("seed{}:{}/{} ", i, mTrPropDone[i], mPropFailed[i]);
1262 }
1263 LOG(info) << "Last call: NCand:" << mCurHyp << " from " << mCrossings.nDCA << " seeds, prop.done/failed: " << rep;
1264#else
1265 if (mUseAbsDCA) {
1266 printf("%d-prong vertex fitter in abs. distance minimization mode\n", N);
1267 } else {
1268 printf("%d-prong vertex fitter in weighted distance minimization mode\n", N);
1269 }
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);
1273#endif
1274}
1275
1276//___________________________________________________________________
1277template <int N, typename... Args>
1278GPUd() o2::track::TrackParCov DCAFitterN<N, Args...>::createParentTrackParCov(int cand, bool sectorAlpha) const
1279{
1280 std::array<float, 21> covV = {0.};
1281 std::array<float, 3> pvecV = {0.};
1282 int q = 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);
1287
1288 // Propagate only the native momentum-parameter covariance
1289 // (snp,tgl,q/pt) to the lab momentum covariance. The final constructor
1290 // below rotates the summed lab covariance to the parent alpha frame.
1291 if (hasMomentum) {
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;
1317 }
1318
1319 for (int i = 0; i < 3; i++) {
1320 pvecV[i] += pvecT[i];
1321 }
1322 q += trc.getCharge();
1323 }
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);
1331 return o2::track::TrackParCov(getPCACandidatePos(cand), pvecV, covV, q, sectorAlpha);
1332}
1333
1334//___________________________________________________________________
1335template <int N, typename... Args>
1336GPUd() o2::track::TrackPar DCAFitterN<N, Args...>::createParentTrackPar(int cand, bool sectorAlpha) const
1337{
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.};
1342 int q = 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];
1349 }
1350 q += trc.getCharge();
1351 }
1352 const std::array<float, 3> vertex = {(float)wvtx[0], (float)wvtx[1], (float)wvtx[2]};
1353 return o2::track::TrackPar(vertex, pvecV, q, sectorAlpha);
1354}
1355
1356//___________________________________________________________________
1357template <int N, typename... Args>
1358GPUdi() bool DCAFitterN<N, Args...>::propagateParamToX(o2::track::TrackPar& t, float x)
1359{
1360 bool res = true;
1361 if (mUsePropagator || mMatCorr != o2::base::Propagator::MatCorrType::USEMatCorrNONE) {
1362#ifndef GPUCA_GPUCODE
1363 res = o2::base::Propagator::Instance()->PropagateToXBxByBz(t, x, mMaxSnp, mMaxStep, mMatCorr);
1364#endif
1365 } else {
1366 res = t.propagateParamTo(x, mBz);
1367 }
1368 if (!res) {
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());
1374#else
1375 printf("fitter %d: error (%ld muted): propagation to %.4f failed\n", mFitterID, mLoggerBadProp.evCount, x);
1376#endif
1377 }
1378 }
1379 return res;
1380}
1381
1382//___________________________________________________________________
1383template <int N, typename... Args>
1384GPUdi() bool DCAFitterN<N, Args...>::propagateToX(o2::track::TrackParCov& t, float x)
1385{
1386 bool res = true;
1387 if (mUsePropagator || mMatCorr != o2::base::Propagator::MatCorrType::USEMatCorrNONE) {
1388#ifndef GPUCA_GPUCODE
1389 res = o2::base::Propagator::Instance()->PropagateToXBxByBz(t, x, mMaxSnp, mMaxStep, mMatCorr);
1390#endif
1391 } else {
1392 res = t.propagateTo(x, mBz);
1393 }
1394 if (!res) {
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());
1400#else
1401 printf("fitter %d: error (%ld muted): propagation to %.4f failed\n", mFitterID, mLoggerBadProp.evCount, x);
1402#endif
1403 }
1404 }
1405 return res;
1406}
1407
1410
1411namespace device
1412{
1413template <typename Fitter>
1414void print(const int nBlocks, const int nThreads, Fitter& ft);
1415
1416template <typename Fitter, class... Tr>
1417int process(const int nBlocks, const int nThreads, Fitter&, Tr&... args);
1418
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);
1421} // namespace device
1422
1423} // namespace vertexing
1424} // namespace o2
1425#endif // _ALICEO2_DCA_FITTERN_
std::function< void(void *, const void *)> assign
Base track model for the Barrel, params only, w/o covariance.
uint64_t vertex
Definition RawEventData.h:9
void print() const
int32_t i
Helper classes for helical tracks manipulations.
constexpr int p2()
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:178
const Track & getTrack(int i, int cand=0) const
create parent track param with errors for decay vertex
Definition DCAFitterN.h:205
GPUd() const auto getPCACandidatePos(int cand=0) const
return position of quality-ordered candidate in the internal structures
Definition DCAFitterN.h:171
const Track * getOrigTrackPtr(int i) const
Definition DCAFitterN.h:236
GPUdi() FitStatus getFitStatus(int cand=0) const noexcept
return number of iterations during minimization (no check for its validity)
Definition DCAFitterN.h:238
int class Tr const T & t
Definition DCAFitterN.h:330
void setBadCovPolicy(BadCovPolicy v)
Definition DCAFitterN.h:365
GPUd() bool calcPCACoefs()
GPUdi() size_t getCallID() const
Definition DCAFitterN.h:287
GPUdi() void setFitterID(int i)
Definition DCAFitterN.h:286
int cand
track X-param at V0 candidate (no check for the candidate validity)
Definition DCAFitterN.h:313
GPUdi() int getNIterations(int cand=0) const
Definition DCAFitterN.h:241
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:170
GPUdi() void clearLogThrottlers()
Definition DCAFitterN.h:358
int getCandidatePosition(int cand=0) const
return Chi2 at PCA candidate (no check for its validity)
Definition DCAFitterN.h:178
static constexpr int getNProngs()
Definition DCAFitterN.h:160
bool isPropagationFailure(int cand=0) const
Definition DCAFitterN.h:191
DCAFitterN(float bz, bool useAbsDCA, bool prop2DCA)
Definition DCAFitterN.h:163
GPUdi() void setPropagateToPCA(bool v
Track & getTrack(int i, int cand=0)
Definition DCAFitterN.h:195
std::array< float, 6 > calcPCACovMatrixFlat(int cand=0) const
Definition DCAFitterN.h:230
GPUdi() static void setTrackPos(Vec3D &pnt
float getChi2AtPCACandidate(int cand=0) const
Definition DCAFitterN.h:181
GPUd() bool propagateTracksToVertex(int cand=0)
check if propagation of tracks to candidate vertex was done
BadCovPolicy getBadCovPolicy() const
Definition DCAFitterN.h:366
int class Tr const T const Tr & args
Definition DCAFitterN.h:331
GLdouble n
Definition glcorearb.h:1982
GLfloat GLfloat GLfloat alpha
Definition glcorearb.h:279
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
GLint y
Definition glcorearb.h:270
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLboolean r
Definition glcorearb.h:1233
constexpr float Almost0
const TrackingFrameInfo *const const Cluster *const const float const float bz
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
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
int process(const int nBlocks, const int nThreads, Fitter &, Tr &... args)
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
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
int process(po::variables_map &vm)
GPUdi() bool needToLog()
Definition DCAFitterN.h:91
GPUd() bool set(const o2
Definition DCAFitterN.h:41
GPUdDefault() TrackCovI()=default
GPUd() TrackDeriv(const o2
Definition DCAFitterN.h:75
GPUd() void set(const o2
Definition DCAFitterN.h:76
GPUdDefault() TrackDeriv()=default
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
vec clear()