Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:10:52

0001 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0002 #include "FWCore/Utilities/interface/Exception.h"
0003 #include "EventFilter/L1TRawToDigi/plugins/UnpackerFactory.h"
0004 
0005 #include "L1Trigger/L1TMuon/interface/MuonRawDigiTranslator.h"
0006 
0007 #include "MuonUnpacker.h"
0008 
0009 namespace l1t {
0010   namespace stage2 {
0011     MuonUnpacker::MuonUnpacker() : muonCollection_(nullptr), muonShowerCollection_(nullptr), muonCopy_(0) {}
0012 
0013     bool MuonUnpacker::unpack(const Block& block, UnpackerCollections* coll) {
0014       LogDebug("L1T") << "Block ID  = " << block.header().getID() << " size = " << block.header().getSize();
0015       // process only if there is a payload
0016       // If all BX block were zero suppressed the block header size is 0.
0017       if (block.header().getSize() < 1) {
0018         return true;
0019       }
0020 
0021       auto payload = block.payload();
0022 
0023       int nBX, firstBX, lastBX;
0024       // Check if per BX zero suppression was enabled
0025       bool bxZsEnabled = ((block.header().getFlags() >> bxzs_enable_shift_) & 0x1) == 1;
0026       // Calculate the total number of BXs
0027       if (bxZsEnabled) {
0028         BxBlockHeader bxHeader(payload.at(0));
0029         nBX = bxHeader.getTotalBx();
0030       } else {
0031         nBX = int(ceil(block.header().getSize() / nWords_));
0032       }
0033       getBXRange(nBX, firstBX, lastBX);
0034 
0035       // Set the muon collection and the BX range
0036       muonCollection_ = static_cast<L1TObjectCollections*>(coll)->getMuons(muonCopy_);
0037       muonCollection_->setBXRange(firstBX, lastBX);
0038       // Set the muon shower collection and the BX range
0039       muonShowerCollection_ = static_cast<L1TObjectCollections*>(coll)->getMuonShowers(muonCopy_);
0040       muonShowerCollection_->setBXRange(firstBX, lastBX);
0041 
0042       LogDebug("L1T") << "nBX = " << nBX << " first BX = " << firstBX << " lastBX = " << lastBX;
0043 
0044       // Get the BX blocks and unpack them
0045       auto bxBlocks = block.getBxBlocks(nWords_, bxZsEnabled);
0046       for (const auto& bxBlock : bxBlocks) {
0047         // Throw an exception if finding a corrupt BX header with out of range BX numbers
0048         const auto bx = bxBlock.header().getBx();
0049         if (bx < firstBX || bx > lastBX) {
0050           throw cms::Exception("CorruptData")
0051               << "Corrupt RAW data from FED " << fed_ << ", AMC " << block.amc().getAMCNumber() << ". BX number " << bx
0052               << " in BX header is outside of the BX range [" << firstBX << "," << lastBX
0053               << "] defined in the block header.";
0054         }
0055         unpackBx(bx, bxBlock.payload(), block.header().getID());
0056       }
0057       return true;
0058     }
0059 
0060     void MuonUnpacker::unpackBx(int bx,
0061                                 const std::vector<uint32_t>& payload,
0062                                 unsigned int blockID,
0063                                 unsigned int startIdx) {
0064       unsigned int i = startIdx + 2;  // Only words 2-5 are "standard" muon words.
0065       // Check if there are enough words left in the payload
0066       if (startIdx + nWords_ <= payload.size()) {
0067         // Unpacking showers.
0068         // The shower from uGMT is transmitted via four links, each link
0069         // carrying one of the bits of the shower. We therefore have to
0070         // determine which link we're looking at and act accordingly.
0071         // Output links are odd and input links are even.
0072         int link_offset{0};  // This is correct for the uGT unpacker
0073         if (fed_ == 1402) {  // For uGMT we have to adjust the block/link ID
0074           link_offset = 1;
0075         }
0076         unsigned linkID{(blockID - link_offset) / 2};
0077 
0078         // Try to get the shower for this BX and if it doesn't exist create an
0079         // empty one and push it in.
0080         // Note: We can't just create it for the first linkID, because in
0081         // prinicple there could be a case where that is removed by the ZS.
0082         MuonShower shower;
0083         if (!muonShowerCollection_->isEmpty(bx)) {
0084           shower = muonShowerCollection_->at(bx, 0);
0085           muonShowerCollection_->erase(bx, 0);
0086         }
0087         if (linkID == 0) {  // OneNominal shower is embedded in the first muon of the first link
0088           shower.setOneNominalInTime(l1t::MuonRawDigiTranslator::showerFired(payload[i + 1], fed_, getAlgoVersion()));
0089           // The intial 2023 uGMT firmware put the TwoLoose shower on the wrong link, so we have to do it there.
0090           if (fed_ == 1402 && getAlgoVersion() == l1t::MuonRawDigiTranslator::kUgmtFwVersionShowersFrom2023) {
0091             shower.setTwoLooseDiffSectorsInTime(
0092                 l1t::MuonRawDigiTranslator::showerFired(payload[i + 3], fed_, getAlgoVersion()));
0093           }
0094         } else if (linkID ==
0095                    1) {  // OneTight and TwoLoose showers are embedded in the first and second muons of the second link
0096           shower.setOneTightInTime(l1t::MuonRawDigiTranslator::showerFired(payload[i + 1], fed_, getAlgoVersion()));
0097           // Set the two loose showers from this link in all cases except if we're using the faulty uGMT bitfile
0098           if (!(fed_ == 1402 && getAlgoVersion() == l1t::MuonRawDigiTranslator::kUgmtFwVersionShowersFrom2023)) {
0099             shower.setTwoLooseDiffSectorsInTime(
0100                 l1t::MuonRawDigiTranslator::showerFired(payload[i + 3], fed_, getAlgoVersion()));
0101           }
0102         }
0103 
0104         if (shower.isValid()) {
0105           muonShowerCollection_->push_back(bx, shower);
0106         }
0107 
0108         for (unsigned nWord = 2; nWord < nWords_; nWord += 2) {  // Only words 2-5 are "standard" muon words.
0109           uint32_t raw_data_spare = payload[startIdx + 1];
0110           uint32_t raw_data_00_31 = payload[i++];
0111           uint32_t raw_data_32_63 = payload[i++];
0112           LogDebug("L1T") << "raw_data_spare = 0x" << hex << raw_data_spare << " raw_data_00_31 = 0x" << raw_data_00_31
0113                           << " raw_data_32_63 = 0x" << raw_data_32_63;
0114           // skip empty muons (hwPt == 0)
0115           if (((raw_data_00_31 >> l1t::MuonRawDigiTranslator::ptShift_) & l1t::MuonRawDigiTranslator::ptMask_) == 0) {
0116             LogDebug("L1T") << "Muon hwPt zero. Skip.";
0117             continue;
0118           }
0119 
0120           Muon mu;
0121 
0122           MuonRawDigiTranslator::fillMuon(
0123               mu, raw_data_spare, raw_data_00_31, raw_data_32_63, fed_, getAlgoVersion(), nWord / 2);
0124 
0125           LogDebug("L1T") << "Mu" << nWord / 2 << ": eta " << mu.hwEta() << " phi " << mu.hwPhi() << " pT " << mu.hwPt()
0126                           << " iso " << mu.hwIso() << " qual " << mu.hwQual() << " charge " << mu.hwCharge()
0127                           << " charge valid " << mu.hwChargeValid();
0128 
0129           muonCollection_->push_back(bx, mu);
0130         }
0131       } else {
0132         edm::LogWarning("L1T") << "Only " << payload.size() - i << " 32 bit words in this BX but " << nWords_
0133                                << " are required. Not unpacking the data for BX " << bx << ".";
0134       }
0135     }
0136   }  // namespace stage2
0137 }  // namespace l1t
0138 
0139 DEFINE_L1T_UNPACKER(l1t::stage2::MuonUnpacker);