From 7335d9a10a160b4b65ae2e010df4e0f4f701db40 Mon Sep 17 00:00:00 2001 From: cerminar Date: Mon, 11 Jan 2021 16:17:44 +0100 Subject: [PATCH 1/7] first implementation of EG firmware --- firmware/data.h | 44 ++++- firmware/pftkegalgo.cpp | 195 +++++++++++++++++++++ firmware/pftkegalgo.h | 38 ++++ pftkegalgo_test.cpp | 186 ++++++++++++++++++++ ref/pftkegalgo_ref.cpp | 338 ++++++++++++++++++++++++++++++++++++ ref/pftkegalgo_ref.h | 75 ++++++++ run_hls_ptkegalgo.tcl | 38 ++++ utils/DiscretePF2Firmware.h | 1 + utils/Firmware2DiscretePF.h | 1 + 9 files changed, 913 insertions(+), 3 deletions(-) create mode 100644 firmware/pftkegalgo.cpp create mode 100644 firmware/pftkegalgo.h create mode 100644 pftkegalgo_test.cpp create mode 100644 ref/pftkegalgo_ref.cpp create mode 100644 ref/pftkegalgo_ref.h create mode 100644 run_hls_ptkegalgo.tcl diff --git a/firmware/data.h b/firmware/data.h index 607254a..f2d0671 100644 --- a/firmware/data.h +++ b/firmware/data.h @@ -17,6 +17,9 @@ typedef ap_uint<14> tk2em_dr_t; typedef ap_uint<14> tk2calo_dr_t; typedef ap_uint<10> em2calo_dr_t; typedef ap_uint<13> tk2calo_dq_t; +// FIXME: randomly chosen +typedef ap_uint<3> hwflags_t; + enum PID { PID_Charged=0, PID_Neutral=1, PID_Photon=2, PID_Electron=3, PID_Muon=4 }; @@ -27,11 +30,16 @@ enum PID { PID_Charged=0, PID_Neutral=1, PID_Photon=2, PID_Electron=3, PID_Muon= #define NMU 4 #define NSELCALO 20 #define NALLNEUTRALS NSELCALO - // dummy - #define NEMCALO 1 + // FIXME: determine how big this needs to be + #define NEMCALO 20 #define NPHOTON NEMCALO // not used but must be there because used in header files #define NNEUTRALS 1 + // Configuration of EG algo follows + // FIXME: determine how big this needs to be + #define NEMCALOSEL_EGIN 10 + #define DOBREMRECOVERY + #define NEM_EGOUT 5 //-------------------------------- #elif defined(REG_HGCalNoTK) #define NCALO 12 @@ -141,9 +149,11 @@ struct EmCaloObj { pt_t hwPt, hwPtErr; eta_t hwEta; // relative to the region center, at calo phi_t hwPhi; // relative to the region center, at calo + hwflags_t hwFlags; + }; inline void clear(EmCaloObj & c) { - c.hwPt = 0; c.hwPtErr = 0; c.hwEta = 0; c.hwPhi = 0; + c.hwPt = 0; c.hwPtErr = 0; c.hwEta = 0; c.hwPhi = 0; c.hwFlags = 0; } @@ -252,9 +262,37 @@ inline void fill(PuppiObj &out, const HadCaloObj &src, pt_t puppiPt, puppiWgt_t out.setHwPuppiW(puppiWgt); } +struct EGIsoEleParticle { + pt_t hwPt; + eta_t hwEta; // at calo face + phi_t hwPhi; + // uint16_t hwQual; + // track parameters for electrons + eta_t hwVtxEta; + phi_t hwVtxPhi; + z0_t hwZ0; + bool hwCharge; + // uint16_t hwIso; +}; +inline void clear(EGIsoEleParticle & c) { + c.hwPt = 0; c.hwEta = 0; c.hwPhi = 0; + c.hwVtxEta = 0; c.hwVtxPhi = 0; c.hwZ0=0; + c.hwCharge = false; +} +struct EGIsoParticle { + pt_t hwPt; + eta_t hwEta; // at calo face + phi_t hwPhi; + // uint16_t hwQual; + // uint16_t hwIso; +}; + +inline void clear(EGIsoParticle & c) { + c.hwPt = 0; c.hwEta = 0; c.hwPhi = 0; +} //TMUX #define NETA_TMUX 2 diff --git a/firmware/pftkegalgo.cpp b/firmware/pftkegalgo.cpp new file mode 100644 index 0000000..7244205 --- /dev/null +++ b/firmware/pftkegalgo.cpp @@ -0,0 +1,195 @@ +#include "pftkegalgo.h" +#include + +#include "pfalgo_common.icc" + +ap_int ell_dpt_int_cap(eta_t eta1, phi_t phi1, eta_t eta2, phi_t phi2, pt_t pt1, pt_t pt2, ap_int max) { +#pragma HLS INLINE + // FIXME: this should be configurable + const ap_uint<10> cdeta = 16; + const ap_uint<10> cm = 256; + + ap_int d_eta = (eta1-eta2); + ap_int d_phi = (phi1-phi2); + + int ell = d_phi*d_phi + d_eta*d_eta*cdeta; + // FIXME: should be ap_uint ? + ap_int d_pt = abs(pt1 - pt2); + return (ell <= int(cm)) ? d_pt : max; +} + + + +template +void calo2tk_ellipticdptvals(const EmCaloObj &em, const TkObj track[NTRACK], ap_int calo_track_dptval[NTRACK]) { +#pragma HLS INLINE + // ap_int ? + // FIXME: uint + // FIXME: some of this should be configurable + const ap_int eDPTMAX = DPTMAX; + const pt_t trkQualityPtMin_ = 40; // 10 GeV + + track_loop: for (int itk = 0; itk < NTRACK; ++itk) { + if (track[itk].hwPt < trkQualityPtMin_ || em.hwPt == 0) { + calo_track_dptval[itk] = eDPTMAX; + } else { + calo_track_dptval[itk] = ell_dpt_int_cap(em.hwEta, em.hwPhi, track[itk].hwEta, track[itk].hwPhi, em.hwPt, track[itk].hwPt, eDPTMAX); + // std::cout << "[" << itk << "] dpt: " << calo_track_dptval[itk] << std::endl; + } + } + +} + + + +void link_emCalo2emCalo(const EmCaloObj emcalo[NEMCALOSEL_EGIN], ap_uint emCalo2emcalo_bit[NEMCALOSEL_EGIN]) { + #pragma HLS ARRAY_PARTITION variable=emcalo complete dim=1 + #pragma HLS ARRAY_PARTITION variable=emCalo2emcalo_bit complete dim=1 + #pragma HLS INLINE + + // FIXME: configuration + const ap_int dEtaMaxBrem_ = 5; // 0.02; -> round(0.02*4*180/3.14) + const ap_int dPhiMaxBrem_ = 23; // 0.1; -> round(0.1*4*180/3.14) + + // NOTE: we assume the input to be sorted!!! + brem_reco_outer_loop: for (int ic = 0; ic < NEMCALOSEL_EGIN; ++ic) { + auto &calo = emcalo[ic]; + brem_reco_inner_loop: for (int jc = ic + 1; jc < NEMCALOSEL_EGIN; ++jc) { + auto &otherCalo = emcalo[jc]; + if (calo.hwPt != 0 && otherCalo.hwPt != 0 && + abs(otherCalo.hwEta - calo.hwEta) < dEtaMaxBrem_ && + abs(otherCalo.hwPhi - calo.hwPhi) < dPhiMaxBrem_) { + emCalo2emcalo_bit[ic][jc] = 1; + emCalo2emcalo_bit[jc][jc] = 1; // use diagonal bit to mark the cluster as already used + } + } + } +} + + + + + +void link_emCalo2tk(const EmCaloObj emcalo[NEMCALOSEL_EGIN], + const TkObj track[NTRACK], + ap_uint emCalo2tk_bit[NEMCALOSEL_EGIN]) { + #pragma HLS INLINE + + #pragma HLS ARRAY_PARTITION variable=emcalo complete dim=1 + #pragma HLS ARRAY_PARTITION variable=track complete dim=1 + #pragma HLS ARRAY_PARTITION variable=emCalo2tk_bit complete dim=1 + + // FIXME: parametrize + const int DPTMAX = 65535; // DPT = 16+1 bits -> max = 2^16-1 = ((1<<16)-1) + calo_loop: for (int ic = 0; ic < NEMCALOSEL_EGIN; ++ic) { + ap_int dptvals[NTRACK]; + calo2tk_ellipticdptvals(emcalo[ic], track, dptvals); + emCalo2tk_bit[ic] = pick_closest>(dptvals); + } + +} + + +void sel_emCalo(const EmCaloObj emcalo[NEMCALO], EmCaloObj emcalo_sel[NEMCALOSEL_EGIN]) { + #pragma HLS INLINE + + EmCaloObj emcalo_selt[NEMCALO]; + #pragma HLS ARRAY_PARTITION variable=emcalo_sel complete dim=1 + #pragma HLS ARRAY_PARTITION variable=emcalo_selt complete dim=1 + EmCaloObj emcalo_zero; + clear(emcalo_zero); + in_select_loop: for(int ic = 0; ic < NEMCALO; ++ic) { + emcalo_selt[ic] = (emcalo[ic].hwFlags == SELHWQUAL) ? emcalo[ic] : emcalo_zero; + } + ptsort_hwopt(emcalo_selt, emcalo_sel); +} + + +void pftkegalgo(const EmCaloObj emcalo[NCALO], const TkObj track[NTRACK], + // ap_uint emCalo2tk_bit[NEMCALOSEL_EGIN], ap_uint emCalo2emcalo_bit[NEMCALOSEL_EGIN], + EGIsoParticle photons[NEM_EGOUT], EGIsoEleParticle eles[NEM_EGOUT]) { + #pragma HLS PIPELINE II=1 + #pragma HLS ARRAY_PARTITION variable=emcalo complete dim=1 + #pragma HLS ARRAY_PARTITION variable=track complete dim=1 + + #pragma HLS ARRAY_PARTITION variable=photons complete dim=1 + #pragma HLS ARRAY_PARTITION variable=eles complete dim=1 + + // FIXME: filter out qualities which are not useful for later processing (eg quality !=4 in HGC) + // EmCaloObj emcalo_sel[NEMCALOSEL_EGIN]; + EmCaloObj emcalo_sel[NEMCALOSEL_EGIN]; + EmCaloObj emcalo_selt[NEMCALO]; + #pragma HLS ARRAY_PARTITION variable=emcalo_sel complete dim=1 + #pragma HLS ARRAY_PARTITION variable=emcalo_selt complete dim=1 + EmCaloObj emcalo_zero; + clear(emcalo_zero); + in_select_loop: for(int ic = 0; ic < NEMCALO; ++ic) { + emcalo_selt[ic] = (emcalo[ic].hwFlags == SELHWQUAL) ? emcalo[ic] : emcalo_zero; + } + ptsort_hwopt(emcalo_selt, emcalo_sel); + + // FIXME: shall we forseen the same selection step for tracks? + ap_uint emCalo2tk_bit[NEMCALOSEL_EGIN]; + ap_uint emCalo2emcalo_bit[NEMCALOSEL_EGIN]; + #pragma HLS ARRAY_PARTITION variable=emCalo2tk_bit complete dim=1 + #pragma HLS ARRAY_PARTITION variable=emCalo2emcalo_bit complete dim=1 + + // initialize + init_loop: for (int ic = 0; ic < NEMCALOSEL_EGIN; ++ic) { + emCalo2tk_bit[ic] = 0; + emCalo2emcalo_bit[ic] = 0; + } + + #if defined(DOBREMRECOVERY) + link_emCalo2emCalo(emcalo_sel, emCalo2emcalo_bit); + #endif + // + link_emCalo2tk(emcalo_sel, track, emCalo2tk_bit); + + + EGIsoParticle photons_temp[NEMCALOSEL_EGIN]; + EGIsoEleParticle eles_temp[NEMCALOSEL_EGIN]; + #pragma HLS ARRAY_PARTITION variable=photons_temp complete dim=1 + #pragma HLS ARRAY_PARTITION variable=eles_temp complete dim=1 + + int track_id = -1; + loop_calo: for (int ic = 0; ic < NEMCALOSEL_EGIN; ++ic) { + loop_track_matched: for(int it = 0; it < NTRACK; ++it) { + if(emCalo2tk_bit[ic][it]) { + track_id = it; + break; + } + } + + pt_t ptcorr = emcalo_sel[ic].hwPt; + #if defined(DOBREMRECOVERY) + if(emCalo2emcalo_bit[ic][ic] != 1) { // FIXME: we still save the multiclusters used as brem??? + // FIXME: we should set the quality bit as "brem-recovery performed" + loop_calo_brem_reco: for (int ioc = 0; ioc < NEMCALOSEL_EGIN; ++ioc) { + if(emCalo2emcalo_bit[ic][ioc]) { + ptcorr += emcalo_sel[ioc].hwPt; + } + } + } + #endif + + photons_temp[ic].hwPt = ptcorr; + photons_temp[ic].hwEta = emcalo_sel[ic].hwEta; + photons_temp[ic].hwPhi = emcalo_sel[ic].hwPhi; + + if(emCalo2tk_bit[ic]) { + eles_temp[ic].hwPt = ptcorr; + eles_temp[ic].hwEta = emcalo_sel[ic].hwEta; + eles_temp[ic].hwPhi = emcalo_sel[ic].hwPhi; + // FIXME: add track properties @ vertex using + eles_temp[ic].hwZ0 = track[track_id].hwZ0; + //track[it] + } else { + clear(eles_temp[ic]); + } + + } + ptsort_hwopt(photons_temp, photons); + ptsort_hwopt(eles_temp, eles); + +} diff --git a/firmware/pftkegalgo.h b/firmware/pftkegalgo.h new file mode 100644 index 0000000..7928105 --- /dev/null +++ b/firmware/pftkegalgo.h @@ -0,0 +1,38 @@ +#ifndef FIRMWARE_PFTKEGALGO_H +#define FIRMWARE_PFTKEGALGO_H + +// FIXME: move to data.h +// FIXME: tune on the basis of the region occupancy +// FIXME: this needs to go somewhere else +#define SELHWQUAL 4 + +#ifndef REG_HGCal + + #ifndef CMSSW_GIT_HASH + #warning "REG_HGCal is not #defined, but this algorithm has only been tested there" + #endif +#endif + +#include "pfalgo_common.h" +#include "data.h" + +void pftkegalgo(const EmCaloObj emcalo[NEMCALO], const TkObj track[NTRACK], + EGIsoParticle photons[NEM_EGOUT], + EGIsoEleParticle eles[NEM_EGOUT] +) ; + +void link_emCalo2tk(const EmCaloObj emcalo[NEMCALOSEL_EGIN], const TkObj track[NTRACK], ap_uint emCalo2tk_bit[NEMCALOSEL_EGIN]); + +void link_emCalo2emCalo(const EmCaloObj emcalo[NEMCALOSEL_EGIN], ap_uint emCalo2emcalo_bit[NEMCALOSEL_EGIN]); + +void sel_emCalo(const EmCaloObj emcalo[NEMCALO], EmCaloObj emcalo_sel[NEMCALOSEL_EGIN]); + +// FIXME: I added this to have pfalgo_common.icc compile... +#ifndef CMSSW_GIT_HASH +#define PFALGO_DR2MAX_TK_CALO 525 +#define PFALGO_TK_MAXINVPT_LOOSE 40 +#define PFALGO_TK_MAXINVPT_TIGHT 80 +#endif + + +#endif diff --git a/pftkegalgo_test.cpp b/pftkegalgo_test.cpp new file mode 100644 index 0000000..10ebe16 --- /dev/null +++ b/pftkegalgo_test.cpp @@ -0,0 +1,186 @@ +#include +#include "firmware/pftkegalgo.h" + +#include "ref/pftkegalgo_ref.h" + +#include "utils/DiscretePFInputsReader.h" +#include "utils/pattern_serializer.h" +#include "utils/test_utils.h" + +#define NTEST 10000 + +bool emcalo_equal(const EmCaloObj &emcalo1, const EmCaloObj &emcalo2) { + return emcalo1.hwPt == emcalo2.hwPt && emcalo1.hwEta == emcalo2.hwEta && emcalo1.hwPhi == emcalo2.hwPhi; +} + +bool compare(const EGIsoEleParticle&ele1, const EGIsoEleParticle&ele2) { + // FIXME: add other parameters + return (ele1.hwPt == ele2.hwPt && + ele1.hwEta == ele2.hwEta && + ele1.hwPhi == ele2.hwPhi && + ele1.hwZ0 == ele2.hwZ0); +} + +bool compare(const EGIsoParticle&ele1, const EGIsoParticle&ele2) { + // FIXME: add other parameters + return (ele1.hwPt == ele2.hwPt && + ele1.hwEta == ele2.hwEta && + ele1.hwPhi == ele2.hwPhi); +} + + +int main() { + HumanReadablePatternSerializer debugHR("-", /*zerosuppress=*/true); // this will print on stdout, we'll use it for errors + + DiscretePFInputsReader inputs("DoubleElectron_PU200_HGCal.dump"); + + // input TP objects + HadCaloObj calo[NCALO]; EmCaloObj emcalo[NEMCALO]; TkObj track[NTRACK]; z0_t hwZPV; + MuObj mu[NMU]; + + // output PF objects + PFChargedObj outch[NTRACK], outch_ref[NTRACK]; + PFNeutralObj outne[NSELCALO], outne_ref[NSELCALO]; + PFChargedObj outmupf[NMU], outmupf_ref[NMU]; + + PFTkEGAlgo::pftkegalgo_config cfg(NTRACK, NEMCALO, NEMCALOSEL_EGIN, NEM_EGOUT); + + // ----------------------------------------- + // run multiple tests + int passed_tests = 0; + int nEles_tests = 0; + int nPhotons_tests = 0; + + for (int test = 1; test <= NTEST; ++test) { + // std::cout << "------------ TEST: " << test << std::endl; + // get the inputs from the input object + if (!inputs.nextRegion(calo, emcalo, track, mu, hwZPV)) break; + + // for(auto region: inputs.event().regions) { + // printf("# of EM objects: %u\n", region.emcalo.size()); + // for(auto emc: region.emcalo) { + // printf(" - hwFlags: %u\n", emc.hwFlags); + // } + // } + + // 0 - input cluster selection + EmCaloObj emcalo_sel[NEMCALOSEL_EGIN]; + EmCaloObj emcalo_sel_ref[NEMCALOSEL_EGIN]; + sel_emCalo(emcalo, emcalo_sel); + PFTkEGAlgo::sel_emCalo_ref(emcalo, emcalo_sel_ref); + + + // FIXME: determine output depth + int emCalo2tk_ref[NEMCALOSEL_EGIN], emCalo2tk[NEMCALOSEL_EGIN]; + for(int id = 0; id < NEMCALOSEL_EGIN; id++) { + emCalo2tk_ref[id] = -1; + emCalo2tk[id] = -1; + } + + + int emCalo2emcalo_ref[NEMCALOSEL_EGIN], emCalo2emcalo[NEMCALOSEL_EGIN]; + for(int id = 0; id < NEMCALOSEL_EGIN; id++) { + emCalo2emcalo_ref[id] = -1; + emCalo2emcalo[id] = -1; + } + + // pftkegalgo(emcalo, track); + EGIsoParticle egphs_ref[NEM_EGOUT]; + EGIsoEleParticle egele_ref[NEM_EGOUT]; + PFTkEGAlgo::pftkegalgo_ref(cfg, emcalo_sel_ref, track, emCalo2tk_ref, emCalo2emcalo_ref, egphs_ref, egele_ref); + + ap_uint emCalo2tk_bit[NEMCALOSEL_EGIN]; + ap_uint emCalo2emcalo_bit[NEMCALOSEL_EGIN]; + EGIsoParticle egphs[NEM_EGOUT]; + EGIsoEleParticle egele[NEM_EGOUT]; + + for(int i = 0; i < NEMCALOSEL_EGIN; i++) { + emCalo2tk_bit[i] = 0; + emCalo2emcalo_bit[i] = 0; + } + + link_emCalo2emCalo(emcalo_sel, emCalo2emcalo_bit); + link_emCalo2tk(emcalo_sel, track, emCalo2tk_bit); + + pftkegalgo(emcalo, track, egphs, egele) ; + + for(int ic = 0; ic < NEMCALOSEL_EGIN; ic++) { + for(int it = 0; it < NTRACK; it++) { + if(emCalo2tk_bit[ic][it]) + emCalo2tk[ic] = it; + } + } + + for(int ic = 0; ic < NEMCALOSEL_EGIN; ic++) { + if(emCalo2emcalo_bit[ic][ic]) continue; + for(int it = 0; it < NEMCALOSEL_EGIN; it++) { + if(emCalo2emcalo_bit[ic][it]) + emCalo2emcalo[it] = ic; + } + } + + // ----------------------------------------- + // validation against the reference algorithm + int errors = 0; + // int ntot = 0, nch = 0, nneu = 0, nmu = 0; + for(int i = 0; i < NEMCALOSEL_EGIN; i++) { + if (!emcalo_equal(emcalo_sel_ref[i], emcalo_sel[i])) { + std::cout << "emcalo_sel [" << i << "]" << " REF: " << emcalo_sel_ref[i].hwPt << " FW: " << emcalo_sel[i].hwPt << std::endl; + errors++; + } + } + + for(int i = 0; i < NEMCALOSEL_EGIN; i++) { + if (emCalo2tk_ref[i] != emCalo2tk[i]) { + std::cout << "emCalo2tk [" << i << "]" << " REF: " << emCalo2tk_ref[i] << " FW: " << emCalo2tk[i] << std::endl; + errors++; + } + } + + for(int i = 0; i < NEMCALOSEL_EGIN; i++) { + if (emCalo2emcalo_ref[i] != emCalo2emcalo[i]) { + std::cout << "emCalo2emcalo [" << i << "]" << " REF: " << emCalo2emcalo_ref[i] << " FW: " << emCalo2emcalo[i] << std::endl; + errors++; + } + } + + for(int it = 0; it < NEM_EGOUT; it++) { + if(egele_ref[it].hwPt > 0) { + nEles_tests++; + if(!compare(egele_ref[it], egele[it])) { + errors++; + std::cout << "[" << it << "] REF ele pt: " << egele_ref[it].hwPt << " FW ele pt: " << egele[it].hwPt << std::endl; + std::cout << " REF ele Z0: " << egele_ref[it].hwZ0 << " FW ele z0: " << egele[it].hwZ0 << std::endl; + + + } + } + } + + for(int it = 0; it < NEM_EGOUT; it++) { + if(egphs_ref[it].hwPt > 0) { + nPhotons_tests++; + if(!compare(egphs_ref[it], egphs[it])) { + errors++; + std::cout << "[" << it << "] REF photon pt: " << egphs_ref[it].hwPt << " FW photon pt: " << egphs[it].hwPt << std::endl; + } + + } + } + + + if (errors != 0) { + printf("Error in computing test %d (%d)\n", test, errors); + // printf("Inputs: \n"); debugHR.dump_inputs(calo, track, mu); + // printf("Reference output: \n"); debugHR.dump_outputs(outch_ref, outne_ref, outmupf_ref); + // printf("Current output: \n"); debugHR.dump_outputs(outch, outne, outmupf); + return 1; + } else { + passed_tests++; + // printf("Passed test %d\n", test); + } + } + printf("Passed %d tests (%d electrons, %d photons)\n", passed_tests, nEles_tests, nPhotons_tests); + + return 0; +} diff --git a/ref/pftkegalgo_ref.cpp b/ref/pftkegalgo_ref.cpp new file mode 100644 index 0000000..b6b1541 --- /dev/null +++ b/ref/pftkegalgo_ref.cpp @@ -0,0 +1,338 @@ +#include "pftkegalgo_ref.h" + + +#include "../utils/Firmware2DiscretePF.h" +#include "../utils/DiscretePF2Firmware.h" + +#include +#include +#include +#include +#include + + + +int g_pftkegalgo_debug_ref_ = 0; + +using namespace PFTkEGAlgo; +// void PFTkEGAlgo::initRegion(Region &r) const { +// // FIXME: assume imput is sorted already +// r.egobjs.clear(); +// } +float PFTkEGAlgo::deltaPhi(float phi1, float phi2) { + // reduce to [-pi,pi] + float x = phi1 - phi2; + float o2pi = 1. / (2. * M_PI); + if (std::abs(x) <= float(M_PI)) + return x; + float n = std::round(x * o2pi); + return x - n * float(2. * M_PI); +} + +void PFTkEGAlgo::link_emCalo2emCalo(const std::vector& emcalo, + std::vector &emCalo2emCalo) { + // FIXME: needs configuration + bool filterHwQuality_ = true; + int caloHwQual_ = 4; + float dEtaMaxBrem_ = 0.02; + float dPhiMaxBrem_ = 0.1; + // NOTE: we assume the input to be sorted!!! + for (int ic = 0, nc = emcalo.size(); ic < nc; ++ic) { + auto &calo = emcalo[ic]; + if (filterHwQuality_ && calo.hwFlags != caloHwQual_) + continue; + + if (emCalo2emCalo[ic] != -1) + continue; + + for (int jc = ic + 1; jc < nc; ++jc) { + if (emCalo2emCalo[jc] != -1) + continue; + + auto &otherCalo = emcalo[jc]; + if (filterHwQuality_ && otherCalo.hwFlags != caloHwQual_) + continue; + + if (fabs(otherCalo.floatEta() - calo.floatEta()) < dEtaMaxBrem_ && + fabs(deltaPhi(otherCalo.floatPhi(), calo.floatPhi())) < dPhiMaxBrem_) { + emCalo2emCalo[jc] = ic; + } + } + } +} + + + +void PFTkEGAlgo::link_emCalo2tk(const std::vector &emcalo, + const std::vector &track, + std::vector &emCalo2tk) { + + + + + // FIXME: configuration + int caloHwQual_ = 4; + float dEtaMax = 0.0174533; // FIXME: should be 0.01 but it is too small give eta precision. We use 0.0174533 hwEta: 4 + float dPhiMax = 0.07; + bool filterHwQuality_ = true; + int debug_ = 1; + float trkQualityPtMin_ = 10.; + if (debug_ > 10) + std::cout << "[link_emCalo2tk]" << std::endl; + + for (int ic = 0, nc = emcalo.size(); ic < nc; ++ic) { + auto &calo = emcalo[ic]; + + if (filterHwQuality_ && calo.hwFlags != caloHwQual_) + continue; + + if (debug_ > 10) { + std::cout << "[REF] EM calo [" << ic << "] hwFlags: " << calo.hwFlags << std::endl; + std::cout << "--- calo: pt: " << calo.floatPt() << " eta: " << calo.floatEta() << " phi: " << calo.floatPhi() + << std::endl; + } + + float dPtMin = 999; + for (int itk = 0, ntk = track.size(); itk < ntk; ++itk) { + const auto &tk = track[itk]; + if (tk.floatPt() < trkQualityPtMin_) + continue; + + if (debug_ > 10) { + std::cout << "[REF] tk [" << itk << "] tk: pt: " << tk.floatPt() << " eta: " << tk.floatEta() << " phi: " << tk.floatPhi() << " z0: " << tk.hwZ0 + << std::endl; + } + + float d_phi = deltaPhi(tk.floatPhi(), calo.floatPhi()); + float d_eta = tk.floatEta() - calo.floatEta(); // We only use it squared + + // if (debug_ > 0) + // std::cout << " deta: " << fabs(d_eta) << " dphi: " << d_phi + // << " ell: " << ((d_phi / dPhiMax) * (d_phi / dPhiMax)) + ((d_eta / dEtaMax) * (d_eta / dEtaMax)) + // << std::endl; + // std::cout << "Global abs eta: " << r.globalAbsEta(calo.floatEta()) + // << " abs eta: " << fabs(calo.floatEta()) << std::endl; + + if ((((d_phi / dPhiMax) * (d_phi / dPhiMax)) + ((d_eta / dEtaMax) * (d_eta / dEtaMax))) < 1.) { + if (debug_ > 0) { + if (debug_ <= 10){ + std::cout << "[REF] EM calo [" << ic << "] hwFlags: " << calo.hwFlags << std::endl; + std::cout << "--- calo: pt: " << calo.floatPt() << " eta: " << calo.floatEta() << " phi: " << calo.floatPhi() + << std::endl; + std::cout << "[REF] tk [" << itk << " tk: pt: " << tk.floatPt() << " eta: " << tk.floatEta() << " phi: " << tk.floatPhi() << " z0: " << tk.hwZ0 + << std::endl; + } + std::cout << " pass elliptic " << std::endl; + } + // NOTE: for now we implement only best pt match. This is NOT what is done in the L1TkElectronTrackProducer + if (fabs(tk.floatPt() - calo.floatPt()) < dPtMin) { + if (debug_ > 0) + std::cout << " best pt match: " << fabs(tk.floatPt() - calo.floatPt()) << std::endl; + emCalo2tk[ic] = itk; + dPtMin = fabs(tk.floatPt() - calo.floatPt()); + } + } + } + } +} + + + + + +void PFTkEGAlgo::pftkegalgo_ref_set_debug(int debug) { g_pftkegalgo_debug_ref_ = debug; } + +bool PFTkEGAlgo::hwpt_sort(const l1tpf_impl::CaloCluster &i, const l1tpf_impl::CaloCluster &j) { + return (i.hwPt > j.hwPt); +} + + +void PFTkEGAlgo::sel_emCalo_ref(const EmCaloObj emcalo[/*cfg.nCALO*/], + EmCaloObj emcalo_sel_ref[/*cfg.nCALO*/]) { + + + std::vector emcalos(NEMCALO); + for(int ic = 0; ic < NEMCALO; ic++) { + // if (emcalo[i].hwPt == 0) continue; + l1tpf_impl::CaloCluster c; + fw2dpf::convert(emcalo[ic], c); + // if(emcalo[ic].hwPt != 0) + // std::cout << "[" << ic << "] EmCaloObj pt: " << emcalo[ic].hwPt << " CaloCluster pt: " << c.hwPt << std::endl; + emcalos.push_back(c); + } + std::sort(emcalos.begin(), emcalos.end(), hwpt_sort); + + for(int ic = 0; ic < NEMCALOSEL_EGIN; ic++) { + clear(emcalo_sel_ref[ic]); + } + + int jc = 0; + for(int ic = 0; ic < NEMCALO; ic++) { + if(emcalos[ic].hwFlags == 4) { + // std::cout << "[" << ic << "] EmCaloObj pt: " << emcalos[ic].hwPt << " hwflags: " << emcalos[ic].hwFlags << std::endl; + dpf2fw::convert(emcalos[ic], emcalo_sel_ref[jc++]); + if(jc == NEMCALOSEL_EGIN) break; + } + } +} + + + +void PFTkEGAlgo::pftkegalgo_ref(const pftkegalgo_config &cfg, + const EmCaloObj emcalo[/*cfg.nCALO*/], + const TkObj track[/*cfg.nTRACK*/], + int emCalo2tk_ref[], + int emCalo2emcalo_ref[], + EGIsoParticle egphs_ref[], + EGIsoEleParticle egele_ref[]) { + + // printf("[pftkegalgo_ref]\n"); + + bool doBremRecovery_ = true; + // if (g_pftkegalgo_debug_ref_) { + // #ifdef L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_MORE + PFTkEGAlgo::Region reg; + + // std::vector tracks; + // std::vector emcalos; + + + for (unsigned int i = 0; i < cfg.nTRACK; ++i) { if (track[i].hwPt == 0) continue; + l1tpf_impl::PropagatedTrack tk; fw2dpf::convert(track[i], tk); + // printf("FW \t track %3d: pt %8d [ %7.2f ] calo eta %+7d [ %+5.2f ] calo phi %+7d [ %+5.2f ] calo ptErr %6d [ %7.2f ] tight %d\n", + // i, tk.hwPt, tk.floatPt(), tk.hwEta, tk.floatEta(), tk.hwPhi, tk.floatPhi(), tk.hwCaloPtErr, tk.floatCaloPtErr(), int(track[i].hwTightQuality)); + reg.track.push_back(tk); + } + for (unsigned int i = 0; i < cfg.nEMCALO; ++i) { if (emcalo[i].hwPt == 0) continue; + l1tpf_impl::CaloCluster c; fw2dpf::convert(emcalo[i], c); + // printf("FW \t EM calo %3d: pt %8d [ %7.2f ] calo eta %+7d [ %+5.2f ] calo phi %+7d [ %+5.2f ] calo emPt %7d [ %7.2f ] isEM %d \n", + // i, c.hwPt, c.floatPt(), c.hwEta, c.floatEta(), c.hwPhi, c.floatPhi(), c.hwEmPt, c.floatEmPt(), c.isEM); + reg.emcalo.push_back(c); + } + + // printf("# tracks: %3d # emcalos: %3d\n", tracks.size(), emcalos.size()); + + + std::vector emCalo2emCalo(reg.emcalo.size(), -1); + if (doBremRecovery_) + link_emCalo2emCalo(reg.emcalo, emCalo2emCalo); + // convert to array + for(int id = 0; id < cfg.nEMCALO && id < emCalo2emCalo.size(); id++) { + emCalo2emcalo_ref[id] = emCalo2emCalo[id]; + } + + + std::vector emCalo2tk(reg.emcalo.size(), -1); + link_emCalo2tk(reg.emcalo, reg.track, emCalo2tk); + + // convert to array + for(int id = 0; id < cfg.nEMCALO && id < emCalo2tk.size(); id++) { + emCalo2tk_ref[id] = emCalo2tk[id]; + } + + + eg_algo(reg, emCalo2emCalo, emCalo2tk); + + // std::cout << "# EG photons: " << reg.egphotons.size() << " # eles: " << reg.egeles.size() << std::endl; + + // initialize and fill the output arrays + for(int ic = 0; ic != cfg.nEM_EGOUT; ++ic) { + clear(egphs_ref[ic]); + clear(egele_ref[ic]); + } + + for(int ic = 0; ic != reg.egphotons.size(); ++ic) { + egphs_ref[ic] = reg.egphotons[ic]; + } + for(int ic = 0; ic != reg.egeles.size(); ++ic) { + egele_ref[ic] = reg.egeles[ic]; + } + +} + + +void PFTkEGAlgo::eg_algo(Region &r, + const std::vector &emCalo2emCalo, + const std::vector &emCalo2tk) { + + bool filterHwQuality_ = true; + int caloHwQual_ = 4; + bool doBremRecovery_ = true; + + for (int ic = 0, nc = r.emcalo.size(); ic < nc; ++ic) { + auto &calo = r.emcalo[ic]; + if (filterHwQuality_ && calo.hwFlags != caloHwQual_) + continue; + + int itk = emCalo2tk[ic]; + + + // check if brem recovery is on + if (!doBremRecovery_) { + // 1. create EG objects before brem recovery + addEgObjsToPF(r, ic, calo.hwFlags, calo.hwPt, itk); + continue; + } + + // check if the cluster has already been used in a brem reclustering + if (emCalo2emCalo[ic] != -1) + continue; + + int ptBremReco = calo.hwPt; + + for (int jc = ic; jc < nc; ++jc) { + if (emCalo2emCalo[jc] == ic) { + auto &otherCalo = r.emcalo[jc]; + ptBremReco += otherCalo.hwPt; + } + } + + // 2. create EG objects with brem recovery + // FIXME: duplicating the object is suboptimal but this is done for keeping things as in TDR code... + addEgObjsToPF(r, ic, calo.hwFlags + 1, ptBremReco, itk); + } +} + +EGIsoParticle &PFTkEGAlgo::addEGIsoToPF(std::vector &egobjs, + const l1tpf_impl::CaloCluster &calo, + const int hwQual, + const int ptCorr) { + EGIsoParticle egiso; + egiso.hwPt = ptCorr; + egiso.hwEta = calo.hwEta; + egiso.hwPhi = calo.hwPhi; + // egiso.hwQual = hwQual; + // egiso.hwIso = 0; + egobjs.push_back(egiso); + return egobjs.back(); +} + +EGIsoEleParticle &PFTkEGAlgo::addEGIsoEleToPF(std::vector &egobjs, + const l1tpf_impl::CaloCluster &calo, + const l1tpf_impl::PropagatedTrack &track, + const int hwQual, + const int ptCorr) { + EGIsoEleParticle egiso; + egiso.hwPt = ptCorr; + egiso.hwEta = calo.hwEta; + egiso.hwPhi = calo.hwPhi; + + // egiso.hwVtxEta = track.hwVtxEta; + // egiso.hwVtxPhi = track.hwVtxPhi; + egiso.hwZ0 = track.hwZ0; + // egiso.hwCharge = track.hwCharge; + + // egiso.hwQual = hwQual; + // egiso.hwIso = 0; + egobjs.push_back(egiso); + return egobjs.back(); +} + +void PFTkEGAlgo::addEgObjsToPF( + Region &r, const int calo_idx, const int hwQual, const int ptCorr, const int tk_idx) { + EGIsoParticle &egobj = addEGIsoToPF(r.egphotons, r.emcalo[calo_idx], r.emcalo[calo_idx].hwFlags + 1, ptCorr); + if (tk_idx != -1) { + // egobj.ele_idx = r.egeles.size(); + addEGIsoEleToPF(r.egeles, r.emcalo[calo_idx], r.track[tk_idx], r.emcalo[calo_idx].hwFlags + 1, ptCorr); + } +} diff --git a/ref/pftkegalgo_ref.h b/ref/pftkegalgo_ref.h new file mode 100644 index 0000000..21587a3 --- /dev/null +++ b/ref/pftkegalgo_ref.h @@ -0,0 +1,75 @@ +#ifndef PFTKEGALGO_REF_H +#define PFTKEGALGO_REF_H +#ifndef CMSSW_GIT_HASH + #include "../DiscretePFInputs.h" +#else + #include "../../interface/DiscretePFInputs.h" +#endif + +#include "../firmware/pfalgo2hgc.h" +#include "pfalgo_common_ref.h" + + + +namespace PFTkEGAlgo { + + struct pftkegalgo_config { + unsigned int nTRACK; + unsigned int nEMCALO; + unsigned int nEMCALOSEL_EGIN; + unsigned int nEM_EGOUT; + + pftkegalgo_config(unsigned int nTrack, unsigned int nEmCalo, unsigned int nEmCaloSel_in, unsigned int nEmOut) : + nTRACK(nTrack), nEMCALO(nEmCalo), nEMCALOSEL_EGIN(nEmCaloSel_in), nEM_EGOUT(nEmOut) {} + }; + + struct Region { + std::vector emcalo; + std::vector track; + std::vector egphotons; + std::vector egeles; + }; + + void pftkegalgo_ref_set_debug(int debug) ; + + void pftkegalgo_ref(const pftkegalgo_config &cfg, + const EmCaloObj emcalo[/*cfg.nCALO*/], + const TkObj track[/*cfg.nTRACK*/], + int emCalo2tk_ref[], + int emCalo2emcalo_ref[], + EGIsoParticle egphs_ref[], + EGIsoEleParticle egele_ref[]) ; + + void link_emCalo2emCalo(const std::vector& emcalo, + std::vector &emCalo2emCalo); + + void link_emCalo2tk(const std::vector &emcalo, + const std::vector &track, + std::vector &emCalo2tk); + + float deltaPhi(float phi1, float phi2); + + bool hwpt_sort(const l1tpf_impl::CaloCluster &i, const l1tpf_impl::CaloCluster &j); + + void sel_emCalo_ref(const EmCaloObj emcalo[/*cfg.nCALO*/], + EmCaloObj emcalo_sel_ref[/*cfg.nCALO*/]); + + void eg_algo(Region &r, + const std::vector &emCalo2emCalo, + const std::vector &emCalo2tk); + + EGIsoParticle &addEGIsoToPF(std::vector &egobjs, + const l1tpf_impl::CaloCluster &calo, + const int hwQual, + const int ptCorr); + + EGIsoEleParticle &addEGIsoEleToPF(std::vector &egobjs, + const l1tpf_impl::CaloCluster &calo, + const l1tpf_impl::PropagatedTrack &track, + const int hwQual, + const int ptCorr); + + void addEgObjsToPF(Region &r, const int calo_idx, const int hwQual, const int ptCorr, const int tk_idx); +} + +#endif diff --git a/run_hls_ptkegalgo.tcl b/run_hls_ptkegalgo.tcl new file mode 100644 index 0000000..bc81096 --- /dev/null +++ b/run_hls_ptkegalgo.tcl @@ -0,0 +1,38 @@ +# get the configuration +#source config_hls_fullpfalgo_mp7.tcl +set pfBoard "none" +#set pfBoard "VCU118" +set pfReg "HGCal" +set cflags "-std=c++0x -DREG_${pfReg} -DBOARD_${pfBoard}" + +# open the project, don't forget to reset +open_project -reset "proj_tkeg${pfReg}_${pfBoard}" + + +if { $pfBoard == "none" } { + set_top pftkegalgo +} else { + set_top packed_pftkegalgo +} +add_files firmware/pftkegalgo.cpp -cflags "${cflags}" +add_files -tb pftkegalgo_test.cpp -cflags "${cflags}" +add_files -tb ref/pftkegalgo_ref.cpp -cflags "${cflags}" +add_files -tb ref/pfalgo_common_ref.cpp -cflags "${cflags}" +add_files -tb utils/pattern_serializer.cpp -cflags "${cflags}" +add_files -tb utils/test_utils.cpp -cflags "${cflags}" +add_files -tb data/TTbar_PU200_HGCal.dump + +# reset the solution +open_solution -reset "solution" +set_part {xcvu9p-flga2104-2L-e} +create_clock -period 3.0 -name default + +config_interface -trim_dangling_port +# do stuff +csim_design +csynth_design +cosim_design -trace_level all +#export_design -format ip_catalog -vendor "cern-cms" -version ${l1pfIPVersion} -description "${l1pfTopFunc}" + +# exit Vivado HLS +exit diff --git a/utils/DiscretePF2Firmware.h b/utils/DiscretePF2Firmware.h index a438a03..f075fe9 100644 --- a/utils/DiscretePF2Firmware.h +++ b/utils/DiscretePF2Firmware.h @@ -36,6 +36,7 @@ namespace dpf2fw { out.hwPtErr = in.hwPtErr; out.hwEta = in.hwEta; out.hwPhi = in.hwPhi; + out.hwFlags = in.hwFlags; } inline void convert(const l1tpf_impl::Muon & in, MuObj & out) { out.hwPt = in.hwPt; diff --git a/utils/Firmware2DiscretePF.h b/utils/Firmware2DiscretePF.h index caf9815..9fe6071 100644 --- a/utils/Firmware2DiscretePF.h +++ b/utils/Firmware2DiscretePF.h @@ -128,6 +128,7 @@ namespace fw2dpf { out.hwPtErr = in.hwPtErr; out.hwEta = in.hwEta; out.hwPhi = in.hwPhi; + out.hwFlags = in.hwFlags; out.src = nullptr; } inline void convert(const MuObj & in, l1tpf_impl::Muon & out) { From 12c721665e4ad27f38390b8dea7b7a46464a6113 Mon Sep 17 00:00:00 2001 From: cerminar Date: Thu, 21 Jan 2021 12:23:32 +0100 Subject: [PATCH 2/7] correct namespace for abs functions --- firmware/pftkegalgo.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/firmware/pftkegalgo.cpp b/firmware/pftkegalgo.cpp index 7244205..d2c1bdf 100644 --- a/firmware/pftkegalgo.cpp +++ b/firmware/pftkegalgo.cpp @@ -1,6 +1,6 @@ #include "pftkegalgo.h" #include - +#include "hls_math.h" #include "pfalgo_common.icc" ap_int ell_dpt_int_cap(eta_t eta1, phi_t phi1, eta_t eta2, phi_t phi2, pt_t pt1, pt_t pt2, ap_int max) { @@ -13,8 +13,9 @@ ap_int ell_dpt_int_cap(eta_t eta1, phi_t phi1, eta_t eta2, phi_t ap_int d_phi = (phi1-phi2); int ell = d_phi*d_phi + d_eta*d_eta*cdeta; + // FIXME: should be ap_uint ? - ap_int d_pt = abs(pt1 - pt2); + ap_int d_pt = hls::abs(pt1 - pt2); return (ell <= int(cm)) ? d_pt : max; } @@ -57,8 +58,8 @@ void link_emCalo2emCalo(const EmCaloObj emcalo[NEMCALOSEL_EGIN], ap_uint Date: Thu, 21 Jan 2021 12:24:24 +0100 Subject: [PATCH 3/7] bugfix in ref algo --- ref/pftkegalgo_ref.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ref/pftkegalgo_ref.cpp b/ref/pftkegalgo_ref.cpp index b6b1541..597eaf2 100644 --- a/ref/pftkegalgo_ref.cpp +++ b/ref/pftkegalgo_ref.cpp @@ -330,9 +330,9 @@ EGIsoEleParticle &PFTkEGAlgo::addEGIsoEleToPF(std::vector &ego void PFTkEGAlgo::addEgObjsToPF( Region &r, const int calo_idx, const int hwQual, const int ptCorr, const int tk_idx) { - EGIsoParticle &egobj = addEGIsoToPF(r.egphotons, r.emcalo[calo_idx], r.emcalo[calo_idx].hwFlags + 1, ptCorr); + EGIsoParticle &egobj = addEGIsoToPF(r.egphotons, r.emcalo[calo_idx], hwQual, ptCorr); if (tk_idx != -1) { // egobj.ele_idx = r.egeles.size(); - addEGIsoEleToPF(r.egeles, r.emcalo[calo_idx], r.track[tk_idx], r.emcalo[calo_idx].hwFlags + 1, ptCorr); + addEGIsoEleToPF(r.egeles, r.emcalo[calo_idx], r.track[tk_idx], hwQual, ptCorr); } } From dd8092e955802aa89ed7e19af1d3c3303111239d Mon Sep 17 00:00:00 2001 From: cerminar Date: Tue, 26 Jan 2021 10:15:38 +0100 Subject: [PATCH 4/7] Improve configurability to cope with barrel implementation + cosmetics --- firmware/data.h | 5 ++ firmware/pftkegalgo.cpp | 50 ++++++++++------- firmware/pftkegalgo.h | 12 ---- pftkegalgo_test.cpp | 11 ++-- ref/pftkegalgo_ref.cpp | 47 +++++----------- ref/pftkegalgo_ref.h | 118 ++++++++++++++++++++++++++-------------- run_hls_ptkegalgo.tcl | 5 +- 7 files changed, 134 insertions(+), 114 deletions(-) diff --git a/firmware/data.h b/firmware/data.h index f2d0671..249affe 100644 --- a/firmware/data.h +++ b/firmware/data.h @@ -108,6 +108,11 @@ enum PID { PID_Charged=0, PID_Neutral=1, PID_Photon=2, PID_Electron=3, PID_Muon= #define NSELCALO 10 #define NALLNEUTRALS (NPHOTON+NSELCALO) #define NNEUTRALS 25 + // EG configuration + #define NEMCALOSEL_EGIN 10 + // #define DOBREMRECOVERY + #define NEM_EGOUT 10 + #endif #endif // region diff --git a/firmware/pftkegalgo.cpp b/firmware/pftkegalgo.cpp index d2c1bdf..e43e870 100644 --- a/firmware/pftkegalgo.cpp +++ b/firmware/pftkegalgo.cpp @@ -48,7 +48,6 @@ void link_emCalo2emCalo(const EmCaloObj emcalo[NEMCALOSEL_EGIN], ap_uint dEtaMaxBrem_ = 5; // 0.02; -> round(0.02*4*180/3.14) const ap_int dPhiMaxBrem_ = 23; // 0.1; -> round(0.1*4*180/3.14) @@ -90,44 +89,54 @@ void link_emCalo2tk(const EmCaloObj emcalo[NEMCALOSEL_EGIN], } +#if defined(REG_HGCal) +void sel_emCalo(const EmCaloObj emcalo[NEMCALO], EmCaloObj emcalo_sel[NEMCALOSEL_EGIN]) { + #pragma HLS INLINE + + EmCaloObj emcalo_sel_temp[NEMCALO]; + #pragma HLS ARRAY_PARTITION variable=emcalo_sel complete dim=1 + #pragma HLS ARRAY_PARTITION variable=emcalo_sel_temp complete dim=1 + EmCaloObj emcalo_zero; + clear(emcalo_zero); + in_select_loop: for(int ic = 0; ic < NEMCALO; ++ic) { + emcalo_sel_temp[ic] = (emcalo[ic].hwFlags == 4) ? emcalo[ic] : emcalo_zero; + } + ptsort_hwopt(emcalo_sel_temp, emcalo_sel); +} +#endif + +#if defined(REG_Barrel) +// NOTE: for now this is a placeholder more than anything else void sel_emCalo(const EmCaloObj emcalo[NEMCALO], EmCaloObj emcalo_sel[NEMCALOSEL_EGIN]) { #pragma HLS INLINE - EmCaloObj emcalo_selt[NEMCALO]; + EmCaloObj emcalo_sel_temp[NEMCALO]; #pragma HLS ARRAY_PARTITION variable=emcalo_sel complete dim=1 - #pragma HLS ARRAY_PARTITION variable=emcalo_selt complete dim=1 + #pragma HLS ARRAY_PARTITION variable=emcalo_sel_temp complete dim=1 EmCaloObj emcalo_zero; clear(emcalo_zero); in_select_loop: for(int ic = 0; ic < NEMCALO; ++ic) { - emcalo_selt[ic] = (emcalo[ic].hwFlags == SELHWQUAL) ? emcalo[ic] : emcalo_zero; + // we require pt>2GeV + emcalo_sel_temp[ic] = (emcalo[ic].hwPt > 8) ? emcalo[ic] : emcalo_zero; } - ptsort_hwopt(emcalo_selt, emcalo_sel); + ptsort_hwopt(emcalo_sel_temp, emcalo_sel); } +#endif + void pftkegalgo(const EmCaloObj emcalo[NCALO], const TkObj track[NTRACK], - // ap_uint emCalo2tk_bit[NEMCALOSEL_EGIN], ap_uint emCalo2emcalo_bit[NEMCALOSEL_EGIN], EGIsoParticle photons[NEM_EGOUT], EGIsoEleParticle eles[NEM_EGOUT]) { - #pragma HLS PIPELINE II=1 + #pragma HLS PIPELINE II=HLS_pipeline_II #pragma HLS ARRAY_PARTITION variable=emcalo complete dim=1 #pragma HLS ARRAY_PARTITION variable=track complete dim=1 #pragma HLS ARRAY_PARTITION variable=photons complete dim=1 #pragma HLS ARRAY_PARTITION variable=eles complete dim=1 - // FIXME: filter out qualities which are not useful for later processing (eg quality !=4 in HGC) - // EmCaloObj emcalo_sel[NEMCALOSEL_EGIN]; EmCaloObj emcalo_sel[NEMCALOSEL_EGIN]; - EmCaloObj emcalo_selt[NEMCALO]; - #pragma HLS ARRAY_PARTITION variable=emcalo_sel complete dim=1 - #pragma HLS ARRAY_PARTITION variable=emcalo_selt complete dim=1 - EmCaloObj emcalo_zero; - clear(emcalo_zero); - in_select_loop: for(int ic = 0; ic < NEMCALO; ++ic) { - emcalo_selt[ic] = (emcalo[ic].hwFlags == SELHWQUAL) ? emcalo[ic] : emcalo_zero; - } - ptsort_hwopt(emcalo_selt, emcalo_sel); + sel_emCalo(emcalo, emcalo_sel); // FIXME: shall we forseen the same selection step for tracks? ap_uint emCalo2tk_bit[NEMCALOSEL_EGIN]; @@ -182,9 +191,8 @@ void pftkegalgo(const EmCaloObj emcalo[NCALO], const TkObj track[NTRACK], eles_temp[ic].hwPt = ptcorr; eles_temp[ic].hwEta = emcalo_sel[ic].hwEta; eles_temp[ic].hwPhi = emcalo_sel[ic].hwPhi; - // FIXME: add track properties @ vertex using - eles_temp[ic].hwZ0 = track[track_id].hwZ0; - //track[it] + // FIXME: add track properties @ vertex using track[track_id] + eles_temp[ic].hwZ0 = track[track_id].hwZ0; } else { clear(eles_temp[ic]); } diff --git a/firmware/pftkegalgo.h b/firmware/pftkegalgo.h index 7928105..429de4e 100644 --- a/firmware/pftkegalgo.h +++ b/firmware/pftkegalgo.h @@ -1,18 +1,6 @@ #ifndef FIRMWARE_PFTKEGALGO_H #define FIRMWARE_PFTKEGALGO_H -// FIXME: move to data.h -// FIXME: tune on the basis of the region occupancy -// FIXME: this needs to go somewhere else -#define SELHWQUAL 4 - -#ifndef REG_HGCal - - #ifndef CMSSW_GIT_HASH - #warning "REG_HGCal is not #defined, but this algorithm has only been tested there" - #endif -#endif - #include "pfalgo_common.h" #include "data.h" diff --git a/pftkegalgo_test.cpp b/pftkegalgo_test.cpp index 10ebe16..e0b2b97 100644 --- a/pftkegalgo_test.cpp +++ b/pftkegalgo_test.cpp @@ -43,8 +43,9 @@ int main() { PFNeutralObj outne[NSELCALO], outne_ref[NSELCALO]; PFChargedObj outmupf[NMU], outmupf_ref[NMU]; - PFTkEGAlgo::pftkegalgo_config cfg(NTRACK, NEMCALO, NEMCALOSEL_EGIN, NEM_EGOUT); - + pFTkEGAlgo::pftkegalgo_config cfg(NTRACK, NEMCALO, NEMCALOSEL_EGIN, NEM_EGOUT, true, true); + + pFTkEGAlgo::PFTkEGAlgo algo(cfg); // ----------------------------------------- // run multiple tests int passed_tests = 0; @@ -67,7 +68,7 @@ int main() { EmCaloObj emcalo_sel[NEMCALOSEL_EGIN]; EmCaloObj emcalo_sel_ref[NEMCALOSEL_EGIN]; sel_emCalo(emcalo, emcalo_sel); - PFTkEGAlgo::sel_emCalo_ref(emcalo, emcalo_sel_ref); + algo.sel_emCalo_ref(emcalo, emcalo_sel_ref); // FIXME: determine output depth @@ -87,7 +88,7 @@ int main() { // pftkegalgo(emcalo, track); EGIsoParticle egphs_ref[NEM_EGOUT]; EGIsoEleParticle egele_ref[NEM_EGOUT]; - PFTkEGAlgo::pftkegalgo_ref(cfg, emcalo_sel_ref, track, emCalo2tk_ref, emCalo2emcalo_ref, egphs_ref, egele_ref); + algo.pftkegalgo_ref(cfg, emcalo_sel_ref, track, emCalo2tk_ref, emCalo2emcalo_ref, egphs_ref, egele_ref); ap_uint emCalo2tk_bit[NEMCALOSEL_EGIN]; ap_uint emCalo2emcalo_bit[NEMCALOSEL_EGIN]; @@ -151,8 +152,6 @@ int main() { errors++; std::cout << "[" << it << "] REF ele pt: " << egele_ref[it].hwPt << " FW ele pt: " << egele[it].hwPt << std::endl; std::cout << " REF ele Z0: " << egele_ref[it].hwZ0 << " FW ele z0: " << egele[it].hwZ0 << std::endl; - - } } } diff --git a/ref/pftkegalgo_ref.cpp b/ref/pftkegalgo_ref.cpp index 597eaf2..aa6ee30 100644 --- a/ref/pftkegalgo_ref.cpp +++ b/ref/pftkegalgo_ref.cpp @@ -14,11 +14,9 @@ int g_pftkegalgo_debug_ref_ = 0; -using namespace PFTkEGAlgo; -// void PFTkEGAlgo::initRegion(Region &r) const { -// // FIXME: assume imput is sorted already -// r.egobjs.clear(); -// } +using namespace pFTkEGAlgo; + + float PFTkEGAlgo::deltaPhi(float phi1, float phi2) { // reduce to [-pi,pi] float x = phi1 - phi2; @@ -31,11 +29,6 @@ float PFTkEGAlgo::deltaPhi(float phi1, float phi2) { void PFTkEGAlgo::link_emCalo2emCalo(const std::vector& emcalo, std::vector &emCalo2emCalo) { - // FIXME: needs configuration - bool filterHwQuality_ = true; - int caloHwQual_ = 4; - float dEtaMaxBrem_ = 0.02; - float dPhiMaxBrem_ = 0.1; // NOTE: we assume the input to be sorted!!! for (int ic = 0, nc = emcalo.size(); ic < nc; ++ic) { auto &calo = emcalo[ic]; @@ -67,16 +60,6 @@ void PFTkEGAlgo::link_emCalo2tk(const std::vector &emca const std::vector &track, std::vector &emCalo2tk) { - - - - // FIXME: configuration - int caloHwQual_ = 4; - float dEtaMax = 0.0174533; // FIXME: should be 0.01 but it is too small give eta precision. We use 0.0174533 hwEta: 4 - float dPhiMax = 0.07; - bool filterHwQuality_ = true; - int debug_ = 1; - float trkQualityPtMin_ = 10.; if (debug_ > 10) std::cout << "[link_emCalo2tk]" << std::endl; @@ -106,6 +89,14 @@ void PFTkEGAlgo::link_emCalo2tk(const std::vector &emca float d_phi = deltaPhi(tk.floatPhi(), calo.floatPhi()); float d_eta = tk.floatEta() - calo.floatEta(); // We only use it squared + auto eta_index = + std::distance( + absEtaBoundaries_.begin(), + std::lower_bound(absEtaBoundaries_.begin(), absEtaBoundaries_.end(), r.globalAbsEta(calo.floatEta()))) - + 1; + float dEtaMax = dEtaValues_[eta_index]; + float dPhiMax = dPhiValues_[eta_index]; + // if (debug_ > 0) // std::cout << " deta: " << fabs(d_eta) << " dphi: " << d_phi // << " ell: " << ((d_phi / dPhiMax) * (d_phi / dPhiMax)) + ((d_eta / dEtaMax) * (d_eta / dEtaMax)) @@ -140,9 +131,9 @@ void PFTkEGAlgo::link_emCalo2tk(const std::vector &emca -void PFTkEGAlgo::pftkegalgo_ref_set_debug(int debug) { g_pftkegalgo_debug_ref_ = debug; } +// void PFTkEGAlgo::pftkegalgo_ref_set_debug(int debug) { g_pftkegalgo_debug_ref_ = debug; } -bool PFTkEGAlgo::hwpt_sort(const l1tpf_impl::CaloCluster &i, const l1tpf_impl::CaloCluster &j) { +bool pFTkEGAlgo::hwpt_sort(const l1tpf_impl::CaloCluster &i, const l1tpf_impl::CaloCluster &j) { return (i.hwPt > j.hwPt); } @@ -187,15 +178,9 @@ void PFTkEGAlgo::pftkegalgo_ref(const pftkegalgo_config &cfg, EGIsoEleParticle egele_ref[]) { // printf("[pftkegalgo_ref]\n"); - - bool doBremRecovery_ = true; // if (g_pftkegalgo_debug_ref_) { // #ifdef L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_MORE - PFTkEGAlgo::Region reg; - - // std::vector tracks; - // std::vector emcalos; - + pFTkEGAlgo::Region reg; for (unsigned int i = 0; i < cfg.nTRACK; ++i) { if (track[i].hwPt == 0) continue; l1tpf_impl::PropagatedTrack tk; fw2dpf::convert(track[i], tk); @@ -255,10 +240,6 @@ void PFTkEGAlgo::eg_algo(Region &r, const std::vector &emCalo2emCalo, const std::vector &emCalo2tk) { - bool filterHwQuality_ = true; - int caloHwQual_ = 4; - bool doBremRecovery_ = true; - for (int ic = 0, nc = r.emcalo.size(); ic < nc; ++ic) { auto &calo = r.emcalo[ic]; if (filterHwQuality_ && calo.hwFlags != caloHwQual_) diff --git a/ref/pftkegalgo_ref.h b/ref/pftkegalgo_ref.h index 21587a3..02c9743 100644 --- a/ref/pftkegalgo_ref.h +++ b/ref/pftkegalgo_ref.h @@ -11,7 +11,7 @@ -namespace PFTkEGAlgo { +namespace pFTkEGAlgo { struct pftkegalgo_config { unsigned int nTRACK; @@ -19,8 +19,21 @@ namespace PFTkEGAlgo { unsigned int nEMCALOSEL_EGIN; unsigned int nEM_EGOUT; - pftkegalgo_config(unsigned int nTrack, unsigned int nEmCalo, unsigned int nEmCaloSel_in, unsigned int nEmOut) : - nTRACK(nTrack), nEMCALO(nEmCalo), nEMCALOSEL_EGIN(nEmCaloSel_in), nEM_EGOUT(nEmOut) {} + bool filterHwQuality; + bool doBremRecovery; + + pftkegalgo_config(unsigned int nTrack, + unsigned int nEmCalo, + unsigned int nEmCaloSel_in, + unsigned int nEmOut, + bool filterHwQuality, + bool doBremRecovery) : + nTRACK(nTrack), + nEMCALO(nEmCalo), + nEMCALOSEL_EGIN(nEmCaloSel_in), + nEM_EGOUT(nEmOut), + filterHwQuality(filterHwQuality), + doBremRecovery(doBremRecovery) {} }; struct Region { @@ -30,46 +43,71 @@ namespace PFTkEGAlgo { std::vector egeles; }; - void pftkegalgo_ref_set_debug(int debug) ; - - void pftkegalgo_ref(const pftkegalgo_config &cfg, - const EmCaloObj emcalo[/*cfg.nCALO*/], - const TkObj track[/*cfg.nTRACK*/], - int emCalo2tk_ref[], - int emCalo2emcalo_ref[], - EGIsoParticle egphs_ref[], - EGIsoEleParticle egele_ref[]) ; - - void link_emCalo2emCalo(const std::vector& emcalo, - std::vector &emCalo2emCalo); - - void link_emCalo2tk(const std::vector &emcalo, - const std::vector &track, - std::vector &emCalo2tk); - - float deltaPhi(float phi1, float phi2); + // void pftkegalgo_ref_set_debug(int debug) ; bool hwpt_sort(const l1tpf_impl::CaloCluster &i, const l1tpf_impl::CaloCluster &j); - void sel_emCalo_ref(const EmCaloObj emcalo[/*cfg.nCALO*/], - EmCaloObj emcalo_sel_ref[/*cfg.nCALO*/]); - - void eg_algo(Region &r, - const std::vector &emCalo2emCalo, - const std::vector &emCalo2tk); - - EGIsoParticle &addEGIsoToPF(std::vector &egobjs, - const l1tpf_impl::CaloCluster &calo, - const int hwQual, - const int ptCorr); - - EGIsoEleParticle &addEGIsoEleToPF(std::vector &egobjs, - const l1tpf_impl::CaloCluster &calo, - const l1tpf_impl::PropagatedTrack &track, - const int hwQual, - const int ptCorr); - - void addEgObjsToPF(Region &r, const int calo_idx, const int hwQual, const int ptCorr, const int tk_idx); + class PFTkEGAlgo { + public: + + PFTkEGAlgo(const pftkegalgo_config& config) : + cfg(config), + filterHwQuality_(config.filterHwQuality), + doBremRecovery_(config.doBremRecovery) {} + + void pftkegalgo_ref(const pftkegalgo_config &cfg, + const EmCaloObj emcalo[/*cfg.nCALO*/], + const TkObj track[/*cfg.nTRACK*/], + int emCalo2tk_ref[], + int emCalo2emcalo_ref[], + EGIsoParticle egphs_ref[], + EGIsoEleParticle egele_ref[]) ; + + void link_emCalo2emCalo(const std::vector& emcalo, + std::vector &emCalo2emCalo); + + void link_emCalo2tk(const std::vector &emcalo, + const std::vector &track, + std::vector &emCalo2tk); + + float deltaPhi(float phi1, float phi2); + + + void sel_emCalo_ref(const EmCaloObj emcalo[/*cfg.nCALO*/], + EmCaloObj emcalo_sel_ref[/*cfg.nCALO*/]); + + void eg_algo(Region &r, + const std::vector &emCalo2emCalo, + const std::vector &emCalo2tk); + + EGIsoParticle &addEGIsoToPF(std::vector &egobjs, + const l1tpf_impl::CaloCluster &calo, + const int hwQual, + const int ptCorr); + + EGIsoEleParticle &addEGIsoEleToPF(std::vector &egobjs, + const l1tpf_impl::CaloCluster &calo, + const l1tpf_impl::PropagatedTrack &track, + const int hwQual, + const int ptCorr); + + void addEgObjsToPF(Region &r, const int calo_idx, const int hwQual, const int ptCorr, const int tk_idx); + private: + + pftkegalgo_config cfg; + bool debug_ = 1; + bool filterHwQuality_; + bool doBremRecovery_; + + int caloHwQual_ = 4; + float dEtaMaxBrem_ = 0.02; + float dPhiMaxBrem_ = 0.1; + std::vector absEtaBoundaries_{0.0, 0.9, 1.5}; + // FIXME: should be {0.025, 0.015, 0.01} but 0.01 it is too small give eta precision. We use 0.0174533 hwEta: 4 + std::vector dEtaValues_{0.025, 0.015, 0.0174533}; + std::vector dPhiValues_{0.07, 0.07, 0.07}; + float trkQualityPtMin_ = 10; + }; } #endif diff --git a/run_hls_ptkegalgo.tcl b/run_hls_ptkegalgo.tcl index bc81096..d8dfd77 100644 --- a/run_hls_ptkegalgo.tcl +++ b/run_hls_ptkegalgo.tcl @@ -3,7 +3,7 @@ set pfBoard "none" #set pfBoard "VCU118" set pfReg "HGCal" -set cflags "-std=c++0x -DREG_${pfReg} -DBOARD_${pfBoard}" +set cflags "-std=c++0x -DREG_${pfReg} -DBOARD_${pfBoard} -DHLS_pipeline_II=4" # open the project, don't forget to reset open_project -reset "proj_tkeg${pfReg}_${pfBoard}" @@ -20,7 +20,8 @@ add_files -tb ref/pftkegalgo_ref.cpp -cflags "${cflags}" add_files -tb ref/pfalgo_common_ref.cpp -cflags "${cflags}" add_files -tb utils/pattern_serializer.cpp -cflags "${cflags}" add_files -tb utils/test_utils.cpp -cflags "${cflags}" -add_files -tb data/TTbar_PU200_HGCal.dump +#add_files -tb data/TTbar_PU200_HGCal.dump +add_files -tb data/DoubleElectron_PU200_HGCal.dump # reset the solution open_solution -reset "solution" From e13fe217885aba1f53758046b7e9919bd276c4b5 Mon Sep 17 00:00:00 2001 From: cerminar Date: Thu, 28 Jan 2021 09:41:45 +0100 Subject: [PATCH 5/7] Handle barrel and endcap configurations --- firmware/pftkegalgo.cpp | 34 +++++++++++++++++++++++------ pftkegalgo_test.cpp | 25 +++++++++++++++++----- ref/pftkegalgo_ref.cpp | 5 +++-- ref/pftkegalgo_ref.h | 28 +++++++++++++++++++++--- run_hls_ptkegalgo_barrel.tcl | 39 ++++++++++++++++++++++++++++++++++ utils/DiscretePFInputsReader.h | 3 ++- 6 files changed, 117 insertions(+), 17 deletions(-) create mode 100644 run_hls_ptkegalgo_barrel.tcl diff --git a/firmware/pftkegalgo.cpp b/firmware/pftkegalgo.cpp index e43e870..6434cc8 100644 --- a/firmware/pftkegalgo.cpp +++ b/firmware/pftkegalgo.cpp @@ -5,15 +5,38 @@ ap_int ell_dpt_int_cap(eta_t eta1, phi_t phi1, eta_t eta2, phi_t phi2, pt_t pt1, pt_t pt2, ap_int max) { #pragma HLS INLINE - // FIXME: this should be configurable - const ap_uint<10> cdeta = 16; + +#if defined(REG_HGCal) + // const ap_uint<10> cdeta_int = 16; + const ap_ufixed<12,10> cdeta = 16; +#endif + +#if defined(REG_Barrel) + // const ap_uint<10> cdeta_int = (hls::abs(eta1) > 3) ? 22 : 8; + // //FIXME: global absolute eta > 0.9 + // const ap_ufixed<10,12> cdeta = (hls::abs(eta1) > 3) ? 21.75 : 7.75; + // const ap_uint<10> cdeta = 22; + const ap_ufixed<12,10> cdeta = 21.75; +#endif + const ap_uint<10> cm = 256; + // const ap_uint<10> cm_int = 256; + ap_int d_eta = (eta1-eta2); ap_int d_phi = (phi1-phi2); - int ell = d_phi*d_phi + d_eta*d_eta*cdeta; - + // ap_uint<22> ell = d_phi*d_phi + d_eta*d_eta*cdeta; + ap_uint<22> ell = d_phi*d_phi + d_eta*d_eta*cdeta; + // int ell_int = d_phi*d_phi + d_eta*d_eta*cdeta_int; + // int pippo = d_eta*d_eta*cdeta; + // int pippo2 = d_eta*d_eta*cdeta_int; + + // std::cout << "cdeta: " << cdeta < ? ap_int d_pt = hls::abs(pt1 - pt2); return (ell <= int(cm)) ? d_pt : max; @@ -23,10 +46,9 @@ ap_int ell_dpt_int_cap(eta_t eta1, phi_t phi1, eta_t eta2, phi_t template void calo2tk_ellipticdptvals(const EmCaloObj &em, const TkObj track[NTRACK], ap_int calo_track_dptval[NTRACK]) { -#pragma HLS INLINE +// #pragma HLS INLINE // ap_int ? // FIXME: uint - // FIXME: some of this should be configurable const ap_int eDPTMAX = DPTMAX; const pt_t trkQualityPtMin_ = 40; // 10 GeV diff --git a/pftkegalgo_test.cpp b/pftkegalgo_test.cpp index e0b2b97..a0a7f6d 100644 --- a/pftkegalgo_test.cpp +++ b/pftkegalgo_test.cpp @@ -31,19 +31,30 @@ bool compare(const EGIsoParticle&ele1, const EGIsoParticle&ele2) { int main() { HumanReadablePatternSerializer debugHR("-", /*zerosuppress=*/true); // this will print on stdout, we'll use it for errors +#if defined(REG_HGCal) +std::cout << "REG_Hgcal" << std::endl; DiscretePFInputsReader inputs("DoubleElectron_PU200_HGCal.dump"); - + bool filterHwQuality = true; + bool doBremRecovery = true; +#endif + +#if defined(REG_Barrel) +std::cout << "REG_Barrel" << std::endl; + DiscretePFInputsReader inputs("DoubleElectron_PU200_Barrel.dump"); + bool filterHwQuality = false; + bool doBremRecovery = false; +#endif // input TP objects HadCaloObj calo[NCALO]; EmCaloObj emcalo[NEMCALO]; TkObj track[NTRACK]; z0_t hwZPV; MuObj mu[NMU]; - + float reg_eta_center; // output PF objects PFChargedObj outch[NTRACK], outch_ref[NTRACK]; PFNeutralObj outne[NSELCALO], outne_ref[NSELCALO]; PFChargedObj outmupf[NMU], outmupf_ref[NMU]; - pFTkEGAlgo::pftkegalgo_config cfg(NTRACK, NEMCALO, NEMCALOSEL_EGIN, NEM_EGOUT, true, true); + pFTkEGAlgo::pftkegalgo_config cfg(NTRACK, NEMCALO, NEMCALOSEL_EGIN, NEM_EGOUT, filterHwQuality, doBremRecovery); pFTkEGAlgo::PFTkEGAlgo algo(cfg); // ----------------------------------------- @@ -55,7 +66,7 @@ int main() { for (int test = 1; test <= NTEST; ++test) { // std::cout << "------------ TEST: " << test << std::endl; // get the inputs from the input object - if (!inputs.nextRegion(calo, emcalo, track, mu, hwZPV)) break; + if (!inputs.nextRegion(calo, emcalo, track, mu, hwZPV, reg_eta_center)) break; // for(auto region: inputs.event().regions) { // printf("# of EM objects: %u\n", region.emcalo.size()); @@ -63,7 +74,8 @@ int main() { // printf(" - hwFlags: %u\n", emc.hwFlags); // } // } - + algo.setRegionEtaCenter(reg_eta_center); + std::cout<< "Region eta center: " << reg_eta_center << std::endl; // 0 - input cluster selection EmCaloObj emcalo_sel[NEMCALOSEL_EGIN]; EmCaloObj emcalo_sel_ref[NEMCALOSEL_EGIN]; @@ -100,7 +112,10 @@ int main() { emCalo2emcalo_bit[i] = 0; } + #ifndef REG_Barrel link_emCalo2emCalo(emcalo_sel, emCalo2emcalo_bit); + #endif + link_emCalo2tk(emcalo_sel, track, emCalo2tk_bit); pftkegalgo(emcalo, track, egphs, egele) ; diff --git a/ref/pftkegalgo_ref.cpp b/ref/pftkegalgo_ref.cpp index aa6ee30..253bee9 100644 --- a/ref/pftkegalgo_ref.cpp +++ b/ref/pftkegalgo_ref.cpp @@ -92,11 +92,12 @@ void PFTkEGAlgo::link_emCalo2tk(const std::vector &emca auto eta_index = std::distance( absEtaBoundaries_.begin(), - std::lower_bound(absEtaBoundaries_.begin(), absEtaBoundaries_.end(), r.globalAbsEta(calo.floatEta()))) - + std::lower_bound(absEtaBoundaries_.begin(), absEtaBoundaries_.end(), globalAbsEta(calo.floatEta()))) - 1; float dEtaMax = dEtaValues_[eta_index]; float dPhiMax = dPhiValues_[eta_index]; - + + std::cout << "eta: " << calo.floatEta() << " globa eta: " << globalAbsEta(calo.floatEta()) << " deta_max: " << dEtaMax << " dphimax: " << dPhiMax << std::endl; // if (debug_ > 0) // std::cout << " deta: " << fabs(d_eta) << " dphi: " << d_phi // << " ell: " << ((d_phi / dPhiMax) * (d_phi / dPhiMax)) + ((d_eta / dEtaMax) * (d_eta / dEtaMax)) diff --git a/ref/pftkegalgo_ref.h b/ref/pftkegalgo_ref.h index 02c9743..c5e78e8 100644 --- a/ref/pftkegalgo_ref.h +++ b/ref/pftkegalgo_ref.h @@ -47,6 +47,8 @@ namespace pFTkEGAlgo { bool hwpt_sort(const l1tpf_impl::CaloCluster &i, const l1tpf_impl::CaloCluster &j); + + class PFTkEGAlgo { public: @@ -92,8 +94,21 @@ namespace pFTkEGAlgo { const int ptCorr); void addEgObjsToPF(Region &r, const int calo_idx, const int hwQual, const int ptCorr, const int tk_idx); + + //FIXME: this is hugly but we will soon change the interface + void setRegionEtaCenter(float etacenter) { + reg_eta_center_ = etacenter; + } + private: + + float globalAbsEta(float localEta) { + return std::abs(localEta + reg_eta_center_); + } + + + pftkegalgo_config cfg; bool debug_ = 1; bool filterHwQuality_; @@ -102,11 +117,18 @@ namespace pFTkEGAlgo { int caloHwQual_ = 4; float dEtaMaxBrem_ = 0.02; float dPhiMaxBrem_ = 0.1; - std::vector absEtaBoundaries_{0.0, 0.9, 1.5}; + // FIXME: need region center in FW, we don't have it for now hence we keep 1 value for the barrel + // std::vector absEtaBoundaries_{0.0, 0.9, 1.5}; + // // FIXME: should be {0.025, 0.015, 0.01} but 0.01 it is too small give eta precision. We use 0.0174533 hwEta: 4 + // std::vector dEtaValues_{0.025, 0.015, 0.0174533}; + // std::vector dPhiValues_{0.07, 0.07, 0.07}; + std::vector absEtaBoundaries_{0.0, 1.5}; // FIXME: should be {0.025, 0.015, 0.01} but 0.01 it is too small give eta precision. We use 0.0174533 hwEta: 4 - std::vector dEtaValues_{0.025, 0.015, 0.0174533}; - std::vector dPhiValues_{0.07, 0.07, 0.07}; + std::vector dEtaValues_{0.015, 0.0174533}; + std::vector dPhiValues_{0.07, 0.07}; + float trkQualityPtMin_ = 10; + float reg_eta_center_; }; } diff --git a/run_hls_ptkegalgo_barrel.tcl b/run_hls_ptkegalgo_barrel.tcl new file mode 100644 index 0000000..155f807 --- /dev/null +++ b/run_hls_ptkegalgo_barrel.tcl @@ -0,0 +1,39 @@ +# get the configuration +#source config_hls_fullpfalgo_mp7.tcl +set pfBoard "none" +#set pfBoard "VCU118" +set pfReg "Barrel" +set cflags "-std=c++0x -DREG_${pfReg} -DBOARD_${pfBoard} -DHLS_pipeline_II=2" + +# open the project, don't forget to reset +open_project -reset "proj_tkeg${pfReg}_${pfBoard}" + + +if { $pfBoard == "none" } { + set_top pftkegalgo +} else { + set_top packed_pftkegalgo +} +add_files firmware/pftkegalgo.cpp -cflags "${cflags}" +add_files -tb pftkegalgo_test.cpp -cflags "${cflags}" +add_files -tb ref/pftkegalgo_ref.cpp -cflags "${cflags}" +add_files -tb ref/pfalgo_common_ref.cpp -cflags "${cflags}" +add_files -tb utils/pattern_serializer.cpp -cflags "${cflags}" +add_files -tb utils/test_utils.cpp -cflags "${cflags}" +#add_files -tb data/TTbar_PU200_HGCal.dump +add_files -tb data/DoubleElectron_PU200_Barrel.dump + +# reset the solution +open_solution -reset "solution" +set_part {xcvu9p-flga2104-2L-e} +create_clock -period 3.0 -name default + +config_interface -trim_dangling_port +# do stuff +csim_design +csynth_design +cosim_design -trace_level all +#export_design -format ip_catalog -vendor "cern-cms" -version ${l1pfIPVersion} -description "${l1pfTopFunc}" + +# exit Vivado HLS +exit diff --git a/utils/DiscretePFInputsReader.h b/utils/DiscretePFInputsReader.h index 963d591..23456f5 100644 --- a/utils/DiscretePFInputsReader.h +++ b/utils/DiscretePFInputsReader.h @@ -48,7 +48,7 @@ class DiscretePFInputsReader { } ~DiscretePFInputsReader() { fclose(file_); } // for region-by-region approach - bool nextRegion(HadCaloObj calo[NCALO], EmCaloObj emcalo[NEMCALO], TkObj track[NTRACK], MuObj mu[NMU], z0_t & hwZPV) { + bool nextRegion(HadCaloObj calo[NCALO], EmCaloObj emcalo[NEMCALO], TkObj track[NTRACK], MuObj mu[NMU], z0_t & hwZPV, float ®_eta_center) { if (!nextRegion()) return false; const Region &r = event_.regions[iregion_]; @@ -56,6 +56,7 @@ class DiscretePFInputsReader { dpf2fw::convert(r.calo, calo); dpf2fw::convert(r.emcalo, emcalo); dpf2fw::convert(r.muon, mu); + reg_eta_center = r.etaCenter; #ifdef __GXX_EXPERIMENTAL_CXX0X__ hwZPV = event_.z0 * l1tpf_impl::InputTrack::Z0_SCALE; From 9cfd32e31cc06095c84d8be7f28238e9c8259706 Mon Sep 17 00:00:00 2001 From: cerminar Date: Thu, 28 Jan 2021 10:21:41 +0100 Subject: [PATCH 6/7] Change handling of Pipeline II --- firmware/pftkegalgo.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/firmware/pftkegalgo.cpp b/firmware/pftkegalgo.cpp index 6434cc8..343b88d 100644 --- a/firmware/pftkegalgo.cpp +++ b/firmware/pftkegalgo.cpp @@ -150,7 +150,22 @@ void sel_emCalo(const EmCaloObj emcalo[NEMCALO], EmCaloObj emcalo_sel[NEMCALOSEL void pftkegalgo(const EmCaloObj emcalo[NCALO], const TkObj track[NTRACK], EGIsoParticle photons[NEM_EGOUT], EGIsoEleParticle eles[NEM_EGOUT]) { - #pragma HLS PIPELINE II=HLS_pipeline_II + #ifdef HLS_pipeline_II + #if HLS_pipeline_II == 1 + #pragma HLS pipeline II=1 + #elif HLS_pipeline_II == 2 + #pragma HLS pipeline II=2 + #elif HLS_pipeline_II == 3 + #pragma HLS pipeline II=3 + #elif HLS_pipeline_II == 4 + #pragma HLS pipeline II=4 + #elif HLS_pipeline_II == 6 + #pragma HLS pipeline II=6 + #endif + #else + #pragma HLS pipeline II=2 + #endif + // #pragma HLS PIPELINE II=HLS_pipeline_II #pragma HLS ARRAY_PARTITION variable=emcalo complete dim=1 #pragma HLS ARRAY_PARTITION variable=track complete dim=1 From 6a832cae234e66672bfef3238b97c1b99b08b31c Mon Sep 17 00:00:00 2001 From: cerminar Date: Thu, 28 Jan 2021 10:37:08 +0100 Subject: [PATCH 7/7] try inlining more --- firmware/pfalgo_common.icc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/pfalgo_common.icc b/firmware/pfalgo_common.icc index 00b1611..c906c84 100644 --- a/firmware/pfalgo_common.icc +++ b/firmware/pfalgo_common.icc @@ -60,6 +60,7 @@ ap_uint dr2_plus_dpt_int_cap(int dr2, pt_t pt1, pt_t pt2, PTS_t ptscale, ap_ template void ptsort_hwopt(const T in[NIn], T out[NOut]) { + #pragma HLS INLINE T tmp[NOut]; #pragma HLS ARRAY_PARTITION variable=tmp complete @@ -218,6 +219,7 @@ struct picker_of_closest { template ap_uint pick_closest(const DR_T calo_track_drval[NCA]) { + #pragma HLS INLINE const DR_T eDR2MAX = DR2MAX; typedef match::value>> match_t; match_t candidates[NCA]; @@ -355,5 +357,3 @@ void pfmualgo(const MuObj mu[NMU], const TkObj track[NTRACK], const ap_uint } } } - -