31 #include <unordered_map> 111 using BestNodeMap = std::unordered_map<const reco::ClusterHit3D*,BestNodeTuple>;
180 TVector3 uWireDir = uWireGeo->
Direction();
191 TVector3 vWireDir = vWireGeo->
Direction();
240 theClockBuildClusters.
stop();
248 mf::LogDebug(
"MinSpanTreeAlg") <<
">>>>> Cluster3DHits done, found " << clusterParametersList.size() <<
" clusters" <<
std::endl;
259 if (hitPairList.empty())
return;
268 size_t clusterIdx(0);
299 curEdgeItr = curEdgeList.erase(curEdgeItr);
304 curCluster->push_back(lastAddedHit);
308 float bestDistance(1.5);
316 for(
auto& pair : CandPairList)
320 double edgeWeight = lastAddedHit->
getHitChiSquare() * pair.second->getHitChiSquare();
322 curEdgeList.push_back(
reco::EdgeTuple(lastAddedHit,pair.second,edgeWeight));
327 if (curEdgeList.empty())
329 std::cout <<
"-----------------------------------------------------------------------------------------" <<
std::endl;
330 std::cout <<
"**> Cluster idx: " << clusterIdx++ <<
" has " << curCluster->size() <<
" hits" <<
std::endl;
336 if (freeHitItr == hitPairList.end())
break;
338 std::cout <<
"##################################################################>Processing another cluster" <<
std::endl;
343 curClusterItr = --clusterParametersList.end();
345 curEdgeMap = &(*curClusterItr).getHit3DToEdgeMap();
346 curCluster = &(*curClusterItr).getHitPairListPtr();
347 lastAddedHit = &(*freeHitItr++);
353 curEdgeList.sort([](
const auto&
left,
const auto&
right){
return std::get<2>(
left) < std::get<2>(
right);});
358 (*curEdgeMap)[std::get<0>(curEdge)].
push_back(curEdge);
359 (*curEdgeMap)[std::get<1>(curEdge)].
push_back(
reco::EdgeTuple(std::get<1>(curEdge),std::get<0>(curEdge),std::get<2>(curEdge)));
362 lastAddedHit = std::get<1>(curEdge);
368 theClockDBScan.
stop();
379 float bestQuality(0.);
380 float aveNumEdges(0.);
381 size_t maxNumEdges(0);
382 size_t nIsolatedHits(0);
395 for(
const auto&
hit : hitPairList)
403 tempList.push_front(std::get<0>(curEdgeMap[
hit].front()));
405 if (quality > bestQuality)
407 longestCluster = tempList;
408 bestQuality = quality;
418 aveNumEdges /=
float(hitPairList.size());
419 std::cout <<
"----> # isolated hits: " << nIsolatedHits <<
", longest branch: " << longestCluster.size() <<
", cluster size: " << hitPairList.size() <<
", ave # edges: " << aveNumEdges <<
", max: " << maxNumEdges <<
std::endl;
421 if (!longestCluster.empty())
423 hitPairList = longestCluster;
424 for(
const auto&
hit : hitPairList)
426 for(
const auto& edge : curEdgeMap[
hit]) bestEdgeList.emplace_back(edge);
429 std::cout <<
" ====> new cluster size: " << hitPairList.size() <<
std::endl;
434 theClockPathFinding.
stop();
474 for(
const auto& hit3D : curCluster)
477 if (!curEdgeMap[hit3D].
empty() && curEdgeMap[hit3D].
size() == 1)
479 Eigen::Vector3f pcaToHitVec(hit3D->getPosition()[0] - pcaCenter(0),
480 hit3D->getPosition()[1] - pcaCenter(1),
481 hit3D->getPosition()[2] - pcaCenter(2));
485 isolatedPointList.emplace_back(pcaToHit(2),pcaToHit(1),hit3D);
489 std::cout <<
"************* Finding best path with A* in cluster *****************" <<
std::endl;
490 std::cout <<
"**> There are " << curCluster.size() <<
" hits, " << isolatedPointList.size() <<
" isolated hits, the alpha parameter is " << alpha <<
std::endl;
491 std::cout <<
"**> PCA len: " << pcaLen <<
", wid: " << pcaWidth <<
", height: " << pcaHeight <<
", ratio: " << pcaHeight/pcaWidth <<
std::endl;
494 if (isolatedPointList.size() > 1)
497 isolatedPointList.sort([](
const auto&
left,
const auto&
right){
return (
std::abs(std::get<0>(
left) - std::get<0>(
right)) > std::numeric_limits<float>::epsilon()) ? std::get<0>(
left) < std::get<0>(
right) : std::get<1>(
left) < std::get<1>(
right);});
503 std::cout <<
"**> Sorted " << isolatedPointList.size() <<
" hits, longest distance: " <<
DistanceBetweenNodes(startHit,stopHit) <<
std::endl;
510 LeastCostPath(curEdgeMap[startHit].front(),stopHit,clusterParams,cost);
519 std::cout <<
"++++++>>> PCA failure! # hits: " << curCluster.size() <<
std::endl;
525 theClockPathFinding.
stop();
558 while(!openList.empty())
564 if (openList.size() > 1)
565 currentNodeItr = std::min_element(openList.begin(),openList.end(),[bestNodeMap](
const auto& next,
const auto& best){
return std::get<2>(bestNodeMap.at(next)) < std::get<2>(bestNodeMap.at(best));});
571 if (currentNode == goalNode)
582 openList.erase(currentNodeItr);
586 const BestNodeTuple& currentNodeTuple = bestNodeMap.at(currentNode);
587 float currentNodeScore = std::get<1>(currentNodeTuple);
592 for(
const auto& curEdge : curEdgeList)
598 float tentative_gScore = currentNodeScore + std::get<2>(curEdge);
603 if (candNodeItr == bestNodeMap.end())
605 openList.push_back(candHit3D);
607 else if (tentative_gScore > std::get<1>(candNodeItr->second))
continue;
612 bestNodeMap[candHit3D] =
BestNodeTuple(currentNode,tentative_gScore, tentative_gScore + guessToTarget);
625 while(std::get<0>(bestNodeMap.at(goalNode)) != goalNode)
630 pathNodeList.push_front(goalNode);
631 bestEdgeList.push_front(bestEdge);
636 pathNodeList.push_front(goalNode);
644 float& showMeTheMoney)
const 653 if (edgeListItr != curEdgeMap.end() && !edgeListItr->second.empty())
658 for(
const auto& edge : edgeListItr->second)
661 if (std::get<1>(edge) == std::get<0>(curEdge))
continue;
664 if (std::get<1>(edge) == goalNode)
666 bestNodeList.push_back(goalNode);
667 bestEdgeList.push_back(edge);
668 showMeTheMoney = std::get<2>(edge);
673 float currentCost(0.);
679 showMeTheMoney = std::get<2>(edge) + currentCost;
696 const Eigen::Vector3f& node1Pos = node1->
getPosition();
697 const Eigen::Vector3f& node2Pos = node2->
getPosition();
698 float deltaNode[] = {node1Pos[0]-node2Pos[0], node1Pos[1]-node2Pos[1], node1Pos[2]-node2Pos[2]};
701 return std::sqrt(deltaNode[0]*deltaNode[0]+deltaNode[1]*deltaNode[1]+deltaNode[2]*deltaNode[2]);
724 float& bestTreeQuality)
const 727 float bestQuality(0.);
728 float curEdgeWeight =
std::max(0.3,std::get<2>(curEdge));
729 float curEdgeProj(1./curEdgeWeight);
733 if (edgeListItr != hitToEdgeMap.end())
736 const Eigen::Vector3f& firstHitPos = std::get<0>(curEdge)->getPosition();
737 const Eigen::Vector3f& secondHitPos = std::get<1>(curEdge)->getPosition();
738 float curEdgeVec[] = {secondHitPos[0]-firstHitPos[0],secondHitPos[1]-firstHitPos[1],secondHitPos[2]-firstHitPos[2]};
739 float curEdgeMag = std::sqrt(curEdgeVec[0]*curEdgeVec[0]+curEdgeVec[1]*curEdgeVec[1]+curEdgeVec[2]*curEdgeVec[2]);
741 curEdgeMag =
std::max(
float(0.1),curEdgeMag);
743 for(
const auto& edge : edgeListItr->second)
746 if (std::get<1>(edge) == std::get<0>(curEdge))
continue;
752 if (quality > bestQuality)
754 hitPairListPtr = tempList;
755 bestQuality = quality;
756 curEdgeProj = 1./curEdgeMag;
761 hitPairListPtr.push_front(std::get<1>(curEdge));
763 bestTreeQuality += bestQuality + curEdgeProj;
765 return hitPairListPtr;
775 size_t nStartedWith(hitPairVector.size());
776 size_t nRejectedHits(0);
781 for(
const auto& hit3D : hitPairVector)
784 size_t n2DHitsIn3DHit(0);
785 size_t nThisClusterOnly(0);
786 size_t nOtherCluster(0);
789 const std::set<const reco::ClusterHit3D*>* otherClusterHits = 0;
791 for(
const auto& hit2D : hit3D->getHits())
793 if (!hit2D)
continue;
797 if (hit2DToClusterMap[hit2D].
size() < 2) nThisClusterOnly = hit2DToClusterMap[hit2D][&clusterParams].
size();
800 for(
const auto& clusterHitMap : hit2DToClusterMap[hit2D])
802 if (clusterHitMap.first == &clusterParams)
continue;
804 if (clusterHitMap.second.size() > nOtherCluster)
806 nOtherCluster = clusterHitMap.second.size();
808 otherClusterHits = &clusterHitMap.second;
814 if (n2DHitsIn3DHit < 3 && nThisClusterOnly > 1 && nOtherCluster > 0)
816 bool skip3DHit(
false);
818 for(
const auto& otherHit3D : *otherClusterHits)
820 size_t nOther2DHits(0);
822 for(
const auto& otherHit2D : otherHit3D->getHits())
824 if (!otherHit2D)
continue;
829 if (nOther2DHits > 2)
837 if (skip3DHit)
continue;
841 goodHits.emplace_back(hit3D);
844 std::cout <<
"###>> Input " << nStartedWith <<
" hits, rejected: " << nRejectedHits <<
std::endl;
846 hitPairVector.resize(goodHits.size());
847 std::copy(goodHits.begin(),goodHits.end(),hitPairVector.begin());
857 return (*left).getHitPairListPtr().size() > (*right).getHitPairListPtr().size();
874 return left->
getHits()[m_plane[0]]->getHit()->PeakTime() < right->
getHits()[m_plane[0]]->getHit()->PeakTime();
883 return left->
getHits()[m_plane[1]]->getHit()->PeakTime() < right->
getHits()[m_plane[1]]->getHit()->PeakTime();
906 if (curCluster.size() > 2)
916 std::vector<size_t> closestPlane = {0, 0, 0 };
917 std::vector<float> bestAngle = {0.,0.,0.};
919 for(
size_t plane = 0; plane < 3; plane++)
921 const std::vector<float>& wireDir =
m_wireDir[plane];
923 float dotProd = std::fabs(pcaAxis[0]*wireDir[0] + pcaAxis[1]*wireDir[1] + pcaAxis[2]*wireDir[2]);
925 if (dotProd > bestAngle[0])
927 bestAngle[2] = bestAngle[1];
928 closestPlane[2] = closestPlane[1];
929 bestAngle[1] = bestAngle[0];
930 closestPlane[1] = closestPlane[0];
931 closestPlane[0] = plane;
932 bestAngle[0] = dotProd;
934 else if (dotProd > bestAngle[1])
936 bestAngle[2] = bestAngle[1];
937 closestPlane[2] = closestPlane[1];
938 closestPlane[1] = plane;
939 bestAngle[1] = dotProd;
943 closestPlane[2] = plane;
944 bestAngle[2] = dotProd;
955 std::cout <<
"********************************************************************************************" <<
std::endl;
956 std::cout <<
"**>>>>> longest axis: " << closestPlane[0] <<
", best angle: " << bestAngle[0] <<
std::endl;
957 std::cout <<
"**>>>>> second axis: " << closestPlane[1] <<
", best angle: " << bestAngle[1] <<
std::endl;
963 size_t bestPlane = closestPlane[0];
967 while(firstHitItr != localHitList.end())
972 while(lastHitItr != localHitList.end())
975 if (currentHit->
getWireIDs()[bestPlane] != (*lastHitItr)->getWireIDs()[bestPlane])
break;
978 if (currentHit->
getHits()[bestPlane] && (*lastHitItr)->getHits()[bestPlane] && currentHit->
getHits()[bestPlane] != (*lastHitItr)->getHits()[bestPlane])
break;
981 if ((!(currentHit->
getHits()[bestPlane]) && (*lastHitItr)->getHits()[bestPlane]) || (currentHit->
getHits()[bestPlane] && !((*lastHitItr)->getHits()[bestPlane])))
break;
998 while(firstHitItr != lastHitItr)
1002 currentHit = *++firstHitItr;
1005 firstHitItr = lastHitItr;
1028 curCluster = testList;
bool operator()(const reco::ClusterHit3D *left, const reco::ClusterHit3D *right) const
reco::HitPairListPtr & getBestHitPairListPtr()
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
void configure(fhicl::ParameterSet const &pset) override
std::list< reco::ClusterHit3D > HitPairList
std::vector< std::vector< float > > m_wireDir
void LeastCostPath(const reco::EdgeTuple &, const reco::ClusterHit3D *, reco::ClusterParameters &, float &) const
Find the lowest cost path between two nodes using MST edges.
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
float getTimeToExecute(TimeValues index) const override
If monitoring, recover the time to execute a particular function.
std::tuple< const reco::ClusterHit3D *, float, float > BestNodeTuple
geo::Geometry const * m_geometry
bool m_enableMonitoring
Data members to follow.
const Eigen::Vector3f getPosition() const
std::list< ProjectedPoint > ProjectedPointList
void Cluster3DHits(reco::HitPairListPtr &hitPairList, reco::ClusterParametersList &clusterParametersList) const override
Given a set of recob hits, run DBscan to form 3D clusters.
std::list< KdTreeNode > KdTreeNodeList
Implements a kdTree for use in clustering.
size_t FindNearestNeighbors(const reco::ClusterHit3D *, const KdTreeNode &, CandPairList &, float &) const
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
const std::vector< size_t > & m_plane
reco::EdgeList & getBestEdgeList()
MinSpanTreeAlg(const fhicl::ParameterSet &)
Constructor.
reco::Hit3DToEdgeMap & getHit3DToEdgeMap()
reco::HitPairListPtr & getHitPairListPtr()
IClusterAlg interface class definiton.
std::vector< size_t > ChannelStatusVec
define data structure for keeping track of channel status
float DistanceBetweenNodes(const reco::ClusterHit3D *, const reco::ClusterHit3D *) const
unsigned int getStatusBits() const
void AStar(const reco::ClusterHit3D *, const reco::ClusterHit3D *, float alpha, kdTree::KdTreeNode &, reco::ClusterParameters &) const
Algorithm to find shortest path between two 3D hits.
art framework interface to geometry description
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
std::list< EdgeTuple > EdgeList
void PruneAmbiguousHits(reco::ClusterParameters &, reco::Hit2DToClusterMap &) const
Prune the obvious ambiguous hits.
fInnerVessel push_back(Point(-578.400000, 0.000000, 0.000000))
const EigenValues & getEigenValues() const
std::vector< ChannelStatusVec > ChannelStatusByPlaneVec
std::unordered_map< const reco::ClusterHit3D *, BestNodeTuple > BestNodeMap
T get(std::string const &key) const
const Eigen::Vector3f & getAvePosition() const
void RunPrimsAlgorithm(reco::HitPairList &, kdTree::KdTreeNode &, reco::ClusterParametersList &) const
Driver for Prim's algorithm.
Path checking algorithm has seen this hit.
TimeValues
enumerate the possible values for time checking if monitoring timing
void CheckHitSorting(reco::ClusterParameters &clusterParams) const
void Cluster3DHits(reco::HitPairList &hitPairList, reco::ClusterParametersList &clusterParametersList) const override
Given a set of recob hits, run DBscan to form 3D clusters.
std::tuple< const reco::ClusterHit3D *, const reco::ClusterHit3D *, double > EdgeTuple
std::list< const reco::ClusterHit3D * > HitPairListPtr
This provides an art tool interface definition for 3D Cluster algorithms.
static int max(int a, int b)
The geometry of one entire detector, as served by art.
Definition of data types for geometry description.
std::unique_ptr< lar_cluster3d::IClusterParametersBuilder > m_clusterBuilder
Common cluster builder tool.
std::vector< float > m_timeVector
Detector simulation of raw signals on wires.
std::list< CandPair > CandPairList
Encapsulate the geometry of a wire.
Declaration of signal hit object.
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
const std::vector< geo::WireID > & getWireIDs() const
~MinSpanTreeAlg()
Destructor.
std::unordered_map< const reco::ClusterHit2D *, ClusterToHitPairSetMap > Hit2DToClusterMap
bool operator()(const reco::ClusterParametersList::iterator &left, const reco::ClusterParametersList::iterator &right)
float getHitChiSquare() const
std::unordered_map< const reco::ClusterHit3D *, reco::EdgeList > Hit3DToEdgeMap
double accumulated_real_time() const
unsigned int ChannelID_t
Type representing the ID of a readout channel.
float getTimeToExecute() const
auto const & get(AssnsNode< L, R, D > const &r)
KdTreeNode & BuildKdTree(Hit3DVec::iterator, Hit3DVec::iterator, KdTreeNodeList &, int depth=0) const
Given an input set of ClusterHit3D objects, build a kd tree structure.
const ClusterHit2DVec & getHits() const
void ReconstructBestPath(const reco::ClusterHit3D *, BestNodeMap &, reco::HitPairListPtr &, reco::EdgeList &) const
std::list< ClusterParameters > ClusterParametersList
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
const EigenVectors & getEigenVectors() const
QTextStream & endl(QTextStream &s)
SetCheckHitOrder(const std::vector< size_t > &plane)
void FindBestPathInCluster(reco::ClusterParameters &) const
Algorithm to find the best path through the given cluster.
PrincipalComponentsAlg m_pcaAlg
void setStatusBit(unsigned bits) const
WireGeo const * WirePtr(geo::WireID const &wireid) const
Returns the specified wire.
reco::HitPairListPtr DepthFirstSearch(const reco::EdgeTuple &, const reco::Hit3DToEdgeMap &, float &) const
a depth first search to find longest branches