diff --git a/DataFormats/L1TCorrelator/interface/TkElectron.h b/DataFormats/L1TCorrelator/interface/TkElectron.h index 9f1ac1eaeeff0..c5b70d79598fb 100644 --- a/DataFormats/L1TCorrelator/interface/TkElectron.h +++ b/DataFormats/L1TCorrelator/interface/TkElectron.h @@ -39,16 +39,18 @@ namespace l1t { float trkzVtx() const { return trkzVtx_; } double trackCurvature() const { return trackCurvature_; } - + float idScore() const { return idScore_; } // ---------- member functions --------------------------- void setTrkzVtx(float TrkzVtx) { trkzVtx_ = TrkzVtx; } void setTrackCurvature(double trackCurvature) { trackCurvature_ = trackCurvature; } + void setIdScore(float score) { idScore_ = score; } private: edm::Ptr trkPtr_; float trkzVtx_; double trackCurvature_; + float idScore_; }; } // namespace l1t #endif diff --git a/DataFormats/L1TCorrelator/src/classes_def.xml b/DataFormats/L1TCorrelator/src/classes_def.xml index 0685c6bc1356e..723849343a5a9 100644 --- a/DataFormats/L1TCorrelator/src/classes_def.xml +++ b/DataFormats/L1TCorrelator/src/classes_def.xml @@ -44,7 +44,9 @@ - + + + diff --git a/DataFormats/L1TParticleFlow/interface/PFCandidate.h b/DataFormats/L1TParticleFlow/interface/PFCandidate.h index c6d52246a6fa5..567eb6f80b7fb 100644 --- a/DataFormats/L1TParticleFlow/interface/PFCandidate.h +++ b/DataFormats/L1TParticleFlow/interface/PFCandidate.h @@ -48,9 +48,13 @@ namespace l1t { void setZ0(float z0) { setVertex(reco::Particle::Point(0, 0, z0)); } void setDxy(float dxy) { dxy_ = dxy; } + void setCaloEta(float caloeta) { caloEta_ = caloeta; } + void setCaloPhi(float calophi) { caloPhi_ = calophi; } float z0() const { return vz(); } float dxy() const { return dxy_; } + float caloEta() const { return caloEta_; } + float caloPhi() const { return caloPhi_; } int16_t hwZ0() const { return hwZ0_; } int16_t hwDxy() const { return hwDxy_; } @@ -70,7 +74,7 @@ namespace l1t { PFClusterRef clusterRef_; PFTrackRef trackRef_; MuonRef muonRef_; - float dxy_, puppiWeight_; + float dxy_, puppiWeight_, caloEta_, caloPhi_; int16_t hwZ0_, hwDxy_; uint16_t hwTkQuality_, hwPuppiWeight_, hwEmID_; diff --git a/DataFormats/L1TParticleFlow/interface/PFCluster.h b/DataFormats/L1TParticleFlow/interface/PFCluster.h index 1851746b51d19..2272ccbe353db 100644 --- a/DataFormats/L1TParticleFlow/interface/PFCluster.h +++ b/DataFormats/L1TParticleFlow/interface/PFCluster.h @@ -22,10 +22,14 @@ namespace l1t { float ptError = 0, int hwpt = 0, int hweta = 0, - int hwphi = 0) + int hwphi = 0, + float absZBarycenter = 0., + float sigmaRR = 0.) : L1Candidate(PolarLorentzVector(pt, eta, phi, 0), hwpt, hweta, hwphi, /*hwQuality=*/isEM ? 1 : 0), hOverE_(hOverE), - ptError_(ptError) { + ptError_(ptError), + absZBarycenter_(absZBarycenter), + sigmaRR_(sigmaRR) { setPdgId(isEM ? 22 : 130); // photon : non-photon(K0) } PFCluster( @@ -37,6 +41,12 @@ namespace l1t { float hOverE() const { return hOverE_; } void setHOverE(float hOverE) { hOverE_ = hOverE; } + void setSigmaRR(float sigmaRR) { sigmaRR_ = sigmaRR; } + float absZBarycenter() const { return absZBarycenter_; } + + void setAbsZBarycenter(float absZBarycenter) { absZBarycenter_ = absZBarycenter; } + float sigmaRR() const { return sigmaRR_; } + float emEt() const { if (hOverE_ == -1) return 0; @@ -68,6 +78,9 @@ namespace l1t { private: float hOverE_, ptError_, egVsPionMVAOut_, egVsPUMVAOut_; + // HGC dedicated quantities (0ed by default) + float absZBarycenter_, sigmaRR_; + ConstituentsAndFractions constituents_; }; diff --git a/DataFormats/L1TParticleFlow/interface/bit_encoding.h b/DataFormats/L1TParticleFlow/interface/bit_encoding.h index 9aa7446e75962..695594179d573 100644 --- a/DataFormats/L1TParticleFlow/interface/bit_encoding.h +++ b/DataFormats/L1TParticleFlow/interface/bit_encoding.h @@ -58,4 +58,34 @@ inline void l1pf_pattern_unpack(const ap_uint data[], T objs[N]) { } } +template +inline void l1pf_pattern_pack_slim(const T objs[N], ap_uint data[]) { +#ifdef __SYNTHESIS__ +#pragma HLS inline +#pragma HLS inline region recursive +#endif + assert(T::BITWIDTH_SLIM <= NB); + for (unsigned int i = 0; i < N; ++i) { +#ifdef __SYNTHESIS__ +#pragma HLS unroll +#endif + data[i + OFFS] = objs[i].pack_slim(); + } +} + +template +inline void l1pf_pattern_unpack_slim(const ap_uint data[], T objs[N]) { +#ifdef __SYNTHESIS__ +#pragma HLS inline +#pragma HLS inline region recursive +#endif + assert(T::BITWIDTH_SLIM <= NB); + for (unsigned int i = 0; i < N; ++i) { +#ifdef __SYNTHESIS__ +#pragma HLS unroll +#endif + objs[i] = T::unpack(data[i + OFFS]); + } +} + #endif diff --git a/DataFormats/L1TParticleFlow/interface/datatypes.h b/DataFormats/L1TParticleFlow/interface/datatypes.h index f56e7b36c2495..be802bc540b6e 100644 --- a/DataFormats/L1TParticleFlow/interface/datatypes.h +++ b/DataFormats/L1TParticleFlow/interface/datatypes.h @@ -39,6 +39,12 @@ namespace l1ct { typedef ap_uint<10> em2calo_dr_t; typedef ap_uint<13> tk2calo_dq_t; typedef ap_uint<4> egquality_t; + typedef ap_uint<3> stub_t; + typedef ap_ufixed<10, 1, AP_TRN, AP_SAT> srrtot_t; + typedef ap_uint<8> meanz_t; // mean - MEANZ_OFFSET(= 320 cm) + typedef ap_ufixed<10, 5, AP_TRN, AP_SAT> hoe_t; + typedef ap_uint<4> redChi2Bin_t; + // FIXME: adjust range 10-11bits -> 1/4 - 1/2TeV is probably more than enough for all reasonable use cases typedef ap_ufixed<11, 9, AP_TRN, AP_SAT> iso_t; @@ -149,6 +155,11 @@ namespace l1ct { constexpr float Z0_LSB = 0.05; constexpr float DXY_LSB = 0.05; constexpr float PUPPIW_LSB = 1.0 / 256; + constexpr float MEANZ_OFFSET = 320.; + constexpr float SRRTOT_LSB = 0.0019531250; // pow(2, -9) + constexpr unsigned int SRRTOT_SCALE = 64; // pow(2, 6) + constexpr float HOE_LSB = 0.031250000; // pow(2, -5) + inline float floatPt(pt_t pt) { return pt.to_float(); } inline float floatPt(dpt_t pt) { return pt.to_float(); } inline float floatPt(pt2_t pt2) { return pt2.to_float(); } @@ -164,6 +175,9 @@ namespace l1ct { inline float floatDxy(dxy_t dxy) { return dxy.to_float() * DXY_LSB; } inline float floatPuppiW(puppiWgt_t puppiw) { return puppiw.to_float() * PUPPIW_LSB; } 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 pt_t makePt(int pt) { return ap_ufixed<16, 14>(pt) >> 2; } inline dpt_t makeDPt(int dpt) { return ap_fixed<18, 16>(dpt) >> 2; } @@ -194,6 +208,9 @@ namespace l1ct { inline iso_t makeIso(float iso) { return iso_t(0.25 * round(iso * 4)); } inline int makeDR2FromFloatDR(float dr) { return ceil(dr * dr / ETAPHI_LSB / ETAPHI_LSB); } + inline srrtot_t makeSrrTot(float var) { return srrtot_t(SRRTOT_LSB * round(var * SRRTOT_SCALE / SRRTOT_LSB)); }; + inline meanz_t makeMeanZ(float var) { return round(var - MEANZ_OFFSET); }; + inline hoe_t makeHoe(float var) { return hoe_t(HOE_LSB * round(var / HOE_LSB)); }; inline float maxAbsEta() { return ((1 << (eta_t::width - 1)) - 1) * ETAPHI_LSB; } inline float maxAbsPhi() { return ((1 << (phi_t::width - 1)) - 1) * ETAPHI_LSB; } diff --git a/DataFormats/L1TParticleFlow/interface/layer1_emulator.h b/DataFormats/L1TParticleFlow/interface/layer1_emulator.h index a257ed2efbda6..fcb415d426017 100644 --- a/DataFormats/L1TParticleFlow/interface/layer1_emulator.h +++ b/DataFormats/L1TParticleFlow/interface/layer1_emulator.h @@ -39,7 +39,7 @@ namespace l1ct { }; struct TkObjEmu : public TkObj { - uint16_t hwChi2, hwStubs; + uint16_t hwChi2; float simPt, simCaloEta, simCaloPhi, simVtxEta, simVtxPhi, simZ0, simD0; const l1t::PFTrack *src; bool read(std::fstream &from); @@ -48,7 +48,6 @@ namespace l1ct { TkObj::clear(); src = nullptr; hwChi2 = 0; - hwStubs = 0; simPt = 0; simCaloEta = 0; simCaloPhi = 0; @@ -196,6 +195,7 @@ namespace l1ct { const l1t::PFTrack *srcTrack; // we use an index to the standalone object needed to retrieve a Ref when putting int sta_idx; + float idScore; bool read(std::fstream &from); bool write(std::fstream &to) const; void clear() { @@ -203,6 +203,7 @@ namespace l1ct { srcCluster = nullptr; srcTrack = nullptr; sta_idx = -1; + idScore = -999; clearIsoVars(); } @@ -334,7 +335,7 @@ namespace l1ct { }; struct Event { - enum { VERSION = 11 }; + enum { VERSION = 12 }; uint32_t run, lumi; uint64_t event; RawInputs raw; diff --git a/DataFormats/L1TParticleFlow/interface/layer1_objs.h b/DataFormats/L1TParticleFlow/interface/layer1_objs.h index 83765fc4b2b10..48af69b993de1 100644 --- a/DataFormats/L1TParticleFlow/interface/layer1_objs.h +++ b/DataFormats/L1TParticleFlow/interface/layer1_objs.h @@ -12,10 +12,13 @@ namespace l1ct { phi_t hwPhi; // relative to the region center, at calo pt_t hwEmPt; emid_t hwEmID; + srrtot_t hwSrrTot; + meanz_t hwMeanZ; + hoe_t hwHoe; inline bool operator==(const HadCaloObj &other) const { return hwPt == other.hwPt && hwEta == other.hwEta && hwPhi == other.hwPhi && hwEmPt == other.hwEmPt && - hwEmID == other.hwEmID; + hwEmID == other.hwEmID && hwSrrTot == other.hwSrrTot && hwMeanZ == other.hwMeanZ && hwHoe == other.hwHoe; } inline bool operator>(const HadCaloObj &other) const { return hwPt > other.hwPt; } @@ -27,6 +30,9 @@ namespace l1ct { hwPhi = 0; hwEmPt = 0; hwEmID = 0; + hwSrrTot = 0; + hwMeanZ = 0; + hwHoe = 0; } int intPt() const { return Scales::intPt(hwPt); } @@ -37,10 +43,16 @@ namespace l1ct { float floatEmPt() const { return Scales::floatPt(hwEmPt); } float floatEta() const { return Scales::floatEta(hwEta); } float floatPhi() const { return Scales::floatPhi(hwPhi); } + float floatSrrTot() const { return Scales::floatSrrTot(hwSrrTot); }; + float floatMeanZ() const { return Scales::floatMeanZ(hwMeanZ); }; + float floatHoe() const { return Scales::floatHoe(hwHoe); }; bool hwIsEM() const { return hwEmID != 0; } - static const int BITWIDTH = pt_t::width + eta_t::width + phi_t::width + pt_t::width + emid_t::width; + static const int BITWIDTH_SLIM = pt_t::width + eta_t::width + phi_t::width + pt_t::width + emid_t::width; + + static const int BITWIDTH = BITWIDTH_SLIM + srrtot_t::width + meanz_t::width + hoe_t::width; + inline ap_uint pack() const { ap_uint ret; unsigned int start = 0; @@ -49,8 +61,12 @@ namespace l1ct { pack_into_bits(ret, start, hwPhi); pack_into_bits(ret, start, hwEmPt); pack_into_bits(ret, start, hwEmID); + pack_into_bits(ret, start, hwSrrTot); + pack_into_bits(ret, start, hwMeanZ); + pack_into_bits(ret, start, hwHoe); return ret; } + inline static HadCaloObj unpack(const ap_uint &src) { HadCaloObj ret; unsigned int start = 0; @@ -59,8 +75,13 @@ namespace l1ct { unpack_from_bits(src, start, ret.hwPhi); unpack_from_bits(src, start, ret.hwEmPt); unpack_from_bits(src, start, ret.hwEmID); + unpack_from_bits(src, start, ret.hwSrrTot); + unpack_from_bits(src, start, ret.hwMeanZ); + unpack_from_bits(src, start, ret.hwHoe); return ret; } + + inline ap_uint pack_slim() const { return pack()(BITWIDTH_SLIM - 1, 0); } }; inline void clear(HadCaloObj &c) { c.clear(); } @@ -70,10 +91,13 @@ namespace l1ct { eta_t hwEta; // relative to the region center, at calo phi_t hwPhi; // relative to the region center, at calo emid_t hwEmID; + srrtot_t hwSrrTot; + meanz_t hwMeanZ; + hoe_t hwHoe; inline bool operator==(const EmCaloObj &other) const { return hwPt == other.hwPt && hwEta == other.hwEta && hwPhi == other.hwPhi && hwPtErr == other.hwPtErr && - hwEmID == other.hwEmID; + hwEmID == other.hwEmID && hwSrrTot == other.hwSrrTot && hwMeanZ == other.hwMeanZ && hwHoe == other.hwHoe; } inline bool operator>(const EmCaloObj &other) const { return hwPt > other.hwPt; } @@ -85,6 +109,9 @@ namespace l1ct { hwEta = 0; hwPhi = 0; hwEmID = 0; + hwSrrTot = 0; + hwMeanZ = 0; + hwHoe = 0; } int intPt() const { return Scales::intPt(hwPt); } @@ -95,8 +122,14 @@ namespace l1ct { float floatPtErr() const { return Scales::floatPt(hwPtErr); } float floatEta() const { return Scales::floatEta(hwEta); } float floatPhi() const { return Scales::floatPhi(hwPhi); } + float floatSrrTot() const { return Scales::floatSrrTot(hwSrrTot); }; + float floatMeanZ() const { return Scales::floatMeanZ(hwMeanZ); }; + float floatHoe() const { return Scales::floatHoe(hwHoe); }; + + static const int BITWIDTH_SLIM = pt_t::width + eta_t::width + phi_t::width + pt_t::width + emid_t::width; + + static const int BITWIDTH = BITWIDTH_SLIM + srrtot_t::width + meanz_t::width + hoe_t::width; - static const int BITWIDTH = pt_t::width + eta_t::width + phi_t::width + pt_t::width + emid_t::width; inline ap_uint pack() const { ap_uint ret; unsigned int start = 0; @@ -105,6 +138,9 @@ namespace l1ct { pack_into_bits(ret, start, hwPhi); pack_into_bits(ret, start, hwPtErr); pack_into_bits(ret, start, hwEmID); + pack_into_bits(ret, start, hwSrrTot); + pack_into_bits(ret, start, hwMeanZ); + pack_into_bits(ret, start, hwHoe); return ret; } inline static EmCaloObj unpack(const ap_uint &src) { @@ -115,8 +151,14 @@ namespace l1ct { unpack_from_bits(src, start, ret.hwPhi); unpack_from_bits(src, start, ret.hwPtErr); unpack_from_bits(src, start, ret.hwEmID); + unpack_from_bits(src, start, ret.hwSrrTot); + unpack_from_bits(src, start, ret.hwMeanZ); + unpack_from_bits(src, start, ret.hwHoe); + return ret; } + + inline ap_uint pack_slim() const { return pack()(BITWIDTH_SLIM - 1, 0); } }; inline void clear(EmCaloObj &c) { c.clear(); } @@ -130,6 +172,11 @@ namespace l1ct { z0_t hwZ0; dxy_t hwDxy; tkquality_t hwQuality; + stub_t hwStubs; + redChi2Bin_t hwRedChi2RZ; // 4 bits + redChi2Bin_t hwRedChi2RPhi; // 4 bits + //FIXME: 3 bits would be enough + redChi2Bin_t hwRedChi2Bend; // 4 bits enum TkQuality { PFLOOSE = 1, PFTIGHT = 2 }; bool isPFLoose() const { return hwQuality[0]; } @@ -140,7 +187,8 @@ namespace l1ct { inline bool operator==(const TkObj &other) const { return hwPt == other.hwPt && hwEta == other.hwEta && hwPhi == other.hwPhi && hwDEta == other.hwDEta && hwDPhi == other.hwDPhi && hwZ0 == other.hwZ0 && hwDxy == other.hwDxy && hwCharge == other.hwCharge && - hwQuality == other.hwQuality; + hwQuality == other.hwQuality && hwStubs == other.hwStubs && hwRedChi2RZ == other.hwRedChi2RZ && + hwRedChi2RPhi == other.hwRedChi2RPhi && hwRedChi2Bend == other.hwRedChi2Bend; } inline bool operator>(const TkObj &other) const { return hwPt > other.hwPt; } @@ -156,6 +204,10 @@ namespace l1ct { hwDxy = 0; hwCharge = false; hwQuality = 0; + hwStubs = 0; + hwRedChi2RZ = 0; + hwRedChi2RPhi = 0; + hwRedChi2Bend = 0; } int intPt() const { return Scales::intPt(hwPt); } @@ -174,8 +226,12 @@ namespace l1ct { float floatZ0() const { return Scales::floatZ0(hwZ0); } float floatDxy() const { return Scales::floatDxy(hwDxy); } - static const int BITWIDTH = pt_t::width + eta_t::width + phi_t::width + tkdeta_t::width + tkdphi_t::width + 1 + - z0_t::width + dxy_t::width + tkquality_t::width; + static const int BITWIDTH_SLIM = pt_t::width + eta_t::width + phi_t::width + tkdeta_t::width + tkdphi_t::width + 1 + + z0_t::width + dxy_t::width + tkquality_t::width; + + static const int BITWIDTH = + BITWIDTH_SLIM + stub_t::width + redChi2Bin_t::width + redChi2Bin_t::width + redChi2Bin_t::width; + inline ap_uint pack() const { ap_uint ret; unsigned int start = 0; @@ -188,6 +244,10 @@ namespace l1ct { pack_into_bits(ret, start, hwZ0); pack_into_bits(ret, start, hwDxy); pack_into_bits(ret, start, hwQuality); + pack_into_bits(ret, start, hwStubs); + pack_into_bits(ret, start, hwRedChi2RZ); + pack_into_bits(ret, start, hwRedChi2RPhi); + pack_into_bits(ret, start, hwRedChi2Bend); return ret; } inline static TkObj unpack(const ap_uint &src) { @@ -202,8 +262,13 @@ namespace l1ct { unpack_from_bits(src, start, ret.hwZ0); unpack_from_bits(src, start, ret.hwDxy); unpack_from_bits(src, start, ret.hwQuality); + unpack_from_bits(src, start, ret.hwStubs); + unpack_from_bits(src, start, ret.hwRedChi2RZ); + unpack_from_bits(src, start, ret.hwRedChi2RPhi); + unpack_from_bits(src, start, ret.hwRedChi2Bend); return ret; } + inline ap_uint pack_slim() const { return pack()(BITWIDTH_SLIM - 1, 0); } }; inline void clear(TkObj &c) { c.clear(); } diff --git a/DataFormats/L1TParticleFlow/src/PFCandidate.cc b/DataFormats/L1TParticleFlow/src/PFCandidate.cc index 964e55687ec86..36907c32df2ad 100644 --- a/DataFormats/L1TParticleFlow/src/PFCandidate.cc +++ b/DataFormats/L1TParticleFlow/src/PFCandidate.cc @@ -5,6 +5,8 @@ l1t::PFCandidate::PFCandidate( : L1Candidate(p, hwpt, hweta, hwphi, /*hwQuality=*/int(kind)), dxy_(0), puppiWeight_(puppiWeight), + caloEta_(0), + caloPhi_(0), hwZ0_(0), hwDxy_(0), hwTkQuality_(0), diff --git a/DataFormats/L1TParticleFlow/src/classes_def.xml b/DataFormats/L1TParticleFlow/src/classes_def.xml index 5f90ab44bb63d..c0ec668e42d2e 100644 --- a/DataFormats/L1TParticleFlow/src/classes_def.xml +++ b/DataFormats/L1TParticleFlow/src/classes_def.xml @@ -1,6 +1,7 @@ - + + @@ -19,7 +20,8 @@ - + + @@ -67,4 +69,3 @@ - diff --git a/DataFormats/L1TParticleFlow/src/layer1_emulator.cpp b/DataFormats/L1TParticleFlow/src/layer1_emulator.cpp index f0b56b1c25022..3f1284413bbf7 100644 --- a/DataFormats/L1TParticleFlow/src/layer1_emulator.cpp +++ b/DataFormats/L1TParticleFlow/src/layer1_emulator.cpp @@ -34,14 +34,14 @@ bool l1ct::EmCaloObjEmu::write(std::fstream& to) const { return writeObj(from, *this) && readVar(from, hwChi2) && readVar(from, hwStubs) && readVar(from, simPt) && - readVar(from, simCaloEta) && readVar(from, simCaloPhi) && readVar(from, simVtxEta) && - readVar(from, simVtxPhi) && readVar(from, simZ0) && readVar(from, simD0); + return readObj(from, *this) && readVar(from, hwChi2) && readVar(from, simPt) && readVar(from, simCaloEta) && + readVar(from, simCaloPhi) && readVar(from, simVtxEta) && readVar(from, simVtxPhi) && readVar(from, simZ0) && + readVar(from, simD0); } bool l1ct::TkObjEmu::write(std::fstream& to) const { - return writeObj(*this, to) && writeVar(hwChi2, to) && writeVar(hwStubs, to) && writeVar(simPt, to) && - writeVar(simCaloEta, to) && writeVar(simCaloPhi, to) && writeVar(simVtxEta, to) && writeVar(simVtxPhi, to) && - writeVar(simZ0, to) && writeVar(simD0, to); + return writeObj(*this, to) && writeVar(hwChi2, to) && writeVar(simPt, to) && writeVar(simCaloEta, to) && + writeVar(simCaloPhi, to) && writeVar(simVtxEta, to) && writeVar(simVtxPhi, to) && writeVar(simZ0, to) && + writeVar(simD0, to); } bool l1ct::MuObjEmu::read(std::fstream& from) { diff --git a/L1Trigger/Phase2L1ParticleFlow/data/compositeID.json b/L1Trigger/Phase2L1ParticleFlow/data/compositeID.json new file mode 100644 index 0000000000000..53b57c4329f2d --- /dev/null +++ b/L1Trigger/Phase2L1ParticleFlow/data/compositeID.json @@ -0,0 +1 @@ +{"max_depth": 4, "n_trees": 10, "n_classes": 2, "n_features": 11, "trees": [[{"feature": [1, 2, 0, 3, 0, 8, 2, 3, 5, 5, 1, 5, 2, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2], "threshold": [0.140625, 0.264648438, 11.4795256, 3.5, 16.6602802, 8.5, 0.245117188, -2.5, 0.0630929098, 0.585964918, 0.109375, 0.594282091, 0.252929688, 0.171875, 0.171875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "children_left": [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "children_right": [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "value": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.415820152, 0.556879818, 0.25938049, -0.557010412, -0.523303628, 0.309383601, 0.345235407, -0.177057937, -0.577262163, -0.463166773, -0.295891047, -0.521123528, 0.248503745, -0.140788257, -0.208826631, -0.495121777], "parent": [-1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14], "depth": [0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], "iLeaf": [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]}], [{"feature": [1, 1, 0, 4, 0, 8, 2, 8, 3, 8, 6, 0, 3, 5, 5, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2], "threshold": [0.140625, 0.109375, 12.9026089, -13.5, 15.8960209, 7.5, 0.256835938, 2.5, -2.5, 3.5, 19.5, 8.71144676, 2.5, 0.981220245, 1.01574898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "children_left": [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "children_right": [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "value": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.358234763, 0.404870719, -0.173584998, 0.459649861, -0.37743035, -0.0318962, 0.344911397, -0.540425003, -0.450546473, -0.387152672, -0.232723728, -0.485472769, 0.149142668, -0.281907678, -0.319123685, -0.469176918], "parent": [-1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14], "depth": [0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], "iLeaf": [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]}], [{"feature": [1, 2, 0, 0, 0, 8, 6, 1, 1, 0, 8, 5, 3, 2, 1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2], "threshold": [0.140625, 0.256835938, 9.48655319, 6.65358782, 30.484045, 9.5, 16.5, 0.109375, 0.109375, 11.8594818, 9.5, 0.701351345, -2.5, 0.260742188, 0.171875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "children_left": [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "children_right": [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "value": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.17315872, -0.212719589, 0.398817331, 0.243386999, -0.380143821, -0.169372901, 0.430269539, -0.376156092, -0.378161937, 0.694794357, -0.450359076, -0.180556566, 0.0424509495, -0.275738239, -0.161556199, -0.390238196], "parent": [-1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14], "depth": [0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], "iLeaf": [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]}], [{"feature": [1, 1, 0, 4, 0, 8, 2, 8, 2, 2, 5, 5, 3, 1, 6, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2], "threshold": [0.140625, 0.109375, 7.69071722, -13.5, 14.5519686, 8.5, 0.254882812, 2.5, 0.256835938, 0.219726562, 0.951564014, 0.0752535984, -1.5, 0.171875, 16.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "children_left": [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "children_right": [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "value": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.301308185, 0.304734617, 0.359152883, 0.0685707554, 0.139380425, -0.196517661, 0.26767078, -0.092287831, 0.0782259256, -0.350551367, -0.37530303, -0.175267071, 0.193004847, -0.116770878, -0.22124359, -0.341241091], "parent": [-1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14], "depth": [0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], "iLeaf": [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]}], [{"feature": [1, 3, 1, 3, 5, 3, 3, 5, 4, 10, 5, 3, 5, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2], "threshold": [0.109375, 4.5, 0.171875, -2.5, 0.0630929098, 2.5, 2.5, 0.0503542498, -26.5, 1.5, 0.0889862627, -1.5, 0.0574394017, -2.5, 3.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "children_left": [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "children_right": [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "value": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.528415024, -0.341509908, -0.224257782, 0.332276493, 0.414823771, -0.166062027, -0.161982179, -0.427514702, -0.287400812, 0.144089252, 0.727860332, -0.371313125, -0.353289098, -0.11641188, -0.313981056, -0.364676535], "parent": [-1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14], "depth": [0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], "iLeaf": [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]}], [{"feature": [1, 4, 2, 8, 10, 3, 2, 0, 4, 2, -2, 3, 3, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2], "threshold": [0.109375, -13.5, 0.262695312, 2.5, 6.5, 1.5, 0.290039062, 6.54269695, -39.5, 0.252929688, 0, -2.5, 3.5, 9.02065659, 47.6570053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2.0, -2.0], "children_left": [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 29, 21, 23, 25, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "children_right": [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 30, 22, 24, 26, 28, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "value": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.20732594, 0, 0, 0, 0, -0.0745446905, -0.490941644, -0.30292502, 0.351926744, 0.317744046, 0.0299588144, -0.341244638, 0.0837424397, -0.1667739, -0.344421178, -0.299592078, -0.171457857, -0.324574828, 0.0762122124, -1.20732594, -1.20732594], "parent": [-1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 11, 11, 12, 12, 13, 13, 14, 14, 10, 10], "depth": [0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], "iLeaf": [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]}], [{"feature": [1, 0, 2, 5, 2, 0, 0, 0, 8, 10, 3, 8, 5, 5, 6, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2], "threshold": [0.109375, 7.04383469, 0.254882812, 0.0827398598, 0.280273438, 14.939868, 9.47421837, 2.81626415, 9.5, 3.5, 1.5, 3.5, 1.05517507, 0.057422813, 16.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "children_left": [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "children_right": [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "value": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.0296402257, 0.372503281, -0.279174328, 0.221156016, 0.313555121, 0.181570679, 0.0492865816, -0.56892544, -0.23718825, -0.00179062958, 0.199230328, -0.261860698, 0.66392386, -0.278425187, -0.0756268799, -0.2803078], "parent": [-1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14], "depth": [0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], "iLeaf": [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]}], [{"feature": [1, 0, 3, 10, 2, 3, 5, 3, 2, 10, 8, 0, 6, 2, 3, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2], "threshold": [0.109375, 20.5230389, 2.5, 5.5, 0.280273438, -2.5, 0.0702819526, 4.5, 0.241210938, 3.5, 9.5, 39.9494553, 17.5, 0.291992188, 3.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "children_left": [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "children_right": [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "value": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.183256373, -0.15534921, 0.0191810895, -1.47547853, 0.31037724, 0.204687983, 0.284539312, -0.43629247, -0.310324848, 0.889182568, 0.0579996705, -0.232304126, 0.737877786, -0.190356895, -0.212541878, -0.326160461], "parent": [-1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14], "depth": [0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], "iLeaf": [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]}], [{"feature": [0, 3, 5, 1, 3, 6, 0, -2, 3, 1, 5, 4, 0, 6, 9, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2], "threshold": [20.5809975, -2.5, 1.04217935, 0.078125, 1.5, 19.5, 58.5983238, 0, -4.5, 0.234375, 0.0664517879, -10.0, 24.7252579, 11.5, 7.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2.0, -2.0], "children_left": [1, 3, 5, 7, 9, 11, 13, 29, 15, 17, 19, 21, 23, 25, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "children_right": [2, 4, 6, 8, 10, 12, 14, 30, 16, 18, 20, 22, 24, 26, 28, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "value": [0, 0, 0, 0, 0, 0, 0, 0.363402009, 0, 0, 0, 0, 0, 0, 0, -0.312803566, -0.204151258, 0.0456621125, -0.14882116, 0.20181866, -0.25203824, -1.20155859, 0.277422816, -0.404247284, 0.160260811, 0.580196619, -0.262717366, 0.406997979, -0.171044543, 0.363402009, 0.363402009], "parent": [-1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 7, 7], "depth": [0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], "iLeaf": [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]}], [{"feature": [0, 2, 5, 3, 2, 2, 0, 1, 3, 4, 5, 6, 0, 9, 9, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2], "threshold": [30.4840431, 0.245117188, 1.16153455, -1.5, 0.282226562, 0.280273438, 58.5983238, 0.140625, 2.5, 9.5, 0.948028684, 11.5, 35.0835876, 3.5, 7.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "children_left": [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "children_right": [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], "value": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0297101662, -0.228048578, 0.0833817348, -0.235787436, -0.063608937, -0.25884518, -0.224756852, -0.356927872, -0.296937495, 0.299284011, 0.524167776, -0.222849742, -0.0959210619, -0.489832073, 0.43333599, -0.154233307], "parent": [-1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14], "depth": [0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], "iLeaf": [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]}]], "init_predict": [0, 0], "norm": 1} \ No newline at end of file diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/common/inversion.h b/L1Trigger/Phase2L1ParticleFlow/interface/common/inversion.h new file mode 100644 index 0000000000000..8628a4ca1af24 --- /dev/null +++ b/L1Trigger/Phase2L1ParticleFlow/interface/common/inversion.h @@ -0,0 +1,60 @@ +#ifndef CC_INVERSION_H__ +#define CC_INVERSION_H__ + +constexpr int ceillog2(int x) { return (x <= 2) ? 1 : 1 + ceillog2((x + 1) / 2); } + +template +inline float real_val_from_idx(unsigned i) { + // Treat the index as the top N bits + static constexpr int NB = ceillog2(N); // number of address bits for table + data_T x(0); + // The MSB of 1 is implicit in the table + x[x.width - 1] = 1; + // So we can use the next NB bits for real data + x(x.width - 2, x.width - NB - 1) = i; + return (float)x; +} + +template +inline unsigned idx_from_real_val(data_T x) { + // Slice the top N bits to get an index into the table + static constexpr int NB = ceillog2(N); // number of address bits for table + // Slice the top-1 NB bits of the value + // the MSB of '1' is implicit, so only slice below that + ap_uint y = x(x.width - 2, x.width - NB - 1); + return (unsigned)y(NB - 1, 0); +} + +template +void init_invert_table(table_T table_out[N]) { + // The template data_T is the data type used to address the table + for (unsigned i = 0; i < N; i++) { + float x = real_val_from_idx(i); + table_T inv_x = 1 / x; + table_out[i] = inv_x; + } +} + +template +table_t invert_with_shift(in_t in) { + table_t inv_table[N]; + init_invert_table(inv_table); + + // find the first '1' in the denominator + int msb = 0; + for (int b = 0; b < in.width; b++) { + // #pragma HLS unroll + if (in[b]) + msb = b; + } + // shift up the denominator such that the left-most bit (msb) is '1' + in_t in_shifted = in << (in.width - msb - 1); + // lookup the inverse of the shifted input + int idx = idx_from_real_val(in_shifted); + table_t inv_in = inv_table[idx]; + // shift the output back + table_t out = inv_in << (in.width - msb - 1); + return out; +} + +#endif \ No newline at end of file diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/conifer.h b/L1Trigger/Phase2L1ParticleFlow/interface/conifer.h index 61ee6d89b9e85..542806376f964 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/conifer.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/conifer.h @@ -1,8 +1,12 @@ #ifndef CONIFER_CPP_H__ #define CONIFER_CPP_H__ -#include "FWCore/Utilities/interface/Exception.h" #include "nlohmann/json.hpp" #include +#ifdef CMSSW_GIT_HASH +#include "FWCore/Utilities/interface/Exception.h" +#else +#include +#endif namespace conifer { @@ -115,18 +119,25 @@ namespace conifer { std::vector decision_function(std::vector x) const { /* Do the prediction */ +#ifdef CMSSW_GIT_HASH if (x.size() != n_features) { throw cms::Exception("RuntimeError") << "Conifer : Size of feature vector mismatches expected n_features" << std::endl; } +#else + if (x.size() != n_features) { + throw std::runtime_error("Conifer : Size of feature vector mismatches expected n_features"); + } +#endif std::vector values; std::vector> values_trees; values_trees.resize(n_classes); values.resize(n_classes, U(0)); for (unsigned int i = 0; i < n_classes; i++) { - std::transform(trees.begin(), trees.end(), std::back_inserter(values_trees.at(i)), [&i, &x](auto tree_v) { - return tree_v.at(i).decision_function(x); - }); + std::transform(trees.begin(), + trees.end(), + std::back_inserter(values_trees.at(i)), + [&i, &x](std::vector> tree_v) { return tree_v.at(i).decision_function(x); }); if (useAddTree) { values.at(i) = init_predict_.at(i); values.at(i) += reduce>(values_trees.at(i), add); @@ -152,4 +163,4 @@ namespace conifer { } // namespace conifer -#endif \ No newline at end of file +#endif diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegalgo_ref.h b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegalgo_ref.h index b75be595ee9df..363a4130f9f34 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegalgo_ref.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegalgo_ref.h @@ -4,6 +4,8 @@ #include "DataFormats/L1TParticleFlow/interface/layer1_emulator.h" #include "DataFormats/L1TParticleFlow/interface/egamma.h" #include "DataFormats/L1TParticleFlow/interface/pf.h" +#include "L1Trigger/Phase2L1ParticleFlow/interface/conifer.h" +#include "L1Trigger/Phase2L1ParticleFlow/interface/common/inversion.h" namespace edm { class ParameterSet; @@ -30,6 +32,8 @@ namespace l1ct { std::vector dEtaValues; std::vector dPhiValues; float trkQualityPtMin; // GeV + bool doCompositeTkEle; + unsigned int nCompCandPerCluster; bool writeEgSta; struct IsoParameters { @@ -53,6 +57,18 @@ namespace l1ct { bool doPfIso; EGIsoEleObjEmu::IsoType hwIsoTypeTkEle; EGIsoObjEmu::IsoType hwIsoTypeTkEm; + + struct CompIDParameters { + CompIDParameters(const edm::ParameterSet &); + CompIDParameters(double bdtScore_loose_wp, double bdtScore_tight_wp, const std::string &model) + : bdtScore_loose_wp(bdtScore_loose_wp), bdtScore_tight_wp(bdtScore_tight_wp), conifer_model(model) {} + const double bdtScore_loose_wp; // XGBOOST score + const double bdtScore_tight_wp; // XGBOOST score + const std::string conifer_model; + }; + + CompIDParameters compIDparams; + int debug = 0; PFTkEGAlgoEmuConfig(const edm::ParameterSet &iConfig); @@ -72,6 +88,8 @@ namespace l1ct { const std::vector &dEtaValues = {0.015, 0.01}, const std::vector &dPhiValues = {0.07, 0.07}, float trkQualityPtMin = 10., + bool doCompositeTkEle = false, + unsigned int nCompCandPerCluster = 4, bool writeEgSta = false, const IsoParameters &tkIsoParams_tkEle = {2., 0.6, 0.03, 0.2}, const IsoParameters &tkIsoParams_tkEm = {2., 0.6, 0.07, 0.3}, @@ -81,6 +99,8 @@ namespace l1ct { bool doPfIso = false, EGIsoEleObjEmu::IsoType hwIsoTypeTkEle = EGIsoEleObjEmu::IsoType::TkIso, EGIsoObjEmu::IsoType hwIsoTypeTkEm = EGIsoObjEmu::IsoType::TkIsoPV, + // FIXME: maybe we round these? + const CompIDParameters &compIDparams = {0.7927004, 0.9826955, "compositeID.json"}, int debug = 0) : nTRACK(nTrack), @@ -95,10 +115,15 @@ namespace l1ct { emClusterPtMin(emClusterPtMin), dEtaMaxBrem(dEtaMaxBrem), dPhiMaxBrem(dPhiMaxBrem), + //absEtaBoundaries(std::move(absEtaBoundaries)), + //dEtaValues(std::move(dEtaValues)), + //dPhiValues(std::move(dPhiValues)), absEtaBoundaries(absEtaBoundaries), dEtaValues(dEtaValues), dPhiValues(dPhiValues), trkQualityPtMin(trkQualityPtMin), + doCompositeTkEle(doCompositeTkEle), + nCompCandPerCluster(nCompCandPerCluster), writeEgSta(writeEgSta), tkIsoParams_tkEle(tkIsoParams_tkEle), tkIsoParams_tkEm(tkIsoParams_tkEm), @@ -108,12 +133,13 @@ namespace l1ct { doPfIso(doPfIso), hwIsoTypeTkEle(hwIsoTypeTkEle), hwIsoTypeTkEm(hwIsoTypeTkEm), + compIDparams(compIDparams), debug(debug) {} }; class PFTkEGAlgoEmulator { public: - PFTkEGAlgoEmulator(const PFTkEGAlgoEmuConfig &config) : cfg(config), debug_(cfg.debug) {} + PFTkEGAlgoEmulator(const PFTkEGAlgoEmuConfig &config); virtual ~PFTkEGAlgoEmulator() {} @@ -132,13 +158,33 @@ namespace l1ct { bool writeEgSta() const { return cfg.writeEgSta; } + typedef ap_fixed<21, 12, AP_RND_CONV, AP_SAT> bdt_feature_t; + typedef ap_fixed<12, 3, AP_RND_CONV, AP_SAT> bdt_score_t; + private: void link_emCalo2emCalo(const std::vector &emcalo, std::vector &emCalo2emCalo) const; - void link_emCalo2tk(const PFRegionEmu &r, - const std::vector &emcalo, - const std::vector &track, - std::vector &emCalo2tk) const; + void link_emCalo2tk_elliptic(const PFRegionEmu &r, + const std::vector &emcalo, + const std::vector &track, + std::vector &emCalo2tk) const; + + void link_emCalo2tk_composite(const PFRegionEmu &r, + const std::vector &emcalo, + const std::vector &track, + std::vector &emCalo2tk, + std::vector &emCaloTkBdtScore) const; + + struct CompositeCandidate { + unsigned int cluster_idx; + unsigned int track_idx; + double dpt; // For sorting + }; + + float compute_composite_score(CompositeCandidate &cand, + const std::vector &emcalo, + const std::vector &track, + const PFTkEGAlgoEmuConfig::CompIDParameters ¶ms) const; //FIXME: still needed float deltaPhi(float phi1, float phi2) const; @@ -152,6 +198,7 @@ namespace l1ct { const std::vector &track, const std::vector &emCalo2emCalo, const std::vector &emCalo2tk, + const std::vector &emCaloTkBdtScore, std::vector &egstas, std::vector &egobjs, std::vector &egeleobjs) const; @@ -165,6 +212,7 @@ namespace l1ct { const unsigned int hwQual, const pt_t ptCorr, const int tk_idx, + const float bdtScore, const std::vector &components = {}) const; EGObjEmu &addEGStaToPF(std::vector &egobjs, @@ -182,7 +230,8 @@ namespace l1ct { const EmCaloObjEmu &calo, const TkObjEmu &track, const unsigned int hwQual, - const pt_t ptCorr) const; + const pt_t ptCorr, + const float bdtScore) const; // FIXME: reimplemented from PFAlgoEmulatorBase template @@ -309,6 +358,7 @@ namespace l1ct { z0_t z0) const; PFTkEGAlgoEmuConfig cfg; + conifer::BDT, false> *composite_bdt_; int debug_; }; } // namespace l1ct diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/tkinput_ref.h b/L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/tkinput_ref.h index 585156036ca9a..2545a6dabc243 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/tkinput_ref.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/tkinput_ref.h @@ -22,14 +22,24 @@ namespace l1ct { }; TrackInputEmulator(const edm::ParameterSet &iConfig); - TrackInputEmulator(Region = Region::Endcap, Encoding encoding = Encoding::Stepping, bool bitwise = true); + TrackInputEmulator(Region = Region::Endcap, + Encoding encoding = Encoding::Stepping, + bool bitwise = true, + bool slim = true); std::pair decodeTrack(ap_uint<96> tkword, const l1ct::PFRegionEmu §or) const { - return decodeTrack(tkword, sector, bitwise_); + return decodeTrack(tkword, sector, bitwise_, slim_); } std::pair decodeTrack(ap_uint<96> tkword, const l1ct::PFRegionEmu §or, - bool bitwise) const; + bool bitwise) const { + return decodeTrack(tkword, sector, bitwise, slim_); + } + + std::pair decodeTrack(ap_uint<96> tkword, + const l1ct::PFRegionEmu §or, + bool bitwise, + bool slim) const; //== Unpackers == static bool valid(const ap_uint<96> &tkword) { return tkword[95]; } @@ -151,6 +161,15 @@ namespace l1ct { const std::vector &tanlLUT() const { return tanlLUT_; } const std::vector &ptLUT() const { return ptLUT_; } + unsigned int countSetBits(unsigned int n) const { + unsigned int count = 0; + while (n) { + n &= (n - 1); + count++; + } + return count; + } + protected: // utilities template @@ -175,6 +194,9 @@ namespace l1ct { /// Whether to run the bitwise accurate or floating point conversions bool bitwise_; + /// Whether to unpack and populate also nstubs and various chi2 variables (needed for CompibedID in the endcap) + bool slim_; + /// Main constants float rInvToPt_, phiScale_, z0Scale_; diff --git a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc index f5599d121d0b9..619ef495249a6 100644 --- a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc +++ b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc @@ -72,7 +72,6 @@ class L1TCorrelatorLayer1Producer : public edm::stream::EDProducer<> { std::unique_ptr l1tkegalgo_; std::unique_ptr l1tkegsorter_; - bool writeEgSta_; // Region dump const std::string regionDumpName_; bool writeRawHgcalCluster_; @@ -114,6 +113,7 @@ class L1TCorrelatorLayer1Producer : public edm::stream::EDProducer<> { std::unique_ptr fetchEmCalo() const; std::unique_ptr fetchTracks() const; std::unique_ptr fetchPF() const; + std::unique_ptr> fetchDecodedTracks() const; void putPuppi(edm::Event &iEvent) const; void putEgStaObjects(edm::Event &iEvent, @@ -175,6 +175,7 @@ L1TCorrelatorLayer1Producer::L1TCorrelatorLayer1Producer(const edm::ParameterSet #if 0 // LATER produces("TKVtx"); #endif + produces>("DecodedTK"); for (const auto &tag : iConfig.getParameter>("emClusters")) { emCands_.push_back(consumes(tag)); @@ -364,6 +365,7 @@ void L1TCorrelatorLayer1Producer::produce(edm::Event &iEvent, const edm::EventSe iEvent.put(fetchEmCalo(), "EmCalo"); iEvent.put(fetchHadCalo(), "Calo"); iEvent.put(fetchTracks(), "TK"); + iEvent.put(fetchDecodedTracks(), "DecodedTK"); // Then do the vertexing, and save it out std::vector z0s; @@ -636,7 +638,6 @@ void L1TCorrelatorLayer1Producer::addDecodedTrack(l1ct::DetectorSector> &sec, const l1t::PFCluster &c) { ap_uint<256> cwrd = 0; - ap_uint<14> w_pt = round(c.pt() / 0.25); + ap_ufixed<14, 12, AP_RND_CONV, AP_SAT> w_pt = c.pt(); ap_uint<14> w_empt = round(c.emEt() / 0.25); constexpr float ETAPHI_LSB = M_PI / 720; ap_int<9> w_eta = round(sec.region.localEta(c.eta()) / ETAPHI_LSB); ap_int<9> w_phi = round(sec.region.localPhi(c.phi()) / ETAPHI_LSB); ap_uint<10> w_qual = c.hwQual(); - - cwrd(13, 0) = w_pt; + // FIXME: this is an arbitrary choice to keep the rounding consistent with the "addDecodedHadCalo" one + ap_uint<13> w_srrtot = round(c.sigmaRR() * l1ct::Scales::SRRTOT_SCALE / l1ct::Scales::SRRTOT_LSB); + ap_uint<12> w_meanz = round(c.absZBarycenter()); + // FIXME: the calibration can actually make hoe become negative....we add a small protection for now + // We use ap_ufixed to handle saturation and rounding + ap_ufixed<10, 5, AP_RND_CONV, AP_SAT> w_hoe = c.hOverE(); + + cwrd(13, 0) = w_pt.range(); cwrd(27, 14) = w_empt; cwrd(72, 64) = w_eta; cwrd(81, 73) = w_phi; cwrd(115, 106) = w_qual; + // FIXME: we add the variables use by composite-ID. The definitin will have to be reviewd once the + // hgc format is better defined. For now we use + // hwMeanZ = word 1 bits 30-19 + // hwSrrTot = word 3 bits 21 - 9 + // hoe = word 1 bits 63-52 (currently spare in the interface) + cwrd(213, 201) = w_srrtot; + cwrd(94, 83) = w_meanz; + cwrd(127, 116) = w_hoe.range(); + sec.obj.push_back(cwrd); } void L1TCorrelatorLayer1Producer::addDecodedEmCalo(l1ct::DetectorSector &sec, const l1t::PFCluster &c) { l1ct::EmCaloObjEmu calo; + // set the endcap-sepcific variables to default value: + calo.clear(); calo.hwPt = l1ct::Scales::makePtFromFloat(c.pt()); calo.hwEta = l1ct::Scales::makeGlbEta(c.eta()) - sec.region.hwEtaCenter; // important to enforce that the region boundary is on a discrete value @@ -841,6 +863,37 @@ std::unique_ptr L1TCorrelatorLayer1Producer::fetchTr return ret; } +std::unique_ptr> L1TCorrelatorLayer1Producer::fetchDecodedTracks() const { + auto ret = std::make_unique>(); + for (const auto &r : event_.decoded.track) { + const auto ® = r.region; + for (const auto &p : r.obj) { + if (p.hwPt == 0 || !reg.isFiducial(p)) + continue; + reco::Particle::PolarLorentzVector p4( + p.floatPt(), reg.floatGlbEta(p.hwVtxEta()), reg.floatGlbPhi(p.hwVtxPhi()), 0); + + reco::Particle::Point vtx(0, 0, p.floatZ0()); + + ret->emplace_back(l1t::PFTrack(p.intCharge(), + reco::Particle::LorentzVector(p4), + vtx, + p.src->track(), + 0, + reg.floatGlbEta(p.hwEta), + reg.floatGlbPhi(p.hwPhi), + -1, + -1, + p.hwQuality.to_int(), + false, + p.intPt(), + p.intEta(), + p.intPhi())); + } + } + return ret; +} + std::unique_ptr L1TCorrelatorLayer1Producer::fetchPF() const { auto ret = std::make_unique(); for (unsigned int ir = 0, nr = event_.pfinputs.size(); ir < nr; ++ir) { @@ -861,6 +914,9 @@ std::unique_ptr L1TCorrelatorLayer1Producer::fetchPF ret->back().setHwZ0(p.hwZ0); ret->back().setHwDxy(p.hwDxy); ret->back().setHwTkQuality(p.hwTkQuality); + ret->back().setCaloEta(reg.floatGlbEtaOf(p)); + ret->back().setCaloPhi(reg.floatGlbPhiOf(p)); + setRefs_(ret->back(), p); } for (const auto &p : event_.out[ir].pfneutral) { @@ -871,6 +927,8 @@ std::unique_ptr L1TCorrelatorLayer1Producer::fetchPF p.hwId.isPhoton() ? l1t::PFCandidate::Photon : l1t::PFCandidate::NeutralHadron; ret->emplace_back(type, 0, p4, 1, p.intPt(), p.intEta(), p.intPhi()); ret->back().setHwEmID(p.hwEmID); + ret->back().setCaloEta(reg.floatGlbEtaOf(p)); + ret->back().setCaloPhi(reg.floatGlbPhiOf(p)); setRefs_(ret->back(), p); } } @@ -1042,6 +1100,7 @@ void L1TCorrelatorLayer1Producer::putEgObjects(edm::Event &iEvent, tkele.setHwQual(egele.hwQual); tkele.setPFIsol(egele.floatRelIso(l1ct::EGIsoEleObjEmu::IsoType::PfIso)); tkele.setEgBinaryWord(egele.pack()); + tkele.setIdScore(egele.idScore); tkeles->push_back(tkele); nele_obj.push_back(tkeles->size() - 1); } diff --git a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc index 99b0251eff85b..54399d8a497a3 100644 --- a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc +++ b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc @@ -351,7 +351,8 @@ void L1TCtL2EgProducer::convertToEmu(const l1t::TkElectron &tkele, emu.setHwIso(EGIsoEleObjEmu::IsoType::PfIso, l1ct::Scales::makeIso(tkele.pfIsol() * tkele.pt())); emu.setHwIso(EGIsoEleObjEmu::IsoType::PuppiIso, l1ct::Scales::makeIso(tkele.puppiIsol() * tkele.pt())); // std::cout << "[convertToEmu] TkEle pt: " << emu.hwPt << " eta: " << emu.hwEta << " phi: " << emu.hwPhi << " staidx: " << emu.sta_idx << std::endl; - + // FIXME: this is temporary while waiting to move the BDT score to the FW object + emu.idScore = tkele.idScore(); boarOut.egelectron.push_back(emu); } @@ -421,6 +422,7 @@ l1t::TkElectron L1TCtL2EgProducer::convertFromEmu(const l1ct::EGIsoEleObjEmu &eg tkele.setPFIsol(egele.floatRelIso(l1ct::EGIsoEleObjEmu::IsoType::PfIso)); tkele.setPuppiIsol(egele.floatRelIso(l1ct::EGIsoEleObjEmu::IsoType::PuppiIso)); tkele.setEgBinaryWord(gteg.pack()); + tkele.setIdScore(egele.idScore); return tkele; } diff --git a/L1Trigger/Phase2L1ParticleFlow/plugins/PFClusterProducerFromHGC3DClusters.cc b/L1Trigger/Phase2L1ParticleFlow/plugins/PFClusterProducerFromHGC3DClusters.cc index 7d393fe347bd9..0a76d751f90c0 100644 --- a/L1Trigger/Phase2L1ParticleFlow/plugins/PFClusterProducerFromHGC3DClusters.cc +++ b/L1Trigger/Phase2L1ParticleFlow/plugins/PFClusterProducerFromHGC3DClusters.cc @@ -129,7 +129,8 @@ void l1tpf::PFClusterProducerFromHGC3DClusters::produce(edm::Event &iEvent, cons //float em_old = cluster.emEt(); float em_new = it->iPt(l1t::HGCalMulticluster::EnergyInterpretation::EM); float pt_new = had_old + em_new; - float hoe_new = em_new > 0 ? (had_old / em_new) : -1; + // FIXME: -1 can be a problem for later stages of the processing. For now we set it to something which saturates the hoe variable + float hoe_new = em_new > 0 ? (had_old / em_new) : 999; cluster = l1t::PFCluster(pt_new, it->eta(), it->phi(), hoe_new, /*isEM=*/isEM); //printf("Scenario %d: pt %7.2f eta %+5.3f em %7.2f, EMI %7.2f, h/e % 8.3f --> pt %7.2f, em %7.2f, h/e % 8.3f\n", // 2, pt, it->eta(), em_old, em_new, hoe, cluster.pt(), cluster.emEt(), cluster.hOverE()); @@ -156,6 +157,10 @@ void l1tpf::PFClusterProducerFromHGC3DClusters::produce(edm::Event &iEvent, cons corrector_.correctPt(cluster); cluster.setPtError(resol_(cluster.pt(), std::abs(cluster.eta()))); + // We se the cluster shape variables used downstream + cluster.setAbsZBarycenter(fabs(it->zBarycenter())); + cluster.setSigmaRR(it->sigmaRRTot()); + out->push_back(cluster); out->back().addConstituent(edm::Ptr(multiclusters, multiclusters->key(it))); if (hasEmId_) { diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1TkEgAlgoEmulator_cfi.py b/L1Trigger/Phase2L1ParticleFlow/python/l1TkEgAlgoEmulator_cfi.py index 3d1621b655d56..a060853085cbd 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1TkEgAlgoEmulator_cfi.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/l1TkEgAlgoEmulator_cfi.py @@ -1,6 +1,5 @@ import FWCore.ParameterSet.Config as cms - tkEgAlgoParameters = cms.PSet( nTRACK=cms.uint32(50), # very large numbers for first test nTRACK_EGIN=cms.uint32(50), # very large numbers for first test @@ -50,7 +49,15 @@ doTkIso=cms.bool(True), doPfIso=cms.bool(True), hwIsoTypeTkEle=cms.uint32(0), - hwIsoTypeTkEm=cms.uint32(2) + hwIsoTypeTkEm=cms.uint32(2), + doCompositeTkEle=cms.bool(False), + nCompCandPerCluster=cms.uint32(3), + compositeParametersTkEle=cms.PSet( + # the working points are cuts on BDT output logits log(p/1-p) + loose_wp=cms.double(-4.), + tight_wp=cms.double(0.214844), + model=cms.string("L1Trigger/Phase2L1ParticleFlow/data/compositeID.json") + ), ) tkEgSorterParameters = cms.PSet( diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1TkEgAlgo_cfi.py b/L1Trigger/Phase2L1ParticleFlow/python/l1TkEgAlgo_cfi.py deleted file mode 100644 index 500121131a360..0000000000000 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1TkEgAlgo_cfi.py +++ /dev/null @@ -1,47 +0,0 @@ -import FWCore.ParameterSet.Config as cms - -tkEgConfig = cms.PSet( - debug=cms.untracked.int32(0), - doBremRecovery=cms.bool(True), - doTkIsolation=cms.bool(True), - filterHwQuality=cms.bool(True), - caloHwQual=cms.int32(4), - dEtaMaxBrem=cms.double(0.02), - dPhiMaxBrem=cms.double(0.1), - absEtaBoundaries=cms.vdouble(0.0, 0.9, 1.5), - dEtaValues=cms.vdouble(0.025, 0.015, 0.01), # last was 0.0075 in TDR - dPhiValues=cms.vdouble(0.07, 0.07, 0.07), - caloEtMin=cms.double(0.0), - trkQualityPtMin=cms.double(10.0), - trkQualityChi2=cms.double(1e10), - writeEgSta=cms.bool(True), - tkIsoParametersTkEm=cms.PSet( - tkQualityPtMin=cms.double(2.), - dZ=cms.double(0.6), - dRMin=cms.double(0.07), - dRMax=cms.double(0.30), - tkQualityChi2Max=cms.double(100), - ), - tkIsoParametersTkEle=cms.PSet( - tkQualityPtMin=cms.double(2.), - dZ=cms.double(0.6), - dRMin=cms.double(0.03), - dRMax=cms.double(0.20), - tkQualityChi2Max=cms.double(1e10), - ), - pfIsoParametersTkEm=cms.PSet( - tkQualityPtMin=cms.double(1.), - dZ=cms.double(0.6), - dRMin=cms.double(0.07), - dRMax=cms.double(0.30), - tkQualityChi2Max=cms.double(100), - ), - pfIsoParametersTkEle=cms.PSet( - tkQualityPtMin=cms.double(1.), - dZ=cms.double(0.6), - dRMin=cms.double(0.03), - dRMax=cms.double(0.20), - tkQualityChi2Max=cms.double(1e10), - ) - -) diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py index ee6fc05d8726a..1b0799daa2e49 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py @@ -29,6 +29,7 @@ region = cms.string("barrel"), trackWordEncoding = cms.string("biased"), bitwiseAccurate = cms.bool(True), + slimDataFormat = cms.bool(True), ptLUTBits = cms.uint32(11), etaLUTBits = cms.uint32(10), etaPreOffs = cms.int32(0), @@ -169,6 +170,7 @@ region = cms.string("endcap"), trackWordEncoding = cms.string("biased"), bitwiseAccurate = cms.bool(True), + slimDataFormat = cms.bool(False), ptLUTBits = cms.uint32(11), etaLUTBits = cms.uint32(11), etaPreOffs = cms.int32(0), @@ -261,7 +263,9 @@ doBremRecovery=True, doEndcapHwQual=True, writeBeforeBremRecovery=False, - writeEGSta=True), + writeEGSta=True, + doCompositeTkEle=True, + trkQualityPtMin=0.), # This should be 10 GeV when doCompositeTkEle=False tkEgSorterParameters=tkEgSorterParameters.clone( nObjToSort = 5 ), @@ -290,6 +294,12 @@ writeRawHgcalCluster = cms.untracked.bool(True) ) +l1tLayer1HGCalElliptic = l1tLayer1HGCal.clone( + tkEgAlgoParameters = l1tLayer1HGCal.tkEgAlgoParameters.clone( + doCompositeTkEle = False, + trkQualityPtMin = 10.) +) + l1tLayer1HGCalExtended = l1tLayer1HGCal.clone(tracks = cms.InputTag('l1tPFTracksFromL1TracksExtended')) l1tLayer1HGCalNoTK = cms.EDProducer("L1TCorrelatorLayer1Producer", @@ -526,6 +536,50 @@ ) ) +l1tLayer1EGElliptic = cms.EDProducer( + "L1TEGMultiMerger", + tkElectrons=cms.VPSet( + cms.PSet( + instance=cms.string("L1TkEleEE"), + pfProducers=cms.VInputTag( + cms.InputTag("l1tLayer1HGCalElliptic", 'L1TkEle') + ) + ), + cms.PSet( + instance=cms.string("L1TkEleEB"), + pfProducers=cms.VInputTag( + cms.InputTag("l1tLayer1Barrel", 'L1TkEle') + ) + ) + ), + tkEms=cms.VPSet( + cms.PSet( + instance=cms.string("L1TkEmEE"), + pfProducers=cms.VInputTag( + cms.InputTag("l1tLayer1HGCalElliptic", 'L1TkEm'), + cms.InputTag("l1tLayer1HGCalNoTK", 'L1TkEm') + ) + ), + cms.PSet( + instance=cms.string("L1TkEmEB"), + pfProducers=cms.VInputTag( + cms.InputTag("l1tLayer1Barrel", 'L1TkEm') + ) + ) + ), + tkEgs=cms.VPSet( + cms.PSet( + instance=cms.string("L1EgEE"), + pfProducers=cms.VInputTag( + cms.InputTag("l1tLayer1HGCalElliptic", 'L1Eg'), + cms.InputTag("l1tLayer1HGCalNoTK", 'L1Eg') + ) + ) + ) +) + + + L1TLayer1TaskInputsTask = cms.Task( l1tPFClustersFromL1EGClusters, l1tPFClustersFromCombinedCaloHCal, @@ -542,5 +596,7 @@ l1tLayer1HF, l1tLayer1, l1tLayer1Extended, - l1tLayer1EG + l1tLayer1HGCalElliptic, + l1tLayer1EG, + l1tLayer1EGElliptic ) diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py index 517c8e82bf733..e42be9d3b8211 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py @@ -150,8 +150,46 @@ # ) ) +l1tLayer2EGElliptic = l1tLayer2EG.clone( + tkElectrons=cms.VPSet( + cms.PSet( + pfProducer=cms.InputTag("l1tLayer1HGCalElliptic", 'L1TkElePerBoard'), + channels=cms.vint32(3, 4) + ), + cms.PSet( + pfProducer=cms.InputTag("l1tLayer1Barrel", 'L1TkElePerBoard'), + channels=cms.vint32(0, 1, 2) + ), + ), + tkEms=cms.VPSet( + cms.PSet( + pfProducer=cms.InputTag("l1tLayer1HGCalElliptic", 'L1TkEmPerBoard'), + channels=cms.vint32(3, 4) + ), + cms.PSet( + pfProducer=cms.InputTag("l1tLayer1HGCalNoTK", 'L1TkEmPerBoard'), + channels=cms.vint32(-1) + ), + cms.PSet( + pfProducer=cms.InputTag("l1tLayer1Barrel", 'L1TkEmPerBoard'), + channels=cms.vint32(0, 1, 2) + ), + ), + tkEgs=cms.VPSet( + cms.PSet( + pfProducer=cms.InputTag("l1tLayer1HGCalElliptic", 'L1Eg'), + channels=cms.vint32(-1) + ), + cms.PSet( + pfProducer=cms.InputTag("l1tLayer1HGCalNoTK", 'L1Eg'), + channels=cms.vint32(-1) + ), + ), +) + L1TLayer2EGTask = cms.Task( l1tLayer2Deregionizer, - l1tLayer2EG + l1tLayer2EG, + l1tLayer2EGElliptic ) diff --git a/L1Trigger/Phase2L1ParticleFlow/src/egamma/pfeginput_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/egamma/pfeginput_ref.cpp index 71716e7f542c2..560e0eb96df7f 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/egamma/pfeginput_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/egamma/pfeginput_ref.cpp @@ -31,6 +31,10 @@ void EGInputSelectorEmulator::select_eginput(const l1ct::HadCaloObjEmu &in, out.hwPtErr = 0; // shift to get rid of PFEM ID bit (more usable final EG quality) out.hwEmID = (in.hwEmID >> 1); + + out.hwSrrTot = in.hwSrrTot; + out.hwMeanZ = in.hwMeanZ; + out.hwHoe = in.hwHoe; valid_out = (in.hwEmID & cfg.idMask) != 0; } diff --git a/L1Trigger/Phase2L1ParticleFlow/src/egamma/pftkegalgo_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/egamma/pftkegalgo_ref.cpp index 2fc881879455d..3f78f3529253f 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/egamma/pftkegalgo_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/egamma/pftkegalgo_ref.cpp @@ -7,6 +7,7 @@ #include #include #include +#include using namespace l1ct; @@ -30,6 +31,8 @@ l1ct::PFTkEGAlgoEmuConfig::PFTkEGAlgoEmuConfig(const edm::ParameterSet &pset) dEtaValues(pset.getParameter>("dEtaValues")), dPhiValues(pset.getParameter>("dPhiValues")), trkQualityPtMin(pset.getParameter("trkQualityPtMin")), + doCompositeTkEle(pset.getParameter("doCompositeTkEle")), + nCompCandPerCluster(pset.getParameter("nCompCandPerCluster")), writeEgSta(pset.getParameter("writeEGSta")), tkIsoParams_tkEle(pset.getParameter("tkIsoParametersTkEle")), tkIsoParams_tkEm(pset.getParameter("tkIsoParametersTkEm")), @@ -39,6 +42,7 @@ l1ct::PFTkEGAlgoEmuConfig::PFTkEGAlgoEmuConfig(const edm::ParameterSet &pset) doPfIso(pset.getParameter("doPfIso")), hwIsoTypeTkEle(static_cast(pset.getParameter("hwIsoTypeTkEle"))), hwIsoTypeTkEm(static_cast(pset.getParameter("hwIsoTypeTkEm"))), + compIDparams(pset.getParameter("compositeParametersTkEle")), debug(pset.getUntrackedParameter("debug", 0)) {} l1ct::PFTkEGAlgoEmuConfig::IsoParameters::IsoParameters(const edm::ParameterSet &pset) @@ -47,8 +51,25 @@ l1ct::PFTkEGAlgoEmuConfig::IsoParameters::IsoParameters(const edm::ParameterSet pset.getParameter("dRMin"), pset.getParameter("dRMax")) {} +l1ct::PFTkEGAlgoEmuConfig::CompIDParameters::CompIDParameters(const edm::ParameterSet &pset) + : CompIDParameters(pset.getParameter("loose_wp"), + pset.getParameter("tight_wp"), + pset.getParameter("model")) {} + #endif +PFTkEGAlgoEmulator::PFTkEGAlgoEmulator(const PFTkEGAlgoEmuConfig &config) + : cfg(config), composite_bdt_(nullptr), debug_(cfg.debug) { + if (cfg.doCompositeTkEle) { +#ifdef CMSSW_GIT_HASH + auto resolvedFileName = edm::FileInPath(cfg.compIDparams.conifer_model).fullPath(); +#else + auto resolvedFileName = cfg.compIDparams.conifer_model; +#endif + composite_bdt_ = new conifer::BDT(resolvedFileName); + } +} + void PFTkEGAlgoEmulator::toFirmware(const PFInputRegion &in, PFRegion ®ion, EmCaloObj emcalo[/*nCALO*/], @@ -109,10 +130,10 @@ void PFTkEGAlgoEmulator::link_emCalo2emCalo(const std::vector &emc } } -void PFTkEGAlgoEmulator::link_emCalo2tk(const PFRegionEmu &r, - const std::vector &emcalo, - const std::vector &track, - std::vector &emCalo2tk) const { +void PFTkEGAlgoEmulator::link_emCalo2tk_elliptic(const PFRegionEmu &r, + const std::vector &emcalo, + const std::vector &track, + std::vector &emCalo2tk) const { unsigned int nTrackMax = std::min(track.size(), cfg.nTRACK_EGIN); for (int ic = 0, nc = emcalo.size(); ic < nc; ++ic) { auto &calo = emcalo[ic]; @@ -146,6 +167,90 @@ void PFTkEGAlgoEmulator::link_emCalo2tk(const PFRegionEmu &r, } } +void PFTkEGAlgoEmulator::link_emCalo2tk_composite(const PFRegionEmu &r, + const std::vector &emcalo, + const std::vector &track, + std::vector &emCalo2tk, + std::vector &emCaloTkBdtScore) const { + unsigned int nTrackMax = std::min(track.size(), cfg.nTRACK_EGIN); + for (int ic = 0, nc = emcalo.size(); ic < nc; ++ic) { + auto &calo = emcalo[ic]; + + std::vector candidates; + + for (unsigned int itk = 0; itk < nTrackMax; ++itk) { + const auto &tk = track[itk]; + if (tk.floatPt() <= cfg.trkQualityPtMin) + continue; + + float d_phi = deltaPhi(tk.floatPhi(), calo.floatPhi()); + float d_eta = tk.floatEta() - calo.floatEta(); // We only use it squared + float dR = std::sqrt((d_phi * d_phi) + (d_eta * d_eta)); + + if (dR < 0.2) { + // Only store indices, dR and dpT for now. The other quantities are computed only for the best nCandPerCluster. + CompositeCandidate cand; + cand.cluster_idx = ic; + cand.track_idx = itk; + cand.dpt = std::abs(tk.floatPt() - calo.floatPt()); + candidates.push_back(cand); + } + } + // FIXME: find best sort criteria, for now we use dpt + std::sort(candidates.begin(), + candidates.end(), + [](const CompositeCandidate &a, const CompositeCandidate &b) -> bool { return a.dpt < b.dpt; }); + unsigned int nCandPerCluster = std::min(candidates.size(), cfg.nCompCandPerCluster); + if (nCandPerCluster == 0) + continue; + + float maxScore = -999; + int ibest = -1; + for (unsigned int icand = 0; icand < nCandPerCluster; icand++) { + auto &cand = candidates[icand]; + const std::vector &emcalo_sel = emcalo; + float score = compute_composite_score(cand, emcalo_sel, track, cfg.compIDparams); + if ((score > cfg.compIDparams.bdtScore_loose_wp) && (score > maxScore)) { + maxScore = score; + ibest = icand; + } + } + if (ibest != -1) { + emCalo2tk[ic] = candidates[ibest].track_idx; + emCaloTkBdtScore[ic] = maxScore; + } + } +} + +float PFTkEGAlgoEmulator::compute_composite_score(CompositeCandidate &cand, + const std::vector &emcalo, + const std::vector &track, + const PFTkEGAlgoEmuConfig::CompIDParameters ¶ms) const { + // Get the cluster/track objects that form the composite candidate + const auto &calo = emcalo[cand.cluster_idx]; + const auto &tk = track[cand.track_idx]; + + // Prepare the input features + bdt_feature_t hoe = calo.hwHoe; + bdt_feature_t tkpt = tk.hwPt; + bdt_feature_t srrtot = calo.hwSrrTot; + bdt_feature_t deta = tk.hwEta - calo.hwEta; + ap_ufixed<18, 0> calo_invPt = invert_with_shift, 1024>(calo.hwPt); + bdt_feature_t dpt = tk.hwPt * calo_invPt; + bdt_feature_t meanz = calo.hwMeanZ; + bdt_feature_t dphi = tk.hwPhi - calo.hwPhi; + bdt_feature_t nstubs = tk.hwStubs; + bdt_feature_t chi2rphi = tk.hwRedChi2RPhi; + bdt_feature_t chi2rz = tk.hwRedChi2RZ; + bdt_feature_t chi2bend = tk.hwRedChi2Bend; + + // Run BDT inference + std::vector inputs = {tkpt, hoe, srrtot, deta, dphi, dpt, meanz, nstubs, chi2rphi, chi2rz, chi2bend}; + std::vector bdt_score = composite_bdt_->decision_function(inputs); + + return bdt_score[0]; +} + void PFTkEGAlgoEmulator::sel_emCalo(unsigned int nmax_sel, const std::vector &emcalo, std::vector &emcalo_sel) const { @@ -171,7 +276,6 @@ void PFTkEGAlgoEmulator::run(const PFInputRegion &in, OutputRegion &out) const { << std::endl; } } - // FIXME: can be removed in the endcap since now running with the "interceptor". // Might still be needed in barrel // filter and select first N elements of input clusters @@ -183,12 +287,18 @@ void PFTkEGAlgoEmulator::run(const PFInputRegion &in, OutputRegion &out) const { link_emCalo2emCalo(emcalo_sel, emCalo2emCalo); std::vector emCalo2tk(emcalo_sel.size(), -1); - link_emCalo2tk(in.region, emcalo_sel, in.track, emCalo2tk); + std::vector emCaloTkBdtScore(emcalo_sel.size(), -999); + + if (cfg.doCompositeTkEle) { + link_emCalo2tk_composite(in.region, emcalo_sel, in.track, emCalo2tk, emCaloTkBdtScore); + } else { + link_emCalo2tk_elliptic(in.region, emcalo_sel, in.track, emCalo2tk); + } out.egsta.clear(); std::vector egobjs; std::vector egeleobjs; - eg_algo(in.region, emcalo_sel, in.track, emCalo2emCalo, emCalo2tk, out.egsta, egobjs, egeleobjs); + eg_algo(in.region, emcalo_sel, in.track, emCalo2emCalo, emCalo2tk, emCaloTkBdtScore, out.egsta, egobjs, egeleobjs); unsigned int nEGOut = std::min(cfg.nEM_EGOUT, egobjs.size()); unsigned int nEGEleOut = std::min(cfg.nEM_EGOUT, egeleobjs.size()); @@ -205,6 +315,7 @@ void PFTkEGAlgoEmulator::eg_algo(const PFRegionEmu ®ion, const std::vector &track, const std::vector &emCalo2emCalo, const std::vector &emCalo2tk, + const std::vector &emCaloTkBdtScore, std::vector &egstas, std::vector &egobjs, std::vector &egeleobjs) const { @@ -220,6 +331,7 @@ void PFTkEGAlgoEmulator::eg_algo(const PFRegionEmu ®ion, << " phi " << calo.hwPhi << std::endl; int itk = emCalo2tk[ic]; + float bdt = emCaloTkBdtScore[ic]; // check if brem recovery is on if (!cfg.doBremRecovery || cfg.writeBeforeBremRecovery) { @@ -232,7 +344,7 @@ void PFTkEGAlgoEmulator::eg_algo(const PFRegionEmu ®ion, egQual = calo.hwEmID | 0x8; } - addEgObjsToPF(egstas, egobjs, egeleobjs, emcalo, track, ic, egQual, calo.hwPt, itk); + addEgObjsToPF(egstas, egobjs, egeleobjs, emcalo, track, ic, egQual, calo.hwPt, itk, bdt); } if (!cfg.doBremRecovery) @@ -255,7 +367,7 @@ void PFTkEGAlgoEmulator::eg_algo(const PFRegionEmu ®ion, // 2. create EG objects with brem recovery // NOTE: duplicating the object is suboptimal but this is done for keeping things as in TDR code... - addEgObjsToPF(egstas, egobjs, egeleobjs, emcalo, track, ic, calo.hwEmID, ptBremReco, itk, components); + addEgObjsToPF(egstas, egobjs, egeleobjs, emcalo, track, ic, calo.hwEmID, ptBremReco, itk, bdt, components); } } @@ -309,7 +421,8 @@ EGIsoEleObjEmu &PFTkEGAlgoEmulator::addEGIsoEleToPF(std::vector const EmCaloObjEmu &calo, const TkObjEmu &track, const unsigned int hwQual, - const pt_t ptCorr) const { + const pt_t ptCorr, + const float bdtScore) const { EGIsoEleObjEmu egiso; egiso.clear(); egiso.hwPt = ptCorr; @@ -317,9 +430,14 @@ EGIsoEleObjEmu &PFTkEGAlgoEmulator::addEGIsoEleToPF(std::vector egiso.hwPhi = calo.hwPhi; unsigned int egHwQual = hwQual; if (cfg.doEndcapHwQual) { - // 1. zero-suppress the loose EG-ID (bit 1) - // 2. for now use the standalone tight definition (bit 0) to set the tight point for eles (bit 1) - egHwQual = (hwQual & 0x9) | ((hwQual & 0x1) << 1); + if (cfg.doCompositeTkEle) { + // tight ele WP is set for tight BDT score + egHwQual = (hwQual & 0x9) | ((bdtScore >= cfg.compIDparams.bdtScore_tight_wp) << 1); + } else { + // 1. zero-suppress the loose EG-ID (bit 1) + // 2. for now use the standalone tight definition (bit 0) to set the tight point for eles (bit 1) + egHwQual = (hwQual & 0x9) | ((hwQual & 0x1) << 1); + } } egiso.hwQual = egHwQual; egiso.hwDEta = track.hwVtxEta() - egiso.hwEta; @@ -328,6 +446,7 @@ EGIsoEleObjEmu &PFTkEGAlgoEmulator::addEGIsoEleToPF(std::vector egiso.hwCharge = track.hwCharge; egiso.srcCluster = calo.src; egiso.srcTrack = track.src; + egiso.idScore = bdtScore; egobjs.push_back(egiso); if (debug_ > 2) @@ -346,6 +465,7 @@ void PFTkEGAlgoEmulator::addEgObjsToPF(std::vector &egstas, const unsigned int hwQual, const pt_t ptCorr, const int tk_idx, + const float bdtScore, const std::vector &components) const { int sta_idx = -1; if (writeEgSta()) { @@ -355,7 +475,7 @@ void PFTkEGAlgoEmulator::addEgObjsToPF(std::vector &egstas, EGIsoObjEmu &egobj = addEGIsoToPF(egobjs, emcalo[calo_idx], hwQual, ptCorr); egobj.sta_idx = sta_idx; if (tk_idx != -1) { - EGIsoEleObjEmu &eleobj = addEGIsoEleToPF(egeleobjs, emcalo[calo_idx], track[tk_idx], hwQual, ptCorr); + EGIsoEleObjEmu &eleobj = addEGIsoEleToPF(egeleobjs, emcalo[calo_idx], track[tk_idx], hwQual, ptCorr, bdtScore); eleobj.sta_idx = sta_idx; } } diff --git a/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/hgcalinputt_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/hgcalinputt_ref.cpp index d1777586ca753..15bf8a01bca3f 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/hgcalinputt_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/hgcalinputt_ref.cpp @@ -8,6 +8,10 @@ l1ct::HadCaloObjEmu l1ct::HgcalClusterDecoderEmulator::decode(const ap_uint<256> ap_int<9> w_eta = in(72, 64); ap_int<9> w_phi = in(81, 73); ap_uint<10> w_qual = in(115, 106); + ap_uint<13> w_srrtot = in(213, 201); + ap_uint<12> w_meanz = in(94, 83); + // FIXME: we use a spare space in the word for hoe which is not in the current interface + ap_uint<12> w_hoe = in(127, 116); l1ct::HadCaloObjEmu out; out.clear(); @@ -17,5 +21,12 @@ l1ct::HadCaloObjEmu l1ct::HgcalClusterDecoderEmulator::decode(const ap_uint<256> out.hwEmPt = w_empt * l1ct::pt_t(l1ct::Scales::INTPT_LSB); out.hwEmID = w_qual; + // FIXME: variables use by composite-ID need to be added here + out.hwSrrTot = w_srrtot * l1ct::srrtot_t(l1ct::Scales::SRRTOT_LSB); + out.hwMeanZ = (w_meanz == 0) ? l1ct::meanz_t(0) : l1ct::meanz_t(w_meanz - l1ct::meanz_t(l1ct::Scales::MEANZ_OFFSET)); + out.hwHoe = w_hoe * l1ct::hoe_t(l1ct::Scales::HOE_LSB); + + // std::cout << "[HadCaloObjEmu] meanz in: " << w_meanz << " out: " << out.hwMeanZ << std::endl; + return out; } diff --git a/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/tkinput_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/tkinput_ref.cpp index 4f707e49cc3cc..ca61b38eb3eb6 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/tkinput_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/tkinput_ref.cpp @@ -37,7 +37,8 @@ namespace { l1ct::TrackInputEmulator::TrackInputEmulator(const edm::ParameterSet &iConfig) : TrackInputEmulator(parseRegion(iConfig.getParameter("region")), parseEncoding(iConfig.getParameter("trackWordEncoding")), - iConfig.getParameter("bitwiseAccurate")) { + iConfig.getParameter("bitwiseAccurate"), + iConfig.getParameter("slimDataFormat")) { if (region_ != Region::Endcap && region_ != Region::Barrel) { edm::LogError("TrackInputEmulator") << "region '" << iConfig.getParameter("region") << "' is not yet supported"; @@ -81,10 +82,11 @@ l1ct::TrackInputEmulator::TrackInputEmulator(const edm::ParameterSet &iConfig) #endif -l1ct::TrackInputEmulator::TrackInputEmulator(Region region, Encoding encoding, bool bitwise) +l1ct::TrackInputEmulator::TrackInputEmulator(Region region, Encoding encoding, bool bitwise, bool slim) : region_(region), encoding_(encoding), bitwise_(bitwise), + slim_(slim), rInvToPt_(31199.5), phiScale_(0.00038349520), z0Scale_(0.00999469), @@ -100,7 +102,8 @@ l1ct::TrackInputEmulator::TrackInputEmulator(Region region, Encoding encoding, b std::pair l1ct::TrackInputEmulator::decodeTrack(ap_uint<96> tkword, const l1ct::PFRegionEmu §or, - bool bitwise) const { + bool bitwise, + bool slim) const { l1ct::TkObjEmu ret; ret.clear(); auto z0 = signedZ0(tkword); @@ -162,7 +165,6 @@ std::pair l1ct::TrackInputEmulator::decodeTrack(ap_uint<96 fDEta = floatDEtaHGCal(z0, Rinv, tanl); fDPhi = floatDPhiHGCal(z0, Rinv, tanl); } - ret.hwDPhi = std::round(fDPhi); ret.hwDEta = std::round(fDEta); ret.hwPhi = std::round(fvtxPhi - fDPhi * ret.intCharge()); @@ -171,6 +173,14 @@ std::pair l1ct::TrackInputEmulator::decodeTrack(ap_uint<96 ret.hwZ0 = l1ct::Scales::makeZ0(floatZ0(z0)); } + if (!slim) { + ap_uint<7> w_hitPattern = tkword(15, 9); + ret.hwStubs = countSetBits(w_hitPattern); + ret.hwRedChi2RZ = tkword(35, 32); + ret.hwRedChi2RPhi = tkword(67, 64); + ret.hwRedChi2Bend = tkword(18, 16); + } + oksel = ret.hwQuality != 0; } return std::make_pair(ret, oksel);