Skip to content

[L1T] L1TSC4NGJetModel (Phase 2) #47798

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 32 commits into
base: master
Choose a base branch
from

Conversation

Chriisbrown
Copy link
Contributor

PR description:

This PR adds the v0.0.0 Level-1 Trigger SeededCone 4 Next Gen Jet Model to CMSSW. This model tags seededcone 4 jets into 8 different classes uds, g, b, c, tau+, tau-, e, mu and regresses a pT correction for the jet.

This PR also includes changes to the jet data format to include the additional tag scores.
There are minor changes to the PF datatypes to add proper functionality for dxy

The model training is documented here
This model is specifically from this release of the code

This model's training artefacts; firmware, model file and performance plots are located here
The cms-hls4ml model file tagged v0.0.0 is found here
The in progress DPS note is found here

This PR relies on an addition to the cms-dist externals, with the open PR cms-sw/cmsdist#9778

PR validation:

Testing of the code happens automatically as part of the model training CI, artefacts of this are found here

Standard code style checks have been performed as has a phase-2 Level-1 trigger cmsDriver test as documented here

@cmsbuild
Copy link
Contributor

cmsbuild commented Apr 7, 2025

cms-bot internal usage

@cmsbuild
Copy link
Contributor

+1

Size: This PR adds an extra 16KB to repository
Summary: https://cmssdt.cern.ch/SDT/jenkins-artifacts/pull-request-integration/PR-4b45cb/45549/summary.html
COMMIT: a6c8e7c
CMSSW: CMSSW_15_1_X_2025-04-14-2300/el8_amd64_gcc12
User test area: For local testing, you can use /cvmfs/cms-ci.cern.ch/week1/cms-sw/cmssw/47798/45549/install.sh to create a dev area with all the needed externals and cmssw changes.

Comparison Summary

Summary:

  • You potentially added 16 lines to the logs
  • Reco comparison results: 4 differences found in the comparisons
  • DQMHistoTests: Total files compared: 51
  • DQMHistoTests: Total histograms compared: 4027853
  • DQMHistoTests: Total failures: 23
  • DQMHistoTests: Total nulls: 0
  • DQMHistoTests: Total successes: 4027810
  • DQMHistoTests: Total skipped: 20
  • DQMHistoTests: Total Missing objects: 0
  • DQMHistoSizes: Histogram memory added: 0.0 KiB( 50 files compared)
  • Checked 220 log files, 188 edm output root files, 51 DQM output files
  • TriggerResults: no differences found

fMaxEta_(cfg.getParameter<double>("maxEta")),
fMaxJets_(cfg.getParameter<int>("maxJets")),
fNParticles_(cfg.getParameter<int>("nParticles")),
loader(hls4mlEmulator::ModelLoader(cfg.getParameter<string>("l1tSC4NGJetModelPath"))) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Just a note: in Run 3 we get the model names from the menu, but we should generally discuss how we want to do this in Phase 2

std::vector<l1ct::JetTagClass> classes_;

hls4mlEmulator::ModelLoader loader;
std::shared_ptr<hls4mlEmulator::Model> model;
Copy link
Contributor

Choose a reason for hiding this comment

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

could you add a logerror in case the model is not loaded properly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a error throw when the model is not found

fId_.get()[i0] = iParts[i0]->id();
}
setNNVectorVar();
return EvaluateNNFixed();
Copy link
Contributor

Choose a reason for hiding this comment

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

general comment: would it be useful to add some log error/debug lines in case the nn evaluation doesnt work as expected?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added debugging to model input and output so the NN evaluation can be properly debugged

