Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-09-07 04:36:14

0001 // Code to unpack the "ME Data Record"
0002 
0003 #include "EventFilter/L1TRawToDigi/plugins/UnpackerFactory.h"
0004 
0005 #include "EMTFCollections.h"
0006 #include "EMTFUnpackerTools.h"
0007 
0008 // This is the "header" - no EMTFBlockME.h file is needed
0009 namespace l1t {
0010   namespace stage2 {
0011     namespace emtf {
0012 
0013       class MEBlockUnpacker : public Unpacker {  // "MEBlockUnpacker" inherits from "Unpacker"
0014       public:
0015         virtual int checkFormat(const Block& block);
0016         bool unpack(const Block& block,
0017                     UnpackerCollections* coll) override;  // Apparently it's always good to use override in C++
0018         // virtual bool packBlock(const Block& block, UnpackerCollections *coll) override;
0019       };
0020 
0021       // class MEBlockPacker : public Packer { // "MEBlockPacker" inherits from "Packer"
0022       // public:
0023       //    virtual bool unpack(const Block& block, UnpackerCollections *coll) override; // Apparently it's always good to use override in C++
0024       // };
0025 
0026     }  // namespace emtf
0027   }  // namespace stage2
0028 }  // namespace l1t
0029 
0030 namespace l1t {
0031   namespace stage2 {
0032     namespace emtf {
0033 
0034       int MEBlockUnpacker::checkFormat(const Block& block) {
0035         auto payload = block.payload();
0036         int errors = 0;
0037 
0038         // Check the number of 16-bit words
0039         if (payload.size() != 4) {
0040           errors += 1;
0041           edm::LogError("L1T|EMTF") << "Payload size in 'ME Data Record' is different than expected";
0042         }
0043 
0044         // Check that each word is 16 bits
0045         for (unsigned int i = 0; i < 4; i++) {
0046           if (GetHexBits(payload[i], 16, 31) != 0) {
0047             errors += 1;
0048             edm::LogError("L1T|EMTF") << "Payload[" << i << "] has more than 16 bits in 'ME Data Record'";
0049           }
0050         }
0051 
0052         uint16_t MEa = payload[0];
0053         uint16_t MEb = payload[1];
0054         uint16_t MEc = payload[2];
0055         uint16_t MEd = payload[3];
0056 
0057         //Check Format
0058         if (GetHexBits(MEa, 15, 15) != 1) {
0059           errors += 1;
0060           edm::LogError("L1T|EMTF") << "Format identifier bits in MEa are incorrect";
0061         }
0062         if (GetHexBits(MEb, 15, 15) != 1) {
0063           errors += 1;
0064           edm::LogError("L1T|EMTF") << "Format identifier bits in MEb are incorrect";
0065         }
0066         if (GetHexBits(MEc, 15, 15) != 0) {
0067           errors += 1;
0068           edm::LogError("L1T|EMTF") << "Format identifier bits in MEc are incorrect";
0069         }
0070         if (GetHexBits(MEd, 15, 15) != 0) {
0071           errors += 1;
0072           edm::LogError("L1T|EMTF") << "Format identifier bits in MEd are incorrect";
0073         }
0074 
0075         return errors;
0076       }
0077 
0078       // Converts station, CSC_ID, sector, subsector, and neighbor from the ME output
0079       std::vector<int> convert_ME_location(int _station, int _csc_ID, int _sector, bool _csc_ID_shift = false) {
0080         int new_sector = _sector;
0081         int new_csc_ID = _csc_ID;
0082         if (_csc_ID_shift)
0083           new_csc_ID += 1;  // Before FW update on 05.05.16, shift by +1 from 0,1,2... convention to 1,2,3...
0084         if (_station == 0) {
0085           int arr[] = {1, new_csc_ID, new_sector, 1, 0};
0086           std::vector<int> vec(arr, arr + 5);
0087           return vec;
0088         } else if (_station == 1) {
0089           int arr[] = {1, new_csc_ID, new_sector, 2, 0};
0090           std::vector<int> vec(arr, arr + 5);
0091           return vec;
0092         } else if (_station <= 4) {
0093           int arr[] = {_station, new_csc_ID, new_sector, -1, 0};
0094           std::vector<int> vec(arr, arr + 5);
0095           return vec;
0096         } else if (_station == 5) {
0097           new_sector = (_sector != 1) ? _sector - 1 : 6;  // Indicates neighbor chamber, don't return yet
0098         } else {
0099           int arr[] = {_station, _csc_ID, _sector, -99, -99};
0100           std::vector<int> vec(arr, arr + 5);
0101           return vec;
0102         }
0103 
0104         // Mapping for chambers from neighboring sector
0105         if (new_csc_ID == 1) {
0106           int arr[] = {1, 3, new_sector, 2, 1};
0107           std::vector<int> vec(arr, arr + 5);
0108           return vec;
0109         } else if (new_csc_ID == 2) {
0110           int arr[] = {1, 6, new_sector, 2, 1};
0111           std::vector<int> vec(arr, arr + 5);
0112           return vec;
0113         } else if (new_csc_ID == 3) {
0114           int arr[] = {1, 9, new_sector, 2, 1};
0115           std::vector<int> vec(arr, arr + 5);
0116           return vec;
0117         } else if (new_csc_ID == 4) {
0118           int arr[] = {2, 3, new_sector, -1, 1};
0119           std::vector<int> vec(arr, arr + 5);
0120           return vec;
0121         } else if (new_csc_ID == 5) {
0122           int arr[] = {2, 9, new_sector, -1, 1};
0123           std::vector<int> vec(arr, arr + 5);
0124           return vec;
0125         } else if (new_csc_ID == 6) {
0126           int arr[] = {3, 3, new_sector, -1, 1};
0127           std::vector<int> vec(arr, arr + 5);
0128           return vec;
0129         } else if (new_csc_ID == 7) {
0130           int arr[] = {3, 9, new_sector, -1, 1};
0131           std::vector<int> vec(arr, arr + 5);
0132           return vec;
0133         } else if (new_csc_ID == 8) {
0134           int arr[] = {4, 3, new_sector, -1, 1};
0135           std::vector<int> vec(arr, arr + 5);
0136           return vec;
0137         } else if (new_csc_ID == 9) {
0138           int arr[] = {4, 9, new_sector, -1, 1};
0139           std::vector<int> vec(arr, arr + 5);
0140           return vec;
0141         } else {
0142           int arr[] = {_station, _csc_ID, _sector, -99, -99};
0143           std::vector<int> vec(arr, arr + 5);
0144           return vec;
0145         }
0146       }
0147 
0148       bool MEBlockUnpacker::unpack(const Block& block, UnpackerCollections* coll) {
0149         // std::cout << "Inside EMTFBlockME.cc: unpack" << std::endl;
0150 
0151         // Get the payload for this block, made up of 16-bit words (0xffff)
0152         // Format defined in MTF7Payload::getBlock() in src/Block.cc
0153         // payload[0] = bits 0-15, payload[1] = 16-31, payload[3] = 32-47, etc.
0154         auto payload = block.payload();
0155 
0156         // Assign payload to 16-bit words
0157         uint16_t MEa = payload[0];
0158         uint16_t MEb = payload[1];
0159         uint16_t MEc = payload[2];
0160         uint16_t MEd = payload[3];
0161 
0162         // Check Format of Payload
0163         l1t::emtf::ME ME_;
0164         for (int err = 0; err < checkFormat(block); err++)
0165           ME_.add_format_error();
0166 
0167         // res is a pointer to a collection of EMTFDaqOut class objects
0168         // There is one EMTFDaqOut for each MTF7 (60 deg. sector) in the event
0169         EMTFDaqOutCollection* res;
0170         res = static_cast<EMTFCollections*>(coll)->getEMTFDaqOuts();
0171         int iOut = res->size() - 1;
0172 
0173         EMTFHitCollection* res_hit;
0174         res_hit = static_cast<EMTFCollections*>(coll)->getEMTFHits();
0175         EMTFHit Hit_;
0176 
0177         CSCCorrelatedLCTDigiCollection* res_LCT;
0178         res_LCT = static_cast<EMTFCollections*>(coll)->getEMTFLCTs();
0179 
0180         CSCShowerDigiCollection* res_shower;
0181         res_shower = static_cast<EMTFCollections*>(coll)->getEMTFCSCShowers();
0182 
0183         ////////////////////////////
0184         // Unpack the ME Data Record
0185         ////////////////////////////
0186 
0187         // Run 3 has a different EMTF DAQ output format
0188         // Computed as (Year - 2000)*2^9 + Month*2^5 + Day (see Block.cc and EMTFBlockTrailers.cc)
0189         bool run3_DAQ_format =
0190             (getAlgoVersion() >= 11460);  // Firmware from 04.06.22 which enabled new Run 3 DAQ format - EY 04.07.22
0191         bool reducedDAQWindow =
0192             (getAlgoVersion() >=
0193              11656);  // Firmware from 08.12.22 which is used as a flag for new reduced readout window - EY 01.03.23
0194 
0195         // Set fields assuming Run 2 format. Modify for Run 3 later
0196         ME_.set_clct_pattern(GetHexBits(MEa, 0, 3));
0197         ME_.set_quality(GetHexBits(MEa, 4, 7));
0198         ME_.set_wire(GetHexBits(MEa, 8, 14));
0199 
0200         ME_.set_strip(GetHexBits(MEb, 0, 7));
0201         ME_.set_csc_ID(GetHexBits(MEb, 8, 11));
0202         ME_.set_lr(GetHexBits(MEb, 12, 12));
0203         ME_.set_bxe(GetHexBits(MEb, 13, 13));
0204         ME_.set_bc0(GetHexBits(MEb, 14, 14));
0205 
0206         ME_.set_me_bxn(GetHexBits(MEc, 0, 11));
0207         ME_.set_nit(GetHexBits(MEc, 12, 12));
0208         ME_.set_cik(GetHexBits(MEc, 13, 13));
0209         ME_.set_afff(GetHexBits(MEc, 14, 14));
0210 
0211         if (reducedDAQWindow)  // reduced DAQ window is used only after run3 DAQ format
0212           ME_.set_tbin(GetHexBits(MEd, 0, 2) + 1);
0213         else
0214           ME_.set_tbin(GetHexBits(MEd, 0, 2));
0215         ME_.set_vp(GetHexBits(MEd, 3, 3));
0216         ME_.set_station(GetHexBits(MEd, 4, 6));
0217         ME_.set_af(GetHexBits(MEd, 7, 7));
0218         ME_.set_epc(GetHexBits(MEd, 8, 11));
0219         ME_.set_sm(GetHexBits(MEd, 12, 12));
0220         ME_.set_se(GetHexBits(MEd, 13, 13));
0221         ME_.set_afef(GetHexBits(MEd, 14, 14));
0222 
0223         // ME_.set_dataword     ( uint64_t dataword);
0224 
0225         // Convert specially-encoded ME quantities
0226         bool csc_ID_shift = (getAlgoVersion() <=
0227                              8348);  // For FW versions <= 28.04.2016, shift by +1 from 0,1,2... convention to 1,2,3...
0228         // Computed as (Year - 2000)*2^9 + Month*2^5 + Day (see Block.cc and EMTFBlockTrailers.cc)
0229         std::vector<int> conv_vals =
0230             convert_ME_location(ME_.Station(), ME_.CSC_ID(), (res->at(iOut)).PtrEventHeader()->Sector(), csc_ID_shift);
0231 
0232         Hit_.set_station(conv_vals.at(0));
0233         Hit_.set_csc_ID(conv_vals.at(1));
0234         Hit_.set_sector(conv_vals.at(2));
0235         Hit_.set_subsector(conv_vals.at(3));
0236         Hit_.set_neighbor(conv_vals.at(4));
0237         Hit_.set_ring(L1TMuonEndCap::calc_ring(Hit_.Station(), Hit_.CSC_ID(), ME_.Strip()));
0238 
0239         if (Hit_.Station() < 1 || Hit_.Station() > 4)
0240           edm::LogWarning("L1T|EMTF") << "EMTF unpacked LCT station = " << Hit_.Station()
0241                                       << ", outside proper [1, 4] range" << std::endl;
0242         if (Hit_.CSC_ID() < 1 || Hit_.CSC_ID() > 9)
0243           edm::LogWarning("L1T|EMTF") << "EMTF unpacked LCT CSC ID = " << Hit_.CSC_ID()
0244                                       << ", outside proper [1, 9] range" << std::endl;
0245         if (Hit_.Sector() < 1 || Hit_.Sector() > 6)
0246           edm::LogWarning("L1T|EMTF") << "EMTF unpacked LCT sector = " << Hit_.Sector()
0247                                       << ", outside proper [1, 6] range" << std::endl;
0248 
0249         // Modifications for Run 3 format - EY 04.07.22
0250         bool isOTMB = (Hit_.Ring() == 1 or
0251                        Hit_.Ring() == 4);  // Data format is different between OTMBs (MEX/1) and TMBs (MEX/2-3)
0252 
0253         bool isRun3 =
0254             isOTMB and run3_DAQ_format;  // in Run3 DAQ format, OTMB TPs are Run 3 CSC TPs with CCLUT algorithm
0255 
0256         if (run3_DAQ_format) {
0257           ME_.set_quality(GetHexBits(MEa, 4, 6));
0258           ME_.set_quarter_strip(GetHexBits(MEa, 7, 7));
0259 
0260           ME_.set_frame(GetHexBits(MEc, 12, 12));
0261 
0262           ME_.set_eighth_strip(GetHexBits(MEd, 13, 13));
0263 
0264           if (isOTMB) {  // Derive Run 2 pattern ID from Run 3 slope for OTMBs
0265 
0266             ME_.set_slope(GetHexBits(MEd, 8, 11));
0267 
0268             // convert Run-3 slope to Run-2 pattern for CSC TPs coming from MEX/1 chambers
0269             // where the CCLUT algorithm is enabled
0270             const unsigned slopeList[32] = {10, 10, 10, 8, 8, 8, 6, 6, 6, 4, 4, 4, 2, 2, 2, 2,
0271                                             10, 10, 10, 9, 9, 9, 7, 7, 7, 5, 5, 5, 3, 3, 3, 3};
0272 
0273             // this LUT follows the same convention as in CSCPatternBank.cc
0274             unsigned slope_and_sign(ME_.Slope());
0275             if (ME_.LR() == 1) {
0276               slope_and_sign += 16;
0277             }
0278             unsigned run2_converted_PID = slopeList[slope_and_sign];
0279 
0280             ME_.set_clct_pattern(run2_converted_PID);
0281 
0282           } else {  // Use Run 2 pattern directly for TMBs
0283             ME_.set_clct_pattern(GetHexBits(MEd, 8, 11));
0284           }
0285 
0286           // Frame 1 has muon shower related information
0287           if (ME_.Frame() == 1) {
0288             // Run 3 pattern is unused for now. Needs to be combined with rest of the word in Frame 0 - EY 04.07.22
0289             ME_.set_run3_pattern(GetHexBits(MEa, 0, 0));
0290 
0291             // MUS[1] is in MEa, but MUS[0] is in MEb. These encode in time showers - EY 04.07.22
0292             ME_.set_mus_inTime(GetHexBits(MEb, 13, 13, MEa, 1, 1));
0293 
0294             // MUS[3:2] encodes out-of-time showers which are not used for now
0295             ME_.set_mus_outOfTime(GetHexBits(MEa, 2, 3));
0296 
0297             ME_.set_musv(GetHexBits(MEd, 7, 7));
0298           } else {
0299             ME_.set_run3_pattern(GetHexBits(MEa, 0, 3));
0300 
0301             ME_.set_bxe(GetHexBits(MEb, 13, 13));
0302 
0303             ME_.set_af(GetHexBits(MEd, 7, 7));
0304           }
0305         }
0306 
0307         // Fill the EMTFHit
0308         ImportME(Hit_, ME_, (res->at(iOut)).PtrEventHeader()->Endcap(), (res->at(iOut)).PtrEventHeader()->Sector());
0309 
0310         // Set the stub number for this hit
0311         // Each chamber can send up to 2 stubs per BX
0312         ME_.set_stub_num(0);
0313         Hit_.set_stub_num(0);
0314         // See if matching hit is already in event record: exact duplicate, or from neighboring sector
0315         bool exact_duplicate = false;
0316         bool neighbor_duplicate = false;
0317         for (auto const& iHit : *res_hit) {
0318           if (iHit.Is_CSC() == 1 && Hit_.BX() == iHit.BX() && Hit_.Endcap() == iHit.Endcap() &&
0319               Hit_.Station() == iHit.Station() && Hit_.Chamber() == iHit.Chamber() &&
0320               (Hit_.Ring() % 3) == (iHit.Ring() % 3)) {  // ME1/1a and ME1/1b (rings "4" and 1) are the same chamber
0321 
0322             if (Hit_.Ring() == iHit.Ring() && Hit_.Strip() == iHit.Strip() && Hit_.Wire() == iHit.Wire()) {
0323               exact_duplicate = (Hit_.Neighbor() == iHit.Neighbor());
0324               neighbor_duplicate = (Hit_.Neighbor() != iHit.Neighbor());
0325             } else if (Hit_.Neighbor() == iHit.Neighbor()) {
0326               ME_.set_stub_num(ME_.Stub_num() + 1);
0327               Hit_.set_stub_num(Hit_.Stub_num() + 1);
0328             }
0329           }
0330         }  // End loop: for (auto const & iHit : *res_hit)
0331 
0332         // Reject TPs with out-of-range BX values. This needs to be adjusted if we increase l1a_window parameter in EMTF config - EY 03.08.2022
0333         if (Hit_.BX() > 3 or Hit_.BX() < -3) {
0334           edm::LogWarning("L1T|EMTF") << "EMTF unpacked LCTs with out-of-range BX! BX " << Hit_.BX() << ", endcap "
0335                                       << Hit_.Endcap() << ", station " << Hit_.Station() << ", sector " << Hit_.Sector()
0336                                       << ", neighbor " << Hit_.Neighbor() << ", ring " << Hit_.Ring() << ", chamber "
0337                                       << Hit_.Chamber() << ", strip " << Hit_.Strip() << ", wire " << Hit_.Wire()
0338                                       << std::endl;
0339           return true;
0340         }
0341 
0342         if (exact_duplicate)
0343           edm::LogWarning("L1T|EMTF") << "EMTF unpacked duplicate LCTs: BX " << Hit_.BX() << ", endcap "
0344                                       << Hit_.Endcap() << ", station " << Hit_.Station() << ", sector " << Hit_.Sector()
0345                                       << ", neighbor " << Hit_.Neighbor() << ", ring " << Hit_.Ring() << ", chamber "
0346                                       << Hit_.Chamber() << ", strip " << Hit_.Strip() << ", wire " << Hit_.Wire()
0347                                       << std::endl;
0348 
0349         // Set the hit as invalid if quality == 0 (indicates muon shower)
0350         if (Hit_.Quality() == 0)
0351           Hit_.set_valid(0);
0352 
0353         (res->at(iOut)).push_ME(ME_);
0354         if (!exact_duplicate && Hit_.Valid() == 1)
0355           res_hit->push_back(Hit_);
0356         if (!exact_duplicate && !neighbor_duplicate &&
0357             Hit_.Valid() == 1)  // Don't write duplicate LCTs from adjacent sectors
0358           res_LCT->insertDigi(Hit_.CSC_DetId(), Hit_.CreateCSCCorrelatedLCTDigi(isRun3));
0359         if (Hit_.Muon_shower_valid() == 1) {  // Only write when muon shower valid bit is set to 1
0360           res_shower->insertDigi(Hit_.CSC_DetId(), Hit_.CreateCSCShowerDigi());
0361         }
0362         // Finished with unpacking one ME Data Record
0363         return true;
0364 
0365       }  // End bool MEBlockUnpacker::unpack
0366 
0367       // bool MEBlockPacker::pack(const Block& block, UnpackerCollections *coll) {
0368       //    std::cout << "Inside MEBlockPacker::pack" << std::endl;
0369       //    return true;
0370       // } // End bool MEBlockPacker::pack
0371 
0372     }  // End namespace emtf
0373   }  // End namespace stage2
0374 }  // End namespace l1t
0375 
0376 DEFINE_L1T_UNPACKER(l1t::stage2::emtf::MEBlockUnpacker);
0377 // DEFINE_L1T_PACKER(l1t::stage2::MEBlockPacker);