Public Member Functions | Private Types | Private Member Functions | Private Attributes | List of all members
lar_cluster3d::VoronoiPathFinder Class Reference
Inheritance diagram for lar_cluster3d::VoronoiPathFinder:
lar_cluster3d::IClusterModAlg

Public Member Functions

 VoronoiPathFinder (const fhicl::ParameterSet &)
 Constructor. More...
 
 ~VoronoiPathFinder ()
 Destructor. More...
 
void configure (fhicl::ParameterSet const &pset) override
 
void initializeHistograms (art::TFileDirectory &) override
 Interface for initializing histograms if they are desired Note that the idea is to put hisgtograms in a subfolder. More...
 
void ModifyClusters (reco::ClusterParametersList &) const override
 Scan an input collection of clusters and modify those according to the specific implementing algorithm. More...
 
float getTimeToExecute () const override
 If monitoring, recover the time to execute a particular function. More...
 
- Public Member Functions inherited from lar_cluster3d::IClusterModAlg
virtual ~IClusterModAlg () noexcept=default
 Virtual Destructor. More...
 
virtual void configure (const fhicl::ParameterSet &)=0
 Interface for configuring the particular algorithm tool. More...
 

Private Types

using Point = std::tuple< float, float, const reco::ClusterHit3D * >
 
using PointList = std::list< Point >
 
using MinMaxPoints = std::pair< Point, Point >
 
using MinMaxPointPair = std::pair< MinMaxPoints, MinMaxPoints >
 

Private Member Functions

