Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 ///
0002 /// \class l1t::Stage2Layer2EGammaAlgorithmFirmwareImp1
0003 ///
0004 /// \author: Jim Brooke
0005 ///
0006 /// Description: first iteration of stage 2 jet algo
0007 
0008 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0009 #include "L1Trigger/L1TCalorimeter/interface/Stage2Layer2EGammaAlgorithmFirmware.h"
0010 
0011 #include "L1Trigger/L1TCalorimeter/interface/CaloStage2Nav.h"
0012 #include "L1Trigger/L1TCalorimeter/interface/CaloTools.h"
0013 #include "L1Trigger/L1TCalorimeter/interface/BitonicSort.h"
0014 #include "L1Trigger/L1TCalorimeter/interface/AccumulatingSort.h"
0015 
0016 namespace l1t {
0017   bool operator>(const l1t::EGamma& a, const l1t::EGamma& b) { return a.pt() > b.pt(); }
0018 }  // namespace l1t
0019 
0020 /*****************************************************************/
0021 l1t::Stage2Layer2EGammaAlgorithmFirmwareImp1::Stage2Layer2EGammaAlgorithmFirmwareImp1(CaloParamsHelper const* params)
0022     : params_(params)
0023 /*****************************************************************/
0024 {}
0025 
0026 /*****************************************************************/
0027 void l1t::Stage2Layer2EGammaAlgorithmFirmwareImp1::processEvent(const std::vector<l1t::CaloCluster>& clusters,
0028                                                                 const std::vector<l1t::CaloTower>& towers,
0029                                                                 std::vector<l1t::EGamma>& egammas)
0030 /*****************************************************************/
0031 {
0032   l1t::CaloStage2Nav caloNav;
0033   egammas.clear();
0034 
0035   //EGammas without check of FG and shape ID
0036   std::vector<l1t::EGamma> egammas_raw;
0037 
0038   for (const auto& cluster : clusters) {
0039     // Keep only valid clusters
0040     if (cluster.isValid()) {
0041       // need tower energies to recompute egamma trimmed energy
0042       int iEta = cluster.hwEta();
0043       int iPhi = cluster.hwPhi();
0044       int iEtaP = caloNav.offsetIEta(iEta, 1);
0045       int iEtaM = caloNav.offsetIEta(iEta, -1);
0046       int iPhiP = caloNav.offsetIPhi(iPhi, 1);
0047       int iPhiP2 = caloNav.offsetIPhi(iPhi, 2);
0048       int iPhiM = caloNav.offsetIPhi(iPhi, -1);
0049       int iPhiM2 = caloNav.offsetIPhi(iPhi, -2);
0050       const l1t::CaloTower& seed = l1t::CaloTools::getTower(towers, iEta, iPhi);
0051       const l1t::CaloTower& towerNW = l1t::CaloTools::getTower(towers, iEtaM, iPhiM);
0052       const l1t::CaloTower& towerN = l1t::CaloTools::getTower(towers, iEta, iPhiM);
0053       const l1t::CaloTower& towerNE = l1t::CaloTools::getTower(towers, iEtaP, iPhiM);
0054       const l1t::CaloTower& towerE = l1t::CaloTools::getTower(towers, iEtaP, iPhi);
0055       const l1t::CaloTower& towerSE = l1t::CaloTools::getTower(towers, iEtaP, iPhiP);
0056       const l1t::CaloTower& towerS = l1t::CaloTools::getTower(towers, iEta, iPhiP);
0057       const l1t::CaloTower& towerSW = l1t::CaloTools::getTower(towers, iEtaM, iPhiP);
0058       const l1t::CaloTower& towerW = l1t::CaloTools::getTower(towers, iEtaM, iPhi);
0059       const l1t::CaloTower& towerNN = l1t::CaloTools::getTower(towers, iEta, iPhiM2);
0060       const l1t::CaloTower& towerSS = l1t::CaloTools::getTower(towers, iEta, iPhiP2);
0061       //
0062 
0063       int seedEt = seed.hwPt();
0064       int towerEtNW = towerNW.hwPt();
0065       int towerEtN = towerN.hwPt();
0066       int towerEtNE = towerNE.hwPt();
0067       int towerEtE = towerE.hwPt();
0068       int towerEtSE = towerSE.hwPt();
0069       int towerEtS = towerS.hwPt();
0070       int towerEtSW = towerSW.hwPt();
0071       int towerEtW = towerW.hwPt();
0072       int towerEtNN = towerNN.hwPt();
0073       int towerEtSS = towerSS.hwPt();
0074 
0075       if (abs(iEta) > params_->egEtaCut())
0076         continue;
0077 
0078       // initialize egamma from cluster
0079       egammas_raw.push_back(cluster);
0080       l1t::EGamma& egamma = egammas_raw.back();
0081 
0082       // Trim cluster (only for egamma energy computation, the original cluster is unchanged)
0083       l1t::CaloCluster clusterTrim = trimCluster(cluster);
0084 
0085       // Recompute hw energy (of the trimmed cluster) from towers
0086       egamma.setHwPt(seedEt);
0087       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_NW))
0088         egamma.setHwPt(egamma.hwPt() + towerEtNW);
0089       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_N))
0090         egamma.setHwPt(egamma.hwPt() + towerEtN);
0091       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_NE))
0092         egamma.setHwPt(egamma.hwPt() + towerEtNE);
0093       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_E))
0094         egamma.setHwPt(egamma.hwPt() + towerEtE);
0095       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_SE))
0096         egamma.setHwPt(egamma.hwPt() + towerEtSE);
0097       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_S))
0098         egamma.setHwPt(egamma.hwPt() + towerEtS);
0099       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_SW))
0100         egamma.setHwPt(egamma.hwPt() + towerEtSW);
0101       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_W))
0102         egamma.setHwPt(egamma.hwPt() + towerEtW);
0103       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_NN))
0104         egamma.setHwPt(egamma.hwPt() + towerEtNN);
0105       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_SS))
0106         egamma.setHwPt(egamma.hwPt() + towerEtSS);
0107 
0108       //Extended H/E flag computed using all neighbouring towers
0109       bool HoE_ext = idHoverE_ext(seed);
0110       HoE_ext &= idHoverE_ext(towerNW);
0111       HoE_ext &= idHoverE_ext(towerN);
0112       HoE_ext &= idHoverE_ext(towerNE);
0113       HoE_ext &= idHoverE_ext(towerE);
0114       HoE_ext &= idHoverE_ext(towerSE);
0115       HoE_ext &= idHoverE_ext(towerS);
0116       HoE_ext &= idHoverE_ext(towerSW);
0117       HoE_ext &= idHoverE_ext(towerW);
0118       //NN and SS only checked if included
0119       if (cluster.checkClusterFlag(CaloCluster::INCLUDE_NN))
0120         HoE_ext &= idHoverE_ext(towerNN);
0121       if (cluster.checkClusterFlag(CaloCluster::INCLUDE_SS))
0122         HoE_ext &= idHoverE_ext(towerSS);
0123 
0124       // Identification of the egamma
0125       // Based on the seed tower FG bit, the H/E ratio of the seed tower, and the shape of the cluster
0126       bool hOverEBit = cluster.hOverE() > 0 || params_->egBypassHoE();
0127       bool hOverEExtBit = HoE_ext || params_->egBypassExtHOverE();
0128       if (!params_->egBypassExtHOverE())
0129         hOverEExtBit = HoE_ext;
0130       bool shapeBit = idShape(cluster, egamma.hwPt()) || params_->egBypassShape();
0131       bool fgBit = !(cluster.fgECAL()) || params_->egBypassECALFG();
0132       int qual = 0;
0133       if (fgBit)
0134         qual |= (0x1);  // first bit = FG
0135       if (hOverEBit)
0136         qual |= (0x1 << 1);  // second bit = H/E
0137       if (shapeBit)
0138         qual |= (0x1 << 2);  // third bit = shape
0139       if (hOverEExtBit)
0140         qual |= (0x1 << 3);  // fourth bit = shape
0141       egamma.setHwQual(qual);
0142 
0143       // Isolation
0144       int isoLeftExtension = params_->egIsoAreaNrTowersEta();
0145       int isoRightExtension = params_->egIsoAreaNrTowersEta();
0146 
0147       if (cluster.checkClusterFlag(CaloCluster::TRIM_LEFT))
0148         isoRightExtension++;
0149       else
0150         isoLeftExtension++;
0151 
0152       int hwEtSum = CaloTools::calHwEtSum(cluster.hwEta(),
0153                                           cluster.hwPhi(),
0154                                           towers,
0155                                           -isoLeftExtension,
0156                                           isoRightExtension,
0157                                           -1 * params_->egIsoAreaNrTowersPhi(),
0158                                           params_->egIsoAreaNrTowersPhi(),
0159                                           params_->egPUSParam(2));
0160 
0161       int hwFootPrint = isoCalEgHwFootPrint(cluster, towers);
0162       int nrTowers = CaloTools::calNrTowers(-1 * params_->egPUSParam(1),
0163                                             params_->egPUSParam(1),
0164                                             1,
0165                                             72,
0166                                             towers,
0167                                             1 + params_->pileUpTowerThreshold(),
0168                                             999,
0169                                             CaloTools::CALO);
0170       unsigned int lutAddress = isoLutIndex(egamma.hwEta(), nrTowers, egamma.hwPt());
0171 
0172       int isolBit = (((hwEtSum - hwFootPrint) < params_->egIsolationLUT()->data(lutAddress)) ||
0173                      (params_->egIsolationLUT()->data(lutAddress) > 255));
0174       int isolBit2 = (((hwEtSum - hwFootPrint) < params_->egIsolationLUT2()->data(lutAddress)) ||
0175                       (params_->egIsolationLUT2()->data(lutAddress) > 255));
0176       isolBit += (isolBit2 << 1);
0177       egamma.setHwIso(isolBit);
0178       int hwIsoEnergy = hwEtSum - hwFootPrint;
0179 
0180       // development vars
0181       egamma.setTowerIPhi((short int)cluster.hwPhi());
0182       egamma.setTowerIEta((short int)cluster.hwEta());
0183       egamma.setRawEt((short int)egamma.hwPt());
0184       egamma.setIsoEt((short int)hwIsoEnergy);
0185       egamma.setFootprintEt((short int)hwFootPrint);
0186       egamma.setNTT((short int)nrTowers);
0187       egamma.setShape((short int)returnShape(cluster));
0188       egamma.setTowerHoE((short int)returnHoE(seed));
0189 
0190       // Energy calibration
0191       // Corrections function of ieta, ET, and cluster shape
0192       int calibPt = calibratedPt(cluster, egamma.hwPt());
0193       egamma.setHwPt(calibPt);
0194 
0195       // Physical eta/phi. Computed from ieta/iphi of the seed tower and the fine-grain position within the seed
0196       double eta = 0.;
0197       double phi = 0.;
0198       double seedEta = CaloTools::towerEta(cluster.hwEta());
0199       double seedEtaSize = CaloTools::towerEtaSize(cluster.hwEta());
0200       double seedPhi = CaloTools::towerPhi(cluster.hwEta(), cluster.hwPhi());
0201       double seedPhiSize = CaloTools::towerPhiSize(cluster.hwEta());
0202       if (cluster.fgEta() == 0)
0203         eta = seedEta;  // center
0204       //Test
0205       else if (cluster.fgEta() == 2)
0206         eta = seedEta + seedEtaSize * 0.251;  // center + 1/4
0207       else if (cluster.fgEta() == 1)
0208         eta = seedEta - seedEtaSize * 0.251;  // center - 1/4
0209 
0210       //fgPhi is recomputed after trimming
0211       int fgPhi = 0;
0212 
0213       int EtUp = 0;
0214       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_NE))
0215         EtUp += towerEtNE;
0216       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_N))
0217         EtUp += towerEtN;
0218       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_NW))
0219         EtUp += towerEtNW;
0220       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_NN))
0221         EtUp += towerEtNN;
0222       int EtDown = 0;
0223       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_SE))
0224         EtDown += towerEtSE;
0225       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_S))
0226         EtDown += towerEtS;
0227       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_SW))
0228         EtDown += towerEtSW;
0229       if (clusterTrim.checkClusterFlag(CaloCluster::INCLUDE_SS))
0230         EtDown += towerEtSS;
0231       //
0232       if (EtDown > EtUp)
0233         fgPhi = 2;
0234       else if (EtUp > EtDown)
0235         fgPhi = 1;
0236 
0237       if (fgPhi == 0)
0238         phi = seedPhi;  // center
0239       else if (fgPhi == 2)
0240         phi = seedPhi + seedPhiSize * 0.251;  // center + 1/4
0241       else if (fgPhi == 1)
0242         phi = seedPhi - seedPhiSize * 0.251;  // center - 1/4
0243 
0244       // Set 4-vector
0245       math::PtEtaPhiMLorentzVector calibP4((double)calibPt * params_->egLsb(), eta, phi, 0.);
0246       egamma.setP4(calibP4);
0247 
0248     }  //end of cuts on cluster to make EGamma
0249   }  //end of cluster loop
0250 
0251   // prepare content to be sorted -- each phi ring contains 18 elements, with Et = 0 if no candidate exists
0252   math::PtEtaPhiMLorentzVector emptyP4;
0253   l1t::EGamma tempEG(emptyP4, 0, 0, 0, 0);
0254   std::vector<std::vector<l1t::EGamma> > egEtaPos(params_->egEtaCut(), std::vector<l1t::EGamma>(18, tempEG));
0255   std::vector<std::vector<l1t::EGamma> > egEtaNeg(params_->egEtaCut(), std::vector<l1t::EGamma>(18, tempEG));
0256   for (unsigned int iEG = 0; iEG < egammas_raw.size(); iEG++) {
0257     int fgBit = egammas_raw.at(iEG).hwQual() & (0x1);
0258     int hOverEBit = egammas_raw.at(iEG).hwQual() >> 1 & (0x1);
0259     int shapeBit = egammas_raw.at(iEG).hwQual() >> 2 & (0x1);
0260     int hOverEExtBit = egammas_raw.at(iEG).hwQual() >> 3 & (0x1);
0261 
0262     bool IDcuts = (fgBit && hOverEBit && shapeBit && hOverEExtBit) ||
0263                   (egammas_raw.at(iEG).pt() >= params_->egMaxPtHOverE()) || (params_->egBypassEGVetos());
0264 
0265     if (!IDcuts)
0266       continue;
0267     egammas_raw.at(iEG).setHwQual(7);  //Default value in firmware, not used
0268 
0269     if (egammas_raw.at(iEG).hwEta() > 0)
0270       egEtaPos.at(egammas_raw.at(iEG).hwEta() - 1).at((72 - egammas_raw.at(iEG).hwPhi()) / 4) = egammas_raw.at(iEG);
0271     else
0272       egEtaNeg.at(-(egammas_raw.at(iEG).hwEta() + 1)).at((72 - egammas_raw.at(iEG).hwPhi()) / 4) = egammas_raw.at(iEG);
0273   }
0274 
0275   AccumulatingSort<l1t::EGamma> etaPosSorter(6);
0276   AccumulatingSort<l1t::EGamma> etaNegSorter(6);
0277   std::vector<l1t::EGamma> accumEtaPos;
0278   std::vector<l1t::EGamma> accumEtaNeg;
0279 
0280   for (int ieta = 0; ieta < params_->egEtaCut(); ++ieta) {
0281     // eta +
0282     std::vector<l1t::EGamma>::iterator start_, end_;
0283     start_ = egEtaPos.at(ieta).begin();
0284     end_ = egEtaPos.at(ieta).end();
0285     BitonicSort<l1t::EGamma>(down, start_, end_);
0286     etaPosSorter.Merge(egEtaPos.at(ieta), accumEtaPos);
0287 
0288     // eta -
0289     start_ = egEtaNeg.at(ieta).begin();
0290     end_ = egEtaNeg.at(ieta).end();
0291     BitonicSort<l1t::EGamma>(down, start_, end_);
0292     etaNegSorter.Merge(egEtaNeg.at(ieta), accumEtaNeg);
0293   }
0294 
0295   // put all 12 candidates in the original tau vector, removing zero energy ones
0296   egammas.clear();
0297   for (const l1t::EGamma& acceg : accumEtaPos) {
0298     if (acceg.hwPt() > 0)
0299       egammas.push_back(acceg);
0300   }
0301   for (const l1t::EGamma& acceg : accumEtaNeg) {
0302     if (acceg.hwPt() > 0)
0303       egammas.push_back(acceg);
0304   }
0305 }
0306 
0307 /*****************************************************************/
0308 bool l1t::Stage2Layer2EGammaAlgorithmFirmwareImp1::idShape(const l1t::CaloCluster& clus, int hwPt)
0309 /*****************************************************************/
0310 {
0311   unsigned int shape = 0;
0312   if ((clus.checkClusterFlag(CaloCluster::INCLUDE_N)))
0313     shape |= (0x1);
0314   if ((clus.checkClusterFlag(CaloCluster::INCLUDE_S)))
0315     shape |= (0x1 << 1);
0316   if (clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_E)))
0317     shape |= (0x1 << 2);
0318   if (!clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_W)))
0319     shape |= (0x1 << 2);
0320   if (clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_NE)))
0321     shape |= (0x1 << 3);
0322   if (!clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_NW)))
0323     shape |= (0x1 << 3);
0324   if (clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_SE)))
0325     shape |= (0x1 << 4);
0326   if (!clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_SW)))
0327     shape |= (0x1 << 4);
0328   if (clus.checkClusterFlag(CaloCluster::INCLUDE_NN))
0329     shape |= (0x1 << 5);
0330   if (clus.checkClusterFlag(CaloCluster::INCLUDE_SS))
0331     shape |= (0x1 << 6);
0332 
0333   unsigned int lutAddress = idShapeLutIndex(clus.hwEta(), hwPt, shape);
0334   bool shapeBit = ((params_->egCalibrationLUT()->data(lutAddress)) >> 9) & 0x1;
0335 
0336   return shapeBit;
0337 }
0338 
0339 /*****************************************************************/
0340 unsigned int l1t::Stage2Layer2EGammaAlgorithmFirmwareImp1::idShapeLutIndex(int iEta, int E, int shape)
0341 /*****************************************************************/
0342 {
0343   if (params_->egShapeIdType() == "compressed") {
0344     unsigned int iEtaNormed = abs(iEta);
0345     if (iEtaNormed > 28)
0346       iEtaNormed = 28;
0347     if (E > 255)
0348       E = 255;
0349     unsigned int compressedShape = params_->egCompressShapesLUT()->data(shape);
0350     unsigned int compressedE = params_->egCompressShapesLUT()->data((0x1 << 7) + E);
0351     unsigned int compressedEta = params_->egCompressShapesLUT()->data((0x1 << 7) + (0x1 << 8) + iEtaNormed);
0352     return (compressedShape | compressedE | compressedEta);
0353   } else  // Uncompressed (kept for backward compatibility)
0354   {
0355     unsigned int iEtaNormed = abs(iEta);
0356     if (iEtaNormed > 28)
0357       iEtaNormed = 28;
0358     if (E > 255)
0359       E = 255;
0360     unsigned int compressedShape = params_->egCompressShapesLUT()->data(shape);
0361     return E + compressedShape * 256 + (iEtaNormed - 1) * 256 * 64;
0362   }
0363 }
0364 
0365 //calculates the footprint of the electron in hardware values
0366 /*****************************************************************/
0367 int l1t::Stage2Layer2EGammaAlgorithmFirmwareImp1::isoCalEgHwFootPrint(const l1t::CaloCluster& clus,
0368                                                                       const std::vector<l1t::CaloTower>& towers)
0369 /*****************************************************************/
0370 {
0371   int iEta = clus.hwEta();
0372   int iPhi = clus.hwPhi();
0373 
0374   // hwEmEtSumLeft =  CaloTools::calHwEtSum(iEta,iPhi,towers,-1,-1,-1,1,CaloTools::ECAL);
0375   // int hwEmEtSumRight = CaloTools::calHwEtSum(iEta,iPhi,towers,1,1,-1,1,CaloTools::ECAL);
0376 
0377   int etaSide =
0378       clus.checkClusterFlag(CaloCluster::TRIM_LEFT) ? 1 : -1;  //if we trimed left, its the right (ie +ve) side we want
0379   int phiSide = iEta > 0 ? 1 : -1;
0380 
0381   int ecalHwFootPrint = CaloTools::calHwEtSum(iEta,
0382                                               iPhi,
0383                                               towers,
0384                                               0,
0385                                               0,
0386                                               -1 * params_->egIsoVetoNrTowersPhi(),
0387                                               params_->egIsoVetoNrTowersPhi(),
0388                                               params_->egPUSParam(2),
0389                                               CaloTools::ECAL) +
0390                         CaloTools::calHwEtSum(iEta,
0391                                               iPhi,
0392                                               towers,
0393                                               etaSide,
0394                                               etaSide,
0395                                               -1 * params_->egIsoVetoNrTowersPhi(),
0396                                               params_->egIsoVetoNrTowersPhi(),
0397                                               params_->egPUSParam(2),
0398                                               CaloTools::ECAL);
0399 
0400   //Because of compression E+H can be different from E + H
0401   int ecalHwFootPrint_2x1 =
0402       CaloTools::calHwEtSum(iEta, iPhi, towers, 0, 0, 0, 0, params_->egPUSParam(2), CaloTools::ECAL) +
0403       CaloTools::calHwEtSum(iEta, iPhi, towers, 0, 0, phiSide, phiSide, params_->egPUSParam(2), CaloTools::ECAL);
0404 
0405   int ecalhcal_HwFootPrint_2x1 =
0406       CaloTools::calHwEtSum(iEta, iPhi, towers, 0, 0, 0, 0, params_->egPUSParam(2)) +
0407       CaloTools::calHwEtSum(iEta, iPhi, towers, 0, 0, phiSide, phiSide, params_->egPUSParam(2));
0408 
0409   return ecalHwFootPrint - ecalHwFootPrint_2x1 + ecalhcal_HwFootPrint_2x1;
0410 }
0411 
0412 //ieta =-28, nrTowers 0 is 0, increases to ieta28, nrTowers=kNrTowersInSum
0413 /*****************************************************************/
0414 unsigned l1t::Stage2Layer2EGammaAlgorithmFirmwareImp1::isoLutIndex(int iEta, unsigned int nrTowers, int E)
0415 /*****************************************************************/
0416 {
0417   if (params_->egIsolationType() == "compressed") {
0418     if (nrTowers > 255)
0419       nrTowers = 255;
0420     unsigned int iEtaNormed = abs(iEta);
0421     if (iEtaNormed > 28)
0422       iEtaNormed = 28;
0423     if (E > 255)
0424       E = 255;
0425     unsigned int compressednTT = params_->egCompressShapesLUT()->data((0x1 << 7) + (0x1 << 8) + (0x1 << 5) + nrTowers);
0426     unsigned int compressedE = params_->egCompressShapesLUT()->data((0x1 << 7) + E) << 1;
0427     unsigned int compressedEta = params_->egCompressShapesLUT()->data((0x1 << 7) + (0x1 << 8) + iEtaNormed) << 1;
0428 
0429     return (compressednTT | compressedE | compressedEta);
0430   }
0431 
0432   else  // Uncompressed (kept for backward compatibility)
0433   {
0434     const unsigned int kNrTowersInSum = 72 * params_->egPUSParam(1) * 2;
0435     const unsigned int kTowerGranularity = params_->egPUSParam(0);
0436     const unsigned int kMaxAddress = kNrTowersInSum % kTowerGranularity == 0
0437                                          ? (kNrTowersInSum / kTowerGranularity + 1) * 28 * 2
0438                                          : (kNrTowersInSum / kTowerGranularity) * 28 * 2;
0439 
0440     unsigned int nrTowersNormed = nrTowers / kTowerGranularity;
0441 
0442     unsigned int iEtaNormed = iEta + 28;
0443     if (iEta > 0)
0444       iEtaNormed--;  //we skip zero
0445 
0446     if (std::abs(iEta) > 28 || iEta == 0 || nrTowers > kNrTowersInSum)
0447       return kMaxAddress;
0448     else
0449       return iEtaNormed * (kNrTowersInSum / kTowerGranularity + 1) + nrTowersNormed;
0450   }
0451 }
0452 
0453 /*****************************************************************/
0454 int l1t::Stage2Layer2EGammaAlgorithmFirmwareImp1::calibratedPt(const l1t::CaloCluster& clus, int hwPt)
0455 /*****************************************************************/
0456 {
0457   unsigned int shape = 0;
0458   if ((clus.checkClusterFlag(CaloCluster::INCLUDE_N)))
0459     shape |= (0x1);
0460   if ((clus.checkClusterFlag(CaloCluster::INCLUDE_S)))
0461     shape |= (0x1 << 1);
0462   if (clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_E)))
0463     shape |= (0x1 << 2);
0464   if (!clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_W)))
0465     shape |= (0x1 << 2);
0466   if (clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_NE)))
0467     shape |= (0x1 << 3);
0468   if (!clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_NW)))
0469     shape |= (0x1 << 3);
0470   if (clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_SE)))
0471     shape |= (0x1 << 4);
0472   if (!clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_SW)))
0473     shape |= (0x1 << 4);
0474   if (clus.checkClusterFlag(CaloCluster::INCLUDE_NN))
0475     shape |= (0x1 << 5);
0476   if (clus.checkClusterFlag(CaloCluster::INCLUDE_SS))
0477     shape |= (0x1 << 6);
0478 
0479   unsigned int lutAddress = calibrationLutIndex(clus.hwEta(), hwPt, shape);
0480   int corr = params_->egCalibrationLUT()->data(lutAddress) & (0x1ff);  // 9 bits. [0,2]. corrPt = (corr)*rawPt
0481   // the correction can increase or decrease the energy
0482   int rawPt = hwPt;
0483   int corrXrawPt = corr * rawPt;  // 17 bits
0484   // round corr*rawPt
0485   int corrPt = corrXrawPt >> 8;  // 8 MS bits (truncation)
0486 
0487   //12 bits saturation
0488   if (corrPt > 4095)
0489     corrPt = 4095;
0490 
0491   return corrPt;
0492 }
0493 
0494 /*****************************************************************/
0495 unsigned int l1t::Stage2Layer2EGammaAlgorithmFirmwareImp1::calibrationLutIndex(int iEta, int E, int shape)
0496 /*****************************************************************/
0497 {
0498   if (params_->egCalibrationType() == "compressed") {
0499     unsigned int iEtaNormed = abs(iEta);
0500     if (iEtaNormed > 28)
0501       iEtaNormed = 28;
0502     if (E > 255)
0503       E = 255;
0504     unsigned int compressedShape = params_->egCompressShapesLUT()->data(shape);
0505     unsigned int compressedE = params_->egCompressShapesLUT()->data((0x1 << 7) + E);
0506     unsigned int compressedEta = params_->egCompressShapesLUT()->data((0x1 << 7) + (0x1 << 8) + iEtaNormed);
0507     return (compressedShape | compressedE | compressedEta);
0508   } else  // Uncompressed (kept for backward compatibility)
0509   {
0510     unsigned int iEtaNormed = abs(iEta);
0511     if (iEtaNormed > 28)
0512       iEtaNormed = 28;
0513     if (E > 255)
0514       E = 255;
0515     if (E < 22)
0516       E = 22;
0517     unsigned int compressedShape = params_->egCompressShapesLUT()->data(shape);
0518     if (compressedShape > 31)
0519       compressedShape = 31;
0520     return (E - 20) + compressedShape * 236 + (iEtaNormed - 1) * 236 * 32;
0521   }
0522 }
0523 
0524 /*****************************************************************/
0525 l1t::CaloCluster l1t::Stage2Layer2EGammaAlgorithmFirmwareImp1::trimCluster(const l1t::CaloCluster& clus)
0526 /*****************************************************************/
0527 {
0528   l1t::CaloCluster clusCopy = clus;
0529 
0530   unsigned int shape = 0;
0531   if ((clus.checkClusterFlag(CaloCluster::INCLUDE_N)))
0532     shape |= (0x1);
0533   if ((clus.checkClusterFlag(CaloCluster::INCLUDE_S)))
0534     shape |= (0x1 << 1);
0535   if (clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_E)))
0536     shape |= (0x1 << 2);
0537   if (!clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_W)))
0538     shape |= (0x1 << 2);
0539   if (clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_NE)))
0540     shape |= (0x1 << 3);
0541   if (!clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_NW)))
0542     shape |= (0x1 << 3);
0543   if (clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_SE)))
0544     shape |= (0x1 << 4);
0545   if (!clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_SW)))
0546     shape |= (0x1 << 4);
0547   if (clus.checkClusterFlag(CaloCluster::INCLUDE_NN))
0548     shape |= (0x1 << 5);
0549   if (clus.checkClusterFlag(CaloCluster::INCLUDE_SS))
0550     shape |= (0x1 << 6);
0551 
0552   unsigned int lutAddress = trimmingLutIndex(shape, clus.hwEta());
0553   unsigned int shapeTrim = params_->egTrimmingLUT()->data(lutAddress);
0554   // apply trimming flags
0555   clusCopy.setClusterFlag(CaloCluster::INCLUDE_N, (shapeTrim & (0x1)) ? true : false);
0556   clusCopy.setClusterFlag(CaloCluster::INCLUDE_S, (shapeTrim & (0x1 << 1)) ? true : false);
0557   clusCopy.setClusterFlag(CaloCluster::INCLUDE_NN, (shapeTrim & (0x1 << 5)) ? true : false);
0558   clusCopy.setClusterFlag(CaloCluster::INCLUDE_SS, (shapeTrim & (0x1 << 6)) ? true : false);
0559   if (clusCopy.checkClusterFlag(CaloCluster::TRIM_LEFT)) {
0560     clusCopy.setClusterFlag(CaloCluster::INCLUDE_E, (shapeTrim & (0x1 << 2)) ? true : false);
0561     clusCopy.setClusterFlag(CaloCluster::INCLUDE_NE, (shapeTrim & (0x1 << 3)) ? true : false);
0562     clusCopy.setClusterFlag(CaloCluster::INCLUDE_SE, (shapeTrim & (0x1 << 4)) ? true : false);
0563   } else {
0564     clusCopy.setClusterFlag(CaloCluster::INCLUDE_W, (shapeTrim & (0x1 << 2)) ? true : false);
0565     clusCopy.setClusterFlag(CaloCluster::INCLUDE_NW, (shapeTrim & (0x1 << 3)) ? true : false);
0566     clusCopy.setClusterFlag(CaloCluster::INCLUDE_SW, (shapeTrim & (0x1 << 4)) ? true : false);
0567   }
0568   return clusCopy;
0569 }
0570 
0571 /*****************************************************************/
0572 unsigned int l1t::Stage2Layer2EGammaAlgorithmFirmwareImp1::trimmingLutIndex(unsigned int shape, int iEta)
0573 /*****************************************************************/
0574 {
0575   unsigned int iEtaNormed = abs(iEta) - 1;
0576   if (iEtaNormed > 31)
0577     iEtaNormed = 31;
0578   if (shape > 127)
0579     shape = 127;
0580   unsigned int index = iEtaNormed * 128 + shape;
0581   return index;
0582 }
0583 
0584 /*****************************************************************/
0585 unsigned int l1t::Stage2Layer2EGammaAlgorithmFirmwareImp1::returnShape(const l1t::CaloCluster& clus)
0586 /*****************************************************************/
0587 {
0588   unsigned int shape = 0;
0589   if ((clus.checkClusterFlag(CaloCluster::INCLUDE_N)))
0590     shape |= (0x1);
0591   if ((clus.checkClusterFlag(CaloCluster::INCLUDE_S)))
0592     shape |= (0x1 << 1);
0593   if (clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_E)))
0594     shape |= (0x1 << 2);
0595   if (!clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_W)))
0596     shape |= (0x1 << 2);
0597   if (clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_NE)))
0598     shape |= (0x1 << 3);
0599   if (!clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_NW)))
0600     shape |= (0x1 << 3);
0601   if (clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_SE)))
0602     shape |= (0x1 << 4);
0603   if (!clus.checkClusterFlag(CaloCluster::TRIM_LEFT) && (clus.checkClusterFlag(CaloCluster::INCLUDE_SW)))
0604     shape |= (0x1 << 4);
0605   if (clus.checkClusterFlag(CaloCluster::INCLUDE_NN))
0606     shape |= (0x1 << 5);
0607   if (clus.checkClusterFlag(CaloCluster::INCLUDE_SS))
0608     shape |= (0x1 << 6);
0609 
0610   return shape;
0611 }
0612 
0613 /*****************************************************************/
0614 int l1t::Stage2Layer2EGammaAlgorithmFirmwareImp1::returnHoE(const l1t::CaloTower& tow)
0615 /*****************************************************************/
0616 {
0617   int ratio = tow.hwEtRatio();
0618   int qual = tow.hwQual();
0619   bool denomZeroFlag = ((qual & 0x1) > 0);
0620   bool eOverHFlag = ((qual & 0x2) > 0);
0621 
0622   if (denomZeroFlag && !eOverHFlag)  //E=0
0623     ratio = -1;
0624   if (denomZeroFlag && eOverHFlag)    //H=0
0625     ratio = 8;                        // ratio is on 3 bits, so 8 should be ok for overflow
0626   if (!denomZeroFlag && !eOverHFlag)  // H > E
0627     ratio = -1;
0628   //else E >= H , so ratio=log(E/H)
0629 
0630   return ratio;
0631 }
0632 
0633 bool l1t::Stage2Layer2EGammaAlgorithmFirmwareImp1::idHoverE_ext(const l1t::CaloTower tow) {
0634   int qual = tow.hwQual();
0635   bool eOverHFlag = ((qual & 0x2) > 0);
0636 
0637   if (tow.hwPt() <= 10)
0638     return true;  //Only applied for towers with ET>5 GeV
0639   else
0640     return eOverHFlag;
0641 }