From f9420c921efcade6667da712b96cd33c9c1db09d Mon Sep 17 00:00:00 2001 From: Zhenbin Wu Date: Fri, 12 Jan 2024 13:18:12 -0600 Subject: [PATCH 01/17] Update GMT Emualtor for 2024 Annual Review Squash below commits Update Muon DataFormat Add Data and test script Adding new files from Michalis' Remove Node.h The Node class is renamed as TPS Reorganize the header files under plugins The original header files were moved to plugins by central CMSSW. Given the growing code, we think it is better to split header and source files, to keep the code clean. Apply Code format Code Check and Format Add python files Update gmt_cfi file Send TrackerMuon Quality score and isosum Sending quality score and isolation sum to GT Fix bug of the qual score Header Error fix and code formatting L1Trigger/Phase2L1GMT/interface/Constants.h was obsolete and removed. The TPSLUTs.h is used instead. Fix displaced KMTF bug Update DataFormats/L1TMuonPhase2/interface/KMTFTrack.h Co-authored-by: Andrew Loeliger Update DataFormats/L1TMuonPhase2/interface/KMTFTrack.h Co-authored-by: Andrew Loeliger Update L1Trigger/Phase2L1GMT/interface/KMTF.h Co-authored-by: Andrew Loeliger Update L1Trigger/Phase2L1GMT/interface/KMTFCore.h Co-authored-by: Andrew Loeliger Update L1Trigger/Phase2L1GMT/interface/KMTFLUTs.h Co-authored-by: Andrew Loeliger Update L1Trigger/Phase2L1GMT/interface/TPS.h Co-authored-by: Andrew Loeliger Fix comments on DataFormat Work on the comments Move default desctuctor to header files Abstract the prapagation in TPSAlgo Update for CMSSW_14 1. Fix issues when moving to CMSSW_14 release 2. Changed all the printf to edmLogInfo Fix issue from cherry-pick Add Phase-2 OMTF and EMTF to GMT SA - Get the Phase 2 prompt and displaced OMTF and EMTF to GMT SA - Add Phase 2 OMTF, EMTF, GMT to L1 Update apQual to apQualFlag as requested by GT --- .../L1TMuonPhase2/interface/Constants.h | 43 +- .../L1TMuonPhase2/interface/KMTFTrack.h | 399 ++++++ .../L1TMuonPhase2/interface/MuonStub.h | 22 + DataFormats/L1TMuonPhase2/interface/SAMuon.h | 15 +- .../L1TMuonPhase2/interface/TrackerMuon.h | 20 +- DataFormats/L1TMuonPhase2/src/SAMuon.cc | 2 +- DataFormats/L1TMuonPhase2/src/TrackerMuon.cc | 5 +- DataFormats/L1TMuonPhase2/src/classes.h | 1 + DataFormats/L1TMuonPhase2/src/classes_def.xml | 39 +- .../Configuration/python/SimL1Emulator_cff.py | 42 +- L1Trigger/Phase2L1GMT/BuildFile.xml | 1 + .../Phase2L1GMT/data/packedGainLUTs.root | Bin 0 -> 270653 bytes .../{plugins => interface}/ConvertedTTTrack.h | 57 +- .../{plugins => interface}/Isolation.h | 16 +- L1Trigger/Phase2L1GMT/interface/KMTF.h | 36 + L1Trigger/Phase2L1GMT/interface/KMTFCore.h | 171 +++ L1Trigger/Phase2L1GMT/interface/KMTFLUTs.h | 122 ++ .../L1TPhase2GMTEndcapStubProcessor.h | 5 +- .../PreTrackMatchedMuon.h | 94 +- .../Phase2L1GMT/interface/SAMuonCleaner.h | 24 + L1Trigger/Phase2L1GMT/interface/TPS.h | 30 + .../Phase2L1GMT/interface/TPSAlgorithm.h | 77 ++ .../Constants.h => interface/TPSLUTs.h} | 1173 ++++++++--------- .../TopologicalAlgorithm.h | 0 .../Phase2L1GMT/interface/TrackConverter.h | 52 + L1Trigger/Phase2L1GMT/plugins/MuonROI.h | 119 -- L1Trigger/Phase2L1GMT/plugins/Node.h | 196 --- .../Phase2L1GMT/plugins/Phase2L1TGMTFilter.cc | 1 - .../plugins/Phase2L1TGMTFwdMuonTranslator.cc | 284 ++++ .../plugins/Phase2L1TGMTKMTFProducer.cc | 160 +++ .../plugins/Phase2L1TGMTSAMuonGhostCleaner.cc | 126 ++ .../plugins/Phase2L1TGMTSAMuonProducer.cc | 179 --- .../plugins/Phase2L1TGMTStubProducer.cc | 63 +- ...ducer.cc => Phase2L1TGMTTkMuonProducer.cc} | 71 +- .../Phase2L1GMT/plugins/ROITempAssociator.h | 130 -- .../Phase2L1GMT/plugins/TrackConverter.h | 92 -- .../plugins/TrackMuonMatchAlgorithm.h | 626 --------- .../Phase2L1GMT/python/gmtFwdMuons_cfi.py | 9 + .../Phase2L1GMT/python/gmtKMTFMuons_cfi.py | 73 + .../Phase2L1GMT/python/gmtSAMuons_cfi.py | 8 + L1Trigger/Phase2L1GMT/python/gmtStubs_cfi.py | 40 + .../Phase2L1GMT/python/gmtTkMuons_cfi.py | 32 + L1Trigger/Phase2L1GMT/python/gmt_cfi.py | 92 +- L1Trigger/Phase2L1GMT/src/KMTF.cc | 464 +++++++ L1Trigger/Phase2L1GMT/src/KMTFCore.cc | 1167 ++++++++++++++++ .../src/L1TPhase2GMTBarrelStubProcessor.cc | 78 +- .../src/L1TPhase2GMTEndcapStubProcessor.cc | 90 +- L1Trigger/Phase2L1GMT/src/SAMuonCleaner.cc | 156 +++ L1Trigger/Phase2L1GMT/src/TPS.cc | 122 ++ L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc | 544 ++++++++ L1Trigger/Phase2L1GMT/src/TrackConverter.cc | 50 + L1Trigger/Phase2L1GMT/test/gmtStudy.py | 575 ++++---- .../Phase2L1GMT/test/makeKMTFCoarsseEtaLUT.py | 13 + L1Trigger/Phase2L1GMT/test/makeKMTFPTLUT.py | 17 + L1Trigger/Phase2L1GMT/test/runGMT.py | 31 +- L1Trigger/Phase2L1GMT/test/runMuonTrigger.py | 183 +++ L1Trigger/Phase2L1GMT/test/saStudy.py | 240 ++++ L1Trigger/Phase2L1GMT/test/submitCrab.py | 36 +- L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc | 6 +- 59 files changed, 5914 insertions(+), 2605 deletions(-) create mode 100644 DataFormats/L1TMuonPhase2/interface/KMTFTrack.h create mode 100644 L1Trigger/Phase2L1GMT/data/packedGainLUTs.root rename L1Trigger/Phase2L1GMT/{plugins => interface}/ConvertedTTTrack.h (63%) rename L1Trigger/Phase2L1GMT/{plugins => interface}/Isolation.h (96%) create mode 100644 L1Trigger/Phase2L1GMT/interface/KMTF.h create mode 100644 L1Trigger/Phase2L1GMT/interface/KMTFCore.h create mode 100644 L1Trigger/Phase2L1GMT/interface/KMTFLUTs.h rename L1Trigger/Phase2L1GMT/{plugins => interface}/PreTrackMatchedMuon.h (65%) create mode 100644 L1Trigger/Phase2L1GMT/interface/SAMuonCleaner.h create mode 100644 L1Trigger/Phase2L1GMT/interface/TPS.h create mode 100644 L1Trigger/Phase2L1GMT/interface/TPSAlgorithm.h rename L1Trigger/Phase2L1GMT/{plugins/Constants.h => interface/TPSLUTs.h} (52%) rename L1Trigger/Phase2L1GMT/{plugins => interface}/TopologicalAlgorithm.h (100%) create mode 100644 L1Trigger/Phase2L1GMT/interface/TrackConverter.h delete mode 100644 L1Trigger/Phase2L1GMT/plugins/MuonROI.h delete mode 100644 L1Trigger/Phase2L1GMT/plugins/Node.h create mode 100644 L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc create mode 100644 L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTKMTFProducer.cc create mode 100644 L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonGhostCleaner.cc delete mode 100644 L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonProducer.cc rename L1Trigger/Phase2L1GMT/plugins/{Phase2L1TGMTProducer.cc => Phase2L1TGMTTkMuonProducer.cc} (51%) delete mode 100644 L1Trigger/Phase2L1GMT/plugins/ROITempAssociator.h delete mode 100644 L1Trigger/Phase2L1GMT/plugins/TrackConverter.h delete mode 100644 L1Trigger/Phase2L1GMT/plugins/TrackMuonMatchAlgorithm.h create mode 100644 L1Trigger/Phase2L1GMT/python/gmtFwdMuons_cfi.py create mode 100644 L1Trigger/Phase2L1GMT/python/gmtKMTFMuons_cfi.py create mode 100644 L1Trigger/Phase2L1GMT/python/gmtSAMuons_cfi.py create mode 100644 L1Trigger/Phase2L1GMT/python/gmtStubs_cfi.py create mode 100644 L1Trigger/Phase2L1GMT/python/gmtTkMuons_cfi.py create mode 100644 L1Trigger/Phase2L1GMT/src/KMTF.cc create mode 100644 L1Trigger/Phase2L1GMT/src/KMTFCore.cc create mode 100644 L1Trigger/Phase2L1GMT/src/SAMuonCleaner.cc create mode 100644 L1Trigger/Phase2L1GMT/src/TPS.cc create mode 100644 L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc create mode 100644 L1Trigger/Phase2L1GMT/src/TrackConverter.cc create mode 100644 L1Trigger/Phase2L1GMT/test/makeKMTFCoarsseEtaLUT.py create mode 100644 L1Trigger/Phase2L1GMT/test/makeKMTFPTLUT.py create mode 100644 L1Trigger/Phase2L1GMT/test/runMuonTrigger.py create mode 100644 L1Trigger/Phase2L1GMT/test/saStudy.py diff --git a/DataFormats/L1TMuonPhase2/interface/Constants.h b/DataFormats/L1TMuonPhase2/interface/Constants.h index ea8c2f4c0c5cb..8f4ec6c8c2fe7 100644 --- a/DataFormats/L1TMuonPhase2/interface/Constants.h +++ b/DataFormats/L1TMuonPhase2/interface/Constants.h @@ -28,9 +28,9 @@ namespace Phase2L1GMT { const int BITSD0 = 12; //Muon ROI - const int BITSSTUBCOORD = 8; + const int BITSSTUBCOORD = 10; const int BITSSTUBETA = 8; - const int BITSSTUBID = 9; + const int BITSSTUBID = 12; const int BITSSTUBPHIQUALITY = 4; const int BITSSTUBETAQUALITY = 4; const int BITSSTUBTIME = 8; @@ -45,8 +45,8 @@ namespace Phase2L1GMT { const int BITSSIGMAETA = 4; const int BITSSIGMACOORD = 4; const int BITSPROPCOORD = 9; - const int BITSPROPSIGMACOORD_A = 5; - const int BITSPROPSIGMACOORD_B = 5; + const int BITSPROPSIGMACOORD_A = 6; + const int BITSPROPSIGMACOORD_B = 6; const int BITSPROPSIGMAETA_A = 5; const int BITSPROPSIGMAETA_B = 5; @@ -62,8 +62,9 @@ namespace Phase2L1GMT { const int BITSGTETA = 14; const int BITSGTZ0 = 10; const int BITSGTD0 = 10; - const int BITSGTQUAL = 8; - const int BITSGTISO = 4; + const int BITSGTQUAL = 6; + const int BITSGTQUALSC = 7; + const int BITSGTISO = 6; const int BITSGTBETA = 4; // Bitwidth for Tau->3mu object @@ -91,22 +92,24 @@ namespace Phase2L1GMT { const float LSBpt = 0.03125; const float LSBphi = 2. * M_PI / pow(2, BITSPHI); const float LSBeta = 2. * M_PI / pow(2, BITSETA); - const float LSBGTz0 = 0.05; // 0.5mm, in sync with GTT and Correlator - const float LSBGTd0 = 0.03; // from GT interface doc - const float LSBSAz0 = 1.6; // 0.05 * 32 cm, with range +- 25.6 - const float LSBSAd0 = 3.84; // 0.03 * 128 cm, with range +- 245.76 + const float LSBGTiso = 0.25; // 0.25GeV, LSBphi * 8 + const float LSBGTz0 = 0.05; // 0.5mm, in sync with GTT and Correlator + const float LSBGTd0 = 0.03; // from GT interface doc + const float LSBSAz0 = 1.6; // 0.05 * 32 cm, with range +- 25.6 + const float LSBSAd0 = 3.84; // 0.03 * 128 cm, with range +- 245.76 typedef ap_uint<64> wordtype; - typedef ap_uint<1> valid_gt_t; //valid - typedef ap_uint<1> q_gt_t; //charge - typedef ap_uint pt_gt_t; //pt of tracker muon - typedef ap_int phi_gt_t; //phi of tracker muon - typedef ap_int eta_gt_t; //eta of tracker muon - typedef ap_int z0_gt_t; //z0 of tracker muon - typedef ap_int d0_gt_t; //d0 of tracker muon - typedef ap_uint iso_gt_t; //isolation of tracker muon - typedef ap_uint beta_gt_t; //beta of tracker muon - typedef ap_uint qual_gt_t; //quality of tracker muon + typedef ap_uint<1> valid_gt_t; //valid + typedef ap_uint<1> q_gt_t; //charge + typedef ap_uint pt_gt_t; //pt of tracker muon + typedef ap_int phi_gt_t; //phi of tracker muon + typedef ap_int eta_gt_t; //eta of tracker muon + typedef ap_int z0_gt_t; //z0 of tracker muon + typedef ap_int d0_gt_t; //d0 of tracker muon + typedef ap_uint iso_gt_t; //isolation of tracker muon + typedef ap_uint beta_gt_t; //beta of tracker muon + typedef ap_uint qual_gt_t; //quality of tracker muon + typedef ap_int qualsc_gt_t; //quality score of tracker muon (qual/q) //Standalone muon datatype typedef ap_uint<1> valid_sa_t; //valid diff --git a/DataFormats/L1TMuonPhase2/interface/KMTFTrack.h b/DataFormats/L1TMuonPhase2/interface/KMTFTrack.h new file mode 100644 index 0000000000000..7e6197eea6d9e --- /dev/null +++ b/DataFormats/L1TMuonPhase2/interface/KMTFTrack.h @@ -0,0 +1,399 @@ +#ifndef DataFormats_L1TMuonPhase2_KMTFTrack_h +#define DataFormats_L1TMuonPhase2_KMTFTrack_h + +#include "DataFormats/Candidate/interface/LeafCandidate.h" +#include "DataFormats/L1TMuonPhase2/interface/MuonStub.h" +#include "DataFormats/L1Trigger/interface/BXVector.h" + +namespace l1t { + + class KMTFTrack; + typedef std::vector KMTFTrackCollection; + typedef BXVector KMTFTrackBxCollection; + + class KMTFTrack : public reco::LeafCandidate { + public: + KMTFTrack() + : reco::LeafCandidate(-1, reco::LeafCandidate::PolarLorentzVector(0.1, 0.0, 0.0, 0.105)), + unconstrainedP4_(reco::LeafCandidate::PolarLorentzVector(0.1, 0.0, 0.0, 0.105)), + covariance_(std::vector(6, 0.0)), + curvVertex_(0), + ptC_(0), + phiVertex_(0), + dxy_(0), + curvMuon_(0), + ptU_(0), + phiMuon_(0), + phiBMuon_(0), + curv_(0), + phi_(0), + phiB_(0), + coarseEta_(0), + approxPromptChi2_(0), + approxPromptErrChi2_(0), + approxDispChi2_(0), + approxDispErrChi2_(0), + hitPattern_(0), + step_(1), + sector_(0), + wheel_(0), + quality_(0), + hasFineEta_(false), + bx_(0), + rankPrompt_(0), + rankDisp_(0), + idFlag_(0) {} + + ~KMTFTrack() override = default; + + KMTFTrack(const l1t::MuonStubRef& seed, int phi, int phiB) + : reco::LeafCandidate(-1, reco::LeafCandidate::PolarLorentzVector(0.1, 0.0, 0.0, 0.105)), + unconstrainedP4_(reco::LeafCandidate::PolarLorentzVector(0.1, 0.0, 0.0, 0.105)), + covariance_(std::vector(6, 0.0)), + curvVertex_(0), + ptC_(0), + phiVertex_(0), + dxy_(0), + curvMuon_(0), + ptU_(0), + phiMuon_(0), + phiBMuon_(0), + curv_(0), + phi_(phi), + phiB_(phiB), + coarseEta_(0), + approxPromptChi2_(0), + approxPromptErrChi2_(0), + approxDispChi2_(0), + approxDispErrChi2_(0), + hitPattern_(0), + step_(seed->depthRegion()), + sector_(seed->phiRegion()), + wheel_(seed->etaRegion()), + quality_(seed->quality()), + hasFineEta_(false), + bx_(seed->bxNum()), + rankPrompt_(0), + rankDisp_(0), + idFlag_(0) { + stubs_.push_back(seed); + residuals_.push_back(0); + residuals_.push_back(0); + residuals_.push_back(0); + } + + reco::LeafCandidate::PolarLorentzVector displacedP4() const { return unconstrainedP4_; } + + //unconstrained pt + int ptDisplaced() const { return ptU_; } + //unconstrained curvature at station 1 + int curvatureAtMuon() const { return curvMuon_; } + //unconstrained phi at station 1 + int phiAtMuon() const { return phiMuon_; } + //unconstrained phiB at station 1 + int phiBAtMuon() const { return phiBMuon_; } + + //constrained pt + int ptPrompt() const { return ptC_; } + //Constrained curvature at vertex + int curvatureAtVertex() const { return curvVertex_; } + //constrained phi at the vertex + int phiAtVertex() const { return phiVertex_; } + //Impact parameter as calculated from the muon track + int dxy() const { return dxy_; } + //Unconstrained curvature at the Muon systen + int curvature() const { return curv_; } + //Unconstrained phi at the Muon systen + int positionAngle() const { return phi_; } + //Unconstrained bending angle at the Muon systen + int bendingAngle() const { return phiB_; } + //Coarse eta caluclated only using phi segments + int coarseEta() const { return coarseEta_; } + //Approximate Chi2 metrics + int approxPromptChi2() const { return approxPromptChi2_; } + int approxPromptErrChi2() const { return approxPromptErrChi2_; } + int approxDispChi2() const { return approxDispChi2_; } + int approxDispErrChi2() const { return approxDispErrChi2_; } + + int hitPattern() const { return hitPattern_; } + //step; + int step() const { return step_; } + //sector; + int sector() const { return sector_; } + //wheel + int wheel() const { return wheel_; } + //quality + int quality() const { return quality_; } + + //fine eta + int fineEta() const { return fineEta_; } + bool hasFineEta() const { return hasFineEta_; } + + //BX + int bx() const { return bx_; } + + //rank + int rankPrompt() const { return rankPrompt_; } + int rankDisp() const { return rankDisp_; } + + int id() const { return idFlag_; } + + //Associated stubs + const l1t::MuonStubRefVector& stubs() const { return stubs_; } + + //get Kalman gain + const std::vector& kalmanGain(unsigned int step) const { + switch (step) { + case 3: + return kalmanGain3_; + case 2: + return kalmanGain2_; + case 1: + return kalmanGain1_; + case 0: + return kalmanGain0_; + } + return kalmanGain0_; + } + + //get covariance + const std::vector& covariance() const { return covariance_; } + + //get residual + int residual(uint i) const { return residuals_[i]; } + + //check overlap + bool overlapTrack(const KMTFTrack& other) const { + for (const auto& s1 : stubs_) { + for (const auto& s2 : other.stubs()) { + if (s1->phiRegion() == s2->phiRegion() && s1->etaRegion() == s2->etaRegion() && + s1->depthRegion() == s2->depthRegion() && s1->id() == s2->id()) + return true; + } + } + return false; + } + + bool operator==(const KMTFTrack& t2) const { + if (this->stubs().size() != t2.stubs().size()) + return false; + for (unsigned int i = 0; i < this->stubs().size(); ++i) { + const l1t::MuonStubRef& s1 = this->stubs()[i]; + const l1t::MuonStubRef& s2 = t2.stubs()[i]; + if (s1->phiRegion() != s2->phiRegion() || s1->etaRegion() != s2->etaRegion() || + s1->depthRegion() != s2->depthRegion() || s1->id() != s2->id() || s1->tfLayer() != s2->tfLayer()) + return false; + } + return true; + } + + //Set coordinates general + void setCoordinates(int step, int curv, int phi, int phiB) { + step_ = step; + curv_ = curv; + phiB_ = phiB; + phi_ = phi; + } + + void setCoordinatesAtVertex(int curv, int phi, int dxy) { + curvVertex_ = curv; + phiVertex_ = phi; + dxy_ = dxy; + } + + void setCoordinatesAtMuon(int curv, int phi, int phiB) { + curvMuon_ = curv; + phiMuon_ = phi; + phiBMuon_ = phiB; + } + + void setPt(int ptC, int ptU) { + ptC_ = ptC; + ptU_ = ptU; + } + + void setCoarseEta(int eta) { coarseEta_ = eta; } + + void setHitPattern(int pattern) { hitPattern_ = pattern; } + + void setApproxChi2(int chi, int chiErr, bool prompt) { + if (prompt) { + approxPromptChi2_ = chi; + approxPromptErrChi2_ = chiErr; + } else { + approxDispChi2_ = chi; + approxDispErrChi2_ = chiErr; + } + } + + void setPtEtaPhi(double pt, double eta, double phi) { + PolarLorentzVector v(pt, eta, phi, 0.105); + setP4(v); + } + void setPtEtaPhiDisplaced(double pt, double eta, double phi) { + unconstrainedP4_.SetPt(pt); + unconstrainedP4_.SetEta(eta); + unconstrainedP4_.SetPhi(phi); + } + + void addStub(const l1t::MuonStubRef& stub) { + if (stub->quality() < quality_) + quality_ = stub->quality(); + stubs_.push_back(stub); + } + + void setStubs(const l1t::MuonStubRefVector& stubs) { stubs_ = stubs; } + + void setRank(int rank, bool vertex) { + if (vertex) + rankPrompt_ = rank; + else + rankDisp_ = rank; + } + + void setIDFlag(bool passPrompt, bool passDisp) { + unsigned p0 = 0; + unsigned p1 = 0; + + if (passPrompt) + p0 = 1; + if (passDisp) + p1 = 2; + + idFlag_ = p0 | p1; + } + + void setKalmanGain( + unsigned int step, unsigned int K, float a1, float a2, float a3 = 0, float a4 = 0, float a5 = 0, float a6 = 0) { + switch (step) { + case 3: + kalmanGain3_.push_back(K); + kalmanGain3_.push_back(a1); + kalmanGain3_.push_back(a2); + kalmanGain3_.push_back(a3); + kalmanGain3_.push_back(a4); + kalmanGain3_.push_back(a5); + kalmanGain3_.push_back(a6); + break; + case 2: + kalmanGain2_.push_back(K); + kalmanGain2_.push_back(a1); + kalmanGain2_.push_back(a2); + kalmanGain2_.push_back(a3); + kalmanGain2_.push_back(a4); + kalmanGain2_.push_back(a5); + kalmanGain2_.push_back(a6); + break; + case 1: + kalmanGain1_.push_back(K); + kalmanGain1_.push_back(a1); + kalmanGain1_.push_back(a2); + kalmanGain1_.push_back(a3); + kalmanGain1_.push_back(a4); + kalmanGain1_.push_back(a5); + kalmanGain1_.push_back(a6); + break; + case 0: + kalmanGain0_.push_back(K); + kalmanGain0_.push_back(a1); + kalmanGain0_.push_back(a2); + kalmanGain0_.push_back(a3); + break; + + default: + throw cms::Exception("WrongCondition") << "Critical ERROR on setting the Kalman gain\n"; + } + } + + //set covariance + void setCovariance(const CovarianceMatrix& c) { + covariance_[0] = c(0, 0); + covariance_[1] = c(0, 1); + covariance_[2] = c(1, 1); + covariance_[3] = c(0, 2); + covariance_[4] = c(1, 2); + covariance_[5] = c(2, 2); + } + + //set fine eta + void setFineEta(int eta) { + fineEta_ = eta; + hasFineEta_ = true; + } + + //set residual + void setResidual(uint i, int val) { residuals_[i] = val; } + + private: + reco::LeafCandidate::PolarLorentzVector unconstrainedP4_; + + //Covariance matrix for studies + std::vector covariance_; + l1t::MuonStubRefVector stubs_; + + //vertex coordinates + int curvVertex_; + int ptC_; + int phiVertex_; + int dxy_; + + //muon coordinates + int curvMuon_; + int ptU_; + int phiMuon_; + int phiBMuon_; + + //generic coordinates + int curv_; + int phi_; + int phiB_; + //common coordinates + int coarseEta_; + + //Approximate Chi2 metric + int approxPromptChi2_; + int approxPromptErrChi2_; + int approxDispChi2_; + int approxDispErrChi2_; + + //phi bitmask + int hitPattern_; + + //propagation step + int step_; + + //sector + int sector_; + //wheel + int wheel_; + + //quality + int quality_; + + //Fine eta + int fineEta_; + + //has fine eta? + bool hasFineEta_; + + //BX + int bx_; + + //rank + int rankPrompt_; + int rankDisp_; + + //flag + int idFlag_; + + //Kalman Gain for making LUTs + std::vector kalmanGain0_; + std::vector kalmanGain1_; + std::vector kalmanGain2_; + std::vector kalmanGain3_; + + std::vector residuals_; + }; + +} // namespace l1t +#endif diff --git a/DataFormats/L1TMuonPhase2/interface/MuonStub.h b/DataFormats/L1TMuonPhase2/interface/MuonStub.h index eb571d3ca0598..70902648a96b0 100644 --- a/DataFormats/L1TMuonPhase2/interface/MuonStub.h +++ b/DataFormats/L1TMuonPhase2/interface/MuonStub.h @@ -79,6 +79,28 @@ namespace l1t { inline int quality() const { return quality_; } /// return tag (second TS tag) inline int id() const { return id_; } + inline int index() const { return id_; } + /// return address + inline int address() const { + int addr = id_ | (phiRegion_ << 2); + if (etaRegion_ >= 0) { + return addr | (etaRegion_ << 8); + } else { + int twos_comp = ((-etaRegion_) ^ 0xf) + 1; + return addr | (twos_comp << 8); + } + } + + inline int kmtf_address() const { + int addr = id_ | (phiRegion_ << 2); + if (etaRegion_ >= 0) { + return addr | (etaRegion_ << 6); + } else { + int twos_comp = ((-etaRegion_) ^ 0x7) + 1; + return addr | (twos_comp << 6); + } + } + /// return bunch crossing inline int bxNum() const { return bxNum_; } diff --git a/DataFormats/L1TMuonPhase2/interface/SAMuon.h b/DataFormats/L1TMuonPhase2/interface/SAMuon.h index 12ea802dae04f..1eb49f58291d4 100644 --- a/DataFormats/L1TMuonPhase2/interface/SAMuon.h +++ b/DataFormats/L1TMuonPhase2/interface/SAMuon.h @@ -8,6 +8,7 @@ #include "DataFormats/L1TMuon/interface/RegionalMuonCand.h" #include "DataFormats/L1TMuon/interface/RegionalMuonCandFwd.h" #include "DataFormats/L1TMuonPhase2/interface/Constants.h" +#include "DataFormats/L1TMuonPhase2/interface/MuonStub.h" namespace l1t { @@ -30,7 +31,12 @@ namespace l1t { const int hwD0() const { return hwD0_; } const uint hwBeta() const { return hwBeta_; } void setBeta(uint beta) { hwBeta_ = beta; } + void setTF(tftype tf) { tf_ = tf; } + unsigned int trackID() const { return trackID_; } + void setTrackID(unsigned int ID) { trackID_ = ID; } + + const tftype tfType() const { return tf_; } // For GT, returning ap_ type const Phase2L1GMT::valid_sa_t apValid() const { return Phase2L1GMT::valid_sa_t(hwPt() > 0); }; const Phase2L1GMT::pt_sa_t apPt() const { return Phase2L1GMT::pt_sa_t(hwPt()); }; @@ -39,7 +45,7 @@ namespace l1t { const Phase2L1GMT::z0_sa_t apZ0() const { return Phase2L1GMT::z0_sa_t(hwZ0()); }; const Phase2L1GMT::d0_sa_t apD0() const { return Phase2L1GMT::d0_sa_t(hwD0()); }; const Phase2L1GMT::q_sa_t apCharge() const { return Phase2L1GMT::q_sa_t(hwCharge()); }; - const Phase2L1GMT::qual_sa_t apQual() const { return Phase2L1GMT::qual_sa_t(hwQual()); }; + const Phase2L1GMT::qual_sa_t apQualFlag() const { return Phase2L1GMT::qual_sa_t(hwQual()); }; // For HLT const double phZ0() const { return Phase2L1GMT::LSBSAz0 * hwZ0(); } @@ -66,12 +72,19 @@ namespace l1t { return (hwPt() > other.hwPt()); } + void addStub(const MuonStubRef& stub) { stubs_.push_back(stub); } + void setStubs(const MuonStubRefVector& stubs) { stubs_ = stubs; } + const MuonStubRefVector stubs() const { return stubs_; } + private: bool hwCharge_; int hwZ0_; int hwD0_; uint hwBeta_; uint64_t word_; + MuonStubRefVector stubs_; + unsigned int trackID_; + tftype tf_; }; } // namespace l1t diff --git a/DataFormats/L1TMuonPhase2/interface/TrackerMuon.h b/DataFormats/L1TMuonPhase2/interface/TrackerMuon.h index 1dd8cc90bf344..470833d471347 100644 --- a/DataFormats/L1TMuonPhase2/interface/TrackerMuon.h +++ b/DataFormats/L1TMuonPhase2/interface/TrackerMuon.h @@ -8,6 +8,7 @@ #include "DataFormats/L1TMuon/interface/RegionalMuonCand.h" #include "DataFormats/L1TMuon/interface/RegionalMuonCandFwd.h" #include "DataFormats/L1TMuonPhase2/interface/MuonStub.h" +#include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" #include "FWCore/MessageLogger/interface/MessageLogger.h" #include "DataFormats/L1TMuonPhase2/interface/Constants.h" @@ -32,7 +33,7 @@ namespace l1t { ~TrackerMuon() override; const edm::Ptr& trkPtr() const { return trkPtr_; } - const std::vector& muonRef() const { return muRef_; } + const SAMuonRefVector muonRef() const { return muRef_; } const bool hwCharge() const { return hwCharge_; } const int hwZ0() const { return hwZ0_; } @@ -41,7 +42,7 @@ namespace l1t { const int hwIsoSumAp() const { return hwIsoSumAp_; } const uint hwBeta() const { return hwBeta_; } void setBeta(uint beta) { hwBeta_ = beta; } - void setMuonRef(const std::vector& p) { muRef_ = p; } + void setMuonRef(const l1t::SAMuonRefVector& p) { muRef_ = p; } void setHwIsoSum(int isoSum) { hwIsoSum_ = isoSum; } void setHwIsoSumAp(int isoSum) { hwIsoSumAp_ = isoSum; } @@ -53,8 +54,8 @@ namespace l1t { const Phase2L1GMT::z0_gt_t apZ0() const { return Phase2L1GMT::z0_gt_t(hwZ0()); }; const Phase2L1GMT::d0_gt_t apD0() const { return Phase2L1GMT::d0_gt_t(hwD0()); }; const Phase2L1GMT::q_gt_t apCharge() const { return Phase2L1GMT::q_gt_t(hwCharge()); }; - const Phase2L1GMT::qual_gt_t apQual() const { return Phase2L1GMT::qual_gt_t(hwQual()); }; - const Phase2L1GMT::iso_gt_t apIso() const { return Phase2L1GMT::iso_gt_t(hwIso()); }; + const Phase2L1GMT::qual_gt_t apQualFlag() const { return Phase2L1GMT::qual_gt_t(hwQual()); }; + const Phase2L1GMT::iso_gt_t apIso() const { return Phase2L1GMT::iso_gt_t(hwIsoSumAp()); }; const Phase2L1GMT::beta_gt_t apBeta() const { return Phase2L1GMT::beta_gt_t(hwBeta()); }; // For HLT @@ -63,14 +64,16 @@ namespace l1t { const double phPt() const { return Phase2L1GMT::LSBpt * hwPt(); } const double phEta() const { return Phase2L1GMT::LSBeta * hwEta(); } const double phPhi() const { return Phase2L1GMT::LSBphi * hwPhi(); } + const double phIso() const { return Phase2L1GMT::LSBGTiso * hwIsoSumAp(); } const int phCharge() const { return pow(-1, hwCharge()); } - + const uint numberOfMatches() const { return numberOfMatches_; } + const uint numberOfStations() const { return stubs_.size(); } const std::array word() const { return word_; } void setWord(std::array word) { word_ = word; } void print() const; const MuonStubRefVector stubs() const { return stubs_; } void addStub(const MuonStubRef& stub) { stubs_.push_back(stub); } - + void setNumberOfMatches(uint matches) { numberOfMatches_ = matches; } bool operator<(const TrackerMuon& other) const { return (hwPt() < other.hwPt()); } bool operator>(const TrackerMuon& other) const { return (hwPt() > other.hwPt()); } @@ -87,8 +90,9 @@ namespace l1t { int hwIsoSum_; //Store the eneryg sum for isolation with ap_type int hwIsoSumAp_; - - std::vector muRef_; + uint numberOfMatches_; + uint numberOfStations_; + SAMuonRefVector muRef_; MuonStubRefVector stubs_; }; } // namespace l1t diff --git a/DataFormats/L1TMuonPhase2/src/SAMuon.cc b/DataFormats/L1TMuonPhase2/src/SAMuon.cc index b759b84ce1c45..8c5287605a525 100644 --- a/DataFormats/L1TMuonPhase2/src/SAMuon.cc +++ b/DataFormats/L1TMuonPhase2/src/SAMuon.cc @@ -6,7 +6,7 @@ using namespace l1t; SAMuon::SAMuon() : hwZ0_(0), hwD0_(0), word_(0) {} SAMuon::SAMuon(const l1t::Muon& mu, bool charge, uint pt, int eta, int phi, int z0, int d0, uint quality) - : L1Candidate(mu.p4(), pt, eta, phi, quality), hwCharge_(charge), hwZ0_(z0), hwD0_(d0), word_(0) {} + : L1Candidate(mu.p4(), pt, eta, phi, quality), hwCharge_(charge), hwZ0_(z0), hwD0_(d0), word_(0), trackID_(0) {} SAMuon::~SAMuon() {} diff --git a/DataFormats/L1TMuonPhase2/src/TrackerMuon.cc b/DataFormats/L1TMuonPhase2/src/TrackerMuon.cc index 916eb797b8e8e..cf86bdb8a16bd 100644 --- a/DataFormats/L1TMuonPhase2/src/TrackerMuon.cc +++ b/DataFormats/L1TMuonPhase2/src/TrackerMuon.cc @@ -2,7 +2,7 @@ using namespace l1t; -TrackerMuon::TrackerMuon() : hwZ0_(0), hwD0_(0) {} +TrackerMuon::TrackerMuon() : hwZ0_(0), hwD0_(0), numberOfMatches_(0) {} TrackerMuon::TrackerMuon( const edm::Ptr& trk, bool charge, uint pt, int eta, int phi, int z0, int d0, uint quality) @@ -15,7 +15,8 @@ TrackerMuon::TrackerMuon( hwCharge_(charge), hwZ0_(z0), hwD0_(d0), - hwBeta_(15) {} + hwBeta_(15), + numberOfMatches_(0) {} TrackerMuon::~TrackerMuon() {} diff --git a/DataFormats/L1TMuonPhase2/src/classes.h b/DataFormats/L1TMuonPhase2/src/classes.h index 2c0dd2a390149..360e5f3df8586 100644 --- a/DataFormats/L1TMuonPhase2/src/classes.h +++ b/DataFormats/L1TMuonPhase2/src/classes.h @@ -4,6 +4,7 @@ #include "DataFormats/L1TMuonPhase2/interface/MuonStub.h" #include "DataFormats/L1TMuonPhase2/interface/TrackerMuon.h" #include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" +#include "DataFormats/L1TMuonPhase2/interface/KMTFTrack.h" #include "DataFormats/L1TMuonPhase2/interface/EMTFHit.h" #include "DataFormats/L1TMuonPhase2/interface/EMTFTrack.h" diff --git a/DataFormats/L1TMuonPhase2/src/classes_def.xml b/DataFormats/L1TMuonPhase2/src/classes_def.xml index 23c286c1d736c..2678d4190e62f 100644 --- a/DataFormats/L1TMuonPhase2/src/classes_def.xml +++ b/DataFormats/L1TMuonPhase2/src/classes_def.xml @@ -7,21 +7,32 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + + diff --git a/L1Trigger/Configuration/python/SimL1Emulator_cff.py b/L1Trigger/Configuration/python/SimL1Emulator_cff.py index 6136c3cc49919..de66aa375b82c 100644 --- a/L1Trigger/Configuration/python/SimL1Emulator_cff.py +++ b/L1Trigger/Configuration/python/SimL1Emulator_cff.py @@ -128,6 +128,18 @@ _phase2_siml1emulator.add(l1tCaloJetHTT) _phase2_siml1emulator.add(l1tPhase2CaloJetEmulator) +# Overlap and EndCap Muon Track Finder +# ######################################################################## +from L1Trigger.L1TMuonOverlapPhase2.simOmtfPhase2Digis_cfi import * +_phase2_siml1emulator.add(simOmtfPhase2Digis) + +from L1Trigger.L1TMuonEndCapPhase2.simCscTriggerPrimitiveDigisForEMTF_cfi import * +from L1Trigger.L1TMuonEndCapPhase2.rpcRecHitsForEMTF_cfi import * +from L1Trigger.L1TMuonEndCapPhase2.simEmtfDigisPhase2_cfi import * + +_phase2_siml1emulator.add(simCscTriggerPrimitiveDigisForEMTF) +_phase2_siml1emulator.add(rpcRecHitsForEMTF) +_phase2_siml1emulator.add(simEmtfDigisPhase2) # ######################################################################## # Phase-2 L1T - TrackTrigger dependent modules @@ -150,19 +162,27 @@ # Emulated GMT Muons (Tk + Stub, Tk + MuonTFT, StandaloneMuon) # ######################################################################## from L1Trigger.Phase2L1GMT.gmt_cfi import * -l1tTkStubsGmt = l1tGMTStubs.clone() -l1tTkMuonsGmt = l1tGMTMuons.clone( - srcStubs = 'l1tTkStubsGmt' +l1tStubsGmt = gmtStubs.clone() +l1tKMTFMuonsGmt = gmtKMTFMuons.clone( + stubs = cms.InputTag('l1tStubsGmt','kmtf'), ) -l1tSAMuonsGmt = l1tStandaloneMuons.clone() -_phase2_siml1emulator.add( l1tTkStubsGmt ) -_phase2_siml1emulator.add( l1tTkMuonsGmt ) +l1tFwdMuonsGmt = gmtFwdMuons.clone( + stubs = 'l1tStubsGmt:tps' +) +l1tSAMuonsGmt = gmtSAMuons.clone( + barrelPrompt = cms.InputTag('l1tKMTFMuonsGmt:prompt'), + barrelDisp = cms.InputTag('l1tKMTFMuonsGmt:displaced'), + forwardPrompt = cms.InputTag('l1tFwdMuonsGmt:prompt'), + forwardDisp = cms.InputTag('l1tFwdMuonsGmt:displaced') +) +l1tTkMuonsGmt = gmtTkMuons.clone( + srcStubs = 'l1tStubsGmt:tps' +) +_phase2_siml1emulator.add( l1tStubsGmt ) +_phase2_siml1emulator.add( l1tKMTFMuonsGmt ) +_phase2_siml1emulator.add( l1tFwdMuonsGmt ) _phase2_siml1emulator.add( l1tSAMuonsGmt ) - -## fix for low-pt muons, this collection is a copy of the l1tTkMuonsGmt collection -## in which we only keep those low pt muons with an SA muon associated to it. -l1tTkMuonsGmtLowPtFix = l1tGMTFilteredMuons.clone() -_phase2_siml1emulator.add( l1tTkMuonsGmtLowPtFix ) +_phase2_siml1emulator.add( l1tTkMuonsGmt ) # Tracker Objects # ######################################################################## diff --git a/L1Trigger/Phase2L1GMT/BuildFile.xml b/L1Trigger/Phase2L1GMT/BuildFile.xml index bca0bcd832660..8d46e1a62eb96 100644 --- a/L1Trigger/Phase2L1GMT/BuildFile.xml +++ b/L1Trigger/Phase2L1GMT/BuildFile.xml @@ -1,6 +1,7 @@ + diff --git a/L1Trigger/Phase2L1GMT/data/packedGainLUTs.root b/L1Trigger/Phase2L1GMT/data/packedGainLUTs.root new file mode 100644 index 0000000000000000000000000000000000000000..bbfcdf841d55af8982003bd9a871303e2c33ecc6 GIT binary patch literal 270653 zcma&M18`+g(>5C0wryJzPwZsElbP7IPHdYe$;7tJiET`5+jrjgqHf*$SABo4>Ro&F zuI|;fs;i&fBc{|q%CbsF&&J5S(}>3 z7+cyYXlgjKIQ=K5|D_QO`acmI_mpbDz~EZ{1(5r{BY{ETh5S$H!GixM3vufIX2I~^ zEKdL952Yc?E(vG;?|36VBTjG&T?M!)7%*yaFc0txU2BzOO*|2%i11YSlS>Fh#Pg@B zUY7Ize!t*j&TxeS%L$Y4K+r7J6k1ATeGxV&B*6c_TACT)|1cCYxmL1T_+$zb%IoZHyt{VUHI;oUo`vS zv<~3!c!RtV{aj??$6;WdSn>Si-%S8hzzN=656W<0dhFY9S060&X|E1GBE&Cp|BP^C zT_JDB6CapirgQe;camp;y*YPxSW_g{aAN1D6&MllFEc-;*c$GcTIauKc{k*UES~#; zKJB8oza^ZvTS>n>^TDqqa4LQF1N}vJdW_=PzpUfhLx7XSo+Z6c`~i@kqG-`EfFQ|m zU*Kn9l!%K^B&3MRXTQsjA!SHh0@3DW4f0>y#%s>qM%OCYOs@@4vFOJb7K8(Yb4-f= zWKx!M)l*_^^!1;>{6_Y^(0H~k0SV8r)GSwv6@tXxQac9nU8|Q_YLtWA&UNMcGdE{Y znCKRij{~GvA#6V~+pU=+W>QaRU6|;Cd1~HQ&uj@Ak8CT-QDXyB9lIts9dI+7cBVqA za%QBHuTfh4V;JhHykIXGBi%>m6k4ZeL^c#{J1~xvLOa|>=O%s-JJe(j6KNHAKpm%MIVEkH(zk&1{+V5QF51Xir$OVZo^Dvgp@P)PL z$KEOX_)~8Yq_QCw(K0j(oMXt)WO})eG>8VsD^1HZoYF9BO*Mk%6jGOrc>QA{84h0 zN09pq48HRwkrvJ#@l40q#)XM^4{dya>z4-#MdnHI-2O`TR>e+Dw&^!vx9XtvSSV- z1@{s0pzUOgJ&K*wMpQ!P-6O)_(2a2tns<~kY2XUZze6((2fI^vmCH&cY-0O)19cMI zG3f30g-5*s(SO{@J%OT78L%9vCM2WoWS(NT0sG*8AQNG!P-RKth5na@UjIy3njCoVCVuC)F7^oCQtj_)THdne+Uu6WO^VM?h+j%`-iuaq zA)5I?6$igzE2MrCR;bIE=1!3!xDqXbmqwJ_g-NG~aVKrni2V2?2&$hNyEXR@*zKA? zL;|_YdyT1Cw}f9U6Pd`qM>#MhF|M*TQGn2xmltOyz$` z!!y3Sg0aK#$CEgLvEytR0Mo_niYeFR_X-3{S;*Skmgd#pcnU=S9zd$28=S1;6_`Jh za1_i3+foUhlB}u<_lr=SEB05TJtFoip+CyjPl_f?*54&Qq54*6`3&tn%fxL(CKgIv242vnj!ha8__t4!E)3B2%ZG!%lc!(|B zc%eW*t!z0X+y$kuXk*CzvkGe3i8K0X(#{=Pxr#x+4bREz@UP$FgcU~nD0t?J2b1bJ zeHMkUU;{P3uLwn0_aTi}8YgG`8wo)Vl)wur|{qJyEldOi4zC;yuZ>f&XLu{l6;o+2}gp3N5;B8+_12A><$2e*S*} z5ccf<2Y?*^1;BCW{|f*!{S~w{@kUTtWlQ7d-?p4DeWlPR`LXG~@43?XeRS;v^DDBO zhI1fKijjSr(fR~+F$AVAU^M1SU|`S8A_ZZwbETHCNpSq(0*9TV{}h{Vy2}k(EaqG` zYIgp5$$e_O5}p=55_-CuzJta;lGp#n#EOoJ)*p`ONFI!)EiNR4BQ?@ZXc~v$;z=0n zffjYZ>_-^fiit>G%}n;2uj-*G($r-J-^^k|-_1M} zntWwk+ie}W^<2r`S7)_(X~v1v5<7k#49(WJmN6f=t+>5ZjSGkwk6X~Aj`bkxIr+T} z**4Wmja(DfD&EB0=(XVUj6Mk0z-XcLobiJ380qP{O+&1BQC)*ggmIHJ;mQG;QQ(wI ziNG7knLCayYm9SCyHv8#A?{`l6d%X40GB)3QUHO0EjHY1 zLQ3QAlTLurqoLMC4j5RhWs!y#nfd4 zpEaiAV^;L?_%kYpA^l#6p?f4@T7c=}+rHVdL+#-53p9`QZpLp}7#t#W?aWWG33K=_ z%Jj4Hu5ZYiAjKc~j2j4I*0-7C5Ili6DaE4U;jkaigT1O1<^eRkM0!ojC;}zS?Yr5$ zr9v_StwMA?UFaI}2hiXj#w!0VljvC66aTlksBb{5AUk1uC9c6z6w8@Z+C#y(*Q{yR z@xaTTW1##FVtYyFyECbZjo9$ z{TJ&8dSxALqR9#N%YpV$VJg3Gn3bI3>on&zL9RAtv9qf1)?x-0>%kN{T`{qR8T_?w zF-$9Ke*@fT?U#0ee`Z*C+rkD%!~{7T8<%%1XBc*Ix!S_S823d#K)%DIocTp}C!6`y z)i-sh)?qv~ugOPa@-zKHFHvGiZ$%mlRco+KsKICt26QafsNWWW<&c`Nr-CX(|MT+5 z=LbA)ada(P&l~%k;bVOm!bHEEbVZGK2klIyNf{EkVt@F$Dc^gpy4peFp}I-ko3DEA zKmtS~{n*|NE3euf(vR;N2CRS8$SA-F^0f~aKH}C2yMMq0(*_=3n@3llAUt}WKZJi5 z>}`e<1zV@O`_MMnCeT_WKxuA{MD5+e6#+}F_nCP=23pMuq+yOV}D z0?V4T1?vOM6F;=Y-U0HJ_Q3IecatwFTltrTE~FK;!xudjZN+OW&qBuCB?V9 zgHBJUtqZ3u<&L-E=b|992Jt_aZSPT&`0r3TFWVCJw0ohkn9~@NuTwcWF$Zp{WD+fs&lOVSf zSC6$BwPXMA?w%=Ih=H|yqdjBfSLz+Yndzv{ZokZyr@egbBRpc629P$Kf52zT@!r|n zzZycc4eFMEM!dJ}hXvX1GzZepEZ;5bAbm*eP|m0~^YBsh1m}`H%9pLdPI+p=mZNA8 zmtKiE{_n28{(ay_6maDJ5b9sn&0t`{-2d(VH2icrdiyx0OVagaC&14mV$2@nOK}L-9ZWeWBo? zL?G6;Nd`Z1aeehm?`d55;ej1_WzHeiEhP?U1eKnl+2&X^iVSco{^^irs{4@J& zKY!)LivdVKw=eqr?W+%8KmEtQ4!<71WTYX!1^2%A=iT(seu##Cs@Hx94}CqVILEP% ztVM~Jwp}$3wtOS7@~XEcZZ4Bny!!i~|HP?s_m{O~;{a{pezTVJaXr7-e=A{%fqwyM zSCo*MJ0!Djq&h0ERA!Pgr%l;kSZuPe`JmdmP?dAn@nW=zxztlU+UK(c$4WYfK-E=O zdNK(TaWSN-)N@U$H>d)N``0+OnJ=d5o!Cl)?|?|DW#O3$@z0n{t45_1c@+T8&L~b>;?I>!=0_oByZ>$zUE1Lt7lUAE(0&CG> zJ1mTE$aM_`sCEh}^;^O6Br_f;Gu*=0iuz*dq4CmO-@#=vUbw}=tra5Ax!}{w z_p!L`%!2mWt%HQu^->m%m8!+zP^(`JH6NwGQmrcoM*CC2a%>aH2TTPOW=Ds#+j1L? zJ9eI%L`o3BVAR&^qYU>8DJF4oOldo4fy&l8xO{&m(Lm2W-|A(3{3MsL)JuY_lz#

oBbpJU@aGa15=%ss8l8kR42(7PxsXIq+>fNf%9 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

hq5eG{tQRRkd)tZzXOAPrj7hSf*C$kiOkw8dz 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%0Aqo~cX*~Y70 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 C+i~## literal 0 HcmV?d00001 diff --git a/L1Trigger/Phase2L1GMT/plugins/ConvertedTTTrack.h b/L1Trigger/Phase2L1GMT/interface/ConvertedTTTrack.h similarity index 63% rename from L1Trigger/Phase2L1GMT/plugins/ConvertedTTTrack.h rename to L1Trigger/Phase2L1GMT/interface/ConvertedTTTrack.h index 0deebe6b2bc98..af1e253f037b2 100644 --- a/L1Trigger/Phase2L1GMT/plugins/ConvertedTTTrack.h +++ b/L1Trigger/Phase2L1GMT/interface/ConvertedTTTrack.h @@ -3,20 +3,21 @@ #include "DataFormats/L1TrackTrigger/interface/TTTypes.h" #include "DataFormats/L1TMuonPhase2/interface/Constants.h" #include "FWCore/MessageLogger/interface/MessageLogger.h" +#include namespace Phase2L1GMT { class ConvertedTTTrack { public: - ConvertedTTTrack(const uint& charge, - const int& curvature, - const uint& abseta, - const uint& pt, - const int& eta, - const int& phi, - const int& z0, - const int& d0, - const int& quality, + ConvertedTTTrack(const ap_uint<1>& charge, + const ap_int& curvature, + const ap_int& abseta, + const ap_uint& pt, + const ap_int& eta, + const ap_int& phi, + const ap_int& z0, + const ap_int& d0, + const ap_uint<1>& quality, const ap_uint<96>& word) : charge_(charge), curvature_(curvature), @@ -29,21 +30,21 @@ namespace Phase2L1GMT { quality_(quality), word_(word) {} - const uint charge() const { return charge_; } + const ap_uint<1> charge() const { return charge_; } - const int curvature() const { return curvature_; } - const uint abseta() const { return abseta_; } + const ap_int curvature() const { return curvature_; } + const ap_uint abseta() const { return abseta_; } - const uint pt() const { return pt_; } + const ap_uint pt() const { return pt_; } - const int eta() const { return eta_; } - const int phi() const { return phi_; } + const ap_int eta() const { return eta_; } + const ap_int phi() const { return phi_; } - void setPhi(int phi) { phi_ = phi; } + void setPhi(ap_int phi) { phi_ = phi; } - const int z0() const { return z0_; } - const int d0() const { return d0_; } - const int quality() const { return quality_; } + const ap_int z0() const { return z0_; } + const ap_int d0() const { return d0_; } + const ap_uint<1> quality() const { return quality_; } const float offline_pt() const { return offline_pt_; } const float offline_eta() const { return offline_eta_; } const float offline_phi() const { return offline_phi_; } @@ -74,15 +75,15 @@ namespace Phase2L1GMT { const edm::Ptr > trkPtr() const { return trkPtr_; } private: - uint charge_; - int curvature_; - uint abseta_; - uint pt_; - int eta_; - int phi_; - int z0_; - int d0_; - uint quality_; + ap_uint<1> charge_; + ap_int curvature_; + ap_uint abseta_; + ap_uint pt_; + ap_int eta_; + ap_int phi_; + ap_int z0_; + ap_int d0_; + ap_uint<1> quality_; float offline_pt_; float offline_eta_; float offline_phi_; diff --git a/L1Trigger/Phase2L1GMT/plugins/Isolation.h b/L1Trigger/Phase2L1GMT/interface/Isolation.h similarity index 96% rename from L1Trigger/Phase2L1GMT/plugins/Isolation.h rename to L1Trigger/Phase2L1GMT/interface/Isolation.h index 7d17fe1050687..447aff5fd1ea0 100644 --- a/L1Trigger/Phase2L1GMT/plugins/Isolation.h +++ b/L1Trigger/Phase2L1GMT/interface/Isolation.h @@ -150,7 +150,6 @@ namespace Phase2L1GMT { for (auto &mu : trkMus) { int accum = 0; - int iso_ = 0; std::vector overlaps; for (auto t : convertedTracks) { unsigned ovrl = compute_trk_iso(mu, t); @@ -159,18 +158,19 @@ namespace Phase2L1GMT { } } - // Only 8 bit for accumation? + // Accumation without fixed bit width mu.setHwIsoSum(accum); + // Accumation with fixed bit width + // Bit shifts with 3 bits with LSB of 0.25GeV iso_accum_t temp(accum); - accum = temp.to_int(); + mu.setHwIsoSumAp(temp.to_int() >> 3); - mu.setHwIsoSumAp(accum); + //Disable isolation bit, sending isolation sumPT to GT + //iso_ |= SetAbsIsolationBits(accum); + //iso_ |= SetRelIsolationBits(accum, mu.hwPt()); - iso_ |= SetAbsIsolationBits(accum); - iso_ |= SetRelIsolationBits(accum, mu.hwPt()); - - mu.setHwIso(iso_); + //mu.setHwIso(iso_); } if (dumpForHLS_) { diff --git a/L1Trigger/Phase2L1GMT/interface/KMTF.h b/L1Trigger/Phase2L1GMT/interface/KMTF.h new file mode 100644 index 0000000000000..8b9ef11d26ae7 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/interface/KMTF.h @@ -0,0 +1,36 @@ +#ifndef L1Trigger_Phase2L1GMT_KMTF_h +#define L1Trigger_Phase2L1GMT_KMTF_h +#include "DataFormats/L1TMuonPhase2/interface/MuonStub.h" +#include "L1Trigger/Phase2L1GMT/interface/KMTFCore.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include + +namespace Phase2L1GMT { + + class KMTF { + public: + KMTF(int verbose, const edm::ParameterSet& iConfig); + ~KMTF(); + std::pair, std::vector > process(const l1t::MuonStubRefVector& stubsAll, + int bx, + unsigned int MAXN); + + private: + int verbose_; + std::unique_ptr trackMaker_; + void overlapCleanTrack(l1t::KMTFTrack& source, const l1t::KMTFTrack& other, bool eq, bool vertex); + std::vector cleanRegion(const std::vector& tracks2, + const std::vector& tracks3, + const std::vector& tracks4, + bool vertex); + void sort(std::vector& in, bool vertex); + void swap(std::vector& list, int i, int j, bool vertex); + + class SeedSorter { + public: + SeedSorter() {} + bool operator()(const l1t::MuonStubRef& a, const l1t::MuonStubRef& b) { return (a->id() < b->id()); } + }; + }; +} // namespace Phase2L1GMT +#endif diff --git a/L1Trigger/Phase2L1GMT/interface/KMTFCore.h b/L1Trigger/Phase2L1GMT/interface/KMTFCore.h new file mode 100644 index 0000000000000..19291d1f53031 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/interface/KMTFCore.h @@ -0,0 +1,171 @@ +/* +Kalman Filter L1 Muon algorithm +Tyler Lam (UCLA) +Sep. 2021 +*/ +#ifndef L1Trigger_Phase2L1GMT_KMTFCore_h +#define L1Trigger_Phase2L1GMT_KMTFCore_h +#include "L1Trigger/Phase2L1GMT/interface/KMTFLUTs.h" +#include "DataFormats/L1TMuonPhase2/interface/KMTFTrack.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include +#include "ap_fixed.h" + +namespace Phase2L1GMT { + + class KMTFCore { + public: + typedef ROOT::Math::SVector Vector2; + typedef ROOT::Math::SMatrix > CovarianceMatrix2; + typedef ROOT::Math::SMatrix Matrix32; + typedef ROOT::Math::SMatrix Matrix23; + typedef ROOT::Math::SMatrix Matrix13; + typedef ROOT::Math::SMatrix Matrix31; + typedef ROOT::Math::SMatrix Matrix33; + + KMTFCore(const edm::ParameterSet& settings); + + std::pair chain(const l1t::MuonStubRef& seed, const l1t::MuonStubRefVector& stubs); + + std::vector clean(const std::vector& tracks, uint seed, bool vertex); + + private: + std::unique_ptr lutService_; + + std::pair match(const l1t::MuonStubRef& seed, const l1t::MuonStubRefVector& stubs, int step); + + int correctedPhiB(const l1t::MuonStubRef& stub); + void propagate(l1t::KMTFTrack& track); + bool update(l1t::KMTFTrack& track, const l1t::MuonStubRef& stub, int mask, int seedQual); + bool updateOffline(l1t::KMTFTrack& track, const l1t::MuonStubRef& stub); + bool updateOffline1D(l1t::KMTFTrack& track, const l1t::MuonStubRef& stub); + bool updateLUT(l1t::KMTFTrack& track, const l1t::MuonStubRef& stub, int mask, int seedQual); + void vertexConstraint(l1t::KMTFTrack& track); + void vertexConstraintOffline(l1t::KMTFTrack& track); + void vertexConstraintLUT(l1t::KMTFTrack& track); + int hitPattern(const l1t::KMTFTrack& track); + int customBitmask(unsigned int bit1, unsigned int bit2, unsigned int bit3, unsigned int bit4); + bool getBit(int bitmask, int pos); + void setFourVectors(l1t::KMTFTrack& track); + bool estimateChiSquare(l1t::KMTFTrack& track, bool vertex); + void setRank(l1t::KMTFTrack& track, bool vertex); + int wrapAround(int value, int maximum); + int encode(bool ownwheel, int sector, int tag); + std::pair getByCode(const std::vector& tracks, int mask); + uint twosCompToBits(int q); + uint etaStubRank(const l1t::MuonStubRef& stub); + void calculateEta(l1t::KMTFTrack& track); + uint matchAbs(std::map& info, uint i, uint j); + int ptLUT(int K); + + bool verbose_; + + //Initial Curvature + std::vector initK_; + std::vector initK2_; + + //propagation coefficients + std::vector eLoss_; + std::vector aPhi_; + std::vector aPhiB_; + std::vector aPhiBNLO_; + std::vector bPhi_; + std::vector bPhiB_; + double phiAt2_; + std::vector etaLUT0_; + std::vector etaLUT1_; + + //Chi Square estimator input + uint globalChi2Cut_; + uint globalChi2CutLimit_; + + std::vector chiSquareDisp1_; + std::vector chiSquareDisp2_; + std::vector chiSquareDisp3_; + std::vector chiSquareErrADisp1_; + std::vector chiSquareErrADisp2_; + std::vector chiSquareErrADisp3_; + std::vector chiSquareErrBDisp1_; + std::vector chiSquareErrBDisp2_; + std::vector chiSquareErrBDisp3_; + + std::vector chiSquarePrompt1_; + std::vector chiSquarePrompt2_; + std::vector chiSquarePrompt3_; + std::vector chiSquareErrAPrompt1_; + std::vector chiSquareErrAPrompt2_; + std::vector chiSquareErrAPrompt3_; + std::vector chiSquareErrBPrompt1_; + std::vector chiSquareErrBPrompt2_; + std::vector chiSquareErrBPrompt3_; + + std::vector chiSquareCutDispPattern_; + std::vector chiSquareCutOffDisp_; + std::vector chiSquareCutDisp_; + std::vector chiSquareCutPromptPattern_; + std::vector chiSquareCutOffPrompt_; + std::vector chiSquareCutPrompt_; + + //bitmasks to run== diferent combinations for a given seed in a given station + std::vector combos4_; + std::vector combos3_; + std::vector combos2_; + std::vector combos1_; + + //bits for fixed point precision + static const int PHIBSCALE = 16; + static const int PHIBSCALE_INT = 5; + static const int BITSCURV = 16; + static const int BITSPHI = 18; + static const int BITSPHIB = 17; // 12 bits *28 (+5 bits) + static const int BITSPARAM = 14; + static const int GAIN_0 = 9; + static const int GAIN_0INT = 6; + static const int GAIN_4 = 9; + static const int GAIN_4INT = 4; + static const int GAIN_V0 = 9; + static const int GAIN_V0INT = 0; + + static const int GAIN2_0 = 12; + static const int GAIN2_0INT = 6; + static const int GAIN2_1 = 12; + static const int GAIN2_1INT = 3; + static const int GAIN2_4 = 12; + static const int GAIN2_4INT = 4; + static const int GAIN2_5 = 12; + static const int GAIN2_5INT = 0; + //STUFF NOT USED IN THE FIRMWARE BUT ONLY FOR DEBUGGING + /////////////////////////////////////////////////////// + + bool useOfflineAlgo_; + std::vector mScatteringPhi_; + std::vector mScatteringPhiB_; + //point resolution for phi + double pointResolutionPhi_; + //point resolution for phiB + double pointResolutionPhiB_; + std::vector pointResolutionPhiBH_; + std::vector pointResolutionPhiBL_; + //double pointResolutionPhiB_; + //point resolution for vertex + double pointResolutionVertex_; + std::vector curvResolution1_; + std::vector curvResolution2_; + //Sorter + class StubSorter { + public: + StubSorter(uint sector) { sec_ = sector; } + + bool operator()(const l1t::MuonStubRef& a, const l1t::MuonStubRef& b) { + if (a->coord1() < b->coord1()) + return true; + return false; + } + + private: + int sec_; + }; + }; + +} // namespace Phase2L1GMT +#endif diff --git a/L1Trigger/Phase2L1GMT/interface/KMTFLUTs.h b/L1Trigger/Phase2L1GMT/interface/KMTFLUTs.h new file mode 100644 index 0000000000000..06bad605d4ea4 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/interface/KMTFLUTs.h @@ -0,0 +1,122 @@ +#ifndef L1Trigger_Phase2L1GMT_KMTFLUTS_h +#define L1Trigger_Phase2L1GMT_KMTFLUTS_h +#include +#include "TH1.h" +#include "TFile.h" +#include +#include "FWCore/ParameterSet/interface/FileInPath.h" + +namespace Phase2L1GMT { + + class KMTFLUTs { + public: + KMTFLUTs(const std::string &filename) { + edm::FileInPath path(filename); + lutFile_ = new TFile(path.fullPath().c_str()); + lut_[3 * 64 + 8] = (TH1 *)lutFile_->Get("gain_8_3"); + lut_[2 * 64 + 8] = (TH1 *)lutFile_->Get("gain_8_2"); + lut_[2 * 64 + 12] = (TH1 *)lutFile_->Get("gain_12_2"); + lut_[2 * 64 + 4] = (TH1 *)lutFile_->Get("gain_4_2"); + lut_[1 * 64 + 12] = (TH1 *)lutFile_->Get("gain_12_1"); + lut_[1 * 64 + 10] = (TH1 *)lutFile_->Get("gain_10_1"); + lut_[1 * 64 + 6] = (TH1 *)lutFile_->Get("gain_6_1"); + lut_[1 * 64 + 14] = (TH1 *)lutFile_->Get("gain_14_1"); + lut_[3] = (TH1 *)lutFile_->Get("gain_3_0"); + lut_[5] = (TH1 *)lutFile_->Get("gain_5_0"); + lut_[6] = (TH1 *)lutFile_->Get("gain_6_0"); + lut_[7] = (TH1 *)lutFile_->Get("gain_7_0"); + lut_[9] = (TH1 *)lutFile_->Get("gain_9_0"); + lut_[10] = (TH1 *)lutFile_->Get("gain_10_0"); + lut_[11] = (TH1 *)lutFile_->Get("gain_11_0"); + lut_[12] = (TH1 *)lutFile_->Get("gain_12_0"); + lut_[13] = (TH1 *)lutFile_->Get("gain_13_0"); + lut_[14] = (TH1 *)lutFile_->Get("gain_14_0"); + lut_[15] = (TH1 *)lutFile_->Get("gain_15_0"); + + lut2HH_[3 * 64 + 8] = (TH1 *)lutFile_->Get("gain2_8_3_HH"); + lut2HH_[2 * 64 + 8] = (TH1 *)lutFile_->Get("gain2_8_2_HH"); + lut2HH_[2 * 64 + 4] = (TH1 *)lutFile_->Get("gain2_4_2_HH"); + lut2HH_[1 * 64 + 8] = (TH1 *)lutFile_->Get("gain2_8_1_HH"); + lut2HH_[1 * 64 + 4] = (TH1 *)lutFile_->Get("gain2_4_1_HH"); + lut2HH_[1 * 64 + 2] = (TH1 *)lutFile_->Get("gain2_2_1_HH"); + + lut2LH_[3 * 64 + 8] = (TH1 *)lutFile_->Get("gain2_8_3_LH"); + lut2LH_[2 * 64 + 8] = (TH1 *)lutFile_->Get("gain2_8_2_LH"); + lut2LH_[2 * 64 + 4] = (TH1 *)lutFile_->Get("gain2_4_2_LH"); + lut2LH_[1 * 64 + 8] = (TH1 *)lutFile_->Get("gain2_8_1_LH"); + lut2LH_[1 * 64 + 4] = (TH1 *)lutFile_->Get("gain2_4_1_LH"); + lut2LH_[1 * 64 + 2] = (TH1 *)lutFile_->Get("gain2_2_1_LH"); + + lut2HL_[3 * 64 + 8] = (TH1 *)lutFile_->Get("gain2_8_3_HL"); + lut2HL_[2 * 64 + 8] = (TH1 *)lutFile_->Get("gain2_8_2_HL"); + lut2HL_[2 * 64 + 4] = (TH1 *)lutFile_->Get("gain2_4_2_HL"); + lut2HL_[1 * 64 + 8] = (TH1 *)lutFile_->Get("gain2_8_1_HL"); + lut2HL_[1 * 64 + 4] = (TH1 *)lutFile_->Get("gain2_4_1_HL"); + lut2HL_[1 * 64 + 2] = (TH1 *)lutFile_->Get("gain2_2_1_HL"); + + lut2LL_[3 * 64 + 8] = (TH1 *)lutFile_->Get("gain2_8_3_LL"); + lut2LL_[2 * 64 + 8] = (TH1 *)lutFile_->Get("gain2_8_2_LL"); + lut2LL_[2 * 64 + 4] = (TH1 *)lutFile_->Get("gain2_4_2_LL"); + lut2LL_[1 * 64 + 8] = (TH1 *)lutFile_->Get("gain2_8_1_LL"); + lut2LL_[1 * 64 + 4] = (TH1 *)lutFile_->Get("gain2_4_1_LL"); + lut2LL_[1 * 64 + 2] = (TH1 *)lutFile_->Get("gain2_2_1_LL"); + + coarseEta_ = (TH1 *)lutFile_->Get("coarseETALUT"); + } + + ~KMTFLUTs() { + lutFile_->Close(); + if (lutFile_ != nullptr) + delete lutFile_; + } + + std::vector trackGain(uint step, uint bitmask, uint K) { + std::vector gain(4, 0.0); + const TH1 *h = lut_[64 * step + bitmask]; + gain[0] = h->GetBinContent(K + 1); + gain[2] = h->GetBinContent(1024 + K + 1); + return gain; + } + + std::vector trackGain2(uint step, uint bitmask, uint K, uint qual1, uint qual2) { + std::vector gain(4, 0.0); + const TH1 *h; + if (qual1 < 6) { + if (qual2 < 6) + h = lut2LL_[64 * step + bitmask]; + else + h = lut2LH_[64 * step + bitmask]; + } else { + if (qual2 < 6) + h = lut2HL_[64 * step + bitmask]; + else + h = lut2HH_[64 * step + bitmask]; + } + gain[0] = h->GetBinContent(K + 1); + gain[1] = h->GetBinContent(512 + K + 1); + gain[2] = h->GetBinContent(2 * 512 + K + 1); + gain[3] = h->GetBinContent(3 * 512 + K + 1); + return gain; + } + + std::pair vertexGain(uint bitmask, uint K) { + const TH1 *h = lut_[bitmask]; + std::pair gain(-h->GetBinContent(K + 1), -h->GetBinContent(1024 + K + 1)); + return gain; + } + + uint coarseEta(uint mask) { + return uint((1 << 12) * coarseEta_->GetBinContent(coarseEta_->GetXaxis()->FindBin(mask)) / M_PI); + } + + TFile *lutFile_; + std::map lut_; + std::map lut2HH_; + std::map lut2LH_; + std::map lut2HL_; + std::map lut2LL_; + const TH1 *coarseEta_; + }; + +} // namespace Phase2L1GMT +#endif diff --git a/L1Trigger/Phase2L1GMT/interface/L1TPhase2GMTEndcapStubProcessor.h b/L1Trigger/Phase2L1GMT/interface/L1TPhase2GMTEndcapStubProcessor.h index a4402827fce10..aa4502b9d574d 100644 --- a/L1Trigger/Phase2L1GMT/interface/L1TPhase2GMTEndcapStubProcessor.h +++ b/L1Trigger/Phase2L1GMT/interface/L1TPhase2GMTEndcapStubProcessor.h @@ -25,7 +25,10 @@ class L1TPhase2GMTEndcapStubProcessor { const edm::EventSetup& iSetup); private: - l1t::MuonStub buildCSCOnlyStub(const CSCDetId&, const CSCCorrelatedLCTDigi&, const L1TMuon::GeometryTranslator*); + l1t::MuonStub buildCSCOnlyStub(const CSCDetId&, + const CSCCorrelatedLCTDigi&, + const L1TMuon::GeometryTranslator*, + unsigned int); l1t::MuonStub buildRPCOnlyStub(const RPCDetId&, const RPCDigi&, const L1TMuon::GeometryTranslator*); l1t::MuonStubCollection combineStubs(const l1t::MuonStubCollection&, const l1t::MuonStubCollection&); diff --git a/L1Trigger/Phase2L1GMT/plugins/PreTrackMatchedMuon.h b/L1Trigger/Phase2L1GMT/interface/PreTrackMatchedMuon.h similarity index 65% rename from L1Trigger/Phase2L1GMT/plugins/PreTrackMatchedMuon.h rename to L1Trigger/Phase2L1GMT/interface/PreTrackMatchedMuon.h index 26781736ad6e3..927e8f9f1cf82 100644 --- a/L1Trigger/Phase2L1GMT/plugins/PreTrackMatchedMuon.h +++ b/L1Trigger/Phase2L1GMT/interface/PreTrackMatchedMuon.h @@ -3,8 +3,8 @@ #include "FWCore/MessageLogger/interface/MessageLogger.h" #include "DataFormats/L1TMuonPhase2/interface/Constants.h" -#include "DataFormats/L1TMuon/interface/RegionalMuonCandFwd.h" #include "DataFormats/L1TMuonPhase2/interface/MuonStub.h" +#include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" #include "DataFormats/Common/interface/Ptr.h" #include "DataFormats/L1TrackTrigger/interface/TTTrack.h" #include "DataFormats/L1TrackTrigger/interface/TTStub.h" @@ -35,11 +35,12 @@ namespace Phase2L1GMT { beta_(beta), isGlobal_(false), quality_(0), - stubID0_(511), - stubID1_(511), - stubID2_(511), - stubID3_(511), - stubID4_(511), + stubID0_(4095), + stubID1_(4095), + stubID2_(4095), + stubID3_(4095), + stubID4_(4095), + matchMask_(0), valid_(false) {} const uint charge() const { return charge_; } @@ -61,6 +62,8 @@ namespace Phase2L1GMT { const uint stubID2() const { return stubID2_; } const uint stubID3() const { return stubID3_; } const uint stubID4() const { return stubID4_; } + const uint matchMask() const { return matchMask_; } + bool valid() const { return valid_; } void setQuality(uint quality) { quality_ = quality; } @@ -72,26 +75,29 @@ namespace Phase2L1GMT { offline_phi_ = phi; } - void addMuonRef(const l1t::RegionalMuonCandRef& ref) { - muRef_.push_back(ref); - isGlobal_ = true; - } + void addMuonRef(const l1t::SAMuonRef& ref) { muRef_.push_back(ref); } void resetGlobal() { isGlobal_ = false; } - const std::vector& muonRef() const { return muRef_; } - void addStub(const l1t::MuonStubRef& stub) { + const l1t::SAMuonRefVector& muonRef() const { return muRef_; } + void addStub(const l1t::MuonStubRef& stub, uint mask) { stubs_.push_back(stub); - if (stub->tfLayer() == 0) - stubID0_ = stub->id(); - else if (stub->tfLayer() == 1) - stubID1_ = stub->id(); - else if (stub->tfLayer() == 2) - stubID2_ = stub->id(); - else if (stub->tfLayer() == 3) - stubID3_ = stub->id(); - else if (stub->tfLayer() == 4) - stubID4_ = stub->id(); + if (stub->tfLayer() == 0) { + stubID0_ = stub->address(); + matchMask_ = matchMask_ | (mask); + } else if (stub->tfLayer() == 1) { + stubID1_ = stub->address(); + matchMask_ = matchMask_ | (mask << 2); + } else if (stub->tfLayer() == 2) { + stubID2_ = stub->address(); + matchMask_ = matchMask_ | (mask << 4); + } else if (stub->tfLayer() == 3) { + stubID3_ = stub->address(); + matchMask_ = matchMask_ | (mask << 6); + } else if (stub->tfLayer() == 4) { + stubID4_ = stub->address(); + matchMask_ = matchMask_ | (mask << 8); + } } const l1t::MuonStubRefVector& stubs() const { return stubs_; } @@ -109,27 +115,31 @@ namespace Phase2L1GMT { } uint64_t lsb() const { - uint64_t w = charge_ & 0x1; - w = w | (twos_complement(pt_, BITSPT) << 1); - w = w | (twos_complement(phi_, BITSPHI) << (BITSPT + 1)); - w = w | (twos_complement(eta_, BITSETA) << (BITSPHI + BITSPT + 1)); - w = w | (twos_complement(z0_, BITSZ0) << (BITSETA + BITSPHI + BITSPT + 1)); - w = w | (twos_complement(d0_, BITSD0) << (BITSZ0 + BITSETA + BITSPHI + BITSPT + 1)); - return w; + wordtype w = 0; + int bstart = 0; + bstart = wordconcat(w, bstart, charge_ & 0x1, 1); + bstart = wordconcat(w, bstart, pt_, BITSPT); + bstart = wordconcat(w, bstart, phi_, BITSPHI); + bstart = wordconcat(w, bstart, eta_, BITSETA); + bstart = wordconcat(w, bstart, z0_, BITSZ0); + bstart = wordconcat(w, bstart, d0_, BITSD0); + return w.to_int(); } uint64_t msb() const { - uint64_t w2 = 0; - w2 = twos_complement(stubID0_, BITSSTUBID); - w2 = w2 | (twos_complement(stubID1_, BITSSTUBID) << BITSSTUBID); - w2 = w2 | (twos_complement(stubID2_, BITSSTUBID) << (2 * BITSSTUBID)); - w2 = w2 | (twos_complement(stubID3_, BITSSTUBID) << (3 * BITSSTUBID)); - w2 = w2 | (twos_complement(stubID4_, BITSSTUBID) << (4 * BITSSTUBID)); - w2 = w2 | (twos_complement(isGlobal_, 1) << (5 * BITSSTUBID)); - w2 = w2 | (twos_complement(beta_, BITSMUONBETA) << (5 * BITSSTUBID + 1)); - w2 = w2 | (twos_complement(quality_, BITSMATCHQUALITY) << (BITSMUONBETA + 5 * BITSSTUBID + 1)); - w2 = w2 | (twos_complement(valid_, 1) << (BITSMATCHQUALITY + BITSMUONBETA + 5 * BITSSTUBID + 1)); - return w2; + wordtype w2 = 0; + int bstart = 0; + bstart = wordconcat(w2, bstart, stubID0_, BITSSTUBID); + bstart = wordconcat(w2, bstart, stubID1_, BITSSTUBID); + bstart = wordconcat(w2, bstart, stubID2_, BITSSTUBID); + bstart = wordconcat(w2, bstart, stubID3_, BITSSTUBID); + bstart = wordconcat(w2, bstart, stubID4_, BITSSTUBID); + bstart = wordconcat(w2, bstart, isGlobal_, 1); + bstart = wordconcat(w2, bstart, beta_, BITSMUONBETA); + bstart = wordconcat(w2, bstart, quality_, BITSMATCHQUALITY); + bstart = wordconcat(w2, bstart, valid_, 1); + + return w2.to_int(); } void printWord() const { @@ -157,9 +167,11 @@ namespace Phase2L1GMT { uint stubID2_; uint stubID3_; uint stubID4_; + uint matchMask_; + bool valid_; l1t::MuonStubRefVector stubs_; - std::vector muRef_; + l1t::SAMuonRefVector muRef_; edm::Ptr > trkPtr_; }; } // namespace Phase2L1GMT diff --git a/L1Trigger/Phase2L1GMT/interface/SAMuonCleaner.h b/L1Trigger/Phase2L1GMT/interface/SAMuonCleaner.h new file mode 100644 index 0000000000000..7ba695f225138 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/interface/SAMuonCleaner.h @@ -0,0 +1,24 @@ +#ifndef L1Trigger_Phase2L1GMT_SAMuonCleaner_h +#define L1Trigger_Phase2L1GMT_SAMuonCleaner_h + +#include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" + +class SAMuonCleaner { +public: + SAMuonCleaner() = default; + ~SAMuonCleaner() = default; + + std::vector cleanTFMuons(const std::vector& muons); + +private: + std::vector cleanTF(const std::vector& tfMuons); + void overlapCleanTrack(l1t::SAMuon& source, const l1t::SAMuon& other, bool eq); + void overlapCleanTrackInter(l1t::SAMuon& source, const l1t::SAMuon& other); + std::vector interTFClean(const std::vector& bmtf, + const std::vector& omtf, + const std::vector& emtf); + void swap(std::vector&, int i, int j); + void sort(std::vector& in); +}; + +#endif diff --git a/L1Trigger/Phase2L1GMT/interface/TPS.h b/L1Trigger/Phase2L1GMT/interface/TPS.h new file mode 100644 index 0000000000000..91f65f8620f8e --- /dev/null +++ b/L1Trigger/Phase2L1GMT/interface/TPS.h @@ -0,0 +1,30 @@ +#ifndef L1Trigger_Phase2L1GMT_TPS_h +#define L1Trigger_Phase2L1GMT_TPS_h +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "DataFormats/L1TMuonPhase2/interface/TrackerMuon.h" +#include "L1Trigger/Phase2L1GMT/interface/TrackConverter.h" +#include "L1Trigger/Phase2L1GMT/interface/TPSAlgorithm.h" +#include "L1Trigger/Phase2L1GMT/interface/Isolation.h" + +namespace Phase2L1GMT { + + class TPS { + public: + TPS(const edm::ParameterSet& iConfig); + ~TPS() = default; + std::vector processEvent(const std::vector >&, + const l1t::MuonStubRefVector&); + + private: + int verbose_; + std::unique_ptr tt_track_converter_; + std::unique_ptr tps_; + std::unique_ptr isolation_; + std::vector > associateTracksWithNonant( + const std::vector >& tracks, uint processor); + l1t::SAMuonRefVector associateMuonsWithNonant(const l1t::SAMuonRefVector&, uint); + l1t::MuonStubRefVector associateStubsWithNonant(const l1t::MuonStubRefVector&, uint); + }; +} // namespace Phase2L1GMT + +#endif diff --git a/L1Trigger/Phase2L1GMT/interface/TPSAlgorithm.h b/L1Trigger/Phase2L1GMT/interface/TPSAlgorithm.h new file mode 100644 index 0000000000000..bec3898fc1086 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/interface/TPSAlgorithm.h @@ -0,0 +1,77 @@ +#ifndef L1Trigger_Phase2GMT_TPSAlgorithm_h +#define L1Trigger_Phase2GMT_TPSAlgorithm_h + +#include "DataFormats/L1TrackTrigger/interface/TTTrack.h" +#include "DataFormats/L1TrackTrigger/interface/TTTrack_TrackWord.h" +#include "DataFormats/L1TrackTrigger/interface/TTTypes.h" +#include "DataFormats/L1TMuonPhase2/interface/MuonStub.h" +#include "DataFormats/L1TMuonPhase2/interface/TrackerMuon.h" +#include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" +#include "DataFormats/L1Trigger/interface/L1TObjComparison.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "L1Trigger/Phase2L1GMT/interface/ConvertedTTTrack.h" +#include "L1Trigger/Phase2L1GMT/interface/PreTrackMatchedMuon.h" +#include "L1Trigger/Phase2L1GMT/interface/TPSLUTs.h" +#include +#include + +namespace Phase2L1GMT { + + const unsigned int PHIDIVIDER = 1 << (BITSPHI - BITSSTUBCOORD); + const unsigned int ETADIVIDER = 1 << (BITSETA - BITSSTUBETA); + + typedef struct { + ap_int coord1; + ap_uint sigma_coord1; + ap_int coord2; + ap_uint sigma_coord2; + ap_int eta; + ap_uint sigma_eta1; + ap_uint sigma_eta2; + ap_uint<1> valid; + ap_uint<1> is_barrel; + } propagation_t; + + typedef struct { + ap_uint quality; + ap_uint id; + ap_uint<2> valid; + bool isGlobal; + l1t::SAMuonRef muRef; + l1t::MuonStubRef stubRef; + + } match_t; + + class TPSAlgorithm { + public: + TPSAlgorithm(const edm::ParameterSet& iConfig); + ~TPSAlgorithm(); + + std::vector processNonant(const std::vector& convertedTracks, + const l1t::MuonStubRefVector& stubs); + + std::vector cleanNeighbor(const std::vector& muons, + const std::vector& muonsPrevious, + const std::vector& muonsNext, + bool equality); + std::vector convert(std::vector& muons, uint maximum); + bool outputGT(std::vector& muons); + void SetQualityBits(std::vector& muons); + std::vector sort(std::vector& muons, uint maximum); + + private: + int verbose_; + propagation_t propagate(const ConvertedTTTrack& track, uint layer); + ap_uint deltaEta(const ap_int& eta1, const ap_int& eta2); + ap_uint deltaCoord(const ap_int& phi1, const ap_int& phi2); + match_t match(const propagation_t prop, const l1t::MuonStubRef& stub, uint trackID); + match_t propagateAndMatch(const ConvertedTTTrack& track, const l1t::MuonStubRef& stub, uint trackID); + match_t getBest(const std::vector matches); + PreTrackMatchedMuon processTrack(const ConvertedTTTrack&, const l1t::MuonStubRefVector&); + ap_uint<5> cleanMuon(const PreTrackMatchedMuon& mu, const PreTrackMatchedMuon& other, bool eq); + void matchingInfos(std::vector matchInfo, PreTrackMatchedMuon& muon, ap_uint& quality); + std::vector clean(std::vector& muons); + }; +} // namespace Phase2L1GMT + +#endif diff --git a/L1Trigger/Phase2L1GMT/plugins/Constants.h b/L1Trigger/Phase2L1GMT/interface/TPSLUTs.h similarity index 52% rename from L1Trigger/Phase2L1GMT/plugins/Constants.h rename to L1Trigger/Phase2L1GMT/interface/TPSLUTs.h index 9251abc3d0f0f..0db5b9b2d7c4a 100644 --- a/L1Trigger/Phase2L1GMT/plugins/Constants.h +++ b/L1Trigger/Phase2L1GMT/interface/TPSLUTs.h @@ -2,6 +2,7 @@ #define PHASE2L1GMT_PHASE2GMT_CONSTANTS #include "ap_int.h" +#include "DataFormats/L1TMuonPhase2/interface/Constants.h" namespace Phase2L1GMT { @@ -336,418 +337,593 @@ namespace Phase2L1GMT { 3182, 3183, 3184, 3185, 3186, 3187, 3187, 3188, 3189, 3190, 3191, 3192, 3193, 3194, 3194, 3194}; const ap_uint lt_prop_coord1_0[512] = { - 163, 163, 163, 163, 163, 163, 163, 163, 163, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, 165, 165, 164, 164, - 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, - 165, 166, 166, 166, 166, 166, 167, 167, 167, 166, 166, 166, 166, 166, 165, 165, 164, 164, 163, 163, 163, 162, 162, - 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, - 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 161, 161, 161, - 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 162, 162, 162, 162, 162, 162, 161, 161, 161, 161, 161, - 161, 161, 161, 161, 162, 162, 162, 162, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 162, 162, 162, 162, - 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 160, 160, 159, 159, - 158, 158, 157, 156, 155, 154, 154, 153, 152, 151, 149, 148, 147, 146, 145, 144, 142, 141, 140, 139, 137, 136, 135, - 133, 132, 131, 130, 128, 127, 126, 124, 123, 122, 121, 119, 118, 117, 116, 115, 113, 112, 111, 110, 109, 108, 107, - 105, 104, 103, 102, 101, 100, 99, 98, 98, 97, 96, 95, 94, 93, 93, 92, 91, 91, 90, 89, 89, 88, 88, - 87, 87, 87, 86, 86, 85, 85, 85, 84, 84, 83, 82, 82, 81, 81, 80, 80, 80, 79, 79, 78, 78, 78, - 77, 76, 76, 75, 75, 74, 73, 73, 72, 72, 71, 71, 71, 70, 70, 70, 69, 69, 68, 67, 67, 66, 65, - 65, 64, 64, 63, 63, 62, 62, 62, 61, 61, 61, 60, 60, 60, 59, 59, 58, 58, 58, 57, 57, 57, 56, - 56, 56, 56, 55, 55, 55, 55, 54, 54, 54, 54, 53, 53, 52, 52, 52, 51, 51, 50, 50, 49, 48, 48, - 47, 47, 47, 46, 46, 46, 46, 45, 45, 45, 45, 45, 45, 44, 44, 44, 43, 43, 43, 43, 42, 42, 42, - 42, 41, 41, 41, 41, 40, 40, 40, 40, 39, 39, 39, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38}; - + 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 100, 100, 100, 100, 100, 100, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98, 98, 98, 99, 99, 99, 99, + 99, 100, 100, 100, 100, 100, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 99, 99, 99, 99, 99, 99, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 98, 98, 98, 98, 98, 98, 98, 97, 97, 97, 97, 97, 97, 97, 96, 96, 96, 96, 96, 96, 96, + 96, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 94, 94, 94, 94, 93, 93, 93, 93, 93, 92, 92, 92, 92, 91, 91, 91, 90, 90, 89, 88, 88, 87, + 87, 86, 85, 85, 84, 84, 83, 82, 82, 81, 81, 80, 80, 79, 78, 78, 77, 77, 76, 75, 75, 74, 74, + 73, 72, 72, 71, 71, 70, 70, 69, 68, 68, 67, 67, 66, 65, 65, 64, 64, 63, 62, 62, 61, 61, 60, + 60, 59, 58, 58, 57, 57, 56, 55, 55, 54, 54, 53, 53, 53, 52, 52, 52, 51, 51, 51, 50, 50, 50, + 49, 49, 49, 48, 48, 48, 48, 47, 47, 47, 47, 46, 46, 46, 46, 45, 45, 45, 45, 44, 44, 43, 43, + 43, 42, 42, 42, 41, 41, 40, 40, 40, 39, 39, 38, 38, 38, 38, 37, 37, 37, 36, 36, 36, 36, 35, + 35, 35, 34, 34, 34, 34, 33, 33, 33, 33, 32, 32, 32, 32, 31, 31, 31, 31, 30, 30, 30, 30, 30, + 29, 29, 29, 29, 29, 29, 29, 28, 28, 28, 28, 28, 28, 28, 27, 27, 27, 27, 27, 27, 27, 26, 26, + 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 24, 24, 24, 23, 23, 23, 22, 22, 22, 22, 21, 21, 21, + 20, 20, 20, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18}; const ap_uint lt_prop_coord1_1[512] = { - 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, - 175, 175, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 177, 177, 178, 178, 179, 179, 179, 180, 180, - 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 182, 182, 182, 182, 182, 183, 183, 183, 184, 184, - 184, 184, 184, 184, 183, 183, 183, 183, 183, 183, 183, 183, 183, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, - 182, 182, 182, 182, 182, 182, 181, 181, 181, 181, 180, 180, 180, 180, 179, 179, 179, 179, 179, 179, 179, 179, 179, - 179, 179, 179, 179, 179, 179, 178, 178, 178, 178, 177, 177, 177, 176, 176, 176, 176, 175, 175, 175, 175, 175, 175, - 175, 174, 174, 174, 174, 174, 174, 174, 174, 174, 173, 173, 173, 172, 172, 172, 171, 170, 170, 169, 169, 169, 168, - 168, 168, 167, 167, 166, 165, 165, 164, 163, 162, 161, 160, 159, 158, 158, 157, 156, 156, 155, 154, 154, 153, 153, - 153, 152, 152, 152, 152, 151, 151, 151, 150, 150, 149, 149, 148, 147, 147, 146, 145, 144, 144, 143, 142, 142, 141, - 141, 140, 140, 139, 138, 138, 137, 136, 135, 134, 133, 131, 130, 129, 128, 127, 126, 125, 124, 124, 123, 123, 122, - 122, 122, 122, 121, 121, 121, 120, 120, 119, 118, 117, 116, 115, 114, 114, 113, 113, 112, 112, 112, 112, 111, 111, - 111, 110, 109, 109, 108, 108, 107, 106, 106, 105, 104, 103, 103, 102, 101, 100, 99, 98, 97, 95, 94, 94, 93, - 93, 92, 92, 93, 93, 93, 93, 94, 93, 93, 92, 92, 91, 90, 89, 88, 87, 86, 85, 85, 84, 84, 83, - 83, 82, 82, 81, 81, 80, 80, 79, 79, 78, 78, 78, 77, 77, 76, 76, 75, 75, 74, 74, 73, 73, 72, - 72, 71, 71, 71, 70, 70, 70, 70, 70, 69, 69, 69, 68, 68, 67, 67, 66, 66, 65, 64, 64, 63, 63, - 62, 62, 61, 61, 61, 60, 60, 60, 60, 59, 59, 58, 58, 57, 57, 56, 56, 55, 55, 54, 54, 54, 54, - 53, 53, 53, 53, 53, 52, 52, 52, 51, 51, 50, 50, 49, 49, 48, 48, 47, 47, 46, 46, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45}; - + 109, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 109, 109, 109, 109, 109, 109, 109, 109, + 109, 109, 109, 108, 108, 108, 108, 108, 108, 108, 108, 108, 107, 107, 107, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 106, 106, 106, 106, 106, 106, 106, + 106, 106, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 104, 104, 104, 104, 104, 104, 103, 103, 103, 103, 103, + 103, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 102, 102, 102, 101, 101, 101, 100, 100, 100, 99, 99, 99, 98, 98, 98, 97, 97, 96, 96, 95, 95, + 94, 94, 93, 93, 93, 92, 92, 91, 91, 90, 90, 89, 89, 88, 88, 87, 87, 86, 86, 85, 85, 84, 84, + 83, 83, 82, 82, 82, 81, 81, 81, 80, 80, 79, 79, 79, 78, 78, 78, 77, 77, 76, 76, 76, 75, 75, + 75, 74, 74, 74, 73, 73, 73, 72, 72, 72, 71, 71, 70, 70, 69, 69, 68, 68, 68, 67, 67, 66, 66, + 65, 65, 64, 64, 64, 63, 63, 62, 62, 62, 61, 61, 61, 60, 60, 60, 59, 59, 58, 58, 58, 57, 57, + 57, 56, 56, 55, 55, 55, 54, 54, 54, 53, 53, 52, 52, 52, 51, 51, 51, 51, 50, 50, 50, 49, 49, + 49, 49, 48, 48, 48, 47, 47, 47, 46, 46, 46, 46, 45, 45, 45, 44, 44, 44, 44, 43, 43, 43, 42, + 42, 42, 41, 41, 41, 40, 40, 40, 39, 39, 39, 38, 38, 38, 37, 37, 37, 37, 36, 36, 36, 36, 35, + 35, 35, 35, 34, 34, 34, 33, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32, 32, 32, 31, 31, 31, 31, + 31, 31, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30}; const ap_uint lt_prop_coord1_2[512] = { - 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 188, 188, 188, 188, 188, 188, 188, 188, 188, 187, 187, 187, 187, - 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 185, 185, 184, 183, 183, 183, 183, 183, 183, - 183, 183, 183, 183, 183, 183, 182, 182, 182, 181, 181, 181, 181, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, - 180, 180, 179, 179, 179, 179, 178, 178, 177, 177, 176, 175, 175, 174, 174, 174, 173, 173, 173, 173, 173, 173, 173, - 173, 173, 173, 172, 172, 172, 172, 172, 172, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 172, 172, - 172, 172, 172, 172, 172, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 172, 172, 172, 172, 172, 172, 172, 171, - 171, 171, 171, 171, 170, 170, 169, 169, 168, 168, 168, 167, 167, 166, 166, 166, 165, 164, 163, 162, 162, 161, 160, - 159, 158, 158, 158, 158, 158, 159, 159, 159, 160, 160, 160, 159, 158, 157, 156, 155, 154, 154, 153, 153, 153, 153, - 153, 153, 154, 154, 154, 154, 154, 153, 153, 152, 151, 150, 149, 147, 146, 145, 143, 142, 141, 140, 139, 139, 138, - 138, 138, 138, 138, 138, 137, 136, 136, 134, 133, 132, 131, 130, 129, 128, 128, 127, 127, 127, 126, 126, 126, 125, - 125, 124, 123, 123, 122, 121, 119, 118, 117, 115, 114, 113, 112, 111, 110, 110, 110, 109, 109, 110, 110, 109, 109, - 109, 108, 107, 106, 105, 104, 103, 103, 102, 102, 102, 102, 102, 102, 102, 101, 101, 100, 99, 98, 97, 95, 94, - 93, 93, 92, 91, 91, 91, 90, 90, 90, 89, 89, 89, 88, 88, 87, 87, 86, 85, 85, 84, 83, 82, 82, - 81, 81, 80, 80, 79, 79, 79, 78, 78, 77, 77, 76, 75, 75, 74, 73, 72, 72, 71, 71, 70, 70, 70, - 70, 69, 69, 69, 68, 68, 67, 67, 66, 66, 66, 65, 65, 65, 65, 64, 64, 63, 63, 62, 62, 61, 60, - 60, 59, 58, 58, 58, 57, 57, 57, 57, 57, 57, 56, 56, 55, 55, 54, 53, 52, 52, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 50, 50, 50, 49, 48, 48, 47, 47, 46, 46, 45, 45, 45, 45, 45, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46}; - + 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 118, 118, 118, 118, 118, + 118, 118, 118, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, + 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114, 114, 114, 114, 113, 113, 113, + 113, 113, 113, 113, 113, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 111, + 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 110, 110, 110, 110, 110, 110, 110, 109, + 109, 109, 109, 109, 109, 109, 108, 108, 108, 108, 107, 107, 107, 106, 106, 106, 105, 105, 105, 104, 104, 104, 104, + 103, 103, 103, 102, 102, 101, 101, 101, 100, 100, 100, 99, 99, 99, 98, 98, 98, 97, 97, 96, 96, 95, 95, + 94, 94, 93, 93, 92, 92, 91, 91, 90, 90, 89, 89, 88, 88, 87, 86, 86, 85, 85, 84, 84, 83, 83, + 82, 82, 81, 81, 81, 80, 80, 80, 79, 79, 79, 78, 78, 77, 77, 77, 76, 76, 75, 75, 74, 74, 73, + 73, 72, 72, 71, 71, 70, 70, 69, 69, 68, 68, 67, 67, 67, 66, 66, 66, 65, 65, 65, 64, 64, 64, + 64, 63, 63, 62, 62, 62, 61, 61, 60, 60, 59, 59, 59, 58, 58, 57, 57, 56, 56, 56, 55, 55, 54, + 54, 54, 53, 53, 53, 52, 52, 52, 51, 51, 51, 50, 50, 50, 50, 49, 49, 49, 48, 48, 48, 48, 47, + 47, 47, 47, 46, 46, 46, 45, 45, 45, 44, 44, 44, 43, 43, 42, 42, 42, 41, 41, 41, 40, 40, 40, + 39, 39, 39, 39, 38, 38, 38, 38, 37, 37, 37, 37, 36, 36, 36, 35, 35, 35, 35, 34, 34, 34, 33, + 33, 33, 32, 32, 32, 31, 31, 31, 30, 30, 30, 29, 29, 29, 28, 28, 28, 27, 27, 26, 26, 26, 25, + 25, 25, 24, 24, 24, 23, 23, 23, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22}; const ap_uint lt_prop_coord1_3[512] = { - 177, 177, 177, 177, 177, 177, 178, 178, 178, 179, 179, 179, 180, 180, 180, 181, 181, 181, 182, 182, 182, 182, 182, - 182, 182, 182, 182, 182, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 180, 180, 179, 179, 179, 178, 178, - 178, 178, 178, 178, 178, 178, 178, 178, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 178, 178, 178, 178, 179, - 179, 179, 179, 179, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 179, 179, - 179, 179, 179, 180, 180, 180, 180, 180, 180, 179, 179, 179, 178, 178, 177, 176, 176, 176, 175, 175, 175, 175, 174, - 174, 174, 174, 174, 173, 173, 173, 172, 172, 172, 172, 171, 171, 171, 170, 170, 170, 170, 169, 169, 169, 169, 168, - 168, 168, 167, 167, 167, 167, 166, 166, 166, 166, 165, 165, 165, 164, 164, 164, 163, 163, 163, 162, 162, 162, 161, - 161, 161, 160, 160, 160, 159, 159, 159, 158, 158, 158, 157, 157, 157, 156, 156, 155, 155, 155, 154, 154, 153, 153, - 152, 152, 152, 151, 151, 150, 150, 149, 149, 148, 147, 147, 146, 145, 144, 143, 142, 141, 141, 140, 139, 138, 138, - 137, 137, 136, 136, 135, 135, 134, 134, 133, 133, 132, 132, 131, 130, 129, 129, 128, 127, 126, 125, 125, 124, 123, - 123, 122, 121, 121, 120, 119, 119, 118, 117, 116, 115, 115, 114, 113, 113, 112, 112, 112, 111, 111, 111, 111, 110, - 109, 109, 108, 107, 106, 105, 104, 104, 103, 103, 103, 102, 102, 102, 102, 102, 101, 101, 100, 100, 99, 98, 98, - 97, 96, 95, 95, 94, 93, 93, 92, 92, 91, 91, 90, 90, 90, 89, 89, 88, 88, 87, 86, 85, 84, 84, - 83, 82, 81, 81, 80, 80, 79, 79, 78, 78, 78, 78, 77, 77, 76, 76, 76, 75, 74, 74, 73, 72, 72, - 71, 70, 70, 70, 69, 69, 69, 69, 69, 69, 69, 68, 68, 67, 66, 66, 65, 64, 64, 63, 63, 63, 62, - 62, 62, 61, 61, 61, 61, 60, 60, 60, 59, 59, 59, 58, 58, 57, 57, 56, 55, 55, 55, 54, 54, 54, - 54, 54, 54, 54, 54, 53, 53, 53, 52, 52, 51, 50, 50, 49, 49, 49, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48}; - + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 118, 118, 118, 118, + 118, 118, 118, 118, 118, 118, 118, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 117, 117, 117, 117, 117, 117, 117, 117, + 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 116, 116, 116, 116, 116, 116, 116, 116, 116, 115, + 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 113, 113, 113, 112, 112, 112, 112, 111, 111, 111, 111, 110, 110, 110, 110, 109, 109, 109, 109, 108, 108, 108, + 108, 107, 107, 107, 107, 106, 106, 106, 106, 105, 105, 105, 105, 104, 104, 104, 104, 103, 103, 103, 103, 102, 102, + 102, 102, 101, 101, 101, 101, 100, 100, 100, 100, 99, 99, 99, 99, 98, 98, 98, 97, 97, 96, 96, 95, 95, + 94, 94, 94, 93, 93, 92, 92, 91, 91, 90, 90, 89, 89, 88, 88, 88, 87, 87, 86, 86, 85, 85, 84, + 84, 83, 83, 83, 82, 82, 81, 81, 81, 80, 80, 79, 79, 79, 78, 78, 78, 77, 77, 76, 76, 76, 75, + 75, 75, 74, 74, 73, 73, 73, 72, 72, 72, 71, 71, 71, 70, 70, 69, 69, 69, 68, 68, 68, 67, 67, + 67, 66, 66, 66, 65, 65, 64, 63, 63, 62, 62, 61, 61, 60, 60, 59, 58, 58, 57, 57, 56, 56, 56, + 56, 55, 55, 55, 55, 54, 54, 54, 54, 53, 53, 53, 53, 52, 52, 52, 51, 51, 51, 50, 50, 50, 49, + 49, 49, 48, 48, 48, 48, 47, 47, 47, 46, 46, 46, 46, 45, 45, 45, 44, 44, 44, 44, 43, 43, 43, + 42, 42, 42, 42, 41, 41, 41, 40, 40, 40, 40, 39, 39, 39, 38, 38, 38, 38, 37, 37, 37, 36, 36, + 36, 35, 35, 35, 35, 34, 34, 34, 33, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32, 32, 32, 31, 31, + 31, 31, 31, 31, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30}; const ap_uint lt_prop_coord1_4[512] = { - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 165, 165, 165, 165, 165, 165, 164, 164, 164, 164, 164, - 163, 163, 163, 163, 163, 162, 162, 162, 161, 161, 160, 160, 159, 159, 158, 158, 157, 157, 157, 156, 156, 155, 155, - 155, 155, 154, 154, 154, 154, 153, 153, 152, 152, 151, 150, 149, 148, 147, 146, 144, 143, 142, 140, 139, 138, 137, - 135, 134, 133, 132, 131, 131, 130, 129, 128, 127, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 116, - 115, 114, 113, 113, 112, 111, 111, 110, 109, 108, 108, 107, 106, 106, 105, 104, 104, 103, 103, 103, 102, 102, 101, - 101, 100, 100, 99, 99, 98, 98, 97, 97, 97, 96, 96, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95}; - + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 112, 112, 112, 111, 111, 111, 110, 110, 110, 109, 109, 109, 108, 108, 107, + 107, 107, 106, 106, 106, 105, 105, 105, 105, 104, 104, 104, 104, 104, 103, 103, 103, 103, 102, 102, 102, 102, 101, + 101, 100, 100, 99, 99, 98, 97, 97, 96, 95, 95, 94, 94, 93, 92, 92, 91, 91, 91, 90, 90, 89, 89, + 88, 88, 88, 87, 87, 86, 86, 85, 85, 84, 84, 83, 83, 82, 82, 81, 81, 80, 80, 79, 79, 78, 78, + 77, 77, 76, 76, 76, 75, 75, 75, 74, 74, 74, 73, 73, 73, 72, 72, 72, 71, 71, 70, 70, 70, 69, + 69, 69, 68, 68, 67, 67, 67, 66, 66, 66, 65, 65, 64, 64, 64, 63, 63, 63, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62}; const ap_uint lt_prop_coord2_0[512] = { - 203, 203, 203, 203, 203, 203, 203, 203, 204, 204, 205, 205, 206, 207, 208, 208, 209, 210, 211, 212, 212, 213, 213, - 214, 214, 215, 215, 215, 216, 216, 216, 217, 217, 217, 218, 219, 219, 220, 221, 222, 222, 223, 224, 225, 226, 226, - 226, 227, 227, 227, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, - 226, 226, 226, 225, 225, 225, 225, 225, 225, 225, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 223, 223, 223, 223, 222, 222, 222, 222, 222, 222, 222, 223, 223, 223, 223, 223, 223, 223, 223, 222, 222, 221, 221, - 220, 219, 219, 218, 217, 217, 216, 215, 214, 214, 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 204, 203, 202, - 202, 201, 201, 201, 200, 200, 199, 198, 198, 197, 195, 194, 192, 190, 188, 185, 183, 181, 179, 178, 176, 175, 174, - 172, 171, 170, 169, 168, 166, 165, 164, 162, 161, 159, 158, 156, 155, 153, 152, 150, 149, 147, 146, 145, 144, 143, - 142, 141, 140, 140, 139, 138, 137, 136, 136, 135, 134, 133, 133, 132, 131, 130, 129, 129, 128, 127, 126, 126, 125, - 124, 123, 123, 122, 121, 121, 120, 119, 118, 118, 117, 116, 116, 115, 114, 114, 113, 113, 112, 111, 111, 110, 110, - 109, 109, 108, 107, 107, 106, 106, 105, 105, 104, 104, 104, 103, 103, 102, 102, 101, 101, 101, 100, 100, 100, 99, - 99, 99, 99, 98, 98, 98, 97, 97, 97, 96, 96, 96, 95, 95, 94, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93}; + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 93, 93, 93, 93, 93, 93, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 93, 93, 93, 93, 93, 92, 92, 92, 92, 92, 92, 91, 91, 91, 91, 91, 91, + 90, 90, 90, 90, 90, 90, 90, 89, 89, 89, 89, 89, 89, 88, 88, 88, 87, 87, 87, 86, 86, 86, 85, 85, 85, 85, 84, + 84, 84, 84, 84, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 82, 82, 82, 82, 82, 81, 81, 81, 80, 80, 80, 79, 79, + 79, 78, 78, 78, 77, 77, 76, 76, 75, 75, 74, 74, 74, 73, 73, 72, 72, 71, 71, 70, 70, 69, 69, 69, 69, 69, 69, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65}; const ap_uint lt_prop_coord2_1[512] = { - 148, 148, 148, 148, 148, 149, 149, 149, 149, 149, 149, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, - 150, 150, 150, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 150, 150, 150, 151, 151, 151, 151, 151, 151, - 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, - 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 152, 152, 152, 152, 152, 152, 152, 152, 152, - 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, - 154, 154, 154, 154, 154, 154, 154, 155, 155, 155, 155, 155, 155, 155, 155, 154, 154, 154, 154, 154, 154, 155, 155, - 155, 155, 155, 154, 154, 154, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 152, - 152, 152, 152, 151, 151, 150, 150, 150, 149, 148, 148, 147, 147, 146, 145, 145, 144, 143, 143, 142, 141, 141, 140, - 140, 139, 138, 138, 137, 137, 136, 136, 135, 134, 133, 133, 132, 131, 130, 129, 127, 126, 125, 124, 123, 123, 122, - 122, 121, 121, 121, 120, 120, 119, 119, 118, 117, 116, 115, 114, 113, 112, 112, 112, 112, 112, 112, 111, 111, 111, - 111, 110, 109, 108, 107, 107, 106, 105, 104, 104, 103, 103, 102, 102, 101, 100, 100, 99, 98, 97, 96, 96, 95, - 94, 94, 93, 93, 93, 92, 92, 92, 91, 91, 90, 90, 89, 89, 88, 88, 87, 86, 86, 85, 85, 84, 83, - 83, 82, 82, 82, 81, 81, 80, 80, 80, 79, 79, 78, 78, 77, 77, 76, 76, 75, 75, 74, 74, 73, 73, - 72, 72, 71, 71, 71, 70, 70, 70, 70, 70, 69, 69, 69, 69, 68, 68, 68, 67, 67, 66, 66, 65, 65, - 64, 63, 63, 62, 62, 61, 61, 61, 60, 60, 59, 59, 58, 58, 57, 56, 56, 55, 55, 54, 54, 54, 54, - 54, 54, 54, 54, 53, 53, 53, 52, 52, 51, 51, 50, 50, 49, 48, 48, 47, 47, 46, 46, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45}; - + 67, 67, 67, 68, 68, 68, 68, 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, + 65, 65, 65, 64, 64, 64, 64, 64, 64, 63, 63, 63, 63, 63, 62, 62, 62, 62, 61, 61, 61, 61, 60, 60, + 60, 60, 60, 60, 60, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 58, 58, 57, 57, 57, 57, 56, 56, 56, + 55, 55, 55, 55, 54, 54, 54, 53, 53, 53, 53, 53, 52, 52, 52, 52, 52, 51, 51, 51, 51, 51, 50, 50, + 50, 50, 49, 49, 49, 49, 49, 76, 104, 104, 104, 103, 103, 103, 103, 102, 102, 102, 102, 101, 101, 101, 101, 100, + 100, 100, 100, 99, 99, 99, 99, 98, 98, 97, 97, 97, 96, 96, 95, 95, 94, 94, 93, 93, 92, 92, 92, 91, + 91, 90, 90, 89, 89, 88, 88, 87, 87, 86, 86, 85, 85, 84, 83, 83, 83, 82, 82, 82, 81, 81, 80, 80, + 80, 79, 79, 79, 78, 78, 78, 77, 77, 76, 76, 76, 75, 75, 75, 74, 74, 73, 73, 73, 72, 72, 71, 71, + 71, 70, 70, 70, 69, 69, 68, 68, 68, 67, 67, 67, 66, 66, 66, 65, 65, 65, 64, 64, 64, 63, 63, 63, + 62, 62, 62, 61, 61, 61, 61, 60, 60, 59, 58, 58, 57, 57, 56, 56, 55, 55, 54, 53, 53, 52, 52, 51, + 51, 51, 51, 50, 50, 50, 50, 50, 49, 49, 49, 49, 49, 48, 48, 48, 48, 47, 47, 47, 46, 46, 46, 46, + 45, 45, 45, 44, 44, 44, 43, 43, 43, 43, 42, 42, 42, 41, 41, 41, 40, 40, 40, 40, 39, 39, 39, 38, + 38, 38, 38, 37, 37, 37, 37, 37, 36, 36, 36, 36, 36, 35, 35, 35, 35, 35, 34, 34, 34, 34, 34, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33}; const ap_uint lt_prop_coord2_2[512] = { - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 78, 78, 78, 78, 78, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 76, 76, 76, 76, 75, 75, 74, 73, 73, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 74, 74, 74, 74, 74, - 74, 73, 72, 72, 71, 70, 69, 69, 68, 68, 68, 68, 68, 68, 68, 67, 67, 67, 66, 66, 66, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 66, - 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, 68, 68, 68, 68, 68, 69, 69, 69, 69, 68, 68, 67, - 67, 66, 66, 65, 65, 66, 67, 69, 72, 75, 79, 84, 89, 95, 101, 107, 114, 120, 127, 133, 139, 144, 149, - 154, 158, 161, 163, 165, 165, 165, 165, 164, 163, 162, 160, 160, 159, 158, 158, 158, 158, 157, 157, 157, 157, 158, - 158, 158, 158, 158, 158, 158, 157, 157, 157, 156, 156, 155, 154, 152, 151, 149, 147, 145, 143, 142, 140, 139, 138, - 137, 136, 135, 134, 134, 133, 133, 132, 131, 131, 130, 129, 129, 128, 127, 126, 126, 125, 124, 124, 123, 123, 122, - 122, 121, 121, 120, 120, 119, 118, 118, 117, 116, 115, 113, 112, 111, 110, 109, 109, 108, 107, 107, 107, 107, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108}; - + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 35, 35, 35, 35, 35, 35, 35, 35, 35, 34, 34, 34, 34, 34, 34, 33, 33, 33, 33, 33, 33, 32, + 32, 32, 32, 32, 32, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 71, 111, + 110, 110, 110, 109, 109, 109, 108, 108, 108, 107, 107, 107, 106, 106, 106, 105, 105, 105, 104, 104, 104, 103, 103, + 103, 102, 102, 101, 101, 101, 100, 100, 100, 99, 99, 98, 98, 98, 97, 97, 96, 96, 96, 95, 95, 94, 94, + 93, 93, 92, 92, 91, 91, 90, 90, 89, 89, 88, 88, 87, 87, 86, 86, 85, 85, 84, 84, 83, 83, 82, + 82, 82, 81, 81, 80, 80, 80, 79, 79, 78, 78, 78, 77, 77, 76, 76, 76, 75, 75, 75, 74, 74, 74, + 73, 73, 73, 72, 72, 72, 71, 71, 71, 70, 70, 70, 69, 69, 69, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68}; const ap_uint lt_prop_coord2_3[512] = { - 25, 25, 25, 25, 25, 25, 24, 24, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 24, 24, 24, 24, - 24, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 22, 22, 22, 22, 21, 21, 21, 21, 21, 21, 21, 22, 22, 23, 23, 23, - 23, 23, 23, 22, 21, 20, 20, 19, 18, 18, 17, 17, 17, 18, 18, 19, 20, 21, 22, 23, 24, 26, 27, - 28, 30, 32, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 58, 60, 62, 65, 67, 70, 72, 74, - 77, 79, 82, 84, 86, 89, 91, 94, 96, 98, 101, 103, 105, 107, 110, 112, 114, 116, 118, 120, 122, 124, 125, - 127, 129, 130, 132, 133, 134, 136, 137, 138, 139, 140, 141, 141, 142, 142, 143, 143, 143, 143, 142, 142, 141, 140, - 139, 138, 136, 135, 134, 133, 132, 131, 131, 130, 130, 129, 129, 129, 128, 128, 127, 127, 127, 126, 125, 124, 124, - 123, 122, 120, 119, 118, 117, 116, 115, 114, 114, 113, 112, 112, 111, 111, 111, 111, 111, 111, 111, 111, 111, 110, - 110, 109, 109, 108, 107, 106, 105, 104, 103, 103, 102, 101, 100, 99, 99, 98, 97, 97, 96, 96, 95, 94, 94, - 93, 93, 92, 91, 91, 90, 89, 89, 88, 88, 88, 87, 87, 87, 86, 86, 86, 86, 85, 85, 84, 84, 84, - 83, 82, 82, 81, 81, 80, 79, 79, 78, 78, 78, 77, 77, 76, 76, 76, 75, 75, 75, 74, 74, 73, 72, - 72, 72, 71, 71, 71, 71, 70, 70, 70, 70, 69, 69, 69, 68, 68, 67, 66, 66, 65, 64, 63, 63, 62, - 62, 61, 61, 60, 60, 60, 59, 59, 59, 59, 59, 58, 58, 58, 57, 57, 57, 56, 56, 56, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 54, 54, 54, 53, 53, 52, 51, 50, 49, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47}; - + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 18, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 64, 109, 108, 108, 108, 107, 107, 106, 106, 106, 105, 105, 105, 104, 104, 103, 103, + 103, 102, 102, 102, 101, 101, 100, 100, 100, 99, 99, 98, 98, 98, 97, 97, 97, 96, 96, 95, 95, 95, 94, + 94, 94, 93, 93, 92, 92, 92, 91, 91, 90, 90, 90, 89, 89, 88, 88, 87, 87, 86, 86, 85, 85, 84, + 84, 84, 83, 83, 82, 82, 82, 81, 81, 80, 80, 80, 79, 79, 78, 78, 78, 77, 77, 76, 76, 76, 75, + 75, 75, 74, 74, 74, 73, 73, 73, 72, 72, 72, 71, 71, 70, 70, 70, 69, 69, 68, 68, 67, 67, 67, + 66, 66, 65, 65, 65, 64, 64, 63, 63, 63, 62, 62, 61, 61, 61, 60, 60, 59, 59, 59, 58, 58, 58, + 57, 57, 57, 56, 56, 56, 55, 55, 55, 55, 54, 54, 54, 53, 53, 53, 52, 52, 52, 51, 51, 50, 50, + 50, 49, 49, 49, 48, 48, 48, 47, 47, 47, 47, 46, 46, 46, 46, 45, 45, 45, 44, 44, 44, 44, 43, + 43, 43, 42, 42, 42, 42, 41, 41, 41, 40, 40, 40, 40, 39, 39, 39, 38, 38, 38, 38, 37, 37, 37, + 36, 36, 36, 36, 35, 35, 35, 35, 34, 34, 34, 33, 33, 33, 33, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32}; const ap_uint lt_prop_coord2_4[512] = { - 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 172, 172, 171, 171, 171, 170, 170, 170, 169, 169, 169, 168, - 168, 167, 167, 166, 166, 165, 164, 164, 163, 162, 161, 160, 160, 159, 158, 157, 156, 156, 155, 154, 153, 152, 152, - 151, 150, 149, 149, 148, 147, 146, 146, 145, 144, 144, 143, 142, 141, 141, 140, 139, 139, 138, 137, 136, 136, 135, - 134, 133, 133, 132, 131, 130, 130, 129, 128, 128, 127, 126, 126, 125, 124, 123, 122, 121, 120, 119, 119, 118, 117, - 116, 116, 115, 115, 114, 113, 113, 112, 111, 111, 110, 109, 108, 108, 107, 106, 106, 105, 104, 104, 103, 103, 103, - 102, 102, 102, 102, 101, 101, 101, 100, 100, 100, 99, 98, 97, 96, 95, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93}; + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 113, 113, 113, 113, 112, 112, 112, 111, 111, 111, 111, 110, 110, 110, 109, 109, 109, + 109, 108, 108, 108, 107, 107, 107, 106, 106, 106, 106, 105, 105, 105, 104, 104, 104, 103, 103, 103, 102, 102, 102, + 101, 101, 100, 100, 99, 98, 98, 97, 97, 96, 95, 95, 94, 94, 93, 93, 92, 92, 91, 91, 91, 90, 90, + 90, 89, 89, 88, 88, 88, 87, 87, 86, 86, 85, 85, 84, 84, 83, 83, 82, 81, 81, 80, 80, 79, 79, + 78, 78, 77, 77, 76, 76, 76, 75, 75, 75, 74, 74, 73, 73, 73, 72, 72, 72, 71, 71, 71, 70, 70, + 69, 69, 69, 68, 68, 67, 67, 67, 66, 66, 65, 65, 65, 65, 64, 64, 64, 63, 63, 63, 63, 62, 62, + 62, 62, 61, 61, 61, 61, 60, 60, 60, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59}; const ap_uint lt_res0_coord1_0[512] = { - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; - + 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; const ap_uint lt_res0_coord1_1[512] = { - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; - + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; const ap_uint lt_res0_coord1_2[512] = { - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; - + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14}; const ap_uint lt_res0_coord1_3[512] = { - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, - 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; - + 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, + 15, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}; const ap_uint lt_res0_coord1_4[512] = { - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; - + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}; const ap_uint lt_res0_coord2_0[512] = { - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}; - + 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, + 17, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 22, 23, 24, 24, 25, 26, 27, 27, 28, 29, 29, 30, 31, + 31, 32, 33, 33, 34, 35, 36, 36, 36, 36, 36, 35, 34, 34, 33, 32, 31, 31, 30, 29, 29, 28, 27, 27, 26, 25, 25, + 24, 23, 23, 22, 21, 21, 20, 19, 19, 18, 17, 16, 16, 16, 17, 18, 19, 21, 22, 24, 25, 26, 28, 29, 31, 32, 34, + 35, 36, 38, 39, 41, 42, 43, 45, 46, 48, 49, 51, 52, 53, 55, 56, 58, 59, 59, 60, 59, 59, 58, 57, 57, 56, 55, + 55, 54, 53, 53, 52, 51, 51, 50, 49, 49, 48, 47, 47, 46, 45, 45, 44, 43, 43, 42, 41, 41, 40, 39, 39, 38, 37, + 37, 36, 35, 35, 34, 33, 33, 32, 31, 31, 30, 29, 29, 28, 27, 27, 26, 25, 25, 24, 23, 23, 22, 22, 21, 20, 20, + 19, 18, 18, 17, 16, 16, 15, 14, 14, 13, 12, 12, 11, 10, 10, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}; const ap_uint lt_res0_coord2_1[512] = { - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; - + 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, + 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 22, 22, 22, 22, 22, 22, 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 18, 19, 19, + 19, 20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 27, 28, 28, 29, 30, 30, 31, 31, 32, 33, 33, 34, 35, 35, + 36, 36, 37, 37, 37, 36, 36, 35, 34, 34, 33, 32, 32, 31, 30, 30, 29, 28, 28, 27, 27, 26, 25, 25, 24, 23, 23, + 22, 21, 21, 20, 19, 19, 18, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, + 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, 20, 20, + 19, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17}; const ap_uint lt_res0_coord2_2[512] = { - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; - + 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 21, 21, 21, 21, 20, 20, 20, 20, 19, 19, 19, 19, 18, 18, + 18, 18, 17, 17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20}; const ap_uint lt_res0_coord2_3[512] = { - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; - + 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 16, 16, + 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, + 28, 27, 27, 26, 26, 25, 25, 24, 24, 23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16, 16, 15, 15, + 14, 14, 13, 13, 13, 14, 15, 15, 16, 17, 17, 18, 18, 19, 20, 20, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 27, + 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 32, 32, 32, 32, 31, 31, 31, 30, 30, 30, 30, 29, 29, 29, 29, 28, 28, + 28, 27, 27, 27, 27, 26, 26, 26, 25, 25, 25, 25, 24, 24, 24, 24, 23, 23, 23, 22, 22, 22, 22, 21, 21, 21, 21, + 20, 20, 20, 19, 19, 19, 19, 18, 18, 18, 17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17}; const ap_uint lt_res0_coord2_4[512] = { - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19}; + + const ap_uint lt_res1_coord1_0[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + const ap_uint lt_res1_coord1_1[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; + const ap_uint lt_res1_coord1_2[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; + const ap_uint lt_res1_coord1_3[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; + const ap_uint lt_res1_coord1_4[512] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + const ap_uint lt_res1_coord2_0[512] = { + 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, + 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 5, 5, 5, 5, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; + const ap_uint lt_res1_coord2_1[512] = { + 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; + const ap_uint lt_res1_coord2_2[512] = { + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, + 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + const ap_uint lt_res1_coord2_3[512] = { + 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, + 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; + const ap_uint lt_res1_coord2_4[512] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; const ap_uint lt_res0_eta1_0[512] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, @@ -909,206 +1085,6 @@ namespace Phase2L1GMT { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}; - ////shift those by 24 - const ap_uint lt_res1_coord1_0[512] = { - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, - 5, 5, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, - 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, - 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 5, 5, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; - - const ap_uint lt_res1_coord1_1[512] = { - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, - 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, - 12, 12, 13, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 18, 18, 18, - 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 14, 14, 14, 14, 13, 13, 13, 13, 12, - 12, 12, 12, 11, 11, 11, 10, 10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 6, 6, 6, 6, - 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, - 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - const ap_uint lt_res1_coord1_2[512] = { - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; - - const ap_uint lt_res1_coord1_3[512] = { - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, - 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9, - 9, 9, 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 5, - 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; - - const ap_uint lt_res1_coord1_4[512] = { - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; - - const ap_uint lt_res1_coord2_0[512] = { - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, - 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - - const ap_uint lt_res1_coord2_1[512] = { - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, - 8, 8, 8, 8, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}; - - const ap_uint lt_res1_coord2_2[512] = { - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, - 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, - 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 13, 13, 13, 12, 12, 11, 11, 10, 9, 8, 8, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; - - const ap_uint lt_res1_coord2_3[512] = { - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 6, 6, 5, - 5, 5, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, - 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; - - const ap_uint lt_res1_coord2_4[512] = { - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, - 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, - 13, 13, 12, 12, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, - 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, - 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}; const ap_uint lt_res1_eta_0[512] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -1194,18 +1170,6 @@ namespace Phase2L1GMT { 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; - // const ap_uint<8> lt_tpsID[256] = { - // 40, 56, 64, 88, 64, 32, 60, 56, 56, 56, 56, 56, 56, 56, 56, 56, 28, 56, 56, 54, 36, 36, 36, 36, 36, 36, - // 36, 36, 32, 28, 28, 28, 28, 52, 56, 52, 52, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 28, 56, 52, 52, - // 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 28, 52, 36, 36, 36, 36, 36, 36, 36, 36, 56, 56, 36, 56, - // 36, 36, 28, 60, 60, 60, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 28, 120, 120, 120, 92, 92, 64, 64, - // 64, 64, 64, 64, 64, 64, 64, 64, 28, 120, 152, 128, 100, 124, 80, 80, 64, 100, 64, 64, 64, 64, 64, 64, 28, 88, - // 92, 64, 92, 60, 60, 60, 92, 60, 60, 60, 60, 60, 60, 60, 36, 88, 88, 64, 64, 60, 60, 60, 60, 60, 60, 60, - // 92, 92, 92, 92, 28, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 28, 92, 92, 92, 92, 92, - // 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 28, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, - // 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - // 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}; - // NEW LUT with Low Pt (Bin 0, Pt<8 GeV) increased quality requirement. WP95. No changes for Pt>8 const ap_uint<8> lt_tpsID[256] = { 59, 56, 64, 88, 64, 32, 60, 56, 56, 56, 56, 56, 56, 56, 56, 56, 33, 56, 56, 54, 36, 36, 36, 36, 36, 36, @@ -1220,4 +1184,5 @@ namespace Phase2L1GMT { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}; } // namespace Phase2L1GMT + #endif diff --git a/L1Trigger/Phase2L1GMT/plugins/TopologicalAlgorithm.h b/L1Trigger/Phase2L1GMT/interface/TopologicalAlgorithm.h similarity index 100% rename from L1Trigger/Phase2L1GMT/plugins/TopologicalAlgorithm.h rename to L1Trigger/Phase2L1GMT/interface/TopologicalAlgorithm.h diff --git a/L1Trigger/Phase2L1GMT/interface/TrackConverter.h b/L1Trigger/Phase2L1GMT/interface/TrackConverter.h new file mode 100644 index 0000000000000..a12a2a5ed213f --- /dev/null +++ b/L1Trigger/Phase2L1GMT/interface/TrackConverter.h @@ -0,0 +1,52 @@ +#ifndef L1Trigger_Phase2L1GMT_TrackConverter_h +#define L1Trigger_Phase2L1GMT_TrackConverter_h + +#include "L1Trigger/Phase2L1GMT/interface/ConvertedTTTrack.h" +#include "L1Trigger/Phase2L1GMT/interface/TPSLUTs.h" +#include "DataFormats/L1TMuonPhase2/interface/TrackerMuon.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +namespace Phase2L1GMT { + + class TrackConverter { + public: + TrackConverter(const edm::ParameterSet& iConfig); + ~TrackConverter() = default; + + std::vector convertTracks(const std::vector >& tracks); + + private: + int verbose_; + typedef ap_uint<96> wordtype; + + uint generateQuality(const edm::Ptr >& track) { return 1; } + + uint ptLookup(uint absCurv) { + for (auto i : ptShifts) { + if (absCurv >= uint(i[0]) && absCurv < uint(i[1])) { + if (i[2] < 0) + return i[4]; + else + return (absCurv >> i[2]) + i[3]; + } + } + return 0; + } + + uint etaLookup(uint absTanL) { + for (auto i : etaShifts) { + if (absTanL >= uint(i[0]) && absTanL < uint(i[1])) { + if (i[2] < 0) + return i[4]; + else + return (absTanL >> i[2]) + i[3]; + } + } + return 0; + } + + ConvertedTTTrack convert(const edm::Ptr >& track); + }; +} // namespace Phase2L1GMT + +#endif diff --git a/L1Trigger/Phase2L1GMT/plugins/MuonROI.h b/L1Trigger/Phase2L1GMT/plugins/MuonROI.h deleted file mode 100644 index f0d0989af6f92..0000000000000 --- a/L1Trigger/Phase2L1GMT/plugins/MuonROI.h +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef PHASE2GMT_MUONROI -#define PHASE2GMT_MUONROI -#include -#include "DataFormats/L1TMuonPhase2/interface/Constants.h" -#include "DataFormats/L1TMuonPhase2/interface/MuonStub.h" -#include "DataFormats/L1TMuon/interface/RegionalMuonCand.h" -#include "DataFormats/L1TMuon/interface/RegionalMuonCandFwd.h" -#include "DataFormats/L1Trigger/interface/L1TObjComparison.h" -#include "DataFormats/L1Trigger/interface/BXVector.h" -#include "FWCore/MessageLogger/interface/MessageLogger.h" - -namespace Phase2L1GMT { - - class MuonROI { - public: - MuonROI(int bx, uint charge, uint pt, uint quality) : bx_(bx), charge_(charge), pt_(pt), quality_(quality) {} - - const int bx() const { return bx_; } - - const uint charge() const { return charge_; } - - const uint pt() const { return pt_; } - const int quality() const { return quality_; } - - const float offline_pt() const { return offline_pt_; } - - void setOfflinePt(float pt) { offline_pt_ = pt; } - - void addStub(const l1t::MuonStubRef& stub) { stubs_.push_back(stub); } - - void setMuonRef(const l1t::RegionalMuonCandRef& ref) { - muRef_ = ref; - isGlobal_ = true; - } - bool isGlobalMuon() const { return isGlobal_; } - - const l1t::RegionalMuonCandRef& muonRef() const { return muRef_; } - - friend std::ostream& operator<<(std::ostream& s, const MuonROI& id) { - s.setf(ios::right, ios::adjustfield); - s << "ROI:" - << " " - << "BX: " << setw(5) << id.bx_ << " " - << "charge:" << setw(5) << id.charge_ << " " - << "pt:" << setw(5) << id.pt_ << " " - << "quality:" << setw(5) << id.quality_ << " " - << "offline pt:" << setw(5) << id.offline_pt_; - return s; - } - - const l1t::MuonStubRefVector& stubs() const { return stubs_; } - - ap_uint<64> stubWord(const l1t::MuonStubRef& stub) const { - ap_uint<64> word = 0; - word = word | twos_complement(stub->coord1(), BITSSTUBCOORD); - word = word | (twos_complement(stub->coord2(), BITSSTUBCOORD) << BITSSTUBCOORD); - word = word | (twos_complement(stub->eta1(), BITSSTUBETA) << (2 * BITSSTUBCOORD)); - word = word | (twos_complement(stub->eta2(), BITSSTUBETA) << (2 * BITSSTUBCOORD + BITSSTUBETA)); - word = word | (twos_complement(stub->quality(), BITSSTUBPHIQUALITY) << (2 * BITSSTUBCOORD + 2 * BITSSTUBETA)); - word = word | (twos_complement(stub->etaQuality(), BITSSTUBETAQUALITY) - << (2 * BITSSTUBCOORD + 2 * BITSSTUBETA + BITSSTUBPHIQUALITY)); - word = word | (twos_complement(stub->bxNum(), BITSSTUBTIME) - << (2 * BITSSTUBCOORD + 2 * BITSSTUBETA + BITSSTUBPHIQUALITY + BITSSTUBETAQUALITY)); - word = word | (twos_complement(stub->id(), BITSSTUBID) - << (2 * BITSSTUBCOORD + 2 * BITSSTUBETA + BITSSTUBPHIQUALITY + BITSSTUBETAQUALITY + BITSSTUBTIME)); - return word; - } - - ap_uint<32> roiWord() const { - ap_uint<32> word = 0; - word = word | twos_complement(bx_, BITSMUONBX); - word = word | (twos_complement(isGlobal_, 1) << (BITSMUONBX)); - word = word | (twos_complement(charge_, 1) << (BITSMUONBX + 1)); - word = word | (twos_complement(pt_, BITSPT) << (BITSMUONBX + 2)); - word = word | (twos_complement(quality_, BITSSTAMUONQUALITY) << (BITSMUONBX + 2 + BITSPT)); - return word; - } - - void printROILine() const { - ap_uint<64> s0 = 0x1ff000000000000; - ap_uint<64> s1 = 0x1ff000000000000; - ap_uint<64> s2 = 0x1ff000000000000; - ap_uint<64> s3 = 0x1ff000000000000; - ap_uint<64> s4 = 0x1ff000000000000; - for (const auto& s : stubs_) { - if (s->tfLayer() == 0) - s0 = stubWord(s); - if (s->tfLayer() == 1) - s1 = stubWord(s); - if (s->tfLayer() == 2) - s2 = stubWord(s); - if (s->tfLayer() == 3) - s3 = stubWord(s); - if (s->tfLayer() == 4) - s4 = stubWord(s); - } - LogDebug("MuonROI") << "MuonROI " << std::setfill('0') << std::setw(8) << std::hex - << (long long unsigned int)(roiWord().to_uint64()) << std::setfill('0') << std::setw(16) - << std::hex << (long long unsigned int)(s4.to_uint64()) << std::setfill('0') << std::setw(16) - << std::hex << (long long unsigned int)(s3.to_uint64()) << std::setfill('0') << std::setw(16) - << std::hex << (long long unsigned int)(s2.to_uint64()) << std::setfill('0') << std::setw(16) - << std::hex << (long long unsigned int)(s1.to_uint64()) << std::setfill('0') << std::setw(16) - << std::hex << (long long unsigned int)(s0.to_uint64()); - } - - private: - int bx_; - uint charge_; - uint pt_; - uint quality_; - bool isGlobal_; - float offline_pt_; - - l1t::MuonStubRefVector stubs_; - l1t::RegionalMuonCandRef muRef_; - }; -} // namespace Phase2L1GMT - -#endif diff --git a/L1Trigger/Phase2L1GMT/plugins/Node.h b/L1Trigger/Phase2L1GMT/plugins/Node.h deleted file mode 100644 index f28a287f54074..0000000000000 --- a/L1Trigger/Phase2L1GMT/plugins/Node.h +++ /dev/null @@ -1,196 +0,0 @@ -#ifndef PHASE2GMT_NODE -#define PHASE2GMT_NODE -#include "FWCore/ParameterSet/interface/ParameterSet.h" -#include "TrackConverter.h" -#include "ROITempAssociator.h" -#include "TrackMuonMatchAlgorithm.h" -#include "Isolation.h" -#include "Tauto3Mu.h" -#include "DataFormats/L1TMuonPhase2/interface/TrackerMuon.h" - -namespace Phase2L1GMT { - - class Node { - public: - Node(const edm::ParameterSet& iConfig) - : verbose_(iConfig.getParameter("verbose")), - tt_track_converter_(new TrackConverter(iConfig.getParameter("trackConverter"))), - roi_assoc_(new ROITempAssociator(iConfig.getParameter("roiTrackAssociator"))), - track_mu_match_(new TrackMuonMatchAlgorithm(iConfig.getParameter("trackMatching"))), - isolation_(new Isolation(iConfig.getParameter("isolation"))), - tauto3mu_(new Tauto3Mu(iConfig.getParameter("tauto3mu"))) {} - - ~Node() {} - - std::vector processEvent(const std::vector >& tracks, - const l1t::ObjectRefBxCollection& muonTracks, - const l1t::MuonStubRefVector& stubs) { - //Split tracks to the links as they come - std::vector > tracks0 = associateTracksWithNonant(tracks, 0); - std::vector > tracks1 = associateTracksWithNonant(tracks, 1); - std::vector > tracks2 = associateTracksWithNonant(tracks, 2); - std::vector > tracks3 = associateTracksWithNonant(tracks, 3); - std::vector > tracks4 = associateTracksWithNonant(tracks, 4); - std::vector > tracks5 = associateTracksWithNonant(tracks, 5); - std::vector > tracks6 = associateTracksWithNonant(tracks, 6); - std::vector > tracks7 = associateTracksWithNonant(tracks, 7); - std::vector > tracks8 = associateTracksWithNonant(tracks, 8); - - //Transition stubs to different nonants with overlap - l1t::MuonStubRefVector stubs0 = associateStubsWithNonant(stubs, 0); - l1t::MuonStubRefVector stubs1 = associateStubsWithNonant(stubs, 1); - l1t::MuonStubRefVector stubs2 = associateStubsWithNonant(stubs, 2); - l1t::MuonStubRefVector stubs3 = associateStubsWithNonant(stubs, 3); - l1t::MuonStubRefVector stubs4 = associateStubsWithNonant(stubs, 4); - l1t::MuonStubRefVector stubs5 = associateStubsWithNonant(stubs, 5); - l1t::MuonStubRefVector stubs6 = associateStubsWithNonant(stubs, 6); - l1t::MuonStubRefVector stubs7 = associateStubsWithNonant(stubs, 7); - l1t::MuonStubRefVector stubs8 = associateStubsWithNonant(stubs, 8); - - //Convert TT tracks to our internal tracking format - std::vector convertedTracks0 = tt_track_converter_->convertTracks(tracks0); - std::vector convertedTracks1 = tt_track_converter_->convertTracks(tracks1); - std::vector convertedTracks2 = tt_track_converter_->convertTracks(tracks2); - std::vector convertedTracks3 = tt_track_converter_->convertTracks(tracks3); - std::vector convertedTracks4 = tt_track_converter_->convertTracks(tracks4); - std::vector convertedTracks5 = tt_track_converter_->convertTracks(tracks5); - std::vector convertedTracks6 = tt_track_converter_->convertTracks(tracks6); - std::vector convertedTracks7 = tt_track_converter_->convertTracks(tracks7); - std::vector convertedTracks8 = tt_track_converter_->convertTracks(tracks8); - - //Build ROIs per nonant - std::vector rois0 = roi_assoc_->associate(0, muonTracks, stubs0); - std::vector rois1 = roi_assoc_->associate(0, muonTracks, stubs1); - std::vector rois2 = roi_assoc_->associate(0, muonTracks, stubs2); - std::vector rois3 = roi_assoc_->associate(0, muonTracks, stubs3); - std::vector rois4 = roi_assoc_->associate(0, muonTracks, stubs4); - std::vector rois5 = roi_assoc_->associate(0, muonTracks, stubs5); - std::vector rois6 = roi_assoc_->associate(0, muonTracks, stubs6); - std::vector rois7 = roi_assoc_->associate(0, muonTracks, stubs7); - std::vector rois8 = roi_assoc_->associate(0, muonTracks, stubs8); - - //run track - muon matching per nonant - std::vector mu0 = track_mu_match_->processNonant(convertedTracks0, rois0); - std::vector mu1 = track_mu_match_->processNonant(convertedTracks1, rois1); - std::vector mu2 = track_mu_match_->processNonant(convertedTracks2, rois2); - std::vector mu3 = track_mu_match_->processNonant(convertedTracks3, rois3); - std::vector mu4 = track_mu_match_->processNonant(convertedTracks4, rois4); - std::vector mu5 = track_mu_match_->processNonant(convertedTracks5, rois5); - std::vector mu6 = track_mu_match_->processNonant(convertedTracks6, rois6); - std::vector mu7 = track_mu_match_->processNonant(convertedTracks7, rois7); - std::vector mu8 = track_mu_match_->processNonant(convertedTracks8, rois8); - if (verbose_) - printf("Matching Nonant 5 with %zu tracks and %zu rois and %zu stubs\n", - convertedTracks5.size(), - rois5.size(), - stubs5.size()); - - //clean neighboring nonants - std::vector muCleaned = track_mu_match_->cleanNeighbor(mu0, mu8, mu1, true); - std::vector muCleaned1 = track_mu_match_->cleanNeighbor(mu1, mu0, mu2, false); - std::vector muCleaned2 = track_mu_match_->cleanNeighbor(mu2, mu1, mu3, true); - std::vector muCleaned3 = track_mu_match_->cleanNeighbor(mu3, mu2, mu4, false); - std::vector muCleaned4 = track_mu_match_->cleanNeighbor(mu4, mu3, mu5, true); - std::vector muCleaned5 = track_mu_match_->cleanNeighbor(mu5, mu4, mu6, false); - std::vector muCleaned6 = track_mu_match_->cleanNeighbor(mu6, mu5, mu7, true); - std::vector muCleaned7 = track_mu_match_->cleanNeighbor(mu7, mu6, mu8, false); - std::vector muCleaned8 = - track_mu_match_->cleanNeighbor(mu8, mu7, mu0, false); //ARGH! 9 sectors - so some duplicates very rarely - - //merge all the collections - std::copy(muCleaned1.begin(), muCleaned1.end(), std::back_inserter(muCleaned)); - std::copy(muCleaned2.begin(), muCleaned2.end(), std::back_inserter(muCleaned)); - std::copy(muCleaned3.begin(), muCleaned3.end(), std::back_inserter(muCleaned)); - std::copy(muCleaned4.begin(), muCleaned4.end(), std::back_inserter(muCleaned)); - std::copy(muCleaned5.begin(), muCleaned5.end(), std::back_inserter(muCleaned)); - std::copy(muCleaned6.begin(), muCleaned6.end(), std::back_inserter(muCleaned)); - std::copy(muCleaned7.begin(), muCleaned7.end(), std::back_inserter(muCleaned)); - std::copy(muCleaned8.begin(), muCleaned8.end(), std::back_inserter(muCleaned)); - - std::vector trackMatchedMuonsNoIso = track_mu_match_->convert(muCleaned, 32); - - //Isolation and tau3mu will read those muons and all 9 collections of convertedTracks* - std::vector convertedTracks = convertedTracks0; - std::copy(convertedTracks1.begin(), convertedTracks1.end(), std::back_inserter(convertedTracks)); - std::copy(convertedTracks2.begin(), convertedTracks2.end(), std::back_inserter(convertedTracks)); - std::copy(convertedTracks3.begin(), convertedTracks3.end(), std::back_inserter(convertedTracks)); - std::copy(convertedTracks4.begin(), convertedTracks4.end(), std::back_inserter(convertedTracks)); - std::copy(convertedTracks5.begin(), convertedTracks5.end(), std::back_inserter(convertedTracks)); - std::copy(convertedTracks6.begin(), convertedTracks6.end(), std::back_inserter(convertedTracks)); - std::copy(convertedTracks7.begin(), convertedTracks7.end(), std::back_inserter(convertedTracks)); - std::copy(convertedTracks8.begin(), convertedTracks8.end(), std::back_inserter(convertedTracks)); - - //sorter here: - std::vector sortedTrackMuonsNoIso = track_mu_match_->sort(trackMatchedMuonsNoIso, 12); - - isolation_->isolation_allmu_alltrk(sortedTrackMuonsNoIso, convertedTracks); - - //tauto3mu_->GetTau3Mu(sortedTrackMuonsNoIso, convertedTracks); - - track_mu_match_->outputGT(sortedTrackMuonsNoIso); - - return sortedTrackMuonsNoIso; //when we add more collections like tau3mu etc we change that - } - - private: - int verbose_; - std::unique_ptr tt_track_converter_; - std::unique_ptr roi_assoc_; - std::unique_ptr track_mu_match_; - std::unique_ptr isolation_; - std::unique_ptr tauto3mu_; - - std::vector > associateTracksWithNonant( - const std::vector >& tracks, uint processor) { - std::vector > out; - for (const auto& track : tracks) { - if (track->phiSector() == processor) { - out.push_back(track); - } - } - return out; - } - - l1t::MuonStubRefVector associateStubsWithNonant(const l1t::MuonStubRefVector& allStubs, uint processor) { - l1t::MuonStubRefVector out; - - ap_int center = ap_int((processor * 910) / 32); - - for (const auto& s : allStubs) { - ap_int phi = 0; - if (s->quality() & 0x1) - phi = s->coord1(); - else - phi = s->coord2(); - - ap_int deltaPhi = phi - center; - ap_uint absDeltaPhi = - (deltaPhi < 0) ? ap_uint(-deltaPhi) : ap_uint(deltaPhi); - if (absDeltaPhi < 42) - out.push_back(s); - - /* if (processor==0 && phi>=-3000/32 && phi<=3000/32 ) */ - /* out.push_back(s); */ - /* else if (processor==1 && (phi>=-1000/32 && phi<=5000/32) ) */ - /* out.push_back(s); */ - /* else if (processor==2 && (phi>=500/32 && phi<=6500/32) ) */ - /* out.push_back(s); */ - /* else if (processor==3 && (phi>=2000/32 || phi<=-8000/32) ) */ - /* out.push_back(s); */ - /* else if (processor==4 && (phi>=4500/32 || phi<=-6000/32) ) */ - /* out.push_back(s); */ - /* else if (processor==5 && (phi>=6000/32 || phi<=-4500/32) ) */ - /* out.push_back(s); */ - /* else if (processor==6 && (phi>=8000/32 || phi<=-2000/32) ) */ - /* out.push_back(s); */ - /* else if (processor==7 && (phi>=-7000/32 && phi<=0) ) */ - /* out.push_back(s); */ - /* else if (processor==8 && (phi>=-4500/32 && phi<=1000/32) ) */ - /* out.push_back(s); */ - } - return out; - } - }; -} // namespace Phase2L1GMT - -#endif diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFilter.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFilter.cc index ea0d9617e7cb7..dfe0d16a91388 100644 --- a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFilter.cc +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFilter.cc @@ -9,7 +9,6 @@ #include "FWCore/Utilities/interface/StreamID.h" #include "DataFormats/L1TMuonPhase2/interface/TrackerMuon.h" #include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" -#include "Node.h" // // class declaration diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc new file mode 100644 index 0000000000000..bfe78b7976fa4 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc @@ -0,0 +1,284 @@ +// -*- C++ -*- + +#ifndef PHASE2GMT_SAFWDMUONTRANSLATOR +#define PHASE2GMT_SAFWDMUONTRANSLATOR + +// system include files +#include +#include + +// user include files +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Utilities/interface/StreamID.h" +#include "DataFormats/L1Trigger/interface/Muon.h" +#include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" + +// +// class declaration +// +using namespace Phase2L1GMT; +using namespace l1t; + +class Phase2L1TGMTFwdMuonTranslator : public edm::stream::EDProducer<> { +public: + explicit Phase2L1TGMTFwdMuonTranslator(const edm::ParameterSet&); + ~Phase2L1TGMTFwdMuonTranslator() override = default; + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); + +private: + void produce(edm::Event&, const edm::EventSetup&) override; + + l1t::SAMuon Convertl1tMuon(const l1t::RegionalMuonCand& mu, const int bx_, bool isDisplaced = false); + l1t::MuonStubRefVector selectLayerBX(const l1t::MuonStubRefVector& all, int bx, uint layer); + void associateStubs(l1t::SAMuon&, const l1t::MuonStubRefVector&); + + // ----------member data --------------------------- + edm::EDGetTokenT stubToken_; + edm::EDGetTokenT omtfTrackToken_; + edm::EDGetTokenT emtfTrackToken_; +}; +// +// constants, enums and typedefs +// + +// +// static data member definitions +// + +// +// constructors and destructor +// +Phase2L1TGMTFwdMuonTranslator::Phase2L1TGMTFwdMuonTranslator(const edm::ParameterSet& iConfig) +<<<<<<< HEAD + : muonToken_(consumes(iConfig.getParameter("muons"))), + stubToken_(consumes(iConfig.getParameter("stubs"))) { +======= + : stubToken_(consumes(iConfig.getParameter("stubs"))), + omtfTrackToken_(consumes(iConfig.getParameter("omtfTracks"))), + emtfTrackToken_(consumes(iConfig.getParameter("emtfTracks"))) { +>>>>>>> d34010dded1 (Add Phase-2 OMTF and EMTF to GMT SA) + produces >("prompt").setBranchAlias("prompt"); +} + +// ------------ method called to produce the data ------------ +void Phase2L1TGMTFwdMuonTranslator::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + using namespace edm; +<<<<<<< HEAD + edm::Handle muon; + iEvent.getByToken(muonToken_, muon); + edm::Handle stubHandle; + iEvent.getByToken(stubToken_, stubHandle); +======= + + edm::Handle stubHandle; + iEvent.getByToken(stubToken_, stubHandle); + + edm::Handle emtf_tracks; + iEvent.getByToken(emtfTrackToken_, emtf_tracks); + + edm::Handle omtf_tracks; + iEvent.getByToken(omtfTrackToken_, omtf_tracks); + + // Process Stubs +>>>>>>> d34010dded1 (Add Phase-2 OMTF and EMTF to GMT SA) + l1t::MuonStubRefVector stubs; + for (uint i = 0; i < stubHandle->size(); ++i) { + l1t::MuonStubRef stub(stubHandle, i); + if (stub->bxNum() == 0) + stubs.push_back(stub); + } + + std::vector prompt; + + // TODO: Will receive hybrid stubs from OMTF/EMTF + // std::vector hybridStubs; + // edm::RefProd stubRefProd = iEvent.getRefBeforePut >("hybridStubs"); + // l1t::MuonStubRef::key_type idxStub =0; + +<<<<<<< HEAD + for (unsigned int i = 0; i < muon->size(0); ++i) { + const l1t::Muon& mu = muon->at(0, i); + l1t::SAMuon samuon = Convertl1tMuon(mu, 0); + if (samuon.tfType() == l1t::tftype::bmtf) + continue; +======= + // Convert OMTF Muons to SAMuons + for (unsigned int i = 0; i < omtf_tracks->size(0); ++i) { + const l1t::RegionalMuonCand& mu = omtf_tracks->at(0, i); + // Since OMTF is using Phase-1 LSB, will convert to SAMuon locally + // We should move to passing words in future + l1t::SAMuon samuon; + if (mu.hwPt() > 0) + samuon = Convertl1tMuon(mu, 0); + else if (mu.hwPtUnconstrained() > 0) //Assume exculsive, need double check + samuon = Convertl1tMuon(mu, 0, true); + +>>>>>>> d34010dded1 (Add Phase-2 OMTF and EMTF to GMT SA) + //now associate the stubs + associateStubs(samuon, stubs); + + // Add To Collections + if (mu.hwPt() > 0) + prompt.push_back(samuon); + else if (mu.hwPtUnconstrained() > 0) + displaced.push_back(samuon); + } + std::unique_ptr > prompt_ptr = std::make_unique >(prompt); + iEvent.put(std::move(prompt_ptr), "prompt"); +} + +// === FUNCTION ============================================================ +// Name: Phase2L1TGMTFwdMuonTranslator::Convertl1tMuon +// Description: +// =========================================================================== +SAMuon Phase2L1TGMTFwdMuonTranslator::Convertl1tMuon(const l1t::RegionalMuonCand& mu, const int bx_, bool isDisplaced) { + ap_uint qual = mu.hwQual(); + int charge = mu.hwSign(); + + ap_uint pt = 0; + if (!isDisplaced && mu.hwPt() > 0) + pt = round(mu.hwPt() * 0.5 / LSBpt); // Phase-1 LSB 0.5GeV + if (isDisplaced && mu.hwPtUnconstrained() > 0) + pt = round(mu.hwPtUnconstrained() * 0.5 / LSBpt); // Phase-1 LSB 0.5GeV + + constexpr double p1phiLSB = 2 * M_PI / 576; + ap_int phi = round(mu.hwPhi() * p1phiLSB / LSBphi); // Phase-1 LSB (2*pi/576) + ap_int eta = round(mu.hwEta() * 0.010875 / LSBeta); // Phase-1 LSB 0.010875 + + // FIXME: Below are not well defined in phase1 GMT + // Using the version from Correlator for now + ap_int z0 = 0; // No tracks info in Phase 1 + // Use 2 bits with LSB = 30cm for BMTF and 25cm for EMTF currently, but subjet to change + ap_int d0 = mu.hwDXY(); + + //Here do not use the word format to GT but use the word format expected by GMT + int bstart = 0; + wordtype word(0); + bstart = wordconcat(word, bstart, 1, 1); + bstart = wordconcat(word, bstart, pt, BITSGTPT); + bstart = wordconcat(word, bstart, phi, BITSGTPHI); + bstart = wordconcat(word, bstart, eta, BITSGTETA); + bstart = wordconcat(word, bstart, z0, BITSSAZ0); + bstart = wordconcat(word, bstart, d0, BITSSAD0); + bstart = wordconcat(word, bstart, charge, 1); + bstart = wordconcat(word, bstart, qual, BITSSAQUAL); + + // Calculate Lorentz Vector + math::PtEtaPhiMLorentzVector p4(pt * LSBpt, eta * LSBeta, phi * LSBphi, 0.0); + SAMuon samuon(p4, charge, pt.to_uint(), eta.to_int(), phi.to_int(), z0.to_int(), d0.to_int(), qual.to_uint()); + samuon.setTF(mu.trackFinderType()); + samuon.setWord(word); + + return samuon; +} // ----- end of function Phase2L1TGMTFwdMuonTranslator::Convertl1tMuon ----- + +l1t::MuonStubRefVector Phase2L1TGMTFwdMuonTranslator::selectLayerBX(const l1t::MuonStubRefVector& all, + int bx, + uint layer) { + l1t::MuonStubRefVector out; + for (const auto& stub : all) { + if (stub->bxNum() == bx && stub->tfLayer() == layer) + out.push_back(stub); + } + return out; +} + +void Phase2L1TGMTFwdMuonTranslator::associateStubs(l1t::SAMuon& mu, const l1t::MuonStubRefVector& stubs) { + for (unsigned int layer = 0; layer <= 4; ++layer) { + l1t::MuonStubRefVector selectedStubs = selectLayerBX(stubs, 0, layer); + int bestStubINT = -1; + float dPhi = 1000.0; + for (uint i = 0; i < selectedStubs.size(); ++i) { + const l1t::MuonStubRef& stub = selectedStubs[i]; + float deltaPhi = + (stub->quality() & 0x1) ? stub->offline_coord1() - mu.p4().phi() : stub->offline_coord2() - mu.p4().phi(); + if (deltaPhi > M_PI) + deltaPhi = deltaPhi - 2 * M_PI; + if (deltaPhi < -M_PI) + deltaPhi = deltaPhi + 2 * M_PI; + deltaPhi = fabs(deltaPhi); + float deltaEta = (stub->etaQuality() == 0 || (stub->etaQuality() & 0x1)) + ? fabs(stub->offline_eta1() - mu.p4().eta()) + : fabs(stub->offline_eta2() - mu.p4().eta()); + if (deltaPhi < 0.3 && deltaEta < 0.3 && deltaPhi < dPhi) { + dPhi = deltaPhi; + bestStubINT = i; + } + } + if (bestStubINT >= 0) { + mu.addStub(selectedStubs[bestStubINT]); + } + } +} + +SAMuon Phase2L1TGMTFwdMuonTranslator::ConvertEMTFTrack(const l1t::phase2::EMTFTrack& track, const int bx_) { + // Convert EMTF Phi and Theta to Global Phi and Eta + float track_phi = emtf::phase2::tp::calc_phi_glob_rad_from_loc( + track.sector(), emtf::phase2::tp::calc_phi_loc_deg_from_int(track.modelPhi())); + float track_theta = emtf::phase2::tp::calc_theta_rad_from_int(track.modelEta()); + float track_eta = -1 * std::log(std::tan(track_theta / 2)); + + track_theta *= track.endcap(); + track_eta *= track.endcap(); + + // Calculate Lorentz Vector + // Muon mass taken from L1Trigger/L1TMuon/plugins/L1TMuonProducer.cc + math::PtEtaPhiMLorentzVector p4(track.emtfPt() * LSBpt, track_eta, track_phi, 0.0); + + // Quantize Values + ap_uint qual = track.emtfModeV2(); // Not sure how this should be handled; using mode for now + int charge = track.emtfQ(); // EMTF uses the same convention + ap_uint pt = track.emtfPt(); // Quantized by EMTF in the same units + ap_int phi = round(track_phi / LSBphi); + ap_int eta = round(track_eta / LSBeta); + ap_int z0 = track.emtfZ0(); // Quantized by EMTF in the same units + ap_int d0 = track.emtfD0(); // Quantized by EMTF in the same units + + //Here do not use the word format to GT but use the word format expected by GMT + int bstart = 0; + wordtype word(0); + bstart = wordconcat(word, bstart, 1, 1); + bstart = wordconcat(word, bstart, pt, BITSPT); + bstart = wordconcat(word, bstart, phi, BITSPHI); + bstart = wordconcat(word, bstart, eta, BITSETA); + bstart = wordconcat(word, bstart, z0, BITSSAZ0); + bstart = wordconcat(word, bstart, d0, BITSSAD0); + bstart = wordconcat(word, bstart, charge, 1); + bstart = wordconcat(word, bstart, qual, BITSSAQUAL); + + SAMuon samuon(p4, charge, pt.to_uint(), eta.to_int(), phi.to_int(), z0.to_int(), d0.to_int(), qual.to_uint()); + + // +1=Positive Endcap and -1=Negative Endcap + if (track.endcap() == 1) + samuon.setTF(tftype::emtf_pos); + else + samuon.setTF(tftype::emtf_neg); + + samuon.setWord(word); + + return samuon; +} + +// ------------ method fills 'descriptions' with the allowed parameters for the module ------------ +void Phase2L1TGMTFwdMuonTranslator::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + //The following says we do not know what parameters are allowed so do no validation + // Please change this to state exactly what you do use, even if it is no parameters + edm::ParameterSetDescription desc; + + // Input Collections + desc.add("stubs", edm::InputTag("gmtStubs")); + desc.add("emtfTracks", edm::InputTag("simEmtfDigisPhase2")); + desc.add("omtfTracks", edm::InputTag("simOmtfPhase2Digis")); + + // Register + descriptions.add("Phase2L1TGMTFwdMuonTranslator", desc); +} + +//define this as a plug-in +DEFINE_FWK_MODULE(Phase2L1TGMTFwdMuonTranslator); +#endif diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTKMTFProducer.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTKMTFProducer.cc new file mode 100644 index 0000000000000..2eb12259867f5 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTKMTFProducer.cc @@ -0,0 +1,160 @@ +// -*- C++ -*- +// +// Package: L1Trigger/Phase2L1GMT +// Class: Phase2L1TGMTSAMuonProducer +// Original Author: Michalis Bachtis + +#ifndef PHASE2GMT_KMTFPRODUCER +#define PHASE2GMT_KMTFPRODUCER + +// system include files +#include +#include + +// user include files +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/stream/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Utilities/interface/StreamID.h" + +#include "DataFormats/L1Trigger/interface/Muon.h" +#include "DataFormats/L1Trigger/interface/L1MuonParticleFwd.h" +#include "DataFormats/L1Trigger/interface/L1MuonParticle.h" + +#include "DataFormats/L1TMuonPhase2/interface/Constants.h" +#include "L1Trigger/Phase2L1GMT/interface/KMTF.h" +#include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" + +// +// class declaration +// +using namespace Phase2L1GMT; +using namespace l1t; + +class Phase2L1TGMTKMTFProducer : public edm::stream::EDProducer<> { +public: + explicit Phase2L1TGMTKMTFProducer(const edm::ParameterSet&); + ~Phase2L1TGMTKMTFProducer() override = default; + +private: + void produce(edm::Event&, const edm::EventSetup&) override; + + // ----------member data --------------------------- + edm::EDGetTokenT stubToken_; + std::unique_ptr kmtf_; + unsigned int Nprompt; + unsigned int Ndisplaced; +}; + +// +// constants, enums and typedefs +// + +// +// static data member definitions +// + +// +// constructors and destructor +// +Phase2L1TGMTKMTFProducer::Phase2L1TGMTKMTFProducer(const edm::ParameterSet& iConfig) + : stubToken_(consumes(iConfig.getParameter("stubs"))), + kmtf_(new KMTF(iConfig.getParameter("verbose"), iConfig.getParameter("algo"))), + Nprompt(iConfig.getParameter("Nprompt")), + Ndisplaced(iConfig.getParameter("Ndisplaced")) { + produces >("prompt").setBranchAlias("prompt"); + produces >("displaced").setBranchAlias("displaced"); + produces >("kmtfTracks"); +} + +// +// member functions +// + +// ------------ method called to produce the data ------------ +void Phase2L1TGMTKMTFProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + using namespace edm; + edm::Handle stubHandle; + iEvent.getByToken(stubToken_, stubHandle); + + l1t::MuonStubRefVector stubs; + for (uint i = 0; i < stubHandle->size(); ++i) { + l1t::MuonStubRef stub(stubHandle, i); + if (stub->bxNum() == 0) + stubs.push_back(stub); + } + + // KMTF + std::vector prompt; + std::vector displaced; + std::pair, std::vector > kmtfOutput = kmtf_->process(stubs, 0, 32); + std::vector kmtfTracks; + for (const auto& track : kmtfOutput.first) { + kmtfTracks.push_back(track); + l1t::SAMuon p(track.p4(), + (track.curvatureAtVertex() < 0), + track.ptPrompt(), + track.coarseEta(), + track.phiAtMuon() / (1 << 5), + 0, + 0, + track.stubs().size() - 1); + p.setTF(l1t::tftype::bmtf); + int bstart = 0; + wordtype word(0); + bstart = wordconcat(word, bstart, 1, 1); + bstart = wordconcat(word, bstart, p.hwCharge(), 1); + bstart = wordconcat(word, bstart, p.hwPt(), BITSPT); + bstart = wordconcat(word, bstart, p.hwPhi(), BITSPHI); + bstart = wordconcat(word, bstart, p.hwEta(), BITSETA); + bstart = wordconcat(word, bstart, p.hwD0(), BITSSAD0); + bstart = wordconcat(word, bstart, track.rankPrompt(), 8); + + for (const auto& stub : track.stubs()) + p.addStub(stub); + p.setWord(word); + prompt.push_back(p); + } + + for (const auto& track : kmtfOutput.second) { + kmtfTracks.push_back(track); + ap_int<7> dxy = track.dxy() * ap_ufixed<8, 1>(1.606); + l1t::SAMuon p(track.displacedP4(), + (track.curvatureAtMuon() < 0), + track.ptDisplaced(), + track.coarseEta(), + track.phiAtMuon() / (1 << 5), + 0, + dxy, + track.approxDispChi2()); + int bstart = 0; + wordtype word(0); + bstart = wordconcat(word, bstart, 1, 1); + bstart = wordconcat(word, bstart, p.hwCharge(), 1); + bstart = wordconcat(word, bstart, p.hwPt(), BITSPT); + bstart = wordconcat(word, bstart, p.hwPhi(), BITSPHI); + bstart = wordconcat(word, bstart, p.hwEta(), BITSETA); + bstart = wordconcat(word, bstart, p.hwD0(), BITSSAD0); + bstart = wordconcat(word, bstart, track.rankDisp(), 8); + + for (const auto& stub : track.stubs()) { + p.addStub(stub); + } + p.setWord(word); + displaced.push_back(p); + } + std::unique_ptr > prompt_ptr = std::make_unique >(prompt); + std::unique_ptr > displaced_ptr = std::make_unique >(displaced); + std::unique_ptr > kmtf_ptr = std::make_unique >(kmtfTracks); + iEvent.put(std::move(prompt_ptr), "prompt"); + iEvent.put(std::move(displaced_ptr), "displaced"); + iEvent.put(std::move(kmtf_ptr), "kmtfTracks"); +} + +//define this as a plug-in +DEFINE_FWK_MODULE(Phase2L1TGMTKMTFProducer); +#endif diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonGhostCleaner.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonGhostCleaner.cc new file mode 100644 index 0000000000000..fb215300c8722 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonGhostCleaner.cc @@ -0,0 +1,126 @@ +// -*- C++ -*- +#ifndef PHASE2GMT_SAMUONGHOSTCLEANER +#define PHASE2GMT_SAMUONGHOSTCLEANER + +// system include files +#include +#include + +// user include files +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Utilities/interface/StreamID.h" +#include "DataFormats/L1Trigger/interface/Muon.h" +#include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" +#include "L1Trigger/Phase2L1GMT/interface/SAMuonCleaner.h" +// +// class declaration +// +using namespace Phase2L1GMT; +using namespace l1t; + +class Phase2L1TGMTSAMuonGhostCleaner : public edm::stream::EDProducer<> { +public: + explicit Phase2L1TGMTSAMuonGhostCleaner(const edm::ParameterSet&); + ~Phase2L1TGMTSAMuonGhostCleaner() override = default; + +private: + void produce(edm::Event&, const edm::EventSetup&) override; + + std::vector prodMuons(std::vector& muons); + + // ----------member data --------------------------- + edm::EDGetTokenT > barrelTokenPrompt_; + edm::EDGetTokenT > barrelTokenDisp_; + edm::EDGetTokenT > fwdTokenPrompt_; + edm::EDGetTokenT > fwdTokenDisp_; + + SAMuonCleaner ghostCleaner; +}; +// +// constants, enums and typedefs +// + +// +// static data member definitions +// + +// +// constructors and destructor +// +Phase2L1TGMTSAMuonGhostCleaner::Phase2L1TGMTSAMuonGhostCleaner(const edm::ParameterSet& iConfig) + : barrelTokenPrompt_(consumes >(iConfig.getParameter("barrelPrompt"))), + barrelTokenDisp_(consumes >(iConfig.getParameter("barrelDisp"))), + fwdTokenPrompt_(consumes >(iConfig.getParameter("forwardPrompt"))), + fwdTokenDisp_(consumes >(iConfig.getParameter("forwardDisp"))) { + produces >("prompt"); + produces >("displaced"); +} + +// === FUNCTION ============================================================ +// Name: Phase2L1TGMTSAMuonGhostCleaner::prodMuons +// Description: +// =========================================================================== +std::vector Phase2L1TGMTSAMuonGhostCleaner::prodMuons(std::vector& muons) { + std::vector cleanedMuons = ghostCleaner.cleanTFMuons(muons); + //here switch to the offical word required by the GT + std::vector finalMuons; + for (const auto& mu : cleanedMuons) { + l1t::SAMuon m = mu; + if (m.tfType() == l1t::tftype::bmtf) + m.setHwQual(m.hwQual() >> 4); + int bstart = 0; + wordtype word(0); + bstart = wordconcat(word, bstart, 1, 1); + bstart = wordconcat(word, bstart, m.hwPt(), BITSGTPT); + bstart = wordconcat(word, bstart, m.hwPhi(), BITSGTPHI); + bstart = wordconcat(word, bstart, m.hwEta(), BITSGTETA); + bstart = wordconcat(word, bstart, m.hwZ0(), BITSSAZ0); + bstart = wordconcat(word, bstart, m.hwD0(), BITSSAD0); + bstart = wordconcat(word, bstart, m.hwCharge(), 1); + bstart = wordconcat(word, bstart, m.hwQual(), BITSSAQUAL); + m.setWord(word); + finalMuons.push_back(m); + } + return finalMuons; +} // ----- end of function Phase2L1TGMTSAMuonGhostCleaner::prodMuons ----- + +// ------------ method called to produce the data ------------ +void Phase2L1TGMTSAMuonGhostCleaner::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + using namespace edm; + + edm::Handle > barrelPrompt; + iEvent.getByToken(barrelTokenPrompt_, barrelPrompt); + + edm::Handle > barrelDisp; + iEvent.getByToken(barrelTokenDisp_, barrelDisp); + + edm::Handle > forwardPrompt; + iEvent.getByToken(fwdTokenPrompt_, forwardPrompt); + + edm::Handle > forwardDisp; + iEvent.getByToken(fwdTokenDisp_, forwardDisp); + + // Prompt muons + std::vector muons = *barrelPrompt.product(); + muons.insert(muons.end(), forwardPrompt->begin(), forwardPrompt->end()); + std::vector finalPrompt = prodMuons(muons); + + // Displace muons + muons.clear(); + muons = *barrelDisp.product(); + muons.insert(muons.end(), forwardDisp->begin(), forwardDisp->end()); + std::vector finalDisp = prodMuons(muons); + + std::unique_ptr > prompt_ptr = std::make_unique >(finalPrompt); + std::unique_ptr > disp_ptr = std::make_unique >(finalDisp); + iEvent.put(std::move(prompt_ptr), "prompt"); + iEvent.put(std::move(disp_ptr), "displaced"); +} + +DEFINE_FWK_MODULE(Phase2L1TGMTSAMuonGhostCleaner); + +#endif diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonProducer.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonProducer.cc deleted file mode 100644 index c6284873729c5..0000000000000 --- a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonProducer.cc +++ /dev/null @@ -1,179 +0,0 @@ -// -*- C++ -*- -// -// Package: L1Trigger/Phase2L1GMT -// Class: Phase2L1TGMTSAMuonProducer -// -/**\class Phase2L1TGMTSAMuonProducer Phase2L1TGMTSAMuonProducer.cc L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonProducer.cc - - Description: [one line class summary] - - Implementation: - [Notes on implementation] -*/ -// -// Original Author: Zhenbin Wu -// Created: Fri, 30 Apr 2021 19:10:59 GMT -// -// - -#ifndef PHASE2GMT_SAMUONPRODUCER -#define PHASE2GMT_SAMUONPRODUCER - -// system include files -#include -#include - -// user include files -#include "FWCore/Framework/interface/Frameworkfwd.h" -#include "FWCore/Framework/interface/stream/EDProducer.h" - -#include "FWCore/Framework/interface/Event.h" -#include "FWCore/Framework/interface/MakerMacros.h" - -#include "FWCore/ParameterSet/interface/ParameterSet.h" -#include "FWCore/Utilities/interface/StreamID.h" - -#include "DataFormats/L1Trigger/interface/Muon.h" -#include "DataFormats/L1Trigger/interface/L1MuonParticleFwd.h" -#include "DataFormats/L1Trigger/interface/L1MuonParticle.h" - -#include "DataFormats/L1TMuonPhase2/interface/Constants.h" -#include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" -// -// class declaration -// -using namespace Phase2L1GMT; -using namespace l1t; - -class Phase2L1TGMTSAMuonProducer : public edm::stream::EDProducer<> { -public: - explicit Phase2L1TGMTSAMuonProducer(const edm::ParameterSet&); - ~Phase2L1TGMTSAMuonProducer() override = default; - - static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); - -private: - void beginStream(edm::StreamID) override; - void produce(edm::Event&, const edm::EventSetup&) override; - void endStream() override; - - l1t::SAMuon Convertl1tMuon(const l1t::Muon& mu, const int bx_); - - // ----------member data --------------------------- - edm::EDGetTokenT > muonToken_; - unsigned int Nprompt; - unsigned int Ndisplaced; -}; - -Phase2L1TGMTSAMuonProducer::Phase2L1TGMTSAMuonProducer(const edm::ParameterSet& iConfig) - : muonToken_(consumes(iConfig.getParameter("muonToken"))), - Nprompt(iConfig.getParameter("Nprompt")), - Ndisplaced(iConfig.getParameter("Ndisplaced")) { - produces >("promptSAMuons").setBranchAlias("prompt"); - produces >("displacedSAMuons").setBranchAlias("displaced"); -} - -// -// member functions -// - -// ------------ method called to produce the data ------------ -void Phase2L1TGMTSAMuonProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { - using namespace edm; - edm::Handle muon; - iEvent.getByToken(muonToken_, muon); - - // Output - std::vector prompt; - std::vector displaced; - - for (int bx = muon->getFirstBX(); bx <= muon->getLastBX(); ++bx) { - //TODO: We are expecting to send all BX. Using bx0 for now - if (bx != 0) { - continue; - } - - for (uint i = 0; i < muon->size(bx); ++i) { - const l1t::Muon& mu = muon->at(bx, i); - - //TODO: Still looking for a way to get displaced muon - if (abs(mu.hwDXY()) > 0) - displaced.push_back(Convertl1tMuon(mu, bx)); - else - prompt.push_back(Convertl1tMuon(mu, bx)); - } - - // Sort by hwPt - std::sort(prompt.begin(), prompt.end(), std::greater<>()); - std::sort(displaced.begin(), displaced.end(), std::greater<>()); - - // Store into output, allow up to 18 prompt + 18 displayed - if (prompt.size() > Nprompt) { - prompt.resize(Nprompt); - } - if (displaced.size() > Ndisplaced) { - displaced.resize(Ndisplaced); - } - } - - std::unique_ptr > prompt_ptr = std::make_unique >(prompt); - std::unique_ptr > displaced_ptr = std::make_unique >(displaced); - iEvent.put(std::move(prompt_ptr), "promptSAMuons"); - iEvent.put(std::move(displaced_ptr), "displacedSAMuons"); -} - -// === FUNCTION ============================================================ -// Name: Phase2L1TGMTSAMuonProducer::Convertl1tMuon -// Description: -// =========================================================================== -SAMuon Phase2L1TGMTSAMuonProducer::Convertl1tMuon(const l1t::Muon& mu, const int bx_) { - qual_sa_t qual = mu.hwQual(); - int charge = mu.charge() > 0 ? 0 : 1; - - pt_sa_t pt = round(mu.pt() / LSBpt); - phi_sa_t phi = round(mu.phi() / LSBphi); - eta_sa_t eta = round(mu.eta() / LSBeta); - // FIXME: Below are not well defined in phase1 GMT - // Using the version from Correlator for now - z0_sa_t z0 = 0; // No tracks info in Phase 1 - // Use 2 bits with LSB = 30cm for BMTF and 25cm for EMTF currently, but subjet to change - d0_sa_t d0 = mu.hwDXY(); - - int bstart = 0; - wordtype word(0); - bstart = wordconcat(word, bstart, pt > 0, 1); - bstart = wordconcat(word, bstart, pt, BITSGTPT); - bstart = wordconcat(word, bstart, phi, BITSGTPHI); - bstart = wordconcat(word, bstart, eta, BITSGTETA); - bstart = wordconcat(word, bstart, z0, BITSSAZ0); - bstart = wordconcat(word, bstart, d0, BITSSAD0); - bstart = wordconcat(word, bstart, charge, 1); - bstart = wordconcat(word, bstart, qual, BITSSAQUAL); - - SAMuon samuon(mu, charge, pt.to_uint(), eta.to_int(), phi.to_int(), z0.to_int(), d0.to_int(), qual.to_uint()); - samuon.setWord(word); - return samuon; -} // ----- end of function Phase2L1TGMTSAMuonProducer::Convertl1tMuon ----- - -// ------------ method called once each stream before processing any runs, lumis or events ------------ -void Phase2L1TGMTSAMuonProducer::beginStream(edm::StreamID) { - // please remove this method if not needed -} - -// ------------ method called once each stream after processing all runs, lumis and events ------------ -void Phase2L1TGMTSAMuonProducer::endStream() { - // please remove this method if not needed -} - -// ------------ method fills 'descriptions' with the allowed parameters for the module ------------ -void Phase2L1TGMTSAMuonProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { - edm::ParameterSetDescription desc; - desc.add("muonToken", edm::InputTag("simGmtStage2Digis")); - desc.add("Nprompt", 12); - desc.add("Ndisplaced", 12); - descriptions.add("standaloneMuons", desc); -} - -//define this as a plug-in -DEFINE_FWK_MODULE(Phase2L1TGMTSAMuonProducer); -#endif diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTStubProducer.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTStubProducer.cc index 44d0d8d84f9c1..6b1c78c4a158e 100644 --- a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTStubProducer.cc +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTStubProducer.cc @@ -30,7 +30,7 @@ class Phase2L1TGMTStubProducer : public edm::stream::EDProducer<> { void beginStream(edm::StreamID) override; void produce(edm::Event&, const edm::EventSetup&) override; void endStream() override; - + l1t::MuonStub convertToHybrid(const l1t::MuonStub& stub); edm::EDGetTokenT> srcCSC_; edm::EDGetTokenT srcDT_; edm::EDGetTokenT srcDTTheta_; @@ -51,7 +51,8 @@ Phase2L1TGMTStubProducer::Phase2L1TGMTStubProducer(const edm::ParameterSet& iCon procEndcap_(new L1TPhase2GMTEndcapStubProcessor(iConfig.getParameter("Endcap"))), procBarrel_(new L1TPhase2GMTBarrelStubProcessor(iConfig.getParameter("Barrel"))), verbose_(iConfig.getParameter("verbose")) { - produces(); + produces("kmtf"); + produces("tps"); edm::ConsumesCollector consumesColl(consumesCollector()); translator_ = new L1TMuon::GeometryTranslator(consumesColl); } @@ -71,6 +72,24 @@ Phase2L1TGMTStubProducer::~Phase2L1TGMTStubProducer() { // member functions // +l1t::MuonStub Phase2L1TGMTStubProducer::convertToHybrid(const l1t::MuonStub& stub) { + l1t::MuonStub hybrid(stub.etaRegion(), + stub.phiRegion(), + stub.depthRegion(), + stub.tfLayer(), + stub.coord1() / 256, //for track matching was 1024 + stub.coord2() / 256, //for track matching was 1024 + stub.id(), + stub.bxNum(), + 0x3, //for track matching + stub.eta1(), + stub.eta2(), + stub.etaQuality(), + stub.type()); + hybrid.setOfflineQuantities(stub.offline_coord1(), stub.offline_coord2(), stub.offline_eta1(), stub.offline_eta2()); + return hybrid; +} + // ------------ method called to produce the data ------------ void Phase2L1TGMTStubProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { using namespace edm; @@ -90,6 +109,7 @@ void Phase2L1TGMTStubProducer::produce(edm::Event& iEvent, const edm::EventSetup //Generate a unique stub ID l1t::MuonStubCollection stubs; + l1t::MuonStubCollection stubsKMTF; uint count0 = 0; uint count1 = 0; @@ -99,46 +119,17 @@ void Phase2L1TGMTStubProducer::produce(edm::Event& iEvent, const edm::EventSetup l1t::MuonStubCollection stubsEndcap = procEndcap_->makeStubs(*cscDigis, *rpcDigis, translator_, iSetup); for (auto& stub : stubsEndcap) { - if (stub.tfLayer() == 0) { - stub.setID(count0); - count0++; - } else if (stub.tfLayer() == 1) { - stub.setID(count1); - count1++; - } else if (stub.tfLayer() == 2) { - stub.setID(count2); - count2++; - } else if (stub.tfLayer() == 3) { - stub.setID(count3); - count3++; - } else { - stub.setID(count4); - count4++; - } stubs.push_back(stub); } l1t::MuonStubCollection stubsBarrel = procBarrel_->makeStubs(dtDigis.product(), dtThetaDigis.product()); for (auto& stub : stubsBarrel) { - if (stub.tfLayer() == 0) { - stub.setID(count0); - count0++; - } else if (stub.tfLayer() == 1) { - stub.setID(count1); - count1++; - } else if (stub.tfLayer() == 2) { - stub.setID(count2); - count2++; - } else if (stub.tfLayer() == 3) { - stub.setID(count3); - count3++; - } else { - stub.setID(count4); - count4++; - } - stubs.push_back(stub); + //convert to Hybrid + stubs.push_back(convertToHybrid(stub)); + stubsKMTF.push_back(stub); } - iEvent.put(std::make_unique(stubs)); + iEvent.put(std::make_unique(stubs), "tps"); + iEvent.put(std::make_unique(stubsKMTF), "kmtf"); } // ------------ method called once each stream before processing any runs, lumis or events ------------ diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTProducer.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTTkMuonProducer.cc similarity index 51% rename from L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTProducer.cc rename to L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTTkMuonProducer.cc index 5595b20e9c0b1..36957153d86b4 100644 --- a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTProducer.cc +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTTkMuonProducer.cc @@ -8,7 +8,7 @@ #include "FWCore/ParameterSet/interface/ParameterSet.h" #include "FWCore/Utilities/interface/StreamID.h" #include "DataFormats/L1TMuonPhase2/interface/TrackerMuon.h" -#include "Node.h" +#include "L1Trigger/Phase2L1GMT/interface/TPS.h" // // class declaration @@ -16,10 +16,10 @@ using namespace Phase2L1GMT; using namespace l1t; -class Phase2L1TGMTProducer : public edm::stream::EDProducer<> { +class Phase2L1TGMTTkMuonProducer : public edm::stream::EDProducer<> { public: - explicit Phase2L1TGMTProducer(const edm::ParameterSet&); - ~Phase2L1TGMTProducer() override; + explicit Phase2L1TGMTTkMuonProducer(const edm::ParameterSet&); + ~Phase2L1TGMTTkMuonProducer() override; static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); @@ -27,24 +27,18 @@ class Phase2L1TGMTProducer : public edm::stream::EDProducer<> { void beginStream(edm::StreamID) override; void produce(edm::Event&, const edm::EventSetup&) override; void endStream() override; - std::unique_ptr node_; + std::unique_ptr tps_; edm::EDGetTokenT srcTracks_; edm::EDGetTokenT > srcStubs_; - edm::EDGetTokenT > bmtfTracks_; - edm::EDGetTokenT > emtfTracks_; - edm::EDGetTokenT > omtfTracks_; int minTrackStubs_; int bxMin_; int bxMax_; }; -Phase2L1TGMTProducer::Phase2L1TGMTProducer(const edm::ParameterSet& iConfig) - : node_(new Node(iConfig)), +Phase2L1TGMTTkMuonProducer::Phase2L1TGMTTkMuonProducer(const edm::ParameterSet& iConfig) + : tps_(new TPS(iConfig)), srcTracks_(consumes(iConfig.getParameter("srcTracks"))), srcStubs_(consumes >(iConfig.getParameter("srcStubs"))), - bmtfTracks_(consumes >(iConfig.getParameter("srcBMTF"))), - emtfTracks_(consumes >(iConfig.getParameter("srcEMTF"))), - omtfTracks_(consumes >(iConfig.getParameter("srcOMTF"))), minTrackStubs_(iConfig.getParameter("minTrackStubs")), bxMin_(iConfig.getParameter("muonBXMin")), bxMax_(iConfig.getParameter("muonBXMax")) @@ -53,7 +47,7 @@ Phase2L1TGMTProducer::Phase2L1TGMTProducer(const edm::ParameterSet& iConfig) produces >(); } -Phase2L1TGMTProducer::~Phase2L1TGMTProducer() { +Phase2L1TGMTTkMuonProducer::~Phase2L1TGMTTkMuonProducer() { // do anything here that needs to be done at destruction time // (e.g. close files, deallocate resources etc.) } @@ -63,7 +57,7 @@ Phase2L1TGMTProducer::~Phase2L1TGMTProducer() { // // ------------ method called to produce the data ------------ -void Phase2L1TGMTProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { +void Phase2L1TGMTTkMuonProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { using namespace edm; Handle trackHandle; iEvent.getByToken(srcTracks_, trackHandle); @@ -76,55 +70,26 @@ void Phase2L1TGMTProducer::produce(edm::Event& iEvent, const edm::EventSetup& iS tracks.push_back(track); } + l1t::MuonStubRefVector muonStubs; Handle > stubHandle; iEvent.getByToken(srcStubs_, stubHandle); - l1t::MuonStubRefVector stubs; - for (uint i = 0; i < stubHandle->size(); ++i) { - l1t::MuonStubRef stub(stubHandle, i); - if (stub->bxNum() >= bxMin_ && stub->bxNum() <= bxMax_) - stubs.push_back(stub); + for (size_t i = 0; i < stubHandle->size(); ++i) { + MuonStubRef stub(stubHandle, i); + muonStubs.push_back(stub); } - ObjectRefBxCollection muonTracks; - // BXVector muonTracks; - - Handle > bmtfHandle; - iEvent.getByToken(bmtfTracks_, bmtfHandle); - Handle > emtfHandle; - iEvent.getByToken(emtfTracks_, emtfHandle); - Handle > omtfHandle; - iEvent.getByToken(omtfTracks_, omtfHandle); - - for (int bx = bxMin_; bx <= bxMax_; ++bx) { - if (bx >= bmtfHandle->getFirstBX() && bx <= bmtfHandle->getLastBX()) - for (size_t i = 0; i < bmtfHandle->size(bx); ++i) { - RegionalMuonCandRef muon(bmtfHandle, i); - muonTracks.push_back(bx, muon); - } - if (bx >= omtfHandle->getFirstBX() && bx <= omtfHandle->getLastBX()) - for (size_t i = 0; i < omtfHandle->size(bx); ++i) { - RegionalMuonCandRef muon(omtfHandle, i); - muonTracks.push_back(bx, muon); - } - if (bx >= emtfHandle->getFirstBX() && bx <= emtfHandle->getLastBX()) - for (size_t i = 0; i < emtfHandle->size(bx); ++i) { - RegionalMuonCandRef muon(emtfHandle, i); - muonTracks.push_back(bx, muon); - } - } - - std::vector out = node_->processEvent(tracks, muonTracks, stubs); + std::vector out = tps_->processEvent(tracks, muonStubs); std::unique_ptr > out1 = std::make_unique >(out); iEvent.put(std::move(out1)); } // ------------ method called once each stream before processing any runs, lumis or events ------------ -void Phase2L1TGMTProducer::beginStream(edm::StreamID) {} +void Phase2L1TGMTTkMuonProducer::beginStream(edm::StreamID) {} // ------------ method called once each stream after processing all runs, lumis and events ------------ -void Phase2L1TGMTProducer::endStream() {} +void Phase2L1TGMTTkMuonProducer::endStream() {} -void Phase2L1TGMTProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { +void Phase2L1TGMTTkMuonProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { //The following says we do not know what parameters are allowed so do no validation // Please change this to state exactly what you do use, even if it is no parameters edm::ParameterSetDescription desc; @@ -133,4 +98,4 @@ void Phase2L1TGMTProducer::fillDescriptions(edm::ConfigurationDescriptions& desc } //define this as a plug-in -DEFINE_FWK_MODULE(Phase2L1TGMTProducer); +DEFINE_FWK_MODULE(Phase2L1TGMTTkMuonProducer); diff --git a/L1Trigger/Phase2L1GMT/plugins/ROITempAssociator.h b/L1Trigger/Phase2L1GMT/plugins/ROITempAssociator.h deleted file mode 100644 index 633064697db20..0000000000000 --- a/L1Trigger/Phase2L1GMT/plugins/ROITempAssociator.h +++ /dev/null @@ -1,130 +0,0 @@ -#ifndef PHASE2GMT_TEMPORARY_ASSOCIATOR -#define PHASE2GMT_TEMPORARY_ASSOCIATOR - -#include "ap_int.h" -#include "MuonROI.h" -#include "DataFormats/L1TMuonPhase2/interface/MuonStub.h" -#include "FWCore/ParameterSet/interface/ParameterSet.h" - -namespace Phase2L1GMT { - - class ROITempAssociator { - public: - ROITempAssociator(const edm::ParameterSet& iConfig) {} - ~ROITempAssociator() {} - - std::vector associate(int bx, - const l1t::ObjectRefBxCollection& muons, - const l1t::MuonStubRefVector& stubs) { - std::vector out; - l1t::MuonStubRefVector usedStubs; - - if (muons.size() > 0) { - for (unsigned int i = 0; i < muons.size(bx); ++i) { - const l1t::RegionalMuonCandRef& mu = muons.at(bx, i); - uint pt = mu->hwPt(); - uint charge = mu->hwSign(); - - float eta = mu->hwEta() * 0.010875; - - int globalPhi = 0; - if (mu->trackFinderType() == l1t::bmtf) { - globalPhi = mu->processor() * 48 + mu->hwPhi() - 24; - } else { - globalPhi = mu->processor() * 96 + mu->hwPhi() + 24; - } - - float phi = globalPhi * 2 * M_PI / 576.0; - if (phi > (M_PI)) - phi = phi - 2 * M_PI; - else if (phi < (-M_PI)) - phi = phi + 2 * M_PI; - - MuonROI roi(bx, charge, pt, 1); - roi.setMuonRef(mu); - l1t::MuonStubRefVector cleanedStubs = clean(stubs, usedStubs); - - for (unsigned int layer = 0; layer <= 4; ++layer) { - l1t::MuonStubRefVector selectedStubs = selectLayerBX(cleanedStubs, bx, layer); - int bestStubINT = -1; - float dPhi = 1000.0; - - for (uint i = 0; i < selectedStubs.size(); ++i) { - const l1t::MuonStubRef& stub = selectedStubs[i]; - float deltaPhi = (stub->quality() & 0x1) ? stub->offline_coord1() - phi : stub->offline_coord2() - phi; - if (deltaPhi > M_PI) - deltaPhi = deltaPhi - 2 * M_PI; - else if (deltaPhi < -M_PI) - deltaPhi = deltaPhi + 2 * M_PI; - deltaPhi = fabs(deltaPhi); - float deltaEta = (stub->etaQuality() == 0 || (stub->etaQuality() & 0x1)) - ? fabs(stub->offline_eta1() - eta) - : fabs(stub->offline_eta2() - eta); - if (deltaPhi < (M_PI / 6.0) && deltaEta < 0.3 && deltaPhi < dPhi) { - dPhi = deltaPhi; - bestStubINT = i; - } - } - if (bestStubINT >= 0) { - roi.addStub(selectedStubs[bestStubINT]); - usedStubs.push_back(selectedStubs[bestStubINT]); - } - } - if (out.size() < 16 && !roi.stubs().empty()) - out.push_back(roi); - } - } - //Now the stubs only . Find per layer - - l1t::MuonStubRefVector cleanedStubs = clean(stubs, usedStubs); - - while (!cleanedStubs.empty()) { - MuonROI roi(bx, 0, 0, 0); - roi.addStub(cleanedStubs[0]); - usedStubs.push_back(cleanedStubs[0]); - for (unsigned int layer = 0; layer <= 4; ++layer) { - if (layer == cleanedStubs[0]->tfLayer()) - continue; - l1t::MuonStubRefVector selectedStubs = selectLayerBX(cleanedStubs, bx, layer); - if (!selectedStubs.empty()) { - roi.addStub(selectedStubs[0]); - usedStubs.push_back(selectedStubs[0]); - } - } - if (!roi.stubs().empty()) - if (out.size() < 16) - out.push_back(roi); - cleanedStubs = clean(cleanedStubs, usedStubs); - } - return out; - } - - private: - l1t::MuonStubRefVector selectLayerBX(const l1t::MuonStubRefVector& all, int bx, uint layer) { - l1t::MuonStubRefVector out; - for (const auto& stub : all) { - if (stub->bxNum() == bx && stub->tfLayer() == layer) - out.push_back(stub); - } - return out; - } - - l1t::MuonStubRefVector clean(const l1t::MuonStubRefVector& all, const l1t::MuonStubRefVector& used) { - l1t::MuonStubRefVector out; - for (const auto& stub : all) { - bool keep = true; - for (const auto& st : used) { - if (st == stub) { - keep = false; - break; - } - } - if (keep) - out.push_back(stub); - } - return out; - } - }; -} // namespace Phase2L1GMT - -#endif diff --git a/L1Trigger/Phase2L1GMT/plugins/TrackConverter.h b/L1Trigger/Phase2L1GMT/plugins/TrackConverter.h deleted file mode 100644 index d175f34da179c..0000000000000 --- a/L1Trigger/Phase2L1GMT/plugins/TrackConverter.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef PHASE2GMT_TRACKCONVERTER -#define PHASE2GMT_TRACKCONVERTER - -#include "ConvertedTTTrack.h" -#include "Constants.h" -#include "DataFormats/L1TMuonPhase2/interface/TrackerMuon.h" -#include "FWCore/ParameterSet/interface/ParameterSet.h" - -namespace Phase2L1GMT { - - class TrackConverter { - public: - TrackConverter(const edm::ParameterSet& iConfig) : verbose_(iConfig.getParameter("verbose")) {} - ~TrackConverter() {} - - std::vector convertTracks(const std::vector >& tracks) { - std::vector out; - out.reserve(tracks.size()); - for (const auto& t : tracks) - out.push_back(convert(t)); - return out; - } - - private: - int verbose_; - typedef ap_uint<96> wordtype; - - uint generateQuality(const edm::Ptr >& track) { return 1; } - - uint ptLookup(uint absCurv) { - for (auto i : ptShifts) { - if (absCurv >= uint(i[0]) && absCurv < uint(i[1])) { - if (i[2] < 0) - return i[4]; - else - return (absCurv >> i[2]) + i[3]; - } - } - return 0; - } - - uint etaLookup(uint absTanL) { - for (auto i : etaShifts) { - if (absTanL >= uint(i[0]) && absTanL < uint(i[1])) { - if (i[2] < 0) - return i[4]; - else - return (absTanL >> i[2]) + i[3]; - } - } - return 0; - } - - ConvertedTTTrack convert(const edm::Ptr >& track) { - uint charge = (track->rInv() < 0) ? 1 : 0; - int curvature = track->rInv() * (1 << (BITSTTCURV - 1)) / maxCurv_; - int phi = track->phi() * (1 << (BITSPHI - 1)) / (M_PI); - int tanLambda = track->tanL() * (1 << (BITSTTTANL - 1)) / maxTanl_; - int z0 = track->z0() * (1 << (BITSZ0 - 1)) / maxZ0_; - int d0 = track->d0() * (1 << (BITSD0 - 1)) / maxD0_; - //calculate pt - uint absCurv = curvature > 0 ? (curvature) : (-curvature); - uint pt = ptLUT[ptLookup(absCurv)]; - uint quality = generateQuality(track); - uint absTanL = tanLambda > 0 ? (tanLambda) : (-tanLambda); - uint absEta = etaLUT[etaLookup(absTanL)]; - int eta = tanLambda > 0 ? (absEta) : (-absEta); - - ap_int phiSec = ap_int(phi) - - ap_int((track->phiSector() * 40 * M_PI / 180.) * (1 << (BITSPHI - 1)) / (M_PI)); - ap_int phiCorrected = ap_int(phiSec + track->phiSector() * 910); - - wordtype word = 0; - int bstart = 0; - bstart = wordconcat(word, bstart, curvature, BITSTTCURV); - bstart = wordconcat(word, bstart, phiSec, BITSTTPHI); - bstart = wordconcat(word, bstart, tanLambda, BITSTTTANL); - bstart = wordconcat(word, bstart, z0, BITSZ0); - bstart = wordconcat(word, bstart, d0, BITSD0); - bstart = wordconcat(word, bstart, uint(track->chi2()), 4); - - ConvertedTTTrack convertedTrack(charge, curvature, absEta, pt, eta, phiCorrected.to_int(), z0, d0, quality, word); - convertedTrack.setOfflineQuantities(track->momentum().transverse(), track->eta(), track->phi()); - if (verbose_) - convertedTrack.print(); - convertedTrack.setTrkPtr(track); - return convertedTrack; - } - }; -} // namespace Phase2L1GMT - -#endif diff --git a/L1Trigger/Phase2L1GMT/plugins/TrackMuonMatchAlgorithm.h b/L1Trigger/Phase2L1GMT/plugins/TrackMuonMatchAlgorithm.h deleted file mode 100644 index 30f3ad6d8a3f5..0000000000000 --- a/L1Trigger/Phase2L1GMT/plugins/TrackMuonMatchAlgorithm.h +++ /dev/null @@ -1,626 +0,0 @@ -#ifndef PHASE2GMT_TRACKMUONMATCHALGO -#define PHASE2GMT_TRACKMUONMATCHALGO - -#include "DataFormats/L1TrackTrigger/interface/TTTrack.h" -#include "DataFormats/L1TrackTrigger/interface/TTTrack_TrackWord.h" -#include "DataFormats/L1TrackTrigger/interface/TTTypes.h" -#include "DataFormats/L1TMuonPhase2/interface/MuonStub.h" -#include "DataFormats/L1TMuonPhase2/interface/TrackerMuon.h" -#include "DataFormats/L1TMuon/interface/RegionalMuonCand.h" -#include "DataFormats/L1TMuon/interface/RegionalMuonCandFwd.h" -#include "DataFormats/L1Trigger/interface/L1TObjComparison.h" -#include "TrackConverter.h" -#include "PreTrackMatchedMuon.h" -#include "FWCore/ParameterSet/interface/ParameterSet.h" -#include "MuonROI.h" -#include "ConvertedTTTrack.h" -#include "Constants.h" -#include - -namespace Phase2L1GMT { - - const unsigned int PHIDIVIDER = 1 << (BITSPHI - BITSSTUBCOORD); - const unsigned int ETADIVIDER = 1 << (BITSETA - BITSSTUBETA); - - typedef struct { - ap_int coord1; - ap_uint sigma_coord1; - ap_int coord2; - ap_uint sigma_coord2; - ap_int eta; - ap_uint sigma_eta1; - ap_uint sigma_eta2; - ap_uint<1> valid; - ap_uint<1> is_barrel; - } propagation_t; - - typedef struct { - ap_uint quality; - ap_uint id; - ap_uint<1> valid; - bool isGlobal; - l1t::RegionalMuonCandRef muRef; - l1t::MuonStubRef stubRef; - - } match_t; - - class TrackMuonMatchAlgorithm { - public: - TrackMuonMatchAlgorithm(const edm::ParameterSet& iConfig) : verbose_(iConfig.getParameter("verbose")) {} - - ~TrackMuonMatchAlgorithm() {} - - std::vector processNonant(const std::vector& convertedTracks, - const std::vector& rois) { - std::vector preMuons; - for (const auto& track : convertedTracks) { - PreTrackMatchedMuon mu = processTrack(track, rois); - if (mu.valid() && preMuons.size() < 16) - preMuons.push_back(mu); - } - std::vector cleanedMuons = clean(preMuons); - return cleanedMuons; - } - - std::vector cleanNeighbor(const std::vector& muons, - const std::vector& muonsPrevious, - const std::vector& muonsNext, - bool equality) { - std::vector out; - - if (muons.empty()) - return out; - - if (verbose_ == 1) { - printf("-----Cleaning Up Muons in the neighbours\n"); - printf("Before:\n"); - } - - for (uint i = 0; i < muons.size(); ++i) { - if (verbose_ == 1) { - muons[i].print(); - } - ap_uint<5> mask = 0x1f; - for (uint j = 0; j < muonsPrevious.size(); ++j) { - mask = mask & cleanMuon(muons[i], muonsPrevious[j], equality); - } - for (uint j = 0; j < muonsNext.size(); ++j) { - mask = mask & cleanMuon(muons[i], muonsNext[j], equality); - } - if (mask) { - if (verbose_ == 1) - printf("kept\n"); - out.push_back(muons[i]); - } else { - if (verbose_ == 1) - printf("discarded\n"); - } - } - return out; - } - - std::vector convert(std::vector& muons, uint maximum) { - std::vector out; - for (const auto& mu : muons) { - if (out.size() == maximum) - break; - l1t::TrackerMuon muon(mu.trkPtr(), mu.charge(), mu.pt(), mu.eta(), mu.phi(), mu.z0(), mu.d0(), mu.quality()); - muon.setMuonRef(mu.muonRef()); - for (const auto& stub : mu.stubs()) - muon.addStub(stub); - out.push_back(muon); - if (verbose_ == 1) { - printf("Final Muon:"); - muon.print(); - } - } - return out; - } - - bool outputGT(std::vector& muons) { - for (auto& mu : muons) { - wordtype word1 = 0; - wordtype word2 = 0; - - int bstart = 0; - bstart = wordconcat(word1, bstart, mu.hwPt(), BITSGTPT); - bstart = wordconcat(word1, bstart, mu.hwPhi(), BITSGTPHI); - bstart = wordconcat(word1, bstart, mu.hwEta(), BITSGTETA); - bstart = wordconcat(word1, bstart, mu.hwZ0(), BITSGTZ0); - bstart = wordconcat(word1, bstart, (mu.hwD0() >> 2), BITSGTD0); - - bstart = 0; - bstart = wordconcat(word2, bstart, mu.hwCharge(), 1); - bstart = wordconcat(word2, bstart, mu.hwQual(), BITSGTQUAL); - bstart = wordconcat(word2, bstart, mu.hwIso(), BITSGTISO); - bstart = wordconcat(word2, bstart, mu.hwBeta(), BITSGTBETA); - - std::array wordout = {{word1, word2}}; - mu.setWord(wordout); - } - return true; - } - - std::vector sort(std::vector& muons, uint maximum) { - if (muons.size() < 2) - return muons; - - std::sort(muons.begin(), muons.end(), [](l1t::TrackerMuon a, l1t::TrackerMuon b) { return a.hwPt() > b.hwPt(); }); - std::vector out; - for (unsigned int i = 0; i < muons.size(); ++i) { - out.push_back(muons[i]); - if (i == (maximum - 1)) - break; - } - - return out; - } - - private: - int verbose_; - - propagation_t propagate(const ConvertedTTTrack& track, uint layer) { - ap_uint prop_coord1 = 0; - ap_uint prop_coord2 = 0; - ap_uint res0_coord1 = 0; - ap_uint res1_coord1 = 0; - ap_uint res0_coord2 = 0; - ap_uint res1_coord2 = 0; - ap_uint res0_eta1 = 0; - ap_uint res1_eta = 0; - ap_uint res0_eta2 = 0; - ap_uint<1> is_barrel = 0; - - uint reducedAbsEta = track.abseta() / 8; - - if (layer == 0) { - prop_coord1 = lt_prop_coord1_0[reducedAbsEta]; - prop_coord2 = lt_prop_coord2_0[reducedAbsEta]; - res0_coord1 = lt_res0_coord1_0[reducedAbsEta]; - res1_coord1 = lt_res1_coord1_0[reducedAbsEta]; - res0_coord2 = lt_res0_coord2_0[reducedAbsEta]; - res1_coord2 = lt_res1_coord2_0[reducedAbsEta]; - res0_eta1 = lt_res0_eta1_0[reducedAbsEta]; - res1_eta = lt_res1_eta_0[reducedAbsEta]; - res0_eta2 = lt_res0_eta2_0[reducedAbsEta]; - is_barrel = reducedAbsEta < barrelLimit0_ ? 1 : 0; - } else if (layer == 1) { - prop_coord1 = lt_prop_coord1_1[reducedAbsEta]; - prop_coord2 = lt_prop_coord2_1[reducedAbsEta]; - res0_coord1 = lt_res0_coord1_1[reducedAbsEta]; - res1_coord1 = lt_res1_coord1_1[reducedAbsEta]; - res0_coord2 = lt_res0_coord2_1[reducedAbsEta]; - res1_coord2 = lt_res1_coord2_1[reducedAbsEta]; - res0_eta1 = lt_res0_eta1_1[reducedAbsEta]; - res1_eta = lt_res1_eta_1[reducedAbsEta]; - res0_eta2 = lt_res0_eta2_1[reducedAbsEta]; - is_barrel = reducedAbsEta < barrelLimit1_ ? 1 : 0; - - } else if (layer == 2) { - prop_coord1 = lt_prop_coord1_2[reducedAbsEta]; - prop_coord2 = lt_prop_coord2_2[reducedAbsEta]; - res0_coord1 = lt_res0_coord1_2[reducedAbsEta]; - res1_coord1 = lt_res1_coord1_2[reducedAbsEta]; - res0_coord2 = lt_res0_coord2_2[reducedAbsEta]; - res1_coord2 = lt_res1_coord2_2[reducedAbsEta]; - res0_eta1 = lt_res0_eta1_2[reducedAbsEta]; - res1_eta = lt_res1_eta_2[reducedAbsEta]; - res0_eta2 = lt_res0_eta2_2[reducedAbsEta]; - is_barrel = reducedAbsEta < barrelLimit2_ ? 1 : 0; - - } else if (layer == 3) { - prop_coord1 = lt_prop_coord1_3[reducedAbsEta]; - prop_coord2 = lt_prop_coord2_3[reducedAbsEta]; - res0_coord1 = lt_res0_coord1_3[reducedAbsEta]; - res1_coord1 = lt_res1_coord1_3[reducedAbsEta]; - res0_coord2 = lt_res0_coord2_3[reducedAbsEta]; - res1_coord2 = lt_res1_coord2_3[reducedAbsEta]; - res0_eta1 = lt_res0_eta1_3[reducedAbsEta]; - res1_eta = lt_res1_eta_3[reducedAbsEta]; - res0_eta2 = lt_res0_eta2_3[reducedAbsEta]; - is_barrel = reducedAbsEta < barrelLimit3_ ? 1 : 0; - - } else if (layer == 4) { - prop_coord1 = lt_prop_coord1_4[reducedAbsEta]; - prop_coord2 = lt_prop_coord2_4[reducedAbsEta]; - res0_coord1 = lt_res0_coord1_4[reducedAbsEta]; - res1_coord1 = lt_res1_coord1_4[reducedAbsEta]; - res0_coord2 = lt_res0_coord2_4[reducedAbsEta]; - res1_coord2 = lt_res1_coord2_4[reducedAbsEta]; - res0_eta1 = lt_res0_eta1_4[reducedAbsEta]; - res1_eta = lt_res1_eta_4[reducedAbsEta]; - res0_eta2 = lt_res0_eta2_4[reducedAbsEta]; - is_barrel = 0; - } - - propagation_t out; - ap_int curvature = track.curvature(); - ap_int phi = track.phi(); - ap_int c1kFull = prop_coord1 * curvature; - ap_int c1k = (c1kFull) / 1024; - ap_int coord1 = phi - c1k; - - out.coord1 = coord1 / PHIDIVIDER; - - ap_int c2kFull = prop_coord2 * curvature; - - ap_int c2k = (c2kFull) / 1024; - if (is_barrel) - out.coord2 = -c2k / PHIDIVIDER; - else - out.coord2 = (phi - c2k) / PHIDIVIDER; - - ap_int eta = track.eta(); - out.eta = eta / ETADIVIDER; - - ap_uint<2 * BITSTTCURV - 2> curvature2All = curvature * curvature; - ap_uint curvature2 = curvature2All / 2; - - //Remember to change emulator with new k2 - ap_uint rescoord1k = (res1_coord1 * curvature2) >> 23; - ap_ufixed sigma_coord1 = res0_coord1 + rescoord1k; - out.sigma_coord1 = ap_uint(sigma_coord1); - - ap_uint rescoord2k = (res1_coord2 * curvature2) >> 23; - ap_ufixed sigma_coord2 = res0_coord2 + rescoord2k; - out.sigma_coord2 = ap_uint(sigma_coord2); - - ap_uint resetak = (res1_eta * curvature2) >> 23; - ap_ufixed sigma_eta1 = res0_eta1 + resetak; - out.sigma_eta1 = ap_uint(sigma_eta1); - ap_ufixed sigma_eta2 = res0_eta2 + resetak; - out.sigma_eta2 = ap_uint(sigma_eta2); - out.valid = 1; - out.is_barrel = is_barrel; - - if (verbose_ == 1) - - printf("Propagating to layer %d:is barrel=%d coords=%d+-%d , %d +-%d etas = %d +- %d +-%d\n", - int(layer), - out.is_barrel.to_int(), - out.coord1.to_int(), - out.sigma_coord1.to_int(), - out.coord2.to_int(), - out.sigma_coord2.to_int(), - out.eta.to_int(), - out.sigma_eta1.to_int(), - out.sigma_eta2.to_int()); - - return out; - } - - ap_uint deltaEta(const ap_int& eta1, const ap_int& eta2) { - ap_fixed dEta = eta1 - eta2; - if (dEta < 0) - return ap_uint(-dEta); - else - return ap_uint(dEta); - } - - ap_uint deltaCoord(const ap_int& phi1, const ap_int& phi2) { - ap_int dPhiRoll = phi1 - phi2; - ap_ufixed dPhi; - if (dPhiRoll < 0) - dPhi = ap_ufixed(-dPhiRoll); - else - dPhi = ap_ufixed(dPhiRoll); - - return ap_uint(dPhi); - } - - match_t match(const propagation_t prop, const l1t::MuonStubRef& stub) { - if (verbose_ == 1) { - printf("Matching to "); - stub->print(); - } - //Matching of Coord1 - ap_uint<1> coord1Matched; - ap_uint deltaCoord1 = deltaCoord(prop.coord1, stub->coord1()); - if (deltaCoord1 <= prop.sigma_coord1 && (stub->quality() & 0x1)) { - coord1Matched = 1; - } else { - coord1Matched = 0; - } - if (verbose_ == 1) - printf("Coord1 matched=%d delta=%d res=%d\n", - coord1Matched.to_int(), - deltaCoord1.to_int(), - prop.sigma_coord1.to_int()); - - //Matching of Coord2 - ap_uint<1> coord2Matched; - ap_uint deltaCoord2 = deltaCoord(prop.coord2, stub->coord2()); - if (deltaCoord2 <= prop.sigma_coord2 && (stub->quality() & 0x2)) { - coord2Matched = 1; - } else { - coord2Matched = 0; - } - if (verbose_ == 1) - printf("Coord2 matched=%d delta=%d res=%d\n", - coord2Matched.to_int(), - deltaCoord2.to_int(), - prop.sigma_coord2.to_int()); - - //Matching of Eta1 - - ap_uint<1> eta1Matched; - - //if we have really bad quality[Barrel no eta] - //increase the resolution - ap_ufixed prop_sigma_eta1; - if (stub->etaQuality() == 0) - prop_sigma_eta1 = prop.sigma_eta1 + 6; - else - prop_sigma_eta1 = prop.sigma_eta1; - - ap_uint deltaEta1 = deltaEta(prop.eta, stub->eta1()); - if (deltaEta1 <= prop_sigma_eta1 && (stub->etaQuality() == 0 || (stub->etaQuality() & 0x1))) - eta1Matched = 1; - else - eta1Matched = 0; - - if (verbose_ == 1) - printf("eta1 matched=%d delta=%d res=%d\n", eta1Matched.to_int(), deltaEta1.to_int(), prop_sigma_eta1.to_int()); - - //Matching of Eta2 - - ap_uint<1> eta2Matched; - - ap_uint deltaEta2 = deltaEta(prop.eta, stub->eta2()); - if (deltaEta2 <= prop.sigma_eta2 && (stub->etaQuality() & 0x2)) - eta2Matched = 1; - else - eta2Matched = 0; - match_t out; - out.id = stub->id(); - - if (verbose_ == 1) - printf("eta2 matched=%d delta=%d res=%d\n", eta2Matched.to_int(), deltaEta2.to_int(), prop.sigma_eta2.to_int()); - - //if barrel, coord1 has to always be matched, coord2 maybe and eta1 is needed if etaQ=0 or then the one that depends on eta quality - if (prop.is_barrel) { - out.valid = (coord1Matched == 1 && (eta1Matched == 1 || eta2Matched == 1)); - if (out.valid == 0) { - out.quality = 0; - } else { - out.quality = 32 - deltaCoord1; - if (coord2Matched == 1) - out.quality += 32 - deltaCoord2; - } - } - //if endcap each coordinate is independent except the case where phiQuality=1 and etaQuality==3 - else { - bool match1 = (coord1Matched == 1 && eta1Matched == 1); - bool match2 = (coord2Matched == 1 && eta2Matched == 1); - bool match3 = - (coord1Matched == 1 && (eta1Matched || eta2Matched) && stub->etaQuality() == 3 && stub->quality() == 1); - out.valid = match1 || match2 || match3; - if (out.valid == 0) - out.quality = 0; - else { - out.quality = 0; - if (match1 || match3) - out.quality += 32 - deltaCoord1; - if (match2) - out.quality += 32 - deltaCoord2; - } - } - if (verbose_ == 1) - printf("GlobalMatchQuality = %d\n", out.quality.to_int()); - out.stubRef = stub; - return out; - } - - match_t propagateAndMatch(const ConvertedTTTrack& track, const l1t::MuonStubRef& stub) { - propagation_t prop = propagate(track, stub->tfLayer()); - return match(prop, stub); - } - - match_t getBest(const std::vector matches) { - match_t best = matches[0]; - for (const auto& m : matches) { - if (m.quality > best.quality) - best = m; - } - - return best; - } - - PreTrackMatchedMuon processTrack(const ConvertedTTTrack& track, const std::vector& rois) { - std::vector matchInfo0; - std::vector matchInfo1; - std::vector matchInfo2; - std::vector matchInfo3; - std::vector matchInfo4; - - if (verbose_ == 1 && !rois.empty()) { - printf("-----------processing new track----------"); - track.print(); - } - for (const auto& roi : rois) { - if (verbose_ == 1) { - printf("New ROI with %d stubs \n", int(roi.stubs().size())); - } - for (const auto& stub : roi.stubs()) { - match_t m = propagateAndMatch(track, stub); - if (m.valid == 1) { - if (roi.isGlobalMuon() && roi.muonRef().isNonnull()) { - m.isGlobal = true; - m.muRef = roi.muonRef(); - } - - if (stub->tfLayer() == 0) - matchInfo0.push_back(m); - else if (stub->tfLayer() == 1) - matchInfo1.push_back(m); - else if (stub->tfLayer() == 2) - matchInfo2.push_back(m); - else if (stub->tfLayer() == 3) - matchInfo3.push_back(m); - else if (stub->tfLayer() == 4) - matchInfo4.push_back(m); - } - } - } - - ap_ufixed<6, 6, AP_TRN_ZERO, AP_SAT_SYM> ptPenalty = ap_ufixed<6, 6, AP_TRN_ZERO, AP_SAT_SYM>(track.pt() / 32); - - ap_uint quality = 0; - PreTrackMatchedMuon muon(track.charge(), track.pt(), track.eta(), track.phi(), track.z0(), track.d0()); - - if (!matchInfo0.empty()) { - match_t b = getBest(matchInfo0); - if (b.valid) { - muon.addStub(b.stubRef); - if (b.isGlobal) - muon.addMuonRef(b.muRef); - quality += b.quality; - } - } - if (!matchInfo1.empty()) { - match_t b = getBest(matchInfo1); - if (b.valid) { - muon.addStub(b.stubRef); - if (b.isGlobal) - muon.addMuonRef(b.muRef); - quality += b.quality; - } - } - if (!matchInfo2.empty()) { - match_t b = getBest(matchInfo2); - if (b.valid) { - muon.addStub(b.stubRef); - if (b.isGlobal) - muon.addMuonRef(b.muRef); - quality += b.quality; - } - } - if (!matchInfo3.empty()) { - match_t b = getBest(matchInfo3); - if (b.valid) { - muon.addStub(b.stubRef); - if (b.isGlobal) - muon.addMuonRef(b.muRef); - quality += b.quality; - } - } - if (!matchInfo4.empty()) { - match_t b = getBest(matchInfo4); - if (b.valid) { - muon.addStub(b.stubRef); - if (b.isGlobal) - muon.addMuonRef(b.muRef); - quality += b.quality; - } - } - - muon.setOfflineQuantities(track.offline_pt(), track.offline_eta(), track.offline_phi()); - muon.setTrkPtr(track.trkPtr()); - - ap_uint<8> etaAddr = muon.eta() < 0 ? ap_uint<8>(-muon.eta() / 256) : ap_uint<8>((muon.eta()) / 256); - ap_uint<8> ptAddr = muon.pt() > 4095 ? ap_uint<8>(15) : ap_uint<8>(muon.pt() / 256); - ap_uint<8> addr = ptAddr | (etaAddr << 4); - ap_uint<8> qualityCut = lt_tpsID[addr]; - - if (quality >= qualityCut) { - muon.setValid(true); - muon.setQuality(quality + ptPenalty); - } else { - muon.setValid(false); - muon.setQuality(0); - muon.resetGlobal(); - } - if (verbose_ == 1) - muon.print(); - - if (verbose_ == 1 && !rois.empty()) { //patterns for HLS - - printf("TPS %d", track.trkPtr()->phiSector()); - track.printWord(); - - for (uint i = 0; i < 16; ++i) { - if (rois.size() > i) { - rois[i].printROILine(); - } else { - printf("%08x", 0); - printf("%016lx", 0x1ff000000000000); - printf("%016lx", 0x1ff000000000000); - printf("%016lx", 0x1ff000000000000); - printf("%016lx", 0x1ff000000000000); - printf("%016lx", 0x1ff000000000000); - } - } - muon.printWord(); - printf("\n"); - } - return muon; - } - - ap_uint<5> cleanMuon(const PreTrackMatchedMuon& mu, const PreTrackMatchedMuon& other, bool eq) { - ap_uint<5> valid = 0; - ap_uint<5> overlap = 0; - if (mu.stubID0() != 511) { - valid = valid | 0x1; - if (mu.stubID0() == other.stubID0()) - overlap = overlap | 0x1; - } - if (mu.stubID1() != 511) { - valid = valid | 0x2; - if (mu.stubID1() == other.stubID1()) - overlap = overlap | 0x2; - } - if (mu.stubID2() != 511) { - valid = valid | 0x4; - if (mu.stubID2() == other.stubID2()) - overlap = overlap | 0x4; - } - if (mu.stubID3() != 511) { - valid = valid | 0x8; - if (mu.stubID3() == other.stubID3()) - overlap = overlap | 0x8; - } - if (mu.stubID4() != 511) { - valid = valid | 0x10; - if (mu.stubID4() == other.stubID4()) - overlap = overlap | 0x10; - } - - if (((mu.quality() < other.quality()) && (!eq)) || ((mu.quality() <= other.quality()) && (eq))) - return valid & (~overlap); - else - return valid; - } - - std::vector clean(std::vector& muons) { - std::vector out; - if (muons.empty()) - return out; - if (verbose_ == 1) { - printf("-----Cleaning Up Muons in the same Nonant\n"); - printf("Before:\n"); - } - for (uint i = 0; i < muons.size(); ++i) { - if (verbose_ == 1) - muons[i].print(); - - ap_uint<5> mask = 0x1f; - for (uint j = 0; j < muons.size(); ++j) { - if (i == j) - continue; - mask = mask & cleanMuon(muons[i], muons[j], false); - } - if (mask) { - if (verbose_ == 1) - printf("kept\n"); - out.push_back(muons[i]); - } else { - if (verbose_ == 1) - printf("discarded\n"); - } - } - return out; - } - }; -} // namespace Phase2L1GMT - -#endif diff --git a/L1Trigger/Phase2L1GMT/python/gmtFwdMuons_cfi.py b/L1Trigger/Phase2L1GMT/python/gmtFwdMuons_cfi.py new file mode 100644 index 0000000000000..29edd9d6ffcbe --- /dev/null +++ b/L1Trigger/Phase2L1GMT/python/gmtFwdMuons_cfi.py @@ -0,0 +1,9 @@ +import FWCore.ParameterSet.Config as cms + +gmtFwdMuons = cms.EDProducer( + 'Phase2L1TGMTFwdMuonTranslator', + stubs = cms.InputTag('gmtStubs','tps'), + omtfTracks = cms.InputTag('simOmtfPhase2Digis', 'OMTF'), + emtfTracks = cms.InputTag('simEmtfDigisPhase2'), + +) diff --git a/L1Trigger/Phase2L1GMT/python/gmtKMTFMuons_cfi.py b/L1Trigger/Phase2L1GMT/python/gmtKMTFMuons_cfi.py new file mode 100644 index 0000000000000..b328e18adac84 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/python/gmtKMTFMuons_cfi.py @@ -0,0 +1,73 @@ +import FWCore.ParameterSet.Config as cms + + +gmtKMTFMuons = cms.EDProducer('Phase2L1TGMTKMTFProducer', + stubs = cms.InputTag('gmtStubs','kmtf'), + verbose = cms.int32(0), + algo = cms.PSet( + verbose = cms.bool(False), + lutFile = cms.string("L1Trigger/Phase2L1GMT/data/packedGainLUTs.root"), + initialK = cms.vdouble(-0.4576229536749278, -0.6364802777566145, -1.0305030909883524, -1.7272067322624118), + initialK2 = cms.vdouble(-6.442002637356136e-05, -9.582709649965545e-05, -0.0002741064246218815, -0.0014910074450869175), + eLoss = cms.vdouble(6.77765e-05,0,0,0), + + aPhi = cms.vdouble(5.6533349391874275, 0.03477876333443834, 0.032506522838098864, 0.024752809174909053), + aPhiB = cms.vdouble(-2.02, -0.2994087741381382, -0.4033668521165302, -0.3592231728688621), + aPhiBNLO = cms.vdouble(9.04133e-05,0,0,0), + + bPhi = cms.vdouble(-1,.18245,.20898,.17286), + bPhiB = cms.vdouble(-1,1.18245,1.20898,1.17286), + phiAt2 = cms.double(0.17917991867483288), + etaLUT0 = cms.vdouble(8.946,7.508,6.279,6.399), + etaLUT1 = cms.vdouble(0.159,0.116,0.088,0.128), + + #Chi2 Calculation coefficients + + chiSquareDisp1 = cms.vdouble(0.241,0.575,0.892), + chiSquareDisp2 = cms.vdouble(0.347,0.707), + chiSquareDisp3 = cms.vdouble(0.336), + + chiSquareErrADisp1 = cms.vint32(21,23,45), + chiSquareErrADisp2 = cms.vint32(14,28), + chiSquareErrADisp3 = cms.vint32(29), + chiSquareErrBDisp1 = cms.vdouble(5*0.108,5*0.161,5*0.148), + chiSquareErrBDisp2 = cms.vdouble(5*0.146,5*0.189), + chiSquareErrBDisp3 = cms.vdouble(5*0.100), + + chiSquarePrompt1 = cms.vdouble(-0.323,-0.508,-0.578), + chiSquarePrompt2 = cms.vdouble(-0.228,-0.343), + chiSquarePrompt3 = cms.vdouble(-0.100), + + chiSquareErrAPrompt1 = cms.vint32(21,24,33), + chiSquareErrAPrompt2 = cms.vint32(18,14), + chiSquareErrAPrompt3 = cms.vint32(21), + chiSquareErrBPrompt1 = cms.vdouble(5*0.009,5*0.016,5*0.012), + chiSquareErrBPrompt2 = cms.vdouble(5*0.013,5*0.055), + chiSquareErrBPrompt3 = cms.vdouble(5*0.01), + chiSquareCutDispPattern = cms.vint32(), + chiSquareCutOffDisp = cms.vint32(), + chiSquareCutDisp = cms.vint32(), + chiSquareCutPromptPattern = cms.vint32(), + chiSquareCutOffPrompt = cms.vint32(), + chiSquareCutPrompt = cms.vint32(), + combos4=cms.vint32(9,10,11,12,13,14,15), + combos3=cms.vint32(5,6,7), + combos2=cms.vint32(3), + combos1=cms.vint32(), #for future possible usage + useOfflineAlgo = cms.bool(False), + ###Only for the offline algo -not in firmware -------------------- + mScatteringPhi = cms.vdouble(0.1169021113298598, 0.00016777763395543814, 0.0004322078772344548, 0.00024985881710722107), + mScatteringPhiB = cms.vdouble(.0522762, 0.01762000062188365, 0.03508319015441297, 0.03126825551530328), + pointResolutionPhi = cms.double(1.), + pointResolutionPhiB = cms.double(12493.7429036), + pointResolutionPhiBH = cms.vdouble(19925.62953113343, 15583.06791339368, 10258.11768352221, 15462.112839170433), + pointResolutionPhiBL = cms.vdouble(161519.85395846734, 155051.58394241595, 149693.88179343447, 174896.46766622085), + pointResolutionVertex = cms.double(1.), + curvResolution1 = cms.vdouble(1, 2.36097e+03, 8.73003e+02, 2.58138e5), + curvResolution2 = cms.vdouble(1, 4.903692e+00, 4.87941e+01, 0)), + Nprompt = cms.uint32(12), + Ndisplaced = cms.uint32(12) +) + + + diff --git a/L1Trigger/Phase2L1GMT/python/gmtSAMuons_cfi.py b/L1Trigger/Phase2L1GMT/python/gmtSAMuons_cfi.py new file mode 100644 index 0000000000000..ca4559d026428 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/python/gmtSAMuons_cfi.py @@ -0,0 +1,8 @@ +import FWCore.ParameterSet.Config as cms +gmtSAMuons = cms.EDProducer('Phase2L1TGMTSAMuonGhostCleaner', + barrelPrompt = cms.InputTag('gmtKMTFMuons:prompt'), + barrelDisp = cms.InputTag('gmtKMTFMuons:displaced'), + forwardPrompt = cms.InputTag('gmtFwdMuons:prompt'), + forwardDisp = cms.InputTag('gmtFwdMuons:displaced') +) + diff --git a/L1Trigger/Phase2L1GMT/python/gmtStubs_cfi.py b/L1Trigger/Phase2L1GMT/python/gmtStubs_cfi.py new file mode 100644 index 0000000000000..1e4f32896bc7f --- /dev/null +++ b/L1Trigger/Phase2L1GMT/python/gmtStubs_cfi.py @@ -0,0 +1,40 @@ +import FWCore.ParameterSet.Config as cms + +gmtStubs = cms.EDProducer("Phase2L1TGMTStubProducer", + verbose = cms.int32(0), + srcCSC = cms.InputTag("simCscTriggerPrimitiveDigis"), + srcDT = cms.InputTag("dtTriggerPhase2PrimitiveDigis"), + srcDTTheta = cms.InputTag("simDtTriggerPrimitiveDigis"), + srcRPC = cms.InputTag("simMuonRPCDigis"), + Endcap =cms.PSet( + verbose = cms.uint32(0), + minBX = cms.int32(0), + maxBX = cms.int32(0), + coord1LSB = cms.double(0.00076660156*8),#was 32 + eta1LSB = cms.double(7.68334e-04*32), + coord2LSB = cms.double(0.00076660156*8),# was 32 + eta2LSB = cms.double(7.68334e-04*32), + phiMatch = cms.double(0.05), + etaMatch = cms.double(0.1) + ), + Barrel = cms.PSet( + verbose = cms.int32(0),#2 for patterns + minPhiQuality = cms.int32(0),#was 0!!! + minThetaQuality = cms.int32(0), + minBX = cms.int32(0), + maxBX = cms.int32(0), + phiLSB = cms.double(2.3968450e-05), + phiBDivider = cms.int32(1), + etaLSB = cms.double(7.68334e-04*32), + eta_1 = cms.vint32(int(-1503/32),int(-1446/32),int(-1387/32),int(-1327/32),int(-1266/32),int(-1194/32),int(-1125/32),int(-985/32),int(-916/32),int(-839/32),int(-752/32),int(-670/32),int(-582/32),int(-489/32),int(-315/32),int(-213/32),int(-115/32),int(-49/32),int(49/32),int(115/32),int(213/32),int(315/32),int(489/32),int(582/32),int(670/32),int(752/32),int(839/32),int(916/32),int(985/32),int(1125/32),int(1194/32),int(1266/32),int(1327/32),int(1387/32),int(1446/32), 1503), + eta_2 = cms.vint32(int(-1334/32),int(-1279/32),int(-1227/32),int(-1168/32),int(-1109/32),int(-1044/32),int(-982/32),int(-861/32),int(-793/32),int(-720/32),int(-648/32),int(-577/32),int(-496/32),int(-425/32),int(-268/32),int(-185/32),int(-97/32),int(-51/32),int(51/32),int(97/32),int(185/32),int(268/32),int(425/32),int(496/32),int(577/32),int(648/32),int(720/32),int(793/32),int(861/32),int(982/32),int(1044/32),int(1109/32),int(1168/32),int(1227/32),int(1279/32),1334), + eta_3 = cms.vint32(int(-1148/32),int(-1110/32),int(-1051/32),int(-1004/32),int(-947/32),int(-895/32),int(-839/32),int(-728/32),int(-668/32),int(-608/32),int(-546/32),int(-485/32),int(-425/32),int(-366/32),int(-222/32),int(-155/32),int(-87/32),int(-40/32),int(40/32),int(87/32),int(155/32),int(222/32),int(366/32),int(425/32),int(485/32),int(546/32),int(608/32),int(668/32),int(728/32),int(839/32),int(895/32),int(947/32),int(1004/32),int(1051/32),int(1110/32), 1148), + + coarseEta_1 = cms.vint32(int(0/32),int(758/32),int(1336/32)), + coarseEta_2 = cms.vint32(int(0/32),int(653/32),int(1168/32)), + coarseEta_3 = cms.vint32(int(0/32),int(552/32),int(1001/32)), + coarseEta_4 = cms.vint32(int(0/32),int(478/32),int(878/32)), + phiOffset = cms.vint32(0,0,0,0) + ) +) + diff --git a/L1Trigger/Phase2L1GMT/python/gmtTkMuons_cfi.py b/L1Trigger/Phase2L1GMT/python/gmtTkMuons_cfi.py new file mode 100644 index 0000000000000..1a0704a5e2a85 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/python/gmtTkMuons_cfi.py @@ -0,0 +1,32 @@ +import FWCore.ParameterSet.Config as cms +gmtTkMuons = cms.EDProducer('Phase2L1TGMTTkMuonProducer', + srcTracks = cms.InputTag("l1tTTTracksFromTrackletEmulation:Level1TTTracks"), + srcStubs = cms.InputTag('gmtStubs:tps'), + minTrackStubs = cms.int32(4), + muonBXMin = cms.int32(0), + muonBXMax = cms.int32(0), + verbose = cms.int32(0), + trackConverter = cms.PSet( + verbose = cms.int32(0) + ), + trackMatching = cms.PSet( + verbose=cms.int32(0) + ), + isolation = cms.PSet( + AbsIsoThresholdL = cms.int32(160), + AbsIsoThresholdM = cms.int32(120), + AbsIsoThresholdT = cms.int32(80), + RelIsoThresholdL = cms.double(0.1), + RelIsoThresholdM = cms.double(0.05), + RelIsoThresholdT = cms.double(0.01), + verbose = cms.int32(0), + IsodumpForHLS = cms.int32(0), + ), + tauto3mu = cms.PSet() + +) + + + + + diff --git a/L1Trigger/Phase2L1GMT/python/gmt_cfi.py b/L1Trigger/Phase2L1GMT/python/gmt_cfi.py index 0c2008095889a..33e5b1a1e7ba8 100644 --- a/L1Trigger/Phase2L1GMT/python/gmt_cfi.py +++ b/L1Trigger/Phase2L1GMT/python/gmt_cfi.py @@ -1,81 +1,10 @@ -import FWCore.ParameterSet.Config as cms - -l1tGMTStubs = cms.EDProducer("Phase2L1TGMTStubProducer", - verbose = cms.int32(0), - srcCSC = cms.InputTag("simCscTriggerPrimitiveDigis"), - srcDT = cms.InputTag("dtTriggerPhase2PrimitiveDigis"), - srcDTTheta = cms.InputTag("simDtTriggerPrimitiveDigis"), - srcRPC = cms.InputTag("simMuonRPCDigis"), - Endcap =cms.PSet( - verbose = cms.uint32(0), - minBX = cms.int32(0), - maxBX = cms.int32(0), - coord1LSB = cms.double(0.00076660156*32), - eta1LSB = cms.double(7.68334e-04*32), - coord2LSB = cms.double(0.00076660156*32), - eta2LSB = cms.double(7.68334e-04*32), - phiMatch = cms.double(0.05), - etaMatch = cms.double(0.1) - ), - Barrel = cms.PSet( - verbose = cms.int32(0), - minPhiQuality = cms.int32(0),#was 5 - minThetaQuality = cms.int32(0), - minBX = cms.int32(0), - maxBX = cms.int32(0), - phiLSB = cms.double(0.00076660156*32), - phiBDivider = cms.int32(16), - etaLSB = cms.double(7.68334e-04*32), - eta_1 = cms.vint32(int(-1503/32),int(-1446/32),int(-1387/32),int(-1327/32),int(-1266/32),int(-1194/32),int(-1125/32),int(-985/32),int(-916/32),int(-839/32),int(-752/32),int(-670/32),int(-582/32),int(-489/32),int(-315/32),int(-213/32),int(-115/32),int(-49/32),int(49/32),int(115/32),int(213/32),int(315/32),int(489/32),int(582/32),int(670/32),int(752/32),int(839/32),int(916/32),int(985/32),int(1125/32),int(1194/32),int(1266/32),int(1327/32),int(1387/32),int(1446/32), 1503), - eta_2 = cms.vint32(int(-1334/32),int(-1279/32),int(-1227/32),int(-1168/32),int(-1109/32),int(-1044/32),int(-982/32),int(-861/32),int(-793/32),int(-720/32),int(-648/32),int(-577/32),int(-496/32),int(-425/32),int(-268/32),int(-185/32),int(-97/32),int(-51/32),int(51/32),int(97/32),int(185/32),int(268/32),int(425/32),int(496/32),int(577/32),int(648/32),int(720/32),int(793/32),int(861/32),int(982/32),int(1044/32),int(1109/32),int(1168/32),int(1227/32),int(1279/32),1334), - eta_3 = cms.vint32(int(-1148/32),int(-1110/32),int(-1051/32),int(-1004/32),int(-947/32),int(-895/32),int(-839/32),int(-728/32),int(-668/32),int(-608/32),int(-546/32),int(-485/32),int(-425/32),int(-366/32),int(-222/32),int(-155/32),int(-87/32),int(-40/32),int(40/32),int(87/32),int(155/32),int(222/32),int(366/32),int(425/32),int(485/32),int(546/32),int(608/32),int(668/32),int(728/32),int(839/32),int(895/32),int(947/32),int(1004/32),int(1051/32),int(1110/32), 1148), - - coarseEta_1 = cms.vint32(int(0/32),int(758/32),int(1336/32)), - coarseEta_2 = cms.vint32(int(0/32),int(653/32),int(1168/32)), - coarseEta_3 = cms.vint32(int(0/32),int(552/32),int(1001/32)), - coarseEta_4 = cms.vint32(int(0/32),int(478/32),int(878/32)), - phiOffset = cms.vint32(int(33/32),int(-8/32),int(+14/32),0) - ) - -) - - - - - -l1tGMTMuons = cms.EDProducer('Phase2L1TGMTProducer', - srcTracks = cms.InputTag("l1tTTTracksFromTrackletEmulation:Level1TTTracks"), - srcStubs = cms.InputTag('l1tGMTStubs'), - srcBMTF = cms.InputTag('simBmtfDigis','BMTF'), - srcEMTF = cms.InputTag('simEmtfDigis','EMTF'), - srcOMTF = cms.InputTag('simOmtfDigis','OMTF'), - minTrackStubs = cms.int32(4), - muonBXMin = cms.int32(0), - muonBXMax = cms.int32(0), - verbose = cms.int32(0), - trackConverter = cms.PSet( - verbose = cms.int32(0) - ), - roiTrackAssociator = cms.PSet( - verbose=cms.int32(0) - ), - trackMatching = cms.PSet( - verbose=cms.int32(0) - ), - isolation = cms.PSet( - AbsIsoThresholdL = cms.int32(160), - AbsIsoThresholdM = cms.int32(120), - AbsIsoThresholdT = cms.int32(80), - RelIsoThresholdL = cms.double(0.1), - RelIsoThresholdM = cms.double(0.05), - RelIsoThresholdT = cms.double(0.01), - verbose = cms.int32(0), - IsodumpForHLS = cms.int32(0), - ), - tauto3mu = cms.PSet() - -) - +from L1Trigger.Phase2L1GMT.gmtStubs_cfi import * +from L1Trigger.Phase2L1GMT.gmtKMTFMuons_cfi import * +from L1Trigger.Phase2L1GMT.gmtFwdMuons_cfi import * +from L1Trigger.Phase2L1GMT.gmtSAMuons_cfi import * +from L1Trigger.Phase2L1GMT.gmtTkMuons_cfi import * +l1tGMTStubs = cms.Sequence(gmtStubs) +l1tGMTMuons = cms.Sequence(gmtKMTFMuons*gmtFwdMuons*gmtSAMuons*gmtTkMuons) l1tGMTFilteredMuons = cms.EDProducer('Phase2L1TGMTFilter', srcMuons = cms.InputTag("l1tTkMuonsGmt",""), @@ -85,10 +14,3 @@ etaBE = cms.double(0.9) ) - - -l1tStandaloneMuons = cms.EDProducer('Phase2L1TGMTSAMuonProducer', - muonToken = cms.InputTag('simGmtStage2Digis'), - Nprompt = cms.uint32(12), - Ndisplaced = cms.uint32(12) - ) diff --git a/L1Trigger/Phase2L1GMT/src/KMTF.cc b/L1Trigger/Phase2L1GMT/src/KMTF.cc new file mode 100644 index 0000000000000..918554895b131 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/src/KMTF.cc @@ -0,0 +1,464 @@ +#include "L1Trigger/Phase2L1GMT/interface/KMTF.h" +using namespace Phase2L1GMT; + +KMTF::KMTF(int verbose, const edm::ParameterSet& iConfig) + : verbose_(verbose), trackMaker_(std::make_unique(iConfig)) {} + +KMTF::~KMTF() = default; + +std::pair, std::vector > KMTF::process( + const l1t::MuonStubRefVector& stubsAll, int bx, unsigned int MAXN) { + std::vector pretracksP2; + std::vector pretracksP3; + std::vector pretracksP4; + std::vector pretracksD2; + std::vector pretracksD3; + std::vector pretracksD4; + uint Nstubs4 = 0; + uint Nstubs3 = 0; + uint Nstubs2 = 0; + uint Nstubs1 = 0; + + l1t::MuonStubRefVector stubs4; + l1t::MuonStubRefVector stubs3; + l1t::MuonStubRefVector stubs2; + l1t::MuonStubRefVector stubs1; + + for (const auto& stub : stubsAll) { + if (stub->bxNum() != bx || stub->id() > 3) + continue; + if (!stub->isBarrel()) + continue; + + if (stub->depthRegion() == 4) { + if (Nstubs4 < MAXN) { + stubs4.push_back(stub); + Nstubs4++; + } + } + if (stub->depthRegion() == 3) { + if (Nstubs3 < MAXN) { + stubs3.push_back(stub); + Nstubs3++; + } + } + if (stub->depthRegion() == 2) { + if (Nstubs2 < MAXN) { + stubs2.push_back(stub); + Nstubs2++; + } + } + if (stub->depthRegion() == 1) { + if (Nstubs1 < MAXN) { + stubs1.push_back(stub); + Nstubs1++; + } + } + } + + //Sort the seeds by tag so that the emulator is aligned like the firmware + SeedSorter sorter; + if (stubs4.size() > 1) { + std::sort(stubs4.begin(), stubs4.end(), sorter); + } + if (stubs3.size() > 1) { + std::sort(stubs3.begin(), stubs3.end(), sorter); + } + if (stubs2.size() > 1) { + std::sort(stubs2.begin(), stubs2.end(), sorter); + } + if (stubs1.size() > 1) { + std::sort(stubs1.begin(), stubs1.end(), sorter); + } + + bool pre_patterns = (verbose_ > 1) && ((Nstubs4 + Nstubs3 + Nstubs2 + Nstubs1) > 2); + + //OK now process the data almost as in hardware + for (unsigned int i = 0; i < 32; ++i) { + //print the stubs taking into account + + bool patterns = pre_patterns && ((i < Nstubs4) || (i < Nstubs3) || (i << Nstubs2)); + + if (patterns) { + edm::LogInfo("KMTF") << "KMTFPattern " << std::flush; + if (i < Nstubs4) + edm::LogInfo("KMTF") << stubs4[0]->coord1() << " " << stubs4[0]->coord2() << " " << stubs4[0]->quality() << " " + << " 1 " << stubs4[0]->kmtf_address() << " 0 " << std::flush; + else + edm::LogInfo("KMTF") << "0 0 0 0 511 0 " << std::flush; + + if (i < Nstubs3) { + for (const auto& s : stubs3) { + edm::LogInfo("KMTF") << "" << s->coord1() << " " << s->coord2() << " " << s->quality() << " 1 " + << s->kmtf_address() << " 0 " << std::flush; + } + //pad with zeros + for (unsigned int j = stubs3.size(); j < 32; ++j) { + edm::LogInfo("KMTF") << "0 0 0 0 511 0 " << std::flush; + } + } else { + for (unsigned int j = stubs3.size(); j < 32; ++j) { + edm::LogInfo("KMTF") << "0 0 0 0 511 0 " << std::flush; + } + for (const auto& s : stubs3) { + edm::LogInfo("KMTF") << "" << s->coord1() << " " << s->coord2() << " " << s->quality() << " 1 " + << s->kmtf_address() << " 0 " << std::flush; + } + } + + if (i < Nstubs2) { + for (const auto& s : stubs2) { + edm::LogInfo("KMTF") << "" << s->coord1() << " " << s->coord2() << " " << s->quality() << " 1 " + << s->kmtf_address() << " 0 " << std::flush; + } + //pad with zeros + for (unsigned int j = stubs2.size(); j < 32; ++j) { + edm::LogInfo("KMTF") << "0 0 0 0 511 0 " << std::flush; + } + } else { + for (unsigned int j = stubs2.size(); j < 32; ++j) { + edm::LogInfo("KMTF") << "0 0 0 0 511 0 " << std::flush; + } + for (const auto& s : stubs2) { + edm::LogInfo("KMTF") << s->coord1() << " " << s->coord2() << " " << s->quality() << " 1 " << s->kmtf_address() + << " 0 " << std::flush; + } + } + if (i < Nstubs1) { + for (const auto& s : stubs1) { + edm::LogInfo("KMTF") << s->coord1() << " " << s->coord2() << " " << s->quality() << " 1 " << s->kmtf_address() + << " 0 " << std::flush; + } + //pad with zeros + for (unsigned int j = stubs1.size(); j < 32; ++j) { + edm::LogInfo("KMTF") << "0 0 0 0 511 0 " << std::flush; + } + } else { + for (unsigned int j = stubs1.size(); j < 32; ++j) { + edm::LogInfo("KMTF") << "0 0 0 0 511 0 " << std::flush; + } + for (const auto& s : stubs1) { + edm::LogInfo("KMTF") << s->coord1() << " " << s->coord2() << " " << s->quality() << " 1 " << s->kmtf_address() + << " 0 " << std::flush; + } + } + } + + //seed is 4 + if (i < Nstubs4) { + l1t::MuonStubRefVector stubs_proc; + if (Nstubs3 > 0) + stubs_proc.insert(stubs_proc.end(), stubs3.begin(), stubs3.end()); + if (Nstubs2 > 0) + stubs_proc.insert(stubs_proc.end(), stubs2.begin(), stubs2.end()); + if (Nstubs1 > 0) + stubs_proc.insert(stubs_proc.end(), stubs1.begin(), stubs1.end()); + std::pair tracks = trackMaker_->chain(stubs4[0], stubs_proc); + if (tracks.first.id() & 0x1) + pretracksP4.push_back(tracks.first); + if (tracks.second.id() & 0x2) + pretracksD4.push_back(tracks.second); + if (patterns) { + if (tracks.first.id() & 0x1) + edm::LogInfo("KMTF") << "1 " << (tracks.first.curvatureAtVertex() < 0 ? 1 : 0) << " " + << tracks.first.ptPrompt() << " " << tracks.first.phiAtMuon() / (1 << 5) << " " + << tracks.first.coarseEta() << " " << int(tracks.first.dxy() * ap_ufixed<8, 1>(1.606)) + << " " << tracks.first.rankPrompt() << " " << std::flush; + + else + edm::LogInfo("KMTF") << "0 0 0 0 0 0 0 " << std::flush; + if (tracks.second.id() & 0x2) + edm::LogInfo("KMTF") << "1 " << (tracks.second.curvatureAtVertex() < 0 ? 1 : 0) << " " + << tracks.second.ptDisplaced() << " " << tracks.second.phiAtMuon() / (1 << 5) << " " + << tracks.second.coarseEta() << " " << int(tracks.second.dxy() * ap_ufixed<8, 1>(1.606)) + << " " << tracks.second.rankDisp() << " " << std::flush; + + else + edm::LogInfo("KMTF") << "0 0 0 0 0 0 0 " << std::flush; + } + } else if (patterns) { + edm::LogInfo("KMTF") << "0 0 0 0 0 0 0 " << std::flush; + edm::LogInfo("KMTF") << "0 0 0 0 0 0 0 " << std::flush; + } + + if (i < Nstubs3) { + l1t::MuonStubRefVector stubs_proc; + if (Nstubs2 > 0) + stubs_proc.insert(stubs_proc.end(), stubs2.begin(), stubs2.end()); + if (Nstubs1 > 0) + stubs_proc.insert(stubs_proc.end(), stubs1.begin(), stubs1.end()); + std::pair tracks = trackMaker_->chain(stubs3[0], stubs_proc); + if (tracks.first.id() & 0x1) + pretracksP3.push_back(tracks.first); + if (tracks.second.id() & 0x2) + pretracksD3.push_back(tracks.second); + if (patterns) { + if (tracks.first.id() & 0x1) + edm::LogInfo("KMTF") << "1 " << (tracks.first.curvatureAtVertex() < 0 ? 1 : 0) << " " + << tracks.first.ptPrompt() << " " << tracks.first.phiAtMuon() / (1 << 5) << " " + << tracks.first.coarseEta() << " " << int(tracks.first.dxy() * ap_ufixed<8, 1>(1.606)) + << " " << tracks.first.rankPrompt() << " " << std::flush; + + else + edm::LogInfo("KMTF") << "0 0 0 0 0 0 0 " << std::flush; + if (tracks.second.id() & 0x2) + edm::LogInfo("KMTF") << "1 " << (tracks.second.curvatureAtVertex() < 0 ? 1 : 0) << " " + << tracks.second.ptDisplaced() << " " << tracks.second.phiAtMuon() / (1 << 5) << " " + << tracks.second.coarseEta() << " " << int(tracks.second.dxy() * ap_ufixed<8, 1>(1.606)) + << " " << tracks.second.rankDisp() << " " << std::flush; + + else + edm::LogInfo("KMTF") << "0 0 0 0 0 0 0 " << std::flush; + } + } else if (patterns) { + edm::LogInfo("KMTF") << "0 0 0 0 0 0 0 " << std::flush; + edm::LogInfo("KMTF") << "0 0 0 0 0 0 0 " << std::flush; + } + if (i < Nstubs2) { + l1t::MuonStubRefVector stubs_proc; + if (Nstubs1 > 0) + stubs_proc.insert(stubs_proc.end(), stubs1.begin(), stubs1.end()); + std::pair tracks = trackMaker_->chain(stubs2[0], stubs_proc); + if (tracks.first.id() & 0x1) + pretracksP2.push_back(tracks.first); + if (tracks.second.id() & 0x2) + pretracksD2.push_back(tracks.second); + if (patterns) { + if (tracks.first.id() & 0x1) + edm::LogInfo("KMTF") << "1 " << (tracks.first.curvatureAtVertex() < 0 ? 1 : 0) << " " + << tracks.first.ptPrompt() << " " << tracks.first.phiAtMuon() / (1 << 5) << " " + << tracks.first.coarseEta() << " " << int(tracks.first.dxy() * ap_ufixed<8, 1>(1.606)) + << " " << tracks.first.rankPrompt() << " " << std::flush; + + else + edm::LogInfo("KMTF") << "0 0 0 0 0 0 0 " << std::flush; + if (tracks.second.id() & 0x2) + edm::LogInfo("KMTF") << "1 " << (tracks.second.curvatureAtVertex() < 0 ? 1 : 0) << " " + << tracks.second.ptDisplaced() << " " << tracks.second.phiAtMuon() / (1 << 5) << " " + << tracks.second.coarseEta() << " " << int(tracks.second.dxy() * ap_ufixed<8, 1>(1.606)) + << " " << tracks.second.rankDisp(); + else + edm::LogInfo("KMTF") << "0 0 0 0 0 0 0" << std::flush; + } + } else if (patterns) { + edm::LogInfo("KMTF") << "0 0 0 0 0 0 0 " << std::flush; + edm::LogInfo("KMTF") << "0 0 0 0 0 0 0"; + } + //Now the shift register emulation in C_++ + if (stubs4.size() > 1) { + l1t::MuonStubRef s4 = stubs4[0]; + stubs4.erase(stubs4.begin(), stubs4.begin() + 1); + stubs4.push_back(s4); + } + if (stubs3.size() > 1) { + l1t::MuonStubRef s3 = stubs3[0]; + stubs3.erase(stubs3.begin(), stubs3.begin() + 1); + stubs3.push_back(s3); + } + if (stubs2.size() > 1) { + l1t::MuonStubRef s2 = stubs2[0]; + stubs2.erase(stubs2.begin(), stubs2.begin() + 1); + stubs2.push_back(s2); + } + if (stubs1.size() > 1) { + l1t::MuonStubRef s1 = stubs1[0]; + stubs1.erase(stubs1.begin(), stubs1.begin() + 1); + stubs1.push_back(s1); + } + } + + std::vector cleanedPrompt = cleanRegion(pretracksP2, pretracksP3, pretracksP4, true); + std::vector cleanedDisp = cleanRegion(pretracksD2, pretracksD3, pretracksD4, false); + if (verbose_) { + edm::LogInfo("KMTF") << "Prompt pretracks 2=" << int(pretracksP2.size()) << " 3=" << int(pretracksP3.size()) + << " 4=" << int(pretracksP4.size()); + edm::LogInfo("KMTF") << "Cleaned Tracks Prompt=" << (int)cleanedPrompt.size() + << " Displaced=" << (int)cleanedDisp.size(); + } + + if (verbose_ && !cleanedPrompt.empty()) + for (const auto& t : cleanedPrompt) + if (t.id() != 0) + edm::LogInfo("KMTF") << "final cleaned sector track from all chains track pt=" << t.ptPrompt() + << " pattern=" << t.hitPattern() << " rank=" << t.rankPrompt(); + + sort(cleanedPrompt, true); + sort(cleanedDisp, false); + + if (verbose_ && !cleanedPrompt.empty()) + for (const auto& t : cleanedPrompt) + if (t.id() != 0) + edm::LogInfo("KMTF") << "final sorted sector track from all chains track pt=" << t.ptPrompt() + << " pattern=" << t.hitPattern() << " rank=" << t.rankPrompt(); + + return std::make_pair(cleanedPrompt, cleanedDisp); +} + +void KMTF::overlapCleanTrack(l1t::KMTFTrack& source, const l1t::KMTFTrack& other, bool eq, bool vertex) { + int rank1 = vertex ? source.rankPrompt() : source.rankDisp(); + int rank2 = vertex ? other.rankPrompt() : other.rankDisp(); + int id1 = vertex ? source.id() & 0x1 : source.id() & 0x2; + int id2 = vertex ? other.id() & 0x1 : other.id() & 0x2; + bool keep = true; + unsigned int pattern = 0; + if (id1 == 0) + keep = false; + else if (id1 != 0 && id2 != 0) { + if (eq && rank1 <= rank2) + keep = false; + if ((!eq) && rank1 < rank2) + keep = false; + } + + l1t::MuonStubRefVector stubs; + for (const auto& s1 : source.stubs()) { + bool ok = true; + for (const auto& s2 : other.stubs()) { + if ((*s1) == (*s2) && (!keep)) + ok = false; + } + if (ok) { + stubs.push_back(s1); + pattern = pattern | (1 << (s1->depthRegion() - 1)); + } + } + source.setStubs(stubs); + source.setHitPattern(pattern); +} + +std::vector KMTF::cleanRegion(const std::vector& tracks2, + const std::vector& tracks3, + const std::vector& tracks4, + bool vertex) { + std::vector cleaned2; + for (unsigned int i = 0; i < tracks2.size(); ++i) { + l1t::KMTFTrack source = tracks2[i]; + + for (unsigned int j = 0; j < tracks2.size(); ++j) { + if (i == j) + continue; + overlapCleanTrack(source, tracks2[j], false, vertex); + } + for (unsigned int j = 0; j < tracks3.size(); ++j) { + overlapCleanTrack(source, tracks3[j], true, vertex); + } + for (unsigned int j = 0; j < tracks4.size(); ++j) { + overlapCleanTrack(source, tracks4[j], true, vertex); + } + + if (source.stubs().size() > 1) + cleaned2.push_back(source); + } + + std::vector cleaned3; + for (unsigned int i = 0; i < tracks3.size(); ++i) { + l1t::KMTFTrack source = tracks3[i]; + + for (unsigned int j = 0; j < tracks3.size(); ++j) { + if (i == j) + continue; + overlapCleanTrack(source, tracks3[j], false, vertex); + } + for (unsigned int j = 0; j < tracks2.size(); ++j) { + overlapCleanTrack(source, tracks2[j], false, vertex); + } + for (unsigned int j = 0; j < tracks4.size(); ++j) { + overlapCleanTrack(source, tracks4[j], true, vertex); + } + + if (source.stubs().size() > 1) + cleaned3.push_back(source); + } + + std::vector cleaned4; + for (unsigned int i = 0; i < tracks4.size(); ++i) { + l1t::KMTFTrack source = tracks4[i]; + + for (unsigned int j = 0; j < tracks4.size(); ++j) { + if (i == j) + continue; + overlapCleanTrack(source, tracks4[j], false, vertex); + } + for (unsigned int j = 0; j < tracks3.size(); ++j) { + overlapCleanTrack(source, tracks3[j], false, vertex); + } + for (unsigned int j = 0; j < tracks2.size(); ++j) { + overlapCleanTrack(source, tracks2[j], false, vertex); + } + + if (source.stubs().size() > 1) + cleaned4.push_back(source); + } + uint max234 = std::max(cleaned2.size(), std::max(cleaned3.size(), cleaned4.size())); + + std::vector output; + + for (uint i = 0; i < max234; ++i) { + if (i < cleaned2.size()) + output.push_back(cleaned2[i]); + if (i < cleaned3.size()) + output.push_back(cleaned3[i]); + if (i < cleaned4.size()) + output.push_back(cleaned4[i]); + } + return output; +} + +void KMTF::swap(std::vector& list, int i, int j, bool vertex) { + const l1t::KMTFTrack& track1 = list[i]; + const l1t::KMTFTrack& track2 = list[j]; + int id1 = track1.id(); + int id2 = track2.id(); + int pt1 = vertex ? track1.ptPrompt() : track1.ptDisplaced(); + int pt2 = vertex ? track2.ptPrompt() : track2.ptDisplaced(); + bool swap = false; + if (vertex) { + id1 = id1 & 0x1; + id2 = id2 & 0x1; + } else { + id1 = id1 & 0x2; + id2 = id2 & 0x2; + } + if (id1 && (!id2)) + swap = false; + else if ((!id1) && id2) + swap = true; + else if (id1 && id2) { + if (pt1 > pt2) + swap = false; + else + swap = true; + } else { + swap = false; + } + if (swap) { + l1t::KMTFTrack tmp = list[i]; + list[i] = list[j]; + list[j] = tmp; + } +} + +void KMTF::sort(std::vector& in, bool vertex) { + l1t::KMTFTrack nullTrack; + nullTrack.setPtEtaPhi(0, 0, 0); + nullTrack.setIDFlag(false, false); + nullTrack.setRank(0, vertex); + while (in.size() < 32) + in.push_back(nullTrack); + + for (uint iteration = 0; iteration < 16; ++iteration) { + for (uint i = 0; i < 32; i = i + 2) { + swap(in, i, i + 1, vertex); + } + for (uint i = 1; i < 31; i = i + 2) { + swap(in, i, i + 1, vertex); + } + } + + std::vector out; + for (const auto& track : in) { + if ((vertex && (track.id() & 0x1)) || ((!vertex) && (track.id() & 0x2))) + out.push_back(track); + } + in = out; +} diff --git a/L1Trigger/Phase2L1GMT/src/KMTFCore.cc b/L1Trigger/Phase2L1GMT/src/KMTFCore.cc new file mode 100644 index 0000000000000..d58b84e1705fd --- /dev/null +++ b/L1Trigger/Phase2L1GMT/src/KMTFCore.cc @@ -0,0 +1,1167 @@ +#include "L1Trigger/Phase2L1GMT/interface/KMTFCore.h" +using namespace Phase2L1GMT; +KMTFCore::KMTFCore(const edm::ParameterSet& settings) + : lutService_(new KMTFLUTs(settings.getParameter("lutFile"))), + verbose_(settings.getParameter("verbose")), + initK_(settings.getParameter >("initialK")), + initK2_(settings.getParameter >("initialK2")), + eLoss_(settings.getParameter >("eLoss")), + aPhi_(settings.getParameter >("aPhi")), + aPhiB_(settings.getParameter >("aPhiB")), + aPhiBNLO_(settings.getParameter >("aPhiBNLO")), + bPhi_(settings.getParameter >("bPhi")), + bPhiB_(settings.getParameter >("bPhiB")), + phiAt2_(settings.getParameter("phiAt2")), + + chiSquareDisp1_(settings.getParameter >("chiSquareDisp1")), + chiSquareDisp2_(settings.getParameter >("chiSquareDisp2")), + chiSquareDisp3_(settings.getParameter >("chiSquareDisp3")), + chiSquareErrADisp1_(settings.getParameter >("chiSquareErrADisp1")), + chiSquareErrADisp2_(settings.getParameter >("chiSquareErrADisp2")), + chiSquareErrADisp3_(settings.getParameter >("chiSquareErrADisp3")), + chiSquareErrBDisp1_(settings.getParameter >("chiSquareErrBDisp1")), + chiSquareErrBDisp2_(settings.getParameter >("chiSquareErrBDisp2")), + chiSquareErrBDisp3_(settings.getParameter >("chiSquareErrBDisp3")), + + chiSquarePrompt1_(settings.getParameter >("chiSquarePrompt1")), + chiSquarePrompt2_(settings.getParameter >("chiSquarePrompt2")), + chiSquarePrompt3_(settings.getParameter >("chiSquarePrompt3")), + chiSquareErrAPrompt1_(settings.getParameter >("chiSquareErrAPrompt1")), + chiSquareErrAPrompt2_(settings.getParameter >("chiSquareErrAPrompt2")), + chiSquareErrAPrompt3_(settings.getParameter >("chiSquareErrAPrompt3")), + chiSquareErrBPrompt1_(settings.getParameter >("chiSquareErrBPrompt1")), + chiSquareErrBPrompt2_(settings.getParameter >("chiSquareErrBPrompt2")), + chiSquareErrBPrompt3_(settings.getParameter >("chiSquareErrBPrompt3")), + + chiSquareCutDispPattern_(settings.getParameter >("chiSquareCutDispPattern")), + chiSquareCutOffDisp_(settings.getParameter >("chiSquareCutOffDisp")), + chiSquareCutDisp_(settings.getParameter >("chiSquareCutDisp")), + + chiSquareCutPromptPattern_(settings.getParameter >("chiSquareCutPromptPattern")), + chiSquareCutOffPrompt_(settings.getParameter >("chiSquareCutOffPrompt")), + chiSquareCutPrompt_(settings.getParameter >("chiSquareCutPrompt")), + + combos4_(settings.getParameter >("combos4")), + combos3_(settings.getParameter >("combos3")), + combos2_(settings.getParameter >("combos2")), + combos1_(settings.getParameter >("combos1")), + + useOfflineAlgo_(settings.getParameter("useOfflineAlgo")), + mScatteringPhi_(settings.getParameter >("mScatteringPhi")), + mScatteringPhiB_(settings.getParameter >("mScatteringPhiB")), + pointResolutionPhi_(settings.getParameter("pointResolutionPhi")), + pointResolutionPhiB_(settings.getParameter("pointResolutionPhiB")), + pointResolutionPhiBH_(settings.getParameter >("pointResolutionPhiBH")), + pointResolutionPhiBL_(settings.getParameter >("pointResolutionPhiBL")), + pointResolutionVertex_(settings.getParameter("pointResolutionVertex")), + curvResolution1_(settings.getParameter >("curvResolution1")), + curvResolution2_(settings.getParameter >("curvResolution2")) {} + +std::pair KMTFCore::chain(const l1t::MuonStubRef& seed, + const l1t::MuonStubRefVector& stubs) { + std::vector pretracks; + std::vector combinatorics; + int seedQual; + switch (seed->depthRegion()) { + case 1: + combinatorics = combos1_; + break; + case 2: + combinatorics = combos2_; + break; + case 3: + combinatorics = combos3_; + break; + case 4: + combinatorics = combos4_; + break; + default: + throw cms::Exception("KMTFCore") << "Something really bad happend\n"; + } + + l1t::KMTFTrack nullTrack(seed, seed->coord1(), correctedPhiB(seed)); + seedQual = seed->quality(); + for (const auto& mask : combinatorics) { + l1t::KMTFTrack track(seed, seed->coord1(), correctedPhiB(seed)); + int phiB = correctedPhiB(seed); + int charge; + if (phiB == 0) + charge = 0; + else + charge = phiB / fabs(phiB); + + int address = phiB; + if (track.step() == 4 && (fabs(seed->coord2()) > 15)) + address = charge * 15 * ap_ufixed(28.5205658); + if (track.step() == 3 && (fabs(seed->coord2()) > 100)) + address = charge * 100 * ap_ufixed(28.5205658); + if (track.step() == 2 && (fabs(seed->coord2()) > 250)) + address = charge * 250 * ap_ufixed(28.5205658); + int initialK = + int(initK_[seed->depthRegion() - 1] * address / (1 + initK2_[seed->depthRegion() - 1] * charge * address)); + if (initialK >= pow(2, BITSCURV - 1)) + initialK = pow(2, BITSCURV - 1) - 1; + if (initialK <= -pow(2, BITSCURV - 1)) + initialK = -pow(2, BITSCURV - 1) + 1; + track.setCoordinates(seed->depthRegion(), initialK, seed->coord1(), phiB); + if (seed->quality() < 6) { + track.setCoordinates(seed->depthRegion(), initialK, seed->coord1(), 0); + } + if (verbose_) { + edm::LogInfo("KMTFCore") << "Initial state: phiB=" << phiB << " addr=" << address << " K=" << initialK; + } + track.setHitPattern(hitPattern(track)); + //set covariance + l1t::KMTFTrack::CovarianceMatrix covariance; + float DK = curvResolution1_[track.step() - 1] + curvResolution2_[track.step() - 1] * initialK * initialK; + if (seed->quality() < 6) + DK = pow(2, 22); + // DK = pow(2,24); + covariance(0, 0) = DK * 4; + covariance(0, 1) = 0; + covariance(0, 2) = 0; + covariance(1, 0) = 0; + covariance(1, 1) = float(pointResolutionPhi_); + covariance(1, 2) = 0; + covariance(2, 0) = 0; + covariance(2, 1) = 0; + if (!(mask == 1 || mask == 2 || mask == 3 || mask == 4 || mask == 5 || mask == 9 || mask == 6 || mask == 10 || + mask == 12)) + covariance(2, 2) = float(pointResolutionPhiB_); + else { + if (seed->quality() < 6) + covariance(2, 2) = float(pointResolutionPhiBL_[seed->depthRegion() - 1]); + else + covariance(2, 2) = float(pointResolutionPhiBH_[seed->depthRegion() - 1]); + } + track.setCovariance(covariance); + + // + if (verbose_) { + edm::LogInfo("KMTFCore") << "New Kalman fit staring at step=" << track.step() << ", phi=" << track.positionAngle() + << ", phiB=" << track.bendingAngle() << ", with curvature=" << track.curvature(); + edm::LogInfo("KMTFCore") << "BITMASK:" << std::flush; + for (unsigned int i = 0; i < 4; ++i) + edm::LogInfo("KMTFCore") << getBit(mask, i) << std::flush; + edm::LogInfo("KMTFCore") << std::endl; + edm::LogInfo("KMTFCore") << "------------------------------------------------------"; + edm::LogInfo("KMTFCore") << "------------------------------------------------------"; + edm::LogInfo("KMTFCore") << "------------------------------------------------------"; + edm::LogInfo("KMTFCore") << "stubs:"; + for (const auto& stub : stubs) + edm::LogInfo("KMTFCore") << "station=" << stub->depthRegion() << " phi=" << stub->coord1() + << " phiB=" << correctedPhiB(stub) << " qual=" << stub->quality() + << " tag=" << stub->id() << " sector=" << stub->phiRegion() + << " wheel=" << stub->etaRegion() << " fineEta= " << stub->eta1() << " " + << stub->eta2(); + edm::LogInfo("KMTFCore") << "------------------------------------------------------"; + edm::LogInfo("KMTFCore") << "------------------------------------------------------"; + } + + bool passedU = false; + bool passedV = false; + while (track.step() > 0) { + // muon station 1 + if (track.step() == 1) { + track.setCoordinatesAtMuon(track.curvature(), track.positionAngle(), track.bendingAngle()); + passedU = estimateChiSquare(track, false); + setRank(track, false); + + if (verbose_) + edm::LogInfo("KMTFCore") << "Calculated Chi2 for displaced track =" << track.approxDispChi2() + << " Passed Cut=" << passedU; + calculateEta(track); + setFourVectors(track); + //calculate coarse eta + ////////////////////// + if (verbose_) + edm::LogInfo("KMTFCore") << "Unconstrained PT in Muon System: pt=" << track.displacedP4().pt(); + calculateEta(track); + } + + propagate(track); + if (verbose_) + edm::LogInfo("KMTFCore") << "propagated Coordinates step:" << track.step() << "phi=" << track.positionAngle() + << "phiB=" << track.bendingAngle() << "K=" << track.curvature(); + if (track.step() > 0) + if (getBit(mask, track.step() - 1)) { + std::pair bestStub = match(seed, stubs, track.step()); + if (verbose_) + edm::LogInfo("KMTFCore") << "Found match =" << bestStub.first << " index=" << bestStub.second + << " number of all stubs=" << stubs.size(); + + if ((!bestStub.first) || (!update(track, stubs[bestStub.second], mask, seedQual))) + break; + if (verbose_) { + edm::LogInfo("KMTFCore") << "updated Coordinates step:" << track.step() << " phi=" << track.positionAngle() + << " phiB=" << track.bendingAngle() << " K=" << track.curvature(); + } + } + + if (track.step() == 0) { + track.setCoordinatesAtVertex(track.curvature(), track.positionAngle(), track.bendingAngle()); + if (verbose_) + edm::LogInfo("KMTFCore") << " Coordinates before vertex constraint step:" << track.step() + << " phi=" << track.phiAtVertex() << " dxy=" << track.dxy() + << " K=" << track.curvatureAtVertex(); + + //apply vertex constraint for non single tracks + if (track.stubs().size() > 1) + vertexConstraint(track); + + passedV = estimateChiSquare(track, true); + setRank(track, true); + + if (verbose_) + edm::LogInfo("KMTFCore") << "Calculated Chi2 for prompt track =" << track.approxPromptChi2() + << " Passed Cut=" << passedV; + + if (verbose_) { + edm::LogInfo("KMTFCore") << " Coordinates after vertex constraint step:" << track.step() + << " phi=" << track.phiAtVertex() << " dxy=" << track.dxy() + << " K=" << track.curvatureAtVertex() + << " maximum local chi2=" << track.approxPromptChi2(); + edm::LogInfo("KMTFCore") << "------------------------------------------------------"; + edm::LogInfo("KMTFCore") << "------------------------------------------------------"; + } + setFourVectors(track); + //finally set the displaced or prompt ID + track.setIDFlag(passedV, passedU); + + if (verbose_) + edm::LogInfo("KMTFCore") << "Floating point coordinates at vertex: pt=" << track.pt() + << ", eta=" << track.eta() << " phi=" << track.phi(); + + pretracks.push_back(track); + } + } + } + if (verbose_) { + if (!pretracks.empty()) + edm::LogInfo("KMTFCore") << "-----Kalman Algo at station " << seed->depthRegion() << " (uncleaned)-----"; + for (const auto& track : pretracks) + edm::LogInfo("KMTFCore") << "Kalman Track charge=" << track.charge() << " pt=" << track.pt() + << " hit pattern = " << track.hitPattern() << " eta=" << track.eta() + << " phi=" << track.phi() << " curvature=" << track.curvatureAtVertex() + << " curvature STA =" << track.curvatureAtMuon() + << " stubs=" << int(track.stubs().size()) << " chi2=" << track.approxPromptChi2() << "," + << track.approxDispChi2() << " rank=" << track.rankPrompt() << "," << track.rankDisp() + << " pts=" << track.pt() << " " << track.displacedP4().pt() << " ID=" << track.id(); + } + //Now for all the pretracks we need only one vertex constrained and one vertex unconstrained + //so we clean twice + if (verbose_) + edm::LogInfo("KMTFCore") << "Chain Reconstructed " << pretracks.size() + << " pretracks, now cleaning them separately"; + + std::vector cleanedPrompt = clean(pretracks, seed->depthRegion(), true); + std::vector cleanedDisp = clean(pretracks, seed->depthRegion(), false); + if (verbose_) + edm::LogInfo("KMTFCore") << "Cleaned Chain tracks prompt=" << cleanedPrompt.size() + << " displaced=" << cleanedDisp.size(); + + if (cleanedPrompt.empty() && cleanedDisp.empty()) + return std::make_pair(nullTrack, nullTrack); + else if ((!cleanedPrompt.empty()) && cleanedDisp.empty()) + return std::make_pair(cleanedPrompt[0], nullTrack); + else if (cleanedPrompt.empty() && (!cleanedDisp.empty())) + return std::make_pair(nullTrack, cleanedDisp[0]); + else + return std::make_pair(cleanedPrompt[0], cleanedDisp[0]); +} + +std::vector KMTFCore::clean(const std::vector& tracks, uint seed, bool vertex) { + std::vector out; + + std::map infoRank; + std::map infoTrack; + for (uint i = 1; i <= 15; ++i) { + infoRank[i] = -1; + } + + for (const auto& track : tracks) { + if (vertex) { + if ((track.id() & 0x1) == 0) + continue; + if (verbose_) + edm::LogInfo("KMTFCore") << "Chain Cleaning : Pre Track = pattern = " << track.rankPrompt() + << " rank=" << track.hitPattern(); + infoRank[track.hitPattern()] = track.rankPrompt(); + infoTrack[track.hitPattern()] = track; + + } else { + if ((track.id() & 0x2) == 0) + continue; + infoRank[track.hitPattern()] = track.rankDisp(); + infoTrack[track.hitPattern()] = track; + } + } + + int selected = 15; + if (seed == 4) //station 4 seeded + { + int sel6 = infoRank[10] >= infoRank[12] ? 10 : 12; + int sel5 = infoRank[14] >= infoRank[9] ? 14 : 9; + int sel4 = infoRank[11] >= infoRank[13] ? 11 : 13; + int sel3 = infoRank[sel6] >= infoRank[sel5] ? sel6 : sel5; + int sel2 = infoRank[sel4] >= infoRank[sel3] ? sel4 : sel3; + int sel1 = infoRank[15] >= infoRank[sel2] ? 15 : sel2; + if (vertex) + selected = infoRank[sel1] > 0 ? sel1 : 8; + else + selected = sel1; + } + if (seed == 3) //station 3 seeded + { + int sel2 = infoRank[5] >= infoRank[6] ? 5 : 6; + int sel1 = infoRank[7] >= infoRank[sel2] ? 7 : sel2; + if (vertex) + selected = infoRank[sel1] > 0 ? sel1 : 4; + else + selected = sel1; + } + if (seed == 2) //station 2 seeded + { + if (vertex) + selected = infoRank[3] > 0 ? 3 : 2; + else + selected = 3; + } + if (seed == 1) //station 1 seeded + selected = 1; + + auto search = infoTrack.find(selected); + if (search != infoTrack.end()) + out.push_back(search->second); + + return out; +} + +std::pair KMTFCore::match(const l1t::MuonStubRef& seed, const l1t::MuonStubRefVector& stubs, int step) { + l1t::MuonStubRefVector selected; + std::map diffInfo; + for (uint i = 0; i < 32; ++i) { + diffInfo[i] = 60000; + } + + int wheel = seed->etaRegion(); + int innerWheel = 0; + if (wheel == -2) + innerWheel = -1; + if (wheel == -1) + innerWheel = 0; + if (wheel == 0) + innerWheel = 1982; + if (wheel == 1) + innerWheel = 0; + if (wheel == 2) + innerWheel = 1; + //calculate the distance of all stubs + + for (unsigned int N = 0; N < stubs.size(); ++N) { + const l1t::MuonStubRef& stub = stubs[N]; + //Should not be stubs with tag=4 but there are, so skip those + if (verbose_) + edm::LogInfo("KMTFCore") << "testing stub on depth=" << stub->depthRegion() << " for step=" << step; + + if (stub->depthRegion() != step) + continue; + if (verbose_) + edm::LogInfo("KMTFCore") << "Passed"; + + uint distance = fabs(wrapAround((seed->coord1() - stub->coord1()) >> 3, 32768)); + //if the wheels are not adjacent make this huge + if (!((stub->etaRegion() == wheel) || (stub->etaRegion() == innerWheel))) + distance = 60000; + + diffInfo[N] = distance; + } + + uint s1_1 = matchAbs(diffInfo, 0, 1); + uint s1_2 = matchAbs(diffInfo, 2, 3); + uint s1_3 = matchAbs(diffInfo, 4, 5); + uint s1_4 = matchAbs(diffInfo, 6, 7); + uint s1_5 = matchAbs(diffInfo, 8, 9); + uint s1_6 = matchAbs(diffInfo, 10, 11); + uint s1_7 = matchAbs(diffInfo, 12, 13); + uint s1_8 = matchAbs(diffInfo, 14, 15); + uint s1_9 = matchAbs(diffInfo, 16, 17); + uint s1_10 = matchAbs(diffInfo, 18, 19); + uint s1_11 = matchAbs(diffInfo, 20, 21); + uint s1_12 = matchAbs(diffInfo, 22, 23); + uint s1_13 = matchAbs(diffInfo, 24, 25); + uint s1_14 = matchAbs(diffInfo, 26, 27); + uint s1_15 = matchAbs(diffInfo, 28, 29); + uint s1_16 = matchAbs(diffInfo, 30, 31); + + uint s2_1 = matchAbs(diffInfo, s1_1, s1_2); + uint s2_2 = matchAbs(diffInfo, s1_3, s1_4); + uint s2_3 = matchAbs(diffInfo, s1_5, s1_6); + uint s2_4 = matchAbs(diffInfo, s1_7, s1_8); + uint s2_5 = matchAbs(diffInfo, s1_9, s1_10); + uint s2_6 = matchAbs(diffInfo, s1_11, s1_12); + uint s2_7 = matchAbs(diffInfo, s1_13, s1_14); + uint s2_8 = matchAbs(diffInfo, s1_15, s1_16); + + uint s3_1 = matchAbs(diffInfo, s2_1, s2_2); + uint s3_2 = matchAbs(diffInfo, s2_3, s2_4); + uint s3_3 = matchAbs(diffInfo, s2_5, s2_6); + uint s3_4 = matchAbs(diffInfo, s2_7, s2_8); + + uint s4_1 = matchAbs(diffInfo, s3_1, s3_2); + uint s4_2 = matchAbs(diffInfo, s3_3, s3_4); + + uint s5 = matchAbs(diffInfo, s4_1, s4_2); + + if (diffInfo[s5] != 60000) + return std::make_pair(true, s5); + else + return std::make_pair(false, 0); +} + +int KMTFCore::correctedPhiB(const l1t::MuonStubRef& stub) { + return ap_fixed(ap_ufixed(28.5205658) * + stub->coord2()); +} + +void KMTFCore::propagate(l1t::KMTFTrack& track) { + int K = track.curvature(); + int phi = track.positionAngle(); + int phiB = track.bendingAngle(); + unsigned int step = track.step(); + + int charge = 1; + if (K != 0) + charge = K / fabs(K); + + int KBound = K; + if (KBound > pow(2, BITSCURV - 3) - 1) + KBound = pow(2, BITSCURV - 3) - 1; + if (KBound < -(pow(2, BITSCURV - 3) - 1)) + KBound = -(pow(2, BITSCURV - 3) - 1); + + int deltaK = 0; + int KNew = K; + if (step == 1) { + ap_ufixed<17, 0> eLoss = ap_ufixed<17, 0>(eLoss_[step - 1]); + ap_fixed Kint = ap_fixed(KBound); + ap_fixed<16, 5> eK = eLoss * Kint; + if (charge < 0) + eK = -eK; + ap_fixed KnewInt = ap_fixed(K) - eK * Kint; + KNew = KnewInt; + if (verbose_) + edm::LogInfo("KMTFCore") << "propagate to vertex Kint=" << Kint.to_int() << " ek=" << eK.to_float() + << " Knew=" << KNew; + } + + //phi propagation + ap_fixed phi11 = ap_fixed(aPhi_[step - 1]) * ap_fixed(K); + ap_fixed phi12 = + ap_fixed(-bPhi_[step - 1]) * ap_fixed(phiB); + + if (verbose_) { + edm::LogInfo("KMTFCore") << "phi prop = " << K << " * " << ap_fixed(aPhi_[step - 1]).to_float() + << " = " << phi11.to_int() << ", " << phiB << " * " + << ap_fixed(-bPhi_[step - 1]).to_float() << " = " << phi12.to_int(); + } + int phiNew = ap_fixed(phi + phi11 + phi12); + + //phiB propagation + ap_fixed phiB11 = ap_fixed(aPhiB_[step - 1]) * ap_fixed(K); + ap_fixed phiB12 = + ap_ufixed(bPhiB_[step - 1]) * ap_fixed(phiB); + int phiBNew = ap_fixed(phiB11 + phiB12); + if (verbose_) { + edm::LogInfo("KMTFCore") << "phiB prop = " << K << " * " << ap_fixed(aPhiB_[step - 1]).to_float() + << " = " << phiB11.to_int() << ", " << phiB << " * " + << ap_ufixed(bPhiB_[step - 1]).to_float() << " = " << phiB12.to_int(); + } + + //Only for the propagation to vertex we use second order; + if (step == 1) { + ap_fixed<10, 4> aPhiB = aPhiB_[step - 1]; + ap_ufixed<16, 0> aPhiBNLO = aPhiBNLO_[step - 1]; + + ap_fixed Kint = ap_fixed(KBound); + ap_fixed aK = aPhiB * Kint; + ap_fixed<16, 5> eK = aPhiBNLO * Kint; + if (charge < 0) + eK = -eK; + ap_fixed DXY = aK + eK * Kint; + //ap_fixed diff = DXY - ap_fixed(phiB); + + ap_fixed diff = DXY - ap_fixed(phiB); + + phiBNew = ap_fixed(diff); + if (verbose_) { + edm::LogInfo("KMTFCore") << "Vertex phiB prop = " << DXY.to_int() << "(=" << aK.to_int() << " +" + << (eK * Kint).to_int() << ") - " << ap_fixed(phiB).to_int() << " = " + << phiBNew; + } + } + /////////////////////////////////////////////////////// + //Rest of the stuff is for the offline version only + //where we want to check what is happening in the covariance matrix + + //Create the transformation matrix + double a[9]; + a[0] = 1.; + a[1] = 0.0; + a[2] = 0.0; + a[3] = aPhi_[step - 1]; + // a[3] = 0.0; + a[4] = 1.0; + a[5] = -bPhi_[step - 1]; + //a[6]=0.0; + a[6] = aPhiB_[step - 1]; + if (step == 1) + a[6] = aPhiB_[step - 1] / 2.0; + + a[7] = 0.0; + a[8] = bPhiB_[step - 1]; + + ROOT::Math::SMatrix P(a, 9); + + const std::vector& covLine = track.covariance(); + l1t::KMTFTrack::CovarianceMatrix cov(covLine.begin(), covLine.end()); + cov = ROOT::Math::Similarity(P, cov); + + //Add the multiple scattering + double phiRMS = mScatteringPhi_[step - 1] * K * K; + double phiBRMS = mScatteringPhiB_[step - 1] * K * K; + + std::vector b(6); + b[0] = 0; + b[1] = 0; + b[2] = phiRMS; + b[3] = 0; + b[4] = 0; + b[5] = phiBRMS; + + reco::Candidate::CovarianceMatrix MS(b.begin(), b.end()); + + cov = cov + MS; + + if (verbose_) { + edm::LogInfo("KMTFCore") << "Covariance term for phiB = " << cov(2, 2); + edm::LogInfo("KMTFCore") << "Multiple scattering term for phiB = " << MS(2, 2); + } + + track.setCovariance(cov); + track.setCoordinates(step - 1, KNew, phiNew, phiBNew); +} + +bool KMTFCore::update(l1t::KMTFTrack& track, const l1t::MuonStubRef& stub, int mask, int seedQual) { + // updateEta(track, stub); + if (useOfflineAlgo_) { + if (mask == 3 || mask == 5 || mask == 9 || mask == 6 || mask == 10 || mask == 12) + return updateOffline(track, stub); + else + return updateOffline1D(track, stub); + + } else + return updateLUT(track, stub, mask, seedQual); +} + +bool KMTFCore::updateOffline(l1t::KMTFTrack& track, const l1t::MuonStubRef& stub) { + int trackK = track.curvature(); + int trackPhi = track.positionAngle(); + int trackPhiB = track.bendingAngle(); + + int phi = stub->coord1(); + int phiB = correctedPhiB(stub); + + Vector2 residual; + residual[0] = ap_fixed(phi - trackPhi); + residual[1] = phiB - trackPhiB; + + Matrix23 H; + H(0, 0) = 0.0; + H(0, 1) = 1.0; + H(0, 2) = 0.0; + H(1, 0) = 0.0; + H(1, 1) = 0.0; + H(1, 2) = 1.0; + + CovarianceMatrix2 R; + R(0, 0) = pointResolutionPhi_; + R(0, 1) = 0.0; + R(1, 0) = 0.0; + if (stub->quality() < 6) + R(1, 1) = pointResolutionPhiBL_[track.step() - 1]; + else + R(1, 1) = pointResolutionPhiBH_[track.step() - 1]; + + const std::vector& covLine = track.covariance(); + l1t::KMTFTrack::CovarianceMatrix cov(covLine.begin(), covLine.end()); + CovarianceMatrix2 S = ROOT::Math::Similarity(H, cov) + R; + if (!S.Invert()) + return false; + Matrix32 Gain = cov * ROOT::Math::Transpose(H) * S; + + track.setKalmanGain( + track.step(), fabs(trackK), Gain(0, 0), Gain(0, 1), Gain(1, 0), Gain(1, 1), Gain(2, 0), Gain(2, 1)); + + int KNew = (trackK + int(Gain(0, 0) * residual(0) + Gain(0, 1) * residual(1))); + if (fabs(KNew) > pow(2, BITSCURV - 1)) + return false; + + int phiNew = wrapAround(trackPhi + residual(0), pow(2, BITSPHI - 1)); + int phiBNew = wrapAround(trackPhiB + int(Gain(2, 0) * residual(0) + Gain(2, 1) * residual(1)), pow(2, BITSPHIB - 1)); + + track.setResidual(stub->depthRegion() - 1, fabs(phi - phiNew) + fabs(phiB - phiBNew)); + + if (verbose_) { + edm::LogInfo("KMTFCore") << "residual " << phi << " - " << trackPhi << " = " << int(residual[0]) << " " << phiB + << " - " << trackPhiB << " = " << int(residual[1]); + edm::LogInfo("KMTFCore") << "Gains offline: " << Gain(0, 0) << " " << Gain(0, 1) << " " << Gain(2, 0) << " " + << Gain(2, 1); + edm::LogInfo("KMTFCore") << " K = " << trackK << " + " << Gain(0, 0) << " * " << residual(0) << " + " << Gain(0, 1) + << " * " << residual(1); + edm::LogInfo("KMTFCore") << " phiB = " << trackPhiB << " + " << Gain(2, 0) << " * " << residual(0) << " + " + << Gain(2, 1) << " * " << residual(1); + } + + track.setCoordinates(track.step(), KNew, phiNew, phiBNew); + Matrix33 covNew = cov - Gain * (H * cov); + l1t::KMTFTrack::CovarianceMatrix c; + + c(0, 0) = covNew(0, 0); + c(0, 1) = covNew(0, 1); + c(0, 2) = covNew(0, 2); + c(1, 0) = covNew(1, 0); + c(1, 1) = covNew(1, 1); + c(1, 2) = covNew(1, 2); + c(2, 0) = covNew(2, 0); + c(2, 1) = covNew(2, 1); + c(2, 2) = covNew(2, 2); + if (verbose_) { + edm::LogInfo("KMTFCore") << "Post Fit Covariance Matrix " << cov(0, 0) << " " << cov(1, 1) << " " << cov(2, 2); + } + + track.setCovariance(c); + track.addStub(stub); + track.setHitPattern(hitPattern(track)); + + return true; +} + +bool KMTFCore::updateOffline1D(l1t::KMTFTrack& track, const l1t::MuonStubRef& stub) { + int trackK = track.curvature(); + int trackPhi = track.positionAngle(); + int trackPhiB = track.bendingAngle(); + + int phi = stub->coord1(); + + double residual = ap_fixed(phi - trackPhi); + + if (verbose_) + edm::LogInfo("KMTFCore") << "residuals " << phi << " - " << trackPhi << " = " << int(residual); + + Matrix13 H; + H(0, 0) = 0.0; + H(0, 1) = 1.0; + H(0, 2) = 0.0; + + const std::vector& covLine = track.covariance(); + l1t::KMTFTrack::CovarianceMatrix cov(covLine.begin(), covLine.end()); + + double S = ROOT::Math::Similarity(H, cov)(0, 0) + pointResolutionPhi_; + if (S == 0.0) + return false; + Matrix31 Gain = cov * ROOT::Math::Transpose(H) / S; + + track.setKalmanGain(track.step(), fabs(trackK), Gain(0, 0), 0.0, Gain(1, 0), 0.0, Gain(2, 0), 0.0); + + int KNew = wrapAround(trackK + int(Gain(0, 0) * residual), pow(2, BITSCURV - 1)); + int phiNew = wrapAround(trackPhi + residual, pow(2, BITSPHI - 1)); + int phiBNew = wrapAround(trackPhiB + int(Gain(2, 0) * residual), pow(2, BITSPHIB - 1)); + track.setCoordinates(track.step(), KNew, phiNew, phiBNew); + Matrix33 covNew = cov - Gain * (H * cov); + l1t::KMTFTrack::CovarianceMatrix c; + + if (verbose_) { + edm::LogInfo("KMTFCore") << "phiUpdate: " << int(Gain(0, 0) * residual) << " " << int(Gain(2, 0) * residual); + edm::LogInfo("KMTFCore") << " K = " << trackK << " + " << Gain(0, 0) << " * " << residual; + edm::LogInfo("KMTFCore") << " phiBNew = " << trackPhiB << " + " << Gain(2, 0) << " * " << residual; + } + + c(0, 0) = covNew(0, 0); + c(0, 1) = covNew(0, 1); + c(0, 2) = covNew(0, 2); + c(1, 0) = covNew(1, 0); + c(1, 1) = covNew(1, 1); + c(1, 2) = covNew(1, 2); + c(2, 0) = covNew(2, 0); + c(2, 1) = covNew(2, 1); + c(2, 2) = covNew(2, 2); + track.setCovariance(c); + track.addStub(stub); + track.setHitPattern(hitPattern(track)); + + return true; +} + +bool KMTFCore::updateLUT(l1t::KMTFTrack& track, const l1t::MuonStubRef& stub, int mask, int seedQual) { + int trackK = track.curvature(); + int trackPhi = track.positionAngle(); + int trackPhiB = track.bendingAngle(); + + int phi = stub->coord1(); + int phiB = correctedPhiB(stub); + + Vector2 residual; + ap_fixed residualPhi = phi - trackPhi; + ap_fixed residualPhiB = phiB - trackPhiB; + + if (verbose_) + edm::LogInfo("KMTFCore") << "residual " << phi << " - " << trackPhi << " = " << residualPhi.to_int() << " " << phiB + << " - " << trackPhiB << " = " << residualPhiB.to_int(); + + uint absK = fabs(trackK); + if (absK > pow(2, BITSCURV - 2) - 1) + absK = pow(2, BITSCURV - 2) - 1; + + std::vector GAIN; + if (verbose_) { + edm::LogInfo("KMTFCore") << "Looking up LUTs for mask=" << mask << " with hit pattern=" << track.hitPattern(); + } + //For the three stub stuff use only gains 0 and 4 + if (!(mask == 3 || mask == 5 || mask == 9 || mask == 6 || mask == 10 || mask == 12)) { + GAIN = lutService_->trackGain(track.step(), track.hitPattern(), absK / 16); + GAIN[1] = 0.0; + GAIN[3] = 0.0; + + } else { + GAIN = lutService_->trackGain2(track.step(), track.hitPattern(), absK / 32, seedQual, stub->quality()); + } + if (verbose_) { + edm::LogInfo("KMTFCore") << "Gains (fp): " << GAIN[0] << " " << GAIN[1] << " " << GAIN[2] << " " << GAIN[3]; + + if (!(mask == 3 || mask == 5 || mask == 9 || mask == 6 || mask == 10 || mask == 12)) + edm::LogInfo("KMTFCore") << "Addr=" << absK / 16 + << " gain0=" << ap_ufixed(GAIN[0]).to_float() << " gain4=-" + << ap_ufixed(GAIN[2]).to_float(); + else + edm::LogInfo("KMTFCore") << "Addr=" << absK / 32 << " " << ap_ufixed(GAIN[0]).to_float() + << " -" << ap_ufixed(GAIN[1]).to_float() << " " + << ap_ufixed(GAIN[2]).to_float() << " " + << ap_ufixed(GAIN[3]).to_float(); + } + + track.setKalmanGain(track.step(), fabs(trackK), GAIN[0], GAIN[1], 1, 0, GAIN[2], GAIN[3]); + + int KNew; + if (!(mask == 3 || mask == 5 || mask == 9 || mask == 6 || mask == 10 || mask == 12)) { + KNew = ap_fixed(ap_fixed(trackK) + + ap_ufixed(GAIN[0]) * residualPhi); + if (verbose_) { + edm::LogInfo("KMTFCore") << "K = " << KNew << " = " << ap_fixed(trackK).to_int() << " + " + << ap_ufixed(GAIN[0]).to_float() << "*" << residualPhi.to_int(); + } + } else { + ap_fixed k11 = ap_ufixed(GAIN[0]) * residualPhi; + ap_fixed k12 = ap_ufixed(GAIN[1]) * residualPhiB; + + KNew = ap_fixed(ap_fixed(trackK) + k11 - k12); + if (verbose_) { + edm::LogInfo("KMTFCore") << "K = " << KNew << " = " << ap_fixed(trackK).to_int() << " + " + << k11.to_int() << " + " << k12.to_int(); + } + } + if ((KNew > (pow(2, BITSCURV - 1) - 1)) || (KNew < -(pow(2, BITSCURV - 1)))) { + if (verbose_) + edm::LogInfo("KMTFCore") << "K has saturated, track has extremely low energy"; + return false; + } + KNew = wrapAround(KNew, pow(2, BITSCURV - 1)); + int phiNew = phi; + + //different products for different firmware logic + ap_fixed pbdouble_0 = ap_ufixed(GAIN[2]) * residualPhi; + ap_fixed pb_1 = ap_ufixed(GAIN[3]) * residualPhiB; + ap_fixed pb_0 = ap_ufixed(GAIN[2]) * residualPhi; + + if (verbose_) { + edm::LogInfo("KMTFCore") << "phiupdate " << pb_0.to_float() << " " << pb_1.to_float() << " " + << pbdouble_0.to_float(); + } + + int phiBNew; + if (!(mask == 3 || mask == 5 || mask == 9 || mask == 6 || mask == 10 || mask == 12)) { + phiBNew = ap_fixed(ap_fixed(trackPhiB) - + ap_ufixed(GAIN[2]) * residualPhi); + } else { + phiBNew = ap_fixed(ap_fixed(trackPhiB) + pb_1 - pbdouble_0); + } + + if ((phiBNew > (pow(2, BITSPHIB - 1) - 1)) || (phiBNew < (-pow(2, BITSPHIB - 1)))) + return false; + + track.setCoordinates(track.step(), KNew, phiNew, phiBNew); + track.addStub(stub); + track.setHitPattern(hitPattern(track)); + if (verbose_) { + edm::LogInfo("KMTFCore") << "Stub station =" << stub->depthRegion(); + + edm::LogInfo("KMTFCore") << "Updated Hit Pattern =" << track.hitPattern(); + } + + return true; +} + +void KMTFCore::vertexConstraint(l1t::KMTFTrack& track) { + if (useOfflineAlgo_) + vertexConstraintOffline(track); + else + vertexConstraintLUT(track); +} + +void KMTFCore::vertexConstraintOffline(l1t::KMTFTrack& track) { + double residual = -track.dxy(); + Matrix13 H; + H(0, 0) = 0; + H(0, 1) = 0; + H(0, 2) = 1; + + const std::vector& covLine = track.covariance(); + l1t::KMTFTrack::CovarianceMatrix cov(covLine.begin(), covLine.end()); + + double S = (ROOT::Math::Similarity(H, cov))(0, 0) + pointResolutionVertex_; + S = 1.0 / S; + Matrix31 Gain = cov * (ROOT::Math::Transpose(H)) * S; + track.setKalmanGain(track.step(), fabs(track.curvature()), Gain(0, 0), Gain(1, 0), Gain(2, 0)); + + if (verbose_) { + edm::LogInfo("KMTFCore") << "sigma3=" << cov(0, 3) << " sigma6=" << cov(3, 3); + edm::LogInfo("KMTFCore") << " K = " << track.curvature() << " + " << Gain(0, 0) << " * " << residual; + } + + int KNew = wrapAround(int(track.curvature() + Gain(0, 0) * residual), pow(2, BITSCURV - 1)); + int phiNew = wrapAround(int(track.positionAngle() + Gain(1, 0) * residual), pow(2, BITSPHI)); + int dxyNew = wrapAround(int(track.dxy() + Gain(2, 0) * residual), pow(2, BITSPHIB)); + if (verbose_) + edm::LogInfo("KMTFCore") << "Post fit impact parameter=" << dxyNew; + track.setCoordinatesAtVertex(KNew, phiNew, -residual); + Matrix33 covNew = cov - Gain * (H * cov); + l1t::KMTFTrack::CovarianceMatrix c; + c(0, 0) = covNew(0, 0); + c(0, 1) = covNew(0, 1); + c(0, 2) = covNew(0, 2); + c(1, 0) = covNew(1, 0); + c(1, 1) = covNew(1, 1); + c(1, 2) = covNew(1, 2); + c(2, 0) = covNew(2, 0); + c(2, 1) = covNew(2, 1); + c(2, 2) = covNew(2, 2); + track.setCovariance(c); + // track.covariance = track.covariance - Gain*H*track.covariance; +} + +void KMTFCore::vertexConstraintLUT(l1t::KMTFTrack& track) { + double residual = -track.dxy(); + uint absK = fabs(track.curvature()); + if (absK > pow(2, BITSCURV - 4) - 1) + absK = pow(2, BITSCURV - 4) - 1; + + std::pair GAIN = lutService_->vertexGain(track.hitPattern(), absK / 4); + track.setKalmanGain(track.step(), fabs(track.curvature()), GAIN.first, GAIN.second, -1); + + ap_fixed k_0 = + -(ap_ufixed(fabs(GAIN.first))) * ap_fixed(residual); + int KNew = ap_fixed(k_0 + ap_fixed(track.curvature())); + + if (verbose_) { + edm::LogInfo("KMTFCore") << "VERTEX GAIN(" << absK / 4 << ")= -" + << ap_ufixed(fabs(GAIN.first)).to_float() << " * " + << ap_fixed(residual).to_int() << " = " << k_0.to_int(); + } + + //int p_0 = fp_product(GAIN.second, int(residual), 7); + int p_0 = GAIN.second * int(residual); + int phiNew = wrapAround(track.positionAngle() + p_0, pow(2, BITSPHI - 1)); + track.setCoordinatesAtVertex(KNew, phiNew, -residual); +} + +int KMTFCore::hitPattern(const l1t::KMTFTrack& track) { + unsigned int mask = 0; + for (const auto& stub : track.stubs()) { + mask = mask + round(pow(2, stub->depthRegion() - 1)); + } + return mask; +} + +int KMTFCore::customBitmask(unsigned int bit1, unsigned int bit2, unsigned int bit3, unsigned int bit4) { + return bit1 * 1 + bit2 * 2 + bit3 * 4 + bit4 * 8; +} + +bool KMTFCore::getBit(int bitmask, int pos) { return (bitmask & (1 << pos)) >> pos; } + +void KMTFCore::setFourVectors(l1t::KMTFTrack& track) { + int etaINT = track.coarseEta(); + double lsbEta = M_PI / pow(2, 12); + + int charge = 1; + if (track.curvatureAtVertex() < 0) + charge = -1; + + int ptC = ptLUT(track.curvatureAtVertex()); + int ptU = ptLUT(track.curvatureAtMuon()); + + //if only one stub return the phi of the stub. + //Also set PT =0 and dxy=0 + if (track.stubs().size() == 1) { + ptC = 0; + track.setCoordinatesAtMuon(track.curvatureAtMuon(), track.stubs()[0]->coord1(), track.phiBAtMuon()); + track.setCoordinatesAtVertex(track.curvatureAtVertex(), track.phiAtVertex(), 0); + } + track.setPt(ptC, ptU); + //shift the dxy by 10 bits + track.setCoordinatesAtVertex(track.curvatureAtVertex(), track.phiAtVertex(), track.dxy() / 1024); + + //vertex + double pt = ptC * 0.03125; + double phi = (track.phiAtMuon() / 32) * M_PI / pow(2, 12); + double eta = etaINT * lsbEta; + track.setPtEtaPhi(pt, eta, phi); + track.setCharge(charge); + pt = double(ptLUT(track.curvatureAtMuon())) * 0.03125; + track.setPtEtaPhiDisplaced(pt, eta, phi); +} + +bool KMTFCore::estimateChiSquare(l1t::KMTFTrack& track, bool vertex) { + int K; + uint chi = 0; + uint chiErr = 0; + + //exception for 1 stub tracks and vertex constraint + //displaced track not allowed / prompt are allowed + if (track.stubs().size() == 1) { + if (!vertex) + return false; + else { + track.setApproxChi2(127, chiErr, vertex); + return true; + } + } + + std::vector prop; + std::vector propErrB; + std::vector propErrA; + std::vector cut; + + const l1t::MuonStubRef& innerStub = track.stubs()[track.stubs().size() - 1]; + + if (vertex) { + K = track.curvatureAtVertex(); + if (innerStub->depthRegion() == 1) { + prop = chiSquarePrompt1_; + propErrA = chiSquareErrAPrompt1_; + propErrB = chiSquareErrBPrompt1_; + } else if (innerStub->depthRegion() == 2) { + prop = chiSquarePrompt2_; + propErrA = chiSquareErrAPrompt2_; + propErrB = chiSquareErrBPrompt2_; + + } else if (innerStub->depthRegion() == 3) { + prop = chiSquarePrompt3_; + propErrA = chiSquareErrAPrompt3_; + propErrB = chiSquareErrBPrompt3_; + } + } else { + K = track.curvatureAtMuon(); + if (innerStub->depthRegion() == 1) { + prop = chiSquareDisp1_; + propErrA = chiSquareErrADisp1_; + propErrB = chiSquareErrBDisp1_; + + } else if (innerStub->depthRegion() == 2) { + prop = chiSquareDisp2_; + propErrA = chiSquareErrADisp2_; + propErrB = chiSquareErrBDisp2_; + + } else if (innerStub->depthRegion() == 3) { + prop = chiSquareDisp3_; + propErrA = chiSquareErrADisp3_; + propErrB = chiSquareErrBDisp3_; + } + } + + ap_fixed Kdig = K; + ap_fixed Kshifted = Kdig >> 4; + ap_ufixed absK = 0; + + if (Kshifted < 0) + absK = (-Kshifted); + else + absK = (Kshifted); + + for (unsigned int i = 0; i < (track.stubs().size() - 1); i++) { + const l1t::MuonStubRef& stub = track.stubs()[i]; + + int diffPhi = ap_fixed(stub->coord1() - innerStub->coord1()) >> 4; + int diffPhiB = ap_fixed(correctedPhiB(stub) - correctedPhiB(innerStub)) >> 4; + if (vertex) + diffPhiB = 0; + + if (verbose_) + edm::LogInfo("KMTFCore") << "Error propagation coefficients A=" + << propErrA[stub->depthRegion() - innerStub->depthRegion() - 1] + << " B=" << propErrB[stub->depthRegion() - innerStub->depthRegion() - 1] << " BK = " + << uint(ap_fixed<8, 2>(propErrB[stub->depthRegion() - innerStub->depthRegion() - 1]) * + (absK >> 4)); + uint positionError = propErrA[stub->depthRegion() - innerStub->depthRegion() - 1]; + if (stub->quality() < 6 || innerStub->quality() < 6) + positionError = positionError * 2; + + uint err = + positionError + uint(ap_fixed<8, 2>(propErrB[stub->depthRegion() - innerStub->depthRegion() - 1]) * absK); + ap_fixed<8, 2> propC = ap_fixed<8, 2>(prop[stub->depthRegion() - innerStub->depthRegion() - 1]); + ap_fixed AK = -propC * Kshifted; + int delta = diffPhi + diffPhiB + AK; + uint absDelta = delta < 0 ? -delta : delta; + chi = chi + absDelta; + chiErr = chiErr + err; + if (verbose_) { + edm::LogInfo("KMTFCore") << "Chi Square stub for track with pattern=" << track.hitPattern() + << " inner stub depth=" << innerStub->depthRegion() << "-> AK=" << int(AK) + << " stubDepth=" << stub->depthRegion() << " diff1=" << diffPhi << " diff2=" << diffPhiB + << " delta=" << absDelta << " absK=" << uint(absK) << " err=" << err; + } + } + if (verbose_) { + edm::LogInfo("KMTFCore") << "Chi Square =" << chi << " ChiSquare Error = " << chiErr; + } + + track.setApproxChi2(chi, chiErr, vertex); + if (chi > chiErr) + return false; + return true; +} + +void KMTFCore::setRank(l1t::KMTFTrack& track, bool vertex) { + uint chi = 0; + if (vertex) + chi = track.approxPromptChi2() > 127 ? 127 : track.approxPromptChi2(); + else + chi = track.approxDispChi2() > 127 ? 127 : track.approxDispChi2(); + + uint Q = 0; + for (const auto& stub : track.stubs()) { + if (stub->quality() > 2) + Q = Q + 2; + else + Q = Q + 1; + } + uint rank = Q * 4 - chi + 125; + + //exception for track 1100 + if (hitPattern(track) == customBitmask(0, 0, 1, 1)) { + rank = 1; + } + + //Exception for one stub tracks. + if (track.stubs().size() == 1) + rank = 0; + + if (verbose_) + edm::LogInfo("KMTFCore") << "Rank Calculated for vertex=" << vertex << " = " << rank; + track.setRank(rank, vertex); +} + +int KMTFCore::wrapAround(int value, int maximum) { + if (value > maximum - 1) + return wrapAround(value - 2 * maximum, maximum); + if (value < -maximum) + return wrapAround(value + 2 * maximum, maximum); + return value; +} + +int KMTFCore::encode(bool ownwheel, int sector, int tag) { + int wheel = ownwheel ? 1 : 0; + int phi = 0; + if (sector == 1) + phi = 1; + if (sector == -1) + phi = 2; + int addr = (wheel << 4) + (phi << 2) + tag; + return addr; +} + +std::pair KMTFCore::getByCode(const std::vector& tracks, int mask) { + for (uint i = 0; i < tracks.size(); ++i) { + edm::LogInfo("KMTFCore") << "Code=" << tracks[i].hitPattern() << ", track=" << mask; + if (tracks[i].hitPattern() == mask) + return std::make_pair(true, i); + } + return std::make_pair(false, 0); +} + +uint KMTFCore::twosCompToBits(int q) { + if (q >= 0) + return q; + else + return (~q) + 1; +} + +uint KMTFCore::etaStubRank(const l1t::MuonStubRef& stub) { + if (stub->etaQuality() == 3) + return 0; + if (stub->etaQuality() == 0) + return 0; + return (stub->etaQuality()); +} + +void KMTFCore::calculateEta(l1t::KMTFTrack& track) { + uint pattern = track.hitPattern(); + int wheel = track.stubs()[0]->etaRegion(); + uint awheel = fabs(wheel); + int sign = 1; + if (wheel < 0) + sign = -1; + uint nstubs = track.stubs().size(); + if (nstubs <= 1) { + track.setCoarseEta(0); + return; + } + uint mask = 0; + + for (unsigned int i = 0; i < track.stubs().size(); ++i) { + mask = mask | ((uint(fabs(track.stubs()[i]->etaRegion()) + 1) << (2 * (track.stubs()[i]->depthRegion() - 1)))); + } + if (verbose_) + edm::LogInfo("KMTFCore") << "Mask = " << mask; + + track.setCoarseEta(sign * lutService_->coarseEta(mask)); + if (verbose_) + edm::LogInfo("KMTFCore") << "Coarse Eta mask=" << mask << " set = " << sign * lutService_->coarseEta(mask); + track.setFineEta(0); +} + +uint KMTFCore::matchAbs(std::map& info, uint i, uint j) { + if (info[i] < info[j]) + return i; + else + return j; +} + +int KMTFCore::ptLUT(int K) { + int charge = (K >= 0) ? +1 : -1; + float lsb = 1.25 / float(1 << (BITSCURV - 1)); + float FK = fabs(K); + int pt = 0; + if (FK > 8191) + FK = 8191; + if (FK < 103) + FK = 103; + FK = FK * lsb; + if (FK == 0) { + pt = 8191; + } else { + float ptF = 1.0 / FK; //ct + pt = int(ptF / 0.03125); + } + + return pt; +} diff --git a/L1Trigger/Phase2L1GMT/src/L1TPhase2GMTBarrelStubProcessor.cc b/L1Trigger/Phase2L1GMT/src/L1TPhase2GMTBarrelStubProcessor.cc index 6e29a5440c4c2..80f565827c9ca 100644 --- a/L1Trigger/Phase2L1GMT/src/L1TPhase2GMTBarrelStubProcessor.cc +++ b/L1Trigger/Phase2L1GMT/src/L1TPhase2GMTBarrelStubProcessor.cc @@ -3,6 +3,8 @@ #include #include #include +#include +#include L1TPhase2GMTBarrelStubProcessor::L1TPhase2GMTBarrelStubProcessor() : minPhiQuality_(0), minBX_(-3), maxBX_(3) {} @@ -74,17 +76,18 @@ l1t::MuonStub L1TPhase2GMTBarrelStubProcessor::buildStubNoEta(const L1Phase2MuDT int sign = wheel > 0 ? 1 : -1; int sector = phiS.scNum(); int station = phiS.stNum(); - double globalPhi = (sector * 30) + phiS.phi() * 30. / 65535.; - if (globalPhi < -180) - globalPhi += 360; - if (globalPhi > 180) - globalPhi -= 360; - globalPhi = globalPhi * M_PI / 180.; - int phi = int(globalPhi / phiLSB_) + phiOffset_[station - 1]; - int phiB = phiS.phiBend() / phiBFactor_; - uint tag = phiS.index(); + + ap_uint<18> normalization0 = sector * ap_uint<15>(21845); + ap_int<18> normalization1 = ap_int<18>(ap_int<17>(phiS.phi()) * ap_ufixed<8, 0>(0.3183)); + ap_int<18> kmtf_phi = ap_int<18>(normalization0 + normalization1); + int phi = int(kmtf_phi); + float globalPhi = phi * M_PI / (1 << 17); + + // double globalPhi = (sector * 30) + phiS.phi() * 30. / 65535.; + int tag = phiS.index(); + int bx = phiS.bxNum() - 20; - int quality = 3; + int quality = phiS.quality(); uint tfLayer = phiS.stNum() - 1; int eta = -16384; if (station == 1) { @@ -103,8 +106,9 @@ l1t::MuonStub L1TPhase2GMTBarrelStubProcessor::buildStubNoEta(const L1Phase2MuDT //Now full eta eta = eta * sign; - l1t::MuonStub stub(wheel, sector, station, tfLayer, phi, phiB, tag, bx, quality, eta, 0, 0, 1); - stub.setOfflineQuantities(globalPhi, float(phiB), eta * etaLSB_, 0.0); + l1t::MuonStub stub(wheel, sector, station, tfLayer, phi, phiS.phiBend(), tag, bx, quality, eta, 0, 0, 1); + + stub.setOfflineQuantities(globalPhi, float(phiS.phiBend() * 0.49e-3), eta * etaLSB_, 0.0); return stub; } @@ -112,6 +116,9 @@ l1t::MuonStubCollection L1TPhase2GMTBarrelStubProcessor::makeStubs(const L1Phase const L1MuDTChambThContainer* etaContainer) { l1t::MuonStubCollection out; for (int bx = minBX_; bx <= maxBX_; bx++) { + ostringstream os; + if (verbose_ == 2) + os << "PATTERN "; for (int wheel = -2; wheel <= 2; wheel++) { for (int sector = 0; sector < 12; sector++) { for (int station = 1; station < 5; station++) { @@ -127,6 +134,24 @@ l1t::MuonStubCollection L1TPhase2GMTBarrelStubProcessor::makeStubs(const L1Phase continue; if (phiDigi.quality() < minPhiQuality_) continue; + + if (verbose_ == 2) { + ap_uint<64> wphi = ap_uint<17>(phiDigi.phi()); + ap_uint<64> wphib = ap_uint<13>(phiDigi.phiBend()); + ap_uint<64> wr1 = ap_uint<21>(0); + ap_uint<64> wq = ap_uint<4>(phiDigi.quality()); + ap_uint<64> wr2 = ap_uint<9>(0); + ap_uint<64> sN = 0; + sN = sN | wphi; + sN = sN | (wphib << 17); + sN = sN | (wr1 << 30); + sN = sN | (wq << 51); + sN = sN | (wr2 << 55); + unsigned int index = (station - 1) * 4 + phiDigi.index(); + os << std::setw(0) << std::dec << sector << " " << wheel << " " << station << " "; + os << std::uppercase << std::setfill('0') << std::setw(16) << std::hex << uint64_t(sN) << " "; + } + if (hasEta) { out.push_back(buildStub(phiDigi, tseta)); } else { @@ -136,29 +161,20 @@ l1t::MuonStubCollection L1TPhase2GMTBarrelStubProcessor::makeStubs(const L1Phase } } } + if (verbose_ == 2) + edm::LogInfo("BarrelStub") << os.str() << std::endl; } if (verbose_) { - printf("Barrel Stubs\n"); + edm::LogInfo("BarrelStub") << "Barrel Stubs"; for (const auto& stub : out) - printf( - "Barrel Stub bx=%d TF=%d etaRegion=%d phiRegion=%d depthRegion=%d coord1=%f,%d coord2=%f,%d eta1=%f,%d " - "eta2=%f,%d quality=%d etaQuality=%d\n", - stub.bxNum(), - stub.tfLayer(), - stub.etaRegion(), - stub.phiRegion(), - stub.depthRegion(), - stub.offline_coord1(), - stub.coord1(), - stub.offline_coord2(), - stub.coord2(), - stub.offline_eta1(), - stub.eta1(), - stub.offline_eta2(), - stub.eta2(), - stub.quality(), - stub.etaQuality()); + edm::LogInfo("BarrelStub") << "Barrel Stub bx=" << stub.bxNum() << " TF=" << stub.tfLayer() + << " etaRegion=" << stub.etaRegion() << " phiRegion=" << stub.phiRegion() + << " depthRegion=" << stub.depthRegion() << " coord1=" << stub.offline_coord1() << "," + << stub.coord1() << " coord2=" << stub.offline_coord2() << "," << stub.coord2() + << " eta1=" << stub.offline_eta1() << "," << stub.eta1() + << " eta2=" << stub.offline_eta2() << "," << stub.eta2() + << " quality=" << stub.quality() << " etaQuality=" << stub.etaQuality(); } return out; diff --git a/L1Trigger/Phase2L1GMT/src/L1TPhase2GMTEndcapStubProcessor.cc b/L1Trigger/Phase2L1GMT/src/L1TPhase2GMTEndcapStubProcessor.cc index 4287ed0401bf9..d9aa58ce1aeeb 100644 --- a/L1Trigger/Phase2L1GMT/src/L1TPhase2GMTEndcapStubProcessor.cc +++ b/L1Trigger/Phase2L1GMT/src/L1TPhase2GMTEndcapStubProcessor.cc @@ -22,7 +22,8 @@ L1TPhase2GMTEndcapStubProcessor::~L1TPhase2GMTEndcapStubProcessor() {} l1t::MuonStub L1TPhase2GMTEndcapStubProcessor::buildCSCOnlyStub(const CSCDetId& detid, const CSCCorrelatedLCTDigi& digi, - const L1TMuon::GeometryTranslator* translator) { + const L1TMuon::GeometryTranslator* translator, + unsigned int tag) { int endcap = detid.endcap(); int station = detid.station(); int chamber = detid.chamber(); @@ -62,7 +63,7 @@ l1t::MuonStub L1TPhase2GMTEndcapStubProcessor::buildCSCOnlyStub(const CSCDetId& else if (station == 4) //ME4/2 tfLayer = 3; - l1t::MuonStub stub(wheel, sector, station, tfLayer, phi, 0, 0, bx, quality, eta1, 0, 1, 0); + l1t::MuonStub stub(wheel, sector, station, tfLayer, phi, 0, tag, bx, quality, eta1, 0, 1, 0); stub.setOfflineQuantities(gp.phi().value(), 0.0, gp.eta(), 0.0); return stub; @@ -250,8 +251,10 @@ l1t::MuonStubCollection L1TPhase2GMTEndcapStubProcessor::makeStubs( for (; chamber != chend; ++chamber) { auto digi = (*chamber).second.first; auto dend = (*chamber).second.second; + unsigned int tag = 0; for (; digi != dend; ++digi) { - l1t::MuonStub stub = buildCSCOnlyStub((*chamber).first, *digi, t); + l1t::MuonStub stub = buildCSCOnlyStub((*chamber).first, *digi, t, tag); + tag = tag + 1; if (stub.bxNum() >= minBX_ && stub.bxNum() <= maxBX_) cscStubs.push_back(stub); } @@ -276,65 +279,34 @@ l1t::MuonStubCollection L1TPhase2GMTEndcapStubProcessor::makeStubs( l1t::MuonStubCollection combinedStubs = combineStubs(cscStubs, rpcStubs); if (verbose_) { - printf("CSC Stubs\n"); + edm::LogInfo("EndcapStub") << "CSC Stubs"; for (const auto& stub : cscStubs) - printf( - "CSC Stub bx=%d TF=%d etaRegion=%d phiRegion=%d depthRegion=%d coord1=%f,%d coord2=%f,%d eta1=%f,%d " - "eta2=%f,%d quality=%d etaQuality=%d\n", - stub.bxNum(), - stub.tfLayer(), - stub.etaRegion(), - stub.phiRegion(), - stub.depthRegion(), - stub.offline_coord1(), - stub.coord1(), - stub.offline_coord2(), - stub.coord2(), - stub.offline_eta1(), - stub.eta1(), - stub.offline_eta2(), - stub.eta2(), - stub.quality(), - stub.etaQuality()); - printf("RPC Stubs\n"); + edm::LogInfo("EndcapStub") << "CSC Stub bx=" << stub.bxNum() << " TF=" << stub.tfLayer() + << " etaRegion=" << stub.etaRegion() << " phiRegion=" << stub.phiRegion() + << " depthRegion=" << stub.depthRegion() << " coord1=" << stub.offline_coord1() << "," + << stub.coord1() << " coord2=" << stub.offline_coord2() << "," << stub.coord2() + << " eta1=" << stub.offline_eta1() << "," << stub.eta1() + << " eta2=" << stub.offline_eta2() << "," << stub.eta2() + << " quality=" << stub.quality() << " etaQuality=" << stub.etaQuality(); + + edm::LogInfo("EndcapStub") << "RPC Stubs"; for (const auto& stub : rpcStubs) - printf( - "RPC Stub bx=%d TF=%d etaRegion=%d phiRegion=%d depthRegion=%d coord1=%f,%d coord2=%f,%d eta1=%f,%d " - "eta2=%f,%d quality=%d etaQuality=%d\n", - stub.bxNum(), - stub.tfLayer(), - stub.etaRegion(), - stub.phiRegion(), - stub.depthRegion(), - stub.offline_coord1(), - stub.coord1(), - stub.offline_coord2(), - stub.coord2(), - stub.offline_eta1(), - stub.eta1(), - stub.offline_eta2(), - stub.eta2(), - stub.quality(), - stub.etaQuality()); + edm::LogInfo("EndcapStub") << "RPC Stub bx=" << stub.bxNum() << " TF=" << stub.tfLayer() + << " etaRegion=" << stub.etaRegion() << " phiRegion=" << stub.phiRegion() + << " depthRegion=" << stub.depthRegion() << " coord1=" << stub.offline_coord1() << "," + << stub.coord1() << " coord2=" << stub.offline_coord2() << "," << stub.coord2() + << " eta1=" << stub.offline_eta1() << "," << stub.eta1() + << " eta2=" << stub.offline_eta2() << "," << stub.eta2() + << " quality=" << stub.quality() << " etaQuality=" << stub.etaQuality(); + for (const auto& stub : combinedStubs) - printf( - "Combined Stub bx=%d TF=%d etaRegion=%d phiRegion=%d depthRegion=%d coord1=%f,%d coord2=%f,%d eta1=%f,%d " - "eta2=%f,%d quality=%d etaQuality=%d\n", - stub.bxNum(), - stub.tfLayer(), - stub.etaRegion(), - stub.phiRegion(), - stub.depthRegion(), - stub.offline_coord1(), - stub.coord1(), - stub.offline_coord2(), - stub.coord2(), - stub.offline_eta1(), - stub.eta1(), - stub.offline_eta2(), - stub.eta2(), - stub.quality(), - stub.etaQuality()); + edm::LogInfo("EndcapStub") << "Combined Stub bx=" << stub.bxNum() << " TF=" << stub.tfLayer() + << " etaRegion=" << stub.etaRegion() << " phiRegion=" << stub.phiRegion() + << " depthRegion=" << stub.depthRegion() << " coord1=" << stub.offline_coord1() << "," + << stub.coord1() << " coord2=" << stub.offline_coord2() << "," << stub.coord2() + << " eta1=" << stub.offline_eta1() << "," << stub.eta1() + << " eta2=" << stub.offline_eta2() << "," << stub.eta2() + << " quality=" << stub.quality() << " etaQuality=" << stub.etaQuality(); } return combinedStubs; diff --git a/L1Trigger/Phase2L1GMT/src/SAMuonCleaner.cc b/L1Trigger/Phase2L1GMT/src/SAMuonCleaner.cc new file mode 100644 index 0000000000000..acb733be263f8 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/src/SAMuonCleaner.cc @@ -0,0 +1,156 @@ +#include "L1Trigger/Phase2L1GMT/interface/SAMuonCleaner.h" + +void SAMuonCleaner::overlapCleanTrack(l1t::SAMuon& source, const l1t::SAMuon& other, bool eq) { + int rank1 = source.hwQual(); + int rank2 = other.hwQual(); + bool keep = true; + if ((eq && rank1 <= rank2) || ((!eq) && rank1 < rank2)) + keep = false; + l1t::MuonStubRefVector stubs; + for (const auto& s1 : source.stubs()) { + bool ok = true; + for (const auto& s2 : other.stubs()) { + if ((*s1) == (*s2) && (!keep)) + ok = false; + } + if (ok) { + stubs.push_back(s1); + } + } + source.setStubs(stubs); +} + +void SAMuonCleaner::overlapCleanTrackInter(l1t::SAMuon& source, const l1t::SAMuon& other) { + bool keep = false; + l1t::MuonStubRefVector stubs; + for (const auto& s1 : source.stubs()) { + bool ok = true; + for (const auto& s2 : other.stubs()) { + if ((*s1) == (*s2) && (!keep)) + ok = false; + } + if (ok) { + stubs.push_back(s1); + } + } + source.setStubs(stubs); +} + +std::vector SAMuonCleaner::cleanTF(const std::vector& tfMuons) { + std::vector out; + for (unsigned int i = 0; i < tfMuons.size(); ++i) { + l1t::SAMuon source = tfMuons[i]; + for (unsigned int j = 0; j < tfMuons.size(); ++j) { + if (i == j) + continue; + overlapCleanTrack(source, tfMuons[j], false); + } + if (source.stubs().size() > 1) + out.push_back(source); + } + return out; +} + +std::vector SAMuonCleaner::interTFClean(const std::vector& bmtf, + const std::vector& omtf, + const std::vector& emtf) { + std::vector out = emtf; + for (unsigned int i = 0; i < omtf.size(); ++i) { + l1t::SAMuon source = omtf[i]; + for (const auto& other : emtf) { + overlapCleanTrackInter(source, other); + } + if (source.stubs().size() > 1) + out.push_back(source); + } + for (unsigned int i = 0; i < bmtf.size(); ++i) { + l1t::SAMuon source = bmtf[i]; + for (const auto& other : omtf) { + overlapCleanTrackInter(source, other); + } + if (source.stubs().size() > 1) + out.push_back(source); + } + return out; +} + +void SAMuonCleaner::swap(std::vector& list, int i, int j) { + const l1t::SAMuon& track1 = list[i]; + const l1t::SAMuon& track2 = list[j]; + + int pt1 = track1.pt(); + int pt2 = track2.pt(); + bool swap = false; + if (pt1 > pt2) + swap = false; + else + swap = true; + + if (swap) { + l1t::SAMuon tmp = list[i]; + list[i] = list[j]; + list[j] = tmp; + } +} + +void SAMuonCleaner::sort(std::vector& in) { + l1t::SAMuon nullTrack; + nullTrack.setP4(reco::Candidate::LorentzVector(0, 0, 0, 0.000001)); + while (in.size() < 32) + in.push_back(nullTrack); + + for (uint iteration = 0; iteration < 16; ++iteration) { + for (uint i = 0; i < 32; i = i + 2) { + swap(in, i, i + 1); + } + for (uint i = 1; i < 31; i = i + 2) { + swap(in, i, i + 1); + } + } + + std::vector out; + for (const auto& track : in) { + if (!track.stubs().empty() && out.size() < 12) + out.push_back(track); + } + in = out; +} + +std::vector SAMuonCleaner::cleanTFMuons(const std::vector& muons) { + std::vector out; + + //split into collections + std::vector bmtf; + std::vector omtf_pos; + std::vector emtf_pos; + std::vector omtf_neg; + std::vector emtf_neg; + + for (const auto& mu : muons) { + if (mu.tfType() == l1t::tftype::bmtf) { + bmtf.push_back(mu); + } else if (mu.tfType() == l1t::tftype::omtf_pos) { + omtf_pos.push_back(mu); + } else if (mu.tfType() == l1t::tftype::emtf_pos) { + emtf_pos.push_back(mu); + } else if (mu.tfType() == l1t::tftype::omtf_neg) { + omtf_neg.push_back(mu); + } else if (mu.tfType() == l1t::tftype::emtf_neg) { + emtf_neg.push_back(mu); + } + } + + std::vector omtf_cleaned = cleanTF(omtf_pos); + std::vector omtf_neg_cleaned = cleanTF(omtf_neg); + omtf_cleaned.insert(omtf_cleaned.end(), omtf_neg_cleaned.begin(), omtf_neg_cleaned.end()); + sort(omtf_cleaned); + + std::vector emtf_cleaned = cleanTF(emtf_pos); + std::vector emtf_neg_cleaned = cleanTF(emtf_neg); + emtf_cleaned.insert(emtf_cleaned.end(), emtf_neg_cleaned.begin(), emtf_neg_cleaned.end()); + sort(emtf_cleaned); + + std::vector cleaned = interTFClean(bmtf, omtf_cleaned, emtf_cleaned); + sort(cleaned); + return cleaned; +} diff --git a/L1Trigger/Phase2L1GMT/src/TPS.cc b/L1Trigger/Phase2L1GMT/src/TPS.cc new file mode 100644 index 0000000000000..773cad5d64150 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/src/TPS.cc @@ -0,0 +1,122 @@ +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "DataFormats/L1TMuonPhase2/interface/TrackerMuon.h" +#include "L1Trigger/Phase2L1GMT/interface/TPS.h" + +using namespace Phase2L1GMT; + +TPS::TPS(const edm::ParameterSet& iConfig) + : verbose_(iConfig.getParameter("verbose")), + tt_track_converter_(new TrackConverter(iConfig.getParameter("trackConverter"))), + tps_(new TPSAlgorithm(iConfig.getParameter("trackMatching"))), + isolation_(new Isolation(iConfig.getParameter("isolation"))) {} + +std::vector TPS::processEvent(const std::vector >& tracks, + const l1t::MuonStubRefVector& muonStubs) { + //Split tracks to the links as they come + std::array >, 9> loctracks; + for (unsigned i = 0; i < 9; ++i) + loctracks[i] = associateTracksWithNonant(tracks, i); + + //Convert TT tracks to our internal tracking format + std::array, 9> convertedTracks; + for (unsigned i = 0; i < 9; ++i) + convertedTracks[i] = tt_track_converter_->convertTracks(loctracks.at(i)); + + //Transition stubs to different nonants with overlap + std::array stubs; + for (int i = 0; i < 9; ++i) + stubs[i] = associateStubsWithNonant(muonStubs, i); + + //run track - muon matching per nonant + std::array, 9> mus; + for (int i = 0; i < 9; ++i) + mus[i] = tps_->processNonant(convertedTracks.at(i), stubs.at(i)); + + //clean neighboring nonants + std::vector > muCleaneds; + muCleaneds.push_back(tps_->cleanNeighbor(mus[0], mus[8], mus[1], true)); + muCleaneds.push_back(tps_->cleanNeighbor(mus[1], mus[0], mus[2], false)); + muCleaneds.push_back(tps_->cleanNeighbor(mus[2], mus[1], mus[3], true)); + muCleaneds.push_back(tps_->cleanNeighbor(mus[3], mus[2], mus[4], false)); + muCleaneds.push_back(tps_->cleanNeighbor(mus[4], mus[3], mus[5], true)); + muCleaneds.push_back(tps_->cleanNeighbor(mus[5], mus[4], mus[6], false)); + muCleaneds.push_back(tps_->cleanNeighbor(mus[6], mus[5], mus[7], true)); + muCleaneds.push_back(tps_->cleanNeighbor(mus[7], mus[6], mus[8], false)); + //ARGH! 9 sectors - so some duplicates very rarely + muCleaneds.push_back(tps_->cleanNeighbor(mus[8], mus[7], mus[0], false)); + + //merge all the collections + std::vector mergedCleaned; + for (auto&& v : muCleaneds) { + mergedCleaned.insert(mergedCleaned.end(), v.begin(), v.end()); + } + + std::vector trackMatchedMuonsNoIso = tps_->convert(mergedCleaned, 32); + + //sorter here: + std::vector sortedTrackMuonsNoIso = tps_->sort(trackMatchedMuonsNoIso, 12); + + tps_->SetQualityBits(sortedTrackMuonsNoIso); + + //Isolation and tau3mu will read those muons and all 9 collections of convertedTracks* + std::vector mergedconvertedTracks; + for (auto&& v : convertedTracks) { + mergedconvertedTracks.insert(mergedconvertedTracks.end(), v.begin(), v.end()); + } + + isolation_->isolation_allmu_alltrk(sortedTrackMuonsNoIso, mergedconvertedTracks); + + // To be enable when tau->3mu rate study is ready + //tauto3mu_->GetTau3Mu(sortedTrackMuonsNoIso, mergedconvertedTracks); + + tps_->outputGT(sortedTrackMuonsNoIso); + + return sortedTrackMuonsNoIso; //when we add more collections like tau3mu etc we change that +} + +std::vector > TPS::associateTracksWithNonant( + const std::vector >& tracks, uint processor) { + std::vector > out; + for (const auto& track : tracks) { + if (track->phiSector() == processor) { + out.push_back(track); + } + } + return out; +} + +l1t::SAMuonRefVector TPS::associateMuonsWithNonant(const l1t::SAMuonRefVector& muons, uint processor) { + l1t::SAMuonRefVector out; + + ap_int center = ap_int(processor * 910); + + for (const auto& s : muons) { + ap_int deltaPhi = s->hwPhi() - center; + ap_uint absDeltaPhi = + (deltaPhi < 0) ? ap_uint(-deltaPhi) : ap_uint(deltaPhi); + if (absDeltaPhi < 683) + out.push_back(s); + } + return out; +} + +l1t::MuonStubRefVector TPS::associateStubsWithNonant(const l1t::MuonStubRefVector& allStubs, uint processor) { + l1t::MuonStubRefVector out; + + ap_int center = ap_int((processor * 910) / 8); //was 32 + + for (const auto& s : allStubs) { + ap_int phi = 0; + if (s->quality() & 0x1) + phi = s->coord1(); + else + phi = s->coord2(); + + ap_int deltaPhi = phi - center; + ap_uint absDeltaPhi = + (deltaPhi < 0) ? ap_uint(-deltaPhi) : ap_uint(deltaPhi); + if (absDeltaPhi < 168) //was 42 + out.push_back(s); + } + return out; +} diff --git a/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc b/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc new file mode 100644 index 0000000000000..95a7503b22c0c --- /dev/null +++ b/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc @@ -0,0 +1,544 @@ +#include "L1Trigger/Phase2L1GMT/interface/TPSAlgorithm.h" + +using namespace Phase2L1GMT; + +TPSAlgorithm::TPSAlgorithm(const edm::ParameterSet& iConfig) : verbose_(iConfig.getParameter("verbose")) {} + +TPSAlgorithm::~TPSAlgorithm() {} + +std::vector TPSAlgorithm::processNonant(const std::vector& convertedTracks, + const l1t::MuonStubRefVector& stubs) { + std::vector preMuons; + for (const auto& track : convertedTracks) { + PreTrackMatchedMuon mu = processTrack(track, stubs); + if (mu.valid() && preMuons.size() < 16) + preMuons.push_back(mu); + } + std::vector cleanedMuons = clean(preMuons); + return cleanedMuons; +} + +std::vector TPSAlgorithm::cleanNeighbor(const std::vector& muons, + const std::vector& muonsPrevious, + const std::vector& muonsNext, + bool equality) { + std::vector out; + + if (muons.empty()) + return out; + + if (verbose_ == 1) { + edm::LogInfo("TPSAlgo") << "-----Cleaning Up Muons in the neighbours"; + edm::LogInfo("TPSAlgo") << "Before:"; + } + + for (uint i = 0; i < muons.size(); ++i) { + if (verbose_ == 1) { + muons[i].print(); + } + ap_uint<5> mask = 0x1f; + for (uint j = 0; j < muonsPrevious.size(); ++j) { + mask = mask & cleanMuon(muons[i], muonsPrevious[j], equality); + } + for (uint j = 0; j < muonsNext.size(); ++j) { + mask = mask & cleanMuon(muons[i], muonsNext[j], equality); + } + if (mask) { + if (verbose_ == 1) + edm::LogInfo("TPSAlgo") << "kept"; + out.push_back(muons[i]); + } else { + if (verbose_ == 1) + edm::LogInfo("TPSAlgo") << "discarded"; + } + } + return out; +} + +std::vector TPSAlgorithm::convert(std::vector& muons, uint maximum) { + std::vector out; + for (const auto& mu : muons) { + if (out.size() == maximum) + break; + l1t::TrackerMuon muon(mu.trkPtr(), mu.charge(), mu.pt(), mu.eta(), mu.phi(), mu.z0(), mu.d0(), mu.quality()); + muon.setMuonRef(mu.muonRef()); + for (const auto& stub : mu.stubs()) + muon.addStub(stub); + + uint matches = 0; + uint mask = mu.matchMask(); + + for (uint i = 0; i < 10; i = i + 1) { + if (mask & (1 << i)) + matches++; + } + muon.setNumberOfMatches(matches); + out.push_back(muon); + + if (verbose_ == 1) { + edm::LogInfo("TPSAlgo") << "Final Muon:" << std::flush; + muon.print(); + } + } + return out; +} + +void TPSAlgorithm::SetQualityBits(std::vector& muons) { + for (auto& mu : muons) { + // A preliminary suggestion. Need feedback from the menu group + bool veryloose = mu.numberOfMatches() > 0; + bool loose = mu.numberOfMatches() > 1; + bool medium = mu.stubs().size() > 1; + bool tight = mu.numberOfMatches() > 2; + int qualbit = 0; + qualbit = (veryloose << 0) | (loose << 1) | (medium << 2) | (tight << 3); + mu.setHwQual(qualbit); + } +} + +bool TPSAlgorithm::outputGT(std::vector& muons) { + for (auto& mu : muons) { + wordtype word1 = 0; + wordtype word2 = 0; + + int bstart = 0; + bstart = wordconcat(word1, bstart, mu.hwPt(), BITSGTPT); + bstart = wordconcat(word1, bstart, mu.hwPhi(), BITSGTPHI); + bstart = wordconcat(word1, bstart, mu.hwEta(), BITSGTETA); + bstart = wordconcat(word1, bstart, mu.hwZ0(), BITSGTZ0); + bstart = wordconcat(word1, bstart, (mu.hwD0() >> 2), BITSGTD0); + + bstart = 0; + bstart = wordconcat(word2, bstart, mu.hwCharge(), 1); + bstart = wordconcat(word2, bstart, mu.hwQual(), BITSGTQUAL); + bstart = wordconcat(word2, bstart, mu.hwIso(), BITSGTISO); + bstart = wordconcat(word2, bstart, mu.hwBeta(), BITSGTBETA); + + std::array wordout = {{word1, word2}}; + mu.setWord(wordout); + } + return true; +} + +std::vector TPSAlgorithm::sort(std::vector& muons, uint maximum) { + if (muons.size() < 2) + return muons; + + std::sort(muons.begin(), muons.end(), [](l1t::TrackerMuon a, l1t::TrackerMuon b) { return a.hwPt() > b.hwPt(); }); + std::vector out; + for (unsigned int i = 0; i < muons.size(); ++i) { + out.push_back(muons[i]); + if (i == (maximum - 1)) + break; + } + + return out; +} + +propagation_t TPSAlgorithm::propagate(const ConvertedTTTrack& track, uint layer) { + static const std::array*, 5> lt_prop_coord1 = { + {lt_prop_coord1_0, lt_prop_coord1_1, lt_prop_coord1_2, lt_prop_coord1_3, lt_prop_coord1_4}}; + static const std::array*, 5> lt_prop_coord2 = { + {lt_prop_coord2_0, lt_prop_coord2_1, lt_prop_coord2_2, lt_prop_coord2_3, lt_prop_coord2_4}}; + + static const std::array*, 5> lt_res0_coord1 = { + {lt_res0_coord1_0, lt_res0_coord1_1, lt_res0_coord1_2, lt_res0_coord1_3, lt_res0_coord1_4}}; + static const std::array*, 5> lt_res1_coord1 = { + {lt_res1_coord1_0, lt_res1_coord1_1, lt_res1_coord1_2, lt_res1_coord1_3, lt_res1_coord1_4}}; + static const std::array*, 5> lt_res0_coord2 = { + {lt_res0_coord2_0, lt_res0_coord2_1, lt_res0_coord2_2, lt_res0_coord2_3, lt_res0_coord2_4}}; + static const std::array*, 5> lt_res1_coord2 = { + {lt_res1_coord2_0, lt_res1_coord2_1, lt_res1_coord2_2, lt_res1_coord2_3, lt_res1_coord2_4}}; + + static const std::array*, 5> lt_res0_eta1 = { + {lt_res0_eta1_0, lt_res0_eta1_1, lt_res0_eta1_2, lt_res0_eta1_3, lt_res0_eta1_4}}; + static const std::array*, 5> lt_res1_eta1 = { + {lt_res1_eta_0, lt_res1_eta_1, lt_res1_eta_2, lt_res1_eta_3, lt_res1_eta_4}}; + + static const std::array*, 5> lt_res0_eta2 = { + {lt_res0_eta2_0, lt_res0_eta2_1, lt_res0_eta2_2, lt_res0_eta2_3, lt_res0_eta2_4}}; + + static const uint barrellimit[5] = {barrelLimit0_, barrelLimit1_, barrelLimit2_, barrelLimit3_, barrelLimit4_}; + + ap_uint prop_coord1 = 0; + ap_uint prop_coord2 = 0; + ap_uint res0_coord1 = 0; + ap_uint res1_coord1 = 0; + ap_uint res0_coord2 = 0; + ap_uint res1_coord2 = 0; + ap_uint res0_eta1 = 0; + ap_uint res1_eta = 0; + ap_uint res0_eta2 = 0; + ap_uint<1> is_barrel = 0; + + uint reducedAbsEta = track.abseta() / 8; + + //Propagate to layers + assert(layer < 5); + prop_coord1 = lt_prop_coord1[layer][reducedAbsEta]; + prop_coord2 = lt_prop_coord2[layer][reducedAbsEta]; + res0_coord1 = lt_res0_coord1[layer][reducedAbsEta]; + res1_coord1 = lt_res1_coord1[layer][reducedAbsEta]; + res0_coord2 = lt_res0_coord2[layer][reducedAbsEta]; + res1_coord2 = lt_res1_coord2[layer][reducedAbsEta]; + res0_eta1 = lt_res0_eta1[layer][reducedAbsEta]; + res1_eta = lt_res1_eta1[layer][reducedAbsEta]; + res0_eta2 = lt_res0_eta2[layer][reducedAbsEta]; + is_barrel = reducedAbsEta < barrellimit[layer] ? 1 : 0; + + propagation_t out; + ap_int curvature = track.curvature(); + ap_int phi = track.phi(); + ap_int c1kFull = prop_coord1 * curvature; + ap_int c1k = (c1kFull) / 1024; + ap_int coord1 = phi - c1k; + + out.coord1 = coord1 / PHIDIVIDER; + + ap_int c2kFull = prop_coord2 * curvature; + + ap_int c2k = (c2kFull) / 1024; + if (is_barrel) + out.coord2 = -c2k / PHIDIVIDER; + else + out.coord2 = (phi - c2k) / PHIDIVIDER; + + ap_int eta = track.eta(); + out.eta = eta / ETADIVIDER; + + ap_uint<2 * BITSTTCURV - 2> curvature2All = curvature * curvature; + ap_uint curvature2 = curvature2All / 2; + + /////New propagation for sigma + ap_uint absK = 0; + if (track.curvature() < 0) + absK = ap_uint(-track.curvature()); + else + absK = ap_uint(track.curvature()); + + //bound the resolution propagation + if (absK > 4095) + absK = 4095; + + ap_uint s1kFull = res1_coord1 * absK; + ap_uint s1k = s1kFull / 1024; + ap_uint sigma1 = res0_coord1 + s1k; + out.sigma_coord1 = ap_uint(sigma1 / PHIDIVIDER); + + ap_uint s2kFull = res1_coord2 * absK; + ap_uint s2k = s2kFull / 1024; + ap_uint sigma2 = res0_coord2 + s2k; + out.sigma_coord2 = ap_uint(sigma2 / PHIDIVIDER); + + ap_uint resetak = (res1_eta * curvature2) >> 23; + ap_ufixed sigma_eta1 = res0_eta1 + resetak; + out.sigma_eta1 = ap_uint(sigma_eta1); + ap_ufixed sigma_eta2 = res0_eta2 + resetak; + out.sigma_eta2 = ap_uint(sigma_eta2); + out.valid = 1; + out.is_barrel = is_barrel; + + if (verbose_ == 1) { + edm::LogInfo("TPSAlgo") << "Propagating to layer " << int(layer) << ":is barrel=" << out.is_barrel.to_int() + << " coords=" << out.coord1.to_int() << "+-" << out.sigma_coord1.to_int() << " , " + << out.coord2.to_int() << " +-" << out.sigma_coord2.to_int() + << " etas = " << out.eta.to_int() << " +- " << out.sigma_eta1.to_int() << " +-" + << out.sigma_eta2.to_int(); + + edm::LogInfo("TPSAlgo") << "----- breakout of sigma 1 : constant=" << res0_coord1.to_int() + << " slope=" << res1_coord1.to_int() << " before division=" << s1k.to_int(); + + edm::LogInfo("TPSAlgo") << "----- breakout of sigma 2 : constant=" << res0_coord2.to_int() + << " slope=" << res1_coord2.to_int() << " before division=" << s2k.to_int(); + } + return out; +} + +ap_uint TPSAlgorithm::deltaEta(const ap_int& eta1, const ap_int& eta2) { + ap_fixed dEta = eta1 - eta2; + if (dEta < 0) + return ap_uint(-dEta); + else + return ap_uint(dEta); +} + +ap_uint TPSAlgorithm::deltaCoord(const ap_int& phi1, + const ap_int& phi2) { + ap_int dPhiRoll = phi1 - phi2; + ap_ufixed dPhi; + if (dPhiRoll < 0) + dPhi = ap_ufixed(-dPhiRoll); + else + dPhi = ap_ufixed(dPhiRoll); + + return ap_uint(dPhi); +} + +match_t TPSAlgorithm::match(const propagation_t prop, const l1t::MuonStubRef& stub, uint trackID) { + if (verbose_ == 1) { + edm::LogInfo("TPSAlgo") << "Matching to coord1=" << stub->coord1() << " coord2=" << stub->coord2() + << " eta1=" << stub->eta1() << " eta2=" << stub->eta2(); + + stub->print(); + } + //Matching of Coord1 + ap_uint<1> coord1Matched; + ap_uint deltaCoord1 = deltaCoord(prop.coord1, stub->coord1()); + if (deltaCoord1 <= prop.sigma_coord1 && (stub->quality() & 0x1)) { + coord1Matched = 1; + } else { + coord1Matched = 0; + } + if (verbose_ == 1) + edm::LogInfo("TPSAlgo") << "Coord1 matched=" << coord1Matched.to_int() << " delta=" << deltaCoord1.to_int() + << " res=" << prop.sigma_coord1.to_int(); + + //Matching of Coord2 + ap_uint<1> coord2Matched; + ap_uint deltaCoord2 = deltaCoord(prop.coord2, stub->coord2()); + if (deltaCoord2 <= prop.sigma_coord2 && (stub->quality() & 0x2)) { + coord2Matched = 1; + } else { + coord2Matched = 0; + } + if (verbose_ == 1) + edm::LogInfo("TPSAlgo") << "Coord2 matched=" << coord2Matched.to_int() << " delta=" << deltaCoord2.to_int() + << " res=" << prop.sigma_coord2.to_int(); + + //Matching of Eta1 + + ap_uint<1> eta1Matched; + + //if we have really bad quality[Barrel no eta] + //increase the resolution + ap_ufixed prop_sigma_eta1; + if (stub->etaQuality() == 0) + prop_sigma_eta1 = prop.sigma_eta1 + 6; + else + prop_sigma_eta1 = prop.sigma_eta1; + + ap_uint deltaEta1 = deltaEta(prop.eta, stub->eta1()); + if (deltaEta1 <= prop_sigma_eta1 && (stub->etaQuality() == 0 || (stub->etaQuality() & 0x1))) + eta1Matched = 1; + else + eta1Matched = 0; + + if (verbose_ == 1) + edm::LogInfo("TPSAlgo") << "eta1 matched=" << eta1Matched.to_int() << " delta=" << deltaEta1.to_int() + << " res=" << prop_sigma_eta1.to_int(); + + //Matching of Eta2 + + ap_uint<1> eta2Matched; + + ap_uint deltaEta2 = deltaEta(prop.eta, stub->eta2()); + if (deltaEta2 <= prop.sigma_eta2 && (stub->etaQuality() & 0x2)) + eta2Matched = 1; + else + eta2Matched = 0; + match_t out; + out.id = trackID; + + if (verbose_ == 1) + edm::LogInfo("TPSAlgo") << "eta2 matched=" << eta2Matched.to_int() << " delta=" << deltaEta2.to_int() + << " res=" << prop.sigma_eta2.to_int(); + + //Note I divided by 4 because of the new coordinate. Make it automatic + + //if barrel, coord1 has to always be matched, coord2 maybe and eta1 is needed if etaQ=0 or then the one that depends on eta quality + if (prop.is_barrel) { + out.valid = (coord1Matched == 1 && (eta1Matched == 1 || eta2Matched == 1)) ? 1 : 0; + if (out.valid == 0) { + out.quality = 0; + } else { + out.quality = 32 - deltaCoord1 / 4; + if (coord2Matched == 1) { + out.quality += 32 - deltaCoord2 / 4; + out.valid = 3; + } + } + } + //if endcap each coordinate is independent except the case where phiQuality=1 and etaQuality==3 + else { + bool match1 = (coord1Matched == 1 && eta1Matched == 1); + bool match2 = (coord2Matched == 1 && eta2Matched == 1); + bool match3 = + (coord1Matched == 1 && (eta1Matched || eta2Matched) && stub->etaQuality() == 3 && stub->quality() == 1); + out.valid = (match1 || match2 || match3) ? 1 : 0; + if (out.valid == 0) + out.quality = 0; + else { + out.quality = 0; + if (match1 || match3) + out.quality += 32 - deltaCoord1 / 4; + if (match2) { + out.quality += 32 - deltaCoord2 / 4; + if (match1 || match3) + out.valid = 3; + } + } + } + if (verbose_ == 1) + edm::LogInfo("TPSAlgo") << "GlobalMatchQuality = " << out.quality.to_int(); + out.stubRef = stub; + return out; +} + +match_t TPSAlgorithm::propagateAndMatch(const ConvertedTTTrack& track, const l1t::MuonStubRef& stub, uint trackID) { + propagation_t prop = propagate(track, stub->tfLayer()); + return match(prop, stub, trackID); +} + +match_t TPSAlgorithm::getBest(const std::vector matches) { + match_t best = matches[0]; + for (const auto& m : matches) { + if (m.quality > best.quality) + best = m; + } + + return best; +} + +void TPSAlgorithm::matchingInfos(std::vector matchInfo, + PreTrackMatchedMuon& muon, + ap_uint& quality) { + if (!matchInfo.empty()) { + match_t b = getBest(matchInfo); + if (b.valid != 0) { + muon.addStub(b.stubRef, b.valid); + if (b.isGlobal) + muon.addMuonRef(b.muRef); + quality += b.quality; + } + } +} + +PreTrackMatchedMuon TPSAlgorithm::processTrack(const ConvertedTTTrack& track, const l1t::MuonStubRefVector& stubs) { + std::array, 6> matchInfos; + + if (verbose_ == 1 && !stubs.empty()) { + edm::LogInfo("TPSAlgo") << "-----------processing new track----------"; + track.print(); + } + for (const auto& stub : stubs) { + match_t m = propagateAndMatch(track, stub, 0); + if (m.valid != 0 && stub->tfLayer() < 6) { + matchInfos[stub->tfLayer()].push_back(m); + } + } + + ap_ufixed<6, 6, AP_TRN_ZERO, AP_SAT_SYM> ptPenalty = ap_ufixed<6, 6, AP_TRN_ZERO, AP_SAT_SYM>(track.pt() / 32); + + ap_uint quality = 0; + PreTrackMatchedMuon muon(track.charge(), track.pt(), track.eta(), track.phi(), track.z0(), track.d0()); + + for (auto&& m : matchInfos) + matchingInfos(m, muon, quality); + + muon.setOfflineQuantities(track.offline_pt(), track.offline_eta(), track.offline_phi()); + muon.setTrkPtr(track.trkPtr()); + + ap_uint<8> etaAddr = muon.eta() < 0 ? ap_uint<8>(-muon.eta() / 256) : ap_uint<8>((muon.eta()) / 256); + ap_uint<8> ptAddr = muon.pt() > 4095 ? ap_uint<8>(15) : ap_uint<8>(muon.pt() / 256); + ap_uint<8> addr = ptAddr | (etaAddr << 4); + ap_uint<8> qualityCut = lt_tpsID[addr]; + + if (!muon.stubs().empty()) { //change the ID for now + muon.setValid(true); + muon.setQuality(quality + ptPenalty); + } else { + muon.setValid(false); + muon.setQuality(0); + muon.resetGlobal(); + } + if (verbose_ == 1) + muon.print(); + + if (verbose_ == 1 && !stubs.empty()) { //patterns for HLS + + edm::LogInfo("TPSAlgo") << "TPS " << track.trkPtr()->phiSector() << std::flush; + track.printWord(); + + for (uint i = 0; i < 16; ++i) { + if (stubs.size() > i) { + edm::LogInfo("TPSAlgo") << "remember to implement printout of muon"; + } else { + edm::LogInfo("TPSAlgo") << std::hex << std::setw(8) << 0 << std::flush; + edm::LogInfo("TPSAlgo") << std::hex << std::setw(16) << 0x1ff000000000000 << std::flush; + edm::LogInfo("TPSAlgo") << std::hex << std::setw(16) << 0x1ff000000000000 << std::flush; + edm::LogInfo("TPSAlgo") << std::hex << std::setw(16) << 0x1ff000000000000 << std::flush; + edm::LogInfo("TPSAlgo") << std::hex << std::setw(16) << 0x1ff000000000000 << std::flush; + edm::LogInfo("TPSAlgo") << std::hex << std::setw(16) << 0x1ff000000000000 << std::flush; + } + } + muon.printWord(); + edm::LogInfo("TPSAlgo") << std::endl; + } + return muon; +} + +ap_uint<5> TPSAlgorithm::cleanMuon(const PreTrackMatchedMuon& mu, const PreTrackMatchedMuon& other, bool eq) { + ap_uint<5> valid = 0; + ap_uint<5> overlap = 0; + constexpr int bittest = 0xfff; // 4095, corresponding to 11bits + if (mu.stubID0() != bittest) { + valid = valid | 0x1; + if (mu.stubID0() == other.stubID0()) + overlap = overlap | 0x1; + } + if (mu.stubID1() != bittest) { + valid = valid | 0x2; + if (mu.stubID1() == other.stubID1()) + overlap = overlap | 0x2; + } + if (mu.stubID2() != bittest) { + valid = valid | 0x4; + if (mu.stubID2() == other.stubID2()) + overlap = overlap | 0x4; + } + if (mu.stubID3() != bittest) { + valid = valid | 0x8; + if (mu.stubID3() == other.stubID3()) + overlap = overlap | 0x8; + } + if (mu.stubID4() != bittest) { + valid = valid | 0x10; + if (mu.stubID4() == other.stubID4()) + overlap = overlap | 0x10; + } + + if (((mu.quality() < other.quality()) && (!eq)) || ((mu.quality() <= other.quality()) && (eq))) + return valid & (~overlap); + else + return valid; +} + +std::vector TPSAlgorithm::clean(std::vector& muons) { + std::vector out; + if (muons.empty()) + return out; + if (verbose_ == 1) { + edm::LogInfo("TPSAlgo") << "-----Cleaning Up Muons in the same Nonant"; + edm::LogInfo("TPSAlgo") << "Before:"; + } + for (uint i = 0; i < muons.size(); ++i) { + if (verbose_ == 1) + muons[i].print(); + + ap_uint<5> mask = 0x1f; + for (uint j = 0; j < muons.size(); ++j) { + if (i == j) + continue; + mask = mask & cleanMuon(muons[i], muons[j], false); + } + if (mask) { + if (verbose_ == 1) + edm::LogInfo("TPSAlgo") << "kept"; + out.push_back(muons[i]); + } else { + if (verbose_ == 1) + edm::LogInfo("TPSAlgo") << "discarded"; + } + } + return out; +} diff --git a/L1Trigger/Phase2L1GMT/src/TrackConverter.cc b/L1Trigger/Phase2L1GMT/src/TrackConverter.cc new file mode 100644 index 0000000000000..414ee8b69ced0 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/src/TrackConverter.cc @@ -0,0 +1,50 @@ +#include "L1Trigger/Phase2L1GMT/interface/TrackConverter.h" + +using namespace Phase2L1GMT; + +TrackConverter::TrackConverter(const edm::ParameterSet& iConfig) : verbose_(iConfig.getParameter("verbose")) {} + +std::vector TrackConverter::convertTracks( + const std::vector >& tracks) { + std::vector out; + out.reserve(tracks.size()); + for (const auto& t : tracks) + out.push_back(convert(t)); + return out; +} + +ConvertedTTTrack TrackConverter::convert(const edm::Ptr >& track) { + uint charge = (track->rInv() < 0) ? 1 : 0; + ap_int curvature = ap_int(track->getRinvBits()); + ap_int phisec = ap_int(ap_int(track->getPhiBits()) / 2); + ap_int tanLambda = ap_int(track->getTanlBits()); + ap_int z0 = ap_int(ap_int(track->getZ0Bits()) / (1 << (BITSTTZ0 - BITSZ0))); + ap_int d0 = ap_int(ap_int(track->getD0Bits()) / (1 << (BITSTTD0 - BITSD0))); + //calculate pt + ap_uint absCurv = + curvature > 0 ? ap_uint(curvature) : ap_uint(-curvature); + ap_uint pt = ptLUT[ptLookup(absCurv)]; + ap_uint<1> quality = generateQuality(track); + ap_uint absTanL = + tanLambda > 0 ? ap_uint(tanLambda) : ap_uint(-tanLambda); + ap_uint absEta = etaLUT[etaLookup(absTanL)]; + ap_int eta = tanLambda > 0 ? ap_int(absEta) : ap_int(-absEta); + + ap_int phi = ap_int(phisec + track->phiSector() * 910); + + wordtype word = 0; + int bstart = 0; + bstart = wordconcat(word, bstart, curvature, BITSTTCURV); + bstart = wordconcat(word, bstart, phi, BITSPHI); //was phiSec + bstart = wordconcat(word, bstart, tanLambda, BITSTTTANL); + bstart = wordconcat(word, bstart, z0, BITSZ0); + bstart = wordconcat(word, bstart, d0, BITSD0); + bstart = wordconcat(word, bstart, uint(track->chi2()), 4); + + ConvertedTTTrack convertedTrack(charge, curvature, absEta, pt, eta, phi, z0, d0, quality, word); + convertedTrack.setOfflineQuantities(LSBpt * pt, LSBeta * eta, LSBphi * phi); + if (verbose_) + convertedTrack.print(); + convertedTrack.setTrkPtr(track); + return convertedTrack; +} diff --git a/L1Trigger/Phase2L1GMT/test/gmtStudy.py b/L1Trigger/Phase2L1GMT/test/gmtStudy.py index f80fac6b05a58..629cf94d927a8 100644 --- a/L1Trigger/Phase2L1GMT/test/gmtStudy.py +++ b/L1Trigger/Phase2L1GMT/test/gmtStudy.py @@ -1,255 +1,372 @@ import ROOT,itertools,math +import argparse from array import array from DataFormats.FWLite import Events, Handle +import subprocess ROOT.FWLiteEnabler.enable() -# - -#0.005 -#idCut=[ -#20, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 48, 44, 44, 44, 60, 20, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 48, 20, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 60, 20, 24, 20, 44, 44, 44, 44, 44, 44, 44, 44, 20, 44, 44, 44, 60, 20, 24, 24, 24, 24, 44, 24, 24, 24, 20, 44, 40, 44, 44, 48, 44, 20, 44, 44, 48, 48, 48, 48, 60, 48, 48, 60, 60, 48, 60, 60, 60, 20, 44, 60, 60, 60, 60, 60, 60, 60, 48, 60, 60, 44, 60, 60, 60, 20, 40, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 16, 20, 60, 60, 60, 60, 60, 60, 60, 60, 48, 60, 44, 60, 60, 60, 16, 20, 44, 60, 60, 60, 60, 60, 48, 60, 60, 60, 60, 60, 60, 60, 20, 20, 40, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 48, 60, 20, 16, 20, 44, 48, 44, 44, 44, 60, 60, 60, 60, 48, 48, 48, 60, 20, 20, 20, 60, 44, 60, 60, 60, 60, 44, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60] - -#0.006 - -idCut=[ -36, 56, 64, 64, 32, 32, 60, 56, 56, 56, 56, 56, 56, 56, 56, 56, #0 -28, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 28, 28, 28, 28, #16 -28, 52, 56, 52, 52, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, #32 -28, 52, 52, 52, 56, 56, 56, 56, 56, 56, 56, 28, 56, 56, 56, 56, #48 -28, 36, 36, 36, 36, 36, 36, 36, 36, 36, 56, 56, 36, 56, 36, 36, #64 -28, 56, 60, 60, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, #80 -28, 92, 120, 120, 92, 92, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, #96 -28, 120, 152, 128, 100, 124, 80, 80, 64, 64, 64, 64, 64, 64, 64,64, #112 -28, 88, 92, 64, 92, 60, 60, 60, 92, 60, 60, 60, 60, 60, 60, 60, #128 -36, 88, 88, 64, 64, 60, 60, 60, 60, 60, 60, 60, 92, 92, 92,92, #144 -28, 64, 92, 88, 88, 88, 88, 88, 88, 88, 88, 88, 120, 120, 120,120, #160 -28, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,92, #176 -28, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,92, #192 -64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,64, #208 -64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,64, #224 -64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64] #240 - -idCut=[ -40, 56, 64, 88, 64, 32, 60, 56, 56, 56, 56, 56, 56, 56, 56, 56, #0 -28, 56, 56, 54, 36, 36, 36, 36, 36, 36, 36, 36, 32, 28, 28, 28, #16 -28, 52, 56, 52, 52, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, #32 -28, 56, 52, 52, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, #48 -28, 52, 36, 36, 36, 36, 36, 36, 36, 36, 56, 56, 36, 56, 36, 36, #64 -28, 60, 60, 60, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, #80 -28, 120, 120, 120, 92, 92, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, #96 -28, 120, 152, 128, 100, 124, 80, 80, 64, 100, 64, 64, 64, 64, 64,64, #112 -28, 88, 92, 64, 92, 60, 60, 60, 92, 60, 60, 60, 60, 60, 60, 60, #128 -36, 88, 88, 64, 64, 60, 60, 60, 60, 60, 60, 60, 92, 92, 92,92, #144 -28, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,88, #160 -28, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,92, #176 -28, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,92, #192 -64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,64, #208 -64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,64, #224 -64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64] #240 - - -def ID(eta,pt,quality): - p=pt - if p>4095: - p=4095 - p=p/256 - e=int(abs(eta)) - e=e/256 - addr=(e<<4) | p - if (quality-min(64,pt/32))>=(idCut[addr]): - return True - else: - return False - -#verbose=False -#tag='singleMuonOfficial' -#isData=False -#tag='signal' -def strAppend(s): - return "root://cmsxrootd.fnal.gov/"+s -from dy200 import * -from jpsi import * -from minbias import * -tag='/uscmst1b_scratch/lpc1/3DayLifetime/bachtis/DY200' -#events=Events(['/uscmst1b_scratch/lpc1/3DayLifetime/bachtis/MinBias.root' -# ]) -events=Events(map(strAppend,dy200)) +class muon_trigger_analyzer(object): + def __init__(self,prefix,thresholds=[0,3,5,10,15,20,30]): + self.bunchfactor = 40000*2760.0/3564.0 + self.prefix=prefix + self.thresholds = thresholds + self.histoData={'effpt':{}, 'effeta':{},'geneta':{},'genphi':{},'genlxy':{},'efflxy':{},'effphi':{},'effptB':{},'effptO':{},'effptE':{},'rateeta':{}} + self.histoData['genpt'] = ROOT.TH1D(prefix+"_genpt","genpt",50,0,100) + self.histoData['genptB'] = ROOT.TH1D(prefix+"_genptB","genptB",50,0,100) + self.histoData['genptO'] = ROOT.TH1D(prefix+"_genptO","genptO",50,0,100) + self.histoData['genptE'] = ROOT.TH1D(prefix+"_genptE","genptE",50,0,100) + self.histoData['rate'] = ROOT.TH1D(prefix+"_rate","rate",20,0,100) + self.histoData['resolution'] = ROOT.TH2D(prefix+"_resolution","resolution",20,0,100,100,-2,2) + self.histoData['rateBarrel'] = ROOT.TH1D(prefix+"_rateBarrel","rate",20,0,100) + self.histoData['rateOverlap'] = ROOT.TH1D(prefix+"_rateOverlap","rate",20,0,100) + self.histoData['rateEndcap'] = ROOT.TH1D(prefix+"_rateEndcap","rate",20,0,100) + for t in thresholds: + self.histoData['effpt'][t] = ROOT.TH1D(prefix+"_effpt_"+str(t),"effpt_"+str(t),50,0,100) + self.histoData['effptB'][t] = ROOT.TH1D(prefix+"_effptB_"+str(t),"effpt_"+str(t),50,0,100) + self.histoData['effptO'][t] = ROOT.TH1D(prefix+"_effptO_"+str(t),"effpt_"+str(t),50,0,100) + self.histoData['effptE'][t] = ROOT.TH1D(prefix+"_effptE_"+str(t),"effpt_"+str(t),50,0,100) + self.histoData['effeta'][t] = ROOT.TH1D(prefix+"_effeta_"+str(t),"effeta_"+str(t),48,-2.4,2.4) + self.histoData['effphi'][t] = ROOT.TH1D(prefix+"_effphi_"+str(t),"effphi_"+str(t),32,-math.pi,math.pi) + self.histoData['efflxy'][t] = ROOT.TH1D(prefix+"_efflxy_"+str(t),"efflxy_"+str(t),50,0,200) + self.histoData['geneta'][t] = ROOT.TH1D(prefix+"_geneta_"+str(t),"effeta_"+str(t),48,-2.4,2.4) + self.histoData['genphi'][t] = ROOT.TH1D(prefix+"_genphi_"+str(t),"genphi_"+str(t),32,-math.pi,math.pi) + self.histoData['genlxy'][t] = ROOT.TH1D(prefix+"_genlxy_"+str(t),"genlxy_"+str(t),50,0,200) + self.histoData['rateeta'][t] = ROOT.TH1D(prefix+"_rateeta_"+str(t),"rateeta_"+str(t),24,-2.4,2.4) + + def deltaPhi(self, p1, p2): + '''Computes delta phi, handling periodic limit conditions.''' + res = p1 - p2 + while res > math.pi: + res -= 2*math.pi + while res < -math.pi: + res += 2*math.pi + return res + + def deltaR(self, *args ): + return math.sqrt( self.deltaR2(*args) ) + + def deltaR2(self, e1, p1, e2, p2): + de = e1 - e2 + dp = self.deltaPhi(p1, p2) + return de*de + dp*dp + def getLxy(self,muon): + return abs(math.sqrt(muon.vx()*muon.vx()+muon.vy()*muon.vy())) + + def getDxy(self,muon): + tanphi = math.tan(m.phi()) + x=(tanphi*tanphi*muon.vx()-muon.vy()*tanphi)/(1+tanphi*tanphi) + y=muon.vy()+tanphi*(x-muon.vx()) + return abs(math.sqrt(x*x+y*y)) + + def getEta1(self,muon): + lxy = self.getLxy(muon) + vz = muon.vz() + theta1 = math.atan((700.-lxy)/(650.-vz)) + + if (theta1 < 0): + theta1 = math.pi+theta1 + eta1 = -math.log(math.tan(theta1/2.0)) + return eta1 + + def getEta2(self,muon): + lxy = self.getLxy(muon) + vz = muon.vz() + theta2 = math.pi-math.atan((700.-lxy)/(650.+vz)) + if theta2 > math.pi: + theta2 = theta2-math.pi + eta2 = -math.log(math.tan(theta2/2.0)) + return eta2 + + def getAcceptance(self,muon): + eta1 = self.getEta1(muon) + eta2 = self.getEta2(muon) + if muon.eta() < eta1 and muon.eta() > eta2: + return True #Muon is within barrel acceptance + else: + return False #Muon is outside of barrel + + def getSt2Eta(self,muon): + lxy = self.getLxy(muon) + vz = muon.vz() + theta_mu = 2*math.atan(math.exp(-muon.eta())) + st1_z = (512.-lxy)/math.tan(theta_mu)+vz + st1_r = 512. + theta_st1 = math.atan2(st1_r,st1_z) + eta_st1 = -math.log(math.tan(theta_st1/2.)) + return eta_st1 + + def getSt2Phi(self,muon): + # calculate intersection of line and circle + x1 = muon.vx() + y1 = muon.vy() + x2 = muon.vx() + muon.px()/(muon.px()**2+muon.py()**2) + y2 = muon.vy() + muon.py()/(muon.px()**2+muon.py()**2) + r = 512. + dx = x2-x1 + dy = y2-y1 + dr = math.sqrt(dx**2+dy**2) + D = x1*y2-x2*y1 + delta = (r**2)*(dr**2)-D**2 + if delta < 0: + return math.atan2(y1, x1) + # Two possible intersections = two possible phi values + xP = (D*dy+math.copysign(1,dy)*dx*math.sqrt(delta))/dr**2 + xM = (D*dy-math.copysign(1,dy)*dx*math.sqrt(delta))/dr**2 + yP = (-D*dx+abs(dy)*math.sqrt(delta))/dr**2 + yM = (-D*dx-abs(dy)*math.sqrt(delta))/dr**2 + + p1 = (xP, yP) + p2 = (xM, yM) + phi1 = math.atan2(yP,xP) + phi2 = math.atan2(yM,xM) + + phi = min([phi1, phi2], key = lambda x: abs(self.deltaPhi(x, muon.phi()))) #probably a better way to select which intersection + return phi + + + def process(self,gen,l1,dr=0.3,verbose=0): + #first efficiency + for g in gen: + if verbose: + print("Gen Muon pt={pt} eta={eta} phi={phi} vxy={dxy}".format(pt=g.pt(),eta=g.eta(),phi=g.phi(),dxy=math.sqrt(g.vx()*g.vx()+g.vy()*g.vy()))) + self.histoData['genpt'].Fill(g.pt()) + if abs(g.eta())<0.83: + self.histoData['genptB'].Fill(g.pt()) + elif abs(g.eta())>0.83 and abs(g.eta())<1.2: + self.histoData['genptO'].Fill(g.pt()) + else: + self.histoData['genptE'].Fill(g.pt()) + #Now let's process every threshold + for t in self.thresholds: + if g.pt()>(t+10): + self.histoData['geneta'][t].Fill(g.eta()) + self.histoData['genphi'][t].Fill(g.phi()) + if self.getAcceptance(g): + self.histoData['genlxy'][t].Fill(self.getLxy(g)) + + matched=[] + matchedDisplaced=[] + for mu in l1: + if mu.pt()20 and self.prefix=='tk' and t==15: +# import pdb;pdb.set_trace() + if len(matched)>0: + self.histoData['effpt'][t].Fill(g.pt()) + if abs(g.eta())<0.83: + self.histoData['effptB'][t].Fill(g.pt()) + elif abs(g.eta())>0.83 and abs(g.eta())<1.2: + self.histoData['effptO'][t].Fill(g.pt()) + else: + self.histoData['effptE'][t].Fill(g.pt()) + if g.pt()>(t+10): + self.histoData['effeta'][t].Fill(g.eta()) + self.histoData['effphi'][t].Fill(g.phi()) + deltaPt=10000 + best=None + for match in matched: + delta=abs(match.pt()-g.pt()) + if delta0: + if g.pt()>(t+10) and self.getAcceptance(g): + self.histoData['efflxy'][t].Fill(self.getLxy(g)) + + + #now rate + maxElement=None + maxPt=0 + for l in l1: + if verbose: + print("{prefix} Muon pt={pt} eta={eta} phi={phi} stubs={stubs}".format(prefix=self.prefix,pt=l.pt(),eta=l.eta(),phi=l.phi(),stubs=len(l.stubs()))) + for s in l.stubs(): + print("-----> Associated Stub etaR={eta} phiR={phi} depthR={depth} coord1={coord1} coord2={coord2} q={q} ".format(eta=s.etaRegion(),phi=s.phiRegion(),depth=s.depthRegion(),coord1=s.offline_coord1(),coord2=s.offline_coord2(),q=s.quality())) + if l.pt()>maxPt: + maxPt=l.pt() + maxElement=l + if maxElement!=None: + self.histoData['rate'].Fill(maxPt) + if abs(maxElement.eta())<0.83: + self.histoData['rateBarrel'].Fill(maxPt) + elif abs(maxElement.eta())>0.83 and abs(maxElement.eta())<1.2: + self.histoData['rateOverlap'].Fill(maxPt) + else: + self.histoData['rateEndcap'].Fill(maxPt) + for t in self.thresholds: + if maxPt>t: + self.histoData['rateeta'][t].Fill(maxElement.eta()) + + def write(self,f): + f.cd() + self.histoData['genpt'].Write() + self.histoData['genptB'].Write() + self.histoData['genptO'].Write() + self.histoData['genptE'].Write() + self.histoData['resolution'].Write() + c =self.histoData['rate'].GetCumulative(False) + c.Scale(float(self.bunchfactor)/float(counter)) + c.Write(self.prefix+"_rate") + c =self.histoData['rateBarrel'].GetCumulative(False) + c.Scale(float(self.bunchfactor)/float(counter)) + c.Write(self.prefix+"_rateBarrel") + c =self.histoData['rateOverlap'].GetCumulative(False) + c.Scale(float(self.bunchfactor)/float(counter)) + c.Write(self.prefix+"_rateOverlap") + c =self.histoData['rateEndcap'].GetCumulative(False) + c.Scale(float(self.bunchfactor)/float(counter)) + c.Write(self.prefix+"_rateEndcap") + for t in self.thresholds: + c =self.histoData['rateeta'][t] + c.Scale(float(self.bunchfactor)/float(counter)) + c.Write(self.prefix+"_rateeta_"+str(t)) + g = ROOT.TGraphAsymmErrors(self.histoData['effpt'][t],self.histoData['genpt']) + g.Write(self.prefix+"_eff_"+str(t)) + g = ROOT.TGraphAsymmErrors(self.histoData['effptB'][t],self.histoData['genptB']) + g.Write(self.prefix+"_effB_"+str(t)) + g = ROOT.TGraphAsymmErrors(self.histoData['effptO'][t],self.histoData['genptO']) + g.Write(self.prefix+"_effO_"+str(t)) + g = ROOT.TGraphAsymmErrors(self.histoData['effptE'][t],self.histoData['genptE']) + g.Write(self.prefix+"_effE_"+str(t)) + g = ROOT.TGraphAsymmErrors(self.histoData['effeta'][t],self.histoData['geneta'][t]) + g.Write(self.prefix+"_effeta_"+str(t)) + g = ROOT.TGraphAsymmErrors(self.histoData['effphi'][t],self.histoData['genphi'][t]) + g.Write(self.prefix+"_effphi_"+str(t)) + g = ROOT.TGraphAsymmErrors(self.histoData['efflxy'][t],self.histoData['genlxy'][t]) + g.Write(self.prefix+"_efflxy_"+str(t)) + + -#events=Events(minbias) -#events=Events(['reprocess.root']) -def fetchTracks(event): - trackHandle = Handle('vector,Phase2TrackerDigi,edm::refhelper::FindForDetSetVector > > >') - event.getByLabel("l1tTTTracksFromTrackletEmulation:Level1TTTracks",trackHandle) - return trackHandle.product() - +#HELPERS +def strAppend(s): + return "root://cmsxrootd.fnal.gov/"+s +def fetchSTA(event,tag,etamax=3.0): + phiSeg2 = Handle ('vector') + event.getByLabel(tag,phiSeg2) + return list(filter(lambda x: abs(x.eta())') event.getByLabel(tag,phiSeg2) - return filter(lambda x: abs(x.eta())') event.getByLabel(tag,phiSeg2) return phiSeg2.product() - def fetchGEN(event,etaMax=3.0): genH = Handle ('vector') event.getByLabel('genParticles',genH) - genMuons=filter(lambda x: abs(x.pdgId())==13 and x.status()==1 and abs(x.eta()) math.pi: - res -= 2*math.pi - while res < -math.pi: - res += 2*math.pi - return res - -def deltaR( *args ): - return math.sqrt( deltaR2(*args) ) - -def deltaR2( e1, p1, e2, p2): - de = e1 - e2 - dp = deltaPhi(p1, p2) - return de*de + dp*dp - - - - -quality = ROOT.TH3D("quality","",16,0,4096,16,0,4096,128,0,512) -qualityAll = ROOT.TH3D("qualityAll","",16,0,4096,16,0,4096,128,0,512) -histoData={'effpt':{}, 'effeta':{},'geneta':{},'genphi':{},'effphi':{}} -histoData['genpt'] = ROOT.TH1D("genpt","genpt",50,0,50) - -thresholds=[1,3,5,15,20] -for t in thresholds: - histoData['effpt'][t] = ROOT.TH1D("effpt_"+str(t),"effpt_"+str(t),50,0,50) - histoData['effeta'][t] = ROOT.TH1D("effeta_"+str(t),"effeta_"+str(t),48,-2.4,2.4) - histoData['effphi'][t] = ROOT.TH1D("effphi_"+str(t),"effphi_"+str(t),32,-math.pi,math.pi) - histoData['geneta'][t] = ROOT.TH1D("geneta_"+str(t),"effeta_"+str(t),48,-2.4,2.4) - histoData['genphi'][t] = ROOT.TH1D("genphi_"+str(t),"genphi_"+str(t),32,-math.pi,math.pi) - - - - -histoData['rate']= ROOT.TH1D("rate","rate",50,0,100) -histoData['rate20eta']= ROOT.TH1D("rate20eta","rate",8,0,8) - - -BUNCHFACTOR=40000*2760.0/3564.0 - -QUALITYCUT=0 +def EOSls(path): + print('eos root://cmseos.fnal.gov/ find -name "*root" %s' % path ) + p = subprocess.Popen('eos root://cmseos.fnal.gov/ find -name "*root" %s' % path, + stdout = subprocess.PIPE, stderr = subprocess.PIPE, + shell=True) + stdout, stderr = p.communicate() + out = ["root://cmseos.fnal.gov/"+i.decode('UTF-8') for i in stdout.split()] + return out +#DATASET +# from samples200 import * +# toProcess = dy200 +# files=[] +# for p in toProcess: + # files.append(strAppend(p)) +# events=Events(files) +# tag='DY_v1' +# tag='disp200' + +parser = argparse.ArgumentParser(description='Process some integers.') +parser.add_argument('--tag', default="Tau", help="fdf") +parser.add_argument('--prod', default="gmtMuons", help="fdf") +args = parser.parse_args() +tag = args.tag +samples = { + "MB_org" : "/eos/uscms//store/group/lpctrig/benwu/GMT_Ntupler/Spring22_GMToriginal_v2/MinBias_TuneCP5_14TeV-pythia8/PHASEII_MinBias/", + "DY_org" : "/eos/uscms//store/group/lpctrig/benwu/GMT_Ntupler/Spring22_GMToriginal_v2/DYToLL_M-50_TuneCP5_14TeV-pythia8/PHASEII_DYToLL/", + "MB_v1" : "/eos/uscms//store/group/lpctrig/benwu/GMT_Ntupler/Spring22_GMT_v3/MinBias_TuneCP5_14TeV-pythia8/PHASEII_MinBias/", + "DY_v1" : "/eos/uscms//store/group/lpctrig/benwu/GMT_Ntupler/Spring22_GMT_v3/DYToLL_M-50_TuneCP5_14TeV-pythia8/PHASEII_DYToLL/", +} +flist = EOSls(samples[tag]) +events= Events(flist) +# events=Events(['file:/uscmst1b_scratch/lpc1/3DayLifetime/bachtis/gmt.root']) +#events=Events(['file:gmt.root']) +# events=Events(['file:reprocess.root']) + + +#ANALYSIS SETUP verbose=0 -counter=-1 +saAnalyzer = muon_trigger_analyzer('sta_prompt') +kmtfAnalyzer_p = muon_trigger_analyzer('kmtf_prompt') +kmtfAnalyzer_d = muon_trigger_analyzer('kmtf_disp') +tkAnalyzer_1st = muon_trigger_analyzer('tk_1st') +tkAnalyzer_2st = muon_trigger_analyzer('tk_2st') +tkAnalyzer_2m = muon_trigger_analyzer('tk_2m') +tkAnalyzer_3m = muon_trigger_analyzer('tk_3m') +tkAnalyzer_4m = muon_trigger_analyzer('tk_4m') + +#EVENT LOOP + +counter=0; for event in events: - counter=counter+1 - if counter==100000: - break; - gen=fetchGEN(event,2.4) - stubs = fetchStubs(event,'l1tGMTStubs') - tps = filter(lambda x: ID(x.hwEta(),x.hwPt(),x.hwQual()),fetchTPS(event,'l1tGMTMuons')) -# tps = fetchTPS(event,'gmtMuons') - tracks=fetchTracks(event) - - if verbose: - for t in sorted(tracks,key=lambda x: x.momentum().transverse(),reverse=True): - print("Track ",t.eta(),t.phi(),t.momentum().transverse(),t.getStubRefs().size()) - for t in sorted(tps,key=lambda x: x.pt(),reverse=True): - print("Tracker Muon pt={pt} eta={eta} phi={phi} qual={qual}".format(pt=t.pt(),eta=t.eta(),phi=t.phi(),qual=t.hwQual)) - - # import pdb;pdb.set_trace() - for s in stubs: - print(" All Stub depth={depth} eta={eta1},{eta1I},{eta2},{eta2I} phi={phi1},{phi1I},{phi2},{phi2I} qualities={etaQ},{phiQ}".format(depth=s.depthRegion(),eta1=s.offline_eta1(),eta1I=s.eta1(),eta2=s.offline_eta2(),eta2I=s.eta2(),phi1=s.offline_coord1(),phi1I=s.coord1(),phi2=s.offline_coord2(),phi2I=s.coord2(),etaQ=s.etaQuality(),phiQ=s.quality())) - - - if len(tps)>0: - tpsInEta =filter(lambda x: abs(x.eta())<2.4,tps) - if len(tpsInEta)>0: - best=max(tpsInEta,key=lambda x: x.pt()) - qualityAll.Fill(abs(best.hwEta()),best.hwPt(),best.hwQual()-min(63,best.hwPt()/32)) - pt=best.pt() - if pt>99.9: - pt=99.9 - histoData['rate'].Fill(pt) - if pt>20: - histoData['rate20eta'].Fill(abs(best.hwEta())/512) -# import pdb;pdb.set_trace() - - - if counter %1000==0: - print(counter) - if verbose: - print ("EVENT:",counter) - - #efficiencies -loop on gen - for g in gen: - histoData['genpt'].Fill(g.pt()) - for thres in thresholds: - if g.pt()>(thres+2.0): - histoData['geneta'][thres].Fill(g.eta()) - histoData['genphi'][thres].Fill(g.phi()) - - if verbose: - print("Gen Muon pt={pt} eta={eta} phi={phi} charge={charge}".format(pt=g.pt(),eta=g.eta(),phi=g.phi(),charge=g.charge())) - - foundMatch=False - tpsMatched = sorted(filter(lambda x: deltaR(g.eta(),g.phi(),x.eta(),x.phi())<0.3, tps),key=lambda x:x.pt(),reverse=True) -# if len(tpsMatched)==0 and g.pt()>10: -# print("Not Matched ",g.pt(),g.eta(),len(tps)) -# import pdb;pdb.set_trace() - if len(tpsMatched)>0: - foundMatch=True - - if verbose: - for t in tpsMatched: - print(" -> matched track ->Tracker Muon pt={pt} eta={eta} phi={phi} qual={qual}".format(pt=t.pt(),eta=t.eta(),phi=t.phi(),qual=t.hwQual())) - best=tpsMatched[0] - quality.Fill(abs(best.hwEta()),best.hwPt(),best.hwQual()-min(63,best.hwPt()/32)) - for thres in thresholds: - overThreshold = filter(lambda x: x.pt()>thres,tpsMatched) - if len(overThreshold)>0: - histoData['effpt'][thres].Fill(g.pt()) - if g.pt()>(thres+2.0): - histoData['effeta'][thres].Fill(g.eta()) - histoData['effphi'][thres].Fill(g.phi()) - - - - - - - - stubsMatched = filter(lambda x: deltaR(g.eta(),g.phi(),x.offline_eta1(),x.offline_coord1())<0.3, stubs) - if verbose: - for s in stubsMatched: - print(" -> matched stub -> Muon Stub eta={eta1},{eta2} phi={phi1},{phi2} qualities={etaQ},{phiQ}".format(eta1=s.offline_eta1(),eta2=s.offline_eta2(),phi1=s.offline_coord1(),phi2=s.offline_coord2(),etaQ=s.etaQuality(),phiQ=s.quality())) - - - -f=ROOT.TFile("tpsResults_output.root","RECREATE") + if verbose: + print('EVENT {}'.format(counter)) + gen=fetchGEN(event,2.4) + genKMTF=fetchGEN(event,0.83) + sa=fetchSTA(event,'gmtSAMuons:prompt',2.5) + kmtf_p=fetchSTA(event,'gmtKMTFMuons:prompt',2.5) + kmtf_d=fetchSTA(event,'gmtKMTFMuons:displaced',2.5) + tps=fetchTPS(event,'gmtTkMuons',2.5) + # sa=fetchSTA(event,'l1tSAMuonsGmt:prompt',2.5) + # kmtf_p=fetchSTA(event,'l1tKMTFMuonsGmt:prompt',2.5) + # kmtf_d=fetchSTA(event,'l1tKMTFMuonsGmt:displaced',2.5) + # tps=fetchTPS(event,'l1tTkMuonsGmt',2.5) + tps_2st=list(filter(lambda x: x.stubs().size()>1,tps)) + tps_2m=list(filter(lambda x: x.numberOfMatches()>1,tps)) + tps_3m=list(filter(lambda x: x.numberOfMatches()>2,tps)) + tps_4m=list(filter(lambda x: x.numberOfMatches()>3,tps)) + #analyze + saAnalyzer.process(gen,sa,0.6,verbose) + kmtfAnalyzer_p.process(genKMTF,kmtf_p,0.6,verbose) + kmtfAnalyzer_d.process(genKMTF,kmtf_d,0.6,verbose) + tkAnalyzer_1st.process(gen,tps,0.2,verbose) + tkAnalyzer_2st.process(gen,tps_2st,0.2,0) + tkAnalyzer_2m.process(gen,tps_2m,0.2,0) + tkAnalyzer_3m.process(gen,tps_3m,0.2,0) + tkAnalyzer_4m.process(gen,tps_4m,0.2,0) + + + +# if verbose==1 and counter==69: +# import pdb;pdb.set_trace() + #counter +# if counter==100000: +# break + + if (counter %10000 ==0): + print(counter) + counter=counter+1 + +f=ROOT.TFile("gmtAnalysis_{tag}.root".format(tag=tag),"RECREATE") f.cd() -quality.Write() -qualityAll.Write() - -c = histoData['rate'].GetCumulative(False) -c.Scale(float(BUNCHFACTOR)/float(counter)) -c.Write("rate") - -for t in thresholds: - g = ROOT.TGraphAsymmErrors(histoData['effpt'][t],histoData['genpt']) - g.Write("eff_"+str(t)) - g = ROOT.TGraphAsymmErrors(histoData['effeta'][t],histoData['geneta'][t]) - g.Write("effeta_"+str(t)) - g = ROOT.TGraphAsymmErrors(histoData['effphi'][t],histoData['genphi'][t]) - g.Write("effphi_"+str(t)) - +saAnalyzer.write(f) +kmtfAnalyzer_p.write(f) +kmtfAnalyzer_d.write(f) +tkAnalyzer_1st.write(f) +tkAnalyzer_2st.write(f) +tkAnalyzer_2m.write(f) +tkAnalyzer_3m.write(f) +tkAnalyzer_4m.write(f) f.Close() - diff --git a/L1Trigger/Phase2L1GMT/test/makeKMTFCoarsseEtaLUT.py b/L1Trigger/Phase2L1GMT/test/makeKMTFCoarsseEtaLUT.py new file mode 100644 index 0000000000000..c2f8b21e5bf32 --- /dev/null +++ b/L1Trigger/Phase2L1GMT/test/makeKMTFCoarsseEtaLUT.py @@ -0,0 +1,13 @@ +import ROOT +from math import pi +f=ROOT.TFile("../data/packedGainLUTs.root") +lut=f.Get("coarseETALUT") +l=[] +for i in range(0,256): + b = lut.GetXaxis().FindBin(i) + c=lut.GetBinContent(b) + l.append(str(int((1<<12)*c/pi))) + +print("const ap_uint coarseEtaLUT[256] ={"+','.join(l)+'};') + +f.Close() diff --git a/L1Trigger/Phase2L1GMT/test/makeKMTFPTLUT.py b/L1Trigger/Phase2L1GMT/test/makeKMTFPTLUT.py new file mode 100644 index 0000000000000..50301705ea5ac --- /dev/null +++ b/L1Trigger/Phase2L1GMT/test/makeKMTFPTLUT.py @@ -0,0 +1,17 @@ +lut=[] +for k in range(0,8192): + if k<103: + fk=103 + else: + fk=k + lsb = 1.25 /float(1 << 15); + fk=fk*lsb + if fk==0: + lut.append(str(8191)) + else: + ptF = 1.0/fk + pt =int(ptF/0.03125) + lut.append(str(pt)) + +print("const ap_uint ptLUT[8192] = {"+','.join(lut)+'};') + diff --git a/L1Trigger/Phase2L1GMT/test/runGMT.py b/L1Trigger/Phase2L1GMT/test/runGMT.py index 4268397646d3c..4817dfaefd9f0 100644 --- a/L1Trigger/Phase2L1GMT/test/runGMT.py +++ b/L1Trigger/Phase2L1GMT/test/runGMT.py @@ -5,9 +5,9 @@ # with command line options: step1 --conditions 111X_mcRun4_realistic_T15_v3 -n 2 --era Phase2C9 --eventcontent FEVTDEBUGHLT --runUnscheduled file:/eos/cms/store/relval/CMSSW_11_0_0/RelValTTbar_14TeV/GEN-SIM-DIGI-RAW/PU25ns_110X_mcRun4_realistic_v3_2026D49PU200-v2/10000/01054EE2-1B51-C449-91A2-5202A60D16A3.root -s RAW2DIGI,L1TrackTrigger,L1 --datatier FEVTDEBUGHLT --customise SLHCUpgradeSimulations/Configuration/aging.customise_aging_1000,L1Trigger/Configuration/customisePhase2TTNoMC.customisePhase2TTNoMC,Configuration/DataProcessing/Utils.addMonitoring --geometry Extended2026D49 --fileout file:/tmp/step1_Reprocess_TrackTrigger_L1.root --no_exec --nThreads 8 --python step1_L1_ProdLike.py --filein das:/TT_TuneCP5_14TeV-powheg-pythia8/Phase2HLTTDRWinter20DIGI-PU200_110X_mcRun4_realistic_v3-v2/GEN-SIM-DIGI-RAW import FWCore.ParameterSet.Config as cms -from Configuration.Eras.Era_Phase2C9_cff import Phase2C9 +from Configuration.Eras.Era_Phase2C17I13M9_cff import Phase2C17I13M9 -process = cms.Process('L1',Phase2C9) +process = cms.Process('L1',Phase2C17I13M9) # import of standard configurations process.load('Configuration.StandardSequences.Services_cff') @@ -15,32 +15,24 @@ process.load('FWCore.MessageService.MessageLogger_cfi') process.load('Configuration.EventContent.EventContent_cff') process.load('SimGeneral.MixingModule.mixNoPU_cfi') -process.load('Configuration.Geometry.GeometryExtended2026D49Reco_cff') +process.load('Configuration.Geometry.GeometryExtended2026D88Reco_cff') process.load('Configuration.StandardSequences.MagneticField_cff') -process.load('Configuration.StandardSequences.RawToDigi_Data_cff') +process.load('Configuration.StandardSequences.RawToDigi_cff') process.load('Configuration.StandardSequences.L1TrackTrigger_cff') process.load('Configuration.StandardSequences.SimL1Emulator_cff') process.load('Configuration.StandardSequences.EndOfProcess_cff') process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff') process.maxEvents = cms.untracked.PSet( - input = cms.untracked.int32(18), + input = cms.untracked.int32(-1), output = cms.optional.untracked.allowed(cms.int32,cms.PSet), ) # Input source process.source = cms.Source("PoolSource", fileNames = cms.untracked.vstring( ( -#'/store/mc/Phase2HLTTDRWinter20DIGI/JPsiToMuMu_Pt0to100-pythia8_TuneCP5-gun/GEN-SIM-DIGI-RAW/PU200_110X_mcRun4_realistic_v3-v2/20000/087AA768-91E6-124F-B226-DC00C45D967D.root', -'/store/mc/Phase2HLTTDRWinter20DIGI/DYToLL_M-50_TuneCP5_14TeV-pythia8/GEN-SIM-DIGI-RAW/PU200_pilot_110X_mcRun4_realistic_v3-v2/10000/0036F7A2-BADA-1E4E-8FE7-ABE1A9AEC350.root', -'/store/mc/Phase2HLTTDRWinter20DIGI/DYToLL_M-50_TuneCP5_14TeV-pythia8/GEN-SIM-DIGI-RAW/PU200_pilot_110X_mcRun4_realistic_v3-v2/10000/007C3CAA-5209-3B47-8755-4C6D0A3A5CD2.root', -'/store/mc/Phase2HLTTDRWinter20DIGI/DYToLL_M-50_TuneCP5_14TeV-pythia8/GEN-SIM-DIGI-RAW/PU200_pilot_110X_mcRun4_realistic_v3-v2/10000/00AECAEC-8DFE-8D49-AF78-A55FCEBB46B7.root', -'/store/mc/Phase2HLTTDRWinter20DIGI/DYToLL_M-50_TuneCP5_14TeV-pythia8/GEN-SIM-DIGI-RAW/PU200_pilot_110X_mcRun4_realistic_v3-v2/10000/00B04974-FAC3-5A4E-B5AE-9483D8FAD5B1.root', -'/store/mc/Phase2HLTTDRWinter20DIGI/DYToLL_M-50_TuneCP5_14TeV-pythia8/GEN-SIM-DIGI-RAW/PU200_pilot_110X_mcRun4_realistic_v3-v2/10000/00D64490-55F9-7E4E-B3CE-BE668F1A5938.root', -'/store/mc/Phase2HLTTDRWinter20DIGI/DYToLL_M-50_TuneCP5_14TeV-pythia8/GEN-SIM-DIGI-RAW/PU200_pilot_110X_mcRun4_realistic_v3-v2/10000/01708416-15F1-5B47-A8A0-B32D355622DB.root' ) ), secondaryFileNames = cms.untracked.vstring() -# skipEvents=cms.untracked.uint32(36) ) process.options = cms.untracked.PSet( @@ -49,6 +41,8 @@ TryToContinue = cms.untracked.vstring(), allowUnscheduled = cms.obsolete.untracked.bool, canDeleteEarly = cms.untracked.vstring(), + deleteNonConsumedUnscheduledModules = cms.untracked.bool(True), + dumpOptions = cms.untracked.bool(False), emptyRunLumiMode = cms.obsolete.untracked.string, eventSetup = cms.untracked.PSet( forceNumberOfConcurrentIOVs = cms.untracked.PSet( @@ -86,8 +80,8 @@ fileName = cms.untracked.string('reprocess.root'), outputCommands = cms.untracked.vstring( "drop *_*_*_*", - "keep *_l1tGMTMuons_*_*", - "keep *_l1tGMTStubs_*_*", + "keep *_gmt*Muons_*_*", + "keep *_gmtStubs_*_*", "keep *_genParticles_*_*", "keep *_l1tTTTracksFromTrackletEmulation_Level1TTTracks_*", "keep *_l1tTkMuons_*_*" @@ -99,7 +93,7 @@ # Other statements from Configuration.AlCa.GlobalTag import GlobalTag -process.GlobalTag = GlobalTag(process.GlobalTag, '111X_mcRun4_realistic_T15_v3', '') +process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:phase2_realistic', '') ## #Calibrate Digis @@ -153,13 +147,10 @@ process = addMonitoring(process) # End of customisation functions -#do not add changes to your config after this point (unless you know what you are doing) -from FWCore.ParameterSet.Utilities import convertToUnscheduled -process=convertToUnscheduled(process) - # Customisation from command line +process.source.inputCommands = cms.untracked.vstring("keep *", "drop l1tPFJets_*_*_*") # Add early deletion of temporary data products to reduce peak memory need from Configuration.StandardSequences.earlyDeleteSettings_cff import customiseEarlyDelete process = customiseEarlyDelete(process) diff --git a/L1Trigger/Phase2L1GMT/test/runMuonTrigger.py b/L1Trigger/Phase2L1GMT/test/runMuonTrigger.py new file mode 100644 index 0000000000000..10f844b9fc97f --- /dev/null +++ b/L1Trigger/Phase2L1GMT/test/runMuonTrigger.py @@ -0,0 +1,183 @@ +# Auto generated configuration file +# using: +# Revision: 1.19 +# Source: /local/reps/CMSSW/CMSSW/Configuration/Applications/python/ConfigBuilder.py,v +# with command line options: step1 --conditions 125X_mcRun4_realistic_v2 -n 2 --era Phase2C17I13M9 --eventcontent FEVTDEBUGHLT -s RAW2DIGI,L1TrackTrigger,L1 --datatier GEN-SIM-DIGI-RAW-MINIAOD --fileout file:test.root --customise SLHCUpgradeSimulations/Configuration/aging.customise_aging_1000,Configuration/DataProcessing/Utils.addMonitoring,L1Trigger/Configuration/customisePhase2.addHcalTriggerPrimitives,L1Trigger/Configuration/customisePhase2FEVTDEBUGHLT.customisePhase2FEVTDEBUGHLT,L1Trigger/Configuration/customisePhase2TTNoMC.customisePhase2TTNoMC --geometry Extended2026D88 --nThreads 8 --filein /store/mc/Phase2Fall22DRMiniAOD/TT_TuneCP5_14TeV-powheg-pythia8/GEN-SIM-DIGI-RAW-MINIAOD/PU200_125X_mcRun4_realistic_v2_ext1-v1/30000/000c5e5f-78f7-44ee-95fe-7b2f2c2e2312.root --mc --customise_commands=process.source.inputCommands = cms.untracked.vstring("keep *", "drop l1tPFJets_*_*_*") +import FWCore.ParameterSet.Config as cms + +from Configuration.Eras.Era_Phase2C17I13M9_cff import Phase2C17I13M9 + +process = cms.Process('PHASE2MUONL1T',Phase2C17I13M9) + +# import of standard configurations +process.load('Configuration.StandardSequences.Services_cff') +process.load('SimGeneral.HepPDTESSource.pythiapdt_cfi') +process.load('FWCore.MessageService.MessageLogger_cfi') +process.load('Configuration.EventContent.EventContent_cff') +process.load('SimGeneral.MixingModule.mixNoPU_cfi') +process.load('Configuration.Geometry.GeometryExtended2026D88Reco_cff') +process.load('Configuration.StandardSequences.MagneticField_cff') +process.load('Configuration.StandardSequences.RawToDigi_cff') +process.load('Configuration.StandardSequences.L1TrackTrigger_cff') +process.load('Configuration.StandardSequences.SimL1Emulator_cff') +process.load('Configuration.StandardSequences.EndOfProcess_cff') +process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff') + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(-1), + output = cms.optional.untracked.allowed(cms.int32,cms.PSet) +) + +# Input source +process.source = cms.Source("PoolSource", + fileNames = cms.untracked.vstring( + "file:/uscms_data/d2/lpctrig/benwu/GMTEmulator/TT2L2Nu_PU200_Spring23.root", +# '/store/user/bachtis/L1T/DYToLL_M-50_TuneCP5_14TeV-pythia8/PHASEII_DY200a/230803_231922/0000/skim_10.root' +#'/store/mc/Phase2Fall22DRMiniAOD/MinBias_TuneCP5_14TeV-pythia8/GEN-SIM-DIGI-RAW-MINIAOD/PU200_125X_mcRun4_realistic_v2-v1/30000/001ec7cf-71d4-4eb4-9002-078d21560b2f.root' + ), + secondaryFileNames = cms.untracked.vstring() +) + +process.options = cms.untracked.PSet( + # FailPath = cms.untracked.vstring(), + IgnoreCompletely = cms.untracked.vstring(), + Rethrow = cms.untracked.vstring(), + # SkipEvent = cms.untracked.vstring(), + accelerators = cms.untracked.vstring('*'), + allowUnscheduled = cms.obsolete.untracked.bool, + canDeleteEarly = cms.untracked.vstring(), + deleteNonConsumedUnscheduledModules = cms.untracked.bool(True), + dumpOptions = cms.untracked.bool(False), + emptyRunLumiMode = cms.obsolete.untracked.string, + eventSetup = cms.untracked.PSet( + forceNumberOfConcurrentIOVs = cms.untracked.PSet( + allowAnyLabel_=cms.required.untracked.uint32 + ), + numberOfConcurrentIOVs = cms.untracked.uint32(0) + ), + fileMode = cms.untracked.string('FULLMERGE'), + forceEventSetupCacheClearOnNewRun = cms.untracked.bool(False), + makeTriggerResults = cms.obsolete.untracked.bool, + numberOfConcurrentLuminosityBlocks = cms.untracked.uint32(0), + numberOfConcurrentRuns = cms.untracked.uint32(1), + numberOfStreams = cms.untracked.uint32(0), + numberOfThreads = cms.untracked.uint32(1), + printDependencies = cms.untracked.bool(False), + sizeOfStackForThreadsInKB = cms.optional.untracked.uint32, + throwIfIllegalParameter = cms.untracked.bool(True), + wantSummary = cms.untracked.bool(False) +) + +# Production Info +process.configurationMetadata = cms.untracked.PSet( + annotation = cms.untracked.string('step1 nevts:2'), + name = cms.untracked.string('Applications'), + version = cms.untracked.string('$Revision: 1.19 $') +) + +# Output definition +process.FEVTDEBUGHLTEventContent.outputCommands = [ + 'drop *_*_*_*', + 'keep *_g4SimHits_Muon*_*', + 'keep *_CalibratedDigis_*_MUONL1T', + 'keep *_dtTriggerPhase2PrimitiveDigis_*_MUONL1T', + 'keep *_l1tStubsGmt_*_MUONL1T', + 'keep *_l1tSAMuonsGmt_*_MUONL1T', + 'keep *_l1tKMTFMuonsGmt_*_MUONL1T', + 'keep *_l1tFwdMuonsGmt_*_MUONL1T', + 'keep *_l1tTkMuonsGmt_*_MUONL1T', + 'keep *_genParticles_*_*', + 'keep *_simCscTriggerPrimitiveDigis_*_*', + 'keep *_simDtTriggerPrimitiveDigis_*_*', + 'keep *_simMuonRPCDigis_*_*', + 'keep *_simMuonDTDigis_*_*', + 'keep *_simBmtfDigis_*_*', + 'keep *_simEmtfDigis_*_*', + 'keep *_simGmtStage2Digis_*_*', + "keep *_gmt*Muons_*_*", + "keep *_gmtStubs_*_*", + "keep *_genParticles_*_*", + "keep *_l1tTTTracksFromTrackletEmulation_Level1TTTracks_*", + "keep *_l1tTkMuons_*_*", + 'keep *_simOmtfDigis_*_*', + 'keep *_l1tTTTracksFromTrackletEmulation_Level1TTTracks_*' +] + +#process.FEVTDEBUGHLTEventContent.outputCommands.append('drop l1tTrackerMuons_l1tTkMuonsGmt__HLT') + + + +process.FEVTDEBUGHLToutput = cms.OutputModule("PoolOutputModule", + dataset = cms.untracked.PSet( + dataTier = cms.untracked.string('GEN-SIM-DIGI-RAW-MINIAOD'), + filterName = cms.untracked.string('') + ), + fileName = cms.untracked.string('file:skim.root'), + outputCommands = process.FEVTDEBUGHLTEventContent.outputCommands, + splitLevel = cms.untracked.int32(0) +) + +# Additional output definition + +# Other statements +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(process.GlobalTag, '125X_mcRun4_realistic_v2', '') + + +process.load("L1Trigger.Phase2L1GMT.gmt_cff") +process.L1simulation_step = cms.Path(process.CalibratedDigis*process.dtTriggerPhase2PrimitiveDigis*process.phase2GMT) + +process.endjob_step = cms.EndPath(process.endOfProcess) +process.FEVTDEBUGHLToutput_step = cms.EndPath(process.FEVTDEBUGHLToutput) + +# Schedule definition +process.schedule = cms.Schedule(process.L1simulation_step,process.endjob_step,process.FEVTDEBUGHLToutput_step) +from PhysicsTools.PatAlgos.tools.helpers import associatePatAlgosToolsTask +associatePatAlgosToolsTask(process) + +#Setup FWK for multithreaded +#process.options.numberOfThreads = 8 +#process.options.numberOfStreams = 0 + +# customisation of the process. + +# Automatic addition of the customisation function from SLHCUpgradeSimulations.Configuration.aging +from SLHCUpgradeSimulations.Configuration.aging import customise_aging_1000 + +#call to customisation function customise_aging_1000 imported from SLHCUpgradeSimulations.Configuration.aging +process = customise_aging_1000(process) + +# Automatic addition of the customisation function from Configuration.DataProcessing.Utils +from Configuration.DataProcessing.Utils import addMonitoring + +#call to customisation function addMonitoring imported from Configuration.DataProcessing.Utils +process = addMonitoring(process) + +# Automatic addition of the customisation function from L1Trigger.Configuration.customisePhase2 +from L1Trigger.Configuration.customisePhase2 import addHcalTriggerPrimitives + +#call to customisation function addHcalTriggerPrimitives imported from L1Trigger.Configuration.customisePhase2 +process = addHcalTriggerPrimitives(process) + +# Automatic addition of the customisation function from L1Trigger.Configuration.customisePhase2FEVTDEBUGHLT +from L1Trigger.Configuration.customisePhase2FEVTDEBUGHLT import customisePhase2FEVTDEBUGHLT + +#call to customisation function customisePhase2FEVTDEBUGHLT imported from L1Trigger.Configuration.customisePhase2FEVTDEBUGHLT +process = customisePhase2FEVTDEBUGHLT(process) + +# Automatic addition of the customisation function from L1Trigger.Configuration.customisePhase2TTNoMC +from L1Trigger.Configuration.customisePhase2TTNoMC import customisePhase2TTNoMC + +#call to customisation function customisePhase2TTNoMC imported from L1Trigger.Configuration.customisePhase2TTNoMC +process = customisePhase2TTNoMC(process) + +# End of customisation functions + + +# Customisation from command line + +process.source.inputCommands = cms.untracked.vstring("keep *", "drop l1tPFJets_*_*_*") +# Add early deletion of temporary data products to reduce peak memory need +from Configuration.StandardSequences.earlyDeleteSettings_cff import customiseEarlyDelete +process = customiseEarlyDelete(process) +# End adding early deletion diff --git a/L1Trigger/Phase2L1GMT/test/saStudy.py b/L1Trigger/Phase2L1GMT/test/saStudy.py new file mode 100644 index 0000000000000..bd1b42f89d96d --- /dev/null +++ b/L1Trigger/Phase2L1GMT/test/saStudy.py @@ -0,0 +1,240 @@ +import ROOT,itertools,math +from array import array +from DataFormats.FWLite import Events, Handle +ROOT.FWLiteEnabler.enable() + + + + +def strAppend(s): + return "root://cmsxrootd.fnal.gov/"+s + +def fetchKMTF(event,tag,etamax=3.0): + phiSeg2 = Handle ('vector') + event.getByLabel(tag,phiSeg2) + return list(filter(lambda x: abs(x.eta())') + event.getByLabel(tag,phiSeg2) + return phiSeg2.product() + + +def fetchGEN(event,etaMax=3.0): + genH = Handle ('vector') + event.getByLabel('genParticles',genH) + genMuons=list(filter(lambda x: abs(x.pdgId())==13 and x.status()==1 and abs(x.eta()) math.pi: + res -= 2*math.pi + while res < -math.pi: + res += 2*math.pi + return res + +def deltaR( *args ): + return math.sqrt( deltaR2(*args) ) + +def deltaR2( e1, p1, e2, p2): + de = e1 - e2 + dp = deltaPhi(p1, p2) + return de*de + dp*dp + + +histoData={'effpt':{}, 'effeta':{},'geneta':{},'genphi':{},'effphi':{},'effptB':{},'effptO':{},'effptE':{}} +histoData['genpt'] = ROOT.TH1D("genpt","genpt",20,0,100) +histoData['genptB'] = ROOT.TH1D("genptB","genptB",20,0,100) +histoData['genptO'] = ROOT.TH1D("genptO","genptO",20,0,100) +histoData['genptE'] = ROOT.TH1D("genptE","genptE",20,0,100) +rate = ROOT.TH1D("rate","rate",20,0,100) +rateB = ROOT.TH1D("rateB","rateB",20,0,100) +rateO = ROOT.TH1D("rateO","rateO",20,0,100) +rateE = ROOT.TH1D("rateE","rateE",20,0,100) + +thresholds=[0,1,3,5,15,20] +for t in thresholds: + histoData['effpt'][t] = ROOT.TH1D("effpt_"+str(t),"effpt_"+str(t),20,0,100) + histoData['effptB'][t] = ROOT.TH1D("effptB_"+str(t),"effpt_"+str(t),20,0,100) + histoData['effptO'][t] = ROOT.TH1D("effptO_"+str(t),"effpt_"+str(t),20,0,100) + histoData['effptE'][t] = ROOT.TH1D("effptE_"+str(t),"effpt_"+str(t),20,0,100) + histoData['effeta'][t] = ROOT.TH1D("effeta_"+str(t),"effeta_"+str(t),48,-2.4,2.4) + histoData['effphi'][t] = ROOT.TH1D("effphi_"+str(t),"effphi_"+str(t),32,-math.pi,math.pi) + histoData['geneta'][t] = ROOT.TH1D("geneta_"+str(t),"effeta_"+str(t),48,-2.4,2.4) + histoData['genphi'][t] = ROOT.TH1D("genphi_"+str(t),"genphi_"+str(t),32,-math.pi,math.pi) + + + + +etaLUT = ROOT.TH2D("etaLUT","etaLUT",256,0,256,128,0.0,1.0) + +from samples200 import * +toProcess = jpsi200 + +files=[] + +for p in toProcess: + files.append(strAppend(p)) + +#events=Events(['file:/uscmst1b_scratch/lpc1/3DayLifetime/bachtis/test.root']) +events=Events(files) + + + +displaced=0 + + + +BUNCHFACTOR=40000*2760.0/3564.0 + +counter=0; +for event in events: + + gen=fetchGEN(event,2.4) + sa=fetchKMTF(event,'l1tSAMuonsGmt:prompt',2.5) + if displaced==1: + gen=fetchGEN(event,0.) + sa=fetchKMTF(event,'l1tKMTFMuonsGmt:displaced',2.5) + + highq=[] + + #reject single stub muons + for s in sa: + if s.hwQual()>0: + highq.append(s) + sa=highq + + maxPT = None + maxPTB = None + maxPTO = None + maxPTE = None + + for s in sa: + if maxPT==None or s.pt()>maxPT: + maxPT=s.pt() + if (maxPTB==None or s.pt()>maxPTB) and abs(s.eta())<0.83: + maxPTB=s.pt() + if (maxPTO==None or s.pt()>maxPTO) and abs(s.eta())>0.83 and abs(s.eta())<1.2: + maxPTO=s.pt() + if (maxPTE==None or s.pt()>maxPTE) and abs(s.eta())>1.2: + maxPTE=s.pt() + if maxPT!=None: + rate.Fill(maxPT) + if maxPTB!=None: + rateB.Fill(maxPTB) + if maxPTO!=None: + rateO.Fill(maxPTO) + if maxPTE!=None: + rateE.Fill(maxPTE) + + + +# print('---------------------NEW EVENT---------------------') + if counter %10000 ==0: + print(counter) + +# if counter==150000: +# break; +# print(counter) +# print('Generated muons') + for m in gen: + +# print("gen pt=",m.pt()) + histoData['genpt'].Fill(m.pt()) + if abs(m.eta())<0.83: + histoData['genptB'].Fill(m.pt()) + elif abs(m.eta())>0.83 and abs(m.eta())<1.2: + histoData['genptO'].Fill(m.pt()) + else: + histoData['genptE'].Fill(m.pt()) + for t in thresholds: + if m.pt()>(float(t)+10.0): + histoData['geneta'][t].Fill(m.eta()) + histoData['genphi'][t].Fill(m.phi()) + #fill the etaLUT + for r in sa: + if abs(deltaPhi(r.phi(),m.phi()))<0.3 and r.pt()>float(t) and r.hwQual()>0: + code=0; + for s in r.stubs(): + code = code| ( (int(abs(s.etaRegion())+1))<<(2*(s.depthRegion()-1))) + etaLUT.Fill(code,abs(m.eta())) + + for t in thresholds: +# print("Threshold {}".format(t)) +# for s in sa: +# print("muon pt={}".format(s.pt())) + matched=False + for r in sa: +# print("SA over muon pt={}".format(r.pt())) + + if deltaR(r.eta(),r.phi(),m.eta(),m.phi())<0.5 and r.pt()>float(t) and r.hwQual()>0: + matched=True + break +# print("matched={}".format(matched)) + if matched: + histoData['effpt'][t].Fill(m.pt()) + if abs(m.eta())<0.83: + histoData['effptB'][t].Fill(m.pt()) + elif abs(m.eta())>0.83 and abs(m.eta())<1.2: + histoData['effptO'][t].Fill(m.pt()) + else: + histoData['effptE'][t].Fill(m.pt()) + if m.pt()>(t+10): + histoData['effeta'][t].Fill(m.eta()) + histoData['effphi'][t].Fill(m.phi()) + + counter=counter+1 + +f=ROOT.TFile("saStudy_results.root","RECREATE") +f.cd() +#c = histoData['rate'].GetCumulative(False) +#c.Scale(float(BUNCHFACTOR)/float(counter)) +#c.Write("rate") +histoData['genpt'].Write("genpt") +histoData['genptB'].Write("genptB") +histoData['genptO'].Write("genptO") +histoData['genptE'].Write("genptE") +etaLUT.Write() +rate.Write() +rateB.Write() +rateE.Write() +rateO.Write() + +c = rate.GetCumulative(False) +c.Scale(float(BUNCHFACTOR)/float(counter)) +c.Write("rate") +c = rateB.GetCumulative(False) +c.Scale(float(BUNCHFACTOR)/float(counter)) +c.Write("rateBarrel") +c = rateO.GetCumulative(False) +c.Scale(float(BUNCHFACTOR)/float(counter)) +c.Write("rateOverlap") +c = rateE.GetCumulative(False) +c.Scale(float(BUNCHFACTOR)/float(counter)) +c.Write("rateEndcap") + + +for t in thresholds: + histoData['effpt'][t].Write("numpt_"+str(t)) + histoData['effeta'][t].Write("numeta_"+str(t)) + histoData['effphi'][t].Write("numphi_"+str(t)) + histoData['geneta'][t].Write("geneta_"+str(t)) + histoData['genphi'][t].Write("genphi_"+str(t)) + + g = ROOT.TGraphAsymmErrors(histoData['effpt'][t],histoData['genpt']) + g.Write("eff_"+str(t)) + g = ROOT.TGraphAsymmErrors(histoData['effptB'][t],histoData['genptB']) + g.Write("effB_"+str(t)) + g = ROOT.TGraphAsymmErrors(histoData['effptO'][t],histoData['genptO']) + g.Write("effO_"+str(t)) + g = ROOT.TGraphAsymmErrors(histoData['effptE'][t],histoData['genptE']) + g.Write("effE_"+str(t)) + g = ROOT.TGraphAsymmErrors(histoData['effeta'][t],histoData['geneta'][t]) + g.Write("effeta_"+str(t)) + g = ROOT.TGraphAsymmErrors(histoData['effphi'][t],histoData['genphi'][t]) + g.Write("effphi_"+str(t)) + +f.Close() diff --git a/L1Trigger/Phase2L1GMT/test/submitCrab.py b/L1Trigger/Phase2L1GMT/test/submitCrab.py index ab0d0069b9924..0e1fc86e97d2e 100644 --- a/L1Trigger/Phase2L1GMT/test/submitCrab.py +++ b/L1Trigger/Phase2L1GMT/test/submitCrab.py @@ -19,29 +19,51 @@ 'MinBias200_c':'/MinBias_TuneCP5_14TeV-pythia8/Phase2HLTTDRWinter20DIGI-PU200_withNewMB_110X_mcRun4_realistic_v3_ext1-v2/GEN-SIM-DIGI-RAW' } +data_Fall22 = { + 'DYToLL' : '/DYToLL_M-50_TuneCP5_14TeV-pythia8/Phase2Fall22DRMiniAOD-PU200_125X_mcRun4_realistic_v2-v1/GEN-SIM-DIGI-RAW-MINIAOD', + 'DsToTauTo3Mu' : '/DsToTauTo3Mu_TuneCP5_14TeV-pythia8/Phase2Fall22DRMiniAOD-PU200_125X_mcRun4_realistic_v2-v1/GEN-SIM-DIGI-RAW-MINIAOD', + 'MinBias' : '/MinBias_TuneCP5_14TeV-pythia8/Phase2Fall22DRMiniAOD-PU200_125X_mcRun4_realistic_v2-v1/GEN-SIM-DIGI-RAW-MINIAOD', + # 'Mu_0to200' : '/SingleMuon_Pt-0To200_Eta-1p4To3p1-gun/Phase2Fall22DRMiniAOD-PU200_125X_mcRun4_realistic_v2-v1/GEN-SIM-DIGI-RAW-MINIAOD', + # 'Mu_to500' : '/SingleMuon_Pt-200To500_Eta-1p4To3p1-gun/Phase2Fall22DRMiniAOD-PU200_125X_mcRun4_realistic_v2-v1/GEN-SIM-DIGI-RAW-MINIAOD', + 'TTTo2L2Nu' : '/TTTo2L2Nu_TuneCP5_14TeV-powheg-pythia8/Phase2Fall22DRMiniAOD-PU200_125X_mcRun4_realistic_v2-v1/GEN-SIM-DIGI-RAW-MINIAOD', + 'TTToSemiLepton' : '/TTToSemiLepton_TuneCP5_14TeV-powheg-pythia8/Phase2Fall22DRMiniAOD-PU200_125X_mcRun4_realistic_v2-v1/GEN-SIM-DIGI-RAW-MINIAOD', + 'TauTo3Mu' : '/TauTo3Mu_TuneCP5_14TeV-pythia8/Phase2Fall22DRMiniAOD-PU200_125X_mcRun4_realistic_v2-v1/GEN-SIM-DIGI-RAW-MINIAOD', + # 'GNN' : '/DSTau3Mu_pCut1_14TeV_Pythia8/jschulte-PhaseIIMTDTDRAutumn18DR-PU200_103X_upgrade2023_realistic_v2_GEN-SIM-DIGI-RAW_part3-v1-0b09b1d51eb1b176460746cc4e457a22/USER' +} + +data_Spring23= { + 'DYToLL' : '/DYToLL_M-50_TuneCP5_14TeV-pythia8/Phase2Spring23DIGIRECOMiniAOD-PU200_L1TFix_Trk1GeV_131X_mcRun4_realistic_v9-v3/GEN-SIM-DIGI-RAW-MINIAOD', + 'DsToTauTo3Mu' : '/DsToTauTo3Mu_TuneCP5_14TeV-pythia8/Phase2Spring23DIGIRECOMiniAOD-PU200_131X_mcRun4_realistic_v5-v1/GEN-SIM-DIGI-RAW-MINIAOD', + 'MinBias' : '/MinBias_TuneCP5_14TeV-pythia8/Phase2Spring23DIGIRECOMiniAOD-PU200_L1TFix_Trk1GeV_131X_mcRun4_realistic_v9_ext1-v2/GEN-SIM-DIGI-RAW-MINIAOD', + # 'Mu_0to200' : '/SingleMuon_Pt-0To200_Eta-1p4To3p1-gun/Phase2Fall22DRMiniAOD-PU200_125X_mcRun4_realistic_v2-v1/GEN-SIM-DIGI-RAW-MINIAOD', + # 'Mu_to500' : '/SingleMuon_Pt-200To500_Eta-1p4To3p1-gun/Phase2Fall22DRMiniAOD-PU200_125X_mcRun4_realistic_v2-v1/GEN-SIM-DIGI-RAW-MINIAOD', + 'TTTo2L2Nu' : '/TTTo2L2Nu_TuneCP5_14TeV-powheg-pythia8/Phase2Spring23DIGIRECOMiniAOD-PU200_Trk1GeV_131X_mcRun4_realistic_v5-v1/GEN-SIM-DIGI-RAW-MINIAOD', + # 'GNN' : '/DSTau3Mu_pCut1_14TeV_Pythia8/jschulte-PhaseIIMTDTDRAutumn18DR-PU200_103X_upgrade2023_realistic_v2_GEN-SIM-DIGI-RAW_part3-v1-0b09b1d51eb1b176460746cc4e457a22/USER' +} + -for tag,dataset in data.iteritems(): +for tag,dataset in data_Spring23.iteritems(): FILE=""" from CRABClient.UserUtilities import config config = config() config.General.requestName = 'skim_{tag}' -config.General.workArea = 'crab_projects' +config.General.workArea = 'crab_projects_Spring_v3' config.General.transferOutputs = True -config.General.transferLogs = False +config.General.transferLogs = True config.JobType.pluginName = 'Analysis' config.JobType.psetName = 'runGMT.py' config.Data.inputDataset = '{dataset}' config.Data.inputDBS = 'global' config.Data.splitting = 'FileBased' -config.Data.unitsPerJob = 1 -config.Data.outLFNDirBase = '/store/user/bachtis/L1TF4' -config.Data.publication = True +config.Data.unitsPerJob = 2 +config.Data.outLFNDirBase = '/store/group/lpctrig/benwu/GMT_Ntupler/Spring22_GMT_v3' +config.Data.publication = False config.Data.ignoreLocality = True config.Data.outputDatasetTag = 'PHASEII_{tag}' config.Site.storageSite = 'T3_US_FNALLPC' config.Site.whitelist = ['T2_US_*'] config.JobType.allowUndistributedCMSSW = True -config.JobType.maxMemoryMB = 4000 +config.JobType.maxMemoryMB = 5000 """.format(tag=tag,dataset=dataset) f=open("crab_{tag}.py".format(tag=tag),"w") print(FILE) diff --git a/L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc b/L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc index 4e1cf7d93ecc9..a7ab13fecf97e 100644 --- a/L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc +++ b/L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc @@ -219,7 +219,7 @@ namespace l1t { gtObj.hwPhi_ = obj.apPhi().to_int(); gtObj.hwEta_ = obj.apEta().to_int(); gtObj.hwZ0_ = hwZ0; - gtObj.hwQual_ = obj.apQual().to_int(); + gtObj.hwQual_ = obj.apQualFlag().to_int(); gtObj.hwCharge_ = obj.apCharge().to_int(); gtObj.hwD0_ = obj.apD0().to_int(); gtObj.objectType_ = P2GTCandidate::GMTSaPromptMuons; @@ -245,7 +245,7 @@ namespace l1t { gtObj.hwPhi_ = obj.apPhi().to_int(); gtObj.hwEta_ = obj.apEta().to_int(); gtObj.hwZ0_ = hwZ0; - gtObj.hwQual_ = obj.apQual().to_int(); + gtObj.hwQual_ = obj.apQualFlag().to_int(); gtObj.hwCharge_ = obj.apCharge().to_int(); gtObj.hwD0_ = obj.apD0().to_int(); gtObj.objectType_ = P2GTCandidate::GMTSaDisplacedMuons; @@ -272,7 +272,7 @@ namespace l1t { gtObj.hwEta_ = obj.apEta().to_int(); gtObj.hwZ0_ = hwZ0; gtObj.hwIso_ = obj.apIso().to_int(); - gtObj.hwQual_ = obj.apQual().to_int(); + gtObj.hwQual_ = obj.apQualFlag().to_int(); gtObj.hwCharge_ = obj.apCharge().to_int(); gtObj.hwD0_ = obj.apD0().to_int(); gtObj.hwBeta_ = obj.apBeta().to_int(); From 90d71da875e9241eb60340a65939445ad3d4f75d Mon Sep 17 00:00:00 2001 From: Zhenbin Wu Date: Wed, 20 Mar 2024 14:52:46 -0500 Subject: [PATCH 02/17] Update apQualFlag to apQualFlags as requested by GT --- DataFormats/L1TMuonPhase2/interface/SAMuon.h | 2 +- DataFormats/L1TMuonPhase2/interface/TrackerMuon.h | 2 +- L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DataFormats/L1TMuonPhase2/interface/SAMuon.h b/DataFormats/L1TMuonPhase2/interface/SAMuon.h index 1eb49f58291d4..31c53af75d299 100644 --- a/DataFormats/L1TMuonPhase2/interface/SAMuon.h +++ b/DataFormats/L1TMuonPhase2/interface/SAMuon.h @@ -45,7 +45,7 @@ namespace l1t { const Phase2L1GMT::z0_sa_t apZ0() const { return Phase2L1GMT::z0_sa_t(hwZ0()); }; const Phase2L1GMT::d0_sa_t apD0() const { return Phase2L1GMT::d0_sa_t(hwD0()); }; const Phase2L1GMT::q_sa_t apCharge() const { return Phase2L1GMT::q_sa_t(hwCharge()); }; - const Phase2L1GMT::qual_sa_t apQualFlag() const { return Phase2L1GMT::qual_sa_t(hwQual()); }; + const Phase2L1GMT::qual_sa_t apQualFlags() const { return Phase2L1GMT::qual_sa_t(hwQual()); }; // For HLT const double phZ0() const { return Phase2L1GMT::LSBSAz0 * hwZ0(); } diff --git a/DataFormats/L1TMuonPhase2/interface/TrackerMuon.h b/DataFormats/L1TMuonPhase2/interface/TrackerMuon.h index 470833d471347..8946a8195afb2 100644 --- a/DataFormats/L1TMuonPhase2/interface/TrackerMuon.h +++ b/DataFormats/L1TMuonPhase2/interface/TrackerMuon.h @@ -54,7 +54,7 @@ namespace l1t { const Phase2L1GMT::z0_gt_t apZ0() const { return Phase2L1GMT::z0_gt_t(hwZ0()); }; const Phase2L1GMT::d0_gt_t apD0() const { return Phase2L1GMT::d0_gt_t(hwD0()); }; const Phase2L1GMT::q_gt_t apCharge() const { return Phase2L1GMT::q_gt_t(hwCharge()); }; - const Phase2L1GMT::qual_gt_t apQualFlag() const { return Phase2L1GMT::qual_gt_t(hwQual()); }; + const Phase2L1GMT::qual_gt_t apQualFlags() const { return Phase2L1GMT::qual_gt_t(hwQual()); }; const Phase2L1GMT::iso_gt_t apIso() const { return Phase2L1GMT::iso_gt_t(hwIsoSumAp()); }; const Phase2L1GMT::beta_gt_t apBeta() const { return Phase2L1GMT::beta_gt_t(hwBeta()); }; diff --git a/L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc b/L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc index a7ab13fecf97e..6166e35c93271 100644 --- a/L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc +++ b/L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc @@ -219,7 +219,7 @@ namespace l1t { gtObj.hwPhi_ = obj.apPhi().to_int(); gtObj.hwEta_ = obj.apEta().to_int(); gtObj.hwZ0_ = hwZ0; - gtObj.hwQual_ = obj.apQualFlag().to_int(); + gtObj.hwQual_ = obj.apQualFlags().to_int(); gtObj.hwCharge_ = obj.apCharge().to_int(); gtObj.hwD0_ = obj.apD0().to_int(); gtObj.objectType_ = P2GTCandidate::GMTSaPromptMuons; @@ -245,7 +245,7 @@ namespace l1t { gtObj.hwPhi_ = obj.apPhi().to_int(); gtObj.hwEta_ = obj.apEta().to_int(); gtObj.hwZ0_ = hwZ0; - gtObj.hwQual_ = obj.apQualFlag().to_int(); + gtObj.hwQual_ = obj.apQualFlags().to_int(); gtObj.hwCharge_ = obj.apCharge().to_int(); gtObj.hwD0_ = obj.apD0().to_int(); gtObj.objectType_ = P2GTCandidate::GMTSaDisplacedMuons; @@ -272,7 +272,7 @@ namespace l1t { gtObj.hwEta_ = obj.apEta().to_int(); gtObj.hwZ0_ = hwZ0; gtObj.hwIso_ = obj.apIso().to_int(); - gtObj.hwQual_ = obj.apQualFlag().to_int(); + gtObj.hwQual_ = obj.apQualFlags().to_int(); gtObj.hwCharge_ = obj.apCharge().to_int(); gtObj.hwD0_ = obj.apD0().to_int(); gtObj.hwBeta_ = obj.apBeta().to_int(); From 7518022bb269828b6fa3e875d9b67e7df560a445 Mon Sep 17 00:00:00 2001 From: Zhenbin Wu Date: Wed, 20 Mar 2024 18:34:54 -0500 Subject: [PATCH 03/17] Update PTLUT corresponding to minRinv 0.006 from L1Track --- L1Trigger/Phase2L1GMT/interface/TPSLUTs.h | 236 ++++++++++-------- .../test/makeTrackConversionLUTs.py | 72 ++++-- 2 files changed, 185 insertions(+), 123 deletions(-) diff --git a/L1Trigger/Phase2L1GMT/interface/TPSLUTs.h b/L1Trigger/Phase2L1GMT/interface/TPSLUTs.h index 0db5b9b2d7c4a..5463f039df9f6 100644 --- a/L1Trigger/Phase2L1GMT/interface/TPSLUTs.h +++ b/L1Trigger/Phase2L1GMT/interface/TPSLUTs.h @@ -6,115 +6,135 @@ namespace Phase2L1GMT { - const int ptShifts[9][5] = {{1, 86, -1, 0, 0}, - {86, 1184, 0, -85, 0}, - {1184, 1674, 1, 507, 0}, - {1674, 2367, 2, 925, 0}, - {2367, 3346, 3, 1222, 0}, - {3346, 4732, 4, 1431, 0}, - {4732, 6691, 5, 1580, 0}, - {6691, 10923, 6, 1686, 0}, - {10923, 16384, -2, 0, 1857}}; + const int ptShifts[8][5] = {{1, 122, -1, 0, 0}, + {122, 1415, 0, -121, 0}, + {1415, 2000, 1, 586, 0}, + {2000, 2828, 2, 1086, 0}, + {2828, 3999, 3, 1440, 0}, + {3999, 5654, 4, 1691, 0}, + {5654, 7996, 5, 1869, 0}, + {7996, 16385, 6, 1995, 0}}; - const ap_uint ptLUT[1858] = { - 8191, 8128, 8035, 7944, 7855, 7767, 7682, 7598, 7517, 7437, 7358, 7282, 7207, 7133, 7061, 6991, 6921, 6853, 6787, - 6722, 6658, 6595, 6533, 6473, 6413, 6355, 6298, 6242, 6186, 6132, 6079, 6026, 5975, 5924, 5874, 5825, 5777, 5730, - 5683, 5638, 5592, 5548, 5504, 5461, 5419, 5377, 5336, 5296, 5256, 5217, 5178, 5140, 5103, 5066, 5029, 4993, 4958, - 4923, 4888, 4855, 4821, 4788, 4755, 4723, 4692, 4660, 4629, 4599, 4569, 4539, 4510, 4481, 4453, 4424, 4397, 4369, - 4342, 4315, 4289, 4263, 4237, 4211, 4186, 4161, 4136, 4112, 4088, 4064, 4041, 4018, 3995, 3972, 3949, 3927, 3905, - 3884, 3862, 3841, 3820, 3799, 3779, 3758, 3738, 3718, 3699, 3679, 3660, 3641, 3622, 3603, 3585, 3567, 3548, 3531, - 3513, 3495, 3478, 3461, 3444, 3427, 3410, 3393, 3377, 3361, 3345, 3329, 3313, 3297, 3282, 3267, 3251, 3236, 3221, - 3207, 3192, 3178, 3163, 3149, 3135, 3121, 3107, 3093, 3080, 3066, 3053, 3039, 3026, 3013, 3000, 2987, 2975, 2962, - 2950, 2937, 2925, 2913, 2901, 2889, 2877, 2865, 2853, 2842, 2830, 2819, 2807, 2796, 2785, 2774, 2763, 2752, 2741, - 2731, 2720, 2709, 2699, 2689, 2678, 2668, 2658, 2648, 2638, 2628, 2618, 2608, 2599, 2589, 2580, 2570, 2561, 2551, - 2542, 2533, 2524, 2515, 2506, 2497, 2488, 2479, 2470, 2461, 2453, 2444, 2436, 2427, 2419, 2411, 2402, 2394, 2386, - 2378, 2370, 2362, 2354, 2346, 2338, 2330, 2322, 2315, 2307, 2300, 2292, 2284, 2277, 2270, 2262, 2255, 2248, 2241, - 2233, 2226, 2219, 2212, 2205, 2198, 2191, 2185, 2178, 2171, 2164, 2158, 2151, 2144, 2138, 2131, 2125, 2118, 2112, - 2106, 2099, 2093, 2087, 2081, 2074, 2068, 2062, 2056, 2050, 2044, 2038, 2032, 2026, 2020, 2015, 2009, 2003, 1997, - 1992, 1986, 1980, 1975, 1969, 1964, 1958, 1953, 1947, 1942, 1936, 1931, 1926, 1920, 1915, 1910, 1905, 1900, 1894, - 1889, 1884, 1879, 1874, 1869, 1864, 1859, 1854, 1849, 1844, 1840, 1835, 1830, 1825, 1820, 1816, 1811, 1806, 1802, - 1797, 1792, 1788, 1783, 1779, 1774, 1770, 1765, 1761, 1756, 1752, 1748, 1743, 1739, 1735, 1730, 1726, 1722, 1718, - 1713, 1709, 1705, 1701, 1697, 1693, 1689, 1684, 1680, 1676, 1672, 1668, 1664, 1660, 1657, 1653, 1649, 1645, 1641, - 1637, 1633, 1629, 1626, 1622, 1618, 1614, 1611, 1607, 1603, 1600, 1596, 1592, 1589, 1585, 1582, 1578, 1574, 1571, - 1567, 1564, 1560, 1557, 1553, 1550, 1547, 1543, 1540, 1536, 1533, 1530, 1526, 1523, 1520, 1516, 1513, 1510, 1507, - 1503, 1500, 1497, 1494, 1491, 1487, 1484, 1481, 1478, 1475, 1472, 1469, 1466, 1462, 1459, 1456, 1453, 1450, 1447, - 1444, 1441, 1438, 1435, 1432, 1430, 1427, 1424, 1421, 1418, 1415, 1412, 1409, 1407, 1404, 1401, 1398, 1395, 1393, - 1390, 1387, 1384, 1382, 1379, 1376, 1373, 1371, 1368, 1365, 1363, 1360, 1357, 1355, 1352, 1350, 1347, 1344, 1342, - 1339, 1337, 1334, 1332, 1329, 1326, 1324, 1321, 1319, 1316, 1314, 1312, 1309, 1307, 1304, 1302, 1299, 1297, 1295, - 1292, 1290, 1287, 1285, 1283, 1280, 1278, 1276, 1273, 1271, 1269, 1266, 1264, 1262, 1260, 1257, 1255, 1253, 1251, - 1248, 1246, 1244, 1242, 1239, 1237, 1235, 1233, 1231, 1229, 1226, 1224, 1222, 1220, 1218, 1216, 1214, 1212, 1209, - 1207, 1205, 1203, 1201, 1199, 1197, 1195, 1193, 1191, 1189, 1187, 1185, 1183, 1181, 1179, 1177, 1175, 1173, 1171, - 1169, 1167, 1165, 1163, 1161, 1159, 1157, 1155, 1154, 1152, 1150, 1148, 1146, 1144, 1142, 1140, 1139, 1137, 1135, - 1133, 1131, 1129, 1128, 1126, 1124, 1122, 1120, 1118, 1117, 1115, 1113, 1111, 1110, 1108, 1106, 1104, 1103, 1101, - 1099, 1097, 1096, 1094, 1092, 1091, 1089, 1087, 1085, 1084, 1082, 1080, 1079, 1077, 1075, 1074, 1072, 1071, 1069, - 1067, 1066, 1064, 1062, 1061, 1059, 1058, 1056, 1054, 1053, 1051, 1050, 1048, 1046, 1045, 1043, 1042, 1040, 1039, - 1037, 1036, 1034, 1033, 1031, 1030, 1028, 1027, 1025, 1024, 1022, 1021, 1019, 1018, 1016, 1015, 1013, 1012, 1010, - 1009, 1007, 1006, 1004, 1003, 1002, 1000, 999, 997, 996, 994, 993, 992, 990, 989, 987, 986, 985, 983, - 982, 980, 979, 978, 976, 975, 974, 972, 971, 970, 968, 967, 966, 964, 963, 962, 960, 959, 958, - 956, 955, 954, 952, 951, 950, 949, 947, 946, 945, 943, 942, 941, 940, 938, 937, 936, 935, 933, - 932, 931, 930, 928, 927, 926, 925, 923, 922, 921, 920, 919, 917, 916, 915, 914, 913, 911, 910, - 909, 908, 907, 906, 904, 903, 902, 901, 900, 899, 897, 896, 895, 894, 893, 892, 891, 889, 888, - 887, 886, 885, 884, 883, 882, 880, 879, 878, 877, 876, 875, 874, 873, 872, 871, 869, 868, 867, - 866, 865, 864, 863, 862, 861, 860, 859, 858, 857, 856, 855, 854, 853, 851, 850, 849, 848, 847, - 846, 845, 844, 843, 842, 841, 840, 839, 838, 837, 836, 835, 834, 833, 832, 831, 830, 829, 828, - 827, 826, 825, 824, 823, 822, 821, 820, 820, 819, 818, 817, 816, 815, 814, 813, 812, 811, 810, - 809, 808, 807, 806, 805, 804, 804, 803, 802, 801, 800, 799, 798, 797, 796, 795, 794, 793, 793, - 792, 791, 790, 789, 788, 787, 786, 785, 785, 784, 783, 782, 781, 780, 779, 778, 778, 777, 776, - 775, 774, 773, 772, 772, 771, 770, 769, 768, 767, 767, 766, 765, 764, 763, 762, 761, 761, 760, - 759, 758, 757, 757, 756, 755, 754, 753, 752, 752, 751, 750, 749, 748, 748, 747, 746, 745, 744, - 744, 743, 742, 741, 741, 740, 739, 738, 737, 737, 736, 735, 734, 734, 733, 732, 731, 730, 730, - 729, 728, 727, 727, 726, 725, 724, 724, 723, 722, 721, 721, 720, 719, 718, 718, 717, 716, 716, - 715, 714, 713, 713, 712, 711, 710, 710, 709, 708, 708, 707, 706, 705, 705, 704, 703, 703, 702, - 701, 700, 700, 699, 698, 698, 697, 696, 696, 695, 694, 694, 693, 692, 691, 691, 690, 689, 689, - 688, 687, 687, 686, 685, 685, 684, 683, 683, 682, 681, 681, 680, 679, 679, 678, 677, 677, 676, - 675, 675, 674, 673, 673, 672, 672, 671, 670, 670, 669, 668, 668, 667, 666, 666, 665, 664, 664, - 663, 663, 662, 661, 661, 660, 659, 659, 658, 658, 657, 656, 656, 655, 655, 654, 653, 653, 652, - 651, 651, 650, 650, 649, 648, 648, 647, 647, 646, 645, 645, 644, 644, 643, 643, 642, 641, 641, - 640, 640, 639, 638, 638, 637, 637, 636, 636, 635, 634, 634, 633, 633, 632, 631, 631, 630, 630, - 629, 629, 628, 628, 627, 626, 626, 625, 625, 624, 624, 623, 622, 622, 621, 621, 620, 620, 619, - 619, 618, 618, 617, 616, 616, 615, 615, 614, 614, 613, 613, 612, 612, 611, 611, 610, 609, 609, - 608, 608, 607, 607, 606, 606, 605, 605, 604, 604, 603, 603, 602, 602, 601, 601, 600, 600, 599, - 599, 598, 597, 597, 596, 596, 595, 595, 594, 594, 593, 593, 592, 592, 591, 591, 590, 589, 588, - 587, 586, 585, 584, 583, 582, 581, 580, 579, 578, 577, 576, 575, 574, 573, 573, 572, 571, 570, - 569, 568, 567, 566, 565, 564, 563, 562, 561, 561, 560, 559, 558, 557, 556, 555, 554, 553, 553, - 552, 551, 550, 549, 548, 547, 547, 546, 545, 544, 543, 542, 541, 541, 540, 539, 538, 537, 536, - 536, 535, 534, 533, 532, 532, 531, 530, 529, 528, 528, 527, 526, 525, 524, 524, 523, 522, 521, - 521, 520, 519, 518, 517, 517, 516, 515, 514, 514, 513, 512, 511, 511, 510, 509, 508, 508, 507, - 506, 505, 505, 504, 503, 503, 502, 501, 500, 500, 499, 498, 498, 497, 496, 495, 495, 494, 493, - 493, 492, 491, 491, 490, 489, 489, 488, 487, 486, 486, 485, 484, 484, 483, 482, 482, 481, 480, - 480, 479, 478, 478, 477, 477, 476, 475, 475, 474, 473, 473, 472, 471, 471, 470, 469, 469, 468, - 468, 467, 466, 466, 465, 464, 464, 463, 463, 462, 461, 461, 460, 460, 459, 458, 458, 457, 457, - 456, 455, 455, 454, 454, 453, 452, 452, 451, 451, 450, 450, 449, 448, 448, 447, 447, 446, 446, - 445, 444, 444, 443, 443, 442, 442, 441, 440, 440, 439, 439, 438, 438, 437, 437, 436, 436, 435, - 434, 434, 433, 433, 432, 432, 431, 431, 430, 430, 429, 429, 428, 428, 427, 427, 426, 425, 425, - 424, 424, 423, 423, 422, 422, 421, 421, 420, 420, 419, 419, 418, 418, 417, 416, 415, 414, 413, - 412, 411, 410, 409, 408, 407, 406, 405, 404, 403, 402, 401, 400, 399, 399, 398, 397, 396, 395, - 394, 393, 392, 391, 391, 390, 389, 388, 387, 386, 385, 385, 384, 383, 382, 381, 380, 380, 379, - 378, 377, 376, 375, 375, 374, 373, 372, 371, 371, 370, 369, 368, 368, 367, 366, 365, 364, 364, - 363, 362, 361, 361, 360, 359, 358, 358, 357, 356, 356, 355, 354, 353, 353, 352, 351, 351, 350, - 349, 348, 348, 347, 346, 346, 345, 344, 344, 343, 342, 342, 341, 340, 340, 339, 338, 338, 337, - 336, 336, 335, 334, 334, 333, 333, 332, 331, 331, 330, 329, 329, 328, 328, 327, 326, 326, 325, - 325, 324, 323, 323, 322, 322, 321, 320, 320, 319, 319, 318, 317, 317, 316, 316, 315, 315, 314, - 313, 313, 312, 312, 311, 311, 310, 310, 309, 308, 308, 307, 307, 306, 306, 305, 305, 304, 304, - 303, 303, 302, 302, 301, 301, 300, 300, 299, 298, 298, 297, 297, 296, 296, 296, 295, 295, 294, - 293, 292, 291, 290, 289, 288, 287, 286, 285, 284, 283, 282, 281, 281, 280, 279, 278, 277, 276, - 275, 274, 273, 273, 272, 271, 270, 269, 268, 268, 267, 266, 265, 264, 264, 263, 262, 261, 260, - 260, 259, 258, 257, 257, 256, 255, 254, 254, 253, 252, 251, 251, 250, 249, 249, 248, 247, 246, - 246, 245, 244, 244, 243, 242, 242, 241, 240, 240, 239, 238, 238, 237, 236, 236, 235, 235, 234, - 233, 233, 232, 231, 231, 230, 230, 229, 228, 228, 227, 227, 226, 226, 225, 224, 224, 223, 223, - 222, 221, 221, 220, 220, 219, 219, 218, 218, 217, 217, 216, 215, 215, 214, 214, 213, 213, 212, - 212, 211, 211, 210, 210, 209, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, - 196, 195, 195, 194, 193, 192, 191, 190, 190, 189, 188, 187, 186, 186, 185, 184, 183, 182, 182, - 181, 180, 179, 179, 178, 177, 177, 176, 175, 174, 174, 173, 172, 172, 171, 170, 170, 169, 168, - 168, 167, 166, 166, 165, 165, 164, 163, 163, 162, 162, 161, 160, 160, 159, 159, 158, 157, 157, - 156, 156, 155, 155, 154, 154, 153, 152, 152, 151, 151, 150, 150, 149, 149, 148, 148, 148, 147, - 146, 145, 144, 143, 142, 141, 140, 140, 139, 138, 137, 136, 135, 134, 134, 133, 132, 131, 130, - 130, 129, 128, 127, 127, 126, 125, 124, 124, 123, 122, 122, 121, 120, 120, 119, 118, 118, 117, - 117, 116, 115, 115, 114, 113, 113, 112, 112, 111, 111, 110, 110, 109, 108, 108, 107, 107, 106, - 106, 105, 105, 105, 104, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 95, 94, 93, 92, - 91, 91, 90, 89, 88, 88, 87, 86, 86, 85, 84, 84, 83, 82, 82, 81, 81, 80, 79, - 79, 78, 78, 77, 77, 76, 76, 75, 75, 74, 74, 73, 73, 72, 72, 71, 71, 70, 70, - 69, 69, 68, 68, 68, 67, 67, 66, 66, 66, 65, 65, 64, 64, 64}; + const ap_uint ptLUT[2251] = { + 8191, 8184, 8117, 8052, 7987, 7924, 7861, 7800, 7739, 7680, 7621, 7564, 7507, 7451, 7396, 7341, 7288, 7235, 7183, + 7131, 7081, 7031, 6982, 6933, 6885, 6838, 6792, 6746, 6701, 6656, 6612, 6568, 6525, 6483, 6441, 6400, 6359, 6319, + 6279, 6240, 6201, 6163, 6125, 6088, 6051, 6014, 5978, 5943, 5908, 5873, 5839, 5805, 5771, 5738, 5705, 5673, 5641, + 5609, 5578, 5547, 5516, 5486, 5456, 5426, 5397, 5368, 5339, 5311, 5283, 5255, 5227, 5200, 5173, 5146, 5120, 5094, + 5068, 5042, 5017, 4992, 4967, 4943, 4918, 4894, 4870, 4847, 4823, 4800, 4777, 4754, 4732, 4709, 4687, 4665, 4644, + 4622, 4601, 4580, 4559, 4538, 4518, 4497, 4477, 4457, 4437, 4418, 4398, 4379, 4360, 4341, 4322, 4303, 4285, 4267, + 4248, 4230, 4213, 4195, 4177, 4160, 4143, 4126, 4109, 4092, 4075, 4059, 4042, 4026, 4010, 3994, 3978, 3962, 3946, + 3931, 3915, 3900, 3885, 3870, 3855, 3840, 3825, 3811, 3796, 3782, 3768, 3753, 3739, 3725, 3711, 3698, 3684, 3671, + 3657, 3644, 3631, 3617, 3604, 3591, 3578, 3566, 3553, 3540, 3528, 3515, 3503, 3491, 3479, 3467, 3455, 3443, 3431, + 3419, 3407, 3396, 3384, 3373, 3362, 3350, 3339, 3328, 3317, 3306, 3295, 3284, 3273, 3263, 3252, 3242, 3231, 3221, + 3210, 3200, 3190, 3180, 3170, 3159, 3150, 3140, 3130, 3120, 3110, 3101, 3091, 3081, 3072, 3063, 3053, 3044, 3035, + 3025, 3016, 3007, 2998, 2989, 2980, 2971, 2963, 2954, 2945, 2936, 2928, 2919, 2911, 2902, 2894, 2886, 2877, 2869, + 2861, 2853, 2844, 2836, 2828, 2820, 2812, 2804, 2797, 2789, 2781, 2773, 2766, 2758, 2750, 2743, 2735, 2728, 2720, + 2713, 2706, 2698, 2691, 2684, 2677, 2669, 2662, 2655, 2648, 2641, 2634, 2627, 2620, 2614, 2607, 2600, 2593, 2587, + 2580, 2573, 2567, 2560, 2553, 2547, 2540, 2534, 2528, 2521, 2515, 2509, 2502, 2496, 2490, 2484, 2477, 2471, 2465, + 2459, 2453, 2447, 2441, 2435, 2429, 2423, 2417, 2412, 2406, 2400, 2394, 2388, 2383, 2377, 2371, 2366, 2360, 2355, + 2349, 2344, 2338, 2333, 2327, 2322, 2316, 2311, 2306, 2300, 2295, 2290, 2285, 2279, 2274, 2269, 2264, 2259, 2254, + 2249, 2244, 2239, 2234, 2229, 2224, 2219, 2214, 2209, 2204, 2199, 2194, 2189, 2185, 2180, 2175, 2170, 2166, 2161, + 2156, 2152, 2147, 2142, 2138, 2133, 2129, 2124, 2120, 2115, 2111, 2106, 2102, 2097, 2093, 2089, 2084, 2080, 2076, + 2071, 2067, 2063, 2059, 2054, 2050, 2046, 2042, 2038, 2033, 2029, 2025, 2021, 2017, 2013, 2009, 2005, 2001, 1997, + 1993, 1989, 1985, 1981, 1977, 1973, 1969, 1965, 1961, 1958, 1954, 1950, 1946, 1942, 1939, 1935, 1931, 1927, 1924, + 1920, 1916, 1913, 1909, 1905, 1902, 1898, 1894, 1891, 1887, 1884, 1880, 1877, 1873, 1870, 1866, 1863, 1859, 1856, + 1852, 1849, 1845, 1842, 1839, 1835, 1832, 1829, 1825, 1822, 1819, 1815, 1812, 1809, 1805, 1802, 1799, 1796, 1792, + 1789, 1786, 1783, 1780, 1776, 1773, 1770, 1767, 1764, 1761, 1758, 1755, 1752, 1748, 1745, 1742, 1739, 1736, 1733, + 1730, 1727, 1724, 1721, 1718, 1715, 1713, 1710, 1707, 1704, 1701, 1698, 1695, 1692, 1689, 1686, 1684, 1681, 1678, + 1675, 1672, 1670, 1667, 1664, 1661, 1658, 1656, 1653, 1650, 1648, 1645, 1642, 1639, 1637, 1634, 1631, 1629, 1626, + 1623, 1621, 1618, 1616, 1613, 1610, 1608, 1605, 1603, 1600, 1597, 1595, 1592, 1590, 1587, 1585, 1582, 1580, 1577, + 1575, 1572, 1570, 1567, 1565, 1562, 1560, 1558, 1555, 1553, 1550, 1548, 1545, 1543, 1541, 1538, 1536, 1534, 1531, + 1529, 1527, 1524, 1522, 1520, 1517, 1515, 1513, 1510, 1508, 1506, 1504, 1501, 1499, 1497, 1495, 1492, 1490, 1488, + 1486, 1483, 1481, 1479, 1477, 1475, 1473, 1470, 1468, 1466, 1464, 1462, 1460, 1458, 1455, 1453, 1451, 1449, 1447, + 1445, 1443, 1441, 1439, 1437, 1434, 1432, 1430, 1428, 1426, 1424, 1422, 1420, 1418, 1416, 1414, 1412, 1410, 1408, + 1406, 1404, 1402, 1400, 1398, 1396, 1394, 1392, 1391, 1389, 1387, 1385, 1383, 1381, 1379, 1377, 1375, 1373, 1371, + 1370, 1368, 1366, 1364, 1362, 1360, 1358, 1357, 1355, 1353, 1351, 1349, 1347, 1346, 1344, 1342, 1340, 1338, 1337, + 1335, 1333, 1331, 1329, 1328, 1326, 1324, 1322, 1321, 1319, 1317, 1315, 1314, 1312, 1310, 1309, 1307, 1305, 1303, + 1302, 1300, 1298, 1297, 1295, 1293, 1292, 1290, 1288, 1287, 1285, 1283, 1282, 1280, 1278, 1277, 1275, 1273, 1272, + 1270, 1269, 1267, 1265, 1264, 1262, 1261, 1259, 1257, 1256, 1254, 1253, 1251, 1250, 1248, 1246, 1245, 1243, 1242, + 1240, 1239, 1237, 1236, 1234, 1233, 1231, 1230, 1228, 1227, 1225, 1224, 1222, 1221, 1219, 1218, 1216, 1215, 1213, + 1212, 1210, 1209, 1207, 1206, 1204, 1203, 1201, 1200, 1199, 1197, 1196, 1194, 1193, 1191, 1190, 1189, 1187, 1186, + 1184, 1183, 1182, 1180, 1179, 1177, 1176, 1175, 1173, 1172, 1170, 1169, 1168, 1166, 1165, 1164, 1162, 1161, 1160, + 1158, 1157, 1156, 1154, 1153, 1152, 1150, 1149, 1148, 1146, 1145, 1144, 1142, 1141, 1140, 1138, 1137, 1136, 1135, + 1133, 1132, 1131, 1129, 1128, 1127, 1126, 1124, 1123, 1122, 1121, 1119, 1118, 1117, 1116, 1114, 1113, 1112, 1111, + 1109, 1108, 1107, 1106, 1104, 1103, 1102, 1101, 1100, 1098, 1097, 1096, 1095, 1094, 1092, 1091, 1090, 1089, 1088, + 1086, 1085, 1084, 1083, 1082, 1081, 1079, 1078, 1077, 1076, 1075, 1074, 1072, 1071, 1070, 1069, 1068, 1067, 1066, + 1064, 1063, 1062, 1061, 1060, 1059, 1058, 1057, 1055, 1054, 1053, 1052, 1051, 1050, 1049, 1048, 1047, 1045, 1044, + 1043, 1042, 1041, 1040, 1039, 1038, 1037, 1036, 1035, 1034, 1032, 1031, 1030, 1029, 1028, 1027, 1026, 1025, 1024, + 1023, 1022, 1021, 1020, 1019, 1018, 1017, 1016, 1015, 1014, 1013, 1012, 1011, 1009, 1008, 1007, 1006, 1005, 1004, + 1003, 1002, 1001, 1000, 999, 998, 997, 996, 995, 994, 993, 992, 991, 990, 989, 989, 988, 987, 986, + 985, 984, 983, 982, 981, 980, 979, 978, 977, 976, 975, 974, 973, 972, 971, 970, 969, 968, 967, + 966, 966, 965, 964, 963, 962, 961, 960, 959, 958, 957, 956, 955, 954, 954, 953, 952, 951, 950, + 949, 948, 947, 946, 945, 945, 944, 943, 942, 941, 940, 939, 938, 937, 937, 936, 935, 934, 933, + 932, 931, 930, 930, 929, 928, 927, 926, 925, 924, 924, 923, 922, 921, 920, 919, 918, 918, 917, + 916, 915, 914, 913, 913, 912, 911, 910, 909, 908, 908, 907, 906, 905, 904, 904, 903, 902, 901, + 900, 899, 899, 898, 897, 896, 895, 895, 894, 893, 892, 891, 891, 890, 889, 888, 887, 887, 886, + 885, 884, 884, 883, 882, 881, 880, 880, 879, 878, 877, 877, 876, 875, 874, 873, 873, 872, 871, + 870, 870, 869, 868, 867, 867, 866, 865, 864, 864, 863, 862, 861, 861, 860, 859, 858, 858, 857, + 856, 856, 855, 854, 853, 853, 852, 851, 850, 850, 849, 848, 848, 847, 846, 845, 845, 844, 843, + 843, 842, 841, 840, 840, 839, 838, 838, 837, 836, 835, 835, 834, 833, 833, 832, 831, 831, 830, + 829, 829, 828, 827, 826, 826, 825, 824, 824, 823, 822, 822, 821, 820, 820, 819, 818, 818, 817, + 816, 816, 815, 814, 814, 813, 812, 812, 811, 810, 810, 809, 808, 808, 807, 806, 806, 805, 805, + 804, 803, 803, 802, 801, 801, 800, 799, 799, 798, 797, 797, 796, 796, 795, 794, 794, 793, 792, + 792, 791, 790, 790, 789, 789, 788, 787, 787, 786, 786, 785, 784, 784, 783, 782, 782, 781, 781, + 780, 779, 779, 778, 778, 777, 776, 776, 775, 775, 774, 773, 773, 772, 772, 771, 770, 770, 769, + 769, 768, 767, 767, 766, 766, 765, 764, 764, 763, 763, 762, 762, 761, 760, 760, 759, 759, 758, + 758, 757, 756, 756, 755, 755, 754, 754, 753, 752, 752, 751, 751, 750, 750, 749, 748, 748, 747, + 747, 746, 746, 745, 745, 744, 743, 743, 742, 742, 741, 741, 740, 740, 739, 738, 738, 737, 737, + 736, 736, 735, 735, 734, 734, 733, 732, 732, 731, 731, 730, 730, 729, 729, 728, 728, 727, 727, + 726, 726, 725, 725, 724, 723, 723, 722, 722, 721, 721, 720, 720, 719, 719, 718, 718, 717, 717, + 716, 716, 715, 715, 714, 714, 713, 713, 712, 712, 711, 711, 710, 710, 709, 709, 708, 708, 707, + 707, 706, 705, 704, 703, 702, 701, 700, 699, 698, 697, 696, 695, 694, 693, 692, 691, 690, 689, + 688, 687, 686, 685, 684, 683, 682, 681, 681, 680, 679, 678, 677, 676, 675, 674, 673, 672, 671, + 671, 670, 669, 668, 667, 666, 665, 664, 663, 663, 662, 661, 660, 659, 658, 657, 656, 656, 655, + 654, 653, 652, 651, 650, 650, 649, 648, 647, 646, 645, 645, 644, 643, 642, 641, 640, 640, 639, + 638, 637, 636, 636, 635, 634, 633, 632, 631, 631, 630, 629, 628, 628, 627, 626, 625, 624, 624, + 623, 622, 621, 621, 620, 619, 618, 617, 617, 616, 615, 614, 614, 613, 612, 611, 611, 610, 609, + 608, 608, 607, 606, 605, 605, 604, 603, 603, 602, 601, 600, 600, 599, 598, 597, 597, 596, 595, + 595, 594, 593, 593, 592, 591, 590, 590, 589, 588, 588, 587, 586, 586, 585, 584, 584, 583, 582, + 581, 581, 580, 579, 579, 578, 577, 577, 576, 575, 575, 574, 573, 573, 572, 571, 571, 570, 570, + 569, 568, 568, 567, 566, 566, 565, 564, 564, 563, 562, 562, 561, 561, 560, 559, 559, 558, 557, + 557, 556, 556, 555, 554, 554, 553, 553, 552, 551, 551, 550, 549, 549, 548, 548, 547, 546, 546, + 545, 545, 544, 543, 543, 542, 542, 541, 541, 540, 539, 539, 538, 538, 537, 536, 536, 535, 535, + 534, 534, 533, 532, 532, 531, 531, 530, 530, 529, 529, 528, 527, 527, 526, 526, 525, 525, 524, + 524, 523, 522, 522, 521, 521, 520, 520, 519, 519, 518, 518, 517, 516, 516, 515, 515, 514, 514, + 513, 513, 512, 512, 511, 511, 510, 510, 509, 509, 508, 508, 507, 507, 506, 506, 505, 504, 504, + 503, 503, 502, 502, 501, 501, 500, 500, 499, 499, 498, 497, 496, 495, 494, 493, 492, 491, 490, + 489, 488, 487, 486, 485, 484, 483, 482, 481, 480, 480, 479, 478, 477, 476, 475, 474, 473, 472, + 471, 470, 470, 469, 468, 467, 466, 465, 464, 464, 463, 462, 461, 460, 459, 458, 458, 457, 456, + 455, 454, 453, 453, 452, 451, 450, 449, 449, 448, 447, 446, 445, 445, 444, 443, 442, 441, 441, + 440, 439, 438, 438, 437, 436, 435, 434, 434, 433, 432, 431, 431, 430, 429, 428, 428, 427, 426, + 426, 425, 424, 423, 423, 422, 421, 421, 420, 419, 418, 418, 417, 416, 416, 415, 414, 414, 413, + 412, 412, 411, 410, 410, 409, 408, 408, 407, 406, 406, 405, 404, 404, 403, 402, 402, 401, 400, + 400, 399, 398, 398, 397, 397, 396, 395, 395, 394, 393, 393, 392, 392, 391, 390, 390, 389, 388, + 388, 387, 387, 386, 385, 385, 384, 384, 383, 383, 382, 381, 381, 380, 380, 379, 378, 378, 377, + 377, 376, 376, 375, 374, 374, 373, 373, 372, 372, 371, 371, 370, 370, 369, 368, 368, 367, 367, + 366, 366, 365, 365, 364, 364, 363, 363, 362, 361, 361, 360, 360, 359, 359, 358, 358, 357, 357, + 356, 356, 355, 355, 354, 354, 353, 353, 352, 351, 350, 349, 348, 347, 346, 345, 344, 343, 342, + 341, 341, 340, 339, 338, 337, 336, 335, 334, 333, 332, 331, 331, 330, 329, 328, 327, 326, 325, + 325, 324, 323, 322, 321, 320, 320, 319, 318, 317, 316, 316, 315, 314, 313, 312, 312, 311, 310, + 309, 309, 308, 307, 306, 306, 305, 304, 303, 303, 302, 301, 300, 300, 299, 298, 297, 297, 296, + 295, 295, 294, 293, 293, 292, 291, 291, 290, 289, 289, 288, 287, 287, 286, 285, 285, 284, 283, + 283, 282, 281, 281, 280, 280, 279, 278, 278, 277, 276, 276, 275, 275, 274, 273, 273, 272, 272, + 271, 270, 270, 269, 269, 268, 268, 267, 266, 266, 265, 265, 264, 264, 263, 262, 262, 261, 261, + 260, 260, 259, 259, 258, 258, 257, 257, 256, 255, 255, 254, 254, 253, 253, 252, 252, 251, 251, + 250, 250, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, 240, 239, 238, 237, 236, 235, + 234, 233, 232, 232, 231, 230, 229, 228, 227, 226, 226, 225, 224, 223, 222, 222, 221, 220, 219, + 219, 218, 217, 216, 216, 215, 214, 213, 213, 212, 211, 210, 210, 209, 208, 208, 207, 206, 206, + 205, 204, 204, 203, 202, 202, 201, 200, 200, 199, 198, 198, 197, 197, 196, 195, 195, 194, 193, + 193, 192, 192, 191, 191, 190, 189, 189, 188, 188, 187, 187, 186, 185, 185, 184, 184, 183, 183, + 182, 182, 181, 181, 180, 180, 179, 179, 178, 178, 177, 177, 176, 176, 175, 174, 173, 172, 171, + 170, 169, 168, 167, 166, 166, 165, 164, 163, 162, 161, 160, 160, 159, 158, 157, 156, 156, 155, + 154, 153, 153, 152, 151, 150, 150, 149, 148, 148, 147, 146, 145, 145, 144, 143, 143, 142, 141, + 141, 140, 140, 139, 138, 138, 137, 137, 136, 135, 135, 134, 134, 133, 132, 132, 131, 131, 130, + 130, 129, 129, 128, 128, 127, 127, 126, 126, 125, 125, 124, 123, 122, 121, 120, 120, 119, 118, + 117, 116, 115, 114, 113, 113, 112, 111, 110, 109, 109, 108, 107, 106, 106, 105, 104, 104, 103, + 102, 102, 101, 100, 100, 99, 98, 98, 97, 97, 96, 95, 95, 94, 94, 93, 93, 92, 91, + 91, 90, 90, 89, 89, 88, 88, 87, 87, 86, 86, 85, 85, 85, 84, 84, 83, 83, 82, + 82, 81, 81, 81, 80, 80, 79, 79, 79, 78, 78, 77, 77, 77, 76, 76, 76, 75, 75, + 74, 74, 74, 73, 73, 73, 72, 72, 72, 71, 71, 71, 70, 70, 70, 69, 69, 69, 69, + 68, 68, 68, 67, 67, 67, 67, 66, 66, 66, 65, 65, 65, 65, 64, 64, 64, 64, 63, + 63, 63, 63, 62, 62, 62, 62, 61, 61}; const int etaShifts[4][5] = { {0, 3230, 1, 0, 0}, {3230, 9594, 2, 808, 0}, {9594, 23557, 4, 2608, 0}, {23557, 32768, -2, 0, 4081}}; diff --git a/L1Trigger/Phase2L1GMT/test/makeTrackConversionLUTs.py b/L1Trigger/Phase2L1GMT/test/makeTrackConversionLUTs.py index 50ce892d3cddc..8f7f2c1b17d47 100644 --- a/L1Trigger/Phase2L1GMT/test/makeTrackConversionLUTs.py +++ b/L1Trigger/Phase2L1GMT/test/makeTrackConversionLUTs.py @@ -14,15 +14,24 @@ from collections import defaultdict, Counter from pprint import pprint -BITSABSCURV=14 +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Constant for PT ~~~~~ +## Constant from L1 Track Trigger +#https://github.com/cms-sw/cmssw/blob/master/L1Trigger/TrackTrigger/python/ProducerSetup_cfi.py#L98 +Bfield = 3.81120228767395 # in T +SpeedOfLight = 2.99792458 # in e8 m/s +# https://github.com/cms-sw/cmssw/blob/master/DataFormats/L1TrackTrigger/interface/TTTrack_TrackWord.h#L87 +minRinv = 0.006 +BITSRinv = 15 +BITSABSRinv=14 BITSPT=13 -maxCurv = 0.00855 -ptLSB=0.025 +ptLSB=0.03125 ptLUT=[] pts = [] ptshifts = [] +stepRinv = (2. * abs(minRinv)) / (1 << BITSRinv) +drawPT = False - +## Constant for Eta BITSTTTANL=16-1 BITSETA=13-1 maxTanL=8.0 @@ -32,9 +41,11 @@ etashifts = [] def GetPtLUT(): - for i in range(1,(1<> i[2])+i[3], LUT[(inpt >> i[2])+i[3]] def ptChecks(shiftmap, LUT, bounderidx=False): - for i in range(1,(1< (1< (1< 0.025 ): - print("pt : ", i, pOB, pts[i-1], ptLUT[i-1], idx, pINT, int(pINT)*0.025) + if (abs(pOB - float(pINT)*ptLSB) > ptLSB ): + print("pt : ", i, pOB, pts[i-1], ptLUT[i-1], idx, pINT, int(pINT) *ptLSB) + + if drawPT is True: + import matplotlib.pyplot as plt + fig, (ax1, ax2) = plt.subplots(2, 1, layout='constrained') + ax1.plot(l_ptOBs, l_ptINTs, 'bo', label="Round up") + ax1.plot(l_ptOBs, l_lkpts, 'r+', label="Look up") + ax1.set_xscale('log') + ax1.legend() + ax1.set_xlabel("input pt") + ax1.set_ylabel("convert pt") + + diff = (np.array(l_ptINTs) - np.array(l_lkpts))/ptLSB + ax2.plot(l_ptOBs, diff, 'bo', label="Difference") + ax2.set_xscale('log') + ax2.legend() + ax2.set_xlabel("input pt") + ax2.set_ylabel("pt LSB") + ax2.set_ylim([-2.5, 2.5]) + plt.savefig("pt_check.png") def etaChecks(shiftmap, LUT, bounderidx=False): for i in range(0,(1<<(BITSTTTANL))): @@ -258,11 +294,17 @@ def PrintEtaLUT(k, etaLUT): print("int etaShifts[{nOps}][5]={{".format(nOps=len(k)) + ", ".join(shiftout) + "};") print("ap_uint etaLUT[{address}]={{".format(address=len(etaLUT)) +', '.join(etaLUT)+'};') + + + if __name__ == "__main__": bounderidx=True GetPtLUT() - k = GetLUTwrtLSB(pts, ptLSB, isPT=True, nbits=[ 1, 2, 3, 4, 5, 6, 7], lowerbound=2, upperbound=((1< 1: print("index is not continuous: ", con) @@ -270,7 +312,7 @@ def PrintEtaLUT(k, etaLUT): # print("Total size of LUT is %d" % len(y)) PrintPTLUT(k, y) - # # ### Eta + # ### Eta GetEtaLUT() k = GetLUTwrtLSB(etas, etaLSB, isPT=False, nbits=[0, 1, 2, 3, 5], upperbound =2.45) k, x, y = ProducedFinalLUT(etaLUT, k, bounderidx=bounderidx) From 7a079c2afc24aa32e0c213718c459a14b913c2ae Mon Sep 17 00:00:00 2001 From: Zhenbin Wu Date: Wed, 20 Mar 2024 19:08:27 -0500 Subject: [PATCH 04/17] Update to new EMTF function names --- DataFormats/L1TMuonPhase2/src/classes_def.xml | 17 ++--- L1Trigger/Phase2L1GMT/BuildFile.xml | 1 + .../plugins/Phase2L1TGMTFwdMuonTranslator.cc | 65 +++++++++++-------- 3 files changed, 48 insertions(+), 35 deletions(-) diff --git a/DataFormats/L1TMuonPhase2/src/classes_def.xml b/DataFormats/L1TMuonPhase2/src/classes_def.xml index 2678d4190e62f..ff91adc51ca31 100644 --- a/DataFormats/L1TMuonPhase2/src/classes_def.xml +++ b/DataFormats/L1TMuonPhase2/src/classes_def.xml @@ -24,15 +24,16 @@ - - - - - - - - + + + + + + + + + diff --git a/L1Trigger/Phase2L1GMT/BuildFile.xml b/L1Trigger/Phase2L1GMT/BuildFile.xml index 8d46e1a62eb96..8bab30271e844 100644 --- a/L1Trigger/Phase2L1GMT/BuildFile.xml +++ b/L1Trigger/Phase2L1GMT/BuildFile.xml @@ -4,6 +4,7 @@ + diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc index bfe78b7976fa4..4b492b90b2cf3 100644 --- a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc @@ -16,6 +16,8 @@ #include "FWCore/Utilities/interface/StreamID.h" #include "DataFormats/L1Trigger/interface/Muon.h" #include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" +#include "DataFormats/L1TMuonPhase2/interface/EMTFTrack.h" +#include "L1Trigger/L1TMuonEndCapPhase2/interface/Utils/TPUtils.h" // // class declaration @@ -37,6 +39,8 @@ class Phase2L1TGMTFwdMuonTranslator : public edm::stream::EDProducer<> { l1t::MuonStubRefVector selectLayerBX(const l1t::MuonStubRefVector& all, int bx, uint layer); void associateStubs(l1t::SAMuon&, const l1t::MuonStubRefVector&); + l1t::SAMuon ConvertEMTFTrack(const l1t::phase2::EMTFTrack& track, const int bx_); + // ----------member data --------------------------- edm::EDGetTokenT stubToken_; edm::EDGetTokenT omtfTrackToken_; @@ -54,26 +58,16 @@ class Phase2L1TGMTFwdMuonTranslator : public edm::stream::EDProducer<> { // constructors and destructor // Phase2L1TGMTFwdMuonTranslator::Phase2L1TGMTFwdMuonTranslator(const edm::ParameterSet& iConfig) -<<<<<<< HEAD - : muonToken_(consumes(iConfig.getParameter("muons"))), - stubToken_(consumes(iConfig.getParameter("stubs"))) { -======= : stubToken_(consumes(iConfig.getParameter("stubs"))), omtfTrackToken_(consumes(iConfig.getParameter("omtfTracks"))), emtfTrackToken_(consumes(iConfig.getParameter("emtfTracks"))) { ->>>>>>> d34010dded1 (Add Phase-2 OMTF and EMTF to GMT SA) produces >("prompt").setBranchAlias("prompt"); + produces >("displaced").setBranchAlias("displaced"); } // ------------ method called to produce the data ------------ void Phase2L1TGMTFwdMuonTranslator::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { using namespace edm; -<<<<<<< HEAD - edm::Handle muon; - iEvent.getByToken(muonToken_, muon); - edm::Handle stubHandle; - iEvent.getByToken(stubToken_, stubHandle); -======= edm::Handle stubHandle; iEvent.getByToken(stubToken_, stubHandle); @@ -85,28 +79,21 @@ void Phase2L1TGMTFwdMuonTranslator::produce(edm::Event& iEvent, const edm::Event iEvent.getByToken(omtfTrackToken_, omtf_tracks); // Process Stubs ->>>>>>> d34010dded1 (Add Phase-2 OMTF and EMTF to GMT SA) l1t::MuonStubRefVector stubs; + for (uint i = 0; i < stubHandle->size(); ++i) { l1t::MuonStubRef stub(stubHandle, i); + if (stub->bxNum() == 0) stubs.push_back(stub); } + // Collect Muons std::vector prompt; // TODO: Will receive hybrid stubs from OMTF/EMTF - // std::vector hybridStubs; - // edm::RefProd stubRefProd = iEvent.getRefBeforePut >("hybridStubs"); - // l1t::MuonStubRef::key_type idxStub =0; - -<<<<<<< HEAD - for (unsigned int i = 0; i < muon->size(0); ++i) { - const l1t::Muon& mu = muon->at(0, i); - l1t::SAMuon samuon = Convertl1tMuon(mu, 0); - if (samuon.tfType() == l1t::tftype::bmtf) - continue; -======= + std::vector displaced; + // Convert OMTF Muons to SAMuons for (unsigned int i = 0; i < omtf_tracks->size(0); ++i) { const l1t::RegionalMuonCand& mu = omtf_tracks->at(0, i); @@ -118,7 +105,6 @@ void Phase2L1TGMTFwdMuonTranslator::produce(edm::Event& iEvent, const edm::Event else if (mu.hwPtUnconstrained() > 0) //Assume exculsive, need double check samuon = Convertl1tMuon(mu, 0, true); ->>>>>>> d34010dded1 (Add Phase-2 OMTF and EMTF to GMT SA) //now associate the stubs associateStubs(samuon, stubs); @@ -128,8 +114,33 @@ void Phase2L1TGMTFwdMuonTranslator::produce(edm::Event& iEvent, const edm::Event else if (mu.hwPtUnconstrained() > 0) displaced.push_back(samuon); } + + // Convert EMTF++ Tracks to SAMuons + for (unsigned int track_id = 0; track_id < emtf_tracks->size(); ++track_id) { + const auto& track = emtf_tracks->at(track_id); + + if (track.valid() == 0) { + continue; + } + + auto samuon = ConvertEMTFTrack(track, 0); + + //now associate the stubs + associateStubs(samuon, stubs); + + // Add To Collections + if (track.unconstrained()) { + displaced.push_back(samuon); + } else { + prompt.push_back(samuon); + } + } + + // Output Prompt Muon Collection std::unique_ptr > prompt_ptr = std::make_unique >(prompt); + std::unique_ptr > displaced_ptr = std::make_unique >(displaced); iEvent.put(std::move(prompt_ptr), "prompt"); + iEvent.put(std::move(displaced_ptr), "displaced"); } // === FUNCTION ============================================================ @@ -218,9 +229,9 @@ void Phase2L1TGMTFwdMuonTranslator::associateStubs(l1t::SAMuon& mu, const l1t::M SAMuon Phase2L1TGMTFwdMuonTranslator::ConvertEMTFTrack(const l1t::phase2::EMTFTrack& track, const int bx_) { // Convert EMTF Phi and Theta to Global Phi and Eta - float track_phi = emtf::phase2::tp::calc_phi_glob_rad_from_loc( - track.sector(), emtf::phase2::tp::calc_phi_loc_deg_from_int(track.modelPhi())); - float track_theta = emtf::phase2::tp::calc_theta_rad_from_int(track.modelEta()); + float track_phi = emtf::phase2::tp::calcPhiGlobRadFromLoc(track.sector(), + emtf::phase2::tp::calcPhiLocDegFromInt(track.modelPhi())); + float track_theta = emtf::phase2::tp::calcThetaRadFromInt(track.modelEta()); float track_eta = -1 * std::log(std::tan(track_theta / 2)); track_theta *= track.endcap(); From 0899da42b9ae064dc457a5076caaca6beee5e18f Mon Sep 17 00:00:00 2001 From: Zhenbin Wu Date: Wed, 20 Mar 2024 20:30:58 -0500 Subject: [PATCH 05/17] Add back code-format --- .../Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc index 4b492b90b2cf3..46fbadc15806c 100644 --- a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc @@ -229,8 +229,8 @@ void Phase2L1TGMTFwdMuonTranslator::associateStubs(l1t::SAMuon& mu, const l1t::M SAMuon Phase2L1TGMTFwdMuonTranslator::ConvertEMTFTrack(const l1t::phase2::EMTFTrack& track, const int bx_) { // Convert EMTF Phi and Theta to Global Phi and Eta - float track_phi = emtf::phase2::tp::calcPhiGlobRadFromLoc(track.sector(), - emtf::phase2::tp::calcPhiLocDegFromInt(track.modelPhi())); + float track_phi = + emtf::phase2::tp::calcPhiGlobRadFromLoc(track.sector(), emtf::phase2::tp::calcPhiLocDegFromInt(track.modelPhi())); float track_theta = emtf::phase2::tp::calcThetaRadFromInt(track.modelEta()); float track_eta = -1 * std::log(std::tan(track_theta / 2)); From 8f379e8edf16a3674be84e704354f7e7a1797e73 Mon Sep 17 00:00:00 2001 From: Michail Bachtis Date: Thu, 21 Mar 2024 19:02:58 -0500 Subject: [PATCH 06/17] correlator inputs and bug fixes in words --- .../plugins/Phase2L1TGMTFwdMuonTranslator.cc | 18 +++++++++--------- .../python/l1ctLayer1_cff.py | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc index 46fbadc15806c..f0b92183ec087 100644 --- a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc @@ -171,13 +171,13 @@ SAMuon Phase2L1TGMTFwdMuonTranslator::Convertl1tMuon(const l1t::RegionalMuonCand int bstart = 0; wordtype word(0); bstart = wordconcat(word, bstart, 1, 1); - bstart = wordconcat(word, bstart, pt, BITSGTPT); - bstart = wordconcat(word, bstart, phi, BITSGTPHI); - bstart = wordconcat(word, bstart, eta, BITSGTETA); - bstart = wordconcat(word, bstart, z0, BITSSAZ0); - bstart = wordconcat(word, bstart, d0, BITSSAD0); bstart = wordconcat(word, bstart, charge, 1); - bstart = wordconcat(word, bstart, qual, BITSSAQUAL); + bstart = wordconcat(word, bstart, pt, BITSPT); + bstart = wordconcat(word, bstart, phi, BITSPHI); + bstart = wordconcat(word, bstart, eta, BITSETA); + // bstart = wordconcat(word, bstart, z0, BITSSAZ0); NOT YET SUPPORTED BY GMT + bstart = wordconcat(word, bstart, d0, BITSSAD0); + bstart = wordconcat(word, bstart, qual, 8); //FOR NOW 8 bits to be efficienct with Ghost busting. THIS IS ***NOT*** THE FINAL QUALITY // Calculate Lorentz Vector math::PtEtaPhiMLorentzVector p4(pt * LSBpt, eta * LSBeta, phi * LSBphi, 0.0); @@ -254,13 +254,13 @@ SAMuon Phase2L1TGMTFwdMuonTranslator::ConvertEMTFTrack(const l1t::phase2::EMTFTr int bstart = 0; wordtype word(0); bstart = wordconcat(word, bstart, 1, 1); + bstart = wordconcat(word, bstart, charge, 1); bstart = wordconcat(word, bstart, pt, BITSPT); bstart = wordconcat(word, bstart, phi, BITSPHI); bstart = wordconcat(word, bstart, eta, BITSETA); - bstart = wordconcat(word, bstart, z0, BITSSAZ0); + // bstart = wordconcat(word, bstart, z0, BITSSAZ0); NOT YET SUPPORTED BY GMT bstart = wordconcat(word, bstart, d0, BITSSAD0); - bstart = wordconcat(word, bstart, charge, 1); - bstart = wordconcat(word, bstart, qual, BITSSAQUAL); + bstart = wordconcat(word, bstart, qual, 8);//FOR NOW 8 bits to be efficienct with Ghost busting. THIS IS ***NOT*** THE FINAL QUALITY SAMuon samuon(p4, charge, pt.to_uint(), eta.to_int(), phi.to_int(), z0.to_int(), d0.to_int(), qual.to_uint()); diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py index d49040e905a6f..4f1895ebd6a59 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py @@ -11,7 +11,7 @@ l1tLayer1Barrel = cms.EDProducer("L1TCorrelatorLayer1Producer", tracks = cms.InputTag('l1tPFTracksFromL1Tracks'), - muons = cms.InputTag('l1tSAMuonsGmt','promptSAMuons'), + muons = cms.InputTag('l1tSAMuonsGmt','prompt'), emClusters = cms.VInputTag(cms.InputTag('l1tPFClustersFromL1EGClusters:selected')), hadClusters = cms.VInputTag(cms.InputTag('l1tPFClustersFromCombinedCaloHCal:calibrated')), vtxCollection = cms.InputTag("l1tVertexFinderEmulator","L1VerticesEmulation"), @@ -132,7 +132,7 @@ l1tLayer1HGCal = cms.EDProducer("L1TCorrelatorLayer1Producer", tracks = cms.InputTag('l1tPFTracksFromL1Tracks'), - muons = cms.InputTag('l1tSAMuonsGmt','promptSAMuons'), + muons = cms.InputTag('l1tSAMuonsGmt','prompt'), emClusters = cms.VInputTag(cms.InputTag('l1tPFClustersFromHGC3DClusters:egamma')), # used only for E/gamma hadClusters = cms.VInputTag(cms.InputTag('l1tPFClustersFromHGC3DClusters')), vtxCollection = cms.InputTag("l1tVertexFinderEmulator","L1VerticesEmulation"), @@ -268,7 +268,7 @@ ) l1tLayer1HGCalNoTK = cms.EDProducer("L1TCorrelatorLayer1Producer", - muons = cms.InputTag('l1tSAMuonsGmt','promptSAMuons'), + muons = cms.InputTag('l1tSAMuonsGmt','prompt'), emClusters = cms.VInputTag(cms.InputTag('l1tPFClustersFromHGC3DClusters:egamma')), # used only for E/gamma hadClusters = cms.VInputTag(cms.InputTag('l1tPFClustersFromHGC3DClusters')), vtxCollection = cms.InputTag("l1tVertexFinderEmulator","L1VerticesEmulation"), @@ -360,7 +360,7 @@ ) l1tLayer1HF = cms.EDProducer("L1TCorrelatorLayer1Producer", - muons = cms.InputTag('l1tSAMuonsGmt','promptSAMuons'), + muons = cms.InputTag('l1tSAMuonsGmt','prompt'), hadClusters = cms.VInputTag(cms.InputTag('l1tPFClustersFromCombinedCaloHF:calibrated')), vtxCollection = cms.InputTag("l1tVertexFinderEmulator","L1VerticesEmulation"), nVtx = cms.int32(1), From 5924afffab0edc776e43181159b2493a46b2073b Mon Sep 17 00:00:00 2001 From: Zhenbin Wu Date: Thu, 21 Mar 2024 19:42:11 -0500 Subject: [PATCH 07/17] Update code-format --- .../Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc index f0b92183ec087..6dbde24afb612 100644 --- a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc @@ -177,7 +177,8 @@ SAMuon Phase2L1TGMTFwdMuonTranslator::Convertl1tMuon(const l1t::RegionalMuonCand bstart = wordconcat(word, bstart, eta, BITSETA); // bstart = wordconcat(word, bstart, z0, BITSSAZ0); NOT YET SUPPORTED BY GMT bstart = wordconcat(word, bstart, d0, BITSSAD0); - bstart = wordconcat(word, bstart, qual, 8); //FOR NOW 8 bits to be efficienct with Ghost busting. THIS IS ***NOT*** THE FINAL QUALITY + bstart = wordconcat( + word, bstart, qual, 8); //FOR NOW 8 bits to be efficienct with Ghost busting. THIS IS ***NOT*** THE FINAL QUALITY // Calculate Lorentz Vector math::PtEtaPhiMLorentzVector p4(pt * LSBpt, eta * LSBeta, phi * LSBphi, 0.0); @@ -260,7 +261,8 @@ SAMuon Phase2L1TGMTFwdMuonTranslator::ConvertEMTFTrack(const l1t::phase2::EMTFTr bstart = wordconcat(word, bstart, eta, BITSETA); // bstart = wordconcat(word, bstart, z0, BITSSAZ0); NOT YET SUPPORTED BY GMT bstart = wordconcat(word, bstart, d0, BITSSAD0); - bstart = wordconcat(word, bstart, qual, 8);//FOR NOW 8 bits to be efficienct with Ghost busting. THIS IS ***NOT*** THE FINAL QUALITY + bstart = wordconcat( + word, bstart, qual, 8); //FOR NOW 8 bits to be efficienct with Ghost busting. THIS IS ***NOT*** THE FINAL QUALITY SAMuon samuon(p4, charge, pt.to_uint(), eta.to_int(), phi.to_int(), z0.to_int(), d0.to_int(), qual.to_uint()); From 54e95fbae5fcc797844552f96a2572c6722551ea Mon Sep 17 00:00:00 2001 From: Andrew Loeliger Date: Tue, 2 Apr 2024 13:53:04 -0500 Subject: [PATCH 08/17] Update prompt and displaced muon names to reflect GMT changes --- L1Trigger/Phase2L1GT/python/l1tGTProducer_cff.py | 6 +++--- .../plugins/L1TCorrelatorLayer1Producer.cc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/L1Trigger/Phase2L1GT/python/l1tGTProducer_cff.py b/L1Trigger/Phase2L1GT/python/l1tGTProducer_cff.py index 26242b1495839..45f332b07cac5 100644 --- a/L1Trigger/Phase2L1GT/python/l1tGTProducer_cff.py +++ b/L1Trigger/Phase2L1GT/python/l1tGTProducer_cff.py @@ -7,9 +7,9 @@ GTTPromptJets = cms.InputTag("l1tTrackJetsEmulation", "L1TrackJets"), GTTDisplacedJets = cms.InputTag("l1tTrackJetsExtendedEmulation", "L1TrackJetsExtended"), GTTPrimaryVert = cms.InputTag("l1tVertexFinderEmulator", "L1VerticesEmulation"), - GMTSaPromptMuons = cms.InputTag("l1tSAMuonsGmt", "promptSAMuons"), - GMTSaDisplacedMuons = cms.InputTag("l1tSAMuonsGmt", "displacedSAMuons"), - GMTTkMuons = cms.InputTag("l1tTkMuonsGmtLowPtFix", "l1tTkMuonsGmtLowPtFix"), + GMTSaPromptMuons = cms.InputTag("l1tSAMuonsGmt", "prompt"), + GMTSaDisplacedMuons = cms.InputTag("l1tSAMuonsGmt", "displaced"), + GMTTkMuons = cms.InputTag("l1tTkMuonsGmt"), CL2Jets = cms.InputTag("l1tSC4PFL1PuppiCorrectedEmulator"), CL2Electrons = cms.InputTag("l1tLayer2EG", "L1CtTkElectron"), CL2Photons = cms.InputTag("l1tLayer2EG", "L1CtTkEm"), diff --git a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc index 38e8222dab630..c801ffd14444b 100644 --- a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc +++ b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc @@ -346,7 +346,7 @@ void L1TCorrelatorLayer1Producer::fillDescriptions(edm::ConfigurationDescription edm::ParameterSetDescription desc; // Inputs and cuts desc.add("tracks", edm::InputTag("")); - desc.add("muons", edm::InputTag("l1tSAMuonsGmt", "promptSAMuons")); + desc.add("muons", edm::InputTag("l1tSAMuonsGmt", "prompt")); desc.add>("emClusters", std::vector()); desc.add>("hadClusters", std::vector()); desc.add("vtxCollection", edm::InputTag("l1tVertexFinderEmulator", "L1VerticesEmulation")); From 77af8b7bb965b33a99bfd2962a1bf55bfd1bdaf9 Mon Sep 17 00:00:00 2001 From: Zhenbin Wu Date: Wed, 20 Mar 2024 18:34:54 -0500 Subject: [PATCH 09/17] Cherry-pick all the fixes of GMT emulator for AR Update PTLUT corresponding to minRinv 0.006 from L1Track correlator inputs and bug fixes in words Update code-format Clean EMTF track Update prompt and displaced muon names to reflect GMT changes Added EMTF-GMT quality Added EMTF Quality to Phase2L1TGMTFwdMuonTranslator Ran code-format Moved emtf quality cut before EMTF track conversion Fixing the x3 missing in multiple scattering LUTs --- .../L1TMuonPhase2/interface/EMTFTrack.h | 3 + DataFormats/L1TMuonPhase2/src/classes_def.xml | 3 +- .../interface/Algo/OutputLayer.h | 2 + .../src/Algo/OutputLayer.cc | 83 +++++++++ L1Trigger/Phase2L1GMT/interface/TPSLUTs.h | 165 ++---------------- .../plugins/Phase2L1TGMTFwdMuonTranslator.cc | 19 +- L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc | 4 +- 7 files changed, 121 insertions(+), 158 deletions(-) diff --git a/DataFormats/L1TMuonPhase2/interface/EMTFTrack.h b/DataFormats/L1TMuonPhase2/interface/EMTFTrack.h index 76ee00fc82324..5608d98cf6c18 100644 --- a/DataFormats/L1TMuonPhase2/interface/EMTFTrack.h +++ b/DataFormats/L1TMuonPhase2/interface/EMTFTrack.h @@ -41,6 +41,7 @@ namespace l1t::phase2 { void setEmtfBeta(int32_t aEmtfBeta) { emtf_beta_ = aEmtfBeta; } void setEmtfModeV1(int16_t aEmtfModeV1) { emtf_mode_v1_ = aEmtfModeV1; } void setEmtfModeV2(int16_t aEmtfModeV2) { emtf_mode_v2_ = aEmtfModeV2; } + void setEmtfQuality(int16_t aEmtfQuality) { emtf_quality_ = aEmtfQuality; } void setSiteHits(const site_hits_t& aSiteHits) { site_hits_ = aSiteHits; } void setSiteSegs(const site_segs_t& aSiteSegs) { site_segs_ = aSiteSegs; } @@ -71,6 +72,7 @@ namespace l1t::phase2 { int32_t emtfBeta() const { return emtf_beta_; } int16_t emtfModeV1() const { return emtf_mode_v1_; } int16_t emtfModeV2() const { return emtf_mode_v2_; } + int16_t emtfQuality() const { return emtf_quality_; } const site_hits_t& siteHits() const { return site_hits_; } const site_segs_t& siteSegs() const { return site_segs_; } @@ -101,6 +103,7 @@ namespace l1t::phase2 { int32_t emtf_beta_; int16_t emtf_mode_v1_; int16_t emtf_mode_v2_; + int16_t emtf_quality_; site_hits_t site_hits_; site_segs_t site_segs_; diff --git a/DataFormats/L1TMuonPhase2/src/classes_def.xml b/DataFormats/L1TMuonPhase2/src/classes_def.xml index ff91adc51ca31..3af19882e9fc8 100644 --- a/DataFormats/L1TMuonPhase2/src/classes_def.xml +++ b/DataFormats/L1TMuonPhase2/src/classes_def.xml @@ -40,8 +40,9 @@ - + + diff --git a/L1Trigger/L1TMuonEndCapPhase2/interface/Algo/OutputLayer.h b/L1Trigger/L1TMuonEndCapPhase2/interface/Algo/OutputLayer.h index 41a025eac31eb..d11f727e6c4e2 100644 --- a/L1Trigger/L1TMuonEndCapPhase2/interface/Algo/OutputLayer.h +++ b/L1Trigger/L1TMuonEndCapPhase2/interface/Algo/OutputLayer.h @@ -34,6 +34,8 @@ namespace emtf::phase2::algo { int findEMTFModeV1(const track_t::site_mask_t&) const; int findEMTFModeV2(const track_t::site_mask_t&) const; + + int findEMTFQuality(const track_t&, const int&, const int&) const; }; } // namespace emtf::phase2::algo diff --git a/L1Trigger/L1TMuonEndCapPhase2/src/Algo/OutputLayer.cc b/L1Trigger/L1TMuonEndCapPhase2/src/Algo/OutputLayer.cc index 552ab14f9e3ec..61b128733a380 100644 --- a/L1Trigger/L1TMuonEndCapPhase2/src/Algo/OutputLayer.cc +++ b/L1Trigger/L1TMuonEndCapPhase2/src/Algo/OutputLayer.cc @@ -69,6 +69,7 @@ void OutputLayer::apply(const int& endcap, // Find EMTF/GMT variables const int emtf_mode_v1 = findEMTFModeV1(track.site_mask); const int emtf_mode_v2 = findEMTFModeV2(track.site_mask); + const int emtf_quality = findEMTFQuality(track, emtf_mode_v1, emtf_mode_v2); // Init Parameters auto& out_trk = out_tracks.emplace_back(); @@ -96,6 +97,7 @@ void OutputLayer::apply(const int& endcap, out_trk.setEmtfBeta(0); // not yet implemented out_trk.setEmtfModeV1(emtf_mode_v1); out_trk.setEmtfModeV2(emtf_mode_v2); + out_trk.setEmtfQuality(emtf_quality); out_trk.setSiteHits(site_hits); out_trk.setSiteSegs(site_segs); @@ -221,3 +223,84 @@ int OutputLayer::findEMTFModeV2(const track_t::site_mask_t& x) const { return mode; } + +int OutputLayer::findEMTFQuality(const track_t& track, const int& mode_v1, const int& mode_v2) const { + // Short-Circuit: Invalid track + if (track.valid == 0) { + return 0; + } + + // Short-Circuit: Single Station + bool is_single_station = (mode_v1 == 0); + is_single_station |= (mode_v1 == 1); + is_single_station |= (mode_v1 == 2); + is_single_station |= (mode_v1 == 4); + is_single_station |= (mode_v1 == 8); + + if (is_single_station) { + return 0; + } + + // Calculate Quality Based on ModeV2 + if (mode_v2 == 0) { + // Single Hit + if ((0 <= track.quality) && (track.quality <= 3)) { + return 1; + } else if ((4 <= track.quality) && (track.quality <= 7)) { + return 2; + } else if (7 < track.quality) { + return 3; + } + + return 0; + } else if (mode_v2 == 4) { + // Triple Muon Quality + if ((8 <= track.quality) && (track.quality <= 11)) { + return 5; + } else if ((12 <= track.quality) && (track.quality <= 15)) { + return 6; + } else if (15 < track.quality) { + return 7; + } + + return 4; + } else if (mode_v2 == 8) { + // Double Muon Quality + bool valid_mode = (mode_v1 == 9); + valid_mode |= (mode_v1 == 10); + valid_mode |= (mode_v1 == 12); + + if (valid_mode) { + if ((16 <= track.quality) && (track.quality <= 23)) { + return 9; + } else if ((24 <= track.quality) && (track.quality <= 31)) { + return 10; + } else if (31 < track.quality) { + return 11; + } + } + + return 8; + } else if (mode_v2 == 12) { + // Single Muon Quality + bool valid_mode = (mode_v1 == 11); + valid_mode |= (mode_v1 == 13); + valid_mode |= (mode_v1 == 14); + valid_mode |= (mode_v1 == 15); + + if (valid_mode) { + if ((32 <= track.quality) && (track.quality <= 39)) { + return 13; + } else if ((40 <= track.quality) && (track.quality <= 51)) { + return 14; + } else if (51 < track.quality) { + return 15; + } + } + + return 12; + } + + // Invalid track + return 0; +} diff --git a/L1Trigger/Phase2L1GMT/interface/TPSLUTs.h b/L1Trigger/Phase2L1GMT/interface/TPSLUTs.h index 5463f039df9f6..ef15026f907d9 100644 --- a/L1Trigger/Phase2L1GMT/interface/TPSLUTs.h +++ b/L1Trigger/Phase2L1GMT/interface/TPSLUTs.h @@ -793,157 +793,20 @@ namespace Phase2L1GMT { 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19}; - const ap_uint lt_res1_coord1_0[512] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - const ap_uint lt_res1_coord1_1[512] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; - const ap_uint lt_res1_coord1_2[512] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; - const ap_uint lt_res1_coord1_3[512] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; - const ap_uint lt_res1_coord1_4[512] = { - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - const ap_uint lt_res1_coord2_0[512] = { - 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, - 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, - 5, 5, 5, 5, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; - const ap_uint lt_res1_coord2_1[512] = { - 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; - const ap_uint lt_res1_coord2_2[512] = { - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, - 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - const ap_uint lt_res1_coord2_3[512] = { - 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, - 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; - const ap_uint lt_res1_coord2_4[512] = { - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + + +const ap_uint lt_res1_coord1_0[512] = {7,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}; +const ap_uint lt_res1_coord1_1[512] = {7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,9,9,9,9,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; +const ap_uint lt_res1_coord1_2[512] = {7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,9,9,9,9,9,9,8,8,8,8,8,8,8,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; +const ap_uint lt_res1_coord1_3[512] = {7,7,8,8,8,8,8,8,8,9,9,9,9,9,9,10,10,10,10,10,10,11,11,11,11,11,11,12,12,12,12,12,12,13,13,13,13,13,13,14,14,14,14,14,14,15,15,15,15,15,14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,10,10,10,10,10,10,10,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10}; +const ap_uint lt_res1_coord1_4[512] = {12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,13,13,13,13,13,13,13,12,12,12,12,12,11,11,11,11,11,11,10,10,10,10,10,10,9,9,9,9,9,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5}; +const ap_uint lt_res1_coord2_0[512] = {7,7,8,8,9,9,10,10,11,11,12,12,13,13,13,14,14,15,15,16,16,17,17,18,18,18,19,19,20,20,21,21,22,22,23,23,24,24,24,25,25,26,26,27,27,28,28,28,28,28,28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,23,23,23,22,22,22,22,21,21,21,20,20,20,20,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,18,18,18,18,18,18,18,18,18,18,18,17,17,17,17,16,16,16,16,15,15,15,15,14,14,14,14,14,13,13,13,13,12,12,12,12,11,11,11,11,11,11,11,12,12,13,13,13,14,14,15,15,16,16,17,17,18,18,18,19,19,20,20,21,21,22,22,22,23,23,24,24,24,24,23,22,22,21,20,19,18,18,17,16,15,15,14,13,12,11,11,10,9,8,7,7,6,5,4,3,3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6}; +const ap_uint lt_res1_coord2_1[512] = {18,18,18,18,18,18,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,15,15,15,15,15,15,14,14,14,14,14,13,13,13,13,13,12,12,12,12,12,11,11,11,11,11,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,14,15,15,15,15,16,16,16,16,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16,15,15,15,15,15,15,15,14,14,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9}; +const ap_uint lt_res1_coord2_2[512] = {21,21,21,21,21,21,21,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,27,27,27,27,26,26,26,26,26,26,25,25,25,25,25,24,24,24,24,24,24,23,23,23,23,23,22,22,22,22,22,22,21,21,21,22,22,22,22,22,22,22,23,23,23,23,23,23,23,24,24,24,24,24,24,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,27,27,27,26,26,25,25,24,24,23,23,22,22,21,21,20,20,19,19,19,18,18,17,17,16,16,15,15,14,14,13,13,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4}; +const ap_uint lt_res1_coord2_3[512] = {26,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,30,30,30,30,29,29,29,28,28,28,27,27,26,26,26,25,25,25,24,24,23,23,23,22,22,22,21,21,21,20,20,19,19,19,18,18,18,19,19,20,20,20,21,21,22,22,22,23,23,24,24,24,25,25,26,26,26,27,27,28,28,28,29,29,29,30,30,30,30,30,30,29,29,29,28,28,28,27,27,27,26,26,26,25,25,25,24,24,24,23,23,23,22,22,22,21,21,21,20,20,20,20,20,19,19,19,19,19,19,19,19,19,18,18,18,18,18,18,18,18,18,17,17,17,17,17,17,17,17,17,16,16,16,16,16,16,16,16,15,15,15,15,15,15,15,15,15,14,14,14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9}; + const ap_uint lt_res1_coord2_4[512] = {12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,10,10,10,10,10,10,10,9,9,9,9,9,9,9,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4}; + + const ap_uint lt_res0_eta1_0[512] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc index 6dbde24afb612..52aabb1183131 100644 --- a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc @@ -119,7 +119,18 @@ void Phase2L1TGMTFwdMuonTranslator::produce(edm::Event& iEvent, const edm::Event for (unsigned int track_id = 0; track_id < emtf_tracks->size(); ++track_id) { const auto& track = emtf_tracks->at(track_id); - if (track.valid() == 0) { + // Short-Circuit: Only keep valid tracks that are in BX=0 + if ((track.valid() == 0) || (track.bx() != 0)) { + continue; + } + + // Short-Circuit: Only keep tracks with quality above 3 to avoid single hit tracks + if (track.emtfQuality() <= 3) { + continue; + } + + // Short-Circuit: Only keep tracks with the max relevance score (127) + if (track.emtfRels() != 127) { continue; } @@ -243,9 +254,9 @@ SAMuon Phase2L1TGMTFwdMuonTranslator::ConvertEMTFTrack(const l1t::phase2::EMTFTr math::PtEtaPhiMLorentzVector p4(track.emtfPt() * LSBpt, track_eta, track_phi, 0.0); // Quantize Values - ap_uint qual = track.emtfModeV2(); // Not sure how this should be handled; using mode for now - int charge = track.emtfQ(); // EMTF uses the same convention - ap_uint pt = track.emtfPt(); // Quantized by EMTF in the same units + ap_uint qual = track.emtfQuality(); // Quality provided by EMTF to GMT + int charge = track.emtfQ(); // EMTF uses the same convention + ap_uint pt = track.emtfPt(); // Quantized by EMTF in the same units ap_int phi = round(track_phi / LSBphi); ap_int eta = round(track_eta / LSBeta); ap_int z0 = track.emtfZ0(); // Quantized by EMTF in the same units diff --git a/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc b/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc index 95a7503b22c0c..640b560c47808 100644 --- a/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc +++ b/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc @@ -217,8 +217,8 @@ propagation_t TPSAlgorithm::propagate(const ConvertedTTTrack& track, uint layer) absK = ap_uint(track.curvature()); //bound the resolution propagation - if (absK > 4095) - absK = 4095; + if (absK > 6000) + absK = 6000; ap_uint s1kFull = res1_coord1 * absK; ap_uint s1k = s1kFull / 1024; From b80d7c3366d30e3c235d9d08fcd8265c198f6de2 Mon Sep 17 00:00:00 2001 From: Zhenbin Wu Date: Fri, 12 Apr 2024 16:26:42 -0500 Subject: [PATCH 10/17] Code-format of TPSLUT --- L1Trigger/Phase2L1GMT/interface/TPSLUTs.h | 209 ++++++++++++++++++++-- 1 file changed, 195 insertions(+), 14 deletions(-) diff --git a/L1Trigger/Phase2L1GMT/interface/TPSLUTs.h b/L1Trigger/Phase2L1GMT/interface/TPSLUTs.h index ef15026f907d9..4c21a0e0c5d73 100644 --- a/L1Trigger/Phase2L1GMT/interface/TPSLUTs.h +++ b/L1Trigger/Phase2L1GMT/interface/TPSLUTs.h @@ -793,20 +793,201 @@ namespace Phase2L1GMT { 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19}; - - -const ap_uint lt_res1_coord1_0[512] = {7,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}; -const ap_uint lt_res1_coord1_1[512] = {7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,9,9,9,9,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; -const ap_uint lt_res1_coord1_2[512] = {7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,9,9,9,9,9,9,8,8,8,8,8,8,8,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; -const ap_uint lt_res1_coord1_3[512] = {7,7,8,8,8,8,8,8,8,9,9,9,9,9,9,10,10,10,10,10,10,11,11,11,11,11,11,12,12,12,12,12,12,13,13,13,13,13,13,14,14,14,14,14,14,15,15,15,15,15,14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,10,10,10,10,10,10,10,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10}; -const ap_uint lt_res1_coord1_4[512] = {12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,13,13,13,13,13,13,13,12,12,12,12,12,11,11,11,11,11,11,10,10,10,10,10,10,9,9,9,9,9,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5}; -const ap_uint lt_res1_coord2_0[512] = {7,7,8,8,9,9,10,10,11,11,12,12,13,13,13,14,14,15,15,16,16,17,17,18,18,18,19,19,20,20,21,21,22,22,23,23,24,24,24,25,25,26,26,27,27,28,28,28,28,28,28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,23,23,23,22,22,22,22,21,21,21,20,20,20,20,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,18,18,18,18,18,18,18,18,18,18,18,17,17,17,17,16,16,16,16,15,15,15,15,14,14,14,14,14,13,13,13,13,12,12,12,12,11,11,11,11,11,11,11,12,12,13,13,13,14,14,15,15,16,16,17,17,18,18,18,19,19,20,20,21,21,22,22,22,23,23,24,24,24,24,23,22,22,21,20,19,18,18,17,16,15,15,14,13,12,11,11,10,9,8,7,7,6,5,4,3,3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6}; -const ap_uint lt_res1_coord2_1[512] = {18,18,18,18,18,18,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,15,15,15,15,15,15,14,14,14,14,14,13,13,13,13,13,12,12,12,12,12,11,11,11,11,11,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,14,15,15,15,15,16,16,16,16,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16,15,15,15,15,15,15,15,14,14,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9}; -const ap_uint lt_res1_coord2_2[512] = {21,21,21,21,21,21,21,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,27,27,27,27,26,26,26,26,26,26,25,25,25,25,25,24,24,24,24,24,24,23,23,23,23,23,22,22,22,22,22,22,21,21,21,22,22,22,22,22,22,22,23,23,23,23,23,23,23,24,24,24,24,24,24,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,27,27,27,26,26,25,25,24,24,23,23,22,22,21,21,20,20,19,19,19,18,18,17,17,16,16,15,15,14,14,13,13,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4}; -const ap_uint lt_res1_coord2_3[512] = {26,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,30,30,30,30,29,29,29,28,28,28,27,27,26,26,26,25,25,25,24,24,23,23,23,22,22,22,21,21,21,20,20,19,19,19,18,18,18,19,19,20,20,20,21,21,22,22,22,23,23,24,24,24,25,25,26,26,26,27,27,28,28,28,29,29,29,30,30,30,30,30,30,29,29,29,28,28,28,27,27,27,26,26,26,25,25,25,24,24,24,23,23,23,22,22,22,21,21,21,20,20,20,20,20,19,19,19,19,19,19,19,19,19,18,18,18,18,18,18,18,18,18,17,17,17,17,17,17,17,17,17,16,16,16,16,16,16,16,16,15,15,15,15,15,15,15,15,15,14,14,14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9}; - const ap_uint lt_res1_coord2_4[512] = {12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,10,10,10,10,10,10,10,9,9,9,9,9,9,9,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4}; - - + const ap_uint lt_res1_coord1_0[512] = { + 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; + const ap_uint lt_res1_coord1_1[512] = { + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, + 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; + const ap_uint lt_res1_coord1_2[512] = { + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, + 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, + 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; + const ap_uint lt_res1_coord1_3[512] = { + 7, 7, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, + 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 14, 14, 14, 14, + 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, + 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, + 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}; + const ap_uint lt_res1_coord1_4[512] = { + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 11, 11, + 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; + const ap_uint lt_res1_coord2_0[512] = { + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 19, + 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 28, 28, 28, 28, 27, 27, 27, + 27, 26, 26, 26, 25, 25, 25, 25, 24, 24, 24, 23, 23, 23, 22, 22, 22, 22, 21, 21, 21, 20, 20, 20, 20, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, 13, + 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, + 19, 19, 20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 24, 24, 23, 22, 22, 21, 20, 19, 18, 18, 17, 16, 15, 15, + 14, 13, 12, 11, 11, 10, 9, 8, 7, 7, 6, 5, 4, 3, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}; + const ap_uint lt_res1_coord2_1[512] = { + 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 11, 11, 11, + 11, 11, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, + 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, + 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; + const ap_uint lt_res1_coord2_2[512] = { + 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, + 24, 24, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 26, 26, 26, 26, + 26, 26, 25, 25, 25, 25, 25, 24, 24, 24, 24, 24, 24, 23, 23, 23, 23, 23, 22, 22, 22, 22, 22, 22, 21, 21, 21, + 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 28, 28, 28, 27, 27, 27, 26, 26, 25, 25, 24, 24, 23, 23, 22, 22, 21, 21, 20, 20, 19, 19, + 19, 18, 18, 17, 17, 16, 16, 15, 15, 14, 14, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; + const ap_uint lt_res1_coord2_3[512] = { + 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 29, 29, 29, 28, 28, 28, + 27, 27, 26, 26, 26, 25, 25, 25, 24, 24, 23, 23, 23, 22, 22, 22, 21, 21, 21, 20, 20, 19, 19, 19, 18, 18, 18, + 19, 19, 20, 20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 24, 25, 25, 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, + 29, 30, 30, 30, 30, 30, 30, 29, 29, 29, 28, 28, 28, 27, 27, 27, 26, 26, 26, 25, 25, 25, 24, 24, 24, 23, 23, + 23, 22, 22, 22, 21, 21, 21, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, + 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; + const ap_uint lt_res1_coord2_4[512] = { + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, + 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; const ap_uint lt_res0_eta1_0[512] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, From 81ac49016dadf3c4f7f2cd5c23b1d3d03e0d3043 Mon Sep 17 00:00:00 2001 From: Andrew Loeliger Date: Thu, 18 Apr 2024 03:35:07 -0500 Subject: [PATCH 11/17] update DQM muon tag --- DQMOffline/L1Trigger/python/L1TPhase2MuonOffline_cfi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DQMOffline/L1Trigger/python/L1TPhase2MuonOffline_cfi.py b/DQMOffline/L1Trigger/python/L1TPhase2MuonOffline_cfi.py index 6ccc686a49fd2..122b83bb7522c 100644 --- a/DQMOffline/L1Trigger/python/L1TPhase2MuonOffline_cfi.py +++ b/DQMOffline/L1Trigger/python/L1TPhase2MuonOffline_cfi.py @@ -40,7 +40,7 @@ useL1AtVtxCoord = cms.untracked.bool(False), genParticlesInputTag = cms.untracked.InputTag("genParticles"), - gmtMuonToken = cms.InputTag("l1tSAMuonsGmt", "promptSAMuons"), + gmtMuonToken = cms.InputTag("l1tSAMuonsGmt", "prompt"), gmtTkMuonToken = cms.InputTag("l1tTkMuonsGmt",""), efficiencyVsPtBins = cms.untracked.vdouble(effVsPtBins), From 642efa55a6aebdaec3bb5a86a0cd09850c142f9b Mon Sep 17 00:00:00 2001 From: Zhenbin Wu Date: Mon, 22 Apr 2024 11:49:55 -0500 Subject: [PATCH 12/17] Apply fixes for Phase-2 OMTF --- .../Configuration/python/SimL1Emulator_cff.py | 4 ++- .../plugins/Phase2L1TGMTFwdMuonTranslator.cc | 31 +++++++++++-------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/L1Trigger/Configuration/python/SimL1Emulator_cff.py b/L1Trigger/Configuration/python/SimL1Emulator_cff.py index de66aa375b82c..4af9b674ec40d 100644 --- a/L1Trigger/Configuration/python/SimL1Emulator_cff.py +++ b/L1Trigger/Configuration/python/SimL1Emulator_cff.py @@ -130,7 +130,9 @@ # Overlap and EndCap Muon Track Finder # ######################################################################## -from L1Trigger.L1TMuonOverlapPhase2.simOmtfPhase2Digis_cfi import * +from L1Trigger.L1TMuonOverlapPhase2.fakeOmtfParamsPhase2_cff import * +from L1Trigger.L1TMuonOverlapPhase2.simOmtfPhase2Digis_extrapol_cfi import * +_phase2_siml1emulator.add(omtfParamsPhase2) _phase2_siml1emulator.add(simOmtfPhase2Digis) from L1Trigger.L1TMuonEndCapPhase2.simCscTriggerPrimitiveDigisForEMTF_cfi import * diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc index 52aabb1183131..97e7c11b9b6d6 100644 --- a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTFwdMuonTranslator.cc @@ -100,19 +100,18 @@ void Phase2L1TGMTFwdMuonTranslator::produce(edm::Event& iEvent, const edm::Event // Since OMTF is using Phase-1 LSB, will convert to SAMuon locally // We should move to passing words in future l1t::SAMuon samuon; - if (mu.hwPt() > 0) + if (mu.hwPt() > 0) { samuon = Convertl1tMuon(mu, 0); - else if (mu.hwPtUnconstrained() > 0) //Assume exculsive, need double check - samuon = Convertl1tMuon(mu, 0, true); - - //now associate the stubs - associateStubs(samuon, stubs); - - // Add To Collections - if (mu.hwPt() > 0) + //now associate the stubs + associateStubs(samuon, stubs); prompt.push_back(samuon); - else if (mu.hwPtUnconstrained() > 0) + } + if (mu.hwPtUnconstrained() > 0) { + samuon = Convertl1tMuon(mu, 0, true); + //now associate the stubs + associateStubs(samuon, stubs); displaced.push_back(samuon); + } } // Convert EMTF++ Tracks to SAMuons @@ -166,10 +165,16 @@ SAMuon Phase2L1TGMTFwdMuonTranslator::Convertl1tMuon(const l1t::RegionalMuonCand if (!isDisplaced && mu.hwPt() > 0) pt = round(mu.hwPt() * 0.5 / LSBpt); // Phase-1 LSB 0.5GeV if (isDisplaced && mu.hwPtUnconstrained() > 0) - pt = round(mu.hwPtUnconstrained() * 0.5 / LSBpt); // Phase-1 LSB 0.5GeV + pt = round(mu.hwPtUnconstrained() * 1.0 / LSBpt); // Phase-1 LSB 1.0GeV!! + // BEWARE: THIS CONVERSION IS ONLY VALID FOR OMTF constexpr double p1phiLSB = 2 * M_PI / 576; - ap_int phi = round(mu.hwPhi() * p1phiLSB / LSBphi); // Phase-1 LSB (2*pi/576) + // From the uGMTConfiguration of OMTF. OMTF send in local phi!! + // all others correspond to 120 degree sectors = 192 in int-scale + int globPhi = mu.processor() * 192 + mu.hwPhi(); + // first processor starts at CMS phi = 15 degrees (24 in int)... Handle wrap-around with %. Add 576 to make sure the number is positive + globPhi = (globPhi + 600) % 576; + ap_int phi = round(globPhi * p1phiLSB / LSBphi); // Phase-1 LSB (2*pi/576) ap_int eta = round(mu.hwEta() * 0.010875 / LSBeta); // Phase-1 LSB 0.010875 // FIXME: Below are not well defined in phase1 GMT @@ -242,7 +247,7 @@ void Phase2L1TGMTFwdMuonTranslator::associateStubs(l1t::SAMuon& mu, const l1t::M SAMuon Phase2L1TGMTFwdMuonTranslator::ConvertEMTFTrack(const l1t::phase2::EMTFTrack& track, const int bx_) { // Convert EMTF Phi and Theta to Global Phi and Eta float track_phi = - emtf::phase2::tp::calcPhiGlobRadFromLoc(track.sector(), emtf::phase2::tp::calcPhiLocDegFromInt(track.modelPhi())); + emtf::phase2::tp::calcPhiGlobRadFromLoc(track.sector(), emtf::phase2::tp::calcPhiLocRadFromInt(track.modelPhi())); float track_theta = emtf::phase2::tp::calcThetaRadFromInt(track.modelEta()); float track_eta = -1 * std::log(std::tan(track_theta / 2)); From 73b6f8bbe6590fc93801f21c946f251d992dfa66 Mon Sep 17 00:00:00 2001 From: Zhenbin Wu Date: Wed, 22 May 2024 10:41:12 -0500 Subject: [PATCH 13/17] small bugfix --- L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTKMTFProducer.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTKMTFProducer.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTKMTFProducer.cc index 2eb12259867f5..87297ccb94de7 100644 --- a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTKMTFProducer.cc +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTKMTFProducer.cc @@ -131,6 +131,7 @@ void Phase2L1TGMTKMTFProducer::produce(edm::Event& iEvent, const edm::EventSetup 0, dxy, track.approxDispChi2()); + p.setTF(l1t::tftype::bmtf); int bstart = 0; wordtype word(0); bstart = wordconcat(word, bstart, 1, 1); From d300559fd22a9c00963173a7a1a601c865e4c010 Mon Sep 17 00:00:00 2001 From: Zhenbin Wu Date: Fri, 24 May 2024 10:55:28 -0500 Subject: [PATCH 14/17] Update OMTF config with PR #45032. --- L1Trigger/Configuration/python/SimL1Emulator_cff.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/L1Trigger/Configuration/python/SimL1Emulator_cff.py b/L1Trigger/Configuration/python/SimL1Emulator_cff.py index 4af9b674ec40d..4143cf23e525c 100644 --- a/L1Trigger/Configuration/python/SimL1Emulator_cff.py +++ b/L1Trigger/Configuration/python/SimL1Emulator_cff.py @@ -131,9 +131,7 @@ # Overlap and EndCap Muon Track Finder # ######################################################################## from L1Trigger.L1TMuonOverlapPhase2.fakeOmtfParamsPhase2_cff import * -from L1Trigger.L1TMuonOverlapPhase2.simOmtfPhase2Digis_extrapol_cfi import * _phase2_siml1emulator.add(omtfParamsPhase2) -_phase2_siml1emulator.add(simOmtfPhase2Digis) from L1Trigger.L1TMuonEndCapPhase2.simCscTriggerPrimitiveDigisForEMTF_cfi import * from L1Trigger.L1TMuonEndCapPhase2.rpcRecHitsForEMTF_cfi import * From 79e2fde8864319fd9789770128c632ef97f07a2b Mon Sep 17 00:00:00 2001 From: Zhenbin Wu Date: Fri, 24 May 2024 10:59:44 -0500 Subject: [PATCH 15/17] Update OMTF Config --- L1Trigger/Configuration/python/SimL1Emulator_cff.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/L1Trigger/Configuration/python/SimL1Emulator_cff.py b/L1Trigger/Configuration/python/SimL1Emulator_cff.py index 4143cf23e525c..de66aa375b82c 100644 --- a/L1Trigger/Configuration/python/SimL1Emulator_cff.py +++ b/L1Trigger/Configuration/python/SimL1Emulator_cff.py @@ -130,8 +130,8 @@ # Overlap and EndCap Muon Track Finder # ######################################################################## -from L1Trigger.L1TMuonOverlapPhase2.fakeOmtfParamsPhase2_cff import * -_phase2_siml1emulator.add(omtfParamsPhase2) +from L1Trigger.L1TMuonOverlapPhase2.simOmtfPhase2Digis_cfi import * +_phase2_siml1emulator.add(simOmtfPhase2Digis) from L1Trigger.L1TMuonEndCapPhase2.simCscTriggerPrimitiveDigisForEMTF_cfi import * from L1Trigger.L1TMuonEndCapPhase2.rpcRecHitsForEMTF_cfi import * From 223ea415d6dacefb2ee79f28d42091821535084a Mon Sep 17 00:00:00 2001 From: Zhenbin Wu Date: Tue, 4 Jun 2024 13:40:28 -0500 Subject: [PATCH 16/17] Update Valid bit of SAMuon and TkMuon to GT --- L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonGhostCleaner.cc | 2 +- L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonGhostCleaner.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonGhostCleaner.cc index fb215300c8722..aa5bfb92cd627 100644 --- a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonGhostCleaner.cc +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonGhostCleaner.cc @@ -74,7 +74,7 @@ std::vector Phase2L1TGMTSAMuonGhostCleaner::prodMuons(std::vector> 4); int bstart = 0; wordtype word(0); - bstart = wordconcat(word, bstart, 1, 1); + bstart = wordconcat(word, bstart, m.hwPt()>0, 1); bstart = wordconcat(word, bstart, m.hwPt(), BITSGTPT); bstart = wordconcat(word, bstart, m.hwPhi(), BITSGTPHI); bstart = wordconcat(word, bstart, m.hwEta(), BITSGTETA); diff --git a/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc b/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc index 640b560c47808..8f84c0cf06a34 100644 --- a/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc +++ b/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc @@ -102,6 +102,7 @@ bool TPSAlgorithm::outputGT(std::vector& muons) { wordtype word2 = 0; int bstart = 0; + bstart = wordconcat(word1, bstart, mu.hwPt()>0, 1); bstart = wordconcat(word1, bstart, mu.hwPt(), BITSGTPT); bstart = wordconcat(word1, bstart, mu.hwPhi(), BITSGTPHI); bstart = wordconcat(word1, bstart, mu.hwEta(), BITSGTETA); From b15d6adc7ca0a5a25ae194de8115e45072040262 Mon Sep 17 00:00:00 2001 From: Zhenbin Wu Date: Tue, 11 Jun 2024 10:50:05 -0500 Subject: [PATCH 17/17] Code-format of last commit --- L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonGhostCleaner.cc | 2 +- L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonGhostCleaner.cc b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonGhostCleaner.cc index aa5bfb92cd627..a88e38ee54d60 100644 --- a/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonGhostCleaner.cc +++ b/L1Trigger/Phase2L1GMT/plugins/Phase2L1TGMTSAMuonGhostCleaner.cc @@ -74,7 +74,7 @@ std::vector Phase2L1TGMTSAMuonGhostCleaner::prodMuons(std::vector> 4); int bstart = 0; wordtype word(0); - bstart = wordconcat(word, bstart, m.hwPt()>0, 1); + bstart = wordconcat(word, bstart, m.hwPt() > 0, 1); bstart = wordconcat(word, bstart, m.hwPt(), BITSGTPT); bstart = wordconcat(word, bstart, m.hwPhi(), BITSGTPHI); bstart = wordconcat(word, bstart, m.hwEta(), BITSGTETA); diff --git a/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc b/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc index 8f84c0cf06a34..43d5535e59155 100644 --- a/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc +++ b/L1Trigger/Phase2L1GMT/src/TPSAlgorithm.cc @@ -102,7 +102,7 @@ bool TPSAlgorithm::outputGT(std::vector& muons) { wordtype word2 = 0; int bstart = 0; - bstart = wordconcat(word1, bstart, mu.hwPt()>0, 1); + bstart = wordconcat(word1, bstart, mu.hwPt() > 0, 1); bstart = wordconcat(word1, bstart, mu.hwPt(), BITSGTPT); bstart = wordconcat(word1, bstart, mu.hwPhi(), BITSGTPHI); bstart = wordconcat(word1, bstart, mu.hwEta(), BITSGTETA);