9 #include "art/Framework/Services/Registry/ServiceHandle.h"
10 #include "art/Utilities/make_tool.h"
11 #include "art/Utilities/ToolMacros.h"
12 #include "cetlib/cpu_timer.h"
13 #include "fhiclcpp/ParameterSet.h"
14 #include "messagefacility/MessageLogger/MessageLogger.h"
31 #include <unordered_map>
41 namespace lar_cluster3d {
58 void configure(fhicl::ParameterSet
const &pset)
override;
111 using BestNodeMap = std::unordered_map<const reco::ClusterHit3D*,BestNodeTuple>;
149 m_pcaAlg(pset.
get<fhicl::ParameterSet>(
"PrincipalComponentsAlg")),
150 m_kdTree(pset.
get<fhicl::ParameterSet>(
"kdTree"))
167 art::ServiceHandle<geo::Geometry const>
geometry;
180 TVector3 uWireDir = uWireGeo->
Direction();
191 TVector3 vWireDir = vWireGeo->
Direction();
203 m_clusterBuilder = art::make_tool<lar_cluster3d::IClusterParametersBuilder>(pset.get<fhicl::ParameterSet>(
"ClusterParamsBuilder"));
231 cet::cpu_timer theClockBuildClusters;
240 theClockBuildClusters.stop();
248 mf::LogDebug(
"MinSpanTreeAlg") <<
">>>>> Cluster3DHits done, found " << clusterParametersList.size() <<
" clusters" << std::endl;
259 if (hitPairList.empty())
return;
262 cet::cpu_timer theClockDBScan;
268 size_t clusterIdx(0);
274 reco::HitPairList::iterator freeHitItr = hitPairList.begin();
283 reco::ClusterParametersList::iterator curClusterItr = --clusterParametersList.end();
296 for(reco::EdgeList::iterator curEdgeItr = curEdgeList.begin(); curEdgeItr != curEdgeList.end();)
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);
385 cet::cpu_timer theClockPathFinding;
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;
414 aveNumEdges += float(curEdgeMap[
hit].
size());
415 maxNumEdges = std::max(maxNumEdges,curEdgeMap[
hit].
size());
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();
445 cet::cpu_timer theClockPathFinding;
468 float alpha = std::min(
float(1.),std::max(
float(0.001),pcaWidth/pcaLen));
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;
508 float cost(std::numeric_limits<float>::max());
519 std::cout <<
"++++++>>> PCA failure! # hits: " << curCluster.size() << std::endl;
525 theClockPathFinding.stop();
558 while(!openList.empty())
561 reco::HitPairListPtr::iterator currentNodeItr = openList.begin();
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);
601 BestNodeMap::iterator candNodeItr = bestNodeMap.find(candHit3D);
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
649 reco::Hit3DToEdgeMap::const_iterator edgeListItr = curEdgeMap.find(std::get<1>(curEdge));
651 showMeTheMoney = std::numeric_limits<float>::max();
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.);
677 if (currentCost < std::numeric_limits<float>::max())
679 showMeTheMoney = std::get<2>(edge) + currentCost;
685 if (showMeTheMoney < std::numeric_limits<float>::max())
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);
731 reco::Hit3DToEdgeMap::const_iterator edgeListItr = hitToEdgeMap.find(std::get<1>(curEdge));
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());
854 bool operator()(
const reco::ClusterParametersList::iterator&
left,
const reco::ClusterParametersList::iterator&
right)
857 return (*left).getHitPairListPtr().size() > (*right).getHitPairListPtr().size();
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;
960 reco::HitPairListPtr::iterator firstHitItr = localHitList.begin();
961 reco::HitPairListPtr::iterator lastHitItr = localHitList.begin();
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
Interface for configuring the particular algorithm tool.
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
std::tuple< const reco::ClusterHit3D *, float, float > BestNodeTuple
const geo::GeometryCore * geometry
geo::Geometry const * m_geometry
bool m_enableMonitoring
Data members to follow.
const Eigen::Vector3f getPosition() const
std::list< ProjectedPoint > ProjectedPointList
Declaration of signal hit object.
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.
std::size_t size(FixedBins< T, C > const &) noexcept
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.
std::list< EdgeTuple > EdgeList
void PruneAmbiguousHits(reco::ClusterParameters &, reco::Hit2DToClusterMap &) const
Prune the obvious ambiguous hits.
const EigenValues & getEigenValues() const
std::vector< ChannelStatusVec > ChannelStatusByPlaneVec
std::unordered_map< const reco::ClusterHit3D *, BestNodeTuple > BestNodeMap
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 Cluster3DHits(reco::HitPairListPtr &hitPairList, reco::ClusterParametersList &clusterParametersList) const override
Given a set of recob hits, run DBscan to form 3D clusters.
void CheckHitSorting(reco::ClusterParameters &clusterParams) const
void fill(const art::PtrVector< recob::Hit > &hits, int only_plane)
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.
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
std::list< CandPair > CandPairList
This header file defines the interface to a principal components analysis designed to be used within ...
Encapsulate the geometry of a wire.
const std::vector< geo::WireID > & getWireIDs() const
~MinSpanTreeAlg()
Destructor.
std::unordered_map< const reco::ClusterHit2D *, ClusterToHitPairSetMap > Hit2DToClusterMap
float getTimeToExecute(TimeValues index) const override
If monitoring, recover the time to execute a particular function.
bool operator()(const reco::ClusterParametersList::iterator &left, const reco::ClusterParametersList::iterator &right)
float getHitChiSquare() const
std::unordered_map< const reco::ClusterHit3D *, reco::EdgeList > Hit3DToEdgeMap
unsigned int ChannelID_t
Type representing the ID of a readout channel.
float getTimeToExecute() const
KdTreeNode & BuildKdTree(Hit3DVec::iterator, Hit3DVec::iterator, KdTreeNodeList &, int depth=0) const
Given an input set of ClusterHit3D objects, build a kd tree structure.
bool empty(FixedBins< T, C > const &) noexcept
const ClusterHit2DVec & getHits() const
BEGIN_PROLOG don t mess with this pandoraTrackGausCryoW true
art framework interface to geometry description
BEGIN_PROLOG could also be cout
void ReconstructBestPath(const reco::ClusterHit3D *, BestNodeMap &, reco::HitPairListPtr &, reco::EdgeList &) const
std::list< ClusterParameters > ClusterParametersList
const EigenVectors & getEigenVectors() const
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