Project
Loading...
Searching...
No Matches
TRDGlobalTrackingSpec.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
13
14#include <TMap.h>
15#include <TObjString.h>
17#include "TRDBase/Geometry.h"
37#include "ITStracking/IOUtils.h"
45
46// GPU header
47#include "GPUReconstruction.h"
48#include "GPUChainTracking.h"
49#include "GPUChainTrackingGetters.inc"
51#include "GPUO2InterfaceUtils.h"
52#include "GPUSettings.h"
54#include "GPUDataTypesIO.h"
55#include "GPUTRDDef.h"
56#include "GPUTRDTrack.h"
57#include "GPUTRDTrackletWord.h"
58#include "GPUTRDInterfaces.h"
59#include "GPUTRDGeometry.h"
60#include "GPUConstantMem.h"
62
63#ifdef ENABLE_UPGRADES
65#endif
66
67#include <regex>
68#include <algorithm>
69#include <numeric>
70
71using namespace o2::framework;
72using namespace o2::gpu;
73using namespace o2::globaltracking;
74using namespace o2::trd::constants;
75
77
78namespace o2
79{
80namespace trd
81{
82
84
86{
88 mTimer.Stop();
89 mTimer.Reset();
90}
91
92void TRDGlobalTracking::updateTimeDependentParams(ProcessingContext& pc)
93{
95 mTPCVDriftHelper.extractCCDBInputs(pc);
96
97 auto const& raw = pc.inputs().get<const char*>("corrMap");
98 mTPCCorrMaps = &o2::gpu::TPCFastTransformPOD::get(raw);
99 float lumiCTP = mRequestCTPLumi ? pc.inputs().get<float>("lumiCTP") : 0;
100
101 // pc.inputs().get<TopologyDictionary*>("cldict"); // called by the RecoContainer to trigger finaliseCCDB
102 static bool initOnceDone = false;
103 if (!initOnceDone) { // this params need to be queried only once
104 initOnceDone = true;
105 // init-once stuff
106
107 auto geo = Geometry::instance();
109 geo->createPadPlaneArray();
110 geo->createClusterMatrixArray();
111 mFlatGeo = std::make_unique<GeometryFlat>(*geo);
112
113 GPURecoStepConfiguration cfgRecoStep;
114 cfgRecoStep.steps = gpudatatypes::RecoStep::NoRecoStep;
115 cfgRecoStep.inputs.clear();
116 cfgRecoStep.outputs.clear();
117 mRec = GPUReconstruction::CreateInstance("CPU", true);
118
120 config.ReadConfigurableParam(config);
122 config.configProcessing.o2PropagatorUseGPUField = false;
123 mRecoParam.init(o2::base::Propagator::Instance()->getNominalBz(), &config.configReconstruction);
124
125 mRec->SetSettings(&config.configGRP, &config.configReconstruction, &config.configProcessing, &cfgRecoStep);
126
127 mChainTracking = mRec->AddChain<GPUChainTracking>();
129
130 mTracker = new GPUTRDTracker();
131 mTracker->SetNCandidates(mRec->GetProcessingSettings().trdNCandidates); // must be set before initialization
132 if (mStrict && mRec->GetProcessingSettings().trdNCandidates == 1) {
133 LOG(error) << "Strict matching mode requested, but tracks with another close hypothesis will not be rejected. Please set trdNCandidates to at least 3.";
134 }
135 mTracker->SetProcessPerTimeFrame(true);
136 mTracker->SetGenerateSpacePoints(false); // set to true to force space point calculation by the TRD tracker itself
137
138 mRec->RegisterGPUProcessor(mTracker, false);
139 mChainTracking->SetTRDGeometry(std::move(mFlatGeo));
140 mChainTracking->SetTRDRecoParam(&mRecoParam);
141 if (mRec->Init()) {
142 LOG(fatal) << "GPUReconstruction could not be initialized";
143 }
144
145 mTracker->PrintSettings();
146 LOG(info) << "Strict matching mode is " << ((mStrict) ? "ON" : "OFF");
147 LOGF(info, "The search road in time for ITS-TPC tracks is set to %.1f sigma and %.2f us are added to it on top",
148 mRec->GetParam().rec.trd.nSigmaTerrITSTPC, mRec->GetParam().rec.trd.addTimeRoadITSTPC);
149
151 if (mWithPID) {
152 mBase = getTRDPIDPolicy(mPolicy);
153 mBase->init(pc);
154 mBase->setLocalGainFactors(pc.inputs().get<o2::trd::LocalGainFactor*>("localgainfactors").get());
155 }
156 }
157
158 const auto& trackTune = TrackTuneParams::Instance();
159 float scale = lumiCTP;
160 if (scale < 0.f) {
161 scale = 0.f;
162 }
163 mCovDiagInner = trackTune.getCovInnerTotal(scale);
164 mCovDiagOuter = trackTune.getCovOuterTotal(scale);
165
166 if (mTPCVDriftHelper.isUpdated()) {
168 mTPCTBinMUS = elParam.ZbinWidth;
169 mTPCTBinMUSInv = 1. / mTPCTBinMUS;
170 auto& vd = mTPCVDriftHelper.getVDriftObject();
171 mTPCVdrift = vd.getVDrift();
172 mTPCTDriftOffset = vd.getTimeOffset();
173 LOGP(info, "Updating TPC VDrift factor of {} wrt reference {} and DriftTimeOffset correction {} wrt {} from source {}",
174 vd.corrFact, vd.refVDrift, vd.timeOffsetCorr, vd.refTimeOffset, mTPCVDriftHelper.getSourceName());
175 mTracker->SetTPCVdrift(mTPCVdrift);
176 mTracker->SetTPCTDriftOffset(mTPCTDriftOffset);
177 mTPCVDriftHelper.acknowledgeUpdate();
178 }
179}
180
182{
184 return;
185 }
186 if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) {
187 return;
188 }
189 if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) {
190 LOG(info) << "cluster dictionary updated";
191 mITSDict = (const o2::itsmft::TopologyDictionary*)obj;
192 return;
193 }
194#ifdef ENABLE_UPGRADES
195 if (matcher == ConcreteDataMatcher("IT3", "CLUSDICT", 0)) {
196 LOG(info) << "it3 cluster dictionary updated";
197 mIT3Dict = (const o2::its3::TopologyDictionary*)obj;
198 return;
199 }
200#endif
201}
202
203void TRDGlobalTracking::fillMCTruthInfo(const TrackTRD& trk, o2::MCCompLabel lblSeed, std::vector<o2::MCCompLabel>& lblContainerTrd, std::vector<o2::MCCompLabel>& lblContainerMatch, const o2::dataformats::MCTruthContainer<o2::MCCompLabel>* trkltLabels) const
204{
205 // Check MC labels of the TRD tracklets attached to the track seed.
206 // Set TRD track label to the most frequent tracklet label.
207 // Fake flag is set if either not all TRD tracklets have most frequent label
208 // or if the seeding label is different from the most frequent TRD label.
209 // In case multiple tracklet labels occur most often we choose the one which matches the label of the seed, or,
210 // if that is not the case one of the most frequent labels is chosen arbitrarily
211 LOG(debug) << "Checking seed with label: " << lblSeed;
212 std::unordered_map<o2::MCCompLabel, unsigned int> labelCounter;
213 int maxOccurences = 0;
214 for (int iLy = 0; iLy < constants::NLAYER; ++iLy) {
215 auto trkltIndex = trk.getTrackletIndex(iLy);
216 if (trkltIndex == -1) {
217 // no tracklet in this layer
218 continue;
219 }
220 const auto& lblsTrklt = trkltLabels->getLabels(trkltIndex);
221 for (const auto lblTrklt : lblsTrklt) {
222 int nOcc = ++labelCounter[lblTrklt];
223 if (nOcc > maxOccurences) {
224 maxOccurences = nOcc;
225 }
226 }
227 }
228 o2::MCCompLabel mostFrequentLabel;
229 for (const auto& [lbl, count] : labelCounter) {
230 LOG(debug) << "Label " << lbl << " occured " << count << " times.";
231 if (count == maxOccurences) {
232 if (lblSeed == lbl) {
233 // most frequent label matches seed label
234 mostFrequentLabel = lbl;
235 mostFrequentLabel.setFakeFlag(maxOccurences != trk.getNtracklets());
236 lblContainerTrd.push_back(mostFrequentLabel);
237 lblContainerMatch.push_back(lblSeed); // is not fake by definition, since the seed label matches the TRD track label
238 return;
239 } else {
240 // maybe multiple labels occur with the same frequency and the next one might match the seed?
241 mostFrequentLabel = lbl;
242 }
243 }
244 }
245 mostFrequentLabel.setFakeFlag(maxOccurences != trk.getNtracklets());
246 lblContainerTrd.push_back(mostFrequentLabel);
247 lblSeed.setFakeFlag(lblSeed != mostFrequentLabel);
248 lblContainerMatch.push_back(lblSeed);
249}
250
251void TRDGlobalTracking::fillTrackTriggerRecord(const std::vector<TrackTRD>& tracks, std::vector<TrackTriggerRecord>& trigRec, const gsl::span<const o2::trd::TriggerRecord>& trackletTrigRec) const
252{
253 // after the tracking is done we assemble here a TrackTriggerRecord similar to the TriggerRecord
254 // which for each TRD trigger stores the index of the first found track and the total number of tracks
255
256 int nTracksCurr = 0;
257 int iTrackFirst = 0;
258 int prevCollisionID = -1;
259
260 for (size_t iTrk = 0; iTrk < tracks.size(); ++iTrk) {
261 const auto& trk = tracks[iTrk];
262 auto collisionID = trk.getCollisionId();
263 if (iTrk == 0) {
264 prevCollisionID = collisionID;
265 }
266 if (collisionID != prevCollisionID) {
267 // we have a track from a new trigger within the same TF
268 trigRec.emplace_back(trackletTrigRec[prevCollisionID].getBCData(), iTrackFirst, nTracksCurr);
269 iTrackFirst += nTracksCurr;
270 prevCollisionID = collisionID;
271 nTracksCurr = 0;
272 }
273 ++nTracksCurr;
274 }
275 if (nTracksCurr > 0) {
276 // this is the last trigger record for this TF, we can take the collision ID from the last track
277 trigRec.emplace_back(trackletTrigRec[tracks.back().getCollisionId()].getBCData(), iTrackFirst, nTracksCurr);
278 }
279}
280
282{
283 mTimer.Start(false);
285 inputTracks.collectData(pc, *mDataRequest);
286 updateTimeDependentParams(pc);
287 storeConfigs(pc);
288 mChainTracking->ClearIOPointers();
289
290 mTPCClusterIdxStruct = &inputTracks.inputsTPCclusters->clusterIndex;
291 mTPCRefitter = std::make_unique<o2::gpu::GPUO2InterfaceRefit>(mTPCClusterIdxStruct, mTPCCorrMaps, o2::base::Propagator::Instance()->getNominalBz(), inputTracks.getTPCTracksClusterRefs().data(), 0, inputTracks.clusterShMapTPC.data(), inputTracks.occupancyMapTPC.data(), inputTracks.occupancyMapTPC.size(), nullptr, o2::base::Propagator::Instance());
292 auto tmpInputContainer = getRecoInputContainer(pc, &mChainTracking->mIOPtrs, &inputTracks, mUseMC);
293 auto tmpContainer = GPUWorkflowHelper::fillIOPtr(mChainTracking->mIOPtrs, inputTracks, mUseMC, nullptr, GTrackID::getSourcesMask("TRD"), mTrkMask, GTrackID::mask_t{GTrackID::MASK_NONE});
294 mTrackletsRaw = inputTracks.getTRDTracklets();
295 mTrackletsCalib = inputTracks.getTRDCalibratedTracklets();
296 mTPCTracksArray = inputTracks.getTPCTracks();
297 if (GTrackID::includesDet(GTrackID::DetID::ITS, mTrkMask)) {
298 // load ITS tracks and clusters needed for the refit
299 mITSTracksArray = inputTracks.getITSTracks();
300 mITSTrackClusIdx = inputTracks.getITSTracksClusterRefs();
301 mITSABRefsArray = inputTracks.getITSABRefs();
302 mITSABTrackClusIdx = inputTracks.getITSABClusterRefs();
303 const auto clusITS = inputTracks.getITSClusters();
304 const auto patterns = inputTracks.getITSClustersPatterns();
305 auto pattIt = patterns.begin();
306 mITSClustersArray.clear();
307 mITSClustersArray.reserve(clusITS.size());
308#ifdef ENABLE_UPGRADES
309 if (o2::GlobalParams::Instance().withITS3) {
310 o2::its3::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mIT3Dict);
311 } else {
312 o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict);
313 }
314#else
315 o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict);
316#endif
317 }
318
319 LOGF(info, "There are %i tracklets in total from %i trigger records", mChainTracking->mIOPtrs.nTRDTracklets, mChainTracking->mIOPtrs.nTRDTriggerRecords);
320 LOGF(info, "As input seeds are available: %i ITS-TPC matched tracks and %i TPC tracks", mChainTracking->mIOPtrs.nTracksTPCITSO2, mChainTracking->mIOPtrs.nOutputTracksTPCO2);
321
322 std::vector<o2::MCCompLabel> matchLabelsITSTPC;
323 std::vector<o2::MCCompLabel> trdLabelsITSTPC;
324 std::vector<o2::MCCompLabel> matchLabelsTPC;
325 std::vector<o2::MCCompLabel> trdLabelsTPC;
326 gsl::span<const o2::MCCompLabel> tpcTrackLabels;
327 gsl::span<const o2::MCCompLabel> itstpcTrackLabels;
328 if (mUseMC) {
329 if (GTrackID::includesSource(GTrackID::Source::ITSTPC, mTrkMask)) {
330 itstpcTrackLabels = inputTracks.getTPCITSTracksMCLabels();
331 }
332 if (GTrackID::includesSource(GTrackID::Source::TPC, mTrkMask)) {
333 tpcTrackLabels = inputTracks.getTPCTracksMCLabels();
334 }
335 }
336 mTracker->Reset();
337 mRec->PrepareEvent();
338 mRec->SetupGPUProcessor(mTracker, true);
339
340 // check trigger record filter setting
341 bool foundFilteredTrigger = false;
342 for (unsigned int iTrig = 0; iTrig < mChainTracking->mIOPtrs.nTRDTriggerRecords; ++iTrig) {
343 if (mChainTracking->mIOPtrs.trdTrigRecMask[iTrig] == 0) {
344 foundFilteredTrigger = true;
345 }
346 LOGF(debug, "TRD trigger %u added with time %f", iTrig, mChainTracking->mIOPtrs.trdTriggerTimes[iTrig]);
347 }
348 if (!foundFilteredTrigger && mTrigRecFilter) {
349 static bool warningSent = false;
350 if (!warningSent) {
351 LOG(warning) << "Trigger filtering requested, but no TRD trigger is actually masked. Can be that none needed to be masked or that the setting was not active for the tracklet transformer";
352 warningSent = true;
353 }
354 } else if (foundFilteredTrigger && !mTrigRecFilter) {
355 LOG(error) << "Trigger filtering is not requested, but masked TRD triggers are found. Rerun tracklet transformer without trigger filtering";
356 }
357
358 // load input tracks
359 const auto& trackTune = TrackTuneParams::Instance();
360 LOG(debug) << "Start loading input seeds into TRD tracker";
361 int nTracksLoadedITSTPC = 0;
362 int nTracksLoadedTPC = 0;
363 // load ITS-TPC matched tracks
364 for (unsigned int iTrk = 0; iTrk < mChainTracking->mIOPtrs.nTracksTPCITSO2; ++iTrk) {
365 const auto& trkITSTPC = mChainTracking->mIOPtrs.tracksTPCITSO2[iTrk];
366 GPUTRDTracker::HelperTrackAttributes trkAttribs;
367 trkAttribs.mTime = trkITSTPC.getTimeMUS().getTimeStamp();
368 trkAttribs.mTimeAddMax = trkITSTPC.getTimeMUS().getTimeStampError() * mRec->GetParam().rec.trd.nSigmaTerrITSTPC + mRec->GetParam().rec.trd.addTimeRoadITSTPC;
369 trkAttribs.mTimeSubMax = trkITSTPC.getTimeMUS().getTimeStampError() * mRec->GetParam().rec.trd.nSigmaTerrITSTPC + mRec->GetParam().rec.trd.addTimeRoadITSTPC;
370 GPUTRDTrack trkLoad(trkITSTPC);
371 // no TrackTuneParams for outerParam of ITS-TPC tracks: if needed, they are corrected already in the ITS-TPC matching refit
372 auto trackGID = GTrackID(iTrk, GTrackID::ITSTPC);
373 if (mTracker->LoadTrack(trkLoad, trackGID.getRaw(), true, &trkAttribs)) {
374 continue;
375 }
376 ++nTracksLoadedITSTPC;
377 LOGF(debug, "Loaded ITS-TPC track %i with time %f. Window from %f to %f", nTracksLoadedITSTPC, trkAttribs.mTime, trkAttribs.mTime - trkAttribs.mTimeSubMax, trkAttribs.mTime + trkAttribs.mTimeAddMax);
378 }
379 // load TPC-only tracks
380 for (unsigned int iTrk = 0; iTrk < mChainTracking->mIOPtrs.nOutputTracksTPCO2; ++iTrk) {
381 if (mChainTracking->mIOPtrs.tpcLinkITS && mChainTracking->mIOPtrs.tpcLinkITS[iTrk] != -1) {
382 // this TPC tracks has already been matched to ITS and the ITS-TPC track has already been loaded in the tracker
383 continue;
384 }
385 const auto& trkTpc = mChainTracking->mIOPtrs.outputTracksTPCO2[iTrk];
386 GPUTRDTracker::HelperTrackAttributes trkAttribs;
387 trkAttribs.mTime = trkTpc.getTime0() * mTPCTBinMUS - mTPCTDriftOffset; // account for the eventual time bias for TPC tracks time
388 trkAttribs.mTimeAddMax = trkTpc.getDeltaTFwd() * mTPCTBinMUS;
389 trkAttribs.mTimeSubMax = trkTpc.getDeltaTBwd() * mTPCTBinMUS;
390 if (trkTpc.hasASideClustersOnly()) {
391 trkAttribs.mSide = -1;
392 } else if (trkTpc.hasCSideClustersOnly()) {
393 trkAttribs.mSide = 1;
394 }
395 GPUTRDTrack trkLoad(trkTpc);
396 if (!trackTune.sourceLevelTPC) { // correct TPC tracks only if they were not corrected on the source level
397 if (trackTune.useTPCOuterCorr) {
398 trkLoad.updateParams(trackTune.tpcParOuter);
399 }
400 if (trackTune.tpcCovOuterType != TrackTuneParams::AddCovType::Disable) {
401 trkLoad.updateCov(mCovDiagOuter, trackTune.tpcCovOuterType == TrackTuneParams::AddCovType::WithCorrelations);
402 }
403 }
404 auto trackGID = GTrackID(iTrk, GTrackID::TPC);
405 if (mTracker->LoadTrack(trkLoad, trackGID.getRaw(), true, &trkAttribs)) {
406 continue;
407 }
408 ++nTracksLoadedTPC;
409 LOGF(debug, "Loaded TPC track %i with time %f. Window from %f to %f", nTracksLoadedTPC, trkAttribs.mTime, trkAttribs.mTime - trkAttribs.mTimeSubMax, trkAttribs.mTime + trkAttribs.mTimeAddMax);
410 }
411 LOGF(info, "%i tracks are loaded into the TRD tracker. Out of those %i ITS-TPC tracks and %i TPC tracks", nTracksLoadedITSTPC + nTracksLoadedTPC, nTracksLoadedITSTPC, nTracksLoadedTPC);
412
413 // Load the FT0 triggered BCs if this is requested
414
415 if (mTrkMask[GTrackID::FT0]) { // pile-up tagging was requested
416 auto ft0recPoints = inputTracks.getFT0RecPoints();
417 uint32_t firstOrbit = 0;
418 for (size_t ft0id = 0; ft0id < ft0recPoints.size(); ft0id++) {
419 const auto& f0rec = ft0recPoints[ft0id];
420 if (ft0id == 0) {
421 firstOrbit = f0rec.getInteractionRecord().orbit;
422 }
423 if (o2::ft0::InteractionTag::Instance().isSelected(f0rec)) {
424 uint32_t currentOrbit = f0rec.getInteractionRecord().orbit;
425 mTriggeredBCFT0.push_back(f0rec.getInteractionRecord().bc + (currentOrbit - firstOrbit) * o2::constants::lhc::LHCMaxBunches);
426 }
427 }
428 }
429
430 mTracker->SetFT0TriggeredBC(mTriggeredBCFT0.data(), mTriggeredBCFT0.size());
431
432 // start the tracking
433 // mTracker->DumpTracks();
434 mChainTracking->DoTRDGPUTracking<GPUTRDTrackerKernels::o2Version>(mTracker);
435 // mTracker->DumpTracks();
436
437 // finished tracking, now collect the output
438 std::vector<TrackTRD> tracksOutITSTPC;
439 std::vector<TrackTRD> tracksOutTPC;
440 std::vector<TrackTriggerRecord> trackTrigRecITSTPC;
441 std::vector<TrackTriggerRecord> trackTrigRecTPC;
442 GPUTRDTrack* tracksOutRaw = mTracker->Tracks();
443 std::vector<unsigned int> trackIdxArray(mTracker->NTracks()); // track indices sorted by trigger record index
444 std::iota(trackIdxArray.begin(), trackIdxArray.end(), 0);
445 std::sort(trackIdxArray.begin(), trackIdxArray.end(), [tracksOutRaw](int lhs, int rhs) { return tracksOutRaw[lhs].getCollisionId() < tracksOutRaw[rhs].getCollisionId(); });
446
447 std::vector<std::pair<uint8_t, uint8_t>> pileUpDist;
448 bool ft0Seen = false;
449 if (mTrkMask[GTrackID::FT0]) { // pile-up tagging was requested
450 long maxDiffFwd = mTracker->Param().rec.trd.pileupFwdNBC;
451 long maxDiffBwd = mTracker->Param().rec.trd.pileupBwdNBC;
452 auto ft0recPoints = inputTracks.getFT0RecPoints();
453 auto trdTriggers = tmpInputContainer->mTriggerRecords;
454 ft0Seen = ft0recPoints.size() > 0;
455 pileUpDist.resize(trdTriggers.size(), {0, 0});
456 size_t curFT0 = 0;
457 for (size_t itrd = 0; itrd < trdTriggers.size(); itrd++) {
458 const auto& trig = trdTriggers[itrd];
459 uint8_t fwd = 0, bwd = 0;
460 for (size_t ft0id = curFT0; ft0id < ft0recPoints.size(); ft0id++) {
461 const auto& f0rec = ft0recPoints[ft0id];
462 if (o2::ft0::InteractionTag::Instance().isSelected(f0rec)) {
463 auto bcdiff = trig.getBCData().toLong() - f0rec.getInteractionRecord().toLong();
464 if (bcdiff > maxDiffBwd) {
465 curFT0 = ft0id + 1;
466 continue;
467 }
468 if (bcdiff > 0) { // pre-trigger pileup, maxDiffBwd is guaranteed to be < max uint8_t
469 if (bwd == 0) {
470 bwd = uint8_t(bcdiff);
471 }
472 } else {
473 if (bcdiff < -maxDiffFwd) {
474 break;
475 }
476 fwd = uint8_t(-bcdiff); // post-trigger pileup, maxDiffFwd is guaranteed to be < max uint8_t
477 }
478 }
479 }
480 pileUpDist[itrd] = {bwd, fwd};
481 }
482 }
483
484 int nTrackletsAttached = 0; // only used for debug information
485 int nTracksFailedTPCTRDRefit = 0;
486 int nTracksFailedITSTPCTRDRefit = 0;
487 for (int iTrk = 0; iTrk < mTracker->NTracks(); ++iTrk) {
488 const auto& trdTrack = mTracker->Tracks()[trackIdxArray[iTrk]];
489 if (trdTrack.getCollisionId() < 0) {
490 // skip tracks without TRD tracklets (the collision ID for the TRD tracks is initialized to -1 and only changed if a tracklet is attached to the track)
491 continue;
492 }
493 if (mStrict && (trdTrack.getIsAmbiguous() || trdTrack.getReducedChi2() > mTracker->Param().rec.trd.chi2StrictCut)) {
494 // skip tracks which have another hypothesis close to the best one or which do are above strict chi2 threshold
495 continue;
496 }
497 if (trdTrack.getNtracklets() < mTracker->Param().rec.trd.nTrackletsMin) {
498 continue;
499 }
500 if (trdTrack.getChi2() / trdTrack.getNtracklets() > mTracker->Param().rec.trd.maxChi2Red) {
501 continue;
502 }
503 nTrackletsAttached += trdTrack.getNtracklets();
504 auto trackGID = trdTrack.getRefGlobalTrackId();
505 if (trackGID.includesDet(GTrackID::Source::ITS)) {
506 // this track is from an ITS-TPC seed
507 tracksOutITSTPC.push_back(trdTrack);
508 if (ft0Seen) {
509 tracksOutITSTPC.back().setPileUpDistance(pileUpDist[trdTrack.getCollisionId()].first, pileUpDist[trdTrack.getCollisionId()].second);
510 } else {
511 tracksOutITSTPC.back().setPileUpDistance(mTracker->Param().rec.trd.pileupBwdNBC, mTracker->Param().rec.trd.pileupFwdNBC);
512 }
513 if (!refitITSTPCTRDTrack(tracksOutITSTPC.back(), mChainTracking->mIOPtrs.trdTriggerTimes[trdTrack.getCollisionId()], &inputTracks) || std::isnan(tracksOutITSTPC.back().getSnp())) {
514 tracksOutITSTPC.pop_back();
515 ++nTracksFailedITSTPCTRDRefit;
516 continue;
517 }
518 if (mUseMC) {
519 fillMCTruthInfo(trdTrack, itstpcTrackLabels[trackGID], trdLabelsITSTPC, matchLabelsITSTPC, inputTracks.getTRDTrackletsMCLabels());
520 }
521 if (mWithPID) {
522 tracksOutITSTPC.back().setSignal(mBase->process(trdTrack, inputTracks, false));
523 }
524 } else {
525 // this track is from a TPC-only seed
526 tracksOutTPC.push_back(trdTrack);
527 if (ft0Seen) {
528 tracksOutTPC.back().setPileUpDistance(pileUpDist[trdTrack.getCollisionId()].first, pileUpDist[trdTrack.getCollisionId()].second);
529 } else {
530 tracksOutTPC.back().setPileUpDistance(mTracker->Param().rec.trd.pileupBwdNBC, mTracker->Param().rec.trd.pileupFwdNBC);
531 }
532 if (!refitTPCTRDTrack(tracksOutTPC.back(), mChainTracking->mIOPtrs.trdTriggerTimes[trdTrack.getCollisionId()], &inputTracks) || std::isnan(tracksOutTPC.back().getSnp())) {
533 tracksOutTPC.pop_back();
534 ++nTracksFailedTPCTRDRefit;
535 continue;
536 }
537 if (mUseMC) {
538 fillMCTruthInfo(trdTrack, tpcTrackLabels[trackGID], trdLabelsTPC, matchLabelsTPC, inputTracks.getTRDTrackletsMCLabels());
539 }
540 if (mWithPID) {
541 tracksOutTPC.back().setSignal(mBase->process(trdTrack, inputTracks, true));
542 }
543 }
544 }
545
546 fillTrackTriggerRecord(tracksOutITSTPC, trackTrigRecITSTPC, tmpInputContainer->mTriggerRecords);
547 fillTrackTriggerRecord(tracksOutTPC, trackTrigRecTPC, tmpInputContainer->mTriggerRecords);
548
549 LOGF(info, "The TRD tracker found %lu tracks from TPC seeds and %lu tracks from ITS-TPC seeds and attached in total %i tracklets out of %i",
550 tracksOutTPC.size(), tracksOutITSTPC.size(), nTrackletsAttached, mChainTracking->mIOPtrs.nTRDTracklets);
551 LOGF(info, "Number of tracks failed in the refit: TPC-TRD (%i), ITS-TPC-TRD (%i)", nTracksFailedTPCTRDRefit, nTracksFailedITSTPCTRDRefit);
552
553 uint32_t ss = o2::globaltracking::getSubSpec(mStrict ? o2::globaltracking::MatchingType::Strict : o2::globaltracking::MatchingType::Standard);
554 if (GTrackID::includesSource(GTrackID::Source::ITSTPC, mTrkMask)) {
555 pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MATCH_ITSTPC", 0}, tracksOutITSTPC);
556 pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRGREC_ITSTPC", 0}, trackTrigRecITSTPC);
557 if (mUseMC) {
558 pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MCLB_ITSTPC", 0}, matchLabelsITSTPC);
559 pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MCLB_ITSTPC_TRD", 0}, trdLabelsITSTPC);
560 }
561 }
562 if (GTrackID::includesSource(GTrackID::Source::TPC, mTrkMask)) {
563 pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MATCH_TPC", ss}, tracksOutTPC);
564 pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "TRGREC_TPC", ss}, trackTrigRecTPC);
565 if (mUseMC) {
566 pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MCLB_TPC", ss}, matchLabelsTPC);
567 pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "MCLB_TPC_TRD", ss}, trdLabelsTPC);
568 }
569 }
570
571 mTimer.Stop();
572}
573
574void TRDGlobalTracking::storeConfigs(ProcessingContext& pc)
575{
576 static bool first = true;
577 if (first) {
578 first = false;
581 TMap md;
582 md.SetOwnerKeyValue();
583 md.Add(new TObjString(o2::gpu::internal::GPUConfigurableParamGPUSettingsRecTRD::Instance().getName().c_str()), new TObjString(o2::conf::ConfigurableParam::asJSON(o2::gpu::internal::GPUConfigurableParamGPUSettingsRecTRD::Instance().getName()).c_str()));
584 pc.outputs().snapshot(Output{"META", "TRDTRACKER", 0}, md);
585 }
586 }
587}
588
590{
591 auto propagator = o2::base::Propagator::Instance();
592
593 // refit ITS-TPC-TRD track outwards to outermost TRD space point (start with ITS outer track parameters)
594 auto& outerParam = trk.getOuterParam();
595 auto detRefs = recoCont->getSingleDetectorRefs(trk.getRefGlobalTrackId());
596 int nCl = -1, clEntry = -1, nClRefit = 0, clRefs[14];
597 float chi2Out = 0, timeZErr = 0.;
598 bool pileUpOn = trk.hasPileUpInfo(); // distance to farthest collision within the pileup integration time is set
600 auto matCorr = o2::base::Propagator::MatCorrType(mRec->GetParam().rec.trd.matCorrType);
601 if (detRefs[GTrackID::ITS].isIndexSet()) { // this is ITS track
602 const auto& trkITS = mITSTracksArray[detRefs[GTrackID::ITS]];
603 outerParam = trkITS.getParamOut();
604 outerParam.setPID(recoCont->getTPCITSTrack(trk.getRefGlobalTrackId()).getPID(), true);
605 nCl = trkITS.getNumberOfClusters();
606 clEntry = trkITS.getFirstClusterEntry();
607 chi2Out = trkITS.getChi2();
608 for (int icl = 0; icl < nCl; icl++) { // clusters are stored from outer to inner layers
609 clRefs[icl] = mITSTrackClusIdx[clEntry + icl]; // from outer to inner layer
610 }
611 } else { // this is ITS-AB track, will need to refit including the ITS part
612 const auto& trkITSABref = mITSABRefsArray[detRefs[GTrackID::ITSAB]];
613 nCl = trkITSABref.getNClusters();
614 clEntry = trkITSABref.getFirstEntry();
615 outerParam = recoCont->getTPCITSTrack(trk.getRefGlobalTrackId()); // start from the inner kinematics of ITS-TPC, no need to set PID, will be transferred from ITSTPC track
616 outerParam.resetCovariance(100); // reset covariance to something big
617 // refit
618 for (int icl = 0; icl < nCl; icl++) { // clusters are stored from inner to outer layers
619 const auto& clus = mITSClustersArray[clRefs[nCl - icl - 1] = mITSABTrackClusIdx[clEntry + icl]]; // register in clRefs from outer to inner layer
620 if (!outerParam.rotate(geom->getSensorRefAlpha(clus.getSensorID())) ||
621 !propagator->propagateToX(outerParam, clus.getX(), propagator->getNominalBz(), o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, matCorr)) {
622 break;
623 }
624 chi2Out += outerParam.getPredictedChi2(clus);
625 if (!outerParam.update(clus)) {
626 break;
627 }
628 nClRefit++;
629 }
630 if (nClRefit != nCl) {
631 LOG(debug) << "ITS-AB refit outward failed";
632 return false;
633 }
634 }
635 // propagate to TPC inner boundary
636 float xtogo = 0;
637 if (!outerParam.getXatLabR(o2::constants::geom::XTPCInnerRef, xtogo, propagator->getNominalBz(), o2::track::DirOutward) ||
638 !propagator->PropagateToXBxByBz(outerParam, xtogo, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, matCorr)) {
639 LOG(debug) << "Propagation to inner TPC boundary X=" << xtogo << " failed, Xtr=" << outerParam.getX() << " snp=" << outerParam.getSnp();
640 return false;
641 }
642 int retVal = mTPCRefitter->RefitTrackAsTrackParCov(outerParam, mTPCTracksArray[detRefs[GTrackID::TPC]].getClusterRef(), timeTRD * mTPCTBinMUSInv, &chi2Out, true, false); // outward refit
643 if (retVal < 0) {
644 LOG(debug) << "TPC refit outwards failed";
645 return false;
646 }
647
648 if (!refitTRDTrack(trk, chi2Out, false, false)) {
649 LOG(debug) << "TRD refit outwards failed";
650 return false;
651 }
652 // refit ITS-TPC-TRD track inwards to innermost ITS cluster
653 // here we also calculate the LT integral for matching to TOF
654 float chi2In = 0.f;
655 if (!refitTRDTrack(trk, chi2In, true, false)) {
656 LOG(debug) << "TRD refit inwards failed";
657 return false;
658 }
659 auto posStart = trk.getXYZGlo();
660 retVal = mTPCRefitter->RefitTrackAsTrackParCov(trk, mTPCTracksArray[detRefs[GTrackID::TPC]].getClusterRef(), timeTRD * mTPCTBinMUSInv, &chi2In, false, false); // inward refit
661 if (retVal < 0) {
662 LOG(debug) << "TPC refit inwards failed";
663 return false;
664 }
665 // if for some reason the track was overshoot over the inner field cage, bring it back w/o material correction and LTintegral update
666 if (trk.getX() < o2::constants::geom::XTPCInnerRef &&
667 !propagator->PropagateToXBxByBz(trk, o2::constants::geom::XTPCInnerRef, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, o2::base::Propagator::MatCorrType::USEMatCorrNONE)) {
668 LOG(debug) << "BACK-Propagationto inner boundary failed";
669 return false;
670 }
671 auto posEnd = trk.getXYZGlo();
672 auto lInt = propagator->estimateLTIncrement(trk, posStart, posEnd);
673 trk.getLTIntegralOut().addStep(lInt, trk.getQ2P2());
674 // trk.getLTIntegralOut().addX2X0(lInt * mTPCmeanX0Inv); // do we need to account for the material budget here? probably
675
676 const auto& trackTune = TrackTuneParams::Instance();
677 if (trackTune.tpcCovInnerType != TrackTuneParams::AddCovType::Disable || trackTune.useTPCInnerCorr) { // if needed, correct TPC track in the middle of TPC->ITS refit
678 if (!propagator->PropagateToXBxByBz(trk, o2::constants::geom::XTPCInnerRef, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, matCorr, &trk.getLTIntegralOut())) {
679 LOG(debug) << "Propagation to TPC inner reference X for ITS refit inwards failed";
680 return false;
681 }
682 if (!trackTune.useTPCInnerCorr) {
683 trk.updateParams(trackTune.tpcParInner);
684 }
685 if (trackTune.tpcCovInnerType != TrackTuneParams::AddCovType::Disable) {
686 trk.updateCov(mCovDiagInner, trackTune.tpcCovInnerType == TrackTuneParams::AddCovType::WithCorrelations);
687 }
688 }
689
690 nClRefit = 0;
691 for (int icl = 0; icl < nCl; icl++) {
692 const auto& clus = mITSClustersArray[clRefs[icl]];
693 if (!trk.rotate(geom->getSensorRefAlpha(clus.getSensorID())) ||
694 // note: here we also calculate the L,T integral (in the inward direction, but this is irrelevant)
695 // note: we should eventually use TPC pid in the refit (TODO)
696 // note: since we are at small R, we can use field BZ component at origin rather than 3D field
697 !propagator->propagateToX(trk, clus.getX(), propagator->getNominalBz(), o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, matCorr, &trk.getLTIntegralOut())) {
698 break;
699 }
700 chi2In += trk.getPredictedChi2(clus);
701 if (!trk.update(clus)) {
702 break;
703 }
704 nClRefit++;
705 }
706 if (nClRefit != nCl) {
707 LOG(debug) << "ITS refit inwards failed";
708 return false;
709 }
710 // We need to update the LTOF integral by the distance to the "primary vertex"
711 // We want to leave the track at the the position of its last update, so we do a fast propagation on the TrackPar copy of trfit,
712 // and since for the LTOF calculation the material effects are irrelevant, we skip material corrections
713 const o2::dataformats::VertexBase vtxDummy; // at the moment using dummy vertex: TODO use MeanVertex constraint instead
714 o2::track::TrackPar trkPar(trk);
715 if (!propagator->propagateToDCA(vtxDummy.getXYZ(), trkPar, propagator->getNominalBz(), o2::base::Propagator::MAX_STEP, matCorr, nullptr, &trk.getLTIntegralOut())) {
716 LOG(error) << "LTOF integral might be incorrect";
717 }
718 return true;
719}
720
722{
723 auto propagator = o2::base::Propagator::Instance();
724 auto matCorr = o2::base::Propagator::MatCorrType(mRec->GetParam().rec.trd.matCorrType);
725 // refit TPC-TRD track outwards toward outermost TRD space point
726 auto& outerParam = trk.getOuterParam();
727 auto detRefs = recoCont->getSingleDetectorRefs(trk.getRefGlobalTrackId());
728 outerParam = trk;
729 float chi2Out = 0, timeZErr = 0.;
730 bool pileUpOn = trk.hasPileUpInfo(); // distance to farthest collision within the pileup integration time is set
731 int retVal = mTPCRefitter->RefitTrackAsTrackParCov(outerParam, mTPCTracksArray[detRefs[GTrackID::TPC]].getClusterRef(), timeTRD * mTPCTBinMUSInv, &chi2Out, true, false); // outward refit
732 if (retVal < 0) {
733 LOG(debug) << "TPC refit outwards failed";
734 return false;
735 }
736 if (pileUpOn) { // account pileup time uncertainty in Z errors
737 timeZErr = mTPCVdrift * trk.getPileUpTimeErrorMUS();
738 outerParam.updateCov(timeZErr, o2::track::CovLabels::kSigZ2);
739 }
740 if (!refitTRDTrack(trk, chi2Out, false, true)) {
741 LOG(debug) << "TRD refit outwards failed";
742 return false;
743 }
744
745 // refit TPC-TRD track inwards toward inner TPC radius
746 float chi2In = 0.f;
747 if (!refitTRDTrack(trk, chi2In, true, true)) {
748 LOG(debug) << "TRD refit inwards failed";
749 return false;
750 }
751 auto posStart = trk.getXYZGlo();
752 retVal = mTPCRefitter->RefitTrackAsTrackParCov(trk, mTPCTracksArray[detRefs[GTrackID::TPC]].getClusterRef(), timeTRD * mTPCTBinMUSInv, &chi2In, false, false); // inward refit
753 if (retVal < 0) {
754 LOG(debug) << "TPC refit inwards failed";
755 return false;
756 }
757 if (pileUpOn) { // account pileup time uncertainty in Z errors
758 trk.updateCov(timeZErr, o2::track::CovLabels::kSigZ2);
759 }
760 // if for some reason the track was overshoot over the inner field cage, bring it back w/o material correction and LTintegral update
761 if (trk.getX() < o2::constants::geom::XTPCInnerRef &&
762 !propagator->PropagateToXBxByBz(trk, o2::constants::geom::XTPCInnerRef, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, o2::base::Propagator::MatCorrType::USEMatCorrNONE)) {
763 LOG(debug) << "BACK-Propagationto inner boundary failed";
764 return false;
765 }
766 auto posEnd = trk.getXYZGlo();
767 auto lInt = propagator->estimateLTIncrement(trk, posStart, posEnd);
768 trk.getLTIntegralOut().addStep(lInt, trk.getQ2P2());
769 // trk.getLTIntegralOut().addX2X0(lInt * mTPCmeanX0Inv); // do we need to account for the material budget here? probably?
770
771 if (!propagator->PropagateToXBxByBz(trk, o2::constants::geom::XTPCInnerRef, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, matCorr, &trk.getLTIntegralOut())) {
772 LOG(debug) << "Final propagation to inner TPC radius failed (not removing the track because of this)";
773 }
774
775 const auto& trackTune = TrackTuneParams::Instance(); // if needed, correct the track after inward TPC refit
776 if (!trackTune.useTPCInnerCorr) {
777 trk.updateParams(trackTune.tpcParInner);
778 }
779 if (trackTune.tpcCovInnerType != TrackTuneParams::AddCovType::Disable) {
780 trk.updateCov(mCovDiagInner, trackTune.tpcCovInnerType == TrackTuneParams::AddCovType::WithCorrelations);
781 }
782
783 propagator->estimateLTFast(trk.getLTIntegralOut(), trk); // guess about initial value for the track integral from the origin
784 return true;
785}
786
787bool TRDGlobalTracking::refitTRDTrack(TrackTRD& trk, float& chi2, bool inwards, bool tpcSA)
788{
789 auto propagator = o2::base::Propagator::Instance();
790
791 int lyStart = inwards ? NLAYER - 1 : 0;
792 int direction = inwards ? -1 : 1;
793 int lyEnd = inwards ? -1 : NLAYER;
794 o2::track::TrackParCov* trkParam = nullptr;
795 o2::track::TrackLTIntegral* tofL = nullptr;
796 auto matCorr = o2::base::Propagator::MatCorrType(mRec->GetParam().rec.trd.matCorrType);
797
798 if (inwards) {
799 trkParam = &trk;
800 tofL = &trk.getLTIntegralOut();
801 } else {
802 trkParam = &trk.getOuterParam();
803 trkParam->setUserField(trk.getUserField()); // pileup timing info
804
805 const auto& trackTune = TrackTuneParams::Instance();
806 if ((trackTune.useTPCOuterCorr || trackTune.tpcCovOuterType != TrackTuneParams::AddCovType::Disable) &&
807 (!tpcSA || !trackTune.sourceLevelTPC)) { // for TPC standalone make sure correction was not applied ad the source level
808 if (!propagator->PropagateToXBxByBz(*trkParam, o2::constants::geom::XTPCOuterRef, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, matCorr)) {
809 LOG(debug) << "Propagation to TPC outer reference X for TRD outward refit failed";
810 return false;
811 }
812 if (trackTune.useTPCOuterCorr) {
813 trkParam->updateParams(trackTune.tpcParOuter);
814 }
815 if (trackTune.tpcCovOuterType != TrackTuneParams::AddCovType::Disable) {
816 trkParam->updateCov(mCovDiagOuter, trackTune.tpcCovOuterType == TrackTuneParams::AddCovType::WithCorrelations);
817 }
818 }
819 }
820
821 // Find most probable BCs and RMS for pile-up correction and error. Same BC is assumed for all tracklets
822 float tCorrPileUp = 0.;
823 float tErrPileUp2 = 0;
824 float maxProb = 0.f;
825 // The uncertainty is the RMS wrt the default correction of all possible corrections weighted by their probability
826 float sumCorr = 0.f;
827 float sumCorr2 = 0.f;
828 float sumProb = 0.f;
829 for (int iBC = 0; iBC < mTriggeredBCFT0.size(); iBC++) {
830 int deltaBC = roundf(mTriggeredBCFT0[iBC] - mChainTracking->mIOPtrs.trdTriggerTimes[trk.getCollisionId()] / o2::constants::lhc::LHCBunchSpacingMUS);
831 if (deltaBC <= mRecoParam.getPileUpRangeBefore() || deltaBC >= mRecoParam.getPileUpRangeAfter()) {
832 continue;
833 }
834 // collect the charges
835 std::array<int, 6> q0;
836 std::array<int, 6> q1;
837 for (int iLy = 0; iLy < NLAYER; iLy++) {
838 int trkltId = trk.getTrackletIndex(iLy);
839 if (trkltId < 0) {
840 q0[iLy] = -1;
841 q1[iLy] = -1;
842 } else {
843 q0[iLy] = mTrackletsRaw[trkltId].getQ0();
844 q1[iLy] = mTrackletsRaw[trkltId].getQ1();
845 }
846 }
847 // get pile-up probability
848 float probBC = mRecoParam.getPileUpProbTrack(deltaBC, q0, q1);
849 sumCorr += probBC * deltaBC;
850 sumCorr2 += probBC * deltaBC * deltaBC;
851 sumProb += probBC;
852 if (probBC > maxProb) {
853 maxProb = probBC;
854 tCorrPileUp = -deltaBC;
855 }
856 }
857 if (sumProb > 1e-6) {
858 tErrPileUp2 = sumCorr2 / sumProb - 2 * tCorrPileUp * sumCorr / sumProb + tCorrPileUp * tCorrPileUp;
859 }
860
861 if (inwards) {
862 // reset covariance to something big for inwards refit
863 trkParam->resetCovariance(100);
864 }
865 for (int iLy = lyStart; iLy != lyEnd; iLy += direction) {
866 int trkltId = trk.getTrackletIndex(iLy);
867 if (trkltId < 0) {
868 continue;
869 }
870 int trkltDet = mTrackletsRaw[trkltId].getDetector();
871 int trkltSec = trkltDet / (NLAYER * NSTACK);
872 if (trkltSec != o2::math_utils::angle2Sector(trkParam->getAlpha())) {
873 if (!trkParam->rotate(o2::math_utils::sector2Angle(trkltSec))) {
874 LOGF(debug, "Track at alpha=%.2f could not be rotated in tracklet coordinate system with alpha=%.2f", trkParam->getAlpha(), o2::math_utils::sector2Angle(trkltSec));
875 return false;
876 }
877 }
878 if (!propagator->PropagateToXBxByBz(*trkParam, mTrackletsCalib[trkltId].getX(), o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, matCorr, tofL)) {
879 LOGF(debug, "Track propagation failed in layer %i (pt=%f, xTrk=%f, xToGo=%f)", iLy, trkParam->getPt(), trkParam->getX(), mTrackletsCalib[trkltId].getX());
880 return false;
881 }
882 const PadPlane* pad = Geometry::instance()->getPadPlane(trkltDet);
883 float tilt = tan(TMath::DegToRad() * pad->getTiltingAngle()); // tilt is signed! and returned in degrees
884 float dyTiltCorr = tilt * trkParam->getTgl() * Geometry::instance()->cdrHght();
885 float tiltCorrUp = tilt * (mTrackletsCalib[trkltId].getZ() - trkParam->getZ());
886 float zPosCorrUp = mTrackletsCalib[trkltId].getZ() + mRecoParam.getZCorrCoeffNRC() * trkParam->getTgl();
887 float padLength = pad->getRowSize(mTrackletsRaw[trkltId].getPadRow());
888 if (!((trkParam->getSigmaZ2() < (padLength * padLength / 12.f)) && (std::fabs(mTrackletsCalib[trkltId].getZ() - trkParam->getZ()) < padLength))) {
889 tiltCorrUp = 0.f;
890 }
891
892 // conversion from slope in pad per time bin to slope in cm per BC = tracklets[trkltIdx].getSlopeFloat() * padWidth / BCperTimeBin
893 float slopeFactor = mTrackletsRaw[trkltId].getSlopeFloat() * pad->getWidthIPad() / 4.f;
894 float yCorrPileUp = tCorrPileUp * slopeFactor;
895 float yAddErrPileUp2 = tErrPileUp2 * slopeFactor * slopeFactor;
896
897 int nTrackletsChamber = mTracker->GetNtrackletsChamber(trk.getCollisionId(), trkltDet);
898 float angularPull = (mTrackletsCalib[trkltId].getDy() + dyTiltCorr - mRecoParam.convertAngleToDy(trkParam->getSnp())) / std::sqrt(mRecoParam.getDyRes(trkParam->getSnp(), nTrackletsChamber));
899
900 std::array<float, 2> trkltPosUp{mTrackletsCalib[trkltId].getY() - tiltCorrUp + yCorrPileUp, zPosCorrUp};
901 std::array<float, 3> trkltCovUp;
902 mRecoParam.recalcTrkltCov(tilt, trkParam->getSnp(), pad->getRowSize(mTrackletsRaw[trkltId].getPadRow()), trkltCovUp, (mRec->GetParam().rec.trd.useAngularPull != 0 ? angularPull : 0.), nTrackletsChamber);
903 trkltCovUp[0] += yAddErrPileUp2;
904
905 chi2 += trkParam->getPredictedChi2(trkltPosUp, trkltCovUp);
906 if (!trkParam->update(trkltPosUp, trkltCovUp)) {
907 LOGF(debug, "Failed to update track with space point in layer %i", iLy);
908 return false;
909 }
910 }
911 if (!inwards) { // to make sure that the inward fit will start from the trkParam
912 ((o2::track::TrackParCov&)trk) = *trkParam;
913 } else { // propagate to the TPC outer reference
914 if (!propagator->PropagateToXBxByBz(*trkParam, o2::constants::geom::XTPCOuterRef, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, matCorr, tofL)) {
915 LOG(debug) << "Propagation to TPC outer reference X after TRD inward refit failed";
916 return false;
917 }
918 // make sure we are in the correct sector
919 int sector = o2::math_utils::angle2Sector(trkParam->getPhiPos());
920 if (sector != o2::math_utils::angle2Sector(trkParam->getAlpha()) &&
921 !trkParam->rotate(o2::math_utils::sector2Angle(sector)) &&
922 !propagator->PropagateToXBxByBz(*trkParam, o2::constants::geom::XTPCOuterRef, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, matCorr, tofL)) {
923 LOG(debug) << "Propagation/rotation to TPC outer reference X after TRD inward refit failed " << trkParam->asString();
924 return false;
925 }
926 }
927 return true;
928}
929
931{
932 LOGF(info, "TRD global tracking total timing: Cpu: %.3e Real: %.3e s in %d slots",
933 mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1);
934}
935
936DataProcessorSpec getTRDGlobalTrackingSpec(bool useMC, GTrackID::mask_t src, bool trigRecFilterActive, bool strict, bool withPID, PIDPolicy policy, bool requestCTPLumi)
937{
938 std::vector<OutputSpec> outputs;
939 uint32_t ss = o2::globaltracking::getSubSpec(strict ? o2::globaltracking::MatchingType::Strict : o2::globaltracking::MatchingType::Standard);
940 std::shared_ptr<DataRequest> dataRequest = std::make_shared<DataRequest>();
941 if (strict) {
942 dataRequest->setMatchingInputStrict();
943 }
944 auto trkSrc = src;
945 trkSrc |= GTrackID::getSourcesMask("TPC");
946 dataRequest->requestClusters(GTrackID::getSourcesMask("TRD"), useMC);
947 dataRequest->requestTPCClusters(false); // only needed for refit, don't care about labels
948 if (GTrackID::includesSource(GTrackID::Source::ITSTPC, src)) {
949 // ITS clusters are only needed if we match to ITS-TPC tracks
950#ifdef ENABLE_UPGRADES
951 if (o2::GlobalParams::Instance().withITS3) {
952 dataRequest->requestIT3Clusters(false); // only needed for refit, don't care about labels
953 } else {
954 dataRequest->requestITSClusters(false); // only needed for refit, don't care about labels
955 }
956#else
957 dataRequest->requestITSClusters(false); // only needed for refit, don't care about labels
958#endif
959 trkSrc |= GTrackID::getSourcesMask("ITS");
960 }
961 dataRequest->requestTracks(trkSrc, useMC);
962 auto& inputs = dataRequest->inputs;
963 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(false, // orbitResetTime
964 false, // GRPECS=true
965 false, // GRPLHCIF
966 true, // GRPMagField
967 true, // askMatLUT
969 inputs,
970 true);
972 Options opts;
973
974 dataRequest->inputs.emplace_back("corrMap", o2::header::gDataOriginTPC, "TPCCORRMAP", 0, Lifetime::Timeframe);
975
976 if (requestCTPLumi) {
977 dataRequest->inputs.emplace_back("lumiCTP", o2::header::gDataOriginCTP, "LUMICTP", 0, Lifetime::Timeframe);
978 }
979
980 // Request PID policy data
981 if (withPID) {
982 // request policy
983 switch (policy) {
984 case PIDPolicy::LQ1D:
985 inputs.emplace_back("lq1dlut", "TRD", "LQ1D", 0, Lifetime::Condition, ccdbParamSpec("TRD/PID/LQ1D"));
986 break;
987 case PIDPolicy::LQ2D:
988 inputs.emplace_back("lq2dlut", "TRD", "LQ2D", 0, Lifetime::Condition, ccdbParamSpec("TRD/PID/LQ2D"));
989 break;
990 case PIDPolicy::LQ3D:
991 inputs.emplace_back("lq3dlut", "TRD", "LQ3D", 0, Lifetime::Condition, ccdbParamSpec("TRD/PID/LQ3D"));
992 break;
993#ifdef TRDPID_WITH_ONNX
994 case PIDPolicy::XGB:
995 inputs.emplace_back("xgb", "TRD", "XGB", 0, Lifetime::Condition, ccdbParamSpec("TRD_test/PID_new/xgb"));
996 break;
997 case PIDPolicy::PY:
998 inputs.emplace_back("py", "TRD", "py", 0, Lifetime::Condition, ccdbParamSpec("TRD_test/PID_new/py"));
999 break;
1000#endif
1001 case PIDPolicy::Dummy:
1002 break;
1003 default:
1004 throw std::runtime_error("Unable to load requested PID policy data!");
1005 }
1006 // request calibration data
1007 inputs.emplace_back("localgainfactors", "TRD", "LOCALGAINFACTORS", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/LocalGainFactor"));
1008 }
1009
1010 if (GTrackID::includesSource(GTrackID::Source::ITSTPC, src)) {
1011 outputs.emplace_back(o2::header::gDataOriginTRD, "MATCH_ITSTPC", 0, Lifetime::Timeframe);
1012 outputs.emplace_back(o2::header::gDataOriginTRD, "TRGREC_ITSTPC", 0, Lifetime::Timeframe);
1013 if (useMC) {
1014 outputs.emplace_back(o2::header::gDataOriginTRD, "MCLB_ITSTPC", 0, Lifetime::Timeframe);
1015 outputs.emplace_back(o2::header::gDataOriginTRD, "MCLB_ITSTPC_TRD", 0, Lifetime::Timeframe);
1016 }
1017 if (withPID) {
1018 outputs.emplace_back(o2::header::gDataOriginTRD, "TRDPID_ITSTPC", 0, Lifetime::Timeframe);
1019 }
1020 }
1021 if (GTrackID::includesSource(GTrackID::Source::TPC, src)) {
1022 outputs.emplace_back(o2::header::gDataOriginTRD, "MATCH_TPC", ss, Lifetime::Timeframe);
1023 outputs.emplace_back(o2::header::gDataOriginTRD, "TRGREC_TPC", ss, Lifetime::Timeframe);
1024 if (useMC) {
1025 outputs.emplace_back(o2::header::gDataOriginTRD, "MCLB_TPC", ss, Lifetime::Timeframe);
1026 outputs.emplace_back(o2::header::gDataOriginTRD, "MCLB_TPC_TRD", ss, Lifetime::Timeframe);
1027 }
1028 if (trigRecFilterActive) {
1029 LOG(info) << "Matching to TPC-only tracks requested, but IRs without ITS contribution are filtered out (used strict matching mode to constrain TPC tracks before matching to ITS)";
1030 }
1031 }
1032
1033 outputs.emplace_back("META", "TRDTRACKER", 0, Lifetime::Sporadic);
1034
1035 std::string processorName = o2::utils::Str::concat_string("trd-globaltracking", GTrackID::getSourcesNames(src));
1036 std::regex reg("[,\\[\\]]+");
1037 processorName = regex_replace(processorName, reg, "_");
1038
1039 return DataProcessorSpec{
1040 processorName,
1041 inputs,
1042 outputs,
1043 AlgorithmSpec{adaptFromTask<TRDGlobalTracking>(useMC, withPID, policy, dataRequest, ggRequest, src, trigRecFilterActive, strict, requestCTPLumi)},
1044 opts};
1045}
1046
1047} // namespace trd
1048} // namespace o2
Definition of the ITS/MFT clusterer settings.
std::string getName(const TDataMember *dm, int index, int size)
o2d::GlobalTrackID GTrackID
Definition of the ITSMFT cluster.
Global TRD definitions and constants.
Definition of the Names Generator class.
Definition of the GeometryManager class.
std::ostringstream debug
Definition of the FIT RecPoints class.
o2::raw::RawFileWriter * raw
int32_t retVal
TRD Tracklet word for GPU tracker - 32bit tracklet info + half chamber ID + index.
Some ALICE geometry constants of common interest.
Definition of the GeometryTGeo class.
Definition of the parameter class for the detector electronics.
Declarations of the helper class for clusters / roadwidth matching.
Struct for input data required by TRD tracking workflow.
class to create TPC fast transformation
Result of refitting TPC-ITS matched track.
Configurable params for tracks ad hoc tuning.
Helper class to obtain TPC clusters / digits / labels from DPL.
void clear()
Definition bitfield.h:54
void setFakeFlag(bool v=true)
void checkUpdates(o2::framework::ProcessingContext &pc)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
static std::string getConfigOutputFileName(const std::string &procName, const std::string &confName="", bool json=true)
Definition NameConf.cxx:120
static constexpr float MAX_SIN_PHI
Definition Propagator.h:72
static constexpr float MAX_STEP
Definition Propagator.h:73
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:178
static std::string asJSON(std::string const &keyOnly="")
static void write(std::string const &filename, std::string const &keyOnly="")
static mask_t getSourcesMask(const std::string_view srcList)
static std::string getSourcesNames(mask_t srcm)
A container to hold and manage MC truth information/labels.
gsl::span< TruthElement > getLabels(uint32_t dataindex)
void snapshot(const Output &spec, T const &object)
decltype(auto) get(R binding, int part=0) const
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
void SetTRDGeometry(std::unique_ptr< o2::trd::GeometryFlat > &&geo)
void SetO2Propagator(const o2::base::Propagator *prop)
void SetTRDRecoParam(std::unique_ptr< GPUTRDRecoParam > &&par)
int32_t DoTRDGPUTracking(T *externalInstance=nullptr)
GPUTrackingInOutPointers & mIOPtrs
static float getNominalGPUBz(T &src)
void SetupGPUProcessor(T *proc, bool allocate)
void RegisterGPUProcessor(T *proc, bool deviceSlave)
void SetSettings(float solenoidBzNominalGPU, const GPURecoStepConfiguration *workflow=nullptr)
static GPUReconstruction * CreateInstance(const GPUSettingsDeviceBackend &cfg)
const GPUParam & GetParam() const
const GPUSettingsProcessing & GetProcessingSettings() const
void init(float bz, const GPUSettingsRec *rec=nullptr)
Load parameterization for given magnetic field.
void SetNCandidates(int32_t n)
static std::shared_ptr< const tmpDataContainer > fillIOPtr(GPUTrackingInOutPointers &ioPtr, const o2::globaltracking::RecoContainer &recoCont, bool useMC, const GPUCalibObjectsConst *calib=nullptr, GID::mask_t maskCl=GID::MASK_ALL, GID::mask_t maskTrk=GID::MASK_ALL, GID::mask_t maskMatch=GID::MASK_ALL)
static GeometryTGeo * Instance()
void fillMatrixCache(int mask) override
static void requestCCDBInputs(std::vector< o2::framework::InputSpec > &inputs, bool laser=true, bool itstpcTgl=true)
void extractCCDBInputs(o2::framework::ProcessingContext &pc, bool laser=true, bool itstpcTgl=true)
const VDriftCorrFact & getVDriftObject() const
bool accountCCDBInputs(const o2::framework::ConcreteDataMatcher &matcher, void *obj)
static std::string_view getSourceName(Source s)
bool isUpdated() const
static Geometry * instance()
Definition Geometry.h:33
void fillMCTruthInfo(const TrackTRD &trk, o2::MCCompLabel lblSeed, std::vector< o2::MCCompLabel > &lblContainerTrd, std::vector< o2::MCCompLabel > &lblContainerMatch, const o2::dataformats::MCTruthContainer< o2::MCCompLabel > *trkltLabels) const
void finaliseCCDB(o2::framework::ConcreteDataMatcher &matcher, void *obj) final
void endOfStream(o2::framework::EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
void run(o2::framework::ProcessingContext &pc) final
bool refitTRDTrack(TrackTRD &trk, float &chi2, bool inwards, bool tpcSA)
void init(o2::framework::InitContext &ic) final
bool refitITSTPCTRDTrack(TrackTRD &trk, float timeTRD, o2::globaltracking::RecoContainer *recoCont)
void fillTrackTriggerRecord(const std::vector< TrackTRD > &tracks, std::vector< TrackTriggerRecord > &trigRec, const gsl::span< const o2::trd::TriggerRecord > &trackletTrigRec) const
bool refitTPCTRDTrack(TrackTRD &trk, float timeTRD, o2::globaltracking::RecoContainer *recoCont)
GLenum src
Definition glcorearb.h:1767
GLint GLsizei count
Definition glcorearb.h:399
constexpr o2::header::DataOrigin gDataOriginCTP
Definition DataHeader.h:564
constexpr o2::header::DataOrigin gDataOriginTPC
Definition DataHeader.h:576
constexpr o2::header::DataOrigin gDataOriginTRD
Definition DataHeader.h:577
constexpr float XTPCOuterRef
reference radius to propagate outer TPC track
constexpr float XTPCInnerRef
reference radius at which TPC provides the tracks
constexpr double LHCBunchSpacingMUS
constexpr int LHCMaxBunches
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
std::vector< ConfigParamSpec > ccdbParamSpec(std::string const &path, int runDependent, std::vector< CCDBMetadata > metadata={}, int qrate=0)
std::vector< ConfigParamSpec > Options
GPUTRDTracker_t< GPUTRDTrack, GPUTRDPropagator > GPUTRDTracker
Definition GPUTRDDef.h:58
void convertCompactClusters(gsl::span< const itsmft::CompClusterExt > clusters, gsl::span< const unsigned char >::iterator &pattIt, std::vector< o2::BaseCluster< float > > &output, const o2::its3::TopologyDictionary *dict)
convert compact clusters to 3D spacepoints
Definition IOUtils.cxx:25
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
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
framework::DataProcessorSpec getTRDGlobalTrackingSpec(bool useMC, o2::dataformats::GlobalTrackID::mask_t src, bool trigRecFilterActive, bool strict, bool withPID, PIDPolicy policy, bool requestCTPLumi)
create a processor spec
std::unique_ptr< PIDBase > getTRDPIDPolicy(PIDPolicy policy)
Factory function to create a PID policy.
Definition PIDBase.cxx:63
PIDPolicy
Option for available PID policies.
Definition PID.h:29
@ LQ3D
3-Dimensional Likelihood model
@ LQ2D
2-Dimensional Likelihood model
@ Dummy
Dummy object outputting -1.f.
@ LQ1D
1-Dimensional Likelihood model
auto getRecoInputContainer(o2::framework::ProcessingContext &pc, o2::gpu::GPUTrackingInOutPointers *ptrs, const o2::globaltracking::RecoContainer *inputTracks, bool mc=false)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string name
The name of the associated DataProcessorSpec.
Definition DeviceSpec.h:50
size_t inputTimesliceId
The time pipelining id of this particular device.
Definition DeviceSpec.h:68
GlobalIDSet getSingleDetectorRefs(GTrackID gidx) const
gsl::span< const o2::trd::CalibratedTracklet > getTRDCalibratedTracklets() const
const o2::dataformats::MCTruthContainer< o2::MCCompLabel > * getTRDTrackletsMCLabels() const
gsl::span< const unsigned char > clusterShMapTPC
externally set TPC clusters sharing map
const o2::dataformats::TrackTPCITS & getTPCITSTrack(GTrackID gid) const
void collectData(o2::framework::ProcessingContext &pc, const DataRequest &request)
std::unique_ptr< o2::tpc::internal::getWorkflowTPCInput_ret > inputsTPCclusters
gsl::span< const unsigned int > occupancyMapTPC
externally set TPC clusters occupancy map
gsl::span< const o2::trd::Tracklet64 > getTRDTracklets() const
gpudatatypes::RecoStepField steps
gpudatatypes::InOutTypeField inputs
gpudatatypes::InOutTypeField outputs
const o2::dataformats::TrackTPCITS * tracksTPCITSO2
const o2::tpc::TrackTPC * outputTracksTPCO2
static constexpr int T2L
Definition Cartesian.h:55
static constexpr int T2GRot
Definition Cartesian.h:57
static std::string concat_string(Ts const &... ts)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"