Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-07-22 22:47:10

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