Project
Loading...
Searching...
No Matches
TrackingStudy.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 <cmath>
14
15#include <TStopwatch.h>
16#include <TF1.h>
17
31#include "Framework/Task.h"
33#include "ITS3Base/SpecsV2.h"
46
47namespace o2::its3::study
48{
49
50using namespace o2::framework;
56using T2VMap = std::unordered_map<GTrackID, size_t>;
57
58class TrackingStudySpec : public Task
59{
60 public:
61 TrackingStudySpec(std::shared_ptr<DataRequest> dr, std::shared_ptr<o2::base::GRPGeomRequest> gr, GTrackID::mask_t src, bool useMC)
62 : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mUseMC(useMC) {}
63 ~TrackingStudySpec() final = default;
64 void init(InitContext& ic) final;
65 void run(ProcessingContext& pc) final;
66 void endOfStream(EndOfStreamContext& ec) final;
67 void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final;
68
69 private:
70 void process(o2::globaltracking::RecoContainer& recoData);
71 void updateTimeDependentParams(ProcessingContext& pc);
72 std::vector<o2::BaseCluster<float>> prepareITSClusters(const o2::globaltracking::RecoContainer& data) const;
73 bool selectTrack(GTrackID trkID, o2::globaltracking::RecoContainer& recoData, bool checkMCTruth = true) const;
74 T2VMap buildT2V(o2::globaltracking::RecoContainer& recoData, bool includeCont = false, bool requireMCMatch = true) const;
75 bool refitITSPVTrack(o2::globaltracking::RecoContainer& recoData, o2::track::TrackParCov& trFit, GTrackID gidx);
76 void doDCAStudy(o2::globaltracking::RecoContainer& recoData);
77 void doDCARefitStudy(o2::globaltracking::RecoContainer& recoData);
78 void doPullStudy(o2::globaltracking::RecoContainer& recoData);
79 void doMCStudy(o2::globaltracking::RecoContainer& recoData);
80
81 struct TrackCounter {
82 TrackCounter() = default;
83
84 void operator+=(int src)
85 {
86 if (src >= 0 && src < static_cast<int>(mSuccess.size())) {
87 ++mSuccess[src];
88 }
89 }
90
91 void operator-=(int src)
92 {
93 if (src >= 0 && src < static_cast<int>(mirrors.size())) {
94 ++mirrors[src];
95 }
96 }
97
98 void operator&=(int src)
99 {
100 if (src >= 0 && src < static_cast<int>(mRejected.size())) {
101 ++mRejected[src];
102 }
103 }
104
105 void print() const
106 {
107 LOGP(info, "\t\t\tSuccess / Error / Rejected");
108 for (int cis = 0; cis < GTrackID::NSources; ++cis) {
109 const auto cdm = GTrackID::getSourceDetectorsMask(cis);
110 if (cdm[DetID::ITS]) {
111 LOGP(info, "\t{:{}}\t{} / {} / {}", GTrackID::getSourceName(cis), 15, mSuccess[cis], mirrors[cis], mRejected[cis]);
112 }
113 }
114 }
115
116 void reset()
117 {
118 mSuccess.fill(0);
119 mirrors.fill(0);
120 mRejected.fill(0);
121 }
122
123 std::array<size_t, GTrackID::NSources> mSuccess{};
124 std::array<size_t, GTrackID::NSources> mirrors{};
125 std::array<size_t, GTrackID::NSources> mRejected{};
126 };
127 TrackCounter mTrackCounter;
128
129 std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOut;
130 std::shared_ptr<DataRequest> mDataRequest;
131 std::shared_ptr<o2::base::GRPGeomRequest> mGGCCDBRequest;
132 bool mUseMC{false};
133 GTrackID::mask_t mTracksSrc;
134 o2::vertexing::PVertexer mVertexer;
135 o2::steer::MCKinematicsReader mcReader; // reader of MC information
136 const o2::its3::TopologyDictionary* mITSDict = nullptr; // cluster patterns dictionary
137};
138
140{
142 int lane = ic.services().get<const o2::framework::DeviceSpec>().inputTimesliceId;
143 int maxLanes = ic.services().get<const o2::framework::DeviceSpec>().maxInputTimeslices;
144 std::string dbgnm = maxLanes == 1 ? "its3TrackStudy.root" : fmt::format("its3TrackStudy_{}.root", lane);
145 mDBGOut = std::make_unique<o2::utils::TreeStreamRedirector>(dbgnm.c_str(), "recreate");
146
148 LOGP(fatal, "initialization of MCKinematicsReader failed");
149 }
150}
151
153{
155 recoData.collectData(pc, *mDataRequest);
156 updateTimeDependentParams(pc);
157 process(recoData);
158}
159
160void TrackingStudySpec::updateTimeDependentParams(ProcessingContext& pc)
161{
163 if (static bool initOnceDone{false}; !initOnceDone) { // this params need to be queried only once
164 initOnceDone = true;
166 mVertexer.init();
168 }
169}
170
172{
173 mDBGOut.reset();
174}
175
177{
179 return;
180 }
181 if (matcher == ConcreteDataMatcher("IT3", "CLUSDICT", 0)) {
182 LOG(info) << "cluster dictionary updated";
183 mITSDict = (const o2::its3::TopologyDictionary*)obj;
184 return;
185 }
186}
187
188void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData)
189{
190 const auto& conf = ITS3TrackingStudyParam::Instance();
191 if (conf.doDCA) {
192 doDCAStudy(recoData);
193 }
194 if (conf.doDCARefit) {
195 doDCARefitStudy(recoData);
196 }
197 if (mUseMC && conf.doPull) {
198 doPullStudy(recoData);
199 }
200 if (mUseMC && conf.doMC) {
201 doMCStudy(recoData);
202 }
203}
204
205std::vector<o2::BaseCluster<float>> TrackingStudySpec::prepareITSClusters(const o2::globaltracking::RecoContainer& data) const
206{
207 std::vector<o2::BaseCluster<float>> itscl;
208 const auto& clusITS = data.getITSClusters();
209 if (clusITS.size()) {
210 const auto& patterns = data.getITSClustersPatterns();
211 itscl.reserve(clusITS.size());
212 auto pattIt = patterns.begin();
213 o2::its3::ioutils::convertCompactClusters(clusITS, pattIt, itscl, mITSDict);
214 }
215 return std::move(itscl);
216}
217
218bool TrackingStudySpec::selectTrack(GTrackID trkID, o2::globaltracking::RecoContainer& recoData, bool checkMCTruth) const
219{
220 const auto& conf = ITS3TrackingStudyParam::Instance();
221 if (!trkID.includesDet(GTrackID::ITS)) {
222 return false;
223 }
224 if (!recoData.isTrackSourceLoaded(trkID.getSource())) {
225 return false;
226 }
227 auto contributorsGID = recoData.getSingleDetectorRefs(trkID);
228 if (!contributorsGID[GTrackID::ITS].isIndexSet()) { // we need of course ITS
229 return false;
230 }
231 // ITS specific
232 const auto& itsTrk = recoData.getITSTrack(contributorsGID[GTrackID::ITS]);
233 if (itsTrk.getChi2() > conf.maxChi2 || itsTrk.getNClusters() < conf.minITSCls) {
234 return false;
235 }
236 // TPC specific
237 if (contributorsGID[GTrackID::TPC].isIndexSet()) {
238 const auto& tpcTrk = recoData.getTPCTrack(contributorsGID[GTrackID::TPC]);
239 if (tpcTrk.getNClusters() < conf.minTPCCls) {
240 return false;
241 }
242 }
243 // general
244 const auto& gTrk = recoData.getTrackParam(trkID);
245 if (gTrk.getPt() < conf.minPt || gTrk.getPt() > conf.maxPt) {
246 return false;
247 }
248 if (std::abs(gTrk.getEta()) > conf.maxEta) {
249 return false;
250 }
251 if (mUseMC && checkMCTruth) {
252 const auto& itsLbl = recoData.getTrackMCLabel(contributorsGID[GTrackID::ITS]);
253 if (!itsLbl.isValid()) {
254 return false;
255 }
256 if (contributorsGID[GTrackID::TPC].isIndexSet()) {
257 const auto& tpcLbl = recoData.getTrackMCLabel(contributorsGID[GTrackID::TPC]);
258 if (itsLbl != tpcLbl) {
259 return false;
260 }
261 }
262 if (contributorsGID[GTrackID::TRD].isIndexSet()) {
263 // TODO
264 }
265 if (contributorsGID[GTrackID::TOF].isIndexSet()) {
266 const auto& tofLbls = recoData.getTOFClustersMCLabels()->getLabels(contributorsGID[GTrackID::TOF]);
267 for (const auto& lbl : tofLbls) {
268 if (lbl.isValid()) {
269 return true;
270 }
271 }
272 }
273 }
274 return true;
275}
276
277T2VMap TrackingStudySpec::buildT2V(o2::globaltracking::RecoContainer& recoData, bool includeCont, bool requireMCMatch) const
278{
279 // build track->vertex assoc., maybe including contributor tracks
280 const auto& conf = ITS3TrackingStudyParam::Instance();
281 auto pvvec = recoData.getPrimaryVertices();
282 auto trackIndex = recoData.getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks
283 auto vtxRefs = recoData.getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs
284 auto nv = vtxRefs.size() - 1; // last entry is for unassigned tracks, ignore them
285 T2VMap t2v;
286 for (size_t iv = 0; iv < nv; ++iv) {
287 const auto& pv = pvvec[iv];
288 if (pv.getNContributors() - 1 < conf.minPVCont) {
289 continue;
290 }
291 if (requireMCMatch) {
292 auto pvl = recoData.getPrimaryVertexMCLabel(iv);
293 }
294 const auto& vtxRef = vtxRefs[iv];
295 int it = vtxRef.getFirstEntry(), itLim = it + vtxRef.getEntries();
296 for (; it < itLim; it++) {
297 const auto& tvid = trackIndex[it];
298 if (tvid.isAmbiguous()) {
299 continue;
300 }
301 if (!recoData.isTrackSourceLoaded(tvid.getSource())) {
302 continue;
303 }
304 if (mUseMC && requireMCMatch) {
305 const auto& pvlbl = recoData.getPrimaryVertexMCLabel(iv);
306 if (pvlbl.getEventID() != recoData.getTrackMCLabel(tvid).getEventID()) {
307 continue;
308 }
309 }
310 t2v[tvid] = iv;
311 if (includeCont) {
312 auto contributorsGID = recoData.getSingleDetectorRefs(tvid);
313 for (int cis = 0; cis < GTrackID::NSources; cis++) {
314 const auto cdm = GTrackID::getSourceDetectorsMask(cis);
315 if (!recoData.isTrackSourceLoaded(cis) || !cdm[DetID::ITS] || !contributorsGID[cis].isIndexSet()) {
316 continue;
317 }
318 if (mUseMC && requireMCMatch) {
319 const auto& pvlbl = recoData.getPrimaryVertexMCLabel(iv);
320 if (pvlbl.getEventID() != recoData.getTrackMCLabel(contributorsGID[cis]).getEventID()) {
321 continue;
322 }
323 }
324 t2v[contributorsGID[cis]] = iv;
325 }
326 }
327 }
328 }
329 return std::move(t2v);
330}
331
332bool TrackingStudySpec::refitITSPVTrack(o2::globaltracking::RecoContainer& recoData, o2::track::TrackParCov& trFit, GTrackID gidx)
333{
334 if (gidx.getSource() != GTrackID::ITS) {
335 return false;
336 }
337 static auto pvvec = recoData.getPrimaryVertices();
338 static auto t2v = buildT2V(recoData, true, true);
339 static const auto itsClusters = prepareITSClusters(recoData);
340 static std::vector<unsigned int> itsTracksROF;
341 if (static bool done{false}; !done) {
342 done = true;
343 const auto& itsTracksROFRec = recoData.getITSTracksROFRecords();
344 itsTracksROF.resize(recoData.getITSTracks().size());
345 for (unsigned irf = 0, cnt = 0; irf < itsTracksROFRec.size(); irf++) {
346 int ntr = itsTracksROFRec[irf].getNEntries();
347 for (int itr = 0; itr < ntr; itr++) {
348 itsTracksROF[cnt++] = irf;
349 }
350 }
351 }
352 auto prop = o2::base::Propagator::Instance();
353 const auto& conf = ITS3TrackingStudyParam::Instance();
354 std::array<o2::BaseCluster<float>, 8> clArr{};
355 std::array<float, 8> clAlpha{};
356 const auto trkIn = recoData.getTrackParam(gidx);
357 const auto trkOut = recoData.getTrackParamOut(gidx);
358 const auto& itsTrOrig = recoData.getITSTrack(gidx);
359 int ncl = itsTrOrig.getNumberOfClusters(), rof = itsTracksROF[gidx.getIndex()];
360 const auto& itsTrackClusRefs = recoData.getITSTracksClusterRefs();
361 int clEntry = itsTrOrig.getFirstClusterEntry();
362 const auto propagator = o2::base::Propagator::Instance();
363 // convert PV to a fake cluster in the track DCA frame
364 const auto& pv = pvvec[t2v[gidx]];
365 auto trkPV = trkIn;
366 if (!prop->propagateToDCA(pv, trkPV, prop->getNominalBz(), 2.0, conf.CorrType)) {
367 mTrackCounter -= gidx.getSource();
368 return false;
369 }
370 // create base cluster from the PV, with the alpha corresponding to the track at DCA
371 float cosAlp = NAN, sinAlp = NAN;
372 o2::math_utils::sincos(trkPV.getAlpha(), sinAlp, cosAlp);
373 // vertex position rotated to track frame
374 clArr[0].setXYZ(pv.getX() * cosAlp + pv.getY() * sinAlp, -pv.getX() * sinAlp + pv.getY() * cosAlp, pv.getZ());
375 clArr[0].setSigmaY2(0.5 * (pv.getSigmaX2() + pv.getSigmaY2()));
376 clArr[0].setSigmaZ2(pv.getSigmaZ2());
377 clAlpha[0] = trkPV.getAlpha();
378 for (int icl = 0; icl < ncl; ++icl) { // ITS clusters are referred in layer decreasing order
379 clArr[ncl - icl] = itsClusters[itsTrackClusRefs[clEntry + icl]];
380 clAlpha[ncl - icl] = o2::its::GeometryTGeo::Instance()->getSensorRefAlpha(clArr[ncl - icl].getSensorID());
381 }
382 // start refit
383 trFit = trkOut;
384 trFit.resetCovariance(1'000);
385 float chi2{0};
386 for (int icl = ncl; icl >= 0; --icl) { // go backwards
387 if (!trFit.rotate(clAlpha[icl]) || !prop->propagateToX(trFit, clArr[icl].getX(), prop->getNominalBz(), 0.85, 2.0, conf.CorrType)) {
388 mTrackCounter -= gidx.getSource();
389 return false;
390 }
391 chi2 += trFit.getPredictedChi2(clArr[icl]);
392 if (!trFit.update(clArr[icl])) {
393 mTrackCounter -= gidx.getSource();
394 return false;
395 }
396 }
397 // chi2 < conf.maxChi2; should I cut here?
398 return true;
399};
400
401void TrackingStudySpec::doDCAStudy(o2::globaltracking::RecoContainer& recoData)
402{
404 LOGP(info, "Doing DCA study");
405 mTrackCounter.reset();
406 const auto& conf = ITS3TrackingStudyParam::Instance();
407 auto prop = o2::base::Propagator::Instance();
408 TStopwatch sw;
409 sw.Start();
410 int nDCAFits{0}, nDCAFitsFail{0};
411 auto pvvec = recoData.getPrimaryVertices();
412 auto trackIndex = recoData.getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks
413 auto vtxRefs = recoData.getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs
414 auto nv = vtxRefs.size() - 1; // last entry is for unassigned tracks, ignore them
415 auto& stream = (*mDBGOut) << "dca";
416 for (int iv = 0; iv < nv; iv++) {
417 const auto& pv = pvvec[iv];
418 const auto& vtref = vtxRefs[iv];
419 for (int is = 0; is < GTrackID::NSources; is++) {
420 const auto dm = GTrackID::getSourceDetectorsMask(is);
421 if (!recoData.isTrackSourceLoaded(is) || !dm[DetID::ITS]) {
422 mTrackCounter &= is;
423 continue;
424 }
425 int idMin = vtref.getFirstEntryOfSource(is), idMax = idMin + vtref.getEntriesOfSource(is);
426 for (int i = idMin; i < idMax; i++) {
427 const auto vid = trackIndex[i];
428 if (!vid.isPVContributor()) {
429 mTrackCounter &= vid.getSource();
430 continue;
431 }
432
433 // we fit each different sub-track type, that include ITS, e.g.
434 // ITS,ITS-TPC,ITS-TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD-TOF
435 auto contributorsGID = recoData.getSingleDetectorRefs(vid);
436 for (int cis = 0; cis < GTrackID::NSources && cis <= is; cis++) {
437 const auto cdm = GTrackID::getSourceDetectorsMask(cis);
438 if (!recoData.isTrackSourceLoaded(cis) || !cdm[DetID::ITS] || !contributorsGID[cis].isIndexSet()) {
439 mTrackCounter &= cis;
440 continue;
441 }
442 if (!selectTrack(contributorsGID[cis], recoData)) {
443 mTrackCounter &= vid.getSource();
444 continue;
445 }
446
447 o2::dataformats::DCA dcaInfo;
448 const auto& trk = recoData.getTrackParam(contributorsGID[cis]);
449 auto trkRefit = trk;
450 // for ITS standalone tracks instead of having the trk at the pv we refit with the pv
451 if (conf.refitITS && cis == GTrackID::ITS && !refitITSPVTrack(recoData, trkRefit, contributorsGID[cis])) {
452 mTrackCounter -= cis;
453 continue;
454 } else {
455 trkRefit.invalidate();
456 };
457
458 auto trkDCA = trk;
459 if (!prop->propagateToDCABxByBz(pv, trkDCA, 2.f, conf.CorrType, &dcaInfo)) {
460 mTrackCounter -= cis;
461 ++nDCAFitsFail;
462 continue;
463 }
464
465 stream << "src=" << cis
466 << "pv=" << pv
467 << "trk=" << trk
468 << "trkRefit=" << trkRefit
469 << "trkAtPV=" << trkDCA
470 << "dca=" << dcaInfo;
471
472 if (mUseMC) {
473 const auto& lbl = recoData.getTrackMCLabel(contributorsGID[cis]);
474 lbl.print();
475 o2::dataformats::DCA dcaInfoMC;
476 const auto& eve = mcReader.getMCEventHeader(lbl.getSourceID(), lbl.getEventID());
478 mcEve.setPos({(float)eve.GetX(), (float)eve.GetY(), (float)eve.GetZ()});
479 auto trkC = trk;
480 if (!prop->propagateToDCABxByBz(mcEve, trkC, 2.f, conf.CorrType, &dcaInfoMC)) {
481 mTrackCounter -= cis;
482 ++nDCAFitsFail;
483 continue;
484 }
485 const auto& mcTrk = mcReader.getTrack(lbl);
486 if (mcTrk == nullptr) {
487 LOGP(fatal, "mcTrk is null did selection fail?");
488 }
489 stream << "mcTrk=" << *mcTrk
490 << "dca2MC=" << dcaInfoMC
491 << "lbl=" << lbl;
492 }
493 stream << "\n";
494
495 ++nDCAFits;
496 mTrackCounter += cis;
497 }
498 }
499 }
500 }
501 sw.Stop();
502 LOGP(info, "doDCAStudy: accepted {} fits, failed {} (in {:.2f} seconds)", nDCAFits, nDCAFitsFail, sw.RealTime());
503 mTrackCounter.print();
504}
505
506void TrackingStudySpec::doDCARefitStudy(o2::globaltracking::RecoContainer& recoData)
507{
509 LOGP(info, "Doing DCARefit study");
510 mTrackCounter.reset();
511 const auto& conf = ITS3TrackingStudyParam::Instance();
512 auto prop = o2::base::Propagator::Instance();
513 TStopwatch sw;
514 sw.Start();
515
516 // build track->vertex assoc.
517 auto pvvec = recoData.getPrimaryVertices();
518 auto vtxRefs = recoData.getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs
519 auto nv = vtxRefs.size() - 1; // last entry is for unassigned tracks, ignore them
520 auto t2v = buildT2V(recoData);
521 std::vector<std::vector<GTrackID>> v2t;
522 v2t.resize(nv);
523 auto creator = [&](const auto& trk, GTrackID trkID, float _t0, float terr) -> bool {
524 if constexpr (!isBarrelTrack<decltype(trk)>()) {
525 mTrackCounter &= trkID.getSource();
526 return false;
527 }
528 if (!trkID.includesDet(GTrackID::ITS)) {
529 mTrackCounter &= trkID.getSource();
530 return false;
531 }
532 // general
533 if constexpr (isBarrelTrack<decltype(trk)>()) {
534 if (trk.getPt() < conf.minPt || trk.getPt() > conf.maxPt) {
535 mTrackCounter &= trkID.getSource();
536 return false;
537 }
538 if (std::abs(trk.getEta()) > conf.maxEta) {
539 mTrackCounter &= trkID.getSource();
540 return false;
541 }
542 if (!t2v.contains(trkID)) {
543 mTrackCounter &= trkID.getSource();
544 return false;
545 }
546 if (!selectTrack(trkID, recoData, mUseMC)) {
547 mTrackCounter &= trkID.getSource();
548 return false;
549 }
550 }
551 v2t[t2v[trkID]].push_back(trkID);
552 return true;
553 };
554 recoData.createTracksVariadic(creator);
555
556 int nDCAFits{0}, nDCAFitsFail{0};
557 auto& stream = (*mDBGOut) << "dcaRefit";
558 for (size_t iv = 0; iv < nv; ++iv) {
559 const auto& pv = pvvec[iv];
560 const auto& trkIDs = v2t[iv];
561 if (trkIDs.size() - 1 < conf.minPVCont) {
562 continue;
563 }
564 std::vector<o2::track::TrackParCov> trks;
565 trks.reserve(trkIDs.size());
566 for (const auto& trkID : trkIDs) {
567 trks.push_back(recoData.getTrackParam(trkID));
568 }
569
570 if (!mVertexer.prepareVertexRefit(trks, pv)) {
571 continue;
572 }
573 std::vector<bool> trkMask(trkIDs.size(), true);
574 for (size_t it{0}; it < trkMask.size(); ++it) {
575 trkMask[it] = false; // mask current track from pv refit
576 if (it != 0) {
577 trkMask[it - 1] = true; // unmask previoustrack from pv refit
578 }
579 auto pvRefit = mVertexer.refitVertex(trkMask, pv);
580 if (pvRefit.getChi2() < 0) {
581 trkMask[it] = true;
582 continue;
583 }
584
585 // check DCA both for refitted and original PV
586 o2::dataformats::DCA dcaInfo;
587 auto trkC = trks[it];
588 if (!prop->propagateToDCABxByBz(pv, trkC, 2.f, conf.CorrType, &dcaInfo)) {
589 mTrackCounter -= trkIDs[it].getSource();
590 ++nDCAFitsFail;
591 continue;
592 }
593 o2::dataformats::DCA dcaInfoRefit;
594 auto trkCRefit = trks[it];
595 if (!prop->propagateToDCABxByBz(pv, trkCRefit, 2.f, conf.CorrType, &dcaInfoRefit)) {
596 mTrackCounter -= trkIDs[it].getSource();
597 ++nDCAFitsFail;
598 continue;
599 }
600
601 stream << "src=" << trkIDs[it].getSource()
602 << "pv=" << pv
603 << "trkAtPV=" << trkC
604 << "dca=" << dcaInfo
605 << "pvRefit=" << pvRefit
606 << "trkAtPVRefit=" << trkC
607 << "dcaRefit=" << dcaInfoRefit;
608 if (mUseMC) {
609 const auto& mcTrk = mcReader.getTrack(recoData.getTrackMCLabel(trkIDs[it]));
610 if (mcTrk == nullptr) {
611 LOGP(fatal, "mcTrk is null did selection fail?");
612 }
613 stream << "mcTrk=" << *mcTrk;
614 }
615 stream << "\n";
616 ++nDCAFits;
617 mTrackCounter += trkIDs[it].getSource();
618 }
619 }
620 sw.Stop();
621 LOGP(info, "doDCARefitStudy: accepted {} fits, failed {} (in {:.2f} seconds)", nDCAFits, nDCAFitsFail, sw.RealTime());
622 mTrackCounter.print();
623}
624
625void TrackingStudySpec::doPullStudy(o2::globaltracking::RecoContainer& recoData)
626{
627 // check track pulls compared to mc generation
628 LOGP(info, "Doing Pull study");
629 mTrackCounter.reset();
630 TStopwatch sw;
631 sw.Start();
632 int nPulls{0}, nPullsFail{0};
633 auto prop = o2::base::Propagator::Instance();
634 const auto& conf = ITS3TrackingStudyParam::Instance();
635
636 auto checkInTrack = [&](GTrackID trkID) {
637 if (!selectTrack(trkID, recoData)) {
638 mTrackCounter &= trkID.getSource();
639 return;
640 }
641 const auto mcTrk = mcReader.getTrack(recoData.getTrackMCLabel(trkID));
642 if (!mcTrk) {
643 return;
644 }
645 auto trk = recoData.getTrackParam(trkID);
646
647 // for ITS standalone tracks we add the PV as an additional measurement point
648 if (conf.refitITS && trkID.getSource() == GTrackID::ITS && !refitITSPVTrack(recoData, trk, trkID)) {
649 mTrackCounter -= trkID.getSource();
650 ++nPullsFail;
651 return;
652 }
653
654 std::array<float, 3> xyz{(float)mcTrk->GetStartVertexCoordinatesX(), (float)mcTrk->GetStartVertexCoordinatesY(), (float)mcTrk->GetStartVertexCoordinatesZ()},
655 pxyz{(float)mcTrk->GetStartVertexMomentumX(), (float)mcTrk->GetStartVertexMomentumY(), (float)mcTrk->GetStartVertexMomentumZ()};
656 TParticlePDG* pPDG = TDatabasePDG::Instance()->GetParticle(mcTrk->GetPdgCode());
657 if (!pPDG) {
658 mTrackCounter -= trkID.getSource();
659 ++nPullsFail;
660 return;
661 }
662 o2::track::TrackPar mcTrkO2(xyz, pxyz, TMath::Nint(pPDG->Charge() / 3), false);
663 // propagate it to the alpha/X of the reconstructed track
664 if (!mcTrkO2.rotate(trk.getAlpha()) || !prop->PropagateToXBxByBz(mcTrkO2, trk.getX())) {
665 mTrackCounter -= trkID.getSource();
666 ++nPullsFail;
667 return;
668 }
669 const auto contTrk = recoData.getSingleDetectorRefs(trkID);
670 const auto& itsTrk = recoData.getITSTrack(contTrk[GTrackID::ITS]);
671
672 (*mDBGOut)
673 << "pull"
674 << "src=" << trkID.getSource()
675 << "itsTrk=" << itsTrk
676 << "mcTrk=" << mcTrkO2
677 << "mcPart=" << mcTrk
678 << "trk=" << trk
679 << "\n";
680 ++nPulls;
681 mTrackCounter += trkID.getSource();
682 };
683
684 for (size_t iTrk{0}; iTrk < recoData.getITSTracks().size(); ++iTrk) {
685 checkInTrack(GTrackID(iTrk, GTrackID::ITS));
686 }
687 for (size_t iTrk{0}; iTrk < recoData.getTPCITSTracks().size(); ++iTrk) {
688 checkInTrack(GTrackID(iTrk, GTrackID::ITSTPC));
689 }
690 for (size_t iTrk{0}; iTrk < recoData.getITSTPCTRDTracksMCLabels().size(); ++iTrk) {
691 checkInTrack(GTrackID(iTrk, GTrackID::ITSTPCTRD));
692 }
693 for (size_t iTrk{0}; iTrk < recoData.getITSTPCTOFMatches().size(); ++iTrk) {
694 checkInTrack(GTrackID(iTrk, GTrackID::ITSTPCTOF));
695 }
696 for (size_t iTrk{0}; iTrk < recoData.getITSTPCTRDTOFMatches().size(); ++iTrk) {
697 checkInTrack(GTrackID(iTrk, GTrackID::ITSTPCTRDTOF));
698 }
699 sw.Stop();
700 LOGP(info, "doPullStudy: accepted {} pulls; rejected {} (in {:.2f} seconds)", nPulls, nPullsFail, sw.RealTime());
701 mTrackCounter.print();
702}
703
704void TrackingStudySpec::doMCStudy(o2::globaltracking::RecoContainer& recoData)
705{
706 LOGP(info, "Doing MC study");
707 mTrackCounter.reset();
708 TStopwatch sw;
709 sw.Start();
710 int nTracks{0};
711
712 const int iSrc{0};
713 const int nev = mcReader.getNEvents(iSrc);
714 std::unordered_map<o2::MCCompLabel, ParticleInfoExt> info;
715
716 LOGP(info, "** Filling particle table ... ");
717 for (int iEve{0}; iEve < nev; ++iEve) {
718 const auto& mcTrks = mcReader.getTracks(iSrc, iEve);
719 for (int iTrk{0}; iTrk < mcTrks.size(); ++iTrk) {
720 const auto& mcTrk = mcTrks[iTrk];
721 const auto pdg = mcTrk.GetPdgCode();
722 if (o2::O2DatabasePDG::Instance()->GetParticle(pdg) == nullptr) {
723 continue;
724 }
725 const auto apdg = std::abs(pdg);
726 if (apdg != 11 && apdg != 211 && apdg != 321 && apdg != 2212) {
727 continue;
728 }
729 o2::MCCompLabel lbl(iTrk, iEve, iSrc);
730 auto& part = info[lbl];
731 part.mcTrack = mcTrk;
732 }
733 }
734 LOGP(info, "** Creating particle/clusters correspondence ... ");
735 const auto& clusters = recoData.getITSClusters();
736 const auto& clustersMCLCont = recoData.getITSClustersMCLabels();
737 for (auto iCluster{0}; iCluster < clusters.size(); ++iCluster) {
738 auto labs = clustersMCLCont->getLabels(iCluster);
739 for (auto& lab : labs) {
740 if (!lab.isValid() || lab.getSourceID() != 0 || !lab.isCorrect()) {
741 continue;
742 }
743 int trackID = 0, evID = 0, srcID = 0;
744 bool fake = false;
745 lab.get(trackID, evID, srcID, fake);
746 auto& cluster = clusters[iCluster];
747 auto layer = o2::its::GeometryTGeo::Instance()->getLayer(cluster.getSensorID());
748 auto& part = info[{trackID, evID, srcID}];
749 part.clusters |= (1 << layer);
750 if (fake) {
751 part.fakeClusters |= (1 << layer);
752 }
753 }
754 }
755 LOGP(info, "** Analysing tracks ... ");
756 auto accountLbl = [&](const globaltracking::RecoContainer::GlobalIDSet& contributorsGID, DetID::ID det) {
757 if (contributorsGID[det].isIndexSet()) {
758 const auto& lbl = recoData.getTrackMCLabel(contributorsGID[det]);
759 if (lbl.isValid()) {
760 o2::MCCompLabel iLbl(lbl.getTrackID(), lbl.getEventID(), lbl.getSourceID());
761 if (info.contains(iLbl)) {
762 auto& part = info[iLbl];
763 SETBIT(part.recoTracks, det);
764 if (lbl.isFake()) {
765 SETBIT(part.fakeTracks, det);
766 }
767 }
768 }
769 }
770 };
771 auto creator = [&](const auto& trk, GTrackID trkID, float _t0, float terr) -> bool {
772 if constexpr (!isBarrelTrack<decltype(trk)>()) {
773 return false;
774 }
775 if (!trkID.includesDet(GTrackID::ITS)) {
776 return false;
777 }
778 // general
779 auto contributorsGID = recoData.getSingleDetectorRefs(trkID);
780 if (!contributorsGID[GTrackID::ITS].isIndexSet()) { // we need of course ITS
781 return false;
782 }
783 const auto& gLbl = recoData.getTrackMCLabel(trkID);
784 if (!gLbl.isValid()) {
785 return false;
786 }
787 o2::MCCompLabel iLbl(gLbl.getTrackID(), gLbl.getEventID(), gLbl.getSourceID());
788 if (!info.contains(iLbl)) {
789 return false;
790 }
791 auto& part = info[iLbl];
792 part.recoTrack = recoData.getTrackParam(trkID);
793
794 accountLbl(contributorsGID, DetID::ITS);
795 accountLbl(contributorsGID, DetID::TPC);
796 accountLbl(contributorsGID, DetID::TRD);
797 accountLbl(contributorsGID, DetID::TOF);
798
799 ++nTracks;
800 return true;
801 };
802 recoData.createTracksVariadic(creator);
803
804 LOGP(info, "Streaming output to tree");
805 for (const auto& [_, part] : info) {
806 (*mDBGOut) << "mc"
807 << "part=" << part
808 << "\n";
809 }
810
811 sw.Stop();
812 LOGP(info, "doMCStudy: accounted {} MCParticles and {} tracks (in {:.2f} seconds)", info.size(), nTracks, sw.RealTime());
813}
814
816{
817 std::vector<OutputSpec> outputs;
818 auto dataRequest = std::make_shared<DataRequest>();
819
820 dataRequest->requestTracks(srcTracks, useMC);
821 dataRequest->requestIT3Clusters(useMC);
822 dataRequest->requestClusters(srcClusters, useMC);
823 dataRequest->requestPrimaryVertices(useMC);
824 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(false, // orbitResetTime
825 true, // GRPECS=true
826 true, // GRPLHCIF
827 true, // GRPMagField
828 true, // askMatLUT
830 dataRequest->inputs,
831 true);
832
833 return DataProcessorSpec{
834 .name = "its3-track-study",
835 .inputs = dataRequest->inputs,
836 .outputs = outputs,
837 .algorithm = AlgorithmSpec{adaptFromTask<TrackingStudySpec>(dataRequest, ggRequest, srcTracks, useMC)},
838 .options = {}};
839}
840
841} // namespace o2::its3::study
Wrapper container for different reconstructed object types.
Definition of the ITSMFT digit.
Definition of the GeometryManager class.
Definition of the ITSMFT Hit class.
Definition of the BuildTopologyDictionary class for ITS3.
void print() const
int32_t i
bool done
Helper for geometry and GRP related CCDB requests.
Global index for barrel track: provides provenance (detectors combination), index in respective array...
Definition of the GeometryTGeo class.
Utility functions for MC particles.
Primary vertex finder.
Wrapper container for different reconstructed object types.
o2::track::TrackParCov TrackParCov
Definition Recon.h:39
Referenc on track indices contributing to the vertex, with possibility chose tracks from specific sou...
void print() const
int getEventID() const
static TDatabasePDG * Instance()
void checkUpdates(o2::framework::ProcessingContext &pc)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
static std::string getCollisionContextFileName(const std::string_view prefix="")
Definition NameConf.cxx:52
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:175
Static class with identifiers, bitmasks and names for ALICE detectors.
Definition DetID.h:58
static constexpr ID ITS
Definition DetID.h:63
static constexpr ID TRD
Definition DetID.h:65
static constexpr ID TPC
Definition DetID.h:64
static constexpr ID TOF
Definition DetID.h:66
ServiceRegistryRef services()
Definition InitContext.h:34
void finaliseCCDB(ConcreteDataMatcher &matcher, void *obj) final
void run(ProcessingContext &pc) final
void endOfStream(EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
void init(InitContext &ic) final
TrackingStudySpec(std::shared_ptr< DataRequest > dr, std::shared_ptr< o2::base::GRPGeomRequest > gr, GTrackID::mask_t src, bool useMC)
int getLayer(int index) const
Get chip layer, from 0.
float getSensorRefAlpha(int isn) const
static GeometryTGeo * Instance()
void fillMatrixCache(int mask) override
bool initFromDigitContext(std::string_view filename)
MCTrack const * getTrack(o2::MCCompLabel const &) const
size_t getNEvents(int source) const
Get number of events.
o2::dataformats::MCEventHeader const & getMCEventHeader(int source, int event) const
retrieves the MCEventHeader for a given eventID and sourceID
std::vector< MCTrack > const & getTracks(int source, int event) const
variant returning all tracks for source and event at once
bool prepareVertexRefit(const TR &tracks, const o2d::VertexBase &vtxSeed)
Definition PVertexer.h:359
PVertex refitVertex(const std::vector< bool > useTrack, const o2d::VertexBase &vtxSeed)
GLenum src
Definition glcorearb.h:1767
GLsizeiptr size
Definition glcorearb.h:659
GLboolean * data
Definition glcorearb.h:298
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
GLuint GLuint stream
Definition glcorearb.h:1806
Defining PrimaryVertex explicitly as messageable.
void convertCompactClusters(gsl::span< const itsmft::CompClusterExt > clusters, gsl::span< const unsigned char >::iterator &pattIt, std::vector< o2::BaseCluster< float > > &output, const its3::TopologyDictionary *dict)
convert compact clusters to 3D spacepoints
Definition IOUtils.cxx:30
std::unordered_map< GTrackID, size_t > T2VMap
o2::framework::DataProcessorSpec getTrackingStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC)
o2::dataformats::GlobalTrackID GTrackID
TrackParCovF TrackParCov
Definition Track.h:33
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Defining DataPointCompositeObject explicitly as copiable.
GlobalIDSet getSingleDetectorRefs(GTrackID gidx) const
const o2::tpc::TrackTPC & getTPCTrack(GTrackID id) const
void createTracksVariadic(T creator, GTrackID::mask_t srcSel=GTrackID::getSourcesMask("all")) const
o2::MCCompLabel getTrackMCLabel(GTrackID id) const
const o2::track::TrackParCov & getTrackParam(GTrackID gidx) const
const o2::MCEventLabel & getPrimaryVertexMCLabel(int i) const
void collectData(o2::framework::ProcessingContext &pc, const DataRequest &request)
const o2::track::TrackParCov & getTrackParamOut(GTrackID gidx) const
const o2::its::TrackITS & getITSTrack(GTrackID gid) const
std::array< GTrackID, GTrackID::NSources > GlobalIDSet
static constexpr int L2G
Definition Cartesian.h:54
static constexpr int T2L
Definition Cartesian.h:55
static constexpr int T2G
Definition Cartesian.h:56
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
TStopwatch sw
std::vector< Cluster > clusters