Project
Loading...
Searching...
No Matches
TrackMCStudy.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>
21#include "ITStracking/IOUtils.h"
55#include "GPUO2InterfaceRefit.h"
56#include "GPUParam.h"
57#include "GPUParam.inc"
58#include "MathUtils/fit.h"
59#include "TPCFastTransformPOD.h"
60#include <TRandom.h>
61#include <map>
62#include <unordered_map>
63#include <array>
64#include <utility>
65#include <gsl/span>
66
67// workflow to study relation of reco tracks to MCTruth
68// o2-trackmc-study-workflow --device-verbosity 3 -b --run
69
70namespace o2::trackstudy
71{
72
73using namespace o2::framework;
76
80using VTIndexV = std::pair<int, o2::dataformats::VtxTrackIndex>;
83
85
86class TrackMCStudy final : public Task
87{
88 public:
89 TrackMCStudy(std::shared_ptr<DataRequest> dr, std::shared_ptr<o2::base::GRPGeomRequest> gr, GTrackID::mask_t src, bool checkSV)
90 : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mCheckSV(checkSV) {}
91 ~TrackMCStudy() final = default;
92 void init(InitContext& ic) final;
93 void run(ProcessingContext& pc) final;
94 void endOfStream(EndOfStreamContext& ec) final;
95 void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final;
96 void process(const o2::globaltracking::RecoContainer& recoData);
97
98 private:
99 void processTPCTrackRefs();
100 void processITSTracks(const o2::globaltracking::RecoContainer& recoData);
101 void loadTPCOccMap(const o2::globaltracking::RecoContainer& recoData);
102 void fillMCClusterInfo(const o2::globaltracking::RecoContainer& recoData);
103 void prepareITSData(const o2::globaltracking::RecoContainer& recoData);
104 bool processMCParticle(int src, int ev, int trid);
105 bool addMCParticle(const MCTrack& mctr, const o2::MCCompLabel& lb, TParticlePDG* pPDG = nullptr);
106 bool acceptMCCharged(const MCTrack& tr, const o2::MCCompLabel& lb, int followDec = -1);
107 bool propagateToRefX(o2::track::TrackParCov& trcTPC, o2::track::TrackParCov& trcITS);
108 bool refitV0(int i, o2::dataformats::V0& v0, const o2::globaltracking::RecoContainer& recoData);
109 void updateTimeDependentParams(ProcessingContext& pc);
110 float getDCAYCut(float pt) const;
111
112 const std::vector<o2::MCTrack>* mCurrMCTracks = nullptr;
113 TVector3 mCurrMCVertex;
114 o2::tpc::VDriftHelper mTPCVDriftHelper{};
115 const o2::gpu::TPCFastTransformPOD* mTPCCorrMaps{nullptr};
116 std::shared_ptr<DataRequest> mDataRequest;
117 std::shared_ptr<o2::base::GRPGeomRequest> mGGCCDBRequest;
118 std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOut;
119 std::vector<float> mTBinClOcc;
120 std::vector<float> mTBinClOccHist; //< original occupancy
121 std::vector<long> mIntBC;
122 std::vector<float> mTPCOcc;
123 std::vector<int> mITSOcc; //< N ITS clusters in the ROF containing collision
124 std::vector<o2::BaseCluster<float>> mITSClustersArray;
125 const o2::itsmft::TopologyDictionary* mITSDict = nullptr;
126
127 bool mCheckSV = false; //< check SV binding (apart from prongs availability)
128 bool mRecProcStage = false; //< flag that the MC particle was added only at the stage of reco tracks processing
129 int mNTPCOccBinLength = 0;
130 float mNTPCOccBinLengthInv = -1.f;
131 int mVerbose = 0;
132 float mITSTimeBiasMUS = 0.f;
133 float mITSROFrameLengthMUS = 0.f;
134 float mTPCTBinMUS = 0.;
135
136 int mNCheckDecays = 0;
137
138 GTrackID::mask_t mTracksSrc{};
139 o2::steer::MCKinematicsReader mcReader; // reader of MC information
140 std::vector<int> mITSROF;
141 std::vector<TBracket> mITSROFBracket;
142 std::vector<o2::MCCompLabel> mDecProdLblPool; // labels of decay products to watch, added to MC map
143 std::vector<MCVertex> mMCVtVec{};
144
145 struct DecayRef {
146 o2::MCCompLabel mother{};
147 o2::track::TrackPar parent{};
148 int pdg = 0;
149 int daughterFirst = -1;
150 int daughterLast = -1;
151 int foundSVID = -1;
152 };
153 std::vector<std::vector<DecayRef>> mDecaysMaps; // for every parent particle to watch, store its label and entries of 1st/last decay product labels in mDecProdLblPool
154 std::unordered_map<o2::MCCompLabel, TrackFamily> mSelMCTracks;
155 std::unordered_map<o2::MCCompLabel, std::pair<int, int>> mSelTRefIdx;
156 std::vector<o2::track::TrackPar> mSelTRefs;
158 static constexpr float MaxSnp = 0.9; // max snp of ITS or TPC track at xRef to be matched
159};
160
162{
164 mcReader.initFromDigitContext("collisioncontext.root");
165
166 mDBGOut = std::make_unique<o2::utils::TreeStreamRedirector>("trackMCStudy.root", "recreate");
167 mVerbose = ic.options().get<int>("device-verbosity");
168
170 for (int id = 0; id < sizeof(params.decayPDG) / sizeof(int); id++) {
171 if (params.decayPDG[id] < 0) {
172 break;
173 }
174 mNCheckDecays++;
175 }
176 mDecaysMaps.resize(mNCheckDecays);
177}
178
180{
182 for (int i = 0; i < mNCheckDecays; i++) {
183 mDecaysMaps[i].clear();
184 }
185 mDecProdLblPool.clear();
186 mMCVtVec.clear();
187 mCurrMCTracks = nullptr;
188
189 recoData.collectData(pc, *mDataRequest.get()); // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer
190 updateTimeDependentParams(pc); // Make sure this is called after recoData.collectData, which may load some conditions
191 mRecProcStage = false;
192 process(recoData);
193}
194
195void TrackMCStudy::updateTimeDependentParams(ProcessingContext& pc)
196{
198 mTPCVDriftHelper.extractCCDBInputs(pc);
199 auto const& raw = pc.inputs().get<const char*>("corrMap");
200 mTPCCorrMaps = &o2::gpu::TPCFastTransformPOD::get(raw);
201 static bool initOnceDone = false;
202 if (!initOnceDone) { // this params need to be queried only once
203 initOnceDone = true;
205 mITSROFrameLengthMUS = o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS) ? alpParamsITS.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingMUS : alpParamsITS.roFrameLengthTrig * 1.e-3;
206 LOGP(info, "VertexTrackMatcher ITSROFrameLengthMUS:{}", mITSROFrameLengthMUS);
207
209 mTPCTBinMUS = elParam.ZbinWidth;
211 if (mCheckSV) {
212 const auto& svparam = o2::vertexing::SVertexerParams::Instance();
213 mFitterV0.setBz(o2::base::Propagator::Instance()->getNominalBz());
214 mFitterV0.setOldMode(svparam.oldDCAFitterMode);
215 mFitterV0.setUseAbsDCA(svparam.useAbsDCA);
216 mFitterV0.setPropagateToPCA(false);
217 mFitterV0.setMaxR(svparam.maxRIni);
218 mFitterV0.setMinParamChange(svparam.minParamChange);
219 mFitterV0.setMinRelChi2Change(svparam.minRelChi2Change);
220 mFitterV0.setMaxDZIni(svparam.maxDZIni);
221 mFitterV0.setMaxDXYIni(svparam.maxDXYIni);
222 mFitterV0.setMaxChi2(svparam.maxChi2);
223 mFitterV0.setMatCorrType(o2::base::Propagator::MatCorrType(svparam.matCorr));
224 mFitterV0.setUsePropagator(svparam.usePropagator);
225 mFitterV0.setRefitWithMatCorr(svparam.refitWithMatCorr);
226 mFitterV0.setMaxStep(svparam.maxStep);
227 mFitterV0.setMaxSnp(svparam.maxSnp);
228 mFitterV0.setMinXSeed(svparam.minXSeed);
229 }
230 }
231}
232
234{
235 constexpr float SQRT12Inv = 0.288675f;
237 auto pvvec = recoData.getPrimaryVertices();
238 auto pvvecLbl = recoData.getPrimaryVertexMCLabels();
239 auto trackIndex = recoData.getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks
240 auto vtxRefs = recoData.getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs
241 auto prop = o2::base::Propagator::Instance();
242 int nv = vtxRefs.size();
243 float vdriftTB = mTPCVDriftHelper.getVDriftObject().getVDrift() * o2::tpc::ParameterElectronics::Instance().ZbinWidth; // VDrift expressed in cm/TimeBin
244 float itsBias = 0.5 * mITSROFrameLengthMUS + o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance().roFrameBiasInBC * o2::constants::lhc::LHCBunchSpacingMUS; // ITS time is supplied in \mus as beginning of ROF
245
246 prepareITSData(recoData);
247 loadTPCOccMap(recoData);
248 auto getITSPatt = [&](GTrackID gid, uint8_t& ncl) {
249 int8_t patt = 0;
250 if (gid.getSource() == VTIndex::ITSAB) {
251 const auto& itsTrf = recoData.getITSABRefs()[gid];
252 ncl = itsTrf.getNClusters();
253 for (int il = 0; il < 7; il++) {
254 if (itsTrf.hasHitOnLayer(il)) {
255 patt |= 0x1 << il;
256 }
257 }
258 patt |= 0x1 << 7;
259 } else {
260 const auto& itsTr = recoData.getITSTrack(gid);
261 for (int il = 0; il < 7; il++) {
262 if (itsTr.hasHitOnLayer(il)) {
263 patt |= 0x1 << il;
264 ncl++;
265 }
266 }
267 }
268 return patt;
269 };
270
271 auto fillTPCClusterInfo = [&recoData](const o2::tpc::TrackTPC& trc, RecTrack& tref) {
272 if (recoData.inputsTPCclusters) {
273 uint8_t clSect = 0, clRow = 0, lowestR = -1;
274 uint32_t clIdx = 0;
275 const auto clRefs = recoData.getTPCTracksClusterRefs();
276 const auto tpcClusAcc = recoData.getTPCClusters();
277 const auto shMap = recoData.clusterShMapTPC;
278 for (int ic = 0; ic < trc.getNClusterReferences(); ic++) { // outside -> inside ordering, but on the sector boundaries backward jumps are possible
279 trc.getClusterReference(clRefs, ic, clSect, clRow, clIdx);
280 if (clRow < lowestR) {
281 tref.rowCountTPC++;
282 lowestR = clRow;
283 }
284 unsigned int absoluteIndex = tpcClusAcc.clusterOffset[clSect][clRow] + clIdx;
285 if (shMap[absoluteIndex] & o2::gpu::GPUTPCGMMergedTrackHit::flagShared) {
286 tref.nClTPCShared++;
287 }
288 }
289 tref.lowestPadRow = lowestR;
290 const auto& clus = tpcClusAcc.clusters[clSect][clRow][clIdx];
291 int padFromEdge = int(clus.getPad()), npads = o2::gpu::GPUTPCGeometry::NPads(clRow);
292 if (padFromEdge > npads / 2) {
293 padFromEdge = npads - 1 - padFromEdge;
294 }
295 tref.padFromEdge = uint8_t(padFromEdge);
296 trc.getClusterReference(clRefs, 0, clSect, clRow, clIdx);
297 tref.rowMaxTPC = clRow;
298 }
299 };
300
301 auto flagTPCClusters = [&recoData](const o2::tpc::TrackTPC& trc, o2::MCCompLabel lbTrc) {
302 if (recoData.inputsTPCclusters) {
303 const auto clRefs = recoData.getTPCTracksClusterRefs();
304 const auto* TPCClMClab = recoData.inputsTPCclusters->clusterIndex.clustersMCTruth;
305 const auto& TPCClusterIdxStruct = recoData.inputsTPCclusters->clusterIndex;
306 for (int ic = 0; ic < trc.getNClusterReferences(); ic++) {
307 uint8_t clSect = 0, clRow = 0;
308 uint32_t clIdx = 0;
309 trc.getClusterReference(clRefs, ic, clSect, clRow, clIdx);
310 auto labels = TPCClMClab->getLabels(clIdx + TPCClusterIdxStruct.clusterOffset[clSect][clRow]);
311 for (auto& lbl : labels) {
312 if (lbl == lbTrc) {
313 const_cast<o2::MCCompLabel&>(lbl).setFakeFlag(true); // actually, in this way we are flagging that this cluster was correctly attached
314 break;
315 }
316 }
317 }
318 }
319 };
320
321 {
322 const auto* digconst = mcReader.getDigitizationContext();
323 const auto& mcEvRecords = digconst->getEventRecords(false);
324 int ITSTimeBias = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance().roFrameBiasInBC;
325 int ITSROFLen = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance().roFrameLengthInBC;
326 unsigned int rofCount = 0;
327 const auto ITSClusROFRec = recoData.getITSClustersROFRecords();
328 for (const auto& mcIR : mcEvRecords) {
329 long tbc = mcIR.differenceInBC(recoData.startIR);
330 auto& mcVtx = mMCVtVec.emplace_back();
331 mcVtx.ts = tbc * o2::constants::lhc::LHCBunchSpacingMUS + mcIR.getTimeOffsetWrtBC() * 1e-3;
332 mcVtx.ID = mIntBC.size();
333 mIntBC.push_back(tbc);
334 int occBin = tbc / 8 * mNTPCOccBinLengthInv;
335 mTPCOcc.push_back(occBin < 0 ? mTBinClOcc[0] : (occBin >= mTBinClOcc.size() ? mTBinClOcc.back() : mTBinClOcc[occBin]));
336 // fill ITS occupancy
337 long gbc = mcIR.toLong();
338 while (rofCount < ITSClusROFRec.size()) {
339 long rofbcMin = ITSClusROFRec[rofCount].getBCData().toLong() + ITSTimeBias, rofbcMax = rofbcMin + ITSROFLen;
340 if (gbc < rofbcMin) { // IRs and ROFs are sorted, so this IR is prior of all ROFs
341 mITSOcc.push_back(0);
342 } else if (gbc < rofbcMax) {
343 mITSOcc.push_back(ITSClusROFRec[rofCount].getNEntries());
344 } else {
345 rofCount++; // test next ROF
346 continue;
347 }
348 break;
349 }
350 if (mNTPCOccBinLengthInv > 0.f) {
351 mcVtx.occTPCV.resize(params.nOccBinsDrift);
352 int grp = TMath::Max(1, TMath::Nint(params.nTBPerOccBin * mNTPCOccBinLengthInv));
353 for (int ib = 0; ib < params.nOccBinsDrift; ib++) {
354 float smb = 0;
355 int tbs = occBin + TMath::Nint(ib * params.nTBPerOccBin * mNTPCOccBinLengthInv);
356 for (int ig = 0; ig < grp; ig++) {
357 if (tbs >= 0 && tbs < int(mTBinClOccHist.size())) {
358 smb += mTBinClOccHist[tbs];
359 }
360 tbs++;
361 }
362 mcVtx.occTPCV[ib] = smb;
363 }
364 }
365 if (rofCount >= ITSClusROFRec.size()) {
366 mITSOcc.push_back(0); // IR after the last ROF
367 }
368 }
369 }
370 // collect interesting MC particle (tracks and parents)
371 int curSrcMC = 0, curEvMC = 0;
372 for (curSrcMC = 0; curSrcMC < (int)mcReader.getNSources(); curSrcMC++) {
373 if (mVerbose > 1) {
374 LOGP(info, "Source {}", curSrcMC);
375 }
376 int nev = mcReader.getNEvents(curSrcMC);
377 bool okAccVtx = true;
378 if (nev != (int)mMCVtVec.size()) {
379 LOGP(debug, "source {} has {} events while {} MC vertices were booked", curSrcMC, nev, mMCVtVec.size());
380 okAccVtx = false;
381 if (nev > (int)mMCVtVec.size()) { // QED
382 continue;
383 }
384 }
385 for (curEvMC = 0; curEvMC < nev; curEvMC++) {
386 if (mVerbose > 1) {
387 LOGP(info, "Event {}", curEvMC);
388 }
389 mCurrMCTracks = &mcReader.getTracks(curSrcMC, curEvMC);
390 const_cast<o2::dataformats::MCEventHeader&>(mcReader.getMCEventHeader(curSrcMC, curEvMC)).GetVertex(mCurrMCVertex);
391 if (okAccVtx) {
392 auto& pos = mMCVtVec[curEvMC].pos;
393 if (pos[2] < -999) {
394 pos[0] = mCurrMCVertex.X();
395 pos[1] = mCurrMCVertex.Y();
396 pos[2] = mCurrMCVertex.Z();
397 }
398 }
399 for (int itr = 0; itr < mCurrMCTracks->size(); itr++) {
400 processMCParticle(curSrcMC, curEvMC, itr);
401 }
402 }
403 }
404 if (mVerbose > 0) {
405 for (int id = 0; id < mNCheckDecays; id++) {
406 LOGP(info, "Decay PDG={} : {} entries", params.decayPDG[id], mDecaysMaps[id].size());
407 }
408 }
409
410 // add reconstruction info to MC particles. If MC particle was not selected before but was reconstrected, account MC info
411 mRecProcStage = true; // MC particles accepted only at this stage will be flagged
412 for (int iv = 0; iv < nv; iv++) {
413 if (mVerbose > 1) {
414 LOGP(info, "processing PV {} of {}", iv, nv);
415 }
416 o2::MCEventLabel pvLbl;
417 int pvID = -1;
418 if (iv < (int)pvvecLbl.size()) {
419 pvLbl = pvvecLbl[iv];
420 pvID = iv;
421 if (pvLbl.isSet() && pvLbl.getEventID() < mMCVtVec.size()) {
422 mMCVtVec[pvLbl.getEventID()].recVtx.emplace_back(RecPV{pvvec[iv], pvLbl});
423 }
424 }
425 const auto& vtref = vtxRefs[iv];
426 for (int is = GTrackID::NSources; is--;) {
427 DetID::mask_t dm = GTrackID::getSourceDetectorsMask(is);
428 if (!mTracksSrc[is] || !recoData.isTrackSourceLoaded(is) || !(dm[DetID::ITS] || dm[DetID::TPC])) {
429 continue;
430 }
431 int idMin = vtref.getFirstEntryOfSource(is), idMax = idMin + vtref.getEntriesOfSource(is);
432 for (int i = idMin; i < idMax; i++) {
433 auto vid = trackIndex[i];
434 const auto& trc = recoData.getTrackParam(vid);
435 if (trc.getPt() < params.minPt || std::abs(trc.getTgl()) > params.maxTgl) {
436 continue;
437 }
438 auto lbl = recoData.getTrackMCLabel(vid);
439 if (lbl.isValid()) {
440 lbl.setFakeFlag(false);
441 auto entry = mSelMCTracks.find(lbl);
442 if (entry == mSelMCTracks.end()) { // add the track which was not added during MC scan
443 if (lbl.getSourceID() != curSrcMC || lbl.getEventID() != curEvMC) {
444 curSrcMC = lbl.getSourceID();
445 curEvMC = lbl.getEventID();
446 mCurrMCTracks = &mcReader.getTracks(curSrcMC, curEvMC);
447 const_cast<o2::dataformats::MCEventHeader&>(mcReader.getMCEventHeader(curSrcMC, curEvMC)).GetVertex(mCurrMCVertex);
448 }
449 if (!acceptMCCharged((*mCurrMCTracks)[lbl.getTrackID()], lbl)) {
450 continue;
451 }
452 entry = mSelMCTracks.find(lbl);
453 }
454 auto& trackFamily = entry->second;
455 if (vid.isAmbiguous()) { // do not repeat ambiguous tracks
456 if (trackFamily.contains(vid)) {
457 continue;
458 }
459 }
460 auto& trf = trackFamily.recTracks.emplace_back();
461 trf.gid = vid; // account(iv, vid);
462 trf.pvID = pvID;
463 trf.pvLabel = pvLbl;
464 while (dm[DetID::ITS] && dm[DetID::TPC]) { // this track should have both ITS and TPC parts, if ITS was mismatched, fill it to its proper MC track slot
465 auto gidSet = recoData.getSingleDetectorRefs(vid);
466 if (!gidSet[GTrackID::ITS].isSourceSet()) {
467 break; // AB track, nothing to check
468 }
469 auto lblITS = recoData.getTrackMCLabel(gidSet[GTrackID::ITS]);
470 if (lblITS == trackFamily.mcTrackInfo.label) {
471 break; // correct match, no need for special treatment
472 }
473 const auto& trcITSF = recoData.getTrackParam(gidSet[GTrackID::ITS]);
474 if (trcITSF.getPt() < params.minPt || std::abs(trcITSF.getTgl()) > params.maxTgl) {
475 break; // ignore this track
476 }
477 auto entryOfFake = mSelMCTracks.find(lblITS);
478 if (entryOfFake == mSelMCTracks.end()) { // this MC track was not selected
479 break;
480 }
481 auto& trackFamilyOfFake = entryOfFake->second;
482 auto& trfOfFake = trackFamilyOfFake.recTracks.emplace_back();
483 trfOfFake.gid = gidSet[GTrackID::ITS]; // account(iv, vid);
484 break;
485 }
486 if (mVerbose > 1) {
487 LOGP(info, "Matched rec track {} to MC track {}", vid.asString(), entry->first.asString());
488 }
489 } else {
490 continue;
491 }
492 }
493 }
494 }
495
496 LOGP(info, "collected {} MC tracks", mSelMCTracks.size());
497 if (params.minTPCRefsToExtractClRes > 0 || params.storeTPCTrackRefs) { // prepare MC trackrefs for TPC
498 processTPCTrackRefs();
499 }
500
501 int mcnt = 0;
502 for (auto& entry : mSelMCTracks) {
503 auto& trackFam = entry.second;
504 auto& tracks = trackFam.recTracks;
505 mcnt++;
506 if (tracks.empty()) {
507 continue;
508 }
509 if (mVerbose > 1) {
510 LOGP(info, "Processing MC track#{} {} -> {} reconstructed tracks", mcnt - 1, entry.first.asString(), tracks.size());
511 }
512 // sort according to the gid complexity (in principle, should be already sorted due to the backwards loop over NSources above
513 std::sort(tracks.begin(), tracks.end(), [](const RecTrack& lhs, const RecTrack& rhs) {
514 const auto mskL = lhs.gid.getSourceDetectorsMask();
515 const auto mskR = rhs.gid.getSourceDetectorsMask();
516 bool itstpcL = mskL[DetID::ITS] && mskL[DetID::TPC], itstpcR = mskR[DetID::ITS] && mskR[DetID::TPC];
517 if (itstpcL && !itstpcR) { // to avoid TPC/TRD or TPC/TOF shadowing ITS/TPC
518 return true;
519 }
520 return lhs.gid.getSource() > rhs.gid.getSource();
521 });
522 if (params.storeTPCTrackRefs) {
523 auto rft = mSelTRefIdx.find(entry.first);
524 if (rft != mSelTRefIdx.end()) {
525 auto rfent = rft->second;
526 for (int irf = rfent.first; irf < rfent.second; irf++) {
527 trackFam.mcTrackInfo.trackRefsTPC.push_back(mSelTRefs[irf]);
528 }
529 }
530 }
531 // fill track params
532 int tcnt = 0;
533 for (auto& tref : tracks) {
534 if (tref.gid.isSourceSet()) {
535 auto gidSet = recoData.getSingleDetectorRefs(tref.gid);
536 tref.track = recoData.getTrackParam(tref.gid);
537 if (recoData.getTrackMCLabel(tref.gid).isFake()) {
538 tref.flags |= RecTrack::FakeGLO;
539 }
540 auto msk = tref.gid.getSourceDetectorsMask();
541 if (msk[DetID::ITS]) {
542 if (gidSet[GTrackID::ITS].isSourceSet()) { // has ITS track rather than AB tracklet
543 tref.pattITS = getITSPatt(gidSet[GTrackID::ITS], tref.nClITS);
544 if (trackFam.entITS < 0) {
545 trackFam.entITS = tcnt;
546 }
547 auto lblITS = recoData.getTrackMCLabel(gidSet[GTrackID::ITS]);
548 if (lblITS.isFake()) {
549 tref.flags |= RecTrack::FakeITS;
550 }
551 if (lblITS == trackFam.mcTrackInfo.label) {
552 trackFam.entITSFound = tcnt;
553 }
554 } else { // AB ITS tracklet
555 tref.pattITS = getITSPatt(gidSet[GTrackID::ITSAB], tref.nClITS);
556 if (recoData.getTrackMCLabel(gidSet[GTrackID::ITSAB]).isFake()) {
557 tref.flags |= RecTrack::FakeITS;
558 }
559 }
560 if (msk[DetID::TPC]) {
561 if (trackFam.entITSTPC < 0) { // has both ITS and TPC contribution
562 trackFam.entITSTPC = tcnt;
563 }
564 if (recoData.getTrackMCLabel(gidSet[GTrackID::ITSTPC]).isFake()) {
565 tref.flags |= RecTrack::FakeITSTPC;
566 }
567
568 if (msk[DetID::TRD]) {
569 if (recoData.getTrackMCLabel(gidSet[GTrackID::ITSTPCTRD]).isFake()) {
570 tref.flags |= RecTrack::FakeTRD;
571 }
572 if (msk[DetID::TOF]) {
573 if (recoData.getTrackMCLabel(gidSet[GTrackID::ITSTPCTRDTOF]).isFake()) {
574 tref.flags |= RecTrack::FakeTOF;
575 }
576 }
577 } else {
578 if (msk[DetID::TOF]) {
579 if (recoData.getTrackMCLabel(gidSet[GTrackID::ITSTPCTOF]).isFake()) {
580 tref.flags |= RecTrack::FakeTOF;
581 }
582 }
583 }
584 }
585 }
586 if (msk[DetID::TPC]) {
587 const auto& trtpc = recoData.getTPCTrack(gidSet[GTrackID::TPC]);
588 tref.nClTPC = trtpc.getNClusters();
589 if (trtpc.hasBothSidesClusters()) {
590 tref.flags |= RecTrack::HASACSides;
591 }
592 fillTPCClusterInfo(trtpc, tref);
593 flagTPCClusters(trtpc, entry.first);
594 if (trackFam.entTPC < 0) {
595 trackFam.entTPC = tcnt;
596 trackFam.tpcT0 = trtpc.getTime0();
597 }
598 if (recoData.getTrackMCLabel(gidSet[GTrackID::TPC]).isFake()) {
599 tref.flags |= RecTrack::FakeTPC;
600 }
601 if (!msk[DetID::ITS]) {
602 if (msk[DetID::TRD]) {
603 if (recoData.getTrackMCLabel(gidSet[GTrackID::TPCTRD]).isFake()) {
604 tref.flags |= RecTrack::FakeTRD;
605 }
606 if (msk[DetID::TOF]) {
607 if (recoData.getTrackMCLabel(gidSet[GTrackID::TPCTRDTOF]).isFake()) {
608 tref.flags |= RecTrack::FakeTOF;
609 }
610 }
611 } else {
612 if (msk[DetID::TOF]) {
613 if (recoData.getTrackMCLabel(gidSet[GTrackID::TPCTOF]).isFake()) {
614 tref.flags |= RecTrack::FakeTOF;
615 }
616 }
617 }
618 }
619 }
620 float ts = 0, terr = 0;
621 if (tref.gid.getSource() != GTrackID::ITS) {
622 recoData.getTrackTime(tref.gid, ts, terr);
623 tref.ts = timeEst{ts, terr};
624 } else {
625 const auto& itsBra = mITSROFBracket[mITSROF[tref.gid.getIndex()]];
626 tref.ts = timeEst{itsBra.mean(), itsBra.delta() * SQRT12Inv};
627 }
628 } else {
629 LOGP(info, "Invalid entry {} of {} getTrackMCLabel {}", tcnt, tracks.size(), tref.gid.asString());
630 }
631 tcnt++;
632 }
633 if (trackFam.entITS > -1 && trackFam.entTPC > -1) { // ITS and TPC were found but matching failed
634 auto vidITS = recoData.getITSContributorGID(tracks[trackFam.entITS].gid);
635 auto vidTPC = recoData.getTPCContributorGID(tracks[trackFam.entTPC].gid);
636 auto trcTPC = recoData.getTrackParam(vidTPC);
637 auto trcITS = recoData.getTrackParamOut(vidITS);
638 if (propagateToRefX(trcTPC, trcITS)) {
639 trackFam.trackITSProp = trcITS;
640 trackFam.trackTPCProp = trcTPC;
641 } else {
642 trackFam.trackITSProp.invalidate();
643 trackFam.trackTPCProp.invalidate();
644 }
645 } else {
646 trackFam.trackITSProp.invalidate();
647 trackFam.trackTPCProp.invalidate();
648 }
649 }
650
651 // SVertices (V0s)
652 if (mCheckSV) {
653 auto v0s = recoData.getV0sIdx();
654 auto prpr = [](o2::trackstudy::TrackFamily& f) {
655 std::string s;
656 s += fmt::format(" par {} Ntpccl={} Nitscl={} ", f.mcTrackInfo.pdgParent, f.mcTrackInfo.nTPCCl, f.mcTrackInfo.nITSCl);
657 for (auto& t : f.recTracks) {
658 s += t.gid.asString();
659 s += " ";
660 }
661 return s;
662 };
663 for (int svID; svID < (int)v0s.size(); svID++) {
664 const auto& v0idx = v0s[svID];
665 int nOKProngs = 0, realMCSVID = -1;
666 int8_t decTypeID = -1;
667 for (int ipr = 0; ipr < v0idx.getNProngs(); ipr++) {
668 auto mcl = recoData.getTrackMCLabel(v0idx.getProngID(ipr)); // was this MC particle selected?
669 auto itl = mSelMCTracks.find(mcl);
670 if (itl == mSelMCTracks.end()) {
671 nOKProngs = -1; // was not selected as interesting one, ignore
672 break;
673 }
674 auto& trackFamily = itl->second;
675 int decayParentIndex = trackFamily.mcTrackInfo.parentEntry;
676 if (decayParentIndex < 0) { // does not come from decay
677 break;
678 }
679 if (ipr == 0) {
680 realMCSVID = decayParentIndex;
681 decTypeID = trackFamily.mcTrackInfo.parentDecID;
682 nOKProngs = 1;
683 LOGP(debug, "Prong{} {} comes from {}/{}", ipr, prpr(trackFamily), decTypeID, realMCSVID);
684 continue;
685 }
686 if (realMCSVID != decayParentIndex || decTypeID != trackFamily.mcTrackInfo.parentDecID) {
687 break;
688 }
689 LOGP(debug, "Prong{} {} comes from {}/{}", ipr, prpr(trackFamily), decTypeID, realMCSVID);
690 nOKProngs++;
691 }
692 if (nOKProngs == v0idx.getNProngs()) { // all prongs are from the decay of MC parent which deemed to be interesting, flag it
693 LOGP(debug, "Decay {}/{} was found", decTypeID, realMCSVID);
694 mDecaysMaps[decTypeID][realMCSVID].foundSVID = svID;
695 }
696 }
697 }
698
699 // collect ITS/TPC cluster info for selected MC particles
700 fillMCClusterInfo(recoData);
701
702 // single tracks
703 for (auto& entry : mSelMCTracks) {
704 auto& trackFam = entry.second;
705 (*mDBGOut) << "tracks" << "tr=" << trackFam << "\n";
706 }
707
708 // decays
709 std::vector<TrackFamily> decFam;
710 for (int id = 0; id < mNCheckDecays; id++) {
711 std::string decTreeName = fmt::format("dec{}", params.decayPDG[id]);
712 for (const auto& dec : mDecaysMaps[id]) {
713 decFam.clear();
714 bool skip = false;
715 for (int idd = dec.daughterFirst; idd <= dec.daughterLast; idd++) {
716 auto dtLbl = mDecProdLblPool[idd]; // daughter MC label
717 const auto& dtFamily = mSelMCTracks[dtLbl];
718 if (dtFamily.mcTrackInfo.pdgParent != dec.pdg) {
719 LOGP(error, "{}-th decay (pdg={}): {} in {}:{} range refers to MC track with pdgParent = {}", id, params.decayPDG[id], idd, dec.daughterFirst, dec.daughterLast, dtFamily.mcTrackInfo.pdgParent);
720 skip = true;
721 break;
722 }
723 decFam.push_back(dtFamily);
724 }
725 if (!skip) {
727 if (dec.foundSVID >= 0 && !refitV0(dec.foundSVID, v0, recoData)) {
728 v0.invalidate();
729 }
730 (*mDBGOut) << decTreeName.c_str() << "pdgPar=" << dec.pdg << "trPar=" << dec.parent << "prod=" << decFam << "found=" << dec.foundSVID << "sv=" << v0 << "\n";
731 }
732 }
733 }
734
735 for (auto& mcVtx : mMCVtVec) { // sort rec.vertices in mult. order
736 std::sort(mcVtx.recVtx.begin(), mcVtx.recVtx.end(), [](const RecPV& lhs, const RecPV& rhs) {
737 return lhs.pv.getNContributors() > rhs.pv.getNContributors();
738 });
739 (*mDBGOut) << "mcVtxTree" << "mcVtx=" << mcVtx << "\n";
740 }
741
742 if (params.storeITSInfo) {
743 processITSTracks(recoData);
744 }
745}
746
747void TrackMCStudy::processTPCTrackRefs()
748{
749 constexpr float alpsec[18] = {0.174533, 0.523599, 0.872665, 1.221730, 1.570796, 1.919862, 2.268928, 2.617994, 2.967060, 3.316126, 3.665191, 4.014257, 4.363323, 4.712389, 5.061455, 5.410521, 5.759587, 6.108652};
750 constexpr float sinAlp[18] = {0.173648, 0.500000, 0.766044, 0.939693, 1.000000, 0.939693, 0.766044, 0.500000, 0.173648, -0.173648, -0.500000, -0.766044, -0.939693, -1.000000, -0.939693, -0.766044, -0.500000, -0.173648};
751 constexpr float cosAlp[18] = {0.984808, 0.866025, 0.642788, 0.342020, 0.000000, -0.342020, -0.642788, -0.866025, -0.984808, -0.984808, -0.866025, -0.642788, -0.342020, -0.000000, 0.342020, 0.642788, 0.866025, 0.984808};
753 for (auto& entry : mSelMCTracks) {
754 auto lb = entry.first;
755 auto trspan = mcReader.getTrackRefs(lb.getSourceID(), lb.getEventID(), lb.getTrackID());
756 int q = entry.second.mcTrackInfo.track.getCharge();
757 if (q * q != 1) {
758 continue;
759 }
760 int ref0entry = mSelTRefs.size(), nrefsSel = 0;
761 for (const auto& trf : trspan) {
762 if (trf.getDetectorId() != 1) { // process TPC only
763 continue;
764 }
765 float pT = std::sqrt(trf.Px() * trf.Px() + trf.Py() * trf.Py());
766 if (pT < 0.05) {
767 continue;
768 }
769 float secX, secY, phi = std::atan2(trf.Y(), trf.X());
770 int sector = o2::math_utils::angle2Sector(phi);
771 o2::math_utils::rotateZInv(trf.X(), trf.Y(), secX, secY, sinAlp[sector], cosAlp[sector]); // sector coordinates
772 float phiPt = std::atan2(trf.Py(), trf.Px());
773 o2::math_utils::bringTo02Pi(phiPt);
774 auto dphiPt = phiPt - alpsec[sector];
775 if (dphiPt > o2::constants::math::PI) { // account for wraps
777 } else if (dphiPt < -o2::constants::math::PI) {
779 } else if (std::abs(dphiPt) > o2::constants::math::PIHalf * 0.8) {
780 continue; // ignore backward going or parallel to padrows tracks
781 }
782 float tgL = trf.Pz() / pT;
783 std::array<float, 5> pars = {secY, trf.Z(), std::sin(dphiPt), tgL, q / pT};
784 auto& refTrack = mSelTRefs.emplace_back(secX, alpsec[sector], pars);
785 refTrack.setUserField(uint16_t(sector));
786 nrefsSel++;
787 }
788 if (nrefsSel < params.minTPCRefsToExtractClRes) {
789 mSelTRefs.resize(ref0entry); // discard unused tracks
790 continue;
791 } else {
792 mSelTRefIdx[lb] = std::make_pair(ref0entry, ref0entry + nrefsSel);
793 }
794 }
795}
796
797void TrackMCStudy::fillMCClusterInfo(const o2::globaltracking::RecoContainer& recoData)
798{
799 // TPC clusters info
800 const auto& TPCClusterIdxStruct = recoData.inputsTPCclusters->clusterIndex;
801 const auto* TPCClMClab = recoData.inputsTPCclusters->clusterIndex.clustersMCTruth;
803
804 ClResTPC clRes{};
805 for (uint8_t row = 0; row < 152; row++) { // we need to go in increasing row, so this should be the outer loop
806 for (uint8_t sector = 0; sector < 36; sector++) {
807 unsigned int offs = TPCClusterIdxStruct.clusterOffset[sector][row];
808 for (unsigned int icl0 = 0; icl0 < TPCClusterIdxStruct.nClusters[sector][row]; icl0++) {
809 const auto labels = TPCClMClab->getLabels(icl0 + offs);
810 int ncontLb = 0; // number of real contrubutors to this label (w/o noise)
811 for (const auto& lbl : labels) {
812 if (!lbl.isValid()) {
813 continue;
814 }
815 ncontLb++;
816 }
817 const auto& clus = TPCClusterIdxStruct.clusters[sector][row][icl0];
818 int tbinH = int(clus.getTime() * mNTPCOccBinLengthInv); // time bin converted to slot of the occ. histo
819 clRes.contTracks.clear();
820 bool doClusRes = (params.minTPCRefsToExtractClRes > 0) && (params.rejectClustersResStat <= 0. || gRandom->Rndm() < params.rejectClustersResStat);
821 for (auto lbl : labels) {
822 bool corrAttach = lbl.isFake(); // was this flagged in the flagTPCClusters called from process ?
823 lbl.setFakeFlag(false);
824 auto entry = mSelMCTracks.find(lbl);
825 if (entry == mSelMCTracks.end()) { // not selected
826 continue;
827 }
828 auto& mctr = entry->second.mcTrackInfo;
829 mctr.nTPCCl++;
830 if (row > mctr.maxTPCRow) {
831 mctr.maxTPCRow = row;
832 mctr.maxTPCRowSect = sector;
833 mctr.nUsedPadRows++;
834 } else if (row == 0 && mctr.nUsedPadRows == 0) {
835 mctr.nUsedPadRows++;
836 }
837 if (row < mctr.minTPCRow) {
838 mctr.minTPCRow = row;
839 mctr.minTPCRowSect = sector;
840 }
841 if (mctr.minTPCRowSect == sector && row > mctr.maxTPCRowInner) {
842 mctr.maxTPCRowInner = row;
843 }
844 if (ncontLb > 1) {
845 mctr.nTPCClShared++;
846 }
847 // try to extract ideal track position
848 if (doClusRes) {
849 auto entTRefIDsIt = mSelTRefIdx.find(lbl);
850 if (entTRefIDsIt == mSelTRefIdx.end()) {
851 continue;
852 }
853 float xc, yc, zc;
854 mTPCCorrMaps->Transform(sector, row, clus.getPad(), clus.getTime(), xc, yc, zc, mctr.bcInTF / 8.); // nominal time of the track
855
856 const auto& entTRefIDs = entTRefIDsIt->second;
857 // find bracketing TRef params
858 int entIDBelow = -1, entIDAbove = -1;
859 float xBelow = -1e6, xAbove = 1e6;
860
861 for (int entID = entTRefIDs.first; entID < entTRefIDs.second; entID++) {
862 const auto& refTr = mSelTRefs[entID];
863 if (refTr.getUserField() != sector % 18) {
864 continue;
865 }
866 if ((refTr.getX() < xc) && (refTr.getX() > xBelow) && (refTr.getX() > xc - params.maxTPCRefExtrap)) {
867 xBelow = refTr.getX();
868 entIDBelow = entID;
869 }
870 if ((refTr.getX() > xc) && (refTr.getX() < xAbove) && (refTr.getX() < xc + params.maxTPCRefExtrap)) {
871 xAbove = refTr.getX();
872 entIDAbove = entID;
873 }
874 }
875 if ((entIDBelow < 0 && entIDAbove < 0) || (params.requireTopBottomRefs && (entIDBelow < 0 || entIDAbove < 0))) {
876 continue;
877 }
878 auto prop = o2::base::Propagator::Instance();
879 o2::track::TrackPar tparAbove, tparBelow;
880 bool okBelow = entIDBelow >= 0 && prop->PropagateToXBxByBz((tparBelow = mSelTRefs[entIDBelow]), xc, 0.99, 2.);
881 bool okAbove = entIDAbove >= 0 && prop->PropagateToXBxByBz((tparAbove = mSelTRefs[entIDAbove]), xc, 0.99, 2.);
882 if ((!okBelow && !okAbove) || (params.requireTopBottomRefs && (!okBelow || !okAbove))) {
883 continue;
884 }
885
886 int nmeas = 0;
887 auto& clCont = clRes.contTracks.emplace_back();
888 clCont.corrAttach = corrAttach;
889 if (okBelow) {
890 clCont.below = {mSelTRefs[entIDBelow].getX(), tparBelow.getY(), tparBelow.getZ()};
891 clCont.snp += tparBelow.getSnp();
892 clCont.tgl += tparBelow.getTgl();
893 clCont.q2pt += tparBelow.getQ2Pt();
894 nmeas++;
895 }
896 if (okAbove) {
897 clCont.above = {mSelTRefs[entIDAbove].getX(), tparAbove.getY(), tparAbove.getZ()};
898 clCont.snp += tparAbove.getSnp();
899 clCont.tgl += tparAbove.getTgl();
900 clCont.q2pt += tparAbove.getQ2Pt();
901 nmeas++;
902 }
903 if (nmeas) {
904 if (clRes.contTracks.size() == 1) {
905 int occBin = mctr.bcInTF / 8 * mNTPCOccBinLengthInv;
906 clRes.occ = occBin < 0 ? mTBinClOcc[0] : (occBin >= mTBinClOcc.size() ? mTBinClOcc.back() : mTBinClOcc[occBin]);
907 }
908 clCont.xyz = {xc, yc, zc};
909 if (nmeas > 1) {
910 clCont.snp *= 0.5;
911 clCont.tgl *= 0.5;
912 clCont.q2pt *= 0.5;
913 }
914 } else {
915 clRes.contTracks.pop_back();
916 }
917 }
918 }
919 if (clRes.getNCont()) {
920 clRes.sect = sector;
921 clRes.row = row;
922 clRes.qtot = clus.getQtot();
923 clRes.qmax = clus.getQmax();
924 clRes.flags = clus.getFlags();
925 clRes.sigmaTimePacked = clus.sigmaTimePacked;
926 clRes.sigmaPadPacked = clus.sigmaPadPacked;
927 clRes.ncont = ncontLb;
928 clRes.sortCont();
929
930 if (tbinH < 0) {
931 tbinH = 0;
932 } else if (tbinH >= int(mTBinClOccHist.size())) {
933 tbinH = (int)mTBinClOccHist.size() - 1;
934 }
935 clRes.occBin = mTBinClOccHist[tbinH];
936
937 (*mDBGOut) << "clres" << "clr=" << clRes << "\n";
938 }
939 }
940 }
941 }
942 // fill ITS cluster info
943 const auto* mcITSClusters = recoData.getITSClustersMCLabels();
944 const auto& ITSClusters = recoData.getITSClusters();
945 for (unsigned int icl = 0; icl < ITSClusters.size(); icl++) {
946 const auto labels = mcITSClusters->getLabels(icl);
947 for (const auto& lbl : labels) {
948 auto entry = mSelMCTracks.find(lbl);
949 if (entry == mSelMCTracks.end()) { // not selected
950 continue;
951 }
952 auto& mctr = entry->second.mcTrackInfo;
953 mctr.nITSCl++;
954 mctr.pattITSCl |= 0x1 << o2::itsmft::ChipMappingITS::getLayer(ITSClusters[icl].getChipID());
955 }
956 }
957
958 for (auto& entry : mSelMCTracks) { // count ITS reconstructable tracks
959 const auto& trackFam = entry.second;
960 const auto& mctr = trackFam.mcTrackInfo;
961 if (mctr.getLowestITSLayer() == 0 && mctr.getNITSClusCont() > 3) { // has 4 innermost layers
962 auto& mcev = mMCVtVec[mctr.label.getEventID()];
963 mcev.nTrackSelRCBL0++;
964 if (mctr.isPrimary()) {
965 mcev.nTrackSelRCBL0P++;
966 }
967 if (trackFam.entITSFound >= 0) {
968 mcev.nTrackRecRCBL0++;
969 }
970
971 if (mctr.maxTPCRow - mctr.minTPCRow >= params.nMinTPCRowSpan) {
972 mcev.nTrackSelRCBL1++;
973 if (mctr.isPrimary()) {
974 mcev.nTrackSelRCBL1P++;
975 }
976 if (trackFam.entITSTPC >= 0) {
977 mcev.nTrackRecRCBL1++;
978 }
979 }
980 }
981 }
982}
983
984bool TrackMCStudy::propagateToRefX(o2::track::TrackParCov& trcTPC, o2::track::TrackParCov& trcITS)
985{
986 bool refReached = false;
987 constexpr float TgHalfSector = 0.17632698f;
989 int trialsLeft = 2;
990 while (o2::base::Propagator::Instance()->PropagateToXBxByBz(trcTPC, par.XMatchingRef, MaxSnp, 2., par.matCorr)) {
991 if (refReached) {
992 break;
993 }
994 // make sure the track is indeed within the sector defined by alpha
995 if (fabs(trcTPC.getY()) < par.XMatchingRef * TgHalfSector) {
996 refReached = true;
997 break; // ok, within
998 }
999 if (!trialsLeft--) {
1000 break;
1001 }
1002 auto alphaNew = o2::math_utils::angle2Alpha(trcTPC.getPhiPos());
1003 if (!trcTPC.rotate(alphaNew) != 0) {
1004 break; // failed (RS: check effect on matching tracks to neighbouring sector)
1005 }
1006 }
1007 if (!refReached) {
1008 return false;
1009 }
1010 refReached = false;
1011 float alp = trcTPC.getAlpha();
1012 if (!trcITS.rotate(alp) != 0 || !o2::base::Propagator::Instance()->PropagateToXBxByBz(trcITS, par.XMatchingRef, MaxSnp, 2., par.matCorr)) {
1013 return false;
1014 }
1015 return true;
1016}
1017
1018void TrackMCStudy::endOfStream(EndOfStreamContext& ec)
1019{
1020 mDBGOut.reset();
1021}
1022
1023void TrackMCStudy::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj)
1024{
1025 if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) {
1026 return;
1027 }
1028 if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) {
1029 return;
1030 }
1031 if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) {
1032 LOG(info) << "ITS Alpide param updated";
1034 par.printKeyValues();
1035 mITSTimeBiasMUS = par.roFrameBiasInBC * o2::constants::lhc::LHCBunchSpacingNS * 1e-3;
1036 mITSROFrameLengthMUS = par.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS * 1e-3;
1037 return;
1038 }
1039 if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) {
1040 LOG(info) << "cluster dictionary updated";
1041 mITSDict = (const o2::itsmft::TopologyDictionary*)obj;
1042 return;
1043 }
1044}
1045
1046//_____________________________________________________
1047void TrackMCStudy::prepareITSData(const o2::globaltracking::RecoContainer& recoData)
1048{
1049 const auto ITSTracksArray = recoData.getITSTracks();
1050 const auto ITSTrackROFRec = recoData.getITSTracksROFRecords();
1051 int nROFs = ITSTrackROFRec.size();
1052 mITSROF.clear();
1053 mITSROFBracket.clear();
1054 mITSROF.reserve(ITSTracksArray.size());
1055 mITSROFBracket.reserve(ITSTracksArray.size());
1056 for (int irof = 0; irof < nROFs; irof++) {
1057 const auto& rofRec = ITSTrackROFRec[irof];
1058 long nBC = rofRec.getBCData().differenceInBC(recoData.startIR);
1059 float tMin = nBC * o2::constants::lhc::LHCBunchSpacingMUS + mITSTimeBiasMUS;
1060 float tMax = tMin + mITSROFrameLengthMUS;
1061 mITSROFBracket.emplace_back(tMin, tMax);
1062 for (int it = 0; it < rofRec.getNEntries(); it++) {
1063 mITSROF.push_back(irof);
1064 }
1065 }
1066}
1067/*
1068float TrackMCStudy::getDCAYCut(float pt) const
1069{
1070 static TF1 fun("dcayvspt", mDCAYFormula.c_str(), 0, 20);
1071 return fun.Eval(pt);
1072}
1073*/
1074
1075bool TrackMCStudy::processMCParticle(int src, int ev, int trid)
1076{
1077 const auto& mcPart = (*mCurrMCTracks)[trid];
1078 int pdg = mcPart.GetPdgCode();
1079 bool res = false;
1080 while (true) {
1081 auto lbl = o2::MCCompLabel(trid, ev, src);
1082 int decay = -1; // is this decay to watch?
1084 if (mcPart.T() < params.decayMotherMaxT) {
1085 for (int id = 0; id < mNCheckDecays; id++) {
1086 if (params.decayPDG[id] == std::abs(pdg)) {
1087 decay = id;
1088 break;
1089 }
1090 }
1091 if (decay >= 0) { // check if decay and kinematics is acceptable
1092 auto& decayPool = mDecaysMaps[decay];
1093 int idd0 = mcPart.getFirstDaughterTrackId(), idd1 = mcPart.getLastDaughterTrackId(); // we want only charged and trackable daughters
1094 int dtStart = mDecProdLblPool.size(), dtEnd = -1;
1095 if (idd0 < 0) {
1096 break;
1097 }
1098 for (int idd = idd0; idd <= idd1; idd++) {
1099 const auto& product = (*mCurrMCTracks)[idd];
1100 auto lbld = o2::MCCompLabel(idd, ev, src);
1101 if (!acceptMCCharged(product, lbld, decay)) {
1102 decay = -1; // discard decay
1103 mDecProdLblPool.resize(dtStart);
1104 break;
1105 }
1106 mDecProdLblPool.push_back(lbld); // register prong entry and label
1107 }
1108 if (decay >= 0) {
1109 // account decay
1110 dtEnd = mDecProdLblPool.size();
1111 for (int dtid = dtStart; dtid < dtEnd; dtid++) { // flag selected decay parent entry in the prongs MCs
1112 mSelMCTracks[mDecProdLblPool[dtid]].mcTrackInfo.parentEntry = decayPool.size();
1113 mSelMCTracks[mDecProdLblPool[dtid]].mcTrackInfo.parentDecID = int8_t(decay);
1114 }
1115 dtEnd--;
1116 std::array<float, 3> xyz{(float)mcPart.GetStartVertexCoordinatesX(), (float)mcPart.GetStartVertexCoordinatesY(), (float)mcPart.GetStartVertexCoordinatesZ()};
1117 std::array<float, 3> pxyz{(float)mcPart.GetStartVertexMomentumX(), (float)mcPart.GetStartVertexMomentumY(), (float)mcPart.GetStartVertexMomentumZ()};
1118 decayPool.emplace_back(DecayRef{lbl,
1119 o2::track::TrackPar(xyz, pxyz, TMath::Nint(O2DatabasePDG::Instance()->GetParticle(mcPart.GetPdgCode())->Charge() / 3), false),
1120 mcPart.GetPdgCode(), dtStart, dtEnd});
1121 if (mVerbose > 1) {
1122 LOGP(info, "Adding MC parent pdg={} {}, with prongs in {}:{} range", pdg, lbl.asString(), dtStart, dtEnd);
1123 }
1124 res = true; // Accept!
1125 }
1126 break;
1127 }
1128 }
1129 // check if this is a charged which should be processed but was not accounted as a decay product
1130 if (mSelMCTracks.find(lbl) == mSelMCTracks.end()) {
1131 res = acceptMCCharged(mcPart, lbl);
1132 }
1133 break;
1134 }
1135 return res;
1136}
1137
1138bool TrackMCStudy::acceptMCCharged(const MCTrack& tr, const o2::MCCompLabel& lb, int followDecay)
1139{
1141 if (tr.GetPt() < params.minPtMC ||
1142 std::abs(tr.GetTgl()) > params.maxTglMC ||
1143 tr.R2() > params.maxRMC * params.maxRMC) {
1144 if (mVerbose > 1 && followDecay > -1) {
1145 LOGP(info, "rejecting decay {} prong : pdg={}, pT={}, tgL={}, r={}", followDecay, tr.GetPdgCode(), tr.GetPt(), tr.GetTgl(), std::sqrt(tr.R2()));
1146 }
1147 return false;
1148 }
1149 float dx = tr.GetStartVertexCoordinatesX() - mCurrMCVertex.X(), dy = tr.GetStartVertexCoordinatesY() - mCurrMCVertex.Y(), dz = tr.GetStartVertexCoordinatesZ() - mCurrMCVertex.Z();
1150 float r2 = dx * dx + dy * dy;
1151 float posTgl2 = r2 > 1 && std::abs(dz) < 20 ? dz * dz / r2 : 0;
1152 if (posTgl2 > params.maxPosTglMC * params.maxPosTglMC) {
1153 if (mVerbose > 1 && followDecay > -1) {
1154 LOGP(info, "rejecting decay {} prong : pdg={}, pT={}, tgL={}, dr={}, dz={} r={}, z={}, posTgl={}", followDecay, tr.GetPdgCode(), tr.GetPt(), tr.GetTgl(), std::sqrt(r2), dz, std::sqrt(tr.R2()), tr.GetStartVertexCoordinatesZ(), std::sqrt(posTgl2));
1155 }
1156 return false;
1157 }
1158 if (params.requireITSorTPCTrackRefs) {
1159 auto trspan = mcReader.getTrackRefs(lb.getSourceID(), lb.getEventID(), lb.getTrackID());
1160 bool ok = false;
1161 for (const auto& trf : trspan) {
1162 if (trf.getDetectorId() == DetID::ITS || trf.getDetectorId() == DetID::TPC) {
1163 ok = true;
1164 break;
1165 }
1166 }
1167 if (!ok) {
1168 return false;
1169 }
1170 }
1171 TParticlePDG* pPDG = O2DatabasePDG::Instance()->GetParticle(tr.GetPdgCode());
1172 if (!pPDG) {
1173 LOGP(debug, "Unknown particle {}", tr.GetPdgCode());
1174 return false;
1175 }
1176 if (pPDG->Charge() == 0.) {
1177 return false;
1178 }
1179 return addMCParticle(tr, lb, pPDG);
1180}
1181
1182bool TrackMCStudy::addMCParticle(const MCTrack& mcPart, const o2::MCCompLabel& lb, TParticlePDG* pPDG)
1183{
1184 std::array<float, 3> xyz{(float)mcPart.GetStartVertexCoordinatesX(), (float)mcPart.GetStartVertexCoordinatesY(), (float)mcPart.GetStartVertexCoordinatesZ()};
1185 std::array<float, 3> pxyz{(float)mcPart.GetStartVertexMomentumX(), (float)mcPart.GetStartVertexMomentumY(), (float)mcPart.GetStartVertexMomentumZ()};
1186 if (!pPDG && !(pPDG = O2DatabasePDG::Instance()->GetParticle(mcPart.GetPdgCode()))) {
1187 LOGP(debug, "Unknown particle {}", mcPart.GetPdgCode());
1188 return false;
1189 }
1190 auto& mcEntry = mSelMCTracks[lb];
1191 mcEntry.mcTrackInfo.pdg = mcPart.GetPdgCode();
1192 mcEntry.mcTrackInfo.track = o2::track::TrackPar(xyz, pxyz, TMath::Nint(pPDG->Charge() / 3), true);
1193 mcEntry.mcTrackInfo.label = lb;
1194 mcEntry.mcTrackInfo.bcInTF = mIntBC[lb.getEventID()];
1195 mcEntry.mcTrackInfo.occTPC = mTPCOcc[lb.getEventID()];
1196 mcEntry.mcTrackInfo.occITS = mITSOcc[lb.getEventID()];
1197 mcEntry.mcTrackInfo.occTPCV = mMCVtVec[lb.getEventID()].occTPCV;
1198 if (mRecProcStage) {
1199 mcEntry.mcTrackInfo.setAddedAtRecStage();
1200 }
1201 if (o2::mcutils::MCTrackNavigator::isPhysicalPrimary(mcPart, *mCurrMCTracks)) {
1202 mcEntry.mcTrackInfo.setPrimary();
1203 }
1204 int moth = -1;
1205 o2::MCCompLabel mclbPar;
1206 if ((moth = mcPart.getMotherTrackId()) >= 0) {
1207 const auto& mcPartPar = (*mCurrMCTracks)[moth];
1208 mcEntry.mcTrackInfo.pdgParent = mcPartPar.GetPdgCode();
1209 }
1210 if (mcPart.isPrimary() && mcReader.getNEvents(lb.getSourceID()) == mMCVtVec.size()) {
1211 mMCVtVec[lb.getEventID()].nTrackSel++;
1212 if (mcPart.GetPt() > 0.1) {
1213 mMCVtVec[lb.getEventID()].nTrackSel100++;
1214 }
1215 }
1216 if (mVerbose > 1) {
1217 LOGP(info, "Adding charged MC pdg={} {} ", mcPart.GetPdgCode(), lb.asString());
1218 }
1219 return true;
1220}
1221
1222bool TrackMCStudy::refitV0(int i, o2::dataformats::V0& v0, const o2::globaltracking::RecoContainer& recoData)
1223{
1224 const auto& id = recoData.getV0sIdx()[i];
1225 auto seedP = recoData.getTrackParam(id.getProngID(0));
1226 auto seedN = recoData.getTrackParam(id.getProngID(1));
1227 bool isTPConly = (id.getProngID(0).getSource() == GTrackID::TPC) || (id.getProngID(1).getSource() == GTrackID::TPC);
1228 const auto& svparam = o2::vertexing::SVertexerParams::Instance();
1229 if (svparam.mTPCTrackPhotonTune && isTPConly) {
1230 mFitterV0.setMaxDZIni(svparam.mTPCTrackMaxDZIni);
1231 mFitterV0.setMaxDXYIni(svparam.mTPCTrackMaxDXYIni);
1232 mFitterV0.setMaxChi2(svparam.mTPCTrackMaxChi2);
1233 mFitterV0.setCollinear(true);
1234 }
1235 int nCand = mFitterV0.process(seedP, seedN);
1236 if (svparam.mTPCTrackPhotonTune && isTPConly) { // restore
1237 // Reset immediately to the defaults
1238 mFitterV0.setMaxDZIni(svparam.maxDZIni);
1239 mFitterV0.setMaxDXYIni(svparam.maxDXYIni);
1240 mFitterV0.setMaxChi2(svparam.maxChi2);
1241 mFitterV0.setCollinear(false);
1242 }
1243 if (nCand == 0) { // discard this pair
1244 return false;
1245 }
1246 const int cand = 0;
1247 if (!mFitterV0.isPropagateTracksToVertexDone(cand) && !mFitterV0.propagateTracksToVertex(cand)) {
1248 return false;
1249 }
1250 const auto& trPProp = mFitterV0.getTrack(0, cand);
1251 const auto& trNProp = mFitterV0.getTrack(1, cand);
1252 std::array<float, 3> pP{}, pN{};
1253 trPProp.getPxPyPzGlo(pP);
1254 trNProp.getPxPyPzGlo(pN);
1255 std::array<float, 3> pV0 = {pP[0] + pN[0], pP[1] + pN[1], pP[2] + pN[2]};
1256 auto p2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1] + pV0[2] * pV0[2];
1257 const auto& pv = recoData.getPrimaryVertex(id.getVertexID());
1258 const auto v0XYZ = mFitterV0.getPCACandidatePos(cand);
1259 float dx = v0XYZ[0] - pv.getX(), dy = v0XYZ[1] - pv.getY(), dz = v0XYZ[2] - pv.getZ(), prodXYZv0 = dx * pV0[0] + dy * pV0[1] + dz * pV0[2];
1260 float cosPA = prodXYZv0 / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0);
1261 new (&v0) o2::dataformats::V0(v0XYZ, pV0, mFitterV0.calcPCACovMatrixFlat(cand), trPProp, trNProp);
1262 v0.setDCA(mFitterV0.getChi2AtPCACandidate(cand));
1263 v0.setCosPA(cosPA);
1264 return true;
1265}
1266
1267void TrackMCStudy::loadTPCOccMap(const o2::globaltracking::RecoContainer& recoData)
1268{
1269 auto NHBPerTF = o2::base::GRPGeomHelper::instance().getGRPECS()->getNHBFPerTF();
1270 const auto& TPCOccMap = recoData.occupancyMapTPC;
1271 auto prop = o2::base::Propagator::Instance();
1272 auto TPCRefitter = std::make_unique<o2::gpu::GPUO2InterfaceRefit>(&recoData.inputsTPCclusters->clusterIndex, mTPCCorrMaps, prop->getNominalBz(),
1273 recoData.getTPCTracksClusterRefs().data(), 0, recoData.clusterShMapTPC.data(), TPCOccMap.data(), TPCOccMap.size(), nullptr, prop);
1274 mNTPCOccBinLength = TPCRefitter->getParam()->rec.tpc.occupancyMapTimeBins;
1275 mTBinClOcc.clear();
1276 if (mNTPCOccBinLength > 1 && TPCOccMap.size()) {
1277 mNTPCOccBinLengthInv = 1. / mNTPCOccBinLength;
1278 int nTPCBins = NHBPerTF * o2::constants::lhc::LHCMaxBunches / 8, ninteg = 0;
1279 int nTPCOccBins = nTPCBins * mNTPCOccBinLengthInv, sumBins = std::max(1, int(o2::constants::lhc::LHCMaxBunches / 8 * mNTPCOccBinLengthInv));
1280 mTBinClOcc.resize(nTPCOccBins);
1281 mTBinClOccHist.resize(nTPCOccBins);
1282 float sm = 0., tb = 0.5 * mNTPCOccBinLength;
1283 for (int i = 0; i < nTPCOccBins; i++) {
1284 mTBinClOccHist[i] = TPCRefitter->getParam()->GetUnscaledMult(tb);
1285 tb += mNTPCOccBinLength;
1286 }
1287 for (int i = nTPCOccBins; i--;) {
1288 sm += mTBinClOccHist[i];
1289 if (i + sumBins < nTPCOccBins) {
1290 sm -= mTBinClOccHist[i + sumBins];
1291 }
1292 mTBinClOcc[i] = sm;
1293 }
1294 } else {
1295 mTBinClOcc.resize(1);
1296 mTBinClOccHist.resize(1);
1297 }
1298}
1299
1300void TrackMCStudy::processITSTracks(const o2::globaltracking::RecoContainer& recoData)
1301{
1302 if (!mITSDict) {
1303 LOGP(warn, "ITS data is not loaded");
1304 return;
1305 }
1306 const auto itsTracks = recoData.getITSTracks();
1307 const auto itsLbls = recoData.getITSTracksMCLabels();
1308 const auto itsClRefs = recoData.getITSTracksClusterRefs();
1309 const auto clusITS = recoData.getITSClusters();
1310 const auto patterns = recoData.getITSClustersPatterns();
1312 auto pattIt = patterns.begin();
1313 mITSClustersArray.clear();
1314 mITSClustersArray.reserve(clusITS.size());
1315
1316 o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray, mITSDict);
1317 auto geom = o2::its::GeometryTGeo::Instance();
1318 int ntr = itsLbls.size();
1319 LOGP(info, "We have {} ITS clusters and the number of patterns is {}, ITSdict:{} NMCLabels: {}", clusITS.size(), patterns.size(), mITSDict != nullptr, itsLbls.size());
1320
1321 std::vector<int> evord(ntr);
1322 std::iota(evord.begin(), evord.end(), 0);
1323 std::sort(evord.begin(), evord.end(), [&](int i, int j) { return itsLbls[i] < itsLbls[j]; });
1324 std::vector<ITSHitInfo> outHitInfo;
1325 std::array<int, 7> cl2arr{};
1326
1327 for (int itr0 = 0; itr0 < ntr; itr0++) {
1328 auto itr = evord[itr0];
1329 const auto& itsTr = itsTracks[itr];
1330 const auto& itsLb = itsLbls[itr];
1331 // LOGP(info,"proc {} {} {}",itr0, itr, itsLb.asString());
1332 int nCl = itsTr.getNClusters();
1333 if (itsLb.isFake() || nCl < params.minITSClForITSoutput) {
1334 continue;
1335 }
1336 auto entrySel = mSelMCTracks.find(itsLb);
1337 if (entrySel == mSelMCTracks.end()) {
1338 continue;
1339 }
1340 outHitInfo.clear();
1341 cl2arr.fill(-1);
1342 auto clEntry = itsTr.getFirstClusterEntry();
1343 for (int iCl = nCl; iCl--;) { // clusters are stored from outer to inner layers
1344 const auto& cls = mITSClustersArray[itsClRefs[clEntry + iCl]];
1345 int hpos = outHitInfo.size();
1346 auto& hinf = outHitInfo.emplace_back();
1347 hinf.clus = cls;
1348 hinf.clus.setCount(geom->getLayer(cls.getSensorID()));
1349 geom->getSensorXAlphaRefPlane(cls.getSensorID(), hinf.chipX, hinf.chipAlpha);
1350 cl2arr[hinf.clus.getCount()] = hpos; // to facilitate finding the cluster of the layer
1351 }
1352 auto trspan = mcReader.getTrackRefs(itsLb.getSourceID(), itsLb.getEventID(), itsLb.getTrackID());
1353 int ilrc = -1, nrefAcc = 0;
1354 for (const auto& trf : trspan) {
1355 if (trf.getDetectorId() != 0) { // process ITS only
1356 continue;
1357 }
1358 int lrt = trf.getUserId(); // layer of the reference, but there might be multiple hits on the same layer
1359 int clEnt = cl2arr[lrt];
1360 if (clEnt < 0) {
1361 continue;
1362 }
1363 auto& hinf = outHitInfo[clEnt];
1364 float traX, traY;
1365 o2::math_utils::rotateZInv(trf.X(), trf.Y(), traX, traY, std::sin(hinf.chipAlpha), std::cos(hinf.chipAlpha)); // tracking coordinates of the reference
1366 if (hinf.trefXT < 1 || std::abs(traX - hinf.chipX) < std::abs(hinf.trefXT - hinf.chipX)) {
1367 if (hinf.trefXT < 1) {
1368 nrefAcc++;
1369 }
1370 hinf.tref = trf;
1371 hinf.trefXT = traX;
1372 hinf.trefYT = traY;
1373 }
1374 }
1375 (*mDBGOut) << "itsTree" << "hits=" << outHitInfo << "trIn=" << ((o2::track::TrackParCov&)itsTr) << "trOut=" << itsTr.getParamOut() << "mcTr=" << entrySel->second.mcTrackInfo.track << "mcPDG=" << entrySel->second.mcTrackInfo.pdg << "nTrefs=" << nrefAcc << "\n";
1376 }
1377}
1378
1380{
1381 std::vector<OutputSpec> outputs;
1382 Options opts{
1383 {"device-verbosity", VariantType::Int, 0, {"Verbosity level"}},
1384 {"dcay-vs-pt", VariantType::String, "0.0105 + 0.0350 / pow(x, 1.1)", {"Formula for global tracks DCAy vs pT cut"}},
1385 {"min-tpc-clusters", VariantType::Int, 60, {"Cut on TPC clusters"}},
1386 {"max-tpc-dcay", VariantType::Float, 2.f, {"Cut on TPC dcaY"}},
1387 {"max-tpc-dcaz", VariantType::Float, 2.f, {"Cut on TPC dcaZ"}},
1388 {"min-x-prop", VariantType::Float, 6.f, {"track should be propagated to this X at least"}}};
1389 auto dataRequest = std::make_shared<DataRequest>();
1390 bool useMC = true;
1391 dataRequest->requestTracks(srcTracks, useMC);
1392 dataRequest->requestClusters(srcClusters, useMC);
1393 dataRequest->requestPrimaryVertices(useMC);
1394 if (checkSV) {
1395 dataRequest->requestSecondaryVertices(useMC);
1396 }
1397 o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs);
1398 dataRequest->inputs.emplace_back("corrMap", o2::header::gDataOriginTPC, "TPCCORRMAP", 0, Lifetime::Timeframe);
1399 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(false, // orbitResetTime
1400 true, // GRPECS=true
1401 true, // GRPLHCIF
1402 true, // GRPMagField
1403 true, // askMatLUT
1405 dataRequest->inputs,
1406 true);
1407
1408 return DataProcessorSpec{
1409 "track-mc-study",
1410 dataRequest->inputs,
1411 outputs,
1412 AlgorithmSpec{adaptFromTask<TrackMCStudy>(dataRequest, ggRequest, srcTracks, checkSV)},
1413 opts};
1414}
1415
1416} // namespace o2::trackstudy
std::vector< std::string > labels
Defintions for N-prongs secondary vertex fit.
Wrapper container for different reconstructed object types.
Definition of the GeometryManager class.
std::ostringstream debug
Definition of the FIT RecPoints class.
int32_t i
o2::raw::RawFileWriter * raw
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.
Configurable params for TPC ITS matching.
Definition of the Names Generator class.
Definition of the parameter class for the detector electronics.
uint16_t pos
Definition RawData.h:3
uint32_t j
Definition RawData.h:0
uint32_t res
Definition RawData.h:0
Wrapper container for different reconstructed object types.
o2::track::TrackParCov TrackParCov
Definition Recon.h:39
Configurable params for secondary vertexer.
POD correction map.
Result of refitting TPC-ITS matched track.
Reference on ITS/MFT clusters set.
Helper class to extract VDrift from different sources.
Referenc on track indices contributing to the vertex, with possibility chose tracks from specific sou...
bool isFake() const
Definition MCCompLabel.h:85
void setFakeFlag(bool v=true)
int getTrackID() const
int getSourceID() const
int getEventID() const
std::string asString() const
bool isSet() const
int getEventID() const
Double_t GetStartVertexMomentumZ() const
Definition MCTrack.h:81
Double_t GetStartVertexMomentumX() const
Definition MCTrack.h:79
bool isPrimary() const
Definition MCTrack.h:75
Double_t GetStartVertexCoordinatesY() const
Definition MCTrack.h:83
Double_t GetPt() const
Definition MCTrack.h:109
Double_t GetStartVertexCoordinatesZ() const
Definition MCTrack.h:84
Double_t R2() const
production radius squared
Definition MCTrack.h:88
Double_t GetStartVertexMomentumY() const
Definition MCTrack.h:80
Double_t GetTgl() const
Definition MCTrack.h:142
Double_t GetStartVertexCoordinatesX() const
Definition MCTrack.h:82
Int_t GetPdgCode() const
Accessors.
Definition MCTrack.h:72
Int_t getMotherTrackId() const
Definition MCTrack.h:73
static TDatabasePDG * Instance()
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
void setDCA(float d)
Definition V0.h:47
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
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.
static GeometryTGeo * Instance()
void fillMatrixCache(int mask) override
static constexpr int getLayer(int chipSW)
static bool isPhysicalPrimary(o2::MCTrack const &p, std::vector< o2::MCTrack > const &pcontainer)
Definition MCUtils.cxx:73
std::vector< o2::InteractionTimeRecord > & getEventRecords(bool withQED=false)
bool initFromDigitContext(std::string_view filename)
DigitizationContext const * getDigitizationContext() 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
size_t getNSources() const
Get number of sources.
std::vector< MCTrack > const & getTracks(int source, int event) const
variant returning all tracks for source and event at once
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
void endOfStream(EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
void init(InitContext &ic) final
void finaliseCCDB(ConcreteDataMatcher &matcher, void *obj) final
void run(ProcessingContext &pc) final
void process(const o2::globaltracking::RecoContainer &recoData)
TrackMCStudy(std::shared_ptr< DataRequest > dr, std::shared_ptr< o2::base::GRPGeomRequest > gr, GTrackID::mask_t src, bool checkSV)
~TrackMCStudy() final=default
GLenum src
Definition glcorearb.h:1767
GLuint entry
Definition glcorearb.h:5735
GLdouble f
Definition glcorearb.h:310
GLenum const GLfloat * params
Definition glcorearb.h:272
GLfloat v0
Definition glcorearb.h:811
GLuint id
Definition glcorearb.h:650
@ ITSClusters
constexpr o2::header::DataOrigin gDataOriginTPC
Definition DataHeader.h:576
constexpr double LHCBunchSpacingMUS
constexpr int LHCMaxBunches
constexpr double LHCBunchSpacingNS
constexpr float TwoPI
constexpr float PI
constexpr float PIHalf
Node par(int index)
Parameters.
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
std::vector< ConfigParamSpec > Options
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
o2::track::TrackParCov int int int float int nCl
detail::Bracket< float > Bracketf_t
Definition Primitive2D.h:40
float angle2Alpha(float phi)
Definition Utils.h:203
int angle2Sector(float phi)
Definition Utils.h:183
std::tuple< float, float > rotateZInv(float xG, float yG, float snAlp, float csAlp)
Definition Utils.h:142
TrackParCovF TrackParCov
Definition Track.h:33
TrackParF TrackPar
Definition Track.h:29
std::pair< int, o2::dataformats::VtxTrackIndex > VTIndexV
o2::framework::DataProcessorSpec getTrackMCStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool checkSV)
create a processor spec
o2::dataformats::VtxTrackRef V2TRef
o2::dataformats::VtxTrackIndex VTIndex
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
GTrackID getITSContributorGID(GTrackID source) const
GlobalIDSet getSingleDetectorRefs(GTrackID gidx) const
const o2::tpc::TrackTPC & getTPCTrack(GTrackID id) const
const o2::tpc::ClusterNativeAccess & getTPCClusters() const
o2::MCCompLabel getTrackMCLabel(GTrackID id) const
GTrackID getTPCContributorGID(GTrackID source) const
const o2::track::TrackParCov & getTrackParam(GTrackID gidx) const
gsl::span< const unsigned char > clusterShMapTPC
externally set TPC clusters sharing map
void collectData(o2::framework::ProcessingContext &pc, const DataRequest &request)
const o2::track::TrackParCov & getTrackParamOut(GTrackID gidx) const
const o2::dataformats::PrimaryVertex & getPrimaryVertex(int i) const
const o2::its::TrackITS & getITSTrack(GTrackID gid) const
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 constexpr int T2L
Definition Cartesian.h:56
static constexpr int T2GRot
Definition Cartesian.h:58
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< int > row