ATLAS Offline Software
Loading...
Searching...
No Matches
LArRawDataReadingAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
11#include "eformat/Version.h"
12#include "eformat/index.h"
13
19
20#include "LArFebHeaderReader.h"
22
23LArRawDataReadingAlg::LArRawDataReadingAlg(const std::string& name, ISvcLocator* pSvcLocator) :
24 AthReentrantAlgorithm(name, pSvcLocator) {}
25
29
30 m_doDigits = !m_digitKey.empty();
31 ATH_CHECK(m_digitKey.initialize(m_doDigits));
32
35
36 ATH_CHECK(m_eventInfoKey.initialize() );
37
39 ATH_CHECK(detStore()->retrieve(m_onlineId,"LArOnlineID"));
40 //
41 //Fill FT list if only Barrel/EC and side is given:
42 if (m_vBEPreselection.size() && m_vPosNegPreselection.size() && m_vFTPreselection.size()==0) {
43 std::set<unsigned> fts;
44 if (std::find(m_vBEPreselection.begin(),m_vBEPreselection.end(),0)!=m_vBEPreselection.end()) { //Barrel selected
45 fts.insert({0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31});
46 }
47 if (std::find(m_vBEPreselection.begin(),m_vBEPreselection.end(),1)!=m_vBEPreselection.end()) { //Endcap selected
48 fts.insert({0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24});
49 }
50 m_vFTPreselection.value().insert(m_vFTPreselection.begin(),fts.begin(),fts.end());
51 }
52
53 //Build list of preselected Feedthroughs
54 if (m_vBEPreselection.size() && m_vPosNegPreselection.size() && m_vFTPreselection.size()) {
55 ATH_MSG_INFO("Building list of selected feedthroughs");
56 for (const unsigned iBE : m_vBEPreselection) {
57 for (const unsigned iPN: m_vPosNegPreselection) {
58 for (const unsigned iFT: m_vFTPreselection) {
59 HWIdentifier finalFTId=m_onlineId->feedthrough_Id(iBE,iPN,iFT);
60 //unsigned int finalFTId32 = finalFTId.get_identifier32().get_compact();
61 ATH_MSG_INFO("Adding feedthrough Barrel/Endcap=" << iBE << " pos/neg=" << iPN << " FT=" << iFT
62 //<< " (0x" << std::hex << finalFTId.get_identifier32().get_compact() << std::dec << ")");
63 << " " << std::hex << finalFTId << std::dec << ")");
64 m_vFinalPreselection.insert(finalFTId);
65 }
66 }
67 }
68 }//end if something set
69
70 if (!m_subCaloPreselection.value().empty()) {
71 ATH_MSG_INFO("Adding list of selected subcalo"<<m_subCaloPreselection.value());
72 std::set<HWIdentifier> subcaloFTs;
73 if (m_subCaloPreselection.value().compare("EM")==0) {
74 for (auto febid : m_onlineId->feb_range()) {
75 if (m_onlineId->isEMBchannel(febid) || m_onlineId->isEMECchannel(febid)) {
76 subcaloFTs.insert(m_onlineId->feedthrough_Id(febid));
77 }
78 }
79 }
80 else if (m_subCaloPreselection.value().find("HEC")!=std::string::npos || m_subCaloPreselection.value().find("FCAL")!=std::string::npos) {
81 if (m_subCaloPreselection.value().find("HEC")!=std::string::npos) {
82 for (auto febid : m_onlineId->feb_range()) {
83 if (m_onlineId->isHECchannel(febid)) {
84 subcaloFTs.insert(m_onlineId->feedthrough_Id(febid));
85 }
86 }
87 }
88 if (m_subCaloPreselection.value().find("FCAL")!=std::string::npos) {
89 for (auto febid : m_onlineId->feb_range()) {
90 if (m_onlineId->isFCALchannel(febid)) {
91 subcaloFTs.insert(m_onlineId->feedthrough_Id(febid));
92 }
93 }
94 }
95 } else {
96 ATH_MSG_ERROR("Configuration problem, property 'SubCaloPreselection' set to " << m_subCaloPreselection.value() << ", expect 'EM', 'HEC' or 'FCAL'");
97 return StatusCode::FAILURE;
98 }
99 std::cout << "set sizes:" << subcaloFTs.size() << ", " << m_vFinalPreselection.size() << std::endl;
100 if (m_vFinalPreselection.size()>0) {
101 //Form the intersection of the preselection give as subdet and side/FT/slot
102 for(auto it = m_vFinalPreselection.begin(); it != m_vFinalPreselection.end(); ) {
103 if (subcaloFTs.find(*it)==subcaloFTs.end())
104 it=m_vFinalPreselection.erase(it);
105 else
106 ++it;
107 }
108 if (m_vFinalPreselection.empty()) {
109 ATH_MSG_WARNING("Apparently inconistent configuration of FT preselections. No preselection left after intersecting 'SubCaloPreselection' with 'PosNeg/BE/FT' preselection");
110 }
111 }
112 else {
113 m_vFinalPreselection.swap(subcaloFTs);
114 }
115 }//end if subCaloPreselection set
116
117 if (!m_vFinalPreselection.empty()) {
118 ATH_MSG_INFO("Give pre-selection covers " << m_vFinalPreselection.size() << " feedthroughts. first is: "<< MSG::hex << *(m_vFinalPreselection.begin()) << MSG::dec <<" Will ignore bytestream data from other feedthroughs.");
119 }
120
121 return StatusCode::SUCCESS;
122}
123
124StatusCode LArRawDataReadingAlg::execute(const EventContext& ctx) const {
125 LArRawChannelContainer* rawChannels=nullptr;
126 LArDigitContainer* digits=nullptr;
127 LArFebHeaderContainer* febHeaders=nullptr;
128
129 if (m_doRawChannels) {
131 ATH_CHECK(rawChannelsHdl.record(std::make_unique<LArRawChannelContainer>()));
132 rawChannels=rawChannelsHdl.ptr();
133 rawChannels->reserve(182468); //Total number of LAr readout channels
134 }
135
136 if (m_doDigits) {
138 ATH_CHECK(digitsHdl.record(std::make_unique<LArDigitContainer>()));
139 digits=digitsHdl.ptr();
140 digits->reserve(1000); //Approximate number of Digits above threshold
141 }
142
143 if (m_doFebHeaders) {
145 ATH_CHECK(febHeadersHdl.record(std::make_unique<LArFebHeaderContainer>()));
146 febHeaders=febHeadersHdl.ptr();
147 febHeaders->reserve(1524); //Total number of LAr Front End Boards
148 }
149
150 //Get full events and filter out LAr ROBs
151 const RawEvent* fullEvent=m_robDataProviderSvc->getEvent(ctx);
152 std::map<eformat::SubDetectorGroup, std::vector<const uint32_t*> > rawEventTOC;
153 eformat::helper::build_toc(*fullEvent, rawEventTOC);
154 auto larRobs=rawEventTOC.find(eformat::LAR);
155 if (larRobs==rawEventTOC.end()) {
156 ATH_MSG_DEBUG("No LAr data found in this event. Recording empty LArRawChannelContainer");
157 return StatusCode::SUCCESS;
158 }
159
160
161 std::unique_ptr<LArRodBlockStructure> rodBlock;
162 uint16_t rodMinorVersion=0x0;
163 uint32_t rodBlockType=0x0;
164
165
166 for (const uint32_t* robPtr : larRobs->second) {
168 ATH_MSG_VERBOSE("Decoding ROB fragment 0x" << std::hex << rob.rob_source_id () << " with " << std::dec << rob.rod_fragment_size_word() << " ROB words");
169
170 if (rob.rod_fragment_size_word() <3) {
171 if (m_failOnCorruption) {
172 ATH_MSG_ERROR("Encountered corrupt ROD fragment, less than 3 words!");
173 return StatusCode::FAILURE;
174 }else {
175 continue;
176 }
177 } else if(rob.rob_source_id()& 0x1000 ){
178 //ATH_MSG_DEBUG(" skip Latome fragment with source ID "<< std::hex << rob.rob_source_id()
179 rodBlock=nullptr;
180 continue;
181 } else if(!(rob.rod_source_id()>>12& 0x0F) //0xnn0nnn must be
182 && !((rob.rod_source_id()>>20) == 4) ){ //0x4nnnnn must be
183
184 ATH_MSG_WARNING("Found not LAr fragment " << " event: "<<ctx.eventID().event_number());
186 ATH_MSG_WARNING("Rob source id.: 0x"<< std::hex << rob.rob_source_id () <<std::dec <<" ROD Source id: 0x"<<std::hex<<rob.rod_source_id()<<std::dec<<" Lvl1ID: "<<eventInfo->extendedLevel1ID());
187 continue;
188 }
189
190
191 eformat::helper::Version ver(rob.rod_version());
192 //(re-)init rodBlock only once per event or if (very unlikly or even impossible) some FEBs have a different firmware
193 if (rodBlock==nullptr || rodMinorVersion !=ver.minor_version() || rodBlockType!=(rob.rod_detev_type()&0xff)) {
194 rodMinorVersion=ver.minor_version();
195 rodBlockType=rob.rod_detev_type()&0xff;
196 ATH_MSG_VERBOSE("Found version " << rodMinorVersion << " of Rod Block Type " << rodBlockType);
197 if (rodBlockType==4) { //Physics mode
198 switch(rodMinorVersion) {
199 case 12: //Physics mode v6 09.03.2011 for LHC
200 rodBlock.reset(new LArRodBlockPhysicsV6 (this->msgSvc().get()));
201 break;
202 case 11: //Physics mode v5 16.06.2008 for LHC
203 case 10: //Physics mode v5 16.06.2008 for LHC
204 rodBlock.reset(new LArRodBlockPhysicsV5 (this->msgSvc().get()));
205 break;
206 default: // Unknown version of rod block type 4 (Physics mode)
207 if (m_failOnCorruption) {
208 ATH_MSG_ERROR("Found unsupported ROD Block version " << rodMinorVersion
209 << " of ROD block type " << rodBlockType << ". ROD Source id: 0x" <<std::hex<<rob.rod_source_id());
210 return StatusCode::FAILURE;
211 }
212 else {
213 ATH_MSG_WARNING("Found unsupported ROD Block version " << rodMinorVersion
214 << " of ROD block type " << rodBlockType << ". ROD Source id: 0x" <<std::hex<<rob.rod_source_id());
215 continue;
216 }
217 }// end switch(rodMinorVersion)
218 }//end rodBlockType==4 (physics mode)
219 else if (rodBlockType==2) { //Transparent mode
220 switch(rodMinorVersion) {
221 case 4:
222 rodBlock.reset(new LArRodBlockTransparentV0<LArRodBlockHeaderTransparentV0> (this->msgSvc().get()));
223 break;
224 case 12:
225 rodBlock.reset(new LArRodBlockCalibrationV3 (this->msgSvc().get()));
226 break;
227 default:
228 ATH_MSG_WARNING("Found unsupported ROD Block version " << rodMinorVersion
229 << " of ROD block type " << rodBlockType);
230 return m_failOnCorruption ? StatusCode::FAILURE : StatusCode::SUCCESS;
231 }
232 }
233 }//End if need to re-init RodBlock
234
235 const uint32_t* pData=rob.rod_data();
236 const uint32_t nData=rob.rod_ndata();
237 if (nData==0) {
238 if (m_failOnCorruption) {
239 ATH_MSG_ERROR("ROD 0x"<<std::hex<<rob.rod_source_id() << std::dec << " reports data block size 0");
240 return StatusCode::FAILURE;
241 }
242 else {
243 ATH_MSG_WARNING("ROD 0x"<<std::hex<<rob.rod_source_id() << std::dec << " reports data block size 0");
244 continue; //Jump to next ROD
245 }
246 }
247
248 if (!rodBlock || !rodBlock->setFragment(pData,nData)) {
249 if (m_failOnCorruption) {
250 ATH_MSG_ERROR("Failed to assign fragment pointer to LArRodBlockStructure");
251 return StatusCode::FAILURE;
252 }
253 else {
254 ATH_MSG_WARNING("Failed to assign fragment pointer to LArRodBlockStructure");
255 continue; // Jump to next ROD
256 }
257 }
258
259 if(m_verifyChecksum) {
260 const uint32_t onsum = rodBlock->onlineCheckSum();
261 const uint32_t offsum = rodBlock->offlineCheckSum();
262 if(onsum!=offsum) {
263 if (m_failOnCorruption) {
264 ATH_MSG_ERROR("Checksum error:");
265 ATH_MSG_ERROR("online checksum = 0x" << MSG::hex << onsum);
266 ATH_MSG_ERROR("offline checksum = 0x" << MSG::hex << offsum << MSG::dec);
267 return StatusCode::FAILURE;
268 } else {
269 continue; //Jump to the next ROD-block
270 }
271 }
272 }
273
274 //Loop over FEBs in ROD:
275 do {
276 HWIdentifier fId(Identifier32(rodBlock->getFEBID()));
277 if (!m_onlineId->isValidId(fId)) {
278 if (m_failOnCorruption){
279 ATH_MSG_ERROR("Invalid FEB identifer 0x" << std::hex << fId.get_identifier32().get_compact());
280 return StatusCode::FAILURE;
281 } else {
282 ATH_MSG_WARNING("Invalid FEB identifer 0x" << std::hex << fId.get_identifier32().get_compact());
283 continue; //Jump to next FEB
284 }
285 }
286
287 if (m_vFinalPreselection.size()) {
288 const auto ftId=m_onlineId->feedthrough_Id(fId);
289 if (m_vFinalPreselection.find(ftId)==m_vFinalPreselection.end()) {
290 ATH_MSG_DEBUG("Feedthrough with id " << MSG::hex << ftId << MSG::dec <<" not in preselection. Ignored.");
291 continue;
292 } else {
293 ATH_MSG_DEBUG("Feedthrough with id " << MSG::hex << ftId << MSG::dec <<" is preselected.");
294 }
295 }
296
297 const int NthisFebChannel=m_onlineId->channelInSlotMax(fId);
298
299 //Decode RawChanels (if requested)
300 if (m_doRawChannels) {
301 int32_t energy;
302 int32_t time;
303 int32_t quality;
304 uint32_t gain;
305 int fcNb;
306 while (rodBlock->getNextEnergy(fcNb,energy,time,quality,gain)) {
307 if (fcNb>=NthisFebChannel)
308 continue;
309
310 HWIdentifier cId = m_onlineId->channel_Id(fId,fcNb);
311 uint16_t iquality = 0;
312 uint16_t iprovenance = LArProv::DSPCALC; //0x1000
313 if (quality>0) {
314 iprovenance |= LArProv::QTPRESENT; //0x2000
315 iquality = (quality & 0xFFFF);
316 }
317 rawChannels->emplace_back(cId, energy, time, iquality, iprovenance, (CaloGain::CaloGain)gain);
318 }//end getNextEnergyLoop
319 }//end if m_doRawChannels
320
321 //Decode LArDigits (if requested)
322 if (m_doDigits) {
323 uint32_t gain;
324 int fcNb;
325 std::vector<short> samples;
326 while (rodBlock->getNextRawData(fcNb,samples,gain)) {
327 if (fcNb>=NthisFebChannel)
328 continue;
329 if (samples.size()==0) continue; // Ignore missing cells
330 HWIdentifier cId = m_onlineId->channel_Id(fId,fcNb);
331 digits->emplace_back(new LArDigit(cId, (CaloGain::CaloGain)gain, std::move(samples)));
332 samples.clear();
333 }//end getNextRawData loop
334 }//end if m_doDigits
335
336 //Decode FebHeaders (if requested)
337 if (m_doFebHeaders) {
338 std::unique_ptr<LArFebHeader> larFebHeader(new LArFebHeader(fId));
339 LArFebHeaderReader::fillFebHeader(larFebHeader.get(),rodBlock.get(),rob);
340 febHeaders->push_back(std::move(larFebHeader));
341 }//end if m_doFebHeaders
342
343 }while (rodBlock->nextFEB()); //Get NextFeb
344 } //end loop over ROBs
345 return StatusCode::SUCCESS;
346}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
OFFLINE_FRAGMENTS_NAMESPACE::FullEventFragment RawEvent
data type for reading raw event
Definition RawEvent.h:37
const ServiceHandle< StoreGateSvc > & detStore() const
An algorithm that can be simultaneously executed in multiple threads.
void reserve(size_type n)
Attempt to preallocate enough memory for a specified number of elements.
value_type emplace_back(value_type pElem)
Add an element to the end of the collection.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
value_type get_compact() const
Get the compact id.
Identifier32 get_identifier32() const
Get the 32-bit version Identifier, will be invalid if >32 bits needed.
Container class for LArDigit.
Liquid Argon digit base class.
Definition LArDigit.h:25
Container class for LArFebHeader.
Holds information from the FEB Header.
Container for LArRawChannel (IDC using LArRawChannelCollection).
LArRawDataReadingAlg(const std::string &name, ISvcLocator *pSvcLocator)
Gaudi::Property< std::vector< unsigned > > m_vPosNegPreselection
Gaudi::Property< std::vector< unsigned > > m_vBEPreselection
std::set< HWIdentifier > m_vFinalPreselection
BooleanProperty m_failOnCorruption
SG::WriteHandleKey< LArRawChannelContainer > m_rawChannelKey
const LArOnlineID * m_onlineId
ServiceHandle< IROBDataProviderSvc > m_robDataProviderSvc
StatusCode initialize() override
SG::WriteHandleKey< LArFebHeaderContainer > m_febHeaderKey
BooleanProperty m_verifyChecksum
Gaudi::Property< std::string > m_subCaloPreselection
SG::WriteHandleKey< LArDigitContainer > m_digitKey
Gaudi::Property< std::vector< unsigned > > m_vFTPreselection
StatusCode execute(const EventContext &ctx) const override
SG::ReadHandleKey< xAOD::EventInfo > m_eventInfoKey
This class provides decoding/encoding from/to ROD format.
This class provides decoding/encoding from/to ROD format.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
pointer_type ptr()
Dereference the pointer.
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:132
void fillFebHeader(LArFebHeader *lfh, const LArRodBlockStructure *bl, const ROBFragment &robFrag)
Fill info for one FEB Header.
eformat::ROBFragment< PointerType > ROBFragment
Definition RawEvent.h:27