@@ -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-
562602unsigned 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-
624633void 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