Project
Loading...
Searching...
No Matches
MatchCosmics.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
15#include "GPUO2InterfaceRefit.h"
26#include "ITStracking/IOUtils.h"
36#include <algorithm>
37#include <numeric>
38
39using namespace o2::globaltracking;
40
43
44//________________________________________________________
46{
47 updateTimeDependentParams();
48 mRecords.clear();
49 mWinners.clear();
50 mCosmicTracks.clear();
51 mCosmicTracksLbl.clear();
52
53 createSeeds(data);
54 int ntr = mSeeds.size();
55
56 // propagate to DCA to origin
57 const o2::math_utils::Point3D<float> v{0., 0., 0};
58 for (int i = 0; i < ntr; i++) {
59 auto& trc = mSeeds[i];
60 if (!o2::base::Propagator::Instance()->propagateToDCABxByBz(v, trc, mMatchParams->maxStep, mMatchParams->matCorr)) {
61 trc.matchID = Reject; // reject track
62 }
63 }
64
65 // sort in time bracket lower edge
66 std::vector<int> sortID(ntr);
67 std::iota(sortID.begin(), sortID.end(), 0);
68 std::sort(sortID.begin(), sortID.end(), [this](int a, int b) { return mSeeds[a].tBracket.getMin() < mSeeds[b].tBracket.getMin(); });
69
70 for (int i = 0; i < ntr; i++) {
71 for (int j = i + 1; j < ntr; j++) {
72 if (checkPair(sortID[i], sortID[j]) == RejTime) {
73 break;
74 }
75 }
76 }
77
78 selectWinners();
79 refitWinners(data);
80
81 mTFCount++;
82}
83
84//________________________________________________________
85void MatchCosmics::refitWinners(const o2::globaltracking::RecoContainer& data)
86{
87 LOG(info) << "Refitting " << mWinners.size() << " winner matches";
88 int count = 0;
89 auto tpcTBinMUSInv = 1. / mTPCTBinMUS;
90 const auto& tpcClusRefs = data.getTPCTracksClusterRefs();
91 const auto& tpcClusShMap = data.clusterShMapTPC;
92 const auto& tpcClusOccMap = data.occupancyMapTPC;
93 std::unique_ptr<o2::gpu::GPUO2InterfaceRefit> tpcRefitter;
94 if (data.inputsTPCclusters) {
95 tpcRefitter = std::make_unique<o2::gpu::GPUO2InterfaceRefit>(&data.inputsTPCclusters->clusterIndex,
96 mTPCCorrMapsHelper, mBz,
97 tpcClusRefs.data(), 0, tpcClusShMap.data(),
98 tpcClusOccMap.data(), tpcClusOccMap.size(), nullptr, o2::base::Propagator::Instance());
99 tpcRefitter->setTrackReferenceX(900); // disable propagation after refit by setting reference to value > 500
100 }
101
102 const auto& itsClusters = prepareITSClusters(data);
103 // RS FIXME: this is probably a temporary solution, since ITS tracking over boundaries will likely change the TrackITS format
104 std::vector<int> itsTracksROF;
105
106 const auto& itsTracksROFRec = data.getITSTracksROFRecords();
107 itsTracksROF.resize(data.getITSTracks().size());
108 for (unsigned irf = 0, cnt = 0; irf < itsTracksROFRec.size(); irf++) {
109 int ntr = itsTracksROFRec[irf].getNEntries();
110 for (int itr = 0; itr < ntr; itr++) {
111 itsTracksROF[cnt++] = irf;
112 }
113 }
114
115 auto refitITSTrack = [this, &data, &itsTracksROF, &itsClusters](o2::track::TrackParCov& trFit, GTrackID gidx, float& chi2, bool inward = false) {
116 const auto& itsTrOrig = data.getITSTrack(gidx);
117 int nclRefit = 0, ncl = itsTrOrig.getNumberOfClusters(), rof = itsTracksROF[gidx.getIndex()];
118 const auto& itsTrackClusRefs = data.getITSTracksClusterRefs();
119 int clEntry = itsTrOrig.getFirstClusterEntry();
120 const auto propagator = o2::base::Propagator::Instance();
121 const auto geomITS = o2::its::GeometryTGeo::Instance();
122 int from = ncl - 1, to = -1, step = -1;
123 if (inward) {
124 from = 0;
125 to = ncl;
126 step = 1;
127 }
128 for (int icl = from; icl != to; icl += step) { // ITS clusters are referred in layer decreasing order
129 const auto& clus = itsClusters[itsTrackClusRefs[clEntry + icl]];
130 float alpha = geomITS->getSensorRefAlpha(clus.getSensorID()), x = clus.getX();
131 if (!trFit.rotate(alpha) || !propagator->propagateToX(trFit, x, propagator->getNominalBz(), this->mMatchParams->maxSnp, this->mMatchParams->maxStep, this->mMatchParams->matCorr)) {
132 break;
133 }
134 chi2 += trFit.getPredictedChi2(clus);
135 if (!trFit.update(clus)) {
136 break;
137 }
138 nclRefit++;
139 }
140 return nclRefit == ncl ? ncl : -1;
141 };
142
143 for (auto winRID : mWinners) {
144 const auto& rec = mRecords[winRID];
145 int poolEntryID[2] = {rec.id0, rec.id1};
146 const o2::track::TrackParCov outerLegs[2] = {data.getTrackParamOut(mSeeds[rec.id0].origID), data.getTrackParamOut(mSeeds[rec.id1].origID)};
147 auto tOverlap = mSeeds[rec.id0].tBracket.getOverlap(mSeeds[rec.id1].tBracket);
148 float t0 = tOverlap.mean(), dt = tOverlap.delta() * 0.5;
149 auto pnt0 = outerLegs[0].getXYZGlo(), pnt1 = outerLegs[1].getXYZGlo();
150 int btm = 0, top = 1;
151 // we fit topward from bottom
152 if (pnt0.Y() > pnt1.Y()) {
153 btm = 1;
154 top = 0;
155 }
156 LOG(debug) << "Winner " << count++ << " Record " << winRID << " Partners:"
157 << " B: " << mSeeds[poolEntryID[btm]].origID << "/" << mSeeds[poolEntryID[btm]].origID.getSourceName()
158 << " U: " << mSeeds[poolEntryID[top]].origID << "/" << mSeeds[poolEntryID[top]].origID.getSourceName()
159 << " | T:" << tOverlap.asString();
160
161 float chi2 = 0;
162 int nclTot = 0;
163
164 // Start from bottom leg inward refit
165 o2::track::TrackParCov trCosm(mSeeds[poolEntryID[btm]]); // copy of the btm track
166 // The bottom leg needs refit only if it is an unconstrained TPC track, otherwise it is already refitted as inner param
167 if (mSeeds[poolEntryID[btm]].origID.getSource() == GTrackID::TPC) {
168 const auto& tpcTrOrig = data.getTPCTrack(mSeeds[poolEntryID[btm]].origID);
169 trCosm = outerLegs[btm];
170 trCosm.resetCovariance();
171 // in case of cosmics, constrain the momentum
172 if (!mFieldON) {
173 trCosm.setQ2Pt(-o2::track::kMostProbablePt);
174 }
175 int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosm, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2, false, false); // inward refit, reset
176 if (retVal < 0) { // refit failed
177 LOG(debug) << "Inward refit of btm TPC track failed.";
178 continue;
179 }
180 nclTot += retVal;
181 LOG(debug) << "chi2 after btm TPC refit with " << retVal << " clusters : " << chi2 << " orig.chi2 was " << tpcTrOrig.getChi2();
182 } else { // just collect NClusters and chi2
183 // since we did not refit bottom track, we just invert its conventional q/pT in case of B=0, so that after the inversion it gets correct sign
184 if (!mFieldON) {
185 trCosm.setQ2Pt(-trCosm.getQ2Pt());
186 }
187 auto gidxListBtm = data.getSingleDetectorRefs(mSeeds[poolEntryID[btm]].origID);
188 if (gidxListBtm[GTrackID::TPC].isIndexSet()) {
189 const auto& tpcTrOrig = data.getTPCTrack(gidxListBtm[GTrackID::TPC]);
190 nclTot += tpcTrOrig.getNClusters();
191 chi2 += tpcTrOrig.getChi2();
192 }
193 if (gidxListBtm[GTrackID::ITS].isIndexSet()) {
194 const auto& itsTrOrig = data.getITSTrack(gidxListBtm[GTrackID::ITS]);
195 nclTot += itsTrOrig.getNClusters();
196 chi2 += itsTrOrig.getChi2();
197 }
198 }
199 trCosm.invert();
200 if (!trCosm.rotate(mSeeds[poolEntryID[top]].getAlpha()) ||
201 !o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosm, mSeeds[poolEntryID[top]].getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) {
202 LOG(debug) << "Rotation/propagation of btm-track to top-track frame failed.";
203 continue;
204 }
205 // save bottom parameter at merging point
206 auto trCosmBtm = trCosm;
207 int nclBtm = nclTot;
208
209 // Continue with top leg outward refit
210 auto gidxListTop = data.getSingleDetectorRefs(mSeeds[poolEntryID[top]].origID);
211
212 // is there ITS sub-track?
213 if (gidxListTop[GTrackID::ITS].isIndexSet()) {
214 auto nclfit = refitITSTrack(trCosm, gidxListTop[GTrackID::ITS], chi2, false);
215 if (nclfit < 0) {
216 continue;
217 }
218 LOG(debug) << "chi2 after top ITS refit with " << nclfit << " clusters : " << chi2 << " orig.chi2 was " << data.getITSTrack(gidxListTop[GTrackID::ITS]).getChi2();
219 nclTot += nclfit;
220 } // ITS refit
221 //
222 if (gidxListTop[GTrackID::TPC].isIndexSet()) { // outward refit in TPC
223 // go to TPC boundary, if needed
224 if (trCosm.getX() * trCosm.getX() + trCosm.getY() * trCosm.getY() <= o2::constants::geom::XTPCInnerRef * o2::constants::geom::XTPCInnerRef) {
225 float xtogo = 0;
226 if (!trCosm.getXatLabR(o2::constants::geom::XTPCInnerRef, xtogo, mBz, o2::track::DirOutward) ||
227 !o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosm, xtogo, mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) {
228 LOG(debug) << "Propagation to inner TPC boundary X=" << xtogo << " failed";
229 continue;
230 }
231 }
232 const auto& tpcTrOrig = data.getTPCTrack(gidxListTop[GTrackID::TPC]);
233 int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosm, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2, true, false); // outward refit, no reset
234 if (retVal < 0) { // refit failed
235 LOG(debug) << "Outward refit of top TPC track failed.";
236 continue;
237 } // outward refit in TPC
238 LOG(debug) << "chi2 after top TPC refit with " << retVal << " clusters : " << chi2 << " orig.chi2 was " << tpcTrOrig.getChi2();
239 nclTot += retVal;
240 }
241
242 // inward refit of top leg for evaluation in DCA
243 float chi2Dummy = 0;
244 auto trCosmTop = outerLegs[top];
245 if (gidxListTop[GTrackID::TPC].isIndexSet()) { // inward refit in TPC
246 const auto& tpcTrOrig = data.getTPCTrack(gidxListTop[GTrackID::TPC]);
247 int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosmTop, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2Dummy, false, true); // inward refit, reset
248 if (retVal < 0) { // refit failed
249 LOG(debug) << "Outward refit of top TPC track failed.";
250 continue;
251 } // inward refit in TPC
252 }
253 // is there ITS sub-track ?
254 if (gidxListTop[GTrackID::ITS].isIndexSet()) {
255 auto nclfit = refitITSTrack(trCosmTop, gidxListTop[GTrackID::ITS], chi2Dummy, true);
256 if (nclfit < 0) {
257 continue;
258 }
259 nclTot += nclfit;
260 } // ITS refit
261 // propagate to bottom param
262 if (!trCosmTop.rotate(trCosmBtm.getAlpha()) ||
263 !o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosmTop, trCosmBtm.getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) {
264 LOG(debug) << "Rotation/propagation of top-track to bottom-track frame failed.";
265 continue;
266 }
267 // calculate weighted average of 2 legs and chi2
268 o2::track::TrackParCov::MatrixDSym5 cov5;
269 float chi2Match = trCosmBtm.getPredictedChi2(trCosmTop, cov5);
270 if (!trCosmBtm.update(trCosmTop, cov5)) {
271 LOG(debug) << "Top/Bottom update failed";
272 continue;
273 }
274 // create final track
275 mCosmicTracks.emplace_back(mSeeds[poolEntryID[btm]].origID, mSeeds[poolEntryID[top]].origID, trCosmBtm, trCosmTop, chi2, chi2Match, nclTot, t0, dt);
276 if (mUseMC) {
277 o2::MCCompLabel lbl[2] = {data.getTrackMCLabel(mSeeds[poolEntryID[btm]].origID), data.getTrackMCLabel(mSeeds[poolEntryID[top]].origID)};
278 auto& tlb = mCosmicTracksLbl.emplace_back((nclBtm > nclTot - nclBtm ? lbl[0] : lbl[1]));
279 tlb.setFakeFlag(lbl[0] != lbl[1]);
280 }
281 }
282 LOG(info) << "Validated " << mCosmicTracks.size() << " top-bottom tracks in TF# " << mTFCount;
283}
284
285//________________________________________________________
286void MatchCosmics::selectWinners()
287{
288 // select mutually best matches
289 int ntr = mSeeds.size(), iter = 0, nValidated = 0;
290 mWinners.reserve(mRecords.size() / 2); // there are 2 records per match candidate
291 do {
292 nValidated = 0;
293 int nRemaining = 0;
294 for (int i = 0; i < ntr; i++) {
295 if (mSeeds[i].matchID < 0 || mRecords[mSeeds[i].matchID].next == Validated) { // either have no match or already validated
296 continue;
297 }
298 nRemaining++;
299 if (validateMatch(i)) {
300 mWinners.push_back(mSeeds[i].matchID);
301 nValidated++;
302 continue;
303 }
304 }
305 LOGF(info, "iter %d Validated %d of %d remaining matches", iter, nValidated, nRemaining);
306 iter++;
307 } while (nValidated);
308}
309
310//________________________________________________________
311bool MatchCosmics::validateMatch(int partner0)
312{
313 // make sure that the best partner of seed_i has also seed_i as a best partner
314 auto& matchRec = mRecords[mSeeds[partner0].matchID];
315 auto partner1 = matchRec.id1;
316 auto& patnerRec = mRecords[mSeeds[partner1].matchID];
317 if (patnerRec.next == Validated) { // partner1 was already validated with other partner0
318 return false;
319 }
320 if (patnerRec.id1 == partner0) { // mutually best
321 // unlink winner partner0 from all other mathes
322 auto next0 = matchRec.next;
323 while (next0 > MinusOne) {
324 auto& nextRec = mRecords[next0];
325 suppressMatch(partner0, nextRec.id1);
326 next0 = nextRec.next;
327 }
328 matchRec.next = Validated;
329
330 // unlink winner partner1 from all other matches
331 auto next1 = patnerRec.next;
332 while (next1 > MinusOne) {
333 auto& nextRec = mRecords[next1];
334 suppressMatch(partner1, nextRec.id1);
335 next1 = nextRec.next;
336 }
337 patnerRec.next = Validated;
338 return true;
339 }
340 return false;
341}
342
343//________________________________________________________
344void MatchCosmics::suppressMatch(int partner0, int partner1)
345{
346 // suppress reference to partner0 from partner1 match record
347 if (mSeeds[partner1].matchID < 0 || mRecords[mSeeds[partner1].matchID].next == Validated) {
348 LOG(warning) << "Attempt to remove null or validated partner match " << mSeeds[partner1].matchID;
349 return;
350 }
351 int topID = MinusOne, next = mSeeds[partner1].matchID;
352 while (next > MinusOne) {
353 auto& matchRec = mRecords[next];
354 if (matchRec.id1 == partner0) {
355 if (topID < 0) { // best match
356 mSeeds[partner1].matchID = matchRec.next; // exclude best match link
357 } else { // not the 1st link in the chain
358 mRecords[topID].next = matchRec.next;
359 }
360 return;
361 }
362 topID = next;
363 next = matchRec.next;
364 }
365}
366
367//________________________________________________________
368MatchCosmics::RejFlag MatchCosmics::checkPair(int i, int j)
369{
370 // if validated with given chi2, register match
371 RejFlag rej = RejOther;
372 auto& seed0 = mSeeds[i];
373 auto& seed1 = mSeeds[j];
374 if (seed0.matchID == Reject) {
375 return rej;
376 }
377 if (seed1.matchID == Reject) {
378 return rej;
379 }
380
381 LOG(debug) << "Seed " << i << " [" << seed0.tBracket.getMin() << " : " << seed0.tBracket.getMax() << "] | "
382 << "Seed " << j << " [" << seed1.tBracket.getMin() << " : " << seed1.tBracket.getMax() << "] | ";
383 LOG(debug) << seed0.origID << " | " << seed0.o2::track::TrackPar::asString();
384 LOG(debug) << seed1.origID << " | " << seed1.o2::track::TrackPar::asString();
385
386 if (seed1.tBracket > seed0.tBracket) {
387 return (rej = RejTime); // since the brackets are sorted in tmin, all following tbj will also exceed tbi
388 }
389 float chi2 = 1.e9f;
390
391 // check
392 // 1) crude check on tgl and q/pt (if B!=0). Note: back-to-back tracks will have mutually params (see TrackPar::invertParam)
393 while (1) {
394 auto dTgl = seed0.getTgl() + seed1.getTgl();
395 if (dTgl * dTgl > (mMatchParams->systSigma2[o2::track::kTgl] + seed0.getSigmaTgl2() + seed1.getSigmaTgl2()) * mMatchParams->crudeNSigma2Cut[o2::track::kTgl]) {
396 rej = RejTgl;
397 break;
398 }
399 if (mFieldON) {
400 auto dQ2Pt = seed0.getQ2Pt() + seed1.getQ2Pt();
401 if (dQ2Pt * dQ2Pt > (mMatchParams->systSigma2[o2::track::kQ2Pt] + seed0.getSigma1Pt2() + seed1.getSigma1Pt2()) * mMatchParams->crudeNSigma2Cut[o2::track::kQ2Pt]) {
402 rej = RejQ2Pt;
403 break;
404 }
405 }
406 o2::track::TrackParCov seed1Inv = seed1;
407 seed1Inv.invert();
408 for (int i = 0; i < o2::track::kNParams; i++) { // add systematic error
409 seed1Inv.updateCov(mMatchParams->systSigma2[i], o2::track::DiagMap[i]);
410 }
411
412 if (!seed1Inv.rotate(seed0.getAlpha()) ||
413 !o2::base::Propagator::Instance()->PropagateToXBxByBz(seed1Inv, seed0.getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) {
414 rej = RejProp;
415 break;
416 }
417 auto dSnp = seed0.getSnp() - seed1Inv.getSnp();
418 if (dSnp * dSnp > (seed0.getSigmaSnp2() + seed1Inv.getSigmaSnp2()) * mMatchParams->crudeNSigma2Cut[o2::track::kSnp]) {
419 rej = RejSnp;
420 break;
421 }
422 auto dY = seed0.getY() - seed1Inv.getY();
423 if (dY * dY > (seed0.getSigmaY2() + seed1Inv.getSigmaY2()) * mMatchParams->crudeNSigma2Cut[o2::track::kY]) {
424 rej = RejY;
425 break;
426 }
427 bool ignoreZ = seed0.origID.getSource() == o2d::GlobalTrackID::TPC || seed1.origID.getSource() == o2d::GlobalTrackID::TPC;
428 if (!ignoreZ) { // cut on Z makes no sense for TPC only tracks
429 auto dZ = seed0.getZ() - seed1Inv.getZ();
430 if (dZ * dZ > (seed0.getSigmaZ2() + seed1Inv.getSigmaZ2()) * mMatchParams->crudeNSigma2Cut[o2::track::kZ]) {
431 rej = RejZ;
432 break;
433 }
434 } else { // inflate Z error
435 seed1Inv.setCov(250. * 250., o2::track::DiagMap[o2::track::kZ]);
436 seed1Inv.setCov(0., o2::track::CovarMap[o2::track::kZ][o2::track::kY]); // set all correlation terms for Z error to 0
437 seed1Inv.setCov(0., o2::track::CovarMap[o2::track::kZ][o2::track::kSnp]);
438 seed1Inv.setCov(0., o2::track::CovarMap[o2::track::kZ][o2::track::kTgl]);
439 seed1Inv.setCov(0., o2::track::CovarMap[o2::track::kZ][o2::track::kQ2Pt]);
440 }
441 // calculate chi2 (expensive)
442 chi2 = seed0.getPredictedChi2(seed1Inv);
443 if (chi2 > mMatchParams->crudeChi2Cut) {
444 rej = RejChi2;
445 break;
446 }
447 rej = Accept;
448 registerMatch(i, j, chi2);
449 registerMatch(j, i, chi2); // the reverse reference can be also done in a separate loop
450 LOG(debug) << "Chi2 = " << chi2 << " NMatches " << mRecords.size();
451 break;
452 }
453
454#ifdef _ALLOW_DEBUG_TREES_
455 if (mDBGOut && ((rej == Accept && isDebugFlag(MatchTreeAccOnly)) || isDebugFlag(MatchTreeAll))) {
456 auto seed1I = seed1;
457 seed1I.invert();
458 if (seed1I.rotate(seed0.getAlpha()) && o2::base::Propagator::Instance()->PropagateToXBxByBz(seed1I, seed0.getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) {
459 int rejI = int(rej);
460 (*mDBGOut) << "match"
461 << "tf=" << mTFCount << "seed0=" << seed0 << "seed1=" << seed1I << "chi2Match=" << chi2 << "rej=" << rejI << "\n";
462 }
463 }
464#endif
465
466 return rej;
467}
468
469//________________________________________________________
470void MatchCosmics::registerMatch(int i, int j, float chi2)
471{
473 int newRef = mRecords.size();
474 auto& matchRec = mRecords.emplace_back(MatchRecord{i, j, chi2, MinusOne});
475 auto* best = &mSeeds[i].matchID;
476 while (*best > MinusOne) {
477 auto& oldMatchRec = mRecords[*best];
478 if (oldMatchRec.chi2 > chi2) { // insert new match in front of the old one
479 matchRec.next = *best; // new record will refer to the one it is superseding
480 *best = newRef; // the reference on the superseded record should now refer to new one
481 break;
482 }
483 best = &oldMatchRec.next;
484 }
485 if (matchRec.next == MinusOne) { // did not supersed any other record
486 *best = newRef;
487 }
488}
489
490//________________________________________________________
491void MatchCosmics::createSeeds(const o2::globaltracking::RecoContainer& data)
492{
493 // Scan all inputs and create seeding tracks
494
495 mSeeds.clear();
496
497 auto creator = [this](auto& _tr, GTrackID _origID, float t0, float terr) {
498 if constexpr (std::is_base_of_v<o2::track::TrackParCov, std::decay_t<decltype(_tr)>>) {
499 if (std::abs(_tr.getQ2Pt()) > this->mQ2PtCutoff) {
500 return true;
501 }
502 if constexpr (isTPCTrack<decltype(_tr)>()) {
503 if (!this->mMatchParams->allowTPCOnly) {
504 return true;
505 }
506 // unconstrained TPC track, with t0 = TrackTPC.getTime0+0.5*(DeltaFwd-DeltaBwd) and terr = 0.5*(DeltaFwd+DeltaBwd) in TimeBins
507 t0 *= this->mTPCTBinMUS;
508 terr *= this->mTPCTBinMUS;
509 } else if (isITSTrack<decltype(_tr)>()) {
510 t0 += 0.5 * this->mITSROFrameLengthMUS; // time 0 is supplied as beginning of ROF in \mus
511 terr *= this->mITSROFrameLengthMUS; // error is supplied a half-ROF duration, convert to \mus
512 } else { // all other tracks are provided with time and its gaussian error in \mus
513 terr *= this->mMatchParams->nSigmaTError;
514 }
515 terr += this->mMatchParams->timeToleranceMUS;
516 mSeeds.emplace_back(TrackSeed{_tr, {t0 - terr, t0 + terr}, _origID, MinusOne});
517 return true;
518 } else {
519 return false;
520 }
521 };
522
523 data.createTracksVariadic(creator);
524
525 LOG(info) << "collected " << mSeeds.size() << " seeds";
526}
527
528//________________________________________________________
529void MatchCosmics::updateTimeDependentParams()
530{
533 mTPCTBinMUS = elParam.ZbinWidth; // TPC bin in microseconds
534 mBz = o2::base::Propagator::Instance()->getNominalBz();
535 mFieldON = std::abs(mBz) > 0.01;
536 mQ2PtCutoff = 1.f / std::max(0.05f, mMatchParams->minSeedPt);
537 if (mFieldON) {
538 mQ2PtCutoff *= 5.00668 / std::abs(mBz);
539 } else {
540 mQ2PtCutoff = 1e9;
541 }
542}
543
544//________________________________________________________
546{
548
549#ifdef _ALLOW_DEBUG_TREES_COSM
550 // debug streamer
551 if (mDBGFlags) {
552 mDBGOut = std::make_unique<o2::utils::TreeStreamRedirector>(mDebugTreeFileName.data(), "recreate");
553 }
554#endif
555}
556
557//________________________________________________________
558std::vector<o2::BaseCluster<float>> MatchCosmics::prepareITSClusters(const o2::globaltracking::RecoContainer& data) const
559{
560 std::vector<o2::BaseCluster<float>> itscl;
561 const auto& clusITS = data.getITSClusters();
562 if (clusITS.size()) {
563 const auto& patterns = data.getITSClustersPatterns();
564 itscl.reserve(clusITS.size());
565 auto pattIt = patterns.begin();
566 o2::its::ioutils::convertCompactClusters(clusITS, pattIt, itscl, mITSDict);
567 }
568 return std::move(itscl);
569}
570
571//______________________________________________
573{
574#ifdef _ALLOW_DEBUG_TREES_COSM
575 mDBGOut.reset();
576#endif
577}
578
579#ifdef _ALLOW_DEBUG_TREES_
580//______________________________________________
581void MatchCosmics::setDebugFlag(UInt_t flag, bool on)
582{
584 if (on) {
585 mDBGFlags |= flag;
586 } else {
587 mDBGFlags &= ~flag;
588 }
589}
590
591//______________________________________________
593{
594 mTPCVDrift = v.refVDrift * v.corrFact;
595 mTPCVDriftCorrFact = v.corrFact;
596 mTPCVDriftRef = v.refVDrift;
597 mTPCDriftTimeOffset = v.getTimeOffset();
598}
599
600//______________________________________________
602{
603 mTPCCorrMapsHelper = maph;
604}
605
606#endif
Definition of the ITSMFT compact cluster.
Helper class to access correction maps.
Wrapper container for different reconstructed object types.
Definition of the TOF cluster.
Definition of the FIT RecPoints class.
int32_t i
int32_t retVal
Some ALICE geometry constants of common interest.
Accessor for TrackParCov derived objects from multiple containers.
Definition of the GeometryTGeo class.
Definition of the ITSMFT ROFrame (trigger) record.
Class to perform matching/refit of cosmic tracks legs.
Class to store the output of the matching to TOF.
Class to perform TPC ITS matching.
Definition of the parameter class for the detector electronics.
uint32_t j
Definition RawData.h:0
Wrapper container for different reconstructed object types.
constexpr auto isITSTrack()
class to create TPC fast transformation
Definition of the ITS track.
Result of refitting TPC-ITS matched track.
Result of refitting TPC with TOF match constraint.
calibration data from laser track calibration
std::ostringstream debug
Helper class to obtain TPC clusters / digits / labels from DPL.
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:143
@ MatchTreeAll
produce matching candidates tree for all candidates
@ MatchTreeAccOnly
fill the matching candidates tree only once the cut is passed
static constexpr int Validated
void setTPCCorrMaps(o2::gpu::CorrectionMapsHelper *maph)
bool isDebugFlag(UInt_t flags) const
get debug trees flags
void setDebugFlag(UInt_t flag, bool on=true)
set the name of output debug file
void setTPCVDrift(const o2::tpc::VDriftCorrFact &v)
static constexpr int Reject
void process(const o2::globaltracking::RecoContainer &data)
static constexpr int MinusOne
static GeometryTGeo * Instance()
GLfloat GLfloat GLfloat alpha
Definition glcorearb.h:279
GLint GLenum GLint x
Definition glcorearb.h:403
GLint GLsizei count
Definition glcorearb.h:399
const GLdouble * v
Definition glcorearb.h:832
GLdouble GLdouble GLdouble GLdouble top
Definition glcorearb.h:4077
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLboolean * data
Definition glcorearb.h:298
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
Definition glcorearb.h:5034
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
constexpr float XTPCInnerRef
reference radius at which TPC provides the tracks
void convertCompactClusters(gsl::span< const itsmft::CompClusterExt > clusters, gsl::span< const unsigned char >::iterator &pattIt, std::vector< o2::BaseCluster< float > > &output, const itsmft::TopologyDictionary *dict)
convert compact clusters to 3D spacepoints
Definition IOUtils.cxx:49
return * this
TrackParCovF TrackParCov
Definition Track.h:33
constexpr int kNParams
value_T step
Definition TrackUtils.h:42
constexpr float kMostProbablePt
GPUReconstruction * rec
float crudeNSigma2Cut[o2::track::kNParams]
o2::base::Propagator::MatCorrType matCorr
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"