ATLAS Offline Software
Loading...
Searching...
No Matches
SCT_RodEncoder.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "SCT_RodEncoder.h"
6
8
14
15#include "Identifier/Identifier.h"
17
18namespace { // Anonymous namespace
19 int rodLinkFromOnlineID(const SCT_OnlineId onlineID)
20 {
21 const uint32_t fibre{onlineID.fibre()};
22 const int formatter{static_cast<int>((fibre/12) & 0x7)};
23 const int linkNum{static_cast<int>((fibre - (formatter*12)) & 0xF)};
24 const int rodLink{(formatter << 4) | linkNum};
25 return rodLink;
26 }
27 bool isOdd(const int someNumber)
28 {
29 return static_cast<bool>(someNumber & 1);
30 }
31
32 bool isEven(const int someNumber)
33 {
34 return not isOdd(someNumber);
35 }
36
37 bool swappedCable(const int moduleSide, const int linkNumber)
38 {
39 return isOdd(linkNumber) ? (moduleSide==0) : (moduleSide==1);
40 }
41} // End of anonymous namespace
42
43// Constructor
44
45SCT_RodEncoder::SCT_RodEncoder(const std::string& type, const std::string& name,
46 const IInterface* parent) :
47 base_class(type, name, parent)
48{
49}
50
51// Initialize
52
54{
55 ATH_MSG_DEBUG("SCT_RodEncoder::initialize()");
56
57 // Retrieve cabling tool
58 ATH_CHECK(m_cabling.retrieve());
59 ATH_MSG_DEBUG("Retrieved tool " << m_cabling);
60
61 ATH_CHECK(detStore()->retrieve(m_sctID, "SCT_ID"));
62 ATH_CHECK(m_bsErrTool.retrieve());
63
64 // See if strip numbers go from 0 to 767 or vice versa for all the wafers.
65 // swapPhiReadoutDirection will not change during a run.
66 // Since this is access to SiDetectorElement during initialization,
67 // condition object of SiDetectorElementCollection is not accessible.
68 // SCT_DetectorManager has to be used.
69 const InDetDD::SCT_DetectorManager* sctDetManager{nullptr};
70 ATH_CHECK(detStore()->retrieve(sctDetManager, "SCT"));
71
72 const InDetDD::SiDetectorElementCollection* sctDetElementColl{sctDetManager->getDetectorElementCollection()};
73 for (const InDetDD::SiDetectorElement* sctDetElement : *sctDetElementColl) {
74 if (sctDetElement->swapPhiReadoutDirection()) {
75 m_swapModuleID.insert(sctDetElement->identify());
76 }
77 }
78
79 return StatusCode::SUCCESS;
80}
81
82// Finalize
83
85{
86 return StatusCode::SUCCESS;
87}
88
89// fillROD method
90
91void SCT_RodEncoder::fillROD(std::vector<uint32_t>& vec32Data, const uint32_t& robID,
92 const std::vector<const SCT_RDORawData*>& vecRDOs) const
93{
94 // Retrieve errors from SCT_ByteStreamErrorsSvc
95 const EventContext& ctx{Gaudi::Hive::currentContext()};
96 const std::set<IdentifierHash> timeOutErrors{m_bsErrTool->getErrorSet(SCT_ByteStreamErrors::TimeOutError,ctx)};
97 const std::set<IdentifierHash> lvl1IDErrors{m_bsErrTool->getErrorSet(SCT_ByteStreamErrors::LVL1IDError,ctx)};
98 const std::set<IdentifierHash> bcIDErrors{m_bsErrTool->getErrorSet(SCT_ByteStreamErrors::BCIDError,ctx)};
99 const std::set<IdentifierHash> preambleErrors{m_bsErrTool->getErrorSet(SCT_ByteStreamErrors::PreambleError,ctx)};
100 const std::set<IdentifierHash> formatterErrors{m_bsErrTool->getErrorSet(SCT_ByteStreamErrors::FormatterError,ctx)};
101 const std::set<IdentifierHash> trailerErrors{m_bsErrTool->getErrorSet(SCT_ByteStreamErrors::TrailerError,ctx)};
102 const std::set<IdentifierHash> headerTrailerErrors{m_bsErrTool->getErrorSet(SCT_ByteStreamErrors::HeaderTrailerLimitError,ctx)};
103 const std::set<IdentifierHash> trailerOverflowErrors{m_bsErrTool->getErrorSet(SCT_ByteStreamErrors::TrailerOverflowError,ctx)};
104 const std::set<IdentifierHash> abcdErrors{m_bsErrTool->getErrorSet(SCT_ByteStreamErrors::ABCDError,ctx)};
105 const std::set<IdentifierHash> rawErrors{m_bsErrTool->getErrorSet(SCT_ByteStreamErrors::RawError,ctx)};
106
107 std::vector<uint16_t> vec16Data;
108
109 // Loop over errors here - just add headers (w/ errors), trailers (w/errors), and raw and abcd errors
110 addHeadersWithErrors(robID, &timeOutErrors, TIMEOUT_ERR, vec16Data);
111 addHeadersWithErrors(robID, &lvl1IDErrors, L1_ERR, vec16Data);
112 addHeadersWithErrors(robID, &bcIDErrors, BCID_ERR, vec16Data);
113 addHeadersWithErrors(robID, &preambleErrors, PREAMBLE_ERR, vec16Data);
114 addHeadersWithErrors(robID, &formatterErrors, FORMATTER_ERR, vec16Data);
115
116 addTrailersWithErrors(robID, &trailerErrors, TRAILER_ERR, vec16Data);
117 addTrailersWithErrors(robID, &headerTrailerErrors, HEADER_TRAILER_ERR, vec16Data);
118 addTrailersWithErrors(robID, &trailerOverflowErrors, TRAILER_OVFLW_ERR, vec16Data);
119
120 addSpecificErrors(robID, &abcdErrors, ABCD_ERR, vec16Data);
121 addSpecificErrors(robID, &rawErrors, RAWDATA_ERR, vec16Data);
122
123 std::vector<bool> vec_isDuplicated(vecRDOs.size(), false);
124
125 // Loop over RDOs to check for duplicates and fill vec_isDuplicated vector
126 for (unsigned int iRDO1{0}; iRDO1<vecRDOs.size(); iRDO1++) {
127 const SCT_RDORawData* rdo1{vecRDOs.at(iRDO1)};
128 if (rdo1 == nullptr) {
129 ATH_MSG_ERROR("RDO pointer is nullptr. skipping this hit.");
130 vec_isDuplicated.at(iRDO1) = true;
131 continue;
132 }
133
134 // Check if there is another RDO with the same first strip
135 for (unsigned int iRDO2{0}; iRDO2<iRDO1; iRDO2++) {
136 const SCT_RDORawData* rdo2{vecRDOs.at(iRDO2)};
137 if (vec_isDuplicated.at(iRDO2)) continue;
138
139 if (rdo1->identify() == rdo2->identify()) {
140 // Keep RDO with larger cluster size. If cluster sizes are the same, keep the first one.
141 if (rdo1->getGroupSize() >= rdo2->getGroupSize()) {
142 vec_isDuplicated.at(iRDO2) = true;
143 }
144 else {
145 vec_isDuplicated.at(iRDO1) = true;
146 }
147 break;
148 }
149 }
150 }
151
152 std::vector<int> vecTimeBins;
153 int strip{0};
154 int timeBin{0};
155 int groupSize{0};
156
157 uint32_t lastHeader{0};
158 bool firstInROD{true};
159 uint16_t lastTrailer{0};
160
161 // Loop over RDOs to decode to 16 bit words
162 for (unsigned int iRDO{0}; iRDO<vecRDOs.size(); iRDO++) {
163 const SCT_RDORawData* rdo{vecRDOs.at(iRDO)};
164 if (vec_isDuplicated.at(iRDO)) continue;
165
166 const uint16_t header{this->getHeaderUsingRDO(rdo)};
167 if (header != lastHeader) {
168 if (not firstInROD) {
169 vec16Data.push_back(lastTrailer);
170 }
171 firstInROD = false;
172 vec16Data.push_back(header);
173 lastHeader = header;
174 lastTrailer = getTrailer(0);
175 }
176 if (m_condensed.value()) { // Condensed mode
177 strip = getStrip(rdo);
178 groupSize = rdo->getGroupSize();
179 if (groupSize == 1) { // For single hit
180 const int constGroupSize{1};
181 const int constStrip{strip};
182 encodeData(vecTimeBins, vec16Data, rdo, constGroupSize, constStrip);
183 }
184 // Sim RDO could have groupe size > 1, then they are split 2 by 2 to built the condensed BS data.
185 else { // Encoding in condensed BS paired data from groupe size > 1.
186 const int chipFirst{strip/128};
187 const int chipLast{(strip+groupSize-1)/128};
188
189 for (int chip{chipFirst}; chip<=chipLast; chip++) {
190 int tmpGroupSize = 0;
191 if (chipFirst == chipLast) tmpGroupSize = groupSize; // In case of one chip
192 else if (chip == chipLast) tmpGroupSize = strip+groupSize-chip*128; // In case of last chip
193 else if (chip == chipFirst) tmpGroupSize = (chip+1)*128-strip; // In case of first chip
194 else tmpGroupSize = 128; // In case of middle chip
195 const int tmpStrip1{chip==chipFirst ? strip : 128*chip};
196
197 const int numPairedRDO{tmpGroupSize/2};
198 for (int i =0; i<numPairedRDO; i++) {
199 const int constGroupSize{2};
200 const int constStrip{tmpStrip1+ (2*i)};
201 encodeData(vecTimeBins, vec16Data, rdo, constGroupSize, constStrip);
202 }
203 if ((tmpGroupSize != 0) and isOdd(tmpGroupSize)) {// The last hit from a cluster with odd group size
204 const int constGroupSize{1};
205 const int constStrip{tmpStrip1+ (tmpGroupSize - 1)};
206 encodeData(vecTimeBins, vec16Data, rdo, constGroupSize, constStrip);
207 }
208 }
209 }
210
211 } // End of Condensed mode
212
213 else { // Expanded mode
214 vecTimeBins.clear();
215 const SCT_RDORawData* rdo{vecRDOs.at(iRDO)};
216 //coverity[UNUSED_VALUE:FALSE]
217 strip = getStrip(rdo);
218 timeBin = getTimeBin(rdo);
219 groupSize = rdo->getGroupSize();
220
221 for (int t{0}; t < groupSize; t++) {
222 vecTimeBins.push_back(timeBin);
223 strip++;
224 }
225 const int constStrip{getStrip(rdo)};
226 const int constGroupSize{rdo->getGroupSize()};
227 encodeData(vecTimeBins, vec16Data, rdo, constGroupSize, constStrip);
228
229 } // End of Expanded mode
230 } // End of RDO decode loop
231
232 if ((not firstInROD) and (lastTrailer != 0)) {
233 vec16Data.push_back(lastTrailer);
234 }
235
236 // 16 bits TO 32 bits and pack into 32 bit vectors
237 packFragments(vec16Data,vec32Data);
238
239 return;
240}
241
242// encodeData method
243
244void SCT_RodEncoder::encodeData(const std::vector<int>& vecTimeBins, std::vector<uint16_t>& vec16Words,
245 const SCT_RDORawData* rdo, const int& groupSize, const int& strip) const
246{
247 const int encodedSide{side(rdo) << 14};
248
249 const Identifier idColl{offlineID(rdo)};
250 int tmpStrip{strip};
251 if (m_swapModuleID.find(idColl) != m_swapModuleID.end()) { // Check if the strip has to be swapped (swap phi readout direction)
252 tmpStrip= 767 - tmpStrip;
253 tmpStrip= tmpStrip-(groupSize-1);
254 }
255
256 const int chipNum{((tmpStrip/128) & 0x7) << 11};
257 const int clustBaseAddr{((tmpStrip-(chipNum*128)) & 0x7F) << 4};
258
259 int timeBin{0};
260 int firstHitErr{0 << 2};
261 int secondHitErr{0 << 3};
262
263 const SCT3_RawData* rdoCosmic{dynamic_cast<const SCT3_RawData*>(rdo)};
264 if (rdoCosmic != nullptr) {
265 timeBin = getTimeBin(rdoCosmic);
266 firstHitErr = ((rdoCosmic)->FirstHitError()) << 2;
267 secondHitErr = ((rdoCosmic)->SecondHitError()) << 3;
268 }
269
270 if (m_condensed.value()) { // Condensed mode
271 if (groupSize == 1) { // For single hit
272 const uint16_t hitCondSingle{static_cast<uint16_t>(0x8000 | encodedSide | chipNum | clustBaseAddr | firstHitErr)};
273 vec16Words.push_back(hitCondSingle);
274 }
275 else if (groupSize == 2) { // For paired strip Hits
276 const uint16_t hitCondPaired{static_cast<uint16_t>(0x8001 | encodedSide | chipNum | clustBaseAddr | secondHitErr | firstHitErr)};
277 vec16Words.push_back(hitCondPaired);
278 }
279 } // End of Condensed mode
280
281 else { // Expanded mode
282 const int numEven{static_cast<int>((vecTimeBins.size() - 1)/2)};
283
284 // First hit
285 const uint16_t hitExpFirst{static_cast<uint16_t>(0x8000 | encodedSide | chipNum | clustBaseAddr | timeBin)};
286 vec16Words.push_back(hitExpFirst);
287
288 // Even consecutive strips to the first one 1DDD 1st consec strip 1DDD 2nd consec strip
289 for (int i{1}; i<=numEven; i++) {
290 const uint16_t hitExpEven{static_cast<uint16_t>(0x8088 | ((vecTimeBins[(2*i-1)] & 0xF) << 4) | (vecTimeBins[2*i] & 0xF))};
291 vec16Words.push_back(hitExpEven);
292 }
293 // Last bin of the Odd next hits
294 if ((not vecTimeBins.empty()) and isEven(vecTimeBins.size())) {
295 const uint16_t hitExpLast{static_cast<uint16_t>(0x8008 | (vecTimeBins[vecTimeBins.size()-1] & 0xF))};
296 vec16Words.push_back(hitExpLast);
297 }
298 } // End of Expanded mode
299
300 return;
301}
302
303// packFragments function
304
305void SCT_RodEncoder::packFragments(std::vector<uint16_t>& vec16Words,
306 std::vector<uint32_t>& vec32Words) const
307{
308 int num16Words{static_cast<int>(vec16Words.size())};
309 if (isOdd(num16Words)) {
310 // Just add an additional 16bit words to make even size v16 to in the 32 bits word 0x40004000
311 vec16Words.push_back(0x4000);
312 num16Words++;
313 }
314 // Now merge 2 consecutive 16 bit words in 32 bit words
315 const unsigned short int numWords{2};
316 const unsigned short int position[numWords]{0, 16};
317 unsigned short int arr16Words[numWords]{0, 0};
318 for (int i{0}; i<num16Words; i += numWords) {
319 arr16Words[i%numWords] = vec16Words[i+1];
320 arr16Words[(i+1)%numWords] = vec16Words[i];
321 const uint32_t uint32Word{set32Bits(arr16Words, position, numWords)};
322 vec32Words.push_back(uint32Word);
323#ifdef SCT_DEBUG
324 ATH_MSG_INFO("SCT encoder -> PackFragments: Output rod 0x"<<std::hex<<uint32Word<<std::dec);
325#endif
326 }
327
328 return;
329}
330
331// set32Bits function
332
333uint32_t SCT_RodEncoder::set32Bits(const unsigned short int* arr16Words,
334 const unsigned short int* position,
335 const unsigned short int& numWords) const
336{
337 uint32_t uint32Word{0};
338 uint32_t pos{0};
339 uint32_t uint16Word{0};
340 for (uint16_t i{0}; i<numWords; i++) {
341 uint16Word = static_cast<uint32_t>(*(arr16Words+i));
342 pos = static_cast<uint32_t>(*(position+i));
343 uint32Word |= (uint16Word<<pos);
344 }
345 return uint32Word;
346}
347
348// Get RDO info functions
349
351{
352 const Identifier rdoID{rdo->identify()};
353 return m_sctID->strip(rdoID);
354}
355
357{
358 const Identifier rdoId{rdo->identify()};
359 return m_sctID->wafer_id(rdoId);
360}
361
362uint32_t SCT_RodEncoder::onlineID(const SCT_RDORawData* rdo) const
363{
364 const Identifier waferID{offlineID(rdo)};
365 const IdentifierHash offlineIDHash{m_sctID->wafer_hash(waferID)};
366 return static_cast<uint32_t>(m_cabling->getOnlineIdFromHash(offlineIDHash));
367}
368
370{
371 return rodLinkFromOnlineID(onlineID(rdo));
372}
373
375{
376 const Identifier rdoID{rdo->identify()};
377 int sctSide{m_sctID->side(rdoID)};
378 // see if we need to swap sides due to cabling weirdness
379 const int linkNum{getRODLink(rdo) & 0xF};
380 if (swappedCable(sctSide,linkNum)) sctSide = 1-sctSide;
381 return sctSide;
382}
383
385{
386 int timeBin{0};
387 const SCT3_RawData* rdoCosmic{dynamic_cast<const SCT3_RawData*>(rdo)};
388 if (rdoCosmic != nullptr) timeBin = rdoCosmic->getTimeBin();
389 return timeBin;
390}
391
392// Get headers and trailer functions
393
395{
396 const int rodLink{getRODLink(rdo)};
397 const uint16_t linkHeader{static_cast<uint16_t>(0x2000 | (m_condensed.value() << 8) | rodLink)};
398 return linkHeader;
399}
400
401uint16_t SCT_RodEncoder::getHeaderUsingHash(const IdentifierHash& linkHash, const int& errorWord) const
402{
403 const int rodLink{rodLinkFromOnlineID(m_cabling->getOnlineIdFromHash(linkHash))};
404 const uint16_t linkHeader{static_cast<uint16_t>(0x2000 | errorWord | (m_condensed.value() << 8) | rodLink)};
405 return linkHeader;
406}
407
408uint16_t SCT_RodEncoder::getTrailer(const int& errorWord) const
409{
410 const uint16_t linkTrailer{static_cast<uint16_t>(0x4000 | errorWord)};
411 return linkTrailer;
412}
413
414// Add errors functions
415
416void SCT_RodEncoder::addHeadersWithErrors(const uint32_t& robID, const std::set<IdentifierHash>* errors,
417 const ErrorWords& errType, std::vector<uint16_t>& vec16Data) const
418{
419 for (const IdentifierHash& linkHash: *errors) {
420 const uint32_t errROBID{m_cabling->getRobIdFromHash(linkHash)};
421 if (errROBID == robID) {
422 const uint16_t header{getHeaderUsingHash(linkHash, errType)};
423 vec16Data.push_back(header);
424 const uint16_t trailer{getTrailer(NULL_TRAILER_ERR)};
425 vec16Data.push_back(trailer);
426 }
427 }
428}
429
430//
431void SCT_RodEncoder::addTrailersWithErrors(const uint32_t& robID, const std::set<IdentifierHash>* errors,
432 const ErrorWords& errType, std::vector<uint16_t>& vec16Data) const
433{
434 for (const IdentifierHash& linkHash: *errors) {
435 const uint32_t errROBID{m_cabling->getRobIdFromHash(linkHash)};
436 if (errROBID == robID) {
437 const uint16_t header{getHeaderUsingHash(linkHash, NULL_HEADER_ERR)};
438 const uint16_t trailer{getTrailer(errType)};
439 vec16Data.push_back(header);
440 vec16Data.push_back(trailer);
441 }
442 }
443}
444
445void SCT_RodEncoder::addSpecificErrors(const uint32_t& robID, const std::set<IdentifierHash>* errors,
446 const ErrorWords& errType, std::vector<uint16_t>& vec16Data) const
447{
448 for (const IdentifierHash& linkHash: *errors) {
449 const uint32_t errROBID{m_cabling->getRobIdFromHash(linkHash)};
450 if (errROBID == robID) {
451 const uint16_t header{getHeaderUsingHash(linkHash, NULL_HEADER_ERR)};
452 const uint16_t trailer{getTrailer(NULL_TRAILER_ERR)};
453 vec16Data.push_back(header);
454 vec16Data.push_back(errType);
455 vec16Data.push_back(trailer);
456 }
457 }
458}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
Header file for abstract interface to SCT cabling tool.
This is an Identifier helper class for the SCT subdetector.
This is a "hash" representation of an Identifier.
Dedicated detector manager extending the functionality of the SiDetectorManager with dedicated SCT in...
virtual const SiDetectorElementCollection * getDetectorElementCollection() const override
access to whole collectiom
Class to hold the SiDetectorElement objects to be put in the detector store.
Class to hold geometrical description of a silicon detector element.
virtual Identifier identify() const override final
int getTimeBin() const
SCT_OnlineId is a class to hold an online id number and provide check on validity,...
std::uint32_t fibre() const
Return the fibre.
virtual int getGroupSize() const =0
virtual StatusCode finalize() override
Finalize.
void encodeData(const std::vector< int > &vecTimeBins, std::vector< uint16_t > &vec16Words, const SCT_RDORawData *rdo, const int &groupSize, const int &strip) const
Method to encode RDO data to vector of 16 bin words.
uint16_t getTrailer(const int &errorWord) const
Get the 16-bit word for a trailer, with or without ByteStream errors.
ErrorWords
Definitions of enum error words to be retrieved from SCT_ByteStreamErrorSvc in fillROD(....
ToolHandle< ISCT_ByteStreamErrorsTool > m_bsErrTool
Tool that keeps track of modules that give rise to errors in the bytestream.
SCT_RodEncoder(const std::string &type, const std::string &name, const IInterface *parent)
Constructor.
void addTrailersWithErrors(const uint32_t &robID, const std::set< IdentifierHash > *errors, const ErrorWords &errType, std::vector< uint16_t > &vec16Data) const
Add trailers with errors for ROB to the vector of 16 bit words.
virtual void fillROD(std::vector< uint32_t > &vec32Data, const uint32_t &robID, const std::vector< const SCT_RDORawData * > &vecRDOs) const override
Main Convert method.
const SCT_ID * m_sctID
Identifier helper class for the SCT subdetector that creates compact Identifier objects and Identifie...
uint32_t set32Bits(const unsigned short int *arr16Words, const unsigned short int *position, const unsigned short int &numWords) const
@breif Method to set pairs of 16 bit words to a 32 bit word.
void packFragments(std::vector< uint16_t > &vec16Words, std::vector< uint32_t > &vec32Words) const
Method to pack vector of 16 bit words intto a vector of 32 bit words.
ToolHandle< ISCT_CablingTool > m_cabling
Providing mappings of online and offline identifiers and also serial numbers.
BooleanProperty m_condensed
Boolean used to determine if fillROD(...) should use Condensed or Expanded mode when decoding.
std::set< Identifier > m_swapModuleID
Swap Module identifier, set by SCTRawContByteStreamTool.
int getRODLink(const SCT_RDORawData *rdo) const
Get the ROD link number info in the RDO header data.
int side(const SCT_RDORawData *rdo) const
Get the side info from the RDO.
virtual StatusCode initialize() override
Initialize.
uint16_t getHeaderUsingHash(const IdentifierHash &linkHash, const int &errorWord) const
Get the 16-bit word for a header for a link with a ByteStream error.
uint32_t onlineID(const SCT_RDORawData *rdo) const
Get the online Identifier from the RDO.
uint16_t getHeaderUsingRDO(const SCT_RDORawData *rdo) const
Get the 16-bit word for a header for a hit.
void addSpecificErrors(const uint32_t &robID, const std::set< IdentifierHash > *errors, const ErrorWords &errType, std::vector< uint16_t > &vec16Data) const
Add specific errors for ROB to the vector of 16 bit words.
void addHeadersWithErrors(const uint32_t &robID, const std::set< IdentifierHash > *errors, const ErrorWords &errType, std::vector< uint16_t > &vec16Data) const
Add header with errors for ROB to the vector of 16 bit words.
int getStrip(const SCT_RDORawData *rdo) const
Get the strip number info from the RDO.
int getTimeBin(const SCT_RDORawData *rdo) const
Get the time bin info from the RDO.
Identifier offlineID(const SCT_RDORawData *rdo) const
Get the offline Identifier from the RDO.
setEventNumber uint32_t