Back to home page

Project CMSSW displayed by LXR

 
 

    


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

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 == 4
0108         sector = (link != 4 ? evt_sector : (evt_sector == 1 ? 6 : evt_sector - 1));
0109         subsector = (link < 4 ? link : (link == 4 ? 5 : link - 1));
0110         neighbor = (link == 4 ? 1 : 0);
0111         layer = (cluster_id / 4) % 2 + 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           GEMPadDigiClusterCollection* res_GEM;
0166           res_GEM = static_cast<EMTFCollections*>(coll)->getEMTFGEMPadClusters();
0167 
0168           ////////////////////////////
0169           // Unpack the GEM Data Record
0170           ////////////////////////////
0171           if (run3_DAQ_format) {  // Run 3 DAQ format has 2 TPs per block
0172             if (i == 1) {         // GE1/1 layer 1, GE2/1 not know yet
0173               GEM_.set_pad(GetHexBits(GEMa, 0, 8));
0174               GEM_.set_partition(GetHexBits(GEMa, 9, 11));
0175               GEM_.set_cluster_size(GetHexBits(GEMa, 12, 14));
0176 
0177               if (reducedDAQWindow)  // reduced DAQ window is used only after run3 DAQ format
0178                 GEM_.set_tbin(GetHexBits(GEMb, 0, 2) + 1);
0179               else
0180                 GEM_.set_tbin(GetHexBits(GEMb, 0, 2));
0181               GEM_.set_vp(GetHexBits(GEMb, 3, 3));
0182               GEM_.set_bc0(GetHexBits(GEMb, 7, 7));
0183               GEM_.set_cluster_id(GetHexBits(GEMb, 8, 11));
0184               GEM_.set_link(GetHexBits(GEMb, 12, 14));
0185             } else if (i == 2) {  // GE1/1 layer2, GE2/1 not know yet
0186               GEM_.set_pad(GetHexBits(GEMc, 0, 8));
0187               GEM_.set_partition(GetHexBits(GEMc, 9, 11));
0188               GEM_.set_cluster_size(GetHexBits(GEMc, 12, 14));
0189 
0190               if (reducedDAQWindow)  // reduced DAQ window is used only after run3 DAQ format
0191                 GEM_.set_tbin(GetHexBits(GEMd, 0, 2) + 1);
0192               else
0193                 GEM_.set_tbin(GetHexBits(GEMd, 0, 2));
0194               GEM_.set_vp(GetHexBits(GEMd, 3, 3));
0195               GEM_.set_bc0(GetHexBits(GEMd, 7, 7));
0196               GEM_.set_cluster_id(GetHexBits(GEMd, 8, 11));
0197               GEM_.set_link(GetHexBits(GEMd, 12, 14));
0198             }
0199           } else {
0200             GEM_.set_pad(GetHexBits(GEMa, 0, 8));
0201             GEM_.set_partition(GetHexBits(GEMa, 9, 11));
0202             GEM_.set_cluster_size(GetHexBits(GEMa, 12, 14));
0203 
0204             GEM_.set_cluster_id(GetHexBits(GEMb, 8, 11));
0205             GEM_.set_link(GetHexBits(GEMb, 12, 14));
0206 
0207             GEM_.set_gem_bxn(GetHexBits(GEMc, 0, 11));
0208             GEM_.set_bc0(GetHexBits(GEMc, 14, 14));
0209 
0210             GEM_.set_tbin(GetHexBits(GEMd, 0, 2));
0211             GEM_.set_vp(GetHexBits(GEMd, 3, 3));
0212 
0213             // GEM_.set_dataword(uint64_t dataword);
0214           }
0215 
0216           // Convert specially-encoded GEM quantities
0217           int _station, _ring, _sector, _subsector, _neighbor, _layer;
0218           convert_GEM_location(_station,
0219                                _ring,
0220                                _sector,
0221                                _subsector,
0222                                _neighbor,
0223                                _layer,
0224                                (res->at(iOut)).PtrEventHeader()->Sector(),
0225                                GEM_.ClusterID(),
0226                                GEM_.Link());
0227 
0228           int _sector_gem = _sector;
0229           int _subsector_gem = _subsector;
0230           int _chamber = ((_sector_gem - 1) * 6 + _subsector_gem + 2) % 36 + 1;
0231           // Define CSC-like subsector)
0232           int _subsector_csc = (_station != 1) ? 0 : ((_chamber % 6 > 2) ? 1 : 2);
0233 
0234           Hit_.set_station(_station);
0235           Hit_.set_ring(_ring);
0236           Hit_.set_sector(_sector);
0237           Hit_.set_subsector(_subsector_csc);
0238           Hit_.set_chamber(_chamber);
0239           Hit_.set_neighbor(_neighbor);
0240           Hit_.set_layer(_layer);
0241 
0242           // Fill the EMTFHit
0243           ImportGEM(Hit_, GEM_, (res->at(iOut)).PtrEventHeader()->Endcap(), (res->at(iOut)).PtrEventHeader()->Sector());
0244 
0245           // Set the stub number for this hit
0246           // Each GEM superchamber can send up to 8 clusters per layer per BX
0247           // Also count stubs in corresponding CSC chamber; GEM hit counting is on top of LCT counting
0248           Hit_.set_stub_num(0);
0249           // See if matching hit is already in event record
0250           bool exact_duplicate = false;
0251           for (auto const& iHit : *res_hit) {
0252             if (Hit_.BX() == iHit.BX() && Hit_.Endcap() == iHit.Endcap() && Hit_.Station() == iHit.Station() &&
0253                 Hit_.Chamber() == iHit.Chamber()) {
0254               if ((iHit.Is_CSC() == 1 && iHit.Ring() == 2) ||
0255                   (iHit.Is_GEM() == 1)) {  // Copied from RPC, but GEM has no ring 2/3...
0256                 if (Hit_.Neighbor() == iHit.Neighbor()) {
0257                   Hit_.set_stub_num(Hit_.Stub_num() + 1);
0258                   if (iHit.Is_GEM() == 1 && iHit.Ring() == Hit_.Ring() && iHit.Roll() == Hit_.Roll() &&
0259                       iHit.Pad() == Hit_.Pad()) {
0260                     exact_duplicate = true;
0261                   }
0262                 }
0263               }
0264             }
0265           }  // End loop: for (auto const & iHit : *res_hit)
0266 
0267           // 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
0268           if (Hit_.BX() > 3 or Hit_.BX() < -3) {
0269             edm::LogWarning("L1T|EMTF") << "EMTF unpacked  GEM digis with out-of-range BX! BX " << Hit_.BX()
0270                                         << ", endcap " << Hit_.Endcap() << ", station " << Hit_.Station()
0271                                         << ", neighbor " << Hit_.Neighbor() << ", ring " << Hit_.Ring() << ", chamber "
0272                                         << Hit_.Chamber() << ", roll " << Hit_.Roll() << ", pad " << Hit_.Pad()
0273                                         << std::endl;
0274             return true;
0275           }
0276 
0277           // TODO: Re-enable once GEM TP data format is fixed
0278           // if (exact_duplicate)
0279           //   edm::LogWarning("L1T|EMTF") << "EMTF unpacked duplicate GEM digis: BX " << Hit_.BX() << ", endcap "
0280           //                               << Hit_.Endcap() << ", station " << Hit_.Station() << ", neighbor "
0281           //                               << Hit_.Neighbor() << ", ring " << Hit_.Ring() << ", chamber " << Hit_.Chamber()
0282           //                               << ", roll " << Hit_.Roll() << ", pad " << Hit_.Pad() << std::endl;
0283 
0284           (res->at(iOut)).push_GEM(GEM_);
0285           if (!exact_duplicate and Hit_.Valid())
0286             res_hit->push_back(Hit_);
0287 
0288           if (!exact_duplicate and Hit_.Valid())
0289             res_GEM->insertDigi(Hit_.GEM_DetId(), Hit_.CreateGEMPadDigiCluster());
0290 
0291           // Finished with unpacking one GEM Data Record
0292         }
0293         return true;
0294 
0295       }  // End bool GEMBlockUnpacker::unpack
0296 
0297       // bool GEMBlockPacker::pack(const Block& block, UnpackerCollections *coll) {
0298       //    std::cout << "Inside GEMBlockPacker::pack" << std::endl;
0299       //    return true;
0300       // } // End bool GEMBlockPacker::pack
0301 
0302     }  // End namespace emtf
0303   }  // End namespace stage2
0304 }  // End namespace l1t
0305 
0306 DEFINE_L1T_UNPACKER(l1t::stage2::emtf::GEMBlockUnpacker);
0307 // DEFINE_L1T_PACKER(l1t::stage2::emtf::GEMBlockPacker);