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 {
130 std::vector<SG::WriteHandle<xAOD::MuonRoIContainer>> roiHandles =
m_roiWriteKeys.makeHandles(eventContext);
131 for (
auto& roiHandle : roiHandles) {
132 ATH_CHECK(roiHandle.record(std::make_unique<xAOD::MuonRoIContainer>(),
133 std::make_unique<xAOD::MuonRoIAuxContainer>()));
134 ATH_MSG_DEBUG(
"Recorded MuonRoIContainer with key " << roiHandle.key());
138 std::vector<SG::WriteHandle<xAOD::MuonRoIContainer>> topoHandles;
141 for (
auto& topoHandle : topoHandles) {
142 ATH_CHECK(topoHandle.record(std::make_unique<xAOD::MuonRoIContainer>(),
143 std::make_unique<xAOD::MuonRoIAuxContainer>()));
144 ATH_MSG_DEBUG(
"Recorded MuCTPIL1Topo with key " << topoHandle.key());
149 const eformat::helper::SourceIdentifier sid(
m_robIds.value().at(0));
150 auto it = std::find_if(vrobf.begin(), vrobf.end(), [&sid](
const ROBF* rob){return rob->rob_source_id() == sid.code();});
151 if (
it == vrobf.end()) {
152 ATH_MSG_DEBUG(
"No MUCTPI ROB fragment with ID 0x" << std::hex << sid.code() << std::dec
153 <<
" was found, MuonRoIContainer will be empty");
154 return StatusCode::SUCCESS;
160 const uint32_t ndata = rob->rod_ndata();
168 std::vector<int> bcidOffsetsWrtROB;
173 ATH_MSG_ERROR(
"Empty ROD data in MUCTPI ROB 0x" << std::hex << sid.code() << std::dec);
175 return StatusCode::FAILURE;
177 ATH_MSG_DEBUG(
"Starting to decode " << ndata <<
" ROD words");
181 std::vector<std::pair<size_t,size_t>> roiSlices;
182 std::vector<std::pair<size_t,size_t>> topoSlices;
187 ATH_MSG_DEBUG(
"MUCTPI raw word " << iWord <<
": 0x" << std::hex << word << std::dec);
189 ++wordTypeCounts[
static_cast<size_t>(wordType)];
195 <<
", NTOB=" <<
header.tobCount <<
", NCAND=" <<
header.candCount);
197 roiSlices.emplace_back(0,0);
199 topoSlices.emplace_back(0,0);
201 bcidOffsetsWrtROB.push_back(bcidDiff(
header.bcid, rob->rod_bc_id()));
211 if (roiSlices.empty()) {
212 ATH_MSG_ERROR(
"Unexpected data format - found candidate word before any timeslice header");
214 return StatusCode::FAILURE;
217 std::pair<size_t,size_t>&
slice = roiSlices.back();
225 if (topoSlices.empty()) {
226 ATH_MSG_ERROR(
"Unexpected data format - found Topo TOB word before any timeslice header");
227 return StatusCode::FAILURE;
230 std::pair<size_t,size_t>&
slice = topoSlices.back();
239 if (!errorBits.empty()) {
240 ATH_MSG_DEBUG(
"MUCTPI ROD data flagged with errors. The data status word is 0x" << std::hex << word << std::dec);
241 for (
size_t bit : errorBits) {
242 ATH_MSG_DEBUG(
"Error bit " << bit <<
": " << LVL1::MuCTPIBits::DataStatusWordErrors.at(bit));
250 ATH_MSG_ERROR(
"The MUCTPI word 0x" << std::hex << word << std::dec <<
" does not match any known word type");
252 return StatusCode::FAILURE;
262 const size_t nSlices{roiSlices.size()};
264 if (nSlices > nOutputSlices) {
266 return StatusCode::FAILURE;
267 }
else if (nSlices !=
static_cast<size_t>(rob->rod_detev_type())) {
268 ATH_MSG_ERROR(
"Found " << nSlices <<
" time slices, but Detector Event Type word indicates there should be "
269 << rob->rod_detev_type());
270 return StatusCode::FAILURE;
271 }
else if (nSlices!=1 && nSlices!=3 && nSlices!=5) {
272 ATH_MSG_ERROR(
"Expected 1, 3 or 5 time slices but found " << nSlices);
273 return StatusCode::FAILURE;
275 const size_t outputOffset = nOutputSlices/2 - nSlices/2;
280 const size_t nTopoSlices{topoSlices.size()};
282 if (nTopoSlices > nTopoOutputSlices) {
284 return StatusCode::FAILURE;
285 }
else if (nTopoSlices !=
static_cast<size_t>(rob->rod_detev_type())) {
286 ATH_MSG_ERROR(
"Found " << nTopoSlices <<
" time slices, but Detector Event Type word indicates there should be "
287 << rob->rod_detev_type());
288 return StatusCode::FAILURE;
289 }
else if (nTopoSlices!=1 && nTopoSlices!=3 && nTopoSlices!=5) {
290 ATH_MSG_ERROR(
"Expected 1, 3 or 5 time slices but found " << nTopoSlices);
291 return StatusCode::FAILURE;
293 const size_t topoOutputOffset = nTopoOutputSlices/2 - nTopoSlices/2;
299 auto topoHandleIt = topoHandles.begin();
300 for (
auto& roiHandle : roiHandles) {
301 auto& topoHandle = *topoHandleIt;
306 Monitored::Scalar<int> monNumDiff{
"NumOutputDiffRoITopo",
static_cast<int>(monNumRoIs)-
static_cast<int>(monNumTopo)};
307 ATH_MSG_DEBUG(
"Decoded " << monNumRoIs <<
" RoIs into the " << roiHandle.key() <<
" container "
308 "and " << monNumTopo <<
" Topo TOBs into the " << topoHandle.key() <<
" container");
312 ATH_MSG_DEBUG(
"Decoded " << monNumRoIs <<
" RoIs into the " << roiHandle.key() <<
" container");
318 return StatusCode::SUCCESS;
325 const EventContext& eventContext) {
327 std::vector<SG::ReadHandle<xAOD::MuonRoIContainer>> handles =
m_roiReadKeys.makeHandles(eventContext);
331 for (
auto& handle : handles) {
333 if (!handle->empty()) {
334 rodSize += handle->size();
340 ATH_MSG_DEBUG(
"There are no muon RoIs to encode in this event");
346 rodSize += 4*nSlices + 1;
347 ATH_MSG_DEBUG(
"Going to encode " << nSlices <<
" time slices into " << rodSize <<
" ROD words");
350 clearCache(eventContext);
358 std::vector<int> bcidOffsetsWrtROB;
360 auto monitorCandidate = [](
const auto& monTool,
const xAOD::MuonRoI& roi){
362 const uint32_t word = roi.roiWord();
363 using SubsysID_ut = std::underlying_type_t<LVL1::MuCTPIBits::SubsysID>;
366 std::string sectorName{s_sectorNames[
static_cast<size_t>(subsysID)]};
373 auto inputIt = handles.begin();
376 for (
int iSlice=0; iSlice<nSlices; ++iSlice, ++inputIt) {
378 uint32_t bcid = bcidSum(eventContext.eventID().bunch_crossing_id(), iSlice - nSlices/2);
379 static constexpr
uint32_t tobCount = 0;
380 uint32_t candCount = (*inputIt)->size();
383 bcidOffsetsWrtROB.push_back(bcidDiff(
bcid, eventContext.eventID().bunch_crossing_id()));
384 ATH_MSG_DEBUG(
"Added timeslice header word with BCID=" <<
bcid <<
", NTOB=" << tobCount <<
", NCAND=" << candCount);
389 data[iWord++] = word;
397 data[iWord++] = roiWordRemoveOfflineRun3Flag(roi->roiWord());
398 ATH_MSG_DEBUG(
"Added RoI word 0x" << std::hex << roi->roiWord() << std::dec);
401 ATH_MSG_DEBUG(
"Added " << (*inputIt)->size() <<
" candidate words");
413 if (iWord!=rodSize) {
414 ATH_MSG_ERROR(
"Expected to fill " << rodSize <<
" ROD words but filled " << iWord);
415 return StatusCode::FAILURE;
419 const eformat::helper::SourceIdentifier sid(
m_robIds.value().at(0));
420 vrobf.push_back(newRobFragment(eventContext, sid.code(), rodSize,
data, nSlices));
422 return StatusCode::SUCCESS;
429 const std::vector<std::pair<size_t,size_t>>&
slices,
432 const EventContext& eventContext)
const {
433 auto outputIt = handles.begin();
434 std::advance(outputIt, outputOffset);
435 for (
const auto& [sliceStart,sliceSize] :
slices) {
437 ATH_MSG_DEBUG(
"Decoding RoI word 0x" << std::hex << word << std::dec <<
" into the " << outputIt->key() <<
" container");
440 (*outputIt)->push_back(std::make_unique<xAOD::MuonRoI>());
458 ATH_MSG_ERROR(
"Failed to determine Sector ID from RoI word 0x" << std::hex << word << std::dec);
459 return StatusCode::FAILURE;
465 const std::pair<std::string, double> minThrInfo =
m_thresholdTool->getMinThresholdNameAndValue(
470 (*outputIt)->back()->initialize(roiWordAddOfflineRun3Flag(word),
477 using SubsysID_ut = std::underlying_type_t<LVL1::MuCTPIBits::SubsysID>;
479 std::string sectorName{s_sectorNames[
static_cast<size_t>(subsysID)]};
487 return StatusCode::SUCCESS;
494 const std::vector<std::pair<size_t,size_t>>&
slices,
497 const EventContext& )
const {
498 int toposliceiterator = -1;
499 int nomBCID_slice =
slices.size() / 2 ;
500 int topobcidOffset = 0;
506 constexpr
static bool local_topo_debug{
true};
511 const auto & exMU =
l1menu->thrExtraInfo().MU();
512 auto tgcPtValues = exMU.knownTgcPtValues();
514 auto outputIt = handles.begin();
515 std::advance(outputIt, outputOffset);
517 for (
const auto& [sliceStart,sliceSize] :
slices) {
521 std::stringstream sectorName;
524 topobcidOffset = toposliceiterator - nomBCID_slice;
527 (*outputIt)->push_back(std::make_unique<xAOD::MuonRoI>());
529 ATH_MSG_DEBUG(
"MuCTPIL1Topo: Decoding Topo word 0x" << std::hex << word << std::dec <<
" into the " << outputIt->key() <<
" container");
535 if (local_topo_debug) {
536 ATH_MSG_DEBUG(
"MuCTPIL1Topo: TOPOSLICE data: " <<
data <<
" sliceStart: "<<sliceStart<<
" sliceSize: " <<sliceSize );
537 ATH_MSG_DEBUG(
"MuCTPIL1Topo word: 0x" << std::hex << word << std::dec );
538 ATH_MSG_DEBUG(
"MuCTPIL1Topo word: 0b" << std::bitset<32>(word) );
542 if (topoheader.det == 0) {
546 else if (topoheader.det == 1) {
550 else if (topoheader.det == 2) {
554 if (topoheader.hemi) sectorName <<
"A";
555 else sectorName<<
"C";
556 sectorName << topoheader.sec;
559 if (local_topo_debug) {
563 ATH_MSG_DEBUG(
"MuCTPIL1Topo etacode: " << topoheader.etacode );
564 ATH_MSG_DEBUG(
"MuCTPIL1Topo phicode: " << topoheader.phicode );
573 unsigned short roi =
m_l1topoLUT.
getBarrelROI(topoheader.hemi, topoheader.sec, topoheader.barrel_eta_lookup, topoheader.barrel_phi_lookup);
575 if (local_topo_debug) {
577 ATH_MSG_DEBUG(
"MuCTPIL1Topo barrel_eta_lookup: " << topoheader.barrel_eta_lookup );
578 ATH_MSG_DEBUG(
"MuCTPIL1Topo barrel_phi_lookup: " << topoheader.barrel_phi_lookup );
584 if (local_topo_debug) {
585 ATH_MSG_DEBUG(
"MuCTPIL1Topo phiOvl(0): " << topoheader.flag0);
586 ATH_MSG_DEBUG(
"MuCTPIL1Topo is2cand(1):" << topoheader.flag1);
591 roiWord |= (
static_cast<uint32_t>(topoheader.pt/2) & RUN3_CAND_PT_MASK) << RUN3_CAND_PT_SHIFT;
592 roiWord |= (
static_cast<uint32_t>(topoheader.flag1) & ROI_OVERFLOW_MASK) << RUN3_ROI_OVERFLOW_SHIFT;
595 (*outputIt)->back()->initialize(roiWordAddOfflineRun3Flag(
roiWord),
599 tgcPtValues[topoheader.pt]);
606 if (local_topo_debug) {
619 if (local_topo_debug) {
620 ATH_MSG_DEBUG(
"MuCTPIL1Topo charge (0):" << topoheader.flag0);
621 ATH_MSG_DEBUG(
"MuCTPIL1Topo bw2or3 (1):" << topoheader.flag1);
622 ATH_MSG_DEBUG(
"MuCTPIL1Topo innerCoin (2):" << topoheader.flag2);
623 ATH_MSG_DEBUG(
"MuCTPIL1Topo goodMF (3):" << topoheader.flag3);
627 roiWord |= (
static_cast<uint32_t>(topoheader.pt) & RUN3_CAND_PT_MASK) << RUN3_CAND_PT_SHIFT;
629 roiWord |= (FORWARD_ADDRESS_MASK & CAND_SECTOR_ADDRESS_MASK) << RUN3_CAND_SECTOR_ADDRESS_SHIFT;
630 if (topoheader.flag0) {
roiWord |= (0x1) << RUN3_CAND_TGC_CHARGE_SIGN_SHIFT;}
631 if (topoheader.flag1) {
roiWord |= (0x1) << RUN3_CAND_TGC_BW2OR3_SHIFT;}
632 if (topoheader.flag2) {
roiWord |= (0x1) << RUN3_CAND_TGC_INNERCOIN_SHIFT;}
633 if (topoheader.flag3) {
roiWord |= (0x1) << RUN3_CAND_TGC_GOODMF_SHIFT;}
636 (*outputIt)->back()->initialize(roiWordAddOfflineRun3Flag(
roiWord),
640 tgcPtValues[topoheader.pt]);
647 ATH_MSG_DEBUG(
"MuCTPIL1Topo: L1Topo output recorded to StoreGate with key " << outputIt->key() <<
" and bcidOffset: " << topobcidOffset);
651 using SubsysID_ut = std::underlying_type_t<SubsysID_t>;
656 case 2: {subsysID=SubsysID_t::Forward;
break;}
660 std::string subsysName{s_sectorNames[
static_cast<size_t>(subsysID)]};
669 return StatusCode::SUCCESS;