Project
Loading...
Searching...
No Matches
GPUTPCGMTrackParam.cxx
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
14
15#define GPUCA_CADEBUG 0
16#define DEBUG_SINGLE_TRACK -1
17
18#include "GPUTPCDef.h"
19#include "GPUTPCGMTrackParam.h"
21#include "GPUTPCGMPropagator.h"
22#include "GPUTPCGMBorderTrack.h"
23#include "GPUTPCGMMergedTrack.h"
25#include "GPUTPCGMMerger.h"
26#include "GPUTPCTracker.h"
27#include "GPUdEdx.h"
28#include "GPUParam.h"
29#include "GPUO2DataTypes.h"
30#include "GPUConstantMem.h"
31#include "TPCFastTransform.h"
33#include "GPUTPCConvertImpl.h"
34#include "GPUTPCGMMergerTypes.h"
35#include "GPUParam.inc"
36#include "GPUGetConstexpr.h"
37
38#ifdef GPUCA_CADEBUG_ENABLED
39#include "GPUSettings.h"
41#endif
42
43#ifndef GPUCA_GPUCODE_DEVICE
44#include <cmath>
45#include <cstdlib>
46#endif
47
48using namespace o2::gpu;
49using namespace o2::tpc;
50
51GPUd() bool GPUTPCGMTrackParam::Fit(GPUTPCGMMerger* GPUrestrict() merger, int32_t iTrk, GPUTPCGMMergedTrackHit* GPUrestrict() clusters, int32_t& GPUrestrict() N, int32_t& GPUrestrict() NTolerated, float& GPUrestrict() Alpha, int32_t attempt, float maxSinPhi, GPUTPCGMMergedTrack& GPUrestrict() track)
52{
53 static constexpr float kDeg2Rad = M_PI / 180.f;
54 CADEBUG(static constexpr float kSectAngle = 2 * M_PI / 18.f);
55
56 const GPUParam& GPUrestrict() param = merger->Param();
57
58 GPUdEdx dEdx, dEdxAlt;
61 prop.SetMaterialTPC();
62 prop.SetPolynomialField(&param.polynomialField);
63 prop.SetMaxSinPhi(maxSinPhi);
64 if (param.rec.tpc.mergerInterpolateErrors) {
65 for (int32_t i = 0; i < N; i++) {
66 interpolation.hit[i].errorY = -1;
67 }
68 }
69
70 const int32_t nWays = param.rec.tpc.nWays;
71 const int32_t maxN = N;
72 int32_t ihitStart = 0;
73 float covYYUpd = 0.f;
74 float lastUpdateX = -1.f;
75 uint8_t lastRow = 255;
76 uint8_t lastSector = 255;
77 float deltaZ = 0.f;
78
79 for (int32_t iWay = 0; iWay < nWays; iWay++) {
80 int32_t nMissed = 0, nMissed2 = 0;
81 float sumInvSqrtCharge = 0.f;
82 int32_t nAvgCharge = 0;
83
84 if (iWay && (iWay & 1) == 0) {
85 StoreOuter(&track.OuterParam(), prop.GetAlpha());
86 }
87
88 int32_t resetT0 = initResetT0();
89 const bool refit = (nWays == 1 || iWay >= 1);
90 const bool finalOutInFit = iWay + 2 >= nWays;
91 const bool finalFit = iWay == nWays - 1;
92 const float maxSinForUpdate = CAMath::Sin(70.f * kDeg2Rad);
93
94 ResetCovariance();
95 prop.SetSeedingErrors(!(refit && attempt == 0));
96 prop.SetFitInProjections(true); // param.rec.fitInProjections == -1 ? (iWay == 0) : param.rec.fitInProjections); // TODO: Reenable once fixed
97 prop.SetPropagateBzOnly(param.rec.fitPropagateBzOnly == -1 ? !finalFit : param.rec.fitPropagateBzOnly);
98 prop.SetMatLUT((param.rec.useMatLUT && finalFit) ? merger->GetConstantMem()->calibObjects.matLUT : nullptr);
99 prop.SetTrack(this, iWay ? prop.GetAlpha() : Alpha);
100 ConstrainSinPhi(iWay == 0 ? 0.95f : GPUCA_MAX_SIN_PHI_LOW);
101 CADEBUG(printf("Fitting track %d way %d (sector %d, alpha %f) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", iTrk, iWay, CAMath::Float2IntRn(prop.GetAlpha() / kSectAngle) + (mP[1] < 0 ? 18 : 0), prop.GetAlpha()));
102
103 N = 0;
104 lastUpdateX = -1;
105 const bool inFlyDirection = iWay & 1;
106 const int32_t wayDirection = (iWay & 1) ? -1 : 1;
107
108 int32_t goodRows = 0;
109 for (int32_t ihit = ihitStart; ihit >= 0 && ihit < maxN; ihit += wayDirection) {
110 const bool crossCE = lastSector != 255 && ((lastSector < 18) ^ (clusters[ihit].sector < 18));
111 if (crossCE) {
112 lastSector = clusters[ihit].sector;
113 }
114
115 if ((param.rec.tpc.trackFitRejectMode > 0 && nMissed >= param.rec.tpc.trackFitRejectMode) || nMissed2 >= param.rec.tpc.trackFitMaxRowMissedHard || clusters[ihit].state & GPUTPCGMMergedTrackHit::flagReject) {
116 CADEBUG(printf("\tSkipping hit %d, %d hits rejected, flag %X\n", ihit, nMissed, (int32_t)clusters[ihit].state));
117 if (finalOutInFit && !(clusters[ihit].state & GPUTPCGMMergedTrackHit::flagReject)) {
119 }
120 continue;
121 }
122
123 const bool allowChangeClusters = finalOutInFit && (nWays == 1 || ((iWay & 1) ? (ihit <= CAMath::Max(maxN / 2, maxN - 30)) : (ihit >= CAMath::Min(maxN / 2, 30))));
124
125 int32_t ihitMergeFirst = ihit;
126 uint8_t clusterState = clusters[ihit].state;
127 const float clAlpha = param.Alpha(clusters[ihit].sector);
128 float xx, yy, zz;
129 {
130 const ClusterNative& GPUrestrict() cl = merger->GetConstantMem()->ioPtrs.clustersNative->clustersLinear[clusters[ihit].num];
131 merger->GetConstantMem()->calibObjects.fastTransformHelper->Transform(clusters[ihit].sector, clusters[ihit].row, cl.getPad(), cl.getTime(), xx, yy, zz, mTOffset);
132 }
133 // clang-format off
134 CADEBUG(printf("\tHit %3d/%3d Row %3d: Cluster Alpha %8.3f %3d, X %8.3f - Y %8.3f, Z %8.3f (Missed %d)\n", ihit, maxN, (int32_t)clusters[ihit].row, clAlpha, (int32_t)clusters[ihit].sector, xx, yy, zz, nMissed));
135 // CADEBUG(if ((uint32_t)merger->GetTrackingChain()->mIOPtrs.nMCLabelsTPC > clusters[ihit].num))
136 // CADEBUG({printf(" MC:"); for (int32_t i = 0; i < 3; i++) {int32_t mcId = merger->GetTrackingChain()->mIOPtrs.mcLabelsTPC[clusters[ihit].num].fClusterID[i].fMCID; if (mcId >= 0) printf(" %d", mcId); } } printf("\n"));
137 // clang-format on
138 if (MergeDoubleRowClusters(ihit, wayDirection, clusters, merger, prop, xx, yy, zz, maxN, clAlpha, clusterState, allowChangeClusters) == -1) {
139 nMissed++;
140 nMissed2++;
141 continue;
142 }
143
144 if (param.rec.tpc.rejectIFCLowRadiusCluster) {
145 const float r2 = xx * xx + yy * yy;
146 const float rmax = (83.5f + param.rec.tpc.sysClusErrorMinDist);
147 if (r2 < rmax * rmax) {
148 MarkClusters(clusters, ihitMergeFirst, ihit, wayDirection, GPUTPCGMMergedTrackHit::flagRejectErr);
149 continue;
150 }
151 }
152
153 const auto& cluster = clusters[ihit];
154
155 // clang-format off
156 CADEBUG(printf("\tSector %2d %11sTrack Alpha %8.3f %s, X %8.3f - Y %8.3f, Z %8.3f - QPt %7.2f (%7.2f), SP %5.2f (%5.2f) %28s --- Cov sY %8.3f sZ %8.3f sSP %8.3f sPt %8.3f - YPt %8.3f\n", (int32_t)cluster.sector, "", prop.GetAlpha(), (CAMath::Abs(prop.GetAlpha() - clAlpha) < 0.01 ? " " : " R!"), mX, mP[0], mP[1], mP[4], prop.GetQPt0(), mP[2], prop.GetSinPhi0(), "", sqrtf(mC[0]), sqrtf(mC[2]), sqrtf(mC[5]), sqrtf(mC[14]), mC[10]));
157 // clang-format on
158 if (allowChangeClusters && lastRow != 255 && CAMath::Abs(cluster.row - lastRow) > 1) {
160 bool dodEdx = param.dodEdxEnabled && param.rec.tpc.adddEdxSubThresholdClusters && finalFit && CAMath::Abs(cluster.row - lastRow) == 2;
161 dodEdx = AttachClustersPropagate(merger, cluster.sector, lastRow, cluster.row, iTrk, track.Leg() == 0, prop, inFlyDirection, GPUCA_MAX_SIN_PHI, dodEdx);
162 if (dodEdx) {
163 dEdx.fillSubThreshold(lastRow - wayDirection);
164 if GPUCA_RTC_CONSTEXPR (GPUCA_GET_CONSTEXPR(param.rec.tpc, dEdxClusterRejectionFlagMask) != GPUCA_GET_CONSTEXPR(param.rec.tpc, dEdxClusterRejectionFlagMaskAlt)) {
165 dEdxAlt.fillSubThreshold(lastRow - wayDirection);
166 }
167 }
168 }
169 }
170
171 int32_t retValProp = prop.PropagateToXAlpha(xx, clAlpha, inFlyDirection);
172 // clang-format off
173 CADEBUG(if (!CheckCov()){printf("INVALID COV AFTER PROPAGATE!!!\n");});
174 // clang-format on
175 if (retValProp == -2) // Rotation failed, try to bring to new x with old alpha first, rotate, and then propagate to x, alpha
176 {
177 CADEBUG(printf("REROTATE\n"));
178 if (prop.PropagateToXAlpha(xx, prop.GetAlpha(), inFlyDirection) == 0) {
179 retValProp = prop.PropagateToXAlpha(xx, clAlpha, inFlyDirection);
180 }
181 }
182 if (lastRow == 255 || CAMath::Abs((int32_t)lastRow - (int32_t)cluster.row) > 5 || lastSector != cluster.sector || (param.rec.tpc.trackFitRejectMode < 0 && -nMissed <= param.rec.tpc.trackFitRejectMode)) {
183 goodRows = 0;
184 } else {
185 goodRows++;
186 }
187 if (retValProp == 0) {
188 lastRow = cluster.row;
189 lastSector = cluster.sector;
190 }
191 // clang-format off
192 CADEBUG(printf("\t%21sPropaga Alpha %8.3f , X %8.3f - Y %8.3f, Z %8.3f - QPt %7.2f (%7.2f), SP %5.2f (%5.2f) --- Res %8.3f %8.3f --- Cov sY %8.3f sZ %8.3f sSP %8.3f sPt %8.3f - YPt %8.3f - PErr %d", "", prop.GetAlpha(), mX, mP[0], mP[1], mP[4], prop.GetQPt0(), mP[2], prop.GetSinPhi0(), mP[0] - yy, mP[1] - zz, sqrtf(mC[0]), sqrtf(mC[2]), sqrtf(mC[5]), sqrtf(mC[14]), mC[10], retValProp));
193 // clang-format on
194
195 if (crossCE) {
196 if (param.rec.tpc.addErrorsCECrossing) {
197 if (param.rec.tpc.addErrorsCECrossing >= 2) {
198 AddCovDiagErrorsWithCorrelations(param.rec.tpc.errorsCECrossing);
199 } else {
200 AddCovDiagErrors(param.rec.tpc.errorsCECrossing);
201 }
202 } else if (mC[2] < 0.5f) {
203 mC[2] = 0.5f;
204 }
205 }
206
207 float uncorrectedY = -1e6f;
208 if (allowChangeClusters) {
209 uncorrectedY = AttachClusters(merger, cluster.sector, cluster.row, iTrk, track.Leg() == 0, prop);
210 }
211
212 const bool sinPhiErr = mNDF > 0 && CAMath::Abs(prop.GetSinPhi0()) >= maxSinForUpdate;
213 if (mNDF >= 0 && (mC[0] > param.rec.tpc.trackFitCovLimit || mC[2] > param.rec.tpc.trackFitCovLimit)) {
214 break;
215 }
216 if (retValProp || sinPhiErr) {
217 MarkClusters(clusters, ihitMergeFirst, ihit, wayDirection, GPUTPCGMMergedTrackHit::flagHighIncl);
218 nMissed2++;
219 NTolerated++;
220 CADEBUG(printf(", %d --- break\n", (int32_t)sinPhiErr));
221 continue;
222 }
223 CADEBUG(printf("\n"));
224
225 int32_t retValUpd = 0, retValInt = 0;
226 float threshold = 3.f + (lastUpdateX >= 0 ? (CAMath::Abs(mX - lastUpdateX) / 2) : 0.f);
227 if (mNDF > (int32_t)param.rec.tpc.mergerNonInterpolateRejectMinNDF && (CAMath::Abs(yy - mP[0]) > threshold || CAMath::Abs(zz - mP[1]) > threshold)) {
229 } else {
230 int8_t rejectChi2 = 0;
231 if (attempt == 0) {
232 if (param.rec.tpc.mergerInterpolateErrors && CAMath::Abs(ihit - ihitMergeFirst) <= 1) {
233 if (iWay == nWays - 3) {
235 } else if (iWay == nWays - 2) {
237 } else if (iWay == nWays - 1) {
238 rejectChi2 = (param.rec.tpc.mergerInterpolateRejectAlsoOnCurrentPosition && GetNDF() > (int32_t)param.rec.tpc.mergerNonInterpolateRejectMinNDF) ? GPUTPCGMPropagator::rejectDirect : 0;
239 }
240 } else {
241 rejectChi2 = allowChangeClusters && goodRows > 5;
242 }
243 }
244
245 float err2Y, err2Z;
246 const float time = merger->GetConstantMem()->ioPtrs.clustersNative ? merger->GetConstantMem()->ioPtrs.clustersNative->clustersLinear[cluster.num].getTime() : -1.f;
247 const float invSqrtCharge = merger->GetConstantMem()->ioPtrs.clustersNative ? CAMath::InvSqrt(merger->GetConstantMem()->ioPtrs.clustersNative->clustersLinear[cluster.num].qMax) : 0.f;
248 const float invCharge = merger->GetConstantMem()->ioPtrs.clustersNative ? (1.f / merger->GetConstantMem()->ioPtrs.clustersNative->clustersLinear[cluster.num].qMax) : 0.f;
249 float invAvgCharge = (sumInvSqrtCharge += invSqrtCharge) / ++nAvgCharge;
250 invAvgCharge *= invAvgCharge;
251 prop.GetErr2(err2Y, err2Z, param, zz, cluster.row, clusterState, cluster.sector, time, invAvgCharge, invCharge);
252
253 if (rejectChi2 >= GPUTPCGMPropagator::rejectInterFill) {
256 } else {
257 retValInt = prop.InterpolateReject(param, yy, zz, clusterState, rejectChi2, &interpolation.hit[ihit], err2Y, err2Z, deltaZ);
258 }
259 }
260
261 if (param.rec.tpc.rejectEdgeClustersInTrackFit && uncorrectedY > -1e6f && param.rejectEdgeClusterByY(uncorrectedY, cluster.row, CAMath::Sqrt(mC[0]))) { // uncorrectedY > -1e6f implies allowChangeClusters
263 } else {
264 retValUpd = prop.Update(yy, zz, cluster.row, param, clusterState, rejectChi2, refit, err2Y, err2Z);
265 }
266 GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamUpdateTrack, iTrk)) {
267 merger->DebugStreamerUpdate(iTrk, ihit, xx, yy, zz, cluster, merger->GetConstantMem()->ioPtrs.clustersNative->clustersLinear[cluster.num], *this, prop, interpolation.hit[ihit], rejectChi2, refit, retValUpd, sumInvSqrtCharge / nAvgCharge * sumInvSqrtCharge / nAvgCharge, yy, zz, clusterState, retValInt, err2Y, err2Z);
268 });
269 }
270 // clang-format off
271 CADEBUG(if (!CheckCov()) GPUError("INVALID COV AFTER UPDATE!!!"));
272 CADEBUG(printf("\t%21sFit Alpha %8.3f , X %8.3f - Y %8.3f, Z %8.3f - QPt %7.2f (%7.2f), SP %5.2f (%5.2f), DzDs %5.2f %16s --- Cov sY %8.3f sZ %8.3f sSP %8.3f sPt %8.3f - YPt %8.3f - FErr %d %d\n", "", prop.GetAlpha(), mX, mP[0], mP[1], mP[4], prop.GetQPt0(), mP[2], prop.GetSinPhi0(), mP[3], "", sqrtf(mC[0]), sqrtf(mC[2]), sqrtf(mC[5]), sqrtf(mC[14]), mC[10], retValUpd, retValInt));
273 // clang-format on
274
275 ConstrainSinPhi(); // TODO: Limit using ConstrainSinPhi everywhere!
276 if (!retValUpd && !retValInt) // track is updated
277 {
278 lastUpdateX = mX;
279 covYYUpd = mC[0];
280 nMissed = nMissed2 = 0;
281 UnmarkClusters(clusters, ihitMergeFirst, ihit, wayDirection, GPUTPCGMMergedTrackHit::flagHighIncl);
282 N++;
283 ihitStart = ihit;
284 float dy = mP[0] - prop.Model().Y();
285 float dz = mP[1] - prop.Model().Z();
286 if (CAMath::Abs(mP[4]) * param.qptB5Scaler > 10 && --resetT0 <= 0 && CAMath::Abs(mP[2]) < 0.15f && dy * dy + dz * dz > 1) {
287 CADEBUG(printf("Reinit linearization\n"));
288 prop.SetTrack(this, prop.GetAlpha());
289 }
291 if (param.dodEdxEnabled && finalFit) { // TODO: Costimize flag to remove, and option to remove double-clusters
292 bool acc = (clusterState & param.rec.tpc.dEdxClusterRejectionFlagMask) == 0, accAlt = (clusterState & param.rec.tpc.dEdxClusterRejectionFlagMaskAlt) == 0;
293 if (acc || accAlt) {
294 float qtot = 0, qmax = 0, pad = 0, relTime = 0;
295 const int32_t clusterCount = (ihit - ihitMergeFirst) * wayDirection + 1;
296 for (int32_t iTmp = ihitMergeFirst; iTmp != ihit + wayDirection; iTmp += wayDirection) {
297 const ClusterNative& cl = merger->GetConstantMem()->ioPtrs.clustersNative->clustersLinear[cluster.num];
298 qtot += cl.qTot;
299 qmax = CAMath::Max<float>(qmax, cl.qMax);
300 pad += cl.getPad();
301 relTime += cl.getTime();
302 }
303 qtot /= clusterCount; // TODO: Weighted Average
304 pad /= clusterCount;
305 relTime /= clusterCount;
306 relTime = relTime - CAMath::Round(relTime);
307 if (acc) {
308 dEdx.fillCluster(qtot, qmax, cluster.row, cluster.sector, mP[2], mP[3], merger->GetConstantMem()->calibObjects, zz, pad, relTime);
309 }
310 if GPUCA_RTC_CONSTEXPR (GPUCA_GET_CONSTEXPR(param.rec.tpc, dEdxClusterRejectionFlagMask) != GPUCA_GET_CONSTEXPR(param.rec.tpc, dEdxClusterRejectionFlagMaskAlt)) {
311 if (accAlt) {
312 dEdxAlt.fillCluster(qtot, qmax, cluster.row, cluster.sector, mP[2], mP[3], merger->GetConstantMem()->calibObjects, zz, pad, relTime);
313 }
314 }
315 }
316 }
317 }
318 } else if (retValInt || retValUpd >= GPUTPCGMPropagator::updateErrorClusterRejected) { // cluster far away form the track
319 if (retValInt || allowChangeClusters) {
320 MarkClusters(clusters, ihitMergeFirst, ihit, wayDirection, GPUTPCGMMergedTrackHit::flagRejectDistance);
321 } else if (finalFit) {
322 MarkClusters(clusters, ihitMergeFirst, ihit, wayDirection, GPUTPCGMMergedTrackHit::flagRejectErr);
323 }
324 if (!retValInt) {
325 nMissed++;
326 nMissed2++;
327 }
328 } else {
329 break; // bad chi2 for the whole track, stop the fit
330 }
331 }
332 if (finalOutInFit && !(merger->Param().rec.tpc.disableRefitAttachment & 4) && lastRow != 255 && lastSector != 255) {
333 StoreLoopPropagation(merger, lastSector, lastRow, iTrk, lastRow > clusters[(iWay & 1) ? (maxN - 1) : 0].row, prop.GetAlpha());
334 CADEBUG(printf("\t\tSTORING %d lastRow %d row %d out %d\n", iTrk, (int)lastRow, (int)clusters[(iWay & 1) ? (maxN - 1) : 0].row, lastRow > clusters[(iWay & 1) ? (maxN - 1) : 0].row));
335 }
336 if (!(iWay & 1) && !finalFit && !track.CCE() && !track.Looper()) {
337 deltaZ = ShiftZ(clusters, merger, maxN);
338 } else {
339 deltaZ = 0.f;
340 }
341 }
342 ConstrainSinPhi();
343
344 GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamUpdateTrack, iTrk)) {
345 o2::utils::DebugStreamer::instance()->getStreamer("debug_accept_track", "UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName("debug_accept_track").data() << "iTrk=" << iTrk << "outerParam=" << track.OuterParam() << "track=" << this << "ihitStart=" << ihitStart << "\n";
346 })
347
348 if (!(N + NTolerated >= GPUCA_TRACKLET_SELECTOR_MIN_HITS_B5(mP[4] * param.qptB5Scaler) && 2 * NTolerated <= CAMath::Max(10, N) && CheckNumericalQuality(covYYUpd))) {
349 return false; // TODO: NTolerated should never become that large, check what is going wrong!
350 }
351 if (param.rec.tpc.minNClustersFinalTrack != -1 && N + NTolerated < param.rec.tpc.minNClustersFinalTrack) {
352 return false;
353 }
354
355 if (param.par.dodEdx && param.dodEdxEnabled) {
356 dEdx.computedEdx(merger->MergedTracksdEdx()[iTrk], param);
357 if GPUCA_RTC_CONSTEXPR (GPUCA_GET_CONSTEXPR(param.rec.tpc, dEdxClusterRejectionFlagMask) != GPUCA_GET_CONSTEXPR(param.rec.tpc, dEdxClusterRejectionFlagMaskAlt)) {
358 dEdxAlt.computedEdx(merger->MergedTracksdEdxAlt()[iTrk], param);
359 }
360 }
361 Alpha = prop.GetAlpha();
362 MoveToReference(prop, param, Alpha);
363 NormalizeAlpha(Alpha);
364
365 return true;
366}
367
368GPUdni() void GPUTPCGMTrackParam::MoveToReference(GPUTPCGMPropagator& prop, const GPUParam& param, float& Alpha)
369{
370 static constexpr float kDeg2Rad = M_PI / 180.f;
371 static constexpr float kSectAngle = 2 * M_PI / 18.f;
372
373 if (param.rec.tpc.trackReferenceX <= 500) {
374 GPUTPCGMTrackParam save = *this;
375 float saveAlpha = Alpha;
376 for (int32_t attempt = 0; attempt < 3; attempt++) {
377 float dAngle = CAMath::Round(CAMath::ATan2(mP[0], mX) / kDeg2Rad / 20.f) * kSectAngle;
378 Alpha += dAngle;
379 if (prop.PropagateToXAlpha(param.rec.tpc.trackReferenceX, Alpha, 0)) {
380 break;
381 }
382 ConstrainSinPhi();
383 if (CAMath::Abs(mP[0]) <= mX * CAMath::Tan(kSectAngle / 2.f)) {
384 return;
385 }
386 }
387 *this = save;
388 Alpha = saveAlpha;
389 }
390 if (CAMath::Abs(mP[0]) > mX * CAMath::Tan(kSectAngle / 2.f)) {
391 float dAngle = CAMath::Round(CAMath::ATan2(mP[0], mX) / kDeg2Rad / 20.f) * kSectAngle;
392 Rotate(dAngle);
393 ConstrainSinPhi();
394 Alpha += dAngle;
395 }
396}
397
398GPUd() void GPUTPCGMTrackParam::MirrorTo(GPUTPCGMPropagator& GPUrestrict() prop, float toY, float toZ, bool inFlyDirection, const GPUParam& param, uint8_t row, uint8_t clusterState, bool mirrorParameters, int8_t sector)
399{
400 if (mirrorParameters) {
401 prop.Mirror(inFlyDirection);
402 }
403 float err2Y, err2Z;
404 prop.GetErr2(err2Y, err2Z, param, toZ, row, clusterState, sector, -1.f, 0.f, 0.f); // Use correct time / avgCharge
405 prop.Model().Y() = mP[0] = toY;
406 prop.Model().Z() = mP[1] = toZ;
407 if (mC[0] < err2Y) {
408 mC[0] = err2Y;
409 }
410 if (mC[2] < err2Z) {
411 mC[2] = err2Z;
412 }
413 if (CAMath::Abs(mC[5]) < 0.1f) {
414 mC[5] = mC[5] > 0 ? 0.1f : -0.1f;
415 }
416 if (mC[9] < 1.f) {
417 mC[9] = 1.f;
418 }
419 mC[1] = mC[4] = mC[6] = mC[8] = mC[11] = mC[13] = 0;
420 prop.SetTrack(this, prop.GetAlpha());
421 mNDF = -3;
422 mChi2 = 0;
423}
424
425GPUd() int32_t GPUTPCGMTrackParam::MergeDoubleRowClusters(int32_t& ihit, int32_t wayDirection, GPUTPCGMMergedTrackHit* GPUrestrict() clusters, const GPUTPCGMMerger* GPUrestrict() merger, GPUTPCGMPropagator& GPUrestrict() prop, float& GPUrestrict() xx, float& GPUrestrict() yy, float& GPUrestrict() zz, int32_t maxN, float clAlpha, uint8_t& GPUrestrict() clusterState, bool rejectChi2)
426{
427 if (ihit + wayDirection >= 0 && ihit + wayDirection < maxN && clusters[ihit].row == clusters[ihit + wayDirection].row && clusters[ihit].sector == clusters[ihit + wayDirection].sector) {
428 float maxDistY, maxDistZ;
429 prop.GetErr2(maxDistY, maxDistZ, merger->Param(), zz, clusters[ihit].row, 0, clusters[ihit].sector, -1.f, 0.f, 0.f); // TODO: Use correct time, avgCharge
430 maxDistY = (maxDistY + mC[0]) * 20.f;
431 maxDistZ = (maxDistZ + mC[2]) * 20.f;
432 int32_t noReject = 0; // Cannot reject if simple estimation of y/z fails (extremely unlike case)
433 if (CAMath::Abs(clAlpha - prop.GetAlpha()) > 1.e-4f) {
434 noReject = prop.RotateToAlpha(clAlpha);
435 }
436 float projY = 0, projZ = 0;
437 if (noReject == 0) {
438 noReject |= prop.GetPropagatedYZ(xx, projY, projZ);
439 }
440 float count = 0.f;
441 xx = yy = zz = 0.f;
442 clusterState = 0;
443 while (true) {
444 const ClusterNative& GPUrestrict() cl = merger->GetConstantMem()->ioPtrs.clustersNative->clustersLinear[clusters[ihit].num];
445 float clamp = cl.qTot;
446 float clx, cly, clz;
447 merger->GetConstantMem()->calibObjects.fastTransformHelper->Transform(clusters[ihit].sector, clusters[ihit].row, cl.getPad(), cl.getTime(), clx, cly, clz, mTOffset);
448 float dy = cly - projY;
449 float dz = clz - projZ;
450 if (noReject == 0 && (dy * dy > maxDistY || dz * dz > maxDistZ)) {
451 CADEBUG(printf("\t\tRejecting double-row cluster: dy %f, dz %f, chiY %f, chiZ %f (Y: trk %f prj %f cl %f - Z: trk %f prj %f cl %f)\n", dy, dz, sqrtf(maxDistY), sqrtf(maxDistZ), mP[0], projY, cly, mP[1], projZ, clz));
452 if (rejectChi2) {
454 }
455 } else {
456 CADEBUG(printf("\t\tMerging hit row %d X %f Y %f Z %f (dy %f, dz %f, chiY %f, chiZ %f)\n", clusters[ihit].row, clx, cly, clz, dy, dz, sqrtf(maxDistY), sqrtf(maxDistZ)));
457 xx += clx * clamp; // TODO: Weight in pad/time instead of XYZ
458 yy += cly * clamp;
459 zz += clz * clamp;
460 clusterState |= clusters[ihit].state;
461 count += clamp;
462 }
463 if (!(ihit + wayDirection >= 0 && ihit + wayDirection < maxN && clusters[ihit].row == clusters[ihit + wayDirection].row && clusters[ihit].sector == clusters[ihit + wayDirection].sector)) {
464 break;
465 }
466 ihit += wayDirection;
467 }
468 if (count < 0.1f) {
469 CADEBUG(printf("\t\tNo matching cluster in double-row, skipping\n"));
470 return -1;
471 }
472 xx /= count;
473 yy /= count;
474 zz /= count;
475 }
476 return 0;
477}
478
479GPUd() float GPUTPCGMTrackParam::AttachClusters(const GPUTPCGMMerger* GPUrestrict() Merger, int32_t sector, int32_t iRow, int32_t iTrack, bool goodLeg, GPUTPCGMPropagator& prop)
480{
481 float Y, Z;
482 float X = 0;
483 Merger->GetConstantMem()->calibObjects.fastTransformHelper->InverseTransformYZtoX(sector, iRow, mP[0], mP[1], X);
484 if (prop.GetPropagatedYZ(X, Y, Z)) {
485 Y = mP[0];
486 Z = mP[1];
487 }
488 return AttachClusters(Merger, sector, iRow, iTrack, goodLeg, Y, Z);
489}
490
491GPUd() float GPUTPCGMTrackParam::AttachClusters(const GPUTPCGMMerger* GPUrestrict() Merger, int32_t sector, int32_t iRow, int32_t iTrack, bool goodLeg, float Y, float Z)
492{
493 const auto& param = Merger->Param();
494 if (param.rec.tpc.disableRefitAttachment & 1) {
495 return -1e6f;
496 }
497 const GPUTPCTracker& GPUrestrict() tracker = *(Merger->GetConstantMem()->tpcTrackers + sector);
498 const GPUTPCRow& GPUrestrict() row = tracker.Row(iRow);
499 GPUglobalref() const cahit2* hits = tracker.HitData(row);
500 GPUglobalref() const calink* firsthit = tracker.FirstHitInBin(row);
501 if (row.NHits() == 0) {
502 return -1e6f;
503 }
504
505 const float zOffset = param.par.continuousTracking ? Merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(sector, mTOffset, param.continuousMaxTimeBin) : 0; // TODO: do some validatiomns for the transform conv functions...
506 const float y0 = row.Grid().YMin();
507 const float stepY = row.HstepY();
508 const float z0 = row.Grid().ZMin() - zOffset; // We can use our own ZOffset, since this is only used temporarily anyway
509 const float stepZ = row.HstepZ();
510 int32_t bin, ny, nz;
511
512 float uncorrectedY, uncorrectedZ;
513 Merger->GetConstantMem()->calibObjects.fastTransformHelper->InverseTransformYZtoNominalYZ(sector, iRow, Y, Z, uncorrectedY, uncorrectedZ);
514 if (CAMath::Abs(uncorrectedY) > row.getTPCMaxY()) {
515 return uncorrectedY;
516 }
517
518 bool protect = CAMath::Abs(GetQPt() * param.qptB5Scaler) <= param.rec.tpc.rejectQPtB5 && goodLeg;
519 float err2Y, err2Z;
520 param.GetClusterErrors2(sector, iRow, Z, mP[2], mP[3], -1.f, 0.f, 0.f, err2Y, err2Z); // TODO: Use correct time/avgCharge
521 const float tubeMaxSize2 = protect ? param.rec.tpc.tubeProtectMaxSize2 : param.rec.tpc.tubeRemoveMaxSize2;
522 const float tubeMinSize2 = protect ? param.rec.tpc.tubeProtectMinSize2 : 0.f;
523 float tubeSigma2 = protect ? param.rec.tpc.tubeProtectSigma2 : param.rec.tpc.tubeRemoveSigma2;
524 uint32_t pad = CAMath::Float2UIntRn(GPUTPCGeometry::LinearY2Pad(sector, iRow, uncorrectedY));
525 float time = Merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->InverseTransformInTimeFrame(sector, uncorrectedZ + (param.par.continuousTracking ? Merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(sector, mTOffset, param.continuousMaxTimeBin) : 0), param.continuousMaxTimeBin); // TODO: Simplify this call in TPCFastTransform
526 if (iRow < param.rec.tpc.tubeExtraProtectMinRow ||
527 pad < param.rec.tpc.tubeExtraProtectEdgePads || pad >= (uint32_t)(GPUTPCGeometry::NPads(iRow) - param.rec.tpc.tubeExtraProtectEdgePads) ||
528 param.GetUnscaledMult(time) / GPUTPCGeometry::Row2X(iRow) > param.rec.tpc.tubeExtraProtectMinOccupancy) {
529 tubeSigma2 *= protect ? 2 : 0.5;
530 }
531 const float sy2 = CAMath::Max(tubeMinSize2, CAMath::Min(tubeMaxSize2, tubeSigma2 * (err2Y + CAMath::Abs(mC[0])))); // Cov can be bogus when following circle
532 const float sz2 = CAMath::Max(tubeMinSize2, CAMath::Min(tubeMaxSize2, tubeSigma2 * (err2Z + CAMath::Abs(mC[2])))); // In that case we should provide the track error externally
533 const float tubeY = CAMath::Sqrt(sy2);
534 const float tubeZ = CAMath::Sqrt(sz2);
535 const float sy21 = 1.f / sy2;
536 const float sz21 = 1.f / sz2;
537
538 row.Grid().GetBinArea(uncorrectedY, uncorrectedZ + zOffset, tubeY, tubeZ, bin, ny, nz);
539 const int32_t nBinsY = row.Grid().Ny();
540 const int32_t idOffset = tracker.Data().ClusterIdOffset();
541 const int32_t* ids = &(tracker.Data().ClusterDataIndex()[row.HitNumberOffset()]);
542 uint32_t myWeight = Merger->TrackOrderAttach()[iTrack] | gputpcgmmergertypes::attachAttached | gputpcgmmergertypes::attachTube;
543 GPUAtomic(uint32_t)* const weights = Merger->ClusterAttachment();
544 if (goodLeg) {
546 }
547 if (protect) {
549 }
550
551 for (int32_t k = 0; k <= nz; k++) {
552 const int32_t mybin = bin + k * nBinsY;
553 const uint32_t hitFst = firsthit[mybin];
554 const uint32_t hitLst = firsthit[mybin + ny + 1];
555 for (uint32_t ih = hitFst; ih < hitLst; ih++) {
556 int32_t id = idOffset + ids[ih];
557 GPUAtomic(uint32_t)* const weight = weights + id;
558 if constexpr (GPUCA_PAR_NO_ATOMIC_PRECHECK == 0) {
559 if (myWeight <= *weight) {
560 continue;
561 }
562 }
563 const cahit2 hh = hits[ih];
564 const float y = y0 + hh.x * stepY;
565 const float z = z0 + hh.y * stepZ;
566 const float dy = y - uncorrectedY;
567 const float dz = z - uncorrectedZ;
568 if (dy * dy * sy21 + dz * dz * sz21 <= CAMath::Sqrt(2.f)) {
569 // CADEBUG(printf("Found Y %f Z %f\n", y, z));
570 CAMath::AtomicMax(weight, myWeight);
571 }
572 }
573 }
574 return uncorrectedY;
575}
576
577GPUd() bool GPUTPCGMTrackParam::AttachClustersPropagate(const GPUTPCGMMerger* GPUrestrict() Merger, int32_t sector, int32_t lastRow, int32_t toRow, int32_t iTrack, bool goodLeg, GPUTPCGMPropagator& GPUrestrict() prop, bool inFlyDirection, float maxSinPhi, bool dodEdx)
578{
579 static constexpr float kSectAngle = 2 * M_PI / 18.f;
580 if (Merger->Param().rec.tpc.disableRefitAttachment & 2) {
581 return dodEdx;
582 }
583 if (CAMath::Abs(lastRow - toRow) < 2) {
584 return dodEdx;
585 }
586 int32_t step = toRow > lastRow ? 1 : -1;
587 float xx = mX - GPUTPCGeometry::Row2X(lastRow);
588 for (int32_t iRow = lastRow + step; iRow != toRow; iRow += step) {
589 if (CAMath::Abs(mP[2]) > maxSinPhi) {
590 return dodEdx;
591 }
592 if (CAMath::Abs(mP[0]) > CAMath::Abs(mX) * CAMath::Tan(kSectAngle / 2.f)) {
593 return dodEdx;
594 }
595 int32_t err = prop.PropagateToXAlpha(xx + GPUTPCGeometry::Row2X(iRow), prop.GetAlpha(), inFlyDirection);
596 if (err) {
597 return dodEdx;
598 }
599 if (dodEdx && iRow + step == toRow) {
600 float yUncorrected, zUncorrected;
601 Merger->GetConstantMem()->calibObjects.fastTransformHelper->InverseTransformYZtoNominalYZ(sector, iRow, mP[0], mP[1], yUncorrected, zUncorrected);
602 uint32_t pad = CAMath::Float2UIntRn(GPUTPCGeometry::LinearY2Pad(sector, iRow, yUncorrected));
603 if (pad >= GPUTPCGeometry::NPads(iRow) || (Merger->GetConstantMem()->calibObjects.dEdxCalibContainer && Merger->GetConstantMem()->calibObjects.dEdxCalibContainer->isDead(sector, iRow, pad))) {
604 dodEdx = false;
605 }
606 }
607 CADEBUG(printf("Attaching in row %d\n", iRow));
608 AttachClusters(Merger, sector, iRow, iTrack, goodLeg, prop);
609 }
610 return dodEdx;
611}
612
613GPUdii() void GPUTPCGMTrackParam::StoreOuter(gputpcgmmergertypes::GPUTPCOuterParam* outerParam, float alpha)
614{
615 CADEBUG(printf("\t%21sStorO Alpha %8.3f , X %8.3f - Y %8.3f, Z %8.3f - QPt %7.2f, SP %5.2f --- Cov sY %8.3f sZ %8.3f sSP %8.3f sPt %8.3f\n", "", alpha, mX, mP[0], mP[1], mP[4], mP[2], sqrtf(mC[0]), sqrtf(mC[2]), sqrtf(mC[5]), sqrtf(mC[14])));
616 for (int32_t i = 0; i < 5; i++) {
617 outerParam->P[i] = mP[i];
618 }
619 for (int32_t i = 0; i < 15; i++) {
620 outerParam->C[i] = mC[i];
621 }
622 outerParam->X = mX;
623 outerParam->alpha = alpha;
624}
625
626GPUdic(0, 1) void GPUTPCGMTrackParam::StoreLoopPropagation(const GPUTPCGMMerger* GPUrestrict() Merger, int32_t sector, int32_t iRow, int32_t iTrack, bool outwards, float alpha)
627{
628 if (iRow == 0 || iRow == GPUCA_ROW_COUNT - 1) {
629 return;
630 }
631 if (CAMath::Abs(mP[2]) >= GPUCA_MAX_SIN_PHI) { // TODO: How can we avoid this?
632 return;
633 }
634 if (CAMath::Abs(mP[2]) < 0.75) {
635 return;
636 }
637 if ((mP[2] * mP[4] < 0) ^ outwards) {
638 return;
639 }
640
641 uint32_t nLoopData = CAMath::AtomicAdd(&Merger->Memory()->nLoopData, 1u);
642 if (nLoopData >= Merger->NMaxTracks()) {
643 Merger->raiseError(GPUErrors::ERROR_MERGER_LOOPER_OVERFLOW, nLoopData, Merger->NMaxTracks());
644 CAMath::AtomicExch(&Merger->Memory()->nLoopData, Merger->NMaxTracks());
645 return;
646 }
648 data.param = *this;
649 data.track = iTrack;
650 data.alpha = alpha;
651 data.sector = sector;
652 data.row = iRow;
653 data.outwards = outwards;
654 Merger->LoopData()[nLoopData] = data;
655}
656
657GPUdii() void GPUTPCGMTrackParam::PropagateLooper(const GPUTPCGMMerger* GPUrestrict() Merger, int32_t loopIdx)
658{
660 prop.SetMaterialTPC();
661 prop.SetPolynomialField(&Merger->Param().polynomialField);
662 prop.SetMaxSinPhi(GPUCA_MAX_SIN_PHI);
663 prop.SetMatLUT(Merger->Param().rec.useMatLUT ? Merger->GetConstantMem()->calibObjects.matLUT : nullptr);
664 prop.SetSeedingErrors(false);
665 prop.SetFitInProjections(true);
666 prop.SetPropagateBzOnly(false);
667
668 GPUTPCGMLoopData& data = Merger->LoopData()[loopIdx];
669 prop.SetTrack(&data.param, data.alpha);
670 if (false) {
671 data.param.AttachClustersLooper(Merger, data.sector, data.row, data.track, data.outwards, prop);
672 } else {
673 data.param.AttachClustersLooperFollow(Merger, prop, data.sector, data.row, data.track, data.outwards);
674 }
675}
676
677GPUdi() void GPUTPCGMTrackParam::AttachClustersLooperFollow(const GPUTPCGMMerger* GPUrestrict() Merger, GPUTPCGMPropagator& GPUrestrict() prop, int32_t sector, int32_t iRow, int32_t iTrack, bool up)
678{
679 float toX = mX;
680 bool inFlyDirection = (Merger->MergedTracks()[iTrack].Leg() & 1) ^ up;
681
682 static constexpr float kSectAngle = 2 * M_PI / 18.f;
683 const GPUParam& GPUrestrict() param = Merger->Param();
684 bool right = (mP[2] < 0) ^ up;
685 const int32_t sectorSide = sector >= (GPUCA_NSECTORS / 2) ? (GPUCA_NSECTORS / 2) : 0;
686 float lrFactor = right ^ !up ? 1.f : -1.f;
687 // clang-format off
688 CADEBUG(printf("\nCIRCLE Track %d: Sector %d Alpha %f X %f Y %f Z %f SinPhi %f DzDs %f QPt %f - Right %d Up %d lrFactor %f\n", iTrack, sector, prop.GetAlpha(), mX, mP[0], mP[1], mP[2], mP[3], mP[4], (int32_t)right, (int32_t)up, lrFactor));
689 // clang-format on
690
691 if (prop.RotateToAlpha(prop.GetAlpha() + (CAMath::Pi() / 2.f) * lrFactor)) {
692 return;
693 }
694 CADEBUG(printf("\tRotated: X %f Y %f Z %f SinPhi %f (Alpha %f / %f)\n", mP[0], mX, mP[1], mP[2], prop.GetAlpha(), prop.GetAlpha() + CAMath::Pi() / 2.f));
695 uint32_t maxTries = 100;
696 while (true) {
697 while (CAMath::Abs(mX) <= CAMath::Abs(mP[0]) * CAMath::Tan(kSectAngle / 2.f) + 0.1f) {
698 if (maxTries-- == 0) {
699 return;
700 }
701 if (CAMath::Abs(mP[2]) > 0.7f) {
702 return;
703 }
704 if (up ? (-mP[0] * lrFactor > GPUTPCGeometry::Row2X(GPUCA_ROW_COUNT - 1)) : (-mP[0] * lrFactor < GPUTPCGeometry::Row2X(0))) {
705 return;
706 }
707 if (!((up ? (-mP[0] * lrFactor >= toX) : (-mP[0] * lrFactor <= toX)) || (right ^ (mP[2] > 0)))) {
708 return;
709 }
710 int32_t err = prop.PropagateToXAlpha(mX + (up ? 1.f : -1.f), prop.GetAlpha(), inFlyDirection);
711 if (err) {
712 CADEBUG(printf("\t\tpropagation error (%d)\n", err));
713 return;
714 }
715 CADEBUG(printf("\tPropagated to y = %f: X %f Z %f SinPhi %f\n", mX, mP[0], mP[1], mP[2]));
716 for (int32_t j = 0; j < GPUCA_ROW_COUNT; j++) { // TODO: Avoid iterating over all rows
717 float rowX = GPUTPCGeometry::Row2X(j);
718 if (CAMath::Abs(rowX - (-mP[0] * lrFactor)) < 1.5f) {
719 CADEBUG(printf("\t\tAttempt row %d (X %f Y %f Z %f)\n", j, rowX, mX * lrFactor, mP[1]));
720 AttachClusters(Merger, sector, j, iTrack, false, mX * lrFactor, mP[1]);
721 }
722 }
723 }
724 if (maxTries-- == 0) {
725 return;
726 }
727 if (right) {
728 if (++sector >= sectorSide + 18) {
729 sector -= 18;
730 }
731 } else {
732 if (--sector < sectorSide) {
733 sector += 18;
734 }
735 }
736 CADEBUG(printf("\tRotating to sector %d: %f --> %f\n", sector, prop.GetAlpha(), param.Alpha(sector) + (CAMath::Pi() / 2.f) * lrFactor));
737 int32_t err = prop.RotateToAlpha(param.Alpha(sector) + (CAMath::Pi() / 2.f) * lrFactor);
738 if (err) {
739 CADEBUG(printf("Rotation Error %d\n", err));
740 return;
741 }
742 CADEBUG(printf("\tAfter Rotating Alpha %f Position X %f Y %f Z %f SinPhi %f\n", prop.GetAlpha(), mP[0], mX, mP[1], mP[2]));
743 }
744}
745
746GPUdi() void GPUTPCGMTrackParam::AttachClustersLooper(const GPUTPCGMMerger* GPUrestrict() Merger, int32_t sector, int32_t iRow, int32_t iTrack, bool outwards, GPUTPCGMPropagator& GPUrestrict() prop)
747{
748 static constexpr float kSectAngle = 2 * M_PI / 18.f;
749 // Note that the coordinate system is rotated by 90 degree swapping X and Y!
750 float X = mP[2] > 0 ? mP[0] : -mP[0];
751 float Y = mP[2] > 0 ? -mX : mX;
752 float Z = mP[1];
753 float SinPhi = CAMath::Sqrt(1 - mP[2] * mP[2]) * (mP[2] > 0 ? -1 : 1);
754 float b = prop.GetBz(prop.GetAlpha(), mX, mP[0], mP[1]);
755
756 float dx = outwards ? 1.f : -1.f;
757 const float myRowX = GPUTPCGeometry::Row2X(iRow);
758 // printf("\nAttachMirror sector %d row %d outwards %d\n", (int)sector, (int)iRow, (int)outwards);
759 // printf("X %f Y %f Z %f SinPhi %f -->\n", mX, mP[0], mP[1], mP[2]);
760 // printf("X %f Y %f Z %f SinPhi %f, dx %f\n", X, Y, Z, SinPhi, dx);
761 uint32_t maxTries = 100;
762 while (maxTries--) {
763 float ex = CAMath::Sqrt(1 - SinPhi * SinPhi);
764 float exi = 1.f / ex;
765 float dxBzQ = dx * -b * mP[4];
766 float newSinPhi = SinPhi + dxBzQ;
767 if (CAMath::Abs(newSinPhi) > GPUCA_MAX_SIN_PHI_LOW) {
768 // printf("Abort, newSinPhi %f\n", newSinPhi);
769 return;
770 }
771 if (mP[2] > 0 ? (newSinPhi > 0.5) : (newSinPhi < -0.5)) {
772 // printf("Finished, newSinPhi %f\n", newSinPhi);
773 return;
774 }
775 float dS = dx * exi;
776 float h2 = dS * exi * exi;
777 float h4 = .5f * h2 * dxBzQ;
778
779 X += dx;
780 Y += dS * SinPhi + h4;
781 Z += dS * mP[3];
782 SinPhi = newSinPhi;
783 if (CAMath::Abs(X) > CAMath::Abs(Y) * CAMath::Tan(kSectAngle / 2.f)) {
784 // printf("Abort, sector edge\n");
785 return;
786 }
787
788 // printf("count %d: At X %f Y %f Z %f SinPhi %f\n", maxTries, mP[2] > 0 ? -Y : Y, mP[2] > 0 ? X : -X, Z, SinPhi);
789 float paramX = mP[2] > 0 ? -Y : Y;
790 int32_t step = outwards ? 1 : -1;
791 int32_t found = 0;
792 for (int32_t j = iRow; j >= 0 && j < GPUCA_ROW_COUNT && found < 3; j += step) {
793 float rowX = mX + GPUTPCGeometry::Row2X(j) - myRowX;
794 if (CAMath::Abs(rowX - paramX) < 1.5f) {
795 // printf("Attempt row %d at y %f\n", j, X);
796 AttachClusters(Merger, sector, j, iTrack, false, mP[2] > 0 ? X : -X, Z);
797 }
798 }
799 }
800}
801
802GPUd() float GPUTPCGMTrackParam::ShiftZ(const GPUTPCGMMergedTrackHit* clusters, const GPUTPCGMMerger* merger, int32_t N)
803{
804 if (N == 0) {
805 N = 1;
806 }
807 const auto& GPUrestrict() cls = merger->GetConstantMem()->ioPtrs.clustersNative->clustersLinear;
808 float z0 = cls[clusters[0].num].getTime(), zn = cls[clusters[N - 1].num].getTime();
809 const auto tmp = zn > z0 ? std::array<float, 3>{zn, z0, GPUTPCGeometry::Row2X(clusters[N - 1].row)} : std::array<float, 3>{z0, zn, GPUTPCGeometry::Row2X(clusters[0].row)};
810 return ShiftZ(merger, clusters[0].sector, tmp[0], tmp[1], tmp[2]);
811}
812
813GPUd() float GPUTPCGMTrackParam::ShiftZ(const GPUTPCGMMerger* GPUrestrict() merger, int32_t sector, float cltmax, float cltmin, float clx)
814{
815 if (!merger->Param().par.continuousTracking) {
816 return 0.f;
817 }
818 float deltaZ = 0.f;
819 bool beamlineReached = false;
820 const float r1 = CAMath::Max(0.0001f, CAMath::Abs(mP[4] * merger->Param().polynomialField.GetNominalBz()));
821 if (r1 < 0.01501) { // 100 MeV @ 0.5T ~ 0.66m cutof
822 const float dist2 = mX * mX + mP[0] * mP[0];
823 const float dist1r2 = dist2 * r1 * r1;
824 if (dist1r2 < 4) {
825 const float alpha = CAMath::ACos(1 - 0.5f * dist1r2); // Angle of a circle, such that |(cosa, sina) - (1,0)| == dist
826 const float beta = CAMath::ATan2(mP[0], mX);
827 const int32_t comp = mP[2] > CAMath::Sin(beta);
828 const float sinab = CAMath::Sin((comp ? 0.5f : -0.5f) * alpha + beta); // Angle of circle through origin and track position, to be compared to Snp
829 const float res = CAMath::Abs(sinab - mP[2]);
830
831 if (res < 0.2) {
832 const float r = 1.f / r1;
833 const float dS = alpha * r;
834 float z0 = dS * mP[3];
835 if (CAMath::Abs(z0) > GPUTPCGeometry::TPCLength()) {
836 z0 = z0 > 0 ? GPUTPCGeometry::TPCLength() : -GPUTPCGeometry::TPCLength();
837 }
838 deltaZ = mP[1] - z0;
839 beamlineReached = true;
840
841 // printf("X %9.3f Y %9.3f QPt %9.3f R %9.3f --> Alpha %9.3f Snp %9.3f Snab %9.3f Res %9.3f dS %9.3f z0 %9.3f\n", mX, mP[0], mP[4], r, alpha / 3.1415 * 180, mP[2], sinab, res, dS, z0);
842 }
843 }
844 }
845
846 if (!beamlineReached) {
847 float refZ = ((sector < GPUCA_NSECTORS / 2) ? merger->Param().rec.tpc.defaultZOffsetOverR : -merger->Param().rec.tpc.defaultZOffsetOverR) * clx;
848 float basez;
849 merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->TransformIdealZ(sector, cltmax, basez, mTOffset);
850 deltaZ = basez - refZ;
851 }
852 {
853 float deltaT = merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convDeltaZtoDeltaTimeInTimeFrame(sector, deltaZ);
854 mTOffset += deltaT;
855 const float maxT = cltmin - merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->getT0();
856 const float minT = cltmax - merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->getMaxDriftTime(sector);
857 // printf("T Check: Clusters %f %f, min %f max %f vtx %f\n", tz1, tz2, minT, maxT, mTOffset);
858 deltaT = 0.f;
859 if (mTOffset < minT) {
860 deltaT = minT - mTOffset;
861 }
862 if (mTOffset + deltaT > maxT) {
863 deltaT = maxT - mTOffset;
864 }
865 if (deltaT != 0.f) {
866 deltaZ += merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convDeltaTimeToDeltaZinTimeFrame(sector, deltaT);
867 // printf("Moving clusters to TPC Range: QPt %f, New mTOffset %f, t1 %f, t2 %f, Shift %f in Z: %f to %f --> %f to %f in T\n", mP[4], mTOffset + deltaT, tz1, tz2, deltaZ, tz2 - mTOffset, tz1 - mTOffset, tz2 - mTOffset - deltaT, tz1 - mTOffset - deltaT);
868 mTOffset += deltaT;
869 }
870 mP[1] -= deltaZ;
871 }
872 // printf("\n");
873 return -deltaZ;
874}
875
876GPUd() bool GPUTPCGMTrackParam::CheckCov() const
877{
878 const float* c = mC;
879 bool ok = c[0] >= 0 && c[2] >= 0 && c[5] >= 0 && c[9] >= 0 && c[14] >= 0 && (c[1] * c[1] <= c[2] * c[0]) && (c[3] * c[3] <= c[5] * c[0]) && (c[4] * c[4] <= c[5] * c[2]) && (c[6] * c[6] <= c[9] * c[0]) && (c[7] * c[7] <= c[9] * c[2]) && (c[8] * c[8] <= c[9] * c[5]) &&
880 (c[10] * c[10] <= c[14] * c[0]) && (c[11] * c[11] <= c[14] * c[2]) && (c[12] * c[12] <= c[14] * c[5]) && (c[13] * c[13] <= c[14] * c[9]);
881 return ok;
882}
883
884GPUd() bool GPUTPCGMTrackParam::CheckNumericalQuality(float overrideCovYY) const
885{
886 //* Check that the track parameters and covariance matrix are reasonable
887 bool ok = CAMath::Finite(mX) && CAMath::Finite(mChi2);
888 // CADEBUG(printf("OK %d - %f - ", (int32_t)ok, mX); for (int32_t i = 0; i < 5; i++) { printf("%f ", mP[i]); } printf(" - "); for (int32_t i = 0; i < 15; i++) { printf("%f ", mC[i]); } printf("\n"));
889 const float* c = mC;
890 for (int32_t i = 0; i < 15; i++) {
891 ok = ok && CAMath::Finite(c[i]);
892 }
893 for (int32_t i = 0; i < 5; i++) {
894 ok = ok && CAMath::Finite(mP[i]);
895 }
896 if ((overrideCovYY > 0 ? overrideCovYY : c[0]) > 4.f * 4.f || c[2] > 4.f * 4.f || c[5] > 2.f * 2.f || c[9] > 2.f * 2.f) {
897 ok = 0;
898 }
899 if (CAMath::Abs(mP[2]) > GPUCA_MAX_SIN_PHI) {
900 ok = 0;
901 }
902 if (!CheckCov()) {
903 ok = false;
904 }
905 return ok;
906}
907
908GPUdii() void GPUTPCGMTrackParam::RefitTrack(GPUTPCGMMergedTrack& GPUrestrict() track, int32_t iTrk, GPUTPCGMMerger* GPUrestrict() merger, int32_t attempt) // VS: GPUd changed to GPUdii. No change in output and no performance penalty.
909{
910 if (!track.OK()) {
911 return;
912 }
913
914 // clang-format off
915 CADEBUG(if (DEBUG_SINGLE_TRACK != -1 && iTrk != ((DEBUG_SINGLE_TRACK == -2 && getenv("DEBUG_TRACK")) ? atoi(getenv("DEBUG_TRACK")) : DEBUG_SINGLE_TRACK)) { track.SetNClusters(0); track.SetOK(0); return; } );
916 // clang-format on
917
918 int32_t nTrackHits = track.NClusters();
919 int32_t NTolerated = 0; // Clusters not fit but tollerated for track length cut
920 GPUTPCGMTrackParam t = track.Param();
921 float Alpha = track.Alpha();
922 CADEBUG(int32_t nTrackHitsOld = nTrackHits; float ptOld = t.QPt());
923 bool ok = t.Fit(merger, iTrk, merger->Clusters() + track.FirstClusterRef(), nTrackHits, NTolerated, Alpha, attempt, GPUCA_MAX_SIN_PHI, track);
924 CADEBUG(printf("Finished Fit Track %d\n", iTrk));
925 CADEBUG(printf("OUTPUT hits %d -> %d+%d = %d, QPt %f -> %f, SP %f, OK %d chi2 %f chi2ndf %f\n", nTrackHitsOld, nTrackHits, NTolerated, nTrackHits + NTolerated, ptOld, t.QPt(), t.SinPhi(), (int32_t)ok, t.Chi2(), t.Chi2() / CAMath::Max(1, nTrackHits)));
926
927 if (!ok && attempt == 0 && merger->Param().rec.tpc.retryRefit) {
928 for (uint32_t i = 0; i < track.NClusters(); i++) {
929 merger->Clusters()[track.FirstClusterRef() + i].state &= GPUTPCGMMergedTrackHit::clustererAndSharedFlags;
930 }
931 CADEBUG(printf("Track rejected, marking for retry\n"));
932 if (merger->Param().rec.tpc.retryRefit == 2) {
933 nTrackHits = track.NClusters();
934 NTolerated = 0; // Clusters not fit but tollerated for track length cut
935 t = track.Param();
936 Alpha = track.Alpha();
937 ok = t.Fit(merger, iTrk, merger->Clusters() + track.FirstClusterRef(), nTrackHits, NTolerated, Alpha, 1, GPUCA_MAX_SIN_PHI, track);
938 } else {
939 uint32_t nRefit = CAMath::AtomicAdd(&merger->Memory()->nRetryRefit, 1u);
940 merger->RetryRefitIds()[nRefit] = iTrk;
941 return;
942 }
943 }
944 if (CAMath::Abs(t.QPt()) < 1.e-4f) {
945 t.QPt() = 1.e-4f;
946 }
947
948 CADEBUG(if (t.GetX() > 250) { printf("ERROR, Track %d at impossible X %f, Pt %f, Looper %d\n", iTrk, t.GetX(), CAMath::Abs(1.f / t.QPt()), (int32_t)merger->MergedTracks()[iTrk].Looper()); });
949
950 track.SetOK(ok);
951 track.SetNClustersFitted(nTrackHits);
952 track.Param() = t;
953 track.Alpha() = Alpha;
954
955 // if (track.OK()) merger->DebugRefitMergedTrack(track);
956}
957
958GPUd() void GPUTPCGMTrackParam::Rotate(float alpha)
959{
960 float cA, sA;
961 CAMath::SinCos(alpha, sA, cA);
962 float x0 = mX;
963 float sinPhi0 = mP[2], cosPhi0 = CAMath::Sqrt(1 - mP[2] * mP[2]);
964 float cosPhi = cosPhi0 * cA + sinPhi0 * sA;
965 float sinPhi = -cosPhi0 * sA + sinPhi0 * cA;
966 float j0 = cosPhi0 / cosPhi;
967 float j2 = cosPhi / cosPhi0;
968 mX = x0 * cA + mP[0] * sA;
969 mP[0] = -x0 * sA + mP[0] * cA;
970 mP[2] = sinPhi;
971 mC[0] *= j0 * j0;
972 mC[1] *= j0;
973 mC[3] *= j0;
974 mC[6] *= j0;
975 mC[10] *= j0;
976
977 mC[3] *= j2;
978 mC[4] *= j2;
979 mC[5] *= j2 * j2;
980 mC[8] *= j2;
981 mC[12] *= j2;
982 if (cosPhi < 0) { // change direction ( t0 direction is already changed in t0.UpdateValues(); )
983 SinPhi() = -SinPhi();
984 DzDs() = -DzDs();
985 QPt() = -QPt();
986 mC[3] = -mC[3];
987 mC[4] = -mC[4];
988 mC[6] = -mC[6];
989 mC[7] = -mC[7];
990 mC[10] = -mC[10];
991 mC[11] = -mC[11];
992 }
993}
994
995GPUd() void GPUTPCGMTrackParam::AddCovDiagErrors(const float* GPUrestrict() errors2)
996{
997 mC[0] += errors2[0];
998 mC[2] += errors2[1];
999 mC[5] += errors2[2];
1000 mC[9] += errors2[3];
1001 mC[14] += errors2[4];
1002}
1003
1004GPUd() void GPUTPCGMTrackParam::AddCovDiagErrorsWithCorrelations(const float* GPUrestrict() errors2)
1005{
1006 const int32_t diagMap[5] = {0, 2, 5, 9, 14};
1007 const float oldDiag[5] = {mC[0], mC[2], mC[5], mC[9], mC[14]};
1008 for (int32_t i = 0; i < 5; i++) {
1009 mC[diagMap[i]] += errors2[i];
1010 for (int32_t j = 0; j < i; j++) {
1011 mC[diagMap[i - 1] + j + 1] *= gpu::CAMath::Sqrt(mC[diagMap[i]] * mC[diagMap[j]] / (oldDiag[i] * oldDiag[j]));
1012 }
1013 }
1014}
benchmark::State & state
Helper class to access correction maps.
int16_t time
Definition RawEventData.h:4
int32_t i
#define GPUdic(...)
#define GPUAtomic(type)
#define GPUrestrict()
#define GPUglobalref()
#define GPUCA_DEBUG_STREAMER_CHECK(...)
#define GPUCA_RTC_CONSTEXPR
#define GPUCA_MAX_SIN_PHI_LOW
#define GPUCA_TRACKLET_SELECTOR_MIN_HITS_B5(QPTB5)
#define GPUCA_MAX_SIN_PHI
#define GPUCA_PAR_NO_ATOMIC_PRECHECK
#define GPUCA_PAR_MERGER_INTERPOLATION_ERROR_TYPE_A
#define CADEBUG(...)
Definition GPUDef.h:72
#define GPUCA_GET_CONSTEXPR(obj, val)
GPUdii() void GPUTPCGMTrackParam
GPUdni() void GPUTPCGMTrackParam
#define DEBUG_SINGLE_TRACK
#define GPUCA_NSECTORS
#define GPUCA_ROW_COUNT
uint32_t j
Definition RawData.h:0
uint32_t res
Definition RawData.h:0
uint32_t c
Definition RawData.h:2
Definition of TPCFastTransform class.
double num
float int32_t const GPUParam int16_t int8_t bool int8_t sector
float int32_t const GPUParam & param
int32_t GPUTPCGMMergedTrackHit int32_t int32_t float & Alpha
int32_t GPUTPCGMMergedTrackHit int32_t int32_t float int32_t float GPUTPCGMMergedTrack & track
int32_t int32_t int32_t bool float Y
GLfloat GLfloat GLfloat alpha
Definition glcorearb.h:279
GLsizei const GLuint const GLfloat * weights
Definition glcorearb.h:5475
GLint GLsizei count
Definition glcorearb.h:399
GLuint * ids
Definition glcorearb.h:647
GLenum array
Definition glcorearb.h:4274
GLdouble GLdouble right
Definition glcorearb.h:4077
GLuint GLuint GLfloat weight
Definition glcorearb.h:5477
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLboolean * data
Definition glcorearb.h:298
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLuint GLfloat x0
Definition glcorearb.h:5034
GLenum clamp
Definition glcorearb.h:1245
GLboolean r
Definition glcorearb.h:1233
GLenum GLfloat param
Definition glcorearb.h:271
GLuint id
Definition glcorearb.h:650
GLuint GLfloat GLfloat y0
Definition glcorearb.h:5034
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
uint32_t calink
Definition GPUTPCDef.h:30
Global TPC definitions and constants.
Definition SimTraits.h:168
GPUd() void PIDResponse
Definition PIDResponse.h:71
GPUdi() T BetheBlochAleph(T bg
value_T step
Definition TrackUtils.h:42
value_T maxT
Definition TrackUtils.h:132
@ streamUpdateTrack
stream update track informations
Defining DataPointCompositeObject explicitly as copiable.
std::string getTime(uint64_t ts)
GPUCA_PAR_MERGER_INTERPOLATION_ERROR_TYPE_A errorY
InterpolationErrorHit hit[GPUCA_MERGER_MAX_TRACK_CLUSTERS]
std::vector< Cluster > clusters
std::vector< int > row