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