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