41 #include <boost/geometry.hpp>
42 #include <boost/geometry/geometries/box.hpp>
43 #include <boost/geometry/geometries/point.hpp>
44 #include <boost/geometry/index/rtree.hpp>
45 #include <boost/geometry/policies/compare.hpp>
48 #include <Eigen/Dense>
57 #include <unordered_set>
63 #define LogDebug(exp) if(Verbosity()>0) std::cout << "DEBUG: " << __FILE__ << ": " << __LINE__ << ": " << exp
65 #define LogDebug(exp) (void)0
68 #define LogError(exp) if(Verbosity()>0) std::cout << "ERROR: " << __FILE__ << ": " << __LINE__ << ": " << exp
69 #define LogWarning(exp) if(Verbosity()>0) std::cout << "WARNING: " << __FILE__ << ": " << __LINE__ << ": " << exp
75 typedef bg::model::point<float, 3, bg::cs::cartesian>
point;
76 typedef bg::model::box<point>
box;
77 typedef std::pair<point, TrkrDefs::cluskey>
pointKey;
80 typedef std::vector<TrkrDefs::cluskey>
keylist;
87 template<
typename T,
size_t N>
88 struct hash<std::array<T,N>>
99 h = h * 31 + hasher(a[i]);
104 template<
typename A,
typename B>
114 return (hashA(a.first)*31+hashB(a.second));
123 template<
class T>
inline constexpr
T square(
const T&
x ) {
return x*
x; }
128 double phi = std::atan2( position.y(), position.x() );
129 if( phi < 0 ) phi += 2.*
M_PI;
137 return std::log((norm+position.z())/(norm-position.z()))/2;
144 {
return std::make_pair(std::array<float,3>({p.first.get<0>(),p.first.get<1>(),p.first.get<2>()}),p.second); }
146 std::vector<coordKey> fromPointKey(
const std::vector<pointKey>& p)
148 std::vector<coordKey> output;
149 output.resize(p.size());
151 {
return fromPointKey(
point); } );
156 double breaking_angle(
double x1,
double y1,
double z1,
double x2,
double y2,
double z2)
158 double l1 = sqrt(x1*x1+y1*y1+z1*z1);
159 double l2 = sqrt(x2*x2+y2*y2+z2*z2);
160 double sx = (x1/l1+x2/l2);
161 double sy = (y1/l1+y2/l2);
162 double sz = (z1/l1+z2/l2);
163 double dx = (x1/l1-x2/l2);
164 double dy = (y1/l1-y2/l2);
165 double dz = (z1/l1-z2/l2);
166 return 2*atan2(sqrt(dx*dx+dy*dy+dz*dz),sqrt(sx*sx+sy*sy+sz*sz));
172 namespace bg = boost::geometry;
173 namespace bgi = boost::geometry::index;
176 const std::string &
name,
177 unsigned int start_layer,
178 unsigned int end_layer,
179 unsigned int min_nhits_per_cluster,
180 unsigned int min_clusters_per_track,
181 unsigned int nlayers_maps,
182 unsigned int nlayers_intt,
183 unsigned int nlayers_tpc,
184 float neighbor_phi_width,
185 float neighbor_eta_width,
187 float cosTheta_limit)
189 , _nlayers_maps(nlayers_maps)
190 , _nlayers_intt(nlayers_intt)
191 , _nlayers_tpc(nlayers_tpc)
192 , _start_layer(start_layer)
193 , _end_layer(end_layer)
194 , _min_nhits_per_cluster(min_nhits_per_cluster)
195 , _min_clusters_per_track(min_clusters_per_track)
196 , _neighbor_phi_width(neighbor_phi_width)
197 , _neighbor_eta_width(neighbor_eta_width)
198 , _max_sin_phi(maxSinPhi)
199 , _cosTheta_limit(cosTheta_limit)
205 tGeometry = findNode::getClass<ActsTrackingGeometry>(topNode,
"ActsTrackingGeometry");
208 std::cout <<
PHWHERE <<
"No acts tracking geometry, can't proceed" << std::endl;
212 surfMaps = findNode::getClass<ActsSurfaceMaps>(topNode,
"ActsSurfaceMaps");
215 std::cout <<
PHWHERE <<
"No acts surface maps, can't proceed" << std::endl;
235 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
237 double phimin_2pi =
phimin;
238 double phimax_2pi = phimax;
240 if (phimax > 2*
M_PI) phimax_2pi = phimax-2*
M_PI;
241 rtree.query(bgi::intersects(
box(
point(phimin_2pi, etamin, lmin),
point(phimax_2pi, etamax, lmax))), std::back_inserter(returned_values));
252 for (
int j = 0; j < 60; ++j) nlayer[j] = 0;
254 for (
auto hitsetitr = hitsetrange.first;
255 hitsetitr != hitsetrange.second;
258 for(
auto clusIter = range.first; clusIter != range.second; ++clusIter ){
263 if (layer < _start_layer || layer >=
_end_layer){
264 if(
Verbosity()>0) std::cout <<
"layer: " << layer << std::endl;
282 std::cout <<
"CaSeeder: Cluster: " << key << std::endl;
283 std::cout <<
" Global before: " << global_before[0] <<
" " << global_before[1] <<
" " << global_before[2] << std::endl;
284 std::cout <<
" Global after : " << globalpos_d[0] <<
" " << globalpos_d[1] <<
" " << globalpos_d[2] << std::endl;
287 const Acts::Vector3F globalpos = { (float) globalpos_d.x(), (float) globalpos_d.y(), (float) globalpos_d.z()};
288 cachedPositions.insert(std::make_pair(ckey, globalpos));
290 const double clus_phi = get_phi( globalpos );
291 const double clus_eta = get_eta( globalpos );
292 const double clus_l =
layer;
295 std::cout <<
"Found cluster " << ckey <<
" in layer " << layer << std::endl;
297 std::vector<pointKey> testduplicate;
298 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);
299 if (!testduplicate.empty())
306 _rtree.insert(std::make_pair(
point(clus_phi, clus_eta, clus_l), ckey));
310 if(
Verbosity()>1)
for (
int j = 0; j < 60; ++j) std::cout <<
"nhits in layer " << j <<
": " << nlayer[j] << std::endl;
311 if(
Verbosity()>0) std::cout <<
"fill time: " <<
t_fill->get_accumulated_time() / 1000. <<
" sec" << std::endl;
312 if(
Verbosity()>0) std::cout <<
"number of duplicates : " << n_dupli << std::endl;
313 return cachedPositions;
321 std::cerr <<
PHWHERE <<
"Cluster Iteration Map missing, aborting." << std::endl;
331 if(
Verbosity()>0) std::cout <<
"Initial RTree fill time: " <<
t_seed->get_accumulated_time() / 1000 <<
" s" << std::endl;
333 int numberofseeds = 0;
336 if(
Verbosity()>0) std::cout <<
"number of seeds " << numberofseeds << std::endl;
337 if(
Verbosity()>0) std::cout <<
"Kalman filtering time: " <<
t_seed->get_accumulated_time() / 1000 <<
" s" << std::endl;
346 std::vector<pointKey> allClusters;
347 std::vector<std::unordered_set<keylink>> belowLinks;
348 std::vector<std::unordered_set<keylink>> aboveLinks;
360 if(
Verbosity()>0) std::cout <<
"allClusters search time: " <<
t_seed->get_accumulated_time() / 1000 <<
" s" << std::endl;
361 LogDebug(
" number of clusters: " << allClusters.size() << std::endl);
364 std::pair<std::vector<std::unordered_set<keylink>>,std::vector<std::unordered_set<keylink>>> links =
CreateLinks(fromPointKey(allClusters), globalPositions);
365 std::vector<std::vector<keylink>> biLinks =
FindBiLinks(links.first,links.second);
366 std::vector<keylist> trackSeedKeyLists =
FollowBiLinks(biLinks,globalPositions);
367 std::vector<keylist> cleanSeedKeyLists =
RemoveBadClusters(trackSeedKeyLists, globalPositions);
368 std::vector<SvtxTrack_v2> seeds =
fitter->ALICEKalmanFilter(cleanSeedKeyLists,
true, globalPositions);
373 std::pair<std::vector<std::unordered_set<keylink>>,std::vector<std::unordered_set<keylink>>>
PHCASeeding::CreateLinks(
const std::vector<coordKey>& clusters,
const PositionMap& globalPositions,
int mode)
const
375 size_t nclusters = 0;
377 double cluster_find_time = 0;
378 double rtree_query_time = 0;
379 double transform_time = 0;
380 double compute_best_angle_time = 0;
381 double set_insert_time = 0;
383 std::vector<std::unordered_set<keylink>> belowLinks;
384 std::vector<std::unordered_set<keylink>> aboveLinks;
388 for (
auto StartCluster = clusters.begin(); StartCluster != clusters.end(); ++StartCluster)
392 double StartPhi = StartCluster->first[0];
393 double StartEta = StartCluster->first[1];
394 unsigned int StartLayer = StartCluster->first[2];
397 const auto& globalpos = globalPositions.at(StartCluster->second);
398 double StartX = globalpos(0);
399 double StartY = globalpos(1);
400 double StartZ = globalpos(2);
402 cluster_find_time +=
t_seed->elapsed();
404 LogDebug(
" starting cluster:" << std::endl);
405 LogDebug(
" eta: " << StartEta << std::endl);
406 LogDebug(
" phi: " << StartPhi << std::endl);
407 LogDebug(
" layer: " << StartLayer << std::endl);
409 std::vector<pointKey> ClustersAbove;
410 std::vector<pointKey> ClustersBelow;
414 (
double) StartLayer - 1.5,
417 (
double) StartLayer - 0.5,
422 (
double) StartLayer + 0.5,
425 (
double) StartLayer + 1.5,
428 rtree_query_time +=
t_seed->elapsed();
430 LogDebug(
" entries in below layer: " << ClustersBelow.size() << std::endl);
431 LogDebug(
" entries in above layer: " << ClustersAbove.size() << std::endl);
432 std::vector<std::array<double,3>> delta_below;
433 std::vector<std::array<double,3>> delta_above;
436 delta_below.resize(ClustersBelow.size());
437 delta_above.resize(ClustersAbove.size());
440 std::transform(ClustersBelow.begin(),ClustersBelow.end(),delta_below.begin(),
442 const auto& belowpos = globalPositions.at(BelowCandidate.second);
443 return std::array<double,3>{belowpos(0)-StartX,
445 belowpos(2)-StartZ};});
447 std::transform(ClustersAbove.begin(),ClustersAbove.end(),delta_above.begin(),
449 const auto& abovepos = globalPositions.at(AboveCandidate.second);
450 return std::array<double,3>{abovepos(0)-StartX,
452 abovepos(2)-StartZ};});
454 transform_time +=
t_seed->elapsed();
459 double maxCosPlaneAngle = -0.9;
461 coordKey bestBelowCluster = std::make_pair(std::array<float,3>({0.,0.,-1e9}),0);
462 coordKey bestAboveCluster = std::make_pair(std::array<float,3>({0.,0.,-1e9}),0);
463 for(
size_t iAbove = 0; iAbove<delta_above.size(); ++iAbove)
465 for(
size_t iBelow = 0; iBelow<delta_below.size(); ++iBelow)
470 double angle = breaking_angle(
471 delta_below[iBelow][0],
472 delta_below[iBelow][1],
473 delta_below[iBelow][2],
474 delta_above[iAbove][0],
475 delta_above[iAbove][1],
476 delta_above[iAbove][2]);
477 if(cos(angle) < maxCosPlaneAngle)
479 maxCosPlaneAngle = cos(angle);
481 bestBelowCluster = fromPointKey(ClustersBelow[iBelow]);
482 bestAboveCluster = fromPointKey(ClustersAbove[iAbove]);
487 if(mode == skip_layers::on)
493 std::vector<pointKey> clustersTwoLayersBelow;
497 (
double) StartLayer - 2.5,
500 (
double) StartLayer - 1.5,
501 clustersTwoLayersBelow);
502 std::vector<std::array<double,3>> delta_2below;
503 delta_2below.clear();
504 delta_2below.resize(clustersTwoLayersBelow.size());
505 std::transform(clustersTwoLayersBelow.begin(),clustersTwoLayersBelow.end(),delta_2below.begin(),
507 const auto& belowpos = globalPositions.at(BelowCandidate.second);
508 return std::array<double,3>{(belowpos(0))-StartX,
509 (belowpos(1))-StartY,
510 (belowpos(2))-StartZ};});
511 for(
size_t iAbove = 0; iAbove<delta_above.size(); ++iAbove)
513 for(
size_t iBelow = 0; iBelow<delta_2below.size(); ++iBelow)
515 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];
516 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]);
517 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]);
518 double cosPlaneAngle = dotProduct / (belowSqLength*aboveSqLength);
519 if(cosPlaneAngle < maxCosPlaneAngle)
521 maxCosPlaneAngle = cosPlaneAngle;
522 bestBelowCluster = fromPointKey(clustersTwoLayersBelow[iBelow]);
523 bestAboveCluster = fromPointKey(ClustersAbove[iAbove]);
530 std::vector<pointKey> clustersTwoLayersAbove;
534 (
double) StartLayer + 1.5,
537 (
double) StartLayer + 2.5,
538 clustersTwoLayersAbove);
539 std::vector<std::array<double,3>> delta_2above;
540 delta_2above.clear();
541 delta_2above.resize(clustersTwoLayersAbove.size());
542 std::transform(clustersTwoLayersAbove.begin(),clustersTwoLayersAbove.end(),delta_2above.begin(),
544 const auto& abovepos = globalPositions.at(AboveCandidate.second);
545 return std::array<double,3>{(abovepos(0))-StartX,
546 (abovepos(1))-StartY,
547 (abovepos(2))-StartZ};});
548 for(
size_t iAbove = 0; iAbove<delta_2above.size(); ++iAbove)
550 for(
size_t iBelow = 0; iBelow<delta_below.size(); ++iBelow)
552 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];
553 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]);
554 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]);
555 double cosPlaneAngle = dotProduct / (belowSqLength*aboveSqLength);
556 if(cosPlaneAngle < maxCosPlaneAngle)
558 maxCosPlaneAngle = cosPlaneAngle;
559 bestBelowCluster = fromPointKey(ClustersBelow[iBelow]);
560 bestAboveCluster = fromPointKey(clustersTwoLayersAbove[iAbove]);
568 compute_best_angle_time +=
t_seed->elapsed();
571 if(bestBelowCluster.second != 0) belowLinks[layer_index].insert(
keylink{{*StartCluster,bestBelowCluster}});
572 if(bestAboveCluster.second != 0) aboveLinks[layer_index].insert(
keylink{{*StartCluster,bestAboveCluster}});
574 set_insert_time +=
t_seed->elapsed();
576 LogDebug(
" max collinearity: " << maxCosPlaneAngle << std::endl);
581 std::cout <<
"triplet forming time: " <<
t_seed->get_accumulated_time() / 1000 <<
" s" << std::endl;
582 std::cout <<
"starting cluster setup: " << cluster_find_time / 1000 <<
" s" << std::endl;
583 std::cout <<
"RTree query: " << rtree_query_time /1000 <<
" s" << std::endl;
584 std::cout <<
"Transform: " << transform_time /1000 <<
" s" << std::endl;
585 std::cout <<
"Compute best triplet: " << compute_best_angle_time /1000 <<
" s" << std::endl;
586 std::cout <<
"Set insert: " << set_insert_time /1000 <<
" s" << std::endl;
590 return std::make_pair(belowLinks,aboveLinks);
593 std::vector<std::vector<keylink>>
PHCASeeding::FindBiLinks(
const std::vector<std::unordered_set<keylink>>& belowLinks,
const std::vector<std::unordered_set<keylink>>& aboveLinks)
const
596 std::vector<std::vector<keylink>> bidirectionalLinks;
600 for(
auto belowLink = belowLinks[
layer].begin(); belowLink != belowLinks[
layer].end(); ++belowLink)
602 if((*belowLink)[1].second==0)
continue;
604 keylink reversed = {(*belowLink)[1],(*belowLink)[0]};
605 auto sameAboveLinkExists = aboveLinks[end_layer_index].find(reversed);
606 if(sameAboveLinkExists != aboveLinks[end_layer_index].end())
608 bidirectionalLinks[
layer].push_back((*belowLink));
613 if(
Verbosity()>0) std::cout <<
"bidirectional link forming time: " <<
t_seed->get_accumulated_time() / 1000 <<
" s" << std::endl;
616 return bidirectionalLinks;
623 std::vector<keylist> trackSeedKeyLists;
628 for(
auto startCand = bidirectionalLinks[
layer].begin(); startCand != bidirectionalLinks[
layer].end(); ++startCand)
630 bool has_above_link =
false;
631 unsigned int imax = 1;
632 if(
layer==_nlayers_tpc-2) imax = 1;
633 for(
unsigned int i=1;i<=
imax;i++)
635 has_above_link = has_above_link || std::any_of(bidirectionalLinks[
layer+i].begin(),bidirectionalLinks[
layer+i].end(),[&](
keylink k){
return (*startCand)[0]==k[1];});
644 trackSeedKeyLists.push_back({(*startCand)[0].second,(*startCand)[1].second});
649 if(
Verbosity()>0) std::cout <<
"starting cluster finding time: " <<
t_seed->get_accumulated_time() / 1000 <<
" s" << std::endl;
652 for(
auto trackKeyChain = trackSeedKeyLists.begin(); trackKeyChain != trackSeedKeyLists.end(); ++trackKeyChain)
654 bool reached_end =
false;
659 bool no_next_link =
true;
660 for(
auto testlink = bidirectionalLinks[trackHead_layer].begin(); testlink != bidirectionalLinks[trackHead_layer].end(); ++testlink)
662 if((*testlink)[0].second==trackHead)
664 trackKeyChain->push_back((*testlink)[1].
second);
665 no_next_link =
false;
668 if(no_next_link) reached_end =
true;
672 if(
Verbosity()>0) std::cout <<
"keychain assembly time: " <<
t_seed->get_accumulated_time() / 1000 <<
" s" << std::endl;
674 LogDebug(
" track key chains assembled: " << trackSeedKeyLists.size() << std::endl);
675 LogDebug(
" track key chain lengths: " << std::endl);
676 for(
auto trackKeyChain = trackSeedKeyLists.begin(); trackKeyChain != trackSeedKeyLists.end(); ++trackKeyChain)
678 LogDebug(
" " << trackKeyChain->size() << std::endl);
681 LogDebug(
" track key associations:" << std::endl);
682 for(
size_t i=0;i<trackSeedKeyLists.size();++i)
684 LogDebug(
" seed " << i <<
":" << std::endl);
686 double lasteta = -100;
687 double lastphi = -100;
688 for(
size_t j=0;j<trackSeedKeyLists[i].size();++j)
690 const auto& globalpos = globalPositions.at(trackSeedKeyLists[i][j]);
691 const double clus_phi = get_phi( globalpos );
692 const double clus_eta = get_eta( globalpos );
693 const double etajump = clus_eta-lasteta;
694 const double phijump = clus_phi-lastphi;
698 if((fabs(etajump)>0.1 && lasteta!=-100) || (fabs(phijump)>1 && lastphi!=-100))
700 LogDebug(
" Eta or Phi jump too large! " << std::endl);
703 LogDebug(
" (eta,phi,layer) = (" << clus_eta <<
"," << clus_phi <<
"," << lay <<
") " <<
704 " (x,y,z) = (" << globalpos(0) <<
"," << globalpos(1) <<
"," << globalpos(2) <<
")" << std::endl);
709 std::cout <<
" eta, phi, layer = (" << clus_eta <<
"," << clus_phi <<
"," << lay <<
") " <<
710 " (x,y,z) = (" << globalpos(0) <<
"," << globalpos(1) <<
"," << globalpos(2) <<
")" << std::endl;
716 LogDebug(
" Total large jumps: " << jumpcount << std::endl);
718 if(
Verbosity()>0) std::cout <<
"eta-phi sanity check time: " <<
t_seed->get_accumulated_time() / 1000 <<
" s" << std::endl;
720 return trackSeedKeyLists;
725 if(
Verbosity()>0) std::cout <<
"removing bad clusters" << std::endl;
726 std::vector<keylist> clean_chains;
728 for(
const auto& chain : chains)
730 if(chain.size()<3)
continue;
733 std::vector<std::pair<double,double>> xy_pts;
738 const auto &global = globalPositions.at(ckey);
739 double x = global(0);
740 double y = global(1);
741 xy_pts.push_back(std::make_pair(x,y));
745 if(
Verbosity()>0) std::cout <<
"chain size: " << chain.size() << std::endl;
754 fitter->CircleFitByTaubin(xy_pts,R,X0,Y0);
762 if( std::isnan( R ) )
continue;
765 const std::vector<double> xy_resid =
fitter->GetCircleClusterResiduals(xy_pts,R,X0,Y0);
766 for(
size_t i=0;i<chain.size();i++)
769 clean_chain.push_back(chain[i]);
772 clean_chains.push_back(clean_chain);
773 if(
Verbosity()>0) std::cout <<
"pushed clean chain with " << clean_chain.size() <<
" clusters" << std::endl;
781 for(
const auto&
seed:seeds )
787 if(
Verbosity()>0) std::cout <<
"Called Setup" << std::endl;
788 if(
Verbosity()>0) std::cout <<
"topNode:" << topNode << std::endl;
797 m_dcc = findNode::getClass<TpcDistortionCorrectionContainer>(topNode,
"TpcDistortionCorrectionContainer");
799 { std::cout <<
"PHCASeeding::Setup - found TPC distortion correction container" << std::endl; }
801 t_fill = std::make_unique<PHTimer>(
"t_fill");
802 t_seed = std::make_unique<PHTimer>(
"t_seed");
816 if(
Verbosity()>0) std::cout <<
"Called End " << std::endl;