ATLAS Offline Software
Loading...
Searching...
No Matches
ITkPixelDecodingAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
7#include "eformat/ROBFragment.h"
8
9#define ENABLE_TIMING = true;
10#ifdef ENABLE_TIMING
11#define SCOPED_TIMER(name, msg) ITkPixelDecoding::ScopedTimer timer_##__LINE__(name, msg)
12#else
13#define SCOPED_TIMER(name, msg)
14#endif
15
16
17using namespace itksw::pix::endec;
18
19ITkPixelDecodingAlg::ITkPixelDecodingAlg(const std::string& name, ISvcLocator* pSvcLocator) :
20 AthReentrantAlgorithm(name, pSvcLocator)
21{
22
23}
24
25
27{
29
30 ATH_CHECK(m_pixelCablingKey.initialize());
31
32 ATH_CHECK(detStore()->retrieve(m_idHelper, "PixelID"));
33
34 ATH_CHECK(m_pixelRDOKey.initialize());
35
36 //this should go into the cabling likely...
37 for (size_t hash = 0; hash < m_idHelper->wafer_hash_max(); hash++){
38 m_sourceIDs.push_back(m_idHelper->wafer_id(hash).get_identifier32().get_compact() | 0b00 );
39 m_sourceIDs.push_back(m_idHelper->wafer_id(hash).get_identifier32().get_compact() | 0b10 );
40 m_sourceIDs.push_back(m_idHelper->wafer_id(hash).get_identifier32().get_compact() | 0b01 );
41 m_sourceIDs.push_back(m_idHelper->wafer_id(hash).get_identifier32().get_compact() | 0b11 );
42 }
43
44 return StatusCode::SUCCESS;
45}
46
47StatusCode ITkPixelDecodingAlg::execute(const EventContext& ctx) const
48{
49 //Timing
50 SCOPED_TIMER("ITkPixelDecodingAlg::execute", msg());
51
52 //Retrieve the ROB IDs from cabling - dummy as of now, happens in initialize()
54 const ITkPixelCablingData* cabling = *cablingData;
55
56 //Instantiate the output. RN using the old pixel RDO, nothing fancier than that
57 std::unique_ptr<PixelRDO_Container> rdoCont = std::make_unique<PixelRDO_Container>(m_idHelper->wafer_hash_max());
58
59 //Instantiate the decoder. Doing this once per event is fine and MT-safe
60 //It needs a "callback" that implements methods required by concepts. This is
61 //the drawback of using an external code (by ITk online sw). Each of these methods
62 //is then called at appropriate places in the decoding. The decoder is configured
63 //with data format options. The callback can do whatever with the decoded hits
64 //e. g. print them on the screen or put them in a container as RDOs.
65 DataFormat fmt;
66 fmt.options.en_chip_id = true;
67 fmt.options.en_eos = true;
68 PixelCallbacks::RDOCallback cb(rdoCont.get(), m_idHelper, msg());
69 DecCore<PixelCallbacks::RDOCallback> core(fmt, cb);
70
71 //Invoke ROBDataProviderService, fetch the concerned ROBs.
72 std::vector<const eformat::ROBFragment<const uint32_t*>*> ROBs;
73 m_robDataProviderSvc->getROBData(ctx, cabling->sourceIDs(), ROBs);
74 ATH_MSG_DEBUG("Retrieved " << ROBs.size() << " fragments");
75
76 //The ROB/ROD payload contains a chain of [FE header 0] [FE data 0] ... [FE header N] [FE data N]
77 //we need to sort these header-data pairs in each ROB payload according to the module ID to
78 //fill each module exactly once.
79 //from the GBT fragment building algorithm documentation (https://gitlab.cern.ch/atlas-tdaq-software/swrod#gbt-fragment-building-algorithm)
80 // "size: 16-bit value that contains a total size (in 4-byte words) of the data packet including the size of the header itself."
81 //i. e. the first 16 bits of the first word allow us to identify where the next FE starts, etc. We can jump once through
82 //the payload to separate the FE data and store the moduleID, {start idx, size} map, sort according to the key and then
83 //read in that order from the underlying array without copying.
84
85
86 //We can now loop over the payloads of the ROB fragments retrieved earlier.
87 //There's as of now a little annoyance that the decoder eats 64 bit frames
88 //but the ROBs come in 32 bits. At least they have the same endian polarity.
89 //Nevertheless, we need to rearrange them.
90
91 for (const auto& ROB : ROBs){
92 //This loops over ROB fragments identified by sourceID
93
94 //First, get the payload that contains the above-mentioned GBT fragment structure
95 const uint32_t* payload = ROB->rod_data();
96 uint32_t length = ROB->rod_ndata();
97
98 //now starting from the 0th word, map out the GBT fragment beginnings
99 //the map needs to be sorted by the low bits of detectorResourceID
100 auto comp = [](const uint32_t& a, const uint32_t& b){
101 uint32_t aLSB = a & 0x00FFFFFF;
102 uint32_t bLSB = b & 0x00FFFFFF;
103 if (aLSB != bLSB) return aLSB < bLSB;
104 return a < b;
105 };
106
107 std::map<uint32_t, std::pair<size_t, uint16_t>, decltype(comp)> GBTFragments(comp);
108
109 size_t idx = 0;
110 while (idx < length){
111 uint16_t GBTFragmentSize = (payload[idx] & 0xFFFF0000) >> 16;
112 uint32_t detectorResourceID = payload[idx + 1];
113 //this is where we want to map detectorResourceID on trueDetectorResourceID
114 GBTFragments.insert({detectorResourceID, {idx, GBTFragmentSize}});
115 idx += GBTFragmentSize;
116 }
117
118 //at this point the GBT fragments are sorted by the moduleID, so they can
119 //be added to the EDM (each module can be filled once). Before sorting,
120 //it could in principle happen that two chips from module A would have
121 //a GBT fragment from a chip belonging to module B in between.
122
123 //Now we can loop over the sorted chips and fill them, always changing
124 //the module we're currently dealing with
125
126 uint32_t moduleID = 0xFFFFFFFF;
127 for (const auto& [detectorResourceID, range] : GBTFragments){
128
129 //are we still filling the same module?
130 uint32_t currentModuleID = ITkPixelCabling::dridToModuleID(detectorResourceID);
131 if (moduleID != currentModuleID){
132 moduleID = currentModuleID;
133 cb.setOfflineID(currentModuleID);
134 cb.setTransformType(cabling->transformType(currentModuleID));
135 }
136 cb.setChipID(ITkPixelCabling::dridToChipID(detectorResourceID));
137
138 //Translate the data into 64 bits. We know the length, so we can reserve
139 //the space to avoid reallocation. Since the frames are always 64 bits split
140 //into 32, they'll always be divisible by 2 without modulo. First 2 words are
141 //the GBT fragment header, hence range.first + 2
142 std::vector<uint64_t> payload64;
143 payload64.resize((range.second - 2) / 2);
144 size_t payloadIdx = 0;
145 for (uint32_t word = range.first + 2; word < range.first + range.second; word += 2){
146 payload64[payloadIdx] = ((uint64_t)(payload[word]) << 32) | payload[word + 1];
147 payloadIdx++;
148 }
149
150 //Decode!
151 core.initialize();
152 core.decode(payload64);
153 core.finalize();
154
155 }
156
157 }
158
159 //The container is filled by now. We can write it to SG
160 SG::WriteHandle<PixelRDO_Container> pixelRDOContainerHandle(m_pixelRDOKey, ctx);
161 ATH_CHECK(pixelRDOContainerHandle.record(std::move(rdoCont)));
162
163 return StatusCode::SUCCESS;
164}
165
167 return StatusCode::SUCCESS;
168}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
double length(const pvec &v)
#define SCOPED_TIMER(name, msg)
static Double_t a
Handle class for reading from StoreGate.
const char *const fmt
const ServiceHandle< StoreGateSvc > & detStore() const
An algorithm that can be simultaneously executed in multiple threads.
virtual StatusCode initialize() override
ServiceHandle< IROBDataProviderSvc > m_robDataProviderSvc
std::vector< uint32_t > m_sourceIDs
virtual StatusCode finalize() override
virtual StatusCode execute(const EventContext &ctx) const override
SG::WriteHandleKey< PixelRDO_Container > m_pixelRDOKey
const PixelID * m_idHelper
SG::ReadCondHandleKey< ITkPixelCablingData > m_pixelCablingKey
ITkPixelDecodingAlg(const std::string &name, ISvcLocator *pSvcLocator)
void setChipID(const uint8_t &chipID)
void setOfflineID(const uint32_t &offlineID)
void setTransformType(const ITkPixelCabling::TransformType &transform)
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
uint32_t dridToModuleID(const uint32_t &drid)
uint8_t dridToChipID(const uint32_t &drid)