reco::ClusterParametersList::iterator breakIntoTinyBits (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. More...
 
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. More...
 
bool makeCandidateCluster (Eigen::Vector3f &, reco::ClusterParameters &, reco::HitPairListPtr::iterator, reco::HitPairListPtr::iterator, int) const
 
float closestApproach (const Eigen::Vector3f &, const Eigen::Vector3f &, const Eigen::Vector3f &, const Eigen::Vector3f &, Eigen::Vector3f &, Eigen::Vector3f &) const
 
void buildConvexHull (reco::ClusterParameters &clusterParameters, int level=0) const
 
void buildVoronoiDiagram (reco::ClusterParameters &clusterParameters, int level=0) const
 
float findConvexHullEndPoints (const reco::EdgeList &, const reco::ClusterHit3D *, const reco::ClusterHit3D *) const
 

Private Attributes

bool fEnableMonitoring
 FHICL parameters. More...
 
size_t fMinTinyClusterSize
 Minimum size for a "tiny" cluster. More...
 
float fTimeToProcess
 
bool fFillHistograms
 Histogram definitions. More...
 
TH1F * fTopNum3DHits
 
TH1F * fTopNumEdges
 
TH1F * fTopEigen21Ratio
 
TH1F * fTopEigen20Ratio
 
TH1F * fTopEigen10Ratio
 
TH1F * fTopPrimaryLength
 
TH1F * fSubNum3DHits
 
TH1F * fSubNumEdges
 
TH1F * fSubEigen21Ratio
 
TH1F * fSubEigen20Ratio
 
TH1F * fSubEigen10Ratio
 
TH1F * fSubPrimaryLength
 
TH1F * fSubCosToPrevPCA
 
TH1F * fSubCosExtToPCA
 
TH1F * fSubMaxDefect
 
TH1F * fSubUsedDefect
 
std::unique_ptr< lar_cluster3d::IClusterAlgfClusterAlg
 Tools. More...
 
PrincipalComponentsAlg fPCAAlg
 

Detailed Description

Definition at line 39 of file VoronoiPathFinder_tool.cc.

Member Typedef Documentation

Definition at line 119 of file VoronoiPathFinder_tool.cc.

Definition at line 118 of file VoronoiPathFinder_tool.cc.

using lar_cluster3d::VoronoiPathFinder::Point = std::tuple<float,float,const reco::ClusterHit3D*>
private

Definition at line 116 of file VoronoiPathFinder_tool.cc.

Definition at line 117 of file VoronoiPathFinder_tool.cc.

Constructor & Destructor Documentation

lar_cluster3d::VoronoiPathFinder::VoronoiPathFinder ( const fhicl::ParameterSet )
explicit

Constructor.

Parameters
pset

Definition at line 162 of file VoronoiPathFinder_tool.cc.

162  :
163  fPCAAlg(pset.get<fhicl::ParameterSet>("PrincipalComponentsAlg"))
164 {
165  this->configure(pset);
166 }
void configure(fhicl::ParameterSet const &pset) override
lar_cluster3d::VoronoiPathFinder::~VoronoiPathFinder ( )

Destructor.

Definition at line 170 of file VoronoiPathFinder_tool.cc.

171 {
172 }

Member Function Documentation

reco::ClusterParametersList::iterator lar_cluster3d::VoronoiPathFinder::breakIntoTinyBits ( reco::ClusterParameters cluster,
reco::PrincipalComponents lastPCA,
reco::ClusterParametersList::iterator  positionItr,
reco::ClusterParametersList outputClusterList,
int  level = 0 
) const
private

Use PCA to try to find path in cluster.

Parameters
clusterParametersThe given cluster parameters object to try to split
clusterParametersListThe list of clusters

Definition at line 331 of file VoronoiPathFinder_tool.cc.

336 {
337  // This needs to be a recursive routine...
338  // Idea is to take the input cluster and order 3D hits by arclength along PCA primary axis
339  // If the cluster is above the minimum number of hits then we divide into two and call ourself
340  // with the two halves. This means we form a new cluster with hits and PCA and then call ourself
341  // If the cluster is below the minimum then we can't break any more, simply add this cluster to
342  // the new output list.
343 
344  // set an indention string
345  std::string pluses(level/2, '+');
346  std::string indent(level/2, ' ');
347 
348  indent += pluses;
349 
350  reco::ClusterParametersList::iterator inputPositionItr = positionItr;
351 
352  // To make best use of this we'll also want the PCA for this cluster... so...
353  // Recover the prime ingredients
354  reco::PrincipalComponents& fullPCA = clusterToBreak.getFullPCA();
355  std::vector<double> eigenValVec = {3. * std::sqrt(fullPCA.getEigenValues()[0]),
356  3. * std::sqrt(fullPCA.getEigenValues()[1]),
357  3. * std::sqrt(fullPCA.getEigenValues()[2])};
358  Eigen::Vector3f fullPrimaryVec(fullPCA.getEigenVectors().row(2));
359  Eigen::Vector3f lastPrimaryVec(lastPCA.getEigenVectors().row(2));
360 
361  double cosNewToLast = std::abs(fullPrimaryVec.dot(lastPrimaryVec));
362  double eigen2To1Ratio = eigenValVec[2] / eigenValVec[1];
363  double eigen1To0Ratio = eigenValVec[1] / eigenValVec[2];
364  double eigen2To0Ratio = eigenValVec[0] / eigenValVec[2];
365  double eigen2And1Ave = 0.5 * (eigenValVec[1] + eigenValVec[0]);
366  double eigenAveTo0Ratio = eigen2And1Ave / eigenValVec[2];
367 
368  bool storeCurrentCluster(true);
369  int minimumClusterSize(fMinTinyClusterSize);
370 
371  std::cout << indent << ">>> breakIntoTinyBits with " << clusterToBreak.getHitPairListPtr().size() << " input hits, " << clusterToBreak.getBestEdgeList().size() << " edges, rat21: " << eigen2To1Ratio << ", rat20: " << eigen2To0Ratio << ", rat10: " << eigen1To0Ratio << ", ave0: " << eigenAveTo0Ratio << std::endl;
372  std::cout << indent << " --> eigen 0/1/2: " << eigenValVec[0] << "/" << eigenValVec[1] << "/" << eigenValVec[2] << ", cos: " << cosNewToLast << std::endl;
373 
374  // Create a rough cut intended to tell us when we've reached the land of diminishing returns
375  if (clusterToBreak.getBestEdgeList().size() > 5 && cosNewToLast > 0.25 && eigen2To1Ratio < 0.9 && eigen2To0Ratio > 0.001 &&
376  clusterToBreak.getHitPairListPtr().size() > size_t(2 * minimumClusterSize))
377  {
378  // We want to find the convex hull vertices that lie furthest from the line to/from the extreme points
379  // To find these we:
380  // 1) recover the extreme points
381  // 2) form the vector between them
382  // 3) loop through the vertices and keep track of distance to this vector
383  // 4) Sort the resulting list by furthest points and select the one we want
384  reco::ProjectedPointList::const_iterator extremePointListItr = clusterToBreak.getConvexHull().getConvexHullExtremePoints().begin();
385 
386  const reco::ClusterHit3D* firstEdgeHit = std::get<2>(*extremePointListItr++);
387  const reco::ClusterHit3D* secondEdgeHit = std::get<2>(*extremePointListItr);
388  Eigen::Vector3f edgeVec(secondEdgeHit->getPosition()[0] - firstEdgeHit->getPosition()[0],
389  secondEdgeHit->getPosition()[1] - firstEdgeHit->getPosition()[1],
390  secondEdgeHit->getPosition()[2] - firstEdgeHit->getPosition()[2]);
391  double edgeLen = edgeVec.norm();
392 
393  // normalize it
394  edgeVec.normalize();
395 
396  // Recover the list of 3D hits associated to this cluster
397  reco::HitPairListPtr& clusHitPairVector = clusterToBreak.getHitPairListPtr();
398 
399  // Calculate the doca to the PCA primary axis for each 3D hit
400  // Importantly, this also gives us the arclength along that axis to the hit
401  fPCAAlg.PCAAnalysis_calc3DDocas(clusHitPairVector, fullPCA);
402 
403  // Sort the hits along the PCA
404  clusHitPairVector.sort([](const auto& left, const auto& right){return left->getArclenToPoca() < right->getArclenToPoca();});
405 
406  // Set up container to keep track of edges
407  using DistEdgeTuple = std::tuple<float, const reco::EdgeTuple*>;
408  using DistEdgeTupleVec = std::vector<DistEdgeTuple>;
409 
410  DistEdgeTupleVec distEdgeTupleVec;
411 
412  // Now loop through all the edges and search for the furthers point
413  for(const auto& edge : clusterToBreak.getBestEdgeList())
414  {
415  const reco::ClusterHit3D* nextEdgeHit = std::get<0>(edge); // recover the first point
416 
417  // Create vector to this point from the longest edge
418  Eigen::Vector3f hitToEdgeVec(nextEdgeHit->getPosition()[0] - firstEdgeHit->getPosition()[0],
419  nextEdgeHit->getPosition()[1] - firstEdgeHit->getPosition()[1],
420  nextEdgeHit->getPosition()[2] - firstEdgeHit->getPosition()[2]);
421 
422  // Get projection
423  float hitProjection = hitToEdgeVec.dot(edgeVec);
424 
425  // Require that the point is really "opposite" the longest edge
426  if (hitProjection > 0. && hitProjection < edgeLen)
427  {
428  Eigen::Vector3f distToHitVec = hitToEdgeVec - hitProjection * edgeVec;
429  float distToHit = distToHitVec.norm();
430 
431  distEdgeTupleVec.emplace_back(distToHit,&edge);
432  }
433  }
434 
435  std::sort(distEdgeTupleVec.begin(),distEdgeTupleVec.end(),[](const auto& left,const auto& right){return std::get<0>(left) > std::get<0>(right);});
436 
437  for(const auto& distEdgeTuple : distEdgeTupleVec)
438  {
439  const reco::EdgeTuple& edgeTuple = *std::get<1>(distEdgeTuple);
440  const reco::ClusterHit3D* edgeHit = std::get<0>(edgeTuple);
441 
442  // Now find the hit identified above as furthest away
443  reco::HitPairListPtr::iterator vertexItr = std::find(clusHitPairVector.begin(),clusHitPairVector.end(),edgeHit);
444 
445  // Make sure enough hits either side, otherwise we just keep the current cluster
446  if (vertexItr == clusHitPairVector.end() || std::distance(clusHitPairVector.begin(),vertexItr) < minimumClusterSize || std::distance(vertexItr,clusHitPairVector.end()) < minimumClusterSize) continue;
447 
448  // Now we create a list of pairs of iterators to the start and end of each subcluster
449  using Hit3DItrPair = std::pair<reco::HitPairListPtr::iterator,reco::HitPairListPtr::iterator>;
450  using VertexPairList = std::list<Hit3DItrPair>;
451 
452  VertexPairList vertexPairList;
453 
454  vertexPairList.emplace_back(Hit3DItrPair(clusHitPairVector.begin(),vertexItr));
455  vertexPairList.emplace_back(Hit3DItrPair(vertexItr,clusHitPairVector.end()));
456 
457  storeCurrentCluster = false;
458 
459  // Ok, now loop through our pairs
460  for(auto& hit3DItrPair : vertexPairList)
461  {
462  reco::ClusterParameters clusterParams;
463  reco::HitPairListPtr& hitPairListPtr = clusterParams.getHitPairListPtr();
464 
465  std::cout << indent << "+> -- building new cluster, size: " << std::distance(hit3DItrPair.first,hit3DItrPair.second) << std::endl;
466 
467  // size the container...
468  hitPairListPtr.resize(std::distance(hit3DItrPair.first,hit3DItrPair.second));
469 
470  // and copy the hits into the container
471  std::copy(hit3DItrPair.first,hit3DItrPair.second,hitPairListPtr.begin());
472 
473  // First stage of feature extraction runs here
474  fPCAAlg.PCAAnalysis_3D(hitPairListPtr, clusterParams.getFullPCA());
475 
476  // Recover the new fullPCA
477  reco::PrincipalComponents& newFullPCA = clusterParams.getFullPCA();
478 
479  // Must have a valid pca
480  if (newFullPCA.getSvdOK())
481  {
482  std::cout << indent << "+> -- >> cluster has a valid Full PCA" << std::endl;
483 
484  // If the PCA's are opposite the flip the axes
485  if (fullPrimaryVec.dot(newFullPCA.getEigenVectors().row(2)) < 0.)
486  {
487  for(size_t vecIdx = 0; vecIdx < 3; vecIdx++) newFullPCA.flipAxis(vecIdx);
488  }
489 
490  // Set the skeleton PCA to make sure it has some value
491  clusterParams.getSkeletonPCA() = clusterParams.getFullPCA();
492 
493  // Be sure to compute the oonvex hull surrounding the now broken cluster
494  buildConvexHull(clusterParams, level+2);
495 
496  positionItr = breakIntoTinyBits(clusterParams, fullPCA, positionItr, outputClusterList, level+4);
497  }
498  }
499 
500  // If successful in breaking the cluster then we are done, otherwise try to loop
501  // again taking the next furthest hit
502  break;
503  }
504  }
505 
506  // First question, are we done breaking?
507  if (storeCurrentCluster)
508  {
509  // I think this is where we fill out the rest of the parameters?
510  // Start by adding the 2D hits...
511  // See if we can avoid duplicates by temporarily transferring to a set
512  std::set<const reco::ClusterHit2D*> hitSet;
513 
514  // Loop through 3D hits to get a set of unique 2D hits
515  for(const auto& hit3D : clusterToBreak.getHitPairListPtr())
516  {
517  for(const auto& hit2D : hit3D->getHits())
518  {
519  if (hit2D) hitSet.insert(hit2D);
520  }
521  }
522 
523  // Now add these to the new cluster
524  for(const auto& hit2D : hitSet)
525  {
526  hit2D->setStatusBit(reco::ClusterHit2D::USED);
527  clusterToBreak.UpdateParameters(hit2D);
528  }
529 
530  std::cout << indent << "*********>>> storing new subcluster of size " << clusterToBreak.getHitPairListPtr().size() << std::endl;
531 
532  positionItr = outputClusterList.insert(positionItr,clusterToBreak);
533 
534  // Are we filling histograms
535  if (fFillHistograms)
536  {
537  int num3DHits = clusterToBreak.getHitPairListPtr().size();
538  int numEdges = clusterToBreak.getBestEdgeList().size();
539  Eigen::Vector3f newPrimaryVec(fullPCA.getEigenVectors().row(2));
540  Eigen::Vector3f lastPrimaryVec(lastPCA.getEigenVectors().row(2));
541  float cosToLast = newPrimaryVec.dot(lastPrimaryVec);
542 
543  fSubNum3DHits->Fill(std::min(num3DHits,199), 1.);
544  fSubNumEdges->Fill(std::min(numEdges,199), 1.);
545  fSubEigen21Ratio->Fill(eigen2To1Ratio, 1.);
546  fSubEigen20Ratio->Fill(eigen2To0Ratio, 1.);
547  fSubEigen10Ratio->Fill(eigen1To0Ratio, 1.);
548  fSubCosToPrevPCA->Fill(cosToLast, 1.);
549  fSubPrimaryLength->Fill(std::min(eigenValVec[2],199.), 1.);
550  }
551 
552  // The above points to the element, want the next element
553  positionItr++;
554  }
555  else if (inputPositionItr != positionItr)
556  {
557  std::cout << indent << "***** DID NOT STORE A CLUSTER *****" << std::endl;
558  }
559 
560  return positionItr;
561 }
intermediate_table::iterator iterator
void PCAAnalysis_calc3DDocas(const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca) const
bool getSvdOK() const
Definition: Cluster3D.h:244
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
void flipAxis(size_t axis)
Definition: Cluster3D.cxx:208
std::string string
Definition: nybbler.cc:12
const Eigen::Vector3f getPosition() const
Definition: Cluster3D.h:158
reco::PrincipalComponents & getSkeletonPCA()
Definition: Cluster3D.h:478
intermediate_table::const_iterator const_iterator
reco::HitPairListPtr & getHitPairListPtr()
Definition: Cluster3D.h:476
T abs(T value)
const EigenValues & getEigenValues() const
Definition: Cluster3D.h:246
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:477
void buildConvexHull(reco::ClusterParameters &clusterParameters, int level=0) const
std::tuple< const reco::ClusterHit3D *, const reco::ClusterHit3D *, double > EdgeTuple
Definition: Cluster3D.h:344
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:335
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
reco::ClusterParametersList::iterator breakIntoTinyBits(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.
T copy(T const &v)
size_t fMinTinyClusterSize
Minimum size for a "tiny" cluster.
bool fFillHistograms
Histogram definitions.
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247
QTextStream & endl(QTextStream &s)
void lar_cluster3d::VoronoiPathFinder::buildConvexHull ( reco::ClusterParameters clusterParameters,
int  level = 0 
) const
private

Definition at line 861 of file VoronoiPathFinder_tool.cc.

862 {
863  // set an indention string
864  std::string minuses(level/2, '-');
865  std::string indent(level/2, ' ');
866 
867  indent += minuses;
868 
869  // The plan is to build the enclosing 2D polygon around the points in the PCA plane of most spread for this cluster
870  // To do so we need to start by building a list of 2D projections onto the plane of most spread...
871  reco::PrincipalComponents& pca = clusterParameters.getFullPCA();
872 
873  // Recover the parameters from the Principal Components Analysis that we need to project and accumulate
874  Eigen::Vector3f pcaCenter(pca.getAvePosition()[0],pca.getAvePosition()[1],pca.getAvePosition()[2]);
875 
876  //dcel2d::PointList pointList;
877  using Point = std::tuple<float,float,const reco::ClusterHit3D*>;
878  using PointList = std::list<Point>;
879 
880  reco::ConvexHull& convexHull = clusterParameters.getConvexHull();
881  PointList pointList = convexHull.getProjectedPointList();
882 
883  // Loop through hits and do projection to plane
884  for(const auto& hit3D : clusterParameters.getHitPairListPtr())
885  {
886  Eigen::Vector3f pcaToHitVec(hit3D->getPosition()[0] - pcaCenter(0),
887  hit3D->getPosition()[1] - pcaCenter(1),
888  hit3D->getPosition()[2] - pcaCenter(2));
889  Eigen::Vector3f pcaToHit = pca.getEigenVectors() * pcaToHitVec;
890 
891  pointList.emplace_back(dcel2d::Point(pcaToHit(0),pcaToHit(1),hit3D));
892  }
893 
894  // Sort the point vec by increasing x, then increase y
895  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);});
896 
897  // containers for finding the "best" hull...
898  std::vector<ConvexHull> convexHullVec;
899  std::vector<PointList> rejectedListVec;
900  bool increaseDepth(pointList.size() > 5);
901  float lastArea(std::numeric_limits<float>::max());
902 
903  while(increaseDepth)
904  {
905  // Get another convexHull container
906  convexHullVec.push_back(ConvexHull(pointList));
907  rejectedListVec.push_back(PointList());
908 
909  const ConvexHull& convexHull = convexHullVec.back();
910  PointList& rejectedList = rejectedListVec.back();
911  const PointList& convexHullPoints = convexHull.getConvexHull();
912 
913  increaseDepth = false;
914 
915  if (convexHull.getConvexHullArea() > 0.)
916  {
917  std::cout << indent << "-> built convex hull, 3D hits: " << pointList.size() << " with " << convexHullPoints.size() << " vertices" << ", area: " << convexHull.getConvexHullArea() << std::endl;
918  std::cout << indent << "-> -Points:";
919  for(const auto& point : convexHullPoints)
920  std::cout << " (" << std::get<0>(point) << "," << std::get<1>(point) << ")";
921  std::cout << std::endl;
922 
923  if (convexHullVec.size() < 2 || convexHull.getConvexHullArea() < 0.8 * lastArea)
924  {
925  for(auto& point : convexHullPoints)
926  {
927  pointList.remove(point);
928  rejectedList.emplace_back(point);
929  }
930  lastArea = convexHull.getConvexHullArea();
931 // increaseDepth = true;
932  }
933  }
934  }
935 
936  // do we have a valid convexHull?
937  while(!convexHullVec.empty() && convexHullVec.back().getConvexHullArea() < 0.5)
938  {
939  convexHullVec.pop_back();
940  rejectedListVec.pop_back();
941  }
942 
943  // If we found the convex hull then build edges around the region
944  if (!convexHullVec.empty())
945  {
946  size_t nRejectedTotal(0);
947  reco::HitPairListPtr hitPairListPtr = clusterParameters.getHitPairListPtr();
948 
949  for(const auto& rejectedList : rejectedListVec)
950  {
951  nRejectedTotal += rejectedList.size();
952 
953  for(const auto& rejectedPoint : rejectedList)
954  {
955  std::cout << indent << "-> -- Point is " << convexHullVec.back().findNearestDistance(rejectedPoint) << " from nearest edge" << std::endl;
956 
957  if (convexHullVec.back().findNearestDistance(rejectedPoint) > 0.5)
958  hitPairListPtr.remove(std::get<2>(rejectedPoint));
959  }
960  }
961 
962  std::cout << indent << "-> Removed " << nRejectedTotal << " leaving " << pointList.size() << "/" << hitPairListPtr.size() << " points" << std::endl;
963 
964  // Now add "edges" to the cluster to describe the convex hull (for the display)
965  reco::Hit3DToEdgeMap& edgeMap = convexHull.getConvexHullEdgeMap();
966  reco::EdgeList& bestEdgeList = convexHull.getConvexHullEdgeList();
967 
968  Point lastPoint = convexHullVec.back().getConvexHull().front();
969 
970  for(auto& curPoint : convexHullVec.back().getConvexHull())
971  {
972  if (curPoint == lastPoint) continue;
973 
974  const reco::ClusterHit3D* lastPoint3D = std::get<2>(lastPoint);
975  const reco::ClusterHit3D* curPoint3D = std::get<2>(curPoint);
976 
977  float distBetweenPoints = (curPoint3D->getPosition()[0] - lastPoint3D->getPosition()[0]) * (curPoint3D->getPosition()[0] - lastPoint3D->getPosition()[0])
978  + (curPoint3D->getPosition()[1] - lastPoint3D->getPosition()[1]) * (curPoint3D->getPosition()[1] - lastPoint3D->getPosition()[1])
979  + (curPoint3D->getPosition()[2] - lastPoint3D->getPosition()[2]) * (curPoint3D->getPosition()[2] - lastPoint3D->getPosition()[2]);
980 
981  distBetweenPoints = std::sqrt(distBetweenPoints);
982 
983  reco::EdgeTuple edge(lastPoint3D,curPoint3D,distBetweenPoints);
984 
985  edgeMap[lastPoint3D].push_back(edge);
986  edgeMap[curPoint3D].push_back(edge);
987  bestEdgeList.emplace_back(edge);
988 
989  lastPoint = curPoint;
990  }
991 
992  // Store the "extreme" points
993  const ConvexHull::PointList& extremePoints = convexHullVec.back().getExtremePoints();
994  reco::ProjectedPointList& extremePointList = convexHull.getConvexHullExtremePoints();
995 
996  for(const auto& point : extremePoints) extremePointList.push_back(point);
997  }
998 
999  return;
1000 }
std::string string
Definition: nybbler.cc:12
const Eigen::Vector3f getPosition() const
Definition: Cluster3D.h:158
std::list< ProjectedPoint > ProjectedPointList
Definition: Cluster3D.h:353
std::list< Point > PointList
The list of the projected points.
Definition: ConvexHull.h:34
reco::HitPairListPtr & getHitPairListPtr()
Definition: Cluster3D.h:476
T abs(T value)
std::list< EdgeTuple > EdgeList
Definition: Cluster3D.h:345
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:477
std::tuple< double, double, const reco::ClusterHit3D * > Point
Definitions used by the VoronoiDiagram algorithm.
Definition: DCEL.h:44
Define a container for working with the convex hull.
Definition: Cluster3D.h:360
const Eigen::Vector3f & getAvePosition() const
Definition: Cluster3D.h:248
std::tuple< const reco::ClusterHit3D *, const reco::ClusterHit3D *, double > EdgeTuple
Definition: Cluster3D.h:344
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:335
static int max(int a, int b)
reco::ConvexHull & getConvexHull()
Definition: Cluster3D.h:482
std::unordered_map< const reco::ClusterHit3D *, reco::EdgeList > Hit3DToEdgeMap
Definition: Cluster3D.h:347
reco::ProjectedPointList & getProjectedPointList()
Definition: Cluster3D.h:383
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247
QTextStream & endl(QTextStream &s)
void lar_cluster3d::VoronoiPathFinder::buildVoronoiDiagram ( reco::ClusterParameters clusterParameters,
int  level = 0 
) const
private

