Project
Loading...
Searching...
No Matches
TPCTimeSeriesSpec.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
16
17#include "Framework/Task.h"
18#include "Framework/Logger.h"
24#include "TPCBase/Mapper.h"
32#include "MathUtils/Tsallis.h"
33#include "MathUtils/Utils.h"
41#include <random>
42#include <chrono>
50#include "TROOT.h"
57
58using namespace o2::globaltracking;
62using namespace o2::framework;
63
64namespace o2
65{
66namespace tpc
67{
68
69class TPCTimeSeries : public Task
70{
71 public:
74 uint8_t trdPattern = 0;
75 uint8_t nTRDTracklets = 0;
76 int trackletIndices[6] = {-1, -1, -1, -1, -1, -1};
77 o2::track::TrackParCov trdTrackParCov; // TRD track state for propagation to the common local X = 275 cm plane
78 bool hasTRDTrackPar = false;
79 };
80
84 static float chi2Match_Phi(const o2::track::TrackParCov& trk1, const o2::track::TrackParCov& trk2)
85 {
86 float d0 = trk1.getY() - trk2.getY();
87 float d1 = trk1.getSnp() - trk2.getSnp();
88 float d2 = trk1.getQ2Pt() - trk2.getQ2Pt();
89 // Combined covariance C = C1 + C2
90 float c00 = trk1.getSigmaY2() + trk2.getSigmaY2();
91 float c01 = trk1.getSigmaSnpY() + trk2.getSigmaSnpY();
92 float c02 = trk1.getSigma1PtY() + trk2.getSigma1PtY();
93 float c11 = trk1.getSigmaSnp2() + trk2.getSigmaSnp2();
94 float c12 = trk1.getSigma1PtSnp() + trk2.getSigma1PtSnp();
95 float c22 = trk1.getSigma1Pt2() + trk2.getSigma1Pt2();
96 float det = c00 * (c11 * c22 - c12 * c12) - c01 * (c01 * c22 - c12 * c02) + c02 * (c01 * c12 - c11 * c02);
97 if (std::abs(det) < 1e-30f) {
98 return -1.f;
99 }
100 float detInv = 1.f / det;
101 float i00 = (c11 * c22 - c12 * c12) * detInv;
102 float i01 = (c02 * c12 - c01 * c22) * detInv;
103 float i02 = (c01 * c12 - c02 * c11) * detInv;
104 float i11 = (c00 * c22 - c02 * c02) * detInv;
105 float i12 = (c01 * c02 - c00 * c12) * detInv;
106 float i22 = (c00 * c11 - c01 * c01) * detInv;
107 return d0 * (i00 * d0 + i01 * d1 + i02 * d2) + d1 * (i01 * d0 + i11 * d1 + i12 * d2) + d2 * (i02 * d0 + i12 * d1 + i22 * d2);
108 }
109
113 static float chi2Match_Z(const o2::track::TrackParCov& trk1, const o2::track::TrackParCov& trk2)
114 {
115 float d0 = trk1.getZ() - trk2.getZ();
116 float d1 = trk1.getTgl() - trk2.getTgl();
117 float c00 = trk1.getSigmaZ2() + trk2.getSigmaZ2();
118 float c01 = trk1.getSigmaTglZ() + trk2.getSigmaTglZ();
119 float c11 = trk1.getSigmaTgl2() + trk2.getSigmaTgl2();
120 float det = c00 * c11 - c01 * c01;
121 if (std::abs(det) < 1e-30f) {
122 return -1.f;
123 }
124 float detInv = 1.f / det;
125 return (d0 * d0 * c11 - 2.f * d0 * d1 * c01 + d1 * d1 * c00) * detInv;
126 }
127
129 TPCTimeSeries(std::shared_ptr<o2::base::GRPGeomRequest> req, const bool disableWriter, const o2::base::Propagator::MatCorrType matType, const bool enableUnbinnedWriter, const bool tpcOnly, std::shared_ptr<o2::globaltracking::DataRequest> dr) : mCCDBRequest(req), mDisableWriter(disableWriter), mMatType(matType), mUnbinnedWriter(enableUnbinnedWriter), mTPCOnly(tpcOnly), mDataRequest(dr) {};
130
132 {
134 mNMaxTracks = ic.options().get<int>("max-tracks");
135 mMinMom = ic.options().get<float>("min-momentum");
136 mMinNCl = ic.options().get<int>("min-cluster");
137 mMaxTgl = ic.options().get<float>("max-tgl");
138 mMaxQPt = ic.options().get<float>("max-qPt");
139 mCoarseStep = ic.options().get<float>("coarse-step");
140 mFineStep = ic.options().get<float>("fine-step");
141 mCutDCA = ic.options().get<float>("cut-DCA-median");
142 mCutRMS = ic.options().get<float>("cut-DCA-RMS");
143 mRefXSec = ic.options().get<float>("refX-for-sector");
144 mTglBins = ic.options().get<int>("tgl-bins");
145 mPhiBins = ic.options().get<int>("phi-bins");
146 mQPtBins = ic.options().get<int>("qPt-bins");
147 mNThreads = ic.options().get<int>("threads");
148 maxITSTPCDCAr = ic.options().get<float>("max-ITS-TPC-DCAr");
149 maxITSTPCDCAz = ic.options().get<float>("max-ITS-TPC-DCAz");
150 maxITSTPCDCAr_comb = ic.options().get<float>("max-ITS-TPC-DCAr_comb");
151 maxITSTPCDCAz_comb = ic.options().get<float>("max-ITS-TPC-DCAz_comb");
152 mTimeWindowMUS = ic.options().get<float>("time-window-mult-mus");
153 mMIPdEdx = ic.options().get<float>("MIP-dedx");
154 mMaxSnp = ic.options().get<float>("max-snp");
155 mXCoarse = ic.options().get<float>("mX-coarse");
156 mSqrt = ic.options().get<float>("sqrts");
157 mMultBins = ic.options().get<int>("mult-bins");
158 mMultMax = ic.options().get<int>("mult-max");
159 mMinTracksPerVertex = ic.options().get<int>("min-tracks-per-vertex");
160 mMaxdEdxRatio = ic.options().get<float>("max-dedx-ratio");
161 mMaxdEdxRegionRatio = ic.options().get<float>("max-dedx-region-ratio");
162 mSamplingFactor = ic.options().get<float>("sampling-factor");
163 mSampleTsallis = ic.options().get<bool>("sample-unbinned-tsallis");
164 mXOuterMatching = ic.options().get<float>("refX-for-outer-ITS");
165 mUseMinBiasTrigger = !ic.options().get<bool>("disable-min-bias-trigger");
166 mMaxOccupancyHistBins = ic.options().get<int>("max-occupancy-bins");
167 mStoreFullTrackPar = ic.options().get<bool>("store-full-trackpar");
168
169 if (mUnbinnedWriter) {
170 for (int iThread = 0; iThread < mNThreads; ++iThread) {
171 mGenerator.emplace_back(std::mt19937(std::random_device{}()));
172 }
173 }
174 mBufferVals.resize(mNThreads);
175 mBufferDCA.setBinning(mPhiBins, mTglBins, mQPtBins, mMultBins, mMaxTgl, mMaxQPt, mMultMax);
176 if (mUnbinnedWriter) {
177 std::string outfile = ic.options().get<std::string>("out-file-unbinned");
178 if (mNThreads > 1) {
179 ROOT::EnableThreadSafety();
180 }
181 mStreamer.resize(mNThreads);
182 for (int iThread = 0; iThread < mNThreads; ++iThread) {
183 std::string outfileThr = outfile;
184 outfileThr.replace(outfileThr.length() - 5, outfileThr.length(), fmt::format("_{}.root", iThread));
185 LOGP(info, "Writing unbinned data to: {}", outfileThr);
186 mStreamer[iThread] = std::make_unique<o2::utils::TreeStreamRedirector>(outfileThr.data(), "recreate");
187 }
188 }
189 }
190
191 void run(ProcessingContext& pc) final
192 {
194 // run-level TRD readout flag from GRPECS (unbinned output only): 1 = TRD in readout, 0 = not in readout,
195 // 255 = unknown (defensive: GRPECS is requested only with the unbinned writer)
196 mTRDInReadout = 255;
197 if (mUnbinnedWriter) {
198 const auto* grpecs = o2::base::GRPGeomHelper::instance().getGRPECS();
199 mTRDInReadout = grpecs ? static_cast<uint8_t>(grpecs->isDetReadOut(DetID::TRD) ? 1 : 0) : static_cast<uint8_t>(255);
200 }
201 mTPCVDriftHelper.extractCCDBInputs(pc);
202 mPTHelper.extractCCDBInputs(pc);
203 if (mTPCVDriftHelper.isUpdated()) {
204 mTPCVDriftHelper.acknowledgeUpdate();
205 mVDrift = mTPCVDriftHelper.getVDriftObject().getVDrift();
206 LOGP(info, "Updated reference drift velocity to: {}", mVDrift);
207 }
208 pc.inputs().get<TTree*>("tpcSecFlucInfo");
209 mBufferDCA.mVDrift = mVDrift;
210
211 const int nBins = getNBins();
212
213 mTimeMS = o2::base::GRPGeomHelper::instance().getOrbitResetTimeMS() + processing_helpers::getFirstTForbit(pc) * o2::constants::lhc::LHCOrbitMUS / 1000;
215 mBufferDCA.mSecEdgeFlucCorr = mSecEdgeFlucInfo.getSectorsAtTime(mRun, static_cast<long>(mTimeMS));
216 mBufferDCA.mTemperature = mPTHelper.getMeanTemperature(mTimeMS);
217 mBufferDCA.mPressure = mPTHelper.getPressure(mTimeMS);
218
219 // init only once
220 if (mAvgADCAr.size() != nBins) {
221 mBufferDCA.resize(nBins);
222 mAvgADCAr.resize(nBins);
223 mAvgCDCAr.resize(nBins);
224 mAvgADCAz.resize(nBins);
225 mAvgCDCAz.resize(nBins);
226 mAvgMeffA.resize(nBins);
227 mAvgMeffC.resize(nBins);
228 mAvgChi2MatchA.resize(nBins);
229 mAvgChi2MatchC.resize(nBins);
230 mMIPdEdxRatioQMaxA.resize(nBins);
231 mMIPdEdxRatioQMaxC.resize(nBins);
232 mMIPdEdxRatioQTotA.resize(nBins);
233 mMIPdEdxRatioQTotC.resize(nBins);
234 mTPCChi2A.resize(nBins);
235 mTPCChi2C.resize(nBins);
236 mTPCNClA.resize(nBins);
237 mTPCNClC.resize(nBins);
238 mLogdEdxQTotA.resize(nBins);
239 mLogdEdxQTotC.resize(nBins);
240 mLogdEdxQMaxA.resize(nBins);
241 mLogdEdxQMaxC.resize(nBins);
242 mITSPropertiesA.resize(nBins);
243 mITSPropertiesC.resize(nBins);
244 mITSTPCDeltaPA.resize(nBins);
245 mITSTPCDeltaPC.resize(nBins);
246 mSigmaYZA.resize(nBins);
247 mSigmaYZC.resize(nBins);
248 }
249
250 RecoContainer recoData;
251 recoData.collectData(pc, *mDataRequest.get());
252
253 // getting tracks
254 auto tracksTPC = recoData.getTPCTracks();
255 auto tracksITSTPC = mTPCOnly ? gsl::span<o2::dataformats::TrackTPCITS>() : recoData.getTPCITSTracks();
256 auto tracksITS = mTPCOnly ? gsl::span<o2::its::TrackITS>() : recoData.getITSTracks();
257
258 // getting the vertices
259 auto vertices = mTPCOnly ? gsl::span<o2::dataformats::PrimaryVertex>() : recoData.getPrimaryVertices();
260 auto primMatchedTracks = mTPCOnly ? gsl::span<o2::dataformats::VtxTrackIndex>() : recoData.getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks
261 auto primMatchedTracksRef = mTPCOnly ? gsl::span<o2::dataformats::VtxTrackRef>() : recoData.getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs
262
263 // get occupancy map
264 mBufferDCA.mOccupancyMapTPC = std::vector<unsigned int>(recoData.occupancyMapTPC.begin(), recoData.occupancyMapTPC.end());
265 if (mBufferDCA.mOccupancyMapTPC.size() > mMaxOccupancyHistBins) {
266 mBufferDCA.mOccupancyMapTPC.resize(mMaxOccupancyHistBins);
267 }
268
269 // TOF clusters
270 const auto& tofClusters = mTPCOnly ? gsl::span<o2::tof::Cluster>() : recoData.getTOFClusters();
271
272 LOGP(info, "Processing {} vertices, {} primary matched vertices, {} TPC tracks, {} ITS tracks, {} ITS-TPC tracks, {} TOF clusters", vertices.size(), primMatchedTracks.size(), tracksTPC.size(), tracksITS.size(), tracksITSTPC.size(), tofClusters.size());
273
274 // calculate mean vertex, RMS and count vertices
275 auto indicesITSTPC_vtx = processVertices(vertices, primMatchedTracks, primMatchedTracksRef, recoData);
276
277 // storing indices to ITS-TPC tracks and vertex ID for tpc track
278 std::unordered_map<unsigned int, std::array<int, 2>> indicesITSTPC; // TPC track index -> ITS-TPC track index, vertex ID
279 // loop over all ITS-TPC tracks
280 for (int i = 0; i < tracksITSTPC.size(); ++i) {
281 auto it = indicesITSTPC_vtx.find(i);
282 // check if ITS-TPC track has attached vertex
283 const auto idxVtx = (it != indicesITSTPC_vtx.end()) ? (it->second) : -1;
284 // store TPC index and ITS-TPC+vertex index
285 indicesITSTPC[tracksITSTPC[i].getRefTPC().getIndex()] = {i, idxVtx};
286 }
287
288 std::vector<std::tuple<int, float, float, o2::track::TrackLTIntegral, double, float, unsigned int, unsigned short>> idxTPCTrackToTOFCluster; // store for each tpc track index the index to the TOF cluster
289
290 // get matches to TOF in case skimmed data is produced
291 if (mUnbinnedWriter) {
292 // getLTIntegralOut(), ///< L,TOF integral calculated during the propagation
293 // getSignal() mSignal = 0.0; ///< TOF time in ps
295 idxTPCTrackToTOFCluster = std::vector<std::tuple<int, float, float, o2::track::TrackLTIntegral, double, float, unsigned int, unsigned short>>(tracksTPC.size(), {-1, -999, -999, defLT, 0, 0, 0, 0});
296 const std::vector<gsl::span<const o2::dataformats::MatchInfoTOF>> tofMatches{recoData.getTPCTOFMatches(), recoData.getTPCTRDTOFMatches(), recoData.getITSTPCTOFMatches(), recoData.getITSTPCTRDTOFMatches()};
297
298 const auto& ft0rec = recoData.getFT0RecPoints();
299 // fill available FT0-AC event times vs BClong
300 std::map<ULong64_t, short> t0array;
301 for (const auto& t0 : ft0rec) {
302 if (!(t0.isValidTime(1) && t0.isValidTime(2))) { // skip if !(A & C)
303 continue;
304 }
305
306 auto bclong = t0.mIntRecord.differenceInBC(recoData.startIR);
307 if (t0array.find(bclong) == t0array.end()) { // add if it doesn't exist
308 t0array.emplace(std::make_pair(bclong, t0.getCollisionTime(0)));
309 }
310 }
311
312 static const double BC_TIME_INPS_INV = 1E-3 / o2::constants::lhc::LHCBunchSpacingNS;
313
314 // loop over ITS-TPC-TRD-TOF and ITS-TPC-TOF tracks an store for each ITS-TPC track the TOF track index
315 for (const auto& tofMatch : tofMatches) {
316 for (const auto& tpctofmatch : tofMatch) {
317 auto refTPC = recoData.getTPCContributorGID(tpctofmatch.getTrackRef());
318 if (refTPC.isIndexSet()) {
319 o2::track::TrackLTIntegral ltIntegral = tpctofmatch.getLTIntegralOut();
320 ULong64_t bclongtof = (tpctofmatch.getSignal() - 10000) * BC_TIME_INPS_INV;
321 double t0 = 0; // bclongtof * o2::constants::lhc::LHCBunchSpacingNS * 1E3; // if you want to subtract also the BC uncomment this part (-> tofsignal can be a float)
322 unsigned int mask = 0;
323 if (!(t0array.find(bclongtof) == t0array.end())) { // subtract FT0-AC if it exists in the same BC
324 t0 += t0array.find(bclongtof)->second;
325 mask |= o2::dataformats::MatchInfoTOF::QualityFlags::hasT0sameBC; // 8th bit if FT0-AC in same BC
326 }
327
328 double signal = tpctofmatch.getSignal() - t0;
329 float deltaT = tpctofmatch.getDeltaT();
330
331 float dy = tpctofmatch.getDYatTOF(); // residual orthogonal to the strip (it should be close to zero)
332 bool isMultiHitZ = tpctofmatch.getHitPatternUpDown();
333 bool isMultiHitX = tpctofmatch.getHitPatternLeftRight();
334 bool isMultiStripMatch = tpctofmatch.getChi2() < 1E-9;
335 float chi2 = tpctofmatch.getChi2();
336 bool hasT0_1BCbefore = (t0array.find(bclongtof - 1) != t0array.end());
337 bool hasT0_2BCbefore = (t0array.find(bclongtof - 2) != t0array.end());
338
339 if (isMultiHitX) { // 1nd bit on if multiple hits along X
341 }
342 if (isMultiHitZ) { // 2nd bit on if multiple hits along Z
344 }
345 if (fabs(dy) > 0.5) { // 3rd bit on if Y-residual too large
347 }
348 if (isMultiStripMatch) { // 4th bit on if two strips fired
350 }
351 if (chi2 > 1E-4) { // 5th bit on if chi2 > 1E-4 -> not inside the pad
353 }
354 if (chi2 > 3) { // 6th bit on if chi2 > 3
356 }
357 if (chi2 > 5) { // 7th bit on if chi2 > 5
359 }
360 if (hasT0_1BCbefore) { // 9th bit if FT0-AC also BC before
362 }
363 if (hasT0_2BCbefore) { // 10th bit if FT0-AC also 2BCs before
365 }
366
367 idxTPCTrackToTOFCluster[refTPC] = {tpctofmatch.getIdxTOFCl(), tpctofmatch.getDXatTOF(), tpctofmatch.getDZatTOF(), ltIntegral, signal, deltaT, mask, tpctofmatch.getChannel() % 8736};
368 }
369 }
370 }
371 }
372
373 // find nearest vertex of tracks which have no vertex assigned
374 findNearesVertex(tracksTPC, vertices);
375
376 // D2: build TPC track index → TRD tracklet data map (for unbinned output)
377 // For each TPC track that has a TRD match, store the TrackTRD tracklet indices
378 std::unordered_map<unsigned int, TRDTrackletData> tpcToTRDMap;
379 auto trdTracklets = (mTPCOnly || !recoData.inputsTRD) ? gsl::span<const o2::trd::Tracklet64>() : recoData.getTRDTracklets();
380 auto trdCalibTracklets = (mTPCOnly || !recoData.inputsTRD) ? gsl::span<const o2::trd::CalibratedTracklet>() : recoData.getTRDCalibratedTracklets();
381
382 // TRD-triggered BCs of this TF: TRD is read out only at these BCs. Built once per TF; per entry only the triggers closest
383 // to the collision are stored (trdTrigDBCBefore/After). Records with bc >= LHCMaxBunches are dropped, as in the AOD producer.
384 mTRDTrigBCs.clear();
385 mTRDTrigBCsInTF.clear();
386 if (mUnbinnedWriter && !mTPCOnly && recoData.inputsTRD) {
387 const auto trdTrig = recoData.getTRDTriggerRecords();
388 mTRDTrigBCs.reserve(trdTrig.size());
389 for (const auto& trg : trdTrig) {
390 if (trg.getBCData().bc < o2::constants::lhc::LHCMaxBunches) {
391 mTRDTrigBCs.push_back(trg.getBCData());
392 }
393 }
394 std::sort(mTRDTrigBCs.begin(), mTRDTrigBCs.end());
395 }
396 if (mUnbinnedWriter && !mTPCOnly) {
397 // scan ITS-TPC-TRD tracks
398 auto itstpctrdTracks = recoData.getITSTPCTRDTracks<o2::trd::TrackTRD>();
399 for (unsigned int ig = 0; ig < itstpctrdTracks.size(); ++ig) {
400 auto gid = GTrackID(ig, GTrackID::ITSTPCTRD);
401 auto refTPC = recoData.getTPCContributorGID(gid);
402 if (!refTPC.isIndexSet()) {
403 continue;
404 }
405 auto refTRD = recoData.getSingleDetectorRefs(gid)[GTrackID::TRD];
406 if (!refTRD.isIndexSet()) {
407 continue;
408 }
409 const auto& trdTrack = recoData.getTrack<o2::trd::TrackTRD>(refTRD);
410 TRDTrackletData trdData;
411 for (int iLay = 0; iLay < 6; ++iLay) {
412 auto trkltId = trdTrack.getTrackletIndex(iLay);
413 if (trkltId >= 0) {
414 trdData.trdPattern |= (1 << iLay);
415 trdData.nTRDTracklets++;
416 trdData.trackletIndices[iLay] = trkltId;
417 }
418 }
419 // TRD-out: outer state of the ITS-TPC-TRD track (outward refit through ITS, TPC and TRD, at the outermost TRD layer).
420 // The base state of TrackTRD is the inward refit, which ends at the innermost ITS cluster.
421 trdData.trdTrackParCov = recoData.getTrackParamOut(gid);
422 trdData.hasTRDTrackPar = true;
423 tpcToTRDMap[refTPC] = trdData;
424 }
425 }
426
427 // getting cluster references for cluster bitmask
428 if (mUnbinnedWriter) {
429 mTPCTrackClIdx = pc.inputs().get<gsl::span<o2::tpc::TPCClRefElem>>("trackTPCClRefs");
430 mFirstTFOrbit = processing_helpers::getFirstTForbit(pc);
431 // TRD-triggered BCs as BC numbers from the TF start (orbit mFirstTFOrbit, bc 0), in the order of mTRDTrigBCs (sorted)
432 const o2::InteractionRecord irTFStart(0, mFirstTFOrbit);
433 mTRDTrigBCsInTF.reserve(mTRDTrigBCs.size());
434 for (const auto& ir : mTRDTrigBCs) {
435 mTRDTrigBCsInTF.push_back(static_cast<int>(ir.differenceInBC(irTFStart)));
436 }
437 }
438
439 // get local multiplicity - count neighbouring tracks
440 findNNeighbourTracks(tracksTPC);
441
442 // reset buffers
443 for (int i = 0; i < nBins; ++i) {
444 for (int type = 0; type < mAvgADCAr[i].size(); ++type) {
445 mAvgADCAr[i][type].clear();
446 mAvgCDCAr[i][type].clear();
447 mAvgADCAz[i][type].clear();
448 mAvgCDCAz[i][type].clear();
449 }
450 for (int type = 0; type < mMIPdEdxRatioQMaxA[i].size(); ++type) {
451 mMIPdEdxRatioQMaxA[i][type].clear();
452 mMIPdEdxRatioQMaxC[i][type].clear();
453 mMIPdEdxRatioQTotA[i][type].clear();
454 mMIPdEdxRatioQTotC[i][type].clear();
455 mTPCChi2A[i][type].clear();
456 mTPCChi2C[i][type].clear();
457 mTPCNClA[i][type].clear();
458 mTPCNClC[i][type].clear();
459 mMIPdEdxRatioQMaxA[i][type].setUseWeights(false);
460 mMIPdEdxRatioQMaxC[i][type].setUseWeights(false);
461 mMIPdEdxRatioQTotA[i][type].setUseWeights(false);
462 mMIPdEdxRatioQTotC[i][type].setUseWeights(false);
463 mTPCChi2A[i][type].setUseWeights(false);
464 mTPCChi2C[i][type].setUseWeights(false);
465 mTPCNClA[i][type].setUseWeights(false);
466 mTPCNClC[i][type].setUseWeights(false);
467 }
468 for (int type = 0; type < mLogdEdxQTotA[i].size(); ++type) {
469 mLogdEdxQTotA[i][type].clear();
470 mLogdEdxQTotC[i][type].clear();
471 mLogdEdxQMaxA[i][type].clear();
472 mLogdEdxQMaxC[i][type].clear();
473 mLogdEdxQTotA[i][type].setUseWeights(false);
474 mLogdEdxQTotC[i][type].setUseWeights(false);
475 mLogdEdxQMaxA[i][type].setUseWeights(false);
476 mLogdEdxQMaxC[i][type].setUseWeights(false);
477 }
478 for (int j = 0; j < mITSPropertiesA[i].size(); ++j) {
479 mITSPropertiesA[i][j].clear();
480 mITSPropertiesC[i][j].clear();
481 mITSPropertiesA[i][j].setUseWeights(false);
482 mITSPropertiesC[i][j].setUseWeights(false);
483 }
484
485 for (int j = 0; j < mITSTPCDeltaPA[i].size(); ++j) {
486 mITSTPCDeltaPA[i][j].clear();
487 mITSTPCDeltaPC[i][j].clear();
488 mITSTPCDeltaPA[i][j].setUseWeights(false);
489 mITSTPCDeltaPC[i][j].setUseWeights(false);
490 }
491
492 for (int j = 0; j < mSigmaYZA[i].size(); ++j) {
493 mSigmaYZA[i][j].clear();
494 mSigmaYZC[i][j].clear();
495 mSigmaYZA[i][j].setUseWeights(false);
496 mSigmaYZC[i][j].setUseWeights(false);
497 }
498
499 for (int j = 0; j < mAvgMeffA[i].size(); ++j) {
500 mAvgMeffA[i][j].clear();
501 mAvgMeffC[i][j].clear();
502 mAvgChi2MatchA[i][j].clear();
503 mAvgChi2MatchC[i][j].clear();
504 mAvgMeffA[i][j].setUseWeights(false);
505 mAvgMeffC[i][j].setUseWeights(false);
506 mAvgChi2MatchA[i][j].setUseWeights(false);
507 mAvgChi2MatchC[i][j].setUseWeights(false);
508 }
509 }
510
511 for (int i = 0; i < mNThreads; ++i) {
512 mBufferVals[i].front().clear();
513 mBufferVals[i].back().clear();
514 }
515
516 // define number of tracks which are used
517 const auto nTracks = tracksTPC.size();
518 const size_t loopEnd = (mNMaxTracks < 0) ? nTracks : ((mNMaxTracks > nTracks) ? nTracks : size_t(mNMaxTracks));
519
520 // reserve memory
521 for (int i = 0; i < nBins; ++i) {
522 const int lastIdxPhi = mBufferDCA.mTSTPC.getIndexPhi(mPhiBins);
523 const int lastIdxTgl = mBufferDCA.mTSTPC.getIndexTgl(mTglBins);
524 const int lastIdxQPt = mBufferDCA.mTSTPC.getIndexqPt(mQPtBins);
525 const int lastIdxMult = mBufferDCA.mTSTPC.getIndexMult(mMultBins);
526 const int firstIdx = mBufferDCA.mTSTPC.getIndexInt();
527 int resMem = 0;
528 if (i < lastIdxPhi) {
529 resMem = loopEnd / mPhiBins;
530 } else if (i < lastIdxTgl) {
531 resMem = loopEnd / mTglBins;
532 } else if (i < lastIdxQPt) {
533 resMem = loopEnd / mQPtBins;
534 } else if (i < lastIdxMult) {
535 resMem = loopEnd / mMultBins;
536 } else {
537 resMem = loopEnd;
538 }
539 // Divide by 2 for A-C-side
540 resMem /= 2;
541 for (int type = 0; type < mAvgADCAr[i].size(); ++type) {
542 mAvgADCAr[i][type].reserve(resMem);
543 mAvgCDCAr[i][type].reserve(resMem);
544 mAvgADCAz[i][type].reserve(resMem);
545 mAvgCDCAz[i][type].reserve(resMem);
546 }
547 for (int type = 0; type < mMIPdEdxRatioQMaxA[i].size(); ++type) {
548 mMIPdEdxRatioQMaxA[i][type].reserve(resMem);
549 mMIPdEdxRatioQMaxC[i][type].reserve(resMem);
550 mMIPdEdxRatioQTotA[i][type].reserve(resMem);
551 mMIPdEdxRatioQTotC[i][type].reserve(resMem);
552 mTPCChi2A[i][type].reserve(resMem);
553 mTPCChi2C[i][type].reserve(resMem);
554 mTPCNClA[i][type].reserve(resMem);
555 mTPCNClC[i][type].reserve(resMem);
556 }
557 for (int j = 0; j < mAvgMeffA[i].size(); ++j) {
558 mAvgMeffA[i][j].reserve(resMem);
559 mAvgMeffC[i][j].reserve(resMem);
560 mAvgChi2MatchA[i][j].reserve(resMem);
561 mAvgChi2MatchC[i][j].reserve(resMem);
562 }
563 for (int j = 0; j < mITSPropertiesA[i].size(); ++j) {
564 mITSPropertiesA[i][j].reserve(resMem);
565 mITSPropertiesC[i][j].reserve(resMem);
566 }
567 for (int j = 0; j < mITSTPCDeltaPA[i].size(); ++j) {
568 mITSTPCDeltaPA[i][j].reserve(resMem);
569 mITSTPCDeltaPC[i][j].reserve(resMem);
570 }
571 for (int j = 0; j < mSigmaYZA[i].size(); ++j) {
572 mSigmaYZA[i][j].reserve(resMem);
573 mSigmaYZC[i][j].reserve(resMem);
574 }
575 for (int j = 0; j < mAvgMeffA[i].size(); ++j) {
576 mLogdEdxQTotA[i][j].reserve(resMem);
577 mLogdEdxQTotC[i][j].reserve(resMem);
578 mLogdEdxQMaxA[i][j].reserve(resMem);
579 mLogdEdxQMaxC[i][j].reserve(resMem);
580 }
581 }
582 for (int iThread = 0; iThread < mNThreads; ++iThread) {
583 const int resMem = (mNThreads > 0) ? loopEnd / mNThreads : loopEnd;
584 mBufferVals[iThread].front().reserve(loopEnd, 1);
585 mBufferVals[iThread].back().reserve(loopEnd, 0);
586 }
587
588 using timer = std::chrono::high_resolution_clock;
589 auto startTotal = timer::now();
590
591 // loop over tracks and calculate DCAs
592 if (loopEnd < nTracks) {
593 // draw random tracks
594 std::vector<size_t> ind(nTracks);
595 std::iota(ind.begin(), ind.end(), 0);
596 std::minstd_rand rng(std::time(nullptr));
597 std::shuffle(ind.begin(), ind.end(), rng);
598
599 auto myThread = [&](int iThread) {
600 for (size_t i = iThread; i < loopEnd; i += mNThreads) {
601 if (acceptTrack(tracksTPC[i])) {
602 fillDCA(tracksTPC, tracksITSTPC, vertices, i, iThread, indicesITSTPC, tracksITS, idxTPCTrackToTOFCluster, tofClusters, tpcToTRDMap, trdTracklets, trdCalibTracklets);
603 }
604 }
605 };
606
607 std::vector<std::thread> threads(mNThreads);
608 for (int i = 0; i < mNThreads; i++) {
609 threads[i] = std::thread(myThread, i);
610 }
611
612 for (auto& th : threads) {
613 th.join();
614 }
615 } else {
616 auto myThread = [&](int iThread) {
617 for (size_t i = iThread; i < loopEnd; i += mNThreads) {
618 if (acceptTrack(tracksTPC[i])) {
619 fillDCA(tracksTPC, tracksITSTPC, vertices, i, iThread, indicesITSTPC, tracksITS, idxTPCTrackToTOFCluster, tofClusters, tpcToTRDMap, trdTracklets, trdCalibTracklets);
620 }
621 }
622 };
623
624 std::vector<std::thread> threads(mNThreads);
625 for (int i = 0; i < mNThreads; i++) {
626 threads[i] = std::thread(myThread, i);
627 }
628
629 for (auto& th : threads) {
630 th.join();
631 }
632 }
633
634 // fill DCA values from buffer
635 for (const auto& vals : mBufferVals) {
636 for (int type = 0; type < vals.size(); ++type) {
637 const auto& val = vals[type];
638 const auto nPoints = val.side.size();
639 for (int i = 0; i < nPoints; ++i) {
640 const auto tglBin = val.tglBin[i];
641 const auto phiBin = val.phiBin[i];
642 const auto qPtBin = val.qPtBin[i];
643 const auto multBin = val.multBin[i];
644 const auto dcar = val.dcar[i];
645 const auto dcaz = val.dcaz[i];
646 const auto dcarW = val.dcarW[i];
647 const int binInt = nBins - 1;
648 const bool fillCombDCA = ((type == 1) && (val.dcarcomb[i] != -1) && (val.dcazcomb[i] != -1));
649 const bool fillDCAR = (type == 1) ? (dcar != -999) : true;
650 const std::array<int, 5> bins{tglBin, phiBin, qPtBin, multBin, binInt};
651 // fill bins
652 for (auto bin : bins) {
653 if (val.side[i] == Side::C) {
654 if (fillDCAR) {
655 mAvgCDCAr[bin][type].addValue(dcar, dcarW);
656 }
657 if (fillCombDCA) {
658 mAvgCDCAr[bin][2].addValue(val.dcarcomb[i], dcarW);
659 mAvgCDCAz[bin][2].addValue(val.dcazcomb[i], dcarW);
660 }
661 // fill only in case of valid value
662 if (dcaz != 0) {
663 mAvgCDCAz[bin][type].addValue(dcaz, dcarW);
664 }
665 } else {
666 if (fillDCAR) {
667 mAvgADCAr[bin][type].addValue(dcar, dcarW);
668 }
669 if (fillCombDCA) {
670 mAvgADCAr[bin][2].addValue(val.dcarcomb[i], dcarW);
671 mAvgADCAz[bin][2].addValue(val.dcazcomb[i], dcarW);
672 }
673 // fill only in case of valid value
674 if (dcaz != 0) {
675 mAvgADCAz[bin][type].addValue(dcaz, dcarW);
676 }
677 }
678 }
679 }
680 }
681 }
682
683 // calculate statistics and store values
684 // loop over TPC sides
685 for (int type = 0; type < 2; ++type) {
686 // loop over phi and tgl bins
687 for (int slice = 0; slice < nBins; ++slice) {
688 auto& bufferDCA = (type == 0) ? mBufferDCA.mTSTPC : mBufferDCA.mTSITSTPC;
689
690 const auto dcaAr = mAvgADCAr[slice][type].filterPointsMedian(mCutDCA, mCutRMS);
691 bufferDCA.mDCAr_A_Median[slice] = std::get<0>(dcaAr);
692 bufferDCA.mDCAr_A_WeightedMean[slice] = std::get<1>(dcaAr);
693 bufferDCA.mDCAr_A_RMS[slice] = std::get<2>(dcaAr);
694 bufferDCA.mDCAr_A_NTracks[slice] = std::get<3>(dcaAr);
695
696 const auto dcaAz = mAvgADCAz[slice][type].filterPointsMedian(mCutDCA, mCutRMS);
697 bufferDCA.mDCAz_A_Median[slice] = std::get<0>(dcaAz);
698 bufferDCA.mDCAz_A_WeightedMean[slice] = std::get<1>(dcaAz);
699 bufferDCA.mDCAz_A_RMS[slice] = std::get<2>(dcaAz);
700 bufferDCA.mDCAz_A_NTracks[slice] = std::get<3>(dcaAz);
701
702 const auto dcaCr = mAvgCDCAr[slice][type].filterPointsMedian(mCutDCA, mCutRMS);
703 bufferDCA.mDCAr_C_Median[slice] = std::get<0>(dcaCr);
704 bufferDCA.mDCAr_C_WeightedMean[slice] = std::get<1>(dcaCr);
705 bufferDCA.mDCAr_C_RMS[slice] = std::get<2>(dcaCr);
706 bufferDCA.mDCAr_C_NTracks[slice] = std::get<3>(dcaCr);
707
708 const auto dcaCz = mAvgCDCAz[slice][type].filterPointsMedian(mCutDCA, mCutRMS);
709 bufferDCA.mDCAz_C_Median[slice] = std::get<0>(dcaCz);
710 bufferDCA.mDCAz_C_WeightedMean[slice] = std::get<1>(dcaCz);
711 bufferDCA.mDCAz_C_RMS[slice] = std::get<2>(dcaCz);
712 bufferDCA.mDCAz_C_NTracks[slice] = std::get<3>(dcaCz);
713 // store combined ITS-TPC DCAs
714 if (type == 1) {
715 const auto dcaArComb = mAvgADCAr[slice][2].filterPointsMedian(mCutDCA, mCutRMS);
716 mBufferDCA.mDCAr_comb_A_Median[slice] = std::get<0>(dcaArComb);
717 mBufferDCA.mDCAr_comb_A_RMS[slice] = std::get<2>(dcaArComb);
718
719 const auto dcaAzCom = mAvgADCAz[slice][2].filterPointsMedian(mCutDCA, mCutRMS);
720 mBufferDCA.mDCAz_comb_A_Median[slice] = std::get<0>(dcaAzCom);
721 mBufferDCA.mDCAz_comb_A_RMS[slice] = std::get<2>(dcaAzCom);
722
723 const auto dcaCrComb = mAvgCDCAr[slice][2].filterPointsMedian(mCutDCA, mCutRMS);
724 mBufferDCA.mDCAr_comb_C_Median[slice] = std::get<0>(dcaCrComb);
725 mBufferDCA.mDCAr_comb_C_RMS[slice] = std::get<2>(dcaCrComb);
726
727 const auto dcaCzComb = mAvgCDCAz[slice][2].filterPointsMedian(mCutDCA, mCutRMS);
728 mBufferDCA.mDCAz_comb_C_Median[slice] = std::get<0>(dcaCzComb);
729 mBufferDCA.mDCAz_comb_C_RMS[slice] = std::get<2>(dcaCzComb);
730 }
731 }
732 }
733
734 // calculate matching eff
735 for (const auto& vals : mBufferVals) {
736 const auto& val = vals.front();
737 const auto nPoints = val.side.size();
738 for (int i = 0; i < nPoints; ++i) {
739 const auto tglBin = val.tglBin[i];
740 const auto phiBin = val.phiBin[i];
741 const auto qPtBin = val.qPtBin[i];
742 const auto multBin = val.multBin[i];
743 const auto dcar = val.dcar[i];
744 const auto dcaz = val.dcaz[i];
745 const auto hasITS = val.hasITS[i];
746 const auto chi2Match = val.chi2Match[i];
747 const auto dedxRatioqMax = val.dedxRatioqMax[i];
748 const auto dedxRatioqTot = val.dedxRatioqTot[i];
749 const auto sqrtChi2TPC = val.sqrtChi2TPC[i];
750 const auto nClTPC = val.nClTPC[i];
751 const int binInt = nBins - 1;
752 const Side side = val.side[i];
753 const bool isCSide = (side == Side::C);
754 const auto& bufferDCARMSR = isCSide ? mBufferDCA.mTSTPC.mDCAr_C_RMS : mBufferDCA.mTSTPC.mDCAr_A_RMS;
755 const auto& bufferDCARMSZ = isCSide ? mBufferDCA.mTSTPC.mDCAz_C_RMS : mBufferDCA.mTSTPC.mDCAz_A_RMS;
756 const auto& bufferDCAMedR = isCSide ? mBufferDCA.mTSTPC.mDCAr_C_Median : mBufferDCA.mTSTPC.mDCAr_A_Median;
757 const auto& bufferDCAMedZ = isCSide ? mBufferDCA.mTSTPC.mDCAz_C_Median : mBufferDCA.mTSTPC.mDCAz_A_Median;
758 auto& mAvgEff = isCSide ? mAvgMeffC : mAvgMeffA;
759 auto& mAvgChi2Match = isCSide ? mAvgChi2MatchC : mAvgChi2MatchA;
760 auto& mAvgmMIPdEdxRatioqMax = isCSide ? mMIPdEdxRatioQMaxC : mMIPdEdxRatioQMaxA;
761 auto& mAvgmMIPdEdxRatioqTot = isCSide ? mMIPdEdxRatioQTotC : mMIPdEdxRatioQTotA;
762 auto& mAvgmTPCChi2 = isCSide ? mTPCChi2C : mTPCChi2A;
763 auto& mAvgmTPCNCl = isCSide ? mTPCNClC : mTPCNClA;
764 auto& mAvgmdEdxRatioQMax = isCSide ? mLogdEdxQMaxC : mLogdEdxQMaxA;
765 auto& mAvgmdEdxRatioQTot = isCSide ? mLogdEdxQTotC : mLogdEdxQTotA;
766 auto& mITSProperties = isCSide ? mITSPropertiesC : mITSPropertiesA;
767 auto& mSigmaYZ = isCSide ? mSigmaYZC : mSigmaYZA;
768 auto& mITSTPCDeltaP = isCSide ? mITSTPCDeltaPC : mITSTPCDeltaPA;
769
770 const std::array<int, 5> bins{tglBin, phiBin, qPtBin, multBin, binInt};
771 // fill bins
772 for (auto bin : bins) {
773 // make DCA cut - select only good tracks
774 if ((std::abs(dcar - bufferDCAMedR[bin]) < (bufferDCARMSR[bin] * mCutRMS)) && (std::abs(dcaz - bufferDCAMedZ[bin]) < (bufferDCARMSZ[bin] * mCutRMS))) {
775 const auto gID = val.gID[i];
776 mAvgEff[bin][0].addValue(hasITS);
777 // count tpc only tracks not matched
778 if (!hasITS) {
779 mAvgEff[bin][1].addValue(hasITS);
780 mAvgEff[bin][2].addValue(hasITS);
781 }
782 // count tracks from ITS standalone and afterburner
784 mAvgEff[bin][1].addValue(hasITS);
786 mAvgEff[bin][2].addValue(hasITS);
787 }
788 if (chi2Match > 0) {
789 mAvgChi2Match[bin][0].addValue(chi2Match);
791 mAvgChi2Match[bin][1].addValue(chi2Match);
793 mAvgChi2Match[bin][2].addValue(chi2Match);
794 }
795 }
796 if (dedxRatioqMax > 0) {
797 mAvgmMIPdEdxRatioqMax[bin][0].addValue(dedxRatioqMax);
798 }
799 if (dedxRatioqTot > 0) {
800 mAvgmMIPdEdxRatioqTot[bin][0].addValue(dedxRatioqTot);
801 }
802 mAvgmTPCChi2[bin][0].addValue(sqrtChi2TPC);
803 mAvgmTPCNCl[bin][0].addValue(nClTPC);
804 if (hasITS) {
805 if (dedxRatioqMax > 0) {
806 mAvgmMIPdEdxRatioqMax[bin][1].addValue(dedxRatioqMax);
807 }
808 if (dedxRatioqTot > 0) {
809 mAvgmMIPdEdxRatioqTot[bin][1].addValue(dedxRatioqTot);
810 }
811 mAvgmTPCChi2[bin][1].addValue(sqrtChi2TPC);
812 mAvgmTPCNCl[bin][1].addValue(nClTPC);
813 }
814
815 float dedxNormQMax = val.dedxValsqMax[i].dedxNorm;
816 if (dedxNormQMax > 0) {
817 mAvgmdEdxRatioQMax[bin][0].addValue(dedxNormQMax);
818 }
819
820 float dedxNormQTot = val.dedxValsqTot[i].dedxNorm;
821 if (dedxNormQTot > 0) {
822 mAvgmdEdxRatioQTot[bin][0].addValue(dedxNormQTot);
823 }
824
825 float dedxIROCQMax = val.dedxValsqMax[i].dedxIROC;
826 if (dedxIROCQMax > 0) {
827 mAvgmdEdxRatioQMax[bin][1].addValue(dedxIROCQMax);
828 }
829
830 float dedxIROCQTot = val.dedxValsqTot[i].dedxIROC;
831 if (dedxIROCQTot > 0) {
832 mAvgmdEdxRatioQTot[bin][1].addValue(dedxIROCQTot);
833 }
834
835 float dedxOROC1QMax = val.dedxValsqMax[i].dedxOROC1;
836 if (dedxOROC1QMax > 0) {
837 mAvgmdEdxRatioQMax[bin][2].addValue(dedxOROC1QMax);
838 }
839
840 float dedxOROC1QTot = val.dedxValsqTot[i].dedxOROC1;
841 if (dedxOROC1QTot > 0) {
842 mAvgmdEdxRatioQTot[bin][2].addValue(dedxOROC1QTot);
843 }
844
845 float dedxOROC2QMax = val.dedxValsqMax[i].dedxOROC2;
846 if (dedxOROC2QMax > 0) {
847 mAvgmdEdxRatioQMax[bin][3].addValue(dedxOROC2QMax);
848 }
849
850 float dedxOROC2QTot = val.dedxValsqTot[i].dedxOROC2;
851 if (dedxOROC2QTot > 0) {
852 mAvgmdEdxRatioQTot[bin][3].addValue(dedxOROC2QTot);
853 }
854
855 float dedxOROC3QMax = val.dedxValsqMax[i].dedxOROC3;
856 if (dedxOROC3QMax > 0) {
857 mAvgmdEdxRatioQMax[bin][4].addValue(dedxOROC3QMax);
858 }
859
860 float dedxOROC3QTot = val.dedxValsqTot[i].dedxOROC3;
861 if (dedxOROC3QTot > 0) {
862 mAvgmdEdxRatioQTot[bin][4].addValue(dedxOROC3QTot);
863 }
864
865 float nClITS = val.nClITS[i];
866 if (nClITS > 0) {
867 mITSProperties[bin][0].addValue(nClITS);
868 }
869 float chi2ITS = val.chi2ITS[i];
870 if (chi2ITS > 0) {
871 mITSProperties[bin][1].addValue(chi2ITS);
872 }
873
874 float sigmay2 = val.sigmaY2[i];
875 if (sigmay2 > 0) {
876 mSigmaYZ[bin][0].addValue(sigmay2);
877 }
878 float sigmaz2 = val.sigmaZ2[i];
879 if (sigmaz2 > 0) {
880 mSigmaYZ[bin][1].addValue(sigmaz2);
881 }
882
883 float deltaP2 = val.deltaP2[i];
884 if (deltaP2 != -999) {
885 mITSTPCDeltaP[bin][0].addValue(deltaP2);
886 }
887
888 float deltaP3 = val.deltaP3[i];
889 if (deltaP3 != -999) {
890 mITSTPCDeltaP[bin][1].addValue(deltaP3);
891 }
892
893 float deltaP4 = val.deltaP4[i];
894 if (deltaP4 != -999) {
895 mITSTPCDeltaP[bin][2].addValue(deltaP4);
896 }
897 }
898 }
899 }
900 }
901
902 // store matching eff
903 for (int slice = 0; slice < nBins; ++slice) {
904 for (int i = 0; i < mAvgMeffA[slice].size(); ++i) {
905 auto& itsBuf = (i == 0) ? mBufferDCA.mITSTPCAll : ((i == 1) ? mBufferDCA.mITSTPCStandalone : mBufferDCA.mITSTPCAfterburner);
906 itsBuf.mITSTPC_A_MatchEff[slice] = mAvgMeffA[slice][i].getMean();
907 itsBuf.mITSTPC_C_MatchEff[slice] = mAvgMeffC[slice][i].getMean();
908 itsBuf.mITSTPC_A_Chi2Match[slice] = mAvgChi2MatchA[slice][i].getMean();
909 itsBuf.mITSTPC_C_Chi2Match[slice] = mAvgChi2MatchC[slice][i].getMean();
910 }
911
912 // loop over TPC and ITS-TPC tracks
913 for (int i = 0; i < mMIPdEdxRatioQMaxC[slice].size(); ++i) {
914 auto& buff = (i == 0) ? mBufferDCA.mTSTPC : mBufferDCA.mTSITSTPC;
915 buff.mMIPdEdxRatioQMaxA[slice] = mMIPdEdxRatioQMaxA[slice][i].getMean();
916 buff.mMIPdEdxRatioQMaxC[slice] = mMIPdEdxRatioQMaxC[slice][i].getMean();
917 buff.mMIPdEdxRatioQTotA[slice] = mMIPdEdxRatioQTotA[slice][i].getMean();
918 buff.mMIPdEdxRatioQTotC[slice] = mMIPdEdxRatioQTotC[slice][i].getMean();
919 buff.mTPCChi2C[slice] = mTPCChi2C[slice][i].getMean();
920 buff.mTPCChi2A[slice] = mTPCChi2A[slice][i].getMean();
921 buff.mTPCNClC[slice] = mTPCNClC[slice][i].getMean();
922 buff.mTPCNClA[slice] = mTPCNClA[slice][i].getMean();
923 }
924
925 // loop over qMax and qTot
926 for (int type = 0; type < 2; ++type) {
927 auto& logdEdxA = (type == 0) ? mLogdEdxQMaxA : mLogdEdxQTotA;
928 auto& buffer = (type == 0) ? mBufferDCA.mdEdxQMax : mBufferDCA.mdEdxQTot;
929 // fill A-side
930 buffer.mLogdEdx_A_Median[slice] = logdEdxA[slice][0].getMedian();
931 buffer.mLogdEdx_A_RMS[slice] = logdEdxA[slice][0].getStdDev();
932 buffer.mLogdEdx_A_IROC_Median[slice] = logdEdxA[slice][1].getMedian();
933 buffer.mLogdEdx_A_IROC_RMS[slice] = logdEdxA[slice][1].getStdDev();
934 buffer.mLogdEdx_A_OROC1_Median[slice] = logdEdxA[slice][2].getMedian();
935 buffer.mLogdEdx_A_OROC1_RMS[slice] = logdEdxA[slice][2].getStdDev();
936 buffer.mLogdEdx_A_OROC2_Median[slice] = logdEdxA[slice][3].getMedian();
937 buffer.mLogdEdx_A_OROC2_RMS[slice] = logdEdxA[slice][3].getStdDev();
938 buffer.mLogdEdx_A_OROC3_Median[slice] = logdEdxA[slice][4].getMedian();
939 buffer.mLogdEdx_A_OROC3_RMS[slice] = logdEdxA[slice][4].getStdDev();
940 // fill C-side
941 auto& logdEdxC = (type == 0) ? mLogdEdxQMaxC : mLogdEdxQTotC;
942 buffer.mLogdEdx_C_Median[slice] = logdEdxC[slice][0].getMedian();
943 buffer.mLogdEdx_C_RMS[slice] = logdEdxC[slice][0].getStdDev();
944 buffer.mLogdEdx_C_IROC_Median[slice] = logdEdxC[slice][1].getMedian();
945 buffer.mLogdEdx_C_IROC_RMS[slice] = logdEdxC[slice][1].getStdDev();
946 buffer.mLogdEdx_C_OROC1_Median[slice] = logdEdxC[slice][2].getMedian();
947 buffer.mLogdEdx_C_OROC1_RMS[slice] = logdEdxC[slice][2].getStdDev();
948 buffer.mLogdEdx_C_OROC2_Median[slice] = logdEdxC[slice][3].getMedian();
949 buffer.mLogdEdx_C_OROC2_RMS[slice] = logdEdxC[slice][3].getStdDev();
950 buffer.mLogdEdx_C_OROC3_Median[slice] = logdEdxC[slice][4].getMedian();
951 buffer.mLogdEdx_C_OROC3_RMS[slice] = logdEdxC[slice][4].getStdDev();
952 }
953
954 // ITS properties
955 // A-side
956 mBufferDCA.mITS_A_NCl_Median[slice] = mITSPropertiesA[slice][0].getMedian();
957 mBufferDCA.mITS_A_NCl_RMS[slice] = mITSPropertiesA[slice][0].getStdDev();
958 mBufferDCA.mSqrtITSChi2_Ncl_A_Median[slice] = mITSPropertiesA[slice][1].getMedian();
959 mBufferDCA.mSqrtITSChi2_Ncl_A_RMS[slice] = mITSPropertiesA[slice][1].getStdDev();
960 // C-side
961 mBufferDCA.mITS_C_NCl_Median[slice] = mITSPropertiesC[slice][0].getMedian();
962 mBufferDCA.mITS_C_NCl_RMS[slice] = mITSPropertiesC[slice][0].getStdDev();
963 mBufferDCA.mSqrtITSChi2_Ncl_C_Median[slice] = mITSPropertiesC[slice][1].getMedian();
964 mBufferDCA.mSqrtITSChi2_Ncl_C_RMS[slice] = mITSPropertiesC[slice][1].getStdDev();
965
966 //...
967 mBufferDCA.mITSTPCDeltaP2_A_Median[slice] = mITSTPCDeltaPA[slice][0].getMedian();
968 mBufferDCA.mITSTPCDeltaP3_A_Median[slice] = mITSTPCDeltaPA[slice][1].getMedian();
969 mBufferDCA.mITSTPCDeltaP4_A_Median[slice] = mITSTPCDeltaPA[slice][2].getMedian();
970 mBufferDCA.mITSTPCDeltaP2_C_Median[slice] = mITSTPCDeltaPC[slice][0].getMedian();
971 mBufferDCA.mITSTPCDeltaP3_C_Median[slice] = mITSTPCDeltaPC[slice][1].getMedian();
972 mBufferDCA.mITSTPCDeltaP4_C_Median[slice] = mITSTPCDeltaPC[slice][2].getMedian();
973 mBufferDCA.mITSTPCDeltaP2_A_RMS[slice] = mITSTPCDeltaPA[slice][0].getStdDev();
974 mBufferDCA.mITSTPCDeltaP3_A_RMS[slice] = mITSTPCDeltaPA[slice][1].getStdDev();
975 mBufferDCA.mITSTPCDeltaP4_A_RMS[slice] = mITSTPCDeltaPA[slice][2].getStdDev();
976 mBufferDCA.mITSTPCDeltaP2_C_RMS[slice] = mITSTPCDeltaPC[slice][0].getStdDev();
977 mBufferDCA.mITSTPCDeltaP3_C_RMS[slice] = mITSTPCDeltaPC[slice][1].getStdDev();
978 mBufferDCA.mITSTPCDeltaP4_C_RMS[slice] = mITSTPCDeltaPC[slice][2].getStdDev();
979 mBufferDCA.mTPCSigmaY2A_Median[slice] = mSigmaYZA[slice][0].getMedian();
980 mBufferDCA.mTPCSigmaZ2A_Median[slice] = mSigmaYZA[slice][1].getMedian();
981 mBufferDCA.mTPCSigmaY2C_Median[slice] = mSigmaYZC[slice][0].getMedian();
982 mBufferDCA.mTPCSigmaZ2C_Median[slice] = mSigmaYZC[slice][1].getMedian();
983 mBufferDCA.mTPCSigmaY2A_RMS[slice] = mSigmaYZA[slice][0].getStdDev();
984 mBufferDCA.mTPCSigmaZ2A_RMS[slice] = mSigmaYZA[slice][1].getStdDev();
985 mBufferDCA.mTPCSigmaY2C_RMS[slice] = mSigmaYZC[slice][0].getStdDev();
986 mBufferDCA.mTPCSigmaZ2C_RMS[slice] = mSigmaYZC[slice][1].getStdDev();
987 }
988
989 auto stop = timer::now();
990 std::chrono::duration<float> time = stop - startTotal;
991 LOGP(info, "Time series creation took {}", time.count());
992
993 // send data
994 sendOutput(pc);
995 }
996
998 {
999 for (auto& streamer : mStreamer) {
1000 streamer->Close();
1001 }
1002 eos.services().get<ControlService>().readyToQuit(QuitRequest::Me);
1003 }
1004
1005 void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) final
1006 {
1007 mTPCVDriftHelper.accountCCDBInputs(matcher, obj);
1008 mPTHelper.accountCCDBInputs(matcher, obj);
1010 if (matcher == ConcreteDataMatcher(o2::header::gDataOriginTPC, "InfoMapSecFluc", 0)) {
1011 LOGP(info, "Updating TPC sector edge fluctuation info");
1012 mSecEdgeFlucInfo.setFromTree(*((TTree*)obj));
1013 LOGP(info, "Loaded sector edge fluctuation information with {} intervals for {} runs", mSecEdgeFlucInfo.size(), mSecEdgeFlucInfo.getNRuns());
1014 }
1015 }
1016
1017 private:
1019 struct ValsdEdx {
1020 float dedxNorm = 0;
1021 float dedxIROC = 0;
1022 float dedxOROC1 = 0;
1023 float dedxOROC2 = 0;
1024 float dedxOROC3 = 0;
1025 };
1026
1027 struct FillVals {
1028 void reserve(int n, int type)
1029 {
1030 side.reserve(n);
1031 tglBin.reserve(n);
1032 phiBin.reserve(n);
1033 qPtBin.reserve(n);
1034 multBin.reserve(n);
1035 dcar.reserve(n);
1036 dcaz.reserve(n);
1037 dcarW.reserve(n);
1038 dedxRatioqTot.reserve(n);
1039 dedxRatioqMax.reserve(n);
1040 sqrtChi2TPC.reserve(n);
1041 nClTPC.reserve(n);
1042 if (type == 1) {
1043 hasITS.reserve(n);
1044 chi2Match.reserve(n);
1045 gID.reserve(n);
1046 dedxValsqTot.reserve(n);
1047 dedxValsqMax.reserve(n);
1048 nClITS.reserve(n);
1049 chi2ITS.reserve(n);
1050 deltaP2.reserve(n);
1051 deltaP3.reserve(n);
1052 deltaP4.reserve(n);
1053 sigmaY2.reserve(n);
1054 sigmaZ2.reserve(n);
1055 } else if (type == 0) {
1056 dcarcomb.reserve(n);
1057 dcazcomb.reserve(n);
1058 }
1059 }
1060
1061 void clear()
1062 {
1063 side.clear();
1064 tglBin.clear();
1065 phiBin.clear();
1066 qPtBin.clear();
1067 multBin.clear();
1068 dcar.clear();
1069 dcaz.clear();
1070 dcarW.clear();
1071 hasITS.clear();
1072 chi2Match.clear();
1073 dedxRatioqTot.clear();
1074 dedxRatioqMax.clear();
1075 sqrtChi2TPC.clear();
1076 nClTPC.clear();
1077 gID.clear();
1078 dcarcomb.clear();
1079 dcazcomb.clear();
1080 nClITS.clear();
1081 chi2ITS.clear();
1082 dedxValsqTot.clear();
1083 dedxValsqMax.clear();
1084 deltaP2.clear();
1085 deltaP3.clear();
1086 deltaP4.clear();
1087 sigmaY2.clear();
1088 sigmaZ2.clear();
1089 }
1090
1091 void emplace_back(Side sideTmp, int tglBinTmp, int phiBinTmp, int qPtBinTmp, int multBinTmp, float dcarTmp, float dcazTmp, float dcarWTmp, float dedxRatioqTotTmp, float dedxRatioqMaxTmp, float sqrtChi2TPCTmp, float nClTPCTmp, o2::dataformats::GlobalTrackID::Source gIDTmp, float chi2MatchTmp, int hasITSTmp, int nClITSTmp, float chi2ITSTmp, const ValsdEdx& dedxValsqTotTmp, const ValsdEdx& dedxValsqMaxTmp, float sigmaY2Tmp, float sigmaZ2Tmp)
1092 {
1093 side.emplace_back(sideTmp);
1094 tglBin.emplace_back(tglBinTmp);
1095 phiBin.emplace_back(phiBinTmp);
1096 qPtBin.emplace_back(qPtBinTmp);
1097 multBin.emplace_back(multBinTmp);
1098 dcar.emplace_back(dcarTmp);
1099 dcaz.emplace_back(dcazTmp);
1100 dcarW.emplace_back(dcarWTmp);
1101 dedxRatioqTot.emplace_back(dedxRatioqTotTmp);
1102 dedxRatioqMax.emplace_back(dedxRatioqMaxTmp);
1103 sqrtChi2TPC.emplace_back(sqrtChi2TPCTmp);
1104 nClTPC.emplace_back(nClTPCTmp);
1105 chi2Match.emplace_back(chi2MatchTmp);
1106 hasITS.emplace_back(hasITSTmp);
1107 gID.emplace_back(gIDTmp);
1108 dedxValsqMax.emplace_back(dedxValsqMaxTmp);
1109 dedxValsqTot.emplace_back(dedxValsqTotTmp);
1110 nClITS.emplace_back(nClITSTmp);
1111 chi2ITS.emplace_back(chi2ITSTmp);
1112 sigmaY2.emplace_back(sigmaY2Tmp);
1113 sigmaZ2.emplace_back(sigmaZ2Tmp);
1114 deltaP2.emplace_back(-999);
1115 deltaP3.emplace_back(-999);
1116 deltaP4.emplace_back(-999);
1117 }
1118
1119 void setDeltaParam(float deltaP2Tmp, float deltaP3Tmp, float deltaP4Tmp)
1120 {
1121 if (!deltaP2.empty()) {
1122 deltaP2.back() = deltaP2Tmp;
1123 deltaP3.back() = deltaP3Tmp;
1124 deltaP4.back() = deltaP4Tmp;
1125 }
1126 }
1127
1128 void emplace_back_ITSTPC(Side sideTmp, int tglBinTmp, int phiBinTmp, int qPtBinTmp, int multBinTmp, float dcarTmp, float dcazTmp, float dcarWTmp, float dedxRatioqTotTmp, float dedxRatioqMaxTmp, float sqrtChi2TPCTmp, float nClTPCTmp, float dcarCombTmp, float dcazCombTmp)
1129 {
1130 side.emplace_back(sideTmp);
1131 tglBin.emplace_back(tglBinTmp);
1132 phiBin.emplace_back(phiBinTmp);
1133 qPtBin.emplace_back(qPtBinTmp);
1134 multBin.emplace_back(multBinTmp);
1135 dcar.emplace_back(dcarTmp);
1136 dcaz.emplace_back(dcazTmp);
1137 dcarW.emplace_back(dcarWTmp);
1138 dedxRatioqTot.emplace_back(dedxRatioqTotTmp);
1139 dedxRatioqMax.emplace_back(dedxRatioqMaxTmp);
1140 sqrtChi2TPC.emplace_back(sqrtChi2TPCTmp);
1141 nClTPC.emplace_back(nClTPCTmp);
1142 dcarcomb.emplace_back(dcarCombTmp);
1143 dcazcomb.emplace_back(dcazCombTmp);
1144 }
1145
1146 std::vector<Side> side;
1147 std::vector<int> tglBin;
1148 std::vector<int> phiBin;
1149 std::vector<int> qPtBin;
1150 std::vector<int> multBin;
1151 std::vector<float> dcar;
1152 std::vector<float> dcaz;
1153 std::vector<float> dcarW;
1154 std::vector<bool> hasITS;
1155 std::vector<float> chi2Match;
1156 std::vector<float> dedxRatioqTot;
1157 std::vector<float> dedxRatioqMax;
1158 std::vector<float> sqrtChi2TPC;
1159 std::vector<float> nClTPC;
1160 std::vector<float> dcarcomb;
1161 std::vector<float> dcazcomb;
1162 std::vector<ValsdEdx> dedxValsqTot;
1163 std::vector<ValsdEdx> dedxValsqMax;
1164 std::vector<int> nClITS;
1165 std::vector<float> chi2ITS;
1166 std::vector<o2::dataformats::GlobalTrackID::Source> gID;
1167 std::vector<float> deltaP2;
1168 std::vector<float> deltaP3;
1169 std::vector<float> deltaP4;
1170 std::vector<float> sigmaY2;
1171 std::vector<float> sigmaZ2;
1172 };
1173 std::shared_ptr<o2::base::GRPGeomRequest> mCCDBRequest;
1174 const bool mDisableWriter{false};
1176 const bool mUnbinnedWriter{false};
1177 const bool mTPCOnly{false};
1178 std::shared_ptr<o2::globaltracking::DataRequest> mDataRequest;
1179 int mPhiBins = SECTORSPERSIDE;
1180 int mTglBins{3};
1181 int mQPtBins{20};
1182 TimeSeriesITSTPC mBufferDCA;
1183 std::vector<std::array<RobustAverage, 3>> mAvgADCAr;
1184 std::vector<std::array<RobustAverage, 3>> mAvgCDCAr;
1185 std::vector<std::array<RobustAverage, 3>> mAvgADCAz;
1186 std::vector<std::array<RobustAverage, 3>> mAvgCDCAz;
1187 std::vector<std::array<RobustAverage, 2>> mMIPdEdxRatioQMaxA;
1188 std::vector<std::array<RobustAverage, 2>> mMIPdEdxRatioQMaxC;
1189 std::vector<std::array<RobustAverage, 2>> mMIPdEdxRatioQTotA;
1190 std::vector<std::array<RobustAverage, 2>> mMIPdEdxRatioQTotC;
1191 std::vector<std::array<RobustAverage, 2>> mTPCChi2A;
1192 std::vector<std::array<RobustAverage, 2>> mTPCChi2C;
1193 std::vector<std::array<RobustAverage, 2>> mTPCNClA;
1194 std::vector<std::array<RobustAverage, 2>> mTPCNClC;
1195 std::vector<std::array<RobustAverage, 3>> mAvgMeffA;
1196 std::vector<std::array<RobustAverage, 3>> mAvgMeffC;
1197 std::vector<std::array<RobustAverage, 3>> mAvgChi2MatchA;
1198 std::vector<std::array<RobustAverage, 3>> mAvgChi2MatchC;
1199 std::vector<std::array<RobustAverage, 10>> mLogdEdxQTotA;
1200 std::vector<std::array<RobustAverage, 10>> mLogdEdxQTotC;
1201 std::vector<std::array<RobustAverage, 10>> mLogdEdxQMaxA;
1202 std::vector<std::array<RobustAverage, 10>> mLogdEdxQMaxC;
1203 std::vector<std::array<RobustAverage, 2>> mITSPropertiesA;
1204 std::vector<std::array<RobustAverage, 2>> mITSPropertiesC;
1205 std::vector<std::array<RobustAverage, 3>> mITSTPCDeltaPA;
1206 std::vector<std::array<RobustAverage, 3>> mITSTPCDeltaPC;
1207 std::vector<std::array<RobustAverage, 2>> mSigmaYZA;
1208 std::vector<std::array<RobustAverage, 2>> mSigmaYZC;
1209 int mNMaxTracks{-1};
1210 float mMinMom{1};
1211 int mMinNCl{80};
1212 float mMaxTgl{1};
1213 float mMaxQPt{5};
1214 float mCoarseStep{1};
1215 float mFineStep{0.005};
1216 float mCutDCA{5};
1217 float mCutRMS{5};
1218 float mRefXSec{108.475};
1219 int mNThreads{1};
1220 float maxITSTPCDCAr{0.2};
1221 float maxITSTPCDCAz{10};
1222 float maxITSTPCDCAr_comb{0.2};
1223 float maxITSTPCDCAz_comb{0.2};
1224 gsl::span<const TPCClRefElem> mTPCTrackClIdx{};
1225 std::vector<std::array<FillVals, 2>> mBufferVals;
1226 uint32_t mFirstTFOrbit{0};
1227 float mTimeWindowMUS{50};
1228 float mMIPdEdx{50};
1229 std::vector<int> mNTracksWindow;
1230 std::vector<int> mNearestVtxTPC;
1231 o2::tpc::VDriftHelper mTPCVDriftHelper{};
1232 float mVDrift{2.64};
1233 float mMaxSnp{0.85};
1234 float mXCoarse{40};
1235 float mSqrt{13600};
1236 int mMultBins{20};
1237 int mMultMax{80000};
1238 PIDResponse mPID;
1239 int mMinTracksPerVertex{5};
1240 float mMaxdEdxRatio{0.3};
1241 float mMaxdEdxRegionRatio{0.5};
1242 float mSamplingFactor{0.1};
1243 bool mSampleTsallis{false};
1244 bool mStoreFullTrackPar{false};
1245 uint8_t mTRDInReadout{255};
1246 std::vector<o2::InteractionRecord> mTRDTrigBCs;
1247 std::vector<int> mTRDTrigBCsInTF;
1248 std::vector<int> mNContributorsITS;
1249 std::vector<int> mNContributorsITSTPC;
1250 std::vector<int> mNContributorsTRD;
1251 std::vector<std::mt19937> mGenerator;
1252 std::vector<std::unique_ptr<o2::utils::TreeStreamRedirector>> mStreamer;
1253 float mXOuterMatching{60};
1254 bool mUseMinBiasTrigger{false};
1255 long mTimeMS{};
1256 int mRun{};
1257 int mMaxOccupancyHistBins{912};
1258 PressureTemperatureHelper mPTHelper;
1259 o2::tpc::SectorEdgeFluctuations mSecEdgeFlucInfo;
1260
1262 bool acceptTrack(const TrackTPC& track) const { return std::abs(track.getTgl()) < mMaxTgl; }
1263
1264 bool checkTrack(const TrackTPC& track) const
1265 {
1266 const bool isGoodTrack = ((track.getNClusters() < mMinNCl) || (track.getP() < mMinMom)) ? false : true;
1267 return isGoodTrack;
1268 }
1269
1270 void fillDCA(const gsl::span<const TrackTPC> tracksTPC, const gsl::span<const o2::dataformats::TrackTPCITS> tracksITSTPC, const gsl::span<const o2::dataformats::PrimaryVertex> vertices, const int iTrk, const int iThread, const std::unordered_map<unsigned int, std::array<int, 2>>& indicesITSTPC, const gsl::span<const o2::its::TrackITS> tracksITS, const std::vector<std::tuple<int, float, float, o2::track::TrackLTIntegral, double, float, unsigned int, unsigned short>>& idxTPCTrackToTOFCluster, const gsl::span<const o2::tof::Cluster> tofClusters, const std::unordered_map<unsigned int, TRDTrackletData>& tpcToTRDMap, const gsl::span<const o2::trd::Tracklet64> trdTracklets, const gsl::span<const o2::trd::CalibratedTracklet> trdCalibTracklets)
1271 {
1272 const auto& trackFull = tracksTPC[iTrk];
1273 const bool isGoodTrack = checkTrack(trackFull);
1274
1275 // check for min bias trigger - sample flat -
1276 bool minBiasOk = false;
1277 const float factorMinBias = 0.1 * mSamplingFactor;
1278 if (mUnbinnedWriter && mUseMinBiasTrigger) {
1279 std::uniform_real_distribution<> distr(0., 1.);
1280 if (distr(mGenerator[iThread]) < factorMinBias) {
1281 minBiasOk = true;
1282 }
1283 }
1284
1285 // check if at least one check passed
1286 if (!isGoodTrack && !minBiasOk) {
1287 return;
1288 }
1289
1290 o2::track::TrackParCov track = tracksTPC[iTrk];
1291
1292 // propagate track to the DCA and fill in slice
1293 auto propagator = o2::base::Propagator::Instance();
1294
1295 // propagate track to DCA
1296 std::array<float, 2> dca;
1297 const o2::math_utils::Point3D<float> refPoint{0, 0, 0};
1298
1299 // coarse propagation
1300 if (!propagator->PropagateToXBxByBz(track, mXCoarse, mMaxSnp, mCoarseStep, mMatType)) {
1301 return;
1302 }
1303
1304 // fine propagation with Bz only
1305 if (!propagator->propagateToDCA(refPoint, track, propagator->getNominalBz(), mFineStep, mMatType, &dca)) {
1306 return;
1307 }
1308
1309 o2::track::TrackPar trackTmp(tracksTPC[iTrk]);
1310
1311 // coarse propagation to centre of IROC for phi bin
1312 if (!propagator->propagateTo(trackTmp, mRefXSec, false, mMaxSnp, mCoarseStep, mMatType)) {
1313 return;
1314 }
1315
1316 // Saturate bin indices — edge bins act as overflow (Phase 0.2 fix)
1317 const int tglBin = std::clamp(static_cast<int>(mTglBins * std::abs(trackTmp.getTgl()) / mMaxTgl) + mPhiBins,
1318 mPhiBins, mPhiBins + mTglBins - 1);
1319 const int phiBin = std::clamp(static_cast<int>(mPhiBins * trackTmp.getPhi() / o2::constants::math::TwoPI),
1320 0, mPhiBins - 1);
1321
1322 const int offsQPtBin = mPhiBins + mTglBins;
1323 const int qPtBin = std::clamp(offsQPtBin + static_cast<int>(mQPtBins * (trackTmp.getQ2Pt() + mMaxQPt) / (2 * mMaxQPt)),
1324 offsQPtBin, offsQPtBin + mQPtBins - 1);
1325 const int localMult = mNTracksWindow[iTrk];
1326
1327 const int offsMult = offsQPtBin + mQPtBins;
1328 const int multBin = std::clamp(offsMult + static_cast<int>(mMultBins * localMult / mMultMax),
1329 offsMult, offsMult + mMultBins - 1);
1330 const int nBins = getNBins();
1331
1332 float sigmaY2 = 0;
1333 float sigmaZ2 = 0;
1334 const int sector = o2::math_utils::angle2Sector(trackTmp.getPhiPos());
1335 // find possible ITS-TPC track and vertex index
1336 auto it = indicesITSTPC.find(iTrk);
1337 const auto idxITSTPC = (it != indicesITSTPC.end()) ? (it->second) : std::array<int, 2>{-1, -1};
1338
1339 // get vertex (check if vertex ID is valid). In case no vertex is assigned return nearest vertex or else default vertex
1340 const auto vertex = (idxITSTPC.back() != -1) ? vertices[idxITSTPC.back()] : ((mNearestVtxTPC[iTrk] != -1) ? vertices[mNearestVtxTPC[iTrk]] : o2::dataformats::PrimaryVertex{});
1341 // index of that vertex (-1: none) and its contributor counts, -1 without vertex
1342 const int vtxID = (idxITSTPC.back() != -1) ? idxITSTPC.back() : mNearestVtxTPC[iTrk];
1343 const int nContribITS = (vtxID >= 0 && vtxID < static_cast<int>(mNContributorsITS.size())) ? mNContributorsITS[vtxID] : -1;
1344 const int nContribITSTPC = (vtxID >= 0 && vtxID < static_cast<int>(mNContributorsITSTPC.size())) ? mNContributorsITSTPC[vtxID] : -1;
1345 const int nContribTRD = (vtxID >= 0 && vtxID < static_cast<int>(mNContributorsTRD.size())) ? mNContributorsTRD[vtxID] : -1;
1346
1347 // calculate DCAz: (time TPC track - time vertex) * vDrift + sign_side * vertexZ
1348 const float signSide = trackFull.hasCSideClustersOnly() ? -1 : 1; // invert sign for C-side
1349 const float dcaZFromDeltaTime = (vertex.getTimeStamp().getTimeStamp() == 0) ? 0 : (o2::tpc::ParameterElectronics::Instance().ZbinWidth * trackFull.getTime0() - vertex.getTimeStamp().getTimeStamp()) * mVDrift + signSide * vertex.getZ();
1350
1351 // for weight of DCA
1352 const float resCl = std::min(trackFull.getNClusters(), static_cast<int>(Mapper::PADROWS)) / static_cast<float>(Mapper::PADROWS);
1353
1354 const float div = (resCl * track.getPt());
1355 if (div == 0) {
1356 return;
1357 }
1358
1359 const float fB = 0.2 / div;
1360 const float fA = 0.15 + 0.15; // = 0.15 with additional misalignment error
1361 const float dcarW = 1. / std::sqrt(fA * fA + fB * fB); // Weight of DCA: Rms2 ~ 0.15^2 + k/(L^2*pt) → 0.15**2 + (0.2/((NCl/152)*pt)^2);
1362
1363 // store values for TPC DCA only for A- or C-side only tracks
1364 const bool hasITSTPC = idxITSTPC.front() != -1;
1365
1366 // get ratio of chi2 in case ITS-TPC track has been found
1367 const float chi2 = hasITSTPC ? tracksITSTPC[idxITSTPC.front()].getChi2Match() : -1;
1369 // check for source in case of ITS-TPC
1370 if (hasITSTPC) {
1371 const auto src = tracksITSTPC[idxITSTPC.front()].getRefITS().getSource();
1376 }
1377 }
1378
1379 const float chi2Match = (chi2 > 0) ? std::sqrt(chi2) : -1;
1380 const float sqrtChi2TPC = (trackFull.getChi2() > 0) ? std::sqrt(trackFull.getChi2()) : 0;
1381 const float nClTPC = trackFull.getNClusters();
1382
1383 // const float dedx = mUseQMax ? track.getdEdx().dEdxMaxTPC : track.getdEdx().dEdxTotTPC;
1384 const float dedxRatioqTot = (trackFull.getdEdx().dEdxTotTPC > 0) ? (mMIPdEdx / trackFull.getdEdx().dEdxTotTPC) : -1;
1385 const float dedxRatioqMax = (trackFull.getdEdx().dEdxMaxTPC > 0) ? (mMIPdEdx / trackFull.getdEdx().dEdxMaxTPC) : -1;
1386
1387 const auto dedxQTotVars = getdEdxVars(0, trackFull);
1388 const auto dedxQMaxVars = getdEdxVars(1, trackFull);
1389
1390 // make check to avoid crash in case no or less ITS tracks have been found!
1391 const int idxITSTrack = (hasITSTPC && (gID == o2::dataformats::GlobalTrackID::Source::ITS)) ? tracksITSTPC[idxITSTPC.front()].getRefITS().getIndex() : -1;
1392 const bool idxITSCheck = (idxITSTrack != -1);
1393
1394 const int nClITS = idxITSCheck ? tracksITS[idxITSTrack].getNClusters() : -1;
1395 float chi2ITS = idxITSCheck ? tracksITS[idxITSTrack].getChi2() : -1;
1396 if ((chi2ITS > 0) && (nClITS > 0)) {
1397 chi2ITS = std::sqrt(chi2ITS / nClITS);
1398 }
1399 sigmaY2 = track.getSigmaY2();
1400 sigmaZ2 = track.getSigmaZ2();
1401 if (isGoodTrack) {
1402 if (trackFull.hasCSideClustersOnly()) {
1403 mBufferVals[iThread].front().emplace_back(Side::C, tglBin, phiBin, qPtBin, multBin, dca[0], dcaZFromDeltaTime, dcarW, dedxRatioqTot, dedxRatioqMax, sqrtChi2TPC, nClTPC, gID, chi2Match, hasITSTPC, nClITS, chi2ITS, dedxQTotVars, dedxQMaxVars, sigmaY2, sigmaZ2);
1404 } else if (trackFull.hasASideClustersOnly()) {
1405 mBufferVals[iThread].front().emplace_back(Side::A, tglBin, phiBin, qPtBin, multBin, dca[0], dcaZFromDeltaTime, dcarW, dedxRatioqTot, dedxRatioqMax, sqrtChi2TPC, nClTPC, gID, chi2Match, hasITSTPC, nClITS, chi2ITS, dedxQTotVars, dedxQMaxVars, sigmaY2, sigmaZ2);
1406 }
1407 }
1408
1409 // make propagation for ITS-TPC Track
1410 // check if the track was assigned to ITS track
1411 std::array<float, 2> dcaITSTPC{0, 0};
1412 float deltaP0 = -999;
1413 float deltaP1 = -999;
1414 float deltaP2 = -999;
1415 float deltaP3 = -999;
1416 float deltaP4 = -999;
1417 float phiITSTPCAtVertex = -999; // phi of ITS-TPC track at vertex
1418 float dcaTPCAtVertex = -999;
1419 if (hasITSTPC) {
1420 // propagate ITS-TPC track to (0,0)
1421 auto trackITSTPCTmp = tracksITSTPC[idxITSTPC.front()];
1422 // fine propagation with Bz only
1423 if (propagator->propagateToDCA(refPoint, trackITSTPCTmp, propagator->getNominalBz(), mFineStep, mMatType, &dcaITSTPC)) {
1424 // make cut on abs(DCA)
1425 if ((std::abs(dcaITSTPC[0]) < maxITSTPCDCAr) && (std::abs(dcaITSTPC[1]) < maxITSTPCDCAz)) {
1426 // store TPC only DCAs
1427 // propagate to vertex in case the track belongs to vertex
1428 const bool contributeToVertex = (idxITSTPC.back() != -1);
1429 std::array<float, 2> dcaITSTPCTmp{-1, -1};
1430
1431 if (contributeToVertex) {
1432 if (propagator->propagateToDCA(vertex.getXYZ(), trackITSTPCTmp, propagator->getNominalBz(), mFineStep, mMatType, &dcaITSTPCTmp)) {
1433 phiITSTPCAtVertex = trackITSTPCTmp.getPhi();
1434 dcaITSTPC = dcaITSTPCTmp;
1435 }
1436
1437 // propagate TPC track to vertex
1438 std::array<float, 2> dcaTPCTmp{-1, -1};
1439 if (propagator->propagateToDCA(vertex.getXYZ(), track, propagator->getNominalBz(), mFineStep, mMatType, &dcaTPCTmp)) {
1440 dcaTPCAtVertex = dcaTPCTmp[0];
1441 }
1442 }
1443
1444 // make cut around DCA to vertex due to gammas
1445 if ((std::abs(dcaITSTPCTmp[0]) < maxITSTPCDCAr_comb) && (std::abs(dcaITSTPCTmp[1]) < maxITSTPCDCAz_comb)) {
1446 // propagate TPC track to ITS track and store delta track parameters
1447 if (idxITSTrack >= 0 && track.rotate(tracksITS[idxITSTrack].getAlpha()) && propagator->propagateTo(track, trackITSTPCTmp.getX(), false, mMaxSnp, mFineStep, mMatType)) {
1448 o2::track::TrackPar trackITS(tracksITS[idxITSTrack]);
1449 const bool propITSOk = propagator->propagateTo(trackITS, trackITSTPCTmp.getX(), false, mMaxSnp, mFineStep, mMatType);
1450 if (propITSOk) {
1451 deltaP0 = track.getParam(0) - trackITS.getParam(0);
1452 deltaP1 = track.getParam(1) - trackITS.getParam(1);
1453 deltaP2 = track.getParam(2) - trackITS.getParam(2);
1454 deltaP3 = track.getParam(3) - trackITS.getParam(3);
1455 deltaP4 = track.getParam(4) - trackITS.getParam(4);
1456 mBufferVals[iThread].front().setDeltaParam(deltaP2, deltaP3, deltaP4);
1457 }
1458 }
1459 } else {
1460 dcaITSTPCTmp[0] = -1;
1461 dcaITSTPCTmp[1] = -1;
1462 }
1463
1464 if (isGoodTrack) {
1465 if (trackFull.hasCSideClustersOnly()) {
1466 mBufferVals[iThread].back().emplace_back_ITSTPC(Side::C, tglBin, phiBin, qPtBin, multBin, dcaTPCAtVertex, dcaZFromDeltaTime, dcarW, dedxRatioqTot, dedxRatioqMax, sqrtChi2TPC, nClTPC, dcaITSTPCTmp[0], dcaITSTPCTmp[1]);
1467 } else if (trackFull.hasASideClustersOnly()) {
1468 mBufferVals[iThread].back().emplace_back_ITSTPC(Side::A, tglBin, phiBin, qPtBin, multBin, dcaTPCAtVertex, dcaZFromDeltaTime, dcarW, dedxRatioqTot, dedxRatioqMax, sqrtChi2TPC, nClTPC, dcaITSTPCTmp[0], dcaITSTPCTmp[1]);
1469 }
1470 }
1471 }
1472 }
1473 }
1474
1475 if (mUnbinnedWriter && mStreamer[iThread]) {
1476 const float factorPt = mSamplingFactor;
1477 bool writeData = true;
1478 bool writeDataITSTPC = false;
1479 float weight = 0;
1480 float weightITSTPC = 0;
1481 if (mSampleTsallis) {
1482 std::uniform_real_distribution<> distr(0., 1.);
1483 writeData = o2::math_utils::Tsallis::downsampleTsallisCharged(tracksTPC[iTrk].getPt(), factorPt, mSqrt, weight, distr(mGenerator[iThread]));
1484 if (hasITSTPC) {
1485 writeDataITSTPC = o2::math_utils::Tsallis::downsampleTsallisCharged(tracksITSTPC[idxITSTPC.front()].getPt(), factorPt, mSqrt, weightITSTPC, distr(mGenerator[iThread]));
1486 }
1487 }
1488 if (writeData || writeDataITSTPC || minBiasOk) {
1489 auto clusterMask = makeClusterBitMask(trackFull);
1490 const auto& trkOrig = tracksTPC[iTrk];
1491 const bool isNearestVtx = (idxITSTPC.back() == -1); // is nearest vertex in case no vertex was found
1492 const float mx_ITS = hasITSTPC ? tracksITSTPC[idxITSTPC.front()].getX() : -1;
1493 const float pt_ITS = hasITSTPC ? tracksITSTPC[idxITSTPC.front()].getQ2Pt() : -1;
1494 const float chi2match_ITSTPC = hasITSTPC ? tracksITSTPC[idxITSTPC.front()].getChi2Match() : -1;
1495 const int nClITS = idxITSCheck ? tracksITS[idxITSTrack].getNClusters() : -1;
1496 const int chi2ITS = idxITSCheck ? tracksITS[idxITSTrack].getChi2() : -1;
1497 // D1: ITS cluster sizes (4-bit per layer, mask bit 28 = kSharedClusters)
1498 const uint32_t itsClusterSizes = idxITSCheck ? (static_cast<uint32_t>(tracksITS[idxITSTrack].getClusterSizes()) & 0x0FFFFFFFu) : 0u;
1499 const bool itsHasSharedClusters = idxITSCheck ? tracksITS[idxITSTrack].hasSharedClusters() : false;
1500 const uint32_t itsPattern = idxITSCheck ? (tracksITS[idxITSTrack].getPattern() & 0x7Fu) : 0u;
1501
1502 // D2: TRD tracklet data — native objects per layer
1503 uint8_t trdPattern = 0;
1504 uint8_t nTRDTracklets = 0;
1505 std::vector<o2::trd::Tracklet64> trdTrackletVec(6);
1506 std::vector<o2::trd::CalibratedTracklet> trdCalibVec(6);
1507 auto itTRD = tpcToTRDMap.find(iTrk);
1508 if (itTRD != tpcToTRDMap.end()) {
1509 const auto& trdData = itTRD->second;
1510 trdPattern = trdData.trdPattern;
1511 nTRDTracklets = trdData.nTRDTracklets;
1512 for (int iLay = 0; iLay < 6; ++iLay) {
1513 if (trdData.trackletIndices[iLay] >= 0) {
1514 trdTrackletVec[iLay] = trdTracklets[trdData.trackletIndices[iLay]];
1515 if (trdData.trackletIndices[iLay] < static_cast<int>(trdCalibTracklets.size())) {
1516 trdCalibVec[iLay] = trdCalibTracklets[trdData.trackletIndices[iLay]];
1517 }
1518 }
1519 }
1520 }
1521
1522 // TPC-out / TRD-in states on a common local X plane, computed for every written entry (Architect decision 2026-10-28:
1523 // residuals always stored; only the full TrackPar objects depend on --store-full-trackpar).
1524 // Open Phase 0.4 finding, deferred: the target is local X = kTPCTRDMiddle in the frame rotated to the track position
1525 // angle (lab radius = sqrt(X^2 + Y^2), not exactly 275 cm). The TRD side is the outer state of the ITS-TPC-TRD track,
1526 // propagated inward to the plane; its outward refit includes the TPC clusters, so TRD - TPC is not independent.
1527 static constexpr float kTPCTRDMiddle = 275.f; // cm, common local X plane between TPC outer wall and TRD layer 0
1528 static constexpr uint32_t kDeltaTRDTPCMask = 0xFFFFE000; // keep 10 mantissa bits: float16-like relative precision ~1e-3
1529 o2::track::TrackParCov tpcOutCov; // local temporary with covariance (needed for chi2); persisted as TrackPar
1530 o2::track::TrackParCov trdInCov;
1531 uint8_t tpcOutOK = 2; // 0 propagated, 2 propagation failed
1532 uint8_t trdInOK = 1; // 0 propagated, 1 not attempted (no TRD match or tpcOutOK != 0), 2 propagation failed; count TRD matches with trdPattern > 0
1533 float chi2PhiTPCTRD = -1.f; // -1: not computed (trdInOK != 0) or singular covariance
1534 float chi2ZTPCTRD = -1.f;
1535 // deltaTRDTPC: TrackPar used as a residual container. mX and mAlpha = the common plane and frame (full precision,
1536 // copied from the propagated TPC state); mP[0..4] = TRD - TPC of Y, Z, Snp, Tgl, Q2Pt, truncated to 10 mantissa bits.
1537 // Meaningful: getX(), getAlpha(), getParam(i), getY(), getZ(), getSnp(), getTgl(), getQ2Pt(); not meaningful: derived
1538 // getters (getPt(), getP(), getPhi(), getEta(), getCurvature(), ...). Charge, PID and user field are those of the TPC
1539 // track. Default object (X = 0, parameters 0) if trdInOK != 0: select with trdInOK == 0.
1540 o2::track::TrackPar deltaTRDTPC;
1541 // D1: TPC outer → kTPCTRDMiddle
1542 tpcOutCov = o2::track::TrackParCov(tracksTPC[iTrk].getParamOut());
1543 {
1544 // rotate to sector angle at current position
1545 float sn = std::sin(tpcOutCov.getAlpha());
1546 float cs = std::cos(tpcOutCov.getAlpha());
1547 float gy = tpcOutCov.getX() * sn + tpcOutCov.getY() * cs;
1548 float gx = tpcOutCov.getX() * cs - tpcOutCov.getY() * sn;
1549 if (tpcOutCov.rotate(std::atan2(gy, gx)) &&
1550 propagator->propagateTo(tpcOutCov, kTPCTRDMiddle, false, mMaxSnp, mCoarseStep, mMatType)) {
1551 tpcOutOK = 0;
1552 }
1553 }
1554
1555 // D2: TRD matched → kTPCTRDMiddle, rotated to SAME alpha as TPC out
1556 if (itTRD != tpcToTRDMap.end() && itTRD->second.hasTRDTrackPar && tpcOutOK == 0) {
1557 trdInCov = o2::track::TrackParCov(itTRD->second.trdTrackParCov);
1558 // rotate to TPC alpha FIRST, then propagate — guarantees same frame + same X
1559 if (trdInCov.rotate(tpcOutCov.getAlpha()) &&
1560 propagator->propagateTo(trdInCov, kTPCTRDMiddle, false, mMaxSnp, mCoarseStep, mMatType)) {
1561 trdInOK = 0;
1562 chi2PhiTPCTRD = chi2Match_Phi(tpcOutCov, trdInCov);
1563 chi2ZTPCTRD = chi2Match_Z(tpcOutCov, trdInCov);
1564 deltaTRDTPC = tpcOutCov; // mX, mAlpha (and charge, PID) of the common plane
1565 for (int iPar = 0; iPar < 5; ++iPar) {
1566 deltaTRDTPC.setParam(o2::math_utils::truncateFloatFraction(trdInCov.getParam(iPar) - tpcOutCov.getParam(iPar), kDeltaTRDTPCMask), iPar);
1567 }
1568 } else {
1569 trdInOK = 2; // propagation failed
1570 }
1571 }
1572
1573 // TRD read out in the collision of this entry: TRD-triggered BCs closest to the BC range [IRMin, IRMax] of the entry's
1574 // vertex. Both 0: a TRD trigger inside the range. Otherwise trdTrigDBCBefore < 0 = BCs from the range start back to the
1575 // closest earlier trigger, trdTrigDBCAfter > 0 = BCs from the range end to the closest later trigger. Sentinels -999999 /
1576 // 999999: no vertex with a BC range, or no such trigger in this TF.
1577 int trdTrigDBCBefore = -999999;
1578 int trdTrigDBCAfter = 999999;
1579 if (vtxID >= 0 && !vertex.getIRMin().isDummy() && !vertex.getIRMax().isDummy()) {
1580 const auto& irMin = vertex.getIRMin();
1581 const auto& irMax = vertex.getIRMax();
1582 const auto itTrig = std::lower_bound(mTRDTrigBCs.begin(), mTRDTrigBCs.end(), irMin); // first trigger at or after irMin
1583 if (itTrig != mTRDTrigBCs.end() && *itTrig <= irMax) {
1584 trdTrigDBCBefore = 0;
1585 trdTrigDBCAfter = 0;
1586 } else {
1587 if (itTrig != mTRDTrigBCs.end()) {
1588 trdTrigDBCAfter = static_cast<int>(itTrig->differenceInBC(irMax));
1589 }
1590 if (itTrig != mTRDTrigBCs.begin()) {
1591 trdTrigDBCBefore = static_cast<int>((itTrig - 1)->differenceInBC(irMin));
1592 }
1593 }
1594 }
1595
1596 // For calibrating the two estimators: BC of the vertex time as a BC number from the TF start (orbit firstTFOrbit, bc 0;
1597 // same reference as vertex_time), and the closest TRD-triggered BCs at or before / at or after it, as BC differences to
1598 // vertex_bc: trdTrigDBCVtxBefore <= 0, trdTrigDBCVtxAfter >= 0 (both 0 if a trigger is at vertex_bc).
1599 // Sentinels: vertex_bc -999999 without vertex; -999999 / 999999 without vertex or without such a trigger in this TF.
1600 int vertexBC = -999999;
1601 int trdTrigDBCVtxBefore = -999999;
1602 int trdTrigDBCVtxAfter = 999999;
1603 if (vtxID >= 0) {
1604 vertexBC = static_cast<int>(std::lround(vertex.getTimeStamp().getTimeStamp() / o2::constants::lhc::LHCBunchSpacingMUS));
1605 const auto itBC = std::lower_bound(mTRDTrigBCsInTF.begin(), mTRDTrigBCsInTF.end(), vertexBC); // first trigger at or after vertexBC
1606 if (itBC != mTRDTrigBCsInTF.end()) {
1607 trdTrigDBCVtxAfter = *itBC - vertexBC;
1608 }
1609 if (itBC != mTRDTrigBCsInTF.end() && *itBC == vertexBC) {
1610 trdTrigDBCVtxBefore = 0;
1611 } else if (itBC != mTRDTrigBCsInTF.begin()) {
1612 trdTrigDBCVtxBefore = *(itBC - 1) - vertexBC;
1613 }
1614 }
1615
1616 int typeSide = 2; // A- and C-Side cluster
1617 if (trackFull.hasASideClustersOnly()) {
1618 typeSide = 0;
1619 } else if (trackFull.hasCSideClustersOnly()) {
1620 typeSide = 1;
1621 }
1622
1623 // check for TOF and propagate TPC track to TOF cluster
1624 bool hasTOFCluster = (std::get<0>(idxTPCTrackToTOFCluster[iTrk]) != -1);
1625 auto tofCl = hasTOFCluster ? tofClusters[std::get<0>(idxTPCTrackToTOFCluster[iTrk])] : o2::tof::Cluster();
1626
1627 float tpcYDeltaAtTOF = -999;
1628 float tpcZDeltaAtTOF = -999;
1629 if (hasTOFCluster) {
1630 o2::track::TrackPar trackTmpOut(tracksTPC[iTrk].getParamOut());
1631 if (trackTmpOut.rotate(o2::math_utils::sector2Angle(tofCl.getSector())) && propagator->propagateTo(trackTmpOut, tofCl.getX(), false, mMaxSnp, mFineStep, mMatType)) {
1632 tpcYDeltaAtTOF = trackTmpOut.getY() - tofCl.getY();
1633 tpcZDeltaAtTOF = signSide * (o2::tpc::ParameterElectronics::Instance().ZbinWidth * trackFull.getTime0() - vertex.getTimeStamp().getTimeStamp()) * mVDrift - trackTmpOut.getZ() + tofCl.getZ();
1634 }
1635 }
1636
1637 // get delta parameter between inner and outer
1638 float deltaTPCParamInOutTgl = trackFull.getTgl() - trackFull.getParamOut().getTgl();
1639 float deltaTPCParamInOutQPt = trackFull.getQ2Pt() - trackFull.getParamOut().getQ2Pt();
1640
1641 // propagate TPC track and ITS-TPC track to outer matching at 60cm
1642 float deltaP0OuterITS = -999;
1643 float deltaP1OuterITS = -999;
1644 float deltaP2OuterITS = -999;
1645 float deltaP3OuterITS = -999;
1646 float deltaP4OuterITS = -999;
1647 if (idxITSCheck) {
1648 o2::track::TrackPar trackTmpOut(tracksITS[idxITSTrack].getParamOut());
1649 const bool propITSOk = propagator->propagateTo(trackTmpOut, mXOuterMatching, false, mMaxSnp, mCoarseStep, mMatType);
1650 if (propITSOk && trackTmp.rotate(trackTmpOut.getAlpha())) {
1651 const bool propTPCOk = propagator->propagateTo(trackTmp, mXOuterMatching, false, mMaxSnp, mCoarseStep, mMatType);
1652 if (propTPCOk) {
1653 // store delta parameters
1654 deltaP0OuterITS = trackTmp.getParam(0) - trackTmpOut.getParam(0);
1655 deltaP1OuterITS = trackTmp.getParam(1) - trackTmpOut.getParam(1);
1656 deltaP2OuterITS = trackTmp.getParam(2) - trackTmpOut.getParam(2);
1657 deltaP3OuterITS = trackTmp.getParam(3) - trackTmpOut.getParam(3);
1658 deltaP4OuterITS = trackTmp.getParam(4) - trackTmpOut.getParam(4);
1659 }
1660 }
1661 }
1662 // triggerMask bits:
1663 // 0x1: flat minimum-bias stream
1664 // 0x2: Tsallis stream sampled with TPC-only pT
1665 // 0x4: Tsallis stream sampled with ITS-TPC combined pT
1666 const int triggerMask = 0x1 * minBiasOk + 0x2 * writeData + 0x4 * writeDataITSTPC;
1667
1668 float deltaP2ConstrVtx = -999;
1669 float deltaP3ConstrVtx = -999;
1670 float deltaP4ConstrVtx = -999;
1671
1672 // cov of TPC track constrained at vertex
1673 float covTPCConstrVtxP2 = -999;
1674 float covTPCConstrVtxP3 = -999;
1675 float covTPCConstrVtxP4 = -999;
1676
1677 // cov of ITS-TPC track at vertex
1678 float covITSTPCConstrVtxP2 = -999;
1679 float covITSTPCConstrVtxP3 = -999;
1680 float covITSTPCConstrVtxP4 = -999;
1681
1682 float covTPCAtVertex0 = -999;
1683 float covTPCAtVertex1 = -999;
1684
1685 const bool contributeToVertex = (idxITSTPC.back() != -1);
1686 if (hasITSTPC && contributeToVertex) {
1687 o2::track::TrackParCov trackITSTPCTmp = tracksITSTPC[idxITSTPC.front()];
1688 std::array<float, 2> dcaITSTPCTmp{-1, -1};
1689 if (propagator->propagateToDCA(vertex.getXYZ(), trackITSTPCTmp, propagator->getNominalBz(), mFineStep, mMatType, &dcaITSTPCTmp)) {
1690 o2::track::TrackParCov trackTPC = tracksTPC[iTrk];
1691 if (trackTPC.rotate(trackITSTPCTmp.getAlpha()) && propagator->propagateTo(trackTPC, trackITSTPCTmp.getX(), false, mMaxSnp, mFineStep, mMatType)) {
1692 // store covariance of TPC track at vertex
1693 covTPCAtVertex0 = trackTPC.getCovarElem(0, 0);
1694 covTPCAtVertex1 = trackTPC.getCovarElem(1, 1);
1695
1696 trackTPC.update(vertex);
1697 deltaP2ConstrVtx = trackTPC.getParam(2) - trackITSTPCTmp.getParam(2);
1698 deltaP3ConstrVtx = trackTPC.getParam(3) - trackITSTPCTmp.getParam(3);
1699 deltaP4ConstrVtx = trackTPC.getParam(4) - trackITSTPCTmp.getParam(4);
1700 covTPCConstrVtxP2 = trackTPC.getCovarElem(2, 2);
1701 covTPCConstrVtxP3 = trackTPC.getCovarElem(3, 3);
1702 covTPCConstrVtxP4 = trackTPC.getCovarElem(4, 4);
1703 covITSTPCConstrVtxP2 = trackITSTPCTmp.getCovarElem(2, 2);
1704 covITSTPCConstrVtxP3 = trackITSTPCTmp.getCovarElem(3, 3);
1705 covITSTPCConstrVtxP4 = trackITSTPCTmp.getCovarElem(4, 4);
1706 }
1707 }
1708 }
1709 double vertexTime = vertex.getTimeStamp().getTimeStamp();
1710 double trackTime0 = trackFull.getTime0();
1711 // Optional payload (--store-full-trackpar, default off), persisted without covariance as TrackPar.
1712 // This statement and the main chain below fill ONE entry: TreeStream keeps its element index until "\n",
1713 // and the flag is constant for the job, so every entry has the same branch set (a varying set silently
1714 // drops entries). Keep both statements adjacent, with no return/continue in between, and keep the objects in
1715 // scope until the "\n" below (TreeStream stores pointers and reads them when the entry is filled).
1716 // tpcAtVtx = TPC track after the DCA step; its reference depends on the path:
1717 // all tracks: DCA to (0,0,0);
1718 // then, for ITS-TPC vertex contributors passing the ITS-TPC DCA cuts: DCA to the primary vertex;
1719 // then, if also passing the combined DCA cut and having an ITS track: rotated to the ITS track frame and
1720 // propagated to the X of the ITS-TPC track.
1721 // With the switch on, these three branches come first in the tree (compare by branch name, not position).
1722 o2::track::TrackPar tpcOutPar;
1723 o2::track::TrackPar trdInPar;
1724 o2::track::TrackPar tpcAtVtxPar;
1725 if (mStoreFullTrackPar) {
1726 tpcOutPar = tpcOutCov;
1727 trdInPar = trdInCov;
1728 tpcAtVtxPar = track;
1729 *mStreamer[iThread] << "treeTimeSeries"
1730 << "tpcOut=" << tpcOutPar
1731 << "trdIn=" << trdInPar
1732 << "tpcAtVtx=" << tpcAtVtxPar;
1733 }
1734 *mStreamer[iThread] << "treeTimeSeries"
1735 // DCAs
1736 << "triggerMask=" << triggerMask
1737 << "factorMinBias=" << factorMinBias
1738 << "factorPt=" << factorPt
1739 << "weight=" << weight
1740 << "weight_ITSTPC=" << weightITSTPC
1741 << "dcar_tpc_vertex=" << dcaTPCAtVertex
1742 << "dcar_tpc=" << dca[0]
1743 << "dcaz_tpc=" << dca[1]
1744 << "dcar_itstpc=" << dcaITSTPC[0]
1745 << "dcaz_itstpc=" << dcaITSTPC[1]
1746 << "dcarW=" << dcarW
1747 << "dcaZFromDeltaTime=" << dcaZFromDeltaTime
1748 << "hasITSTPC=" << hasITSTPC
1749 // vertex
1750 << "vertex_x=" << vertex.getX()
1751 << "vertex_y=" << vertex.getY()
1752 << "vertex_z=" << vertex.getZ()
1753 << "vertex_time=" << vertex.getTimeStamp().getTimeStamp()
1754 << "vertex_nContributors=" << vertex.getNContributors()
1755 // contributor counts of the same vertex (-1 without vertex) and TRD triggers closest to its BC range
1756 << "vertex_nContributorsITS=" << nContribITS
1757 << "vertex_nContributorsITSTPC=" << nContribITSTPC
1758 << "vertex_nContributorsTRD=" << nContribTRD
1759 << "trdTrigDBCBefore=" << trdTrigDBCBefore
1760 << "trdTrigDBCAfter=" << trdTrigDBCAfter
1761 // vertex BC (from its time, BC number from the TF start) and closest TRD triggers as BC differences to it
1762 << "vertex_bc=" << vertexBC
1763 << "trdTrigDBCVtxBefore=" << trdTrigDBCVtxBefore
1764 << "trdTrigDBCVtxAfter=" << trdTrigDBCVtxAfter
1765 << "isNearestVertex=" << isNearestVtx
1766 // tpc track properties
1767 << "pt=" << trkOrig.getPt()
1768 << "qpt_ITSTPC=" << pt_ITS
1769 << "tpc_timebin=" << trkOrig.getTime0()
1770 << "qpt=" << trkOrig.getParam(4)
1771 << "ncl=" << trkOrig.getNClusters()
1772 << "ncl_shared=" << trkOrig.getNClusters()
1773 << "tgl=" << trkOrig.getTgl()
1774 << "side_type=" << typeSide
1775 << "phi=" << trkOrig.getPhi()
1776 << "clusterMask=" << clusterMask
1777 << "dedxTPC=" << trkOrig.getdEdx()
1778 << "chi2=" << trkOrig.getChi2()
1779 << "mX=" << trkOrig.getX()
1780 << "mX_ITS=" << mx_ITS
1781 << "nClITS=" << nClITS
1782 << "chi2ITS=" << chi2ITS
1783 << "itsClusterSizes=" << itsClusterSizes
1784 << "itsHasSharedClusters=" << itsHasSharedClusters
1785 << "itsPattern=" << itsPattern
1786 // D2: TRD tracklet data
1787 << "trdPattern=" << trdPattern
1788 << "nTRDTracklets=" << nTRDTracklets
1789 << "trdTracklets=" << trdTrackletVec
1790 << "trdCalibTracklets=" << trdCalibVec
1791 // TPC out / TRD in on the common local X = 275 cm plane: status, matching chi2 and TRD - TPC residuals
1792 // (the full TrackPar objects are written above, only with --store-full-trackpar)
1793 << "tpcOutOK=" << tpcOutOK
1794 << "trdInOK=" << trdInOK
1795 << "chi2PhiTPCTRD=" << chi2PhiTPCTRD
1796 << "chi2ZTPCTRD=" << chi2ZTPCTRD
1797 << "deltaTRDTPC=" << deltaTRDTPC
1798 // TRD in detector readout for this run (GRPECS): 1 yes, 0 no, 255 unknown
1799 << "trdInReadout=" << mTRDInReadout
1800 << "chi2match_ITSTPC=" << chi2match_ITSTPC
1801 << "PID=" << trkOrig.getPID().getID()
1802 // TPC cov at vertex (without vertex constrained)
1803 << "covTPCAtVertex0=" << covTPCAtVertex0
1804 << "covTPCAtVertex1=" << covTPCAtVertex1
1805 // TPC cov at vertex (with vertex constrained)
1806 << "covTPCConstrVtxP2=" << covTPCConstrVtxP2
1807 << "covTPCConstrVtxP3=" << covTPCConstrVtxP3
1808 << "covTPCConstrVtxP4=" << covTPCConstrVtxP4
1809 // ITS-TPC cov at vertex (with vertex constrained)
1810 << "covITSTPCConstrVtxP2=" << covITSTPCConstrVtxP2
1811 << "covITSTPCConstrVtxP3=" << covITSTPCConstrVtxP3
1812 << "covITSTPCConstrVtxP4=" << covITSTPCConstrVtxP4
1813 // delta Parameter at vertex with TPC track constrained at vertex
1814 << "deltaP2ConstrVtx=" << deltaP2ConstrVtx
1815 << "deltaP3ConstrVtx=" << deltaP3ConstrVtx
1816 << "deltaP4ConstrVtx=" << deltaP4ConstrVtx
1817 //
1818 << "deltaPar0=" << deltaP0
1819 << "deltaPar1=" << deltaP1
1820 << "deltaPar2=" << deltaP2
1821 << "deltaPar3=" << deltaP3
1822 << "deltaPar4=" << deltaP4
1823 << "sigmaY2=" << sigmaY2
1824 << "sigmaZ2=" << sigmaZ2
1825 // meta
1826 << "mult=" << mNTracksWindow[iTrk]
1827 << "time_window_mult=" << mTimeWindowMUS
1828 << "firstTFOrbit=" << mFirstTFOrbit
1829 << "timeMS=" << mTimeMS
1830 << "run=" << mRun
1831 << "mVDrift=" << mVDrift
1832 << "its_flag=" << int(gID)
1833 << "sqrtChi2Match=" << chi2Match
1834 // TOF cluster
1835 << "tpcYDeltaAtTOF=" << tpcYDeltaAtTOF
1836 << "tpcZDeltaAtTOF=" << tpcZDeltaAtTOF
1837 << "mDXatTOF=" << std::get<1>(idxTPCTrackToTOFCluster[iTrk])
1838 << "mDZatTOF=" << std::get<2>(idxTPCTrackToTOFCluster[iTrk])
1839 << "mTOFLength=" << std::get<3>(idxTPCTrackToTOFCluster[iTrk])
1840 << "mTOFSignal=" << std::get<4>(idxTPCTrackToTOFCluster[iTrk])
1841 << "mDeltaTTOFTPC=" << std::get<5>(idxTPCTrackToTOFCluster[iTrk])
1842 << "vertexTime=" << vertexTime
1843 << "trackTime0=" << trackTime0
1844 << "TOFmask=" << std::get<6>(idxTPCTrackToTOFCluster[iTrk])
1845 << "TOFchannel=" << std::get<7>(idxTPCTrackToTOFCluster[iTrk])
1846 // TPC delta param
1847 << "deltaTPCParamInOutTgl=" << deltaTPCParamInOutTgl
1848 << "deltaTPCParamInOutQPt=" << deltaTPCParamInOutQPt
1849 // delta parameter between ITS-TPC - TPC at 60 cm
1850 << "deltaP0OuterITS=" << deltaP0OuterITS
1851 << "deltaP1OuterITS=" << deltaP1OuterITS
1852 << "deltaP2OuterITS=" << deltaP2OuterITS
1853 << "deltaP3OuterITS=" << deltaP3OuterITS
1854 << "deltaP4OuterITS=" << deltaP4OuterITS
1855 << "mXOuterMatching=" << mXOuterMatching
1856 // phi of ITS-TPC track at vertex
1857 << "phiITSTPCAtVertex=" << phiITSTPCAtVertex
1858 << "\n";
1859 }
1860 }
1861 }
1862
1863 void sendOutput(ProcessingContext& pc)
1864 {
1865 mBufferDCA.mTSTPC.setStartTime(mTimeMS);
1866 mBufferDCA.mTSITSTPC.setStartTime(mTimeMS);
1867 pc.outputs().snapshot(Output{header::gDataOriginTPC, getDataDescriptionTimeSeries()}, mBufferDCA);
1868 // in case of ROOT output also store the TFinfo in the TTree
1869 if (!mDisableWriter) {
1872 pc.outputs().snapshot(Output{header::gDataOriginTPC, getDataDescriptionTPCTimeSeriesTFId()}, tfinfo);
1873 }
1874 }
1875
1877 void findNearesVertex(const gsl::span<const TrackTPC> tracksTPC, const gsl::span<const o2::dataformats::PrimaryVertex> vertices)
1878 {
1879 // create list of time bins of tracks
1880 const int nVertices = vertices.size();
1881
1882 const int nTracks = tracksTPC.size();
1883 mNearestVtxTPC.clear();
1884 mNearestVtxTPC.resize(nTracks);
1885
1886 // in case no vertices are found
1887 if (!nVertices) {
1888 std::fill(mNearestVtxTPC.begin(), mNearestVtxTPC.end(), -1);
1889 return;
1890 }
1891
1892 // store timestamps of vertices. Assume vertices are already sorted in time!
1893 std::vector<float> times_vtx;
1894 times_vtx.reserve(nVertices);
1895 for (const auto& vtx : vertices) {
1896 times_vtx.emplace_back(vtx.getTimeStamp().getTimeStamp());
1897 }
1898
1899 // loop over tpc tracks and find nearest vertex
1900 auto myThread = [&](int iThread) {
1901 for (int i = iThread; i < nTracks; i += mNThreads) {
1902 const float timeTrack = o2::tpc::ParameterElectronics::Instance().ZbinWidth * tracksTPC[i].getTime0();
1903 const auto lower = std::lower_bound(times_vtx.begin(), times_vtx.end(), timeTrack);
1904 int closestVtx = std::distance(times_vtx.begin(), lower);
1905 // if value is out of bounds use last value
1906 if (closestVtx == nVertices) {
1907 closestVtx -= 1;
1908 } else if (closestVtx > 0) {
1909 // if idx > 0 check preceeding value
1910 double diff1 = std::abs(timeTrack - *lower);
1911 double diff2 = std::abs(timeTrack - *(lower - 1));
1912 if (diff2 < diff1) {
1913 closestVtx -= 1;
1914 }
1915 }
1916 mNearestVtxTPC[i] = closestVtx;
1917 }
1918 };
1919
1920 std::vector<std::thread> threads(mNThreads);
1921 for (int i = 0; i < mNThreads; i++) {
1922 threads[i] = std::thread(myThread, i);
1923 }
1924
1925 // wait for the threads to finish
1926 for (auto& th : threads) {
1927 th.join();
1928 }
1929 }
1930
1932 std::vector<bool> makeClusterBitMask(const TrackTPC& track) const
1933 {
1934 std::vector<bool> tpcClusterMask(Mapper::PADROWS, false);
1935 const int nCl = track.getNClusterReferences();
1936 for (int j = 0; j < nCl; ++j) {
1937 uint8_t sector, padrow;
1938 uint32_t clusterIndexInRow;
1939 track.getClusterReference(mTPCTrackClIdx, j, sector, padrow, clusterIndexInRow);
1940 tpcClusterMask[padrow] = true;
1941 }
1942 return tpcClusterMask;
1943 }
1944
1946 void findNNeighbourTracks(const gsl::span<const TrackTPC> tracksTPC)
1947 {
1948 const float tpcTBinMUS = o2::tpc::ParameterElectronics::Instance().ZbinWidth; // 0.199606f; time bin in MUS
1949 const float windowTimeBins = mTimeWindowMUS / tpcTBinMUS; // number of neighbouring time bins to check
1950
1951 // create list of time bins of tracks
1952 std::vector<float> times;
1953 const int nTracks = tracksTPC.size();
1954 times.reserve(nTracks);
1955 for (const auto& trk : tracksTPC) {
1956 times.emplace_back(trk.getTime0());
1957 }
1958 std::sort(times.begin(), times.end());
1959
1960 mNTracksWindow.clear();
1961 mNTracksWindow.resize(nTracks);
1962
1963 // loop over tpc tracks and count number of neighouring tracks
1964 auto myThread = [&](int iThread) {
1965 for (int i = iThread; i < nTracks; i += mNThreads) {
1966 const float t0 = tracksTPC[i].getTime0();
1967 const auto upperV0 = std::upper_bound(times.begin(), times.end(), t0 + windowTimeBins);
1968 const auto lowerV0 = std::lower_bound(times.begin(), times.end(), t0 - windowTimeBins);
1969 const int nMult = std::distance(times.begin(), upperV0) - std::distance(times.begin(), lowerV0);
1970 mNTracksWindow[i] = nMult;
1971 }
1972 };
1973
1974 std::vector<std::thread> threads(mNThreads);
1975 for (int i = 0; i < mNThreads; i++) {
1976 threads[i] = std::thread(myThread, i);
1977 }
1978
1979 // wait for the threads to finish
1980 for (auto& th : threads) {
1981 th.join();
1982 }
1983 }
1984
1985 std::unordered_map<unsigned int, int> processVertices(const gsl::span<const o2::dataformats::PrimaryVertex> vertices, const gsl::span<const o2::dataformats::VtxTrackIndex> primMatchedTracks, const gsl::span<const o2::dataformats::VtxTrackRef> primMatchedTracksRef, const RecoContainer& recoData)
1986 {
1987 // storing collision vertex to ITS-TPC track index
1988 std::unordered_map<unsigned int, int> indicesITSTPC_vtx; // ITS-TPC track index -> collision vertex ID
1989
1990 std::unordered_map<int, int> nContributors_ITS; // ITS: vertex ID -> n contributors
1991 std::unordered_map<int, int> nContributors_ITSTPC; // ITS-TPC (and ITS-TPC-TRD, ITS-TPC-TOF, ITS-TPC-TRD-TOF): vertex ID -> n contributors
1992 std::unordered_map<int, int> nContributors_TRD; // ITS-TPC-TRD (and ITS-TPC-TRD-TOF): vertex ID -> n TRD-matched PV contributors
1993
1994 // loop over collisions
1995 if (!vertices.empty()) {
1996 for (const auto& ref : primMatchedTracksRef) {
1997 // loop over ITS and ITS-TPC sources
1998 const std::array<TrkSrc, 5> sources = {TrkSrc::ITSTPC, TrkSrc::ITSTPCTRD, TrkSrc::ITSTPCTOF, TrkSrc::ITSTPCTRDTOF, TrkSrc::ITS};
1999 for (auto source : sources) {
2000 const int vID = ref.getVtxID(); // vertex ID
2001 const int firstEntry = ref.getFirstEntryOfSource(source);
2002 const int nEntries = ref.getEntriesOfSource(source);
2003 // loop over all tracks belonging to the vertex
2004 for (int i = 0; i < nEntries; ++i) {
2005 const auto& matchedTrk = primMatchedTracks[i + firstEntry];
2006 bool pvCont = matchedTrk.isPVContributor();
2007 if (pvCont) {
2008 // store index of ITS-TPC track container and vertex ID
2009 auto refITSTPC = recoData.getSingleDetectorRefs(matchedTrk)[TrkSrc::ITSTPC];
2010 if (refITSTPC.isIndexSet()) {
2011 indicesITSTPC_vtx[refITSTPC] = vID;
2012 ++nContributors_ITSTPC[vID];
2013 // count TRD-matched PV contributors
2014 if (source == TrkSrc::ITSTPCTRD || source == TrkSrc::ITSTPCTRDTOF) {
2015 ++nContributors_TRD[vID];
2016 }
2017 } else {
2018 ++nContributors_ITS[vID];
2019 }
2020 }
2021 }
2022 }
2023 }
2024 }
2025
2026 // per-vertex contributor counts, also written per entry of the unbinned tree (vertex_nContributorsITS/ITSTPC/TRD)
2027 mNContributorsITS.assign(vertices.size(), 0);
2028 mNContributorsITSTPC.assign(vertices.size(), 0);
2029 mNContributorsTRD.assign(vertices.size(), 0);
2030 const int nVertices = vertices.size();
2031 for (const auto& [vID, n] : nContributors_ITS) {
2032 if (vID >= 0 && vID < nVertices) {
2033 mNContributorsITS[vID] = n;
2034 }
2035 }
2036 for (const auto& [vID, n] : nContributors_ITSTPC) {
2037 if (vID >= 0 && vID < nVertices) {
2038 mNContributorsITSTPC[vID] = n;
2039 }
2040 }
2041 for (const auto& [vID, n] : nContributors_TRD) {
2042 if (vID >= 0 && vID < nVertices) {
2043 mNContributorsTRD[vID] = n;
2044 }
2045 }
2046
2047 // calculate statistics
2048 std::array<RobustAverage, 4> avgVtxITS;
2049 std::array<RobustAverage, 4> avgVtxITSTPC;
2050 for (int i = 0; i < avgVtxITS.size(); ++i) {
2051 avgVtxITS[i].reserve(vertices.size());
2052 avgVtxITSTPC[i].reserve(vertices.size());
2053 }
2054 for (int ivtx = 0; ivtx < vertices.size(); ++ivtx) {
2055 const auto& vtx = vertices[ivtx];
2056 const float itsFrac = nContributors_ITS[ivtx] / static_cast<float>(vtx.getNContributors());
2057 const float itstpcFrac = (nContributors_ITS[ivtx] + nContributors_ITSTPC[ivtx]) / static_cast<float>(vtx.getNContributors());
2058
2059 const float itsMin = 0.2;
2060 const float itsMax = 0.8;
2061 if ((itsFrac > itsMin) && (itsFrac < itsMax)) {
2062 avgVtxITS[0].addValue(vtx.getX());
2063 avgVtxITS[1].addValue(vtx.getY());
2064 avgVtxITS[2].addValue(vtx.getZ());
2065 avgVtxITS[3].addValue(vtx.getNContributors());
2066 }
2067
2068 const float itstpcMax = 0.95;
2069 if (itstpcFrac < itstpcMax) {
2070 avgVtxITSTPC[0].addValue(vtx.getX());
2071 avgVtxITSTPC[1].addValue(vtx.getY());
2072 avgVtxITSTPC[2].addValue(vtx.getZ());
2073 avgVtxITSTPC[3].addValue(vtx.getNContributors());
2074 }
2075 }
2076
2077 // ITS
2078 mBufferDCA.nPrimVertices_ITS.front() = avgVtxITS[3].getValues().size();
2079 mBufferDCA.nVertexContributors_ITS_Median.front() = avgVtxITS[3].getMedian();
2080 mBufferDCA.nVertexContributors_ITS_RMS.front() = avgVtxITS[3].getStdDev();
2081 mBufferDCA.vertexX_ITS_Median.front() = avgVtxITS[0].getMedian();
2082 mBufferDCA.vertexY_ITS_Median.front() = avgVtxITS[1].getMedian();
2083 mBufferDCA.vertexZ_ITS_Median.front() = avgVtxITS[2].getMedian();
2084 mBufferDCA.vertexX_ITS_RMS.front() = avgVtxITS[0].getStdDev();
2085 mBufferDCA.vertexY_ITS_RMS.front() = avgVtxITS[1].getStdDev();
2086 mBufferDCA.vertexZ_ITS_RMS.front() = avgVtxITS[2].getStdDev();
2087
2088 // ITS-TPC
2089 mBufferDCA.nPrimVertices_ITSTPC.front() = avgVtxITSTPC[3].getValues().size();
2090 mBufferDCA.nVertexContributors_ITSTPC_Median.front() = avgVtxITSTPC[3].getMedian();
2091 mBufferDCA.nVertexContributors_ITSTPC_RMS.front() = avgVtxITSTPC[3].getStdDev();
2092 mBufferDCA.vertexX_ITSTPC_Median.front() = avgVtxITSTPC[0].getMedian();
2093 mBufferDCA.vertexY_ITSTPC_Median.front() = avgVtxITSTPC[1].getMedian();
2094 mBufferDCA.vertexZ_ITSTPC_Median.front() = avgVtxITSTPC[2].getMedian();
2095 mBufferDCA.vertexX_ITSTPC_RMS.front() = avgVtxITSTPC[0].getStdDev();
2096 mBufferDCA.vertexY_ITSTPC_RMS.front() = avgVtxITSTPC[1].getStdDev();
2097 mBufferDCA.vertexZ_ITSTPC_RMS.front() = avgVtxITSTPC[2].getStdDev();
2098
2099 // TRD matching fraction (summed over all vertices in this TF)
2100 int sumITSTPCBased = 0;
2101 int sumWithTRD = 0;
2102 for (int ivtx = 0; ivtx < vertices.size(); ++ivtx) {
2103 sumITSTPCBased += nContributors_ITSTPC[ivtx];
2104 sumWithTRD += nContributors_TRD[ivtx];
2105 }
2106 mBufferDCA.nITSTPCBasedPVContributors.front() = sumITSTPCBased;
2107 mBufferDCA.nITSTPCWithTRDPVContributors.front() = sumWithTRD;
2108 mBufferDCA.fracTRD.front() = (sumITSTPCBased > 0) ? static_cast<float>(sumWithTRD) / sumITSTPCBased : std::nanf("");
2109
2110 // quantiles and truncated mean
2111 RobustAverage avg(vertices.size(), false);
2112 for (const auto& vtx : vertices) {
2113 if (vtx.getNContributors() > mMinTracksPerVertex) {
2114 // transform by n^0.5 to get more flat distribution
2115 avg.addValue(std::sqrt(vtx.getNContributors()));
2116 }
2117 }
2118
2119 // nPrimVertices_Quantiles
2120 int sizeQ = mBufferDCA.nVertexContributors_Quantiles.size();
2121 const int nBinsQ = 20;
2122 if (sizeQ >= (nBinsQ + 3)) {
2123 for (int iq = 0; iq < nBinsQ; ++iq) {
2124 const float quantile = (iq + 1) / static_cast<float>(nBinsQ);
2125 const float val = avg.getQuantile(quantile, 1);
2126 mBufferDCA.nVertexContributors_Quantiles[iq] = val * val;
2127 }
2128 const float tr0 = avg.getTrunctedMean(0.05, 0.95);
2129 const float tr1 = avg.getTrunctedMean(0.1, 0.9);
2130 const float tr2 = avg.getTrunctedMean(0.2, 0.8);
2131 mBufferDCA.nVertexContributors_Quantiles[sizeQ - 3] = tr0 * tr0;
2132 mBufferDCA.nVertexContributors_Quantiles[sizeQ - 2] = tr1 * tr1;
2133 mBufferDCA.nVertexContributors_Quantiles[sizeQ - 1] = tr2 * tr2;
2134 }
2135 mBufferDCA.nPrimVertices.front() = vertices.size();
2136
2137 return indicesITSTPC_vtx;
2138 }
2139
2141 int getNBins() const { return mBufferDCA.mTSTPC.getNBins(); }
2142
2143 ValsdEdx getdEdxVars(bool useQMax, const TrackTPC& track) const
2144 {
2145 const float dedx = useQMax ? track.getdEdx().dEdxMaxTPC : track.getdEdx().dEdxTotTPC;
2146 const float dedxRatioNorm = mPID.getExpectedSignal(track, o2::track::PID::ID(o2::track::PID::Pion)) / dedx;
2147 float dedxNorm = (dedxRatioNorm > 0) ? std::log(mPID.getExpectedSignal(track, o2::track::PID::ID(o2::track::PID::Pion)) / dedx) : -1;
2148 // restrict to specified range
2149 if (std::abs(dedxNorm) > mMaxdEdxRatio) {
2150 dedxNorm = -1;
2151 }
2152
2153 // get log(dedxRegion / dedx)
2154 float dedxIROC = -1;
2155 float dedxOROC1 = -1;
2156 float dedxOROC2 = -1;
2157 float dedxOROC3 = -1;
2158 if (dedx > 0) {
2159 dedxIROC = useQMax ? track.getdEdx().dEdxMaxIROC : track.getdEdx().dEdxTotIROC;
2160 dedxOROC1 = useQMax ? track.getdEdx().dEdxMaxOROC1 : track.getdEdx().dEdxTotOROC1;
2161 dedxOROC2 = useQMax ? track.getdEdx().dEdxMaxOROC2 : track.getdEdx().dEdxTotOROC2;
2162 dedxOROC3 = useQMax ? track.getdEdx().dEdxMaxOROC3 : track.getdEdx().dEdxTotOROC3;
2163 dedxIROC /= dedx;
2164 dedxOROC1 /= dedx;
2165 dedxOROC2 /= dedx;
2166 dedxOROC3 /= dedx;
2167 dedxIROC = (dedxIROC > 0) ? std::log(dedxIROC) : -1;
2168 dedxOROC1 = (dedxOROC1 > 0) ? std::log(dedxOROC1) : -1;
2169 dedxOROC2 = (dedxOROC2 > 0) ? std::log(dedxOROC2) : -1;
2170 dedxOROC3 = (dedxOROC3 > 0) ? std::log(dedxOROC3) : -1;
2171
2172 // restrict to specified range
2173 if (std::abs(dedxIROC) > mMaxdEdxRegionRatio) {
2174 dedxIROC = -1;
2175 }
2176 if (std::abs(dedxOROC1) > mMaxdEdxRegionRatio) {
2177 dedxOROC1 = -1;
2178 }
2179 if (std::abs(dedxOROC2) > mMaxdEdxRegionRatio) {
2180 dedxOROC2 = -1;
2181 }
2182 if (std::abs(dedxOROC3) > mMaxdEdxRegionRatio) {
2183 dedxOROC3 = -1;
2184 }
2185 }
2186 return ValsdEdx{dedxNorm, dedxIROC, dedxOROC1, dedxOROC2, dedxOROC3};
2187 }
2188};
2189
2190o2::framework::DataProcessorSpec getTPCTimeSeriesSpec(const bool disableWriter, const o2::base::Propagator::MatCorrType matType, const bool enableUnbinnedWriter, GTrackID::mask_t src)
2191{
2192 auto dataRequest = std::make_shared<DataRequest>();
2193 bool useMC = false;
2194 GTrackID::mask_t srcTracks = GTrackID::getSourcesMask("TPC,ITS,ITS-TPC,ITS-TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD-TOF") & src;
2195 dataRequest->requestTracks(srcTracks, useMC);
2196 if (src[GTrackID::TPC]) {
2197 dataRequest->requestClusters(GTrackID::getSourcesMask("TPC"), useMC);
2198 }
2199 // D2: request TRD tracklets for tracks with TRD contribution
2200 if (srcTracks[GTrackID::ITSTPCTRD] || srcTracks[GTrackID::ITSTPCTRDTOF]) {
2201 dataRequest->requestTRDTracklets(useMC);
2202 }
2203
2204 bool tpcOnly = srcTracks == GTrackID::getSourcesMask("TPC");
2205 if (srcTracks.any() && !tpcOnly) {
2206 dataRequest->requestFT0RecPoints(useMC);
2207 dataRequest->requestPrimaryVertices(useMC);
2208 }
2209
2210 const bool enableAskMatLUT = matType == o2::base::Propagator::MatCorrType::USEMatCorrLUT;
2211 auto ccdbRequest = std::make_shared<o2::base::GRPGeomRequest>(!disableWriter, // orbitResetTime
2212 enableUnbinnedWriter, // GRPECS only when the unbinned trdInReadout can be written
2213 false, // GRPLHCIF
2214 true, // GRPMagField
2215 enableAskMatLUT, // askMatLUT
2217 dataRequest->inputs,
2218 true,
2219 true);
2220
2221 o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs);
2223 dataRequest->inputs.emplace_back("tpcSecFlucInfo", o2::header::gDataOriginTPC, "InfoMapSecFluc", 0, Lifetime::Condition, ccdbParamSpec(CDBTypeMap.at(CDBType::CalSecEdgeInfo), {}, 1));
2224
2225 std::vector<OutputSpec> outputs;
2226 outputs.emplace_back(o2::header::gDataOriginTPC, getDataDescriptionTimeSeries(), 0, Lifetime::Sporadic);
2227 if (!disableWriter) {
2228 outputs.emplace_back(o2::header::gDataOriginTPC, getDataDescriptionTPCTimeSeriesTFId(), 0, Lifetime::Sporadic);
2229 }
2230
2231 return DataProcessorSpec{
2232 "tpc-time-series",
2233 dataRequest->inputs,
2234 outputs,
2235 AlgorithmSpec{adaptFromTask<TPCTimeSeries>(ccdbRequest, disableWriter, matType, enableUnbinnedWriter, tpcOnly, dataRequest)},
2236 Options{
2237 {"min-momentum", VariantType::Float, 0.2f, {"Minimum momentum of the tracks"}},
2238 {"min-cluster", VariantType::Int, 80, {"Minimum number of clusters of the tracks"}},
2239 {"max-tgl", VariantType::Float, 1.4f, {"Maximum accepted tgl of the tracks"}},
2240 {"max-qPt", VariantType::Float, 5.f, {"Maximum abs(qPt) bin"}},
2241 {"max-snp", VariantType::Float, 0.85f, {"Maximum sinus(phi) for propagation"}},
2242 {"coarse-step", VariantType::Float, 5.f, {"Coarse step during track propagation"}},
2243 {"fine-step", VariantType::Float, 2.f, {"Fine step during track propagation"}},
2244 {"mX-coarse", VariantType::Float, 40.f, {"Perform coarse propagation up to this mx"}},
2245 {"max-tracks", VariantType::Int, -1, {"Number of maximum tracks to process"}},
2246 {"cut-DCA-median", VariantType::Float, 3.f, {"Cut on the DCA: abs(DCA-medianDCA)<cut-DCA-median"}},
2247 {"cut-DCA-RMS", VariantType::Float, 3.f, {"Sigma cut on the DCA"}},
2248 {"refX-for-sector", VariantType::Float, 108.475f, {"Reference local x position for the sector information (default centre of IROC)"}},
2249 {"refX-for-outer-ITS", VariantType::Float, 60.f, {"Reference local x position for matching at outer ITS"}},
2250 {"tgl-bins", VariantType::Int, 30, {"Number of tgl bins for time series variables"}},
2251 {"phi-bins", VariantType::Int, 54, {"Number of phi bins for time series variables"}},
2252 {"qPt-bins", VariantType::Int, 18, {"Number of qPt bins for time series variables"}},
2253 {"mult-bins", VariantType::Int, 25, {"Number of multiplicity bins for time series variables"}},
2254 {"mult-max", VariantType::Int, 50000, {"MAximum multiplicity bin"}},
2255 {"threads", VariantType::Int, 4, {"Number of parallel threads"}},
2256 {"max-ITS-TPC-DCAr", VariantType::Float, 0.2f, {"Maximum absolut DCAr value for ITS-TPC tracks"}},
2257 {"max-ITS-TPC-DCAz", VariantType::Float, 10.f, {"Maximum absolut DCAz value for ITS-TPC tracks - larger due to vertex spread"}},
2258 {"max-ITS-TPC-DCAr_comb", VariantType::Float, 0.2f, {"Maximum absolut DCAr value for ITS-TPC tracks to vertex for combined DCA"}},
2259 {"max-ITS-TPC-DCAz_comb", VariantType::Float, 0.2f, {"Maximum absolut DCAr value for ITS-TPC tracks to vertex for combined DCA"}},
2260 {"MIP-dedx", VariantType::Float, 50.f, {"MIP dEdx for MIP/dEdx monitoring"}},
2261 {"time-window-mult-mus", VariantType::Float, 50.f, {"Time window in micro s for multiplicity estimate"}},
2262 {"sqrts", VariantType::Float, 13600.f, {"Centre of mass energy used for downsampling"}},
2263 {"min-tracks-per-vertex", VariantType::Int, 6, {"Minimum number of tracks per vertex required"}},
2264 {"max-dedx-ratio", VariantType::Float, 0.3f, {"Maximum absolute log(dedx(pion)/dedx) ratio"}},
2265 {"max-dedx-region-ratio", VariantType::Float, 0.5f, {"Maximum absolute log(dedx(region)/dedx) ratio"}},
2266 {"sample-unbinned-tsallis", VariantType::Bool, false, {"Perform sampling of unbinned data based on Tsallis function"}},
2267 {"sampling-factor", VariantType::Float, 0.001f, {"Sampling factor in case sample-unbinned-tsallis is used"}},
2268 {"disable-min-bias-trigger", VariantType::Bool, false, {"Disable the minimum bias trigger for skimmed data"}},
2269 {"store-full-trackpar", VariantType::Bool, false, {"Experimental: store tpcOut, trdIn (common local X = 275 cm plane) and tpcAtVtx as TrackPar in the unbinned tree"}},
2270 {"out-file-unbinned", VariantType::String, "time_series_tracks.root", {"name of the output file for the unbinned data"}},
2271 {"max-occupancy-bins", VariantType::Int, 912, {"Maximum number of occupancy bins"}}}};
2272}
2273
2274} // namespace tpc
2275} // end namespace o2
std::vector< unsigned long > times
CDB Type definitions for TPC.
General auxilliary methods.
Wrapper container for different reconstructed object types.
o2d::GlobalTrackID GTrackID
Definition of the TOF cluster.
uint64_t vertex
Definition RawEventData.h:9
int16_t time
Definition RawEventData.h:4
Definition of the FIT RecPoints class.
int32_t i
Helper for geometry and GRP related CCDB requests.
float chi2
calibrator class for accumulating integrated clusters
Header to collect LHC related constants.
bounded_vector< float > bins
Class to store the output of the matching to TOF.
double lower[3]
int32_t nEntries
Definition Objects.cxx:40
Definition of the parameter class for the detector electronics.
Helper class to extract pressure and temperature.
uint32_t j
Definition RawData.h:0
uint32_t side
Definition RawData.h:0
uint32_t padrow
Definition RawData.h:5
class for performing robust averaging and outlier filtering
Class to parse and query time-dependent TPC sector edge fluctuation intervals.
Definition of the ITS track.
Result of refitting TPC-ITS matched track.
Helper class to extract VDrift from different sources.
Extention of GlobalTrackID by flags relevant for verter-track association.
Referenc on track indices contributing to the vertex, with possibility chose tracks from specific sou...
auto getOrbitResetTimeMS() const
void checkUpdates(o2::framework::ProcessingContext &pc)
bool finaliseCCDB(o2::framework::ConcreteDataMatcher &matcher, void *obj)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:180
static mask_t getSourcesMask(const std::string_view srcList)
Static class with identifiers, bitmasks and names for ALICE detectors.
Definition DetID.h:60
void snapshot(const Output &spec, T const &object)
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
Cluster class for TOF.
Definition Cluster.h:37
static constexpr unsigned int PADROWS
total number of pad rows
Definition Mapper.h:528
static void requestCCDBInputs(std::vector< o2::framework::InputSpec > &inputs)
float getPressure(const ULong64_t timestamp) const
get pressure for given time stamp in ms
void extractCCDBInputs(o2::framework::ProcessingContext &pc) const
trigger checking for CCDB objects
float getMeanTemperature(const ULong64_t timestamp) const
get mean temperature over A and C side
bool accountCCDBInputs(const o2::framework::ConcreteDataMatcher &matcher, void *obj)
check for new CCDB objects
size_t size() const
Total number of intervals across all runs.
std::vector< std::pair< int, float > > getSectorsAtTime(int run, Long64_t timestampMS) const
void setFromTree(TTree &tree, const int iEntry=0, const char *brName="SectorEdgeFluctuation")
set this object from input tree
size_t getNRuns() const
number of total runs stored
void finaliseCCDB(o2::framework::ConcreteDataMatcher &matcher, void *obj) final
static float chi2Match_Phi(const o2::track::TrackParCov &trk1, const o2::track::TrackParCov &trk2)
void run(ProcessingContext &pc) final
void init(framework::InitContext &ic) final
TPCTimeSeries(std::shared_ptr< o2::base::GRPGeomRequest > req, const bool disableWriter, const o2::base::Propagator::MatCorrType matType, const bool enableUnbinnedWriter, const bool tpcOnly, std::shared_ptr< o2::globaltracking::DataRequest > dr)
\constructor
void endOfStream(EndOfStreamContext &eos) final
static float chi2Match_Z(const o2::track::TrackParCov &trk1, const o2::track::TrackParCov &trk2)
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
bool accountCCDBInputs(const o2::framework::ConcreteDataMatcher &matcher, void *obj)
bool isUpdated() const
pid_constants::ID ID
Definition PID.h:92
GLdouble n
Definition glcorearb.h:1982
GLenum src
Definition glcorearb.h:1767
GLuint buffer
Definition glcorearb.h:655
GLuint GLuint GLfloat weight
Definition glcorearb.h:5477
GLsizei GLsizei GLchar * source
Definition glcorearb.h:798
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
GLuint GLfloat * val
Definition glcorearb.h:1582
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
Definition glcorearb.h:5034
GLint ref
Definition glcorearb.h:291
GLint GLuint mask
Definition glcorearb.h:291
GLsizei GLenum * sources
Definition glcorearb.h:2516
constexpr o2::header::DataOrigin gDataOriginTPC
Definition DataHeader.h:579
uint8_t int statusCode int
uint8_t itsSharedClusterMap uint8_t
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
std::vector< ConfigParamSpec > ccdbParamSpec(std::string const &path, int runDependent, std::vector< CCDBMetadata > metadata={}, int qrate=0)
GPUCA_B64_OP constexpr u64 div(u64 a, u64 b)
o2::tpc::PIDResponse PIDResponse
Definition PIDStudy.cxx:70
o2::track::TrackParCov int int int float int nCl
const bool const int TrackITSInternal< NLayers > & track
int angle2Sector(float phi)
Definition Utils.h:183
float sector2Angle(int sect)
Definition Utils.h:193
uint32_t getFirstTForbit(o2::framework::ProcessingContext &pc)
uint64_t getTimeStamp(o2::framework::ProcessingContext &pc)
uint64_t getRunNumber(o2::framework::ProcessingContext &pc)
const std::unordered_map< CDBType, const std::string > CDBTypeMap
Storage name in CCDB for each calibration and parameter type.
Definition CDBTypes.h:98
o2::framework::DataProcessorSpec getTPCTimeSeriesSpec(const bool disableWriter, const o2::base::Propagator::MatCorrType matType, const bool enableUnbinnedWriter, o2::dataformats::GlobalTrackID::mask_t src)
Side
TPC readout sidE.
Definition Defs.h:37
@ A
Definition Defs.h:37
@ C
Definition Defs.h:38
TrackParCovF TrackParCov
Definition Track.h:33
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
int64_t differenceInBC(const InteractionRecord &other) const
static void fillTFIDInfo(o2::framework::ProcessingContext &pc, o2::dataformats::TFIDInfo &ti)
const U & getTrack(int src, int id) const
GlobalIDSet getSingleDetectorRefs(GTrackID gidx) const
gsl::span< const o2::trd::CalibratedTracklet > getTRDCalibratedTracklets() const
gsl::span< const o2::trd::TriggerRecord > getTRDTriggerRecords() const
GTrackID getTPCContributorGID(GTrackID source) const
std::unique_ptr< o2::trd::RecoInputContainer > inputsTRD
void collectData(o2::framework::ProcessingContext &pc, const DataRequest &request)
const o2::track::TrackParCov & getTrackParamOut(GTrackID gidx) const
gsl::span< const unsigned int > occupancyMapTPC
externally set TPC clusters occupancy map
gsl::span< const o2::trd::Tracklet64 > getTRDTracklets() const
static bool downsampleTsallisCharged(float pt, float factorPt, float sqrts, float &weight, float rnd, float mass=0.13957)
Definition Tsallis.cxx:31
D2: per-track TRD tracklet lookup data.
std::vector< float > mDCAr_comb_A_RMS
DCAr RMS for ITS-TPC track - A-side.
std::vector< float > mTPCSigmaZ2A_RMS
sigmaZ2 RMS at vertex
std::vector< float > mSqrtITSChi2_Ncl_C_Median
sqrt(ITC chi2 / ncl)
ITSTPC_Matching mITSTPCAll
ITS-TPC matching efficiency for ITS standalone + afterburner.
std::vector< float > mITSTPCDeltaP4_C_RMS
RMS of track param TPC - track param ITS-TPC for param 4 - A-side.
std::vector< float > mTPCSigmaZ2C_RMS
sigmaZ2 RMS at vertex
TimeSeries mTSTPC
TPC standalone DCAs.
std::vector< float > mITSTPCDeltaP4_A_Median
track param TPC - track param ITS-TPC for param 4 - A-side
ITSTPC_Matching mITSTPCStandalone
ITS-TPC matching efficiency for ITS standalone.
std::vector< float > mITSTPCDeltaP4_C_Median
track param TPC - track param ITS-TPC for param 4 - A-side
std::vector< float > mITSTPCDeltaP3_A_RMS
RMS of track param TPC - track param ITS-TPC for param 3 - A-side.
std::vector< float > mITS_A_NCl_Median
its number of clusters
std::vector< float > mDCAr_comb_C_Median
DCAr for ITS-TPC track - C-side.
std::vector< float > mSqrtITSChi2_Ncl_A_Median
sqrt(ITC chi2 / ncl)
std::vector< float > mSqrtITSChi2_Ncl_C_RMS
sqrt(ITC chi2 / ncl)
std::vector< float > mDCAz_comb_A_RMS
DCAz RMS for ITS-TPC track - A-side.
std::vector< float > mITSTPCDeltaP2_C_RMS
RMS of track param TPC - track param ITS-TPC for param 2 - A-side.
std::vector< float > mITSTPCDeltaP3_A_Median
track param TPC - track param ITS-TPC for param 3 - A-side
void resize(const unsigned int nTotal)
resize buffer for accumulated currents
std::vector< float > mITSTPCDeltaP2_A_Median
track param TPC - track param ITS-TPC for param 2 - A-side
std::vector< float > mSqrtITSChi2_Ncl_A_RMS
sqrt(ITC chi2 / ncl)
std::vector< float > mITSTPCDeltaP2_C_Median
track param TPC - track param ITS-TPC for param 2 - A-side
std::vector< unsigned int > mOccupancyMapTPC
cluster occupancy map
std::vector< std::pair< int, float > > mSecEdgeFlucCorr
applied sector edge fluctuation correction
std::vector< float > mITSTPCDeltaP4_A_RMS
RMS of track param TPC - track param ITS-TPC for param 4 - A-side.
std::vector< float > mTPCSigmaY2A_Median
sigmaY2 at vertex
std::vector< float > mITSTPCDeltaP3_C_RMS
RMS of track param TPC - track param ITS-TPC for param 3 - A-side.
TimeSeries mTSITSTPC
ITS-TPC standalone DCAs.
std::vector< float > mTPCSigmaY2C_Median
sigmaY2 at vertex
std::vector< float > mTPCSigmaZ2C_Median
sigmaZ2 at vertex
std::vector< float > mITS_C_NCl_RMS
its number of clusters
std::vector< float > mDCAz_comb_A_Median
DCAz for ITS-TPC track - A-side.
std::vector< float > mDCAz_comb_C_RMS
DCAz RMS for ITS-TPC track - C-side.
ITSTPC_Matching mITSTPCAfterburner
ITS-TPC matchin efficiency fir ITS afterburner.
std::vector< float > mTPCSigmaY2C_RMS
sigmaY2 RMS at vertex
std::vector< float > mITSTPCDeltaP3_C_Median
track param TPC - track param ITS-TPC for param 3 - A-side
std::vector< float > mDCAz_comb_C_Median
DCAz for ITS-TPC track - C-side.
std::vector< float > mTPCSigmaZ2A_Median
sigmaZ2 at vertex
std::vector< float > mDCAr_comb_C_RMS
DCAr RMS for ITS-TPC track - C-side.
float mVDrift
drift velocity in cm/us
std::vector< float > mITS_C_NCl_Median
its number of clusters
TimeSeriesdEdx mdEdxQTot
time series for dE/dx qTot monitoring
std::vector< float > mITS_A_NCl_RMS
its number of clusters
std::vector< float > mITSTPCDeltaP2_A_RMS
RMS of track param TPC - track param ITS-TPC for param 2 - A-side.
std::vector< float > mTPCSigmaY2A_RMS
sigmaY2 RMS at vertex
std::vector< float > mDCAr_comb_A_Median
DCAr for ITS-TPC track - A-side.
void setBinning(const int nBinsPhi, const int nBinsTgl, const int qPtBins, const int nBinsMult, float tglMax, float qPtMax, float multMax)
TimeSeriesdEdx mdEdxQMax
time series for dE/dx qMax monitoring
int getIndexInt(int slice=0) const
std::vector< float > mDCAr_C_Median
integrated 1D DCAr for C-side weighted mean in phi/tgl slices
std::vector< float > mDCAz_A_RMS
integrated 1D DCAz for A-side RMS in phi/tgl slices
std::vector< float > mDCAz_C_Median
integrated 1D DCAz for C-side median in phi/tgl slices
int getIndexPhi(const int iPhi, int slice=0) const
std::vector< float > mDCAz_A_Median
integrated 1D DCAz for A-side median in phi/tgl slices
std::vector< float > mDCAr_C_RMS
integrated 1D DCAr for C-side RMS in phi/tgl slices
std::vector< float > mDCAr_A_Median
integrated 1D DCAr for A-side median in phi/tgl slices
int getIndexTgl(const int iTgl, int slice=0) const
std::vector< float > mMIPdEdxRatioQMaxA
ratio of MIP/dEdx - qMax -
std::vector< float > mDCAz_C_RMS
integrated 1D DCAz for C-side RMS in phi/tgl slices
int getIndexqPt(const int iqPt, int slice=0) const
std::vector< float > mDCAr_A_RMS
integrated 1D DCAr for A-side RMS in phi/tgl slices
int getIndexMult(const int iMult, int slice=0) const
std::vector< float > mLogdEdx_A_Median
log(dEdx_exp(pion)/dEdx) - A-side
o2::InteractionRecord ir(0, 0)
vec clear()
std::uniform_int_distribution< unsigned long long > distr