Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:20:56

0001 #include "L1Trigger/L1TMuonEndCap/interface/BestTrackSelection.h"
0002 
0003 #include "helper.h"  // to_hex, to_binary
0004 
0005 void BestTrackSelection::configure(int verbose,
0006                                    int endcap,
0007                                    int sector,
0008                                    int bx,
0009                                    int bxWindow,
0010                                    int maxRoadsPerZone,
0011                                    int maxTracks,
0012                                    bool useSecondEarliest,
0013                                    bool bugSameSectorPt0) {
0014   verbose_ = verbose;
0015   endcap_ = endcap;
0016   sector_ = sector;
0017   bx_ = bx;
0018 
0019   bxWindow_ = bxWindow;
0020   maxRoadsPerZone_ = maxRoadsPerZone;
0021   maxTracks_ = maxTracks;
0022   useSecondEarliest_ = useSecondEarliest;
0023   bugSameSectorPt0_ = bugSameSectorPt0;
0024 }
0025 
0026 void BestTrackSelection::process(const std::deque<EMTFTrackCollection>& extended_best_track_cands,
0027                                  EMTFTrackCollection& best_tracks) const {
0028   int num_cands = 0;
0029   for (const auto& cands : extended_best_track_cands) {
0030     for (const auto& cand : cands) {
0031       if (cand.Rank() > 0) {
0032         num_cands += 1;
0033       }
0034     }
0035   }
0036   bool early_exit = (num_cands == 0);
0037 
0038   if (early_exit)
0039     return;
0040 
0041   if (!useSecondEarliest_) {
0042     cancel_one_bx(extended_best_track_cands, best_tracks);
0043   } else {
0044     cancel_multi_bx(extended_best_track_cands, best_tracks);
0045   }
0046 
0047   if (verbose_ > 0) {  // debug
0048     for (const auto& track : best_tracks) {
0049       std::cout << "track: " << track.Winner() << " rank: " << to_hex(track.Rank())
0050                 << " ph_deltas: " << array_as_string(track.PtLUT().delta_ph)
0051                 << " th_deltas: " << array_as_string(track.PtLUT().delta_th) << " phi: " << track.Phi_fp()
0052                 << " theta: " << track.Theta_fp() << " cpat: " << array_as_string(track.PtLUT().cpattern)
0053                 << " bx: " << track.BX() << std::endl;
0054       for (int i = 0; i < emtf::NUM_STATIONS + 1; ++i) {  // stations 0-4
0055         if (track.PtLUT().bt_vi[i] != 0)
0056           std::cout << ".. track segments: st: " << i << " v: " << track.PtLUT().bt_vi[i]
0057                     << " h: " << track.PtLUT().bt_hi[i] << " c: " << track.PtLUT().bt_ci[i]
0058                     << " s: " << track.PtLUT().bt_si[i] << std::endl;
0059       }
0060     }
0061   }
0062 }
0063 
0064 void BestTrackSelection::cancel_one_bx(const std::deque<EMTFTrackCollection>& extended_best_track_cands,
0065                                        EMTFTrackCollection& best_tracks) const {
0066   const int max_z = emtf::NUM_ZONES;   // = 4 zones
0067   const int max_n = maxRoadsPerZone_;  // = 3 candidates per zone
0068   const int max_zn = max_z * max_n;    // = 12 total candidates
0069   emtf_assert(maxTracks_ <= max_zn);
0070 
0071   // Emulate the arrays used in firmware
0072   typedef std::array<int, 3> segment_ref_t;
0073   std::vector<std::vector<segment_ref_t> > segments(max_zn,
0074                                                     std::vector<segment_ref_t>());  // 2D array [zn][num segments]
0075 
0076   std::vector<std::vector<bool> > larger(max_zn, std::vector<bool>(max_zn, false));  // 2D array [zn][zn]
0077   std::vector<std::vector<bool> > winner(max_zn, std::vector<bool>(max_zn, false));
0078 
0079   std::vector<bool> exists(max_zn, false);  // 1D array [zn]
0080   std::vector<bool> killed(max_zn, false);
0081   std::vector<int> rank(max_zn, 0);
0082   //std::vector<int>  good_bx(max_zn, 0);
0083 
0084   // Initialize arrays: rank, segments
0085   for (int z = 0; z < max_z; ++z) {
0086     const EMTFTrackCollection& tracks = extended_best_track_cands.at(z);
0087     const int ntracks = tracks.size();
0088     emtf_assert(ntracks <= max_n);
0089 
0090     for (int n = 0; n < ntracks; ++n) {
0091       const int zn = (n * max_z) + z;  // for (i = 0; i < 12; i = i+1) rank[i%4][i/4]
0092       const EMTFTrack& track = tracks.at(n);
0093 
0094       rank.at(zn) = track.Rank();
0095 
0096       for (const auto& conv_hit : track.Hits()) {
0097         emtf_assert(conv_hit.Valid());
0098 
0099         // A segment identifier (chamber, strip, bx)
0100         const segment_ref_t segment = {{conv_hit.PC_station() * 9 + conv_hit.PC_chamber(),
0101                                         (conv_hit.PC_segment() % 2),
0102                                         0}};  // FW doesn't check whether a segment is CSC or RPC
0103         //int chamber_index  = int(conv_hit.Subsystem() == TriggerPrimitive::kRPC)*9*5;
0104         //chamber_index     += conv_hit.PC_station()*9;
0105         //chamber_index     += conv_hit.PC_chamber();
0106         //const segment_ref_t segment = {{chamber_index, conv_hit.Strip(), 0}};
0107         segments.at(zn).push_back(segment);
0108       }
0109     }  // end loop over n
0110   }    // end loop over z
0111 
0112   // Simultaneously compare each rank with each other
0113   int i = 0, j = 0, ri = 0, rj = 0, gt = 0, eq = 0, sum = 0;
0114 
0115   for (i = 0; i < max_zn; ++i) {
0116     for (j = 0; j < max_zn; ++j) {
0117       larger[i][j] = false;
0118     }
0119     larger[i][i] = true;  // result of comparison with itself
0120     //ri = rank[i%4][i/4]; // first index loops zone, second loops candidate. Zone loops faster, so we give equal priority to zones
0121     ri = rank[i];
0122 
0123     for (j = 0; j < max_zn; ++j) {
0124       // i&j bits show which rank is larger
0125       // the comparison scheme below avoids problems
0126       // when there are two or more tracks with the same rank
0127       //rj = rank[j%4][j/4];
0128       rj = rank[j];
0129       gt = ri > rj;
0130       eq = ri == rj;
0131       if ((i < j && (gt || eq)) || (i > j && gt))
0132         larger[i][j] = true;
0133     }
0134     // "larger" array shows the result of comparison for each rank
0135 
0136     // track exists if quality != 0
0137     exists[i] = (ri != 0);
0138   }
0139 
0140   // ghost cancellation, only in the current BX so far
0141   for (i = 0; i < max_zn - 1; ++i) {    // candidate loop
0142     for (j = i + 1; j < max_zn; ++j) {  // comparison candidate loop
0143       int shared_segs = 0;
0144 
0145       // count shared segments
0146       for (const auto& isegment : segments.at(i)) {  // loop over all pairs of hits
0147         for (const auto& jsegment : segments.at(j)) {
0148           if (isegment == jsegment) {  // same chamber and same segment
0149             shared_segs += 1;
0150           }
0151         }
0152       }
0153 
0154       if (shared_segs > 0) {  // a single shared segment means it's ghost
0155         // kill candidate that has lower rank
0156         if (larger[i][j])
0157           killed[j] = true;
0158         else
0159           killed[i] = true;
0160       }
0161     }
0162   }
0163 
0164   // remove ghosts according to kill mask
0165   //exists = exists & (~kill1);
0166   for (i = 0; i < max_zn; ++i) {
0167     exists[i] = exists[i] && (!killed[i]);
0168   }
0169 
0170   bool anything_exists = (std::find(exists.begin(), exists.end(), 1) != exists.end());
0171   if (!anything_exists)
0172     return;
0173 
0174   // update "larger" array
0175   for (i = 0; i < max_zn; ++i) {
0176     for (j = 0; j < max_zn; ++j) {
0177       //if  (exists[i]) larger[i] = larger[i] | (~exists); // if this track exists make it larger than all non-existing tracks
0178       //else  larger[i] = 0; // else make it smaller than anything
0179       if (exists[i])
0180         larger[i][j] = larger[i][j] || (!exists[j]);
0181       else
0182         larger[i][j] = false;
0183     }
0184   }
0185 
0186   if (verbose_ > 0) {  // debug
0187     std::cout << "exists: ";
0188     for (i = max_zn - 1; i >= 0; --i) {
0189       std::cout << exists[i];
0190     }
0191     std::cout << std::endl;
0192     std::cout << "killed: ";
0193     for (i = max_zn - 1; i >= 0; --i) {
0194       std::cout << killed[i];
0195     }
0196     std::cout << std::endl;
0197     for (j = 0; j < max_zn; ++j) {
0198       std::cout << "larger: ";
0199       for (i = max_zn - 1; i >= 0; --i) {
0200         std::cout << larger[j][i];
0201       }
0202       std::cout << std::endl;
0203     }
0204   }
0205 
0206   // count zeros in the comparison results. The best track will have none, the next will have one, the third will have two
0207   // skip the bits corresponding to the comparison of the track with itself
0208   for (i = 0; i < max_zn; ++i) {
0209     sum = 0;
0210     for (j = 0; j < max_zn; ++j) {
0211       if (larger[i][j] == 0)
0212         sum += 1;
0213     }
0214 
0215     if (sum < maxTracks_) {
0216       winner[sum][i] = true;  // assign positional winner codes
0217     }
0218 
0219     if (sum < maxTracks_ && bugSameSectorPt0_ && sum > 0) {
0220       // just keep the best track and kill the rest of them
0221       winner[sum][i] = false;
0222     }
0223   }
0224 
0225   // Output best tracks according to winner signals
0226   best_tracks.clear();
0227 
0228   for (int o = 0; o < maxTracks_; ++o) {  // output candidate loop
0229     int z = 0, n = 0;
0230     for (i = 0; i < max_zn; ++i) {  // winner bit loop
0231       if (winner[o][i]) {
0232         n = i / max_z;
0233         z = i % max_z;
0234 
0235         const EMTFTrackCollection& tracks = extended_best_track_cands.at(z);
0236         const EMTFTrack& track = tracks.at(n);
0237         best_tracks.push_back(track);
0238 
0239         // Update winner, BX
0240         best_tracks.back().set_track_num(best_tracks.size() - 1);
0241         best_tracks.back().set_winner(o);
0242         best_tracks.back().set_bx(best_tracks.back().First_BX());
0243       }
0244     }
0245   }
0246 }
0247 
0248 void BestTrackSelection::cancel_multi_bx(const std::deque<EMTFTrackCollection>& extended_best_track_cands,
0249                                          EMTFTrackCollection& best_tracks) const {
0250   const int max_h = bxWindow_;         // = 3 bx history
0251   const int max_z = emtf::NUM_ZONES;   // = 4 zones
0252   const int max_n = maxRoadsPerZone_;  // = 3 candidates per zone
0253   const int max_zn = max_z * max_n;    // = 12 total candidates
0254   const int max_hzn = max_h * max_zn;  // = 36 total candidates
0255   emtf_assert(maxTracks_ <= max_hzn);
0256 
0257   const int delayBX = bxWindow_ - 1;
0258   const int num_h = extended_best_track_cands.size() / max_z;  // num of bx history so far
0259 
0260   // Emulate the arrays used in firmware
0261   typedef std::array<int, 3> segment_ref_t;
0262   std::vector<std::vector<segment_ref_t> > segments(max_hzn,
0263                                                     std::vector<segment_ref_t>());  // 2D array [hzn][num segments]
0264 
0265   std::vector<std::vector<bool> > larger(max_hzn, std::vector<bool>(max_hzn, false));  // 2D array [hzn][hzn]
0266   std::vector<std::vector<bool> > winner(max_hzn, std::vector<bool>(max_hzn, false));
0267 
0268   std::vector<bool> exists(max_hzn, false);  // 1D array [hzn]
0269   std::vector<bool> killed(max_hzn, false);
0270   std::vector<int> rank(max_hzn, 0);
0271   std::vector<int> good_bx(max_hzn, 0);
0272 
0273   // Initialize arrays: rank, good_bx, segments
0274   for (int h = 0; h < num_h; ++h) {
0275     // 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]
0276     // extended_best_track_cands[4..7] has 4 zones for road/pattern BX-1 with possible tracks from [BX-3, BX-2, BX-1]
0277     // extended_best_track_cands[8..11] has 4 zones for road/pattern BX-2 with possible tracks from [BX-4, BX-3, BX-2]
0278 
0279     for (int z = 0; z < max_z; ++z) {
0280       const EMTFTrackCollection& tracks = extended_best_track_cands.at(h * max_z + z);
0281       const int ntracks = tracks.size();
0282       emtf_assert(ntracks <= max_n);
0283 
0284       for (int n = 0; n < ntracks; ++n) {
0285         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]
0286         const EMTFTrack& track = tracks.at(n);
0287         int cand_bx = track.Second_BX();
0288         cand_bx -= (bx_ - delayBX);  // convert track.second_bx=[BX-2, BX-1, BX-0] --> cand_bx=[0,1,2]
0289 
0290         rank.at(hzn) = track.Rank();
0291         if (cand_bx == 0)
0292           good_bx.at(hzn) = 1;  // kill this rank if it's not the right BX
0293 
0294         for (const auto& conv_hit : track.Hits()) {
0295           emtf_assert(conv_hit.Valid());
0296 
0297           // Notes from Alex (2017-03-16):
0298           //
0299           //     What happens currently is that RPC hits are inserted instead of
0300           // CSC hits, if CSC hits are missing. So the track address will point
0301           // at a CSC chamber, but the actual hit may have come from
0302           // corresponding RPC located behind it. If the same substitution
0303           // happened in the neighboring sector, then the cancellation in uGMT
0304           // will work correctly. If the substitution happened in only one
0305           // sector, then RPC hit may "trump" a CSC hit, or vice versa.
0306 
0307           // A segment identifier (chamber, strip, bx)
0308           const segment_ref_t segment = {{conv_hit.PC_station() * 9 + conv_hit.PC_chamber(),
0309                                           (conv_hit.PC_segment() % 2),
0310                                           conv_hit.BX()}};  // FW doesn't check whether a segment is CSC or RPC
0311           //int chamber_index  = int(conv_hit.Subsystem() == TriggerPrimitive::kRPC)*9*5;
0312           //chamber_index     += conv_hit.PC_station()*9;
0313           //chamber_index     += conv_hit.PC_chamber();
0314           //const segment_ref_t segment = {{chamber_index, conv_hit.Strip(), conv_hit.BX()}};
0315           segments.at(hzn).push_back(segment);
0316         }
0317       }  // end loop over n
0318     }    // end loop over z
0319   }      // end loop over h
0320 
0321   // Simultaneously compare each rank with each other
0322   int i = 0, j = 0, ri = 0, rj = 0, sum = 0;
0323 
0324   for (i = 0; i < max_hzn; ++i) {
0325     //for (j = 0; j < max_hzn; ++j) {
0326     //  larger[i][j] = 0;
0327     //}
0328     larger[i][i] = true;  // result of comparison with itself
0329     //ri = rank[i%4][i/4]; // first index loops zone, second loops candidate. Zone loops faster, so we give equal priority to zones
0330     ri = rank[i];
0331 
0332     for (j = i + 1; j < max_hzn; ++j) {
0333       // i&j bits show which rank is larger
0334       //rj = rank[j%4][j/4];
0335       rj = rank[j];
0336       if (ri >= rj)
0337         larger[i][j] = true;
0338       else
0339         larger[j][i] = true;
0340     }
0341     // "larger" array shows the result of comparison for each rank
0342 
0343     // track exists if quality != 0
0344     exists[i] = (ri != 0);
0345   }
0346 
0347   // ghost cancellation, over 3 BXs
0348   for (i = 0; i < max_hzn - 1; ++i) {    // candidate loop
0349     for (j = i + 1; j < max_hzn; ++j) {  // comparison candidate loop
0350       int shared_segs = 0;
0351 
0352       // count shared segments
0353       for (const auto& isegment : segments.at(i)) {  // loop over all pairs of hits
0354         for (const auto& jsegment : segments.at(j)) {
0355           if (isegment == jsegment) {  // same chamber and same segment
0356             shared_segs += 1;
0357           }
0358         }
0359       }
0360 
0361       if (shared_segs > 0) {  // a single shared segment means it's ghost
0362         // kill candidate that has lower rank
0363         if (larger[i][j])
0364           killed[j] = true;
0365         else
0366           killed[i] = true;
0367       }
0368     }
0369   }
0370 
0371   // remove ghosts according to kill mask
0372   //exists = exists & (~kill1);
0373   for (i = 0; i < max_hzn; ++i) {
0374     exists[i] = exists[i] && (!killed[i]);
0375   }
0376 
0377   // remove tracks that are not at correct BX number
0378   //exists = exists & good_bx;
0379   for (i = 0; i < max_hzn; ++i) {
0380     exists[i] = exists[i] & good_bx[i];
0381   }
0382 
0383   bool anything_exists = (std::find(exists.begin(), exists.end(), 1) != exists.end());
0384   if (!anything_exists)
0385     return;
0386 
0387   // update "larger" array
0388   for (i = 0; i < max_hzn; ++i) {
0389     for (j = 0; j < max_hzn; ++j) {
0390       //if  (exists[i]) larger[i] = larger[i] | (~exists); // if this track exists make it larger than all non-existing tracks
0391       //else  larger[i] = 0; // else make it smaller than anything
0392       if (exists[i])
0393         larger[i][j] = larger[i][j] || (!exists[j]);
0394       else
0395         larger[i][j] = false;
0396     }
0397   }
0398 
0399   if (verbose_ > 0) {  // debug
0400     std::cout << "exists: ";
0401     for (i = max_hzn - 1; i >= 0; --i) {
0402       std::cout << exists[i];
0403       if ((i % max_zn) == 0 && i != 0)
0404         std::cout << "_";
0405     }
0406     std::cout << std::endl;
0407     std::cout << "killed: ";
0408     for (i = max_hzn - 1; i >= 0; --i) {
0409       std::cout << killed[i];
0410       if ((i % max_zn) == 0 && i != 0)
0411         std::cout << "_";
0412     }
0413     std::cout << std::endl;
0414     for (j = 0; j < max_hzn; ++j) {
0415       std::cout << "larger: ";
0416       for (i = max_hzn - 1; i >= 0; --i) {
0417         std::cout << larger[j][i];
0418         if ((i % max_zn) == 0 && i != 0)
0419           std::cout << "_";
0420       }
0421       std::cout << std::endl;
0422     }
0423   }
0424 
0425   // count zeros in the comparison results. The best track will have none, the next will have one, the third will have two
0426   for (i = 0; i < max_hzn; ++i) {
0427     sum = 0;
0428     for (j = 0; j < max_hzn; ++j) {
0429       if (larger[i][j] == 0)
0430         sum += 1;
0431     }
0432 
0433     if (sum < maxTracks_) {
0434       winner[sum][i] = true;  // assign positional winner codes
0435     }
0436 
0437     if (sum < maxTracks_ && bugSameSectorPt0_ && sum > 0) {
0438       // just keep the best track and kill the rest of them
0439       winner[sum][i] = false;
0440     }
0441   }
0442 
0443   // Output best tracks according to winner signals
0444   best_tracks.clear();
0445 
0446   for (int o = 0; o < maxTracks_; ++o) {  // output candidate loop
0447     int h = 0, n = 0, z = 0;
0448     for (i = 0; i < max_hzn; ++i) {  // winner bit loop
0449       if (winner[o][i]) {
0450         h = (i / max_z / max_n);
0451         n = (i / max_z) % max_n;
0452         z = i % max_z;
0453 
0454         const EMTFTrackCollection& tracks = extended_best_track_cands.at(h * max_z + z);
0455         const EMTFTrack& track = tracks.at(n);
0456         best_tracks.push_back(track);
0457 
0458         // Update winner, BX
0459         best_tracks.back().set_track_num(best_tracks.size() - 1);
0460         best_tracks.back().set_winner(o);
0461         best_tracks.back().set_bx(best_tracks.back().Second_BX());
0462       }
0463     }
0464   }
0465 }