Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MvtxStandaloneTracking.C
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file MvtxStandaloneTracking.C
2 
5 #include <trackbase/TrkrDefUtil.h>
6 
8 #include <phool/PHIODataNode.h>
9 #include <phool/PHNodeIterator.h>
10 #include <phool/getClass.h>
11 
12 #include <TDecompSVD.h>
13 #include <TMath.h>
14 
15 #include <iostream>
16 #include <utility>
17 #include <stdio.h>
18 #include <map>
19 
21  : window_x_(10)
22  , window_z_(10)
23  , ghostrejection_(false)
24  , verbosity_(0)
25 {
26 
27 }
28 
30 {
31 }
32 
33 void
34 MvtxStandaloneTracking::RunTracking(PHCompositeNode* topNode, MvtxTrackList &trklst, std::vector<int> &lyrs)
35 {
36  // check for appropriate layers
37  if ( lyrs.size() < 3 || lyrs.size() > 4 )
38  {
39  std::cout << PHWHERE << "ERROR: Inappropriate number of input layers - " << lyrs.size() << std::endl;
40  return;
41  }
42 
43  trklst.clear();
44 
45  //------
46  //--- get cluster container
47  //------
48  clusters_ = findNode::getClass<TrkrClusterContainer>(topNode, "TrkrClusterContainer");
49  if (!clusters_)
50  {
51  std::cout << PHWHERE << "ERROR: Can't find node TrkrClusterContainer" << std::endl;
52  return;
53  }
54 
55 
56  //------
57  //--- associate clusters
58  //------
59  AssociateClusters(trklst, lyrs);
60 
61  if ( verbosity_ > 0 )
62  std::cout << PHWHERE << " Finished associating clusters. N candidates:" << trklst.size() << std::endl;
63  //------
64  //--- fit tracks
65  //------
66  for ( unsigned int itrk = 0; itrk < trklst.size(); itrk++)
67  {
68  TrackFitXY(trklst.at(itrk));
69  TrackFitZY(trklst.at(itrk));
70  } // itrk
71 
72  if ( verbosity_ > 1 )
73  PrintTrackCandidates(trklst);
74 
75 
76  //------
77  // --- choose best tracks
78  //------
79  if ( ghostrejection_ && trklst.size() > 1 )
80  RunGhostRejection(trklst);
81 
82  // --- done
83  return;
84 }
85 
86 void
88 {
89 
90  // --- utility class
91  TrkrDefUtil util;
92 
93 
94  // --- loop over all clusters in the first desired layer
96  clusters_->GetClusters(TrkrDefs::TRKRID::mvtx_id, lyrs.at(0));
97  for ( TrkrClusterContainer::ConstIterator iter0 = clusrange0.first;
98  iter0 != clusrange0.second;
99  ++iter0)
100  {
101 
102  // -- loop over all clusters in the second desired layer
104  clusters_->GetClusters(TrkrDefs::TRKRID::mvtx_id, lyrs.at(1));
105  for ( TrkrClusterContainer::ConstIterator iter1 = clusrange1.first;
106  iter1 != clusrange1.second;
107  ++iter1)
108  {
109 
110  // get clusters
111  TrkrCluster* clus0 = iter0->second;
112  TrkrCluster* clus1 = iter1->second;
113 
114  // calculate slope & interecept in xy plane
115  double mxy = CalcSlope(clus0->GetY(), clus0->GetX(), clus1->GetY(), clus1->GetX());
116  double bxy = CalcIntecept(clus0->GetY(), clus0->GetX(), mxy);
117 
118  // calculate slope & interecept in zy plane
119  double mzy = CalcSlope(clus0->GetY(), clus0->GetZ(), clus1->GetY(), clus1->GetZ());
120  double bzy = CalcIntecept(clus0->GetY(), clus0->GetZ(), mxy);
121 
122  // -- loop over all clusters in the third desired layer
124  clusters_->GetClusters(TrkrDefs::TRKRID::mvtx_id, lyrs.at(2));
125  for ( TrkrClusterContainer::ConstIterator iter2 = clusrange2.first;
126  iter2 != clusrange2.second;
127  ++iter2)
128  {
129 
130  // check that the projection is within our window
131  if ( fabs((iter2->second)->GetX() - CalcProjection((iter2->second)->GetY(), mxy, bxy)) < window_x_ &&
132  fabs((iter2->second)->GetZ() - CalcProjection((iter2->second)->GetY(), mzy, bzy)) < window_z_ )
133  {
134 
135  // make the candidate
136  MvtxTrack trk;
137  (trk.ClusterList).push_back(iter0->second);
138  (trk.ClusterList).push_back(iter1->second);
139  (trk.ClusterList).push_back(iter2->second);
140 
141  // if there's another layer, require it
142  if ( lyrs.size() > 3 )
143  {
145  clusters_->GetClusters(TrkrDefs::TRKRID::mvtx_id, lyrs.at(3));
146  for ( TrkrClusterContainer::ConstIterator iter3 = clusrange3.first;
147  iter3 != clusrange3.second;
148  ++iter3)
149  {
150 
151  // check that the projection is within our window
152  if ( fabs((iter3->second)->GetX() - CalcProjection((iter3->second)->GetY(), mxy, bxy)) < window_x_ &&
153  fabs((iter3->second)->GetZ() - CalcProjection((iter3->second)->GetY(), mzy, bzy)) < window_z_ )
154  {
155 
156  (trk.ClusterList).push_back(iter3->second);
157  trklst.push_back(trk);
158  }
159  }
160  }
161  // else we're done
162  else
163  {
164  trklst.push_back(trk);
165  }
166 
167  }
168  } // clusrange 2
169  } // clusrange 1
170  } // clusrange 0
171 
172 }
173 
174 
175 void
177 {
178  if ( verbosity_ > 0 )
179  std::cout << PHWHERE << " Running Ghost Rejection on "
180  << trklst.size() << " tracks" << std::endl;
181 
182  // --- First, make a map of all cluster keys & track index
183  std::multimap<TrkrDefs::cluskey, unsigned int> key_trk_map;
184 
185  for (unsigned int itrk = 0; itrk < trklst.size(); itrk++)
186  {
187  for (unsigned int iclus = 0; iclus < trklst.at(itrk).ClusterList.size(); iclus++)
188  {
189  TrkrDefs::cluskey ckey = trklst.at(itrk).ClusterList.at(iclus)->GetClusKey();
190  key_trk_map.insert(std::make_pair(ckey, itrk));
191  } // iclus
192  } // itrk
193 
194  // --- find clusters associated with more than one track and pick the best track
195  std::set<unsigned int> remove_set;
196  for ( auto iter = key_trk_map.begin(); iter != key_trk_map.end(); ++iter)
197  {
198  // get the upper bound for this key
199  auto upiter = key_trk_map.upper_bound(iter->first);
200 
201  // iterate over common clusters and get the best track
202  double chi2_best = 9999.;
203  unsigned int idx_best = 0;
204  int ntrk = 0;
205  for ( auto jter = iter; jter != upiter; ++jter)
206  {
207  ntrk++;
208  double chi2 = trklst.at(jter->second).chi2_xy + trklst.at(jter->second).chi2_zy;
209  if ( chi2 < chi2_best && chi2 > 0 )
210  {
211  chi2_best = chi2;
212  idx_best = jter->second;
213  }
214  }
215 
216  // FOR TESTING
217  if ( ntrk > 1 && verbosity_ > 1 )
218  {
219  std::cout << PHWHERE << " Tracks sharing cluster:" << ntrk << std::endl;
220  for ( auto jter = iter; jter != upiter; ++jter)
221  {
222  double chi2 = trklst.at(jter->second).chi2_xy + trklst.at(jter->second).chi2_zy;
223  std::cout << " "
224  << " trk idx: " << jter->second
225  << " chi2:" << chi2
226  << " m_xy:" << trklst.at(jter->second).m_xy;
227 
228  if ( jter->second == idx_best)
229  {
230  std::cout << " <--- BEST" << std::endl;
231  }
232  else
233  {
234  std::cout << std::endl;
235  }
236  }
237  }
238 
239  // remove all pairs that aren't the best
240  for ( auto jter = iter; jter != upiter; ++jter)
241  {
242  if ( jter->second != idx_best )
243  {
244  remove_set.insert(jter->second);
245  }
246  }
247  } // iter
248 
249 
250  // --- Now remove tracks from the track list
251  // reverse iterate so we don't have to keep track of indeces changed by removal
252  if ( verbosity_ > 0 )
253  {
254  std::cout << PHWHERE << " List of idx to remove:";
255  for ( auto it = remove_set.begin(); it != remove_set.end(); ++it)
256  {
257  std::cout << " " << *it;
258  }
259  std::cout << std::endl;
260  }
261 
262 
263  for ( auto rit = remove_set.rbegin(); rit != remove_set.rend(); ++rit)
264  trklst.erase(trklst.begin() + *rit);
265 
266  // --- done
267 
268  if ( verbosity_ > 1 )
269  {
270  std::cout << PHWHERE << " Remaining tracks:" << std::endl;
271  for ( unsigned int i = 0; i < trklst.size(); i++)
272  {
273  double chi2 = trklst.at(i).chi2_xy + trklst.at(i).chi2_zy;
274  std::cout << " chi2:" << chi2 << " m_xy:" << trklst.at(i).m_xy << std::endl;
275  }
276  }
277 
278  return;
279 }
280 
281 
282 TVectorD
283 MvtxStandaloneTracking::SolveGLS(TMatrixD &X, TVectorD &y, TMatrixD &L)
284 {
285  // Simple generalized linear least-squares fitter.
286  // Solve y(X) = beta'*X + error(L) for beta (vector of regression coefs.)
287  // L is the inverse covariance matrix for y.
288  // Least-squares solution involves solving X' L X beta = X' L y
289 
290  TMatrixD XT(X); XT.T();
291  TMatrixD A = XT * L * X;
292  TVectorD b = XT * L * y;
293 
294  // Now solve A*beta = b using SVD. Decompose A = U S V'.
295  TDecompSVD svd(A);
296  TMatrixD UT = svd.GetU(); UT.T();
297 
298  // Construct Moore-Penrose pseudoinverse of S
299  TVectorD s = svd.GetSig();
300  TMatrixD Sd(s.GetNrows(), s.GetNrows());
301  for (int i = 0; i < s.GetNrows(); i++)
302  Sd(i, i) = s(i) > 0 ? 1. / s(i) : 0.;
303 
304  TVectorD beta = svd.GetV() * Sd * UT * b;
305 
306  return beta;
307 }
308 
309 void
311 {
312  // Longitudinal/polar component
313  // Fit track using a straight line x(y') = x0 + c*y'.
314  // Assigns residuals, z-intercept, and polar angle.
315 
316  // m = # measurements; n = # parameters.
317  int m = (trk.ClusterList).size(), n = 2;
318 
319  TMatrixD X(m, n);
320  TMatrixD Cinv(m, m);
321  TVectorD y(m);
322  TVectorD x(m);
323 
324  for (int iclus = 0; iclus < m; iclus++)
325  {
326  TrkrCluster *clus = (trk.ClusterList).at(iclus);
327 
328  x(iclus) = clus->GetX();
329  y(iclus) = clus->GetY();
330 
331  X(iclus, 0) = 1;
332  X(iclus, 1) = y(iclus);
333 
334  Cinv(iclus, iclus) = 2.0 * sqrt(clus->GetSize(0, 0));
335  }
336 
337  TVectorD beta = SolveGLS(X, x, Cinv);
338  double x0 = beta(0), c = beta(1);
339 
340  trk.m_xy = c;
341  trk.b_xy = x0;
342 
343  double chi2 = 0;
344  for (int iclus = 0; iclus < m; iclus++)
345  {
346  TrkrCluster *clus = (trk.ClusterList).at(iclus);
347 
348  double cx = clus->GetX();
349  double cy = clus->GetY();
350 
351  double px = cy * c + x0;
352 
353  double dx = cx - px;
354  trk.dx.push_back(dx);
355 
356  chi2 += pow(dx, 2) / clus->GetError(0, 0);
357  }
358  chi2 /= double(m - 2);
359  trk.chi2_xy = chi2;
360 
361  return;
362 }
363 
364 void
366 {
367  // Longitudinal/polar component
368  // Fit track using a straight line z(y') = z0 + c*y'.
369  // Assigns residuals, z-intercept, and polar angle.
370 
371  // m = # measurements; n = # parameters.
372  int m = (trk.ClusterList).size(), n = 2;
373 
374  TMatrixD X(m, n);
375  TMatrixD Cinv(m, m);
376  TVectorD y(m);
377  TVectorD z(m);
378 
379  for (int iclus = 0; iclus < m; iclus++)
380  {
381  TrkrCluster *clus = (trk.ClusterList).at(iclus);
382 
383  z(iclus) = clus->GetZ();
384  y(iclus) = clus->GetY();
385 
386  X(iclus, 0) = 1;
387  X(iclus, 1) = y(iclus);
388 
389  Cinv(iclus, iclus) = 2.0 * sqrt(clus->GetSize(2, 2));
390  }
391 
392  TVectorD beta = SolveGLS(X, z, Cinv);
393  double z0 = beta(0), c = beta(1);
394 
395  trk.m_zy = c;
396  trk.b_zy = z0;
397 
398  double chi2 = 0;
399  for (int iclus = 0; iclus < m; iclus++)
400  {
401  TrkrCluster *clus = (trk.ClusterList).at(iclus);
402 
403  double cz = clus->GetZ();
404  double cy = clus->GetY();
405 
406  double pz = cy * c + z0;
407 
408  double dz = cz - pz;
409  trk.dz.push_back(dz);
410 
411  chi2 += pow(dz, 2) / clus->GetError(2, 2);
412  }
413  chi2 /= double(m - 2);
414  trk.chi2_zy = chi2;
415 
416  return;
417 }
418 
419 void
421 {
422  std::cout << "===================================================" << std::endl;
423  std::cout << "== " << PHWHERE << " Found " << trklst.size() << " Track Candidates" << std::endl;
424  std::cout << "===================================================" << std::endl;
425  for ( unsigned int i = 0; i < trklst.size(); i++)
426  {
427  std::cout << "== " << i << std::endl;
428  for ( unsigned int j = 0; j < trklst.at(i).ClusterList.size(); j++)
429  {
430  std::cout << " clus " << j
431  << " key:0x" << std::hex << trklst.at(i).ClusterList.at(j)->GetClusKey() << std::dec
432  << " (" << trklst.at(i).ClusterList.at(j)->GetX()
433  << ", " << trklst.at(i).ClusterList.at(j)->GetY()
434  << ", " << trklst.at(i).ClusterList.at(j)->GetZ()
435  << ")"
436  << " dx:" << trklst.at(i).dx.at(j)
437  << " dz:" << trklst.at(i).dz.at(j)
438  << std::endl;
439  }
440  std::cout << " xy"
441  << " m:" << trklst.at(i).m_xy
442  << " b:" << trklst.at(i).b_xy
443  << " chi2:" << trklst.at(i).chi2_xy
444  << std::endl;
445  std::cout << " zy"
446  << " m:" << trklst.at(i).m_zy
447  << " b:" << trklst.at(i).b_zy
448  << " chi2:" << trklst.at(i).chi2_zy
449  << std::endl;
450  } // i
451  std::cout << "===================================================" << std::endl;
452 }
453 
454 double
455 MvtxStandaloneTracking::CalcSlope(double x0, double y0, double x1, double y1)
456 {
457  return (y1 - y0) / (x1 - x0);
458 }
459 
460 double
461 MvtxStandaloneTracking::CalcIntecept(double x0, double y0, double m)
462 {
463  return y0 - x0 * m;
464 }
465 
466 double
468 {
469  return m * x + b;
470 }
471