Back to home page

Project CMSSW displayed by LXR

 
 

    


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

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   ~L1TCaloLayer1RawToDigi() override;
0071 
0072   static void fillDescriptions(ConfigurationDescriptions& descriptions);
0073 
0074 private:
0075   void beginStream(StreamID) override;
0076   void produce(Event&, const EventSetup&) override;
0077   void endStream() override;
0078 
0079   void makeECalTPGs(uint32_t lPhi, UCTCTP7RawData& ctp7Data, std::unique_ptr<EcalTrigPrimDigiCollection>& ecalTPGs);
0080 
0081   void makeHCalTPGs(uint32_t lPhi, UCTCTP7RawData& ctp7Data, std::unique_ptr<HcalTrigPrimDigiCollection>& hcalTPGs);
0082 
0083   void makeHFTPGs(uint32_t lPhi, UCTCTP7RawData& ctp7Data, std::unique_ptr<HcalTrigPrimDigiCollection>& hcalTPGs);
0084 
0085   void makeRegions(uint32_t lPhi, UCTCTP7RawData& ctp7Data, std::unique_ptr<L1CaloRegionCollection>& regions);
0086 
0087   //virtual void beginRun(Run const&, EventSetup const&) override;
0088   //virtual void endRun(Run const&, EventSetup const&) override;
0089   //virtual void beginLuminosityBlock(LuminosityBlock const&, EventSetup const&) override;
0090   //virtual void endLuminosityBlock(LuminosityBlock const&, EventSetup const&) override;
0091 
0092   // ----------member data ---------------------------
0093 
0094   InputTag fedRawDataLabel;
0095   std::vector<int> fedIDs;
0096 
0097   uint32_t event;
0098 
0099   bool verbose;
0100 };
0101 
0102 //
0103 // constants, enums and typedefs
0104 //
0105 
0106 //
0107 // static data member definitions
0108 //
0109 
0110 //
0111 // constructors and destructor
0112 //
0113 L1TCaloLayer1RawToDigi::L1TCaloLayer1RawToDigi(const ParameterSet& iConfig)
0114     : fedRawDataLabel(iConfig.getParameter<InputTag>("fedRawDataLabel")),
0115       fedIDs(iConfig.getParameter<std::vector<int> >("FEDIDs")),
0116       event(0),
0117       verbose(iConfig.getParameter<bool>("verbose")) {
0118   produces<EcalTrigPrimDigiCollection>();
0119   produces<HcalTrigPrimDigiCollection>();
0120   produces<L1CaloRegionCollection>();
0121 
0122   consumes<FEDRawDataCollection>(fedRawDataLabel);
0123 }
0124 
0125 L1TCaloLayer1RawToDigi::~L1TCaloLayer1RawToDigi() {}
0126 
0127 //
0128 // member functions
0129 //
0130 
0131 // ------------ method called to produce the data  ------------
0132 void L1TCaloLayer1RawToDigi::produce(Event& iEvent, const EventSetup& iSetup) {
0133   using namespace edm;
0134   using namespace std;
0135 
0136   Handle<FEDRawDataCollection> fedRawDataCollection;
0137   iEvent.getByLabel(fedRawDataLabel, fedRawDataCollection);
0138 
0139   std::unique_ptr<EcalTrigPrimDigiCollection> ecalTPGs(new EcalTrigPrimDigiCollection);
0140   std::unique_ptr<HcalTrigPrimDigiCollection> hcalTPGs(new HcalTrigPrimDigiCollection);
0141   std::unique_ptr<L1CaloRegionCollection> regions(new L1CaloRegionCollection);
0142 
0143   // if raw data collection is present, check the headers and do the unpacking
0144   if (fedRawDataCollection.isValid()) {
0145     for (uint32_t i = 0; i < fedIDs.size(); i++) {
0146       uint32_t fed = fedIDs[i];
0147 
0148       const FEDRawData& fedRawData = fedRawDataCollection->FEDData(fed);
0149 
0150       //Check FED size
0151       if (verbose)
0152         LogDebug("L1TCaloLayer1RawToDigi")
0153             << "Upacking FEDRawData for fed " << std::dec << fed << " of size " << fedRawData.size();
0154 
0155       const uint64_t* fedRawDataArray = (const uint64_t*)fedRawData.data();
0156 
0157       if (fedRawData.size() == 0 || fedRawDataArray == nullptr) {
0158         LogDebug("L1TCaloLayer1RawToDigi") << "Could not load FED data for " << fed << ", putting empty collections!";
0159         continue;
0160       }
0161 
0162       UCTDAQRawData daqData(fedRawDataArray);
0163       if (verbose && event < 5)
0164         daqData.print();
0165       for (uint32_t i = 0; i < daqData.nAMCs(); i++) {
0166         UCTAMCRawData amcData(daqData.amcPayload(i));
0167         if (verbose && event < 5) {
0168           LogDebug("L1TCaloLayer1") << endl;
0169           amcData.print();
0170           LogDebug("L1TCaloLayer1") << endl;
0171         }
0172         uint32_t lPhi = amcData.layer1Phi();
0173         UCTCTP7RawData ctp7Data(amcData.payload());
0174         if (verbose && event < 5)
0175           ctp7Data.print();
0176         if (verbose && event < 5)
0177           LogDebug("L1TCaloLayer1") << endl;
0178         makeECalTPGs(lPhi, ctp7Data, ecalTPGs);
0179         makeHCalTPGs(lPhi, ctp7Data, hcalTPGs);
0180         // Note: HF TPGs are added at the tail of other TPGs
0181         makeHFTPGs(lPhi, ctp7Data, hcalTPGs);
0182         makeRegions(lPhi, ctp7Data, regions);
0183       }
0184     }
0185 
0186   } else {
0187     LogError("L1T") << "Cannot unpack: no collection found";
0188 
0189     return;
0190   }
0191 
0192   iEvent.put(std::move(ecalTPGs));
0193   iEvent.put(std::move(hcalTPGs));
0194   iEvent.put(std::move(regions));
0195 
0196   event++;
0197   if (verbose && event == 5)
0198     LogDebug("L1TCaloLayer1") << "L1TCaloLayer1RawToDigi: Goodbye! Tired of printing junk" << endl;
0199 }
0200 
0201 void L1TCaloLayer1RawToDigi::makeECalTPGs(uint32_t lPhi,
0202                                           UCTCTP7RawData& ctp7Data,
0203                                           std::unique_ptr<EcalTrigPrimDigiCollection>& ecalTPGs) {
0204   UCTCTP7RawData::CaloType cType = UCTCTP7RawData::EBEE;
0205   for (uint32_t iPhi = 0; iPhi < 4; iPhi++) {  // Loop over all four phi divisions on card
0206     int cPhi = -1 + lPhi * 4 + iPhi;           // Calorimeter phi index
0207     if (cPhi == 0)
0208       cPhi = 72;
0209     else if (cPhi == -1)
0210       cPhi = 71;
0211     else if (cPhi < -1) {
0212       LogError("L1TCaloLayer1RawToDigi") << "L1TCaloLayer1RawToDigi: Major error in makeECalTPGs" << std::endl;
0213       return;
0214     }
0215     for (int cEta = -28; cEta <= 28; cEta++) {  // Calorimeter Eta indices (HB/HE for now)
0216       if (cEta != 0) {                          // Calorimeter eta = 0 is invalid
0217         bool negativeEta = false;
0218         if (cEta < 0)
0219           negativeEta = true;
0220         uint32_t iEta = abs(cEta);
0221         // This code is fragile! Note that towerDatum is packed as is done in EcalTriggerPrimitiveSample
0222         // Bottom 8-bits are ET
0223         // Then finegrain feature bit
0224         // Then three bits have ttBits, which I have no clue about (not available on ECAL links so not set)
0225         // Then there is a spare FG Veto bit, which is used for L1 spike detection (not available on ECAL links so not set)
0226         // Top three bits seem to be unused. So, we steal those to set the tower masking, link masking and link status information
0227         // To decode these custom three bits use ((EcalTriggerPrimitiveSample::raw() >> 13) & 0x7)
0228         uint32_t towerDatum = ctp7Data.getET(cType, negativeEta, iEta, iPhi);
0229         if (ctp7Data.getFB(cType, negativeEta, iEta, iPhi) != 0)
0230           towerDatum |= 0x0100;
0231         if (ctp7Data.isTowerMasked(cType, negativeEta, iEta, iPhi))
0232           towerDatum |= 0x2000;
0233         if (ctp7Data.isLinkMasked(cType, negativeEta, iEta, iPhi))
0234           towerDatum |= 0x4000;
0235         if (ctp7Data.isLinkMisaligned(cType, negativeEta, iEta, iPhi) ||
0236             ctp7Data.isLinkInError(cType, negativeEta, iEta, iPhi) ||
0237             ctp7Data.isLinkDown(cType, negativeEta, iEta, iPhi))
0238           towerDatum |= 0x8000;
0239         EcalTriggerPrimitiveSample sample(towerDatum);
0240         int zSide = cEta / ((int)iEta);
0241         // As far as I can tell, the ECal unpacker only uses barrel and endcap IDs, never EcalTriggerTower
0242         const EcalSubdetector ecalTriggerTower =
0243             (iEta > 17) ? EcalSubdetector::EcalEndcap : EcalSubdetector::EcalBarrel;
0244         EcalTrigTowerDetId id(zSide, ecalTriggerTower, iEta, cPhi);
0245         EcalTriggerPrimitiveDigi tpg(id);
0246         tpg.setSize(1);
0247         tpg.setSample(0, sample);
0248         ecalTPGs->push_back(tpg);
0249       }
0250     }
0251   }
0252 }
0253 
0254 void L1TCaloLayer1RawToDigi::makeHCalTPGs(uint32_t lPhi,
0255                                           UCTCTP7RawData& ctp7Data,
0256                                           std::unique_ptr<HcalTrigPrimDigiCollection>& hcalTPGs) {
0257   UCTCTP7RawData::CaloType cType = UCTCTP7RawData::HBHE;
0258   for (uint32_t iPhi = 0; iPhi < 4; iPhi++) {  // Loop over all four phi divisions on card
0259     int cPhi = -1 + lPhi * 4 + iPhi;           // Calorimeter phi index
0260     if (cPhi == 0)
0261       cPhi = 72;
0262     else if (cPhi == -1)
0263       cPhi = 71;
0264     else if (cPhi < -1) {
0265       LogError("L1TCaloLayer1RawToDigi") << "L1TCaloLayer1RawToDigi: Major error in makeHCalTPGs" << std::endl;
0266       return;
0267     }
0268     for (int cEta = -28; cEta <= 28; cEta++) {  // Calorimeter Eta indices (HB/HE for now)
0269       if (cEta != 0) {                          // Calorimeter eta = 0 is invalid
0270         bool negativeEta = false;
0271         if (cEta < 0)
0272           negativeEta = true;
0273         uint32_t iEta = abs(cEta);
0274         // This code is fragile! Note that towerDatum is packed as is done in HcalTriggerPrimitiveSample
0275         // Bottom 8-bits are ET
0276         // Then feature bit
0277         // The remaining bits are undefined presently
0278         // We use next three bits for link details, which we did not have room in EcalTriggerPrimitiveSample case
0279         // We use next three bits to set the tower masking, link masking and link status information as done for Ecal
0280         // To decode these custom six bits use ((EcalTriggerPrimitiveSample::raw() >> 9) & 0x77)
0281         uint32_t towerDatum = ctp7Data.getET(cType, negativeEta, iEta, iPhi);
0282         if (ctp7Data.getFB(cType, negativeEta, iEta, iPhi) != 0)
0283           towerDatum |= 0x0100;
0284         if (ctp7Data.isLinkMisaligned(cType, negativeEta, iEta, iPhi))
0285           towerDatum |= 0x0200;
0286         if (ctp7Data.isLinkInError(cType, negativeEta, iEta, iPhi))
0287           towerDatum |= 0x0400;
0288         if (ctp7Data.isLinkDown(cType, negativeEta, iEta, iPhi))
0289           towerDatum |= 0x0800;
0290         if (ctp7Data.isTowerMasked(cType, negativeEta, iEta, iPhi))
0291           towerDatum |= 0x2000;
0292         if (ctp7Data.isLinkMasked(cType, negativeEta, iEta, iPhi))
0293           towerDatum |= 0x4000;
0294         if (ctp7Data.isLinkMisaligned(cType, negativeEta, iEta, iPhi) ||
0295             ctp7Data.isLinkInError(cType, negativeEta, iEta, iPhi) ||
0296             ctp7Data.isLinkDown(cType, negativeEta, iEta, iPhi))
0297           towerDatum |= 0x8000;
0298         HcalTriggerPrimitiveSample sample(towerDatum);
0299         HcalTrigTowerDetId id(cEta, cPhi);
0300         HcalTriggerPrimitiveDigi tpg(id);
0301         tpg.setSize(1);
0302         tpg.setSample(0, sample);
0303         hcalTPGs->push_back(tpg);
0304       }
0305     }
0306   }
0307 }
0308 
0309 void L1TCaloLayer1RawToDigi::makeHFTPGs(uint32_t lPhi,
0310                                         UCTCTP7RawData& ctp7Data,
0311                                         std::unique_ptr<HcalTrigPrimDigiCollection>& hcalTPGs) {
0312   UCTCTP7RawData::CaloType cType = UCTCTP7RawData::HF;
0313   for (uint32_t side = 0; side <= 1; side++) {
0314     bool negativeEta = false;
0315     if (side == 0)
0316       negativeEta = true;
0317     for (uint32_t iEta = 30; iEta <= 40; iEta++) {
0318       for (uint32_t iPhi = 0; iPhi < 2; iPhi++) {
0319         if (iPhi == 1 && iEta == 40)
0320           iEta = 41;
0321         int cPhi = 1 + lPhi * 4 + iPhi * 2;  // Calorimeter phi index: 1, 3, 5, ... 71
0322         if (iEta == 41)
0323           cPhi -= 2;                  // Last two HF are 3, 7, 11, ...
0324         cPhi = (cPhi + 69) % 72 + 1;  // cPhi -= 2 mod 72
0325         int cEta = iEta;
0326         if (negativeEta)
0327           cEta = -iEta;
0328         // This code is fragile! Note that towerDatum is packed as is done in HcalTriggerPrimitiveSample
0329         // Bottom 8-bits are ET
0330         // Then feature bit
0331         // Then minBias ADC count bit
0332         // The remaining bits are undefined presently
0333         // We use next three bits for link details, which we did not have room in EcalTriggerPrimitiveSample case
0334         // We use next three bits to set the tower masking, link masking and link status information as done for Ecal
0335         // To decode these custom six bits use ((EcalTriggerPrimitiveSample::raw() >> 9) & 0x77)
0336         uint32_t towerDatum = ctp7Data.getET(cType, negativeEta, iEta, iPhi);
0337         towerDatum |= ctp7Data.getFB(cType, negativeEta, iEta, iPhi) << 8;
0338         if (ctp7Data.isLinkMisaligned(cType, negativeEta, iEta, iPhi))
0339           towerDatum |= 0x0400;
0340         if (ctp7Data.isLinkInError(cType, negativeEta, iEta, iPhi))
0341           towerDatum |= 0x0800;
0342         if (ctp7Data.isLinkDown(cType, negativeEta, iEta, iPhi))
0343           towerDatum |= 0x1000;
0344         if (ctp7Data.isTowerMasked(cType, negativeEta, iEta, iPhi))
0345           towerDatum |= 0x2000;
0346         if (ctp7Data.isLinkMasked(cType, negativeEta, iEta, iPhi))
0347           towerDatum |= 0x4000;
0348         if (ctp7Data.isLinkMisaligned(cType, negativeEta, iEta, iPhi) ||
0349             ctp7Data.isLinkInError(cType, negativeEta, iEta, iPhi) ||
0350             ctp7Data.isLinkDown(cType, negativeEta, iEta, iPhi))
0351           towerDatum |= 0x8000;
0352         HcalTriggerPrimitiveSample sample(towerDatum);
0353         HcalTrigTowerDetId id(cEta, cPhi);
0354         id.setVersion(1);  // To not process these 1x1 HF TPGs with RCT
0355         HcalTriggerPrimitiveDigi tpg(id);
0356         tpg.setSize(1);
0357         tpg.setSample(0, sample);
0358         hcalTPGs->push_back(tpg);
0359       }
0360     }
0361   }
0362 }
0363 
0364 void L1TCaloLayer1RawToDigi::makeRegions(uint32_t lPhi,
0365                                          UCTCTP7RawData& ctp7Data,
0366                                          std::unique_ptr<L1CaloRegionCollection>& regions) {
0367   for (uint32_t side = 0; side <= 1; side++) {
0368     bool negativeEta = false;
0369     if (side == 0)
0370       negativeEta = true;
0371     for (uint32_t region = 0; region <= 6; region++) {
0372       uint32_t regionData = ctp7Data.getRegionSummary(negativeEta, region);
0373       uint32_t lEta = 10 - region;  // GCT eta goes 0-21, 0-3 -HF, 4-10 -B/E, 11-17 +B/E, 18-21 +HF
0374       if (!negativeEta)
0375         lEta = region + 11;
0376       regions->push_back(L1CaloRegion((uint16_t)regionData, (unsigned)lEta, (unsigned)lPhi, (int16_t)0));
0377     }
0378   }
0379 }
0380 
0381 // ------------ method called once each stream before processing any runs, lumis or events  ------------
0382 void L1TCaloLayer1RawToDigi::beginStream(StreamID) {}
0383 
0384 // ------------ method called once each stream after processing all runs, lumis and events  ------------
0385 void L1TCaloLayer1RawToDigi::endStream() {}
0386 
0387 // ------------ method called when starting to processes a run  ------------
0388 /*
0389   void
0390   L1TCaloLayer1RawToDigi::beginRun(Run const&, EventSetup const&)
0391   {
0392   }
0393 */
0394 
0395 // ------------ method called when ending the processing of a run  ------------
0396 /*
0397   void
0398   L1TCaloLayer1RawToDigi::endRun(Run const&, EventSetup const&)
0399   {
0400   }
0401 */
0402 
0403 // ------------ method called when starting to processes a luminosity block  ------------
0404 /*
0405   void
0406   L1TCaloLayer1RawToDigi::beginLuminosityBlock(LuminosityBlock const&, EventSetup const&)
0407   {
0408   }
0409 */
0410 
0411 // ------------ method called when ending the processing of a luminosity block  ------------
0412 /*
0413   void
0414   L1TCaloLayer1RawToDigi::endLuminosityBlock(LuminosityBlock const&, EventSetup const&)
0415   {
0416   }
0417 */
0418 
0419 // ------------ method fills 'descriptions' with the allowed parameters for the module  ------------
0420 void L1TCaloLayer1RawToDigi::fillDescriptions(ConfigurationDescriptions& descriptions) {
0421   //The following says we do not know what parameters are allowed so do no validation
0422   // Please change this to state exactly what you do use, even if it is no parameters
0423   ParameterSetDescription desc;
0424   desc.setUnknown();
0425   descriptions.addDefault(desc);
0426 }
0427 
0428 //define this as a plug-in
0429 DEFINE_FWK_MODULE(L1TCaloLayer1RawToDigi);