Project
Loading...
Searching...
No Matches
TPCRefitter.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
12#include <random>
13#include <vector>
14#include <TStopwatch.h>
20#include "TPCFastTransformPOD.h"
26#include "Framework/Task.h"
27#include "MathUtils/Tsallis.h"
34#include "GPUO2InterfaceRefit.h"
39
40namespace o2::trackstudy
41{
42
43using namespace o2::framework;
46
52
54
55class TPCRefitterSpec final : public Task
56{
57 public:
58 enum StudyType {
59 TPC = 0x1,
60 ITSTPC = 0x2,
61 Cosmics = 0x4,
62 };
64 Streamer = 0x1,
65 TFVectors = 0x2,
66 };
67 TPCRefitterSpec(std::shared_ptr<DataRequest> dr, std::shared_ptr<o2::base::GRPGeomRequest> gr, GTrackID::mask_t src, bool useMC)
68 : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mUseMC(useMC) {}
69 ~TPCRefitterSpec() final = default;
70 void init(InitContext& ic) final;
71 void run(ProcessingContext& pc) final;
72 void endOfStream(EndOfStreamContext& ec) final;
73 void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final;
74 void process(o2::globaltracking::RecoContainer& recoData);
75 bool getDCAs(const o2::track::TrackPar& track, float& dcar, float& dcaz);
76
77 private:
78 void updateTimeDependentParams(ProcessingContext& pc);
79 std::shared_ptr<DataRequest> mDataRequest;
80 std::shared_ptr<o2::base::GRPGeomRequest> mGGCCDBRequest;
81 o2::tpc::VDriftHelper mTPCVDriftHelper{};
82 const o2::gpu::TPCFastTransformPOD* mTPCCorrMaps{nullptr};
83 bool mUseMC{false};
84 bool mUseGPUModel{false};
85 float mXRef = 83.;
86 float mDCAMinPt = 1.;
87 int mTFStart = 0;
88 int mTFEnd = 999999999;
89 int mTFCount = -1;
90 int mDCAMinNCl = 80;
91 int mStudyType = 0;
92 int mWriterType = 0;
93 float mSqrt{13600};
94 float mSamplingFactor{0.1};
95 bool mUseR = false;
96 bool mEnableDCA = false;
97 int mWriteTrackClusters = 0;
98 bool mDoSampling{false};
99 bool mDoRefit{true};
100 bool mIgnorLegsWOGoodTime{false};
101 bool mUseCosmicLegTiming{false};
102 std::vector<size_t> mClusterOccupancy;
103 std::vector<size_t> mITSTPCTrackOccupanyTPCTime;
104 std::vector<size_t> mITSTPCTrackOccupanyCombinedTime;
105 std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOutTPC;
106 std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOutITSTPC;
107 std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOutTPCTF;
108 std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOutITSTPCTF;
109 std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOutCosmics;
110 std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOutCl;
111 float mITSROFrameLengthMUS = 0.;
112 GTrackID::mask_t mTracksSrc{};
114 std::mt19937 mGenerator;
115 float mVdriftTB;
116 float mTPCTBBias;
117 uint32_t mTimeBinsPerTF{};
118 uint32_t mOccupancyBinsPerTF{};
119 uint32_t mTimeBinsPerDrift{500};
120 //
121 // Input data
122 //
123 gsl::span<const o2::tpc::TPCClRefElem> mTPCTrackClusIdx;
124 gsl::span<const o2::tpc::TrackTPC> mTPCTracksArray;
125 gsl::span<const o2::dataformats::TrackTPCITS> mITSTPCTracksArray;
126 gsl::span<const o2::its::TrackITS> mITSTracksArray;
127 gsl::span<const o2::dataformats::TrackCosmics> mCosmics;
128 gsl::span<const unsigned char> mTPCRefitterShMap;
129 gsl::span<const unsigned int> mTPCRefitterOccMap;
130 const o2::tpc::ClusterNativeAccess* mTPCClusterIdxStruct = nullptr;
131 gsl::span<const o2::MCCompLabel> mTPCTrkLabels;
132 std::unique_ptr<o2::gpu::GPUO2InterfaceRefit> mTPCRefitter;
133 std::vector<o2::InteractionTimeRecord> mIntRecs;
134
135 void fillOccupancyVectors(o2::globaltracking::RecoContainer& recoData);
136 bool processTPCTrack(o2::tpc::TrackTPC tr, o2::MCCompLabel lbl, o2::utils::TreeStreamRedirector* streamer, const o2::its::TrackITS* its = nullptr, const o2::dataformats::TrackTPCITS* itstpc = nullptr, bool outward = false, float time0custom = -1);
137 void processCosmics(o2::globaltracking::RecoContainer& recoData);
138};
139
141{
143 mXRef = ic.options().get<float>("target-x");
144 mUseR = ic.options().get<bool>("use-r-as-x");
145 mEnableDCA = ic.options().get<bool>("enable-dcas");
146 mUseGPUModel = ic.options().get<bool>("use-gpu-fitter");
147 mTFStart = ic.options().get<int>("tf-start");
148 mTFEnd = ic.options().get<int>("tf-end");
149 mDCAMinPt = ic.options().get<float>("dcaMinPt");
150 mDCAMinNCl = ic.options().get<float>("dcaMinNCl");
151 mSqrt = ic.options().get<float>("sqrts");
152 mSamplingFactor = ic.options().get<float>("sampling-factor");
153 mDoSampling = ic.options().get<bool>("do-sampling");
154 mDoRefit = ic.options().get<bool>("do-refit");
155 mStudyType = ic.options().get<int>("study-type");
156 mWriterType = ic.options().get<int>("writer-type");
157 mWriteTrackClusters = ic.options().get<int>("write-track-clusters");
158 mIgnorLegsWOGoodTime = ic.options().get<bool>("ignore-legs-wo-outer-det");
159 mUseCosmicLegTiming = ic.options().get<bool>("use-cosmic-leg-timing");
160
161 const auto occBinsPerDrift = ic.options().get<uint32_t>("occupancy-bins-per-drift");
162 mTimeBinsPerTF = (o2::raw::HBFUtils::Instance().nHBFPerTF * o2::constants::lhc::LHCMaxBunches) / 8 + 2 * mTimeBinsPerDrift; // add one drift before and after the TF
163 mOccupancyBinsPerTF = static_cast<uint32_t>(std::ceil(float(mTimeBinsPerTF * occBinsPerDrift) / mTimeBinsPerDrift));
164 mClusterOccupancy.resize(mOccupancyBinsPerTF);
165 mITSTPCTrackOccupanyTPCTime.resize(mOccupancyBinsPerTF);
166 mITSTPCTrackOccupanyCombinedTime.resize(mOccupancyBinsPerTF);
167 LOGP(info, "Using {} bins for the occupancy per TF", mOccupancyBinsPerTF);
168
169 int lane = ic.services().get<const o2::framework::DeviceSpec>().inputTimesliceId;
170 int maxLanes = ic.services().get<const o2::framework::DeviceSpec>().maxInputTimeslices;
171 auto composeName = [maxLanes, lane](const std::string& seed) { return maxLanes > 1 ? fmt::format("{}_{}.root", seed, lane) : fmt::format("{}.root", seed); };
172
173 if ((mWriterType & WriterType::Streamer) == WriterType::Streamer) {
174 if ((mStudyType & StudyType::TPC) == StudyType::TPC) {
175 mDBGOutTPC = std::make_unique<o2::utils::TreeStreamRedirector>(composeName("tpctracks-study-streamer").c_str(), "recreate");
176 }
177 if ((mStudyType & StudyType::ITSTPC) == StudyType::ITSTPC) {
178 mDBGOutITSTPC = std::make_unique<o2::utils::TreeStreamRedirector>(composeName("itstpctracks-study-streamer").c_str(), "recreate");
179 }
180 if ((mStudyType & StudyType::Cosmics) == StudyType::Cosmics) {
181 mDBGOutCosmics = std::make_unique<o2::utils::TreeStreamRedirector>(composeName("cosmics-study-streamer").c_str(), "recreate");
182 }
183 }
184 if (ic.options().get<bool>("dump-clusters")) {
185 mDBGOutCl = std::make_unique<o2::utils::TreeStreamRedirector>(composeName("tpc-trackStudy-cl").c_str(), "recreate");
186 }
187
188 if (mXRef < 0.) {
189 mXRef = 0.;
190 }
191 mGenerator = std::mt19937(std::random_device{}());
192}
193
195{
196 ++mTFCount;
197 if (mTFCount < mTFStart || mTFCount > mTFEnd) {
198 LOGP(info, "Skipping TF {}", mTFCount);
199 return;
200 }
201
203 recoData.collectData(pc, *mDataRequest.get()); // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer
204 updateTimeDependentParams(pc); // Make sure this is called after recoData.collectData, which may load some conditions
205 fillOccupancyVectors(recoData);
206 process(recoData);
207
208 if (mTFCount >= mTFEnd) {
209 LOGP(info, "Stopping processing after TF {}", mTFCount);
211 return;
212 }
213}
214
215void TPCRefitterSpec::updateTimeDependentParams(ProcessingContext& pc)
216{
218 mTPCVDriftHelper.extractCCDBInputs(pc);
219 auto const& raw = pc.inputs().get<const char*>("corrMap");
220 mTPCCorrMaps = &o2::gpu::TPCFastTransformPOD::get(raw);
221}
222
223void TPCRefitterSpec::fillOccupancyVectors(o2::globaltracking::RecoContainer& recoData)
224{
225 // reset counters
226 std::fill(mClusterOccupancy.begin(), mClusterOccupancy.end(), 0u);
227 std::fill(mITSTPCTrackOccupanyTPCTime.begin(), mITSTPCTrackOccupanyTPCTime.end(), 0u);
228 std::fill(mITSTPCTrackOccupanyCombinedTime.begin(), mITSTPCTrackOccupanyCombinedTime.end(), 0u);
229
230 // fill cluster occupancy
231 const auto& clusterIndex = recoData.inputsTPCclusters->clusterIndex;
232 using namespace o2::tpc::constants;
233 for (int sector = 0; sector < MAXSECTOR; ++sector) {
234 for (int padrow = 0; padrow < MAXGLOBALPADROW; ++padrow) {
235 for (size_t icl = 0; icl < clusterIndex.nClusters[sector][padrow]; ++icl) {
236 const auto& cl = clusterIndex.clusters[sector][padrow][icl];
237 // shift by one TPC drift to allow seeing pile-up
238 const auto tpcTime = cl.getTime() + mTimeBinsPerDrift;
239 const uint32_t clOccPos = static_cast<uint32_t>(tpcTime * mOccupancyBinsPerTF / mTimeBinsPerTF);
240 if (clOccPos >= mOccupancyBinsPerTF) {
241 LOGP(error, "cluster with time {} outside TPC acceptanc", cl.getTime());
242 } else {
243 ++mClusterOccupancy[clOccPos];
244 }
245 }
246 }
247 }
248
249 // fill track occupancy for its-tpc matched tracks
250 auto tpcTracks = recoData.getTPCTracks();
251 auto itstpcTracks = recoData.getTPCITSTracks();
252 const auto& paramEle = o2::tpc::ParameterElectronics::Instance();
253
254 for (const auto& tpcitsTrack : itstpcTracks) {
255 const auto idxTPC = tpcitsTrack.getRefTPC().getIndex();
256 if (idxTPC >= tpcTracks.size()) {
257 LOGP(fatal, "TPC index {} out of array size {}", idxTPC, tpcTracks.size());
258 }
259 const auto& tpcTrack = tpcTracks[idxTPC];
260 // shift by one TPC drift to allow seeing pile-up
261 const auto tpcTime = tpcTrack.getTime0() + mTimeBinsPerDrift;
262 if (tpcTime >= 0) {
263 const uint32_t clOccPosTPC = static_cast<uint32_t>(tpcTime * mOccupancyBinsPerTF / mTimeBinsPerTF);
264 if (clOccPosTPC < mITSTPCTrackOccupanyTPCTime.size()) {
265 ++mITSTPCTrackOccupanyTPCTime[clOccPosTPC];
266 } else {
267 LOGP(warn, "TF {}: TPC occupancy index {} out of range {}", mTFCount, clOccPosTPC, mITSTPCTrackOccupanyTPCTime.size());
268 }
269 }
270 // convert mus to time bins
271 // shift by one TPC drift to allow seeing pile-up
272 const auto tpcitsTime = tpcitsTrack.getTimeMUS().getTimeStamp() / paramEle.ZbinWidth + mTimeBinsPerDrift;
273 if (tpcitsTime > 0) {
274 const uint32_t clOccPosITSTPC = static_cast<uint32_t>(tpcitsTime * mOccupancyBinsPerTF / mTimeBinsPerTF);
275 if (clOccPosITSTPC < mITSTPCTrackOccupanyCombinedTime.size()) {
276 ++mITSTPCTrackOccupanyCombinedTime[clOccPosITSTPC];
277 }
278 }
279 }
280
281 auto fillDebug = [this](o2::utils::TreeStreamRedirector* streamer) {
282 if (streamer) {
283 *streamer << "occupancy"
284 << "tfCounter=" << mTFCount
285 << "clusterOcc=" << mClusterOccupancy
286 << "tpcTrackTimeOcc=" << mITSTPCTrackOccupanyTPCTime
287 << "itstpcTrackTimeOcc=" << mITSTPCTrackOccupanyCombinedTime
288 << "\n";
289 }
290 };
291
292 fillDebug(mDBGOutTPC.get());
293 fillDebug(mDBGOutITSTPC.get());
294}
295
297{
298 auto prop = o2::base::Propagator::Instance();
299
300 mITSTracksArray = recoData.getITSTracks();
301 mTPCTracksArray = recoData.getTPCTracks();
302 mITSTPCTracksArray = recoData.getTPCITSTracks();
303 mCosmics = recoData.getCosmicTracks();
304
305 mTPCTrackClusIdx = recoData.getTPCTracksClusterRefs();
306 mTPCClusterIdxStruct = &recoData.inputsTPCclusters->clusterIndex;
307 mTPCRefitterShMap = recoData.clusterShMapTPC;
308 mTPCRefitterOccMap = recoData.occupancyMapTPC;
309
310 LOGP(info, "Processing TF {} with {} its, {} tpc, {} its-tpc tracks and {} comsmics", mTFCount, mITSTracksArray.size(), mTPCTracksArray.size(), mITSTPCTracksArray.size(), mCosmics.size());
311 if (mUseMC) { // extract MC tracks
312 const o2::steer::DigitizationContext* digCont = nullptr;
313 if (!mcReader.initFromDigitContext("collisioncontext.root")) {
314 throw std::invalid_argument("initialization of MCKinematicsReader failed");
315 }
316 digCont = mcReader.getDigitizationContext();
317 mIntRecs = digCont->getEventRecords();
318 mTPCTrkLabels = recoData.getTPCTracksMCLabels();
319 }
320
321 mTPCRefitter = std::make_unique<o2::gpu::GPUO2InterfaceRefit>(mTPCClusterIdxStruct, mTPCCorrMaps, prop->getNominalBz(), mTPCTrackClusIdx.data(), 0, mTPCRefitterShMap.data(), mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size(), nullptr, prop);
322
323 mVdriftTB = mTPCVDriftHelper.getVDriftObject().getVDrift() * o2::tpc::ParameterElectronics::Instance().ZbinWidth; // VDrift expressed in cm/TimeBin
324 mTPCTBBias = mTPCVDriftHelper.getVDriftObject().getTimeOffset() / (8 * o2::constants::lhc::LHCBunchSpacingMUS);
325
326 auto dumpClusters = [this] {
327 static int tf = 0;
328 const auto* corrMap = this->mTPCCorrMaps;
329 for (int sector = 0; sector < 36; sector++) {
330 float alp = ((sector % 18) * 20 + 10) * TMath::DegToRad();
331 float sn = TMath::Sin(alp), cs = TMath::Cos(alp);
332 for (int row = 0; row < 152; row++) {
333 for (int ic = 0; ic < this->mTPCClusterIdxStruct->nClusters[sector][row]; ic++) {
334 const auto cl = this->mTPCClusterIdxStruct->clusters[sector][row][ic];
335 float x, y, z, xG, yG;
336 corrMap->TransformIdeal(sector, row, cl.getPad(), cl.getTime(), x, y, z, 0);
337 o2::math_utils::detail::rotateZ(x, y, xG, yG, sn, cs);
338 LOGP(debug, "tf:{} s:{} r:{} p:{} t:{} qm:{} qt:{} f:{} x:{} y:{} z:{}", tf, sector, row, cl.getPad(), cl.getTime(), cl.getQmax(), cl.getQtot(), cl.getFlags(), x, y, z);
339 (*mDBGOutCl) << "tpccl"
340 << "tf=" << tf << "sect=" << sector << "row=" << row << "pad=" << cl.getPad() << "time=" << cl.getTime() << "qmax=" << cl.getQmax() << "qtot=" << cl.getQtot()
341 << "sigT=" << cl.getSigmaTime() << "sigP=" << cl.getSigmaPad()
342 << "flags=" << cl.getFlags()
343 << "x=" << x << "y=" << y << "z=" << z << "xg=" << xG << "yg=" << yG
344 << "\n";
345 }
346 }
347 }
348 tf++;
349 };
350
351 if (mDBGOutCl) {
352 dumpClusters();
353 }
354
355 if ((mStudyType & StudyType::TPC) == StudyType::TPC) {
356 for (size_t itr = 0; itr < mTPCTracksArray.size(); itr++) {
357 processTPCTrack(mTPCTracksArray[itr], mUseMC ? mTPCTrkLabels[itr] : o2::MCCompLabel{}, mDBGOutTPC.get());
358 }
359 }
360
361 if ((mStudyType & StudyType::ITSTPC) == StudyType::ITSTPC) {
362 for (const auto& tpcitsTrack : mITSTPCTracksArray) {
363 const auto idxTPC = tpcitsTrack.getRefTPC().getIndex();
364 const auto idxITS = tpcitsTrack.getRefITS().getIndex();
365 if (idxITS >= mITSTracksArray.size()) {
366 LOGP(fatal, "ITS index {} out of array size {}", idxITS, mITSTracksArray.size());
367 }
368 if (idxTPC >= mTPCTracksArray.size()) {
369 LOGP(fatal, "TPC index {} out of array size {}", idxTPC, mTPCTracksArray.size());
370 }
371 processTPCTrack(mTPCTracksArray[idxTPC], mUseMC ? mTPCTrkLabels[idxTPC] : o2::MCCompLabel{}, mDBGOutITSTPC.get(), &mITSTracksArray[idxITS], &tpcitsTrack);
372 }
373 }
374
375 if (mCosmics.size() > 0) {
376 LOGP(info, "Procssing {} cosmics", mCosmics.size());
377 processCosmics(recoData);
378 }
379}
380
382{
383 mDBGOutTPC.reset();
384 mDBGOutITSTPC.reset();
385 mDBGOutTPCTF.reset();
386 mDBGOutITSTPCTF.reset();
387 mDBGOutCosmics.reset();
388 mDBGOutCl.reset();
389}
390
392{
394 return;
395 }
396 if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) {
397 return;
398 }
399}
400
401bool TPCRefitterSpec::getDCAs(const o2::track::TrackPar& track, float& dcar, float& dcaz)
402{
403 auto propagator = o2::base::Propagator::Instance();
404 std::array<float, 2> dca;
405 const o2::math_utils::Point3D<float> refPoint{0, 0, 0};
406 o2::track::TrackPar propTrack(track);
407 const auto ok = propagator->propagateToDCABxByBz(refPoint, propTrack, 2., o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dca);
408 dcar = dca[0];
409 dcaz = dca[1];
410 if (!ok) {
411 dcar = 9998.;
412 dcaz = 9998.;
413 }
414 return ok;
415}
416
417bool TPCRefitterSpec::processTPCTrack(o2::tpc::TrackTPC tr, o2::MCCompLabel lbl, o2::utils::TreeStreamRedirector* streamer, const o2::its::TrackITS* its, const o2::dataformats::TrackTPCITS* itstpc, bool outward, float time0custom)
418{
419 auto prop = o2::base::Propagator::Instance();
420 static long counter = -1;
421
422 struct ClusterData {
423 std::vector<int> occCl;
424 std::vector<short> clSector, clRow;
425 std::vector<float> clX, clY, clZ, clXI, clYI, clZI; // *I are the uncorrected cluster positions
426 std::vector<tpc::ClusterNative> clNative;
427 } clData;
428 float dcar, dcaz, dcarRef, dcazRef;
429
430 // auto tr = mTPCTracksArray[itr]; // create track copy
431 if (tr.hasBothSidesClusters()) {
432 return false;
433 }
434
435 bool sampleTsallis = false;
436 bool sampleMB = false;
437 float tsallisWeight = 0;
438 if (mDoSampling) {
439 std::uniform_real_distribution<> distr(0., 1.);
440 if (o2::math_utils::Tsallis::downsampleTsallisCharged(tr.getPt(), mSamplingFactor, mSqrt, tsallisWeight, distr(mGenerator))) {
441 sampleTsallis = true;
442 }
443 if (distr(mGenerator) < mSamplingFactor) {
444 sampleMB = true;
445 }
446
447 if (!sampleMB && !sampleTsallis) {
448 return false;
449 }
450 }
451 //=========================================================================
452 // create refitted copy
453 auto trackRefit = [&tr, this](o2::track::TrackParCov& trc, float t, float chi2refit, bool outward = false) -> bool {
454 int retVal = mUseGPUModel ? this->mTPCRefitter->RefitTrackAsGPU(trc, tr.getClusterRef(), t, &chi2refit, outward, true)
455 : this->mTPCRefitter->RefitTrackAsTrackParCov(trc, tr.getClusterRef(), t, &chi2refit, outward, true);
456 if (retVal < 0) {
457 LOGP(warn, "Refit failed ({}) with time={}: track#{}[{}]", retVal, t, counter, trc.asString());
458 return false;
459 }
460 return true;
461 };
462
463 auto trackProp = [&tr, prop, this](o2::track::TrackParCov& trc) -> bool {
464 if (!trc.rotate(tr.getAlpha())) {
465 LOGP(warn, "Rotation to original track alpha {} failed, track#{}[{}]", tr.getAlpha(), counter, trc.asString());
466 return false;
467 }
468 float xtgt = this->mXRef;
469 if (mUseR && !trc.getXatLabR(this->mXRef, xtgt, prop->getNominalBz(), o2::track::DirInward)) {
470 xtgt = 0;
471 return false;
472 }
473 if (!prop->PropagateToXBxByBz(trc, xtgt)) {
474 LOGP(warn, "Propagation to X={} failed, track#{}[{}]", xtgt, counter, trc.asString());
475 return false;
476 }
477 return true;
478 };
479
480 // auto prepClus = [this, &tr, &clSector, &clRow, &clX, &clY, &clZ, &clXI, &clYI, &clZI, &clNative](float t) { // extract cluster info
481 auto prepClus = [this, &tr, &clData](float t) { // extract cluster info
482 int count = tr.getNClusters();
483 const auto* corrMap = this->mTPCCorrMaps;
484 const o2::tpc::ClusterNative* cl = nullptr;
485 for (int ic = count; ic--;) {
486 uint8_t sector, row;
487 uint32_t clusterIndex;
488 o2::tpc::TrackTPC::getClusterReference(mTPCTrackClusIdx, ic, sector, row, clusterIndex, tr.getClusterRef());
489 unsigned int absoluteIndex = mTPCClusterIdxStruct->clusterOffset[sector][row] + clusterIndex;
490 cl = &mTPCClusterIdxStruct->clusters[sector][row][clusterIndex];
491 uint8_t clflags = cl->getFlags();
492 if (mTPCRefitterShMap[absoluteIndex] & o2::gpu::GPUTPCGMMergedTrackHit::flagShared) {
493 clflags |= 0x10;
494 }
495 clData.clSector.emplace_back(sector);
496 clData.clRow.emplace_back(row);
497 auto& clCopy = clData.clNative.emplace_back(*cl);
498 clCopy.setFlags(clflags);
499
500 float x, y, z;
501 // ideal transformation without distortions
502 corrMap->TransformIdeal(sector, row, cl->getPad(), cl->getTime(), x, y, z, t); // nominal time of the track
503 clData.clXI.emplace_back(x);
504 clData.clYI.emplace_back(y);
505 clData.clZI.emplace_back(z);
506
507 // transformation without distortions
508 mTPCCorrMaps->Transform(sector, row, cl->getPad(), cl->getTime(), x, y, z, t); // nominal time of the track
509 clData.clX.emplace_back(x);
510 clData.clY.emplace_back(y);
511 clData.clZ.emplace_back(z);
512
513 // occupancy estimator
514 const auto tpcTime = cl->getTime() + mTimeBinsPerDrift;
515 const uint32_t clOccPosTPC = static_cast<uint32_t>(tpcTime * mOccupancyBinsPerTF / mTimeBinsPerTF);
516 clData.occCl.emplace_back((clOccPosTPC < mClusterOccupancy.size()) ? mClusterOccupancy[clOccPosTPC] : -1);
517 }
518 };
519
520 //=========================================================================
521
522 auto trf = tr.getOuterParam(); // we refit inward original track
523 float chi2refit = 0;
524 float time0 = tr.getTime0();
525 if (time0custom > 0) {
526 time0 = time0custom;
527 }
528 if (mDoRefit) {
529 if (!trackRefit(trf, time0, chi2refit) || !trackProp(trf)) {
530 return false;
531 }
532 }
533
534 // propagate original track
535 if (!trackProp(tr)) {
536 return false;
537 }
538
539 if (mWriteTrackClusters) {
540 prepClus(time0); // original clusters
541 }
542
543 if (mEnableDCA) {
544 dcar = dcaz = dcarRef = dcazRef = 9999.f;
545 if ((trf.getPt() > mDCAMinPt) && (tr.getNClusters() > mDCAMinNCl)) {
546 getDCAs(trf, dcarRef, dcazRef);
547 getDCAs(tr, dcar, dcaz);
548 }
549 }
550
551 counter++;
552 // store results
553 if (streamer) {
554 (*streamer) << "tpc"
555 << "counter=" << counter
556 << "tfCounter=" << mTFCount
557 << "tpc=" << tr;
558
559 if (mDoRefit) {
560 (*streamer) << "tpc"
561 << "tpcRF=" << trf
562 << "time0=" << time0
563 << "chi2refit=" << chi2refit;
564 }
565
566 if (mDoSampling) {
567 (*streamer) << "tpc"
568 << "tsallisWeight=" << tsallisWeight
569 << "sampleTsallis=" << sampleTsallis
570 << "sampleMB=" << sampleMB;
571 }
572
573 if (mWriteTrackClusters) {
574 (*streamer) << "tpc"
575 << "clSector=" << clData.clSector
576 << "clRow=" << clData.clRow;
577
578 if ((mWriteTrackClusters & 0x1) == 0x1) {
579 (*streamer) << "tpc"
580 << "cl=" << clData.clNative;
581 }
582
583 if ((mWriteTrackClusters & 0x2) == 0x2) {
584 (*streamer) << "tpc"
585 << "clX=" << clData.clX
586 << "clY=" << clData.clY
587 << "clZ=" << clData.clZ;
588 }
589
590 if ((mWriteTrackClusters & 0x4) == 0x4) {
591 (*streamer) << "tpc"
592 << "clXI=" << clData.clXI // ideal (uncorrected) cluster positions
593 << "clYI=" << clData.clYI // ideal (uncorrected) cluster positions
594 << "clZI=" << clData.clZI; // ideal (uncorrected) cluster positions
595 }
596
597 if ((mWriteTrackClusters & 0x8) == 0x8) {
598 (*streamer) << "tpc"
599 << "clOcc=" << clData.occCl;
600 }
601 }
602
603 if (its) {
604 (*streamer) << "tpc"
605 << "its=" << *its;
606 }
607 if (itstpc) {
608 (*streamer) << "tpc"
609 << "itstpc=" << *itstpc;
610 }
611
612 if (mEnableDCA) {
613 (*streamer) << "tpc"
614 << "dcar=" << dcar
615 << "dcaz=" << dcaz
616 << "dcarRef=" << dcarRef
617 << "dcazRef=" << dcazRef;
618 }
619
620 if (mUseMC) {
621 (*streamer) << "tpc"
622 << "mcLabel=" << lbl;
623 }
624
625 (*streamer) << "tpc"
626 << "\n";
627 }
628
629 float dz = 0;
630
631 if (mUseMC) { // impose MC time in TPC timebin and refit inward after resetted covariance
632 // extract MC truth
633 const o2::MCTrack* mcTrack = nullptr;
634 if (!lbl.isValid() || !(mcTrack = mcReader.getTrack(lbl))) {
635 return false;
636 }
637 long bc = mIntRecs[lbl.getEventID()].toLong(); // bunch crossing of the interaction
638 float bcTB = bc / 8. + mTPCTBBias; // the same in TPC timebins, accounting for the TPC time bias
639 // create MC truth track in O2 format
640 std::array<float, 3> xyz{(float)mcTrack->GetStartVertexCoordinatesX(), (float)mcTrack->GetStartVertexCoordinatesY(), (float)mcTrack->GetStartVertexCoordinatesZ()},
641 pxyz{(float)mcTrack->GetStartVertexMomentumX(), (float)mcTrack->GetStartVertexMomentumY(), (float)mcTrack->GetStartVertexMomentumZ()};
642 TParticlePDG* pPDG = TDatabasePDG::Instance()->GetParticle(mcTrack->GetPdgCode());
643 if (!pPDG) {
644 return false;
645 }
646 o2::track::TrackPar mctrO2(xyz, pxyz, TMath::Nint(pPDG->Charge() / 3), false);
647 //
648 // propagate it to the alpha/X of the reconstructed track
649 if (!mctrO2.rotate(tr.getAlpha()) || !prop->PropagateToXBxByBz(mctrO2, tr.getX())) {
650 return false;
651 }
652 // now create a properly refitted track with correct time and distortions correction
653 {
654 auto trfm = tr.getOuterParam(); // we refit inward
655 // impose MC time in TPC timebin and refit inward after resetted covariance
656 float chi2refit = 0;
657 if (!trackRefit(trfm, bcTB, chi2refit) || !trfm.rotate(tr.getAlpha()) || !prop->PropagateToXBxByBz(trfm, tr.getX())) {
658 LOGP(warn, "Failed to propagate MC-time refitted track#{} [{}] to X/alpha of original track [{}]", counter, trfm.asString(), tr.asString());
659 return false;
660 }
661 // estimate Z shift in case of no-distortions
662 dz = (tr.getTime0() - bcTB) * mVdriftTB;
663 if (tr.hasCSideClustersOnly()) {
664 dz = -dz;
665 }
666 //
667 prepClus(bcTB); // clusters for MC time
668 if (streamer) {
669 (*streamer) << "tpcMC"
670 << "counter=" << counter
671 << "movTrackRef=" << trfm
672 << "mcTrack=" << mctrO2
673 << "imposedTB=" << bcTB
674 << "chi2refit=" << chi2refit
675 << "dz=" << dz
676 << "clX=" << clData.clX
677 << "clY=" << clData.clY
678 << "clZ=" << clData.clZ
679 << "\n";
680 }
681 }
682 return false;
683 }
684
685 return true;
686}
687
688void TPCRefitterSpec::processCosmics(o2::globaltracking::RecoContainer& recoData)
689{
691 const auto invBinWidth = 1.f / par.ZbinWidth;
692
693 for (const auto& cosmic : mCosmics) {
694 //
695 const GTrackID gidTopBot[] = {cosmic.getRefTop(), cosmic.getRefBottom()};
696 // LOGP(info, "Sources: {} - {}", o2::dataformats::GlobalTrackID::getSourceName(gidTopBot[0].getSource()), o2::dataformats::GlobalTrackID::getSourceName(gidTopBot[1].getSource()));
697 // Wequire at least one TRD of TOF contribution to constrain the timestamp
698 bool hasGoodTime[2] = {false, false};
699 std::array<GTrackID, GTrackID::NSources> contributorsGID[2];
700 for (int i = 0; i < 2; i++) {
701 contributorsGID[i] = recoData.getSingleDetectorRefs(gidTopBot[i]);
702 hasGoodTime[i] = gidTopBot[i].includesDet(DetID::TOF) || gidTopBot[i].includesDet(DetID::TRD);
703 }
704 if (!hasGoodTime[0] && !hasGoodTime[1]) {
705 continue;
706 }
707 float trackTime = cosmic.getTimeMUS().getTimeStamp() * invBinWidth; // this time corresponds to the center of top/bottom legs time-brackers intersection, i.e. should be the most precise one
708
709 for (int i = 0; i < 2; i++) {
710 if (!contributorsGID[i][GTrackID::TPC].isSourceSet() || (mIgnorLegsWOGoodTime && !hasGoodTime[i])) {
711 continue;
712 }
713 const auto& trackTPC = mTPCTracksArray[contributorsGID[i][GTrackID::TPC]];
714 float useTrackTime = trackTime, dummyError = 0.f;
715 if (mUseCosmicLegTiming && hasGoodTime[i]) { // track out time was requested (if available)
716 recoData.getTrackTime(gidTopBot[i], useTrackTime, dummyError);
717 useTrackTime *= invBinWidth;
718 }
719 processTPCTrack(trackTPC, mUseMC ? mTPCTrkLabels[contributorsGID[i][GTrackID::TPC]] : o2::MCCompLabel{}, mDBGOutCosmics.get(), nullptr, nullptr, false, useTrackTime);
720 }
721 }
722}
723
724DataProcessorSpec getTPCRefitterSpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool useMC, bool requestCosmics)
725{
726 std::vector<OutputSpec> outputs;
727 Options opts{
728 {"target-x", VariantType::Float, 83.f, {"Try to propagate to this radius"}},
729 {"dump-clusters", VariantType::Bool, false, {"dump all clusters"}},
730 {"write-track-clusters", VariantType::Int, 3, {"Bitmask write clusters associated to the track, full native cluster (0x1), corrected (0x2) and uncorrected (0x4) positions, (0x8) occupancy info"}},
731 {"tf-start", VariantType::Int, 0, {"1st TF to process"}},
732 {"tf-end", VariantType::Int, 999999999, {"last TF to process"}},
733 {"use-gpu-fitter", VariantType::Bool, false, {"use GPU track model for refit instead of TrackParCov"}},
734 {"do-refit", VariantType::Bool, false, {"do refitting of TPC track"}},
735 {"use-r-as-x", VariantType::Bool, false, {"Use radius instead of target sector X"}},
736 {"enable-dcas", VariantType::Bool, false, {"Propagate to DCA and add it to the tree"}},
737 {"dcaMinPt", VariantType::Float, 1.f, {"Min pT of tracks propagated to DCA"}},
738 {"dcaMinNCl", VariantType::Int, 80, {"Min number of clusters for tracks propagated to DCA"}},
739 {"sqrts", VariantType::Float, 13600.f, {"Centre of mass energy used for downsampling"}},
740 {"do-sampling", VariantType::Bool, false, {"Perform sampling, min. bias and on Tsallis function, using 'sampling-factor'"}},
741 {"sampling-factor", VariantType::Float, 0.1f, {"Sampling factor in case sample-unbinned-tsallis is used"}},
742 {"study-type", VariantType::Int, 1, {"Bitmask of study type: 0x1 = TPC only, 0x2 = TPC + ITS, 0x4 = Cosmics"}},
743 {"writer-type", VariantType::Int, 1, {"Bitmask of writer type: 0x1 = per track streamer, 0x2 = per TF vectors"}},
744 {"occupancy-bins-per-drift", VariantType::UInt32, 31u, {"number of bin for occupancy histogram per drift time (500tb)"}},
745 {"ignore-legs-wo-outer-det", VariantType::Bool, false, {"Ignore cosmic legs w/o TRD or TOF constraint even if other leg is well constrained"}},
746 {"use-cosmic-leg-timing", VariantType::Bool, false, {"Use leg-specific timestamp instead of cosmic track final timestamp"}},
747 };
748 auto dataRequest = std::make_shared<DataRequest>();
749
750 dataRequest->requestTracks(srcTracks, useMC);
751 dataRequest->requestClusters(srcClusters, useMC);
752 if (requestCosmics) {
753 dataRequest->requestCoscmicTracks(useMC);
754 }
755 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(false, // orbitResetTime
756 true, // GRPECS=true
757 false, // GRPLHCIF
758 true, // GRPMagField
759 true, // askMatLUT
761 dataRequest->inputs,
762 true);
763 o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs);
764 dataRequest->inputs.emplace_back("corrMap", o2::header::gDataOriginTPC, "TPCCORRMAP", 0, Lifetime::Timeframe);
765 return DataProcessorSpec{
766 "tpc-refitter",
767 dataRequest->inputs,
768 outputs,
769 AlgorithmSpec{adaptFromTask<TPCRefitterSpec>(dataRequest, ggRequest, srcTracks, useMC)},
770 opts};
771}
772
773} // namespace o2::trackstudy
Wrapper container for different reconstructed object types.
std::ostringstream debug
uint64_t bc
Definition RawEventData.h:5
int32_t i
o2::raw::RawFileWriter * raw
int32_t retVal
Helper for geometry and GRP related CCDB requests.
Global index for barrel track: provides provenance (detectors combination), index in respective array...
Header to collect LHC related constants.
Definition of the parameter class for the detector electronics.
uint32_t padrow
Definition RawData.h:5
Wrapper container for different reconstructed object types.
POD correction map.
Result of top-bottom cosmic tracks leg matching.
Helper class to extract VDrift from different sources.
int getEventID() const
bool isValid() const
Definition MCCompLabel.h:75
Double_t GetStartVertexMomentumZ() const
Definition MCTrack.h:81
Double_t GetStartVertexMomentumX() const
Definition MCTrack.h:79
Double_t GetStartVertexCoordinatesY() const
Definition MCTrack.h:83
Double_t GetStartVertexCoordinatesZ() const
Definition MCTrack.h:84
Double_t GetStartVertexMomentumY() const
Definition MCTrack.h:80
Double_t GetStartVertexCoordinatesX() const
Definition MCTrack.h:82
Int_t GetPdgCode() const
Accessors.
Definition MCTrack.h:72
void checkUpdates(o2::framework::ProcessingContext &pc)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:178
Static class with identifiers, bitmasks and names for ALICE detectors.
Definition DetID.h:58
static constexpr ID TRD
Definition DetID.h:65
static constexpr ID TOF
Definition DetID.h:66
ServiceRegistryRef services()
Definition InitContext.h:34
ConfigParamRegistry const & options()
Definition InitContext.h:33
decltype(auto) get(R binding, int part=0) const
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
std::vector< o2::InteractionTimeRecord > & getEventRecords(bool withQED=false)
bool initFromDigitContext(std::string_view filename)
DigitizationContext const * getDigitizationContext() const
MCTrack const * getTrack(o2::MCCompLabel const &) const
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)
TPCRefitterSpec(std::shared_ptr< DataRequest > dr, std::shared_ptr< o2::base::GRPGeomRequest > gr, GTrackID::mask_t src, bool useMC)
void process(o2::globaltracking::RecoContainer &recoData)
void run(ProcessingContext &pc) final
void init(InitContext &ic) final
void endOfStream(EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
@ ITSTPC
TPC + ITS matched tracks.
bool getDCAs(const o2::track::TrackPar &track, float &dcar, float &dcaz)
@ Streamer
Write per track streamer information.
@ TFVectors
Writer vectors per TF.
void finaliseCCDB(ConcreteDataMatcher &matcher, void *obj) final
GLint GLenum GLint x
Definition glcorearb.h:403
GLenum src
Definition glcorearb.h:1767
GLint GLsizei count
Definition glcorearb.h:399
GLint y
Definition glcorearb.h:270
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
GLuint counter
Definition glcorearb.h:3987
constexpr o2::header::DataOrigin gDataOriginTPC
Definition DataHeader.h:576
uint8_t itsSharedClusterMap uint8_t
constexpr double LHCBunchSpacingMUS
constexpr int LHCMaxBunches
Node par(int index)
Parameters.
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
std::vector< ConfigParamSpec > Options
auto get(const std::byte *buffer, size_t=0)
Definition DataHeader.h:454
std::tuple< T, T > rotateZ(T xL, T yL, T snAlp, T csAlp)
detail::Bracket< float > Bracketf_t
Definition Primitive2D.h:40
return * this
TrackParCovF TrackParCov
Definition Track.h:33
o2::math_utils::Bracketf_t TBracket
o2::framework::DataProcessorSpec getTPCRefitterSpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC, bool requestCosmics=false)
create a processor spec
o2::dataformats::VtxTrackRef V2TRef
o2::dataformats::VtxTrackIndex VTIndex
@ sampleTsallis
perform sampling on tsallis pdf
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::unique_ptr< GPUReconstructionTimeframe > tf
GlobalIDSet getSingleDetectorRefs(GTrackID gidx) const
gsl::span< const unsigned char > clusterShMapTPC
externally set TPC clusters sharing map
void collectData(o2::framework::ProcessingContext &pc, const DataRequest &request)
std::unique_ptr< o2::tpc::internal::getWorkflowTPCInput_ret > inputsTPCclusters
void getTrackTime(GTrackID gid, float &t, float &tErr) const
gsl::span< const unsigned int > occupancyMapTPC
externally set TPC clusters occupancy map
static bool downsampleTsallisCharged(float pt, float factorPt, float sqrts, float &weight, float rnd, float mass=0.13957)
Definition Tsallis.cxx:31
int nHBFPerTF
number of orbits per BC
Definition HBFUtils.h:138
unsigned int nClusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
const ClusterNative * clusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
unsigned int clusterOffset[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
float getTimeOffset() const
std::uniform_int_distribution< unsigned long long > distr
std::vector< int > row