Project
Loading...
Searching...
No Matches
TPCTrackStudy.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 <vector>
13#include <TStopwatch.h>
17#include "TPCFastTransformPOD.h"
30#include "GPUO2InterfaceRefit.h"
34
35namespace o2::trackstudy
36{
37
38using namespace o2::framework;
41
47
49
50class TPCTrackStudySpec final : public Task
51{
52 public:
53 TPCTrackStudySpec(std::shared_ptr<DataRequest> dr, std::shared_ptr<o2::base::GRPGeomRequest> gr, GTrackID::mask_t src, bool useMC)
54 : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mUseMC(useMC) {}
55 ~TPCTrackStudySpec() final = default;
56 void init(InitContext& ic) final;
57 void run(ProcessingContext& pc) final;
58 void endOfStream(EndOfStreamContext& ec) final;
59 void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final;
60 void process(o2::globaltracking::RecoContainer& recoData);
61
62 private:
63 void updateTimeDependentParams(ProcessingContext& pc);
64 std::shared_ptr<DataRequest> mDataRequest;
65 std::shared_ptr<o2::base::GRPGeomRequest> mGGCCDBRequest;
66 o2::tpc::VDriftHelper mTPCVDriftHelper{};
67 const o2::gpu::TPCFastTransformPOD* mTPCCorrMaps{nullptr};
68 bool mUseMC{false};
69 bool mUseGPUModel{false};
70 float mXRef = 0.;
71 int mNMoves = 6;
72 int mTFStart = 0;
73 int mTFEnd = 999999999;
74 int mTFCount = -1;
75 bool mUseR = false;
76 bool mRepRef = false;
77 std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOut;
78 std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOutCl;
79 float mITSROFrameLengthMUS = 0.;
80 GTrackID::mask_t mTracksSrc{};
81 o2::steer::MCKinematicsReader mcReader; // reader of MC information
82 //
83 // TPC data
84 gsl::span<const o2::tpc::TPCClRefElem> mTPCTrackClusIdx;
85 gsl::span<const o2::tpc::TrackTPC> mTPCTracksArray;
86 gsl::span<const unsigned char> mTPCRefitterShMap;
87 gsl::span<const unsigned int> mTPCRefitterOccMap;
88 const o2::tpc::ClusterNativeAccess* mTPCClusterIdxStruct = nullptr;
89 gsl::span<const o2::MCCompLabel> mTPCTrkLabels;
90 std::unique_ptr<o2::gpu::GPUO2InterfaceRefit> mTPCRefitter;
91};
92
94{
96 mXRef = ic.options().get<float>("target-x");
97 mNMoves = std::max(2, ic.options().get<int>("n-moves"));
98 mUseR = ic.options().get<bool>("use-r-as-x");
99 mRepRef = ic.options().get<bool>("repeat-ini-ref");
100 mUseGPUModel = ic.options().get<bool>("use-gpu-fitter");
101 mTFStart = ic.options().get<int>("tf-start");
102 mTFEnd = ic.options().get<int>("tf-end");
103 if (mXRef < 0.) {
104 mXRef = 0.;
105 }
106 mDBGOut = std::make_unique<o2::utils::TreeStreamRedirector>("tpc-trackStudy.root", "recreate");
107 if (ic.options().get<bool>("dump-clusters")) {
108 mDBGOutCl = std::make_unique<o2::utils::TreeStreamRedirector>("tpc-trackStudy-cl.root", "recreate");
109 }
110}
111
113{
114 mTFCount++;
115 if (mTFCount < mTFStart || mTFCount > mTFEnd) {
116 LOGP(info, "Skipping TF {}", mTFCount);
117 return;
118 }
119
121 recoData.collectData(pc, *mDataRequest.get()); // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer
122 updateTimeDependentParams(pc); // Make sure this is called after recoData.collectData, which may load some conditions
123 process(recoData);
124
125 if (mTFCount > mTFEnd) {
126 LOGP(info, "Stopping processing after TF {}", mTFCount);
128 return;
129 }
130}
131
132void TPCTrackStudySpec::updateTimeDependentParams(ProcessingContext& pc)
133{
135 mTPCVDriftHelper.extractCCDBInputs(pc);
136 auto const& raw = pc.inputs().get<const char*>("corrMap");
137 mTPCCorrMaps = &o2::gpu::TPCFastTransformPOD::get(raw);
138 static bool initOnceDone = false;
139 if (!initOnceDone) { // this params need to be queried only once
140 initOnceDone = true;
141 // none at the moment
142 }
143}
144
146{
147 static long counter = -1;
148 auto prop = o2::base::Propagator::Instance();
149
150 mTPCTracksArray = recoData.getTPCTracks();
151 mTPCTrackClusIdx = recoData.getTPCTracksClusterRefs();
152 mTPCClusterIdxStruct = &recoData.inputsTPCclusters->clusterIndex;
153 mTPCRefitterShMap = recoData.clusterShMapTPC;
154 mTPCRefitterOccMap = recoData.occupancyMapTPC;
155
156 std::vector<o2::InteractionTimeRecord> intRecs;
157 if (mUseMC) { // extract MC tracks
158 const o2::steer::DigitizationContext* digCont = nullptr;
159 if (!mcReader.initFromDigitContext("collisioncontext.root")) {
160 throw std::invalid_argument("initialization of MCKinematicsReader failed");
161 }
162 digCont = mcReader.getDigitizationContext();
163 intRecs = digCont->getEventRecords();
164 mTPCTrkLabels = recoData.getTPCTracksMCLabels();
165 }
166 if (mTPCTracksArray.size()) {
167 LOGP(info, "Found {} TPC tracks", mTPCTracksArray.size());
168 mTPCRefitter = std::make_unique<o2::gpu::GPUO2InterfaceRefit>(mTPCClusterIdxStruct, mTPCCorrMaps, prop->getNominalBz(), mTPCTrackClusIdx.data(), 0, mTPCRefitterShMap.data(), mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size(), nullptr, o2::base::Propagator::Instance());
169 }
170 float vdriftTB = mTPCVDriftHelper.getVDriftObject().getVDrift() * o2::tpc::ParameterElectronics::Instance().ZbinWidth; // VDrift expressed in cm/TimeBin
171 float tpcTBBias = mTPCVDriftHelper.getVDriftObject().getTimeOffset() / (8 * o2::constants::lhc::LHCBunchSpacingMUS);
172 std::vector<short> clSector, clRow;
173 std::vector<float> clX, clY, clZ;
174
175 auto dumpClusters = [this] {
176 static int tf = 0;
177 const auto* corrMap = this->mTPCCorrMaps;
178 for (int sector = 0; sector < 36; sector++) {
179 float alp = ((sector % 18) * 20 + 10) * TMath::DegToRad();
180 float sn = TMath::Sin(alp), cs = TMath::Cos(alp);
181 for (int row = 0; row < 152; row++) {
182 for (int ic = 0; ic < this->mTPCClusterIdxStruct->nClusters[sector][row]; ic++) {
183 const auto cl = this->mTPCClusterIdxStruct->clusters[sector][row][ic];
184 float x, y, z, xG, yG;
185 corrMap->TransformIdeal(sector, row, cl.getPad(), cl.getTime(), x, y, z, 0);
186 o2::math_utils::detail::rotateZ(x, y, xG, yG, sn, cs);
187 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);
188 (*mDBGOutCl) << "tpccl"
189 << "tf=" << tf << "sect=" << sector << "row=" << row << "pad=" << cl.getPad() << "time=" << cl.getTime() << "qmax=" << cl.getQmax() << "qtot=" << cl.getQtot()
190 << "sigT=" << cl.getSigmaTime() << "sigP=" << cl.getSigmaPad()
191 << "flags=" << cl.getFlags()
192 << "x=" << x << "y=" << y << "z=" << z << "xg=" << xG << "yg=" << yG
193 << "\n";
194 }
195 }
196 }
197 tf++;
198 };
199
200 if (mDBGOutCl) {
201 dumpClusters();
202 }
203
204 for (size_t itr = 0; itr < mTPCTracksArray.size(); itr++) {
205 auto tr = mTPCTracksArray[itr]; // create track copy
206 int side = 0;
207 if (tr.hasBothSidesClusters()) {
208 continue;
209 }
210 side = tr.hasASideClustersOnly() ? 1 : -1;
211 //=========================================================================
212 // create refitted copy
213 auto trackRefit = [itr, this](o2::track::TrackParCov& trc, float t) -> bool {
214 float chi2Out = 0;
215 int retVal = mUseGPUModel ? this->mTPCRefitter->RefitTrackAsGPU(trc, this->mTPCTracksArray[itr].getClusterRef(), t, &chi2Out, false, true) : this->mTPCRefitter->RefitTrackAsTrackParCov(trc, this->mTPCTracksArray[itr].getClusterRef(), t, &chi2Out, false, true);
216 if (retVal < 0) {
217 LOGP(warn, "Refit failed ({}) with time={}: track#{}[{}]", retVal, t, counter, trc.asString());
218 return false;
219 }
220 return true;
221 };
222
223 auto trackProp = [&tr, itr, prop, this](o2::track::TrackParCov& trc) -> bool {
224 if (!trc.rotate(tr.getAlpha())) {
225 LOGP(warn, "Rotation to original track alpha {} failed, track#{}[{}]", tr.getAlpha(), counter, trc.asString());
226 return false;
227 }
228 float xtgt = this->mXRef;
229 if (mUseR && !trc.getXatLabR(this->mXRef, xtgt, prop->getNominalBz(), o2::track::DirInward)) {
230 xtgt = 0;
231 return false;
232 }
233 if (!prop->PropagateToXBxByBz(trc, xtgt)) {
234 LOGP(warn, "Propagation to X={} failed, track#{}[{}]", xtgt, counter, trc.asString());
235 return false;
236 }
237 return true;
238 };
239
240 auto prepClus = [this, &tr, &clSector, &clRow, &clX, &clY, &clZ](float t) { // extract cluster info
241 clSector.clear();
242 clRow.clear();
243 clX.clear();
244 clY.clear();
245 clZ.clear();
246 int count = tr.getNClusters();
247 const o2::tpc::ClusterNative* cl = nullptr;
248 for (int ic = count; ic--;) {
249 uint8_t sector, row;
250 cl = &tr.getCluster(this->mTPCTrackClusIdx, ic, *this->mTPCClusterIdxStruct, sector, row);
251 clSector.push_back(sector);
252 clRow.push_back(row);
253 float x, y, z;
254 mTPCCorrMaps->Transform(sector, row, cl->getPad(), cl->getTime(), x, y, z, t); // nominal time of the track
255 clX.push_back(x);
256 clY.push_back(y);
257 clZ.push_back(z);
258 }
259 };
260
261 //=========================================================================
262
263 auto trf = tr.getOuterParam(); // we refit inward original track
264 if (!trackRefit(trf, tr.getTime0()) || !trackProp(trf)) {
265 continue;
266 }
267
268 // propagate original track
269 if (!trackProp(tr)) {
270 continue;
271 }
272
273 prepClus(tr.getTime0()); // original clusters
274 counter++;
275 // store results
276 (*mDBGOut) << "tpcIni"
277 << "counter=" << counter
278 << "iniTrack=" << tr
279 << "iniTrackRef=" << trf
280 << "side=" << side
281 << "time=" << tr.getTime0()
282 << "clSector=" << clSector
283 << "clRow=" << clRow
284 << "clX=" << clX
285 << "clY=" << clY
286 << "clZ=" << clZ
287 << "\n";
288
289 float dz = 0;
290
291 while (mUseMC) { // impose MC time in TPC timebin and refit inward after resetted covariance
292 // extract MC truth
293 const o2::MCTrack* mcTrack = nullptr;
294 auto lbl = mTPCTrkLabels[itr];
295 if (!lbl.isValid() || !(mcTrack = mcReader.getTrack(lbl))) {
296 break;
297 }
298 long bc = intRecs[lbl.getEventID()].toLong(); // bunch crossing of the interaction
299 float bcTB = bc / 8. + tpcTBBias; // the same in TPC timebins, accounting for the TPC time bias
300 // create MC truth track in O2 format
301 std::array<float, 3> xyz{(float)mcTrack->GetStartVertexCoordinatesX(), (float)mcTrack->GetStartVertexCoordinatesY(), (float)mcTrack->GetStartVertexCoordinatesZ()},
302 pxyz{(float)mcTrack->GetStartVertexMomentumX(), (float)mcTrack->GetStartVertexMomentumY(), (float)mcTrack->GetStartVertexMomentumZ()};
303 TParticlePDG* pPDG = TDatabasePDG::Instance()->GetParticle(mcTrack->GetPdgCode());
304 if (!pPDG) {
305 break;
306 }
307 o2::track::TrackPar mctrO2(xyz, pxyz, TMath::Nint(pPDG->Charge() / 3), false);
308 //
309 // propagate it to the alpha/X of the reconstructed track
310 if (!mctrO2.rotate(tr.getAlpha()) || !prop->PropagateToXBxByBz(mctrO2, tr.getX())) {
311 break;
312 }
313 // now create a properly refitted track with correct time and distortions correction
314 {
315 auto trfm = tr.getOuterParam(); // we refit inward
316 // impose MC time in TPC timebin and refit inward after resetted covariance
317 if (!trackRefit(trfm, bcTB) || !trfm.rotate(tr.getAlpha()) || !prop->PropagateToXBxByBz(trfm, tr.getX())) {
318 LOGP(warn, "Failed to propagate MC-time refitted track#{} [{}] to X/alpha of original track [{}]", counter, trfm.asString(), tr.asString());
319 break;
320 }
321 // estimate Z shift in case of no-distortions
322 dz = (tr.getTime0() - bcTB) * vdriftTB;
323 if (tr.hasCSideClustersOnly()) {
324 dz = -dz;
325 }
326 //
327 prepClus(bcTB); // clusters for MC time
328 (*mDBGOut) << "tpcMC"
329 << "counter=" << counter
330 << "movTrackRef=" << trfm
331 << "mcTrack=" << mctrO2
332 << "side=" << side
333 << "imposedTB=" << bcTB
334 << "dz=" << dz
335 << "clX=" << clX
336 << "clY=" << clY
337 << "clZ=" << clZ
338 << "\n";
339 }
340 break;
341 }
342 // refit and store the same track for a few compatible times
343 float tmin = tr.getTime0() - tr.getDeltaTBwd();
344 float tmax = tr.getTime0() + tr.getDeltaTFwd();
345 for (int it = 0; it < mNMoves; it++) {
346 float tb = tmin + it * (tmax - tmin) / (mNMoves - 1);
347 auto trfm = tr.getOuterParam(); // we refit inward
348 // impose time in TPC timebin and refit inward after resetted covariance
349 if (!trackRefit(trfm, tb) || !trfm.rotate(tr.getAlpha()) || !prop->PropagateToXBxByBz(trfm, tr.getX())) {
350 LOGP(warn, "Failed to propagate time={} refitted track#{} [{}] to X/alpha of original track [{}]", tb, counter, trfm.asString(), tr.asString());
351 continue;
352 }
353 // estimate Z shift in case of no-distortions
354 dz = (tr.getTime0() - tb) * vdriftTB;
355 if (tr.hasCSideClustersOnly()) {
356 dz = -dz;
357 }
358 //
359 int mnm = mNMoves - 1;
360 prepClus(tb); // clusters for MC time
361 (*mDBGOut) << "tpcMov"
362 << "counter=" << counter
363 << "copy=" << it
364 << "maxCopy=" << mnm
365 << "movTrackRef=" << trfm;
366 if (mRepRef) {
367 (*mDBGOut) << "tpcMov"
368 << "iniTrackRef=" << trf << "time=" << tr.getTime0();
369 }
370 (*mDBGOut) << "tpcMov"
371 << "side=" << side
372 << "imposedTB=" << tb
373 << "dz=" << dz
374 << "clX=" << clX
375 << "clY=" << clY
376 << "clZ=" << clZ
377 << "\n";
378 }
379 }
380}
381
383{
384 mDBGOut.reset();
385 mDBGOutCl.reset();
386}
387
389{
391 return;
392 }
393 if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) {
394 return;
395 }
396}
397
399{
400 std::vector<OutputSpec> outputs;
401 Options opts{
402 {"target-x", VariantType::Float, 70.f, {"Try to propagate to this radius"}},
403 {"n-moves", VariantType::Int, 6, {"Number of moves in allow range"}},
404 {"dump-clusters", VariantType::Bool, false, {"dump clusters"}},
405 {"tf-start", VariantType::Int, 0, {"1st TF to process"}},
406 {"tf-end", VariantType::Int, 999999999, {"last TF to process"}},
407 {"use-gpu-fitter", VariantType::Bool, false, {"use GPU track model for refit instead of TrackParCov"}},
408 {"repeat-ini-ref", VariantType::Bool, false, {"store ini-refit param with every moved track"}},
409 {"use-r-as-x", VariantType::Bool, false, {"Use radius instead of target sector X"}}};
410 auto dataRequest = std::make_shared<DataRequest>();
411
412 dataRequest->requestTracks(srcTracks, useMC);
413 dataRequest->requestClusters(srcClusters, useMC);
414 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(false, // orbitResetTime
415 true, // GRPECS=true
416 false, // GRPLHCIF
417 true, // GRPMagField
418 true, // askMatLUT
420 dataRequest->inputs,
421 true);
422 o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs);
423 dataRequest->inputs.emplace_back("corrMap", o2::header::gDataOriginTPC, "TPCCORRMAP", 0, Lifetime::Timeframe);
424
425 return DataProcessorSpec{
426 "tpc-track-study",
427 dataRequest->inputs,
428 outputs,
429 AlgorithmSpec{adaptFromTask<TPCTrackStudySpec>(dataRequest, ggRequest, srcTracks, useMC)},
430 opts};
431}
432
433} // namespace o2::trackstudy
Wrapper container for different reconstructed object types.
Definition of the GeometryManager class.
std::ostringstream debug
uint64_t bc
Definition RawEventData.h:5
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...
Utility functions for MC particles.
Definition of the Names Generator class.
Definition of the parameter class for the detector electronics.
uint32_t side
Definition RawData.h:0
Wrapper container for different reconstructed object types.
POD correction map.
Helper class to extract VDrift from different sources.
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
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)
TPCTrackStudySpec(std::shared_ptr< DataRequest > dr, std::shared_ptr< o2::base::GRPGeomRequest > gr, GTrackID::mask_t src, bool useMC)
void endOfStream(EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
void init(InitContext &ic) final
void run(ProcessingContext &pc) final
void process(o2::globaltracking::RecoContainer &recoData)
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
constexpr double LHCBunchSpacingMUS
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
std::vector< ConfigParamSpec > Options
std::tuple< T, T > rotateZ(T xL, T yL, T snAlp, T csAlp)
detail::Bracket< float > Bracketf_t
Definition Primitive2D.h:40
TrackParCovF TrackParCov
Definition Track.h:33
o2::math_utils::Bracketf_t TBracket
o2::dataformats::VtxTrackRef V2TRef
o2::dataformats::VtxTrackIndex VTIndex
o2::framework::DataProcessorSpec getTPCTrackStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC)
create a processor spec
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::unique_ptr< GPUReconstructionTimeframe > tf
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
gsl::span< const unsigned int > occupancyMapTPC
externally set TPC clusters occupancy map
unsigned int nClusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
const ClusterNative * clusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
float getTimeOffset() const
std::vector< int > row