17 #include "eformat/SourceIdentifier.h"
35 using namespace std::literals::string_view_literals;
37 constexpr
static std::array<std::string_view,4> s_sectorNames = {{
"Undefined"sv,
"Barrel"sv,
"Forward"sv,
"Endcap"sv}};
39 constexpr
static int s_bcidsFullOrbit{3564};
41 constexpr
int bcidDiff(
int a,
int b) {
43 while (
diff < -s_bcidsFullOrbit/2) {
diff += s_bcidsFullOrbit;}
44 while (
diff > s_bcidsFullOrbit/2 - 1) {
diff -= s_bcidsFullOrbit;}
48 constexpr
int bcidSum(
int a,
int b) {
50 while (
sum < 0) {
sum += s_bcidsFullOrbit;}
51 while (
sum >= s_bcidsFullOrbit) {
sum -= s_bcidsFullOrbit;}
56 return (candidateWord | 0x1u<<31);
60 return (candidateWord & ~(0x1u<<31));
68 const std::string&
name,
82 ATH_MSG_DEBUG((
mode==ConversionMode::Encoding ?
"Encoding" :
"Decoding") <<
" ROB IDs: "
83 << MSG::hex <<
m_robIds.value() << MSG::dec);
87 <<
"does not match the number of RoI output containers (" <<
m_roiWriteKeys.size() <<
")");
88 return StatusCode::FAILURE;
94 return StatusCode::FAILURE;
98 ATH_MSG_ERROR(
"This tool implementation assumes there is exactly one MUCTPI ROB, but "
99 <<
m_robIds.size() <<
" were configured");
100 return StatusCode::SUCCESS;
121 return StatusCode::SUCCESS;
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;
162 const uint32_t ndata = rob->rod_ndata();
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;
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();
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();
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) {
244 ATH_MSG_DEBUG(
"Error bit " << bit <<
": " << LVL1::MuCTPIBits::DataStatusWordErrors.at(bit));
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;
348 const uint32_t ndata = rob->rod_ndata();
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();
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();
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) {
428 ATH_MSG_DEBUG(
"Error bit " << bit <<
": " << LVL1::MuCTPIBits::DataStatusWordErrors.at(bit));
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();
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);
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) {
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;
666 constexpr
static bool local_topo_debug{
true};
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) {
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);
751 roiWord |= (
static_cast<uint32_t>(topoheader.pt/2) & RUN3_CAND_PT_MASK) << RUN3_CAND_PT_SHIFT;
752 roiWord |= (
static_cast<uint32_t>(topoheader.flag1) & ROI_OVERFLOW_MASK) << RUN3_ROI_OVERFLOW_SHIFT;
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);
787 roiWord |= (
static_cast<uint32_t>(topoheader.pt) & RUN3_CAND_PT_MASK) << RUN3_CAND_PT_SHIFT;
789 roiWord |= (FORWARD_ADDRESS_MASK & CAND_SECTOR_ADDRESS_MASK) << RUN3_CAND_SECTOR_ADDRESS_SHIFT;
790 if (topoheader.flag0) {
roiWord |= (0x1) << RUN3_CAND_TGC_CHARGE_SIGN_SHIFT;}
791 if (topoheader.flag1) {
roiWord |= (0x1) << RUN3_CAND_TGC_BW2OR3_SHIFT;}
792 if (topoheader.flag2) {
roiWord |= (0x1) << RUN3_CAND_TGC_INNERCOIN_SHIFT;}
793 if (topoheader.flag3) {
roiWord |= (0x1) << RUN3_CAND_TGC_GOODMF_SHIFT;}
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>;
816 case 2: {subsysID=SubsysID_t::Forward;
break;}
820 std::string subsysName{s_sectorNames[
static_cast<size_t>(subsysID)]};
829 return StatusCode::SUCCESS;