Project
Loading...
Searching...
No Matches
GPUReconstructionConvert.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
15#ifndef GPUCA_STANDALONE
17#include "TPCBase/Sector.h"
19#include "TPCBase/Mapper.h"
20#endif
21
23#include "TPCFastTransformPOD.h"
24#include "GPUTPCClusterData.h"
25#include "GPUO2DataTypes.h"
26#include "GPUDataTypesIO.h"
27#include "GPUTPCGeometry.h"
28#include "AliHLTTPCRawCluster.h" // VS: It can not be removed. Used in line 93.
29#include "GPUParam.h"
30#include "GPULogging.h"
31#include <algorithm>
32#include <vector>
33
34#include "clusterFinderDefs.h"
40#include "TPCBase/RDHUtils.h"
41#include "TPCBase/CRU.h"
43
44#include <oneapi/tbb.h>
45
46using namespace o2::gpu;
47using namespace o2::tpc;
48using namespace o2::tpc::constants;
49using namespace std::string_literals;
50
51void GPUReconstructionConvert::ConvertRun2RawToNative(o2::tpc::ClusterNativeAccess& native, std::unique_ptr<ClusterNative[]>& nativeBuffer, const AliHLTTPCRawCluster** rawClusters, uint32_t* nRawClusters)
52{
53 memset((void*)&native, 0, sizeof(native));
54 for (uint32_t i = 0; i < NSECTORS; i++) {
55 for (uint32_t j = 0; j < nRawClusters[i]; j++) {
56 native.nClusters[i][rawClusters[i][j].GetPadRow()]++;
57 }
58 native.nClustersTotal += nRawClusters[i];
59 }
60 nativeBuffer.reset(new ClusterNative[native.nClustersTotal]);
61 native.clustersLinear = nativeBuffer.get();
62 native.setOffsetPtrs();
63 for (uint32_t i = 0; i < NSECTORS; i++) {
64 for (uint32_t j = 0; j < GPUTPCGeometry::NROWS; j++) {
65 native.nClusters[i][j] = 0;
66 }
67 for (uint32_t j = 0; j < nRawClusters[i]; j++) {
68 const AliHLTTPCRawCluster& org = rawClusters[i][j];
69 int32_t row = org.GetPadRow();
70 ClusterNative& c = nativeBuffer[native.clusterOffset[i][row] + native.nClusters[i][row]++];
71 c.setTimeFlags(org.GetTime(), org.GetFlags());
72 c.setPad(org.GetPad());
73 c.setSigmaTime(CAMath::Sqrt(org.GetSigmaTime2()));
74 c.setSigmaPad(CAMath::Sqrt(org.GetSigmaPad2()));
75 c.qMax = org.GetQMax();
76 c.qTotPacked = org.GetCharge();
77 }
78 }
79}
80
82{
83 float retVal = 0;
84 for (uint32_t i = 0; i < NSECTORS; i++) {
85 for (uint32_t j = 0; j < GPUTPCGeometry::NROWS; j++) {
86 for (uint32_t k = 0; k < native.nClusters[i][j]; k++) {
87 if (native.clusters[i][j][k].getTime() > retVal) {
88 retVal = native.clusters[i][j][k].getTime();
89 }
90 }
91 }
92 }
93 return ceil(retVal);
94}
95
97{
98 float retVal = 0;
99 for (uint32_t i = 0; i < NSECTORS; i++) {
100 for (uint32_t k = 0; k < digits.nTPCDigits[i]; k++) {
101 if (digits.tpcDigits[i][k].getTimeStamp() > retVal) {
102 retVal = digits.tpcDigits[i][k].getTimeStamp();
103 }
104 }
105 }
106 return ceil(retVal);
107}
108
110{
111 float retVal = 0;
112 for (uint32_t i = 0; i < NSECTORS; i++) {
113 int32_t firstHBF = zspages.sector[i].count[0] ? o2::raw::RDHUtils::getHeartBeatOrbit(*(const o2::header::RAWDataHeader*)zspages.sector[i].zsPtr[0][0]) : 0;
114 for (uint32_t j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) {
115 for (uint32_t k = 0; k < zspages.sector[i].count[j]; k++) {
116 const char* page = (const char*)zspages.sector[i].zsPtr[j][k];
117 for (uint32_t l = 0; l < zspages.sector[i].nZSPtr[j][k]; l++) {
120 int32_t nTimeBinSpan = hdr->nTimeBinSpan;
122 TPCZSHDRV2* hdr2 = (TPCZSHDRV2*)hdr;
123 if (hdr2->flags & TPCZSHDRV2::ZSFlags::nTimeBinSpanBit8) {
124 nTimeBinSpan += 256;
125 }
126 }
127 uint32_t timeBin = (hdr->timeOffset + (o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstHBF) * o2::constants::lhc::LHCMaxBunches) / LHCBCPERTIMEBIN + nTimeBinSpan;
128 if (timeBin > retVal) {
129 retVal = timeBin;
130 }
131 }
132 }
133 }
134 }
135 return ceil(retVal);
136}
137
138// ------------------------------------------------- TPC ZS -------------------------------------------------
139
140#ifndef GPUCA_RUN2
141namespace o2::gpu
142{
143namespace // anonymous
144{
145
146// ------------------------------------------------- TPC ZS General -------------------------------------------------
147
148typedef std::array<int64_t, TPCZSHDR::TPC_ZS_PAGE_SIZE / sizeof(int64_t)> zsPage;
149
150struct zsEncoder {
151 int32_t curRegion = 0, outputRegion = 0;
152 uint32_t encodeBits = 0;
153 uint32_t zsVersion = 0;
154 uint32_t iSector = 0;
156 const o2::InteractionRecord* ir = nullptr;
157 const GPUParam* param = nullptr;
158 bool padding = false;
160 int32_t endpoint = 0, outputEndpoint = 0;
161 int64_t hbf = -1, nexthbf = 0;
162 zsPage* page = nullptr;
163 uint8_t* pagePtr = nullptr;
164 int32_t bcShiftInFirstHBF = 0;
165 int32_t firstTimebinInPage = -1;
167 bool needAnotherPage = false;
168 uint32_t packetCounter = 0;
169 uint32_t pageCounter = 0;
170 void ZSfillEmpty(void* ptr, int32_t shift, uint32_t feeId, int32_t orbit, int32_t linkid);
171 static void ZSstreamOut(uint16_t* bufIn, uint32_t& lenIn, uint8_t* bufOut, uint32_t& lenOut, uint32_t nBits);
172 int64_t getHbf(int64_t timestamp) { return (timestamp * LHCBCPERTIMEBIN + bcShiftInFirstHBF) / o2::constants::lhc::LHCMaxBunches; }
173};
174
175inline void zsEncoder::ZSfillEmpty(void* ptr, int32_t shift, uint32_t feeId, int32_t orbit, int32_t linkid)
176{
179 o2::raw::RDHUtils::setHeartBeatBC(*rdh, shift);
181 o2::raw::RDHUtils::setVersion(*rdh, o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>());
182 o2::raw::RDHUtils::setFEEID(*rdh, feeId);
184 o2::raw::RDHUtils::setLinkID(*rdh, linkid);
187}
188
189inline void zsEncoder::ZSstreamOut(uint16_t* bufIn, uint32_t& lenIn, uint8_t* bufOut, uint32_t& lenOut, uint32_t nBits)
190{
191 uint32_t byte = 0, bits = 0;
192 uint32_t mask = (1 << nBits) - 1;
193 for (uint32_t i = 0; i < lenIn; i++) {
194 byte |= (bufIn[i] & mask) << bits;
195 bits += nBits;
196 while (bits >= 8) {
197 bufOut[lenOut++] = (uint8_t)(byte & 0xFF);
198 byte = byte >> 8;
199 bits -= 8;
200 }
201 }
202 if (bits) {
203 bufOut[lenOut++] = byte;
204 }
205 lenIn = 0;
206}
207
208static inline auto ZSEncoderGetDigits(const GPUTrackingInOutDigits& in, int32_t i) { return in.tpcDigits[i]; }
209static inline auto ZSEncoderGetNDigits(const GPUTrackingInOutDigits& in, int32_t i) { return in.nTPCDigits[i]; }
210#ifndef GPUCA_STANDALONE
211using DigitArray = std::array<gsl::span<const o2::tpc::Digit>, o2::tpc::Sector::MAXSECTOR>;
212static inline auto ZSEncoderGetDigits(const DigitArray& in, int32_t i) { return in[i].data(); }
213static inline auto ZSEncoderGetNDigits(const DigitArray& in, int32_t i) { return in[i].size(); }
214#endif
215
216// ------------------------------------------------- TPC ZS Original Row-based ZS -------------------------------------------------
217
218struct zsEncoderRow : public zsEncoder {
219 std::array<uint16_t, TPCZSHDR::TPC_ZS_PAGE_SIZE> streamBuffer = {};
220 std::array<uint8_t, TPCZSHDR::TPC_ZS_PAGE_SIZE> streamBuffer8 = {};
221 TPCZSHDR* hdr = nullptr;
223 uint8_t* nSeq = nullptr;
224 int32_t seqLen = 0;
225 int32_t endpointStart = 0;
226 int32_t nRowsInTB = 0;
227 uint32_t streamSize = 0, streamSize8 = 0;
228 constexpr static int32_t RAWLNK = rdh_utils::UserLogicLinkID;
229
230 bool checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k);
231 bool writeSubPage();
233 void initPage() {}
234 uint32_t encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k);
235
236 bool sort(const o2::tpc::Digit a, const o2::tpc::Digit b);
237 void decodePage(std::vector<o2::tpc::Digit>& outputBuffer, const zsPage* page, uint32_t endpoint, uint32_t firstOrbit, uint32_t triggerBC = 0);
238};
239
240inline bool zsEncoderRow::sort(const o2::tpc::Digit a, const o2::tpc::Digit b)
241{
242 int32_t endpointa = GPUTPCGeometry::GetRegion(a.getRow());
243 int32_t endpointb = GPUTPCGeometry::GetRegion(b.getRow());
244 endpointa = 2 * endpointa + (a.getRow() >= GPUTPCGeometry::GetRegionStart(endpointa) + GPUTPCGeometry::GetRegionRows(endpointa) / 2);
245 endpointb = 2 * endpointb + (b.getRow() >= GPUTPCGeometry::GetRegionStart(endpointb) + GPUTPCGeometry::GetRegionRows(endpointb) / 2);
246 if (endpointa != endpointb) {
247 return endpointa <= endpointb;
248 }
249 if (a.getTimeStamp() != b.getTimeStamp()) {
250 return a.getTimeStamp() < b.getTimeStamp();
251 }
252 if (a.getRow() != b.getRow()) {
253 return a.getRow() < b.getRow();
254 }
255 return a.getPad() < b.getPad();
256}
257
258bool zsEncoderRow::checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k)
259{
260 seqLen = 1;
261 if (lastRow != tmpBuffer[k].getRow()) {
262 endpointStart = GPUTPCGeometry::GetRegionStart(curRegion);
263 endpoint = curRegion * 2;
264 if (tmpBuffer[k].getRow() >= endpointStart + GPUTPCGeometry::GetRegionRows(curRegion) / 2) {
265 endpoint++;
266 endpointStart += GPUTPCGeometry::GetRegionRows(curRegion) / 2;
267 }
268 }
269 for (uint32_t l = k + 1; l < tmpBuffer.size(); l++) {
270 if (tmpBuffer[l].getRow() == tmpBuffer[k].getRow() && tmpBuffer[l].getTimeStamp() == tmpBuffer[k].getTimeStamp() && tmpBuffer[l].getPad() == tmpBuffer[l - 1].getPad() + 1) {
271 seqLen++;
272 } else {
273 break;
274 }
275 }
276 if (lastEndpoint >= 0 && lastTime != -1 && (int32_t)hdr->nTimeBinSpan + tmpBuffer[k].getTimeStamp() - lastTime >= 256) {
277 lastEndpoint = -1;
278 }
279 if (endpoint == lastEndpoint) {
280 uint32_t sizeChk = (uint32_t)(pagePtr - reinterpret_cast<uint8_t*>(page)); // already written
281 sizeChk += 2 * (nRowsInTB + (tmpBuffer[k].getRow() != lastRow && tmpBuffer[k].getTimeStamp() == lastTime)); // TB HDR
282 sizeChk += streamSize8; // in stream buffer
283 sizeChk += (lastTime != tmpBuffer[k].getTimeStamp()) && ((sizeChk + (streamSize * encodeBits + 7) / 8) & 1); // time bin alignment
284 sizeChk += (tmpBuffer[k].getTimeStamp() != lastTime || tmpBuffer[k].getRow() != lastRow) ? 3 : 0; // new row overhead
285 sizeChk += (lastTime != -1 && tmpBuffer[k].getTimeStamp() > lastTime) ? ((tmpBuffer[k].getTimeStamp() - lastTime - 1) * 2) : 0; // empty time bins
286 sizeChk += 2; // sequence metadata
287 const uint32_t streamSizeChkBits = streamSize * encodeBits + ((lastTime != tmpBuffer[k].getTimeStamp() && (streamSize * encodeBits) % 8) ? (8 - (streamSize * encodeBits) % 8) : 0);
288 if (sizeChk + (encodeBits + streamSizeChkBits + 7) / 8 > TPCZSHDR::TPC_ZS_PAGE_SIZE) {
289 lastEndpoint = -1;
290 } else if (sizeChk + (seqLen * encodeBits + streamSizeChkBits + 7) / 8 > TPCZSHDR::TPC_ZS_PAGE_SIZE) {
291 seqLen = ((TPCZSHDR::TPC_ZS_PAGE_SIZE - sizeChk) * 8 - streamSizeChkBits) / encodeBits;
292 }
293 // sizeChk += (seqLen * encodeBits + streamSizeChkBits + 7) / 8;
294 // printf("Endpoint %d (%d), Pos %d, Chk %d, Len %d, rows %d, StreamSize %d %d, time %d (%d), row %d (%d), pad %d\n", endpoint, lastEndpoint, (int32_t) (pagePtr - reinterpret_cast<uint8_t*>(page)), sizeChk, seqLen, nRowsInTB, streamSize8, streamSize, (int32_t)tmpBuffer[k].getTimeStamp(), lastTime, (int32_t)tmpBuffer[k].getRow(), lastRow, tmpBuffer[k].getPad());
295 }
296 return endpoint != lastEndpoint || tmpBuffer[k].getTimeStamp() != lastTime;
297}
298
299bool zsEncoderRow::writeSubPage()
300{
301 if (pagePtr != reinterpret_cast<uint8_t*>(page)) {
302 pagePtr += 2 * nRowsInTB;
303 ZSstreamOut(streamBuffer.data(), streamSize, streamBuffer8.data(), streamSize8, encodeBits);
304 pagePtr = std::copy(streamBuffer8.data(), streamBuffer8.data() + streamSize8, pagePtr);
305 if (pagePtr - reinterpret_cast<uint8_t*>(page) > 8192) {
306 throw std::runtime_error("internal error during ZS encoding");
307 }
308 streamSize8 = 0;
309 for (int32_t l = 1; l < nRowsInTB; l++) {
310 curTBHdr->rowAddr1()[l - 1] += 2 * nRowsInTB;
311 }
312 }
313 return endpoint != lastEndpoint;
314}
315
316uint32_t zsEncoderRow::encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k)
317{
318 if (tmpBuffer[k].getTimeStamp() != lastTime) {
319 if (lastTime != -1) {
320 hdr->nTimeBinSpan += tmpBuffer[k].getTimeStamp() - lastTime - 1;
321 pagePtr += (tmpBuffer[k].getTimeStamp() - lastTime - 1) * 2;
322 }
323 hdr->nTimeBinSpan++;
324 if ((pagePtr - reinterpret_cast<uint8_t*>(page)) & 1) {
325 pagePtr++;
326 }
327 curTBHdr = reinterpret_cast<TPCZSTBHDR*>(pagePtr);
328 curTBHdr->rowMask |= (endpoint & 1) << 15;
329 nRowsInTB = 0;
331 }
332 if (tmpBuffer[k].getRow() != lastRow) {
333 curTBHdr->rowMask |= 1 << (tmpBuffer[k].getRow() - endpointStart);
334 ZSstreamOut(streamBuffer.data(), streamSize, streamBuffer8.data(), streamSize8, encodeBits);
335 if (nRowsInTB) {
336 curTBHdr->rowAddr1()[nRowsInTB - 1] = (pagePtr - reinterpret_cast<uint8_t*>(page)) + streamSize8;
337 }
338 nRowsInTB++;
339 nSeq = streamBuffer8.data() + streamSize8++;
340 *nSeq = 0;
341 }
342 (*nSeq)++;
343 streamBuffer8[streamSize8++] = tmpBuffer[k].getPad();
345 for (int32_t l = 0; l < seqLen; l++) {
346 streamBuffer[streamSize++] = (uint16_t)(tmpBuffer[k + l].getChargeFloat() * encodeBitsFactor + 0.5f);
347 }
348 return seqLen;
349}
350
351void zsEncoderRow::decodePage(std::vector<o2::tpc::Digit>& outputBuffer, const zsPage* decPage, uint32_t decEndpoint, uint32_t firstOrbit, uint32_t triggerBC)
352{
353 const uint8_t* decPagePtr = reinterpret_cast<const uint8_t*>(decPage);
354 const o2::header::RAWDataHeader* rdh = (const o2::header::RAWDataHeader*)decPagePtr;
355 if (o2::raw::RDHUtils::getMemorySize(*rdh) == sizeof(o2::header::RAWDataHeader)) {
356 return;
357 }
358 decPagePtr += sizeof(o2::header::RAWDataHeader);
359 const TPCZSHDR* decHDR = reinterpret_cast<const TPCZSHDR*>(decPagePtr);
360 decPagePtr += sizeof(*decHDR);
361 if (decHDR->version != 1 && decHDR->version != 2) {
362 throw std::runtime_error("invalid ZS version "s + std::to_string(decHDR->version) + " (1 or 2 expected)"s);
363 }
364 const float decodeBitsFactor = 1.f / (1 << (encodeBits - 10));
365 uint32_t mask = (1 << encodeBits) - 1;
366 int32_t cruid = decHDR->cruID;
367 uint32_t sector = cruid / 10;
368 if (sector != iSector) {
369 throw std::runtime_error("invalid TPC sector");
370 }
371 int32_t region = cruid % 10;
372 if ((uint32_t)region != decEndpoint / 2) {
373 throw std::runtime_error("CRU ID / endpoint mismatch");
374 }
375 int32_t nRowsRegion = GPUTPCGeometry::GetRegionRows(region);
376
377 int32_t timeBin = (decHDR->timeOffset + (uint64_t)(o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstOrbit) * o2::constants::lhc::LHCMaxBunches) / LHCBCPERTIMEBIN;
378 for (int32_t l = 0; l < decHDR->nTimeBinSpan; l++) {
379 if ((decPagePtr - reinterpret_cast<const uint8_t*>(decPage)) & 1) {
380 decPagePtr++;
381 }
382 const TPCZSTBHDR* tbHdr = reinterpret_cast<const TPCZSTBHDR*>(decPagePtr);
383 bool upperRows = tbHdr->rowMask & 0x8000;
384 if (tbHdr->rowMask != 0 && ((upperRows) ^ ((decEndpoint & 1) != 0))) {
385 throw std::runtime_error("invalid endpoint");
386 }
387 const int32_t rowOffset = GPUTPCGeometry::GetRegionStart(region) + (upperRows ? (nRowsRegion / 2) : 0);
388 const int32_t nRows = upperRows ? (nRowsRegion - nRowsRegion / 2) : (nRowsRegion / 2);
389 const int32_t nRowsUsed = __builtin_popcount((uint32_t)(tbHdr->rowMask & 0x7FFF));
390 decPagePtr += nRowsUsed ? (2 * nRowsUsed) : 2;
391 int32_t rowPos = 0;
392 for (int32_t m = 0; m < nRows; m++) {
393 if ((tbHdr->rowMask & (1 << m)) == 0) {
394 continue;
395 }
396 const uint8_t* rowData = rowPos == 0 ? decPagePtr : (reinterpret_cast<const uint8_t*>(decPage) + tbHdr->rowAddr1()[rowPos - 1]);
397 const int32_t nSeqRead = *rowData;
398 const uint8_t* adcData = rowData + 2 * nSeqRead + 1;
399 int32_t nADC = (rowData[2 * nSeqRead] * encodeBits + 7) / 8;
400 decPagePtr += 1 + 2 * nSeqRead + nADC;
401 uint32_t byte = 0, bits = 0, posXbits = 0;
402 std::array<uint16_t, TPCZSHDR::TPC_ZS_PAGE_SIZE> decBuffer;
403 for (int32_t n = 0; n < nADC; n++) {
404 byte |= *(adcData++) << bits;
405 bits += 8;
406 while (bits >= encodeBits) {
407 decBuffer[posXbits++] = byte & mask;
408 byte = byte >> encodeBits;
409 bits -= encodeBits;
410 }
411 }
412 posXbits = 0;
413 for (int32_t n = 0; n < nSeqRead; n++) {
414 const int32_t decSeqLen = rowData[(n + 1) * 2] - (n ? rowData[n * 2] : 0);
415 for (int32_t o = 0; o < decSeqLen; o++) {
416 outputBuffer.emplace_back(o2::tpc::Digit{cruid, decBuffer[posXbits++] * decodeBitsFactor, (tpccf::Row)(rowOffset + m), (tpccf::Pad)(rowData[n * 2 + 1] + o), timeBin + l});
417 }
418 }
419 rowPos++;
420 }
421 }
422}
423
424// ------------------------------------------------- TPC ZS Link Based ZS -------------------------------------------------
425
426#ifndef GPUCA_STANDALONE
427struct zsEncoderLinkBased : public zsEncoder {
428 TPCZSHDRV2* hdr = nullptr;
430 int32_t inverseChannelMapping[5][32];
431 int32_t nSamples = 0;
432 int32_t link = 0;
433 bool finishPage = false;
434 std::vector<uint16_t> adcValues = {};
435 std::bitset<80> bitmask = {};
436
437 void createBitmask(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k);
438 void init();
439 bool sort(const o2::tpc::Digit a, const o2::tpc::Digit b);
440};
441
442void zsEncoderLinkBased::init()
443{
445 for (int32_t i = 0; i < 5; i++) {
446 for (int32_t j = 0; j < 32; j++) {
448 }
449 }
450 for (int32_t iCRU = 0; iCRU < 2; iCRU++) {
451 for (int32_t iChannel = 0; iChannel < 80; iChannel++) {
452 int32_t sampaOnFEC = 0, channelOnSAMPA = 0;
453 Mapper::getSampaAndChannelOnFEC(iCRU, iChannel, sampaOnFEC, channelOnSAMPA);
454 if (inverseChannelMapping[sampaOnFEC][channelOnSAMPA] != -1 && inverseChannelMapping[sampaOnFEC][channelOnSAMPA] != iChannel) {
455 GPUError("ERROR: Channel conflict: %d %d: %d vs %d", sampaOnFEC, channelOnSAMPA, inverseChannelMapping[sampaOnFEC][channelOnSAMPA], iChannel);
456 throw std::runtime_error("ZS error");
457 }
458 inverseChannelMapping[sampaOnFEC][channelOnSAMPA] = iChannel;
459 }
460 }
461 for (int32_t i = 0; i < 5; i++) {
462 for (int32_t j = 0; j < 32; j++) {
463 if (inverseChannelMapping[i][j] == -1) {
464 GPUError("ERROR: Map missing for sampa %d channel %d", i, j);
465 throw std::runtime_error("ZS error");
466 }
467 }
468 }
469}
470
471void zsEncoderLinkBased::createBitmask(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k)
472{
473 const auto& mapper = Mapper::instance();
474 nSamples = 0;
475 adcValues.clear();
476 bitmask.reset();
477 uint32_t l;
478 for (l = k; l < tmpBuffer.size(); l++) {
479 const auto& a = tmpBuffer[l];
480 int32_t cruinsector = GPUTPCGeometry::GetRegion(a.getRow());
481 o2::tpc::GlobalPadNumber pad = mapper.globalPadNumber(o2::tpc::PadPos(a.getRow(), a.getPad()));
482 o2::tpc::FECInfo fec = mapper.fecInfo(pad);
483 o2::tpc::CRU cru = cruinsector;
484 int32_t fecInPartition = fec.getIndex() - mapper.getPartitionInfo(cru.partition()).getSectorFECOffset();
485 int32_t tmpEndpoint = 2 * cruinsector + (fecInPartition >= (mapper.getPartitionInfo(cru.partition()).getNumberOfFECs() + 1) / 2);
486 if (l == k) {
487 link = fecInPartition;
488 endpoint = tmpEndpoint;
489 } else if (endpoint != tmpEndpoint || link != fecInPartition || tmpBuffer[l].getTimeStamp() != tmpBuffer[k].getTimeStamp()) {
490 break;
491 }
492 int32_t channel = inverseChannelMapping[fec.getSampaChip()][fec.getSampaChannel()];
493 bitmask[channel] = 1;
494 adcValues.emplace_back((uint16_t)(a.getChargeFloat() * encodeBitsFactor + 0.5f));
495 }
496 nSamples = l - k;
497}
498
499bool zsEncoderLinkBased::sort(const o2::tpc::Digit a, const o2::tpc::Digit b)
500{
501 // Fixme: this is blasphemy... one shoult precompute all values and sort an index array
502 int32_t cruinsectora = GPUTPCGeometry::GetRegion(a.getRow());
503 int32_t cruinsectorb = GPUTPCGeometry::GetRegion(b.getRow());
504 if (cruinsectora != cruinsectorb) {
505 return cruinsectora < cruinsectorb;
506 }
507 const auto& mapper = Mapper::instance();
508 o2::tpc::GlobalPadNumber pada = mapper.globalPadNumber(o2::tpc::PadPos(a.getRow(), a.getPad()));
509 o2::tpc::GlobalPadNumber padb = mapper.globalPadNumber(o2::tpc::PadPos(b.getRow(), b.getPad()));
510 o2::tpc::FECInfo feca = mapper.fecInfo(pada);
511 o2::tpc::FECInfo fecb = mapper.fecInfo(padb);
512 o2::tpc::CRU cru = cruinsectora;
513 int32_t fecInPartitiona = feca.getIndex() - mapper.getPartitionInfo(cru.partition()).getSectorFECOffset();
514 int32_t fecInPartitionb = fecb.getIndex() - mapper.getPartitionInfo(cru.partition()).getSectorFECOffset();
515
516 int32_t endpointa = 2 * cruinsectora + (fecInPartitiona >= (mapper.getPartitionInfo(cru.partition()).getNumberOfFECs() + 1) / 2);
517 int32_t endpointb = 2 * cruinsectorb + (fecInPartitionb >= (mapper.getPartitionInfo(cru.partition()).getNumberOfFECs() + 1) / 2);
518 if (endpointa != endpointb) {
519 return endpointa < endpointb;
520 }
521 if (a.getTimeStamp() != b.getTimeStamp()) {
522 return a.getTimeStamp() < b.getTimeStamp();
523 }
524 if (fecInPartitiona != fecInPartitionb) {
525 return fecInPartitiona < fecInPartitionb;
526 }
528}
529
530// ------------------------------------------------- TPC Improved Link Based ZS -------------------------------------------------
531
532struct zsEncoderImprovedLinkBased : public zsEncoderLinkBased {
533 bool checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k);
534 uint32_t encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k);
535 void decodePage(std::vector<o2::tpc::Digit>& outputBuffer, const zsPage* page, uint32_t endpoint, uint32_t firstOrbit, uint32_t triggerBC = 0);
536 bool writeSubPage();
537 void initPage();
538
539 constexpr static int32_t RAWLNK = rdh_utils::ILBZSLinkID;
540};
541
542bool zsEncoderImprovedLinkBased::checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k)
543{
544 createBitmask(tmpBuffer, k);
546 if (firstTimebinInPage != -1 && tmpBuffer[k].getTimeStamp() - firstTimebinInPage >= 1 << (sizeof(hdr->nTimeBinSpan) * 8)) {
547 finishPage = true;
548 }
549 if (!finishPage) {
550 uint32_t sizeChk = (uint32_t)(pagePtr - reinterpret_cast<uint8_t*>(page));
553 sizeChk += (nSamples * TPCZSHDRV2::TPC_ZS_NBITS_V34 + 127) / 128 * 16;
554 } else {
555 sizeChk += (nSamples + 2 * TPCZSHDRV2::SAMPLESPER64BIT - 1) / (2 * TPCZSHDRV2::SAMPLESPER64BIT) * 16;
556 }
557 if (sizeChk > TPCZSHDR::TPC_ZS_PAGE_SIZE) {
558 finishPage = true;
559 }
560 }
561 return finishPage;
562}
563
564uint32_t zsEncoderImprovedLinkBased::encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k)
565{
567 pagePtr += sizeof(*tbHdr);
568 tbHdr->bunchCrossing = (tmpBuffer[k].getTimeStamp() - firstTimebinInPage) * LHCBCPERTIMEBIN;
570 tbHdr->bitMaskHigh = (bitmask >> 64).to_ulong();
571 tbHdr->bitMaskLow = (bitmask & std::bitset<80>(0xFFFFFFFFFFFFFFFFlu)).to_ulong();
572 tbHdr->syncOffsetBC = 0;
573 tbHdr->fecInPartition = link;
574 hdr->nTimeBinSpan = tmpBuffer[k].getTimeStamp() - firstTimebinInPage;
575 hdr->nTimebinHeaders++;
577 tbHdr->numWordsPayload = (nSamples * TPCZSHDRV2::TPC_ZS_NBITS_V34 + 127) / 128; // tightly packed ADC samples
578 uint32_t tmp = 0;
579 uint32_t tmpIn = nSamples;
580 ZSstreamOut(adcValues.data(), tmpIn, pagePtr, tmp, encodeBits);
581 } else {
583 uint64_t* payloadPtr = (uint64_t*)pagePtr;
584 for (uint32_t i = 0; i < 2 * tbHdr->numWordsPayload; i++) {
585 payloadPtr[i] = 0;
586 }
587 for (uint32_t i = 0; i < nSamples; i++) {
589 }
590 }
591 pagePtr += tbHdr->numWordsPayload * 16;
592 return nSamples;
593}
594
595bool zsEncoderImprovedLinkBased::writeSubPage()
596{
597 return finishPage;
598}
599
600void zsEncoderImprovedLinkBased::initPage()
601{
603 hdr->nTimebinHeaders = 0;
604 hdr->firstZSDataOffset = 0;
605}
606
607void zsEncoderImprovedLinkBased::decodePage(std::vector<o2::tpc::Digit>& outputBuffer, const zsPage* decPage, uint32_t decEndpoint, uint32_t firstOrbit, uint32_t triggerBC)
608{
609 const auto& mapper = Mapper::instance();
610 const uint8_t* decPagePtr = reinterpret_cast<const uint8_t*>(decPage);
611 const o2::header::RAWDataHeader* rdh = (const o2::header::RAWDataHeader*)decPagePtr;
612 if (o2::raw::RDHUtils::getMemorySize(*rdh) == sizeof(o2::header::RAWDataHeader)) {
613 return;
614 }
615 decPagePtr += sizeof(o2::header::RAWDataHeader);
616 const TPCZSHDRV2* decHDR = reinterpret_cast<const TPCZSHDRV2*>(decPagePtr);
617 decPagePtr += sizeof(*decHDR);
618 if (decHDR->version != ZSVersion::ZSVersionLinkBasedWithMeta) {
619 throw std::runtime_error("invalid ZS version "s + std::to_string(decHDR->version) + " ("s + std::to_string(ZSVersion::ZSVersionLinkBasedWithMeta) + " expected)"s);
620 }
622 throw std::runtime_error("Magic word missing");
623 }
624 const float decodeBitsFactor = 1.f / (1 << (encodeBits - 10));
625 uint32_t mask = (1 << encodeBits) - 1;
626 int32_t cruid = decHDR->cruID;
627 uint32_t sector = cruid / 10;
628 if (sector != iSector) {
629 throw std::runtime_error("invalid TPC sector");
630 }
631 int32_t region = cruid % 10;
632 decPagePtr += decHDR->firstZSDataOffset * 16;
633 for (uint32_t i = 0; i < decHDR->nTimebinHeaders; i++) {
635#if 0 // Decoding using the function for the original linkZS
636 o2::tpc::CRU cru = cruid % 10;
637 const int32_t feeLink = tbHdr->fecInPartition - (decEndpoint & 1) * ((mapper.getPartitionInfo(cru.partition()).getNumberOfFECs() + 1) / 2);
638 auto fillADC = [&outputBuffer](int32_t cru, int32_t rowInSector, int32_t padInRow, int32_t timeBin, float adcValue) {
639 outputBuffer.emplace_back(o2::tpc::Digit{cruid, adcValue, rowInSector, padInRow, timeBin});
640 return true;
641 };
642 size_t size = sizeof(*tbHdr) + tbHdr->numWordsPayload * 16;
643 raw_processing_helpersa::processZSdata((const char*)decPagePtr, size, rdh_utils::getFEEID(cruid, decEndpoint & 1, feeLink), o2::raw::RDHUtils::getHeartBeatOrbit(*rdh), firstOrbit, decHDR->timeOffset, fillADC);
644#else // Decoding directly
645 if (!tbHdr->isLinkZS()) {
646 throw std::runtime_error("ZS TB Hdr does not have linkZS magic word");
647 }
648 int32_t timeBin = (int32_t(decHDR->timeOffset) + int32_t(tbHdr->bunchCrossing) + (int32_t)(o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstOrbit) * o2::constants::lhc::LHCMaxBunches - triggerBC) / LHCBCPERTIMEBIN;
649 if (timeBin < 0) {
650 LOGP(debug, "zsEncoderImprovedLinkBased::decodePage skipping digits hdr->tOff {} + hdr->bc {} + (orbit {} - firstOrbit {}) * maxBunch {} - triggerBC {} = {} < 0", decHDR->timeOffset, tbHdr->bunchCrossing, o2::raw::RDHUtils::getHeartBeatOrbit(*rdh), firstOrbit, o2::constants::lhc::LHCMaxBunches, triggerBC, timeBin);
651 continue;
652 }
653 const uint8_t* adcData = (const uint8_t*)(decPagePtr + sizeof(*tbHdr));
654 const auto& bitmask = tbHdr->getChannelBits();
655 int32_t nADC = bitmask.count();
656 std::vector<uint16_t> decBuffer(nADC);
658 uint32_t byte = 0, bits = 0, posXbits = 0;
659 while (posXbits < nADC) {
660 byte |= *(adcData++) << bits;
661 bits += 8;
662 while (bits >= encodeBits) {
663 decBuffer[posXbits++] = byte & mask;
664 byte = byte >> encodeBits;
665 bits -= encodeBits;
666 }
667 }
668 } else {
669 const uint64_t* adcData64 = (const uint64_t*)adcData;
670 for (int32_t j = 0; j < nADC; j++) {
672 }
673 }
674 for (int32_t j = 0, k = 0; j < bitmask.size(); j++) {
675 if (bitmask[j]) {
676 int32_t sampaOnFEC = 0, channelOnSAMPA = 0;
677 mapper.getSampaAndChannelOnFEC(cruid, j, sampaOnFEC, channelOnSAMPA);
678 const auto padSecPos = mapper.padSecPos(cruid, tbHdr->fecInPartition, sampaOnFEC, channelOnSAMPA);
679 const auto& padPos = padSecPos.getPadPos();
680 outputBuffer.emplace_back(o2::tpc::Digit{cruid, decBuffer[k++] * decodeBitsFactor, (tpccf::Row)padPos.getRow(), (tpccf::Pad)padPos.getPad(), timeBin});
681 }
682 }
683#endif
684 decPagePtr += sizeof(*tbHdr) + tbHdr->numWordsPayload * 16;
685 }
686}
687
688// ------------------------------------------------- TPC ZS Dense Link Based ZS -------------------------------------------------
689
690struct zsEncoderDenseLinkBased : public zsEncoderLinkBased {
691 bool checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k);
692 uint32_t encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k);
693 void decodePage(std::vector<o2::tpc::Digit>& outputBuffer, const zsPage* page, uint32_t endpoint, uint32_t firstOrbit, uint32_t triggerBC = 0);
694 bool writeSubPage();
695 void initPage();
696 void amendPageErrorMessage(std::ostringstream& oss, const o2::header::RAWDataHeader* rdh, const TPCZSHDRV2* decHDR, const uint8_t* payloadEnd, const uint8_t* decPagePtr, uint32_t nOutput);
697
698 uint16_t curTimeBin = 0;
699 std::vector<uint8_t> sequenceBuffer;
700 std::vector<uint16_t> sequenceBufferADC;
701
702 constexpr static int32_t RAWLNK = rdh_utils::DLBZSLinkID;
703 constexpr static int32_t v2nbits = 10;
704};
705
706bool zsEncoderDenseLinkBased::checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k)
707{
708 createBitmask(tmpBuffer, k);
710 uint16_t newTimeBin = tmpBuffer[k].getTimeStamp() - firstTimebinInPage;
711 bool retVall = finishPage || newTimeBin != curTimeBin;
712 return retVall;
713}
714
715uint32_t zsEncoderDenseLinkBased::encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, uint32_t k)
716{
717 if (sequenceBuffer.size() == 0) {
719 if (zsVersion == ZSVersion::ZSVersionDenseLinkBasedV2) {
720 bc &= 0xFFC;
721 }
722 sequenceBuffer.emplace_back(bc << 4);
723 sequenceBuffer.emplace_back(bc >> 4);
724 curTimeBin = tmpBuffer[k].getTimeStamp() - firstTimebinInPage;
725 hdr->nTimeBinSpan = curTimeBin & 0xFF;
726 if (curTimeBin & 0x100) {
727 hdr->flags |= TPCZSHDRV2::ZSFlags::nTimeBinSpanBit8;
728 }
729 hdr->nTimebinHeaders++;
730 }
731 sequenceBuffer[0]++;
732
733 sequenceBuffer.emplace_back(link);
734 uint8_t* plink = &sequenceBuffer.back();
735
736 std::bitset<10> bitmaskL2;
737 for (int32_t i = 9; i >= 0; i--) {
738 bitmaskL2.set(i, ((bitmask >> (i * 8)) & std::bitset<80>(0xFF)).any());
739 }
740 if (bitmaskL2.all()) {
741 *plink |= 0b00100000;
742 } else {
743 *plink |= (bitmaskL2.to_ulong() >> 2) & 0b11000000;
744 sequenceBuffer.emplace_back(bitmaskL2.to_ulong() & 0xFF);
745 }
746
747 for (int32_t i = 0; i < 10; i++) {
748 if (bitmaskL2.test(i)) {
749 sequenceBuffer.emplace_back(((bitmask >> (i * 8)) & std::bitset<80>(0xFF)).to_ulong());
750 }
751 }
752
753 static_assert(TPCZSHDRV2::TPC_ZS_NBITS_V34 == 12);
754 if (nSamples) {
755 sequenceBufferADC.insert(sequenceBufferADC.end(), adcValues.begin(), adcValues.end());
756 }
757
758 return nSamples;
759}
760
761bool zsEncoderDenseLinkBased::writeSubPage()
762{
763 uint32_t offset = sequenceBuffer.size();
764 if (sequenceBufferADC.size()) {
765 bool need12bit = zsVersion != ZSVersion::ZSVersionDenseLinkBasedV2;
766 uint32_t needNow = 0;
767 if (zsVersion == ZSVersion::ZSVersionDenseLinkBasedV2) {
768 for (uint32_t i = 0; i < sequenceBufferADC.size(); i++) {
769 if (sequenceBufferADC[i] >= (1 << v2nbits)) {
770 need12bit = true;
771 break;
772 }
773 }
774 }
775 uint32_t encodeBitsBlock = encodeBits;
776 if (!need12bit) {
777 encodeBitsBlock = v2nbits;
778 sequenceBuffer[0] |= 0x10;
779 }
780 sequenceBuffer.resize(offset + (sequenceBufferADC.size() * encodeBitsBlock + 7) / 8);
781 uint32_t tmp = 0;
782 uint32_t tmpIn = sequenceBufferADC.size();
783 ZSstreamOut(sequenceBufferADC.data(), tmpIn, sequenceBuffer.data() + offset, tmp, encodeBitsBlock);
784 sequenceBufferADC.clear();
785 }
786
787 if (sequenceBuffer.size()) {
788 uint32_t sizeLeft = TPCZSHDR::TPC_ZS_PAGE_SIZE - (pagePtr - (uint8_t*)page) - sizeof(TPCZSHDRV2) - (hdr->flags & TPCZSHDRV2::ZSFlags::TriggerWordPresent ? TPCZSHDRV2::TRIGGER_WORD_SIZE : 0);
789 uint32_t size = sequenceBuffer.size();
790 uint32_t fill = std::min(sizeLeft, size);
791 memcpy(pagePtr, sequenceBuffer.data(), fill);
792 pagePtr += fill;
793 if (size != fill) {
795 sequenceBuffer.erase(sequenceBuffer.begin(), sequenceBuffer.begin() + fill);
796 } else {
797 sequenceBuffer.clear();
798 }
799 finishPage = finishPage || size >= sizeLeft || needAnotherPage;
800 }
801
802 return finishPage;
803}
804
805void zsEncoderDenseLinkBased::initPage()
806{
808 hdr->nTimebinHeaders = 0;
809 memcpy(pagePtr, sequenceBuffer.data(), sequenceBuffer.size());
810 hdr->firstZSDataOffset = sequenceBuffer.size() + sizeof(o2::header::RAWDataHeader);
811 pagePtr += sequenceBuffer.size();
812 sequenceBuffer.clear();
813 hdr->flags = 0;
814}
815
816void zsEncoderDenseLinkBased::decodePage(std::vector<o2::tpc::Digit>& outputBuffer, const zsPage* decPage, uint32_t decEndpoint, uint32_t firstOrbit, uint32_t triggerBC)
817{
818 const auto& mapper = Mapper::instance();
819 const uint8_t* decPagePtr = reinterpret_cast<const uint8_t*>(decPage);
820 const o2::header::RAWDataHeader* rdh = (const o2::header::RAWDataHeader*)decPagePtr;
821 if (o2::raw::RDHUtils::getMemorySize(*rdh) == sizeof(o2::header::RAWDataHeader)) {
822 return;
823 }
824 const TPCZSHDRV2* decHDR = reinterpret_cast<const TPCZSHDRV2*>(decPagePtr + o2::raw::RDHUtils::getMemorySize(*rdh) - sizeof(TPCZSHDRV2));
825 decPagePtr += sizeof(o2::header::RAWDataHeader);
826 if (decHDR->version < ZSVersion::ZSVersionDenseLinkBased || decHDR->version > ZSVersion::ZSVersionDenseLinkBasedV2) {
827 throw std::runtime_error("invalid ZS version "s + std::to_string(decHDR->version) + " ("s + std::to_string(ZSVersion::ZSVersionDenseLinkBased) + " - "s + std::to_string(ZSVersion::ZSVersionDenseLinkBasedV2) + " expected)"s);
828 }
830 throw std::runtime_error("Magic word missing");
831 }
832 const uint8_t* payloadEnd = ((const uint8_t*)decPage) + o2::raw::RDHUtils::getMemorySize(*rdh) - sizeof(TPCZSHDRV2) - ((decHDR->flags & TPCZSHDRV2::ZSFlags::TriggerWordPresent) ? TPCZSHDRV2::TRIGGER_WORD_SIZE : 0);
833 const float decodeBitsFactor = 1.f / (1 << (encodeBits - 10));
834 int32_t cruid = decHDR->cruID;
835 uint32_t sector = cruid / 10;
836 if (sector != iSector) {
837 throw std::runtime_error("invalid TPC sector");
838 }
839 int32_t region = cruid % 10;
840 decPagePtr += decHDR->firstZSDataOffset - sizeof(o2::header::RAWDataHeader);
841 std::vector<uint8_t> tmpBuffer;
842 bool extendFailure = false;
843 uint32_t nOutput = 0;
844 uint32_t minTimeBin = -1, maxTimeBin = 0;
845 for (uint32_t i = 0; i < decHDR->nTimebinHeaders; i++) {
846 int32_t sizeLeftInPage = payloadEnd - decPagePtr;
847 if (sizeLeftInPage <= 0) {
848 throw std::runtime_error("Decoding ran beyond end of page before processing extended timebin");
849 }
851 if (o2::raw::RDHUtils::getMemorySize(*rdh) != TPCZSHDR::TPC_ZS_PAGE_SIZE) {
852 throw std::runtime_error("pageExtends signaled, but current page is not full");
853 }
854
855 const uint8_t* pageNext = ((const uint8_t*)decPage) + TPCZSHDR::TPC_ZS_PAGE_SIZE;
856 const o2::header::RAWDataHeader* rdhNext = (const o2::header::RAWDataHeader*)pageNext;
857
858 if ((uint16_t)(o2::raw::RDHUtils::getPageCounter(*rdh) + 1) != o2::raw::RDHUtils::getPageCounter(*rdhNext)) {
859 GPUError("Incomplete HBF: Payload extended to next page, but next page missing in stream (packet counters %d %d)", (int32_t)o2::raw::RDHUtils::getPageCounter(*rdh), (int32_t)o2::raw::RDHUtils::getPageCounter(*rdhNext));
860 extendFailure = true;
861 decPagePtr = payloadEnd; // Next 8kb page is missing in stream, cannot decode remaining data, skip it
862 break;
863 }
864
865 const TPCZSHDRV2* hdrNext = reinterpret_cast<const TPCZSHDRV2*>(pageNext + o2::raw::RDHUtils::getMemorySize(*rdhNext) - sizeof(TPCZSHDRV2));
866 tmpBuffer.resize(sizeLeftInPage + hdrNext->firstZSDataOffset - sizeof(o2::header::RAWDataHeader));
867 memcpy(tmpBuffer.data(), decPagePtr, sizeLeftInPage);
868 memcpy(tmpBuffer.data() + sizeLeftInPage, pageNext + sizeof(o2::header::RAWDataHeader), hdrNext->firstZSDataOffset - sizeof(o2::header::RAWDataHeader));
869 decPagePtr = tmpBuffer.data();
870 payloadEnd = decPagePtr + tmpBuffer.size();
871 }
872 uint8_t linkCount = *((const uint8_t*)decPagePtr) & 0x0F;
873 uint16_t linkBC = (*((const uint16_t*)decPagePtr) & 0xFFF0) >> 4;
874 bool v2Flag = decHDR->version == ZSVersion::ZSVersionDenseLinkBasedV2 && *((const uint8_t*)decPagePtr) & 0x10;
875 if (decHDR->version == ZSVersion::ZSVersionDenseLinkBasedV2) {
876 linkBC &= 0xFFC;
877 }
878 decPagePtr += sizeof(uint16_t);
879 std::vector<int32_t> links;
880 std::vector<std::bitset<80>> bitmasks;
881 uint32_t nTotalSamples = 0;
882 for (uint32_t l = 0; l < linkCount; l++) {
883 uint8_t decLinkX = *((const uint8_t*)decPagePtr);
884 decPagePtr += sizeof(uint8_t);
885 uint8_t decLink = decLinkX & 0b00011111;
886 std::bitset<10> bitmaskL2;
887 if (decLinkX & 0b00100000) {
888 bitmaskL2.set();
889 } else {
890 bitmaskL2 = std::bitset<10>(((((uint16_t)decLinkX) & 0b11000000) << 2) | (uint16_t)*((const uint8_t*)decPagePtr));
891 decPagePtr += sizeof(uint8_t);
892 }
893
894 std::bitset<80> bitmask(0);
895 for (int32_t i = 0; i < 10; i++) {
896 if (bitmaskL2.test(i)) {
897 bitmask |= std::bitset<80>(*((const uint8_t*)decPagePtr)) << i * 8;
898 decPagePtr += sizeof(uint8_t);
899 }
900 }
901 links.emplace_back(decLink);
902 bitmasks.emplace_back(bitmask);
903 nTotalSamples += bitmask.count();
904 }
905
906 const uint8_t* adcData = (const uint8_t*)decPagePtr;
907 int32_t encodeBitsBlock = v2Flag ? v2nbits : encodeBits;
908 decPagePtr += (nTotalSamples * encodeBitsBlock + 7) / 8;
909
910 // time bin might be smaller 0 due to triggerBC
911 int32_t timeBin = (int32_t(linkBC) + (int32_t)(o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstOrbit) * o2::constants::lhc::LHCMaxBunches - int32_t(triggerBC)) / LHCBCPERTIMEBIN;
912 if (timeBin < 0 || nTotalSamples == 0) {
913 if (timeBin < 0 && nTotalSamples > 0) {
914 LOGP(debug, "zsEncoderDenseLinkBased::decodePage skipping digits (linkBC {} + orbit {} - firstOrbit {}) * maxBunch {} - triggerBC {} = {} < 0, nTotalSamples {}", linkBC, o2::raw::RDHUtils::getHeartBeatOrbit(*rdh), firstOrbit, o2::constants::lhc::LHCMaxBunches, triggerBC, timeBin, nTotalSamples);
915 }
916 continue;
917 }
918 if (timeBin > maxTimeBin) {
919 maxTimeBin = timeBin;
920 }
921 if (timeBin < minTimeBin) {
922 minTimeBin = timeBin;
923 }
924
925 std::vector<uint16_t> samples(nTotalSamples);
926 uint32_t mask = (1 << encodeBitsBlock) - 1;
927 uint32_t byte = 0, bits = 0, posXbits = 0;
928 while (posXbits < nTotalSamples) {
929 byte |= *(adcData++) << bits;
930 bits += 8;
931 while (bits >= encodeBitsBlock && posXbits < nTotalSamples) {
932 samples[posXbits++] = byte & mask;
933 byte = byte >> encodeBitsBlock;
934 bits -= encodeBitsBlock;
935 }
936 }
937 uint32_t samplePos = 0;
938
939 for (uint32_t l = 0; l < linkCount; l++) {
940 uint8_t decLink = links[l];
941 const auto& bitmask = bitmasks[l];
942 int32_t nADC = bitmask.count();
943
944 for (int32_t j = 0; j < bitmask.size(); j++) {
945 if (bitmask[j]) {
946 int32_t sampaOnFEC = 0, channelOnSAMPA = 0;
947 mapper.getSampaAndChannelOnFEC(cruid, j, sampaOnFEC, channelOnSAMPA);
948 const auto padSecPos = mapper.padSecPos(cruid, decLink, sampaOnFEC, channelOnSAMPA);
949 const auto& padPos = padSecPos.getPadPos();
950 outputBuffer.emplace_back(o2::tpc::Digit{cruid, samples[samplePos++] * decodeBitsFactor, (tpccf::Row)padPos.getRow(), (tpccf::Pad)padPos.getPad(), timeBin});
951 nOutput++;
952 }
953 }
954 }
955 }
956
957 int32_t hdrMinTimeBin = (int32_t(decHDR->timeOffset) + int32_t(o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstOrbit) * o2::constants::lhc::LHCMaxBunches - triggerBC);
958 if (triggerBC > 0 && hdrMinTimeBin < 0) {
959 hdrMinTimeBin = 0;
960 }
961 hdrMinTimeBin /= LHCBCPERTIMEBIN;
962 int32_t hdrMaxTimeBin = hdrMinTimeBin + decHDR->nTimeBinSpan + ((decHDR->flags & TPCZSHDRV2::ZSFlags::nTimeBinSpanBit8) ? 256 : 0);
963
964 if (!extendFailure && nOutput != decHDR->nADCsamples) {
965 std::ostringstream oss;
966 oss << "Number of decoded digits " << nOutput << " does not match value from MetaInfo " << decHDR->nADCsamples;
967 amendPageErrorMessage(oss, rdh, decHDR, nullptr, nullptr, nOutput);
968 throw std::runtime_error(oss.str());
969 }
970
971 if (decHDR->nADCsamples && (minTimeBin < hdrMinTimeBin || maxTimeBin > hdrMaxTimeBin)) {
972 std::ostringstream oss;
973 oss << "Incorrect time bin range in MetaInfo, header reports " << hdrMinTimeBin << " - " << hdrMaxTimeBin << "(timeOffset: " << decHDR->timeOffset << " + (orbit: " << o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) << " - firstOrbit " << firstOrbit << ") * LHCMaxBunches - triggerBC: " << triggerBC << ", decoded data is " << minTimeBin << " - " << maxTimeBin;
974 amendPageErrorMessage(oss, rdh, decHDR, payloadEnd, decPagePtr, nOutput);
975 throw std::runtime_error(oss.str());
976 }
977
978 if (decHDR->nTimebinHeaders && payloadEnd - decPagePtr < 0) {
979 std::ostringstream oss;
980 oss << "Decoding ran over end of page";
981 amendPageErrorMessage(oss, rdh, decHDR, payloadEnd, decPagePtr, nOutput);
982 throw std::runtime_error(oss.str());
983 }
984 if (decHDR->nTimebinHeaders && payloadEnd - decPagePtr >= 2 * o2::raw::RDHUtils::GBTWord128) {
985 std::ostringstream oss;
986 oss << "Decoding didn't reach end of page";
987 amendPageErrorMessage(oss, rdh, decHDR, payloadEnd, decPagePtr, nOutput);
988 throw std::runtime_error(oss.str());
989 }
990}
991
992void zsEncoderDenseLinkBased::amendPageErrorMessage(std::ostringstream& oss, const o2::header::RAWDataHeader* rdh, const TPCZSHDRV2* decHDR, const uint8_t* payloadEnd, const uint8_t* decPagePtr, uint32_t nOutput)
993{
994 if (payloadEnd && decPagePtr) {
995 oss << " (payloadEnd " << (void*)payloadEnd << " - decPagePtr " << (void*)decPagePtr << " - " << (payloadEnd - decPagePtr) << " bytes left, " << nOutput << " of " << decHDR->nADCsamples << " digits decoded)\n";
996 } else {
997 oss << "\n";
998 }
999 constexpr size_t bufferSize = 3 * std::max(sizeof(*rdh), sizeof(*decHDR)) + 1;
1000 char dumpBuffer[bufferSize];
1001 for (size_t i = 0; i < sizeof(*rdh); i++) {
1002 snprintf(dumpBuffer + 3 * i, 4, "%02X ", (int32_t)((uint8_t*)rdh)[i]);
1003 }
1004 oss << "RDH of page: " << dumpBuffer << "\n";
1005 for (size_t i = 0; i < sizeof(*decHDR); i++) {
1006 snprintf(dumpBuffer + 3 * i, 4, "%02X ", (int32_t)((uint8_t*)decHDR)[i]);
1007 }
1008 oss << "Meta header of page: " << dumpBuffer << "\n";
1009}
1010
1011#endif // !GPUCA_STANDALONE
1012
1013// ------------------------------------------------- TPC ZS Main Encoder -------------------------------------------------
1014
1015template <class T>
1016struct zsEncoderRun : public T {
1017 uint32_t run(std::vector<zsPage>* buffer, std::vector<o2::tpc::Digit>& tmpBuffer, size_t* totalSize = nullptr);
1018 size_t compare(std::vector<zsPage>* buffer, std::vector<o2::tpc::Digit>& tmpBuffer);
1019
1020 using T::bcShiftInFirstHBF;
1021 using T::checkInput;
1022 using T::curRegion;
1023 using T::decodePage;
1024 using T::encodeBits;
1025 using T::encodeBitsFactor;
1026 using T::encodeSequence;
1027 using T::endpoint;
1028 using T::firstTimebinInPage;
1029 using T::getHbf;
1030 using T::hbf;
1031 using T::hdr;
1032 using T::init;
1033 using T::initPage;
1034 using T::ir;
1035 using T::iSector;
1036 using T::lastEndpoint;
1037 using T::lastRow;
1038 using T::lastTime;
1039 using T::needAnotherPage;
1040 using T::nexthbf;
1041 using T::outputEndpoint;
1042 using T::outputRegion;
1043 using T::packetCounter;
1044 using T::padding;
1045 using T::page;
1046 using T::pageCounter;
1047 using T::pagePtr;
1048 using T::param;
1049 using T::raw;
1050 using T::sort;
1051 using T::writeSubPage;
1052 using T::ZSfillEmpty;
1053 using T::zsVersion;
1054};
1055
1056template <class T>
1057inline uint32_t zsEncoderRun<T>::run(std::vector<zsPage>* buffer, std::vector<o2::tpc::Digit>& tmpBuffer, size_t* totalSize)
1058{
1059 uint32_t totalPages = 0;
1060 zsPage singleBuffer;
1061#ifndef GPUCA_STANDALONE
1062 int32_t maxhbf = 0;
1063 int32_t minhbf = o2::constants::lhc::LHCMaxBunches;
1064#endif
1065 bcShiftInFirstHBF = ir ? ir->bc : 0;
1066 int32_t orbitShift = ir ? ir->orbit : 0;
1067 int32_t rawcru = 0;
1068 int32_t rawendpoint = 0;
1069 (void)(rawcru + rawendpoint); // avoid compiler warning
1070 encodeBitsFactor = (1 << (encodeBits - 10));
1071
1072 std::sort(tmpBuffer.begin(), tmpBuffer.end(), [this](const o2::tpc::Digit a, const o2::tpc::Digit b) { return sort(a, b); });
1073 for (uint32_t k = 0; k <= tmpBuffer.size();) {
1074 bool mustWritePage = false, mustWriteSubPage = false;
1075 if (needAnotherPage) {
1076 needAnotherPage = false;
1077 mustWritePage = true;
1078 } else {
1079 if (k < tmpBuffer.size()) {
1080 if (tmpBuffer[k].getTimeStamp() != lastTime) {
1081 nexthbf = getHbf(tmpBuffer[k].getTimeStamp());
1082 if (nexthbf < 0) {
1083 throw std::runtime_error("Received digit before the defined first orbit");
1084 }
1085 if (hbf != nexthbf) {
1086 lastEndpoint = -2;
1087 mustWritePage = true;
1088 }
1089 }
1090 if (lastRow != tmpBuffer[k].getRow()) {
1091 curRegion = GPUTPCGeometry::GetRegion(tmpBuffer[k].getRow());
1092 }
1093 mustWriteSubPage = checkInput(tmpBuffer, k);
1094 } else {
1095 nexthbf = -1;
1096 mustWritePage = true;
1097 }
1098 }
1099 if (mustWritePage || mustWriteSubPage) {
1100 mustWritePage |= writeSubPage();
1101
1102 if (page && mustWritePage) {
1103 if constexpr (std::is_same_v<T, struct zsEncoderDenseLinkBased>) {
1104 if ((pagePtr - (uint8_t*)page) % o2::raw::RDHUtils::GBTWord128) {
1106 }
1107 uint8_t* triggerWord = nullptr;
1108 if (hbf != nexthbf || endpoint != lastEndpoint) {
1110 if ((pagePtr - (uint8_t*)page) % (2 * o2::raw::RDHUtils::GBTWord128)) {
1111 pagePtr += o2::raw::RDHUtils::GBTWord128; // align to 256 bit, size constrained cannot be affected by this
1112 }
1114 } else {
1115 needAnotherPage = true;
1116 }
1117 if (this->sequenceBuffer.size()) {
1118 needAnotherPage = true;
1119 }
1120 }
1122 triggerWord = pagePtr;
1124 }
1125 if ((pagePtr - (uint8_t*)page) % (2 * o2::raw::RDHUtils::GBTWord128) == 0) {
1126 pagePtr += o2::raw::RDHUtils::GBTWord128; // align to 128bit mod 256
1127 }
1128 TPCZSHDRV2* pagehdr = (TPCZSHDRV2*)pagePtr;
1129 pagePtr += sizeof(TPCZSHDRV2);
1130 if (pagePtr - (uint8_t*)page > TPCZSHDR::TPC_ZS_PAGE_SIZE) {
1131 throw std::runtime_error("TPC ZS page overflow");
1132 }
1133 memcpy(pagehdr, hdr, sizeof(*hdr));
1134 if (triggerWord) {
1135 memset(triggerWord, 0, o2::tpc::TPCZSHDRV2::TRIGGER_WORD_SIZE);
1136 }
1137 }
1138 const rdh_utils::FEEIDType rawfeeid = rdh_utils::getFEEID(rawcru, rawendpoint, this->RAWLNK);
1139 if (totalSize) {
1140 *totalSize += !std::is_same_v<T, struct zsEncoderDenseLinkBased> && (lastEndpoint == -1 || hbf == nexthbf) ? TPCZSHDR::TPC_ZS_PAGE_SIZE : (pagePtr - (uint8_t*)page);
1141 }
1142 size_t size = !std::is_same_v<T, struct zsEncoderDenseLinkBased> && (padding || lastEndpoint == -1 || hbf == nexthbf) ? TPCZSHDR::TPC_ZS_PAGE_SIZE : (pagePtr - (uint8_t*)page);
1143 size = CAMath::nextMultipleOf<o2::raw::RDHUtils::GBTWord128>(size);
1144#ifndef GPUCA_STANDALONE
1145 if (raw) {
1146 raw->addData(rawfeeid, rawcru, 0, rawendpoint, *ir + hbf * o2::constants::lhc::LHCMaxBunches, gsl::span<char>((char*)page + sizeof(o2::header::RAWDataHeader), (char*)page + size), true, 0, 2);
1147 maxhbf = std::max<int32_t>(maxhbf, hbf);
1148 minhbf = std::min<int32_t>(minhbf, hbf);
1149 } else
1150#endif
1151 {
1153 o2::raw::RDHUtils::setHeartBeatOrbit(*rdh, hbf + orbitShift);
1154 o2::raw::RDHUtils::setHeartBeatBC(*rdh, bcShiftInFirstHBF);
1156 o2::raw::RDHUtils::setVersion(*rdh, o2::raw::RDHUtils::getVersion<o2::header::RAWDataHeader>());
1157 o2::raw::RDHUtils::setFEEID(*rdh, rawfeeid);
1159 o2::raw::RDHUtils::setLinkID(*rdh, this->RAWLNK);
1162 }
1163 }
1164 if (k >= tmpBuffer.size() && !needAnotherPage) {
1165 break;
1166 }
1167 }
1168 if (mustWritePage) {
1169 if (!needAnotherPage) {
1170 if (hbf != nexthbf) {
1171 pageCounter = 0;
1172 }
1175 hbf = nexthbf;
1176 lastTime = -1;
1178 }
1179 if (raw) {
1180 page = &singleBuffer;
1181 } else {
1182 if (buffer[outputEndpoint].size() == 0 && nexthbf > orbitShift) {
1183 buffer[outputEndpoint].emplace_back();
1184 ZSfillEmpty(&buffer[outputEndpoint].back(), bcShiftInFirstHBF, rdh_utils::getFEEID(iSector * 10 + outputEndpoint / 2, outputEndpoint & 1, this->RAWLNK), orbitShift, this->RAWLNK); // Emplace empty page with RDH containing beginning of TF
1185 if (totalSize) {
1186 *totalSize += sizeof(o2::header::RAWDataHeader);
1187 }
1188 totalPages++;
1189 }
1190 buffer[outputEndpoint].emplace_back();
1191 page = &buffer[outputEndpoint].back();
1192 }
1193 pagePtr = reinterpret_cast<uint8_t*>(page);
1194 std::fill(page->begin(), page->end(), 0);
1196 if constexpr (std::is_same_v<T, struct zsEncoderDenseLinkBased>) {
1197 hdr = &this->hdrBuffer;
1198 } else {
1199 hdr = reinterpret_cast<decltype(hdr)>(pagePtr);
1200 pagePtr += sizeof(*hdr);
1201 }
1203 hdr->cruID = iSector * 10 + outputRegion;
1204 hdr->nTimeBinSpan = 0;
1205 hdr->nADCsamples = 0;
1206 rawcru = iSector * 10 + outputRegion;
1207 rawendpoint = outputEndpoint & 1;
1209 firstTimebinInPage = tmpBuffer[k].getTimeStamp();
1210 initPage();
1211 totalPages++;
1212 }
1213 if (needAnotherPage) {
1214 continue;
1215 }
1216 uint32_t nEncoded = encodeSequence(tmpBuffer, k);
1217 lastTime = tmpBuffer[k].getTimeStamp();
1218 lastRow = tmpBuffer[k].getRow();
1219 hdr->nADCsamples += nEncoded;
1220 k += nEncoded;
1221 }
1222 if (raw) {
1223#ifndef GPUCA_STANDALONE
1224 if (iSector == 0) {
1225 for (int32_t i = minhbf; i <= maxhbf; i++) {
1226 raw->addData(46208, 360, rdh_utils::SACLinkID, 0, *ir + i * o2::constants::lhc::LHCMaxBunches, gsl::span<char>((char*)&singleBuffer, (char*)&singleBuffer), true, 0, 4);
1227 }
1228 }
1229#endif
1230 } else {
1231 for (uint32_t j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) {
1232 if (buffer[j].size() == 0) {
1233 buffer[j].emplace_back();
1234 ZSfillEmpty(&buffer[j].back(), bcShiftInFirstHBF, rdh_utils::getFEEID(iSector * 10 + j / 2, j & 1, this->RAWLNK), orbitShift, this->RAWLNK);
1235 totalPages++;
1236 }
1237 }
1238 }
1239 return totalPages;
1240}
1241
1242template <class T>
1243size_t zsEncoderRun<T>::compare(std::vector<zsPage>* buffer, std::vector<o2::tpc::Digit>& tmpBuffer)
1244{
1245 size_t nErrors = 0;
1246 std::vector<o2::tpc::Digit> compareBuffer;
1247 compareBuffer.reserve(tmpBuffer.size());
1248 for (uint32_t j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) {
1249 uint32_t firstOrbit = ir ? ir->orbit : 0;
1250 for (uint32_t k = 0; k < buffer[j].size(); k++) {
1251 zsPage* decPage = &buffer[j][k];
1252 decodePage(compareBuffer, decPage, j, firstOrbit);
1253 }
1254 }
1255 if (tmpBuffer.size() != compareBuffer.size()) {
1256 nErrors += tmpBuffer.size();
1257 printf("Number of clusters mismatch %d %d\n", (int32_t)tmpBuffer.size(), (int32_t)compareBuffer.size());
1258 } else {
1259 for (uint32_t j = 0; j < tmpBuffer.size(); j++) {
1260 const float decodeBitsFactor = (1 << (encodeBits - 10));
1261 const float c = CAMath::Round(tmpBuffer[j].getChargeFloat() * decodeBitsFactor) / decodeBitsFactor;
1262 int32_t ok = c == compareBuffer[j].getChargeFloat() && (int32_t)tmpBuffer[j].getTimeStamp() == (int32_t)compareBuffer[j].getTimeStamp() && (int32_t)tmpBuffer[j].getPad() == (int32_t)compareBuffer[j].getPad() && (int32_t)tmpBuffer[j].getRow() == (int32_t)compareBuffer[j].getRow();
1263 if (ok) {
1264 continue;
1265 }
1266 nErrors++;
1267 printf("%4u: OK %d: Charge %3d %3d Time %4d %4d Pad %3d %3d Row %3d %3d\n", j, ok,
1268 (int32_t)c, (int32_t)compareBuffer[j].getChargeFloat(), (int32_t)tmpBuffer[j].getTimeStamp(), (int32_t)compareBuffer[j].getTimeStamp(), (int32_t)tmpBuffer[j].getPad(), (int32_t)compareBuffer[j].getPad(), (int32_t)tmpBuffer[j].getRow(), (int32_t)compareBuffer[j].getRow());
1269 }
1270 }
1271 return nErrors;
1272}
1273
1274} // anonymous namespace
1275} // namespace o2::gpu
1276#endif // !GPUCA_RUN2
1277
1278template <class S>
1279void GPUReconstructionConvert::RunZSEncoder(const S& in, std::unique_ptr<uint64_t[]>* outBuffer, uint32_t* outSizes, o2::raw::RawFileWriter* raw, const o2::InteractionRecord* ir, const GPUParam& param, int32_t version, bool verify, float threshold, bool padding, std::function<void(std::vector<o2::tpc::Digit>&)> digitsFilter)
1280{
1281 // Pass in either outBuffer / outSizes, to fill standalone output buffers, or raw to use RawFileWriter
1282 // ir is the interaction record for time bin 0
1283 if (((outBuffer == nullptr) ^ (outSizes == nullptr)) || ((raw != nullptr) && (ir == nullptr)) || !((outBuffer == nullptr) ^ (raw == nullptr)) || (raw && verify)) {
1284 throw std::runtime_error("Invalid parameters");
1285 }
1286#ifndef GPUCA_RUN2
1287 std::vector<zsPage> buffer[NSECTORS][GPUTrackingInOutZS::NENDPOINTS];
1288 struct tmpReductionResult {
1289 uint32_t totalPages = 0;
1290 size_t totalSize = 0;
1291 size_t nErrors = 0;
1292 size_t digitsInput = 0;
1293 size_t digitsEncoded = 0;
1294 };
1295 auto reduced = tbb::parallel_reduce(tbb::blocked_range<uint32_t>(0, NSECTORS), tmpReductionResult(), [&](const auto range, auto red) {
1296 for (uint32_t i = range.begin(); i < range.end(); i++) {
1297 std::vector<o2::tpc::Digit> tmpBuffer;
1298 red.digitsInput += ZSEncoderGetNDigits(in, i);
1299 tmpBuffer.resize(ZSEncoderGetNDigits(in, i));
1300 if (threshold > 0.f && !digitsFilter) {
1301 auto it = std::copy_if(ZSEncoderGetDigits(in, i), ZSEncoderGetDigits(in, i) + ZSEncoderGetNDigits(in, i), tmpBuffer.begin(), [threshold](auto& v) { return v.getChargeFloat() >= threshold; });
1302 tmpBuffer.resize(std::distance(tmpBuffer.begin(), it));
1303 } else {
1304 std::copy(ZSEncoderGetDigits(in, i), ZSEncoderGetDigits(in, i) + ZSEncoderGetNDigits(in, i), tmpBuffer.begin());
1305 }
1306
1307 if (digitsFilter) {
1308 digitsFilter(tmpBuffer);
1309 if (threshold > 0.f) {
1310 std::vector<o2::tpc::Digit> tmpBuffer2 = std::move(tmpBuffer);
1311 tmpBuffer = std::vector<o2::tpc::Digit>(tmpBuffer2.size());
1312 auto it = std::copy_if(tmpBuffer2.begin(), tmpBuffer2.end(), tmpBuffer.begin(), [threshold](auto& v) { return v.getChargeFloat() >= threshold; });
1313 tmpBuffer.resize(std::distance(tmpBuffer.begin(), it));
1314 }
1315 }
1316 red.digitsEncoded += tmpBuffer.size();
1317
1318 auto runZS = [&](auto& encoder) {
1319 encoder.zsVersion = version;
1320 encoder.init();
1321 red.totalPages += encoder.run(buffer[i], tmpBuffer, &red.totalSize);
1322 if (verify) {
1323 red.nErrors += encoder.compare(buffer[i], tmpBuffer); // Verification
1324 }
1325 };
1326
1327 if (version >= ZSVersion::ZSVersionRowBased10BitADC && version <= ZSVersion::ZSVersionRowBased12BitADC) {
1328 zsEncoderRun<zsEncoderRow> enc{{{.iSector = i, .raw = raw, .ir = ir, .param = &param, .padding = padding}}};
1329 runZS(enc);
1330 } else if (version >= ZSVersion::ZSVersionLinkBasedWithMeta && version <= ZSVersion::ZSVersionDenseLinkBasedV2) {
1331#ifndef GPUCA_STANDALONE
1332 if (version == ZSVersion::ZSVersionLinkBasedWithMeta) {
1333 zsEncoderRun<zsEncoderImprovedLinkBased> enc{{{{.iSector = i, .raw = raw, .ir = ir, .param = &param, .padding = padding}}}};
1334 runZS(enc);
1335 } else if (version >= ZSVersion::ZSVersionDenseLinkBased && version <= ZSVersion::ZSVersionDenseLinkBasedV2) {
1336 zsEncoderRun<zsEncoderDenseLinkBased> enc{{{{.iSector = i, .raw = raw, .ir = ir, .param = &param, .padding = padding}}}};
1337 runZS(enc);
1338 }
1339#else
1340 throw std::runtime_error("Link based ZS encoding not supported in standalone build");
1341#endif
1342 } else {
1343 throw std::runtime_error("Invalid ZS version "s + std::to_string(version) + ", cannot decode"s);
1344 }
1345 }
1346 return red; }, [&](const auto& red1, const auto& red2) {
1347 auto red = red1;
1348 red.totalPages += red2.totalPages;
1349 red.totalSize += red2.totalSize;
1350 red.nErrors += red2.nErrors;
1351 red.digitsInput += red2.digitsInput;
1352 red.digitsEncoded += red2.digitsEncoded;
1353 return red; });
1354
1355 if (outBuffer) {
1356 outBuffer->reset(new uint64_t[reduced.totalPages * TPCZSHDR::TPC_ZS_PAGE_SIZE / sizeof(uint64_t)]);
1357 uint64_t offset = 0;
1358 for (uint32_t i = 0; i < NSECTORS; i++) {
1359 for (uint32_t j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) {
1360 memcpy((char*)outBuffer->get() + offset, buffer[i][j].data(), buffer[i][j].size() * TPCZSHDR::TPC_ZS_PAGE_SIZE);
1362 outSizes[i * GPUTrackingInOutZS::NENDPOINTS + j] = buffer[i][j].size();
1363 }
1364 }
1365 }
1366 if (reduced.nErrors) {
1367 GPUError("ERROR: %lu INCORRECT SAMPLES DURING ZS ENCODING VERIFICATION!!!", reduced.nErrors);
1368 } else if (verify) {
1369 GPUInfo("ENCODING VERIFICATION PASSED");
1370 }
1371 GPUInfo("TOTAL ENCODED SIZE: %lu (%lu of %lu digits encoded)", reduced.totalSize, reduced.digitsEncoded, reduced.digitsInput);
1372#endif
1373}
1374
1375template void GPUReconstructionConvert::RunZSEncoder<GPUTrackingInOutDigits>(const GPUTrackingInOutDigits&, std::unique_ptr<uint64_t[]>*, uint32_t*, o2::raw::RawFileWriter*, const o2::InteractionRecord*, const GPUParam&, int32_t, bool, float, bool, std::function<void(std::vector<o2::tpc::Digit>&)> digitsFilter);
1376#ifndef GPUCA_STANDALONE
1377template void GPUReconstructionConvert::RunZSEncoder<DigitArray>(const DigitArray&, std::unique_ptr<uint64_t[]>*, uint32_t*, o2::raw::RawFileWriter*, const o2::InteractionRecord*, const GPUParam&, int32_t, bool, float, bool, std::function<void(std::vector<o2::tpc::Digit>&)> digitsFilter);
1378#endif
1379
1380void GPUReconstructionConvert::RunZSEncoderCreateMeta(const uint64_t* buffer, const uint32_t* sizes, void** ptrs, GPUTrackingInOutZS* out)
1381{
1382 uint64_t offset = 0;
1383 for (uint32_t i = 0; i < NSECTORS; i++) {
1384 for (uint32_t j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) {
1385 ptrs[i * GPUTrackingInOutZS::NENDPOINTS + j] = (char*)buffer + offset;
1387 out->sector[i].zsPtr[j] = &ptrs[i * GPUTrackingInOutZS::NENDPOINTS + j];
1389 out->sector[i].count[j] = 1;
1390 }
1391 }
1392}
1393
1394void GPUReconstructionConvert::RunZSFilter(std::unique_ptr<o2::tpc::Digit[]>* buffers, const o2::tpc::Digit* const* ptrs, size_t* nsb, const size_t* ns, const GPUParam& param, bool zs12bit, float threshold)
1395{
1396 for (uint32_t i = 0; i < NSECTORS; i++) {
1397 if (buffers[i].get() != ptrs[i] || nsb != ns) {
1398 throw std::runtime_error("Not owning digits");
1399 }
1400 uint32_t j = 0;
1401 const uint32_t decodeBits = zs12bit ? TPCZSHDR::TPC_ZS_NBITS_V2 : TPCZSHDR::TPC_ZS_NBITS_V1;
1402 const float decodeBitsFactor = (1 << (decodeBits - 10));
1403 for (uint32_t k = 0; k < ns[i]; k++) {
1404 if (buffers[i][k].getChargeFloat() >= threshold) {
1405 if (k > j) {
1406 buffers[i][j] = buffers[i][k];
1407 }
1408 if (zs12bit) {
1409 buffers[i][j].setCharge(CAMath::Round(buffers[i][j].getChargeFloat() * decodeBitsFactor) / decodeBitsFactor);
1410 } else {
1411 buffers[i][j].setCharge(CAMath::Round(buffers[i][j].getChargeFloat()));
1412 }
1413 j++;
1414 }
1415 }
1416 nsb[i] = j;
1417 }
1418}
1419
1420#ifndef GPUCA_STANDALONE
1421namespace o2::gpu::internal
1422{
1423template <class T>
1424static inline auto GetDecoder_internal(const GPUParam* param, int32_t version)
1425{
1426 std::shared_ptr<T> enc = std::make_shared<T>();
1427 if (param == nullptr) {
1428 static GPUParam dummyParam;
1429 param = &dummyParam;
1430 }
1431 enc->param = param;
1432 enc->zsVersion = version;
1433 enc->init();
1434 return [enc](std::vector<o2::tpc::Digit>& outBuffer, const void* page, uint32_t firstTfOrbit, uint32_t triggerBC = 0) {
1436 if (o2::raw::RDHUtils::getMemorySize(rdh) == sizeof(o2::header::RAWDataHeader)) {
1437 return;
1438 }
1439 if (o2::raw::RDHUtils::getDetectorField(rdh) != 2) {
1440 return;
1441 }
1442 o2::tpc::CRU cru(o2::tpc::rdh_utils::getCRU(rdh));
1443 enc->iSector = cru.sector();
1444 int32_t endpoint = cru.region() * 2 + o2::tpc::rdh_utils::getEndPoint(rdh);
1445 enc->decodePage(outBuffer, (const zsPage*)page, endpoint, firstTfOrbit, triggerBC);
1446 };
1447}
1448} // namespace o2::gpu::internal
1449
1450std::function<void(std::vector<o2::tpc::Digit>&, const void*, uint32_t, uint32_t)> GPUReconstructionConvert::GetDecoder(int32_t version, const GPUParam* param)
1451{
1453 return o2::gpu::internal::GetDecoder_internal<zsEncoderRow>(param, version);
1455 return o2::gpu::internal::GetDecoder_internal<zsEncoderImprovedLinkBased>(param, version);
1457 return o2::gpu::internal::GetDecoder_internal<zsEncoderDenseLinkBased>(param, version);
1458 } else {
1459 throw std::runtime_error("Invalid ZS version "s + std::to_string(version) + ", cannot create decoder"s);
1460 }
1461}
1462#endif
uint16_t padding
Definition of the TPC Digit.
std::ostringstream debug
uint64_t orbit
Definition RawEventData.h:6
uint64_t bc
Definition RawEventData.h:5
int32_t i
uint8_t * nSeq
int32_t outputEndpoint
std::array< uint8_t, TPCZSHDR::TPC_ZS_PAGE_SIZE > streamBuffer8
int64_t nexthbf
uint32_t zsVersion
TPCZSTBHDR * curTBHdr
int32_t lastEndpoint
TPCZSHDR * hdr
uint32_t encodeBits
zsPage * page
uint32_t iSector
uint32_t streamSize8
float encodeBitsFactor
uint32_t streamSize
std::array< uint16_t, TPCZSHDR::TPC_ZS_PAGE_SIZE > streamBuffer
int32_t curRegion
std::bitset< 80 > bitmask
uint8_t * pagePtr
int32_t endpointStart
int32_t inverseChannelMapping[5][32]
int32_t lastTime
TPCZSHDRV2 hdrBuffer
uint32_t pageCounter
int32_t nSamples
int32_t lastRow
int32_t bcShiftInFirstHBF
uint16_t curTimeBin
std::vector< uint8_t > sequenceBuffer
int32_t nRowsInTB
std::vector< uint16_t > sequenceBufferADC
std::vector< uint16_t > adcValues
int32_t firstTimebinInPage
uint32_t packetCounter
o2::raw::RawFileWriter * raw
int32_t outputRegion
int32_t retVal
Header to collect LHC related constants.
uint32_t j
Definition RawData.h:0
uint8_t endpoint
Definition RawData.h:0
uint32_t c
Definition RawData.h:2
uint32_t version
Definition RawData.h:8
Utility class to write detectors data to (multiple) raw data file(s) respecting CRU format.
POD correction map.
TBranch * ptr
definitions to deal with the link based zero suppression format
Definitions of TPC Zero Suppression Data Headers.
static void RunZSEncoder(const S &in, std::unique_ptr< uint64_t[]> *outBuffer, uint32_t *outSizes, o2::raw::RawFileWriter *raw, const o2::InteractionRecord *ir, const GPUParam &param, int32_t version, bool verify, float threshold=0.f, bool padding=false, std::function< void(std::vector< o2::tpc::Digit > &)> digitsFilter=nullptr)
static std::function< void(std::vector< o2::tpc::Digit > &, const void *, uint32_t, uint32_t)> GetDecoder(int32_t version, const GPUParam *param)
static void RunZSFilter(std::unique_ptr< o2::tpc::Digit[]> *buffers, const o2::tpc::Digit *const *ptrs, size_t *nsb, const size_t *ns, const GPUParam &param, bool zs12bit, float threshold)
static int32_t GetMaxTimeBin(const o2::tpc::ClusterNativeAccess &native)
static void RunZSEncoderCreateMeta(const uint64_t *buffer, const uint32_t *sizes, void **ptrs, GPUTrackingInOutZS *out)
static void ConvertRun2RawToNative(o2::tpc::ClusterNativeAccess &native, std::unique_ptr< o2::tpc::ClusterNative[]> &nativeBuffer, const AliHLTTPCRawCluster **rawClusters, uint32_t *nRawClusters)
static constexpr uint32_t NROWS
void addData(uint16_t feeid, uint16_t cru, uint8_t lnk, uint8_t endpoint, const IR &ir, const gsl::span< char > data, bool preformatted=false, uint32_t trigger=0, uint32_t detField=0)
unsigned char partition() const
Definition CRU.h:63
unsigned char getSampaChannel() const
Definition FECInfo.h:45
unsigned char getIndex() const
Definition FECInfo.h:41
unsigned char getSampaChip() const
Definition FECInfo.h:44
static Mapper & instance(const std::string mappingDir="")
Definition Mapper.h:44
static constexpr void getSampaAndChannelOnFEC(const int cruID, const size_t rawFECChannel, int &sampaOnFEC, int &channelOnSAMPA)
Definition Mapper.h:275
static constexpr int MAXSECTOR
Definition Sector.h:44
std::array< gsl::span< const o2::tpc::Digit >, Sector::MAXSECTOR > DigitArray
GLdouble n
Definition glcorearb.h:1982
const GLfloat * m
Definition glcorearb.h:4066
GLuint buffer
Definition glcorearb.h:655
GLsizeiptr size
Definition glcorearb.h:659
const GLdouble * v
Definition glcorearb.h:832
GLuint GLsizei const GLuint const GLintptr const GLsizeiptr * sizes
Definition glcorearb.h:2595
GLsizei samples
Definition glcorearb.h:1309
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLenum GLint * range
Definition glcorearb.h:1899
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
Definition glcorearb.h:4150
GLintptr offset
Definition glcorearb.h:660
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLenum GLfloat param
Definition glcorearb.h:271
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLint GLuint mask
Definition glcorearb.h:291
const GLuint * buffers
Definition glcorearb.h:656
uint8_t itsSharedClusterMap uint8_t
constexpr int LHCMaxBunches
const GBTLinkAttributes links[kNGBTLinks]
Definition RawWriter.h:54
RAWDataHeaderV7 RAWDataHeader
void dumpBuffer(gsl::span< const std::byte > buffer, std::ostream &out=std::cout, size_t maxbytes=std::numeric_limits< size_t >::max())
Definition DumpBuffer.h:139
constexpr int LHCBCPERTIMEBIN
Definition Constants.h:38
uint64_t getTimeStamp(o2::framework::ProcessingContext &pc)
uint16_t FEEIDType
Definition RDHUtils.h:26
Global TPC definitions and constants.
Definition SimTraits.h:168
@ ZSVersionDenseLinkBased
@ ZSVersionLinkBasedWithMeta
@ ZSVersionDenseLinkBasedV2
@ ZSVersionRowBased10BitADC
@ ZSVersionRowBased12BitADC
unsigned short GlobalPadNumber
global pad number
Definition Defs.h:112
constexpr std::array< int, nLayers > nRows
Definition Specs.h:59
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
int32_t GetCharge() const
uint16_t GetFlags() const
int32_t GetPadRow() const
uint32_t orbit
LHC orbit.
uint16_t bc
bunch crossing ID of interaction
const o2::tpc::Digit * tpcDigits[NSECTORS]
GPUTrackingInOutZSSector sector[NSECTORS]
static constexpr uint32_t NENDPOINTS
static void setLinkID(H &rdh, uint8_t v, NOTPTR(H))
Definition RDHUtils.h:258
static void setDetectorField(H &rdh, uint32_t v, NOTPTR(H))
Definition RDHUtils.h:584
static constexpr int GBTWord128
Definition RDHUtils.h:54
static void setPageCounter(H &rdh, uint16_t v, NOTPTR(H))
Definition RDHUtils.h:559
static void setMemorySize(H &rdh, uint16_t v, NOTPTR(H))
Definition RDHUtils.h:242
static void setVersion(H &rdh, uint8_t v, NOTPTR(H))
Definition RDHUtils.h:90
static void setPacketCounter(H &rdh, uint8_t v, NOTPTR(H))
Definition RDHUtils.h:274
static void setHeartBeatOrbit(RDHv4 &rdh, uint32_t v)
Definition RDHUtils.h:364
static void setFEEID(RDHv4 &rdh, uint16_t v)
Definition RDHUtils.h:148
unsigned int nClusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
const ClusterNative * clusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
unsigned int clusterOffset[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
const ClusterNative * clustersLinear
unsigned short nTimebinHeaders
unsigned char magicWord
unsigned short firstZSDataOffset
static constexpr bool TIGHTLY_PACKED_V3
static constexpr unsigned int TPC_ZS_NBITS_V34
static constexpr unsigned int SAMPLESPER64BIT
static constexpr unsigned int TRIGGER_WORD_SIZE
unsigned char nTimeBinSpan
unsigned char version
unsigned short timeOffset
unsigned short cruID
static constexpr unsigned int TPC_ZS_NBITS_V1
static constexpr unsigned int TPC_ZS_NBITS_V2
static constexpr size_t TPC_ZS_PAGE_SIZE
unsigned short nADCsamples
unsigned short rowMask
void compare(std::string_view s1, std::string_view s2)
o2::InteractionRecord ir(0, 0)
std::vector< Digit > digits
std::vector< int > row