Definition at line 1003 of file VoronoiPathFinder_tool.cc.

1004 {
1005  // The plan is to build the enclosing 2D polygon around the points in the PCA plane of most spread for this cluster
1006  // To do so we need to start by building a list of 2D projections onto the plane of most spread...
1007  reco::PrincipalComponents& pca = clusterParameters.getFullPCA();
1008 
1009  // Recover the parameters from the Principal Components Analysis that we need to project and accumulate
1010  Eigen::Vector3f pcaCenter(pca.getAvePosition()[0],pca.getAvePosition()[1],pca.getAvePosition()[2]);
1011 
1012  dcel2d::PointList pointList;
1013 
1014  // Loop through hits and do projection to plane
1015  for(const auto& hit3D : clusterParameters.getHitPairListPtr())
1016  {
1017  Eigen::Vector3f pcaToHitVec(hit3D->getPosition()[0] - pcaCenter(0),
1018  hit3D->getPosition()[1] - pcaCenter(1),
1019  hit3D->getPosition()[2] - pcaCenter(2));
1020  Eigen::Vector3f pcaToHit = pca.getEigenVectors() * pcaToHitVec;
1021 
1022  pointList.emplace_back(dcel2d::Point(pcaToHit(1),pcaToHit(2),hit3D));
1023  }
1024 
1025  // Sort the point vec by increasing x, then increase y
1026  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);});
1027 
1028  std::cout << " ==> Build V diagram, sorted point list contains " << pointList.size() << " hits" << std::endl;
1029 
1030  // Set up the voronoi diagram builder
1031  voronoi2d::VoronoiDiagram voronoiDiagram(clusterParameters.getHalfEdgeList(),clusterParameters.getVertexList(),clusterParameters.getFaceList());
1032 
1033  // And make the diagram
1034  voronoiDiagram.buildVoronoiDiagram(pointList);
1035 
1036  // Recover the voronoi diagram vertex list and the container to store them in
1037  dcel2d::VertexList& vertexList = clusterParameters.getVertexList();
1038 
1039  // Now get the inverse of the rotation matrix so we can get the vertex positions,
1040  // which lie in the plane of the two largest PCA axes, in the standard coordinate system
1041  Eigen::Matrix3f rotationMatrixInv = pca.getEigenVectors().inverse();
1042 
1043  // Translate and fill
1044  for(auto& vertex : vertexList)
1045  {
1046  Eigen::Vector3f coords = rotationMatrixInv * vertex.getCoords();
1047 
1048  coords += pcaCenter;
1049 
1050  vertex.setCoords(coords);
1051  }
1052 
1053  // Now do the Convex Hull
1054  // Now add "edges" to the cluster to describe the convex hull (for the display)
1055  reco::Hit3DToEdgeMap& edgeMap = clusterParameters.getHit3DToEdgeMap();
1056  reco::EdgeList& bestEdgeList = clusterParameters.getBestEdgeList();
1057 
1058 // const dcel2d::PointList& edgePoints = voronoiDiagram.getConvexHull();
1059 // PointList localList;
1060 //
1061 // for(const auto& edgePoint : edgePoints) localList.emplace_back(std::get<0>(edgePoint),std::get<1>(edgePoint),std::get<2>(edgePoint));
1062 //
1063 // // Sort the point vec by increasing x, then increase y
1064 // localList.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);});
1065 //
1066 // // Why do I need to do this?
1067 // ConvexHull convexHull(localList);
1068 //
1069 // Point lastPoint = convexHull.getConvexHull().front();
1070  dcel2d::Point lastPoint = voronoiDiagram.getConvexHull().front();
1071 
1072 // std::cout << "@@@@>> Build convex hull, voronoi handed " << edgePoints.size() << " points, convexHull cut to " << convexHull.getConvexHull().size() << std::endl;
1073 
1074 // for(auto& curPoint : convexHull.getConvexHull())
1075  for(auto& curPoint : voronoiDiagram.getConvexHull())
1076  {
1077  if (curPoint == lastPoint) continue;
1078 
1079  const reco::ClusterHit3D* lastPoint3D = std::get<2>(lastPoint);
1080  const reco::ClusterHit3D* curPoint3D = std::get<2>(curPoint);
1081 
1082  float distBetweenPoints = (curPoint3D->getPosition()[0] - lastPoint3D->getPosition()[0]) * (curPoint3D->getPosition()[0] - lastPoint3D->getPosition()[0])
1083  + (curPoint3D->getPosition()[1] - lastPoint3D->getPosition()[1]) * (curPoint3D->getPosition()[1] - lastPoint3D->getPosition()[1])
1084  + (curPoint3D->getPosition()[2] - lastPoint3D->getPosition()[2]) * (curPoint3D->getPosition()[2] - lastPoint3D->getPosition()[2]);
1085 
1086  distBetweenPoints = std::sqrt(distBetweenPoints);
1087 
1088  reco::EdgeTuple edge(lastPoint3D,curPoint3D,distBetweenPoints);
1089 
1090  edgeMap[lastPoint3D].push_back(edge);
1091  edgeMap[curPoint3D].push_back(edge);
1092  bestEdgeList.emplace_back(edge);
1093 
1094  lastPoint = curPoint;
1095  }
1096 
1097  std::cout << "****> vertexList containted " << vertexList.size() << " vertices for " << clusterParameters.getHitPairListPtr().size() << " hits" << std::endl;
1098 
1099  return;
1100 }
const Eigen::Vector3f getPosition() const
Definition: Cluster3D.h:158
reco::EdgeList & getBestEdgeList()
Definition: Cluster3D.h:481
reco::Hit3DToEdgeMap & getHit3DToEdgeMap()
Definition: Cluster3D.h:479
reco::HitPairListPtr & getHitPairListPtr()
Definition: Cluster3D.h:476
T abs(T value)
std::list< EdgeTuple > EdgeList
Definition: Cluster3D.h:345
VoronoiDiagram class definiton.
Definition: Voronoi.h:31
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:477
std::tuple< double, double, const reco::ClusterHit3D * > Point
Definitions used by the VoronoiDiagram algorithm.
Definition: DCEL.h:44
void buildVoronoiDiagram(const dcel2d::PointList &)
Given an input set of 2D points construct a 2D voronoi diagram.
Definition: Voronoi.cxx:133
const Eigen::Vector3f & getAvePosition() const
Definition: Cluster3D.h:248
std::tuple< const reco::ClusterHit3D *, const reco::ClusterHit3D *, double > EdgeTuple
Definition: Cluster3D.h:344
dcel2d::FaceList & getFaceList()
Definition: Cluster3D.h:483
std::list< Point > PointList
Definition: DCEL.h:45
std::unordered_map< const reco::ClusterHit3D *, reco::EdgeList > Hit3DToEdgeMap
Definition: Cluster3D.h:347
dcel2d::HalfEdgeList & getHalfEdgeList()
Definition: Cluster3D.h:485
std::list< Vertex > VertexList
Definition: DCEL.h:182
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247
QTextStream & endl(QTextStream &s)
dcel2d::VertexList & getVertexList()
Definition: Cluster3D.h:484
vertex reconstruction
float lar_cluster3d::VoronoiPathFinder::closestApproach ( const Eigen::Vector3f &  P0,
const Eigen::Vector3f &  u0,
const Eigen::Vector3f &  P1,
const Eigen::Vector3f &  u1,
Eigen::Vector3f &  poca0,
Eigen::Vector3f &  poca1 
) const
private

