Project
Loading...
Searching...
No Matches
TrackFinder.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 <cassert>
20#include <cmath>
21#include <iostream>
22#include <stdexcept>
23
24#include <TGeoGlobalMagField.h>
25#include <TMatrixD.h>
26#include <TMath.h>
27
28#include "Field/MagneticField.h"
29#include "MCHBase/Error.h"
32
33namespace o2
34{
35namespace mch
36{
37
38using namespace std;
39
40constexpr double TrackFinder::SDefaultChamberZ[10];
41constexpr double TrackFinder::SChamberThicknessInX0[10];
42constexpr int TrackFinder::SNDE[10];
43
44//_________________________________________________________________________________________________
46{
48
49 // Set the parameters used for fitting the tracks during the tracking
50 const auto& trackerParam = TrackerParam::Instance();
51 mTrackFitter.setBendingVertexDispersion(trackerParam.bendingVertexDispersion);
52 mTrackFitter.setChamberResolution(trackerParam.chamberResolutionX, trackerParam.chamberResolutionY);
53 mTrackFitter.smoothTracks(true);
54
55 // use the Runge-Kutta extrapolation v2
57
58 // Pre-compute some parameters used during the tracking
59 mChamberResolutionX2 = trackerParam.chamberResolutionX * trackerParam.chamberResolutionX;
60 mChamberResolutionY2 = trackerParam.chamberResolutionY * trackerParam.chamberResolutionY;
61 mBendingVertexDispersion2 = trackerParam.bendingVertexDispersion * trackerParam.bendingVertexDispersion;
62 mMaxChi2ForTracking = 2. * trackerParam.sigmaCutForTracking * trackerParam.sigmaCutForTracking;
63 mMaxChi2ForImprovement = 2. * trackerParam.sigmaCutForImprovement * trackerParam.sigmaCutForImprovement;
64
65 // set the maximum MCS angle in chamber from the minimum acceptable momentum
67 double inverseBendingP = (SMinBendingMomentum > 0.) ? 1. / SMinBendingMomentum : 1.;
68 param.setInverseBendingMomentum(inverseBendingP);
69 for (int iCh = 0; iCh < 10; ++iCh) {
70 mMaxMCSAngle2[iCh] = TrackExtrap::getMCSAngle2(param, SChamberThicknessInX0[iCh], 1.);
71 }
72
73 // prepare the internal array of list of vector
74 // grouping DEs in z-planes (2 for chambers 1-4 and 4 for chambers 5-10)
75 for (int iCh = 0; iCh < 4; ++iCh) {
76 mClusters[2 * iCh].reserve(2);
77 mClusters[2 * iCh].emplace_back(100 * (iCh + 1) + 1, nullptr);
78 mClusters[2 * iCh].emplace_back(100 * (iCh + 1) + 3, nullptr);
79 mClusters[2 * iCh + 1].reserve(2);
80 mClusters[2 * iCh + 1].emplace_back(100 * (iCh + 1), nullptr);
81 mClusters[2 * iCh + 1].emplace_back(100 * (iCh + 1) + 2, nullptr);
82 }
83 for (int iCh = 4; iCh < 6; ++iCh) {
84 mClusters[8 + 4 * (iCh - 4)].reserve(5);
85 mClusters[8 + 4 * (iCh - 4)].emplace_back(100 * (iCh + 1), nullptr);
86 mClusters[8 + 4 * (iCh - 4)].emplace_back(100 * (iCh + 1) + 2, nullptr);
87 mClusters[8 + 4 * (iCh - 4)].emplace_back(100 * (iCh + 1) + 4, nullptr);
88 mClusters[8 + 4 * (iCh - 4)].emplace_back(100 * (iCh + 1) + 14, nullptr);
89 mClusters[8 + 4 * (iCh - 4)].emplace_back(100 * (iCh + 1) + 16, nullptr);
90 mClusters[8 + 4 * (iCh - 4) + 1].reserve(4);
91 mClusters[8 + 4 * (iCh - 4) + 1].emplace_back(100 * (iCh + 1) + 1, nullptr);
92 mClusters[8 + 4 * (iCh - 4) + 1].emplace_back(100 * (iCh + 1) + 3, nullptr);
93 mClusters[8 + 4 * (iCh - 4) + 1].emplace_back(100 * (iCh + 1) + 15, nullptr);
94 mClusters[8 + 4 * (iCh - 4) + 1].emplace_back(100 * (iCh + 1) + 17, nullptr);
95 mClusters[8 + 4 * (iCh - 4) + 2].reserve(4);
96 mClusters[8 + 4 * (iCh - 4) + 2].emplace_back(100 * (iCh + 1) + 6, nullptr);
97 mClusters[8 + 4 * (iCh - 4) + 2].emplace_back(100 * (iCh + 1) + 8, nullptr);
98 mClusters[8 + 4 * (iCh - 4) + 2].emplace_back(100 * (iCh + 1) + 10, nullptr);
99 mClusters[8 + 4 * (iCh - 4) + 2].emplace_back(100 * (iCh + 1) + 12, nullptr);
100 mClusters[8 + 4 * (iCh - 4) + 3].reserve(5);
101 mClusters[8 + 4 * (iCh - 4) + 3].emplace_back(100 * (iCh + 1) + 5, nullptr);
102 mClusters[8 + 4 * (iCh - 4) + 3].emplace_back(100 * (iCh + 1) + 7, nullptr);
103 mClusters[8 + 4 * (iCh - 4) + 3].emplace_back(100 * (iCh + 1) + 9, nullptr);
104 mClusters[8 + 4 * (iCh - 4) + 3].emplace_back(100 * (iCh + 1) + 11, nullptr);
105 mClusters[8 + 4 * (iCh - 4) + 3].emplace_back(100 * (iCh + 1) + 13, nullptr);
106 }
107 for (int iCh = 6; iCh < 10; ++iCh) {
108 mClusters[8 + 4 * (iCh - 4)].reserve(7);
109 mClusters[8 + 4 * (iCh - 4)].emplace_back(100 * (iCh + 1), nullptr);
110 mClusters[8 + 4 * (iCh - 4)].emplace_back(100 * (iCh + 1) + 2, nullptr);
111 mClusters[8 + 4 * (iCh - 4)].emplace_back(100 * (iCh + 1) + 4, nullptr);
112 mClusters[8 + 4 * (iCh - 4)].emplace_back(100 * (iCh + 1) + 6, nullptr);
113 mClusters[8 + 4 * (iCh - 4)].emplace_back(100 * (iCh + 1) + 20, nullptr);
114 mClusters[8 + 4 * (iCh - 4)].emplace_back(100 * (iCh + 1) + 22, nullptr);
115 mClusters[8 + 4 * (iCh - 4)].emplace_back(100 * (iCh + 1) + 24, nullptr);
116 mClusters[8 + 4 * (iCh - 4) + 1].reserve(6);
117 mClusters[8 + 4 * (iCh - 4) + 1].emplace_back(100 * (iCh + 1) + 1, nullptr);
118 mClusters[8 + 4 * (iCh - 4) + 1].emplace_back(100 * (iCh + 1) + 3, nullptr);
119 mClusters[8 + 4 * (iCh - 4) + 1].emplace_back(100 * (iCh + 1) + 5, nullptr);
120 mClusters[8 + 4 * (iCh - 4) + 1].emplace_back(100 * (iCh + 1) + 21, nullptr);
121 mClusters[8 + 4 * (iCh - 4) + 1].emplace_back(100 * (iCh + 1) + 23, nullptr);
122 mClusters[8 + 4 * (iCh - 4) + 1].emplace_back(100 * (iCh + 1) + 25, nullptr);
123 mClusters[8 + 4 * (iCh - 4) + 2].reserve(6);
124 mClusters[8 + 4 * (iCh - 4) + 2].emplace_back(100 * (iCh + 1) + 8, nullptr);
125 mClusters[8 + 4 * (iCh - 4) + 2].emplace_back(100 * (iCh + 1) + 10, nullptr);
126 mClusters[8 + 4 * (iCh - 4) + 2].emplace_back(100 * (iCh + 1) + 12, nullptr);
127 mClusters[8 + 4 * (iCh - 4) + 2].emplace_back(100 * (iCh + 1) + 14, nullptr);
128 mClusters[8 + 4 * (iCh - 4) + 2].emplace_back(100 * (iCh + 1) + 16, nullptr);
129 mClusters[8 + 4 * (iCh - 4) + 2].emplace_back(100 * (iCh + 1) + 18, nullptr);
130 mClusters[8 + 4 * (iCh - 4) + 3].reserve(7);
131 mClusters[8 + 4 * (iCh - 4) + 3].emplace_back(100 * (iCh + 1) + 7, nullptr);
132 mClusters[8 + 4 * (iCh - 4) + 3].emplace_back(100 * (iCh + 1) + 9, nullptr);
133 mClusters[8 + 4 * (iCh - 4) + 3].emplace_back(100 * (iCh + 1) + 11, nullptr);
134 mClusters[8 + 4 * (iCh - 4) + 3].emplace_back(100 * (iCh + 1) + 13, nullptr);
135 mClusters[8 + 4 * (iCh - 4) + 3].emplace_back(100 * (iCh + 1) + 15, nullptr);
136 mClusters[8 + 4 * (iCh - 4) + 3].emplace_back(100 * (iCh + 1) + 17, nullptr);
137 mClusters[8 + 4 * (iCh - 4) + 3].emplace_back(100 * (iCh + 1) + 19, nullptr);
138 }
139}
140
141//_________________________________________________________________________________________________
142void TrackFinder::initField(float l3Current, float dipoleCurrent)
143{
145 mTrackFitter.initField(l3Current, dipoleCurrent);
146}
147
148//_________________________________________________________________________________________________
149const std::list<Track>& TrackFinder::findTracks(gsl::span<const Cluster> clusters)
150{
152 std::unordered_map<int, std::list<const Cluster*>> clustersPerDE{};
153 for (const auto& cluster : clusters) {
154 clustersPerDE[cluster.getDEId()].emplace_back(&cluster);
155 }
156 return findTracks(clustersPerDE);
157}
158
159//_________________________________________________________________________________________________
160const std::list<Track>& TrackFinder::findTracks(const std::unordered_map<int, std::list<const Cluster*>>& clusters)
161{
163
164 mTracks.clear();
165 mStartTime = std::chrono::steady_clock::now();
166
167 // fill the internal array of pointers to the list of clusters per DE
168 for (auto& plane : mClusters) {
169 for (auto& de : plane) {
170 auto itDE = clusters.find(de.first);
171 if (itDE == clusters.end()) {
172 de.second = nullptr;
173 } else {
174 de.second = &(itDE->second);
175 }
176 }
177 }
178
179 // use the chamber resolution when fitting the tracks during the tracking
180 mTrackFitter.useChamberResolution();
181
182 try {
183
184 // find track candidates on stations 4 and 5
185 auto tStart = std::chrono::high_resolution_clock::now();
186 findTrackCandidates();
187 auto tEnd = std::chrono::high_resolution_clock::now();
188 mTimeFindCandidates += tEnd - tStart;
189 if (TrackerParam::Instance().moreCandidates) {
190 tStart = std::chrono::high_resolution_clock::now();
191 findMoreTrackCandidates();
192 tEnd = std::chrono::high_resolution_clock::now();
193 mTimeFindMoreCandidates += tEnd - tStart;
194 }
195 mNCandidates += mTracks.size();
196 print("------ list of track candidates ------");
197 printTracks();
198
199 // track each candidate down to chamber 1 and remove it
200 tStart = std::chrono::high_resolution_clock::now();
201 for (auto itTrack = mTracks.begin(); itTrack != mTracks.end();) {
202 std::unordered_map<int, std::unordered_set<uint32_t>> excludedClusters{};
203 followTrackInChamber(itTrack, 5, 0, false, excludedClusters);
204 print("findTracks: removing candidate at position #", getTrackIndex(itTrack));
205 itTrack = mTracks.erase(itTrack);
206 }
207 tEnd = std::chrono::high_resolution_clock::now();
208 mTimeFollowTracks += tEnd - tStart;
209 print("------ list of tracks before improvement and cleaning ------");
210 printTracks();
211
212 } catch (exception const& e) {
213 LOG(warning) << e.what() << " --> abort";
214 mTracks.clear();
215 return mTracks;
216 }
217
218 // improve the reconstructed tracks
219 auto tStart = std::chrono::high_resolution_clock::now();
220 improveTracks();
221 auto tEnd = std::chrono::high_resolution_clock::now();
222 mTimeImproveTracks += tEnd - tStart;
223
224 // remove connected tracks in stations(1..) 3, 4 and 5
225 tStart = std::chrono::high_resolution_clock::now();
226 removeConnectedTracks(2, 4);
227 tEnd = std::chrono::high_resolution_clock::now();
228 mTimeCleanTracks += tEnd - tStart;
229
230 // refine the tracks using cluster resolution or just finalize them
231 if (TrackerParam::Instance().refineTracks) {
232 tStart = std::chrono::high_resolution_clock::now();
233 mTrackFitter.useClusterResolution();
234 refineTracks();
235 tEnd = std::chrono::high_resolution_clock::now();
236 mTimeRefineTracks += tEnd - tStart;
237 } else {
238 finalize();
239 }
240
241 return mTracks;
242}
243
244//_________________________________________________________________________________________________
245void TrackFinder::findTrackCandidates()
246{
250
251 // start by looking for candidates on station 5
252 findTrackCandidatesInSt5();
253
254 for (auto itTrack = mTracks.begin(); itTrack != mTracks.end();) {
255
256 // prepare backward tracking if not already done
257 if (!itTrack->hasCurrentParam()) {
258 prepareBackwardTracking(itTrack, false);
259 }
260
261 // look for compatible clusters on station 4
262 std::unordered_map<int, std::unordered_set<uint32_t>> excludedClusters{};
263 auto itNewTrack = followTrackInChamber(itTrack, 7, 6, false, excludedClusters);
264
265 // keep the current candidate only if no compatible cluster is found and the station is not requested
266 if (!TrackerParam::Instance().requestStation[3] && excludedClusters.empty() && itTrack->areCurrentParamValid()) {
267 ++itTrack;
268 } else {
269 print("findTrackCandidates: removing candidate at position #", getTrackIndex(itTrack));
270 itTrack = mTracks.erase(itTrack);
271 // prepare backward tracking for the new tracks
272 for (; itNewTrack != mTracks.end() && itNewTrack != itTrack; ++itNewTrack) {
273 prepareBackwardTracking(itNewTrack, false);
274 }
275 }
276 }
277
278 // list the cluster combinations already used in stations 4 and 5
279 std::vector<std::array<uint32_t, 8>> usedClusters(mTracks.size());
280 int iTrack(0);
281 for (const auto& track : mTracks) {
282 for (const auto& param : track) {
283 int iCl = 2 * (param.getClusterPtr()->getChamberId() - 6) + param.getClusterPtr()->getDEId() % 2;
284 usedClusters[iTrack][iCl] = param.getClusterPtr()->uid;
285 }
286 ++iTrack;
287 }
288
289 auto itLastCandidateFromSt5 = mTracks.empty() ? mTracks.end() : std::prev(mTracks.end());
290
291 // then look for candidates on station 4
292 findTrackCandidatesInSt4();
293
294 auto itFirstCandidateOnSt4 = (itLastCandidateFromSt5 == mTracks.end()) ? mTracks.begin() : std::next(itLastCandidateFromSt5);
295 for (auto itTrack = itFirstCandidateOnSt4; itTrack != mTracks.end();) {
296
297 // prepare forward tracking if not already done
298 if (!itTrack->hasCurrentParam()) {
299 try {
300 prepareForwardTracking(itTrack, true);
301 } catch (exception const&) {
302 print("findTrackCandidates: removing candidate at position #", getTrackIndex(itTrack));
303 itTrack = mTracks.erase(itTrack);
304 continue;
305 }
306 }
307
308 // look for compatible clusters on each chamber of station 5 separately,
309 // exluding those already attached to an identical candidate on station 4
310 // (cases where both chambers of station 5 are fired should have been found in the first step)
311 std::unordered_map<int, std::unordered_set<uint32_t>> excludedClusters{};
312 if (!usedClusters.empty()) {
313 std::array<uint32_t, 4> currentClusters{};
314 for (const auto& param : *itTrack) {
315 int iCl = 2 * (param.getClusterPtr()->getChamberId() - 6) + param.getClusterPtr()->getDEId() % 2;
316 currentClusters[iCl] = param.getClusterPtr()->uid;
317 }
318 excludeClustersFromIdenticalTracks(currentClusters, usedClusters, excludedClusters);
319 }
320 auto itFirstNewTrack = followTrackInChamber(itTrack, 8, 8, false, excludedClusters);
321 auto itNewTrack = followTrackInChamber(itTrack, 9, 9, false, excludedClusters);
322 if (itFirstNewTrack == mTracks.end()) {
323 itFirstNewTrack = itNewTrack;
324 }
325
326 // keep the current candidate only if no compatible cluster is found and the station is not requested
327 if (!TrackerParam::Instance().requestStation[4] && excludedClusters.empty()) {
328 itFirstNewTrack = itTrack;
329 ++itTrack;
330 } else {
331 print("findTrackCandidates: removing candidate at position #", getTrackIndex(itTrack));
332 itTrack = mTracks.erase(itTrack);
333 }
334
335 // refit the track(s) and prepare to continue the tracking in the backward direction
336 while (itFirstNewTrack != mTracks.end() && itFirstNewTrack != itTrack) {
337 try {
338 prepareBackwardTracking(itFirstNewTrack, true);
339 ++itFirstNewTrack;
340 } catch (exception const&) {
341 print("findTrackCandidates: removing candidate at position #", getTrackIndex(itFirstNewTrack));
342 itFirstNewTrack = mTracks.erase(itFirstNewTrack);
343 }
344 }
345 }
346}
347
348//_________________________________________________________________________________________________
349void TrackFinder::findTrackCandidatesInSt5()
350{
353
354 print("--- find candidates in station 5 ---");
355
356 for (int iPlaneCh9 = 27; iPlaneCh9 > 23; --iPlaneCh9) {
357
358 for (int iPlaneCh10 = 28; iPlaneCh10 < 32; ++iPlaneCh10) {
359
360 // skip candidates that have already been found starting from a previous combination
361 bool skipUsedPairs = (iPlaneCh9 == 24 || iPlaneCh9 == 26 || iPlaneCh10 == 29 || iPlaneCh10 == 31);
362
363 // find all valid candidates between these 2 planes
364 auto itTrack = findTrackCandidates(iPlaneCh9, iPlaneCh10, skipUsedPairs, mTracks.begin());
365
366 // stop here if overlaps have already been checked on both chambers
367 if ((iPlaneCh9 == 24 || iPlaneCh9 == 26) && (iPlaneCh10 == 29 || iPlaneCh10 == 31)) {
368 continue;
369 }
370
371 while (itTrack != mTracks.end()) {
372
373 auto itNextTrack = std::next(itTrack);
374
375 if (iPlaneCh10 == 28 || iPlaneCh10 == 30) {
376
377 // if not already done, look for compatible clusters in the overlapping regions of chamber 10
378 try {
379 prepareForwardTracking(itTrack, true);
380 } catch (exception const&) {
381 print("findTrackCandidatesInSt5: removing candidate at position #", getTrackIndex(itTrack));
382 itTrack = mTracks.erase(itTrack);
383 continue;
384 }
385 auto itNewTrack = followTrackInOverlapDE(itTrack, itTrack->last().getClusterPtr()->getDEId(), iPlaneCh10 + 1);
386
387 if (itNewTrack != mTracks.end()) {
388
389 // remove the initial candidate if compatible cluster(s) are found
390 print("findTrackCandidatesInSt5: removing candidate at position #", getTrackIndex(itTrack));
391 itTrack = mTracks.erase(itTrack);
392
393 // refit the track(s) with new attached cluster(s) and prepare to continue the tracking in the backward direction
394 bool stop(false);
395 while (!stop) {
396 itTrack = std::prev(itTrack);
397 if (itTrack == itNewTrack) {
398 stop = true;
399 }
400 try {
401 prepareBackwardTracking(itTrack, true);
402 } catch (exception const&) {
403 print("findTrackCandidatesInSt5: removing candidate at position #", getTrackIndex(itTrack));
404 itTrack = mTracks.erase(itTrack);
405 }
406 }
407 } else {
408 // prepare to continue the tracking in the backward direction with the initial candidate
409 prepareBackwardTracking(itTrack, false);
410 }
411 }
412
413 if (iPlaneCh9 == 25 || iPlaneCh9 == 27) {
414
415 while (itTrack != itNextTrack) {
416
417 // if not already done, look for compatible clusters in the overlapping regions of chamber 9
418 if (!itTrack->hasCurrentParam()) {
419 prepareBackwardTracking(itTrack, false);
420 }
421 auto itNewTrack = followTrackInOverlapDE(itTrack, itTrack->first().getClusterPtr()->getDEId(), iPlaneCh9 - 1);
422
423 // keep the initial candidate only if no compatible cluster is found
424 if (itNewTrack == mTracks.end()) {
425 ++itTrack;
426 } else {
427 print("findTrackCandidatesInSt5: removing candidate at position #", getTrackIndex(itTrack));
428 itTrack = mTracks.erase(itTrack);
429 }
430 }
431 }
432
433 itTrack = itNextTrack;
434 }
435 }
436 }
437
438 // remove tracks out of limits now that overlaps have been checked
439 for (auto itTrack = mTracks.begin(); itTrack != mTracks.end();) {
440 if (itTrack->isRemovable()) {
441 itTrack = mTracks.erase(itTrack);
442 } else {
443 ++itTrack;
444 }
445 }
446}
447
448//_________________________________________________________________________________________________
449void TrackFinder::findTrackCandidatesInSt4()
450{
453
454 print("--- find candidates in station 4 ---");
455
456 auto itLastCandidateFromSt5 = mTracks.empty() ? mTracks.end() : std::prev(mTracks.end());
457
458 for (int iPlaneCh8 = 20; iPlaneCh8 < 24; ++iPlaneCh8) {
459
460 for (int iPlaneCh7 = 19; iPlaneCh7 > 15; --iPlaneCh7) {
461
462 // skip candidates that have already been found starting from a previous combination
463 bool skipUsedPairs = (iPlaneCh7 == 18 || iPlaneCh7 == 16 || iPlaneCh8 == 21 || iPlaneCh8 == 23);
464
465 // find all valid candidates between these 2 planes
466 auto itFirstCandidateOnSt4 = (itLastCandidateFromSt5 == mTracks.end()) ? mTracks.begin() : std::next(itLastCandidateFromSt5);
467 auto itTrack = findTrackCandidates(iPlaneCh7, iPlaneCh8, skipUsedPairs, itFirstCandidateOnSt4);
468
469 // stop here if overlaps have already been checked on both chambers
470 if ((iPlaneCh7 == 18 || iPlaneCh7 == 16) && (iPlaneCh8 == 21 || iPlaneCh8 == 23)) {
471 continue;
472 }
473
474 while (itTrack != mTracks.end()) {
475
476 auto itNextTrack = std::next(itTrack);
477
478 if (iPlaneCh7 == 19 || iPlaneCh7 == 17) {
479
480 // if not already done, look for compatible clusters in the overlapping regions of chamber 7
481 prepareBackwardTracking(itTrack, false);
482 auto itNewTrack = followTrackInOverlapDE(itTrack, itTrack->first().getClusterPtr()->getDEId(), iPlaneCh7 - 1);
483
484 // keep the initial candidate only if no compatible cluster is found
485 if (itNewTrack != mTracks.end()) {
486 print("findTrackCandidatesInSt4: removing candidate at position #", getTrackIndex(itTrack));
487 mTracks.erase(itTrack);
488 itTrack = itNewTrack;
489 }
490 }
491
492 while (itTrack != itNextTrack) {
493
494 // for every tracks, prepare to continue the tracking in the forward direction
495 try {
496 prepareForwardTracking(itTrack, true);
497 } catch (exception const&) {
498 print("findTrackCandidatesInSt4: removing candidate at position #", getTrackIndex(itTrack));
499 itTrack = mTracks.erase(itTrack);
500 continue;
501 }
502
503 if (iPlaneCh8 == 20 || iPlaneCh8 == 22) {
504
505 // if not already done, look for compatible clusters in the overlapping regions of chamber 8
506 auto itNewTrack = followTrackInOverlapDE(itTrack, itTrack->last().getClusterPtr()->getDEId(), iPlaneCh8 + 1);
507
508 // keep the initial candidate only if no compatible cluster is found
509 if (itNewTrack == mTracks.end()) {
510 ++itTrack;
511 } else {
512 // prepare to continue the tracking of the new tracks from the last attached cluster
513 for (; itNewTrack != itTrack; ++itNewTrack) {
514 prepareForwardTracking(itNewTrack, false);
515 }
516 print("findTrackCandidatesInSt4: removing candidate at position #", getTrackIndex(itTrack));
517 itTrack = mTracks.erase(itTrack);
518 }
519 } else {
520 ++itTrack;
521 }
522 }
523 }
524 }
525 }
526
527 // remove tracks out of limits now that overlaps have been checked
528 auto itTrack = (itLastCandidateFromSt5 == mTracks.end()) ? mTracks.begin() : ++itLastCandidateFromSt5;
529 while (itTrack != mTracks.end()) {
530 if (itTrack->isRemovable()) {
531 itTrack = mTracks.erase(itTrack);
532 } else {
533 ++itTrack;
534 }
535 }
536}
537
538//_________________________________________________________________________________________________
539void TrackFinder::findMoreTrackCandidates()
540{
545
546 print("--- find more candidates ---");
547
548 auto itLastCandidate = mTracks.empty() ? mTracks.end() : std::prev(mTracks.end());
549
550 for (int iPlaneSt4 = 23; iPlaneSt4 > 15; --iPlaneSt4) {
551
552 for (int iPlaneSt5 = 24; iPlaneSt5 < 32; ++iPlaneSt5) {
553
554 // find all valid candidates between these 2 planes
555 auto itTrack = findTrackCandidates(iPlaneSt4, iPlaneSt5, true, mTracks.begin());
556
557 // stop here if overlaps have already been checked on both chambers
558 if ((iPlaneSt4 % 2 == 0) && (iPlaneSt5 % 2 == 1)) {
559 continue;
560 }
561
562 while (itTrack != mTracks.end()) {
563
564 auto itNextTrack = std::next(itTrack);
565
566 if (iPlaneSt5 % 2 == 0) {
567
568 // if not already done, look for compatible clusters in the overlapping regions of that chamber in station 5
569 try {
570 prepareForwardTracking(itTrack, true);
571 } catch (exception const&) {
572 print("findMoreTrackCandidates: removing candidate at position #", getTrackIndex(itTrack));
573 itTrack = mTracks.erase(itTrack);
574 continue;
575 }
576 auto itNewTrack = followTrackInOverlapDE(itTrack, itTrack->last().getClusterPtr()->getDEId(), iPlaneSt5 + 1);
577
578 if (itNewTrack != mTracks.end()) {
579
580 // remove the initial candidate if compatible cluster(s) are found
581 print("findMoreTrackCandidates: removing candidate at position #", getTrackIndex(itTrack));
582 itTrack = mTracks.erase(itTrack);
583
584 // refit the track(s) with new cluster(s) and prepare to continue the tracking in the backward direction
585 bool stop(false);
586 while (!stop) {
587 itTrack = std::prev(itTrack);
588 if (itTrack == itNewTrack) {
589 stop = true;
590 }
591 try {
592 prepareBackwardTracking(itTrack, true);
593 } catch (exception const&) {
594 print("findMoreTrackCandidates: removing candidate at position #", getTrackIndex(itTrack));
595 itTrack = mTracks.erase(itTrack);
596 }
597 }
598 } else {
599 // prepare to continue the tracking in the backward direction with the initial candidate
600 prepareBackwardTracking(itTrack, false);
601 }
602 }
603
604 if (iPlaneSt4 % 2 == 1) {
605
606 while (itTrack != itNextTrack) {
607
608 // if not already done, look for compatible clusters in the overlapping regions of that chamber in station 4
609 if (!itTrack->hasCurrentParam()) {
610 prepareBackwardTracking(itTrack, false);
611 }
612 auto itNewTrack = followTrackInOverlapDE(itTrack, itTrack->first().getClusterPtr()->getDEId(), iPlaneSt4 - 1);
613
614 // keep the initial candidate only if no compatible cluster is found
615 if (itNewTrack == mTracks.end()) {
616 ++itTrack;
617 } else {
618 print("findMoreTrackCandidates: removing candidate at position #", getTrackIndex(itTrack));
619 itTrack = mTracks.erase(itTrack);
620 }
621 }
622 }
623
624 itTrack = itNextTrack;
625 }
626 }
627 }
628
629 // remove tracks out of limits now that overlaps have been checked
630 // and make sure every new tracks are prepared to continue the tracking in the backward direction
631 auto itTrack = (itLastCandidate == mTracks.end()) ? mTracks.begin() : ++itLastCandidate;
632 while (itTrack != mTracks.end()) {
633 if (itTrack->isRemovable()) {
634 itTrack = mTracks.erase(itTrack);
635 } else {
636 if (!itTrack->hasCurrentParam()) {
637 prepareBackwardTracking(itTrack, false);
638 }
639 ++itTrack;
640 }
641 }
642}
643
644//_________________________________________________________________________________________________
645std::list<Track>::iterator TrackFinder::findTrackCandidates(int plane1, int plane2, bool skipUsedPairs, const std::list<Track>::iterator& itFirstTrack)
646{
651
652 const auto& trackerParam = TrackerParam::Instance();
653
654 // maximum impact parameter dispersion**2 due to MCS in chambers
655 double impactMCS2(0.);
656 int chamber1 = getChamberId(plane1);
657 for (int iCh = 0; iCh <= chamber1; ++iCh) {
658 impactMCS2 += SDefaultChamberZ[iCh] * SDefaultChamberZ[iCh] * mMaxMCSAngle2[iCh];
659 }
660
661 // create an iterator to the last track of the list before adding new ones
662 auto itTrack = mTracks.empty() ? mTracks.end() : std::prev(mTracks.end());
663
664 // list the cluster combinations used on the chambers corresponding to plane1 and plane2
665 int chamber2 = getChamberId(plane2);
666 std::vector<std::array<uint32_t, 4>> usedClusters{};
667 if (skipUsedPairs) {
668 usedClusters.reserve(mTracks.size());
669 for (auto itTrk = itFirstTrack; itTrk != mTracks.end(); ++itTrk) {
670 usedClusters.push_back({0, 0, 0, 0});
671 for (const auto& param : *itTrk) {
672 int ch = param.getClusterPtr()->getChamberId();
673 if (ch == chamber1) {
674 usedClusters.back()[param.getClusterPtr()->getDEId() % 2] = param.getClusterPtr()->uid;
675 } else if (ch == chamber2) {
676 usedClusters.back()[2 + param.getClusterPtr()->getDEId() % 2] = param.getClusterPtr()->uid;
677 }
678 }
679 }
680 }
681
682 for (auto& de1 : mClusters[plane1]) {
683
684 // skip DE without cluster
685 if (de1.second == nullptr) {
686 continue;
687 }
688
689 for (const auto cluster1 : *de1.second) {
690
691 double z1 = cluster1->getZ();
692
693 for (auto& de2 : mClusters[plane2]) {
694
695 // skip DE without cluster
696 if (de2.second == nullptr) {
697 continue;
698 }
699
700 for (const auto cluster2 : *de2.second) {
701
702 // skip combinations of clusters already part of a track if requested
703 if (skipUsedPairs && areUsed(*cluster1, *cluster2, usedClusters)) {
704 continue;
705 }
706
707 double z2 = cluster2->getZ();
708 double dZ = z1 - z2;
709
710 // check if non bending impact parameter is within tolerances
711 double nonBendingSlope = (cluster1->getX() - cluster2->getX()) / dZ;
712 double nonBendingImpactParam = TMath::Abs(cluster1->getX() - cluster1->getZ() * nonBendingSlope);
713 double nonBendingImpactParamErr = TMath::Sqrt((z1 * z1 * mChamberResolutionX2 + z2 * z2 * mChamberResolutionX2) / dZ / dZ + impactMCS2);
714 if ((nonBendingImpactParam - trackerParam.sigmaCutForTracking * nonBendingImpactParamErr) > (3. * trackerParam.nonBendingVertexDispersion)) {
715 continue;
716 }
717
718 double bendingSlope = (cluster1->getY() - cluster2->getY()) / dZ;
719 if (TrackExtrap::isFieldON()) { // depending whether the field is ON or OFF
720 // check if bending momentum is within tolerances
721 double bendingImpactParam = cluster1->getY() - cluster1->getZ() * bendingSlope;
722 double bendingImpactParamErr2 = (z1 * z1 * mChamberResolutionY2 + z2 * z2 * mChamberResolutionY2) / dZ / dZ + impactMCS2;
723 double bendingMomentum = TMath::Abs(TrackExtrap::getBendingMomentumFromImpactParam(bendingImpactParam));
724 double bendingMomentumErr = TMath::Sqrt((mBendingVertexDispersion2 + bendingImpactParamErr2) / bendingImpactParam / bendingImpactParam + 0.01) * bendingMomentum;
725 if ((bendingMomentum + 3. * bendingMomentumErr) < SMinBendingMomentum) {
726 continue;
727 }
728 } else {
729 // or check if bending impact parameter is within tolerances
730 double bendingImpactParam = TMath::Abs(cluster1->getY() - cluster1->getZ() * bendingSlope);
731 double bendingImpactParamErr = TMath::Sqrt((z1 * z1 * mChamberResolutionY2 + z2 * z2 * mChamberResolutionY2) / dZ / dZ + impactMCS2);
732 if ((bendingImpactParam - trackerParam.sigmaCutForTracking * bendingImpactParamErr) > (3. * trackerParam.bendingVertexDispersion)) {
733 continue;
734 }
735 }
736
737 // create a new track candidate
738 createTrack(*cluster1, *cluster2);
739 }
740 }
741 }
742 }
743
744 return (itTrack == mTracks.end()) ? mTracks.begin() : ++itTrack;
745}
746
747//_________________________________________________________________________________________________
748std::list<Track>::iterator TrackFinder::followTrackInOverlapDE(const std::list<Track>::iterator& itTrack, int currentDE, int plane)
749{
756
757 print("followTrackInOverlapDE: follow track #", getTrackIndex(itTrack), " currently at DE ", currentDE, " to plane ", plane);
758 printTrack(*itTrack);
759
760 // the current track parameters must be set
761 assert(itTrack->hasCurrentParam());
762
763 auto itNewTrack(itTrack);
764
765 const TrackParam& currentParam = itTrack->getCurrentParam();
766 int currentChamber = itTrack->getCurrentChamber();
767
768 // loop over all DEs of plane
769 TrackParam paramAtCluster{};
770 for (auto& de : mClusters[plane]) {
771
772 // skip DE without cluster
773 if (de.second == nullptr) {
774 continue;
775 }
776
777 // skip DE that do not overlap with the current DE
778 if (de.first % 100 != (currentDE % 100 + 1) % SNDE[currentChamber] && de.first % 100 != (currentDE % 100 - 1 + SNDE[currentChamber]) % SNDE[currentChamber]) {
779 continue;
780 }
781
782 // look for cluster candidate in this DE
783 for (const auto cluster : *de.second) {
784
785 // try to add the current cluster
786 if (!isCompatible(currentParam, *cluster, paramAtCluster)) {
787 continue;
788 }
789
790 // duplicate the track and add the new cluster
791 itNewTrack = addTrack(itNewTrack, *itTrack);
792 print("followTrackInOverlapDE: duplicating candidate at position #", getTrackIndex(itNewTrack), " to add cluster ", cluster->getIdAsString());
793 itNewTrack->addParamAtCluster(paramAtCluster);
794
795 // tag the track as removable (if it is not already the case) if it is out of limits
796 if (!itNewTrack->isRemovable() && !isAcceptable(paramAtCluster)) {
797 itNewTrack->removable();
798 }
799 }
800 }
801
802 return (itNewTrack == itTrack) ? mTracks.end() : itNewTrack;
803}
804
805//_________________________________________________________________________________________________
806std::list<Track>::iterator TrackFinder::followTrackInChamber(std::list<Track>::iterator& itTrack,
807 int chamber, int lastChamber, bool canSkip,
808 std::unordered_map<int, std::unordered_set<uint32_t>>& excludedClusters)
809{
823
824 // list of (half-)planes, 2 or 4 per chamber, ordered according to the direction of propagation,
825 // which is forward when going to station 5 and backward otherwise with the present algorithm
826 static constexpr int plane[10][4] = {{1, 0, -1, -1}, {3, 2, -1, -1}, {5, 4, -1, -1}, {7, 6, -1, -1}, {11, 10, 9, 8}, {15, 14, 13, 12}, {19, 18, 17, 16}, {23, 22, 21, 20}, {24, 25, 26, 27}, {28, 29, 30, 31}};
827
828 print("followTrackInChamber: follow track #", getTrackIndex(itTrack), " to chamber ", chamber + 1, " up to chamber ", lastChamber + 1);
829
830 // the current track parameters must be set at a different chamber and valid
831 if (!itTrack->areCurrentParamValid() || chamber == itTrack->getCurrentChamber()) {
832 return mTracks.end();
833 }
834
835 std::chrono::duration<double> currentTrackingDuration = std::chrono::steady_clock::now() - mStartTime;
836 if (currentTrackingDuration.count() > TrackerParam::Instance().maxTrackingDuration) {
837 mErrorMap.add(ErrorType::Tracking_TooLong, 0, 0);
838 throw length_error(string("Tracking is taking too long (") + std::round(currentTrackingDuration.count()) + " s)");
839 }
840
841 // determine whether the chamber is the first one reached on the station
842 int currentChamber = itTrack->getCurrentChamber();
843 bool isFirstOnStation = ((chamber < currentChamber && chamber % 2 == 1) || (chamber > currentChamber && chamber % 2 == 0));
844
845 // follow the track in the 2 planes or 4 half-planes of the chamber
846 auto itFirstNewTrack = followTrackInChamber(itTrack, plane[chamber][0], plane[chamber][1], lastChamber, excludedClusters);
847 if (chamber > 3) {
848 auto itNewTrack = followTrackInChamber(itTrack, plane[chamber][2], plane[chamber][3], lastChamber, excludedClusters);
849 if (itFirstNewTrack == mTracks.end()) {
850 itFirstNewTrack = itNewTrack;
851 }
852 }
853
854 // add MCS effects in that chamber before going further with this track or stop here if the track could not reach that chamber
855 if (itTrack->areCurrentParamValid()) {
856 TrackExtrap::addMCSEffect(itTrack->getCurrentParam(), SChamberThicknessInX0[chamber], -1.);
857 } else {
858 return itFirstNewTrack;
859 }
860
861 if (chamber != lastChamber) {
862
863 // save the current track parameters before going to the next chamber
864 TrackParam currentParam = itTrack->getCurrentParam();
865
866 // consider the possibility to skip the chamber if it is the first one of the station or if we know we can skip it,
867 // i.e. if a compatible cluster has been found on the first chamber and none has been found on the second
868 if (isFirstOnStation || (canSkip && excludedClusters.empty())) {
869 int nextChamber = (chamber > lastChamber) ? chamber - 1 : chamber + 1;
870 auto itNewTrack = followTrackInChamber(itTrack, nextChamber, lastChamber, false, excludedClusters);
871 if (itFirstNewTrack == mTracks.end()) {
872 itFirstNewTrack = itNewTrack;
873 }
874 }
875
876 // consider the possibility to skip the entire station if not requested and not the last one
877 if (isFirstOnStation && !TrackerParam::Instance().requestStation[chamber / 2] && chamber / 2 != lastChamber / 2) {
878 int nextChamber = (chamber > lastChamber) ? chamber - 2 : chamber + 2;
879 auto itNewTrack = followTrackInChamber(itTrack, nextChamber, lastChamber, false, excludedClusters);
880 if (itFirstNewTrack == mTracks.end()) {
881 itFirstNewTrack = itNewTrack;
882 }
883 }
884
885 // reset the current track parameters to the ones at that chamber if needed
886 // (not sure it is needed at all but that way it is clear what the current track parameters are at the end of this function)
887 if (itTrack->getCurrentChamber() != chamber) {
888 setCurrentParam(*itTrack, currentParam, chamber);
889 }
890 } else {
891
892 // add a new track if a cluster has been found on the first chamber of the station but not on the second and last one
893 // or if one reaches station 1 and it is not requested, whether a cluster has been found on it or not
894 if ((!isFirstOnStation && canSkip && excludedClusters.empty()) ||
895 (chamber / 2 == 0 && !TrackerParam::Instance().requestStation[0] && (isFirstOnStation || !canSkip))) {
896 auto itNewTrack = addTrack(itTrack, *itTrack);
897 if (itFirstNewTrack == mTracks.end()) {
898 itFirstNewTrack = itNewTrack;
899 }
900 print("followTrackInChamber: duplicating candidate at position #", getTrackIndex(itFirstNewTrack));
901 }
902 }
903
904 return itFirstNewTrack;
905}
906
907//_________________________________________________________________________________________________
908std::list<Track>::iterator TrackFinder::followTrackInChamber(std::list<Track>::iterator& itTrack,
909 int plane1, int plane2, int lastChamber,
910 std::unordered_map<int, std::unordered_set<uint32_t>>& excludedClusters)
911{
924
925 print("followTrackInChamber: follow track #", getTrackIndex(itTrack), " to planes ", plane1, " and ", plane2, " up to chamber ", lastChamber + 1);
926 printTrack(*itTrack);
927
928 // the current track parameters must be set and valid
929 if (!itTrack->areCurrentParamValid()) {
930 return mTracks.end();
931 }
932
933 auto itFirstNewTrack(mTracks.end());
934
935 // add MCS effects in the missing chambers if any. Update the current parameters in the process
936 int chamber = getChamberId(plane1);
937 if ((chamber < itTrack->getCurrentChamber() - 1 || chamber > itTrack->getCurrentChamber() + 1) &&
938 !propagateCurrentParam(*itTrack, (chamber < itTrack->getCurrentChamber()) ? chamber + 1 : chamber - 1)) {
939 return mTracks.end();
940 }
941
942 // extrapolate the candidate to the chamber if not already there
943 TrackParam paramAtChamber = itTrack->getCurrentParam();
944 if (itTrack->getCurrentChamber() != chamber && !TrackExtrap::extrapToZCov(paramAtChamber, SDefaultChamberZ[chamber], true)) {
945 itTrack->invalidateCurrentParam();
946 return mTracks.end();
947 }
948
949 // determine the next chamber to go to, if lastChamber is not yet reached
950 int nextChamber(-1);
951 if (chamber > lastChamber) {
952 nextChamber = chamber - 1;
953 } else if (chamber < lastChamber) {
954 nextChamber = chamber + 1;
955 }
956
957 // loop over all DEs of plane1
958 TrackParam paramAtCluster1{};
959 TrackParam currentParamAtCluster1{};
960 TrackParam paramAtCluster2{};
961 std::unordered_map<int, std::unordered_set<uint32_t>> newExcludedClusters{};
962 for (auto& de1 : mClusters[plane1]) {
963
964 // skip DE without cluster
965 if (de1.second == nullptr) {
966 continue;
967 }
968
969 // get the list of excluded clusters for the DE
970 auto itExcludedClusters = excludedClusters.find(de1.first);
971 bool hasExcludedClusters = (itExcludedClusters != excludedClusters.end());
972
973 // look for cluster candidate in this DE
974 for (const auto cluster1 : *de1.second) {
975
976 // skip excluded clusters
977 if (hasExcludedClusters && itExcludedClusters->second.count(cluster1->uid) > 0) {
978 continue;
979 }
980
981 // try to add the current cluster
982 if (!isCompatible(paramAtChamber, *cluster1, paramAtCluster1)) {
983 continue;
984 }
985
986 // add it to the list of excluded clusters for this candidate
987 excludedClusters[de1.first].emplace(cluster1->uid);
988
989 // skip tracks out of limits, but after checking for overlaps
990 bool isAcceptableAtCluster1 = isAcceptable(paramAtCluster1);
991
992 // save the current parameters at cluster1, reset the propagator and add MCS effects before going to plane2
993 currentParamAtCluster1 = paramAtCluster1;
994 currentParamAtCluster1.resetPropagator();
995 TrackExtrap::addMCSEffect(currentParamAtCluster1, SChamberThicknessInX0[chamber], -1.);
996
997 // loop over all DEs of plane2
998 bool cluster2Found(false);
999 for (auto& de2 : mClusters[plane2]) {
1000
1001 // skip DE without cluster
1002 if (de2.second == nullptr) {
1003 continue;
1004 }
1005
1006 // skip DE that do not overlap with the DE of plane1
1007 if (de2.first % 100 != (de1.first % 100 + 1) % SNDE[chamber] && de2.first % 100 != (de1.first % 100 - 1 + SNDE[chamber]) % SNDE[chamber]) {
1008 continue;
1009 }
1010
1011 // look for cluster candidate in this DE
1012 for (const auto cluster2 : *de2.second) {
1013
1014 // try to add the current cluster
1015 if (!isCompatible(currentParamAtCluster1, *cluster2, paramAtCluster2)) {
1016 continue;
1017 }
1018
1019 cluster2Found = true;
1020
1021 // add it to the list of excluded clusters for this candidate
1022 excludedClusters[de2.first].emplace(cluster2->uid);
1023
1024 // skip tracks out of limits
1025 if (!isAcceptableAtCluster1 || !isAcceptable(paramAtCluster2)) {
1026 continue;
1027 }
1028
1029 // continue the tracking to the next chambers and attach the 2 clusters to the new tracks if any
1030 auto itNewTrack = addClustersAndFollowTrack(itTrack, paramAtCluster1, &paramAtCluster2, nextChamber, lastChamber, newExcludedClusters);
1031 if (itFirstNewTrack == mTracks.end()) {
1032 itFirstNewTrack = itNewTrack;
1033 }
1034
1035 // transfert the list of new excluded clusters to the full list for the initial candidate
1036 moveClusters(newExcludedClusters, excludedClusters);
1037 }
1038 }
1039
1040 if (!cluster2Found && isAcceptableAtCluster1) {
1041
1042 // continue the tracking with only cluster1 if no compatible cluster is found on plane2 and the track stays within limits
1043 auto itNewTrack = addClustersAndFollowTrack(itTrack, paramAtCluster1, nullptr, nextChamber, lastChamber, newExcludedClusters);
1044 if (itFirstNewTrack == mTracks.end()) {
1045 itFirstNewTrack = itNewTrack;
1046 }
1047
1048 // transfert the list of new excluded clusters to the full list for the initial candidate
1049 moveClusters(newExcludedClusters, excludedClusters);
1050 }
1051 }
1052 }
1053
1054 // loop over all DEs of plane2
1055 for (auto& de2 : mClusters[plane2]) {
1056
1057 // skip DE without cluster
1058 if (de2.second == nullptr) {
1059 continue;
1060 }
1061
1062 // get the list of excluded clusters for the DE
1063 auto itExcludedClusters = excludedClusters.find(de2.first);
1064 bool hasExcludedClusters = (itExcludedClusters != excludedClusters.end());
1065
1066 // look for cluster candidate in this DE
1067 for (const auto cluster2 : *de2.second) {
1068
1069 // skip excluded clusters (in particular the ones already attached together with a cluster on plane1)
1070 if (hasExcludedClusters && itExcludedClusters->second.count(cluster2->uid) > 0) {
1071 continue;
1072 }
1073
1074 // try to add the current cluster
1075 if (!isCompatible(paramAtChamber, *cluster2, paramAtCluster2)) {
1076 continue;
1077 }
1078
1079 // add it to the list of excluded clusters for this candidate
1080 excludedClusters[de2.first].emplace(cluster2->uid);
1081
1082 // skip tracks out of limits
1083 if (!isAcceptable(paramAtCluster2)) {
1084 continue;
1085 }
1086
1087 // continue the tracking to the next chambers and attach the cluster to the new tracks if any
1088 auto itNewTrack = addClustersAndFollowTrack(itTrack, paramAtCluster2, nullptr, nextChamber, lastChamber, newExcludedClusters);
1089 if (itFirstNewTrack == mTracks.end()) {
1090 itFirstNewTrack = itNewTrack;
1091 }
1092
1093 // transfert the list of new excluded clusters to the full list for the initial candidate
1094 moveClusters(newExcludedClusters, excludedClusters);
1095 }
1096 }
1097
1098 // reset the current parameters to the ones at that chamber if needed, not adding MCS effects yet
1099 if (itTrack->getCurrentChamber() != chamber) {
1100 setCurrentParam(*itTrack, paramAtChamber, chamber);
1101 }
1102
1103 return itFirstNewTrack;
1104}
1105
1106//_________________________________________________________________________________________________
1107std::list<Track>::iterator TrackFinder::addClustersAndFollowTrack(std::list<Track>::iterator& itTrack, const TrackParam& paramAtCluster1,
1108 const TrackParam* paramAtCluster2, int nextChamber, int lastChamber,
1109 std::unordered_map<int, std::unordered_set<uint32_t>>& excludedClusters)
1110{
1116
1117 // the list of excluded clusters must be empty here as new cluster(s) are being attached to the candidate
1118 assert(excludedClusters.empty());
1119
1120 auto itFirstNewTrack(mTracks.end());
1121
1122 if (nextChamber >= 0) {
1123
1124 // the tracking continues from paramAtCluster2, if any, or from paramAtCluster1
1125 if (paramAtCluster2) {
1126 print("addClustersAndFollowTrack: 2 clusters found (", paramAtCluster1.getClusterPtr()->getIdAsString(), " and ",
1127 paramAtCluster2->getClusterPtr()->getIdAsString(), "). Continuing the tracking of candidate #", getTrackIndex(itTrack));
1128 setCurrentParam(*itTrack, *paramAtCluster2, paramAtCluster2->getClusterPtr()->getChamberId());
1129 } else {
1130 print("addClustersAndFollowTrack: 1 cluster found (", paramAtCluster1.getClusterPtr()->getIdAsString(),
1131 "). Continuing the tracking of candidate #", getTrackIndex(itTrack));
1132 setCurrentParam(*itTrack, paramAtCluster1, paramAtCluster1.getClusterPtr()->getChamberId());
1133 }
1134
1135 // follow the track to the next chamber, which can be skipped if it is on the same station
1136 bool canSkip = (nextChamber / 2 == paramAtCluster1.getClusterPtr()->getChamberId() / 2);
1137 auto itNewTrack = followTrackInChamber(itTrack, nextChamber, lastChamber, canSkip, excludedClusters);
1138 itFirstNewTrack = itNewTrack;
1139
1140 // attach the current cluster(s) to every new tracks found
1141 if (itNewTrack != mTracks.end()) {
1142 while (itNewTrack != itTrack) {
1143 itNewTrack->addParamAtCluster(paramAtCluster1);
1144 if (paramAtCluster2) {
1145 itNewTrack->addParamAtCluster(*paramAtCluster2);
1146 print("addClustersAndFollowTrack: add to the candidate at position #", getTrackIndex(itNewTrack),
1147 " clusters ", paramAtCluster1.getClusterPtr()->getIdAsString(), " and ", paramAtCluster2->getClusterPtr()->getIdAsString());
1148 } else {
1149 print("addClustersAndFollowTrack: add to the candidate at position #", getTrackIndex(itNewTrack),
1150 " cluster ", paramAtCluster1.getClusterPtr()->getIdAsString());
1151 }
1152 ++itNewTrack;
1153 }
1154 }
1155
1156 } else {
1157
1158 // or duplicate the track and add the new cluster(s)
1159 itFirstNewTrack = addTrack(itTrack, *itTrack);
1160 itFirstNewTrack->addParamAtCluster(paramAtCluster1);
1161 if (paramAtCluster2) {
1162 itFirstNewTrack->addParamAtCluster(*paramAtCluster2);
1163 print("addClustersAndFollowTrack: duplicating candidate at position #", getTrackIndex(itFirstNewTrack), " to add 2 clusters (",
1164 paramAtCluster1.getClusterPtr()->getIdAsString(), " and ", paramAtCluster2->getClusterPtr()->getIdAsString(), ")");
1165 } else {
1166 print("addClustersAndFollowTrack: duplicating candidate at position #", getTrackIndex(itFirstNewTrack),
1167 " to add 1 cluster (", paramAtCluster1.getClusterPtr()->getIdAsString(), ")");
1168 }
1169 }
1170
1171 return itFirstNewTrack;
1172}
1173
1174//_________________________________________________________________________________________________
1175void TrackFinder::improveTracks()
1176{
1181
1182 for (auto itTrack = mTracks.begin(); itTrack != mTracks.end();) {
1183
1184 bool removeTrack(false);
1185
1186 // At the first step, only run the smoother
1187 auto itStartingParam = std::prev(itTrack->rend());
1188
1189 while (true) {
1190
1191 // Refit the part of the track affected by the cluster removal, run the smoother, but do not finalize
1192 try {
1193 mTrackFitter.fit(*itTrack, true, false, (itStartingParam == itTrack->rbegin()) ? nullptr : &itStartingParam);
1194 } catch (exception const&) {
1195 removeTrack = true;
1196 break;
1197 }
1198
1199 // Identify removable clusters
1200 itTrack->tagRemovableClusters(requestedStationMask(), !TrackerParam::Instance().moreCandidates);
1201
1202 // Look for the cluster with the worst local chi2
1203 double worstLocalChi2(-1.);
1204 auto itWorstParam(itTrack->end());
1205 for (auto itParam = itTrack->begin(); itParam != itTrack->end(); ++itParam) {
1206 if (itParam->getLocalChi2() > worstLocalChi2) {
1207 worstLocalChi2 = itParam->getLocalChi2();
1208 itWorstParam = itParam;
1209 }
1210 }
1211
1212 // If the worst chi2 is under requirement then the track is improved
1213 if (worstLocalChi2 < mMaxChi2ForImprovement) {
1214 break;
1215 }
1216
1217 // If the worst cluster is not removable then the track cannot be improved
1218 if (!itWorstParam->isRemovable()) {
1219 removeTrack = true;
1220 break;
1221 }
1222
1223 // Remove the worst cluster
1224 auto itNextParam = itTrack->removeParamAtCluster(itWorstParam);
1225
1226 // Decide from where to refit the track: from the cluster next the one suppressed or
1227 // from scratch if the removed cluster was used to compute the tracking seed
1228 itStartingParam = itTrack->rbegin();
1229 auto itNextToNextParam = (itNextParam == itTrack->end()) ? itNextParam : std::next(itNextParam);
1230 while (itNextToNextParam != itTrack->end()) {
1231 if (itNextToNextParam->getClusterPtr()->getChamberId() != itNextParam->getClusterPtr()->getChamberId()) {
1232 itStartingParam = std::make_reverse_iterator(++itNextParam);
1233 break;
1234 }
1235 ++itNextToNextParam;
1236 }
1237 }
1238
1239 // Remove the track if it couldn't be improved
1240 if (removeTrack) {
1241 print("improveTracks: removing candidate at position #", getTrackIndex(itTrack));
1242 itTrack = mTracks.erase(itTrack);
1243 } else {
1244 ++itTrack;
1245 }
1246 }
1247}
1248
1249//_________________________________________________________________________________________________
1250void TrackFinder::removeConnectedTracks(int stMin, int stMax)
1251{
1255
1256 if (mTracks.size() < 2) {
1257 return;
1258 }
1259
1260 int chMin = 2 * stMin;
1261 int chMax = 2 * stMax + 1;
1262 int nPlane = 2 * (chMax - chMin + 1);
1263
1264 // first loop to fill the arrays of cluster Ids, number of fired chambers and normalized chi2
1265 std::vector<uint32_t> ClIds(nPlane * mTracks.size());
1266 std::vector<uint8_t> nFiredCh(mTracks.size());
1267 std::vector<double> nChi2(mTracks.size());
1268 int previousCh(-1);
1269 int iTrack(0);
1270 for (auto itTrack = mTracks.begin(); itTrack != mTracks.end(); ++itTrack, ++iTrack) {
1271 for (auto itParam = itTrack->rbegin(); itParam != itTrack->rend(); ++itParam) {
1272 int ch = itParam->getClusterPtr()->getChamberId();
1273 if (ch != previousCh) {
1274 ++nFiredCh[iTrack];
1275 previousCh = ch;
1276 }
1277 if (ch >= chMin && ch <= chMax) {
1278 ClIds[nPlane * iTrack + 2 * (ch - chMin) + itParam->getClusterPtr()->getDEId() % 2] = itParam->getClusterPtr()->uid;
1279 }
1280 }
1281 nChi2[iTrack] = itTrack->first().getTrackChi2() / (itTrack->getNDF() - 1);
1282 }
1283
1284 // second loop to tag the tracks to remove
1285 std::vector<bool> remove(mTracks.size(), false);
1286 int iindex = ClIds.size() - 1;
1287 for (int iTrack1 = mTracks.size() - 1; iTrack1 > -1; --iTrack1, iindex -= nPlane) {
1288 int jindex = iindex - nPlane;
1289 for (int iTrack2 = iTrack1 - 1; iTrack2 > -1; --iTrack2) {
1290 for (int iPlane = nPlane; iPlane > 0; --iPlane) {
1291 if (ClIds[iindex] == ClIds[jindex] && ClIds[iindex] > 0) {
1292 if (nFiredCh[iTrack2] > nFiredCh[iTrack1] ||
1293 (nFiredCh[iTrack2] == nFiredCh[iTrack1] && nChi2[iTrack2] < nChi2[iTrack1])) {
1294 remove[iTrack1] = true;
1295 } else {
1296 remove[iTrack2] = true;
1297 }
1298 iindex -= iPlane;
1299 jindex -= iPlane;
1300 break;
1301 }
1302 --iindex;
1303 --jindex;
1304 }
1305 iindex += nPlane;
1306 }
1307 }
1308
1309 // third loop to remove them. That way all combinations are tested.
1310 iTrack = 0;
1311 for (auto itTrack = mTracks.begin(); itTrack != mTracks.end(); ++iTrack) {
1312 if (remove[iTrack]) {
1313 print("removeConnectedTracks: removing candidate at position #", getTrackIndex(itTrack));
1314 itTrack = mTracks.erase(itTrack);
1315 } else {
1316 ++itTrack;
1317 }
1318 }
1319}
1320
1321//_________________________________________________________________________________________________
1322void TrackFinder::refineTracks()
1323{
1325
1326 for (auto itTrack = mTracks.begin(); itTrack != mTracks.end();) {
1327 try {
1328 mTrackFitter.fit(*itTrack);
1329 ++itTrack;
1330 } catch (exception const&) {
1331 print("refineTracks: removing candidate at position #", getTrackIndex(itTrack));
1332 itTrack = mTracks.erase(itTrack);
1333 }
1334 }
1335}
1336
1337//_________________________________________________________________________________________________
1338void TrackFinder::finalize()
1339{
1341 for (auto& track : mTracks) {
1342 for (auto& param : track) {
1343 param.setParameters(param.getSmoothParameters());
1344 param.setCovariances(param.getSmoothCovariances());
1345 }
1346 }
1347}
1348
1349//_________________________________________________________________________________________________
1350void TrackFinder::createTrack(const Cluster& cl1, const Cluster& cl2)
1351{
1355
1356 if (mTracks.size() >= TrackerParam::Instance().maxCandidates) {
1358 throw length_error(string("Too many track candidates (") + mTracks.size() + ")");
1359 }
1360
1361 // create the track and the trackParam at each cluster
1362 Track& track = mTracks.emplace_back();
1363 track.createParamAtCluster(cl2);
1364 track.createParamAtCluster(cl1);
1365 print("createTrack: creating candidate at position #", getTrackIndex(std::prev(mTracks.end())),
1366 " with clusters ", cl1.getIdAsString(), " and ", cl2.getIdAsString());
1367
1368 // fit the track using the Kalman filter
1369 try {
1370 mTrackFitter.fit(track, false);
1371 } catch (exception const&) {
1372 print("... fit failed --> removing it");
1373 mTracks.erase(std::prev(mTracks.end()));
1374 }
1375}
1376
1377//_________________________________________________________________________________________________
1378std::list<Track>::iterator TrackFinder::addTrack(const std::list<Track>::iterator& pos, const Track& track)
1379{
1382 if (mTracks.size() >= TrackerParam::Instance().maxCandidates) {
1384 throw length_error(string("Too many track candidates (") + mTracks.size() + ")");
1385 }
1386 return mTracks.emplace(pos, track);
1387}
1388
1389//_________________________________________________________________________________________________
1390bool TrackFinder::isAcceptable(const TrackParam& param) const
1391{
1393
1394 // impact parameter dispersion**2 due to MCS in chambers
1395 int chamber = param.getClusterPtr()->getChamberId();
1396 double impactMCS2(0.);
1397 if (TrackExtrap::isFieldON() && chamber < 6) {
1398 // track momentum is known
1399 for (int iCh = 0; iCh <= chamber; ++iCh) {
1400 impactMCS2 += SDefaultChamberZ[iCh] * SDefaultChamberZ[iCh] * TrackExtrap::getMCSAngle2(param, SChamberThicknessInX0[iCh], 1.);
1401 }
1402 } else {
1403 // track momentum is unknown
1404 for (Int_t iCh = 0; iCh <= chamber; ++iCh) {
1405 impactMCS2 += SDefaultChamberZ[iCh] * SDefaultChamberZ[iCh] * mMaxMCSAngle2[iCh];
1406 }
1407 }
1408
1409 const auto& trackerParam = TrackerParam::Instance();
1410 const TMatrixD& paramCov = param.getCovariances();
1411 double z = param.getZ();
1412
1413 // check if non bending impact parameter is within tolerances
1414 double nonBendingImpactParam = TMath::Abs(param.getNonBendingCoor() - z * param.getNonBendingSlope());
1415 double nonBendingImpactParamErr = TMath::Sqrt(paramCov(0, 0) + z * z * paramCov(1, 1) - 2. * z * paramCov(0, 1) + impactMCS2);
1416 if ((nonBendingImpactParam - trackerParam.sigmaCutForTracking * nonBendingImpactParamErr) > (3. * trackerParam.nonBendingVertexDispersion)) {
1417 return false;
1418 }
1419
1420 if (TrackExtrap::isFieldON()) { // depending whether the field is ON or OFF
1421 // check if bending momentum is within tolerances
1422 double bendingMomentum = TMath::Abs(1. / param.getInverseBendingMomentum());
1423 double bendingMomentumErr = TMath::Sqrt(paramCov(4, 4)) * bendingMomentum * bendingMomentum;
1424 if (chamber < 6 && (bendingMomentum + trackerParam.sigmaCutForTracking * bendingMomentumErr) < SMinBendingMomentum) {
1425 return false;
1426 } else if ((bendingMomentum + 3. * bendingMomentumErr) < SMinBendingMomentum) {
1427 return false;
1428 }
1429 } else {
1430 // or check if bending impact parameter is within tolerances
1431 double bendingImpactParam = TMath::Abs(param.getBendingCoor() - z * param.getBendingSlope());
1432 double bendingImpactParamErr = TMath::Sqrt(paramCov(2, 2) + z * z * paramCov(3, 3) - 2. * z * paramCov(2, 3) + impactMCS2);
1433 if ((bendingImpactParam - trackerParam.sigmaCutForTracking * bendingImpactParamErr) > (3. * trackerParam.bendingVertexDispersion)) {
1434 return false;
1435 }
1436 }
1437
1438 return true;
1439}
1440
1441//_________________________________________________________________________________________________
1442void TrackFinder::prepareForwardTracking(std::list<Track>::iterator& itTrack, bool runSmoother)
1443{
1447
1448 if (runSmoother) {
1449 auto itStartingParam = std::prev(itTrack->rend());
1450 mTrackFitter.fit(*itTrack, true, false, &itStartingParam, true);
1451 }
1452
1453 setCurrentParam(*itTrack, itTrack->last(), itTrack->last().getClusterPtr()->getChamberId(), runSmoother);
1454}
1455
1456//_________________________________________________________________________________________________
1457void TrackFinder::prepareBackwardTracking(std::list<Track>::iterator& itTrack, bool refit)
1458{
1462
1463 if (refit) {
1464 mTrackFitter.fit(*itTrack, false);
1465 }
1466
1467 setCurrentParam(*itTrack, itTrack->first(), itTrack->first().getClusterPtr()->getChamberId());
1468}
1469
1470//_________________________________________________________________________________________________
1471void TrackFinder::setCurrentParam(Track& track, const TrackParam& param, int chamber, bool smoothed)
1472{
1475
1476 track.setCurrentParam(param, chamber);
1477
1478 if (smoothed) {
1479 TrackParam& currentParam = track.getCurrentParam();
1480 currentParam.setParameters(param.getSmoothParameters());
1481 currentParam.setCovariances(param.getSmoothCovariances());
1482 }
1483
1484 if (param.getClusterPtr()) {
1485 TrackParam& currentParam = track.getCurrentParam();
1486 currentParam.resetPropagator();
1487 TrackExtrap::addMCSEffect(currentParam, SChamberThicknessInX0[chamber], -1.);
1488 }
1489}
1490
1491//_________________________________________________________________________________________________
1492bool TrackFinder::propagateCurrentParam(Track& track, int chamber)
1493{
1497
1498 TrackParam& currentParam = track.getCurrentParam();
1499 int& currentChamber = track.getCurrentChamber();
1500 while (currentChamber != chamber) {
1501
1502 currentChamber += (chamber < currentChamber) ? -1 : 1;
1503
1504 if (!TrackExtrap::extrapToZCov(currentParam, SDefaultChamberZ[currentChamber], true)) {
1505 track.invalidateCurrentParam();
1506 return false;
1507 }
1508
1509 TrackExtrap::addMCSEffect(currentParam, SChamberThicknessInX0[currentChamber], -1.);
1510 }
1511
1512 return true;
1513}
1514
1515//_________________________________________________________________________________________________
1516bool TrackFinder::areUsed(const Cluster& cl1, const Cluster& cl2, const std::vector<std::array<uint32_t, 4>>& usedClusters)
1517{
1519 int iCl1 = cl1.getDEId() % 2;
1520 int iCl2 = 2 + cl2.getDEId() % 2;
1521 for (const auto& clusters : usedClusters) {
1522 if (clusters[iCl1] == cl1.uid && clusters[iCl2] == cl2.uid) {
1523 return true;
1524 }
1525 }
1526 return false;
1527}
1528
1529//_________________________________________________________________________________________________
1530void TrackFinder::excludeClustersFromIdenticalTracks(const std::array<uint32_t, 4>& currentClusters,
1531 const std::vector<std::array<uint32_t, 8>>& usedClusters,
1532 std::unordered_map<int, std::unordered_set<uint32_t>>& excludedClusters)
1533{
1536
1537 for (const auto& clusters : usedClusters) {
1538
1539 bool identicalTrack(true);
1540 for (int iCl = 0; iCl < 4; ++iCl) {
1541 if (clusters[iCl] != currentClusters[iCl] && currentClusters[iCl] > 0) {
1542 identicalTrack = false;
1543 break;
1544 }
1545 }
1546
1547 if (identicalTrack) {
1548 for (int iCl = 4; iCl < 8; ++iCl) {
1549 if (clusters[iCl] > 0) {
1550 excludedClusters[Cluster::getDEId(clusters[iCl])].emplace(clusters[iCl]);
1551 }
1552 }
1553 }
1554 }
1555}
1556
1557//_________________________________________________________________________________________________
1558void TrackFinder::moveClusters(std::unordered_map<int, std::unordered_set<uint32_t>>& source, std::unordered_map<int, std::unordered_set<uint32_t>>& destination)
1559{
1561 for (auto& sourceDE : source) {
1562 destination[sourceDE.first].insert(sourceDE.second.begin(), sourceDE.second.end());
1563 }
1564 source.clear();
1565}
1566
1567//_________________________________________________________________________________________________
1568bool TrackFinder::isCompatible(const TrackParam& param, const Cluster& cluster, TrackParam& paramAtCluster)
1569{
1572
1573 // fast try to add the current cluster
1574 if (!tryOneClusterFast(param, cluster)) {
1575 return false;
1576 }
1577
1578 // try to add the current cluster accurately
1579 if (tryOneCluster(param, cluster, paramAtCluster) >= mMaxChi2ForTracking) {
1580 return false;
1581 }
1582
1583 // save the extrapolated parameters and covariances for the smoother
1584 paramAtCluster.setExtrapParameters(paramAtCluster.getParameters());
1585 paramAtCluster.setExtrapCovariances(paramAtCluster.getCovariances());
1586
1587 // compute the new track parameters including the cluster using the Kalman filter
1588 try {
1589 mTrackFitter.runKalmanFilter(paramAtCluster);
1590 } catch (exception const&) {
1591 return false;
1592 }
1593
1594 return true;
1595}
1596
1597//_________________________________________________________________________________________________
1598bool TrackFinder::tryOneClusterFast(const TrackParam& param, const Cluster& cluster)
1599{
1604
1605 ++mNCallTryOneClusterFast;
1606
1607 double dZ = cluster.getZ() - param.getZ();
1608 double dX = cluster.getX() - (param.getNonBendingCoor() + param.getNonBendingSlope() * dZ);
1609 double dY = cluster.getY() - (param.getBendingCoor() + param.getBendingSlope() * dZ);
1610 const TMatrixD& paramCov = param.getCovariances();
1611 double errX2 = paramCov(0, 0) + dZ * dZ * paramCov(1, 1) + 2. * dZ * paramCov(0, 1) + mChamberResolutionX2;
1612 double errY2 = paramCov(2, 2) + dZ * dZ * paramCov(3, 3) + 2. * dZ * paramCov(2, 3) + mChamberResolutionY2;
1613
1614 double dXmax = TrackerParam::Instance().sigmaCutForTracking * TMath::Sqrt(2. * errX2) + SMaxNonBendingDistanceToTrack;
1615 double dYmax = TrackerParam::Instance().sigmaCutForTracking * TMath::Sqrt(2. * errY2) + SMaxBendingDistanceToTrack;
1616
1617 if (TMath::Abs(dX) > dXmax || TMath::Abs(dY) > dYmax) {
1618 return false;
1619 }
1620 return true;
1621}
1622
1623//_________________________________________________________________________________________________
1624double TrackFinder::tryOneCluster(const TrackParam& param, const Cluster& cluster, TrackParam& paramAtCluster)
1625{
1630
1631 ++mNCallTryOneCluster;
1632
1633 // Extrapolate the track parameters and covariances at the z position of the cluster
1634 paramAtCluster = param;
1635 paramAtCluster.setClusterPtr(&cluster);
1636 if (!TrackExtrap::extrapToZCov(paramAtCluster, cluster.getZ(), true)) {
1637 return mTrackFitter.getMaxChi2();
1638 }
1639
1640 // Compute the cluster-track residuals in bending and non bending directions
1641 double dX = cluster.getX() - paramAtCluster.getNonBendingCoor();
1642 double dY = cluster.getY() - paramAtCluster.getBendingCoor();
1643
1644 // Combine the cluster and track resolutions and covariances
1645 const TMatrixD& paramCov = paramAtCluster.getCovariances();
1646 double sigmaX2 = paramCov(0, 0) + mChamberResolutionX2;
1647 double sigmaY2 = paramCov(2, 2) + mChamberResolutionY2;
1648 double covXY = paramCov(0, 2);
1649 double det = sigmaX2 * sigmaY2 - covXY * covXY;
1650
1651 // Compute and return the matching chi2
1652 if (det == 0.) {
1653 return mTrackFitter.getMaxChi2();
1654 }
1655 return (dX * dX * sigmaY2 + dY * dY * sigmaX2 - 2. * dX * dY * covXY) / det;
1656}
1657
1658//_________________________________________________________________________________________________
1659uint8_t TrackFinder::requestedStationMask() const
1660{
1663 uint8_t mask(0);
1664 for (int i = 0; i < 5; ++i) {
1665 if (TrackerParam::Instance().requestStation[i]) {
1666 mask |= (1 << i);
1667 }
1668 }
1669 return mask;
1670}
1671
1672//_________________________________________________________________________________________________
1673int TrackFinder::getTrackIndex(const std::list<Track>::iterator& itCurrentTrack) const
1674{
1679
1680 if (mDebugLevel < 1) {
1681 return -3;
1682 }
1683
1684 if (itCurrentTrack == mTracks.end()) {
1685 return -1;
1686 }
1687
1688 int index(0);
1689 for (auto itTrack = mTracks.begin(); itTrack != itCurrentTrack; ++itTrack) {
1690 if (itTrack == mTracks.end()) {
1691 return -2;
1692 }
1693 ++index;
1694 }
1695
1696 return index;
1697}
1698
1699//_________________________________________________________________________________________________
1700void TrackFinder::printTracks() const
1701{
1703 if (mDebugLevel > 1) {
1704 for (const auto& track : mTracks) {
1705 track.print();
1706 }
1707 }
1708}
1709
1710//_________________________________________________________________________________________________
1711void TrackFinder::printTrack(const Track& track) const
1712{
1714 if (mDebugLevel > 1) {
1715 track.print();
1716 }
1717}
1718
1719//_________________________________________________________________________________________________
1720void TrackFinder::printTrackParam(const TrackParam& trackParam) const
1721{
1723 if (mDebugLevel > 1) {
1724 trackParam.print();
1725 }
1726}
1727
1728//_________________________________________________________________________________________________
1729template <class... Args>
1730void TrackFinder::print(Args... args) const
1731{
1733 if (mDebugLevel > 0) {
1734 (cout << ... << args) << "\n";
1735 }
1736}
1737
1738//_________________________________________________________________________________________________
1740{
1742 LOG(info) << "number of candidates tracked = " << mNCandidates;
1744 LOG(info) << "number of times tryOneClusterFast() is called = " << mNCallTryOneClusterFast;
1745 LOG(info) << "number of times tryOneCluster() is called = " << mNCallTryOneCluster;
1746}
1747
1748//_________________________________________________________________________________________________
1750{
1752 LOG(info) << "findTrackCandidates duration = " << mTimeFindCandidates.count() << " s";
1753 LOG(info) << "findMoreTrackCandidates duration = " << mTimeFindMoreCandidates.count() << " s";
1754 LOG(info) << "followTracks duration = " << mTimeFollowTracks.count() << " s";
1755 LOG(info) << "improveTracks duration = " << mTimeImproveTracks.count() << " s";
1756 LOG(info) << "removeConnectedTracks duration = " << mTimeCleanTracks.count() << " s";
1757 LOG(info) << "refineTracks duration = " << mTimeRefineTracks.count() << " s";
1758}
1759
1760} // namespace mch
1761} // 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.
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 void useExtrapV2(bool extrapV2=true)
Switch to Runge-Kutta extrapolation v2.
Definition TrackExtrap.h:50
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()
const std::list< Track > & findTracks(gsl::span< const Cluster > clusters)
void initField(float l3Current, float dipoleCurrent)
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
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
GLsizei GLsizei GLchar * source
Definition glcorearb.h:798
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
o2::track::TrackParCov Track
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.
uint16_t de
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Cluster > clusters