CMS 3D CMS Logo

DupFitTrkKiller.cc
Go to the documentation of this file.
5 #include <map>
6 
7 using namespace std;
8 
9 namespace tmtt {
10 
11  //=== Make available cfg parameters & specify which algorithm is to be used for duplicate track removal.
12 
13  DupFitTrkKiller::DupFitTrkKiller(const Settings* settings)
14  : settings_(settings), dupTrkAlg_(static_cast<DupAlgoName>(settings->dupTrkAlgFit())) {}
15 
16  //=== Eliminate duplicate tracks from the input collection, and so return a reduced list of tracks.
17 
18  list<const L1fittedTrack*> DupFitTrkKiller::filter(const list<L1fittedTrack>& vecTracks) const {
20  // We are not running duplicate removal, so return original fitted track collection.
21  list<const L1fittedTrack*> copyTracks;
22  for (const L1fittedTrack& trk : vecTracks) {
23  copyTracks.push_back(&trk);
24  }
25  return copyTracks;
26 
27  } else {
28  // Choose which algorithm to run, based on parameter dupTrkAlg_.
29  switch (dupTrkAlg_) {
30  // Run filters that only work on fitted tracks.
31  case DupAlgoName::Algo1:
32  return filterAlg1(vecTracks);
33  break;
34  case DupAlgoName::Algo2:
35  return filterAlg2(vecTracks);
36  break;
37  default:
38  throw cms::Exception("BadConfig") << "KillDupTrks: Cfg option DupFitTrkAlg has invalid value.";
39  }
40  }
41  }
42 
43  //=== Duplicate removal algorithm designed to run after the track helix fit, which eliminates duplicates
44  //=== simply by requiring that the fitted (q/Pt, phi0) of the track correspond to the same HT cell in
45  //=== which the track was originally found by the HT.
46  //=== N.B. This code runs on tracks in a single sector. It could be extended to run on tracks in entire
47  //=== tracker by adding the track's sector number to memory "htCellUsed" below.
48 
49  list<const L1fittedTrack*> DupFitTrkKiller::filterAlg1(const list<L1fittedTrack>& tracks) const {
50  // Hard-wired options to play with.
51  constexpr bool debug = false;
52  constexpr bool doRecoveryStep = true; // Do 2nd pass through rejected tracks to see if any should be rescued.
53  constexpr bool reduceDups = true; // Option attempting to reduce duplicate tracks during 2nd pass.
54  constexpr bool memorizeAllHTcells =
55  false; // First pass stores in memory all cells that the HT found tracks in, not just those of tracks accepted by the first pass.
56  constexpr bool doSectorCheck = false; // Require fitted helix to lie within sector.
57  constexpr bool usePtAndZ0Cuts = false;
58  constexpr bool goOutsideArray = true; // Also store in memory stubs outside the HT array during 2nd pass.
59  constexpr bool limitDiff = true; // Limit allowed diff. between HT & Fit cell to <= 1.
60 
61  if (debug && not tracks.empty())
62  PrintL1trk() << "Start DupFitTrkKiller" << tracks.size();
63 
64  list<const L1fittedTrack*> tracksFiltered;
65 
66  // Make a first pass through the tracks, doing initial identification of duplicate tracks.
67  // N.B. BY FILLING THIS WITH CELLS AROUND SELECTED TRACKS, RATHER THAN JUST THE CELL CONTAINING THE
68  // TRACK, ONE CAN REDUCE THE DUPLICATE RATE FURTHER, AT COST TO EFFICIENCY.
69  set<pair<unsigned int, unsigned int>> htCellUsed;
70  list<const L1fittedTrack*> tracksRejected;
71 
72  // For checking if multiple tracks corresponding to same TP are accepted by duplicate removal.
73  map<unsigned int, pair<unsigned int, unsigned int>> tpFound;
74  map<unsigned int, unsigned int> tpFoundAtPass;
75 
76  for (const L1fittedTrack& trk : tracks) {
77  // Only consider tracks whose fitted helix parameters are in the same sector as the HT originally used to find the track.
78  if ((!doSectorCheck) || trk.consistentSector()) {
79  if ((!usePtAndZ0Cuts) ||
80  (std::abs(trk.z0()) < settings_->beamWindowZ() && trk.pt() > settings_->houghMinPt() - 0.2)) {
81  // For debugging.
82  [[clang::suppress]] const TP* tp = trk.matchedTP();
83 
84  // Check if this track's fitted (q/pt, phi0) helix parameters correspond to the same HT cell as the HT originally found the track in.
85  bool consistentCell = trk.consistentHTcell();
86  if (consistentCell) {
87  // This track is probably not a duplicate, so keep & and store its HT cell location (which equals the HT cell corresponding to the fitted track).
88  tracksFiltered.push_back(&trk);
89  // Memorize HT cell location corresponding to this track (identical for HT track & fitted track).
90  if (!memorizeAllHTcells) {
91  pair<unsigned int, unsigned int> htCell = trk.cellLocationHT();
92  htCellUsed.insert(htCell);
93  if (trk.l1track3D()->mergedHTcell()) {
94  // If this is a merged cell, block the other elements too, in case a track found by the HT in an unmerged cell
95  // has a fitted cell there.
96  pair<unsigned int, unsigned int> htCell10(htCell.first + 1, htCell.second);
97  pair<unsigned int, unsigned int> htCell01(htCell.first, htCell.second + 1);
98  pair<unsigned int, unsigned int> htCell11(htCell.first + 1, htCell.second + 1);
99  htCellUsed.insert(htCell10);
100  htCellUsed.insert(htCell01);
101  htCellUsed.insert(htCell11);
102  }
103  }
104 
105  if (debug && tp != nullptr) {
106  PrintL1trk() << "FIRST PASS: m=" << trk.cellLocationHT().first << "/" << trk.cellLocationFit().first
107  << " c=" << trk.cellLocationHT().second << "/" << trk.cellLocationFit().second
108  << " Delta(m,c)=(" << int(trk.cellLocationHT().first) - int(trk.cellLocationFit().first)
109  << "," << int(trk.cellLocationHT().second) - int(trk.cellLocationFit().second)
110  << ") pure=" << trk.purity() << " merged=" << trk.l1track3D()->mergedHTcell()
111  << " #layers=" << trk.l1track3D()->numLayers() << " tp=" << tp->index() << " dupCell=("
112  << tpFound[tp->index()].first << "," << tpFound[tp->index()].second
113  << ") dup=" << tpFoundAtPass[tp->index()];
114  // If the following two variables are non-zero in printout, then track has already been found,
115  // so we have mistakenly kept a duplicate.
116  if (tpFound.find(tp->index()) != tpFound.end())
117  tpFound[tp->index()] = trk.cellLocationFit();
118  tpFoundAtPass[tp->index()] = 1;
119  }
120 
121  } else {
122  if (limitDiff) {
123  const unsigned int maxDiff = 1;
124  if (abs(int(trk.cellLocationHT().first) - int(trk.cellLocationFit().first)) <= int(maxDiff) &&
125  abs(int(trk.cellLocationHT().second) - int(trk.cellLocationFit().second)) <= int(maxDiff))
126  tracksRejected.push_back(&trk);
127  } else {
128  tracksRejected.push_back(&trk);
129  }
130 
131  if (debug && tp != nullptr) {
132  PrintL1trk() << "FIRST REJECT: m=" << trk.cellLocationHT().first << "/" << trk.cellLocationFit().first
133  << " c=" << trk.cellLocationHT().second << "/" << trk.cellLocationFit().second
134  << " Delta(m,c)=(" << int(trk.cellLocationHT().first) - int(trk.cellLocationFit().first)
135  << "," << int(trk.cellLocationHT().second) - int(trk.cellLocationFit().second)
136  << ") pure=" << trk.purity() << " merged=" << trk.l1track3D()->mergedHTcell()
137  << " #layers=" << trk.l1track3D()->numLayers() << " tp=" << tp->index() << " dupCell=("
138  << tpFound[tp->index()].first << "," << tpFound[tp->index()].second
139  << ") dup=" << tpFoundAtPass[tp->index()];
140  }
141  }
142  // Memorize HT cell location corresponding to this track, even if it was not accepted by first pass..
143  if (memorizeAllHTcells) {
144  pair<unsigned int, unsigned int> htCell =
145  trk.cellLocationFit(); // Intentionally used fit instead of HT here.
146  htCellUsed.insert(htCell);
147  if (trk.l1track3D()->mergedHTcell()) {
148  // If this is a merged cell, block the other elements too, in case a track found by the HT in an unmerged cell
149  // has a fitted cell there.
150  // N.B. NO GOOD REASON WHY "-1" IS NOT DONE HERE TOO. MIGHT REDUCE DUPLICATE RATE?
151  pair<unsigned int, unsigned int> htCell10(htCell.first + 1, htCell.second);
152  pair<unsigned int, unsigned int> htCell01(htCell.first, htCell.second + 1);
153  pair<unsigned int, unsigned int> htCell11(htCell.first + 1, htCell.second + 1);
154  htCellUsed.insert(htCell10);
155  htCellUsed.insert(htCell01);
156  htCellUsed.insert(htCell11);
157  }
158  }
159  }
160  }
161  }
162 
163  if (doRecoveryStep) {
164  // Making a second pass through the rejected tracks, checking if any should be rescued.
165  for (const L1fittedTrack* trk : tracksRejected) {
166  // Get location in HT array corresponding to fitted track helix parameters.
167  pair<unsigned int, unsigned int> htCell = trk->cellLocationFit();
168  // If this HT cell was not already memorized, rescue this track, since it is probably not a duplicate,
169  // but just a track whose fitted helix parameters are a bit wierd for some reason.
170  if (htCellUsed.count(htCell) == 0) {
171  tracksFiltered.push_back(trk); // Rescue track.
172  // Optionally store cell location to avoid rescuing other tracks at the same location, which may be duplicates of this track.
173  bool outsideCheck = (goOutsideArray || trk->pt() > settings_->houghMinPt());
174  if (reduceDups && outsideCheck)
175  htCellUsed.insert(htCell);
176 
177  // For debugging.
178  [[clang::suppress]] const TP* tp = trk->matchedTP();
179 
180  if (debug && tp != nullptr) {
181  PrintL1trk() << "SECOND PASS: m=" << trk->cellLocationHT().first << "/" << trk->cellLocationFit().first
182  << " c=" << trk->cellLocationHT().second << "/" << trk->cellLocationFit().second
183  << " Delta(m,c)=(" << int(trk->cellLocationHT().first) - int(trk->cellLocationFit().first)
184  << "," << int(trk->cellLocationHT().second) - int(trk->cellLocationFit().second)
185  << ") pure=" << trk->purity() << " merged=" << trk->l1track3D()->mergedHTcell()
186  << " #layers=" << trk->l1track3D()->numLayers() << " tp=" << tp->index() << " dupCell=("
187  << tpFound[tp->index()].first << "," << tpFound[tp->index()].second
188  << ") dup=" << tpFoundAtPass[tp->index()];
189  if (tpFound.find(tp->index()) != tpFound.end())
190  tpFound[tp->index()] = htCell;
191  tpFoundAtPass[tp->index()] = 2;
192  }
193  }
194  }
195  }
196 
197  // Debug printout to identify duplicate tracks that survived.
198  if (debug)
199  this->printDuplicateTracks(tracksFiltered);
200 
201  return tracksFiltered;
202  }
203 
204  //=== Duplicate removal algorithm designed to run after the track helix fit, which eliminates duplicates
205  //=== simply by requiring that no two tracks should have fitted (q/Pt, phi0) that correspond to the same HT
206  //=== cell. If they do, then only the first to arrive is kept.
207  //=== N.B. This code runs on tracks in a single sector. It could be extended to run on tracks in entire
208  //=== tracker by adding the track's sector number to memory "htCellUsed" below.
209 
210  list<const L1fittedTrack*> DupFitTrkKiller::filterAlg2(const list<L1fittedTrack>& tracks) const {
211  // Hard-wired options to play with.
212  const bool debug = false;
213 
214  if (debug && not tracks.empty())
215  PrintL1trk() << "START " << tracks.size();
216 
217  list<const L1fittedTrack*> tracksFiltered;
218  set<pair<unsigned int, unsigned int>> htCellUsed;
219 
220  for (const L1fittedTrack& trk : tracks) {
221  // Get location in HT array corresponding to fitted track helix parameters.
222  pair<unsigned int, unsigned int> htCell = trk.cellLocationFit();
223  // If this HT cell was not already memorized, rescue this track, since it is probably not a duplicate,
224  // but just a track whose fitted helix parameters are a bit wierd for some reason.
225  if (htCellUsed.count(htCell) == 0) {
226  tracksFiltered.push_back(&trk); // Rescue track.
227  // Store cell location to avoid rescuing other tracks at the same location, which may be duplicates of this track.
228  htCellUsed.insert(htCell);
229  if (debug) {
230  const TP* tp = trk.matchedTP();
231  int tpIndex = (tp != nullptr) ? tp->index() : -999;
232  PrintL1trk() << "ALG51: m=" << trk.cellLocationHT().first << "/" << trk.cellLocationFit().first
233  << " c=" << trk.cellLocationHT().second << "/" << trk.cellLocationFit().second
234  << " tp=" << tpIndex << " pure=" << trk.purity();
235  }
236  }
237  }
238 
239  // Debug printout to identify duplicate tracks that survived.
240  if (debug)
241  this->printDuplicateTracks(tracksFiltered);
242 
243  return tracksFiltered;
244  }
245 
246  // Debug printout of which tracks are duplicates.
247  void DupFitTrkKiller::printDuplicateTracks(const list<const L1fittedTrack*>& tracks) const {
248  map<const TP*, list<const L1fittedTrack*>> tpMap;
249  for (const L1fittedTrack* trk : tracks) {
250  const TP* tp = trk->matchedTP();
251  if (tp != nullptr) {
252  tpMap[tp].push_back(trk);
253  }
254  }
255  for (const auto& p : tpMap) {
256  const TP* tp = p.first;
257  const list<const L1fittedTrack*> vecTrk = p.second;
258  if (vecTrk.size() > 1) {
259  for (const L1fittedTrack* trk : vecTrk) {
260  PrintL1trk() << " MESS UP : m=" << trk->cellLocationHT().first << "/" << trk->cellLocationFit().first
261  << " c=" << trk->cellLocationHT().second << "/" << trk->cellLocationFit().second
262  << " tp=" << tp->index() << " tp_pt=" << tp->pt() << " fit_pt=" << trk->pt()
263  << " pure=" << trk->purity();
264  PrintL1trk() << " stubs = ";
265  for (const Stub* s : trk->stubs())
266  PrintL1trk() << s->index() << " ";
267  PrintL1trk();
268  }
269  }
270  }
271  if (not tracks.empty())
272  PrintL1trk() << "FOUND " << tracks.size();
273  }
274 
275 } // namespace tmtt
Trktree trk
Definition: Trktree.cc:2
Definition: TP.h:23
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
#define debug
Definition: HDRShower.cc:19
=== This is the base class for the linearised chi-squared track fit algorithms.
Definition: Array2D.h:16
float maxDiff(float one, float two, float three, float four)
double houghMinPt() const
Definition: Settings.h:135
const Settings * settings_
std::list< const L1fittedTrack * > filter(const std::list< L1fittedTrack > &vecTracks) const
std::list< const L1fittedTrack * > filterAlg1(const std::list< L1fittedTrack > &tracks) const
std::list< const L1fittedTrack * > filterAlg2(const std::list< L1fittedTrack > &tracks) const
void printDuplicateTracks(const std::list< const L1fittedTrack *> &tracks) const
double beamWindowZ() const
Definition: Settings.h:129