Definition at line 1103 of file VoronoiPathFinder_tool.cc.

1109 {
1110  // Technique is to compute the arclength to each point of closest approach
1111  Eigen::Vector3f w0 = P0 - P1;
1112  float a(1.);
1113  float b(u0.dot(u1));
1114  float c(1.);
1115  float d(u0.dot(w0));
1116  float e(u1.dot(w0));
1117  float den(a * c - b * b);
1118 
1119  float arcLen0 = (b * e - c * d) / den;
1120  float arcLen1 = (a * e - b * d) / den;
1121 
1122  poca0 = P0 + arcLen0 * u0;
1123  poca1 = P1 + arcLen1 * u1;
1124 
1125  return (poca0 - poca1).norm();
1126 }
const double e
const double a
static bool * b
Definition: config.cpp:1043
void lar_cluster3d::VoronoiPathFinder::configure ( fhicl::ParameterSet const &  pset)
override

Definition at line 176 of file VoronoiPathFinder_tool.cc.

177 {
178  fEnableMonitoring = pset.get<bool> ("EnableMonitoring", true );
179  fMinTinyClusterSize = pset.get<size_t>("MinTinyClusterSize",40);
180  fClusterAlg = art::make_tool<lar_cluster3d::IClusterAlg>(pset.get<fhicl::ParameterSet>("ClusterAlg"));
181 
182  fTimeToProcess = 0.;
183 
184  return;
185 }
std::unique_ptr< lar_cluster3d::IClusterAlg > fClusterAlg
Tools.
size_t fMinTinyClusterSize
Minimum size for a "tiny" cluster.
float lar_cluster3d::VoronoiPathFinder::findConvexHullEndPoints ( const reco::EdgeList convexHull,
const reco::ClusterHit3D first3D,
const reco::ClusterHit3D last3D 
) const
private

