Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 #include "L1Trigger/L1TMuonEndCap/interface/PrimitiveMatching.h"
0002 #include "DataFormats/L1TMuon/interface/L1TMuonSubsystems.h"
0003 
0004 #include "helper.h"  // to_hex, to_binary, merge_sort3
0005 
0006 namespace {
0007   const int bw_fph = 13;              // bit width of ph, full precision
0008   const int bpow = 7;                 // (1 << bpow) is count of input ranks
0009   const int invalid_ph_diff = 0x1ff;  // 511 (9-bit)
0010 }  // namespace
0011 
0012 void PrimitiveMatching::configure(int verbose,
0013                                   int endcap,
0014                                   int sector,
0015                                   int bx,
0016                                   bool fixZonePhi,
0017                                   bool useNewZones,
0018                                   bool bugSt2PhDiff,
0019                                   bool bugME11Dupes) {
0020   verbose_ = verbose;
0021   endcap_ = endcap;
0022   sector_ = sector;
0023   bx_ = bx;
0024 
0025   fixZonePhi_ = fixZonePhi;
0026   useNewZones_ = useNewZones;
0027   bugSt2PhDiff_ = bugSt2PhDiff;
0028   bugME11Dupes_ = bugME11Dupes;
0029 }
0030 
0031 void PrimitiveMatching::process(const std::deque<EMTFHitCollection>& extended_conv_hits,
0032                                 const emtf::zone_array<EMTFRoadCollection>& zone_roads,
0033                                 emtf::zone_array<EMTFTrackCollection>& zone_tracks) const {
0034   // Function to update fs_history encoded in fs_segment
0035   auto update_fs_history = [](int fs_segment, int this_bx, int hit_bx) {
0036     // 0 for current BX, 1 for previous BX, 2 for BX before that
0037     int fs_history = this_bx - hit_bx;
0038     fs_segment |= ((fs_history & 0x3) << 4);
0039     return fs_segment;
0040   };
0041 
0042   // Function to update bt_history encoded in bt_segment
0043   auto update_bt_history = [](int bt_segment, int this_bx, int hit_bx) {
0044     // 0 for current BX, 1 for previous BX, 2 for BX before that
0045     int bt_history = this_bx - hit_bx;
0046     bt_segment |= ((bt_history & 0x3) << 5);
0047     return bt_segment;
0048   };
0049 
0050   // Exit if no roads
0051   int num_roads = 0;
0052   for (const auto& roads : zone_roads)
0053     num_roads += roads.size();
0054   bool early_exit = (num_roads == 0);
0055 
0056   if (early_exit)
0057     return;
0058 
0059   if (verbose_ > 0) {  // debug
0060     for (const auto& roads : zone_roads) {
0061       for (const auto& road : roads) {
0062         std::cout << "pattern on match input: z: " << road.Zone() - 1 << " r: " << road.Winner()
0063                   << " ph_num: " << road.Key_zhit() << " ph_q: " << to_hex(road.Quality_code())
0064                   << " ly: " << to_binary(road.Layer_code(), 3) << " str: " << to_binary(road.Straightness(), 3)
0065                   << std::endl;
0066       }
0067     }
0068   }
0069 
0070   // Organize converted hits by (zone, station)
0071   std::array<EMTFHitCollection, emtf::NUM_ZONES * emtf::NUM_STATIONS> zs_conv_hits;
0072 
0073   bool use_fs_zone_code = true;  // use zone code as in firmware find_segment module
0074 
0075   std::deque<EMTFHitCollection>::const_iterator ext_conv_hits_it = extended_conv_hits.begin();
0076   std::deque<EMTFHitCollection>::const_iterator ext_conv_hits_end = extended_conv_hits.end();
0077 
0078   for (; ext_conv_hits_it != ext_conv_hits_end; ++ext_conv_hits_it) {
0079     EMTFHitCollection::const_iterator conv_hits_it = ext_conv_hits_it->begin();
0080     EMTFHitCollection::const_iterator conv_hits_end = ext_conv_hits_it->end();
0081 
0082     for (; conv_hits_it != conv_hits_end; ++conv_hits_it) {
0083       int istation = conv_hits_it->Station() - 1;
0084       int zone_code = conv_hits_it->Zone_code();  // decide based on original zone code
0085       if (use_fs_zone_code)
0086         zone_code = conv_hits_it->FS_zone_code();  // decide based on new zone code
0087 
0088       // A hit can go into multiple zones
0089       for (int izone = 0; izone < emtf::NUM_ZONES; ++izone) {
0090         if (!zone_roads.at(izone).empty()) {
0091           if (zone_code & (1 << izone)) {
0092             const int zs = (izone * emtf::NUM_STATIONS) + istation;
0093             zs_conv_hits.at(zs).push_back(*conv_hits_it);
0094 
0095             // Update fs_history and bt_history depending on the processor BX
0096             // This update only goes into the hits associated to a track, it does not affect the original hit collection
0097             EMTFHit& conv_hit = zs_conv_hits.at(zs).back();  // pass by reference
0098             int old_fs_segment = conv_hit.FS_segment();
0099             int new_fs_segment = update_fs_history(old_fs_segment, bx_, conv_hit.BX());
0100             conv_hit.set_fs_segment(new_fs_segment);
0101 
0102             int old_bt_segment = conv_hit.BT_segment();
0103             int new_bt_segment = update_bt_history(old_bt_segment, bx_, conv_hit.BX());
0104             conv_hit.set_bt_segment(new_bt_segment);
0105           }
0106         }
0107       }
0108 
0109     }  // end loop over conv_hits
0110   }    // end loop over extended_conv_hits
0111 
0112   if (verbose_ > 1) {  // debug
0113     for (int izone = 0; izone < emtf::NUM_ZONES; ++izone) {
0114       for (int istation = 0; istation < emtf::NUM_STATIONS; ++istation) {
0115         const int zs = (izone * emtf::NUM_STATIONS) + istation;
0116         for (const auto& conv_hit : zs_conv_hits.at(zs)) {
0117           std::cout << "z: " << izone << " st: " << istation + 1 << " cscid: " << conv_hit.CSC_ID()
0118                     << " ph_zone_phi: " << conv_hit.Zone_hit() << " ph_low_prec: " << (conv_hit.Zone_hit() << 5)
0119                     << " ph_high_prec: " << conv_hit.Phi_fp()
0120                     << " ph_high_low_diff: " << (conv_hit.Phi_fp() - (conv_hit.Zone_hit() << 5)) << std::endl;
0121         }
0122       }
0123     }
0124   }
0125 
0126   // Keep the best phi difference for every road by (zone, station)
0127   std::array<std::vector<hit_sort_pair_t>, emtf::NUM_ZONES * emtf::NUM_STATIONS> zs_phi_differences;
0128 
0129   // Get the best-matching hits by comparing phi difference between
0130   // pattern and segment
0131   for (int izone = 0; izone < emtf::NUM_ZONES; ++izone) {
0132     for (int istation = 0; istation < emtf::NUM_STATIONS; ++istation) {
0133       const int zs = (izone * emtf::NUM_STATIONS) + istation;
0134 
0135       // This leaves zone_roads.at(izone) and zs_conv_hits.at(zs) unchanged
0136       // zs_phi_differences.at(zs) gets filled with a pair of <phi_diff, conv_hit> for the
0137       // conv_hit with the lowest phi_diff from the pattern in this station and zone
0138       process_single_zone_station(
0139           izone + 1, istation + 1, zone_roads.at(izone), zs_conv_hits.at(zs), zs_phi_differences.at(zs));
0140       emtf_assert(zone_roads.at(izone).size() == zs_phi_differences.at(zs).size());
0141     }  // end loop over stations
0142   }    // end loop over zones
0143 
0144   if (verbose_ > 1) {  // debug
0145     for (int izone = 0; izone < emtf::NUM_ZONES; ++izone) {
0146       const auto& roads = zone_roads.at(izone);
0147       for (unsigned iroad = 0; iroad < roads.size(); ++iroad) {
0148         const auto& road = roads.at(iroad);
0149         for (int istation = 0; istation < emtf::NUM_STATIONS; ++istation) {
0150           const int zs = (izone * emtf::NUM_STATIONS) + istation;
0151           int ph_diff = zs_phi_differences.at(zs).at(iroad).first;
0152           std::cout << "find seg: z: " << road.Zone() - 1 << " r: " << road.Winner() << " st: " << istation
0153                     << " ph_diff: " << ph_diff << std::endl;
0154         }
0155       }
0156     }
0157   }
0158 
0159   // Build all tracks in each zone
0160   for (int izone = 0; izone < emtf::NUM_ZONES; ++izone) {
0161     const EMTFRoadCollection& roads = zone_roads.at(izone);
0162 
0163     for (unsigned iroad = 0; iroad < roads.size(); ++iroad) {
0164       const EMTFRoad& road = roads.at(iroad);
0165 
0166       // Create a track
0167       EMTFTrack track;
0168       track.set_endcap(road.Endcap());
0169       track.set_sector(road.Sector());
0170       track.set_sector_idx(road.Sector_idx());
0171       track.set_bx(road.BX());
0172       track.set_zone(road.Zone());
0173       track.set_ph_num(road.Key_zhit());
0174       track.set_ph_q(road.Quality_code());
0175       track.set_rank(road.Quality_code());
0176       track.set_winner(road.Winner());
0177 
0178       track.clear_Hits();
0179 
0180       // Insert hits
0181       for (int istation = 0; istation < emtf::NUM_STATIONS; ++istation) {
0182         const int zs = (izone * emtf::NUM_STATIONS) + istation;
0183 
0184         const EMTFHitCollection& conv_hits = zs_conv_hits.at(zs);
0185         int ph_diff = zs_phi_differences.at(zs).at(iroad).first;
0186         hit_ptr_t conv_hit_ptr = zs_phi_differences.at(zs).at(iroad).second;
0187 
0188         if (ph_diff != invalid_ph_diff) {
0189           // Inserts the conv_hit with the lowest phi_diff, as well as its duplicate
0190           // (same strip and phi, different wire and theta), if a duplicate exists
0191           insert_hits(conv_hit_ptr, conv_hits, track);
0192         }
0193       }
0194 
0195       if (fixZonePhi_) {
0196         emtf_assert(!track.Hits().empty());
0197       }
0198 
0199       // Output track
0200       zone_tracks.at(izone).push_back(track);
0201 
0202     }  // end loop over roads
0203   }    // end loop over zones
0204 
0205   if (verbose_ > 0) {  // debug
0206     for (const auto& tracks : zone_tracks) {
0207       for (const auto& track : tracks) {
0208         for (const auto& hit : track.Hits()) {
0209           std::cout << "match seg: z: " << track.Zone() - 1 << " pat: " << track.Winner() << " st: " << hit.Station()
0210                     << " vi: " << to_binary(0b1, 2) << " hi: " << ((hit.FS_segment() >> 4) & 0x3)
0211                     << " ci: " << ((hit.FS_segment() >> 1) & 0x7) << " si: " << (hit.FS_segment() & 0x1)
0212                     << " ph: " << hit.Phi_fp() << " th: " << hit.Theta_fp() << std::endl;
0213         }
0214       }
0215     }
0216   }
0217 }
0218 
0219 void PrimitiveMatching::process_single_zone_station(int zone,
0220                                                     int station,
0221                                                     const EMTFRoadCollection& roads,
0222                                                     const EMTFHitCollection& conv_hits,
0223                                                     std::vector<hit_sort_pair_t>& phi_differences) const {
0224   // max phi difference between pattern and segment
0225   // This doesn't depend on the pattern straightness - any hit within the max phi difference may match
0226   int max_ph_diff = (station == 1) ? 15 : 7;
0227   //int bw_ph_diff = (station == 1) ? 5 : 4; // ph difference bit width
0228   //int invalid_ph_diff = (station == 1) ? 31 : 15;  // invalid difference
0229 
0230   if (fixZonePhi_) {
0231     if (station == 1) {
0232       max_ph_diff = 496;  // width of pattern in ME1 + rounding error 15*32+16
0233       //bw_ph_diff = 9;
0234       //invalid_ph_diff = 0x1ff;
0235     } else if (station == 2) {
0236       if (bugSt2PhDiff_)
0237         max_ph_diff = 16;  // just rounding error for ME2 (pattern must match ME2 hit phi if there was one)
0238       else
0239         max_ph_diff = 240;  // same as ME3,4
0240       //bw_ph_diff = 5;
0241       //invalid_ph_diff = 0x1f;
0242     } else {
0243       max_ph_diff = 240;  // width of pattern in ME3,4 + rounding error 7*32+16
0244       //bw_ph_diff = 8;
0245       //invalid_ph_diff = 0xff;
0246     }
0247   }
0248 
0249   auto abs_diff = [](int a, int b) { return std::abs(a - b); };
0250 
0251   // Simple sort by ph_diff
0252   struct {
0253     typedef hit_sort_pair_t value_type;
0254     bool operator()(const value_type& lhs, const value_type& rhs) const { return lhs.first <= rhs.first; }
0255   } less_ph_diff_cmp;
0256 
0257   // Emulation of FW sorting with 3-way comparator
0258   struct {
0259     typedef hit_sort_pair_t value_type;
0260     int operator()(const value_type& a, const value_type& b, const value_type& c) const {
0261       int r = 0;
0262       r |= bool(a.first <= b.first);
0263       r <<= 1;
0264       r |= bool(b.first <= c.first);
0265       r <<= 1;
0266       r |= bool(c.first <= a.first);
0267 
0268       int rr = 0;
0269       switch (r) {
0270         //case 0b000 : rr = 3; break;  // invalid
0271         case 0b001:
0272           rr = 2;
0273           break;  // c
0274         case 0b010:
0275           rr = 1;
0276           break;  // b
0277         case 0b011:
0278           rr = 1;
0279           break;  // b
0280         case 0b100:
0281           rr = 0;
0282           break;  // a
0283         case 0b101:
0284           rr = 2;
0285           break;  // c
0286         case 0b110:
0287           rr = 0;
0288           break;  // a
0289         //case 0b111 : rr = 0; break;  // invalid
0290         default:
0291           rr = 0;
0292           break;
0293       }
0294       return rr;
0295     }
0296   } less_ph_diff_cmp3;
0297 
0298   // ___________________________________________________________________________
0299   // For each road, find the segment with min phi difference in every station
0300 
0301   EMTFRoadCollection::const_iterator roads_it = roads.begin();
0302   EMTFRoadCollection::const_iterator roads_end = roads.end();
0303 
0304   for (; roads_it != roads_end; ++roads_it) {
0305     int ph_pat = roads_it->Key_zhit();    // pattern key phi value
0306     int ph_q = roads_it->Quality_code();  // pattern quality code
0307     emtf_assert(ph_pat >= 0 && ph_q > 0);
0308 
0309     if (fixZonePhi_) {
0310       ph_pat <<= 5;  // add missing 5 lower bits to pattern phi
0311     }
0312 
0313     std::vector<hit_sort_pair_t> tmp_phi_differences;
0314 
0315     EMTFHitCollection::const_iterator conv_hits_it = conv_hits.begin();
0316     EMTFHitCollection::const_iterator conv_hits_end = conv_hits.end();
0317 
0318     for (; conv_hits_it != conv_hits_end; ++conv_hits_it) {
0319       int ph_seg = conv_hits_it->Phi_fp();             // ph from segments
0320       int ph_seg_red = ph_seg >> (bw_fph - bpow - 1);  // remove unused low bits
0321       emtf_assert(ph_seg >= 0);
0322 
0323       if (fixZonePhi_) {
0324         ph_seg_red = ph_seg;  // use full-precision phi
0325       }
0326 
0327       // Get abs phi difference
0328       int ph_diff = abs_diff(ph_pat, ph_seg_red);
0329       if (ph_diff > max_ph_diff)
0330         ph_diff = invalid_ph_diff;  // difference is too high, cannot be the same pattern
0331 
0332       if (ph_diff != invalid_ph_diff)
0333         tmp_phi_differences.push_back(std::make_pair(ph_diff, conv_hits_it));  // make a key-value pair
0334     }
0335 
0336     // _________________________________________________________________________
0337     // Sort to find the segment with min phi difference
0338 
0339     if (!tmp_phi_differences.empty()) {
0340       // Because the sorting is sensitive to FW ordering, use the exact FW sorting.
0341       // This implementation still slightly differs from FW because I prefer to
0342       // use a sorting function that is as generic as possible.
0343       bool use_fw_sorting = true;
0344 
0345       if (useNewZones_)
0346         use_fw_sorting = false;
0347 
0348       if (use_fw_sorting) {
0349         // zone_cham = 4 for [fs_01, fs_02, fs_03, fs_11], or 7 otherwise
0350         // tot_diff = 27 or 45 in FW; it is 27 or 54 in the C++ merge_sort3 impl
0351         const int max_drift = 3;  // should use bxWindow from the config
0352         const int zone_cham = ((zone == 1 && (2 <= station && station <= 4)) || (zone == 2 && station == 2)) ? 4 : 7;
0353         const int seg_ch = 2;
0354         const int tot_diff =
0355             (max_drift * zone_cham * seg_ch) + ((zone_cham == 4) ? 3 : 12);  // provide padding for 3-input comparators
0356 
0357         std::vector<hit_sort_pair_t> fw_sort_array(tot_diff, std::make_pair(invalid_ph_diff, conv_hits_end));
0358 
0359         // FW doesn't check if the hit is CSC or RPC
0360         std::vector<hit_sort_pair_t>::const_iterator phdiffs_it = tmp_phi_differences.begin();
0361         std::vector<hit_sort_pair_t>::const_iterator phdiffs_end = tmp_phi_differences.end();
0362 
0363         for (; phdiffs_it != phdiffs_end; ++phdiffs_it) {
0364           //int ph_diff    = phdiffs_it->first;
0365           int fs_segment = phdiffs_it->second->FS_segment();
0366 
0367           // Calculate the index to put into the fw_sort_array
0368           int fs_history = ((fs_segment >> 4) & 0x3);
0369           int fs_chamber = ((fs_segment >> 1) & 0x7);
0370           fs_segment = (fs_segment & 0x1);
0371           unsigned fw_sort_array_index = (fs_history * zone_cham * seg_ch) + (fs_chamber * seg_ch) + fs_segment;
0372 
0373           emtf_assert(fs_history < max_drift && fs_chamber < zone_cham && fs_segment < seg_ch);
0374           emtf_assert(fw_sort_array_index < fw_sort_array.size());
0375           fw_sort_array.at(fw_sort_array_index) = *phdiffs_it;
0376         }
0377 
0378         // Debug
0379         //std::cout << "phdiffs" << std::endl;
0380         //for (unsigned i = 0; i < fw_sort_array.size(); ++i)
0381         //  std::cout << fw_sort_array.at(i).first << " ";
0382         //std::cout << std::endl;
0383 
0384         // Debug
0385         //std::cout << "Before sort" << std::endl;
0386         //for (unsigned i = 0; i < fw_sort_array.size(); ++i)
0387         //  std::cout << fw_sort_array.at(i).second->FS_segment() << " ";
0388         //std::cout << std::endl;
0389 
0390         // Find the best phi difference according to FW sorting
0391         //merge_sort3(fw_sort_array.begin(), fw_sort_array.end(), less_ph_diff_cmp, less_ph_diff_cmp3);
0392         merge_sort3_with_hint(fw_sort_array.begin(),
0393                               fw_sort_array.end(),
0394                               less_ph_diff_cmp,
0395                               less_ph_diff_cmp3,
0396                               ((tot_diff == 54) ? tot_diff / 2 : tot_diff / 3));
0397 
0398         // Store the best phi difference
0399         phi_differences.push_back(fw_sort_array.front());
0400 
0401         // Debug
0402         //std::cout << "After sort" << std::endl;
0403         //for (unsigned i = 0; i < fw_sort_array.size(); ++i)
0404         //  std::cout << fw_sort_array.at(i).second->FS_segment() << " ";
0405         //std::cout << std::endl;
0406 
0407       } else {  // use C++ sorting
0408         struct {
0409           typedef hit_sort_pair_t value_type;
0410           bool operator()(const value_type& lhs, const value_type& rhs) const {
0411             // If different types, prefer CSC over RPC; else prefer the closer hit in dPhi
0412             if (lhs.second->Subsystem() != rhs.second->Subsystem())
0413               return (lhs.second->Subsystem() == L1TMuon::kCSC);
0414             else
0415               return lhs.first <= rhs.first;
0416           }
0417         } tmp_less_ph_diff_cmp;
0418 
0419         // Find best phi difference
0420         std::stable_sort(tmp_phi_differences.begin(), tmp_phi_differences.end(), tmp_less_ph_diff_cmp);
0421 
0422         // Store the best phi difference
0423         phi_differences.push_back(tmp_phi_differences.front());
0424       }
0425 
0426     } else {
0427       // No segment found
0428       phi_differences.push_back(std::make_pair(invalid_ph_diff, conv_hits_end));  // make a key-value pair
0429     }
0430 
0431   }  // end loop over roads
0432 }
0433 
0434 void PrimitiveMatching::insert_hits(hit_ptr_t conv_hit_ptr,
0435                                     const EMTFHitCollection& conv_hits,
0436                                     EMTFTrack& track) const {
0437   EMTFHitCollection::const_iterator conv_hits_it = conv_hits.begin();
0438   EMTFHitCollection::const_iterator conv_hits_end = conv_hits.end();
0439 
0440   const bool is_csc_me11 = (conv_hit_ptr->Subsystem() == L1TMuon::kCSC) && (conv_hit_ptr->Station() == 1) &&
0441                            (conv_hit_ptr->Ring() == 1 || conv_hit_ptr->Ring() == 4);
0442 
0443   // Find all possible duplicated hits, insert them
0444   for (; conv_hits_it != conv_hits_end; ++conv_hits_it) {
0445     const EMTFHit& conv_hit_i = *conv_hits_it;
0446     const EMTFHit& conv_hit_j = *conv_hit_ptr;
0447 
0448     // All these must match: [bx_history][station][chamber][segment]
0449     if ((conv_hit_i.Subsystem() == conv_hit_j.Subsystem()) && (conv_hit_i.PC_station() == conv_hit_j.PC_station()) &&
0450         (conv_hit_i.PC_chamber() == conv_hit_j.PC_chamber()) &&
0451         (conv_hit_i.Ring() == conv_hit_j.Ring()) &&  // because of ME1/1
0452         (conv_hit_i.Strip() == conv_hit_j.Strip()) &&
0453         //(conv_hit_i.Wire()       == conv_hit_j.Wire()) &&
0454         (conv_hit_i.Pattern() == conv_hit_j.Pattern()) && (conv_hit_i.BX() == conv_hit_j.BX()) &&
0455         ((conv_hit_i.Is_RPC() == false) ||
0456          ((conv_hit_i.Strip_low() == conv_hit_j.Strip_low()) && (conv_hit_i.Strip_hi() == conv_hit_j.Strip_hi()) &&
0457           (conv_hit_i.Roll() == conv_hit_j.Roll()) && (conv_hit_i.Phi_fp() == conv_hit_j.Phi_fp()) &&
0458           (conv_hit_i.Theta_fp() == conv_hit_j.Theta_fp()))) &&
0459         true) {
0460       // All duplicates with the same strip but different wire must have same phi_fp
0461       emtf_assert(conv_hit_i.Phi_fp() == conv_hit_j.Phi_fp());
0462 
0463       track.push_Hit(conv_hit_i);
0464 
0465     } else if ((bugME11Dupes_ &&
0466                 is_csc_me11) &&  // if reproduce ME1/1 theta duplication bug, do not check 'ring', 'strip' and 'pattern'
0467                (conv_hit_i.Subsystem() == conv_hit_j.Subsystem()) &&
0468                (conv_hit_i.PC_station() == conv_hit_j.PC_station()) &&
0469                (conv_hit_i.PC_chamber() == conv_hit_j.PC_chamber()) &&
0470                //(conv_hit_i.Ring()       == conv_hit_j.Ring()) &&  // because of ME1/1
0471                //(conv_hit_i.Strip()      == conv_hit_j.Strip()) &&
0472                //(conv_hit_i.Wire()       == conv_hit_j.Wire()) &&
0473                //(conv_hit_i.Pattern()    == conv_hit_j.Pattern()) &&
0474                (conv_hit_i.BX() == conv_hit_j.BX()) &&
0475                //(conv_hit_i.Strip_low()  == conv_hit_j.Strip_low()) && // For RPC clusters
0476                //(conv_hit_i.Strip_hi()   == conv_hit_j.Strip_hi()) &&  // For RPC clusters
0477                //(conv_hit_i.Roll()       == conv_hit_j.Roll()) &&      // For RPC clusters
0478                true) {
0479       // Dirty hack
0480       EMTFHit tmp_hit = conv_hit_j;
0481       tmp_hit.set_theta_fp(conv_hit_i.Theta_fp());
0482       track.push_Hit(tmp_hit);
0483     }
0484   }
0485 
0486   // Sort by station
0487   struct {
0488     typedef EMTFHit value_type;
0489     bool operator()(const value_type& lhs, const value_type& rhs) const { return lhs.Station() < rhs.Station(); }
0490   } less_station_cmp;
0491 
0492   EMTFHitCollection tmp_hits = track.Hits();
0493   std::stable_sort(tmp_hits.begin(), tmp_hits.end(), less_station_cmp);
0494   track.set_Hits(tmp_hits);
0495 }