CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_5_3_13_patch3/src/EventFilter/GctRawToDigi/src/GctFormatTranslateMCLegacy.cc

Go to the documentation of this file.
00001 #include "EventFilter/GctRawToDigi/src/GctFormatTranslateMCLegacy.h"
00002 
00003 // C++ headers
00004 #include <iostream>
00005 #include <cassert>
00006 
00007 // Framework headers
00008 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00009 
00010 // Namespace resolution
00011 using std::cout;
00012 using std::endl;
00013 using std::pair;
00014 using std::make_pair;
00015 using std::vector;
00016 
00017 // INITIALISE STATIC VARIABLES
00018 GctFormatTranslateMCLegacy::BlockLengthMap GctFormatTranslateMCLegacy::m_blockLength = GctFormatTranslateMCLegacy::BlockLengthMap();
00019 GctFormatTranslateMCLegacy::BlockNameMap GctFormatTranslateMCLegacy::m_blockName = GctFormatTranslateMCLegacy::BlockNameMap();
00020 GctFormatTranslateMCLegacy::BlockIdToUnpackFnMap GctFormatTranslateMCLegacy::m_blockUnpackFn = GctFormatTranslateMCLegacy::BlockIdToUnpackFnMap();
00021 GctFormatTranslateMCLegacy::BlkToRctCrateMap GctFormatTranslateMCLegacy::m_rctEmCrate = GctFormatTranslateMCLegacy::BlkToRctCrateMap();
00022 GctFormatTranslateMCLegacy::BlkToRctCrateMap GctFormatTranslateMCLegacy::m_rctJetCrate = GctFormatTranslateMCLegacy::BlkToRctCrateMap();
00023 GctFormatTranslateMCLegacy::BlockIdToEmCandIsoBoundMap GctFormatTranslateMCLegacy::m_internEmIsoBounds = GctFormatTranslateMCLegacy::BlockIdToEmCandIsoBoundMap();
00024 
00025 
00026 // PUBLIC METHODS
00027 
00028 GctFormatTranslateMCLegacy::GctFormatTranslateMCLegacy(bool hltMode, bool unpackSharedRegions):
00029   GctFormatTranslateBase(hltMode, unpackSharedRegions)
00030 {
00031   static bool initClass = true;
00032 
00033   if(initClass)
00034   {
00035     initClass = false;
00036 
00037     /*** Setup BlockID to BlockLength Map ***/
00038     // Miscellaneous Blocks
00039     m_blockLength.insert(make_pair(0x000,0));      // NULL
00040     m_blockLength.insert(make_pair(0x0ff,198));    // Temporary hack: All RCT Calo Regions for CMSSW pack/unpack
00041     // ConcJet FPGA
00042     m_blockLength.insert(make_pair(0x583,8));      // ConcJet: Jet Cands and Counts Output to GT
00043     // ConcElec FPGA
00044     m_blockLength.insert(make_pair(0x683,6));      // ConcElec: EM Cands and Energy Sums Output to GT
00045     // Electron Leaf FPGAs
00046     m_blockLength.insert(make_pair(0x804,15));     // Leaf0ElecPosEtaU1: Raw Input
00047     m_blockLength.insert(make_pair(0x884,12));     // Leaf0ElecPosEtaU2: Raw Input
00048     m_blockLength.insert(make_pair(0xc04,15));     // Leaf0ElecNegEtaU1: Raw Input
00049     m_blockLength.insert(make_pair(0xc84,12));     // Leaf0ElecNegEtaU2: Raw Input
00050 
00051 
00052     /*** Setup BlockID to BlockName Map ***/
00053     // Miscellaneous Blocks
00054     m_blockName.insert(make_pair(0x000,"NULL"));
00055     m_blockName.insert(make_pair(0x0ff,"All RCT Calo Regions"));  // Temporary hack: All RCT Calo Regions for CMSSW pack/unpack
00056     // ConcJet FPGA
00057     m_blockName.insert(make_pair(0x583,"ConcJet: Jet Cands and Counts Output to GT"));
00058     // ConcElec FPGA
00059     m_blockName.insert(make_pair(0x683,"ConcElec: EM Cands and Energy Sums Output to GT"));
00060     // Electron Leaf FPGAs
00061     m_blockName.insert(make_pair(0x804,"Leaf0ElecPosEtaU1: Raw Input"));
00062     m_blockName.insert(make_pair(0x884,"Leaf0ElecPosEtaU2: Raw Input"));
00063     m_blockName.insert(make_pair(0xc04,"Leaf0ElecNegEtaU1: Raw Input"));
00064     m_blockName.insert(make_pair(0xc84,"Leaf0ElecNegEtaU2: Raw Input"));
00065 
00066 
00067     /*** Setup BlockID to Unpack-Function Map ***/
00068     // Miscellaneous Blocks
00069     m_blockUnpackFn[0x000] = &GctFormatTranslateMCLegacy::blockDoNothing;                    // NULL
00070     m_blockUnpackFn[0x0ff] = &GctFormatTranslateMCLegacy::blockToAllRctCaloRegions;          // Temporary hack: All RCT Calo Regions for CMSSW pack/unpack
00071     // ConcJet FPGA                                                             
00072     m_blockUnpackFn[0x583] = &GctFormatTranslateMCLegacy::blockToGctJetCandsAndCounts;       // ConcJet: Jet Cands and Counts Output to GT
00073     // ConcElec FPGA                                                            
00074     m_blockUnpackFn[0x683] = &GctFormatTranslateMCLegacy::blockToGctEmCandsAndEnergySums;    // ConcElec: EM Cands and Energy Sums Output to GT
00075     // Electron Leaf FPGAs                                                      
00076     m_blockUnpackFn[0x804] = &GctFormatTranslateMCLegacy::blockToFibresAndToRctEmCand;       // Leaf0ElecPosEtaU1: Raw Input
00077     m_blockUnpackFn[0x884] = &GctFormatTranslateMCLegacy::blockToFibresAndToRctEmCand;       // Leaf0ElecPosEtaU2: Raw Input
00078     m_blockUnpackFn[0xc04] = &GctFormatTranslateMCLegacy::blockToFibresAndToRctEmCand;       // Leaf0ElecNegEtaU1: Raw Input
00079     m_blockUnpackFn[0xc84] = &GctFormatTranslateMCLegacy::blockToFibresAndToRctEmCand;       // Leaf0ElecNegEtaU2: Raw Input
00080 
00081 
00082     /*** Setup RCT Em Crate Map ***/
00083     m_rctEmCrate[0x804] = 13;
00084     m_rctEmCrate[0x884] = 9;
00085     m_rctEmCrate[0xc04] = 4;
00086     m_rctEmCrate[0xc84] = 0;
00087 
00088 
00089     /*** Setup RCT jet crate map. ***/
00090     // No entries required!
00091 
00092 
00093     /*** Setup Block ID map for pipeline payload positions of isolated Internal EM Cands. ***/
00094     // No entries required!
00095   }
00096 }
00097 
00098 GctFormatTranslateMCLegacy::~GctFormatTranslateMCLegacy()
00099 {
00100 }
00101 
00102 GctBlockHeader GctFormatTranslateMCLegacy::generateBlockHeader(const unsigned char * data) const
00103 {
00104   // Turn the four 8-bit header words into the full 32-bit header.
00105   uint32_t hdr = data[0] + (data[1]<<8) + (data[2]<<16) + (data[3]<<24);
00106 
00107   //  Bit mapping of header:
00108   //  ----------------------
00109   //  11:0   => block_id  Unique pipeline identifier.
00110   //   - 3:0    =>> pipe_id There can be up to 16 different pipelines per FPGA.
00111   //   - 6:4    =>> reserved  Do not use yet. Set to zero.
00112   //   - 11:7   =>> fpga geograpical add  The VME geographical address of the FPGA.
00113   //  15:12  => event_id  Determined locally.  Not reset by Resync.
00114   //  19:16  => number_of_time_samples  If time samples 15 or more then value = 15.
00115   //  31:20  => event_bxId  The bunch crossing the data was recorded.
00116 
00117   uint32_t blockId = hdr & 0xfff;
00118   uint32_t blockLength = 0;  // Set to zero until we know it's a valid block
00119   uint32_t nSamples = (hdr>>16) & 0xf;
00120   uint32_t bxId = (hdr>>20) & 0xfff;
00121   uint32_t eventId = (hdr>>12) & 0xf;
00122   bool valid = (blockLengthMap().find(blockId) != blockLengthMap().end());
00123 
00124   if(valid) { blockLength = blockLengthMap().find(blockId)->second; }
00125   
00126   return GctBlockHeader(blockId, blockLength, nSamples, bxId, eventId, valid);  
00127 }
00128 
00129 // conversion
00130 bool GctFormatTranslateMCLegacy::convertBlock(const unsigned char * data, const GctBlockHeader& hdr)
00131 {
00132   // if the block has no time samples, don't bother with it.
00133   if ( hdr.nSamples() < 1 ) { return true; }
00134 
00135   if(!checkBlock(hdr)) { return false; }  // Check the block to see if it's possible to unpack.
00136 
00137   // The header validity check above will protect against
00138   // the map::find() method returning the end of the map,
00139   // assuming the block header definitions are up-to-date.
00140   (this->*m_blockUnpackFn.find(hdr.blockId())->second)(data, hdr);  // Calls the correct unpack function, based on block ID.
00141   
00142   return true;
00143 }
00144 
00145 // Output EM Candidates and energy sums packing
00146 void GctFormatTranslateMCLegacy::writeGctOutEmAndEnergyBlock(unsigned char * d,
00147                                                              const L1GctEmCandCollection* iso,
00148                                                              const L1GctEmCandCollection* nonIso,
00149                                                              const L1GctEtTotalCollection* etTotal,
00150                                                              const L1GctEtHadCollection* etHad,
00151                                                              const L1GctEtMissCollection* etMiss)
00152 {
00153   // Set up a vector of the collections for easy iteration.
00154   vector<const L1GctEmCandCollection*> emCands(NUM_EM_CAND_CATEGORIES);
00155   emCands.at(NON_ISO_EM_CANDS)=nonIso;
00156   emCands.at(ISO_EM_CANDS)=iso;
00157   
00158   /* To hold the offsets within the EM candidate collections for the bx=0 candidates.
00159    * The capture index doesn't seem to get set properly by the emulator, so take the
00160    * first bx=0 cand as the highest energy EM cand, and the fourth as the lowest. */
00161   vector<unsigned> bx0EmCandOffsets(NUM_EM_CAND_CATEGORIES);
00162 
00163   // Loop over the different catagories of EM cands to find the bx=0 offsets.
00164   for(unsigned int iCat = 0 ; iCat < NUM_EM_CAND_CATEGORIES ; ++iCat)
00165   {
00166     const L1GctEmCandCollection * cands = emCands.at(iCat);
00167     unsigned& offset = bx0EmCandOffsets.at(iCat);
00168     if(!findBx0OffsetInCollection(offset, cands)) { LogDebug("GCT") << "No EM candidates with bx=0!\nAborting packing of GCT EM Cand and Energy Sum Output!"; return; }
00169     if((cands->size()-offset) < 4) { LogDebug("GCT") << "Insufficient EM candidates with bx=0!\nAborting packing of GCT EM Cand and Energy Sum Output!"; return; }
00170   }
00171   
00172   unsigned bx0EtTotalOffset, bx0EtHadOffset, bx0EtMissOffset;
00173   if(!findBx0OffsetInCollection(bx0EtTotalOffset, etTotal)) { LogDebug("GCT") << "No Et Total value for bx=0!\nAborting packing of GCT EM Cand and Energy Sum Output!"; return; }
00174   if(!findBx0OffsetInCollection(bx0EtHadOffset, etHad)) { LogDebug("GCT") << "No Et Hadronic value for bx=0!\nAborting packing of GCT EM Cand and Energy Sum Output!"; return; }
00175   if(!findBx0OffsetInCollection(bx0EtMissOffset, etMiss)) { LogDebug("GCT") << "No Et Miss value for bx=0!\nAborting packing of GCT EM Cand and Energy Sum Output!"; return; } 
00176   
00177   // We should now have all requisite data, so we can get on with packing
00178 
00179   unsigned nSamples = 1; // ** NOTE can only currenly do 1 timesample! **
00180   
00181   // write header
00182   writeRawHeader(d, 0x683, nSamples);   
00183   
00184   d=d+4;  // move to the block payload.
00185 
00186   // FIRST DO EM CANDS
00187 
00188   // re-interpret payload pointer to 16 bit.
00189   uint16_t * p16 = reinterpret_cast<uint16_t *>(d);
00190 
00191   for (unsigned iCat=0; iCat < NUM_EM_CAND_CATEGORIES; ++iCat)   // loop over non-iso/iso candidates categories
00192   {
00193     const L1GctEmCandCollection * em = emCands.at(iCat);   // The current category of EM cands.
00194     const unsigned bx0Offset = bx0EmCandOffsets.at(iCat);  // The offset in the EM cand collection to the bx=0 cands.
00195     
00196     uint16_t * cand = p16 + (iCat*4);
00197 
00198     *cand = em->at(bx0Offset).raw();
00199     cand++;
00200     *cand = em->at(bx0Offset + 2).raw();
00201     cand += nSamples;
00202     *cand = em->at(bx0Offset + 1).raw();
00203     cand++;
00204     *cand = em->at(bx0Offset + 3).raw();
00205   }
00206   
00207   // NOW DO ENERGY SUMS
00208   // assumes these are all 1-object collections, ie. central BX only
00209   p16+=8;  // Move past EM cands
00210   *p16 = etTotal->at(bx0EtTotalOffset).raw();  // Et Total - 16 bits.
00211   p16++;
00212   *p16 = etHad->at(bx0EtHadOffset).raw();  // Et Hadronic - next 16 bits
00213   p16++;
00214   uint32_t * p32 = reinterpret_cast<uint32_t *>(p16);  // For writing Missing Et (32-bit raw data)
00215   *p32 = etMiss->at(bx0EtMissOffset).raw();  // Et Miss on final 32 bits of block payload.
00216 }
00217 
00218 void GctFormatTranslateMCLegacy::writeGctOutJetBlock(unsigned char * d,
00219                                                      const L1GctJetCandCollection* cenJets,
00220                                                      const L1GctJetCandCollection* forJets,
00221                                                      const L1GctJetCandCollection* tauJets, 
00222                                                      const L1GctHFRingEtSumsCollection* hfRingSums,
00223                                                      const L1GctHFBitCountsCollection* hfBitCounts,
00224                                                      const L1GctHtMissCollection* htMiss)
00225 {
00226   // Set up a vector of the collections for easy iteration.
00227   vector<const L1GctJetCandCollection*> jets(NUM_JET_CATEGORIES);
00228   jets.at(CENTRAL_JETS)=cenJets;
00229   jets.at(FORWARD_JETS)=forJets;
00230   jets.at(TAU_JETS)=tauJets;
00231 
00232   /* To hold the offsets within the three jet cand collections for the bx=0 jets.
00233    * The capture index doesn't seem to get set properly by the emulator, so take the
00234    * first bx=0 jet as the highest energy jet, and the fourth as the lowest. */
00235   vector<unsigned> bx0JetCandOffsets(NUM_JET_CATEGORIES);
00236 
00237   // Loop over the different catagories of jets to find the bx=0 offsets.
00238   for(unsigned int iCat = 0 ; iCat < NUM_JET_CATEGORIES ; ++iCat)
00239   {
00240     const L1GctJetCandCollection * jetCands = jets.at(iCat);
00241     unsigned& offset = bx0JetCandOffsets.at(iCat);
00242     if(!findBx0OffsetInCollection(offset, jetCands)) { LogDebug("GCT") << "No jet candidates with bx=0!\nAborting packing of GCT Jet Output!"; return; }
00243     if((jetCands->size()-offset) < 4) { LogDebug("GCT") << "Insufficient jet candidates with bx=0!\nAborting packing of GCT Jet Output!"; return; }
00244   }
00245   
00246   // Now find the collection offsets for the HfRingSums, HfBitCounts, and HtMiss with bx=0
00247   unsigned bx0HfRingSumsOffset, bx0HfBitCountsOffset, bx0HtMissOffset;
00248   if(!findBx0OffsetInCollection(bx0HfRingSumsOffset, hfRingSums)) { LogDebug("GCT") << "No ring sums with bx=0!\nAborting packing of GCT Jet Output!"; return; }
00249   if(!findBx0OffsetInCollection(bx0HfBitCountsOffset, hfBitCounts)) { LogDebug("GCT") << "No bit counts with bx=0!\nAborting packing of GCT Jet Output!"; return; }
00250   if(!findBx0OffsetInCollection(bx0HtMissOffset, htMiss)) { LogDebug("GCT") << "No missing Ht with bx=0!\nAborting packing of GCT Jet Output!"; return; }
00251 
00252   // Now write the header, as we should now have all requisite data.
00253   writeRawHeader(d, 0x583, 1);  // ** NOTE can only currenly do 1 timesample! **
00254   
00255   d=d+4;  // move forward past the block header to the block payload.
00256 
00257   // FIRST DO JET CANDS
00258   // re-interpret pointer to 16 bits - the space allocated for each Jet candidate.
00259   uint16_t * p16 = reinterpret_cast<uint16_t *>(d);
00260   
00261   const unsigned categoryOffset = 4;  // Offset to jump from one jet category to the next.
00262   const unsigned nextCandPairOffset = 2;  // Offset to jump to next candidate pair.
00263 
00264   // Loop over the different catagories of jets
00265   for(unsigned iCat = 0 ; iCat < NUM_JET_CATEGORIES ; ++iCat)
00266   {
00267     const L1GctJetCandCollection * jetCands = jets.at(iCat); // The current category of jet cands.
00268     const unsigned cand0Offset = iCat*categoryOffset;       // the offset on p16 to get the rank 0 Jet Cand of the correct category.
00269     const unsigned bx0Offset = bx0JetCandOffsets.at(iCat);  // The offset in the jet cand collection to the bx=0 jets.
00270     
00271     p16[cand0Offset] = jetCands->at(bx0Offset).raw();  // rank 0 jet in bx=0
00272     p16[cand0Offset + nextCandPairOffset] = jetCands->at(bx0Offset + 1).raw(); // rank 1 jet in bx=0
00273     p16[cand0Offset + 1] = jetCands->at(bx0Offset + 2).raw(); // rank 2 jet in bx=0
00274     p16[cand0Offset + nextCandPairOffset + 1] = jetCands->at(bx0Offset + 3).raw(); // rank 3 jet in bx=0.
00275   }
00276   
00277   // NOW DO JET COUNTS
00278   d=d+24;  // move forward past the jet cands to the jet counts section
00279 
00280   // re-interpret pointer to 32 bit.
00281   uint32_t * p32 = reinterpret_cast<uint32_t *>(d);
00282   
00283   uint32_t tmp = hfBitCounts->at(bx0HfBitCountsOffset).raw() & 0xfff;
00284   tmp |= hfRingSums->at(bx0HfRingSumsOffset).etSum(0)<<12;
00285   tmp |= hfRingSums->at(bx0HfRingSumsOffset).etSum(1)<<16;
00286   tmp |= hfRingSums->at(bx0HfRingSumsOffset).etSum(2)<<19;
00287   tmp |= hfRingSums->at(bx0HfRingSumsOffset).etSum(3)<<22;
00288   p32[0] = tmp;
00289   
00290   const L1GctHtMiss& bx0HtMiss = htMiss->at(bx0HtMissOffset);
00291   uint32_t htMissRaw = 0x5555c000 |
00292                        (bx0HtMiss.overFlow() ? 0x1000 : 0x0000) |
00293                        ((bx0HtMiss.et() & 0x7f) << 5) |
00294                        ((bx0HtMiss.phi() & 0x1f));
00295   
00296   p32[1] = htMissRaw;
00297 }
00298 
00299 void GctFormatTranslateMCLegacy::writeRctEmCandBlocks(unsigned char * d, const L1CaloEmCollection * rctEm)
00300 {
00301   // This method is one giant "temporary" hack for CMSSW_1_8_X and CMSSW_2_0_0.
00302 
00303   if(rctEm->size() == 0 || rctEm->size()%144 != 0)  // Should be 18 crates * 2 types (iso/noniso) * 4 electrons = 144 for 1 bx.
00304   {
00305     LogDebug("GCT") << "Block pack error: bad L1CaloEmCollection size detected!\n"
00306                     << "Aborting packing of RCT EM Cand data!";
00307     return;
00308   }
00309 
00310   // Need 18 sets of EM fibre data, since 18 RCT crates  
00311   SourceCardRouting::EmuToSfpData emuToSfpData[18];
00312 
00313   // Fill in the input arrays with the data from the digi  
00314   for(unsigned i=0, size=rctEm->size(); i < size ; ++i)
00315   {
00316     const L1CaloEmCand &cand = rctEm->at(i);
00317     if(cand.bx() != 0) { continue; }  // Only interested in bunch crossing zero for now!
00318     unsigned crateNum = cand.rctCrate();
00319     unsigned index = cand.index();
00320     
00321     // Some error checking.
00322     assert(crateNum < 18); // Only 18 RCT crates!
00323     assert(index < 4); // Should only be 4 cands of each type per crate!
00324     
00325     if(cand.isolated())
00326     {
00327       emuToSfpData[crateNum].eIsoRank[index] = cand.rank();
00328       emuToSfpData[crateNum].eIsoCardId[index] = cand.rctCard();
00329       emuToSfpData[crateNum].eIsoRegionId[index] = cand.rctRegion();
00330     }
00331     else
00332     {
00333       emuToSfpData[crateNum].eNonIsoRank[index] = cand.rank();
00334       emuToSfpData[crateNum].eNonIsoCardId[index] = cand.rctCard();
00335       emuToSfpData[crateNum].eNonIsoRegionId[index] = cand.rctRegion();
00336     }
00337     // Note doing nothing with the MIP bit and Q bit arrays as we are not
00338     // interested in them; these arrays will contain uninitialised junk
00339     // and so you will get out junk for sourcecard output 0 - I.e. don't
00340     // trust sfp[0][0] or sfp[1][0] output!. 
00341   }
00342 
00343   // Now run the conversion
00344   for(unsigned c = 0 ; c < 18 ; ++c)
00345   {
00346     srcCardRouting().EMUtoSFP(emuToSfpData[c].eIsoRank, emuToSfpData[c].eIsoCardId, emuToSfpData[c].eIsoRegionId,
00347                               emuToSfpData[c].eNonIsoRank, emuToSfpData[c].eNonIsoCardId, emuToSfpData[c].eNonIsoRegionId,
00348                               emuToSfpData[c].mipBits, emuToSfpData[c].qBits, emuToSfpData[c].sfp);
00349   }
00350   
00351   // Now pack up the data into the RAW format.
00352   BlkToRctCrateMap::iterator blockStartCrateIter;
00353   for(blockStartCrateIter = rctEmCrateMap().begin() ; blockStartCrateIter != rctEmCrateMap().end() ; ++blockStartCrateIter)
00354   {
00355     unsigned blockId = blockStartCrateIter->first;
00356     unsigned startCrate = blockStartCrateIter->second;
00357     unsigned blockLength_32bit = blockLengthMap()[blockId];
00358     
00359     writeRawHeader(d, blockId, 1);
00360     d+=4; // move past header.
00361     
00362     // Want a 16 bit pointer to push the 16 bit data in.
00363     uint16_t * p16 = reinterpret_cast<uint16_t *>(const_cast<unsigned char *>(d));
00364     
00365     for(unsigned iCrate=startCrate, end=startCrate + blockLength_32bit/3 ; iCrate < end ; ++iCrate)
00366     {
00367       for(unsigned iOutput = 1 ; iOutput < 4 ; ++iOutput)  // skipping output 0 as that is Q-bit/MIP-bit data.
00368       {
00369         for(unsigned iCycle = 0 ; iCycle < 2 ; ++iCycle)
00370         {
00371           *p16 = emuToSfpData[iCrate].sfp[iCycle][iOutput];
00372           ++p16;
00373         }
00374       } 
00375     }
00376     
00377     // Now move d onto the location of the next block header
00378     d+=(blockLength_32bit*4);
00379   }
00380 }
00381 
00382 void GctFormatTranslateMCLegacy::writeAllRctCaloRegionBlock(unsigned char * d, const L1CaloRegionCollection * rctCalo)
00383 {
00384   // This method is one giant "temporary" hack for CMSSW_1_8_X and CMSSW_2_0_0.
00385 
00386   if(rctCalo->size() == 0 || rctCalo->size()%396 != 0)  // Should be 396 calo regions for 1 bx.
00387   {
00388     LogDebug("GCT") << "Block pack error: bad L1CaloRegionCollection size detected!\n"
00389                     << "Aborting packing of RCT Calo Region data!";
00390     return;
00391   }
00392 
00393   writeRawHeader(d, 0x0ff, 1);
00394   d+=4; // move past header.
00395 
00396   // Want a 16 bit pointer to push the 16 bit data in.
00397   uint16_t * p16 = reinterpret_cast<uint16_t *>(const_cast<unsigned char *>(d));
00398  
00399   for(unsigned i=0, size=rctCalo->size(); i < size ; ++i)
00400   {
00401     const L1CaloRegion &reg = rctCalo->at(i);
00402     if(reg.bx() != 0) { continue; }  // Only interested in bunch crossing zero for now!
00403     const unsigned crateNum = reg.rctCrate();
00404     const unsigned regionIndex = reg.rctRegionIndex();
00405     assert(crateNum < 18); // Only 18 RCT crates!
00406     
00407     // Gotta make the raw data as there currently isn't a method of getting raw from L1CaloRegion
00408     const uint16_t raw =  reg.et()                        | 
00409                          (reg.overFlow()  ? 0x400  : 0x0) |
00410                          (reg.fineGrain() ? 0x800  : 0x0) |
00411                          (reg.mip()       ? 0x1000 : 0x0) |
00412                          (reg.quiet()     ? 0x2000 : 0x0);
00413  
00414     unsigned offset = 0;  // for storing calculated raw data offset.   
00415     if(reg.isHbHe())  // Is a barrel/endcap region
00416     {
00417       const unsigned cardNum = reg.rctCard();
00418       assert(cardNum < 7);  // 7 RCT cards per crate for the barrel/endcap
00419       assert(regionIndex < 2); // regionIndex less than 2 for barrel/endcap
00420       
00421       // Calculate position in the raw data from crateNum, cardNum, and regionIndex
00422       offset = crateNum*22 + cardNum*2 + regionIndex;
00423     }
00424     else  // Must be forward region
00425     {
00426       assert(regionIndex < 8); // regionIndex less than 8 for forward calorimeter.
00427       offset = crateNum*22 + 14 + regionIndex;
00428     }
00429     p16[offset] = raw;  // Write raw data in correct place!
00430   }
00431 }
00432 
00433 
00434 // PROTECTED METHODS
00435 
00436 uint32_t GctFormatTranslateMCLegacy::generateRawHeader(const uint32_t blockId,
00437                                                        const uint32_t nSamples,
00438                                                        const uint32_t bxId,
00439                                                        const uint32_t eventId) const
00440 {
00441   //  Bit mapping of header:
00442   //  ----------------------
00443   //  11:0   => block_id  Unique pipeline identifier.
00444   //   - 3:0    =>> pipe_id There can be up to 16 different pipelines per FPGA.
00445   //   - 6:4    =>> reserved  Do not use yet. Set to zero.
00446   //   - 11:7   =>> fpga geograpical add  The VME geographical address of the FPGA.
00447   //  15:12  => event_id  Determined locally.  Not reset by Resync.
00448   //  19:16  => number_of_time_samples  If time samples 15 or more then value = 15.
00449   //  31:20  => event_bxId  The bunch crossing the data was recorded.
00450 
00451   return ((bxId & 0xfff) << 20) | ((nSamples & 0xf) << 16) | ((eventId & 0xf) << 12) | (blockId & 0xfff);
00452 }
00453 
00454 
00455 // PRIVATE METHODS
00456 
00457 // Output EM Candidates unpacking
00458 void GctFormatTranslateMCLegacy::blockToGctEmCandsAndEnergySums(const unsigned char * d, const GctBlockHeader& hdr)
00459 {
00460   const unsigned int id = hdr.blockId();
00461   const unsigned int nSamples = hdr.nSamples();
00462 
00463   // Re-interpret pointer.  p16 will be pointing at the 16 bit word that
00464   // contains the rank0 non-isolated electron of the zeroth time-sample.
00465   const uint16_t * p16 = reinterpret_cast<const uint16_t *>(d);
00466 
00467   // UNPACK EM CANDS
00468 
00469   const unsigned int emCandCategoryOffset = nSamples * 4;  // Offset to jump from the non-iso electrons to the isolated ones.
00470   const unsigned int timeSampleOffset = nSamples * 2;  // Offset to jump to next candidate pair in the same time-sample.
00471 
00472   unsigned int samplesToUnpack = 1;
00473   if(!hltMode()) { samplesToUnpack = nSamples; }  // Only if not running in HLT mode do we want more than 1 timesample. 
00474 
00475   for (unsigned int iso=0; iso<2; ++iso)  // loop over non-iso/iso candidate pairs
00476   {
00477     bool isoFlag = (iso==1);
00478 
00479     // Get the correct collection to put them in.
00480     L1GctEmCandCollection* em;
00481     if (isoFlag) { em = colls()->gctIsoEm(); }
00482     else { em = colls()->gctNonIsoEm(); }
00483 
00484     for (unsigned int bx=0; bx<samplesToUnpack; ++bx) // loop over time samples
00485     {
00486       // cand0Offset will give the offset on p16 to get the rank 0 candidate
00487       // of the correct category and timesample.
00488       const unsigned int cand0Offset = iso*emCandCategoryOffset + bx*2;
00489 
00490       em->push_back(L1GctEmCand(p16[cand0Offset], isoFlag, id, 0, bx));  // rank0 electron
00491       em->push_back(L1GctEmCand(p16[cand0Offset + timeSampleOffset], isoFlag, id, 1, bx));  // rank1 electron
00492       em->push_back(L1GctEmCand(p16[cand0Offset + 1], isoFlag, id, 2, bx));  // rank2 electron
00493       em->push_back(L1GctEmCand(p16[cand0Offset + timeSampleOffset + 1], isoFlag, id, 3, bx));  // rank3 electron
00494     }
00495   }
00496 
00497   p16 += emCandCategoryOffset * 2;  // Move the pointer over the data we've already unpacked.
00498 
00499   // UNPACK ENERGY SUMS
00500   // NOTE: we are only unpacking one timesample of these currently!
00501 
00502   colls()->gctEtTot()->push_back(L1GctEtTotal(p16[0]));  // Et total (timesample 0).
00503   colls()->gctEtHad()->push_back(L1GctEtHad(p16[1]));  // Et hadronic (timesample 0).
00504 
00505   // 32-bit pointer for getting Missing Et.
00506   const uint32_t * p32 = reinterpret_cast<const uint32_t *>(p16);
00507 
00508   colls()->gctEtMiss()->push_back(L1GctEtMiss(p32[nSamples])); // Et Miss (timesample 0).
00509 }
00510 
00511 void GctFormatTranslateMCLegacy::blockToGctJetCandsAndCounts(const unsigned char * d, const GctBlockHeader& hdr)
00512 {
00513   const unsigned int id = hdr.blockId();  // Capture block ID.
00514   const unsigned int nSamples = hdr.nSamples();  // Number of time-samples.
00515 
00516   // Re-interpret block payload pointer to 16 bits so it sees one candidate at a time.
00517   // p16 points to the start of the block payload, at the rank0 tau jet candidate.
00518   const uint16_t * p16 = reinterpret_cast<const uint16_t *>(d);
00519 
00520   // UNPACK JET CANDS
00521 
00522   const unsigned int jetCandCategoryOffset = nSamples * 4;  // Offset to jump from one jet category to the next.
00523   const unsigned int timeSampleOffset = nSamples * 2;  // Offset to jump to next candidate pair in the same time-sample.
00524 
00525   unsigned int samplesToUnpack = 1;
00526   if(!hltMode()) { samplesToUnpack = nSamples; }  // Only if not running in HLT mode do we want more than 1 timesample. 
00527 
00528   // Loop over the different catagories of jets
00529   for(unsigned int iCat = 0 ; iCat < NUM_JET_CATEGORIES ; ++iCat)
00530   {
00531     L1GctJetCandCollection * const jets = gctJets(iCat);
00532     assert(jets->empty()); // The supplied vector should be empty.
00533 
00534     bool tauflag = (iCat == TAU_JETS);
00535     bool forwardFlag = (iCat == FORWARD_JETS);
00536 
00537     // Loop over the different timesamples (bunch crossings).
00538     for(unsigned int bx = 0 ; bx < samplesToUnpack ; ++bx)
00539     {
00540       // cand0Offset will give the offset on p16 to get the rank 0 Jet Cand of the correct category and timesample.
00541       const unsigned int cand0Offset = iCat*jetCandCategoryOffset + bx*2;
00542 
00543       // Rank 0 Jet.
00544       jets->push_back(L1GctJetCand(p16[cand0Offset], tauflag, forwardFlag, id, 0, bx));
00545       // Rank 1 Jet.
00546       jets->push_back(L1GctJetCand(p16[cand0Offset + timeSampleOffset], tauflag, forwardFlag, id, 1, bx));
00547       // Rank 2 Jet.
00548       jets->push_back(L1GctJetCand(p16[cand0Offset + 1],  tauflag, forwardFlag, id, 2, bx));
00549       // Rank 3 Jet.
00550       jets->push_back(L1GctJetCand(p16[cand0Offset + timeSampleOffset + 1], tauflag, forwardFlag, id, 3, bx));
00551     }
00552   }
00553 
00554   p16 += NUM_JET_CATEGORIES * jetCandCategoryOffset; // Move the pointer over the data we've already unpacked.
00555 
00556   // NOW UNPACK: HFBitCounts, HFRingEtSums and Missing Ht
00557   // NOTE: we are only unpacking one timesample of these currently!
00558 
00559   // Re-interpret block payload pointer to 32 bits so it sees six jet counts at a time.
00560   const uint32_t * p32 = reinterpret_cast<const uint32_t *>(p16);
00561 
00562   // Channel 0 carries both HF counts and sums
00563   colls()->gctHfBitCounts()->push_back(L1GctHFBitCounts::fromConcHFBitCounts(id,6,0,p32[0])); 
00564   colls()->gctHfRingEtSums()->push_back(L1GctHFRingEtSums::fromConcRingSums(id,6,0,p32[0]));
00565 
00566   // Channel 1 carries Missing HT.
00567   colls()->gctHtMiss()->push_back(L1GctHtMiss(p32[nSamples], 0));
00568 }
00569 
00570 // Input EM Candidates unpacking
00571 // this is the last time I deal the RCT bit assignment travesty!!!
00572 void GctFormatTranslateMCLegacy::blockToRctEmCand(const unsigned char * d, const GctBlockHeader& hdr)
00573 {
00574   // Don't want to do this in HLT optimisation mode!
00575   if(hltMode()) { LogDebug("GCT") << "HLT mode - skipping unpack of RCT EM Cands"; return; }
00576 
00577   unsigned int id = hdr.blockId();
00578   unsigned int nSamples = hdr.nSamples();
00579   unsigned int length = hdr.blockLength();
00580 
00581   // re-interpret pointer
00582   uint16_t * p = reinterpret_cast<uint16_t *>(const_cast<unsigned char *>(d));
00583 
00584   // arrays of source card data
00585   uint16_t sfp[2][4]; // [ cycle ] [ SFP ]
00586   uint16_t eIsoRank[4];
00587   uint16_t eIsoCard[4];
00588   uint16_t eIsoRgn[4];
00589   uint16_t eNonIsoRank[4];
00590   uint16_t eNonIsoCard[4];
00591   uint16_t eNonIsoRgn[4];
00592   uint16_t MIPbits[7][2];
00593   uint16_t QBits[7][2];
00594 
00595   unsigned int bx = 0;
00596 
00597   // loop over crates
00598   for (unsigned int crate=rctEmCrateMap()[id]; crate<rctEmCrateMap()[id]+length/3; ++crate) {
00599 
00600     // read SC SFP words
00601     for (unsigned short iSfp=0 ; iSfp<4 ; ++iSfp) {
00602       for (unsigned short cyc=0 ; cyc<2 ; ++cyc) {
00603         if (iSfp==0) { sfp[cyc][iSfp] = 0; } // muon bits
00604         else {                               // EM candidate
00605           sfp[cyc][iSfp] = *p;
00606           ++p;
00607         }
00608       }
00609       p = p + 2*(nSamples-1);
00610     }
00611 
00612     // fill SC arrays
00613     srcCardRouting().SFPtoEMU(eIsoRank, eIsoCard, eIsoRgn, eNonIsoRank, eNonIsoCard, eNonIsoRgn, MIPbits, QBits, sfp);
00614     
00615     // create EM cands
00616     for (unsigned short int i=0; i<4; ++i) {
00617       colls()->rctEm()->push_back( L1CaloEmCand( eIsoRank[i], eIsoRgn[i], eIsoCard[i], crate, true, i, bx) );
00618     }
00619     for (unsigned short int i=0; i<4; ++i) {
00620       colls()->rctEm()->push_back( L1CaloEmCand( eNonIsoRank[i], eNonIsoRgn[i], eNonIsoCard[i], crate, false, i, bx) );
00621     }
00622   }
00623 }
00624 
00625 // Fibre unpacking
00626 void GctFormatTranslateMCLegacy::blockToFibres(const unsigned char * d, const GctBlockHeader& hdr)
00627 {
00628   // Don't want to do this in HLT optimisation mode!
00629   if(hltMode()) { LogDebug("GCT") << "HLT mode - skipping unpack of GCT Fibres"; return; }
00630   
00631   unsigned int id = hdr.blockId();
00632   unsigned int nSamples = hdr.nSamples();
00633   unsigned int length = hdr.blockLength();
00634 
00635   // re-interpret pointer
00636   uint32_t * p = reinterpret_cast<uint32_t *>(const_cast<unsigned char *>(d));
00637 
00638   for (unsigned int i=0; i<length; ++i) {
00639     for (unsigned int bx=0; bx<nSamples; ++bx) {
00640       colls()->gctFibres()->push_back( L1GctFibreWord(*p, id, i, bx) );
00641       ++p;
00642     }
00643   } 
00644 }
00645 
00646 void GctFormatTranslateMCLegacy::blockToFibresAndToRctEmCand(const unsigned char * d, const GctBlockHeader& hdr)
00647 {
00648   this->blockToRctEmCand(d, hdr);
00649   this->blockToFibres(d, hdr);
00650 }
00651 
00652 void GctFormatTranslateMCLegacy::blockToAllRctCaloRegions(const unsigned char * d, const GctBlockHeader& hdr)
00653 {
00654   // Don't want to do this in HLT optimisation mode!
00655   if(hltMode()) { LogDebug("GCT") << "HLT mode - skipping unpack of RCT Calo Regions"; return; }
00656 
00657   // This method is one giant "temporary" hack whilst waiting for proper
00658   // pipeline formats for the RCT calo region data.
00659   
00660   const int nSamples = hdr.nSamples();  // Number of time-samples.
00661 
00662   // Re-interpret block payload pointer to 16 bits
00663   const uint16_t * p16 = reinterpret_cast<const uint16_t *>(d);
00664   
00665   for(unsigned iCrate = 0 ; iCrate < 18 ; ++iCrate)
00666   {
00667     // Barrel and endcap regions
00668     for(unsigned iCard = 0 ; iCard < 7 ; ++iCard)
00669     {
00670       // Samples
00671       for(int16_t iSample = 0 ; iSample < nSamples ; ++iSample)
00672       {
00673         // Two regions per card (and per 32-bit word).
00674         for(unsigned iRegion = 0 ; iRegion < 2 ; ++iRegion)
00675         {
00676           L1CaloRegionDetId id(iCrate, iCard, iRegion);
00677           colls()->rctCalo()->push_back(L1CaloRegion(*p16, id.ieta(), id.iphi(), iSample));
00678           ++p16; //advance pointer
00679         }
00680       }
00681     }
00682     // Forward regions (8 regions numbered 0 through 7, packed in 4 sets of pairs)
00683     for(unsigned iRegionPairNum = 0 ; iRegionPairNum < 4 ; ++iRegionPairNum)
00684     {
00685       // Samples
00686       for(int16_t iSample = 0 ; iSample < nSamples ; ++iSample)
00687       {
00688         // two regions in a pair
00689         for(unsigned iPair = 0 ; iPair < 2 ; ++iPair)
00690         {
00691           // For forward regions, RCTCard=999
00692           L1CaloRegionDetId id(iCrate, 999, iRegionPairNum*2 + iPair);
00693           colls()->rctCalo()->push_back(L1CaloRegion(*p16, id.ieta(), id.iphi(), iSample));
00694           ++p16; //advance pointer
00695         }
00696       }
00697     }
00698   }
00699 }
00700 
00701 template <typename Collection> 
00702 bool GctFormatTranslateMCLegacy::findBx0OffsetInCollection(unsigned& bx0Offset, const Collection* coll)
00703 {
00704   bool foundBx0 = false;
00705   unsigned size = coll->size();
00706   for(bx0Offset = 0 ; bx0Offset < size ; ++bx0Offset)
00707   {
00708     if(coll->at(bx0Offset).bx() == 0) { foundBx0 = true; break; }
00709   }
00710   return foundBx0;
00711 }