Definition at line 1128 of file VoronoiPathFinder_tool.cc.

1129 {
1130  float largestDistance(0.);
1131 
1132  // Note that edges are vectors and that the convex hull edge list will be ordered
1133  // The idea is that the maximum distance from a given edge is to the edge just before the edge that "turns back" towards the current edge
1134  // meaning that the dot product of the two edges becomes negative.
1135  reco::EdgeList::const_iterator firstEdgeItr = convexHull.begin();
1136 
1137  while(firstEdgeItr != convexHull.end())
1138  {
1139  reco::EdgeList::const_iterator nextEdgeItr = firstEdgeItr;
1140 
1141 // Eigen::Vector2f firstEdgeVec(std::get<3>(*firstEdgeItr),std::get<);
1142 // Eigen::Vector2f lastPrimaryVec(lastPCA.getEigenVectors()[0][0],lastPCA.getEigenVectors()[0][1],lastPCA.getEigenVectors()[0][2]);
1143 // float cosToLast = newPrimaryVec.dot(lastPrimaryVec);
1144 
1145  while(++nextEdgeItr != convexHull.end())
1146  {
1147 
1148  }
1149  }
1150 
1151  return largestDistance;
1152 }
intermediate_table::const_iterator const_iterator
float lar_cluster3d::VoronoiPathFinder::getTimeToExecute ( ) const
inlineoverridevirtual

If monitoring, recover the time to execute a particular function.

Implements lar_cluster3d::IClusterModAlg.

Definition at line 75 of file VoronoiPathFinder_tool.cc.

void lar_cluster3d::VoronoiPathFinder::initializeHistograms ( art::TFileDirectory &  histDir)
overridevirtual

Interface for initializing histograms if they are desired Note that the idea is to put hisgtograms in a subfolder.

Parameters
TFileDirectory- the folder to store the hists in

Implements lar_cluster3d::IClusterModAlg.

Definition at line 187 of file VoronoiPathFinder_tool.cc.

188 {
189  // It is assumed that the input TFileDirectory has been set up to group histograms into a common
190  // folder at the calling routine's level. Here we create one more level of indirection to keep
191  // histograms made by this tool separate.
192  fFillHistograms = true;
193 
194  std::string dirName = "VoronoiPath";
195 
196  art::TFileDirectory dir = histDir.mkdir(dirName.c_str());
197 
198  // Divide into two sets of hists... those for the overall cluster and
199  // those for the subclusters
200  fTopNum3DHits = dir.make<TH1F>("TopNum3DHits", "Number 3D Hits", 200, 0., 200.);
201  fTopNumEdges = dir.make<TH1F>("TopNumEdges", "Number Edges", 200, 0., 200.);
202  fTopEigen21Ratio = dir.make<TH1F>("TopEigen21Rat", "Eigen 2/1 Ratio", 100, 0., 1.);
203  fTopEigen20Ratio = dir.make<TH1F>("TopEigen20Rat", "Eigen 2/0 Ratio", 100, 0., 1.);
204  fTopEigen10Ratio = dir.make<TH1F>("TopEigen10Rat", "Eigen 1/0 Ratio", 100, 0., 1.);
205  fTopPrimaryLength = dir.make<TH1F>("TopPrimaryLen", "Primary Length", 200, 0., 200.);
206 
207  fSubNum3DHits = dir.make<TH1F>("SubNum3DHits", "Number 3D Hits", 200, 0., 200.);
208  fSubNumEdges = dir.make<TH1F>("SubNumEdges", "Number Edges", 200, 0., 200.);
209  fSubEigen21Ratio = dir.make<TH1F>("SubEigen21Rat", "Eigen 2/1 Ratio", 100, 0., 1.);
210  fSubEigen20Ratio = dir.make<TH1F>("SubEigen20Rat", "Eigen 2/0 Ratio", 100, 0., 1.);
211  fSubEigen10Ratio = dir.make<TH1F>("SubEigen10Rat", "Eigen 1/0 Ratio", 100, 0., 1.);
212  fSubPrimaryLength = dir.make<TH1F>("SubPrimaryLen", "Primary Length", 200, 0., 200.);
213  fSubCosToPrevPCA = dir.make<TH1F>("SubCosToPrev", "Cos(theta)", 101, 0., 1.01);
214  fSubCosExtToPCA = dir.make<TH1F>("SubCosExtPCA", "Cos(theta)", 102, -1.01, 1.01);
215  fSubMaxDefect = dir.make<TH1F>("SubMaxDefect", "Max Defect", 100, 0., 50.);
216  fSubUsedDefect = dir.make<TH1F>("SubUsedDefect", "Used Defect", 100, 0., 50.);
217 
218  return;
219 }
std::string string
Definition: nybbler.cc:12
string dir
bool fFillHistograms
Histogram definitions.
bool lar_cluster3d::VoronoiPathFinder::makeCandidateCluster ( Eigen::Vector3f &  primaryPCA,
reco::ClusterParameters candCluster,
reco::HitPairListPtr::iterator  firstHitItr,
reco::HitPairListPtr::iterator  lastHitItr,
int  level 
) const
private

Definition at line 787 of file VoronoiPathFinder_tool.cc.

