10 #include "cetlib/search_path.h" 11 #include "cetlib/cpu_timer.h" 25 #include "larevt/CalibrationDBI/Interface/ChannelStatusService.h" 26 #include "larevt/CalibrationDBI/Interface/ChannelStatusProvider.h" 34 #include <unordered_map> 35 #include <Eigen/Dense> 110 using BestNodeMap = std::unordered_map<const reco::ClusterHit3D*,BestNodeTuple>;
150 m_pcaAlg(pset.get<
fhicl::ParameterSet>(
"PrincipalComponentsAlg")),
181 TVector3 uWireDir = uWireGeo->
Direction();
192 TVector3 vWireDir = vWireGeo->
Direction();
230 cet::cpu_timer theClockBuildClusters;
239 theClockBuildClusters.stop();
247 mf::LogDebug(
"Cluster3D") <<
">>>>> Cluster3DHits done, found " << clusterParametersList.size() <<
" clusters" << std::endl;
258 if (hitPairList.empty())
return;
261 cet::cpu_timer theClockDBScan;
267 size_t clusterIdx(0);
298 curEdgeItr = curEdgeList.erase(curEdgeItr);
303 curCluster->push_back(lastAddedHit);
307 float bestDistance(1.5);
313 for(
auto& pair : CandPairList)
317 if (curEdgeList.empty())
319 std::cout <<
"-----------------------------------------------------------------------------------------" << std::endl;
320 std::cout <<
"**> Cluster idx: " << clusterIdx++ <<
" has " << curCluster->size() <<
" hits" << std::endl;
326 if (freeHitItr == hitPairList.end())
break;
328 std::cout <<
"##################################################################>Processing another cluster" << std::endl;
333 curClusterItr = --clusterParametersList.end();
335 curEdgeMap = &(*curClusterItr).getHit3DToEdgeMap();
336 curCluster = &(*curClusterItr).getHitPairListPtr();
337 lastAddedHit = (*freeHitItr++).
get();
343 curEdgeList.sort([](
const auto&
left,
const auto&
right){
return std::get<2>(
left) < std::get<2>(
right);});
348 (*curEdgeMap)[std::get<0>(curEdge)].push_back(curEdge);
349 (*curEdgeMap)[std::get<1>(curEdge)].push_back(
reco::EdgeTuple(std::get<1>(curEdge),std::get<0>(curEdge),std::get<2>(curEdge)));
352 lastAddedHit = std::get<1>(curEdge);
358 theClockDBScan.stop();
369 float bestQuality(0.);
370 float aveNumEdges(0.);
371 size_t maxNumEdges(0);
372 size_t nIsolatedHits(0);
375 cet::cpu_timer theClockPathFinding;
385 for(
const auto&
hit : hitPairList)
387 if (!curEdgeMap[
hit].empty() && curEdgeMap[
hit].size() == 1)
393 tempList.push_front(std::get<0>(curEdgeMap[
hit].front()));
395 if (quality > bestQuality)
397 longestCluster = tempList;
398 bestQuality = quality;
404 aveNumEdges += float(curEdgeMap[
hit].size());
405 maxNumEdges =
std::max(maxNumEdges,curEdgeMap[
hit].size());
408 aveNumEdges /= float(hitPairList.size());
409 std::cout <<
"----> # isolated hits: " << nIsolatedHits <<
", longest branch: " << longestCluster.size() <<
", cluster size: " << hitPairList.size() <<
", ave # edges: " << aveNumEdges <<
", max: " << maxNumEdges << std::endl;
411 if (!longestCluster.empty())
413 hitPairList = longestCluster;
414 for(
const auto&
hit : hitPairList)
416 for(
const auto& edge : curEdgeMap[
hit]) bestEdgeList.emplace_back(edge);
419 std::cout <<
" ====> new cluster size: " << hitPairList.size() << std::endl;
424 theClockPathFinding.stop();
435 cet::cpu_timer theClockPathFinding;
444 if (curCluster.size() > 2)
461 for(
const auto&
hit : curCluster)
462 if (!curEdgeMap[
hit].empty() && curEdgeMap[
hit].size() == 1)
463 isolatedHitList.emplace_back(std::get<0>(curEdgeMap[
hit].front()));
465 std::cout <<
"************* Finding best path with A* in cluster *****************" << std::endl;
466 std::cout <<
"**> There are " << curCluster.size() <<
" hits, " << isolatedHitList.size() <<
" isolated hits, the alpha parameter is " << alpha << std::endl;
467 std::cout <<
"**> PCA len: " << pcaLen <<
", wid: " << pcaWidth <<
", height: " << pcaHeight <<
", ratio: " << pcaHeight/pcaWidth << std::endl;
472 while(firstItr != isolatedHitList.end())
477 float delta1stPca[] = {firstPos[0]-pcaPos[0],firstPos[1]-pcaPos[1],firstPos[2]-pcaPos[2]};
478 float firstPcaProj = std::fabs(delta1stPca[0]*pcaAxis[0] + delta1stPca[1]*pcaAxis[1] + delta1stPca[2]*pcaAxis[2]);
480 if (firstPcaProj < 0.75 * pcaLen)
continue;
484 const float* secondPos = (*secondItr)->getPosition();
485 float delta2ndPca[] = {secondPos[0]-pcaPos[0],secondPos[1]-pcaPos[1],secondPos[2]-pcaPos[2]};
486 float secondPcaProj = std::fabs(delta2ndPca[0]*pcaAxis[0] + delta2ndPca[1]*pcaAxis[1] + delta2ndPca[2]*pcaAxis[2]);
488 if (secondPcaProj < 0.75 * pcaLen)
continue;
490 float deltaPos[] = {secondPos[0]-firstPos[0],secondPos[1]-firstPos[1],secondPos[2]-firstPos[2]};
491 float projection = std::fabs(deltaPos[0]*pcaAxis[0]+deltaPos[1]*pcaAxis[1]+deltaPos[2]*pcaAxis[2]);
493 edgeList.emplace_back(firstHit,*secondItr,projection);
498 if (edgeList.empty())
500 if (isolatedHitList.size() > 20)
502 std::cout <<
"!!!! What happened???? " << std::endl;
506 if (!edgeList.empty())
508 edgeList.sort([](
const auto&
left,
const auto&
right){
return std::get<2>(
left) > std::get<2>(
right);});
513 std::cout <<
"**> Sorted " << edgeList.size() <<
" edges, longest distance: " <<
DistanceBetweenNodes(std::get<0>(bestEdge),std::get<1>(bestEdge)) << std::endl;
518 AStar(std::get<0>(bestEdge),std::get<1>(bestEdge),alpha,topNode,bestHitPairListPtr,bestEdgeList);
526 std::cout <<
"**> Best path has " << bestHitPairListPtr.size() <<
" hits, " << bestEdgeList.size() <<
" edges" << std::endl;
531 std::cout <<
"++++++>>> PCA failure! # hits: " << curCluster.size() << std::endl;
537 theClockPathFinding.stop();
566 while(!openList.empty())
572 if (openList.size() > 1)
573 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));});
579 if (currentNode == goalNode)
592 openList.erase(currentNodeItr);
607 const BestNodeTuple& currentNodeTuple = bestNodeMap.at(currentNode);
608 float currentNodeScore = std::get<1>(currentNodeTuple);
610 for(
auto& candPair : CandPairList)
616 float tentative_gScore = currentNodeScore + candPair.first;
621 if (candNodeItr == bestNodeMap.end())
623 openList.push_back(candPair.second);
626 else if (tentative_gScore > std::get<1>(candNodeItr->second))
continue;
629 const float* currentNodePos = currentNode->
getPosition();
630 const float* nextNodePos = candPair.second->getPosition();
631 float curNextDelta[] = {nextNodePos[0]-currentNodePos[0], nextNodePos[1]-currentNodePos[1], nextNodePos[2]-currentNodePos[2]};
633 const float* goalNodePos = goalNode->
getPosition();
634 float goalNextDelta[] = {goalNodePos[0]-nextNodePos[0], goalNodePos[1]-nextNodePos[1], goalNodePos[2]-nextNodePos[2]};
636 float curNextMag = std::sqrt(curNextDelta[0]*curNextDelta[0] + curNextDelta[1]*curNextDelta[1] + curNextDelta[2]*curNextDelta[2]);
637 float goalNextMag = std::sqrt(goalNextDelta[0]*goalNextDelta[0] + goalNextDelta[1]*goalNextDelta[1] + goalNextDelta[2]*goalNextDelta[2]);
639 float cosTheta = (curNextDelta[0]*goalNextDelta[0] + curNextDelta[1]*goalNextDelta[1] + curNextDelta[2]*goalNextDelta[2]);
641 if (cosTheta > 0. || cosTheta < 0.) cosTheta /= (curNextMag * goalNextMag);
646 float hWeight = alpha*goalNextMag/
std::max(0.01,0.5*(1.+cosTheta));
649 bestNodeMap[candPair.second] =
BestNodeTuple(currentNode,tentative_gScore, tentative_gScore + hWeight);
665 while(std::get<0>(bestNodeMap.at(goalNode)) != goalNode)
670 pathNodeList.push_front(goalNode);
671 bestEdgeList.push_front(bestEdge);
676 pathNodeList.push_front(goalNode);
686 float& showMeTheMoney)
const 692 if (edgeListItr != hitToEdgeMap.end())
694 for(
const auto& edge : edgeListItr->second)
697 if (std::get<1>(edge) == std::get<0>(curEdge))
continue;
700 if (std::get<1>(edge) == goalNode)
702 bestNodeList.push_back(goalNode);
703 bestEdgeList.push_back(edge);
704 showMeTheMoney = std::get<2>(edge);
709 float currentCost(0.);
711 LeastCostPath(edge,goalNode,hitToEdgeMap,bestNodeList,bestEdgeList,currentCost);
715 showMeTheMoney = std::get<2>(edge) + currentCost;
723 bestNodeList.push_front(std::get<1>(curEdge));
724 bestEdgeList.push_front(curEdge);
734 float deltaNode[] = {node1Pos[0]-node2Pos[0], node1Pos[1]-node2Pos[1], node1Pos[2]-node2Pos[2]};
737 return std::sqrt(deltaNode[0]*deltaNode[0]+deltaNode[1]*deltaNode[1]+deltaNode[2]*deltaNode[2]);
760 float& bestTreeQuality)
const 763 float bestQuality(0.);
764 float curEdgeWeight =
std::max(0.3,std::get<2>(curEdge));
765 float curEdgeProj(1./curEdgeWeight);
769 if (edgeListItr != hitToEdgeMap.end())
772 const float* firstHitPos = std::get<0>(curEdge)->getPosition();
773 const float* secondHitPos = std::get<1>(curEdge)->getPosition();
774 float curEdgeVec[] = {secondHitPos[0]-firstHitPos[0],secondHitPos[1]-firstHitPos[1],secondHitPos[2]-firstHitPos[2]};
775 float curEdgeMag = std::sqrt(curEdgeVec[0]*curEdgeVec[0]+curEdgeVec[1]*curEdgeVec[1]+curEdgeVec[2]*curEdgeVec[2]);
777 curEdgeMag =
std::max(
float(0.1),curEdgeMag);
779 for(
const auto& edge : edgeListItr->second)
782 if (std::get<1>(edge) == std::get<0>(curEdge))
continue;
788 if (quality > bestQuality)
790 hitPairListPtr = tempList;
791 bestQuality = quality;
792 curEdgeProj = 1./curEdgeMag;
797 hitPairListPtr.push_front(std::get<1>(curEdge));
799 bestTreeQuality += bestQuality + curEdgeProj;
801 return hitPairListPtr;
811 size_t nStartedWith(hitPairVector.size());
812 size_t nRejectedHits(0);
817 for(
const auto& hit3D : hitPairVector)
820 size_t n2DHitsIn3DHit(0);
821 size_t nThisClusterOnly(0);
822 size_t nOtherCluster(0);
825 const std::set<const reco::ClusterHit3D*>* otherClusterHits = 0;
827 for(
const auto& hit2D : hit3D->getHits())
829 if (!hit2D)
continue;
833 if (hit2DToClusterMap[hit2D].size() < 2) nThisClusterOnly = hit2DToClusterMap[hit2D][&clusterParams].size();
836 for(
const auto& clusterHitMap : hit2DToClusterMap[hit2D])
838 if (clusterHitMap.first == &clusterParams)
continue;
840 if (clusterHitMap.second.size() > nOtherCluster)
842 nOtherCluster = clusterHitMap.second.size();
844 otherClusterHits = &clusterHitMap.second;
850 if (n2DHitsIn3DHit < 3 && nThisClusterOnly > 1 && nOtherCluster > 0)
852 bool skip3DHit(
false);
854 for(
const auto& otherHit3D : *otherClusterHits)
856 size_t nOther2DHits(0);
858 for(
const auto& otherHit2D : otherHit3D->getHits())
860 if (!otherHit2D)
continue;
865 if (nOther2DHits > 2)
873 if (skip3DHit)
continue;
877 goodHits.emplace_back(hit3D);
880 std::cout <<
"###>> Input " << nStartedWith <<
" hits, rejected: " << nRejectedHits << std::endl;
882 hitPairVector.resize(goodHits.size());
883 std::copy(goodHits.begin(),goodHits.end(),hitPairVector.begin());
893 return (*left).getHitPairListPtr().size() > (*right).getHitPairListPtr().size();
910 return left->
getHits()[m_plane[0]]->getHit().PeakTime() < right->
getHits()[m_plane[0]]->getHit().PeakTime();
919 return left->
getHits()[m_plane[1]]->getHit().PeakTime() < right->
getHits()[m_plane[1]]->getHit().PeakTime();
942 if (curCluster.size() > 2)
952 std::vector<size_t> closestPlane = {0, 0, 0 };
953 std::vector<float> bestAngle = {0.,0.,0.};
955 for(
size_t plane = 0; plane < 3; plane++)
957 const std::vector<float>& wireDir =
m_wireDir[plane];
959 float dotProd = std::fabs(pcaAxis[0]*wireDir[0] + pcaAxis[1]*wireDir[1] + pcaAxis[2]*wireDir[2]);
961 if (dotProd > bestAngle[0])
963 bestAngle[2] = bestAngle[1];
964 closestPlane[2] = closestPlane[1];
965 bestAngle[1] = bestAngle[0];
966 closestPlane[1] = closestPlane[0];
967 closestPlane[0] = plane;
968 bestAngle[0] = dotProd;
970 else if (dotProd > bestAngle[1])
972 bestAngle[2] = bestAngle[1];
973 closestPlane[2] = closestPlane[1];
974 closestPlane[1] = plane;
975 bestAngle[1] = dotProd;
979 closestPlane[2] = plane;
980 bestAngle[2] = dotProd;
991 std::cout <<
"********************************************************************************************" << std::endl;
992 std::cout <<
"**>>>>> longest axis: " << closestPlane[0] <<
", best angle: " << bestAngle[0] << std::endl;
993 std::cout <<
"**>>>>> second axis: " << closestPlane[1] <<
", best angle: " << bestAngle[1] << std::endl;
994 std::cout <<
" " << std::endl;
999 size_t bestPlane = closestPlane[0];
1003 while(firstHitItr != localHitList.end())
1008 while(lastHitItr != localHitList.end())
1011 if (currentHit->
getWireIDs()[bestPlane] != (*lastHitItr)->getWireIDs()[bestPlane])
break;
1014 if (currentHit->
getHits()[bestPlane] && (*lastHitItr)->getHits()[bestPlane] && currentHit->
getHits()[bestPlane] != (*lastHitItr)->getHits()[bestPlane])
break;
1017 if ((!(currentHit->
getHits()[bestPlane]) && (*lastHitItr)->getHits()[bestPlane]) || (currentHit->
getHits()[bestPlane] && !((*lastHitItr)->getHits()[bestPlane])))
break;
1034 while(firstHitItr != lastHitItr)
1038 currentHit = *++firstHitItr;
1041 firstHitItr = lastHitItr;
1064 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::vector< std::vector< float > > m_wireDir
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
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
This algorithm will create and then cluster 3D hits using DBScan.
ClusterParamsBuilder m_clusterBuilder
bool m_enableMonitoring
Data members to follow.
Declaration of signal hit object.
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()
const float * getAvePosition() const
void BuildClusterInfo(reco::ClusterParametersList &clusterParametersList) const
Given the results of running DBScan, format the clusters so that they can be easily transferred back ...
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
std::list< std::unique_ptr< reco::ClusterHit3D >> HitPairList
std::list< EdgeTuple > EdgeList
void PruneAmbiguousHits(reco::ClusterParameters &, reco::Hit2DToClusterMap &) const
Prune the obvious ambiguous hits.
std::vector< ChannelStatusVec > ChannelStatusByPlaneVec
ClusterParamsBuilder class definiton.
std::unordered_map< const reco::ClusterHit3D *, BestNodeTuple > BestNodeMap
T get(std::string const &key) 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.
void fill(const art::PtrVector< recob::Hit > &hits, int only_plane)
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.
const float * getPosition() const
std::vector< float > m_timeVector
Vector Direction() const
Returns the wire direction as a norm-one vector.
Detector simulation of raw signals on wires.
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.
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Utility object to perform functions of association.
const float * getEigenValues() const
Encapsulate the construction of a single detector plane.
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)
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.
const ClusterHit2DVec & getHits() const
void LeastCostPath(const reco::EdgeTuple &, const reco::ClusterHit3D *, const reco::Hit3DToEdgeMap &, reco::HitPairListPtr &, reco::EdgeList &, float &) const
Find the lowest cost path between two nodes using MST edges.
geo::Geometry * m_geometry
art framework interface to geometry description
void ReconstructBestPath(const reco::ClusterHit3D *, BestNodeMap &, reco::HitPairListPtr &, reco::EdgeList &) const
std::list< ClusterParameters > ClusterParametersList
void AStar(const reco::ClusterHit3D *, const reco::ClusterHit3D *, float alpha, kdTree::KdTreeNode &, reco::HitPairListPtr &, reco::EdgeList &) const
Algorithm to find shortest path between two 3D hits.
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