CMS 3D CMS Logo

MiniHoughTransform.cc
Go to the documentation of this file.
2 
3 #include <numeric>
4 #include <algorithm>
5 #include <iterator>
6 #include <deque>
7 #include <vector>
8 #include <set>
9 #include <utility>
10 #include <cmath>
11 
12 using namespace std;
13 using namespace edm;
14 using namespace tt;
15 
16 namespace trackerTFP {
17 
19  const Setup* setup,
20  const DataFormats* dataFormats,
21  int region)
22  : enableTruncation_(iConfig.getParameter<bool>("EnableTruncation")),
23  setup_(setup),
24  dataFormats_(dataFormats),
25  inv2R_(dataFormats_->format(Variable::inv2R, Process::ht)),
26  phiT_(dataFormats_->format(Variable::phiT, Process::ht)),
27  region_(region),
28  numBinsInv2R_(setup_->htNumBinsInv2R()),
29  numCells_(setup_->mhtNumCells()),
30  numNodes_(setup_->mhtNumDLBNodes()),
31  numChannel_(setup_->mhtNumDLBChannel()),
32  input_(numBinsInv2R_) {}
33 
34  // read in and organize input product (fill vector input_)
36  auto valid = [](int sum, const FrameStub& frame) { return sum + (frame.first.isNonnull() ? 1 : 0); };
37  int nStubsHT(0);
38  for (int binInv2R = 0; binInv2R < numBinsInv2R_; binInv2R++) {
39  const StreamStub& stream = streams[region_ * numBinsInv2R_ + binInv2R];
40  nStubsHT += accumulate(stream.begin(), stream.end(), 0, valid);
41  }
42  stubsHT_.reserve(nStubsHT);
43  stubsMHT_.reserve(nStubsHT * numCells_);
44  for (int binInv2R = 0; binInv2R < numBinsInv2R_; binInv2R++) {
45  const int inv2R = inv2R_.toSigned(binInv2R);
46  const StreamStub& stream = streams[region_ * numBinsInv2R_ + binInv2R];
47  vector<StubHT*>& stubs = input_[binInv2R];
48  stubs.reserve(stream.size());
49  // Store input stubs in vector, so rest of MHT algo can work with pointers to them (saves CPU)
50  for (const FrameStub& frame : stream) {
51  StubHT* stub = nullptr;
52  if (frame.first.isNonnull()) {
53  stubsHT_.emplace_back(frame, dataFormats_, inv2R);
54  stub = &stubsHT_.back();
55  }
56  stubs.push_back(stub);
57  }
58  }
59  }
60 
61  // fill output products
63  // fill MHT cells
64  vector<deque<StubMHT*>> stubsCells(numBinsInv2R_ * numCells_);
65  for (int channel = 0; channel < numBinsInv2R_; channel++)
66  fill(channel, input_[channel], stubsCells);
67  // perform static load balancing
68  vector<vector<StubMHT*>> streamsSLB(numBinsInv2R_);
69  for (int channel = 0; channel < numBinsInv2R_; channel++) {
70  vector<deque<StubMHT*>> tmp(numCells_);
71  // gather streams to mux together: same MHT cell of 4 adjacent MHT input streams
72  for (int k = 0; k < numCells_; k++)
73  swap(tmp[k], stubsCells[(channel / numCells_) * numBinsInv2R_ + channel % numCells_ + k * numCells_]);
74  slb(tmp, streamsSLB[channel], lost[channel]);
75  }
76  // dynamic load balancing stage 1
77  vector<vector<StubMHT*>> streamsDLB(numBinsInv2R_);
78  for (int node = 0; node < numNodes_; node++) {
79  vector<vector<StubMHT*>> tmp(numChannel_);
80  // gather streams to dynamically balance them
81  for (int k = 0; k < numChannel_; k++)
82  swap(tmp[k], streamsSLB[(node / numCells_) * numNodes_ + node % numCells_ + k * numCells_]);
83  dlb(tmp);
84  for (int k = 0; k < numChannel_; k++)
85  swap(tmp[k], streamsDLB[node * numChannel_ + k]);
86  }
87  // dynamic load balancing stage 2
88  vector<vector<StubMHT*>> streamsMHT(numBinsInv2R_);
89  for (int node = 0; node < numNodes_; node++) {
90  vector<vector<StubMHT*>> tmp(numChannel_);
91  // gather streams to dynamically balance them
92  for (int k = 0; k < numChannel_; k++)
93  swap(tmp[k], streamsDLB[node + k * numNodes_]);
94  dlb(tmp);
95  for (int k = 0; k < numChannel_; k++)
96  swap(tmp[k], streamsMHT[node * numChannel_ + k]);
97  }
98  // fill output product
99  for (int channel = 0; channel < numBinsInv2R_; channel++) {
100  const vector<StubMHT*>& stubs = streamsMHT[channel];
101  StreamStub& stream = accepted[region_ * numBinsInv2R_ + channel];
102  stream.reserve(stubs.size());
103  for (StubMHT* stub : stubs)
104  stream.emplace_back(stub ? stub->frame() : FrameStub());
105  }
106  }
107 
108  // perform finer pattern recognition per track
109  void MiniHoughTransform::fill(int channel, const vector<StubHT*>& stubs, vector<deque<StubMHT*>>& streams) {
110  if (stubs.empty())
111  return;
112  int id;
113  auto differentHT = [&id](StubHT* stub) { return id != stub->trackId(); };
114  auto differentMHT = [&id](StubMHT* stub) { return !stub || id != stub->trackId(); };
115  for (auto it = stubs.begin(); it != stubs.end();) {
116  const auto start = it;
117  id = (*it)->trackId();
118  it = find_if(it, stubs.end(), differentHT);
119  const int size = distance(start, it);
120  // create finer track candidates stub container
121  vector<vector<StubMHT*>> mhtCells(numCells_);
122  for (vector<StubMHT*>& mhtCell : mhtCells)
123  mhtCell.reserve(size);
124  // fill finer track candidates stub container
125  for (auto stub = start; stub != it; stub++) {
126  const double r = (*stub)->r();
127  const double chi = (*stub)->phi();
128  // identify finer track candidates for this stub
129  // 0 and 1 belong to the MHT cells with larger inv2R; 0 and 2 belong to those with smaller track PhiT
130  vector<int> cells;
131  cells.reserve(numCells_);
132  const bool compA = 2. * abs(chi) < phiT_.base();
133  const bool compB = 2. * abs(chi) < abs(r * inv2R_.base());
134  const bool compAB = compA && compB;
135  if (chi >= 0. && r >= 0.) {
136  cells.push_back(3);
137  if (compA)
138  cells.push_back(1);
139  if (compAB)
140  cells.push_back(2);
141  }
142  if (chi >= 0. && r < 0.) {
143  cells.push_back(1);
144  if (compA)
145  cells.push_back(3);
146  if (compAB)
147  cells.push_back(0);
148  }
149  if (chi < 0. && r >= 0.) {
150  cells.push_back(0);
151  if (compA)
152  cells.push_back(2);
153  if (compAB)
154  cells.push_back(1);
155  }
156  if (chi < 0. && r < 0.) {
157  cells.push_back(2);
158  if (compA)
159  cells.push_back(0);
160  if (compAB)
161  cells.push_back(3);
162  }
163  // organise stubs in finer track candidates
164  for (int cell : cells) {
165  const int inv2R = cell / setup_->mhtNumBinsPhiT();
166  const int phiT = cell % setup_->mhtNumBinsPhiT();
167  stubsMHT_.emplace_back(**stub, phiT, inv2R);
168  mhtCells[cell].push_back(&stubsMHT_.back());
169  }
170  }
171  // perform pattern recognition
172  for (int sel = 0; sel < numCells_; sel++) {
173  deque<StubMHT*>& stream = streams[channel * numCells_ + sel];
174  vector<StubMHT*>& mhtCell = mhtCells[sel];
175  set<int> layers;
176  auto toLayer = [](StubMHT* stub) { return stub->layer(); };
177  transform(mhtCell.begin(), mhtCell.end(), inserter(layers, layers.begin()), toLayer);
178  if ((int)layers.size() < setup_->mhtMinLayers())
179  mhtCell.clear();
180  for (StubMHT* stub : mhtCell)
181  stream.push_back(stub);
182  stream.insert(stream.end(), size - (int)mhtCell.size(), nullptr);
183  }
184  }
185  for (int sel = 0; sel < numCells_; sel++) {
186  deque<StubMHT*>& stream = streams[channel * numCells_ + sel];
187  // remove all gaps between end and last stub
188  for (auto it = stream.end(); it != stream.begin();)
189  it = (*--it) ? stream.begin() : stream.erase(it);
190  // read out fine track cannot start before rough track has read in completely, add gaps to take this into account
191  int pos(0);
192  for (auto it = stream.begin(); it != stream.end();) {
193  if (!(*it)) {
194  it = stream.erase(it);
195  continue;
196  }
197  id = (*it)->trackId();
198  const int s = distance(it, find_if(it, stream.end(), differentMHT));
199  const int d = distance(stream.begin(), it);
200  pos += s;
201  if (d < pos) {
202  const int diff = pos - d;
203  it = stream.insert(it, diff, nullptr);
204  it = next(it, diff);
205  } else
206  it = stream.erase(remove(next(stream.begin(), pos), it, nullptr), it);
207  it = next(it, s);
208  }
209  // adjust stream start so that first output stub is in first place in case of quickest track
210  if (!stream.empty())
211  stream.erase(stream.begin(), next(stream.begin(), setup_->mhtMinLayers()));
212  }
213  }
214 
215  // Static load balancing of inputs: mux 4 streams to 1 stream
216  void MiniHoughTransform::slb(vector<deque<StubMHT*>>& inputs, vector<StubMHT*>& accepted, StreamStub& lost) const {
217  if (all_of(inputs.begin(), inputs.end(), [](const deque<StubMHT*>& stubs) { return stubs.empty(); }))
218  return;
219  auto size = [](int sum, const deque<StubMHT*>& stubs) { return sum = stubs.size(); };
220  const int nFrames = accumulate(inputs.begin(), inputs.end(), 0, size);
221  accepted.reserve(nFrames);
222  // input fifos
223  vector<deque<StubMHT*>> stacks(numCells_);
224  // helper for handshake
225  TTBV empty(-1, numCells_, true);
226  TTBV enable(0, numCells_);
227  // clock accurate firmware emulation, each while trip describes one clock tick, one stub in and one stub out per tick
228  while (!all_of(inputs.begin(), inputs.end(), [](const deque<StubMHT*>& d) { return d.empty(); }) or
229  !all_of(stacks.begin(), stacks.end(), [](const deque<StubMHT*>& d) { return d.empty(); })) {
230  // store stub in fifo
231  for (int channel = 0; channel < numCells_; channel++) {
232  StubMHT* stub = pop_front(inputs[channel]);
233  if (stub)
234  stacks[channel].push_back(stub);
235  }
236  // identify empty fifos
237  for (int channel = 0; channel < numCells_; channel++)
238  empty[channel] = stacks[channel].empty();
239  // chose new fifo to read from if current fifo got empty
240  const int iEnableOld = enable.plEncode();
241  if (enable.none() || empty[iEnableOld]) {
242  enable.reset();
243  const int iNotEmpty = empty.plEncode(false);
244  if (iNotEmpty < numCells_)
245  enable.set(iNotEmpty);
246  }
247  // read from chosen fifo
248  const int iEnable = enable.plEncode();
249  if (enable.any())
250  accepted.push_back(pop_front(stacks[iEnable]));
251  else
252  // gap if no fifo has been chosen
253  accepted.push_back(nullptr);
254  }
255  // perform truncation if desired
256  if (enableTruncation_ && (int)accepted.size() > setup_->numFrames()) {
257  const auto limit = next(accepted.begin(), setup_->numFrames());
258  auto valid = [](int sum, StubMHT* stub) { return sum + (stub ? 1 : 0); };
259  const int nLost = accumulate(limit, accepted.end(), 0, valid);
260  lost.reserve(nLost);
261  for (auto it = limit; it != accepted.end(); it++)
262  if (*it)
263  lost.emplace_back((*it)->frame());
264  accepted.erase(limit, accepted.end());
265  }
266  // cosmetics -- remove gaps at the end of stream
267  for (auto it = accepted.end(); it != accepted.begin();)
268  it = (*--it) == nullptr ? accepted.erase(it) : accepted.begin();
269  }
270 
271  // Dynamic load balancing of inputs: swapping parts of streams to balance the amount of tracks per stream
272  void MiniHoughTransform::dlb(vector<vector<StubMHT*>>& streams) const {
273  if (all_of(streams.begin(), streams.end(), [](const vector<StubMHT*>& stubs) { return stubs.empty(); }))
274  return;
275  auto maxSize = [](int size, const vector<StubMHT*>& stream) { return size = max(size, (int)stream.size()); };
276  const int nMax = accumulate(streams.begin(), streams.end(), 0, maxSize);
277  for (vector<StubMHT*>& stream : streams)
278  stream.resize(nMax, nullptr);
279  vector<int> prevTrks(numChannel_, -1);
280  bool swapping(false);
281  vector<int> loads(numChannel_, 0);
282  for (int i = 0; i < nMax; i++) {
283  TTBV newTrks(0, numChannel_);
284  for (int k = 0; k < numChannel_; k++)
285  if (!streams[numChannel_ - k - 1][i] && streams[k][i] && streams[k][i]->trackId() != prevTrks[k])
286  newTrks.set(k);
287  for (int k = 0; k < numChannel_; k++)
288  if (newTrks[k])
289  if ((swapping && loads[numChannel_ - k - 1] > loads[k]) ||
290  (!swapping && loads[k] > loads[numChannel_ - k - 1]))
291  swapping = !swapping;
292  for (int k = 0; k < numChannel_; k++) {
293  if (streams[k][i])
294  loads[swapping ? numChannel_ - k - 1 : k]++;
295  prevTrks[k] = streams[k][i] ? streams[k][i]->trackId() : -1;
296  }
297  if (swapping)
298  swap(streams[0][i], streams[1][i]);
299  }
300  // remove all gaps between end and last stub
301  for (vector<StubMHT*>& stream : streams)
302  for (auto it = stream.end(); it != stream.begin();)
303  it = (*--it) ? stream.begin() : stream.erase(it);
304  }
305 
306  // remove and return first element of deque, returns nullptr if empty
307  template <class T>
308  T* MiniHoughTransform::pop_front(deque<T*>& ts) const {
309  T* t = nullptr;
310  if (!ts.empty()) {
311  t = ts.front();
312  ts.pop_front();
313  }
314  return t;
315  }
316 
317 } // namespace trackerTFP
Definition: start.py:1
double base() const
Definition: DataFormats.h:117
Bit vector used by Track Trigger emulators. Mainly used to convert integers into arbitrary (within ma...
Definition: TTBV.h:20
std::pair< TTStubRef, Frame > FrameStub
Definition: TTTypes.h:60
T * pop_front(std::deque< T *> &ts) const
Class to process and provide run-time constants used by Track Trigger emulators.
Definition: Setup.h:44
std::vector< StreamStub > StreamsStub
Definition: TTTypes.h:66
std::vector< FrameStub > StreamStub
Definition: TTTypes.h:63
void slb(std::vector< std::deque< StubMHT *>> &inputs, std::vector< StubMHT *> &accepted, tt::StreamStub &lost) const
int numFrames() const
Definition: Setup.h:153
uint32_t T const *__restrict__ uint32_t const *__restrict__ int32_t int Histo::index_type cudaStream_t stream
std::vector< StubMHT > stubsMHT_
void swap(Association< C > &lhs, Association< C > &rhs)
Definition: Association.h:112
Definition: TTTypes.h:54
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
int mhtMinLayers() const
Definition: Setup.h:460
std::vector< std::vector< StubHT * > > input_
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
enable
Messages.
Definition: DiMuonV_cfg.py:93
TTBV & set()
Definition: TTBV.h:187
d
Definition: ztail.py:151
void dlb(std::vector< std::vector< StubMHT *>> &streams) const
void produce(tt::StreamsStub &accepted, tt::StreamsStub &lost)
int toSigned(int i) const
Definition: DataFormats.h:100
void fill(int channel, const std::vector< StubHT *> &input, std::vector< std::deque< StubMHT *>> &output)
HLT enums.
int mhtNumBinsPhiT() const
Definition: Setup.h:452
std::vector< StubHT > stubsHT_
void consume(const tt::StreamsStub &streams)
Class to calculate and provide dataformats used by Track Trigger emulator.
Definition: DataFormats.h:216
tmp
align.sh
Definition: createJobs.py:716
long double T
unsigned transform(const HcalDetId &id, unsigned transformCode)