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