Project
Loading...
Searching...
No Matches
TrackInterpolation.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
17
20#include "ITStracking/IOUtils.h"
23#include "TOFBase/Geo.h"
25#include "DataFormatsTPC/Defs.h"
30#include "MathUtils/Tsallis.h"
31#include "TRDBase/PadPlane.h"
32#include "TMath.h"
34#include "Framework/Logger.h"
36#include "GPUO2InterfaceUtils.h"
38#include "GPUO2InterfaceRefit.h"
39#include "GPUParam.h"
40#include "GPUParam.inc"
41#include <set>
42#include <algorithm>
43#include <random>
44
45using namespace o2::tpc;
48
49bool UnbinnedResid::gInitDone = false;
50
52{
53 if (!isITS()) {
55 }
56 // ITS alpha repends on the chip ID
59}
60
62{
63 if (isTPC()) {
64 return param::RowX[row];
65 }
67 if (isITS()) {
68 return o2::its::GeometryTGeo::Instance()->getSensorRefX(channel); // ITS X repends on the chip ID
69 }
70 if (isTRD()) {
71 auto geo = o2::trd::Geometry::instance();
72 ROOT::Math::Impl::Transform3D<double>::Point local{geo->cdrHght() - 0.5 - 0.279, 0., 0.}; // see TrackletTransformer::transformTracklet
73 return (geo->getMatrixT2L(channel) ^ local).X();
74 }
75 if (isTOF()) {
76 int det[5];
78 float pos[3] = {0.f, 0.f, 0.f};
80 float posl[3] = {pos[0], pos[1], pos[2]};
82 return pos[2]; // coordinates in sector frame: note that the rotation above puts z in pos[1], the radial coordinate in pos[2], and the tangent coordinate in pos[0] (this is to match the TOF residual system, where we don't use the radial component), so we swap their positions.
83 }
84 LOGP(fatal, "Did not recognize detector type: row:{}, sec:{}, channel:{}", row, sec, channel);
85 return 0.;
86}
87
89{
90 if (!gInitDone) {
91 LOGP(warn, "geometry initialization was not done, doing this for the current timestamp");
92 init();
93 if (!gInitDone) {
94 LOGP(fatal, "geometry initialization failed");
95 }
96 }
97}
98
99void UnbinnedResid::init(long timestamp)
100{
101 if (gInitDone) {
102 LOGP(warn, "Initialization was already done");
103 return;
104 }
105 if (!gGeoManager) {
106 o2::ccdb::BasicCCDBManager::instance().getSpecific<TGeoManager>("GLO/Config/GeometryAligned", timestamp);
107 }
108 auto geoTRD = o2::trd::Geometry::instance();
109 geoTRD->createPadPlaneArray();
110 geoTRD->createClusterMatrixArray();
111 gInitDone = true;
112}
113
118
120{
121 if (mDBGOut) {
122 mDBGOut->Close();
123 mDBGOut.reset();
124 }
125}
126
128{
129 // perform initialization
130 LOG(info) << "Start initializing TrackInterpolation";
131 if (mInitDone) {
132 LOG(error) << "Initialization already performed.";
133 return;
134 }
135
136 const auto& elParam = ParameterElectronics::Instance();
137 mTPCTimeBinMUS = elParam.ZbinWidth;
138
139 mFastTransform = std::move(TPCFastTransformHelperO2::instance()->create(0));
140
141 mBz = o2::base::Propagator::Instance()->getNominalBz();
142 mRecoParam.init(mBz);
143 mGeoTRD = o2::trd::Geometry::instance();
145
146 mSourcesConfigured = src;
147 mSourcesConfiguredMap = srcMap;
148 mSingleSourcesConfigured = (mSourcesConfigured == mSourcesConfiguredMap);
149 mTrackTypes.insert({GTrackID::ITSTPC, 0});
150 mTrackTypes.insert({GTrackID::ITSTPCTRD, 1});
151 mTrackTypes.insert({GTrackID::ITSTPCTOF, 2});
152 mTrackTypes.insert({GTrackID::ITSTPCTRDTOF, 3});
153
155 geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G));
156 mTPCParam = o2::gpu::GPUO2InterfaceUtils::getFullParamShared(0.f, mNHBPerTF);
157
158 if (mParams->writeValidationData) {
159 std::string dbgnm = mNLanes == 1 ? "track_interpolation_dbg.root" : fmt::format("track_interpolation_dbg_{}.root", mLaneID);
160 mDBGOut = std::make_unique<o2::utils::TreeStreamRedirector>(dbgnm.c_str(), "recreate");
161 }
162
163 mInitDone = true;
164 LOGP(info, "Done initializing TrackInterpolation. Configured track input: {}. Track input specifically for map: {}",
165 GTrackID::getSourcesNames(mSourcesConfigured), mSingleSourcesConfigured ? "identical" : GTrackID::getSourcesNames(mSourcesConfiguredMap));
166}
167
169{
170 LOGP(debug, "Check if input track {} is accepted", gid.asString());
171 bool hasOuterPoint = gidTable[GTrackID::TRD].isIndexSet() || gidTable[GTrackID::TOF].isIndexSet();
172 if (!hasOuterPoint && !mProcessITSTPConly) {
173 return false; // don't do ITS-only extrapolation through TPC
174 }
175 const auto itsTrk = mRecoCont->getITSTrack(gidTable[GTrackID::ITS]);
176 const auto tpcTrk = mRecoCont->getTPCTrack(gidTable[GTrackID::TPC]);
177
178 if (gidTable[GTrackID::TRD].isIndexSet()) {
179 // TRD specific cuts
180 const auto& trdTrk = mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTable[GTrackID::ITSTPCTRD]);
181 if (trdTrk.getNtracklets() < mParams->minTRDNTrklts) {
182 return false;
183 }
184 }
185 // reduced chi2 cut is the same for all track types
186 if (itsTrk.getChi2() / itsTrk.getNumberOfClusters() > mParams->maxITSChi2 || tpcTrk.getChi2() / tpcTrk.getNClusterReferences() > mParams->maxTPCChi2) {
187 return false;
188 }
189 if (!hasOuterPoint) {
190 // ITS-TPC track (does not have outer points in TRD or TOF)
191 if (itsTrk.getNumberOfClusters() < mParams->minITSNClsNoOuterPoint || tpcTrk.getNClusterReferences() < mParams->minTPCNClsNoOuterPoint) {
192 return false;
193 }
194 if (itsTrk.getPt() < mParams->minPtNoOuterPoint) {
195 return false;
196 }
197 } else {
198 if (itsTrk.getNumberOfClusters() < mParams->minITSNCls || tpcTrk.getNClusterReferences() < mParams->minTPCNCls) {
199 return false;
200 }
201 }
202
203 auto trc = mRecoCont->getTrackParam(gid);
205 auto prop = o2::base::Propagator::Instance();
206 if (!prop->propagateToDCA(pv, trc, prop->getNominalBz(), 2., o2::base::PropagatorF::MatCorrType::USEMatCorrLUT, &dca)) {
207 return false;
208 }
209 if (dca.getR2() > mParams->maxDCA * mParams->maxDCA) {
210 return false;
211 }
212 return true;
213}
214
216{
217 LOGP(debug, "Trying to find valid source for {} in {}", GTrackID::getSourceName(src), GTrackID::getSourcesNames(mask));
220 return GTrackID::ITSTPCTRD;
221 } else if (mask[GTrackID::ITSTPC]) {
222 return GTrackID::ITSTPC;
223 } else {
224 return GTrackID::NSources;
225 }
226 } else if (src == GTrackID::ITSTPCTRD || src == GTrackID::ITSTPCTOF) {
227 if (mask[GTrackID::ITSTPC]) {
228 return GTrackID::ITSTPC;
229 } else {
230 return GTrackID::NSources;
231 }
232 } else {
233 return GTrackID::NSources;
234 }
235}
236
238{
239 mRecoCont = &inp;
240 uint32_t nTrackSeeds = 0;
241 uint32_t countSeedCandidates[4] = {0};
242 auto pvvec = mRecoCont->getPrimaryVertices();
243 auto trackIndex = mRecoCont->getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks
244 auto vtxRefs = mRecoCont->getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs
245 int nv = vtxRefs.size() - 1;
246 GTrackID::mask_t allowedSources = GTrackID::getSourcesMask("ITS-TPC,ITS-TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD-TOF") & mSourcesConfigured;
247 constexpr std::array<int, 3> SrcFast = {int(GTrackID::ITSTPCTRD), int(GTrackID::ITSTPCTOF), int(GTrackID::ITSTPCTRDTOF)};
248 if (mParams->refitITS) {
249 mITSRefitSeedID.resize(mRecoCont->getITSTracks().size(), -1);
250 }
251
252 for (int iv = 0; iv < nv; iv++) {
253 LOGP(debug, "processing PV {} of {}", iv, nv);
254
255 const auto& vtref = vtxRefs[iv];
256 auto pv = pvvec[iv];
257 if (mParams->minTOFTRDPVContributors > 0) { // we want only PVs constrained by fast detectors
258 int nfound = 0;
259 bool usePV = false;
260 for (uint32_t is = 0; is < SrcFast.size() && !usePV; is++) {
261 int src = SrcFast[is], idMin = vtref.getFirstEntryOfSource(src), idMax = idMin + vtref.getEntriesOfSource(src);
262 for (int i = idMin; i < idMax; i++) {
263 if (trackIndex[i].isPVContributor() && (++nfound == mParams->minTOFTRDPVContributors)) {
264 usePV = true;
265 break;
266 }
267 }
268 }
269 if (!usePV) {
270 continue;
271 }
272 }
273
274 for (int is = GTrackID::NSources; is--;) {
275 if (!allowedSources[is]) {
276 continue;
277 }
278 LOGP(debug, "Checking source {}", is);
279 int idMin = vtref.getFirstEntryOfSource(is), idMax = idMin + vtref.getEntriesOfSource(is);
280 for (int i = idMin; i < idMax; i++) {
281 auto vid = trackIndex[i];
282 auto vidOrig = vid; // in case only ITS-TPC tracks are configured vid might be overwritten. We need to remember it for the PID
283 if (mParams->ignoreNonPVContrib && !vid.isPVContributor()) {
284 continue;
285 }
286 if (vid.isAmbiguous()) {
287 continue;
288 }
289 auto gidTable = mRecoCont->getSingleDetectorRefs(vid);
290 if (!mSourcesConfigured[is]) {
291 auto src = findValidSource(mSourcesConfigured, static_cast<GTrackID::Source>(vid.getSource()));
293 LOGP(debug, "prepareInputTrackSample: Found valid source {}", GTrackID::getSourceName(src));
294 vid = gidTable[src];
295 gidTable = mRecoCont->getSingleDetectorRefs(vid);
296 } else {
297 break; // no valid source for this vertex track source exists
298 }
299 }
300 ++countSeedCandidates[mTrackTypes[vid.getSource()]];
301 LOGP(debug, "Checking vid {}", vid.asString());
302 if (!isInputTrackAccepted(vid, gidTable, pv)) {
303 continue;
304 }
305 mSeeds.push_back(mRecoCont->getITSTrack(gidTable[GTrackID::ITS]).getParamOut());
306 mSeeds.back().setPID(mRecoCont->getTrackParam(vidOrig).getPID(), true);
307 mGIDs.push_back(vid);
308 mGIDtables.push_back(gidTable);
309 mTrackTimes.push_back(pv.getTimeStamp().getTimeStamp());
310 mTrackIndices[mTrackTypes[vid.getSource()]].push_back(nTrackSeeds++);
311 mTrackPVID.push_back(iv);
312 }
313 }
314 }
315
316 LOGP(info, "Created {} seeds. {} out of {} ITS-TPC-TRD-TOF, {} out of {} ITS-TPC-TRD, {} out of {} ITS-TPC-TOF, {} out of {} ITS-TPC",
317 nTrackSeeds,
318 mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRDTOF]].size(), countSeedCandidates[mTrackTypes[GTrackID::ITSTPCTRDTOF]],
319 mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRD]].size(), countSeedCandidates[mTrackTypes[GTrackID::ITSTPCTRD]],
320 mTrackIndices[mTrackTypes[GTrackID::ITSTPCTOF]].size(), countSeedCandidates[mTrackTypes[GTrackID::ITSTPCTOF]],
321 mTrackIndices[mTrackTypes[GTrackID::ITSTPC]].size(), countSeedCandidates[mTrackTypes[GTrackID::ITSTPC]]);
322}
323
325{
326 std::random_device rd;
327 std::mt19937 g(rd());
328 std::uniform_real_distribution<> distr(0., 1.);
329 float weight = 0;
331}
332
334{
335 // main processing function
336 if (!mInitDone) {
337 LOG(error) << "Initialization not yet done. Aborting...";
338 return;
339 }
340 // set the input containers
341 mTPCTrackClusIdx = mRecoCont->getTPCTracksClusterRefs();
342 mTPCShClassMap = mRecoCont->clusterShMapTPC;
343 mTPCClusterIdxStruct = &mRecoCont->getTPCClusters();
344 int nbOccTOT = o2::gpu::GPUO2InterfaceRefit::fillOccupancyMapGetSize(mNHBPerTF, mTPCParam.get());
345 o2::gpu::GPUO2InterfaceUtils::paramUseExternalOccupancyMap(mTPCParam.get(), mNHBPerTF, mRecoCont->occupancyMapTPC.data(), nbOccTOT);
346 mNTPCOccBinLength = mTPCParam->rec.tpc.occupancyMapTimeBins;
347 mNTPCOccBinLengthInv = 1.f / mNTPCOccBinLength;
348 {
349 if (!mITSDict) {
350 LOG(error) << "No ITS dictionary available";
351 return;
352 }
353 mITSTrackClusIdx = mRecoCont->getITSTracksClusterRefs();
354 const auto clusITS = mRecoCont->getITSClusters();
355 const auto patterns = mRecoCont->getITSClustersPatterns();
356 auto pattIt = patterns.begin();
357 mITSClustersArray.clear();
358 mITSClustersArray.reserve(clusITS.size());
359 LOGP(info, "We have {} ITS clusters and the number of patterns is {}", clusITS.size(), patterns.size());
360 o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict);
361 }
362
363 // In case we have more input tracks available than are required per TF
364 // we want to sample them. But we still prefer global ITS-TPC-TRD-TOF tracks
365 // over ITS-TPC-TRD tracks and so on. So we have to shuffle the indices
366 // in blocks.
367 std::random_device rd;
368 std::mt19937 g(rd());
369 std::vector<uint32_t> trackIndices; // here we keep the GIDs for all track types in a single vector to use in loop
370 std::shuffle(mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRDTOF]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRDTOF]].end(), g);
371 std::shuffle(mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRD]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRD]].end(), g);
372 std::shuffle(mTrackIndices[mTrackTypes[GTrackID::ITSTPCTOF]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTOF]].end(), g);
373 std::shuffle(mTrackIndices[mTrackTypes[GTrackID::ITSTPC]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPC]].end(), g);
374 trackIndices.insert(trackIndices.end(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRDTOF]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRDTOF]].end());
375 trackIndices.insert(trackIndices.end(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRD]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRD]].end());
376 trackIndices.insert(trackIndices.end(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTOF]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTOF]].end());
377 trackIndices.insert(trackIndices.end(), mTrackIndices[mTrackTypes[GTrackID::ITSTPC]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPC]].end());
378 int nSeeds = mSeeds.size(), lastChecked = 0;
379 mParentID.clear();
380 mParentID.resize(nSeeds, -1);
381
382 int maxOutputTracks = (mMaxTracksPerTF >= 0) ? mMaxTracksPerTF + mAddTracksForMapPerTF : nSeeds;
383 mTrackData.reserve(maxOutputTracks);
384 mClRes.reserve(maxOutputTracks * param::NPadRows);
385 mDetInfoRes.reserve(maxOutputTracks * param::NPadRows);
386 bool maxTracksReached = false;
387 for (int iSeed = 0; iSeed < nSeeds; ++iSeed) {
388 if (mMaxTracksPerTF >= 0 && mTrackDataCompact.size() >= mMaxTracksPerTF + mAddTracksForMapPerTF) {
389 LOG(info) << "Maximum number of tracks per TF reached. Skipping the remaining " << nSeeds - iSeed << " tracks.";
390 break;
391 }
392 int seedIndex = trackIndices[iSeed];
393 if (mParams->enableTrackDownsampling && !isTrackSelected(mSeeds[seedIndex])) {
394 continue;
395 }
396 auto addPart = [this, seedIndex](GTrackID::Source src) {
397 this->mGIDs.push_back(this->mGIDtables[seedIndex][src]);
398 this->mGIDtables.push_back(this->mRecoCont->getSingleDetectorRefs(this->mGIDs.back()));
399 this->mTrackTimes.push_back(this->mTrackTimes[seedIndex]);
400 this->mSeeds.push_back(this->mSeeds[seedIndex]);
401 this->mParentID.push_back(seedIndex); // store parent seed id
402 this->mTrackPVID.push_back(this->mTrackPVID[seedIndex]);
403 };
404
405 GTrackID::mask_t partsAdded;
406 if (!mSingleSourcesConfigured && !mSourcesConfiguredMap[mGIDs[seedIndex].getSource()]) {
407 auto src = findValidSource(mSourcesConfiguredMap, static_cast<GTrackID::Source>(mGIDs[seedIndex].getSource()));
409 LOGP(debug, "process {}: Found valid source {} for {} | nseeds:{} mSeeds:{} used: {}", iSeed, GTrackID::getSourceName(src), GTrackID::getSourceName(mGIDs[seedIndex].getSource()), nSeeds, mSeeds.size(), mTrackDataCompact.size());
410 addPart(src);
411 }
412 }
413 if (mMaxTracksPerTF >= 0 && mTrackDataCompact.size() >= mMaxTracksPerTF) {
414 if (!maxTracksReached) {
415 LOGP(info, "We already have reached mMaxTracksPerTF={}, but we continue to create seeds until mAddTracksForMapPerTF={} is also reached, iSeed: {} of {} inital seeds", mMaxTracksPerTF, mAddTracksForMapPerTF, iSeed, nSeeds);
416 }
417 maxTracksReached = true;
418 continue;
419 }
420 if (mGIDs[seedIndex].includesDet(DetID::TRD) || mGIDs[seedIndex].includesDet(DetID::TOF)) {
421 interpolateTrack(seedIndex);
422 LOGP(debug, "interpolateTrack {} {}, accepted: {}", iSeed, GTrackID::getSourceName(mGIDs[seedIndex].getSource()), mTrackDataCompact.size());
423 if (mProcessSeeds) {
424 if (mGIDs[seedIndex].includesDet(DetID::TRD) && mGIDs[seedIndex].includesDet(DetID::TOF) && !partsAdded[GTrackID::ITSTPCTRD]) {
425 addPart(GTrackID::ITSTPCTRD);
426 }
427 if (!partsAdded[GTrackID::ITSTPC]) {
428 addPart(GTrackID::ITSTPC);
429 }
430 }
431 } else {
432 extrapolateTrack(seedIndex);
433 LOGP(debug, "extrapolateTrack {} {}, accepted: {}", iSeed, GTrackID::getSourceName(mGIDs[seedIndex].getSource()), mTrackDataCompact.size());
434 }
435 lastChecked = iSeed;
436 }
437 std::vector<int> remSeeds;
438 if (mSeeds.size() > ++lastChecked) {
439 remSeeds.resize(mSeeds.size() - lastChecked);
440 std::iota(remSeeds.begin(), remSeeds.end(), lastChecked);
441 std::shuffle(remSeeds.begin(), remSeeds.end(), g);
442 LOGP(info, "Up to {} tracks out of {} additional seeds will be processed in random order, of which {} are stripped versions, accepted seeds: {}",
443 mAddTracksForMapPerTF > 0 ? mAddTracksForMapPerTF : remSeeds.size(),
444 remSeeds.size(), mSeeds.size() - nSeeds, mTrackDataCompact.size());
445 }
446 int extraChecked = 0;
447 for (int iSeed : remSeeds) {
448 if (mAddTracksForMapPerTF > 0 && mTrackDataCompact.size() >= mMaxTracksPerTF + mAddTracksForMapPerTF) {
449 LOGP(info, "Maximum number {} of additional tracks per TF reached. Skipping the remaining {} tracks", mAddTracksForMapPerTF, remSeeds.size() - extraChecked);
450 break;
451 }
452 extraChecked++;
453 if (mGIDs[iSeed].includesDet(DetID::TRD) || mGIDs[iSeed].includesDet(DetID::TOF)) {
454 interpolateTrack(iSeed);
455 LOGP(debug, "extra check {} of {}, seed {} interpolateTrack {}, used: {}", extraChecked, remSeeds.size(), iSeed, GTrackID::getSourceName(mGIDs[iSeed].getSource()), mTrackDataCompact.size());
456 } else {
457 LOGP(debug, "extra check {} of {}, seed {} extrapolateTrack {}, used: {}", extraChecked, remSeeds.size(), iSeed, GTrackID::getSourceName(mGIDs[iSeed].getSource()), mTrackDataCompact.size());
458 extrapolateTrack(iSeed);
459 }
460 }
461 LOGP(info, "Could process {} tracks successfully ({} rejected in refits, {} in propagation, {} as loopers), {} residuals were rejected, {} accepted",
462 mTrackData.size(), mNRejRefit, mNRejProp, mNRejLoop, mRejectedResiduals, mClRes.size());
463 mRejectedResiduals = 0;
464 mNRejRefit = 0;
465 mNRejProp = 0;
466 mNRejLoop = 0;
467}
468
470{
471 LOGP(debug, "Starting track interpolation for GID {}", mGIDs[iSeed].asString());
472 TrackData trackData;
473 o2::trd::Tracklet64 trkl64;
475 std::unique_ptr<TrackDataExtended> trackDataExtended;
476 std::vector<TPCClusterResiduals> clusterResiduals;
477 auto propagator = o2::base::Propagator::Instance();
478 const auto& gidTable = mGIDtables[iSeed];
479 const auto& trkTPC = mRecoCont->getTPCTrack(gidTable[GTrackID::TPC]);
480 const auto& trkITS = mRecoCont->getITSTrack(gidTable[GTrackID::ITS]);
481 if (mDumpTrackPoints) {
482 trackDataExtended = std::make_unique<TrackDataExtended>();
483 (*trackDataExtended).gid = mGIDs[iSeed];
484 (*trackDataExtended).clIdx.setFirstEntry(mClRes.size());
485 (*trackDataExtended).trkITS = trkITS;
486 (*trackDataExtended).trkTPC = trkTPC;
487 auto nCl = trkITS.getNumberOfClusters();
488 auto clEntry = trkITS.getFirstClusterEntry();
489 for (int iCl = nCl - 1; iCl >= 0; iCl--) { // clusters are stored from outer to inner layers
490 const auto& clsITS = mITSClustersArray[mITSTrackClusIdx[clEntry + iCl]];
491 (*trackDataExtended).clsITS.push_back(clsITS);
492 }
493 }
494 if (mParams->refitITS && !refITSTrack(gidTable[GTrackID::ITS], iSeed)) {
495 mNRejRefit++;
496 return;
497 }
498 trackData.gid = mGIDs[iSeed];
499 trackData.par = mSeeds[iSeed];
500 auto trkWork = mSeeds[iSeed];
501 o2::track::TrackPar trkInner{trkWork};
502 // reset the cache array (sufficient to set cluster available to zero)
503 for (auto& elem : mCache) {
504 elem.clAvailable = 0;
505 }
506 trackData.clIdx.setFirstEntry(mClRes.size()); // reference the first cluster residual belonging to this track
507 float clusterTimeBinOffset = mTrackTimes[iSeed] / mTPCTimeBinMUS;
508
509 // store the TPC cluster positions in the cache, as well as dedx info
510 std::array<std::pair<uint16_t, uint16_t>, constants::MAXGLOBALPADROW> mCacheDEDX{};
511 std::array<short, constants::MAXGLOBALPADROW> multBins{};
512 for (int iCl = trkTPC.getNClusterReferences(); iCl--;) {
513 uint8_t sector, row;
514 uint32_t clusterIndexInRow;
515 trkTPC.getClusterReference(mTPCTrackClusIdx, iCl, sector, row, clusterIndexInRow);
516 unsigned int absoluteIndex = mTPCClusterIdxStruct->clusterOffset[sector][row] + clusterIndexInRow;
517 const auto& clTPC = mTPCClusterIdxStruct->clustersLinear[absoluteIndex];
518 float clTPCX;
519 std::array<float, 2> clTPCYZ;
520 mFastTransform->TransformIdeal(sector, row, clTPC.getPad(), clTPC.getTime(), clTPCX, clTPCYZ[0], clTPCYZ[1], clusterTimeBinOffset);
521 mCache[row].clSec = sector;
522 mCache[row].clAvailable = 1;
523 mCache[row].clY = clTPCYZ[0];
524 mCache[row].clZ = clTPCYZ[1];
525 mCache[row].clAngle = o2::math_utils::sector2Angle(sector);
526 mCache[row].clFlags = clTPC.getFlags();
527 if (mTPCShClassMap[absoluteIndex] & o2::gpu::GPUTPCGMMergedTrackHit::flagShared) {
529 }
530 mCacheDEDX[row].first = std::min<uint16_t>(clTPC.getQtot(), UINT16_MAX);
531 mCacheDEDX[row].second = clTPC.getQmax();
532 int imb = int(clTPC.getTime() * mNTPCOccBinLengthInv);
533 if (imb < mTPCParam->occupancyMapSize) {
534 multBins[row] = 1 + std::max(0, imb);
535 }
536 }
537
538 // extrapolate seed through TPC and store track position at each pad row
539 for (int iRow = 0; iRow < param::NPadRows; ++iRow) {
540 if (!mCache[iRow].clAvailable) {
541 continue;
542 }
543 if (!trkWork.rotate(mCache[iRow].clAngle)) {
544 LOG(debug) << "Failed to rotate track during first extrapolation";
545 mNRejProp++;
546 return;
547 }
548 if (!propagator->PropagateToXBxByBz(trkWork, param::RowX[iRow], mParams->maxSnp, mParams->maxStep, mMatCorr)) {
549 LOG(debug) << "Failed on first extrapolation";
550 mNRejProp++;
551 return;
552 }
553 mCache[iRow].y[ExtOut] = trkWork.getY();
554 mCache[iRow].z[ExtOut] = trkWork.getZ();
555 mCache[iRow].sy2[ExtOut] = trkWork.getSigmaY2();
556 mCache[iRow].szy[ExtOut] = trkWork.getSigmaZY();
557 mCache[iRow].sz2[ExtOut] = trkWork.getSigmaZ2();
558 mCache[iRow].snp[ExtOut] = trkWork.getSnp();
559 // printf("Track alpha at row %i: %.2f, Y(%.2f), Z(%.2f)\n", iRow, trkWork.getAlpha(), trkWork.getY(), trkWork.getZ());
560 }
561
562 // start from outermost cluster with outer refit and back propagation
563 if (gidTable[GTrackID::TOF].isIndexSet()) {
564 LOG(debug) << "TOF point available";
565 const auto& clTOF = mRecoCont->getTOFClusters()[gidTable[GTrackID::TOF]];
566 if (mDumpTrackPoints) {
567 (*trackDataExtended).clsTOF = clTOF;
568 (*trackDataExtended).matchTOF = mRecoCont->getTOFMatch(mGIDs[iSeed]);
569 }
570 const int clTOFSec = clTOF.getCount();
571 const float clTOFAlpha = o2::math_utils::sector2Angle(clTOFSec);
572 if (!trkWork.rotate(clTOFAlpha)) {
573 LOG(debug) << "Failed to rotate into TOF cluster sector frame";
574 mNRejProp++;
575 return;
576 }
577 float clTOFxyz[3] = {clTOF.getX(), clTOF.getY(), clTOF.getZ()};
578 if (!clTOF.isInNominalSector()) {
579 o2::tof::Geo::alignedToNominalSector(clTOFxyz, clTOFSec); // go from the aligned to nominal sector frame
580 }
581 std::array<float, 2> clTOFYZ{clTOFxyz[1], clTOFxyz[2]};
582 std::array<float, 3> clTOFCov{mParams->sigYZ2TOF, 0.f, mParams->sigYZ2TOF}; // assume no correlation between y and z and equal cluster error sigma^2 = (3cm)^2 / 12
583 if (!propagator->PropagateToXBxByBz(trkWork, clTOFxyz[0], mParams->maxSnp, mParams->maxStep, mMatCorr)) {
584 LOG(debug) << "Failed final propagation to TOF radius";
585 mNRejProp++;
586 return;
587 }
588 // TODO: check if reset of covariance matrix is needed here (or, in case TOF point is not available at outermost TRD layer)
589 if (!trkWork.update(clTOFYZ, clTOFCov)) {
590 LOG(debug) << "Failed to update extrapolated ITS track with TOF cluster";
591 // LOGF(info, "trkWork.y=%f, cl.y=%f, trkWork.z=%f, cl.z=%f", trkWork.getY(), clTOFYZ[0], trkWork.getZ(), clTOFYZ[1]);
592 mNRejProp++;
593 return;
594 }
595 }
596 if (gidTable[GTrackID::TRD].isIndexSet()) {
597 LOG(debug) << "TRD available";
598 const auto& trkTRD = mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTable[GTrackID::ITSTPCTRD]);
599 if (mDumpTrackPoints) {
600 (*trackDataExtended).trkTRD = trkTRD;
601 }
602 for (int iLayer = o2::trd::constants::NLAYER - 1; iLayer >= 0; --iLayer) {
603 std::array<float, 2> trkltTRDYZ{};
604 std::array<float, 3> trkltTRDCov{};
605 int res = processTRDLayer(trkTRD, iLayer, trkWork, &trkltTRDYZ, &trkltTRDCov);
606 if (res == -1) { // no TRD tracklet in this layer
607 continue;
608 }
609 if (res < -1) { // failed to reach this layer
610 return;
611 }
612 if (!trkWork.update(trkltTRDYZ, trkltTRDCov)) {
613 LOG(debug) << "Failed to update track at TRD layer " << iLayer;
614 mNRejProp++;
615 return;
616 }
617 }
618 }
619
620 if (mDumpTrackPoints) {
621 (*trackDataExtended).trkOuter = trkWork;
622 }
623 auto trkOuter = trkWork; // outer param
624
625 // go back through the TPC and store updated track positions
626 bool outerParamStored = false;
627 for (int iRow = param::NPadRows; iRow--;) {
628 if (!mCache[iRow].clAvailable) {
629 continue;
630 }
631 if (mProcessSeeds && !outerParamStored) {
632 // for debug purposes we store the track parameters
633 // of the refitted ITS-(TRD)-(TOF) track at the
634 // outermose TPC cluster if we are processing all seeds
635 // i.e. if we in any case also process the ITS-TPC only
636 // part of the same track
637 trackData.par = trkWork;
638 outerParamStored = true;
639 }
640 if (!trkWork.rotate(mCache[iRow].clAngle)) {
641 LOG(debug) << "Failed to rotate track during back propagation";
642 mNRejProp++;
643 return;
644 }
645 if (!propagator->PropagateToXBxByBz(trkWork, param::RowX[iRow], mParams->maxSnp, mParams->maxStep, mMatCorr)) {
646 LOG(debug) << "Failed on back propagation";
647 // printf("trkX(%.2f), clX(%.2f), clY(%.2f), clZ(%.2f), alphaTOF(%.2f)\n", trkWork.getX(), param::RowX[iRow], clTOFYZ[0], clTOFYZ[1], clTOFAlpha);
648 mNRejProp++;
649 return;
650 }
651 mCache[iRow].y[ExtIn] = trkWork.getY();
652 mCache[iRow].z[ExtIn] = trkWork.getZ();
653 mCache[iRow].sy2[ExtIn] = trkWork.getSigmaY2();
654 mCache[iRow].szy[ExtIn] = trkWork.getSigmaZY();
655 mCache[iRow].sz2[ExtIn] = trkWork.getSigmaZ2();
656 mCache[iRow].snp[ExtIn] = trkWork.getSnp();
657 }
658
659 // calculate weighted mean at each pad row (assume for now y and z are uncorrelated) and store residuals to TPC clusters
660 unsigned short deltaRow = 0;
661 for (int iRow = 0; iRow < param::NPadRows; ++iRow) {
662 if (!mCache[iRow].clAvailable) {
663 ++deltaRow;
664 continue;
665 }
666 float wTotY = 1.f / mCache[iRow].sy2[ExtOut] + 1.f / mCache[iRow].sy2[ExtIn];
667 float wTotZ = 1.f / mCache[iRow].sz2[ExtOut] + 1.f / mCache[iRow].sz2[ExtIn];
668 mCache[iRow].y[Int] = (mCache[iRow].y[ExtOut] / mCache[iRow].sy2[ExtOut] + mCache[iRow].y[ExtIn] / mCache[iRow].sy2[ExtIn]) / wTotY;
669 mCache[iRow].z[Int] = (mCache[iRow].z[ExtOut] / mCache[iRow].sz2[ExtOut] + mCache[iRow].z[ExtIn] / mCache[iRow].sz2[ExtIn]) / wTotZ;
670
671 // simple average w/o weighting for angle
672 mCache[iRow].snp[Int] = (mCache[iRow].snp[ExtOut] + mCache[iRow].snp[ExtIn]) / 2.f;
673
674 const auto dY = mCache[iRow].clY - mCache[iRow].y[Int];
675 const auto dZ = mCache[iRow].clZ - mCache[iRow].z[Int];
676 const auto y = mCache[iRow].y[Int];
677 const auto z = mCache[iRow].z[Int];
678 const auto snp = mCache[iRow].snp[Int];
679 const auto sec = mCache[iRow].clSec;
680 clusterResiduals.emplace_back(dY, dZ, y, z, snp, sec, deltaRow, mCache[iRow].clFlags);
681
682 deltaRow = 1;
683 }
684 trackData.chi2TRD = gidTable[GTrackID::TRD].isIndexSet() ? mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTable[GTrackID::ITSTPCTRD]).getChi2() : 0;
685 trackData.chi2TPC = trkTPC.getChi2();
686 trackData.chi2ITS = trkITS.getChi2();
687 trackData.nClsTPC = trkTPC.getNClusterReferences();
688 trackData.nClsITS = trkITS.getNumberOfClusters();
689 trackData.nTrkltsTRD = gidTable[GTrackID::TRD].isIndexSet() ? mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTable[GTrackID::ITSTPCTRD]).getNtracklets() : 0;
690
691 double t0forTOF = 0.; // to be set if TOF is matched
692 float t0forTOFwithinBC = 0.f;
693 float t0forTOFres = 9999.f;
694
695 if (gidTable[GTrackID::TOF].isIndexSet()) {
696 const auto& tofMatch = mRecoCont->getTOFMatch(mGIDs[iSeed]);
697 ULong64_t bclongtof = (tofMatch.getSignal() - 10000) * o2::tof::Geo::BC_TIME_INPS_INV;
698 t0forTOF = tofMatch.getFT0Best(); // setting t0 for TOF
699 t0forTOFwithinBC = t0forTOF - bclongtof * o2::tof::Geo::BC_TIME_INPS;
700 t0forTOFres = tofMatch.getFT0BestRes();
701 trackData.deltaTOF = tofMatch.getSignal() - t0forTOF - tofMatch.getLTIntegralOut().getTOF(trkTPC.getPID().getID());
702 trackData.clAvailTOF = uint16_t(t0forTOFres);
703 } else {
704 trackData.clAvailTOF = 0;
705 }
706 trackData.dEdxTPC = trkTPC.getdEdx().dEdxTotTPC;
707
708 mTrackValidation.clear(); // for refitted track parameters and flagging rejected clusters
709
710 bool stored = false;
711 trackData.filterFlag = mParams->skipOutlierFiltering ? -1 : validateTrack(trackData, mTrackValidation, clusterResiduals, true);
712 if (trackData.filterFlag <= 0 || mParams->writeUnfiltered) {
713 int nClValidated = 0;
714 int iRow = 0;
715 for (unsigned int iCl = 0; iCl < clusterResiduals.size(); ++iCl) {
716 iRow += clusterResiduals[iCl].dRow;
717 const auto rej = trackData.filterFlag < 0 ? false : mTrackValidation.points[iCl].flagRej;
718 if (rej && !mParams->keepRejectedResiduals) { // skip masked cluster residual
719 continue;
720 }
721 const float tgPhi = clusterResiduals[iCl].snp / std::sqrt((1.f - clusterResiduals[iCl].snp) * (1.f + clusterResiduals[iCl].snp));
722 const auto dy = clusterResiduals[iCl].dy;
723 const auto dz = clusterResiduals[iCl].dz;
724 const auto y = clusterResiduals[iCl].y;
725 const auto z = clusterResiduals[iCl].z;
726 const auto sec = clusterResiduals[iCl].sec;
727 const short flags = clusterResiduals[iCl].flags;
728 if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(y) < param::MaxY) && (std::abs(z) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) {
729 mClRes.emplace_back(dy, dz, tgPhi, y, z, iRow, sec, flags, rej);
730 mDetInfoRes.emplace_back().setTPC(mCacheDEDX[iRow].first, mCacheDEDX[iRow].second); // qtot, qmax
731 ++nClValidated;
732 } else {
733 ++mRejectedResiduals;
734 }
735 }
736 trackData.clIdx.setEntries(nClValidated);
737
738 // store multiplicity info
739 for (int ist = 0; ist < NSTACKS; ist++) {
740 int mltBinMin = 0x7ffff, mltBinMax = -1, prevBin = -1;
741 for (int ir = STACKROWS[ist]; ir < STACKROWS[ist + 1]; ir++) {
742 if (multBins[ir] != prevBin && multBins[ir] > 0) { // there is a cluster different from previous one
743 prevBin = multBins[ir];
744 if (multBins[ir] > mltBinMax) {
745 mltBinMax = multBins[ir];
746 }
747 if (multBins[ir] < mltBinMin) {
748 mltBinMin = multBins[ir];
749 }
750 }
751 }
752 if (--mltBinMin >= 0) { // we were offsetting bin IDs by 1!
753 float avMlt = 0;
754 for (int ib = mltBinMin; ib < mltBinMax; ib++) {
755 avMlt += mTPCParam->occupancyMap[ib];
756 }
757 avMlt /= (mltBinMax - mltBinMin);
758 trackData.setMultStack(avMlt, ist);
759 }
760 }
761
762 bool stopPropagation = !mExtDetResid;
763 if (!stopPropagation) {
764 // do we have TRD residuals to add?
765 trkWork = trkOuter;
766 if (gidTable[GTrackID::TRD].isIndexSet()) {
767 const auto& trkTRD = mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTable[GTrackID::ITSTPCTRD]);
768 for (int iLayer = 0; iLayer < o2::trd::constants::NLAYER; iLayer++) {
769 std::array<float, 2> trkltTRDYZ{};
770 int res = processTRDLayer(trkTRD, iLayer, trkWork, &trkltTRDYZ, nullptr, &trackData, &trkl64, &trklCalib);
771 if (res == -1) { // no traklet on this layer
772 continue;
773 }
774 if (res < -1) { // failed to reach this layer
775 stopPropagation = true;
776 break;
777 }
778
779 float tgPhi = trkWork.getSnp() / std::sqrt((1.f - trkWork.getSnp()) * (1.f + trkWork.getSnp()));
780 auto dy = trkltTRDYZ[0] - trkWork.getY();
781 auto dz = trkltTRDYZ[1] - trkWork.getZ();
782 if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWork.getY()) < param::MaxY) && (std::abs(trkWork.getZ()) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) {
783 mClRes.emplace_back(dy, dz, tgPhi, trkWork.getY(), trkWork.getZ(), 160 + iLayer, o2::math_utils::angle2Sector(trkWork.getAlpha()), (short)res);
784 mDetInfoRes.emplace_back().setTRD(trkl64.getQ0(), trkl64.getQ1(), trkl64.getQ2(), trklCalib.getDy()); // q0,q1,q2,slope
785 trackData.nExtDetResid++;
786 }
787 }
788 }
789
790 // do we have TOF residual to add?
791 while (gidTable[GTrackID::TOF].isIndexSet() && !stopPropagation) {
792 const auto& clTOF = mRecoCont->getTOFClusters()[gidTable[GTrackID::TOF]];
793 float clTOFxyz[3] = {clTOF.getX(), clTOF.getY(), clTOF.getZ()};
794 if (!clTOF.isInNominalSector()) {
795 o2::tof::Geo::alignedToNominalSector(clTOFxyz, clTOF.getCount()); // go from the aligned to nominal sector frame
796 }
797 const float clTOFAlpha = o2::math_utils::sector2Angle(clTOF.getCount());
798 if (trkWork.getAlpha() != clTOFAlpha && !trkWork.rotate(clTOFAlpha)) {
799 LOG(debug) << "Failed to rotate into TOF cluster sector frame";
800 stopPropagation = true;
801 break;
802 }
803 if (!propagator->PropagateToXBxByBz(trkWork, clTOFxyz[0], mParams->maxSnp, mParams->maxStep, mMatCorr)) {
804 LOG(debug) << "Failed final propagation to TOF radius";
805 break;
806 }
807
808 float tgPhi = trkWork.getSnp() / std::sqrt((1.f - trkWork.getSnp()) * (1.f + trkWork.getSnp()));
809 auto dy = clTOFxyz[1] - trkWork.getY();
810 auto dz = clTOFxyz[2] - trkWork.getZ();
811 // get seeding track time
812
813 if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWork.getY()) < param::MaxY) && (std::abs(trkWork.getZ()) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) {
814 mClRes.emplace_back(dy, dz, tgPhi, trkWork.getY(), trkWork.getZ(), 170, clTOF.getCount(), clTOF.getPadInSector());
815 // get seeding track time
816 if (!gidTable[GTrackID::ITSTPC].isIndexSet()) {
817 LOGP(fatal, "ITS-TPC seed index is not set for TOF track");
818 }
819 float tdif = static_cast<float>(clTOF.getTime() - t0forTOF); // time in \mus wrt interaction time0
820 mDetInfoRes.emplace_back().setTOF(tdif * 1e-6);
821 trackData.nExtDetResid++;
822 }
823 break;
824 }
825
826 // add ITS residuals
827 while (!stopPropagation) {
828 auto& trkWorkITS = trkInner; // this is ITS outer param
829 auto nCl = trkITS.getNumberOfClusters();
830 auto clEntry = trkITS.getFirstClusterEntry();
832 for (int iCl = 0; iCl < nCl; iCl++) { // clusters are stored from outer to inner layers
833 const auto& cls = mITSClustersArray[mITSTrackClusIdx[clEntry + iCl]];
834 int chip = cls.getSensorID();
835 float chipX, chipAlpha;
836 geom->getSensorXAlphaRefPlane(cls.getSensorID(), chipX, chipAlpha);
837 if (!trkWorkITS.rotate(chipAlpha) || !propagator->PropagateToXBxByBz(trkWorkITS, chipX, mParams->maxSnp, mParams->maxStep, mMatCorr)) {
838 LOGP(debug, "Failed final propagation to ITS X={} alpha={}", chipX, chipAlpha);
839 stopPropagation = true;
840 break;
841 }
842 float tgPhi = trkWorkITS.getSnp() / std::sqrt((1.f - trkWorkITS.getSnp()) * (1.f + trkWorkITS.getSnp()));
843 auto dy = cls.getY() - trkWorkITS.getY();
844 auto dz = cls.getZ() - trkWorkITS.getZ();
845 if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWorkITS.getY()) < param::MaxY) && (std::abs(trkWorkITS.getZ()) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) {
846 mClRes.emplace_back(dy, dz, tgPhi, trkWorkITS.getY(), trkWorkITS.getZ(), 180 + geom->getLayer(cls.getSensorID()), -1, cls.getSensorID());
847 mDetInfoRes.emplace_back(); // empty placeholder
848 trackData.nExtDetResid++;
849 }
850 }
851 if (!stopPropagation) { // add residual to PV
852 const auto& pv = mRecoCont->getPrimaryVertices()[mTrackPVID[iSeed]];
853 o2::math_utils::Point3D<float> vtx{pv.getX(), pv.getY(), pv.getZ()};
854 if (!propagator->propagateToDCA(vtx, trkWorkITS, mBz, mParams->maxStep, mMatCorr)) {
855 LOGP(debug, "Failed propagation to DCA to PV ({} {} {}), {}", pv.getX(), pv.getY(), pv.getZ(), trkWorkITS.asString());
856 stopPropagation = true;
857 break;
858 }
859 // rotate PV to the track frame
860 float sn, cs, alpha = trkWorkITS.getAlpha();
861 math_utils::detail::bringToPMPi(alpha);
862 math_utils::detail::sincos<float>(alpha, sn, cs);
863 float xv = vtx.X() * cs + vtx.Y() * sn, yv = -vtx.X() * sn + vtx.Y() * cs, zv = vtx.Z();
864 auto dy = yv - trkWorkITS.getY();
865 auto dz = zv - trkWorkITS.getZ();
866 if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWorkITS.getY()) < param::MaxY) && (std::abs(trkWorkITS.getZ()) < param::MaxZ) && std::abs(xv) < param::MaxVtxX) {
867 short compXV = static_cast<short>(xv * 0x7fff / param::MaxVtxX);
868 mClRes.emplace_back(dy, dz, alpha / TMath::Pi(), trkWorkITS.getY(), trkWorkITS.getZ(), 190, -1, compXV);
869 if (!gidTable[GTrackID::ITSTPC].isIndexSet()) {
870 LOGP(fatal, "ITS-TPC seed index is not set for TOF track");
871 }
872 float tdif = pv.getTimeStamp().getTimeStamp() - mRecoCont->getTPCITSTrack(gidTable[GTrackID::ITSTPC]).getTimeMUS().getTimeStamp();
873 mDetInfoRes.emplace_back().setPV(tdif); // time in \mus wrt seeding ITS-TPC track
874 trackData.nExtDetResid++;
875 }
876 }
877 break;
878 }
879 }
880
881 mGIDsSuccess.push_back(mGIDs[iSeed]);
882 mTrackDataCompact.emplace_back(trackData.clIdx.getFirstEntry(), trackData.multStack, nClValidated, mGIDs[iSeed].getSource(), trackData.nExtDetResid, trackData.filterFlag);
883 mTrackData.push_back(std::move(trackData));
884 stored = true;
885 if (mDumpTrackPoints) {
886 (*trackDataExtended).clIdx.setEntries(nClValidated);
887 (*trackDataExtended).nExtDetResid = trackData.nExtDetResid;
888 (*trackDataExtended).filterFlag = trackData.filterFlag;
889 mTrackDataExtended.push_back(std::move(*trackDataExtended));
890 }
891 }
892 if (mParams->writeValidationData && trackData.filterFlag >= 0 && mDBGOut) {
893 (*mDBGOut) << "valdata" << "params=" << mTrackValidation << "trackData=" << (stored ? mTrackData.back() : trackData) << "\n";
894 }
895}
896
898 std::array<float, 2>* trkltTRDYZ, std::array<float, 3>* trkltTRDCov, TrackData* trkData,
900{
901 // return chamber ID (0:539) in case of successful processing, -1 if there is no TRD tracklet at given layer, -2 if processing failed
902 int trkltIdx = trkTRD.getTrackletIndex(iLayer);
903 if (trkltIdx < 0) {
904 return -1; // no TRD tracklet in this layer
905 }
906 const auto& trdSP = mRecoCont->getTRDCalibratedTracklets()[trkltIdx];
907 const auto& trdTrklt = mRecoCont->getTRDTracklets()[trkltIdx];
908 auto trkltDet = trdTrklt.getDetector();
909 auto trkltSec = trkltDet / (o2::trd::constants::NLAYER * o2::trd::constants::NSTACK);
910 if (trkltSec != o2::math_utils::angle2Sector(trkWork.getAlpha())) {
911 if (!trkWork.rotate(o2::math_utils::sector2Angle(trkltSec))) {
912 LOG(debug) << "Track could not be rotated in TRD tracklet coordinate system in layer " << iLayer;
913 return -2;
914 }
915 }
916 if (!o2::base::Propagator::Instance()->PropagateToXBxByBz(trkWork, trdSP.getX(), mParams->maxSnp, mParams->maxStep, mMatCorr)) {
917 LOG(debug) << "Failed propagation to TRD layer " << iLayer;
918 return -2;
919 }
920 if (trkltTRDYZ) {
921 const auto* pad = mGeoTRD->getPadPlane(trkltDet);
922 float tilt = tan(TMath::DegToRad() * pad->getTiltingAngle()); // tilt is signed! and returned in degrees
923 float tiltCorrUp = tilt * (trdSP.getZ() - trkWork.getZ());
924 float zPosCorrUp = trdSP.getZ() + mRecoParam.getZCorrCoeffNRC() * trkWork.getTgl(); // maybe Z can be corrected on avarage already by the tracklet transformer?
925 float padLength = pad->getRowSize(trdTrklt.getPadRow());
926 if (!((trkWork.getSigmaZ2() < (padLength * padLength / 12.f)) && (std::abs(trdSP.getZ() - trkWork.getZ()) < padLength))) {
927 tiltCorrUp = 0.f;
928 }
929 (*trkltTRDYZ)[0] = trdSP.getY() - tiltCorrUp;
930 (*trkltTRDYZ)[1] = zPosCorrUp;
931 if (trkltTRDCov) {
932 mRecoParam.recalcTrkltCov(tilt, trkWork.getSnp(), pad->getRowSize(trdTrklt.getPadRow()), *trkltTRDCov);
933 }
934 }
935 if (trkData) {
936 auto slope = trdSP.getDy();
937 if (std::abs(slope) < param::MaxTRDSlope) {
938 trkData->TRDTrkltSlope[iLayer] = slope * 0x7fff / param::MaxTRDSlope;
939 }
940 }
941 if (trk64) {
942 *trk64 = trdTrklt;
943 }
944 if (trkCalib) {
945 *trkCalib = trdSP;
946 }
947 return trkltDet;
948}
949
951{
952 // extrapolate ITS-only track through TPC and store residuals to TPC clusters in the output vectors
953 LOGP(debug, "Starting track extrapolation for GID {}", mGIDs[iSeed].asString());
954 const auto& gidTable = mGIDtables[iSeed];
955 TrackData trackData;
956 o2::trd::Tracklet64 trkl64;
958 std::unique_ptr<TrackDataExtended> trackDataExtended;
959 std::vector<TPCClusterResiduals> clusterResiduals;
960 trackData.clIdx.setFirstEntry(mClRes.size());
961 const auto& trkITS = mRecoCont->getITSTrack(gidTable[GTrackID::ITS]);
962 const auto& trkTPC = mRecoCont->getTPCTrack(gidTable[GTrackID::TPC]);
963 if (mDumpTrackPoints) {
964 trackDataExtended = std::make_unique<TrackDataExtended>();
965 (*trackDataExtended).gid = mGIDs[iSeed];
966 (*trackDataExtended).clIdx.setFirstEntry(mClRes.size());
967 (*trackDataExtended).trkITS = trkITS;
968 (*trackDataExtended).trkTPC = trkTPC;
969 auto nCl = trkITS.getNumberOfClusters();
970 auto clEntry = trkITS.getFirstClusterEntry();
971 for (int iCl = nCl - 1; iCl >= 0; iCl--) { // clusters are stored from outer to inner layers
972 const auto& clsITS = mITSClustersArray[mITSTrackClusIdx[clEntry + iCl]];
973 (*trackDataExtended).clsITS.push_back(clsITS);
974 }
975 }
976 if (mParams->refitITS && !refITSTrack(gidTable[GTrackID::ITS], iSeed)) {
977 mNRejRefit++;
978 return;
979 }
980 trackData.gid = mGIDs[iSeed];
981 trackData.par = mSeeds[iSeed];
982
983 auto trkWork = mSeeds[iSeed];
984 float clusterTimeBinOffset = mTrackTimes[iSeed] / mTPCTimeBinMUS;
985 auto propagator = o2::base::Propagator::Instance();
986 unsigned short rowPrev = 0; // used to calculate dRow of two consecutive cluster residuals
987 unsigned short nMeasurements = 0;
988 uint8_t clRowPrev = constants::MAXGLOBALPADROW; // used to identify and skip split clusters on the same pad row
989 std::array<std::pair<uint16_t, uint16_t>, constants::MAXGLOBALPADROW> mCacheDEDX{};
990 std::array<short, constants::MAXGLOBALPADROW> multBins{};
991 for (int iCl = trkTPC.getNClusterReferences(); iCl--;) {
992 uint8_t sector, row;
993 uint32_t clusterIndexInRow;
994 trkTPC.getClusterReference(mTPCTrackClusIdx, iCl, sector, row, clusterIndexInRow);
995 unsigned int absoluteIndex = mTPCClusterIdxStruct->clusterOffset[sector][row] + clusterIndexInRow;
996 const auto& cl = mTPCClusterIdxStruct->clustersLinear[absoluteIndex];
997 if (clRowPrev == row) {
998 // if there are split clusters we only take the first one on the pad row
999 continue;
1000 } else if (clRowPrev < constants::MAXGLOBALPADROW && clRowPrev > row) {
1001 // we seem to be looping, abort this track
1002 LOGP(debug, "TPC track with pT={} GeV and {} clusters has cluster {} on row {} while the previous cluster was on row {}",
1003 mSeeds[iSeed].getPt(), trkTPC.getNClusterReferences(), iCl, row, clRowPrev);
1004 mNRejLoop++;
1005 return;
1006 } else {
1007 // this is the first cluster we see on this pad row
1008 clRowPrev = row;
1009 }
1010 float x = 0, y = 0, z = 0;
1011 mFastTransform->TransformIdeal(sector, row, cl.getPad(), cl.getTime(), x, y, z, clusterTimeBinOffset);
1012 if (!trkWork.rotate(o2::math_utils::sector2Angle(sector))) {
1013 mNRejProp++;
1014 return;
1015 }
1016 if (!propagator->PropagateToXBxByBz(trkWork, x, mParams->maxSnp, mParams->maxStep, mMatCorr)) {
1017 mNRejProp++;
1018 return;
1019 }
1020
1021 const auto dY = y - trkWork.getY();
1022 const auto dZ = z - trkWork.getZ();
1023 const auto ty = trkWork.getY();
1024 const auto tz = trkWork.getZ();
1025 const auto snp = trkWork.getSnp();
1026 const auto sec = sector;
1027 unsigned char flags = cl.getFlags();
1028 if (mTPCShClassMap[absoluteIndex] & o2::gpu::GPUTPCGMMergedTrackHit::flagShared) {
1030 }
1031 clusterResiduals.emplace_back(dY, dZ, ty, tz, snp, sec, row - rowPrev, flags);
1032 mCacheDEDX[row].first = cl.getQtot();
1033 mCacheDEDX[row].second = cl.getQmax();
1034 rowPrev = row;
1035 int imb = int(cl.getTime() * mNTPCOccBinLengthInv);
1036 if (imb < mTPCParam->occupancyMapSize) {
1037 multBins[row] = 1 + std::max(0, imb);
1038 }
1039 ++nMeasurements;
1040 }
1041
1042 mTrackValidation.clear(); // for refitted track parameters and flagging rejected clusters
1043 if (clusterResiduals.size() > constants::MAXGLOBALPADROW) {
1044 LOGP(warn, "Extrapolated ITS-TPC track and found more residuals than possible ({})", clusterResiduals.size());
1045 mNRejLoop++;
1046 return;
1047 }
1048
1049 trackData.chi2TPC = trkTPC.getChi2();
1050 trackData.chi2ITS = trkITS.getChi2();
1051 trackData.nClsTPC = trkTPC.getNClusterReferences();
1052 trackData.nClsITS = trkITS.getNumberOfClusters();
1053 trackData.clIdx.setEntries(nMeasurements);
1054 trackData.dEdxTPC = trkTPC.getdEdx().dEdxTotTPC;
1055 if (mDumpTrackPoints) {
1056 (*trackDataExtended).trkOuter = trkWork;
1057 }
1058
1059 bool stored = false;
1060 trackData.filterFlag = mParams->skipOutlierFiltering ? -1 : validateTrack(trackData, mTrackValidation, clusterResiduals, false);
1061 if (trackData.filterFlag <= 0 || mParams->writeUnfiltered) {
1062 int nClValidated = 0, iRow = 0;
1063 unsigned int iCl = 0;
1064 for (iCl = 0; iCl < clusterResiduals.size(); ++iCl) {
1065 iRow += clusterResiduals[iCl].dRow;
1066 if (iRow >= param::NPadRows) { // RS why do we need this?
1067 continue;
1068 }
1069 const auto rej = trackData.filterFlag < 0 ? false : mTrackValidation.points[iCl].flagRej;
1070 if (rej && !mParams->keepRejectedResiduals) { // skip masked cluster residual
1071 continue;
1072 }
1073 const float tgPhi = clusterResiduals[iCl].snp / std::sqrt((1.f - clusterResiduals[iCl].snp) * (1.f + clusterResiduals[iCl].snp));
1074 const auto dy = clusterResiduals[iCl].dy;
1075 const auto dz = clusterResiduals[iCl].dz;
1076 const auto y = clusterResiduals[iCl].y;
1077 const auto z = clusterResiduals[iCl].z;
1078 const short flags = clusterResiduals[iCl].flags;
1079 if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(y) < param::MaxY) && (std::abs(z) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) {
1080 mClRes.emplace_back(dy, dz, tgPhi, y, z, iRow, clusterResiduals[iCl].sec, flags, rej);
1081 mDetInfoRes.emplace_back().setTPC(mCacheDEDX[iRow].first, mCacheDEDX[iRow].second); // qtot, qmax
1082 ++nClValidated;
1083 } else {
1084 ++mRejectedResiduals;
1085 }
1086 }
1087 trackData.clIdx.setEntries(nClValidated);
1088
1089 // store multiplicity info
1090 for (int ist = 0; ist < NSTACKS; ist++) {
1091 int mltBinMin = 0x7ffff, mltBinMax = -1, prevBin = -1;
1092 for (int ir = STACKROWS[ist]; ir < STACKROWS[ist + 1]; ir++) {
1093 if (multBins[ir] != prevBin && multBins[ir] > 0) { // there is a cluster
1094 prevBin = multBins[ir];
1095 if (multBins[ir] > mltBinMax) {
1096 mltBinMax = multBins[ir];
1097 }
1098 if (multBins[ir] < mltBinMin) {
1099 mltBinMin = multBins[ir];
1100 }
1101 }
1102 }
1103 if (--mltBinMin >= 0) { // we were offsetting bin IDs by 1!
1104 float avMlt = 0;
1105 for (int ib = mltBinMin; ib < mltBinMax; ib++) {
1106 avMlt += mTPCParam->occupancyMap[ib];
1107 }
1108 avMlt /= (mltBinMax - mltBinMin);
1109 trackData.setMultStack(avMlt, ist);
1110 }
1111 }
1112
1113 bool stopPropagation = !mExtDetResid;
1114 if (!stopPropagation) {
1115 // do we have TRD residuals to add?
1116 int iSeedFull = mParentID[iSeed] == -1 ? iSeed : mParentID[iSeed];
1117 auto gidFull = mGIDs[iSeedFull];
1118 const auto& gidTableFull = mGIDtables[iSeedFull];
1119 if (gidTableFull[GTrackID::TRD].isIndexSet()) {
1120 const auto& trkTRD = mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTableFull[GTrackID::ITSTPCTRD]);
1121 trackData.nTrkltsTRD = trkTRD.getNtracklets();
1122 trackData.chi2TRD = trkTRD.getChi2();
1123 for (int iLayer = 0; iLayer < o2::trd::constants::NLAYER; iLayer++) {
1124 std::array<float, 2> trkltTRDYZ{};
1125 int res = processTRDLayer(trkTRD, iLayer, trkWork, &trkltTRDYZ, nullptr, &trackData, &trkl64, &trklCalib);
1126 if (res == -1) { // no traklet on this layer
1127 continue;
1128 }
1129 if (res < -1) { // failed to reach this layer
1130 stopPropagation = true;
1131 break;
1132 }
1133
1134 float tgPhi = trkWork.getSnp() / std::sqrt((1.f - trkWork.getSnp()) * (1.f + trkWork.getSnp()));
1135 auto dy = trkltTRDYZ[0] - trkWork.getY();
1136 auto dz = trkltTRDYZ[1] - trkWork.getZ();
1137 const auto sec = clusterResiduals[iCl].sec;
1138 if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWork.getY()) < param::MaxY) && (std::abs(trkWork.getZ()) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) {
1139 mClRes.emplace_back(dy, dz, tgPhi, trkWork.getY(), trkWork.getZ(), 160 + iLayer, o2::math_utils::angle2Sector(trkWork.getAlpha()), (short)res);
1140 mDetInfoRes.emplace_back().setTRD(trkl64.getQ0(), trkl64.getQ1(), trkl64.getQ2(), trklCalib.getDy()); // q0,q1,q2,slope
1141 trackData.nExtDetResid++;
1142 }
1143 }
1144 }
1145
1146 // do we have TOF residual to add?
1147 trackData.clAvailTOF = 0;
1148 while (gidTableFull[GTrackID::TOF].isIndexSet() && !stopPropagation) {
1149 const auto& tofMatch = mRecoCont->getTOFMatch(gidFull);
1150 ULong64_t bclongtof = (tofMatch.getSignal() - 10000) * o2::tof::Geo::BC_TIME_INPS_INV;
1151 double t0forTOF = tofMatch.getFT0Best(); // setting t0 for TOF
1152 float t0forTOFwithinBC = t0forTOF - bclongtof * o2::tof::Geo::BC_TIME_INPS;
1153 float t0forTOFres = tofMatch.getFT0BestRes();
1154 trackData.deltaTOF = tofMatch.getSignal() - t0forTOF - tofMatch.getLTIntegralOut().getTOF(trkTPC.getPID().getID());
1155 trackData.clAvailTOF = uint16_t(t0forTOFres);
1156 const auto& clTOF = mRecoCont->getTOFClusters()[gidTableFull[GTrackID::TOF]];
1157 const float clTOFAlpha = o2::math_utils::sector2Angle(clTOF.getCount());
1158 float clTOFxyz[3] = {clTOF.getX(), clTOF.getY(), clTOF.getZ()};
1159 if (!clTOF.isInNominalSector()) {
1160 o2::tof::Geo::alignedToNominalSector(clTOFxyz, clTOF.getCount()); // go from the aligned to nominal sector frame
1161 }
1162 if (trkWork.getAlpha() != clTOFAlpha && !trkWork.rotate(clTOFAlpha)) {
1163 LOG(debug) << "Failed to rotate into TOF cluster sector frame";
1164 stopPropagation = true;
1165 break;
1166 }
1167 if (!propagator->PropagateToXBxByBz(trkWork, clTOFxyz[0], mParams->maxSnp, mParams->maxStep, mMatCorr)) {
1168 LOG(debug) << "Failed final propagation to TOF radius";
1169 break;
1170 }
1171
1172 float tgPhi = trkWork.getSnp() / std::sqrt((1.f - trkWork.getSnp()) * (1.f + trkWork.getSnp()));
1173 auto dy = clTOFxyz[1] - trkWork.getY();
1174 auto dz = clTOFxyz[2] - trkWork.getZ();
1175 if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWork.getY()) < param::MaxY) && (std::abs(trkWork.getZ()) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) {
1176 mClRes.emplace_back(dy, dz, tgPhi, trkWork.getY(), trkWork.getZ(), 170, clTOF.getCount(), clTOF.getPadInSector());
1177 // get seeding track time
1178 if (!gidTableFull[GTrackID::ITSTPC].isIndexSet()) {
1179 LOGP(fatal, "ITS-TPC seed index is not set for TOF track");
1180 }
1181
1182 float tdif = static_cast<float>(clTOF.getTime() - t0forTOF); // time in \mus wrt interaction time0
1183 mDetInfoRes.emplace_back().setTOF(tdif * 1e-6); // time in \mus wrt seeding ITS-TPC track
1184 trackData.nExtDetResid++;
1185 }
1186 break;
1187 }
1188
1189 // add ITS residuals
1190 while (!stopPropagation) {
1191 o2::track::TrackPar trkWorkITS{trackData.par}; // this is ITS outer param
1192 auto nCl = trkITS.getNumberOfClusters();
1193 auto clEntry = trkITS.getFirstClusterEntry();
1194 auto geom = o2::its::GeometryTGeo::Instance();
1195 for (int iCl = 0; iCl < nCl; iCl++) { // clusters are stored from outer to inner layers
1196 const auto& cls = mITSClustersArray[mITSTrackClusIdx[clEntry + iCl]];
1197 int chip = cls.getSensorID();
1198 float chipX, chipAlpha;
1199 geom->getSensorXAlphaRefPlane(cls.getSensorID(), chipX, chipAlpha);
1200 if (!trkWorkITS.rotate(chipAlpha) || !propagator->propagateToX(trkWorkITS, chipX, mBz, mParams->maxSnp, mParams->maxStep, mMatCorr)) {
1201 LOGP(debug, "Failed final propagation to ITS X={} alpha={}", chipX, chipAlpha);
1202 stopPropagation = true;
1203 break;
1204 }
1205 float tgPhi = trkWorkITS.getSnp() / std::sqrt((1.f - trkWorkITS.getSnp()) * (1.f + trkWorkITS.getSnp()));
1206 auto dy = cls.getY() - trkWorkITS.getY();
1207 auto dz = cls.getZ() - trkWorkITS.getZ();
1208 if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWorkITS.getY()) < param::MaxY) && (std::abs(trkWorkITS.getZ()) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) {
1209 mClRes.emplace_back(dy, dz, tgPhi, trkWorkITS.getY(), trkWorkITS.getZ(), 180 + geom->getLayer(cls.getSensorID()), -1, cls.getSensorID());
1210 mDetInfoRes.emplace_back(); // empty placeholder
1211 trackData.nExtDetResid++;
1212 }
1213 }
1214 if (!stopPropagation) { // add residual to PV
1215 const auto& pv = mRecoCont->getPrimaryVertices()[mTrackPVID[iSeed]];
1216 o2::math_utils::Point3D<float> vtx{pv.getX(), pv.getY(), pv.getZ()};
1217 if (!propagator->propagateToDCA(vtx, trkWorkITS, mBz, mParams->maxStep, mMatCorr)) {
1218 LOGP(debug, "Failed propagation to DCA to PV ({} {} {}), {}", pv.getX(), pv.getY(), pv.getZ(), trkWorkITS.asString());
1219 stopPropagation = true;
1220 break;
1221 }
1222 // rotate PV to the track frame
1223 float sn, cs, alpha = trkWorkITS.getAlpha();
1224 math_utils::detail::bringToPMPi(alpha);
1225 math_utils::detail::sincos<float>(alpha, sn, cs);
1226 float xv = vtx.X() * cs + vtx.Y() * sn, yv = -vtx.X() * sn + vtx.Y() * cs, zv = vtx.Z();
1227 auto dy = yv - trkWorkITS.getY();
1228 auto dz = zv - trkWorkITS.getZ();
1229 if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWorkITS.getY()) < param::MaxY) && (std::abs(trkWorkITS.getZ()) < param::MaxZ) && std::abs(xv) < param::MaxVtxX) {
1230 short compXV = static_cast<short>(xv * 0x7fff / param::MaxVtxX);
1231 mClRes.emplace_back(dy, dz, alpha / TMath::Pi(), trkWorkITS.getY(), trkWorkITS.getZ(), 190, -1, compXV);
1232 if (!gidTableFull[GTrackID::ITSTPC].isIndexSet()) {
1233 LOGP(fatal, "ITS-TPC seed index is not set for TOF track");
1234 }
1235 float tdif = pv.getTimeStamp().getTimeStamp() - mRecoCont->getTPCITSTrack(gidTableFull[GTrackID::ITSTPC]).getTimeMUS().getTimeStamp();
1236 mDetInfoRes.emplace_back().setPV(tdif); // time in \mus wrt seeding ITS-TPC track
1237 trackData.nExtDetResid++;
1238 }
1239 }
1240 break;
1241 }
1242 }
1243 mTrackData.push_back(std::move(trackData));
1244 stored = true;
1245 mGIDsSuccess.push_back(mGIDs[iSeed]);
1246 mTrackDataCompact.emplace_back(trackData.clIdx.getFirstEntry(), trackData.multStack, nClValidated, mGIDs[iSeed].getSource(), trackData.nExtDetResid, trackData.filterFlag);
1247 if (mDumpTrackPoints) {
1248 (*trackDataExtended).clIdx.setEntries(nClValidated);
1249 (*trackDataExtended).nExtDetResid = trackData.nExtDetResid;
1250 (*trackDataExtended).filterFlag = trackData.filterFlag;
1251 mTrackDataExtended.push_back(std::move(*trackDataExtended));
1252 }
1253 }
1254 if (mParams->writeValidationData && trackData.filterFlag >= 0 && mDBGOut) {
1255 (*mDBGOut) << "valdata" << "params=" << mTrackValidation << "trackData=" << (stored ? mTrackData.back() : trackData) << "\n";
1256 }
1257}
1258
1259int8_t TrackInterpolation::validateTrack(const TrackData& trk, TrackValidationData& params, const std::vector<TPCClusterResiduals>& clsRes, bool interpol)
1260{
1261 int8_t status = 0;
1262 while (true) {
1263 if (clsRes.size() < mParams->minNCl) {
1264 // no enough clusters for this track to be considered
1265 LOG(debug) << "Skipping track with too few clusters: " << clsRes.size();
1266 status |= 0x1;
1267 if (!mParams->keepRejectedResiduals) {
1268 break; // we don't keep de-validated tracks, no need to check further
1269 }
1270 }
1271
1272 bool resHelix = compareToHelix(trk, params, clsRes);
1273 if (!resHelix && interpol) {
1274 LOG(debug) << "Skipping track too far from helix approximation";
1275 status |= 0x1 << 1;
1276 if (!mParams->keepRejectedResiduals) {
1277 break; // we don't keep de-validated tracks, no need to check further
1278 }
1279 }
1280 if (interpol && (std::abs(mBz) > 0.01 && std::abs(params.qpt) > mParams->maxQ2Pt)) {
1281 LOG(debug) << "Skipping track with too high q/pT: " << params.qpt;
1282 status |= 0x1 << 2;
1283 if (!mParams->keepRejectedResiduals) {
1284 break; // we don't keep de-validated tracks, no need to check further
1285 }
1286 }
1287 if (!outlierFiltering(trk, params, clsRes)) {
1288 status |= 0x1 << 3;
1289 if (!mParams->keepRejectedResiduals) {
1290 break; // we don't keep de-validated tracks, no need to check further
1291 }
1292 }
1293 break;
1294 }
1295 return status & 0x7f;
1296}
1297
1298bool TrackInterpolation::compareToHelix(const TrackData& trk, TrackValidationData& params, const std::vector<TPCClusterResiduals>& clsRes)
1299{
1300 float curvature = std::abs(trk.par.getQ2Pt() * mBz * o2::constants::physics::LightSpeedCm2S * 1e-14f);
1301 int secFirst = clsRes[0].sec;
1302 float phiSect = (secFirst + .5f) * o2::constants::math::SectorSpanRad;
1303 float snPhi = sin(phiSect);
1304 float csPhi = cos(phiSect);
1305
1306 int iRow = 0;
1307 int nCl = clsRes.size();
1308 for (unsigned int iP = 0; iP < nCl; ++iP) {
1309 auto& point = params.points.emplace_back();
1310
1311 iRow += clsRes[iP].dRow;
1312 point.yTrk = clsRes[iP].y;
1313 point.sec = clsRes[iP].sec;
1314 if (clsRes[iP].sec != secFirst) {
1315 float phiSectCurrent = (clsRes[iP].sec + .5f) * o2::constants::math::SectorSpanRad;
1316 float cs = cos(phiSectCurrent - phiSect);
1317 float sn = sin(phiSectCurrent - phiSect);
1318 point.xLab = param::RowX[iRow] * cs - point.yTrk * sn;
1319 point.yLab = point.yTrk * cs + param::RowX[iRow] * sn;
1320 } else {
1321 point.xLab = param::RowX[iRow];
1322 point.yLab = point.yTrk;
1323 }
1324 // this is needed only later, but we retrieve it already now to save another loop
1325 point.zTrk = clsRes[iP].z;
1326 point.xTrk = param::RowX[iRow];
1327 point.dy = clsRes[iP].dy;
1328 point.dz = clsRes[iP].dz;
1329 // done retrieving values for later
1330 if (iP > 0) {
1331 float dx = point.xLab - params.points[iP - 1].xLab;
1332 float dy = point.yLab - params.points[iP - 1].yLab;
1333 float ds2 = dx * dx + dy * dy;
1334 float ds = sqrt(ds2); // circular path (linear approximation)
1335 // if the curvature of the track or the (approximated) chord length is too large the more exact formula is used:
1336 // chord length = 2r * asin(ds/(2r))
1337 // using the first two terms of the tailer expansion for asin(x) ~ x + x^3 / 6
1338 if (ds * curvature > 0.05) {
1339 ds *= (1.f + ds2 * curvature * curvature / 24.f);
1340 }
1341 point.sPath = params.points[iP - 1].sPath + ds;
1342 } else {
1343 point.sPath = 0;
1344 }
1345 }
1346 if (std::abs(mBz) < 0.01) {
1347 // for B=0 we don't need to try a circular fit...
1348 return true;
1349 }
1351 // determine curvature
1352 float phiI = TMath::ATan2(params.points.front().yLab, params.points.front().xLab);
1353 float phiF = TMath::ATan2(params.points.back().yLab, params.points.back().xLab);
1354 if (phiI < 0) {
1356 }
1357 if (phiF < 0) {
1359 }
1360 float dPhi = phiF - phiI;
1361 float curvSign = -1.f;
1362 if (dPhi > 0) {
1363 if (dPhi < o2::constants::math::PI) {
1364 curvSign = 1.f;
1365 }
1366 } else if (dPhi < -o2::constants::math::PI) {
1367 curvSign = 1.f;
1368 }
1369 params.qpt = std::copysign(1.f / (params.r * mBz * o2::constants::physics::LightSpeedCm2S * 1e-14f), curvSign);
1370
1372
1373 // max deviations in both directions from helix fit in y and z
1374 float hMinY = 1e9f;
1375 float hMaxY = -1e9f;
1376 float hMinZ = 1e9f;
1377 float hMaxZ = -1e9f;
1378 // extract residuals in Z and fill track slopes in sector frame
1379 int secCurr = -1;
1380 iRow = 0;
1381 float xcSec = 0;
1382 for (unsigned int iCl = 0; iCl < nCl; ++iCl) {
1383 iRow += clsRes[iCl].dRow;
1384 auto& pnt = params.points[iCl];
1385 pnt.residHelixZ = pnt.zTrk - (params.zOffs + pnt.sPath * params.tgl);
1386 if (pnt.residHelixZ < hMinZ) {
1387 hMinZ = pnt.residHelixZ;
1388 }
1389 if (pnt.residHelixZ > hMaxZ) {
1390 hMaxZ = pnt.residHelixZ;
1391 }
1392 if (pnt.residHelixY < hMinY) {
1393 hMinY = pnt.residHelixY;
1394 }
1395 if (pnt.residHelixY > hMaxY) {
1396 hMaxY = pnt.residHelixY;
1397 }
1398 int sec = clsRes[iCl].sec;
1399 if (sec != secCurr) {
1400 secCurr = sec;
1401 phiSect = (.5f + sec) * o2::constants::math::SectorSpanRad;
1402 snPhi = sin(phiSect);
1403 csPhi = cos(phiSect);
1404 xcSec = params.xcLab * csPhi + params.ycLab * snPhi; // recalculate circle center in the new sector frame
1405 }
1406 float cstalp = (param::RowX[iRow] - xcSec) / params.r;
1407 if (std::abs(cstalp) > 1.f - sFloatEps) {
1408 // track cannot reach this pad row
1409 cstalp = std::copysign(1.f - sFloatEps, cstalp);
1410 }
1411 pnt.tglArr = cstalp / sqrt((1 - cstalp) * (1 + cstalp)); // 1 / tan(acos(cstalp)) = cstalp / sqrt(1 - cstalp^2)
1412
1413 // In B+ the slope of q- should increase with x. Just look on q * B
1414 if (params.qpt * mBz > 0) {
1415 pnt.tglArr = -pnt.tglArr;
1416 }
1417 }
1418 // LOGF(info, "CompareToHelix: hMaxY(%f), hMinY(%f), hMaxZ(%f), hMinZ(%f). Max deviation allowed: y(%.2f), z(%.2f)", hMaxY, hMinY, hMaxZ, hMinZ, mParams->maxDevHelixY, mParams->maxDevHelixZ);
1419 // LOGF(info, "New pt/Q (%f), old pt/Q (%f)", 1./params.qpt, 1./trk.qPt);
1420 return std::abs(hMaxY - hMinY) < mParams->maxDevHelixY && std::abs(hMaxZ - hMinZ) < mParams->maxDevHelixZ;
1421}
1422
1423bool TrackInterpolation::outlierFiltering(const TrackData& trk, TrackValidationData& params, const std::vector<TPCClusterResiduals>& clsRes)
1424{
1425 if (clsRes.size() < mParams->nMALong) {
1426 LOG(debug) << "Skipping track with too few clusters for long moving average: " << clsRes.size();
1427 return false;
1428 }
1429 float rmsLong = checkResiduals(trk, params, clsRes);
1430 if (static_cast<float>(params.nRej) / clsRes.size() > mParams->maxRejFrac) {
1431 LOGP(debug, "Skipping track with too many clusters rejected: {} out of {}", params.nRej, clsRes.size());
1432 return false;
1433 }
1434 if (rmsLong > mParams->maxRMSLong) {
1435 LOG(debug) << "Skipping track with too large RMS: " << rmsLong;
1436 return false;
1437 }
1438 return true;
1439}
1440
1441float TrackInterpolation::checkResiduals(const TrackData& trk, TrackValidationData& params, const std::vector<TPCClusterResiduals>& clsRes)
1442{
1443 float rmsLong = 0.f;
1444
1445 int nCl = clsRes.size();
1446 int iClFirst = 0;
1447 int iClLast = nCl - 1;
1448 int secStart = clsRes[0].sec;
1449
1450 auto rejectAll = [&params]() {
1451 for (auto& pnt : params.points) {
1452 pnt.flagRej = true;
1453 }
1454 params.nRej = params.points.size();
1455 };
1456
1457 // arrays with differences / abs(differences) of points to their neighbourhood, initialized to zero
1458 std::array<float, param::NPadRows> absDevY{};
1459 std::array<float, param::NPadRows> absDevZ{};
1460
1461 for (unsigned int iCl = 0; iCl < nCl; ++iCl) {
1462 if (iCl < iClLast && clsRes[iCl].sec == secStart) {
1463 continue;
1464 }
1465 // sector changed or last cluster reached
1466 // now run estimators for all points in the same sector
1467 int nClSec = iCl - iClFirst;
1468 if (iCl == iClLast) {
1469 ++nClSec;
1470 }
1471 diffToLocLine(params, iClFirst, nClSec);
1472 iClFirst = iCl;
1473 secStart = clsRes[iCl].sec;
1474 }
1475 // store abs deviations
1476 int nAccY = 0;
1477 int nAccZ = 0;
1478 for (int iCl = nCl; iCl--;) {
1479 const auto pnt = params.points[iCl];
1480 if (std::abs(pnt.diffYSmooth) > param::sEps) {
1481 absDevY[nAccY++] = std::abs(pnt.diffYSmooth);
1482 }
1483 if (std::abs(pnt.diffZSmooth) > param::sEps) {
1484 absDevZ[nAccZ++] = std::abs(pnt.diffZSmooth);
1485 }
1486 }
1487 if (nAccY < mParams->minNumberOfAcceptedResiduals || nAccZ < mParams->minNumberOfAcceptedResiduals) {
1488 // mask all clusters
1489 LOGP(debug, "Accepted {} clusters for dY {} clusters for dZ, but required at least {} for both", nAccY, nAccZ, mParams->minNumberOfAcceptedResiduals);
1490 rejectAll();
1491 return 0.f;
1492 }
1493 // estimate rms on 90% of the smallest deviations
1494 int nKeepY = static_cast<int>(.9 * nAccY);
1495 int nKeepZ = static_cast<int>(.9 * nAccZ);
1496 std::nth_element(absDevY.begin(), absDevY.begin() + nKeepY, absDevY.begin() + nAccY);
1497 std::nth_element(absDevZ.begin(), absDevZ.begin() + nKeepZ, absDevZ.begin() + nAccZ);
1498 float rmsYkeep = 0.f;
1499 float rmsZkeep = 0.f;
1500 for (int i = nKeepY; i--;) {
1501 rmsYkeep += absDevY[i] * absDevY[i];
1502 }
1503 for (int i = nKeepZ; i--;) {
1504 rmsZkeep += absDevZ[i] * absDevZ[i];
1505 }
1506 rmsYkeep = std::sqrt(rmsYkeep / nKeepY);
1507 rmsZkeep = std::sqrt(rmsZkeep / nKeepZ);
1508 if (rmsYkeep < param::sEps || rmsZkeep < param::sEps) {
1509 LOG(warning) << "Too small RMS: " << rmsYkeep << "(y), " << rmsZkeep << "(z).";
1510 rejectAll();
1511 return 0.f;
1512 }
1513 float rmsYkeepI = 1.f / rmsYkeep;
1514 float rmsZkeepI = 1.f / rmsZkeep;
1515 int nAcc = 0;
1516 std::array<float, param::NPadRows> yAcc;
1517 std::array<float, param::NPadRows> yDiffLong;
1518 for (int iCl = 0; iCl < nCl; ++iCl) {
1519 auto& pnt = params.points[iCl];
1520 auto yDiffScl = pnt.diffYSmooth * rmsYkeepI;
1521 auto zDiffScl = pnt.diffZSmooth * rmsZkeepI;
1522 if (yDiffScl * yDiffScl + zDiffScl * zDiffScl > mParams->maxStdDevMA) {
1523 pnt.flagRej = true;
1524 params.nRej++;
1525 } else {
1526 yAcc[nAcc++] = pnt.dy;
1527 }
1528 }
1529 if (nAcc > mParams->nMALong) {
1530 diffToMA(nAcc, yAcc, yDiffLong);
1531 float average = 0.f, rms = 0.f;
1532 for (int i = 0; i < nAcc; ++i) {
1533 average += yDiffLong[i];
1534 rms += yDiffLong[i] * yDiffLong[i];
1535 }
1536 average /= nAcc;
1537 rmsLong = rms / nAcc - average * average;
1538 rmsLong = (rmsLong > 0) ? std::sqrt(rmsLong) : 0.f;
1539 }
1540 return rmsLong;
1541}
1542
1544{
1545 std::array<float, param::NPadRows + 1> sumX1{}, sumX2{}, sumY1{}, sumXY{}, sumZ1{}, sumXZ{};
1546 for (int i = 0; i < np; ++i) {
1547 const auto& pnt = params.points[start + i];
1548 const float x = pnt.xTrk, y = pnt.dy, z = pnt.dz;
1549 sumX1[i + 1] = sumX1[i] + x;
1550 sumX2[i + 1] = sumX2[i] + x * x;
1551 sumY1[i + 1] = sumY1[i] + y;
1552 sumXY[i + 1] = sumXY[i] + x * y;
1553 sumZ1[i + 1] = sumZ1[i] + z;
1554 sumXZ[i + 1] = sumXZ[i] + x * z;
1555 }
1556
1557 for (int i = 0; i < np; ++i) {
1558 auto& pnt = params.points[start + i];
1559
1560 const int iLeft = std::max(0, i - mParams->nMAShort);
1561 const int iRight = std::min(np - 1, i + mParams->nMAShort);
1562
1563 const int nPoints = iRight - iLeft; // excluding current point
1564
1565 if (nPoints < mParams->nMAShort) {
1566 continue;
1567 }
1568
1569 const float nPointsInv = 1.f / nPoints;
1570
1571 float sX1 = sumX1[iRight + 1] - sumX1[iLeft] - pnt.xTrk;
1572 float sX2 = sumX2[iRight + 1] - sumX2[iLeft] - pnt.xTrk * pnt.xTrk;
1573 float sY1 = sumY1[iRight + 1] - sumY1[iLeft] - pnt.dy;
1574 float sXY = sumXY[iRight + 1] - sumXY[iLeft] - pnt.xTrk * pnt.dy;
1575 float sZ1 = sumZ1[iRight + 1] - sumZ1[iLeft] - pnt.dz;
1576 float sXZ = sumXZ[iRight + 1] - sumXZ[iLeft] - pnt.xTrk * pnt.dz;
1577
1578 const float det = sX2 - nPointsInv * sX1 * sX1;
1579
1580 if (std::abs(det) < 1e-12f) {
1581 continue;
1582 }
1583
1584 const float slopeY = (sXY - nPointsInv * sX1 * sY1) / det;
1585 const float offsetY = nPointsInv * (sY1 - slopeY * sX1);
1586 const float slopeZ = (sXZ - nPointsInv * sX1 * sZ1) / det;
1587 const float offsetZ = nPointsInv * (sZ1 - slopeZ * sX1);
1588 pnt.diffYSmooth = pnt.dy - (slopeY * pnt.xTrk + offsetY);
1589 pnt.diffZSmooth = pnt.dz - (slopeZ * pnt.xTrk + offsetZ);
1590 }
1591}
1592
1593void TrackInterpolation::diffToMA(const int np, const std::array<float, param::NPadRows>& y, std::array<float, param::NPadRows>& diffMA)
1594{
1595 // Calculate
1596 std::array<float, param::NPadRows + 1> sum{};
1597 for (int i = 0; i < np; ++i) {
1598 sum[i + 1] = sum[i] + y[i];
1599 }
1600 for (int i = 0; i < np; ++i) {
1601 diffMA[i] = 0.f;
1602 int iLeft = std::max(0, i - mParams->nMALong);
1603 int iRight = std::min(np - 1, i + mParams->nMALong);
1604 int nPoints = iRight - iLeft;
1605 if (nPoints < mParams->nMALong) { // this cannot happen, since at least mParams->nMALong points are required as neighbours for this function to be called
1606 continue;
1607 }
1608 float movingAverage = (sum[iRight + 1] - sum[iLeft] - y[i]) / nPoints;
1609 diffMA[i] = y[i] - movingAverage;
1610 }
1611}
1612
1614{
1615 mTrackData.clear();
1616 mTrackDataCompact.clear();
1617 mTrackDataExtended.clear();
1618 mClRes.clear();
1619 mDetInfoRes.clear();
1620 mGIDsSuccess.clear();
1621 for (auto& vec : mTrackIndices) {
1622 vec.clear();
1623 }
1624 mGIDs.clear();
1625 mGIDtables.clear();
1626 mTrackTimes.clear();
1627 mSeeds.clear();
1628 mITSRefitSeedID.clear();
1629 mTrackPVID.clear();
1630}
1631
1632//______________________________________________
1634{
1635 // Attention! For the refit we are using reference VDrift and TDriftOffest rather than high-rate calibrated, since we want to have fixed reference over the run
1636 if (v.refVDrift != mTPCVDriftRef) {
1637 mTPCVDriftRef = v.refVDrift;
1638 mTPCDriftTimeOffsetRef = v.refTimeOffset;
1639 LOGP(info, "Imposing reference VDrift={}/TDrift={} for TPC residuals extraction", mTPCVDriftRef, mTPCDriftTimeOffsetRef);
1640 o2::tpc::TPCFastTransformHelperO2::instance()->updateCalibration(*mFastTransform, 0, 1.0, mTPCVDriftRef, mTPCDriftTimeOffsetRef);
1641 }
1642}
1643
1644//______________________________________________
1646{
1647 // refit ITS track outwards taking PID (unless already refitted) from the seed and reassign to the seed
1648 auto& seed = mSeeds[seedID];
1649 int refitID = mITSRefitSeedID[gid.getIndex()];
1650 if (refitID >= 0) { // track was already refitted
1651 if (mSeeds[refitID].getPID() == seed.getPID()) {
1652 seed = mSeeds[refitID];
1653 }
1654 return true;
1655 }
1656 const auto& trkITS = mRecoCont->getITSTrack(gid);
1657 // fetch clusters
1658 auto nCl = trkITS.getNumberOfClusters();
1659 auto clEntry = trkITS.getFirstClusterEntry();
1660 o2::track::TrackParCov track(trkITS); // start from the inner param
1661 track.resetCovariance();
1662 track.setCov(track.getQ2Pt() * track.getQ2Pt() * track.getCov()[o2::track::CovLabels::kSigQ2Pt2], o2::track::CovLabels::kSigQ2Pt2);
1663 track.setPID(seed.getPID());
1664 o2::track::TrackPar refLin(track); // and use it also as linearization reference
1665 auto geom = o2::its::GeometryTGeo::Instance();
1666 auto prop = o2::base::Propagator::Instance();
1667 for (int iCl = nCl - 1; iCl >= 0; iCl--) { // clusters are stored from outer to inner layers
1668 const auto& cls = mITSClustersArray[mITSTrackClusIdx[clEntry + iCl]];
1669 int chip = cls.getSensorID();
1670 float chipX, chipAlpha;
1671 geom->getSensorXAlphaRefPlane(cls.getSensorID(), chipX, chipAlpha);
1672 if (!track.rotate(chipAlpha, refLin, mBz)) {
1673 LOGP(debug, "failed to rotate ITS tracks to alpha={} for the refit: {}", chipAlpha, track.asString());
1674 return false;
1675 }
1676 if (!prop->propagateToX(track, refLin, cls.getX(), mBz, o2::base::PropagatorImpl<float>::MAX_SIN_PHI, o2::base::PropagatorImpl<float>::MAX_STEP, o2::base::PropagatorF::MatCorrType::USEMatCorrLUT)) {
1677 LOGP(debug, "failed to propagate ITS tracks to X={}: {}", cls.getX(), track.asString());
1678 return false;
1679 }
1680 std::array<float, 2> posTF{cls.getY(), cls.getZ()};
1681 std::array<float, 3> covTF{cls.getSigmaY2(), cls.getSigmaYZ(), cls.getSigmaZ2()};
1682 if (!track.update(posTF, covTF)) {
1683 LOGP(debug, "failed to update ITS tracks by cluster ({},{})/({},{},{})", track.asString(), cls.getY(), cls.getZ(), cls.getSigmaY2(), cls.getSigmaYZ(), cls.getSigmaZ2());
1684 return false;
1685 }
1686 if (mParams->shiftRefToCluster) {
1687 refLin.setY(posTF[0]);
1688 refLin.setZ(posTF[1]);
1689 }
1690 }
1691 seed = track;
1692 // memorize that this ITS track was already refitted
1693 mITSRefitSeedID[gid.getIndex()] = seedID;
1694 return true;
1695}
std::string asString(TDataMember const &dm, char *pointer)
Global TRD definitions and constants.
std::ostringstream debug
int32_t i
Definition of the GeometryTGeo class.
Definition of the parameter class for the detector electronics.
uint16_t pos
Definition RawData.h:3
uint16_t slope
Definition RawData.h:1
uint32_t res
Definition RawData.h:0
Definition of the TrackInterpolation class.
Definition of the TrackResiduals class.
calibration data from laser track calibration
Referenc on track indices contributing to the vertex, with possibility chose tracks from specific sou...
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:178
static BasicCCDBManager & instance()
T * getSpecific(std::string const &path, long timestamp=-1, MD metaData=MD(), std::map< std::string, std::string > *headers=nullptr)
retrieve an object of type T from CCDB as stored under path, timestamp and metaData
static mask_t getSourcesMask(const std::string_view srcList)
static std::string getSourcesNames(mask_t srcm)
Static class with identifiers, bitmasks and names for ALICE detectors.
Definition DetID.h:58
static constexpr ID TRD
Definition DetID.h:65
static constexpr ID TOF
Definition DetID.h:66
static size_t fillOccupancyMapGetSize(uint32_t nHbfPerTf, const GPUParam *param=nullptr)
static void paramUseExternalOccupancyMap(GPUParam *param, uint32_t nHbfPerTf, const uint32_t *occupancymap, int32_t occupancyMapSize)
static std::shared_ptr< GPUParam > getFullParamShared(float solenoidBz, uint32_t nHbfPerTf=0, std::unique_ptr< GPUO2InterfaceConfiguration > *pConfiguration=nullptr, std::unique_ptr< GPUSettingsO2 > *pO2Settings=nullptr, bool *autoMaxTimeBin=nullptr)
void init(float bz, const GPUSettingsRec *rec=nullptr)
Load parameterization for given magnetic field.
float getSensorRefAlpha(int isn) const
static GeometryTGeo * Instance()
float getSensorRefX(int isn) const
static constexpr Double_t BC_TIME_INPS
Definition Geo.h:105
static constexpr Double_t BC_TIME_INPS_INV
Definition Geo.h:106
static void rotateToSector(Float_t *xyz, Int_t isector)
Definition Geo.cxx:1029
static void getPos(Int_t *det, Float_t *pos)
Definition Geo.cxx:491
static constexpr Int_t NPADSXSECTOR
Definition Geo.h:120
static void getVolumeIndices(Int_t index, Int_t *detId)
Definition Geo.cxx:543
static void alignedToNominalSector(Float_t *xyz, Int_t isector)
Definition Geo.cxx:1049
static TPCFastTransformHelperO2 * instance()
Singleton.
int updateCalibration(TPCFastTransform &fastTransform, int64_t TimeStamp, float vDriftFactor=1.f, float vDriftRef=0.f, float driftTimeOffset=0.f)
Updates the transformation with the new time stamp.
float checkResiduals(const TrackData &trk, TrackValidationData &params, const std::vector< TPCClusterResiduals > &clsRes)
void prepareInputTrackSample(const o2::globaltracking::RecoContainer &inp)
Prepare input track sample (not relying on CreateTracksVariadic functionality)
int processTRDLayer(const o2::trd::TrackTRD &trkTRD, int iLayer, o2::track::TrackParCov &trkWork, std::array< float, 2 > *trkltTRDYZ=nullptr, std::array< float, 3 > *trkltTRDCov=nullptr, TrackData *trkData=nullptr, o2::trd::Tracklet64 *trk64=nullptr, o2::trd::CalibratedTracklet *trkCalib=nullptr)
bool isInputTrackAccepted(const o2::dataformats::GlobalTrackID &gid, const o2::globaltracking::RecoContainer::GlobalIDSet &gidTable, const o2::dataformats::PrimaryVertex &pv) const
Check if input track passes configured cuts.
o2::dataformats::GlobalTrackID::Source findValidSource(const o2::dataformats::GlobalTrackID::mask_t mask, const o2::dataformats::GlobalTrackID::Source src) const
For given vertex track source which is not in mSourcesConfigured find the seeding source which is ena...
bool refITSTrack(o2::dataformats::GlobalTrackID, int iSeed)
@ ExtIn
extrapolation inwards of TRD/TOF track
@ Int
interpolation (mean positions of both extrapolations)
@ ExtOut
extrapolation outwards of ITS track
void diffToMA(const int np, const std::array< float, param::NPadRows > &y, std::array< float, param::NPadRows > &diffMA)
For a given set of points, calculate their deviation from the moving average (build from the neighbou...
bool compareToHelix(const TrackData &trk, TrackValidationData &params, const std::vector< TPCClusterResiduals > &clsRes)
void diffToLocLine(TrackValidationData &params, int start, int np)
For a given set of points, calculate the differences from each point to the fitted lines from all oth...
void process()
Main processing function.
void setTPCVDrift(const o2::tpc::VDriftCorrFact &v)
int8_t validateTrack(const TrackData &trk, TrackValidationData &params, const std::vector< TPCClusterResiduals > &clsRes, bool interpol)
bool isTrackSelected(const o2::track::TrackParCov &trk) const
Given the defined downsampling factor tsalisThreshold check if track is selected.
void reset()
Reset cache and output vectors.
bool outlierFiltering(const TrackData &trk, TrackValidationData &params, const std::vector< TPCClusterResiduals > &clsRes)
void init(o2::dataformats::GlobalTrackID::mask_t src, o2::dataformats::GlobalTrackID::mask_t srcMap)
Initialize everything, set the requested track sources.
static bool fitPoly1(int nCl, std::array< float, param::NPadRows > &x, std::array< float, param::NPadRows > &y, std::array< float, 2 > &res)
static void fitCircle(int nCl, std::array< float, param::NPadRows > &x, std::array< float, param::NPadRows > &y, float &xc, float &yc, float &r, std::array< float, param::NPadRows > &residHelixY)
static Geometry * instance()
Definition Geometry.h:33
GLfloat GLfloat GLfloat alpha
Definition glcorearb.h:279
GLint GLenum GLint x
Definition glcorearb.h:403
GLenum src
Definition glcorearb.h:1767
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLuint end
Definition glcorearb.h:469
const GLdouble * v
Definition glcorearb.h:832
GLuint GLuint GLfloat weight
Definition glcorearb.h:5477
GLint y
Definition glcorearb.h:270
GLenum const GLfloat * params
Definition glcorearb.h:272
GLboolean GLboolean g
Definition glcorearb.h:1233
GLbitfield flags
Definition glcorearb.h:1570
GLuint start
Definition glcorearb.h:469
GLint GLuint mask
Definition glcorearb.h:291
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
constexpr float TwoPI
constexpr float SectorSpanRad
constexpr float PI
constexpr float LightSpeedCm2S
constexpr double MassPionCharged
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 angle2Sector(float phi)
Definition Utils.h:183
float sector2Angle(int sect)
Definition Utils.h:193
constexpr int MAXGLOBALPADROW
Definition Constants.h:34
Global TPC definitions and constants.
Definition SimTraits.h:168
Enum< T >::Iterator begin(Enum< T >)
Definition Defs.h:156
DataT sum(const Vector< DataT, N > &a)
Definition Vector.h:107
TrackParCovF TrackParCov
Definition Track.h:33
constexpr int NLAYER
the number of layers
Definition Constants.h:27
constexpr int NSTACK
the number of stacks per sector
Definition Constants.h:26
GlobalIDSet getSingleDetectorRefs(GTrackID gidx) const
const o2::tpc::TrackTPC & getTPCTrack(GTrackID id) const
gsl::span< const o2::trd::CalibratedTracklet > getTRDCalibratedTracklets() const
const o2::tpc::ClusterNativeAccess & getTPCClusters() const
const o2::track::TrackParCov & getTrackParam(GTrackID gidx) const
gsl::span< const unsigned char > clusterShMapTPC
externally set TPC clusters sharing map
const o2::dataformats::TrackTPCITS & getTPCITSTrack(GTrackID gid) const
const o2::its::TrackITS & getITSTrack(GTrackID gid) const
auto getITSTPCTRDTrack(GTrackID id) const
gsl::span< const unsigned int > occupancyMapTPC
externally set TPC clusters occupancy map
std::array< GTrackID, GTrackID::NSources > GlobalIDSet
gsl::span< const o2::trd::Tracklet64 > getTRDTracklets() const
const o2::dataformats::MatchInfoTOF & getTOFMatch(GTrackID id) const
static constexpr int L2G
Definition Cartesian.h:54
static constexpr int T2L
Definition Cartesian.h:55
static bool downsampleTsallisCharged(float pt, float factorPt, float sqrts, float &weight, float rnd, float mass=0.13957)
Definition Tsallis.cxx:31
unsigned int clusterOffset[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
const ClusterNative * clustersLinear
float maxRejFrac
if the fraction of rejected clusters of a track is higher, the full track is invalidated
float maxDevHelixZ
max deviation in Z for clusters wrt helix fit
int nMALong
number of points to be used for moving average (long range)
float minPtNoOuterPoint
minimum pt for ITS-TPC tracks to be considered for extrapolation
int minTRDNTrklts
min number of TRD space points
bool refitITS
refit ITS tracks with PID attached to the seed
int nMAShort
number of points to be used for estimation of distance from local line (short range)
float maxDevHelixY
max deviation in Y for clusters wrt helix fit
float maxStdDevMA
max cluster std. deviation (Y^2 + Z^2) wrt moving average to accept
bool skipOutlierFiltering
if set, the outlier filtering will not be applied at all
bool ignoreNonPVContrib
flag if tracks which did not contribute to the PV should be ignored or not
bool keepRejectedResiduals
if set, keep rejected residuals setting rejected flag
int minITSNClsNoOuterPoint
min number of ITS clusters if no hit in TRD or TOF exists
int minTPCNCls
min number of TPC clusters
float tsalisThreshold
in case the sampling functions returns a value smaller than this the track is discarded (1....
bool shiftRefToCluster
when reftting the ITS track, shift the lin.reference to cluster after every update (better material m...
bool writeValidationData
write track validation data for debugging
float maxStep
maximum step for propagation
int minTOFTRDPVContributors
min contributors from TRD or TOF (fast detectors) to consider tracks of this PV
bool enableTrackDownsampling
flag if track sampling shall be enabled or not
float maxQ2Pt
max fitted q/pt for a track to be used for calibration
float sigYZ2TOF
for now assume cluster error for TOF equal for all clusters in both Y and Z
int minNumberOfAcceptedResiduals
min number of accepted residuals for
float maxRMSLong
maximum variance of the cluster residuals wrt moving avarage for a track to be considered
int minITSNCls
min number of ITS clusters
float maxSnp
max snp when propagating tracks
bool writeUnfiltered
if set, tracks failing validation will be kept with filterFlag>0 giving the reason of rejection
int minNCl
min number of clusters in a track to be used for calibration
int minTPCNClsNoOuterPoint
min number of TPC clusters if no hit in TRD or TOF exists
Structure filled for each track with track quality information and a vector with TPCClusterResiduals.
float chi2TRD
chi2 of TRD track
float dEdxTPC
TPC dEdx information.
unsigned short nTrkltsTRD
number of attached TRD tracklets
unsigned short clAvailTOF
whether or not track seed has a matched TOF cluster, if so, gives the resolution of the T0 in ps
std::array< uint8_t, 4 > multStack
short TRDTrkltSlope[6]
TRD tracklet slope 0x7fff / param::MaxTRDSlope.
unsigned short nClsITS
number of attached ITS clusters
o2::dataformats::RangeReference clIdx
index of first cluster residual and total number of TPC cluster residuals of this track
float chi2TPC
chi2 of TPC track
o2::track::TrackParCov par
ITS track at inner TPC radius.
unsigned short nClsTPC
number of attached TPC clusters
void setMultStack(float v, int stack)
o2::dataformats::GlobalTrackID gid
global track ID for seeding track
float deltaTOF
TOFsignal - T0 - texp(PID), if T0 is available.
int8_t filterFlag
-1: validation was not done, 0: validated, >0 : reason not passing validation, see validateTrack meth...
uint8_t nExtDetResid
number of external detectors (to TPC) residuals stored, on top of clIdx.getEntries
float chi2ITS
chi2 of ITS track
unsigned char sec
TPC sector (0..35)
unsigned char row
TPC pad row.
static void init(long timestamp=-1)
short channel
extra channel info (ITS chip ID, TRD chamber, TOF main pad within the sector)
o2::mch::DsIndex ds
std::vector< o2::ctf::BufferType > vec
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)
std::uniform_int_distribution< unsigned long long > distr
std::random_device rd
std::vector< int > row