CMS 3D CMS Logo

BestTrackSelection.cc
Go to the documentation of this file.
2 
3 #include "helper.h" // to_hex, to_binary
4 
5 
7  int verbose, int endcap, int sector, int bx,
8  int bxWindow,
9  int maxRoadsPerZone, int maxTracks, bool useSecondEarliest,
10  bool bugSameSectorPt0
11 ) {
12  verbose_ = verbose;
13  endcap_ = endcap;
14  sector_ = sector;
15  bx_ = bx;
16 
17  bxWindow_ = bxWindow;
18  maxRoadsPerZone_ = maxRoadsPerZone;
20  useSecondEarliest_ = useSecondEarliest;
21  bugSameSectorPt0_ = bugSameSectorPt0;
22 }
23 
25  const std::deque<EMTFTrackCollection>& extended_best_track_cands,
26  EMTFTrackCollection& best_tracks
27 ) const {
28  int num_cands = 0;
29  for (const auto& cands : extended_best_track_cands) {
30  for (const auto& cand : cands) {
31  if (cand.Rank() > 0) {
32  num_cands += 1;
33  }
34  }
35  }
36  bool early_exit = (num_cands == 0);
37 
38  if (early_exit)
39  return;
40 
41 
42  if (!useSecondEarliest_) {
43  cancel_one_bx(extended_best_track_cands, best_tracks);
44  } else {
45  cancel_multi_bx(extended_best_track_cands, best_tracks);
46  }
47 
48  if (verbose_ > 0) { // debug
49  for (const auto& track : best_tracks) {
50  std::cout << "track: " << track.Winner() << " rank: " << to_hex(track.Rank())
51  << " ph_deltas: " << array_as_string(track.PtLUT().delta_ph)
52  << " th_deltas: " << array_as_string(track.PtLUT().delta_th)
53  << " phi: " << track.Phi_fp() << " theta: " << track.Theta_fp()
54  << " cpat: " << array_as_string(track.PtLUT().cpattern)
55  << " bx: " << track.BX()
56  << std::endl;
57  for (int i = 0; i < emtf::NUM_STATIONS+1; ++i) { // stations 0-4
58  if (track.PtLUT().bt_vi[i] != 0)
59  std::cout << ".. track segments: st: " << i
60  << " v: " << track.PtLUT().bt_vi[i]
61  << " h: " << track.PtLUT().bt_hi[i]
62  << " c: " << track.PtLUT().bt_ci[i]
63  << " s: " << track.PtLUT().bt_si[i]
64  << std::endl;
65  }
66  }
67  }
68 
69 }
70 
72  const std::deque<EMTFTrackCollection>& extended_best_track_cands,
73  EMTFTrackCollection& best_tracks
74 ) const {
75  const int max_z = emtf::NUM_ZONES; // = 4 zones
76  const int max_n = maxRoadsPerZone_; // = 3 candidates per zone
77  const int max_zn = max_z * max_n; // = 12 total candidates
78  if (not (maxTracks_ <= max_zn))
79  { edm::LogError("L1T") << "maxTracks_ = " << maxTracks_ << ", max_zn = " << max_zn; return; }
80 
81  // Emulate the arrays used in firmware
82  typedef std::array<int, 3> segment_ref_t;
83  std::vector<std::vector<segment_ref_t> > segments(max_zn, std::vector<segment_ref_t>()); // 2D array [zn][num segments]
84 
85  std::vector<std::vector<bool> > larger(max_zn, std::vector<bool>(max_zn, false)); // 2D array [zn][zn]
86  std::vector<std::vector<bool> > winner(max_zn, std::vector<bool>(max_zn, false));
87 
88  std::vector<bool> exists (max_zn, false); // 1D array [zn]
89  std::vector<bool> killed (max_zn, false);
90  std::vector<int> rank (max_zn, 0);
91  //std::vector<int> good_bx(max_zn, 0);
92 
93  // Initialize arrays: rank, segments
94  for (int z = 0; z < max_z; ++z) {
95  const EMTFTrackCollection& tracks = extended_best_track_cands.at(z);
96  const int ntracks = tracks.size();
97  if (not (ntracks <= max_n))
98  { edm::LogError("L1T") << "ntracks = " << ntracks << ", max_n = " << max_n; return; }
99 
100  for (int n = 0; n < ntracks; ++n) {
101  const int zn = (n * max_z) + z; // for (i = 0; i < 12; i = i+1) rank[i%4][i/4]
102  const EMTFTrack& track = tracks.at(n);
103 
104  rank.at(zn) = track.Rank();
105 
106  for (const auto& conv_hit : track.Hits()) {
107  if (not (conv_hit.Valid()))
108  { edm::LogError("L1T") << "conv_hit.Valid() = " << conv_hit.Valid(); return; }
109 
110  // A segment identifier (chamber, strip, bx)
111  const segment_ref_t segment = {{conv_hit.PC_station()*9 + conv_hit.PC_chamber(), (conv_hit.PC_segment() % 2), 0}}; // FW doesn't check whether a segment is CSC or RPC
112  //int chamber_index = int(conv_hit.Subsystem() == TriggerPrimitive::kRPC)*9*5;
113  //chamber_index += conv_hit.PC_station()*9;
114  //chamber_index += conv_hit.PC_chamber();
115  //const segment_ref_t segment = {{chamber_index, conv_hit.Strip(), 0}};
116  segments.at(zn).push_back(segment);
117  }
118  } // end loop over n
119  } // end loop over z
120 
121  // Simultaneously compare each rank with each other
122  int i=0, j=0, ri=0, rj=0, gt=0, eq=0, sum=0;
123 
124  for (i = 0; i < max_zn; ++i) {
125  for (j = 0; j < max_zn; ++j) {
126  larger[i][j] = false;
127  }
128  larger[i][i] = true; // result of comparison with itself
129  //ri = rank[i%4][i/4]; // first index loops zone, second loops candidate. Zone loops faster, so we give equal priority to zones
130  ri = rank[i];
131 
132  for (j = 0; j < max_zn; ++j) {
133  // i&j bits show which rank is larger
134  // the comparison scheme below avoids problems
135  // when there are two or more tracks with the same rank
136  //rj = rank[j%4][j/4];
137  rj = rank[j];
138  gt = ri > rj;
139  eq = ri == rj;
140  if ((i < j && (gt || eq)) || (i > j && gt))
141  larger[i][j] = true;
142  }
143  // "larger" array shows the result of comparison for each rank
144 
145  // track exists if quality != 0
146  exists[i] = (ri != 0);
147  }
148 
149  // ghost cancellation, only in the current BX so far
150  for (i = 0; i < max_zn-1; ++i) { // candidate loop
151  for (j = i+1; j < max_zn; ++j) { // comparison candidate loop
152  int shared_segs = 0;
153 
154  // count shared segments
155  for (const auto& isegment : segments.at(i)) { // loop over all pairs of hits
156  for (const auto& jsegment : segments.at(j)) {
157  if (isegment == jsegment) { // same chamber and same segment
158  shared_segs += 1;
159  }
160  }
161  }
162 
163  if (shared_segs > 0) { // a single shared segment means it's ghost
164  // kill candidate that has lower rank
165  if (larger[i][j])
166  killed[j] = true;
167  else
168  killed[i] = true;
169  }
170  }
171  }
172 
173  // remove ghosts according to kill mask
174  //exists = exists & (~kill1);
175  for (i = 0; i < max_zn; ++i) {
176  exists[i] = exists[i] & (!killed[i]);
177  }
178 
179  bool anything_exists = (std::find(exists.begin(), exists.end(), 1) != exists.end());
180  if (!anything_exists)
181  return;
182 
183  // update "larger" array
184  for (i = 0; i < max_zn; ++i) {
185  for (j = 0; j < max_zn; ++j) {
186  //if (exists[i]) larger[i] = larger[i] | (~exists); // if this track exists make it larger than all non-existing tracks
187  //else larger[i] = 0; // else make it smaller than anything
188  if (exists[i])
189  larger[i][j] = larger[i][j] | (!exists[j]);
190  else
191  larger[i][j] = false;
192  }
193  }
194 
195  if (verbose_ > 0) { // debug
196  std::cout << "exists: ";
197  for (i = max_zn-1; i >= 0; --i) {
198  std::cout << exists[i];
199  }
200  std::cout << std::endl;
201  std::cout << "killed: ";
202  for (i = max_zn-1; i >= 0; --i) {
203  std::cout << killed[i];
204  }
205  std::cout << std::endl;
206  for (j = 0; j < max_zn; ++j) {
207  std::cout << "larger: ";
208  for (i = max_zn-1; i >= 0; --i) {
209  std::cout << larger[j][i];
210  }
211  std::cout << std::endl;
212  }
213  }
214 
215  // count zeros in the comparison results. The best track will have none, the next will have one, the third will have two
216  // skip the bits corresponding to the comparison of the track with itself
217  for (i = 0; i < max_zn; ++i) {
218  sum = 0;
219  for (j = 0; j < max_zn; ++j) {
220  if (larger[i][j] == 0)
221  sum += 1;
222  }
223 
224  if (sum < maxTracks_) {
225  winner[sum][i] = true; // assign positional winner codes
226  }
227 
228  if (sum < maxTracks_ && bugSameSectorPt0_ && sum > 0) {
229  // just keep the best track and kill the rest of them
230  winner[sum][i] = false;
231  }
232  }
233 
234  // Output best tracks according to winner signals
235  best_tracks.clear();
236 
237  for (int o = 0; o < maxTracks_; ++o) { // output candidate loop
238  int z = 0, n = 0;
239  for (i = 0; i < max_zn; ++i) { // winner bit loop
240  if (winner[o][i]) {
241  n = i / max_z;
242  z = i % max_z;
243 
244  const EMTFTrackCollection& tracks = extended_best_track_cands.at(z);
245  const EMTFTrack& track = tracks.at(n);
246  best_tracks.push_back(track);
247 
248  // Update winner, BX
249  best_tracks.back().set_track_num ( best_tracks.size() - 1 );
250  best_tracks.back().set_winner ( o );
251  best_tracks.back().set_bx ( best_tracks.back().First_BX() );
252  }
253  }
254  }
255 }
256 
258  const std::deque<EMTFTrackCollection>& extended_best_track_cands,
259  EMTFTrackCollection& best_tracks
260 ) const {
261  const int max_h = bxWindow_; // = 3 bx history
262  const int max_z = emtf::NUM_ZONES; // = 4 zones
263  const int max_n = maxRoadsPerZone_; // = 3 candidates per zone
264  const int max_zn = max_z * max_n; // = 12 total candidates
265  const int max_hzn = max_h * max_zn; // = 36 total candidates
266  if (not (maxTracks_ <= max_hzn))
267  { edm::LogError("L1T") << "maxTracks_ = " << maxTracks_ << ", max_hzn = " << max_hzn; return; }
268 
269  const int delayBX = bxWindow_ - 1;
270  const int num_h = extended_best_track_cands.size() / max_z; // num of bx history so far
271 
272  // Emulate the arrays used in firmware
273  typedef std::array<int, 3> segment_ref_t;
274  std::vector<std::vector<segment_ref_t> > segments(max_hzn, std::vector<segment_ref_t>()); // 2D array [hzn][num segments]
275 
276  std::vector<std::vector<bool> > larger(max_hzn, std::vector<bool>(max_hzn, false)); // 2D array [hzn][hzn]
277  std::vector<std::vector<bool> > winner(max_hzn, std::vector<bool>(max_hzn, false));
278 
279  std::vector<bool> exists (max_hzn, false); // 1D array [hzn]
280  std::vector<bool> killed (max_hzn, false);
281  std::vector<int> rank (max_hzn, 0);
282  std::vector<int> good_bx(max_hzn, 0);
283 
284  // Initialize arrays: rank, good_bx, segments
285  for (int h = 0; h < num_h; ++h) {
286  // extended_best_track_cands[0..3] has 4 zones for road/pattern BX-0 (i.e. current) with possible tracks from [BX-2, BX-1, BX-0]
287  // extended_best_track_cands[4..7] has 4 zones for road/pattern BX-1 with possible tracks from [BX-3, BX-2, BX-1]
288  // extended_best_track_cands[8..11] has 4 zones for road/pattern BX-2 with possible tracks from [BX-4, BX-3, BX-2]
289 
290  for (int z = 0; z < max_z; ++z) {
291  const EMTFTrackCollection& tracks = extended_best_track_cands.at(h*max_z + z);
292  const int ntracks = tracks.size();
293  if (not (ntracks <= max_n))
294  { edm::LogError("L1T") << "ntracks = " << ntracks << ", max_n = " << max_n; return; }
295 
296  for (int n = 0; n < ntracks; ++n) {
297  const int hzn = (h * max_z * max_n) + (n * max_z) + z; // for (i = 0; i < 12; i = i+1) rank[i%4][i/4]
298  const EMTFTrack& track = tracks.at(n);
299  int cand_bx = track.Second_BX();
300  cand_bx -= (bx_ - delayBX); // convert track.second_bx=[BX-2, BX-1, BX-0] --> cand_bx=[0,1,2]
301 
302  rank.at(hzn) = track.Rank();
303  if (cand_bx == 0)
304  good_bx.at(hzn) = 1; // kill this rank if it's not the right BX
305 
306  for (const auto& conv_hit : track.Hits()) {
307  if (not (conv_hit.Valid()))
308  { edm::LogError("L1T") << "conv_hit.Valid() = " << conv_hit.Valid(); return; }
309 
310  // Notes from Alex (2017-03-16):
311  //
312  // What happens currently is that RPC hits are inserted instead of
313  // CSC hits, if CSC hits are missing. So the track address will point
314  // at a CSC chamber, but the actual hit may have come from
315  // corresponding RPC located behind it. If the same substitution
316  // happened in the neighboring sector, then the cancellation in uGMT
317  // will work correctly. If the substitution happened in only one
318  // sector, then RPC hit may "trump" a CSC hit, or vice versa.
319 
320  // A segment identifier (chamber, strip, bx)
321  const segment_ref_t segment = {{conv_hit.PC_station()*9 + conv_hit.PC_chamber(), (conv_hit.PC_segment() % 2), conv_hit.BX()}}; // FW doesn't check whether a segment is CSC or RPC
322  //int chamber_index = int(conv_hit.Subsystem() == TriggerPrimitive::kRPC)*9*5;
323  //chamber_index += conv_hit.PC_station()*9;
324  //chamber_index += conv_hit.PC_chamber();
325  //const segment_ref_t segment = {{chamber_index, conv_hit.Strip(), conv_hit.BX()}};
326  segments.at(hzn).push_back(segment);
327  }
328  } // end loop over n
329  } // end loop over z
330  } // end loop over h
331 
332  // Simultaneously compare each rank with each other
333  int i=0, j=0, ri=0, rj=0, sum=0;
334 
335  for (i = 0; i < max_hzn; ++i) {
336  //for (j = 0; j < max_hzn; ++j) {
337  // larger[i][j] = 0;
338  //}
339  larger[i][i] = true; // result of comparison with itself
340  //ri = rank[i%4][i/4]; // first index loops zone, second loops candidate. Zone loops faster, so we give equal priority to zones
341  ri = rank[i];
342 
343  for (j = i+1; j < max_hzn; ++j) {
344  // i&j bits show which rank is larger
345  //rj = rank[j%4][j/4];
346  rj = rank[j];
347  if (ri >= rj)
348  larger[i][j] = true;
349  else
350  larger[j][i] = true;
351  }
352  // "larger" array shows the result of comparison for each rank
353 
354  // track exists if quality != 0
355  exists[i] = (ri != 0);
356  }
357 
358  // ghost cancellation, over 3 BXs
359  for (i = 0; i < max_hzn-1; ++i) { // candidate loop
360  for (j = i+1; j < max_hzn; ++j) { // comparison candidate loop
361  int shared_segs = 0;
362 
363  // count shared segments
364  for (const auto& isegment : segments.at(i)) { // loop over all pairs of hits
365  for (const auto& jsegment : segments.at(j)) {
366  if (isegment == jsegment) { // same chamber and same segment
367  shared_segs += 1;
368  }
369  }
370  }
371 
372  if (shared_segs > 0) { // a single shared segment means it's ghost
373  // kill candidate that has lower rank
374  if (larger[i][j])
375  killed[j] = true;
376  else
377  killed[i] = true;
378  }
379  }
380  }
381 
382  // remove ghosts according to kill mask
383  //exists = exists & (~kill1);
384  for (i = 0; i < max_hzn; ++i) {
385  exists[i] = exists[i] & (!killed[i]);
386  }
387 
388  // remove tracks that are not at correct BX number
389  //exists = exists & good_bx;
390  for (i = 0; i < max_hzn; ++i) {
391  exists[i] = exists[i] & good_bx[i];
392  }
393 
394  bool anything_exists = (std::find(exists.begin(), exists.end(), 1) != exists.end());
395  if (!anything_exists)
396  return;
397 
398  // update "larger" array
399  for (i = 0; i < max_hzn; ++i) {
400  for (j = 0; j < max_hzn; ++j) {
401  //if (exists[i]) larger[i] = larger[i] | (~exists); // if this track exists make it larger than all non-existing tracks
402  //else larger[i] = 0; // else make it smaller than anything
403  if (exists[i])
404  larger[i][j] = larger[i][j] | (!exists[j]);
405  else
406  larger[i][j] = false;
407  }
408  }
409 
410  if (verbose_ > 0) { // debug
411  std::cout << "exists: ";
412  for (i = max_hzn-1; i >= 0; --i) {
413  std::cout << exists[i];
414  if ((i%max_zn) == 0 && i != 0) std::cout << "_";
415  }
416  std::cout << std::endl;
417  std::cout << "killed: ";
418  for (i = max_hzn-1; i >= 0; --i) {
419  std::cout << killed[i];
420  if ((i%max_zn) == 0 && i != 0) std::cout << "_";
421  }
422  std::cout << std::endl;
423  for (j = 0; j < max_hzn; ++j) {
424  std::cout << "larger: ";
425  for (i = max_hzn-1; i >= 0; --i) {
426  std::cout << larger[j][i];
427  if ((i%max_zn) == 0 && i != 0) std::cout << "_";
428  }
429  std::cout << std::endl;
430  }
431  }
432 
433  // count zeros in the comparison results. The best track will have none, the next will have one, the third will have two
434  for (i = 0; i < max_hzn; ++i) {
435  sum = 0;
436  for (j = 0; j < max_hzn; ++j) {
437  if (larger[i][j] == 0)
438  sum += 1;
439  }
440 
441  if (sum < maxTracks_) {
442  winner[sum][i] = true; // assign positional winner codes
443  }
444 
445  if (sum < maxTracks_ && bugSameSectorPt0_ && sum > 0) {
446  // just keep the best track and kill the rest of them
447  winner[sum][i] = false;
448  }
449  }
450 
451  // Output best tracks according to winner signals
452  best_tracks.clear();
453 
454  for (int o = 0; o < maxTracks_; ++o) { // output candidate loop
455  int h = 0, n = 0, z = 0;
456  for (i = 0; i < max_hzn; ++i) { // winner bit loop
457  if (winner[o][i]) {
458  h = (i / max_z / max_n);
459  n = (i / max_z) % max_n;
460  z = i % max_z;
461 
462  const EMTFTrackCollection& tracks = extended_best_track_cands.at(h*max_z + z);
463  const EMTFTrack& track = tracks.at(n);
464  best_tracks.push_back(track);
465 
466  // Update winner, BX
467  best_tracks.back().set_track_num ( best_tracks.size() - 1 );
468  best_tracks.back().set_winner ( o );
469  best_tracks.back().set_bx ( best_tracks.back().Second_BX() );
470  }
471  }
472  }
473 }
static char to_hex(unsigned int i)
Definition: types.cc:29
void process(const std::deque< EMTFTrackCollection > &extended_best_track_cands, EMTFTrackCollection &best_tracks) const
bool verbose
FWCore Framework interface EventSetupRecordImplementation h
Helper function to determine trigger accepts.
int killed
Definition: mps_check.py:38
int NUM_ZONES
Definition: Common.h:67
void cancel_multi_bx(const std::deque< EMTFTrackCollection > &extended_best_track_cands, EMTFTrackCollection &best_tracks) const
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:20
l1t::EMTFTrackCollection EMTFTrackCollection
Definition: Common.h:29
int NUM_STATIONS
Definition: Common.h:71
int Second_BX() const
Definition: EMTFTrack.h:136
void configure(int verbose, int endcap, int sector, int bx, int bxWindow, int maxRoadsPerZone, int maxTracks, bool useSecondEarliest, bool bugSameSectorPt0)
EMTFHitCollection Hits() const
Definition: EMTFTrack.h:81
int Rank() const
Definition: EMTFTrack.h:131
void cancel_one_bx(const std::deque< EMTFTrackCollection > &extended_best_track_cands, EMTFTrackCollection &best_tracks) const