41#include <unordered_map>
51 updateTimeDependentParams();
54 mCosmicTracks.clear();
55 mCosmicTracksLbl.clear();
58 int ntr = mSeeds.size();
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)) {
69 if (mMatchParams->
dcaCutChi2[trc.origID.getSource()] > 0.f && mUsePVInfo && (std::abs(trc.getY()) < mMatchParams->
fiducialRIP && std::abs(trc.getZ()) < mMatchParams->
fiducialZIP)) {
71 for (
int iv = trc.vtIDMin; iv < trc.vtIDMax; iv++) {
72 const auto& pv =
data.getPrimaryVertex(iv);
75 if (!trcatPV.propagateToDCA(pv, mBz, &dca)) {
80 const auto& trcTPC =
data.getTPCTrack(trc.origID);
82 dca.setZ(dca.getZ() + (trcTPC.hasASideClustersOnly() ? deltaZ : -deltaZ));
85 if (dca.calcChi2() < mMatchParams->
dcaCutChi2[trc.origID.getSource()]) {
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) {
103 ntr = lastValid >= 0 ? lastValid + 1 : 0;
104 LOGP(info,
"Collected {} seeds, validated: {}", mSeeds.size(), 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) {
123 LOG(info) <<
"Refitting " << mWinners.size() <<
" winner matches";
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,
133 tpcClusRefs.data(), 0, tpcClusShMap.data(),
137 const auto& itsClusters = prepareITSClusters(
data);
139 std::vector<int> itsTracksROF;
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;
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();
157 int from =
ncl - 1, to = -1,
step = -1;
163 for (
int icl = from; icl != to; icl +=
step) {
164 const auto& clus = itsClusters[itsTrackClusRefs[clEntry + icl]];
165 float alpha = geomITS->getSensorRefAlpha(clus.getSensorID()),
x = clus.getX();
169 chi2 += trFit.getPredictedChi2(clus);
170 if (!trFit.update(clus)) {
175 return nclRefit ==
ncl ?
ncl : -1;
178 for (
auto winRID : mWinners) {
179 const auto&
rec = mRecords[winRID];
180 int poolEntryID[2] = {
rec.id0,
rec.id1};
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;
187 if (pnt0.Y() > pnt1.Y()) {
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();
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();
210 int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosm, tpcTrOrig.getClusterRef(),
t0 * tpcTBinMUSInv, &chi2,
false,
false);
212 LOG(
debug) <<
"Inward refit of btm TPC track failed.";
216 LOG(
debug) <<
"chi2 after btm TPC refit with " <<
retVal <<
" clusters : " << chi2 <<
" orig.chi2 was " << tpcTrOrig.getChi2();
220 trCosm.setQ2Pt(-trCosm.getQ2Pt());
222 auto gidxListBtm =
data.getSingleDetectorRefs(mSeeds[poolEntryID[btm]].origID);
225 nclTot += tpcTrOrig.getNClusters();
226 chi2 += tpcTrOrig.getChi2();
230 nclTot += itsTrOrig.getNClusters();
231 chi2 += itsTrOrig.getChi2();
235 if (!trCosm.rotate(mSeeds[poolEntryID[
top]].getAlpha()) ||
237 LOG(
debug) <<
"Rotation/propagation of btm-track to top-track frame failed.";
241 auto trCosmBtm = trCosm;
245 auto gidxListTop =
data.getSingleDetectorRefs(mSeeds[poolEntryID[
top]].origID);
249 auto nclfit = refitITSTrack(trCosm, gidxListTop[
GTrackID::ITS], chi2,
false);
253 LOG(
debug) <<
"chi2 after top ITS refit with " << nclfit <<
" clusters : " << chi2 <<
" orig.chi2 was " <<
data.getITSTrack(gidxListTop[
GTrackID::ITS]).getChi2();
263 LOG(
debug) <<
"Propagation to inner TPC boundary X=" << xtogo <<
" failed";
268 int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosm, tpcTrOrig.getClusterRef(),
t0 * tpcTBinMUSInv, &chi2,
true,
false);
270 LOG(
debug) <<
"Outward refit of top TPC track failed.";
273 LOG(
debug) <<
"chi2 after top TPC refit with " <<
retVal <<
" clusters : " << chi2 <<
" orig.chi2 was " << tpcTrOrig.getChi2();
279 auto trCosmTop = outerLegs[
top];
282 int retVal = tpcRefitter->RefitTrackAsTrackParCov(trCosmTop, tpcTrOrig.getClusterRef(),
t0 * tpcTBinMUSInv, &chi2Dummy,
false,
true);
284 LOG(
debug) <<
"Outward refit of top TPC track failed.";
290 auto nclfit = refitITSTrack(trCosmTop, gidxListTop[
GTrackID::ITS], chi2Dummy,
true);
297 if (!trCosmTop.rotate(trCosmBtm.getAlpha()) ||
299 LOG(
debug) <<
"Rotation/propagation of top-track to bottom-track frame failed.";
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";
310 mCosmicTracks.emplace_back(mSeeds[poolEntryID[btm]].origID, mSeeds[poolEntryID[
top]].origID, trCosmBtm, trCosmTop, chi2, chi2Match, nclTot,
t0, dt);
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]);
317 LOG(info) <<
"Validated " << mCosmicTracks.size() <<
" top-bottom tracks in TF# " << mTFCount;
321void MatchCosmics::selectWinners()
324 int ntr = mSeeds.size(), iter = 0, nValidated = 0;
325 mWinners.reserve(mRecords.size() / 2);
329 for (
int i = 0;
i < ntr;
i++) {
330 if (mSeeds[
i].matchID < 0 || mRecords[mSeeds[
i].matchID].next ==
Validated) {
334 if (validateMatch(
i)) {
335 mWinners.push_back(mSeeds[
i].matchID);
340 LOGF(info,
"iter %d Validated %d of %d remaining matches", iter, nValidated, nRemaining);
342 }
while (nValidated);
346bool MatchCosmics::validateMatch(
int partner0)
349 auto& matchRec = mRecords[mSeeds[partner0].matchID];
350 auto partner1 = matchRec.id1;
351 auto& patnerRec = mRecords[mSeeds[partner1].matchID];
355 if (patnerRec.id1 == partner0) {
357 auto next0 = matchRec.next;
359 auto& nextRec = mRecords[next0];
360 suppressMatch(partner0, nextRec.id1);
361 next0 = nextRec.next;
366 auto next1 = patnerRec.next;
368 auto& nextRec = mRecords[next1];
369 suppressMatch(partner1, nextRec.id1);
370 next1 = nextRec.next;
379void MatchCosmics::suppressMatch(
int partner0,
int partner1)
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;
386 int topID =
MinusOne, next = mSeeds[partner1].matchID;
388 auto& matchRec = mRecords[next];
389 if (matchRec.id1 == partner0) {
391 mSeeds[partner1].matchID = matchRec.next;
393 mRecords[topID].next = matchRec.next;
398 next = matchRec.next;
407 auto& seed0 = mSeeds[
i];
408 auto& seed1 = mSeeds[
j];
409 if (seed0.matchID ==
Reject) {
412 if (seed1.matchID ==
Reject) {
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();
421 if (seed1.tBracket > seed0.tBracket) {
429 auto dTgl = seed0.getTgl() + seed1.getTgl();
435 auto dQ2Pt = seed0.getQ2Pt() + seed1.getQ2Pt();
444 seed1Inv.updateCov(mMatchParams->
systSigma2[
i], o2::track::DiagMap[
i]);
447 if (!seed1Inv.rotate(seed0.getAlpha()) ||
452 auto dSnp = seed0.getSnp() - seed1Inv.getSnp();
457 auto dY = seed0.getY() - seed1Inv.getY();
462 bool ignoreZ = seed0.origID.getSource() == o2d::GlobalTrackID::TPC || seed1.origID.getSource() == o2d::GlobalTrackID::TPC;
466 auto dZ = seed0.getZ() - seed1Inv.getZ();
472 seed1Inv.setCov(250. * 250., o2::track::DiagMap[
o2::track::kZ]);
479 chi2 = seed0.getPredictedChi2(seed1Inv);
485 registerMatch(
i,
j, chi2);
486 registerMatch(
j,
i, chi2);
487 LOG(
debug) <<
"Chi2 = " << chi2 <<
" NMatches " << mRecords.size();
491#ifdef _ALLOW_DEBUG_TREES_
497 (*mDBGOut) <<
"match"
498 <<
"tf=" << mTFCount <<
"seed0=" << seed0 <<
"seed1=" << seed1I <<
"chi2Match=" << chi2 <<
"rej=" << rejI <<
"\n";
507void MatchCosmics::registerMatch(
int i,
int j,
float chi2)
510 int newRef = mRecords.size();
512 auto* best = &mSeeds[
i].matchID;
514 auto& oldMatchRec = mRecords[*best];
515 if (oldMatchRec.chi2 > chi2) {
516 matchRec.next = *best;
520 best = &oldMatchRec.next;
533 std::unordered_map<GTrackID, int> trackEntry;
535 auto creator = [
this, &trackEntry](
auto& _tr,
GTrackID _origID,
float t0,
float terr) {
537 if (std::abs(_tr.getQ2Pt()) > this->mQ2PtCutoff) {
540 if constexpr (isTPCTrack<decltype(_tr)>()) {
545 t0 *= this->mTPCTBinMUS;
546 terr *= this->mTPCTBinMUS;
548 t0 += 0.5 * this->mITSROFrameLengthMUS;
549 terr *= this->mITSROFrameLengthMUS;
554 trackEntry[_origID] = mSeeds.size();
555 mSeeds.emplace_back(TrackSeed{_tr, {
t0 - terr,
t0 + terr}, _origID,
MinusOne});
556 if constexpr (isTPCTrack<decltype(_tr)>()) {
565 data.createTracksVariadic(creator);
568 auto trackIndex =
data.getPrimaryVertexMatchedTracks();
569 auto vtxRefs =
data.getPrimaryVertexMatchedTrackRefs();
570 int nv = vtxRefs.size() - 1;
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()) {
586 if (
seed.vtIDMin < 0) {
589 seed.vtIDMax = std::max(
short(iv),
seed.vtIDMax);
596void MatchCosmics::updateTimeDependentParams()
600 mTPCTBinMUS = elParam.ZbinWidth;
602 mFieldON = std::abs(mBz) > 0.01;
603 mQ2PtCutoff = 1.f / std::max(0.05f, mMatchParams->
minSeedPt);
605 mQ2PtCutoff *= 5.00668 / std::abs(mBz);
616#ifdef _ALLOW_DEBUG_TREES_COSM
619 mDBGOut = std::make_unique<o2::utils::TreeStreamRedirector>(mDebugTreeFileName.data(),
"recreate");
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();
635 return std::move(itscl);
641#ifdef _ALLOW_DEBUG_TREES_COSM
646#ifdef _ALLOW_DEBUG_TREES_
661 mTPCVDrift =
v.refVDrift *
v.corrFact;
662 mTPCVDriftCorrFact =
v.corrFact;
663 mTPCVDriftRef =
v.refVDrift;
664 mTPCDriftTimeOffset =
v.getTimeOffset();
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
static GeometryTGeo * Instance()
GLfloat GLfloat GLfloat alpha
GLdouble GLdouble GLdouble GLdouble top
GLboolean GLboolean GLboolean b
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
GLboolean GLboolean GLboolean GLboolean a
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
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
constexpr float kMostProbablePt
float crudeNSigma2Cut[o2::track::kNParams]
o2::base::Propagator::MatCorrType matCorr
float dcaCutChi2[o2::dataformats::GlobalTrackID::NSources]
bool discardPVContributors
float systSigma2[o2::track::kNParams]
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"