@@ -363,11 +369,29 @@ void l1ct::TrackInputEmulator::configPhi(int bits) {

float l1ct::TrackInputEmulator::floatZ0(ap_int<12> z0) const { return z0Scale_ * toFloat_(z0); }

// float l1ct::TrackInputEmulator::floatDxy(ap_int<13> dxy) const { return dxyScale_ * toFloat_(dxy); }
float l1ct::TrackInputEmulator::floatDxy(ap_int<13> dxy) const {
// return dxyScale_ * toFloat_(dxy);
Copy link
Contributor

Choose a reason for hiding this comment

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

can this comment be removed? (L372, L374)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

l1ct::z0_t l1ct::TrackInputEmulator::convZ0(ap_int<12> z0) const {
int offs = z0 >= 0 ? z0OffsPos_ : z0OffsNeg_;
return (z0.to_int() * z0Mult_ + offs) >> z0BitShift_;
}

l1ct::dxy_t l1ct::TrackInputEmulator::convDxy(ap_int<13> dxy) const {
int offs = dxy >= 0 ? dxyOffsPos_ : dxyOffsNeg_;
// return (dxy.to_int() * dxyMult_ + offs) >> dxyBitShift_;
Copy link
Contributor

Choose a reason for hiding this comment

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

can this comment be removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -34,7 +34,7 @@ namespace l1ct {
typedef ap_ufixed<10, 5, AP_TRN, AP_SAT> hoe_t;
typedef ap_uint<4> redChi2Bin_t;
typedef ap_fixed<10, 1, AP_RND_CONV, AP_SAT> id_score_t; // ID score to be between -1 (background) and 1 (signal)
typedef ap_ufixed<10, 1, AP_RND, AP_SAT> b_tag_score_t; // result_t from the NN is still apx_fixed<16,6>
typedef ap_ufixed<8, 1, AP_RND_CONV, AP_SAT> jet_tag_score_t; // 8 bit jet jet probability from 0 to 1
Copy link
Contributor

Choose a reason for hiding this comment

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

Just something to keep in mind: we found with axol1tl that the score type is subject to change with different model versions, so we are thinking about adding a template function to the base cms-hls4ml emulator class to get the result/score type so that the score type does not need to be hardcoded into the emulator. just something to look out for and perhaps modify in the future

@@ -144,7 +144,9 @@ namespace l1ct {
constexpr float INTPT_LSB = 0.25;
constexpr float ETAPHI_LSB = M_PI / INTPHI_PI;
constexpr float Z0_LSB = 0.05;
constexpr float DXY_LSB = 0.05;
//constexpr float DXY_LSB = 0.05;
Copy link
Contributor

Choose a reason for hiding this comment

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

could this comment be removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment on lines +427 to +437
dxyMult_ = std::round(scale * (1 << bits));
switch (encoding_) {
case Encoding::Stepping:
dxyOffsPos_ = std::round(+scale * 0.5 * (1 << bits) + 0.5 * (1 << bits));
dxyOffsNeg_ = std::round(-scale * 0.5 * (1 << bits) + 0.5 * (1 << bits));
break;
case Encoding::Biased:
dxyOffsPos_ = std::round(+scale * 0.5 * (1 << bits) + 0.5 * (1 << bits));
dxyOffsNeg_ = std::round(+scale * 0.5 * (1 << bits) + 0.5 * (1 << bits));
break;
case Encoding::Unbiased:
Copy link
Contributor

Choose a reason for hiding this comment

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

some comments explaining what is being done here might be useful

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added comment explaining the function and the variables it sets

Copy link
Contributor

@BenjaminRS BenjaminRS left a comment

Choose a reason for hiding this comment

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

Hi Chris, thanks for this PR. I have some comments on the code.

@@ -19,7 +19,7 @@ namespace l1ct {
typedef ap_int<11> glbphi_t;
typedef ap_int<5> vtx_t;
typedef ap_int<10> z0_t; // 40cm / 0.1
typedef ap_int<8> dxy_t; // tbd
typedef ap_uint<8> dxy_t; // tbd
Copy link
Contributor

Choose a reason for hiding this comment

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

In the comment: why is this tbd?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed from tbd to an explanation of the variable

Comment on lines 148 to 149
constexpr float DXY_LSB = 0.00390625;
constexpr float DXYSQRT_LSB = 0.015625;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to add comments explaining these values please?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added comments explaining where these values come from

inline float floatPuppiW(puppiWgt_t puppiw) { return puppiw.to_float(); }
inline float floatIso(iso_t iso) { return iso.to_float(); }
inline float floatSrrTot(srrtot_t srrtot) { return srrtot.to_float() / SRRTOT_SCALE; };
inline float floatMeanZ(meanz_t meanz) { return meanz + MEANZ_OFFSET; };
inline float floatHoe(hoe_t hoe) { return hoe.to_float(); };
inline float floatIDScore(id_score_t score) { return score.to_float(); };
inline float floatBtagScore(b_tag_score_t b_tag_score) { return b_tag_score.to_float(); }
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it correct to remove the b-tag score completely?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We now wrap everything up in the float ID score which supersedes the BtagScore

@@ -169,20 +171,20 @@ namespace l1ct {
inline float floatEta(glbeta_t eta) { return eta.to_float() * ETAPHI_LSB; }
inline float floatPhi(glbphi_t phi) { return phi.to_float() * ETAPHI_LSB; }
inline float floatZ0(z0_t z0) { return z0.to_float() * Z0_LSB; }
inline float floatDxy(dxy_t dxy) { return dxy.to_float() * DXY_LSB; }
inline float floatDxy(dxy_t dxy) { return dxy.to_float() * DXYSQRT_LSB; }
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it correct to have this using DXYSQRT_LSB and in

inline dxy_t makeDxy(float dxy) { return dxy_t(std::round(dxy / DXY_LSB)); }
using DXY_LSB?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This has been changes at L187 to use DXYSQRT_LSB

inline bool operator==(const Jet &other) const { return valid == other.valid && z0 == other.z0 && v3 == other.v3; }
inline bool operator==(const Jet &other) const {
bool eq = valid == other.valid && z0 == other.z0 && v3 == other.v3;
for (unsigned i = 0; i < NTagFields; i++) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Could simplify here and L109 and L136 with

Suggested change
for (unsigned i = 0; i < NTagFields; i++) {
for (auto i:NTagFields) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not changed as NTagFields is a single integer value so there wasn't a clean auto loop version

Copy link
Contributor

Choose a reason for hiding this comment

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

As an FYI you can include the ranges library and then use:

for (auto i : std::views::iota(0, static_cast<int>(NTagFields))){

But it is up to you if you want to change these or not

#include "L1Trigger/Phase2L1ParticleFlow/interface/jetmet/L1SeedConePFJetEmulator.h"

//HLS4ML compiled emulator modeling
#include <string>
Copy link
Contributor

Choose a reason for hiding this comment

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

Already included on

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed

class L1TSC4NGJetID {
public:
L1TSC4NGJetID(const std::shared_ptr<hls4mlEmulator::Model> model, int iNParticles);
~L1TSC4NGJetID() = default;
Copy link
Contributor

Choose a reason for hiding this comment

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

Needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not needed and removed

Comment on lines 19 to 21
#include <string>
#include "ap_fixed.h"
#include "hls4ml/emulator.h"
Copy link
Contributor

Choose a reason for hiding this comment

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

No need for these as they are already included in

#include <string>
#include "ap_fixed.h"
#include "hls4ml/emulator.h"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

#include "ap_fixed.h"
#include "hls4ml/emulator.h"

using namespace l1t;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we avoid this please? I see l1t::PFJet is used below anyway

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

}
std::sort(taggedJets.begin(), taggedJets.end(), [](l1t::PFJet a, l1t::PFJet b) { return (a.pt() > b.pt()); });

std::unique_ptr<l1t::PFJetCollection> taggedJetsCollection(new l1t::PFJetCollection);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should use std::make_unique instead of the new

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

PR code review 1
@cmsbuild
Copy link
Contributor

+code-checks

Logs: https://cmssdt.cern.ch/SDT/code-checks/cms-sw-PR-47798/44599

@cmsbuild
Copy link
Contributor

Pull request #47798 was updated. @BenjaminRS, @Moanwar, @cmsbuild, @quinnanm, @srimanob, @subirsarkar can you please check and sign again.

@BenjaminRS
Copy link
Contributor

test parameters:

@BenjaminRS
Copy link
Contributor

please test

@cmsbuild
Copy link
Contributor

+1

Size: This PR adds an extra 16KB to repository
Summary: https://cmssdt.cern.ch/SDT/jenkins-artifacts/pull-request-integration/PR-4b45cb/45702/summary.html
COMMIT: f7583c7
CMSSW: CMSSW_15_1_X_2025-04-24-1100/el8_amd64_gcc12
User test area: For local testing, you can use /cvmfs/cms-ci.cern.ch/week0/cms-sw/cmssw/47798/45702/install.sh to create a dev area with all the needed externals and cmssw changes.

Comparison Summary

Summary:

  • You potentially added 15 lines to the logs
  • Reco comparison results: 8 differences found in the comparisons
  • DQMHistoTests: Total files compared: 51
  • DQMHistoTests: Total histograms compared: 4024789
  • DQMHistoTests: Total failures: 19
  • DQMHistoTests: Total nulls: 0
  • DQMHistoTests: Total successes: 4024750
  • DQMHistoTests: Total skipped: 20
  • DQMHistoTests: Total Missing objects: 0
  • DQMHistoSizes: Histogram memory added: 0.0 KiB( 50 files compared)
  • Checked 220 log files, 188 edm output root files, 51 DQM output files
  • TriggerResults: no differences found

@BenjaminRS
Copy link
Contributor

+l1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.