792 {
793  std::string indent(level/2, ' ');
794 
795  reco::HitPairListPtr& hitPairListPtr = candCluster.getHitPairListPtr();
796 
797  std::cout << indent << "+> -- building new cluster, size: " << std::distance(firstHitItr,lastHitItr) << std::endl;
798 
799  // size the container...
800  hitPairListPtr.resize(std::distance(firstHitItr,lastHitItr));
801 
802  // and copy the hits into the container
803  std::copy(firstHitItr,lastHitItr,hitPairListPtr.begin());
804 
805  // First stage of feature extraction runs here
806  fPCAAlg.PCAAnalysis_3D(hitPairListPtr, candCluster.getFullPCA());
807 
808  // Recover the new fullPCA
809  reco::PrincipalComponents& newFullPCA = candCluster.getFullPCA();
810 
811  // Will we want to store this cluster?
812  bool keepThisCluster(false);
813 
814  // Must have a valid pca
815  if (newFullPCA.getSvdOK())
816  {
817  std::cout << indent << "+> -- >> cluster has a valid Full PCA" << std::endl;
818 
819  // Need to check if the PCA direction has been reversed
820  Eigen::Vector3f newPrimaryVec(newFullPCA.getEigenVectors().row(2));
821 
822  // If the PCA's are opposite the flip the axes
823  if (primaryPCA.dot(newPrimaryVec) < 0.)
824  {
825  for(size_t vecIdx = 0; vecIdx < 3; vecIdx++) newFullPCA.flipAxis(vecIdx);
826 
827  newPrimaryVec = Eigen::Vector3f(newFullPCA.getEigenVectors().row(2));
828  }
829 
830  // Set the skeleton PCA to make sure it has some value
831  candCluster.getSkeletonPCA() = candCluster.getFullPCA();
832 
833  // Be sure to compute the oonvex hull surrounding the now broken cluster
834  buildConvexHull(candCluster, level+2);
835 
836  std::vector<double> eigenValVec = {3. * std::sqrt(newFullPCA.getEigenValues()[0]),
837  3. * std::sqrt(newFullPCA.getEigenValues()[1]),
838  3. * std::sqrt(newFullPCA.getEigenValues()[2])};
839  double cosNewToLast = std::abs(primaryPCA.dot(newPrimaryVec));
840  double eigen2To1Ratio = eigenValVec[2] / eigenValVec[1];
841  double eigen1To0Ratio = eigenValVec[1] / eigenValVec[2];
842  double eigen2To0Ratio = eigenValVec[0] / eigenValVec[2];
843  double eigen2And1Ave = 0.5 * (eigenValVec[1] + eigenValVec[0]);
844  double eigenAveTo0Ratio = eigen2And1Ave / eigenValVec[2];
845 
846  std::cout << indent << ">>> subDivideClusters with " << candCluster.getHitPairListPtr().size() << " input hits, " << candCluster.getBestEdgeList().size() << " edges, rat21: " << eigen2To1Ratio << ", rat20: " << eigen2To0Ratio << ", rat10: " << eigen1To0Ratio << ", ave0: " << eigenAveTo0Ratio << std::endl;
847  std::cout << indent << " --> eigen 0/1/2: " << eigenValVec[0] << "/" << eigenValVec[1] << "/" << eigenValVec[2] << ", cos: " << cosNewToLast << std::endl;
848 
849  // Create a rough cut intended to tell us when we've reached the land of diminishing returns
850 // if (candCluster.getBestEdgeList().size() > 4 && cosNewToLast > 0.25 && eigen2To1Ratio < 0.9 && eigen2To0Ratio > 0.001)
851  if (candCluster.getBestEdgeList().size() > 4 && cosNewToLast > 0.25 && eigen2To1Ratio > 0.01 && eigen2To1Ratio < 0.99 && eigen1To0Ratio < 0.5)
852  {
853  keepThisCluster = true;
854  }
855  }
856 
857  return keepThisCluster;
858 }
bool getSvdOK() const
Definition: Cluster3D.h:244
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
void flipAxis(size_t axis)
Definition: Cluster3D.cxx:208
std::string string
Definition: nybbler.cc:12
reco::PrincipalComponents & getSkeletonPCA()
Definition: Cluster3D.h:478
reco::EdgeList & getBestEdgeList()
Definition: Cluster3D.h:481
reco::HitPairListPtr & getHitPairListPtr()
Definition: Cluster3D.h:476
T abs(T value)
const EigenValues & getEigenValues() const
Definition: Cluster3D.h:246
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:477
void buildConvexHull(reco::ClusterParameters &clusterParameters, int level=0) const
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:335
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
T copy(T const &v)
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247
QTextStream & endl(QTextStream &s)
void lar_cluster3d::VoronoiPathFinder::ModifyClusters ( reco::ClusterParametersList clusterParametersList) const
overridevirtual

Scan an input collection of clusters and modify those according to the specific implementing algorithm.

Parameters
clusterParametersListA list of cluster objects (parameters from associated hits)

Top level interface for algorithm to consider pairs of clusters from the input list and determine if they are consistent with each other and, therefore, should be merged. This is done by looking at the PCA for each cluster and looking at the projection of the primary axis along the vector connecting their centers.

Implements lar_cluster3d::IClusterModAlg.

Definition at line 221 of file VoronoiPathFinder_tool.cc.

222 {
223  /**
224  * @brief Top level interface for algorithm to consider pairs of clusters from the input
225  * list and determine if they are consistent with each other and, therefore, should
226  * be merged. This is done by looking at the PCA for each cluster and looking at the
227  * projection of the primary axis along the vector connecting their centers.
228  */
229 
230  // Initial clustering is done, now trim the list and get output parameters
231  cet::cpu_timer theClockBuildClusters;
232 
233  // Start clocks if requested
234  if (fEnableMonitoring) theClockBuildClusters.start();
235 
236  int countClusters(0);
237 
238  // This is the loop over candidate 3D clusters
239  // Note that it might be that the list of candidate clusters is modified by splitting
240  // So we use the following construct to make sure we get all of them
241  reco::ClusterParametersList::iterator clusterParametersListItr = clusterParametersList.begin();
242 
243  while(clusterParametersListItr != clusterParametersList.end())
244  {
245  // Dereference to get the cluster paramters
246  reco::ClusterParameters& clusterParameters = *clusterParametersListItr;
247 
248  std::cout << "**> Looking at Cluster " << countClusters++ << ", # hits: " << clusterParameters.getHitPairListPtr().size() << std::endl;
249 
250  // It turns out that computing the convex hull surrounding the points in the 2D projection onto the
251  // plane of largest spread in the PCA is a good way to break up the cluster... and we do it here since
252  // we (currently) want this to be part of the standard output
253  buildVoronoiDiagram(clusterParameters);
254 
255  // Make sure our cluster has enough hits...
256  if (clusterParameters.getHitPairListPtr().size() > fMinTinyClusterSize)
257  {
258  // Get an interim cluster list
259  reco::ClusterParametersList reclusteredParameters;
260 
261  // Call the main workhorse algorithm for building the local version of candidate 3D clusters
262  //******** Remind me why we need to call this at this point when the same hits will be used? ********
263  //fClusterAlg->Cluster3DHits(clusterParameters.getHitPairListPtr(), reclusteredParameters);
264  reclusteredParameters.push_back(clusterParameters);
265 
266  std::cout << ">>>>>>>>>>> Reclustered to " << reclusteredParameters.size() << " Clusters <<<<<<<<<<<<<<<" << std::endl;
267 
268  // Only process non-empty results
269  if (!reclusteredParameters.empty())
270  {
271  // Loop over the reclustered set
272  for (auto& cluster : reclusteredParameters)
273  {
274  std::cout << "****> Calling breakIntoTinyBits with " << cluster.getHitPairListPtr().size() << " hits" << std::endl;
275 
276  // It turns out that computing the convex hull surrounding the points in the 2D projection onto the
277  // plane of largest spread in the PCA is a good way to break up the cluster... and we do it here since
278  // we (currently) want this to be part of the standard output
280 
281  // Break our cluster into smaller elements...
282  subDivideCluster(cluster, cluster.getFullPCA(), cluster.daughterList().end(), cluster.daughterList(), 4);
283 
284  std::cout << "****> Broke Cluster with " << cluster.getHitPairListPtr().size() << " into " << cluster.daughterList().size() << " sub clusters";
285  for(auto& clus : cluster.daughterList()) std::cout << ", " << clus.getHitPairListPtr().size();
286  std::cout << std::endl;
287 
288  // Add the daughters to the cluster
289  clusterParameters.daughterList().insert(clusterParameters.daughterList().end(),cluster);
290 
291  // If filling histograms we do the main cluster here
292  if (fFillHistograms)
293  {
294  reco::PrincipalComponents& fullPCA = cluster.getFullPCA();
295  std::vector<double> eigenValVec = {3. * std::sqrt(fullPCA.getEigenValues()[0]),
296  3. * std::sqrt(fullPCA.getEigenValues()[1]),
297  3. * std::sqrt(fullPCA.getEigenValues()[2])};
298  double eigen2To1Ratio = eigenValVec[0] / eigenValVec[1];
299  double eigen1To0Ratio = eigenValVec[1] / eigenValVec[2];
300  double eigen2To0Ratio = eigenValVec[0] / eigenValVec[2];
301  int num3DHits = cluster.getHitPairListPtr().size();
302  int numEdges = cluster.getBestEdgeList().size();
303 
304  fTopNum3DHits->Fill(std::min(num3DHits,199), 1.);
305  fTopNumEdges->Fill(std::min(numEdges,199), 1.);
306  fTopEigen21Ratio->Fill(eigen2To1Ratio, 1.);
307  fTopEigen20Ratio->Fill(eigen2To0Ratio, 1.);
308  fTopEigen10Ratio->Fill(eigen1To0Ratio, 1.);
309  fTopPrimaryLength->Fill(std::min(eigenValVec[0],199.), 1.);
310  }
311  }
312  }
313  }
314 
315  // Go to next cluster parameters object
316  clusterParametersListItr++;
317  }
318 
319  if (fEnableMonitoring)
320  {
321  theClockBuildClusters.stop();
322 
323  fTimeToProcess = theClockBuildClusters.accumulated_real_time();
324  }
325 
326  mf::LogDebug("Cluster3D") << ">>>>> Cluster Path finding done" << std::endl;
327 
328  return;
329 }
intermediate_table::iterator iterator
void cluster(In first, In last, Out result, Pred *pred)
Definition: NNClusters.h:41
reco::HitPairListPtr & getHitPairListPtr()
Definition: Cluster3D.h:476
Cluster finding and building.
ClusterParametersList & daughterList()
Definition: Cluster3D.h:450
const EigenValues & getEigenValues() const
Definition: Cluster3D.h:246
void buildConvexHull(reco::ClusterParameters &clusterParameters, int level=0) const
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.
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
void buildVoronoiDiagram(reco::ClusterParameters &clusterParameters, int level=0) const
size_t fMinTinyClusterSize
Minimum size for a "tiny" cluster.
double accumulated_real_time() const
Definition: cpu_timer.cc:66
void start()
Definition: cpu_timer.cc:83
bool fFillHistograms
Histogram definitions.
std::list< ClusterParameters > ClusterParametersList
Definition: Cluster3D.h:404
QTextStream & endl(QTextStream &s)
reco::ClusterParametersList::iterator lar_cluster3d::VoronoiPathFinder::subDivideCluster ( reco::ClusterParameters cluster,
reco::PrincipalComponents lastPCA,
reco::ClusterParametersList::iterator  positionItr,
reco::ClusterParametersList outputClusterList,
int  level = 0 
) const
private

