Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 #include <stdexcept>
0002 
0003 #include "L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.h"
0004 
0005 // PIPE ENTRY AND BUFFER
0006 template <typename T>
0007 l1ct::tdr_regionizer::PipeEntry<T> l1ct::tdr_regionizer::Pipe<T>::popEntry() {
0008   assert(pipe_.size() > 0);
0009   auto last = pipe_.back();
0010   // shift one over
0011   for (size_t i = pipe_.size() - 1; i > 0; --i) {
0012     pipe_[i] = pipe_[i - 1];
0013   }
0014   pipe_[0].setInvalid();
0015   return last;
0016 }
0017 
0018 template <typename T>
0019 void l1ct::tdr_regionizer::Pipe<T>::reset() {
0020   for (auto& pe : pipe_) {
0021     pe.setInvalid();
0022   }
0023 }
0024 
0025 template <typename T>
0026 void l1ct::tdr_regionizer::Pipes<T>::reset() {
0027   for (auto& pipe : pipes_) {
0028     pipe.reset();
0029   }
0030 }
0031 
0032 template <typename T>
0033 void l1ct::tdr_regionizer::Pipes<T>::setTaps(size_t taps) {
0034   for (auto& pipe : pipes_) {
0035     pipe.setTaps(taps);
0036   }
0037 }
0038 
0039 // BUFFER ENTRY AND BUFFER
0040 template <typename T>
0041 l1ct::tdr_regionizer::BufferEntry<T>::BufferEntry(
0042     const T& obj, std::vector<size_t> srIndices, int glbeta, int glbphi, bool duplicate, unsigned int clk)
0043     : obj_(obj), srIndices_(srIndices), glbeta_(glbeta), glbphi_(glbphi), duplicate_(duplicate), linkobjclk_(clk) {
0044   objcount_ = 0;
0045 }
0046 
0047 template <typename T>
0048 inline void l1ct::tdr_regionizer::Buffer<T>::addEntry(
0049     const T& obj,
0050     std::vector<size_t> srIndices,
0051     int glbeta,
0052     int glbphi,
0053     bool duplicate,  // this is mainly for GCT, is it one of the duplicates
0054     unsigned int dupNum,
0055     unsigned int ndup) {
0056   // dupNum is the duplicate number of this buffer (int range 0 to ndup_-1)
0057   auto objClk = nextObjClk(ndup, obj.intPt() == 0);
0058   data_.emplace_back(obj, srIndices, glbeta, glbphi, duplicate, objClk);
0059   if (timeOfNextObject_ < 0) {
0060     timeOfNextObject_ = objClk;
0061   }
0062 }
0063 
0064 template <typename T>
0065 void l1ct::tdr_regionizer::Buffer<T>::updateNextObjectTime(int currTime, bool incrementTime) {
0066   if (data_.size() > 0) {
0067     auto nextTime = incrementTime ? currTime + 1 : currTime;
0068     timeOfNextObject_ = std::max(front().clock(), static_cast<unsigned int>(nextTime));
0069   } else {
0070     timeOfNextObject_ = -1;
0071   }
0072 }
0073 
0074 template <typename T>
0075 inline unsigned int l1ct::tdr_regionizer::Buffer<T>::nextObjClk(unsigned int ndup, bool skip) {
0076   unsigned int nextVal = std::max(clkindex360_, clkindex240_) / 3;
0077 
0078   clkindex360_ += 2 * ndup;
0079 
0080   // Though a 360MHz clock is used, one doesn't need to a 240MHz clock for pt == 0
0081   if (!skip) {
0082     clkindex240_ += 3;
0083   }
0084   return nextVal;
0085 }
0086 
0087 // explicit for tracks
0088 template <>
0089 inline unsigned int l1ct::tdr_regionizer::Buffer<l1ct::TkObjEmu>::nextObjClk(unsigned int ndup, bool skip) {
0090   if (ndup != 1) {
0091     throw std::invalid_argument("Only ndup==1 is currently supported for the TkObjEmu buffers.");
0092   }
0093 
0094   unsigned int nextVal = std::max(clkindex360_, clkindex240_) / 3;
0095 
0096   clkindex360_ += 2;
0097   if ((clkindex360_ - INIT360) % 6 == 4) {
0098     clkindex360_ += 2;
0099   }
0100 
0101   if (!skip) {
0102     clkindex240_ += 3;
0103   }
0104   return nextVal;
0105 }
0106 
0107 template <typename T>
0108 l1ct::tdr_regionizer::PipeEntry<T> l1ct::tdr_regionizer::Buffer<T>::popEntry(int currTime, bool debug) {
0109   if (front().nextSR() < 0) {
0110     // throwout
0111     pop();
0112     if (debug) {
0113       dbgCout() << "updating time clock = " << front().clock() << ", currTime = " << currTime << std::endl;
0114     }
0115     updateNextObjectTime(currTime);
0116     return l1ct::tdr_regionizer::PipeEntry<T>();
0117   }
0118 
0119   auto pipeEntry =
0120       l1ct::tdr_regionizer::PipeEntry<T>(front().obj(), front().nextSR(), front().glbEta(), front().glbPhi());
0121   front().incSR();
0122   if (front().nextSR() < 0) {
0123     // no more SRs for current front
0124     pop();
0125   } else {
0126     if (debug) {
0127       dbgCout() << "Remain on same object, nextSR = " << front().nextSR() << std::endl;
0128     }
0129     // this is a processing_stall, but throwouts that follow can still be dropped
0130     // due to the pipeline have to look two ticks back
0131     if (numEntries() > 1 && data_[1].nextSR() == -1 && static_cast<int>(data_[1].clock()) == currTime + 2) {
0132       if (debug) {
0133         dbgCout() << "removing a following throwout with time " << data_[1].clock() << std::endl;
0134       }
0135       data_.erase(data_.begin() + 1);
0136     } else if (numEntries() > 2 && data_[2].nextSR() == -1 && static_cast<int>(data_[2].clock()) <= currTime + 2) {
0137       if (debug) {
0138         dbgCout() << "removing the two-back throwout with time " << data_[2].clock() << std::endl;
0139       }
0140       data_.erase(data_.begin() + 2);
0141     }
0142   }
0143   if (debug) {
0144     dbgCout() << "updating time clock = " << front().clock() << ", currTime = " << currTime << std::endl;
0145   }
0146 
0147   updateNextObjectTime(currTime);
0148   return pipeEntry;
0149 }
0150 
0151 // REGIONIZER
0152 template <typename T>
0153 l1ct::tdr_regionizer::Regionizer<T>::Regionizer(unsigned int neta,
0154                                                 unsigned int nphi,
0155                                                 unsigned int maxobjects,
0156                                                 int bigRegionMin,
0157                                                 int bigRegionMax,
0158                                                 unsigned int nclocks,
0159                                                 unsigned int ndup,
0160                                                 bool debug)
0161     : neta_(neta),
0162       nphi_(nphi),
0163       maxobjects_(maxobjects),
0164       nsectors_(0),
0165       bigRegionMin_(bigRegionMin),
0166       bigRegionMax_(bigRegionMax),
0167       nclocks_(nclocks),
0168       ndup_(ndup),
0169       pipes_(neta * nphi),
0170       smallRegionObjects_(neta * nphi),
0171       firstEvent_(true),
0172       debug_(debug) {}
0173 
0174 template <typename T>
0175 void l1ct::tdr_regionizer::Regionizer<T>::initSectors(const std::vector<DetectorSector<T>>& sectors) {
0176   assert(nsectors_ == 0);
0177 
0178   // we need a mapping of physical (what's in the sectors variable) to logical,
0179   // but it's easier to create the inverse, first
0180 
0181   if (debug_) {
0182     dbgCout() << "sectors.size() = " << sectors.size() << std::endl;
0183   }
0184 
0185   for (const auto& sector : sectors) {
0186     if (debug_) {
0187       dbgCout() << "intEtaCenter() = " << sector.region.intEtaCenter()
0188                 << ", intPhiCenter() = " << sector.region.intPhiCenter() << std::endl;
0189     }
0190     if (isInBigRegionLoose(sector.region)) {
0191       sectorMapLogToPhys_.push_back(sectors_.size());
0192       sectors_.push_back(sector.region);
0193     }
0194   }
0195   nsectors_ = sectors_.size();
0196   buffers_.resize(nsectors_ * ndup_);
0197 
0198   std::sort(sectorMapLogToPhys_.begin(), sectorMapLogToPhys_.end(), [this](size_t a, size_t b) {
0199     return this->sortSectors(a, b);
0200   });
0201   if (debug_) {
0202     for (auto val : sectorMapLogToPhys_) {
0203       dbgCout() << "sectorMapLogToPhys phys index = " << val << ", eta = " << sectors_[val].intEtaCenter()
0204                 << ", phi = " << sectors_[val].intPhiCenter() << std::endl;
0205     }
0206   }
0207 
0208   // now invert the sectorMapLogToPhys_
0209   sectorMapPhysToLog_.resize(sectorMapLogToPhys_.size());
0210   for (size_t i = 0; i < sectorMapLogToPhys_.size(); ++i) {
0211     sectorMapPhysToLog_[sectorMapLogToPhys_[i]] = i;
0212   }
0213 
0214   pipes_.setTaps(nsectors_ * ndup_);
0215 }
0216 
0217 template <typename T>
0218 void l1ct::tdr_regionizer::Regionizer<T>::initSectors(const DetectorSector<T>& sector) {
0219   assert(nsectors_ == 0);
0220   nsectors_ = 1;
0221   sectors_.push_back(sector.region);
0222   sectorMapLogToPhys_.push_back(0);
0223   sectorMapPhysToLog_.push_back(0);
0224   buffers_.resize(nsectors_ * ndup_);
0225   if (debug_) {
0226     dbgCout() << "Number of sectors: " << nsectors_ << std::endl;
0227   }
0228   pipes_.setTaps(nsectors_ * ndup_);
0229 }
0230 
0231 template <typename T>
0232 void l1ct::tdr_regionizer::Regionizer<T>::fillBuffers(const std::vector<DetectorSector<T>>& sectors) {
0233   setBuffers(fillLinks(sectors));
0234 }
0235 
0236 template <typename T>
0237 void l1ct::tdr_regionizer::Regionizer<T>::fillBuffers(const DetectorSector<T>& sector) {
0238   setBuffers(fillLinks(sector));
0239 }
0240 
0241 // this function is for sorting small regions
0242 // in eta first, then in phi
0243 template <typename T>
0244 bool l1ct::tdr_regionizer::Regionizer<T>::sortRegionsRegular(size_t a, size_t b) const {
0245   // first do eta
0246   auto etaa = regions_[a].intEtaCenter();
0247   auto etab = regions_[b].intEtaCenter();
0248   auto phia = regions_[a].intPhiCenter();
0249   auto phib = regions_[b].intPhiCenter();
0250   return sortRegionsHelper(etaa, etab, phia, phib);
0251 }
0252 
0253 // this function is for sorting small regions
0254 // in eta first, then in phi
0255 template <typename T>
0256 bool l1ct::tdr_regionizer::Regionizer<T>::sortRegionsHelper(int etaa, int etab, int phia, int phib) const {
0257   // first do eta
0258   if (etaa < etab) {
0259     return true;
0260   } else if (etaa > etab) {
0261     return false;
0262   }
0263 
0264   // if here, then etaa == etab, move to phi
0265   if (bigRegionMax_ < bigRegionMin_) {
0266     // the wraparound case, rewrap around pi
0267     if (phia < 0) {
0268       phia += l1ct::Scales::INTPHI_TWOPI;
0269     }
0270     if (phib < 0) {
0271       phib += l1ct::Scales::INTPHI_TWOPI;
0272     }
0273   }
0274   // regular phi
0275   if (phia < phib) {
0276     return true;
0277   } else {
0278     return false;
0279   }
0280 }
0281 
0282 // this function is for sorting the sectors
0283 // in eta first, then in phi
0284 template <typename T>
0285 bool l1ct::tdr_regionizer::Regionizer<T>::sortSectors(size_t a, size_t b) const {
0286   // first do eta
0287   auto etaa = sectors_[a].intEtaCenter();
0288   auto etab = sectors_[b].intEtaCenter();
0289   auto phia = sectors_[a].intPhiCenter();
0290   auto phib = sectors_[b].intPhiCenter();
0291   return sortRegionsHelper(etaa, etab, phia, phib);
0292 }
0293 
0294 template <typename T>
0295 void l1ct::tdr_regionizer::Regionizer<T>::initRegions(const std::vector<PFInputRegion>& regions) {
0296   regions_.resize(regions.size());
0297   for (unsigned int i = 0; i < regions.size(); ++i) {
0298     regions_[i] = regions[i].region;
0299     if (isInBigRegion(regions_[i])) {
0300       regionmap_.push_back(i);
0301       if (debug_) {
0302         dbgCout() << "region [" << i << "] eta/phi: " << regions_[i].intEtaCenter() << " " << regions_[i].intPhiCenter()
0303                   << ", eta half width = " << regions_[i].hwEtaHalfWidth.to_int()
0304                   << ", phi half width = " << regions_[i].hwPhiHalfWidth.to_int()
0305                   << ", eta extra = " << regions_[i].hwEtaExtra.to_int()
0306                   << ", phi extra = " << regions_[i].hwPhiExtra.to_int() << std::endl;
0307       }
0308     }
0309   }
0310   assert(regionmap_.size() == neta_ * nphi_);
0311   std::sort(
0312       regionmap_.begin(), regionmap_.end(), [this](size_t a, size_t b) { return this->sortRegionsRegular(a, b); });
0313 }
0314 
0315 template <typename T>
0316 bool l1ct::tdr_regionizer::Regionizer<T>::isInBigRegion(const PFRegionEmu& reg) const {
0317   auto phi = reg.intPhiCenter();
0318   if (bigRegionMax_ < bigRegionMin_) {
0319     // the wraparound case
0320     return phi > bigRegionMin_ || phi < bigRegionMax_;
0321   } else {
0322     // the normal case
0323     return phi > bigRegionMin_ && phi < bigRegionMax_;
0324   }
0325 }
0326 
0327 template <typename T>
0328 bool l1ct::tdr_regionizer::Regionizer<T>::isInBigRegionLoose(const PFRegionEmu& reg) const {
0329   auto phi = reg.intPhiCenter();
0330   auto brmax = phi_wrap(bigRegionMax_ + reg.hwPhiHalfWidth.to_int() + reg.hwPhiExtra.to_int());
0331   auto brmin = phi_wrap(bigRegionMin_ - reg.hwPhiHalfWidth.to_int() - reg.hwPhiExtra.to_int());
0332   if (brmax < brmin) {
0333     // the wraparound case
0334     return phi > brmin || phi < brmax;
0335   } else {
0336     // the normal case
0337     return phi > brmin && phi < brmax;
0338   }
0339 }
0340 
0341 template <>
0342 inline bool l1ct::tdr_regionizer::Regionizer<l1ct::HadCaloObjEmu>::isInBigRegionLoose(const PFRegionEmu& reg) const {
0343   return isInBigRegion(reg);
0344 }
0345 
0346 template <>
0347 inline bool l1ct::tdr_regionizer::Regionizer<l1ct::EmCaloObjEmu>::isInBigRegionLoose(const PFRegionEmu& reg) const {
0348   return isInBigRegion(reg);
0349 }
0350 
0351 template <>
0352 inline bool l1ct::tdr_regionizer::Regionizer<l1ct::TkObjEmu>::isInBigRegionLoose(const PFRegionEmu& reg) const {
0353   auto phi = reg.intPhiCenter();
0354   auto brmax = phi_wrap(bigRegionMax_ + 2 * reg.hwPhiHalfWidth.to_int());
0355   auto brmin = phi_wrap(bigRegionMin_ - 2 * reg.hwPhiHalfWidth.to_int());
0356   if (brmax < brmin) {
0357     // the wraparound case
0358     return phi > brmin || phi < brmax;
0359   } else {
0360     // the normal case
0361     return phi > brmin && phi < brmax;
0362   }
0363 }
0364 
0365 template <typename T>
0366 std::vector<size_t> l1ct::tdr_regionizer::Regionizer<T>::getSmallRegions(int glbeta, int glbphi) const {
0367   std::vector<size_t> srIndices;  // the signal regions this object should go into
0368 
0369   // only iterate over regions covered by board
0370   for (size_t i = 0; i < regionmap_.size(); i++) {
0371     auto regionidx = regionIndex(i);
0372     int regphi = phi_wrap(glbphi - regions_[regionidx].intPhiCenter());
0373     int regeta = glbeta - regions_[regionidx].intEtaCenter();
0374 
0375     // add a special check to not have 3 eta regions
0376     if (regions_[regionidx].isInside(regeta, regphi) &&
0377         !((glbeta == 57 && regeta == -115) || (glbeta == -57 && regeta == 115))) {
0378       srIndices.push_back(i);
0379     }
0380   }
0381 
0382   // In a silly convention, the order of these nneds to be modified if there are 4.
0383   if (srIndices.size() == 4) {
0384     auto ent1 = srIndices[1];
0385     srIndices[1] = srIndices[2];
0386     srIndices[2] = ent1;
0387   }
0388   return srIndices;
0389 }
0390 
0391 template <typename T>
0392 void l1ct::tdr_regionizer::Regionizer<T>::addToBuffer(const T& obj, unsigned int buffer, unsigned int dupNum) {
0393   assert(buffer < numBuffers());
0394   const unsigned int sector = buffer / ndup_;
0395   auto glbphi = sectors_[sector].hwGlbPhiOf(obj).to_int();
0396   auto glbeta = sectors_[sector].hwGlbEtaOf(obj).to_int();
0397   // get the SR indices that this object should go into
0398   buffers_[buffer].addEntry(obj,
0399                             getSmallRegions(glbeta, glbphi),
0400                             glbeta,
0401                             glbphi,
0402                             isDuplicate(obj.hwPhi.to_int(), logicBuffIndex(buffer)),
0403                             dupNum,
0404                             ndup_);
0405 }
0406 
0407 template <typename T>
0408 void l1ct::tdr_regionizer::Regionizer<T>::setBuffer(const std::vector<T>& objvec, unsigned int buffer) {
0409   assert(buffer < numBuffers());
0410   buffers_[buffer].reset();
0411   unsigned int dupNum = buffer % ndup_;
0412   for (unsigned int i = dupNum; i < objvec.size(); i += ndup_) {
0413     if (debug_) {
0414       dbgCout() << "Buffer " << buffer << " dupNum " << dupNum << ": add obj, index " << i
0415                 << " with pt = " << objvec[i].intPt() << std::endl;
0416     }
0417     addToBuffer(objvec[i], buffer, dupNum);
0418   }
0419 }
0420 
0421 template <typename T>
0422 void l1ct::tdr_regionizer::Regionizer<T>::setBuffers(const std::vector<std::vector<T>>&& objvecvec) {
0423   assert(numBuffers() == objvecvec.size() * ndup_);
0424   for (unsigned int buffer = 0; buffer < numBuffers(); buffer++) {
0425     setBuffer(objvecvec[buffer / ndup_], buffer);
0426   }
0427 }
0428 
0429 template <typename T>
0430 void l1ct::tdr_regionizer::Regionizer<T>::addToSmallRegion(l1ct::tdr_regionizer::PipeEntry<T>&& pipeEntry) {
0431   if (pipeEntry.valid()) {
0432     auto rawObj = pipeEntry.obj();
0433 
0434     // in small region, the relative eta and phi are based on a different center, so need to update
0435     auto realRegIdx = regionIndex(pipeEntry.sr());
0436     auto etaC = regions_[realRegIdx].intEtaCenter();
0437     auto phiC = regions_[realRegIdx].intPhiCenter();
0438 
0439     int locEta = pipeEntry.glbEta() - etaC;
0440     int locPhi = phi_wrap(pipeEntry.glbPhi() - phiC);
0441 
0442     rawObj.hwEta = locEta;
0443     rawObj.hwPhi = locPhi;
0444 
0445     smallRegionObjects_[pipeEntry.sr()].push_back(rawObj);
0446   }
0447 }
0448 
0449 template <typename T>
0450 void l1ct::tdr_regionizer::Regionizer<T>::run() {
0451   if (debug_)
0452     printDebug(-1);
0453 
0454   // first event doesn't have a delayed start
0455   int startTime = firstEvent_ ? 0 : DELAY_TO_START;
0456   firstEvent_ = false;
0457 
0458   for (int currTime = startTime; currTime < 972 + startTime;
0459        currTime++) {  //this is the max allowable if nothing ever blocks
0460                       // not positive where 972 comes from. It seems to be 162 * 6
0461 
0462     // to exit early
0463     bool processedAll = true;  // to be overwritten if not the case
0464 
0465     // handle the fifo buffers
0466     for (size_t bufIdx = 0; bufIdx < buffers_.size(); ++bufIdx) {
0467       auto& buffer = buffers_[bufIdx];
0468       if (buffer.timeOfNextObject() >= 0) {
0469         processedAll = false;
0470       }
0471       while (buffer.timeOfNextObject() == currTime) {
0472         // time to handle the buffer entry
0473         const auto nextSR = buffer.front().nextSR();
0474         if (debug_) {
0475           dbgCout() << "Current time " << currTime << ", handling bufIdx " << bufIdx << ", logical "
0476                     << logicBuffIndex(bufIdx) << " object with SR = " << nextSR << ", pt = " << buffer.pt()
0477                     << ", glbeta = " << buffer.glbEta() << ", glbphi = " << buffer.glbPhi()
0478                     << ", duplicate = " << buffer.duplicate() << std::endl;
0479         }
0480         if (buffer.pt() == 0) {  // double check that this also works for tracks
0481           if (debug_) {
0482             dbgCout() << "---Throw out, don't increment time" << std::endl;
0483           }
0484           buffer.pop();
0485           buffer.updateNextObjectTime(currTime, false);  // do not increment time
0486         } else if (buffer.duplicate()) {
0487           // remove the whole object, not worrying about nextSR
0488           if (debug_) {
0489             dbgCout() << "---Throw out, duplicate, increment time" << std::endl;
0490           }
0491           buffer.pop();
0492           buffer.updateNextObjectTime(currTime);  // do increment time
0493         } else if (nextSR < 0 || smallRegionObjects_[nextSR].size() == maxobjects_) {
0494           // throwout or SR full, just get rid of object
0495           if (debug_) {
0496             dbgCout() << "---Throw out" << std::endl;
0497           }
0498           buffer.popEntry(currTime, debug_);
0499         } else {
0500           const auto logicBufIdx = logicBuffIndex(bufIdx);
0501           if (pipes_.valid(nextSR, logicBufIdx)) {
0502             // The pipe already has an entry, so wait till space is available
0503             buffer.updateNextObjectTime(currTime);
0504           } else {
0505             // put the value in the pipe
0506             pipes_.addEntry(nextSR, logicBufIdx, buffer.popEntry(currTime, debug_));
0507           }
0508         }
0509       }
0510     }
0511 
0512     if (debug_)
0513       printDebug(currTime);
0514 
0515     // add the small regions
0516     for (size_t i = 0; i < pipes_.size(); i++) {
0517       addToSmallRegion(pipes_.popEntry(i));
0518     }
0519 
0520     // check ot see if you have processed all
0521     if (processedAll) {
0522       // first clear the pipes
0523       for (size_t tap = 0; tap < pipes_.numTaps(); tap++) {
0524         // add the small regions
0525         for (size_t i = 0; i < pipes_.size(); i++) {
0526           addToSmallRegion(pipes_.popEntry(i));
0527         }
0528       }
0529       if (debug_)
0530         printDebug(2000);
0531       break;
0532     }
0533   }  //end main loop
0534 }
0535 
0536 template <typename T>
0537 void l1ct::tdr_regionizer::Regionizer<T>::reset() {
0538   for (auto& buffer : buffers_) {
0539     buffer.reset();
0540   }
0541   pipes_.reset();
0542   for (auto& smallRegionObject : smallRegionObjects_) {
0543     smallRegionObject.clear();
0544   }
0545   firstEvent_ = true;
0546 }
0547 
0548 template <typename T>
0549 std::map<size_t, std::vector<T>> l1ct::tdr_regionizer::Regionizer<T>::fillRegions(bool doSort) {
0550   std::map<size_t, std::vector<T>> srMap;
0551   for (size_t sr = 0; sr < smallRegionObjects_.size(); sr++) {
0552     srMap[regionIndex(sr)] = smallRegionObjects_[sr];
0553     if (doSort) {
0554       std::sort(srMap[regionIndex(sr)].begin(), srMap[regionIndex(sr)].end(), std::greater<>());
0555     }
0556   }
0557   return srMap;
0558 }
0559 
0560 template <typename T>
0561 size_t l1ct::tdr_regionizer::Regionizer<T>::logicBuffIndex(size_t bufIdx) const {
0562   const unsigned int sector = bufIdx / ndup_;
0563   auto logSector = sectorMapPhysToLog_[sector];
0564   return logSector * ndup_ + bufIdx % ndup_;
0565 }
0566 
0567 // default is no duplicates. Note, locPhi is for the sector, not small region
0568 template <typename T>
0569 bool l1ct::tdr_regionizer::Regionizer<T>::isDuplicate(int locphi, size_t logicBufIdx) const {
0570   return false;
0571 }
0572 
0573 // specialize for GCT  (CHECK ESPECIALLY EDGES)
0574 template <>
0575 inline bool l1ct::tdr_regionizer::Regionizer<l1ct::HadCaloObjEmu>::isDuplicate(int locphi, size_t logicBufIdx) const {
0576   auto odd = logicBufIdx % 2;
0577   if (odd) {
0578     return locphi <= -120;
0579   } else {
0580     return locphi > 120;
0581   }
0582 }
0583 
0584 template <>
0585 inline bool l1ct::tdr_regionizer::Regionizer<l1ct::EmCaloObjEmu>::isDuplicate(int locphi, size_t logicBufIdx) const {
0586   auto odd = logicBufIdx % 2;
0587   if (odd) {
0588     return locphi <= -120;
0589   } else {
0590     return locphi > 120;
0591   }
0592 }
0593 
0594 template <typename T>
0595 void l1ct::tdr_regionizer::Regionizer<T>::printDebug(int count) const {
0596   dbgCout() << "BUFFERS, (for " << numBuffers() << " buffers)" << std::endl;
0597   dbgCout() << count << "\tbuffer\tlogical\titem\tpt\teta\tphi\tduplicate\tclock" << std::endl;
0598   for (auto sector : sectorMapLogToPhys_) {
0599     for (unsigned int dup = 0; dup < ndup_; dup++) {
0600       const unsigned int buffer = sector * ndup_ + dup;
0601       for (unsigned int j = 0; j < numEntries(buffer); j++) {
0602         dbgCout() << "\t" << buffer << "\t" << logicBuffIndex(buffer) << "\t" << j << "\t" << buffers_[buffer].pt(j)
0603                   << "\t" << buffers_[buffer].glbEta(j) << "\t" << buffers_[buffer].glbPhi(j) << "\t"
0604                   << buffers_[buffer].duplicate(j) << "\t" << buffers_[buffer].clock(j) << std::endl;
0605       }
0606       dbgCout() << "-------------------------------" << std::endl;
0607     }
0608   }
0609   dbgCout() << "PIPES, (for " << pipes_.size() << " pipes)" << std::endl;
0610   dbgCout() << count << "\tpipe\ttap\tsr\tpt\teta\tphi" << std::endl;
0611   for (int tap = pipes_.numTaps() - 1; tap >= 0; --tap) {
0612     for (int pipe = pipes_.size() - 1; pipe >= 0; --pipe) {
0613       auto entry = pipes_.entry(pipe, tap);
0614       dbgCout() << "\t" << pipe << "\t" << tap + 1 << "\t" << entry.sr() << "\t" << entry.pt() << "\t" << entry.glbEta()
0615                 << "\t" << entry.glbPhi() << std::endl;
0616     }
0617     dbgCout() << "-------------------------------" << std::endl;
0618   }
0619 
0620   dbgCout() << "SMALL REGIONS" << std::endl;
0621   for (unsigned int region = 0; region < neta_ * nphi_; region++) {
0622     dbgCout() << count << "\tregion\t\titem\tpt\tloceta\tlocphi" << std::endl;
0623     auto realRegIdx = regionIndex(region);
0624     auto etaC = regions_[realRegIdx].intEtaCenter();
0625     auto phiC = regions_[realRegIdx].intPhiCenter();
0626     for (unsigned int j = 0; j < smallRegionObjects_[region].size(); j++) {
0627       dbgCout() << "\t" << region << " (" << etaC << ", " << phiC << ")\t" << j << "\t"
0628                 << smallRegionObjects_[region][j].intPt() << "\t" << smallRegionObjects_[region][j].intEta() << "\t"
0629                 << smallRegionObjects_[region][j].intPhi() << std::endl;
0630     }
0631     dbgCout() << "-------------------------------" << std::endl;
0632   }
0633   dbgCout() << "TIMES" << std::endl;
0634   for (unsigned int i = 0; i < numBuffers(); i++) {
0635     dbgCout() << "  " << buffers_[i].timeOfNextObject();
0636   }
0637   dbgCout() << "\n-------------------------------" << std::endl;
0638 }
0639 
0640 // returns 2D arrays, sectors (links) first dimension, objects second
0641 template <typename T>
0642 std::vector<std::vector<T>> l1ct::tdr_regionizer::Regionizer<T>::fillLinks(
0643     const std::vector<DetectorSector<T>>& sectors) const {
0644   std::vector<std::vector<T>> links;
0645 
0646   if (maxobjects_ == 0) {
0647     return links;
0648   }
0649   //one link per sector
0650   for (const auto& sector : sectors) {
0651     if (isInBigRegionLoose(sector.region)) {
0652       links.emplace_back();
0653       for (unsigned int io = 0; io < sector.size() && io < nclocks_; io++) {
0654         links.back().push_back(sector[io]);
0655       }
0656     }
0657   }
0658 
0659   return links;
0660 }
0661 
0662 template <typename T>
0663 std::vector<std::vector<T>> l1ct::tdr_regionizer::Regionizer<T>::fillLinks(const DetectorSector<T>& sector) const {
0664   std::vector<std::vector<T>> links;
0665 
0666   if (maxobjects_ == 0) {
0667     return links;
0668   }
0669 
0670   links.emplace_back();
0671   for (unsigned int io = 0; io < sector.size() && io < nclocks_; io++) {
0672     links.back().push_back(sector[io]);
0673   }
0674   return links;
0675 }