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"
29#include "ITStracking/IOUtils.h"
38#include "TPCFastTransformPOD.h"
39#include <algorithm>
40#include <numeric>
41#include <unordered_map>
42
43using namespace o2::globaltracking;
44
47
48//________________________________________________________
50{
51 updateTimeDependentParams();
52 mRecords.clear();
53 mWinners.clear();
54 mCosmicTracks.clear();
55 mCosmicTracksLbl.clear();
56
57 createSeeds(data);
58 int ntr = mSeeds.size();
59 const auto prop = o2::base::Propagator::Instance();
60 // propagate to DCA to origin
61 const o2::math_utils::Point3D<float> v{0., 0., 0};
62 for (int i = 0; i < ntr; i++) {
63 auto& trc = mSeeds[i];
64 if (trc.matchID != Reject) {
65 if (!prop->propagateToDCABxByBz(v, trc, mMatchParams->maxStep, mMatchParams->matCorr)) {
66 trc.matchID = Reject; // reject track
67 continue;
68 }
69 if (mMatchParams->dcaCutChi2[trc.origID.getSource()] > 0.f && mUsePVInfo && (std::abs(trc.getY()) < mMatchParams->fiducialRIP && std::abs(trc.getZ()) < mMatchParams->fiducialZIP)) {
70 // do the propagation only if we are in the fiducial IP range.
71 for (int iv = trc.vtIDMin; iv < trc.vtIDMax; iv++) {
72 const auto& pv = data.getPrimaryVertex(iv);
73 o2::track::TrackParCov trcatPV(trc);
75 if (!trcatPV.propagateToDCA(pv, mBz, &dca)) {
76 trc.matchID = Reject;
77 break;
78 }
79 if (trc.origID.getSource() == GTrackID::TPC) { // correct the track Z position for the vertex time
80 const auto& trcTPC = data.getTPCTrack(trc.origID);
81 float deltaZ = trcTPC.hasBothSidesClusters() ? 0.f : (pv.getTimeStamp().getTimeStamp() - trcTPC.getTime0() * 8 * o2::constants::lhc::LHCBunchSpacingMUS) * mTPCVDrift;
82 dca.setZ(dca.getZ() + (trcTPC.hasASideClustersOnly() ? deltaZ : -deltaZ));
83 }
84 dca.addCov({mMatchParams->systSigma2[0], 0.f, mMatchParams->systSigma2[1]});
85 if (dca.calcChi2() < mMatchParams->dcaCutChi2[trc.origID.getSource()]) {
86 trc.matchID = Reject;
87 break;
88 }
89 }
90 }
91 }
92 }
93 // sort in time bracket lower edge, putting rejected tracks in the end
94 std::vector<int> sortID(ntr);
95 std::iota(sortID.begin(), sortID.end(), 0);
96 std::sort(sortID.begin(), sortID.end(), [this](int a, int b) { return mSeeds[a].matchID == Reject ? false : (mSeeds[b].matchID == Reject ? true : (mSeeds[a].tBracket.getMin() < mSeeds[b].tBracket.getMin())); });
97 int lastValid = ntr - 1;
98 for (; lastValid >= 0; lastValid--) {
99 if (mSeeds[sortID[lastValid]].matchID != Reject) {
100 break;
101 }
102 }
103 ntr = lastValid >= 0 ? lastValid + 1 : 0;
104 LOGP(info, "Collected {} seeds, validated: {}", mSeeds.size(), ntr);
105 sortID.resize(ntr);
106 for (int i = 0; i < ntr; i++) {
107 for (int j = i + 1; j < ntr; j++) {
108 if (checkPair(sortID[i], sortID[j]) == RejTime) {
109 break;
110 }
111 }
112 }
113
114 selectWinners();
115 refitWinners(data);
116
117 mTFCount++;
118}
119
120//________________________________________________________
121void MatchCosmics::refitWinners(const o2::globaltracking::RecoContainer& data)
122{
123 LOG(info) << "Refitting " << mWinners.size() << " winner matches";
124 int count = 0;
125 auto tpcTBinMUSInv = 1. / mTPCTBinMUS;
126 const auto& tpcClusRefs = data.getTPCTracksClusterRefs();
127 const auto& tpcClusShMap = data.clusterShMapTPC;
128 const auto& tpcClusOccMap = data.occupancyMapTPC;
129 std::unique_ptr<o2::gpu::GPUO2InterfaceRefit> tpcRefitter;
130 if (data.inputsTPCclusters) {
131 tpcRefitter = std::make_unique<o2::gpu::GPUO2InterfaceRefit>(&data.inputsTPCclusters->clusterIndex,
132 mTPCCorrMaps, mBz,
133 tpcClusRefs.data(), 0, tpcClusShMap.data(),
134 tpcClusOccMap.data(), tpcClusOccMap.size(), nullptr, o2::base::Propagator::Instance());
135 }
136
137 const auto& itsClusters = prepareITSClusters(data);
138 // RS FIXME: this is probably a temporary solution, since ITS tracking over boundaries will likely change the TrackITS format
139 std::vector<int> itsTracksROF;
140
141 const auto& itsTracksROFRec = data.getITSTracksROFRecords();
142 itsTracksROF.resize(data.getITSTracks().size());
143 for (unsigned irf = 0, cnt = 0; irf < itsTracksROFRec.size(); irf++) {
144 int ntr = itsTracksROFRec[irf].getNEntries();
145 for (int itr = 0; itr < ntr; itr++) {
146 itsTracksROF[cnt++] = irf;
147 }
148 }
149
150 auto refitITSTrack = [this, &data, &itsTracksROF, &itsClusters](o2::track::TrackParCov& trFit, GTrackID gidx, float& chi2, bool inward = false) {
151 const auto& itsTrOrig = data.getITSTrack(gidx);
152 int nclRefit = 0, ncl = itsTrOrig.getNumberOfClusters(), rof = itsTracksROF[gidx.getIndex()];
153 const auto& itsTrackClusRefs = data.getITSTracksClusterRefs();
154 int clEntry = itsTrOrig.getFirstClusterEntry();
156 const auto geomITS = o2::its::GeometryTGeo::Instance();
157 int from = ncl - 1, to = -1, step = -1;
158 if (inward) {
159 from = 0;
160 to = ncl;
161 step = 1;
162 }
163 for (int icl = from; icl != to; icl += step) { // ITS clusters are referred in layer decreasing order
164 const auto& clus = itsClusters[itsTrackClusRefs[clEntry + icl]];
165 float alpha = geomITS->getSensorRefAlpha(clus.getSensorID()), x = clus.getX();
166 if (!trFit.rotate(alpha) || !propagator->propagateToX(trFit, x, propagator->getNominalBz(), this->mMatchParams->maxSnp, this->mMatchParams->maxStep, this->mMatchParams->matCorr)) {
167 break;
168 }
169 chi2 += trFit.getPredictedChi2(clus);
170 if (!trFit.update(clus)) {
171 break;
172 }
173 nclRefit++;
174 }
175 return nclRefit == ncl ? ncl : -1;
176 };
177
178 for (auto winRID : mWinners) {
179 const auto& rec = mRecords[winRID];
180 int poolEntryID[2] = {rec.id0, rec.id1};
181 const o2::track::TrackParCov outerLegs[2] = {data.getTrackParamOut(mSeeds[rec.id0].origID), data.getTrackParamOut(mSeeds[rec.id1].origID)};
182 auto tOverlap = mSeeds[rec.id0].tBracket.getOverlap(mSeeds[rec.id1].tBracket);
183 float t0 = tOverlap.mean(), dt = tOverlap.delta() * 0.5;
184 auto pnt0 = outerLegs[0].getXYZGlo(), pnt1 = outerLegs[1].getXYZGlo();
185 int btm = 0, top = 1;
186 // we fit topward from bottom
187 if (pnt0.Y() > pnt1.Y()) {
188 btm = 1;
189 top = 0;
190 }
191 LOG(debug) << "Winner " << count++ << " Record " << winRID << " Partners:"
192 << " B: " << mSeeds[poolEntryID[btm]].origID << "/" << mSeeds[poolEntryID[btm]].origID.getSourceName()
193 << " U: " << mSeeds[poolEntryID[top]].origID << "/" << mSeeds[poolEntryID[top]].origID.getSourceName()
194 << " | T:" << tOverlap.asString();
195
196 float chi2 = 0;
197 int nclTot = 0;
198
199 // Start from bottom leg inward refit
200 o2::track::TrackParCov trCosm(mSeeds[poolEntryID[btm]]); // copy of the btm track
201 // The bottom leg needs refit only if it is an unconstrained TPC track, otherwise it is already refitted as inner param
202 if (mSeeds[poolEntryID[btm]].origID.getSource() == GTrackID::TPC) {
203 const auto& tpcTrOrig = data.getTPCTrack(mSeeds[poolEntryID[btm]].origID);
204 trCosm = outerLegs[btm];
205 trCosm.resetCovariance();
206 // in case of cosmics, constrain the momentum
207 if (!mFieldON) {
208 trCosm.setQ2Pt(-o2::track::kMostProbablePt);
209 }
210 int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosm, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2, false, false); // inward refit, reset
211 if (retVal < 0) { // refit failed
212 LOG(debug) << "Inward refit of btm TPC track failed.";
213 continue;
214 }
215 nclTot += retVal;
216 LOG(debug) << "chi2 after btm TPC refit with " << retVal << " clusters : " << chi2 << " orig.chi2 was " << tpcTrOrig.getChi2();
217 } else { // just collect NClusters and chi2
218 // 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
219 if (!mFieldON) {
220 trCosm.setQ2Pt(-trCosm.getQ2Pt());
221 }
222 auto gidxListBtm = data.getSingleDetectorRefs(mSeeds[poolEntryID[btm]].origID);
223 if (gidxListBtm[GTrackID::TPC].isIndexSet()) {
224 const auto& tpcTrOrig = data.getTPCTrack(gidxListBtm[GTrackID::TPC]);
225 nclTot += tpcTrOrig.getNClusters();
226 chi2 += tpcTrOrig.getChi2();
227 }
228 if (gidxListBtm[GTrackID::ITS].isIndexSet()) {
229 const auto& itsTrOrig = data.getITSTrack(gidxListBtm[GTrackID::ITS]);
230 nclTot += itsTrOrig.getNClusters();
231 chi2 += itsTrOrig.getChi2();
232 }
233 }
234 trCosm.invert();
235 if (!trCosm.rotate(mSeeds[poolEntryID[top]].getAlpha()) ||
236 !o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosm, mSeeds[poolEntryID[top]].getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) {
237 LOG(debug) << "Rotation/propagation of btm-track to top-track frame failed.";
238 continue;
239 }
240 // save bottom parameter at merging point
241 auto trCosmBtm = trCosm;
242 int nclBtm = nclTot;
243
244 // Continue with top leg outward refit
245 auto gidxListTop = data.getSingleDetectorRefs(mSeeds[poolEntryID[top]].origID);
246
247 // is there ITS sub-track?
248 if (gidxListTop[GTrackID::ITS].isIndexSet()) {
249 auto nclfit = refitITSTrack(trCosm, gidxListTop[GTrackID::ITS], chi2, false);
250 if (nclfit < 0) {
251 continue;
252 }
253 LOG(debug) << "chi2 after top ITS refit with " << nclfit << " clusters : " << chi2 << " orig.chi2 was " << data.getITSTrack(gidxListTop[GTrackID::ITS]).getChi2();
254 nclTot += nclfit;
255 } // ITS refit
256 //
257 if (gidxListTop[GTrackID::TPC].isIndexSet()) { // outward refit in TPC
258 // go to TPC boundary, if needed
259 if (trCosm.getX() * trCosm.getX() + trCosm.getY() * trCosm.getY() <= o2::constants::geom::XTPCInnerRef * o2::constants::geom::XTPCInnerRef) {
260 float xtogo = 0;
261 if (!trCosm.getXatLabR(o2::constants::geom::XTPCInnerRef, xtogo, mBz, o2::track::DirOutward) ||
262 !o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosm, xtogo, mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) {
263 LOG(debug) << "Propagation to inner TPC boundary X=" << xtogo << " failed";
264 continue;
265 }
266 }
267 const auto& tpcTrOrig = data.getTPCTrack(gidxListTop[GTrackID::TPC]);
268 int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosm, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2, true, false); // outward refit, no reset
269 if (retVal < 0) { // refit failed
270 LOG(debug) << "Outward refit of top TPC track failed.";
271 continue;
272 } // outward refit in TPC
273 LOG(debug) << "chi2 after top TPC refit with " << retVal << " clusters : " << chi2 << " orig.chi2 was " << tpcTrOrig.getChi2();
274 nclTot += retVal;
275 }
276
277 // inward refit of top leg for evaluation in DCA
278 float chi2Dummy = 0;
279 auto trCosmTop = outerLegs[top];
280 if (gidxListTop[GTrackID::TPC].isIndexSet()) { // inward refit in TPC
281 const auto& tpcTrOrig = data.getTPCTrack(gidxListTop[GTrackID::TPC]);
282 int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosmTop, tpcTrOrig.getClusterRef(), t0 * tpcTBinMUSInv, &chi2Dummy, false, true); // inward refit, reset
283 if (retVal < 0) { // refit failed
284 LOG(debug) << "Outward refit of top TPC track failed.";
285 continue;
286 } // inward refit in TPC
287 }
288 // is there ITS sub-track ?
289 if (gidxListTop[GTrackID::ITS].isIndexSet()) {
290 auto nclfit = refitITSTrack(trCosmTop, gidxListTop[GTrackID::ITS], chi2Dummy, true);
291 if (nclfit < 0) {
292 continue;
293 }
294 nclTot += nclfit;
295 } // ITS refit
296 // propagate to bottom param
297 if (!trCosmTop.rotate(trCosmBtm.getAlpha()) ||
298 !o2::base::Propagator::Instance()->PropagateToXBxByBz(trCosmTop, trCosmBtm.getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) {
299 LOG(debug) << "Rotation/propagation of top-track to bottom-track frame failed.";
300 continue;
301 }
302 // calculate weighted average of 2 legs and chi2
303 o2::track::TrackParCov::MatrixDSym5 cov5;
304 float chi2Match = trCosmBtm.getPredictedChi2(trCosmTop, cov5);
305 if (!trCosmBtm.update(trCosmTop, cov5)) {
306 LOG(debug) << "Top/Bottom update failed";
307 continue;
308 }
309 // create final track
310 mCosmicTracks.emplace_back(mSeeds[poolEntryID[btm]].origID, mSeeds[poolEntryID[top]].origID, trCosmBtm, trCosmTop, chi2, chi2Match, nclTot, t0, dt);
311 if (mUseMC) {
312 o2::MCCompLabel lbl[2] = {data.getTrackMCLabel(mSeeds[poolEntryID[btm]].origID), data.getTrackMCLabel(mSeeds[poolEntryID[top]].origID)};
313 auto& tlb = mCosmicTracksLbl.emplace_back((nclBtm > nclTot - nclBtm ? lbl[0] : lbl[1]));
314 tlb.setFakeFlag(lbl[0] != lbl[1]);
315 }
316 }
317 LOG(info) << "Validated " << mCosmicTracks.size() << " top-bottom tracks in TF# " << mTFCount;
318}
319
320//________________________________________________________
321void MatchCosmics::selectWinners()
322{
323 // select mutually best matches
324 int ntr = mSeeds.size(), iter = 0, nValidated = 0;
325 mWinners.reserve(mRecords.size() / 2); // there are 2 records per match candidate
326 do {
327 nValidated = 0;
328 int nRemaining = 0;
329 for (int i = 0; i < ntr; i++) {
330 if (mSeeds[i].matchID < 0 || mRecords[mSeeds[i].matchID].next == Validated) { // either have no match or already validated
331 continue;
332 }
333 nRemaining++;
334 if (validateMatch(i)) {
335 mWinners.push_back(mSeeds[i].matchID);
336 nValidated++;
337 continue;
338 }
339 }
340 LOGF(info, "iter %d Validated %d of %d remaining matches", iter, nValidated, nRemaining);
341 iter++;
342 } while (nValidated);
343}
344
345//________________________________________________________
346bool MatchCosmics::validateMatch(int partner0)
347{
348 // make sure that the best partner of seed_i has also seed_i as a best partner
349 auto& matchRec = mRecords[mSeeds[partner0].matchID];
350 auto partner1 = matchRec.id1;
351 auto& patnerRec = mRecords[mSeeds[partner1].matchID];
352 if (patnerRec.next == Validated) { // partner1 was already validated with other partner0
353 return false;
354 }
355 if (patnerRec.id1 == partner0) { // mutually best
356 // unlink winner partner0 from all other mathes
357 auto next0 = matchRec.next;
358 while (next0 > MinusOne) {
359 auto& nextRec = mRecords[next0];
360 suppressMatch(partner0, nextRec.id1);
361 next0 = nextRec.next;
362 }
363 matchRec.next = Validated;
364
365 // unlink winner partner1 from all other matches
366 auto next1 = patnerRec.next;
367 while (next1 > MinusOne) {
368 auto& nextRec = mRecords[next1];
369 suppressMatch(partner1, nextRec.id1);
370 next1 = nextRec.next;
371 }
372 patnerRec.next = Validated;
373 return true;
374 }
375 return false;
376}
377
378//________________________________________________________
379void MatchCosmics::suppressMatch(int partner0, int partner1)
380{
381 // suppress reference to partner0 from partner1 match record
382 if (mSeeds[partner1].matchID < 0 || mRecords[mSeeds[partner1].matchID].next == Validated) {
383 LOG(warning) << "Attempt to remove null or validated partner match " << mSeeds[partner1].matchID;
384 return;
385 }
386 int topID = MinusOne, next = mSeeds[partner1].matchID;
387 while (next > MinusOne) {
388 auto& matchRec = mRecords[next];
389 if (matchRec.id1 == partner0) {
390 if (topID < 0) { // best match
391 mSeeds[partner1].matchID = matchRec.next; // exclude best match link
392 } else { // not the 1st link in the chain
393 mRecords[topID].next = matchRec.next;
394 }
395 return;
396 }
397 topID = next;
398 next = matchRec.next;
399 }
400}
401
402//________________________________________________________
403MatchCosmics::RejFlag MatchCosmics::checkPair(int i, int j)
404{
405 // if validated with given chi2, register match
406 RejFlag rej = RejOther;
407 auto& seed0 = mSeeds[i];
408 auto& seed1 = mSeeds[j];
409 if (seed0.matchID == Reject) {
410 return rej;
411 }
412 if (seed1.matchID == Reject) {
413 return rej;
414 }
415
416 LOG(debug) << "Seed " << i << " [" << seed0.tBracket.getMin() << " : " << seed0.tBracket.getMax() << "] | "
417 << "Seed " << j << " [" << seed1.tBracket.getMin() << " : " << seed1.tBracket.getMax() << "] | ";
418 LOG(debug) << seed0.origID << " | " << seed0.o2::track::TrackPar::asString();
419 LOG(debug) << seed1.origID << " | " << seed1.o2::track::TrackPar::asString();
420
421 if (seed1.tBracket > seed0.tBracket) {
422 return (rej = RejTime); // since the brackets are sorted in tmin, all following tbj will also exceed tbi
423 }
424 float chi2 = 1.e9f;
425
426 // check
427 // 1) crude check on tgl and q/pt (if B!=0). Note: back-to-back tracks will have mutually params (see TrackPar::invertParam)
428 while (1) {
429 auto dTgl = seed0.getTgl() + seed1.getTgl();
430 if (dTgl * dTgl > (mMatchParams->systSigma2[o2::track::kTgl] + seed0.getSigmaTgl2() + seed1.getSigmaTgl2()) * mMatchParams->crudeNSigma2Cut[o2::track::kTgl]) {
431 rej = RejTgl;
432 break;
433 }
434 if (mFieldON) {
435 auto dQ2Pt = seed0.getQ2Pt() + seed1.getQ2Pt();
436 if (dQ2Pt * dQ2Pt > (mMatchParams->systSigma2[o2::track::kQ2Pt] + seed0.getSigma1Pt2() + seed1.getSigma1Pt2()) * mMatchParams->crudeNSigma2Cut[o2::track::kQ2Pt]) {
437 rej = RejQ2Pt;
438 break;
439 }
440 }
441 o2::track::TrackParCov seed1Inv = seed1;
442 seed1Inv.invert();
443 for (int i = 0; i < o2::track::kNParams; i++) { // add systematic error
444 seed1Inv.updateCov(mMatchParams->systSigma2[i], o2::track::DiagMap[i]);
445 }
446
447 if (!seed1Inv.rotate(seed0.getAlpha()) ||
448 !o2::base::Propagator::Instance()->PropagateToXBxByBz(seed1Inv, seed0.getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) {
449 rej = RejProp;
450 break;
451 }
452 auto dSnp = seed0.getSnp() - seed1Inv.getSnp();
453 if (dSnp * dSnp > (seed0.getSigmaSnp2() + seed1Inv.getSigmaSnp2()) * mMatchParams->crudeNSigma2Cut[o2::track::kSnp]) {
454 rej = RejSnp;
455 break;
456 }
457 auto dY = seed0.getY() - seed1Inv.getY();
458 if (dY * dY > (seed0.getSigmaY2() + seed1Inv.getSigmaY2()) * mMatchParams->crudeNSigma2Cut[o2::track::kY]) {
459 rej = RejY;
460 break;
461 }
462 bool ignoreZ = seed0.origID.getSource() == o2d::GlobalTrackID::TPC || seed1.origID.getSource() == o2d::GlobalTrackID::TPC;
463 // RSTODO this is simplification: one should constraint the TPC-only track Z by the time of other candidate (at least their difference of both tracks are TPC only).
464 // If the shift is large, eventually the tracks need to be refitted.
465 if (!ignoreZ) { // cut on Z makes no sense for TPC only tracks
466 auto dZ = seed0.getZ() - seed1Inv.getZ();
467 if (dZ * dZ > (seed0.getSigmaZ2() + seed1Inv.getSigmaZ2()) * mMatchParams->crudeNSigma2Cut[o2::track::kZ]) {
468 rej = RejZ;
469 break;
470 }
471 } else { // inflate Z error
472 seed1Inv.setCov(250. * 250., o2::track::DiagMap[o2::track::kZ]);
473 seed1Inv.setCov(0., o2::track::CovarMap[o2::track::kZ][o2::track::kY]); // set all correlation terms for Z error to 0
474 seed1Inv.setCov(0., o2::track::CovarMap[o2::track::kZ][o2::track::kSnp]);
475 seed1Inv.setCov(0., o2::track::CovarMap[o2::track::kZ][o2::track::kTgl]);
476 seed1Inv.setCov(0., o2::track::CovarMap[o2::track::kZ][o2::track::kQ2Pt]);
477 }
478 // calculate chi2 (expensive)
479 chi2 = seed0.getPredictedChi2(seed1Inv);
480 if (chi2 > mMatchParams->crudeChi2Cut) {
481 rej = RejChi2;
482 break;
483 }
484 rej = Accept;
485 registerMatch(i, j, chi2);
486 registerMatch(j, i, chi2); // the reverse reference can be also done in a separate loop
487 LOG(debug) << "Chi2 = " << chi2 << " NMatches " << mRecords.size();
488 break;
489 }
490
491#ifdef _ALLOW_DEBUG_TREES_
492 if (mDBGOut && ((rej == Accept && isDebugFlag(MatchTreeAccOnly)) || isDebugFlag(MatchTreeAll))) {
493 auto seed1I = seed1;
494 seed1I.invert();
495 if (seed1I.rotate(seed0.getAlpha()) && o2::base::Propagator::Instance()->PropagateToXBxByBz(seed1I, seed0.getX(), mMatchParams->maxSnp, mMatchParams->maxStep, mMatchParams->matCorr)) {
496 int rejI = int(rej);
497 (*mDBGOut) << "match"
498 << "tf=" << mTFCount << "seed0=" << seed0 << "seed1=" << seed1I << "chi2Match=" << chi2 << "rej=" << rejI << "\n";
499 }
500 }
501#endif
502
503 return rej;
504}
505
506//________________________________________________________
507void MatchCosmics::registerMatch(int i, int j, float chi2)
508{
510 int newRef = mRecords.size();
511 auto& matchRec = mRecords.emplace_back(MatchRecord{i, j, chi2, MinusOne});
512 auto* best = &mSeeds[i].matchID;
513 while (*best > MinusOne) {
514 auto& oldMatchRec = mRecords[*best];
515 if (oldMatchRec.chi2 > chi2) { // insert new match in front of the old one
516 matchRec.next = *best; // new record will refer to the one it is superseding
517 *best = newRef; // the reference on the superseded record should now refer to new one
518 break;
519 }
520 best = &oldMatchRec.next;
521 }
522 if (matchRec.next == MinusOne) { // did not supersed any other record
523 *best = newRef;
524 }
525}
526
527//________________________________________________________
528void MatchCosmics::createSeeds(const o2::globaltracking::RecoContainer& data)
529{
530 // Scan all inputs and create seeding tracks
531
532 mSeeds.clear();
533 std::unordered_map<GTrackID, int> trackEntry;
534
535 auto creator = [this, &trackEntry](auto& _tr, GTrackID _origID, float t0, float terr) {
536 if constexpr (std::is_base_of_v<o2::track::TrackParCov, std::decay_t<decltype(_tr)>>) {
537 if (std::abs(_tr.getQ2Pt()) > this->mQ2PtCutoff) {
538 return true;
539 }
540 if constexpr (isTPCTrack<decltype(_tr)>()) {
541 if (!this->mMatchParams->allowTPCOnly) {
542 return true;
543 }
544 // unconstrained TPC track, with t0 = TrackTPC.getTime0+0.5*(DeltaFwd-DeltaBwd) and terr = 0.5*(DeltaFwd+DeltaBwd) in TimeBins
545 t0 *= this->mTPCTBinMUS;
546 terr *= this->mTPCTBinMUS;
547 } else if (isITSTrack<decltype(_tr)>()) {
548 t0 += 0.5 * this->mITSROFrameLengthMUS; // time 0 is supplied as beginning of ROF in \mus
549 terr *= this->mITSROFrameLengthMUS; // error is supplied a half-ROF duration, convert to \mus
550 } else { // all other tracks are provided with time and its gaussian error in \mus
551 terr *= this->mMatchParams->nSigmaTError;
552 }
553 terr += this->mMatchParams->timeToleranceMUS;
554 trackEntry[_origID] = mSeeds.size();
555 mSeeds.emplace_back(TrackSeed{_tr, {t0 - terr, t0 + terr}, _origID, MinusOne});
556 if constexpr (isTPCTrack<decltype(_tr)>()) {
557 mSeeds.back().setCov(this->mMatchParams->tpcExtraZError2 + _tr.getCov()[o2::track::kSigZ2], o2::track::kSigZ2);
558 }
559 return true;
560 } else {
561 return false;
562 }
563 };
564
565 data.createTracksVariadic(creator);
566
567 if (mUsePVInfo) { // if needed, veto with the primary vertex info
568 auto trackIndex = data.getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks
569 auto vtxRefs = data.getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs
570 int nv = vtxRefs.size() - 1; // The last entry is for unassigned tracks, no need to check them
572 for (int iv = 0; iv < nv; iv++) {
573 const auto& vtref = vtxRefs[iv];
574 int it = vtref.getFirstEntry(), itLim = it + vtref.getEntries();
575 for (; it < itLim; it++) {
576 auto tvid = trackIndex[it];
577 auto entry = trackEntry.find(tvid);
578 if (entry == trackEntry.end()) {
579 continue;
580 }
581 auto& seed = mSeeds[entry->second];
582 if (seed.matchID == Reject || (mMatchParams->discardPVContributors && tvid.isPVContributor())) {
583 seed.matchID = Reject;
584 continue;
585 }
586 if (seed.vtIDMin < 0) {
587 seed.vtIDMin = iv;
588 }
589 seed.vtIDMax = std::max(short(iv), seed.vtIDMax);
590 }
591 }
592 }
593}
594
595//________________________________________________________
596void MatchCosmics::updateTimeDependentParams()
597{
600 mTPCTBinMUS = elParam.ZbinWidth; // TPC bin in microseconds
601 mBz = o2::base::Propagator::Instance()->getNominalBz();
602 mFieldON = std::abs(mBz) > 0.01;
603 mQ2PtCutoff = 1.f / std::max(0.05f, mMatchParams->minSeedPt);
604 if (mFieldON) {
605 mQ2PtCutoff *= 5.00668 / std::abs(mBz);
606 } else {
607 mQ2PtCutoff = 1e9;
608 }
609}
610
611//________________________________________________________
613{
615
616#ifdef _ALLOW_DEBUG_TREES_COSM
617 // debug streamer
618 if (mDBGFlags) {
619 mDBGOut = std::make_unique<o2::utils::TreeStreamRedirector>(mDebugTreeFileName.data(), "recreate");
620 }
621#endif
622}
623
624//________________________________________________________
625std::vector<o2::BaseCluster<float>> MatchCosmics::prepareITSClusters(const o2::globaltracking::RecoContainer& data) const
626{
627 std::vector<o2::BaseCluster<float>> itscl;
628 const auto& clusITS = data.getITSClusters();
629 if (clusITS.size()) {
630 const auto& patterns = data.getITSClustersPatterns();
631 itscl.reserve(clusITS.size());
632 auto pattIt = patterns.begin();
633 o2::its::ioutils::convertCompactClusters(clusITS, pattIt, itscl, mITSDict);
634 }
635 return std::move(itscl);
636}
637
638//______________________________________________
640{
641#ifdef _ALLOW_DEBUG_TREES_COSM
642 mDBGOut.reset();
643#endif
644}
645
646#ifdef _ALLOW_DEBUG_TREES_
647//______________________________________________
648void MatchCosmics::setDebugFlag(UInt_t flag, bool on)
649{
651 if (on) {
652 mDBGFlags |= flag;
653 } else {
654 mDBGFlags &= ~flag;
655 }
656}
657
658//______________________________________________
660{
661 mTPCVDrift = v.refVDrift * v.corrFact;
662 mTPCVDriftCorrFact = v.corrFact;
663 mTPCVDriftRef = v.refVDrift;
664 mTPCDriftTimeOffset = v.getTimeOffset();
665}
666
667//______________________________________________
669{
670 mTPCCorrMaps = maph;
671}
672
673#endif
Definition of the ITSMFT compact cluster.
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
POD correction map.
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
Referenc on track indices contributing to the vertex, with possibility chose tracks from specific sou...
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
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 setTPCCorrMaps(const o2::gpu::TPCFastTransformPOD *maph)
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
GLuint entry
Definition glcorearb.h:5735
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
constexpr double LHCBunchSpacingMUS
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
int const float const TrackSeed< NLayers > & seed
int int int float float float int const float const TrackingFrameInfo *const const float const o2::base::Propagator * propagator
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
float dcaCutChi2[o2::dataformats::GlobalTrackID::NSources]
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"