Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:19:36

0001 #include <memory>
0002 
0003 #include "L1Trigger/CSCTriggerPrimitives/interface/CSCGEMMotherboard.h"
0004 CSCGEMMotherboard::CSCGEMMotherboard(unsigned endcap,
0005                                      unsigned station,
0006                                      unsigned sector,
0007                                      unsigned subsector,
0008                                      unsigned chamber,
0009                                      CSCBaseboard::Parameters& conf)
0010     : CSCMotherboard(endcap, station, sector, subsector, chamber, conf),
0011       drop_low_quality_alct_(conf.tmbParams().getParameter<bool>("dropLowQualityALCTs")),
0012       drop_low_quality_clct_(conf.tmbParams().getParameter<bool>("dropLowQualityCLCTs")),
0013       build_lct_from_alct_gem_(conf.tmbParams().getParameter<bool>("buildLCTfromALCTandGEM")),
0014       build_lct_from_clct_gem_(conf.tmbParams().getParameter<bool>("buildLCTfromCLCTandGEM")) {
0015   // case for ME1/1
0016   if (isME11_) {
0017     drop_low_quality_clct_me1a_ = conf.tmbParams().getParameter<bool>("dropLowQualityCLCTs_ME1a");
0018   }
0019 
0020   alct_gem_bx_window_size_ = conf.tmbParams().getParameter<unsigned>("windowBXALCTGEM");
0021   clct_gem_bx_window_size_ = conf.tmbParams().getParameter<unsigned>("windowBXCLCTGEM");
0022 
0023   assign_gem_csc_bending_ = conf.tmbParams().getParameter<bool>("assignGEMCSCBending");
0024   qualityAssignment_->setGEMCSCBending(assign_gem_csc_bending_);
0025 
0026   // These LogErrors are sanity checks and should not be printed
0027   if (isME11_ and !runME11ILT_) {
0028     edm::LogError("CSCGEMMotherboard") << "TMB constructed while runME11ILT_ is not set!";
0029   };
0030 
0031   if (isME21_ and !runME21ILT_) {
0032     edm::LogError("CSCGEMMotherboard") << "TMB constructed while runME21ILT_ is not set!";
0033   };
0034 
0035   // super chamber has layer=0!
0036   gemId = GEMDetId(theRegion, 1, theStation, 0, theChamber, 0).rawId();
0037 
0038   clusterProc_ = std::make_shared<GEMClusterProcessor>(theRegion, theStation, theChamber, conf.conf());
0039 
0040   cscGEMMatcher_ = std::make_unique<CSCGEMMatcher>(theRegion, theStation, theChamber, conf.tmbParams(), conf.conf());
0041 }
0042 
0043 CSCGEMMotherboard::~CSCGEMMotherboard() {}
0044 
0045 void CSCGEMMotherboard::clear() { clusterProc_->clear(); }
0046 
0047 //function to convert GEM-CSC amended signed slope into Run2 legacy pattern number
0048 uint16_t CSCGEMMotherboard::Run2PatternConverter(const int slope) const {
0049   unsigned sign = std::signbit(slope);
0050   unsigned slope_ = abs(slope);
0051   uint16_t Run2Pattern = 0;
0052 
0053   if (slope_ < 3)
0054     Run2Pattern = 10;
0055   else if (slope_ < 6)
0056     Run2Pattern = 8 + sign;
0057   else if (slope_ < 9)
0058     Run2Pattern = 6 + sign;
0059   else if (slope_ < 12)
0060     Run2Pattern = 4 + sign;
0061   else
0062     Run2Pattern = 2 + sign;
0063 
0064   return Run2Pattern;
0065 }
0066 
0067 void CSCGEMMotherboard::run(const CSCWireDigiCollection* wiredc,
0068                             const CSCComparatorDigiCollection* compdc,
0069                             const GEMPadDigiClusterCollection* gemClusters,
0070                             const RunContext& context) {
0071   // Step 1: Setup
0072   clear();
0073 
0074   // check for GEM geometry
0075   if (context.gemGeometry_ == nullptr) {
0076     edm::LogError("CSCGEMMotherboard") << "run() called for GEM-CSC integrated trigger without valid GEM geometry! \n";
0077     return;
0078   }
0079 
0080   // Step 2: Run the processors
0081   CSCMotherboard::RunContext mbc{context.cscGeometry_,
0082                                  context.lookupTableCCLUT_,
0083                                  context.lookupTableME11ILT_,
0084                                  context.lookupTableME21ILT_,
0085                                  context.parameters_};
0086   auto [alctV, clctV] = runCommon(wiredc, compdc, mbc);
0087 
0088   // if there are no ALCTs and no CLCTs, do not run the ALCT-CLCT correlation
0089   if (alctV.empty() and clctV.empty())
0090     return;
0091 
0092   // Step 3: run the GEM cluster processor to get the internal clusters
0093   clusterProc_->run(gemClusters, context.lookupTableME11ILT_, context.lookupTableME21ILT_);
0094   hasGE21Geometry16Partitions_ = clusterProc_->hasGE21Geometry16Partitions();
0095 
0096   // Step 4: ALCT-CLCT-GEM matching
0097   matchALCTCLCTGEM(context.lookupTableME11ILT_, context.lookupTableME21ILT_);
0098 
0099   // Step 5: Select at most 2 LCTs per BX
0100   selectLCTs();
0101 }
0102 
0103 void CSCGEMMotherboard::matchALCTCLCTGEM(const CSCL1TPLookupTableME11ILT* lookupTableME11ILT,
0104                                          const CSCL1TPLookupTableME21ILT* lookupTableME21ILT) {
0105   // no matching is done for GE2/1 geometries with 8 eta partitions
0106   // this has been superseded by 16-eta partition geometries
0107   if (isME21_ and !hasGE21Geometry16Partitions_)
0108     return;
0109 
0110   for (int bx_alct = 0; bx_alct < CSCConstants::MAX_ALCT_TBINS; bx_alct++) {
0111     // Declaration of all LCTs for this BX:
0112 
0113     // ALCT + CLCT + GEM
0114     CSCCorrelatedLCTDigi LCTbestAbestCgem, LCTbestAsecondCgem, LCTsecondAbestCgem, LCTsecondAsecondCgem;
0115     // ALCT + CLCT
0116     CSCCorrelatedLCTDigi LCTbestAbestC, LCTbestAsecondC, LCTsecondAbestC, LCTsecondAsecondC;
0117     // CLCT + 2 GEM
0118     CSCCorrelatedLCTDigi LCTbestCLCTgem, LCTsecondCLCTgem;
0119     // ALCT + 2 GEM
0120     CSCCorrelatedLCTDigi LCTbestALCTgem, LCTsecondALCTgem;
0121 
0122     // Construct all the LCTs, selection will come later:
0123 
0124     CSCALCTDigi bestALCT = alctProc->getBestALCT(bx_alct), secondALCT = alctProc->getSecondALCT(bx_alct);
0125     CSCCLCTDigi bestCLCT, secondCLCT;
0126     GEMInternalClusters clustersGEM;
0127 
0128     // Find best and second CLCTs by preferred CLCT BX, taking into account that there is an offset in the simulation
0129 
0130     unsigned matchingBX = 0;
0131     unsigned matching_clctbx = 0;
0132     unsigned bx_clct = 0;
0133 
0134     std::vector<unsigned> clctBx_qualbend_match;
0135     sortCLCTByQualBend(bx_alct, clctBx_qualbend_match);
0136 
0137     bool hasLocalShower = false;
0138     for (unsigned ibx = 1; ibx <= match_trig_window_size() / 2; ibx++)
0139       hasLocalShower = (hasLocalShower or clctProc->getLocalShowerFlag(bx_alct - CSCConstants::ALCT_CLCT_OFFSET - ibx));
0140     // BestCLCT and secondCLCT
0141     for (unsigned mbx = 0; mbx < match_trig_window_size(); mbx++) {
0142       //bx_clct_run2 would be overflow when bx_alct is small but it is okay
0143       unsigned bx_clct_run2 = bx_alct + preferred_bx_match(mbx) - CSCConstants::ALCT_CLCT_OFFSET;
0144       unsigned bx_clct_qualbend = clctBx_qualbend_match[mbx];
0145       bx_clct = (sort_clct_bx() or not(hasLocalShower)) ? bx_clct_run2 : bx_clct_qualbend;
0146 
0147       if (bx_clct >= CSCConstants::MAX_CLCT_TBINS)
0148         continue;
0149       matchingBX = mbx;
0150       matching_clctbx = mbx;
0151 
0152       if ((clctProc->getBestCLCT(bx_clct)).isValid())
0153         break;
0154     }
0155 
0156     bestCLCT = clctProc->getBestCLCT(bx_clct);
0157     secondCLCT = clctProc->getSecondCLCT(bx_clct);
0158 
0159     if (!bestALCT.isValid() and !secondALCT.isValid() and !bestCLCT.isValid() and !secondCLCT.isValid())
0160       continue;
0161     if (!build_lct_from_clct_gem_ and !bestALCT.isValid())
0162       continue;
0163     if (!build_lct_from_alct_gem_ and !bestCLCT.isValid())
0164       continue;
0165 
0166     if (infoV > 1)
0167       LogTrace("CSCGEMMotherboard") << "GEMCSCOTMB: Successful ALCT-CLCT match: bx_alct = " << bx_alct
0168                                     << "; bx_clct = " << matching_clctbx << "; mbx = " << matchingBX << " bestALCT "
0169                                     << bestALCT << " secondALCT " << secondALCT << " bestCLCT " << bestCLCT
0170                                     << " secondCLCT " << secondCLCT;
0171     // ALCT + CLCT + GEM
0172 
0173     for (unsigned gmbx = 0; gmbx < alct_gem_bx_window_size_; gmbx++) {
0174       unsigned bx_gem = bx_alct + preferred_bx_match(gmbx);
0175       clustersGEM = clusterProc_->getClusters(bx_gem, GEMClusterProcessor::AllClusters);
0176       if (!clustersGEM.empty()) {
0177         correlateLCTsGEM(bestALCT, bestCLCT, clustersGEM, lookupTableME11ILT, lookupTableME21ILT, LCTbestAbestCgem);
0178         correlateLCTsGEM(bestALCT, secondCLCT, clustersGEM, lookupTableME11ILT, lookupTableME21ILT, LCTbestAsecondCgem);
0179         correlateLCTsGEM(secondALCT, bestCLCT, clustersGEM, lookupTableME11ILT, lookupTableME21ILT, LCTsecondAbestCgem);
0180         correlateLCTsGEM(
0181             secondALCT, secondCLCT, clustersGEM, lookupTableME11ILT, lookupTableME21ILT, LCTsecondAsecondCgem);
0182         break;
0183       }
0184     }
0185 
0186     // ALCT + CLCT
0187 
0188     correlateLCTsGEM(bestALCT, bestCLCT, LCTbestAbestC);
0189     correlateLCTsGEM(bestALCT, secondCLCT, LCTbestAsecondC);
0190     correlateLCTsGEM(secondALCT, bestCLCT, LCTsecondAbestC);
0191     correlateLCTsGEM(secondALCT, secondCLCT, LCTsecondAsecondC);
0192 
0193     // CLCT + 2 GEM
0194 
0195     if (build_lct_from_clct_gem_) {
0196       unsigned bx_gem = bx_alct;
0197 
0198       clustersGEM = clusterProc_->getClusters(bx_gem, GEMClusterProcessor::CoincidenceClusters);
0199       correlateLCTsGEM(bestCLCT, clustersGEM, lookupTableME11ILT, lookupTableME21ILT, LCTbestCLCTgem);
0200       clustersGEM = clusterProc_->getClusters(bx_gem, GEMClusterProcessor::CoincidenceClusters);
0201       correlateLCTsGEM(secondCLCT, clustersGEM, lookupTableME11ILT, lookupTableME21ILT, LCTsecondCLCTgem);
0202     }
0203 
0204     // ALCT + 2 GEM
0205 
0206     if (build_lct_from_alct_gem_) {
0207       for (unsigned gmbx = 0; gmbx < alct_gem_bx_window_size_; gmbx++) {
0208         unsigned bx_gem = bx_alct + preferred_bx_match(gmbx);
0209         clustersGEM = clusterProc_->getClusters(bx_gem, GEMClusterProcessor::CoincidenceClusters);
0210         if (!clustersGEM.empty()) {
0211           correlateLCTsGEM(bestALCT, clustersGEM, LCTbestALCTgem);
0212           correlateLCTsGEM(secondALCT, clustersGEM, LCTsecondALCTgem);
0213           break;
0214         }
0215       }
0216     }
0217 
0218     // Select LCTs, following FW logic
0219 
0220     std::vector<CSCCorrelatedLCTDigi> selectedLCTs;
0221 
0222     // CASE => Only bestALCT is valid
0223     if (bestALCT.isValid() and !secondALCT.isValid() and !bestCLCT.isValid() and !secondCLCT.isValid()) {
0224       if (LCTbestALCTgem.isValid()) {
0225         LCTbestALCTgem.setTrknmb(1);
0226         allLCTs_(bx_alct, matchingBX, 0) = LCTbestALCTgem;
0227       }
0228     }
0229 
0230     // CASE => Only bestCLCT is valid
0231     if (!bestALCT.isValid() and !secondALCT.isValid() and bestCLCT.isValid() and !secondCLCT.isValid()) {
0232       if (LCTbestCLCTgem.isValid()) {
0233         LCTbestCLCTgem.setTrknmb(1);
0234         allLCTs_(bx_alct, matchingBX, 0) = LCTbestCLCTgem;
0235       }
0236     }
0237 
0238     // CASE => bestALCT and bestCLCT are valid
0239     if (bestALCT.isValid() and !secondALCT.isValid() and bestCLCT.isValid() and !secondCLCT.isValid()) {
0240       if (LCTbestAbestCgem.isValid()) {
0241         LCTbestAbestCgem.setTrknmb(1);
0242         allLCTs_(bx_alct, matchingBX, 0) = LCTbestAbestCgem;
0243       } else if (LCTbestAbestC.isValid()) {
0244         LCTbestAbestC.setTrknmb(1);
0245         allLCTs_(bx_alct, matchingBX, 0) = LCTbestAbestC;
0246       }
0247     }
0248 
0249     // CASE => bestALCT, secondALCT, bestCLCT are valid
0250     if (bestALCT.isValid() and secondALCT.isValid() and bestCLCT.isValid() and !secondCLCT.isValid()) {
0251       CSCCorrelatedLCTDigi lctbb, lctsb;
0252       if (LCTbestAbestCgem.isValid())
0253         lctbb = LCTbestAbestCgem;
0254       else if (LCTbestAbestC.isValid())
0255         lctbb = LCTbestAbestC;
0256       if (LCTsecondAbestCgem.isValid())
0257         lctsb = LCTsecondAbestCgem;
0258       else if (LCTsecondAbestC.isValid())
0259         lctsb = LCTsecondAbestC;
0260 
0261       if (lctbb.getQuality() >= lctsb.getQuality() and lctbb.isValid()) {
0262         selectedLCTs.push_back(lctbb);
0263         if (LCTsecondALCTgem.isValid() and build_lct_from_alct_gem_)
0264           selectedLCTs.push_back(LCTsecondALCTgem);
0265         else if (LCTsecondAbestC.isValid())
0266           selectedLCTs.push_back(LCTsecondAbestC);
0267       } else if (lctbb.getQuality() < lctsb.getQuality() and lctsb.isValid()) {
0268         selectedLCTs.push_back(lctsb);
0269         if (LCTbestALCTgem.isValid() and build_lct_from_alct_gem_)
0270           selectedLCTs.push_back(LCTbestALCTgem);
0271         else if (LCTbestAbestC.isValid())
0272           selectedLCTs.push_back(LCTbestAbestC);
0273       }
0274 
0275       sortLCTs(selectedLCTs);
0276 
0277       for (unsigned iLCT = 0; iLCT < std::min(unsigned(selectedLCTs.size()), unsigned(CSCConstants::MAX_LCTS_PER_CSC));
0278            iLCT++) {
0279         if (selectedLCTs[iLCT].isValid()) {
0280           selectedLCTs[iLCT].setTrknmb(iLCT + 1);
0281           allLCTs_(bx_alct, matchingBX, iLCT) = selectedLCTs[iLCT];
0282         }
0283       }
0284     }
0285 
0286     // CASE => bestALCT, bestCLCT, secondCLCT are valid
0287     if (bestALCT.isValid() and !secondALCT.isValid() and bestCLCT.isValid() and secondCLCT.isValid()) {
0288       CSCCorrelatedLCTDigi lctbb, lctbs;
0289       if (LCTbestAbestCgem.isValid())
0290         lctbb = LCTbestAbestCgem;
0291       else if (LCTbestAbestC.isValid())
0292         lctbb = LCTbestAbestC;
0293       if (LCTbestAsecondCgem.isValid())
0294         lctbs = LCTbestAsecondCgem;
0295       else if (LCTbestAsecondC.isValid())
0296         lctbs = LCTbestAsecondC;
0297 
0298       if (lctbb.getQuality() >= lctbs.getQuality() and lctbb.isValid()) {
0299         selectedLCTs.push_back(lctbb);
0300         if (LCTsecondCLCTgem.isValid() and build_lct_from_clct_gem_)
0301           selectedLCTs.push_back(LCTsecondCLCTgem);
0302         else if (LCTbestAsecondC.isValid())
0303           selectedLCTs.push_back(LCTbestAsecondC);
0304       } else if (lctbb.getQuality() < lctbs.getQuality() and lctbs.isValid()) {
0305         selectedLCTs.push_back(lctbs);
0306         if (LCTbestCLCTgem.isValid() and build_lct_from_alct_gem_)
0307           selectedLCTs.push_back(LCTbestCLCTgem);
0308         else if (LCTbestAbestC.isValid())
0309           selectedLCTs.push_back(LCTbestAbestC);
0310       }
0311 
0312       sortLCTs(selectedLCTs);
0313 
0314       for (unsigned iLCT = 0; iLCT < std::min(unsigned(selectedLCTs.size()), unsigned(CSCConstants::MAX_LCTS_PER_CSC));
0315            iLCT++) {
0316         if (selectedLCTs[iLCT].isValid()) {
0317           selectedLCTs[iLCT].setTrknmb(iLCT + 1);
0318           allLCTs_(bx_alct, matchingBX, iLCT) = selectedLCTs[iLCT];
0319         }
0320       }
0321     }
0322 
0323     // CASE => bestALCT, secondALCT, bestCLCT, secondCLCT are valid
0324     if (bestALCT.isValid() and secondALCT.isValid() and bestCLCT.isValid() and secondCLCT.isValid()) {
0325       CSCCorrelatedLCTDigi lctbb, lctbs, lctsb, lctss;
0326 
0327       // compute LCT bestA-bestC
0328       if (LCTbestAbestCgem.isValid())
0329         lctbb = LCTbestAbestCgem;
0330       else if (LCTbestAbestC.isValid())
0331         lctbb = LCTbestAbestC;
0332 
0333       // compute LCT bestA-secondC
0334       if (LCTbestAsecondCgem.isValid())
0335         lctbs = LCTbestAsecondCgem;
0336       else if (LCTbestAsecondC.isValid())
0337         lctbs = LCTbestAsecondC;
0338 
0339       if (lctbb.getQuality() >= lctbs.getQuality()) {
0340         // push back LCT bestA-bestC
0341         selectedLCTs.push_back(lctbb);
0342 
0343         // compute LCT secondA-secondC
0344         if (LCTsecondAsecondCgem.isValid())
0345           lctss = LCTsecondAsecondCgem;
0346         else if (LCTsecondAsecondC.isValid())
0347           lctss = LCTsecondAsecondC;
0348 
0349         // push back LCT secondA-secondC
0350         selectedLCTs.push_back(lctss);
0351       } else {
0352         // push back LCT bestA-secondC
0353         selectedLCTs.push_back(lctbs);
0354 
0355         // compute LCT secondA-bestC
0356         if (LCTsecondAbestCgem.isValid())
0357           lctsb = LCTsecondAbestCgem;
0358         else if (LCTsecondAbestC.isValid())
0359           lctsb = LCTsecondAbestC;
0360 
0361         // push back LCT secondA-bestC
0362         selectedLCTs.push_back(lctsb);
0363       }
0364 
0365       sortLCTs(selectedLCTs);
0366 
0367       for (unsigned iLCT = 0; iLCT < std::min(unsigned(selectedLCTs.size()), unsigned(CSCConstants::MAX_LCTS_PER_CSC));
0368            iLCT++) {
0369         if (selectedLCTs[iLCT].isValid()) {
0370           selectedLCTs[iLCT].setTrknmb(iLCT + 1);
0371           allLCTs_(bx_alct, matchingBX, iLCT) = selectedLCTs[iLCT];
0372         }
0373       }
0374     }
0375   }
0376 }
0377 
0378 // Correlate CSC and GEM information. Option ALCT-CLCT-GEM
0379 void CSCGEMMotherboard::correlateLCTsGEM(const CSCALCTDigi& ALCT,
0380                                          const CSCCLCTDigi& CLCT,
0381                                          const GEMInternalClusters& clusters,
0382                                          const CSCL1TPLookupTableME11ILT* lookupTableME11ILT,
0383                                          const CSCL1TPLookupTableME21ILT* lookupTableME21ILT,
0384                                          CSCCorrelatedLCTDigi& lct) const {
0385   // Sanity checks on ALCT, CLCT, GEM clusters
0386   if (!ALCT.isValid()) {
0387     LogTrace("CSCGEMMotherboard") << "Best ALCT invalid in correlateLCTsGEM";
0388     return;
0389   }
0390 
0391   if (!CLCT.isValid()) {
0392     LogTrace("CSCGEMMotherboard") << "Best CLCT invalid in correlateLCTsGEM";
0393     return;
0394   }
0395 
0396   GEMInternalClusters ValidClusters;
0397   for (const auto& cl : clusters)
0398     if (cl.isValid())
0399       ValidClusters.push_back(cl);
0400   if (ValidClusters.empty())
0401     return;
0402 
0403   // We can now check possible triplets and construct all LCTs with
0404   // valid ALCT, valid CLCTs and GEM clusters
0405   GEMInternalCluster bestCluster;
0406   cscGEMMatcher_->bestClusterLoc(ALCT, CLCT, ValidClusters, lookupTableME11ILT, lookupTableME21ILT, bestCluster);
0407   if (bestCluster.isValid())
0408     constructLCTsGEM(ALCT, CLCT, bestCluster, lookupTableME11ILT, lookupTableME21ILT, lct);
0409 }
0410 
0411 // Correlate CSC information. Option ALCT-CLCT
0412 void CSCGEMMotherboard::correlateLCTsGEM(const CSCALCTDigi& ALCT,
0413                                          const CSCCLCTDigi& CLCT,
0414                                          CSCCorrelatedLCTDigi& lct) const {
0415   // Sanity checks on ALCT, CLCT
0416   if (!ALCT.isValid() or (ALCT.getQuality() == 0 and drop_low_quality_alct_)) {
0417     LogTrace("CSCGEMMotherboard") << "Best ALCT invalid in correlateLCTsGEM";
0418     return;
0419   }
0420 
0421   bool dropLowQualityCLCT = drop_low_quality_clct_;
0422   if (isME11_ and CLCT.getKeyStrip() > CSCConstants::MAX_HALF_STRIP_ME1B)
0423     dropLowQualityCLCT = drop_low_quality_clct_me1a_;
0424 
0425   if (!CLCT.isValid() or (CLCT.getQuality() <= 3 and dropLowQualityCLCT)) {
0426     LogTrace("CSCGEMMotherboard") << "Best CLCT invalid in correlateLCTsGEM";
0427     return;
0428   }
0429 
0430   // construct LCT
0431   if (match_trig_enable() and doesALCTCrossCLCT(ALCT, CLCT)) {
0432     constructLCTsGEM(ALCT, CLCT, lct);
0433   }
0434 }
0435 
0436 // Correlate CSC and GEM information. Option CLCT-GEM
0437 void CSCGEMMotherboard::correlateLCTsGEM(const CSCCLCTDigi& CLCT,
0438                                          const GEMInternalClusters& clusters,
0439                                          const CSCL1TPLookupTableME11ILT* lookupTableME11ILT,
0440                                          const CSCL1TPLookupTableME21ILT* lookupTableME21ILT,
0441                                          CSCCorrelatedLCTDigi& lct) const {
0442   // Sanity checks on CLCT, GEM clusters
0443   bool dropLowQualityCLCT = drop_low_quality_clct_;
0444   if (isME11_ and CLCT.getKeyStrip() > CSCConstants::MAX_HALF_STRIP_ME1B)
0445     dropLowQualityCLCT = drop_low_quality_clct_me1a_;
0446 
0447   if (!CLCT.isValid() or (CLCT.getQuality() <= 3 and dropLowQualityCLCT)) {
0448     LogTrace("CSCGEMMotherboard") << "Best CLCT invalid in correlateLCTsGEM";
0449     return;
0450   }
0451 
0452   GEMInternalClusters ValidClusters;
0453   for (const auto& cl : clusters)
0454     if (cl.isValid())
0455       ValidClusters.push_back(cl);
0456   if (ValidClusters.empty())
0457     return;
0458 
0459   // get the best matching cluster
0460   GEMInternalCluster bestCluster;
0461   cscGEMMatcher_->bestClusterLoc(CLCT, ValidClusters, lookupTableME11ILT, lookupTableME21ILT, bestCluster);
0462 
0463   // construct all LCTs with valid CLCTs and coincidence clusters
0464   if (bestCluster.isCoincidence()) {
0465     constructLCTsGEM(CLCT, bestCluster, lookupTableME11ILT, lookupTableME21ILT, lct);
0466   }
0467 }
0468 
0469 // Correlate CSC and GEM information. Option ALCT-GEM
0470 void CSCGEMMotherboard::correlateLCTsGEM(const CSCALCTDigi& ALCT,
0471                                          const GEMInternalClusters& clusters,
0472                                          CSCCorrelatedLCTDigi& lct) const {
0473   // Sanity checks on ALCT, GEM clusters
0474   if (!ALCT.isValid() or (ALCT.getQuality() == 0 and drop_low_quality_alct_)) {
0475     LogTrace("CSCGEMMotherboard") << "Best ALCT invalid in correlateLCTsGEM";
0476     return;
0477   }
0478 
0479   GEMInternalClusters ValidClusters;
0480   for (const auto& cl : clusters)
0481     if (cl.isValid())
0482       ValidClusters.push_back(cl);
0483   if (ValidClusters.empty())
0484     return;
0485 
0486   // get the best matching cluster
0487   GEMInternalCluster bestCluster;
0488   cscGEMMatcher_->bestClusterLoc(ALCT, ValidClusters, bestCluster);
0489 
0490   // construct all LCTs with valid ALCTs and coincidence clusters
0491   if (bestCluster.isCoincidence()) {
0492     constructLCTsGEM(ALCT, bestCluster, lct);
0493   }
0494 }
0495 
0496 // Construct LCT from CSC and GEM information. Option ALCT-CLCT-GEM
0497 void CSCGEMMotherboard::constructLCTsGEM(const CSCALCTDigi& alct,
0498                                          const CSCCLCTDigi& clct,
0499                                          const GEMInternalCluster& gem,
0500                                          const CSCL1TPLookupTableME11ILT* lookupTableME11ILT,
0501                                          const CSCL1TPLookupTableME21ILT* lookupTableME21ILT,
0502                                          CSCCorrelatedLCTDigi& thisLCT) const {
0503   thisLCT.setValid(true);
0504   if (gem.isCoincidence())
0505     thisLCT.setType(CSCCorrelatedLCTDigi::ALCTCLCT2GEM);
0506   else if (gem.isValid())
0507     thisLCT.setType(CSCCorrelatedLCTDigi::ALCTCLCTGEM);
0508   thisLCT.setQuality(qualityAssignment_->findQuality(alct, clct, gem));
0509   thisLCT.setALCT(getBXShiftedALCT(alct));
0510   thisLCT.setCLCT(getBXShiftedCLCT(clct));
0511   // set pads if there are any
0512   thisLCT.setGEM1(gem.mid1());
0513   thisLCT.setGEM2(gem.mid2());
0514   thisLCT.setPattern(encodePattern(clct.getPattern()));
0515   thisLCT.setMPCLink(0);
0516   thisLCT.setBX0(0);
0517   thisLCT.setSyncErr(0);
0518   thisLCT.setCSCID(theTrigChamber);
0519   thisLCT.setTrknmb(0);  // will be set later after sorting
0520   thisLCT.setWireGroup(alct.getKeyWG());
0521   thisLCT.setStrip(clct.getKeyStrip());
0522   thisLCT.setBend(clct.getBend());
0523   thisLCT.setBX(alct.getBX());
0524   if (runCCLUT_) {
0525     thisLCT.setRun3(true);
0526     if (assign_gem_csc_bending_ &&
0527         gem.isValid()) {  //calculate new slope from strip difference between CLCT and associated GEM
0528       int slope = cscGEMMatcher_->calculateGEMCSCBending(clct, gem, lookupTableME11ILT, lookupTableME21ILT);
0529       thisLCT.setSlope(abs(slope));
0530       thisLCT.setBend(std::signbit(slope));
0531       thisLCT.setPattern(Run2PatternConverter(slope));
0532     } else
0533       thisLCT.setSlope(clct.getSlope());
0534     thisLCT.setQuartStripBit(clct.getQuartStripBit());
0535     thisLCT.setEighthStripBit(clct.getEighthStripBit());
0536     thisLCT.setRun3Pattern(clct.getRun3Pattern());
0537   }
0538 }
0539 
0540 // Construct LCT from CSC and GEM information. Option ALCT-CLCT
0541 void CSCGEMMotherboard::constructLCTsGEM(const CSCALCTDigi& aLCT,
0542                                          const CSCCLCTDigi& cLCT,
0543                                          CSCCorrelatedLCTDigi& thisLCT) const {
0544   thisLCT.setValid(true);
0545   thisLCT.setType(CSCCorrelatedLCTDigi::ALCTCLCT);
0546   thisLCT.setALCT(getBXShiftedALCT(aLCT));
0547   thisLCT.setCLCT(getBXShiftedCLCT(cLCT));
0548   thisLCT.setPattern(encodePattern(cLCT.getPattern()));
0549   thisLCT.setMPCLink(0);
0550   thisLCT.setBX0(0);
0551   thisLCT.setSyncErr(0);
0552   thisLCT.setCSCID(theTrigChamber);
0553   thisLCT.setTrknmb(0);  // will be set later after sorting
0554   thisLCT.setWireGroup(aLCT.getKeyWG());
0555   thisLCT.setStrip(cLCT.getKeyStrip());
0556   thisLCT.setBend(cLCT.getBend());
0557   thisLCT.setBX(aLCT.getBX());
0558   thisLCT.setQuality(qualityAssignment_->findQuality(aLCT, cLCT));
0559   if (runCCLUT_) {
0560     thisLCT.setRun3(true);
0561     // 4-bit slope value derived with the CCLUT algorithm
0562     thisLCT.setSlope(cLCT.getSlope());
0563     thisLCT.setQuartStripBit(cLCT.getQuartStripBit());
0564     thisLCT.setEighthStripBit(cLCT.getEighthStripBit());
0565     thisLCT.setRun3Pattern(cLCT.getRun3Pattern());
0566   }
0567 }
0568 
0569 // Construct LCT from CSC and GEM information. Option CLCT-2GEM
0570 void CSCGEMMotherboard::constructLCTsGEM(const CSCCLCTDigi& clct,
0571                                          const GEMInternalCluster& gem,
0572                                          const CSCL1TPLookupTableME11ILT* lookupTableME11ILT,
0573                                          const CSCL1TPLookupTableME21ILT* lookupTableME21ILT,
0574                                          CSCCorrelatedLCTDigi& thisLCT) const {
0575   thisLCT.setValid(true);
0576   thisLCT.setType(CSCCorrelatedLCTDigi::CLCT2GEM);
0577   thisLCT.setQuality(qualityAssignment_->findQuality(clct, gem));
0578   thisLCT.setCLCT(getBXShiftedCLCT(clct));
0579   thisLCT.setGEM1(gem.mid1());
0580   thisLCT.setGEM2(gem.mid2());
0581   thisLCT.setPattern(encodePattern(clct.getPattern()));
0582   thisLCT.setMPCLink(0);
0583   thisLCT.setBX0(0);
0584   thisLCT.setSyncErr(0);
0585   thisLCT.setCSCID(theTrigChamber);
0586   thisLCT.setTrknmb(0);  // will be set later after sorting
0587   thisLCT.setWireGroup(gem.getKeyWG());
0588   thisLCT.setStrip(clct.getKeyStrip());
0589   thisLCT.setBend(clct.getBend());
0590   thisLCT.setBX(gem.bx());
0591   if (runCCLUT_) {
0592     thisLCT.setRun3(true);
0593     if (assign_gem_csc_bending_ &&
0594         gem.isValid()) {  //calculate new slope from strip difference between CLCT and associated GEM
0595       int slope = cscGEMMatcher_->calculateGEMCSCBending(clct, gem, lookupTableME11ILT, lookupTableME21ILT);
0596       thisLCT.setSlope(abs(slope));
0597       thisLCT.setBend(pow(-1, std::signbit(slope)));
0598       thisLCT.setPattern(Run2PatternConverter(slope));
0599     } else
0600       thisLCT.setSlope(clct.getSlope());
0601     thisLCT.setQuartStripBit(clct.getQuartStripBit());
0602     thisLCT.setEighthStripBit(clct.getEighthStripBit());
0603     thisLCT.setRun3Pattern(clct.getRun3Pattern());
0604   }
0605 }
0606 
0607 // Construct LCT from CSC and GEM information. Option ALCT-2GEM
0608 void CSCGEMMotherboard::constructLCTsGEM(const CSCALCTDigi& alct,
0609                                          const GEMInternalCluster& gem,
0610                                          CSCCorrelatedLCTDigi& thisLCT) const {
0611   thisLCT.setValid(true);
0612   thisLCT.setType(CSCCorrelatedLCTDigi::ALCT2GEM);
0613   thisLCT.setQuality(qualityAssignment_->findQuality(alct, gem));
0614   thisLCT.setALCT(getBXShiftedALCT(alct));
0615   thisLCT.setGEM1(gem.mid1());
0616   thisLCT.setGEM2(gem.mid2());
0617   thisLCT.setPattern(10);
0618   thisLCT.setMPCLink(0);
0619   thisLCT.setBX0(0);
0620   thisLCT.setSyncErr(0);
0621   thisLCT.setCSCID(theTrigChamber);
0622   thisLCT.setTrknmb(0);  // will be set later after sorting
0623   thisLCT.setWireGroup(alct.getKeyWG());
0624   thisLCT.setStrip(gem.getKeyStrip());
0625   thisLCT.setBend(0);
0626   thisLCT.setBX(alct.getBX());
0627   if (runCCLUT_) {
0628     thisLCT.setRun3(true);
0629     thisLCT.setSlope(0);
0630     thisLCT.setQuartStripBit(false);
0631     thisLCT.setEighthStripBit(false);
0632     // ALCT-2GEM type LCTs do not bend in the chamber
0633     thisLCT.setRun3Pattern(4);
0634   }
0635 }
0636 
0637 void CSCGEMMotherboard::sortLCTs(std::vector<CSCCorrelatedLCTDigi>& lcts) const {
0638   // LCTs are sorted by quality. If there are two with the same quality, then the sorting is done by the slope
0639   std::sort(lcts.begin(), lcts.end(), [](const CSCCorrelatedLCTDigi& lct1, const CSCCorrelatedLCTDigi& lct2) -> bool {
0640     if (lct1.getQuality() > lct2.getQuality())
0641       return lct1.getQuality() > lct2.getQuality();
0642     else if (lct1.getQuality() == lct2.getQuality())
0643       return lct1.getSlope() < lct2.getSlope();
0644     else
0645       return false;
0646   });
0647 }