Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 #include "EventFilter/GctRawToDigi/src/GctFormatTranslateMCLegacy.h"
0002 
0003 // C++ headers
0004 #include <iostream>
0005 #include <cassert>
0006 
0007 // Framework headers
0008 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0009 
0010 // Namespace resolution
0011 using std::cout;
0012 using std::endl;
0013 using std::make_pair;
0014 using std::pair;
0015 using std::vector;
0016 
0017 // INITIALISE STATIC VARIABLES
0018 /*** Setup BlockID to BlockLength Map ***/
0019 const GctFormatTranslateMCLegacy::BlockLengthMap GctFormatTranslateMCLegacy::m_blockLength = {
0020     // Miscellaneous Blocks
0021     {0x000, 0},    // NULL
0022     {0x0ff, 198},  // Temporary hack: All RCT Calo Regions for CMSSW pack/unpack
0023     // ConcJet FPGA
0024     {0x583, 8},  // ConcJet: Jet Cands and Counts Output to GT
0025     // ConcElec FPGA
0026     {0x683, 6},  // ConcElec: EM Cands and Energy Sums Output to GT
0027     // Electron Leaf FPGAs
0028     {0x804, 15},   // Leaf0ElecPosEtaU1: Raw Input
0029     {0x884, 12},   // Leaf0ElecPosEtaU2: Raw Input
0030     {0xc04, 15},   // Leaf0ElecNegEtaU1: Raw Input
0031     {0xc84, 12}};  // Leaf0ElecNegEtaU2: Raw Input
0032 
0033 /*** Setup BlockID to BlockName Map ***/
0034 const GctFormatTranslateMCLegacy::BlockNameMap GctFormatTranslateMCLegacy::m_blockName = {
0035     // Miscellaneous Blocks
0036     {0x000, "NULL"},
0037     {0x0ff, "All RCT Calo Regions"},  // Temporary hack: All RCT Calo Regions for CMSSW pack/unpack
0038     // ConcJet FPGA
0039     {0x583, "ConcJet: Jet Cands and Counts Output to GT"},
0040     // ConcElec FPGA
0041     {0x683, "ConcElec: EM Cands and Energy Sums Output to GT"},
0042     // Electron Leaf FPGAs
0043     {0x804, "Leaf0ElecPosEtaU1: Raw Input"},
0044     {0x884, "Leaf0ElecPosEtaU2: Raw Input"},
0045     {0xc04, "Leaf0ElecNegEtaU1: Raw Input"},
0046     {0xc84, "Leaf0ElecNegEtaU2: Raw Input"}};
0047 
0048 /*** Setup BlockID to Unpack-Function Map ***/
0049 const GctFormatTranslateMCLegacy::BlockIdToUnpackFnMap GctFormatTranslateMCLegacy::m_blockUnpackFn = {
0050     // Miscellaneous Blocks
0051     {0x000, &GctFormatTranslateMCLegacy::blockDoNothing},  // NULL
0052     {0x0ff,
0053      &GctFormatTranslateMCLegacy::blockToAllRctCaloRegions},  // Temporary hack: All RCT Calo Regions for CMSSW pack/unpack
0054     // ConcJet FPGA
0055     {0x583, &GctFormatTranslateMCLegacy::blockToGctJetCandsAndCounts},  // ConcJet: Jet Cands and Counts Output to GT
0056     // ConcElec FPGA
0057     {0x683,
0058      &GctFormatTranslateMCLegacy::blockToGctEmCandsAndEnergySums},  // ConcElec: EM Cands and Energy Sums Output to GT
0059     // Electron Leaf FPGAs
0060     {0x804, &GctFormatTranslateMCLegacy::blockToFibresAndToRctEmCand},  // Leaf0ElecPosEtaU1: Raw Input
0061     {0x884, &GctFormatTranslateMCLegacy::blockToFibresAndToRctEmCand},  // Leaf0ElecPosEtaU2: Raw Input
0062     {0xc04, &GctFormatTranslateMCLegacy::blockToFibresAndToRctEmCand},  // Leaf0ElecNegEtaU1: Raw Input
0063     {0xc84, &GctFormatTranslateMCLegacy::blockToFibresAndToRctEmCand}   // Leaf0ElecNegEtaU2: Raw Input
0064 };
0065 
0066 /*** Setup RCT Em Crate Map ***/
0067 const GctFormatTranslateMCLegacy::BlkToRctCrateMap GctFormatTranslateMCLegacy::m_rctEmCrate = {
0068     {0x804, 13}, {0x884, 9}, {0xc04, 4}, {0xc84, 0}};
0069 
0070 /*** Setup RCT jet crate map. ***/
0071 // No entries required!
0072 const GctFormatTranslateMCLegacy::BlkToRctCrateMap GctFormatTranslateMCLegacy::m_rctJetCrate;
0073 
0074 /*** Setup Block ID map for pipeline payload positions of isolated Internal EM Cands. ***/
0075 // No entries required!
0076 const GctFormatTranslateMCLegacy::BlockIdToEmCandIsoBoundMap GctFormatTranslateMCLegacy::m_internEmIsoBounds;
0077 
0078 // PUBLIC METHODS
0079 
0080 GctFormatTranslateMCLegacy::GctFormatTranslateMCLegacy(bool hltMode, bool unpackSharedRegions)
0081     : GctFormatTranslateBase(hltMode, unpackSharedRegions) {}
0082 
0083 GctFormatTranslateMCLegacy::~GctFormatTranslateMCLegacy() {}
0084 
0085 GctBlockHeader GctFormatTranslateMCLegacy::generateBlockHeader(const unsigned char* data) const {
0086   // Turn the four 8-bit header words into the full 32-bit header.
0087   uint32_t hdr = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24);
0088 
0089   //  Bit mapping of header:
0090   //  ----------------------
0091   //  11:0   => block_id  Unique pipeline identifier.
0092   //   - 3:0    =>> pipe_id There can be up to 16 different pipelines per FPGA.
0093   //   - 6:4    =>> reserved  Do not use yet. Set to zero.
0094   //   - 11:7   =>> fpga geograpical add  The VME geographical address of the FPGA.
0095   //  15:12  => event_id  Determined locally.  Not reset by Resync.
0096   //  19:16  => number_of_time_samples  If time samples 15 or more then value = 15.
0097   //  31:20  => event_bxId  The bunch crossing the data was recorded.
0098 
0099   uint32_t blockId = hdr & 0xfff;
0100   uint32_t blockLength = 0;  // Set to zero until we know it's a valid block
0101   uint32_t nSamples = (hdr >> 16) & 0xf;
0102   uint32_t bxId = (hdr >> 20) & 0xfff;
0103   uint32_t eventId = (hdr >> 12) & 0xf;
0104   bool valid = (blockLengthMap().find(blockId) != blockLengthMap().end());
0105 
0106   if (valid) {
0107     blockLength = blockLengthMap().find(blockId)->second;
0108   }
0109 
0110   return GctBlockHeader(blockId, blockLength, nSamples, bxId, eventId, valid);
0111 }
0112 
0113 // conversion
0114 bool GctFormatTranslateMCLegacy::convertBlock(const unsigned char* data, const GctBlockHeader& hdr) {
0115   // if the block has no time samples, don't bother with it.
0116   if (hdr.nSamples() < 1) {
0117     return true;
0118   }
0119 
0120   if (!checkBlock(hdr)) {
0121     return false;
0122   }  // Check the block to see if it's possible to unpack.
0123 
0124   // The header validity check above will protect against
0125   // the map::find() method returning the end of the map,
0126   // assuming the block header definitions are up-to-date.
0127   (this->*m_blockUnpackFn.find(hdr.blockId())->second)(data,
0128                                                        hdr);  // Calls the correct unpack function, based on block ID.
0129 
0130   return true;
0131 }
0132 
0133 // Output EM Candidates and energy sums packing
0134 void GctFormatTranslateMCLegacy::writeGctOutEmAndEnergyBlock(unsigned char* d,
0135                                                              const L1GctEmCandCollection* iso,
0136                                                              const L1GctEmCandCollection* nonIso,
0137                                                              const L1GctEtTotalCollection* etTotal,
0138                                                              const L1GctEtHadCollection* etHad,
0139                                                              const L1GctEtMissCollection* etMiss) {
0140   // Set up a vector of the collections for easy iteration.
0141   vector<const L1GctEmCandCollection*> emCands(NUM_EM_CAND_CATEGORIES);
0142   emCands.at(NON_ISO_EM_CANDS) = nonIso;
0143   emCands.at(ISO_EM_CANDS) = iso;
0144 
0145   /* To hold the offsets within the EM candidate collections for the bx=0 candidates.
0146    * The capture index doesn't seem to get set properly by the emulator, so take the
0147    * first bx=0 cand as the highest energy EM cand, and the fourth as the lowest. */
0148   vector<unsigned> bx0EmCandOffsets(NUM_EM_CAND_CATEGORIES);
0149 
0150   // Loop over the different catagories of EM cands to find the bx=0 offsets.
0151   for (unsigned int iCat = 0; iCat < NUM_EM_CAND_CATEGORIES; ++iCat) {
0152     const L1GctEmCandCollection* cands = emCands.at(iCat);
0153     unsigned& offset = bx0EmCandOffsets.at(iCat);
0154     if (!findBx0OffsetInCollection(offset, cands)) {
0155       LogDebug("GCT") << "No EM candidates with bx=0!\nAborting packing of GCT EM Cand and Energy Sum Output!";
0156       return;
0157     }
0158     if ((cands->size() - offset) < 4) {
0159       LogDebug("GCT")
0160           << "Insufficient EM candidates with bx=0!\nAborting packing of GCT EM Cand and Energy Sum Output!";
0161       return;
0162     }
0163   }
0164 
0165   unsigned bx0EtTotalOffset, bx0EtHadOffset, bx0EtMissOffset;
0166   if (!findBx0OffsetInCollection(bx0EtTotalOffset, etTotal)) {
0167     LogDebug("GCT") << "No Et Total value for bx=0!\nAborting packing of GCT EM Cand and Energy Sum Output!";
0168     return;
0169   }
0170   if (!findBx0OffsetInCollection(bx0EtHadOffset, etHad)) {
0171     LogDebug("GCT") << "No Et Hadronic value for bx=0!\nAborting packing of GCT EM Cand and Energy Sum Output!";
0172     return;
0173   }
0174   if (!findBx0OffsetInCollection(bx0EtMissOffset, etMiss)) {
0175     LogDebug("GCT") << "No Et Miss value for bx=0!\nAborting packing of GCT EM Cand and Energy Sum Output!";
0176     return;
0177   }
0178 
0179   // We should now have all requisite data, so we can get on with packing
0180 
0181   unsigned nSamples = 1;  // ** NOTE can only currenly do 1 timesample! **
0182 
0183   // write header
0184   writeRawHeader(d, 0x683, nSamples);
0185 
0186   d = d + 4;  // move to the block payload.
0187 
0188   // FIRST DO EM CANDS
0189 
0190   // re-interpret payload pointer to 16 bit.
0191   uint16_t* p16 = reinterpret_cast<uint16_t*>(d);
0192 
0193   for (unsigned iCat = 0; iCat < NUM_EM_CAND_CATEGORIES; ++iCat)  // loop over non-iso/iso candidates categories
0194   {
0195     const L1GctEmCandCollection* em = emCands.at(iCat);    // The current category of EM cands.
0196     const unsigned bx0Offset = bx0EmCandOffsets.at(iCat);  // The offset in the EM cand collection to the bx=0 cands.
0197 
0198     uint16_t* cand = p16 + (iCat * 4);
0199 
0200     *cand = em->at(bx0Offset).raw();
0201     cand++;
0202     *cand = em->at(bx0Offset + 2).raw();
0203     cand += nSamples;
0204     *cand = em->at(bx0Offset + 1).raw();
0205     cand++;
0206     *cand = em->at(bx0Offset + 3).raw();
0207   }
0208 
0209   // NOW DO ENERGY SUMS
0210   // assumes these are all 1-object collections, ie. central BX only
0211   p16 += 8;                                    // Move past EM cands
0212   *p16 = etTotal->at(bx0EtTotalOffset).raw();  // Et Total - 16 bits.
0213   p16++;
0214   *p16 = etHad->at(bx0EtHadOffset).raw();  // Et Hadronic - next 16 bits
0215   p16++;
0216   uint32_t* p32 = reinterpret_cast<uint32_t*>(p16);  // For writing Missing Et (32-bit raw data)
0217   *p32 = etMiss->at(bx0EtMissOffset).raw();          // Et Miss on final 32 bits of block payload.
0218 }
0219 
0220 void GctFormatTranslateMCLegacy::writeGctOutJetBlock(unsigned char* d,
0221                                                      const L1GctJetCandCollection* cenJets,
0222                                                      const L1GctJetCandCollection* forJets,
0223                                                      const L1GctJetCandCollection* tauJets,
0224                                                      const L1GctHFRingEtSumsCollection* hfRingSums,
0225                                                      const L1GctHFBitCountsCollection* hfBitCounts,
0226                                                      const L1GctHtMissCollection* htMiss) {
0227   // Set up a vector of the collections for easy iteration.
0228   vector<const L1GctJetCandCollection*> jets(NUM_JET_CATEGORIES);
0229   jets.at(CENTRAL_JETS) = cenJets;
0230   jets.at(FORWARD_JETS) = forJets;
0231   jets.at(TAU_JETS) = tauJets;
0232 
0233   /* To hold the offsets within the three jet cand collections for the bx=0 jets.
0234    * The capture index doesn't seem to get set properly by the emulator, so take the
0235    * first bx=0 jet as the highest energy jet, and the fourth as the lowest. */
0236   vector<unsigned> bx0JetCandOffsets(NUM_JET_CATEGORIES);
0237 
0238   // Loop over the different catagories of jets to find the bx=0 offsets.
0239   for (unsigned int iCat = 0; iCat < NUM_JET_CATEGORIES; ++iCat) {
0240     const L1GctJetCandCollection* jetCands = jets.at(iCat);
0241     unsigned& offset = bx0JetCandOffsets.at(iCat);
0242     if (!findBx0OffsetInCollection(offset, jetCands)) {
0243       LogDebug("GCT") << "No jet candidates with bx=0!\nAborting packing of GCT Jet Output!";
0244       return;
0245     }
0246     if ((jetCands->size() - offset) < 4) {
0247       LogDebug("GCT") << "Insufficient jet candidates with bx=0!\nAborting packing of GCT Jet Output!";
0248       return;
0249     }
0250   }
0251 
0252   // Now find the collection offsets for the HfRingSums, HfBitCounts, and HtMiss with bx=0
0253   unsigned bx0HfRingSumsOffset, bx0HfBitCountsOffset, bx0HtMissOffset;
0254   if (!findBx0OffsetInCollection(bx0HfRingSumsOffset, hfRingSums)) {
0255     LogDebug("GCT") << "No ring sums with bx=0!\nAborting packing of GCT Jet Output!";
0256     return;
0257   }
0258   if (!findBx0OffsetInCollection(bx0HfBitCountsOffset, hfBitCounts)) {
0259     LogDebug("GCT") << "No bit counts with bx=0!\nAborting packing of GCT Jet Output!";
0260     return;
0261   }
0262   if (!findBx0OffsetInCollection(bx0HtMissOffset, htMiss)) {
0263     LogDebug("GCT") << "No missing Ht with bx=0!\nAborting packing of GCT Jet Output!";
0264     return;
0265   }
0266 
0267   // Now write the header, as we should now have all requisite data.
0268   writeRawHeader(d, 0x583, 1);  // ** NOTE can only currenly do 1 timesample! **
0269 
0270   d = d + 4;  // move forward past the block header to the block payload.
0271 
0272   // FIRST DO JET CANDS
0273   // re-interpret pointer to 16 bits - the space allocated for each Jet candidate.
0274   uint16_t* p16 = reinterpret_cast<uint16_t*>(d);
0275 
0276   const unsigned categoryOffset = 4;      // Offset to jump from one jet category to the next.
0277   const unsigned nextCandPairOffset = 2;  // Offset to jump to next candidate pair.
0278 
0279   // Loop over the different catagories of jets
0280   for (unsigned iCat = 0; iCat < NUM_JET_CATEGORIES; ++iCat) {
0281     const L1GctJetCandCollection* jetCands = jets.at(iCat);  // The current category of jet cands.
0282     const unsigned cand0Offset =
0283         iCat * categoryOffset;  // the offset on p16 to get the rank 0 Jet Cand of the correct category.
0284     const unsigned bx0Offset = bx0JetCandOffsets.at(iCat);  // The offset in the jet cand collection to the bx=0 jets.
0285 
0286     p16[cand0Offset] = jetCands->at(bx0Offset).raw();                               // rank 0 jet in bx=0
0287     p16[cand0Offset + nextCandPairOffset] = jetCands->at(bx0Offset + 1).raw();      // rank 1 jet in bx=0
0288     p16[cand0Offset + 1] = jetCands->at(bx0Offset + 2).raw();                       // rank 2 jet in bx=0
0289     p16[cand0Offset + nextCandPairOffset + 1] = jetCands->at(bx0Offset + 3).raw();  // rank 3 jet in bx=0.
0290   }
0291 
0292   // NOW DO JET COUNTS
0293   d = d + 24;  // move forward past the jet cands to the jet counts section
0294 
0295   // re-interpret pointer to 32 bit.
0296   uint32_t* p32 = reinterpret_cast<uint32_t*>(d);
0297 
0298   uint32_t tmp = hfBitCounts->at(bx0HfBitCountsOffset).raw() & 0xfff;
0299   tmp |= hfRingSums->at(bx0HfRingSumsOffset).etSum(0) << 12;
0300   tmp |= hfRingSums->at(bx0HfRingSumsOffset).etSum(1) << 16;
0301   tmp |= hfRingSums->at(bx0HfRingSumsOffset).etSum(2) << 19;
0302   tmp |= hfRingSums->at(bx0HfRingSumsOffset).etSum(3) << 22;
0303   p32[0] = tmp;
0304 
0305   const L1GctHtMiss& bx0HtMiss = htMiss->at(bx0HtMissOffset);
0306   uint32_t htMissRaw = 0x5555c000 | (bx0HtMiss.overFlow() ? 0x1000 : 0x0000) | ((bx0HtMiss.et() & 0x7f) << 5) |
0307                        ((bx0HtMiss.phi() & 0x1f));
0308 
0309   p32[1] = htMissRaw;
0310 }
0311 
0312 void GctFormatTranslateMCLegacy::writeRctEmCandBlocks(unsigned char* d, const L1CaloEmCollection* rctEm) {
0313   // This method is one giant "temporary" hack for CMSSW_1_8_X and CMSSW_2_0_0.
0314 
0315   if (rctEm->empty() ||
0316       rctEm->size() % 144 != 0)  // Should be 18 crates * 2 types (iso/noniso) * 4 electrons = 144 for 1 bx.
0317   {
0318     LogDebug("GCT") << "Block pack error: bad L1CaloEmCollection size detected!\n"
0319                     << "Aborting packing of RCT EM Cand data!";
0320     return;
0321   }
0322 
0323   // Need 18 sets of EM fibre data, since 18 RCT crates
0324   SourceCardRouting::EmuToSfpData emuToSfpData[18];
0325 
0326   // Fill in the input arrays with the data from the digi
0327   for (unsigned i = 0, size = rctEm->size(); i < size; ++i) {
0328     const L1CaloEmCand& cand = rctEm->at(i);
0329     if (cand.bx() != 0) {
0330       continue;
0331     }  // Only interested in bunch crossing zero for now!
0332     unsigned crateNum = cand.rctCrate();
0333     unsigned index = cand.index();
0334 
0335     // Some error checking.
0336     assert(crateNum < 18);  // Only 18 RCT crates!
0337     assert(index < 4);      // Should only be 4 cands of each type per crate!
0338 
0339     if (cand.isolated()) {
0340       emuToSfpData[crateNum].eIsoRank[index] = cand.rank();
0341       emuToSfpData[crateNum].eIsoCardId[index] = cand.rctCard();
0342       emuToSfpData[crateNum].eIsoRegionId[index] = cand.rctRegion();
0343     } else {
0344       emuToSfpData[crateNum].eNonIsoRank[index] = cand.rank();
0345       emuToSfpData[crateNum].eNonIsoCardId[index] = cand.rctCard();
0346       emuToSfpData[crateNum].eNonIsoRegionId[index] = cand.rctRegion();
0347     }
0348     // Note doing nothing with the MIP bit and Q bit arrays as we are not
0349     // interested in them; these arrays will contain uninitialised junk
0350     // and so you will get out junk for sourcecard output 0 - I.e. don't
0351     // trust sfp[0][0] or sfp[1][0] output!.
0352   }
0353 
0354   // Now run the conversion
0355   for (unsigned c = 0; c < 18; ++c) {
0356     srcCardRouting().EMUtoSFP(emuToSfpData[c].eIsoRank,
0357                               emuToSfpData[c].eIsoCardId,
0358                               emuToSfpData[c].eIsoRegionId,
0359                               emuToSfpData[c].eNonIsoRank,
0360                               emuToSfpData[c].eNonIsoCardId,
0361                               emuToSfpData[c].eNonIsoRegionId,
0362                               emuToSfpData[c].mipBits,
0363                               emuToSfpData[c].qBits,
0364                               emuToSfpData[c].sfp);
0365   }
0366 
0367   // Now pack up the data into the RAW format.
0368   for (auto blockStartCrateIter = rctEmCrateMap().begin(); blockStartCrateIter != rctEmCrateMap().end();
0369        ++blockStartCrateIter) {
0370     unsigned blockId = blockStartCrateIter->first;
0371     unsigned startCrate = blockStartCrateIter->second;
0372     auto found = blockLengthMap().find(blockId);
0373     //assert(found != blockLengthMap().end());
0374     unsigned blockLength_32bit = found->second;
0375 
0376     writeRawHeader(d, blockId, 1);
0377     d += 4;  // move past header.
0378 
0379     // Want a 16 bit pointer to push the 16 bit data in.
0380     uint16_t* p16 = reinterpret_cast<uint16_t*>(const_cast<unsigned char*>(d));
0381 
0382     for (unsigned iCrate = startCrate, end = startCrate + blockLength_32bit / 3; iCrate < end; ++iCrate) {
0383       for (unsigned iOutput = 1; iOutput < 4; ++iOutput)  // skipping output 0 as that is Q-bit/MIP-bit data.
0384       {
0385         for (unsigned iCycle = 0; iCycle < 2; ++iCycle) {
0386           *p16 = emuToSfpData[iCrate].sfp[iCycle][iOutput];
0387           ++p16;
0388         }
0389       }
0390     }
0391 
0392     // Now move d onto the location of the next block header
0393     d += (blockLength_32bit * 4);
0394   }
0395 }
0396 
0397 void GctFormatTranslateMCLegacy::writeAllRctCaloRegionBlock(unsigned char* d, const L1CaloRegionCollection* rctCalo) {
0398   // This method is one giant "temporary" hack for CMSSW_1_8_X and CMSSW_2_0_0.
0399 
0400   if (rctCalo->empty() || rctCalo->size() % 396 != 0)  // Should be 396 calo regions for 1 bx.
0401   {
0402     LogDebug("GCT") << "Block pack error: bad L1CaloRegionCollection size detected!\n"
0403                     << "Aborting packing of RCT Calo Region data!";
0404     return;
0405   }
0406 
0407   writeRawHeader(d, 0x0ff, 1);
0408   d += 4;  // move past header.
0409 
0410   // Want a 16 bit pointer to push the 16 bit data in.
0411   uint16_t* p16 = reinterpret_cast<uint16_t*>(const_cast<unsigned char*>(d));
0412 
0413   for (unsigned i = 0, size = rctCalo->size(); i < size; ++i) {
0414     const L1CaloRegion& reg = rctCalo->at(i);
0415     if (reg.bx() != 0) {
0416       continue;
0417     }  // Only interested in bunch crossing zero for now!
0418     const unsigned crateNum = reg.rctCrate();
0419     const unsigned regionIndex = reg.rctRegionIndex();
0420     assert(crateNum < 18);  // Only 18 RCT crates!
0421 
0422     // Gotta make the raw data as there currently isn't a method of getting raw from L1CaloRegion
0423     const uint16_t raw = reg.et() | (reg.overFlow() ? 0x400 : 0x0) | (reg.fineGrain() ? 0x800 : 0x0) |
0424                          (reg.mip() ? 0x1000 : 0x0) | (reg.quiet() ? 0x2000 : 0x0);
0425 
0426     unsigned offset = 0;  // for storing calculated raw data offset.
0427     if (reg.isHbHe())     // Is a barrel/endcap region
0428     {
0429       const unsigned cardNum = reg.rctCard();
0430       assert(cardNum < 7);      // 7 RCT cards per crate for the barrel/endcap
0431       assert(regionIndex < 2);  // regionIndex less than 2 for barrel/endcap
0432 
0433       // Calculate position in the raw data from crateNum, cardNum, and regionIndex
0434       offset = crateNum * 22 + cardNum * 2 + regionIndex;
0435     } else  // Must be forward region
0436     {
0437       assert(regionIndex < 8);  // regionIndex less than 8 for forward calorimeter.
0438       offset = crateNum * 22 + 14 + regionIndex;
0439     }
0440     p16[offset] = raw;  // Write raw data in correct place!
0441   }
0442 }
0443 
0444 // PROTECTED METHODS
0445 
0446 uint32_t GctFormatTranslateMCLegacy::generateRawHeader(const uint32_t blockId,
0447                                                        const uint32_t nSamples,
0448                                                        const uint32_t bxId,
0449                                                        const uint32_t eventId) const {
0450   //  Bit mapping of header:
0451   //  ----------------------
0452   //  11:0   => block_id  Unique pipeline identifier.
0453   //   - 3:0    =>> pipe_id There can be up to 16 different pipelines per FPGA.
0454   //   - 6:4    =>> reserved  Do not use yet. Set to zero.
0455   //   - 11:7   =>> fpga geograpical add  The VME geographical address of the FPGA.
0456   //  15:12  => event_id  Determined locally.  Not reset by Resync.
0457   //  19:16  => number_of_time_samples  If time samples 15 or more then value = 15.
0458   //  31:20  => event_bxId  The bunch crossing the data was recorded.
0459 
0460   return ((bxId & 0xfff) << 20) | ((nSamples & 0xf) << 16) | ((eventId & 0xf) << 12) | (blockId & 0xfff);
0461 }
0462 
0463 // PRIVATE METHODS
0464 
0465 // Output EM Candidates unpacking
0466 void GctFormatTranslateMCLegacy::blockToGctEmCandsAndEnergySums(const unsigned char* d, const GctBlockHeader& hdr) {
0467   const unsigned int id = hdr.blockId();
0468   const unsigned int nSamples = hdr.nSamples();
0469 
0470   // Re-interpret pointer.  p16 will be pointing at the 16 bit word that
0471   // contains the rank0 non-isolated electron of the zeroth time-sample.
0472   const uint16_t* p16 = reinterpret_cast<const uint16_t*>(d);
0473 
0474   // UNPACK EM CANDS
0475 
0476   const unsigned int emCandCategoryOffset =
0477       nSamples * 4;  // Offset to jump from the non-iso electrons to the isolated ones.
0478   const unsigned int timeSampleOffset = nSamples * 2;  // Offset to jump to next candidate pair in the same time-sample.
0479 
0480   unsigned int samplesToUnpack = 1;
0481   if (!hltMode()) {
0482     samplesToUnpack = nSamples;
0483   }  // Only if not running in HLT mode do we want more than 1 timesample.
0484 
0485   for (unsigned int iso = 0; iso < 2; ++iso)  // loop over non-iso/iso candidate pairs
0486   {
0487     bool isoFlag = (iso == 1);
0488 
0489     // Get the correct collection to put them in.
0490     L1GctEmCandCollection* em;
0491     if (isoFlag) {
0492       em = colls()->gctIsoEm();
0493     } else {
0494       em = colls()->gctNonIsoEm();
0495     }
0496 
0497     for (unsigned int bx = 0; bx < samplesToUnpack; ++bx)  // loop over time samples
0498     {
0499       // cand0Offset will give the offset on p16 to get the rank 0 candidate
0500       // of the correct category and timesample.
0501       const unsigned int cand0Offset = iso * emCandCategoryOffset + bx * 2;
0502 
0503       em->push_back(L1GctEmCand(p16[cand0Offset], isoFlag, id, 0, bx));                         // rank0 electron
0504       em->push_back(L1GctEmCand(p16[cand0Offset + timeSampleOffset], isoFlag, id, 1, bx));      // rank1 electron
0505       em->push_back(L1GctEmCand(p16[cand0Offset + 1], isoFlag, id, 2, bx));                     // rank2 electron
0506       em->push_back(L1GctEmCand(p16[cand0Offset + timeSampleOffset + 1], isoFlag, id, 3, bx));  // rank3 electron
0507     }
0508   }
0509 
0510   p16 += emCandCategoryOffset * 2;  // Move the pointer over the data we've already unpacked.
0511 
0512   // UNPACK ENERGY SUMS
0513   // NOTE: we are only unpacking one timesample of these currently!
0514 
0515   colls()->gctEtTot()->push_back(L1GctEtTotal(p16[0]));  // Et total (timesample 0).
0516   colls()->gctEtHad()->push_back(L1GctEtHad(p16[1]));    // Et hadronic (timesample 0).
0517 
0518   // 32-bit pointer for getting Missing Et.
0519   const uint32_t* p32 = reinterpret_cast<const uint32_t*>(p16);
0520 
0521   colls()->gctEtMiss()->push_back(L1GctEtMiss(p32[nSamples]));  // Et Miss (timesample 0).
0522 }
0523 
0524 void GctFormatTranslateMCLegacy::blockToGctJetCandsAndCounts(const unsigned char* d, const GctBlockHeader& hdr) {
0525   const unsigned int id = hdr.blockId();         // Capture block ID.
0526   const unsigned int nSamples = hdr.nSamples();  // Number of time-samples.
0527 
0528   // Re-interpret block payload pointer to 16 bits so it sees one candidate at a time.
0529   // p16 points to the start of the block payload, at the rank0 tau jet candidate.
0530   const uint16_t* p16 = reinterpret_cast<const uint16_t*>(d);
0531 
0532   // UNPACK JET CANDS
0533 
0534   const unsigned int jetCandCategoryOffset = nSamples * 4;  // Offset to jump from one jet category to the next.
0535   const unsigned int timeSampleOffset = nSamples * 2;  // Offset to jump to next candidate pair in the same time-sample.
0536 
0537   unsigned int samplesToUnpack = 1;
0538   if (!hltMode()) {
0539     samplesToUnpack = nSamples;
0540   }  // Only if not running in HLT mode do we want more than 1 timesample.
0541 
0542   // Loop over the different catagories of jets
0543   for (unsigned int iCat = 0; iCat < NUM_JET_CATEGORIES; ++iCat) {
0544     L1GctJetCandCollection* const jets = gctJets(iCat);
0545     assert(jets->empty());  // The supplied vector should be empty.
0546 
0547     bool tauflag = (iCat == TAU_JETS);
0548     bool forwardFlag = (iCat == FORWARD_JETS);
0549 
0550     // Loop over the different timesamples (bunch crossings).
0551     for (unsigned int bx = 0; bx < samplesToUnpack; ++bx) {
0552       // cand0Offset will give the offset on p16 to get the rank 0 Jet Cand of the correct category and timesample.
0553       const unsigned int cand0Offset = iCat * jetCandCategoryOffset + bx * 2;
0554 
0555       // Rank 0 Jet.
0556       jets->push_back(L1GctJetCand(p16[cand0Offset], tauflag, forwardFlag, id, 0, bx));
0557       // Rank 1 Jet.
0558       jets->push_back(L1GctJetCand(p16[cand0Offset + timeSampleOffset], tauflag, forwardFlag, id, 1, bx));
0559       // Rank 2 Jet.
0560       jets->push_back(L1GctJetCand(p16[cand0Offset + 1], tauflag, forwardFlag, id, 2, bx));
0561       // Rank 3 Jet.
0562       jets->push_back(L1GctJetCand(p16[cand0Offset + timeSampleOffset + 1], tauflag, forwardFlag, id, 3, bx));
0563     }
0564   }
0565 
0566   p16 += NUM_JET_CATEGORIES * jetCandCategoryOffset;  // Move the pointer over the data we've already unpacked.
0567 
0568   // NOW UNPACK: HFBitCounts, HFRingEtSums and Missing Ht
0569   // NOTE: we are only unpacking one timesample of these currently!
0570 
0571   // Re-interpret block payload pointer to 32 bits so it sees six jet counts at a time.
0572   const uint32_t* p32 = reinterpret_cast<const uint32_t*>(p16);
0573 
0574   // Channel 0 carries both HF counts and sums
0575   colls()->gctHfBitCounts()->push_back(L1GctHFBitCounts::fromConcHFBitCounts(id, 6, 0, p32[0]));
0576   colls()->gctHfRingEtSums()->push_back(L1GctHFRingEtSums::fromConcRingSums(id, 6, 0, p32[0]));
0577 
0578   // Channel 1 carries Missing HT.
0579   colls()->gctHtMiss()->push_back(L1GctHtMiss(p32[nSamples], 0));
0580 }
0581 
0582 // Input EM Candidates unpacking
0583 // this is the last time I deal the RCT bit assignment travesty!!!
0584 void GctFormatTranslateMCLegacy::blockToRctEmCand(const unsigned char* d, const GctBlockHeader& hdr) {
0585   // Don't want to do this in HLT optimisation mode!
0586   if (hltMode()) {
0587     LogDebug("GCT") << "HLT mode - skipping unpack of RCT EM Cands";
0588     return;
0589   }
0590 
0591   unsigned int id = hdr.blockId();
0592   unsigned int nSamples = hdr.nSamples();
0593   unsigned int length = hdr.blockLength();
0594 
0595   // re-interpret pointer
0596   uint16_t* p = reinterpret_cast<uint16_t*>(const_cast<unsigned char*>(d));
0597 
0598   // arrays of source card data
0599   uint16_t sfp[2][4];  // [ cycle ] [ SFP ]
0600   uint16_t eIsoRank[4];
0601   uint16_t eIsoCard[4];
0602   uint16_t eIsoRgn[4];
0603   uint16_t eNonIsoRank[4];
0604   uint16_t eNonIsoCard[4];
0605   uint16_t eNonIsoRgn[4];
0606   uint16_t MIPbits[7][2];
0607   uint16_t QBits[7][2];
0608 
0609   unsigned int bx = 0;
0610 
0611   // loop over crates
0612   auto found = rctEmCrateMap().find(id);
0613   assert(found != rctEmCrateMap().end());
0614   for (unsigned int crate = found->second; crate < found->second + length / 3; ++crate) {
0615     // read SC SFP words
0616     for (unsigned short iSfp = 0; iSfp < 4; ++iSfp) {
0617       for (unsigned short cyc = 0; cyc < 2; ++cyc) {
0618         if (iSfp == 0) {
0619           sfp[cyc][iSfp] = 0;
0620         }       // muon bits
0621         else {  // EM candidate
0622           sfp[cyc][iSfp] = *p;
0623           ++p;
0624         }
0625       }
0626       p = p + 2 * (nSamples - 1);
0627     }
0628 
0629     // fill SC arrays
0630     srcCardRouting().SFPtoEMU(eIsoRank, eIsoCard, eIsoRgn, eNonIsoRank, eNonIsoCard, eNonIsoRgn, MIPbits, QBits, sfp);
0631 
0632     // create EM cands
0633     for (unsigned short int i = 0; i < 4; ++i) {
0634       colls()->rctEm()->push_back(L1CaloEmCand(eIsoRank[i], eIsoRgn[i], eIsoCard[i], crate, true, i, bx));
0635     }
0636     for (unsigned short int i = 0; i < 4; ++i) {
0637       colls()->rctEm()->push_back(L1CaloEmCand(eNonIsoRank[i], eNonIsoRgn[i], eNonIsoCard[i], crate, false, i, bx));
0638     }
0639   }
0640 }
0641 
0642 // Fibre unpacking
0643 void GctFormatTranslateMCLegacy::blockToFibres(const unsigned char* d, const GctBlockHeader& hdr) {
0644   // Don't want to do this in HLT optimisation mode!
0645   if (hltMode()) {
0646     LogDebug("GCT") << "HLT mode - skipping unpack of GCT Fibres";
0647     return;
0648   }
0649 
0650   unsigned int id = hdr.blockId();
0651   unsigned int nSamples = hdr.nSamples();
0652   unsigned int length = hdr.blockLength();
0653 
0654   // re-interpret pointer
0655   uint32_t* p = reinterpret_cast<uint32_t*>(const_cast<unsigned char*>(d));
0656 
0657   for (unsigned int i = 0; i < length; ++i) {
0658     for (unsigned int bx = 0; bx < nSamples; ++bx) {
0659       colls()->gctFibres()->push_back(L1GctFibreWord(*p, id, i, bx));
0660       ++p;
0661     }
0662   }
0663 }
0664 
0665 void GctFormatTranslateMCLegacy::blockToFibresAndToRctEmCand(const unsigned char* d, const GctBlockHeader& hdr) {
0666   this->blockToRctEmCand(d, hdr);
0667   this->blockToFibres(d, hdr);
0668 }
0669 
0670 void GctFormatTranslateMCLegacy::blockToAllRctCaloRegions(const unsigned char* d, const GctBlockHeader& hdr) {
0671   // Don't want to do this in HLT optimisation mode!
0672   if (hltMode()) {
0673     LogDebug("GCT") << "HLT mode - skipping unpack of RCT Calo Regions";
0674     return;
0675   }
0676 
0677   // This method is one giant "temporary" hack whilst waiting for proper
0678   // pipeline formats for the RCT calo region data.
0679 
0680   const int nSamples = hdr.nSamples();  // Number of time-samples.
0681 
0682   // Re-interpret block payload pointer to 16 bits
0683   const uint16_t* p16 = reinterpret_cast<const uint16_t*>(d);
0684 
0685   for (unsigned iCrate = 0; iCrate < 18; ++iCrate) {
0686     // Barrel and endcap regions
0687     for (unsigned iCard = 0; iCard < 7; ++iCard) {
0688       // Samples
0689       for (int16_t iSample = 0; iSample < nSamples; ++iSample) {
0690         // Two regions per card (and per 32-bit word).
0691         for (unsigned iRegion = 0; iRegion < 2; ++iRegion) {
0692           L1CaloRegionDetId id(iCrate, iCard, iRegion);
0693           colls()->rctCalo()->push_back(L1CaloRegion(*p16, id.ieta(), id.iphi(), iSample));
0694           ++p16;  //advance pointer
0695         }
0696       }
0697     }
0698     // Forward regions (8 regions numbered 0 through 7, packed in 4 sets of pairs)
0699     for (unsigned iRegionPairNum = 0; iRegionPairNum < 4; ++iRegionPairNum) {
0700       // Samples
0701       for (int16_t iSample = 0; iSample < nSamples; ++iSample) {
0702         // two regions in a pair
0703         for (unsigned iPair = 0; iPair < 2; ++iPair) {
0704           // For forward regions, RCTCard=999
0705           L1CaloRegionDetId id(iCrate, 999, iRegionPairNum * 2 + iPair);
0706           colls()->rctCalo()->push_back(L1CaloRegion(*p16, id.ieta(), id.iphi(), iSample));
0707           ++p16;  //advance pointer
0708         }
0709       }
0710     }
0711   }
0712 }
0713 
0714 template <typename Collection>
0715 bool GctFormatTranslateMCLegacy::findBx0OffsetInCollection(unsigned& bx0Offset, const Collection* coll) {
0716   bool foundBx0 = false;
0717   unsigned size = coll->size();
0718   for (bx0Offset = 0; bx0Offset < size; ++bx0Offset) {
0719     if (coll->at(bx0Offset).bx() == 0) {
0720       foundBx0 = true;
0721       break;
0722     }
0723   }
0724   return foundBx0;
0725 }