128 const EventContext& eventContext)
const {
132 std::vector<SG::WriteHandle<xAOD::MuonRoIContainer>> roiHandles =
m_roiWriteKeys.makeHandles(eventContext);
133 for (
auto& roiHandle : roiHandles) {
134 ATH_CHECK(roiHandle.record(std::make_unique<xAOD::MuonRoIContainer>(),
135 std::make_unique<xAOD::MuonRoIAuxContainer>()));
136 ATH_MSG_DEBUG(
"Recorded MuonRoIContainer with key " << roiHandle.key());
140 std::vector<SG::WriteHandle<xAOD::MuonRoIContainer>> topoHandles;
143 for (
auto& topoHandle : topoHandles) {
144 ATH_CHECK(topoHandle.record(std::make_unique<xAOD::MuonRoIContainer>(),
145 std::make_unique<xAOD::MuonRoIAuxContainer>()));
146 ATH_MSG_DEBUG(
"Recorded MuCTPIL1Topo with key " << topoHandle.key());
151 const eformat::helper::SourceIdentifier sid(
m_robIds.value().at(0));
152 auto it = std::find_if(vrobf.begin(), vrobf.end(), [&sid](
const ROBF* rob){return rob->rob_source_id() == sid.code();});
153 if (it == vrobf.end()) {
154 ATH_MSG_DEBUG(
"No MUCTPI ROB fragment with ID 0x" << std::hex << sid.code() << std::dec
155 <<
" was found, MuonRoIContainer will be empty");
156 return StatusCode::SUCCESS;
160 const ROBF* rob = *it;
162 const uint32_t ndata = rob->rod_ndata();
163 const uint32_t*
const data = rob->rod_data();
170 std::vector<int> bcidOffsetsWrtROB;
175 ATH_MSG_ERROR(
"Empty ROD data in MUCTPI ROB 0x" << std::hex << sid.code() << std::dec);
177 return StatusCode::FAILURE;
179 ATH_MSG_DEBUG(
"Starting to decode " << ndata <<
" ROD words");
183 std::vector<std::pair<size_t,size_t>> roiSlices;
184 std::vector<std::pair<size_t,size_t>> topoSlices;
188 for (
const uint32_t word : std::span{
data, ndata}) {
189 ATH_MSG_DEBUG(
"MUCTPI raw word " << iWord <<
": 0x" << std::hex << word << std::dec);
191 ++wordTypeCounts[
static_cast<size_t>(wordType)];
197 <<
", NTOB=" <<
header.tobCount <<
", NCAND=" <<
header.candCount);
199 roiSlices.emplace_back(0,0);
201 topoSlices.emplace_back(0,0);
203 bcidOffsetsWrtROB.push_back(bcidDiff(
header.bcid, rob->rod_bc_id()));
213 if (roiSlices.empty()) {
214 ATH_MSG_ERROR(
"Unexpected data format - found candidate word before any timeslice header");
216 return StatusCode::FAILURE;
219 std::pair<size_t,size_t>& slice = roiSlices.back();
220 if (slice.first==0) slice.first = iWord;
221 slice.second = iWord - slice.first + 1;
227 if (topoSlices.empty()) {
228 ATH_MSG_ERROR(
"Unexpected data format - found Topo TOB word before any timeslice header");
229 return StatusCode::FAILURE;
232 std::pair<size_t,size_t>& slice = topoSlices.back();
233 if (slice.first==0) slice.first = iWord;
234 slice.second = iWord - slice.first + 1;
241 if (!errorBits.empty()) {
242 ATH_MSG_DEBUG(
"MUCTPI ROD data flagged with errors. The data status word is 0x" << std::hex << word << std::dec);
243 for (
size_t bit : errorBits) {
252 ATH_MSG_ERROR(
"The MUCTPI word 0x" << std::hex << word << std::dec <<
" does not match any known word type");
254 return StatusCode::FAILURE;
264 const size_t nSlices{roiSlices.size()};
266 if (nSlices > nOutputSlices) {
268 return StatusCode::FAILURE;
269 }
else if (nSlices !=
static_cast<size_t>(rob->rod_detev_type())) {
270 ATH_MSG_ERROR(
"Found " << nSlices <<
" time slices, but Detector Event Type word indicates there should be "
271 << rob->rod_detev_type());
272 return StatusCode::FAILURE;
273 }
else if (nSlices!=1 && nSlices!=3 && nSlices!=5) {
274 ATH_MSG_ERROR(
"Expected 1, 3 or 5 time slices but found " << nSlices);
275 return StatusCode::FAILURE;
277 const size_t outputOffset = nOutputSlices/2 - nSlices/2;
282 const size_t nTopoSlices{topoSlices.size()};
284 if (nTopoSlices > nTopoOutputSlices) {
286 return StatusCode::FAILURE;
287 }
else if (nTopoSlices !=
static_cast<size_t>(rob->rod_detev_type())) {
288 ATH_MSG_ERROR(
"Found " << nTopoSlices <<
" time slices, but Detector Event Type word indicates there should be "
289 << rob->rod_detev_type());
290 return StatusCode::FAILURE;
291 }
else if (nTopoSlices!=1 && nTopoSlices!=3 && nTopoSlices!=5) {
292 ATH_MSG_ERROR(
"Expected 1, 3 or 5 time slices but found " << nTopoSlices);
293 return StatusCode::FAILURE;
295 const size_t topoOutputOffset = nTopoOutputSlices/2 - nTopoSlices/2;
301 auto topoHandleIt = topoHandles.begin();
302 for (
auto& roiHandle : roiHandles) {
303 auto& topoHandle = *topoHandleIt;
308 Monitored::Scalar<int> monNumDiff{
"NumOutputDiffRoITopo",
static_cast<int>(monNumRoIs)-
static_cast<int>(monNumTopo)};
309 ATH_MSG_DEBUG(
"Decoded " << monNumRoIs <<
" RoIs into the " << roiHandle.key() <<
" container "
310 "and " << monNumTopo <<
" Topo TOBs into the " << topoHandle.key() <<
" container");
314 ATH_MSG_DEBUG(
"Decoded " << monNumRoIs <<
" RoIs into the " << roiHandle.key() <<
" container");
320 return StatusCode::SUCCESS;
326 std::vector<SG::WriteHandle<xAOD::MuonRoIContainer>> topoHandles;
329 for (
auto& topoHandle : topoHandles) {
330 ATH_CHECK(topoHandle.record(std::make_unique<xAOD::MuonRoIContainer>(),
331 std::make_unique<xAOD::MuonRoIAuxContainer>()));
332 ATH_MSG_DEBUG(
"Recorded MuCTPIL1Topo with key " << topoHandle.key());
337 const eformat::helper::SourceIdentifier sid(
m_robIds.value().at(0));
338 auto it = std::find_if(vrobf.begin(), vrobf.end(), [&sid](
const ROBF* rob){return rob->rob_source_id() == sid.code();});
339 if (it == vrobf.end()) {
340 ATH_MSG_DEBUG(
"No MUCTPI ROB fragment with ID 0x" << std::hex << sid.code() << std::dec
341 <<
" was found, MuonRoIContainer will be empty");
342 return StatusCode::SUCCESS;
346 const ROBF* rob = *it;
348 const uint32_t ndata = rob->rod_ndata();
349 const uint32_t*
const data = rob->rod_data();
356 std::vector<int> bcidOffsetsWrtROB;
361 ATH_MSG_ERROR(
"Empty ROD data in MUCTPI ROB 0x" << std::hex << sid.code() << std::dec);
362 return StatusCode::FAILURE;
364 ATH_MSG_DEBUG(
"Starting to decode " << ndata <<
" ROD words");
368 std::vector<std::pair<size_t,size_t>> roiSlices;
369 std::vector<std::pair<size_t,size_t>> topoSlices;
374 ATH_MSG_DEBUG(
"MUCTPI raw word " << iWord <<
": 0x" << std::hex << word << std::dec);
376 ++wordTypeCounts[
static_cast<size_t>(wordType)];
382 <<
", NTOB=" <<
header.tobCount <<
", NCAND=" <<
header.candCount);
384 roiSlices.emplace_back(0,0);
386 topoSlices.emplace_back(0,0);
388 bcidOffsetsWrtROB.push_back(bcidDiff(
header.bcid, rob->rod_bc_id()));
398 if (roiSlices.empty()) {
399 ATH_MSG_ERROR(
"Unexpected data format - found candidate word before any timeslice header");
400 return StatusCode::FAILURE;
403 std::pair<size_t,size_t>& slice = roiSlices.back();
404 if (slice.first==0) slice.first = iWord;
405 slice.second = iWord - slice.first + 1;
411 if (topoSlices.empty()) {
412 ATH_MSG_ERROR(
"Unexpected data format - found Topo TOB word before any timeslice header");
413 return StatusCode::FAILURE;
416 std::pair<size_t,size_t>& slice = topoSlices.back();
417 if (slice.first==0) slice.first = iWord;
418 slice.second = iWord - slice.first + 1;
425 if (!errorBits.empty()) {
426 ATH_MSG_DEBUG(
"MUCTPI ROD data flagged with errors. The data status word is 0x" << std::hex << word << std::dec);
427 for (
size_t bit : errorBits) {
435 ATH_MSG_ERROR(
"The MUCTPI word 0x" << std::hex << word << std::dec <<
" does not match any known word type");
436 return StatusCode::FAILURE;
443 const size_t nSlices{roiSlices.size()};
445 if (nSlices > nOutputSlices) {
447 return StatusCode::FAILURE;
448 }
else if (nSlices !=
static_cast<size_t>(rob->rod_detev_type())) {
449 ATH_MSG_ERROR(
"Found " << nSlices <<
" time slices, but Detector Event Type word indicates there should be "
450 << rob->rod_detev_type());
451 return StatusCode::FAILURE;
452 }
else if (nSlices!=1 && nSlices!=3 && nSlices!=5) {
453 ATH_MSG_ERROR(
"Expected 1, 3 or 5 time slices but found " << nSlices);
454 return StatusCode::FAILURE;
459 const size_t nTopoSlices{topoSlices.size()};
461 if (nTopoSlices > nTopoOutputSlices) {
463 return StatusCode::FAILURE;
464 }
else if (nTopoSlices !=
static_cast<size_t>(rob->rod_detev_type())) {
465 ATH_MSG_ERROR(
"Found " << nTopoSlices <<
" time slices, but Detector Event Type word indicates there should be "
466 << rob->rod_detev_type());
467 return StatusCode::FAILURE;
468 }
else if (nTopoSlices!=1 && nTopoSlices!=3 && nTopoSlices!=5) {
469 ATH_MSG_ERROR(
"Expected 1, 3 or 5 time slices but found " << nTopoSlices);
470 return StatusCode::FAILURE;
472 const size_t topoOutputOffset = nTopoOutputSlices/2 - nTopoSlices/2;
476 return StatusCode::SUCCESS;
485 const EventContext& eventContext) {
487 std::vector<SG::ReadHandle<xAOD::MuonRoIContainer>> handles =
m_roiReadKeys.makeHandles(eventContext);
491 for (
auto& handle : handles) {
493 if (!handle->empty()) {
494 rodSize += handle->size();
495 nSlices = std::max(nSlices, 1+2*std::abs(
m_readoutWindow/2 - iHandle));
500 ATH_MSG_DEBUG(
"There are no muon RoIs to encode in this event");
506 rodSize += 4*nSlices + 1;
507 ATH_MSG_DEBUG(
"Going to encode " << nSlices <<
" time slices into " << rodSize <<
" ROD words");
510 clearCache(eventContext);
511 uint32_t*
data = newRodData(eventContext, rodSize);
518 std::vector<int> bcidOffsetsWrtROB;
520 auto monitorCandidate = [](
const auto& monTool,
const xAOD::MuonRoI& roi){
522 const uint32_t word = roi.roiWord();
523 using SubsysID_ut = std::underlying_type_t<LVL1::MuCTPIBits::SubsysID>;
526 std::string sectorName{s_sectorNames[
static_cast<size_t>(subsysID)]};
533 auto inputIt = handles.begin();
536 for (
int iSlice=0; iSlice<nSlices; ++iSlice, ++inputIt) {
538 uint32_t bcid = bcidSum(eventContext.eventID().bunch_crossing_id(), iSlice - nSlices/2);
539 static constexpr uint32_t tobCount = 0;
540 uint32_t candCount = (*inputIt)->size();
543 bcidOffsetsWrtROB.push_back(bcidDiff(bcid, eventContext.eventID().bunch_crossing_id()));
544 ATH_MSG_DEBUG(
"Added timeslice header word with BCID=" << bcid <<
", NTOB=" << tobCount <<
", NCAND=" << candCount);
549 data[iWord++] = word;
557 data[iWord++] = roiWordRemoveOfflineRun3Flag(roi->roiWord());
558 ATH_MSG_DEBUG(
"Added RoI word 0x" << std::hex << roi->roiWord() << std::dec);
561 ATH_MSG_DEBUG(
"Added " << (*inputIt)->size() <<
" candidate words");
573 if (iWord!=rodSize) {
574 ATH_MSG_ERROR(
"Expected to fill " << rodSize <<
" ROD words but filled " << iWord);
575 return StatusCode::FAILURE;
579 const eformat::helper::SourceIdentifier sid(
m_robIds.value().at(0));
580 vrobf.push_back(newRobFragment(eventContext, sid.code(), rodSize,
data, nSlices));
582 return StatusCode::SUCCESS;
589 const std::vector<std::pair<size_t,size_t>>& slices,
592 const EventContext& eventContext)
const {
593 auto outputIt = handles.begin();
594 std::advance(outputIt, outputOffset);
595 for (
const auto& [sliceStart,sliceSize] : slices) {
596 for (
const uint32_t word : std::span{
data+sliceStart, sliceSize}) {
597 ATH_MSG_DEBUG(
"Decoding RoI word 0x" << std::hex << word << std::dec <<
" into the " << outputIt->key() <<
" container");
600 (*outputIt)->push_back(std::make_unique<xAOD::MuonRoI>());
618 ATH_MSG_ERROR(
"Failed to determine Sector ID from RoI word 0x" << std::hex << word << std::dec);
619 return StatusCode::FAILURE;
625 const std::pair<std::string, double> minThrInfo =
m_thresholdTool->getMinThresholdNameAndValue(
630 (*outputIt)->back()->initialize(roiWordAddOfflineRun3Flag(word),
637 using SubsysID_ut = std::underlying_type_t<LVL1::MuCTPIBits::SubsysID>;
639 std::string sectorName{s_sectorNames[
static_cast<size_t>(subsysID)]};
647 return StatusCode::SUCCESS;
654 const std::vector<std::pair<size_t,size_t>>& slices,
657 const EventContext& )
const {
658 int toposliceiterator = -1;
659 int nomBCID_slice = slices.size() / 2 ;
660 int topobcidOffset = 0;
661 unsigned short subsystem = 0;
666 constexpr static bool local_topo_debug{
true};
669 ATH_CHECK( detStore()->retrieve(l1menu) );
671 const auto & exMU = l1menu->thrExtraInfo().MU();
672 auto tgcPtValues = exMU.knownTgcPtValues();
674 auto outputIt = handles.begin();
675 std::advance(outputIt, outputOffset);
677 for (
const auto& [sliceStart,sliceSize] : slices) {
679 for (
const uint32_t word : std::span{
data+sliceStart, sliceSize}) {
681 std::stringstream sectorName;
684 topobcidOffset = toposliceiterator - nomBCID_slice;
687 (*outputIt)->push_back(std::make_unique<xAOD::MuonRoI>());
689 ATH_MSG_DEBUG(
"MuCTPIL1Topo: Decoding Topo word 0x" << std::hex << word << std::dec <<
" into the " << outputIt->key() <<
" container");
695 if (local_topo_debug) {
696 ATH_MSG_DEBUG(
"MuCTPIL1Topo: TOPOSLICE data: " <<
data <<
" sliceStart: "<<sliceStart<<
" sliceSize: " <<sliceSize );
697 ATH_MSG_DEBUG(
"MuCTPIL1Topo word: 0x" << std::hex << word << std::dec );
698 ATH_MSG_DEBUG(
"MuCTPIL1Topo word: 0b" << std::bitset<32>(word) );
702 if (topoheader.det == 0) {
706 else if (topoheader.det == 1) {
710 else if (topoheader.det == 2) {
714 if (topoheader.hemi) sectorName <<
"A";
715 else sectorName<<
"C";
716 sectorName << topoheader.sec;
719 if (local_topo_debug) {
723 ATH_MSG_DEBUG(
"MuCTPIL1Topo etacode: " << topoheader.etacode );
724 ATH_MSG_DEBUG(
"MuCTPIL1Topo phicode: " << topoheader.phicode );
733 unsigned short roi =
m_l1topoLUT.getBarrelROI(topoheader.hemi, topoheader.sec, topoheader.barrel_eta_lookup, topoheader.barrel_phi_lookup);
735 if (local_topo_debug) {
737 ATH_MSG_DEBUG(
"MuCTPIL1Topo barrel_eta_lookup: " << topoheader.barrel_eta_lookup );
738 ATH_MSG_DEBUG(
"MuCTPIL1Topo barrel_phi_lookup: " << topoheader.barrel_phi_lookup );
744 if (local_topo_debug) {
745 ATH_MSG_DEBUG(
"MuCTPIL1Topo phiOvl(0): " << topoheader.flag0);
746 ATH_MSG_DEBUG(
"MuCTPIL1Topo is2cand(1):" << topoheader.flag1);
750 uint32_t roiWord = 0;
755 (*outputIt)->back()->initialize(roiWordAddOfflineRun3Flag(roiWord),
759 tgcPtValues[topoheader.pt]);
766 if (local_topo_debug) {
779 if (local_topo_debug) {
780 ATH_MSG_DEBUG(
"MuCTPIL1Topo charge (0):" << topoheader.flag0);
781 ATH_MSG_DEBUG(
"MuCTPIL1Topo bw2or3 (1):" << topoheader.flag1);
782 ATH_MSG_DEBUG(
"MuCTPIL1Topo innerCoin (2):" << topoheader.flag2);
783 ATH_MSG_DEBUG(
"MuCTPIL1Topo goodMF (3):" << topoheader.flag3);
786 uint32_t roiWord = 0;
796 (*outputIt)->back()->initialize(roiWordAddOfflineRun3Flag(roiWord),
800 tgcPtValues[topoheader.pt]);
807 ATH_MSG_DEBUG(
"MuCTPIL1Topo: L1Topo output recorded to StoreGate with key " << outputIt->key() <<
" and bcidOffset: " << topobcidOffset);
811 using SubsysID_ut = std::underlying_type_t<SubsysID_t>;
812 SubsysID_t subsysID{SubsysID_t::Undefined};
814 case 0: {subsysID=SubsysID_t::Barrel;
break;}
815 case 1: {subsysID=SubsysID_t::Endcap;
break;}
816 case 2: {subsysID=SubsysID_t::Forward;
break;}
820 std::string subsysName{s_sectorNames[
static_cast<size_t>(subsysID)]};
829 return StatusCode::SUCCESS;