Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:20:48

0001 #include "L1Trigger/L1TMuon/interface/MicroGMTCancelOutUnit.h"
0002 #include "L1Trigger/L1TMuon/interface/GMTInternalMuon.h"
0003 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0004 
0005 namespace l1t {
0006   MicroGMTCancelOutUnit::MicroGMTCancelOutUnit() {}
0007 
0008   MicroGMTCancelOutUnit::~MicroGMTCancelOutUnit() {}
0009 
0010   void MicroGMTCancelOutUnit::initialise(L1TMuonGlobalParamsHelper* microGMTParamsHelper) {
0011     int fwVersion = microGMTParamsHelper->fwVersion();
0012     m_boPosMatchQualLUT = l1t::MicroGMTMatchQualLUTFactory::create(
0013         microGMTParamsHelper->bOPosMatchQualLUT(), cancel_t::omtf_bmtf_pos, fwVersion);
0014     m_boNegMatchQualLUT = l1t::MicroGMTMatchQualLUTFactory::create(
0015         microGMTParamsHelper->bONegMatchQualLUT(), cancel_t::omtf_bmtf_neg, fwVersion);
0016     m_foPosMatchQualLUT = l1t::MicroGMTMatchQualLUTFactory::create(
0017         microGMTParamsHelper->fOPosMatchQualLUT(), cancel_t::omtf_emtf_pos, fwVersion);
0018     m_foNegMatchQualLUT = l1t::MicroGMTMatchQualLUTFactory::create(
0019         microGMTParamsHelper->fONegMatchQualLUT(), cancel_t::omtf_emtf_neg, fwVersion);
0020     m_ovlPosSingleMatchQualLUT = l1t::MicroGMTMatchQualLUTFactory::create(
0021         microGMTParamsHelper->ovlPosSingleMatchQualLUT(), cancel_t::omtf_omtf_pos, fwVersion);
0022     m_ovlNegSingleMatchQualLUT = l1t::MicroGMTMatchQualLUTFactory::create(
0023         microGMTParamsHelper->ovlNegSingleMatchQualLUT(), cancel_t::omtf_omtf_neg, fwVersion);
0024     m_fwdPosSingleMatchQualLUT = l1t::MicroGMTMatchQualLUTFactory::create(
0025         microGMTParamsHelper->fwdPosSingleMatchQualLUT(), cancel_t::emtf_emtf_pos, fwVersion);
0026     m_fwdNegSingleMatchQualLUT = l1t::MicroGMTMatchQualLUTFactory::create(
0027         microGMTParamsHelper->fwdNegSingleMatchQualLUT(), cancel_t::emtf_emtf_neg, fwVersion);
0028 
0029     m_lutDict[tftype::omtf_neg + tftype::bmtf * 10] = m_boNegMatchQualLUT;
0030     m_lutDict[tftype::omtf_pos + tftype::bmtf * 10] = m_boPosMatchQualLUT;
0031     m_lutDict[tftype::omtf_pos + tftype::omtf_pos * 10] = m_ovlPosSingleMatchQualLUT;
0032     m_lutDict[tftype::omtf_neg + tftype::omtf_neg * 10] = m_ovlNegSingleMatchQualLUT;
0033     m_lutDict[tftype::emtf_pos + tftype::emtf_pos * 10] = m_fwdPosSingleMatchQualLUT;
0034     m_lutDict[tftype::emtf_neg + tftype::emtf_neg * 10] = m_fwdNegSingleMatchQualLUT;
0035     m_lutDict[tftype::omtf_pos + tftype::emtf_pos * 10] = m_foPosMatchQualLUT;
0036     m_lutDict[tftype::omtf_neg + tftype::emtf_neg * 10] = m_foNegMatchQualLUT;
0037   }
0038 
0039   void MicroGMTCancelOutUnit::setCancelOutBits(GMTInternalWedges& wedges, tftype trackFinder, cancelmode mode) {
0040     std::vector<std::shared_ptr<GMTInternalMuon>> coll1;
0041     coll1.reserve(3);
0042     std::vector<std::shared_ptr<GMTInternalMuon>> coll2;
0043     coll2.reserve(3);
0044     int maxWedges = 6;
0045     if (trackFinder == bmtf) {
0046       maxWedges = 12;
0047     }
0048     for (int currentWedge = 0; currentWedge < maxWedges; ++currentWedge) {
0049       for (const auto& mu : wedges.at(currentWedge)) {
0050         coll1.push_back(mu);
0051       }
0052       // handle wrap around: max "wedge" has to be compared to first "wedge"
0053       int neighbourWedge = (currentWedge + 1) % maxWedges;
0054       for (const auto& mu : wedges.at(neighbourWedge)) {
0055         coll2.push_back(mu);
0056       }
0057       if (mode == cancelmode::coordinate) {
0058         getCoordinateCancelBits(coll2, coll1);  // in case of a tie coll1 muon wins
0059       } else {
0060         getTrackAddrCancelBits(mode, coll1, coll2);
0061       }
0062 
0063       coll1.clear();
0064       coll2.clear();
0065     }
0066   }
0067 
0068   void MicroGMTCancelOutUnit::setCancelOutBitsOverlapBarrel(GMTInternalWedges& omtfSectors,
0069                                                             GMTInternalWedges& bmtfWedges,
0070                                                             cancelmode mode) {
0071     // overlap sector collection
0072     std::vector<std::shared_ptr<GMTInternalMuon>> coll1;
0073     coll1.reserve(3);
0074     // barrel wedge collection with 4 wedges
0075     std::vector<std::shared_ptr<GMTInternalMuon>> coll2;
0076     coll2.reserve(12);
0077 
0078     for (int currentSector = 0; currentSector < 6; ++currentSector) {
0079       for (const auto& omtfMuon : omtfSectors.at(currentSector)) {
0080         coll1.push_back(omtfMuon);
0081       }
0082       // BMTF | 1  | 2  | 3  | 4  | 5  | 6  | 7  | 8  | 9  | 10 | 11 | 0  |
0083       // OMTF |    0    |    1    |    2    |    3    |    4    |    5    |
0084       // cancel OMTF sector x with corresponding BMTF wedge + the two on either side;
0085       // e.g. OMTF 0 with BMTF 0, 1, 2, 3, OMTF 2 with BMTF 4, 5, 6, 7 etc.
0086       for (int i = 0; i < 4; ++i) {
0087         int currentWedge = (currentSector * 2 + i) % 12;
0088         for (const auto& bmtfMuon : bmtfWedges.at(currentWedge)) {
0089           coll2.push_back(bmtfMuon);
0090         }
0091       }
0092       if (mode == cancelmode::coordinate) {
0093         getCoordinateCancelBits(coll1, coll2);
0094       } else {
0095         getTrackAddrCancelBits(mode, coll1, coll2);
0096       }
0097       coll1.clear();
0098       coll2.clear();
0099     }
0100   }
0101 
0102   void MicroGMTCancelOutUnit::setCancelOutBitsOverlapEndcap(GMTInternalWedges& omtfSectors,
0103                                                             GMTInternalWedges& emtfSectors,
0104                                                             cancelmode mode) {
0105     // overlap sector collection
0106     std::vector<std::shared_ptr<GMTInternalMuon>> coll1;
0107     coll1.reserve(3);
0108     // endcap sector collection with 3 sectors
0109     std::vector<std::shared_ptr<GMTInternalMuon>> coll2;
0110     coll2.reserve(9);
0111 
0112     for (int curOmtfSector = 0; curOmtfSector < 6; ++curOmtfSector) {
0113       for (const auto& omtfMuon : omtfSectors.at(curOmtfSector)) {
0114         coll1.push_back(omtfMuon);
0115       }
0116       // OMTF |    0    |    1    |    2    |    3    |    4    |    5    |
0117       // EMTF |    0    |    1    |    2    |    3    |    4    |    5    |
0118       // cancel OMTF sector x with corresponding EMTF sector + the ones on either side;
0119       // e.g. OMTF 1 with EMTF 0, 1, 2; OMTF 0 with EMTF 5, 0, 1 etc.
0120       for (int i = 0; i < 3; ++i) {
0121         // handling the wrap around: adding 5 because 0 has to be compared to 5
0122         int curEmtfSector = ((curOmtfSector + 5) + i) % 6;
0123         for (const auto& emtfMuon : emtfSectors.at(curEmtfSector)) {
0124           coll2.push_back(emtfMuon);
0125         }
0126       }
0127       if (mode == cancelmode::coordinate) {
0128         getCoordinateCancelBits(coll1, coll2);
0129       } else {
0130         getTrackAddrCancelBits(mode, coll1, coll2);
0131       }
0132       coll1.clear();
0133       coll2.clear();
0134     }
0135   }
0136 
0137   void MicroGMTCancelOutUnit::getCoordinateCancelBits(std::vector<std::shared_ptr<GMTInternalMuon>>& coll1,
0138                                                       std::vector<std::shared_ptr<GMTInternalMuon>>& coll2) {
0139     if (coll1.empty() || coll2.empty()) {
0140       return;
0141     }
0142     tftype coll1TfType = (*coll1.begin())->trackFinderType();
0143     tftype coll2TfType = (*coll2.begin())->trackFinderType();
0144     if (coll2TfType != tftype::bmtf && coll1TfType % 2 != coll2TfType % 2) {
0145       edm::LogError("Detector side mismatch")
0146           << "Overlap-Endcap cancel out between positive and negative detector side attempted. Check eta assignment. "
0147              "OMTF candidate: TF type: "
0148           << coll1TfType << ", hwEta: " << (*coll1.begin())->hwEta() << ". EMTF candidate: TF type: " << coll2TfType
0149           << ", hwEta: " << (*coll2.begin())->hwEta() << ". TF type even: pos. side; odd: neg. side." << std::endl;
0150       return;
0151     }
0152 
0153     MicroGMTMatchQualLUT* matchLUT = m_lutDict.at(coll1TfType + coll2TfType * 10).get();
0154 
0155     for (auto mu_w1 = coll1.begin(); mu_w1 != coll1.end(); ++mu_w1) {
0156       int etaFine1 = (*mu_w1)->hwHF();
0157       // for EMTF muons set eta fine bit to true since hwHF is the halo bit
0158       if (coll1TfType == tftype::emtf_pos || coll1TfType == tftype::emtf_neg) {
0159         etaFine1 = 1;
0160       }
0161       for (auto mu_w2 = coll2.begin(); mu_w2 != coll2.end(); ++mu_w2) {
0162         int etaFine2 = (*mu_w2)->hwHF();
0163         // for EMTF muons set eta fine bit to true since hwHF is the halo bit
0164         if (coll2TfType == tftype::emtf_pos || coll2TfType == tftype::emtf_neg) {
0165           etaFine2 = 1;
0166         }
0167         // both muons must have the eta fine bit set in order to use the eta fine part of the LUT
0168         int etaFine = (int)(etaFine1 > 0 && etaFine2 > 0);
0169 
0170         // The LUT for cancellation takes reduced width phi and eta, we need the LSBs
0171         int dPhiMask = (1 << matchLUT->getDeltaPhiWidth()) - 1;
0172         int dEtaMask = (1 << matchLUT->getDeltaEtaWidth()) - 1;
0173 
0174         int dPhi = (*mu_w1)->hwGlobalPhi() - (*mu_w2)->hwGlobalPhi();
0175         dPhi = std::abs(dPhi);
0176         if (dPhi > 338)
0177           dPhi -= 576;  // shifts dPhi to [-pi, pi) in integer scale
0178         dPhi = std::abs(dPhi);
0179         int dEta = std::abs((*mu_w1)->hwEta() - (*mu_w2)->hwEta());
0180         // check first if the delta is within the LSBs that the LUT takes, otherwise the distance
0181         // is greater than what we want to cancel -> e.g. 31(int) is max => 31*0.01 = 0.31 (rad)
0182         // LUT takes 5 LSB for dEta and 3 LSB for dPhi
0183         if (dEta <= dEtaMask && dPhi <= dPhiMask) {
0184           int match = matchLUT->lookup(etaFine, dEta & dEtaMask, dPhi & dPhiMask);
0185           if (match == 1) {
0186             if ((*mu_w1)->hwQual() > (*mu_w2)->hwQual()) {
0187               (*mu_w2)->setHwCancelBit(1);
0188             } else {
0189               (*mu_w1)->setHwCancelBit(1);
0190             }
0191           }
0192         }
0193       }
0194     }
0195   }
0196 
0197   void MicroGMTCancelOutUnit::getTrackAddrCancelBits(cancelmode mode,
0198                                                      std::vector<std::shared_ptr<GMTInternalMuon>>& coll1,
0199                                                      std::vector<std::shared_ptr<GMTInternalMuon>>& coll2) {
0200     if (coll1.empty() || coll2.empty()) {
0201       return;
0202     }
0203     // Address based cancel out for BMTF
0204     if ((*coll1.begin())->trackFinderType() == tftype::bmtf && (*coll2.begin())->trackFinderType() == tftype::bmtf) {
0205       if (mode == cancelmode::tracks) {
0206         getTrackAddrCancelBitsOrigBMTF(coll1, coll2);
0207       } else if (mode == cancelmode::kftracks) {
0208         getTrackAddrCancelBitsKfBMTF(coll1, coll2);
0209       }
0210       // Address based cancel out for EMTF
0211     } else if (((*coll1.begin())->trackFinderType() == tftype::emtf_pos &&
0212                 (*coll2.begin())->trackFinderType() == tftype::emtf_pos) ||
0213                ((*coll1.begin())->trackFinderType() == tftype::emtf_neg &&
0214                 (*coll2.begin())->trackFinderType() == tftype::emtf_neg)) {
0215       for (auto mu_s1 = coll1.begin(); mu_s1 != coll1.end(); ++mu_s1) {
0216         std::map<int, int> trkAddr_s1 = (*mu_s1)->origin().trackAddress();
0217         int me1_ch_s1 = trkAddr_s1[l1t::RegionalMuonCand::emtfAddress::kME1Ch];
0218         int me2_ch_s1 = trkAddr_s1[l1t::RegionalMuonCand::emtfAddress::kME2Ch];
0219         int me3_ch_s1 = trkAddr_s1[l1t::RegionalMuonCand::emtfAddress::kME3Ch];
0220         int me4_ch_s1 = trkAddr_s1[l1t::RegionalMuonCand::emtfAddress::kME4Ch];
0221         if (me1_ch_s1 + me2_ch_s1 + me3_ch_s1 + me4_ch_s1 == 0) {
0222           continue;
0223         }
0224         int me1_seg_s1 = trkAddr_s1[l1t::RegionalMuonCand::emtfAddress::kME1Seg];
0225         int me2_seg_s1 = trkAddr_s1[l1t::RegionalMuonCand::emtfAddress::kME2Seg];
0226         int me3_seg_s1 = trkAddr_s1[l1t::RegionalMuonCand::emtfAddress::kME3Seg];
0227         int me4_seg_s1 = trkAddr_s1[l1t::RegionalMuonCand::emtfAddress::kME4Seg];
0228         for (auto mu_s2 = coll2.begin(); mu_s2 != coll2.end(); ++mu_s2) {
0229           std::map<int, int> trkAddr_s2 = (*mu_s2)->origin().trackAddress();
0230           int me1_ch_s2 = trkAddr_s2[l1t::RegionalMuonCand::emtfAddress::kME1Ch];
0231           int me2_ch_s2 = trkAddr_s2[l1t::RegionalMuonCand::emtfAddress::kME2Ch];
0232           int me3_ch_s2 = trkAddr_s2[l1t::RegionalMuonCand::emtfAddress::kME3Ch];
0233           int me4_ch_s2 = trkAddr_s2[l1t::RegionalMuonCand::emtfAddress::kME4Ch];
0234           if (me1_ch_s2 + me2_ch_s2 + me3_ch_s2 + me4_ch_s2 == 0) {
0235             continue;
0236           }
0237           int me1_seg_s2 = trkAddr_s2[l1t::RegionalMuonCand::emtfAddress::kME1Seg];
0238           int me2_seg_s2 = trkAddr_s2[l1t::RegionalMuonCand::emtfAddress::kME2Seg];
0239           int me3_seg_s2 = trkAddr_s2[l1t::RegionalMuonCand::emtfAddress::kME3Seg];
0240           int me4_seg_s2 = trkAddr_s2[l1t::RegionalMuonCand::emtfAddress::kME4Seg];
0241 
0242           int nMatchedStations = 0;
0243           if (me1_ch_s2 != 0 && me1_ch_s1 == me1_ch_s2 + 3 && me1_seg_s1 == me1_seg_s2) {
0244             ++nMatchedStations;
0245           }
0246           if (me2_ch_s2 != 0 && me2_ch_s1 == me2_ch_s2 + 2 && me2_seg_s1 == me2_seg_s2) {
0247             ++nMatchedStations;
0248           }
0249           if (me3_ch_s2 != 0 && me3_ch_s1 == me3_ch_s2 + 2 && me3_seg_s1 == me3_seg_s2) {
0250             ++nMatchedStations;
0251           }
0252           if (me4_ch_s2 != 0 && me4_ch_s1 == me4_ch_s2 + 2 && me4_seg_s1 == me4_seg_s2) {
0253             ++nMatchedStations;
0254           }
0255 
0256           //std::cout << "Shared hits found: " << nMatchedStations << std::endl;
0257           if (nMatchedStations > 0) {
0258             if ((*mu_s1)->origin().hwQual() >= (*mu_s2)->origin().hwQual()) {
0259               (*mu_s2)->setHwCancelBit(1);
0260             } else {
0261               (*mu_s1)->setHwCancelBit(1);
0262             }
0263           }
0264         }
0265       }
0266     } else {
0267       edm::LogError("Cancel out not implemented")
0268           << "Address based cancel out is currently only implemented for the barrel track finder.";
0269     }
0270   }
0271 
0272   void MicroGMTCancelOutUnit::getTrackAddrCancelBitsOrigBMTF(std::vector<std::shared_ptr<GMTInternalMuon>>& coll1,
0273                                                              std::vector<std::shared_ptr<GMTInternalMuon>>& coll2) {
0274     for (auto mu_w1 = coll1.begin(); mu_w1 != coll1.end(); ++mu_w1) {
0275       std::map<int, int> trkAddr_w1 = (*mu_w1)->origin().trackAddress();
0276       int wheelNum_w1 = trkAddr_w1[l1t::RegionalMuonCand::bmtfAddress::kWheelNum];
0277       int wheelSide_w1 = trkAddr_w1[l1t::RegionalMuonCand::bmtfAddress::kWheelSide];
0278       std::vector<int> stations_w1;
0279       stations_w1.push_back(trkAddr_w1[l1t::RegionalMuonCand::bmtfAddress::kStat1]);
0280       stations_w1.push_back(trkAddr_w1[l1t::RegionalMuonCand::bmtfAddress::kStat2]);
0281       stations_w1.push_back(trkAddr_w1[l1t::RegionalMuonCand::bmtfAddress::kStat3]);
0282       stations_w1.push_back(trkAddr_w1[l1t::RegionalMuonCand::bmtfAddress::kStat4]);
0283       //std::cout << "Track address 1: wheelSide (1 == negative side): " << wheelSide_w1 << ", wheelNum: " << wheelNum_w1 << ", stations1234: 0x" << hex << stations_w1[0] << stations_w1[1] << stations_w1[2] << stations_w1[3] << dec << std::endl;
0284 
0285       for (auto mu_w2 = coll2.begin(); mu_w2 != coll2.end(); ++mu_w2) {
0286         std::map<int, int> trkAddr_w2 = (*mu_w2)->origin().trackAddress();
0287         int wheelNum_w2 = trkAddr_w2[l1t::RegionalMuonCand::bmtfAddress::kWheelNum];
0288         int wheelSide_w2 = trkAddr_w2[l1t::RegionalMuonCand::bmtfAddress::kWheelSide];
0289         std::vector<int> stations_w2;
0290         stations_w2.push_back(trkAddr_w2[l1t::RegionalMuonCand::bmtfAddress::kStat1]);
0291         stations_w2.push_back(trkAddr_w2[l1t::RegionalMuonCand::bmtfAddress::kStat2]);
0292         stations_w2.push_back(trkAddr_w2[l1t::RegionalMuonCand::bmtfAddress::kStat3]);
0293         stations_w2.push_back(trkAddr_w2[l1t::RegionalMuonCand::bmtfAddress::kStat4]);
0294         //std::cout << "Track address 2: wheelSide (1 == negative side): " << wheelSide_w2 << ", wheelNum: " << wheelNum_w2 << ", stations1234: 0x" << hex << stations_w2[0] << stations_w2[1] << stations_w2[2] << stations_w2[3] << dec << std::endl;
0295 
0296         int nMatchedStations = 0;
0297         // search for duplicates in stations 2-4
0298         for (int i = 1; i < 4; ++i) {
0299           if (wheelSide_w1 == wheelSide_w2) {  // both tracks are on the same detector side
0300             if (wheelNum_w1 == wheelNum_w2) {  // both tracks have the same reference wheel
0301               if ((stations_w1[i] == 0x0 && stations_w2[i] == 0x2) ||
0302                   (stations_w1[i] == 0x1 && stations_w2[i] == 0x3) ||
0303                   (stations_w1[i] == 0x4 && stations_w2[i] == 0x0) ||
0304                   (stations_w1[i] == 0x5 && stations_w2[i] == 0x1) ||
0305                   (stations_w1[i] == 0x8 && stations_w2[i] == 0xA) ||
0306                   (stations_w1[i] == 0x9 && stations_w2[i] == 0xB) ||
0307                   (stations_w1[i] == 0xC && stations_w2[i] == 0x8) ||
0308                   (stations_w1[i] == 0xD && stations_w2[i] == 0x9)) {
0309                 ++nMatchedStations;
0310               }
0311             } else if (wheelNum_w1 == wheelNum_w2 - 1) {  // track 2 is one wheel higher than track 1
0312               if ((stations_w1[i] == 0x0 && stations_w2[i] == 0xA) ||
0313                   (stations_w1[i] == 0x1 && stations_w2[i] == 0xB) ||
0314                   (stations_w1[i] == 0x4 && stations_w2[i] == 0x8) ||
0315                   (stations_w1[i] == 0x5 && stations_w2[i] == 0x9)) {
0316                 ++nMatchedStations;
0317               }
0318             } else if (wheelNum_w1 == wheelNum_w2 + 1) {  // track 2 is one wheel lower than track 1
0319               if ((stations_w1[i] == 0x8 && stations_w2[i] == 0x2) ||
0320                   (stations_w1[i] == 0x9 && stations_w2[i] == 0x3) ||
0321                   (stations_w1[i] == 0xC && stations_w2[i] == 0x0) ||
0322                   (stations_w1[i] == 0xD && stations_w2[i] == 0x1)) {
0323                 ++nMatchedStations;
0324               }
0325             }
0326           } else {
0327             if (wheelNum_w1 == 0 &&
0328                 wheelNum_w2 == 0) {  // both tracks are on either side of the central wheel (+0 and -0)
0329               if ((stations_w1[i] == 0x8 && stations_w2[i] == 0xA) ||
0330                   (stations_w1[i] == 0x9 && stations_w2[i] == 0xB) ||
0331                   (stations_w1[i] == 0xC && stations_w2[i] == 0x8) ||
0332                   (stations_w1[i] == 0xD && stations_w2[i] == 0x9)) {
0333                 ++nMatchedStations;
0334               }
0335             }
0336           }
0337         }
0338         //std::cout << "Shared hits found: " << nMatchedStations << std::endl;
0339         if (nMatchedStations > 0) {
0340           if ((*mu_w1)->origin().hwQual() >= (*mu_w2)->origin().hwQual()) {
0341             (*mu_w2)->setHwCancelBit(1);
0342           } else {
0343             (*mu_w1)->setHwCancelBit(1);
0344           }
0345         }
0346       }
0347     }
0348   }
0349 
0350   void MicroGMTCancelOutUnit::getTrackAddrCancelBitsKfBMTF(std::vector<std::shared_ptr<GMTInternalMuon>>& coll1,
0351                                                            std::vector<std::shared_ptr<GMTInternalMuon>>& coll2) {
0352     for (auto mu_w1 = coll1.begin(); mu_w1 != coll1.end(); ++mu_w1) {
0353       std::map<int, int> trkAddr_w1 = (*mu_w1)->origin().trackAddress();
0354       int wheelNum_w1 = trkAddr_w1[l1t::RegionalMuonCand::bmtfAddress::kWheelNum];
0355       int wheelSide_w1 = trkAddr_w1[l1t::RegionalMuonCand::bmtfAddress::kWheelSide];
0356       std::vector<int> stations_w1;
0357       stations_w1.push_back(trkAddr_w1[l1t::RegionalMuonCand::bmtfAddress::kStat1]);
0358       stations_w1.push_back(trkAddr_w1[l1t::RegionalMuonCand::bmtfAddress::kStat2]);
0359       stations_w1.push_back(trkAddr_w1[l1t::RegionalMuonCand::bmtfAddress::kStat3]);
0360       stations_w1.push_back(trkAddr_w1[l1t::RegionalMuonCand::bmtfAddress::kStat4]);
0361       //std::cout << "Track address 1: wheelSide (1 == negative side): " << wheelSide_w1 << ", wheelNum: " << wheelNum_w1 << ", stations1234: 0x" << hex << stations_w1[0] << stations_w1[1] << stations_w1[2] << stations_w1[3] << dec << std::endl;
0362       //std::cout << "Muon1 eta: " << (*mu_w1)->hwEta() << " phi: " << (*mu_w1)->hwGlobalPhi() << " pT: " << (*mu_w1)->hwPt() << " qual: " << (*mu_w1)->origin().hwQual() << std::endl;
0363 
0364       for (auto mu_w2 = coll2.begin(); mu_w2 != coll2.end(); ++mu_w2) {
0365         std::map<int, int> trkAddr_w2 = (*mu_w2)->origin().trackAddress();
0366         int wheelNum_w2 = trkAddr_w2[l1t::RegionalMuonCand::bmtfAddress::kWheelNum];
0367         int wheelSide_w2 = trkAddr_w2[l1t::RegionalMuonCand::bmtfAddress::kWheelSide];
0368         std::vector<int> stations_w2;
0369         stations_w2.push_back(trkAddr_w2[l1t::RegionalMuonCand::bmtfAddress::kStat1]);
0370         stations_w2.push_back(trkAddr_w2[l1t::RegionalMuonCand::bmtfAddress::kStat2]);
0371         stations_w2.push_back(trkAddr_w2[l1t::RegionalMuonCand::bmtfAddress::kStat3]);
0372         stations_w2.push_back(trkAddr_w2[l1t::RegionalMuonCand::bmtfAddress::kStat4]);
0373         // std::cout << "Track address 2: wheelSide (1 == negative side): " << wheelSide_w2 << ", wheelNum: " << wheelNum_w2 << ", stations1234: 0x" << hex << stations_w2[0] << stations_w2[1] << stations_w2[2] << stations_w2[3] << dec << std::endl;
0374         // std::cout << "Muon2 eta: " << (*mu_w2)->hwEta() << " phi: " << (*mu_w2)->hwGlobalPhi() << " pT: " << (*mu_w2)->hwPt() << " qual: " << (*mu_w2)->origin().hwQual() << std::endl;
0375 
0376         int nMatchedStations = 0;
0377         // search for duplicates in stations 1-3
0378         for (int i = 0; i < 3; ++i) {
0379           if (wheelSide_w1 == wheelSide_w2) {  // both tracks are on the same detector side
0380             if (wheelNum_w1 == wheelNum_w2) {  // both tracks have the same reference wheel
0381               if ((stations_w1[i] == 0x2 && stations_w2[i] == 0x0) ||
0382                   (stations_w1[i] == 0x3 && stations_w2[i] == 0x1) ||
0383                   (stations_w1[i] == 0x0 && stations_w2[i] == 0x4) ||
0384                   (stations_w1[i] == 0x1 && stations_w2[i] == 0x5) ||
0385                   (stations_w1[i] == 0xA && stations_w2[i] == 0x8) ||
0386                   (stations_w1[i] == 0xB && stations_w2[i] == 0x9) ||
0387                   (stations_w1[i] == 0x8 && stations_w2[i] == 0xC) ||
0388                   (stations_w1[i] == 0x9 && stations_w2[i] == 0xD)) {
0389                 ++nMatchedStations;
0390               }
0391             } else if (wheelNum_w1 == wheelNum_w2 - 1) {  // track 2 is one wheel higher than track 1
0392               if ((stations_w1[i] == 0xA && stations_w2[i] == 0x0) ||
0393                   (stations_w1[i] == 0xB && stations_w2[i] == 0x1) ||
0394                   (stations_w1[i] == 0x8 && stations_w2[i] == 0x4) ||
0395                   (stations_w1[i] == 0x9 && stations_w2[i] == 0x5)) {
0396                 ++nMatchedStations;
0397               }
0398             } else if (wheelNum_w1 == wheelNum_w2 + 1) {  // track 2 is one wheel lower than track 1
0399               if ((stations_w1[i] == 0x2 && stations_w2[i] == 0x8) ||
0400                   (stations_w1[i] == 0x3 && stations_w2[i] == 0x9) ||
0401                   (stations_w1[i] == 0x0 && stations_w2[i] == 0xC) ||
0402                   (stations_w1[i] == 0x1 && stations_w2[i] == 0xD)) {
0403                 ++nMatchedStations;
0404               }
0405             }
0406           } else {  // If one muon in 0+ and one muon in 0- (0+ and 0- are physically the same wheel), however wheel 0 is not split in kalman algorithm
0407             if (wheelNum_w1 == 0 && wheelNum_w2 == 1) {
0408               if ((stations_w1[i] == 0xA && stations_w2[i] == 0x0) ||
0409                   (stations_w1[i] == 0xB && stations_w2[i] == 0x1) ||
0410                   (stations_w1[i] == 0x8 && stations_w2[i] == 0x4) ||
0411                   (stations_w1[i] == 0x9 && stations_w2[i] == 0x5)) {
0412                 ++nMatchedStations;
0413               }
0414             } else if (wheelNum_w1 == 1 && wheelNum_w2 == 0) {
0415               if ((stations_w1[i] == 0x2 && stations_w2[i] == 0x8) ||
0416                   (stations_w1[i] == 0x3 && stations_w2[i] == 0x9) ||
0417                   (stations_w1[i] == 0x0 && stations_w2[i] == 0xC) ||
0418                   (stations_w1[i] == 0x1 && stations_w2[i] == 0xD)) {
0419                 ++nMatchedStations;
0420               }
0421             }
0422           }
0423         }
0424         //std::cout << "Shared hits found: " << nMatchedStations << std::endl;
0425         if (nMatchedStations > 0) {
0426           if ((*mu_w1)->origin().hwQual() >= (*mu_w2)->origin().hwQual()) {
0427             (*mu_w2)->setHwCancelBit(1);
0428           } else {
0429             (*mu_w1)->setHwCancelBit(1);
0430           }
0431         }
0432       }
0433     }
0434   }
0435 
0436 }  // namespace l1t