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>
53#include "GPUO2InterfaceRefit.h"
54#include "GPUParam.h"
55#include "GPUParam.inc"
56#include "MathUtils/fit.h"
57#include <TRandom.h>
58#include <map>
59#include <unordered_map>
60#include <array>
61#include <utility>
62#include <gsl/span>
63
64// workflow to study relation of reco tracks to MCTruth
65// o2-trackmc-study-workflow --device-verbosity 3 -b --run
66
67namespace o2::trackstudy
68{
69
70using namespace o2::framework;
73
77using VTIndexV = std::pair<int, o2::dataformats::VtxTrackIndex>;
80
82
83class TrackMCStudy : public Task
84{
85 public:
86 TrackMCStudy(std::shared_ptr<DataRequest> dr, std::shared_ptr<o2::base::GRPGeomRequest> gr, GTrackID::mask_t src, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, bool checkSV)
87 : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mCheckSV(checkSV)
88 {
89 mTPCCorrMapsLoader.setLumiScaleType(sclOpts.lumiType);
90 mTPCCorrMapsLoader.setLumiScaleMode(sclOpts.lumiMode);
91 }
92 ~TrackMCStudy() final = default;
93 void init(InitContext& ic) final;
94 void run(ProcessingContext& pc) final;
95 void endOfStream(EndOfStreamContext& ec) final;
96 void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final;
97 void process(const o2::globaltracking::RecoContainer& recoData);
98
99 private:
100 void processTPCTrackRefs();
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 gsl::span<const MCTrack> mCurrMCTracks;
113 TVector3 mCurrMCVertex;
114 o2::tpc::VDriftHelper mTPCVDriftHelper{};
115 o2::tpc::CorrectionMapsLoader mTPCCorrMapsLoader{};
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 bool mCheckSV = false; //< check SV binding (apart from prongs availability)
125 int mNTPCOccBinLength = 0;
126 float mNTPCOccBinLengthInv;
127 int mVerbose = 0;
128 float mITSTimeBiasMUS = 0.f;
129 float mITSROFrameLengthMUS = 0.f;
130 float mTPCTBinMUS = 0.;
131
132 int mNCheckDecays = 0;
133
134 GTrackID::mask_t mTracksSrc{};
135 o2::steer::MCKinematicsReader mcReader; // reader of MC information
136 std::vector<int> mITSROF;
137 std::vector<TBracket> mITSROFBracket;
138 std::vector<o2::MCCompLabel> mDecProdLblPool; // labels of decay products to watch, added to MC map
139 std::vector<MCVertex> mMCVtVec{};
140
141 struct DecayRef {
142 o2::MCCompLabel mother{};
143 o2::track::TrackPar parent{};
144 int pdg = 0;
145 int daughterFirst = -1;
146 int daughterLast = -1;
147 int foundSVID = -1;
148 };
149 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
150 std::unordered_map<o2::MCCompLabel, TrackFamily> mSelMCTracks;
151 std::unordered_map<o2::MCCompLabel, std::pair<int, int>> mSelTRefIdx;
152 std::vector<o2::track::TrackPar> mSelTRefs;
154 static constexpr float MaxSnp = 0.9; // max snp of ITS or TPC track at xRef to be matched
155};
156
158{
160 mcReader.initFromDigitContext("collisioncontext.root");
161
162 mDBGOut = std::make_unique<o2::utils::TreeStreamRedirector>("trackMCStudy.root", "recreate");
163 mVerbose = ic.options().get<int>("device-verbosity");
164
166 for (int id = 0; id < sizeof(params.decayPDG) / sizeof(int); id++) {
167 if (params.decayPDG[id] < 0) {
168 break;
169 }
170 mNCheckDecays++;
171 }
172 mDecaysMaps.resize(mNCheckDecays);
173 mTPCCorrMapsLoader.init(ic);
174}
175
177{
179 for (int i = 0; i < mNCheckDecays; i++) {
180 mDecaysMaps[i].clear();
181 }
182 mDecProdLblPool.clear();
183 mMCVtVec.clear();
184 mCurrMCTracks = {};
185
186 recoData.collectData(pc, *mDataRequest.get()); // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer
187 updateTimeDependentParams(pc); // Make sure this is called after recoData.collectData, which may load some conditions
188 process(recoData);
189}
190
191void TrackMCStudy::updateTimeDependentParams(ProcessingContext& pc)
192{
194 mTPCVDriftHelper.extractCCDBInputs(pc);
195 mTPCCorrMapsLoader.extractCCDBInputs(pc);
196 bool updateMaps = false;
197 if (mTPCCorrMapsLoader.isUpdated()) {
198 mTPCCorrMapsLoader.acknowledgeUpdate();
199 updateMaps = true;
200 }
201 if (mTPCVDriftHelper.isUpdated()) {
202 LOGP(info, "Updating TPC fast transform map with new VDrift factor of {} wrt reference {} and DriftTimeOffset correction {} wrt {} from source {}",
203 mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift,
204 mTPCVDriftHelper.getVDriftObject().timeOffsetCorr, mTPCVDriftHelper.getVDriftObject().refTimeOffset,
205 mTPCVDriftHelper.getSourceName());
206 mTPCVDriftHelper.acknowledgeUpdate();
207 updateMaps = true;
208 }
209 if (updateMaps) {
210 mTPCCorrMapsLoader.updateVDrift(mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getVDriftObject().getTimeOffset());
211 }
212 static bool initOnceDone = false;
213 if (!initOnceDone) { // this params need to be queried only once
214 initOnceDone = true;
216 mITSROFrameLengthMUS = o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS) ? alpParamsITS.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingMUS : alpParamsITS.roFrameLengthTrig * 1.e-3;
217 LOGP(info, "VertexTrackMatcher ITSROFrameLengthMUS:{}", mITSROFrameLengthMUS);
218
220 mTPCTBinMUS = elParam.ZbinWidth;
221
222 if (mCheckSV) {
223 const auto& svparam = o2::vertexing::SVertexerParams::Instance();
224 mFitterV0.setBz(o2::base::Propagator::Instance()->getNominalBz());
225 mFitterV0.setUseAbsDCA(svparam.useAbsDCA);
226 mFitterV0.setPropagateToPCA(false);
227 mFitterV0.setMaxR(svparam.maxRIni);
228 mFitterV0.setMinParamChange(svparam.minParamChange);
229 mFitterV0.setMinRelChi2Change(svparam.minRelChi2Change);
230 mFitterV0.setMaxDZIni(svparam.maxDZIni);
231 mFitterV0.setMaxDXYIni(svparam.maxDXYIni);
232 mFitterV0.setMaxChi2(svparam.maxChi2);
233 mFitterV0.setMatCorrType(o2::base::Propagator::MatCorrType(svparam.matCorr));
234 mFitterV0.setUsePropagator(svparam.usePropagator);
235 mFitterV0.setRefitWithMatCorr(svparam.refitWithMatCorr);
236 mFitterV0.setMaxStep(svparam.maxStep);
237 mFitterV0.setMaxSnp(svparam.maxSnp);
238 mFitterV0.setMinXSeed(svparam.minXSeed);
239 }
240 }
241}
242
244{
245 constexpr float SQRT12Inv = 0.288675f;
247 auto pvvec = recoData.getPrimaryVertices();
248 auto pvvecLbl = recoData.getPrimaryVertexMCLabels();
249 auto trackIndex = recoData.getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks
250 auto vtxRefs = recoData.getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs
251 auto prop = o2::base::Propagator::Instance();
252 int nv = vtxRefs.size();
253 float vdriftTB = mTPCVDriftHelper.getVDriftObject().getVDrift() * o2::tpc::ParameterElectronics::Instance().ZbinWidth; // VDrift expressed in cm/TimeBin
254 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
255
256 prepareITSData(recoData);
257 loadTPCOccMap(recoData);
258 auto getITSPatt = [&](GTrackID gid, uint8_t& ncl) {
259 int8_t patt = 0;
260 if (gid.getSource() == VTIndex::ITSAB) {
261 const auto& itsTrf = recoData.getITSABRefs()[gid];
262 ncl = itsTrf.getNClusters();
263 for (int il = 0; il < 7; il++) {
264 if (itsTrf.hasHitOnLayer(il)) {
265 patt |= 0x1 << il;
266 }
267 }
268 patt |= 0x1 << 7;
269 } else {
270 const auto& itsTr = recoData.getITSTrack(gid);
271 for (int il = 0; il < 7; il++) {
272 if (itsTr.hasHitOnLayer(il)) {
273 patt |= 0x1 << il;
274 ncl++;
275 }
276 }
277 }
278 return patt;
279 };
280
281 auto getLowestPadrow = [&recoData](const o2::tpc::TrackTPC& trc) {
282 if (recoData.inputsTPCclusters) {
283 uint8_t clSect = 0, clRow = 0;
284 uint32_t clIdx = 0;
285 const auto clRefs = recoData.getTPCTracksClusterRefs();
286 trc.getClusterReference(clRefs, trc.getNClusterReferences() - 1, clSect, clRow, clIdx);
287 return int(clRow);
288 }
289 return -1;
290 };
291
292 auto flagTPCClusters = [&recoData](const o2::tpc::TrackTPC& trc, o2::MCCompLabel lbTrc) {
293 if (recoData.inputsTPCclusters) {
294 const auto clRefs = recoData.getTPCTracksClusterRefs();
295 const auto* TPCClMClab = recoData.inputsTPCclusters->clusterIndex.clustersMCTruth;
296 const auto& TPCClusterIdxStruct = recoData.inputsTPCclusters->clusterIndex;
297 for (int ic = 0; ic < trc.getNClusterReferences(); ic++) {
298 uint8_t clSect = 0, clRow = 0;
299 uint32_t clIdx = 0;
300 trc.getClusterReference(clRefs, ic, clSect, clRow, clIdx);
301 auto labels = TPCClMClab->getLabels(clIdx + TPCClusterIdxStruct.clusterOffset[clSect][clRow]);
302 for (auto& lbl : labels) {
303 if (lbl == lbTrc) {
304 const_cast<o2::MCCompLabel&>(lbl).setFakeFlag(true); // actually, in this way we are flagging that this cluster was correctly attached
305 break;
306 }
307 }
308 }
309 }
310 };
311
312 {
313 const auto* digconst = mcReader.getDigitizationContext();
314 const auto& mcEvRecords = digconst->getEventRecords(false);
315 int ITSTimeBias = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance().roFrameBiasInBC;
316 int ITSROFLen = o2::itsmft::DPLAlpideParam<o2::detectors::DetID::ITS>::Instance().roFrameLengthInBC;
317 unsigned int rofCount = 0;
318 const auto ITSClusROFRec = recoData.getITSClustersROFRecords();
319 for (const auto& mcIR : mcEvRecords) {
320 long tbc = mcIR.differenceInBC(recoData.startIR);
321 auto& mcVtx = mMCVtVec.emplace_back();
322 mcVtx.ts = tbc * o2::constants::lhc::LHCBunchSpacingMUS + mcIR.getTimeOffsetWrtBC() * 1e-3;
323 mcVtx.ID = mIntBC.size();
324 mIntBC.push_back(tbc);
325 int occBin = tbc / 8 * mNTPCOccBinLengthInv;
326 mTPCOcc.push_back(occBin < 0 ? mTBinClOcc[0] : (occBin >= mTBinClOcc.size() ? mTBinClOcc.back() : mTBinClOcc[occBin]));
327 // fill ITS occupancy
328 long gbc = mcIR.toLong();
329 while (rofCount < ITSClusROFRec.size()) {
330 long rofbcMin = ITSClusROFRec[rofCount].getBCData().toLong() + ITSTimeBias, rofbcMax = rofbcMin + ITSROFLen;
331 if (gbc < rofbcMin) { // IRs and ROFs are sorted, so this IR is prior of all ROFs
332 mITSOcc.push_back(0);
333 } else if (gbc < rofbcMax) {
334 mITSOcc.push_back(ITSClusROFRec[rofCount].getNEntries());
335 } else {
336 rofCount++; // test next ROF
337 continue;
338 }
339 break;
340 }
341 if (rofCount >= ITSClusROFRec.size()) {
342 mITSOcc.push_back(0); // IR after the last ROF
343 }
344 }
345 }
346 // collect interesting MC particle (tracks and parents)
347 int curSrcMC = 0, curEvMC = 0;
348 for (curSrcMC = 0; curSrcMC < (int)mcReader.getNSources(); curSrcMC++) {
349 if (mVerbose > 1) {
350 LOGP(info, "Source {}", curSrcMC);
351 }
352 int nev = mcReader.getNEvents(curSrcMC);
353 bool okAccVtx = true;
354 if (nev != (int)mMCVtVec.size()) {
355 LOGP(error, "source {} has {} events while {} MC vertices were booked", curSrcMC, nev, mMCVtVec.size());
356 okAccVtx = false;
357 }
358 for (curEvMC = 0; curEvMC < nev; curEvMC++) {
359 if (mVerbose > 1) {
360 LOGP(info, "Event {}", curEvMC);
361 }
362 const auto& mt = mcReader.getTracks(curSrcMC, curEvMC);
363 mCurrMCTracks = gsl::span<const MCTrack>(mt.data(), mt.size());
364 const_cast<o2::dataformats::MCEventHeader&>(mcReader.getMCEventHeader(curSrcMC, curEvMC)).GetVertex(mCurrMCVertex);
365 if (okAccVtx) {
366 auto& pos = mMCVtVec[curEvMC].pos;
367 if (pos[2] < -999) {
368 pos[0] = mCurrMCVertex.X();
369 pos[1] = mCurrMCVertex.Y();
370 pos[2] = mCurrMCVertex.Z();
371 }
372 }
373 for (int itr = 0; itr < mCurrMCTracks.size(); itr++) {
374 processMCParticle(curSrcMC, curEvMC, itr);
375 }
376 }
377 }
378 if (mVerbose > 0) {
379 for (int id = 0; id < mNCheckDecays; id++) {
380 LOGP(info, "Decay PDG={} : {} entries", params.decayPDG[id], mDecaysMaps[id].size());
381 }
382 }
383
384 // add reconstruction info to MC particles. If MC particle was not selected before but was reconstrected, account MC info
385 for (int iv = 0; iv < nv; iv++) {
386 if (mVerbose > 1) {
387 LOGP(info, "processing PV {} of {}", iv, nv);
388 }
389 o2::MCEventLabel pvLbl;
390 int pvID = -1;
391 if (iv < (int)pvvecLbl.size()) {
392 pvLbl = pvvecLbl[iv];
393 pvID = iv;
394 if (pvLbl.isSet() && pvLbl.getEventID() < mMCVtVec.size()) {
395 mMCVtVec[pvLbl.getEventID()].recVtx.emplace_back(RecPV{pvvec[iv], pvLbl});
396 }
397 }
398 const auto& vtref = vtxRefs[iv];
399 for (int is = GTrackID::NSources; is--;) {
400 DetID::mask_t dm = GTrackID::getSourceDetectorsMask(is);
401 if (!mTracksSrc[is] || !recoData.isTrackSourceLoaded(is) || !(dm[DetID::ITS] || dm[DetID::TPC])) {
402 continue;
403 }
404 int idMin = vtref.getFirstEntryOfSource(is), idMax = idMin + vtref.getEntriesOfSource(is);
405 for (int i = idMin; i < idMax; i++) {
406 auto vid = trackIndex[i];
407 const auto& trc = recoData.getTrackParam(vid);
408 if (trc.getPt() < params.minPt || std::abs(trc.getTgl()) > params.maxTgl) {
409 continue;
410 }
411 auto lbl = recoData.getTrackMCLabel(vid);
412 if (lbl.isValid()) {
413 lbl.setFakeFlag(false);
414 auto entry = mSelMCTracks.find(lbl);
415 if (entry == mSelMCTracks.end()) { // add the track which was not added during MC scan
416 if (lbl.getSourceID() != curSrcMC || lbl.getEventID() != curEvMC) {
417 curSrcMC = lbl.getSourceID();
418 curEvMC = lbl.getEventID();
419 const auto& mt = mcReader.getTracks(curSrcMC, curEvMC);
420 mCurrMCTracks = gsl::span<const MCTrack>(mt.data(), mt.size());
421 const_cast<o2::dataformats::MCEventHeader&>(mcReader.getMCEventHeader(curSrcMC, curEvMC)).GetVertex(mCurrMCVertex);
422 }
423 if (!acceptMCCharged(mCurrMCTracks[lbl.getTrackID()], lbl)) {
424 continue;
425 }
426 entry = mSelMCTracks.find(lbl);
427 }
428 auto& trackFamily = entry->second;
429 if (vid.isAmbiguous()) { // do not repeat ambiguous tracks
430 if (trackFamily.contains(vid)) {
431 continue;
432 }
433 }
434 auto& trf = trackFamily.recTracks.emplace_back();
435 trf.gid = vid; // account(iv, vid);
436 trf.pvID = pvID;
437 trf.pvLabel = pvLbl;
438 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
439 auto gidSet = recoData.getSingleDetectorRefs(vid);
440 if (!gidSet[GTrackID::ITS].isSourceSet()) {
441 break; // AB track, nothing to check
442 }
443 auto lblITS = recoData.getTrackMCLabel(gidSet[GTrackID::ITS]);
444 if (lblITS == trackFamily.mcTrackInfo.label) {
445 break; // correct match, no need for special treatment
446 }
447 const auto& trcITSF = recoData.getTrackParam(gidSet[GTrackID::ITS]);
448 if (trcITSF.getPt() < params.minPt || std::abs(trcITSF.getTgl()) > params.maxTgl) {
449 break; // ignore this track
450 }
451 auto entryOfFake = mSelMCTracks.find(lblITS);
452 if (entryOfFake == mSelMCTracks.end()) { // this MC track was not selected
453 break;
454 }
455 auto& trackFamilyOfFake = entryOfFake->second;
456 auto& trfOfFake = trackFamilyOfFake.recTracks.emplace_back();
457 trfOfFake.gid = gidSet[GTrackID::ITS]; // account(iv, vid);
458 break;
459 }
460 if (mVerbose > 1) {
461 LOGP(info, "Matched rec track {} to MC track {}", vid.asString(), entry->first.asString());
462 }
463 } else {
464 continue;
465 }
466 }
467 }
468 }
469
470 LOGP(info, "collected {} MC tracks", mSelMCTracks.size());
471 if (params.minTPCRefsToExtractClRes > 0) { // prepare MC trackrefs for TPC
472 processTPCTrackRefs();
473 }
474
475 int mcnt = 0;
476 for (auto& entry : mSelMCTracks) {
477 auto& trackFam = entry.second;
478 auto& tracks = trackFam.recTracks;
479 mcnt++;
480 if (tracks.empty()) {
481 continue;
482 }
483 if (mVerbose > 1) {
484 LOGP(info, "Processing MC track#{} {} -> {} reconstructed tracks", mcnt - 1, entry.first.asString(), tracks.size());
485 }
486 // sort according to the gid complexity (in principle, should be already sorted due to the backwards loop over NSources above
487 std::sort(tracks.begin(), tracks.end(), [](const RecTrack& lhs, const RecTrack& rhs) {
488 const auto mskL = lhs.gid.getSourceDetectorsMask();
489 const auto mskR = rhs.gid.getSourceDetectorsMask();
490 bool itstpcL = mskL[DetID::ITS] && mskL[DetID::TPC], itstpcR = mskR[DetID::ITS] && mskR[DetID::TPC];
491 if (itstpcL && !itstpcR) { // to avoid TPC/TRD or TPC/TOF shadowing ITS/TPC
492 return true;
493 }
494 return lhs.gid.getSource() > rhs.gid.getSource();
495 });
496 // fill track params
497 int tcnt = 0;
498 for (auto& tref : tracks) {
499 if (tref.gid.isSourceSet()) {
500 auto gidSet = recoData.getSingleDetectorRefs(tref.gid);
501 tref.track = recoData.getTrackParam(tref.gid);
502 if (recoData.getTrackMCLabel(tref.gid).isFake()) {
503 tref.flags |= RecTrack::FakeGLO;
504 }
505 auto msk = tref.gid.getSourceDetectorsMask();
506 if (msk[DetID::ITS]) {
507 if (gidSet[GTrackID::ITS].isSourceSet()) { // has ITS track rather than AB tracklet
508 tref.pattITS = getITSPatt(gidSet[GTrackID::ITS], tref.nClITS);
509 if (trackFam.entITS < 0) {
510 trackFam.entITS = tcnt;
511 }
512 auto lblITS = recoData.getTrackMCLabel(gidSet[GTrackID::ITS]);
513 if (lblITS.isFake()) {
514 tref.flags |= RecTrack::FakeITS;
515 }
516 if (lblITS == trackFam.mcTrackInfo.label) {
517 trackFam.entITSFound = tcnt;
518 }
519 } else { // AB ITS tracklet
520 tref.pattITS = getITSPatt(gidSet[GTrackID::ITSAB], tref.nClITS);
521 if (recoData.getTrackMCLabel(gidSet[GTrackID::ITSAB]).isFake()) {
522 tref.flags |= RecTrack::FakeITS;
523 }
524 }
525 if (msk[DetID::TPC] && trackFam.entITSTPC < 0) { // has both ITS and TPC contribution
526 trackFam.entITSTPC = tcnt;
527 if (recoData.getTrackMCLabel(gidSet[GTrackID::ITSTPC]).isFake()) {
528 tref.flags |= RecTrack::FakeITSTPC;
529 }
530 }
531 }
532 if (msk[DetID::TPC]) {
533 const auto& trtpc = recoData.getTPCTrack(gidSet[GTrackID::TPC]);
534 tref.nClTPC = trtpc.getNClusters();
535 tref.lowestPadRow = getLowestPadrow(trtpc);
536 flagTPCClusters(trtpc, entry.first);
537 if (trackFam.entTPC < 0) {
538 trackFam.entTPC = tcnt;
539 trackFam.tpcT0 = trtpc.getTime0();
540 }
541 if (recoData.getTrackMCLabel(gidSet[GTrackID::TPC]).isFake()) {
542 tref.flags |= RecTrack::FakeTPC;
543 }
544 }
545 float ts = 0, terr = 0;
546 if (tref.gid.getSource() != GTrackID::ITS) {
547 recoData.getTrackTime(tref.gid, ts, terr);
548 tref.ts = timeEst{ts, terr};
549 } else {
550 const auto& itsBra = mITSROFBracket[mITSROF[tref.gid.getIndex()]];
551 tref.ts = timeEst{itsBra.mean(), itsBra.delta() * SQRT12Inv};
552 }
553 } else {
554 LOGP(info, "Invalid entry {} of {} getTrackMCLabel {}", tcnt, tracks.size(), tref.gid.asString());
555 }
556 tcnt++;
557 }
558 if (trackFam.entITS > -1 && trackFam.entTPC > -1) { // ITS and TPC were found but matching failed
559 auto vidITS = tracks[trackFam.entITS].gid;
560 auto vidTPC = tracks[trackFam.entTPC].gid;
561 auto trcTPC = recoData.getTrackParam(vidTPC);
562 auto trcITS = recoData.getTrackParamOut(vidITS);
563 if (propagateToRefX(trcTPC, trcITS)) {
564 trackFam.trackITSProp = trcITS;
565 trackFam.trackTPCProp = trcTPC;
566 } else {
567 trackFam.trackITSProp.invalidate();
568 trackFam.trackTPCProp.invalidate();
569 }
570 } else {
571 trackFam.trackITSProp.invalidate();
572 trackFam.trackTPCProp.invalidate();
573 }
574 }
575
576 // SVertices (V0s)
577 if (mCheckSV) {
578 auto v0s = recoData.getV0sIdx();
579 auto prpr = [](o2::trackstudy::TrackFamily& f) {
580 std::string s;
581 s += fmt::format(" par {} Ntpccl={} Nitscl={} ", f.mcTrackInfo.pdgParent, f.mcTrackInfo.nTPCCl, f.mcTrackInfo.nITSCl);
582 for (auto& t : f.recTracks) {
583 s += t.gid.asString();
584 s += " ";
585 }
586 return s;
587 };
588 for (int svID; svID < (int)v0s.size(); svID++) {
589 const auto& v0idx = v0s[svID];
590 int nOKProngs = 0, realMCSVID = -1;
591 int8_t decTypeID = -1;
592 for (int ipr = 0; ipr < v0idx.getNProngs(); ipr++) {
593 auto mcl = recoData.getTrackMCLabel(v0idx.getProngID(ipr)); // was this MC particle selected?
594 auto itl = mSelMCTracks.find(mcl);
595 if (itl == mSelMCTracks.end()) {
596 nOKProngs = -1; // was not selected as interesting one, ignore
597 break;
598 }
599 auto& trackFamily = itl->second;
600 int decayParentIndex = trackFamily.mcTrackInfo.parentEntry;
601 if (decayParentIndex < 0) { // does not come from decay
602 break;
603 }
604 if (ipr == 0) {
605 realMCSVID = decayParentIndex;
606 decTypeID = trackFamily.mcTrackInfo.parentDecID;
607 nOKProngs = 1;
608 LOGP(debug, "Prong{} {} comes from {}/{}", ipr, prpr(trackFamily), decTypeID, realMCSVID);
609 continue;
610 }
611 if (realMCSVID != decayParentIndex || decTypeID != trackFamily.mcTrackInfo.parentDecID) {
612 break;
613 }
614 LOGP(debug, "Prong{} {} comes from {}/{}", ipr, prpr(trackFamily), decTypeID, realMCSVID);
615 nOKProngs++;
616 }
617 if (nOKProngs == v0idx.getNProngs()) { // all prongs are from the decay of MC parent which deemed to be interesting, flag it
618 LOGP(debug, "Decay {}/{} was found", decTypeID, realMCSVID);
619 mDecaysMaps[decTypeID][realMCSVID].foundSVID = svID;
620 }
621 }
622 }
623
624 // collect ITS/TPC cluster info for selected MC particles
625 fillMCClusterInfo(recoData);
626
627 // single tracks
628 for (auto& entry : mSelMCTracks) {
629 auto& trackFam = entry.second;
630 (*mDBGOut) << "tracks" << "tr=" << trackFam << "\n";
631 }
632
633 // decays
634 std::vector<TrackFamily> decFam;
635 for (int id = 0; id < mNCheckDecays; id++) {
636 std::string decTreeName = fmt::format("dec{}", params.decayPDG[id]);
637 for (const auto& dec : mDecaysMaps[id]) {
638 decFam.clear();
639 bool skip = false;
640 for (int idd = dec.daughterFirst; idd <= dec.daughterLast; idd++) {
641 auto dtLbl = mDecProdLblPool[idd]; // daughter MC label
642 const auto& dtFamily = mSelMCTracks[dtLbl];
643 if (dtFamily.mcTrackInfo.pdgParent != dec.pdg) {
644 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);
645 skip = true;
646 break;
647 }
648 decFam.push_back(dtFamily);
649 }
650 if (!skip) {
652 if (dec.foundSVID >= 0 && !refitV0(dec.foundSVID, v0, recoData)) {
653 v0.invalidate();
654 }
655 (*mDBGOut) << decTreeName.c_str() << "pdgPar=" << dec.pdg << "trPar=" << dec.parent << "prod=" << decFam << "found=" << dec.foundSVID << "sv=" << v0 << "\n";
656 }
657 }
658 }
659
660 for (auto& mcVtx : mMCVtVec) { // sort rec.vertices in mult. order
661 std::sort(mcVtx.recVtx.begin(), mcVtx.recVtx.end(), [](const RecPV& lhs, const RecPV& rhs) {
662 return lhs.pv.getNContributors() > rhs.pv.getNContributors();
663 });
664 (*mDBGOut) << "mcVtxTree" << "mcVtx=" << mcVtx << "\n";
665 }
666}
667
668void TrackMCStudy::processTPCTrackRefs()
669{
670 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};
671 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};
672 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};
674 for (auto& entry : mSelMCTracks) {
675 auto lb = entry.first;
676 auto trspan = mcReader.getTrackRefs(lb.getSourceID(), lb.getEventID(), lb.getTrackID());
677 int q = entry.second.mcTrackInfo.track.getCharge();
678 if (q * q != 1) {
679 continue;
680 }
681 int ref0entry = mSelTRefs.size(), nrefsSel = 0;
682 for (const auto& trf : trspan) {
683 if (trf.getDetectorId() != 1) { // process TPC only
684 continue;
685 }
686 float pT = std::sqrt(trf.Px() * trf.Px() + trf.Py() * trf.Py());
687 if (pT < 0.05) {
688 continue;
689 }
690 float secX, secY, phi = std::atan2(trf.Y(), trf.X());
691 int sector = o2::math_utils::angle2Sector(phi);
692 o2::math_utils::rotateZInv(trf.X(), trf.Y(), secX, secY, sinAlp[sector], cosAlp[sector]); // sector coordinates
693 float phiPt = std::atan2(trf.Py(), trf.Px());
694 o2::math_utils::bringTo02Pi(phiPt);
695 auto dphiPt = phiPt - alpsec[sector];
696 if (dphiPt > o2::constants::math::PI) { // account for wraps
698 } else if (dphiPt < -o2::constants::math::PI) {
700 } else if (std::abs(dphiPt) > o2::constants::math::PIHalf * 0.8) {
701 continue; // ignore backward going or parallel to padrows tracks
702 }
703 float tgL = trf.Pz() / pT;
704 std::array<float, 5> pars = {secY, trf.Z(), std::sin(dphiPt), tgL, q / pT};
705 auto& refTrack = mSelTRefs.emplace_back(secX, alpsec[sector], pars);
706 refTrack.setUserField(uint16_t(sector));
707 nrefsSel++;
708 }
709 if (nrefsSel < params.minTPCRefsToExtractClRes) {
710 mSelTRefs.resize(ref0entry); // discard unused tracks
711 continue;
712 } else {
713 mSelTRefIdx[lb] = std::make_pair(ref0entry, ref0entry + nrefsSel);
714 }
715 }
716}
717
718void TrackMCStudy::fillMCClusterInfo(const o2::globaltracking::RecoContainer& recoData)
719{
720 // TPC clusters info
721 const auto& TPCClusterIdxStruct = recoData.inputsTPCclusters->clusterIndex;
722 const auto* TPCClMClab = recoData.inputsTPCclusters->clusterIndex.clustersMCTruth;
724
725 ClResTPC clRes{};
726 for (uint8_t sector = 0; sector < 36; sector++) {
727 for (uint8_t row = 0; row < 152; row++) {
728 unsigned int offs = TPCClusterIdxStruct.clusterOffset[sector][row];
729 for (unsigned int icl0 = 0; icl0 < TPCClusterIdxStruct.nClusters[sector][row]; icl0++) {
730 const auto labels = TPCClMClab->getLabels(icl0 + offs);
731 int ncontLb = 0; // number of real contrubutors to this label (w/o noise)
732 for (const auto& lbl : labels) {
733 if (!lbl.isValid()) {
734 continue;
735 }
736 ncontLb++;
737 }
738 const auto& clus = TPCClusterIdxStruct.clusters[sector][row][icl0];
739 int tbinH = int(clus.getTime() * mNTPCOccBinLengthInv); // time bin converted to slot of the occ. histo
740 clRes.contTracks.clear();
741 bool doClusRes = (params.minTPCRefsToExtractClRes > 0) && (params.rejectClustersResStat <= 0. || gRandom->Rndm() < params.rejectClustersResStat);
742 for (auto lbl : labels) {
743 bool corrAttach = lbl.isFake(); // was this flagged in the flagTPCClusters called from process ?
744 lbl.setFakeFlag(false);
745 auto entry = mSelMCTracks.find(lbl);
746 if (entry == mSelMCTracks.end()) { // not selected
747 continue;
748 }
749 auto& mctr = entry->second.mcTrackInfo;
750 mctr.nTPCCl++;
751 if (row > mctr.maxTPCRow) {
752 mctr.maxTPCRow = row;
753 mctr.maxTPCRowSect = sector;
754 mctr.nUsedPadRows++;
755 } else if (row == 0 && mctr.nUsedPadRows == 0) {
756 mctr.nUsedPadRows++;
757 }
758 if (row < mctr.minTPCRow) {
759 mctr.minTPCRow = row;
760 mctr.minTPCRowSect = sector;
761 }
762 if (mctr.minTPCRowSect == sector && row > mctr.maxTPCRowInner) {
763 mctr.maxTPCRowInner = row;
764 }
765 if (ncontLb > 1) {
766 mctr.nTPCClShared++;
767 }
768 // try to extract ideal track position
769 if (doClusRes) {
770 auto entTRefIDsIt = mSelTRefIdx.find(lbl);
771 if (entTRefIDsIt == mSelTRefIdx.end()) {
772 continue;
773 }
774 float xc, yc, zc;
775 mTPCCorrMapsLoader.Transform(sector, row, clus.getPad(), clus.getTime(), xc, yc, zc, mctr.bcInTF / 8.); // nominal time of the track
776
777 const auto& entTRefIDs = entTRefIDsIt->second;
778 // find bracketing TRef params
779 int entIDBelow = -1, entIDAbove = -1;
780 float xBelow = -1e6, xAbove = 1e6;
781
782 for (int entID = entTRefIDs.first; entID < entTRefIDs.second; entID++) {
783 const auto& refTr = mSelTRefs[entID];
784 if (refTr.getUserField() != sector % 18) {
785 continue;
786 }
787 if ((refTr.getX() < xc) && (refTr.getX() > xBelow) && (refTr.getX() > xc - params.maxTPCRefExtrap)) {
788 xBelow = refTr.getX();
789 entIDBelow = entID;
790 }
791 if ((refTr.getX() > xc) && (refTr.getX() < xAbove) && (refTr.getX() < xc + params.maxTPCRefExtrap)) {
792 xAbove = refTr.getX();
793 entIDAbove = entID;
794 }
795 }
796 if ((entIDBelow < 0 && entIDAbove < 0) || (params.requireTopBottomRefs && (entIDBelow < 0 || entIDAbove < 0))) {
797 continue;
798 }
799 auto prop = o2::base::Propagator::Instance();
800 o2::track::TrackPar tparAbove, tparBelow;
801 bool okBelow = entIDBelow >= 0 && prop->PropagateToXBxByBz((tparBelow = mSelTRefs[entIDBelow]), xc, 0.99, 2.);
802 bool okAbove = entIDAbove >= 0 && prop->PropagateToXBxByBz((tparAbove = mSelTRefs[entIDAbove]), xc, 0.99, 2.);
803 if ((!okBelow && !okAbove) || (params.requireTopBottomRefs && (!okBelow || !okAbove))) {
804 continue;
805 }
806
807 int nmeas = 0;
808 auto& clCont = clRes.contTracks.emplace_back();
809 clCont.corrAttach = corrAttach;
810 if (okBelow) {
811 clCont.below = {mSelTRefs[entIDBelow].getX(), tparBelow.getY(), tparBelow.getZ()};
812 clCont.snp += tparBelow.getSnp();
813 clCont.tgl += tparBelow.getTgl();
814 clCont.q2pt += tparBelow.getQ2Pt();
815 nmeas++;
816 }
817 if (okAbove) {
818 clCont.above = {mSelTRefs[entIDAbove].getX(), tparAbove.getY(), tparAbove.getZ()};
819 clCont.snp += tparAbove.getSnp();
820 clCont.tgl += tparAbove.getTgl();
821 clCont.q2pt += tparAbove.getQ2Pt();
822 nmeas++;
823 }
824 if (nmeas) {
825 if (clRes.contTracks.size() == 1) {
826 int occBin = mctr.bcInTF / 8 * mNTPCOccBinLengthInv;
827 clRes.occ = occBin < 0 ? mTBinClOcc[0] : (occBin >= mTBinClOcc.size() ? mTBinClOcc.back() : mTBinClOcc[occBin]);
828 }
829 clCont.xyz = {xc, yc, zc};
830 if (nmeas > 1) {
831 clCont.snp *= 0.5;
832 clCont.tgl *= 0.5;
833 clCont.q2pt *= 0.5;
834 }
835 } else {
836 clRes.contTracks.pop_back();
837 }
838 }
839 }
840 if (clRes.getNCont()) {
841 clRes.sect = sector;
842 clRes.row = row;
843 clRes.qtot = clus.getQtot();
844 clRes.qmax = clus.getQmax();
845 clRes.flags = clus.getFlags();
846 clRes.sigmaTimePacked = clus.sigmaTimePacked;
847 clRes.sigmaPadPacked = clus.sigmaPadPacked;
848 clRes.ncont = ncontLb;
849 clRes.sortCont();
850
851 if (tbinH < 0) {
852 tbinH = 0;
853 } else if (tbinH >= int(mTBinClOccHist.size())) {
854 tbinH = (int)mTBinClOccHist.size() - 1;
855 }
856 clRes.occBin = mTBinClOccHist[tbinH];
857
858 (*mDBGOut) << "clres" << "clr=" << clRes << "\n";
859 }
860 }
861 }
862 }
863 // fill ITS cluster info
864 const auto* mcITSClusters = recoData.getITSClustersMCLabels();
865 const auto& ITSClusters = recoData.getITSClusters();
866 for (unsigned int icl = 0; icl < ITSClusters.size(); icl++) {
867 const auto labels = mcITSClusters->getLabels(icl);
868 for (const auto& lbl : labels) {
869 auto entry = mSelMCTracks.find(lbl);
870 if (entry == mSelMCTracks.end()) { // not selected
871 continue;
872 }
873 auto& mctr = entry->second.mcTrackInfo;
874 mctr.nITSCl++;
875 mctr.pattITSCl |= 0x1 << o2::itsmft::ChipMappingITS::getLayer(ITSClusters[icl].getChipID());
876 }
877 }
878}
879
880bool TrackMCStudy::propagateToRefX(o2::track::TrackParCov& trcTPC, o2::track::TrackParCov& trcITS)
881{
882 bool refReached = false;
883 constexpr float TgHalfSector = 0.17632698f;
885 int trialsLeft = 2;
886 while (o2::base::Propagator::Instance()->PropagateToXBxByBz(trcTPC, par.XMatchingRef, MaxSnp, 2., par.matCorr)) {
887 if (refReached) {
888 break;
889 }
890 // make sure the track is indeed within the sector defined by alpha
891 if (fabs(trcTPC.getY()) < par.XMatchingRef * TgHalfSector) {
892 refReached = true;
893 break; // ok, within
894 }
895 if (!trialsLeft--) {
896 break;
897 }
898 auto alphaNew = o2::math_utils::angle2Alpha(trcTPC.getPhiPos());
899 if (!trcTPC.rotate(alphaNew) != 0) {
900 break; // failed (RS: check effect on matching tracks to neighbouring sector)
901 }
902 }
903 if (!refReached) {
904 return false;
905 }
906 refReached = false;
907 float alp = trcTPC.getAlpha();
908 if (!trcITS.rotate(alp) != 0 || !o2::base::Propagator::Instance()->PropagateToXBxByBz(trcITS, par.XMatchingRef, MaxSnp, 2., par.matCorr)) {
909 return false;
910 }
911 return true;
912}
913
914void TrackMCStudy::endOfStream(EndOfStreamContext& ec)
915{
916 mDBGOut.reset();
917}
918
919void TrackMCStudy::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj)
920{
921 if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) {
922 return;
923 }
924 if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) {
925 return;
926 }
927 if (mTPCCorrMapsLoader.accountCCDBInputs(matcher, obj)) {
928 return;
929 }
930 if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) {
931 LOG(info) << "ITS Alpide param updated";
933 par.printKeyValues();
934 mITSTimeBiasMUS = par.roFrameBiasInBC * o2::constants::lhc::LHCBunchSpacingNS * 1e-3;
935 mITSROFrameLengthMUS = par.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS * 1e-3;
936 return;
937 }
938}
939
940//_____________________________________________________
941void TrackMCStudy::prepareITSData(const o2::globaltracking::RecoContainer& recoData)
942{
943 const auto ITSTracksArray = recoData.getITSTracks();
944 const auto ITSTrackROFRec = recoData.getITSTracksROFRecords();
945 int nROFs = ITSTrackROFRec.size();
946 mITSROF.clear();
947 mITSROFBracket.clear();
948 mITSROF.reserve(ITSTracksArray.size());
949 mITSROFBracket.reserve(ITSTracksArray.size());
950 for (int irof = 0; irof < nROFs; irof++) {
951 const auto& rofRec = ITSTrackROFRec[irof];
952 long nBC = rofRec.getBCData().differenceInBC(recoData.startIR);
953 float tMin = nBC * o2::constants::lhc::LHCBunchSpacingMUS + mITSTimeBiasMUS;
954 float tMax = tMin + mITSROFrameLengthMUS;
955 mITSROFBracket.emplace_back(tMin, tMax);
956 for (int it = 0; it < rofRec.getNEntries(); it++) {
957 mITSROF.push_back(irof);
958 }
959 }
960}
961/*
962float TrackMCStudy::getDCAYCut(float pt) const
963{
964 static TF1 fun("dcayvspt", mDCAYFormula.c_str(), 0, 20);
965 return fun.Eval(pt);
966}
967*/
968
969bool TrackMCStudy::processMCParticle(int src, int ev, int trid)
970{
971 const auto& mcPart = mCurrMCTracks[trid];
972 int pdg = mcPart.GetPdgCode();
973 bool res = false;
974 while (true) {
975 auto lbl = o2::MCCompLabel(trid, ev, src);
976 int decay = -1; // is this decay to watch?
978 if (mcPart.T() < params.decayMotherMaxT) {
979 for (int id = 0; id < mNCheckDecays; id++) {
980 if (params.decayPDG[id] == std::abs(pdg)) {
981 decay = id;
982 break;
983 }
984 }
985 if (decay >= 0) { // check if decay and kinematics is acceptable
986 auto& decayPool = mDecaysMaps[decay];
987 int idd0 = mcPart.getFirstDaughterTrackId(), idd1 = mcPart.getLastDaughterTrackId(); // we want only charged and trackable daughters
988 int dtStart = mDecProdLblPool.size(), dtEnd = -1;
989 if (idd0 < 0) {
990 break;
991 }
992 for (int idd = idd0; idd <= idd1; idd++) {
993 const auto& product = mCurrMCTracks[idd];
994 auto lbld = o2::MCCompLabel(idd, ev, src);
995 if (!acceptMCCharged(product, lbld, decay)) {
996 decay = -1; // discard decay
997 mDecProdLblPool.resize(dtStart);
998 break;
999 }
1000 mDecProdLblPool.push_back(lbld); // register prong entry and label
1001 }
1002 if (decay >= 0) {
1003 // account decay
1004 dtEnd = mDecProdLblPool.size();
1005 for (int dtid = dtStart; dtid < dtEnd; dtid++) { // flag selected decay parent entry in the prongs MCs
1006 mSelMCTracks[mDecProdLblPool[dtid]].mcTrackInfo.parentEntry = decayPool.size();
1007 mSelMCTracks[mDecProdLblPool[dtid]].mcTrackInfo.parentDecID = int8_t(decay);
1008 }
1009 dtEnd--;
1010 std::array<float, 3> xyz{(float)mcPart.GetStartVertexCoordinatesX(), (float)mcPart.GetStartVertexCoordinatesY(), (float)mcPart.GetStartVertexCoordinatesZ()};
1011 std::array<float, 3> pxyz{(float)mcPart.GetStartVertexMomentumX(), (float)mcPart.GetStartVertexMomentumY(), (float)mcPart.GetStartVertexMomentumZ()};
1012 decayPool.emplace_back(DecayRef{lbl,
1013 o2::track::TrackPar(xyz, pxyz, TMath::Nint(O2DatabasePDG::Instance()->GetParticle(mcPart.GetPdgCode())->Charge() / 3), false),
1014 mcPart.GetPdgCode(), dtStart, dtEnd});
1015 if (mVerbose > 1) {
1016 LOGP(info, "Adding MC parent pdg={} {}, with prongs in {}:{} range", pdg, lbl.asString(), dtStart, dtEnd);
1017 }
1018 res = true; // Accept!
1019 }
1020 break;
1021 }
1022 }
1023 // check if this is a charged which should be processed but was not accounted as a decay product
1024 if (mSelMCTracks.find(lbl) == mSelMCTracks.end()) {
1025 res = acceptMCCharged(mcPart, lbl);
1026 }
1027 break;
1028 }
1029 return res;
1030}
1031
1032bool TrackMCStudy::acceptMCCharged(const MCTrack& tr, const o2::MCCompLabel& lb, int followDecay)
1033{
1035 if (tr.GetPt() < params.minPtMC ||
1036 std::abs(tr.GetTgl()) > params.maxTglMC ||
1037 tr.R2() > params.maxRMC * params.maxRMC) {
1038 if (mVerbose > 1 && followDecay > -1) {
1039 LOGP(info, "rejecting decay {} prong : pdg={}, pT={}, tgL={}, r={}", followDecay, tr.GetPdgCode(), tr.GetPt(), tr.GetTgl(), std::sqrt(tr.R2()));
1040 }
1041 return false;
1042 }
1043 float dx = tr.GetStartVertexCoordinatesX() - mCurrMCVertex.X(), dy = tr.GetStartVertexCoordinatesY() - mCurrMCVertex.Y(), dz = tr.GetStartVertexCoordinatesZ() - mCurrMCVertex.Z();
1044 float r2 = dx * dx + dy * dy;
1045 float posTgl2 = r2 > 1 && std::abs(dz) < 20 ? dz * dz / r2 : 0;
1046 if (posTgl2 > params.maxPosTglMC * params.maxPosTglMC) {
1047 if (mVerbose > 1 && followDecay > -1) {
1048 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));
1049 }
1050 return false;
1051 }
1052 if (params.requireITSorTPCTrackRefs) {
1053 auto trspan = mcReader.getTrackRefs(lb.getSourceID(), lb.getEventID(), lb.getTrackID());
1054 bool ok = false;
1055 for (const auto& trf : trspan) {
1056 if (trf.getDetectorId() == DetID::ITS || trf.getDetectorId() == DetID::TPC) {
1057 ok = true;
1058 break;
1059 }
1060 }
1061 if (!ok) {
1062 return false;
1063 }
1064 }
1065 TParticlePDG* pPDG = O2DatabasePDG::Instance()->GetParticle(tr.GetPdgCode());
1066 if (!pPDG) {
1067 LOGP(debug, "Unknown particle {}", tr.GetPdgCode());
1068 return false;
1069 }
1070 if (pPDG->Charge() == 0.) {
1071 return false;
1072 }
1073 return addMCParticle(tr, lb, pPDG);
1074}
1075
1076bool TrackMCStudy::addMCParticle(const MCTrack& mcPart, const o2::MCCompLabel& lb, TParticlePDG* pPDG)
1077{
1078 std::array<float, 3> xyz{(float)mcPart.GetStartVertexCoordinatesX(), (float)mcPart.GetStartVertexCoordinatesY(), (float)mcPart.GetStartVertexCoordinatesZ()};
1079 std::array<float, 3> pxyz{(float)mcPart.GetStartVertexMomentumX(), (float)mcPart.GetStartVertexMomentumY(), (float)mcPart.GetStartVertexMomentumZ()};
1080 if (!pPDG && !(pPDG = O2DatabasePDG::Instance()->GetParticle(mcPart.GetPdgCode()))) {
1081 LOGP(debug, "Unknown particle {}", mcPart.GetPdgCode());
1082 return false;
1083 }
1084 auto& mcEntry = mSelMCTracks[lb];
1085 mcEntry.mcTrackInfo.pdg = mcPart.GetPdgCode();
1086 mcEntry.mcTrackInfo.track = o2::track::TrackPar(xyz, pxyz, TMath::Nint(pPDG->Charge() / 3), true);
1087 mcEntry.mcTrackInfo.label = lb;
1088 mcEntry.mcTrackInfo.bcInTF = mIntBC[lb.getEventID()];
1089 mcEntry.mcTrackInfo.occTPC = mTPCOcc[lb.getEventID()];
1090 mcEntry.mcTrackInfo.occITS = mITSOcc[lb.getEventID()];
1091 int moth = -1;
1092 o2::MCCompLabel mclbPar;
1093 if ((moth = mcPart.getMotherTrackId()) >= 0) {
1094 const auto& mcPartPar = mCurrMCTracks[moth];
1095 mcEntry.mcTrackInfo.pdgParent = mcPartPar.GetPdgCode();
1096 }
1097 if (mcPart.isPrimary() && mcReader.getNEvents(lb.getSourceID()) == mMCVtVec.size()) {
1098 mMCVtVec[lb.getEventID()].nTrackSel++;
1099 }
1100 if (mVerbose > 1) {
1101 LOGP(info, "Adding charged MC pdg={} {} ", mcPart.GetPdgCode(), lb.asString());
1102 }
1103 return true;
1104}
1105
1106bool TrackMCStudy::refitV0(int i, o2::dataformats::V0& v0, const o2::globaltracking::RecoContainer& recoData)
1107{
1108 const auto& id = recoData.getV0sIdx()[i];
1109 auto seedP = recoData.getTrackParam(id.getProngID(0));
1110 auto seedN = recoData.getTrackParam(id.getProngID(1));
1111 bool isTPConly = (id.getProngID(0).getSource() == GTrackID::TPC) || (id.getProngID(1).getSource() == GTrackID::TPC);
1112 const auto& svparam = o2::vertexing::SVertexerParams::Instance();
1113 if (svparam.mTPCTrackPhotonTune && isTPConly) {
1114 mFitterV0.setMaxDZIni(svparam.mTPCTrackMaxDZIni);
1115 mFitterV0.setMaxDXYIni(svparam.mTPCTrackMaxDXYIni);
1116 mFitterV0.setMaxChi2(svparam.mTPCTrackMaxChi2);
1117 mFitterV0.setCollinear(true);
1118 }
1119 int nCand = mFitterV0.process(seedP, seedN);
1120 if (svparam.mTPCTrackPhotonTune && isTPConly) { // restore
1121 // Reset immediately to the defaults
1122 mFitterV0.setMaxDZIni(svparam.maxDZIni);
1123 mFitterV0.setMaxDXYIni(svparam.maxDXYIni);
1124 mFitterV0.setMaxChi2(svparam.maxChi2);
1125 mFitterV0.setCollinear(false);
1126 }
1127 if (nCand == 0) { // discard this pair
1128 return false;
1129 }
1130 const int cand = 0;
1131 if (!mFitterV0.isPropagateTracksToVertexDone(cand) && !mFitterV0.propagateTracksToVertex(cand)) {
1132 return false;
1133 }
1134 const auto& trPProp = mFitterV0.getTrack(0, cand);
1135 const auto& trNProp = mFitterV0.getTrack(1, cand);
1136 std::array<float, 3> pP{}, pN{};
1137 trPProp.getPxPyPzGlo(pP);
1138 trNProp.getPxPyPzGlo(pN);
1139 std::array<float, 3> pV0 = {pP[0] + pN[0], pP[1] + pN[1], pP[2] + pN[2]};
1140 auto p2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1] + pV0[2] * pV0[2];
1141 const auto& pv = recoData.getPrimaryVertex(id.getVertexID());
1142 const auto v0XYZ = mFitterV0.getPCACandidatePos(cand);
1143 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];
1144 float cosPA = prodXYZv0 / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0);
1145 new (&v0) o2::dataformats::V0(v0XYZ, pV0, mFitterV0.calcPCACovMatrixFlat(cand), trPProp, trNProp);
1146 v0.setDCA(mFitterV0.getChi2AtPCACandidate(cand));
1147 v0.setCosPA(cosPA);
1148 return true;
1149}
1150
1151void TrackMCStudy::loadTPCOccMap(const o2::globaltracking::RecoContainer& recoData)
1152{
1153 auto NHBPerTF = o2::base::GRPGeomHelper::instance().getGRPECS()->getNHBFPerTF();
1154 const auto& TPCOccMap = recoData.occupancyMapTPC;
1155 auto prop = o2::base::Propagator::Instance();
1156 auto TPCRefitter = std::make_unique<o2::gpu::GPUO2InterfaceRefit>(&recoData.inputsTPCclusters->clusterIndex, &mTPCCorrMapsLoader, prop->getNominalBz(),
1157 recoData.getTPCTracksClusterRefs().data(), 0, recoData.clusterShMapTPC.data(), TPCOccMap.data(), TPCOccMap.size(), nullptr, prop);
1158 mNTPCOccBinLength = TPCRefitter->getParam()->rec.tpc.occupancyMapTimeBins;
1159 mTBinClOcc.clear();
1160 if (mNTPCOccBinLength > 1 && TPCOccMap.size()) {
1161 mNTPCOccBinLengthInv = 1. / mNTPCOccBinLength;
1162 int nTPCBins = NHBPerTF * o2::constants::lhc::LHCMaxBunches / 8, ninteg = 0;
1163 int nTPCOccBins = nTPCBins * mNTPCOccBinLengthInv, sumBins = std::max(1, int(o2::constants::lhc::LHCMaxBunches / 8 * mNTPCOccBinLengthInv));
1164 mTBinClOcc.resize(nTPCOccBins);
1165 mTBinClOccHist.resize(nTPCOccBins);
1166 float sm = 0., tb = 0.5 * mNTPCOccBinLength;
1167 for (int i = 0; i < nTPCOccBins; i++) {
1168 mTBinClOccHist[i] = TPCRefitter->getParam()->GetUnscaledMult(tb);
1169 tb += mNTPCOccBinLength;
1170 }
1171 for (int i = nTPCOccBins; i--;) {
1172 sm += mTBinClOccHist[i];
1173 if (i + sumBins < nTPCOccBins) {
1174 sm -= mTBinClOccHist[i + sumBins];
1175 }
1176 mTBinClOcc[i] = sm;
1177 }
1178 } else {
1179 mTBinClOcc.resize(1);
1180 mTBinClOccHist.resize(1);
1181 }
1182}
1183
1185{
1186 std::vector<OutputSpec> outputs;
1187 Options opts{
1188 {"device-verbosity", VariantType::Int, 0, {"Verbosity level"}},
1189 {"dcay-vs-pt", VariantType::String, "0.0105 + 0.0350 / pow(x, 1.1)", {"Formula for global tracks DCAy vs pT cut"}},
1190 {"min-tpc-clusters", VariantType::Int, 60, {"Cut on TPC clusters"}},
1191 {"max-tpc-dcay", VariantType::Float, 2.f, {"Cut on TPC dcaY"}},
1192 {"max-tpc-dcaz", VariantType::Float, 2.f, {"Cut on TPC dcaZ"}},
1193 {"min-x-prop", VariantType::Float, 6.f, {"track should be propagated to this X at least"}}};
1194 auto dataRequest = std::make_shared<DataRequest>();
1195 bool useMC = true;
1196 dataRequest->requestTracks(srcTracks, useMC);
1197 dataRequest->requestClusters(srcClusters, useMC);
1198 dataRequest->requestPrimaryVertices(useMC);
1199 if (checkSV) {
1200 dataRequest->requestSecondaryVertices(useMC);
1201 }
1202 o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs);
1203 o2::tpc::CorrectionMapsLoader::requestCCDBInputs(dataRequest->inputs, opts, sclOpts);
1204 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(false, // orbitResetTime
1205 true, // GRPECS=true
1206 true, // GRPLHCIF
1207 true, // GRPMagField
1208 true, // askMatLUT
1210 dataRequest->inputs,
1211 true);
1212
1213 return DataProcessorSpec{
1214 "track-mc-study",
1215 dataRequest->inputs,
1216 outputs,
1217 AlgorithmSpec{adaptFromTask<TrackMCStudy>(dataRequest, ggRequest, srcTracks, sclOpts, checkSV)},
1218 opts};
1219}
1220
1221} // namespace o2::trackstudy
Helper class to access load maps from CCDB.
Defintions for N-prongs secondary vertex fit.
Wrapper container for different reconstructed object types.
Definition of the GeometryManager class.
Definition of the FIT RecPoints class.
int32_t i
ITSClusters
Helper for geometry and GRP related CCDB requests.
Global index for barrel track: provides provenance (detectors combination), index in respective array...
Utility functions for MC particles.
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 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.
Result of refitting TPC-ITS matched track.
Reference on ITS/MFT clusters set.
Helper class to extract VDrift from different sources.
std::ostringstream debug
Referenc on track indices contributing to the vertex, with possibility chose tracks from specific sou...
bool isFake() const
Definition MCCompLabel.h:78
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:143
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 TPC
Definition DetID.h:64
ConfigParamRegistry const & options()
Definition InitContext.h:33
static constexpr int getLayer(int chipSW)
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
void extractCCDBInputs(o2::framework::ProcessingContext &pc)
void updateVDrift(float vdriftCorr, float vdrifRef, float driftTimeOffset=0)
static void requestCCDBInputs(std::vector< o2::framework::InputSpec > &inputs, std::vector< o2::framework::ConfigParamSpec > &options, const CorrectionMapsLoaderGloOpts &gloOpts)
recalculate inverse correction
void init(o2::framework::InitContext &ic)
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
static std::string_view getSourceName(Source s)
bool isUpdated() const
TrackMCStudy(std::shared_ptr< DataRequest > dr, std::shared_ptr< o2::base::GRPGeomRequest > gr, GTrackID::mask_t src, const o2::tpc::CorrectionMapsLoaderGloOpts &sclOpts, bool checkSV)
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() 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
constexpr double LHCBunchSpacingMUS
constexpr int LHCMaxBunches
constexpr double LHCBunchSpacingNS
constexpr float TwoPI
constexpr float PI
constexpr float PIHalf
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::vector< ConfigParamSpec > Options
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::framework::DataProcessorSpec getTrackMCStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, const o2::tpc::CorrectionMapsLoaderGloOpts &sclOpts, bool checkSV)
create a processor spec
o2::dataformats::VtxTrackIndex VTIndex
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
GlobalIDSet getSingleDetectorRefs(GTrackID gidx) const
const o2::tpc::TrackTPC & getTPCTrack(GTrackID id) const
o2::MCCompLabel getTrackMCLabel(GTrackID id) 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
int lumiType
what estimator to used for corrections scaling: 0: no scaling, 1: CTP, 2: IDC
int lumiMode
what corrections method to use: 0: classical scaling, 1: Using of the derivative map,...
float refTimeOffset
additive time offset reference (\mus)
float refVDrift
reference vdrift for which factor was extracted
float getTimeOffset() const
float timeOffsetCorr
additive time offset correction (\mus)
float corrFact
drift velocity correction factor (multiplicative)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< int > row