Skip to content

Commit 1d1b946

Browse files
committed
TPC: Implement dense improved link-based ZS
1 parent cc39dd7 commit 1d1b946

2 files changed

Lines changed: 228 additions & 51 deletions

File tree

DataFormats/Detectors/TPC/include/DataFormatsTPC/ZeroSuppression.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,19 @@ struct TPCZSHDR {
3939
static constexpr unsigned int TPC_ZS_NBITS_V1 = 10;
4040
static constexpr unsigned int TPC_ZS_NBITS_V2 = 12;
4141

42-
unsigned char version; // ZS format version:
43-
// 1: original row-based format with 10-bit ADC values
44-
// 2: original row-based format with 12-bit ADC values
45-
// 3: improved link-based format with extra META header
42+
unsigned char version; // ZS format version:
43+
// 1: original row-based format with 10-bit ADC values
44+
// 2: original row-based format with 12-bit ADC values
45+
// 3: improved link-based format with extra META header
46+
// 4: tightly-packed link based
4647
unsigned char nTimeBins; // Number of time bins in this raw page
4748
unsigned short cruID; // CRU id
4849
unsigned short timeOffset; // Time offset in BC after orbit in RDH
4950
unsigned short nADCsamples; // Total number of ADC samples in this raw page
5051
};
5152
struct TPCZSHDRV2 : public TPCZSHDR {
5253
static constexpr unsigned int TPC_ZS_NBITS_V3 = 12;
54+
static constexpr unsigned int TPC_ZS_NBITS_V4 = 12;
5355
static constexpr bool TIGHTLY_PACKED_V3 = false;
5456
static constexpr unsigned int SAMPLESPER64BIT = 64 / TPC_ZS_NBITS_V3; // 5 12-bit samples with 4 bit padding per 64 bit word for non-TIGHTLY_PACKED data
5557

GPU/GPUTracking/Base/GPUReconstructionConvert.cxx

Lines changed: 222 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ void zsEncoderRow::decodePage(std::vector<o2::tpc::Digit>& outputBuffer, const z
456456
// ------------------------------------------------- TPC ZS Improved Link Based ZS -------------------------------------------------
457457

458458
#ifdef GPUCA_O2_LIB
459-
struct zsEncoderImprovedLinkBased : public zsEncoder {
459+
struct zsEncoderLinkBased : public zsEncoder {
460460
TPCZSHDRV2* hdr = nullptr;
461461
int inverseChannelMapping[5][32];
462462
int nSamples = 0;
@@ -465,16 +465,14 @@ struct zsEncoderImprovedLinkBased : public zsEncoder {
465465
std::vector<unsigned short> adcValues = {};
466466
std::bitset<80> bitmask = {};
467467

468-
bool checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, unsigned int k);
468+
void createBitmask(std::vector<o2::tpc::Digit>& tmpBuffer, unsigned int k);
469469
bool writeSubPage();
470470
void init();
471471
void initPage();
472-
unsigned int encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, unsigned int k);
473472
bool sort(const o2::tpc::Digit a, const o2::tpc::Digit b);
474-
void decodePage(std::vector<o2::tpc::Digit>& outputBuffer, const zsPage* page, unsigned int endpoint, unsigned int firstOrbit);
475473
};
476474

477-
void zsEncoderImprovedLinkBased::init()
475+
void zsEncoderLinkBased::init()
478476
{
479477
for (int i = 0; i < 5; i++) {
480478
for (int j = 0; j < 32; j++) {
@@ -502,14 +500,14 @@ void zsEncoderImprovedLinkBased::init()
502500
}
503501
}
504502

505-
void zsEncoderImprovedLinkBased::initPage()
503+
void zsEncoderLinkBased::initPage()
506504
{
507505
hdr->magicWord = o2::tpc::zerosupp_link_based::CommonHeader::MagicWordLinkZSMetaHeader;
508506
hdr->nTimebinHeaders = 0;
509507
hdr->firstZSDataOffset = 0;
510508
}
511509

512-
bool zsEncoderImprovedLinkBased::checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, unsigned int k)
510+
void zsEncoderLinkBased::createBitmask(std::vector<o2::tpc::Digit>& tmpBuffer, unsigned int k)
513511
{
514512
const auto& mapper = Mapper::instance();
515513
nSamples = 0;
@@ -539,6 +537,53 @@ bool zsEncoderImprovedLinkBased::checkInput(std::vector<o2::tpc::Digit>& tmpBuff
539537
if (tmpBuffer[k].getTimeStamp() - firstTimebinInPage + 1 > (1 << (sizeof(hdr->nTimeBins) * 8)) - 1) {
540538
finishPage = true;
541539
}
540+
}
541+
542+
bool zsEncoderLinkBased::writeSubPage()
543+
{
544+
return finishPage;
545+
}
546+
547+
bool zsEncoderLinkBased::sort(const o2::tpc::Digit a, const o2::tpc::Digit b)
548+
{
549+
// Fixme: this is blasphemy... one shoult precompute all values and sort an index array
550+
int cruinsectora = param.tpcGeometry.GetRegion(a.getRow());
551+
int cruinsectorb = param.tpcGeometry.GetRegion(b.getRow());
552+
if (cruinsectora != cruinsectorb) {
553+
return cruinsectora < cruinsectorb;
554+
}
555+
const auto& mapper = Mapper::instance();
556+
o2::tpc::GlobalPadNumber pada = mapper.globalPadNumber(o2::tpc::PadPos(a.getRow(), a.getPad()));
557+
o2::tpc::GlobalPadNumber padb = mapper.globalPadNumber(o2::tpc::PadPos(b.getRow(), b.getPad()));
558+
o2::tpc::FECInfo feca = mapper.fecInfo(pada);
559+
o2::tpc::FECInfo fecb = mapper.fecInfo(padb);
560+
o2::tpc::CRU cru = cruinsectora;
561+
int fecInPartitiona = feca.getIndex() - mapper.getPartitionInfo(cru.partition()).getSectorFECOffset();
562+
int fecInPartitionb = fecb.getIndex() - mapper.getPartitionInfo(cru.partition()).getSectorFECOffset();
563+
564+
int endpointa = 2 * cruinsectora + (fecInPartitiona >= (mapper.getPartitionInfo(cru.partition()).getNumberOfFECs() + 1) / 2);
565+
int endpointb = 2 * cruinsectorb + (fecInPartitionb >= (mapper.getPartitionInfo(cru.partition()).getNumberOfFECs() + 1) / 2);
566+
if (endpointa != endpointb) {
567+
return endpointa < endpointb;
568+
}
569+
if (a.getTimeStamp() != b.getTimeStamp()) {
570+
return a.getTimeStamp() < b.getTimeStamp();
571+
}
572+
if (fecInPartitiona != fecInPartitionb) {
573+
return fecInPartitiona < fecInPartitionb;
574+
}
575+
return inverseChannelMapping[feca.getSampaChip()][feca.getSampaChannel()] < inverseChannelMapping[fecb.getSampaChip()][fecb.getSampaChannel()];
576+
}
577+
578+
struct zsEncoderImprovedLinkBased : public zsEncoderLinkBased {
579+
bool checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, unsigned int k);
580+
unsigned int encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, unsigned int k);
581+
void decodePage(std::vector<o2::tpc::Digit>& outputBuffer, const zsPage* page, unsigned int endpoint, unsigned int firstOrbit);
582+
};
583+
584+
bool zsEncoderImprovedLinkBased::checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, unsigned int k)
585+
{
586+
createBitmask(tmpBuffer, k);
542587
if (!finishPage) {
543588
unsigned int sizeChk = (unsigned int)(pagePtr - reinterpret_cast<unsigned char*>(page));
544589
sizeChk += sizeof(o2::tpc::zerosupp_link_based::CommonHeader);
@@ -554,11 +599,6 @@ bool zsEncoderImprovedLinkBased::checkInput(std::vector<o2::tpc::Digit>& tmpBuff
554599
return finishPage;
555600
}
556601

557-
bool zsEncoderImprovedLinkBased::writeSubPage()
558-
{
559-
return finishPage;
560-
}
561-
562602
unsigned int zsEncoderImprovedLinkBased::encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, unsigned int k)
563603
{
564604
o2::tpc::zerosupp_link_based::CommonHeader* tbHdr = (o2::tpc::zerosupp_link_based::CommonHeader*)pagePtr;
@@ -590,37 +630,6 @@ unsigned int zsEncoderImprovedLinkBased::encodeSequence(std::vector<o2::tpc::Dig
590630
return nSamples;
591631
}
592632

593-
bool zsEncoderImprovedLinkBased::sort(const o2::tpc::Digit a, const o2::tpc::Digit b)
594-
{
595-
// Fixme: this is blasphemy... one shoult precompute all values and sort an index array
596-
int cruinsectora = param.tpcGeometry.GetRegion(a.getRow());
597-
int cruinsectorb = param.tpcGeometry.GetRegion(b.getRow());
598-
if (cruinsectora != cruinsectorb) {
599-
return cruinsectora < cruinsectorb;
600-
}
601-
const auto& mapper = Mapper::instance();
602-
o2::tpc::GlobalPadNumber pada = mapper.globalPadNumber(o2::tpc::PadPos(a.getRow(), a.getPad()));
603-
o2::tpc::GlobalPadNumber padb = mapper.globalPadNumber(o2::tpc::PadPos(b.getRow(), b.getPad()));
604-
o2::tpc::FECInfo feca = mapper.fecInfo(pada);
605-
o2::tpc::FECInfo fecb = mapper.fecInfo(padb);
606-
o2::tpc::CRU cru = cruinsectora;
607-
int fecInPartitiona = feca.getIndex() - mapper.getPartitionInfo(cru.partition()).getSectorFECOffset();
608-
int fecInPartitionb = fecb.getIndex() - mapper.getPartitionInfo(cru.partition()).getSectorFECOffset();
609-
610-
int endpointa = 2 * cruinsectora + (fecInPartitiona >= (mapper.getPartitionInfo(cru.partition()).getNumberOfFECs() + 1) / 2);
611-
int endpointb = 2 * cruinsectorb + (fecInPartitionb >= (mapper.getPartitionInfo(cru.partition()).getNumberOfFECs() + 1) / 2);
612-
if (endpointa != endpointb) {
613-
return endpointa < endpointb;
614-
}
615-
if (a.getTimeStamp() != b.getTimeStamp()) {
616-
return a.getTimeStamp() < b.getTimeStamp();
617-
}
618-
if (fecInPartitiona != fecInPartitionb) {
619-
return fecInPartitiona < fecInPartitionb;
620-
}
621-
return inverseChannelMapping[feca.getSampaChip()][feca.getSampaChannel()] < inverseChannelMapping[fecb.getSampaChip()][fecb.getSampaChannel()];
622-
}
623-
624633
void zsEncoderImprovedLinkBased::decodePage(std::vector<o2::tpc::Digit>& outputBuffer, const zsPage* decPage, unsigned int decEndpoint, unsigned int firstOrbit)
625634
{
626635
const auto& mapper = Mapper::instance();
@@ -697,6 +706,166 @@ void zsEncoderImprovedLinkBased::decodePage(std::vector<o2::tpc::Digit>& outputB
697706
decPagePtr += sizeof(*tbHdr) + tbHdr->numWordsPayload * 16;
698707
}
699708
}
709+
710+
struct zsEncoderDenseLinkBased : public zsEncoderLinkBased {
711+
bool checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, unsigned int k);
712+
unsigned int encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, unsigned int k);
713+
void decodePage(std::vector<o2::tpc::Digit>& outputBuffer, const zsPage* page, unsigned int endpoint, unsigned int firstOrbit);
714+
715+
unsigned char* linkCounter = nullptr;
716+
unsigned char curTimeBin = 0;
717+
};
718+
719+
bool zsEncoderDenseLinkBased::checkInput(std::vector<o2::tpc::Digit>& tmpBuffer, unsigned int k)
720+
{
721+
createBitmask(tmpBuffer, k);
722+
if (tmpBuffer[k].getTimeStamp() - firstTimebinInPage >= (1 << (sizeof(unsigned char) * 8))) {
723+
finishPage = true;
724+
}
725+
if (!finishPage) {
726+
unsigned int sizeChk = (unsigned int)(pagePtr - reinterpret_cast<unsigned char*>(page));
727+
sizeChk += 3 * sizeof(char); // timebin + linkID + linkCounter
728+
sizeChk += 80 / 8; // bitmask
729+
sizeChk += (nSamples * TPCZSHDRV2::TPC_ZS_NBITS_V4 + 7) / 8;
730+
if (sizeChk > TPCZSHDR::TPC_ZS_PAGE_SIZE) {
731+
finishPage = true;
732+
}
733+
}
734+
if (finishPage) {
735+
linkCounter = nullptr;
736+
}
737+
return finishPage;
738+
}
739+
740+
unsigned int zsEncoderDenseLinkBased::encodeSequence(std::vector<o2::tpc::Digit>& tmpBuffer, unsigned int k)
741+
{
742+
unsigned char newTimeBin = tmpBuffer[k].getTimeStamp() - firstTimebinInPage;
743+
if (linkCounter == nullptr || newTimeBin != curTimeBin) {
744+
*((unsigned char*)pagePtr) = newTimeBin;
745+
pagePtr += sizeof(unsigned char);
746+
linkCounter = (unsigned char*)pagePtr;
747+
*linkCounter = 1;
748+
curTimeBin = newTimeBin;
749+
pagePtr += sizeof(unsigned char);
750+
hdr->nTimeBins = tmpBuffer[k].getTimeStamp() - firstTimebinInPage + 1;
751+
hdr->nTimebinHeaders++;
752+
} else {
753+
(*linkCounter)++;
754+
}
755+
unsigned char xlink = link;
756+
int maskLen = 10;
757+
if ((bitmask & std::bitset<80>(0xFFFFFFFFFFlu)).none()) {
758+
xlink |= 0b10000000;
759+
maskLen = 5;
760+
bitmask = bitmask >> 40;
761+
} else if (((bitmask >> 40) & std::bitset<80>(0xFFFFFFFFFFlu)).none()) {
762+
xlink |= 0b01000000;
763+
maskLen = 5;
764+
} else if ((bitmask & std::bitset<80>(0xFFFFFlu)).none() && ((bitmask >> 60) & std::bitset<80>(0xFFFFFlu)).none()) {
765+
xlink |= 0b11000000;
766+
maskLen = 5;
767+
bitmask = bitmask >> 20;
768+
} else if (((bitmask >> 20) & std::bitset<80>(0xFFFFFFFFFFlu)).none()) {
769+
xlink |= 0b00100000;
770+
maskLen = 5;
771+
bitmask = ((bitmask >> 40) & std::bitset<80>(0xFFFFF00000lu)) | (bitmask & std::bitset<80>(0xFFFFFlu));
772+
}
773+
*((unsigned char*)pagePtr) = xlink;
774+
pagePtr += sizeof(unsigned char);
775+
for (int i = maskLen - 1; i >= 0; i--) {
776+
*((unsigned char*)pagePtr) = ((bitmask >> (i * 8)) & std::bitset<80>(0xFF)).to_ulong();
777+
pagePtr += sizeof(unsigned char);
778+
}
779+
unsigned int tmp = 0;
780+
unsigned int tmpIn = nSamples;
781+
ZSstreamOut(adcValues.data(), tmpIn, pagePtr, tmp, encodeBits);
782+
pagePtr += tmp;
783+
return nSamples;
784+
}
785+
786+
void zsEncoderDenseLinkBased::decodePage(std::vector<o2::tpc::Digit>& outputBuffer, const zsPage* decPage, unsigned int decEndpoint, unsigned int firstOrbit)
787+
{
788+
const auto& mapper = Mapper::instance();
789+
const unsigned char* decPagePtr = reinterpret_cast<const unsigned char*>(decPage);
790+
const o2::header::RAWDataHeader* rdh = (const o2::header::RAWDataHeader*)decPagePtr;
791+
if (o2::raw::RDHUtils::getMemorySize(*rdh) == sizeof(o2::header::RAWDataHeader)) {
792+
return;
793+
}
794+
decPagePtr += sizeof(o2::header::RAWDataHeader);
795+
const TPCZSHDRV2* decHDR = reinterpret_cast<const TPCZSHDRV2*>(decPagePtr);
796+
decPagePtr += sizeof(*decHDR);
797+
if (decHDR->version != 4) {
798+
throw std::runtime_error("invalid ZS version");
799+
}
800+
if (decHDR->magicWord != o2::tpc::zerosupp_link_based::CommonHeader::MagicWordLinkZSMetaHeader) {
801+
throw std::runtime_error("Magic word missing");
802+
}
803+
const float decodeBitsFactor = 1.f / (1 << (encodeBits - 10));
804+
unsigned int mask = (1 << encodeBits) - 1;
805+
int cruid = decHDR->cruID;
806+
unsigned int sector = cruid / 10;
807+
if (sector != iSector) {
808+
throw std::runtime_error("invalid TPC sector");
809+
}
810+
int region = cruid % 10;
811+
decPagePtr += decHDR->firstZSDataOffset * 16;
812+
for (unsigned int i = 0; i < decHDR->nTimebinHeaders; i++) {
813+
unsigned char linkTimeBin = *((char*)decPagePtr);
814+
decPagePtr += sizeof(char);
815+
unsigned char linkCount = *((char*)decPagePtr);
816+
decPagePtr += sizeof(char);
817+
for (unsigned int l = 0; l < linkCount; l++) {
818+
unsigned char decLinkX = *((char*)decPagePtr);
819+
unsigned char decLink = decLinkX & 0b00011111;
820+
decPagePtr += sizeof(char);
821+
int maskLen = 10;
822+
if (decLinkX & 0b11100000) {
823+
maskLen = 5;
824+
}
825+
std::bitset<80> bitmask(0);
826+
for (int i = maskLen - 1; i >= 0; i--) {
827+
bitmask |= std::bitset<80>(*((unsigned char*)decPagePtr)) << i * 8;
828+
decPagePtr += sizeof(unsigned char);
829+
}
830+
if (decLinkX & 0b11100000) {
831+
if ((decLinkX & 0b11100000) == 0b10000000) {
832+
bitmask = bitmask << 40;
833+
} else if ((decLinkX & 0b11100000) == 0b01000000) {
834+
// nothing to be done;
835+
} else if ((decLinkX & 0b11100000) == 0b11000000) {
836+
bitmask = bitmask << 20;
837+
} else if ((decLinkX & 0b11100000) == 0b00100000) {
838+
bitmask = ((bitmask & std::bitset<80>(0xFFFFF00000lu)) << 40) | (bitmask & std::bitset<80>(0xFFFFFlu));
839+
}
840+
}
841+
int timeBin = (decHDR->timeOffset + (unsigned long)(o2::raw::RDHUtils::getHeartBeatOrbit(*rdh) - firstOrbit) * o2::constants::lhc::LHCMaxBunches) / LHCBCPERTIMEBIN + linkTimeBin;
842+
const unsigned char* adcData = (const unsigned char*)(decPagePtr);
843+
int nADC = bitmask.count();
844+
decPagePtr += (nADC * TPCZSHDRV2::TPC_ZS_NBITS_V4 + 7) / 8;
845+
std::vector<unsigned short> decBuffer(nADC);
846+
unsigned int byte = 0, bits = 0, posXbits = 0;
847+
while (posXbits < nADC) {
848+
byte |= *(adcData++) << bits;
849+
bits += 8;
850+
while (bits >= encodeBits) {
851+
decBuffer[posXbits++] = byte & mask;
852+
byte = byte >> encodeBits;
853+
bits -= encodeBits;
854+
}
855+
}
856+
for (int j = 0, k = 0; j < bitmask.size(); j++) {
857+
if (bitmask[j]) {
858+
int sampaOnFEC = 0, channelOnSAMPA = 0;
859+
mapper.getSampaAndChannelOnFEC(cruid, j, sampaOnFEC, channelOnSAMPA);
860+
const auto padSecPos = mapper.padSecPos(cruid, decLink, sampaOnFEC, channelOnSAMPA);
861+
const auto& padPos = padSecPos.getPadPos();
862+
outputBuffer.emplace_back(o2::tpc::Digit{0, (float)decBuffer[k++] * decodeBitsFactor, (tpccf::Row)padPos.getRow(), (tpccf::Pad)padPos.getPad(), timeBin});
863+
}
864+
}
865+
}
866+
}
867+
}
868+
700869
#endif // GPUCA_O2_LIB
701870

