Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ def _appendPhase2Digis(obj):
'keep *_l1tLayer1EG_*_*',
'keep *_l1tLayer2EG_*_*',
'keep *_l1tMETPFProducer_*_*',
'keep *_l1tMETMLProducer_*_*',
'keep *_l1tNNTauProducer_*_*',
'keep *_l1tNNTauProducerPuppi_*_*',
'keep *_l1tHPSPFTauProducerPF_*_*',
Expand Down
1 change: 1 addition & 0 deletions L1Trigger/Configuration/python/SimL1Emulator_cff.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@

from L1Trigger.Phase2L1ParticleFlow.l1tMETPFProducer_cfi import *
_phase2_siml1emulator.add(l1tMETPFProducer)
_phase2_siml1emulator.add(l1tMETMLProducer)


# NNTaus
Expand Down
2 changes: 2 additions & 0 deletions L1Trigger/Phase2L1ParticleFlow/BuildFile.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
<use name="tensorflow"/>
<use name="roottmva"/>
<use name="hls"/>
<use name="hls4mlEmulatorExtras"/>
<use name="L1METML"/>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I ask what the earliest version of CMSSW is that has L1METML? This isn't a problem for you, but we may need to make sure the IB is up to a version that supports your model in CMSSW.

Copy link
Member Author

@jmduarte jmduarte Feb 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was merged on December 20: cms-sw/cmsdist#8901 so I believe CMSSW_14_0_0_pre2 has it (built on December 22), but if not, definitely CMSSW_14_0_0_pre3 has it.

<export>
<lib name="1"/>
</export>
Expand Down
114 changes: 112 additions & 2 deletions L1Trigger/Phase2L1ParticleFlow/plugins/L1MetPfProducer.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <vector>
#include <string>
#include <ap_int.h>
#include <ap_fixed.h>
#include <TVector2.h>
Expand All @@ -13,12 +14,15 @@
#include "DataFormats/L1Trigger/interface/EtSum.h"
#include "DataFormats/Math/interface/LorentzVector.h"

#include "hls4ml/emulator.h"

using namespace l1t;

class L1MetPfProducer : public edm::global::EDProducer<> {
public:
explicit L1MetPfProducer(const edm::ParameterSet&);
~L1MetPfProducer() override;
static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);

private:
void produce(edm::StreamID, edm::Event& iEvent, const edm::EventSetup& iSetup) const override;
Expand Down Expand Up @@ -48,34 +52,80 @@ class L1MetPfProducer : public edm::global::EDProducer<> {
const int invTableBits_ = 10;
const int invTableSize_ = (1 << invTableBits_);

// hls4ml emulator objects
bool useMlModel_;
std::shared_ptr<hls4mlEmulator::Model> model;
std::string modelVersion_;
typedef ap_fixed<32, 16> input_t;
typedef ap_fixed<32, 16> result_t;
int numContInputs_ = 4;
int numPxPyInputs_ = 2;
int numCatInputs_ = 2;
int numInputs_ = numContInputs_ + numPxPyInputs_ + numCatInputs_;

void Project(pt_t pt, phi_t phi, pxy_t& pxy, bool isX, bool debug = false) const;
void PhiFromXY(pxy_t px, pxy_t py, phi_t& phi, bool debug = false) const;

int EncodePdgId(int pdgId) const;

void CalcMetHLS(std::vector<float> pt, std::vector<float> phi, reco::Candidate::PolarLorentzVector& metVector) const;
void CalcMlMet(std::vector<float> pt,
std::vector<float> eta,
std::vector<float> phi,
std::vector<float> puppiWeight,
std::vector<int> pdgId,
std::vector<int> charge,
reco::Candidate::PolarLorentzVector& metVector) const;
};

L1MetPfProducer::L1MetPfProducer(const edm::ParameterSet& cfg)
: _l1PFToken(consumes<std::vector<l1t::PFCandidate>>(cfg.getParameter<edm::InputTag>("L1PFObjects"))),
maxCands_(cfg.getParameter<int>("maxCands")) {
maxCands_(cfg.getParameter<int>("maxCands")),
modelVersion_(cfg.getParameter<std::string>("modelVersion")) {
produces<std::vector<l1t::EtSum>>();
useMlModel_ = (modelVersion_.length() > 0);
if (useMlModel_) {
hls4mlEmulator::ModelLoader loader(modelVersion_);
model = loader.load_model();
}
}

void L1MetPfProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
edm::ParameterSetDescription desc;
desc.add<edm::InputTag>("L1PFObjects", edm::InputTag("L1PFProducer", "l1pfCandidates"));
desc.add<int>("maxCands", 128);
desc.add<std::string>("modelVersion", "");
descriptions.add("L1MetPfProducer", desc);
}

