Skip to content
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

Emulator cluster firmware style #43363

Merged
merged 9 commits into from
Dec 8, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,9 @@
process.l1tTrackerEmuHTMiss.debug = (options.debug > 0)

#Disable internal track selection
#There is a problem with setting all of these (especially eta) to high numbers.
process.l1tTrackJetsEmulation.MaxDzTrackPV = cms.double(10000.0)
process.l1tTrackJetsEmulation.trk_zMax = cms.double(10000.0) # maximum track z
process.l1tTrackJetsEmulation.trk_ptMax = cms.double(10000.0) # maximumum track pT before saturation [GeV]
process.l1tTrackJetsEmulation.trk_ptMin = cms.double(0.0) # minimum track pt [GeV]
process.l1tTrackJetsEmulation.trk_etaMax = cms.double(10000.0) # maximum track eta
process.l1tTrackJetsEmulation.trk_zMax = cms.double(20.46912512) # maximum track z from TrackWord
process.l1tTrackJetsEmulation.nStubs4PromptChi2=cms.double(10000.0) #Prompt track quality flags for loose/tight
process.l1tTrackJetsEmulation.nStubs4PromptBend=cms.double(10000.0)
process.l1tTrackJetsEmulation.nStubs5PromptChi2=cms.double(10000.0)
Expand Down
87 changes: 87 additions & 0 deletions L1Trigger/L1TTrackMatch/plugins/L1TrackJetClustering.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,22 @@ namespace l1ttrackjet {
const unsigned int ETA_INTPART_BITS{3};
const unsigned int kExtraGlobalPhiBit{4};

static constexpr int kEtaWordLength = 15;
static constexpr int kPhiWordLength = 12;

//Constants used for jet clustering in eta direction
static constexpr int kThirteenBitMask = 0b1111111111111;
static constexpr int kEtaFineBinEdge1 = 0b0011001100110;
static constexpr int kEtaFineBinEdge2 = 0b0110011001100;
static constexpr int kEtaFineBinEdge3 = 0b1001100110010;
static constexpr int kEtaFineBinEdge4 = 0b1100110011000;

//Constants used for jet clustering in phi direction
static constexpr int kTwelveBitMask = 0b011111111111;
static constexpr int kPhiBinHalfWidth = 0b000100101111;
static constexpr int kNumPhiBins = 27;
static constexpr int kPhiBinZeroOffset = 12; // phi bin zero offset between firmware and emulator

typedef ap_ufixed<TTTrack_TrackWord::TrackBitWidths::kRinvSize - 1, PT_INTPART_BITS, AP_TRN, AP_SAT> pt_intern;
typedef ap_fixed<TTTrack_TrackWord::TrackBitWidths::kTanlSize, ETA_INTPART_BITS, AP_TRN, AP_SAT> glbeta_intern;
typedef ap_int<TTTrack_TrackWord::TrackBitWidths::kPhiSize + kExtraGlobalPhiBit> glbphi_intern;
Expand Down Expand Up @@ -113,6 +129,77 @@ namespace l1ttrackjet {
return PassQuality;
}

// Eta binning following the hardware logic
inline unsigned int eta_bin_firmwareStyle(int eta_word) {
//Function that reads in 15-bit eta word (in two's complement) and returns the index of eta bin in which it belongs
//Logic follows exactly according to the firmware
//We will first determine if eta is pos/neg from the first bit. Each half of the grid is then split into four coarse bins. Bits 2&3 determine which coarse bin to assign
//The coarse bins are split into 5 fine bins, final 13 bits determine which of these coarse bins this track needs to assign
int eta_coarse = 0;
int eta_fine = 0;

if (eta_word & (1 << kEtaWordLength)) { //If eta is negative (first/leftmost bit is 1)
//Second and third bits contain information about which of four coarse bins
eta_coarse = 5 * ((eta_word & (3 << (kEtaWordLength - 2))) >> (kEtaWordLength - 2));
} else { //else eta is positive (first/leftmost bit is 0)
eta_coarse = 5 * (4 + ((eta_word & (3 << (kEtaWordLength - 2))) >> (kEtaWordLength - 2)));
}

//Now get the fine bin index. The numbers correspond to the decimal representation of fine bin edges in binary
int j = eta_word & kThirteenBitMask;
if (j < kEtaFineBinEdge1)
eta_fine = 0;
else if (j < kEtaFineBinEdge2)
eta_fine = 1;
else if (j < kEtaFineBinEdge3)
eta_fine = 2;
else if (j < kEtaFineBinEdge4)
eta_fine = 3;
else
eta_fine = 4;

//Final eta bin is coarse bin index + fine bin index, subtract 8 to make eta_bin at eta=-2.4 have index=0
int eta_ = (eta_coarse + eta_fine) - 8;
return eta_;
}

// Phi binning following the hardware logic
inline unsigned int phi_bin_firmwareStyle(int phi_sector_raw, int phi_word) {
//Function that reads in decimal integers phi_sector_raw and phi_word and returns the index of phi bin in which it belongs
//phi_sector_raw is integer 0-8 correspoding to one of 9 phi sectors
//phi_word is 12 bit word representing the phi value measured w.r.t the center of the sector

int phi_coarse = 3 * phi_sector_raw; //phi_coarse is index of phi coarse binning (sector edges)
int phi_fine = 0; //phi_fine is index of fine bin inside sectors. Each sector contains 3 fine bins

//Determine fine bin. First bit is sign, next 11 bits determine fine bin
//303 is distance from 0 to first fine bin edge
//2047 is eleven 1's, use the &2047 to extract leftmost 11 bits.

//The allowed range for phi goes further than the edges of bin 0 or 2 (bit value 909). There's an apparent risk of phi being > 909, however this will always mean the track is in the next link (i.e. track beyond bin 2 in this link means track is actually in bin 0 of adjacent link)

if (phi_word & (1 << (kPhiWordLength - 1))) { //if phi is negative (first bit 1)
//Since negative, we 'flip' the phi word, then check if it is in fine bin 0 or 1
if ((kTwelveBitMask - (phi_word & kTwelveBitMask)) > kPhiBinHalfWidth) {
phi_fine = 0;
} else if ((kTwelveBitMask - (phi_word & kTwelveBitMask)) < kPhiBinHalfWidth) {
phi_fine = 1;
}
} else { //else phi is positive (first bit 0)
//positive phi, no 'flip' necessary. Just check if in fine bin 1 or 2
if ((phi_word & kTwelveBitMask) < kPhiBinHalfWidth) {
phi_fine = 1;
} else if ((phi_word & kTwelveBitMask) > kPhiBinHalfWidth) {
phi_fine = 2;
}
}

// Final operation is a shift by pi (half a grid) to make bin at index=0 at -pi
int phi_bin_ = (phi_coarse + phi_fine + kPhiBinZeroOffset) % kNumPhiBins;

return phi_bin_;
}

// L1 clustering (in eta)
template <typename T, typename Pt, typename Eta, typename Phi>
inline std::vector<T> L1_clustering(T *phislice, int etaBins_, Eta etaStep_) {
Expand Down
95 changes: 29 additions & 66 deletions L1Trigger/L1TTrackMatch/plugins/L1TrackJetEmulatorProducer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -256,22 +256,20 @@ void L1TrackJetEmulatorProducer::produce(Event &iEvent, const EventSetup &iSetup
}
}

//Begin Firmware-style clustering
// logic: loop over z bins find tracks in this bin and arrange them in a 2D eta-phi matrix
for (unsigned int zbin = 0; zbin < zmins.size(); ++zbin) {
// initialize matrices for every z bin
z0_intern zmin = zmins[zbin];
z0_intern zmax = zmaxs[zbin];

TrackJetEmulationEtaPhiBin epbins[phiBins_][etaBins_];

std::copy(&epbins_default[0][0], &epbins_default[0][0] + phiBins_ * etaBins_, &epbins[0][0]);

//clear containers
L1clusters.clear();
L2clusters.clear();

// fill grid
for (unsigned int k = 0; k < L1TrkPtrs_.size(); ++k) {
//// conversions
//-z0
z0_intern trkZ = L1TrkPtrs_[k]->getZ0Word();

if (zmax < trkZ)
Expand All @@ -281,75 +279,40 @@ void L1TrackJetEmulatorProducer::produce(Event &iEvent, const EventSetup &iSetup
if (zbin == 0 && zmin == trkZ)
continue;

//-pt
// Pt
ap_uint<TTTrack_TrackWord::TrackBitWidths::kRinvSize - 1> ptEmulationBits = L1TrkPtrs_[k]->getRinvWord();
pt_intern trkpt;
trkpt.V = ptEmulationBits.range();

//-eta
TTTrack_TrackWord::tanl_t etaEmulationBits = L1TrkPtrs_[k]->getTanlWord();
glbeta_intern trketa;
trketa.V = etaEmulationBits.range();

//-phi
int Sector = L1TrkPtrs_[k]->phiSector();
double sector_phi_value = 0;
if (Sector < 5) {
sector_phi_value = 2.0 * M_PI * Sector / 9.0;
} else {
sector_phi_value = (-1.0 * M_PI + M_PI / 9.0 + (Sector - 5) * 2.0 * M_PI / 9.0);
}

glbphi_intern trkphiSector = DoubleToBit(sector_phi_value,
TTTrack_TrackWord::TrackBitWidths::kPhiSize + kExtraGlobalPhiBit,
TTTrack_TrackWord::stepPhi0);
glbphi_intern local_phi = 0;
local_phi.V = L1TrkPtrs_[k]->getPhiWord();
glbphi_intern local_phi2 =
DoubleToBit(BitToDouble(local_phi, TTTrack_TrackWord::TrackBitWidths::kPhiSize, TTTrack_TrackWord::stepPhi0),
TTTrack_TrackWord::TrackBitWidths::kPhiSize + kExtraGlobalPhiBit,
TTTrack_TrackWord::stepPhi0);
glbphi_intern trkphi = local_phi2 + trkphiSector;

//-d0
// d0
d0_intern abs_trkD0 = L1TrkPtrs_[k]->getD0Word();

//-nstub
// nstubs
int trk_nstubs = (int)L1TrkPtrs_[k]->getStubRefs().size();

// now fill the 2D grid with tracks
for (int i = 0; i < phiBins_; ++i) {
for (int j = 0; j < etaBins_; ++j) {
glbeta_intern eta_min = epbins[i][j].eta - etaStep_ / 2; //eta min
glbeta_intern eta_max = epbins[i][j].eta + etaStep_ / 2; //eta max
glbphi_intern phi_min = epbins[i][j].phi - phiStep_ / 2; //phi min
glbphi_intern phi_max = epbins[i][j].phi + phiStep_ / 2; //phi max
if ((trketa < eta_min) && j != 0)
continue;
if ((trketa > eta_max) && j != etaBins_ - 1)
continue;
if ((trkphi < phi_min) && i != 0)
continue;
if ((trkphi > phi_max) && i != phiBins_ - 1)
continue;

if (trkpt < pt_intern(trkPtMax_))
epbins[i][j].pTtot += trkpt;
else
epbins[i][j].pTtot += pt_intern(trkPtMax_);
if ((abs_trkD0 >
DoubleToBit(d0CutNStubs5_, TTTrack_TrackWord::TrackBitWidths::kD0Size, TTTrack_TrackWord::stepD0) &&
trk_nstubs >= 5 && d0CutNStubs5_ >= 0) ||
(abs_trkD0 >
DoubleToBit(d0CutNStubs4_, TTTrack_TrackWord::TrackBitWidths::kD0Size, TTTrack_TrackWord::stepD0) &&
trk_nstubs == 4 && d0CutNStubs4_ >= 0))
epbins[i][j].nxtracks += 1;

epbins[i][j].trackidx.push_back(k);
++epbins[i][j].ntracks;
} // for each etabin
} // for each phibin
} //end loop over tracks
// Phi bin
int i = phi_bin_firmwareStyle(L1TrkPtrs_[k]->phiSector(),
L1TrkPtrs_[k]->getPhiWord()); //Function defined in L1TrackJetClustering.h

// Eta bin
int j = eta_bin_firmwareStyle(L1TrkPtrs_[k]->getTanlWord()); //Function defined in L1TrackJetClustering.h

if (trkpt < pt_intern(trkPtMax_))
epbins[i][j].pTtot += trkpt;
else
epbins[i][j].pTtot += pt_intern(trkPtMax_);
if ((abs_trkD0 >
DoubleToBit(d0CutNStubs5_, TTTrack_TrackWord::TrackBitWidths::kD0Size, TTTrack_TrackWord::stepD0) &&
trk_nstubs >= 5 && d0CutNStubs5_ >= 0) ||
(abs_trkD0 >
DoubleToBit(d0CutNStubs4_, TTTrack_TrackWord::TrackBitWidths::kD0Size, TTTrack_TrackWord::stepD0) &&
trk_nstubs == 4 && d0CutNStubs4_ >= 0))
epbins[i][j].nxtracks += 1;

epbins[i][j].trackidx.push_back(k);
++epbins[i][j].ntracks;
}
//End Firmware style clustering

// first layer clustering - in eta using grid
for (int phibin = 0; phibin < phiBins_; ++phibin) {
Expand Down