Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 // -*- C++ -*-
0002 //
0003 // Package:    EventFilter/L1TXRawToDigi
0004 // Class:      L1TCaloLayer1RawToDigi
0005 //
0006 /**\class L1TCaloLayer1RawToDigi L1TCaloLayer1RawToDigi.cc EventFilter/L1TCaloLayer1RawToDigi/plugins/L1TCaloLayer1RawToDigi.cc
0007 
0008    Description: Raw data unpacker for Layer-1 of Level-1 Calorimeter Trigger
0009 
0010    Implementation: This is meant to be simple and straight-forward.  
0011        Potential complications due to any changes in firmware are not foreseen.
0012        It is assumed that if there are major changes, which is unlikely, there 
0013        will be a new unpacker written to deal with that.
0014 
0015 */
0016 //
0017 // Original Author:  Sridhara Rao Dasu
0018 //         Created:  Sun, 13 Sep 2015 00:31:25 GMT
0019 //
0020 //
0021 
0022 // system include files
0023 #include <memory>
0024 
0025 // user include files
0026 #include "FWCore/Framework/interface/Frameworkfwd.h"
0027 #include "FWCore/Framework/interface/stream/EDProducer.h"
0028 #include "FWCore/Framework/interface/MakerMacros.h"
0029 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0030 #include "FWCore/MessageLogger/interface/MessageDrop.h"
0031 
0032 #include "FWCore/Framework/interface/Event.h"
0033 
0034 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0035 #include "FWCore/Utilities/interface/StreamID.h"
0036 
0037 // Raw data collection headers
0038 #include "DataFormats/FEDRawData/interface/FEDRawDataCollection.h"
0039 #include "DataFormats/FEDRawData/interface/FEDHeader.h"
0040 #include "DataFormats/FEDRawData/interface/FEDTrailer.h"
0041 
0042 #include "DataFormats/EcalDigi/interface/EcalDigiCollections.h"
0043 #include "DataFormats/EcalDigi/interface/EcalTriggerPrimitiveDigi.h"
0044 #include "DataFormats/EcalDigi/interface/EcalTriggerPrimitiveSample.h"
0045 
0046 #include "DataFormats/EcalDetId/interface/EcalTrigTowerDetId.h"
0047 
0048 #include "DataFormats/HcalDigi/interface/HcalDigiCollections.h"
0049 #include "DataFormats/HcalDigi/interface/HcalTriggerPrimitiveDigi.h"
0050 #include "DataFormats/HcalDigi/interface/HcalTriggerPrimitiveSample.h"
0051 
0052 #include "DataFormats/HcalDetId/interface/HcalTrigTowerDetId.h"
0053 
0054 #include "DataFormats/L1CaloTrigger/interface/L1CaloCollections.h"
0055 #include "DataFormats/L1CaloTrigger/interface/L1CaloRegion.h"
0056 
0057 #include "EventFilter/L1TXRawToDigi/interface/UCTDAQRawData.h"
0058 #include "EventFilter/L1TXRawToDigi/interface/UCTAMCRawData.h"
0059 #include "EventFilter/L1TXRawToDigi/interface/UCTCTP7RawData.h"
0060 
0061 using namespace edm;
0062 
0063 //
0064 // class declaration
0065 //
0066 
0067 class L1TCaloLayer1RawToDigi : public stream::EDProducer<> {
0068 public:
0069   explicit L1TCaloLayer1RawToDigi(const ParameterSet&);
0070 
0071   static void fillDescriptions(ConfigurationDescriptions& descriptions);
0072 
0073 private:
0074   void produce(Event&, const EventSetup&) override;
0075 
0076   void makeECalTPGs(uint32_t lPhi, UCTCTP7RawData& ctp7Data, std::unique_ptr<EcalTrigPrimDigiCollection>& ecalTPGs);
0077 
0078   void makeHCalTPGs(uint32_t lPhi, UCTCTP7RawData& ctp7Data, std::unique_ptr<HcalTrigPrimDigiCollection>& hcalTPGs);
0079 
0080   void makeHFTPGs(uint32_t lPhi, UCTCTP7RawData& ctp7Data, std::unique_ptr<HcalTrigPrimDigiCollection>& hcalTPGs);
0081 
0082   void makeRegions(uint32_t lPhi, UCTCTP7RawData& ctp7Data, std::unique_ptr<L1CaloRegionCollection>& regions);
0083 
0084   // ----------member data ---------------------------
0085 
0086   InputTag fedRawDataLabel;
0087   std::vector<int> fedIDs;
0088 
0089   uint32_t event;
0090 
0091   bool verbose;
0092 };
0093 
0094 //
0095 // constants, enums and typedefs
0096 //
0097 
0098 //
0099 // static data member definitions
0100 //
0101 
0102 //
0103 // constructors and destructor
0104 //
0105 L1TCaloLayer1RawToDigi::L1TCaloLayer1RawToDigi(const ParameterSet& iConfig)
0106     : fedRawDataLabel(iConfig.getParameter<InputTag>("fedRawDataLabel")),
0107       fedIDs(iConfig.getParameter<std::vector<int> >("FEDIDs")),
0108       event(0),
0109       verbose(iConfig.getParameter<bool>("verbose")) {
0110   produces<EcalTrigPrimDigiCollection>();
0111   produces<HcalTrigPrimDigiCollection>();
0112   produces<L1CaloRegionCollection>();
0113 
0114   consumes<FEDRawDataCollection>(fedRawDataLabel);
0115 }
0116 
0117 //
0118 // member functions
0119 //
0120 
0121 // ------------ method called to produce the data  ------------
0122 void L1TCaloLayer1RawToDigi::produce(Event& iEvent, const EventSetup& iSetup) {
0123   using namespace edm;
0124   using namespace std;
0125 
0126   Handle<FEDRawDataCollection> fedRawDataCollection;
0127   iEvent.getByLabel(fedRawDataLabel, fedRawDataCollection);
0128 
0129   std::unique_ptr<EcalTrigPrimDigiCollection> ecalTPGs(new EcalTrigPrimDigiCollection);
0130   std::unique_ptr<HcalTrigPrimDigiCollection> hcalTPGs(new HcalTrigPrimDigiCollection);
0131   std::unique_ptr<L1CaloRegionCollection> regions(new L1CaloRegionCollection);
0132 
0133   // if raw data collection is present, check the headers and do the unpacking
0134   if (fedRawDataCollection.isValid()) {
0135     for (uint32_t i = 0; i < fedIDs.size(); i++) {
0136       uint32_t fed = fedIDs[i];
0137 
0138       const FEDRawData& fedRawData = fedRawDataCollection->FEDData(fed);
0139 
0140       //Check FED size
0141       if (verbose)
0142         LogDebug("L1TCaloLayer1RawToDigi")
0143             << "Upacking FEDRawData for fed " << std::dec << fed << " of size " << fedRawData.size();
0144 
0145       const uint64_t* fedRawDataArray = (const uint64_t*)fedRawData.data();
0146 
0147       if (fedRawData.size() == 0 || fedRawDataArray == nullptr) {
0148         LogDebug("L1TCaloLayer1RawToDigi") << "Could not load FED data for " << fed << ", putting empty collections!";
0149         continue;
0150       }
0151 
0152       UCTDAQRawData daqData(fedRawDataArray);
0153       if (verbose && event < 5)
0154         daqData.print();
0155       for (uint32_t i = 0; i < daqData.nAMCs(); i++) {
0156         UCTAMCRawData amcData(daqData.amcPayload(i));
0157         if (verbose && event < 5) {
0158           LogDebug("L1TCaloLayer1") << endl;
0159           amcData.print();
0160           LogDebug("L1TCaloLayer1") << endl;
0161         }
0162         uint32_t lPhi = amcData.layer1Phi();
0163         UCTCTP7RawData ctp7Data(amcData.payload());
0164         if (verbose && event < 5)
0165           ctp7Data.print();
0166         if (verbose && event < 5)
0167           LogDebug("L1TCaloLayer1") << endl;
0168         makeECalTPGs(lPhi, ctp7Data, ecalTPGs);
0169         makeHCalTPGs(lPhi, ctp7Data, hcalTPGs);
0170         // Note: HF TPGs are added at the tail of other TPGs
0171         makeHFTPGs(lPhi, ctp7Data, hcalTPGs);
0172         makeRegions(lPhi, ctp7Data, regions);
0173       }
0174     }
0175 
0176   } else {
0177     LogError("L1T") << "Cannot unpack: no collection found";
0178 
0179     return;
0180   }
0181 
0182   iEvent.put(std::move(ecalTPGs));
0183   iEvent.put(std::move(hcalTPGs));
0184   iEvent.put(std::move(regions));
0185 
0186   event++;
0187   if (verbose && event == 5)
0188     LogDebug("L1TCaloLayer1") << "L1TCaloLayer1RawToDigi: Goodbye! Tired of printing junk" << endl;
0189 }
0190 
0191 void L1TCaloLayer1RawToDigi::makeECalTPGs(uint32_t lPhi,
0192                                           UCTCTP7RawData& ctp7Data,
0193                                           std::unique_ptr<EcalTrigPrimDigiCollection>& ecalTPGs) {
0194   UCTCTP7RawData::CaloType cType = UCTCTP7RawData::EBEE;
0195   for (uint32_t iPhi = 0; iPhi < 4; iPhi++) {  // Loop over all four phi divisions on card
0196     int cPhi = -1 + lPhi * 4 + iPhi;           // Calorimeter phi index
0197     if (cPhi == 0)
0198       cPhi = 72;
0199     else if (cPhi == -1)
0200       cPhi = 71;
0201     else if (cPhi < -1) {
0202       LogError("L1TCaloLayer1RawToDigi") << "L1TCaloLayer1RawToDigi: Major error in makeECalTPGs" << std::endl;
0203       return;
0204     }
0205     for (int cEta = -28; cEta <= 28; cEta++) {  // Calorimeter Eta indices (HB/HE for now)
0206       if (cEta != 0) {                          // Calorimeter eta = 0 is invalid
0207         bool negativeEta = false;
0208         if (cEta < 0)
0209           negativeEta = true;
0210         uint32_t iEta = abs(cEta);
0211         // This code is fragile! Note that towerDatum is packed as is done in EcalTriggerPrimitiveSample
0212         // Bottom 8-bits are ET
0213         // Then finegrain feature bit
0214         // Then three bits have ttBits, which I have no clue about (not available on ECAL links so not set)
0215         // Then there is a spare FG Veto bit, which is used for L1 spike detection (not available on ECAL links so not set)
0216         // Top three bits seem to be unused. So, we steal those to set the tower masking, link masking and link status information
0217         // To decode these custom three bits use ((EcalTriggerPrimitiveSample::raw() >> 13) & 0x7)
0218         uint32_t towerDatum = ctp7Data.getET(cType, negativeEta, iEta, iPhi);
0219         if (ctp7Data.getFB(cType, negativeEta, iEta, iPhi) != 0)
0220           towerDatum |= 0x0100;
0221         if (ctp7Data.isTowerMasked(cType, negativeEta, iEta, iPhi))
0222           towerDatum |= 0x2000;
0223         if (ctp7Data.isLinkMasked(cType, negativeEta, iEta, iPhi))
0224           towerDatum |= 0x4000;
0225         if (ctp7Data.isLinkMisaligned(cType, negativeEta, iEta, iPhi) ||
0226             ctp7Data.isLinkInError(cType, negativeEta, iEta, iPhi) ||
0227             ctp7Data.isLinkDown(cType, negativeEta, iEta, iPhi))
0228           towerDatum |= 0x8000;
0229         EcalTriggerPrimitiveSample sample(towerDatum);
0230         int zSide = cEta / ((int)iEta);
0231         // As far as I can tell, the ECal unpacker only uses barrel and endcap IDs, never EcalTriggerTower
0232         const EcalSubdetector ecalTriggerTower =
0233             (iEta > 17) ? EcalSubdetector::EcalEndcap : EcalSubdetector::EcalBarrel;
0234         EcalTrigTowerDetId id(zSide, ecalTriggerTower, iEta, cPhi);
0235         EcalTriggerPrimitiveDigi tpg(id);
0236         tpg.setSize(1);
0237         tpg.setSample(0, sample);
0238         ecalTPGs->push_back(tpg);
0239       }
0240     }
0241   }
0242 }
0243 
0244 void L1TCaloLayer1RawToDigi::makeHCalTPGs(uint32_t lPhi,
0245                                           UCTCTP7RawData& ctp7Data,
0246                                           std::unique_ptr<HcalTrigPrimDigiCollection>& hcalTPGs) {
0247   UCTCTP7RawData::CaloType cType = UCTCTP7RawData::HBHE;
0248   for (uint32_t iPhi = 0; iPhi < 4; iPhi++) {  // Loop over all four phi divisions on card
0249     int cPhi = -1 + lPhi * 4 + iPhi;           // Calorimeter phi index
0250     if (cPhi == 0)
0251       cPhi = 72;
0252     else if (cPhi == -1)
0253       cPhi = 71;
0254     else if (cPhi < -1) {
0255       LogError("L1TCaloLayer1RawToDigi") << "L1TCaloLayer1RawToDigi: Major error in makeHCalTPGs" << std::endl;
0256       return;
0257     }
0258     for (int cEta = -28; cEta <= 28; cEta++) {  // Calorimeter Eta indices (HB/HE for now)
0259       if (cEta != 0) {                          // Calorimeter eta = 0 is invalid
0260         bool negativeEta = false;
0261         if (cEta < 0)
0262           negativeEta = true;
0263         uint32_t iEta = abs(cEta);
0264         // This code is fragile! Note that towerDatum is packed as is done in HcalTriggerPrimitiveSample
0265         // Bottom 8-bits are ET
0266         // Then feature bit
0267         // The remaining bits are undefined presently
0268         // We use next three bits for link details, which we did not have room in EcalTriggerPrimitiveSample case
0269         // We use next three bits to set the tower masking, link masking and link status information as done for Ecal
0270         // To decode these custom six bits use ((EcalTriggerPrimitiveSample::raw() >> 9) & 0x77)
0271         uint32_t towerDatum = ctp7Data.getET(cType, negativeEta, iEta, iPhi);
0272         if (ctp7Data.getFB(cType, negativeEta, iEta, iPhi) != 0)
0273           towerDatum |= 0x0100;
0274         if (ctp7Data.isLinkMisaligned(cType, negativeEta, iEta, iPhi))
0275           towerDatum |= 0x0200;
0276         if (ctp7Data.isLinkInError(cType, negativeEta, iEta, iPhi))
0277           towerDatum |= 0x0400;
0278         if (ctp7Data.isLinkDown(cType, negativeEta, iEta, iPhi))
0279           towerDatum |= 0x0800;
0280         if (ctp7Data.isTowerMasked(cType, negativeEta, iEta, iPhi))
0281           towerDatum |= 0x2000;
0282         if (ctp7Data.isLinkMasked(cType, negativeEta, iEta, iPhi))
0283           towerDatum |= 0x4000;
0284         if (ctp7Data.isLinkMisaligned(cType, negativeEta, iEta, iPhi) ||
0285             ctp7Data.isLinkInError(cType, negativeEta, iEta, iPhi) ||
0286             ctp7Data.isLinkDown(cType, negativeEta, iEta, iPhi))
0287           towerDatum |= 0x8000;
0288         HcalTriggerPrimitiveSample sample(towerDatum);
0289         HcalTrigTowerDetId id(cEta, cPhi);
0290         HcalTriggerPrimitiveDigi tpg(id);
0291         tpg.setSize(1);
0292         tpg.setSample(0, sample);
0293         hcalTPGs->push_back(tpg);
0294       }
0295     }
0296   }
0297 }
0298 
0299 void L1TCaloLayer1RawToDigi::makeHFTPGs(uint32_t lPhi,
0300                                         UCTCTP7RawData& ctp7Data,
0301                                         std::unique_ptr<HcalTrigPrimDigiCollection>& hcalTPGs) {
0302   UCTCTP7RawData::CaloType cType = UCTCTP7RawData::HF;
0303   for (uint32_t side = 0; side <= 1; side++) {
0304     bool negativeEta = false;
0305     if (side == 0)
0306       negativeEta = true;
0307     for (uint32_t iEta = 30; iEta <= 40; iEta++) {
0308       for (uint32_t iPhi = 0; iPhi < 2; iPhi++) {
0309         if (iPhi == 1 && iEta == 40)
0310           iEta = 41;
0311         int cPhi = 1 + lPhi * 4 + iPhi * 2;  // Calorimeter phi index: 1, 3, 5, ... 71
0312         if (iEta == 41)
0313           cPhi -= 2;                  // Last two HF are 3, 7, 11, ...
0314         cPhi = (cPhi + 69) % 72 + 1;  // cPhi -= 2 mod 72
0315         int cEta = iEta;
0316         if (negativeEta)
0317           cEta = -iEta;
0318         // This code is fragile! Note that towerDatum is packed as is done in HcalTriggerPrimitiveSample
0319         // Bottom 8-bits are ET
0320         // Then feature bit
0321         // Then minBias ADC count bit
0322         // The remaining bits are undefined presently
0323         // We use next three bits for link details, which we did not have room in EcalTriggerPrimitiveSample case
0324         // We use next three bits to set the tower masking, link masking and link status information as done for Ecal
0325         // To decode these custom six bits use ((EcalTriggerPrimitiveSample::raw() >> 9) & 0x77)
0326         uint32_t towerDatum = ctp7Data.getET(cType, negativeEta, iEta, iPhi);
0327         towerDatum |= ctp7Data.getFB(cType, negativeEta, iEta, iPhi) << 8;
0328         if (ctp7Data.isLinkMisaligned(cType, negativeEta, iEta, iPhi))
0329           towerDatum |= 0x0400;
0330         if (ctp7Data.isLinkInError(cType, negativeEta, iEta, iPhi))
0331           towerDatum |= 0x0800;
0332         if (ctp7Data.isLinkDown(cType, negativeEta, iEta, iPhi))
0333           towerDatum |= 0x1000;
0334         if (ctp7Data.isTowerMasked(cType, negativeEta, iEta, iPhi))
0335           towerDatum |= 0x2000;
0336         if (ctp7Data.isLinkMasked(cType, negativeEta, iEta, iPhi))
0337           towerDatum |= 0x4000;
0338         if (ctp7Data.isLinkMisaligned(cType, negativeEta, iEta, iPhi) ||
0339             ctp7Data.isLinkInError(cType, negativeEta, iEta, iPhi) ||
0340             ctp7Data.isLinkDown(cType, negativeEta, iEta, iPhi))
0341           towerDatum |= 0x8000;
0342         HcalTriggerPrimitiveSample sample(towerDatum);
0343         HcalTrigTowerDetId id(cEta, cPhi);
0344         id.setVersion(1);  // To not process these 1x1 HF TPGs with RCT
0345         HcalTriggerPrimitiveDigi tpg(id);
0346         tpg.setSize(1);
0347         tpg.setSample(0, sample);
0348         hcalTPGs->push_back(tpg);
0349       }
0350     }
0351   }
0352 }
0353 
0354 void L1TCaloLayer1RawToDigi::makeRegions(uint32_t lPhi,
0355                                          UCTCTP7RawData& ctp7Data,
0356                                          std::unique_ptr<L1CaloRegionCollection>& regions) {
0357   for (uint32_t side = 0; side <= 1; side++) {
0358     bool negativeEta = false;
0359     if (side == 0)
0360       negativeEta = true;
0361     for (uint32_t region = 0; region <= 6; region++) {
0362       uint32_t regionData = ctp7Data.getRegionSummary(negativeEta, region);
0363       uint32_t lEta = 10 - region;  // GCT eta goes 0-21, 0-3 -HF, 4-10 -B/E, 11-17 +B/E, 18-21 +HF
0364       if (!negativeEta)
0365         lEta = region + 11;
0366       regions->push_back(L1CaloRegion((uint16_t)regionData, (unsigned)lEta, (unsigned)lPhi, (int16_t)0));
0367     }
0368   }
0369 }
0370 
0371 // ------------ method fills 'descriptions' with the allowed parameters for the module  ------------
0372 void L1TCaloLayer1RawToDigi::fillDescriptions(ConfigurationDescriptions& descriptions) {
0373   //The following says we do not know what parameters are allowed so do no validation
0374   // Please change this to state exactly what you do use, even if it is no parameters
0375   ParameterSetDescription desc;
0376   desc.setUnknown();
0377   descriptions.addDefault(desc);
0378 }
0379 
0380 //define this as a plug-in
0381 DEFINE_FWK_MODULE(L1TCaloLayer1RawToDigi);