diff --git a/L1Trigger/DTTriggerPhase2/plugins/DTTrigPhase2Prod.cc b/L1Trigger/DTTriggerPhase2/plugins/DTTrigPhase2Prod.cc index 5d31059221cba..2e0c78edc9ee4 100644 --- a/L1Trigger/DTTriggerPhase2/plugins/DTTrigPhase2Prod.cc +++ b/L1Trigger/DTTriggerPhase2/plugins/DTTrigPhase2Prod.cc @@ -177,9 +177,9 @@ class DTTrigPhase2Prod : public edm::stream::EDProducer<> { bool activateBuffer_; int superCellhalfspacewidth_; float superCelltimewidth_; - std::vector distribDigis(std::queue>& inQ); + std::vector distribDigis(std::queue>& inQ); void processDigi(std::queue>& inQ, - std::vector>*>& vec); + std::vector>>& vec); // RPC std::unique_ptr rpc_integrator_; @@ -375,14 +375,14 @@ void DTTrigPhase2Prod::produce(Event& iEvent, const EventSetup& iEventSetup) { tmpvec.clear(); // Distribute the digis from the queue into supercells - std::vector superCells; + std::vector superCells; superCells = distribDigis(timequeue); // Process each supercell & collect the resulting muonpaths (as the muonpaths std::vector is only enlarged each time // the groupings access it, it's not needed to "collect" the final products). while (!superCells.empty()) { - grouping_obj_->run(iEvent, iEventSetup, *(superCells.back()), muonpaths[chid.rawId()]); + grouping_obj_->run(iEvent, iEventSetup, superCells.back(), muonpaths[chid.rawId()]); superCells.pop_back(); } } else { @@ -1247,35 +1247,36 @@ int DTTrigPhase2Prod::assignQualityOrder(const metaPrimitive& mP) const { return qmap_.find(mP.quality)->second; } -std::vector DTTrigPhase2Prod::distribDigis(std::queue>& inQ) { - std::vector>*> tmpVector; +std::vector DTTrigPhase2Prod::distribDigis(std::queue>& inQ) { + // Use value-based containers to avoid returning pointers to local variables. + std::vector>> tmpVector; tmpVector.clear(); - std::vector collVector; + std::vector collVector; collVector.clear(); while (!inQ.empty()) { processDigi(inQ, tmpVector); } for (auto& sQ : tmpVector) { DTDigiCollection tmpColl; - while (!sQ->empty()) { - tmpColl.insertDigi((sQ->front().first), (sQ->front().second)); - sQ->pop(); + while (!sQ.empty()) { + tmpColl.insertDigi((sQ.front().first), (sQ.front().second)); + sQ.pop(); } - collVector.push_back(&tmpColl); + collVector.push_back(std::move(tmpColl)); } return collVector; } void DTTrigPhase2Prod::processDigi(std::queue>& inQ, - std::vector>*>& vec) { + std::vector>>& vec) { bool classified = false; if (!vec.empty()) { for (auto& sC : vec) { // Conditions for entering a super cell. - if ((sC->front().second.time() + superCelltimewidth_) > inQ.front().second.time()) { + if ((sC.front().second.time() + superCelltimewidth_) > inQ.front().second.time()) { // Time requirement - if (std::abs(sC->front().second.wire() - inQ.front().second.wire()) <= superCellhalfspacewidth_) { + if (std::abs(sC.front().second.wire() - inQ.front().second.wire()) <= superCellhalfspacewidth_) { // Spatial requirement - sC->push(std::move(inQ.front())); + sC.push(std::move(inQ.front())); classified = true; } } @@ -1293,7 +1294,7 @@ void DTTrigPhase2Prod::processDigi(std::queue>& inQ newQueue.push(tmpPair); inQ.pop(); - vec.push_back(&newQueue); + vec.push_back(std::move(newQueue)); } void DTTrigPhase2Prod::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { diff --git a/L1Trigger/L1TMuonOverlapPhase1/BuildFile.xml b/L1Trigger/L1TMuonOverlapPhase1/BuildFile.xml index e843803313dc9..6fbc9fecae7ad 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/BuildFile.xml +++ b/L1Trigger/L1TMuonOverlapPhase1/BuildFile.xml @@ -35,4 +35,3 @@ - diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/AngleConverterBase.h b/L1Trigger/L1TMuonOverlapPhase1/interface/AngleConverterBase.h deleted file mode 100644 index a8dd733e69df3..0000000000000 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/AngleConverterBase.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef L1T_OmtfP1_ANGLECONVERTER_H -#define L1T_OmtfP1_ANGLECONVERTER_H - -#include "L1Trigger/L1TMuonOverlapPhase1/interface/ProcConfigurationBase.h" - -#include "FWCore/Framework/interface/ESHandle.h" -#include "DataFormats/GeometryVector/interface/GlobalPoint.h" -#include "DataFormats/L1TMuon/interface/RegionalMuonCandFwd.h" -#include "Geometry/Records/interface/MuonGeometryRecord.h" -#include "FWCore/Framework/interface/ESWatcher.h" - -#include - -namespace edm { - class EventSetup; -} - -class RPCGeometry; -class CSCGeometry; -class CSCLayer; -class DTGeometry; - -class L1MuDTChambPhDigi; -class L1MuDTChambThDigi; -class L1MuDTChambThContainer; -class CSCCorrelatedLCTDigi; -class RPCDigi; - -class DTChamberId; -class CSCDetId; -class RPCDetId; - -struct EtaValue { - int eta = 0; - ///error of the eta measurement - int etaSigma = 0; - int quality = 0; - - int bx = 0; - int timing = 0; //sub-bx timing, should be already in scale common for all muon subsystems -}; - -struct MuonGeometryTokens { - edm::ESGetToken rpcGeometryEsToken; - edm::ESGetToken cscGeometryEsToken; - edm::ESGetToken dtGeometryEsToken; -}; - -class AngleConverterBase { -public: - AngleConverterBase(); - virtual ~AngleConverterBase(); - - ///Update the Geometry with current Event Setup - virtual void checkAndUpdateGeometry(const edm::EventSetup&, - const ProcConfigurationBase* config, - const MuonGeometryTokens& muonGeometryTokens); - - /// get phi of DT,CSC and RPC azimutal angle digi in processor scale, used by OMTF algorithm. - /// in case of wrong phi returns OMTFConfiguration::instance()->nPhiBins - /// phiZero - desired phi where the scale should start, should be in the desired scale, use getProcessorPhiZero to obtain it - virtual int getProcessorPhi(int phiZero, l1t::tftype part, int dtScNum, int dtPhi) const; - - virtual int getProcessorPhi( - int phiZero, l1t::tftype part, const CSCDetId& csc, const CSCCorrelatedLCTDigi& digi, unsigned int iInput) const; - - virtual int getProcessorPhi(unsigned int iProcessor, - l1t::tftype part, - const RPCDetId& rollId, - const unsigned int& digi) const; - virtual int getProcessorPhi(int phiZero, - l1t::tftype part, - const RPCDetId& rollId, - const unsigned int& digi1, - const unsigned int& digi2) const; - - ///returns the eta position of the DT chamber - ///(n.b. in the DT phi and eta segments are independent) - virtual EtaValue getGlobalEtaDt(const DTChamberId& detId) const; - - //adds the eta segments from the thetaDigi to etaSegments - virtual void getGlobalEta(const L1MuDTChambThDigi& thetaDigi, std::vector& etaSegments) const; - virtual std::vector getGlobalEta(const L1MuDTChambThContainer* dtThDigis, int bxFrom, int bxTo) const; - - ///Convert local eta coordinate to global digital microGMT scale. - virtual EtaValue getGlobalEta(const CSCDetId& detId, const CSCCorrelatedLCTDigi& aDigi) const; - - ///returns the eta position of the CSC chamber - virtual EtaValue getGlobalEtaCsc(const CSCDetId& detId) const; - - ///Convert local eta coordinate to global digital microGMT scale. - ///EtaValue::etaSigma is half of the strip - virtual EtaValue getGlobalEta(unsigned int rawid, const unsigned int& aDigi) const; - - float cscChamberEtaSize(const CSCDetId& id) const; - -protected: - ///Check orientation of strips in given CSC chamber - virtual bool isCSCCounterClockwise(const CSCLayer* layer) const; - - ///Find BTI group - virtual const int findBTIgroup(const L1MuDTChambPhDigi& aDigi, const L1MuDTChambThContainer* dtThDigis); - - // pointers to the current geometry records - unsigned long long _geom_cache_id = 0; - edm::ESHandle _georpc; - edm::ESHandle _geocsc; - edm::ESHandle _geodt; - - edm::ESWatcher muonGeometryRecordWatcher; - - const ProcConfigurationBase* config = nullptr; - ///Number of phi bins along 2Pi. - unsigned int nPhiBins = 0; -}; - -#endif diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/MuonStubMakerBase.h b/L1Trigger/L1TMuonOverlapPhase1/interface/MuonStubMakerBase.h index 4cd2efb411c37..c9b1c346df8e1 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/MuonStubMakerBase.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/MuonStubMakerBase.h @@ -6,7 +6,6 @@ #include "DataFormats/GEMDigi/interface/GEMPadDigiCollection.h" #include "DataFormats/L1DTTrackFinder/interface/L1MuDTChambPhContainer.h" #include "DataFormats/L1DTTrackFinder/interface/L1MuDTChambThContainer.h" -#include "DataFormats/L1TMuon/interface/RegionalMuonCandFwd.h" #include "DataFormats/MuonDetId/interface/DTChamberId.h" #include "DataFormats/MuonDetId/interface/RPCDetId.h" #include "DataFormats/RPCDigi/interface/RPCDigiCollection.h" @@ -167,7 +166,7 @@ class RpcDigiToStubsConverter : public DigiToStubsConverterBase { const RpcClusterization* rpcClusterization; }; -//forward declaration - MuonGeometryTokens is defined and used in the AngleConverterBase +//forward declaration - MuonGeometryTokens is defined and used in the OmtfAngleConverter struct MuonGeometryTokens; class MuonStubMakerBase { diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/AlgoMuon.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/AlgoMuon.h index ab005a8b9e254..066b78b5c5bca 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/AlgoMuon.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/AlgoMuon.h @@ -42,10 +42,8 @@ class AlgoMuon { //hardware pt int getPtConstr() const { return goldenPaternConstr == nullptr ? 0 : goldenPaternConstr->key().thePt; } - //hardware upt, in the phase1 the upt scale unit is 1 GeV, while for the pt the unit is 0.5GeV - int getPtUnconstr() const { - return goldenPaternUnconstr == nullptr ? 0 : (goldenPaternUnconstr->key().thePt - 1) / 2 + 1; - } + //hardware upt, in the pattens scale, not in the GMT scale + int getPtUnconstr() const { return goldenPaternUnconstr == nullptr ? 0 : goldenPaternUnconstr->key().thePt; } int getChargeConstr() const { return goldenPaternConstr == nullptr ? -1 : goldenPaternConstr->key().theCharge; } @@ -125,21 +123,29 @@ class AlgoMuon { this->goldenPaternUnconstr = goldenPaternUnconstr; } + int getQuality() const { return quality; } + + void setQuality(int quality = 0) { this->quality = quality; } + int getChargeNNConstr() const { return chargeNNConstr; } void setChargeNNConstr(int chargeNn = 0) { chargeNNConstr = chargeNn; } - int getPtNNConstr() const { return ptNNConstr; } + float getPtNNConstr() const { return ptNNConstr; } + + void setPtNNConstr(float ptNn = 0) { ptNNConstr = ptNn; } - void setPtNNConstr(int ptNn = 0) { ptNNConstr = ptNn; } + float getPtNNUnconstr() const { return ptNNUnconstr; } - int getChargeNNUnconstr() const { return chargeNNUnconstr; } + void setPtNNUnconstr(float ptNnUnconstr) { ptNNUnconstr = ptNnUnconstr; } - void setChargeNNUnconstr(int chargeNnUnconstr = 0) { chargeNNUnconstr = chargeNnUnconstr; } + int getDxyNn() const { return dxyNN; } - int getPtNNUnconstr() const { return ptNNUnconstr; } + void setDxyNn(int dxyNn = 0) { dxyNN = dxyNn; } - void setPtNNUnconstr(int ptNnUnconstr = 0) { ptNNUnconstr = ptNnUnconstr; } + const std::vector& getNnOutputs() const { return nnOutputs; } + + void setNnOutputs(const std::vector& nnOutputs) { this->nnOutputs = nnOutputs; } private: ///FIXME maybe the gpResult cannot be a reference or pointer, ad not a copy @@ -165,11 +171,16 @@ class AlgoMuon { std::vector> killedMuons; - int ptNNConstr = 0; + int quality = 0; + + float ptNNConstr = 0; int chargeNNConstr = 0; - int ptNNUnconstr = 0; - int chargeNNUnconstr = 0; + float ptNNUnconstr = 0; + + int dxyNN = 0; + + std::vector nnOutputs; }; typedef std::shared_ptr AlgoMuonPtr; diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/FinalMuon.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/FinalMuon.h new file mode 100644 index 0000000000000..810d182dad740 --- /dev/null +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/FinalMuon.h @@ -0,0 +1,113 @@ +/* + * FinalMuon.h + * + * Created on: Dec 17, 2024 + * Author: kbunkow + */ + +#ifndef L1T_OmtfP1_FinalMuon_H +#define L1T_OmtfP1_FinalMuon_H + +#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/AlgoMuon.h" + +class FinalMuon { +public: + FinalMuon() {}; + FinalMuon(const AlgoMuonPtr& algoMuon) + : algoMuon(algoMuon), quality(algoMuon->getQuality()), firedLayerCnt(algoMuon->getFiredLayerCnt()) {}; + + virtual ~FinalMuon() {}; + + const AlgoMuonPtr& getAlgoMuon() const { return algoMuon; } + + int getSign() const { return sign; } + + void setSign(int sign = 0) { this->sign = sign; } + + void setBx(int bx = 0) { this->bx = bx; } + + int getBx() const { return bx; } + + int getProcessor() const { return processor; } + + void setProcessor(int processor = -1) { this->processor = processor; } + + void setTrackFinderType(l1t::tftype mtfType) { this->mtfType = mtfType; } + l1t::tftype trackFinderType() const { return mtfType; } + + int getQuality() const { return quality; } + + void setQuality(int quality = 0) { this->quality = quality; } + + float getPtGev() const { return ptGev; } + + void setPtGev(float ptGev = -1) { this->ptGev = ptGev; } + + float getPtUnconstrGev() const { return ptUnconstrGev; } + + void setPtUnconstrGev(float ptUnconstrGev = -1) { this->ptUnconstrGev = ptUnconstrGev; } + + float getEtaRad() const { return etaRad; } + + void setEtaRad(float etaRad = -10) { this->etaRad = etaRad; } + + float getPhiRad() const { return phiRad; } + + void setPhiRad(float phiRad = -10) { this->phiRad = phiRad; } + + int getPtGmt() const { return ptGmt; } + + void setPtGmt(int ptGmt = 0) { this->ptGmt = ptGmt; } + + int getPtUnconstrGmt() const { return ptUnconstrGmt; } + + void setPtUnconstrGmt(int ptUnconstrGmt = 0) { this->ptUnconstrGmt = ptUnconstrGmt; } + + int getPhiGmt() const { return phiGmt; } + + void setPhiGmt(int phiGmt = 0) { this->phiGmt = phiGmt; } + + int getEtaGmt() const { return etaGmt; } + + void setEtaGmt(int etaGmt = 0) { this->etaGmt = etaGmt; } + + int getFiredLayerCnt() const { return firedLayerCnt; } + + void setFiredLayerCnt(int firedLayerCnt = 0) { this->firedLayerCnt = firedLayerCnt; } + + int getFiredLayerBits() const { return firedLayerBits; } + + void setFiredLayerBits(int firedLayerBits = 0) { this->firedLayerBits = firedLayerBits; } + + friend std::ostream& operator<<(std::ostream& out, const FinalMuon& finalMuon); + +private: + AlgoMuonPtr algoMuon; + + int bx = 0; + int processor = -1; + l1t::tftype mtfType = l1t::omtf_pos; + + int quality = 0; + + int sign = 0; + + float ptGev = -1; + float ptUnconstrGev = -1; + float phiRad = -10; + float etaRad = -10; + + int ptGmt = 0; + int ptUnconstrGmt = 0; + int phiGmt = 0; + int etaGmt = 0; + + int firedLayerCnt = 0; + + int firedLayerBits = 0; +}; + +typedef std::shared_ptr FinalMuonPtr; +typedef std::vector FinalMuons; + +#endif /* FinalMuon */ diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/GoldenPattern.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/GoldenPattern.h index 89f1d7d8692f7..edf8fee29a9c4 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/GoldenPattern.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/GoldenPattern.h @@ -82,9 +82,8 @@ class GoldenPattern : public GoldenPatternBase { ///Reset contents of all data vectors, keeping the vectors size virtual void reset(); - ///Propagate phi from given reference layer to MB2 or ME2 - ///expressed in integer MicroGMT scale: 1.1/2.61*240 = 101 - int propagateRefPhi(int phiRef, int etaRef, unsigned int iRefLayer) override; + ///Propagates phi from a given reference layer (iRefLayer) to a selected iLayer + int propagateRefPhi(int phiRef, int etaRef, unsigned int iRefLayer, unsigned int iLayer) override; protected: ///Distributions for all reference layers diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/GoldenPatternBase.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/GoldenPatternBase.h index cce6d74ef5bb9..deacb0734bda4 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/GoldenPatternBase.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/GoldenPatternBase.h @@ -105,10 +105,8 @@ class GoldenPatternBase { const std::vector& extrapolatedPhi, const MuonStubPtr& refStub); - ///Propagate phi from given reference layer to MB2 or ME2 - ///ME2 is used if eta of reference hit is larger than 1.1 - ///expressed in integer MicroGMT scale: 1.1/2.61*240 = 101 - virtual int propagateRefPhi(int phiRef, int etaRef, unsigned int iRefLayer) = 0; + ///Propagates phi from a given reference layer (iRefLayer) to a selected iLayer + virtual int propagateRefPhi(int phiRef, int etaRef, unsigned int iRefLayer, unsigned int iLayer) = 0; resultsArrayType& getResults() { return results; } diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/GoldenPatternResult.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/GoldenPatternResult.h index fd8aaa1bb3ccd..a090abf3cd4a2 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/GoldenPatternResult.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/GoldenPatternResult.h @@ -58,8 +58,6 @@ class GoldenPatternResult { void set(int refLayer, int phi, int eta, int refHitPhi); - void setStubResult(float pdfVal, bool valid, int pdfBin, int layer, MuonStubPtr stub); - void setStubResult(int layer, StubResult& stubResult); int getRefLayer() const { return this->refLayer; } diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/IOMTFEmulationObserver.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/IOMTFEmulationObserver.h index 750d03f0a2e72..8f0e36d1490bb 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/IOMTFEmulationObserver.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/IOMTFEmulationObserver.h @@ -9,6 +9,7 @@ #define L1T_OmtfP1_IOMTFRECONSTRUCTIONOBSERVER_H_ #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/AlgoMuon.h" +#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/FinalMuon.h" #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFinput.h" #include "FWCore/Framework/interface/EventSetup.h" @@ -40,12 +41,11 @@ class IOMTFEmulationObserver { const std::shared_ptr& input, const AlgoMuons& algoCandidates, const AlgoMuons& gbCandidates, - const std::vector& candMuons) = 0; + const FinalMuons& finalMuons) = 0; virtual void observeEventBegin(const edm::Event& iEvent) {} - virtual void observeEventEnd(const edm::Event& iEvent, - std::unique_ptr& finalCandidates) {}; + virtual void observeEventEnd(const edm::Event& iEvent, FinalMuons& finalMuons) {}; virtual void endJob() = 0; }; diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/IProcessorEmulator.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/IProcessorEmulator.h index 0be9fc6615513..0efaf399bece6 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/IProcessorEmulator.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/IProcessorEmulator.h @@ -33,17 +33,17 @@ class IProcessorEmulator { virtual AlgoMuons ghostBust(AlgoMuons refHitCands, int charge = 0) = 0; - virtual bool checkHitPatternValidity(unsigned int hits) = 0; + virtual FinalMuons getFinalMuons(unsigned int iProcessor, l1t::tftype mtfType, const AlgoMuons& gbCandidates) = 0; - virtual std::vector getFinalcandidates(unsigned int iProcessor, - l1t::tftype mtfType, - const AlgoMuons& algoCands) = 0; + virtual std::vector getRegionalMuonCands(unsigned int iProcessor, + l1t::tftype mtfType, + FinalMuons& finalMuons) = 0; - virtual std::vector run(unsigned int iProcessor, - l1t::tftype mtfType, - int bx, - OMTFinputMaker* inputMaker, - std::vector >& observers) = 0; + virtual FinalMuons run(unsigned int iProcessor, + l1t::tftype mtfType, + int bx, + OMTFinputMaker* inputMaker, + std::vector >& observers) = 0; virtual void printInfo() const = 0; }; diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFConfiguration.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFConfiguration.h index 475ae3a3392c4..1ff8423146831 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFConfiguration.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFConfiguration.h @@ -136,23 +136,44 @@ class OMTFConfiguration : public ProcConfigurationBase { const vector4D& getMeasurements4D() const { return measurements4D; } const vector4D& getMeasurements4Dref() const { return measurements4Dref; } + //pt unit of the OMTF patrterns, the same as in the phase-1 uGMT + //TODO refactor to omtfPtUnit double ptUnit = 0.5; // GeV/unit ///uGMT pt scale conversion - double hwPtToGev(int hwPt) const override { return (hwPt - 1.) * ptUnit; } - - double uptUnit = 1; // GeV/unit - double hwUPtToGev(int hwPt) const override { return (hwPt - 1.) * uptUnit; } + //TODO refactor to omtfPtToGev + double hwPtToGev(int hwPt) const override { return (hwPt == 0 ? 0 : (hwPt - 1.) * ptUnit); } ///uGMT pt scale conversion: [0GeV, 0.5GeV) = 1 [0.5GeV, 1 Gev) = 2 int ptGevToHw(double ptGev) const override { return (ptGev / ptUnit + 1); } - int calcGlobalPhi(int locPhi, int proc) const; - - double etaUnit = 0.010875; //=2.61/240 TODO value taken from the interface note, should be defined somewhere globally ///center of eta bin - virtual double hwEtaToEta(int hwEta) const { return (hwEta * etaUnit); } + virtual double hwEtaToEta(int hwEta) const { return (hwEta * etaUnit_); } + + //TODO use version with round + int etaToHwEta(double eta) const override { return (eta / etaUnit_); } + //int etaToHwEta(double eta) const override { return std::lround(eta / etaUnit_); } + + //TODO the phase-1 values 92, 79 and 75 are quite far from the chamber middle, should be fixed for phase-2 + //eta of the middle DT Wheel 2 MB1, in the OMTF scale + int mb1W2Eta() const override { + //92 in phase 1 scale + return etaToHwEta(1.0005); + } + + //eta of the middle DT Wheel 2 MB2, in the OMTF scale + int mb2W2Eta() const override { + //79 in phase 1 scale + return etaToHwEta(0.859125); + } - int etaToHwEta(double eta) const override { return (eta / etaUnit); } + //eta of the middle DT Wheel 2 MB3, in the OMTF scale + int mb3W2Eta() const override { + //75 in phase 1 scale + return etaToHwEta(0.815625); + } + + //eta of the middle DT Wheel 2 MB4, in the OMTF scale + int mb4W2Eta() const override { return etaToHwEta(0.67); } static unsigned int eta2Bits(unsigned int eta); @@ -160,12 +181,7 @@ class OMTFConfiguration : public ProcConfigurationBase { static int etaBit2Code(unsigned int bit); - double phiGmtUnit = 2. * M_PI / 576; //TODO from the interface note, should be defined somewhere globally - //phi in radians - virtual int phiToGlobalHwPhi(double phi) const { return std::floor(phi / phiGmtUnit); } - - //phi in radians - virtual double hwPhiToGlobalPhi(int phi) const { return phi * phiGmtUnit; } + double phiGmtUnit = 2. * M_PI / 576; //phase-1, from the interface note, should be defined somewhere globally ///iProcessor - 0...5 ///phiRad [-pi,pi] @@ -176,9 +192,16 @@ class OMTFConfiguration : public ProcConfigurationBase { return 0; // TODO replace getProcScalePhi(unsigned int iProcessor, double phiRad) with this function } - double procHwPhiToGlobalPhi(int procHwPhi, int procHwPhi0) const; + //returns the global phi in the OMTF scale + int procPhiOmtfToGlobalPhiOmtf(unsigned int iProcessor, int procHwPhi) const; - int procPhiToGmtPhi(int procPhi) const { + //phi in radians, -pi to pi convention + double procPhiOmtfToPhiRad(unsigned int iProcessor, int procHwPhi) const { + auto procPhi = procPhiOmtfToGlobalPhiOmtf(iProcessor, procHwPhi) * 2. * M_PI / nPhiBins(); + return (procPhi > M_PI) ? procPhi - 2. * M_PI : procPhi; + }; + + int procPhiToGmtPhase1Phi(int procPhi) const { ///conversion factor from OMTF to uGMT scale is 5400/576 i.e. phiValue/=9.375; return floor(procPhi * 437. / (1 << 12)); // ie. use as in hw: 9.3729977 //cannot be (procPhi * 437) >> 12, because this floor is needed @@ -285,6 +308,8 @@ class OMTFConfiguration : public ProcConfigurationBase { bool cleanStubs() const { return cleanStubs_; } + bool usePhase2DTPrimitives() const { return usePhase2DTPrimitives_; } + private: L1TMuonOverlapParams rawParams; @@ -366,6 +391,8 @@ class OMTFConfiguration : public ProcConfigurationBase { bool dumpResultToXML = false; bool cleanStubs_ = false; + + bool usePhase2DTPrimitives_ = false; }; #endif diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFProcessor.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFProcessor.h index 68ce5b1dac266..7f41caf37a3f5 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFProcessor.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFProcessor.h @@ -2,6 +2,7 @@ #define L1T_OmtfP1_OMTFProcessor_H #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/AlgoMuon.h" +#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/FinalMuon.h" #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/GoldenPattern.h" #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/GoldenPatternResult.h" #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/IGhostBuster.h" @@ -11,8 +12,6 @@ #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/ProcessorBase.h" #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/SorterBase.h" -#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/PtAssignmentBase.h" - #include "FWCore/Framework/interface/Event.h" #include "FWCore/ParameterSet/interface/ParameterSet.h" @@ -61,6 +60,7 @@ class OMTFProcessor : public ProcessorBase, public IProcessor int extrapolateDtPhiBFloatPoint(const int& refLogicLayer, const int& refPhi, const int& refPhiB, + const int& refHitSuperLayer, unsigned int targetLayer, const int& targetStubPhi, const int& targetStubQuality, @@ -72,6 +72,7 @@ class OMTFProcessor : public ProcessorBase, public IProcessor int extrapolateDtPhiBFixedPoint(const int& refLogicLayer, const int& refPhi, const int& refPhiB, + const int& refHitSuperLayer, unsigned int targetLayer, const int& targetStubPhi, const int& targetStubQuality, @@ -97,10 +98,15 @@ class OMTFProcessor : public ProcessorBase, public IProcessor return ghostBuster->select(refHitCands, charge); } - //convert algo muon to outgoing Candidates - std::vector getFinalcandidates(unsigned int iProcessor, - l1t::tftype mtfType, - const AlgoMuons& algoCands) override; + void assignQuality(AlgoMuons::value_type& algoMuon); + + FinalMuons getFinalMuons(unsigned int iProcessor, l1t::tftype mtfType, const AlgoMuons& gbCandidates) override; + + void convertToGmtScalesPhase1(unsigned int iProcessor, l1t::tftype mtfType, FinalMuonPtr& finalMuon); + + std::vector getRegionalMuonCands(unsigned int iProcessor, + l1t::tftype mtfType, + FinalMuons& finalMuons) override; ///allows to use other sorter implementation than the default one virtual void setSorter(SorterBase* sorter) { this->sorter.reset(sorter); } @@ -108,13 +114,11 @@ class OMTFProcessor : public ProcessorBase, public IProcessor ///allows to use other IGhostBuster implementation than the default one void setGhostBuster(IGhostBuster* ghostBuster) override { this->ghostBuster.reset(ghostBuster); } - virtual void setPtAssignment(PtAssignmentBase* ptAssignment) { this->ptAssignment = ptAssignment; } - - std::vector run(unsigned int iProcessor, - l1t::tftype mtfType, - int bx, - OMTFinputMaker* inputMaker, - std::vector >& observers) override; + FinalMuons run(unsigned int iProcessor, + l1t::tftype mtfType, + int bx, + OMTFinputMaker* inputMaker, + std::vector >& observers) override; void printInfo() const override; @@ -130,15 +134,12 @@ class OMTFProcessor : public ProcessorBase, public IProcessor ///Candidate with invalid hit patterns is assigned quality=0. ///Currently the list of invalid patterns is hardcoded. ///This has to be read from configuration. - bool checkHitPatternValidity(unsigned int hits) override; + static bool checkHitPatternValidity(unsigned int hits); std::unique_ptr > sorter; std::unique_ptr ghostBuster; - //ptAssignment should be destroyed where it is created, i.e. by OmtfEmulation or OMTFReconstruction - PtAssignmentBase* ptAssignment = nullptr; - bool useStubQualInExtr = false; bool useEndcapStubsRInExtr = false; diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFReconstruction.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFReconstruction.h index 868077a7f755a..19e2152ee0090 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFReconstruction.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFReconstruction.h @@ -43,12 +43,12 @@ class OMTFReconstruction { void endJob(); - void beginRun(edm::Run const& run, - edm::EventSetup const& iSetup, - edm::ESGetToken& omtfParamsEsToken, - const MuonGeometryTokens& muonGeometryTokens, - const edm::ESGetToken& magneticFieldEsToken, - const edm::ESGetToken& propagatorEsToken); + virtual void beginRun(edm::Run const& run, + edm::EventSetup const& iSetup, + edm::ESGetToken& omtfParamsEsToken, + const MuonGeometryTokens& muonGeometryTokens, + const edm::ESGetToken& magneticFieldEsToken, + const edm::ESGetToken& propagatorEsToken); std::unique_ptr reconstruct(const edm::Event&, const edm::EventSetup&); diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OmtfAngleConverter.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OmtfAngleConverter.h index 7c12d7aa6b6a3..934f59f302a23 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OmtfAngleConverter.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OmtfAngleConverter.h @@ -8,26 +8,90 @@ #ifndef L1T_OmtfP1_OMTFANGLECONVERTER_H_ #define L1T_OmtfP1_OMTFANGLECONVERTER_H_ -#include "L1Trigger/L1TMuonOverlapPhase1/interface/AngleConverterBase.h" +#include "L1Trigger/L1TMuonOverlapPhase1/interface/ProcConfigurationBase.h" -class OmtfAngleConverter : public AngleConverterBase { +#include "FWCore/Framework/interface/ESHandle.h" +#include "DataFormats/GeometryVector/interface/GlobalPoint.h" +#include "DataFormats/L1TMuon/interface/RegionalMuonCandFwd.h" +#include "Geometry/Records/interface/MuonGeometryRecord.h" +#include "FWCore/Framework/interface/ESWatcher.h" + +#include + +class RPCGeometry; +class CSCGeometry; +class CSCLayer; +class DTGeometry; + +class L1MuDTChambPhDigi; +class L1MuDTChambThDigi; +class L1MuDTChambThContainer; +class CSCCorrelatedLCTDigi; +class RPCDigi; + +class DTChamberId; +class CSCDetId; +class RPCDetId; + +struct MuonGeometryTokens { + edm::ESGetToken rpcGeometryEsToken; + edm::ESGetToken cscGeometryEsToken; + edm::ESGetToken dtGeometryEsToken; +}; + +class OmtfAngleConverter { public: - OmtfAngleConverter() : AngleConverterBase() {} + OmtfAngleConverter() {} + + virtual ~OmtfAngleConverter(); - ~OmtfAngleConverter() override; + ///Update the Geometry with current Event Setup + virtual void checkAndUpdateGeometry(const edm::EventSetup&, + const ProcConfigurationBase* config, + const MuonGeometryTokens& muonGeometryTokens); + + /// get phi of DT,CSC and RPC azimutal angle digi in processor scale, used by OMTF algorithm. + /// in case of wrong phi returns OMTFConfiguration::instance()->nPhiBins + /// phiZero - desired phi where the scale should start, should be in the desired scale, use getProcessorPhiZero to obtain it + virtual int getProcessorPhi(int phiZero, l1t::tftype part, int dtScNum, int dtPhi) const; + + virtual int getProcessorPhi( + int phiZero, l1t::tftype part, const CSCDetId& csc, const CSCCorrelatedLCTDigi& digi, unsigned int iInput) const; + + virtual int getProcessorPhi(int phiZero, + l1t::tftype part, + const RPCDetId& rollId, + const unsigned int& digi1, + const unsigned int& digi2) const; ///Convert local eta coordinate to global digital microGMT scale. ///theta is returned only if in the dtThDigis is only one hit, otherwise eta = 95 or middle of the chamber - virtual int getGlobalEta(const DTChamberId dTChamberId, const L1MuDTChambThContainer *dtThDigis, int bxNum) const; + virtual int getGlobalEta(const DTChamberId dTChamberId, const L1MuDTChambThContainer* dtThDigis, int bxNum) const; ///Convert local eta coordinate to global digital microGMT scale. - virtual int getGlobalEta(unsigned int rawid, const CSCCorrelatedLCTDigi &aDigi, float &r) const; + virtual int getGlobalEta(unsigned int rawid, const CSCCorrelatedLCTDigi& aDigi, float& r) const; ///Convert local eta coordinate to global digital microGMT scale. - virtual int getGlobalEtaRpc(unsigned int rawid, const unsigned int &aDigi, float &r) const; + virtual int getGlobalEtaRpc(unsigned int rawid, const unsigned int& aDigi, float& r) const; + +protected: + ///Check orientation of strips in given CSC chamber + virtual bool isCSCCounterClockwise(const CSCLayer* layer) const; + + ///Find BTI group + virtual const int findBTIgroup(const L1MuDTChambPhDigi& aDigi, const L1MuDTChambThContainer* dtThDigis); + + // pointers to the current geometry records + unsigned long long _geom_cache_id = 0; + edm::ESHandle _georpc; + edm::ESHandle _geocsc; + edm::ESHandle _geodt; + + edm::ESWatcher muonGeometryRecordWatcher; - //to avoid Clang Warnings "hides overloaded virtual functions" - using AngleConverterBase::getGlobalEta; + const ProcConfigurationBase* config = nullptr; + ///Number of phi bins along 2Pi. + unsigned int nPhiBins = 0; }; #endif /* L1T_OmtfP1_OMTFANGLECONVERTER_H_ */ diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/PtAssignmentBase.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/PtAssignmentBase.h deleted file mode 100644 index 83b098918f3ce..0000000000000 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/PtAssignmentBase.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * PtAssignmentBase.h - * - * Created on: Mar 16, 2020 - * Author: kbunkow - */ - -#ifndef L1T_OmtfP1_PTASSIGNMENTBASE_H_ -#define L1T_OmtfP1_PTASSIGNMENTBASE_H_ - -#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/AlgoMuon.h" -#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/IOMTFEmulationObserver.h" - -/* - * base class for the objects providing an alternative pt assignment on top of the OMTF golden pattern (like neural network) - * getPts() is called inside OMTFProcessor::getFinalcandidates - */ -class PtAssignmentBase { -public: - PtAssignmentBase(const OMTFConfiguration* omtfConfig) : omtfConfig(omtfConfig) {} - virtual ~PtAssignmentBase(); - - virtual std::vector getPts(AlgoMuons::value_type& algoMuon, - std::vector >& observers) = 0; - -protected: - const OMTFConfiguration* omtfConfig = nullptr; -}; - -#endif /* L1T_OmtfP1_PTASSIGNMENTBASE_H_ */ diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/XMLEventWriter.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/XMLEventWriter.h index cfbca57a38d3c..1e22f9711a895 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/XMLEventWriter.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/XMLEventWriter.h @@ -36,12 +36,11 @@ class XMLEventWriter : public IOMTFEmulationObserver { const std::shared_ptr& input, const AlgoMuons& algoCandidates, const AlgoMuons& gbCandidates, - const std::vector& candMuons) override; + const FinalMuons& finalMuons) override; void observeEventBegin(const edm::Event& iEvent) override; - void observeEventEnd(const edm::Event& iEvent, - std::unique_ptr& finalCandidates) override; + void observeEventEnd(const edm::Event& iEvent, FinalMuons& finalMuons) override; void endJob() override; diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/ProcConfigurationBase.h b/L1Trigger/L1TMuonOverlapPhase1/interface/ProcConfigurationBase.h index 2b2cbb14b89e4..dc27315ca2152 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/ProcConfigurationBase.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/ProcConfigurationBase.h @@ -9,6 +9,8 @@ #define L1T_OmtfP1_PROCCONFIGURATIONBASE_H_ #include "FWCore/ParameterSet/interface/ParameterSet.h" +#include + class ProcConfigurationBase { public: ProcConfigurationBase(); @@ -25,8 +27,6 @@ class ProcConfigurationBase { virtual double hwPtToGev(int hwPt) const = 0; - virtual double hwUPtToGev(int hwPt) const = 0; - ///uGMT pt scale conversion: [0GeV, 0.5GeV) = 1 [0.5GeV, 1 Gev) = 2 virtual int ptGevToHw(double ptGev) const = 0; @@ -35,6 +35,18 @@ class ProcConfigurationBase { virtual int etaToHwEta(double eta) const = 0; + //eta of the middle DT Wheel 2 MB1, in the OMTF scale + virtual int mb1W2Eta() const = 0; + + //eta of the middle DT Wheel 2 MB2, in the OMTF scale + virtual int mb2W2Eta() const = 0; + + //eta of the middle DT Wheel 2 MB3, in the OMTF scale + virtual int mb3W2Eta() const = 0; + + //eta of the middle DT Wheel 2 MB4, in the OMTF scale + virtual int mb4W2Eta() const = 0; + //returns address for the pdf LUTs virtual unsigned int ptHwToPtBin(int ptHw) const { return 0; } @@ -55,6 +67,10 @@ class ProcConfigurationBase { virtual void setCscLctCentralBx(int lctCentralBx) { this->cscLctCentralBx_ = lctCentralBx; } + virtual int dtBxShift() const { return dtBxShift_; } + + virtual void setDtBxShift(int dtBxShift) { this->dtBxShift_ = dtBxShift; } + virtual bool getRpcDropAllClustersIfMoreThanMax() const { return rpcDropAllClustersIfMoreThanMax; } virtual void setRpcDropAllClustersIfMoreThanMax(bool rpcDropAllClustersIfMoreThanMax = true) { @@ -85,11 +101,12 @@ class ProcConfigurationBase { enum class StubEtaEncoding { //in the firmware the eta is encoded as fired bits in the 9bit word, this is DT phase-1 encoding. - //In the emulator in most of the places eta value is used, but with the DT-like binning, i.e. only certain values are valid, see OMTFConfiguration::eta2Bits() + //In the emulator in most of the places eta value is used, but with the DT-like bining, i.e. only certain values are valid, see OMTFConfiguration::eta2Bits() //this is the OMTF run2 option bits = 0, - //the phase1 eta scale is used, but all hw values are valid, i.e. the DT-phase one binnig is NOT used + //the phase1 eta scale is used, but all hw values are valid, i.e. the DT-phase-1 bining is NOT used valueP1Scale = 1, + valueP2Scale = 2, }; StubEtaEncoding getStubEtaEncoding() const { return stubEtaEncoding; } @@ -100,9 +117,16 @@ class ProcConfigurationBase { //in the link data it can be different, and it is converted in the DtDigiToStubsConverterOmtf::addDTphiDigi double dtPhiBUnitsRad() const { return dtPhiBUnitsRad_; } + double etaUnit() const { return etaUnit_; } + +protected: + double etaUnit_ = 0.010875; //=2.61/240 - value from the phase1 interface note + private: int cscLctCentralBx_ = 8; //CSCConstants::LCT_CENTRAL_BX; + int dtBxShift_ = 20; //phase-2 DT segment BX shift, different for MC and data + //parameters of the RpcClusterization unsigned int rpcMaxClusterSize = 3; unsigned int rpcMaxClusterCnt = 2; diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/StubResult.h b/L1Trigger/L1TMuonOverlapPhase1/interface/StubResult.h index 9260297345b2d..eade5a406c714 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/StubResult.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/StubResult.h @@ -15,13 +15,15 @@ class StubResult { public: StubResult() {} //empty result - StubResult(float pdfVal, bool valid, int pdfBin, int layer, MuonStubPtr stub) - : pdfVal(pdfVal), valid(valid), pdfBin(pdfBin), layer(layer), stub(stub) {} + StubResult(float pdfVal, bool valid, int pdfBin, int deltaPhi, int layer, MuonStubPtr stub) + : pdfVal(pdfVal), valid(valid), pdfBin(pdfBin), deltaPhi(deltaPhi), layer(layer), stub(stub) {} const MuonStubPtr& getMuonStub() const { return stub; } int getPdfBin() const { return pdfBin; } + int getDeltaPhi() const { return deltaPhi; } + float getPdfVal() const { return pdfVal; } void setPdfVal(float pdfVal) { this->pdfVal = pdfVal; } @@ -47,6 +49,9 @@ class StubResult { //stub and pdfBin should be needed only for debug, testing, generating patterns, etc, but rather not in the firmware int pdfBin = 0; + //input for the neural network + int deltaPhi = 0; + //n.b, layer might be different then the the stub->layer, because it might be the result of the bending layer (how about eta?) int layer = 0; diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/CandidateSimMuonMatcher.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/CandidateSimMuonMatcher.h index efa54c9b4facc..8cb869fa57d24 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/CandidateSimMuonMatcher.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/CandidateSimMuonMatcher.h @@ -52,19 +52,9 @@ class MatchingResult { MatchingResult() {} - MatchingResult(const SimTrack& simTrack) : simTrack(&simTrack) { - pdgId = simTrack.type(); - genPt = simTrack.momentum().pt(); - genEta = simTrack.momentum().eta(); - genPhi = simTrack.momentum().phi(); - } - - MatchingResult(const TrackingParticle& trackingParticle) : trackingParticle(&trackingParticle) { - pdgId = trackingParticle.pdgId(); - genPt = trackingParticle.pt(); - genEta = trackingParticle.momentum().eta(); - genPhi = trackingParticle.momentum().phi(); - } + MatchingResult(const SimTrack& simTrack, const SimVertex* simVertex); + + MatchingResult(const TrackingParticle& trackingParticle); ResultType result = ResultType::notMatched; //bool propagationFailed = false; @@ -76,19 +66,28 @@ class MatchingResult { double matchingLikelihood = 0; - const l1t::RegionalMuonCand* muonCand = nullptr; - AlgoMuonPtr procMuon; //Processor gbCandidate + FinalMuonPtr muonCand; //to avoid using simTrack or trackingParticle - double pdgId = 0; + int pdgId = 0; + //int parrentPdgId = 0; double genPt = 0; double genEta = 0; double genPhi = 0; + int genCharge = 0; + + float vertexEta = 0; + float vertexPhi = 0; + float muonDxy = 0; + float muonRho = 0; + int parentPdgId = 0; const SimTrack* simTrack = nullptr; const SimVertex* simVertex = nullptr; const TrackingParticle* trackingParticle = nullptr; + + friend std::ostream& operator<<(std::ostream& out, const MatchingResult& matchingResult); }; /* @@ -97,7 +96,8 @@ class MatchingResult { class CandidateSimMuonMatcher : public IOMTFEmulationObserver { public: CandidateSimMuonMatcher(const edm::ParameterSet& edmCfg, - const OMTFConfiguration* omtfConfig, + //const OMTFConfiguration* omtfConfig, + int nProcessors, const edm::ESGetToken& magneticFieldEsToken, const edm::ESGetToken& propagatorEsToken); @@ -110,73 +110,73 @@ class CandidateSimMuonMatcher : public IOMTFEmulationObserver { const std::shared_ptr&, const AlgoMuons& algoCandidates, const AlgoMuons& gbCandidates, - const std::vector& candMuons) override; + const FinalMuons& finalMuons) override; void observeEventBegin(const edm::Event& event) override; - void observeEventEnd(const edm::Event& event, - std::unique_ptr& finalCandidates) override; + void observeEventEnd(const edm::Event& event, FinalMuons& finalMuons) override; void endJob() override; + int calcGlobalPhi(int locPhi, int proc); + //simplified ghost busting - //only candidates in the bx=0 are included - //ghost busts at the same time the mtfCands and the gbCandidates - //gbCandidates - all gbCandidates from all processors, should be one-to-one as the mtfCands, - //and the ghostBustedProcMuons are one-to-onr to the returned RegionalMuonCands - std::vector ghostBust(const l1t::RegionalMuonCandBxCollection* mtfCands, - const AlgoMuons& gbCandidates, - AlgoMuons& ghostBustedProcMuons); + FinalMuons ghostBust(const FinalMuons& finalMuons); FreeTrajectoryState simTrackToFts(const SimTrack& simTrack, const SimVertex& simVertex); FreeTrajectoryState simTrackToFts(const TrackingParticle& trackingParticle); + TrajectoryStateOnSurface atStation1(const FreeTrajectoryState& ftsStart) const; + TrajectoryStateOnSurface atStation2(const FreeTrajectoryState& ftsStart) const; TrajectoryStateOnSurface propagate(const SimTrack& simTrack, const edm::SimVertexContainer* simVertices); TrajectoryStateOnSurface propagate(const TrackingParticle& trackingParticle); - //tsof should be the result of track propagation - MatchingResult match(const l1t::RegionalMuonCand* omtfCand, - const AlgoMuonPtr& procMuon, - const SimTrack& simTrack, - TrajectoryStateOnSurface& tsof); + void propagate(MatchingResult& result); - MatchingResult match(const l1t::RegionalMuonCand* omtfCand, - const AlgoMuonPtr& procMuon, - const TrackingParticle& trackingParticle, - TrajectoryStateOnSurface& tsof); + void match(const FinalMuons& finalMuons, MatchingResult& result, std::vector& matchingResults); - std::vector cleanMatching(std::vector matchingResults, - std::vector& muonCands, - AlgoMuons& ghostBustedProcMuons); + void match(const FinalMuonPtr& finalMuon3, MatchingResult& result); - std::vector match(std::vector& muonCands, - AlgoMuons& ghostBustedProcMuons, + std::vector cleanMatching(std::vector matchingResults, const FinalMuons& finalMuons); + + std::vector match(const FinalMuons& finalMuons, const edm::SimTrackContainer* simTracks, const edm::SimVertexContainer* simVertices, std::function const& simTrackFilter); - std::vector match(std::vector& muonCands, - AlgoMuons& ghostBustedProcMuons, + std::vector match(const FinalMuons& finalMuons, const TrackingParticleCollection* trackingParticles, std::function const& simTrackFilter); //matching without any propagation, just checking basic geometrical agreement between simMuon and candidates //problem with propagation is the it does not work for low pt muons (pt < ~3GeV) //which is not good for dumping the data for the NN training. So for that purpose it is better to use the matchSimple - std::vector matchSimple(std::vector& muonCands, - AlgoMuons& ghostBustedProcMuons, + std::vector matchSimple(const FinalMuons& finalMuons, const edm::SimTrackContainer* simTracks, const edm::SimVertexContainer* simVertices, std::function const& simTrackFilter); + //no matching, just collect muonCands + std::vector collectMuonCands(const FinalMuons& finalMuons); + std::vector getMatchingResults() { return matchingResults; } + enum class MatchingType : short { + noMatcher = -1, + withPropagator = 0, + simplePropagation = 1, + simpleMatching = 2, + collectMuonCands = 3 + }; + + MatchingType getMatchingType() const { return matchingType; } + private: - const OMTFConfiguration* omtfConfig; + int nProcessors = 6; const edm::ParameterSet& edmCfg; @@ -189,10 +189,16 @@ class CandidateSimMuonMatcher : public IOMTFEmulationObserver { edm::ESHandle magField; edm::ESHandle propagator; - TH1D* deltaPhiPropCandMean = nullptr; - TH1D* deltaPhiPropCandStdDev = nullptr; + TH1* minDelta_pos = nullptr; + TH1* maxDelta_pos = nullptr; + TH1* medianDelta_pos = nullptr; + + TH1* minDelta_neg = nullptr; + TH1* maxDelta_neg = nullptr; + TH1* medianDelta_neg = nullptr; - bool usePropagation = false; + MatchingType matchingType = MatchingType::simpleMatching; + //bool usePropagation = false; }; #endif /* L1T_OmtfP1_TOOLS_MUONCANDIDATEMATCHER_H_ */ diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/DataROOTDumper2.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/DataROOTDumper2.h index 1543e9d831525..4d7cbfd872d7a 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/DataROOTDumper2.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/DataROOTDumper2.h @@ -22,6 +22,8 @@ #include "TH2.h" #include +#include +#include class TTree; @@ -35,11 +37,16 @@ struct OmtfEvent { char muonCharge = 0; float muonDxy = 0; float muonRho = 0; + //pdgId in principle should be int + short parentPdgId = 0; + float vertexEta = 0; + float vertexPhi = 0; float omtfPt = 0, omtfEta = 0, omtfPhi = 0, omtfUPt = 0; char omtfCharge = 0; char omtfProcessor = 0; short omtfScore = 0; + short omtfRefHitPhi = 0; short omtfHwEta = 0; @@ -62,9 +69,9 @@ struct OmtfEvent { struct { char layer; char quality; - char z; + char etaHw; char valid; - short eta; + short deltaR; short phiDist; }; }; @@ -72,6 +79,9 @@ struct OmtfEvent { ~Hit() {} }; + // ensure the packed Hit view fits in the unsigned long rawData storage + static_assert(sizeof(Hit) <= sizeof(unsigned long), "OmtfEvent::Hit must fit into unsigned long rawData"); + std::vector hits; }; @@ -88,10 +98,9 @@ class DataROOTDumper2 : public EmulationObserverBase { const std::shared_ptr&, const AlgoMuons& algoCandidates, const AlgoMuons& gbCandidates, - const std::vector& candMuons) override; + const FinalMuons& finalMuons) override; - void observeEventEnd(const edm::Event& iEvent, - std::unique_ptr& finalCandidates) override; + void observeEventEnd(const edm::Event& iEvent, FinalMuons& finalMuons) override; void endJob() override; @@ -109,11 +118,9 @@ class DataROOTDumper2 : public EmulationObserverBase { TH1I* ptGenPos = nullptr; TH1I* ptGenNeg = nullptr; - std::vector hitVsPt; + //std::vector hitVsPt; bool dumpKilledOmtfCands = false; - - bool usePropagation = false; }; #endif /* L1T_OmtfP1_TOOLS_DATAROOTDUMPER2_H_ */ diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/EmulationObserverBase.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/EmulationObserverBase.h index f2e7b90c6831c..18617066fd2d8 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/EmulationObserverBase.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/EmulationObserverBase.h @@ -27,7 +27,7 @@ class EmulationObserverBase : public IOMTFEmulationObserver { const std::shared_ptr& input, const AlgoMuons& algoCandidates, const AlgoMuons& gbCandidates, - const std::vector& candMuons) override; + const FinalMuons& finalMuons) override; void observeEventBegin(const edm::Event& iEvent) override; @@ -41,7 +41,7 @@ class EmulationObserverBase : public IOMTFEmulationObserver { const std::vector findGenMuon(const edm::Event& event); protected: - edm::ParameterSet edmCfg; + const edm::ParameterSet& edmCfg; const OMTFConfiguration* omtfConfig; const SimTrack* simMuon = nullptr; @@ -49,7 +49,7 @@ class EmulationObserverBase : public IOMTFEmulationObserver { //candidate found by omtf in a given event AlgoMuons::value_type omtfCand; - l1t::RegionalMuonCand regionalMuonCand; + FinalMuonPtr finalMuon; //AlgoMuons algoCandidates; diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/EventCapture.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/EventCapture.h index df9f23524226b..3d4e086c4c257 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/EventCapture.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/EventCapture.h @@ -34,12 +34,11 @@ class EventCapture : public IOMTFEmulationObserver { const std::shared_ptr&, const AlgoMuons& algoCandidates, const AlgoMuons& gbCandidates, - const std::vector& candMuons) override; + const FinalMuons& finalMuons) override; void observeEventBegin(const edm::Event& event) override; - void observeEventEnd(const edm::Event& event, - std::unique_ptr& finalCandidates) override; + void observeEventEnd(const edm::Event& event, FinalMuons& finalMuons) override; void endJob() override; diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/PatternGenerator.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/PatternGenerator.h index 6b95241296579..66f53d7f01d7e 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/PatternGenerator.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/PatternGenerator.h @@ -20,8 +20,7 @@ class PatternGenerator : public PatternOptimizerBase { ~PatternGenerator() override; - void observeEventEnd(const edm::Event& iEvent, - std::unique_ptr& finalCandidates) override; + void observeEventEnd(const edm::Event& iEvent, FinalMuons& finalMuons) override; void endJob() override; diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/PatternOptimizerBase.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/PatternOptimizerBase.h index 549d67948f186..50bcfce47f089 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/PatternOptimizerBase.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/PatternOptimizerBase.h @@ -33,8 +33,7 @@ class PatternOptimizerBase : public EmulationObserverBase { ~PatternOptimizerBase() override; - void observeEventEnd(const edm::Event& iEvent, - std::unique_ptr& finalCandidates) override; + void observeEventEnd(const edm::Event& iEvent, FinalMuons& finalMuons) override; void endJob() override; diff --git a/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/StubsSimHitsMatcher.h b/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/StubsSimHitsMatcher.h index aa6796067fcfb..fc52564544e6c 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/StubsSimHitsMatcher.h +++ b/L1Trigger/L1TMuonOverlapPhase1/interface/Tools/StubsSimHitsMatcher.h @@ -9,6 +9,7 @@ #define L1T_OmtfP1_TOOLS_STUBSSIMHITSMATCHER_H_ #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/AlgoMuon.h" +#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/FinalMuon.h" #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFinput.h" #include "FWCore/Framework/interface/EventSetup.h" @@ -39,8 +40,7 @@ class StubsSimHitsMatcher { void endJob(); void match(const edm::Event& iEvent, - const l1t::RegionalMuonCand* omtfCand, - const AlgoMuonPtr& procMuon, + const FinalMuonPtr& finalMuon, std::ostringstream& ostr); //Processor gbCandidate); class MatchedTrackInfo { diff --git a/L1Trigger/L1TMuonOverlapPhase1/plugins/L1TMuonOverlapPhase1TrackProducer.h b/L1Trigger/L1TMuonOverlapPhase1/plugins/L1TMuonOverlapPhase1TrackProducer.h index 4ab0e27c19322..fbf5ccdbeaa7d 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/plugins/L1TMuonOverlapPhase1TrackProducer.h +++ b/L1Trigger/L1TMuonOverlapPhase1/plugins/L1TMuonOverlapPhase1TrackProducer.h @@ -46,7 +46,7 @@ class L1TMuonOverlapPhase1TrackProducer : public edm::one::EDProducer omtfParamsEsToken; - //needed for AngleConverterBase + //needed for OmtfAngleConverter MuonGeometryTokens muonGeometryTokens; ///needed by tools/CandidateSimMuonMatcher.h diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/AngleConverterBase.cc b/L1Trigger/L1TMuonOverlapPhase1/src/AngleConverterBase.cc deleted file mode 100644 index 35c1bde1863e1..0000000000000 --- a/L1Trigger/L1TMuonOverlapPhase1/src/AngleConverterBase.cc +++ /dev/null @@ -1,457 +0,0 @@ -#include "L1Trigger/L1TMuonOverlapPhase1/interface/AngleConverterBase.h" -#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFConfiguration.h" - -#include "DataFormats/CSCDigi/interface/CSCConstants.h" -#include "L1Trigger/DTUtilities/interface/DTTrigGeom.h" - -#include "FWCore/Framework/interface/EventSetup.h" -#include "Geometry/Records/interface/MuonGeometryRecord.h" -#include "Geometry/CSCGeometry/interface/CSCGeometry.h" -#include "Geometry/DTGeometry/interface/DTGeometry.h" -#include "Geometry/RPCGeometry/interface/RPCGeometry.h" -#include "DataFormats/CSCDigi/interface/CSCCorrelatedLCTDigi.h" -#include "DataFormats/L1DTTrackFinder/interface/L1MuDTChambPhDigi.h" -#include "DataFormats/L1DTTrackFinder/interface/L1MuDTChambThContainer.h" -#include "DataFormats/RPCDigi/interface/RPCDigi.h" -#include "FWCore/MessageLogger/interface/MessageLogger.h" - -#include - -namespace { - template - int sgn(T val) { - return (T(0) < val) - (val < T(0)); - } - - int fixCscOffsetGeom(int offsetLoc) { - // fix for CSC geo dependence from GlobalTag - - // dump of CSC offsets for MC global tag - const std::vector offCSC = {-154, -133, -17, -4, 4, 17, 133, 146, 154, 167, 283, 296, 304, 317, - 433, 446, 454, 467, 583, 596, 604, 617, 733, 746, 754, 767, 883, 904}; - auto gep = std::lower_bound(offCSC.begin(), offCSC.end(), offsetLoc); - int fixOff = (gep != offCSC.end()) ? *gep : *(gep - 1); - if (gep != offCSC.begin() && std::abs(*(gep - 1) - offsetLoc) < std::abs(fixOff - offsetLoc)) - fixOff = *(gep - 1); - return fixOff; - } - -} // namespace - -AngleConverterBase::AngleConverterBase() : _geom_cache_id(0ULL) {} -/////////////////////////////////////// -/////////////////////////////////////// -AngleConverterBase::~AngleConverterBase() {} -/////////////////////////////////////// -/////////////////////////////////////// -void AngleConverterBase::checkAndUpdateGeometry(const edm::EventSetup& es, - const ProcConfigurationBase* config, - const MuonGeometryTokens& muonGeometryTokens) { - if (muonGeometryRecordWatcher.check(es)) { - _georpc = es.getHandle(muonGeometryTokens.rpcGeometryEsToken); - _geocsc = es.getHandle(muonGeometryTokens.cscGeometryEsToken); - _geodt = es.getHandle(muonGeometryTokens.dtGeometryEsToken); - } - this->config = config; - nPhiBins = config->nPhiBins(); -} -/////////////////////////////////////// -/////////////////////////////////////// -int AngleConverterBase::getProcessorPhi(int phiZero, l1t::tftype part, int dtScNum, int dtPhi) const { - int dtPhiBins = 4096; - - double hsPhiPitch = 2 * M_PI / nPhiBins; // width of phi Pitch, related to halfStrip at CSC station 2 - - int sector = dtScNum + 1; //NOTE: there is a inconsistency in DT sector numb. Thus +1 needed to get detector numb. - - double scale = 1. / dtPhiBins / hsPhiPitch; - int scale_coeff = lround(scale * pow(2, 11)); // 216.2688 - - int ichamber = sector - 1; - if (ichamber > 6) - ichamber = ichamber - 12; - - int offsetGlobal = (int)nPhiBins * ichamber / 12; - - int phiConverted = floor(dtPhi * scale_coeff / pow(2, 11)) + offsetGlobal - phiZero; - - //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" phiZero "<foldPhi(phi)<foldPhi(phiConverted); -} -/////////////////////////////////////// -/////////////////////////////////////// -int AngleConverterBase::getProcessorPhi( - int phiZero, l1t::tftype part, const CSCDetId& csc, const CSCCorrelatedLCTDigi& digi, unsigned int iInput) const { - const double hsPhiPitch = 2 * M_PI / nPhiBins; - // - // get offset for each chamber. - // FIXME: These parameters depends on processor and chamber only so may be precomputed and put in map - // - - int halfStrip = digi.getStrip(); // returns halfStrip 0..159 - - const CSCChamber* chamber = _geocsc->chamber(csc); - - //in the PhaseIITDRSpring19DR dataset (generated with CMSSW_10_6_1_patch2?), in case of the ME1/1 ring 4 (higher eta) the detId in the CSCCorrelatedLCTDigiCollection is ME1/1 ring 1 (instead ME1/1/4 as it was before), - //and the digi.getStrip() is increased by 2*64 (i.e. number of half strips in the chamber roll) - if (csc.station() == 1 && csc.ring() == 1 && halfStrip > 128) { - CSCDetId cscME11 = CSCDetId(csc.endcap(), csc.station(), 4, csc.chamber()); //changing ring to 4 - chamber = _geocsc->chamber(cscME11); - } - - const CSCChamberSpecs* cspec = chamber->specs(); - const CSCLayer* layer = chamber->layer(3); - int order = (layer->centerOfStrip(2).phi() - layer->centerOfStrip(1).phi() > 0) ? 1 : -1; - double stripPhiPitch = cspec->stripPhiPitch(); - double scale = std::abs(stripPhiPitch / hsPhiPitch / 2.); - if (std::abs(scale - 1.) < 0.0002) - scale = 1.; - - double phiHalfStrip0 = layer->centerOfStrip(1).phi() - order * stripPhiPitch / 4.; - - int offsetLoc = lround((phiHalfStrip0) / hsPhiPitch - phiZero); - offsetLoc = config->foldPhi(offsetLoc); - - if (csc.station() == 1 && csc.ring() == 1 && halfStrip > 128) { //ME1/1/ - /* if(cspec->nStrips() != 64) - edm::LogImportant("l1tOmtfEventPrint") <<__FUNCTION__<<":"<<__LINE__<<" cspec->nStrips() != 64 in case of the ME1/1, phi of the muon stub will be not correct. chamber " - <nStrips() "<nStrips()<nStrips() = 48. but the offset of 128 half strips in the digi.getStrip() looks to be good*/ - halfStrip -= 128; - } - - //FIXME: to be checked (only important for ME1/3) keep more bits for offset, truncate at the end - - int fixOff = offsetLoc; - // a quick fix for towards geometry changes due to global tag. - // in case of MC tag fixOff should be identical to offsetLoc - - if (config->getFixCscGeometryOffset()) { - if (config->nProcessors() == 6) //phase1 - fixOff = fixCscOffsetGeom(offsetLoc); //TODO does not work in when phiZero is always 0. Fix this - else if (config->nProcessors() == 3) { //phase2 - //TODO fix this bricolage!!!!!!!!!!!!!! - if (iInput >= 14) - fixOff = fixCscOffsetGeom(offsetLoc - 900) + 900; - else - fixOff = fixCscOffsetGeom(offsetLoc); - } - } - int phi = fixOff + order * scale * halfStrip; - //the phi conversion is done like above - and not simply converting the layer->centerOfStrip(halfStrip/2 +1).phi() - to mimic this what is done by the firmware, - //where phi of the stub is calculated with use of the offset and scale provided by an register - - /*//debug - auto localPoint = layer->toLocal(layer->centerOfStrip(halfStrip)); - LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << ":" << 147 << " csc: " <id()<<" "<id().rawId() - << " halfStrip "<centerOfStrip(halfStrip).phi()<<" local phi "<foldPhi(phi)<<" ("<centerOfStrip(halfStrip/2 +1).phi() ) - <<" centerOfStrip/hsPhiPitch "<< ( (layer->centerOfStrip(halfStrip/2 + 1).phi() )/hsPhiPitch)<<" hsPhiPitch "<geometry()->phiSpan().first<<" phiSpan.s "<geometry()->phiSpan().second - <<" nStrips "<nStrips() - //<<" strip 1 "<centerOfStrip(1).phi() )<<" strip last "<centerOfStrip(cspec->nStrips()).phi() ) - << std::endl;*/ - - return config->foldPhi(phi); -} - -/////////////////////////////////////// -/////////////////////////////////////// -int AngleConverterBase::getProcessorPhi( - int phiZero, l1t::tftype part, const RPCDetId& rollId, const unsigned int& digi1, const unsigned int& digi2) const { - const double hsPhiPitch = 2 * M_PI / nPhiBins; - const int dummy = nPhiBins; - const RPCRoll* roll = _georpc->roll(rollId); - if (!roll) - return dummy; - - double stripPhi1 = (roll->toGlobal(roll->centreOfStrip((int)digi1))).phi(); // note [-pi,pi] - double stripPhi2 = (roll->toGlobal(roll->centreOfStrip((int)digi2))).phi(); // note [-pi,pi] - - // the case when the two strips are on different sides of phi = pi - if (std::signbit(stripPhi1) != std::signbit(stripPhi2) && std::abs(stripPhi1) > M_PI / 2.) { - if (std::signbit(stripPhi1)) { //stripPhi1 is negative - stripPhi1 += 2 * M_PI; - } else //stripPhi2 is negative - stripPhi2 += 2 * M_PI; - } - int halfStrip = lround(((stripPhi1 + stripPhi2) / 2.) / hsPhiPitch); - halfStrip = config->foldPhi(halfStrip); //only for the case when the two strips are on different sides of phi = pi - - LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << ":" << 185 << " roll " << rollId.rawId() << " " << rollId - << " cluster: firstStrip " << digi1 << " stripPhi1Global " << stripPhi1 - << " stripPhi1LocalPhi " << roll->centreOfStrip((int)digi1).x() << " y " - << roll->centreOfStrip((int)digi1).y() << " lastStrip " << digi2 << " stripPhi2Global " - << stripPhi2 << " stripPhi2LocalPhi x " << roll->centreOfStrip((int)digi2).x() << " y " - << roll->centreOfStrip((int)digi2).y() << " halfStrip " << halfStrip << std::endl; - - return config->foldPhi(halfStrip - phiZero); -} - -int AngleConverterBase::getProcessorPhi(unsigned int iProcessor, - l1t::tftype part, - const RPCDetId& rollId, - const unsigned int& digi) const { - const double hsPhiPitch = 2 * M_PI / nPhiBins; - const int dummy = nPhiBins; - int processor = iProcessor + 1; - const RPCRoll* roll = _georpc->roll(rollId); - if (!roll) - return dummy; - - double phi15deg = M_PI / 3. * (processor - 1) + M_PI / 12.; - // "0" is 15degree moved cyclically to each processor, note [0,2pi] - - double stripPhi = (roll->toGlobal(roll->centreOfStrip((int)digi))).phi(); // note [-pi,pi] - - // adjust [0,2pi] and [-pi,pi] to get deltaPhi difference properly - switch (processor) { - case 1: - break; - case 6: { - phi15deg -= 2 * M_PI; - break; - } - default: { - if (stripPhi < 0) - stripPhi += 2 * M_PI; - break; - } - } - - // local angle in CSC halfStrip usnits - int halfStrip = lround((stripPhi - phi15deg) / hsPhiPitch); - - return halfStrip; -} -/////////////////////////////////////// -/////////////////////////////////////// -EtaValue AngleConverterBase::getGlobalEtaDt(const DTChamberId& detId) const { - Local2DPoint chamberMiddleLP(0, 0); - GlobalPoint chamberMiddleGP = _geodt->chamber(detId)->toGlobal(chamberMiddleLP); - - const DTChamberId baseidNeigh(detId.wheel() + (detId.wheel() >= 0 ? -1 : +1), detId.station(), detId.sector()); - GlobalPoint chambNeighMiddleGP = _geodt->chamber(baseidNeigh)->toGlobal(chamberMiddleLP); - - EtaValue etaValue = { - config->etaToHwEta(chamberMiddleGP.eta()), - config->etaToHwEta(std::abs(chamberMiddleGP.eta() - chambNeighMiddleGP.eta())) / 2, - 0, //quality - 0, //bx - 0 //timin - }; - - //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" rawid "<& etaSegments) const { - const DTChamberId baseid(thetaDigi.whNum(), thetaDigi.stNum(), thetaDigi.scNum() + 1); - DTTrigGeom trig_geom(_geodt->chamber(baseid), false); - - // super layer 2 is the theta superlayer in a DT chamber - // station 4 does not have a theta super layer - // the BTI index from the theta trigger is an OR of some BTI outputs - // so, we choose the BTI that's in the middle of the group - // as the BTI that we get theta from - // TODO:::::>>> need to make sure this ordering doesn't flip under wheel sign - const int NBTI_theta = trig_geom.nCell(2); - for (unsigned int btiGroup = 0; btiGroup < 7; ++btiGroup) { - if (thetaDigi.position(btiGroup)) { - unsigned btiActual = btiGroup * NBTI_theta / 7 + NBTI_theta / 14 + 1; - DTBtiId thetaBTI = DTBtiId(baseid, 2, btiActual); - GlobalPoint theta_gp = trig_geom.CMSPosition(thetaBTI); - - EtaValue etaValue = { - config->etaToHwEta(theta_gp.eta()), - 0, - thetaDigi.quality(btiGroup), - thetaDigi.bxNum(), - 0 //TODO what about sub-bx timing??? - }; - etaSegments.emplace_back(etaValue); - - //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" bx "< AngleConverterBase::getGlobalEta(const L1MuDTChambThContainer* dtThDigis, - int bxFrom, - int bxTo) const { - //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" dtThDigis size "<getContainer()->size()< etaSegments; - - for (auto& thetaDigi : (*(dtThDigis->getContainer()))) { - if (thetaDigi.bxNum() >= bxFrom && thetaDigi.bxNum() <= bxTo) { - getGlobalEta(thetaDigi, etaSegments); - } - } - return etaSegments; -} - -//just read from the drawing -float AngleConverterBase::cscChamberEtaSize(const CSCDetId& detId) const { - if (detId.station() == 1) { - if (detId.ring() == 1) - return (2.5 - 1.6) / 2.; - ///ME1/1 lower eta (b?, eta < ~2.1), L1TkMuonBayes eta bins 6-11 - but getGlobalEtaCsc(const CSCDetId& detId) gives the midle of the full chamber, so here we put the size of the full chamber - if (detId.ring() == 2) - return (1.7 - 1.2) / 2.; - if (detId.ring() == 3) - return (1.12 - 0.9) / 2.; - if (detId.ring() == 4) - return (2.5 - 1.6) / 2.; ///ME1/1 higher eta (a?, eta > ~2.1), L1TkMuonBayes eta bins 10-15 - } else if (detId.station() == 2) { - if (detId.ring() == 1) - return (2.5 - 1.6) / 2.; - if (detId.ring() == 2) - return (1.6 - 1.0) / 2.; - } else if (detId.station() == 3) { - if (detId.ring() == 1) - return (2.5 - 1.7) / 2.; - if (detId.ring() == 2) - return (1.7 - 1.1) / 2.; - } else if (detId.station() == 4) { - if (detId.ring() == 1) - return (2.45 - 1.8) / 2.; - if (detId.ring() == 2) - return (1.8 - 1.2) / 2.; - } - return 0; -} - -EtaValue AngleConverterBase::getGlobalEta(const CSCDetId& detId, const CSCCorrelatedLCTDigi& aDigi) const { - ///Code taken from GeometryTranslator. - ///Will be replaced by direct CSC phi local to global scale - ///transformation as used in FPGA implementation - - // alot of this is transcription and consolidation of the CSC - // global phi calculation code - // this works directly with the geometry - // rather than using the old phi luts - - auto chamb = _geocsc->chamber(detId); - auto layer_geom = chamb->layer(CSCConstants::KEY_ALCT_LAYER)->geometry(); - auto layer = chamb->layer(CSCConstants::KEY_ALCT_LAYER); - - const uint16_t keyWG = aDigi.getKeyWG(); - - const LocalPoint lpWg = layer_geom->localCenterOfWireGroup(keyWG); - const GlobalPoint gpWg = layer->surface().toGlobal(lpWg); - - EtaValue etaSegment = { - config->etaToHwEta(gpWg.eta()), - 0, //config->etaToHwEta(cscChamberEtaSize(id) ), - 0, - aDigi.getBX(), - 0 //tming??? - }; - - //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" csc "<chamber(detId); - - Local2DPoint chamberMiddleLP(0, 0); - GlobalPoint chamberMiddleGP = chamb->toGlobal(chamberMiddleLP); - - EtaValue etaValue = { - config->etaToHwEta(chamberMiddleGP.eta()), - config->etaToHwEta(cscChamberEtaSize(detId)), - 0, - 0, //bx - 0 //timnig - }; - - //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" rawid "<roll(id); - const LocalPoint lp = roll->centreOfStrip((int)strip); - const GlobalPoint gp = roll->toGlobal(lp); - - int neighbRoll = 1; //neighbor roll in eta - //roll->chamber()->nrolls() does not work - if (id.region() == 0) { //barel - if (id.station() == 2 && ((std::abs(id.ring()) == 2 && id.layer() == 2) || - (std::abs(id.ring()) != 2 && id.layer() == 1))) { //three-roll chamber - if (id.roll() == 2) - neighbRoll = 1; - else { - neighbRoll = 2; - } - } else //two-roll chamber - neighbRoll = (id.roll() == 1 ? 3 : 1); - } else { //endcap - neighbRoll = id.roll() + (id.roll() == 1 ? +1 : -1); - } - - const RPCDetId idNeigh = - RPCDetId(id.region(), id.ring(), id.station(), id.sector(), id.layer(), id.subsector(), neighbRoll); - //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" rpc "<roll(idNeigh); - const LocalPoint lpNeigh = rollNeigh->centreOfStrip((int)strip); - const GlobalPoint gpNeigh = rollNeigh->toGlobal(lpNeigh); - - EtaValue etaValue = {config->etaToHwEta(gp.eta()), - config->etaToHwEta(std::abs(gp.eta() - gpNeigh.eta())) / - 2, //half of the size of the strip in eta - not precise, but OK - 0}; - - //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" rpc "<geometry()->numberOfStrips(); - const double phi1 = layer->centerOfStrip(1).phi(); - const double phiN = layer->centerOfStrip(nStrips).phi(); - return ((std::abs(phi1 - phiN) < M_PI && phi1 >= phiN) || (std::abs(phi1 - phiN) >= M_PI && phi1 < phiN)); -} -/////////////////////////////////////// -/////////////////////////////////////// -const int AngleConverterBase::findBTIgroup(const L1MuDTChambPhDigi& aDigi, const L1MuDTChambThContainer* dtThDigis) { - int bti_group = -1; - - const L1MuDTChambThDigi* theta_segm = - dtThDigis->chThetaSegm(aDigi.whNum(), aDigi.stNum(), aDigi.scNum(), aDigi.bxNum()); - if (!theta_segm) - return bti_group; - - for (unsigned int i = 0; i < 7; ++i) { - if (theta_segm->position(i) && bti_group < 0) - bti_group = i; - ///If there are more than one theta digi we do not take is - ///due to unresolved ambiguity. In this case we take eta of the - ///middle of the chamber. - else if (theta_segm->position(i) && bti_group > -1) - return -1; - } - - return bti_group; -} -/////////////////////////////////////// -/////////////////////////////////////// diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/MuonStubMakerBase.cc b/L1Trigger/L1TMuonOverlapPhase1/src/MuonStubMakerBase.cc index 459a1d9c0b953..41200216c4d5c 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/MuonStubMakerBase.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/MuonStubMakerBase.cc @@ -54,6 +54,8 @@ void CscDigiToStubsConverter::makeStubs(MuonStubPtrs2D& muonStubsInLayers, int bxFrom, int bxTo, std::vector >& observers) { + boost::property_tree::ptree procDataTree; + auto chamber = cscDigis->begin(); auto chend = cscDigis->end(); for (; chamber != chend; ++chamber) { @@ -65,14 +67,32 @@ void CscDigiToStubsConverter::makeStubs(MuonStubPtrs2D& muonStubsInLayers, auto digi = (*chamber).second.first; auto dend = (*chamber).second.second; + + auto& cscChamber = procDataTree.add_child("cscChamber", boost::property_tree::ptree()); + cscChamber.add(".name", csc.chamberName()); + for (; digi != dend; ++digi) { ///Check if LCT trigger primitive has the right BX. int digiBx = digi->getBX() - config->cscLctCentralBx(); if (digiBx >= bxFrom && digiBx <= bxTo) addCSCstubs(muonStubsInLayers, rawid, *digi, iProcessor, procTyp); + + auto& cscDigi = cscChamber.add_child("cscDigi", boost::property_tree::ptree()); + cscDigi.add(".halfStrip", digi->getStrip()); + cscDigi.add(".keyWG", digi->getKeyWG()); + cscDigi.add(".pattern", digi->getPattern()); + cscDigi.add(".slope", digi->getSlope()); + cscDigi.add(".bend", digi->getBend()); + cscDigi.add(".fractionalSlope", digi->getFractionalSlope()); + cscDigi.add(".quality", digi->getQuality()); + cscDigi.add(".QuartStrip", (int)(digi->getQuartStripBit())); + cscDigi.add(".eighthStrip", (int)(digi->getEighthStripBit())); } } + + for (auto& obs : observers) + obs->addProcesorData("cscData", procDataTree); } void RpcDigiToStubsConverter::makeStubs(MuonStubPtrs2D& muonStubsInLayers, diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/FinalMuon.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/FinalMuon.cc new file mode 100644 index 0000000000000..823c873efdabb --- /dev/null +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/FinalMuon.cc @@ -0,0 +1,25 @@ +/* + * FinalMuon.cc + * + * Created on: Nov 10, 2025 + * Author: kbunkow + */ + +#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/FinalMuon.h" + +#include +#include + +std::ostream &operator<<(std::ostream &out, const FinalMuon &finalMuon) { + out << "finalMuon"; + out << " pt " << std::setw(8) << finalMuon.ptGev << " GeV"; + out << " phi " << std::setw(8) << finalMuon.phiRad; + out << " sign " << std::setw(2) << finalMuon.sign; + out << " eta " << std::setw(8) << finalMuon.etaRad; + out << " ptGmt " << std::setw(8) << finalMuon.getPtGmt(); + out << " etaGmt " << std::setw(8) << finalMuon.getEtaGmt(); + out << " phiGmt " << std::setw(8) << finalMuon.getPhiGmt(); + //<< " hwPhi " << muonCand->hwPhi(); + out << " hwQual " << finalMuon.getQuality() << " processor " << finalMuon.getProcessor(); + return out; +} diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GhostBuster.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GhostBuster.cc index 7cc8378a4ab76..674014ce85959 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GhostBuster.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GhostBuster.cc @@ -40,7 +40,8 @@ AlgoMuons GhostBuster::select(AlgoMuons refHitCands, int charge) { //do not accept candidates with similar phi (any charge combination) //veto window 5deg(=half of logic cone)=5/360*5760=80"logic strips" //veto window 5 degree in GMT scale is 5/360*576=8 units - if (std::abs(omtfConfig->procPhiToGmtPhi((*it1)->getPhi()) - omtfConfig->procPhiToGmtPhi((*it2)->getPhi())) < 8) { + if (std::abs(omtfConfig->procPhiToGmtPhase1Phi((*it1)->getPhi()) - + omtfConfig->procPhiToGmtPhase1Phi((*it2)->getPhi())) < 8) { // if(std::abs(it1->getPhi() - it2->getPhi())<5/360.0*nPhiBins){ isGhost = true; break; diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GhostBusterPreferRefDt.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GhostBusterPreferRefDt.cc index 4da5c102f5d3f..9040241b231cf 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GhostBusterPreferRefDt.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GhostBusterPreferRefDt.cc @@ -105,12 +105,55 @@ AlgoMuons GhostBusterPreferRefDt::select(AlgoMuons muonsIN, int charge) { return true; }; + //this function is for the OMTF version with unconstrained pt, if the DT ref hits with quality 2 are allowed + auto customByRefLayerAndHitQual = [&](const AlgoMuons::value_type& a, const AlgoMuons::value_type& b) -> bool { + if (!a->isValid()) { + return true; + } + if (!b->isValid()) { + return false; + } + + int aRefLayerLogicNum = omtfConfig->getRefToLogicNumber()[a->getRefLayer()]; + int aRefHitQual = 0; + //MB1 or MB2, i.e. the station for which extrapolation is done + if (aRefLayerLogicNum == 0 || aRefLayerLogicNum == 2) { + aRefHitQual = a->getStubResult(aRefLayerLogicNum).getMuonStub()->qualityHw; + aRefHitQual = aRefHitQual >= 4 ? 1 : 0; + } + + int bRefLayerLogicNum = omtfConfig->getRefToLogicNumber()[b->getRefLayer()]; + int bRefHitQual = 0; + if (bRefLayerLogicNum == 0 || bRefLayerLogicNum == 2) { + bRefHitQual = b->getStubResult(bRefLayerLogicNum).getMuonStub()->qualityHw; + bRefHitQual = bRefHitQual >= 4 ? 1 : 0; + } + + if (aRefHitQual > bRefHitQual) + return false; + else if (aRefHitQual == bRefHitQual && aRefLayerLogicNum < bRefLayerLogicNum) + return false; + else if (aRefHitQual == bRefHitQual && aRefLayerLogicNum == bRefLayerLogicNum && a->getPdfSum() > b->getPdfSum()) + return false; + else if (aRefHitQual == bRefHitQual && aRefLayerLogicNum == bRefLayerLogicNum && a->getPdfSum() == b->getPdfSum() && + a->getPatternNumConstr() > b->getPatternNumConstr()) + //should be rather getPatternNum(), but for FW getPatternNumConstr() is easier + return false; + else if (aRefHitQual == bRefHitQual && aRefLayerLogicNum == bRefLayerLogicNum && a->getPdfSum() == b->getPdfSum() && + a->getPatternNumConstr() == b->getPatternNumConstr()) + return false; + else + return true; + }; + if (omtfConfig->getGhostBusterType() == "byLLH") std::sort(muonsIN.rbegin(), muonsIN.rend(), customLessByLLH); else if (omtfConfig->getGhostBusterType() == "byFPLLH") std::sort(muonsIN.rbegin(), muonsIN.rend(), customLessByFPLLH); else if (omtfConfig->getGhostBusterType() == "byRefLayer") std::sort(muonsIN.rbegin(), muonsIN.rend(), customByRefLayer); + else if (omtfConfig->getGhostBusterType() == "byRefLayerAndHitQual") + std::sort(muonsIN.rbegin(), muonsIN.rend(), customByRefLayerAndHitQual); else std::sort(muonsIN.rbegin(), muonsIN.rend(), customLess); @@ -139,8 +182,8 @@ AlgoMuons GhostBusterPreferRefDt::select(AlgoMuons muonsIN, int charge) { for (unsigned int iMu2 = refHitCleanCandsFixedEta.size() - 1; iMu2 >= iMu1 + 1; iMu2--) { auto& muIN2 = refHitCleanCandsFixedEta[iMu2]; - if (muIN2->isValid() && - std::abs(omtfConfig->procPhiToGmtPhi(muIN1->getPhi()) - omtfConfig->procPhiToGmtPhi(muIN2->getPhi())) < 8) { + if (muIN2->isValid() && std::abs(omtfConfig->procPhiToGmtPhase1Phi(muIN1->getPhi()) - + omtfConfig->procPhiToGmtPhase1Phi(muIN2->getPhi())) < 8) { //the candidates are sorted, so only the muIN2 can be killed, as it is "worse" than the muIN1 refHitCleanCandsFixedEta[iMu2]->kill(); refHitCleanCandsFixedEta[iMu1]->getKilledMuons().emplace_back(muIN2); @@ -152,9 +195,10 @@ AlgoMuons GhostBusterPreferRefDt::select(AlgoMuons muonsIN, int charge) { //The condition abs(muIN2->getEtaHw()) != 121 was added in the FW in 2024 //TODO add 95 meaning no DT segment was found, or don't use 95 in OmtfAngleConverter::getGlobalEta if (omtfConfig->getRefToLogicNumber()[muIN1->getRefLayer()] <= 5 && (omtfConfig->fwVersion() >= 6) && - (abs(muIN1->getEtaHw()) == 75 || abs(muIN1->getEtaHw()) == 79 || abs(muIN1->getEtaHw()) == 92) && - (abs(muIN2->getEtaHw()) != 75 && abs(muIN2->getEtaHw()) != 79 && abs(muIN2->getEtaHw()) != 92 && - abs(muIN2->getEtaHw()) != 121)) { + (abs(muIN1->getEtaHw()) == omtfConfig->mb1W2Eta() || abs(muIN1->getEtaHw()) == omtfConfig->mb2W2Eta() || + abs(muIN1->getEtaHw()) == omtfConfig->mb3W2Eta()) && + (abs(muIN2->getEtaHw()) != omtfConfig->mb1W2Eta() && abs(muIN2->getEtaHw()) != omtfConfig->mb2W2Eta() && + abs(muIN2->getEtaHw()) != omtfConfig->mb3W2Eta() && abs(muIN2->getEtaHw()) != 121)) { muIN1->setEta(muIN2->getEtaHw()); } } diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GoldenPattern.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GoldenPattern.cc index 180d08735ca39..40aa39514ab4b 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GoldenPattern.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GoldenPattern.cc @@ -11,8 +11,7 @@ int GoldenPattern::meanDistPhiValue(unsigned int iLayer, unsigned int iRefLayer, //////////////////////////////////////////////////// //////////////////////////////////////////////////// -int GoldenPattern::propagateRefPhi(int phiRef, int etaRef, unsigned int iRefLayer) { - unsigned int iLayer = 2; //MB2 +int GoldenPattern::propagateRefPhi(int phiRef, int etaRef, unsigned int iRefLayer, unsigned int iLayer) { return phiRef + meanDistPhi[iLayer][iRefLayer][0]; //FIXME if the meanDistPhiAlpha is non-zero, then meanDistPhi is alone not good for propagation of the phi //other value should be used, or the ref_layer phiB should be included diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GoldenPatternBase.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GoldenPatternBase.cc index ef381e721267e..e03c7f2c3c43b 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GoldenPatternBase.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GoldenPatternBase.cc @@ -51,6 +51,7 @@ StubResult GoldenPatternBase::process1Layer1RefLayer(unsigned int iRefLayer, int phiMean = this->meanDistPhiValue(iLayer, iRefLayer, refStub->phiBHw); int phiDistMin = myOmtfConfig->nPhiBins(); + int deltaPhiSel = myOmtfConfig->nPhiBins(); ///Select hit closest to the mean of probability ///distribution in given layer @@ -78,7 +79,9 @@ StubResult GoldenPatternBase::process1Layer1RefLayer(unsigned int iRefLayer, if (hitPhi >= (int)myOmtfConfig->nPhiBins()) //TODO is this needed now? the empty hit will be empty stub continue; //empty itHits are marked with nPhiBins() in OMTFProcessor::restrictInput - int phiDist = this->myOmtfConfig->foldPhi(hitPhi - extrapolatedPhi[iStub] - phiMean - phiRefHit); + int deltaPhi = hitPhi - extrapolatedPhi[iStub] - phiRefHit; + int phiDist = deltaPhi - phiMean; + //int phiDist = this->myOmtfConfig->foldPhi(hitPhi - extrapolatedPhi[iStub] - phiMean - phiRefHit); /*LogTrace("l1tOmtfEventPrint") <<"\n"<<__FUNCTION__<<":"<<__LINE__<<" "<myOmtfConfig->isNoHitValueInPdf()) pdfVal = this->pdfValue(iLayer, iRefLayer, 0); - return StubResult(pdfVal, false, myOmtfConfig->nPhiBins(), iLayer, selectedStub); + return StubResult(pdfVal, false, myOmtfConfig->nPhiBins(), myOmtfConfig->nPhiBins(), iLayer, selectedStub); } int pdfMiddle = 1 << (myOmtfConfig->nPdfAddrBits() - 1); @@ -113,7 +117,7 @@ StubResult GoldenPatternBase::process1Layer1RefLayer(unsigned int iRefLayer, ///Check if phiDistMin is within pdf range -63 +63 ///in firmware here the arithmetic "value and sign" is used, therefore the range is -63 +63, and not -64 +63 if (std::abs(phiDistMin) > ((1 << (myOmtfConfig->nPdfAddrBits() - 1)) - 1)) { - return StubResult(0, false, phiDistMin + pdfMiddle, iLayer, selectedStub); + return StubResult(0, false, phiDistMin + pdfMiddle, deltaPhiSel, iLayer, selectedStub); //in some algorithms versions with thresholds we use the bin 0 to store the pdf value returned when there was no hit. //in the version without thresholds, the value in the bin 0 should be 0 @@ -124,9 +128,9 @@ StubResult GoldenPatternBase::process1Layer1RefLayer(unsigned int iRefLayer, //if (this->getDistPhiBitShift(iLayer, iRefLayer) != 0) LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" phiDistMin "<pdfValue(iLayer, iRefLayer, phiDistMin); if (pdfVal <= 0) { - return StubResult(0, false, phiDistMin, iLayer, selectedStub); + return StubResult(0, false, phiDistMin, deltaPhiSel, iLayer, selectedStub); } - return StubResult(pdfVal, true, phiDistMin, iLayer, selectedStub); + return StubResult(pdfVal, true, phiDistMin, deltaPhiSel, iLayer, selectedStub); } //////////////////////////////////////////////////// diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GoldenPatternResult.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GoldenPatternResult.cc index 5577c55e38f84..21b94c60dc70b 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GoldenPatternResult.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/GoldenPatternResult.cc @@ -35,16 +35,6 @@ void GoldenPatternResult::set(int refLayer_, int phi, int eta, int refHitPhi) { this->refHitPhi = refHitPhi; } -void GoldenPatternResult::setStubResult(float pdfVal, bool valid, int pdfBin, int layer, MuonStubPtr stub) { - if (valid) { - //pdfSum and firedLayerBits is calculated in finaliseX() - firedLayerBits |= (1 << layer); - } - stubResults[layer] = StubResult(pdfVal, valid, pdfBin, layer, stub); - - //stub result is added even thought it is not valid since this might be needed for debugging or optimization -} - void GoldenPatternResult::setStubResult(int layer, StubResult& stubResult) { if (stubResult.getValid()) { //pdfSum and firedLayerBits is calculated in finaliseX() @@ -364,8 +354,8 @@ void GoldenPatternResult::finalise10() { //the efficiency difference between quality 8 and 12 seems to be at a level of 1-2% //but in the uGT menu e.g. the L1_DoubleMu0_Upt6_IP_Min1_Upt4 uses quality >= 0, so should be OK - //hard cut - the phiB of the refHit must fit to the pdfS - //but this cut has sometimes side effect: there can be a muon which has has pdfSum = 0 for every pattern, + //hard cut for the contstrainedPt - the phiB of the refHit must fit to the pdf + //but this cut has sometimes side effect: it can result in a muon which has pdfSum = 0 for every pattern, //then in the OMTFSorter::sortRefHitResults the first pattern that has FiredLayerCnt >= 3 is chosen //and not the one with highest pdfSum as it should be //TODO what should be done is to set the pt of such a muons to 0, but after the sorter. diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFConfiguration.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFConfiguration.cc index 4e870e55e6c30..ea1cde892c7e4 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFConfiguration.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFConfiguration.cc @@ -299,6 +299,19 @@ void OMTFConfiguration::configureFromEdmParameterSet(const edm::ParameterSet &ed if (edmParameterSet.exists("cleanStubs")) { cleanStubs_ = edmParameterSet.getParameter("cleanStubs"); } + + if (edmParameterSet.exists("usePhase2DTPrimitives")) { + usePhase2DTPrimitives_ = edmParameterSet.getParameter("usePhase2DTPrimitives"); + } + + //phase-2 + if (getStubEtaEncoding() == ProcConfigurationBase::StubEtaEncoding::valueP2Scale) { + //in DataFormats/L1TMuonPhase2/interface/Constants.h BITSETA = 13 + //for OMTF we reduce the precision + const int BITSETA = 13 - 2; + const float LSBeta = 2. * M_PI / pow(2, BITSETA); + etaUnit_ = LSBeta; + } } /////////////////////////////////////////////// @@ -399,15 +412,6 @@ uint32_t OMTFConfiguration::getLayerNumber(uint32_t rawId) const { return hwNumber; } -int OMTFConfiguration::calcGlobalPhi(int locPhi, int proc) const { - int globPhi = 0; - //60 degree sectors = 96 in int-scale - globPhi = (proc) * 96 * 6 / nProcessors() + locPhi; - // 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; - return globPhi; -} - unsigned int OMTFConfiguration::eta2Bits(unsigned int eta) { if (eta == 73) return 0b100000000; @@ -524,36 +528,29 @@ int OMTFConfiguration::etaBit2Code(unsigned int bit) { /////////////////////////////////////////////// // phiRad should be in the range [-pi,pi] int OMTFConfiguration::getProcScalePhi(unsigned int iProcessor, double phiRad) const { - double phi15deg = - M_PI / 3. * (iProcessor) + M_PI / 12.; // "0" is 15degree moved cyclically to each processor, note [0,2pi] + // "0" is 15degree moved cyclically to each processor, note [0,2pi] + double phi15deg = 2 * M_PI / nProcessors() * (iProcessor) + M_PI / 12.; const double phiUnit = 2 * M_PI / nPhiBins(); //rad/unit // adjust [0,2pi] and [-pi,pi] to get deltaPhi difference properly - switch (iProcessor + 1) { - case 1: - break; - case 6: { - phi15deg -= 2 * M_PI; - break; - } - default: { - if (phiRad < 0) - phiRad += 2 * M_PI; - break; - } - } + if ((iProcessor + 1) == nProcessors()) + phi15deg -= 2 * M_PI; + else if (phiRad < 0) + phiRad += 2 * M_PI; // local angle in CSC halfStrip usnits return lround((phiRad - phi15deg) / phiUnit); //FIXME lround or floor ??? } -/////////////////////////////////////////////// -/////////////////////////////////////////////// -double OMTFConfiguration::procHwPhiToGlobalPhi(int procHwPhi, int procHwPhi0) const { - int globalHwPhi = foldPhi(procHwPhi + procHwPhi0); - const double phiUnit = 2 * M_PI / nPhiBins(); //rad/unit - return globalHwPhi * phiUnit; +//returns the global phi in the OMTF scale +int OMTFConfiguration::procPhiOmtfToGlobalPhiOmtf(unsigned int iProcessor, int procHwPhi) const { + //24 is 360 deg / 15 deg, 15 deg is the offset of the processor internal scale versus CMS phi = 0 rad + int globalPhi = iProcessor * nPhiBins() / nProcessors() + procHwPhi + nPhiBins() / 24; + // Handle wrap-around with %. Add nPhiBins to make sure the number is positive + globalPhi = (globalPhi + nPhiBins()) % nPhiBins(); + + return globalPhi; } /////////////////////////////////////////////// @@ -606,5 +603,7 @@ void OMTFConfiguration::printConfig() const { edm::LogVerbatim("OMTFReconstruction") << "useEndcapStubsRInExtr " << useEndcapStubsRInExtr_ << std::endl; edm::LogVerbatim("OMTFReconstruction") << "dtRefHitMinQuality " << dtRefHitMinQuality << std::endl; + edm::LogVerbatim("OMTFReconstruction") << "etaUnit_ " << etaUnit_ << std::endl; + edm::LogVerbatim("OMTFReconstruction") << "cleanStubs " << cleanStubs_ << std::endl; } diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFProcessor.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFProcessor.cc index cc54c465a2201..e849f9f12ad02 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFProcessor.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFProcessor.cc @@ -28,6 +28,7 @@ #include #include +#include /////////////////////////////////////////////// /////////////////////////////////////////////// @@ -62,7 +63,8 @@ void OMTFProcessor::init(const edm::ParameterSet& edmCfg, edm if (this->myOmtfConfig->getGhostBusterType() == "GhostBusterPreferRefDt" || this->myOmtfConfig->getGhostBusterType() == "byLLH" || this->myOmtfConfig->getGhostBusterType() == "byFPLLH" || - this->myOmtfConfig->getGhostBusterType() == "byRefLayer") { + this->myOmtfConfig->getGhostBusterType() == "byRefLayer" || + this->myOmtfConfig->getGhostBusterType() == "byRefLayerAndHitQual") { setGhostBuster(new GhostBusterPreferRefDt(this->myOmtfConfig)); edm::LogVerbatim("OMTFReconstruction") << "setting " << this->myOmtfConfig->getGhostBusterType() << std::endl; } else { @@ -84,8 +86,8 @@ void OMTFProcessor::init(const edm::ParameterSet& edmCfg, edm } if (this->myOmtfConfig->usePhiBExtrapolationMB1() || this->myOmtfConfig->usePhiBExtrapolationMB2()) { - extrapolFactors.resize(2, std::vector >(this->myOmtfConfig->nLayers())); - extrapolFactorsNorm.resize(2, std::vector >(this->myOmtfConfig->nLayers())); + extrapolFactors.resize(2 * 3, std::vector >(this->myOmtfConfig->nLayers())); + extrapolFactorsNorm.resize(2 * 3, std::vector >(this->myOmtfConfig->nLayers())); //when useFloatingPointExtrapolation is true the extrapolFactors are not used, //all calculations are done in the extrapolateDtPhiBFloatPoint @@ -98,211 +100,263 @@ void OMTFProcessor::init(const edm::ParameterSet& edmCfg, edm } template -std::vector OMTFProcessor::getFinalcandidates(unsigned int iProcessor, - l1t::tftype mtfType, - const AlgoMuons& algoCands) { - std::vector result; +void OMTFProcessor::assignQuality(AlgoMuons::value_type& algoMuon) { + unsigned int quality = 12; + if (this->myOmtfConfig->fwVersion() <= 6) + quality = checkHitPatternValidity(algoMuon->getFiredLayerBits()) ? 0 | (1 << 2) | (1 << 3) : 0 | (1 << 2); //12 : 4 + unsigned int firedLayerBits = static_cast(algoMuon->getFiredLayerBits()); + if (abs(algoMuon->getEtaHw()) == 115 && //115 is eta 1.25 rrrrrrrrccccdddddd + (firedLayerBits == std::bitset<18>("100000001110000000").to_ulong() || + firedLayerBits == std::bitset<18>("000000001110000000").to_ulong() || + firedLayerBits == std::bitset<18>("100000000110000000").to_ulong() || + firedLayerBits == std::bitset<18>("100000001100000000").to_ulong() || + firedLayerBits == std::bitset<18>("100000001010000000").to_ulong())) { + if (this->myOmtfConfig->fwVersion() <= 6) + quality = 4; + else + quality = 1; + } - for (auto& myCand : algoCands) { - l1t::RegionalMuonCand candidate; + if (this->myOmtfConfig->fwVersion() >= 5 && this->myOmtfConfig->fwVersion() <= 6) { + if (firedLayerBits == std::bitset<18>("000000010000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000000100000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000001000000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000010000000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000100000000000011").to_ulong() || + firedLayerBits == std::bitset<18>("001000000000000011").to_ulong() || + firedLayerBits == std::bitset<18>("010000000000000011").to_ulong() || + firedLayerBits == std::bitset<18>("100000000000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000000010000001100").to_ulong() || + firedLayerBits == std::bitset<18>("000000100000001100").to_ulong() || + firedLayerBits == std::bitset<18>("000001000000001100").to_ulong() || + firedLayerBits == std::bitset<18>("000010000000001100").to_ulong() || + firedLayerBits == std::bitset<18>("000100000000001100").to_ulong() || + firedLayerBits == std::bitset<18>("001000000000001100").to_ulong() || + firedLayerBits == std::bitset<18>("010000000000001100").to_ulong() || + firedLayerBits == std::bitset<18>("100000000000001100").to_ulong() || + firedLayerBits == std::bitset<18>("000000010000110000").to_ulong() || + firedLayerBits == std::bitset<18>("000000100000110000").to_ulong() || + firedLayerBits == std::bitset<18>("000001000000110000").to_ulong() || + firedLayerBits == std::bitset<18>("000010000000110000").to_ulong() || + firedLayerBits == std::bitset<18>("000100000000110000").to_ulong() || + firedLayerBits == std::bitset<18>("001000000000110000").to_ulong() || + firedLayerBits == std::bitset<18>("010000000000110000").to_ulong() || + firedLayerBits == std::bitset<18>("100000000000110000").to_ulong()) + quality = 1; + } else if (this->myOmtfConfig->fwVersion() >= 8) { //TODO fix the fwVersion rrrrrrrrccccdddddd + if (firedLayerBits == std::bitset<18>("000000110000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000000100000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000000010000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000000110000000001").to_ulong() || + + firedLayerBits == std::bitset<18>("000001000000001100").to_ulong() || + firedLayerBits == std::bitset<18>("000011000000001100").to_ulong() || + firedLayerBits == std::bitset<18>("000010000000001100").to_ulong() || + firedLayerBits == std::bitset<18>("000011000000000100").to_ulong() || + + firedLayerBits == std::bitset<18>("000000011000000001").to_ulong() || + firedLayerBits == std::bitset<18>("001000010000000001").to_ulong()) + quality = 1; + else if (firedLayerBits == std::bitset<18>("000000010000000101").to_ulong() || + firedLayerBits == std::bitset<18>("000000010001000001").to_ulong() || + firedLayerBits == std::bitset<18>("000000011000000001").to_ulong() || + firedLayerBits == std::bitset<18>("000000011000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000000011100000001").to_ulong() || + firedLayerBits == std::bitset<18>("000000100000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000000100001000100").to_ulong() || + firedLayerBits == std::bitset<18>("000000100100000001").to_ulong() || + firedLayerBits == std::bitset<18>("000000110100000001").to_ulong() || + firedLayerBits == std::bitset<18>("000000111000000000").to_ulong() || + firedLayerBits == std::bitset<18>("000000111000000001").to_ulong() || + firedLayerBits == std::bitset<18>("000000111000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000001000001000100").to_ulong() || + firedLayerBits == std::bitset<18>("000001010000000001").to_ulong() || + firedLayerBits == std::bitset<18>("000001010000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000001010000000100").to_ulong() || + firedLayerBits == std::bitset<18>("000001100000000001").to_ulong() || + firedLayerBits == std::bitset<18>("000001100000000100").to_ulong() || + firedLayerBits == std::bitset<18>("000001100000000111").to_ulong() || + firedLayerBits == std::bitset<18>("000001100001000000").to_ulong() || + firedLayerBits == std::bitset<18>("000001110000000100").to_ulong() || + firedLayerBits == std::bitset<18>("000001110000000101").to_ulong() || + firedLayerBits == std::bitset<18>("000010000000000101").to_ulong() || + firedLayerBits == std::bitset<18>("000010010000000001").to_ulong() || + firedLayerBits == std::bitset<18>("000010010000000100").to_ulong() || + firedLayerBits == std::bitset<18>("000010010000000101").to_ulong() || + firedLayerBits == std::bitset<18>("000010100000000001").to_ulong() || + firedLayerBits == std::bitset<18>("000010100000000101").to_ulong() || + firedLayerBits == std::bitset<18>("000011110000000100").to_ulong() || + firedLayerBits == std::bitset<18>("000011110000000101").to_ulong() || + firedLayerBits == std::bitset<18>("000101000000010101").to_ulong() || + firedLayerBits == std::bitset<18>("001000010000000001").to_ulong() || + firedLayerBits == std::bitset<18>("001000011000000000").to_ulong() || + firedLayerBits == std::bitset<18>("001000011000000001").to_ulong() || + firedLayerBits == std::bitset<18>("001000100000000001").to_ulong() || + firedLayerBits == std::bitset<18>("001000110000000000").to_ulong() || + firedLayerBits == std::bitset<18>("001001000000000100").to_ulong() || + firedLayerBits == std::bitset<18>("001001100000000100").to_ulong() || + firedLayerBits == std::bitset<18>("001010000000000100").to_ulong() || + firedLayerBits == std::bitset<18>("010000000010000001").to_ulong() || + firedLayerBits == std::bitset<18>("010000000011000100").to_ulong() || + firedLayerBits == std::bitset<18>("010000010000000001").to_ulong() || + firedLayerBits == std::bitset<18>("010000100000000001").to_ulong() || + firedLayerBits == std::bitset<18>("100000011000000000").to_ulong() || + firedLayerBits == std::bitset<18>("000000110000000001").to_ulong() || + firedLayerBits == std::bitset<18>("000000010000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000000110000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000011000000001100").to_ulong() || + firedLayerBits == std::bitset<18>("000011000000000100").to_ulong() || + firedLayerBits == std::bitset<18>("000000010010000001").to_ulong() || + firedLayerBits == std::bitset<18>("000010000000001100").to_ulong() || + firedLayerBits == std::bitset<18>("001001000001000100").to_ulong() || + firedLayerBits == std::bitset<18>("000001100000000101").to_ulong() || + firedLayerBits == std::bitset<18>("000000100000000101").to_ulong() || + firedLayerBits == std::bitset<18>("000001100000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000001110000000111").to_ulong() || + firedLayerBits == std::bitset<18>("001000110001000001").to_ulong() || + firedLayerBits == std::bitset<18>("000001110000000011").to_ulong() || + firedLayerBits == std::bitset<18>("001000000001000100").to_ulong() || + firedLayerBits == std::bitset<18>("000000110001000001").to_ulong() || + firedLayerBits == std::bitset<18>("000001000000000101").to_ulong() || + firedLayerBits == std::bitset<18>("001010000001000000").to_ulong() || + firedLayerBits == std::bitset<18>("001100000001000000").to_ulong() || + firedLayerBits == std::bitset<18>("100000010000000001").to_ulong() || + firedLayerBits == std::bitset<18>("010000010010000000").to_ulong() || + firedLayerBits == std::bitset<18>("000010100000001100").to_ulong() || + firedLayerBits == std::bitset<18>("001000110000000011").to_ulong() || + firedLayerBits == std::bitset<18>("000001000000001100").to_ulong() || + firedLayerBits == std::bitset<18>("000000000000111101").to_ulong() || + firedLayerBits == std::bitset<18>("000001100000110001").to_ulong() || + firedLayerBits == std::bitset<18>("000100000000010100").to_ulong() || + firedLayerBits == std::bitset<18>("001000100000000011").to_ulong() || + firedLayerBits == std::bitset<18>("001000110000000001").to_ulong() || + firedLayerBits == std::bitset<18>("010000100010000001").to_ulong() || + firedLayerBits == std::bitset<18>("000100000000110000").to_ulong()) + quality = 8; + } // if (abs(myCand->getEta()) == 121) quality = 4; + if (abs(algoMuon->getEtaHw()) >= 121) + quality = 0; // changed from 4 on request from HI + + algoMuon->setQuality(quality); +} - //the charge is only for the constrained measurement. The constrained measurement is always defined for a valid candidate - if (ptAssignment) { - if (myCand->getPdfSumConstr() > 0 && myCand->getFiredLayerCntConstr() >= 3) - candidate.setHwPt(myCand->getPtNNConstr()); - else if (myCand->getPtUnconstr() > 0) - candidate.setHwPt(1); - else - candidate.setHwPt(0); +template +FinalMuons OMTFProcessor::getFinalMuons(unsigned int iProcessor, + l1t::tftype mtfType, + const AlgoMuons& gbCandidates) { + LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << ":" << __LINE__ << " gbCandidates.size() " << gbCandidates.size() + << std::endl; + FinalMuons finalMuons; + + for (auto& algoMuon : gbCandidates) { + auto finalMuon = std::make_shared(algoMuon); - candidate.setHwSign(myCand->getChargeNNConstr() < 0 ? 1 : 0); + //the charge is only for the constrained measurement. The constrained measurement is always defined for a valid candidate + if (algoMuon->getPdfSumConstr() > 0) { + finalMuon->setPtGev(this->myOmtfConfig->hwPtToGev(algoMuon->getPtConstr())); + } else if (algoMuon->getPtUnconstr() > 0) { + //if myCand->getPdfSumConstr() == 0, the myCand->getPtConstr() might not be 0, see the end of GhostBusterPreferRefDt::select + //pT is set to 0 here, i.e. as in convertToGmtScalesPhase1, pt=1 in GMT scale means 0 GeV + finalMuon->setPtGev(0.0); } else { - if (myCand->getPdfSumConstr() > 0 && myCand->getFiredLayerCntConstr() >= 3) - candidate.setHwPt(myCand->getPtConstr()); - else if (myCand->getPtUnconstr() > 0) - //if myCand->getPdfSumConstr() == 0, the myCand->getPtConstr() might not be 0, see the end of GhostBusterPreferRefDt::select - //but 0 means empty candidate, 1 means pt=0, therefore here we set HwPt to 1, as the PtUnconstr > 0 - candidate.setHwPt(1); - else - candidate.setHwPt(0); + //empty candidates are not added to the finalMuons + continue; + } + + finalMuon->setPtUnconstrGev(this->myOmtfConfig->hwPtToGev(algoMuon->getPtUnconstr())); + + finalMuon->setSign(algoMuon->getChargeConstr() < 0 ? 1 : 0); - candidate.setHwSign(myCand->getChargeConstr() < 0 ? 1 : 0); + if (mtfType == l1t::omtf_pos) { + finalMuon->setEtaRad(this->myOmtfConfig->hwEtaToEta(algoMuon->getEtaHw())); + } else { + finalMuon->setEtaRad((-1) * this->myOmtfConfig->hwEtaToEta(algoMuon->getEtaHw())); } - if (mtfType == l1t::omtf_pos) - candidate.setHwEta(myCand->getEtaHw()); - else - candidate.setHwEta((-1) * myCand->getEtaHw()); + finalMuon->setPhiRad(this->myOmtfConfig->procPhiOmtfToPhiRad(iProcessor, algoMuon->getPhi())); - int phiValue = myCand->getPhi(); - if (phiValue >= int(this->myOmtfConfig->nPhiBins())) - phiValue -= this->myOmtfConfig->nPhiBins(); - phiValue = this->myOmtfConfig->procPhiToGmtPhi(phiValue); - candidate.setHwPhi(phiValue); + //finalMuon->setFiredLayerCnt(algoMuon->getFiredLayerCnt()); + finalMuon->setProcessor(iProcessor); + finalMuon->setTrackFinderType(mtfType); - candidate.setHwSignValid(1); + finalMuons.emplace_back(finalMuon); + } + return finalMuons; +} - if (myCand->getPtUnconstr() >= 0) { //empty PtUnconstrained is -1, maybe should be corrected on the source - //the upt has different hardware scale than the pt, the upt unit is 1 GeV - candidate.setHwPtUnconstrained(myCand->getPtUnconstr()); - } else - candidate.setHwPtUnconstrained(0); +template +void OMTFProcessor::convertToGmtScalesPhase1(unsigned int iProcessor, + l1t::tftype mtfType, + FinalMuonPtr& finalMuon) { + //the charge is only for the constrained measurement. The constrained result is always defined for a valid candidate + if (finalMuon->getAlgoMuon()->getPdfSumConstr() > 0) + finalMuon->setPtGmt(finalMuon->getAlgoMuon()->getPtConstr()); + else if (finalMuon->getAlgoMuon()->getPtUnconstr() > 0) + //if myCand->getPdfSumConstr() == 0, the myCand->getPtConstr() might not be 0, see the end of GhostBusterPreferRefDt::select + //but 0 means empty candidate, 1 means pt=0, therefore here we set HwPt to 1, as the PtUnconstr > 0 + finalMuon->setPtGmt(1); + else + finalMuon->setPtGmt(0); + + //N.B. the phase-1 GMT upt has different hardware scale than the pt, the upt unit is 1 GeV + if (finalMuon->getAlgoMuon()->getPtUnconstr() == 0) + finalMuon->setPtUnconstrGmt(0); + else + finalMuon->setPtUnconstrGmt((finalMuon->getAlgoMuon()->getPtUnconstr() - 1) / 2 + 1); + + if (mtfType == l1t::omtf_pos) { + finalMuon->setEtaGmt(finalMuon->getAlgoMuon()->getEtaHw()); + } else { + finalMuon->setEtaGmt((-1) * finalMuon->getAlgoMuon()->getEtaHw()); + } - unsigned int quality = 12; - if (this->myOmtfConfig->fwVersion() <= 6) - quality = checkHitPatternValidity(myCand->getFiredLayerBits()) ? 0 | (1 << 2) | (1 << 3) : 0 | (1 << 2); //12 : 4 - - if (abs(myCand->getEtaHw()) == 115 && //115 is eta 1.25 rrrrrrrrccccdddddd - (static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("100000001110000000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000001110000000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("100000000110000000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("100000001100000000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("100000001010000000").to_ulong())) { - if (this->myOmtfConfig->fwVersion() <= 6) - quality = 4; - else - quality = 1; - } + //TODO why it is needed? + int phiValue = finalMuon->getAlgoMuon()->getPhi(); + if (phiValue >= int(this->myOmtfConfig->nPhiBins())) + phiValue -= this->myOmtfConfig->nPhiBins(); + phiValue = this->myOmtfConfig->procPhiToGmtPhase1Phi(phiValue); + finalMuon->setPhiGmt(phiValue); + //finalMuon.setHwSignValid(1); +} +/////////////////////////////////////////////////////// +/////////////////////////////////////////////////////// +template +std::vector OMTFProcessor::getRegionalMuonCands(unsigned int iProcessor, + l1t::tftype mtfType, + FinalMuons& finalMuons) { + std::vector result; + + for (auto& finalMuon : finalMuons) { + convertToGmtScalesPhase1(iProcessor, mtfType, finalMuon); + + l1t::RegionalMuonCand candidate; + + candidate.setHwPt(finalMuon->getPtGmt()); + candidate.setHwPtUnconstrained(finalMuon->getPtUnconstrGmt()); + + candidate.setHwPhi(finalMuon->getPhiGmt()); + candidate.setHwEta(finalMuon->getEtaGmt()); + + candidate.setHwSign(finalMuon->getSign()); + candidate.setHwSignValid(1); - if (this->myOmtfConfig->fwVersion() >= 5 && this->myOmtfConfig->fwVersion() <= 6) { - if (static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000010000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000100000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001000000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000010000000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000100000000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001000000000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("010000000000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("100000000000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000010000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000100000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001000000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000010000000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000100000000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001000000000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("010000000000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("100000000000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000010000110000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000100000110000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001000000110000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000010000000110000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000100000000110000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001000000000110000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("010000000000110000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("100000000000110000").to_ulong()) - quality = 1; - } else if (this->myOmtfConfig->fwVersion() >= 8) { //TODO fix the fwVersion rrrrrrrrccccdddddd - if (static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000110000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000100000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000010000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000110000000001").to_ulong() || - - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001000000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000011000000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000010000000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000011000000000100").to_ulong() || - - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000011000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001000010000000001").to_ulong()) - quality = 1; - else if ( - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000010000000101").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000010001000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000011000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000011000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000011100000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000100000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000100001000100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000100100000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000110100000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000111000000000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000111000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000111000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001000001000100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001010000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001010000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001010000000100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001100000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001100000000100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001100000000111").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001100001000000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001110000000100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001110000000101").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000010000000000101").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000010010000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000010010000000100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000010010000000101").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000010100000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000010100000000101").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000011110000000100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000011110000000101").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000101000000010101").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001000010000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001000011000000000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001000011000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001000100000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001000110000000000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001001000000000100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001001100000000100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001010000000000100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("010000000010000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("010000000011000100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("010000010000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("010000100000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("100000011000000000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000110000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000010000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000110000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000011000000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000011000000000100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000010010000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000010000000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001001000001000100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001100000000101").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000100000000101").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001100000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001110000000111").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001000110001000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001110000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001000000001000100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000110001000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001000000000101").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001010000001000000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001100000001000000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("100000010000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("010000010010000000").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000010100000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001000110000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001000000001100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000000000000111101").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000001100000110001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000100000000010100").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001000100000000011").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("001000110000000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("010000100010000001").to_ulong() || - static_cast(myCand->getFiredLayerBits()) == std::bitset<18>("000100000000110000").to_ulong()) - quality = 8; - } // if (abs(myCand->getEta()) == 121) quality = 4; - if (abs(myCand->getEtaHw()) >= 121) - quality = 0; // changed from 4 on request from HI - - candidate.setHwQual(quality); + candidate.setHwQual(finalMuon->getQuality()); std::map trackAddr; - trackAddr[0] = myCand->getFiredLayerBits(); + trackAddr[0] = finalMuon->getAlgoMuon()->getFiredLayerBits(); //TODO in the hardware, the uPt is sent to the uGMT at the trackAddr = (uPt << 18) + trackAddr; //check if it matters if it needs to be here as well - trackAddr[1] = myCand->getRefLayer(); - trackAddr[2] = myCand->getDisc(); + trackAddr[1] = finalMuon->getAlgoMuon()->getRefLayer(); + trackAddr[2] = finalMuon->getAlgoMuon()->getDisc(); if (candidate.hwPt() > 0 || candidate.hwPtUnconstrained() > 0) { candidate.setTrackAddress(trackAddr); candidate.setTFIdentifiers(iProcessor, mtfType); result.push_back(candidate); } } + return result; } -/////////////////////////////////////////////////////// -/////////////////////////////////////////////////////// /////////////////////////////////////////////////////// /////////////////////////////////////////////////////// @@ -349,6 +403,7 @@ template int OMTFProcessor::extrapolateDtPhiBFloatPoint(const int& refLogicLayer, const int& refPhi, const int& refPhiB, + const int& refHitSuperLayer, unsigned int targetLayer, const int& targetStubPhi, const int& targetStubQuality, @@ -357,7 +412,8 @@ int OMTFProcessor::extrapolateDtPhiBFloatPoint(const int& ref const OMTFConfiguration* omtfConfig) { LogTrace("l1tOmtfEventPrint") << "\n" << __FUNCTION__ << ":" << __LINE__ << " refLogicLayer " << refLogicLayer - << " targetLayer " << targetLayer << std::endl; + << " refHitSuperLayer " << refHitSuperLayer << " targetLayer " << targetLayer + << std::endl; LogTrace("l1tOmtfEventPrint") << "refPhi " << refPhi << " refPhiB " << refPhiB << " targetStubPhi " << targetStubPhi << " targetStubQuality " << targetStubQuality << std::endl; @@ -372,15 +428,32 @@ int OMTFProcessor::extrapolateDtPhiBFloatPoint(const int& ref } int reflLayerIndex = refLogicLayer == 0 ? 0 : 1; + if (useStubQualInExtr) { + //the phase-2 DT Trigger Primitives, since CMSSW_14_2_0_pre1 define phi always in "the middle of the chamber" + //also for the uncorrelated stubs + //so the below correction has sense only for the phase-1 + if (refHitSuperLayer == 1) { + rRefLayer = rRefLayer - 23.5 / 2; //inner superlayer + } else if (refHitSuperLayer == 3) { //using refHitSuperLayer = 3 here as in the L1Phase2MuDTPhDigi::slNum() + rRefLayer = rRefLayer + 23.5 / 2; //inner superlayer + } + + reflLayerIndex = (refHitSuperLayer << 1) | reflLayerIndex; + } if (targetLayer == 0 || targetLayer == 2 || targetLayer == 4 || (targetLayer >= 10 && targetLayer <= 14)) { //all units are cm. Values from the CMS geometry - float rTargetLayer = 512.401; //MB2 + float rTargetLayer = 512.475; //MB2 if (targetLayer == 0) - rTargetLayer = 431.133; //MB1 - else if (targetLayer == 4) - rTargetLayer = 617.946; //MB3 + rTargetLayer = 431.175; //MB1 + else if (targetLayer == 4) { //MB3 + //it is different than in the phase-1, as in the phase-2 it is a middle of the DT chamber, not muon station + if (omtfConfig->usePhase2DTPrimitives()) + rTargetLayer = 619.675; + else + rTargetLayer = 617.946; + } else if (targetLayer == 10) rTargetLayer = 413.675; //RB1in @@ -505,6 +578,7 @@ template int OMTFProcessor::extrapolateDtPhiBFixedPoint(const int& refLogicLayer, const int& refPhi, const int& refPhiB, + const int& refHitSuperLayer, unsigned int targetLayer, const int& targetStubPhi, const int& targetStubQuality, @@ -514,6 +588,10 @@ int OMTFProcessor::extrapolateDtPhiBFixedPoint(const int& ref int phiExtr = 0; //delta phi extrapolated int reflLayerIndex = refLogicLayer == 0 ? 0 : 1; + + if (useStubQualInExtr) + reflLayerIndex = (refHitSuperLayer << 1) | reflLayerIndex; + int extrFactor = 0; if (targetLayer == 0 || targetLayer == 2 || targetLayer == 4) { @@ -539,8 +617,8 @@ int OMTFProcessor::extrapolateDtPhiBFixedPoint(const int& ref //if given abs(targetStubEta) value is not present in the map, it is added with default value of 0 //so it should be good. The only problem is that the map can grow... //TODO change to targetStubR when it is implemented in the FW - extrFactor = extrapolFactors[reflLayerIndex][targetLayer][abs(targetStubEta)]; - //extrFactor = extrapolFactors[reflLayerIndex][targetLayer][abs(targetStubR)]; + //extrFactor = extrapolFactors[reflLayerIndex][targetLayer][abs(targetStubEta)]; + extrFactor = extrapolFactors[reflLayerIndex][targetLayer][abs(targetStubR)]; } else { extrFactor = extrapolFactors[reflLayerIndex][targetLayer][0]; } @@ -565,10 +643,20 @@ int OMTFProcessor::extrapolateDtPhiB(const MuonStubPtr& refSt const MuonStubPtr& targetStub, unsigned int targetLayer, const OMTFConfiguration* omtfConfig) { + //0 is correlated segment, so middle of the chamber + // 1 is inner SL, 2 is outer. + //N.B. that in L1Phase2MuDTPhDigi::slNum() out SL is 3 + int refHitSuperLayer = 0; + if (refStub->qualityHw == 2 || refStub->qualityHw == 0) + refHitSuperLayer = 1; + else if (refStub->qualityHw == 3 || refStub->qualityHw == 1) + refHitSuperLayer = 2; + if (useFloatingPointExtrapolation) return OMTFProcessor::extrapolateDtPhiBFloatPoint(refStub->logicLayer, refStub->phiHw, refStub->phiBHw, + refHitSuperLayer, targetLayer, targetStub->phiHw, targetStub->qualityHw, @@ -578,6 +666,7 @@ int OMTFProcessor::extrapolateDtPhiB(const MuonStubPtr& refSt return OMTFProcessor::extrapolateDtPhiBFixedPoint(refStub->logicLayer, refStub->phiHw, refStub->phiBHw, + refHitSuperLayer, targetLayer, targetStub->phiHw, targetStub->qualityHw, @@ -625,7 +714,7 @@ void OMTFProcessor::processInput(unsigned int iProcessor, } boost::property_tree::ptree procDataTree; - LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << " " << __LINE__; + LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << " " << __LINE__ << std::endl; for (unsigned int iLayer = 0; iLayer < this->myOmtfConfig->nLayers(); ++iLayer) { //debug /*for(auto& h : layerHits) { @@ -662,7 +751,7 @@ void OMTFProcessor::processInput(unsigned int iProcessor, LogTrace("l1tOmtfEventPrint") << "\n" << __FUNCTION__ << ":" << __LINE__ << " extrapolating from layer " << refLayerLogicNum - << " - iRefLayer " << aRefHitDef.iRefLayer << " to layer " << iLayer << " stub " << targetStub + << " - iRefLayer " << aRefHitDef.iRefLayer << " to layer " << iLayer << " stub " << *targetStub << " value " << extrapolatedPhi[iStub] << std::endl; if (this->myOmtfConfig->getDumpResultToXML()) { @@ -713,25 +802,29 @@ void OMTFProcessor::processInput(unsigned int iProcessor, int etaRef = refStub->etaHw; //calculating the phiExtrp in the case the RefLayer is MB1, to include it in the candidate phi of candidate + unsigned int layerPhiOut = 2; //the layer at which the candidate output phi is defined + unsigned int extrRefLayer = layerPhiOut == 0 ? 2 : 0; + //N.B. is seems that using layer 0 (MB1) as the layer where the phi is defined gives much worse results - worse phi and more ghosts + int phiExtrp = 0; - if ((this->myOmtfConfig->usePhiBExtrapolationMB1() && aRefHitDef.iRefLayer == 0)) { + if ((this->myOmtfConfig->usePhiBExtrapolationMB1() && aRefHitDef.iRefLayer == extrRefLayer)) { //||(this->myOmtfConfig->getUsePhiBExtrapolationMB2() && aRefHitDef.iRefLayer == 2) ) { //the extrapolation from the layer 2 to the layer 2 has no sense, so phiExtrp is 0 LogTrace("l1tOmtfEventPrint") << "\n" << __FUNCTION__ << ":" << __LINE__ << "extrapolating ref hit to get the phi of the candidate" << std::endl; if (useFloatingPointExtrapolation) phiExtrp = extrapolateDtPhiBFloatPoint( - aRefHitDef.iRefLayer, phiRef, refStub->phiBHw, 2, 0, 6, 0, 0, this->myOmtfConfig); + aRefHitDef.iRefLayer, phiRef, refStub->phiBHw, 0, layerPhiOut, 0, 6, 0, 0, this->myOmtfConfig); else phiExtrp = extrapolateDtPhiBFixedPoint( - aRefHitDef.iRefLayer, phiRef, refStub->phiBHw, 2, 0, 6, 0, 0, this->myOmtfConfig); + aRefHitDef.iRefLayer, phiRef, refStub->phiBHw, 0, layerPhiOut, 0, 6, 0, 0, this->myOmtfConfig); } for (auto& itGP : this->theGPs) { if (itGP->key().thePt == 0) //empty pattern continue; - int phiRefSt2 = itGP->propagateRefPhi(phiRef + phiExtrp, etaRef, aRefHitDef.iRefLayer); + int phiRefSt2 = itGP->propagateRefPhi(phiRef + phiExtrp, etaRef, aRefHitDef.iRefLayer, layerPhiOut); itGP->getResults()[procIndx][iRefHit].set(aRefHitDef.iRefLayer, phiRefSt2, etaRef, phiRef); } } @@ -759,12 +852,11 @@ void OMTFProcessor::processInput(unsigned int iProcessor, /////////////////////////////////////////////////////// template -std::vector OMTFProcessor::run( - unsigned int iProcessor, - l1t::tftype mtfType, - int bx, - OMTFinputMaker* inputMaker, - std::vector >& observers) { +FinalMuons OMTFProcessor::run(unsigned int iProcessor, + l1t::tftype mtfType, + int bx, + OMTFinputMaker* inputMaker, + std::vector >& observers) { //uncomment if you want to check execution time of each method //boost::timer::auto_cpu_timer t("%ws wall, %us user in getProcessorCandidates\n"); @@ -797,37 +889,29 @@ std::vector OMTFProcessor::run( //LogTrace("l1tOmtfEventPrint")<<"processInput "; t.report(); AlgoMuons algoCandidates = sortResults(iProcessor, mtfType); - if (ptAssignment) { - for (auto& myCand : algoCandidates) { - if (myCand->isValid()) { - auto pts = ptAssignment->getPts(myCand, observers); - /*for (unsigned int i = 0; i < pts.size(); i++) { - trackAddr[10 + i] = this->myOmtfConfig->ptGevToHw(pts[i]); - }*/ - } - } - } - //LogTrace("l1tOmtfEventPrint")<<"sortResults "; t.report(); // perform GB //watch out: etaBits2HwEta is used in the ghostBust to convert the AlgoMuons eta, it affect algoCandidates as they are pointers AlgoMuons gbCandidates = ghostBust(algoCandidates); + //assignQuality must be called after ghostBust, because eta is set there + for (auto& gbCandidate : gbCandidates) { + assignQuality(gbCandidate); + } + //LogTrace("l1tOmtfEventPrint")<<"ghostBust"; t.report(); - // fill RegionalMuonCand colleciton - std::vector candMuons = getFinalcandidates(iProcessor, mtfType, gbCandidates); - //LogTrace("l1tOmtfEventPrint")<<"getFinalcandidates "; t.report(); - //fill outgoing collection - for (auto& candMuon : candMuons) { - candMuon.setHwQual(candMuon.hwQual()); + FinalMuons finalMuons = getFinalMuons(iProcessor, mtfType, gbCandidates); + + for (auto& finalMuon : finalMuons) { + finalMuon->setBx(bx); } for (auto& obs : observers) { - obs->observeProcesorEmulation(iProcessor, mtfType, input, algoCandidates, gbCandidates, candMuons); + obs->observeProcesorEmulation(iProcessor, mtfType, input, algoCandidates, gbCandidates, finalMuons); } - return candMuons; + return finalMuons; } template diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFReconstruction.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFReconstruction.cc index dffb0e26e679d..2c16a02fe44f6 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFReconstruction.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFReconstruction.cc @@ -27,11 +27,12 @@ ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// OMTFReconstruction::OMTFReconstruction(const edm::ParameterSet& parameterSet, MuStubsInputTokens& muStubsInputTokens) - : edmParameterSet(parameterSet), - muStubsInputTokens(muStubsInputTokens), + : muStubsInputTokens(muStubsInputTokens), omtfConfig(new OMTFConfiguration()), omtfProc(nullptr), m_OMTFConfigMaker(nullptr) { + edmParameterSet.copyForModify(parameterSet); //why edmParameterSet is not reference? + bxMin = edmParameterSet.exists("bxMin") ? edmParameterSet.getParameter("bxMin") : 0; bxMax = edmParameterSet.exists("bxMax") ? edmParameterSet.getParameter("bxMax") : 0; @@ -102,6 +103,7 @@ void OMTFReconstruction::beginRun(edm::Run const& run, //patterns from the edm::EventSetup are reloaded every beginRun //therefore OMTFProcessor is re-created here + //TODO would be better to just update the patterns in the existing OMTFProcessor edm::LogVerbatim("OMTFReconstruction") << "getting patterns from EventSetup" << std::endl; if (processorType == "OMTFProcessor") { omtfProc = std::make_unique >( @@ -222,7 +224,7 @@ void OMTFReconstruction::addObservers( if (edmParameterSet.exists("candidateSimMuonMatcher")) { if (edmParameterSet.getParameter("candidateSimMuonMatcher")) { observers.emplace_back(std::make_unique( - edmParameterSet, omtfConfig.get(), magneticFieldEsToken, propagatorEsToken)); + edmParameterSet, omtfConfig->nProcessors(), magneticFieldEsToken, propagatorEsToken)); candidateSimMuonMatcher = static_cast(observers.back().get()); } } @@ -282,33 +284,42 @@ std::unique_ptr OMTFReconstruction::reconstru std::unique_ptr candidates = std::make_unique(); candidates->setBXRange(bxMin, bxMax); + FinalMuons allFinalMuons; + ///The order is important: first put omtf_pos candidates, then omtf_neg. for (int bx = bxMin; bx <= bxMax; bx++) { for (unsigned int iProcessor = 0; iProcessor < omtfConfig->nProcessors(); ++iProcessor) { + FinalMuons finalMuons = omtfProc->run(iProcessor, l1t::tftype::omtf_pos, bx, inputMaker.get(), observers); + std::vector candMuons = - omtfProc->run(iProcessor, l1t::tftype::omtf_pos, bx, inputMaker.get(), observers); + omtfProc->getRegionalMuonCands(iProcessor, l1t::tftype::omtf_pos, finalMuons); //fill outgoing collection for (auto& candMuon : candMuons) { candidates->push_back(bx, candMuon); } + + allFinalMuons.insert(allFinalMuons.end(), finalMuons.begin(), finalMuons.end()); } for (unsigned int iProcessor = 0; iProcessor < omtfConfig->nProcessors(); ++iProcessor) { - std::vector candMuons = - omtfProc->run(iProcessor, l1t::tftype::omtf_neg, bx, inputMaker.get(), observers); + FinalMuons finalMuons = omtfProc->run(iProcessor, l1t::tftype::omtf_neg, bx, inputMaker.get(), observers); + std::vector candMuons = + omtfProc->getRegionalMuonCands(iProcessor, l1t::tftype::omtf_neg, finalMuons); //fill outgoing collection for (auto& candMuon : candMuons) { candidates->push_back(bx, candMuon); } + + allFinalMuons.insert(allFinalMuons.end(), finalMuons.begin(), finalMuons.end()); } //edm::LogInfo("OMTFReconstruction") <<"OMTF: Number of candidates in BX="<size(bx) << std::endl;; } for (auto& obs : observers) { - obs->observeEventEnd(iEvent, candidates); + obs->observeEventEnd(iEvent, allFinalMuons); } return candidates; diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFinputMaker.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFinputMaker.cc index a1fd384f8a1bc..7922b988989b4 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFinputMaker.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OMTFinputMaker.cc @@ -178,6 +178,18 @@ void RpcDigiToStubsConverterOmtf::addRPCstub(MuonStubPtrs2D& muonStubsInLayers, float r = 0; stub.etaHw = angleConverter->getGlobalEtaRpc(rawid, cluster.firstStrip, r); + + if (iLayer == 10) + r = 413.675; //RB1in + else if (iLayer == 11) + r = 448.675; //RB1out + else if (iLayer == 12) + r = 494.975; //RB2in + else if (iLayer == 13) + r = 529.975; //RB2out + else if (iLayer == 14) + r = 602.150; //RB3 + stub.r = round(r); stub.qualityHw = cluster.size(); diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OmtfAngleConverter.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OmtfAngleConverter.cc index e67b542ca1f09..f08e8759bc872 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OmtfAngleConverter.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/OmtfAngleConverter.cc @@ -33,7 +33,20 @@ namespace { return (T(0) < val) - (val < T(0)); } - //DT eta bins in the wheel +2 + int fixCscOffsetGeom(int offsetLoc) { + // fix for CSC geo dependence from GlobalTag + + // dump of CSC offsets for MC global tag + const std::vector offCSC = {-154, -133, -17, -4, 4, 17, 133, 146, 154, 167, 283, 296, 304, 317, + 433, 446, 454, 467, 583, 596, 604, 617, 733, 746, 754, 767, 883, 904}; + auto gep = std::lower_bound(offCSC.begin(), offCSC.end(), offsetLoc); + int fixOff = (gep != offCSC.end()) ? *gep : *(gep - 1); + if (gep != offCSC.begin() && std::abs(*(gep - 1) - offsetLoc) < std::abs(fixOff - offsetLoc)) + fixOff = *(gep - 1); + return fixOff; + } + + //phase-1: DT eta bins in the wheel +2 const std::vector bounds = {1.24, 1.14353, 1.09844, 1.05168, 1.00313, 0.952728, 0.90037, 0.8}; // 0.8 -> 73 // 0.85 -> 78 @@ -56,7 +69,7 @@ namespace { return sign * code; } - int etaKeyWG2Code(const CSCDetId &detId, uint16_t keyWG) { + int etaKeyWG2Code(const CSCDetId& detId, uint16_t keyWG) { signed int etaCode = 121; if (detId.station() == 1 && detId.ring() == 2) { if (keyWG < 49) @@ -99,11 +112,163 @@ namespace { } //namespace OmtfAngleConverter::~OmtfAngleConverter() {} +/////////////////////////////////////// +/////////////////////////////////////// +void OmtfAngleConverter::checkAndUpdateGeometry(const edm::EventSetup& es, + const ProcConfigurationBase* config, + const MuonGeometryTokens& muonGeometryTokens) { + if (muonGeometryRecordWatcher.check(es)) { + _georpc = es.getHandle(muonGeometryTokens.rpcGeometryEsToken); + _geocsc = es.getHandle(muonGeometryTokens.cscGeometryEsToken); + _geodt = es.getHandle(muonGeometryTokens.dtGeometryEsToken); + } + this->config = config; + nPhiBins = config->nPhiBins(); +} + +/////////////////////////////////////// +/////////////////////////////////////// +int OmtfAngleConverter::getProcessorPhi(int phiZero, l1t::tftype part, int dtScNum, int dtPhi) const { + int dtPhiBins = 4096; + + double hsPhiPitch = 2 * M_PI / nPhiBins; // width of phi Pitch, related to halfStrip at CSC station 2 + + int sector = dtScNum + 1; //NOTE: there is a inconsistency in DT sector numb. Thus +1 needed to get detector numb. + + double scale = 1. / dtPhiBins / hsPhiPitch; + int scale_coeff = lround(scale * pow(2, 11)); // 216.2688 + + int ichamber = sector - 1; + if (ichamber > 6) + ichamber = ichamber - 12; + + int offsetGlobal = (int)nPhiBins * ichamber / 12; + + int phiConverted = floor(dtPhi * scale_coeff / pow(2, 11)) + offsetGlobal - phiZero; + + //LogTrace("l1tOmtfEventPrint")<<__FUNCTION__<<":"<<__LINE__<<" phiZero "<foldPhi(phi)<foldPhi(phiConverted); +} +/////////////////////////////////////// +/////////////////////////////////////// +int OmtfAngleConverter::getProcessorPhi( + int phiZero, l1t::tftype part, const CSCDetId& csc, const CSCCorrelatedLCTDigi& digi, unsigned int iInput) const { + const double hsPhiPitch = 2 * M_PI / nPhiBins; + // + // get offset for each chamber. + // FIXME: These parameters depends on processor and chamber only so may be precomputed and put in map + // + + int halfStrip = digi.getStrip(); // returns halfStrip 0..159 + + const CSCChamber* chamber = _geocsc->chamber(csc); + + //in the PhaseIITDRSpring19DR dataset (generated with CMSSW_10_6_1_patch2?), in case of the ME1/1 ring 4 (higher eta) the detId in the CSCCorrelatedLCTDigiCollection is ME1/1 ring 1 (instead ME1/1/4 as it was before), + //and the digi.getStrip() is increased by 2*64 (i.e. number of half strips in the chamber roll) + if (csc.station() == 1 && csc.ring() == 1 && halfStrip > 128) { + CSCDetId cscME11 = CSCDetId(csc.endcap(), csc.station(), 4, csc.chamber()); //changing ring to 4 + chamber = _geocsc->chamber(cscME11); + } + + const CSCChamberSpecs* cspec = chamber->specs(); + const CSCLayer* layer = chamber->layer(3); + int order = (layer->centerOfStrip(2).phi() - layer->centerOfStrip(1).phi() > 0) ? 1 : -1; + double stripPhiPitch = cspec->stripPhiPitch(); + double scale = std::abs(stripPhiPitch / hsPhiPitch / 2.); + if (std::abs(scale - 1.) < 0.0002) + scale = 1.; + + double phiHalfStrip0 = layer->centerOfStrip(1).phi() - order * stripPhiPitch / 4.; + + int offsetLoc = lround((phiHalfStrip0) / hsPhiPitch - phiZero); + offsetLoc = config->foldPhi(offsetLoc); + + if (csc.station() == 1 && csc.ring() == 1 && halfStrip > 128) { //ME1/1/ + /* if(cspec->nStrips() != 64) + edm::LogImportant("l1tOmtfEventPrint") <<__FUNCTION__<<":"<<__LINE__<<" cspec->nStrips() != 64 in case of the ME1/1, phi of the muon stub will be not correct. chamber " + <nStrips() "<nStrips()<nStrips() = 48. but the offset of 128 half strips in the digi.getStrip() looks to be good*/ + halfStrip -= 128; + } + + //FIXME: to be checked (only important for ME1/3) keep more bits for offset, truncate at the end + + int fixOff = offsetLoc; + // a quick fix for towards geometry changes due to global tag. + // in case of MC tag fixOff should be identical to offsetLoc + + if (config->getFixCscGeometryOffset()) { + if (config->nProcessors() == 6) //phase1 + fixOff = fixCscOffsetGeom(offsetLoc); //TODO does not work in when phiZero is always 0. Fix this + else if (config->nProcessors() == 3) { //phase2 + //TODO fix this bricolage!!!!!!!!!!!!!! + if (iInput >= 14) + fixOff = fixCscOffsetGeom(offsetLoc - 900) + 900; + else + fixOff = fixCscOffsetGeom(offsetLoc); + } + } + int phi = fixOff + order * scale * halfStrip; + //the phi conversion is done like above - and not simply converting the layer->centerOfStrip(halfStrip/2 +1).phi() - to mimic this what is done by the firmware, + //where phi of the stub is calculated with use of the offset and scale provided by an register + + /*//debug + auto localPoint = layer->toLocal(layer->centerOfStrip(halfStrip)); + LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << ":" << 147 << " csc: " <id()<<" "<id().rawId() + << " halfStrip "<centerOfStrip(halfStrip).phi()<<" local phi "<foldPhi(phi)<<" ("<centerOfStrip(halfStrip/2 +1).phi() ) + <<" centerOfStrip/hsPhiPitch "<< ( (layer->centerOfStrip(halfStrip/2 + 1).phi() )/hsPhiPitch)<<" hsPhiPitch "<geometry()->phiSpan().first<<" phiSpan.s "<geometry()->phiSpan().second + <<" nStrips "<nStrips() + //<<" strip 1 "<centerOfStrip(1).phi() )<<" strip last "<centerOfStrip(cspec->nStrips()).phi() ) + << std::endl;*/ + + return config->foldPhi(phi); +} + +/////////////////////////////////////// +/////////////////////////////////////// +int OmtfAngleConverter::getProcessorPhi( + int phiZero, l1t::tftype part, const RPCDetId& rollId, const unsigned int& digi1, const unsigned int& digi2) const { + const double hsPhiPitch = 2 * M_PI / nPhiBins; + const int dummy = nPhiBins; + const RPCRoll* roll = _georpc->roll(rollId); + if (!roll) + return dummy; + + double stripPhi1 = (roll->toGlobal(roll->centreOfStrip((int)digi1))).phi(); // note [-pi,pi] + double stripPhi2 = (roll->toGlobal(roll->centreOfStrip((int)digi2))).phi(); // note [-pi,pi] + + // the case when the two strips are on different sides of phi = pi + if (std::signbit(stripPhi1) != std::signbit(stripPhi2) && std::abs(stripPhi1) > M_PI / 2.) { + if (std::signbit(stripPhi1)) { //stripPhi1 is negative + stripPhi1 += 2 * M_PI; + } else //stripPhi2 is negative + stripPhi2 += 2 * M_PI; + } + int halfStrip = lround(((stripPhi1 + stripPhi2) / 2.) / hsPhiPitch); + halfStrip = config->foldPhi(halfStrip); //only for the case when the two strips are on different sides of phi = pi + + LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << ":" << 185 << " roll " << rollId.rawId() << " " << rollId + << " cluster: firstStrip " << digi1 << " stripPhi1Global " << stripPhi1 + << " stripPhi1LocalPhi " << roll->centreOfStrip((int)digi1).x() << " y " + << roll->centreOfStrip((int)digi1).y() << " lastStrip " << digi2 << " stripPhi2Global " + << stripPhi2 << " stripPhi2LocalPhi x " << roll->centreOfStrip((int)digi2).x() << " y " + << roll->centreOfStrip((int)digi2).y() << " halfStrip " << halfStrip << std::endl; + + return config->foldPhi(halfStrip - phiZero); +} /////////////////////////////////////// /////////////////////////////////////// int OmtfAngleConverter::getGlobalEta(const DTChamberId dTChamberId, - const L1MuDTChambThContainer *dtThDigis, + const L1MuDTChambThContainer* dtThDigis, int bxNum) const { //const DTChamberId dTChamberId(aDigi.whNum(),aDigi.stNum(),aDigi.scNum()+1); DTTrigGeom trig_geom(_geodt->chamber(dTChamberId), false); @@ -116,7 +281,7 @@ int OmtfAngleConverter::getGlobalEta(const DTChamberId dTChamberId, // TODO:::::>>> need to make sure this ordering doesn't flip under wheel sign const int NBTI_theta = ((dTChamberId.station() != 4) ? trig_geom.nCell(2) : trig_geom.nCell(3)); - const L1MuDTChambThDigi *theta_segm = + const L1MuDTChambThDigi* theta_segm = dtThDigis->chThetaSegm(dTChamberId.wheel(), dTChamberId.station(), dTChamberId.sector() - 1, bxNum); int bti_group = -1; @@ -149,7 +314,7 @@ int OmtfAngleConverter::getGlobalEta(const DTChamberId dTChamberId, if (config->getStubEtaEncoding() == ProcConfigurationBase::StubEtaEncoding::bits) return OMTFConfiguration::eta2Bits(abs(iEta)); - else if (config->getStubEtaEncoding() == ProcConfigurationBase::StubEtaEncoding::valueP1Scale) + else if (config->getStubEtaEncoding() >= ProcConfigurationBase::StubEtaEncoding::valueP1Scale) return abs(iEta); return 0; @@ -157,7 +322,7 @@ int OmtfAngleConverter::getGlobalEta(const DTChamberId dTChamberId, /////////////////////////////////////// /////////////////////////////////////// -int OmtfAngleConverter::getGlobalEta(unsigned int rawid, const CSCCorrelatedLCTDigi &aDigi, float &r) const { +int OmtfAngleConverter::getGlobalEta(unsigned int rawid, const CSCCorrelatedLCTDigi& aDigi, float& r) const { ///Code taken from GeometryTranslator. ///Will be replaced by direct CSC phi local to global scale ///transformation as used in FPGA implementation @@ -213,7 +378,7 @@ int OmtfAngleConverter::getGlobalEta(unsigned int rawid, const CSCCorrelatedLCTD if (config->getStubEtaEncoding() == ProcConfigurationBase::StubEtaEncoding::bits) return OMTFConfiguration::eta2Bits(abs(etaKeyWG2Code(id, keyWG))); - else if (config->getStubEtaEncoding() == ProcConfigurationBase::StubEtaEncoding::valueP1Scale) { + else if (config->getStubEtaEncoding() >= ProcConfigurationBase::StubEtaEncoding::valueP1Scale) { return config->etaToHwEta(abs(gpWg.eta())); } else { return 0; @@ -221,7 +386,7 @@ int OmtfAngleConverter::getGlobalEta(unsigned int rawid, const CSCCorrelatedLCTD } /////////////////////////////////////// /////////////////////////////////////// -int OmtfAngleConverter::getGlobalEtaRpc(unsigned int rawid, const unsigned int &strip, float &r) const { +int OmtfAngleConverter::getGlobalEtaRpc(unsigned int rawid, const unsigned int& strip, float& r) const { const RPCDetId id(rawid); auto roll = _georpc->roll(id); const LocalPoint lp = roll->centreOfStrip((int)strip); @@ -233,7 +398,7 @@ int OmtfAngleConverter::getGlobalEtaRpc(unsigned int rawid, const unsigned int & if (config->getStubEtaEncoding() == ProcConfigurationBase::StubEtaEncoding::bits) return OMTFConfiguration::eta2Bits(abs(etaVal2Code(gp.eta()))); - else if (config->getStubEtaEncoding() == ProcConfigurationBase::StubEtaEncoding::valueP1Scale) + else if (config->getStubEtaEncoding() >= ProcConfigurationBase::StubEtaEncoding::valueP1Scale) return abs(config->etaToHwEta((gp.eta()))); return 0; @@ -241,3 +406,33 @@ int OmtfAngleConverter::getGlobalEtaRpc(unsigned int rawid, const unsigned int & /////////////////////////////////////// /////////////////////////////////////// +bool OmtfAngleConverter::isCSCCounterClockwise(const CSCLayer* layer) const { + const int nStrips = layer->geometry()->numberOfStrips(); + const double phi1 = layer->centerOfStrip(1).phi(); + const double phiN = layer->centerOfStrip(nStrips).phi(); + return ((std::abs(phi1 - phiN) < M_PI && phi1 >= phiN) || (std::abs(phi1 - phiN) >= M_PI && phi1 < phiN)); +} +/////////////////////////////////////// +/////////////////////////////////////// +const int OmtfAngleConverter::findBTIgroup(const L1MuDTChambPhDigi& aDigi, const L1MuDTChambThContainer* dtThDigis) { + int bti_group = -1; + + const L1MuDTChambThDigi* theta_segm = + dtThDigis->chThetaSegm(aDigi.whNum(), aDigi.stNum(), aDigi.scNum(), aDigi.bxNum()); + if (!theta_segm) + return bti_group; + + for (unsigned int i = 0; i < 7; ++i) { + if (theta_segm->position(i) && bti_group < 0) + bti_group = i; + ///If there are more than one theta digi we do not take is + ///due to unresolved ambiguity. In this case we take eta of the + ///middle of the chamber. + else if (theta_segm->position(i) && bti_group > -1) + return -1; + } + + return bti_group; +} +/////////////////////////////////////// +/////////////////////////////////////// diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/PtAssignmentBase.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/PtAssignmentBase.cc deleted file mode 100644 index d732d25518d6f..0000000000000 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/PtAssignmentBase.cc +++ /dev/null @@ -1,10 +0,0 @@ -/* - * PtAssignmentBase.cc - * - * Created on: Mar 16, 2020 - * Author: kbunkow - */ - -#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/PtAssignmentBase.h" - -PtAssignmentBase::~PtAssignmentBase() {} diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/XMLConfigReader.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/XMLConfigReader.cc index aa0495f14de67..3f580ce6fb0f4 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/XMLConfigReader.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/XMLConfigReader.cc @@ -34,7 +34,10 @@ XERCES_CPP_NAMESPACE_USE // XMLConfigReader ////////////////////////////////// inline std::string _toString(XMLCh const *toTranscode) { - std::string tmp(xercesc::XMLString::transcode(toTranscode)); + // XMLString::transcode returns a temporary char* that must be released with XMLString::release + char *tmpC = xercesc::XMLString::transcode(toTranscode); + std::string tmp(tmpC); + XMLString::release(&tmpC); return tmp; } @@ -42,6 +45,31 @@ inline XMLCh *_toDOMS(std::string temp) { XMLCh *buff = XMLString::transcode(temp.c_str()); return buff; } + +// RAII guard for XMLCh* allocated by XMLString::transcode +// Ensures XMLString::release is called on destruction and is non-copyable (moveable). +struct XMLChGuard { + XMLCh *p_; + explicit XMLChGuard(XMLCh *p = nullptr) : p_(p) {} + XMLChGuard(const XMLChGuard &) = delete; + XMLChGuard &operator=(const XMLChGuard &) = delete; + XMLChGuard(XMLChGuard &&o) noexcept : p_(o.p_) { o.p_ = nullptr; } + XMLChGuard &operator=(XMLChGuard &&o) noexcept { + if (this != &o) { + if (p_) + xercesc::XMLString::release(&p_); + p_ = o.p_; + o.p_ = nullptr; + } + return *this; + } + ~XMLChGuard() { + if (p_) + xercesc::XMLString::release(&p_); + } + XMLCh *get() const { return p_; } + operator XMLCh *() const { return p_; } +}; //////////////////////////////////// //////////////////////////////////// XMLConfigReader::XMLConfigReader() { cms::concurrency::xercesInitialize(); } @@ -218,14 +246,12 @@ unsigned int XMLConfigReader::getPatternsVersion() const { xercesc::DOMDocument *doc = parser.getDocument(); assert(doc); - XMLCh *xmlOmtf = _toDOMS("OMTF"); - XMLCh *xmlVersion = _toDOMS("version"); + XMLChGuard xmlOmtf(_toDOMS("OMTF")); + XMLChGuard xmlVersion(_toDOMS("version")); DOMNode *aNode = doc->getElementsByTagName(xmlOmtf)->item(0); DOMElement *aOMTFElement = static_cast(aNode); version = std::stoul(_toString(aOMTFElement->getAttribute(xmlVersion)), nullptr, 16); - XMLString::release(&xmlOmtf); - XMLString::release(&xmlVersion); parser.resetDocumentPool(); } @@ -329,33 +355,33 @@ std::unique_ptr XMLConfigReader::buildGP(DOMElement *aGPEleme unsigned int patternGroup, unsigned int index, unsigned int aGPNumber) { - XMLCh *xmliEta = _toDOMS("iEta"); + XMLChGuard xmliEta(_toDOMS("iEta")); //index 0 means no number at the end std::ostringstream stringStr; if (index > 0) stringStr << "iPt" << index; else stringStr.str("iPt"); - XMLCh *xmliPt = _toDOMS(stringStr.str()); + XMLChGuard xmliPt(_toDOMS(stringStr.str())); stringStr.str(""); if (index > 0) stringStr << "value" << index; else stringStr.str("value"); - XMLCh *xmlValue = _toDOMS(stringStr.str()); + XMLChGuard xmlValue(_toDOMS(stringStr.str())); - XMLCh *xmliCharge = _toDOMS("iCharge"); - XMLCh *xmlLayer = _toDOMS("Layer"); - XMLCh *xmlRefLayer = _toDOMS("RefLayer"); - XMLCh *xmlmeanDistPhi = _toDOMS("meanDistPhi"); //for old version + XMLChGuard xmliCharge(_toDOMS("iCharge")); + XMLChGuard xmlLayer(_toDOMS("Layer")); + XMLChGuard xmlRefLayer(_toDOMS("RefLayer")); + XMLChGuard xmlmeanDistPhi(_toDOMS("meanDistPhi")); //for old version - XMLCh *xmlmeanDistPhi0 = _toDOMS("meanDistPhi0"); //for new version - XMLCh *xmlmeanDistPhi1 = _toDOMS("meanDistPhi1"); //for new version + XMLChGuard xmlmeanDistPhi0(_toDOMS("meanDistPhi0")); //for new version + XMLChGuard xmlmeanDistPhi1(_toDOMS("meanDistPhi1")); //for new version - XMLCh *xmlSelDistPhiShift = _toDOMS("selDistPhiShift"); + XMLChGuard xmlSelDistPhiShift(_toDOMS("selDistPhiShift")); - XMLCh *xmlPDF = _toDOMS("PDF"); + XMLChGuard xmlPDF(_toDOMS("PDF")); unsigned int iPt = std::atoi(_toString(aGPElement->getAttribute(xmliPt)).c_str()); int iEta = std::atoi(_toString(aGPElement->getAttribute(xmliEta)).c_str()); @@ -377,12 +403,12 @@ std::unique_ptr XMLConfigReader::buildGP(DOMElement *aGPEleme } stringStr.str(""); - XMLCh *xmlRefLayerThresh = _toDOMS("RefLayerThresh"); + XMLChGuard xmlRefLayerThresh(_toDOMS("RefLayerThresh")); if (index > 0) stringStr << "tresh" << index; else stringStr.str("tresh"); - XMLCh *xmlTresh = _toDOMS(stringStr.str()); + XMLChGuard xmlTresh(_toDOMS(stringStr.str())); stringStr.str(""); std::vector thresholds(aConfig.nRefLayers(), 0); @@ -446,14 +472,6 @@ std::unique_ptr XMLConfigReader::buildGP(DOMElement *aGPEleme } } } - XMLString::release(&xmliEta); - XMLString::release(&xmliPt); - XMLString::release(&xmliCharge); - XMLString::release(&xmlLayer); - XMLString::release(&xmlRefLayer); - XMLString::release(&xmlmeanDistPhi); - XMLString::release(&xmlPDF); - XMLString::release(&xmlValue); return aGP; } @@ -470,51 +488,51 @@ void XMLConfigReader::readConfig(L1TMuonOverlapParams *aConfig) const { parser.setValidationScheme(XercesDOMParser::Val_Auto); parser.setDoNamespaces(false); - XMLCh *xmlOMTF = _toDOMS("OMTF"); - XMLCh *xmlversion = _toDOMS("version"); - XMLCh *xmlGlobalData = _toDOMS("GlobalData"); - XMLCh *xmlnPdfAddrBits = _toDOMS("nPdfAddrBits"); - XMLCh *xmlnPdfValBits = _toDOMS("nPdfValBits"); - XMLCh *xmlnPhiBits = _toDOMS("nPhiBits"); - XMLCh *xmlnPhiBins = _toDOMS("nPhiBins"); - XMLCh *xmlnProcessors = _toDOMS("nProcessors"); - XMLCh *xmlnLogicRegions = _toDOMS("nLogicRegions"); - XMLCh *xmlnInputs = _toDOMS("nInputs"); - XMLCh *xmlnLayers = _toDOMS("nLayers"); - XMLCh *xmlnRefLayers = _toDOMS("nRefLayers"); - XMLCh *xmliProcessor = _toDOMS("iProcessor"); - XMLCh *xmlbarrelMin = _toDOMS("barrelMin"); - XMLCh *xmlbarrelMax = _toDOMS("barrelMax"); - XMLCh *xmlendcap10DegMin = _toDOMS("endcap10DegMin"); - XMLCh *xmlendcap10DegMax = _toDOMS("endcap10DegMax"); - XMLCh *xmlendcap20DegMin = _toDOMS("endcap20DegMin"); - XMLCh *xmlendcap20DegMax = _toDOMS("endcap20DegMax"); - XMLCh *xmlLayerMap = _toDOMS("LayerMap"); - XMLCh *xmlhwNumber = _toDOMS("hwNumber"); - XMLCh *xmllogicNumber = _toDOMS("logicNumber"); - XMLCh *xmlbendingLayer = _toDOMS("bendingLayer"); - XMLCh *xmlconnectedToLayer = _toDOMS("connectedToLayer"); - XMLCh *xmlRefLayerMap = _toDOMS("RefLayerMap"); - XMLCh *xmlrefLayer = _toDOMS("refLayer"); - XMLCh *xmlProcessor = _toDOMS("Processor"); - XMLCh *xmlRefLayer = _toDOMS("RefLayer"); - XMLCh *xmliRefLayer = _toDOMS("iRefLayer"); - XMLCh *xmliGlobalPhiStart = _toDOMS("iGlobalPhiStart"); - XMLCh *xmlRefHit = _toDOMS("RefHit"); - XMLCh *xmliRefHit = _toDOMS("iRefHit"); - XMLCh *xmliPhiMin = _toDOMS("iPhiMin"); - XMLCh *xmliPhiMax = _toDOMS("iPhiMax"); - XMLCh *xmliInput = _toDOMS("iInput"); - XMLCh *xmliRegion = _toDOMS("iRegion"); - XMLCh *xmlLogicRegion = _toDOMS("LogicRegion"); - XMLCh *xmlLayer = _toDOMS("Layer"); - XMLCh *xmliLayer = _toDOMS("iLayer"); - XMLCh *xmliFirstInput = _toDOMS("iFirstInput"); - XMLCh *xmlnHitsPerLayer = _toDOMS("nHitsPerLayer"); - XMLCh *xmlnRefHits = _toDOMS("nRefHits"); - XMLCh *xmlnTestRefHits = _toDOMS("nTestRefHits"); - XMLCh *xmlnGoldenPatterns = _toDOMS("nGoldenPatterns"); - XMLCh *xmlConnectionMap = _toDOMS("ConnectionMap"); + XMLChGuard xmlOMTF(_toDOMS("OMTF")); + XMLChGuard xmlversion(_toDOMS("version")); + XMLChGuard xmlGlobalData(_toDOMS("GlobalData")); + XMLChGuard xmlnPdfAddrBits(_toDOMS("nPdfAddrBits")); + XMLChGuard xmlnPdfValBits(_toDOMS("nPdfValBits")); + XMLChGuard xmlnPhiBits(_toDOMS("nPhiBits")); + XMLChGuard xmlnPhiBins(_toDOMS("nPhiBins")); + XMLChGuard xmlnProcessors(_toDOMS("nProcessors")); + XMLChGuard xmlnLogicRegions(_toDOMS("nLogicRegions")); + XMLChGuard xmlnInputs(_toDOMS("nInputs")); + XMLChGuard xmlnLayers(_toDOMS("nLayers")); + XMLChGuard xmlnRefLayers(_toDOMS("nRefLayers")); + XMLChGuard xmliProcessor(_toDOMS("iProcessor")); + XMLChGuard xmlbarrelMin(_toDOMS("barrelMin")); + XMLChGuard xmlbarrelMax(_toDOMS("barrelMax")); + XMLChGuard xmlendcap10DegMin(_toDOMS("endcap10DegMin")); + XMLChGuard xmlendcap10DegMax(_toDOMS("endcap10DegMax")); + XMLChGuard xmlendcap20DegMin(_toDOMS("endcap20DegMin")); + XMLChGuard xmlendcap20DegMax(_toDOMS("endcap20DegMax")); + XMLChGuard xmlLayerMap(_toDOMS("LayerMap")); + XMLChGuard xmlhwNumber(_toDOMS("hwNumber")); + XMLChGuard xmllogicNumber(_toDOMS("logicNumber")); + XMLChGuard xmlbendingLayer(_toDOMS("bendingLayer")); + XMLChGuard xmlconnectedToLayer(_toDOMS("connectedToLayer")); + XMLChGuard xmlRefLayerMap(_toDOMS("RefLayerMap")); + XMLChGuard xmlrefLayer(_toDOMS("refLayer")); + XMLChGuard xmlProcessor(_toDOMS("Processor")); + XMLChGuard xmlRefLayer(_toDOMS("RefLayer")); + XMLChGuard xmliRefLayer(_toDOMS("iRefLayer")); + XMLChGuard xmliGlobalPhiStart(_toDOMS("iGlobalPhiStart")); + XMLChGuard xmlRefHit(_toDOMS("RefHit")); + XMLChGuard xmliRefHit(_toDOMS("iRefHit")); + XMLChGuard xmliPhiMin(_toDOMS("iPhiMin")); + XMLChGuard xmliPhiMax(_toDOMS("iPhiMax")); + XMLChGuard xmliInput(_toDOMS("iInput")); + XMLChGuard xmliRegion(_toDOMS("iRegion")); + XMLChGuard xmlLogicRegion(_toDOMS("LogicRegion")); + XMLChGuard xmlLayer(_toDOMS("Layer")); + XMLChGuard xmliLayer(_toDOMS("iLayer")); + XMLChGuard xmliFirstInput(_toDOMS("iFirstInput")); + XMLChGuard xmlnHitsPerLayer(_toDOMS("nHitsPerLayer")); + XMLChGuard xmlnRefHits(_toDOMS("nRefHits")); + XMLChGuard xmlnTestRefHits(_toDOMS("nTestRefHits")); + XMLChGuard xmlnGoldenPatterns(_toDOMS("nGoldenPatterns")); + XMLChGuard xmlConnectionMap(_toDOMS("ConnectionMap")); parser.parse(configFile.c_str()); xercesc::DOMDocument *doc = parser.getDocument(); assert(doc); @@ -711,52 +729,6 @@ void XMLConfigReader::readConfig(L1TMuonOverlapParams *aConfig) const { // Reset the documents vector pool and release all the associated memory back to the system. parser.resetDocumentPool(); - - XMLString::release(&xmlOMTF); - XMLString::release(&xmlversion); - XMLString::release(&xmlGlobalData); - XMLString::release(&xmlnPdfAddrBits); - XMLString::release(&xmlnPdfValBits); - XMLString::release(&xmlnPhiBits); - XMLString::release(&xmlnPhiBins); - XMLString::release(&xmlnProcessors); - XMLString::release(&xmlnLogicRegions); - XMLString::release(&xmlnInputs); - XMLString::release(&xmlnLayers); - XMLString::release(&xmlnRefLayers); - XMLString::release(&xmliProcessor); - XMLString::release(&xmlbarrelMin); - XMLString::release(&xmlbarrelMax); - XMLString::release(&xmlendcap10DegMin); - XMLString::release(&xmlendcap10DegMax); - XMLString::release(&xmlendcap20DegMin); - XMLString::release(&xmlendcap20DegMax); - XMLString::release(&xmlLayerMap); - XMLString::release(&xmlhwNumber); - XMLString::release(&xmllogicNumber); - XMLString::release(&xmlbendingLayer); - XMLString::release(&xmlconnectedToLayer); - XMLString::release(&xmlRefLayerMap); - XMLString::release(&xmlrefLayer); - XMLString::release(&xmlProcessor); - XMLString::release(&xmlRefLayer); - XMLString::release(&xmliRefLayer); - XMLString::release(&xmliGlobalPhiStart); - XMLString::release(&xmlRefHit); - XMLString::release(&xmliRefHit); - XMLString::release(&xmliPhiMin); - XMLString::release(&xmliPhiMax); - XMLString::release(&xmliInput); - XMLString::release(&xmliRegion); - XMLString::release(&xmlLogicRegion); - XMLString::release(&xmlLayer); - XMLString::release(&xmliLayer); - XMLString::release(&xmliFirstInput); - XMLString::release(&xmlnHitsPerLayer); - XMLString::release(&xmlnRefHits); - XMLString::release(&xmlnTestRefHits); - XMLString::release(&xmlnGoldenPatterns); - XMLString::release(&xmlConnectionMap); } } ////////////////////////////////////////////////// diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/XMLEventWriter.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/XMLEventWriter.cc index c68b1853bd58d..63d1d4ef3ea85 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/XMLEventWriter.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Omtf/XMLEventWriter.cc @@ -55,11 +55,11 @@ void XMLEventWriter::observeProcesorEmulation(unsigned int iProcessor, const std::shared_ptr& input, const AlgoMuons& algoCandidates, const AlgoMuons& gbCandidates, - const std::vector& candMuons) { + const FinalMuons& finalMuons) { int endcap = (mtfType == l1t::omtf_neg) ? -1 : ((mtfType == l1t::omtf_pos) ? +1 : 0); OmtfName board(iProcessor, endcap, omtfConfig); - if (candMuons.empty()) + if (finalMuons.empty()) return; for (unsigned int iLayer = 0; iLayer < omtfConfig->nLayers(); ++iLayer) { @@ -168,26 +168,25 @@ void XMLEventWriter::observeProcesorEmulation(unsigned int iProcessor, } } - for (auto& candMuon : candMuons) { + for (auto& finalMuon : finalMuons) { auto& candMuonTree = procTree.add("CandMuon", ""); - candMuonTree.add(".hwEta", candMuon.hwEta()); - candMuonTree.add(".hwPhi", candMuon.hwPhi()); - candMuonTree.add(".hwPt", candMuon.hwPt()); - candMuonTree.add(".hwUPt", candMuon.hwPtUnconstrained()); - candMuonTree.add(".hwQual", candMuon.hwQual()); - candMuonTree.add(".hwSign", candMuon.hwSign()); - candMuonTree.add(".hwSignValid", candMuon.hwSignValid()); - candMuonTree.add(".hwTrackAddress", std::bitset<29>(candMuon.trackAddress().at(0))); - candMuonTree.add(".link", candMuon.link()); - candMuonTree.add(".processor", candMuon.processor()); + candMuonTree.add(".hwEta", finalMuon->getEtaGmt()); + candMuonTree.add(".hwPhi", finalMuon->getPhiGmt()); + candMuonTree.add(".hwPt", finalMuon->getPtGmt()); + candMuonTree.add(".hwUPt", finalMuon->getPtUnconstrGmt()); + candMuonTree.add(".hwQual", finalMuon->getQuality()); + candMuonTree.add(".hwSign", finalMuon->getSign()); + candMuonTree.add(".hwSignValid", 1); + candMuonTree.add(".hwTrackAddress", std::bitset<29>(finalMuon->getAlgoMuon()->getFiredLayerBits())); + candMuonTree.add(".link", (mtfType == l1t::omtf_neg ? 60 + iProcessor : 42 + iProcessor)); + candMuonTree.add(".processor", iProcessor); std::ostringstream stringStr; - if (candMuon.trackFinderType() == l1t::omtf_neg) + if (mtfType == l1t::omtf_neg) stringStr << "OMTF_NEG"; - else if (candMuon.trackFinderType() == l1t::omtf_pos) + else if (mtfType == l1t::omtf_pos) stringStr << "OMTF_POS"; - else - stringStr << candMuon.trackFinderType(); + candMuonTree.add(".trackFinderType", stringStr.str()); } @@ -206,8 +205,7 @@ void XMLEventWriter::observeEventBegin(const edm::Event& iEvent) { eventTree->add(".iBx", 2 * eventId); } -void XMLEventWriter::observeEventEnd(const edm::Event& iEvent, - std::unique_ptr& finalCandidates) {} +void XMLEventWriter::observeEventEnd(const edm::Event& iEvent, FinalMuons& finalMuons) {} void XMLEventWriter::endJob() { edm::LogInfo("l1tOmtfEventPrint") << "XMLEventWriter::endJob() - writing the data to the xml - starting"; diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/ProcConfigurationBase.cc b/L1Trigger/L1TMuonOverlapPhase1/src/ProcConfigurationBase.cc index 8e54b3b69c2e9..d0e085d1f39fc 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/ProcConfigurationBase.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/ProcConfigurationBase.cc @@ -50,6 +50,12 @@ void ProcConfigurationBase::configureFromEdmParameterSet(const edm::ParameterSet << "lctCentralBx: " << edmParameterSet.getParameter("lctCentralBx") << std::endl; } + if (edmParameterSet.exists("dtBxShift")) { + dtBxShift_ = edmParameterSet.getParameter("dtBxShift"); + edm::LogVerbatim("OMTFReconstruction") + << "dtBxShift: " << edmParameterSet.getParameter("dtBxShift") << std::endl; + } + if (edmParameterSet.exists("minDtPhiQuality")) { minDtPhiQuality = edmParameterSet.getParameter("minDtPhiQuality"); edm::LogVerbatim("OMTFReconstruction") @@ -68,6 +74,8 @@ void ProcConfigurationBase::configureFromEdmParameterSet(const edm::ParameterSet stubEtaEncoding = StubEtaEncoding::bits; else if (stubEtaEncodingStr == "valueP1Scale") stubEtaEncoding = StubEtaEncoding::valueP1Scale; + else if (stubEtaEncodingStr == "valueP2Scale") + stubEtaEncoding = StubEtaEncoding::valueP2Scale; else throw cms::Exception(std::string("ProcConfigurationBase::configureFromEdmParameterSet: stubEtaEncoding ") + stubEtaEncodingStr + "is not correct"); diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Tools/CandidateSimMuonMatcher.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Tools/CandidateSimMuonMatcher.cc index 0d62407de2c2f..c7070bc2adcd0 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Tools/CandidateSimMuonMatcher.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Tools/CandidateSimMuonMatcher.cc @@ -24,11 +24,16 @@ #include "TFile.h" #include "TH1D.h" - +/* double hwGmtPhiToGlobalPhi(int phi) { double phiGmtUnit = 2. * M_PI / 576.; - return phi * phiGmtUnit; -} + double globalPhi = phi * phiGmtUnit; + + if (globalPhi > M_PI) + globalPhi = globalPhi - (2. * M_PI); + + return globalPhi; +}*/ double foldPhi(double phi) { if (phi > M_PI) @@ -39,38 +44,182 @@ double foldPhi(double phi) { return phi; } +MatchingResult::MatchingResult(const SimTrack& simTrack, const SimVertex* simVertex) + : simTrack(&simTrack), simVertex(simVertex) { + pdgId = simTrack.type(); + genPt = simTrack.momentum().pt(); + genEta = simTrack.momentum().eta(); + genPhi = simTrack.momentum().phi(); + genCharge = simTrack.charge(); + + if (this->simVertex) { + const math::XYZTLorentzVectorD& vtxPos = this->simVertex->position(); + muonDxy = (-vtxPos.X() * this->simTrack->momentum().py() + vtxPos.Y() * this->simTrack->momentum().px()) / + this->simTrack->momentum().pt(); + muonRho = vtxPos.Rho(); + + vertexEta = vtxPos.eta(); + vertexPhi = vtxPos.phi(); + } else { + // default values when no vertex information is available + muonDxy = 0; + muonRho = 0; + vertexEta = 0; + vertexPhi = 0; + } + + //parentPdgId = 0; TODO +} + +MatchingResult::MatchingResult(const TrackingParticle& trackingParticle) : trackingParticle(&trackingParticle) { + pdgId = trackingParticle.pdgId(); + genPt = trackingParticle.pt(); + genEta = trackingParticle.momentum().eta(); + genPhi = trackingParticle.momentum().phi(); + genCharge = trackingParticle.charge(); + + muonDxy = this->trackingParticle->dxy(); + if (this->trackingParticle->parentVertex().isNonnull()) { + muonRho = this->trackingParticle->parentVertex()->position().Rho(); + vertexEta = this->trackingParticle->parentVertex()->position().eta(); + vertexPhi = this->trackingParticle->parentVertex()->position().phi(); + } else { + muonRho = 0; + vertexEta = 0; + vertexPhi = 0; + } +} + +std::ostream& operator<<(std::ostream& out, const MatchingResult& matchingResult) { + out << "matchingResult:\n"; + if (matchingResult.simTrack || matchingResult.trackingParticle) { + out << " simTrack type " << std::setw(5) << matchingResult.pdgId; + out << " pt " << std::setw(8) << matchingResult.genPt << " GeV"; + out << " eta " << std::setw(8) << matchingResult.genEta; + out << " phi " << std::setw(8) << matchingResult.genPhi; + out << " charge " << std::setw(2) << matchingResult.genCharge; + out << " vertexEta " << std::setw(8) << matchingResult.vertexEta; + out << " vertexPhi " << std::setw(8) << matchingResult.vertexPhi; + out << " muonDxy " << std::setw(8) << matchingResult.muonDxy; + out << " muonRho " << std::setw(8) << matchingResult.muonRho; + out << " parentPdgId " << std::setw(5) << matchingResult.parentPdgId; + } else { + out << " no matched simTrack/trackingParticle"; + } + out << "\n muonCand: "; + if (matchingResult.muonCand) + out << *(matchingResult.muonCand); + else + out << " no matched muonCand "; + + out << "\n deltaEta " << std::setw(8) << matchingResult.deltaEta << " deltaPhi " << std::setw(8) + << matchingResult.deltaPhi << " Likelihood " << std::setw(8) << matchingResult.matchingLikelihood << " result " + << (short)matchingResult.result << std::endl; + return out; +} + +int CandidateSimMuonMatcher::calcGlobalPhi(int locPhi, int proc) { + int globPhi = 0; + //60 degree sectors = 96 in int-scale + globPhi = (proc) * 96 * 6 / nProcessors + locPhi; + // 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 + 24 + 576) % 576; + return globPhi; +} + CandidateSimMuonMatcher::CandidateSimMuonMatcher( const edm::ParameterSet& edmCfg, - const OMTFConfiguration* omtfConfig, + //const OMTFConfiguration* omtfConfig, + int nProcessors, const edm::ESGetToken& magneticFieldEsToken, const edm::ESGetToken& propagatorEsToken) - : omtfConfig(omtfConfig), + : //omtfConfig(omtfConfig), + nProcessors(nProcessors), edmCfg(edmCfg), magneticFieldEsToken(magneticFieldEsToken), propagatorEsToken(propagatorEsToken) { + //needed when CandidateSimMuonMatcher is used outside the OMTF package, where the omtfConfig is not available + if (edmCfg.exists("phase")) { + if (edmCfg.getParameter("phase") == 2) + this->nProcessors = 3; + } + std::string muonMatcherFileName = edmCfg.getParameter("muonMatcherFile").fullPath(); - TFile inFile(muonMatcherFileName.c_str()); + TFile muonMatcherFile(muonMatcherFileName.c_str()); edm::LogImportant("l1tOmtfEventPrint") << " CandidateSimMuonMatcher: using muonMatcherFileName " << muonMatcherFileName << std::endl; - if (edmCfg.exists("candidateSimMuonMatcherType")) { - if (edmCfg.getParameter("candidateSimMuonMatcherType") == "propagation") - usePropagation = true; - else if (edmCfg.getParameter("candidateSimMuonMatcherType") == "matchSimple") - usePropagation = false; + if (edmCfg.getParameter("candidateSimMuonMatcherType") == "withPropagator") + matchingType = MatchingType::withPropagator; + else if (edmCfg.getParameter("candidateSimMuonMatcherType") == "simplePropagation") + matchingType = MatchingType::simplePropagation; + else if (edmCfg.getParameter("candidateSimMuonMatcherType") == "simpleMatching") + matchingType = MatchingType::simpleMatching; + else if (edmCfg.getParameter("candidateSimMuonMatcherType") == "collectMuonCands") + matchingType = MatchingType::collectMuonCands; edm::LogImportant("l1tOmtfEventPrint") << " CandidateSimMuonMatcher: candidateSimMuonMatcherType " << edmCfg.getParameter("candidateSimMuonMatcherType") << std::endl; } - edm::LogImportant("l1tOmtfEventPrint") << " CandidateSimMuonMatcher: usePropagation " << usePropagation << std::endl; + edm::LogImportant("l1tOmtfEventPrint") << " CandidateSimMuonMatcher: matchingType " + << static_cast(matchingType) << std::endl; + + // Try to read histograms from the file; be defensive if file/histograms are missing + if (muonMatcherFile.IsZombie()) { + edm::LogWarning("l1tOmtfEventPrint") << "CandidateSimMuonMatcher: muon matcher file could not be opened: " + << muonMatcherFileName << std::endl; + throw cms::Exception("MissingFile") << "CandidateSimMuonMatcher: muon matcher file could not be opened: " + << muonMatcherFileName << std::endl; + } else { + edm::LogImportant("l1tOmtfEventPrint") << " CandidateSimMuonMatcher: reading histograms from file " << std::endl; + minDelta_pos = dynamic_cast(muonMatcherFile.Get("minDelta_pos")); + LogTrace("l1tOmtfEventPrint") << " CandidateSimMuonMatcher: " << __LINE__ << std::endl; + maxDelta_pos = dynamic_cast(muonMatcherFile.Get("maxDelta_pos")); + medianDelta_pos = dynamic_cast(muonMatcherFile.Get("medianDelta_pos")); + + LogTrace("l1tOmtfEventPrint") << " CandidateSimMuonMatcher: " << __LINE__ << std::endl; + minDelta_neg = dynamic_cast(muonMatcherFile.Get("minDelta_neg")); + maxDelta_neg = dynamic_cast(muonMatcherFile.Get("maxDelta_neg")); + medianDelta_neg = dynamic_cast(muonMatcherFile.Get("medianDelta_neg")); + + LogTrace("l1tOmtfEventPrint") << " CandidateSimMuonMatcher: " << __LINE__ << std::endl; + if (!minDelta_pos || !maxDelta_pos || !medianDelta_pos || !minDelta_neg || !maxDelta_neg || !medianDelta_neg) { + edm::LogWarning("l1tOmtfEventPrint") + << "CandidateSimMuonMatcher: one or more histograms are missing in the file: " << muonMatcherFileName + << std::endl; + throw cms::Exception("MissingHistogram") + << "CandidateSimMuonMatcher: one or more histograms are missing in the file: " << muonMatcherFileName + << std::endl; + } - deltaPhiPropCandMean = (TH1D*)inFile.Get("deltaPhiPropCandMean"); - deltaPhiPropCandStdDev = (TH1D*)inFile.Get("deltaPhiPropCandStdDev"); + // Detach histograms from the file so they survive file close + //it must be like that to assure the histograms leave outside this scope. + //muonMatcherFile as pointer-field in the class somehow does not work. + minDelta_pos->SetDirectory(nullptr); + maxDelta_pos->SetDirectory(nullptr); + medianDelta_pos->SetDirectory(nullptr); + minDelta_neg->SetDirectory(nullptr); + maxDelta_neg->SetDirectory(nullptr); + medianDelta_neg->SetDirectory(nullptr); + } } -CandidateSimMuonMatcher::~CandidateSimMuonMatcher() {} +CandidateSimMuonMatcher::~CandidateSimMuonMatcher() { + if (minDelta_pos) + delete minDelta_pos; + if (maxDelta_pos) + delete maxDelta_pos; + if (medianDelta_pos) + delete medianDelta_pos; + if (minDelta_neg) + delete minDelta_neg; + if (maxDelta_neg) + delete maxDelta_neg; + if (medianDelta_neg) + delete medianDelta_neg; +} void CandidateSimMuonMatcher::beginRun(const edm::EventSetup& eventSetup) { //TODO use edm::ESWatcher magneticFieldRecordWatcher; @@ -85,21 +234,21 @@ void CandidateSimMuonMatcher::observeProcesorEmulation(unsigned int iProcessor, const std::shared_ptr& input, const AlgoMuons& algoCandidates, const AlgoMuons& gbCandidates, - const std::vector& candMuons) { - //debug - unsigned int procIndx = omtfConfig->getProcIndx(iProcessor, mtfType); + const FinalMuons& finalMuons) { + //debug, gbCandidate are not used outside this method + //unsigned int procIndx = omtfConfig->getProcIndx(iProcessor, mtfType); for (auto& gbCandidate : gbCandidates) { - if (gbCandidate->getPtConstr() > 0) { - LogTrace("l1tOmtfEventPrint") << "CandidateSimMuonMatcher::observeProcesorEmulation procIndx" << procIndx << " " - << *gbCandidate << std::endl; + //if (gbCandidate->getPtConstr() > 0) + { + LogTrace("l1tOmtfEventPrint") << "CandidateSimMuonMatcher::observeProcesorEmulation iProcessor " << iProcessor + << " mtfType " << mtfType << *gbCandidate << std::endl; this->gbCandidates.emplace_back(gbCandidate); } } } bool simTrackIsMuonInOmtf(const SimTrack& simTrack) { - if (std::abs(simTrack.type()) == 13 || - std::abs(simTrack.type()) == 1000015) { // 1000015 is stau, todo use other selection (e.g. pt>20) if needed + if (std::abs(simTrack.type()) == 13 || std::abs(simTrack.type()) == 1000015) { // 1000015 is stau //only muons } else return false; @@ -116,7 +265,7 @@ bool simTrackIsMuonInOmtf(const SimTrack& simTrack) { //some margin for matching must be used on top of actual OMTF region, //i.e. (0.82-1.24)=>(0.72-1.3), //otherwise many candidates are marked as ghosts - if ((std::abs(simTrack.momentum().eta()) >= 0.72) && (std::abs(simTrack.momentum().eta()) <= 1.3)) { + if ((std::abs(simTrack.momentum().eta()) >= 0.7) && (std::abs(simTrack.momentum().eta()) <= 1.31)) { LogTrace("l1tOmtfEventPrint") << "simTrackIsMuonInOmtf: is in OMTF"; } else { LogTrace("l1tOmtfEventPrint") << "simTrackIsMuonInOmtf: not in OMTF"; @@ -134,8 +283,10 @@ bool simTrackIsMuonInOmtfBx0(const SimTrack& simTrack) { } bool simTrackIsMuonInBx0(const SimTrack& simTrack) { - if (std::abs(simTrack.type()) == 13 || - std::abs(simTrack.type()) == 1000015) { // 1000015 is stau, todo use other selection (e.g. pt>20) if needed + if (std::abs(simTrack.type()) == 13 || std::abs(simTrack.type()) == 1000015) { // 1000015 is stau + if (simTrack.momentum().pt() < 2.5) //TODO muons with pt < 2.5 GeV do not reach the OMTF + return false; + //only muons if (simTrack.eventId().bunchCrossing() == 0) return true; @@ -147,6 +298,38 @@ bool trackingParticleIsMuonInBx0(const TrackingParticle& trackingParticle) { if (std::abs(trackingParticle.pdgId()) == 13 || std::abs(trackingParticle.pdgId()) == 1000015) { // 1000015 is stau, todo use other selection (e.g. pt>20) if needed + + //in the overlap, the propagation of muons with pt less then ~3.2 fails - the actual threshold depends slightly on eta, + if (trackingParticle.pt() < 2.5) + return false; + + //only muons + if (trackingParticle.eventId().bunchCrossing() == 0) + return true; + } + return false; +} + +bool trackingParticleIsMuonInBx0Displ(const TrackingParticle& trackingParticle) { + if (std::abs(trackingParticle.pdgId()) == 13 || std::abs(trackingParticle.pdgId()) == 1000015) { // 1000015 is stau + + //in the overlap, the propagation of muons with pt less then ~3.2 fails - the actual threshold depends slightly on eta, + if (trackingParticle.pt() < 2.) + return false; + + if (trackingParticle.parentVertex().isNonnull()) { + if (trackingParticle.dxy() < 30) { + if ((std::abs(trackingParticle.momentum().eta()) < 0.7) || (std::abs(trackingParticle.momentum().eta()) > 1.31)) + return false; + } else { + if ((std::abs(trackingParticle.parentVertex()->position().eta()) < 0.7) || + (std::abs(trackingParticle.parentVertex()->position().eta()) > 1.4)) + return false; + } + } else + throw cms::Exception("CandidateSimMuonMatcher", + "trackingParticleIsMuonInBx0Displ: trackingParticle has no parent vertex"); + //only muons if (trackingParticle.eventId().bunchCrossing() == 0) return true; @@ -188,7 +371,7 @@ bool trackingParticleIsMuonInOmtfBx0(const TrackingParticle& trackingParticle) { //some margin for matching must be used on top of actual OMTF region, //i.e. (0.82-1.24)=>(0.72-1.3), //otherwise many candidates are marked as ghosts - if ((std::abs(trackingParticle.momentum().eta()) >= 0.72) && (std::abs(trackingParticle.momentum().eta()) <= 1.3)) { + if ((std::abs(trackingParticle.momentum().eta()) >= 0.7) && (std::abs(trackingParticle.momentum().eta()) <= 1.31)) { } else return false; @@ -202,12 +385,9 @@ bool trackingParticleIsMuonInOmtfEvent0(const TrackingParticle& trackingParticle return trackingParticleIsMuonInOmtfBx0(trackingParticle); } -void CandidateSimMuonMatcher::observeEventEnd(const edm::Event& event, - std::unique_ptr& finalCandidates) { +void CandidateSimMuonMatcher::observeEventEnd(const edm::Event& event, FinalMuons& finalMuons) { LogTrace("l1tOmtfEventPrint") << "\nCandidateSimMuonMatcher::observeEventEnd" << std::endl; - AlgoMuons ghostBustedProcMuons; - std::vector ghostBustedRegionalCands = - CandidateSimMuonMatcher::ghostBust(finalCandidates.get(), gbCandidates, ghostBustedProcMuons); + FinalMuons ghostBustedFinalMuons = CandidateSimMuonMatcher::ghostBust(finalMuons); matchingResults.clear(); if (edmCfg.exists("simTracksTag")) { @@ -220,27 +400,23 @@ void CandidateSimMuonMatcher::observeEventEnd(const edm::Event& event, LogTrace("l1tOmtfEventPrint") << "simTraksHandle size " << simTraksHandle.product()->size() << std::endl; LogTrace("l1tOmtfEventPrint") << "simVertices size " << simVertices.product()->size() << std::endl; - if (usePropagation) { - //TODO use other simTrackFilter if needed <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - //we dont want to check the eta of the generated muon, as it is on the vertex, - //instead inside match, we check the eta of the propagated track to the second muons station - std::function const& simTrackFilter = simTrackIsMuonInBx0; //simTrackIsMuonInOmtfBx0; - - matchingResults = match(ghostBustedRegionalCands, - ghostBustedProcMuons, - simTraksHandle.product(), - simVertices.product(), - simTrackFilter); - } else { + if (matchingType == MatchingType::simpleMatching) { std::function const& simTrackFilter = simTrackIsMuonInOmtfBx0; //simTrackIsMuonInOmtfBx0 provides appropriate eta cut - matchingResults = matchSimple(ghostBustedRegionalCands, - ghostBustedProcMuons, - simTraksHandle.product(), - simVertices.product(), - simTrackFilter); + matchingResults = + matchSimple(ghostBustedFinalMuons, simTraksHandle.product(), simVertices.product(), simTrackFilter); + } else if (matchingType == MatchingType::withPropagator || matchingType == MatchingType::simplePropagation) { + //TODO use other simTrackFilter if needed <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + //withPropagator, we dont want to check the eta of the generated muon, as it is on the vertex, + //instead inside match, we check the eta of the propagated track to the second muons station + std::function const& simTrackFilter = + (matchingType == MatchingType::withPropagator) ? simTrackIsMuonInBx0 : simTrackIsMuonInOmtfBx0; + //withPropagator : simplePropagation + + matchingResults = match(ghostBustedFinalMuons, simTraksHandle.product(), simVertices.product(), simTrackFilter); } + //todo something when noMatcher } else if (edmCfg.exists("trackingParticleTag")) { edm::Handle trackingParticleHandle; @@ -249,86 +425,71 @@ void CandidateSimMuonMatcher::observeEventEnd(const edm::Event& event, << trackingParticleHandle.product()->size() << std::endl; //TODO use other trackParticleFilter if needed <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - std::function trackParticleFilter = - trackingParticleIsMuonInBx0; //trackingParticleIsMuonInOmtfBx0; - matchingResults = - match(ghostBustedRegionalCands, ghostBustedProcMuons, trackingParticleHandle.product(), trackParticleFilter); + //TrackingParticle is used for minBias sample. There we should do propagation to match pions and kaons + std::function trackParticleFilter = trackingParticleIsMuonInBx0Displ; + //trackingParticleIsMuonInBx0; if propagation is used, use trackingParticleIsMuonInOmtfBx0 + matchingResults = match(finalMuons, trackingParticleHandle.product(), trackParticleFilter); + } else if (matchingType == MatchingType::collectMuonCands) { + matchingResults = collectMuonCands(finalMuons); } } void CandidateSimMuonMatcher::endJob() {} -std::vector CandidateSimMuonMatcher::ghostBust( - const l1t::RegionalMuonCandBxCollection* mtfCands, const AlgoMuons& gbCandidates, AlgoMuons& ghostBustedProcMuons) { - if (gbCandidates.size() != mtfCands->size(0)) { - edm::LogError("l1tOmtfEventPrint") << "CandidateSimMuonMatcher::ghostBust(): gbCandidates.size() " - << gbCandidates.size() << " != mtfCands.size() " << mtfCands->size(); - } - - boost::dynamic_bitset<> isKilled(mtfCands->size(0), false); - - for (unsigned int i1 = 0; i1 < mtfCands->size(0); ++i1) { - if (mtfCands->at(0, i1).hwPt() == 0) - continue; - LogTrace("l1tOmtfEventPrint") << "\nCandidateSimMuonMatcher::ghostBust regionalCand pt " << std::setw(3) - << mtfCands->at(0, i1).hwPt() << " qual " << std::setw(2) - << mtfCands->at(0, i1).hwQual() << " proc " << std::setw(2) - << mtfCands->at(0, i1).processor(); - for (unsigned int i2 = i1 + 1; i2 < mtfCands->size(0); ++i2) { - auto& mtfCand1 = mtfCands->at(0, i1); - auto& mtfCand2 = mtfCands->at(0, i2); - if (mtfCand2.hwPt() == 0) - continue; - - if (std::abs(mtfCand1.hwEta() - mtfCand2.hwEta()) < (0.3 / 0.010875)) { - int gloablHwPhi1 = omtfConfig->calcGlobalPhi(mtfCand1.hwPhi(), mtfCand1.processor()); - int gloablHwPhi2 = omtfConfig->calcGlobalPhi(mtfCand2.hwPhi(), mtfCand2.processor()); +FinalMuons CandidateSimMuonMatcher::ghostBust(const FinalMuons& finalMuons) { + boost::dynamic_bitset<> isKilled(finalMuons.size(), false); + //finalMuons are nonempty + for (unsigned int i1 = 0; i1 < finalMuons.size(); ++i1) { + LogTrace("l1tOmtfEventPrint") << "\nCandidateSimMuonMatcher::ghostBusting\n" << *(finalMuons[i1]); + if (finalMuons[i1]->getPtGmt() <= 0) { + //PtGmt > 0 marks valid candidate both for phase1 and phase2. But it should not matter here, as all finalMuons are not empty, so it just a safety check + throw cms::Exception("CandidateSimMuonMatcher") + << "CandidateSimMuonMatcher::ghostBust finalMuons[" << i1 << "] has ptGmt <= 0, ptGmt " + << finalMuons[i1]->getPtGmt() << std::endl; + } + for (unsigned int i2 = i1 + 1; i2 < finalMuons.size(); ++i2) { + auto& mtfCand1 = finalMuons[i1]; + auto& mtfCand2 = finalMuons[i2]; + //if (mtfCand2->getPt() == 0) + // continue; + if (std::abs(mtfCand1->getEtaRad() - mtfCand2->getEtaRad()) < 0.3) { //folding phi - int deltaPhi = std::abs(gloablHwPhi1 - gloablHwPhi2); - if (deltaPhi > 576 / 2) - deltaPhi = std::abs(deltaPhi - 576); - - //one can use the phi in radians like that: - //double globalPhi1 = hwGmtPhiToGlobalPhi(omtfConfig->calcGlobalPhi( mtfCand1.hwPhi(), mtfCand1.processor() ) ); - //double globalPhi2 = hwGmtPhiToGlobalPhi(omtfConfig->calcGlobalPhi( mtfCand2.hwPhi(), mtfCand2.processor() ) ); - - //0.0872664626 = 5 deg, i.e. the same window as in the OMTF ghost buster - if (deltaPhi < 8) { - //if (mtfCand1.hwQual() > mtfCand2.hwQual()) //TODO this is used in the uGMT - //but this should be better - but probably the difference is not big - if (gbCandidates[i1]->getFiredLayerCnt() > gbCandidates[i2]->getFiredLayerCnt()) { + double deltaPhi = std::abs(mtfCand1->getPhiRad() - mtfCand2->getPhiRad()); + if (deltaPhi > M_PI) + deltaPhi = std::abs(deltaPhi - 2 * M_PI); + + //0.116355283466 is 10 units of the phase1 + if (deltaPhi < 10 * 2 * M_PI / 576) { + if (mtfCand1->getFiredLayerCnt() > mtfCand2->getFiredLayerCnt()) { isKilled[i2] = true; } else isKilled[i1] = true; } + LogTrace("l1tOmtfEventPrint") << " mtfCand2 PhiRad " << mtfCand2->getPhiRad() << " etaRad " + << mtfCand2->getEtaRad() << " deltaPhi " << deltaPhi << " isKilled[i2] " + << isKilled[i2] << " isKilled[i1] " << isKilled[i1]; } } } - std::vector resultCands; + FinalMuons resultCands; - for (unsigned int i1 = 0; i1 < mtfCands->size(0); ++i1) { - //dropping candidates with quality 0 !!!!!!!!!!!!!!!!!!!! fixme if not needed - if (!isKilled[i1] && mtfCands->at(0, i1).hwPt()) { - resultCands.push_back(&(mtfCands->at(0, i1))); - ghostBustedProcMuons.push_back(gbCandidates.at(i1)); + LogTrace("l1tOmtfEventPrint") << "\nCandidateSimMuonMatcher::ghostBust - after ghostBusting:" << std::endl; + for (unsigned int i1 = 0; i1 < finalMuons.size(); ++i1) { + //not dropping candidates with quality 0 and 1 + if (!isKilled[i1]) { //&& finalMuons[i1]->getQuality() > 1 + resultCands.push_back(finalMuons[i1]); } - if (mtfCands->at(0, i1).hwPt()) { - LogTrace("l1tOmtfEventPrint") << "CandidateSimMuonMatcher::ghostBust\n regionalCand pt " << std::setw(3) - << mtfCands->at(0, i1).hwPt() << " qual " << std::setw(2) - << mtfCands->at(0, i1).hwQual() << " proc " << std::setw(2) - << mtfCands->at(0, i1).processor() << " eta " << std::setw(4) - << mtfCands->at(0, i1).hwEta() << " gloablEta " << std::setw(8) - << mtfCands->at(0, i1).hwEta() * 0.010875 << " hwPhi " << std::setw(3) - << mtfCands->at(0, i1).hwPhi() << " globalPhi " << std::setw(8) - << hwGmtPhiToGlobalPhi(omtfConfig->calcGlobalPhi(mtfCands->at(0, i1).hwPhi(), - mtfCands->at(0, i1).processor())) - << " fireadLayers " << std::bitset<18>(mtfCands->at(0, i1).trackAddress().at(0)) - << " gb isKilled " << isKilled.test(i1) << std::endl; - - LogTrace("l1tOmtfEventPrint") << *(gbCandidates.at(i1)) << std::endl; + //if (finalMuons[i1]->getPtGmt() > 0) checked earlier, so it is not needed here + { //PtGmt > 0 marks valid candidate both for phase1 and phase2. But it should not matter here, as all finalMuons are not empty + + LogTrace("l1tOmtfEventPrint") << *(finalMuons[i1]) << " gb isKilled " << isKilled.test(i1) << std::endl; + //LogTrace("l1tOmtfEventPrint") << *(gbCandidates.at(i1)) << std::endl; + if (finalMuons[i1]->getAlgoMuon()) + LogTrace("l1tOmtfEventPrint") << *(finalMuons[i1]->getAlgoMuon()) << std::endl; + LogTrace("l1tOmtfEventPrint") << std::endl; } } @@ -339,18 +500,27 @@ std::vector CandidateSimMuonMatcher::ghostBust( return resultCands; } -TrajectoryStateOnSurface CandidateSimMuonMatcher::atStation2(const FreeTrajectoryState& ftsStart) const { +TrajectoryStateOnSurface CandidateSimMuonMatcher::atStation1(const FreeTrajectoryState& ftsStart) const { // propagate to MB1, which defines the OMTF region (W+-2 MB1 is connected only to the OMTF) // 415 cm is R of RB1in, 660.5cm is |z| of the edge of MB2 (B field on) - ReferenceCountingPointer rpc = ReferenceCountingPointer( - new BoundCylinder(GlobalPoint(0., 0., 0.), TkRotation(), SimpleCylinderBounds(415., 415., -660.5, 660.5))); + ReferenceCountingPointer rpc = ReferenceCountingPointer(new BoundCylinder( + GlobalPoint(0., 0., 0.), TkRotation(), SimpleCylinderBounds(431.133, 431.133, -660.5, 660.5))); + //N.B. zMin and zMax do not matter for the propagator->propagate, i.e. there is not cut on them TrajectoryStateOnSurface trackAtRPC = propagator->propagate(ftsStart, *rpc); return trackAtRPC; } +TrajectoryStateOnSurface CandidateSimMuonMatcher::atStation2(const FreeTrajectoryState& ftsStart) const { + ReferenceCountingPointer surface = ReferenceCountingPointer(new BoundCylinder( + GlobalPoint(0., 0., 0.), TkRotation(), SimpleCylinderBounds(512.401, 512.401, -900, 900))); + + TrajectoryStateOnSurface tsof = propagator->propagate(ftsStart, *surface); + return tsof; +} + FreeTrajectoryState CandidateSimMuonMatcher::simTrackToFts(const SimTrack& simTrackPtr, const SimVertex& simVertex) { - int charge = simTrackPtr.type() > 0 ? -1 : 1; //works for muons + int charge = simTrackPtr.charge(); //simTrackPtr.type() > 0 ? -1 : 1; //works for muons GlobalVector p3GV(simTrackPtr.momentum().x(), simTrackPtr.momentum().y(), simTrackPtr.momentum().z()); GlobalPoint r3GP(simVertex.position().x(), simVertex.position().y(), simVertex.position().z()); @@ -361,7 +531,7 @@ FreeTrajectoryState CandidateSimMuonMatcher::simTrackToFts(const SimTrack& simTr } FreeTrajectoryState CandidateSimMuonMatcher::simTrackToFts(const TrackingParticle& trackingParticle) { - int charge = trackingParticle.pdgId() > 0 ? -1 : 1; //works for muons + int charge = trackingParticle.charge(); //trackingParticle.pdgId() > 0 ? -1 : 1; //works for muons GlobalVector p3GV(trackingParticle.momentum().x(), trackingParticle.momentum().y(), trackingParticle.momentum().z()); GlobalPoint r3GP(trackingParticle.vx(), trackingParticle.vy(), trackingParticle.vz()); @@ -382,6 +552,8 @@ TrajectoryStateOnSurface CandidateSimMuonMatcher::propagate(const SimTrack& simT if (((int)simVertex.vertexId()) != vtxInd) { edm::LogImportant("l1tOmtfEventPrint") << "simVertex.vertexId() != vtxInd. simVertex.vertexId() " << simVertex.vertexId() << " vtxInd " << vtxInd << " !!!!!!!!!!!!!!!!!"; + throw cms::Exception("CandidateSimMuonMatcher", + "CandidateSimMuonMatcher::propagate: simVertex.vertexId() != vtxInd"); } } @@ -407,132 +579,72 @@ float normal_pdf(float x, float m, float s) { return inv_sqrt_2pi / s * std::exp(-0.5 * a * a); } -MatchingResult CandidateSimMuonMatcher::match(const l1t::RegionalMuonCand* muonCand, - const AlgoMuonPtr& procMuon, - const SimTrack& simTrack, - TrajectoryStateOnSurface& tsof) { - MatchingResult result(simTrack); +void CandidateSimMuonMatcher::match(const FinalMuonPtr& finalMuon, MatchingResult& result) { + double trackPt = result.genPt; - double candGloablEta = muonCand->hwEta() * 0.010875; //if (std::abs(simTrack.momentum().eta() - candGloablEta) < 0.3) //has no sense for displaced muons { - double candGlobalPhi = omtfConfig->calcGlobalPhi(muonCand->hwPhi(), muonCand->processor()); - candGlobalPhi = hwGmtPhiToGlobalPhi(candGlobalPhi); + result.muonCand = finalMuon; - if (candGlobalPhi > M_PI) - candGlobalPhi = candGlobalPhi - (2. * M_PI); + if (matchingType == MatchingType::simplePropagation) { + //int charge = result.pdgId > 0 ? -1 : 1; //works for muons - result.deltaPhi = foldPhi(tsof.globalPosition().phi() - candGlobalPhi); - result.deltaEta = tsof.globalPosition().eta() - candGloablEta; + TH1* medianDelta = nullptr; + TH1* minDelta = nullptr; + TH1* maxDelta = nullptr; - result.propagatedPhi = tsof.globalPosition().phi(); - result.propagatedEta = tsof.globalPosition().eta(); + if (result.genCharge == 1) { + medianDelta = medianDelta_pos; + minDelta = minDelta_pos; + maxDelta = maxDelta_pos; + } else { + medianDelta = medianDelta_neg; + minDelta = minDelta_neg; + maxDelta = maxDelta_neg; + } - double mean = 0; - double sigma = 1; - //if(!fillMean) - { - auto ptBin = deltaPhiPropCandMean->FindBin(simTrack.momentum().pt()); - mean = deltaPhiPropCandMean->GetBinContent(ptBin); - sigma = deltaPhiPropCandStdDev->GetBinContent(ptBin); - } - result.matchingLikelihood = normal_pdf(result.deltaPhi, mean, sigma); //TODO temporary solution - - result.muonCand = muonCand; - result.procMuon = procMuon; - - //for displaced muons in H2ll - double treshold = 0.15; //pt > 30 - if (simTrack.momentum().pt() < - 10) //TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! tune the threshold!!!!!! - treshold = 0.3; - else if (simTrack.momentum().pt() < - 30) //TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! tune the threshold!!!!!! - treshold = 0.22; - - if (std::abs(result.deltaPhi - mean) < treshold && std::abs(result.deltaEta) < 0.3) - result.result = MatchingResult::ResultType::matched; - - LogTrace("l1tOmtfEventPrint") << "CandidateSimMuonMatcher::match: simTrack type " << simTrack.type() << " pt " - << std::setw(8) << simTrack.momentum().pt() << " eta " << std::setw(8) - << simTrack.momentum().eta() << " phi " << std::setw(8) << simTrack.momentum().phi() - << " propagation eta " << std::setw(8) << tsof.globalPosition().eta() << " phi " - << tsof.globalPosition().phi() << "\n muonCand pt " << std::setw(8) - << muonCand->hwPt() << " candGloablEta " << std::setw(8) << candGloablEta - << " candGlobalPhi " << std::setw(8) << candGlobalPhi << " hwQual " - << muonCand->hwQual() << " deltaEta " << std::setw(8) << result.deltaEta - << " deltaPhi " << std::setw(8) << result.deltaPhi << " sigma " << std::setw(8) - << sigma << " Likelihood " << std::setw(8) << result.matchingLikelihood << " result " - << (short)result.result << std::endl; - } + auto ptBin = medianDelta->FindBin(trackPt); + auto min = minDelta->GetBinContent(ptBin); + auto max = maxDelta->GetBinContent(ptBin); - return result; -} + result.propagatedPhi = foldPhi(result.genPhi + medianDelta->GetBinContent(ptBin)); -MatchingResult CandidateSimMuonMatcher::match(const l1t::RegionalMuonCand* muonCand, - const AlgoMuonPtr& procMuon, - const TrackingParticle& trackingParticle, - TrajectoryStateOnSurface& tsof) { - MatchingResult result(trackingParticle); + result.deltaPhi = foldPhi(result.genPhi - finalMuon->getPhiRad()); + result.deltaEta = result.propagatedEta - finalMuon->getEtaRad(); - double candGloablEta = muonCand->hwEta() * 0.010875; - //if (std::abs(trackingParticle.momentum().eta() - candGloablEta) < 0.3) //has no sense for displaced muons - { - double candGlobalPhi = omtfConfig->calcGlobalPhi(muonCand->hwPhi(), muonCand->processor()); - candGlobalPhi = hwGmtPhiToGlobalPhi(candGlobalPhi); + result.matchingLikelihood = 1. / (std::abs(result.deltaPhi) + 0.001); - if (candGlobalPhi > M_PI) - candGlobalPhi = candGlobalPhi - (2. * M_PI); + if (result.deltaPhi > min && result.deltaPhi < max && std::abs(result.deltaEta) < 0.4) + result.result = MatchingResult::ResultType::matched; + } else if (matchingType == MatchingType::withPropagator) { + result.deltaPhi = foldPhi(result.propagatedPhi - finalMuon->getPhiRad()); + result.deltaEta = result.propagatedEta - finalMuon->getEtaRad(); //propagatedEta is set in propagate - result.deltaPhi = foldPhi(tsof.globalPosition().phi() - candGlobalPhi); - result.deltaEta = tsof.globalPosition().eta() - candGloablEta; + result.matchingLikelihood = 1. / (std::abs(result.deltaPhi) + 0.001); - result.propagatedPhi = tsof.globalPosition().phi(); - result.propagatedEta = tsof.globalPosition().eta(); + double mean = 0; + double treshold = 0; - double mean = 0; - double sigma = 1; - //if(!fillMean) - { - auto ptBin = deltaPhiPropCandMean->FindBin(trackingParticle.pt()); + //for displaced muons in H2ll + //here a coarse threshold are used, as for dispalced muons + treshold = 0.15; //pt > 30 + if (trackPt < 10) //TODO!!!!!!!!!!!!!!!!!!!!! tune the threshold!!!!!! + treshold = 0.4; + else if (trackPt < 30) //TODO!!!!!!!!!!!!!!! tune the threshold!!!!!! + treshold = 0.22; - mean = deltaPhiPropCandMean->GetBinContent(ptBin); - sigma = deltaPhiPropCandStdDev->GetBinContent(ptBin); + mean = 0; + + if (std::abs(result.deltaPhi - mean) < treshold && std::abs(result.deltaEta) < 0.4) + result.result = MatchingResult::ResultType::matched; } - result.matchingLikelihood = normal_pdf(result.deltaPhi, mean, sigma); //TODO temporary solution - - result.muonCand = muonCand; - result.procMuon = procMuon; - - double treshold = 6. * sigma; - if (trackingParticle.pt() > 20) - treshold = 7. * sigma; - if (trackingParticle.pt() > 100) - treshold = 20. * sigma; - - if (std::abs(result.deltaPhi - mean) < treshold && std::abs(result.deltaEta) < 0.3) - result.result = MatchingResult::ResultType::matched; - - LogTrace("l1tOmtfEventPrint") << "CandidateSimMuonMatcher::match: trackingParticle type " - << trackingParticle.pdgId() << " pt " << std::setw(8) << trackingParticle.pt() - << " eta " << std::setw(8) << trackingParticle.momentum().eta() << " phi " - << std::setw(8) << trackingParticle.momentum().phi() << " propagation eta " - << std::setw(8) << tsof.globalPosition().eta() << " phi " - << tsof.globalPosition().phi() << " muonCand pt " << std::setw(8) << muonCand->hwPt() - << " candGloablEta " << std::setw(8) << candGloablEta << " candGlobalPhi " - << std::setw(8) << candGlobalPhi << " hwQual " << muonCand->hwQual() << " deltaEta " - << std::setw(8) << result.deltaEta << " deltaPhi " << std::setw(8) << result.deltaPhi - << " Likelihood " << std::setw(8) << result.matchingLikelihood << " result " - << (short)result.result << std::endl; + LogTrace("l1tOmtfEventPrint") << "CandidateSimMuonMatcher::match::" << __LINE__ << "\n" << result << std::endl; } - - return result; } std::vector CandidateSimMuonMatcher::cleanMatching(std::vector matchingResults, - std::vector& muonCands, - AlgoMuons& ghostBustedProcMuons) { + const FinalMuons& finalMuons) { //Cleaning the matching std::sort( matchingResults.begin(), matchingResults.end(), [](const MatchingResult& a, const MatchingResult& b) -> bool { @@ -558,19 +670,14 @@ std::vector CandidateSimMuonMatcher::cleanMatching(std::vectorFill(ptGen, matchingResult.deltaPhi); //filling overflow is ok here - deltaPhiPropCandStdDev->Fill(ptGen, matchingResult.deltaPhi * matchingResult.deltaPhi); - }*/ - } } - //adding the muonCand-s that were not matched, i.e. in order to analyze them later - unsigned int iCand = 0; - for (auto& muonCand : muonCands) { + //adding the muonCand-s that were not matched, e.g. in order to analyze them later + for (auto& muonCand : finalMuons) { + //PtGmt > 0 marks valid candidate both for phase1 and phase2. But this check is done in ghostBust + //if(muonCand->getPtGmt() == 0) // || muonCand->getQuality() == 0 + // continue; + bool isMatched = false; for (auto& matchingResult : cleanedMatchingResults) { if (matchingResult.muonCand == muonCand) { @@ -582,40 +689,141 @@ std::vector CandidateSimMuonMatcher::cleanMatching(std::vectorhwPt() << " hwQual " - << result.muonCand->hwQual() << " hwEta " << result.muonCand->hwEta() - << " deltaEta " << std::setw(8) << result.deltaEta << " deltaPhi " << std::setw(8) - << result.deltaPhi << " Likelihood " << std::setw(8) << result.matchingLikelihood - << " result " << (short)result.result; - LogTrace("l1tOmtfEventPrint") << " procMuon " << *(result.procMuon) << std::endl; - } else - LogTrace("l1tOmtfEventPrint") << " no muonCand " - << " result " << (short)result.result << std::endl; + LogTrace("l1tOmtfEventPrint") << result << std::endl << std::endl; } LogTrace("l1tOmtfEventPrint") << " " << std::endl; return cleanedMatchingResults; } -std::vector CandidateSimMuonMatcher::match(std::vector& muonCands, - AlgoMuons& ghostBustedProcMuons, +void CandidateSimMuonMatcher::propagate(MatchingResult& result) { + auto doSimplePropagation = [&]() { + TH1* medianDelta = result.genCharge == 1 ? medianDelta_pos : medianDelta_neg; + auto ptBin = medianDelta->FindBin(result.genPt); + result.propagatedPhi = foldPhi(result.genPhi + medianDelta->GetBinContent(ptBin)); + result.propagatedEta = result.genEta; + }; + + if (matchingType == MatchingType::withPropagator) { + FreeTrajectoryState ftsTrack; + if (result.simTrack) { + if (result.simVertex) { + ftsTrack = simTrackToFts(*(result.simTrack), *(result.simVertex)); + } else { + throw cms::Exception("CandidateSimMuonMatcher") + << "CandidateSimMuonMatcher::propagate - simTrack exists but simVertex is missing!!!"; + //throw, to be sue that the issue is noticed. + // Alternatively, if simTrack exists but simVertex is missing, + // fall back to a default vertex at (0,0,0). Or doSimplePropagation(). + SimVertex defVtx; // default constructed vertex at origin + ftsTrack = simTrackToFts(*(result.simTrack), defVtx); + edm::LogImportant("l1tOmtfEventPrint") + << "CandidateSimMuonMatcher::propagate - simTrack has no simVertex, using default vertex" << std::endl; + } + } else if (result.trackingParticle) { + if (result.trackingParticle->parentVertex().isNonnull()) + ftsTrack = simTrackToFts(*result.trackingParticle); + else { + edm::LogImportant("l1tOmtfEventPrint") + << "CandidateSimMuonMatcher::propagate - trackingParticle has no parentVertex!!!" << std::endl; + throw cms::Exception("CandidateSimMuonMatcher") + << "CandidateSimMuonMatcher::propagate - trackingParticle has no parentVertex!!!"; + } + } else { + // Nothing to propagate + result.result = MatchingResult::ResultType::propagationFailed; + return; + } + //TODO check if the ftsTrack is valid + TrajectoryStateOnSurface tsof = atStation2(ftsTrack); //propagation + + if (!tsof.isValid()) { + if (result.genPt > 2.5 && result.trackingParticle && result.trackingParticle->parentVertex().isNonnull()) { + if (result.muonRho < 40) { //TODO why it is done only for trackingParticle and not for simTrack? + doSimplePropagation(); + } + } else { + result.result = MatchingResult::ResultType::propagationFailed; + //result.propagatedEta = 0 in this case + } + } else { + result.propagatedPhi = tsof.globalPosition().phi(); + result.propagatedEta = tsof.globalPosition().eta(); + } + } else if (matchingType == MatchingType::simplePropagation) { + doSimplePropagation(); + } +} + +void CandidateSimMuonMatcher::match(const FinalMuons& finalMuons, + MatchingResult& result, + std::vector& matchingResults) { + propagate(result); + if (result.result == MatchingResult::ResultType::propagationFailed) { //no sense to do matching + + //TODO For the displaced muons adding the muons for which the propagation failed in principle has no sense + //as matching with candidates is not possible then. + //For prompt muons this can be useful, to have the full pt spectrum of gen muons. + //However, using them in the denominator of the efficiency biases the efficiency, because for these muons matching to the candidates is not possible. + //In any case these results are marked in the DataROOTDumper2 omtfEvent.muonEvent = -2. + LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << ":" << __LINE__ << " propagation failed: genPt " << result.genPt + << " genEta " << result.genEta << " eventId " //<< simTrack.eventId().event() + << std::endl; + + //matchingResults.push_back(result); + } else { + //checking if the propagated track is inside the OMTF range, TODO - tune the range!!!!!!!!!!!!!!!!! + //eta 0.7 is the beginning of the MB2, + //the eta range wider than the nominal OMTF region is needed, as in any case muons outside this region are seen by the OMTF + //so it is better to match them to simMuon, otherwise they look like ghosts. + //Besides, it better to train the nn suich that is able to measure its pt, as it may affect the rate + if ((std::abs(result.propagatedEta) >= 0.7) && (std::abs(result.propagatedEta) <= 1.31)) { + LogTrace("l1tOmtfEventPrint") + << "CandidateSimMuonMatcher::match simTrack IS in OMTF region, matching to the omtfCands, propagatedEta: " + << result.propagatedEta; + } else { + LogTrace("l1tOmtfEventPrint") << "simTrack NOT in OMTF region "; + return; + } + + /* TODO fix if filling of the deltaPhiPropCandMean and deltaPhiPropCandStdDev is needed + double ptGen = simTrack.momentum().pt(); + if(ptGen >= deltaPhiVertexProp->GetXaxis()->GetXmax()) + ptGen = deltaPhiVertexProp->GetXaxis()->GetXmax() - 0.01; + + deltaPhiVertexProp->Fill(ptGen, simTrack.momentum().phi() - tsof.globalPosition().phi());*/ + + bool matched = false; + for (auto& muonCand : finalMuons) { + //dropping very low quality candidates, as they are fakes usually - but it has no sense, then the results are not conclusive + //if (muonCand->getQuality() > 1) + { //TOOD uncomment, if this condition is needed + MatchingResult resultCopy = result; + + match(muonCand, resultCopy); + + if (resultCopy.result == MatchingResult::ResultType::matched) { + matchingResults.push_back(resultCopy); + matched = true; + } + } + } + + if (!matched) { //adding matchingResults (i.e. simMuon in this case) also if it was not matched to any candidate + matchingResults.push_back(result); + LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << ":" << __LINE__ << " no matching candidate found" << std::endl; + } + } +} + +std::vector CandidateSimMuonMatcher::match(const FinalMuons& finalMuons, const edm::SimTrackContainer* simTracks, const edm::SimVertexContainer* simVertices, std::function const& simTrackFilter) { @@ -625,78 +833,36 @@ std::vector CandidateSimMuonMatcher::match(std::vector= 0 ? simVertices->at(simTrack.vertIndex()).position().Rho() + : -99) << std::endl; - bool matched = false; - - TrajectoryStateOnSurface tsof = propagate(simTrack, simVertices); - if (!tsof.isValid()) { //no sense to do matching - MatchingResult result(simTrack); - result.result = MatchingResult::ResultType::propagationFailed; - LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << ":" << __LINE__ << " propagation failed: genPt " << result.genPt - << " genEta " << result.genEta << " eventId " << simTrack.eventId().event() - << std::endl; - - matchingResults.push_back(result); + SimVertex simVertex; + int vtxInd = simTrack.vertIndex(); + if (vtxInd < 0) { + edm::LogImportant("l1tOmtfEventPrint") << "Track with no vertex, defaulting to (0,0,0)"; } else { - //checking if the propagated track is inside the OMTF range, TODO - tune the range!!!!!!!!!!!!!!!!! - //eta 0.7 is the beginning of the MB2, - //the eta range wider than the nominal OMTF region is needed, as in any case muons outside this region are seen by the OMTF - //so it better to train the nn suich that is able to measure its pt, as it may affect the rate - if ((std::abs(tsof.globalPosition().eta()) >= 0.7) && (std::abs(tsof.globalPosition().eta()) <= 1.31)) { - LogTrace("l1tOmtfEventPrint") - << "CandidateSimMuonMatcher::match simTrack IS in OMTF region, matching to the omtfCands"; - } else { - LogTrace("l1tOmtfEventPrint") << "simTrack NOT in OMTF region "; - continue; + simVertex = simVertices->at(vtxInd); + if (((int)simVertex.vertexId()) != vtxInd) { + edm::LogImportant("l1tOmtfEventPrint") << "simVertex.vertexId() != vtxInd. simVertex.vertexId() " + << simVertex.vertexId() << " vtxInd " << vtxInd << " !!!!!!!!!!!!!!!!!"; } + } - /* TODO fix if filling of the deltaPhiPropCandMean and deltaPhiPropCandStdDev is needed - double ptGen = simTrack.momentum().pt(); - if(ptGen >= deltaPhiVertexProp->GetXaxis()->GetXmax()) - ptGen = deltaPhiVertexProp->GetXaxis()->GetXmax() - 0.01; - - deltaPhiVertexProp->Fill(ptGen, simTrack.momentum().phi() - tsof.globalPosition().phi());*/ - - unsigned int iCand = 0; - for (auto& muonCand : muonCands) { - //dropping very low quality candidates, as they are fakes usually - but it has no sense, then the results are not conclusive - //if(muonCand->hwQual() > 1) - { - MatchingResult result; - if (tsof.isValid()) { - result = match(muonCand, ghostBustedProcMuons.at(iCand), simTrack, tsof); - } - int vtxInd = simTrack.vertIndex(); - if (vtxInd >= 0) { - result.simVertex = &(simVertices->at( - vtxInd)); //TODO ?????? something strange is here, was commented in the previous version - } - if (result.result == MatchingResult::ResultType::matched) { - matchingResults.push_back(result); - matched = true; - } - } - iCand++; - } + MatchingResult result(simTrack, simTrack.vertIndex() >= 0 ? &(simVertices->at(simTrack.vertIndex())) : nullptr); - if (!matched) { //we are adding also if it was not matching to any candidate - MatchingResult result(simTrack); - matchingResults.push_back(result); - LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << ":" << __LINE__ << " no matching candidate found" << std::endl; - } - } + match(finalMuons, result, matchingResults); } - return cleanMatching(matchingResults, muonCands, ghostBustedProcMuons); + return cleanMatching(matchingResults, finalMuons); } std::vector CandidateSimMuonMatcher::match( - std::vector& muonCands, - AlgoMuons& ghostBustedProcMuons, + const FinalMuons& finalMuons, const TrackingParticleCollection* trackingParticles, std::function const& simTrackFilter) { std::vector matchingResults; @@ -711,72 +877,19 @@ std::vector CandidateSimMuonMatcher::match( LogTrace("l1tOmtfEventPrint") << "CandidateSimMuonMatcher::match, trackingParticle type " << std::setw(3) << trackingParticle.pdgId() << " pt " << std::setw(9) << trackingParticle.pt() - << " eta " << std::setw(9) << trackingParticle.momentum().eta() << " phi " + << " GeV eta " << std::setw(9) << trackingParticle.momentum().eta() << " phi " << std::setw(9) << trackingParticle.momentum().phi() << std::endl; - bool matched = false; - - TrajectoryStateOnSurface tsof = propagate(trackingParticle); - if (!tsof.isValid()) { - LogTrace("l1tOmtfEventPrint") << "CandidateSimMuonMatcher::match:" << __LINE__ << " propagation failed" - << std::endl; - MatchingResult result; - result.result = MatchingResult::ResultType::propagationFailed; - continue; //no sense to do matching - } - - LogTrace("l1tOmtfEventPrint") << "CandidateSimMuonMatcher::match, tsof.globalPosition().eta() " - << tsof.globalPosition().eta(); - - //checking if the propagated track is inside the OMTF range, TODO - tune the range!!!!!!!!!!!!!!!!! - //eta 0.7 is the beginning of the MB2, while 1.31 is mid of RE2 + some margin - if ((std::abs(tsof.globalPosition().eta()) >= 0.7) && (std::abs(tsof.globalPosition().eta()) <= 1.31)) { - LogTrace("l1tOmtfEventPrint") - << "CandidateSimMuonMatcher::match trackingParticle IS in OMTF region, matching to the omtfCands"; - } else { - LogTrace("l1tOmtfEventPrint") << "trackingParticle NOT in OMTF region "; - continue; - } - - /* TODO fix if filling of the deltaPhiPropCandMean and deltaPhiPropCandStdDev is needed - double ptGen = trackingParticle.pt(); - if(ptGen >= deltaPhiVertexProp->GetXaxis()->GetXmax()) - ptGen = deltaPhiVertexProp->GetXaxis()->GetXmax() - 0.01; - - deltaPhiVertexProp->Fill(ptGen, trackingParticle.momentum().phi() - tsof.globalPosition().phi()); - */ - - unsigned int iCand = 0; - for (auto& muonCand : muonCands) { - //dropping very low quality candidates, as they are fakes usually - but it has no sense, then the results are not conclusive then - /*if(muonCand->hwQual() <= 1) - continue; */ - - MatchingResult result; - if (tsof.isValid()) { - result = match(muonCand, ghostBustedProcMuons.at(iCand), trackingParticle, tsof); - } - iCand++; - - if (result.result == MatchingResult::ResultType::matched) { - matchingResults.push_back(result); - matched = true; - } - } + MatchingResult result(trackingParticle); - if (!matched) { //we are adding result also if it there was no matching to any candidate - MatchingResult result(trackingParticle); - matchingResults.push_back(result); - LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << ":" << __LINE__ << " no matching candidate found" << std::endl; - } + match(finalMuons, result, matchingResults); } - return cleanMatching(matchingResults, muonCands, ghostBustedProcMuons); + return cleanMatching(matchingResults, finalMuons); } std::vector CandidateSimMuonMatcher::matchSimple( - std::vector& muonCands, - AlgoMuons& ghostBustedProcMuons, + const FinalMuons& finalMuons, const edm::SimTrackContainer* simTracks, const edm::SimVertexContainer* simVertices, std::function const& simTrackFilter) { @@ -787,34 +900,26 @@ std::vector CandidateSimMuonMatcher::matchSimple( continue; LogTrace("l1tOmtfEventPrint") << "CandidateSimMuonMatcher::matchSimple: simTrack type " << std::setw(3) - << simTrack.type() << " pt " << std::setw(9) << simTrack.momentum().pt() << " eta " - << std::setw(9) << simTrack.momentum().eta() << " phi " << std::setw(9) + << simTrack.type() << " pt " << std::setw(9) << simTrack.momentum().pt() + << " GeV eta " << std::setw(9) << simTrack.momentum().eta() << " phi " << std::setw(9) << simTrack.momentum().phi() << std::endl; bool matched = false; - unsigned int iCand = 0; - for (auto& muonCand : muonCands) { + for (auto& finalMuon : finalMuons) { //dropping very low quality candidates, as they are fakes usually - but it has no sense, then the results are not conclusive //if(muonCand->hwQual() > 1) + //if (finalMuon->getPtGev() > 0) in phase-1 ptGeV=0 is possible for a valid candidate { - MatchingResult result(simTrack); + MatchingResult result(simTrack, simTrack.vertIndex() >= 0 ? &(simVertices->at(simTrack.vertIndex())) : nullptr); - double candGloablEta = muonCand->hwEta() * 0.010875; - double candGlobalPhi = omtfConfig->calcGlobalPhi(muonCand->hwPhi(), muonCand->processor()); - candGlobalPhi = hwGmtPhiToGlobalPhi(candGlobalPhi); + result.deltaPhi = foldPhi(result.genPhi - finalMuon->getPhiRad()); + result.deltaEta = result.genEta - finalMuon->getEtaRad(); - if (candGlobalPhi > M_PI) - candGlobalPhi = candGlobalPhi - (2. * M_PI); + result.propagatedPhi = result.genPhi; + result.propagatedEta = result.genEta; - result.deltaPhi = foldPhi(result.genPhi - candGlobalPhi); - result.deltaEta = result.genEta - candGloablEta; - - result.propagatedPhi = 0; - result.propagatedEta = 0; - - result.muonCand = muonCand; - result.procMuon = ghostBustedProcMuons.at(iCand); + result.muonCand = finalMuon; //TODO histogram can be used, like in the usercode/L1MuonAnalyzer MuonMatcher::matchWithoutPorpagation //for prompt muons @@ -828,53 +933,55 @@ std::vector CandidateSimMuonMatcher::matchSimple( else if (simTrack.momentum().pt() < 20) treshold = 0.5;*/ - //for displaced muons - double treshold = 0.7; + double treshold = 0.5; if (simTrack.momentum().pt() < 5) treshold = 1.5; else if (simTrack.momentum().pt() < 10) treshold = 1.0; - else if (simTrack.momentum().pt() < 20) + else if (simTrack.momentum().pt() < 25) treshold = 0.7; if (std::abs(result.deltaPhi) < treshold && std::abs(result.deltaEta) < 0.5) { result.result = MatchingResult::ResultType::matched; //matchingLikelihood is needed in the cleanMatching, so we put something - if (std::abs(result.deltaPhi) < 0.001) - result.matchingLikelihood = 1. / 0.001; - else - result.matchingLikelihood = 1. / std::abs(result.deltaPhi); + result.matchingLikelihood = 1. / (std::abs(result.deltaPhi) + 0.001); } - LogTrace("l1tOmtfEventPrint") << "CandidateSimMuonMatcher::matchSimple: simTrack type " << simTrack.type() - << " pt " << std::setw(8) << simTrack.momentum().pt() << " eta " << std::setw(8) - << simTrack.momentum().eta() << " phi " << std::setw(8) - << simTrack.momentum().phi() << "\n muonCand pt " << std::setw(8) - << muonCand->hwPt() << " candGloablEta " << std::setw(8) << candGloablEta - << " candGlobalPhi " << std::setw(8) << candGlobalPhi << " hwQual " - << muonCand->hwQual() << " deltaEta " << std::setw(8) << result.deltaEta - << " deltaPhi " << std::setw(8) << result.deltaPhi << " matchingLikelihood " - << result.matchingLikelihood << " result " << (short)result.result << std::endl; - - int vtxInd = simTrack.vertIndex(); - if (vtxInd >= 0) { - result.simVertex = &( - simVertices->at(vtxInd)); //TODO ?????? something strange is here, was commented in the previous version - } + LogTrace("l1tOmtfEventPrint") << "CandidateSimMuonMatcher::matchSimple:\n" << result << std::endl; + if (result.result == MatchingResult::ResultType::matched) { matchingResults.push_back(result); matched = true; } } - iCand++; } if (!matched) { //we are adding also if it was not matched to any candidate - MatchingResult result(simTrack); + MatchingResult result(simTrack, simTrack.vertIndex() >= 0 ? &(simVertices->at(simTrack.vertIndex())) : nullptr); + result.propagatedPhi = result.genPhi; + result.propagatedEta = result.genEta; matchingResults.push_back(result); LogTrace("l1tOmtfEventPrint") << __FUNCTION__ << ":" << __LINE__ << " no matching candidate found" << std::endl; } } - return cleanMatching(matchingResults, muonCands, ghostBustedProcMuons); + return cleanMatching(matchingResults, finalMuons); +} + +std::vector CandidateSimMuonMatcher::collectMuonCands(const FinalMuons& finalMuons) { + std::vector matchingResults; + for (auto& finalMuon : finalMuons) { + //dropping very low quality candidates, as they are fakes usually - but it has no sense, then the results are not conclusive + //if(muonCand->hwQual() > 1) + { + MatchingResult result; + + result.muonCand = finalMuon; + + LogTrace("l1tOmtfEventPrint") << "CandidateSimMuonMatcher::collectMuonCands: " << *finalMuon << std::endl; + + matchingResults.push_back(result); + } + } + return matchingResults; } diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Tools/DataROOTDumper2.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Tools/DataROOTDumper2.cc index c5d0b6f040a7e..db362b701ad23 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Tools/DataROOTDumper2.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Tools/DataROOTDumper2.cc @@ -31,17 +31,6 @@ DataROOTDumper2::DataROOTDumper2(const edm::ParameterSet& edmCfg, if (edmCfg.getParameter("dumpKilledOmtfCands")) dumpKilledOmtfCands = true; - if (edmCfg.exists("candidateSimMuonMatcherType")) { - if (edmCfg.getParameter("candidateSimMuonMatcherType") == "propagation") - usePropagation = true; - else if (edmCfg.getParameter("candidateSimMuonMatcherType") == "matchSimple") - usePropagation = false; - - edm::LogImportant("l1tOmtfEventPrint") - << " CandidateSimMuonMatcher: candidateSimMuonMatcherType " - << edmCfg.getParameter("candidateSimMuonMatcherType") << std::endl; - } - edm::LogVerbatim("l1tOmtfEventPrint") << " DataROOTDumper2 created. dumpKilledOmtfCands " << dumpKilledOmtfCands << std::endl; } @@ -65,6 +54,9 @@ void DataROOTDumper2::initializeTTree() { rootTree->Branch("muonDxy", &omtfEvent.muonDxy); rootTree->Branch("muonRho", &omtfEvent.muonRho); + rootTree->Branch("parentPdgId", &omtfEvent.parentPdgId); + rootTree->Branch("vertexEta", &omtfEvent.vertexEta); + rootTree->Branch("vertexPhi", &omtfEvent.vertexPhi); rootTree->Branch("omtfPt", &omtfEvent.omtfPt); rootTree->Branch("omtfUPt", &omtfEvent.omtfUPt); @@ -79,6 +71,7 @@ void DataROOTDumper2::initializeTTree() { rootTree->Branch("omtfQuality", &omtfEvent.omtfQuality); rootTree->Branch("omtfRefLayer", &omtfEvent.omtfRefLayer); rootTree->Branch("omtfRefHitNum", &omtfEvent.omtfRefHitNum); + rootTree->Branch("omtfRefHitPhi", &omtfEvent.omtfRefHitPhi); rootTree->Branch("omtfFiredLayers", &omtfEvent.omtfFiredLayers); //<<<<<<<<<<<<<<<<<<<<<&, const AlgoMuons& algoCandidates, const AlgoMuons& gbCandidates, - const std::vector& candMuons) {} + const FinalMuons& finalMuons) {} -void DataROOTDumper2::observeEventEnd(const edm::Event& iEvent, - std::unique_ptr& finalCandidates) { +void DataROOTDumper2::observeEventEnd(const edm::Event& iEvent, FinalMuons& finalMuons) { /* int muonCharge = 0; if (simMuon) { @@ -137,18 +129,23 @@ void DataROOTDumper2::observeEventEnd(const edm::Event& iEvent, //for some events there are more than one matchingResults, //Usually at least one them has genPt 0, which means no simMuon was matched, so candidate is ghost (or fake) - //so better is to to drop such event, as it is not sue if the correct simMuon was matched to the candidate. + //so better is to to drop such event, as it is not sure if the correct simMuon was matched to the candidate. //So we assume here that when the propagation is not used it is a single mu sample and this filter has sense - //the propagation is used for multi-muon sample, so then this fitler cannot be used + //the propagation is used for multi-muon sample, so then this filter cannot be used //TODO add a flag to enable this filter? Disable it if not needed - if (!usePropagation && matchingResults.size() > 1) { //omtfConfig->cleanStubs() && + //in the single Mu sample, if there are two matchingResults, and the second has genPt 0, so it is easy to fitler it out when reading the dump. + //so better would be to remove this condition, as it may be activated unintentionly + if (candidateSimMuonMatcher->getMatchingType() == CandidateSimMuonMatcher::MatchingType::simpleMatching && + matchingResults.size() > 1) { //omtfConfig->cleanStubs() && edm::LogVerbatim("l1tOmtfEventPrint") << "\nDataROOTDumper2::observeEventEnd matchingResults.size() " << matchingResults.size() << std::endl; for (auto& matchingResult : matchingResults) { edm::LogVerbatim("l1tOmtfEventPrint") << "matchingResult: genPt " << matchingResult.genPt; - if (matchingResult.procMuon) - edm::LogVerbatim("l1tOmtfEventPrint") << " procMuon.PtConstr " << matchingResult.procMuon->getPtConstr(); + if (matchingResult.muonCand) + edm::LogVerbatim("l1tOmtfEventPrint") + << " procMuon.PtConstr " << matchingResult.muonCand->getAlgoMuon()->getPtConstr() << " processor " + << matchingResult.muonCand->getProcessor() << " hwPhi " << matchingResult.muonCand->getAlgoMuon()->getPhi(); else edm::LogVerbatim("l1tOmtfEventPrint") << " no procMuon" << std::endl; } @@ -162,7 +159,10 @@ void DataROOTDumper2::observeEventEnd(const edm::Event& iEvent, if (matchingResult.trackingParticle) { auto trackingParticle = matchingResult.trackingParticle; - omtfEvent.muonEvent = trackingParticle->eventId().event(); + if (matchingResult.result == MatchingResult::ResultType::propagationFailed) + omtfEvent.muonEvent = -2; + else + omtfEvent.muonEvent = trackingParticle->eventId().event(); omtfEvent.muonPt = trackingParticle->pt(); omtfEvent.muonEta = trackingParticle->momentum().eta(); @@ -170,12 +170,21 @@ void DataROOTDumper2::observeEventEnd(const edm::Event& iEvent, omtfEvent.muonPropEta = matchingResult.propagatedEta; omtfEvent.muonPropPhi = matchingResult.propagatedPhi; omtfEvent.muonCharge = (std::abs(trackingParticle->pdgId()) == 13) ? trackingParticle->pdgId() / -13 : 0; + omtfEvent.muonCharge = trackingParticle->charge(); if (trackingParticle->parentVertex().isNonnull()) { omtfEvent.muonDxy = trackingParticle->dxy(); omtfEvent.muonRho = trackingParticle->parentVertex()->position().Rho(); + + for (auto& parentTrack : trackingParticle->parentVertex()->sourceTracks()) { + omtfEvent.parentPdgId = parentTrack->pdgId(); + LogTrace("l1MuonAnalyzerOmtf") << " DataROOTDumper2 parentTrackPdgId " << omtfEvent.parentPdgId << std::endl; + } } + omtfEvent.vertexPhi = matchingResult.vertexPhi; + omtfEvent.vertexEta = matchingResult.vertexEta; + omtfEvent.deltaEta = matchingResult.deltaEta; omtfEvent.deltaPhi = matchingResult.deltaPhi; @@ -195,8 +204,10 @@ void DataROOTDumper2::observeEventEnd(const edm::Event& iEvent, } } else if (matchingResult.simTrack) { auto simTrack = matchingResult.simTrack; - - omtfEvent.muonEvent = simTrack->eventId().event(); + if (matchingResult.result == MatchingResult::ResultType::propagationFailed) + omtfEvent.muonEvent = -2; + else + omtfEvent.muonEvent = simTrack->eventId().event(); omtfEvent.muonPt = simTrack->momentum().pt(); omtfEvent.muonEta = simTrack->momentum().eta(); @@ -205,12 +216,18 @@ void DataROOTDumper2::observeEventEnd(const edm::Event& iEvent, omtfEvent.muonPropPhi = matchingResult.propagatedPhi; omtfEvent.muonCharge = simTrack->charge(); - if (!simTrack->noVertex() && matchingResult.simVertex) { + /*if (!simTrack->noVertex() && matchingResult.simVertex) { const math::XYZTLorentzVectorD& vtxPos = matchingResult.simVertex->position(); omtfEvent.muonDxy = (-vtxPos.X() * simTrack->momentum().py() + vtxPos.Y() * simTrack->momentum().px()) / simTrack->momentum().pt(); omtfEvent.muonRho = vtxPos.Rho(); - } + }*/ + + omtfEvent.muonDxy = matchingResult.muonDxy; + omtfEvent.muonRho = matchingResult.muonRho; + + omtfEvent.vertexPhi = matchingResult.vertexPhi; + omtfEvent.vertexEta = matchingResult.vertexEta; omtfEvent.deltaEta = matchingResult.deltaEta; omtfEvent.deltaPhi = matchingResult.deltaPhi; @@ -246,27 +263,45 @@ void DataROOTDumper2::observeEventEnd(const edm::Event& iEvent, omtfEvent.muonRho = 0; } - auto addOmtfCand = [&](AlgoMuonPtr& procMuon) { - omtfEvent.omtfPt = omtfConfig->hwPtToGev(procMuon->getPtConstr()); - omtfEvent.omtfUPt = omtfConfig->hwUPtToGev(procMuon->getPtUnconstr()); - omtfEvent.omtfEta = omtfConfig->hwEtaToEta(procMuon->getEtaHw()); - omtfEvent.omtfPhi = procMuon->getPhi(); - omtfEvent.omtfCharge = procMuon->getChargeConstr(); - omtfEvent.omtfScore = procMuon->getPdfSum(); + auto addOmtfCand = [&](FinalMuonPtr muonCand) { + //The constrained measurement is always defined for a valid candidate. In principle here only valid candidates should be, so this check is redundant. + if (muonCand->getAlgoMuon()->getPdfSumConstr() > 0 && muonCand->getAlgoMuon()->getFiredLayerCntConstr() >= 3) + omtfEvent.omtfPt = muonCand->getPtGev(); + else if (muonCand->getAlgoMuon()->getPtUnconstr() > 0) + //if myCand->getPdfSumConstr() == 0, the myCand->getPtConstr() might not be 0, see the end of GhostBusterPreferRefDt::select + //but hwPt=0 means empty candidate, hwPt=1 means pt=0, + //but omtfPt = 0 means empty candidate + //therefore here we set omtfPt=0.5 GeV, if the PtUnconstr > 0 + //N.B it is different than in the OMTFProcessor::convertToOuputScalesPhase1, where hwPt=1 + omtfEvent.omtfPt = 0.5; + else + omtfEvent.omtfPt = omtfConfig->hwPtToGev(0); + + //for candidate with no unconstrained measurement, hardware upt = 0 + //so then omtfEvent.omtfUPt is -1 + omtfEvent.omtfUPt = muonCand->getPtUnconstrGev(); + //omtfEvent.omtfEta = omtfConfig->hwEtaToEta(procMuon->getEtaHw()); + omtfEvent.omtfEta = muonCand->getEtaRad(); + omtfEvent.omtfPhi = muonCand->getPhiRad(); + omtfEvent.omtfCharge = muonCand->getAlgoMuon()->getChargeConstr(); + omtfEvent.omtfScore = muonCand->getAlgoMuon()->getPdfSum(); - omtfEvent.omtfHwEta = procMuon->getEtaHw(); + omtfEvent.omtfHwEta = muonCand->getAlgoMuon()->getEtaHw(); - omtfEvent.omtfFiredLayers = procMuon->getFiredLayerBits(); - omtfEvent.omtfRefLayer = procMuon->getRefLayer(); - omtfEvent.omtfRefHitNum = procMuon->getRefHitNumber(); + omtfEvent.omtfFiredLayers = muonCand->getAlgoMuon()->getFiredLayerBits(); + omtfEvent.omtfRefLayer = muonCand->getAlgoMuon()->getRefLayer(); + omtfEvent.omtfRefHitNum = muonCand->getAlgoMuon()->getRefHitNumber(); omtfEvent.hits.clear(); //TODO choose, which gpResult should be dumped //auto& gpResult = procMuon->getGpResultConstr(); - auto& gpResult = (procMuon->getGpResultUnconstr().getPdfSumUnconstr() > procMuon->getGpResultConstr().getPdfSum()) - ? procMuon->getGpResultUnconstr() - : procMuon->getGpResultConstr(); + auto& gpResult = (muonCand->getAlgoMuon()->getGpResultUnconstr().getPdfSumUnconstr() > + muonCand->getAlgoMuon()->getGpResultConstr().getPdfSum()) + ? muonCand->getAlgoMuon()->getGpResultUnconstr() + : muonCand->getAlgoMuon()->getGpResultConstr(); + + omtfEvent.omtfRefHitPhi = gpResult.getRefHitPhi(); /* edm::LogVerbatim("l1tOmtfEventPrint")<<"DataROOTDumper2:;observeEventEnd muonPt "<qualityHw; - hit.eta = stubResult.getMuonStub()->etaHw; //in which scale? + //hit.eta = stubResult.getMuonStub()->etaHw; //replaced by deltaR hit.valid = stubResult.getValid(); - int hitPhi = stubResult.getMuonStub()->phiHw; - unsigned int refLayerLogicNum = omtfConfig->getRefToLogicNumber()[procMuon->getRefLayer()]; - int phiRefHit = gpResult.getStubResults()[refLayerLogicNum].getMuonStub()->phiHw; - - if (omtfConfig->isBendingLayer(iLogicLayer)) { - hitPhi = stubResult.getMuonStub()->phiBHw; - phiRefHit = 0; //phi ref hit for the bending layer set to 0, since it should not be included in the phiDist - } + unsigned int refLayerLogicNum = omtfConfig->getRefToLogicNumber()[muonCand->getAlgoMuon()->getRefLayer()]; - //phiDist = hitPhi - phiRefHit; - hit.phiDist = hitPhi - phiRefHit; + if (false) { //choose what to dump in hit.phiDist: "hitPhi - phiRefHit" or stubResult.getDeltaPhi() + int hitPhi = stubResult.getMuonStub()->phiHw; + int phiRefHit = gpResult.getStubResults()[refLayerLogicNum].getMuonStub()->phiHw; + hit.phiDist = hitPhi - phiRefHit; - /* LogTrace("l1tOmtfEventPrint")<<" muonPt "<getGoldenPatern()->getDistPhiBitShift(iLogicLayer, procMuon->getRefLayer()) - <<" meanDistPhiValue "<getGoldenPatern()->meanDistPhiValue(iLogicLayer, procMuon->getRefLayer())//<<(phiDist != hit.phiDist? "!!!!!!!<<<<<" : "") - <isBendingLayer(iLogicLayer)) { + hit.phiDist = stubResult.getMuonStub()->phiBHw; + } + } else { + //stubResult.getDeltaPhi() includes the extrapolated phi + hit.phiDist = stubResult.getDeltaPhi(); + } - /*if (hit.phiDist > 504 || hit.phiDist < -512) { - edm::LogVerbatim("l1tOmtfEventPrint") + if (refLayerLogicNum == iLogicLayer) + hit.deltaR = stubResult.getMuonStub()->r - 413; //r of the ref hit - r of RB1in + else + hit.deltaR = stubResult.getMuonStub()->r - gpResult.getStubResults()[refLayerLogicNum].getMuonStub()->r; + + LogTrace("l1tOmtfEventPrint") + << " muonPt " << omtfEvent.muonPt << " omtfPt " << omtfEvent.omtfPt << " RefLayer " + << int(omtfEvent.omtfRefLayer) << " layer " << int(hit.layer) << " PdfBin " << stubResult.getPdfBin() + << " hit.phiDist " << hit.phiDist << " valid " << int(hit.valid) << " " //<<" phiDist "<getGoldenPatern()->getDistPhiBitShift(iLogicLayer, procMuon->getRefLayer()) + //<<" meanDistPhiValue "<getGoldenPatern()->meanDistPhiValue(iLogicLayer, procMuon->getRefLayer())//<<(phiDist != hit.phiDist? "!!!!!!!<<<<<" : "") + << endl; + + if (hit.phiDist > 504 || hit.phiDist < -512) { + LogTrace("l1tOmtfEventPrint") << " muonPt " << omtfEvent.muonPt << " omtfPt " << omtfEvent.omtfPt << " RefLayer " << (int)omtfEvent.omtfRefLayer << " layer " << int(hit.layer) << " hit.phiDist " << hit.phiDist << " valid " << stubResult.getValid() << " !!!!!!!!!!!!!!!!!!!!!!!!" << endl; - }*/ + } - DetId detId(stubResult.getMuonStub()->detId); + /*DetId detId(stubResult.getMuonStub()->detId); if (detId.subdetId() == MuonSubdetId::CSC) { CSCDetId cscId(detId); hit.z = cscId.chamber() % 2; - } + }*/ + + //hit.etaHw is char, so we must limit the value being assigned + //it char range is ok with valueP1Scale + //for the phase2 scale something will have to be done TODO + if (stubResult.getMuonStub()->etaHw > 127) + hit.etaHw = 127; + else if (stubResult.getMuonStub()->etaHw < -127) + hit.etaHw = -127; + else + hit.etaHw = stubResult.getMuonStub()->etaHw; omtfEvent.hits.push_back(hit.rawData); + //edm::LogVerbatim("l1tOmtfEventPrint")<<" hit.layer "<<(int)hit.layer<<" hit.phiDist "<hwPt() << " hwSign " << finalCandidate->hwSign() - << " hwQual " << finalCandidate->hwQual() << " hwEta " << std::setw(4) - << finalCandidate->hwEta() << std::setw(4) << " hwPhi " << finalCandidate->hwPhi() - << " eta " << std::setw(9) << (finalCandidate->hwEta() * 0.010875) - << " isKilled " << procMuon->isKilled() << " tRefLayer " << procMuon->getRefLayer() - << " RefHitNumber " << procMuon->getRefHitNumber() << std::endl; + + LogTrace("l1tOmtfEventPrint") << " hwPt " << matchingResult.muonCand->getAlgoMuon()->getPtConstr() << " hwSign " + << matchingResult.muonCand->getAlgoMuon()->getChargeConstr() << " hwQual " + << matchingResult.muonCand->getQuality() << " hwEta " << std::setw(4) + << matchingResult.muonCand->getAlgoMuon()->getEtaHw() << std::setw(4) << " hwPhi " + << matchingResult.muonCand->getAlgoMuon()->getPhi() << " eta " << std::setw(9) + << matchingResult.muonCand->getEtaRad() << " isKilled " + << matchingResult.muonCand->getAlgoMuon()->isKilled() << " tRefLayer " + << matchingResult.muonCand->getAlgoMuon()->getRefLayer() << " RefHitNumber " + << matchingResult.muonCand->getAlgoMuon()->getRefHitNumber() << std::endl; }; - if (matchingResult.muonCand && matchingResult.procMuon->getPtConstr() > 0 && - matchingResult.muonCand->hwQual() >= 1) { + if (matchingResult.muonCand && matchingResult.muonCand->getAlgoMuon()->getPtConstr() > 0 && + matchingResult.muonCand->getQuality() >= 1) { //TODO set the quality, quality 0 has the candidates with eta > 1.3(?) EtaHw >= 121 //&& matchingResult.genPt < 20 - omtfEvent.omtfQuality = matchingResult.muonCand->hwQual(); //procMuon->getQ(); + omtfEvent.omtfQuality = matchingResult.muonCand->getQuality(); //procMuon->getQ(); omtfEvent.killed = false; - omtfEvent.omtfProcessor = matchingResult.muonCand->processor(); + omtfEvent.omtfProcessor = matchingResult.muonCand->getProcessor(); if (matchingResult.muonCand->trackFinderType() == l1t::omtf_neg) { omtfEvent.omtfProcessor *= -1; } - addOmtfCand(matchingResult.procMuon); + addOmtfCand(matchingResult.muonCand); rootTree->Fill(); + /* TODO there are a few problems with dumping the killed muons: there is no procMuon for them, so the global eta and omtfProcessor are not available if (dumpKilledOmtfCands) { for (auto& killedCand : matchingResult.procMuon->getKilledMuons()) { omtfEvent.omtfQuality = 0; @@ -359,7 +421,7 @@ void DataROOTDumper2::observeEventEnd(const edm::Event& iEvent, addOmtfCand(killedCand); rootTree->Fill(); } - } + }*/ } else if (omtfEvent.muonPt > 0) { //checking if there was a simMuon LogTrace("l1tOmtfEventPrint") << "DataROOTDumper2::observeEventEnd no matching omtfCand" << std::endl; diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Tools/EmulationObserverBase.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Tools/EmulationObserverBase.cc index 107321f386eac..94a4ef4090066 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Tools/EmulationObserverBase.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Tools/EmulationObserverBase.cc @@ -24,7 +24,7 @@ void EmulationObserverBase::observeProcesorEmulation(unsigned int iProcessor, const std::shared_ptr& input, const AlgoMuons& algoCandidates, const AlgoMuons& gbCandidates, - const std::vector& candMuons) { + const FinalMuons& finalMuons) { unsigned int procIndx = omtfConfig->getProcIndx(iProcessor, mtfType); unsigned int i = 0; @@ -37,7 +37,7 @@ void EmulationObserverBase::observeProcesorEmulation(unsigned int iProcessor, candProcIndx = procIndx; //should be good, as the regionalMuonCand is created for every gbCandidate in OMTFProcessor::getFinalcandidates - regionalMuonCand = candMuons.at(i); + finalMuon = finalMuons.at(i); //this->algoCandidates = algoCandidates; //TODO uncomment if needed } diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Tools/EventCapture.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Tools/EventCapture.cc index e777e7e05037a..6cde5b241f3ea 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Tools/EventCapture.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Tools/EventCapture.cc @@ -37,8 +37,8 @@ EventCapture::EventCapture(const edm::ParameterSet& edmCfg, << "EventCapture::EventCapture: no InputTag simTracksTag found" << std::endl; //stubsSimHitsMatcher works only with the trackingParticle, because only them are stored in the pilup events - if (this->candidateSimMuonMatcher && edmCfg.exists("trackingParticleTag")) - stubsSimHitsMatcher = std::make_unique(edmCfg, omtfConfig, muonGeometryTokens); + //if (this->candidateSimMuonMatcher && edmCfg.exists("trackingParticleTag")) + // stubsSimHitsMatcher = std::make_unique(edmCfg, omtfConfig, muonGeometryTokens); } EventCapture::~EventCapture() { @@ -51,6 +51,9 @@ void EventCapture::beginRun(edm::EventSetup const& eventSetup) { } void EventCapture::observeEventBegin(const edm::Event& event) { + edm::LogImportant("l1tOmtfEventPrint") << "EventCapture::observeEventBegin event " << event.id() << " auxBx " + << event.eventAuxiliary().bunchCrossing() << " auxBx " << event.bunchCrossing() + << "*************************" << std::endl; simMuons.clear(); if (!simTracksTag.label().empty()) { @@ -78,7 +81,7 @@ void EventCapture::observeProcesorEmulation(unsigned int iProcessor, const std::shared_ptr& input, const AlgoMuons& algoCandidates, const AlgoMuons& gbCandidates, - const std::vector& candMuons) { + const FinalMuons& finalMuons) { unsigned int procIndx = omtfConfig->getProcIndx(iProcessor, mtfType); edm::LogImportant("l1tOmtfEventPrint") << "EventCapture::observeProcesorEmulation : iProcessor" << iProcessor << " mtfType " << mtfType << " procIndx " << procIndx << " OmtfName(procIndx) " @@ -90,8 +93,7 @@ void EventCapture::observeProcesorEmulation(unsigned int iProcessor, gbCandidatesInProcs[procIndx] = gbCandidates; } -void EventCapture::observeEventEnd(const edm::Event& iEvent, - std::unique_ptr& finalCandidates) { +void EventCapture::observeEventEnd(const edm::Event& iEvent, FinalMuons& finalMuons) { std::ostringstream ostr; //filtering @@ -106,7 +108,6 @@ void EventCapture::observeEventEnd(const edm::Event& iEvent, //TODO choose a condition, to print the desired candidates if (matchingResult.muonCand) { dump = true; - bool runStubsSimHitsMatcher = false; if (matchingResult.trackingParticle) { auto trackingParticle = matchingResult.trackingParticle; @@ -122,19 +123,37 @@ void EventCapture::observeEventEnd(const edm::Event& iEvent, << matchingResult.simTrack->momentum().pt() //<<" Beta "<momentum().Beta() << " eta " << std::setw(9) << matchingResult.simTrack->momentum().eta() << " phi " << std::setw(9) << matchingResult.simTrack->momentum().phi() << std::endl; + //TODO choose a condition, to print the desired candidates + if (matchingResult.simTrack->eventId().event() == 0 && + std::abs(matchingResult.simTrack->momentum().eta()) > 0.82 && + std::abs(matchingResult.simTrack->momentum().eta()) < 1.24) { + //&& matchingResult.simTrack->momentum().pt() >= 22. && + //matchingResult.muonCand != nullptr && matchingResult.muonCand->hwPt() < 47) { + dump = true; + } } else { ostr << "no simMuon "; runStubsSimHitsMatcher = true; } ostr << "matched to: " << std::endl; auto finalCandidate = matchingResult.muonCand; - ostr << " hwPt " << finalCandidate->hwPt() << " hwUPt " << finalCandidate->hwPtUnconstrained() << " hwSign " - << finalCandidate->hwSign() << " hwQual " << finalCandidate->hwQual() << " hwEta " << std::setw(4) - << finalCandidate->hwEta() << std::setw(4) << " hwPhi " << finalCandidate->hwPhi() << " eta " - << std::setw(9) << (finalCandidate->hwEta() * 0.010875) << " phi " << std::endl; + ostr << " hwPt " + << matchingResult.muonCand->getAlgoMuon()->getPtConstr() + //<< " hwUPt " << matchingResult.muonCand->getAlgoMuon()->getPtUnconstr() + << " hwUPt " + << matchingResult.muonCand->getPtUnconstrGmt() + //<< " hwSign " << matchingResult.muonCand->getAlgoMuon()->getChargeConstr() + << " hwSign " << matchingResult.muonCand->getSign() << " hwQual " << matchingResult.muonCand->getQuality() + << " hwEta " + << std::setw(4) + //<< matchingResult.muonCand->getAlgoMuon()->getEtaHw() << std::setw(4) << " hwPhi " << matchingResult.muonCand->getAlgoMuon()->getPhi() + << matchingResult.muonCand->getEtaGmt() << std::setw(4) << " hwPhi " + << matchingResult.muonCand->getPhiGmt() << " eta " << std::setw(9) + << matchingResult.muonCand->getEtaRad() << " phi " + << std::endl; // << matchingResult.muonCand->getPhiRad() << std::endl; if (stubsSimHitsMatcher && runStubsSimHitsMatcher) - stubsSimHitsMatcher->match(iEvent, matchingResult.muonCand, matchingResult.procMuon, ostr); + stubsSimHitsMatcher->match(iEvent, matchingResult.muonCand, ostr); } } } else if (!simTracksTag.label().empty()) { @@ -143,8 +162,9 @@ void EventCapture::observeEventEnd(const edm::Event& iEvent, bool wasSimMuInOmtfNeg = false; for (auto& simMuon : simMuons) { //TODO choose a condition, to print the desired events - if (simMuon->eventId().event() == 0 && std::abs(simMuon->momentum().eta()) > 0.82 && - std::abs(simMuon->momentum().eta()) < 1.24 && simMuon->momentum().pt() >= 3.) { + if (simMuon->eventId().event() == 0 && std::abs(simMuon->momentum().eta()) > 0.82) + //&& std::abs(simMuon->momentum().eta()) < 1.24 && simMuon->momentum().pt() >= 22.) + { ostr << "SimMuon: eventId " << simMuon->eventId().event() << " pdgId " << std::setw(3) << simMuon->type() << " pt " << std::setw(9) << simMuon->momentum().pt() //<<" Beta "<momentum().Beta() << " eta " << std::setw(9) << simMuon->momentum().eta() << " phi " << std::setw(9) @@ -160,14 +180,14 @@ void EventCapture::observeEventEnd(const edm::Event& iEvent, bool wasCandInNeg = false; bool wasCandInPos = false; - for (auto& finalCandidate : *finalCandidates) { + for (auto& finalMuon : finalMuons) { //TODO choose a condition, to print the desired candidates - if (finalCandidate.trackFinderType() == l1t::tftype::omtf_neg && finalCandidate.hwQual() >= 12 && - finalCandidate.hwPt() > 20) + if ( //finalCandidate.trackFinderType() == l1t::tftype::omtf_neg && finalCandidate.hwQual() >= 12 && + finalMuon->getAlgoMuon()->getPtConstr() < 47) wasCandInNeg = true; - if (finalCandidate.trackFinderType() == l1t::tftype::omtf_pos && finalCandidate.hwQual() >= 12 && - finalCandidate.hwPt() > 20) + if ( //finalCandidate.trackFinderType() == l1t::tftype::omtf_pos && finalCandidate.hwQual() >= 12 && + finalMuon->getAlgoMuon()->getPtConstr() < 47) wasCandInPos = true; } @@ -195,41 +215,33 @@ void EventCapture::observeEventEnd(const edm::Event& iEvent, ///printing edm::LogVerbatim("l1tOmtfEventPrint") << "##################### EventCapture::observeEventEnd - dump of event " - << iEvent.id() << " #####################################################" - << std::endl; + << iEvent.id() << " bx " << iEvent.bunchCrossing() + << " #####################################################" << std::endl; edm::LogVerbatim("l1tOmtfEventPrint") << ostr.str() << endl; //printing sim muons edm::LogVerbatim("l1tOmtfEventPrint") << "finalCandidates " << std::endl; - for (int bx = finalCandidates->getFirstBX(); bx <= finalCandidates->getLastBX(); bx++) { - for (auto finalCandidateIt = finalCandidates->begin(bx); finalCandidateIt != finalCandidates->end(bx); - finalCandidateIt++) { - auto& finalCandidate = *finalCandidateIt; - int globHwPhi = (finalCandidate.processor()) * 96 + finalCandidate.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 - globHwPhi = (globHwPhi + 600) % 576; - - double globalPhi = globHwPhi * 2. * M_PI / 576; - if (globalPhi > M_PI) - globalPhi = globalPhi - (2. * M_PI); - - int layerHits = (int)finalCandidate.trackAddress().at(0); + //for (int bx = finalCandidates->getFirstBX(); bx <= finalCandidates->getLastBX(); bx++) + { + for (auto& finalMuon : finalMuons) { + int layerHits = finalMuon->getAlgoMuon()->getFiredLayerBits(); std::bitset<18> layerHitBits(layerHits); edm::LogVerbatim("l1tOmtfEventPrint") - << " bx " << bx << " hwPt " << finalCandidate.hwPt() << " hwUPt " << finalCandidate.hwPtUnconstrained() - << " hwSign " << finalCandidate.hwSign() << " hwQual " << finalCandidate.hwQual() << " hwEta " << std::setw(4) - << finalCandidate.hwEta() << std::setw(4) << " hwPhi " << finalCandidate.hwPhi() << " eta " << std::setw(9) - << (finalCandidate.hwEta() * 0.010875) << " phi " << std::setw(9) << globalPhi << " " << layerHitBits - << " processor " << OmtfName(finalCandidate.processor(), finalCandidate.trackFinderType(), omtfConfig) - << std::endl; - - for (auto& trackAddr : finalCandidate.trackAddress()) { - if (trackAddr.first >= 10) - edm::LogVerbatim("l1tOmtfEventPrint") - << "trackAddr first " << trackAddr.first << " second " << trackAddr.second << " ptGeV " - << omtfConfig->hwPtToGev(trackAddr.second); - } + << " bx " << finalMuon->getBx() << " hwPt " + << finalMuon->getAlgoMuon()->getPtConstr() + //<< " hwUPt " << finalMuon->getAlgoMuon()->getPtUnconstr() + << " hwUPt " << finalMuon->getPtUnconstrGmt() << " hwSign " << finalMuon->getAlgoMuon()->getChargeConstr() + << " hwQual " + << finalMuon->getQuality() + //<< " hwEta " << std::setw(4) << finalMuon->getAlgoMuon()->getEtaHw() + << " hwEta " << std::setw(4) + << finalMuon->getEtaGmt() ////////////////////////////////////////////// + //<< std::setw(4) << " hwPhi " << finalMuon->getAlgoMuon()->getPhi() + << std::setw(4) << " hwPhi " << finalMuon->getPhiGmt() ///////////////////////////////////////////// + << " eta " << std::setw(9) << finalMuon->getEtaRad() /////////////////////////////////////////// + << " phi " << std::setw(9) << finalMuon->getPhiRad() << " " << layerHitBits << " processor " + << OmtfName(finalMuon->getProcessor(), finalMuon->trackFinderType(), omtfConfig) << std::endl; } } edm::LogVerbatim("l1tOmtfEventPrint") << std::endl; @@ -247,8 +259,7 @@ void EventCapture::observeEventEnd(const edm::Event& iEvent, if (stub && (stub->type != MuonStub::Type::EMPTY)) { layerFired = true; - auto globalPhiRad = omtfConfig->procHwPhiToGlobalPhi( - stub->phiHw, OMTFinputMaker::getProcessorPhiZero(omtfConfig, iProc % omtfConfig->nProcessors())); + auto globalPhiRad = omtfConfig->procPhiOmtfToPhiRad(iProc, stub->phiHw); ostrInput << (*stub) << " globalPhiRad " << globalPhiRad << std::endl; } if (layerFired) @@ -347,8 +358,11 @@ void EventCapture::observeEventEnd(const edm::Event& iEvent, edm::LogVerbatim("l1tOmtfEventPrint") << "\ngbCandidates" << std::endl; for (auto& gbCandidate : gbCandidatesInProcs[iProc]) edm::LogVerbatim("l1tOmtfEventPrint") - << " (" << std::setw(5) << gbCandidate->getPtConstr() << "," << std::setw(5) - << gbCandidate->getPtUnconstr() << "," + << " (" << std::setw(5) << gbCandidate->getPtConstr() << "," + << std::setw(5) + //<< ( (gbCandidate->getPtUnconstr() - 1) / 2 + 1 )<< "," //GMT scale + << (gbCandidate->getPtUnconstr() == 0 ? 0 : ((gbCandidate->getPtUnconstr() - 1) / 2 + 1)) + << "," //GMT scale << std::setw(5) << gbCandidate->getGpResultConstr().getFiredLayerCnt() << "," << std::setw(5) << gbCandidate->getGpResultUnconstr().getFiredLayerCnt() @@ -379,30 +393,28 @@ void EventCapture::observeEventEnd(const edm::Event& iEvent, edm::LogVerbatim("l1tOmtfEventPrint") << "finalCandidates " << std::endl; std::ostringstream ostr; - if (finalCandidates->size(0) > 0) { + //if (finalCandidates->size(0) > 0) + { int iMu = 1; - for (auto finalCandidateIt = finalCandidates->begin(0); finalCandidateIt != finalCandidates->end(0); - finalCandidateIt++) { - auto& finalCandidate = *finalCandidateIt; - - auto omtfName = OmtfName(finalCandidate.processor(), finalCandidate.trackFinderType(), omtfConfig); + for (auto& finalMuon : finalMuons) { + auto omtfName = OmtfName(finalMuon->getProcessor(), finalMuon->trackFinderType(), omtfConfig); if (omtfName == board.name()) { - int layerHits = (int)finalCandidate.trackAddress().at(0); + int layerHits = finalMuon->getAlgoMuon()->getFiredLayerBits(); std::bitset<18> layerHitBits(layerHits); - unsigned int trackAddr = finalCandidate.trackAddress().at(0); - unsigned int uPt = finalCandidate.hwPtUnconstrained(); + unsigned int trackAddr = finalMuon->getAlgoMuon()->getFiredLayerBits(); + unsigned int uPt = finalMuon->getPtUnconstrGmt(); //if(uPt == 0) uPt = 5; //TODO remove when fixed in the FW trackAddr = (uPt << 18) + trackAddr; - ostr << "M" << iMu << ":" << std::setw(4) << finalCandidate.hwPt() << "," << std::setw(4) - << finalCandidate.hwQual() << "," << std::setw(4) << finalCandidate.hwPhi() << "," << std::setw(4) - << std::abs(finalCandidate.hwEta()) + ostr << "M" << iMu << ":" << std::setw(4) << finalMuon->getPtGmt() << "," << std::setw(4) + << finalMuon->getQuality() << "," << std::setw(4) << finalMuon->getPhiGmt() << "," << std::setw(4) + << std::abs(finalMuon->getEtaGmt()) << "," //<getSign() << "," << std::setw(4) << 1 << "; "; //ChValid //<< " -- uPt " << std::setw(10) << uPt << " firedLayers " << finalCandidate.trackAddress().at(0); //<Fill(simMuon->momentum().eta()); - candEta->Fill(omtfConfig->hwEtaToEta(regionalMuonCand.hwEta())); + candEta->Fill(finalMuon->getEtaRad()); double ptSim = simMuon->momentum().pt(); int chargeSim = (abs(simMuon->type()) == 13) ? simMuon->type() / -13 : 0; @@ -159,11 +159,7 @@ void PatternGenerator::updateStat() { bool fired = false; if (gpResult.getStubResults()[iLayer].getMuonStub()) { - if (omtfConfig->isBendingLayer(iLayer)) { - if (gpResult.getStubResults()[iLayer].getMuonStub()->qualityHw >= 4) //TODO change quality cut if needed - fired = true; - } else - fired = true; + fired = true; } if (fired) { //the result is not empty @@ -208,7 +204,7 @@ void PatternGenerator::updateStatUsingMatcher2() { //&& matchingResult.muonCand->hwQual() >= 12 && //matchingResult.muonCand->hwPt() > 38 - AlgoMuon* algoMuon = matchingResult.procMuon.get(); + AlgoMuon* algoMuon = matchingResult.muonCand->getAlgoMuon().get(); if (!algoMuon) { edm::LogImportant("l1tOmtfEventPrint") << ":" << __LINE__ << " algoMuon is null" << std::endl; throw runtime_error("algoMuon is null"); @@ -232,7 +228,7 @@ void PatternGenerator::updateStatUsingMatcher2() { eventCntPerGp[exptPatNum]++; candProcIndx = - omtfConfig->getProcIndx(matchingResult.muonCand->processor(), matchingResult.muonCand->trackFinderType()); + omtfConfig->getProcIndx(matchingResult.muonCand->getProcessor(), matchingResult.muonCand->trackFinderType()); //edm::LogImportant("l1tOmtfEventPrint")<<"\n" <<__FUNCTION__<<": "<<__LINE__<<" exptCandGp "<key()<<" candProcIndx "<& finalCandidates) { +void PatternGenerator::observeEventEnd(const edm::Event& iEvent, FinalMuons& finalMuons) { if (simMuon == nullptr || omtfCand->getGoldenPatern() == nullptr) //no sim muon or empty candidate return; if (abs(simMuon->momentum().eta()) < 0.8 || abs(simMuon->momentum().eta()) > 1.24) return; - PatternOptimizerBase::observeEventEnd(iEvent, finalCandidates); + PatternOptimizerBase::observeEventEnd(iEvent, finalMuons); //updateStat(); //updateStatUsingMatcher2(); @@ -428,7 +423,7 @@ void PatternGenerator::endJob() { //groupPatterns(); IMPORTANT don't call grouping here, just set the groups above!!!! - reCalibratePt(); + //reCalibratePt(); this->writeLayerStat = true; } @@ -452,7 +447,7 @@ void PatternGenerator::upadatePdfs() { //the shift for given pattern and layer should be the same same for all refLayers //otherwise the firmware does not compile - at least the phase-1 //for phase2 - /*if ((gp->key().thePt <= 10) && + if ((gp->key().thePt <= 10) && (iLayer == 1 || iLayer == 3 || iLayer == 5)) { //iRefLayer: MB2, iLayer: MB1 and MB2 phiB gp->setDistPhiBitShift(2, iLayer, iRefLayer); } else if ((gp->key().thePt <= 10) && (iLayer == 10)) { //iRefLayer: MB2, iLayer: RB1_in @@ -466,10 +461,10 @@ void PatternGenerator::upadatePdfs() { //so the shift must be increased (or the group should be divided into to 2 groups, but it will increase fw occupancy gp->setDistPhiBitShift(1, iLayer, iRefLayer); } else - gp->setDistPhiBitShift(0, iLayer, iRefLayer);*/ + gp->setDistPhiBitShift(0, iLayer, iRefLayer); //for phase1 - if ((gp->key().thePt <= 8) && + /*if ((gp->key().thePt <= 8) && (iLayer == 1 || iLayer == 3 || iLayer == 5)) { //iRefLayer: MB2, iLayer: MB1 and MB2 phiB gp->setDistPhiBitShift(2, iLayer, iRefLayer); } else if ((gp->key().thePt <= 10) && (iLayer == 10)) { //iRefLayer: MB2, iLayer: RB1_in @@ -486,7 +481,7 @@ void PatternGenerator::upadatePdfs() { //so the shift must be increased (or the group should be divided into to 2 groups, but it will increase fw occupancy gp->setDistPhiBitShift(0, iLayer, iRefLayer); } else - gp->setDistPhiBitShift(0, iLayer, iRefLayer); + gp->setDistPhiBitShift(0, iLayer, iRefLayer);*/ } } } @@ -738,10 +733,10 @@ void PatternGenerator::modifyClassProb(double step) { //if (ptFrom == 20) //pattern Key_13 // newPdfVal += 1; - if (ptFrom >= 22 && ptFrom <= 26) - newPdfVal += 2; - if (ptFrom == 28) //pattern Key_17 - newPdfVal += 1; + //if (ptFrom >= 22 && ptFrom <= 26) + // newPdfVal += 2; + //if (ptFrom == 28) //pattern Key_17 + // newPdfVal += 1; if (ptFrom == 100) newPdfVal = 16; diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Tools/PatternOptimizerBase.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Tools/PatternOptimizerBase.cc index 459cc767684b5..3f5faf9daf56c 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Tools/PatternOptimizerBase.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Tools/PatternOptimizerBase.cc @@ -105,8 +105,7 @@ void PatternOptimizerBase::printPatterns() { } } -void PatternOptimizerBase::observeEventEnd(const edm::Event& iEvent, - std::unique_ptr& finalCandidates) { +void PatternOptimizerBase::observeEventEnd(const edm::Event& iEvent, FinalMuons& finalMuons) { if (simMuon == nullptr || omtfCand->getGoldenPatern() == nullptr) //no sim muon or empty candidate return; diff --git a/L1Trigger/L1TMuonOverlapPhase1/src/Tools/StubsSimHitsMatching.cc b/L1Trigger/L1TMuonOverlapPhase1/src/Tools/StubsSimHitsMatching.cc index 3343ab331546a..1f1c900abf26a 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/src/Tools/StubsSimHitsMatching.cc +++ b/L1Trigger/L1TMuonOverlapPhase1/src/Tools/StubsSimHitsMatching.cc @@ -5,10 +5,10 @@ * Author: kbunkow */ +#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/FinalMuon.h" #include "L1Trigger/L1TMuonOverlapPhase1/interface/Tools/StubsSimHitsMatcher.h" #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OmtfName.h" #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFinputMaker.h" -#include "L1Trigger/L1TMuonOverlapPhase1/interface/AngleConverterBase.h" #include "FWCore/ParameterSet/interface/ParameterSet.h" #include "FWCore/MessageLogger/interface/MessageLogger.h" @@ -91,10 +91,7 @@ void StubsSimHitsMatcher::beginRun(edm::EventSetup const& eventSetup) { } } -void StubsSimHitsMatcher::match(const edm::Event& iEvent, - const l1t::RegionalMuonCand* omtfCand, - const AlgoMuonPtr& procMuon, - std::ostringstream& ostr) { +void StubsSimHitsMatcher::match(const edm::Event& iEvent, const FinalMuonPtr& finalMuon, std::ostringstream& ostr) { ostr << "stubsSimHitsMatching ---------------" << std::endl; edm::Handle rpcSimHitsHandle; @@ -124,14 +121,14 @@ void StubsSimHitsMatcher::match(const edm::Event& iEvent, edm::Handle trackingParticleHandle; iEvent.getByLabel(trackingParticleTag, trackingParticleHandle); - if (procMuon->isValid() && omtfCand) { - OmtfName board(omtfCand->processor(), omtfCand->trackFinderType(), omtfConfig); - auto processorPhiZero = OMTFinputMaker::getProcessorPhiZero(omtfConfig, omtfCand->processor()); + if (finalMuon->getAlgoMuon()->isValid()) { + OmtfName board(finalMuon->getProcessor(), finalMuon->trackFinderType(), omtfConfig); + auto processorPhiZero = OMTFinputMaker::getProcessorPhiZero(omtfConfig, finalMuon->getProcessor()); std::set matchedTrackInfos; - ostr << board.name() << " " << *procMuon << std::endl; + ostr << board.name() << " " << *finalMuon->getAlgoMuon() << std::endl; - auto& gpResult = procMuon->getGpResultConstr(); + auto& gpResult = finalMuon->getAlgoMuon()->getGpResultConstr(); for (unsigned int iLogicLayer = 0; iLogicLayer < gpResult.getStubResults().size(); ++iLogicLayer) { auto& stub = gpResult.getStubResults()[iLogicLayer].getMuonStub(); if (stub && gpResult.isLayerFired(iLogicLayer)) { @@ -145,7 +142,7 @@ void StubsSimHitsMatcher::match(const edm::Event& iEvent, continue; } - auto stubGlobalPhi = omtfConfig->procHwPhiToGlobalPhi(stub->phiHw, processorPhiZero); + auto stubGlobalPhi = omtfConfig->procPhiOmtfToPhiRad(stub->phiHw, processorPhiZero); ostr << (*stub) << "\nstubGlobalPhi " << stubGlobalPhi << std::endl; switch (stubDetId.subdetId()) { @@ -350,8 +347,8 @@ void StubsSimHitsMatcher::match(const edm::Event& iEvent, } } - ostr << board.name() << " " << *procMuon << std::endl; - ostr << procMuon->getGpResultConstr() << std::endl << std::endl; + ostr << board.name() << " " << *finalMuon->getAlgoMuon() << std::endl; + ostr << finalMuon->getAlgoMuon()->getGpResultConstr() << std::endl << std::endl; int maxMatchedStubs = 0; const TrackingParticle* bestMatchedPart = nullptr; diff --git a/L1Trigger/L1TMuonOverlapPhase1/test/runMuonOverlap_run3_data.py b/L1Trigger/L1TMuonOverlapPhase1/test/runMuonOverlap_run3_data.py index 03b24725d5d4c..6c54577b297db 100644 --- a/L1Trigger/L1TMuonOverlapPhase1/test/runMuonOverlap_run3_data.py +++ b/L1Trigger/L1TMuonOverlapPhase1/test/runMuonOverlap_run3_data.py @@ -1,52 +1,55 @@ # -*- coding: utf-8 -*- import FWCore.ParameterSet.Config as cms -process = cms.Process("L1TMuonEmulation") +from Configuration.Eras.Era_Run3_2025_cff import Run3_2025 +process = cms.Process("L1TMuonEmulation", Run3_2025) import os import sys -loadConfigFrom_sqlite_file = True +loadConfigFrom_sqlite_file = False -loadConfigFrom_fakeOmtfParams = False +loadConfigFrom_fakeOmtfParams = True process.load("FWCore.MessageLogger.MessageLogger_cfi") -process.MessageLogger = cms.Service("MessageLogger", - # suppressInfo = cms.untracked.vstring('AfterSource', 'PostModule'), - destinations=cms.untracked.vstring( - # 'detailedInfo', - # 'critical', +verbose = False +log_threshold = 'INFO' + +if verbose: + process.MessageLogger = cms.Service("MessageLogger", + #suppressInfo = cms.untracked.vstring('AfterSource', 'PostModule'), + destinations = cms.untracked.vstring( + #'detailedInfo', + #'critical', #'cout', #'cerr', - 'omtfEventPrint' + 'omtfEventPrint' ), - categories=cms.untracked.vstring('l1tOmtfEventPrint', 'OMTFReconstruction'), #, 'FwkReport' - # cout=cms.untracked.PSet( - # threshold=cms.untracked.string('INFO'), - # default=cms.untracked.PSet(limit=cms.untracked.int32(0)), - # # INFO = cms.untracked.int32(0), - # # DEBUG = cms.untracked.int32(0), - # l1tOmtfEventPrint=cms.untracked.PSet(limit=cms.untracked.int32(1000000000)), - # OMTFReconstruction=cms.untracked.PSet(limit=cms.untracked.int32(1000000000)), - # #FwkReport=cms.untracked.PSet(reportEvery = cms.untracked.int32(50) ), - # ), - - omtfEventPrint = cms.untracked.PSet( + categories = cms.untracked.vstring('l1tOmtfEventPrint', 'OMTFReconstruction', 'l1MuonAnalyzerOmtf'), + omtfEventPrint = cms.untracked.PSet( filename = cms.untracked.string('log_MuonOverlap_run3_data'), extension = cms.untracked.string('.txt'), - threshold = cms.untracked.string('INFO'), + threshold = cms.untracked.string(log_threshold), default = cms.untracked.PSet( limit = cms.untracked.int32(0) ), #INFO = cms.untracked.int32(0), #DEBUG = cms.untracked.int32(0), l1tOmtfEventPrint = cms.untracked.PSet( limit = cms.untracked.int32(1000000000) ), - OMTFReconstruction = cms.untracked.PSet( limit = cms.untracked.int32(1000000000) ) + OMTFReconstruction = cms.untracked.PSet( limit = cms.untracked.int32(1000000000) ), + l1MuonAnalyzerOmtf = cms.untracked.PSet( limit = cms.untracked.int32(1000000000) ) ), - debugModules=cms.untracked.vstring('simOmtfDigis') - # debugModules = cms.untracked.vstring('*') + debugModules = cms.untracked.vstring('simOmtfDigis', 'L1MuonAnalyzerOmtf', 'CalibratedDigis') + #debugModules = cms.untracked.vstring('*') ) -#process.MessageLogger.cerr.FwkReport.reportEvery = cms.untracked.int32(50) -process.options = cms.untracked.PSet(wantSummary=cms.untracked.bool(False), - # SkipEvent = cms.untracked.vstring('ProductNotFound') + #process.MessageLogger.cerr.FwkReport.reportEvery = cms.untracked.int32(100) +if not verbose: + process.MessageLogger.cerr.FwkReport.reportEvery = cms.untracked.int32(10000) + process.MessageLogger.cerr.threshold = cms.untracked.string('INFO') + process.MessageLogger.cerr.l1tOmtfEventPrint = cms.untracked.PSet( limit = cms.untracked.int32(1000000000) ) + process.MessageLogger.cerr.OMTFReconstruction = cms.untracked.PSet( limit = cms.untracked.int32(1000000000) ) + process.MessageLogger.cerr.l1MuonAnalyzerOmtf = cms.untracked.PSet( limit = cms.untracked.int32(1000000000) ) + + process.options = cms.untracked.PSet(wantSummary = cms.untracked.bool(False), + #SkipEvent = cms.untracked.vstring('ProductNotFound') ) process.source = cms.Source('PoolSource', @@ -59,9 +62,10 @@ #'/store/express/Commissioning2021/ExpressCosmics/FEVT/Express-v1/000/344/566/00000/19ef107a-4cd9-4df0-ba93-dbfbab8df1cb.root', #'/store/express/Commissioning2021/ExpressCosmics/FEVT/Express-v1/000/342/094/00000/038c179a-d2ce-45f0-a7d5-8b2d40017042.root', # only DT, fw 0x0008 - '/store/express/Commissioning2021/ExpressCosmics/FEVT/Express-v1/000/344/266/00000/db2cfbdd-5edf-4ee4-aab0-5bdba105728d.root' #DT and RPC fw 0x0008 + #'/store/express/Commissioning2021/ExpressCosmics/FEVT/Express-v1/000/344/266/00000/db2cfbdd-5edf-4ee4-aab0-5bdba105728d.root' #DT and RPC fw 0x0008 #'/store/express/Commissioning2021/ExpressCosmics/FEVT/Express-v1/000/344/566/00000/19ef107a-4cd9-4df0-ba93-dbfbab8df1cb.root' #'/store/express/Commissioning2021/ExpressCosmics/FEVT/Express-v1/000/347/053/00000/7b486245-96ea-4b7c-9fe7-76c957968785.root' #RPC noise only + 'file:/eos/home-k/kbunkow/cms_data/run3_data/Run2025G_398240_Muon0_raw.root' ), ) @@ -70,17 +74,19 @@ # import of standard configurations process.load('Configuration.StandardSequences.Services_cff') process.load('SimGeneral.HepPDTESSource.pythiapdt_cfi') -process.load('Configuration.Geometry.GeometryExtended2017Reco_cff') +#process.load('Configuration.Geometry.GeometryExtended2017Reco_cff') +process.load("Configuration.StandardSequences.GeometryRecoDB_cff") process.load('Configuration.StandardSequences.MagneticField_AutoFromDBCurrent_cff') process.load('Configuration.StandardSequences.EndOfProcess_cff') process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff') +process.load("Configuration.StandardSequences.RawToDigi_Data_cff") #process.load('Configuration.StandardSequences.RawToDigi_Data_cff') #process.load('EventFilter.L1TRawToDigi.omtfStage2Digis_cfi') #unpacker #process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff') from Configuration.AlCa.GlobalTag import GlobalTag -process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:run2_data', '') +process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:run3_data', '') #process.GlobalTag = GlobalTag(process.GlobalTag, '113X_dataRun3_Prompt_v3', '') #process.GlobalTag = GlobalTag(process.GlobalTag, '102X_upgrade2018_realistic_v16', '') @@ -88,7 +94,7 @@ if loadConfigFrom_fakeOmtfParams : ####Event Setup Producer - process.load('L1Trigger.L1TMuonOverlapPhase1.fakeOmtfParams_cff') + process.load('L1Trigger.L1TMuonOverlapPhase1.fakeOmtfParams_extrapolSimple_cff') #process.omtfParams.configXMLFile = cms.FileInPath("L1Trigger/L1TMuon/data/omtf_config/hwToLogicLayer_0x0008.xml") process.esProd = cms.EDAnalyzer("EventSetupRecordDataGetter", @@ -172,6 +178,7 @@ #+ process.dumpED #+ process.dumpES ) + print("Loading OMTF configuration from fakeOmtfParams_cff") else : process.L1TMuonSeq = cms.Sequence( process.omtfStage2Digis + process.simOmtfDigis @@ -186,5 +193,5 @@ ) #process.output_step = cms.EndPath(process.out) -#process.schedule = cms.Schedule(process.L1TMuonPath) +process.schedule = cms.Schedule(process.L1TMuonPath) #process.schedule.extend([process.output_step]) diff --git a/L1Trigger/L1TMuonOverlapPhase2/interface/InputMakerPhase2.h b/L1Trigger/L1TMuonOverlapPhase2/interface/InputMakerPhase2.h index 92f112f4672f0..20a1ebf276fd9 100644 --- a/L1Trigger/L1TMuonOverlapPhase2/interface/InputMakerPhase2.h +++ b/L1Trigger/L1TMuonOverlapPhase2/interface/InputMakerPhase2.h @@ -9,9 +9,8 @@ #define L1Trigger_L1TMuonOverlapPhase2_InputMakerPhase2_h #include "DataFormats/Common/interface/Handle.h" -#include "DataFormats/L1DTTrackFinder/interface/L1MuDTChambThContainer.h" #include "DataFormats/L1DTTrackFinder/interface/L1Phase2MuDTPhContainer.h" -#include "DataFormats/L1TMuon/interface/RegionalMuonCandFwd.h" +#include "DataFormats/L1DTTrackFinder/interface/L1Phase2MuDTThContainer.h" #include "DataFormats/MuonDetId/interface/DTChamberId.h" #include "FWCore/Utilities/interface/EDGetToken.h" @@ -21,11 +20,17 @@ #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFinputMaker.h" #include "L1Trigger/L1TMuonOverlapPhase2/interface/OmtfPhase2AngleConverter.h" +struct MuStubsPhase2InputTokens { + edm::EDGetTokenT inputTokenDtPh; + edm::EDGetTokenT inputTokenDtTh; +}; + class DtPhase2DigiToStubsConverter : public DigiToStubsConverterBase { public: - DtPhase2DigiToStubsConverter(edm::EDGetTokenT inputTokenDtPh, - edm::EDGetTokenT inputTokenDtTh) - : inputTokenDtPh(inputTokenDtPh), inputTokenDtTh(inputTokenDtTh) {} + DtPhase2DigiToStubsConverter(const OMTFConfiguration* config, + edm::EDGetTokenT inputTokenDtPh, + edm::EDGetTokenT inputTokenDtTh) + : config(config), inputTokenDtPh(inputTokenDtPh), inputTokenDtTh(inputTokenDtTh) {} ~DtPhase2DigiToStubsConverter() override {} @@ -41,12 +46,12 @@ class DtPhase2DigiToStubsConverter : public DigiToStubsConverterBase { //dtThDigis is provided as argument, because in the OMTF implementation the phi and eta digis are merged (even thought it is artificial) virtual void addDTphiDigi(MuonStubPtrs2D& muonStubsInLayers, const L1Phase2MuDTPhDigi& digi, - const L1MuDTChambThContainer* dtThDigis, + const L1Phase2MuDTThContainer* dtThDigis, unsigned int iProcessor, l1t::tftype procTyp) = 0; virtual void addDTetaStubs(MuonStubPtrs2D& muonStubsInLayers, - const L1MuDTChambThDigi& thetaDigi, + const L1Phase2MuDTThDigi& thetaDigi, unsigned int iProcessor, l1t::tftype procTyp) = 0; @@ -55,51 +60,51 @@ class DtPhase2DigiToStubsConverter : public DigiToStubsConverterBase { } protected: + const OMTFConfiguration* config = nullptr; bool mergePhiAndTheta = true; edm::EDGetTokenT inputTokenDtPh; - edm::EDGetTokenT inputTokenDtTh; + edm::EDGetTokenT inputTokenDtTh; edm::Handle dtPhDigis; - edm::Handle dtThDigis; + edm::Handle dtThDigis; + + int bunchCrossing = 0; }; class DtPhase2DigiToStubsConverterOmtf : public DtPhase2DigiToStubsConverter { public: DtPhase2DigiToStubsConverterOmtf(const OMTFConfiguration* config, - const OmtfAngleConverter* angleConverter, + const OmtfPhase2AngleConverter* angleConverter, edm::EDGetTokenT inputTokenDtPh, - edm::EDGetTokenT inputTokenDtTh) - : DtPhase2DigiToStubsConverter(inputTokenDtPh, inputTokenDtTh), - config(*config), - angleConverter(*angleConverter) {} + edm::EDGetTokenT inputTokenDtTh) + : DtPhase2DigiToStubsConverter(config, inputTokenDtPh, inputTokenDtTh), angleConverter(*angleConverter) {} ~DtPhase2DigiToStubsConverterOmtf() override = default; //dtThDigis is provided as argument, because in the OMTF implementation the phi and eta digis are merged (even thought it is artificial) void addDTphiDigi(MuonStubPtrs2D& muonStubsInLayers, const L1Phase2MuDTPhDigi& digi, - const L1MuDTChambThContainer* dtThDigis, + const L1Phase2MuDTThContainer* dtThDigis, unsigned int iProcessor, l1t::tftype procTyp) override; void addDTetaStubs(MuonStubPtrs2D& muonStubsInLayers, - const L1MuDTChambThDigi& thetaDigi, + const L1Phase2MuDTThDigi& thetaDigi, unsigned int iProcessor, l1t::tftype procTyp) override; bool acceptDigi(const DTChamberId& dTChamberId, unsigned int iProcessor, l1t::tftype procType) override; private: - const OMTFConfiguration& config; - const OmtfAngleConverter& angleConverter; + const OmtfPhase2AngleConverter& angleConverter; }; class InputMakerPhase2 : public OMTFinputMaker { public: InputMakerPhase2(const edm::ParameterSet& edmParameterSet, MuStubsInputTokens& muStubsInputTokens, - edm::EDGetTokenT inputTokenDTPhPhase2, + MuStubsPhase2InputTokens& muStubsPhase2InputTokens, const OMTFConfiguration* config, std::unique_ptr angleConverter); diff --git a/L1Trigger/L1TMuonOverlapPhase2/interface/LutNetworkFixedPointRegression2Outputs.h b/L1Trigger/L1TMuonOverlapPhase2/interface/LutNetworkFixedPointRegression2Outputs.h index 6880acd14ce70..7471a1df4505b 100644 --- a/L1Trigger/L1TMuonOverlapPhase2/interface/LutNetworkFixedPointRegression2Outputs.h +++ b/L1Trigger/L1TMuonOverlapPhase2/interface/LutNetworkFixedPointRegression2Outputs.h @@ -20,31 +20,33 @@ #include namespace lutNN { - //_I - number of integer bits in the ap_ufixed, _F - number of fractional bits in the ap_ufixed //the network has two outputs, and since each output can have different range, the LUTs in the last layer have different I and F - template + template < + int input_I, + int input_F, + std::size_t inputSize, + int layer1_lut_I, + int layer1_lut_F, + int layer1_neurons, + int layer1_output_I, //to the layer1 output the bias is added to make the layer2 input, therefore the layer1_output_I and layer2_lut_I are different + int layer1_output_F, + int layer2_input_I, + int layer2_lut_I, + int layer2_lut_F, + int layer2_neurons, + int layer3_input_I, + int layer3_input_F, + int layer3_0_inputCnt, + int layer3_0_lut_I, + int layer3_0_lut_F, + int output0_I, + int output0_F, + int layer3_1_inputCnt, + int layer3_1_lut_I, + int layer3_1_lut_F, + int output1_I, + int output1_F> class LutNetworkFixedPointRegression2Outputs : public LutNetworkFixedPointRegressionBase { public: LutNetworkFixedPointRegression2Outputs() { @@ -57,15 +59,22 @@ namespace lutNN { lutLayer3_1.setName("lutLayer3_1"); }; - ~LutNetworkFixedPointRegression2Outputs() override {} + ~LutNetworkFixedPointRegression2Outputs() override {}; - typedef LutNeuronLayerFixedPoint + typedef LutNeuronLayerFixedPoint LutLayer1; LutLayer1 lutLayer1; static constexpr unsigned int noHitCntShift = layer1_output_I; //FIXME should be layer1_output_I ??? - static constexpr int layer2_input_F = layer1_lut_F; + static constexpr int layer2_input_F = layer1_output_F; typedef LutNeuronLayerFixedPoint + layer3_input_I, + layer3_input_F> LutLayer2; LutLayer2 lutLayer2; - static constexpr int layer3_input_F = layer2_lut_F; - typedef LutNeuronLayerFixedPoint + output0_I, + output0_F> LutLayer3_0; LutLayer3_0 lutLayer3_0; //"lutLayer3_0" @@ -95,7 +104,8 @@ namespace lutNN { layer3_1_lut_I, layer3_1_lut_F, 1, - output1_I> + output1_I, + output1_F> LutLayer3_1; LutLayer3_1 lutLayer3_1; //"lutLayer3_1" @@ -130,6 +140,12 @@ namespace lutNN { noHitsCnt++; } + //the minimum required number of hits for a good candidate is 3, + //and the total number of possible hits is 18 (number of OMTF layers) + //so the maximum noHitsCnt is 15. It must be constrained here, otherwise address for the the next layer would be out of LUT range + if (noHitsCnt > 15) + noHitsCnt = 15; + unsigned int bias = (noHitsCnt << noHitCntShift); //layer1Bias switches the input of the layer2 (i.e. output of the layer1) do different regions in the LUTs @@ -152,11 +168,13 @@ namespace lutNN { //pt in the hardware scale, ptGeV = (ptHw -1) / 2 int getCalibratedHwPt() override { - auto lutAddr = ap_ufixed( - lutLayer3_0.getLutOutSum()[0]); - lutAddr = lutAddr << output0_F; + //auto lutAddr = ap_ufixed(lutLayer3_0.getLutOutSum()[0]); + //lutAddr = lutAddr< scale * lut[x] + offset for the last layer } void save(const std::string& filename) override { diff --git a/L1Trigger/L1TMuonOverlapPhase2/interface/LutNetworkFixedPointRegressionMultipleOutputs.h b/L1Trigger/L1TMuonOverlapPhase2/interface/LutNetworkFixedPointRegressionMultipleOutputs.h new file mode 100644 index 0000000000000..7206c0d18e551 --- /dev/null +++ b/L1Trigger/L1TMuonOverlapPhase2/interface/LutNetworkFixedPointRegressionMultipleOutputs.h @@ -0,0 +1,289 @@ +/* + * LutNetworkFixedPointRegressionMultipleOutputs.h + * + * Created on: April 13, 2021 + * Author: Karol Bunkowski, kbunkow@cern.ch + */ + +#ifndef L1Trigger_L1TMuonOverlapPhase2_LutNetworkFixedPointRegressionMultipleOutputs_h +#define L1Trigger_L1TMuonOverlapPhase2_LutNetworkFixedPointRegressionMultipleOutputs_h + +#include "L1Trigger/L1TMuonOverlapPhase2/interface/LutNeuronLayerFixedPoint.h" + +#include "ap_int.h" + +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include + +#include +#include + +namespace lutNN { + + //_I - number of integer bits in the ap_ufixed, _F - number of fractional bits in the ap_ufixed + //the network has two outputs, and since each output can have different range, the LUTs in the last layer have different I and F + template < + int input_I, + int input_F, + std::size_t inputSize, + int layer1_lut_I, + int layer1_lut_F, + int layer1_neurons, + int layer1_output_I, //to the layer1 output the bias is added to make the layer2 input, therefore the layer1_output_I and layer2_lut_I are different + int layer1_output_F, + int layer2_input_I, + int layer2_lut_I, + int layer2_lut_F, + int layer2_neurons, + int layer3_input_I, + int layer3_input_F, + int layer3_0_inputCnt, + int layer3_0_lut_I, + int layer3_0_lut_F, + int output0_I, + int output0_F, + int layer3_0_multiplicity, + int layer3_1_inputCnt, + int layer3_1_lut_I, + int layer3_1_lut_F, + int output1_I, + int output1_F, + int layer3_1_multiplicity> + class LutNetworkFixedPointRegressionMultipleOutputs : public LutNetworkFixedPointRegressionBase { + public: + LutNetworkFixedPointRegressionMultipleOutputs() { + static_assert(layer2_neurons == + (layer3_0_inputCnt * layer3_0_multiplicity + layer3_1_inputCnt * layer3_1_multiplicity)); + + //std::cout << "LutNetworkFixedPoint" << std::endl; + lutLayer1.setName("lutLayer1"); + lutLayer2.setName("lutLayer2"); + for (unsigned int iSubLayer = 0; iSubLayer < lutLayer3_0.size(); iSubLayer++) { + lutLayer3_0[iSubLayer].setName("lutLayer3_0_" + std::to_string(iSubLayer)); + } + for (unsigned int iSubLayer = 0; iSubLayer < lutLayer3_1.size(); iSubLayer++) { + lutLayer3_1[iSubLayer].setName("lutLayer3_1_" + std::to_string(iSubLayer)); + } + }; + + ~LutNetworkFixedPointRegressionMultipleOutputs() override {}; + + typedef LutNeuronLayerFixedPoint + LutLayer1; + LutLayer1 lutLayer1; + + static constexpr unsigned int noHitCntShift = layer1_output_I; //FIXME should be layer1_output_I ??? + + static constexpr int layer2_input_F = layer1_output_F; + + typedef LutNeuronLayerFixedPoint + LutLayer2; + LutLayer2 lutLayer2; + + typedef LutNeuronLayerFixedPoint + LutLayer3_0; + std::array lutLayer3_0; + + typedef LutNeuronLayerFixedPoint + LutLayer3_1; + std::array lutLayer3_1; + + void runWithInterpolation() { + lutLayer1.runWithInterpolation(inputArray); + auto& layer1Out = lutLayer1.getOutWithOffset(); + + std::array, layer1_neurons> + layer1OutWithBias; + for (unsigned int i = 0; i < layer1Out.size(); i++) { + layer1OutWithBias[i] = layer1Out[i] + layer1Bias; + } + + lutLayer2.runWithInterpolation(layer1OutWithBias); + auto& layer2Out = lutLayer2.getOutWithOffset(); + + for (unsigned int iSubLayer = 0; iSubLayer < lutLayer3_0.size(); iSubLayer++) { + typename LutLayer3_0::inputArrayType lutLayer3_0_input; + std::copy(layer2Out.begin() + lutLayer3_0_input.size() * iSubLayer, //from + layer2Out.begin() + lutLayer3_0_input.size() * (iSubLayer + 1), + lutLayer3_0_input.begin()); + + lutLayer3_0[iSubLayer].runWithInterpolation(lutLayer3_0_input); + } + + for (unsigned int iSubLayer = 0; iSubLayer < lutLayer3_1.size(); iSubLayer++) { + typename LutLayer3_1::inputArrayType lutLayer3_1_input; + std::copy( + layer2Out.begin() + lutLayer3_1_input.size() * iSubLayer + + layer3_0_inputCnt * layer3_0_multiplicity, //from + layer2Out.begin() + lutLayer3_1_input.size() * (iSubLayer + 1) + layer3_0_inputCnt * layer3_0_multiplicity, + lutLayer3_1_input.begin()); + + lutLayer3_1[iSubLayer].runWithInterpolation(lutLayer3_1_input); + } + } + + void run(std::vector& inputs, float noHitVal, std::vector& nnResult) override { + unsigned int noHitsCnt = 0; + for (unsigned int iInput = 0; iInput < inputs.size(); iInput++) { + inputArray[iInput] = inputs[iInput]; + if (inputs[iInput] == noHitVal) + noHitsCnt++; + } + + //the minimum required number of hits for a good candidate is 3, + //and the total number of possible hits is 18 (number of OMTF layers) + //so the maximum noHitsCnt is 15. It must be constrained here, otherwise address for the the next layer would be out of LUT range + if (noHitsCnt > 15) + noHitsCnt = 15; + + unsigned int bias = (noHitsCnt << noHitCntShift); + + //layer1Bias switches the input of the layer2 (i.e. output of the layer1) do different regions in the LUTs + //depending on the number of layers without hits + layer1Bias = bias; + + runWithInterpolation(); + + //output0_I goes to the declaration of the lutLayer3_0, but it does not matter, as it is used only for the outputArray + //auto layer3_0_out = ap_ufixed(lutLayer3_0.getLutOutSum()[0]); //TODO should be AP_RND_CONV rather, but it affect the rate + //auto layer3_1_out = ap_fixed (lutLayer3_1.getLutOutSum()[0]); //here layer3_0_out has size 1 + + for (unsigned int iSubLayer = 0; iSubLayer < lutLayer3_0.size(); iSubLayer++) { + nnResult[iSubLayer] = lutLayer3_0[iSubLayer].getLutOutSum()[0].to_float(); //here layer3_0_out has size 1 + //std::cout<<"nnResult["<(lutLayer3_0.getLutOutSum()[0]); + //lutAddr = lutAddr< scale * lut[x] + offset for the last layer + } + + void save(const std::string& filename) override { + // Create an empty property tree object. + boost::property_tree::ptree tree; + + PUT_VAR(tree, name, output0_I) + PUT_VAR(tree, name, output0_F) + PUT_VAR(tree, name, output1_I) + PUT_VAR(tree, name, output1_F) + + lutLayer1.save(tree, name); + lutLayer2.save(tree, name); + for (unsigned int iSubLayer = 0; iSubLayer < lutLayer3_0.size(); iSubLayer++) { + lutLayer3_0[iSubLayer].save(tree, name); + } + for (unsigned int iSubLayer = 0; iSubLayer < lutLayer3_1.size(); iSubLayer++) { + lutLayer3_1[iSubLayer].save(tree, name); + } + + int size = ptCalibrationArray.size(); + std::string key = "LutNetworkFixedPointRegressionMultipleOutputs.ptCalibrationArray"; + PUT_VAR(tree, key, size) + std::ostringstream ostr; + for (auto& a : ptCalibrationArray) { + ostr << a.to_uint() << ", "; + } + tree.put(key + ".values", ostr.str()); + + boost::property_tree::write_xml(filename, + tree, + std::locale(), + boost::property_tree::xml_parser::xml_writer_make_settings(' ', 2)); + } + + void load(const std::string& filename) override { + // Create an empty property tree object. + boost::property_tree::ptree tree; + + boost::property_tree::read_xml(filename, tree); + + CHECK_VAR(tree, name, output0_I) + CHECK_VAR(tree, name, output0_F) + CHECK_VAR(tree, name, output1_I) + CHECK_VAR(tree, name, output1_F) + + lutLayer1.load(tree, name); + lutLayer2.load(tree, name); + for (unsigned int iSubLayer = 0; iSubLayer < lutLayer3_0.size(); iSubLayer++) { + lutLayer3_0[iSubLayer].load(tree, name); + } + for (unsigned int iSubLayer = 0; iSubLayer < lutLayer3_1.size(); iSubLayer++) { + lutLayer3_1[iSubLayer].load(tree, name); + } + + std::string key = "LutNetworkFixedPointRegressionMultipleOutputs.ptCalibrationArray"; + int size = ptCalibrationArray.size(); + CHECK_VAR(tree, key, size) + + auto str = tree.get(key + ".values"); + + std::stringstream ss(str); + std::string item; + + for (auto& a : ptCalibrationArray) { + if (std::getline(ss, item, ',')) { + a = std::stoul(item, nullptr, 10); + } else { + throw std::runtime_error( + "LutNetworkFixedPointRegressionMultipleOutputs::read: number of items get from file is smaller than lut " + "size"); + } + } + } + + auto& getPtCalibrationArray() { return ptCalibrationArray; } + + private: + std::array, inputSize> inputArray; + ap_uint layer1Bias; + + //ptCalibrationArray size should be 1024, the LSB of the input 0.25 GeV, + //the output is int, with range 0...511, the LSB of output 0.5 GeV + std::array, 1 << (output0_I + output0_F)> ptCalibrationArray; + + std::string name = "LutNetworkFixedPointRegressionMultipleOutputs"; + }; + +} /* namespace lutNN */ + +#endif /* L1Trigger_L1TMuonOverlapPhase2_LutNetworkFixedPointRegressionMultipleOutputs_h */ diff --git a/L1Trigger/L1TMuonOverlapPhase2/interface/LutNeuronLayerFixedPoint.h b/L1Trigger/L1TMuonOverlapPhase2/interface/LutNeuronLayerFixedPoint.h index 62cfcb70c3ae2..39143db85dcdd 100644 --- a/L1Trigger/L1TMuonOverlapPhase2/interface/LutNeuronLayerFixedPoint.h +++ b/L1Trigger/L1TMuonOverlapPhase2/interface/LutNeuronLayerFixedPoint.h @@ -25,65 +25,51 @@ namespace lutNN { // constexpr for ceil(log2) from stackoverflow - constexpr size_t floorlog2(size_t i) { - if (!(i > 0)) - throw cms::Exception("Incorrect input") - << "Argument of floorlog2 must be grater than 0, while " << i << " used.\n"; - return i == 1 ? 0 : 1 + floorlog2(i >> 1); - } - constexpr size_t ceillog2(size_t i) { - if (!(i > 0)) - throw cms::Exception("Incorrect input") - << "Argument of ceillog2 must be grater than 0, while " << i << " used.\n"; - return i == 1 ? 0 : floorlog2(i - 1) + 1; - } - - template + constexpr size_t floorlog2(size_t i) { return i == 1 ? 0 : 1 + floorlog2(i >> 1); } + constexpr size_t ceillog2(size_t i) { return i == 1 ? 0 : floorlog2(i - 1) + 1; } + + template class LutNeuronLayerFixedPoint { public: static constexpr int input_W = input_I + input_F; static constexpr int lut_W = lut_I + lut_F; //the lut out values sum - //static const int lutOutSum_I = lut_I + ceil(log2(inputSize)); //MB: ceil(log2(inputSize)) is not constexpr which makes issue for code-checks + //static const int lutOutSum_I = lut_I + ceil(log2(inputSize)); //ceil(log2(inputSize)) is not constexpr which makes issue for code-checks + static_assert(inputSize > 0); static constexpr int lutOutSum_I = lut_I + ceillog2(inputSize); - static constexpr int lutOutSum_W = lutOutSum_I + lut_F; + static constexpr int lutOutSum_W = lutOutSum_I + output_F; - static constexpr int output_W = output_I + lut_F; + static constexpr int output_W = output_I + output_F; //static_assert( (1<, inputSize> inputArrayType; + //the lutSumArrayType lutOutSum_I is such that no overflow in summation is possible typedef std::array, neurons> lutSumArrayType; LutNeuronLayerFixedPoint() { //FIXME initialise name(name) //static_assert(lut_I <= (output_I - ceil(log2(inputSize)) ), "not correct lut_I, output_I and inputSize"); //TODO - LogTrace("l1tOmtfEventPrint") << "Constructing LutNeuronLayerFixedPoint " << name << "\n input_I " - << std::setw(2) << input_I << " input_F " << std::setw(2) << input_F - << " input_W " << std::setw(2) << input_W << " inputSize " << std::setw(2) - << inputSize << "\n lut_I " << std::setw(2) << lut_I << " lut_F " - << std::setw(2) << lut_F << " lut_W " << std::setw(2) << lut_W << " lutSize " - << std::setw(2) << lutSize << "\n lutOutSum_I " << std::setw(2) << lutOutSum_I - << " lutOutSum_W " << std::setw(2) << lutOutSum_W << "\n output_I " - << std::setw(2) << output_I << " output_W " << std::setw(2) << output_W - << "\n neurons " << std::setw(2) << neurons << "\n outOffset " << outOffset << " = " - << std::hex << outOffset << " width " << outOffset.width << std::dec; + LogTrace("l1tOmtfEventPrint") << name << "\n input_I " << std::setw(2) << input_I << " input_F " + << std::setw(2) << input_F << " input_W " << std::setw(2) << input_W + << " inputSize " << std::setw(2) << inputSize << "\n lut_I " << std::setw(2) + << lut_I << " lut_F " << std::setw(2) << lut_F << " lut_W " + << std::setw(2) << lut_W << " lutSize " << std::setw(2) << lutSize + << "\n lutOutSum_I " << std::setw(2) << lutOutSum_I << " lutOutSum_F " + << std::setw(2) << lut_F << " lutOutSum_W " << std::setw(2) << lutOutSum_W + << "\n output_I " << std::setw(2) << output_I << " output_F " << std::setw(2) + << output_F << " output_W " << std::setw(2) << output_W << "\n neurons " + << std::setw(2) << neurons << "\n outOffset " << outOffset << " = " << std::hex + << outOffset << " width " << outOffset.width << std::dec << std::endl; } virtual ~LutNeuronLayerFixedPoint() {} void setName(std::string name) { this->name = name; } - auto& getLutArray() { return lutArray; } - - void setLutArray( - const std::array, lutSize>, neurons>, inputSize>& lutArray) { - this->lutArray = lutArray; - } - void save(boost::property_tree::ptree& tree, std::string keyPath) { PUT_VAR(tree, keyPath + "." + name, input_I) PUT_VAR(tree, keyPath + "." + name, input_F) @@ -92,6 +78,7 @@ namespace lutNN { PUT_VAR(tree, keyPath + "." + name, lut_F) PUT_VAR(tree, keyPath + "." + name, neurons) PUT_VAR(tree, keyPath + "." + name, output_I) + PUT_VAR(tree, keyPath + "." + name, output_F) for (unsigned int iInput = 0; iInput < lutArray.size(); iInput++) { for (unsigned int iNeuron = 0; iNeuron < lutArray[iInput].size(); iNeuron++) { @@ -114,6 +101,7 @@ namespace lutNN { CHECK_VAR(tree, keyPath + "." + name, lut_F) CHECK_VAR(tree, keyPath + "." + name, neurons) CHECK_VAR(tree, keyPath + "." + name, output_I) + CHECK_VAR(tree, keyPath + "." + name, output_F) for (unsigned int iInput = 0; iInput < lutArray.size(); iInput++) { for (unsigned int iNeuron = 0; iNeuron < lutArray[iInput].size(); iNeuron++) { @@ -144,33 +132,51 @@ namespace lutNN { auto address = inputArray.at(iInput).to_uint(); //address in principle is unsigned auto& lut = lutArray.at(iInput).at(iNeuron); - auto addresPlus1 = address + 1; - if (addresPlus1 >= lut.size()) - addresPlus1 = address; + auto addresPlus1 = address; + //there is a protection is in getOutWithOffset() + //but it does not include the bias node, and the noHit value, so the address == lut.size()-1 is still possible + //so this protection is needed here + if (addresPlus1 < (lut.size() - 1)) { + addresPlus1 = address + 1; + } auto derivative = lut.at(addresPlus1) - lut.at(address); // must be signed //N.B. the address and fractionalPart is the same for all neurons, what matters for the firmware ap_ufixed fractionalPart = inputArray.at(iInput); + //the W of derivative is (lut_W + 1) + //the W of (fractionalPart * derivative) is (input_W - input_I) + (lut_W + 1), the F is input_W-input_I + lut_F + //so the F of result is the F of the multiplication, so input_W-input_I + lut_F + //the F of lutOutSum is lut_F,so it is implicitly truncated auto result = lut.at(address) + fractionalPart * derivative; lutOutSum += result; } - - lutOutSumArray.at(iNeuron) = lutOutSum; } return lutOutSumArray; } //Output without offset - auto& getLutOutSum() { return lutOutSumArray; } + lutSumArrayType& getLutOutSum() { return lutOutSumArray; } //converts the output values from signed to unsigned by adding the offset = 1 << (output_I-1) //these values can be then directly used as inputs of the next LUT layer auto& getOutWithOffset() { for (unsigned int iOut = 0; iOut < lutOutSumArray.size(); iOut++) { + //the integer part of the outputArray is usually smaller than inte case of the lutOutSumArray + //therefore the outputArray has AP_SAT to avoid overflow outputArray[iOut] = lutOutSumArray[iOut] + outOffset; + //in the next layer, in runWithInterpolation the addresPlus1 is calculated, so outputArray[iOut] must be smaller the max_ap_fixed() -1 + //std::cout<<__FUNCTION__<<":"<<__LINE__<<" "< (max_ap_ufixed() - 1)) { + edm::LogVerbatim("l1tOmtfEventPrint") + << __FUNCTION__ << ":" << __LINE__ << " " << name << " " + << "iOut " << iOut << " lutOutSumArray[i] " << lutOutSumArray[iOut] << " outputArray[i] " + << outputArray[iOut] << " max_ap_ufixed " << max_ap_ufixed() << " <<<<<<<<<<<<<<<" + << std::endl; + outputArray[iOut] = max_ap_ufixed() - 1; + } } return outputArray; @@ -184,8 +190,8 @@ namespace lutNN { ap_uint outOffset = 1 << (output_I - 1); - std::array, lutSize>, neurons>, inputSize> - lutArray; //[inputNum][outputNum = neuronNum][address] + //[inputNum][outputNum = neuronNum][address] + std::array, lutSize>, neurons>, inputSize> lutArray; std::string name; }; diff --git a/L1Trigger/L1TMuonOverlapPhase2/interface/MlModelBase.h b/L1Trigger/L1TMuonOverlapPhase2/interface/MlModelBase.h new file mode 100644 index 0000000000000..84ccf99ea2c63 --- /dev/null +++ b/L1Trigger/L1TMuonOverlapPhase2/interface/MlModelBase.h @@ -0,0 +1,29 @@ +/* + * PtAssignmentBase.h + * + * Created on: Mar 16, 2020 + * Author: kbunkow + */ + +#ifndef L1T_OmtfP2_MlModelBase_H_ +#define L1T_OmtfP2_MlModelBase_H_ + +#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/AlgoMuon.h" +#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/IOMTFEmulationObserver.h" + +/* + * base class for the objects providing an alternative pt assignment on top of the OMTF golden pattern (like neural network) + */ +class MlModelBase { +public: + MlModelBase(const OMTFConfiguration* omtfConfig) : omtfConfig(omtfConfig) {} + virtual ~MlModelBase(); + + virtual void run(AlgoMuons::value_type& algoMuon, + std::vector >& observers) = 0; + +protected: + const OMTFConfiguration* omtfConfig = nullptr; +}; + +#endif /* L1T_OmtfP2_MlModelBase_H_ */ diff --git a/L1Trigger/L1TMuonOverlapPhase2/interface/NNRegression.h b/L1Trigger/L1TMuonOverlapPhase2/interface/NNRegression.h new file mode 100644 index 0000000000000..450c3aeebae0d --- /dev/null +++ b/L1Trigger/L1TMuonOverlapPhase2/interface/NNRegression.h @@ -0,0 +1,25 @@ +/* + * PtAssignmentNN.h + * + * Created on: May 8, 2020 + * Author: kbunkow + */ + +#ifndef L1Trigger_L1TMuonOverlapPhase2_PtAssigmentNNRegression_h +#define L1Trigger_L1TMuonOverlapPhase2_PtAssigmentNNRegression_h + +#include "L1Trigger/L1TMuonOverlapPhase2/interface/MlModelBase.h" +#include "L1Trigger/L1TMuonOverlapPhase2/interface/LutNetworkFixedPointCommon.h" + +class NNRegression : public MlModelBase { +public: + NNRegression(const edm::ParameterSet& edmCfg, const OMTFConfiguration* omtfConfig, std::string networkFile); + ~NNRegression() override = default; + + void run(AlgoMuons::value_type& algoMuon, std::vector >& observers) override; + +private: + unique_ptr lutNetworkFP; +}; + +#endif /* L1Trigger_L1TMuonOverlapPhase2_PtAssigmentNNRegression_h */ diff --git a/L1Trigger/L1TMuonOverlapPhase2/interface/OmtfEmulation.h b/L1Trigger/L1TMuonOverlapPhase2/interface/OmtfEmulation.h index 22ebd502496a6..9686ce9564466 100644 --- a/L1Trigger/L1TMuonOverlapPhase2/interface/OmtfEmulation.h +++ b/L1Trigger/L1TMuonOverlapPhase2/interface/OmtfEmulation.h @@ -9,28 +9,42 @@ #define L1Trigger_L1TMuonOverlapPhase2_OmtfEmulation_h #include "DataFormats/L1DTTrackFinder/interface/L1Phase2MuDTPhContainer.h" +#include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" #include "FWCore/Utilities/interface/EDGetToken.h" #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFReconstruction.h" #include "L1Trigger/L1TMuonOverlapPhase2/interface/OmtfPhase2AngleConverter.h" +#include "L1Trigger/L1TMuonOverlapPhase2/interface/InputMakerPhase2.h" +#include "L1Trigger/L1TMuonOverlapPhase2/interface/OmtfProcessorPhase2.h" class OmtfEmulation : public OMTFReconstruction { public: OmtfEmulation(const edm::ParameterSet& edmParameterSet, MuStubsInputTokens& muStubsInputTokens, - edm::EDGetTokenT inputTokenDTPhPhase2); + MuStubsPhase2InputTokens& muStubsPhase2InputTokens); void beginJob(); ~OmtfEmulation() override = default; - void addObservers(const MuonGeometryTokens& muonGeometryTokens, - const edm::ESGetToken& magneticFieldEsToken, - const edm::ESGetToken& propagatorEsToken) override; + void beginRun(edm::Run const& run, + edm::EventSetup const& iSetup, + edm::ESGetToken& omtfParamsEsToken, + const MuonGeometryTokens& muonGeometryTokens, + const edm::ESGetToken& magneticFieldEsToken, + const edm::ESGetToken& propagatorEsToken) override; + + struct OmtfOutptuCollections { + std::unique_ptr constrSaMuons; //ip constrained candidates + std::unique_ptr unConstrSaMuons; //ip unconstrained candidates + std::unique_ptr regionalCandidates; //for backward compatibility of analyzers etc. + }; + + OmtfOutptuCollections run(const edm::Event& iEvent, const edm::EventSetup& evSetup); private: - edm::EDGetTokenT inputTokenDTPhPhase2; + MuStubsPhase2InputTokens& muStubsPhase2InputTokens; - unique_ptr ptAssignment; + OmtfProcessorPhase2 omtfProcPhase2; }; #endif /* L1Trigger_L1TMuonOverlapPhase2_OmtfEmulation_h */ diff --git a/L1Trigger/L1TMuonOverlapPhase2/interface/OmtfPhase2AngleConverter.h b/L1Trigger/L1TMuonOverlapPhase2/interface/OmtfPhase2AngleConverter.h index 77ba206e079b3..3908366a53d8b 100644 --- a/L1Trigger/L1TMuonOverlapPhase2/interface/OmtfPhase2AngleConverter.h +++ b/L1Trigger/L1TMuonOverlapPhase2/interface/OmtfPhase2AngleConverter.h @@ -2,14 +2,19 @@ #define OmtfPhase2AngleConverter_h #include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OmtfAngleConverter.h" +#include "DataFormats/L1DTTrackFinder/interface/L1Phase2MuDTThContainer.h" +#include "DataFormats/MuonDetId/interface/DTChamberId.h" class OmtfPhase2AngleConverter : public OmtfAngleConverter { public: - OmtfPhase2AngleConverter() {} + OmtfPhase2AngleConverter() : OmtfAngleConverter() {} ~OmtfPhase2AngleConverter() override = default; // Convert DT phi to OMTF coordinate system. int getProcessorPhi(int phiZero, l1t::tftype part, int dtScNum, int dtPhi) const override; + + //using different name of the method to avoid hiding OmtfAngleConverter methods getGlobalEta + int getGlobalEtaPhase2(DTChamberId dTChamberId, const L1Phase2MuDTThContainer *dtThDigis, int bxNum) const; }; #endif diff --git a/L1Trigger/L1TMuonOverlapPhase2/interface/OmtfProcessorPhase2.h b/L1Trigger/L1TMuonOverlapPhase2/interface/OmtfProcessorPhase2.h new file mode 100644 index 0000000000000..8358ea114bd01 --- /dev/null +++ b/L1Trigger/L1TMuonOverlapPhase2/interface/OmtfProcessorPhase2.h @@ -0,0 +1,51 @@ +/* + * OmtfProcessorPhase2.h + * + * Created on: Oct 29, 2025 + * Author: kbunkow + */ + +#ifndef L1Trigger_L1TMuonOverlapPhase2_OMTFPROCESSORPHASE2_H_ +#define L1Trigger_L1TMuonOverlapPhase2_OMTFPROCESSORPHASE2_H_ + +#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/OMTFProcessor.h" +#include "L1Trigger/L1TMuonOverlapPhase2/interface/MlModelBase.h" + +#include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" + +class OmtfProcessorPhase2 { +public: + //Composition is used over inheritance here, primarily because the OMTFProcessor is a template class and is constructed in OMTFReconstruction + OmtfProcessorPhase2(const OMTFConfiguration* omtfConfig, const unique_ptr& omtfProc); + + virtual ~OmtfProcessorPhase2(); + + void beginRun(const edm::ParameterSet& edmParameterSet, edm::EventSetup const& iSetup); + + FinalMuons run(unsigned int iProcessor, + l1t::tftype mtfType, + int bx, + OMTFinputMaker* inputMaker, + std::vector >& observers); + + void assignQualityPhase2(AlgoMuons::value_type& algoMuon); + + void convertToGmtScalesPhase2(unsigned int iProcessor, l1t::tftype mtfType, FinalMuonPtr& finalMuon); + + l1t::SAMuonCollection getSAMuons(unsigned int iProcessor, + l1t::tftype mtfType, + FinalMuons& finalMuons, + bool costrainedPt); + +private: + const OMTFConfiguration* omtfConfig; + + //reference to the unique_ptr is used here, because the omtfProc might be re-constructed in the OMTFReconstruction each run + const unique_ptr& omtfProc; + + unique_ptr mlModel; + + std::map firedLayersToQuality; +}; + +#endif /* L1Trigger_L1TMuonOverlapPhase2_OMTFPROCESSORPHASE2_H_ */ diff --git a/L1Trigger/L1TMuonOverlapPhase2/interface/PtAssignmentNNRegression.h b/L1Trigger/L1TMuonOverlapPhase2/interface/PtAssignmentNNRegression.h deleted file mode 100644 index 0db72c7b01b78..0000000000000 --- a/L1Trigger/L1TMuonOverlapPhase2/interface/PtAssignmentNNRegression.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * PtAssignmentNN.h - * - * Created on: May 8, 2020 - * Author: kbunkow - */ - -#ifndef L1Trigger_L1TMuonOverlapPhase2_PtAssigmentNNRegression_h -#define L1Trigger_L1TMuonOverlapPhase2_PtAssigmentNNRegression_h - -#include "L1Trigger/L1TMuonOverlapPhase1/interface/Omtf/PtAssignmentBase.h" -#include "L1Trigger/L1TMuonOverlapPhase2/interface/LutNetworkFixedPointRegression2Outputs.h" - -class PtAssignmentNNRegression : public PtAssignmentBase { -public: - PtAssignmentNNRegression(const edm::ParameterSet& edmCfg, - const OMTFConfiguration* omtfConfig, - std::string networkFile); - ~PtAssignmentNNRegression() override = default; - - std::vector getPts(AlgoMuons::value_type& algoMuon, - std::vector >& observers) override; - -private: - unique_ptr lutNetworkFP; -}; - -#endif /* L1Trigger_L1TMuonOverlapPhase2_PtAssigmentNNRegression_h */ diff --git a/L1Trigger/L1TMuonOverlapPhase2/plugins/L1TMuonOverlapPhase2TrackProducer.cc b/L1Trigger/L1TMuonOverlapPhase2/plugins/L1TMuonOverlapPhase2TrackProducer.cc index e332d7cf525b6..46468721d11a3 100644 --- a/L1Trigger/L1TMuonOverlapPhase2/plugins/L1TMuonOverlapPhase2TrackProducer.cc +++ b/L1Trigger/L1TMuonOverlapPhase2/plugins/L1TMuonOverlapPhase2TrackProducer.cc @@ -6,12 +6,14 @@ #include "DataFormats/RPCDigi/interface/RPCDigiCollection.h" #include "SimDataFormats/Track/interface/SimTrackContainer.h" #include "SimDataFormats/Vertex/interface/SimVertexContainer.h" +#include "SimDataFormats/TrackingAnalysis/interface/TrackingParticleFwd.h" #include "FWCore/Framework/interface/EDConsumerBase.h" #include "FWCore/Framework/interface/Event.h" #include "FWCore/Framework/interface/ProductRegistryHelper.h" #include "FWCore/ParameterSet/interface/ParameterSet.h" #include "FWCore/PluginManager/interface/PluginFactory.h" #include "FWCore/Utilities/interface/InputTag.h" +#include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" #include #include @@ -19,10 +21,13 @@ L1TMuonOverlapPhase2TrackProducer::L1TMuonOverlapPhase2TrackProducer(const edm::ParameterSet& edmParameterSet) : muStubsInputTokens( - {consumes(edmParameterSet.getParameter("srcDTPh")), - consumes(edmParameterSet.getParameter("srcDTTh")), + {mayConsume(edmParameterSet.getParameter("srcDTPh")), + mayConsume(edmParameterSet.getParameter("srcDTTh")), consumes(edmParameterSet.getParameter("srcCSC")), consumes(edmParameterSet.getParameter("srcRPC"))}), + muStubsPhase2InputTokens( + {consumes(edmParameterSet.getParameter("srcDTPhPhase2")), + consumes(edmParameterSet.getParameter("srcDTThPhase2"))}), omtfParamsEsToken(esConsumes()), muonGeometryTokens({esConsumes(), esConsumes(), @@ -31,16 +36,18 @@ L1TMuonOverlapPhase2TrackProducer::L1TMuonOverlapPhase2TrackProducer(const edm:: magneticFieldEsToken(esConsumes()), propagatorEsToken(esConsumes( edm::ESInputTag("", "SteppingHelixPropagatorAlong"))), - omtfEmulation(edmParameterSet, - muStubsInputTokens, - consumes(edmParameterSet.getParameter("srcDTPhPhase2"))) { - produces("OMTF"); + omtfEmulation(edmParameterSet, muStubsInputTokens, muStubsPhase2InputTokens) { + produces("OMTF"); //phase-1 collection + produces("OMTFconstr"); + produces("OMTFunconstr"); //it is needed for pattern generation and RootDataDumper if (edmParameterSet.exists("simTracksTag")) mayConsume(edmParameterSet.getParameter("simTracksTag")); if (edmParameterSet.exists("simVertexesTag")) mayConsume(edmParameterSet.getParameter("simVertexesTag")); + if (edmParameterSet.exists("trackingParticleTag")) + mayConsume(edmParameterSet.getParameter("trackingParticleTag")); } ///////////////////////////////////////////////////// @@ -59,9 +66,11 @@ void L1TMuonOverlapPhase2TrackProducer::beginRun(edm::Run const& run, edm::Event void L1TMuonOverlapPhase2TrackProducer::produce(edm::Event& iEvent, const edm::EventSetup& evSetup) { std::ostringstream str; - std::unique_ptr candidates = omtfEmulation.reconstruct(iEvent, evSetup); + auto outptuCollections = omtfEmulation.run(iEvent, evSetup); - iEvent.put(std::move(candidates), "OMTF"); + iEvent.put(std::move(outptuCollections.regionalCandidates), "OMTF"); + iEvent.put(std::move(outptuCollections.constrSaMuons), "OMTFconstr"); + iEvent.put(std::move(outptuCollections.unConstrSaMuons), "OMTFunconstr"); } ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// diff --git a/L1Trigger/L1TMuonOverlapPhase2/plugins/L1TMuonOverlapPhase2TrackProducer.h b/L1Trigger/L1TMuonOverlapPhase2/plugins/L1TMuonOverlapPhase2TrackProducer.h index b15974950dec0..367bcaac37696 100644 --- a/L1Trigger/L1TMuonOverlapPhase2/plugins/L1TMuonOverlapPhase2TrackProducer.h +++ b/L1Trigger/L1TMuonOverlapPhase2/plugins/L1TMuonOverlapPhase2TrackProducer.h @@ -25,10 +25,11 @@ class L1TMuonOverlapPhase2TrackProducer : public edm::one::EDProducer omtfParamsEsToken; - //needed for AngleConverterBase + //needed for OmtfAngleConverter MuonGeometryTokens muonGeometryTokens; ///needed by tools/CandidateSimMuonMatcher.h diff --git a/L1Trigger/L1TMuonOverlapPhase2/python/simOmtfPhase2Digis_DT_2_2_2_cff.py b/L1Trigger/L1TMuonOverlapPhase2/python/simOmtfPhase2Digis_DT_2_2_2_cff.py new file mode 100644 index 0000000000000..ca857f43606f7 --- /dev/null +++ b/L1Trigger/L1TMuonOverlapPhase2/python/simOmtfPhase2Digis_DT_2_2_2_cff.py @@ -0,0 +1,14 @@ +import FWCore.ParameterSet.Config as cms + +from L1Trigger.L1TMuonOverlapPhase2.simOmtfPhase2Digis_cfi import simOmtfPhase2Digis + +#these patterns were gnerated with dtRefHitMinQuality = 4 +#simOmtfPhase2Digis.patternsXMLFile = cms.FileInPath("L1Trigger/L1TMuon/data/omtf_config/Patterns_ExtraplMB1nadMB2DTQualAndRFixedP_DT_2_2_t30__classProb17_recalib2.xml") + +#these patterns were gnerated with dtRefHitMinQuality = 2, so some pdfs are wider, but the performance is very similar as in the Patterns_ExtraplMB1nadMB2DTQualAndRFixedP_DT_2_2_t30__classProb17_recalib2.xml +#simOmtfPhase2Digis.patternsXMLFile = cms.FileInPath("L1Trigger/L1TMuon/data/omtf_config/Patterns_ExtraplMB1nadMB2DTQualAndRFixedP_DT_2_2_2_t31__classProb17_recalib2.xml") + +# the patterns t30 and t31 had rpcDropAllClustersIfMoreThanMax = 0, but also cleanStubs = 1, so then its like rpcDropAllClustersIfMoreThanMax = 1, so are OK + +simOmtfPhase2Digis.dtRefHitMinQuality = cms.int32(2) +simOmtfPhase2Digis.ghostBusterType = cms.string("byRefLayerAndHitQual") \ No newline at end of file diff --git a/L1Trigger/L1TMuonOverlapPhase2/python/simOmtfPhase2Digis_cfi.py b/L1Trigger/L1TMuonOverlapPhase2/python/simOmtfPhase2Digis_cfi.py index c27335f7bf28b..0379d2aa34d50 100644 --- a/L1Trigger/L1TMuonOverlapPhase2/python/simOmtfPhase2Digis_cfi.py +++ b/L1Trigger/L1TMuonOverlapPhase2/python/simOmtfPhase2Digis_cfi.py @@ -5,15 +5,18 @@ srcDTPh = cms.InputTag('simDtTriggerPrimitiveDigis'), srcDTTh = cms.InputTag('simDtTriggerPrimitiveDigis'), srcCSC = cms.InputTag('simCscTriggerPrimitiveDigis','MPCSORTED'), + #srcCSC = cms.InputTag('simCscTriggerPrimitiveDigis'), srcRPC = cms.InputTag('simMuonRPCDigis'), srcDTPhPhase2 = cms.InputTag('dtTriggerPhase2PrimitiveDigis'), srcDTThPhase2 = cms.InputTag('dtTriggerPhase2PrimitiveDigis'), ## XML / PATTERNS file: - configXMLFile = cms.FileInPath("L1Trigger/L1TMuon/data/omtf_config/hwToLogicLayer_0x0209.xml"), - patternsXMLFile = cms.FileInPath("L1Trigger/L1TMuon/data/omtf_config/Patterns_ExtraplMB1nadMB2DTQualAndEtaFixedP_ValueP1Scale_t20_v1_SingleMu_iPt_and_OneOverPt_classProb17_recalib2_minDP0.xml"), - extrapolFactorsFilename = cms.FileInPath("L1Trigger/L1TMuon/data/omtf_config/ExtrapolationFactors_ExtraplMB1nadMB2DTQual_ValueP1Scale_t20.xml"), - + #configXMLFile = cms.FileInPath("L1Trigger/L1TMuon/data/omtf_config/hwToLogicLayer_0x0209.xml"), + configXMLFile = cms.FileInPath("L1Trigger/L1TMuon/data/omtf_config/hwToLogicLayer_0x0210.xml"), + extrapolFactorsFilename = cms.FileInPath("L1Trigger/L1TMuon/data/omtf_config/ExtrapolationFactors_ExtraplMB1nadMB2_R_EtaValueP1Scale_t35.xml"), + #patternsXMLFile = cms.FileInPath("L1Trigger/L1TMuon/data/omtf_config/Patterns_ExtraplMB1andMB2RFixedP_ValueP1Scale_DT_2_2_2_t35__classProb17_recalib2.xml"), #pt defined at approx 80% of the efficiency curve + patternsXMLFile = cms.FileInPath("L1Trigger/L1TMuon/data/omtf_config/Patterns_ExtraplMB1andMB2RFixedP_ValueP1Scale_DT_2_2_2_t35__classProb17.xml"), #pt defined at approx 50% of the efficiency curve + dumpResultToXML = cms.bool(False), dumpDetailedResultToXML = cms.bool(False), XMLDumpFileName = cms.string("TestEvents.xml"), @@ -37,17 +40,23 @@ noHitValueInPdf = cms.bool(True), minDtPhiQuality = cms.int32(2), - minDtPhiBQuality = cms.int32(4), + minDtPhiBQuality = cms.int32(2), dtRefHitMinQuality = cms.int32(4), dtPhiBUnitsRad = cms.int32(1024), #2048 is the orginal phase2 scale, 512 is the phase1 scale - stubEtaEncoding = cms.string("valueP1Scale"), #TODO change to valueP1Scale when InputMakerPhase2 is modifiwed + stubEtaEncoding = cms.string("valueP2Scale"), #TODO change to valueP1Scale when InputMakerPhase2 is modifiwed + rpcMaxClusterSize = cms.int32(3), + rpcMaxClusterCnt = cms.int32(2), + rpcDropAllClustersIfMoreThanMax = cms.bool(True), + usePhiBExtrapolationFromMB1 = cms.bool(True), usePhiBExtrapolationFromMB2 = cms.bool(True), - useStubQualInExtr = cms.bool(True), + #in the DTTriggerPhase2 in PR44924 the phi is defined always in the middle of the chamber, even for the uncorelated stubs + #so the qulaity doeas not maater in the extrapolation + useStubQualInExtr = cms.bool(False), useEndcapStubsRInExtr = cms.bool(True), useFloatingPointExtrapolation = cms.bool(False), diff --git a/L1Trigger/L1TMuonOverlapPhase2/src/InputMakerPhase2.cc b/L1Trigger/L1TMuonOverlapPhase2/src/InputMakerPhase2.cc index db9952a549664..8b45a581b1b38 100644 --- a/L1Trigger/L1TMuonOverlapPhase2/src/InputMakerPhase2.cc +++ b/L1Trigger/L1TMuonOverlapPhase2/src/InputMakerPhase2.cc @@ -16,6 +16,7 @@ void DtPhase2DigiToStubsConverter::loadDigis(const edm::Event& event) { event.getByToken(inputTokenDtPh, dtPhDigis); event.getByToken(inputTokenDtTh, dtThDigis); + bunchCrossing = event.bunchCrossing(); } void DtPhase2DigiToStubsConverter::makeStubs(MuonStubPtrs2D& muonStubsInLayers, @@ -24,50 +25,78 @@ void DtPhase2DigiToStubsConverter::makeStubs(MuonStubPtrs2D& muonStubsInLayers, int bxFrom, int bxTo, std::vector >& observers) { - if (!dtPhDigis) - return; - boost::property_tree::ptree procDataTree; + std::map chamberTrees; + for (const auto& digiIt : *dtPhDigis->getContainer()) { DTChamberId detid(digiIt.whNum(), digiIt.stNum(), digiIt.scNum() + 1); + LogTrace("l1tOmtfEventPrint") << " L1Phase2MuDTPhDigi:35: detid " << detid << " digi " + << " whNum " << digiIt.whNum() << " scNum " << digiIt.scNum() << " stNum " + << digiIt.stNum() << " slNum " << digiIt.slNum() << " quality " << digiIt.quality() + << " rpcFlag " << digiIt.rpcFlag() << " phi " << digiIt.phi() << " phiBend " + << digiIt.phiBend() << " digBx " << digiIt.bxNum() << " correctedBx " + << digiIt.bxNum() - bunchCrossing << std::endl; + ///Check it the data fits into given processor input range if (!acceptDigi(detid, iProcessor, procTyp)) continue; - // HACK for Phase-2 (DT TPs are centered in bX=20) - if (digiIt.bxNum() - 20 >= bxFrom && digiIt.bxNum() - 20 <= bxTo) { + // HACK for Phase-2 (DT TPs are centered in bX=20 in MC, and 13(?) in data) + if (digiIt.bxNum() - config->dtBxShift() >= bxFrom && digiIt.bxNum() - config->dtBxShift() <= bxTo) { addDTphiDigi(muonStubsInLayers, digiIt, dtThDigis.product(), iProcessor, procTyp); - auto& dtP2Digi = procDataTree.add_child("dtP2Digi", boost::property_tree::ptree()); - dtP2Digi.add(".whNum", digiIt.whNum()); - dtP2Digi.add(".scNum", digiIt.scNum()); - dtP2Digi.add(".stNum", digiIt.stNum()); - dtP2Digi.add(".slNum", digiIt.slNum()); - dtP2Digi.add(".quality", digiIt.quality()); - dtP2Digi.add(".rpcFlag", digiIt.rpcFlag()); - dtP2Digi.add(".phi", digiIt.phi()); - dtP2Digi.add(".phiBend", digiIt.phiBend()); + std::ostringstream chamberName; + //chamberName<.whNum", digiIt.whNum()); + dtP2PhiDigi.add(".scNum", digiIt.scNum()); + dtP2PhiDigi.add(".stNum", digiIt.stNum()); + dtP2PhiDigi.add(".slNum", digiIt.slNum()); + dtP2PhiDigi.add(".quality", digiIt.quality()); + dtP2PhiDigi.add(".rpcFlag", digiIt.rpcFlag()); + dtP2PhiDigi.add(".phi", digiIt.phi()); + dtP2PhiDigi.add(".phiBend", digiIt.phiBend()); } } - if (!mergePhiAndTheta) { - for (auto& thetaDigi : (*(dtThDigis->getContainer()))) { - if (thetaDigi.bxNum() >= bxFrom && thetaDigi.bxNum() <= bxTo) { + for (auto& thetaDigi : (*(dtThDigis->getContainer()))) { + if (thetaDigi.bxNum() - config->dtBxShift() >= bxFrom && thetaDigi.bxNum() - config->dtBxShift() <= bxTo) { + if (!mergePhiAndTheta) { addDTetaStubs(muonStubsInLayers, thetaDigi, iProcessor, procTyp); } + + std::ostringstream chamberName; + //chamberName<.whNum", thetaDigi.whNum()); + dtP2ThDigi.add(".scNum", thetaDigi.scNum()); + dtP2ThDigi.add(".stNum", thetaDigi.stNum()); + dtP2ThDigi.add(".quality", thetaDigi.quality()); + dtP2ThDigi.add(".rpcFlag", thetaDigi.rpcFlag()); + dtP2ThDigi.add(".k", thetaDigi.k()); + dtP2ThDigi.add(".z", thetaDigi.z()); } } + for (auto& chamberTree : chamberTrees) { + chamberTree.second.add(".name", chamberTree.first); + procDataTree.add_child("dtChamber", chamberTree.second); + } + for (auto& obs : observers) - obs->addProcesorData("linkData", procDataTree); + obs->addProcesorData("dtData", procDataTree); } //dtThDigis is provided as argument, because in the OMTF implementation the phi and eta digis are merged (even thought it is artificial) void DtPhase2DigiToStubsConverterOmtf::addDTphiDigi(MuonStubPtrs2D& muonStubsInLayers, const L1Phase2MuDTPhDigi& digi, - const L1MuDTChambThContainer* dtThDigis, + const L1Phase2MuDTThContainer* dtThDigis, unsigned int iProcessor, l1t::tftype procTyp) { DTChamberId detid(digi.whNum(), digi.stNum(), digi.scNum() + 1); @@ -75,66 +104,76 @@ void DtPhase2DigiToStubsConverterOmtf::addDTphiDigi(MuonStubPtrs2D& muonStubsInL MuonStub stub; //converting the quality to the same encoding as in phase-1, as it is important for extrapolation - if (digi.quality() >= 6) + if (digi.quality() >= 6) // correlated stub stub.qualityHw = digi.quality() - 2; - else if (digi.quality() >= 3) { + else if (digi.quality() >= 3) { // 4 hit uncorrelated stub if (digi.slNum() == 3) stub.qualityHw = 3; else if (digi.slNum() == 1) stub.qualityHw = 2; - } else { + } else { //quality 1 (3 hits) or 2 (3+2 hits) if (digi.slNum() == 3) stub.qualityHw = 1; else if (digi.slNum() == 1) stub.qualityHw = 0; } - if (stub.qualityHw < config.getMinDtPhiQuality()) + if (stub.qualityHw < config->getMinDtPhiQuality()) return; - unsigned int hwNumber = config.getLayerNumber(detid.rawId()); - if (config.getHwToLogicLayer().find(hwNumber) == config.getHwToLogicLayer().end()) + unsigned int hwNumber = config->getLayerNumber(detid.rawId()); + if (config->getHwToLogicLayer().find(hwNumber) == config->getHwToLogicLayer().end()) return; - auto iter = config.getHwToLogicLayer().find(hwNumber); + auto iter = config->getHwToLogicLayer().find(hwNumber); unsigned int iLayer = iter->second; - unsigned int iInput = OMTFinputMaker::getInputNumber(&config, detid.rawId(), iProcessor, procTyp); + unsigned int iInput = OMTFinputMaker::getInputNumber(config, detid.rawId(), iProcessor, procTyp); //MuonStub& stub = muonStubsInLayers[iLayer][iInput]; stub.type = MuonStub::DT_PHI_ETA; stub.phiHw = angleConverter.getProcessorPhi( - OMTFinputMaker::getProcessorPhiZero(&config, iProcessor), procTyp, digi.scNum(), digi.phi()); + OMTFinputMaker::getProcessorPhiZero(config, iProcessor), procTyp, digi.scNum(), digi.phi()); + + //no config->dtBxShift() here, and also no shift inside getGlobalEtaPhase2 + stub.etaHw = angleConverter.getGlobalEtaPhase2(detid, dtThDigis, digi.bxNum()); + + if (iLayer == 0) + stub.r = 431; //round(431.175); //MB1 + else if (iLayer == 2) { + stub.r = 512; //round(512.475); //MB2 + } else if (iLayer == 4) { + stub.r = 620; //round(619.675); + //MB3, it is different than in the phase-1, as in the phase-2 it is a middle of the DT chamber, not muon station + } - //TODO the dtThDigis are not good yet,so passing an empty container to the angleConverter - //then it should return middle of chambers - //remove when the dtThDigis are fixed on the DT side - L1MuDTChambThContainer dtThDigisEmpty; - stub.etaHw = angleConverter.getGlobalEta(detid, &dtThDigisEmpty, digi.bxNum() - 20); //in phase2, the phiB is 13 bits, and range is [-2, 2 rad] so 4 rad, 2^13 units/(4 rad) = 1^11/rad. //need to convert them to 512units==1rad (to use OLD PATTERNS...) - stub.phiBHw = digi.phiBend() * config.dtPhiBUnitsRad() / 2048; + stub.phiBHw = digi.phiBend() * config->dtPhiBUnitsRad() / 2048; //the cut if (stub.qualityHw >= config.getMinDtPhiBQuality()) is done in the ProcessorBase::restrictInput //as is is done like that in the firmware // need to shift 20-BX to roll-back the shift introduced by the DT TPs - stub.bx = digi.bxNum() - 20; + stub.bx = digi.bxNum() - config->dtBxShift(); //stub.timing = digi.getTiming(); //TODO what about sub-bx timing, is is available? stub.logicLayer = iLayer; stub.detId = detid; - OmtfName board(iProcessor, &config); + OmtfName board(iProcessor, config); LogTrace("l1tOmtfEventPrint") << board.name() << " L1Phase2MuDTPhDigi: detid " << detid << " digi " << " whNum " << digi.whNum() << " scNum " << digi.scNum() << " stNum " << digi.stNum() << " slNum " << digi.slNum() << " quality " << digi.quality() << " rpcFlag " - << digi.rpcFlag() << " phi " << digi.phi() << " phiBend " << digi.phiBend() - << std::endl; - OMTFinputMaker::addStub(&config, muonStubsInLayers, iLayer, iInput, stub); + << digi.rpcFlag() << " phi " << digi.phi() << " phiBend " << digi.phiBend() << " bx " + << digi.bxNum() << std::endl; + LogTrace("l1tOmtfEventPrint") << board.name() << " stub: detid " << detid << " phi " << stub.phiHw << " eta " + << stub.etaHw << " phiB " << stub.phiBHw << " bx " << stub.bx << " quality " + << stub.qualityHw << " logicLayer " << stub.logicLayer << std::endl; + OMTFinputMaker::addStub(config, muonStubsInLayers, iLayer, iInput, stub); } void DtPhase2DigiToStubsConverterOmtf::addDTetaStubs(MuonStubPtrs2D& muonStubsInLayers, - const L1MuDTChambThDigi& thetaDigi, + const L1Phase2MuDTThDigi& thetaDigi, unsigned int iProcessor, l1t::tftype procTyp) { //in the Phase1 omtf the theta stubs are merged with the phi in the addDTphiDigi @@ -144,12 +183,12 @@ void DtPhase2DigiToStubsConverterOmtf::addDTetaStubs(MuonStubPtrs2D& muonStubsIn bool DtPhase2DigiToStubsConverterOmtf::acceptDigi(const DTChamberId& dTChamberId, unsigned int iProcessor, l1t::tftype procType) { - return OMTFinputMaker::acceptDtDigi(&config, dTChamberId, iProcessor, procType); + return OMTFinputMaker::acceptDtDigi(config, dTChamberId, iProcessor, procType); } InputMakerPhase2::InputMakerPhase2(const edm::ParameterSet& edmParameterSet, MuStubsInputTokens& muStubsInputTokens, - edm::EDGetTokenT inputTokenDTPhPhase2, + MuStubsPhase2InputTokens& muStubsPhase2InputTokens, const OMTFConfiguration* config, std::unique_ptr angleConverter) : OMTFinputMaker(edmParameterSet, muStubsInputTokens, config, std::move(angleConverter)) { @@ -162,7 +201,11 @@ InputMakerPhase2::InputMakerPhase2(const edm::ParameterSet& edmParameterSet, "is not true"); //if the Phase2DTPrimitives are used, then the phase1 DT primitives should be dropped edm::LogImportant("OMTFReconstruction") << " using Phase2 DT trigger primitives" << std::endl; + digiToStubsConverters.emplace_back(std::make_unique( - config, this->angleConverter.get(), inputTokenDTPhPhase2, muStubsInputTokens.inputTokenDtTh)); + config, + dynamic_cast(this->angleConverter.get()), + muStubsPhase2InputTokens.inputTokenDtPh, + muStubsPhase2InputTokens.inputTokenDtTh)); } } diff --git a/L1Trigger/L1TMuonOverlapPhase2/src/MlModelBase.cc b/L1Trigger/L1TMuonOverlapPhase2/src/MlModelBase.cc new file mode 100644 index 0000000000000..04f29f7d3fbbc --- /dev/null +++ b/L1Trigger/L1TMuonOverlapPhase2/src/MlModelBase.cc @@ -0,0 +1,10 @@ +/* + * PtAssignmentBase.cc + * + * Created on: Mar 16, 2020 + * Author: kbunkow + */ + +#include "L1Trigger/L1TMuonOverlapPhase2/interface/MlModelBase.h" + +MlModelBase::~MlModelBase() {} diff --git a/L1Trigger/L1TMuonOverlapPhase2/src/NNRegression.cc b/L1Trigger/L1TMuonOverlapPhase2/src/NNRegression.cc new file mode 100644 index 0000000000000..d152e77cc80f6 --- /dev/null +++ b/L1Trigger/L1TMuonOverlapPhase2/src/NNRegression.cc @@ -0,0 +1,510 @@ +/* + * PtAssignmentNN.cc + * + * Created on: May 8, 2020 + * Author: kbunkow + */ + +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +#include "DataFormats/MuonDetId/interface/CSCDetId.h" + +#include "L1Trigger/L1TMuonOverlapPhase2/interface/LutNetworkFixedPointRegressionMultipleOutputs.h" +#include "DataFormats/L1TMuonPhase2/interface/Constants.h" +#include "DataFormats/L1TMuonPhase2/interface/SAMuon.h" + +#include +#include +#include +#include + +#include +#include + +namespace lutNN { + const int input_I = 10; + const int input_F = 7; + const std::size_t networkInputSize = 18; + + const int layer1_neurons = 16; + const int layer1_lut_I = 3; + const int layer1_lut_F = 9; + + const int layer1_output_I = 4; + const int layer1_output_F = layer1_lut_F + 2; + + //4 bits are for the count of the noHit layers which goes to the input of the layer2 + const int layer2_input_I = layer1_output_I + 4; + + const int layer2_neurons = 8 * 2 + 1 + 3; //8 neurons for pt0, pt1 (each), 1 for charge, 3s for p_displ + const int layer2_lut_I = 5; + const int layer2_lut_F = 7; + + const int layer3_input_I = 5; + const int layer3_input_F = layer2_lut_F + 2; + + const int layer3_0_inputCnt = 8; + const int layer3_0_lut_I = 8; + const int layer3_0_lut_F = 5 + 5; + const int output0_I = 8; + const int output0_F = 5 + 5; //layer3_0_lut_F + 2; + const int layer3_0_multiplicity = 2; + + const int layer3_1_inputCnt = 1; + const int layer3_1_lut_I = 8; //TODO it should be smaller than 4 bits + const int layer3_1_lut_F = 5 + 5; + + const int output1_I = 8; + const int output1_F = 5 + 5; + const int layer3_1_multiplicity = 4; + + typedef LutNetworkFixedPointRegressionMultipleOutputs + LutNetworkFP; +} // namespace lutNN + +NNRegression::NNRegression(const edm::ParameterSet& edmCfg, + const OMTFConfiguration* omtfConfig, + std::string networkFile) + : MlModelBase(omtfConfig), lutNetworkFP(make_unique()) { + std::ifstream ifs(networkFile); + + edm::LogImportant("OMTFReconstruction") + << " " << __FUNCTION__ << ":" << __LINE__ << " networkFile " << networkFile << std::endl; + + lutNetworkFP->load(networkFile); + + edm::LogImportant("OMTFReconstruction") << " " << __FUNCTION__ << ":" << __LINE__ << std::endl; +} + +struct OmtfHit { + union { + unsigned long rawData = 0; + + struct { + char layer; + char quality; + char z; + char valid; + short deltaR; + short phiDist; + }; + }; + + OmtfHit(unsigned long rawData) : rawData(rawData) {} +}; + +bool omtfHitWithQualAndRToEventInput(OmtfHit& hit, std::vector& inputs, unsigned int omtfRefLayer, bool print) { + int lustSize = 1024; //TODO change it if needed + int refLayers = 8; + float rangeSize = lustSize / (refLayers * 2); + //float offset = (omtfRefLayer<<7) + rangeMiddle; + + //two ranges for each omtfRefLayer, so that two qualites can be used for each omtfRefLayer + float offset = omtfRefLayer * rangeSize * 2 + rangeSize / 2; + int rangeFactor = 2; //rangeFactor scales the hit.phiDist such that the event->inputs is smaller then 63 + + //if(!hit.valid) + // return false; ///TODO <<<<<<<<<<<<<<<<<<<<<<<<<<<<< + if (hit.layer <= 5) { //DT hits + rangeFactor = 2; //rangeFactor scales the hit.phiDist such that the event->inputs is smaller then 63 + //two ranges for each omtfRefLayer, so that two qualites can be used for each omtfRefLayer + offset = omtfRefLayer * rangeSize * 2 + rangeSize / 2; + if ((hit.layer == 1 || hit.layer == 3 || hit.layer == 5)) { //phiB + //if(!hit.valid) + // return false; ///TODO <<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + if (hit.quality < 2) ///TODO <<<<<<<<<<<<<<<<<<<<<<<<<<<<< + return false; + + if (hit.layer == 1) { + rangeFactor = 8 * 2; + } else if (hit.layer == 3) { + rangeFactor = 8 * 2; + } + + else if (hit.layer == 5) { + rangeFactor = 8 * 2; + } + } else { //phi + rangeFactor *= 4; + } + + if (hit.quality >= 4) { + offset += rangeSize; + //rangeFactor *= 4; + } + + } else if ((hit.layer >= 6 && hit.layer <= 9) || (hit.layer >= 15)) { //CSC hits and RPCe hits + int rBins = 16; + rangeSize = lustSize / (refLayers * rBins); + rangeFactor = 4; + int rBin = std::abs(hit.deltaR) >> 4; + if (rBin >= rBins) { + //cout<<"rBin "<= 10 && hit.layer <= 14) { //RPCb hits + rangeFactor *= 4; + } + + rangeFactor *= 2; //TODO !!!!!!!!!!!!!!!!!!! + + if (abs(hit.phiDist) >= ((rangeSize / 2 - 1) * rangeFactor)) { + if (hit.valid) + cout //<<" muonPt "<= lustSize - 2) + inputs.at(hit.layer) = lustSize - 2; + + if (print || inputs.at(hit.layer) < 0) { + cout //<<"rawData "<inputs.at(hit.layer) < 0 !!!!!!!!!!!!!!!!!" << endl; + cout << endl; + } + + if (inputs[hit.layer] >= lustSize) { //TODO should be the size of the LUT of the first layer + cout << " event->inputs[hit.layer] >= " << lustSize << " !!!!!!!!!!!!!!!!!" << endl; + } + return true; +} + +bool omtfHitWithQualToEventInput(OmtfHit& hit, std::vector& inputs, unsigned int omtfRefLayer, bool print) { + float rangeMiddle = 64 / 2; + float offset = (omtfRefLayer << 7) + rangeMiddle; + + int rangeFactor = 2; //rangeFactor scales the hit.phiDist such that the event->inputs is smaller then 63 + + if ((hit.layer == 1 || hit.layer == 3 || hit.layer == 5)) { + //if (!hit.valid) + // return false; + + if (hit.quality < 2) ///TODO <<<<<<<<<<<<<<<<<<<<<<<<<<<<< + return false; + + if (hit.layer == 1) { + rangeFactor = 8; + } else if (hit.layer == 3) { + rangeFactor = 8; + } else if (hit.layer == 5) { + rangeFactor = 8; + } + + if (hit.quality >= 4) { + offset += (1 << 6); + //rangeFactor *= 4; + } + } else { + //if (!hit.valid) + // return false; + + if ((hit.layer == 0 || hit.layer == 2 || hit.layer == 3)) { + if (hit.quality >= 4) { + offset += (1 << 6); + //rangeFactor *= 4; + } + } + + /*else if(hit.layer == 8 || hit.layer == 17) { + rangeFactor = 4; + }*/ + if (hit.layer == 9) { + rangeFactor = 1; + } + /*else { + rangeFactor = 2; + }*/ + + /*if(hit.valid) { + offset += (1 << 6); + rangeFactor *= 4; + }*/ + } + + rangeFactor *= 4; //TODO !!!!!!!!!!!!!!!!!!! + + if (abs(hit.phiDist) >= ((rangeMiddle - 1) * rangeFactor)) { + cout //<<" muonPt "<= + 1022) //the last address i.e. 1023 is reserved for the no-hit value, so interpolation between the 1022 and 1023 has no sense + inputs.at(hit.layer) = 1022; + + if (print || inputs.at(hit.layer) < 0) { + cout //<<"rawData "<inputs.at(hit.layer) < 0 !!!!!!!!!!!!!!!!!" << endl; + cout << endl; + } + + if (inputs[hit.layer] >= 1024) { //TODO should be the size of the LUT of the first layer + cout << " event->inputs[hit.layer] >= 1024 !!!!!!!!!!!!!!!!!" << endl; + } + return true; +} + +bool omtfHitToEventInput(OmtfHit& hit, std::vector& inputs, unsigned int omtfRefLayer, bool print) { + float offset = (omtfRefLayer << 7) + 64; + + if (hit.valid) { + if ((hit.layer == 1 || hit.layer == 3 || hit.layer == 5) && hit.quality < 4) ///TODO <<<<<<<<<<<<<<<<<<<<<<<<<<<<< + return false; + + int rangeFactor = 2; //rangeFactor scales the hit.phiDist such that the event->inputs is smaller then 63 + if (hit.layer == 1) { + rangeFactor = 8; + } else if (hit.layer == 3) { + rangeFactor = 4; + } else if (hit.layer == 5) { + //rangeFactor = 4; + } else if (hit.layer == 9) { + rangeFactor = 1; + } + + rangeFactor *= 2; //TODO !!!!!!!!!!!!!!!!!!! + + if (std::abs(hit.phiDist) >= (63 * rangeFactor)) { + edm::LogImportant("OMTFReconstruction") //<<" muonPt "<= + 1022) //the last address i.e. 1023 is reserved for the no-hit value, so interpolation between the 1022 and 1023 has no sense + inputs.at(hit.layer) = 1022; + + if (print || inputs.at(hit.layer) < 0) { + edm::LogImportant("OMTFReconstruction") //<<"rawData "<inputs.at(hit.layer) < 0 !!!!!!!!!!!!!!!!!" << endl; + edm::LogImportant("OMTFReconstruction") << endl; + } + + if (inputs[hit.layer] >= 1024) { //TODO should be the size of the LUT of the first layer + edm::LogImportant("OMTFReconstruction") << " event->inputs[hit.layer] >= 1024 !!!!!!!!!!!!!!!!!" << endl; + } + return true; + } + + return false; +} + +void NNRegression::run(AlgoMuons::value_type& algoMuon, + std::vector>& observers) { + LogTrace("l1tOmtfEventPrint") << " " << __FUNCTION__ << ":" << __LINE__ << std::endl; + auto& gpResult = algoMuon->getGpResultConstr(); + //int pdfMiddle = 1<<(omtfConfig->nPdfAddrBits()-1); + + LogTrace("l1tOmtfEventPrint") << " " << __FUNCTION__ << ":" << __LINE__ << std::endl; + /* + edm::LogVerbatim("l1tOmtfEventPrint")<<"DataROOTDumper2:;observeEventEnd muonPt "< inputs(inputCnt, noHitVal); + int hitCnt = 0; + unsigned int refLayerLogicNum = omtfConfig->getRefToLogicNumber()[algoMuon->getRefLayer()]; + for (unsigned int iLogicLayer = 0; iLogicLayer < gpResult.getStubResults().size(); ++iLogicLayer) { + auto& stubResult = gpResult.getStubResults()[iLogicLayer]; + if (stubResult.getMuonStub()) { //&& stubResult.getValid() //TODO!!!!!!!!!!!!!!!!1 + OmtfHit hit(0); + hit.layer = iLogicLayer; + hit.quality = stubResult.getMuonStub()->qualityHw; + //hit.eta = stubResult.getMuonStub()->etaHw; //in which scale? + if (refLayerLogicNum == iLogicLayer) + hit.deltaR = stubResult.getMuonStub()->r - 413; //r of the ref hit - r of RB1in + else + hit.deltaR = stubResult.getMuonStub()->r - gpResult.getStubResults()[refLayerLogicNum].getMuonStub()->r; + + hit.valid = stubResult.getValid(); + + //TODO the hit.phiDist should be set in the same way as in DataROOTDumper2, for the root files used for the NN training + //so either hit.phiDist = hitPhi - phiRefHit; or hit.phiDist = stubResult.getDeltaPhi(); + /* + int hitPhi = stubResult.getMuonStub()->phiHw; + unsigned int refLayerLogicNum = omtfConfig->getRefToLogicNumber()[algoMuon->getRefLayer()]; + int phiRefHit = gpResult.getStubResults()[refLayerLogicNum].getMuonStub()->phiHw; + + if (omtfConfig->isBendingLayer(iLogicLayer)) { + hitPhi = stubResult.getMuonStub()->phiBHw; + phiRefHit = 0; //phi ref hit for the banding layer set to 0, since it should not be included in the phiDist + } + + hit.phiDist = hitPhi - phiRefHit;*/ + + hit.phiDist = stubResult.getDeltaPhi(); + + /* + LogTrace("l1tOmtfEventPrint") <<" muonPt "<getGoldenPatern()->getDistPhiBitShift(iLogicLayer, omtfCand->getRefLayer()) + <<" meanDistPhiValue "<getGoldenPatern()->meanDistPhiValue(iLogicLayer, omtfCand->getRefLayer())//<<(phiDist != hit.phiDist? "!!!!!!!<<<<<" : "") + < 504 || hit.phiDist < -512) { + edm::LogVerbatim("l1tOmtfEventPrint") + //<<" muonPt "<getRefLayer(), false); + } + } + + //noHitCnt input is calculated in the LutNetworkFixedPointRegression2Outputs::run + //so here hitCnt is used only for debug + LogTrace("l1tOmtfEventPrint") << " " << __FUNCTION__ << ":" << __LINE__ << " hitCnt " << hitCnt << std::endl; + + std::vector nnResult(outputCnt); + lutNetworkFP->run(inputs, noHitVal, nnResult); + + LogTrace("l1tOmtfEventPrint") << " " << __FUNCTION__ << ":" << __LINE__ << std::endl; + + int charge = nnResult[2] >= 0 ? 1 : -1; + + LogTrace("l1tOmtfEventPrint") << " " << __FUNCTION__ << ":" << __LINE__ << " nnResult.at(0) " << nnResult.at(0) + << " nnResult.at(1) " << nnResult.at(1) << std::endl; + + //algoMuon->setPtNN(omtfConfig->ptGevToHw(nnResult.at(0))); + //auto calibratedHwPt = lutNetworkFP->getCalibratedHwPt(); + //pt in the hardware scale, ptGeV = (ptHw -1) / 2 + + //algoMuon->setPtNNConstr(omtfConfig->ptGevToHw(calibratedHwPt)); + + //here the pts are GeV + double omtfPt = omtfConfig->hwPtToGev(algoMuon->getPtConstr()); + double nnPt = nnResult.at(0); + double combinedPt = nnPt; + if (nnPt < 2.5 || (omtfPt < 0.75 * nnResult[0])) + combinedPt = omtfPt; + + algoMuon->setPtNNConstr(combinedPt); + + algoMuon->setChargeNNConstr(charge); + + //TODOO uncomment when NN with upt is ready + //int ptHwUnconstr = round(nnResult.at(??) ); + //algoMuon->setPtNNUnconstr(ptHwUnconstr); + + algoMuon->setNnOutputs(nnResult); + + if (omtfConfig->getDumpResultToXML()) { + boost::property_tree::ptree procDataTree; + for (unsigned int i = 0; i < inputs.size(); i++) { + auto& inputTree = procDataTree.add("input", ""); + inputTree.add(".num", i); + inputTree.add(".val", inputs[i]); + } + + std::ostringstream ostr; + + for (unsigned int i = 0; i < nnResult.size(); i++) { + auto& inputTree = procDataTree.add("output", ""); + ostr.str(""); + ostr << std::fixed << std::setprecision(19) << nnResult.at(i); + + inputTree.add(".num", i); + inputTree.add(".val", ostr.str()); + } + //procDataTree.add("calibratedHwPt..val", calibratedHwPt); + + procDataTree.add("hwSign..val", algoMuon->getChargeNNConstr() < 0 ? 1 : 0); + + for (auto& obs : observers) + obs->addProcesorData("regressionNN", procDataTree); + } + + //event.print(); + /* + std::vector pts(classifierToRegressions.size(), 0); + + unsigned int i =0; + for(auto& classifierToRegression : classifierToRegressions) { + auto orgValue = classifierToRegression->getValue(&event); + auto absOrgValue = std::abs(orgValue); + pts.at(i) = classifierToRegression->getCalibratedValue(absOrgValue); + pts.at(i) = std::copysign(pts.at(i), orgValue); + + LogTrace("OMTFReconstruction") <<" "<<__FUNCTION__<<":"<<__LINE__<<" orgValue "< inputTokenDTPhPhase2) - : OMTFReconstruction(edmParameterSet, muStubsInputTokens), inputTokenDTPhPhase2(inputTokenDTPhPhase2) {} + MuStubsPhase2InputTokens& muStubsPhase2InputTokens) + : OMTFReconstruction(edmParameterSet, muStubsInputTokens), + muStubsPhase2InputTokens(muStubsPhase2InputTokens), + omtfProcPhase2(omtfConfig.get(), omtfProc) {} void OmtfEmulation::beginJob() { if (edmParameterSet.exists("usePhase2DTPrimitives") && edmParameterSet.getParameter("usePhase2DTPrimitives")) { inputMaker = std::make_unique(edmParameterSet, muStubsInputTokens, - inputTokenDTPhPhase2, + muStubsPhase2InputTokens, omtfConfig.get(), std::make_unique()); } else { @@ -33,26 +36,74 @@ void OmtfEmulation::beginJob() { } } -void OmtfEmulation::addObservers(const MuonGeometryTokens& muonGeometryTokens, - const edm::ESGetToken& magneticFieldEsToken, - const edm::ESGetToken& propagatorEsToken) { - if (observers.empty()) { //assuring it is done only at the first run - OMTFReconstruction::addObservers(muonGeometryTokens, magneticFieldEsToken, propagatorEsToken); - /* if(edmParameterSet.exists("patternsPtAssignment") && edmParameterSet.getParameter("patternsPtAssignment")) { - //std::string rootFileName = edmParameterSet.getParameter("dumpHitsFileName"); - .emplace_back(std::make_unique(edmParameterSet, omtfConfig.get(), omtfProcGoldenPat->getPatterns(), "")); - }*/ +void OmtfEmulation::beginRun(edm::Run const& run, + edm::EventSetup const& eventSetup, + edm::ESGetToken& omtfParamsEsToken, + const MuonGeometryTokens& muonGeometryTokens, + const edm::ESGetToken& magneticFieldEsToken, + const edm::ESGetToken& propagatorEsToken) { + OMTFReconstruction::beginRun( + run, eventSetup, omtfParamsEsToken, muonGeometryTokens, magneticFieldEsToken, propagatorEsToken); + + omtfProcPhase2.beginRun(edmParameterSet, eventSetup); +} + +OmtfEmulation::OmtfOutptuCollections OmtfEmulation::run(const edm::Event& iEvent, const edm::EventSetup& evSetup) { + LogTrace("l1tOmtfEventPrint") << "\n" << __FUNCTION__ << ":" << __LINE__ << " iEvent " << iEvent.id().event() << endl; + inputMaker->loadAndFilterDigis(iEvent); + + for (auto& obs : observers) { + obs->observeEventBegin(iEvent); } - if (edmParameterSet.exists("neuralNetworkFile") && !ptAssignment) { - edm::LogImportant("OMTFReconstruction") << "constructing PtAssignmentNNRegression" << std::endl; - std::string neuralNetworkFile = edmParameterSet.getParameter("neuralNetworkFile").fullPath(); - ptAssignment = std::make_unique(edmParameterSet, omtfConfig.get(), neuralNetworkFile); + OmtfOutptuCollections outptuCollections; + outptuCollections.constrSaMuons = std::make_unique(); + outptuCollections.unConstrSaMuons = std::make_unique(); + outptuCollections.regionalCandidates = std::make_unique(); + outptuCollections.regionalCandidates->setBXRange(bxMin, bxMax); + + FinalMuons allFinalMuons; + + ///The order is important: first put omtf_pos candidates, then omtf_neg. + for (int bx = bxMin; bx <= bxMax; bx++) { + for (unsigned int iSide = 0; iSide < 2; ++iSide) { + l1t::tftype mtfType = (iSide == 0) ? l1t::tftype::omtf_pos : l1t::tftype::omtf_neg; + for (unsigned int iProcessor = 0; iProcessor < omtfConfig->nProcessors(); ++iProcessor) { + FinalMuons finalMuons = omtfProcPhase2.run(iProcessor, mtfType, bx, inputMaker.get(), observers); + + l1t::SAMuonCollection constrSAMuons = omtfProcPhase2.getSAMuons(iProcessor, mtfType, finalMuons, true); + for (auto& saMuon : constrSAMuons) { + outptuCollections.constrSaMuons->push_back(saMuon); + } + + l1t::SAMuonCollection unconstrSAMuons = omtfProcPhase2.getSAMuons(iProcessor, mtfType, finalMuons, false); + for (auto& saMuon : unconstrSAMuons) { + outptuCollections.unConstrSaMuons->push_back(saMuon); + } + + //getRegionalMuonCands calls convertToGmtScalesPhase1, it sets value ptGmt, phiGmt, etaGmt in finalMuons + //so that regionalCandidates have values in phase-1 scales + //but it will affect the finalMuons stored in allFinalMuons as they are shared pointers, + //Therefore convertToGmtScalesPhase2 is called again. + std::vector candMuons = omtfProc->getRegionalMuonCands(iProcessor, mtfType, finalMuons); + for (auto& candMuon : candMuons) { + outptuCollections.regionalCandidates->push_back(bx, candMuon); + } + //TODO remove it when RegionalCandidates are not needed anymore + for (auto& finalMuon : finalMuons) { + omtfProcPhase2.convertToGmtScalesPhase2(iProcessor, mtfType, finalMuon); + } + + allFinalMuons.insert(allFinalMuons.end(), finalMuons.begin(), finalMuons.end()); + } + } + + //edm::LogInfo("OMTFReconstruction") <<"OMTF: Number of candidates in BX="<size(bx) << std::endl;; } - auto omtfProcGoldenPat = dynamic_cast*>(omtfProc.get()); - if (omtfProcGoldenPat) { - omtfProcGoldenPat->setPtAssignment(ptAssignment.get()); - //omtfProcGoldenPat can be constructed from scratch each run, so ptAssignment is set herer every run + for (auto& obs : observers) { + obs->observeEventEnd(iEvent, allFinalMuons); } + + return outptuCollections; } diff --git a/L1Trigger/L1TMuonOverlapPhase2/src/OmtfPhase2AngleConverter.cc b/L1Trigger/L1TMuonOverlapPhase2/src/OmtfPhase2AngleConverter.cc index 26bbbc46e4477..5f128f912f388 100644 --- a/L1Trigger/L1TMuonOverlapPhase2/src/OmtfPhase2AngleConverter.cc +++ b/L1Trigger/L1TMuonOverlapPhase2/src/OmtfPhase2AngleConverter.cc @@ -20,12 +20,55 @@ int OmtfPhase2AngleConverter::getProcessorPhi(int phiZero, l1t::tftype part, int return config->foldPhi(phiConverted); } -/* TODO implement the etat for the phase2 stubs -int getGlobalEta(const DTChamberId dTChamberId, const L1Phase2MuDTThContainer *dtThDigis, int bxNum) const { +int OmtfPhase2AngleConverter::getGlobalEtaPhase2(DTChamberId dTChamberId, + const L1Phase2MuDTThContainer* dtThDigis, + int bxNum) const { + int dtThBins = 65536; //65536. for [-6.3,6.3] + float kconv = 1 / (dtThBins / 2.); - //const DTChamberId dTChamberId(aDigi.whNum(),aDigi.stNum(),aDigi.scNum()+1); - DTTrigGeom trig_geom(_geodt->chamber(dTChamberId), false); + float eta = -999; + // get the theta digi + bool foundeta = false; + int thetaDigiCnt = 0; + for (const auto& thetaDigi : (*(dtThDigis->getContainer()))) { + if (thetaDigi.whNum() == dTChamberId.wheel() && thetaDigi.stNum() == dTChamberId.station() && + thetaDigi.scNum() == (dTChamberId.sector() - 1) && (thetaDigi.bxNum()) == bxNum) { + // get the theta digi + float k = thetaDigi.k() * kconv; //-pow(-1.,z<0)*log(tan(atan(1/k)/2.)); + eta = -1. * std::copysign(log(fabs(tan(atan(1 / k) / 2.))), thetaDigi.z()); + LogTrace("OMTFReconstruction") << "OmtfPhase2AngleConverter::getGlobalEta(" << dTChamberId << ") eta: " << eta + << " k: " << k << " thetaDigi.k(): " << thetaDigi.k(); + thetaDigiCnt++; + //checking if the obtained eta has reasonable range - temporary fix + if ((dTChamberId.station() == 1 && (std::abs(eta) < 0.85 || std::abs(eta) > 1.20)) || + (dTChamberId.station() == 2 && (std::abs(eta) < 0.75 || std::abs(eta) > 1.04)) || + (dTChamberId.station() == 3 && (std::abs(eta) < 0.63 || std::abs(eta) > 0.92))) { + foundeta = false; + /*edm::LogVerbatim("OMTFReconstruction") + << "OmtfPhase2AngleConverter::getGlobalEta(" << dTChamberId << ") wrong output eta: " << eta << " k: " << k + << " thetaDigi.k(): " << thetaDigi.k() << " quality " << thetaDigi.quality();*/ + } else + foundeta = true; + } + } + //if more than 1 thetaDigi per given chamber - we don't use them, as they are ambiguous and we have no way to match them to the phi digis + if (thetaDigiCnt > 1) + foundeta = false; + + if (foundeta) { + return std::abs(config->etaToHwEta(eta)); + } else { + //Returning eta of the chamber middle + if (dTChamberId.station() == 1) + eta = config->mb1W2Eta(); + else if (dTChamberId.station() == 2) + eta = config->mb2W2Eta(); + else if (dTChamberId.station() == 3) + eta = config->mb3W2Eta(); + + return eta; + } + return 0; //should not be reached } -*/ diff --git a/L1Trigger/L1TMuonOverlapPhase2/src/OmtfProcessorPhase2.cc b/L1Trigger/L1TMuonOverlapPhase2/src/OmtfProcessorPhase2.cc new file mode 100644 index 0000000000000..2fd601a51309e --- /dev/null +++ b/L1Trigger/L1TMuonOverlapPhase2/src/OmtfProcessorPhase2.cc @@ -0,0 +1,375 @@ +/* + * OmtfProcessorPhase2.cc + * + * Created on: Oct 29, 2025 + * Author: kbunkow + */ + +#include +#include "L1Trigger/L1TMuonOverlapPhase2/interface/OmtfProcessorPhase2.h" + +OmtfProcessorPhase2::OmtfProcessorPhase2(const OMTFConfiguration* omtfConfig, + const unique_ptr& omtfProc) + : omtfConfig(omtfConfig), omtfProc(omtfProc) { + //TODO read from configuration + //.....................rrrrrrrrccccdddddd + //.....................765432109876543210 + firedLayersToQuality[0b000000110000000011] = 1; + firedLayersToQuality[0b000000100000000011] = 1; + firedLayersToQuality[0b000000010000000011] = 1; + firedLayersToQuality[0b000000110000000001] = 1; + firedLayersToQuality[0b000001000000001100] = 1; + firedLayersToQuality[0b000011000000001100] = 1; + firedLayersToQuality[0b000010000000001100] = 1; + firedLayersToQuality[0b000011000000000100] = 1; + firedLayersToQuality[0b000000011000000001] = 1; + firedLayersToQuality[0b001000010000000001] = 1; + + firedLayersToQuality[0b000100000000110000] = 1; + firedLayersToQuality[0b001100000000010000] = 1; + + firedLayersToQuality[0b010000110000000001] = 8; + firedLayersToQuality[0b000000111110000001] = 8; + firedLayersToQuality[0b000000001000000011] = 8; + firedLayersToQuality[0b000000111000000001] = 8; + firedLayersToQuality[0b000000101000000001] = 8; + firedLayersToQuality[0b010000011000000001] = 8; + firedLayersToQuality[0b010000100000000001] = 8; + firedLayersToQuality[0b000000110100000001] = 8; + firedLayersToQuality[0b000000100100000001] = 8; + firedLayersToQuality[0b001000100000000001] = 8; + firedLayersToQuality[0b010000010000000001] = 8; + firedLayersToQuality[0b001000110000000001] = 8; + firedLayersToQuality[0b001000110000000000] = 8; + firedLayersToQuality[0b000000010100000001] = 8; + firedLayersToQuality[0b000010100000000001] = 8; + firedLayersToQuality[0b000000100010000001] = 8; + firedLayersToQuality[0b001010010000000101] = 8; + firedLayersToQuality[0b100000000000000011] = 8; + firedLayersToQuality[0b011011000000000000] = 8; + firedLayersToQuality[0b000010110000000001] = 8; + firedLayersToQuality[0b001001110000000001] = 8; + firedLayersToQuality[0b000010100000000101] = 8; + firedLayersToQuality[0b000011110000000001] = 8; + firedLayersToQuality[0b000011110000001101] = 8; + firedLayersToQuality[0b000011100000000101] = 8; + firedLayersToQuality[0b000011110000000101] = 8; + firedLayersToQuality[0b000100000001110000] = 8; + firedLayersToQuality[0b000001110000001101] = 8; + firedLayersToQuality[0b000000110110000001] = 8; + firedLayersToQuality[0b000001110000000001] = 8; + firedLayersToQuality[0b001000010001000001] = 8; + firedLayersToQuality[0b000001100000000101] = 8; + firedLayersToQuality[0b000001100000000001] = 8; + firedLayersToQuality[0b000001110000000101] = 8; + firedLayersToQuality[0b001001110001000001] = 8; + firedLayersToQuality[0b000010110000000101] = 8; + firedLayersToQuality[0b000000010001000001] = 8; + firedLayersToQuality[0b000000100110000001] = 8; + firedLayersToQuality[0b001001100000001100] = 8; + firedLayersToQuality[0b000001010000000001] = 8; + firedLayersToQuality[0b000010100000000011] = 8; + firedLayersToQuality[0b000000100001000001] = 8; + firedLayersToQuality[0b001000110001000001] = 8; + firedLayersToQuality[0b000000010010000001] = 8; + firedLayersToQuality[0b000001010000000101] = 8; + firedLayersToQuality[0b100000100110000001] = 8; + firedLayersToQuality[0b000010010000000101] = 8; + firedLayersToQuality[0b000000110010000001] = 8; + firedLayersToQuality[0b000000000000110100] = 8; + firedLayersToQuality[0b000000010000000101] = 8; + firedLayersToQuality[0b000000110001000001] = 8; + firedLayersToQuality[0b000000010000001100] = 8; + firedLayersToQuality[0b000010110000001101] = 8; + firedLayersToQuality[0b000011010000001101] = 8; + firedLayersToQuality[0b000000100000010001] = 8; + firedLayersToQuality[0b000000110000000101] = 8; + firedLayersToQuality[0b000001100000000111] = 8; + firedLayersToQuality[0b000000100000000101] = 8; + firedLayersToQuality[0b010000010010000001] = 8; + firedLayersToQuality[0b000001100000001101] = 8; + firedLayersToQuality[0b000011100000000111] = 8; + firedLayersToQuality[0b000000010110000001] = 8; + firedLayersToQuality[0b000011110000000111] = 8; + firedLayersToQuality[0b000000011100000000] = 8; + firedLayersToQuality[0b001000010000000011] = 8; + firedLayersToQuality[0b000001110000000011] = 8; + firedLayersToQuality[0b000100000000110000] = 8; + firedLayersToQuality[0b000111100000110100] = 8; + firedLayersToQuality[0b010000010010000000] = 8; + firedLayersToQuality[0b100000010100000000] = 8; + firedLayersToQuality[0b001000100000000011] = 8; + firedLayersToQuality[0b000011100000001101] = 8; + firedLayersToQuality[0b100000011100000000] = 8; + firedLayersToQuality[0b110000011110000001] = 8; + //firedLayersToQuality[0b000000000000110011] = 8; + //firedLayersToQuality[0b000000100110000011] = 8; + //firedLayersToQuality[0b110000000100000000] = 8; + //firedLayersToQuality[0b001011110001001101] = 8; + //firedLayersToQuality[0b010000100001000011] = 8; + //firedLayersToQuality[0b000001100000001100] = 8; + //firedLayersToQuality[0b000001110001000011] = 8; + //firedLayersToQuality[0b011000000010000000] = 8; + //firedLayersToQuality[0b001000110100000011] = 8; + //firedLayersToQuality[0b010001000011000000] = 8; + //firedLayersToQuality[0b100000000110000000] = 8; + //firedLayersToQuality[0b000000000000111100] = 8; +} + +OmtfProcessorPhase2::~OmtfProcessorPhase2() {} + +void OmtfProcessorPhase2::beginRun(const edm::ParameterSet& edmParameterSet, edm::EventSetup const& iSetup) { + if (edmParameterSet.exists("neuralNetworkFile") && !mlModel) { + edm::LogImportant("OMTFReconstruction") << "constructing PtAssignmentNNRegression" << std::endl; + std::string neuralNetworkFile = edmParameterSet.getParameter("neuralNetworkFile").fullPath(); + mlModel = std::make_unique(edmParameterSet, omtfConfig, neuralNetworkFile); + } +} + +void OmtfProcessorPhase2::assignQualityPhase2(AlgoMuons::value_type& algoMuon) { + if (!algoMuon->isValid()) + return; + + //better not to assume anything about quality for pt=0 candidates + /*if (algoMuon->getPtConstr() == 0) { + algoMuon->setQuality(0); //default value + return; + }*/ + + //TODO agree on meaning of quality = 0 + if (abs(algoMuon->getEtaHw()) >= omtfConfig->etaToHwEta(1.3)) { + algoMuon->setQuality(0); + return; + } + + LogTrace("OMTFReconstruction") << "OmtfEmulation::assignQualityPhase2 algoMuon->getFiredLayerBits() " + << std::bitset<18>(algoMuon->getFiredLayerBits()) << " algoMuon->getEtaHw() " + << algoMuon->getEtaHw() << " omtfConfig->etaToHwEta(1.25) " + << omtfConfig->etaToHwEta(1.25) << std::endl; + + if (abs(algoMuon->getEtaHw()) >= omtfConfig->etaToHwEta(1.25) && + (algoMuon->getFiredLayerBits() == std::bitset<18>("100000001110000000").to_ulong() || + algoMuon->getFiredLayerBits() == std::bitset<18>("000000001110000000").to_ulong() || + algoMuon->getFiredLayerBits() == std::bitset<18>("100000000110000000").to_ulong() || + algoMuon->getFiredLayerBits() == std::bitset<18>("100000001100000000").to_ulong() || + algoMuon->getFiredLayerBits() == std::bitset<18>("100000001010000000").to_ulong())) { + algoMuon->setQuality(1); + LogTrace("OMTFReconstruction") << "OmtfEmulation::assignQualityPhase2 assigned quality 1 for etaHw " + << algoMuon->getEtaHw() << std::endl; + return; + } + + auto it = firedLayersToQuality.find(algoMuon->getFiredLayerBits()); + if (it != firedLayersToQuality.end()) { + algoMuon->setQuality(it->second); + } else { + algoMuon->setQuality(12); //default value + } +}; + +void OmtfProcessorPhase2::convertToGmtScalesPhase2(unsigned int iProcessor, + l1t::tftype mtfType, + FinalMuonPtr& finalMuon) { + //ptAssignment (NN) is used only if there was valid candidate from pattern logic + //it overrides the pt from the pattern logic + if (mlModel) { + //PtNNConstr should be in GeV + finalMuon->setPtGev(finalMuon->getAlgoMuon()->getPtNNConstr()); + finalMuon->setSign(finalMuon->getAlgoMuon()->getChargeNNConstr() < 0 ? 1 : 0); + + //TODO use getPtNNUnconstr when the network with upt is trained to set setPtUnconstrGev() + LogTrace("OMTFReconstruction") << "OmtfEmulation::convertToGmtScalesPhase2 using Pt from NN " + << " iProcessor " << iProcessor << " ptNN " + << finalMuon->getAlgoMuon()->getPtNNConstr() << " ptPatterns " + << finalMuon->getAlgoMuon()->getPtConstr() << " ChargeNN " + << finalMuon->getAlgoMuon()->getChargeNNConstr() << " Charge " + << finalMuon->getAlgoMuon()->getChargeConstr() << std::endl; + } + + //in getFinalMuons the PtGeV is set to 0 in this case, as it is like that for the phase-1. + //but for the phase-2 pt = 0 means empty candidate, so we set 1 GeV in this case + if (finalMuon->getAlgoMuon()->getPdfSumConstr() == 0 && finalMuon->getAlgoMuon()->getPtUnconstr() > 0) + finalMuon->setPtGev(1.0); //set to 1 GeV to be able to distinguish from pt=0, which means no candidate + + int maxPtHw = (1 << Phase2L1GMT::BITSPT) - 1; + + int ptHwConstr = finalMuon->getPtGev() * (1. / Phase2L1GMT::LSBpt); + + if (ptHwConstr >= maxPtHw) + ptHwConstr = maxPtHw; + + finalMuon->setPtGmt(ptHwConstr); + + int ptHwUnConstr = finalMuon->getPtUnconstrGev() * (1. / Phase2L1GMT::LSBpt); + + if (ptHwUnConstr >= maxPtHw) + ptHwUnConstr = maxPtHw; + + finalMuon->setPtUnconstrGmt(ptHwUnConstr); + + LogTrace("OMTFReconstruction") << "convertToGmtScalesPhase2 finalMuon->getPtGev() iProcessor " << iProcessor + << " PtGev " << finalMuon->getPtGev() << " PtUnconstrGev " + << finalMuon->getPtUnconstrGev() << std::endl; + + if (mtfType == l1t::omtf_pos) { + finalMuon->setEtaGmt(finalMuon->getAlgoMuon()->getEtaHw()); + } else { + finalMuon->setEtaGmt((-1) * finalMuon->getAlgoMuon()->getEtaHw()); + } + + int globPhi = omtfConfig->procPhiOmtfToGlobalPhiOmtf(iProcessor, finalMuon->getAlgoMuon()->getPhi()); + int gmtPhiBins = 1 << Phase2L1GMT::BITSPHI; + int omtfToGmtFactorPhi = std::lround(gmtPhiBins * (1 << 12) / double(omtfConfig->nPhiBins())); + int gmtPhi = (globPhi * omtfToGmtFactorPhi) >> 12; + finalMuon->setPhiGmt(gmtPhi); + + static const int omtfToGmtFactorEta = std::lround(omtfConfig->etaUnit() / Phase2L1GMT::LSBeta); //should be 2 + LogTrace("OMTFReconstruction") << "OmtfEmulation::convertToGmtScalesPhase2 omtfToGmtFactorEta " << omtfToGmtFactorEta + << std::endl; + int gmtEta = (finalMuon->getAlgoMuon()->getEtaHw() * omtfToGmtFactorEta); + if (mtfType == l1t::omtf_neg) + gmtEta = -gmtEta; + finalMuon->setEtaGmt(gmtEta); + + //finalMuon.setHwSignValid(1); +} + +l1t::SAMuonCollection OmtfProcessorPhase2::getSAMuons(unsigned int iProcessor, + l1t::tftype mtfType, + FinalMuons& finalMuons, + bool costrainedPt) { + l1t::SAMuonCollection saMuons; + for (auto& finalMuon : finalMuons) { + int charge = finalMuon->getSign(); + + unsigned int pt = costrainedPt ? finalMuon->getPtGmt() : finalMuon->getPtUnconstrGmt(); + int d0 = costrainedPt ? 0 : 50 / Phase2L1GMT::LSBSAd0; //finalMuon->getHwD0(); + if (costrainedPt == false) { + //this assures the collection of constrained and unconstrained muons have the same size + //muons that are not displaced also should be in the unconstrained collection + if (finalMuon->getPtUnconstrGmt() == 0) { + pt = finalMuon->getPtGmt(); + d0 = 0; + } + } + + LogTrace("OMTFReconstruction") << "OmtfEmulation::getSAMuons finalMuon->getPtGmt(): " << finalMuon->getPtGmt() + << " finalMuon->getPtUnconstrGmt() " << finalMuon->getPtUnconstrGmt() << std::endl; + + int phi = finalMuon->getPhiGmt(); + int eta = finalMuon->getEtaGmt(); + + int z0 = 0; + + unsigned int qual = finalMuon->getQuality(); + + //TODO FIX + //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, 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); 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 + //TODO for the vertex constrained muon, the z0 and d0 by definition should be 0 - then why give it? + math::PtEtaPhiMLorentzVector p4Constr( + pt * Phase2L1GMT::LSBpt, eta * Phase2L1GMT::LSBeta, phi * Phase2L1GMT::LSBphi, 0.0); + l1t::SAMuon saMuon(p4Constr, charge, pt, eta, phi, z0, d0, qual); + saMuon.setTF(mtfType); + //samuon.setWord(word); + + if (saMuon.hwPt() > 0) { + saMuons.push_back(saMuon); + } + } + + return saMuons; +} + +FinalMuons OmtfProcessorPhase2::run(unsigned int iProcessor, + l1t::tftype mtfType, + int bx, + OMTFinputMaker* inputMaker, + std::vector >& observers) { + //uncomment if you want to check execution time of each method + //boost::timer::auto_cpu_timer t("%ws wall, %us user in getProcessorCandidates\n"); + + for (auto& obs : observers) + obs->observeProcesorBegin(iProcessor, mtfType); + + //input is shared_ptr because the observers may need them after the run() method execution is finished + std::shared_ptr input = std::make_shared(omtfConfig); + inputMaker->buildInputForProcessor(input->getMuonStubs(), iProcessor, mtfType, bx, bx, observers); + + //TODO make a method cleanStubs in OMTFinput + if (omtfConfig->cleanStubs()) { + //this has sense for the pattern generation from the tracks with the secondaries + //if more than one stub is in a given layer, all stubs are removed from this layer + for (unsigned int iLayer = 0; iLayer < input->getMuonStubs().size(); ++iLayer) { + auto& layerStubs = input->getMuonStubs()[iLayer]; + int count = std::count_if(layerStubs.begin(), layerStubs.end(), [](auto& ptr) { return ptr != nullptr; }); + if (count > 1) { + for (auto& ptr : layerStubs) + ptr.reset(); + + LogTrace("OMTFReconstruction") << __FUNCTION__ << ":" << __LINE__ << "cleaning stubs in the layer " << iLayer + << " stubs count :" << count << std::endl; + } + } + } + + //LogTrace("l1tOmtfEventPrint")<<"buildInputForProce "; t.report(); + omtfProc->processInput(iProcessor, mtfType, *(input.get()), observers); + + //LogTrace("l1tOmtfEventPrint")<<"processInput "; t.report(); + AlgoMuons algoCandidates = omtfProc->sortResults(iProcessor, mtfType); + + //assignQuality must be called after ghostBust, because eta is set there + /*for (auto& algoMuon : algoCandidates) { + assignQuality(algoMuon); + }*/ + + if (mlModel) { + for (auto& algoMuon : algoCandidates) { + if (algoMuon->isValid()) { + mlModel->run(algoMuon, observers); + } + } + } + + //LogTrace("l1tOmtfEventPrint")<<"sortResults "; t.report(); + // perform GB + //watch out: etaBits2HwEta is used in the ghostBust to convert the AlgoMuons eta, it affect algoCandidates as they are pointers + AlgoMuons gbCandidates = omtfProc->ghostBust(algoCandidates); + + for (auto& gbCandidate : gbCandidates) { + assignQualityPhase2(gbCandidate); + } + + //LogTrace("l1tOmtfEventPrint")<<"ghostBust"; t.report(); + + FinalMuons finalMuons = omtfProc->getFinalMuons(iProcessor, mtfType, gbCandidates); + + for (auto& finalMuon : finalMuons) { + convertToGmtScalesPhase2(iProcessor, mtfType, finalMuon); + } + + for (auto& finalMuon : finalMuons) { + finalMuon->setBx(bx); + } + + for (auto& obs : observers) { + obs->observeProcesorEmulation(iProcessor, mtfType, input, algoCandidates, gbCandidates, finalMuons); + } + + return finalMuons; +} diff --git a/L1Trigger/L1TMuonOverlapPhase2/src/PtAssignmentNNRegression.cc b/L1Trigger/L1TMuonOverlapPhase2/src/PtAssignmentNNRegression.cc deleted file mode 100644 index ce3cdb6972343..0000000000000 --- a/L1Trigger/L1TMuonOverlapPhase2/src/PtAssignmentNNRegression.cc +++ /dev/null @@ -1,304 +0,0 @@ -/* - * PtAssignmentNN.cc - * - * Created on: May 8, 2020 - * Author: kbunkow - */ - -#include "FWCore/MessageLogger/interface/MessageLogger.h" -#include "FWCore/Framework/interface/EventSetup.h" -#include "FWCore/ParameterSet/interface/ParameterSet.h" - -#include "DataFormats/MuonDetId/interface/CSCDetId.h" - -#include "L1Trigger/L1TMuonOverlapPhase2/interface/PtAssignmentNNRegression.h" - -#include -#include -#include - -#include -#include - -namespace lutNN { - static constexpr int input_I = 10; - static constexpr int input_F = 4; - static constexpr std::size_t networkInputSize = 18; - - static constexpr int layer1_neurons = 16; - static constexpr int layer1_lut_I = 3; - static constexpr int layer1_lut_F = 13; - - static constexpr int layer1_output_I = 4; - //4 bits are for the count of the noHit layers which goes to the input of the layer2 - static constexpr int layer2_input_I = 8; - - static constexpr int layer2_neurons = 9; - static constexpr int layer2_lut_I = 5; - static constexpr int layer2_lut_F = 11; - - static constexpr int layer3_input_I = 5; - - static constexpr int layer3_0_inputCnt = 8; - static constexpr int layer3_0_lut_I = 5; - static constexpr int layer3_0_lut_F = 11; - static constexpr int output0_I = 8; - static constexpr int output0_F = 2; - - static constexpr int layer3_1_inputCnt = 1; - static constexpr int layer3_1_lut_I = 4; - static constexpr int layer3_1_lut_F = 11; - static constexpr int output1_I = 8; - static constexpr int output1_F = 0; //Does not matter in principle - it is not used - - typedef LutNetworkFixedPointRegression2Outputs - LutNetworkFP; -} // namespace lutNN - -PtAssignmentNNRegression::PtAssignmentNNRegression(const edm::ParameterSet& edmCfg, - const OMTFConfiguration* omtfConfig, - std::string networkFile) - : PtAssignmentBase(omtfConfig), lutNetworkFP(make_unique()) { - std::ifstream ifs(networkFile); - - edm::LogImportant("OMTFReconstruction") - << " " << __FUNCTION__ << ":" << __LINE__ << " networkFile " << networkFile << std::endl; - - lutNetworkFP->load(networkFile); - - edm::LogImportant("OMTFReconstruction") << " " << __FUNCTION__ << ":" << __LINE__ << std::endl; -} - -struct OmtfHit { - union { - unsigned long rawData = 0; - - struct { - char layer; - char quality; - char z; - char valid; - short eta; - short phiDist; - }; - }; - - OmtfHit(unsigned long rawData) : rawData(rawData) {} -}; - -bool omtfHitToEventInput(OmtfHit& hit, std::vector& inputs, unsigned int omtfRefLayer, bool print) { - float offset = (omtfRefLayer << 7) + 64; - - if (hit.valid) { - if ((hit.layer == 1 || hit.layer == 3 || hit.layer == 5) && hit.quality < 4) ///TODO <<<<<<<<<<<<<<<<<<<<<<<<<<<<< - return false; - - int rangeFactor = 2; //rangeFactor scales the hit.phiDist such that the event->inputs is smaller then 63 - if (hit.layer == 1) { - rangeFactor = 8; - } - /*else if(hit.layer == 8 || hit.layer == 17) { - rangeFactor = 4; - }*/ - else if (hit.layer == 3) { - rangeFactor = 4; - } else if (hit.layer == 9) { - rangeFactor = 1; - } - /*else { - rangeFactor = 2; - } - */ - - rangeFactor *= 2; //TODO !!!!!!!!!!!!!!!!!!! - - if (std::abs(hit.phiDist) >= (63 * rangeFactor)) { - edm::LogImportant("OMTFReconstruction") //<<" muonPt "<= - 1022) //the last address i.e. 1023 is reserved for the no-hit value, so interpolation between the 1022 and 1023 has no sense - inputs.at(hit.layer) = 1022; - - if (print || inputs.at(hit.layer) < 0) { - edm::LogImportant("OMTFReconstruction") //<<"rawData "<inputs.at(hit.layer) < 0 !!!!!!!!!!!!!!!!!" << endl; - edm::LogImportant("OMTFReconstruction") << endl; - } - - if (inputs[hit.layer] >= 1024) { //TODO should be the size of the LUT of the first layer - edm::LogImportant("OMTFReconstruction") << " event->inputs[hit.layer] >= 1024 !!!!!!!!!!!!!!!!!" << endl; - } - return true; - } - - return false; -} - -std::vector PtAssignmentNNRegression::getPts(AlgoMuons::value_type& algoMuon, - std::vector>& observers) { - LogTrace("l1tOmtfEventPrint") << " " << __FUNCTION__ << ":" << __LINE__ << std::endl; - auto& gpResult = algoMuon->getGpResultConstr(); - //int pdfMiddle = 1<<(omtfConfig->nPdfAddrBits()-1); - - LogTrace("l1tOmtfEventPrint") << " " << __FUNCTION__ << ":" << __LINE__ << std::endl; - /* - edm::LogVerbatim("l1tOmtfEventPrint")<<"DataROOTDumper2:;observeEventEnd muonPt "< inputs(inputCnt, noHitVal); - - for (unsigned int iLogicLayer = 0; iLogicLayer < gpResult.getStubResults().size(); ++iLogicLayer) { - auto& stubResult = gpResult.getStubResults()[iLogicLayer]; - if (stubResult.getMuonStub()) { //&& stubResult.getValid() //TODO!!!!!!!!!!!!!!!!1 - int hitPhi = stubResult.getMuonStub()->phiHw; - unsigned int refLayerLogicNum = omtfConfig->getRefToLogicNumber()[algoMuon->getRefLayer()]; - int phiRefHit = gpResult.getStubResults()[refLayerLogicNum].getMuonStub()->phiHw; - - if (omtfConfig->isBendingLayer(iLogicLayer)) { - hitPhi = stubResult.getMuonStub()->phiBHw; - phiRefHit = 0; //phi ref hit for the banding layer set to 0, since it should not be included in the phiDist - } - - OmtfHit hit(0); - - hit.layer = iLogicLayer; - hit.quality = stubResult.getMuonStub()->qualityHw; - hit.eta = stubResult.getMuonStub()->etaHw; //in which scale? - hit.valid = stubResult.getValid(); - - //phiDist = hitPhi - phiRefHit; - hit.phiDist = hitPhi - phiRefHit; - - /* - LogTrace("l1tOmtfEventPrint") <<" muonPt "<getGoldenPatern()->getDistPhiBitShift(iLogicLayer, omtfCand->getRefLayer()) - <<" meanDistPhiValue "<getGoldenPatern()->meanDistPhiValue(iLogicLayer, omtfCand->getRefLayer())//<<(phiDist != hit.phiDist? "!!!!!!!<<<<<" : "") - < 504 || hit.phiDist < -512) { - edm::LogVerbatim("l1tOmtfEventPrint") - //<<" muonPt "<detId); - if (detId.subdetId() == MuonSubdetId::CSC) { - CSCDetId cscId(detId); - hit.z = cscId.chamber() % 2; - } - - LogTrace("l1tOmtfEventPrint") << "hit: layer " << (int)hit.layer << " quality " << (int)hit.quality << " eta " - << (int)hit.eta << " valid " << (int)hit.valid << " phiDist " << (int)hit.phiDist - << " z " << (int)hit.z << std::endl; - - omtfHitToEventInput(hit, inputs, algoMuon->getRefLayer(), false); - } - } - - LogTrace("l1tOmtfEventPrint") << " " << __FUNCTION__ << ":" << __LINE__ << std::endl; - - std::vector nnResult(outputCnt); - lutNetworkFP->run(inputs, noHitVal, nnResult); - - LogTrace("l1tOmtfEventPrint") << " " << __FUNCTION__ << ":" << __LINE__ << std::endl; - - double pt = std::copysign(nnResult.at(0), nnResult.at(1)); - - LogTrace("l1tOmtfEventPrint") << " " << __FUNCTION__ << ":" << __LINE__ << " nnResult.at(0) " << nnResult.at(0) - << " nnResult.at(1) " << nnResult.at(1) << " pt " << pt << std::endl; - - std::vector pts; - pts.emplace_back(pt); - - //algoMuon->setPtNN(omtfConfig->ptGevToHw(nnResult.at(0))); - auto calibratedHwPt = lutNetworkFP->getCalibratedHwPt(); - algoMuon->setPtNNConstr(calibratedHwPt); - - algoMuon->setChargeNNConstr(nnResult[1] >= 0 ? 1 : -1); - - //TODO add some if here, such that the property_tree is filled only when needed - boost::property_tree::ptree procDataTree; - for (unsigned int i = 0; i < inputs.size(); i++) { - auto& inputTree = procDataTree.add("input", ""); - inputTree.add(".num", i); - inputTree.add(".val", inputs[i]); - } - - std::ostringstream ostr; - ostr << std::fixed << std::setprecision(19) << nnResult.at(0); - procDataTree.add("output0..val", ostr.str()); - - ostr.str(""); - ostr << std::fixed << std::setprecision(19) << nnResult.at(1); - procDataTree.add("output1..val", ostr.str()); - - procDataTree.add("calibratedHwPt..val", calibratedHwPt); - - procDataTree.add("hwSign..val", algoMuon->getChargeNNConstr() < 0 ? 1 : 0); - - for (auto& obs : observers) - obs->addProcesorData("regressionNN", procDataTree); - - return pts; - - //event.print(); - /* - std::vector pts(classifierToRegressions.size(), 0); - - unsigned int i =0; - for(auto& classifierToRegression : classifierToRegressions) { - auto orgValue = classifierToRegression->getValue(&event); - auto absOrgValue = std::abs(orgValue); - pts.at(i) = classifierToRegression->getCalibratedValue(absOrgValue); - pts.at(i) = std::copysign(pts.at(i), orgValue); - - LogTrace("OMTFReconstruction") <<" "<<__FUNCTION__<<":"<<__LINE__<<" orgValue "<