42#include <unordered_map>
54constexpr int ELossGain = 1;
55constexpr int ELossLoss = -1;
61 updateTimeDependentParams();
64 mCosmicTracks.clear();
65 mCosmicTracksLbl.clear();
69 int ntr = mSeeds.size();
75 for (
int i = 0;
i < ntr;
i++) {
76 auto& trc = mSeeds[
i];
77 if (trc.matchID !=
Reject) {
80 std::array<float, 3> momentum{};
81 trc.getPxPyPzGlo(momentum);
82 const int eLossSign = momentum[1] > 0.f ? ELossLoss : ELossGain;
83 if (!prop->propagateToDCABxByBz(
v, trc, mMatchParams->
maxStep, mMatchParams->
matCorr,
nullptr,
nullptr, eLossSign)) {
100 if (mMatchParams->
dcaCutChi2[trc.origID.getSource()] > 0.f && mUsePVInfo && trc.vtIDMin >= 0 && (std::abs(trc.getY()) < mMatchParams->
fiducialRIP && std::abs(trc.getZ()) < mMatchParams->
fiducialZIP)) {
102 for (
int iv = trc.vtIDMin; iv <= trc.vtIDMax; iv++) {
103 const auto& pv =
data.getPrimaryVertex(iv);
106 if (!trcatPV.propagateToDCA(pv, mBz, &dca)) {
111 const auto& trcTPC =
data.getTPCTrack(trc.origID);
112 float deltaZ = trcTPC.hasBothSidesClusters() ? 0.f : (pv.getTimeStamp().getTimeStamp() - trcTPC.getTime0() * 8 * o2::constants::lhc::LHCBunchSpacingMUS) * mTPCVDrift;
113 dca.setZ(dca.getZ() + (trcTPC.hasASideClustersOnly() ? deltaZ : -deltaZ));
116 if (dca.calcChi2() < mMatchParams->
dcaCutChi2[trc.origID.getSource()]) {
125 std::unique_ptr<o2::gpu::GPUO2InterfaceRefit> tpcRefitter;
126 if (
data.inputsTPCclusters) {
127 tpcRefitter = std::make_unique<o2::gpu::GPUO2InterfaceRefit>(&
data.inputsTPCclusters->clusterIndex, mTPCCorrMaps, mBz,
data.getTPCTracksClusterRefs().data(), 0,
128 data.clusterShMapTPC.data(),
data.occupancyMapTPC.data(),
data.occupancyMapTPC.size(),
nullptr,
131 mTPCRefitter = tpcRefitter.get();
133 mNRefitsCommonTime = 0;
136 mNNearBeamConfirmed = 0;
138 prepareTOFClusters(
data);
142 std::vector<int> sortID(ntr);
143 std::iota(sortID.begin(), sortID.end(), 0);
144 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())); });
145 int lastValid = ntr - 1;
146 for (; lastValid >= 0; lastValid--) {
147 if (mSeeds[sortID[lastValid]].matchID !=
Reject) {
151 ntr = lastValid >= 0 ? lastValid + 1 : 0;
152 LOGP(info,
"Collected {} seeds, validated: {}", mSeeds.size(), ntr);
154 for (
int i = 0;
i < ntr;
i++) {
155 for (
int j =
i + 1;
j < ntr;
j++) {
156 if (checkPair(sortID[
i], sortID[
j]) ==
RejTime) {
162 LOGP(info,
"{} accepted pairs confirmed by a TOF flight pair", mNTOFConfirmed);
164 if (mNSeedsPVContributors) {
165 LOGP(info,
"{} seeds rejected as (part of) a primary-vertex contributor", mNSeedsPVContributors);
167 if (mNSeedsNearBeam) {
168 LOGP(info,
"{} seeds near the beam line used in TOF-confirmed pairs only, {} such pairs confirmed", mNSeedsNearBeam, mNNearBeamConfirmed);
173 if (mNRefitsCommonTime) {
174 LOGP(info,
"{} seeds refitted at the common time of same-side pairs", mNRefitsCommonTime);
176 if (mNTOFFallbacks) {
177 LOGP(info,
"{} TOF-confirmed winners failed the refit at the TOF time and were refitted at their time without TOF", mNTOFFallbacks);
179 mTPCRefitter =
nullptr;
188 LOG(info) <<
"Refitting " << mWinners.size() <<
" winner matches";
190 auto tpcTBinMUSInv = 1. / mTPCTBinMUS;
191 auto* tpcRefitter = mTPCRefitter;
193 const auto& itsClusters = prepareITSClusters(
data);
195 std::vector<int> itsTracksROF;
197 const auto& itsTracksROFRec =
data.getITSTracksROFRecords();
198 itsTracksROF.resize(
data.getITSTracks().size());
199 for (
unsigned irf = 0, cnt = 0; irf < itsTracksROFRec.size(); irf++) {
200 int ntr = itsTracksROFRec[irf].getNEntries();
201 for (
int itr = 0; itr < ntr; itr++) {
202 itsTracksROF[cnt++] = irf;
207 const auto& itsTrOrig =
data.getITSTrack(gidx);
208 int nclRefit = 0, ncl = itsTrOrig.getNumberOfClusters(), rof = itsTracksROF[gidx.getIndex()];
209 const auto& itsTrackClusRefs =
data.getITSTracksClusterRefs();
210 int clEntry = itsTrOrig.getFirstClusterEntry();
213 int from = ncl - 1, to = -1, step = -1;
219 for (
int icl = from; icl != to; icl +=
step) {
220 const auto& clus = itsClusters[itsTrackClusRefs[clEntry + icl]];
221 float alpha = geomITS->getSensorRefAlpha(clus.getSensorID()),
x = clus.getX();
222 if (!trFit.rotate(
alpha) || !propagator->propagateToX(trFit,
x, propagator->getNominalBz(),
this->mMatchParams->maxSnp,
this->mMatchParams->maxStep,
this->mMatchParams->matCorr,
nullptr, eLossSign)) {
225 chi2 += trFit.getPredictedChi2(clus);
226 if (!trFit.update(clus)) {
231 return nclRefit ==
ncl ?
ncl : -1;
235 auto refitWinner = [&](
int winRID,
float t0,
float dt) {
236 const auto&
rec = mRecords[winRID];
237 int poolEntryID[2] = {
rec.id0,
rec.id1};
239 for (
auto& leg : outerLegs) {
240 leg.setPID(o2::track::PID::Muon,
true);
242 auto tOverlap = mSeeds[
rec.id0].tBracket.getOverlap(mSeeds[
rec.id1].tBracket);
243 auto pnt0 = outerLegs[0].getXYZGlo(), pnt1 = outerLegs[1].getXYZGlo();
244 int btm = 0,
top = 1;
246 if (pnt0.Y() > pnt1.Y()) {
250 LOG(
debug) <<
"Winner " <<
count++ <<
" Record " << winRID <<
" Partners:"
251 <<
" B: " << mSeeds[poolEntryID[btm]].origID <<
"/" << mSeeds[poolEntryID[btm]].origID.getSourceName()
252 <<
" U: " << mSeeds[poolEntryID[
top]].origID <<
"/" << mSeeds[poolEntryID[
top]].origID.getSourceName()
253 <<
" | T:" << tOverlap.asString();
261 if (mSeeds[poolEntryID[btm]].origID.getSource() ==
GTrackID::TPC) {
262 const auto& tpcTrOrig =
data.getTPCTrack(mSeeds[poolEntryID[btm]].origID);
263 trCosm = outerLegs[btm];
264 trCosm.resetCovariance();
269 int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosm, tpcTrOrig.getClusterRef(),
t0 * tpcTBinMUSInv, &
chi2,
false,
false, ELossGain);
271 LOG(
debug) <<
"Inward refit of btm TPC track failed.";
275 LOG(
debug) <<
"chi2 after btm TPC refit with " <<
retVal <<
" clusters : " <<
chi2 <<
" orig.chi2 was " << tpcTrOrig.getChi2();
279 trCosm.setQ2Pt(-trCosm.getQ2Pt());
281 auto gidxListBtm =
data.getSingleDetectorRefs(mSeeds[poolEntryID[btm]].origID);
284 nclTot += tpcTrOrig.getNClusters();
285 chi2 += tpcTrOrig.getChi2();
289 nclTot += itsTrOrig.getNClusters();
290 chi2 += itsTrOrig.getChi2();
294 if (!trCosm.rotate(mSeeds[poolEntryID[
top]].getAlpha()) ||
296 LOG(
debug) <<
"Rotation/propagation of btm-track to top-track frame failed.";
300 auto trCosmBtm = trCosm;
304 auto gidxListTop =
data.getSingleDetectorRefs(mSeeds[poolEntryID[
top]].origID);
308 auto nclfit = refitITSTrack(trCosm, gidxListTop[
GTrackID::ITS],
chi2,
false, ELossGain);
312 LOG(
debug) <<
"chi2 after top ITS refit with " << nclfit <<
" clusters : " <<
chi2 <<
" orig.chi2 was " <<
data.getITSTrack(gidxListTop[
GTrackID::ITS]).getChi2();
322 LOG(
debug) <<
"Propagation to inner TPC boundary X=" << xtogo <<
" failed";
327 int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosm, tpcTrOrig.getClusterRef(),
t0 * tpcTBinMUSInv, &
chi2,
true,
false, ELossGain);
329 LOG(
debug) <<
"Outward refit of top TPC track failed.";
332 LOG(
debug) <<
"chi2 after top TPC refit with " <<
retVal <<
" clusters : " <<
chi2 <<
" orig.chi2 was " << tpcTrOrig.getChi2();
338 auto trCosmTop = outerLegs[
top];
341 int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosmTop, tpcTrOrig.getClusterRef(),
t0 * tpcTBinMUSInv, &chi2Dummy,
false,
true, ELossLoss);
343 LOG(
debug) <<
"Inward refit of top TPC track failed.";
349 auto nclfit = refitITSTrack(trCosmTop, gidxListTop[
GTrackID::ITS], chi2Dummy,
true, ELossLoss);
356 if (!trCosmTop.rotate(trCosmBtm.getAlpha()) ||
358 LOG(
debug) <<
"Rotation/propagation of top-track to bottom-track frame failed.";
362 o2::track::TrackParCov::MatrixDSym5 cov5;
363 float chi2Match = trCosmBtm.getPredictedChi2(trCosmTop, cov5);
365 LOG(
debug) <<
"Top/Bottom refitted legs disagree, chi2Match " << chi2Match;
368 if (!trCosmBtm.update(trCosmTop, cov5)) {
369 LOG(
debug) <<
"Top/Bottom update failed";
373 if (mSeeds[
rec.id0].tpcSide * mSeeds[
rec.id1].tpcSide < 0 && std::abs(trCosmBtm.getQ2Pt()) > mQ2PtCutoffOppositeSides) {
374 LOG(
debug) <<
"Cosmic with legs on opposite TPC sides below minPtOppositeSides";
378 auto& cosmic = mCosmicTracks.emplace_back(mSeeds[poolEntryID[btm]].origID, mSeeds[poolEntryID[
top]].origID, trCosmBtm, trCosmTop,
chi2, chi2Match, nclTot,
t0, dt);
380 if (mSeeds[poolEntryID[btm]].nearBeam) {
381 flags |= o2d::TrackCosmics::NearBeamBottom;
383 if (mSeeds[poolEntryID[
top]].nearBeam) {
384 flags |= o2d::TrackCosmics::NearBeamTop;
386 cosmic.setFlags(
flags);
388 o2::MCCompLabel lbl[2] = {
data.getTrackMCLabel(mSeeds[poolEntryID[btm]].origID),
data.getTrackMCLabel(mSeeds[poolEntryID[
top]].origID)};
389 auto& tlb = mCosmicTracksLbl.emplace_back((nclBtm > nclTot - nclBtm ? lbl[0] : lbl[1]));
390 tlb.setFakeFlag(lbl[0] != lbl[1]);
394 for (
auto winRID : mWinners) {
395 const auto&
rec = mRecords[winRID];
398 auto refitAt = [&](
float tCommon,
float tCommonErr) {
399 if (tCommonErr >= 0.f) {
400 return refitWinner(winRID, tCommon, tCommonErr);
402 auto tOverlap = mSeeds[
rec.id0].tBracket.getOverlap(mSeeds[
rec.id1].tBracket);
403 return refitWinner(winRID, tOverlap.mean(), tOverlap.delta() * 0.5f);
406 if (!refitAt(
rec.tCommon,
rec.tCommonErr) &&
rec.tofScore >= 0.f && refitAt(
rec.tCommonNoTOF,
rec.tCommonErrNoTOF)) {
410 LOG(info) <<
"Validated " << mCosmicTracks.size() <<
" top-bottom tracks in TF# " << mTFCount;
414void MatchCosmics::selectWinners()
417 int ntr = mSeeds.size(), iter = 0, nValidated = 0;
418 mWinners.reserve(mRecords.size() / 2);
422 for (
int i = 0;
i < ntr;
i++) {
423 if (mSeeds[
i].matchID < 0 || mRecords[mSeeds[
i].matchID].next ==
Validated) {
427 if (validateMatch(
i)) {
428 mWinners.push_back(mSeeds[
i].matchID);
433 LOGF(info,
"iter %d Validated %d of %d remaining matches", iter, nValidated, nRemaining);
435 }
while (nValidated);
439bool MatchCosmics::validateMatch(
int partner0)
442 auto& matchRec = mRecords[mSeeds[partner0].matchID];
443 auto partner1 = matchRec.id1;
444 auto& patnerRec = mRecords[mSeeds[partner1].matchID];
448 if (patnerRec.id1 == partner0) {
450 auto next0 = matchRec.next;
452 auto& nextRec = mRecords[next0];
453 suppressMatch(partner0, nextRec.id1);
454 next0 = nextRec.next;
459 auto next1 = patnerRec.next;
461 auto& nextRec = mRecords[next1];
462 suppressMatch(partner1, nextRec.id1);
463 next1 = nextRec.next;
472void MatchCosmics::suppressMatch(
int partner0,
int partner1)
475 if (mSeeds[partner1].matchID < 0 || mRecords[mSeeds[partner1].matchID].next ==
Validated) {
476 LOG(warning) <<
"Attempt to remove null or validated partner match " << mSeeds[partner1].matchID;
479 int topID =
MinusOne, next = mSeeds[partner1].matchID;
481 auto& matchRec = mRecords[next];
482 if (matchRec.id1 == partner0) {
484 mSeeds[partner1].matchID = matchRec.next;
486 mRecords[topID].next = matchRec.next;
491 next = matchRec.next;
500 auto& seed0 = mSeeds[
i];
501 auto& seed1 = mSeeds[
j];
502 if (seed0.matchID ==
Reject) {
505 if (seed1.matchID ==
Reject) {
509 LOG(
debug) <<
"Seed " <<
i <<
" [" << seed0.tBracket.getMin() <<
" : " << seed0.tBracket.getMax() <<
"] | "
510 <<
"Seed " <<
j <<
" [" << seed1.tBracket.getMin() <<
" : " << seed1.tBracket.getMax() <<
"] | ";
511 LOG(
debug) << seed0.origID <<
" | " << seed0.o2::track::TrackPar::asString();
512 LOG(
debug) << seed1.origID <<
" | " << seed1.o2::track::TrackPar::asString();
514 if (seed1.tBracket > seed0.tBracket) {
519 float tCommonErr = -1.f;
520 float tofScore = -1.f;
521 TrackSeed seed0Common;
522 TrackSeed seed1Common;
523 bool commonTime =
false;
530 if (seed0.tpcSide * seed1.tpcSide < 0 && std::max(std::abs(seed0.getQ2Pt()), std::abs(seed1.getQ2Pt())) > mQ2PtCutoffOppositeSides) {
534 auto dTgl = seed0.getTgl() + seed1.getTgl();
540 auto dQ2Pt = seed0.getQ2Pt() + seed1.getQ2Pt();
551 std::array<float, 3> pca{};
552 seed0.getXYZGlo(pca);
553 const float phi = seed0.getAlpha() + std::asin(seed0.getSnp());
554 const float dir[2] = {std::cos(phi), std::sin(phi)};
557 for (
int k = 0; k < 2; k++) {
558 proj0 += (seed0.xyzRef[k] - pca[k]) * dir[k];
559 proj1 += (seed1.xyzRef[k] - pca[k]) * dir[k];
561 constexpr float MinDist = 20.f;
562 if (std::abs(proj0) > MinDist && std::abs(proj1) > MinDist && proj0 * proj1 > 0.f) {
571 const float tPair = seed0.tBracket.getOverlap(seed1.tBracket).mean();
572 commonTime = refitSeedAtTime(seed0, tPair, seed0Common) && refitSeedAtTime(seed1, tPair, seed1Common);
574 const TrackSeed& leg0 = commonTime ? seed0Common : seed0;
575 const TrackSeed& leg1 = commonTime ? seed1Common : seed1;
578 for (
int i = 0;
i < o2::track::kNParams;
i++) {
579 seed1Inv.updateCov(mMatchParams->
systSigma2[
i], o2::track::DiagMap[
i]);
582 if (!seed1Inv.rotate(leg0.getAlpha()) ||
587 auto dSnp = leg0.getSnp() - seed1Inv.getSnp();
592 auto dY = leg0.getY() - seed1Inv.getY();
597 bool ignoreZ = leg0.origID.getSource() == o2d::GlobalTrackID::TPC || leg1.origID.getSource() == o2d::GlobalTrackID::TPC;
602 const int side0 = leg0.tpcSide;
603 const int side1 = leg1.tpcSide;
605 if (side0 == 0 || side1 == 0 || side0 == side1) {
606 float dZ = leg0.getZ() - seed1Inv.getZ();
607 float dZTimeTol = 0.f;
608 if (side0 != 0 && side1 != 0) {
609 dZ -= side0 * mTPCVDrift * (leg0.tRef - leg1.tRef);
610 }
else if (side1 != 0) {
611 dZ -= side1 * mTPCVDrift * (leg0.tRef - leg1.tRef);
612 if (leg0.origID.getSource() != o2d::GlobalTrackID::TPC) {
613 dZTimeTol = 0.5f * mTPCVDrift * leg0.tBracket.delta();
615 }
else if (side0 != 0) {
616 dZ += side0 * mTPCVDrift * (leg1.tRef - leg0.tRef);
617 if (leg1.origID.getSource() != o2d::GlobalTrackID::TPC) {
618 dZTimeTol = 0.5f * mTPCVDrift * leg1.tBracket.delta();
621 const float dZTol = std::sqrt(sigZ2) + dZTimeTol;
622 if (dZ * dZ > dZTol * dZTol) {
627 const float t = 0.5f * (side0 * (seed1Inv.getZ() - leg0.getZ()) / mTPCVDrift + leg0.tRef + leg1.tRef);
628 const float tTol = std::sqrt(sigZ2) / (2.f * mTPCVDrift);
629 if (t < std::max(leg0.tBracket.getMin(), leg1.tBracket.getMin()) - tTol || t > std::min(leg0.tBracket.getMax(), leg1.tBracket.getMax()) + tTol) {
634 tCommonErr = std::sqrt(leg0.getSigmaZ2() + seed1Inv.getSigmaZ2()) / (2.f * mTPCVDrift);
639 auto dZ = leg0.getZ() - seed1Inv.getZ();
645 seed1Inv.setCov(250. * 250., o2::track::DiagMap[
o2::track::kZ]);
652 chi2 = leg0.getPredictedChi2(seed1Inv);
658 const float tCommonNoTOF = tCommon;
659 const float tCommonErrNoTOF = tCommonErr;
661 const bool timeFixed = tCommonErr >= 0.f;
662 const auto overlap = seed0.tBracket.getOverlap(seed1.tBracket);
663 const float tMin = timeFixed ? tCommon - mMatchParams->
nSigmaTError * tCommonErr : overlap.getMin();
664 const float tMax = timeFixed ? tCommon + mMatchParams->
nSigmaTError * tCommonErr : overlap.getMax();
665 float tofTimeMUS = 0.f;
666 tofScore = findTOFFlightPair(
i,
j, tMin, tMax, tofTimeMUS);
667 if (tofScore >= 0.f) {
668 tCommon = tofTimeMUS;
673 if (seed0.nearBeam || seed1.nearBeam) {
674 if (tofScore < 0.f) {
678 mNNearBeamConfirmed++;
680 registerMatch(
i,
j,
chi2, tCommon, tCommonErr, tofScore, tCommonNoTOF, tCommonErrNoTOF);
681 registerMatch(
j,
i,
chi2, tCommon, tCommonErr, tofScore, tCommonNoTOF, tCommonErrNoTOF);
682 LOG(
debug) <<
"Chi2 = " <<
chi2 <<
" NMatches " << mRecords.size();
686#ifdef _ALLOW_DEBUG_TREES_
688 const TrackSeed& dbgLeg0 = commonTime ? seed0Common : seed0;
689 auto seed1I = commonTime ? seed1Common : seed1;
693 int commonTimeI = commonTime;
694 (*mDBGOut) <<
"match"
695 <<
"tf=" << mTFCount <<
"seed0=" << dbgLeg0 <<
"seed1=" << seed1I <<
"chi2Match=" <<
chi2 <<
"rej=" << rejI <<
"commonTime=" << commonTimeI
696 <<
"side0=" <<
int(seed0.tpcSide) <<
"side1=" <<
int(seed1.tpcSide) <<
"tCommon=" << tCommon <<
"tCommonErr=" << tCommonErr <<
"tofScore=" << tofScore <<
"\n";
705bool MatchCosmics::refitSeedAtTime(
const TrackSeed& seed,
float timeMUS, TrackSeed& out)
710 if (!mTPCRefitter || !mRecoData) {
715 trk.setPID(o2::track::PID::Muon,
true);
716 trk.resetCovariance();
718 std::array<float, 3> momentum{};
719 trk.getPxPyPzGlo(momentum);
720 const int eLossSign = momentum[1] > 0.f ? ELossLoss : ELossGain;
721 if (mTPCRefitter->
RefitTrackAsTrackParCov(trk, tpcTrack.getClusterRef(), timeMUS / mTPCTBinMUS,
nullptr,
false,
true, eLossSign) < 0) {
732 mNRefitsCommonTime++;
741 mTOFClusterOrder.resize(
clusters.size());
742 std::iota(mTOFClusterOrder.begin(), mTOFClusterOrder.end(), 0);
743 std::sort(mTOFClusterOrder.begin(), mTOFClusterOrder.end(), [&
clusters](
int a,
int b) { return clusters[a].getTime() < clusters[b].getTime(); });
744 mTOFClusterTimeMUS.resize(
clusters.size());
745 for (
size_t k = 0; k <
clusters.size(); k++) {
746 mTOFClusterTimeMUS[k] =
clusters[mTOFClusterOrder[k]].getTime() * 1e-6;
748 mSeedTOFCandidates.clear();
749 mSeedTOFCandidates.resize(mSeeds.size());
750 mSeedTOFDone.assign(mSeeds.size(),
false);
754const std::vector<MatchCosmics::TOFCandidate>& MatchCosmics::getTOFCandidates(
int iseed)
758 auto& candidates = mSeedTOFCandidates[iseed];
759 if (mSeedTOFDone[iseed]) {
762 mSeedTOFDone[iseed] =
true;
763 const auto&
seed = mSeeds[iseed];
767 constexpr float MaxFlightMUS = 0.1f;
768 constexpr float RadiusTOF = 380.f;
771 std::array<float, 3> xyz{};
772 std::array<float, 3> dir{};
773 parOut.getXYZGlo(xyz);
774 parOut.getPxPyPzGlo(dir);
776 const float a = dir[0] * dir[0] + dir[1] * dir[1];
777 const float b = xyz[0] * dir[0] + xyz[1] * dir[1];
778 const float c = xyz[0] * xyz[0] + xyz[1] * xyz[1] - RadiusTOF * RadiusTOF;
779 const float disc =
b *
b -
a *
c;
780 if (
a <= 0.f || disc < 0.f) {
783 const float step = (-
b + std::sqrt(disc)) /
a;
785 constexpr int NSectors = 18;
787 bool okSector[3] = {
false,
false,
false};
788 for (
int k = 0; k < 3; k++) {
789 parSector[k] = parOut;
792 const float road = mMatchParams->
tofRoad;
794 const float dzDrift0 =
seed.tpcSide * mTPCVDrift * (
seed.tBracket.getMin() -
seed.tRef);
795 const float dzDrift1 =
seed.tpcSide * mTPCVDrift * (
seed.tBracket.getMax() -
seed.tRef);
796 const float dzMin = std::min(dzDrift0, dzDrift1) - road;
797 const float dzMax = std::max(dzDrift0, dzDrift1) + road;
799 auto first = std::lower_bound(mTOFClusterTimeMUS.begin(), mTOFClusterTimeMUS.end(),
seed.tBracket.getMin() - MaxFlightMUS);
800 for (
auto it =
first; it != mTOFClusterTimeMUS.end() && *it <=
seed.tBracket.getMax() + MaxFlightMUS; ++it) {
801 const int index = mTOFClusterOrder[it - mTOFClusterTimeMUS.begin()];
803 const int k = (cl.getSector() - sectorCentre + NSectors + 1) % NSectors;
804 if (k > 2 || !okSector[k]) {
809 if (!parSector[k].getYZAt(cl.getX(), mBz,
y,
z)) {
812 const float dy = cl.getY() -
y;
813 const float dz = cl.getZ() -
z;
814 if (std::abs(dy) > road || dz < dzMin || dz > dzMax) {
818 const float sinAlpha = std::sin(
alpha);
819 const float cosAlpha = std::cos(
alpha);
820 candidates.push_back(TOFCandidate{
index, cl.getTime() * 1e-3, dy, dz, cl.getX() * cosAlpha - cl.getY() * sinAlpha, cl.getX() * sinAlpha + cl.getY() * cosAlpha, cl.getZ()});
826float MatchCosmics::findTOFFlightPair(
int i,
int j,
float tMinMUS,
float tMaxMUS,
float& tofTimeMUS)
831 constexpr float MaxFlightMUS = 0.1f;
832 constexpr float CmPerNS = 29.9792458f;
833 const auto& candidates0 = getTOFCandidates(
i);
834 const auto& candidates1 = getTOFCandidates(
j);
835 if (candidates0.empty() || candidates1.empty()) {
838 const auto& seed0 = mSeeds[
i];
839 const auto& seed1 = mSeeds[
j];
840 const float curvature = 0.5f * (std::abs(mRecoData->
getTPCTrack(seed0.origID).getCurvature(mBz)) + std::abs(mRecoData->
getTPCTrack(seed1.origID).getCurvature(mBz)));
841 const float road = mMatchParams->
tofRoad;
843 float bestScore = -1.f;
844 for (
const auto& c0 : candidates0) {
845 for (
const auto& c1 : candidates1) {
846 if (c0.index == c1.index) {
849 const auto&
top = c0.gy > c1.gy ? c0 : c1;
850 const auto&
bottom = c0.gy > c1.gy ? c1 : c0;
853 const float halfAngleSin = 0.5f * curvature * chordXY;
854 const float arcXY = halfAngleSin > 1e-4f && halfAngleSin < 1.f ? 2.f * std::asin(halfAngleSin) / curvature : chordXY;
856 const float flightDev = float(
top.timeNS -
bottom.timeNS) +
length / CmPerNS;
857 if (std::abs(flightDev) > tolerance) {
860 const float pairTimeMUS = float(0.5e-3 * (c0.timeNS + c1.timeNS));
861 if (pairTimeMUS < tMinMUS - MaxFlightMUS || pairTimeMUS > tMaxMUS + MaxFlightMUS) {
864 const float dz0 = c0.dz - seed0.tpcSide * mTPCVDrift * (pairTimeMUS - seed0.tRef);
865 const float dz1 = c1.dz - seed1.tpcSide * mTPCVDrift * (pairTimeMUS - seed1.tRef);
866 if (std::abs(dz0) > road || std::abs(dz1) > road) {
869 const float score = (c0.dy * c0.dy + c1.dy * c1.dy + dz0 * dz0 + dz1 * dz1) / (road * road) + flightDev * flightDev / (tolerance * tolerance);
870 if (bestScore < 0.f || score < bestScore) {
872 tofTimeMUS = pairTimeMUS;
880void MatchCosmics::registerMatch(
int i,
int j,
float chi2,
float tCommon,
float tCommonErr,
float tofScore,
float tCommonNoTOF,
float tCommonErrNoTOF)
884 int newRef = mRecords.size();
885 auto& matchRec = mRecords.emplace_back(
MatchRecord{
i,
j,
chi2,
MinusOne, tCommon, tCommonErr, tofScore, tCommonNoTOF, tCommonErrNoTOF});
886 const bool confirmed = tofScore >= 0.f;
887 auto*
best = &mSeeds[
i].matchID;
889 auto& oldMatchRec = mRecords[*
best];
890 const bool oldConfirmed = oldMatchRec.tofScore >= 0.f;
891 if ((confirmed && !oldConfirmed) || (confirmed == oldConfirmed && oldMatchRec.chi2 >
chi2)) {
892 matchRec.next = *
best;
896 best = &oldMatchRec.next;
909 std::unordered_map<GTrackID, int> trackEntry;
911 auto creator = [
this, &trackEntry](
auto& _tr,
GTrackID _origID,
float t0,
float terr) {
913 if (std::abs(_tr.getQ2Pt()) > this->mQ2PtCutoff) {
916 if constexpr (isTPCTrack<decltype(_tr)>()) {
921 t0 *= this->mTPCTBinMUS;
922 terr *= this->mTPCTBinMUS;
924 t0 += 0.5 * this->mITSROFrameLengthMUS;
925 terr *= this->mITSROFrameLengthMUS;
930 trackEntry[_origID] = mSeeds.size();
931 auto&
seed = mSeeds.emplace_back(TrackSeed{_tr, {
t0 - terr,
t0 + terr}, _origID,
MinusOne});
932 seed.setPID(o2::track::PID::Muon,
true);
935 if constexpr (isTPCTrack<decltype(_tr)>()) {
937 seed.tRef = _tr.getTime0() * this->mTPCTBinMUS;
938 seed.tpcSide = _tr.hasASideClustersOnly() ? 1 : (_tr.hasCSideClustersOnly() ? -1 : 0);
946 data.createTracksVariadic(creator, mSeedSources);
948 mNSeedsPVContributors = 0;
950 auto trackIndex =
data.getPrimaryVertexMatchedTracks();
951 auto vtxRefs =
data.getPrimaryVertexMatchedTrackRefs();
952 int nv = vtxRefs.size() - 1;
954 for (
int iv = 0; iv < nv; iv++) {
955 const auto& vtref = vtxRefs[iv];
956 int it = vtref.getFirstEntry(), itLim = it + vtref.getEntries();
957 for (; it < itLim; it++) {
958 auto tvid = trackIndex[it];
959 auto entry = trackEntry.find(tvid);
960 if (
entry == trackEntry.end()) {
962 if (mMatchParams->
discardPVContributors && tvid.isPVContributor() && mPVVetoSources[tvid.getSource()] &&
data.isTrackSourceLoaded(tvid.getSource())) {
963 const auto refs =
data.getSingleDetectorRefs(tvid);
965 if (!mSeedSources[
src] || !refs[
src].isIndexSet()) {
968 auto partEntry = trackEntry.find(refs[
src]);
969 if (partEntry != trackEntry.end() && mSeeds[partEntry->second].matchID !=
Reject) {
970 mSeeds[partEntry->second].matchID =
Reject;
971 mNSeedsPVContributors++;
980 mNSeedsPVContributors++;
985 if (
seed.vtIDMin < 0) {
988 seed.vtIDMax = std::max(
short(iv),
seed.vtIDMax);
995void MatchCosmics::updateTimeDependentParams()
999 mTPCTBinMUS = elParam.ZbinWidth;
1001 mFieldON = std::abs(mBz) > 0.01;
1002 mQ2PtCutoff = 1.f / std::max(0.05f, mMatchParams->
minSeedPt);
1005 mQ2PtCutoff *= 5.00668 / std::abs(mBz);
1006 mQ2PtCutoffOppositeSides *= 5.00668 / std::abs(mBz);
1009 mQ2PtCutoffOppositeSides = 1e9;
1018#ifdef _ALLOW_DEBUG_TREES_COSM
1021 mDBGOut = std::make_unique<o2::utils::TreeStreamRedirector>(mDebugTreeFileName.data(),
"recreate");
1032 for (
int lr = 0; lr < nLr; lr++) {
1034 const auto& clusITS =
data.getITSClusters(lr);
1035 if (clusITS.size()) {
1036 auto pattIt =
data.getITSClustersPatterns(lr).begin();
1048#ifdef _ALLOW_DEBUG_TREES_COSM
1053#ifdef _ALLOW_DEBUG_TREES_
1068 mTPCVDrift =
v.refVDrift *
v.corrFact;
1069 mTPCVDriftCorrFact =
v.corrFact;
1070 mTPCVDriftRef =
v.refVDrift;
1071 mTPCDriftTimeOffset =
v.getTimeOffset();
1077 mTPCCorrMaps = maph;
General auxilliary methods.
Definition of the ITSMFT compact cluster.
Some ALICE geometry constants of common interest.
Accessor for TrackParCov derived objects from multiple containers.
Definition of the GeometryTGeo class.
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.
Wrapper container for different reconstructed object types.
constexpr auto isITSTrack()
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)
static const ParameterElectronics & Instance()
@ 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
@ RejNoTOF
a leg kept by minSeedDCAxyTOF only, and no TOF flight pair
int32_t RefitTrackAsTrackParCov(o2::tpc::TrackTPC &trk, bool outward=false, bool resetCov=false)
static GeometryTGeo * Instance()
void beginLayer(int lr)
to be called once all the layers were filled
void init(int nLr)
< prepare for filling nLr layer slots, discarding the previous content
GLfloat GLfloat GLfloat alpha
GLdouble GLdouble GLdouble GLdouble top
GLboolean GLboolean GLboolean b
GLuint GLsizei GLsizei * length
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
GLboolean GLboolean GLboolean GLboolean a
GLdouble GLdouble GLdouble z
uint8_t int statusCode int
uint8_t itsSharedClusterMap uint8_t
constexpr float XTPCInnerRef
reference radius at which TPC provides the tracks
constexpr int MaxITSLayers
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
int const float const TrackSeed< NLayers > & seed
const bool const bool const int FollowDirection BestTrial TrackITSInternal< NLayers > & best
int angle2Sector(float phi)
float sector2Angle(int sect)
float crudeNSigma2Cut[o2::track::kNParams]
o2::base::Propagator::MatCorrType matCorr
bool refitSameSideAtCommonTime
float dcaCutChi2[o2::dataformats::GlobalTrackID::NSources]
float minSeedDCAxyNSigmaTOF
bool discardPVContributors
float systSigma2[o2::track::kNParams]
const o2::tpc::TrackTPC & getTPCTrack(GTrackID id) const
auto getTOFClusters() const
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Cluster > clusters