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