Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 // Code to unpack the "RPC 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 EMTFBlockRPC.h file is needed
0009 namespace l1t {
0010   namespace stage2 {
0011     namespace emtf {
0012 
0013       class RPCBlockUnpacker : public Unpacker {  // "RPCBlockUnpacker" inherits from "Unpacker"
0014       public:
0015         virtual int checkFormat(const Block& block);
0016         // virtual bool checkFormat() override; // Return "false" if block format does not match expected format
0017         bool unpack(const Block& block,
0018                     UnpackerCollections* coll) override;  // Apparently it's always good to use override in C++
0019         // virtual bool packBlock(const Block& block, UnpackerCollections *coll) override;
0020       };
0021 
0022       // class RPCBlockPacker : public Packer { // "RPCBlockPacker" inherits from "Packer"
0023       // public:
0024       //    virtual bool unpack(const Block& block, UnpackerCollections *coll) override; // Apparently it's always good to use override in C++
0025       // };
0026 
0027     }  // namespace emtf
0028   }    // namespace stage2
0029 }  // namespace l1t
0030 
0031 namespace l1t {
0032   namespace stage2 {
0033     namespace emtf {
0034 
0035       int RPCBlockUnpacker::checkFormat(const Block& block) {
0036         auto payload = block.payload();
0037         int errors = 0;
0038 
0039         // Check the number of 16-bit words
0040         if (payload.size() != 4) {
0041           errors += 1;
0042           edm::LogError("L1T|EMTF") << "Payload size in 'RPC Data Record' is different than expected";
0043         }
0044 
0045         // Check that each word is 16 bits
0046         for (unsigned int i = 0; i < 4; i++) {
0047           if (GetHexBits(payload[i], 16, 31) != 0) {
0048             errors += 1;
0049             edm::LogError("L1T|EMTF") << "Payload[" << i << "] has more than 16 bits in 'RPC Data Record'";
0050           }
0051         }
0052 
0053         uint16_t RPCa = payload[0];
0054         uint16_t RPCb = payload[1];
0055         uint16_t RPCc = payload[2];
0056         uint16_t RPCd = payload[3];
0057 
0058         // Check Format
0059         if (GetHexBits(RPCa, 15, 15) != 0) {
0060           errors += 1;
0061           edm::LogError("L1T|EMTF") << "Format identifier bits in RPCa are incorrect";
0062         }
0063         if (GetHexBits(RPCb, 15, 15) != 0) {
0064           errors += 1;
0065           edm::LogError("L1T|EMTF") << "Format identifier bits in RPCb are incorrect";
0066         }
0067         if (GetHexBits(RPCc, 15, 15) != 1) {
0068           errors += 1;
0069           edm::LogError("L1T|EMTF") << "Format identifier bits in RPCc are incorrect";
0070         }
0071         if (GetHexBits(RPCd, 15, 15) != 0) {
0072           errors += 1;
0073           edm::LogError("L1T|EMTF") << "Format identifier bits in RPCd are incorrect";
0074         }
0075 
0076         return errors;
0077       }
0078 
0079       // Converts station, ring, sector, subsector, neighbor, and segment from the RPC output
0080       void convert_RPC_location(int& station,
0081                                 int& ring,
0082                                 int& sector,
0083                                 int& subsector,
0084                                 int& neighbor,
0085                                 int& segment,
0086                                 const int evt_sector,
0087                                 const int frame,
0088                                 const int word,
0089                                 const int link) {
0090         station = -99;
0091         ring = -99;
0092         sector = -99;
0093         subsector = -99;
0094         neighbor = -99;
0095         segment = -99;
0096 
0097         // "link" is the "link index" field (0 - 6) in the EMTF DAQ document, not "link number" (1 - 7)
0098         // Neighbor indicated by link == 0
0099         sector = (link != 0 ? evt_sector : (evt_sector == 1 ? 6 : evt_sector - 1));
0100         subsector = (link != 0 ? link : 6);
0101         neighbor = (link == 0 ? 1 : 0);
0102         segment = (word % 2);
0103 
0104         if (frame == 0) {
0105           station = (word < 2 ? 1 : 2);
0106           ring = 2;
0107         } else if (frame == 1) {
0108           station = 3;
0109           ring = (word < 2 ? 2 : 3);
0110         } else if (frame == 2) {
0111           station = 4;
0112           ring = (word < 2 ? 2 : 3);
0113         }
0114       }  // End function: void convert_RPC_location()
0115 
0116       bool RPCBlockUnpacker::unpack(const Block& block, UnpackerCollections* coll) {
0117         // std::cout << "Inside EMTFBlockRPC.cc: unpack" << std::endl;
0118 
0119         // Get the payload for this block, made up of 16-bit words (0xffff)
0120         // Format defined in MTF7Payload::getBlock() in src/Block.cc
0121         // payload[0] = bits 0-15, payload[1] = 16-31, payload[3] = 32-47, etc.
0122         auto payload = block.payload();
0123 
0124         // Run 3 has a different EMTF DAQ output format since August 26th
0125         // Computed as (Year - 2000)*2^9 + Month*2^5 + Day (see Block.cc and EMTFBlockTrailers.cc)
0126         bool run3_DAQ_format =
0127             (getAlgoVersion() >=
0128              11546);  // Firmware from 26.08.22 which enabled new Run 3 DAQ format for RPCs - EY 13.09.22
0129         bool reducedDAQWindow =
0130             (getAlgoVersion() >=
0131              11656);  // Firmware from 08.12.22 which is used as a flag for new reduced readout window - EY 01.03.23
0132 
0133         int nTPs = run3_DAQ_format ? 2 : 1;
0134 
0135         // Check Format of Payload
0136         l1t::emtf::RPC RPC_;
0137         for (int err = 0; err < checkFormat(block); err++)
0138           RPC_.add_format_error();
0139 
0140         // Assign payload to 16-bit words
0141         uint16_t RPCa = payload[0];
0142         uint16_t RPCb = payload[1];
0143         uint16_t RPCc = payload[2];
0144         uint16_t RPCd = payload[3];
0145 
0146         // If there are 2 TPs in the block we fill them 1 by 1
0147         for (int i = 1; i <= nTPs; i++) {
0148           // res is a pointer to a collection of EMTFDaqOut class objects
0149           // There is one EMTFDaqOut for each MTF7 (60 deg. sector) in the event
0150           EMTFDaqOutCollection* res;
0151           res = static_cast<EMTFCollections*>(coll)->getEMTFDaqOuts();
0152           int iOut = res->size() - 1;
0153 
0154           EMTFHitCollection* res_hit;
0155           res_hit = static_cast<EMTFCollections*>(coll)->getEMTFHits();
0156           EMTFHit Hit_;
0157 
0158           CPPFDigiCollection* res_CPPF;
0159           res_CPPF = static_cast<EMTFCollections*>(coll)->getEMTFCPPFs();
0160 
0161           ////////////////////////////
0162           // Unpack the RPC Data Record
0163           ////////////////////////////
0164 
0165           if (run3_DAQ_format) {  // Run 3 DAQ format has 2 TPs per block
0166             if (i == 1) {
0167               RPC_.set_phi(GetHexBits(RPCa, 0, 10));
0168               RPC_.set_word(GetHexBits(RPCa, 11, 12));
0169               RPC_.set_frame(GetHexBits(RPCa, 13, 14));
0170 
0171               if (reducedDAQWindow)  // reduced DAQ window is used only after run3 DAQ format
0172                 RPC_.set_tbin(GetHexBits(RPCb, 0, 2) + 1);
0173               else
0174                 RPC_.set_tbin(GetHexBits(RPCb, 0, 2));
0175               RPC_.set_vp(GetHexBits(RPCb, 3, 3));
0176               RPC_.set_theta(GetHexBits(RPCb, 4, 8));
0177               RPC_.set_bc0(GetHexBits(RPCb, 9, 9));
0178               RPC_.set_link(GetHexBits(RPCb, 12, 14));  // Link index (0 - 6); link number runs 1 - 7
0179             } else if (i == 2) {
0180               RPC_.set_phi(GetHexBits(RPCc, 0, 10));
0181               RPC_.set_word(GetHexBits(RPCc, 11, 12));
0182               RPC_.set_frame(GetHexBits(RPCc, 13, 14));
0183 
0184               if (reducedDAQWindow)  // reduced DAQ window is used only after run3 DAQ format
0185                 RPC_.set_tbin(GetHexBits(RPCd, 0, 2) + 1);
0186               else
0187                 RPC_.set_tbin(GetHexBits(RPCd, 0, 2));
0188               RPC_.set_vp(GetHexBits(RPCd, 3, 3));
0189               RPC_.set_theta(GetHexBits(RPCd, 4, 8));
0190               RPC_.set_bc0(GetHexBits(RPCd, 9, 9));
0191               RPC_.set_link(GetHexBits(RPCd, 12, 14));  // Link index (0 - 6); link number runs 1 - 7
0192             }
0193           } else {  // Run 2 DAQ format
0194             RPC_.set_phi(GetHexBits(RPCa, 0, 10));
0195 
0196             RPC_.set_theta(GetHexBits(RPCb, 0, 4));
0197             RPC_.set_word(GetHexBits(RPCb, 8, 9));
0198             RPC_.set_frame(GetHexBits(RPCb, 10, 11));
0199             RPC_.set_link(GetHexBits(RPCb, 12, 14));  // Link index (0 - 6); link number runs 1 - 7
0200 
0201             RPC_.set_rpc_bxn(GetHexBits(RPCc, 0, 11));
0202             RPC_.set_bc0(GetHexBits(RPCc, 14, 14));
0203 
0204             RPC_.set_tbin(GetHexBits(RPCd, 0, 2));
0205             RPC_.set_vp(GetHexBits(RPCd, 3, 3));
0206 
0207             // RPC_.set_dataword            ( uint64_t dataword);
0208           }
0209 
0210           // Convert specially-encoded RPC quantities
0211           int _station, _ring, _sector, _subsector, _neighbor, _segment;
0212           convert_RPC_location(_station,
0213                                _ring,
0214                                _sector,
0215                                _subsector,
0216                                _neighbor,
0217                                _segment,
0218                                (res->at(iOut)).PtrEventHeader()->Sector(),
0219                                RPC_.Frame(),
0220                                RPC_.Word(),
0221                                RPC_.Link());
0222 
0223           // Rotate by 20 deg to match RPC convention in CMSSW
0224           int _sector_rpc = (_subsector < 5) ? _sector : (_sector % 6) + 1;
0225           // Rotate by 2 to match RPC convention in CMSSW (RPCDetId.h)
0226           int _subsector_rpc = ((_subsector + 1) % 6) + 1;
0227           // Define chamber number
0228           int _chamber = (_sector_rpc - 1) * 6 + _subsector_rpc;
0229           // Define CSC-like subsector
0230           int _subsector_csc = (_station != 1) ? 0 : ((_chamber % 6 > 2) ? 1 : 2);
0231 
0232           Hit_.set_station(_station);
0233           Hit_.set_ring(_ring);
0234           Hit_.set_sector(_sector);
0235           Hit_.set_subsector(_subsector_csc);
0236           Hit_.set_sector_RPC(_sector_rpc);
0237           Hit_.set_subsector_RPC(_subsector_rpc);
0238           Hit_.set_chamber(_chamber);
0239           Hit_.set_neighbor(_neighbor);
0240           Hit_.set_pc_segment(_segment);
0241           Hit_.set_fs_segment(_segment);
0242           Hit_.set_bt_segment(_segment);
0243 
0244           // Fill the EMTFHit
0245           ImportRPC(Hit_, RPC_, (res->at(iOut)).PtrEventHeader()->Endcap(), (res->at(iOut)).PtrEventHeader()->Sector());
0246 
0247           // Set the stub number for this hit
0248           // Each chamber can send up to 2 stubs per BX
0249           // Also count stubs in corresponding CSC chamber; RPC hit counting is on top of LCT counting
0250           Hit_.set_stub_num(0);
0251           // See if matching hit is already in event record
0252           bool exact_duplicate = false;
0253           for (auto const& iHit : *res_hit) {
0254             if (Hit_.BX() == iHit.BX() && Hit_.Endcap() == iHit.Endcap() && Hit_.Station() == iHit.Station() &&
0255                 Hit_.Chamber() == iHit.Chamber()) {
0256               if ((iHit.Is_CSC() == 1 && iHit.Ring() == 2) ||
0257                   (iHit.Is_RPC() == 1)) {  // RPC rings 2 and 3 both map to CSC ring 2
0258                 if (Hit_.Neighbor() == iHit.Neighbor()) {
0259                   Hit_.set_stub_num(Hit_.Stub_num() + 1);
0260                   if (iHit.Is_RPC() == 1 && iHit.Ring() == Hit_.Ring() && iHit.Theta_fp() == Hit_.Theta_fp() &&
0261                       iHit.Phi_fp() == Hit_.Phi_fp()) {
0262                     exact_duplicate = true;
0263                   }
0264                 }
0265               }
0266             }
0267           }  // End loop: for (auto const & iHit : *res_hit)
0268 
0269           // 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
0270           if (Hit_.BX() > 3 or Hit_.BX() < -3) {
0271             edm::LogWarning("L1T|EMTF") << "EMTF unpacked CPPF digis with out-of-range BX! BX " << Hit_.BX()
0272                                         << ", endcap " << Hit_.Endcap() << ", station " << Hit_.Station() << ", sector "
0273                                         << Hit_.Sector() << ", neighbor " << Hit_.Neighbor() << ", ring " << Hit_.Ring()
0274                                         << ", chamber " << Hit_.Chamber() << ", theta " << Hit_.Theta_fp() / 4
0275                                         << ", phi " << Hit_.Phi_fp() / 4 << std::endl;
0276             return true;
0277           }
0278 
0279           if (exact_duplicate)
0280             edm::LogWarning("L1T|EMTF") << "EMTF unpacked duplicate CPPF digis: BX " << Hit_.BX() << ", endcap "
0281                                         << Hit_.Endcap() << ", station " << Hit_.Station() << ", sector "
0282                                         << Hit_.Sector() << ", neighbor " << Hit_.Neighbor() << ", ring " << Hit_.Ring()
0283                                         << ", chamber " << Hit_.Chamber() << ", theta " << Hit_.Theta_fp() / 4
0284                                         << ", phi " << Hit_.Phi_fp() / 4 << std::endl;
0285 
0286           (res->at(iOut)).push_RPC(RPC_);
0287           if (!exact_duplicate and Hit_.Valid())
0288             res_hit->push_back(Hit_);
0289           if (!exact_duplicate and Hit_.Valid())
0290             res_CPPF->push_back(Hit_.CreateCPPFDigi());
0291         }
0292 
0293         // Finished with unpacking one RPC Data Record
0294         return true;
0295 
0296       }  // End bool RPCBlockUnpacker::unpack
0297 
0298       // bool RPCBlockPacker::pack(const Block& block, UnpackerCollections *coll) {
0299       //    std::cout << "Inside RPCBlockPacker::pack" << std::endl;
0300       //    return true;
0301       // } // End bool RPCBlockPacker::pack
0302 
0303     }  // End namespace emtf
0304   }    // End namespace stage2
0305 }  // End namespace l1t
0306 
0307 DEFINE_L1T_UNPACKER(l1t::stage2::emtf::RPCBlockUnpacker);
0308 // DEFINE_L1T_PACKER(l1t::stage2::RPCBlockPacker);