Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-10-08 05:11:50

0001 // -*- C++ -*-
0002 
0003 #ifndef PHASE2GMT_SAFWDMUONTRANSLATOR
0004 #define PHASE2GMT_SAFWDMUONTRANSLATOR
0005 
0006 // system include files
0007 #include <memory>
0008 #include <sstream>
0009 
0010 // user include files
0011 #include "FWCore/Framework/interface/Frameworkfwd.h"
0012 #include "FWCore/Framework/interface/stream/EDProducer.h"
0013 #include "FWCore/Framework/interface/Event.h"
0014 #include "FWCore/Framework/interface/MakerMacros.h"
0015 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0016 #include "FWCore/Utilities/interface/StreamID.h"
0017 #include "DataFormats/L1Trigger/interface/Muon.h"
0018 #include "DataFormats/L1TMuonPhase2/interface/SAMuon.h"
0019 #include "DataFormats/L1TMuonPhase2/interface/EMTFTrack.h"
0020 #include "L1Trigger/L1TMuonEndCapPhase2/interface/Utils/TPUtils.h"
0021 
0022 //
0023 // class declaration
0024 //
0025 using namespace Phase2L1GMT;
0026 using namespace l1t;
0027 
0028 class Phase2L1TGMTFwdMuonTranslator : public edm::stream::EDProducer<> {
0029 public:
0030   explicit Phase2L1TGMTFwdMuonTranslator(const edm::ParameterSet&);
0031   ~Phase2L1TGMTFwdMuonTranslator() override = default;
0032 
0033   static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
0034 
0035 private:
0036   void produce(edm::Event&, const edm::EventSetup&) override;
0037 
0038   l1t::SAMuon Convertl1tMuon(const l1t::RegionalMuonCand& mu, const int bx_, bool isDisplaced = false);
0039   l1t::MuonStubRefVector selectLayerBX(const l1t::MuonStubRefVector& all, int bx, uint layer);
0040   void associateStubs(l1t::SAMuon&, const l1t::MuonStubRefVector&);
0041 
0042   l1t::SAMuon ConvertEMTFTrack(const l1t::phase2::EMTFTrack& track, const int bx_);
0043 
0044   // ----------member data ---------------------------
0045   edm::EDGetTokenT<l1t::MuonStubCollection> stubToken_;
0046   edm::EDGetTokenT<l1t::RegionalMuonCandBxCollection> omtfTrackToken_;
0047   edm::EDGetTokenT<l1t::phase2::EMTFTrackCollection> emtfTrackToken_;
0048 };
0049 //
0050 // constants, enums and typedefs
0051 //
0052 
0053 //
0054 // static data member definitions
0055 //
0056 
0057 //
0058 // constructors and destructor
0059 //
0060 Phase2L1TGMTFwdMuonTranslator::Phase2L1TGMTFwdMuonTranslator(const edm::ParameterSet& iConfig)
0061     : stubToken_(consumes<l1t::MuonStubCollection>(iConfig.getParameter<edm::InputTag>("stubs"))),
0062       omtfTrackToken_(consumes<l1t::RegionalMuonCandBxCollection>(iConfig.getParameter<edm::InputTag>("omtfTracks"))),
0063       emtfTrackToken_(consumes<l1t::phase2::EMTFTrackCollection>(iConfig.getParameter<edm::InputTag>("emtfTracks"))) {
0064   produces<std::vector<l1t::SAMuon> >("prompt").setBranchAlias("prompt");
0065   produces<std::vector<l1t::SAMuon> >("displaced").setBranchAlias("displaced");
0066 }
0067 
0068 // ------------ method called to produce the data  ------------
0069 void Phase2L1TGMTFwdMuonTranslator::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) {
0070   using namespace edm;
0071 
0072   edm::Handle<l1t::MuonStubCollection> stubHandle;
0073   iEvent.getByToken(stubToken_, stubHandle);
0074 
0075   edm::Handle<l1t::phase2::EMTFTrackCollection> emtf_tracks;
0076   iEvent.getByToken(emtfTrackToken_, emtf_tracks);
0077 
0078   edm::Handle<l1t::RegionalMuonCandBxCollection> omtf_tracks;
0079   iEvent.getByToken(omtfTrackToken_, omtf_tracks);
0080 
0081   // Process Stubs
0082   l1t::MuonStubRefVector stubs;
0083 
0084   for (uint i = 0; i < stubHandle->size(); ++i) {
0085     l1t::MuonStubRef stub(stubHandle, i);
0086 
0087     if (stub->bxNum() == 0)
0088       stubs.push_back(stub);
0089   }
0090 
0091   // Collect Muons
0092   std::vector<SAMuon> prompt;
0093 
0094   //  TODO: Will receive hybrid stubs from OMTF/EMTF
0095   std::vector<SAMuon> displaced;
0096 
0097   // Convert OMTF Muons to SAMuons
0098   for (unsigned int i = 0; i < omtf_tracks->size(0); ++i) {
0099     const l1t::RegionalMuonCand& mu = omtf_tracks->at(0, i);
0100     // Since OMTF is using Phase-1 LSB, will convert to SAMuon locally
0101     // We should move to passing words in future
0102     l1t::SAMuon samuon;
0103     if (mu.hwPt() > 0) {
0104       samuon = Convertl1tMuon(mu, 0);
0105       //now associate the stubs
0106       associateStubs(samuon, stubs);
0107       prompt.push_back(samuon);
0108     }
0109     if (mu.hwPtUnconstrained() > 0) {
0110       samuon = Convertl1tMuon(mu, 0, true);
0111       //now associate the stubs
0112       associateStubs(samuon, stubs);
0113       displaced.push_back(samuon);
0114     }
0115   }
0116 
0117   // Convert EMTF++ Tracks to SAMuons
0118   for (unsigned int track_id = 0; track_id < emtf_tracks->size(); ++track_id) {
0119     const auto& track = emtf_tracks->at(track_id);
0120 
0121     // Short-Circuit: Only keep valid tracks that are in BX=0
0122     if ((track.valid() == 0) || (track.bx() != 0)) {
0123       continue;
0124     }
0125 
0126     // Short-Circuit: Only keep tracks with quality above 3 to avoid single hit tracks
0127     if (track.emtfQuality() <= 3) {
0128       continue;
0129     }
0130 
0131     // Short-Circuit: Only keep tracks with the max relevance score (127)
0132     if (track.emtfRels() != 127) {
0133       continue;
0134     }
0135 
0136     auto samuon = ConvertEMTFTrack(track, 0);
0137 
0138     //now associate the stubs
0139     associateStubs(samuon, stubs);
0140 
0141     // Add To Collections
0142     if (track.unconstrained()) {
0143       displaced.push_back(samuon);
0144     } else {
0145       prompt.push_back(samuon);
0146     }
0147   }
0148 
0149   // Output Prompt Muon Collection
0150   std::unique_ptr<std::vector<l1t::SAMuon> > prompt_ptr = std::make_unique<std::vector<l1t::SAMuon> >(prompt);
0151   std::unique_ptr<std::vector<l1t::SAMuon> > displaced_ptr = std::make_unique<std::vector<l1t::SAMuon> >(displaced);
0152   iEvent.put(std::move(prompt_ptr), "prompt");
0153   iEvent.put(std::move(displaced_ptr), "displaced");
0154 }
0155 
0156 // ===  FUNCTION  ============================================================
0157 //         Name:  Phase2L1TGMTFwdMuonTranslator::Convertl1tMuon
0158 //  Description:
0159 // ===========================================================================
0160 SAMuon Phase2L1TGMTFwdMuonTranslator::Convertl1tMuon(const l1t::RegionalMuonCand& mu, const int bx_, bool isDisplaced) {
0161   ap_uint<BITSSAQUAL> qual = mu.hwQual();
0162   int charge = mu.hwSign();
0163 
0164   ap_uint<BITSGTPT> pt = 0;
0165   if (!isDisplaced && mu.hwPt() > 0)
0166     pt = round(mu.hwPt() * 0.5 / LSBpt);  // Phase-1 LSB 0.5GeV
0167   if (isDisplaced && mu.hwPtUnconstrained() > 0)
0168     pt = round(mu.hwPtUnconstrained() * 1.0 / LSBpt);  // Phase-1 LSB 1.0GeV!!
0169 
0170   // BEWARE: THIS CONVERSION IS ONLY VALID FOR OMTF
0171   constexpr double p1phiLSB = 2 * M_PI / 576;
0172   // From the uGMTConfiguration of OMTF. OMTF send in local phi!!
0173   // all others correspond to 120 degree sectors = 192 in int-scale
0174   int globPhi = mu.processor() * 192 + mu.hwPhi();
0175   // first processor starts at CMS phi = 15 degrees (24 in int)... Handle wrap-around with %. Add 576 to make sure the number is positive
0176   globPhi = (globPhi + 600) % 576;
0177   ap_int<BITSGTPHI> phi = round(globPhi * p1phiLSB / LSBphi);     // Phase-1 LSB (2*pi/576)
0178   ap_int<BITSGTETA> eta = round(mu.hwEta() * 0.010875 / LSBeta);  // Phase-1 LSB 0.010875
0179 
0180   // FIXME: Below are not well defined in phase1 GMT
0181   // Using the version from Correlator for now
0182   ap_int<BITSSAZ0> z0 = 0;  // No tracks info in Phase 1
0183   // Use 2 bits with LSB = 30cm for BMTF and 25cm for EMTF currently, but subjet to change
0184   ap_int<BITSSAD0> d0 = mu.hwDXY();
0185 
0186   //Here do not use the word format to GT but use the word format expected by GMT
0187   int bstart = 0;
0188   wordtype word(0);
0189   bstart = wordconcat<wordtype>(word, bstart, 1, 1);
0190   bstart = wordconcat<wordtype>(word, bstart, charge, 1);
0191   bstart = wordconcat<wordtype>(word, bstart, pt, BITSPT);
0192   bstart = wordconcat<wordtype>(word, bstart, phi, BITSPHI);
0193   bstart = wordconcat<wordtype>(word, bstart, eta, BITSETA);
0194   //  bstart = wordconcat<wordtype>(word, bstart, z0, BITSSAZ0); NOT YET SUPPORTED BY GMT
0195   bstart = wordconcat<wordtype>(word, bstart, d0, BITSSAD0);
0196   wordconcat<wordtype>(
0197       word, bstart, qual, 8);  //FOR NOW 8 bits to be efficienct with Ghost busting. THIS IS ***NOT*** THE FINAL QUALITY
0198 
0199   // Calculate Lorentz Vector
0200   math::PtEtaPhiMLorentzVector p4(pt * LSBpt, eta * LSBeta, phi * LSBphi, 0.0);
0201   SAMuon samuon(p4, charge, pt.to_uint(), eta.to_int(), phi.to_int(), z0.to_int(), d0.to_int(), qual.to_uint());
0202   samuon.setTF(mu.trackFinderType());
0203   samuon.setWord(word);
0204 
0205   return samuon;
0206 }  // -----  end of function Phase2L1TGMTFwdMuonTranslator::Convertl1tMuon  -----
0207 
0208 l1t::MuonStubRefVector Phase2L1TGMTFwdMuonTranslator::selectLayerBX(const l1t::MuonStubRefVector& all,
0209                                                                     int bx,
0210                                                                     uint layer) {
0211   l1t::MuonStubRefVector out;
0212   for (const auto& stub : all) {
0213     if (stub->bxNum() == bx && stub->tfLayer() == layer)
0214       out.push_back(stub);
0215   }
0216   return out;
0217 }
0218 
0219 void Phase2L1TGMTFwdMuonTranslator::associateStubs(l1t::SAMuon& mu, const l1t::MuonStubRefVector& stubs) {
0220   for (unsigned int layer = 0; layer <= 4; ++layer) {
0221     l1t::MuonStubRefVector selectedStubs = selectLayerBX(stubs, 0, layer);
0222     int bestStubINT = -1;
0223     float dPhi = 1000.0;
0224     for (uint i = 0; i < selectedStubs.size(); ++i) {
0225       const l1t::MuonStubRef& stub = selectedStubs[i];
0226       float deltaPhi =
0227           (stub->quality() & 0x1) ? stub->offline_coord1() - mu.p4().phi() : stub->offline_coord2() - mu.p4().phi();
0228       if (deltaPhi > M_PI)
0229         deltaPhi = deltaPhi - 2 * M_PI;
0230       if (deltaPhi < -M_PI)
0231         deltaPhi = deltaPhi + 2 * M_PI;
0232       deltaPhi = fabs(deltaPhi);
0233       float deltaEta = (stub->etaQuality() == 0 || (stub->etaQuality() & 0x1))
0234                            ? fabs(stub->offline_eta1() - mu.p4().eta())
0235                            : fabs(stub->offline_eta2() - mu.p4().eta());
0236       if (deltaPhi < 0.3 && deltaEta < 0.3 && deltaPhi < dPhi) {
0237         dPhi = deltaPhi;
0238         bestStubINT = i;
0239       }
0240     }
0241     if (bestStubINT >= 0) {
0242       mu.addStub(selectedStubs[bestStubINT]);
0243     }
0244   }
0245 }
0246 
0247 SAMuon Phase2L1TGMTFwdMuonTranslator::ConvertEMTFTrack(const l1t::phase2::EMTFTrack& track, const int bx_) {
0248   // Convert EMTF Phi and Theta to Global Phi and Eta
0249   float track_phi =
0250       emtf::phase2::tp::calcPhiGlobRadFromLoc(track.sector(), emtf::phase2::tp::calcPhiLocRadFromInt(track.modelPhi()));
0251   float track_theta = emtf::phase2::tp::calcThetaRadFromInt(track.modelEta());
0252   float track_eta = -1 * std::log(std::tan(track_theta / 2));
0253 
0254   // track_theta *= track.endcap();
0255   track_eta *= track.endcap();
0256 
0257   // Calculate Lorentz Vector
0258   // Muon mass taken from L1Trigger/L1TMuon/plugins/L1TMuonProducer.cc
0259   math::PtEtaPhiMLorentzVector p4(track.emtfPt() * LSBpt, track_eta, track_phi, 0.0);
0260 
0261   // Quantize Values
0262   ap_uint<BITSSAQUAL> qual = track.emtfQuality();  // Quality provided by EMTF to GMT
0263   int charge = track.emtfQ();                      // EMTF uses the same convention
0264   ap_uint<BITSGTPT> pt = track.emtfPt();           // Quantized by EMTF in the same units
0265   ap_int<BITSGTPHI> phi = round(track_phi / LSBphi);
0266   ap_int<BITSGTETA> eta = round(track_eta / LSBeta);
0267   ap_int<BITSSAZ0> z0 = track.emtfZ0();  // Quantized by EMTF in the same units
0268   ap_int<BITSSAD0> d0 = track.emtfD0();  // Quantized by EMTF in the same units
0269 
0270   //Here do not use the word format to GT but use the word format expected by GMT
0271   int bstart = 0;
0272   wordtype word(0);
0273   bstart = wordconcat<wordtype>(word, bstart, 1, 1);
0274   bstart = wordconcat<wordtype>(word, bstart, charge, 1);
0275   bstart = wordconcat<wordtype>(word, bstart, pt, BITSPT);
0276   bstart = wordconcat<wordtype>(word, bstart, phi, BITSPHI);
0277   bstart = wordconcat<wordtype>(word, bstart, eta, BITSETA);
0278   //  bstart = wordconcat<wordtype>(word, bstart, z0, BITSSAZ0); NOT YET SUPPORTED BY GMT
0279   bstart = wordconcat<wordtype>(word, bstart, d0, BITSSAD0);
0280   wordconcat<wordtype>(
0281       word, bstart, qual, 8);  //FOR NOW 8 bits to be efficienct with Ghost busting. THIS IS ***NOT*** THE FINAL QUALITY
0282 
0283   SAMuon samuon(p4, charge, pt.to_uint(), eta.to_int(), phi.to_int(), z0.to_int(), d0.to_int(), qual.to_uint());
0284 
0285   // +1=Positive Endcap and -1=Negative Endcap
0286   if (track.endcap() == 1)
0287     samuon.setTF(tftype::emtf_pos);
0288   else
0289     samuon.setTF(tftype::emtf_neg);
0290 
0291   samuon.setWord(word);
0292 
0293   return samuon;
0294 }
0295 
0296 // ------------ method fills 'descriptions' with the allowed parameters for the module  ------------
0297 void Phase2L1TGMTFwdMuonTranslator::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
0298   //The following says we do not know what parameters are allowed so do no validation
0299   // Please change this to state exactly what you do use, even if it is no parameters
0300   edm::ParameterSetDescription desc;
0301 
0302   // Input Collections
0303   desc.add<edm::InputTag>("stubs", edm::InputTag("gmtStubs"));
0304   desc.add<edm::InputTag>("emtfTracks", edm::InputTag("simEmtfDigisPhase2"));
0305   desc.add<edm::InputTag>("omtfTracks", edm::InputTag("simOmtfPhase2Digis"));
0306 
0307   // Register
0308   descriptions.add("Phase2L1TGMTFwdMuonTranslator", desc);
0309 }
0310 
0311 //define this as a plug-in
0312 DEFINE_FWK_MODULE(Phase2L1TGMTFwdMuonTranslator);
0313 #endif