ATLAS Offline Software
Loading...
Searching...
No Matches
ITkPixEncoder.cxx
Go to the documentation of this file.
1/*
2Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5/*EXTERNAL CODE PORTED FROM YARR MINIMALLY ADAPTED FOR ATHENA*/
6
7/*
8* Author: Ondra Kovanda, ondrej.kovanda at cern.ch
9* Date: 03/2024
10* Description: ITkPix* encoding base class
11*/
12
13#include "ITkPixEncoder.h"
15#include <bitset>
16
17//Constructor sets up the geometry for all future loops
18
19ITkPixEncoder::ITkPixEncoder(const bool enableChipID, const unsigned nCol, const unsigned nRow, const unsigned nColInCCol,
20 const unsigned nRowInQRow, const unsigned nEventsPerStream, const bool plainHitMap,
21 const bool dropToT): m_nCol(nCol/nColInCCol), m_nRow(nRow/nRowInQRow),
22 m_nColInCCol(nColInCCol), m_nRowInQRow(nRowInQRow), m_nEventsPerStream(nEventsPerStream), m_enableChipID(enableChipID),
23 m_plainHitMap(plainHitMap), m_dropToT(dropToT){
25 else m_bitsPerWord = 63;
26}
27
28void ITkPixEncoder::addBits64(const uint64_t value, const uint8_t length) const {
29
30 //only called from mutex-protected function
31
32 //This adds 'length' lowest bits to the current block. If the current
33 //block gets filled, push it to the output and start a new block with
34 //the rest of the bits that didn't make it. Need to keep track of the
35 //remaining space in the current word. Also, we only have 63 bits for
36 //the added data, as the first bit is EoS.
37 //Case 1: there's enough space for the entire information to be added
38 if (length <= (m_bitsPerWord - m_currBit)){
39
40 //The position at which the new bits should be inserted into the block
41 //is (length of the block - 1) - (currently last bit) - (length)
42 //We need to keep the first bit for EoS, hence the -1
43 m_currBlock |= (value << (m_bitsPerWord - m_currBit - length));
44 m_currBit += length;
45 return;
46 }
47
48 //Case 2: there's not enough space, so we put what we can, push the block
49 //to the output, and the rest to a new block
50 else {
51
52 //How much space do we have?
53 uint8_t remainingBits = m_bitsPerWord - m_currBit;
54
55 //Add that many bits
56 m_currBlock |= ((value >> (length - remainingBits)));
57
58 //Push the current block to the output and reset it and the current
59 //bit counter. The block needs to be split in 32-bit halves before the output
61
62 //What are we left with?
63 uint8_t leftoverBits = length - remainingBits;
64
65 //Now we can add the remainder
66 //Make sure that the remainder we're adding is really only the bits we've not yet
67 //added, otherwise there can be a rogue "1" in the EoS bit, which was already added
68 //in the previous block
69 addBits64((value & (0xFFFFFFFFFFFFFFFF >> (64 - leftoverBits))), leftoverBits);
70
71 }
72}
73
75 //whenever the current block is ready for output,
76 //split it into two 32-bit words and push them to
77 //the output container. Reset the current bloc/bit
78
79 //only called from mutex-protected function
80 if (m_enableChipID){
81 m_currBlock |= ((0x0ULL | m_chipID) << 61);
82 }
83 uint32_t word1 = m_currBlock >> 32;
84 uint32_t word2 = m_currBlock & 0xFFFFFFFF;
85 m_words.push_back(word1);
86 m_words.push_back(word2);
87 m_currBlock = 0x0ULL;
88 m_currBit = 0;
89}
90
91void ITkPixEncoder::encodeQCore(const unsigned nCCol, const unsigned nQRow) const {
92
93 //only called from mutex-protected function
94
95 //produce hit map and ToTs
96 //First, get the top-left pixel in the QCore
97 unsigned col = nCCol * m_nColInCCol;
98 unsigned row = nQRow * m_nRowInQRow;
99
100 //now loop, store ToTs, and build index of the
101 //compressed hit map in the LUT
102 uint16_t lutIndex = 0x0000;
103 std::vector<uint16_t> tots;
104 tots.reserve(16);
105 int pix = 0;
106 for (unsigned pixRow = row; pixRow < row + m_nRowInQRow; pixRow++){
107 for (unsigned pixCol = col; pixCol < col + m_nColInCCol; pixCol++){
108 if (m_hitMap(pixCol, pixRow)){
109 lutIndex |= 0x1 << pix;
110 tots.push_back(m_hitMap(pixCol, pixRow) - 1);
111 }
112 pix++;
113 }
114 }
115
116 //now add the binary-tree encoded & compressed map
117 //from the LUT to the stream. If, instead, the plain
118 //hit map is requested, add the index (which is the
119 //plain hit map in fact)
121
122 //if dropToT is requested, we can return here
123 if (m_dropToT) return;
124
125 //and add the four-bit ToT information for each hit
126 for (auto& tot : tots){
127 addBits64(tot, 4);
128 }
129}
130
131bool ITkPixEncoder::hitInQCore(const unsigned CCol, const unsigned QRow) const {
132 //Was there a hit in this QCore?
133
134 unsigned col = CCol * m_nColInCCol;
135 unsigned row = QRow * m_nRowInQRow;
136
137 for (unsigned pixRow = row; pixRow < row + m_nRowInQRow; pixRow++){
138 for (unsigned pixCol = col; pixCol < col + m_nColInCCol; pixCol++){
139 if (m_hitMap(pixCol, pixRow)) return true;
140 }
141 }
142
143 return false;
144}
145
147
148 //only called from mutex-protected function
149
150 //Fill in a helper map of hit QCores and a vector of last qrow in each ccol
151 m_hitQCores = std::vector<std::vector<bool>>(m_nCCol, std::vector<bool>(m_nQRow, false));
152 m_lastQRow = std::vector<unsigned> (m_nCCol, 0);
153
154 for (unsigned CCol = 0; CCol < m_nCCol; CCol++){
155 for (unsigned QRow = 0; QRow < m_nQRow; QRow++){
156 //if there's a hit in the qcore, flag the helper map
157 m_hitQCores[CCol][QRow] = hitInQCore(CCol, QRow);
158
159 //and keep track of the last qrow in each CCol, so that we can
160 //easily set the isLast bit. Numbering starts at 1, in order to
161 //keep the m_lastQRow[CCol] == 0 case denoting "no hit" in the CCol
162 //to save some looping/ifs later on
163 if (m_hitQCores[CCol][QRow]) m_lastQRow[CCol] = QRow + 1;
164 }
165 }
166
167}
168
170
171 //only called from mutex-protected function
172
173 //This produces the bits for one event.
174 //First, scan the map and produce helpers
175 scanHitMap();
176
177 for (unsigned CCol = 0; CCol < m_nCCol; CCol++){
178 //if there are no hits in this CCol, continue
179 if (m_lastQRow[CCol] == 0) continue;
180 //add the 6-bit (CCol + 1) address
181 addBits64(CCol + 1, 6);
182
183 int previousQRow = -666;
184 for (unsigned QRow = 0; QRow < m_nQRow; QRow++){
185 //if there's no hit in this row, continue
186 if (!m_hitQCores[CCol][QRow]) continue;
187
188 //add the isLast bit
189 QRow + 1 == m_lastQRow[CCol] ? addBits64(0x1, 1) : addBits64(0x0, 1);
190
191 //add the isNeighbor bit. If false, add the QRow address as well.
192 if (QRow == (uint)previousQRow + 1){
193 addBits64(0x1, 1);
194 }
195 else {
196 addBits64(0x0, 1);
197 addBits64(QRow, 8);
198 };
199
200 //add the map and ToT
201 encodeQCore(CCol, QRow);
202
203 //update the previous QRow
204 previousQRow = QRow;
205 }
206 }
207}
208
209void ITkPixEncoder::streamTag(const uint8_t nStream) const {
210
211 //only called from mutex-protected function
212
213 //this adds the 8-bit 'global' stream tag
214 addBits64(nStream, 8);
215}
216
217void ITkPixEncoder::intTag(const uint16_t nEvt) const {
218
219 //only called from mutex-protected function
220
221 //this adds 11 bits of interal tagging between events.
222 //does the tag always need to start with 111?
223 uint16_t tag = nEvt | (0b111 << 8);
224 addBits64(tag, 11);
225}
226
227void ITkPixEncoder::setChipID(const uint8_t& chipID){
228 m_chipID = chipID;
229}
230
232 std::lock_guard<std::mutex> lock(m_mutex);
233 m_words.clear();
234}
double length(const pvec &v)
unsigned int uint
void pushWords32() const
unsigned m_nCol
size_t m_bitsPerWord
void encodeQCore(const unsigned nCCol, const unsigned nQRow) const
unsigned m_nRowInQRow
void scanHitMap() const
void encodeEvent() const
bool hitInQCore(const unsigned CCol, const unsigned QRow) const
unsigned m_nQRow
unsigned m_nCCol
void addBits64(const uint64_t value, const uint8_t length) const
std::mutex m_mutex
unsigned m_nColInCCol
void streamTag(const uint8_t nStream) const
unsigned m_nEventsPerStream
void setChipID(const uint8_t &chipID)
void clear() const
unsigned m_nRow
ITkPixEncoder(const bool enableChipID=true, const unsigned nCol=400, const unsigned nRow=384, const unsigned nColInCCol=8, const unsigned nRowInQRow=2, const unsigned nEventsPerStream=16, const bool plainHitMap=false, const bool dropToT=false)
void intTag(const uint16_t nEvt) const
constexpr std::array< uint32_t, LookUpTableSize > ITkPixV2QCoreEncodingLUT_Length
constexpr std::array< uint32_t, LookUpTableSize > ITkPixV2QCoreEncodingLUT_Tree