Use PCA to try to find path in cluster.

Parameters
clusterParametersThe given cluster parameters object to try to split
clusterParametersListThe list of clusters

Definition at line 563 of file VoronoiPathFinder_tool.cc.

568 {
569  // This is a recursive routine to divide an input cluster, according to the maximum defect point of
570  // the convex hull until we reach the point of no further improvement.
571  // The assumption is that the input cluster is fully formed already, this routine then simply
572  // divides, if successful division into two pieces it then stores the results
573 
574  // No point in doing anything if we don't have enough space points
575  if (clusterToBreak.getHitPairListPtr().size() > size_t(2 * fMinTinyClusterSize))
576  {
577  // set an indention string
578  std::string pluses(level/2, '+');
579  std::string indent(level/2, ' ');
580 
581  indent += pluses;
582 
583  // To make best use of this we'll also want the PCA for this cluster... so...
584  // Recover the prime ingredients
585  reco::PrincipalComponents& fullPCA = clusterToBreak.getFullPCA();
586  std::vector<double> eigenValVec = {3. * std::sqrt(fullPCA.getEigenValues()[0]),
587  3. * std::sqrt(fullPCA.getEigenValues()[1]),
588  3. * std::sqrt(fullPCA.getEigenValues()[2])};
589  Eigen::Vector3f fullPrimaryVec(fullPCA.getEigenVectors().row(2));
590 
591  // We want to find the convex hull vertices that lie furthest from the line to/from the extreme points
592  // To find these we:
593  // 1) recover the extreme points
594  // 2) form the vector between them
595  // 3) loop through the vertices and keep track of distance to this vector
596  // 4) Sort the resulting list by furthest points and select the one we want
597  reco::ProjectedPointList::const_iterator extremePointListItr = clusterToBreak.getConvexHull().getConvexHullExtremePoints().begin();
598 
599  const reco::ClusterHit3D* firstEdgeHit = std::get<2>(*extremePointListItr++);
600  const reco::ClusterHit3D* secondEdgeHit = std::get<2>(*extremePointListItr);
601  Eigen::Vector3f edgeVec(secondEdgeHit->getPosition()[0] - firstEdgeHit->getPosition()[0],
602  secondEdgeHit->getPosition()[1] - firstEdgeHit->getPosition()[1],
603  secondEdgeHit->getPosition()[2] - firstEdgeHit->getPosition()[2]);
604  double edgeLen = edgeVec.norm();
605 
606  // normalize it
607  edgeVec.normalize();
608 
609  // Recover the list of 3D hits associated to this cluster
610  reco::HitPairListPtr& clusHitPairVector = clusterToBreak.getHitPairListPtr();
611 
612  // Calculate the doca to the PCA primary axis for each 3D hit
613  // Importantly, this also gives us the arclength along that axis to the hit
614  fPCAAlg.PCAAnalysis_calc3DDocas(clusHitPairVector, fullPCA);
615 
616  // Sort the hits along the PCA
617  clusHitPairVector.sort([](const auto& left, const auto& right){return left->getArclenToPoca() < right->getArclenToPoca();});
618 
619  // Set up container to keep track of edges
620  using DistEdgeTuple = std::tuple<float, const reco::EdgeTuple*>;
621  using DistEdgeTupleVec = std::vector<DistEdgeTuple>;
622 
623  DistEdgeTupleVec distEdgeTupleVec;
624 
625  // Now loop through all the edges and search for the furthers point
626  for(const auto& edge : clusterToBreak.getBestEdgeList())
627  {
628  const reco::ClusterHit3D* nextEdgeHit = std::get<0>(edge); // recover the first point
629 
630  // Create vector to this point from the longest edge
631  Eigen::Vector3f hitToEdgeVec(nextEdgeHit->getPosition()[0] - firstEdgeHit->getPosition()[0],
632  nextEdgeHit->getPosition()[1] - firstEdgeHit->getPosition()[1],
633  nextEdgeHit->getPosition()[2] - firstEdgeHit->getPosition()[2]);
634 
635  // Get projection
636  float hitProjection = hitToEdgeVec.dot(edgeVec);
637 
638  // Require that the point is really "opposite" the longest edge
639  if (hitProjection > 0. && hitProjection < edgeLen)
640  {
641  Eigen::Vector3f distToHitVec = hitToEdgeVec - hitProjection * edgeVec;
642  float distToHit = distToHitVec.norm();
643 
644  distEdgeTupleVec.emplace_back(distToHit,&edge);
645  }
646  }
647 
648  std::sort(distEdgeTupleVec.begin(),distEdgeTupleVec.end(),[](const auto& left,const auto& right){return std::get<0>(left) > std::get<0>(right);});
649 
650  // Get a temporary container to hol
651  reco::ClusterParametersList tempClusterParametersList;
652  float usedDefectDist(0.);
653 
654  for(const auto& distEdgeTuple : distEdgeTupleVec)
655  {
656  const reco::EdgeTuple& edgeTuple = *std::get<1>(distEdgeTuple);
657  const reco::ClusterHit3D* edgeHit = std::get<0>(edgeTuple);
658 
659  usedDefectDist = std::get<0>(distEdgeTuple);
660 
661  // Now find the hit identified above as furthest away
662  reco::HitPairListPtr::iterator vertexItr = std::find(clusHitPairVector.begin(),clusHitPairVector.end(),edgeHit);
663 
664  // Make sure enough hits either side, otherwise we just keep the current cluster
665  if (vertexItr == clusHitPairVector.end() || std::distance(clusHitPairVector.begin(),vertexItr) < int(fMinTinyClusterSize) || std::distance(vertexItr,clusHitPairVector.end()) < int(fMinTinyClusterSize)) continue;
666 
667  tempClusterParametersList.push_back(reco::ClusterParameters());
668 
669  reco::ClusterParameters& clusterParams1 = tempClusterParametersList.back();
670 
671  if (makeCandidateCluster(fullPrimaryVec, clusterParams1, clusHitPairVector.begin(), vertexItr, level))
672  {
673  tempClusterParametersList.push_back(reco::ClusterParameters());
674 
675  reco::ClusterParameters& clusterParams2 = tempClusterParametersList.back();
676 
677  if (makeCandidateCluster(fullPrimaryVec, clusterParams2, vertexItr, clusHitPairVector.end(), level)) break;
678  }
679 
680  // If here then we could not make two valid clusters and so we try again
681  tempClusterParametersList.clear();
682  }
683 
684  // Fallback in the event of still large clusters but not defect points
685  if (tempClusterParametersList.empty())
686  {
687  std::cout << indent << "===> no cluster cands, edgeLen: " << edgeLen << ", # hits: " << clusHitPairVector.size() << ", max defect: " << std::get<0>(distEdgeTupleVec.front()) << std::endl;
688 
689  usedDefectDist = 0.;
690 
691  if (edgeLen > 20.)
692  {
693  reco::HitPairListPtr::iterator vertexItr = clusHitPairVector.begin();
694 
695  std::advance(vertexItr, clusHitPairVector.size()/2);
696 
697  tempClusterParametersList.push_back(reco::ClusterParameters());
698 
699  reco::ClusterParameters& clusterParams1 = tempClusterParametersList.back();
700 
701  if (makeCandidateCluster(fullPrimaryVec, clusterParams1, clusHitPairVector.begin(), vertexItr, level))
702  {
703  tempClusterParametersList.push_back(reco::ClusterParameters());
704 
705  reco::ClusterParameters& clusterParams2 = tempClusterParametersList.back();
706 
707  if (!makeCandidateCluster(fullPrimaryVec, clusterParams2, vertexItr, clusHitPairVector.end(), level))
708  tempClusterParametersList.clear();
709  }
710  }
711  }
712 
713  // Can only end with no candidate clusters or two so don't
714  for(auto& clusterParams : tempClusterParametersList)
715  {
716  size_t curOutputClusterListSize = outputClusterList.size();
717 
718  positionItr = subDivideCluster(clusterParams, fullPCA, positionItr, outputClusterList, level+4);
719 
720  std::cout << indent << "Output cluster list prev: " << curOutputClusterListSize << ", now: " << outputClusterList.size() << std::endl;
721 
722  // If the cluster we sent in was successfully broken then the position iterator will be shifted
723  // This means we don't want to restore the current cluster here
724  if (curOutputClusterListSize < outputClusterList.size()) continue;
725 
726  // I think this is where we fill out the rest of the parameters?
727  // Start by adding the 2D hits...
728  // See if we can avoid duplicates by temporarily transferring to a set
729  std::set<const reco::ClusterHit2D*> hitSet;
730 
731  // Loop through 3D hits to get a set of unique 2D hits
732  for(const auto& hit3D : clusterParams.getHitPairListPtr())
733  {
734  for(const auto& hit2D : hit3D->getHits())
735  {
736  if (hit2D) hitSet.insert(hit2D);
737  }
738  }
739 
740  // Now add these to the new cluster
741  for(const auto& hit2D : hitSet)
742  {
743  hit2D->setStatusBit(reco::ClusterHit2D::USED);
744  clusterParams.UpdateParameters(hit2D);
745  }
746 
747  std::cout << indent << "*********>>> storing new subcluster of size " << clusterParams.getHitPairListPtr().size() << std::endl;
748 
749  positionItr = outputClusterList.insert(positionItr,clusterParams);
750 
751  // Are we filling histograms
752  if (fFillHistograms)
753  {
754  // Recover the new fullPCA
755  reco::PrincipalComponents& newFullPCA = clusterParams.getFullPCA();
756 
757  Eigen::Vector3f newPrimaryVec(fullPCA.getEigenVectors().row(2));
758  Eigen::Vector3f lastPrimaryVec(newFullPCA.getEigenVectors().row(2));
759 
760  int num3DHits = clusterParams.getHitPairListPtr().size();
761  int numEdges = clusterParams.getBestEdgeList().size();
762  float cosToLast = newPrimaryVec.dot(lastPrimaryVec);
763  double eigen2To1Ratio = eigenValVec[0] / eigenValVec[1];
764  double eigen1To0Ratio = eigenValVec[1] / eigenValVec[2];
765  double eigen2To0Ratio = eigenValVec[2] / eigenValVec[2];
766 
767  fSubNum3DHits->Fill(std::min(num3DHits,199), 1.);
768  fSubNumEdges->Fill(std::min(numEdges,199), 1.);
769  fSubEigen21Ratio->Fill(eigen2To1Ratio, 1.);
770  fSubEigen20Ratio->Fill(eigen2To0Ratio, 1.);
771  fSubEigen10Ratio->Fill(eigen1To0Ratio, 1.);
772  fSubCosToPrevPCA->Fill(cosToLast, 1.);
773  fSubPrimaryLength->Fill(std::min(eigenValVec[2],199.), 1.);
774  fSubCosExtToPCA->Fill(fullPrimaryVec.dot(edgeVec), 1.);
775  fSubMaxDefect->Fill(std::get<0>(distEdgeTupleVec.front()), 1.);
776  fSubUsedDefect->Fill(usedDefectDist, 1.);
777  }
778 
779  // The above points to the element, want the next element
780  positionItr++;
781  }
782  }
783 
784  return positionItr;
785 }
intermediate_table::iterator iterator
void PCAAnalysis_calc3DDocas(const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca) const
std::string string
Definition: nybbler.cc:12
const Eigen::Vector3f getPosition() const
Definition: Cluster3D.h:158
intermediate_table::const_iterator const_iterator
const EigenValues & getEigenValues() const
Definition: Cluster3D.h:246
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.
std::tuple< const reco::ClusterHit3D *, const reco::ClusterHit3D *, double > EdgeTuple
Definition: Cluster3D.h:344
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:335
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
bool makeCandidateCluster(Eigen::Vector3f &, reco::ClusterParameters &, reco::HitPairListPtr::iterator, reco::HitPairListPtr::iterator, int) const
size_t fMinTinyClusterSize
Minimum size for a "tiny" cluster.
bool fFillHistograms
Histogram definitions.
std::list< ClusterParameters > ClusterParametersList
Definition: Cluster3D.h:404
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247
QTextStream & endl(QTextStream &s)

