Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-06-10 01:53:51

0001 #ifndef L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_H
0002 #define L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_H
0003 
0004 #if defined(__GXX_EXPERIMENTAL_CXX0X__) or defined(CMSSW)
0005 #include <cstdint>
0006 #include <limits>
0007 #define L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_MORE
0008 #else
0009 #include <stdint.h>
0010 #endif
0011 
0012 namespace l1t {
0013   class PFTrack;
0014   class PFCluster;
0015   class PFCandidate;
0016   class Muon;
0017 }  // namespace l1t
0018 
0019 // the serialization may be hidden if needed
0020 #include <cmath>
0021 #include <vector>
0022 
0023 namespace l1tpf_impl {
0024 
0025   struct CaloCluster {
0026     int16_t hwPt;
0027     int16_t hwEmPt;
0028     int16_t hwPtErr;
0029     int16_t hwEta;
0030     int16_t hwPhi;
0031     uint16_t hwFlags;
0032     bool isEM, used;
0033     const l1t::PFCluster *src;
0034 
0035     // sorting
0036     bool operator<(const CaloCluster &other) const { return hwPt > other.hwPt; }
0037 
0038 #ifdef L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_MORE
0039     static constexpr float PT_SCALE = 4.0;     // quantize in units of 0.25 GeV (can be changed)
0040     static constexpr float ETAPHI_FACTOR = 4;  // size of an ecal crystal in phi in integer units (our choice)
0041     static constexpr float ETAPHI_SCALE =
0042         ETAPHI_FACTOR *
0043         (180. / M_PI);  // M_PI/180 is the size of an ECal crystal; we make a grid that is 4 times that size
0044     static constexpr int16_t PHI_WRAP = 360 * ETAPHI_FACTOR;  // what is 3.14 in integer
0045 
0046     static int16_t ptToInt16(float pt) {  // avoid overflows
0047       return std::min<float>(round(pt * CaloCluster::PT_SCALE), std::numeric_limits<int16_t>::max());
0048     }
0049 
0050     // filling from floating point
0051     void fill(float pt,
0052               float emPt,
0053               float ptErr,
0054               float eta,
0055               float phi,
0056               bool em,
0057               unsigned int flags,
0058               const l1t::PFCluster *source = nullptr) {
0059       hwPt = CaloCluster::ptToInt16(pt);
0060       hwEmPt = CaloCluster::ptToInt16(emPt);
0061       hwPtErr = CaloCluster::ptToInt16(ptErr);
0062       hwEta = round(eta * CaloCluster::ETAPHI_SCALE);
0063       hwPhi = int16_t(round(phi * CaloCluster::ETAPHI_SCALE)) % CaloCluster::PHI_WRAP;
0064       isEM = em;
0065       used = false;
0066       hwFlags = flags;
0067       src = source;
0068     }
0069 
0070     float floatPt() const { return float(hwPt) / CaloCluster::PT_SCALE; }
0071     float floatEmPt() const { return float(hwEmPt) / CaloCluster::PT_SCALE; }
0072     float floatPtErr() const { return float(hwPtErr) / CaloCluster::PT_SCALE; }
0073     static float minFloatPt() { return float(1.0) / CaloCluster::PT_SCALE; }
0074     float floatEta() const { return float(hwEta) / CaloCluster::ETAPHI_SCALE; }
0075     float floatPhi() const { return float(hwPhi) / CaloCluster::ETAPHI_SCALE; }
0076     void setFloatPt(float pt) { hwPt = round(pt * CaloCluster::PT_SCALE); }
0077     void setFloatEmPt(float emPt) { hwEmPt = round(emPt * CaloCluster::PT_SCALE); }
0078 #endif
0079   };
0080 
0081   // https://twiki.cern.ch/twiki/bin/view/CMS/L1TriggerPhase2InterfaceSpecifications
0082   struct InputTrack {
0083     uint16_t hwInvpt;
0084     int32_t hwVtxEta;
0085     int32_t hwVtxPhi;
0086     bool hwCharge;
0087     int16_t hwZ0;
0088     uint16_t hwChi2, hwStubs;
0089     uint16_t hwFlags;
0090     const l1t::PFTrack *src;
0091 
0092     enum QualityFlags { PFLOOSE = 1, PFTIGHT = 2, TKEG = 4 };
0093     bool quality(QualityFlags q) const { return hwFlags & q; }
0094 
0095 #ifdef L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_MORE
0096     static constexpr float INVPT_SCALE = 2E4;           // 1%/pt @ 100 GeV is 2 bits
0097     static constexpr float VTX_PHI_SCALE = 1 / 1.6E-3;  // 5 micro rad is 2 bits
0098     static constexpr float VTX_ETA_SCALE = 1 / 1E-4;    // no idea, but assume it's somewhat worse than phi
0099     static constexpr float Z0_SCALE = 20;               // 1mm is 2 bits
0100     static constexpr int32_t VTX_ETA_1p3 = 1.3 * InputTrack::VTX_ETA_SCALE;
0101 
0102     // filling from floating point
0103     void fillInput(
0104         float pt, float eta, float phi, int charge, float dz, unsigned int flags, const l1t::PFTrack *source = nullptr) {
0105       hwInvpt = std::min<double>(round(1 / pt * InputTrack::INVPT_SCALE), std::numeric_limits<uint16_t>::max());
0106       hwVtxEta = round(eta * InputTrack::VTX_ETA_SCALE);
0107       hwVtxPhi = round(phi * InputTrack::VTX_PHI_SCALE);
0108       hwCharge = (charge > 0);
0109       hwZ0 = round(dz * InputTrack::Z0_SCALE);
0110       hwFlags = flags;
0111       src = source;
0112     }
0113 
0114     float floatVtxPt() const { return 1 / (float(hwInvpt) / InputTrack::INVPT_SCALE); }
0115     float floatVtxEta() const { return float(hwVtxEta) / InputTrack::VTX_ETA_SCALE; }
0116     float floatVtxPhi() const { return float(hwVtxPhi) / InputTrack::VTX_PHI_SCALE; }
0117     float floatDZ() const { return float(hwZ0) / InputTrack::Z0_SCALE; }
0118     int intCharge() const { return hwCharge ? +1 : -1; }
0119 #endif
0120   };
0121 
0122   struct PropagatedTrack : public InputTrack {
0123     int16_t hwPt;
0124     int16_t hwPtErr;
0125     int16_t hwCaloPtErr;
0126     int16_t hwEta;  // at calo
0127     int16_t hwPhi;  // at calo
0128     bool muonLink;
0129     bool used;  // note: this flag is not used in the default PF, but is used in alternative algos
0130     bool fromPV;
0131 
0132     // sorting
0133     bool operator<(const PropagatedTrack &other) const { return hwPt > other.hwPt; }
0134 
0135 #ifdef L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_MORE
0136     void fillPropagated(
0137         float pt, float ptErr, float caloPtErr, float caloEta, float caloPhi, unsigned int quality, bool isMuon) {
0138       hwPt = CaloCluster::ptToInt16(pt);
0139       hwPtErr = CaloCluster::ptToInt16(ptErr);
0140       hwCaloPtErr = CaloCluster::ptToInt16(caloPtErr);
0141       // saturation protection
0142       if (hwPt == std::numeric_limits<int16_t>::max()) {
0143         hwCaloPtErr = hwPt / 4;
0144       }
0145       hwEta = round(caloEta * CaloCluster::ETAPHI_SCALE);
0146       hwPhi = int16_t(round(caloPhi * CaloCluster::ETAPHI_SCALE)) % CaloCluster::PHI_WRAP;
0147       muonLink = isMuon;
0148       used = false;
0149     }
0150 
0151     float floatPt() const { return float(hwPt) / CaloCluster::PT_SCALE; }
0152     float floatPtErr() const { return float(hwPtErr) / CaloCluster::PT_SCALE; }
0153     float floatCaloPtErr() const { return float(hwCaloPtErr) / CaloCluster::PT_SCALE; }
0154     float floatEta() const { return float(hwEta) / CaloCluster::ETAPHI_SCALE; }
0155     float floatPhi() const { return float(hwPhi) / CaloCluster::ETAPHI_SCALE; }
0156 #endif
0157   };
0158 
0159   struct Muon {
0160     int16_t hwPt;
0161     int16_t hwEta;  // at calo
0162     int16_t hwPhi;  // at calo
0163     uint16_t hwFlags;
0164     bool hwCharge;
0165     const l1t::Muon *src;
0166 
0167     // sorting
0168     bool operator<(const Muon &other) const { return hwPt > other.hwPt; }
0169 
0170 #ifdef L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_MORE
0171     void fill(float pt, float eta, float phi, int charge, unsigned int flags, const l1t::Muon *source = nullptr) {
0172       // we assume we use the same discrete ieta, iphi grid for all particles
0173       hwPt = round(pt * CaloCluster::PT_SCALE);
0174       hwEta = round(eta * CaloCluster::ETAPHI_SCALE);
0175       hwPhi = int16_t(round(phi * CaloCluster::ETAPHI_SCALE)) % CaloCluster::PHI_WRAP;
0176       hwCharge = (charge > 0);
0177       hwFlags = flags;
0178       src = source;
0179     }
0180     float floatPt() const { return float(hwPt) / CaloCluster::PT_SCALE; }
0181     float floatEta() const { return float(hwEta) / CaloCluster::ETAPHI_SCALE; }
0182     float floatPhi() const { return float(hwPhi) / CaloCluster::ETAPHI_SCALE; }
0183     int intCharge() const { return hwCharge ? +1 : -1; }
0184 #endif
0185   };
0186 
0187   struct PFParticle {
0188     int16_t hwPt;
0189     int16_t hwEta;  // at calo face
0190     int16_t hwPhi;
0191     uint8_t hwId;      // CH=0, EL=1, NH=2, GAMMA=3, MU=4
0192     int16_t hwVtxEta;  // propagate back to Vtx for charged particles (if useful?)
0193     int16_t hwVtxPhi;
0194     uint16_t hwFlags;
0195     CaloCluster cluster;
0196     PropagatedTrack track;
0197     bool chargedPV;
0198     uint16_t hwPuppiWeight;
0199     uint16_t hwStatus;  // for debugging
0200     const l1t::Muon *muonsrc;
0201     const l1t::PFCandidate *src;
0202 
0203     // sorting
0204     bool operator<(const PFParticle &other) const { return hwPt > other.hwPt; }
0205 
0206 #ifdef L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_MORE
0207     static constexpr float PUPPI_SCALE = 100;
0208 
0209     float floatPt() const { return float(hwPt) / CaloCluster::PT_SCALE; }
0210     float floatEta() const { return float(hwEta) / CaloCluster::ETAPHI_SCALE; }
0211     float floatPhi() const { return float(hwPhi) / CaloCluster::ETAPHI_SCALE; }
0212     float floatVtxEta() const {
0213       return (track.hwPt > 0 ? track.floatVtxEta() : float(hwVtxEta) / CaloCluster::ETAPHI_SCALE);
0214     }
0215     float floatVtxPhi() const {
0216       return (track.hwPt > 0 ? track.floatVtxPhi() : float(hwVtxPhi) / CaloCluster::ETAPHI_SCALE);
0217     }
0218     float floatDZ() const { return float(track.hwZ0) / InputTrack::Z0_SCALE; }
0219     float floatPuppiW() const { return float(hwPuppiWeight) / PUPPI_SCALE; }
0220     int intCharge() const { return (track.hwPt > 0 ? track.intCharge() : 0); }
0221     void setPuppiW(float w) { hwPuppiWeight = std::round(w * PUPPI_SCALE); }
0222     void setFloatPt(float pt) { hwPt = round(pt * CaloCluster::PT_SCALE); }
0223 #endif
0224   };
0225 
0226   struct EGParticle {
0227     int16_t hwPt;
0228     int16_t hwEta;  // at calo face
0229     int16_t hwPhi;
0230     uint16_t hwQual;
0231 
0232     // FIXME: an index would also do...
0233     CaloCluster cluster;
0234 
0235     // sorting
0236     bool operator<(const EGParticle &other) const { return hwPt > other.hwPt; }
0237 
0238 #ifdef L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_MORE
0239     void setFloatPt(float pt) { hwPt = round(pt * CaloCluster::PT_SCALE); }
0240     float floatPt() const { return float(hwPt) / CaloCluster::PT_SCALE; }
0241     float floatEta() const { return float(hwEta) / CaloCluster::ETAPHI_SCALE; }
0242     float floatPhi() const { return float(hwPhi) / CaloCluster::ETAPHI_SCALE; }
0243 #endif
0244   };
0245 
0246   struct EGIso {
0247     // FIXME: eventually only one iso will be saved
0248     uint16_t hwIso;
0249     uint16_t hwPFIso;
0250 
0251 #ifdef L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_MORE
0252     static constexpr float ISO_SCALE = 100;
0253     void setIso(float iso, uint16_t &hwIso) { hwIso = round(iso * EGIso::ISO_SCALE); }
0254     void setIso(float iso) { setIso(iso, hwIso); }
0255     void setPFIso(float iso) { setIso(iso, hwPFIso); }
0256 
0257     float getFloatIso(uint16_t hwIso) const { return float(hwIso) / EGIso::ISO_SCALE; }
0258     float floatIso() const { return getFloatIso(hwIso); }
0259     float floatPFIso() const { return getFloatIso(hwPFIso); }
0260 #endif
0261   };
0262 
0263   struct EGIsoPV : public EGIso {
0264     uint16_t hwIsoPV;
0265     uint16_t hwPFIsoPV;
0266 
0267 #ifdef L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_MORE
0268     void setIsoPV(float iso) { setIso(iso, hwIsoPV); }
0269     void setPFIsoPV(float iso) { setIso(iso, hwPFIsoPV); }
0270 
0271     float floatIsoPV() const { return getFloatIso(hwIsoPV); }
0272     float floatPFIsoPV() const { return getFloatIso(hwPFIsoPV); }
0273 #endif
0274   };
0275 
0276   struct EGIsoEleParticle : public EGParticle, public EGIso {
0277     // track parameters for electrons
0278     int16_t hwVtxEta;
0279     int16_t hwVtxPhi;
0280     int16_t hwZ0;
0281     bool hwCharge;
0282     PropagatedTrack track;
0283 
0284 #ifdef L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_MORE
0285 
0286     float floatVtxEta() const { return float(hwVtxEta) / InputTrack::VTX_ETA_SCALE; }
0287     float floatVtxPhi() const { return float(hwVtxPhi) / InputTrack::VTX_PHI_SCALE; }
0288     float floatDZ() const { return float(track.hwZ0) / InputTrack::Z0_SCALE; }
0289     int intCharge() const { return hwCharge ? +1 : -1; }
0290 
0291 #endif
0292   };
0293 
0294   struct EGIsoParticle : public EGParticle, public EGIsoPV {
0295 #ifdef L1Trigger_Phase2L1ParticleFlow_DiscretePFInputs_MORE
0296     // NOTE: this is needed because of CMSSW requirements
0297     // i.e. we need to put the EG object and the TkEm and TkEle ones at the same time to have a valid ref
0298     int ele_idx;
0299 #endif
0300   };
0301 
0302   struct InputRegion {
0303     float etaCenter, etaMin, etaMax, phiCenter, phiHalfWidth;
0304     float etaExtra, phiExtra;
0305     std::vector<CaloCluster> calo;
0306     std::vector<CaloCluster> emcalo;
0307     std::vector<PropagatedTrack> track;
0308     std::vector<Muon> muon;
0309 
0310     InputRegion()
0311         : etaCenter(),
0312           etaMin(),
0313           etaMax(),
0314           phiCenter(),
0315           phiHalfWidth(),
0316           etaExtra(),
0317           phiExtra(),
0318           calo(),
0319           emcalo(),
0320           track(),
0321           muon() {}
0322     InputRegion(
0323         float etacenter, float etamin, float etamax, float phicenter, float phihalfwidth, float etaextra, float phiextra)
0324         : etaCenter(etacenter),
0325           etaMin(etamin),
0326           etaMax(etamax),
0327           phiCenter(phicenter),
0328           phiHalfWidth(phihalfwidth),
0329           etaExtra(etaextra),
0330           phiExtra(phiextra),
0331           calo(),
0332           emcalo(),
0333           track(),
0334           muon() {}
0335   };
0336 
0337 }  // namespace l1tpf_impl
0338 #endif