void L1MetPfProducer::produce(edm::StreamID, edm::Event& iEvent, const edm::EventSetup& iSetup) const {
edm::Handle<l1t::PFCandidateCollection> l1PFCandidates;
iEvent.getByToken(_l1PFToken, l1PFCandidates);

std::vector<float> pt;
std::vector<float> eta;
std::vector<float> phi;
std::vector<float> puppiWeight;
std::vector<int> pdgId;
std::vector<int> charge;

for (int i = 0; i < int(l1PFCandidates->size()) && (i < maxCands_ || maxCands_ < 0); i++) {
const auto& l1PFCand = l1PFCandidates->at(i);
pt.push_back(l1PFCand.pt());
eta.push_back(l1PFCand.eta());
phi.push_back(l1PFCand.phi());
puppiWeight.push_back(l1PFCand.puppiWeight());
pdgId.push_back(l1PFCand.pdgId());
charge.push_back(l1PFCand.charge());
}

reco::Candidate::PolarLorentzVector metVector;

CalcMetHLS(pt, phi, metVector);
if (useMlModel_) {
CalcMlMet(pt, eta, phi, puppiWeight, pdgId, charge, metVector);
} else {
CalcMetHLS(pt, phi, metVector);
}

l1t::EtSum theMET(metVector, l1t::EtSum::EtSumType::kTotalHt, 0, 0, 0, 0);

Expand All @@ -84,6 +134,66 @@ void L1MetPfProducer::produce(edm::StreamID, edm::Event& iEvent, const edm::Even
iEvent.put(std::move(metCollection));
}

int L1MetPfProducer::EncodePdgId(int pdgId) const {
switch (abs(pdgId)) {
case 211: // charged hadron (pion)
return 1;
case 130: // neutral hadron (kaon)
return 2;
case 22: // photon
return 3;
case 13: // muon
return 4;
case 11: // electron
return 5;
default:
return 0;
}
}

void L1MetPfProducer::CalcMlMet(std::vector<float> pt,
std::vector<float> eta,
std::vector<float> phi,
std::vector<float> puppiWeight,
std::vector<int> pdgId,
std::vector<int> charge,
reco::Candidate::PolarLorentzVector& metVector) const {
const int inputSize = maxCands_ * numInputs_;

input_t input[800];
result_t result[2];

// initialize with zeros (for padding)
for (int i = 0; i < inputSize; i++) {
input[i] = 0;
}

for (uint i = 0; i < pt.size(); i++) {
// input_cont
input[i * numContInputs_] = pt[i];
input[i * numContInputs_ + 1] = eta[i];
input[i * numContInputs_ + 2] = phi[i];
input[i * numContInputs_ + 3] = puppiWeight[i];
// input_pxpy
input[(maxCands_ * numContInputs_) + (i * numPxPyInputs_)] = pt[i] * cos(phi[i]);
input[(maxCands_ * numContInputs_) + (i * numPxPyInputs_) + 1] = pt[i] * sin(phi[i]);
// input_cat0
input[maxCands_ * (numContInputs_ + numPxPyInputs_) + i] = EncodePdgId(pdgId[i]);
// input_cat1
input[maxCands_ * (numContInputs_ + numPxPyInputs_ + 1) + i] = (abs(charge[i]) <= 1) ? (charge[i] + 2) : 0;
}

model->prepare_input(input);
model->predict();
model->read_result(result);

double met_px = -result[0].to_double();
double met_py = -result[1].to_double();
metVector.SetPt(hypot(met_px, met_py));
metVector.SetPhi(atan2(met_py, met_px));
metVector.SetEta(0);
}

void L1MetPfProducer::CalcMetHLS(std::vector<float> pt,
std::vector<float> phi,
reco::Candidate::PolarLorentzVector& metVector) const {
Expand Down
7 changes: 7 additions & 0 deletions L1Trigger/Phase2L1ParticleFlow/python/l1tMETPFProducer_cfi.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,11 @@
l1tMETPFProducer = cms.EDProducer("L1MetPfProducer",
L1PFObjects = cms.InputTag("l1tLayer1","Puppi"),
maxCands = cms.int32(128),
modelVersion = cms.string(""),
)

l1tMETMLProducer = cms.EDProducer("L1MetPfProducer",
L1PFObjects = cms.InputTag("l1tLayer1","Puppi"),
maxCands = cms.int32(100),
modelVersion = cms.string("L1METML_v1"),
)