Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-06-20 01:53:32

0001 #ifndef tdr_regionizer_elements_ref_h
0002 #define tdr_regionizer_elements_ref_h
0003 
0004 #include "DataFormats/L1TParticleFlow/interface/layer1_emulator.h"
0005 
0006 #include <vector>
0007 #include <map>
0008 #include <deque>
0009 #include <cassert>
0010 #include <algorithm>
0011 
0012 #include "L1Trigger/Phase2L1ParticleFlow/interface/dbgPrintf.h"
0013 
0014 namespace l1ct {
0015   namespace tdr_regionizer {
0016 
0017     inline int phi_wrap(int local_phi) {
0018       if (local_phi > l1ct::Scales::INTPHI_PI)
0019         local_phi -= l1ct::Scales::INTPHI_TWOPI;
0020       else if (local_phi <= -l1ct::Scales::INTPHI_PI)
0021         local_phi += l1ct::Scales::INTPHI_TWOPI;
0022       return local_phi;
0023     }
0024 
0025     /// corresponds to level1_to_2_pipe_t in firmware
0026     template <typename T>
0027     class PipeEntry {
0028     public:
0029       PipeEntry() : obj_(), sr_(-1) {}
0030       PipeEntry(const T& obj, int sr, int glbeta, int glbphi) : obj_(obj), sr_(sr), glbeta_(glbeta), glbphi_(glbphi) {}
0031 
0032       int sr() const { return sr_; }
0033 
0034       // Note, this returns a copy so you can modify
0035       T obj() const { return obj_; }
0036 
0037       bool valid() const { return sr_ >= 0; }
0038 
0039       void setInvalid() { sr_ = -1; }
0040 
0041       int pt() const { return obj_.intPt(); }
0042       int glbPhi() const { return glbphi_; }
0043       int glbEta() const { return glbeta_; }
0044 
0045     private:
0046       T obj_;
0047       /// the SR linearized indices (can index regionmap_) where this object needs to go; -1 means invalid
0048       int sr_;
0049       /// The global eta and phi of the object (hard to get with duplicates)
0050       int glbeta_, glbphi_;
0051     };
0052 
0053     /// The pipe, with multiple inputs and one output
0054     template <typename T>
0055     class Pipe {
0056     public:
0057       /// if using the default constructor, have to call setTaps before use
0058       Pipe() : pipe_() {}
0059 
0060       Pipe(size_t ntaps) : pipe_(ntaps) {}
0061 
0062       void setTaps(size_t taps) { pipe_.resize(taps); }
0063 
0064       /// check if the entry is valid (i.e. already has data)
0065       bool valid(size_t idx) const { return pipe_.at(idx).valid(); }
0066 
0067       /// should check if valid before adding an entry
0068       void addEntry(size_t idx, const PipeEntry<T>& entry) { pipe_[idx] = entry; }
0069 
0070       /// perform one tick, shifting all the entries to higher indices, and returning the last
0071       PipeEntry<T> popEntry();
0072 
0073       void reset();
0074 
0075       size_t size() const { return pipe_.size(); }
0076 
0077       /// for debug
0078       const PipeEntry<T>& entry(size_t idx) const { return pipe_[idx]; }
0079 
0080     private:
0081       std::vector<PipeEntry<T>> pipe_;
0082     };
0083 
0084     /// The pipe, with multiple inputs and one output
0085     template <typename T>
0086     class Pipes {
0087     public:
0088       /// the number of pipes
0089       Pipes(size_t nregions) : pipes_(nregions / SRS_PER_RAM) {}
0090 
0091       /// set the number of taps in each pipe
0092       void setTaps(size_t taps);
0093 
0094       /// check if the entry is valid (i.e. already has data)
0095       bool valid(int sr, size_t logicBufIdx) const { return pipes_[pipeIndex(sr)].valid(logicBufIdx); }
0096 
0097       /// should check if valid before adding an entry
0098       void addEntry(int sr, size_t logicBufIdx, const PipeEntry<T>& entry) {
0099         pipes_[pipeIndex(sr)].addEntry(logicBufIdx, entry);
0100       }
0101 
0102       /// perform one tick, shifting all the entries to higher indices, and returning the last
0103       PipeEntry<T> popEntry(size_t pipe) { return pipes_[pipe].popEntry(); };
0104 
0105       void reset();
0106 
0107       size_t size() const { return pipes_.size(); }
0108 
0109       size_t numTaps() const { return pipes_.at(0).size(); }
0110 
0111       /// for debug
0112       const PipeEntry<T>& entry(size_t pipe, size_t tap) const { return pipes_[pipe].entry(tap); }
0113 
0114     private:
0115       /// SRs share RAMs (and hardware pipes)
0116       static size_t constexpr SRS_PER_RAM = 2;
0117 
0118       /// Because some SRs share pipes, this determines the pipe index for a linearize SR index
0119       /// (This is based on the VHDL function, get_target_pipe_index_subindex)
0120       size_t pipeIndex(int sr) const { return sr / SRS_PER_RAM; }
0121 
0122       std::vector<Pipe<T>> pipes_;
0123     };
0124 
0125     /// the components that make up the L1 regionizer buffer
0126     template <typename T>
0127     class BufferEntry {
0128     public:
0129       BufferEntry() {}
0130       BufferEntry(const T& obj, std::vector<size_t> srIndices, int glbeta, int glbphi, bool duplicate, unsigned int clk);
0131 
0132       unsigned int clock() const { return linkobjclk_; }
0133       int nextSR() const { return (objcount_ < srIndices_.size()) ? srIndices_[objcount_] : -1; }
0134       void incSR() { objcount_++; }
0135       int pt() const { return obj_.intPt(); }
0136       int glbPhi() const { return glbphi_; }
0137       int glbEta() const { return glbeta_; }
0138       int duplicate() const { return duplicate_; }
0139 
0140       //T obj() { return obj_; }
0141       const T& obj() const { return obj_; }
0142 
0143     private:
0144       T obj_;
0145       /// the SR linearized indices (can index regionmap_) where this object needs to go
0146       std::vector<size_t> srIndices_;
0147       /// The global eta and phi of the object (hard to get with duplicates)
0148       int glbeta_, glbphi_;
0149       /// Is this a duplciate that should be ignored? used for GCT duplicate removal
0150       bool duplicate_;
0151       unsigned int linkobjclk_, objcount_;
0152     };
0153 
0154     /// The L1 regionizer buffer (corresponding to level1_fifo_buffer.vhd)
0155     template <typename T>
0156     class Buffer {
0157     public:
0158       Buffer() : clkindex360_(INIT360), clkindex240_(INIT240), timeOfNextObject_(-1) {}
0159 
0160       void addEntry(const T& obj,
0161                     std::vector<size_t> srs,
0162                     int glbeta,
0163                     int glbphi,
0164                     bool duplicate,       // this is mainly for GCT, is it one of the duplicates
0165                     unsigned int dupNum,  // this is for the (currently unused) feature of multiple buffers per sector
0166                     unsigned int ndup);
0167 
0168       BufferEntry<T>& front() { return data_.front(); }
0169       const BufferEntry<T>& front() const { return data_.front(); }
0170 
0171       /// sets the next time something is taken from this buffer
0172       void updateNextObjectTime(int currentTime, bool incrementTime = true);
0173 
0174       /// delete the front element
0175       void pop() { data_.pop_front(); }
0176 
0177       // mostly for debug
0178       unsigned int clock(unsigned int index = 0) const { return data_[index].clock(); }
0179       int pt(unsigned int index = 0) const { return data_[index].pt(); }
0180       int glbPhi(unsigned int index = 0) const { return data_[index].glbPhi(); }
0181       int glbEta(unsigned int index = 0) const { return data_[index].glbEta(); }
0182       int duplicate(unsigned int index = 0) const { return data_[index].duplicate(); }
0183 
0184       unsigned int numEntries() const { return data_.size(); }
0185 
0186       /// pop the first entry, formatted for inclusion in pipe
0187       PipeEntry<T> popEntry(int currTime, bool debug);
0188 
0189       int timeOfNextObject() const { return timeOfNextObject_; }
0190 
0191       void reset() {
0192         clkindex360_ = INIT360;
0193         clkindex240_ = INIT240;
0194         data_.clear();
0195         timeOfNextObject_ = -1;
0196       }
0197 
0198     private:
0199       // used when building up the linkobjclk_ entries for the BufferEntries
0200       unsigned int nextObjClk(unsigned int ndup, bool skip);  // may need to treat pt == 0 and overlap differently
0201       // transient--used only during event construction, not used after
0202       // Counts in 1.39ns increments (i.e. 360 increments by 2, 240 by 3)
0203       unsigned int clkindex360_;
0204       unsigned int clkindex240_;
0205 
0206       // These values represent at what clock count the first data arrives, counting in 1.39ns increments (2 increments
0207       // for one 360MHz clock period, 3 increments for a 240MHz clock period). The 360 version refers to the data as it
0208       // is transferred over the fibers, while the 240 is for data going to the regionizer. Some data is thrown out in between.
0209       // Both counts are used to determine when the data reaches the regionizer.
0210       static unsigned int constexpr INIT360 = 2;
0211       static unsigned int constexpr INIT240 = 4;
0212 
0213       /// The actual data
0214       std::deque<BufferEntry<T>> data_;
0215 
0216       /// the time of the next object in the buffer (-1 if none)
0217       int timeOfNextObject_;
0218     };
0219 
0220     template <typename T>
0221     class Regionizer {
0222     public:
0223       Regionizer() = delete;
0224       Regionizer(unsigned int neta,
0225                  unsigned int nphi,  //the number of eta and phi SRs in a big region (board)
0226                  unsigned int maxobjects,
0227                  int bigRegionMin,
0228                  int bigRegionMax,  // the phi range covered by this board
0229                  unsigned int nclocks,
0230                  unsigned int ndup = 1,  // how much one duplicates the inputs (to increase processing bandwidth)
0231                  bool debug = false);
0232 
0233       void initSectors(const std::vector<DetectorSector<T>>& sectors);
0234       void initSectors(const DetectorSector<T>& sector);
0235       void initRegions(const std::vector<PFInputRegion>& regions);
0236 
0237       void fillBuffers(const std::vector<DetectorSector<T>>& sectors);
0238       void fillBuffers(const DetectorSector<T>& sector);
0239 
0240       void run();
0241 
0242       void reset();
0243 
0244       /// Return a map of of the SRs indexed by SR index (covering only those from board)
0245       std::map<size_t, std::vector<T>> fillRegions(bool doSort);
0246 
0247       void printDebug(int count) const;
0248 
0249     private:
0250       /// is the given small region in the big region
0251       bool isInBigRegion(const PFRegionEmu& reg) const;
0252 
0253       /// Does the given region fit in the big region, taking into account overlaps?
0254       bool isInBigRegionLoose(const PFRegionEmu& reg) const;
0255 
0256       unsigned int numBuffers() const { return buffers_.size(); }
0257       unsigned int numEntries(unsigned int bufferIndex) const { return buffers_[bufferIndex].numEntries(); }
0258 
0259       std::vector<size_t> getSmallRegions(int glbeta, int glbphi) const;
0260 
0261       void addToBuffer(const T& obj, unsigned int index, unsigned int dupNum);
0262       void setBuffer(const std::vector<T>& objvec, unsigned int index);
0263       void setBuffers(const std::vector<std::vector<T>>&& objvecvec);
0264 
0265       /// This retruns the linearized small region associated with the given item (-1 is throwout)
0266       int nextSR(unsigned int linknum, unsigned int index = 0) { return buffers_[linknum].nextSR(index); }
0267 
0268       /// 'put' object in small region
0269       void addToSmallRegion(PipeEntry<T>&&);
0270 
0271       /// returns 2D arrays, sectors (links) first dimension, objects second
0272       std::vector<std::vector<T>> fillLinks(const std::vector<DetectorSector<T>>& sectors) const;
0273       std::vector<std::vector<T>> fillLinks(const DetectorSector<T>& sector) const;
0274 
0275       // this function is for sorting small regions first in phi and then in eta.
0276       // It takes regions_ indices
0277       bool sortRegionsRegular(size_t a, size_t b) const;
0278 
0279       bool sortSectors(size_t a, size_t b) const;
0280 
0281       bool sortRegionsHelper(int etaa, int etab, int phia, int phib) const;
0282 
0283       /// get the index in regions_ for a particular SR.
0284       size_t regionIndex(int sr) const { return regionmap_.at(sr); }
0285 
0286       /// get the logical buffer index (i.e. the index in the order in the firmware)
0287       size_t logicBuffIndex(size_t bufIdx) const;
0288 
0289       /// GCT sends duplicates. This indicates if an entry is a duplicate
0290       /// For other objects, it always returns false
0291       bool isDuplicate(int locphi, size_t logicBufIdx) const;
0292 
0293       /// The numbers of eta and phi in a big region (board)
0294       unsigned int neta_, nphi_;
0295       /// The maximum number of objects to output per small region
0296       unsigned int maxobjects_;
0297       /// The number of input sectors for this type of device
0298       unsigned int nsectors_;
0299       /// the minimum phi of this board
0300       int bigRegionMin_;
0301       /// the maximum phi of this board
0302       int bigRegionMax_;
0303       /// the number of clocks to receive one event
0304       unsigned int nclocks_;
0305       /// How many buffers per link (default 1)
0306       unsigned int ndup_;
0307 
0308       /// the region information associated with each input sector
0309       std::vector<l1ct::PFRegionEmu> sectors_;
0310 
0311       /// the region information associated with each SR
0312       std::vector<l1ct::PFRegionEmu> regions_;
0313 
0314       /// indices of regions that are in the big region (board)
0315       std::vector<size_t> regionmap_;
0316 
0317       /// indices maps the sectors from the way they appear in the software to the (logical) order they are done in the regionizer firmware
0318       std::vector<size_t> sectorMapPhysToLog_;
0319 
0320       /// the inverse mapping of sectormap_ (only used for debug printing)
0321       std::vector<size_t> sectorMapLogToPhys_;
0322 
0323       /// The buffers. There are ndup_ buffers per link/sector
0324       std::vector<Buffer<T>> buffers_;
0325 
0326       /// The pipes, one per ram (see SRS_PER_RAM)
0327       Pipes<T> pipes_;
0328 
0329       /// The objects in each small region handled in board; Indexing corresponds to that in regionmap_
0330       std::vector<std::vector<T>> smallRegionObjects_;
0331 
0332       /// Whether this is the first event (since timing is a bit different then)
0333       bool firstEvent_;
0334 
0335       /// This is the delay (only applied after first event) before processing starts
0336       static unsigned int constexpr DELAY_TO_START = 10;
0337 
0338       bool debug_;
0339     };
0340 
0341   }  // namespace  tdr_regionizer
0342 }  // namespace l1ct
0343 
0344 #endif