diff --git a/DQM/L1TMonitor/src/L1TStage2CaloLayer1.cc b/DQM/L1TMonitor/src/L1TStage2CaloLayer1.cc index a024f7e4f3f87..cbfd853dd2d23 100644 --- a/DQM/L1TMonitor/src/L1TStage2CaloLayer1.cc +++ b/DQM/L1TMonitor/src/L1TStage2CaloLayer1.cc @@ -66,6 +66,8 @@ void L1TStage2CaloLayer1::dqmAnalyze(const edm::Event& event, edm::Handle fedRawDataCollection; event.getByToken(fedRawData_, fedRawDataCollection); bool caloLayer1OutOfRun{true}; + bool FATevent{false}; + bool additionalFB{false}; if (fedRawDataCollection.isValid()) { caloLayer1OutOfRun = false; for (int iFed = 1354; iFed < 1360; iFed += 2) { @@ -78,6 +80,9 @@ void L1TStage2CaloLayer1::dqmAnalyze(const edm::Event& event, UCTDAQRawData daqData(fedRawDataArray); for (uint32_t i = 0; i < daqData.nAMCs(); i++) { UCTAMCRawData amcData(daqData.amcPayload(i)); + const uint32_t* amcPtr = amcData.dataPtr(); + FATevent = ((amcPtr[5] >> 16) & 0xf) == 5; + additionalFB = (amcPtr[5] >> 15) & 0x1; int lPhi = amcData.layer1Phi(); if (daqData.BXID() != amcData.BXID()) { eventMonitors.bxidErrors_->Fill(lPhi); @@ -335,6 +340,33 @@ void L1TStage2CaloLayer1::dqmAnalyze(const edm::Event& event, eventMonitors.hcalOccSent_->Fill(ieta, iphi); } + // 6 HCAL fine grain bits from uHTR readout + bool uHTRfg0 = sentTp.SOI_fineGrain(0); + bool uHTRfg1 = sentTp.SOI_fineGrain(1); + bool uHTRfg2 = sentTp.SOI_fineGrain(2); + bool uHTRfg3 = sentTp.SOI_fineGrain(3); + bool uHTRfg4 = sentTp.SOI_fineGrain(4); + bool uHTRfg5 = sentTp.SOI_fineGrain(5); + + if (uHTRfg0) { + eventMonitors.hcalOccSentFg0_->Fill(ieta, iphi); + } + if (uHTRfg1) { + eventMonitors.hcalOccSentFg1_->Fill(ieta, iphi); + } + if (uHTRfg2) { + eventMonitors.hcalOccSentFg2_->Fill(ieta, iphi); + } + if (uHTRfg3) { + eventMonitors.hcalOccSentFg3_->Fill(ieta, iphi); + } + if (uHTRfg4) { + eventMonitors.hcalOccSentFg4_->Fill(ieta, iphi); + } + if (uHTRfg5) { + eventMonitors.hcalOccSentFg5_->Fill(ieta, iphi); + } + if (towerMasked || caloLayer1OutOfRun) { // Do not compare if we have a mask applied continue; @@ -348,92 +380,116 @@ void L1TStage2CaloLayer1::dqmAnalyze(const edm::Event& event, continue; } - // HCAL LLP trigger feature bits monitoring + // 6 HCAL fine grain bits from Layer1 readout + // Fg 0 is always there in ctp7 payload, set as bit 8 after Et bits in unpacked towerDatum + // When additionalFB flag is set: + // Fg 1-5 are unpacked and set as bits 0-5 in another unpacked towerDatum2 and packed in HCALTP sample(1) + // since standard sample size is 16bit and there is no room in sample(0) which contains already Et and link status + // Otherwise: + // Fg 1-5 are all zero + bool layer1fg0 = recdTp.SOI_fineGrain(0); + bool layer1fg1 = false; + bool layer1fg2 = false; + bool layer1fg3 = false; + bool layer1fg4 = false; + bool layer1fg5 = false; + if (additionalFB && (abs(ieta) < 29)) { + for (const auto& tp : (*hcalTPsRecd)) { + if (not(tp.id().ieta() == ieta && tp.id().iphi() == iphi)) { + continue; + } + layer1fg1 = tp.sample(1).raw() & (1 << 0); + layer1fg2 = tp.sample(1).raw() & (1 << 1); + layer1fg3 = tp.sample(1).raw() & (1 << 2); + layer1fg4 = tp.sample(1).raw() & (1 << 3); + layer1fg5 = tp.sample(1).raw() & (1 << 4); + } + } + + // Check mismatches only for HBHE + const bool Hfg0Agreement = (abs(ieta) < 29) ? (layer1fg0 == uHTRfg0) : true; + const bool Hfg1Agreement = (abs(ieta) < 29) ? (layer1fg1 == uHTRfg1) : true; + const bool Hfg2Agreement = (abs(ieta) < 29) ? (layer1fg2 == uHTRfg2) : true; + const bool Hfg3Agreement = (abs(ieta) < 29) ? (layer1fg3 == uHTRfg3) : true; + const bool Hfg4Agreement = (abs(ieta) < 29) ? (layer1fg4 == uHTRfg4) : true; + const bool Hfg5Agreement = (abs(ieta) < 29) ? (layer1fg5 == uHTRfg5) : true; + // Mute fg4 and fg5 for now (reserved bits not used anyway) + const bool HfgAgreement = (Hfg0Agreement && Hfg1Agreement && Hfg2Agreement && Hfg3Agreement); + + // Construct an 6-bit integer from the layer1 fine grain readout (input to 6:1 logic emulation) + uint64_t fg_bits = 0; + if (layer1fg0) { + fg_bits |= 0x1; + } + if (layer1fg1) { + fg_bits |= 0x1 << 1; + } + if (layer1fg2) { + fg_bits |= 0x1 << 2; + } + if (layer1fg3) { + fg_bits |= 0x1 << 3; + } + if (layer1fg4) { + fg_bits |= 0x1 << 4; + } + if (layer1fg5) { + fg_bits |= 0x1 << 5; + } + + // Current 6:1 LUT in fw + const uint64_t HCalFbLUT = 0xBBBABBBABBBABBBA; + // Expected LLP bit output (mute emulation for normal events, since layer2 only reads out FAT events) + const bool LLPfb_Expd = (FATevent == 1) ? ((HCalFbLUT >> fg_bits) & 1) : false; + // Actual LLP bit output in layer2 data collection + uint32_t tower_hwqual = 0; + for (auto tower = caloTowerDataCol->begin(0); tower != caloTowerDataCol->end(0); ++tower) { + if (not(tower->hwEta() == ieta && tower->hwPhi() == iphi)) { + continue; + } + tower_hwqual = tower->hwQual(); + } + // CaloTower hwQual is 4-bit long, LLP output bit is set at the 2nd bit (counting from 0) + const bool LLPfb_Data = ((tower_hwqual & 0b0100) >> 2) & 1; + + const bool LLPfbAgreement = (abs(ieta) < 29) ? (LLPfb_Expd == LLPfb_Data) : true; + + // Fill feature bits Occ for HBHE only if (abs(ieta) < 29) { - // Input feature bits readout at uHTR vs. Layer1 - if (recdTp.SOI_fineGrain(0)) { + if (layer1fg0) { eventMonitors.hcalOccRecdFg0_->Fill(ieta, iphi); } - if (recdTp.SOI_fineGrain(1)) { + if (layer1fg1) { eventMonitors.hcalOccRecdFg1_->Fill(ieta, iphi); } - if (recdTp.SOI_fineGrain(2)) { + if (layer1fg2) { eventMonitors.hcalOccRecdFg2_->Fill(ieta, iphi); } - if (recdTp.SOI_fineGrain(3)) { + if (layer1fg3) { eventMonitors.hcalOccRecdFg3_->Fill(ieta, iphi); } - if (recdTp.SOI_fineGrain(4)) { + if (layer1fg4) { eventMonitors.hcalOccRecdFg4_->Fill(ieta, iphi); } - if (recdTp.SOI_fineGrain(5)) { + if (layer1fg5) { eventMonitors.hcalOccRecdFg5_->Fill(ieta, iphi); } - if (sentTp.SOI_fineGrain(0)) { - eventMonitors.hcalOccSentFg0_->Fill(ieta, iphi); - } - if (sentTp.SOI_fineGrain(1)) { - eventMonitors.hcalOccSentFg1_->Fill(ieta, iphi); - } - if (sentTp.SOI_fineGrain(2)) { - eventMonitors.hcalOccSentFg2_->Fill(ieta, iphi); - } - if (sentTp.SOI_fineGrain(3)) { - eventMonitors.hcalOccSentFg3_->Fill(ieta, iphi); - } - if (sentTp.SOI_fineGrain(4)) { - eventMonitors.hcalOccSentFg4_->Fill(ieta, iphi); - } - if (sentTp.SOI_fineGrain(5)) { - eventMonitors.hcalOccSentFg5_->Fill(ieta, iphi); - } - if (not(recdTp.SOI_fineGrain(0) == sentTp.SOI_fineGrain(0))) { - eventMonitors.hcalOccFg0Discrepancy_->Fill(ieta, iphi); - } - if (not(recdTp.SOI_fineGrain(1) == sentTp.SOI_fineGrain(1))) { - eventMonitors.hcalOccFg1Discrepancy_->Fill(ieta, iphi); - } - if (not(recdTp.SOI_fineGrain(2) == sentTp.SOI_fineGrain(2))) { - eventMonitors.hcalOccFg2Discrepancy_->Fill(ieta, iphi); - } - if (not(recdTp.SOI_fineGrain(3) == sentTp.SOI_fineGrain(3))) { - eventMonitors.hcalOccFg3Discrepancy_->Fill(ieta, iphi); - } - if (not(recdTp.SOI_fineGrain(4) == sentTp.SOI_fineGrain(4))) { + // fg4-5 are reserved bits and not used + // so compare here and not stream to mismatch list for now + if (not Hfg4Agreement) { eventMonitors.hcalOccFg4Discrepancy_->Fill(ieta, iphi); } - if (not(recdTp.SOI_fineGrain(5) == sentTp.SOI_fineGrain(5))) { + if (not Hfg5Agreement) { eventMonitors.hcalOccFg5Discrepancy_->Fill(ieta, iphi); } - // Construct a 6-bit integer from the 6 fine grain bits at uHTR (will change to at Layer1 readout later) - uint64_t fg_bits = 0; - for (int index = 0; index < 6; index++) { - fg_bits |= sentTp.SOI_fineGrain(index) << index; - } - // Current 6:1 LUT in fw - const uint64_t HCalFbLUT = 0xAAAAAAAAAAAAAAAA; - // Expected feature bit output - const bool fb_Expd = (HCalFbLUT >> fg_bits) & 1; - // Actual feature bit output in data - uint32_t tower_hwqual = 0; - for (auto tower = caloTowerDataCol->begin(0); tower != caloTowerDataCol->end(0); ++tower) { - if (not(tower->hwEta() == ieta && tower->hwPhi() == iphi)) { - continue; - } - tower_hwqual = tower->hwQual(); - } - // CaloTower hwQual is 4-bit long, HCAL Fb is set at the 2nd bit (counting from 0) - const bool fb_Data = ((tower_hwqual & 0b0100) >> 2) & 1; - // Fill Fb Occ and compare between expected and data - if (fb_Expd) { + // Fill Fb Occ and compare between layer1 emulated and layer2 data readout + // FAT events only!! + if (LLPfb_Expd) { eventMonitors.hcalOccLLPFbExpd_->Fill(ieta, iphi); } - if (fb_Data) { + if (LLPfb_Data) { eventMonitors.hcalOccLLPFbData_->Fill(ieta, iphi); } - if (not(fb_Expd == fb_Data)) { - eventMonitors.hcalOccLLPFbDiscrepancy_->Fill(ieta, iphi); - } } if (recdTp.SOI_compressedEt() > tpFillThreshold_) { @@ -449,7 +505,7 @@ void L1TStage2CaloLayer1::dqmAnalyze(const edm::Event& event, } const bool HetAgreement = sentTp.SOI_compressedEt() == recdTp.SOI_compressedEt(); - if (HetAgreement) { + if (HetAgreement && HfgAgreement && LLPfbAgreement) { // Full match if (sentTp.SOI_compressedEt() > tpFillThreshold_) { eventMonitors.hcalOccSentAndRecd_->Fill(ieta, iphi); @@ -479,6 +535,24 @@ void L1TStage2CaloLayer1::dqmAnalyze(const edm::Event& event, else eventMonitors.hcalOccNoMatch_->Fill(ieta, iphi); } + if (not(HfgAgreement && LLPfbAgreement)) { + if (not Hfg0Agreement) { + eventMonitors.hcalOccFg0Discrepancy_->Fill(ieta, iphi); + } + if (not Hfg1Agreement) { + eventMonitors.hcalOccFg1Discrepancy_->Fill(ieta, iphi); + } + if (not Hfg2Agreement) { + eventMonitors.hcalOccFg2Discrepancy_->Fill(ieta, iphi); + } + if (not Hfg3Agreement) { + eventMonitors.hcalOccFg3Discrepancy_->Fill(ieta, iphi); + } + if (not LLPfbAgreement) { + eventMonitors.hcalOccLLPFbDiscrepancy_->Fill(ieta, iphi); + } + updateMismatch(event, 3, streamCache(event.streamID())->streamMismatchList); + } } } diff --git a/EventFilter/L1TRawToDigi/interface/Block.h b/EventFilter/L1TRawToDigi/interface/Block.h index 9b35f0eabd395..0db85f1b0b2f3 100644 --- a/EventFilter/L1TRawToDigi/interface/Block.h +++ b/EventFilter/L1TRawToDigi/interface/Block.h @@ -185,6 +185,7 @@ namespace l1t { unsigned capId_; unsigned bx_per_l1a_; unsigned calo_bxid_; + unsigned six_hcal_feature_bits_; amc::Header amcHeader_; }; } // namespace l1t diff --git a/EventFilter/L1TRawToDigi/plugins/implementations_stage2/CaloLayer1Unpacker.cc b/EventFilter/L1TRawToDigi/plugins/implementations_stage2/CaloLayer1Unpacker.cc index 64c960ed0d6e4..edb5b08219ed6 100644 --- a/EventFilter/L1TRawToDigi/plugins/implementations_stage2/CaloLayer1Unpacker.cc +++ b/EventFilter/L1TRawToDigi/plugins/implementations_stage2/CaloLayer1Unpacker.cc @@ -24,21 +24,45 @@ namespace l1t { int N_BX = (block.header().getFlags() >> 16) & 0xf; // std::cout << " N_BX calculated " << N_BX << std::endl; + int HCALFB = (block.header().getFlags() >> 15) & 0x1; + if (N_BX == 1) { - UCTCTP7RawData ctp7Data(ptr); - makeECalTPGs(ctp7_phi, ctp7Data, res->getEcalDigis()); - makeHCalTPGs(ctp7_phi, ctp7Data, res->getHcalDigis()); - makeHFTPGs(ctp7_phi, ctp7Data, res->getHcalDigis()); - makeRegions(ctp7_phi, ctp7Data, res->getRegions()); + if (HCALFB == 0) { + UCTCTP7RawData ctp7Data(ptr); + makeECalTPGs(ctp7_phi, ctp7Data, res->getEcalDigis()); + makeHCalTPGs(ctp7_phi, ctp7Data, res->getHcalDigis()); + makeHFTPGs(ctp7_phi, ctp7Data, res->getHcalDigis()); + makeRegions(ctp7_phi, ctp7Data, res->getRegions()); + } + if (HCALFB == 1) { + UCTCTP7RawData_HCALFB ctp7Data_HCALFB(ptr); + makeECalTPGs_HCALFB(ctp7_phi, ctp7Data_HCALFB, res->getEcalDigis()); + makeHCalTPGs_HCALFB(ctp7_phi, ctp7Data_HCALFB, res->getHcalDigis()); + makeHFTPGs_HCALFB(ctp7_phi, ctp7Data_HCALFB, res->getHcalDigis()); + makeRegions_HCALFB(ctp7_phi, ctp7Data_HCALFB, res->getRegions()); + } } else if (N_BX == 5) { - UCTCTP7RawData5BX ctp7Data5BX(ptr); - // BX_n = 0, 1, 2, 3, 4, where 2 is nominal - makeECalTPGs5BX(ctp7_phi, ctp7Data5BX, res->getEcalDigis(), 2); - makeHCalTPGs5BX(ctp7_phi, ctp7Data5BX, res->getHcalDigis(), 2); - makeHFTPGs5BX(ctp7_phi, ctp7Data5BX, res->getHcalDigis(), 2); - makeRegions5BX(ctp7_phi, ctp7Data5BX, res->getRegions(), 2); - for (int i = 0; i < 5; i++) { - makeECalTPGs5BX(ctp7_phi, ctp7Data5BX, res->getEcalDigisBx(i), i); + if (HCALFB == 0) { + UCTCTP7RawData5BX ctp7Data5BX(ptr); + // BX_n = 0, 1, 2, 3, 4, where 2 is nominal + makeECalTPGs5BX(ctp7_phi, ctp7Data5BX, res->getEcalDigis(), 2); + makeHCalTPGs5BX(ctp7_phi, ctp7Data5BX, res->getHcalDigis(), 2); + makeHFTPGs5BX(ctp7_phi, ctp7Data5BX, res->getHcalDigis(), 2); + makeRegions5BX(ctp7_phi, ctp7Data5BX, res->getRegions(), 2); + for (int i = 0; i < 5; i++) { + makeECalTPGs5BX(ctp7_phi, ctp7Data5BX, res->getEcalDigisBx(i), i); + } + } + if (HCALFB == 1) { + UCTCTP7RawData5BX_HCALFB ctp7Data5BX_HCALFB(ptr); + // BX_n = 0, 1, 2, 3, 4, where 2 is nominal + makeECalTPGs5BX_HCALFB(ctp7_phi, ctp7Data5BX_HCALFB, res->getEcalDigis(), 2); + makeHCalTPGs5BX_HCALFB(ctp7_phi, ctp7Data5BX_HCALFB, res->getHcalDigis(), 2); + makeHFTPGs5BX_HCALFB(ctp7_phi, ctp7Data5BX_HCALFB, res->getHcalDigis(), 2); + makeRegions5BX_HCALFB(ctp7_phi, ctp7Data5BX_HCALFB, res->getRegions(), 2); + for (int i = 0; i < 5; i++) { + makeECalTPGs5BX_HCALFB(ctp7_phi, ctp7Data5BX_HCALFB, res->getEcalDigisBx(i), i); + } } } else { LogError("CaloLayer1Unpacker") << "Number of BXs to unpack is not 1 or 5, stop here !!! " << N_BX << std::endl; @@ -224,6 +248,190 @@ namespace l1t { } } + // For additional HCAL FB implementation + void CaloLayer1Unpacker::makeECalTPGs_HCALFB(uint32_t lPhi, + UCTCTP7RawData_HCALFB& ctp7Data_HCALFB, + EcalTrigPrimDigiCollection* ecalTPGs) { + UCTCTP7RawData_HCALFB::CaloType cType = UCTCTP7RawData_HCALFB::EBEE; + for (uint32_t iPhi = 0; iPhi < 4; iPhi++) { // Loop over all four phi divisions on card + int cPhi = -1 + lPhi * 4 + iPhi; // Calorimeter phi index + if (cPhi == 0) + cPhi = 72; + else if (cPhi == -1) + cPhi = 71; + else if (cPhi < -1) { + LogError("CaloLayer1Unpacker") << "Major error in makeECalTPGs_HCALFB" << std::endl; + return; + } + for (int cEta = -28; cEta <= 28; cEta++) { // Calorimeter Eta indices (HB/HE for now) + if (cEta != 0) { // Calorimeter eta = 0 is invalid + bool negativeEta = false; + if (cEta < 0) + negativeEta = true; + uint32_t iEta = abs(cEta); + // This code is fragile! Note that towerDatum is packed as is done in EcalTriggerPrimitiveSample + // Bottom 8-bits are ET + // Then finegrain feature bit + // Then three bits have ttBits, which I have no clue about (not available on ECAL links so not set) + // Then there is a spare FG Veto bit, which is used for L1 spike detection (not available on ECAL links so not set) + // Top three bits seem to be unused. So, we steal those to set the tower masking, link masking and link status information + // To decode these custom three bits use ((EcalTriggerPrimitiveSample::raw() >> 13) & 0x7) + uint32_t towerDatum = ctp7Data_HCALFB.getET(cType, negativeEta, iEta, iPhi); + if (ctp7Data_HCALFB.getFB(cType, negativeEta, iEta, iPhi) != 0) + towerDatum |= 0x0100; + if (ctp7Data_HCALFB.isTowerMasked(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x2000; + if (ctp7Data_HCALFB.isLinkMasked(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x4000; + if (ctp7Data_HCALFB.isLinkMisaligned(cType, negativeEta, iEta, iPhi) || + ctp7Data_HCALFB.isLinkInError(cType, negativeEta, iEta, iPhi) || + ctp7Data_HCALFB.isLinkDown(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x8000; + EcalTriggerPrimitiveSample sample(towerDatum); + int zSide = cEta / ((int)iEta); + // As far as I can tell, the ECal unpacker only uses barrel and endcap IDs, never EcalTriggerTower + const EcalSubdetector ecalTriggerTower = + (iEta > 17) ? EcalSubdetector::EcalEndcap : EcalSubdetector::EcalBarrel; + EcalTrigTowerDetId id(zSide, ecalTriggerTower, iEta, cPhi); + EcalTriggerPrimitiveDigi tpg(id); + tpg.setSize(1); + tpg.setSample(0, sample); + ecalTPGs->push_back(tpg); + } + } + } + } + + void CaloLayer1Unpacker::makeHCalTPGs_HCALFB(uint32_t lPhi, + UCTCTP7RawData_HCALFB& ctp7Data_HCALFB, + HcalTrigPrimDigiCollection* hcalTPGs) { + UCTCTP7RawData_HCALFB::CaloType cType = UCTCTP7RawData_HCALFB::HBHE; + for (uint32_t iPhi = 0; iPhi < 4; iPhi++) { // Loop over all four phi divisions on card + int cPhi = -1 + lPhi * 4 + iPhi; // Calorimeter phi index + if (cPhi == 0) + cPhi = 72; + else if (cPhi == -1) + cPhi = 71; + else if (cPhi < -1) { + LogError("CaloLayer1Unpacker") << "Major error in makeHCalTPGs_HCALFB" << std::endl; + return; + } + for (int cEta = -28; cEta <= 28; cEta++) { // Calorimeter Eta indices (HB/HE for now) + if (cEta != 0) { // Calorimeter eta = 0 is invalid + bool negativeEta = false; + if (cEta < 0) + negativeEta = true; + uint32_t iEta = abs(cEta); + // This code is fragile! Note that towerDatum is packed as is done in HcalTriggerPrimitiveSample + // Bottom 8-bits are ET + // Then feature bit + // The remaining bits are undefined presently + // We use next three bits for link details, which we did not have room in EcalTriggerPrimitiveSample case + // We use next three bits to set the tower masking, link masking and link status information as done for Ecal + // To decode these custom six bits use ((EcalTriggerPrimitiveSample::raw() >> 9) & 0x77) + uint32_t towerDatum = ctp7Data_HCALFB.getET(cType, negativeEta, iEta, iPhi); + uint32_t fb = ctp7Data_HCALFB.getFB(cType, negativeEta, iEta, iPhi); + towerDatum |= ((fb & 0x1) << 8); + uint32_t towerDatum2 = ((fb & 0x3E) >> 1); + if (ctp7Data_HCALFB.isLinkMisaligned(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x0200; + if (ctp7Data_HCALFB.isLinkInError(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x0400; + if (ctp7Data_HCALFB.isLinkDown(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x0800; + if (ctp7Data_HCALFB.isTowerMasked(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x2000; + if (ctp7Data_HCALFB.isLinkMasked(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x4000; + if (ctp7Data_HCALFB.isLinkMisaligned(cType, negativeEta, iEta, iPhi) || + ctp7Data_HCALFB.isLinkInError(cType, negativeEta, iEta, iPhi) || + ctp7Data_HCALFB.isLinkDown(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x8000; + HcalTriggerPrimitiveSample sample(towerDatum); + HcalTriggerPrimitiveSample sample2(towerDatum2); + HcalTrigTowerDetId id(cEta, cPhi); + HcalTriggerPrimitiveDigi tpg(id); + tpg.setSize(2); + tpg.setSample(0, sample); + tpg.setSample(1, sample2); + hcalTPGs->push_back(tpg); + } + } + } + } + + void CaloLayer1Unpacker::makeHFTPGs_HCALFB(uint32_t lPhi, + UCTCTP7RawData_HCALFB& ctp7Data_HCALFB, + HcalTrigPrimDigiCollection* hcalTPGs) { + UCTCTP7RawData_HCALFB::CaloType cType = UCTCTP7RawData_HCALFB::HF; + for (uint32_t side = 0; side <= 1; side++) { + bool negativeEta = false; + if (side == 0) + negativeEta = true; + for (uint32_t iEta = 30; iEta <= 40; iEta++) { + for (uint32_t iPhi = 0; iPhi < 2; iPhi++) { + if (iPhi == 1 && iEta == 40) + iEta = 41; + int cPhi = 1 + lPhi * 4 + iPhi * 2; // Calorimeter phi index: 1, 3, 5, ... 71 + if (iEta == 41) + cPhi -= 2; // Last two HF are 3, 7, 11, ... + cPhi = (cPhi + 69) % 72 + 1; // cPhi -= 2 mod 72 + int cEta = iEta; + if (negativeEta) + cEta = -iEta; + // This code is fragile! Note that towerDatum is packed as is done in HcalTriggerPrimitiveSample + // Bottom 8-bits are ET + // Then feature bit + // Then minBias ADC count bit + // The remaining bits are undefined presently + // We use next three bits for link details, which we did not have room in EcalTriggerPrimitiveSample case + // We use next three bits to set the tower masking, link masking and link status information as done for Ecal + // To decode these custom six bits use ((EcalTriggerPrimitiveSample::raw() >> 9) & 0x77) + uint32_t towerDatum = ctp7Data_HCALFB.getET(cType, negativeEta, iEta, iPhi); + towerDatum |= ctp7Data_HCALFB.getFB(cType, negativeEta, iEta, iPhi) << 8; + if (ctp7Data_HCALFB.isLinkMisaligned(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x0400; + if (ctp7Data_HCALFB.isLinkInError(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x0800; + if (ctp7Data_HCALFB.isLinkDown(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x1000; + if (ctp7Data_HCALFB.isTowerMasked(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x2000; + if (ctp7Data_HCALFB.isLinkMasked(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x4000; + if (ctp7Data_HCALFB.isLinkMisaligned(cType, negativeEta, iEta, iPhi) || + ctp7Data_HCALFB.isLinkInError(cType, negativeEta, iEta, iPhi) || + ctp7Data_HCALFB.isLinkDown(cType, negativeEta, iEta, iPhi)) + towerDatum |= 0x8000; + HcalTriggerPrimitiveSample sample(towerDatum); + HcalTrigTowerDetId id(cEta, cPhi); + id.setVersion(1); // To not process these 1x1 HF TPGs with RCT + HcalTriggerPrimitiveDigi tpg(id); + tpg.setSize(1); + tpg.setSample(0, sample); + hcalTPGs->push_back(tpg); + } + } + } + } + + void CaloLayer1Unpacker::makeRegions_HCALFB(uint32_t lPhi, + UCTCTP7RawData_HCALFB& ctp7Data_HCALFB, + L1CaloRegionCollection* regions) { + for (uint32_t side = 0; side <= 1; side++) { + bool negativeEta = false; + if (side == 0) + negativeEta = true; + for (uint32_t region = 0; region <= 6; region++) { + uint32_t regionData = ctp7Data_HCALFB.getRegionSummary(negativeEta, region); + uint32_t lEta = 10 - region; // GCT eta goes 0-21, 0-3 -HF, 4-10 -B/E, 11-17 +B/E, 18-21 +HF + if (!negativeEta) + lEta = region + 11; + regions->push_back(L1CaloRegion((uint16_t)regionData, (unsigned)lEta, (unsigned)lPhi, (int16_t)0)); + } + } + } + // The following four functions are duplicated from above, to be used for 5BX events // They have a new parameter BX_n = 0, 1, 2, 3, 4, where 2 is nominal // And use functions defined in UCTCTP7RawData5BX.h @@ -413,6 +621,194 @@ namespace l1t { } } + // For addtional HCAL FB implementation + void CaloLayer1Unpacker::makeECalTPGs5BX_HCALFB(uint32_t lPhi, + UCTCTP7RawData5BX_HCALFB& ctp7Data5BX_HCALFB, + EcalTrigPrimDigiCollection* ecalTPGs, + uint32_t BX_n) { + UCTCTP7RawData5BX_HCALFB::CaloType cType = UCTCTP7RawData5BX_HCALFB::EBEE; + for (uint32_t iPhi = 0; iPhi < 4; iPhi++) { // Loop over all four phi divisions on card + int cPhi = -1 + lPhi * 4 + iPhi; // Calorimeter phi index + if (cPhi == 0) + cPhi = 72; + else if (cPhi == -1) + cPhi = 71; + else if (cPhi < -1) { + LogError("CaloLayer1Unpacker") << "Major error in makeECalTPGs5BX_HCALFB" << std::endl; + return; + } + for (int cEta = -28; cEta <= 28; cEta++) { // Calorimeter Eta indices (HB/HE for now) + if (cEta != 0) { // Calorimeter eta = 0 is invalid + bool negativeEta = false; + if (cEta < 0) + negativeEta = true; + uint32_t iEta = abs(cEta); + // This code is fragile! Note that towerDatum is packed as is done in EcalTriggerPrimitiveSample + // Bottom 8-bits are ET + // Then finegrain feature bit + // Then three bits have ttBits, which I have no clue about (not available on ECAL links so not set) + // Then there is a spare FG Veto bit, which is used for L1 spike detection (not available on ECAL links so not set) + // Top three bits seem to be unused. So, we steal those to set the tower masking, link masking and link status information + // To decode these custom three bits use ((EcalTriggerPrimitiveSample::raw() >> 13) & 0x7) + uint32_t towerDatum = ctp7Data5BX_HCALFB.getET(cType, negativeEta, iEta, iPhi, BX_n); + if (ctp7Data5BX_HCALFB.getFB(cType, negativeEta, iEta, iPhi, BX_n) != 0) + towerDatum |= 0x0100; + if (ctp7Data5BX_HCALFB.isTowerMasked(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x2000; + if (ctp7Data5BX_HCALFB.isLinkMasked(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x4000; + if (ctp7Data5BX_HCALFB.isLinkMisaligned(cType, negativeEta, iEta, iPhi, BX_n) || + ctp7Data5BX_HCALFB.isLinkInError(cType, negativeEta, iEta, iPhi, BX_n) || + ctp7Data5BX_HCALFB.isLinkDown(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x8000; + EcalTriggerPrimitiveSample sample(towerDatum); + int zSide = cEta / ((int)iEta); + // As far as I can tell, the ECal unpacker only uses barrel and endcap IDs, never EcalTriggerTower + const EcalSubdetector ecalTriggerTower = + (iEta > 17) ? EcalSubdetector::EcalEndcap : EcalSubdetector::EcalBarrel; + EcalTrigTowerDetId id(zSide, ecalTriggerTower, iEta, cPhi); + EcalTriggerPrimitiveDigi tpg(id); + tpg.setSize(1); + tpg.setSample(0, sample); + ecalTPGs->push_back(tpg); + } + } + } + } + + void CaloLayer1Unpacker::makeHCalTPGs5BX_HCALFB(uint32_t lPhi, + UCTCTP7RawData5BX_HCALFB& ctp7Data5BX_HCALFB, + HcalTrigPrimDigiCollection* hcalTPGs, + uint32_t BX_n) { + UCTCTP7RawData5BX_HCALFB::CaloType cType = UCTCTP7RawData5BX_HCALFB::HBHE; + for (uint32_t iPhi = 0; iPhi < 4; iPhi++) { // Loop over all four phi divisions on card + int cPhi = -1 + lPhi * 4 + iPhi; // Calorimeter phi index + if (cPhi == 0) + cPhi = 72; + else if (cPhi == -1) + cPhi = 71; + else if (cPhi < -1) { + LogError("CaloLayer1Unpacker") << "Major error in makeHCalTPGs5BX_HCALFB" << std::endl; + return; + } + for (int cEta = -28; cEta <= 28; cEta++) { // Calorimeter Eta indices (HB/HE for now) + if (cEta != 0) { // Calorimeter eta = 0 is invalid + bool negativeEta = false; + if (cEta < 0) + negativeEta = true; + uint32_t iEta = abs(cEta); + // This code is fragile! Note that towerDatum is packed as is done in HcalTriggerPrimitiveSample + // Bottom 8-bits are ET + // Then feature bit + // The remaining bits are undefined presently + // We use next three bits for link details, which we did not have room in EcalTriggerPrimitiveSample case + // We use next three bits to set the tower masking, link masking and link status information as done for Ecal + // To decode these custom six bits use ((EcalTriggerPrimitiveSample::raw() >> 9) & 0x77) + uint32_t towerDatum = ctp7Data5BX_HCALFB.getET(cType, negativeEta, iEta, iPhi, BX_n); + uint32_t fb = ctp7Data5BX_HCALFB.getFB(cType, negativeEta, iEta, iPhi, BX_n); + towerDatum |= ((fb & 0x1) << 8); + uint32_t towerDatum2 = ((fb & 0x3E) >> 1); + if (ctp7Data5BX_HCALFB.isLinkMisaligned(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x0200; + if (ctp7Data5BX_HCALFB.isLinkInError(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x0400; + if (ctp7Data5BX_HCALFB.isLinkDown(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x0800; + if (ctp7Data5BX_HCALFB.isTowerMasked(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x2000; + if (ctp7Data5BX_HCALFB.isLinkMasked(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x4000; + if (ctp7Data5BX_HCALFB.isLinkMisaligned(cType, negativeEta, iEta, iPhi, BX_n) || + ctp7Data5BX_HCALFB.isLinkInError(cType, negativeEta, iEta, iPhi, BX_n) || + ctp7Data5BX_HCALFB.isLinkDown(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x8000; + HcalTriggerPrimitiveSample sample(towerDatum); + HcalTriggerPrimitiveSample sample2(towerDatum2); + HcalTrigTowerDetId id(cEta, cPhi); + HcalTriggerPrimitiveDigi tpg(id); + tpg.setSize(2); + tpg.setSample(0, sample); + tpg.setSample(1, sample2); + hcalTPGs->push_back(tpg); + } + } + } + } + + void CaloLayer1Unpacker::makeHFTPGs5BX_HCALFB(uint32_t lPhi, + UCTCTP7RawData5BX_HCALFB& ctp7Data5BX_HCALFB, + HcalTrigPrimDigiCollection* hcalTPGs, + uint32_t BX_n) { + UCTCTP7RawData5BX_HCALFB::CaloType cType = UCTCTP7RawData5BX_HCALFB::HF; + for (uint32_t side = 0; side <= 1; side++) { + bool negativeEta = false; + if (side == 0) + negativeEta = true; + for (uint32_t iEta = 30; iEta <= 40; iEta++) { + for (uint32_t iPhi = 0; iPhi < 2; iPhi++) { + if (iPhi == 1 && iEta == 40) + iEta = 41; + int cPhi = 1 + lPhi * 4 + iPhi * 2; // Calorimeter phi index: 1, 3, 5, ... 71 + if (iEta == 41) + cPhi -= 2; // Last two HF are 3, 7, 11, ... + cPhi = (cPhi + 69) % 72 + 1; // cPhi -= 2 mod 72 + int cEta = iEta; + if (negativeEta) + cEta = -iEta; + // This code is fragile! Note that towerDatum is packed as is done in HcalTriggerPrimitiveSample + // Bottom 8-bits are ET + // Then feature bit + // Then minBias ADC count bit + // The remaining bits are undefined presently + // We use next three bits for link details, which we did not have room in EcalTriggerPrimitiveSample case + // We use next three bits to set the tower masking, link masking and link status information as done for Ecal + // To decode these custom six bits use ((EcalTriggerPrimitiveSample::raw() >> 9) & 0x77) + uint32_t towerDatum = ctp7Data5BX_HCALFB.getET(cType, negativeEta, iEta, iPhi, BX_n); + towerDatum |= ctp7Data5BX_HCALFB.getFB(cType, negativeEta, iEta, iPhi, BX_n) << 8; + if (ctp7Data5BX_HCALFB.isLinkMisaligned(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x0400; + if (ctp7Data5BX_HCALFB.isLinkInError(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x0800; + if (ctp7Data5BX_HCALFB.isLinkDown(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x1000; + if (ctp7Data5BX_HCALFB.isTowerMasked(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x2000; + if (ctp7Data5BX_HCALFB.isLinkMasked(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x4000; + if (ctp7Data5BX_HCALFB.isLinkMisaligned(cType, negativeEta, iEta, iPhi, BX_n) || + ctp7Data5BX_HCALFB.isLinkInError(cType, negativeEta, iEta, iPhi, BX_n) || + ctp7Data5BX_HCALFB.isLinkDown(cType, negativeEta, iEta, iPhi, BX_n)) + towerDatum |= 0x8000; + HcalTriggerPrimitiveSample sample(towerDatum); + HcalTrigTowerDetId id(cEta, cPhi); + id.setVersion(1); // To not process these 1x1 HF TPGs with RCT + HcalTriggerPrimitiveDigi tpg(id); + tpg.setSize(1); + tpg.setSample(0, sample); + hcalTPGs->push_back(tpg); + } + } + } + } + + void CaloLayer1Unpacker::makeRegions5BX_HCALFB(uint32_t lPhi, + UCTCTP7RawData5BX_HCALFB& ctp7Data5BX_HCALFB, + L1CaloRegionCollection* regions, + uint32_t BX_n) { + for (uint32_t side = 0; side <= 1; side++) { + bool negativeEta = false; + if (side == 0) + negativeEta = true; + for (uint32_t region = 0; region <= 6; region++) { + uint32_t regionData = ctp7Data5BX_HCALFB.getRegionSummary(negativeEta, region, BX_n); + uint32_t lEta = 10 - region; // GCT eta goes 0-21, 0-3 -HF, 4-10 -B/E, 11-17 +B/E, 18-21 +HF + if (!negativeEta) + lEta = region + 11; + regions->push_back(L1CaloRegion((uint16_t)regionData, (unsigned)lEta, (unsigned)lPhi, (int16_t)0)); + } + } + } + } // namespace stage2 } // namespace l1t diff --git a/EventFilter/L1TRawToDigi/plugins/implementations_stage2/CaloLayer1Unpacker.h b/EventFilter/L1TRawToDigi/plugins/implementations_stage2/CaloLayer1Unpacker.h index 05be11d48a291..d8d86ecf6f052 100644 --- a/EventFilter/L1TRawToDigi/plugins/implementations_stage2/CaloLayer1Unpacker.h +++ b/EventFilter/L1TRawToDigi/plugins/implementations_stage2/CaloLayer1Unpacker.h @@ -4,7 +4,9 @@ #include "EventFilter/L1TRawToDigi/interface/Unpacker.h" #include "CaloLayer1Collections.h" #include "UCTCTP7RawData.h" +#include "UCTCTP7RawData_HCALFB.h" #include "UCTCTP7RawData5BX.h" +#include "UCTCTP7RawData5BX_HCALFB.h" namespace l1t { namespace stage2 { @@ -17,6 +19,16 @@ namespace l1t { void makeHCalTPGs(uint32_t lPhi, UCTCTP7RawData& ctp7Data, HcalTrigPrimDigiCollection* hcalTPGs); void makeHFTPGs(uint32_t lPhi, UCTCTP7RawData& ctp7Data, HcalTrigPrimDigiCollection* hcalTPGs); void makeRegions(uint32_t lPhi, UCTCTP7RawData& ctp7Data, L1CaloRegionCollection* regions); + void makeECalTPGs_HCALFB(uint32_t lPhi, + UCTCTP7RawData_HCALFB& ctp7Data_HCALFB, + EcalTrigPrimDigiCollection* ecalTPGs); + void makeHCalTPGs_HCALFB(uint32_t lPhi, + UCTCTP7RawData_HCALFB& ctp7Data_HCALFB, + HcalTrigPrimDigiCollection* hcalTPGs); + void makeHFTPGs_HCALFB(uint32_t lPhi, + UCTCTP7RawData_HCALFB& ctp7Data_HCALFB, + HcalTrigPrimDigiCollection* hcalTPGs); + void makeRegions_HCALFB(uint32_t lPhi, UCTCTP7RawData_HCALFB& ctp7Data_HCALFB, L1CaloRegionCollection* regions); void makeECalTPGs5BX(uint32_t lPhi, UCTCTP7RawData5BX& ctp7Data5BX, EcalTrigPrimDigiCollection* ecalTPGs, @@ -30,6 +42,22 @@ namespace l1t { HcalTrigPrimDigiCollection* hcalTPGs, uint32_t BX_n); void makeRegions5BX(uint32_t lPhi, UCTCTP7RawData5BX& ctp7Data5BX, L1CaloRegionCollection* regions, uint32_t BX_n); + void makeECalTPGs5BX_HCALFB(uint32_t lPhi, + UCTCTP7RawData5BX_HCALFB& ctp7Data5BX_HCALFB, + EcalTrigPrimDigiCollection* ecalTPGs, + uint32_t BX_n); + void makeHCalTPGs5BX_HCALFB(uint32_t lPhi, + UCTCTP7RawData5BX_HCALFB& ctp7Data5BX_HCALFB, + HcalTrigPrimDigiCollection* hcalTPGs, + uint32_t BX_n); + void makeHFTPGs5BX_HCALFB(uint32_t lPhi, + UCTCTP7RawData5BX_HCALFB& ctp7Data5BX_HCALFB, + HcalTrigPrimDigiCollection* hcalTPGs, + uint32_t BX_n); + void makeRegions5BX_HCALFB(uint32_t lPhi, + UCTCTP7RawData5BX_HCALFB& ctp7Data5BX_HCALFB, + L1CaloRegionCollection* regions, + uint32_t BX_n); }; } // namespace stage2 } // namespace l1t diff --git a/EventFilter/L1TRawToDigi/plugins/implementations_stage2/UCTCTP7RawData5BX_HCALFB.h b/EventFilter/L1TRawToDigi/plugins/implementations_stage2/UCTCTP7RawData5BX_HCALFB.h new file mode 100644 index 0000000000000..cc1819e7f5efa --- /dev/null +++ b/EventFilter/L1TRawToDigi/plugins/implementations_stage2/UCTCTP7RawData5BX_HCALFB.h @@ -0,0 +1,375 @@ +#ifndef UCTCTP7RawData5BX_HCALFB_hh +#define UCTCTP7RawData5BX_HCALFB_hh + +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/MessageLogger/interface/MessageDrop.h" + +class UCTCTP7RawData5BX_HCALFB { +public: + enum CaloType { EBEE = 0, HBHE, HF }; + + // read-only constructor + UCTCTP7RawData5BX_HCALFB(const uint32_t* d) : myDataPtr(d) { + if (myDataPtr == nullptr) { + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "You gave me a nullptr :<"; + } + } + // read-write constructor, caller must allocate 220*5*sizeof(uint32_t) bytes + UCTCTP7RawData5BX_HCALFB(uint32_t* d) : myDataPtr(d), myDataWritePtr(d) { + if (myDataPtr == nullptr) { + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "You gave me a nullptr :<"; + } + } + + // No copy constructor and equality operator are needed + UCTCTP7RawData5BX_HCALFB(const UCTCTP7RawData5BX_HCALFB&) = delete; + const UCTCTP7RawData5BX_HCALFB& operator=(const UCTCTP7RawData5BX_HCALFB& i) = delete; + + virtual ~UCTCTP7RawData5BX_HCALFB() { ; } + + // Access functions for convenience + + const uint32_t* dataPtr() const { return myDataPtr; } + + uint32_t sof() { return myDataPtr[0]; } + + size_t getIndex(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t BX_n) { + size_t index = 0; + if (cType == EBEE || cType == HBHE) { + if (iPhi > 3) { + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "Incorrect iPhi; iPhi = " << iPhi << "; should be in [0,3]"; + return index; + } + if (cEta < 1 || cEta > 28) { + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "Incorrect caloEta; cEta = " << cEta << "; should be in [1-28]"; + return index; + } + // ECAL/HB+HE fragment size is 3/4 32-bit words + // Each fragment covers 2 eta and 4 phi towers + // All four phi towers are in one 32-bit word + // Even and odd eta are in neighboring 32-bit words + // Now each fragment contains 5 BX instead of just 1 + // Here BX_n = 0, 1, 2, 3, 4, where 2 is nominal + if (cType == EBEE) { + index = (((cEta - 1) / 2) * (3 + 4) * 5 + ((cEta - 1) % 2)) + 3 * BX_n; + } + if (cType == HBHE) { + index = (((cEta - 1) / 2) * (3 + 4) * 5 + ((cEta - 1) % 2)) + 4 * BX_n; + } + // But, towers are arranged in a peculiar order for firmware + // convenience - the index needs to be computing with these + // if statements. This is brittle code that one should be + // very careful with. + if (negativeEta) { + // Add offset for 6 ECAL and 6 HCAL fragments + index += (6 * (3 + 4)) * 5; + } else { + if (cEta > 12) { + // Add offset for 14 ECAL, 14 HB+HE and 2 HF fragments + // Note that first six are included in the definition of + // the variable - index + // Note also that HF fragments are larger at 4 32-bit words + index += ((14 * (3 + 4) + (2 * 4))) * 5; + } + } + // Data starts with ECAL towers so offset by 3 additional 32-bit words + if (cType == HBHE) + index += 3 * 5; + } else if (cType == HF) { + if (iPhi > 1) { + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "HF iPhi should be 0 or 1 (for a , b) - invalid iPhi = " << iPhi; + return index; + } + if (cEta < 30 || cEta > 41) { + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "HF cEta should be between 30 and 41 - invalid cEta = " << cEta; + return index; + } + if (negativeEta) { + if (iPhi == 0) { + // Offset by 6 positive eta and 14 negative eta EBEE/HBHE fragments (each 3 32-bit words) + // There are four HF cEta towers packed in each 32-bit word + // Add additional offset of 1 for (34-37) and 2 for (38-41) + index = 20 * (3 + 4) * 5 + ((cEta - 30) / 4) + 4 * BX_n; + } else { + // Additional HF a fragment offset for HF b channel + index = 20 * (3 + 4) * 5 + 1 * 4 * 5 + ((cEta - 30) / 4) + 4 * BX_n; + } + } else { + if (iPhi == 0) { + // Offset by all EBEE/HBHE and two HF fragments (4 32-bit words) + index = 2 * 14 * (3 + 4) * 5 + 2 * 4 * 5 + ((cEta - 30) / 4) + 4 * BX_n; + } else { + // Additional HF a fragment offset for HF b channel + index = 2 * 14 * (3 + 4) * 5 + 3 * 4 * 5 + ((cEta - 30) / 4) + 4 * BX_n; + } + } + } else { + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "Unknown CaloType " << cType; + return index; + } + if (index >= 220 * 5) { + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "Managed to calculate an out-of-bounds index, buyer beware"; + } + return index; + } + + size_t getFeatureIndex(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t BX_n) { + // Get index into the data words for the tower + size_t index = getIndex(cType, negativeEta, cEta, iPhi, BX_n); + if (cType == EBEE || cType == HBHE) { + // Two 32-bit words contain ET, so we should offset the index to + // to the feature and link status bits + if (((cEta - 1) % 2) == 0) { + // [index] is offset to ET of first four towers (0 - 3) + // [index + 2] is where the feature and link status bits are + index += 2; + } else { + // In this case [index] is offset to ET of second four towers (4 - 7) + // [index + 1] is where the feature and link status bits are + index += 1; + } + } else if (cType == HF) { + // HF Fragment has different structure than EBEE and HBHE fragments + // First three 32-bit words have ETs for 11 objects (yes, 11 not 12) + // cEta = 40 / 41 are double in eta and flop bettween a and b HF fragments + // Further the remaining upper byte of the third word actually has feature + // bits. This feature index will point to the 4th 32-bit word. It is + // expected that the top byte from 3rd 32-bit word will be patched in within + // the feature bit access function. + // Since there are three instead of if block as above for EBEE, HBHE + // I wrote here a more compact implementation of index computation. + index += (3 - ((cEta - 30) / 4)); + if (index == 0) { + // Since we sticth index-1, zero is also illegal + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "Managed to calculate an out-of-bounds index, buyer beware"; + } + } else { + // Unknown calotype error already generated in getIndex() + return 0; + } + if (index >= 220 * 5) { + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "Managed to calculate an out-of-bounds index, buyer beware"; + } + return index; + } + + void setET(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t et, uint32_t BX_n) { + if (myDataWritePtr == nullptr) { + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "I was made in read-only mode"; + return; + } + size_t index = getIndex(cType, negativeEta, cEta, iPhi, BX_n); + uint32_t& data = myDataWritePtr[index]; + if (cType == HF) { + // Pick out the correct 8-bits for the iEta chosen + // Note that cEta = 41 is special, it only occurs for iPhi == 1 and shares cEta = 40 position + if (cEta == 41) { + data |= (et & 0xFF) << 16; + } else { + data |= (et & 0xFF) << (((cEta - 30) % 4) * 8); + } + } else { + // Pick out the correct 8-bits for the iPhi chosen + data |= (et & 0xFF) << (iPhi * 8); + } + } + + uint32_t getET(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t BX_n) { + size_t index = getIndex(cType, negativeEta, cEta, iPhi, BX_n); + const uint32_t data = myDataPtr[index]; + uint32_t et = 0xDEADBEEF; + if (cType == HF) { + // Pick out the correct 8-bits for the iEta chosen + // Note that cEta = 41 is special, it only occurs for iPhi == 1 and shares cEta = 40 position + if (cEta == 41) + et = ((data >> 16) & 0xFF); + else + et = ((data >> ((cEta - 30) % 4) * 8) & 0xFF); + } else { + // Pick out the correct 8-bits for the iPhi chosen + et = ((data >> (iPhi * 8)) & 0xFF); + } + return et; + } + + void setFB(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t fb, uint32_t BX_n) { + if (myDataWritePtr == nullptr) { + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "I was made in read-only mode"; + return; + } + if (cType == HF) { + setHFFeatureBits(negativeEta, cEta, iPhi, fb, BX_n); + } else { + size_t index = getFeatureIndex(cType, negativeEta, cEta, iPhi, BX_n); + uint32_t& data = myDataWritePtr[index]; + + uint32_t tower = iPhi; + if (((cEta - 1) % 2) == 1) { + tower += 4; + } + data |= (fb & 0x1) << tower; + } + } + + uint32_t getFB(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t BX_n) { + size_t index = getFeatureIndex(cType, negativeEta, cEta, iPhi, BX_n); + if (cType == HBHE) { + if (((cEta - 1) % 2) == 1) { + index += 1; + } + } + const uint32_t data = myDataPtr[index]; + uint32_t fb = 0; + if (cType == HF) { + fb = getHFFeatureBits(negativeEta, cEta, iPhi, BX_n); + } else if (cType == EBEE) { + // Pick out the correct bit for the tower chosen + uint32_t tower = iPhi; + if (((cEta - 1) % 2) == 1) { + tower += 4; + } + fb = ((data & (0x1 << tower)) != 0) ? 1 : 0; + } else { + fb = ((data >> (iPhi * 6)) & 0x3F); + } + return fb; + } + + void setHFFeatureBits(bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t fb, uint32_t BX_n) { + if (myDataWritePtr == nullptr) { + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "I was made in read-only mode"; + return; + } + size_t index = getFeatureIndex(HF, negativeEta, cEta, iPhi, BX_n); + uint32_t shift = (cEta - 30) * 2; + if (cEta == 41) + shift = 20; // 41 occurs on b-fiber but shares the position of 40 + if (shift >= 8) { + uint32_t& data = myDataWritePtr[index]; + data |= (fb & 0x3) << (shift - 8); + } else { + uint32_t& data = myDataWritePtr[index - 1]; + data |= (fb & 0x3) << (shift + 24); + } + } + + uint32_t getHFFeatureBits(bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t BX_n) { + size_t index = getFeatureIndex(HF, negativeEta, cEta, iPhi, BX_n); + // Stitch together the top 8 bits from previous 32-bit word and bottom 14 bits from this word + const uint32_t data = ((myDataPtr[index] & 0x3FFF) << 8) + (myDataPtr[index - 1] >> 24); + uint32_t shift = (cEta - 30) * 2; + if (cEta == 41) + shift = 20; // 41 occurs on b-fiber but shares the position of 40 + return ((data >> shift) & 0x3); + } + + uint32_t getLinkStatus(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t BX_n) { + size_t index = getFeatureIndex(cType, negativeEta, cEta, iPhi, BX_n); + const uint32_t data = myDataPtr[index]; + const uint32_t data2 = myDataPtr[index + 1]; + uint32_t LS = 0; + if (cType == HBHE) { + LS = (data >> 24) & 0xFF; + LS |= ((data2 >> 24) & 0xFF) << 8; + } else { + LS = (data >> 16); + } + return LS; + } + + size_t getSummaryIndex(bool negativeEta, uint32_t region, uint32_t BX_n) { + size_t index = 2 * 14 * (3 + 4) * 5 + 4 * 4 * 5 + (region / 2) + 4 * BX_n; + if (negativeEta) + index += 4 * 5; + if (index >= 220 * 5) { + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "Managed to calculate an out-of-bounds index, buyer beware"; + } + return index; + } + + void setRegionSummary(bool negativeEta, uint32_t region, uint32_t regionData, uint32_t BX_n) { + if (myDataWritePtr == nullptr) { + edm::LogError("UCTCTP7RawData5BX_HCALFB") << "I was made in read-only mode"; + return; + } + size_t index = getSummaryIndex(negativeEta, region, BX_n); + uint32_t& data = myDataWritePtr[index]; + data |= (regionData & 0xFFFF) << (16 * (region % 2)); + } + + uint32_t getRegionSummary(bool negativeEta, uint32_t region, uint32_t BX_n) { + size_t index = getSummaryIndex(negativeEta, region, BX_n); + const uint32_t data = myDataPtr[index]; + return ((data >> (16 * (region % 2))) & 0xFFFF); + } + + uint32_t getRegionET(bool negativeEta, uint32_t region, uint32_t BX_n) { + return (getRegionSummary(negativeEta, region, BX_n) & 0x3FF); + } + + bool getRegionEGVeto(bool negativeEta, uint32_t region, uint32_t BX_n) { + return (getRegionSummary(negativeEta, region, BX_n) & 0x0400); + } + + bool getRegionTauVeto(bool negativeEta, uint32_t region, uint32_t BX_n) { + return (getRegionSummary(negativeEta, region, BX_n) & 0x0800); + } + + uint32_t getRegionHitLocation(bool negativeEta, uint32_t region, uint32_t BX_n) { + return ((getRegionSummary(negativeEta, region, BX_n) & 0xF000) >> 12); + } + + bool isTowerMasked(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t BX_n) { + uint32_t linkStatus = getLinkStatus(cType, negativeEta, cEta, iPhi, BX_n); + uint32_t tower = iPhi; + if ((cEta % 2) == 0) + tower += 4; + if (cType == HF) { + tower = (cEta - 30); + if (cEta == 41) + tower = 10; + } + return ((linkStatus & (0x1 << tower)) != 0); + } + + bool isLinkMisaligned(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t BX_n) { + uint32_t linkStatus = getLinkStatus(cType, negativeEta, cEta, iPhi, BX_n); + if (cType == EBEE && (cEta == 17 || cEta == 21)) { + return ((linkStatus & 0x00000100) != 0); + } + return ((linkStatus & 0x00001000) != 0); + } + + bool isLinkInError(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t BX_n) { + uint32_t linkStatus = getLinkStatus(cType, negativeEta, cEta, iPhi, BX_n); + if (cType == EBEE && (cEta == 17 || cEta == 21)) { + return ((linkStatus & 0x00000200) != 0); + } + return ((linkStatus & 0x00002000) != 0); + } + + bool isLinkDown(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t BX_n) { + uint32_t linkStatus = getLinkStatus(cType, negativeEta, cEta, iPhi, BX_n); + if (cType == EBEE && (cEta == 17 || cEta == 21)) { + return ((linkStatus & 0x00000400) != 0); + } + return ((linkStatus & 0x00004000) != 0); + } + + bool isLinkMasked(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t BX_n) { + uint32_t linkStatus = getLinkStatus(cType, negativeEta, cEta, iPhi, BX_n); + if (cType == EBEE && (cEta == 17 || cEta == 21)) { + return ((linkStatus & 0x00000800) != 0); + } + return ((linkStatus & 0x00008000) != 0); + } + +private: + // Pointer to contiguous array of 220*5 values + // We assume instantiator of this class will gurantee that fact + const uint32_t* myDataPtr; + // == myDataPtr unless read-only + uint32_t* myDataWritePtr = nullptr; +}; + +#endif diff --git a/EventFilter/L1TRawToDigi/plugins/implementations_stage2/UCTCTP7RawData_HCALFB.h b/EventFilter/L1TRawToDigi/plugins/implementations_stage2/UCTCTP7RawData_HCALFB.h new file mode 100644 index 0000000000000..9373de83b36e9 --- /dev/null +++ b/EventFilter/L1TRawToDigi/plugins/implementations_stage2/UCTCTP7RawData_HCALFB.h @@ -0,0 +1,370 @@ +#ifndef UCTCTP7RawData_HCALFB_hh +#define UCTCTP7RawData_HCALFB_hh + +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/MessageLogger/interface/MessageDrop.h" + +class UCTCTP7RawData_HCALFB { +public: + enum CaloType { EBEE = 0, HBHE, HF }; + + // read-only constructor + UCTCTP7RawData_HCALFB(const uint32_t* d) : myDataPtr(d) { + if (myDataPtr == nullptr) { + edm::LogError("UCTCTP7RawData_HCALFB") << "You gave me a nullptr :<"; + } + } + // read-write constructor, caller must allocate 220*sizeof(uint32_t) bytes + UCTCTP7RawData_HCALFB(uint32_t* d) : myDataPtr(d), myDataWritePtr(d) { + if (myDataPtr == nullptr) { + edm::LogError("UCTCTP7RawData_HCALFB") << "You gave me a nullptr :<"; + } + } + + // No copy constructor and equality operator are needed + UCTCTP7RawData_HCALFB(const UCTCTP7RawData_HCALFB&) = delete; + const UCTCTP7RawData_HCALFB& operator=(const UCTCTP7RawData_HCALFB& i) = delete; + + virtual ~UCTCTP7RawData_HCALFB() { ; } + + // Access functions for convenience + + const uint32_t* dataPtr() const { return myDataPtr; } + + uint32_t sof() { return myDataPtr[0]; } + + size_t getIndex(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi) { + size_t index = 0; + if (cType == EBEE || cType == HBHE) { + if (iPhi > 3) { + edm::LogError("UCTCTP7RawData_HCALFB") << "Incorrect iPhi; iPhi = " << iPhi << "; should be in [0,3]"; + return index; + } + if (cEta < 1 || cEta > 28) { + edm::LogError("UCTCTP7RawData_HCALFB") << "Incorrect caloEta; cEta = " << cEta << "; should be in [1-28]"; + return index; + } + // ECAL/HB+HE fragment size is 3/4 32-bit words + // Each fragment covers 2 eta and 4 phi towers + // All four phi towers are in one 32-bit word + // Even and odd eta are in neighboring 32-bit words + index = (((cEta - 1) / 2) * (3 + 4) + ((cEta - 1) % 2)); + // But, towers are arranged in a peculiar order for firmware + // convenience - the index needs to be computing with these + // if statements. This is brittle code that one should be + // very careful with. + if (negativeEta) { + // Add offset for 6 ECAL and 6 HCAL fragments + index += (6 * (3 + 4)); + } else { + if (cEta > 12) { + // Add offset for 14 ECAL, 14 HB+HE and 2 HF fragments + // Note that first six are included in the definition of + // the variable - index + // Note also that HF fragments are larger at 4 32-bit words + index += ((14 * (3 + 4) + (2 * 4))); + } + } + // Data starts with ECAL towers so offset by 3 additional 32-bit words + if (cType == HBHE) + index += 3; + } else if (cType == HF) { + if (iPhi > 1) { + edm::LogError("UCTCTP7RawData_HCALFB") << "HF iPhi should be 0 or 1 (for a , b) - invalid iPhi = " << iPhi; + return index; + } + if (cEta < 30 || cEta > 41) { + edm::LogError("UCTCTP7RawData_HCALFB") << "HF cEta should be between 30 and 41 - invalid cEta = " << cEta; + return index; + } + if (negativeEta) { + if (iPhi == 0) { + // Offset by 6 positive eta and 14 negative eta EBEE/HBHE fragments (each 3/4 32-bit words) + // There are four HF cEta towers packed in each 32-bit word + // Add additional offset of 1 for (34-37) and 2 for (38-41) + index = 20 * (3 + 4) + ((cEta - 30) / 4); + } else { + // Additional HF a fragment offset for HF b channel + index = 20 * (3 + 4) + 1 * 4 + ((cEta - 30) / 4); + } + } else { + if (iPhi == 0) { + // Offset by all EBEE/HBHE and two HF fragments (4 32-bit words) + index = 2 * 14 * (3 + 4) + 2 * 4 + ((cEta - 30) / 4); + } else { + // Additional HF a fragment offset for HF b channel + index = 2 * 14 * (3 + 4) + 3 * 4 + ((cEta - 30) / 4); + } + } + } else { + edm::LogError("UCTCTP7RawData_HCALFB") << "Unknown CaloType " << cType; + return index; + } + if (index >= 220) { + edm::LogError("UCTCTP7RawData_HCALFB") << "Managed to calculate an out-of-bounds index, buyer beware"; + } + return index; + } + + size_t getFeatureIndex(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi) { + // Get index into the data words for the tower + size_t index = getIndex(cType, negativeEta, cEta, iPhi); + if (cType == EBEE || cType == HBHE) { + // Two 32-bit words contain ET, so we should offset the index to + // to the feature and link status bits + if (((cEta - 1) % 2) == 0) { + // [index] is offset to ET of first four towers (0 - 3) + // [index + 2] is where the feature and link status bits are + index += 2; + } else { + // In this case [index] is offset to ET of second four towers (4 - 7) + // [index + 1] is where the feature and link status bits are + index += 1; + } + } else if (cType == HF) { + // HF Fragment has different structure than EBEE and HBHE fragments + // First three 32-bit words have ETs for 11 objects (yes, 11 not 12) + // cEta = 40 / 41 are double in eta and flop bettween a and b HF fragments + // Further the remaining upper byte of the third word actually has feature + // bits. This feature index will point to the 4th 32-bit word. It is + // expected that the top byte from 3rd 32-bit word will be patched in within + // the feature bit access function. + // Since there are three instead of if block as above for EBEE, HBHE + // I wrote here a more compact implementation of index computation. + index += (3 - ((cEta - 30) / 4)); + if (index == 0) { + // Since we sticth index-1, zero is also illegal + edm::LogError("UCTCTP7RawData_HCALFB") << "Managed to calculate an out-of-bounds index, buyer beware"; + } + } else { + // Unknown calotype error already generated in getIndex() + return 0; + } + if (index >= 220) { + edm::LogError("UCTCTP7RawData_HCALFB") << "Managed to calculate an out-of-bounds index, buyer beware"; + } + return index; + } + + void setET(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t et) { + if (myDataWritePtr == nullptr) { + edm::LogError("UCTCTP7RawData_HCALFB") << "I was made in read-only mode"; + return; + } + size_t index = getIndex(cType, negativeEta, cEta, iPhi); + uint32_t& data = myDataWritePtr[index]; + if (cType == HF) { + // Pick out the correct 8-bits for the iEta chosen + // Note that cEta = 41 is special, it only occurs for iPhi == 1 and shares cEta = 40 position + if (cEta == 41) { + data |= (et & 0xFF) << 16; + } else { + data |= (et & 0xFF) << (((cEta - 30) % 4) * 8); + } + } else { + // Pick out the correct 8-bits for the iPhi chosen + data |= (et & 0xFF) << (iPhi * 8); + } + } + + uint32_t getET(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi) { + size_t index = getIndex(cType, negativeEta, cEta, iPhi); + const uint32_t data = myDataPtr[index]; + uint32_t et = 0xDEADBEEF; + if (cType == HF) { + // Pick out the correct 8-bits for the iEta chosen + // Note that cEta = 41 is special, it only occurs for iPhi == 1 and shares cEta = 40 position + if (cEta == 41) + et = ((data >> 16) & 0xFF); + else + et = ((data >> ((cEta - 30) % 4) * 8) & 0xFF); + } else { + // Pick out the correct 8-bits for the iPhi chosen + et = ((data >> (iPhi * 8)) & 0xFF); + } + return et; + } + + void setFB(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t fb) { + if (myDataWritePtr == nullptr) { + edm::LogError("UCTCTP7RawData_HCALFB") << "I was made in read-only mode"; + return; + } + if (cType == HF) { + setHFFeatureBits(negativeEta, cEta, iPhi, fb); + } else { + size_t index = getFeatureIndex(cType, negativeEta, cEta, iPhi); + uint32_t& data = myDataWritePtr[index]; + + uint32_t tower = iPhi; + if (((cEta - 1) % 2) == 1) { + tower += 4; + } + if (cType == HBHE) { + int depth = fb & 0b1; + int prompt = (fb & 0b10) >> 1; + int delay1 = (fb & 0b100) >> 2; + int delay2 = (fb & 0b1000) >> 3; + if (cEta < 16) + data |= (depth | ((!prompt) & (delay1 | delay2))) << tower; // bit[0] | (!bit[1] & (bit[2] | bit[3])) + } else + data |= (fb & 0x1) << tower; + } + } + + uint32_t getFB(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi) { + size_t index = getFeatureIndex(cType, negativeEta, cEta, iPhi); + if (cType == HBHE) { + if (((cEta - 1) % 2) == 1) { + index += 1; + } + } + const uint32_t data = myDataPtr[index]; + uint32_t fb = 0; + if (cType == HF) { + fb = getHFFeatureBits(negativeEta, cEta, iPhi); + } else if (cType == EBEE) { + // Pick out the correct bit for the tower chosen + uint32_t tower = iPhi; + if (((cEta - 1) % 2) == 1) { + tower += 4; + } + fb = ((data & (0x1 << tower)) != 0) ? 1 : 0; + } else { + fb = ((data >> (iPhi * 6)) & 0x3F); + } + return fb; + } + + void setHFFeatureBits(bool negativeEta, uint32_t cEta, uint32_t iPhi, uint32_t fb) { + if (myDataWritePtr == nullptr) { + edm::LogError("UCTCTP7RawData_HCALFB") << "I was made in read-only mode"; + return; + } + size_t index = getFeatureIndex(HF, negativeEta, cEta, iPhi); + uint32_t shift = (cEta - 30) * 2; + if (cEta == 41) + shift = 20; // 41 occurs on b-fiber but shares the position of 40 + if (shift >= 8) { + uint32_t& data = myDataWritePtr[index]; + data |= (fb & 0x3) << (shift - 8); + } else { + uint32_t& data = myDataWritePtr[index - 1]; + data |= (fb & 0x3) << (shift + 24); + } + } + + uint32_t getHFFeatureBits(bool negativeEta, uint32_t cEta, uint32_t iPhi) { + size_t index = getFeatureIndex(HF, negativeEta, cEta, iPhi); + // Stitch together the top 8 bits from previous 32-bit word and bottom 14 bits from this word + const uint32_t data = ((myDataPtr[index] & 0x3FFF) << 8) + (myDataPtr[index - 1] >> 24); + uint32_t shift = (cEta - 30) * 2; + if (cEta == 41) + shift = 20; // 41 occurs on b-fiber but shares the position of 40 + return ((data >> shift) & 0x3); + } + + uint32_t getLinkStatus(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi) { + size_t index = getFeatureIndex(cType, negativeEta, cEta, iPhi); + const uint32_t data = myDataPtr[index]; + const uint32_t data2 = myDataPtr[index + 1]; + uint32_t LS = 0; + if (cType == HBHE) { + LS = (data >> 24) & 0xFF; + LS |= ((data2 >> 24) & 0xFF) << 8; + } else { + LS = (data >> 16); + } + return LS; + } + + size_t getSummaryIndex(bool negativeEta, uint32_t region) { + size_t index = 2 * 14 * (3 + 4) + 4 * 4 + (region / 2); + if (negativeEta) + index += 4; + if (index >= 220) { + edm::LogError("UCTCTP7RawData_HCALFB") << "Managed to calculate an out-of-bounds index, buyer beware"; + } + return index; + } + + void setRegionSummary(bool negativeEta, uint32_t region, uint32_t regionData) { + if (myDataWritePtr == nullptr) { + edm::LogError("UCTCTP7RawData_HCALFB") << "I was made in read-only mode"; + return; + } + size_t index = getSummaryIndex(negativeEta, region); + uint32_t& data = myDataWritePtr[index]; + data |= (regionData & 0xFFFF) << (16 * (region % 2)); + } + + uint32_t getRegionSummary(bool negativeEta, uint32_t region) { + size_t index = getSummaryIndex(negativeEta, region); + const uint32_t data = myDataPtr[index]; + return ((data >> (16 * (region % 2))) & 0xFFFF); + } + + uint32_t getRegionET(bool negativeEta, uint32_t region) { return (getRegionSummary(negativeEta, region) & 0x3FF); } + + bool getRegionEGVeto(bool negativeEta, uint32_t region) { return (getRegionSummary(negativeEta, region) & 0x0400); } + + bool getRegionTauVeto(bool negativeEta, uint32_t region) { return (getRegionSummary(negativeEta, region) & 0x0800); } + + uint32_t getRegionHitLocation(bool negativeEta, uint32_t region) { + return ((getRegionSummary(negativeEta, region) & 0xF000) >> 12); + } + + bool isTowerMasked(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi) { + uint32_t linkStatus = getLinkStatus(cType, negativeEta, cEta, iPhi); + uint32_t tower = iPhi; + if ((cEta % 2) == 0) + tower += 4; + if (cType == HF) { + tower = (cEta - 30); + if (cEta == 41) + tower = 10; + } + return ((linkStatus & (0x1 << tower)) != 0); + } + + bool isLinkMisaligned(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi) { + uint32_t linkStatus = getLinkStatus(cType, negativeEta, cEta, iPhi); + if (cType == EBEE && (cEta == 17 || cEta == 21)) { + return ((linkStatus & 0x00000100) != 0); + } + return ((linkStatus & 0x00001000) != 0); + } + + bool isLinkInError(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi) { + uint32_t linkStatus = getLinkStatus(cType, negativeEta, cEta, iPhi); + if (cType == EBEE && (cEta == 17 || cEta == 21)) { + return ((linkStatus & 0x00000200) != 0); + } + return ((linkStatus & 0x00002000) != 0); + } + + bool isLinkDown(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi) { + uint32_t linkStatus = getLinkStatus(cType, negativeEta, cEta, iPhi); + if (cType == EBEE && (cEta == 17 || cEta == 21)) { + return ((linkStatus & 0x00000400) != 0); + } + return ((linkStatus & 0x00004000) != 0); + } + + bool isLinkMasked(CaloType cType, bool negativeEta, uint32_t cEta, uint32_t iPhi) { + uint32_t linkStatus = getLinkStatus(cType, negativeEta, cEta, iPhi); + if (cType == EBEE && (cEta == 17 || cEta == 21)) { + return ((linkStatus & 0x00000800) != 0); + } + return ((linkStatus & 0x00008000) != 0); + } + +private: + // Pointer to contiguous array of 220 values + // We assume instantiator of this class will gurantee that fact + const uint32_t* myDataPtr; + // == myDataPtr unless read-only + uint32_t* myDataWritePtr = nullptr; +}; + +#endif diff --git a/EventFilter/L1TRawToDigi/src/Block.cc b/EventFilter/L1TRawToDigi/src/Block.cc index c5c631bd268f9..168a6e02cbb0a 100644 --- a/EventFilter/L1TRawToDigi/src/Block.cc +++ b/EventFilter/L1TRawToDigi/src/Block.cc @@ -211,6 +211,7 @@ namespace l1t { bx_per_l1a_ = (*data_ >> 16) & 0xff; calo_bxid_ = *data_ & 0xfff; capId_ = 0; + six_hcal_feature_bits_ = (*data_ >> 15) & 0x1; if (bx_per_l1a_ > 1) { edm::LogInfo("L1T") << "CTP7 block with multiple bunch crossings:" << bx_per_l1a_; } @@ -225,8 +226,8 @@ namespace l1t { // CTP7 header contains number of BX in payload and the bunch crossing ID // Not sure how to map to generic BlockHeader variables, so just packing // it all in flags variable - unsigned blockFlags = ((bx_per_l1a_ & 0xf) << 16) | (calo_bxid_ & 0xfff); - unsigned blockSize = 192 * (int)bx_per_l1a_; + unsigned blockFlags = ((bx_per_l1a_ & 0xf) << 16) | (calo_bxid_ & 0xfff) | ((six_hcal_feature_bits_ & 0x1) << 15); + unsigned blockSize = (192 + (int)six_hcal_feature_bits_ * 28) * (int)bx_per_l1a_; return BlockHeader(blockId, blockSize, capId_, blockFlags, CTP7); }