702871
// ------------------------------------------------- TPC ZS Main Encoder -------------------------------------------------
@@ -935,11 +1104,17 @@ void GPUReconstructionConvert::RunZSEncoder(const S& in, std::unique_ptr<unsigne
9351104
zsEncoderRun<zsEncoderRow> enc{{{.iSector = i, .raw = raw, .ir = ir, .param = param, .padding = padding}}};
9361105
enc.encodeBits = zs12bit ? TPCZSHDR::TPC_ZS_NBITS_V2 : TPCZSHDR::TPC_ZS_NBITS_V1;
9371106
runZS(enc);
938-
} else if (version == 3) {
1107+
} else if (version >= 3 || version <= 4) {
9391108
#ifdef GPUCA_O2_LIB
940-
zsEncoderRun<zsEncoderImprovedLinkBased> enc{{{.iSector = i, .raw = raw, .ir = ir, .param = param, .padding = padding}}};
941-
enc.encodeBits = TPCZSHDRV2::TPC_ZS_NBITS_V3;
942-
runZS(enc);
1109+
if (version == 3) {
1110+
zsEncoderRun<zsEncoderImprovedLinkBased> enc{{{{.iSector = i, .raw = raw, .ir = ir, .param = param, .padding = padding}}}};
1111+
enc.encodeBits = TPCZSHDRV2::TPC_ZS_NBITS_V3;
1112+
runZS(enc);
1113+
} else if (version == 4) {
1114+
zsEncoderRun<zsEncoderDenseLinkBased> enc{{{{.iSector = i, .raw = raw, .ir = ir, .param = param, .padding = padding}}}};
1115+
enc.encodeBits = TPCZSHDRV2::TPC_ZS_NBITS_V4;
1116+
runZS(enc);
1117+
}
9431118
#else
9441119
throw std::runtime_error("Link based ZS encoding not supported in standalone build");
9451120
#endif

0 commit comments

Comments
 (0)