CMS 3D CMS Logo

ZHoughTransform.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  region_(region),
26  input_(dataFormats->numChannel(Process::mht)),
27  stage_(0) {}
28 
29  // read in and organize input product (fill vector input_)
31  auto valid = [](int& sum, const FrameStub& frame) { return sum += (frame.first.isNonnull() ? 1 : 0); };
33  int nStubsMHT(0);
34  for (int channel = 0; channel < dataFormats_->numChannel(Process::mht); channel++) {
35  const StreamStub& stream = streams[offset + channel];
36  nStubsMHT += accumulate(stream.begin(), stream.end(), 0, valid);
37  }
38  stubsZHT_.reserve(nStubsMHT * (setup_->zhtNumCells() * setup_->zhtNumStages()));
39  for (int channel = 0; channel < dataFormats_->numChannel(Process::mht); channel++) {
40  const StreamStub& stream = streams[offset + channel];
41  vector<StubZHT*>& stubs = input_[channel];
42  stubs.reserve(stream.size());
43  // Store input stubs in vector, so rest of ZHT algo can work with pointers to them (saves CPU)
44  for (const FrameStub& frame : stream) {
45  StubZHT* stub = nullptr;
46  if (frame.first.isNonnull()) {
47  StubMHT stubMHT(frame, dataFormats_);
48  stubsZHT_.emplace_back(stubMHT);
49  stub = &stubsZHT_.back();
50  }
51  stubs.push_back(stub);
52  }
53  }
54  }
55 
56  // fill output products
58  vector<deque<StubZHT*>> streams(dataFormats_->numChannel(Process::mht));
59  for (int channel = 0; channel < dataFormats_->numChannel(Process::mht); channel++)
60  streams[channel] = deque<StubZHT*>(input_[channel].begin(), input_[channel].end());
61  vector<deque<StubZHT*>> stubsCells(dataFormats_->numChannel(Process::mht) * setup_->zhtNumCells());
62  for (stage_ = 0; stage_ < setup_->zhtNumStages(); stage_++) {
63  // fill ZHT cells
64  for (int channel = 0; channel < dataFormats_->numChannel(Process::mht); channel++)
65  fill(channel, streams[channel], stubsCells);
66  // perform static load balancing
67  for (int channel = 0; channel < dataFormats_->numChannel(Process::mht); channel++) {
68  vector<deque<StubZHT*>> tmp(setup_->zhtNumCells());
69  // gather streams to mux together: same ZHT cell of 4 adjacent ZHT input streams
70  for (int k = 0; k < setup_->zhtNumCells(); k++)
71  //swap(tmp[k], stubsCells[(channel / setup_->zhtNumCells()) * dataFormats_->numChannel(Process::mht) + channel % setup_->zhtNumCells() + k * setup_->zhtNumCells()]);
72  swap(tmp[k], stubsCells[channel * setup_->zhtNumCells() + k]);
73  slb(tmp, streams[channel], lost[channel]);
74  }
75  }
76  // fill output product
77  for (int channel = 0; channel < dataFormats_->numChannel(Process::mht); channel++) {
78  deque<StubZHT*>& stubs = streams[channel];
79  StreamStub& stream = accepted[region_ * dataFormats_->numChannel(Process::mht) + channel];
80  merge(stubs, stream);
81  }
82  }
83 
84  // perform finer pattern recognition per track
85  void ZHoughTransform::fill(int channel, const deque<StubZHT*>& stubs, vector<deque<StubZHT*>>& streams) {
86  if (stubs.empty())
87  return;
88  const double baseZT =
90  const double baseCot =
92  int id;
93  auto different = [&id](StubZHT* stub) { return !stub || id != stub->trackId(); };
94  for (auto it = stubs.begin(); it != stubs.end();) {
95  if (!*it) {
96  const auto begin = find_if(it, stubs.end(), [](StubZHT* stub) { return stub; });
97  const int nGaps = distance(it, begin);
98  for (deque<StubZHT*>& stream : streams)
99  stream.insert(stream.end(), nGaps, nullptr);
100  it = begin;
101  continue;
102  }
103  const auto start = it;
104  const double cotGlobal = (*start)->cotf() + setup_->sectorCot((*start)->sectorEta());
105  id = (*it)->trackId();
106  it = find_if(it, stubs.end(), different);
107  const int size = distance(start, it);
108  // create finer track candidates stub container
109  vector<vector<StubZHT*>> mhtCells(setup_->zhtNumCells());
110  for (vector<StubZHT*>& mhtCell : mhtCells)
111  mhtCell.reserve(size);
112  // fill finer track candidates stub container
113  for (auto stub = start; stub != it; stub++) {
114  const double r = (*stub)->r() + setup_->chosenRofPhi() - setup_->chosenRofZ();
115  const double chi = (*stub)->chi();
116  const double dChi = setup_->dZ((*stub)->ttStubRef(), cotGlobal);
117  // identify finer track candidates for this stub
118  // 0 and 1 belong to the ZHT cells with smaller cot; 0 and 2 belong to those with smaller zT
119  vector<int> cells;
120  cells.reserve(setup_->zhtNumCells());
121  const bool compA = 2. * abs(chi) < baseZT + dChi;
122  const bool compB = 2. * abs(chi) < abs(r) * baseCot + dChi;
123  const bool compC = 2. * abs(chi) < dChi;
124  if (chi >= 0. && r >= 0.) {
125  cells.push_back(1);
126  if (compA)
127  cells.push_back(3);
128  if (compB)
129  cells.push_back(0);
130  if (compC)
131  cells.push_back(2);
132  }
133  if (chi >= 0. && r < 0.) {
134  cells.push_back(3);
135  if (compA)
136  cells.push_back(1);
137  if (compB)
138  cells.push_back(2);
139  if (compC)
140  cells.push_back(0);
141  }
142  if (chi < 0. && r >= 0.) {
143  cells.push_back(2);
144  if (compA)
145  cells.push_back(0);
146  if (compB)
147  cells.push_back(3);
148  if (compC)
149  cells.push_back(1);
150  }
151  if (chi < 0. && r < 0.) {
152  cells.push_back(0);
153  if (compA)
154  cells.push_back(2);
155  if (compB)
156  cells.push_back(1);
157  if (compC)
158  cells.push_back(3);
159  }
160  for (int cell : cells) {
161  const double cot = (cell / setup_->zhtNumBinsZT() - .5) * baseCot / 2.;
162  const double zT = (cell % setup_->zhtNumBinsZT() - .5) * baseZT / 2.;
163  stubsZHT_.emplace_back(**stub, zT, cot, cell);
164  mhtCells[cell].push_back(&stubsZHT_.back());
165  }
166  }
167  // perform pattern recognition
168  for (int sel = 0; sel < setup_->zhtNumCells(); sel++) {
169  deque<StubZHT*>& stream = streams[channel * setup_->zhtNumCells() + sel];
170  vector<StubZHT*>& mhtCell = mhtCells[sel];
171  set<int> layers;
172  auto toLayer = [](StubZHT* stub) { return stub->layer(); };
173  transform(mhtCell.begin(), mhtCell.end(), inserter(layers, layers.begin()), toLayer);
174  if ((int)layers.size() < setup_->mhtMinLayers())
175  mhtCell.clear();
176  for (StubZHT* stub : mhtCell)
177  stream.push_back(stub);
178  stream.insert(stream.end(), size - (int)mhtCell.size(), nullptr);
179  }
180  }
181  for (int sel = 0; sel < setup_->zhtNumCells(); sel++) {
182  deque<StubZHT*>& stream = streams[channel * setup_->zhtNumCells() + sel];
183  // remove all gaps between end and last stub
184  for (auto it = stream.end(); it != stream.begin();)
185  it = (*--it) ? stream.begin() : stream.erase(it);
186  // read out fine track cannot start before rough track has read in completely, add gaps to take this into account
187  int pos(0);
188  for (auto it = stream.begin(); it != stream.end();) {
189  if (!(*it)) {
190  it = stream.erase(it);
191  continue;
192  }
193  id = (*it)->trackId();
194  const int s = distance(it, find_if(it, stream.end(), different));
195  const int d = distance(stream.begin(), it);
196  pos += s;
197  if (d < pos) {
198  const int diff = pos - d;
199  it = stream.insert(it, diff, nullptr);
200  it = next(it, diff);
201  } else
202  it = stream.erase(remove(next(stream.begin(), pos), it, nullptr), it);
203  it = next(it, s);
204  }
205  // adjust stream start so that first output stub is in first place in case of quickest track
206  if (!stream.empty())
207  stream.erase(stream.begin(), next(stream.begin(), setup_->mhtMinLayers()));
208  }
209  }
210 
211  // Static load balancing of inputs: mux 4 streams to 1 stream
212  void ZHoughTransform::slb(vector<deque<StubZHT*>>& inputs, deque<StubZHT*>& accepted, StreamStub& lost) const {
213  accepted.clear();
214  if (all_of(inputs.begin(), inputs.end(), [](const deque<StubZHT*>& stubs) { return stubs.empty(); }))
215  return;
216  // input fifos
217  vector<deque<StubZHT*>> stacks(setup_->zhtNumCells());
218  // helper for handshake
219  TTBV empty(-1, setup_->zhtNumCells(), true);
220  TTBV enable(0, setup_->zhtNumCells());
221  // clock accurate firmware emulation, each while trip describes one clock tick, one stub in and one stub out per tick
222  while (!all_of(inputs.begin(), inputs.end(), [](const deque<StubZHT*>& d) { return d.empty(); }) or
223  !all_of(stacks.begin(), stacks.end(), [](const deque<StubZHT*>& d) { return d.empty(); })) {
224  // store stub in fifo
225  for (int channel = 0; channel < setup_->zhtNumCells(); channel++) {
226  StubZHT* stub = pop_front(inputs[channel]);
227  if (stub)
228  stacks[channel].push_back(stub);
229  }
230  // identify empty fifos
231  for (int channel = 0; channel < setup_->zhtNumCells(); channel++)
232  empty[channel] = stacks[channel].empty();
233  // chose new fifo to read from if current fifo got empty
234  const int iEnableOld = enable.plEncode();
235  if (enable.none() || empty[iEnableOld]) {
236  enable.reset();
237  const int iNotEmpty = empty.plEncode(false);
238  if (iNotEmpty < setup_->zhtNumCells())
239  enable.set(iNotEmpty);
240  }
241  // read from chosen fifo
242  const int iEnable = enable.plEncode();
243  if (enable.any())
244  accepted.push_back(pop_front(stacks[iEnable]));
245  else
246  // gap if no fifo has been chosen
247  accepted.push_back(nullptr);
248  }
249  // perform truncation if desired
250  if (enableTruncation_ && (int)accepted.size() > setup_->numFrames()) {
251  const auto limit = next(accepted.begin(), setup_->numFrames());
252  auto valid = [](int& sum, StubZHT* stub) { return sum += stub ? 1 : 0; };
253  const int nLost = accumulate(limit, accepted.end(), 0, valid);
254  lost.reserve(nLost);
255  for (auto it = limit; it != accepted.end(); it++)
256  if (*it)
257  lost.emplace_back((*it)->frame());
258  accepted.erase(limit, accepted.end());
259  }
260  // cosmetics -- remove gaps at the end of stream
261  for (auto it = accepted.end(); it != accepted.begin();)
262  it = (*--it) == nullptr ? accepted.erase(it) : accepted.begin();
263  }
264 
265  //
266  void ZHoughTransform::merge(deque<StubZHT*>& stubs, StreamStub& stream) const {
267  stubs.erase(remove(stubs.begin(), stubs.end(), nullptr), stubs.end());
268  /*stream.reserve(stubs.size());
269  transform(stubs.begin(), stubs.end(), back_inserter(stream), [](StubZHT* stub){ return stub->frame(); });
270  return;*/
271  map<int, set<pair<int, int>>> candidates;
272  const int weight = setup_->zhtNumCells() * pow(2, setup_->zhtNumStages());
273  for (const StubZHT* stub : stubs)
274  candidates[stub->trackId() / weight].emplace(stub->cot(), stub->zT());
275  vector<deque<FrameStub>> tracks(candidates.size());
276  for (auto it = stubs.begin(); it != stubs.end();) {
277  const auto start = it;
278  const int id = (*it)->trackId();
279  const int candId = id / weight;
280  const auto m = candidates.find(candId);
281  pair<int, int> cotp(9e9, -9e9);
282  pair<int, int> zTp(9e9, -9e9);
283  for (const pair<int, int>& para : m->second) {
284  cotp = {min(cotp.first, para.first), max(cotp.second, para.first)};
285  zTp = {min(zTp.first, para.second), max(zTp.second, para.second)};
286  }
287  const int cot = (cotp.first + cotp.second) / 2;
288  const int zT = (cotp.first + cotp.second) / 2;
289  const int pos = distance(candidates.begin(), m);
290  deque<FrameStub>& track = tracks[pos];
291  auto different = [id](const StubZHT* stub) { return id != stub->trackId(); };
292  it = find_if(it, stubs.end(), different);
293  for (auto s = start; s != it; s++) {
294  if (find_if(track.begin(), track.end(), [s](const FrameStub& stub) {
295  return (*s)->ttStubRef() == stub.first;
296  }) != track.end())
297  continue;
298  const StubZHT stub(**s, cot, zT);
299  track.push_back(stub.frame());
300  }
301  }
302  const int size = accumulate(tracks.begin(), tracks.end(), 0, [](int& sum, const deque<FrameStub>& stubs) {
303  return sum += (int)stubs.size();
304  });
305  stream.reserve(size);
306  for (deque<FrameStub>& track : tracks)
307  for (const FrameStub& stub : track)
308  stream.push_back(stub);
309  }
310 
311  // remove and return first element of deque, returns nullptr if empty
312  template <class T>
313  T* ZHoughTransform::pop_front(deque<T*>& ts) const {
314  T* t = nullptr;
315  if (!ts.empty()) {
316  t = ts.front();
317  ts.pop_front();
318  }
319  return t;
320  }
321 
322 } // namespace trackerTFP
size
Write out results.
Definition: start.py:1
double dZ(const TTStubRef &ttStubRef, double cot) const
Definition: Setup.cc:596
void merge(std::deque< StubZHT *> &stubs, tt::StreamStub &stream) const
double base() const
Definition: DataFormats.h:117
double chosenRofZ() const
Definition: Setup.h:413
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
void slb(std::vector< std::deque< StubZHT *>> &inputs, std::deque< StubZHT *> &accepted, tt::StreamStub &lost) const
int zhtNumStages() const
Definition: Setup.h:467
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
int numFrames() const
Definition: Setup.h:153
Definition: weight.py:1
double chosenRofPhi() const
Definition: Setup.h:213
void consume(const tt::StreamsStub &streams)
int zhtNumBinsZT() const
Definition: Setup.h:463
uint32_t T const *__restrict__ uint32_t const *__restrict__ int32_t int Histo::index_type cudaStream_t stream
void swap(Association< C > &lhs, Association< C > &rhs)
Definition: Association.h:117
int numChannel(Process p) const
Definition: DataFormats.h:498
void produce(tt::StreamsStub &accepted, tt::StreamsStub &lost)
Definition: TTTypes.h:54
void fill(int channel, const std::deque< StubZHT *> &input, std::vector< std::deque< StubZHT *>> &output)
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:456
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
std::vector< StubZHT > stubsZHT_
std::vector< std::vector< StubZHT * > > input_
d
Definition: ztail.py:151
caConstants::TupleMultiplicity const CAHitNtupletGeneratorKernelsGPU::HitToTuple const cms::cuda::AtomicPairCounter GPUCACell const *__restrict__ cells
auto const & tracks
cannot be loose
T * pop_front(std::deque< T *> &ts) const
HLT enums.
int zhtNumCells() const
Definition: Setup.h:475
const DataFormats * dataFormats_
tt::FrameStub frame() const
Definition: DataFormats.h:576
Class to calculate and provide dataformats used by Track Trigger emulator.
Definition: DataFormats.h:216
double sectorCot(int eta) const
Definition: Setup.h:428
tmp
align.sh
Definition: createJobs.py:716
long double T
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
const DataFormat & format(Variable v, Process p) const
Definition: DataFormats.h:506
unsigned transform(const HcalDetId &id, unsigned transformCode)