Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 11:00:02

0001 // Code to unpack the "GEM Data Record"
0002 
0003 #include "EventFilter/L1TRawToDigi/plugins/UnpackerFactory.h"
0004 
0005 #include "EMTFCollections.h"
0006 #include "EMTFUnpackerTools.h"
0007 
0008 namespace l1t {
0009   namespace stage2 {
0010     namespace emtf {
0011 
0012       class GEMBlockUnpacker : public Unpacker {
0013       public:
0014         virtual int checkFormat(const Block& block);
0015         // virtual bool checkFormat() override; // Return "false" if block format does not match expected format
0016         bool unpack(const Block& block, UnpackerCollections* coll) override;
0017         // virtual bool packBlock(const Block& block, UnpackerCollections *coll) override;
0018       };
0019 
0020       // class GEMBlockPacker : public Packer {
0021       // public:
0022       //    virtual bool unpack(const Block& block, UnpackerCollections *coll) override;
0023       // };
0024 
0025     }  // namespace emtf
0026   }    // namespace stage2
0027 }  // namespace l1t
0028 
0029 namespace l1t {
0030   namespace stage2 {
0031     namespace emtf {
0032 
0033       int GEMBlockUnpacker::checkFormat(const Block& block) {
0034         auto payload = block.payload();
0035         int errors = 0;
0036 
0037         // Check the number of 16-bit words
0038         if (payload.size() != 4) {
0039           errors += 1;
0040           edm::LogError("L1T|EMTF") << "Payload size in 'GEM Data Record' is different than expected";
0041         }
0042 
0043         // Check that each word is 16 bits
0044         for (size_t i = 0; i < 4; ++i) {
0045           if (GetHexBits(payload[i], 16, 31) != 0) {
0046             errors += 1;
0047             edm::LogError("L1T|EMTF") << "Payload[" << i << "] has more than 16 bits in 'GEM Data Record'";
0048           }
0049         }
0050 
0051         uint16_t GEMa = payload[0];
0052         uint16_t GEMb = payload[1];
0053         uint16_t GEMc = payload[2];
0054         uint16_t GEMd = payload[3];
0055 
0056         // Check Format
0057         if (GetHexBits(GEMa, 15, 15) != 1) {
0058           errors += 1;
0059           edm::LogError("L1T|EMTF") << "Format identifier bits in GEMa are incorrect";
0060         }
0061         if (GetHexBits(GEMb, 15, 15) != 1) {
0062           errors += 1;
0063           edm::LogError("L1T|EMTF") << "Format identifier bits in GEMb are incorrect";
0064         }
0065         if (GetHexBits(GEMc, 15, 15) != 1) {
0066           errors += 1;
0067           edm::LogError("L1T|EMTF") << "Format identifier bits in GEMc are incorrect";
0068         }
0069         if (GetHexBits(GEMd, 15, 15) != 0) {
0070           errors += 1;
0071           edm::LogError("L1T|EMTF") << "Format identifier bits in GEMd are incorrect";
0072         }
0073 
0074         return errors;
0075       }
0076 
0077       /**
0078        * \brief Converts station, ring, sector, subsector, neighbor, and segment from the GEM output
0079        * \param station
0080        * \param ring
0081        * \param sector
0082        * \param subsector
0083        * \param neighbor
0084        * \param segment
0085        * \param evt_sector
0086        * \param frame
0087        * \param word
0088        * \param link is the "link index" field (0 - 6) in the EMTF DAQ document, not "link number" (1 - 7)
0089       */
0090       void convert_GEM_location(int& station,
0091                                 int& ring,
0092                                 int& sector,
0093                                 int& subsector,
0094                                 int& neighbor,
0095                                 int& layer,  // is this correct for the GEM case?
0096                                 const int evt_sector,
0097                                 const int cluster_id,  // used to differentiate between GEM layer 1/2
0098                                 const int link) {
0099         station =
0100             1;  // station is not encoded in the GEM frame for now. Set station = 1 since we only have GE1/1 for Run 3.
0101         ring = 1;  // GEMs are only in GE1/1 and GE2/1
0102         sector = -99;
0103         subsector = -99;
0104         neighbor = -99;
0105         layer = -99;  // the GEM layer is 1 or 2, depending on the cluster ID
0106 
0107         // Neighbor indicated by link == 6
0108         sector = (link != 6 ? evt_sector : (evt_sector == 1 ? 6 : evt_sector - 1));
0109         subsector = (link != 6 ? link : 0);  // TODO: verify subsector 0 in the neighbouring sector?
0110         neighbor = (link == 6 ? 1 : 0);  // TODO: verify that 6 is for the neighbour, not 0 (as written in EMTFBlockRPC)
0111         layer = (cluster_id % 8);        // + 1 if layer should be 1 or 2, otherwise layer is 0 or 1
0112       }
0113 
0114       /**
0115        * \brief Unpack the GEM payload in the EMTF DAQ payload
0116        *
0117        * The GEM payload consists of up to 14 clusters per link (for the two GEM layers)
0118        * 7 links (including neighbour).
0119        * The EMTF firmware packs each cluster word into one 64-bit EMTF record, and
0120        * that is what is unpacked here.
0121        */
0122       bool GEMBlockUnpacker::unpack(const Block& block, UnpackerCollections* coll) {
0123         // std::cout << "Inside EMTFBlockGEM.cc: unpack" << std::endl;
0124 
0125         // Get the payload for this block, made up of 16-bit words (0xffff)
0126         // Format defined in MTF7Payload::getBlock() in src/Block.cc
0127         // payload[0] = bits 0-15, payload[1] = 16-31, payload[3] = 32-47, etc.
0128         auto payload = block.payload();
0129 
0130         // Run 3 has a different EMTF DAQ output format since August 26th
0131         // Computed as (Year - 2000)*2^9 + Month*2^5 + Day (see Block.cc and EMTFBlockTrailers.cc)
0132         bool run3_DAQ_format =
0133             (getAlgoVersion() >=
0134              11546);  // Firmware from 26.08.22 which enabled new Run 3 DAQ format for GEMs - EY 13.09.22
0135         bool reducedDAQWindow =
0136             (getAlgoVersion() >=
0137              11656);  // Firmware from 08.12.22 which is used as a flag for new reduced readout window - EY 01.03.23
0138 
0139         int nTPs = run3_DAQ_format ? 2 : 1;
0140 
0141         // Check Format of Payload
0142         l1t::emtf::GEM GEM_;
0143         for (int err = 0; err < checkFormat(block); ++err) {
0144           GEM_.add_format_error();
0145         }
0146 
0147         // Assign payload to 16-bit words
0148         uint16_t GEMa = payload[0];
0149         uint16_t GEMb = payload[1];
0150         uint16_t GEMc = payload[2];
0151         uint16_t GEMd = payload[3];
0152 
0153         // If there are 2 TPs in the block we fill them 1 by 1
0154         for (int i = 1; i <= nTPs; i++) {
0155           // res is a pointer to a collection of EMTFDaqOut class objects
0156           // There is one EMTFDaqOut for each MTF7 (60 deg. sector) in the event
0157           EMTFDaqOutCollection* res;
0158           res = static_cast<EMTFCollections*>(coll)->getEMTFDaqOuts();
0159           int iOut = res->size() - 1;
0160 
0161           EMTFHitCollection* res_hit;
0162           res_hit = static_cast<EMTFCollections*>(coll)->getEMTFHits();
0163           EMTFHit Hit_;
0164 
0165           // TODO: Verify this is correct for GEM
0166           GEMPadDigiClusterCollection* res_GEM;
0167           res_GEM = static_cast<EMTFCollections*>(coll)->getEMTFGEMPadClusters();
0168 
0169           ////////////////////////////
0170           // Unpack the GEM Data Record
0171           ////////////////////////////
0172           if (run3_DAQ_format) {  // Run 3 DAQ format has 2 TPs per block
0173             if (i == 1) {
0174               GEM_.set_pad(GetHexBits(GEMa, 0, 8));
0175               GEM_.set_partition(GetHexBits(GEMa, 9, 11));
0176               GEM_.set_cluster_size(GetHexBits(GEMa, 12, 14));
0177 
0178               if (reducedDAQWindow)  // reduced DAQ window is used only after run3 DAQ format
0179                 GEM_.set_tbin(GetHexBits(GEMb, 0, 2) + 1);
0180               else
0181                 GEM_.set_tbin(GetHexBits(GEMb, 0, 2));
0182               GEM_.set_vp(GetHexBits(GEMb, 3, 3));
0183               GEM_.set_bc0(GetHexBits(GEMb, 7, 7));
0184               GEM_.set_cluster_id(GetHexBits(GEMb, 8, 11));
0185               GEM_.set_link(GetHexBits(GEMb, 12, 14));
0186             } else if (i == 2) {
0187               GEM_.set_pad(GetHexBits(GEMc, 0, 8));
0188               GEM_.set_partition(GetHexBits(GEMc, 9, 11));
0189               GEM_.set_cluster_size(GetHexBits(GEMc, 12, 14));
0190 
0191               if (reducedDAQWindow)  // reduced DAQ window is used only after run3 DAQ format
0192                 GEM_.set_tbin(GetHexBits(GEMd, 0, 2) + 1);
0193               else
0194                 GEM_.set_tbin(GetHexBits(GEMd, 0, 2));
0195               GEM_.set_vp(GetHexBits(GEMd, 3, 3));
0196               GEM_.set_bc0(GetHexBits(GEMd, 7, 7));
0197               GEM_.set_cluster_id(GetHexBits(GEMd, 8, 11));
0198               GEM_.set_link(GetHexBits(GEMd, 12, 14));
0199             }
0200           } else {
0201             GEM_.set_pad(GetHexBits(GEMa, 0, 8));
0202             GEM_.set_partition(GetHexBits(GEMa, 9, 11));
0203             GEM_.set_cluster_size(GetHexBits(GEMa, 12, 14));
0204 
0205             GEM_.set_cluster_id(GetHexBits(GEMb, 8, 11));
0206             GEM_.set_link(GetHexBits(GEMb, 12, 14));
0207 
0208             GEM_.set_gem_bxn(GetHexBits(GEMc, 0, 11));
0209             GEM_.set_bc0(GetHexBits(GEMc, 14, 14));
0210 
0211             GEM_.set_tbin(GetHexBits(GEMd, 0, 2));
0212             GEM_.set_vp(GetHexBits(GEMd, 3, 3));
0213 
0214             // GEM_.set_dataword(uint64_t dataword);
0215           }
0216 
0217           // Convert specially-encoded GEM quantities
0218           // TODO: is the RPC or CSC method for this function better... - JS 06.07.20
0219           int _station, _ring, _sector, _subsector, _neighbor, _layer;
0220           convert_GEM_location(_station,
0221                                _ring,
0222                                _sector,
0223                                _subsector,
0224                                _neighbor,
0225                                _layer,
0226                                (res->at(iOut)).PtrEventHeader()->Sector(),
0227                                GEM_.ClusterID(),
0228                                GEM_.Link());
0229 
0230           // Rotate by 20 deg to match GEM convention in CMSSW) // FIXME VERIFY
0231           // int _sector_gem = (_subsector < 5) ? _sector : (_sector % 6) + 1; //
0232           int _sector_gem = _sector;
0233           // Rotate by 2 to match GEM convention in CMSSW (GEMDetId.h) // FIXME VERIFY
0234           int _subsector_gem = ((_subsector + 1) % 6) + 1;
0235           // Define chamber number) // FIXME VERIFY
0236           int _chamber = (_sector_gem - 1) * 6 + _subsector_gem;
0237           // Define CSC-like subsector) // FIXME WHY?? VERIFY
0238           int _subsector_csc = (_station != 1) ? 0 : ((_chamber % 6 > 2) ? 1 : 2);
0239 
0240           Hit_.set_station(_station);
0241           Hit_.set_ring(_ring);
0242           Hit_.set_sector(_sector);
0243           Hit_.set_subsector(_subsector_csc);
0244           Hit_.set_chamber(_chamber);
0245           Hit_.set_neighbor(_neighbor);
0246 
0247           // Fill the EMTFHit
0248           ImportGEM(Hit_, GEM_, (res->at(iOut)).PtrEventHeader()->Endcap(), (res->at(iOut)).PtrEventHeader()->Sector());
0249 
0250           // Set the stub number for this hit
0251           // Each chamber can send up to 2 stubs per BX // FIXME is this true for GEM, are stubs relevant for GEMs?
0252           // Also count stubs in corresponding CSC chamber; GEM hit counting is on top of LCT counting
0253           Hit_.set_stub_num(0);
0254           // See if matching hit is already in event record
0255           bool exact_duplicate = false;
0256           for (auto const& iHit : *res_hit) {
0257             if (Hit_.BX() == iHit.BX() && Hit_.Endcap() == iHit.Endcap() && Hit_.Station() == iHit.Station() &&
0258                 Hit_.Chamber() == iHit.Chamber()) {
0259               if ((iHit.Is_CSC() == 1 && iHit.Ring() == 2) ||
0260                   (iHit.Is_GEM() == 1)) {  // Copied from RPC, but GEM has no ring 2/3...
0261                 if (Hit_.Neighbor() == iHit.Neighbor()) {
0262                   Hit_.set_stub_num(Hit_.Stub_num() + 1);
0263                   if (iHit.Is_GEM() == 1 && iHit.Ring() == Hit_.Ring() && iHit.Roll() == Hit_.Roll() &&
0264                       iHit.Pad() == Hit_.Pad()) {
0265                     exact_duplicate = true;
0266                   }
0267                 }
0268               }
0269             }
0270           }  // End loop: for (auto const & iHit : *res_hit)
0271 
0272           // 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
0273           if (Hit_.BX() > 3 or Hit_.BX() < -3) {
0274             edm::LogWarning("L1T|EMTF") << "EMTF unpacked  GEM digis with out-of-range BX! BX " << Hit_.BX()
0275                                         << ", endcap " << Hit_.Endcap() << ", station " << Hit_.Station()
0276                                         << ", neighbor " << Hit_.Neighbor() << ", ring " << Hit_.Ring() << ", chamber "
0277                                         << Hit_.Chamber() << ", roll " << Hit_.Roll() << ", pad " << Hit_.Pad()
0278                                         << std::endl;
0279             return true;
0280           }
0281 
0282           // TODO: Re-enable once GEM TP data format is fixed
0283           // if (exact_duplicate)
0284           //   edm::LogWarning("L1T|EMTF") << "EMTF unpacked duplicate GEM digis: BX " << Hit_.BX() << ", endcap "
0285           //                               << Hit_.Endcap() << ", station " << Hit_.Station() << ", neighbor "
0286           //                               << Hit_.Neighbor() << ", ring " << Hit_.Ring() << ", chamber " << Hit_.Chamber()
0287           //                               << ", roll " << Hit_.Roll() << ", pad " << Hit_.Pad() << std::endl;
0288 
0289           (res->at(iOut)).push_GEM(GEM_);
0290           if (!exact_duplicate and Hit_.Valid())
0291             res_hit->push_back(Hit_);
0292 
0293           if (!exact_duplicate and Hit_.Valid())
0294             res_GEM->insertDigi(Hit_.GEM_DetId(), Hit_.CreateGEMPadDigiCluster());
0295 
0296           // Finished with unpacking one GEM Data Record
0297         }
0298         return true;
0299 
0300       }  // End bool GEMBlockUnpacker::unpack
0301 
0302       // bool GEMBlockPacker::pack(const Block& block, UnpackerCollections *coll) {
0303       //    std::cout << "Inside GEMBlockPacker::pack" << std::endl;
0304       //    return true;
0305       // } // End bool GEMBlockPacker::pack
0306 
0307     }  // End namespace emtf
0308   }    // End namespace stage2
0309 }  // End namespace l1t
0310 
0311 DEFINE_L1T_UNPACKER(l1t::stage2::emtf::GEMBlockUnpacker);
0312 // DEFINE_L1T_PACKER(l1t::stage2::emtf::GEMBlockPacker);