Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-10-25 09:54:11

0001 #include "L1Trigger/CSCTriggerPrimitives/interface/CSCGEMMatcher.h"
0002 #include "L1Trigger/CSCTriggerPrimitives/interface/GEMInternalCluster.h"
0003 #include "DataFormats/CSCDigi/interface/CSCConstants.h"
0004 #include "DataFormats/CSCDigi/interface/CSCALCTDigi.h"
0005 #include "DataFormats/CSCDigi/interface/CSCCLCTDigi.h"
0006 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0007 
0008 #include <algorithm>
0009 #include <cmath>
0010 
0011 CSCGEMMatcher::CSCGEMMatcher(
0012     int endcap, unsigned station, unsigned chamber, const edm::ParameterSet& tmbParams, const edm::ParameterSet& conf)
0013     : endcap_(endcap), station_(station), chamber_(chamber) {
0014   isEven_ = (chamber_ % 2 == 0);
0015 
0016   enable_match_gem_me1a_ = tmbParams.getParameter<bool>("enableMatchGEMandME1a");
0017   enable_match_gem_me1b_ = tmbParams.getParameter<bool>("enableMatchGEMandME1b");
0018 
0019   maxDeltaWG_ = tmbParams.getParameter<unsigned>("maxDeltaWG");
0020   maxDeltaHsEven_ = tmbParams.getParameter<unsigned>("maxDeltaHsEven");
0021   maxDeltaHsOdd_ = tmbParams.getParameter<unsigned>("maxDeltaHsOdd");
0022 
0023   matchCLCTpropagation_ = tmbParams.getParameter<bool>("matchCLCTpropagation");
0024 
0025   mitigateSlopeByCosi_ = tmbParams.getParameter<bool>("mitigateSlopeByCosi");
0026   assign_gem_csc_bending_ = tmbParams.getParameter<bool>("assignGEMCSCBending");
0027 }
0028 
0029 //##############################################################
0030 //                Best clusters by location
0031 //##############################################################
0032 
0033 void CSCGEMMatcher::bestClusterLoc(const CSCALCTDigi& alct,
0034                                    const GEMInternalClusters& clusters,
0035                                    GEMInternalCluster& best) const {
0036   if (!alct.isValid() or clusters.empty())
0037     return;
0038 
0039   // match spatially
0040   GEMInternalClusters clustersLoc;
0041   matchingClustersLoc(alct, clusters, clustersLoc);
0042 
0043   // simply pick the first matching one
0044   if (!clustersLoc.empty())
0045     best = clustersLoc[0];
0046 }
0047 
0048 void CSCGEMMatcher::bestClusterLoc(const CSCCLCTDigi& clct,
0049                                    const GEMInternalClusters& clusters,
0050                                    const CSCL1TPLookupTableME11ILT* lookupTableME11ILT,
0051                                    const CSCL1TPLookupTableME21ILT* lookupTableME21ILT,
0052                                    GEMInternalCluster& best) const {
0053   if (!clct.isValid() or clusters.empty())
0054     return;
0055 
0056   // match spatially
0057   bool ignoreALCTGEMmatch = true;
0058   GEMInternalClusters clustersLoc;
0059   matchingClustersLoc(clct, clusters, clustersLoc, ignoreALCTGEMmatch, lookupTableME11ILT, lookupTableME21ILT);
0060 
0061   // the first matching one is also the closest in phi distance (to expected position, if extrapolating), by ordered list in CLCT matching
0062   if (!clustersLoc.empty())
0063     best = clustersLoc[0];
0064 }
0065 
0066 void CSCGEMMatcher::bestClusterLoc(const CSCALCTDigi& alct,
0067                                    const CSCCLCTDigi& clct,
0068                                    const GEMInternalClusters& clusters,
0069                                    const CSCL1TPLookupTableME11ILT* lookupTableME11ILT,
0070                                    const CSCL1TPLookupTableME21ILT* lookupTableME21ILT,
0071                                    GEMInternalCluster& best) const {
0072   if (!alct.isValid() or !clct.isValid() or clusters.empty())
0073     return;
0074 
0075   // match spatially
0076   GEMInternalClusters clustersLoc;
0077   matchingClustersLoc(alct, clct, clusters, lookupTableME11ILT, lookupTableME21ILT, clustersLoc);
0078 
0079   // the first matching one is also the closest in phi distance (to expected position, if extrapolating), by ordered list in CLCT matching
0080   if (!clustersLoc.empty()) {
0081     best = clustersLoc[0];
0082     if (best.isCoincidence() and !best.isMatchingLayer1() and best.isMatchingLayer2())
0083       best.set_coincidence(false);
0084     // std::cout << "\nGEM selected: " << best << "\n" << std::endl;
0085   }
0086 }
0087 
0088 //##############################################################
0089 //                  Matching by locations
0090 //##############################################################
0091 
0092 // match an ALCT to GEMInternalCluster by location
0093 void CSCGEMMatcher::matchingClustersLoc(const CSCALCTDigi& alct,
0094                                         const GEMInternalClusters& clusters,
0095                                         GEMInternalClusters& output) const {
0096   if (!alct.isValid() or clusters.empty())
0097     return;
0098 
0099   int number_of_wg = 0;
0100   if (station_ == 1)
0101     number_of_wg = CSCConstants::NUM_WIREGROUPS_ME11;
0102   else if (station_ == 2)
0103     number_of_wg = CSCConstants::NUM_WIREGROUPS_ME21;
0104 
0105   // select clusters matched in wiregroup
0106 
0107   for (const auto& cl : clusters) {
0108     // std::cout << "GEM cluster: " << cl << std::endl;
0109     bool isMatchedLayer1 = false;
0110     bool isMatchedLayer2 = false;
0111 
0112     if (cl.id1().layer() == 1) {  // cluster has valid layer 1
0113       int min_wg = std::max(0, int(cl.layer1_min_wg() - maxDeltaWG_));
0114       int max_wg = std::min(number_of_wg - 1, int(cl.layer1_max_wg() + maxDeltaWG_));
0115       if (min_wg <= alct.getKeyWG() and alct.getKeyWG() <= max_wg)
0116         isMatchedLayer1 = true;
0117     }
0118     if (cl.id2().layer() == 2) {  // cluster has valid layer 2
0119       int min_wg = std::max(0, int(cl.layer2_min_wg() - maxDeltaWG_));
0120       int max_wg = std::min(number_of_wg - 1, int(cl.layer2_max_wg() + maxDeltaWG_));
0121       if (min_wg <= alct.getKeyWG() and alct.getKeyWG() <= max_wg)
0122         isMatchedLayer2 = true;
0123     }
0124 
0125     // std::cout << "ALCT-GEM matching L1-L2: " << isMatchedLayer1 << " " << isMatchedLayer2 << std::endl;
0126 
0127     if (isMatchedLayer1 or isMatchedLayer2) {
0128       output.push_back(cl);
0129       if (isMatchedLayer1)
0130         output.back().set_matchingLayer1(true);
0131       if (isMatchedLayer2)
0132         output.back().set_matchingLayer2(true);
0133     }
0134   }
0135 }
0136 
0137 // match a CLCT to GEMInternalCluster by location
0138 void CSCGEMMatcher::matchingClustersLoc(const CSCCLCTDigi& clct,
0139                                         const GEMInternalClusters& clusters,
0140                                         GEMInternalClusters& output,
0141                                         bool ignoreALCTGEMmatch,
0142                                         const CSCL1TPLookupTableME11ILT* lookupTableME11ILT,
0143                                         const CSCL1TPLookupTableME21ILT* lookupTableME21ILT) const {
0144   if (!clct.isValid() or clusters.empty())
0145     return;
0146 
0147   if (station_ == 1 and !enable_match_gem_me1a_ and !enable_match_gem_me1b_)
0148     return;
0149 
0150   const bool isME1a(station_ == 1 and clct.getKeyStrip() > CSCConstants::MAX_HALF_STRIP_ME1B);
0151 
0152   //determine window size
0153   unsigned eighthStripCut = isEven_ ? 4 * maxDeltaHsEven_ : 4 * maxDeltaHsOdd_;  // Cut in 1/8 = 4 * cut in 1/2
0154 
0155   for (const auto& cl : clusters) {
0156     // std::cout << "GEM cluster: " << cl << std::endl;
0157     // if (!ignoreALCTGEMmatch) std::cout << "IN CLCT-GEM => ALCT-GEM matching L1-L2: " << cl.isMatchingLayer1() << " " << cl.isMatchingLayer2() << std::endl;
0158 
0159     bool isMatchedLayer1 = false;
0160     bool isMatchedLayer2 = false;
0161 
0162     if (cl.id1().layer() == 1) {  // cluster has valid layer 1
0163       if ((station_ == 1 and enable_match_gem_me1a_ and
0164            ((isME1a and cl.roll1() == 8) or (!isME1a and cl.roll1() < 8))) or
0165           (station_ == 1 and !enable_match_gem_me1a_ and !isME1a) or (station_ == 2)) {
0166         constexpr bool isLayer2 = false;
0167         unsigned distanceES =
0168             abs(matchedClusterDistES(clct, cl, isLayer2, false, lookupTableME11ILT, lookupTableME21ILT));
0169         if (distanceES <= eighthStripCut)
0170           isMatchedLayer1 = true;
0171       }
0172     }
0173     if (cl.id2().layer() == 2) {  // cluster has valid layer 2
0174       if ((station_ == 1 and enable_match_gem_me1a_ and
0175            ((isME1a and cl.roll2() == 8) or (!isME1a and cl.roll2() < 8))) or
0176           (station_ == 1 and !enable_match_gem_me1a_ and !isME1a) or (station_ == 2)) {
0177         constexpr bool isLayer2 = true;
0178         unsigned distanceES =
0179             abs(matchedClusterDistES(clct, cl, isLayer2, false, lookupTableME11ILT, lookupTableME21ILT));
0180         if (distanceES <= eighthStripCut)
0181           isMatchedLayer2 = true;
0182       }
0183     }
0184 
0185     // std::cout << "CLCT-GEM matching L1-L2: " << isMatchedLayer1 << " " << isMatchedLayer2 << std::endl;
0186 
0187     if (((ignoreALCTGEMmatch or cl.isMatchingLayer1()) and isMatchedLayer1) or
0188         ((ignoreALCTGEMmatch or cl.isMatchingLayer2()) and isMatchedLayer2)) {
0189       output.push_back(cl);
0190       output.back().set_matchingLayer1(false);
0191       output.back().set_matchingLayer2(false);
0192       if ((ignoreALCTGEMmatch or cl.isMatchingLayer1()) and isMatchedLayer1)
0193         output.back().set_matchingLayer1(true);
0194       if ((ignoreALCTGEMmatch or cl.isMatchingLayer2()) and isMatchedLayer2)
0195         output.back().set_matchingLayer2(true);
0196     }
0197   }
0198 
0199   // Sorting of matching cluster prefers copads and ordering by smallest relative distance
0200   std::sort(
0201       output.begin(),
0202       output.end(),
0203       [clct, lookupTableME11ILT, lookupTableME21ILT, this](const GEMInternalCluster cl1,
0204                                                            const GEMInternalCluster cl2) -> bool {
0205         if (cl1.isCoincidence() and !cl2.isCoincidence())
0206           return cl1.isCoincidence();
0207         else if ((cl1.isCoincidence() and cl2.isCoincidence()) or (!cl1.isCoincidence() and !cl2.isCoincidence())) {
0208           bool cl1_isLayer2 = !cl1.isMatchingLayer1() and cl1.isMatchingLayer2();
0209           bool cl2_isLayer2 = !cl2.isMatchingLayer1() and cl2.isMatchingLayer2();
0210           unsigned cl1_distanceES =
0211               abs(matchedClusterDistES(clct, cl1, cl1_isLayer2, false, lookupTableME11ILT, lookupTableME21ILT));
0212           unsigned cl2_distanceES =
0213               abs(matchedClusterDistES(clct, cl2, cl2_isLayer2, false, lookupTableME11ILT, lookupTableME21ILT));
0214           return cl1_distanceES < cl2_distanceES;
0215         } else
0216           return false;
0217       });
0218 }
0219 
0220 void CSCGEMMatcher::matchingClustersLoc(const CSCALCTDigi& alct,
0221                                         const CSCCLCTDigi& clct,
0222                                         const GEMInternalClusters& clusters,
0223                                         const CSCL1TPLookupTableME11ILT* lookupTableME11ILT,
0224                                         const CSCL1TPLookupTableME21ILT* lookupTableME21ILT,
0225                                         GEMInternalClusters& output) const {
0226   // both need to be valid
0227   if (!alct.isValid() or !clct.isValid() or clusters.empty())
0228     return;
0229 
0230   // get the single matches
0231   bool ignoreALCTGEMmatch = false;
0232   GEMInternalClusters alctClusters;
0233   matchingClustersLoc(alct, clusters, alctClusters);
0234   matchingClustersLoc(clct, alctClusters, output, ignoreALCTGEMmatch, lookupTableME11ILT, lookupTableME21ILT);
0235 }
0236 
0237 //##############################################################
0238 //  Ancillary functions: CLCT to GEM distance in eighth strips
0239 //##############################################################
0240 
0241 // calculate distance in eighth-strip units between CLCT and GEM, switch ForceTotal on to calculate total distance without slope extrapolation
0242 int CSCGEMMatcher::matchedClusterDistES(const CSCCLCTDigi& clct,
0243                                         const GEMInternalCluster& cl,
0244                                         const bool isLayer2,
0245                                         const bool ForceTotal,
0246                                         const CSCL1TPLookupTableME11ILT* lookupTableME11ILT,
0247                                         const CSCL1TPLookupTableME21ILT* lookupTableME21ILT) const {
0248   const bool isME1a(station_ == 1 and clct.getKeyStrip() > CSCConstants::MAX_HALF_STRIP_ME1B);
0249 
0250   int cl_es = isME1a ? cl.getKeyStripME1a(8, isLayer2) : cl.getKeyStrip(8, isLayer2);
0251 
0252   int eighthStripDiff = cl_es - clct.getKeyStrip(8);
0253 
0254   if (matchCLCTpropagation_ and !ForceTotal) {  //modification of DeltaStrip by CLCT slope
0255     int SlopeShift = 0;
0256     uint16_t baseSlope = -1;
0257     baseSlope = mitigateSlopeByCosi_ ? mitigatedSlopeByConsistency(clct, lookupTableME11ILT, lookupTableME21ILT)
0258                                      : clct.getSlope();
0259 
0260     int clctSlope = pow(-1, clct.getBend()) * baseSlope;
0261 
0262     SlopeShift = CSCGEMSlopeCorrector(isME1a, clctSlope, isLayer2, lookupTableME11ILT, lookupTableME21ILT);
0263     eighthStripDiff -= SlopeShift;
0264   }
0265 
0266   return eighthStripDiff;
0267 }
0268 
0269 //##############################################################
0270 //  Ancillary functions: CLCT COSI
0271 //##############################################################
0272 
0273 // function to determine CLCT consistency of slope indicator (COSI) and use it to mitigate slope according to LUT
0274 uint16_t CSCGEMMatcher::mitigatedSlopeByConsistency(const CSCCLCTDigi& clct,
0275                                                     const CSCL1TPLookupTableME11ILT* lookupTableME11ILT,
0276                                                     const CSCL1TPLookupTableME21ILT* lookupTableME21ILT) const {
0277   const bool isME1a(station_ == 1 and clct.getKeyStrip() > CSCConstants::MAX_HALF_STRIP_ME1B);
0278 
0279   // extract hit values from CLCT hit matrix
0280   std::vector<std::vector<uint16_t>> CLCTHitMatrix = clct.getHits();
0281   int CLCTHits[6] = {-1, -1, -1, -1, -1, -1};
0282 
0283   for (unsigned layer = 0; layer < CLCTHitMatrix.size(); ++layer) {
0284     for (unsigned position = 0; position < CLCTHitMatrix.at(layer).size(); ++position) {
0285       const uint16_t value = CLCTHitMatrix.at(layer).at(position);
0286       if (value != 0 && value != 65535) {
0287         CLCTHits[layer] = (int)value;
0288         break;
0289       }
0290     }
0291   }
0292 
0293   //Debugging
0294   //std::cout<<"CLCT Hits = "<<CLCTHits[0]<<", "<<CLCTHits[1]<<", "<<CLCTHits[2]<<", "<<CLCTHits[3]<<", "<<CLCTHits[4]<<", "<<CLCTHits[5]<<std::endl;
0295 
0296   //calculate slope consistency
0297   float MinMaxPairDifferences[2] = {999., -999.};
0298   for (unsigned First = 0; First < 5; ++First) {
0299     //skip empty layers
0300     if (CLCTHits[First] == -1)
0301       continue;
0302     for (unsigned Second = First + 1; Second < 6; ++Second) {
0303       //skip empty layers
0304       if (CLCTHits[Second] == -1)
0305         continue;
0306       float PairDifference = (CLCTHits[First] - CLCTHits[Second]) / (float)(Second - First);
0307       if (PairDifference < MinMaxPairDifferences[0])
0308         MinMaxPairDifferences[0] = PairDifference;
0309       if (PairDifference > MinMaxPairDifferences[1])
0310         MinMaxPairDifferences[1] = PairDifference;
0311     }
0312   }
0313 
0314   //calculate consistency of slope indicator: cosi
0315   uint16_t cosi = std::ceil(std::abs(MinMaxPairDifferences[1] - MinMaxPairDifferences[0]));
0316   //Debugging
0317   //std::cout<<"COSI = "<<cosi<<std::endl;
0318 
0319   //disambiguate cosi cases
0320 
0321   //extremely inconsistent track, deprecate slope
0322   if (cosi > 3)
0323     return 0;
0324   //consistent slope, do not change
0325   else if (cosi < 2)
0326     return clct.getSlope();
0327   //need to look up in table 2->1
0328   else if (cosi == 2) {
0329     if (station_ == 1) {
0330       if (isME1a) {
0331         if (chamber_ % 2 == 0)
0332           return lookupTableME11ILT->CSC_slope_cosi_2to1_L1_ME11a_even(clct.getSlope());
0333         else
0334           return lookupTableME11ILT->CSC_slope_cosi_2to1_L1_ME11a_odd(clct.getSlope());
0335       } else {
0336         if (chamber_ % 2 == 0)
0337           return lookupTableME11ILT->CSC_slope_cosi_2to1_L1_ME11b_even(clct.getSlope());
0338         else
0339           return lookupTableME11ILT->CSC_slope_cosi_2to1_L1_ME11b_odd(clct.getSlope());
0340       }
0341     } else {
0342       if (chamber_ % 2 == 0)
0343         return lookupTableME21ILT->CSC_slope_cosi_2to1_L1_ME21_even(clct.getSlope());
0344       else
0345         return lookupTableME21ILT->CSC_slope_cosi_2to1_L1_ME21_odd(clct.getSlope());
0346     }
0347   }
0348   //need to look up in table 3->1
0349   else if (cosi == 3) {
0350     if (station_ == 1) {
0351       if (isME1a) {
0352         if (chamber_ % 2 == 0)
0353           return lookupTableME11ILT->CSC_slope_cosi_3to1_L1_ME11a_even(clct.getSlope());
0354         else
0355           return lookupTableME11ILT->CSC_slope_cosi_3to1_L1_ME11a_odd(clct.getSlope());
0356       } else {
0357         if (chamber_ % 2 == 0)
0358           return lookupTableME11ILT->CSC_slope_cosi_3to1_L1_ME11b_even(clct.getSlope());
0359         else
0360           return lookupTableME11ILT->CSC_slope_cosi_3to1_L1_ME11b_odd(clct.getSlope());
0361       }
0362     } else {
0363       if (chamber_ % 2 == 0)
0364         return lookupTableME21ILT->CSC_slope_cosi_3to1_L1_ME21_even(clct.getSlope());
0365       else
0366         return lookupTableME21ILT->CSC_slope_cosi_3to1_L1_ME21_odd(clct.getSlope());
0367     }
0368   }
0369   //just to avoid compiler errors an error code
0370   else {
0371     return 999;
0372   }
0373 }
0374 
0375 //##############################################################
0376 //  Ancillary functions: CLCT extrapolation towards GEM
0377 //##############################################################
0378 
0379 //function to correct expected GEM position in phi by CSC slope measurement
0380 int CSCGEMMatcher::CSCGEMSlopeCorrector(bool isME1a,
0381                                         int cscSlope,
0382                                         bool isLayer2,
0383                                         const CSCL1TPLookupTableME11ILT* lookupTableME11ILT,
0384                                         const CSCL1TPLookupTableME21ILT* lookupTableME21ILT) const {
0385   int SlopeShift = 0;
0386   int SlopeSign = pow(-1, std::signbit(cscSlope));
0387 
0388   //account for slope mitigation by cosi, if opted-in
0389   if (mitigateSlopeByCosi_) {
0390     if (station_ == 1) {
0391       if (chamber_ % 2 == 0)
0392         SlopeShift = isME1a ? lookupTableME11ILT->CSC_slope_cosi_corr_L1_ME11a_even(std::abs(cscSlope))
0393                             : lookupTableME11ILT->CSC_slope_cosi_corr_L1_ME11b_even(std::abs(cscSlope));
0394       else
0395         SlopeShift = isME1a ? lookupTableME11ILT->CSC_slope_cosi_corr_L1_ME11a_odd(std::abs(cscSlope))
0396                             : lookupTableME11ILT->CSC_slope_cosi_corr_L1_ME11b_odd(std::abs(cscSlope));
0397     } else if (station_ == 2) {
0398       if (chamber_ % 2 == 0)
0399         SlopeShift = lookupTableME21ILT->CSC_slope_cosi_corr_L1_ME21_even(std::abs(cscSlope));
0400       else
0401         SlopeShift = lookupTableME21ILT->CSC_slope_cosi_corr_L1_ME21_odd(std::abs(cscSlope));
0402     }
0403   } else {  //account for slope without mitigation, if opted out
0404     if (station_ == 1) {
0405       if (!isLayer2) {
0406         if (chamber_ % 2 == 0)
0407           SlopeShift = isME1a ? lookupTableME11ILT->CSC_slope_corr_L1_ME11a_even(std::abs(cscSlope))
0408                               : lookupTableME11ILT->CSC_slope_corr_L1_ME11b_even(std::abs(cscSlope));
0409         else
0410           SlopeShift = isME1a ? lookupTableME11ILT->CSC_slope_corr_L1_ME11a_odd(std::abs(cscSlope))
0411                               : lookupTableME11ILT->CSC_slope_corr_L1_ME11b_odd(std::abs(cscSlope));
0412       } else {
0413         if (chamber_ % 2 == 0)
0414           SlopeShift = isME1a ? lookupTableME11ILT->CSC_slope_corr_L2_ME11a_even(std::abs(cscSlope))
0415                               : lookupTableME11ILT->CSC_slope_corr_L2_ME11b_even(std::abs(cscSlope));
0416         else
0417           SlopeShift = isME1a ? lookupTableME11ILT->CSC_slope_corr_L2_ME11a_odd(std::abs(cscSlope))
0418                               : lookupTableME11ILT->CSC_slope_corr_L2_ME11b_odd(std::abs(cscSlope));
0419       }
0420     } else if (station_ == 2) {
0421       if (!isLayer2) {
0422         if (chamber_ % 2 == 0)
0423           SlopeShift = lookupTableME21ILT->CSC_slope_corr_L1_ME21_even(std::abs(cscSlope));
0424         else
0425           SlopeShift = lookupTableME21ILT->CSC_slope_corr_L1_ME21_odd(std::abs(cscSlope));
0426       } else {
0427         if (chamber_ % 2 == 0)
0428           SlopeShift = lookupTableME21ILT->CSC_slope_corr_L2_ME21_even(std::abs(cscSlope));
0429         else
0430           SlopeShift = lookupTableME21ILT->CSC_slope_corr_L2_ME21_odd(std::abs(cscSlope));
0431       }
0432     }
0433   }
0434   return std::round(SlopeShift * SlopeSign);
0435 }
0436 
0437 //##############################################################
0438 //  Ancillary functions: computation of slope corrected by GEM
0439 //##############################################################
0440 
0441 //function to replace the CLCT slope by the slope indicated by the strip difference between the CLCT and its matching GEM internal cluster
0442 int CSCGEMMatcher::calculateGEMCSCBending(const CSCCLCTDigi& clct,
0443                                           const GEMInternalCluster& cluster,
0444                                           const CSCL1TPLookupTableME11ILT* lookupTableME11ILT,
0445                                           const CSCL1TPLookupTableME21ILT* lookupTableME21ILT) const {
0446   const bool isME1a(station_ == 1 and clct.getKeyStrip() > CSCConstants::MAX_HALF_STRIP_ME1B);
0447 
0448   bool isLayer2 = false;
0449   if (!cluster.isMatchingLayer1() and cluster.isMatchingLayer2())
0450     isLayer2 = true;
0451 
0452   //ME1a necessitates a different treatment because of a different strip numbering scheme and strip width
0453   const int SignedEighthStripDiff =
0454       matchedClusterDistES(clct, cluster, isLayer2, true, lookupTableME11ILT, lookupTableME21ILT);
0455   const unsigned eighthStripDiff = abs(SignedEighthStripDiff);  //LUTs consider only absolute change
0456 
0457   //use LUTs to determine absolute slope, default 0
0458   int slopeShift = 0;
0459   if (station_ == 2) {
0460     if (!isLayer2) {
0461       if (isEven_)
0462         slopeShift = lookupTableME21ILT->es_diff_slope_L1_ME21_even(eighthStripDiff);
0463       else
0464         slopeShift = lookupTableME21ILT->es_diff_slope_L1_ME21_odd(eighthStripDiff);
0465     } else {
0466       if (isEven_)
0467         slopeShift = lookupTableME21ILT->es_diff_slope_L2_ME21_even(eighthStripDiff);
0468       else
0469         slopeShift = lookupTableME21ILT->es_diff_slope_L2_ME21_odd(eighthStripDiff);
0470     }
0471   } else if (station_ == 1) {
0472     if (isME1a) {  //is in ME1a
0473       if (!isLayer2) {
0474         if (isEven_)
0475           slopeShift = lookupTableME11ILT->es_diff_slope_L1_ME11a_even(eighthStripDiff);
0476         else
0477           slopeShift = lookupTableME11ILT->es_diff_slope_L1_ME11a_odd(eighthStripDiff);
0478       } else {
0479         if (isEven_)
0480           slopeShift = lookupTableME11ILT->es_diff_slope_L2_ME11a_even(eighthStripDiff);
0481         else
0482           slopeShift = lookupTableME11ILT->es_diff_slope_L2_ME11a_odd(eighthStripDiff);
0483       }
0484     } else {
0485       if (!isLayer2) {
0486         if (isEven_)
0487           slopeShift = lookupTableME11ILT->es_diff_slope_L1_ME11b_even(eighthStripDiff);
0488         else
0489           slopeShift = lookupTableME11ILT->es_diff_slope_L1_ME11b_odd(eighthStripDiff);
0490       } else {
0491         if (isEven_)
0492           slopeShift = lookupTableME11ILT->es_diff_slope_L2_ME11b_even(eighthStripDiff);
0493         else
0494           slopeShift = lookupTableME11ILT->es_diff_slope_L2_ME11b_odd(eighthStripDiff);
0495       }
0496     }
0497   }
0498 
0499   //account for the sign of the difference
0500   slopeShift *= pow(-1, std::signbit(SignedEighthStripDiff));
0501 
0502   return slopeShift;
0503 }