Project
Loading...
Searching...
No Matches
Clusterer.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
14#include <algorithm>
15#include <TTree.h>
16#include "Framework/Logger.h"
20
21#ifdef WITH_OPENMP
22#include <omp.h>
23#endif
24using namespace o2::itsmft;
25
26//__________________________________________________
27void Clusterer::process(int nThreads, PixelReader& reader, CompClusCont* compClus,
28 PatternCont* patterns, ROFRecCont* vecROFRec, MCTruth* labelsCl)
29{
30#ifdef _PERFORM_TIMING_
31 mTimer.Start(kFALSE);
32#endif
33 if (nThreads < 1) {
34 nThreads = 1;
35 }
36 auto autoDecode = reader.getDecodeNextAuto();
37 int rofcount{0};
38 o2::InteractionRecord lastIR{};
39 do {
40 if (autoDecode) {
41 reader.setDecodeNextAuto(false); // internally do not autodecode
42 if (!reader.decodeNextTrigger()) {
43 break; // on the fly decoding was requested, but there were no data left
44 }
45 }
46 if (reader.getInteractionRecord().isDummy()) {
47 continue; // No IR info was found
48 }
49 if (!lastIR.isDummy() && lastIR >= reader.getInteractionRecord()) {
50 const int MaxErrLog = 2;
51 static int errLocCount = 0;
52 if (errLocCount++ < MaxErrLog) {
53 LOGP(warn, "Impossible ROF IR {}, does not exceed previous {}, discarding in clusterization", reader.getInteractionRecord().asString(), lastIR.asString());
54 }
55 continue;
56 }
57 lastIR = reader.getInteractionRecord();
58 // pre-fetch all non-empty chips of current ROF
59 ChipPixelData* curChipData = nullptr;
60 mFiredChipsPtr.clear();
61 size_t nPix = 0;
62 while ((curChipData = reader.getNextChipData(mChips))) {
63 mFiredChipsPtr.push_back(curChipData);
64 nPix += curChipData->getData().size();
65 }
66
67 auto& rof = vecROFRec->emplace_back(reader.getInteractionRecord(), vecROFRec->size(), compClus->size(), 0); // create new ROF
68
69 uint16_t nFired = mFiredChipsPtr.size();
70 if (!nFired) {
71 if (autoDecode) {
72 continue;
73 }
74 break; // just 1 ROF was asked to be processed
75 }
76 if (nFired < nThreads) {
77 nThreads = nFired;
78 }
79#ifndef WITH_OPENMP
80 nThreads = 1;
81#endif
82 uint16_t chipStep = nThreads > 1 ? (nThreads == 2 ? 20 : 10) : nFired;
83 int dynGrp = std::min(4, std::max(1, nThreads / 2));
84 if (nThreads > mThreads.size()) {
85 int oldSz = mThreads.size();
86 mThreads.resize(nThreads);
87 for (int i = oldSz; i < nThreads; i++) {
88 mThreads[i] = std::make_unique<ClustererThread>(this, i);
89 }
90 }
91#ifdef WITH_OPENMP
92#pragma omp parallel for schedule(dynamic, dynGrp) num_threads(nThreads)
93 //>> start of MT region
94 for (uint16_t ic = 0; ic < nFired; ic += chipStep) {
95 auto ith = omp_get_thread_num();
96 if (nThreads > 1) {
97 mThreads[ith]->process(ic, std::min(chipStep, uint16_t(nFired - ic)),
98 &mThreads[ith]->compClusters,
99 patterns ? &mThreads[ith]->patterns : nullptr,
100 labelsCl ? reader.getDigitsMCTruth() : nullptr,
101 labelsCl ? &mThreads[ith]->labels : nullptr, rof);
102 } else { // put directly to the destination
103 mThreads[0]->process(0, nFired, compClus, patterns, labelsCl ? reader.getDigitsMCTruth() : nullptr, labelsCl, rof);
104 }
105 }
106 //<< end of MT region
107#else
108 mThreads[0]->process(0, nFired, compClus, patterns, labelsCl ? reader.getDigitsMCTruth() : nullptr, labelsCl, rof);
109#endif
110 // copy data of all threads but the 1st one to final destination
111 if (nThreads > 1) {
112#ifdef _PERFORM_TIMING_
113 mTimerMerge.Start(false);
114#endif
115 size_t nClTot = 0, nPattTot = 0;
116 int chid = 0, thrStatIdx[nThreads];
117 for (int ith = 0; ith < nThreads; ith++) {
118 std::sort(mThreads[ith]->stats.begin(), mThreads[ith]->stats.end(), [](const ThreadStat& a, const ThreadStat& b) { return a.firstChip < b.firstChip; });
119 thrStatIdx[ith] = 0;
120 nClTot += mThreads[ith]->compClusters.size();
121 nPattTot += mThreads[ith]->patterns.size();
122 }
123 compClus->reserve(nClTot);
124 if (patterns) {
125 patterns->reserve(nPattTot);
126 }
127 while (chid < nFired) {
128 for (int ith = 0; ith < nThreads; ith++) {
129 if (thrStatIdx[ith] >= mThreads[ith]->stats.size()) {
130 continue;
131 }
132 const auto& stat = mThreads[ith]->stats[thrStatIdx[ith]];
133 if (stat.firstChip == chid) {
134 thrStatIdx[ith]++;
135 chid += stat.nChips; // next chip to look
136 const auto clbeg = mThreads[ith]->compClusters.begin() + stat.firstClus;
137 auto szold = compClus->size();
138 compClus->insert(compClus->end(), clbeg, clbeg + stat.nClus);
139 if (patterns) {
140 const auto ptbeg = mThreads[ith]->patterns.begin() + stat.firstPatt;
141 patterns->insert(patterns->end(), ptbeg, ptbeg + stat.nPatt);
142 }
143 if (labelsCl) {
144 labelsCl->mergeAtBack(mThreads[ith]->labels, stat.firstClus, stat.nClus);
145 }
146 }
147 }
148 }
149 for (int ith = 0; ith < nThreads; ith++) {
150 mThreads[ith]->patterns.clear();
151 mThreads[ith]->compClusters.clear();
152 mThreads[ith]->labels.clear();
153 mThreads[ith]->stats.clear();
154 }
155#ifdef _PERFORM_TIMING_
156 mTimerMerge.Stop();
157#endif
158 } else {
159 mThreads[0]->stats.clear();
160 }
161 rof.setNEntries(compClus->size() - rof.getFirstEntry()); // update
162 } while (autoDecode);
163 reader.setDecodeNextAuto(autoDecode); // restore setting
164#ifdef _PERFORM_TIMING_
165 mTimer.Stop();
166#endif
167}
168
169//__________________________________________________
170void Clusterer::ClustererThread::process(uint16_t chip, uint16_t nChips, CompClusCont* compClusPtr, PatternCont* patternsPtr,
171 const ConstMCTruth* labelsDigPtr, MCTruth* labelsClPtr, const ROFRecord& rofPtr)
172{
173 if (stats.empty() || stats.back().firstChip + stats.back().nChips != chip) { // there is a jump, register new block
174 stats.emplace_back(ThreadStat{chip, 0, uint32_t(compClusPtr->size()), patternsPtr ? uint32_t(patternsPtr->size()) : 0, 0, 0});
175 }
176 for (int ic = 0; ic < nChips; ic++) {
177 auto* curChipData = parent->mFiredChipsPtr[chip + ic];
178 auto chipID = curChipData->getChipID();
179 if (parent->mMaxBCSeparationToMask > 0) { // mask pixels fired from the previous ROF
180 const auto& chipInPrevROF = parent->mChipsOld[chipID];
181 if (std::abs(rofPtr.getBCData().differenceInBC(chipInPrevROF.getInteractionRecord())) < parent->mMaxBCSeparationToMask) {
182 parent->mMaxRowColDiffToMask ? curChipData->maskFiredInSample(parent->mChipsOld[chipID], parent->mMaxRowColDiffToMask) : curChipData->maskFiredInSample(parent->mChipsOld[chipID]);
183 }
184 }
185 auto nclus0 = compClusPtr->size();
186 auto validPixID = curChipData->getFirstUnmasked();
187 auto npix = curChipData->getData().size();
188 if (validPixID < npix) { // chip data may have all of its pixels masked!
189 auto valp = validPixID++;
190 if (validPixID == npix) { // special case of a single pixel fired on the chip
191 finishChipSingleHitFast(valp, curChipData, compClusPtr, patternsPtr, labelsDigPtr, labelsClPtr);
192 } else {
193 initChip(curChipData, valp);
194 for (; validPixID < npix; validPixID++) {
195 if (!curChipData->getData()[validPixID].isMasked()) {
196 updateChip(curChipData, validPixID);
197 }
198 }
199 finishChip(curChipData, compClusPtr, patternsPtr, labelsDigPtr, labelsClPtr);
200 }
201 }
202 if (parent->mMaxBCSeparationToMask > 0) { // current chip data will be used in the next ROF to mask overflow pixels
203 parent->mChipsOld[chipID].swap(*curChipData);
204 }
205 }
206 auto& currStat = stats.back();
207 currStat.nChips += nChips;
208 currStat.nClus = compClusPtr->size() - currStat.firstClus;
209 currStat.nPatt = patternsPtr ? (patternsPtr->size() - currStat.firstPatt) : 0;
210}
211
212//__________________________________________________
214 PatternCont* patternsPtr, const ConstMCTruth* labelsDigPtr, MCTruth* labelsClusPtr)
215{
216 const auto& pixData = curChipData->getData();
217 for (int i1 = 0; i1 < preClusterHeads.size(); ++i1) {
218 auto ci = preClusterIndices[i1];
219 if (ci < 0) {
220 continue;
221 }
222 BBox bbox(curChipData->getChipID());
223 int nlab = 0;
224 int next = preClusterHeads[i1];
225 pixArrBuff.clear();
226 while (next >= 0) {
227 const auto& pixEntry = pixels[next];
228 const auto pix = pixData[pixEntry.second];
229 pixArrBuff.push_back(pix); // needed for cluster topology
230 bbox.adjust(pix.getRowDirect(), pix.getCol());
231 if (labelsClusPtr) {
232 if (parent->mSquashingDepth) { // the MCtruth for this pixel is stored in chip data: due to squashing we lose contiguity
233 fetchMCLabels(curChipData->getOrderedPixId(pixEntry.second), labelsDigPtr, nlab);
234 } else { // the MCtruth for this pixel is at curChipData->startID+pixEntry.second
235 fetchMCLabels(pixEntry.second + curChipData->getStartID(), labelsDigPtr, nlab);
236 }
237 }
238 next = pixEntry.first;
239 }
240 preClusterIndices[i1] = -1;
241 for (int i2 = i1 + 1; i2 < preClusterHeads.size(); ++i2) {
242 if (preClusterIndices[i2] != ci) {
243 continue;
244 }
245 next = preClusterHeads[i2];
246 while (next >= 0) {
247 const auto& pixEntry = pixels[next];
248 const auto pix = pixData[pixEntry.second]; // PixelData
249 pixArrBuff.push_back(pix); // needed for cluster topology
250 bbox.adjust(pix.getRowDirect(), pix.getCol());
251 if (labelsClusPtr) {
252 if (parent->mSquashingDepth) { // the MCtruth for this pixel is stored in chip data: due to squashing we lose contiguity
253 fetchMCLabels(curChipData->getOrderedPixId(pixEntry.second), labelsDigPtr, nlab);
254 } else { // the MCtruth for this pixel is at curChipData->startID+pixEntry.second
255 fetchMCLabels(pixEntry.second + curChipData->getStartID(), labelsDigPtr, nlab);
256 }
257 }
258 next = pixEntry.first;
259 }
260 preClusterIndices[i2] = -1;
261 }
262 if (bbox.isAcceptableSize()) {
263 parent->streamCluster(pixArrBuff, &labelsBuff, bbox, parent->mPattIdConverter, compClusPtr, patternsPtr, labelsClusPtr, nlab);
264 } else {
265 auto warnLeft = MaxHugeClusWarn - parent->mNHugeClus;
266 if (!parent->mDropHugeClusters) {
267 if (warnLeft > 0) {
268 LOGP(warn, "Splitting a huge cluster: chipID {}, rows {}:{} cols {}:{}{}", bbox.chipID, bbox.rowMin, bbox.rowMax, bbox.colMin, bbox.colMax,
269 warnLeft == 1 ? " (Further warnings will be muted)" : "");
270#ifdef WITH_OPENMP
271#pragma omp critical
272#endif
273 {
274 parent->mNHugeClus++;
275 }
276 }
277 BBox bboxT(bbox); // truncated box
278 std::vector<PixelData> pixbuf;
279 do {
280 bboxT.rowMin = bbox.rowMin;
281 bboxT.colMax = std::min(bbox.colMax, uint16_t(bboxT.colMin + o2::itsmft::ClusterPattern::MaxColSpan - 1));
282 do { // Select a subset of pixels fitting the reduced bounding box
283 bboxT.rowMax = std::min(bbox.rowMax, uint16_t(bboxT.rowMin + o2::itsmft::ClusterPattern::MaxRowSpan - 1));
284 for (const auto& pix : pixArrBuff) {
285 if (bboxT.isInside(pix.getRowDirect(), pix.getCol())) {
286 pixbuf.push_back(pix);
287 }
288 }
289 if (!pixbuf.empty()) { // Stream a piece of cluster only if the reduced bounding box is not empty
290 parent->streamCluster(pixbuf, &labelsBuff, bboxT, parent->mPattIdConverter, compClusPtr, patternsPtr, labelsClusPtr, nlab, true);
291 pixbuf.clear();
292 }
293 bboxT.rowMin = bboxT.rowMax + 1;
294 } while (bboxT.rowMin < bbox.rowMax);
295 bboxT.colMin = bboxT.colMax + 1;
296 } while (bboxT.colMin < bbox.colMax);
297 }
298 }
299 }
300}
301
302//__________________________________________________
304 PatternCont* patternsPtr, const ConstMCTruth* labelsDigPtr, MCTruth* labelsClusPtr)
305{
306 auto pix = curChipData->getData()[hit];
307 uint16_t row = pix.getRowDirect(), col = pix.getCol();
308
309 if (labelsClusPtr) { // MC labels were requested
310 int nlab = 0;
311 fetchMCLabels(curChipData->getStartID() + hit, labelsDigPtr, nlab);
312 auto cnt = compClusPtr->size();
313 for (int i = nlab; i--;) {
314 labelsClusPtr->addElement(cnt, labelsBuff[i]);
315 }
316 }
317
318 // add to compact clusters, which must be always filled
319 unsigned char patt[ClusterPattern::MaxPatternBytes]{0x1 << (7 - (0 % 8))}; // unrolled 1 hit version of full loop in finishChip
320 uint16_t pattID = (parent->mPattIdConverter.size() == 0) ? CompCluster::InvalidPatternID : parent->mPattIdConverter.findGroupID(1, 1, patt);
321 if ((pattID == CompCluster::InvalidPatternID || parent->mPattIdConverter.isGroup(pattID)) && patternsPtr) {
322 patternsPtr->emplace_back(1); // rowspan
323 patternsPtr->emplace_back(1); // colspan
324 patternsPtr->insert(patternsPtr->end(), std::begin(patt), std::begin(patt) + 1);
325 }
326 compClusPtr->emplace_back(row, col, pattID, curChipData->getChipID());
327}
328
329//__________________________________________________
330Clusterer::Clusterer() : mPattIdConverter()
331{
332#ifdef _PERFORM_TIMING_
333 mTimer.Stop();
334 mTimer.Reset();
335 mTimerMerge.Stop();
336 mTimerMerge.Reset();
337#endif
338}
339
340//__________________________________________________
342{
343 // init chip with the 1st unmasked pixel (entry "from" in the mChipData)
344 prev = column1 + 1;
345 curr = column2 + 1;
347
348 pixels.clear();
349 preClusterHeads.clear();
350 preClusterIndices.clear();
351 auto pix = curChipData->getData()[first];
352 currCol = pix.getCol();
353 curr[pix.getRowDirect()] = 0; // can use getRowDirect since the pixel is not masked
354 // start the first pre-cluster
355 preClusterHeads.push_back(0);
356 preClusterIndices.push_back(0);
357 pixels.emplace_back(-1, first); // id of current pixel
358 noLeftCol = true; // flag that there is no column on the left to check yet
359}
360
361//__________________________________________________
362void Clusterer::ClustererThread::updateChip(const ChipPixelData* curChipData, uint32_t ip)
363{
364 const auto pix = curChipData->getData()[ip];
365 uint16_t row = pix.getRowDirect(); // can use getRowDirect since the pixel is not masked
366 if (currCol != pix.getCol()) { // switch the buffers
367 swapColumnBuffers();
368 resetColumn(curr);
369 noLeftCol = false;
370 if (pix.getCol() > currCol + 1) {
371 // no connection with previous column, this pixel cannot belong to any of the
372 // existing preclusters, create a new precluster and flag to check only the row above for next pixels of this column
373 currCol = pix.getCol();
374 addNewPrecluster(ip, row);
375 noLeftCol = true;
376 return;
377 }
378 currCol = pix.getCol();
379 }
380
381 Bool_t orphan = true;
382
383 if (noLeftCol) { // check only the row above
384 if (curr[row - 1] >= 0) {
385 expandPreCluster(ip, row, curr[row - 1]); // attach to the precluster of the previous row
386 return;
387 }
388 } else {
389#ifdef _ALLOW_DIAGONAL_ALPIDE_CLUSTERS_
390 int neighbours[]{curr[row - 1], prev[row], prev[row + 1], prev[row - 1]};
391#else
392 int neighbours[]{curr[row - 1], prev[row]};
393#endif
394 for (auto pci : neighbours) {
395 if (pci < 0) {
396 continue;
397 }
398 if (orphan) {
399 expandPreCluster(ip, row, pci); // attach to the adjascent precluster
400 orphan = false;
401 continue;
402 }
403 // reassign precluster index to smallest one
404 if (preClusterIndices[pci] < preClusterIndices[curr[row]]) {
405 preClusterIndices[curr[row]] = preClusterIndices[pci];
406 } else {
407 preClusterIndices[pci] = preClusterIndices[curr[row]];
408 }
409 }
410 }
411 if (orphan) {
412 addNewPrecluster(ip, row); // start new precluster
413 }
414}
415
416//__________________________________________________
417void Clusterer::ClustererThread::fetchMCLabels(int digID, const ConstMCTruth* labelsDig, int& nfilled)
418{
419 // transfer MC labels to cluster
420 if (nfilled >= MaxLabels) {
421 return;
422 }
423 const auto& lbls = labelsDig->getLabels(digID);
424 for (int i = lbls.size(); i--;) {
425 int ic = nfilled;
426 for (; ic--;) { // check if the label is already present
427 if (labelsBuff[ic] == lbls[i]) {
428 return; // label is found, do nothing
429 }
430 }
431 labelsBuff[nfilled++] = lbls[i];
432 if (nfilled >= MaxLabels) {
433 break;
434 }
435 }
436 //
437}
438
439//__________________________________________________
441{
442 // reset
443#ifdef _PERFORM_TIMING_
444 mTimer.Stop();
445 mTimer.Reset();
446 mTimerMerge.Stop();
447 mTimerMerge.Reset();
448#endif
449}
450
451//__________________________________________________
453{
454 // print settings
455 LOGP(info, "Clusterizer squashes overflow pixels separated by {} BC and <= {} in row/col seeking down to {} neighbour ROFs", mMaxBCSeparationToSquash, mMaxRowColDiffToMask, mSquashingDepth);
456 LOGP(info, "Clusterizer masks overflow pixels separated by < {} BC and <= {} in row/col", mMaxBCSeparationToMask, mMaxRowColDiffToMask);
457 LOGP(info, "Clusterizer does {} drop huge clusters", mDropHugeClusters ? "" : "not");
458
459#ifdef _PERFORM_TIMING_
460 auto& tmr = const_cast<TStopwatch&>(mTimer); // ugly but this is what root does internally
461 auto& tmrm = const_cast<TStopwatch&>(mTimerMerge);
462 LOG(info) << "Inclusive clusterization timing (w/o disk IO): Cpu: " << tmr.CpuTime()
463 << " Real: " << tmr.RealTime() << " s in " << tmr.Counter() << " slots";
464 LOG(info) << "Threads output merging timing : Cpu: " << tmrm.CpuTime()
465 << " Real: " << tmrm.RealTime() << " s in " << tmrm.Counter() << " slots";
466
467#endif
468}
469
470//__________________________________________________
472{
473 // reset for new run
474 clear();
475 mNHugeClus = 0;
476}
int32_t i
Definition of the ITS cluster finder.
Definition of a container to keep Monte Carlo truth external to simulation objects.
uint32_t col
Definition RawData.h:4
gsl::span< const TruthElement > getLabels(uint32_t dataindex) const
void mergeAtBack(MCTruthContainer< TruthElement > const &other)
void addElement(uint32_t dataindex, TruthElement const &element, bool noElement=false)
uint32_t getOrderedPixId(int pos) const
Definition PixelData.h:275
uint32_t getStartID() const
Definition PixelData.h:110
uint16_t getChipID() const
Definition PixelData.h:108
const std::vector< PixelData > & getData() const
Definition PixelData.h:115
static constexpr int MaxPatternBytes
static constexpr uint8_t MaxRowSpan
static constexpr uint8_t MaxColSpan
void process(int nThreads, PixelReader &r, CompClusCont *compClus, PatternCont *patterns, ROFRecCont *vecROFRec, MCTruth *labelsCl=nullptr)
Definition Clusterer.cxx:27
static constexpr int MaxLabels
Definition Clusterer.h:76
static constexpr int MaxHugeClusWarn
Definition Clusterer.h:77
static constexpr unsigned short InvalidPatternID
Definition CompCluster.h:46
PixelReader class for the ITSMFT.
Definition PixelReader.h:34
virtual int decodeNextTrigger()=0
bool getDecodeNextAuto() const
Definition PixelReader.h:67
void setDecodeNextAuto(bool v)
Definition PixelReader.h:68
const o2::InteractionRecord & getInteractionRecord() const
Definition PixelReader.h:58
virtual const o2::dataformats::ConstMCTruthContainerView< o2::MCCompLabel > * getDigitsMCTruth() const
Definition PixelReader.h:49
virtual bool getNextChipData(ChipPixelData &chipData)=0
const BCData & getBCData() const
Definition ROFRecord.h:58
GLint first
Definition glcorearb.h:399
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLint GLint GLsizei GLint GLenum GLenum const void * pixels
Definition glcorearb.h:275
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
std::vector< unsigned char > PatternCont
Definition Clusterer.h:59
std::vector< ROFRecord > ROFRecCont
Definition Clusterer.h:60
std::vector< CompClusterExt > CompClusCont
Definition Clusterer.h:58
std::string asString() const
int64_t differenceInBC(const InteractionRecord &other) const
bool isInside(uint16_t row, uint16_t col) const
Definition Clusterer.h:86
int column2[SegmentationAlpide::NRows+2]
Definition Clusterer.h:129
int column1[SegmentationAlpide::NRows+2]
Definition Clusterer.h:128
void initChip(const ChipPixelData *curChipData, uint32_t first)
void finishChip(ChipPixelData *curChipData, CompClusCont *compClus, PatternCont *patterns, const ConstMCTruth *labelsDig, MCTruth *labelsClus)
uint16_t currCol
Column being processed.
Definition Clusterer.h:137
bool noLeftCol
flag that there is no column on the left to check
Definition Clusterer.h:138
void fetchMCLabels(int digID, const ConstMCTruth *labelsDig, int &nfilled)
void process(uint16_t chip, uint16_t nChips, CompClusCont *compClusPtr, PatternCont *patternsPtr, const ConstMCTruth *labelsDigPtr, MCTruth *labelsClPtr, const ROFRecord &rofPtr)
void finishChipSingleHitFast(uint32_t hit, ChipPixelData *curChipData, CompClusCont *compClusPtr, PatternCont *patternsPtr, const ConstMCTruth *labelsDigPtr, MCTruth *labelsClusPTr)
std::vector< ThreadStat > stats
Definition Clusterer.h:146
void resetColumn(int *buff)
reset column buffer, for the performance reasons we use memset
Definition Clusterer.h:149
void updateChip(const ChipPixelData *curChipData, uint32_t ip)
methods and transient data used within a thread
Definition Clusterer.h:114
std::vector< o2::mch::DsChannelId > chid
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< int > row