Project
Loading...
Searching...
No Matches
TrackFinderOriginal.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
16
18
19#include <iostream>
20#include <stdexcept>
21
22#include <TGeoGlobalMagField.h>
23#include <TMatrixD.h>
24#include <TMath.h>
25
26#include "Field/MagneticField.h"
27#include "MCHBase/Error.h"
30
31namespace o2
32{
33namespace mch
34{
35
36using namespace std;
37
38constexpr double TrackFinderOriginal::SDefaultChamberZ[10];
39constexpr double TrackFinderOriginal::SChamberThicknessInX0[10];
40
41//_________________________________________________________________________________________________
43{
45
46 // Set the parameters used for fitting the tracks during the tracking
47 const auto& trackerParam = TrackerParam::Instance();
48 mTrackFitter.setBendingVertexDispersion(trackerParam.bendingVertexDispersion);
49 mTrackFitter.setChamberResolution(trackerParam.chamberResolutionX, trackerParam.chamberResolutionY);
50 mTrackFitter.smoothTracks(true);
51
52 // Pre-compute some parameters used during the tracking
53 mChamberResolutionX2 = trackerParam.chamberResolutionX * trackerParam.chamberResolutionX;
54 mChamberResolutionY2 = trackerParam.chamberResolutionY * trackerParam.chamberResolutionY;
55 mBendingVertexDispersion2 = trackerParam.bendingVertexDispersion * trackerParam.bendingVertexDispersion;
56 mMaxChi2ForTracking = 2. * trackerParam.sigmaCutForTracking * trackerParam.sigmaCutForTracking;
57 mMaxChi2ForImprovement = 2. * trackerParam.sigmaCutForImprovement * trackerParam.sigmaCutForImprovement;
58
59 // Set the maximum MCS angle in chamber from the minimum acceptable momentum
61 double inverseBendingP = (SMinBendingMomentum > 0.) ? 1. / SMinBendingMomentum : 1.;
62 param.setInverseBendingMomentum(inverseBendingP);
63 for (int iCh = 0; iCh < 10; ++iCh) {
64 mMaxMCSAngle2[iCh] = TrackExtrap::getMCSAngle2(param, SChamberThicknessInX0[iCh], 1.);
65 }
66}
67
68//_________________________________________________________________________________________________
69void TrackFinderOriginal::initField(float l3Current, float dipoleCurrent)
70{
72 mTrackFitter.initField(l3Current, dipoleCurrent);
73}
74
75//_________________________________________________________________________________________________
76const std::list<Track>& TrackFinderOriginal::findTracks(gsl::span<const Cluster> clusters)
77{
79
80 print("\n------------------ Start the original track finder ------------------");
81 for (auto& clustersInCh : mClusters) {
82 clustersInCh.clear();
83 }
84 mTracks.clear();
85
86 // Group the clusters per chamber
87 for (const auto& cluster : clusters) {
88 mClusters[cluster.getChamberId()].emplace_back(&cluster);
89 }
90
91 // Use the chamber resolution when fitting the tracks during the tracking
92 mTrackFitter.useChamberResolution();
93
94 try {
95
96 // Look for candidates from clusters in stations(1..) 4 and 5
97 print("\n--> Step 1: find track candidates\n");
98 auto tStart = std::chrono::high_resolution_clock::now();
99 findTrackCandidates();
100 auto tEnd = std::chrono::high_resolution_clock::now();
101 mTimeFindCandidates += tEnd - tStart;
102 if (TrackerParam::Instance().moreCandidates) {
103 tStart = std::chrono::high_resolution_clock::now();
104 findMoreTrackCandidates();
105 tEnd = std::chrono::high_resolution_clock::now();
106 mTimeFindMoreCandidates += tEnd - tStart;
107 }
108 mNCandidates += mTracks.size();
109
110 // Stop tracking if no candidate found
111 if (mTracks.empty()) {
112 return mTracks;
113 }
114
115 // Follow tracks in stations(1..) 3, 2 then 1
116 print("\n--> Step 2: Follow track candidates\n");
117 tStart = std::chrono::high_resolution_clock::now();
118 followTracks(mTracks.begin(), mTracks.end(), 2);
119 tEnd = std::chrono::high_resolution_clock::now();
120 mTimeFollowTracks += tEnd - tStart;
121
122 } catch (exception const& e) {
123 LOG(warning) << e.what() << " --> abort";
124 mTracks.clear();
125 return mTracks;
126 }
127
128 // Complete the reconstructed tracks
129 auto tStart = std::chrono::high_resolution_clock::now();
130 if (completeTracks()) {
131 printTracks();
132 removeDuplicateTracks();
133 }
134 auto tEnd = std::chrono::high_resolution_clock::now();
135 mTimeCompleteTracks += tEnd - tStart;
136 print("Currently ", mTracks.size(), " candidates");
137 printTracks();
138
139 // Improve the reconstructed tracks
140 tStart = std::chrono::high_resolution_clock::now();
141 improveTracks();
142 tEnd = std::chrono::high_resolution_clock::now();
143 mTimeImproveTracks += tEnd - tStart;
144 print("Currently ", mTracks.size(), " candidates");
145 printTracks();
146
147 // Remove connected tracks in stations(1..) 3, 4 and 5
148 tStart = std::chrono::high_resolution_clock::now();
149 removeConnectedTracks(3, 4);
150 removeConnectedTracks(2, 2);
151 tEnd = std::chrono::high_resolution_clock::now();
152 mTimeCleanTracks += tEnd - tStart;
153
154 // Refine the tracks using cluster resolution or just finalize them
155 if (TrackerParam::Instance().refineTracks) {
156 tStart = std::chrono::high_resolution_clock::now();
157 mTrackFitter.useClusterResolution();
158 refineTracks();
159 tEnd = std::chrono::high_resolution_clock::now();
160 mTimeRefineTracks += tEnd - tStart;
161 } else {
162 finalize();
163 }
164 printTracks();
165
166 return mTracks;
167}
168
169//_________________________________________________________________________________________________
170void TrackFinderOriginal::findTrackCandidates()
171{
174
175 for (int iSt = 4; iSt >= 3; --iSt) {
176
177 // Find track candidates in the station
178 auto itTrack = findTrackCandidates(2 * iSt, 2 * iSt + 1);
179
180 for (; itTrack != mTracks.end();) {
181
182 // Look for compatible clusters in the other station
183 auto itNewTrack = followTrackInStation(itTrack, 7 - iSt);
184 print("new candidates starting at position #", getTrackIndex(itNewTrack));
185
186 // Keep the current candidate only if no compatible cluster is found and the station is not requested
187 if (!TrackerParam::Instance().requestStation[7 - iSt] && itNewTrack == mTracks.end()) {
188 ++itTrack;
189 } else {
190 print("Removing original candidate now at position #", getTrackIndex(itTrack));
191 printTrackParam(itTrack->first());
192 itTrack = mTracks.erase(itTrack);
193 }
194 }
195
196 print("Currently ", mTracks.size(), " candidates");
197 }
198
199 // Make sure each candidate is unique
200 printTracks();
201 removeDuplicateTracks();
202 printTracks();
203
204 print("Refitting tracks");
205 auto itTrack(mTracks.begin());
206 while (itTrack != mTracks.end()) {
207 try {
208
209 // Refit tracks using the Kalman filter
210 mTrackFitter.fit(*itTrack, false);
211
212 // Make sure they pass the selections
213 if (!isAcceptable(itTrack->first())) {
214 print("Removing candidate at position #", getTrackIndex(itTrack));
215 itTrack = mTracks.erase(itTrack);
216 } else {
217 ++itTrack;
218 }
219 } catch (exception const&) {
220 print("Removing candidate at position #", getTrackIndex(itTrack));
221 itTrack = mTracks.erase(itTrack);
222 }
223 }
224
225 print("Currently ", mTracks.size(), " candidates");
226 printTracks();
227}
228
229//_________________________________________________________________________________________________
230void TrackFinderOriginal::findMoreTrackCandidates()
231{
235
236 // create an iterator to the last track of the list before adding new ones
237 auto itCurrentTrack = mTracks.empty() ? mTracks.end() : std::prev(mTracks.end());
238
239 for (int iCh1 = 6; iCh1 <= 7; ++iCh1) {
240
241 for (int iCh2 = 8; iCh2 <= 9; ++iCh2) {
242
243 // Find track candidates between these 2 chambers
244 auto itTrack = findTrackCandidates(iCh1, iCh2, true);
245
246 for (; itTrack != mTracks.end();) {
247
248 // Look for compatible clusters in the second chamber of station (1..) 5
249 auto itNewTrack = followLinearTrackInChamber(itTrack, 17 - iCh2);
250 print("new candidates starting at position #", getTrackIndex(itNewTrack));
251
252 // Keep the current candidate only if no compatible cluster is found
253 if (itNewTrack == mTracks.end()) {
254 itNewTrack = itTrack;
255 ++itTrack;
256 } else {
257 print("Removing original candidate now at position #", getTrackIndex(itTrack));
258 printTrackParam(itTrack->first());
259 itTrack = mTracks.erase(itTrack);
260 }
261
262 for (; itNewTrack != itTrack;) {
263
264 // Look for compatible clusters in the second chamber of station (1..) 4
265 auto itNewNewTrack = followLinearTrackInChamber(itNewTrack, 13 - iCh1);
266 print("new candidates starting at position #", getTrackIndex(itNewNewTrack));
267
268 // Keep the current candidate only if no compatible cluster is found
269 if (itNewNewTrack == mTracks.end()) {
270 ++itNewTrack;
271 } else {
272 print("Removing original candidate now at position #", getTrackIndex(itNewTrack));
273 printTrackParam(itTrack->first());
274 itNewTrack = mTracks.erase(itNewTrack);
275 }
276 }
277 }
278
279 print("Currently ", mTracks.size(), " candidates");
280 }
281 }
282
283 print("Refitting tracks");
284 itCurrentTrack = (itCurrentTrack == mTracks.end()) ? mTracks.begin() : ++itCurrentTrack;
285 while (itCurrentTrack != mTracks.end()) {
286 try {
287
288 // Refit tracks using the Kalman filter
289 mTrackFitter.fit(*itCurrentTrack, false);
290
291 // Make sure they pass the selections
292 if (!isAcceptable(itCurrentTrack->first())) {
293 print("Removing candidate at position #", getTrackIndex(itCurrentTrack));
294 itCurrentTrack = mTracks.erase(itCurrentTrack);
295 } else {
296 ++itCurrentTrack;
297 }
298 } catch (exception const&) {
299 print("Removing candidate at position #", getTrackIndex(itCurrentTrack));
300 itCurrentTrack = mTracks.erase(itCurrentTrack);
301 }
302 }
303
304 print("Currently ", mTracks.size(), " candidates");
305 printTracks();
306}
307
308//_________________________________________________________________________________________________
309std::list<Track>::iterator TrackFinderOriginal::findTrackCandidates(int ch1, int ch2, bool skipUsedPairs)
310{
315
316 print("Looking for candidates between chamber ", ch1, " and ", ch2);
317
318 const auto& trackerParam = TrackerParam::Instance();
319
320 // maximum impact parameter dispersion**2 due to MCS in chambers
321 double impactMCS2(0.);
322 for (int iCh = 0; iCh <= ch1; ++iCh) {
323 impactMCS2 += SDefaultChamberZ[iCh] * SDefaultChamberZ[iCh] * mMaxMCSAngle2[iCh];
324 }
325
326 // create an iterator to the last track of the list before adding new ones
327 auto itTrack = mTracks.empty() ? mTracks.end() : std::prev(mTracks.end());
328
329 for (const auto cluster1 : mClusters.at(ch1)) {
330
331 double z1 = cluster1->getZ();
332
333 for (const auto cluster2 : mClusters.at(ch2)) {
334
335 // skip combinations of clusters already part of a track if requested
336 if (skipUsedPairs && areUsed(*cluster1, *cluster2)) {
337 continue;
338 }
339
340 double z2 = cluster2->getZ();
341 double dZ = z1 - z2;
342
343 // check if non bending impact parameter is within tolerances
344 double nonBendingSlope = (cluster1->getX() - cluster2->getX()) / dZ;
345 double nonBendingImpactParam = TMath::Abs(cluster1->getX() - cluster1->getZ() * nonBendingSlope);
346 double nonBendingImpactParamErr = TMath::Sqrt((z1 * z1 * mChamberResolutionX2 + z2 * z2 * mChamberResolutionX2) / dZ / dZ + impactMCS2);
347 if ((nonBendingImpactParam - trackerParam.sigmaCutForTracking * nonBendingImpactParamErr) > (3. * trackerParam.nonBendingVertexDispersion)) {
348 continue;
349 }
350
351 double bendingSlope = (cluster1->getY() - cluster2->getY()) / dZ;
352 if (TrackExtrap::isFieldON()) { // depending whether the field is ON or OFF
353 // check if bending momentum is within tolerances
354 double bendingImpactParam = cluster1->getY() - cluster1->getZ() * bendingSlope;
355 double bendingImpactParamErr2 = (z1 * z1 * mChamberResolutionY2 + z2 * z2 * mChamberResolutionY2) / dZ / dZ + impactMCS2;
356 double bendingMomentum = TMath::Abs(TrackExtrap::getBendingMomentumFromImpactParam(bendingImpactParam));
357 double bendingMomentumErr = TMath::Sqrt((mBendingVertexDispersion2 + bendingImpactParamErr2) / bendingImpactParam / bendingImpactParam + 0.01) * bendingMomentum;
358 if ((bendingMomentum + 3. * bendingMomentumErr) < SMinBendingMomentum) {
359 continue;
360 }
361 } else {
362 // or check if bending impact parameter is within tolerances
363 double bendingImpactParam = TMath::Abs(cluster1->getY() - cluster1->getZ() * bendingSlope);
364 double bendingImpactParamErr = TMath::Sqrt((z1 * z1 * mChamberResolutionY2 + z2 * z2 * mChamberResolutionY2) / dZ / dZ + impactMCS2);
365 if ((bendingImpactParam - trackerParam.sigmaCutForTracking * bendingImpactParamErr) > (3. * trackerParam.bendingVertexDispersion)) {
366 continue;
367 }
368 }
369
370 // create a new track candidate
371 createTrack(*cluster1, *cluster2);
372 }
373 }
374
375 print("Currently ", mTracks.size(), " candidates");
376
377 return (itTrack == mTracks.end()) ? mTracks.begin() : ++itTrack;
378}
379
380//_________________________________________________________________________________________________
381bool TrackFinderOriginal::areUsed(const Cluster& cl1, const Cluster& cl2)
382{
384
385 for (const auto& track : mTracks) {
386
387 bool cl1Used(false), cl2Used(false);
388
389 for (auto itParam = track.rbegin(); itParam != track.rend(); ++itParam) {
390
391 if (itParam->getClusterPtr() == &cl1) {
392 cl1Used = true;
393 } else if (itParam->getClusterPtr() == &cl2) {
394 cl2Used = true;
395 }
396
397 if (cl1Used && cl2Used) {
398 return true;
399 }
400 }
401 }
402
403 return false;
404}
405
406//_________________________________________________________________________________________________
407void TrackFinderOriginal::createTrack(const Cluster& cl1, const Cluster& cl2)
408{
412
413 if (mTracks.size() >= TrackerParam::Instance().maxCandidates) {
415 throw length_error(string("Too many track candidates (") + mTracks.size() + ")");
416 }
417
418 print("Creating a new candidate");
419
420 // create the track and the trackParam at each cluster
421 mTracks.emplace_back();
422 TrackParam& param2 = mTracks.back().createParamAtCluster(cl2);
423 TrackParam& param1 = mTracks.back().createParamAtCluster(cl1);
424
425 // Compute track parameters
426 double dZ = cl1.getZ() - cl2.getZ();
427 double nonBendingSlope = (cl1.getX() - cl2.getX()) / dZ;
428 double bendingSlope = (cl1.getY() - cl2.getY()) / dZ;
429 double bendingImpact = cl1.getY() - cl1.getZ() * bendingSlope;
430 double inverseBendingMomentum = 1. / TrackExtrap::getBendingMomentumFromImpactParam(bendingImpact);
431
432 // Set track parameters at first cluster
433 param1.setNonBendingCoor(cl1.getX());
434 param1.setNonBendingSlope(nonBendingSlope);
435 param1.setBendingCoor(cl1.getY());
436 param1.setBendingSlope(bendingSlope);
437 param1.setInverseBendingMomentum(inverseBendingMomentum);
438
439 // Set track parameters at last cluster
440 param2.setNonBendingCoor(cl2.getX());
441 param2.setNonBendingSlope(nonBendingSlope);
442 param2.setBendingCoor(cl2.getY());
443 param2.setBendingSlope(bendingSlope);
444 param2.setInverseBendingMomentum(inverseBendingMomentum);
445
446 // Compute and set track parameters covariances at first cluster
447 TMatrixD paramCov(5, 5);
448 paramCov.Zero();
449 // Non bending plane
450 double cl1Ex2 = mChamberResolutionX2;
451 double cl2Ex2 = mChamberResolutionX2;
452 paramCov(0, 0) = cl1Ex2;
453 paramCov(0, 1) = cl1Ex2 / dZ;
454 paramCov(1, 0) = paramCov(0, 1);
455 paramCov(1, 1) = (cl1Ex2 + cl2Ex2) / dZ / dZ;
456 // Bending plane
457 double cl1Ey2 = mChamberResolutionY2;
458 double cl2Ey2 = mChamberResolutionY2;
459 paramCov(2, 2) = cl1Ey2;
460 paramCov(2, 3) = cl1Ey2 / dZ;
461 paramCov(3, 2) = paramCov(2, 3);
462 paramCov(3, 3) = (cl1Ey2 + cl2Ey2) / dZ / dZ;
463 // Inverse bending momentum (vertex resolution + bending slope resolution + 10% error on dipole parameters+field)
465 paramCov(4, 4) = ((mBendingVertexDispersion2 +
466 (cl1.getZ() * cl1.getZ() * cl2Ey2 + cl2.getZ() * cl2.getZ() * cl1Ey2) / dZ / dZ) /
467 bendingImpact / bendingImpact +
468 0.1 * 0.1) *
469 inverseBendingMomentum * inverseBendingMomentum;
470 paramCov(2, 4) = -cl2.getZ() * cl1Ey2 * inverseBendingMomentum / bendingImpact / dZ;
471 paramCov(4, 2) = paramCov(2, 4);
472 paramCov(3, 4) = -(cl1.getZ() * cl2Ey2 + cl2.getZ() * cl1Ey2) * inverseBendingMomentum / bendingImpact / dZ / dZ;
473 paramCov(4, 3) = paramCov(3, 4);
474 } else {
475 paramCov(4, 4) = inverseBendingMomentum * inverseBendingMomentum;
476 }
477 param1.setCovariances(paramCov);
478
479 // Compute and set track parameters covariances at last cluster
480 // Non bending plane
481 paramCov(0, 0) = cl2Ex2;
482 paramCov(0, 1) = -cl2Ex2 / dZ;
483 paramCov(1, 0) = paramCov(0, 1);
484 // Bending plane
485 paramCov(2, 2) = cl2Ey2;
486 paramCov(2, 3) = -cl2Ey2 / dZ;
487 paramCov(3, 2) = paramCov(2, 3);
488 // Inverse bending momentum (vertex resolution + bending slope resolution + 10% error on dipole parameters+field)
490 paramCov(2, 4) = cl1.getZ() * cl2Ey2 * inverseBendingMomentum / bendingImpact / dZ;
491 paramCov(4, 2) = paramCov(2, 4);
492 }
493 param2.setCovariances(paramCov);
494
495 printTrackParam(param1);
496}
497
498//_________________________________________________________________________________________________
499std::list<Track>::iterator TrackFinderOriginal::addTrack(const std::list<Track>::iterator& pos, const Track& track)
500{
503 if (mTracks.size() >= TrackerParam::Instance().maxCandidates) {
505 throw length_error(string("Too many track candidates (") + mTracks.size() + ")");
506 }
507 return mTracks.emplace(pos, track);
508}
509
510//_________________________________________________________________________________________________
511bool TrackFinderOriginal::isAcceptable(const TrackParam& param) const
512{
514
515 const auto& trackerParam = TrackerParam::Instance();
516 const TMatrixD& paramCov = param.getCovariances();
517 int chamber = param.getClusterPtr()->getChamberId();
518 double z = param.getZ();
519
520 // impact parameter dispersion**2 due to MCS in chambers
521 double impactMCS2(0.);
522 if (TrackExtrap::isFieldON() && chamber < 6) {
523 // track momentum is known
524 for (int iCh = 0; iCh <= chamber; ++iCh) {
525 impactMCS2 += SDefaultChamberZ[iCh] * SDefaultChamberZ[iCh] * TrackExtrap::getMCSAngle2(param, SChamberThicknessInX0[iCh], 1.);
526 }
527 } else {
528 // track momentum is unknown
529 for (Int_t iCh = 0; iCh <= chamber; ++iCh) {
530 impactMCS2 += SDefaultChamberZ[iCh] * SDefaultChamberZ[iCh] * mMaxMCSAngle2[iCh];
531 }
532 }
533
534 // check if non bending impact parameter is within tolerances
535 double nonBendingImpactParam = TMath::Abs(param.getNonBendingCoor() - z * param.getNonBendingSlope());
536 double nonBendingImpactParamErr = TMath::Sqrt(paramCov(0, 0) + z * z * paramCov(1, 1) - 2. * z * paramCov(0, 1) + impactMCS2);
537 if ((nonBendingImpactParam - trackerParam.sigmaCutForTracking * nonBendingImpactParamErr) > (3. * trackerParam.nonBendingVertexDispersion)) {
538 return false;
539 }
540
541 if (TrackExtrap::isFieldON()) { // depending whether the field is ON or OFF
542 // check if bending momentum is within tolerances
543 double bendingMomentum = TMath::Abs(1. / param.getInverseBendingMomentum());
544 double bendingMomentumErr = TMath::Sqrt(paramCov(4, 4)) * bendingMomentum * bendingMomentum;
545 if (chamber < 6 && (bendingMomentum + trackerParam.sigmaCutForTracking * bendingMomentumErr) < SMinBendingMomentum) {
546 return false;
547 } else if ((bendingMomentum + 3. * bendingMomentumErr) < SMinBendingMomentum) {
548 return false;
549 }
550 } else {
551 // or check if bending impact parameter is within tolerances
552 double bendingImpactParam = TMath::Abs(param.getBendingCoor() - z * param.getBendingSlope());
553 double bendingImpactParamErr = TMath::Sqrt(paramCov(2, 2) + z * z * paramCov(3, 3) - 2. * z * paramCov(2, 3) + impactMCS2);
554 if ((bendingImpactParam - trackerParam.sigmaCutForTracking * bendingImpactParamErr) > (3. * trackerParam.bendingVertexDispersion)) {
555 return false;
556 }
557 }
558
559 return true;
560}
561
562//_________________________________________________________________________________________________
563void TrackFinderOriginal::removeDuplicateTracks()
564{
567
568 print("Remove duplicated tracks");
569
570 for (auto itTrack1 = mTracks.begin(); itTrack1 != mTracks.end();) {
571
572 int nClusters1 = itTrack1->getNClusters();
573 bool track1Removed(false);
574
575 for (auto itTrack2 = std::next(itTrack1); itTrack2 != mTracks.end();) {
576
577 int nClusters2 = itTrack2->getNClusters();
578 int nClustersInCommon = itTrack2->getNClustersInCommon(*itTrack1);
579
580 if (nClustersInCommon == nClusters2) {
581 print("Removing candidate at position #", getTrackIndex(itTrack2));
582 itTrack2 = mTracks.erase(itTrack2);
583 } else if (nClustersInCommon == nClusters1) {
584 print("Removing candidate at position #", getTrackIndex(itTrack1));
585 itTrack1 = mTracks.erase(itTrack1);
586 track1Removed = true;
587 break;
588 } else {
589 ++itTrack2;
590 }
591 }
592
593 if (!track1Removed) {
594 ++itTrack1;
595 }
596 }
597
598 print("Currently ", mTracks.size(), " candidates");
599}
600
601//_________________________________________________________________________________________________
602void TrackFinderOriginal::removeConnectedTracks(int stMin, int stMax)
603{
607
608 print("Remove connected tracks in stations [", stMin, ", ", stMax, "]");
609
610 // first loop to tag the tracks to remove...
611 for (auto itTrack1 = mTracks.begin(); itTrack1 != mTracks.end(); ++itTrack1) {
612 for (auto itTrack2 = std::next(itTrack1); itTrack2 != mTracks.end(); ++itTrack2) {
613 if (itTrack2->getNClustersInCommon(*itTrack1, stMin, stMax) > 0) {
614 if (itTrack2->isBetter(*itTrack1)) {
615 itTrack1->connected();
616 } else {
617 itTrack2->connected();
618 }
619 }
620 }
621 }
622
623 // ...then remove them. That way all combinations are tested.
624 for (auto itTrack = mTracks.begin(); itTrack != mTracks.end();) {
625 if (itTrack->isConnected()) {
626 print("Removing candidate at position #", getTrackIndex(itTrack));
627 itTrack = mTracks.erase(itTrack);
628 } else {
629 ++itTrack;
630 }
631 }
632
633 print("Currently ", mTracks.size(), " candidates");
634}
635
636//_________________________________________________________________________________________________
637void TrackFinderOriginal::followTracks(const std::list<Track>::iterator& itTrackBegin,
638 const std::list<Track>::iterator& itTrackEnd, int nextStation)
639{
644
645 print("Follow track candidates #", getTrackIndex(itTrackBegin), " to #", getTrackIndex(std::prev(itTrackEnd)), " in station ", nextStation);
646
647 for (auto itTrack = itTrackBegin; itTrack != itTrackEnd;) {
648
649 // Look for compatible clusters in the next station
650 auto itNewTrack = followTrackInStation(itTrack, nextStation);
651
652 // Try to recover the track if no compatible cluster is found
653 if (itNewTrack == mTracks.end()) {
654
655 // Keep the case where no cluster is found as a possible candidate if the next station is not requested
656 if (!TrackerParam::Instance().requestStation[nextStation]) {
657 print("Duplicate original candidate");
658 itTrack = addTrack(itTrack, *itTrack);
659 }
660
661 // Try to recover
662 itNewTrack = recoverTrack(itTrack, nextStation);
663
664 // Remove the initial candidate or its copy
665 print("Removing original candidate or its copy at position #", getTrackIndex(itTrack));
666 printTrackParam(itTrack->first());
667 itTrack = mTracks.erase(itTrack);
668
669 // If the next station is not requested, we can at minimum continue with the initial candidate
670 if (!TrackerParam::Instance().requestStation[nextStation]) {
671 if (itNewTrack == mTracks.end()) {
672 itNewTrack = itTrack;
673 }
674 ++itTrack;
675 }
676
677 } else {
678
679 // Or remove the initial candidate if new candidates have been produced
680 print("Removing original candidate now at position #", getTrackIndex(itTrack));
681 printTrackParam(itTrack->first());
682 itTrack = mTracks.erase(itTrack);
683 }
684
685 print("Currently ", mTracks.size(), " candidates");
686 printTracks();
687
688 // follow the new candidates, if any, down to the first station
689 if (itNewTrack != mTracks.end() && nextStation != 0) {
690 followTracks(itNewTrack, itTrack, nextStation - 1);
691 }
692 }
693}
694
695//_________________________________________________________________________________________________
696std::list<Track>::iterator TrackFinderOriginal::followTrackInStation(const std::list<Track>::iterator& itTrack, int nextStation)
697{
702
703 print("Follow track candidate #", getTrackIndex(itTrack), " in station ", nextStation);
704 printTrackParam(itTrack->first());
705
706 auto itNewTrack(itTrack);
707 TrackParam extrapTrackParamAtCluster1{};
708 TrackParam extrapTrackParamAtCluster2{};
709 TrackParam extrapTrackParam{};
710
711 // Order the chambers according to the propagation direction (tracking starts with ch2):
712 // - nextStation == station(1...) 5 => forward propagation
713 // - nextStation < station(1...) 5 => backward propagation
714 int ch1(0), ch2(0);
715 if (nextStation == 4) {
716 ch1 = 2 * nextStation + 1;
717 ch2 = 2 * nextStation;
718 } else {
719 ch1 = 2 * nextStation;
720 ch2 = 2 * nextStation + 1;
721 }
722
723 // Get the current track parameters according to the propagation direction
724 TrackParam extrapTrackParamAtCh = (nextStation == 4) ? itTrack->last() : itTrack->first();
725
726 // Add MCS effects in the current chamber
727 int currentChamber(extrapTrackParamAtCh.getClusterPtr()->getChamberId());
728 TrackExtrap::addMCSEffect(extrapTrackParamAtCh, SChamberThicknessInX0[currentChamber], -1.);
729
730 // Reset the propagator for the smoother
731 if (mTrackFitter.isSmootherEnabled()) {
732 extrapTrackParamAtCh.resetPropagator();
733 }
734
735 // Add MCS effects in the missing chamber(s) if any
736 while (ch1 < ch2 && currentChamber > ch2 + 1) {
737 --currentChamber;
738 if (!TrackExtrap::extrapToZCov(extrapTrackParamAtCh, SDefaultChamberZ[currentChamber],
739 mTrackFitter.isSmootherEnabled())) {
740 return mTracks.end();
741 }
742 TrackExtrap::addMCSEffect(extrapTrackParamAtCh, SChamberThicknessInX0[currentChamber], -1.);
743 }
744
745 // Extrapolate the track candidate to chamber 2
746 if (!TrackExtrap::extrapToZCov(extrapTrackParamAtCh, SDefaultChamberZ[ch2], mTrackFitter.isSmootherEnabled())) {
747 return mTracks.end();
748 }
749
750 // Prepare to remember the clusters used in ch1 in combination with a cluster in ch2
751 std::vector<bool> clusterCh1Used(mClusters.at(ch1).size(), false);
752
753 // Look for cluster candidates in chamber 2
754 for (const auto clusterCh2 : mClusters.at(ch2)) {
755
756 // Fast try to add the current cluster
757 if (!tryOneClusterFast(extrapTrackParamAtCh, *clusterCh2)) {
758 continue;
759 }
760
761 // Try to add the current cluster accurately
762 if (tryOneCluster(extrapTrackParamAtCh, *clusterCh2, extrapTrackParamAtCluster2,
763 mTrackFitter.isSmootherEnabled()) >= mMaxChi2ForTracking) {
764 continue;
765 }
766
767 // Save the extrapolated parameters and covariances for the smoother
768 if (mTrackFitter.isSmootherEnabled()) {
769 extrapTrackParamAtCluster2.setExtrapParameters(extrapTrackParamAtCluster2.getParameters());
770 extrapTrackParamAtCluster2.setExtrapCovariances(extrapTrackParamAtCluster2.getCovariances());
771 }
772
773 // Compute the new track parameters including clusterCh2 using the Kalman filter
774 try {
775 mTrackFitter.runKalmanFilter(extrapTrackParamAtCluster2);
776 } catch (exception const&) {
777 continue;
778 }
779
780 // skip tracks out of limits
781 if (!isAcceptable(extrapTrackParamAtCluster2)) {
782 continue;
783 }
784
785 // copy the new track parameters for the next step and add MCS effects in chamber 2
786 extrapTrackParam = extrapTrackParamAtCluster2;
787 TrackExtrap::addMCSEffect(extrapTrackParam, SChamberThicknessInX0[ch2], -1.);
788
789 // Reset the propagator for the smoother
790 if (mTrackFitter.isSmootherEnabled()) {
791 extrapTrackParam.resetPropagator();
792 }
793
794 // Extrapolate the track candidate to chamber 1
795 bool foundSecondCluster(false);
796 if (TrackExtrap::extrapToZCov(extrapTrackParam, SDefaultChamberZ[ch1], mTrackFitter.isSmootherEnabled())) {
797
798 // look for second cluster candidates in chamber 1
799 int iCluster1(-1);
800 for (const auto clusterCh1 : mClusters.at(ch1)) {
801
802 ++iCluster1;
803
804 // Fast try to add the current cluster
805 if (!tryOneClusterFast(extrapTrackParam, *clusterCh1)) {
806 continue;
807 }
808
809 // Try to add the current cluster accurately
810 if (tryOneCluster(extrapTrackParam, *clusterCh1, extrapTrackParamAtCluster1,
811 mTrackFitter.isSmootherEnabled()) >= mMaxChi2ForTracking) {
812 continue;
813 }
814
815 // Save the extrapolated parameters and covariances for the smoother
816 if (mTrackFitter.isSmootherEnabled()) {
817 extrapTrackParamAtCluster1.setExtrapParameters(extrapTrackParamAtCluster1.getParameters());
818 extrapTrackParamAtCluster1.setExtrapCovariances(extrapTrackParamAtCluster1.getCovariances());
819 }
820
821 // Compute the new track parameters including clusterCh1 using the Kalman filter
822 try {
823 mTrackFitter.runKalmanFilter(extrapTrackParamAtCluster1);
824 } catch (exception const&) {
825 continue;
826 }
827
828 // Skip tracks out of limits
829 if (!isAcceptable(extrapTrackParamAtCluster1)) {
830 continue;
831 }
832
833 // Copy the initial candidate into a new track with these 2 clusters added
834 print("Duplicate the candidate");
835 itNewTrack = addTrack(itNewTrack, *itTrack);
836 updateTrack(*itNewTrack, extrapTrackParamAtCluster1, extrapTrackParamAtCluster2);
837
838 // Tag clusterCh1 as used
839 clusterCh1Used[iCluster1] = true;
840 foundSecondCluster = true;
841 }
842 }
843
844 // If no clusterCh1 found then copy the initial candidate into a new track with only clusterCh2 added
845 if (!foundSecondCluster) {
846 print("Duplicate the candidate");
847 itNewTrack = addTrack(itNewTrack, *itTrack);
848 updateTrack(*itNewTrack, extrapTrackParamAtCluster2);
849 }
850 }
851
852 // Add MCS effects in chamber 2
853 TrackExtrap::addMCSEffect(extrapTrackParamAtCh, SChamberThicknessInX0[ch2], -1.);
854
855 // Extrapolate the track candidate to chamber 1
856 if (!TrackExtrap::extrapToZCov(extrapTrackParamAtCh, SDefaultChamberZ[ch1], mTrackFitter.isSmootherEnabled())) {
857 return (itNewTrack == itTrack) ? mTracks.end() : itNewTrack;
858 }
859
860 // look for cluster candidates not already used in chamber 1
861 int iCluster1(-1);
862 for (const auto clusterCh1 : mClusters.at(ch1)) {
863
864 ++iCluster1;
865 if (clusterCh1Used[iCluster1]) {
866 continue;
867 }
868
869 // Fast try to add the current cluster
870 if (!tryOneClusterFast(extrapTrackParamAtCh, *clusterCh1)) {
871 continue;
872 }
873
874 // Try to add the current cluster accurately
875 if (tryOneCluster(extrapTrackParamAtCh, *clusterCh1, extrapTrackParamAtCluster1,
876 mTrackFitter.isSmootherEnabled()) >= mMaxChi2ForTracking) {
877 continue;
878 }
879
880 // Save the extrapolated parameters and covariances for the smoother
881 if (mTrackFitter.isSmootherEnabled()) {
882 extrapTrackParamAtCluster1.setExtrapParameters(extrapTrackParamAtCluster1.getParameters());
883 extrapTrackParamAtCluster1.setExtrapCovariances(extrapTrackParamAtCluster1.getCovariances());
884 }
885
886 // Compute the new track parameters including clusterCh1 using the Kalman filter
887 try {
888 mTrackFitter.runKalmanFilter(extrapTrackParamAtCluster1);
889 } catch (exception const&) {
890 continue;
891 }
892
893 // Skip tracks out of limits
894 if (!isAcceptable(extrapTrackParamAtCluster1)) {
895 continue;
896 }
897
898 // Copy the initial candidate into a new track with clusterCh1 added
899 print("Duplicate the candidate");
900 itNewTrack = addTrack(itNewTrack, *itTrack);
901 updateTrack(*itNewTrack, extrapTrackParamAtCluster1);
902 }
903
904 return (itNewTrack == itTrack) ? mTracks.end() : itNewTrack;
905}
906
907//_________________________________________________________________________________________________
908std::list<Track>::iterator TrackFinderOriginal::followLinearTrackInChamber(const std::list<Track>::iterator& itTrack, int nextChamber)
909{
915
916 print("Follow track candidate #", getTrackIndex(itTrack), " in chamber ", nextChamber);
917 printTrackParam(itTrack->first());
918
919 auto itNewTrack(itTrack);
920 TrackParam extrapTrackParamAtCluster{};
921
922 // Get the current track parameters according to the propagation direction
923 TrackParam trackParam = (nextChamber > 7) ? itTrack->last() : itTrack->first();
924
925 // Add MCS effects in the current chamber
926 TrackExtrap::addMCSEffect(trackParam, SChamberThicknessInX0[trackParam.getClusterPtr()->getChamberId()], -1.);
927
928 // Look for cluster candidates in the next chamber
929 for (const auto cluster : mClusters.at(nextChamber)) {
930
931 // Fast try to add the current cluster
932 if (!tryOneClusterFast(trackParam, *cluster)) {
933 continue;
934 }
935
936 // propagate linearly the track to the z position of the current cluster
937 extrapTrackParamAtCluster = trackParam;
938 TrackExtrap::linearExtrapToZCov(extrapTrackParamAtCluster, cluster->getZ());
939
940 // Try to add the current cluster accurately
941 if (tryOneCluster(extrapTrackParamAtCluster, *cluster, extrapTrackParamAtCluster, false) >= mMaxChi2ForTracking) {
942 continue;
943 }
944
945 // Copy the initial candidate into a new track with cluster added
946 print("Duplicate the candidate");
947 itNewTrack = addTrack(itNewTrack, *itTrack);
948 updateTrack(*itNewTrack, extrapTrackParamAtCluster);
949 }
950
951 return (itNewTrack == itTrack) ? mTracks.end() : itNewTrack;
952}
953
954//_________________________________________________________________________________________________
955bool TrackFinderOriginal::tryOneClusterFast(const TrackParam& param, const Cluster& cluster)
956{
961
962 ++mNCallTryOneClusterFast;
963
964 double dZ = cluster.getZ() - param.getZ();
965 double dX = cluster.getX() - (param.getNonBendingCoor() + param.getNonBendingSlope() * dZ);
966 double dY = cluster.getY() - (param.getBendingCoor() + param.getBendingSlope() * dZ);
967 const TMatrixD& paramCov = param.getCovariances();
968 double errX2 = paramCov(0, 0) + dZ * dZ * paramCov(1, 1) + 2. * dZ * paramCov(0, 1) + mChamberResolutionX2;
969 double errY2 = paramCov(2, 2) + dZ * dZ * paramCov(3, 3) + 2. * dZ * paramCov(2, 3) + mChamberResolutionY2;
970
971 double dXmax = TrackerParam::Instance().sigmaCutForTracking * TMath::Sqrt(2. * errX2) + SMaxNonBendingDistanceToTrack;
972 double dYmax = TrackerParam::Instance().sigmaCutForTracking * TMath::Sqrt(2. * errY2) + SMaxBendingDistanceToTrack;
973
974 if (TMath::Abs(dX) > dXmax || TMath::Abs(dY) > dYmax) {
975 return false;
976 }
977 return true;
978}
979
980//_________________________________________________________________________________________________
981double TrackFinderOriginal::tryOneCluster(const TrackParam& param, const Cluster& cluster, TrackParam& paramAtCluster,
982 bool updatePropagator)
983{
988
989 ++mNCallTryOneCluster;
990
991 // Extrapolate the track parameters and covariances at the z position of the cluster
992 paramAtCluster = param;
993 paramAtCluster.setClusterPtr(&cluster);
994 if (!TrackExtrap::extrapToZCov(paramAtCluster, cluster.getZ(), updatePropagator)) {
995 return mTrackFitter.getMaxChi2();
996 }
997
998 // Compute the cluster-track residuals in bending and non bending directions
999 double dX = cluster.getX() - paramAtCluster.getNonBendingCoor();
1000 double dY = cluster.getY() - paramAtCluster.getBendingCoor();
1001
1002 // Combine the cluster and track resolutions and covariances
1003 const TMatrixD& paramCov = paramAtCluster.getCovariances();
1004 double sigmaX2 = paramCov(0, 0) + mChamberResolutionX2;
1005 double sigmaY2 = paramCov(2, 2) + mChamberResolutionY2;
1006 double covXY = paramCov(0, 2);
1007 double det = sigmaX2 * sigmaY2 - covXY * covXY;
1008
1009 // Compute and return the matching chi2
1010 if (det == 0.) {
1011 return mTrackFitter.getMaxChi2();
1012 }
1013 return (dX * dX * sigmaY2 + dY * dY * sigmaX2 - 2. * dX * dY * covXY) / det;
1014}
1015
1016//_________________________________________________________________________________________________
1017void TrackFinderOriginal::updateTrack(Track& track, TrackParam& trackParamAtCluster)
1018{
1020
1021 // Flag the cluster as being (not) removable
1022 if (TrackerParam::Instance().requestStation[trackParamAtCluster.getClusterPtr()->getChamberId() / 2]) {
1023 trackParamAtCluster.setRemovable(false);
1024 } else {
1025 trackParamAtCluster.setRemovable(true);
1026 }
1027
1028 // No need to compute the chi2 in this case, just set it to minimum possible value
1029 trackParamAtCluster.setLocalChi2(0.);
1030
1031 // Add the parameters at the new cluster
1032 track.addParamAtCluster(trackParamAtCluster);
1033}
1034
1035//_________________________________________________________________________________________________
1036void TrackFinderOriginal::updateTrack(Track& track, TrackParam& trackParamAtCluster1, TrackParam& trackParamAtCluster2)
1037{
1040
1041 // Flag the clusters as being removable
1042 trackParamAtCluster1.setRemovable(true);
1043 trackParamAtCluster2.setRemovable(true);
1044
1045 // Compute the local chi2 at cluster1
1046 const Cluster* cluster1(trackParamAtCluster1.getClusterPtr());
1047 double deltaX = trackParamAtCluster1.getNonBendingCoor() - cluster1->getX();
1048 double deltaY = trackParamAtCluster1.getBendingCoor() - cluster1->getY();
1049 double localChi2 = deltaX * deltaX / mChamberResolutionX2 + deltaY * deltaY / mChamberResolutionY2;
1050 trackParamAtCluster1.setLocalChi2(localChi2);
1051
1052 // Compute the local chi2 at cluster2
1053 const Cluster* cluster2(trackParamAtCluster2.getClusterPtr());
1054 TrackParam extrapTrackParamAtCluster2(trackParamAtCluster1);
1055 TrackExtrap::extrapToZ(extrapTrackParamAtCluster2, trackParamAtCluster2.getZ());
1056 deltaX = extrapTrackParamAtCluster2.getNonBendingCoor() - cluster2->getX();
1057 deltaY = extrapTrackParamAtCluster2.getBendingCoor() - cluster2->getY();
1058 localChi2 = deltaX * deltaX / mChamberResolutionX2 + deltaY * deltaY / mChamberResolutionY2;
1059 trackParamAtCluster2.setLocalChi2(localChi2);
1060
1061 // Add the parameters at the new clusters
1062 track.addParamAtCluster(trackParamAtCluster2);
1063 track.addParamAtCluster(trackParamAtCluster1);
1064}
1065
1066//_________________________________________________________________________________________________
1067std::list<Track>::iterator TrackFinderOriginal::recoverTrack(std::list<Track>::iterator& itTrack, int nextStation)
1068{
1073
1074 // Do not try to recover track until we have attached cluster(s) on station(1..) 3
1075 if (nextStation > 1) {
1076 return mTracks.end();
1077 }
1078
1079 print("Try to recover the track candidate #", getTrackIndex(itTrack), " in station ", nextStation);
1080
1081 // Look for the cluster to remove
1082 auto itWorstParam = itTrack->end();
1083 double worstLocalChi2(-1.);
1084 for (auto itParam = itTrack->begin(); itParam != itTrack->end(); ++itParam) {
1085
1086 // Check if the current cluster is in the previous station
1087 if (itParam->getClusterPtr()->getChamberId() / 2 != nextStation + 1) {
1088 break;
1089 }
1090
1091 // Check if the current cluster is removable
1092 if (!itParam->isRemovable()) {
1093 return mTracks.end();
1094 }
1095
1096 // Reset the current cluster as being not removable if it is on a requested station
1097 if (TrackerParam::Instance().requestStation[nextStation + 1]) {
1098 itParam->setRemovable(false);
1099 }
1100
1101 // Pick up the cluster with the worst chi2
1102 if (itParam->getLocalChi2() > worstLocalChi2) {
1103 worstLocalChi2 = itParam->getLocalChi2();
1104 itWorstParam = itParam;
1105 }
1106 }
1107
1108 // Check if the cluster to remove has been found
1109 if (itWorstParam == itTrack->end()) {
1110 return mTracks.end();
1111 }
1112
1113 // Remove the worst cluster
1114 itTrack->removeParamAtCluster(itWorstParam);
1115
1116 // Recompute the track parameters at the first cluster from the second, as currently done in AliRoot
1117 try {
1118 auto itParam = std::next(itTrack->begin());
1119 auto ritParam = std::make_reverse_iterator(++itParam);
1120 mTrackFitter.fit(*itTrack, false, false, &ritParam);
1121 } catch (exception const&) {
1122 return mTracks.end();
1123 }
1124 // Skip tracks out of limits
1125 if (!isAcceptable(itTrack->first())) {
1126 return mTracks.end();
1127 }
1128
1129 // Look for new cluster(s) in the next station
1130 return followTrackInStation(itTrack, nextStation);
1131}
1132
1133//_________________________________________________________________________________________________
1134bool TrackFinderOriginal::completeTracks()
1135{
1141
1142 print("Complete tracks");
1143
1144 bool completionOccurred(false);
1145 TrackParam paramAtCluster{};
1146 TrackParam bestParamAtCluster{};
1147
1148 for (auto itTrack = mTracks.begin(); itTrack != mTracks.end();) {
1149
1150 bool trackCompleted(false);
1151
1152 for (auto itParam = itTrack->begin(), itPrevParam = itTrack->begin(); itParam != itTrack->end();) {
1153
1154 // Prepare access to the next trackParam before adding new cluster as it can be added in-between
1155 auto itNextParam = std::next(itParam);
1156
1157 // Never test new clusters starting from parameters at last cluster because the covariance matrix is meaningless
1158 TrackParam* param = (itNextParam == itTrack->end()) ? &*itPrevParam : &*itParam;
1159
1160 // Look for a second cluster candidate in the same chamber
1161 int deId = itParam->getClusterPtr()->getDEId();
1162 double bestChi2AtCluster = mTrackFitter.getMaxChi2();
1163 for (const auto cluster : mClusters.at(itParam->getClusterPtr()->getChamberId())) {
1164
1165 // In another detection element
1166 if (cluster->getDEId() == deId) {
1167 continue;
1168 }
1169
1170 // Fast try to add the current cluster
1171 if (!tryOneClusterFast(*itParam, *cluster)) {
1172 continue;
1173 }
1174
1175 // Try to add the current cluster accurately
1176 if (tryOneCluster(*param, *cluster, paramAtCluster, false) >= mMaxChi2ForTracking) {
1177 continue;
1178 }
1179
1180 // Compute the new track parameters including the cluster using the Kalman filter
1181 try {
1182 mTrackFitter.runKalmanFilter(paramAtCluster);
1183 } catch (exception const&) {
1184 continue;
1185 }
1186
1187 // Keep the best cluster
1188 if (paramAtCluster.getTrackChi2() < bestChi2AtCluster) {
1189 bestChi2AtCluster = paramAtCluster.getTrackChi2();
1190 bestParamAtCluster = paramAtCluster;
1191 }
1192 }
1193
1194 // Add the new cluster if any (should be added either just before or just after itParam)
1195 if (bestChi2AtCluster < mTrackFitter.getMaxChi2()) {
1196 itParam->setRemovable(true);
1197 bestParamAtCluster.setRemovable(true);
1198 itTrack->addParamAtCluster(bestParamAtCluster);
1199 trackCompleted = kTRUE;
1200 completionOccurred = kTRUE;
1201 }
1202
1203 itPrevParam = itParam;
1204 itParam = itNextParam;
1205 }
1206
1207 // If the track has been completed, refit it using the Kalman filter and remove it in case of failure
1208 if (trackCompleted) {
1209 try {
1210 mTrackFitter.fit(*itTrack, false);
1211 print("Candidate at position #", getTrackIndex(itTrack), " completed");
1212 ++itTrack;
1213 } catch (exception const&) {
1214 print("Removing candidate at position #", getTrackIndex(itTrack));
1215 itTrack = mTracks.erase(itTrack);
1216 }
1217 } else {
1218 ++itTrack;
1219 }
1220 }
1221
1222 return completionOccurred;
1223}
1224
1225//_________________________________________________________________________________________________
1226void TrackFinderOriginal::improveTracks()
1227{
1232
1233 print("Improve tracks");
1234
1235 // The smoother must be enabled to compute the local chi2 at each cluster
1236 if (!mTrackFitter.isSmootherEnabled()) {
1237 LOG(error) << "Smoother disabled --> tracks cannot be improved";
1238 return;
1239 }
1240
1241 for (auto itTrack = mTracks.begin(); itTrack != mTracks.end();) {
1242
1243 bool removeTrack(false);
1244
1245 // At the first step, only run the smoother
1246 auto itStartingParam = std::prev(itTrack->rend());
1247
1248 while (true) {
1249
1250 // Refit the part of the track affected by the cluster removal, run the smoother, but do not finalize
1251 try {
1252 mTrackFitter.fit(*itTrack, true, false, (itStartingParam == itTrack->rbegin()) ? nullptr : &itStartingParam);
1253 } catch (exception const&) {
1254 removeTrack = true;
1255 break;
1256 }
1257
1258 // Identify removable clusters
1259 itTrack->tagRemovableClusters(requestedStationMask(), false);
1260
1261 // Look for the cluster with the worst local chi2
1262 double worstLocalChi2(-1.);
1263 auto itWorstParam(itTrack->end());
1264 for (auto itParam = itTrack->begin(); itParam != itTrack->end(); ++itParam) {
1265 if (itParam->getLocalChi2() > worstLocalChi2) {
1266 worstLocalChi2 = itParam->getLocalChi2();
1267 itWorstParam = itParam;
1268 }
1269 }
1270
1271 // If the worst chi2 is under requirement then the track is improved
1272 if (worstLocalChi2 < mMaxChi2ForImprovement) {
1273 break;
1274 }
1275
1276 // If the worst cluster is not removable then the track cannot be improved
1277 if (!itWorstParam->isRemovable()) {
1278 removeTrack = true;
1279 break;
1280 }
1281
1282 // Remove the worst cluster
1283 auto itNextParam = itTrack->removeParamAtCluster(itWorstParam);
1284
1285 // Decide from where to refit the track: from the cluster next the one suppressed or
1286 // from scratch if the removed cluster was used to compute the tracking seed
1287 itStartingParam = itTrack->rbegin();
1288 auto itNextToNextParam = (itNextParam == itTrack->end()) ? itNextParam : std::next(itNextParam);
1289 while (itNextToNextParam != itTrack->end()) {
1290 if (itNextToNextParam->getClusterPtr()->getChamberId() != itNextParam->getClusterPtr()->getChamberId()) {
1291 itStartingParam = std::make_reverse_iterator(++itNextParam);
1292 break;
1293 }
1294 ++itNextToNextParam;
1295 }
1296 }
1297
1298 // Remove the track if it couldn't be improved
1299 if (removeTrack) {
1300 print("Removing candidate at position #", getTrackIndex(itTrack));
1301 itTrack = mTracks.erase(itTrack);
1302 } else {
1303 print("Candidate at position #", getTrackIndex(itTrack), " is improved");
1304 ++itTrack;
1305 }
1306 }
1307}
1308
1309//_________________________________________________________________________________________________
1310void TrackFinderOriginal::refineTracks()
1311{
1313
1314 print("Refine tracks");
1315
1316 for (auto itTrack = mTracks.begin(); itTrack != mTracks.end();) {
1317 try {
1318 mTrackFitter.fit(*itTrack, false);
1319 ++itTrack;
1320 } catch (exception const&) {
1321 print("Removing candidate at position #", getTrackIndex(itTrack));
1322 itTrack = mTracks.erase(itTrack);
1323 }
1324 }
1325
1326 improveTracks();
1327
1328 finalize();
1329}
1330
1331//_________________________________________________________________________________________________
1332void TrackFinderOriginal::finalize()
1333{
1335
1336 print("Finalize tracks");
1337
1338 // The smoother must be enabled to compute the final parameters at each cluster
1339 if (!mTrackFitter.isSmootherEnabled()) {
1340 LOG(error) << "Smoother disabled --> tracks cannot be finalized";
1341 return;
1342 }
1343
1344 for (auto& track : mTracks) {
1345 for (auto& param : track) {
1346 param.setParameters(param.getSmoothParameters());
1347 param.setCovariances(param.getSmoothCovariances());
1348 }
1349 }
1350}
1351
1352//_________________________________________________________________________________________________
1353uint8_t TrackFinderOriginal::requestedStationMask() const
1354{
1357
1358 uint8_t mask(0);
1359
1360 for (int i = 0; i < 5; ++i) {
1361 if (TrackerParam::Instance().requestStation[i]) {
1362 mask |= (1 << i);
1363 }
1364 }
1365
1366 return mask;
1367}
1368
1369//_________________________________________________________________________________________________
1370int TrackFinderOriginal::getTrackIndex(const std::list<Track>::iterator& itCurrentTrack) const
1371{
1376
1377 if (mDebugLevel < 1) {
1378 return -3;
1379 }
1380
1381 if (itCurrentTrack == mTracks.end()) {
1382 return -1;
1383 }
1384
1385 int index(0);
1386 for (auto itTrack = mTracks.begin(); itTrack != itCurrentTrack; ++itTrack) {
1387 if (itTrack == mTracks.end()) {
1388 return -2;
1389 }
1390 ++index;
1391 }
1392
1393 return index;
1394}
1395
1396//_________________________________________________________________________________________________
1397void TrackFinderOriginal::printTracks() const
1398{
1400 if (mDebugLevel > 1) {
1401 for (const auto& track : mTracks) {
1402 track.print();
1403 }
1404 }
1405}
1406
1407//_________________________________________________________________________________________________
1408void TrackFinderOriginal::printTrackParam(const TrackParam& trackParam) const
1409{
1411 if (mDebugLevel > 1) {
1412 trackParam.print();
1413 }
1414}
1415
1416//_________________________________________________________________________________________________
1417template <class... Args>
1418void TrackFinderOriginal::print(Args... args) const
1419{
1421 if (mDebugLevel > 0) {
1422 (cout << ... << args) << "\n";
1423 }
1424}
1425
1426//_________________________________________________________________________________________________
1428{
1430 LOG(info) << "number of candidates tracked = " << mNCandidates;
1432 LOG(info) << "number of times tryOneClusterFast() is called = " << mNCallTryOneClusterFast;
1433 LOG(info) << "number of times tryOneCluster() is called = " << mNCallTryOneCluster;
1434}
1435
1436//_________________________________________________________________________________________________
1438{
1440 LOG(info) << "findTrackCandidates duration = " << mTimeFindCandidates.count() << " s";
1441 LOG(info) << "findMoreTrackCandidates duration = " << mTimeFindMoreCandidates.count() << " s";
1442 LOG(info) << "followTracks duration = " << mTimeFollowTracks.count() << " s";
1443 LOG(info) << "completeTracks duration = " << mTimeCompleteTracks.count() << " s";
1444 LOG(info) << "improveTracks duration = " << mTimeImproveTracks.count() << " s";
1445 LOG(info) << "removeConnectedTracks duration = " << mTimeCleanTracks.count() << " s";
1446 LOG(info) << "refineTracks duration = " << mTimeRefineTracks.count() << " s";
1447}
1448
1449} // namespace mch
1450} // namespace o2
definition of the MCH processing errors
void print() const
int32_t i
Configurable parameters for MCH tracking.
Definition of the MagF class.
uint16_t pos
Definition RawData.h:3
Definition of tools for track extrapolation.
Definition of a class to reconstruct tracks with the original algorithm.
HMPID cluster implementation.
Definition Cluster.h:27
void add(ErrorType errorType, uint32_t id0, uint32_t id1, uint64_t n=1)
Definition ErrorMap.cxx:33
static bool extrapToZ(TrackParam &trackParam, double zEnd)
static void addMCSEffect(TrackParam &trackParam, double dZ, double x0)
static bool isFieldON()
Return true if the field is switched ON.
Definition TrackExtrap.h:47
static double getMCSAngle2(const TrackParam &param, double dZ, double x0)
static bool extrapToZCov(TrackParam &trackParam, double zEnd, bool updatePropagator=false)
static double getBendingMomentumFromImpactParam(double impactParam)
static void printNCalls()
static void linearExtrapToZCov(TrackParam &trackParam, double zEnd, bool updatePropagator=false)
void initField(float l3Current, float dipoleCurrent)
const std::list< Track > & findTracks(gsl::span< const Cluster > clusters)
void setChamberResolution(double ex, double ey)
Definition TrackFitter.h:91
void useChamberResolution()
Use the chamber resolution instead of cluster resolution during the fit.
Definition TrackFitter.h:54
void initField(float l3Current, float dipoleCurrent)
void useClusterResolution()
Use the own resolution of each cluster during the fit (default)
Definition TrackFitter.h:52
void setBendingVertexDispersion(double ey)
Set the vertex dispersion in y direction used for the track covariance seed.
Definition TrackFitter.h:44
bool isSmootherEnabled()
Return the smoother enable/disable flag.
Definition TrackFitter.h:49
void smoothTracks(bool smooth)
Enable/disable the smoother (and the saving of related parameters)
Definition TrackFitter.h:47
static constexpr double getMaxChi2()
Return the maximum chi2 above which the track can be considered as abnormal.
Definition TrackFitter.h:65
void fit(Track &track, bool smooth=true, bool finalize=true, std::list< TrackParam >::reverse_iterator *itStartingParam=nullptr, bool skipLocalChi2Calculation=false)
void runKalmanFilter(TrackParam &trackParam)
track parameters for internal use
Definition TrackParam.h:34
GLuint index
Definition glcorearb.h:781
GLenum GLfloat param
Definition glcorearb.h:271
GLint GLuint mask
Definition glcorearb.h:291
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
std::ostream & cout()
uint8_t itsSharedClusterMap uint8_t
float float float float float z2
Definition MathUtils.h:44
float float float float z1
Definition MathUtils.h:44
std::optional< Chamber > chamber(int chamberId)
Definition Chamber.cxx:17
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Defining DataPointCompositeObject explicitly as copiable.
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Cluster > clusters