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