Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHSimpleKFProp.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHSimpleKFProp.cc
1 
7 #include "PHSimpleKFProp.h"
8 #include "PHGhostRejection.h"
9 #include "ALICEKF.h"
10 #include "nanoflann.hpp"
11 #include "GPUTPCTrackParam.h"
13 
15 
18 
19 #include <phfield/PHField.h>
20 #include <phfield/PHFieldUtility.h>
21 #include <phfield/PHFieldConfig.h>
22 #include <phfield/PHFieldConfigv1.h>
23 
24 #include <phool/PHTimer.h>
25 #include <phool/getClass.h>
26 #include <phool/phool.h> // for PHWHERE
27 
28 // tpc distortion correction
30 
32 #include <trackbase/TrkrCluster.h>
34 #include <trackbase/TrkrDefs.h>
36 #include <trackbase/ActsGeometry.h>
37 
41 
44 #include <Geant4/G4SystemOfUnits.hh>
45 
46 #include <Eigen/Core>
47 #include <Eigen/Dense>
48 
49 #include <iostream> // for operator<<, basic_ostream
50 #include <vector>
51 
52 //#define _DEBUG_
53 
54 #if defined(_DEBUG_)
55 #define LogDebug(exp) std::cout << "DEBUG: " << __FILE__ << ": " << __LINE__ << ": " << exp
56 #else
57 #define LogDebug(exp) (void)0
58 #endif
59 
60 #define LogError(exp) std::cout << "ERROR: " << __FILE__ << ": " << __LINE__ << ": " << exp
61 #define LogWarning(exp) std::cout << "WARNING: " << __FILE__ << ": " << __LINE__ << ": " << exp
62 
63 // anonymous namespace for local functions
64 namespace
65 {
66  // square
67  template<class T> inline constexpr T square( const T& x ) { return x*x; }
68 }
69 
70 using keylist = std::vector<TrkrDefs::cluskey>;
71 
73  : SubsysReco(name)
74 {}
75 
77 {
79 }
80 
82 {
83 
84  int ret = get_nodes(topNode);
85  if (ret != Fun4AllReturnCodes::EVENT_OK) return ret;
86  PHFieldConfigv1 fcfg;
87  fcfg.set_field_config(PHFieldConfig::FieldConfigTypes::Field3DCartesian);
88  char *calibrationsroot = getenv("CALIBRATIONROOT");
89  assert(calibrationsroot);
90  auto magField = std::string(calibrationsroot) +
91  std::string("/Field/Map/sphenix3dtrackingmapxyz.root");
92  fcfg.set_filename(magField);
93  // fcfg.set_rescale(1);
94  _field_map = std::unique_ptr<PHField>(PHFieldUtility::BuildFieldMap(&fcfg));
95 
96  fitter = std::make_unique<ALICEKF>(topNode,_cluster_map,_field_map.get(), _fieldDir,
98  fitter->useConstBField(_use_const_field);
99  fitter->setConstBField(_const_field);
100  fitter->useFixedClusterError(_use_fixed_clus_err);
101  fitter->setFixedClusterError(0,_fixed_clus_err.at(0));
102  fitter->setFixedClusterError(1,_fixed_clus_err.at(1));
103  fitter->setFixedClusterError(2,_fixed_clus_err.at(2));
104  // _field_map = PHFieldUtility::GetFieldMapNode(nullptr,topNode);
105  // m_Cache = magField->makeCache(m_tGeometry->magFieldContext);
106 
108 }
109 
110 double PHSimpleKFProp::get_Bz(double x, double y, double z) const
111 {
112  if(_use_const_field) return _const_field;
113  double p[4] = {x*cm,y*cm,z*cm,0.*cm};
114  double bfield[3];
115  _field_map->GetFieldValue(p,bfield);
116  /* Acts::Vector3 loc(0,0,0);
117  int mfex = (magField != nullptr);
118  int tgex = (m_tGeometry != nullptr);
119  std::cout << " getting acts field " << mfex << " " << tgex << std::endl;
120  auto Cache = m_tGeometry->magField->makeCache(m_tGeometry->magFieldContext);
121  auto bf = m_tGeometry->magField->getField(loc,Cache);
122  if(bf.ok())
123  {
124  Acts::Vector3 val = bf.value();
125  std::cout << "bz big: " << bfield[2]/tesla << " bz acts: " << val(2) << std::endl;
126  }
127  */
128  return bfield[2]/tesla;
129 }
130 
132 {
133  //---------------------------------
134  // Get Objects off of the Node Tree
135  //---------------------------------
136 
137  _tgeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
138  if(!_tgeometry)
139  {
140  std::cout << "No Acts tracking geometry, exiting." << std::endl;
142  }
143 
144  // tpc distortion correction
145  m_dcc = findNode::getClass<TpcDistortionCorrectionContainer>(topNode,"TpcDistortionCorrectionContainer");
146  if( m_dcc )
147  { std::cout << "PHSimpleKFProp::InitRun - found TPC distortion correction container" << std::endl; }
148 
150  _cluster_map = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER_TRUTH");
151  else
152  _cluster_map = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
153 
154  if (!_cluster_map)
155  {
156  std::cerr << PHWHERE << " ERROR: Can't find node TRKR_CLUSTER" << std::endl;
158  }
159 
160  _track_map = findNode::getClass<TrackSeedContainer>(topNode, "TpcTrackSeedContainer");
161  if (!_track_map)
162  {
163  std::cerr << PHWHERE << " ERROR: Can't find TrackSeedContainer " << std::endl;
165  }
166 
167  PHG4TpcCylinderGeomContainer *geom_container =
168  findNode::getClass<PHG4TpcCylinderGeomContainer>(topNode, "CYLINDERCELLGEOM_SVTX");
169  if (!geom_container)
170  {
171  std::cerr << PHWHERE << "ERROR: Can't find node CYLINDERCELLGEOM_SVTX" << std::endl;
173  }
174 
175  for(int i=7;i<=54;i++)
176  {
177  radii.push_back(geom_container->GetLayerCellGeom(i)->get_radius());
178  }
179 
181 }
182 
184 {
185  if(_n_iteration!=0){
186  _iteration_map = findNode::getClass<TrkrClusterIterationMapv1>(topNode, "CLUSTER_ITERATION_MAP");
187  if (!_iteration_map){
188  std::cerr << PHWHERE << "Cluster Iteration Map missing, aborting." << std::endl;
190  }
191  }
192 
193  PHTimer timer("KFPropTimer");
194 
195  timer.stop();
196  timer.restart();
197 
198  if(Verbosity()>0) std::cout << "starting Process" << std::endl;
199  PositionMap globalPositions = PrepareKDTrees();
200  if(Verbosity()>0) std::cout << "prepared KD trees" << std::endl;
201 
202  std::vector<std::vector<TrkrDefs::cluskey>> new_chains;
203  std::vector<TrackSeed_v1> unused_tracks;
204  for(int track_it = 0; track_it != _track_map->size(); ++track_it )
205  {
206  if(Verbosity()>0) std::cout << "TPC seed " << track_it << std::endl;
207  // if not a TPC track, ignore
208  TrackSeed* track = _track_map->get(track_it);
209  const bool is_tpc = std::any_of(
210  track->begin_cluster_keys(),
211  track->end_cluster_keys(),
212  []( const TrkrDefs::cluskey& key ) { return TrkrDefs::getTrkrId(key) == TrkrDefs::tpcId; } );
213 
214  if(is_tpc)
215  {
216  std::vector<std::vector<TrkrDefs::cluskey>> keylist;
217  std::vector<TrkrDefs::cluskey> dumvec;
218  std::map<TrkrDefs::cluskey, Acts::Vector3> trackClusPositions;
220  iter != track->end_cluster_keys();
221  ++iter)
222  {
223  dumvec.push_back(*iter);
224  auto pos = globalPositions.at(*iter);
225  trackClusPositions.insert(std::make_pair(*iter,pos));
226  }
227 
229  if(dumvec.size() < 3)
230  { continue; }
231 
232  keylist.push_back(dumvec);
233 
236  std::vector<float> trackChi2;
237  timer.stop();
238  timer.restart();
239 
240  auto seedpair = fitter->ALICEKalmanFilter(keylist, false,
241  trackClusPositions, trackChi2);
242 
243  timer.stop();
244  if(Verbosity() > 3)
245  { std::cout << "single track ALICEKF time " << timer.elapsed()
246  << std::endl;
247  }
248  timer.restart();
250  track->circleFitByTaubin(trackClusPositions, 7, 55);
251  track->lineFit(trackClusPositions, 7, 55);
252  timer.stop();
253  if(Verbosity() > 3)
254  { std::cout << "single track circle fit time " << timer.elapsed() << std::endl; }
255  if(seedpair.first.size() == 0 || seedpair.second.size() == 0)
256  { continue; }
257  if(Verbosity()>0) std::cout << "is tpc track" << std::endl;
258 
259  timer.stop();
260  timer.restart();
261 
262  if(Verbosity()>0) std::cout << "propagate first round" << std::endl;
263  auto preseed = PropagateTrack(track,seedpair.second.at(0),globalPositions);
264 
265  if(Verbosity()>0) std::cout << "preseed size " << preseed.size() << std::endl;
266 
267  if(preseed.size()>40){
268  new_chains.push_back(preseed);
269  continue;
270  }
271 
272  std::vector<std::vector<TrkrDefs::cluskey>> kl;
273  kl.push_back(preseed);
274 
275  if(Verbosity()>0) std::cout << "kl size " << kl.size() << std::endl;
276  std::vector<float> pretrackChi2;
277  auto prepair = fitter->ALICEKalmanFilter(kl,false,globalPositions,pretrackChi2);
278  if(prepair.first.size()==0 || prepair.second.size()==0) continue;
279 
280  auto pretrack = prepair.first.at(0);
281  std::vector<TrkrDefs::cluskey> dumvec2;
282  std::map<TrkrDefs::cluskey, Acts::Vector3> pretrackClusPositions;
283  for(TrackSeed::ConstClusterKeyIter iter = pretrack.begin_cluster_keys();
284  iter != pretrack.end_cluster_keys();
285  ++iter)
286  {
287  dumvec2.push_back(*iter);
288  auto pos = globalPositions.at(*iter);
289  pretrackClusPositions.insert(std::make_pair(*iter,pos));
290  }
291 
292  pretrack.circleFitByTaubin(pretrackClusPositions, 7, 55);
293  pretrack.lineFit(pretrackClusPositions, 7, 55);
294 
295  new_chains.push_back(PropagateTrack(&pretrack, prepair.second.at(0),
296  globalPositions));
297  timer.stop();
298  auto propagatetime = timer.elapsed();
299  if(Verbosity() > 3)
300  { std::cout << "propagate track time " << propagatetime << std::endl; }
301  }
302  else
303  {
304  // this is bad: it copies the track to its base class, which is essentially nothing
305  if(Verbosity()>0) std::cout << "is NOT tpc track" << std::endl;
306  unused_tracks.push_back(*track);
307  }
308  }
309 
310  _track_map->Reset();
311  timer.stop();
312  timer.restart();
313 
314  std::vector<std::vector<TrkrDefs::cluskey>> clean_chains = RemoveBadClusters(new_chains, globalPositions);
315  timer.stop();
316 
317  timer.stop();
318  timer.restart();
319  std::vector<float> trackChi2;
320  auto seeds = fitter->ALICEKalmanFilter(clean_chains, true, globalPositions,
321  trackChi2);
322  timer.stop();
323  auto alicekftime = timer.elapsed();
324  if(Verbosity() > 0 )
325  { std::cout << "full alice kf time all tracks " << alicekftime << std::endl; }
326  timer.stop();
327  timer.restart();
328  publishSeeds(seeds.first, globalPositions);
329 
330  timer.stop();
331  auto circlefittime = timer.elapsed();
332  if(Verbosity() > 0)
333  { std::cout << "circle fit all tracks time " << circlefittime << std::endl; }
334  publishSeeds(unused_tracks);
335 
337  PHGhostRejection rejector(Verbosity());
338  rejector.positionMap(globalPositions);
339  rejector.trackSeedContainer(_track_map);
340  timer.stop();
341  timer.restart();
342  rejector.rejectGhostTracks(trackChi2);
343  timer.stop();
344  if(Verbosity() > 2)
345  { std::cout << "ghost rejection time " << timer.elapsed() << std::endl; }
346 
348 }
349 
351 {
352  // get global position from Acts transform
353  auto globalpos = _tgeometry->getGlobalPosition(key, cluster);
354 
355  // check if TPC distortion correction are in place and apply
356  if( m_dcc ) { globalpos = m_distortionCorrection.get_corrected_position( globalpos, m_dcc ); }
357 
358  return globalpos;
359 }
360 
362 {
363  PositionMap globalPositions;
364  //***** convert clusters to kdhits, and divide by layer
365  std::vector<std::vector<std::vector<double> > > kdhits;
366  kdhits.resize(58);
367  if (!_cluster_map)
368  {
369  std::cout << "WARNING: (tracking.PHTpcTrackerUtil.convert_clusters_to_hits) cluster map is not provided" << std::endl;
370  return globalPositions;
371  }
372 
374  {
375  auto range = _cluster_map->getClusters(hitsetkey);
376  for (TrkrClusterContainer::ConstIterator it = range.first; it != range.second; ++it)
377  {
378  TrkrDefs::cluskey cluskey = it->first;
379  TrkrCluster* cluster = it->second;
380  if(!cluster) continue;
381  if(_n_iteration!=0){
382  if(_iteration_map != NULL ){
383  // std::cout << "map exists entries: " << _iteration_map->size() << std::endl;
384  if(_iteration_map->getIteration(cluskey)>0){
385  //std::cout << "hit used, continue" << std::endl;
386  continue; // skip hits used in a previous iteration
387  }
388  }
389  }
390 
391  const Acts::Vector3 globalpos_d = getGlobalPosition( cluskey, cluster);
392  const Acts::Vector3 globalpos = { (float) globalpos_d.x(), (float) globalpos_d.y(), (float) globalpos_d.z()};
393  globalPositions.insert(std::make_pair(cluskey, globalpos));
394 
395  int layer = TrkrDefs::getLayer(cluskey);
396  std::vector<double> kdhit(4);
397  kdhit[0] = globalpos_d.x();
398  kdhit[1] = globalpos_d.y();
399  kdhit[2] = globalpos_d.z();
400  uint64_t key = cluskey;
401  std::memcpy(&kdhit[3], &key, sizeof(key));
402 
403  // HINT: way to get original uint64_t value from double:
404  //
405  // LOG_DEBUG("tracking.PHTpcTrackerUtil.convert_clusters_to_hits")
406  // << "orig: " << cluster->getClusKey() << ", readback: " << (*((int64_t*)&kdhit[3]));
407 
408  kdhits[layer].push_back(kdhit);
409  }
410  }
411  _ptclouds.resize(kdhits.size());
412  _kdtrees.resize(kdhits.size());
413  for(size_t l=0;l<kdhits.size();++l)
414  {
415  if(Verbosity()>0) std::cout << "l: " << l << std::endl;
416  _ptclouds[l] = std::make_shared<KDPointCloud<double>>();
417  _ptclouds[l]->pts.resize(kdhits[l].size());
418  if(Verbosity()>0) std::cout << "resized to " << kdhits[l].size() << std::endl;
419  for(size_t i=0;i<kdhits[l].size();++i)
420  {
421  _ptclouds[l]->pts[i] = kdhits[l][i];
422  }
423  _kdtrees[l] = std::make_shared<nanoflann::KDTreeSingleIndexAdaptor<nanoflann::L2_Simple_Adaptor<double, KDPointCloud<double>>, KDPointCloud<double>, 3>>(3,*(_ptclouds[l]),nanoflann::KDTreeSingleIndexAdaptorParams(10));
424  _kdtrees[l]->buildIndex();
425  }
426 
427  return globalPositions;
428 }
429 
430 
431 std::vector<TrkrDefs::cluskey> PHSimpleKFProp::PropagateTrack(TrackSeed* track, Eigen::Matrix<double,6,6>& xyzCov, const PositionMap& globalPositions) const
432 {
433  // extract cluster list
434 
435  std::vector<TrkrDefs::cluskey> ckeys;
436  std::copy(track->begin_cluster_keys(),track->end_cluster_keys(),std::back_inserter(ckeys));
437 
438  if(ckeys.size()>1 && ((int)TrkrDefs::getLayer(ckeys.front()))>((int)TrkrDefs::getLayer(ckeys.back())))
439  {
440  std::reverse(ckeys.begin(),ckeys.end());
441  }
442 
443  double track_x = track->get_x();
444  double track_y = track->get_y();
445  double track_z = track->get_z();
446 
447  if(Verbosity()>0) std::cout << "track (x,y,z) = (" << track_x << ", " << track_y << ", " << track_z << ")" << std::endl;
448 
449  double track_px = NAN;
450  double track_py = NAN;
451  double track_pz = NAN;
452  if(_use_const_field)
453  {
454  float pt = fabs(1./track->get_qOverR()) * (0.3/100) * _const_field;
455  float phi = track->get_phi(_cluster_map, _tgeometry);
456  track_px = pt * std::cos(phi);
457  track_py = pt * std::sin(phi);
458  track_pz = pt * std::cosh(track->get_eta()) * std::cos(track->get_theta());
459  }
460  else
461  {
462  track_px = track->get_px(_cluster_map,_tgeometry);
463  track_py = track->get_py(_cluster_map,_tgeometry);
464  track_pz = track->get_pz();
465  }
466 
467  if(Verbosity()>0) std::cout << "track (px,py,pz) = (" << track_px << ", " << track_py << ", " << track_pz << ")" << std::endl;
468 
469  // Move to first tpc cluster layer if necessary
470 // if(sqrt(track_x*track_x+track_y*track_y)<10.)
471 // {
472  if(Verbosity()>0) std::cout << "WARNING: moving track into TPC" << std::endl;
473  std::vector<Acts::Vector3> trkGlobPos;
474  for(const auto& ckey : ckeys)
475  {
477  { trkGlobPos.push_back(globalPositions.at(ckey)); }
478  }
479  // want angle of tangent to circle at innermost (i.e. last) cluster
480  size_t inner_index;
481  if(TrkrDefs::getLayer(ckeys[0])>TrkrDefs::getLayer(ckeys.back()))
482  {
483  inner_index = ckeys.size()-1;
484  }
485  else
486  {
487  inner_index = 0;
488  }
489 
490  double xc = track->get_X0();
491  double yc = track->get_Y0();
492  double cluster_x = trkGlobPos.at(inner_index)(0);
493  double cluster_y = trkGlobPos.at(inner_index)(1);
494  double dy = cluster_y-yc;
495  double dx = cluster_x-xc;
496  double phi = atan2(dy,dx);
497  double dx0 = trkGlobPos.at(0)(0) - xc;
498  double dy0 = trkGlobPos.at(0)(1) - yc;
499  double phi0 = atan2(dy0, dx0);
500  double dx1 = trkGlobPos.at(1)(0) - xc;
501  double dy1 = trkGlobPos.at(1)(1) - yc;
502  double phi1 = atan2(dy1, dx1);
503  double dphi = phi1 - phi0;
504 
505  if(dphi < 0)
506  phi += M_PI / 2.0;
507  else
508  phi -= M_PI / 2.0;
509 
510  double pt = sqrt(track_px*track_px+track_py*track_py);
511  // rotate track momentum vector (pz stays the same)
512  track_px = pt * cos(phi);
513  track_py = pt * sin(phi);
514  track_x = trkGlobPos.at(0)(0);
515  track_y = trkGlobPos.at(0)(1);
516  track_z = trkGlobPos.at(0)(2);
517 
518  if(Verbosity()>0) std::cout << "new track (x,y,z) = " << track_x << ", " << track_y << ", " << track_z << ")" << std::endl;
519  if(Verbosity()>0) std::cout << "new track (px,py,pz) = " << track_px << ", " << track_py << ", " << track_pz << ")" << std::endl;
520 
521 // }
522 
523  double track_pt = sqrt(track_px*track_px + track_py*track_py);
524  if(Verbosity()>0) std::cout << "track pt: " << track_pt << std::endl;
525 
526  // get track parameters
527  GPUTPCTrackParam kftrack;
528  kftrack.InitParam();
529  float track_phi = atan2(track_y,track_x);
530  if(Verbosity()>0) std::cout << "track phi: " << track_phi << std::endl;
531  kftrack.SetQPt(track->get_charge()/track_pt);
532 
533  float track_pX = track_px*cos(track_phi)+track_py*sin(track_phi);
534  float track_pY = -track_px * sin(track_phi) + track_py * cos(track_phi);
535 
536  kftrack.SetSignCosPhi(track_pX/track_pt);
537  kftrack.SetSinPhi(track_pY/track_pt);
538  kftrack.SetDzDs(-track_pz/track_pt);
539 
540  // Y = y
541  // Z = z
542  // SinPhi = py/sqrt(px^2+py^2)
543  // DzDs = pz/sqrt(px^2+py^2)
544  // QPt = 1/sqrt(px^2+py^2)
545 
546  const double track_pt3 = std::pow( track_pt, 3. );
547 
548  Eigen::Matrix<double,6,5> Jrot;
549  Jrot(0,0) = 0; // dY/dx
550  Jrot(1,0) = 1; // dY/dy
551  Jrot(2,0) = 0; // dY/dz
552  Jrot(3,0) = 0; // dY/dpx
553  Jrot(4,0) = 0; // dY/dpy
554  Jrot(5,0) = 0; // dY/dpz
555 
556  Jrot(0,1) = 0; // dZ/dx
557  Jrot(1,1) = 0; // dZ/dy
558  Jrot(2,1) = 1; // dZ/dz
559  Jrot(3,1) = 0; // dZ/dpx
560  Jrot(4,1) = 0; // dZ/dpy
561  Jrot(5,1) = 0; // dZ/dpz
562 
563  Jrot(0,2) = 0; // dSinPhi/dx
564  Jrot(1,2) = 0; // dSinPhi/dy
565  Jrot(2,2) = 0; // dSinPhi/dz
566  Jrot(3,2) = -track_py*track_px/track_pt3; // dSinPhi/dpx
567  Jrot(4,2) = track_px*track_px/track_pt3; // dSinPhi/dpy
568  Jrot(5,2) = 0; // dSinPhi/dpz
569 
570  Jrot(0,3) = 0; // dDzDs/dx
571  Jrot(1,3) = 0; // dDzDs/dy
572  Jrot(2,3) = 0; // dDzDs/dz
573  Jrot(3,3) = -track_px*track_pz/track_pt3; // dDzDs/dpx
574  Jrot(4,3) = -track_py*track_pz/track_pt3; // dDzDs/dpy
575  Jrot(5,3) = 1./track_pt; // dDzDs/dpz
576 
577  Jrot(0,4) = 0; // dQPt/dx
578  Jrot(1,4) = 0; // dQPt/dy
579  Jrot(2,4) = 0; // dQPt/dz
580  Jrot(3,4) = -track_px/track_pt3; // dQPt/dpx
581  Jrot(4,4) = -track_py/track_pt3; // dQPt/dpy
582  Jrot(5,4) = 0; // dQPt/dpz
583 
584  Eigen::Matrix<double,5,5> kfCov = Jrot.transpose()*xyzCov*Jrot;
585 
586  int ctr = 0;
587  for(int i=0;i<5;i++)
588  {
589  for(int j=0;j<5;j++)
590  {
591  if(i>=j)
592  {
593  kftrack.SetCov(ctr,kfCov(i,j));
594  ctr++;
595  }
596  }
597  }
598 
599  std::vector<TrkrDefs::cluskey> propagated_track;
600 
601  kftrack.SetX(track_x*cos(track_phi)+track_y*sin(track_phi));
602  kftrack.SetY(-track_x*sin(track_phi)+track_y*cos(track_phi));
603  kftrack.SetZ(track_z);
604 
605  if(Verbosity()>0)
606  {
607  std::cout << "initial track params:" << std::endl;
608  std::cout << "X: " << kftrack.GetX() << std::endl;
609  std::cout << "Y: " << kftrack.GetY() << std::endl;
610  std::cout << "Z: " << kftrack.GetZ() << std::endl;
611  std::cout << "SinPhi: " << kftrack.GetSinPhi() << std::endl;
612  std::cout << "DzDs: " << kftrack.GetDzDs() << std::endl;
613  std::cout << "QPt: " << kftrack.GetQPt() << std::endl;
614  std::cout << "cov: " << std::endl;
615  for(int i=0; i<15; i++) std::cout << kftrack.GetCov(i) << ", ";
616  std::cout << std::endl;
617 
618  }
619 
620  // get layer for each cluster
621  std::vector<unsigned int> layers;
622  std::transform( ckeys.begin(), ckeys.end(), std::back_inserter( layers ), []( const TrkrDefs::cluskey& key ) { return TrkrDefs::getLayer(key); } );
623 
624  double old_phi = track_phi;
625  unsigned int old_layer = TrkrDefs::getLayer(ckeys[0]);
626  if(Verbosity()>0) std::cout << "first layer: " << old_layer << std::endl;
627  if(Verbosity()>0) std::cout << "cluster (x,y,z) = (" << globalPositions.at(ckeys[0])(0) << ", " << globalPositions.at(ckeys[0])(1) << ", " << globalPositions.at(ckeys[0])(2) << ")" << std::endl;
628  propagated_track.push_back(ckeys[0]);
629 
630  GPUTPCTrackLinearisation kfline(kftrack);
632  kftrack.CalculateFitParameters(fp);
633 
634  // first, propagate downward
635  for(unsigned int l=old_layer+1;l<=54;l++)
636  {
637  if(std::isnan(kftrack.GetX()) ||
638  std::isnan(kftrack.GetY()) ||
639  std::isnan(kftrack.GetZ())) continue;
640  if(fabs(kftrack.GetZ())>105.) continue;
641  if(Verbosity()>0) std::cout << "\nlayer " << l << ":" << std::endl;
642  // check to see whether layer is already occupied by at least one cluster
643  // choosing the last one first (clusters organized from inside out)
644  bool layer_filled = false;
645  TrkrDefs::cluskey next_ckey = 0;
646  for(int k=layers.size()-1; k>=0; k--)
647  {
648  if(layer_filled) continue;
649  if(layers[k]==l)
650  {
651  layer_filled = true;
652  next_ckey = ckeys[k];
653  }
654  }
655  // if layer is already occupied, reset track parameters to last cluster in layer
656  if(layer_filled)
657  {
658  if(Verbosity()>0) std::cout << "layer is filled" << std::endl;
659  TrkrCluster* nc = _cluster_map->findCluster(next_ckey);
660  auto globalpos = globalPositions.at(next_ckey);
661  double cx = globalpos(0);
662  double cy = globalpos(1);
663  double cz = globalpos(2);
664  double cphi = atan2(cy,cx);
665  double cxerr = sqrt(fitter->getClusterError(nc,next_ckey,globalpos,0,0));
666  double cyerr = sqrt(fitter->getClusterError(nc,next_ckey,globalpos,1,1));
667  double czerr = sqrt(fitter->getClusterError(nc,next_ckey,globalpos,2,2));
668  double alpha = cphi-old_phi;
669  double tX = kftrack.GetX();
670  double tY = kftrack.GetY();
671  double tx = tX*cos(old_phi)-tY*sin(old_phi);
672  double ty = tX*sin(old_phi)+tY*cos(old_phi);
673  double tz = kftrack.GetZ();
674 // GPUTPCTrackParam::GPUTPCTrackFitParam fp;
675 // kftrack.CalculateFitParameters(fp);
676  if(Verbosity()>0) std::cout << "track position: (" << tx << ", " << ty << ", " << tz << ")" << std::endl;
677  kftrack.Rotate(alpha/2.,kfline,10.);
678  double newX = cx*cos(cphi)+cy*sin(cphi);
679  kftrack.TransportToXWithMaterial((tX+newX)/2.,kfline,fp,_Bzconst*get_Bz(tx,ty,tz),10.);
680  kftrack.Rotate(alpha/2.,kfline,10.);
681  kftrack.TransportToXWithMaterial(cx*cos(cphi)+cy*sin(cphi),kfline,fp,_Bzconst*get_Bz(tx,ty,tz),10.);
682  if(std::isnan(kftrack.GetX()) ||
683  std::isnan(kftrack.GetY()) ||
684  std::isnan(kftrack.GetZ())) continue;
685  tX = kftrack.GetX();
686  tY = kftrack.GetY();
687  tx = tX*cos(cphi)-tY*sin(cphi);
688  ty = tX*sin(cphi)+tY*cos(cphi);
689  tz = kftrack.GetZ();
690  double tYerr = sqrt(kftrack.GetCov(0));
691  double tzerr = sqrt(kftrack.GetCov(5));
692  double txerr = fabs(tYerr*sin(cphi));
693  double tyerr = fabs(tYerr*cos(cphi));
694  if(Verbosity()>0) std::cout << "cluster position: (" << cx << ", " << cy << ", " << cz << ")" << std::endl;
695  if(Verbosity()>0) std::cout << "cluster position errors: (" << cxerr << ", " << cyerr << ", " << czerr << ")" << std::endl;
696  if(Verbosity()>0) std::cout << "new track position: (" << kftrack.GetX()*cos(cphi)-kftrack.GetY()*sin(cphi) << ", " << kftrack.GetX()*sin(cphi)+kftrack.GetY()*cos(cphi) << ", " << kftrack.GetZ() << ")" << std::endl;
697  if(Verbosity()>0) std::cout << "track position errors: (" << txerr << ", " << tyerr << ", " << tzerr << ")" << std::endl;
698  if(Verbosity()>0) std::cout << "distance: " << sqrt(square(kftrack.GetX()*cos(cphi)-kftrack.GetY()*sin(cphi)-cx)+square(kftrack.GetX()*sin(cphi)+kftrack.GetY()*cos(cphi)-cy)+square(kftrack.GetZ()-cz)) << std::endl;
699  if(1)//fabs(tx-cx)<_max_dist*sqrt(txerr*txerr+cxerr*cxerr) &&
700  //fabs(ty-cy)<_max_dist*sqrt(tyerr*tyerr+cyerr*cyerr) &&
701  //fabs(tz-cz)<_max_dist*sqrt(tzerr*tzerr+czerr*czerr))
702  {
703  if(Verbosity()>0) std::cout << "Kept cluster" << std::endl;
704  propagated_track.push_back(next_ckey);
705 // kftrack.SetX(cx*cos(cphi)+cy*sin(cphi));
706 // kftrack.SetY(-cx*sin(cphi)+cy*cos(cphi));
707 // kftrack.SetZ(cz);
708  }
709  else
710  {
711  if(Verbosity()>0)
712  {
713  std::cout << "Rejected cluster" << std::endl;
714  std::cout << "dx: " << fabs(tx-cx) << " when max = " << _max_dist*sqrt(txerr*txerr+cxerr*cxerr) << std::endl;
715  std::cout << "dy: " << fabs(ty-cy) << " when max = " << _max_dist*sqrt(tyerr*tyerr+cyerr*cyerr) << std::endl;
716  std::cout << "dz: " << fabs(tz-cz) << " when max = " << _max_dist*sqrt(tzerr*tzerr+czerr*czerr) << std::endl;
717  }
718  kftrack.SetNDF(kftrack.GetNDF()-2);
719  //ckeys.erase(std::remove(ckeys.begin(),ckeys.end(),next_ckey),ckeys.end());
720  }
721  old_phi = cphi;
722  }
723  // if layer is not occupied, search for the nearest available cluster to projected track position
724  else
725  {
726  if(Verbosity()>0) std::cout << "layer not filled" << std::endl;
727  // get current track coordinates to extract B field from map
728  double tX = kftrack.GetX();
729  double tY = kftrack.GetY();
730  double tx = tX*cos(old_phi)-tY*sin(old_phi);
731  double ty = tX*sin(old_phi)+tY*cos(old_phi);
732  double tz = kftrack.GetZ();
733 // GPUTPCTrackParam::GPUTPCTrackFitParam fp;
734 // kftrack.CalculateFitParameters(fp);
735  double newX = radii[l-7];
736  double alpha = atan2(ty,tx)-old_phi;
737  kftrack.Rotate(alpha/2.,kfline,10.);
738  kftrack.TransportToXWithMaterial((tX+newX)/2.,kfline,fp,_Bzconst*get_Bz(tx,ty,tz),10.);
739  kftrack.Rotate(alpha/2.,kfline,10.);
740  kftrack.TransportToXWithMaterial(radii[l-7],kfline,fp,_Bzconst*get_Bz(tx,ty,tz),10.);
741  if(std::isnan(kftrack.GetX()) ||
742  std::isnan(kftrack.GetY()) ||
743  std::isnan(kftrack.GetZ())) continue;
744  // update track coordinates after transport
745  tX = kftrack.GetX();
746  tY = kftrack.GetY();
747  double tYerr = sqrt(kftrack.GetCov(0));
748  double tzerr = sqrt(kftrack.GetCov(5));
749  tx = tX*cos(old_phi)-tY*sin(old_phi);
750  ty = tX*sin(old_phi)+tY*cos(old_phi);
751  tz = kftrack.GetZ();
752  double query_pt[3] = {tx, ty, tz};
753 
754  if(m_dcc)
755  {
756  // The distortion corrected cluster positions in globalPos are not at the layer radius
757  // We want to project to the radius appropriate for the globalPos values
758  // Get the distortion correction for the projection point, and calculate the radial increment
759 
760  double proj_radius = sqrt(tx*tx+ty*ty);
761  if(proj_radius > 78.0 || abs(tz) > 105.5) continue; // projection is bad, no cluster will be found
762 
763  Acts::Vector3 proj_pt(tx,ty,tz);
764  if(Verbosity() > 2)
765  std::cout << " call distortion correction for layer " << l << " tx " << tx << " ty " << ty << " tz " << tz << " radius " << proj_radius << std::endl;
766  proj_pt = m_distortionCorrection.get_corrected_position( proj_pt, m_dcc );
767  // this point is meaningless, except that it gives us an estimate of the corrected radius of a point measured in this layer
768  double radius = sqrt(proj_pt[0]*proj_pt[0] + proj_pt[1]*proj_pt[1]);
769  // now project the track to that radius
770  if(Verbosity() > 2)
771  std::cout << " call transport again for layer " << l << " x " << proj_pt[0] << " y " << proj_pt[1] << " z " << proj_pt[2]
772  << " radius " << radius << std::endl;
773  double newX = radius;
774  double alpha = atan2(ty,tx)-old_phi;
775  kftrack.Rotate(alpha/2.,kfline,10.);
776  kftrack.TransportToXWithMaterial((tX+newX)/2.,kfline,fp,_Bzconst*get_Bz(tx,ty,tz),10.);
777  kftrack.Rotate(alpha/2.,kfline,10.);
778  kftrack.TransportToXWithMaterial(radius,kfline,fp,_Bzconst*get_Bz(tx,ty,tz),10.);
779  if(std::isnan(kftrack.GetX()) ||
780  std::isnan(kftrack.GetY()) ||
781  std::isnan(kftrack.GetZ())) continue;
782  tX = kftrack.GetX();
783  tY = kftrack.GetY();
784  tYerr = sqrt(kftrack.GetCov(0));
785  tzerr = sqrt(kftrack.GetCov(5));
786  tx = tX*cos(old_phi)-tY*sin(old_phi);
787  ty = tX*sin(old_phi)+tY*cos(old_phi);
788  tz = kftrack.GetZ();
789  query_pt[0] = tx;
790  query_pt[1] = ty;
791  query_pt[2] = tz;
792  }
793 
794  double txerr = fabs(tYerr*sin(old_phi));
795  double tyerr = fabs(tYerr*cos(old_phi));
796  if(Verbosity()>0) std::cout << "transported to " << radii[l-7] << "\n";
797  if(Verbosity()>0) std::cout << "track position: (" << tx << ", " << ty << ", " << tz << ")" << std::endl;
798  if(Verbosity()>0) std::cout << "track position error: (" << txerr << ", " << tyerr << ", " << tzerr << ")" << std::endl;
799 
800 // size_t ret_index;
801 // double out_dist_sqr;
802 // nanoflann::KNNResultSet<double> resultSet(1);
803 // resultSet.init(&ret_index,&out_dist_sqr);
804 // _kdtrees[l]->findNeighbors(resultSet, &query_pt[0], nanoflann::SearchParams(10));
805  std::vector<long unsigned int> index_out(1);
806  std::vector<double> distance_out(1);
807  int n_results = _kdtrees[l]->knnSearch(&query_pt[0],1,&index_out[0],&distance_out[0]);
808  if(Verbosity()>0) std::cout << "index_out: " << index_out[0] << std::endl;
809  if(Verbosity()>0) std::cout << "squared_distance_out: " << distance_out[0] << std::endl;
810  if(Verbosity()>0) std::cout << "solid_angle_dist: " << atan2(sqrt(distance_out[0]),radii[l-7]) << std::endl;
811  if(n_results==0) continue;
812  std::vector<double> point = _ptclouds[l]->pts[index_out[0]];
813  TrkrDefs::cluskey closest_ckey = (*((int64_t*)&point[3]));
814  TrkrCluster* cc = _cluster_map->findCluster(closest_ckey);
815  auto ccglob = globalPositions.at(closest_ckey);
816  double ccX = ccglob(0);
817  double ccY = ccglob(1);
818  double ccZ = ccglob(2);
819 
820  /*
821  // alternatively:
822  if(m_dcc)
823  {
824  // The distortion corrected cluster positions in globalPos are not at the layer radius
825  // We want to project to the radius appropriate for the globalPos values
826  // Get the radius from the nearest associated cluster found above
827  Acts::Vector3 proj_pt(ccX, ccY, ccZ);
828  double radius = sqrt(proj_pt[0]*proj_pt[0] + proj_pt[1]*proj_pt[1]);
829 
830  // now project the track to that radius
831  if(Verbosity() > 2)
832  std::cout << " call transport again for layer " << l << " x " << proj_pt[0] << " y " << proj_pt[1] << " z " << proj_pt[2]
833  << " radius " << radius << std::endl;
834  kftrack.TransportToX(radius,kfline,_Bzconst*get_Bz(ccX,ccY,ccZ),10.);
835  if(std::isnan(kftrack.GetX()) ||
836  std::isnan(kftrack.GetY()) ||
837  std::isnan(kftrack.GetZ())) continue;
838  tX = kftrack.GetX();
839  tY = kftrack.GetY();
840  tYerr = sqrt(kftrack.GetCov(0));
841  tzerr = sqrt(kftrack.GetCov(5));
842  tx = tX*cos(old_phi)-tY*sin(old_phi);
843  ty = tX*sin(old_phi)+tY*cos(old_phi);
844  tz = kftrack.GetZ();
845  query_pt[0] = tx;
846  query_pt[1] = ty;
847  query_pt[2] = tz;
848 
849  n_results = _kdtrees[l]->knnSearch(&query_pt[0],1,&index_out[0],&distance_out[0]);
850  if(Verbosity()>0) std::cout << "index_out: " << index_out[0] << std::endl;
851  if(Verbosity()>0) std::cout << "squared_distance_out: " << distance_out[0] << std::endl;
852  if(Verbosity()>0) std::cout << "solid_angle_dist: " << atan2(sqrt(distance_out[0]),radii[l-7]) << std::endl;
853  if(n_results==0) continue;
854  point = _ptclouds[l]->pts[index_out[0]];
855  closest_ckey = (*((int64_t*)&point[3]));
856  cc = _cluster_map->findCluster(closest_ckey);
857  ccglob = globalPositions.at(closest_ckey);
858  ccX = ccglob(0);
859  ccY = ccglob(1);
860  ccZ = ccglob(2);
861  }
862  */
863 
864  double cxerr = sqrt(fitter->getClusterError(cc,closest_ckey,ccglob,0,0));
865  double cyerr = sqrt(fitter->getClusterError(cc,closest_ckey,ccglob,1,1));
866  double czerr = sqrt(fitter->getClusterError(cc,closest_ckey,ccglob,2,2));
867  double ccphi = atan2(ccY,ccX);
868  if(Verbosity()>0) std::cout << "cluster position: (" << ccX << ", " << ccY << ", " << ccZ << ")" << std::endl;
869  if(Verbosity()>0) std::cout << "cluster position error: (" << cxerr << ", " << cyerr << ", " << czerr << ")" << std::endl;
870  if(Verbosity()>0) std::cout << "cluster X: " << ccX*cos(ccphi)+ccY*sin(ccphi) << std::endl;
871  if(fabs(tx-ccX)<_max_dist*sqrt(txerr*txerr+cxerr*cxerr) &&
872  fabs(ty-ccY)<_max_dist*sqrt(tyerr*tyerr+cyerr*cyerr) &&
873  fabs(tz-ccZ)<_max_dist*sqrt(tzerr*tzerr+czerr*czerr))
874  {
875  propagated_track.push_back(closest_ckey);
876  layers.push_back(TrkrDefs::getLayer(closest_ckey));
877 /* TrkrCluster* cc = _cluster_map->findCluster(closest_ckey);
878  double ccX = cc->getX();
879  std::cout << "cluster X: " << ccX << std::endl;
880  double ccY = cc->getY();
881  double ccx = ccX*cos(old_phi)-ccY*sin(old_phi);
882  double ccy = ccX*sin(old_phi)+ccY*cos(old_phi);
883  std::cout << "cluster position: (" << ccx << ", " << ccy << ", " << cc->getZ() << ")" << std::endl;
884 */
885 
886  double alpha = ccphi-old_phi;
887  kftrack.Rotate(alpha,kfline,10.);
888 // kftrack.SetX(ccX*cos(ccphi)+ccY*sin(ccphi));
889 // kftrack.SetY(-ccX*sin(ccphi)+ccY*cos(ccphi));
890 // kftrack.SetZ(cc->getZ());
891  double ccaY = -ccX*sin(ccphi)+ccY*cos(ccphi);
892  double ccerrY = fitter->getClusterError(cc,closest_ckey,ccglob,0,0)*sin(ccphi)*sin(ccphi)+fitter->getClusterError(cc,closest_ckey,ccglob,0,1)*sin(ccphi)*cos(ccphi)+fitter->getClusterError(cc,closest_ckey,ccglob,1,1)*cos(ccphi)*cos(ccphi);
893  double ccerrZ = fitter->getClusterError(cc,closest_ckey,ccglob,2,2);
894  kftrack.Filter(ccaY,ccZ,ccerrY,ccerrZ,_max_sin_phi);
895  if(Verbosity()>0) std::cout << "added cluster" << std::endl;
896  old_phi = ccphi;
897  }
898  }
899  old_layer = l;
900  }
901 // old_layer = TrkrDefs::getLayer(ckeys[0]);
902 // std::reverse(ckeys.begin(),ckeys.end());
903  layers.clear();
904  if(Verbosity()>0) std::cout << "\nlayers after outward propagation:" << std::endl;
905  for(int i=0;i<propagated_track.size();i++)
906  {
907  layers.push_back(TrkrDefs::getLayer(propagated_track[i]));
908  if(Verbosity()>0) std::cout << layers[i] << std::endl;
909  }
910  // then, propagate upward
911  for(unsigned int l=old_layer-1;l>=7;l--)
912  {
913  if(std::isnan(kftrack.GetX()) ||
914  std::isnan(kftrack.GetY()) ||
915  std::isnan(kftrack.GetZ())) continue;
916  if(Verbosity()>0) std::cout << "\nlayer " << l << ":" << std::endl;
917  // check to see whether layer is already occupied by at least one cluster
918  // choosing the first one first (clusters organized from outside in)
919  bool layer_filled = false;
920  TrkrDefs::cluskey next_ckey = 0;
921  for(size_t k=0; k<layers.size(); k++)
922  {
923  if(layer_filled) continue;
924  if(layers[k]==l)
925  {
926  layer_filled = true;
927  next_ckey = propagated_track[k];
928  }
929  }
930  // if layer is already occupied, reset track parameters to last cluster in layer
931  if(layer_filled)
932  {
933  if(Verbosity()>0) std::cout << "layer is filled" << std::endl;
934  auto ncglob = globalPositions.at(next_ckey);
935  double cx = ncglob(0);
936  double cy = ncglob(1);
937  double cz = ncglob(2);
938  double cphi = atan2(cy,cx);
939  double alpha = cphi-old_phi;
940  double tX = kftrack.GetX();
941  double tY = kftrack.GetY();
942  double tx = tX*cos(old_phi)-tY*sin(old_phi);
943  double ty = tX*sin(old_phi)+tY*cos(old_phi);
944  double tz = kftrack.GetZ();
945 // GPUTPCTrackParam::GPUTPCTrackFitParam fp;
946 // kftrack.CalculateFitParameters(fp);
947  kftrack.Rotate(alpha/2.,kfline,10.);
948  double newX = cx*cos(cphi)+cy*sin(cphi);
949  kftrack.TransportToXWithMaterial((tX+newX)/2.,kfline,fp,_Bzconst*get_Bz(tx,ty,tz),10.);
950  kftrack.Rotate(alpha/2.,kfline,10.);
951  kftrack.TransportToXWithMaterial(cx*cos(cphi)+cy*sin(cphi),kfline,fp,_Bzconst*get_Bz(tx,ty,tz),10.);
952  if(std::isnan(kftrack.GetX()) ||
953  std::isnan(kftrack.GetY()) ||
954  std::isnan(kftrack.GetZ())) continue;
955  if(Verbosity()>0) std::cout << "transported to " << radii[l-7] << "\n";
956  if(Verbosity()>0) std::cout << "track position: (" << kftrack.GetX()*cos(cphi)-kftrack.GetY()*sin(cphi) << ", " << kftrack.GetX()*sin(cphi)+kftrack.GetY()*cos(cphi) << ", " << kftrack.GetZ() << ")" << std::endl;
957  if(Verbosity()>0) std::cout << "cluster position: (" << cx << ", " << cy << ", " << cz << ")" << std::endl;
958 // kftrack.SetX(cx*cos(cphi)+cy*sin(cphi));
959 // kftrack.SetY(-cx*sin(cphi)+cy*cos(cphi));
960 // kftrack.SetZ(cz);
961 // propagated_track.push_back(next_ckey);
962  old_phi = cphi;
963  }
964  // if layer is not occupied, search for the nearest available cluster to projected track position
965  else
966  {
967  if(Verbosity()>0) std::cout << "layer not filled" << std::endl;
968  double tX = kftrack.GetX();
969  double tY = kftrack.GetY();
970  double tx = tX*cos(old_phi)-tY*sin(old_phi);
971  double ty = tX*sin(old_phi)+tY*cos(old_phi);
972  double tz = kftrack.GetZ();
973 // GPUTPCTrackParam::GPUTPCTrackFitParam fp;
974 // kftrack.CalculateFitParameters(fp);
975  double newX = radii[l-7];
976  double alpha = atan2(ty,tx)-old_phi;
977  kftrack.Rotate(alpha/2.,kfline,10.);
978  kftrack.TransportToXWithMaterial((tX+newX)/2.,kfline,fp,_Bzconst*get_Bz(tx,ty,tz),10.);
979  kftrack.Rotate(alpha/2.,kfline,10.);
980  kftrack.TransportToXWithMaterial(radii[l-7],kfline,fp,_Bzconst*get_Bz(tx,ty,tz),10.);
981  if(std::isnan(kftrack.GetX()) ||
982  std::isnan(kftrack.GetY()) ||
983  std::isnan(kftrack.GetZ())) continue;
984  tX = kftrack.GetX();
985  tY = kftrack.GetY();
986  double tYerr = sqrt(kftrack.GetCov(0));
987  double tzerr = sqrt(kftrack.GetCov(5));
988  tx = tX*cos(old_phi)-tY*sin(old_phi);
989  ty = tX*sin(old_phi)+tY*cos(old_phi);
990  tz = kftrack.GetZ();
991  double query_pt[3] = {tx, ty, tz};
992 
993  // Now look for the nearest cluster to this projection point (tx,ty,tz), which is at the nominal layer radius
994  if(m_dcc)
995  {
996  // The distortion corrected cluster positions in globalPos are not at the layer radius
997  // We want to project to the radius appropriate for the globalPos values
998  // Get the distortion correction for the projection point, and calculate the radial increment
999  double proj_radius = sqrt(tx*tx+ty*ty);
1000  if(proj_radius > 78.0 || abs(tz) > 105.5) continue; // projection is bad, no cluster will be found
1001 
1002  Acts::Vector3 proj_pt(tx,ty,tz);
1003  if(Verbosity() > 2)
1004  std::cout << " call distortion correction for layer " << l << " tx " << tx << " ty " << ty << " tz " << tz << " radius " << proj_radius << std::endl;
1005  proj_pt = m_distortionCorrection.get_corrected_position( proj_pt, m_dcc );
1006  // this point is meaningless, except that it givs us an estimate of the corrected radius of a point measured in this layer
1007  double radius = sqrt(proj_pt[0]*proj_pt[0] + proj_pt[1]*proj_pt[1]);
1008 
1009  // now project the track to that radius
1010  if(Verbosity() > 2)
1011  std::cout << " call transport again for layer " << l << " x " << proj_pt[0] << " y " << proj_pt[1] << " z " << proj_pt[2]
1012  << " radius " << radius << std::endl;
1013  double newX = radius;
1014  double alpha = atan2(ty,tx)-old_phi;
1015  kftrack.Rotate(alpha/2.,kfline,10.);
1016  kftrack.TransportToXWithMaterial((tX+newX)/2.,kfline,fp,_Bzconst*get_Bz(tx,ty,tz),10.);
1017  kftrack.Rotate(alpha/2.,kfline,10.);
1018  kftrack.TransportToXWithMaterial(radius,kfline,fp,_Bzconst*get_Bz(tx,ty,tz),10.);
1019  if(std::isnan(kftrack.GetX()) ||
1020  std::isnan(kftrack.GetY()) ||
1021  std::isnan(kftrack.GetZ())) continue;
1022  tX = kftrack.GetX();
1023  tY = kftrack.GetY();
1024  tYerr = sqrt(kftrack.GetCov(0));
1025  tzerr = sqrt(kftrack.GetCov(5));
1026  tx = tX*cos(old_phi)-tY*sin(old_phi);
1027  ty = tX*sin(old_phi)+tY*cos(old_phi);
1028  tz = kftrack.GetZ();
1029  query_pt[0] = tx;
1030  query_pt[1] = ty;
1031  query_pt[2] = tz;
1032  }
1033 
1034  double txerr = fabs(tYerr*sin(old_phi));
1035  double tyerr = fabs(tYerr*cos(old_phi));
1036  if(Verbosity()>0) std::cout << "transported to " << radii[l-7] << "\n";
1037  if(Verbosity()>0) std::cout << "track position: (" << kftrack.GetX()*cos(old_phi)-kftrack.GetY()*sin(old_phi) << ", " << kftrack.GetX()*sin(old_phi)+kftrack.GetY()*cos(old_phi) << ", " << kftrack.GetZ() << ")" << std::endl;
1038  if(Verbosity()>0) std::cout << "track position errors: (" << txerr << ", " << tyerr << ", " << tzerr << ")" << std::endl;
1039 
1040  std::vector<long unsigned int> index_out(1);
1041  std::vector<double> distance_out(1);
1042  int n_results = _kdtrees[l]->knnSearch(&query_pt[0],1,&index_out[0],&distance_out[0]);
1043  if(Verbosity()>0) std::cout << "index_out: " << index_out[0] << std::endl;
1044  if(Verbosity()>0) std::cout << "squared_distance_out: " << distance_out[0] << std::endl;
1045  if(Verbosity()>0) std::cout << "solid_angle_dist: " << atan2(sqrt(distance_out[0]),radii[l-7]) << std::endl;
1046  if(n_results==0) continue;
1047  std::vector<double> point = _ptclouds[l]->pts[index_out[0]];
1048  TrkrDefs::cluskey closest_ckey = (*((int64_t*)&point[3]));
1049  TrkrCluster* cc = _cluster_map->findCluster(closest_ckey);
1050  auto ccglob2 = globalPositions.at(closest_ckey);
1051  double ccX = ccglob2(0);
1052  double ccY = ccglob2(1);
1053  double ccZ = ccglob2(2);
1054 
1055  /*
1056  // alternatively:
1057  if(m_dcc)
1058  {
1059  // The distortion corrected cluster positions in globalPos are not at the layer radius
1060  // We want to project to the radius appropriate for the globalPos values
1061  // Get the radius from the global position of the nearest cluster found above
1062  Acts::Vector3 proj_pt(ccX, ccY, ccZ);
1063  double radius = sqrt(proj_pt[0]*proj_pt[0] + proj_pt[1]*proj_pt[1]);
1064 
1065  // now project the track to that radius
1066  if(Verbosity() > 2)
1067  std::cout << " call transport again for layer " << l << " x " << proj_pt[0] << " y " << proj_pt[1] << " z " << proj_pt[2]
1068  << " radius " << radius << std::endl;
1069  kftrack.TransportToX(radius,kfline,_Bzconst*get_Bz(ccX,ccY,ccZ),10.);
1070  if(std::isnan(kftrack.GetX()) ||
1071  std::isnan(kftrack.GetY()) ||
1072  std::isnan(kftrack.GetZ())) continue;
1073  tX = kftrack.GetX();
1074  tY = kftrack.GetY();
1075  tYerr = sqrt(kftrack.GetCov(0));
1076  tzerr = sqrt(kftrack.GetCov(5));
1077  tx = tX*cos(old_phi)-tY*sin(old_phi);
1078  ty = tX*sin(old_phi)+tY*cos(old_phi);
1079  tz = kftrack.GetZ();
1080  query_pt[0] = tx;
1081  query_pt[1] = ty;
1082  query_pt[2] = tz;
1083 
1084  n_results = _kdtrees[l]->knnSearch(&query_pt[0],1,&index_out[0],&distance_out[0]);
1085  if(Verbosity()>0) std::cout << "index_out: " << index_out[0] << std::endl;
1086  if(Verbosity()>0) std::cout << "squared_distance_out: " << distance_out[0] << std::endl;
1087  if(Verbosity()>0) std::cout << "solid_angle_dist: " << atan2(sqrt(distance_out[0]),radii[l-7]) << std::endl;
1088  if(n_results==0) continue;
1089  point = _ptclouds[l]->pts[index_out[0]];
1090  closest_ckey = (*((int64_t*)&point[3]));
1091  cc = _cluster_map->findCluster(closest_ckey);
1092  ccglob2 = globalPositions.at(closest_ckey);
1093  ccX = ccglob2(0);
1094  ccY = ccglob2(1);
1095  ccZ = ccglob2(2);
1096  }
1097  */
1098 
1099  double cxerr = sqrt(fitter->getClusterError(cc,closest_ckey,ccglob2,0,0));
1100  double cyerr = sqrt(fitter->getClusterError(cc,closest_ckey,ccglob2,1,1));
1101  double czerr = sqrt(fitter->getClusterError(cc,closest_ckey,ccglob2,2,2));
1102  if(Verbosity()>0) std::cout << "cluster position: (" << ccX << ", " << ccY << ", " << ccZ << ")" << std::endl;
1103  double ccphi = atan2(ccY,ccX);
1104  if(Verbosity()>0) std::cout << "cluster position errors: (" << cxerr << ", " << cyerr << ", " << czerr << ")" << std::endl;
1105  if(Verbosity()>0) std::cout << "cluster X: " << ccX*cos(ccphi)+ccY*sin(ccphi) << std::endl;
1106  double alpha2 = ccphi-old_phi;
1107  if(fabs(tx-ccX)<_max_dist*sqrt(txerr*txerr+cxerr*cxerr) &&
1108  fabs(ty-ccY)<_max_dist*sqrt(tyerr*tyerr+cyerr*cyerr) &&
1109  fabs(tz-ccZ)<_max_dist*sqrt(tzerr*tzerr+czerr*czerr))
1110  {
1111  propagated_track.push_back(closest_ckey);
1112  layers.push_back(TrkrDefs::getLayer(closest_ckey));
1113 /* TrkrCluster* cc = _cluster_map->findCluster(closest_ckey);
1114  double ccX = cc->getX();
1115  std::cout << "cluster X: " << ccX << std::endl;
1116  double ccY = cc->getY();
1117  double ccx = ccX*cos(old_phi)-ccY*sin(old_phi);
1118  double ccy = ccX*sin(old_phi)+ccY*cos(old_phi);
1119  std::cout << "cluster position: (" << ccx << ", " << ccy << ", " << cc->getZ() << ")" << std::endl;
1120  double ccphi = atan2(ccy,ccx);
1121  double alpha = ccphi-old_phi;
1122 */
1123  kftrack.Rotate(alpha2,kfline,10.);
1124  double ccaY = -ccX*sin(ccphi)+ccY*cos(ccphi);
1125  double ccerrY = fitter->getClusterError(cc,closest_ckey,ccglob2,0,0)*sin(ccphi)*sin(ccphi)+fitter->getClusterError(cc,closest_ckey,ccglob2,1,0)*sin(ccphi)*cos(ccphi)+fitter->getClusterError(cc,closest_ckey,ccglob2,1,1)*cos(ccphi)*cos(ccphi);
1126  double ccerrZ = fitter->getClusterError(cc,closest_ckey,ccglob2,2,2);
1127  kftrack.Filter(ccaY,ccZ,ccerrY,ccerrZ,_max_sin_phi);
1128 // kftrack.SetX(ccX*cos(ccphi)+ccY*sin(ccphi));
1129 // kftrack.SetY(-ccX*sin(ccphi)+ccY*cos(ccphi));
1130 // kftrack.SetZ(cc->getZ());
1131  if(Verbosity()>0) std::cout << "added cluster" << std::endl;
1132  old_phi = ccphi;
1133  }
1134  }
1135  old_layer = l;
1136  }
1137  std::sort(propagated_track.begin(),propagated_track.end(),
1139  {return (TrkrDefs::getLayer(a)<TrkrDefs::getLayer(b));});
1140  return propagated_track;
1141 }
1142 
1143 std::vector<keylist> PHSimpleKFProp::RemoveBadClusters(const std::vector<keylist>& chains, const PositionMap& globalPositions) const
1144 {
1145  if(Verbosity()>0) std::cout << "removing bad clusters" << std::endl;
1146  std::vector<keylist> clean_chains;
1147  for(const keylist& chain : chains)
1148  {
1149  if(chain.size()<3) continue;
1150  keylist clean_chain;
1151 
1152  std::vector<std::pair<double,double>> xy_pts;
1153  std::vector<std::pair<double,double>> rz_pts;
1154  for(const TrkrDefs::cluskey& ckey : chain)
1155  {
1156  auto global = globalPositions.at(ckey);
1157  xy_pts.push_back(std::make_pair(global(0),global(1)));
1158  float r = sqrt(global(0)*global(0) + global(1)*global(1));
1159  rz_pts.push_back(std::make_pair(r,global(2)));
1160  }
1161  if(Verbosity()>0) std::cout << "chain size: " << chain.size() << std::endl;
1162 
1163  //fit a circle through x,y coordinates and calculate residuals
1164  const auto [R, X0, Y0] = TrackFitUtils::circle_fit_by_taubin( xy_pts );
1165  const std::vector<double> xy_resid = TrackFitUtils::getCircleClusterResiduals(xy_pts,R,X0,Y0);
1166 
1167  // fit a line through r,z coordinates and calculate residuals
1168  const auto [A, B] = TrackFitUtils::line_fit( rz_pts );
1169  const std::vector<double> rz_resid = TrackFitUtils::getLineClusterResiduals(rz_pts,A,B);
1170 
1171  for(size_t i=0;i<chain.size();i++)
1172  {
1173  //if(xy_resid[i]>_xy_outlier_threshold) continue;
1174  clean_chain.push_back(chain[i]);
1175  }
1176  clean_chains.push_back(clean_chain);
1177  if(Verbosity()>0) std::cout << "pushed clean chain with " << clean_chain.size() << " clusters" << std::endl;
1178  }
1179  return clean_chains;
1180 }
1181 
1182 
1183 
1184 void PHSimpleKFProp::publishSeeds(std::vector<TrackSeed_v1>& seeds, PositionMap& /*positions*/)
1185 {
1186  for(auto& seed: seeds )
1187  {
1189  int q = seed.get_charge();
1190  seed.circleFitByTaubin(_cluster_map, _tgeometry, 7, 55);
1191  seed.lineFit(_cluster_map,_tgeometry, 7, 55);
1192 
1193  seed.set_qOverR(fabs(seed.get_qOverR()) * q);
1194  _track_map->insert(&seed);
1195  }
1196 }
1197 
1198 void PHSimpleKFProp::publishSeeds(const std::vector<TrackSeed_v1>& seeds)
1199 {
1200  for( const auto& seed:seeds )
1201  { _track_map->insert(&seed); }
1202 }