12 #include "cetlib/search_path.h" 13 #include "cetlib/cpu_timer.h" 28 #include <Eigen/Dense> 121 const Eigen::Vector3f&,
122 const Eigen::Vector3f&,
123 const Eigen::Vector3f&,
125 Eigen::Vector3f&)
const;
127 using MinMaxPoints = std::pair<reco::ProjectedPoint,reco::ProjectedPoint>;
134 using KinkTuple = std::tuple<int, reco::ConvexHullKinkTuple, HitOrderTupleList, HitOrderTupleList>;
183 fPCAAlg(pset.get<
fhicl::ParameterSet>(
"PrincipalComponentsAlg"))
220 std::string dirName =
"ConvexHullPath";
227 fTopNumEdges = dir.
make<TH1F>(
"TopNumEdges",
"Number Edges", 200, 0., 200.);
234 fSubNumEdges = dir.
make<TH1F>(
"SubNumEdges",
"Number Edges", 200, 0., 200.);
257 cet::cpu_timer theClockBuildClusters;
267 while(clusterParametersListItr != clusterParametersList.end())
286 reclusteredParameters.push_back(clusterParameters);
289 if (!reclusteredParameters.empty())
292 for (
auto&
cluster : reclusteredParameters)
309 std::vector<double> eigenValVec = {3. * std::sqrt(fullPCA.
getEigenValues()[0]),
312 double eigen2To1Ratio = eigenValVec[2] / eigenValVec[1];
313 double eigen1To0Ratio = eigenValVec[1] / eigenValVec[0];
314 double eigen2To0Ratio = eigenValVec[2] / eigenValVec[0];
315 int num3DHits =
cluster.getHitPairListPtr().size();
316 int numEdges =
cluster.getBestEdgeList().size();
330 clusterParametersListItr++;
335 theClockBuildClusters.stop();
340 mf::LogDebug(
"Cluster3D") <<
">>>>> Cluster Path finding done" << std::endl;
377 Eigen::Vector3f edgeVec(secondEdgeHit->getPosition()[0] - firstEdgeHit->
getPosition()[0],
378 secondEdgeHit->getPosition()[1] - firstEdgeHit->
getPosition()[1],
379 secondEdgeHit->getPosition()[2] - firstEdgeHit->
getPosition()[2]);
380 double edgeLen = edgeVec.norm();
397 clusHitPairVector.sort([](
const auto&
left,
const auto&
right){
return left->getArclenToPoca() <
right->getArclenToPoca();});
405 if (!
breakClusterByKinks(clusterToBreak, clusHitPairVector, tempClusterParametersList, level))
413 if (edgeLen > 10.)
breakClusterInHalf(clusterToBreak, clusHitPairVector, tempClusterParametersList, level);
418 for(
auto& clusterParams : tempClusterParametersList)
420 size_t curOutputClusterListSize = outputClusterList.size();
422 positionItr =
subDivideCluster(clusterParams, fullPCA, positionItr, outputClusterList, level+4);
426 if (curOutputClusterListSize < outputClusterList.size())
continue;
431 std::set<const reco::ClusterHit2D*> hitSet;
434 for(
const auto& hit3D : clusterParams.getHitPairListPtr())
436 for(
const auto& hit2D : hit3D->getHits())
438 if (hit2D) hitSet.insert(hit2D);
443 for(
const auto& hit2D : hitSet)
446 clusterParams.UpdateParameters(hit2D);
449 positionItr = outputClusterList.insert(positionItr,clusterParams);
454 std::vector<double> eigenValVec = {3. * std::sqrt(fullPCA.
getEigenValues()[0]),
462 Eigen::Vector3f lastPrimaryVec(newFullPCA.getEigenVectors()[0][0],newFullPCA.getEigenVectors()[0][1],newFullPCA.getEigenVectors()[0][2]);
464 int num3DHits = clusterParams.getHitPairListPtr().size();
465 int numEdges = clusterParams.getBestEdgeList().size();
466 float cosToLast = newPrimaryVec.dot(lastPrimaryVec);
467 double eigen2To1Ratio = eigenValVec[2] / eigenValVec[1];
468 double eigen1To0Ratio = eigenValVec[1] / eigenValVec[0];
469 double eigen2To0Ratio = eigenValVec[2] / eigenValVec[0];
495 std::string
indent(level/2,
' ');
500 hitPairListPtr.resize(std::distance(firstHitItr,lastHitItr));
503 std::copy(firstHitItr,lastHitItr,hitPairListPtr.begin());
506 bool keepThisCluster(
false);
517 std::vector<double> eigenValVec = {3. * std::sqrt(newFullPCA.
getEigenValues()[0]),
520 double cosNewToLast = std::abs(primaryPCA.dot(newPrimaryVec));
521 double eigen2To1Ratio = eigenValVec[2] / eigenValVec[1];
522 double eigen1To0Ratio = eigenValVec[1] / eigenValVec[0];
528 keepThisCluster =
true;
532 return keepThisCluster;
540 std::string
indent(level/2,
' ');
545 for(
const auto& tupleVal : orderedList) hitPairListPtr.emplace_back(std::get<2>(std::get<2>(tupleVal)));
548 bool keepThisCluster(
false);
559 std::vector<double> eigenValVec = {3. * std::sqrt(newFullPCA.
getEigenValues()[0]),
562 double cosNewToLast = std::abs(primaryPCA.dot(newPrimaryVec));
563 double eigen2To1Ratio = eigenValVec[2] / eigenValVec[1];
564 double eigen1To0Ratio = eigenValVec[1] / eigenValVec[0];
568 if (candCluster.
getBestEdgeList().size() > 4 && cosNewToLast > 0.25 && eigen2To1Ratio > 0.01 && eigen2To1Ratio < 0.99 && eigen1To0Ratio < 0.5)
570 keepThisCluster =
true;
574 return keepThisCluster;
586 bool keepThisCluster(
false);
595 if (primaryPCA.dot(newPrimaryVec) < 0.)
599 eigenVectors.resize(3);
601 for(
size_t vecIdx = 0; vecIdx < 3; vecIdx++)
603 eigenVectors[vecIdx].resize(3,0.);
624 keepThisCluster =
true;
627 return keepThisCluster;
633 using HitKinkTuple = std::tuple<int, reco::HitPairListPtr::iterator>;
634 using HitKinkTupleVec = std::vector<HitKinkTuple>;
637 HitKinkTupleVec kinkTupleVec;
642 for(
auto& kink : kinkPointList)
648 if (kinkItr == hitList.end())
continue;
650 int numStartToKink = std::distance(hitList.begin(),kinkItr);
651 int numKinkToEnd = std::distance(kinkItr, hitList.end());
652 int minNumHits =
std::min(numStartToKink,numKinkToEnd);
658 if (!kinkTupleVec.empty())
660 std::sort(kinkTupleVec.begin(),kinkTupleVec.end(),[](
const auto&
left,
const auto&
right){
return std::get<0>(
left) > std::get<0>(
right);});
671 Eigen::Vector3f fullPrimaryVec(fullPCA.getEigenVectors()[0][0],fullPCA.getEigenVectors()[0][1],fullPCA.getEigenVectors()[0][2]);
683 if (outputClusterList.size() != 2) outputClusterList.clear();
686 return !outputClusterList.empty();
698 for(
auto& kink : kinkPointList)
703 KinkTuple& kinkTuple = kinkTupleVec.back();
705 std::get<1>(kinkTuple) = kink;
708 Eigen::Vector2f firstEdge = -std::get<1>(kink);
716 Eigen::Vector2f secondEdge = std::get<2>(kink);
721 std::get<0>(kinkTuple) =
std::min(firstList.size(),secondList.size());
725 if (firstList.size() + secondList.size() > pointList.size())
730 std::get<0>(kinkTuple) =
std::min(firstList.size(),secondList.size());
737 if (!kinkTupleVec.empty())
740 std::sort(kinkTupleVec.begin(),kinkTupleVec.end(),[](
const auto&
left,
const auto&
right){
return std::get<0>(
left) > std::get<0>(
right);});
743 KinkTuple& kinkTuple = kinkTupleVec.front();
751 Eigen::Vector3f fullPrimaryVec(fullPCA.getEigenVectors()[0][0],fullPCA.getEigenVectors()[0][1],fullPCA.getEigenVectors()[0][2]);
763 if (outputClusterList.size() != 2) outputClusterList.clear();
766 return !outputClusterList.empty();
771 const Eigen::Vector2f& edge,
775 Eigen::Vector2f kinkPos(std::get<0>(point),std::get<1>(point));
778 for (
const auto&
hit : hitList)
782 Eigen::Vector2f hitPos(std::get<0>(
hit),std::get<1>(
hit));
785 Eigen::Vector2f hitToKinkVec = hitPos - kinkPos;
788 float arcLenToPoca = hitToKinkVec.dot(edge);
791 if (arcLenToPoca < 0.)
continue;
794 Eigen::Vector2f pocaPos = kinkPos + arcLenToPoca * edge;
797 Eigen::Vector2f pocaPosToHitPos = hitPos - pocaPos;
798 float pocaToAxis = pocaPosToHitPos.norm();
800 std::cout <<
"-- arcLenToPoca: " << arcLenToPoca <<
", doca: " << pocaToAxis << std::endl;
802 orderedList.emplace_back(arcLenToPoca,pocaToAxis,
hit);
806 orderedList.sort([](
const auto&
left,
const auto&
right){
return std::get<0>(
left) < std::get<0>(
right);});
816 while(shortItr != shortList.end())
822 HitOrderTupleList::iterator longItr = std::find_if(longList.begin(),longList.end(),[&hit3D](
const auto& elem){
return hit3D == std::get<2>(std::get<2>(elem));});
824 if (longItr != longList.end())
826 if (std::get<1>(*longItr) < std::get<1>(*shortItr))
828 shortItr = shortList.erase(shortItr);
832 longItr = longList.erase(longItr);
846 using DistEdgeTuple = std::tuple<float, const reco::EdgeTuple*>;
847 using DistEdgeTupleVec = std::vector<DistEdgeTuple>;
849 DistEdgeTupleVec distEdgeTupleVec;
855 Eigen::Vector3f edgeVec(secondEdgeHit->getPosition()[0] - firstEdgeHit->
getPosition()[0],
856 secondEdgeHit->getPosition()[1] - firstEdgeHit->
getPosition()[1],
857 secondEdgeHit->getPosition()[2] - firstEdgeHit->
getPosition()[2]);
858 double edgeLen = edgeVec.norm();
875 float hitProjection = hitToEdgeVec.dot(edgeVec);
878 if (hitProjection > 0. && hitProjection < edgeLen)
880 Eigen::Vector3f distToHitVec = hitToEdgeVec - hitProjection * edgeVec;
881 float distToHit = distToHitVec.norm();
883 distEdgeTupleVec.emplace_back(distToHit,&edge);
887 std::sort(distEdgeTupleVec.begin(),distEdgeTupleVec.end(),[](
const auto&
left,
const auto&
right){
return std::get<0>(
left) > std::get<0>(
right);});
890 Eigen::Vector3f fullPrimaryVec(fullPCA.getEigenVectors()[0][0],fullPCA.getEigenVectors()[0][1],fullPCA.getEigenVectors()[0][2]);
893 float usedDefectDist(0.);
895 for(
const auto& distEdgeTuple : distEdgeTupleVec)
900 usedDefectDist = std::get<0>(distEdgeTuple);
922 fSubMaxDefect->Fill(std::get<0>(distEdgeTupleVec.front()), 1.);
930 outputClusterList.clear();
933 return !outputClusterList.empty();
940 std::advance(vertexItr, hitList.size()/2);
947 Eigen::Vector3f fullPrimaryVec(fullPCA.getEigenVectors()[0][0],fullPCA.getEigenVectors()[0][1],fullPCA.getEigenVectors()[0][2]);
958 if (outputClusterList.size() != 2) outputClusterList.clear();
960 return !outputClusterList.empty();
970 float biggestGap = 0.;
980 if (currentGap > biggestGap)
982 bigGapHitItr = hitItr;
983 biggestGap = currentGap;
986 lastHit = currentHit;
997 Eigen::Vector3f fullPrimaryVec(fullPCA.getEigenVectors()[0][0],fullPCA.getEigenVectors()[0][1],fullPCA.getEigenVectors()[0][2]);
1008 if (outputClusterList.size() != 2) outputClusterList.clear();
1011 return !outputClusterList.empty();
1018 std::string minuses(level/2,
'-');
1019 std::string
indent(level/2,
' ');
1034 Eigen::Matrix3f rotationMatrix;
1036 rotationMatrix << planeVec0(0), planeVec0(1), planeVec0(2),
1037 planeVec1(0), planeVec1(1), planeVec1(2),
1038 pcaPlaneNrml(0), pcaPlaneNrml(1), pcaPlaneNrml(2);
1046 Eigen::Vector3f pcaToHitVec(hit3D->getPosition()[0] - pcaCenter(0),
1047 hit3D->getPosition()[1] - pcaCenter(1),
1048 hit3D->getPosition()[2] - pcaCenter(2));
1049 Eigen::Vector3f pcaToHit = rotationMatrix * pcaToHitVec;
1051 pointList.emplace_back(
dcel2d::Point(pcaToHit(0),pcaToHit(1),hit3D));
1055 pointList.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);});
1058 std::vector<ConvexHull> convexHullVec;
1059 std::vector<reco::ProjectedPointList> rejectedListVec;
1060 bool increaseDepth(pointList.size() > 3);
1063 while(increaseDepth)
1069 const ConvexHull& convexHull = convexHullVec.back();
1073 increaseDepth =
false;
1077 if (convexHullVec.size() < 2 || convexHull.
getConvexHullArea() < 0.8 * lastArea)
1079 for(
auto& point : convexHullPoints)
1081 pointList.remove(point);
1082 rejectedList.emplace_back(point);
1091 while(!convexHullVec.empty() && convexHullVec.back().getConvexHullArea() < 0.5)
1093 convexHullVec.pop_back();
1094 rejectedListVec.pop_back();
1098 if (!convexHullVec.empty())
1100 size_t nRejectedTotal(0);
1103 for(
const auto& rejectedList : rejectedListVec)
1105 nRejectedTotal += rejectedList.size();
1107 for(
const auto& rejectedPoint : rejectedList)
1109 if (convexHullVec.back().findNearestDistance(rejectedPoint) > 0.5)
1110 hitPairListPtr.remove(std::get<2>(rejectedPoint));
1120 for(
auto& curPoint : convexHullVec.back().getConvexHull())
1122 if (curPoint == lastPoint)
continue;
1127 float distBetweenPoints = (curPoint3D->getPosition()[0] - lastPoint3D->
getPosition()[0]) * (curPoint3D->getPosition()[0] - lastPoint3D->
getPosition()[0])
1128 + (curPoint3D->getPosition()[1] - lastPoint3D->
getPosition()[1]) * (curPoint3D->getPosition()[1] - lastPoint3D->
getPosition()[1])
1129 + (curPoint3D->getPosition()[2] - lastPoint3D->
getPosition()[2]) * (curPoint3D->getPosition()[2] - lastPoint3D->
getPosition()[2]);
1131 distBetweenPoints = std::sqrt(distBetweenPoints);
1135 edgeMap[lastPoint3D].push_back(edge);
1136 edgeMap[curPoint3D].push_back(edge);
1137 edgeList.emplace_back(edge);
1139 lastPoint = curPoint;
1146 for(
const auto& point : extremePoints) extremePointList.push_back(point);
1152 for(
const auto& kink : kinkPoints) kinkPointList.push_back(kink);
1159 const Eigen::Vector3f& u0,
1160 const Eigen::Vector3f& P1,
1161 const Eigen::Vector3f& u1,
1162 Eigen::Vector3f& poca0,
1163 Eigen::Vector3f& poca1)
const 1166 Eigen::Vector3f w0 = P0 - P1;
1168 float b(u0.dot(u1));
1170 float d(u0.dot(w0));
1171 float e(u1.dot(w0));
1172 float den(a * c - b * b);
1174 float arcLen0 = (b *
e - c *
d) / den;
1175 float arcLen1 = (a *
e - b *
d) / den;
1177 poca0 = P0 + arcLen0 * u0;
1178 poca1 = P1 + arcLen1 * u1;
1180 return (poca0 - poca1).norm();
1185 float largestDistance(0.);
1192 while(firstEdgeItr != convexHull.end())
1200 while(++nextEdgeItr != convexHull.end())
1206 return largestDistance;
size_t fMinTinyClusterSize
Minimum size for a "tiny" cluster.
float fConvexHullMinSep
Min hit separation to conisder in convex hull.
void PCAAnalysis_calc3DDocas(const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca) const
bool breakClusterAtBigGap(reco::ClusterParameters &, reco::HitPairListPtr &, reco::ClusterParametersList &, int level) const
~ConvexHullPathFinder()
Destructor.
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
std::tuple< int, reco::ConvexHullKinkTuple, HitOrderTupleList, HitOrderTupleList > KinkTuple
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
float getTimeToExecute() const override
If monitoring, recover the time to execute a particular function.
bool breakClusterInHalf(reco::ClusterParameters &, reco::HitPairListPtr &, reco::ClusterParametersList &, int level) const
std::tuple< float, float, reco::ProjectedPoint > HitOrderTuple
std::list< ProjectedPoint > ProjectedPointList
Declaration of signal hit object.
reco::PrincipalComponents & getSkeletonPCA()
std::list< Point > PointList
The list of the projected points.
reco::ClusterParametersList::iterator subDivideCluster(reco::ClusterParameters &cluster, reco::PrincipalComponents &lastPCA, reco::ClusterParametersList::iterator positionItr, reco::ClusterParametersList &outputClusterList, int level=0) const
Use PCA to try to find path in cluster.
reco::EdgeList & getBestEdgeList()
const float * getAvePosition() const
int getNumHitsUsed() const
reco::HitPairListPtr & getHitPairListPtr()
bool fFillHistograms
Histogram definitions.
Cluster finding and building.
geo::Geometry * fGeometry
Tools.
TFileDirectory mkdir(std::string const &dir, std::string const &descr="")
void configure(fhicl::ParameterSet const &pset) override
IClusterModAlg interface class definiton.
PrincipalComponentsAlg fPCAAlg
ClusterParametersList & daughterList()
Implements a ConvexHull for use in clustering.
std::list< EdgeTuple > EdgeList
reco::PrincipalComponents & getFullPCA()
reco::Hit3DToEdgeMap & getConvexHullEdgeMap()
std::tuple< double, double, const reco::ClusterHit3D * > Point
Definitions used by the VoronoiDiagram algorithm.
reco::ProjectedPointList & getConvexHullExtremePoints()
reco::ConvexHullKinkTupleList & getConvexHullKinkPoints()
Define a container for working with the convex hull.
T get(std::string const &key) const
std::string indent(std::size_t const i)
void pruneHitOrderTupleLists(HitOrderTupleList &, HitOrderTupleList &) const
ConvexHullPathFinder(const fhicl::ParameterSet &)
Constructor.
std::list< ConvexHullKinkTuple > ConvexHullKinkTupleList
std::tuple< const reco::ClusterHit3D *, const reco::ClusterHit3D *, double > EdgeTuple
std::list< const reco::ClusterHit3D * > HitPairListPtr
float getConvexHullArea() const
recover the area of the convex hull
std::vector< std::vector< float > > EigenVectors
This provides an art tool interface definition for 3D Cluster algorithms.
The geometry of one entire detector, as served by art.
const PointList & getConvexHull() const
recover the list of convex hull vertices
const float * getPosition() const
Detector simulation of raw signals on wires.
ConvexHull class definiton.
This header file defines the interface to a principal components analysis designed to be used within ...
Encapsulate the geometry of a wire.
void buildConvexHull(reco::ClusterParameters &clusterParameters, int level=0) const
std::vector< KinkTuple > KinkTupleVec
std::unique_ptr< lar_cluster3d::IClusterAlg > fClusterAlg
Algorithm to do 3D space point clustering.
bool makeCandidateCluster(Eigen::Vector3f &, reco::ClusterParameters &, reco::HitPairListPtr::iterator, reco::HitPairListPtr::iterator, int) const
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
reco::ConvexHull & getConvexHull()
T * make(ARGS...args) const
bool breakClusterByMaxDefect(reco::ClusterParameters &, reco::HitPairListPtr &, reco::ClusterParametersList &, int level) const
Utility object to perform functions of association.
void initializeHistograms(art::TFileDirectory &) override
Interface for initializing histograms if they are desired Note that the idea is to put hisgtograms in...
const float * getEigenValues() const
Encapsulate the construction of a single detector plane.
const float getAveHitDoca() const
float closestApproach(const Eigen::Vector3f &, const Eigen::Vector3f &, const Eigen::Vector3f &, const Eigen::Vector3f &, Eigen::Vector3f &, Eigen::Vector3f &) const
void orderHitsAlongEdge(const reco::ProjectedPointList &, const reco::ProjectedPoint &, const Eigen::Vector2f &, HitOrderTupleList &) const
float fConvexHullKinkAngle
Angle to declare a kink in convex hull calc.
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
This provides an art tool interface definition for 3D Cluster algorithms.
float getArclenToPoca() const
bool breakClusterByKinksTrial(reco::ClusterParameters &, reco::HitPairListPtr &, reco::ClusterParametersList &, int level) const
bool breakClusterByKinks(reco::ClusterParameters &, reco::HitPairListPtr &, reco::ClusterParametersList &, int level) const
std::unordered_map< const reco::ClusterHit3D *, reco::EdgeList > Hit3DToEdgeMap
void ModifyClusters(reco::ClusterParametersList &) const override
Scan an input collection of clusters and modify those according to the specific implementing algorith...
reco::ProjectedPointList & getProjectedPointList()
std::pair< MinMaxPoints, MinMaxPoints > MinMaxPointPair
reco::EdgeList & getConvexHullEdgeList()
bool fEnableMonitoring
FHICL parameters.
float findConvexHullEndPoints(const reco::EdgeList &, const reco::ClusterHit3D *, const reco::ClusterHit3D *) const
std::tuple< float, float, const reco::ClusterHit3D * > ProjectedPoint
Projected coordinates and pointer to hit.
std::list< HitOrderTuple > HitOrderTupleList
art framework interface to geometry description
std::list< ClusterParameters > ClusterParametersList
const EigenVectors & getEigenVectors() const
std::pair< reco::ProjectedPoint, reco::ProjectedPoint > MinMaxPoints
bool completeCandidateCluster(Eigen::Vector3f &, reco::ClusterParameters &, int) const