Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHCASeeding.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHCASeeding.cc
1 
8 #include "PHCASeeding.h"
9 #include "ALICEKF.h"
11 #include "GPUTPCTrackParam.h"
12 
13 // sPHENIX includes
15 
16 #include <phool/PHTimer.h> // for PHTimer
17 #include <phool/getClass.h>
18 #include <phool/phool.h> // for PHWHERE
19 
20 // tpc distortion correction
22 
23 #include <phfield/PHFieldConfigv2.h>
24 
25 // trackbase_historic includes
27 #include <trackbase/TrkrCluster.h> // for TrkrCluster
29 #include <trackbase/TrkrDefs.h> // for getLayer, clu...
34 
35 //ROOT includes for debugging
36 #include <TFile.h>
37 #include <TNtuple.h>
38 
39 //BOOST for combi seeding
40 #include <boost/geometry.hpp>
41 #include <boost/geometry/geometries/box.hpp>
42 #include <boost/geometry/geometries/point.hpp>
43 #include <boost/geometry/index/rtree.hpp>
44 #include <boost/geometry/policies/compare.hpp>
45 
46 #include <Eigen/Core>
47 #include <Eigen/Dense>
48 
49 #include <algorithm>
50 #include <cmath>
51 #include <iostream>
52 #include <numeric>
53 #include <utility> // for pair, make_pair
54 #include <vector>
55 #include <algorithm> // for find
56 #include <unordered_set>
57 #include <memory>
58 
59 //#define _DEBUG_
60 
61 #if defined(_DEBUG_)
62 #define LogDebug(exp) if(Verbosity()>0) std::cout << "DEBUG: " << __FILE__ << ": " << __LINE__ << ": " << exp
63 #else
64 #define LogDebug(exp) (void)0
65 #endif
66 
67 #define LogError(exp) if(Verbosity()>0) std::cout << "ERROR: " << __FILE__ << ": " << __LINE__ << ": " << exp
68 #define LogWarning(exp) if(Verbosity()>0) std::cout << "WARNING: " << __FILE__ << ": " << __LINE__ << ": " << exp
69 
70 //#define _DEBUG_
71 
72 //end
73 
74 typedef bg::model::point<float, 3, bg::cs::cartesian> point;
75 typedef bg::model::box<point> box;
76 typedef std::pair<point, TrkrDefs::cluskey> pointKey;
77 typedef std::pair<std::array<float,3>,TrkrDefs::cluskey> coordKey;
78 typedef std::array<coordKey,2> keylink;
79 typedef std::vector<TrkrDefs::cluskey> keylist;
80 
81 // apparently there is no builtin STL hash function for a std::array
82 // so to use std::unordered_set (essentially a hash table), we have to make our own hasher
83 
84 namespace std
85 {
86  template<typename T,size_t N>
87  struct hash<std::array<T,N>>
88  {
89  typedef std::array<T,N> argument_type;
90  typedef size_t result_type;
91 
92  result_type operator()(const argument_type& a) const
93  {
94  hash<T> hasher;
95  result_type h = 0;
96  for(result_type i = 0; i < N; ++i)
97  {
98  h = h * 31 + hasher(a[i]);
99  }
100  return h;
101  }
102  };
103  template<typename A,typename B>
104  struct hash<pair<A,B>>
105  {
106  typedef pair<A,B> argument_type;
107  typedef size_t result_type;
108 
109  result_type operator()(const argument_type& a) const
110  {
111  hash<A> hashA;
112  hash<B> hashB;
113  return (hashA(a.first)*31+hashB(a.second));
114  }
115  };
116 }
117 
118 // anonymous namespace for local functions
119 namespace
120 {
121  // square
122  template<class T> inline constexpr T square( const T& x ) { return x*x; }
123 
125  inline double get_phi( const Acts::Vector3& position )
126  {
127  double phi = std::atan2( position.y(), position.x() );
128  if( phi < 0 ) phi += 2.*M_PI;
129  return phi;
130  }
131 
133  inline double get_eta( const Acts::Vector3& position )
134  {
135  const double norm = std::sqrt( square(position.x()) + square(position.y()) + square(position.z()) );
136  return std::log((norm+position.z())/(norm-position.z()))/2;
137  }
138 
140 
141 
142  coordKey fromPointKey(const pointKey& p)
143  { return std::make_pair(std::array<float,3>({p.first.get<0>(),p.first.get<1>(),p.first.get<2>()}),p.second); }
144 
145  std::vector<coordKey> fromPointKey(const std::vector<pointKey>& p)
146  {
147  std::vector<coordKey> output;
148  output.resize(p.size());
149  std::transform( p.begin(), p.end(), std::back_inserter( output ), []( const pointKey& point )
150  { return fromPointKey(point); } );
151  return output;
152  }
154 
155  double breaking_angle(double x1, double y1, double z1, double x2, double y2, double z2)
156  {
157  double l1 = sqrt(x1*x1+y1*y1+z1*z1);
158  double l2 = sqrt(x2*x2+y2*y2+z2*z2);
159  double sx = (x1/l1+x2/l2);
160  double sy = (y1/l1+y2/l2);
161  double sz = (z1/l1+z2/l2);
162  double dx = (x1/l1-x2/l2);
163  double dy = (y1/l1-y2/l2);
164  double dz = (z1/l1-z2/l2);
165  return 2*atan2(sqrt(dx*dx+dy*dy+dz*dz),sqrt(sx*sx+sy*sy+sz*sz));
166  }
167 
168 }
169 
170 //using namespace ROOT::Minuit2;
171 namespace bg = boost::geometry;
172 namespace bgi = boost::geometry::index;
173 
175  const std::string &name,
176  unsigned int start_layer,
177  unsigned int end_layer,
178  unsigned int min_nhits_per_cluster,
179  unsigned int min_clusters_per_track,
180  unsigned int nlayers_maps,
181  unsigned int nlayers_intt,
182  unsigned int nlayers_tpc,
183  float neighbor_phi_width,
184  float neighbor_eta_width,
185  float maxSinPhi,
186  float cosTheta_limit)
187  : PHTrackSeeding(name)
188  , _nlayers_maps(nlayers_maps)
189  , _nlayers_intt(nlayers_intt)
190  , _nlayers_tpc(nlayers_tpc)
191  , _start_layer(start_layer)
192  , _end_layer(end_layer)
193  , _min_nhits_per_cluster(min_nhits_per_cluster)
194  , _min_clusters_per_track(min_clusters_per_track)
195  , _neighbor_phi_width(neighbor_phi_width)
196  , _neighbor_eta_width(neighbor_eta_width)
197  , _max_sin_phi(maxSinPhi)
198  , _cosTheta_limit(cosTheta_limit)
199 {
200 }
201 
203 {
204  tGeometry = findNode::getClass<ActsGeometry>(topNode,"ActsGeometry");
205  if(!tGeometry)
206  {
207  std::cout << PHWHERE << "No acts tracking geometry, can't proceed" << std::endl;
209  }
210 
212 }
213 
215 {
216  // get global position from Acts transform
217  auto globalpos = tGeometry->getGlobalPosition(key, cluster);
218 
219  // check if TPC distortion correction are in place and apply
220  if( m_dcc ) { globalpos = m_distortionCorrection.get_corrected_position( globalpos, m_dcc ); }
221 
222  return globalpos;
223 }
224 
225 void PHCASeeding::QueryTree(const bgi::rtree<pointKey, bgi::quadratic<16>> &rtree, double phimin, double etamin, double lmin, double phimax, double etamax, double lmax, std::vector<pointKey> &returned_values) const
226 {
227  double phimin_2pi = phimin;
228  double phimax_2pi = phimax;
229  if (phimin < 0) phimin_2pi = 2*M_PI+phimin;
230  if (phimax > 2*M_PI) phimax_2pi = phimax-2*M_PI;
231  rtree.query(bgi::intersects(box(point(phimin_2pi, etamin, lmin), point(phimax_2pi, etamax, lmax))), std::back_inserter(returned_values));
232 }
233 
235 {
236  if(Verbosity()>1)
237  {
238  std::cout << "fill tree..." << std::endl;
239  }
240  t_fill->stop();
241  int n_dupli = 0;
242  int nlayer[60];
243 
244  PositionMap cachedPositions;
245 
246  for (int j = 0; j < 60; ++j) nlayer[j] = 0;
248  {
249  auto range = _cluster_map->getClusters(hitsetkey);
250  for( auto clusIter = range.first; clusIter != range.second; ++clusIter ){
251 
252  TrkrDefs::cluskey ckey = clusIter->first;
253  TrkrCluster *cluster = clusIter->second;
254  unsigned int layer = TrkrDefs::getLayer(ckey);
255  if (layer < _start_layer || layer >= _end_layer){
256  if(Verbosity()>0) std::cout << "layer: " << layer << std::endl;
257  continue;
258  }
259  if(_iteration_map != NULL && _n_iteration >0){
260  if( _iteration_map->getIteration(ckey) > 0)
261  continue; // skip hits used in a previous iteration
262  }
263 
264  // get global position, convert to Acts::Vector3 and store in map
265  const Acts::Vector3 globalpos_d = getGlobalPosition(ckey, cluster);
266 
267  if(Verbosity() > 3)
268  {
269  auto global_before = tGeometry->getGlobalPosition(ckey, cluster);
270  std::cout << "CaSeeder: Cluster: " << ckey << std::endl;
271  std::cout << " Global before: " << global_before[0] << " " << global_before[1] << " " << global_before[2] << std::endl;
272  std::cout << " Global after : " << globalpos_d[0] << " " << globalpos_d[1] << " " << globalpos_d[2] << std::endl;
273  }
274 
275  const Acts::Vector3 globalpos = { globalpos_d.x(), globalpos_d.y(), globalpos_d.z()};
276  cachedPositions.insert(std::make_pair(ckey, globalpos));
277 
278  const double clus_phi = get_phi( globalpos );
279  const double clus_eta = get_eta( globalpos );
280  const double clus_l = layer;
281 
282  if(Verbosity() > 0)
283  std::cout << "Found cluster " << ckey << " in layer " << layer << std::endl;
284 
285  std::vector<pointKey> testduplicate;
286  QueryTree(_rtree, clus_phi - 0.00001, clus_eta - 0.00001, layer - 0.5, clus_phi + 0.00001, clus_eta + 0.00001, layer + 0.5, testduplicate);
287  if (!testduplicate.empty())
288  {
289  ++n_dupli;
290  continue;
291  }
292  ++nlayer[layer];
293  t_fill->restart();
294  _rtree.insert(std::make_pair(point(clus_phi, globalpos_d.z(), clus_l), ckey));
295  t_fill->stop();
296  }
297  }
298  if(Verbosity()>1) for (int j = 0; j < 60; ++j) std::cout << "nhits in layer " << j << ": " << nlayer[j] << std::endl;
299  if(Verbosity()>0) std::cout << "fill time: " << t_fill->get_accumulated_time() / 1000. << " sec" << std::endl;
300  if(Verbosity()>0) std::cout << "number of duplicates : " << n_dupli << std::endl;
301  return cachedPositions;
302 }
303 
305 {
306  if(Verbosity() > 1)
307  {
308  std::cout << " Process... " << std::endl;
309  }
310 // TFile fpara("CA_para.root", "RECREATE");
311  if(_n_iteration>0){
312  if (!_iteration_map){
313  std::cerr << PHWHERE << "Cluster Iteration Map missing, aborting." << std::endl;
315  }
316  }
317 
318  t_seed->restart();
319 
320  _rtree.clear();
321  PositionMap globalClusPositions = FillTree();
322  t_seed->stop();
323  if(Verbosity()>0) std::cout << "Initial RTree fill time: " << t_seed->get_accumulated_time() / 1000 << " s" << std::endl;
324  t_seed->restart();
325  int numberofseeds = 0;
326  numberofseeds += FindSeedsWithMerger(globalClusPositions);
327  t_seed->stop();
328  if(Verbosity()>0) std::cout << "number of seeds " << numberofseeds << std::endl;
329  if(Verbosity()>0) std::cout << "Kalman filtering time: " << t_seed->get_accumulated_time() / 1000 << " s" << std::endl;
330 // fpara.cd();
331 // fpara.Close();
332 // if(Verbosity()>0) std::cout << "fpara OK\n";
334 }
335 
337 {
338  std::vector<pointKey> allClusters;
339  std::vector<std::unordered_set<keylink>> belowLinks;
340  std::vector<std::unordered_set<keylink>> aboveLinks;
341  belowLinks.resize(_nlayers_tpc);
342  aboveLinks.resize(_nlayers_tpc);
344  0, // phi
345  -200, // eta
346  _start_layer-0.5, // layer
347  2*M_PI, // phi
348  200, // eta
349  _end_layer+0.5, // layer
350  allClusters);
351  t_seed->stop();
352  if(Verbosity()>0) std::cout << "allClusters search time: " << t_seed->get_accumulated_time() / 1000 << " s" << std::endl;
353  LogDebug(" number of clusters: " << allClusters.size() << std::endl);
354  t_seed->restart();
355 
356  std::pair<std::vector<std::unordered_set<keylink>>,std::vector<std::unordered_set<keylink>>> links = CreateLinks(fromPointKey(allClusters), globalPositions);
357  std::vector<std::vector<keylink>> biLinks = FindBiLinks(links.first,links.second);
358  std::vector<keylist> trackSeedKeyLists = FollowBiLinks(biLinks,globalPositions);
359  std::vector<TrackSeed_v1> seeds = RemoveBadClusters(trackSeedKeyLists, globalPositions);
360 
361  publishSeeds(seeds);
362  return seeds.size();
363 }
364 
365 std::pair<std::vector<std::unordered_set<keylink>>,std::vector<std::unordered_set<keylink>>> PHCASeeding::CreateLinks(const std::vector<coordKey>& clusters, const PositionMap& globalPositions) const
366 {
367  size_t nclusters = 0;
368 
369  double cluster_find_time = 0;
370  double rtree_query_time = 0;
371  double transform_time = 0;
372  double compute_best_angle_time = 0;
373  double set_insert_time = 0;
374 
375  std::vector<std::unordered_set<keylink>> belowLinks;
376  std::vector<std::unordered_set<keylink>> aboveLinks;
377  belowLinks.resize(_nlayers_tpc);
378  aboveLinks.resize(_nlayers_tpc);
379 
380  for (auto StartCluster = clusters.begin(); StartCluster != clusters.end(); ++StartCluster)
381  {
382  nclusters++;
383  // get clusters near this one in adjacent layers
384  double StartPhi = StartCluster->first[0];
385  //double StartEta = StartCluster->first[1];
386  unsigned int StartLayer = StartCluster->first[2];
387  if(StartLayer < _start_layer) continue;
388  if(StartLayer > _end_layer) continue;
389  const auto& globalpos = globalPositions.at(StartCluster->second);
390  double StartX = globalpos(0);
391  double StartY = globalpos(1);
392  double StartZ = globalpos(2);
393  t_seed->stop();
394  cluster_find_time += t_seed->elapsed();
395  t_seed->restart();
396  LogDebug(" starting cluster:" << std::endl);
397  LogDebug(" z: " << StartZ << std::endl);
398  LogDebug(" phi: " << StartPhi << std::endl);
399  LogDebug(" layer: " << StartLayer << std::endl);
400 
401  std::vector<pointKey> ClustersAbove;
402  std::vector<pointKey> ClustersBelow;
404  StartPhi-_neighbor_phi_width,
405  StartZ-_neighbor_eta_width,
406  (double) StartLayer - 1.5,
407  StartPhi+_neighbor_phi_width,
408  StartZ+_neighbor_eta_width,
409  (double) StartLayer - 0.5,
410  ClustersBelow);
412  StartPhi-_neighbor_phi_width,
413  StartZ-_neighbor_eta_width,
414  (double) StartLayer + 0.5,
415  StartPhi+_neighbor_phi_width,
416  StartZ+_neighbor_eta_width,
417  (double) StartLayer + 1.5,
418  ClustersAbove);
419  t_seed->stop();
420  rtree_query_time += t_seed->elapsed();
421  t_seed->restart();
422  LogDebug(" entries in below layer: " << ClustersBelow.size() << std::endl);
423  LogDebug(" entries in above layer: " << ClustersAbove.size() << std::endl);
424  std::vector<std::array<double,3>> delta_below;
425  std::vector<std::array<double,3>> delta_above;
426  delta_below.clear();
427  delta_above.clear();
428  delta_below.resize(ClustersBelow.size());
429  delta_above.resize(ClustersAbove.size());
430  // calculate (delta_eta, delta_phi) vector for each neighboring cluster
431 
432  std::transform(ClustersBelow.begin(),ClustersBelow.end(),delta_below.begin(),
433  [&](pointKey BelowCandidate){
434  const auto& belowpos = globalPositions.at(BelowCandidate.second);
435  return std::array<double,3>{belowpos(0)-StartX,
436  belowpos(1)-StartY,
437  belowpos(2)-StartZ};});
438 
439  std::transform(ClustersAbove.begin(),ClustersAbove.end(),delta_above.begin(),
440  [&](pointKey AboveCandidate){
441  const auto& abovepos = globalPositions.at(AboveCandidate.second);
442  return std::array<double,3>{abovepos(0)-StartX,
443  abovepos(1)-StartY,
444  abovepos(2)-StartZ};});
445  t_seed->stop();
446  transform_time += t_seed->elapsed();
447  t_seed->restart();
448 
449  // find the three clusters closest to a straight line
450  // (by maximizing the cos of the angle between the (delta_eta,delta_phi) vectors)
451  double maxCosPlaneAngle = -0.95;
452  //double minSumLengths = 1e9;
453  std::vector<coordKey> bestBelowClusters;
454  std::vector<coordKey> bestAboveClusters;
455  for(size_t iAbove = 0; iAbove<delta_above.size(); ++iAbove)
456  {
457  for(size_t iBelow = 0; iBelow<delta_below.size(); ++iBelow)
458  {
459 // double dotProduct = delta_below[iBelow][0]*delta_above[iAbove][0]+delta_below[iBelow][1]*delta_above[iAbove][1]+delta_below[iBelow][2]*delta_above[iAbove][2];
460 // double belowLength = sqrt(delta_below[iBelow][0]*delta_below[iBelow][0]+delta_below[iBelow][1]*delta_below[iBelow][1]+delta_below[iBelow][2]*delta_below[iBelow][2]);
461 // double aboveLength = sqrt(delta_above[iAbove][0]*delta_above[iAbove][0]+delta_above[iAbove][1]*delta_above[iAbove][1]+delta_above[iAbove][2]*delta_above[iAbove][2]);
462  double angle = breaking_angle(
463  delta_below[iBelow][0],
464  delta_below[iBelow][1],
465  delta_below[iBelow][2],
466  delta_above[iAbove][0],
467  delta_above[iAbove][1],
468  delta_above[iAbove][2]);
469  if(cos(angle) < maxCosPlaneAngle)
470  {
471  //maxCosPlaneAngle = cos(angle);
472  //minSumLengths = belowLength+aboveLength;
473  //bestBelowCluster = fromPointKey(ClustersBelow[iBelow]);
474  //bestAboveCluster = fromPointKey(ClustersAbove[iAbove]);
475  bestBelowClusters.push_back(fromPointKey(ClustersBelow[iBelow]));
476  bestAboveClusters.push_back(fromPointKey(ClustersAbove[iAbove]));
477  }
478  }
479  }
480  /*
481  if(mode == skip_layers::on)
482  {
483  if(maxCosPlaneAngle > _cosTheta_limit)
484  {
485  // if no triplet is sufficiently linear, then it's likely that there's a missing cluster
486  // repeat search but skip one layer below
487  std::vector<pointKey> clustersTwoLayersBelow;
488  QueryTree(_rtree,
489  StartPhi-_neighbor_phi_width,
490  StartEta-_neighbor_eta_width,
491  (double) StartLayer - 2.5,
492  StartPhi+_neighbor_phi_width,
493  StartEta+_neighbor_eta_width,
494  (double) StartLayer - 1.5,
495  clustersTwoLayersBelow);
496  std::vector<std::array<double,3>> delta_2below;
497  delta_2below.clear();
498  delta_2below.resize(clustersTwoLayersBelow.size());
499  std::transform(clustersTwoLayersBelow.begin(),clustersTwoLayersBelow.end(),delta_2below.begin(),
500  [&](pointKey BelowCandidate){
501  const auto& belowpos = globalPositions.at(BelowCandidate.second);
502  return std::array<double,3>{(belowpos(0))-StartX,
503  (belowpos(1))-StartY,
504  (belowpos(2))-StartZ};});
505  for(size_t iAbove = 0; iAbove<delta_above.size(); ++iAbove)
506  {
507  for(size_t iBelow = 0; iBelow<delta_2below.size(); ++iBelow)
508  {
509  double dotProduct = delta_2below[iBelow][0]*delta_above[iAbove][0]+delta_2below[iBelow][1]*delta_above[iAbove][1]+delta_2below[iBelow][2]*delta_above[iAbove][2];
510  double belowSqLength = sqrt(delta_2below[iBelow][0]*delta_2below[iBelow][0]+delta_2below[iBelow][1]*delta_2below[iBelow][1]+delta_2below[iBelow][2]*delta_2below[iBelow][2]);
511  double aboveSqLength = sqrt(delta_above[iAbove][0]*delta_above[iAbove][0]+delta_above[iAbove][1]*delta_above[iAbove][1]+delta_above[iAbove][2]*delta_above[iAbove][2]);
512  double cosPlaneAngle = dotProduct / (belowSqLength*aboveSqLength);
513  if(cosPlaneAngle < maxCosPlaneAngle)
514  {
515  maxCosPlaneAngle = cosPlaneAngle;
516  bestBelowCluster = fromPointKey(clustersTwoLayersBelow[iBelow]);
517  bestAboveCluster = fromPointKey(ClustersAbove[iAbove]);
518  }
519  }
520  }
521  // if no triplet is STILL sufficiently linear, then do the same thing, but skip one layer above
522  if(maxCosPlaneAngle > _cosTheta_limit)
523  {
524  std::vector<pointKey> clustersTwoLayersAbove;
525  QueryTree(_rtree,
526  StartPhi-_neighbor_phi_width,
527  StartEta-_neighbor_eta_width,
528  (double) StartLayer + 1.5,
529  StartPhi+_neighbor_phi_width,
530  StartEta+_neighbor_eta_width,
531  (double) StartLayer + 2.5,
532  clustersTwoLayersAbove);
533  std::vector<std::array<double,3>> delta_2above;
534  delta_2above.clear();
535  delta_2above.resize(clustersTwoLayersAbove.size());
536  std::transform(clustersTwoLayersAbove.begin(),clustersTwoLayersAbove.end(),delta_2above.begin(),
537  [&](pointKey AboveCandidate){
538  const auto& abovepos = globalPositions.at(AboveCandidate.second);
539  return std::array<double,3>{(abovepos(0))-StartX,
540  (abovepos(1))-StartY,
541  (abovepos(2))-StartZ};});
542  for(size_t iAbove = 0; iAbove<delta_2above.size(); ++iAbove)
543  {
544  for(size_t iBelow = 0; iBelow<delta_below.size(); ++iBelow)
545  {
546  double dotProduct = delta_below[iBelow][0]*delta_2above[iAbove][0]+delta_below[iBelow][1]*delta_2above[iAbove][1]+delta_below[iBelow][2]*delta_2above[iAbove][2];
547  double belowSqLength = sqrt(delta_below[iBelow][0]*delta_below[iBelow][0]+delta_below[iBelow][1]*delta_below[iBelow][1]+delta_below[iBelow][2]*delta_below[iBelow][2]);
548  double aboveSqLength = sqrt(delta_2above[iAbove][0]*delta_2above[iAbove][0]+delta_2above[iAbove][1]*delta_2above[iAbove][1]+delta_2above[iAbove][2]*delta_2above[iAbove][2]);
549  double cosPlaneAngle = dotProduct / (belowSqLength*aboveSqLength);
550  if(cosPlaneAngle < maxCosPlaneAngle)
551  {
552  maxCosPlaneAngle = cosPlaneAngle;
553  bestBelowCluster = fromPointKey(ClustersBelow[iBelow]);
554  bestAboveCluster = fromPointKey(clustersTwoLayersAbove[iAbove]);
555  }
556  }
557  }
558  }
559  }
560  }
561  */
562  t_seed->stop();
563  compute_best_angle_time += t_seed->elapsed();
564  t_seed->restart();
565  int layer_index = StartLayer - (_nlayers_intt + _nlayers_maps);
566  //if(bestBelowCluster.second != 0) belowLinks[layer_index].insert(keylink{{*StartCluster,bestBelowCluster}});
567  //if(bestAboveCluster.second != 0) aboveLinks[layer_index].insert(keylink{{*StartCluster,bestAboveCluster}});
568  for(auto cluster : bestBelowClusters) belowLinks[layer_index].insert(keylink{{*StartCluster,cluster}});
569  for(auto cluster : bestAboveClusters) aboveLinks[layer_index].insert(keylink{{*StartCluster,cluster}});
570  t_seed->stop();
571  set_insert_time += t_seed->elapsed();
572  t_seed->restart();
573  LogDebug(" max collinearity: " << maxCosPlaneAngle << std::endl);
574  }
575  t_seed->stop();
576  if(Verbosity()>0)
577  {
578  std::cout << "triplet forming time: " << t_seed->get_accumulated_time() / 1000 << " s" << std::endl;
579  std::cout << "starting cluster setup: " << cluster_find_time / 1000 << " s" << std::endl;
580  std::cout << "RTree query: " << rtree_query_time /1000 << " s" << std::endl;
581  std::cout << "Transform: " << transform_time /1000 << " s" << std::endl;
582  std::cout << "Compute best triplet: " << compute_best_angle_time /1000 << " s" << std::endl;
583  std::cout << "Set insert: " << set_insert_time /1000 << " s" << std::endl;
584  }
585  t_seed->restart();
586 
587  return std::make_pair(belowLinks,aboveLinks);
588 }
589 
590 std::vector<std::vector<keylink>> PHCASeeding::FindBiLinks(const std::vector<std::unordered_set<keylink>>& belowLinks, const std::vector<std::unordered_set<keylink>>& aboveLinks) const
591 {
592  // remove all triplets for which there isn't a mutual association between two clusters
593  std::vector<std::vector<keylink>> bidirectionalLinks;
594  bidirectionalLinks.resize(_nlayers_tpc);
595  for(int layer = _nlayers_tpc-1; layer > 0; --layer)
596  {
597  for(auto belowLink = belowLinks[layer].begin(); belowLink != belowLinks[layer].end(); ++belowLink)
598  {
599  if((*belowLink)[1].second==0) continue;
600  unsigned int end_layer_index = TrkrDefs::getLayer((*belowLink)[1].second) - (_nlayers_intt + _nlayers_maps);
601  keylink reversed = {(*belowLink)[1],(*belowLink)[0]};
602  auto sameAboveLinkExists = aboveLinks[end_layer_index].find(reversed);
603  if(sameAboveLinkExists != aboveLinks[end_layer_index].end())
604  {
605  bidirectionalLinks[layer].push_back((*belowLink));
606  }
607  }
608  }
609  t_seed->stop();
610  if(Verbosity()>0) std::cout << "bidirectional link forming time: " << t_seed->get_accumulated_time() / 1000 << " s" << std::endl;
611  t_seed->restart();
612 
613  return bidirectionalLinks;
614 }
615 
617 {
618  // Menger curvature = 1/R for circumcircle of triangle formed by most recent three clusters
619  // We use here 1/R = 2*sin(breaking angle)/(hypotenuse of triangle)
620  auto& a_pos = globalPositions.at(a);
621  auto& b_pos = globalPositions.at(b);
622  auto& c_pos = globalPositions.at(c);
623  double hypot_length = sqrt(square<double>(c_pos.x()-a_pos.x())+square<double>(c_pos.y()-a_pos.y())+square<double>(c_pos.z()-a_pos.z()));
624  double break_angle = breaking_angle(
625  a_pos.x()-b_pos.x(),
626  a_pos.y()-b_pos.y(),
627  a_pos.z()-b_pos.z(),
628  c_pos.x()-b_pos.x(),
629  c_pos.y()-b_pos.y(),
630  c_pos.z()-b_pos.z());
631  return 2*sin(break_angle)/hypot_length;
632 }
633 
634 std::vector<keylist> PHCASeeding::FollowBiLinks(const std::vector<std::vector<keylink>>& bidirectionalLinks, const PositionMap& globalPositions) const
635 {
636  // follow bidirectional links to form lists of cluster keys
637  // (to be fitted for track seed parameters)
638  std::vector<keylist> trackSeedPairs;
639  // get starting cluster keys, create a keylist for each
640  // (only check last element of each pair because we start from the outer layers and go inward)
641  for(unsigned int layer = 0; layer < _nlayers_tpc-1; ++layer)
642  {
643  for(auto startCand = bidirectionalLinks[layer].begin(); startCand != bidirectionalLinks[layer].end(); ++startCand)
644  {
645  bool has_above_link = false;
646  unsigned int imax = 1;
647  if(layer==_nlayers_tpc-2) imax = 1;
648  for(unsigned int i=1;i<=imax;i++)
649  {
650  has_above_link = has_above_link || std::any_of(bidirectionalLinks[layer+i].begin(),bidirectionalLinks[layer+i].end(),[&](keylink k){return (*startCand)[0]==k[1];});
651  }
652 // for(std::vector<keylink>::iterator testlink = bidirectionalLinks[layer+1].begin(); !has_above_link && (testlink != bidirectionalLinks[layer+1].end()); ++testlink)
653 // {
654 // if((*startCand) == (*testlink)) continue;
655 // if((*startCand)[0] == (*testlink)[1]) has_above_link = true;
656 // }
657  if(!has_above_link)
658  {
659  trackSeedPairs.push_back({(*startCand)[0].second,(*startCand)[1].second});
660  }
661  }
662  }
663 
664  // form all possible starting 3-cluster tracks (we need that to calculate curvature)
665  std::vector<keylist> trackSeedKeyLists;
666  for(auto& trackKeyChain : trackSeedPairs)
667  {
668  TrkrDefs::cluskey trackHead = trackKeyChain.back();
669  unsigned int trackHead_layer = TrkrDefs::getLayer(trackHead) - (_nlayers_intt+_nlayers_maps);
670  for(auto& testlink : bidirectionalLinks[trackHead_layer])
671  {
672  if(testlink[0].second==trackHead)
673  {
674  keylist trackSeedTriplet;
675  trackSeedTriplet.push_back(trackKeyChain[0]);
676  trackSeedTriplet.push_back(trackKeyChain[1]);
677  trackSeedTriplet.push_back(testlink[1].second);
678  trackSeedKeyLists.push_back(trackSeedTriplet);
679  }
680  }
681  }
682 
683  t_seed->stop();
684  if(Verbosity()>0) std::cout << "starting cluster finding time: " << t_seed->get_accumulated_time() / 1000 << " s" << std::endl;
685  t_seed->restart();
686  // assemble track cluster chains from starting cluster keys (ordered from outside in)
687 
688  // std::cout << "STARTING SEED ASSEMBLY" << std::endl;
689 
690 // std::vector<keylist> trackSeedKeyLists;
691  std::vector<keylist> tempSeedKeyLists = trackSeedKeyLists;
692  trackSeedKeyLists.clear();
693 
694  while(tempSeedKeyLists.size()>0)
695  {
696  if(Verbosity()>0) std::cout << "temp size: " << tempSeedKeyLists.size() << std::endl;
697  if(Verbosity()>0) std::cout << "final size: " << trackSeedKeyLists.size() << std::endl;
698  std::vector<keylist> newtempSeedKeyLists;
699  for(auto& seed : tempSeedKeyLists)
700  {
701  TrkrDefs::cluskey trackHead = seed.back();
702  unsigned int trackHead_layer = TrkrDefs::getLayer(trackHead)-(_nlayers_intt+_nlayers_maps);
703  //bool no_next_link = true;
704  for(auto& link : bidirectionalLinks[trackHead_layer])
705  {
706  if(link[0].second != trackHead) continue;
707  auto& head_pos = globalPositions.at(trackHead);
708  auto& prev_pos = globalPositions.at(seed.rbegin()[1]);
709  float x1 = head_pos.x();
710  float y1 = head_pos.y();
711  float z1 = head_pos.z();
712  float x2 = prev_pos.x();
713  float y2 = prev_pos.y();
714  float z2 = prev_pos.z();
715  float dr_12 = sqrt(x1*x1+y1*y1)-sqrt(x2*x2+y2*y2);
716  TrkrDefs::cluskey testCluster = link[1].second;
717  auto& test_pos = globalPositions.at(testCluster);
718  float xt = test_pos.x();
719  float yt = test_pos.y();
720  float zt = test_pos.z();
721  float new_dr = sqrt(xt*xt+yt*yt)-sqrt(x1*x1+y1*y1);
722  if(fabs( (z1-z2)/dr_12 - (zt-z1)/new_dr )>0.5) continue;
723  auto& third_pos = globalPositions.at(seed.rbegin()[2]);
724  float x3 = third_pos.x();
725  float y3 = third_pos.y();
726  float dr_23 = sqrt(x2*x2+y2*y2)-sqrt(x3*x3+y3*y3);
727  float phi1 = atan2(y1,x1);
728  float phi2 = atan2(y2,x2);
729  float phi3 = atan2(y3,x3);
730  float dphi12 = std::fmod(phi1-phi2,M_PI);
731  float dphi23 = std::fmod(phi2-phi3,M_PI);
732  float d2phidr2 = dphi12/(dr_12*dr_12)-dphi23/(dr_23*dr_23);
733  float new_dphi = std::fmod(atan2(yt,xt)-atan2(y1,x1),M_PI);
734  float new_d2phidr2 = new_dphi/(new_dr*new_dr)-dphi12/(dr_12*dr_12);
735  if(seed.size()<6 && fabs(d2phidr2-new_d2phidr2)<.005)
736  {
737  // no_next_link = false;
738  keylist newseed = seed;
739  newseed.push_back(link[1].second);
740  newtempSeedKeyLists.push_back(newseed);
741  }
742  }
743  if(seed.size()>5)
744  {
745  trackSeedKeyLists.push_back(seed);
746  }
747  }
748  if(Verbosity()>0) std::cout << "new temp size: " << newtempSeedKeyLists.size() << std::endl;
749  tempSeedKeyLists = newtempSeedKeyLists;
750  }
751 
752 
753 // trackSeedKeyLists = tempSeedKeyLists;
754 /*
755  for(auto trackKeyChain = trackSeedKeyLists.begin(); trackKeyChain != trackSeedKeyLists.end(); ++trackKeyChain)
756  {
757  bool reached_end = false;
758  while(!reached_end)
759  {
760  TrkrDefs::cluskey trackHead = trackKeyChain->back();
761  TrkrDefs::cluskey secondToLast = trackKeyChain->rbegin()[1];
762  TrkrDefs::cluskey thirdToLast = trackKeyChain->rbegin()[2];
763  auto& head_pos = globalPositions.at(trackHead);
764  auto& sec_pos = globalPositions.at(secondToLast);
765  auto& third_pos = globalPositions.at(thirdToLast);
766  double dz_avg = ((head_pos.z()-sec_pos.z())+(sec_pos.z()-third_pos.z()))/2.;
767  double dx1 = head_pos.x()-sec_pos.x();
768  double dy1 = head_pos.y()-sec_pos.y();
769  double dx2 = sec_pos.x()-third_pos.x();
770  double dy2 = sec_pos.y()-third_pos.y();
771  double ddx = dx1-dx2;
772  double ddy = dy1-dy2;
773  double new_dx = dx1+ddx;
774  double new_dy = dy1+ddy;
775  double new_x = head_pos.x()+new_dx;
776  double new_y = head_pos.y()+new_dy;
777  double new_z = head_pos.z()+dz_avg;
778  std::cout << "(x,y,z) = (" << head_pos.x() << ", " << head_pos.y() << ", " << head_pos.z() << ")" << std::endl;
779  unsigned int trackHead_layer = TrkrDefs::getLayer(trackHead) - (_nlayers_intt + _nlayers_maps);
780  std::cout << "layer " << trackHead_layer << std::endl;
781  std::cout << "projected: (" << new_x << ", " << new_y << ", " << new_z << ")" << std::endl;
782  TrkrDefs::cluskey nextCluster;
783  double bestDist = 1e9;
784  bool no_next_link = true;
785  for(auto testlink = bidirectionalLinks[trackHead_layer].begin(); testlink != bidirectionalLinks[trackHead_layer].end(); ++testlink)
786  {
787  if((*testlink)[0].second==trackHead)
788  {
789  TrkrDefs::cluskey testCluster = (*testlink)[1].second;
790  auto& test_pos = globalPositions.at(testCluster);
791  std::cout << "test cluster: (" << test_pos.x() << ", " << test_pos.y() << ", " << test_pos.z() << ")" << std::endl;
792  double distToNew = sqrt(square<double>(test_pos.x()-new_x)+square<double>(test_pos.y()-new_y)+square<double>(test_pos.z()-new_z));
793  if(distToNew<bestDist)
794  {
795  std::cout << "current best" << std::endl;
796  nextCluster = testCluster;
797  bestDist = distToNew;
798  }
799  no_next_link = false;
800  }
801  }
802  if(!no_next_link) trackKeyChain->push_back(nextCluster);
803  if(no_next_link) reached_end = true;
804  }
805  }
806 */
807  t_seed->stop();
808  if(Verbosity()>0) std::cout << "keychain assembly time: " << t_seed->get_accumulated_time() / 1000 << " s" << std::endl;
809  t_seed->restart();
810  LogDebug(" track key chains assembled: " << trackSeedKeyLists.size() << std::endl);
811  LogDebug(" track key chain lengths: " << std::endl);
812  for(auto trackKeyChain = trackSeedKeyLists.begin(); trackKeyChain != trackSeedKeyLists.end(); ++trackKeyChain)
813  {
814  LogDebug(" " << trackKeyChain->size() << std::endl);
815  }
816  int jumpcount = 0;
817  LogDebug(" track key associations:" << std::endl);
818  for(size_t i=0;i<trackSeedKeyLists.size();++i)
819  {
820  LogDebug(" seed " << i << ":" << std::endl);
821 
822  double lasteta = -100;
823  double lastphi = -100;
824  for(size_t j=0;j<trackSeedKeyLists[i].size();++j)
825  {
826  const auto& globalpos = globalPositions.at(trackSeedKeyLists[i][j]);
827  const double clus_phi = get_phi( globalpos );
828  const double clus_eta = get_eta( globalpos );
829  const double etajump = clus_eta-lasteta;
830  const double phijump = clus_phi-lastphi;
831  #if defined(_DEBUG_)
832  unsigned int lay = TrkrDefs::getLayer(trackSeedKeyLists[i][j].second);
833  #endif
834  if((fabs(etajump)>0.1 && lasteta!=-100) || (fabs(phijump)>1 && lastphi!=-100))
835  {
836  LogDebug(" Eta or Phi jump too large! " << std::endl);
837  ++jumpcount;
838  }
839  LogDebug(" (eta,phi,layer) = (" << clus_eta << "," << clus_phi << "," << lay << ") " <<
840  " (x,y,z) = (" << globalpos(0) << "," << globalpos(1) << "," << globalpos(2) << ")" << std::endl);
841 
842  if(Verbosity() > 0)
843  {
844  unsigned int lay = TrkrDefs::getLayer(trackSeedKeyLists[i][j]);
845  std::cout << " eta, phi, layer = (" << clus_eta << "," << clus_phi << "," << lay << ") " <<
846  " (x,y,z) = (" << globalpos(0) << "," << globalpos(1) << "," << globalpos(2) << ")" << std::endl;
847  }
848  lasteta = clus_eta;
849  lastphi = clus_phi;
850  }
851  }
852  LogDebug(" Total large jumps: " << jumpcount << std::endl);
853  t_seed->stop();
854  if(Verbosity()>0) std::cout << "eta-phi sanity check time: " << t_seed->get_accumulated_time() / 1000 << " s" << std::endl;
855  t_seed->restart();
856  return trackSeedKeyLists;
857 }
858 
859 std::vector<TrackSeed_v1> PHCASeeding::RemoveBadClusters(const std::vector<keylist>& chains, const PositionMap& globalPositions) const
860 {
861  if(Verbosity()>0) std::cout << "removing bad clusters" << std::endl;
862  std::vector<TrackSeed_v1> clean_chains;
863 
864  for(const auto& chain : chains)
865  {
866  if(chain.size()<3) continue;
867  if(Verbosity()>0) std::cout << "chain size: " << chain.size() << std::endl;
868 
870  for( const auto& ckey:chain )
871  {
872  const auto &global = globalPositions.at(ckey);
873  xy_pts.emplace_back( global.x(), global.y() );
874  }
875 
876  // fit a circle through x,y coordinates
877  const auto [R, X0, Y0] = TrackFitUtils::circle_fit_by_taubin( xy_pts );
878 
879  // skip chain entirely if fit fails
880  if( std::isnan( R ) ) continue;
881 
882  // calculate residuals
883  const std::vector<double> xy_resid = TrackFitUtils::getCircleClusterResiduals(xy_pts,R,X0,Y0);
884 
885  // assign clusters to seed
886  TrackSeed_v1 trackseed;
887  for(size_t i=0;i<chain.size();i++)
888  {
889  //if(xy_resid[i]>_xy_outlier_threshold) continue;
890  trackseed.insert_cluster_key(chain.at(i));
891  }
892 
893  clean_chains.push_back(trackseed);
894  if(Verbosity()>0) std::cout << "pushed clean chain with " << trackseed.size_cluster_keys() << " clusters" << std::endl;
895  }
896 
897  return clean_chains;
898 }
899 
900 
901 void PHCASeeding::publishSeeds(const std::vector<TrackSeed_v1>& seeds)
902 {
903 
904  for( const auto& seed:seeds )
905  {
906  auto pseed = std::make_unique<TrackSeed_v1>(seed);
907  if(Verbosity() > 4)
908  { pseed->identify(); }
909  _track_map->insert(pseed.get());
910  }
911 }
912 
914 {
915  // if(Verbosity()>0)
916  std::cout << "Called Setup" << std::endl;
917  if(Verbosity()>0) std::cout << "topNode:" << topNode << std::endl;
918  PHTrackSeeding::Setup(topNode);
919 
920  // geometry initialization
921  int ret = InitializeGeometry(topNode);
923  { return ret; }
924 
925  // tpc distortion correction
926  m_dcc = findNode::getClass<TpcDistortionCorrectionContainer>(topNode,"TpcDistortionCorrectionContainerStatic");
927  if( m_dcc )
928  { std::cout << "PHCASeeding::Setup - found static TPC distortion correction container" << std::endl; }
929 
930  t_fill = std::make_unique<PHTimer>("t_fill");
931  t_seed = std::make_unique<PHTimer>("t_seed");
932  t_fill->stop();
933  t_seed->stop();
934 
935  // fcfg.set_rescale(1);
936  std::unique_ptr<PHField> field_map;
937  if(_use_const_field)
938  {
939  PHFieldConfigv2 fcfg(0,0,_const_field);
940  field_map = std::unique_ptr<PHField>(PHFieldUtility::BuildFieldMap(&fcfg));
941  }
942  else
943  {
944 
945  PHFieldConfigv1 fcfg;
946  fcfg.set_field_config(PHFieldConfig::FieldConfigTypes::Field3DCartesian);
947  char *calibrationsroot = getenv("CALIBRATIONROOT");
948  assert(calibrationsroot);
949  auto magField = std::string(calibrationsroot) +
950  std::string("/Field/Map/sphenix3dtrackingmapxyz.root");
951  fcfg.set_filename(magField);
952  field_map = std::unique_ptr<PHField>(PHFieldUtility::BuildFieldMap(&fcfg));
953  }
954 
955  fitter = std::make_unique<ALICEKF>(topNode,_cluster_map,field_map.get(),_fieldDir,_min_clusters_per_track,_max_sin_phi,Verbosity());
956  fitter->useConstBField(_use_const_field);
957  fitter->setConstBField(_const_field);
958  fitter->useFixedClusterError(_use_fixed_clus_err);
959  fitter->setFixedClusterError(0,_fixed_clus_err.at(0));
960  fitter->setFixedClusterError(1,_fixed_clus_err.at(1));
961  fitter->setFixedClusterError(2,_fixed_clus_err.at(2));
963 }
964 
966 {
967  if(Verbosity()>0) std::cout << "Called End " << std::endl;
969 }