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 mTPCTracksClusIdx = mRecoCont->getTPCTracksClusterRefs();
342 mTPCClusterIdxStruct = &mRecoCont->getTPCClusters();
343 int nbOccTOT = o2::gpu::GPUO2InterfaceRefit::fillOccupancyMapGetSize(mNHBPerTF, mTPCParam.get());
344 o2::gpu::GPUO2InterfaceUtils::paramUseExternalOccupancyMap(mTPCParam.get(), mNHBPerTF, mRecoCont->occupancyMapTPC.data(), nbOccTOT);
345 mNTPCOccBinLength = mTPCParam->rec.tpc.occupancyMapTimeBins;
346 mNTPCOccBinLengthInv = 1.f / mNTPCOccBinLength;
347 {
348 if (!mITSDict) {
349 LOG(error) << "No ITS dictionary available";
350 return;
351 }
352 mITSTrackClusIdx = mRecoCont->getITSTracksClusterRefs();
353 const auto clusITS = mRecoCont->getITSClusters();
354 const auto patterns = mRecoCont->getITSClustersPatterns();
355 auto pattIt = patterns.begin();
356 mITSClustersArray.clear();
357 mITSClustersArray.reserve(clusITS.size());
358 LOGP(info, "We have {} ITS clusters and the number of patterns is {}", clusITS.size(), patterns.size());
359 o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict);
360 }
361
362 // In case we have more input tracks available than are required per TF
363 // we want to sample them. But we still prefer global ITS-TPC-TRD-TOF tracks
364 // over ITS-TPC-TRD tracks and so on. So we have to shuffle the indices
365 // in blocks.
366 std::random_device rd;
367 std::mt19937 g(rd());
368 std::vector<uint32_t> trackIndices; // here we keep the GIDs for all track types in a single vector to use in loop
369 std::shuffle(mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRDTOF]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRDTOF]].end(), g);
370 std::shuffle(mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRD]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRD]].end(), g);
371 std::shuffle(mTrackIndices[mTrackTypes[GTrackID::ITSTPCTOF]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTOF]].end(), g);
372 std::shuffle(mTrackIndices[mTrackTypes[GTrackID::ITSTPC]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPC]].end(), g);
373 trackIndices.insert(trackIndices.end(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRDTOF]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRDTOF]].end());
374 trackIndices.insert(trackIndices.end(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRD]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRD]].end());
375 trackIndices.insert(trackIndices.end(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTOF]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTOF]].end());
376 trackIndices.insert(trackIndices.end(), mTrackIndices[mTrackTypes[GTrackID::ITSTPC]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPC]].end());
377 int nSeeds = mSeeds.size(), lastChecked = 0;
378 mParentID.clear();
379 mParentID.resize(nSeeds, -1);
380
381 int maxOutputTracks = (mMaxTracksPerTF >= 0) ? mMaxTracksPerTF + mAddTracksForMapPerTF : nSeeds;
382 mTrackData.reserve(maxOutputTracks);
383 mClRes.reserve(maxOutputTracks * param::NPadRows);
384 mDetInfoRes.reserve(maxOutputTracks * param::NPadRows);
385 bool maxTracksReached = false;
386 for (int iSeed = 0; iSeed < nSeeds; ++iSeed) {
387 if (mMaxTracksPerTF >= 0 && mTrackDataCompact.size() >= mMaxTracksPerTF + mAddTracksForMapPerTF) {
388 LOG(info) << "Maximum number of tracks per TF reached. Skipping the remaining " << nSeeds - iSeed << " tracks.";
389 break;
390 }
391 int seedIndex = trackIndices[iSeed];
392 if (mParams->enableTrackDownsampling && !isTrackSelected(mSeeds[seedIndex])) {
393 continue;
394 }
395 auto addPart = [this, seedIndex](GTrackID::Source src) {
396 this->mGIDs.push_back(this->mGIDtables[seedIndex][src]);
397 this->mGIDtables.push_back(this->mRecoCont->getSingleDetectorRefs(this->mGIDs.back()));
398 this->mTrackTimes.push_back(this->mTrackTimes[seedIndex]);
399 this->mSeeds.push_back(this->mSeeds[seedIndex]);
400 this->mParentID.push_back(seedIndex); // store parent seed id
401 this->mTrackPVID.push_back(this->mTrackPVID[seedIndex]);
402 };
403
404 GTrackID::mask_t partsAdded;
405 if (!mSingleSourcesConfigured && !mSourcesConfiguredMap[mGIDs[seedIndex].getSource()]) {
406 auto src = findValidSource(mSourcesConfiguredMap, static_cast<GTrackID::Source>(mGIDs[seedIndex].getSource()));
408 LOGP(debug, "process {}: Found valid source {} for {} | nseeds:{} mSeeds:{} used: {}", iSeed, GTrackID::getSourceName(src), GTrackID::getSourceName(mGIDs[seedIndex].getSource()), nSeeds, mSeeds.size(), mTrackDataCompact.size());
409 addPart(src);
410 }
411 }
412 if (mMaxTracksPerTF >= 0 && mTrackDataCompact.size() >= mMaxTracksPerTF) {
413 if (!maxTracksReached) {
414 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);
415 }
416 maxTracksReached = true;
417 continue;
418 }
419 if (mGIDs[seedIndex].includesDet(DetID::TRD) || mGIDs[seedIndex].includesDet(DetID::TOF)) {
420 interpolateTrack(seedIndex);
421 LOGP(debug, "interpolateTrack {} {}, accepted: {}", iSeed, GTrackID::getSourceName(mGIDs[seedIndex].getSource()), mTrackDataCompact.size());
422 if (mProcessSeeds) {
423 if (mGIDs[seedIndex].includesDet(DetID::TRD) && mGIDs[seedIndex].includesDet(DetID::TOF) && !partsAdded[GTrackID::ITSTPCTRD]) {
424 addPart(GTrackID::ITSTPCTRD);
425 }
426 if (!partsAdded[GTrackID::ITSTPC]) {
427 addPart(GTrackID::ITSTPC);
428 }
429 }
430 } else {
431 extrapolateTrack(seedIndex);
432 LOGP(debug, "extrapolateTrack {} {}, accepted: {}", iSeed, GTrackID::getSourceName(mGIDs[seedIndex].getSource()), mTrackDataCompact.size());
433 }
434 lastChecked = iSeed;
435 }
436 std::vector<int> remSeeds;
437 if (mSeeds.size() > ++lastChecked) {
438 remSeeds.resize(mSeeds.size() - lastChecked);
439 std::iota(remSeeds.begin(), remSeeds.end(), lastChecked);
440 std::shuffle(remSeeds.begin(), remSeeds.end(), g);
441 LOGP(info, "Up to {} tracks out of {} additional seeds will be processed in random order, of which {} are stripped versions, accepted seeds: {}",
442 mAddTracksForMapPerTF > 0 ? mAddTracksForMapPerTF : remSeeds.size(),
443 remSeeds.size(), mSeeds.size() - nSeeds, mTrackDataCompact.size());
444 }
445 int extraChecked = 0;
446 for (int iSeed : remSeeds) {
447 if (mAddTracksForMapPerTF > 0 && mTrackDataCompact.size() >= mMaxTracksPerTF + mAddTracksForMapPerTF) {
448 LOGP(info, "Maximum number {} of additional tracks per TF reached. Skipping the remaining {} tracks", mAddTracksForMapPerTF, remSeeds.size() - extraChecked);
449 break;
450 }
451 extraChecked++;
452 if (mGIDs[iSeed].includesDet(DetID::TRD) || mGIDs[iSeed].includesDet(DetID::TOF)) {
453 interpolateTrack(iSeed);
454 LOGP(debug, "extra check {} of {}, seed {} interpolateTrack {}, used: {}", extraChecked, remSeeds.size(), iSeed, GTrackID::getSourceName(mGIDs[iSeed].getSource()), mTrackDataCompact.size());
455 } else {
456 LOGP(debug, "extra check {} of {}, seed {} extrapolateTrack {}, used: {}", extraChecked, remSeeds.size(), iSeed, GTrackID::getSourceName(mGIDs[iSeed].getSource()), mTrackDataCompact.size());
457 extrapolateTrack(iSeed);
458 }
459 }
460 LOGP(info, "Could process {} tracks successfully ({} rejected in refits, {} in propagation, {} as loopers), {} residuals were rejected, {} accepted",
461 mTrackData.size(), mNRejRefit, mNRejProp, mNRejLoop, mRejectedResiduals, mClRes.size());
462 mRejectedResiduals = 0;
463 mNRejRefit = 0;
464 mNRejProp = 0;
465 mNRejLoop = 0;
466}
467
469{
470 LOGP(debug, "Starting track interpolation for GID {}", mGIDs[iSeed].asString());
471 TrackData trackData;
472 o2::trd::Tracklet64 trkl64;
474 std::unique_ptr<TrackDataExtended> trackDataExtended;
475 std::vector<TPCClusterResiduals> clusterResiduals;
476 auto propagator = o2::base::Propagator::Instance();
477 const auto& gidTable = mGIDtables[iSeed];
478 const auto& trkTPC = mRecoCont->getTPCTrack(gidTable[GTrackID::TPC]);
479 const auto& trkITS = mRecoCont->getITSTrack(gidTable[GTrackID::ITS]);
480 if (mDumpTrackPoints) {
481 trackDataExtended = std::make_unique<TrackDataExtended>();
482 (*trackDataExtended).gid = mGIDs[iSeed];
483 (*trackDataExtended).clIdx.setFirstEntry(mClRes.size());
484 (*trackDataExtended).trkITS = trkITS;
485 (*trackDataExtended).trkTPC = trkTPC;
486 auto nCl = trkITS.getNumberOfClusters();
487 auto clEntry = trkITS.getFirstClusterEntry();
488 for (int iCl = nCl - 1; iCl >= 0; iCl--) { // clusters are stored from outer to inner layers
489 const auto& clsITS = mITSClustersArray[mITSTrackClusIdx[clEntry + iCl]];
490 (*trackDataExtended).clsITS.push_back(clsITS);
491 }
492 }
493 if (mParams->refitITS && !refITSTrack(gidTable[GTrackID::ITS], iSeed)) {
494 mNRejRefit++;
495 return;
496 }
497 trackData.gid = mGIDs[iSeed];
498 trackData.par = mSeeds[iSeed];
499 auto trkWork = mSeeds[iSeed];
500 o2::track::TrackPar trkInner{trkWork};
501 // reset the cache array (sufficient to set cluster available to zero)
502 for (auto& elem : mCache) {
503 elem.clAvailable = 0;
504 }
505 trackData.clIdx.setFirstEntry(mClRes.size()); // reference the first cluster residual belonging to this track
506 float clusterTimeBinOffset = mTrackTimes[iSeed] / mTPCTimeBinMUS;
507
508 // store the TPC cluster positions in the cache, as well as dedx info
509 std::array<std::pair<uint16_t, uint16_t>, constants::MAXGLOBALPADROW> mCacheDEDX{};
510 std::array<short, constants::MAXGLOBALPADROW> multBins{};
511 for (int iCl = trkTPC.getNClusterReferences(); iCl--;) {
512 uint8_t sector, row;
513 uint32_t clusterIndexInRow;
514 const auto& clTPC = trkTPC.getCluster(mTPCTracksClusIdx, iCl, *mTPCClusterIdxStruct, sector, row);
515 float clTPCX;
516 std::array<float, 2> clTPCYZ;
517 mFastTransform->TransformIdeal(sector, row, clTPC.getPad(), clTPC.getTime(), clTPCX, clTPCYZ[0], clTPCYZ[1], clusterTimeBinOffset);
518 mCache[row].clSec = sector;
519 mCache[row].clAvailable = 1;
520 mCache[row].clY = clTPCYZ[0];
521 mCache[row].clZ = clTPCYZ[1];
522 mCache[row].clAngle = o2::math_utils::sector2Angle(sector);
523 mCacheDEDX[row].first = clTPC.getQtot();
524 mCacheDEDX[row].second = clTPC.getQmax();
525 int imb = int(clTPC.getTime() * mNTPCOccBinLengthInv);
526 if (imb < mTPCParam->occupancyMapSize) {
527 multBins[row] = 1 + std::max(0, imb);
528 }
529 }
530
531 // extrapolate seed through TPC and store track position at each pad row
532 for (int iRow = 0; iRow < param::NPadRows; ++iRow) {
533 if (!mCache[iRow].clAvailable) {
534 continue;
535 }
536 if (!trkWork.rotate(mCache[iRow].clAngle)) {
537 LOG(debug) << "Failed to rotate track during first extrapolation";
538 mNRejProp++;
539 return;
540 }
541 if (!propagator->PropagateToXBxByBz(trkWork, param::RowX[iRow], mParams->maxSnp, mParams->maxStep, mMatCorr)) {
542 LOG(debug) << "Failed on first extrapolation";
543 mNRejProp++;
544 return;
545 }
546 mCache[iRow].y[ExtOut] = trkWork.getY();
547 mCache[iRow].z[ExtOut] = trkWork.getZ();
548 mCache[iRow].sy2[ExtOut] = trkWork.getSigmaY2();
549 mCache[iRow].szy[ExtOut] = trkWork.getSigmaZY();
550 mCache[iRow].sz2[ExtOut] = trkWork.getSigmaZ2();
551 mCache[iRow].snp[ExtOut] = trkWork.getSnp();
552 // printf("Track alpha at row %i: %.2f, Y(%.2f), Z(%.2f)\n", iRow, trkWork.getAlpha(), trkWork.getY(), trkWork.getZ());
553 }
554
555 // start from outermost cluster with outer refit and back propagation
556 if (gidTable[GTrackID::TOF].isIndexSet()) {
557 LOG(debug) << "TOF point available";
558 const auto& clTOF = mRecoCont->getTOFClusters()[gidTable[GTrackID::TOF]];
559 if (mDumpTrackPoints) {
560 (*trackDataExtended).clsTOF = clTOF;
561 (*trackDataExtended).matchTOF = mRecoCont->getTOFMatch(mGIDs[iSeed]);
562 }
563 const int clTOFSec = clTOF.getCount();
564 const float clTOFAlpha = o2::math_utils::sector2Angle(clTOFSec);
565 if (!trkWork.rotate(clTOFAlpha)) {
566 LOG(debug) << "Failed to rotate into TOF cluster sector frame";
567 mNRejProp++;
568 return;
569 }
570 float clTOFxyz[3] = {clTOF.getX(), clTOF.getY(), clTOF.getZ()};
571 if (!clTOF.isInNominalSector()) {
572 o2::tof::Geo::alignedToNominalSector(clTOFxyz, clTOFSec); // go from the aligned to nominal sector frame
573 }
574 std::array<float, 2> clTOFYZ{clTOFxyz[1], clTOFxyz[2]};
575 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
576 if (!propagator->PropagateToXBxByBz(trkWork, clTOFxyz[0], mParams->maxSnp, mParams->maxStep, mMatCorr)) {
577 LOG(debug) << "Failed final propagation to TOF radius";
578 mNRejProp++;
579 return;
580 }
581 // TODO: check if reset of covariance matrix is needed here (or, in case TOF point is not available at outermost TRD layer)
582 if (!trkWork.update(clTOFYZ, clTOFCov)) {
583 LOG(debug) << "Failed to update extrapolated ITS track with TOF cluster";
584 // LOGF(info, "trkWork.y=%f, cl.y=%f, trkWork.z=%f, cl.z=%f", trkWork.getY(), clTOFYZ[0], trkWork.getZ(), clTOFYZ[1]);
585 mNRejProp++;
586 return;
587 }
588 }
589 if (gidTable[GTrackID::TRD].isIndexSet()) {
590 LOG(debug) << "TRD available";
591 const auto& trkTRD = mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTable[GTrackID::ITSTPCTRD]);
592 if (mDumpTrackPoints) {
593 (*trackDataExtended).trkTRD = trkTRD;
594 }
595 for (int iLayer = o2::trd::constants::NLAYER - 1; iLayer >= 0; --iLayer) {
596 std::array<float, 2> trkltTRDYZ{};
597 std::array<float, 3> trkltTRDCov{};
598 int res = processTRDLayer(trkTRD, iLayer, trkWork, &trkltTRDYZ, &trkltTRDCov);
599 if (res == -1) { // no TRD tracklet in this layer
600 continue;
601 }
602 if (res < -1) { // failed to reach this layer
603 return;
604 }
605 if (!trkWork.update(trkltTRDYZ, trkltTRDCov)) {
606 LOG(debug) << "Failed to update track at TRD layer " << iLayer;
607 mNRejProp++;
608 return;
609 }
610 }
611 }
612
613 if (mDumpTrackPoints) {
614 (*trackDataExtended).trkOuter = trkWork;
615 }
616 auto trkOuter = trkWork; // outer param
617
618 // go back through the TPC and store updated track positions
619 bool outerParamStored = false;
620 for (int iRow = param::NPadRows; iRow--;) {
621 if (!mCache[iRow].clAvailable) {
622 continue;
623 }
624 if (mProcessSeeds && !outerParamStored) {
625 // for debug purposes we store the track parameters
626 // of the refitted ITS-(TRD)-(TOF) track at the
627 // outermose TPC cluster if we are processing all seeds
628 // i.e. if we in any case also process the ITS-TPC only
629 // part of the same track
630 trackData.par = trkWork;
631 outerParamStored = true;
632 }
633 if (!trkWork.rotate(mCache[iRow].clAngle)) {
634 LOG(debug) << "Failed to rotate track during back propagation";
635 mNRejProp++;
636 return;
637 }
638 if (!propagator->PropagateToXBxByBz(trkWork, param::RowX[iRow], mParams->maxSnp, mParams->maxStep, mMatCorr)) {
639 LOG(debug) << "Failed on back propagation";
640 // printf("trkX(%.2f), clX(%.2f), clY(%.2f), clZ(%.2f), alphaTOF(%.2f)\n", trkWork.getX(), param::RowX[iRow], clTOFYZ[0], clTOFYZ[1], clTOFAlpha);
641 mNRejProp++;
642 return;
643 }
644 mCache[iRow].y[ExtIn] = trkWork.getY();
645 mCache[iRow].z[ExtIn] = trkWork.getZ();
646 mCache[iRow].sy2[ExtIn] = trkWork.getSigmaY2();
647 mCache[iRow].szy[ExtIn] = trkWork.getSigmaZY();
648 mCache[iRow].sz2[ExtIn] = trkWork.getSigmaZ2();
649 mCache[iRow].snp[ExtIn] = trkWork.getSnp();
650 }
651
652 // calculate weighted mean at each pad row (assume for now y and z are uncorrelated) and store residuals to TPC clusters
653 unsigned short deltaRow = 0;
654 for (int iRow = 0; iRow < param::NPadRows; ++iRow) {
655 if (!mCache[iRow].clAvailable) {
656 ++deltaRow;
657 continue;
658 }
659 float wTotY = 1.f / mCache[iRow].sy2[ExtOut] + 1.f / mCache[iRow].sy2[ExtIn];
660 float wTotZ = 1.f / mCache[iRow].sz2[ExtOut] + 1.f / mCache[iRow].sz2[ExtIn];
661 mCache[iRow].y[Int] = (mCache[iRow].y[ExtOut] / mCache[iRow].sy2[ExtOut] + mCache[iRow].y[ExtIn] / mCache[iRow].sy2[ExtIn]) / wTotY;
662 mCache[iRow].z[Int] = (mCache[iRow].z[ExtOut] / mCache[iRow].sz2[ExtOut] + mCache[iRow].z[ExtIn] / mCache[iRow].sz2[ExtIn]) / wTotZ;
663
664 // simple average w/o weighting for angle
665 mCache[iRow].snp[Int] = (mCache[iRow].snp[ExtOut] + mCache[iRow].snp[ExtIn]) / 2.f;
666
667 const auto dY = mCache[iRow].clY - mCache[iRow].y[Int];
668 const auto dZ = mCache[iRow].clZ - mCache[iRow].z[Int];
669 const auto y = mCache[iRow].y[Int];
670 const auto z = mCache[iRow].z[Int];
671 const auto snp = mCache[iRow].snp[Int];
672 const auto sec = mCache[iRow].clSec;
673 clusterResiduals.emplace_back(dY, dZ, y, z, snp, sec, deltaRow);
674
675 deltaRow = 1;
676 }
677 trackData.chi2TRD = gidTable[GTrackID::TRD].isIndexSet() ? mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTable[GTrackID::ITSTPCTRD]).getChi2() : 0;
678 trackData.chi2TPC = trkTPC.getChi2();
679 trackData.chi2ITS = trkITS.getChi2();
680 trackData.nClsTPC = trkTPC.getNClusterReferences();
681 trackData.nClsITS = trkITS.getNumberOfClusters();
682 trackData.nTrkltsTRD = gidTable[GTrackID::TRD].isIndexSet() ? mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTable[GTrackID::ITSTPCTRD]).getNtracklets() : 0;
683
684 double t0forTOF = 0.; // to be set if TOF is matched
685 float t0forTOFwithinBC = 0.f;
686 float t0forTOFres = 9999.f;
687
688 if (gidTable[GTrackID::TOF].isIndexSet()) {
689 const auto& tofMatch = mRecoCont->getTOFMatch(mGIDs[iSeed]);
690 ULong64_t bclongtof = (tofMatch.getSignal() - 10000) * o2::tof::Geo::BC_TIME_INPS_INV;
691 t0forTOF = tofMatch.getFT0Best(); // setting t0 for TOF
692 t0forTOFwithinBC = t0forTOF - bclongtof * o2::tof::Geo::BC_TIME_INPS;
693 t0forTOFres = tofMatch.getFT0BestRes();
694 trackData.deltaTOF = tofMatch.getSignal() - t0forTOF - tofMatch.getLTIntegralOut().getTOF(trkTPC.getPID().getID());
695 trackData.clAvailTOF = uint16_t(t0forTOFres);
696 } else {
697 trackData.clAvailTOF = 0;
698 }
699 trackData.dEdxTPC = trkTPC.getdEdx().dEdxTotTPC;
700
701 mTrackValidation.clear(); // for refitted track parameters and flagging rejected clusters
702
703 bool stored = false;
704 trackData.filterFlag = mParams->skipOutlierFiltering ? -1 : validateTrack(trackData, mTrackValidation, clusterResiduals, true);
705 if (trackData.filterFlag <= 0 || mParams->writeUnfiltered) {
706 int nClValidated = 0;
707 int iRow = 0;
708 for (unsigned int iCl = 0; iCl < clusterResiduals.size(); ++iCl) {
709 iRow += clusterResiduals[iCl].dRow;
710 const auto rej = trackData.filterFlag < 0 ? false : mTrackValidation.points[iCl].flagRej;
711 if (rej && !mParams->keepRejectedResiduals) { // skip masked cluster residual
712 continue;
713 }
714 const float tgPhi = clusterResiduals[iCl].snp / std::sqrt((1.f - clusterResiduals[iCl].snp) * (1.f + clusterResiduals[iCl].snp));
715 const auto dy = clusterResiduals[iCl].dy;
716 const auto dz = clusterResiduals[iCl].dz;
717 const auto y = clusterResiduals[iCl].y;
718 const auto z = clusterResiduals[iCl].z;
719 const auto sec = clusterResiduals[iCl].sec;
720 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)) {
721 mClRes.emplace_back(dy, dz, tgPhi, y, z, iRow, sec, -1, rej);
722 mDetInfoRes.emplace_back().setTPC(mCacheDEDX[iRow].first, mCacheDEDX[iRow].second); // qtot, qmax
723 ++nClValidated;
724 } else {
725 ++mRejectedResiduals;
726 }
727 }
728 trackData.clIdx.setEntries(nClValidated);
729
730 // store multiplicity info
731 for (int ist = 0; ist < NSTACKS; ist++) {
732 int mltBinMin = 0x7ffff, mltBinMax = -1, prevBin = -1;
733 for (int ir = STACKROWS[ist]; ir < STACKROWS[ist + 1]; ir++) {
734 if (multBins[ir] != prevBin && multBins[ir] > 0) { // there is a cluster different from previous one
735 prevBin = multBins[ir];
736 if (multBins[ir] > mltBinMax) {
737 mltBinMax = multBins[ir];
738 }
739 if (multBins[ir] < mltBinMin) {
740 mltBinMin = multBins[ir];
741 }
742 }
743 }
744 if (--mltBinMin >= 0) { // we were offsetting bin IDs by 1!
745 float avMlt = 0;
746 for (int ib = mltBinMin; ib < mltBinMax; ib++) {
747 avMlt += mTPCParam->occupancyMap[ib];
748 }
749 avMlt /= (mltBinMax - mltBinMin);
750 trackData.setMultStack(avMlt, ist);
751 }
752 }
753
754 bool stopPropagation = !mExtDetResid;
755 if (!stopPropagation) {
756 // do we have TRD residuals to add?
757 trkWork = trkOuter;
758 if (gidTable[GTrackID::TRD].isIndexSet()) {
759 const auto& trkTRD = mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTable[GTrackID::ITSTPCTRD]);
760 for (int iLayer = 0; iLayer < o2::trd::constants::NLAYER; iLayer++) {
761 std::array<float, 2> trkltTRDYZ{};
762 int res = processTRDLayer(trkTRD, iLayer, trkWork, &trkltTRDYZ, nullptr, &trackData, &trkl64, &trklCalib);
763 if (res == -1) { // no traklet on this layer
764 continue;
765 }
766 if (res < -1) { // failed to reach this layer
767 stopPropagation = true;
768 break;
769 }
770
771 float tgPhi = trkWork.getSnp() / std::sqrt((1.f - trkWork.getSnp()) * (1.f + trkWork.getSnp()));
772 auto dy = trkltTRDYZ[0] - trkWork.getY();
773 auto dz = trkltTRDYZ[1] - trkWork.getZ();
774 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)) {
775 mClRes.emplace_back(dy, dz, tgPhi, trkWork.getY(), trkWork.getZ(), 160 + iLayer, o2::math_utils::angle2Sector(trkWork.getAlpha()), (short)res);
776 mDetInfoRes.emplace_back().setTRD(trkl64.getQ0(), trkl64.getQ1(), trkl64.getQ2(), trklCalib.getDy()); // q0,q1,q2,slope
777 trackData.nExtDetResid++;
778 }
779 }
780 }
781
782 // do we have TOF residual to add?
783 while (gidTable[GTrackID::TOF].isIndexSet() && !stopPropagation) {
784 const auto& clTOF = mRecoCont->getTOFClusters()[gidTable[GTrackID::TOF]];
785 float clTOFxyz[3] = {clTOF.getX(), clTOF.getY(), clTOF.getZ()};
786 if (!clTOF.isInNominalSector()) {
787 o2::tof::Geo::alignedToNominalSector(clTOFxyz, clTOF.getCount()); // go from the aligned to nominal sector frame
788 }
789 const float clTOFAlpha = o2::math_utils::sector2Angle(clTOF.getCount());
790 if (trkWork.getAlpha() != clTOFAlpha && !trkWork.rotate(clTOFAlpha)) {
791 LOG(debug) << "Failed to rotate into TOF cluster sector frame";
792 stopPropagation = true;
793 break;
794 }
795 if (!propagator->PropagateToXBxByBz(trkWork, clTOFxyz[0], mParams->maxSnp, mParams->maxStep, mMatCorr)) {
796 LOG(debug) << "Failed final propagation to TOF radius";
797 break;
798 }
799
800 float tgPhi = trkWork.getSnp() / std::sqrt((1.f - trkWork.getSnp()) * (1.f + trkWork.getSnp()));
801 auto dy = clTOFxyz[1] - trkWork.getY();
802 auto dz = clTOFxyz[2] - trkWork.getZ();
803 // get seeding track time
804
805 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)) {
806 mClRes.emplace_back(dy, dz, tgPhi, trkWork.getY(), trkWork.getZ(), 170, clTOF.getCount(), clTOF.getPadInSector());
807 // get seeding track time
808 if (!gidTable[GTrackID::ITSTPC].isIndexSet()) {
809 LOGP(fatal, "ITS-TPC seed index is not set for TOF track");
810 }
811 float tdif = static_cast<float>(clTOF.getTime() - t0forTOF); // time in \mus wrt interaction time0
812 mDetInfoRes.emplace_back().setTOF(tdif * 1e-6);
813 trackData.nExtDetResid++;
814 }
815 break;
816 }
817
818 // add ITS residuals
819 while (!stopPropagation) {
820 auto& trkWorkITS = trkInner; // this is ITS outer param
821 auto nCl = trkITS.getNumberOfClusters();
822 auto clEntry = trkITS.getFirstClusterEntry();
824 for (int iCl = 0; iCl < nCl; iCl++) { // clusters are stored from outer to inner layers
825 const auto& cls = mITSClustersArray[mITSTrackClusIdx[clEntry + iCl]];
826 int chip = cls.getSensorID();
827 float chipX, chipAlpha;
828 geom->getSensorXAlphaRefPlane(cls.getSensorID(), chipX, chipAlpha);
829 if (!trkWorkITS.rotate(chipAlpha) || !propagator->PropagateToXBxByBz(trkWorkITS, chipX, mParams->maxSnp, mParams->maxStep, mMatCorr)) {
830 LOGP(debug, "Failed final propagation to ITS X={} alpha={}", chipX, chipAlpha);
831 stopPropagation = true;
832 break;
833 }
834 float tgPhi = trkWorkITS.getSnp() / std::sqrt((1.f - trkWorkITS.getSnp()) * (1.f + trkWorkITS.getSnp()));
835 auto dy = cls.getY() - trkWorkITS.getY();
836 auto dz = cls.getZ() - trkWorkITS.getZ();
837 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)) {
838 mClRes.emplace_back(dy, dz, tgPhi, trkWorkITS.getY(), trkWorkITS.getZ(), 180 + geom->getLayer(cls.getSensorID()), -1, cls.getSensorID());
839 mDetInfoRes.emplace_back(); // empty placeholder
840 trackData.nExtDetResid++;
841 }
842 }
843 if (!stopPropagation) { // add residual to PV
844 const auto& pv = mRecoCont->getPrimaryVertices()[mTrackPVID[iSeed]];
845 o2::math_utils::Point3D<float> vtx{pv.getX(), pv.getY(), pv.getZ()};
846 if (!propagator->propagateToDCA(vtx, trkWorkITS, mBz, mParams->maxStep, mMatCorr)) {
847 LOGP(debug, "Failed propagation to DCA to PV ({} {} {}), {}", pv.getX(), pv.getY(), pv.getZ(), trkWorkITS.asString());
848 stopPropagation = true;
849 break;
850 }
851 // rotate PV to the track frame
852 float sn, cs, alpha = trkWorkITS.getAlpha();
853 math_utils::detail::bringToPMPi(alpha);
854 math_utils::detail::sincos<float>(alpha, sn, cs);
855 float xv = vtx.X() * cs + vtx.Y() * sn, yv = -vtx.X() * sn + vtx.Y() * cs, zv = vtx.Z();
856 auto dy = yv - trkWorkITS.getY();
857 auto dz = zv - trkWorkITS.getZ();
858 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) {
859 short compXV = static_cast<short>(xv * 0x7fff / param::MaxVtxX);
860 mClRes.emplace_back(dy, dz, alpha / TMath::Pi(), trkWorkITS.getY(), trkWorkITS.getZ(), 190, -1, compXV);
861 if (!gidTable[GTrackID::ITSTPC].isIndexSet()) {
862 LOGP(fatal, "ITS-TPC seed index is not set for TOF track");
863 }
864 float tdif = pv.getTimeStamp().getTimeStamp() - mRecoCont->getTPCITSTrack(gidTable[GTrackID::ITSTPC]).getTimeMUS().getTimeStamp();
865 mDetInfoRes.emplace_back().setPV(tdif); // time in \mus wrt seeding ITS-TPC track
866 trackData.nExtDetResid++;
867 }
868 }
869 break;
870 }
871 }
872
873 mGIDsSuccess.push_back(mGIDs[iSeed]);
874 mTrackDataCompact.emplace_back(trackData.clIdx.getFirstEntry(), trackData.multStack, nClValidated, mGIDs[iSeed].getSource(), trackData.nExtDetResid, trackData.filterFlag);
875 mTrackData.push_back(std::move(trackData));
876 stored = true;
877 if (mDumpTrackPoints) {
878 (*trackDataExtended).clIdx.setEntries(nClValidated);
879 (*trackDataExtended).nExtDetResid = trackData.nExtDetResid;
880 (*trackDataExtended).filterFlag = trackData.filterFlag;
881 mTrackDataExtended.push_back(std::move(*trackDataExtended));
882 }
883 }
884 if (mParams->writeValidationData && trackData.filterFlag >= 0 && mDBGOut) {
885 (*mDBGOut) << "valdata" << "params=" << mTrackValidation << "trackData=" << (stored ? mTrackData.back() : trackData) << "\n";
886 }
887}
888
890 std::array<float, 2>* trkltTRDYZ, std::array<float, 3>* trkltTRDCov, TrackData* trkData,
892{
893 // return chamber ID (0:539) in case of successful processing, -1 if there is no TRD tracklet at given layer, -2 if processing failed
894 int trkltIdx = trkTRD.getTrackletIndex(iLayer);
895 if (trkltIdx < 0) {
896 return -1; // no TRD tracklet in this layer
897 }
898 const auto& trdSP = mRecoCont->getTRDCalibratedTracklets()[trkltIdx];
899 const auto& trdTrklt = mRecoCont->getTRDTracklets()[trkltIdx];
900 auto trkltDet = trdTrklt.getDetector();
901 auto trkltSec = trkltDet / (o2::trd::constants::NLAYER * o2::trd::constants::NSTACK);
902 if (trkltSec != o2::math_utils::angle2Sector(trkWork.getAlpha())) {
903 if (!trkWork.rotate(o2::math_utils::sector2Angle(trkltSec))) {
904 LOG(debug) << "Track could not be rotated in TRD tracklet coordinate system in layer " << iLayer;
905 return -2;
906 }
907 }
908 if (!o2::base::Propagator::Instance()->PropagateToXBxByBz(trkWork, trdSP.getX(), mParams->maxSnp, mParams->maxStep, mMatCorr)) {
909 LOG(debug) << "Failed propagation to TRD layer " << iLayer;
910 return -2;
911 }
912 if (trkltTRDYZ) {
913 const auto* pad = mGeoTRD->getPadPlane(trkltDet);
914 float tilt = tan(TMath::DegToRad() * pad->getTiltingAngle()); // tilt is signed! and returned in degrees
915 float tiltCorrUp = tilt * (trdSP.getZ() - trkWork.getZ());
916 float zPosCorrUp = trdSP.getZ() + mRecoParam.getZCorrCoeffNRC() * trkWork.getTgl(); // maybe Z can be corrected on avarage already by the tracklet transformer?
917 float padLength = pad->getRowSize(trdTrklt.getPadRow());
918 if (!((trkWork.getSigmaZ2() < (padLength * padLength / 12.f)) && (std::abs(trdSP.getZ() - trkWork.getZ()) < padLength))) {
919 tiltCorrUp = 0.f;
920 }
921 (*trkltTRDYZ)[0] = trdSP.getY() - tiltCorrUp;
922 (*trkltTRDYZ)[1] = zPosCorrUp;
923 if (trkltTRDCov) {
924 mRecoParam.recalcTrkltCov(tilt, trkWork.getSnp(), pad->getRowSize(trdTrklt.getPadRow()), *trkltTRDCov);
925 }
926 }
927 if (trkData) {
928 auto slope = trdSP.getDy();
929 if (std::abs(slope) < param::MaxTRDSlope) {
930 trkData->TRDTrkltSlope[iLayer] = slope * 0x7fff / param::MaxTRDSlope;
931 }
932 }
933 if (trk64) {
934 *trk64 = trdTrklt;
935 }
936 if (trkCalib) {
937 *trkCalib = trdSP;
938 }
939 return trkltDet;
940}
941
943{
944 // extrapolate ITS-only track through TPC and store residuals to TPC clusters in the output vectors
945 LOGP(debug, "Starting track extrapolation for GID {}", mGIDs[iSeed].asString());
946 const auto& gidTable = mGIDtables[iSeed];
947 TrackData trackData;
948 o2::trd::Tracklet64 trkl64;
950 std::unique_ptr<TrackDataExtended> trackDataExtended;
951 std::vector<TPCClusterResiduals> clusterResiduals;
952 trackData.clIdx.setFirstEntry(mClRes.size());
953 const auto& trkITS = mRecoCont->getITSTrack(gidTable[GTrackID::ITS]);
954 const auto& trkTPC = mRecoCont->getTPCTrack(gidTable[GTrackID::TPC]);
955 if (mDumpTrackPoints) {
956 trackDataExtended = std::make_unique<TrackDataExtended>();
957 (*trackDataExtended).gid = mGIDs[iSeed];
958 (*trackDataExtended).clIdx.setFirstEntry(mClRes.size());
959 (*trackDataExtended).trkITS = trkITS;
960 (*trackDataExtended).trkTPC = trkTPC;
961 auto nCl = trkITS.getNumberOfClusters();
962 auto clEntry = trkITS.getFirstClusterEntry();
963 for (int iCl = nCl - 1; iCl >= 0; iCl--) { // clusters are stored from outer to inner layers
964 const auto& clsITS = mITSClustersArray[mITSTrackClusIdx[clEntry + iCl]];
965 (*trackDataExtended).clsITS.push_back(clsITS);
966 }
967 }
968 if (mParams->refitITS && !refITSTrack(gidTable[GTrackID::ITS], iSeed)) {
969 mNRejRefit++;
970 return;
971 }
972 trackData.gid = mGIDs[iSeed];
973 trackData.par = mSeeds[iSeed];
974
975 auto trkWork = mSeeds[iSeed];
976 float clusterTimeBinOffset = mTrackTimes[iSeed] / mTPCTimeBinMUS;
977 auto propagator = o2::base::Propagator::Instance();
978 unsigned short rowPrev = 0; // used to calculate dRow of two consecutive cluster residuals
979 unsigned short nMeasurements = 0;
980 uint8_t clRowPrev = constants::MAXGLOBALPADROW; // used to identify and skip split clusters on the same pad row
981 std::array<std::pair<uint16_t, uint16_t>, constants::MAXGLOBALPADROW> mCacheDEDX{};
982 std::array<short, constants::MAXGLOBALPADROW> multBins{};
983 for (int iCl = trkTPC.getNClusterReferences(); iCl--;) {
984 uint8_t sector, row;
985 uint32_t clusterIndexInRow;
986 const auto& cl = trkTPC.getCluster(mTPCTracksClusIdx, iCl, *mTPCClusterIdxStruct, sector, row);
987 if (clRowPrev == row) {
988 // if there are split clusters we only take the first one on the pad row
989 continue;
990 } else if (clRowPrev < constants::MAXGLOBALPADROW && clRowPrev > row) {
991 // we seem to be looping, abort this track
992 LOGP(debug, "TPC track with pT={} GeV and {} clusters has cluster {} on row {} while the previous cluster was on row {}",
993 mSeeds[iSeed].getPt(), trkTPC.getNClusterReferences(), iCl, row, clRowPrev);
994 mNRejLoop++;
995 return;
996 } else {
997 // this is the first cluster we see on this pad row
998 clRowPrev = row;
999 }
1000 float x = 0, y = 0, z = 0;
1001 mFastTransform->TransformIdeal(sector, row, cl.getPad(), cl.getTime(), x, y, z, clusterTimeBinOffset);
1002 if (!trkWork.rotate(o2::math_utils::sector2Angle(sector))) {
1003 mNRejProp++;
1004 return;
1005 }
1006 if (!propagator->PropagateToXBxByBz(trkWork, x, mParams->maxSnp, mParams->maxStep, mMatCorr)) {
1007 mNRejProp++;
1008 return;
1009 }
1010
1011 const auto dY = y - trkWork.getY();
1012 const auto dZ = z - trkWork.getZ();
1013 const auto ty = trkWork.getY();
1014 const auto tz = trkWork.getZ();
1015 const auto snp = trkWork.getSnp();
1016 const auto sec = sector;
1017 clusterResiduals.emplace_back(dY, dZ, ty, tz, snp, sec, row - rowPrev);
1018 mCacheDEDX[row].first = cl.getQtot();
1019 mCacheDEDX[row].second = cl.getQmax();
1020 rowPrev = row;
1021 int imb = int(cl.getTime() * mNTPCOccBinLengthInv);
1022 if (imb < mTPCParam->occupancyMapSize) {
1023 multBins[row] = 1 + std::max(0, imb);
1024 }
1025 ++nMeasurements;
1026 }
1027
1028 mTrackValidation.clear(); // for refitted track parameters and flagging rejected clusters
1029 if (clusterResiduals.size() > constants::MAXGLOBALPADROW) {
1030 LOGP(warn, "Extrapolated ITS-TPC track and found more residuals than possible ({})", clusterResiduals.size());
1031 mNRejLoop++;
1032 return;
1033 }
1034
1035 trackData.chi2TPC = trkTPC.getChi2();
1036 trackData.chi2ITS = trkITS.getChi2();
1037 trackData.nClsTPC = trkTPC.getNClusterReferences();
1038 trackData.nClsITS = trkITS.getNumberOfClusters();
1039 trackData.clIdx.setEntries(nMeasurements);
1040 trackData.dEdxTPC = trkTPC.getdEdx().dEdxTotTPC;
1041 if (mDumpTrackPoints) {
1042 (*trackDataExtended).trkOuter = trkWork;
1043 }
1044
1045 bool stored = false;
1046 trackData.filterFlag = mParams->skipOutlierFiltering ? -1 : validateTrack(trackData, mTrackValidation, clusterResiduals, false);
1047 if (trackData.filterFlag <= 0 || mParams->writeUnfiltered) {
1048 int nClValidated = 0, iRow = 0;
1049 unsigned int iCl = 0;
1050 for (iCl = 0; iCl < clusterResiduals.size(); ++iCl) {
1051 iRow += clusterResiduals[iCl].dRow;
1052 if (iRow >= param::NPadRows) { // RS why do we need this?
1053 continue;
1054 }
1055 const auto rej = trackData.filterFlag < 0 ? false : mTrackValidation.points[iCl].flagRej;
1056 if (rej && !mParams->keepRejectedResiduals) { // skip masked cluster residual
1057 continue;
1058 }
1059 const float tgPhi = clusterResiduals[iCl].snp / std::sqrt((1.f - clusterResiduals[iCl].snp) * (1.f + clusterResiduals[iCl].snp));
1060 const auto dy = clusterResiduals[iCl].dy;
1061 const auto dz = clusterResiduals[iCl].dz;
1062 const auto y = clusterResiduals[iCl].y;
1063 const auto z = clusterResiduals[iCl].z;
1064 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)) {
1065 mClRes.emplace_back(dy, dz, tgPhi, y, z, iRow, clusterResiduals[iCl].sec, -1, rej);
1066 mDetInfoRes.emplace_back().setTPC(mCacheDEDX[iRow].first, mCacheDEDX[iRow].second); // qtot, qmax
1067 ++nClValidated;
1068 } else {
1069 ++mRejectedResiduals;
1070 }
1071 }
1072 trackData.clIdx.setEntries(nClValidated);
1073
1074 // store multiplicity info
1075 for (int ist = 0; ist < NSTACKS; ist++) {
1076 int mltBinMin = 0x7ffff, mltBinMax = -1, prevBin = -1;
1077 for (int ir = STACKROWS[ist]; ir < STACKROWS[ist + 1]; ir++) {
1078 if (multBins[ir] != prevBin && multBins[ir] > 0) { // there is a cluster
1079 prevBin = multBins[ir];
1080 if (multBins[ir] > mltBinMax) {
1081 mltBinMax = multBins[ir];
1082 }
1083 if (multBins[ir] < mltBinMin) {
1084 mltBinMin = multBins[ir];
1085 }
1086 }
1087 }
1088 if (--mltBinMin >= 0) { // we were offsetting bin IDs by 1!
1089 float avMlt = 0;
1090 for (int ib = mltBinMin; ib < mltBinMax; ib++) {
1091 avMlt += mTPCParam->occupancyMap[ib];
1092 }
1093 avMlt /= (mltBinMax - mltBinMin);
1094 trackData.setMultStack(avMlt, ist);
1095 }
1096 }
1097
1098 bool stopPropagation = !mExtDetResid;
1099 if (!stopPropagation) {
1100 // do we have TRD residuals to add?
1101 int iSeedFull = mParentID[iSeed] == -1 ? iSeed : mParentID[iSeed];
1102 auto gidFull = mGIDs[iSeedFull];
1103 const auto& gidTableFull = mGIDtables[iSeedFull];
1104 if (gidTableFull[GTrackID::TRD].isIndexSet()) {
1105 const auto& trkTRD = mRecoCont->getITSTPCTRDTrack<o2::trd::TrackTRD>(gidTableFull[GTrackID::ITSTPCTRD]);
1106 trackData.nTrkltsTRD = trkTRD.getNtracklets();
1107 for (int iLayer = 0; iLayer < o2::trd::constants::NLAYER; iLayer++) {
1108 std::array<float, 2> trkltTRDYZ{};
1109 int res = processTRDLayer(trkTRD, iLayer, trkWork, &trkltTRDYZ, nullptr, &trackData, &trkl64, &trklCalib);
1110 if (res == -1) { // no traklet on this layer
1111 continue;
1112 }
1113 if (res < -1) { // failed to reach this layer
1114 stopPropagation = true;
1115 break;
1116 }
1117
1118 float tgPhi = trkWork.getSnp() / std::sqrt((1.f - trkWork.getSnp()) * (1.f + trkWork.getSnp()));
1119 auto dy = trkltTRDYZ[0] - trkWork.getY();
1120 auto dz = trkltTRDYZ[1] - trkWork.getZ();
1121 const auto sec = clusterResiduals[iCl].sec;
1122 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)) {
1123 mClRes.emplace_back(dy, dz, tgPhi, trkWork.getY(), trkWork.getZ(), 160 + iLayer, o2::math_utils::angle2Sector(trkWork.getAlpha()), (short)res);
1124 mDetInfoRes.emplace_back().setTRD(trkl64.getQ0(), trkl64.getQ1(), trkl64.getQ2(), trklCalib.getDy()); // q0,q1,q2,slope
1125 trackData.nExtDetResid++;
1126 }
1127 }
1128 }
1129
1130 // do we have TOF residual to add?
1131 trackData.clAvailTOF = 0;
1132 while (gidTableFull[GTrackID::TOF].isIndexSet() && !stopPropagation) {
1133 const auto& tofMatch = mRecoCont->getTOFMatch(gidFull);
1134 ULong64_t bclongtof = (tofMatch.getSignal() - 10000) * o2::tof::Geo::BC_TIME_INPS_INV;
1135 double t0forTOF = tofMatch.getFT0Best(); // setting t0 for TOF
1136 float t0forTOFwithinBC = t0forTOF - bclongtof * o2::tof::Geo::BC_TIME_INPS;
1137 float t0forTOFres = tofMatch.getFT0BestRes();
1138 trackData.deltaTOF = tofMatch.getSignal() - t0forTOF - tofMatch.getLTIntegralOut().getTOF(trkTPC.getPID().getID());
1139 trackData.clAvailTOF = uint16_t(t0forTOFres);
1140 const auto& clTOF = mRecoCont->getTOFClusters()[gidTableFull[GTrackID::TOF]];
1141 const float clTOFAlpha = o2::math_utils::sector2Angle(clTOF.getCount());
1142 float clTOFxyz[3] = {clTOF.getX(), clTOF.getY(), clTOF.getZ()};
1143 if (!clTOF.isInNominalSector()) {
1144 o2::tof::Geo::alignedToNominalSector(clTOFxyz, clTOF.getCount()); // go from the aligned to nominal sector frame
1145 }
1146 if (trkWork.getAlpha() != clTOFAlpha && !trkWork.rotate(clTOFAlpha)) {
1147 LOG(debug) << "Failed to rotate into TOF cluster sector frame";
1148 stopPropagation = true;
1149 break;
1150 }
1151 if (!propagator->PropagateToXBxByBz(trkWork, clTOFxyz[0], mParams->maxSnp, mParams->maxStep, mMatCorr)) {
1152 LOG(debug) << "Failed final propagation to TOF radius";
1153 break;
1154 }
1155
1156 float tgPhi = trkWork.getSnp() / std::sqrt((1.f - trkWork.getSnp()) * (1.f + trkWork.getSnp()));
1157 auto dy = clTOFxyz[1] - trkWork.getY();
1158 auto dz = clTOFxyz[2] - trkWork.getZ();
1159 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)) {
1160 mClRes.emplace_back(dy, dz, tgPhi, trkWork.getY(), trkWork.getZ(), 170, clTOF.getCount(), clTOF.getPadInSector());
1161 // get seeding track time
1162 if (!gidTableFull[GTrackID::ITSTPC].isIndexSet()) {
1163 LOGP(fatal, "ITS-TPC seed index is not set for TOF track");
1164 }
1165
1166 float tdif = static_cast<float>(clTOF.getTime() - t0forTOF); // time in \mus wrt interaction time0
1167 mDetInfoRes.emplace_back().setTOF(tdif * 1e-6); // time in \mus wrt seeding ITS-TPC track
1168 trackData.nExtDetResid++;
1169 }
1170 break;
1171 }
1172
1173 // add ITS residuals
1174 while (!stopPropagation) {
1175 o2::track::TrackPar trkWorkITS{trackData.par}; // this is ITS outer param
1176 auto nCl = trkITS.getNumberOfClusters();
1177 auto clEntry = trkITS.getFirstClusterEntry();
1178 auto geom = o2::its::GeometryTGeo::Instance();
1179 for (int iCl = 0; iCl < nCl; iCl++) { // clusters are stored from outer to inner layers
1180 const auto& cls = mITSClustersArray[mITSTrackClusIdx[clEntry + iCl]];
1181 int chip = cls.getSensorID();
1182 float chipX, chipAlpha;
1183 geom->getSensorXAlphaRefPlane(cls.getSensorID(), chipX, chipAlpha);
1184 if (!trkWorkITS.rotate(chipAlpha) || !propagator->propagateToX(trkWorkITS, chipX, mBz, mParams->maxSnp, mParams->maxStep, mMatCorr)) {
1185 LOGP(debug, "Failed final propagation to ITS X={} alpha={}", chipX, chipAlpha);
1186 stopPropagation = true;
1187 break;
1188 }
1189 float tgPhi = trkWorkITS.getSnp() / std::sqrt((1.f - trkWorkITS.getSnp()) * (1.f + trkWorkITS.getSnp()));
1190 auto dy = cls.getY() - trkWorkITS.getY();
1191 auto dz = cls.getZ() - trkWorkITS.getZ();
1192 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)) {
1193 mClRes.emplace_back(dy, dz, tgPhi, trkWorkITS.getY(), trkWorkITS.getZ(), 180 + geom->getLayer(cls.getSensorID()), -1, cls.getSensorID());
1194 mDetInfoRes.emplace_back(); // empty placeholder
1195 trackData.nExtDetResid++;
1196 }
1197 }
1198 if (!stopPropagation) { // add residual to PV
1199 const auto& pv = mRecoCont->getPrimaryVertices()[mTrackPVID[iSeed]];
1200 o2::math_utils::Point3D<float> vtx{pv.getX(), pv.getY(), pv.getZ()};
1201 if (!propagator->propagateToDCA(vtx, trkWorkITS, mBz, mParams->maxStep, mMatCorr)) {
1202 LOGP(debug, "Failed propagation to DCA to PV ({} {} {}), {}", pv.getX(), pv.getY(), pv.getZ(), trkWorkITS.asString());
1203 stopPropagation = true;
1204 break;
1205 }
1206 // rotate PV to the track frame
1207 float sn, cs, alpha = trkWorkITS.getAlpha();
1208 math_utils::detail::bringToPMPi(alpha);
1209 math_utils::detail::sincos<float>(alpha, sn, cs);
1210 float xv = vtx.X() * cs + vtx.Y() * sn, yv = -vtx.X() * sn + vtx.Y() * cs, zv = vtx.Z();
1211 auto dy = yv - trkWorkITS.getY();
1212 auto dz = zv - trkWorkITS.getZ();
1213 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) {
1214 short compXV = static_cast<short>(xv * 0x7fff / param::MaxVtxX);
1215 mClRes.emplace_back(dy, dz, alpha / TMath::Pi(), trkWorkITS.getY(), trkWorkITS.getZ(), 190, -1, compXV);
1216 if (!gidTableFull[GTrackID::ITSTPC].isIndexSet()) {
1217 LOGP(fatal, "ITS-TPC seed index is not set for TOF track");
1218 }
1219 float tdif = pv.getTimeStamp().getTimeStamp() - mRecoCont->getTPCITSTrack(gidTableFull[GTrackID::ITSTPC]).getTimeMUS().getTimeStamp();
1220 mDetInfoRes.emplace_back().setPV(tdif); // time in \mus wrt seeding ITS-TPC track
1221 trackData.nExtDetResid++;
1222 }
1223 }
1224 break;
1225 }
1226 }
1227 mTrackData.push_back(std::move(trackData));
1228 stored = true;
1229 mGIDsSuccess.push_back(mGIDs[iSeed]);
1230 mTrackDataCompact.emplace_back(trackData.clIdx.getFirstEntry(), trackData.multStack, nClValidated, mGIDs[iSeed].getSource(), trackData.nExtDetResid, trackData.filterFlag);
1231 if (mDumpTrackPoints) {
1232 (*trackDataExtended).clIdx.setEntries(nClValidated);
1233 (*trackDataExtended).nExtDetResid = trackData.nExtDetResid;
1234 (*trackDataExtended).filterFlag = trackData.filterFlag;
1235 mTrackDataExtended.push_back(std::move(*trackDataExtended));
1236 }
1237 }
1238 if (mParams->writeValidationData && trackData.filterFlag >= 0 && mDBGOut) {
1239 (*mDBGOut) << "valdata" << "params=" << mTrackValidation << "trackData=" << (stored ? mTrackData.back() : trackData) << "\n";
1240 }
1241}
1242
1243int8_t TrackInterpolation::validateTrack(const TrackData& trk, TrackValidationData& params, const std::vector<TPCClusterResiduals>& clsRes, bool interpol)
1244{
1245 int8_t status = 0;
1246 while (true) {
1247 if (clsRes.size() < mParams->minNCl) {
1248 // no enough clusters for this track to be considered
1249 LOG(debug) << "Skipping track with too few clusters: " << clsRes.size();
1250 status |= 0x1;
1251 if (!mParams->keepRejectedResiduals) {
1252 break; // we don't keep de-validated tracks, no need to check further
1253 }
1254 }
1255
1256 bool resHelix = compareToHelix(trk, params, clsRes);
1257 if (!resHelix && interpol) {
1258 LOG(debug) << "Skipping track too far from helix approximation";
1259 status |= 0x1 << 1;
1260 if (!mParams->keepRejectedResiduals) {
1261 break; // we don't keep de-validated tracks, no need to check further
1262 }
1263 }
1264 if (interpol && (std::abs(mBz) > 0.01 && std::abs(params.qpt) > mParams->maxQ2Pt)) {
1265 LOG(debug) << "Skipping track with too high q/pT: " << params.qpt;
1266 status |= 0x1 << 2;
1267 if (!mParams->keepRejectedResiduals) {
1268 break; // we don't keep de-validated tracks, no need to check further
1269 }
1270 }
1271 if (!outlierFiltering(trk, params, clsRes)) {
1272 status |= 0x1 << 3;
1273 if (!mParams->keepRejectedResiduals) {
1274 break; // we don't keep de-validated tracks, no need to check further
1275 }
1276 }
1277 break;
1278 }
1279 return status & 0x7f;
1280}
1281
1282bool TrackInterpolation::compareToHelix(const TrackData& trk, TrackValidationData& params, const std::vector<TPCClusterResiduals>& clsRes)
1283{
1284 float curvature = std::abs(trk.par.getQ2Pt() * mBz * o2::constants::physics::LightSpeedCm2S * 1e-14f);
1285 int secFirst = clsRes[0].sec;
1286 float phiSect = (secFirst + .5f) * o2::constants::math::SectorSpanRad;
1287 float snPhi = sin(phiSect);
1288 float csPhi = cos(phiSect);
1289
1290 int iRow = 0;
1291 int nCl = clsRes.size();
1292 for (unsigned int iP = 0; iP < nCl; ++iP) {
1293 auto& point = params.points.emplace_back();
1294
1295 iRow += clsRes[iP].dRow;
1296 point.yTrk = clsRes[iP].y;
1297 point.sec = clsRes[iP].sec;
1298 if (clsRes[iP].sec != secFirst) {
1299 float phiSectCurrent = (clsRes[iP].sec + .5f) * o2::constants::math::SectorSpanRad;
1300 float cs = cos(phiSectCurrent - phiSect);
1301 float sn = sin(phiSectCurrent - phiSect);
1302 point.xLab = param::RowX[iRow] * cs - point.yTrk * sn;
1303 point.yLab = point.yTrk * cs + param::RowX[iRow] * sn;
1304 } else {
1305 point.xLab = param::RowX[iRow];
1306 point.yLab = point.yTrk;
1307 }
1308 // this is needed only later, but we retrieve it already now to save another loop
1309 point.zTrk = clsRes[iP].z;
1310 point.xTrk = param::RowX[iRow];
1311 point.dy = clsRes[iP].dy;
1312 point.dz = clsRes[iP].dz;
1313 // done retrieving values for later
1314 if (iP > 0) {
1315 float dx = point.xLab - params.points[iP - 1].xLab;
1316 float dy = point.yLab - params.points[iP - 1].yLab;
1317 float ds2 = dx * dx + dy * dy;
1318 float ds = sqrt(ds2); // circular path (linear approximation)
1319 // if the curvature of the track or the (approximated) chord length is too large the more exact formula is used:
1320 // chord length = 2r * asin(ds/(2r))
1321 // using the first two terms of the tailer expansion for asin(x) ~ x + x^3 / 6
1322 if (ds * curvature > 0.05) {
1323 ds *= (1.f + ds2 * curvature * curvature / 24.f);
1324 }
1325 point.sPath = params.points[iP - 1].sPath + ds;
1326 } else {
1327 point.sPath = 0;
1328 }
1329 }
1330 if (std::abs(mBz) < 0.01) {
1331 // for B=0 we don't need to try a circular fit...
1332 return true;
1333 }
1335 // determine curvature
1336 float phiI = TMath::ATan2(params.points.front().yLab, params.points.front().xLab);
1337 float phiF = TMath::ATan2(params.points.back().yLab, params.points.back().xLab);
1338 if (phiI < 0) {
1340 }
1341 if (phiF < 0) {
1343 }
1344 float dPhi = phiF - phiI;
1345 float curvSign = -1.f;
1346 if (dPhi > 0) {
1347 if (dPhi < o2::constants::math::PI) {
1348 curvSign = 1.f;
1349 }
1350 } else if (dPhi < -o2::constants::math::PI) {
1351 curvSign = 1.f;
1352 }
1353 params.qpt = std::copysign(1.f / (params.r * mBz * o2::constants::physics::LightSpeedCm2S * 1e-14f), curvSign);
1354
1356
1357 // max deviations in both directions from helix fit in y and z
1358 float hMinY = 1e9f;
1359 float hMaxY = -1e9f;
1360 float hMinZ = 1e9f;
1361 float hMaxZ = -1e9f;
1362 // extract residuals in Z and fill track slopes in sector frame
1363 int secCurr = -1;
1364 iRow = 0;
1365 float xcSec = 0;
1366 for (unsigned int iCl = 0; iCl < nCl; ++iCl) {
1367 iRow += clsRes[iCl].dRow;
1368 auto& pnt = params.points[iCl];
1369 pnt.residHelixZ = pnt.zTrk - (params.zOffs + pnt.sPath * params.tgl);
1370 if (pnt.residHelixZ < hMinZ) {
1371 hMinZ = pnt.residHelixZ;
1372 }
1373 if (pnt.residHelixZ > hMaxZ) {
1374 hMaxZ = pnt.residHelixZ;
1375 }
1376 if (pnt.residHelixY < hMinY) {
1377 hMinY = pnt.residHelixY;
1378 }
1379 if (pnt.residHelixY > hMaxY) {
1380 hMaxY = pnt.residHelixY;
1381 }
1382 int sec = clsRes[iCl].sec;
1383 if (sec != secCurr) {
1384 secCurr = sec;
1385 phiSect = (.5f + sec) * o2::constants::math::SectorSpanRad;
1386 snPhi = sin(phiSect);
1387 csPhi = cos(phiSect);
1388 xcSec = params.xcLab * csPhi + params.ycLab * snPhi; // recalculate circle center in the new sector frame
1389 }
1390 float cstalp = (param::RowX[iRow] - xcSec) / params.r;
1391 if (std::abs(cstalp) > 1.f - sFloatEps) {
1392 // track cannot reach this pad row
1393 cstalp = std::copysign(1.f - sFloatEps, cstalp);
1394 }
1395 pnt.tglArr = cstalp / sqrt((1 - cstalp) * (1 + cstalp)); // 1 / tan(acos(cstalp)) = cstalp / sqrt(1 - cstalp^2)
1396
1397 // In B+ the slope of q- should increase with x. Just look on q * B
1398 if (params.qpt * mBz > 0) {
1399 pnt.tglArr = -pnt.tglArr;
1400 }
1401 }
1402 // 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);
1403 // LOGF(info, "New pt/Q (%f), old pt/Q (%f)", 1./params.qpt, 1./trk.qPt);
1404 return std::abs(hMaxY - hMinY) < mParams->maxDevHelixY && std::abs(hMaxZ - hMinZ) < mParams->maxDevHelixZ;
1405}
1406
1407bool TrackInterpolation::outlierFiltering(const TrackData& trk, TrackValidationData& params, const std::vector<TPCClusterResiduals>& clsRes)
1408{
1409 if (clsRes.size() < mParams->nMALong) {
1410 LOG(debug) << "Skipping track with too few clusters for long moving average: " << clsRes.size();
1411 return false;
1412 }
1413 float rmsLong = checkResiduals(trk, params, clsRes);
1414 if (static_cast<float>(params.nRej) / clsRes.size() > mParams->maxRejFrac) {
1415 LOGP(debug, "Skipping track with too many clusters rejected: {} out of {}", params.nRej, clsRes.size());
1416 return false;
1417 }
1418 if (rmsLong > mParams->maxRMSLong) {
1419 LOG(debug) << "Skipping track with too large RMS: " << rmsLong;
1420 return false;
1421 }
1422 return true;
1423}
1424
1425float TrackInterpolation::checkResiduals(const TrackData& trk, TrackValidationData& params, const std::vector<TPCClusterResiduals>& clsRes)
1426{
1427 float rmsLong = 0.f;
1428
1429 int nCl = clsRes.size();
1430 int iClFirst = 0;
1431 int iClLast = nCl - 1;
1432 int secStart = clsRes[0].sec;
1433
1434 auto rejectAll = [&params]() {
1435 for (auto& pnt : params.points) {
1436 pnt.flagRej = true;
1437 }
1438 params.nRej = params.points.size();
1439 };
1440
1441 // arrays with differences / abs(differences) of points to their neighbourhood, initialized to zero
1442 std::array<float, param::NPadRows> absDevY{};
1443 std::array<float, param::NPadRows> absDevZ{};
1444
1445 for (unsigned int iCl = 0; iCl < nCl; ++iCl) {
1446 if (iCl < iClLast && clsRes[iCl].sec == secStart) {
1447 continue;
1448 }
1449 // sector changed or last cluster reached
1450 // now run estimators for all points in the same sector
1451 int nClSec = iCl - iClFirst;
1452 if (iCl == iClLast) {
1453 ++nClSec;
1454 }
1455 diffToLocLine(params, iClFirst, nClSec);
1456 iClFirst = iCl;
1457 secStart = clsRes[iCl].sec;
1458 }
1459 // store abs deviations
1460 int nAccY = 0;
1461 int nAccZ = 0;
1462 for (int iCl = nCl; iCl--;) {
1463 const auto pnt = params.points[iCl];
1464 if (std::abs(pnt.diffYSmooth) > param::sEps) {
1465 absDevY[nAccY++] = std::abs(pnt.diffYSmooth);
1466 }
1467 if (std::abs(pnt.diffZSmooth) > param::sEps) {
1468 absDevZ[nAccZ++] = std::abs(pnt.diffZSmooth);
1469 }
1470 }
1471 if (nAccY < mParams->minNumberOfAcceptedResiduals || nAccZ < mParams->minNumberOfAcceptedResiduals) {
1472 // mask all clusters
1473 LOGP(debug, "Accepted {} clusters for dY {} clusters for dZ, but required at least {} for both", nAccY, nAccZ, mParams->minNumberOfAcceptedResiduals);
1474 rejectAll();
1475 return 0.f;
1476 }
1477 // estimate rms on 90% of the smallest deviations
1478 int nKeepY = static_cast<int>(.9 * nAccY);
1479 int nKeepZ = static_cast<int>(.9 * nAccZ);
1480 std::nth_element(absDevY.begin(), absDevY.begin() + nKeepY, absDevY.begin() + nAccY);
1481 std::nth_element(absDevZ.begin(), absDevZ.begin() + nKeepZ, absDevZ.begin() + nAccZ);
1482 float rmsYkeep = 0.f;
1483 float rmsZkeep = 0.f;
1484 for (int i = nKeepY; i--;) {
1485 rmsYkeep += absDevY[i] * absDevY[i];
1486 }
1487 for (int i = nKeepZ; i--;) {
1488 rmsZkeep += absDevZ[i] * absDevZ[i];
1489 }
1490 rmsYkeep = std::sqrt(rmsYkeep / nKeepY);
1491 rmsZkeep = std::sqrt(rmsZkeep / nKeepZ);
1492 if (rmsYkeep < param::sEps || rmsZkeep < param::sEps) {
1493 LOG(warning) << "Too small RMS: " << rmsYkeep << "(y), " << rmsZkeep << "(z).";
1494 rejectAll();
1495 return 0.f;
1496 }
1497 float rmsYkeepI = 1.f / rmsYkeep;
1498 float rmsZkeepI = 1.f / rmsZkeep;
1499 int nAcc = 0;
1500 std::array<float, param::NPadRows> yAcc;
1501 std::array<float, param::NPadRows> yDiffLong;
1502 for (int iCl = 0; iCl < nCl; ++iCl) {
1503 auto& pnt = params.points[iCl];
1504 auto yDiffScl = pnt.diffYSmooth * rmsYkeepI;
1505 auto zDiffScl = pnt.diffZSmooth * rmsZkeepI;
1506 if (yDiffScl * yDiffScl + zDiffScl * zDiffScl > mParams->maxStdDevMA) {
1507 pnt.flagRej = true;
1508 params.nRej++;
1509 } else {
1510 yAcc[nAcc++] = pnt.dy;
1511 }
1512 }
1513 if (nAcc > mParams->nMALong) {
1514 diffToMA(nAcc, yAcc, yDiffLong);
1515 float average = 0.f, rms = 0.f;
1516 for (int i = 0; i < nAcc; ++i) {
1517 average += yDiffLong[i];
1518 rms += yDiffLong[i] * yDiffLong[i];
1519 }
1520 average /= nAcc;
1521 rmsLong = rms / nAcc - average * average;
1522 rmsLong = (rmsLong > 0) ? std::sqrt(rmsLong) : 0.f;
1523 }
1524 return rmsLong;
1525}
1526
1528{
1529 std::array<float, param::NPadRows + 1> sumX1{}, sumX2{}, sumY1{}, sumXY{}, sumZ1{}, sumXZ{};
1530 for (int i = 0; i < np; ++i) {
1531 const auto& pnt = params.points[start + i];
1532 const float x = pnt.xTrk, y = pnt.dy, z = pnt.dz;
1533 sumX1[i + 1] = sumX1[i] + x;
1534 sumX2[i + 1] = sumX2[i] + x * x;
1535 sumY1[i + 1] = sumY1[i] + y;
1536 sumXY[i + 1] = sumXY[i] + x * y;
1537 sumZ1[i + 1] = sumZ1[i] + z;
1538 sumXZ[i + 1] = sumXZ[i] + x * z;
1539 }
1540
1541 for (int i = 0; i < np; ++i) {
1542 auto& pnt = params.points[start + i];
1543
1544 const int iLeft = std::max(0, i - mParams->nMAShort);
1545 const int iRight = std::min(np - 1, i + mParams->nMAShort);
1546
1547 const int nPoints = iRight - iLeft; // excluding current point
1548
1549 if (nPoints < mParams->nMAShort) {
1550 continue;
1551 }
1552
1553 const float nPointsInv = 1.f / nPoints;
1554
1555 float sX1 = sumX1[iRight + 1] - sumX1[iLeft] - pnt.xTrk;
1556 float sX2 = sumX2[iRight + 1] - sumX2[iLeft] - pnt.xTrk * pnt.xTrk;
1557 float sY1 = sumY1[iRight + 1] - sumY1[iLeft] - pnt.dy;
1558 float sXY = sumXY[iRight + 1] - sumXY[iLeft] - pnt.xTrk * pnt.dy;
1559 float sZ1 = sumZ1[iRight + 1] - sumZ1[iLeft] - pnt.dz;
1560 float sXZ = sumXZ[iRight + 1] - sumXZ[iLeft] - pnt.xTrk * pnt.dz;
1561
1562 const float det = sX2 - nPointsInv * sX1 * sX1;
1563
1564 if (std::abs(det) < 1e-12f) {
1565 continue;
1566 }
1567
1568 const float slopeY = (sXY - nPointsInv * sX1 * sY1) / det;
1569 const float offsetY = nPointsInv * (sY1 - slopeY * sX1);
1570 const float slopeZ = (sXZ - nPointsInv * sX1 * sZ1) / det;
1571 const float offsetZ = nPointsInv * (sZ1 - slopeZ * sX1);
1572 pnt.diffYSmooth = pnt.dy - (slopeY * pnt.xTrk + offsetY);
1573 pnt.diffZSmooth = pnt.dz - (slopeZ * pnt.xTrk + offsetZ);
1574 }
1575}
1576
1577void TrackInterpolation::diffToMA(const int np, const std::array<float, param::NPadRows>& y, std::array<float, param::NPadRows>& diffMA)
1578{
1579 // Calculate
1580 std::array<float, param::NPadRows + 1> sum{};
1581 for (int i = 0; i < np; ++i) {
1582 sum[i + 1] = sum[i] + y[i];
1583 }
1584 for (int i = 0; i < np; ++i) {
1585 diffMA[i] = 0.f;
1586 int iLeft = std::max(0, i - mParams->nMALong);
1587 int iRight = std::min(np - 1, i + mParams->nMALong);
1588 int nPoints = iRight - iLeft;
1589 if (nPoints < mParams->nMALong) { // this cannot happen, since at least mParams->nMALong points are required as neighbours for this function to be called
1590 continue;
1591 }
1592 float movingAverage = (sum[iRight + 1] - sum[iLeft] - y[i]) / nPoints;
1593 diffMA[i] = y[i] - movingAverage;
1594 }
1595}
1596
1598{
1599 mTrackData.clear();
1600 mTrackDataCompact.clear();
1601 mTrackDataExtended.clear();
1602 mClRes.clear();
1603 mDetInfoRes.clear();
1604 mGIDsSuccess.clear();
1605 for (auto& vec : mTrackIndices) {
1606 vec.clear();
1607 }
1608 mGIDs.clear();
1609 mGIDtables.clear();
1610 mTrackTimes.clear();
1611 mSeeds.clear();
1612 mITSRefitSeedID.clear();
1613 mTrackPVID.clear();
1614}
1615
1616//______________________________________________
1618{
1619 // 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
1620 if (v.refVDrift != mTPCVDriftRef) {
1621 mTPCVDriftRef = v.refVDrift;
1622 mTPCDriftTimeOffsetRef = v.refTimeOffset;
1623 LOGP(info, "Imposing reference VDrift={}/TDrift={} for TPC residuals extraction", mTPCVDriftRef, mTPCDriftTimeOffsetRef);
1624 o2::tpc::TPCFastTransformHelperO2::instance()->updateCalibration(*mFastTransform, 0, 1.0, mTPCVDriftRef, mTPCDriftTimeOffsetRef);
1625 }
1626}
1627
1628//______________________________________________
1630{
1631 // refit ITS track outwards taking PID (unless already refitted) from the seed and reassign to the seed
1632 auto& seed = mSeeds[seedID];
1633 int refitID = mITSRefitSeedID[gid.getIndex()];
1634 if (refitID >= 0) { // track was already refitted
1635 if (mSeeds[refitID].getPID() == seed.getPID()) {
1636 seed = mSeeds[refitID];
1637 }
1638 return true;
1639 }
1640 const auto& trkITS = mRecoCont->getITSTrack(gid);
1641 // fetch clusters
1642 auto nCl = trkITS.getNumberOfClusters();
1643 auto clEntry = trkITS.getFirstClusterEntry();
1644 o2::track::TrackParCov track(trkITS); // start from the inner param
1645 track.resetCovariance();
1646 track.setCov(track.getQ2Pt() * track.getQ2Pt() * track.getCov()[o2::track::CovLabels::kSigQ2Pt2], o2::track::CovLabels::kSigQ2Pt2);
1647 track.setPID(seed.getPID());
1648 o2::track::TrackPar refLin(track); // and use it also as linearization reference
1649 auto geom = o2::its::GeometryTGeo::Instance();
1650 auto prop = o2::base::Propagator::Instance();
1651 for (int iCl = nCl - 1; iCl >= 0; iCl--) { // clusters are stored from outer to inner layers
1652 const auto& cls = mITSClustersArray[mITSTrackClusIdx[clEntry + iCl]];
1653 int chip = cls.getSensorID();
1654 float chipX, chipAlpha;
1655 geom->getSensorXAlphaRefPlane(cls.getSensorID(), chipX, chipAlpha);
1656 if (!track.rotate(chipAlpha, refLin, mBz)) {
1657 LOGP(debug, "failed to rotate ITS tracks to alpha={} for the refit: {}", chipAlpha, track.asString());
1658 return false;
1659 }
1660 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)) {
1661 LOGP(debug, "failed to propagate ITS tracks to X={}: {}", cls.getX(), track.asString());
1662 return false;
1663 }
1664 std::array<float, 2> posTF{cls.getY(), cls.getZ()};
1665 std::array<float, 3> covTF{cls.getSigmaY2(), cls.getSigmaYZ(), cls.getSigmaZ2()};
1666 if (!track.update(posTF, covTF)) {
1667 LOGP(debug, "failed to update ITS tracks by cluster ({},{})/({},{},{})", track.asString(), cls.getY(), cls.getZ(), cls.getSigmaY2(), cls.getSigmaYZ(), cls.getSigmaZ2());
1668 return false;
1669 }
1670 if (mParams->shiftRefToCluster) {
1671 refLin.setY(posTF[0]);
1672 refLin.setZ(posTF[1]);
1673 }
1674 }
1675 seed = track;
1676 // memorize that this ITS track was already refitted
1677 mITSRefitSeedID[gid.getIndex()] = seedID;
1678 return true;
1679}
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
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
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
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