Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-06-03 00:12:13

0001 #include "L1Trigger/TrackerDTC/interface/DTC.h"
0002 
0003 #include <vector>
0004 #include <iterator>
0005 #include <algorithm>
0006 #include <numeric>
0007 
0008 namespace trackerDTC {
0009 
0010   DTC::DTC(const tt::Setup* setup,
0011            const trackerTFP::DataFormats* dataFormats,
0012            const LayerEncoding* layerEncoding,
0013            int dtcId,
0014            const std::vector<std::vector<TTStubRef>>& stubsDTC)
0015       : setup_(setup),
0016         dataFormats_(dataFormats),
0017         region_(dtcId / setup->numDTCsPerRegion()),
0018         board_(dtcId % setup->numDTCsPerRegion()),
0019         modules_(setup->dtcModules(dtcId)),
0020         input_(setup->dtcNumRoutingBlocks(), Stubss(setup->dtcNumModulesPerRoutingBlock())),
0021         lost_(setup->numOverlappingRegions()) {
0022     // count number of stubs on this dtc
0023     auto acc = [](int sum, const std::vector<TTStubRef>& stubsModule) { return sum + stubsModule.size(); };
0024     const int nStubs = std::accumulate(stubsDTC.begin(), stubsDTC.end(), 0, acc);
0025     stubs_.reserve(nStubs);
0026     // convert and assign Stubs to DTC routing block channel
0027     for (int modId = 0; modId < setup->numModulesPerDTC(); modId++) {
0028       const std::vector<TTStubRef>& ttStubRefs = stubsDTC[modId];
0029       if (ttStubRefs.empty())
0030         continue;
0031       // Module which produced this ttStubRefs
0032       const tt::SensorModule* module = modules_.at(modId);
0033       // DTC routing block id [0-1]
0034       const int blockId = modId / setup->dtcNumModulesPerRoutingBlock();
0035       // DTC routing blockc  channel id [0-35]
0036       const int channelId = modId % setup->dtcNumModulesPerRoutingBlock();
0037       // convert TTStubs and fill input channel
0038       Stubs& stubs = input_[blockId][channelId];
0039       for (const TTStubRef& ttStubRef : ttStubRefs) {
0040         stubs_.emplace_back(setup, dataFormats, layerEncoding, module, ttStubRef);
0041         Stub& stub = stubs_.back();
0042         if (stub.valid())
0043           // passed pt and eta cut
0044           stubs.push_back(&stub);
0045       }
0046       // sort stubs by bend
0047       std::sort(stubs.begin(), stubs.end(), [](Stub* lhs, Stub* rhs) {
0048         return std::abs(lhs->bend()) < std::abs(rhs->bend());
0049       });
0050       // truncate stubs if desired
0051       if (!setup_->enableTruncation() || (int)stubs.size() <= setup->numFramesFE())
0052         continue;
0053       // begin of truncated stubs
0054       const auto limit = std::next(stubs.begin(), setup->numFramesFE());
0055       // copy truncated stubs into lost output channel
0056       for (int region = 0; region < setup->numOverlappingRegions(); region++)
0057         std::copy_if(limit, stubs.end(), std::back_inserter(lost_[region]), [region](Stub* stub) {
0058           return stub->inRegion(region);
0059         });
0060       // remove truncated stubs form input channel
0061       stubs.erase(limit, stubs.end());
0062     }
0063   }
0064 
0065   // board level routing in two steps and products filling
0066   void DTC::produce(TTDTC& productAccepted, TTDTC& productLost) {
0067     // router step 1: merges stubs of all modules connected to one routing block into one stream
0068     Stubs lost;
0069     Stubss blockStubs(setup_->dtcNumRoutingBlocks());
0070     for (int routingBlock = 0; routingBlock < setup_->dtcNumRoutingBlocks(); routingBlock++)
0071       merge(input_[routingBlock], blockStubs[routingBlock], lost);
0072     // copy lost stubs during merge into lost output channel
0073     for (int region = 0; region < setup_->numOverlappingRegions(); region++) {
0074       auto inRegion = [region](Stub* stub) { return stub->inRegion(region); };
0075       std::copy_if(lost.begin(), lost.end(), std::back_inserter(lost_[region]), inRegion);
0076     }
0077     // router step 2: merges stubs of all routing blocks and splits stubs into one stream per overlapping region
0078     Stubss regionStubs(setup_->numOverlappingRegions());
0079     split(blockStubs, regionStubs);
0080     // fill products
0081     produce(regionStubs, productAccepted);
0082     produce(lost_, productLost);
0083   }
0084 
0085   // router step 1: merges stubs of all modules connected to one routing block into one stream
0086   void DTC::merge(Stubss& inputs, Stubs& output, Stubs& lost) {
0087     // for each input one fifo
0088     Stubss stacks(inputs.size());
0089     // clock accurate firmware emulation, each while trip describes one clock tick
0090     while (!std::all_of(inputs.begin(), inputs.end(), [](const Stubs& channel) { return channel.empty(); }) ||
0091            !std::all_of(stacks.begin(), stacks.end(), [](const Stubs& channel) { return channel.empty(); })) {
0092       // fill fifos
0093       for (int iInput = 0; iInput < static_cast<int>(inputs.size()); iInput++) {
0094         Stubs& input = inputs[iInput];
0095         Stubs& stack = stacks[iInput];
0096         if (input.empty())
0097           continue;
0098         Stub* stub = pop_front(input);
0099         if (stub) {
0100           if (setup_->enableTruncation() && static_cast<int>(stack.size()) == setup_->dtcDepthMemory() - 1)
0101             // kill current first stub when fifo overflows
0102             lost.push_back(pop_front(stack));
0103           stack.push_back(stub);
0104         }
0105       }
0106       // route stub from a fifo to output if possible
0107       bool nothingToRoute(true);
0108       for (int iInput = inputs.size() - 1; iInput >= 0; iInput--) {
0109         Stubs& stack = stacks[iInput];
0110         if (stack.empty())
0111           continue;
0112         nothingToRoute = false;
0113         output.push_back(pop_front(stack));
0114         // only one stub can be routed to output per clock tick
0115         break;
0116       }
0117       // each clock tick output will grow by one, if no stub is available then by a gap
0118       if (nothingToRoute)
0119         output.push_back(nullptr);
0120     }
0121     // truncate if desired
0122     if (setup_->enableTruncation() && (int)output.size() > setup_->numFramesIOHigh()) {
0123       const auto limit = std::next(output.begin(), setup_->numFramesIOHigh());
0124       std::copy_if(limit, output.end(), std::back_inserter(lost), [](Stub* stub) { return stub; });
0125       output.erase(limit, output.end());
0126     }
0127     // remove all gaps between end and last stub
0128     for (auto it = output.end(); it != output.begin();)
0129       it = (*--it) ? output.begin() : output.erase(it);
0130   }
0131 
0132   // router step 2: merges stubs of all routing blocks and splits stubs into one stream per overlapping region
0133   void DTC::split(Stubss& inputs, Stubss& outputs) {
0134     int region(0);
0135     auto regionMask = [&region](Stub* stub) { return stub && stub->inRegion(region) ? stub : nullptr; };
0136     for (Stubs& output : outputs) {
0137       // copy of masked inputs for each output
0138       Stubss streams(inputs.size());
0139       int i(0);
0140       for (Stubs& input : inputs) {
0141         Stubs& stream = streams[i++];
0142         std::transform(input.begin(), input.end(), back_inserter(stream), regionMask);
0143         for (auto it = stream.end(); it != stream.begin();)
0144           it = (*--it) ? stream.begin() : stream.erase(it);
0145       }
0146       merge(streams, output, lost_[region++]);
0147     }
0148   }
0149 
0150   // conversion from Stubss to TTDTC
0151   void DTC::produce(const Stubss& stubss, TTDTC& product) {
0152     int channel(0);
0153     auto toFrame = [&channel](Stub* stub) { return stub ? stub->frame(channel) : tt::FrameStub(); };
0154     for (const Stubs& stubs : stubss) {
0155       tt::StreamStub stream;
0156       stream.reserve(stubs.size());
0157       std::transform(stubs.begin(), stubs.end(), std::back_inserter(stream), toFrame);
0158       product.setStream(region_, board_, channel++, stream);
0159     }
0160   }
0161 
0162   // pop_front function which additionally returns copy of deleted front
0163   Stub* DTC::pop_front(Stubs& deque) {
0164     Stub* stub = deque.front();
0165     deque.pop_front();
0166     return stub;
0167   }
0168 
0169 }  // namespace trackerDTC