Member Data Documentation

std::unique_ptr<lar_cluster3d::IClusterAlg> lar_cluster3d::VoronoiPathFinder::fClusterAlg
private

Tools.

Algorithm to do 3D space point clustering

Definition at line 158 of file VoronoiPathFinder_tool.cc.

bool lar_cluster3d::VoronoiPathFinder::fEnableMonitoring
private

FHICL parameters.

Definition at line 128 of file VoronoiPathFinder_tool.cc.

bool lar_cluster3d::VoronoiPathFinder::fFillHistograms
private

Histogram definitions.

Definition at line 135 of file VoronoiPathFinder_tool.cc.

size_t lar_cluster3d::VoronoiPathFinder::fMinTinyClusterSize
private

Minimum size for a "tiny" cluster.

Definition at line 129 of file VoronoiPathFinder_tool.cc.

PrincipalComponentsAlg lar_cluster3d::VoronoiPathFinder::fPCAAlg
private

Definition at line 159 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fSubCosExtToPCA
private

Definition at line 151 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fSubCosToPrevPCA
private

Definition at line 150 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fSubEigen10Ratio
private

Definition at line 148 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fSubEigen20Ratio
private

Definition at line 147 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fSubEigen21Ratio
private

Definition at line 146 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fSubMaxDefect
private

Definition at line 152 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fSubNum3DHits
private

Definition at line 144 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fSubNumEdges
private

Definition at line 145 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fSubPrimaryLength
private

Definition at line 149 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fSubUsedDefect
private

Definition at line 153 of file VoronoiPathFinder_tool.cc.

float lar_cluster3d::VoronoiPathFinder::fTimeToProcess
mutableprivate

Definition at line 130 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fTopEigen10Ratio
private

Definition at line 141 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fTopEigen20Ratio
private

Definition at line 140 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fTopEigen21Ratio
private

Definition at line 139 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fTopNum3DHits
private

Definition at line 137 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fTopNumEdges
private

Definition at line 138 of file VoronoiPathFinder_tool.cc.

TH1F* lar_cluster3d::VoronoiPathFinder::fTopPrimaryLength
private

Definition at line 142 of file VoronoiPathFinder_tool.cc.


The documentation for this class was generated from the following file: