Project
Loading...
Searching...
No Matches
MatchTOF.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#include <TTree.h>
12#include <cassert>
13
14#include <fairlogger/Logger.h>
15#include "Field/MagneticField.h"
16#include "Field/MagFieldFast.h"
17#include "TOFBase/Geo.h"
18
20
23#include "MathUtils/Cartesian.h"
24#include "MathUtils/Utils.h"
29
30#include <Math/SMatrix.h>
31#include <Math/SVector.h>
32#include <TFile.h>
33#include <TGeoGlobalMagField.h>
38
40
44
47#include "TOFBase/Utils.h"
48
49#ifdef WITH_OPENMP
50#include <omp.h>
51#endif
52
53using namespace o2::globaltracking;
60
61bool MatchTOF::mHasFillScheme = false;
62bool MatchTOF::mFillScheme[o2::constants::lhc::LHCMaxBunches] = {0};
63
65
66//______________________________________________
67void MatchTOF::run(const o2::globaltracking::RecoContainer& inp, unsigned long firstTForbit)
68{
69 mFirstTForbit = firstTForbit;
70
71 if (!mMatchParams) {
73 mSigmaTimeCut = mMatchParams->nsigmaTimeCut;
74 }
75
77 mRecoCont = &inp;
78 mStartIR = inp.startIR;
79 updateTimeDependentParams();
80
81 mTimerMatchTPC.Reset();
82 mTimerMatchITSTPC.Reset();
83 mTimerTot.Reset();
84
85 mCalibInfoTOF.clear();
86
87 for (int i = 0; i < trkType::SIZEALL; i++) {
88 mMatchedTracks[i].clear();
89 mOutTOFLabels[i].clear();
90 }
91
92 for (int it = 0; it < trkType::SIZE; it++) {
93 for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) {
94 mMatchedTracksIndex[sec][it].clear();
95 mTracksWork[sec][it].clear();
96 mTrackGid[sec][it].clear();
97 mLTinfos[sec][it].clear();
98 if (mMCTruthON) {
99 mTracksLblWork[sec][it].clear();
100 }
101 mTracksSectIndexCache[it][sec].clear();
102 mTracksSeed[it][sec].clear();
103 }
104 }
105
106 for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) {
107 mSideTPC[sec].clear();
108 mExtraTPCFwdTime[sec].clear();
109 }
110
111 mTimerTot.Start();
112 bool isPrepareTOFClusters = prepareTOFClusters();
113 mTimerTot.Stop();
114 LOGF(info, "Timing prepareTOFCluster: Cpu: %.3e s Real: %.3e s in %d slots", mTimerTot.CpuTime(), mTimerTot.RealTime(), mTimerTot.Counter() - 1);
115
116 if (!isPrepareTOFClusters) { // check cluster before of tracks to see also if MC is required
117 return;
118 }
119
120 mTimerTot.Start();
121 if (!prepareTPCData()) {
122 return;
123 }
124 mTimerTot.Stop();
125 LOGF(info, "Timing prepare TPC tracks: Cpu: %.3e s Real: %.3e s in %d slots", mTimerTot.CpuTime(), mTimerTot.RealTime(), mTimerTot.Counter() - 1);
126
127 mTimerTot.Start();
128 if (!prepareFITData()) {
129 return;
130 }
131 mTimerTot.Stop();
132 LOGF(info, "Timing prepare FIT data: Cpu: %.3e s Real: %.3e s in %d slots", mTimerTot.CpuTime(), mTimerTot.RealTime(), mTimerTot.Counter() - 1);
133
134 mTimerTot.Start();
135 std::array<uint32_t, 18> nMatches = {0};
136 // run matching (this can be multi-thread)
137 mTimerMatchITSTPC.Start();
138
139 for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) {
140 mMatchedTracksPairsSec[sec].clear(); // new sector
141 }
142
144
145 if (mIsITSTPCused || mIsTPCTRDused || mIsITSTPCTRDused) {
146#ifdef WITH_OPENMP
147#pragma omp parallel for schedule(dynamic) num_threads(mNlanes)
148#endif
149 for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) {
150 doMatching(sec);
151 }
152 }
153 mTimerMatchITSTPC.Stop();
154
155 mTimerMatchTPC.Start();
156 if (mIsTPCused) {
157#ifdef WITH_OPENMP
158#pragma omp parallel for schedule(dynamic) num_threads(mNlanes)
159#endif
160 for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) {
161 doMatchingForTPC(sec);
162 }
163 }
164 mTimerMatchTPC.Stop();
165
166 // finalize
167 for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) {
168 if (mStoreMatchable) {
169 // if MC check if good or fake matches
170 if (mMCTruthON) {
171 for (auto& matchingPair : mMatchedTracksPairsSec[sec]) {
172 int trkType = (int)matchingPair.getTrackType();
173 int itrk = matchingPair.getIdLocal();
174 const auto& labelsTOF = mTOFClusLabels->getLabels(matchingPair.getTOFClIndex());
175 const auto& labelTrack = mTracksLblWork[sec][trkType][itrk];
176
177 // we have not found the track label among those associated to the TOF cluster --> fake match! We will associate the label of the main channel, but negative
178 bool fake = true;
179 for (auto& lbl : labelsTOF) {
180 if (labelTrack == lbl) { // compares src, evID, trID, ignores fake flag.
181 fake = false;
182 }
183 }
184 if (fake) {
185 matchingPair.setFakeMatch();
186 }
187 }
188 } else {
189 for (auto& matchingPair : mMatchedTracksPairsSec[sec]) {
190 int bct0 = int((matchingPair.getSignal() - matchingPair.getLTIntegralOut().getTOF(0) + 5000) * Geo::BC_TIME_INPS_INV); // bc taken assuming speed of light (el) and 5 ns of margin
191 if (bct0 < 0) { // if negative time (it can happen at the beginng of the TF int was truncated per excess... adjusting)
192 bct0--;
193 }
194 float tof = matchingPair.getSignal() - bct0 * Geo::BC_TIME_INPS;
195 if (std::abs(tof - matchingPair.getLTIntegralOut().getTOF(2)) < 600) {
196 } else if (std::abs(tof - matchingPair.getLTIntegralOut().getTOF(3)) < 600) {
197 } else if (std::abs(tof - matchingPair.getLTIntegralOut().getTOF(4)) < 600) {
198 } else if (std::abs(tof - matchingPair.getLTIntegralOut().getTOF(0)) < 600) {
199 } else if (std::abs(tof - matchingPair.getLTIntegralOut().getTOF(1)) < 600) {
200 } else if (std::abs(tof - matchingPair.getLTIntegralOut().getTOF(5)) < 600) {
201 } else if (std::abs(tof - matchingPair.getLTIntegralOut().getTOF(6)) < 600) {
202 } else if (std::abs(tof - matchingPair.getLTIntegralOut().getTOF(7)) < 600) {
203 } else if (std::abs(tof - matchingPair.getLTIntegralOut().getTOF(8)) < 600) {
204 } else { // no pion, kaon, proton, electron, muon, deuteron, triton, 3He, 4He
205 matchingPair.setFakeMatch();
206 }
207 }
208 }
209 }
210
211 LOG(debug) << "...done. Now check the best matches";
212 nMatches[sec] = mMatchedTracksPairsSec[sec].size();
213 selectBestMatches(sec);
214
215 if (mStoreMatchable) {
216 for (auto& matchingPair : mMatchedTracksPairsSec[sec]) {
217 trkType trkTypeSplitted = trkType::TPC;
218 auto sourceID = matchingPair.getTrackRef().getSource();
220 trkTypeSplitted = trkType::ITSTPC;
221 } else if (sourceID == o2::dataformats::GlobalTrackID::TPCTRD) {
222 trkTypeSplitted = trkType::TPCTRD;
223 } else if (sourceID == o2::dataformats::GlobalTrackID::ITSTPCTRD) {
224 trkTypeSplitted = trkType::ITSTPCTRD;
225 }
226 matchingPair.setTrackType(trkTypeSplitted);
227 }
228 }
229 }
230 std::string nMatchesStr = "Number of pairs matched per sector: ";
231 for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) {
232 nMatchesStr += fmt::format("{} : {} ; ", sec, nMatches[sec]);
233 }
234 LOG(info) << nMatchesStr;
235 // re-arrange outputs from constrained/unconstrained to the 4 cases (TPC, ITS-TPC, TPC-TRD, ITS-TPC-TRD) to be implemented as soon as TPC-TRD and ITS-TPC-TRD tracks available
236
237 mIsTPCused = false;
238 mIsITSTPCused = false;
239 mIsTPCTRDused = false;
240 mIsITSTPCTRDused = false;
241
242 mTimerTot.Stop();
243 LOGF(info, "Timing Do Matching: Cpu: %.3e s Real: %.3e s in %d slots", mTimerTot.CpuTime(), mTimerTot.RealTime(), mTimerTot.Counter() - 1);
244 LOGF(info, "Timing Do Matching Constrained: Cpu: %.3e s Real: %.3e s in %d slots", mTimerMatchITSTPC.CpuTime(), mTimerMatchITSTPC.RealTime(), mTimerMatchITSTPC.Counter() - 1);
245 LOGF(info, "Timing Do Matching TPC : Cpu: %.3e s Real: %.3e s in %d slots", mTimerMatchTPC.CpuTime(), mTimerMatchTPC.RealTime(), mTimerMatchTPC.Counter() - 1);
246}
247
248//______________________________________________
250{
251 mTPCVDrift = v.refVDrift * v.corrFact;
252 mTPCVDriftCorrFact = v.corrFact;
253 mTPCVDriftRef = v.refVDrift;
254 mTPCDriftTimeOffset = v.getTimeOffset();
255}
256
257//______________________________________________
259{
260 mTPCCorrMaps = maph;
261 mCTPLumi = lumi;
262}
263
264//______________________________________________
265void MatchTOF::print() const
266{
268
269 LOG(info) << "****** component for the matching of tracks to TOF clusters ******";
270
271 LOG(info) << "MC truth: " << (mMCTruthON ? "on" : "off");
272 LOG(info) << "Time tolerance: " << mTimeTolerance;
273 LOG(info) << "Space tolerance: " << mSpaceTolerance;
274 LOG(info) << "SigmaTimeCut: " << mSigmaTimeCut;
275
276 LOG(info) << "**********************************************************************";
277}
278//______________________________________________
280{
282}
283//_____________________________________________________
284bool MatchTOF::prepareFITData()
285{
286 // If available, read FIT Info
287 if (mIsFIT) {
288 mFITRecPoints = mRecoCont->getFT0RecPoints();
289 // prepareInteractionTimes();
290 }
291 return true;
292}
293//______________________________________________
294int MatchTOF::prepareInteractionTimes()
295{
296 // do nothing. If you think it can be useful have a look at MatchTPCITS
297 return 0;
298}
299//______________________________________________
300void MatchTOF::printGrouping(const std::vector<o2::dataformats::MatchInfoTOFReco>& origin, const std::vector<std::vector<o2::dataformats::MatchInfoTOFReco>>& grouped)
301{
302 printf("Original vector\n");
303 for (const auto& seed : origin) {
304 printf("Pair: track=%d TOFcl=%d\n", seed.getIdLocal(), seed.getTOFClIndex());
305 }
306
307 printf("\nGroups\n");
308 int ngroups = 0;
309 for (const auto& gr : grouped) {
310 ngroups++;
311 printf("Group %d\n", ngroups);
312 for (const auto& seed : gr) {
313 printf("Pair: track=%d TOFcl=%d\n", seed.getIdLocal(), seed.getTOFClIndex());
314 }
315 }
316}
317//______________________________________________
318void MatchTOF::groupingMatch(const std::vector<o2::dataformats::MatchInfoTOFReco>& origin, std::vector<std::vector<o2::dataformats::MatchInfoTOFReco>>& grouped, std::vector<std::vector<int>>& firstEls, std::vector<std::vector<int>>& secondEls)
319{
320 grouped.clear();
321 firstEls.clear();
322 secondEls.clear();
323
324 std::vector<o2::dataformats::MatchInfoTOFReco> dummy;
325 std::vector<int> dummyInt;
326
327 int pos = 0;
328 int posInVector = 0;
329 std::vector<int> alreadyUsed(origin.size(), 0);
330 while (posInVector < origin.size()) { // go ahead if there are elements
331 if (alreadyUsed[posInVector]) {
332 posInVector++;
333 continue;
334 }
335 bool found = true;
336 grouped.push_back(dummy);
337 auto& trkId = firstEls.emplace_back(dummyInt);
338 auto& cluId = secondEls.emplace_back(dummyInt);
339
340 // first element is the seed
341 const auto& seed = origin[posInVector];
342 trkId.push_back(seed.getIdLocal());
343 cluId.push_back(seed.getTOFClIndex());
344 // remove element added to the current group
345 grouped[pos].push_back(seed);
346 alreadyUsed[posInVector] = true;
347 posInVector++;
348
349 while (found) {
350 found = false;
351 for (int i = posInVector; i < origin.size(); i++) {
352 if (alreadyUsed[i]) {
353 continue;
354 }
355 const auto& seed = origin[i];
356 int matchFirst = -1;
357 int matchSecond = -1;
358 for (const int& ind : trkId) {
359 if (seed.getIdLocal() == ind) {
360 matchFirst = ind;
361 break;
362 }
363 }
364 for (const int& ind : cluId) {
365 if (seed.getTOFClIndex() == ind) {
366 matchSecond = ind;
367 break;
368 }
369 }
370
371 if (matchFirst >= 0 || matchSecond >= 0) { // belong to this group
372 if (matchFirst < 0) {
373 trkId.push_back(seed.getIdLocal());
374 }
375 if (matchSecond < 0) {
376 cluId.push_back(seed.getTOFClIndex());
377 }
378 grouped[pos].push_back(seed);
379 alreadyUsed[i] = true;
380 found = true;
381 break;
382 }
383 }
384 }
385 pos++; // move to the next group
386 }
387}
388
389//______________________________________________
390bool MatchTOF::prepareTPCData()
391{
392 mNotPropagatedToTOF[trkType::UNCONS] = 0;
393 mNotPropagatedToTOF[trkType::CONSTR] = 0;
394
395 auto creator = [this](auto& trk, GTrackID gid, float time0, float terr) {
396 const int nclustersMin = 0;
397 if constexpr (isTPCTrack<decltype(trk)>()) {
398 if (trk.getNClusters() < nclustersMin) {
399 return true;
400 }
401
402 if (std::abs(trk.getQ2Pt()) > mMaxInvPt) {
403 return true;
404 }
405 this->addTPCSeed(trk, gid, time0, terr);
406 }
407 if constexpr (isTPCITSTrack<decltype(trk)>()) {
408 if (trk.getParamOut().getX() < o2::constants::geom::XTPCOuterRef - 1.) {
409 return true;
410 }
411 this->addITSTPCSeed(trk, gid, time0, terr);
412 }
413 if constexpr (isTRDTrack<decltype(trk)>()) {
414 this->addTRDSeed(trk, gid, time0, terr);
415 }
416 return true;
417 };
418 mRecoCont->createTracksVariadic(creator);
419
420#ifdef WITH_OPENMP
421#pragma omp parallel for schedule(dynamic) num_threads(mNlanes)
422#endif
423 for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) {
424 if (mIsTPCused) {
425 propagateTPCTracks(sec);
426 }
427 if (mIsITSTPCused || mIsTPCTRDused || mIsITSTPCTRDused) {
428 propagateConstrTracks(sec);
429 }
430 }
431
432 // re-assign tracks which change sector (no multi-threading)
433 std::array<float, 3> globalPos;
434 for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) {
435 if (mIsTPCused) {
436 for (auto& it : mTracksSeed[trkType::UNCONS][sec]) {
437 auto& pair = mTracksWork[sec][trkType::UNCONS][it];
438 auto& trc = pair.first;
439 trc.getXYZGlo(globalPos);
440 int sector = o2::math_utils::angle2Sector(TMath::ATan2(globalPos[1], globalPos[0]));
441
442 int itnew = mTracksWork[sector][trkType::UNCONS].size();
443
444 mSideTPC[sector].push_back(mSideTPC[sec][it]);
445 mExtraTPCFwdTime[sector].push_back(mExtraTPCFwdTime[sec][it]);
446 mTracksWork[sector][trkType::UNCONS].emplace_back(pair);
447 mTrackGid[sector][trkType::UNCONS].emplace_back(mTrackGid[sec][trkType::UNCONS][it]);
448
449 if (mMCTruthON) {
450 mTracksLblWork[sector][trkType::UNCONS].emplace_back(mTracksLblWork[sec][trkType::UNCONS][it]);
451 }
452 mLTinfos[sector][trkType::UNCONS].emplace_back(mLTinfos[sec][trkType::UNCONS][it]);
453 mVZtpcOnly[sector].push_back(mVZtpcOnly[sec][it]);
454 mTracksSectIndexCache[trkType::UNCONS][sector].push_back(itnew);
455 }
456 }
457
458 for (auto& it : mTracksSeed[trkType::CONSTR][sec]) {
459 auto& pair = mTracksWork[sec][trkType::CONSTR][it];
460 auto& trc = pair.first;
461 trc.getXYZGlo(globalPos);
462 int sector = o2::math_utils::angle2Sector(TMath::ATan2(globalPos[1], globalPos[0]));
463
464 int itnew = mTracksWork[sector][trkType::CONSTR].size();
465
466 mTracksWork[sector][trkType::CONSTR].emplace_back(pair);
467 mTrackGid[sector][trkType::CONSTR].emplace_back(mTrackGid[sec][trkType::CONSTR][it]);
468
469 if (mMCTruthON) {
470 mTracksLblWork[sector][trkType::CONSTR].emplace_back(mTracksLblWork[sec][trkType::CONSTR][it]);
471 }
472 mLTinfos[sector][trkType::CONSTR].emplace_back(mLTinfos[sec][trkType::CONSTR][it]);
473 mTracksSectIndexCache[trkType::CONSTR][sector].push_back(itnew);
474 }
475 }
476
477 for (int it = 0; it < trkType::SIZE; it++) {
478 for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) {
479 mMatchedTracksIndex[sec][it].resize(mTracksWork[sec][it].size());
480 std::fill(mMatchedTracksIndex[sec][it].begin(), mMatchedTracksIndex[sec][it].end(), -1); // initializing all to -1
481 }
482 }
483
484 if (mIsTPCused) {
485 LOG(debug) << "Number of UNCONSTRAINED tracks that failed to be propagated to TOF = " << mNotPropagatedToTOF[trkType::UNCONS];
486
487 // sort tracks in each sector according to their time (increasing in time)
488#ifdef WITH_OPENMP
489#pragma omp parallel for schedule(dynamic) num_threads(mNlanes)
490#endif
491 for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) {
492 auto& indexCache = mTracksSectIndexCache[trkType::UNCONS][sec];
493 LOG(debug) << "Sorting sector" << sec << " | " << indexCache.size() << " tracks";
494 if (!indexCache.size()) {
495 continue;
496 }
497 std::sort(indexCache.begin(), indexCache.end(), [this, sec](int a, int b) {
498 auto& trcA = mTracksWork[sec][trkType::UNCONS][a].second;
499 auto& trcB = mTracksWork[sec][trkType::UNCONS][b].second;
500 return ((trcA.getTimeStamp() - trcA.getTimeStampError()) - (trcB.getTimeStamp() - trcB.getTimeStampError()) < 0.);
501 });
502 } // loop over tracks of single sector
503 }
504 if (mIsITSTPCused || mIsTPCTRDused || mIsITSTPCTRDused) {
505 LOG(debug) << "Number of CONSTRAINED tracks that failed to be propagated to TOF = " << mNotPropagatedToTOF[trkType::CONSTR];
506
507 // sort tracks in each sector according to their time (increasing in time)
508#ifdef WITH_OPENMP
509#pragma omp parallel for schedule(dynamic) num_threads(mNlanes)
510#endif
511 for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) {
512 auto& indexCache = mTracksSectIndexCache[trkType::CONSTR][sec];
513 LOG(debug) << "Sorting sector" << sec << " | " << indexCache.size() << " tracks";
514 if (!indexCache.size()) {
515 continue;
516 }
517 std::sort(indexCache.begin(), indexCache.end(), [this, sec](int a, int b) {
518 auto& trcA = mTracksWork[sec][trkType::CONSTR][a].second;
519 auto& trcB = mTracksWork[sec][trkType::CONSTR][b].second;
520 return ((trcA.getTimeStamp() - mSigmaTimeCut * trcA.getTimeStampError()) - (trcB.getTimeStamp() - mSigmaTimeCut * trcB.getTimeStampError()) < 0.);
521 });
522 } // loop over tracks of single sector
523 }
524
525 if (mRecoCont->inputsTPCclusters) {
526 mTPCClusterIdxStruct = &mRecoCont->inputsTPCclusters->clusterIndex;
527 mTPCTracksArray = mRecoCont->getTPCTracks();
528 mTPCTrackClusIdx = mRecoCont->getTPCTracksClusterRefs();
529 mTPCRefitterShMap = mRecoCont->clusterShMapTPC;
530 mTPCRefitterOccMap = mRecoCont->occupancyMapTPC;
531 }
532
533 return true;
534}
535
536//______________________________________________
537void MatchTOF::propagateTPCTracks(int sec)
538{
539 auto& trkWork = mTracksWork[sec][trkType::UNCONS];
540
541 for (int it = 0; it < trkWork.size(); it++) {
542 o2::track::TrackParCov& trc = trkWork[it].first;
543
544 o2::track::TrackLTIntegral& intLT0 = mLTinfos[sec][trkType::UNCONS][it];
545
546 const auto& trackTune = TrackTuneParams::Instance();
547 if (!trackTune.sourceLevelTPC) { // correct only if TPC track was not corrected at the source level
548 if (trackTune.useTPCOuterCorr) {
549 trc.updateParams(trackTune.tpcParOuter);
550 }
551 if (trackTune.tpcCovOuterType != TrackTuneParams::AddCovType::Disable) { // only TRD-refitted track have cov.matrix already man>
552 trc.updateCov(mCovDiagOuter, trackTune.tpcCovOuterType == TrackTuneParams::AddCovType::WithCorrelations);
553 }
554 }
555 if (!propagateToRefXWithoutCov(trc, mXRef, 10, mBz)) { // we first propagate to 371 cm without considering the covariance matri
556 mNotPropagatedToTOF[trkType::UNCONS]++;
557 continue;
558 }
559
560 if (trc.getX() < o2::constants::geom::XTPCOuterRef - 1.) {
561 if (!propagateToRefXWithoutCov(trc, o2::constants::geom::XTPCOuterRef, 10, mBz) || std::abs(trc.getZ()) > Geo::MAXHZTOF) { // we check that the propagat>
562 mNotPropagatedToTOF[trkType::UNCONS]++;
563 continue;
564 }
565 }
566
567 o2::base::Propagator::Instance()->estimateLTFast(intLT0, trc);
568
569 // the "rough" propagation worked; now we can propagate considering also the cov matrix
570 if (!propagateToRefX(trc, mXRef, 2, intLT0)) { // || std::abs(trc.getZ()) > Geo::MAXHZTOF) { // we check that the propagation with the cov matrix w>
571 mNotPropagatedToTOF[trkType::UNCONS]++;
572 continue;
573 }
574
575 // printf("time0 %f -> %f (diff = %f, err = %f)\n",trackTime0, time0, trackTime0 - time0, terr);
576 // printf("time errors %f,%f -> %f,%f\n",(_tr.getDeltaTBwd() + 5) * mTPCTBinMUS,(_tr.getDeltaTFwd() + 5) * mTPCTBinMUS,trackTime0 - time0 + terr, ti>
577
578 std::array<float, 3> globalPos;
579 trc.getXYZGlo(globalPos);
580 int sector = o2::math_utils::angle2Sector(TMath::ATan2(globalPos[1], globalPos[0]));
581
582 if (sector == sec) {
583 mTracksSectIndexCache[trkType::UNCONS][sector].push_back(it);
584 } else {
585 mTracksSeed[trkType::UNCONS][sec].push_back(it); // to be moved to another sector
586 }
587 }
588}
589//______________________________________________
590void MatchTOF::propagateConstrTracks(int sec)
591{
592 std::array<float, 3> globalPos;
593
594 auto& trkWork = mTracksWork[sec][trkType::CONSTR];
595
596 for (int it = 0; it < trkWork.size(); it++) {
597 o2::track::TrackParCov& trc = trkWork[it].first;
598 o2::track::TrackLTIntegral& intLT0 = mLTinfos[sec][trkType::CONSTR][it];
599
600 // propagate to matching Xref
601 if (!propagateToRefXWithoutCov(trc, mXRef, 2, mBz)) { // we first propagate to 371 cm without considering the covariance matrix
602 mNotPropagatedToTOF[trkType::CONSTR]++;
603 continue;
604 }
605
606 // the "rough" propagation worked; now we can propagate considering also the cov matrix
607 if (!propagateToRefX(trc, mXRef, 2, intLT0) || std::abs(trc.getZ()) > Geo::MAXHZTOF) { // we check that the propagation with the cov matrix worked;>
608 mNotPropagatedToTOF[trkType::CONSTR]++;
609 continue;
610 }
611
612 trc.getXYZGlo(globalPos);
613
614 int sector = o2::math_utils::angle2Sector(TMath::ATan2(globalPos[1], globalPos[0]));
615
616 if (sector == sec) {
617 mTracksSectIndexCache[trkType::CONSTR][sector].push_back(it);
618 } else {
619 mTracksSeed[trkType::CONSTR][sec].push_back(it); // to be moved to another sector
620 }
621 }
622}
623//______________________________________________
624void MatchTOF::addITSTPCSeed(const o2::dataformats::TrackTPCITS& _tr, o2::dataformats::GlobalTrackID srcGID, float time0, float terr)
625{
626 mIsITSTPCused = true;
627
628 auto trc = _tr.getParamOut();
629 o2::track::TrackLTIntegral intLT0 = _tr.getLTIntegralOut();
630
631 timeEst ts(time0, terr);
632 addConstrainedSeed(trc, srcGID, intLT0, ts);
633}
634//______________________________________________
635void MatchTOF::addConstrainedSeed(o2::track::TrackParCov& trc, o2::dataformats::GlobalTrackID srcGID, o2::track::TrackLTIntegral intLT0, timeEst timeMUS)
636{
637 std::array<float, 3> globalPos;
638 trc.getXYZGlo(globalPos);
639
640 int sector = o2::math_utils::angle2Sector(TMath::ATan2(globalPos[1], globalPos[0]));
641
642 // create working copy of track param
643 mTracksWork[sector][trkType::CONSTR].emplace_back(std::make_pair(trc, timeMUS));
644 mTrackGid[sector][trkType::CONSTR].emplace_back(srcGID);
645 mLTinfos[sector][trkType::CONSTR].emplace_back(intLT0);
646
647 if (mMCTruthON) {
648 mTracksLblWork[sector][trkType::CONSTR].emplace_back(mRecoCont->getTPCITSTrackMCLabel(srcGID));
649 }
650
651 //delete trc; // Check: is this needed?
652} //______________________________________________
653void MatchTOF::addTRDSeed(const o2::trd::TrackTRD& _tr, o2::dataformats::GlobalTrackID srcGID, float time0, float terr)
654{
655 if (srcGID.getSource() == o2::dataformats::GlobalTrackID::TPCTRD) {
656 mIsTPCTRDused = true;
657 } else if (srcGID.getSource() == o2::dataformats::GlobalTrackID::ITSTPCTRD) {
658 mIsITSTPCTRDused = true;
659 } else { // shouldn't happen
660 LOG(error) << "MatchTOF::addTRDSee: srcGID.getSource() = " << srcGID.getSource() << " not allowed; expected ones are: " << o2::dataformats::GlobalTrackID::TPCTRD << " and " << o2::dataformats::GlobalTrackID::ITSTPCTRD;
661 }
662
663 auto trc = _tr.getOuterParam();
664
665 o2::track::TrackLTIntegral intLT0 = _tr.getLTIntegralOut();
666
667 // o2::dataformats::TimeStampWithError<float, float>
668 timeEst ts(time0, terr + mExtraTimeToleranceTRD);
669
670 addConstrainedSeed(trc, srcGID, intLT0, ts);
671}
672//______________________________________________
673void MatchTOF::addTPCSeed(const o2::tpc::TrackTPC& _tr, o2::dataformats::GlobalTrackID srcGID, float time0, float terr)
674{
675 mIsTPCused = true;
676
677 std::array<float, 3> globalPos;
678
679 // create working copy of track param
680 timeEst timeInfo;
681 // set
682 float extraErr = 0;
683 if (mIsCosmics) {
684 extraErr = 100;
685 }
686
687 float trackTime0 = _tr.getTime0() * mTPCTBinMUS;
688 timeInfo.setTimeStampError((_tr.getDeltaTBwd() + 5) * mTPCTBinMUS + extraErr);
689 // timeInfo.setTimeStampError(trackTime0 - time0 + terr + extraErr);
690 timeInfo.setTimeStamp(trackTime0);
691
692 auto trc = _tr.getOuterParam();
693 trc.getXYZGlo(globalPos);
694
695 int sector = o2::math_utils::angle2Sector(TMath::ATan2(globalPos[1], globalPos[0]));
696
697 mSideTPC[sector].push_back(_tr.hasASideClustersOnly() ? 1 : (_tr.hasCSideClustersOnly() ? -1 : 0));
698 mExtraTPCFwdTime[sector].push_back((_tr.getDeltaTFwd() + 5) * mTPCTBinMUS + extraErr);
699 // mExtraTPCFwdTime[sector].push_back(time0 + terr - trackTime0 + extraErr);
700 mTracksWork[sector][trkType::UNCONS].emplace_back(std::make_pair(trc, timeInfo));
701 mTrackGid[sector][trkType::UNCONS].emplace_back(srcGID);
702
703 if (mMCTruthON) {
704 mTracksLblWork[sector][trkType::UNCONS].emplace_back(mRecoCont->getTPCTrackMCLabel(srcGID));
705 }
706 o2::track::TrackLTIntegral intLT0; // mTPCTracksWork.back().getLTIntegralOut(); // we get the integrated length from TPC-ITC outward propagation
707 // compute track length up to now
708 mLTinfos[sector][trkType::UNCONS].emplace_back(intLT0);
709 float vz0 = _tr.getZAt(0, mBz);
710 if (std::abs(vz0) > 9000) {
711 vz0 = _tr.getZ() - _tr.getX() * _tr.getTgl();
712 }
713 mVZtpcOnly[sector].push_back(vz0);
714
715 /*
716 const auto& trackTune = TrackTuneParams::Instance();
717 if (!trackTune.sourceLevelTPC) { // correct only if TPC track was not corrected at the source level
718 if (trackTune.useTPCOuterCorr) {
719 trc.updateParams(trackTune.tpcParOuter);
720 }
721 if (trackTune.tpcCovOuterType != TrackTuneParams::AddCovType::Disable) { // only TRD-refitted track have cov.matrix already manipulated
722 trc.updateCov(mCovDiagOuter, trackTune.tpcCovOuterType == TrackTuneParams::AddCovType::WithCorrelations);
723 }
724 }
725 if (!propagateToRefXWithoutCov(trc, mXRef, 10, mBz)) { // we first propagate to 371 cm without considering the covariance matri
726 mNotPropagatedToTOF[trkType::UNCONS]++;
727 return;
728 }
729
730 if (trc.getX() < o2::constants::geom::XTPCOuterRef - 1.) {
731 if (!propagateToRefX(trc, o2::constants::geom::XTPCOuterRef, 10, intLT0) || std::abs(trc.getZ()) > Geo::MAXHZTOF) { // we check that the propagation with the cov matrix worked; CHECK: can it happ
732 mNotPropagatedToTOF[trkType::UNCONS]++;
733 return;
734 }
735 }
736
737 // the "rough" propagation worked; now we can propagate considering also the cov matrix
738 if (!propagateToRefX(trc, mXRef, 2, intLT0)) { // || std::abs(trc.getZ()) > Geo::MAXHZTOF) { // we check that the propagation with the cov matrix worked; CHECK: can it happen that it does not if the prop>
739 mNotPropagatedToTOF[trkType::UNCONS]++;
740 return;
741 }
742
743 // printf("time0 %f -> %f (diff = %f, err = %f)\n",trackTime0, time0, trackTime0 - time0, terr);
744 // printf("time errors %f,%f -> %f,%f\n",(_tr.getDeltaTBwd() + 5) * mTPCTBinMUS,(_tr.getDeltaTFwd() + 5) * mTPCTBinMUS,trackTime0 - time0 + terr, time0 + terr - trackTime0);
745
746 trc.getXYZGlo(globalPos);
747 int sector = o2::math_utils::angle2Sector(TMath::ATan2(globalPos[1], globalPos[0]));
748
749 mTracksSectIndexCache[trkType::UNCONS][sector].push_back(it);
750 */
751 // delete trc; // Check: is this needed?
752}
753//______________________________________________
754bool MatchTOF::prepareTOFClusters()
755{
756 mTOFClustersArrayInp = mRecoCont->getTOFClusters();
757 mTOFClusLabels = mRecoCont->getTOFClustersMCLabels();
758 mMCTruthON = mTOFClusLabels && mTOFClusLabels->getNElements();
759
761
762 // copy the track params, propagate to reference X and build sector tables
763 mTOFClusWork.clear();
764 // mTOFClusWork.reserve(mNumOfClusters); // we cannot do this, we don't have mNumOfClusters yet
765 // if (mMCTruthON) {
766 // mTOFClusLblWork.clear();
767 // mTOFClusLblWork.reserve(mNumOfClusters);
768 // }
769
770 for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) {
771 mTOFClusSectIndexCache[sec].clear();
772 //mTOFClusSectIndexCache[sec].reserve(100 + 1.2 * mNumOfClusters / o2::constants::math::NSectors); // we cannot do this, we don't have mNumOfClusters yet
773 }
774
775 mNumOfClusters = 0;
776
777 int nClusterInCurrentChunk = mTOFClustersArrayInp.size();
778 LOG(debug) << "nClusterInCurrentChunk = " << nClusterInCurrentChunk;
779 mNumOfClusters += nClusterInCurrentChunk;
780 mTOFClusWork.reserve(mTOFClusWork.size() + mNumOfClusters);
781 for (int it = 0; it < nClusterInCurrentChunk; it++) {
782 const Cluster& clOrig = mTOFClustersArrayInp[it];
783 // create working copy of track param
784 mTOFClusWork.emplace_back(clOrig);
785 auto& cl = mTOFClusWork.back();
786 // cache work track index
787 mTOFClusSectIndexCache[cl.getSector()].push_back(mTOFClusWork.size() - 1);
788 }
789
790 // sort clusters in each sector according to their time (increasing in time)
791 for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) {
792 auto& indexCache = mTOFClusSectIndexCache[sec];
793 LOG(debug) << "Sorting sector" << sec << " | " << indexCache.size() << " TOF clusters";
794 if (!indexCache.size()) {
795 continue;
796 }
797 std::sort(indexCache.begin(), indexCache.end(), [this](int a, int b) {
798 auto& clA = mTOFClusWork[a];
799 auto& clB = mTOFClusWork[b];
800 return (clA.getTime() - clB.getTime()) < 0.;
801 });
802 } // loop over TOF clusters of single sector
803
804 if (mMatchedClustersIndex) {
805 delete[] mMatchedClustersIndex;
806 }
807 mMatchedClustersIndex = new int[mNumOfClusters];
808 std::fill_n(mMatchedClustersIndex, mNumOfClusters, -1); // initializing all to -1
809
810 return true;
811}
812//______________________________________________
813void MatchTOF::doMatching(int sec)
814{
815 trkType type = trkType::CONSTR;
816
818 auto& cacheTOF = mTOFClusSectIndexCache[sec]; // array of cached TOF cluster indices for this sector; reminder: they are ordered in time!
819 auto& cacheTrk = mTracksSectIndexCache[type][sec]; // array of cached tracks indices for this sector; reminder: they are ordered in time!
820 int nTracks = cacheTrk.size(), nTOFCls = cacheTOF.size();
821 LOG(debug) << "Matching sector " << sec << ": number of tracks: " << nTracks << ", number of TOF clusters: " << nTOFCls;
822 if (!nTracks || !nTOFCls) {
823 return;
824 }
825 int itof0 = 0; // starting index in TOF clusters for matching of the track
826 int detId[2][5]; // at maximum one track can fall in 2 strips during the propagation; the second dimention of the array is the TOF det index
827 float deltaPos[2][3]; // at maximum one track can fall in 2 strips during the propagation; the second dimention of the array is the residuals
828 o2::track::TrackLTIntegral trkLTInt[2]; // Here we store the integrated track length and time for the (max 2) matched strips
829 int nStepsInsideSameStrip[2] = {0, 0}; // number of propagation steps in the same strip (since we have maximum 2 strips, it has dimention = 2)
830 float deltaPosTemp[3];
831 std::array<float, 3> pos;
832 std::array<float, 3> posBeforeProp;
833 float posFloat[3];
834
835 // prematching for TPC only tracks (identify BC candidate to correct z for TPC track accordingly to v_drift)
836
837 LOG(debug) << "Trying to match %d tracks" << cacheTrk.size();
838 for (int itrk = 0; itrk < cacheTrk.size(); itrk++) {
839 for (int ii = 0; ii < 2; ii++) {
840 detId[ii][2] = -1; // before trying to match, we need to inizialize the detId corresponding to the strip number to -1; this is the array that we will use to save the det id of the maximum 2 strips matched
841 nStepsInsideSameStrip[ii] = 0;
842 }
843 int nStripsCrossedInPropagation = 0; // how many strips were hit during the propagation
844 auto& trackWork = mTracksWork[sec][type][cacheTrk[itrk]];
845 auto& trefTrk = trackWork.first;
846 float pt = trefTrk.getPt();
847 auto& intLT = mLTinfos[sec][type][cacheTrk[itrk]];
848 float timeShift = intLT.getL() * 33.35641; // integrated time for 0.75 beta particles in ps, to take into account the t.o.f. delay with respect the interaction BC
849 // using beta=0.75 to cover beta range [0.59 , 1.04] also for a 8 m track lenght with a 10 ns track resolution (TRD)
850
851 // Printf("intLT (before doing anything): length = %f, time (Pion) = %f", intLT.getL(), intLT.getTOF(o2::track::PID::Pion));
852 float minTrkTime = (trackWork.second.getTimeStamp() - mSigmaTimeCut * trackWork.second.getTimeStampError()) * 1.E6 + timeShift; // minimum time in ps
853 float maxTrkTime = (trackWork.second.getTimeStamp() + mSigmaTimeCut * trackWork.second.getTimeStampError()) * 1.E6 + timeShift + 100E3; // maximum time in ps + 100 ns for slow tracks (beta->0.2)
854 const float sqrt12inv = 1. / sqrt(12.);
855 float resT = (trackWork.second.getTimeStampError() + 100E-3) * sqrt12inv;
856 int istep = 1; // number of steps
857 float step = 1.0; // step size in cm
858
859 //uncomment for local debug
860 /*
861 //trefTrk.getXYZGlo(posBeforeProp);
862 //float posBeforeProp[3] = {trefTrk.getX(), trefTrk.getY(), trefTrk.getZ()}; // in local ref system
863 //printf("Global coordinates: posBeforeProp[0] = %f, posBeforeProp[1] = %f, posBeforeProp[2] = %f\n", posBeforeProp[0], posBeforeProp[1], posBeforeProp[2]);
864 //Printf("Radius xy = %f", TMath::Sqrt(posBeforeProp[0]*posBeforeProp[0] + posBeforeProp[1]*posBeforeProp[1]));
865 //Printf("Radius xyz = %f", TMath::Sqrt(posBeforeProp[0]*posBeforeProp[0] + posBeforeProp[1]*posBeforeProp[1] + posBeforeProp[2]*posBeforeProp[2]));
866 */
867
868 // initializing
869 for (int ii = 0; ii < 2; ii++) {
870 for (int iii = 0; iii < 5; iii++) {
871 detId[ii][iii] = -1;
872 }
873 }
874
875 int detIdTemp[5] = {-1, -1, -1, -1, -1}; // TOF detector id at the current propagation point
876
877 double reachedPoint = mXRef + istep * step;
878
879 while (propagateToRefX(trefTrk, reachedPoint, step, intLT) && nStripsCrossedInPropagation <= 2 && reachedPoint < Geo::RMAX) {
880 // while (o2::base::Propagator::Instance()->PropagateToXBxByBz(trefTrk, mXRef + istep * step, MAXSNP, step, 1, &intLT) && nStripsCrossedInPropagation <= 2 && mXRef + istep * step < Geo::RMAX) {
881
882 trefTrk.getXYZGlo(pos);
883 for (int ii = 0; ii < 3; ii++) { // we need to change the type...
884 posFloat[ii] = pos[ii];
885 }
886
887 // uncomment below only for local debug; this will produce A LOT of output - one print per propagation step
888 /*
889 Printf("posFloat[0] = %f, posFloat[1] = %f, posFloat[2] = %f", posFloat[0], posFloat[1], posFloat[2]);
890 Printf("radius xy = %f", TMath::Sqrt(posFloat[0]*posFloat[0] + posFloat[1]*posFloat[1]));
891 Printf("radius xyz = %f", TMath::Sqrt(posFloat[0]*posFloat[0] + posFloat[1]*posFloat[1] + posFloat[2]*posFloat[2]));
892 */
893
894 for (int idet = 0; idet < 5; idet++) {
895 detIdTemp[idet] = -1;
896 }
897
898 Geo::getPadDxDyDz(posFloat, detIdTemp, deltaPosTemp, sec);
899
900 reachedPoint += step;
901
902 if (detIdTemp[2] == -1) {
903 continue;
904 }
905
906 // uncomment below only for local debug; this will produce A LOT of output - one print per propagation step
907 //Printf("detIdTemp[0] = %d, detIdTemp[1] = %d, detIdTemp[2] = %d, detIdTemp[3] = %d, detIdTemp[4] = %d", detIdTemp[0], detIdTemp[1], detIdTemp[2], detIdTemp[3], detIdTemp[4]);
908 // if (nStripsCrossedInPropagation == 0) { // print in case you have a useful propagation
909 // LOG(debug) << "*********** We have crossed a strip during propagation!*********";
910 // LOG(debug) << "Global coordinates: pos[0] = " << pos[0] << ", pos[1] = " << pos[1] << ", pos[2] = " << pos[2];
911 // LOG(debug) << "detIdTemp[0] = " << detIdTemp[0] << ", detIdTemp[1] = " << detIdTemp[1] << ", detIdTemp[2] = " << detIdTemp[2] << ", detIdTemp[3] = " << detIdTemp[3] << ", detIdTemp[4] = " << detIdTemp[4];
912 // LOG(debug) << "deltaPosTemp[0] = " << deltaPosTemp[0] << ", deltaPosTemp[1] = " << deltaPosTemp[1] << " deltaPosTemp[2] = " << deltaPosTemp[2];
913 // } else {
914 // LOG(debug) << "*********** We have NOT crossed a strip during propagation!*********";
915 // LOG(debug) << "Global coordinates: pos[0] = " << pos[0] << ", pos[1] = " << pos[1] << ", pos[2] = " << pos[2];
916 // LOG(debug) << "detIdTemp[0] = " << detIdTemp[0] << ", detIdTemp[1] = " << detIdTemp[1] << ", detIdTemp[2] = " << detIdTemp[2] << ", detIdTemp[3] = " << detIdTemp[3] << ", detIdTemp[4] = " << detIdTemp[4];
917 // LOG(debug) << "deltaPosTemp[0] = " << deltaPosTemp[0] << ", deltaPosTemp[1] = " << deltaPosTemp[1] << " deltaPosTemp[2] = " << deltaPosTemp[2];
918 // }
919
920 // check if after the propagation we are in a TOF strip
921 // we ended in a TOF strip
922 // LOG(debug) << "nStripsCrossedInPropagation = " << nStripsCrossedInPropagation << ", detId[nStripsCrossedInPropagation][0] = " << detId[nStripsCrossedInPropagation][0] << ", detIdTemp[0] = " << detIdTemp[0] << ", detId[nStripsCrossedInPropagation][1] = " << detId[nStripsCrossedInPropagation][1] << ", detIdTemp[1] = " << detIdTemp[1] << ", detId[nStripsCrossedInPropagation][2] = " << detId[nStripsCrossedInPropagation][2] << ", detIdTemp[2] = " << detIdTemp[2];
923
924 if (nStripsCrossedInPropagation == 0 || // we are crossing a strip for the first time...
925 (nStripsCrossedInPropagation >= 1 && (detId[nStripsCrossedInPropagation - 1][0] != detIdTemp[0] || detId[nStripsCrossedInPropagation - 1][1] != detIdTemp[1] || detId[nStripsCrossedInPropagation - 1][2] != detIdTemp[2]))) { // ...or we are crossing a new strip
926 if (nStripsCrossedInPropagation == 0) {
927 LOG(debug) << "We cross a strip for the first time";
928 }
929 if (nStripsCrossedInPropagation == 2) {
930 break; // we have already matched 2 strips, we cannot match more
931 }
932 nStripsCrossedInPropagation++;
933 }
934 //Printf("nStepsInsideSameStrip[nStripsCrossedInPropagation-1] = %d", nStepsInsideSameStrip[nStripsCrossedInPropagation - 1]);
935 if (nStepsInsideSameStrip[nStripsCrossedInPropagation - 1] == 0) {
936 // fine propagation inside the strip -> 1 mm step
937 trkLTInt[nStripsCrossedInPropagation - 1] = intLT;
938 // temporary variables since propagation can fail
939 int detIdTemp2[5] = {0, 0, 0, 0, 0};
940 float deltaPosTemp2[3] = {deltaPosTemp[0], deltaPosTemp[1], deltaPosTemp[2]};
941 int nstep = 0;
942 const int maxnstep = 50;
943 float xStart = trefTrk.getX();
944 float xStop = xStart;
945 trefTrk.getXYZGlo(pos);
946 for (int ii = 0; ii < 3; ii++) { // we need to change the type...
947 posFloat[ii] = pos[ii];
948 }
949 while (deltaPosTemp2[1] < -0.05 && detIdTemp2[2] != -1 && nstep < maxnstep) { // continuing propagation if dy is negative and we are still inside the strip volume
950 nstep++;
951 xStop += 0.1;
952 propagateToRefXWithoutCov(trefTrk, xStop, 0.1, mBz, posFloat);
953
954 Geo::getPadDxDyDz(posFloat, detIdTemp2, deltaPosTemp2, sec);
955 if (detIdTemp2[2] != -1) { // if propation was succesful -> update params
956 float dx = deltaPosTemp2[0] - deltaPosTemp[0];
957 float dy = deltaPosTemp2[1] - deltaPosTemp[1];
958 float dz = deltaPosTemp2[2] - deltaPosTemp[2];
959 updateTL(trkLTInt[nStripsCrossedInPropagation - 1], sqrt(dx * dx + dy * dy + dz * dz));
960 detIdTemp[0] = detIdTemp2[0];
961 detIdTemp[1] = detIdTemp2[1];
962 detIdTemp[2] = detIdTemp2[2];
963 detIdTemp[3] = detIdTemp2[3];
964 detIdTemp[4] = detIdTemp2[4];
965 deltaPosTemp[0] = deltaPosTemp2[0];
966 deltaPosTemp[1] = deltaPosTemp2[1];
967 deltaPosTemp[2] = deltaPosTemp2[2];
968 }
969 }
970
971 // adjust accordingly to DeltaY
972 updateTL(trkLTInt[nStripsCrossedInPropagation - 1], -deltaPosTemp[1]);
973
974 detId[nStripsCrossedInPropagation - 1][0] = detIdTemp[0];
975 detId[nStripsCrossedInPropagation - 1][1] = detIdTemp[1];
976 detId[nStripsCrossedInPropagation - 1][2] = detIdTemp[2];
977 detId[nStripsCrossedInPropagation - 1][3] = detIdTemp[3];
978 detId[nStripsCrossedInPropagation - 1][4] = detIdTemp[4];
979 deltaPos[nStripsCrossedInPropagation - 1][0] = deltaPosTemp[0];
980 deltaPos[nStripsCrossedInPropagation - 1][1] = deltaPosTemp[1];
981 deltaPos[nStripsCrossedInPropagation - 1][2] = deltaPosTemp[2];
982 // Printf("intLT (after matching to strip %d): length = %f, time (Pion) = %f", nStripsCrossedInPropagation - 1, trkLTInt[nStripsCrossedInPropagation - 1].getL(), trkLTInt[nStripsCrossedInPropagation - 1].getTOF(o2::track::PID::Pion));
983 nStepsInsideSameStrip[nStripsCrossedInPropagation - 1]++;
984 }
985 /* // obsolete
986 else { // a further propagation step in the same strip -> update info (we sum up on all matching with strip - we will divide for the number of steps a bit below)
987 // N.B. the integrated length and time are taken (at least for now) from the first time we crossed the strip, so here we do nothing with those
988 deltaPos[nStripsCrossedInPropagation - 1][0] += deltaPosTemp[0] + (detIdTemp[4] - detId[nStripsCrossedInPropagation - 1][4]) * Geo::XPAD; // residual in x
989 deltaPos[nStripsCrossedInPropagation - 1][1] += deltaPosTemp[1]; // residual in y
990 deltaPos[nStripsCrossedInPropagation - 1][2] += deltaPosTemp[2] + (detIdTemp[3] - detId[nStripsCrossedInPropagation - 1][3]) * Geo::ZPAD; // residual in z
991 nStepsInsideSameStrip[nStripsCrossedInPropagation - 1]++;
992 }
993 */
994 }
995
996 for (Int_t imatch = 0; imatch < nStripsCrossedInPropagation; imatch++) {
997 // we take as residual the average of the residuals along the propagation in the same strip
998 deltaPos[imatch][0] /= nStepsInsideSameStrip[imatch];
999 deltaPos[imatch][1] /= nStepsInsideSameStrip[imatch];
1000 deltaPos[imatch][2] /= nStepsInsideSameStrip[imatch];
1001 }
1002
1003 if (nStripsCrossedInPropagation == 0) {
1004 continue; // the track never hit a TOF strip during the propagation
1005 }
1006 bool foundCluster = false;
1007 for (auto itof = itof0; itof < nTOFCls; itof++) {
1008 // printf("itof = %d\n", itof);
1009 auto& trefTOF = mTOFClusWork[cacheTOF[itof]];
1010 // compare the times of the track and the TOF clusters - remember that they both are ordered in time!
1011 //Printf("trefTOF.getTime() = %f, maxTrkTime = %f, minTrkTime = %f", trefTOF.getTime(), maxTrkTime, minTrkTime);
1012
1013 if (trefTOF.getTime() < minTrkTime) { // this cluster has a time that is too small for the current track, we will get to the next one
1014 //Printf("In trefTOF.getTime() < minTrkTime");
1015 itof0 = itof + 1; // but for the next track that we will check, we will ignore this cluster (the time is anyway too small)
1016 continue;
1017 }
1018 if (trefTOF.getTime() > maxTrkTime) { // no more TOF clusters can be matched to this track
1019 break;
1020 }
1021
1022 int mainChannel = trefTOF.getMainContributingChannel();
1023 int indices[5];
1024 Geo::getVolumeIndices(mainChannel, indices);
1025
1026 // compute fine correction using cluster position instead of pad center
1027 // this because in case of multiple-hit cluster position is averaged on all pads contributing to the cluster (then error position matrix can be used for Chi2 if nedeed)
1028 int ndigits = 1;
1029 float posCorr[3] = {0, 0, 0};
1030
1031 if (trefTOF.isBitSet(Cluster::kLeft)) {
1032 posCorr[0] += Geo::XPAD, ndigits++;
1033 }
1034 if (trefTOF.isBitSet(Cluster::kUpLeft)) {
1035 posCorr[0] += Geo::XPAD, posCorr[2] -= Geo::ZPAD, ndigits++;
1036 }
1037 if (trefTOF.isBitSet(Cluster::kDownLeft)) {
1038 posCorr[0] += Geo::XPAD, posCorr[2] += Geo::ZPAD, ndigits++;
1039 }
1040 if (trefTOF.isBitSet(Cluster::kUp)) {
1041 posCorr[2] -= Geo::ZPAD, ndigits++;
1042 }
1043 if (trefTOF.isBitSet(Cluster::kDown)) {
1044 posCorr[2] += Geo::ZPAD, ndigits++;
1045 }
1046 if (trefTOF.isBitSet(Cluster::kRight)) {
1047 posCorr[0] -= Geo::XPAD, ndigits++;
1048 }
1049 if (trefTOF.isBitSet(Cluster::kUpRight)) {
1050 posCorr[0] -= Geo::XPAD, posCorr[2] -= Geo::ZPAD, ndigits++;
1051 }
1052 if (trefTOF.isBitSet(Cluster::kDownRight)) {
1053 posCorr[0] -= Geo::XPAD, posCorr[2] += Geo::ZPAD, ndigits++;
1054 }
1055
1056 float ndifInv = 1. / ndigits;
1057 if (ndigits > 1) {
1058 posCorr[0] *= ndifInv;
1059 posCorr[1] *= ndifInv;
1060 posCorr[2] *= ndifInv;
1061 }
1062
1063 int trackIdTOF;
1064 int eventIdTOF;
1065 int sourceIdTOF;
1066 for (auto iPropagation = 0; iPropagation < nStripsCrossedInPropagation; iPropagation++) {
1067 int bct0 = int((mTOFClusWork[cacheTOF[itof]].getTime() - trkLTInt[iPropagation].getTOF(0) + 5000) * Geo::BC_TIME_INPS_INV); // bc taken assuming speed of light (el) and 5 ns of margin
1068 if (bct0 < 0) { // if negative time (it can happen at the beginng of the TF int was truncated per excess... adjusting)
1069 bct0--;
1070 }
1071 float tof = mTOFClusWork[cacheTOF[itof]].getTime() - bct0 * Geo::BC_TIME_INPS;
1072 if (tof - trkLTInt[iPropagation].getTOF(6) > 2000) { // reject tracks slower than triton
1073 continue;
1074 }
1075 float cosangle = TMath::Cos(Geo::getAngles(indices[1], indices[2]) * TMath::DegToRad());
1076 const float errXinvMin = 1. / (mMatchParams->maxResX * mMatchParams->maxResX);
1077 const float errZinvMin = 1. / (mMatchParams->maxResZ * mMatchParams->maxResZ);
1078 float errXinv2 = 1. / (trefTrk.getSigmaY2());
1079 float errZinv2 = 1. / (trefTrk.getSigmaZ2() * cosangle); // should be valid only at eta=0
1080
1081 if (errXinv2 < errXinvMin) {
1082 errXinv2 = errXinvMin;
1083 }
1084 if (errZinv2 < errZinvMin) {
1085 errZinv2 = errZinvMin;
1086 }
1087
1088 LOG(debug) << "TOF Cluster [" << itof << ", " << cacheTOF[itof] << "]: indices = " << indices[0] << ", " << indices[1] << ", " << indices[2] << ", " << indices[3] << ", " << indices[4];
1089 LOG(debug) << "Propagated Track [" << itrk << "]: detId[" << iPropagation << "] = " << detId[iPropagation][0] << ", " << detId[iPropagation][1] << ", " << detId[iPropagation][2] << ", " << detId[iPropagation][3] << ", " << detId[iPropagation][4];
1090 float resX = deltaPos[iPropagation][0] - (indices[4] - detId[iPropagation][4]) * Geo::XPAD + posCorr[0]; // readjusting the residuals due to the fact that the propagation fell in a pad that was not exactly the one of the cluster
1091 float resZ = deltaPos[iPropagation][2] - (indices[3] - detId[iPropagation][3]) * Geo::ZPAD + posCorr[2]; // readjusting the residuals due to the fact that the propagation fell in a pad that was not exactly the one of the cluster
1092 float resY = deltaPos[iPropagation][1];
1093 float resXor = resX;
1094 float resZor = resZ;
1095 float res = TMath::Sqrt(resX * resX + resZ * resZ);
1096
1097 if (resX < -1.25) { // distance from closest border
1098 resX += 1.25;
1099 } else if (resX > 1.25) {
1100 resX -= 1.25;
1101 } else {
1102 resX = 1E-3 / (pt + 1E-3); // high-pt should be favoured
1103 }
1104
1105 if (resZ < -1.75) { // distance from closest border
1106 resZ += 1.75;
1107 } else if (resZ > 1.75) {
1108 resZ -= 1.75;
1109 } else {
1110 resZ = 1E-3 / (pt + 1E-3); // high-pt should be favoured
1111 }
1112
1113 LOG(debug) << "resX = " << resX << ", resZ = " << resZ << ", res = " << res;
1114 if (indices[0] != detId[iPropagation][0]) {
1115 continue;
1116 }
1117 if (indices[1] != detId[iPropagation][1]) {
1118 continue;
1119 }
1120 if (indices[2] != detId[iPropagation][2]) {
1121 continue;
1122 }
1123 float chi2 = 0.5 * (resX * resX * errXinv2 + resZ * resZ * errZinv2); // TODO: take into account also the time!
1124
1125 if (res < mSpaceTolerance && chi2 < mMatchParams->maxChi2) { // matching ok!
1126 LOG(debug) << "MATCHING FOUND: We have a match! between track " << mTracksSectIndexCache[type][sec][itrk] << " and TOF cluster " << mTOFClusSectIndexCache[indices[0]][itof];
1127 foundCluster = true;
1128 // set event indexes (to be checked)
1129 int eventIndexTOFCluster = mTOFClusSectIndexCache[indices[0]][itof];
1130 mMatchedTracksPairsSec[sec].emplace_back(cacheTrk[itrk], eventIndexTOFCluster, mTOFClusWork[cacheTOF[itof]].getTime(), chi2, trkLTInt[iPropagation], mTrackGid[sec][type][cacheTrk[itrk]], type, (trefTOF.getTime() - (minTrkTime + maxTrkTime - 100E3) * 0.5) * 1E-6, trefTOF.getZ(), resXor, resZor, resY); // subracting 100 ns to max track which was artificially added
1131 mMatchedTracksPairsSec[sec][mMatchedTracksPairsSec[sec].size() - 1].setPt(pt);
1132 mMatchedTracksPairsSec[sec][mMatchedTracksPairsSec[sec].size() - 1].setResX(sqrt(1. / errXinv2));
1133 mMatchedTracksPairsSec[sec][mMatchedTracksPairsSec[sec].size() - 1].setResZ(sqrt(1. / errZinv2));
1134 mMatchedTracksPairsSec[sec][mMatchedTracksPairsSec[sec].size() - 1].setResT(resT);
1135 mMatchedTracksPairsSec[sec][mMatchedTracksPairsSec[sec].size() - 1].setVz(0.0); // not needed for constrained tracks
1136 mMatchedTracksPairsSec[sec][mMatchedTracksPairsSec[sec].size() - 1].setChannel(mainChannel);
1137 }
1138 }
1139 }
1140 }
1141 return;
1142}
1143//______________________________________________
1144void MatchTOF::doMatchingForTPC(int sec)
1145{
1146 float vdriftInBC = Geo::BC_TIME_INPS * 1E-6 * mTPCVDrift;
1147
1148 int bc_grouping = 40;
1149 int bc_grouping_tolerance = bc_grouping + mTimeTolerance / 25;
1150 int bc_grouping_half = (bc_grouping + 1) / 2;
1151 double BCgranularity = Geo::BC_TIME_INPS * bc_grouping;
1152
1154 auto& cacheTOF = mTOFClusSectIndexCache[sec]; // array of cached TOF cluster indices for this sector; reminder: they are ordered in time!
1155 auto& cacheTrk = mTracksSectIndexCache[trkType::UNCONS][sec]; // array of cached tracks indices for this sector; reminder: they are ordered in time!
1156 int nTracks = cacheTrk.size(), nTOFCls = cacheTOF.size();
1157 LOG(debug) << "Matching sector " << sec << ": number of tracks: " << nTracks << ", number of TOF clusters: " << nTOFCls;
1158 if (!nTracks || !nTOFCls) {
1159 return;
1160 }
1161 int itof0 = 0; // starting index in TOF clusters for matching of the track
1162 float deltaPosTemp[3];
1163 std::array<float, 3> pos;
1164 std::array<float, 3> posBeforeProp;
1165 float posFloat[3];
1166
1167 // prematching for TPC only tracks (identify BC candidate to correct z for TPC track accordingly to v_drift)
1168
1169 std::vector<unsigned long> BCcand;
1170
1171 std::vector<int> nStripsCrossedInPropagation;
1172 std::vector<std::array<std::array<int, 5>, 2>> detId;
1173 std::vector<std::array<o2::track::TrackLTIntegral, 2>> trkLTInt;
1174 std::vector<std::array<std::array<float, 3>, 2>> deltaPos;
1175 std::vector<std::array<int, 2>> nStepsInsideSameStrip;
1176 std::vector<std::array<float, 2>> Zshift;
1177
1178 LOG(debug) << "Trying to match %d tracks" << cacheTrk.size();
1179
1180 for (int itrk = 0; itrk < cacheTrk.size(); itrk++) {
1181 auto& trackWork = mTracksWork[sec][trkType::UNCONS][cacheTrk[itrk]];
1182 auto& trefTrk = trackWork.first;
1183 float pt = trefTrk.getPt();
1184 auto& intLT = mLTinfos[sec][trkType::UNCONS][cacheTrk[itrk]];
1185
1186 float timeShift = intLT.getL() * 33.35641; // integrated time for 0.75 beta particles in ps, to take into account the t.o.f. delay with respect the interaction BC
1187 // using beta=0.75 to cover beta range [0.59 , 1.04] also for a 8 m track lenght with a 10 ns track resolution (TRD)
1188
1189 BCcand.clear();
1190 nStripsCrossedInPropagation.clear();
1191
1192 int side = mSideTPC[sec][cacheTrk[itrk]];
1193 // look at BC candidates for the track
1194 double tpctime = trackWork.second.getTimeStamp(); // in mus
1195 double minTrkTime = (tpctime - trackWork.second.getTimeStampError()) * 1.E6 + timeShift; // minimum time in ps
1196 minTrkTime = int(minTrkTime / BCgranularity) * BCgranularity; // align min to a BC
1197 double maxTrkTime = (tpctime + mExtraTPCFwdTime[sec][cacheTrk[itrk]]) * 1.E6 + timeShift; // maximum time in ps
1198 const float sqrt12inv = 1. / sqrt(12.);
1199 float resT = (maxTrkTime - minTrkTime) * sqrt12inv;
1200
1201 if (mIsCosmics) {
1202 for (double tBC = minTrkTime; tBC < maxTrkTime; tBC += BCgranularity) {
1203 unsigned long ibc = (unsigned long)(tBC * Geo::BC_TIME_INPS_INV);
1204 BCcand.emplace_back(ibc);
1205 nStripsCrossedInPropagation.emplace_back(0);
1206 }
1207 }
1208
1209 int itofMax = nTOFCls;
1210
1211 for (auto itof = itof0; itof < nTOFCls; itof++) {
1212 auto& trefTOF = mTOFClusWork[cacheTOF[itof]];
1213
1214 if (trefTOF.getTime() < minTrkTime) { // this cluster has a time that is too small for the current track, we will get to the next one
1215 itof0 = itof + 1;
1216 continue;
1217 }
1218
1219 if (trefTOF.getTime() > maxTrkTime) { // this cluster has a time that is too large for the current track, close loop
1220 itofMax = itof;
1221 break;
1222 }
1223
1224 if ((trefTOF.getZ() * side < 0) && ((side > 0) != (trackWork.first.getTgl() > 0))) {
1225 continue;
1226 }
1227
1228 unsigned long bc = (unsigned long)(trefTOF.getTime() * Geo::BC_TIME_INPS_INV);
1229
1230 bc = (bc / bc_grouping_half) * bc_grouping_half;
1231
1232 bool isalreadyin = false;
1233
1234 for (int k = 0; k < BCcand.size(); k++) {
1235 if (bc == BCcand[k]) {
1236 isalreadyin = true;
1237 }
1238 }
1239
1240 if (!isalreadyin) {
1241 BCcand.emplace_back(bc);
1242 nStripsCrossedInPropagation.emplace_back(0);
1243 }
1244 }
1245
1246 detId.clear();
1247 detId.reserve(BCcand.size());
1248 trkLTInt.clear();
1249 trkLTInt.reserve(BCcand.size());
1250 Zshift.clear();
1251 Zshift.reserve(BCcand.size());
1252 deltaPos.clear();
1253 deltaPos.reserve(BCcand.size());
1254 nStepsInsideSameStrip.clear();
1255 nStepsInsideSameStrip.reserve(BCcand.size());
1256
1257 // Printf("intLT (before doing anything): length = %f, time (Pion) = %f", intLT.getL(), intLT.getTOF(o2::track::PID::Pion));
1258 int istep = 1; // number of steps
1259 float step = 1.0; // step size in cm
1260
1261 //uncomment for local debug
1262 /*
1263 //trefTrk.getXYZGlo(posBeforeProp);
1264 //float posBeforeProp[3] = {trefTrk.getX(), trefTrk.getY(), trefTrk.getZ()}; // in local ref system
1265 //printf("Global coordinates: posBeforeProp[0] = %f, posBeforeProp[1] = %f, posBeforeProp[2] = %f\n", posBeforeProp[0], posBeforeProp[1], posBeforeProp[2]);
1266 //Printf("Radius xy = %f", TMath::Sqrt(posBeforeProp[0]*posBeforeProp[0] + posBeforeProp[1]*posBeforeProp[1]));
1267 //Printf("Radius xyz = %f", TMath::Sqrt(posBeforeProp[0]*posBeforeProp[0] + posBeforeProp[1]*posBeforeProp[1] + posBeforeProp[2]*posBeforeProp[2]));
1268 */
1269
1270 int detIdTemp[5] = {-1, -1, -1, -1, -1}; // TOF detector id at the current propagation point
1271
1272 double reachedPoint = mXRef + istep * step;
1273
1274 // initializing
1275 for (int ibc = 0; ibc < BCcand.size(); ibc++) {
1276 for (int ii = 0; ii < 2; ii++) {
1277 nStepsInsideSameStrip[ibc][ii] = 0;
1278 for (int iii = 0; iii < 5; iii++) {
1279 detId[ibc][ii][iii] = -1;
1280 }
1281 }
1282 }
1283 while (propagateToRefX(trefTrk, reachedPoint, step, intLT) && reachedPoint < Geo::RMAX) {
1284 // while (o2::base::Propagator::Instance()->PropagateToXBxByBz(trefTrk, mXRef + istep * step, MAXSNP, step, 1, &intLT) && nStripsCrossedInPropagation <= 2 && mXRef + istep * step < Geo::RMAX) {
1285
1286 trefTrk.getXYZGlo(pos);
1287 for (int ii = 0; ii < 3; ii++) { // we need to change the type...
1288 posFloat[ii] = pos[ii];
1289 }
1290
1291 // uncomment below only for local debug; this will produce A LOT of output - one print per propagation step
1292 /*
1293 Printf("posFloat[0] = %f, posFloat[1] = %f, posFloat[2] = %f", posFloat[0], posFloat[1], posFloat[2]);
1294 Printf("radius xy = %f", TMath::Sqrt(posFloat[0]*posFloat[0] + posFloat[1]*posFloat[1]));
1295 Printf("radius xyz = %f", TMath::Sqrt(posFloat[0]*posFloat[0] + posFloat[1]*posFloat[1] + posFloat[2]*posFloat[2]));
1296 */
1297
1298 reachedPoint += step;
1299
1300 // check if you fall in a strip
1301 for (int ibc = 0; ibc < BCcand.size(); ibc++) {
1302 for (int idet = 0; idet < 5; idet++) {
1303 detIdTemp[idet] = -1;
1304 }
1305
1306 if (side > 0) {
1307 posFloat[2] = pos[2] - mTPCVDrift * (trackWork.second.getTimeStamp() - BCcand[ibc] * Geo::BC_TIME_INPS * 1E-6);
1308 } else if (side < 0) {
1309 posFloat[2] = pos[2] + mTPCVDrift * (trackWork.second.getTimeStamp() - BCcand[ibc] * Geo::BC_TIME_INPS * 1E-6);
1310 } else {
1311 posFloat[2] = pos[2];
1312 }
1313
1314 float ZshiftCurrent = posFloat[2] - pos[2];
1315
1316 Geo::getPadDxDyDz(posFloat, detIdTemp, deltaPosTemp, sec);
1317
1318 if (detIdTemp[2] == -1) {
1319 continue;
1320 }
1321
1322 if (nStripsCrossedInPropagation[ibc] == 0 || // we are crossing a strip for the first time...
1323 (nStripsCrossedInPropagation[ibc] >= 1 && (detId[ibc][nStripsCrossedInPropagation[ibc] - 1][0] != detIdTemp[0] || detId[ibc][nStripsCrossedInPropagation[ibc] - 1][1] != detIdTemp[1] || detId[ibc][nStripsCrossedInPropagation[ibc] - 1][2] != detIdTemp[2]))) { // ...or we are crossing a new strip
1324 if (nStripsCrossedInPropagation[ibc] == 0) {
1325 LOG(debug) << "We cross a strip for the first time";
1326 }
1327 if (nStripsCrossedInPropagation[ibc] == 2) {
1328 continue; // we have already matched 2 strips, we cannot match more
1329 }
1330 nStripsCrossedInPropagation[ibc]++;
1331 }
1332
1333 //Printf("nStepsInsideSameStrip[nStripsCrossedInPropagation-1] = %d", nStepsInsideSameStrip[nStripsCrossedInPropagation - 1]);
1334 if (nStepsInsideSameStrip[ibc][nStripsCrossedInPropagation[ibc] - 1] == 0) {
1335 trkLTInt[ibc][nStripsCrossedInPropagation[ibc] - 1] = intLT;
1336 // temporary variables since propagation can fail
1337 int detIdTemp2[5] = {0, 0, 0, 0, 0};
1338 float deltaPosTemp2[3] = {deltaPosTemp[0], deltaPosTemp[1], deltaPosTemp[2]};
1339 int nstep = 0;
1340 const int maxnstep = 50;
1341 float xStart = trefTrk.getX();
1342 float xStop = xStart;
1343 trefTrk.getXYZGlo(pos);
1344 for (int ii = 0; ii < 3; ii++) { // we need to change the type...
1345 posFloat[ii] = pos[ii];
1346 }
1347
1348 while (deltaPosTemp2[1] < -0.05 && detIdTemp2[2] != -1 && nstep < maxnstep) { // continuing propagation if dy is negative and we are still inside the strip volume
1349 nstep++;
1350 xStop += 0.1;
1351 propagateToRefXWithoutCov(trefTrk, xStop, 0.1, mBz, posFloat);
1352
1353 posFloat[2] += ZshiftCurrent;
1354
1355 Geo::getPadDxDyDz(posFloat, detIdTemp2, deltaPosTemp2, sec);
1356 if (detIdTemp2[2] != -1) { // if propation was succesful -> update params
1357 float dx = deltaPosTemp2[0] - deltaPosTemp[0];
1358 float dy = deltaPosTemp2[1] - deltaPosTemp[1];
1359 float dz = deltaPosTemp2[2] - deltaPosTemp[2];
1360 updateTL(trkLTInt[ibc][nStripsCrossedInPropagation[ibc] - 1], sqrt(dx * dx + dy * dy + dz * dz));
1361 detIdTemp[0] = detIdTemp2[0];
1362 detIdTemp[1] = detIdTemp2[1];
1363 detIdTemp[2] = detIdTemp2[2];
1364 detIdTemp[3] = detIdTemp2[3];
1365 detIdTemp[4] = detIdTemp2[4];
1366 deltaPosTemp[0] = deltaPosTemp2[0];
1367 deltaPosTemp[1] = deltaPosTemp2[1];
1368 deltaPosTemp[2] = deltaPosTemp2[2];
1369 }
1370 }
1371
1372 // adjust accordingly to DeltaY
1373 updateTL(trkLTInt[ibc][nStripsCrossedInPropagation[ibc] - 1], -deltaPosTemp[1]);
1374
1375 detId[ibc][nStripsCrossedInPropagation[ibc] - 1][0] = detIdTemp[0];
1376 detId[ibc][nStripsCrossedInPropagation[ibc] - 1][1] = detIdTemp[1];
1377 detId[ibc][nStripsCrossedInPropagation[ibc] - 1][2] = detIdTemp[2];
1378 detId[ibc][nStripsCrossedInPropagation[ibc] - 1][3] = detIdTemp[3];
1379 detId[ibc][nStripsCrossedInPropagation[ibc] - 1][4] = detIdTemp[4];
1380 deltaPos[ibc][nStripsCrossedInPropagation[ibc] - 1][0] = deltaPosTemp[0];
1381 deltaPos[ibc][nStripsCrossedInPropagation[ibc] - 1][1] = deltaPosTemp[1];
1382 deltaPos[ibc][nStripsCrossedInPropagation[ibc] - 1][2] = deltaPosTemp[2];
1383
1384 Zshift[ibc][nStripsCrossedInPropagation[ibc] - 1] = ZshiftCurrent;
1385 // Printf("intLT (after matching to strip %d): length = %f, time (Pion) = %f", nStripsCrossedInPropagation - 1, trkLTInt[nStripsCrossedInPropagation - 1].getL(), trkLTInt[nStripsCrossedInPropagation - 1].getTOF(o2::track::PID::Pion));
1386 nStepsInsideSameStrip[ibc][nStripsCrossedInPropagation[ibc] - 1]++;
1387 }
1388 /* // obsolete
1389 else { // a further propagation step in the same strip -> update info (we sum up on all matching with strip - we will divide for the number of steps a bit below)
1390 // N.B. the integrated length and time are taken (at least for now) from the first time we crossed the strip, so here we do nothing with those
1391 deltaPos[ibc][nStripsCrossedInPropagation[ibc] - 1][0] += deltaPosTemp[0] + (detIdTemp[4] - detId[ibc][nStripsCrossedInPropagation[ibc] - 1][4]) * Geo::XPAD; // residual in x
1392 deltaPos[ibc][nStripsCrossedInPropagation[ibc] - 1][1] += deltaPosTemp[1]; // residual in y
1393 deltaPos[ibc][nStripsCrossedInPropagation[ibc] - 1][2] += deltaPosTemp[2] + (detIdTemp[3] - detId[ibc][nStripsCrossedInPropagation[ibc] - 1][3]) * Geo::ZPAD; // residual in z
1394 nStepsInsideSameStrip[ibc][nStripsCrossedInPropagation[ibc] - 1]++;
1395 }
1396 */
1397 }
1398 }
1399 for (int ibc = 0; ibc < BCcand.size(); ibc++) {
1400 float minTime = (BCcand[ibc] - bc_grouping_tolerance) * Geo::BC_TIME_INPS;
1401 float maxTime = (BCcand[ibc] + bc_grouping_tolerance) * Geo::BC_TIME_INPS;
1402 for (Int_t imatch = 0; imatch < nStripsCrossedInPropagation[ibc]; imatch++) {
1403 // we take as residual the average of the residuals along the propagation in the same strip
1404 deltaPos[ibc][imatch][0] /= nStepsInsideSameStrip[ibc][imatch];
1405 deltaPos[ibc][imatch][1] /= nStepsInsideSameStrip[ibc][imatch];
1406 deltaPos[ibc][imatch][2] /= nStepsInsideSameStrip[ibc][imatch];
1407 }
1408
1409 if (nStripsCrossedInPropagation[ibc] == 0) {
1410 continue; // the track never hit a TOF strip during the propagation
1411 }
1412
1413 bool foundCluster = false;
1414 for (auto itof = itof0; itof < itofMax; itof++) {
1415 // printf("itof = %d\n", itof);
1416 auto& trefTOF = mTOFClusWork[cacheTOF[itof]];
1417 // compare the times of the track and the TOF clusters - remember that they both are ordered in time!
1418
1419 if (trefTOF.getTime() < minTime) { // this cluster has a time that is too small for the current track, we will get to the next one
1420 continue;
1421 }
1422 if (trefTOF.getTime() > maxTime) { // no more TOF clusters can be matched to this track
1423 break;
1424 }
1425
1426 int mainChannel = trefTOF.getMainContributingChannel();
1427 int indices[5];
1428 Geo::getVolumeIndices(mainChannel, indices);
1429
1430 bool isInStrip = false;
1431 for (auto iPropagation = 0; iPropagation < nStripsCrossedInPropagation[ibc]; iPropagation++) {
1432 if (detId[ibc][iPropagation][1] == indices[1] && detId[ibc][iPropagation][2] == indices[2]) {
1433 isInStrip = true;
1434 }
1435 }
1436
1437 if (!isInStrip) {
1438 continue;
1439 }
1440
1441 unsigned long bcClus = trefTOF.getTime() * Geo::BC_TIME_INPS_INV;
1442
1443 // compute fine correction using cluster position instead of pad center
1444 // this because in case of multiple-hit cluster position is averaged on all pads contributing to the cluster (then error position matrix can be used for Chi2 if nedeed)
1445 int ndigits = 1;
1446 float posCorr[3] = {0, 0, 0};
1447
1448 if (trefTOF.isBitSet(Cluster::kLeft)) {
1449 posCorr[0] += Geo::XPAD, ndigits++;
1450 }
1451 if (trefTOF.isBitSet(Cluster::kUpLeft)) {
1452 posCorr[0] += Geo::XPAD, posCorr[2] -= Geo::ZPAD, ndigits++;
1453 }
1454 if (trefTOF.isBitSet(Cluster::kDownLeft)) {
1455 posCorr[0] += Geo::XPAD, posCorr[2] += Geo::ZPAD, ndigits++;
1456 }
1457 if (trefTOF.isBitSet(Cluster::kUp)) {
1458 posCorr[2] -= Geo::ZPAD, ndigits++;
1459 }
1460 if (trefTOF.isBitSet(Cluster::kDown)) {
1461 posCorr[2] += Geo::ZPAD, ndigits++;
1462 }
1463 if (trefTOF.isBitSet(Cluster::kRight)) {
1464 posCorr[0] -= Geo::XPAD, ndigits++;
1465 }
1466 if (trefTOF.isBitSet(Cluster::kUpRight)) {
1467 posCorr[0] -= Geo::XPAD, posCorr[2] -= Geo::ZPAD, ndigits++;
1468 }
1469 if (trefTOF.isBitSet(Cluster::kDownRight)) {
1470 posCorr[0] -= Geo::XPAD, posCorr[2] += Geo::ZPAD, ndigits++;
1471 }
1472
1473 float ndifInv = 1. / ndigits;
1474 if (ndigits > 1) {
1475 posCorr[0] *= ndifInv;
1476 posCorr[1] *= ndifInv;
1477 posCorr[2] *= ndifInv;
1478 }
1479
1480 int trackIdTOF;
1481 int eventIdTOF;
1482 int sourceIdTOF;
1483 for (auto iPropagation = 0; iPropagation < nStripsCrossedInPropagation[ibc]; iPropagation++) {
1484 if (detId[ibc][iPropagation][1] != indices[1] || detId[ibc][iPropagation][2] != indices[2]) {
1485 continue;
1486 }
1487
1488 int bct0 = int((mTOFClusWork[cacheTOF[itof]].getTime() - trkLTInt[ibc][iPropagation].getTOF(0) + 5000) * Geo::BC_TIME_INPS_INV); // bc taken assuming speed of light (el) and 5 ns of margin
1489 if (bct0 < 0) { // if negative time (it can happen at the beginng of the TF int was truncated per excess... adjusting)
1490 bct0--;
1491 }
1492 float tof = mTOFClusWork[cacheTOF[itof]].getTime() - bct0 * Geo::BC_TIME_INPS;
1493 if (tof - trkLTInt[ibc][iPropagation].getTOF(6) > 2000) { // reject tracks slower than triton
1494 continue;
1495 }
1496
1497 if (mMatchParams->applyPIDcutTPConly) { // for TPC only tracks allowing possibility to apply a PID cut
1498 if (std::abs(tof - trkLTInt[ibc][iPropagation].getTOF(2)) < 2000) { // pion hypotesis
1499 } else if (std::abs(tof - trkLTInt[ibc][iPropagation].getTOF(3)) < 2000) { // kaon hypoteis
1500 } else if (std::abs(tof - trkLTInt[ibc][iPropagation].getTOF(4)) < 2000) { // proton hypotesis
1501 } else { // reject matching
1502 continue;
1503 }
1504 }
1505
1506 float cosangle = TMath::Cos(Geo::getAngles(indices[1], indices[2]) * TMath::DegToRad());
1507 const float errXinvMin = 1. / (mMatchParams->maxResX * mMatchParams->maxResX);
1508 const float errZinvMin = 1. / (mMatchParams->maxResZ * mMatchParams->maxResZ);
1509 float errXinv2 = 1. / (trefTrk.getSigmaY2());
1510 float errZinv2 = 1. / (trefTrk.getSigmaZ2() * cosangle); // should be valid only at eta=0
1511
1512 if (errXinv2 < errXinvMin) {
1513 errXinv2 = errXinvMin;
1514 }
1515 if (errZinv2 < errZinvMin) {
1516 errZinv2 = errZinvMin;
1517 }
1518
1519 LOG(debug) << "TOF Cluster [" << itof << ", " << cacheTOF[itof] << "]: indices = " << indices[0] << ", " << indices[1] << ", " << indices[2] << ", " << indices[3] << ", " << indices[4];
1520 LOG(debug) << "Propagated Track [" << itrk << "]: detId[" << iPropagation << "] = " << detId[ibc][iPropagation][0] << ", " << detId[ibc][iPropagation][1] << ", " << detId[ibc][iPropagation][2] << ", " << detId[ibc][iPropagation][3] << ", " << detId[ibc][iPropagation][4];
1521 float resX = deltaPos[ibc][iPropagation][0] - (indices[4] - detId[ibc][iPropagation][4]) * Geo::XPAD + posCorr[0]; // readjusting the residuals due to the fact that the propagation fell in a pad that was not exactly the one of the cluster
1522 float resZ = deltaPos[ibc][iPropagation][2] - (indices[3] - detId[ibc][iPropagation][3]) * Geo::ZPAD + posCorr[2]; // readjusting the residuals due to the fact that the propagation fell in a pad that was not exactly the one of the cluster
1523 float resY = deltaPos[ibc][iPropagation][1];
1524 if (BCcand[ibc] > bcClus) {
1525 resZ += (BCcand[ibc] - bcClus) * vdriftInBC * side; // add bc correction
1526 } else {
1527 resZ -= (bcClus - BCcand[ibc]) * vdriftInBC * side;
1528 }
1529 float resXor = resX;
1530 float resZor = resZ;
1531 float res = TMath::Sqrt(resX * resX + resZ * resZ);
1532
1533 if (resX < -1.25) { // distance from closest border
1534 resX += 1.25;
1535 } else if (resX > 1.25) {
1536 resX -= 1.25;
1537 } else {
1538 resX = 1E-3 / (pt + 1E-3); // high-pt should be favoured
1539 }
1540
1541 if (resZ < -1.75) { // distance from closest border
1542 resZ += 1.75;
1543 } else if (resZ > 1.75) {
1544 resZ -= 1.75;
1545 } else {
1546 resZ = 1E-3 / (pt + 1E-3); // high-pt should be favoured
1547 }
1548
1549 if (indices[0] != detId[ibc][iPropagation][0]) {
1550 continue;
1551 }
1552 if (indices[1] != detId[ibc][iPropagation][1]) {
1553 continue;
1554 }
1555 if (indices[2] != detId[ibc][iPropagation][2]) {
1556 continue;
1557 }
1558
1559 LOG(debug) << "resX = " << resX << ", resZ = " << resZ << ", res = " << res;
1560 float chi2 = mIsCosmics ? resX : 0.5 * (resX * resX * errXinv2 + resZ * resZ * errZinv2); // TODO: take into account also the time!
1561
1562 if (res < mSpaceTolerance && chi2 < mMatchParams->maxChi2) { // matching ok!
1563 LOG(debug) << "MATCHING FOUND: We have a match! between track " << mTracksSectIndexCache[trkType::UNCONS][sec][itrk] << " and TOF cluster " << mTOFClusSectIndexCache[indices[0]][itof];
1564 foundCluster = true;
1565 // set event indexes (to be checked)
1566
1567 int eventIndexTOFCluster = mTOFClusSectIndexCache[indices[0]][itof];
1568 mMatchedTracksPairsSec[sec].emplace_back(cacheTrk[itrk], eventIndexTOFCluster, mTOFClusWork[cacheTOF[itof]].getTime(), chi2, trkLTInt[ibc][iPropagation], mTrackGid[sec][trkType::UNCONS][cacheTrk[itrk]], trkType::UNCONS, trefTOF.getTime() * 1E-6 - tpctime, trefTOF.getZ(), resXor, resZor, resY); // TODO: check if this is correct!
1569 mMatchedTracksPairsSec[sec][mMatchedTracksPairsSec[sec].size() - 1].setPt(pt);
1570 mMatchedTracksPairsSec[sec][mMatchedTracksPairsSec[sec].size() - 1].setResX(sqrt(1. / errXinv2));
1571 mMatchedTracksPairsSec[sec][mMatchedTracksPairsSec[sec].size() - 1].setResZ(sqrt(1. / errZinv2));
1572 mMatchedTracksPairsSec[sec][mMatchedTracksPairsSec[sec].size() - 1].setResT(resT);
1573 mMatchedTracksPairsSec[sec][mMatchedTracksPairsSec[sec].size() - 1].setVz(mVZtpcOnly[sec][itrk] + Zshift[ibc][iPropagation]);
1574 mMatchedTracksPairsSec[sec][mMatchedTracksPairsSec[sec].size() - 1].setChannel(mainChannel);
1575 }
1576 }
1577 }
1578 }
1579 }
1580 return;
1581}
1582//______________________________________________
1583int MatchTOF::findFITIndex(int bc, const gsl::span<const o2::ft0::RecPoints>& FITRecPoints, unsigned long firstOrbit)
1584{
1585 const auto& FT0Params = o2::ft0::InteractionTag::Instance();
1586
1587 if ((!mHasFillScheme) && o2::tof::Utils::hasFillScheme()) {
1588 mHasFillScheme = true;
1589 for (int ibc = 0; ibc < o2::tof::Utils::getNinteractionBC(); ibc++) {
1590 mFillScheme[o2::tof::Utils::getInteractionBC(ibc)] = true;
1591 }
1592 }
1593
1594 if (FITRecPoints.size() == 0) {
1595 return -1;
1596 }
1597
1598 int index = -1;
1599 int distMax = 10;
1600 bool bestQuality = false; // prioritize FT0 BC with good quality (FT0-AC + vertex) to remove umbiguity in Pb-Pb (not a strict cut because inefficient in pp)
1601 const int distThr = 8;
1602
1603 for (unsigned int i = 0; i < FITRecPoints.size(); i++) {
1604 const auto& ft = FITRecPoints[i];
1605 if (!FT0Params.isSelected(ft)) {
1606 continue;
1607 }
1608 const o2::InteractionRecord ir = FITRecPoints[i].getInteractionRecord();
1609 if (mHasFillScheme && !mFillScheme[ir.bc]) {
1610 continue;
1611 }
1612 bool quality = (std::abs(FITRecPoints[i].getCollisionTime(0)) < 1000 && std::abs(FITRecPoints[i].getVertex()) < 1000);
1613 if (bestQuality && !quality) { // if current has no good quality and the one previoulsy selected has -> discard the current one
1614 continue;
1615 }
1616 int bct0 = (ir.orbit - firstOrbit) * o2::constants::lhc::LHCMaxBunches + ir.bc;
1617 int dist = bc - bct0;
1618
1619 bool worseDistance = dist < 0 || dist > distThr || dist > distMax;
1620 if (worseDistance) { // discard if BC is not in the proper range or it is worse than the one already found
1621 continue;
1622 }
1623
1624 bestQuality = quality;
1625 distMax = dist;
1626 index = i;
1627 }
1628
1629 return index;
1630}
1631//______________________________________________
1632void MatchTOF::selectBestMatches(int sec)
1633{
1634 if (mSetHighPurity) {
1635 BestMatchesHP(mMatchedTracksPairsSec[sec], mMatchedTracks, mMatchedTracksIndex[sec], mMatchedClustersIndex, mFITRecPoints, mTOFClusWork, mCalibInfoTOF, mTimestamp, mMCTruthON, mTOFClusLabels, mTracksLblWork[sec], mOutTOFLabels);
1636 return;
1637 }
1638 BestMatches(mMatchedTracksPairsSec[sec], mMatchedTracks, mMatchedTracksIndex[sec], mMatchedClustersIndex, mFITRecPoints, mTOFClusWork, mTracksWork[sec], mCalibInfoTOF, mTimestamp, mMCTruthON, mTOFClusLabels, mTracksLblWork[sec], mOutTOFLabels, mMatchParams->calibMaxChi2);
1639}
1640//______________________________________________
1641void MatchTOF::BestMatches(std::vector<o2::dataformats::MatchInfoTOFReco>& matchedTracksPairs, std::vector<o2::dataformats::MatchInfoTOF>* matchedTracks, std::vector<int>* matchedTracksIndex, int* matchedClustersIndex, const gsl::span<const o2::ft0::RecPoints>& FITRecPoints, const std::vector<Cluster>& TOFClusWork, const std::vector<matchTrack>* TracksWork, std::vector<o2::dataformats::CalibInfoTOF>& CalibInfoTOF, unsigned long Timestamp, bool MCTruthON, const o2::dataformats::MCTruthContainer<o2::MCCompLabel>* TOFClusLabels, const std::vector<o2::MCCompLabel>* TracksLblWork, std::vector<o2::MCCompLabel>* OutTOFLabels, float calibMaxChi2)
1642{
1644
1645 // first, we sort according to the chi2
1646 std::sort(matchedTracksPairs.begin(), matchedTracksPairs.end(), [](const o2::dataformats::MatchInfoTOFReco& a, const o2::dataformats::MatchInfoTOFReco& b) { return (a.getChi2() < b.getChi2()); });
1647 int i = 0;
1648
1649 // then we take discard the pairs if their track or cluster was already matched (since they are ordered in chi2, we will take the best matching)
1650 for (o2::dataformats::MatchInfoTOFReco& matchingPair : matchedTracksPairs) {
1651 int trkType = (int)matchingPair.getTrackType();
1652
1653 int itrk = matchingPair.getIdLocal();
1654
1655 int trkTypeSplitted = trkType;
1656 auto sourceID = matchingPair.getTrackRef().getSource();
1658 trkTypeSplitted = (int)trkType::TPCTRD;
1659 } else if (sourceID == o2::dataformats::GlobalTrackID::ITSTPCTRD) {
1660 trkTypeSplitted = (int)trkType::ITSTPCTRD;
1661 }
1662
1663 if (matchedClustersIndex[matchingPair.getTOFClIndex()] != -1) { // the cluster was already filled
1664 continue;
1665 }
1666 if (matchedTracksIndex[trkType][itrk] != -1) { // the track was already filled
1667 if (trkType) { // not applied for unconstrained tracks (trkType == 0)
1668 // let's check if we can use both matching to improve TOF time
1669 int pairInd = matchedTracksIndex[trkType][itrk];
1670 auto& prevMatching = matchedTracks[trkTypeSplitted][pairInd];
1671
1672 if (pairInd >= matchedTracks[trkTypeSplitted].size()) {
1673 LOG(error) << "Pair index out of range when trying to update TOF time. This should not happen";
1674 continue;
1675 }
1676
1677 int istripOld = TOFClusWork[prevMatching.getTOFClIndex()].getMainContributingChannel() / o2::tof::Geo::NPADS;
1678 int istripNew = TOFClusWork[matchingPair.getTOFClIndex()].getMainContributingChannel() / o2::tof::Geo::NPADS;
1679
1680 if (istripOld != istripNew) { // we accept it only if in a different strip
1681 const o2::track::TrackLTIntegral& intLTnew = matchingPair.getLTIntegralOut();
1682 const o2::track::TrackLTIntegral& intLTold = prevMatching.getLTIntegralOut();
1683
1684 const float cinv = 1.E+10 / TMath::C(); // cm/ps
1685 float deltaT = (intLTnew.getL() - intLTold.getL()) * cinv;
1686
1687 float timeNew = TOFClusWork[matchingPair.getTOFClIndex()].getTime() - deltaT;
1688 float timeOld = TOFClusWork[prevMatching.getTOFClIndex()].getTime();
1689
1690 if (std::abs(timeNew - timeOld) < 200) {
1691 // update time information averaging the two (the second one corrected for the difference in the track length)
1692 prevMatching.setSignal((timeNew + timeOld) * 0.5);
1693 float geanttime = (TOFClusWork[matchingPair.getTOFClIndex()].getTgeant() + TOFClusWork[prevMatching.getTOFClIndex()].getTgeant() - deltaT * 1E-3) * 0.5;
1694 double t0 = (TOFClusWork[matchingPair.getTOFClIndex()].getT0true() + TOFClusWork[prevMatching.getTOFClIndex()].getT0true()) * 0.5;
1695 prevMatching.setTgeant(geanttime);
1696 prevMatching.setT0true(t0);
1697 prevMatching.setChi2(0); // flag such cases with chi2 equal to zero
1698 matchedClustersIndex[matchingPair.getTOFClIndex()] = matchedTracksIndex[trkType][itrk]; // flag also the second cluster as already used
1699 }
1700 }
1701 }
1702
1703 continue;
1704 }
1705 matchedTracksIndex[trkType][itrk] = matchedTracks[trkTypeSplitted].size(); // index of the MatchInfoTOF correspoding to this track
1706 matchedClustersIndex[matchingPair.getTOFClIndex()] = matchedTracksIndex[trkType][itrk]; // index of the track that was matched to this cluster
1707
1708 matchingPair.setTgeant(TOFClusWork[matchingPair.getTOFClIndex()].getTgeant());
1709 matchingPair.setT0true(TOFClusWork[matchingPair.getTOFClIndex()].getT0true());
1710
1711 // let's check if cluster has multiple-hits (noferini)
1712 const auto& tofcl = TOFClusWork[matchingPair.getTOFClIndex()];
1713 if (tofcl.getNumOfContributingChannels() > 1) {
1714 // has an additional hit Up or Down (Z-dir)
1715 matchingPair.setHitPatternUpDown(tofcl.isAdditionalChannelSet(o2::tof::Cluster::kUp) ||
1716 tofcl.isAdditionalChannelSet(o2::tof::Cluster::kUpLeft) ||
1717 tofcl.isAdditionalChannelSet(o2::tof::Cluster::kUpRight) ||
1718 tofcl.isAdditionalChannelSet(o2::tof::Cluster::kDown) ||
1719 tofcl.isAdditionalChannelSet(o2::tof::Cluster::kDownLeft) ||
1720 tofcl.isAdditionalChannelSet(o2::tof::Cluster::kDownRight));
1721 // has an additional hit Left or Right (X-dir)
1722 matchingPair.setHitPatternLeftRight(tofcl.isAdditionalChannelSet(o2::tof::Cluster::kLeft) ||
1723 tofcl.isAdditionalChannelSet(o2::tof::Cluster::kDownLeft) ||
1724 tofcl.isAdditionalChannelSet(o2::tof::Cluster::kUpLeft) ||
1725 tofcl.isAdditionalChannelSet(o2::tof::Cluster::kRight) ||
1726 tofcl.isAdditionalChannelSet(o2::tof::Cluster::kDownRight) ||
1727 tofcl.isAdditionalChannelSet(o2::tof::Cluster::kUpRight));
1728 }
1729
1730 // estimate collision time using FT0 info if available
1731 ULong64_t bclongtofCal = (matchingPair.getSignal() - 10000) * o2::tof::Geo::BC_TIME_INPS_INV;
1732 double t0Best = bclongtofCal * o2::tof::Geo::BC_TIME_INPS; // here just BC
1733 float t0BestRes = 200;
1734 if (FITRecPoints.size() > 0) {
1735 int index = findFITIndex(bclongtofCal, FITRecPoints, mFirstTForbit);
1736 if (index > -1 && FITRecPoints[index].isValidTime(1) && FITRecPoints[index].isValidTime(2)) { // require A and C
1737 t0Best += FITRecPoints[index].getCollisionTime(0);
1738 t0BestRes = 15;
1739 }
1740 }
1741 matchingPair.setFT0Best(t0Best, t0BestRes);
1742 matchedTracks[trkTypeSplitted].push_back(matchingPair); // array of MatchInfoTOF
1743
1744 // get fit info
1745 double t0info = 0;
1746
1747 const o2::track::TrackLTIntegral& intLT = matchingPair.getLTIntegralOut();
1748
1749 if (FITRecPoints.size() > 0 && mIsFIT) {
1750 int index = findFITIndex(TOFClusWork[matchingPair.getTOFClIndex()].getBC() - o2::tof::Geo::LATENCYWINDOW_IN_BC, FITRecPoints, mFirstTForbit);
1751
1752 if (index > -1) {
1753 o2::InteractionRecord ir = FITRecPoints[index].getInteractionRecord();
1754 int bct0 = (ir.orbit - mFirstTForbit) * o2::constants::lhc::LHCMaxBunches + ir.bc;
1755 t0info = bct0 * o2::tof::Geo::BC_TIME_INPS;
1756 }
1757 } else if (!mIsFIT) { // move time to time in orbit to avoid loss of precision when truncating from double to float
1758 int bcStarOrbit = int((TOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() - intLT.getTOF(o2::track::PID::Pion)) * o2::tof::Geo::BC_TIME_INPS_INV);
1759 bcStarOrbit = (bcStarOrbit / o2::constants::lhc::LHCMaxBunches) * o2::constants::lhc::LHCMaxBunches; // truncation
1760 t0info = bcStarOrbit * o2::tof::Geo::BC_TIME_INPS;
1761 }
1762
1763 // add also calibration infos
1764 int flags = 0;
1765 if (sourceID == o2::dataformats::GlobalTrackID::TPC) {
1767 } else if (sourceID == o2::dataformats::GlobalTrackID::ITSTPC) {
1769 } else if (sourceID == o2::dataformats::GlobalTrackID::TPCTRD) {
1771 } else if (sourceID == o2::dataformats::GlobalTrackID::ITSTPCTRD) {
1773 }
1774
1775 int mask = 0;
1776 float deltat;
1777
1778 if (t0info > 0 && mIsFIT) { // FT0 BC found
1779 deltat = TOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() - t0info - intLT.getTOF(o2::track::PID::Pion) - o2::tof::Geo::LATENCYWINDOW_IN_BC * o2::tof::Geo::BC_TIME_INPS; // latency subtracted
1780 mask = 1 << 8; // only FT0 BC allowed (-> BC=0 since t0info already subtracted and assumed to be aligned to the true IntBC)
1781 } else if (!mIsFIT) {
1782 deltat = o2::tof::Utils::subtractInteractionBC(TOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() - t0info - intLT.getTOF(o2::track::PID::Pion), mask, true);
1783 }
1784
1785 const o2::track::TrackParCov& trc = TracksWork[trkType][itrk].first;
1786 float pt = trc.getPt(); // from outer parameters!
1787
1788 if (pt > 1.5) {
1790 }
1791
1792 if (pt < 0.5) {
1794 }
1795
1796 if (mask == 0) {
1798 }
1799
1800 if (TOFClusWork[matchingPair.getTOFClIndex()].getNumOfContributingChannels() != 1) {
1802 }
1803
1804 if (matchingPair.getChi2() < calibMaxChi2 && t0info > 0) { // extra cut in ChiSquare for storing calib info
1805 CalibInfoTOF.emplace_back(TOFClusWork[matchingPair.getTOFClIndex()].getMainContributingChannel(),
1806 Timestamp / 1000 + int(TOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() * 1E-12), // add time stamp
1807 deltat,
1808 TOFClusWork[matchingPair.getTOFClIndex()].getTot(), mask, flags);
1809 }
1810
1811 if (MCTruthON) {
1812 const auto& labelsTOF = TOFClusLabels->getLabels(matchingPair.getTOFClIndex());
1813 auto& labelTrack = TracksLblWork[trkType][itrk];
1814 // we have not found the track label among those associated to the TOF cluster --> fake match! We will associate the label of the main channel, but negative
1815 bool fake = true;
1816 for (auto& lbl : labelsTOF) {
1817 if (labelTrack == lbl) { // compares src, evID, trID, ignores fake flag.
1818 fake = false;
1819 }
1820 }
1821 OutTOFLabels[trkTypeSplitted].emplace_back(labelTrack).setFakeFlag(fake);
1822 }
1823 i++;
1824 }
1825}
1826//______________________________________________
1827void MatchTOF::BestMatchesHP(std::vector<o2::dataformats::MatchInfoTOFReco>& matchedTracksPairs, std::vector<o2::dataformats::MatchInfoTOF>* matchedTracks, std::vector<int>* matchedTracksIndex, int* matchedClustersIndex, const gsl::span<const o2::ft0::RecPoints>& FITRecPoints, const std::vector<Cluster>& TOFClusWork, std::vector<o2::dataformats::CalibInfoTOF>& CalibInfoTOF, unsigned long Timestamp, bool MCTruthON, const o2::dataformats::MCTruthContainer<o2::MCCompLabel>* TOFClusLabels, const std::vector<o2::MCCompLabel>* TracksLblWork, std::vector<o2::MCCompLabel>* OutTOFLabels)
1828{
1830 float chi2SeparationCut = 2;
1831 float chi2S = 3;
1832
1833 std::vector<o2::dataformats::MatchInfoTOFReco> tmpMatch;
1834
1835 // first, we sort according to the chi2
1836 std::sort(matchedTracksPairs.begin(), matchedTracksPairs.end(), [](const o2::dataformats::MatchInfoTOFReco& a, const o2::dataformats::MatchInfoTOFReco& b) { return (a.getChi2() < b.getChi2()); });
1837 int i = 0;
1838 // then we take discard the pairs if their track or cluster was already matched (since they are ordered in chi2, we will take the best matching)
1839 for (const o2::dataformats::MatchInfoTOFReco& matchingPair : matchedTracksPairs) {
1840 int trkType = (int)matchingPair.getTrackType();
1841
1842 int itrk = matchingPair.getIdLocal();
1843
1844 bool discard = matchingPair.getChi2() > chi2S;
1845
1846 if (matchedTracksIndex[trkType][itrk] != -1) { // the track was already filled, check if this competitor is not too close
1847 auto winnerChi = tmpMatch[matchedTracksIndex[trkType][itrk]].getChi2();
1848 if (winnerChi < 0) { // the winner was already discarded as ambiguous
1849 continue;
1850 }
1851 if (matchingPair.getChi2() - winnerChi < chi2SeparationCut) { // discard previously validated winner and it has too close competitor
1852 tmpMatch[matchedTracksIndex[trkType][itrk]].setChi2(-1);
1853 }
1854 continue;
1855 }
1856
1857 if (matchedClustersIndex[matchingPair.getTOFClIndex()] != -1) { // the cluster was already filled, check if this competitor is not too close
1858 auto winnerChi = tmpMatch[matchedClustersIndex[matchingPair.getTOFClIndex()]].getChi2();
1859 if (winnerChi < 0) { // the winner was already discarded as ambiguous
1860 continue;
1861 }
1862 if (matchingPair.getChi2() - winnerChi < chi2SeparationCut) { // discard previously validated winner and it has too close competitor
1863 tmpMatch[matchedClustersIndex[matchingPair.getTOFClIndex()]].setChi2(-1);
1864 }
1865 continue;
1866 }
1867
1868 if (!discard) {
1869 matchedTracksIndex[trkType][itrk] = tmpMatch.size(); // index of the MatchInfoTOF correspoding to this track
1870 matchedClustersIndex[matchingPair.getTOFClIndex()] = matchedTracksIndex[trkType][itrk]; // index of the track that was matched to this clus
1871 tmpMatch.push_back(matchingPair);
1872 }
1873 }
1874
1875 // now write final matches skipping disabled ones
1876 for (auto& matchingPair : tmpMatch) {
1877 if (matchingPair.getChi2() <= 0) {
1878 continue;
1879 }
1880 int trkType = (int)matchingPair.getTrackType();
1881 int itrk = matchingPair.getIdLocal();
1882
1883 int trkTypeSplitted = trkType;
1884 auto sourceID = matchingPair.getTrackRef().getSource();
1886 trkTypeSplitted = (int)trkType::TPCTRD;
1887 } else if (sourceID == o2::dataformats::GlobalTrackID::ITSTPCTRD) {
1888 trkTypeSplitted = (int)trkType::ITSTPCTRD;
1889 }
1890 matchedTracks[trkTypeSplitted].push_back(matchingPair); // array of MatchInfoTOF
1891
1892 const o2::track::TrackLTIntegral& intLT = matchingPair.getLTIntegralOut();
1893
1894 // get fit info
1895 double t0info = 0;
1896
1897 if (FITRecPoints.size() > 0 && mIsFIT) {
1898 int index = findFITIndex(TOFClusWork[matchingPair.getTOFClIndex()].getBC() - o2::tof::Geo::LATENCYWINDOW_IN_BC, FITRecPoints, mFirstTForbit);
1899
1900 if (index > -1) {
1901 o2::InteractionRecord ir = FITRecPoints[index].getInteractionRecord();
1902 int bct0 = (ir.orbit - mFirstTForbit) * o2::constants::lhc::LHCMaxBunches + ir.bc;
1903 t0info = bct0 * o2::tof::Geo::BC_TIME_INPS;
1904 }
1905 } else { // move time to time in orbit to avoid loss of precision when truncating from double to float
1906 int bcStarOrbit = int((TOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() - intLT.getTOF(o2::track::PID::Pion)) * o2::tof::Geo::BC_TIME_INPS_INV);
1907 bcStarOrbit = (bcStarOrbit / o2::constants::lhc::LHCMaxBunches) * o2::constants::lhc::LHCMaxBunches; // truncation
1908 t0info = bcStarOrbit * o2::tof::Geo::BC_TIME_INPS;
1909 }
1910
1911 // add also calibration infos
1913 CalibInfoTOF.emplace_back(TOFClusWork[matchingPair.getTOFClIndex()].getMainContributingChannel(),
1914 Timestamp / 1000 + int(TOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() * 1E-12), // add time stamp
1915 TOFClusWork[matchingPair.getTOFClIndex()].getTimeRaw() - t0info - intLT.getTOF(o2::track::PID::Pion),
1916 TOFClusWork[matchingPair.getTOFClIndex()].getTot(), 0);
1917 }
1918
1919 if (MCTruthON) {
1920 const auto& labelsTOF = TOFClusLabels->getLabels(matchingPair.getTOFClIndex());
1921 auto& labelTrack = TracksLblWork[trkType][itrk];
1922 // we have not found the track label among those associated to the TOF cluster --> fake match! We will associate the label of the main channel, but negative
1923 bool fake = true;
1924 for (auto& lbl : labelsTOF) {
1925 if (labelTrack == lbl) { // compares src, evID, trID, ignores fake flag.
1926 fake = false;
1927 }
1928 }
1929 OutTOFLabels[trkTypeSplitted].emplace_back(labelTrack).setFakeFlag(fake);
1930 }
1931 }
1932}
1933//______________________________________________
1934bool MatchTOF::propagateToRefX(o2::track::TrackParCov& trc, float xRef, float stepInCm, o2::track::TrackLTIntegral& intLT)
1935{
1936 // propagate track to matching reference X
1937 o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; // material correction method
1938 static const float tanHalfSector = tan(o2::constants::math::SectorSpanRad / 2);
1939 bool refReached = false;
1940 float xStart = trc.getX();
1941 // the first propagation will be from 2m, if the track is not at least at 2m
1942 if (xStart < 50.) {
1943 xStart = 50.;
1944 }
1945 int istep = 1;
1946 bool hasPropagated = o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, xStart + istep * stepInCm, MAXSNP, stepInCm, matCorr, &intLT);
1947 while (hasPropagated) {
1948 if (trc.getX() > xRef) {
1949 refReached = true; // we reached the 371cm reference
1950 }
1951 istep++;
1952 if (std::abs(trc.getY()) > trc.getX() * tanHalfSector) { // we are still in the same sector
1953 // we need to rotate the track to go to the new sector
1954 //Printf("propagateToRefX: changing sector");
1955 auto alphaNew = o2::math_utils::angle2Alpha(trc.getPhiPos());
1956 if (!trc.rotate(alphaNew) != 0) {
1957 // Printf("propagateToRefX: failed to rotate");
1958 break; // failed (this line is taken from MatchTPCITS and the following comment too: RS: check effect on matching tracks to neighbouring sector)
1959 }
1960 }
1961 if (refReached) {
1962 break;
1963 }
1964 hasPropagated = o2::base::Propagator::Instance()->PropagateToXBxByBz(trc, xStart + istep * stepInCm, MAXSNP, stepInCm, matCorr, &intLT);
1965 }
1966
1967 // if (std::abs(trc.getSnp()) > MAXSNP) Printf("propagateToRefX: condition on snp not ok, returning false");
1968 //Printf("propagateToRefX: snp of teh track is %f (--> %f grad)", trc.getSnp(), TMath::ASin(trc.getSnp())*TMath::RadToDeg());
1969 return refReached && std::abs(trc.getSnp()) < 0.95; // Here we need to put MAXSNP
1970}
1971//______________________________________________
1972bool MatchTOF::propagateToRefXWithoutCov(const o2::track::TrackParCov& trc, float xRef, float stepInCm, float bzField)
1973{
1974 // propagate track to matching reference X without using the covariance matrix
1975 // we create the copy of the track in a TrackPar object (no cov matrix)
1976 o2::track::TrackPar trcNoCov(trc);
1977 const float tanHalfSector = tan(o2::constants::math::SectorSpanRad / 2);
1978 bool refReached = false;
1979 float xStart = trcNoCov.getX();
1980 // the first propagation will be from 2m, if the track is not at least at 2m
1981 if (xStart < 50.) {
1982 xStart = 50.;
1983 }
1984 int istep = 1;
1985 bool hasPropagated = trcNoCov.propagateParamTo(xStart + istep * stepInCm, bzField);
1986 while (hasPropagated) {
1987 if (trcNoCov.getX() > xRef) {
1988 refReached = true; // we reached the 371cm reference
1989 }
1990 istep++;
1991 if (std::abs(trcNoCov.getY()) > trcNoCov.getX() * tanHalfSector) { // we are still in the same sector
1992 // we need to rotate the track to go to the new sector
1993 //Printf("propagateToRefX: changing sector");
1994 auto alphaNew = o2::math_utils::angle2Alpha(trcNoCov.getPhiPos());
1995 if (!trcNoCov.rotateParam(alphaNew) != 0) {
1996 // Printf("propagateToRefX: failed to rotate");
1997 break; // failed (this line is taken from MatchTPCITS and the following comment too: RS: check effect on matching tracks to neighbouring sector)
1998 }
1999 }
2000 if (refReached) {
2001 break;
2002 }
2003 hasPropagated = trcNoCov.propagateParamTo(xStart + istep * stepInCm, bzField);
2004 }
2005 // if (std::abs(trc.getSnp()) > MAXSNP) Printf("propagateToRefX: condition on snp not ok, returning false");
2006 //Printf("propagateToRefX: snp of teh track is %f (--> %f grad)", trcNoCov.getSnp(), TMath::ASin(trcNoCov.getSnp())*TMath::RadToDeg());
2007
2008 return refReached && std::abs(trcNoCov.getSnp()) < 0.95 && std::abs(trcNoCov.getZ()) < Geo::MAXHZTOF; // Here we need to put MAXSNP
2009}
2010//______________________________________________
2011void MatchTOF::updateTL(o2::track::TrackLTIntegral& intLT, float deltal)
2012{
2013 for (int i = 0; i < intLT.getNTOFs(); i++) {
2014 float betainv = intLT.getTOF(i) / intLT.getL();
2015 intLT.setTOF(intLT.getTOF(i) + deltal * betainv, i);
2016 }
2017 intLT.setL(intLT.getL() + deltal);
2018}
2019
2020//______________________________________________
2021bool MatchTOF::propagateToRefXWithoutCov(const o2::track::TrackParCov& trc, float xRef, float stepInCm, float bzField, float pos[3])
2022{
2023 // propagate track to matching reference X without using the covariance matrix
2024 // we create the copy of the track in a TrackPar object (no cov matrix)
2025 o2::track::TrackPar trcNoCov(trc);
2026 const float tanHalfSector = tan(o2::constants::math::SectorSpanRad / 2);
2027 bool refReached = false;
2028 float xStart = trcNoCov.getX();
2029 // the first propagation will be from 2m, if the track is not at least at 2m
2030 if (xStart < 50.) {
2031 xStart = 50.;
2032 }
2033 int istep = 1;
2034 bool hasPropagated = trcNoCov.propagateParamTo(xStart + istep * stepInCm, bzField);
2035 while (hasPropagated) {
2036 if (trcNoCov.getX() > xRef) {
2037 refReached = true; // we reached the 371cm reference
2038 }
2039 istep++;
2040 if (fabs(trcNoCov.getY()) > trcNoCov.getX() * tanHalfSector) { // we are still in the same sector
2041 // we need to rotate the track to go to the new sector
2042 // Printf("propagateToRefX: changing sector");
2043 auto alphaNew = o2::math_utils::angle2Alpha(trcNoCov.getPhiPos());
2044 if (!trcNoCov.rotateParam(alphaNew) != 0) {
2045 // Printf("propagateToRefX: failed to rotate");
2046 break; // failed (this line is taken from MatchTPCITS and the following comment too: RS: check effect on matching tracks to neighbouring sector)
2047 }
2048 }
2049 if (refReached) {
2050 break;
2051 }
2052 hasPropagated = trcNoCov.propagateParamTo(xStart + istep * stepInCm, bzField);
2053 }
2054 // if (std::abs(trc.getSnp()) > MAXSNP) Printf("propagateToRefX: condition on snp not ok, returning false");
2055 // Printf("propagateToRefX: snp of teh track is %f (--> %f grad)", trcNoCov.getSnp(), TMath::ASin(trcNoCov.getSnp())*TMath::RadToDeg());
2056
2058 trcNoCov.getXYZGlo(xyz);
2059 pos[0] = xyz[0];
2060 pos[1] = xyz[1];
2061 pos[2] = xyz[2];
2062
2063 return refReached && std::abs(trcNoCov.getSnp()) < 0.95 && TMath::Abs(trcNoCov.getZ()) < Geo::MAXHZTOF; // Here we need to put MAXSNP
2064}
2065
2066//______________________________________________
2067void MatchTOF::setDebugFlag(UInt_t flag, bool on)
2068{
2070 if (on) {
2071 mDBGFlags |= flag;
2072 } else {
2073 mDBGFlags &= ~flag;
2074 }
2075}
2076//______________________________________________
2077void MatchTOF::updateTimeDependentParams()
2078{
2081 mTPCTBinMUS = elParam.ZbinWidth; // TPC bin in microseconds
2082 mTPCTBinMUSInv = 1. / mTPCTBinMUS;
2083 mTPCBin2Z = mTPCTBinMUS * mTPCVDrift;
2084
2085 mBz = o2::base::Propagator::Instance()->getNominalBz();
2086 mMaxInvPt = std::abs(mBz) > 0.1 ? 1. / (std::abs(mBz) * 0.05) : 999.;
2087
2088 const auto& trackTune = TrackTuneParams::Instance();
2089 float scale = mCTPLumi;
2090 if (scale < 0.f) {
2091 LOGP(warning, "Negative scale factor for TPC covariance correction, setting it to zero");
2092 scale = 0.f;
2093 }
2094 mCovDiagInner = trackTune.getCovInnerTotal(scale);
2095 mCovDiagOuter = trackTune.getCovOuterTotal(scale);
2096}
2097
2098//_________________________________________________________
2100{
2101 auto& match = mMatchedTracks[trkType::TPC][matchedID];
2102 const auto& tpcTrOrig = mRecoCont->getTPCTrack(match.getTrackRef());
2103 const auto& tofCl = mTOFClustersArrayInp[match.getTOFClIndex()];
2104 const auto& intLT = match.getLTIntegralOut();
2105
2106 // correct the time of the track
2107 auto timeTOFMUS = (tofCl.getTime() - intLT.getTOF(tpcTrOrig.getPID())) * 1e-6; // tof time in \mus, FIXME: account for time of flight to R TOF
2108 auto timeTOFTB = timeTOFMUS * mTPCTBinMUSInv; // TOF time in TPC timebins, including TPC time offset
2109 auto deltaTBins = timeTOFTB - tpcTrOrig.getTime0(); // time shift in timeBins
2110 float timeErr = 0.010; // assume 10 ns error FIXME
2111 auto dzCorr = deltaTBins * mTPCBin2Z;
2112
2113 if (mTPCClusterIdxStruct) { // refit was requested
2114 trConstr.o2::track::TrackParCov::operator=(tpcTrOrig.getOuterParam()); // seed for inward refit of constrained track, made from the outer param
2115 trConstr.setParamOut(tpcTrOrig); // seed for outward refit of constrained track, made from the inner param
2116 } else {
2117 trConstr.o2::track::TrackParCov::operator=(tpcTrOrig); // inner param, we just correct its position, w/o refit
2118 trConstr.setParamOut(tpcTrOrig.getOuterParam()); // outer param, we just correct its position, w/o refit
2119 }
2120
2121 auto& trConstrOut = trConstr.getParamOut();
2122
2123 auto zTrack = trConstr.getZ();
2124 auto zTrackOut = trConstrOut.getZ();
2125
2126 if (tpcTrOrig.hasASideClustersOnly()) {
2127 zTrack += dzCorr;
2128 zTrackOut += dzCorr;
2129 } else if (tpcTrOrig.hasCSideClustersOnly()) {
2130 zTrack -= dzCorr;
2131 zTrackOut -= dzCorr;
2132 } else {
2133 // TODO : special treatment of tracks crossing the CE
2134 }
2135 trConstr.setZ(zTrack);
2136 trConstrOut.setZ(zTrackOut);
2137 //
2138 trConstr.setTimeMUS(timeTOFMUS, timeErr);
2139 trConstr.setRefMatch(matchedID);
2140 if (mTPCClusterIdxStruct) { // refit was requested
2141 float chi2 = 0;
2142 mTPCRefitter->setTrackReferenceX(o2::constants::geom::XTPCInnerRef);
2143 if (mTPCRefitter->RefitTrackAsTrackParCov(trConstr, tpcTrOrig.getClusterRef(), timeTOFTB, &chi2, false, true) < 0) { // inward refit after resetting cov.mat.
2144 LOGP(debug, "Inward Refit failed {}", trConstr.asString());
2145 return false;
2146 }
2147 const auto& trackTune = TrackTuneParams::Instance(); // if needed, correct TPC track after inward refit
2148 if (!trackTune.useTPCInnerCorr) {
2149 trConstr.updateParams(trackTune.tpcParInner);
2150 }
2151 if (trackTune.tpcCovInnerType != TrackTuneParams::AddCovType::Disable) {
2152 trConstr.updateCov(mCovDiagInner, trackTune.tpcCovInnerType == TrackTuneParams::AddCovType::WithCorrelations);
2153 }
2154
2155 trConstr.setChi2Refit(chi2);
2156 //
2157 mTPCRefitter->setTrackReferenceX(o2::constants::geom::XTPCOuterRef);
2158 if (mTPCRefitter->RefitTrackAsTrackParCov(trConstrOut, tpcTrOrig.getClusterRef(), timeTOFTB, &chi2, true, true) < 0) { // outward refit after resetting cov.mat.
2159 LOGP(debug, "Outward Refit failed {}", trConstrOut.asString());
2160 return false;
2161 }
2162 }
2163
2164 return true;
2165}
2166
2167//_________________________________________________________
2169{
2170 if (mTPCClusterIdxStruct) {
2171 mTPCRefitter = std::make_unique<o2::gpu::GPUO2InterfaceRefit>(mTPCClusterIdxStruct, mTPCCorrMaps, mBz,
2172 mTPCTrackClusIdx.data(), 0, mTPCRefitterShMap.data(),
2173 mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size(), nullptr, o2::base::Propagator::Instance());
2174 }
2175}
header::DataOrigin origin
General auxilliary methods.
Wrapper container for different reconstructed object types.
particle ids, masses, names class definition
Definition of the GeometryManager class.
std::ostringstream debug
uint64_t bc
Definition RawEventData.h:5
int32_t i
Header of the General Run Parameters object.
Some ALICE geometry constants of common interest.
Definition of a container to keep Monte Carlo truth external to simulation objects.
Definition of the fast magnetic field parametrization MagFieldFast.
Definition of the MagF class.
ClassImp(MatchTOF)
Class to perform TOF matching to global tracks.
useful math constants
Definition of the parameter class for the detector electronics.
Definition of the parameter class for the detector gas.
Header to collect physics constants.
uint16_t pos
Definition RawData.h:3
uint32_t side
Definition RawData.h:0
uint32_t res
Definition RawData.h:0
Wrapper container for different reconstructed object types.
class to create TPC fast transformation
Track Length and TOF integral.
Configurable params for tracks ad hoc tuning.
calibration data from laser track calibration
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:178
A container to hold and manage MC truth information/labels.
gsl::span< TruthElement > getLabels(uint32_t dataindex)
o2::track::TrackParCov & getParamOut()
Definition TrackTPCTOF.h:53
void setTimeMUS(const timeEst &t)
Definition TrackTPCTOF.h:43
void setParamOut(const o2::track::TrackParCov &v)
Definition TrackTPCTOF.h:55
void setTPCVDrift(const o2::tpc::VDriftCorrFact &v)
Definition MatchTOF.cxx:249
void printCandidatesTOF() const
set time tolerance on track-TOF times comparison
Definition MatchTOF.cxx:279
void setTPCCorrMaps(const o2::gpu::TPCFastTransformPOD *maph, float lumi)
Definition MatchTOF.cxx:258
void run(const o2::globaltracking::RecoContainer &inp, unsigned long firstTForbit=0)
< perform matching for provided input
Definition MatchTOF.cxx:67
void setDebugFlag(UInt_t flag, bool on=true)
set the name of output debug file
static void groupingMatch(const std::vector< o2::dataformats::MatchInfoTOFReco > &origin, std::vector< std::vector< o2::dataformats::MatchInfoTOFReco > > &grouped, std::vector< std::vector< int > > &firstEls, std::vector< std::vector< int > > &secondEls)
Definition MatchTOF.cxx:318
static void printGrouping(const std::vector< o2::dataformats::MatchInfoTOFReco > &origin, const std::vector< std::vector< o2::dataformats::MatchInfoTOFReco > > &grouped)
Definition MatchTOF.cxx:300
static int findFITIndex(int bc, const gsl::span< const o2::ft0::RecPoints > &FITRecPoints, unsigned long firstOrbit)
bool makeConstrainedTPCTrack(int matchedID, o2::dataformats::TrackTPCTOF &trConstr)
populate externally provided container by TOF-time-constrained TPC tracks
HMPID cluster implementation.
Definition Cluster.h:27
Cluster class for TOF.
Definition Cluster.h:37
static constexpr Float_t RMAX
Definition Geo.h:136
static constexpr Float_t ZPAD
Definition Geo.h:143
static constexpr Float_t XPAD
Definition Geo.h:141
static constexpr Double_t BC_TIME_INPS
Definition Geo.h:105
static constexpr Double_t BC_TIME_INPS_INV
Definition Geo.h:106
static Float_t getAngles(Int_t iplate, Int_t istrip)
Definition Geo.h:81
static constexpr Int_t NPADS
Definition Geo.h:112
static void Init()
Definition Geo.cxx:43
static constexpr Int_t LATENCYWINDOW_IN_BC
Definition Geo.h:174
static constexpr Float_t MAXHZTOF
Definition Geo.h:129
static void getVolumeIndices(Int_t index, Int_t *detId)
Definition Geo.cxx:543
static void getPadDxDyDz(const Float_t *pos, Int_t *det, Float_t *DeltaPos, int sector=-1)
Definition Geo.cxx:835
static double subtractInteractionBC(double time, int &mask, bool subLatency=false)
Definition Utils.cxx:122
static int getNinteractionBC()
Definition Utils.cxx:117
static bool hasFillScheme()
Definition Utils.cxx:261
static int getInteractionBC(int ibc)
Definition Utils.h:50
static constexpr ID Pion
Definition PID.h:96
bool match(const std::vector< std::string > &queries, const char *pattern)
Definition dcs-ccdb.cxx:229
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLuint end
Definition glcorearb.h:469
const GLdouble * v
Definition glcorearb.h:832
GLuint index
Definition glcorearb.h:781
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
GLsizei GLenum const void * indices
Definition glcorearb.h:400
GLbitfield flags
Definition glcorearb.h:1570
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
Definition glcorearb.h:5034
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLint GLuint mask
Definition glcorearb.h:291
constexpr float XTPCOuterRef
reference radius to propagate outer TPC track
constexpr float XTPCInnerRef
reference radius at which TPC provides the tracks
constexpr int LHCMaxBunches
constexpr int NSectors
constexpr float SectorSpanRad
float angle2Alpha(float phi)
Definition Utils.h:203
int angle2Sector(float phi)
Definition Utils.h:183
Enum< T >::Iterator begin(Enum< T >)
Definition Defs.h:156
TrackParCovF TrackParCov
Definition Track.h:33
value_T step
Definition TrackUtils.h:42
std::string getTime(uint64_t ts)
uint32_t orbit
LHC orbit.
uint16_t bc
bunch crossing ID of interaction
const o2::tpc::TrackTPC & getTPCTrack(GTrackID id) const
auto getTPCITSTrackMCLabel(GTrackID id) const
void createTracksVariadic(T creator, GTrackID::mask_t srcSel=GTrackID::getSourcesMask("all")) const
auto getTPCTrackMCLabel(GTrackID id) const
gsl::span< const unsigned char > clusterShMapTPC
externally set TPC clusters sharing map
std::unique_ptr< o2::tpc::internal::getWorkflowTPCInput_ret > inputsTPCclusters
gsl::span< const unsigned int > occupancyMapTPC
externally set TPC clusters occupancy map
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)
LumiInfo lumi