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