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"
40#include <random>
41#include <chrono>
44#include "TROOT.h"
51
52using namespace o2::globaltracking;
56using namespace o2::framework;
57
58namespace o2
59{
60namespace tpc
61{
62
63class TPCTimeSeries : public Task
64{
65 public:
67 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) {};
68
70 {
72 mNMaxTracks = ic.options().get<int>("max-tracks");
73 mMinMom = ic.options().get<float>("min-momentum");
74 mMinNCl = ic.options().get<int>("min-cluster");
75 mMaxTgl = ic.options().get<float>("max-tgl");
76 mMaxQPt = ic.options().get<float>("max-qPt");
77 mCoarseStep = ic.options().get<float>("coarse-step");
78 mFineStep = ic.options().get<float>("fine-step");
79 mCutDCA = ic.options().get<float>("cut-DCA-median");
80 mCutRMS = ic.options().get<float>("cut-DCA-RMS");
81 mRefXSec = ic.options().get<float>("refX-for-sector");
82 mTglBins = ic.options().get<int>("tgl-bins");
83 mPhiBins = ic.options().get<int>("phi-bins");
84 mQPtBins = ic.options().get<int>("qPt-bins");
85 mNThreads = ic.options().get<int>("threads");
86 maxITSTPCDCAr = ic.options().get<float>("max-ITS-TPC-DCAr");
87 maxITSTPCDCAz = ic.options().get<float>("max-ITS-TPC-DCAz");
88 maxITSTPCDCAr_comb = ic.options().get<float>("max-ITS-TPC-DCAr_comb");
89 maxITSTPCDCAz_comb = ic.options().get<float>("max-ITS-TPC-DCAz_comb");
90 mTimeWindowMUS = ic.options().get<float>("time-window-mult-mus");
91 mMIPdEdx = ic.options().get<float>("MIP-dedx");
92 mMaxSnp = ic.options().get<float>("max-snp");
93 mXCoarse = ic.options().get<float>("mX-coarse");
94 mSqrt = ic.options().get<float>("sqrts");
95 mMultBins = ic.options().get<int>("mult-bins");
96 mMultMax = ic.options().get<int>("mult-max");
97 mMinTracksPerVertex = ic.options().get<int>("min-tracks-per-vertex");
98 mMaxdEdxRatio = ic.options().get<float>("max-dedx-ratio");
99 mMaxdEdxRegionRatio = ic.options().get<float>("max-dedx-region-ratio");
100 mSamplingFactor = ic.options().get<float>("sampling-factor");
101 mSampleTsallis = ic.options().get<bool>("sample-unbinned-tsallis");
102 mXOuterMatching = ic.options().get<float>("refX-for-outer-ITS");
103 mUseMinBiasTrigger = !ic.options().get<bool>("disable-min-bias-trigger");
104 mMaxOccupancyHistBins = ic.options().get<int>("max-occupancy-bins");
105
106 if (mUnbinnedWriter) {
107 for (int iThread = 0; iThread < mNThreads; ++iThread) {
108 mGenerator.emplace_back(std::mt19937(std::random_device{}()));
109 }
110 }
111 mBufferVals.resize(mNThreads);
112 mBufferDCA.setBinning(mPhiBins, mTglBins, mQPtBins, mMultBins, mMaxTgl, mMaxQPt, mMultMax);
113 if (mUnbinnedWriter) {
114 std::string outfile = ic.options().get<std::string>("out-file-unbinned");
115 if (mNThreads > 1) {
116 ROOT::EnableThreadSafety();
117 }
118 mStreamer.resize(mNThreads);
119 for (int iThread = 0; iThread < mNThreads; ++iThread) {
120 std::string outfileThr = outfile;
121 outfileThr.replace(outfileThr.length() - 5, outfileThr.length(), fmt::format("_{}.root", iThread));
122 LOGP(info, "Writing unbinned data to: {}", outfileThr);
123 mStreamer[iThread] = std::make_unique<o2::utils::TreeStreamRedirector>(outfileThr.data(), "recreate");
124 }
125 }
126 }
127
128 void run(ProcessingContext& pc) final
129 {
131 mTPCVDriftHelper.extractCCDBInputs(pc);
132 mPTHelper.extractCCDBInputs(pc);
133 if (mTPCVDriftHelper.isUpdated()) {
134 mTPCVDriftHelper.acknowledgeUpdate();
135 mVDrift = mTPCVDriftHelper.getVDriftObject().getVDrift();
136 LOGP(info, "Updated reference drift velocity to: {}", mVDrift);
137 }
138 pc.inputs().get<TTree*>("tpcSecFlucInfo");
139 mBufferDCA.mVDrift = mVDrift;
140
141 const int nBins = getNBins();
142
145 mBufferDCA.mSecEdgeFlucCorr = mSecEdgeFlucInfo.getSectorsAtTime(mRun, static_cast<long>(mTimeMS));
146 mBufferDCA.mTemperature = mPTHelper.getMeanTemperature(mTimeMS);
147 mBufferDCA.mPressure = mPTHelper.getPressure(mTimeMS);
148
149 // init only once
150 if (mAvgADCAr.size() != nBins) {
151 mBufferDCA.resize(nBins);
152 mAvgADCAr.resize(nBins);
153 mAvgCDCAr.resize(nBins);
154 mAvgADCAz.resize(nBins);
155 mAvgCDCAz.resize(nBins);
156 mAvgMeffA.resize(nBins);
157 mAvgMeffC.resize(nBins);
158 mAvgChi2MatchA.resize(nBins);
159 mAvgChi2MatchC.resize(nBins);
160 mMIPdEdxRatioQMaxA.resize(nBins);
161 mMIPdEdxRatioQMaxC.resize(nBins);
162 mMIPdEdxRatioQTotA.resize(nBins);
163 mMIPdEdxRatioQTotC.resize(nBins);
164 mTPCChi2A.resize(nBins);
165 mTPCChi2C.resize(nBins);
166 mTPCNClA.resize(nBins);
167 mTPCNClC.resize(nBins);
168 mLogdEdxQTotA.resize(nBins);
169 mLogdEdxQTotC.resize(nBins);
170 mLogdEdxQMaxA.resize(nBins);
171 mLogdEdxQMaxC.resize(nBins);
172 mITSPropertiesA.resize(nBins);
173 mITSPropertiesC.resize(nBins);
174 mITSTPCDeltaPA.resize(nBins);
175 mITSTPCDeltaPC.resize(nBins);
176 mSigmaYZA.resize(nBins);
177 mSigmaYZC.resize(nBins);
178 }
179
180 RecoContainer recoData;
181 recoData.collectData(pc, *mDataRequest.get());
182
183 // getting tracks
184 auto tracksTPC = recoData.getTPCTracks();
185 auto tracksITSTPC = mTPCOnly ? gsl::span<o2::dataformats::TrackTPCITS>() : recoData.getTPCITSTracks();
186 auto tracksITS = mTPCOnly ? gsl::span<o2::its::TrackITS>() : recoData.getITSTracks();
187
188 // getting the vertices
189 auto vertices = mTPCOnly ? gsl::span<o2::dataformats::PrimaryVertex>() : recoData.getPrimaryVertices();
190 auto primMatchedTracks = mTPCOnly ? gsl::span<o2::dataformats::VtxTrackIndex>() : recoData.getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks
191 auto primMatchedTracksRef = mTPCOnly ? gsl::span<o2::dataformats::VtxTrackRef>() : recoData.getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs
192
193 // get occupancy map
194 mBufferDCA.mOccupancyMapTPC = std::vector<unsigned int>(recoData.occupancyMapTPC.begin(), recoData.occupancyMapTPC.end());
195 if (mBufferDCA.mOccupancyMapTPC.size() > mMaxOccupancyHistBins) {
196 mBufferDCA.mOccupancyMapTPC.resize(mMaxOccupancyHistBins);
197 }
198
199 // TOF clusters
200 const auto& tofClusters = mTPCOnly ? gsl::span<o2::tof::Cluster>() : recoData.getTOFClusters();
201
202 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());
203
204 // calculate mean vertex, RMS and count vertices
205 auto indicesITSTPC_vtx = processVertices(vertices, primMatchedTracks, primMatchedTracksRef, recoData);
206
207 // storing indices to ITS-TPC tracks and vertex ID for tpc track
208 std::unordered_map<unsigned int, std::array<int, 2>> indicesITSTPC; // TPC track index -> ITS-TPC track index, vertex ID
209 // loop over all ITS-TPC tracks
210 for (int i = 0; i < tracksITSTPC.size(); ++i) {
211 auto it = indicesITSTPC_vtx.find(i);
212 // check if ITS-TPC track has attached vertex
213 const auto idxVtx = (it != indicesITSTPC_vtx.end()) ? (it->second) : -1;
214 // store TPC index and ITS-TPC+vertex index
215 indicesITSTPC[tracksITSTPC[i].getRefTPC().getIndex()] = {i, idxVtx};
216 }
217
218 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
219
220 // get matches to TOF in case skimmed data is produced
221 if (mUnbinnedWriter) {
222 // getLTIntegralOut(), ///< L,TOF integral calculated during the propagation
223 // getSignal() mSignal = 0.0; ///< TOF time in ps
225 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});
226 const std::vector<gsl::span<const o2::dataformats::MatchInfoTOF>> tofMatches{recoData.getTPCTOFMatches(), recoData.getTPCTRDTOFMatches(), recoData.getITSTPCTOFMatches(), recoData.getITSTPCTRDTOFMatches()};
227
228 const auto& ft0rec = recoData.getFT0RecPoints();
229 // fill available FT0-AC event times vs BClong
230 std::map<ULong64_t, short> t0array;
231 for (const auto& t0 : ft0rec) {
232 if (!(t0.isValidTime(1) && t0.isValidTime(2))) { // skip if !(A & C)
233 continue;
234 }
235
236 auto bclong = t0.mIntRecord.differenceInBC(recoData.startIR);
237 if (t0array.find(bclong) == t0array.end()) { // add if it doesn't exist
238 t0array.emplace(std::make_pair(bclong, t0.getCollisionTime(0)));
239 }
240 }
241
242 static const double BC_TIME_INPS_INV = 1E-3 / o2::constants::lhc::LHCBunchSpacingNS;
243
244 // loop over ITS-TPC-TRD-TOF and ITS-TPC-TOF tracks an store for each ITS-TPC track the TOF track index
245 for (const auto& tofMatch : tofMatches) {
246 for (const auto& tpctofmatch : tofMatch) {
247 auto refTPC = recoData.getTPCContributorGID(tpctofmatch.getTrackRef());
248 if (refTPC.isIndexSet()) {
249 o2::track::TrackLTIntegral ltIntegral = tpctofmatch.getLTIntegralOut();
250 ULong64_t bclongtof = (tpctofmatch.getSignal() - 10000) * BC_TIME_INPS_INV;
251 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)
252 unsigned int mask = 0;
253 if (!(t0array.find(bclongtof) == t0array.end())) { // subtract FT0-AC if it exists in the same BC
254 t0 += t0array.find(bclongtof)->second;
255 mask |= o2::dataformats::MatchInfoTOF::QualityFlags::hasT0sameBC; // 8th bit if FT0-AC in same BC
256 }
257
258 double signal = tpctofmatch.getSignal() - t0;
259 float deltaT = tpctofmatch.getDeltaT();
260
261 float dy = tpctofmatch.getDYatTOF(); // residual orthogonal to the strip (it should be close to zero)
262 bool isMultiHitZ = tpctofmatch.getHitPatternUpDown();
263 bool isMultiHitX = tpctofmatch.getHitPatternLeftRight();
264 bool isMultiStripMatch = tpctofmatch.getChi2() < 1E-9;
265 float chi2 = tpctofmatch.getChi2();
266 bool hasT0_1BCbefore = (t0array.find(bclongtof - 1) != t0array.end());
267 bool hasT0_2BCbefore = (t0array.find(bclongtof - 2) != t0array.end());
268
269 if (isMultiHitX) { // 1nd bit on if multiple hits along X
271 }
272 if (isMultiHitZ) { // 2nd bit on if multiple hits along Z
274 }
275 if (fabs(dy) > 0.5) { // 3rd bit on if Y-residual too large
277 }
278 if (isMultiStripMatch) { // 4th bit on if two strips fired
280 }
281 if (chi2 > 1E-4) { // 5th bit on if chi2 > 1E-4 -> not inside the pad
283 }
284 if (chi2 > 3) { // 6th bit on if chi2 > 3
286 }
287 if (chi2 > 5) { // 7th bit on if chi2 > 5
289 }
290 if (hasT0_1BCbefore) { // 9th bit if FT0-AC also BC before
292 }
293 if (hasT0_2BCbefore) { // 10th bit if FT0-AC also 2BCs before
295 }
296
297 idxTPCTrackToTOFCluster[refTPC] = {tpctofmatch.getIdxTOFCl(), tpctofmatch.getDXatTOF(), tpctofmatch.getDZatTOF(), ltIntegral, signal, deltaT, mask, tpctofmatch.getChannel() % 8736};
298 }
299 }
300 }
301 }
302
303 // find nearest vertex of tracks which have no vertex assigned
304 findNearesVertex(tracksTPC, vertices);
305
306 // getting cluster references for cluster bitmask
307 if (mUnbinnedWriter) {
308 mTPCTrackClIdx = pc.inputs().get<gsl::span<o2::tpc::TPCClRefElem>>("trackTPCClRefs");
309 mFirstTFOrbit = processing_helpers::getFirstTForbit(pc);
310 }
311
312 // get local multiplicity - count neighbouring tracks
313 findNNeighbourTracks(tracksTPC);
314
315 // reset buffers
316 for (int i = 0; i < nBins; ++i) {
317 for (int type = 0; type < mAvgADCAr[i].size(); ++type) {
318 mAvgADCAr[i][type].clear();
319 mAvgCDCAr[i][type].clear();
320 mAvgADCAz[i][type].clear();
321 mAvgCDCAz[i][type].clear();
322 }
323 for (int type = 0; type < mMIPdEdxRatioQMaxA[i].size(); ++type) {
324 mMIPdEdxRatioQMaxA[i][type].clear();
325 mMIPdEdxRatioQMaxC[i][type].clear();
326 mMIPdEdxRatioQTotA[i][type].clear();
327 mMIPdEdxRatioQTotC[i][type].clear();
328 mTPCChi2A[i][type].clear();
329 mTPCChi2C[i][type].clear();
330 mTPCNClA[i][type].clear();
331 mTPCNClC[i][type].clear();
332 mMIPdEdxRatioQMaxA[i][type].setUseWeights(false);
333 mMIPdEdxRatioQMaxC[i][type].setUseWeights(false);
334 mMIPdEdxRatioQTotA[i][type].setUseWeights(false);
335 mMIPdEdxRatioQTotC[i][type].setUseWeights(false);
336 mTPCChi2A[i][type].setUseWeights(false);
337 mTPCChi2C[i][type].setUseWeights(false);
338 mTPCNClA[i][type].setUseWeights(false);
339 mTPCNClC[i][type].setUseWeights(false);
340 }
341 for (int type = 0; type < mLogdEdxQTotA[i].size(); ++type) {
342 mLogdEdxQTotA[i][type].clear();
343 mLogdEdxQTotC[i][type].clear();
344 mLogdEdxQMaxA[i][type].clear();
345 mLogdEdxQMaxC[i][type].clear();
346 mLogdEdxQTotA[i][type].setUseWeights(false);
347 mLogdEdxQTotC[i][type].setUseWeights(false);
348 mLogdEdxQMaxA[i][type].setUseWeights(false);
349 mLogdEdxQMaxC[i][type].setUseWeights(false);
350 }
351 for (int j = 0; j < mITSPropertiesA[i].size(); ++j) {
352 mITSPropertiesA[i][j].clear();
353 mITSPropertiesC[i][j].clear();
354 mITSPropertiesA[i][j].setUseWeights(false);
355 mITSPropertiesC[i][j].setUseWeights(false);
356 }
357
358 for (int j = 0; j < mITSTPCDeltaPA[i].size(); ++j) {
359 mITSTPCDeltaPA[i][j].clear();
360 mITSTPCDeltaPC[i][j].clear();
361 mITSTPCDeltaPA[i][j].setUseWeights(false);
362 mITSTPCDeltaPC[i][j].setUseWeights(false);
363 }
364
365 for (int j = 0; j < mSigmaYZA[i].size(); ++j) {
366 mSigmaYZA[i][j].clear();
367 mSigmaYZC[i][j].clear();
368 mSigmaYZA[i][j].setUseWeights(false);
369 mSigmaYZC[i][j].setUseWeights(false);
370 }
371
372 for (int j = 0; j < mAvgMeffA[i].size(); ++j) {
373 mAvgMeffA[i][j].clear();
374 mAvgMeffC[i][j].clear();
375 mAvgChi2MatchA[i][j].clear();
376 mAvgChi2MatchC[i][j].clear();
377 mAvgMeffA[i][j].setUseWeights(false);
378 mAvgMeffC[i][j].setUseWeights(false);
379 mAvgChi2MatchA[i][j].setUseWeights(false);
380 mAvgChi2MatchC[i][j].setUseWeights(false);
381 }
382 }
383
384 for (int i = 0; i < mNThreads; ++i) {
385 mBufferVals[i].front().clear();
386 mBufferVals[i].back().clear();
387 }
388
389 // define number of tracks which are used
390 const auto nTracks = tracksTPC.size();
391 const size_t loopEnd = (mNMaxTracks < 0) ? nTracks : ((mNMaxTracks > nTracks) ? nTracks : size_t(mNMaxTracks));
392
393 // reserve memory
394 for (int i = 0; i < nBins; ++i) {
395 const int lastIdxPhi = mBufferDCA.mTSTPC.getIndexPhi(mPhiBins);
396 const int lastIdxTgl = mBufferDCA.mTSTPC.getIndexTgl(mTglBins);
397 const int lastIdxQPt = mBufferDCA.mTSTPC.getIndexqPt(mQPtBins);
398 const int lastIdxMult = mBufferDCA.mTSTPC.getIndexMult(mMultBins);
399 const int firstIdx = mBufferDCA.mTSTPC.getIndexInt();
400 int resMem = 0;
401 if (i < lastIdxPhi) {
402 resMem = loopEnd / mPhiBins;
403 } else if (i < lastIdxTgl) {
404 resMem = loopEnd / mTglBins;
405 } else if (i < lastIdxQPt) {
406 resMem = loopEnd / mQPtBins;
407 } else if (i < lastIdxMult) {
408 resMem = loopEnd / mMultBins;
409 } else {
410 resMem = loopEnd;
411 }
412 // Divide by 2 for A-C-side
413 resMem /= 2;
414 for (int type = 0; type < mAvgADCAr[i].size(); ++type) {
415 mAvgADCAr[i][type].reserve(resMem);
416 mAvgCDCAr[i][type].reserve(resMem);
417 mAvgADCAz[i][type].reserve(resMem);
418 mAvgCDCAz[i][type].reserve(resMem);
419 }
420 for (int type = 0; type < mMIPdEdxRatioQMaxA[i].size(); ++type) {
421 mMIPdEdxRatioQMaxA[i][type].reserve(resMem);
422 mMIPdEdxRatioQMaxC[i][type].reserve(resMem);
423 mMIPdEdxRatioQTotA[i][type].reserve(resMem);
424 mMIPdEdxRatioQTotC[i][type].reserve(resMem);
425 mTPCChi2A[i][type].reserve(resMem);
426 mTPCChi2C[i][type].reserve(resMem);
427 mTPCNClA[i][type].reserve(resMem);
428 mTPCNClC[i][type].reserve(resMem);
429 }
430 for (int j = 0; j < mAvgMeffA[i].size(); ++j) {
431 mAvgMeffA[i][j].reserve(resMem);
432 mAvgMeffC[i][j].reserve(resMem);
433 mAvgChi2MatchA[i][j].reserve(resMem);
434 mAvgChi2MatchC[i][j].reserve(resMem);
435 }
436 for (int j = 0; j < mITSPropertiesA[i].size(); ++j) {
437 mITSPropertiesA[i][j].reserve(resMem);
438 mITSPropertiesC[i][j].reserve(resMem);
439 }
440 for (int j = 0; j < mITSTPCDeltaPA[i].size(); ++j) {
441 mITSTPCDeltaPA[i][j].reserve(resMem);
442 mITSTPCDeltaPC[i][j].reserve(resMem);
443 }
444 for (int j = 0; j < mSigmaYZA[i].size(); ++j) {
445 mSigmaYZA[i][j].reserve(resMem);
446 mSigmaYZC[i][j].reserve(resMem);
447 }
448 for (int j = 0; j < mAvgMeffA[i].size(); ++j) {
449 mLogdEdxQTotA[i][j].reserve(resMem);
450 mLogdEdxQTotC[i][j].reserve(resMem);
451 mLogdEdxQMaxA[i][j].reserve(resMem);
452 mLogdEdxQMaxC[i][j].reserve(resMem);
453 }
454 }
455 for (int iThread = 0; iThread < mNThreads; ++iThread) {
456 const int resMem = (mNThreads > 0) ? loopEnd / mNThreads : loopEnd;
457 mBufferVals[iThread].front().reserve(loopEnd, 1);
458 mBufferVals[iThread].back().reserve(loopEnd, 0);
459 }
460
461 using timer = std::chrono::high_resolution_clock;
462 auto startTotal = timer::now();
463
464 // loop over tracks and calculate DCAs
465 if (loopEnd < nTracks) {
466 // draw random tracks
467 std::vector<size_t> ind(nTracks);
468 std::iota(ind.begin(), ind.end(), 0);
469 std::minstd_rand rng(std::time(nullptr));
470 std::shuffle(ind.begin(), ind.end(), rng);
471
472 auto myThread = [&](int iThread) {
473 for (size_t i = iThread; i < loopEnd; i += mNThreads) {
474 if (acceptTrack(tracksTPC[i])) {
475 fillDCA(tracksTPC, tracksITSTPC, vertices, i, iThread, indicesITSTPC, tracksITS, idxTPCTrackToTOFCluster, tofClusters);
476 }
477 }
478 };
479
480 std::vector<std::thread> threads(mNThreads);
481 for (int i = 0; i < mNThreads; i++) {
482 threads[i] = std::thread(myThread, i);
483 }
484
485 for (auto& th : threads) {
486 th.join();
487 }
488 } else {
489 auto myThread = [&](int iThread) {
490 for (size_t i = iThread; i < loopEnd; i += mNThreads) {
491 if (acceptTrack(tracksTPC[i])) {
492 fillDCA(tracksTPC, tracksITSTPC, vertices, i, iThread, indicesITSTPC, tracksITS, idxTPCTrackToTOFCluster, tofClusters);
493 }
494 }
495 };
496
497 std::vector<std::thread> threads(mNThreads);
498 for (int i = 0; i < mNThreads; i++) {
499 threads[i] = std::thread(myThread, i);
500 }
501
502 for (auto& th : threads) {
503 th.join();
504 }
505 }
506
507 // fill DCA values from buffer
508 for (const auto& vals : mBufferVals) {
509 for (int type = 0; type < vals.size(); ++type) {
510 const auto& val = vals[type];
511 const auto nPoints = val.side.size();
512 for (int i = 0; i < nPoints; ++i) {
513 const auto tglBin = val.tglBin[i];
514 const auto phiBin = val.phiBin[i];
515 const auto qPtBin = val.qPtBin[i];
516 const auto multBin = val.multBin[i];
517 const auto dcar = val.dcar[i];
518 const auto dcaz = val.dcaz[i];
519 const auto dcarW = val.dcarW[i];
520 const int binInt = nBins - 1;
521 const bool fillCombDCA = ((type == 1) && (val.dcarcomb[i] != -1) && (val.dcazcomb[i] != -1));
522 const bool fillDCAR = (type == 1) ? (dcar != -999) : true;
523 const std::array<int, 5> bins{tglBin, phiBin, qPtBin, multBin, binInt};
524 // fill bins
525 for (auto bin : bins) {
526 if (val.side[i] == Side::C) {
527 if (fillDCAR) {
528 mAvgCDCAr[bin][type].addValue(dcar, dcarW);
529 }
530 if (fillCombDCA) {
531 mAvgCDCAr[bin][2].addValue(val.dcarcomb[i], dcarW);
532 mAvgCDCAz[bin][2].addValue(val.dcazcomb[i], dcarW);
533 }
534 // fill only in case of valid value
535 if (dcaz != 0) {
536 mAvgCDCAz[bin][type].addValue(dcaz, dcarW);
537 }
538 } else {
539 if (fillDCAR) {
540 mAvgADCAr[bin][type].addValue(dcar, dcarW);
541 }
542 if (fillCombDCA) {
543 mAvgADCAr[bin][2].addValue(val.dcarcomb[i], dcarW);
544 mAvgADCAz[bin][2].addValue(val.dcazcomb[i], dcarW);
545 }
546 // fill only in case of valid value
547 if (dcaz != 0) {
548 mAvgADCAz[bin][type].addValue(dcaz, dcarW);
549 }
550 }
551 }
552 }
553 }
554 }
555
556 // calculate statistics and store values
557 // loop over TPC sides
558 for (int type = 0; type < 2; ++type) {
559 // loop over phi and tgl bins
560 for (int slice = 0; slice < nBins; ++slice) {
561 auto& bufferDCA = (type == 0) ? mBufferDCA.mTSTPC : mBufferDCA.mTSITSTPC;
562
563 const auto dcaAr = mAvgADCAr[slice][type].filterPointsMedian(mCutDCA, mCutRMS);
564 bufferDCA.mDCAr_A_Median[slice] = std::get<0>(dcaAr);
565 bufferDCA.mDCAr_A_WeightedMean[slice] = std::get<1>(dcaAr);
566 bufferDCA.mDCAr_A_RMS[slice] = std::get<2>(dcaAr);
567 bufferDCA.mDCAr_A_NTracks[slice] = std::get<3>(dcaAr);
568
569 const auto dcaAz = mAvgADCAz[slice][type].filterPointsMedian(mCutDCA, mCutRMS);
570 bufferDCA.mDCAz_A_Median[slice] = std::get<0>(dcaAz);
571 bufferDCA.mDCAz_A_WeightedMean[slice] = std::get<1>(dcaAz);
572 bufferDCA.mDCAz_A_RMS[slice] = std::get<2>(dcaAz);
573 bufferDCA.mDCAz_A_NTracks[slice] = std::get<3>(dcaAz);
574
575 const auto dcaCr = mAvgCDCAr[slice][type].filterPointsMedian(mCutDCA, mCutRMS);
576 bufferDCA.mDCAr_C_Median[slice] = std::get<0>(dcaCr);
577 bufferDCA.mDCAr_C_WeightedMean[slice] = std::get<1>(dcaCr);
578 bufferDCA.mDCAr_C_RMS[slice] = std::get<2>(dcaCr);
579 bufferDCA.mDCAr_C_NTracks[slice] = std::get<3>(dcaCr);
580
581 const auto dcaCz = mAvgCDCAz[slice][type].filterPointsMedian(mCutDCA, mCutRMS);
582 bufferDCA.mDCAz_C_Median[slice] = std::get<0>(dcaCz);
583 bufferDCA.mDCAz_C_WeightedMean[slice] = std::get<1>(dcaCz);
584 bufferDCA.mDCAz_C_RMS[slice] = std::get<2>(dcaCz);
585 bufferDCA.mDCAz_C_NTracks[slice] = std::get<3>(dcaCz);
586 // store combined ITS-TPC DCAs
587 if (type == 1) {
588 const auto dcaArComb = mAvgADCAr[slice][2].filterPointsMedian(mCutDCA, mCutRMS);
589 mBufferDCA.mDCAr_comb_A_Median[slice] = std::get<0>(dcaArComb);
590 mBufferDCA.mDCAr_comb_A_RMS[slice] = std::get<2>(dcaArComb);
591
592 const auto dcaAzCom = mAvgADCAz[slice][2].filterPointsMedian(mCutDCA, mCutRMS);
593 mBufferDCA.mDCAz_comb_A_Median[slice] = std::get<0>(dcaAzCom);
594 mBufferDCA.mDCAz_comb_A_RMS[slice] = std::get<2>(dcaAzCom);
595
596 const auto dcaCrComb = mAvgCDCAr[slice][2].filterPointsMedian(mCutDCA, mCutRMS);
597 mBufferDCA.mDCAr_comb_C_Median[slice] = std::get<0>(dcaCrComb);
598 mBufferDCA.mDCAr_comb_C_RMS[slice] = std::get<2>(dcaCrComb);
599
600 const auto dcaCzComb = mAvgCDCAz[slice][2].filterPointsMedian(mCutDCA, mCutRMS);
601 mBufferDCA.mDCAz_comb_C_Median[slice] = std::get<0>(dcaCzComb);
602 mBufferDCA.mDCAz_comb_C_RMS[slice] = std::get<2>(dcaCzComb);
603 }
604 }
605 }
606
607 // calculate matching eff
608 for (const auto& vals : mBufferVals) {
609 const auto& val = vals.front();
610 const auto nPoints = val.side.size();
611 for (int i = 0; i < nPoints; ++i) {
612 const auto tglBin = val.tglBin[i];
613 const auto phiBin = val.phiBin[i];
614 const auto qPtBin = val.qPtBin[i];
615 const auto multBin = val.multBin[i];
616 const auto dcar = val.dcar[i];
617 const auto dcaz = val.dcaz[i];
618 const auto hasITS = val.hasITS[i];
619 const auto chi2Match = val.chi2Match[i];
620 const auto dedxRatioqMax = val.dedxRatioqMax[i];
621 const auto dedxRatioqTot = val.dedxRatioqTot[i];
622 const auto sqrtChi2TPC = val.sqrtChi2TPC[i];
623 const auto nClTPC = val.nClTPC[i];
624 const int binInt = nBins - 1;
625 const Side side = val.side[i];
626 const bool isCSide = (side == Side::C);
627 const auto& bufferDCARMSR = isCSide ? mBufferDCA.mTSTPC.mDCAr_C_RMS : mBufferDCA.mTSTPC.mDCAr_A_RMS;
628 const auto& bufferDCARMSZ = isCSide ? mBufferDCA.mTSTPC.mDCAz_C_RMS : mBufferDCA.mTSTPC.mDCAz_A_RMS;
629 const auto& bufferDCAMedR = isCSide ? mBufferDCA.mTSTPC.mDCAr_C_Median : mBufferDCA.mTSTPC.mDCAr_A_Median;
630 const auto& bufferDCAMedZ = isCSide ? mBufferDCA.mTSTPC.mDCAz_C_Median : mBufferDCA.mTSTPC.mDCAz_A_Median;
631 auto& mAvgEff = isCSide ? mAvgMeffC : mAvgMeffA;
632 auto& mAvgChi2Match = isCSide ? mAvgChi2MatchC : mAvgChi2MatchA;
633 auto& mAvgmMIPdEdxRatioqMax = isCSide ? mMIPdEdxRatioQMaxC : mMIPdEdxRatioQMaxA;
634 auto& mAvgmMIPdEdxRatioqTot = isCSide ? mMIPdEdxRatioQTotC : mMIPdEdxRatioQTotA;
635 auto& mAvgmTPCChi2 = isCSide ? mTPCChi2C : mTPCChi2A;
636 auto& mAvgmTPCNCl = isCSide ? mTPCNClC : mTPCNClA;
637 auto& mAvgmdEdxRatioQMax = isCSide ? mLogdEdxQMaxC : mLogdEdxQMaxA;
638 auto& mAvgmdEdxRatioQTot = isCSide ? mLogdEdxQTotC : mLogdEdxQTotA;
639 auto& mITSProperties = isCSide ? mITSPropertiesC : mITSPropertiesA;
640 auto& mSigmaYZ = isCSide ? mSigmaYZC : mSigmaYZA;
641 auto& mITSTPCDeltaP = isCSide ? mITSTPCDeltaPC : mITSTPCDeltaPA;
642
643 const std::array<int, 5> bins{tglBin, phiBin, qPtBin, multBin, binInt};
644 // fill bins
645 for (auto bin : bins) {
646 // make DCA cut - select only good tracks
647 if ((std::abs(dcar - bufferDCAMedR[bin]) < (bufferDCARMSR[bin] * mCutRMS)) && (std::abs(dcaz - bufferDCAMedZ[bin]) < (bufferDCARMSZ[bin] * mCutRMS))) {
648 const auto gID = val.gID[i];
649 mAvgEff[bin][0].addValue(hasITS);
650 // count tpc only tracks not matched
651 if (!hasITS) {
652 mAvgEff[bin][1].addValue(hasITS);
653 mAvgEff[bin][2].addValue(hasITS);
654 }
655 // count tracks from ITS standalone and afterburner
657 mAvgEff[bin][1].addValue(hasITS);
659 mAvgEff[bin][2].addValue(hasITS);
660 }
661 if (chi2Match > 0) {
662 mAvgChi2Match[bin][0].addValue(chi2Match);
664 mAvgChi2Match[bin][1].addValue(chi2Match);
666 mAvgChi2Match[bin][2].addValue(chi2Match);
667 }
668 }
669 if (dedxRatioqMax > 0) {
670 mAvgmMIPdEdxRatioqMax[bin][0].addValue(dedxRatioqMax);
671 }
672 if (dedxRatioqTot > 0) {
673 mAvgmMIPdEdxRatioqTot[bin][0].addValue(dedxRatioqTot);
674 }
675 mAvgmTPCChi2[bin][0].addValue(sqrtChi2TPC);
676 mAvgmTPCNCl[bin][0].addValue(nClTPC);
677 if (hasITS) {
678 if (dedxRatioqMax > 0) {
679 mAvgmMIPdEdxRatioqMax[bin][1].addValue(dedxRatioqMax);
680 }
681 if (dedxRatioqTot > 0) {
682 mAvgmMIPdEdxRatioqTot[bin][1].addValue(dedxRatioqTot);
683 }
684 mAvgmTPCChi2[bin][1].addValue(sqrtChi2TPC);
685 mAvgmTPCNCl[bin][1].addValue(nClTPC);
686 }
687
688 float dedxNormQMax = val.dedxValsqMax[i].dedxNorm;
689 if (dedxNormQMax > 0) {
690 mAvgmdEdxRatioQMax[bin][0].addValue(dedxNormQMax);
691 }
692
693 float dedxNormQTot = val.dedxValsqTot[i].dedxNorm;
694 if (dedxNormQTot > 0) {
695 mAvgmdEdxRatioQTot[bin][0].addValue(dedxNormQTot);
696 }
697
698 float dedxIROCQMax = val.dedxValsqMax[i].dedxIROC;
699 if (dedxIROCQMax > 0) {
700 mAvgmdEdxRatioQMax[bin][1].addValue(dedxIROCQMax);
701 }
702
703 float dedxIROCQTot = val.dedxValsqTot[i].dedxIROC;
704 if (dedxIROCQTot > 0) {
705 mAvgmdEdxRatioQTot[bin][1].addValue(dedxIROCQTot);
706 }
707
708 float dedxOROC1QMax = val.dedxValsqMax[i].dedxOROC1;
709 if (dedxOROC1QMax > 0) {
710 mAvgmdEdxRatioQMax[bin][2].addValue(dedxOROC1QMax);
711 }
712
713 float dedxOROC1QTot = val.dedxValsqTot[i].dedxOROC1;
714 if (dedxOROC1QTot > 0) {
715 mAvgmdEdxRatioQTot[bin][2].addValue(dedxOROC1QTot);
716 }
717
718 float dedxOROC2QMax = val.dedxValsqMax[i].dedxOROC2;
719 if (dedxOROC2QMax > 0) {
720 mAvgmdEdxRatioQMax[bin][3].addValue(dedxOROC2QMax);
721 }
722
723 float dedxOROC2QTot = val.dedxValsqTot[i].dedxOROC2;
724 if (dedxOROC2QTot > 0) {
725 mAvgmdEdxRatioQTot[bin][3].addValue(dedxOROC2QTot);
726 }
727
728 float dedxOROC3QMax = val.dedxValsqMax[i].dedxOROC3;
729 if (dedxOROC3QMax > 0) {
730 mAvgmdEdxRatioQMax[bin][4].addValue(dedxOROC3QMax);
731 }
732
733 float dedxOROC3QTot = val.dedxValsqTot[i].dedxOROC3;
734 if (dedxOROC3QTot > 0) {
735 mAvgmdEdxRatioQTot[bin][4].addValue(dedxOROC3QTot);
736 }
737
738 float nClITS = val.nClITS[i];
739 if (nClITS > 0) {
740 mITSProperties[bin][0].addValue(nClITS);
741 }
742 float chi2ITS = val.chi2ITS[i];
743 if (chi2ITS > 0) {
744 mITSProperties[bin][1].addValue(chi2ITS);
745 }
746
747 float sigmay2 = val.sigmaY2[i];
748 if (sigmay2 > 0) {
749 mSigmaYZ[bin][0].addValue(sigmay2);
750 }
751 float sigmaz2 = val.sigmaZ2[i];
752 if (sigmaz2 > 0) {
753 mSigmaYZ[bin][1].addValue(sigmaz2);
754 }
755
756 float deltaP2 = val.deltaP2[i];
757 if (deltaP2 != -999) {
758 mITSTPCDeltaP[bin][0].addValue(deltaP2);
759 }
760
761 float deltaP3 = val.deltaP3[i];
762 if (deltaP3 != -999) {
763 mITSTPCDeltaP[bin][1].addValue(deltaP3);
764 }
765
766 float deltaP4 = val.deltaP4[i];
767 if (deltaP4 != -999) {
768 mITSTPCDeltaP[bin][2].addValue(deltaP4);
769 }
770 }
771 }
772 }
773 }
774
775 // store matching eff
776 for (int slice = 0; slice < nBins; ++slice) {
777 for (int i = 0; i < mAvgMeffA[slice].size(); ++i) {
778 auto& itsBuf = (i == 0) ? mBufferDCA.mITSTPCAll : ((i == 1) ? mBufferDCA.mITSTPCStandalone : mBufferDCA.mITSTPCAfterburner);
779 itsBuf.mITSTPC_A_MatchEff[slice] = mAvgMeffA[slice][i].getMean();
780 itsBuf.mITSTPC_C_MatchEff[slice] = mAvgMeffC[slice][i].getMean();
781 itsBuf.mITSTPC_A_Chi2Match[slice] = mAvgChi2MatchA[slice][i].getMean();
782 itsBuf.mITSTPC_C_Chi2Match[slice] = mAvgChi2MatchC[slice][i].getMean();
783 }
784
785 // loop over TPC and ITS-TPC tracks
786 for (int i = 0; i < mMIPdEdxRatioQMaxC[slice].size(); ++i) {
787 auto& buff = (i == 0) ? mBufferDCA.mTSTPC : mBufferDCA.mTSITSTPC;
788 buff.mMIPdEdxRatioQMaxA[slice] = mMIPdEdxRatioQMaxA[slice][i].getMean();
789 buff.mMIPdEdxRatioQMaxC[slice] = mMIPdEdxRatioQMaxC[slice][i].getMean();
790 buff.mMIPdEdxRatioQTotA[slice] = mMIPdEdxRatioQTotA[slice][i].getMean();
791 buff.mMIPdEdxRatioQTotC[slice] = mMIPdEdxRatioQTotC[slice][i].getMean();
792 buff.mTPCChi2C[slice] = mTPCChi2C[slice][i].getMean();
793 buff.mTPCChi2A[slice] = mTPCChi2A[slice][i].getMean();
794 buff.mTPCNClC[slice] = mTPCNClC[slice][i].getMean();
795 buff.mTPCNClA[slice] = mTPCNClA[slice][i].getMean();
796 }
797
798 // loop over qMax and qTot
799 for (int type = 0; type < 2; ++type) {
800 auto& logdEdxA = (type == 0) ? mLogdEdxQMaxA : mLogdEdxQTotA;
801 auto& buffer = (type == 0) ? mBufferDCA.mdEdxQMax : mBufferDCA.mdEdxQTot;
802 // fill A-side
803 buffer.mLogdEdx_A_Median[slice] = logdEdxA[slice][0].getMedian();
804 buffer.mLogdEdx_A_RMS[slice] = logdEdxA[slice][0].getStdDev();
805 buffer.mLogdEdx_A_IROC_Median[slice] = logdEdxA[slice][1].getMedian();
806 buffer.mLogdEdx_A_IROC_RMS[slice] = logdEdxA[slice][1].getStdDev();
807 buffer.mLogdEdx_A_OROC1_Median[slice] = logdEdxA[slice][2].getMedian();
808 buffer.mLogdEdx_A_OROC1_RMS[slice] = logdEdxA[slice][2].getStdDev();
809 buffer.mLogdEdx_A_OROC2_Median[slice] = logdEdxA[slice][3].getMedian();
810 buffer.mLogdEdx_A_OROC2_RMS[slice] = logdEdxA[slice][3].getStdDev();
811 buffer.mLogdEdx_A_OROC3_Median[slice] = logdEdxA[slice][4].getMedian();
812 buffer.mLogdEdx_A_OROC3_RMS[slice] = logdEdxA[slice][4].getStdDev();
813 // fill C-side
814 auto& logdEdxC = (type == 0) ? mLogdEdxQMaxC : mLogdEdxQTotC;
815 buffer.mLogdEdx_C_Median[slice] = logdEdxC[slice][0].getMedian();
816 buffer.mLogdEdx_C_RMS[slice] = logdEdxC[slice][0].getStdDev();
817 buffer.mLogdEdx_C_IROC_Median[slice] = logdEdxC[slice][1].getMedian();
818 buffer.mLogdEdx_C_IROC_RMS[slice] = logdEdxC[slice][1].getStdDev();
819 buffer.mLogdEdx_C_OROC1_Median[slice] = logdEdxC[slice][2].getMedian();
820 buffer.mLogdEdx_C_OROC1_RMS[slice] = logdEdxC[slice][2].getStdDev();
821 buffer.mLogdEdx_C_OROC2_Median[slice] = logdEdxC[slice][3].getMedian();
822 buffer.mLogdEdx_C_OROC2_RMS[slice] = logdEdxC[slice][3].getStdDev();
823 buffer.mLogdEdx_C_OROC3_Median[slice] = logdEdxC[slice][4].getMedian();
824 buffer.mLogdEdx_C_OROC3_RMS[slice] = logdEdxC[slice][4].getStdDev();
825 }
826
827 // ITS properties
828 // A-side
829 mBufferDCA.mITS_A_NCl_Median[slice] = mITSPropertiesA[slice][0].getMedian();
830 mBufferDCA.mITS_A_NCl_RMS[slice] = mITSPropertiesA[slice][0].getStdDev();
831 mBufferDCA.mSqrtITSChi2_Ncl_A_Median[slice] = mITSPropertiesA[slice][1].getMedian();
832 mBufferDCA.mSqrtITSChi2_Ncl_A_RMS[slice] = mITSPropertiesA[slice][1].getStdDev();
833 // C-side
834 mBufferDCA.mITS_C_NCl_Median[slice] = mITSPropertiesC[slice][0].getMedian();
835 mBufferDCA.mITS_C_NCl_RMS[slice] = mITSPropertiesC[slice][0].getStdDev();
836 mBufferDCA.mSqrtITSChi2_Ncl_C_Median[slice] = mITSPropertiesC[slice][1].getMedian();
837 mBufferDCA.mSqrtITSChi2_Ncl_C_RMS[slice] = mITSPropertiesC[slice][1].getStdDev();
838
839 //...
840 mBufferDCA.mITSTPCDeltaP2_A_Median[slice] = mITSTPCDeltaPA[slice][0].getMedian();
841 mBufferDCA.mITSTPCDeltaP3_A_Median[slice] = mITSTPCDeltaPA[slice][1].getMedian();
842 mBufferDCA.mITSTPCDeltaP4_A_Median[slice] = mITSTPCDeltaPA[slice][2].getMedian();
843 mBufferDCA.mITSTPCDeltaP2_C_Median[slice] = mITSTPCDeltaPC[slice][0].getMedian();
844 mBufferDCA.mITSTPCDeltaP3_C_Median[slice] = mITSTPCDeltaPC[slice][1].getMedian();
845 mBufferDCA.mITSTPCDeltaP4_C_Median[slice] = mITSTPCDeltaPC[slice][2].getMedian();
846 mBufferDCA.mITSTPCDeltaP2_A_RMS[slice] = mITSTPCDeltaPA[slice][0].getStdDev();
847 mBufferDCA.mITSTPCDeltaP3_A_RMS[slice] = mITSTPCDeltaPA[slice][1].getStdDev();
848 mBufferDCA.mITSTPCDeltaP4_A_RMS[slice] = mITSTPCDeltaPA[slice][2].getStdDev();
849 mBufferDCA.mITSTPCDeltaP2_C_RMS[slice] = mITSTPCDeltaPC[slice][0].getStdDev();
850 mBufferDCA.mITSTPCDeltaP3_C_RMS[slice] = mITSTPCDeltaPC[slice][1].getStdDev();
851 mBufferDCA.mITSTPCDeltaP4_C_RMS[slice] = mITSTPCDeltaPC[slice][2].getStdDev();
852 mBufferDCA.mTPCSigmaY2A_Median[slice] = mSigmaYZA[slice][0].getMedian();
853 mBufferDCA.mTPCSigmaZ2A_Median[slice] = mSigmaYZA[slice][1].getMedian();
854 mBufferDCA.mTPCSigmaY2C_Median[slice] = mSigmaYZC[slice][0].getMedian();
855 mBufferDCA.mTPCSigmaZ2C_Median[slice] = mSigmaYZC[slice][1].getMedian();
856 mBufferDCA.mTPCSigmaY2A_RMS[slice] = mSigmaYZA[slice][0].getStdDev();
857 mBufferDCA.mTPCSigmaZ2A_RMS[slice] = mSigmaYZA[slice][1].getStdDev();
858 mBufferDCA.mTPCSigmaY2C_RMS[slice] = mSigmaYZC[slice][0].getStdDev();
859 mBufferDCA.mTPCSigmaZ2C_RMS[slice] = mSigmaYZC[slice][1].getStdDev();
860 }
861
862 auto stop = timer::now();
863 std::chrono::duration<float> time = stop - startTotal;
864 LOGP(info, "Time series creation took {}", time.count());
865
866 // send data
867 sendOutput(pc);
868 }
869
871 {
872 for (auto& streamer : mStreamer) {
873 streamer->Close();
874 }
875 eos.services().get<ControlService>().readyToQuit(QuitRequest::Me);
876 }
877
878 void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) final
879 {
880 mTPCVDriftHelper.accountCCDBInputs(matcher, obj);
881 mPTHelper.accountCCDBInputs(matcher, obj);
883 if (matcher == ConcreteDataMatcher(o2::header::gDataOriginTPC, "InfoMapSecFluc", 0)) {
884 LOGP(info, "Updating TPC sector edge fluctuation info");
885 mSecEdgeFlucInfo.setFromTree(*((TTree*)obj));
886 LOGP(info, "Loaded sector edge fluctuation information with {} intervals for {} runs", mSecEdgeFlucInfo.size(), mSecEdgeFlucInfo.getNRuns());
887 }
888 }
889
890 private:
892 struct ValsdEdx {
893 float dedxNorm = 0;
894 float dedxIROC = 0;
895 float dedxOROC1 = 0;
896 float dedxOROC2 = 0;
897 float dedxOROC3 = 0;
898 };
899
900 struct FillVals {
901 void reserve(int n, int type)
902 {
903 side.reserve(n);
904 tglBin.reserve(n);
905 phiBin.reserve(n);
906 qPtBin.reserve(n);
907 multBin.reserve(n);
908 dcar.reserve(n);
909 dcaz.reserve(n);
910 dcarW.reserve(n);
911 dedxRatioqTot.reserve(n);
912 dedxRatioqMax.reserve(n);
913 sqrtChi2TPC.reserve(n);
914 nClTPC.reserve(n);
915 if (type == 1) {
916 hasITS.reserve(n);
917 chi2Match.reserve(n);
918 gID.reserve(n);
919 dedxValsqTot.reserve(n);
920 dedxValsqMax.reserve(n);
921 nClITS.reserve(n);
922 chi2ITS.reserve(n);
923 deltaP2.reserve(n);
924 deltaP3.reserve(n);
925 deltaP4.reserve(n);
926 sigmaY2.reserve(n);
927 sigmaZ2.reserve(n);
928 } else if (type == 0) {
929 dcarcomb.reserve(n);
930 dcazcomb.reserve(n);
931 }
932 }
933
934 void clear()
935 {
936 side.clear();
937 tglBin.clear();
938 phiBin.clear();
939 qPtBin.clear();
940 multBin.clear();
941 dcar.clear();
942 dcaz.clear();
943 dcarW.clear();
944 hasITS.clear();
945 chi2Match.clear();
946 dedxRatioqTot.clear();
947 dedxRatioqMax.clear();
948 sqrtChi2TPC.clear();
949 nClTPC.clear();
950 gID.clear();
951 dcarcomb.clear();
952 dcazcomb.clear();
953 nClITS.clear();
954 chi2ITS.clear();
955 dedxValsqTot.clear();
956 dedxValsqMax.clear();
957 deltaP2.clear();
958 deltaP3.clear();
959 deltaP4.clear();
960 sigmaY2.clear();
961 sigmaZ2.clear();
962 }
963
964 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)
965 {
966 side.emplace_back(sideTmp);
967 tglBin.emplace_back(tglBinTmp);
968 phiBin.emplace_back(phiBinTmp);
969 qPtBin.emplace_back(qPtBinTmp);
970 multBin.emplace_back(multBinTmp);
971 dcar.emplace_back(dcarTmp);
972 dcaz.emplace_back(dcazTmp);
973 dcarW.emplace_back(dcarWTmp);
974 dedxRatioqTot.emplace_back(dedxRatioqTotTmp);
975 dedxRatioqMax.emplace_back(dedxRatioqMaxTmp);
976 sqrtChi2TPC.emplace_back(sqrtChi2TPCTmp);
977 nClTPC.emplace_back(nClTPCTmp);
978 chi2Match.emplace_back(chi2MatchTmp);
979 hasITS.emplace_back(hasITSTmp);
980 gID.emplace_back(gIDTmp);
981 dedxValsqMax.emplace_back(dedxValsqMaxTmp);
982 dedxValsqTot.emplace_back(dedxValsqTotTmp);
983 nClITS.emplace_back(nClITSTmp);
984 chi2ITS.emplace_back(chi2ITSTmp);
985 sigmaY2.emplace_back(sigmaY2Tmp);
986 sigmaZ2.emplace_back(sigmaZ2Tmp);
987 deltaP2.emplace_back(-999);
988 deltaP3.emplace_back(-999);
989 deltaP4.emplace_back(-999);
990 }
991
992 void setDeltaParam(float deltaP2Tmp, float deltaP3Tmp, float deltaP4Tmp)
993 {
994 if (!deltaP2.empty()) {
995 deltaP2.back() = deltaP2Tmp;
996 deltaP3.back() = deltaP3Tmp;
997 deltaP4.back() = deltaP4Tmp;
998 }
999 }
1000
1001 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)
1002 {
1003 side.emplace_back(sideTmp);
1004 tglBin.emplace_back(tglBinTmp);
1005 phiBin.emplace_back(phiBinTmp);
1006 qPtBin.emplace_back(qPtBinTmp);
1007 multBin.emplace_back(multBinTmp);
1008 dcar.emplace_back(dcarTmp);
1009 dcaz.emplace_back(dcazTmp);
1010 dcarW.emplace_back(dcarWTmp);
1011 dedxRatioqTot.emplace_back(dedxRatioqTotTmp);
1012 dedxRatioqMax.emplace_back(dedxRatioqMaxTmp);
1013 sqrtChi2TPC.emplace_back(sqrtChi2TPCTmp);
1014 nClTPC.emplace_back(nClTPCTmp);
1015 dcarcomb.emplace_back(dcarCombTmp);
1016 dcazcomb.emplace_back(dcazCombTmp);
1017 }
1018
1019 std::vector<Side> side;
1020 std::vector<int> tglBin;
1021 std::vector<int> phiBin;
1022 std::vector<int> qPtBin;
1023 std::vector<int> multBin;
1024 std::vector<float> dcar;
1025 std::vector<float> dcaz;
1026 std::vector<float> dcarW;
1027 std::vector<bool> hasITS;
1028 std::vector<float> chi2Match;
1029 std::vector<float> dedxRatioqTot;
1030 std::vector<float> dedxRatioqMax;
1031 std::vector<float> sqrtChi2TPC;
1032 std::vector<float> nClTPC;
1033 std::vector<float> dcarcomb;
1034 std::vector<float> dcazcomb;
1035 std::vector<ValsdEdx> dedxValsqTot;
1036 std::vector<ValsdEdx> dedxValsqMax;
1037 std::vector<int> nClITS;
1038 std::vector<float> chi2ITS;
1039 std::vector<o2::dataformats::GlobalTrackID::Source> gID;
1040 std::vector<float> deltaP2;
1041 std::vector<float> deltaP3;
1042 std::vector<float> deltaP4;
1043 std::vector<float> sigmaY2;
1044 std::vector<float> sigmaZ2;
1045 };
1046 std::shared_ptr<o2::base::GRPGeomRequest> mCCDBRequest;
1047 const bool mDisableWriter{false};
1049 const bool mUnbinnedWriter{false};
1050 const bool mTPCOnly{false};
1051 std::shared_ptr<o2::globaltracking::DataRequest> mDataRequest;
1052 int mPhiBins = SECTORSPERSIDE;
1053 int mTglBins{3};
1054 int mQPtBins{20};
1055 TimeSeriesITSTPC mBufferDCA;
1056 std::vector<std::array<RobustAverage, 3>> mAvgADCAr;
1057 std::vector<std::array<RobustAverage, 3>> mAvgCDCAr;
1058 std::vector<std::array<RobustAverage, 3>> mAvgADCAz;
1059 std::vector<std::array<RobustAverage, 3>> mAvgCDCAz;
1060 std::vector<std::array<RobustAverage, 2>> mMIPdEdxRatioQMaxA;
1061 std::vector<std::array<RobustAverage, 2>> mMIPdEdxRatioQMaxC;
1062 std::vector<std::array<RobustAverage, 2>> mMIPdEdxRatioQTotA;
1063 std::vector<std::array<RobustAverage, 2>> mMIPdEdxRatioQTotC;
1064 std::vector<std::array<RobustAverage, 2>> mTPCChi2A;
1065 std::vector<std::array<RobustAverage, 2>> mTPCChi2C;
1066 std::vector<std::array<RobustAverage, 2>> mTPCNClA;
1067 std::vector<std::array<RobustAverage, 2>> mTPCNClC;
1068 std::vector<std::array<RobustAverage, 3>> mAvgMeffA;
1069 std::vector<std::array<RobustAverage, 3>> mAvgMeffC;
1070 std::vector<std::array<RobustAverage, 3>> mAvgChi2MatchA;
1071 std::vector<std::array<RobustAverage, 3>> mAvgChi2MatchC;
1072 std::vector<std::array<RobustAverage, 10>> mLogdEdxQTotA;
1073 std::vector<std::array<RobustAverage, 10>> mLogdEdxQTotC;
1074 std::vector<std::array<RobustAverage, 10>> mLogdEdxQMaxA;
1075 std::vector<std::array<RobustAverage, 10>> mLogdEdxQMaxC;
1076 std::vector<std::array<RobustAverage, 2>> mITSPropertiesA;
1077 std::vector<std::array<RobustAverage, 2>> mITSPropertiesC;
1078 std::vector<std::array<RobustAverage, 3>> mITSTPCDeltaPA;
1079 std::vector<std::array<RobustAverage, 3>> mITSTPCDeltaPC;
1080 std::vector<std::array<RobustAverage, 2>> mSigmaYZA;
1081 std::vector<std::array<RobustAverage, 2>> mSigmaYZC;
1082 int mNMaxTracks{-1};
1083 float mMinMom{1};
1084 int mMinNCl{80};
1085 float mMaxTgl{1};
1086 float mMaxQPt{5};
1087 float mCoarseStep{1};
1088 float mFineStep{0.005};
1089 float mCutDCA{5};
1090 float mCutRMS{5};
1091 float mRefXSec{108.475};
1092 int mNThreads{1};
1093 float maxITSTPCDCAr{0.2};
1094 float maxITSTPCDCAz{10};
1095 float maxITSTPCDCAr_comb{0.2};
1096 float maxITSTPCDCAz_comb{0.2};
1097 gsl::span<const TPCClRefElem> mTPCTrackClIdx{};
1098 std::vector<std::array<FillVals, 2>> mBufferVals;
1099 uint32_t mFirstTFOrbit{0};
1100 float mTimeWindowMUS{50};
1101 float mMIPdEdx{50};
1102 std::vector<int> mNTracksWindow;
1103 std::vector<int> mNearestVtxTPC;
1104 o2::tpc::VDriftHelper mTPCVDriftHelper{};
1105 float mVDrift{2.64};
1106 float mMaxSnp{0.85};
1107 float mXCoarse{40};
1108 float mSqrt{13600};
1109 int mMultBins{20};
1110 int mMultMax{80000};
1111 PIDResponse mPID;
1112 int mMinTracksPerVertex{5};
1113 float mMaxdEdxRatio{0.3};
1114 float mMaxdEdxRegionRatio{0.5};
1115 float mSamplingFactor{0.1};
1116 bool mSampleTsallis{false};
1117 std::vector<std::mt19937> mGenerator;
1118 std::vector<std::unique_ptr<o2::utils::TreeStreamRedirector>> mStreamer;
1119 float mXOuterMatching{60};
1120 bool mUseMinBiasTrigger{false};
1121 long mTimeMS{};
1122 int mRun{};
1123 int mMaxOccupancyHistBins{912};
1124 PressureTemperatureHelper mPTHelper;
1125 o2::tpc::SectorEdgeFluctuations mSecEdgeFlucInfo;
1126
1128 bool acceptTrack(const TrackTPC& track) const { return std::abs(track.getTgl()) < mMaxTgl; }
1129
1130 bool checkTrack(const TrackTPC& track) const
1131 {
1132 const bool isGoodTrack = ((track.getNClusters() < mMinNCl) || (track.getP() < mMinMom)) ? false : true;
1133 return isGoodTrack;
1134 }
1135
1136 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)
1137 {
1138 const auto& trackFull = tracksTPC[iTrk];
1139 const bool isGoodTrack = checkTrack(trackFull);
1140
1141 // check for min bias trigger - sample flat -
1142 bool minBiasOk = false;
1143 const float factorMinBias = 0.1 * mSamplingFactor;
1144 if (mUnbinnedWriter && mUseMinBiasTrigger) {
1145 std::uniform_real_distribution<> distr(0., 1.);
1146 if (distr(mGenerator[iThread]) < factorMinBias) {
1147 minBiasOk = true;
1148 }
1149 }
1150
1151 // check if at least one check passed
1152 if (!isGoodTrack && !minBiasOk) {
1153 return;
1154 }
1155
1156 o2::track::TrackParCov track = tracksTPC[iTrk];
1157
1158 // propagate track to the DCA and fill in slice
1159 auto propagator = o2::base::Propagator::Instance();
1160
1161 // propagate track to DCA
1162 std::array<float, 2> dca;
1163 const o2::math_utils::Point3D<float> refPoint{0, 0, 0};
1164
1165 // coarse propagation
1166 if (!propagator->PropagateToXBxByBz(track, mXCoarse, mMaxSnp, mCoarseStep, mMatType)) {
1167 return;
1168 }
1169
1170 // fine propagation with Bz only
1171 if (!propagator->propagateToDCA(refPoint, track, propagator->getNominalBz(), mFineStep, mMatType, &dca)) {
1172 return;
1173 }
1174
1175 o2::track::TrackPar trackTmp(tracksTPC[iTrk]);
1176
1177 // coarse propagation to centre of IROC for phi bin
1178 if (!propagator->propagateTo(trackTmp, mRefXSec, false, mMaxSnp, mCoarseStep, mMatType)) {
1179 return;
1180 }
1181
1182 const int tglBin = mTglBins * std::abs(trackTmp.getTgl()) / mMaxTgl + mPhiBins;
1183 const int phiBin = mPhiBins * trackTmp.getPhi() / o2::constants::math::TwoPI;
1184
1185 const int offsQPtBin = mPhiBins + mTglBins;
1186 const int qPtBin = offsQPtBin + mQPtBins * (trackTmp.getQ2Pt() + mMaxQPt) / (2 * mMaxQPt);
1187 const int localMult = mNTracksWindow[iTrk];
1188
1189 const int offsMult = offsQPtBin + mQPtBins;
1190 const int multBin = offsMult + mMultBins * localMult / mMultMax;
1191 const int nBins = getNBins();
1192
1193 if ((phiBin < 0) || (phiBin > mPhiBins) || (tglBin < mPhiBins) || (tglBin > offsQPtBin) || (qPtBin < offsQPtBin) || (qPtBin > offsMult) || (multBin < offsMult) || (multBin > offsMult + mMultBins)) {
1194 return;
1195 }
1196
1197 float sigmaY2 = 0;
1198 float sigmaZ2 = 0;
1199 const int sector = o2::math_utils::angle2Sector(trackTmp.getPhiPos());
1200 // find possible ITS-TPC track and vertex index
1201 auto it = indicesITSTPC.find(iTrk);
1202 const auto idxITSTPC = (it != indicesITSTPC.end()) ? (it->second) : std::array<int, 2>{-1, -1};
1203
1204 // get vertex (check if vertex ID is valid). In case no vertex is assigned return nearest vertex or else default vertex
1205 const auto vertex = (idxITSTPC.back() != -1) ? vertices[idxITSTPC.back()] : ((mNearestVtxTPC[iTrk] != -1) ? vertices[mNearestVtxTPC[iTrk]] : o2::dataformats::PrimaryVertex{});
1206
1207 // calculate DCAz: (time TPC track - time vertex) * vDrift + sign_side * vertexZ
1208 const float signSide = trackFull.hasCSideClustersOnly() ? -1 : 1; // invert sign for C-side
1209 const float dcaZFromDeltaTime = (vertex.getTimeStamp().getTimeStamp() == 0) ? 0 : (o2::tpc::ParameterElectronics::Instance().ZbinWidth * trackFull.getTime0() - vertex.getTimeStamp().getTimeStamp()) * mVDrift + signSide * vertex.getZ();
1210
1211 // for weight of DCA
1212 const float resCl = std::min(trackFull.getNClusters(), static_cast<int>(Mapper::PADROWS)) / static_cast<float>(Mapper::PADROWS);
1213
1214 const float div = (resCl * track.getPt());
1215 if (div == 0) {
1216 return;
1217 }
1218
1219 const float fB = 0.2 / div;
1220 const float fA = 0.15 + 0.15; // = 0.15 with additional misalignment error
1221 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);
1222
1223 // store values for TPC DCA only for A- or C-side only tracks
1224 const bool hasITSTPC = idxITSTPC.front() != -1;
1225
1226 // get ratio of chi2 in case ITS-TPC track has been found
1227 const float chi2 = hasITSTPC ? tracksITSTPC[idxITSTPC.front()].getChi2Match() : -1;
1229 // check for source in case of ITS-TPC
1230 if (hasITSTPC) {
1231 const auto src = tracksITSTPC[idxITSTPC.front()].getRefITS().getSource();
1236 }
1237 }
1238
1239 const float chi2Match = (chi2 > 0) ? std::sqrt(chi2) : -1;
1240 const float sqrtChi2TPC = (trackFull.getChi2() > 0) ? std::sqrt(trackFull.getChi2()) : 0;
1241 const float nClTPC = trackFull.getNClusters();
1242
1243 // const float dedx = mUseQMax ? track.getdEdx().dEdxMaxTPC : track.getdEdx().dEdxTotTPC;
1244 const float dedxRatioqTot = (trackFull.getdEdx().dEdxTotTPC > 0) ? (mMIPdEdx / trackFull.getdEdx().dEdxTotTPC) : -1;
1245 const float dedxRatioqMax = (trackFull.getdEdx().dEdxMaxTPC > 0) ? (mMIPdEdx / trackFull.getdEdx().dEdxMaxTPC) : -1;
1246
1247 const auto dedxQTotVars = getdEdxVars(0, trackFull);
1248 const auto dedxQMaxVars = getdEdxVars(1, trackFull);
1249
1250 // make check to avoid crash in case no or less ITS tracks have been found!
1251 const int idxITSTrack = (hasITSTPC && (gID == o2::dataformats::GlobalTrackID::Source::ITS)) ? tracksITSTPC[idxITSTPC.front()].getRefITS().getIndex() : -1;
1252 const bool idxITSCheck = (idxITSTrack != -1);
1253
1254 const int nClITS = idxITSCheck ? tracksITS[idxITSTrack].getNClusters() : -1;
1255 float chi2ITS = idxITSCheck ? tracksITS[idxITSTrack].getChi2() : -1;
1256 if ((chi2ITS > 0) && (nClITS > 0)) {
1257 chi2ITS = std::sqrt(chi2ITS / nClITS);
1258 }
1259 sigmaY2 = track.getSigmaY2();
1260 sigmaZ2 = track.getSigmaZ2();
1261 if (isGoodTrack) {
1262 if (trackFull.hasCSideClustersOnly()) {
1263 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);
1264 } else if (trackFull.hasASideClustersOnly()) {
1265 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);
1266 }
1267 }
1268
1269 // make propagation for ITS-TPC Track
1270 // check if the track was assigned to ITS track
1271 std::array<float, 2> dcaITSTPC{0, 0};
1272 float deltaP0 = -999;
1273 float deltaP1 = -999;
1274 float deltaP2 = -999;
1275 float deltaP3 = -999;
1276 float deltaP4 = -999;
1277 float phiITSTPCAtVertex = -999; // phi of ITS-TPC track at vertex
1278 float dcaTPCAtVertex = -999;
1279 if (hasITSTPC) {
1280 // propagate ITS-TPC track to (0,0)
1281 auto trackITSTPCTmp = tracksITSTPC[idxITSTPC.front()];
1282 // fine propagation with Bz only
1283 if (propagator->propagateToDCA(refPoint, trackITSTPCTmp, propagator->getNominalBz(), mFineStep, mMatType, &dcaITSTPC)) {
1284 // make cut on abs(DCA)
1285 if ((std::abs(dcaITSTPC[0]) < maxITSTPCDCAr) && (std::abs(dcaITSTPC[1]) < maxITSTPCDCAz)) {
1286 // store TPC only DCAs
1287 // propagate to vertex in case the track belongs to vertex
1288 const bool contributeToVertex = (idxITSTPC.back() != -1);
1289 std::array<float, 2> dcaITSTPCTmp{-1, -1};
1290
1291 if (contributeToVertex) {
1292 if (propagator->propagateToDCA(vertex.getXYZ(), trackITSTPCTmp, propagator->getNominalBz(), mFineStep, mMatType, &dcaITSTPCTmp)) {
1293 phiITSTPCAtVertex = trackITSTPCTmp.getPhi();
1294 dcaITSTPC = dcaITSTPCTmp;
1295 }
1296
1297 // propagate TPC track to vertex
1298 std::array<float, 2> dcaTPCTmp{-1, -1};
1299 if (propagator->propagateToDCA(vertex.getXYZ(), track, propagator->getNominalBz(), mFineStep, mMatType, &dcaTPCTmp)) {
1300 dcaTPCAtVertex = dcaTPCTmp[0];
1301 }
1302 }
1303
1304 // make cut around DCA to vertex due to gammas
1305 if ((std::abs(dcaITSTPCTmp[0]) < maxITSTPCDCAr_comb) && (std::abs(dcaITSTPCTmp[1]) < maxITSTPCDCAz_comb)) {
1306 // propagate TPC track to ITS track and store delta track parameters
1307 if (idxITSTrack >= 0 && track.rotate(tracksITS[idxITSTrack].getAlpha()) && propagator->propagateTo(track, trackITSTPCTmp.getX(), false, mMaxSnp, mFineStep, mMatType)) {
1308 o2::track::TrackPar trackITS(tracksITS[idxITSTrack]);
1309 const bool propITSOk = propagator->propagateTo(trackITS, trackITSTPCTmp.getX(), false, mMaxSnp, mFineStep, mMatType);
1310 if (propITSOk) {
1311 deltaP0 = track.getParam(0) - trackITS.getParam(0);
1312 deltaP1 = track.getParam(1) - trackITS.getParam(1);
1313 deltaP2 = track.getParam(2) - trackITS.getParam(2);
1314 deltaP3 = track.getParam(3) - trackITS.getParam(3);
1315 deltaP4 = track.getParam(4) - trackITS.getParam(4);
1316 mBufferVals[iThread].front().setDeltaParam(deltaP2, deltaP3, deltaP4);
1317 }
1318 }
1319 } else {
1320 dcaITSTPCTmp[0] = -1;
1321 dcaITSTPCTmp[1] = -1;
1322 }
1323
1324 if (isGoodTrack) {
1325 if (trackFull.hasCSideClustersOnly()) {
1326 mBufferVals[iThread].back().emplace_back_ITSTPC(Side::C, tglBin, phiBin, qPtBin, multBin, dcaTPCAtVertex, dcaZFromDeltaTime, dcarW, dedxRatioqTot, dedxRatioqMax, sqrtChi2TPC, nClTPC, dcaITSTPCTmp[0], dcaITSTPCTmp[1]);
1327 } else if (trackFull.hasASideClustersOnly()) {
1328 mBufferVals[iThread].back().emplace_back_ITSTPC(Side::A, tglBin, phiBin, qPtBin, multBin, dcaTPCAtVertex, dcaZFromDeltaTime, dcarW, dedxRatioqTot, dedxRatioqMax, sqrtChi2TPC, nClTPC, dcaITSTPCTmp[0], dcaITSTPCTmp[1]);
1329 }
1330 }
1331 }
1332 }
1333 }
1334
1335 if (mUnbinnedWriter && mStreamer[iThread]) {
1336 const float factorPt = mSamplingFactor;
1337 bool writeData = true;
1338 float weight = 0;
1339 if (mSampleTsallis) {
1340 std::uniform_real_distribution<> distr(0., 1.);
1341 writeData = o2::math_utils::Tsallis::downsampleTsallisCharged(tracksTPC[iTrk].getPt(), factorPt, mSqrt, weight, distr(mGenerator[iThread]));
1342 }
1343 if (writeData || minBiasOk) {
1344 auto clusterMask = makeClusterBitMask(trackFull);
1345 const auto& trkOrig = tracksTPC[iTrk];
1346 const bool isNearestVtx = (idxITSTPC.back() == -1); // is nearest vertex in case no vertex was found
1347 const float mx_ITS = hasITSTPC ? tracksITSTPC[idxITSTPC.front()].getX() : -1;
1348 const float pt_ITS = hasITSTPC ? tracksITSTPC[idxITSTPC.front()].getQ2Pt() : -1;
1349 const float chi2match_ITSTPC = hasITSTPC ? tracksITSTPC[idxITSTPC.front()].getChi2Match() : -1;
1350 const int nClITS = idxITSCheck ? tracksITS[idxITSTrack].getNClusters() : -1;
1351 const int chi2ITS = idxITSCheck ? tracksITS[idxITSTrack].getChi2() : -1;
1352 int typeSide = 2; // A- and C-Side cluster
1353 if (trackFull.hasASideClustersOnly()) {
1354 typeSide = 0;
1355 } else if (trackFull.hasCSideClustersOnly()) {
1356 typeSide = 1;
1357 }
1358
1359 // check for TOF and propagate TPC track to TOF cluster
1360 bool hasTOFCluster = (std::get<0>(idxTPCTrackToTOFCluster[iTrk]) != -1);
1361 auto tofCl = hasTOFCluster ? tofClusters[std::get<0>(idxTPCTrackToTOFCluster[iTrk])] : o2::tof::Cluster();
1362
1363 float tpcYDeltaAtTOF = -999;
1364 float tpcZDeltaAtTOF = -999;
1365 if (hasTOFCluster) {
1366 o2::track::TrackPar trackTmpOut(tracksTPC[iTrk].getParamOut());
1367 if (trackTmpOut.rotate(o2::math_utils::sector2Angle(tofCl.getSector())) && propagator->propagateTo(trackTmpOut, tofCl.getX(), false, mMaxSnp, mFineStep, mMatType)) {
1368 tpcYDeltaAtTOF = trackTmpOut.getY() - tofCl.getY();
1369 tpcZDeltaAtTOF = signSide * (o2::tpc::ParameterElectronics::Instance().ZbinWidth * trackFull.getTime0() - vertex.getTimeStamp().getTimeStamp()) * mVDrift - trackTmpOut.getZ() + tofCl.getZ();
1370 }
1371 }
1372
1373 // get delta parameter between inner and outer
1374 float deltaTPCParamInOutTgl = trackFull.getTgl() - trackFull.getParamOut().getTgl();
1375 float deltaTPCParamInOutQPt = trackFull.getQ2Pt() - trackFull.getParamOut().getQ2Pt();
1376
1377 // propagate TPC track and ITS-TPC track to outer matching at 60cm
1378 float deltaP0OuterITS = -999;
1379 float deltaP1OuterITS = -999;
1380 float deltaP2OuterITS = -999;
1381 float deltaP3OuterITS = -999;
1382 float deltaP4OuterITS = -999;
1383 if (idxITSCheck) {
1384 o2::track::TrackPar trackTmpOut(tracksITS[idxITSTrack].getParamOut());
1385 const bool propITSOk = propagator->propagateTo(trackTmpOut, mXOuterMatching, false, mMaxSnp, mCoarseStep, mMatType);
1386 if (propITSOk && trackTmp.rotate(trackTmpOut.getAlpha())) {
1387 const bool propTPCOk = propagator->propagateTo(trackTmp, mXOuterMatching, false, mMaxSnp, mCoarseStep, mMatType);
1388 if (propTPCOk) {
1389 // store delta parameters
1390 deltaP0OuterITS = trackTmp.getParam(0) - trackTmpOut.getParam(0);
1391 deltaP1OuterITS = trackTmp.getParam(1) - trackTmpOut.getParam(1);
1392 deltaP2OuterITS = trackTmp.getParam(2) - trackTmpOut.getParam(2);
1393 deltaP3OuterITS = trackTmp.getParam(3) - trackTmpOut.getParam(3);
1394 deltaP4OuterITS = trackTmp.getParam(4) - trackTmpOut.getParam(4);
1395 }
1396 }
1397 }
1398 const int triggerMask = 0x1 * minBiasOk + 0x2 * writeData;
1399
1400 float deltaP2ConstrVtx = -999;
1401 float deltaP3ConstrVtx = -999;
1402 float deltaP4ConstrVtx = -999;
1403
1404 // cov of TPC track constrained at vertex
1405 float covTPCConstrVtxP2 = -999;
1406 float covTPCConstrVtxP3 = -999;
1407 float covTPCConstrVtxP4 = -999;
1408
1409 // cov of ITS-TPC track at vertex
1410 float covITSTPCConstrVtxP2 = -999;
1411 float covITSTPCConstrVtxP3 = -999;
1412 float covITSTPCConstrVtxP4 = -999;
1413
1414 float covTPCAtVertex0 = -999;
1415 float covTPCAtVertex1 = -999;
1416
1417 const bool contributeToVertex = (idxITSTPC.back() != -1);
1418 if (hasITSTPC && contributeToVertex) {
1419 o2::track::TrackParCov trackITSTPCTmp = tracksITSTPC[idxITSTPC.front()];
1420 std::array<float, 2> dcaITSTPCTmp{-1, -1};
1421 if (propagator->propagateToDCA(vertex.getXYZ(), trackITSTPCTmp, propagator->getNominalBz(), mFineStep, mMatType, &dcaITSTPCTmp)) {
1422 o2::track::TrackParCov trackTPC = tracksTPC[iTrk];
1423 if (trackTPC.rotate(trackITSTPCTmp.getAlpha()) && propagator->propagateTo(trackTPC, trackITSTPCTmp.getX(), false, mMaxSnp, mFineStep, mMatType)) {
1424 // store covariance of TPC track at vertex
1425 covTPCAtVertex0 = trackTPC.getCovarElem(0, 0);
1426 covTPCAtVertex1 = trackTPC.getCovarElem(1, 1);
1427
1428 trackTPC.update(vertex);
1429 deltaP2ConstrVtx = trackTPC.getParam(2) - trackITSTPCTmp.getParam(2);
1430 deltaP3ConstrVtx = trackTPC.getParam(3) - trackITSTPCTmp.getParam(3);
1431 deltaP4ConstrVtx = trackTPC.getParam(4) - trackITSTPCTmp.getParam(4);
1432 covTPCConstrVtxP2 = trackTPC.getCovarElem(2, 2);
1433 covTPCConstrVtxP3 = trackTPC.getCovarElem(3, 3);
1434 covTPCConstrVtxP4 = trackTPC.getCovarElem(4, 4);
1435 covITSTPCConstrVtxP2 = trackITSTPCTmp.getCovarElem(2, 2);
1436 covITSTPCConstrVtxP3 = trackITSTPCTmp.getCovarElem(3, 3);
1437 covITSTPCConstrVtxP4 = trackITSTPCTmp.getCovarElem(4, 4);
1438 }
1439 }
1440 }
1441 double vertexTime = vertex.getTimeStamp().getTimeStamp();
1442 double trackTime0 = trackFull.getTime0();
1443 *mStreamer[iThread] << "treeTimeSeries"
1444 // DCAs
1445 << "triggerMask=" << triggerMask
1446 << "factorMinBias=" << factorMinBias
1447 << "factorPt=" << factorPt
1448 << "weight=" << weight
1449 << "dcar_tpc_vertex=" << dcaTPCAtVertex
1450 << "dcar_tpc=" << dca[0]
1451 << "dcaz_tpc=" << dca[1]
1452 << "dcar_itstpc=" << dcaITSTPC[0]
1453 << "dcaz_itstpc=" << dcaITSTPC[1]
1454 << "dcarW=" << dcarW
1455 << "dcaZFromDeltaTime=" << dcaZFromDeltaTime
1456 << "hasITSTPC=" << hasITSTPC
1457 // vertex
1458 << "vertex_x=" << vertex.getX()
1459 << "vertex_y=" << vertex.getY()
1460 << "vertex_z=" << vertex.getZ()
1461 << "vertex_time=" << vertex.getTimeStamp().getTimeStamp()
1462 << "vertex_nContributors=" << vertex.getNContributors()
1463 << "isNearestVertex=" << isNearestVtx
1464 // tpc track properties
1465 << "pt=" << trkOrig.getPt()
1466 << "qpt_ITSTPC=" << pt_ITS
1467 << "tpc_timebin=" << trkOrig.getTime0()
1468 << "qpt=" << trkOrig.getParam(4)
1469 << "ncl=" << trkOrig.getNClusters()
1470 << "ncl_shared=" << trkOrig.getNClusters()
1471 << "tgl=" << trkOrig.getTgl()
1472 << "side_type=" << typeSide
1473 << "phi=" << trkOrig.getPhi()
1474 << "clusterMask=" << clusterMask
1475 << "dedxTPC=" << trkOrig.getdEdx()
1476 << "chi2=" << trkOrig.getChi2()
1477 << "mX=" << trkOrig.getX()
1478 << "mX_ITS=" << mx_ITS
1479 << "nClITS=" << nClITS
1480 << "chi2ITS=" << chi2ITS
1481 << "chi2match_ITSTPC=" << chi2match_ITSTPC
1482 << "PID=" << trkOrig.getPID().getID()
1483 // TPC cov at vertex (without vertex constrained)
1484 << "covTPCAtVertex0=" << covTPCAtVertex0
1485 << "covTPCAtVertex1=" << covTPCAtVertex1
1486 // TPC cov at vertex (with vertex constrained)
1487 << "covTPCConstrVtxP2=" << covTPCConstrVtxP2
1488 << "covTPCConstrVtxP3=" << covTPCConstrVtxP3
1489 << "covTPCConstrVtxP4=" << covTPCConstrVtxP4
1490 // ITS-TPC cov at vertex (with vertex constrained)
1491 << "covITSTPCConstrVtxP2=" << covITSTPCConstrVtxP2
1492 << "covITSTPCConstrVtxP3=" << covITSTPCConstrVtxP3
1493 << "covITSTPCConstrVtxP4=" << covITSTPCConstrVtxP4
1494 // delta Parameter at vertex with TPC track constrained at vertex
1495 << "deltaP2ConstrVtx=" << deltaP2ConstrVtx
1496 << "deltaP3ConstrVtx=" << deltaP3ConstrVtx
1497 << "deltaP4ConstrVtx=" << deltaP4ConstrVtx
1498 //
1499 << "deltaPar0=" << deltaP0
1500 << "deltaPar1=" << deltaP1
1501 << "deltaPar2=" << deltaP2
1502 << "deltaPar3=" << deltaP3
1503 << "deltaPar4=" << deltaP4
1504 << "sigmaY2=" << sigmaY2
1505 << "sigmaZ2=" << sigmaZ2
1506 // meta
1507 << "mult=" << mNTracksWindow[iTrk]
1508 << "time_window_mult=" << mTimeWindowMUS
1509 << "firstTFOrbit=" << mFirstTFOrbit
1510 << "timeMS=" << mTimeMS
1511 << "run=" << mRun
1512 << "mVDrift=" << mVDrift
1513 << "its_flag=" << int(gID)
1514 << "sqrtChi2Match=" << chi2Match
1515 // TOF cluster
1516 << "tpcYDeltaAtTOF=" << tpcYDeltaAtTOF
1517 << "tpcZDeltaAtTOF=" << tpcZDeltaAtTOF
1518 << "mDXatTOF=" << std::get<1>(idxTPCTrackToTOFCluster[iTrk])
1519 << "mDZatTOF=" << std::get<2>(idxTPCTrackToTOFCluster[iTrk])
1520 << "mTOFLength=" << std::get<3>(idxTPCTrackToTOFCluster[iTrk])
1521 << "mTOFSignal=" << std::get<4>(idxTPCTrackToTOFCluster[iTrk])
1522 << "mDeltaTTOFTPC=" << std::get<5>(idxTPCTrackToTOFCluster[iTrk])
1523 << "vertexTime=" << vertexTime
1524 << "trackTime0=" << trackTime0
1525 << "TOFmask=" << std::get<6>(idxTPCTrackToTOFCluster[iTrk])
1526 << "TOFchannel=" << std::get<7>(idxTPCTrackToTOFCluster[iTrk])
1527 // TPC delta param
1528 << "deltaTPCParamInOutTgl=" << deltaTPCParamInOutTgl
1529 << "deltaTPCParamInOutQPt=" << deltaTPCParamInOutQPt
1530 // delta parameter between ITS-TPC - TPC at 60 cm
1531 << "deltaP0OuterITS=" << deltaP0OuterITS
1532 << "deltaP1OuterITS=" << deltaP1OuterITS
1533 << "deltaP2OuterITS=" << deltaP2OuterITS
1534 << "deltaP3OuterITS=" << deltaP3OuterITS
1535 << "deltaP4OuterITS=" << deltaP4OuterITS
1536 << "mXOuterMatching=" << mXOuterMatching
1537 // phi of ITS-TPC track at vertex
1538 << "phiITSTPCAtVertex=" << phiITSTPCAtVertex
1539 << "\n";
1540 }
1541 }
1542 }
1543
1544 void sendOutput(ProcessingContext& pc)
1545 {
1546 mBufferDCA.mTSTPC.setStartTime(mTimeMS);
1547 mBufferDCA.mTSITSTPC.setStartTime(mTimeMS);
1548 pc.outputs().snapshot(Output{header::gDataOriginTPC, getDataDescriptionTimeSeries()}, mBufferDCA);
1549 // in case of ROOT output also store the TFinfo in the TTree
1550 if (!mDisableWriter) {
1553 pc.outputs().snapshot(Output{header::gDataOriginTPC, getDataDescriptionTPCTimeSeriesTFId()}, tfinfo);
1554 }
1555 }
1556
1558 void findNearesVertex(const gsl::span<const TrackTPC> tracksTPC, const gsl::span<const o2::dataformats::PrimaryVertex> vertices)
1559 {
1560 // create list of time bins of tracks
1561 const int nVertices = vertices.size();
1562
1563 const int nTracks = tracksTPC.size();
1564 mNearestVtxTPC.clear();
1565 mNearestVtxTPC.resize(nTracks);
1566
1567 // in case no vertices are found
1568 if (!nVertices) {
1569 std::fill(mNearestVtxTPC.begin(), mNearestVtxTPC.end(), -1);
1570 return;
1571 }
1572
1573 // store timestamps of vertices. Assume vertices are already sorted in time!
1574 std::vector<float> times_vtx;
1575 times_vtx.reserve(nVertices);
1576 for (const auto& vtx : vertices) {
1577 times_vtx.emplace_back(vtx.getTimeStamp().getTimeStamp());
1578 }
1579
1580 // loop over tpc tracks and find nearest vertex
1581 auto myThread = [&](int iThread) {
1582 for (int i = iThread; i < nTracks; i += mNThreads) {
1583 const float timeTrack = o2::tpc::ParameterElectronics::Instance().ZbinWidth * tracksTPC[i].getTime0();
1584 const auto lower = std::lower_bound(times_vtx.begin(), times_vtx.end(), timeTrack);
1585 int closestVtx = std::distance(times_vtx.begin(), lower);
1586 // if value is out of bounds use last value
1587 if (closestVtx == nVertices) {
1588 closestVtx -= 1;
1589 } else if (closestVtx > 0) {
1590 // if idx > 0 check preceeding value
1591 double diff1 = std::abs(timeTrack - *lower);
1592 double diff2 = std::abs(timeTrack - *(lower - 1));
1593 if (diff2 < diff1) {
1594 closestVtx -= 1;
1595 }
1596 }
1597 mNearestVtxTPC[i] = closestVtx;
1598 }
1599 };
1600
1601 std::vector<std::thread> threads(mNThreads);
1602 for (int i = 0; i < mNThreads; i++) {
1603 threads[i] = std::thread(myThread, i);
1604 }
1605
1606 // wait for the threads to finish
1607 for (auto& th : threads) {
1608 th.join();
1609 }
1610 }
1611
1613 std::vector<bool> makeClusterBitMask(const TrackTPC& track) const
1614 {
1615 std::vector<bool> tpcClusterMask(Mapper::PADROWS, false);
1616 const int nCl = track.getNClusterReferences();
1617 for (int j = 0; j < nCl; ++j) {
1618 uint8_t sector, padrow;
1619 uint32_t clusterIndexInRow;
1620 track.getClusterReference(mTPCTrackClIdx, j, sector, padrow, clusterIndexInRow);
1621 tpcClusterMask[padrow] = true;
1622 }
1623 return tpcClusterMask;
1624 }
1625
1627 void findNNeighbourTracks(const gsl::span<const TrackTPC> tracksTPC)
1628 {
1629 const float tpcTBinMUS = o2::tpc::ParameterElectronics::Instance().ZbinWidth; // 0.199606f; time bin in MUS
1630 const float windowTimeBins = mTimeWindowMUS / tpcTBinMUS; // number of neighbouring time bins to check
1631
1632 // create list of time bins of tracks
1633 std::vector<float> times;
1634 const int nTracks = tracksTPC.size();
1635 times.reserve(nTracks);
1636 for (const auto& trk : tracksTPC) {
1637 times.emplace_back(trk.getTime0());
1638 }
1639 std::sort(times.begin(), times.end());
1640
1641 mNTracksWindow.clear();
1642 mNTracksWindow.resize(nTracks);
1643
1644 // loop over tpc tracks and count number of neighouring tracks
1645 auto myThread = [&](int iThread) {
1646 for (int i = iThread; i < nTracks; i += mNThreads) {
1647 const float t0 = tracksTPC[i].getTime0();
1648 const auto upperV0 = std::upper_bound(times.begin(), times.end(), t0 + windowTimeBins);
1649 const auto lowerV0 = std::lower_bound(times.begin(), times.end(), t0 - windowTimeBins);
1650 const int nMult = std::distance(times.begin(), upperV0) - std::distance(times.begin(), lowerV0);
1651 mNTracksWindow[i] = nMult;
1652 }
1653 };
1654
1655 std::vector<std::thread> threads(mNThreads);
1656 for (int i = 0; i < mNThreads; i++) {
1657 threads[i] = std::thread(myThread, i);
1658 }
1659
1660 // wait for the threads to finish
1661 for (auto& th : threads) {
1662 th.join();
1663 }
1664 }
1665
1666 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)
1667 {
1668 // storing collision vertex to ITS-TPC track index
1669 std::unordered_map<unsigned int, int> indicesITSTPC_vtx; // ITS-TPC track index -> collision vertex ID
1670
1671 std::unordered_map<int, int> nContributors_ITS; // ITS: vertex ID -> n contributors
1672 std::unordered_map<int, int> nContributors_ITSTPC; // ITS-TPC (and ITS-TPC-TRD, ITS-TPC-TOF, ITS-TPC-TRD-TOF): vertex ID -> n contributors
1673
1674 // loop over collisions
1675 if (!vertices.empty()) {
1676 for (const auto& ref : primMatchedTracksRef) {
1677 // loop over ITS and ITS-TPC sources
1678 const std::array<TrkSrc, 5> sources = {TrkSrc::ITSTPC, TrkSrc::ITSTPCTRD, TrkSrc::ITSTPCTOF, TrkSrc::ITSTPCTRDTOF, TrkSrc::ITS};
1679 for (auto source : sources) {
1680 const int vID = ref.getVtxID(); // vertex ID
1681 const int firstEntry = ref.getFirstEntryOfSource(source);
1682 const int nEntries = ref.getEntriesOfSource(source);
1683 // loop over all tracks belonging to the vertex
1684 for (int i = 0; i < nEntries; ++i) {
1685 const auto& matchedTrk = primMatchedTracks[i + firstEntry];
1686 bool pvCont = matchedTrk.isPVContributor();
1687 if (pvCont) {
1688 // store index of ITS-TPC track container and vertex ID
1689 auto refITSTPC = recoData.getSingleDetectorRefs(matchedTrk)[TrkSrc::ITSTPC];
1690 if (refITSTPC.isIndexSet()) {
1691 indicesITSTPC_vtx[refITSTPC] = vID;
1692 ++nContributors_ITSTPC[vID];
1693 } else {
1694 ++nContributors_ITS[vID];
1695 }
1696 }
1697 }
1698 }
1699 }
1700 }
1701
1702 // calculate statistics
1703 std::array<RobustAverage, 4> avgVtxITS;
1704 std::array<RobustAverage, 4> avgVtxITSTPC;
1705 for (int i = 0; i < avgVtxITS.size(); ++i) {
1706 avgVtxITS[i].reserve(vertices.size());
1707 avgVtxITSTPC[i].reserve(vertices.size());
1708 }
1709 for (int ivtx = 0; ivtx < vertices.size(); ++ivtx) {
1710 const auto& vtx = vertices[ivtx];
1711 const float itsFrac = nContributors_ITS[ivtx] / static_cast<float>(vtx.getNContributors());
1712 const float itstpcFrac = (nContributors_ITS[ivtx] + nContributors_ITSTPC[ivtx]) / static_cast<float>(vtx.getNContributors());
1713
1714 const float itsMin = 0.2;
1715 const float itsMax = 0.8;
1716 if ((itsFrac > itsMin) && (itsFrac < itsMax)) {
1717 avgVtxITS[0].addValue(vtx.getX());
1718 avgVtxITS[1].addValue(vtx.getY());
1719 avgVtxITS[2].addValue(vtx.getZ());
1720 avgVtxITS[3].addValue(vtx.getNContributors());
1721 }
1722
1723 const float itstpcMax = 0.95;
1724 if (itstpcFrac < itstpcMax) {
1725 avgVtxITSTPC[0].addValue(vtx.getX());
1726 avgVtxITSTPC[1].addValue(vtx.getY());
1727 avgVtxITSTPC[2].addValue(vtx.getZ());
1728 avgVtxITSTPC[3].addValue(vtx.getNContributors());
1729 }
1730 }
1731
1732 // ITS
1733 mBufferDCA.nPrimVertices_ITS.front() = avgVtxITS[3].getValues().size();
1734 mBufferDCA.nVertexContributors_ITS_Median.front() = avgVtxITS[3].getMedian();
1735 mBufferDCA.nVertexContributors_ITS_RMS.front() = avgVtxITS[3].getStdDev();
1736 mBufferDCA.vertexX_ITS_Median.front() = avgVtxITS[0].getMedian();
1737 mBufferDCA.vertexY_ITS_Median.front() = avgVtxITS[1].getMedian();
1738 mBufferDCA.vertexZ_ITS_Median.front() = avgVtxITS[2].getMedian();
1739 mBufferDCA.vertexX_ITS_RMS.front() = avgVtxITS[0].getStdDev();
1740 mBufferDCA.vertexY_ITS_RMS.front() = avgVtxITS[1].getStdDev();
1741 mBufferDCA.vertexZ_ITS_RMS.front() = avgVtxITS[2].getStdDev();
1742
1743 // ITS-TPC
1744 mBufferDCA.nPrimVertices_ITSTPC.front() = avgVtxITSTPC[3].getValues().size();
1745 mBufferDCA.nVertexContributors_ITSTPC_Median.front() = avgVtxITSTPC[3].getMedian();
1746 mBufferDCA.nVertexContributors_ITSTPC_RMS.front() = avgVtxITSTPC[3].getStdDev();
1747 mBufferDCA.vertexX_ITSTPC_Median.front() = avgVtxITSTPC[0].getMedian();
1748 mBufferDCA.vertexY_ITSTPC_Median.front() = avgVtxITSTPC[1].getMedian();
1749 mBufferDCA.vertexZ_ITSTPC_Median.front() = avgVtxITSTPC[2].getMedian();
1750 mBufferDCA.vertexX_ITSTPC_RMS.front() = avgVtxITSTPC[0].getStdDev();
1751 mBufferDCA.vertexY_ITSTPC_RMS.front() = avgVtxITSTPC[1].getStdDev();
1752 mBufferDCA.vertexZ_ITSTPC_RMS.front() = avgVtxITSTPC[2].getStdDev();
1753
1754 // quantiles and truncated mean
1755 RobustAverage avg(vertices.size(), false);
1756 for (const auto& vtx : vertices) {
1757 if (vtx.getNContributors() > mMinTracksPerVertex) {
1758 // transform by n^0.5 to get more flat distribution
1759 avg.addValue(std::sqrt(vtx.getNContributors()));
1760 }
1761 }
1762
1763 // nPrimVertices_Quantiles
1764 int sizeQ = mBufferDCA.nVertexContributors_Quantiles.size();
1765 const int nBinsQ = 20;
1766 if (sizeQ >= (nBinsQ + 3)) {
1767 for (int iq = 0; iq < nBinsQ; ++iq) {
1768 const float quantile = (iq + 1) / static_cast<float>(nBinsQ);
1769 const float val = avg.getQuantile(quantile, 1);
1770 mBufferDCA.nVertexContributors_Quantiles[iq] = val * val;
1771 }
1772 const float tr0 = avg.getTrunctedMean(0.05, 0.95);
1773 const float tr1 = avg.getTrunctedMean(0.1, 0.9);
1774 const float tr2 = avg.getTrunctedMean(0.2, 0.8);
1775 mBufferDCA.nVertexContributors_Quantiles[sizeQ - 3] = tr0 * tr0;
1776 mBufferDCA.nVertexContributors_Quantiles[sizeQ - 2] = tr1 * tr1;
1777 mBufferDCA.nVertexContributors_Quantiles[sizeQ - 1] = tr2 * tr2;
1778 }
1779 mBufferDCA.nPrimVertices.front() = vertices.size();
1780
1781 return indicesITSTPC_vtx;
1782 }
1783
1785 int getNBins() const { return mBufferDCA.mTSTPC.getNBins(); }
1786
1787 ValsdEdx getdEdxVars(bool useQMax, const TrackTPC& track) const
1788 {
1789 const float dedx = useQMax ? track.getdEdx().dEdxMaxTPC : track.getdEdx().dEdxTotTPC;
1790 const float dedxRatioNorm = mPID.getExpectedSignal(track, o2::track::PID::ID(o2::track::PID::Pion)) / dedx;
1791 float dedxNorm = (dedxRatioNorm > 0) ? std::log(mPID.getExpectedSignal(track, o2::track::PID::ID(o2::track::PID::Pion)) / dedx) : -1;
1792 // restrict to specified range
1793 if (std::abs(dedxNorm) > mMaxdEdxRatio) {
1794 dedxNorm = -1;
1795 }
1796
1797 // get log(dedxRegion / dedx)
1798 float dedxIROC = -1;
1799 float dedxOROC1 = -1;
1800 float dedxOROC2 = -1;
1801 float dedxOROC3 = -1;
1802 if (dedx > 0) {
1803 dedxIROC = useQMax ? track.getdEdx().dEdxMaxIROC : track.getdEdx().dEdxTotIROC;
1804 dedxOROC1 = useQMax ? track.getdEdx().dEdxMaxOROC1 : track.getdEdx().dEdxTotOROC1;
1805 dedxOROC2 = useQMax ? track.getdEdx().dEdxMaxOROC2 : track.getdEdx().dEdxTotOROC2;
1806 dedxOROC3 = useQMax ? track.getdEdx().dEdxMaxOROC3 : track.getdEdx().dEdxTotOROC3;
1807 dedxIROC /= dedx;
1808 dedxOROC1 /= dedx;
1809 dedxOROC2 /= dedx;
1810 dedxOROC3 /= dedx;
1811 dedxIROC = (dedxIROC > 0) ? std::log(dedxIROC) : -1;
1812 dedxOROC1 = (dedxOROC1 > 0) ? std::log(dedxOROC1) : -1;
1813 dedxOROC2 = (dedxOROC2 > 0) ? std::log(dedxOROC2) : -1;
1814 dedxOROC3 = (dedxOROC3 > 0) ? std::log(dedxOROC3) : -1;
1815
1816 // restrict to specified range
1817 if (std::abs(dedxIROC) > mMaxdEdxRegionRatio) {
1818 dedxIROC = -1;
1819 }
1820 if (std::abs(dedxOROC1) > mMaxdEdxRegionRatio) {
1821 dedxOROC1 = -1;
1822 }
1823 if (std::abs(dedxOROC2) > mMaxdEdxRegionRatio) {
1824 dedxOROC2 = -1;
1825 }
1826 if (std::abs(dedxOROC3) > mMaxdEdxRegionRatio) {
1827 dedxOROC3 = -1;
1828 }
1829 }
1830 return ValsdEdx{dedxNorm, dedxIROC, dedxOROC1, dedxOROC2, dedxOROC3};
1831 }
1832};
1833
1834o2::framework::DataProcessorSpec getTPCTimeSeriesSpec(const bool disableWriter, const o2::base::Propagator::MatCorrType matType, const bool enableUnbinnedWriter, GTrackID::mask_t src)
1835{
1836 auto dataRequest = std::make_shared<DataRequest>();
1837 bool useMC = false;
1838 GTrackID::mask_t srcTracks = GTrackID::getSourcesMask("TPC,ITS,ITS-TPC,ITS-TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD-TOF") & src;
1839 dataRequest->requestTracks(srcTracks, useMC);
1840 if (src[GTrackID::TPC]) {
1841 dataRequest->requestClusters(GTrackID::getSourcesMask("TPC"), useMC);
1842 }
1843
1844 bool tpcOnly = srcTracks == GTrackID::getSourcesMask("TPC");
1845 if (srcTracks.any() && !tpcOnly) {
1846 dataRequest->requestFT0RecPoints(useMC);
1847 dataRequest->requestPrimaryVertices(useMC);
1848 }
1849
1850 const bool enableAskMatLUT = matType == o2::base::Propagator::MatCorrType::USEMatCorrLUT;
1851 auto ccdbRequest = std::make_shared<o2::base::GRPGeomRequest>(!disableWriter, // orbitResetTime
1852 false, // GRPECS=true for nHBF per TF
1853 false, // GRPLHCIF
1854 true, // GRPMagField
1855 enableAskMatLUT, // askMatLUT
1857 dataRequest->inputs,
1858 true,
1859 true);
1860
1861 o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs);
1863 dataRequest->inputs.emplace_back("tpcSecFlucInfo", o2::header::gDataOriginTPC, "InfoMapSecFluc", 0, Lifetime::Condition, ccdbParamSpec(CDBTypeMap.at(CDBType::CalSecEdgeInfo), {}, 1));
1864
1865 std::vector<OutputSpec> outputs;
1866 outputs.emplace_back(o2::header::gDataOriginTPC, getDataDescriptionTimeSeries(), 0, Lifetime::Sporadic);
1867 if (!disableWriter) {
1868 outputs.emplace_back(o2::header::gDataOriginTPC, getDataDescriptionTPCTimeSeriesTFId(), 0, Lifetime::Sporadic);
1869 }
1870
1871 return DataProcessorSpec{
1872 "tpc-time-series",
1873 dataRequest->inputs,
1874 outputs,
1875 AlgorithmSpec{adaptFromTask<TPCTimeSeries>(ccdbRequest, disableWriter, matType, enableUnbinnedWriter, tpcOnly, dataRequest)},
1876 Options{
1877 {"min-momentum", VariantType::Float, 0.2f, {"Minimum momentum of the tracks"}},
1878 {"min-cluster", VariantType::Int, 80, {"Minimum number of clusters of the tracks"}},
1879 {"max-tgl", VariantType::Float, 1.4f, {"Maximum accepted tgl of the tracks"}},
1880 {"max-qPt", VariantType::Float, 5.f, {"Maximum abs(qPt) bin"}},
1881 {"max-snp", VariantType::Float, 0.85f, {"Maximum sinus(phi) for propagation"}},
1882 {"coarse-step", VariantType::Float, 5.f, {"Coarse step during track propagation"}},
1883 {"fine-step", VariantType::Float, 2.f, {"Fine step during track propagation"}},
1884 {"mX-coarse", VariantType::Float, 40.f, {"Perform coarse propagation up to this mx"}},
1885 {"max-tracks", VariantType::Int, -1, {"Number of maximum tracks to process"}},
1886 {"cut-DCA-median", VariantType::Float, 3.f, {"Cut on the DCA: abs(DCA-medianDCA)<cut-DCA-median"}},
1887 {"cut-DCA-RMS", VariantType::Float, 3.f, {"Sigma cut on the DCA"}},
1888 {"refX-for-sector", VariantType::Float, 108.475f, {"Reference local x position for the sector information (default centre of IROC)"}},
1889 {"refX-for-outer-ITS", VariantType::Float, 60.f, {"Reference local x position for matching at outer ITS"}},
1890 {"tgl-bins", VariantType::Int, 30, {"Number of tgl bins for time series variables"}},
1891 {"phi-bins", VariantType::Int, 54, {"Number of phi bins for time series variables"}},
1892 {"qPt-bins", VariantType::Int, 18, {"Number of qPt bins for time series variables"}},
1893 {"mult-bins", VariantType::Int, 25, {"Number of multiplicity bins for time series variables"}},
1894 {"mult-max", VariantType::Int, 50000, {"MAximum multiplicity bin"}},
1895 {"threads", VariantType::Int, 4, {"Number of parallel threads"}},
1896 {"max-ITS-TPC-DCAr", VariantType::Float, 0.2f, {"Maximum absolut DCAr value for ITS-TPC tracks"}},
1897 {"max-ITS-TPC-DCAz", VariantType::Float, 10.f, {"Maximum absolut DCAz value for ITS-TPC tracks - larger due to vertex spread"}},
1898 {"max-ITS-TPC-DCAr_comb", VariantType::Float, 0.2f, {"Maximum absolut DCAr value for ITS-TPC tracks to vertex for combined DCA"}},
1899 {"max-ITS-TPC-DCAz_comb", VariantType::Float, 0.2f, {"Maximum absolut DCAr value for ITS-TPC tracks to vertex for combined DCA"}},
1900 {"MIP-dedx", VariantType::Float, 50.f, {"MIP dEdx for MIP/dEdx monitoring"}},
1901 {"time-window-mult-mus", VariantType::Float, 50.f, {"Time window in micro s for multiplicity estimate"}},
1902 {"sqrts", VariantType::Float, 13600.f, {"Centre of mass energy used for downsampling"}},
1903 {"min-tracks-per-vertex", VariantType::Int, 6, {"Minimum number of tracks per vertex required"}},
1904 {"max-dedx-ratio", VariantType::Float, 0.3f, {"Maximum absolute log(dedx(pion)/dedx) ratio"}},
1905 {"max-dedx-region-ratio", VariantType::Float, 0.5f, {"Maximum absolute log(dedx(region)/dedx) ratio"}},
1906 {"sample-unbinned-tsallis", VariantType::Bool, false, {"Perform sampling of unbinned data based on Tsallis function"}},
1907 {"sampling-factor", VariantType::Float, 0.001f, {"Sampling factor in case sample-unbinned-tsallis is used"}},
1908 {"disable-min-bias-trigger", VariantType::Bool, false, {"Disable the minimum bias trigger for skimmed data"}},
1909 {"out-file-unbinned", VariantType::String, "time_series_tracks.root", {"name of the output file for the unbinned data"}},
1910 {"max-occupancy-bins", VariantType::Int, 912, {"Maximum number of occupancy bins"}}}};
1911}
1912
1913} // namespace tpc
1914} // end namespace o2
std::vector< unsigned long > times
CDB Type definitions for TPC.
Wrapper container for different reconstructed object types.
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.
calibrator class for accumulating integrated clusters
bounded_vector< float > bins
Class to store the output of the matching to TOF.
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:178
static mask_t getSourcesMask(const std::string_view srcList)
Static class with identifiers, bitmasks and names for ALICE detectors.
Definition DetID.h:58
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
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 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
static constexpr ID Pion
Definition PID.h:96
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 GLuint mask
Definition glcorearb.h:291
GLsizei GLenum * sources
Definition glcorearb.h:2516
constexpr o2::header::DataOrigin gDataOriginTPC
Definition DataHeader.h:576
uint8_t itsSharedClusterMap uint8_t
constexpr double LHCOrbitMUS
constexpr double LHCBunchSpacingNS
constexpr float TwoPI
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)
std::vector< ConfigParamSpec > Options
o2::tpc::PIDResponse PIDResponse
Definition PIDStudy.cxx:69
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
constexpr unsigned char SECTORSPERSIDE
Definition Defs.h:40
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:35
@ A
Definition Defs.h:35
@ C
Definition Defs.h:36
TrackParCovF TrackParCov
Definition Track.h:33
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
static void fillTFIDInfo(o2::framework::ProcessingContext &pc, o2::dataformats::TFIDInfo &ti)
GlobalIDSet getSingleDetectorRefs(GTrackID gidx) const
GTrackID getTPCContributorGID(GTrackID source) const
void collectData(o2::framework::ProcessingContext &pc, const DataRequest &request)
gsl::span< const unsigned int > occupancyMapTPC
externally set TPC clusters occupancy map
static bool downsampleTsallisCharged(float pt, float factorPt, float sqrts, float &weight, float rnd, float mass=0.13957)
Definition Tsallis.cxx:31
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
vec clear()
std::uniform_int_distribution< unsigned long long > distr