LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
lar_cluster3d::ClusterPathFinder Class Referenceabstract
Inheritance diagram for lar_cluster3d::ClusterPathFinder:
lar_cluster3d::IClusterModAlg

Public Member Functions

 ClusterPathFinder (const fhicl::ParameterSet &)
 Constructor. More...
 
 ~ClusterPathFinder ()
 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...
 
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::ClusterParametersList::iterator positionItr, reco::ClusterParametersList &outputClusterList, int level=0) const
 Use PCA to try to find path in cluster. More...
 
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
 

Private Attributes

bool m_enableMonitoring
 Data members to follow. More...
 
size_t m_minTinyClusterSize
 Minimum size for a "tiny" cluster. More...
 
float m_timeToProcess
 
geo::Geometrym_geometry
 
std::unique_ptr< lar_cluster3d::IClusterAlgm_clusterAlg
 Algorithm to do 3D space point clustering. More...
 
PrincipalComponentsAlg m_pcaAlg
 

Detailed Description

Definition at line 45 of file ClusterPathFinder_tool.cc.

Member Typedef Documentation

Definition at line 105 of file ClusterPathFinder_tool.cc.

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

Definition at line 103 of file ClusterPathFinder_tool.cc.

Definition at line 104 of file ClusterPathFinder_tool.cc.

Constructor & Destructor Documentation

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

Constructor.

Parameters
pset

Definition at line 123 of file ClusterPathFinder_tool.cc.

References configure().

123  :
124  m_pcaAlg(pset.get<fhicl::ParameterSet>("PrincipalComponentsAlg"))
125 {
126  this->configure(pset);
127 }
void configure(fhicl::ParameterSet const &pset) override
lar_cluster3d::ClusterPathFinder::~ClusterPathFinder ( )

Destructor.

Definition at line 131 of file ClusterPathFinder_tool.cc.

132 {
133 }

Member Function Documentation

reco::ClusterParametersList::iterator lar_cluster3d::ClusterPathFinder::breakIntoTinyBits ( reco::ClusterParameters cluster,
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 239 of file ClusterPathFinder_tool.cc.

References buildConvexHull(), reco::PrincipalComponents::getAveHitDoca(), reco::PrincipalComponents::getAvePosition(), reco::ClusterParameters::getBestEdgeList(), reco::PrincipalComponents::getEigenValues(), reco::PrincipalComponents::getEigenVectors(), reco::ClusterParameters::getFullPCA(), reco::ClusterParameters::getHitPairListPtr(), reco::PrincipalComponents::getNumHitsUsed(), reco::ClusterParameters::getSkeletonPCA(), reco::PrincipalComponents::getSvdOK(), art::detail::indent(), art::left(), m_minTinyClusterSize, m_pcaAlg, lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_3D(), lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_calc3DDocas(), art::right(), reco::ClusterParameters::UpdateParameters(), and reco::ClusterHit2D::USED.

Referenced by getTimeToExecute(), and ModifyClusters().

243 {
244  // This needs to be a recursive routine...
245  // Idea is to take the input cluster and order 3D hits by arclength along PCA primary axis
246  // If the cluster is above the minimum number of hits then we divide into two and call ourself
247  // with the two halves. This means we form a new cluster with hits and PCA and then call ourself
248  // If the cluster is below the minimum then we can't break any more, simply add this cluster to
249  // the new output list.
250 
251  // set an indention string
252  std::string pluses(level/2, '+');
253  std::string indent(level/2, ' ');
254 
255  indent += pluses;
256 
257  reco::ClusterParametersList::iterator inputPositionItr = positionItr;
258 
259  // To make best use of this we'll also want the PCA for this cluster... so...
260  // Recover the prime ingredients
261  reco::PrincipalComponents& fullPCA = clusterToBreak.getFullPCA();
262  std::vector<double> eigenValVec = {3. * std::sqrt(fullPCA.getEigenValues()[0]),
263  3. * std::sqrt(fullPCA.getEigenValues()[1]),
264  3. * std::sqrt(fullPCA.getEigenValues()[2])};
265 
266  std::cout << indent << ">>> breakIntoTinyBits with " << clusterToBreak.getHitPairListPtr().size() << " input hits " << std::endl;
267 
268  // It turns out that computing the convex hull surrounding the points in the 2D projection onto the
269  // plane of largest spread in the PCA is a good way to break up the cluster... and we do it here since
270  // we (currently) want this to be part of the standard output
271  buildConvexHull(clusterToBreak, level+2);
272 
273  bool storeCurrentCluster(true);
274  int minimumClusterSize(m_minTinyClusterSize);
275 
276  // Create a rough cut intended to tell us when we've reached the land of diminishing returns
277  if (clusterToBreak.getBestEdgeList().size() > 6 &&
278  clusterToBreak.getHitPairListPtr().size() > size_t(2 * minimumClusterSize))
279  {
280  // Recover the list of 3D hits associated to this cluster
281  reco::HitPairListPtr& clusHitPairVector = clusterToBreak.getHitPairListPtr();
282 
283  // Calculate the doca to the PCA primary axis for each 3D hit
284  // Importantly, this also gives us the arclength along that axis to the hit
285  m_pcaAlg.PCAAnalysis_calc3DDocas(clusHitPairVector, fullPCA);
286 
287  // Sort the hits along the PCA
288  clusHitPairVector.sort([](const auto& left, const auto& right){return left->getArclenToPoca() < right->getArclenToPoca();});
289 
290  // Now we use the convex hull vertex points to form split points for breaking up the incoming cluster
291  reco::EdgeList& bestEdgeList = clusterToBreak.getBestEdgeList();
292  std::vector<const reco::ClusterHit3D*> vertexHitVec;
293 
294  std::cout << indent << "+> Breaking cluster, convex hull has " << bestEdgeList.size() << " edges to work with" << std::endl;
295 
296  for(const auto& edge : bestEdgeList)
297  {
298  vertexHitVec.push_back(std::get<0>(edge));
299  vertexHitVec.push_back(std::get<1>(edge));
300  }
301 
302  // Sort this vector, we aren't worried about duplicates right now...
303  std::sort(vertexHitVec.begin(),vertexHitVec.end(),[](const auto& left, const auto& right){return left->getArclenToPoca() < right->getArclenToPoca();});
304 
305  // Now we create a list of pairs of iterators to the start and end of each subcluster
306  using Hit3DItrPair = std::pair<reco::HitPairListPtr::iterator,reco::HitPairListPtr::iterator>;
307  using VertexPairList = std::list<Hit3DItrPair>;
308 
309  VertexPairList vertexPairList;
310  reco::HitPairListPtr::iterator firstHitItr = clusHitPairVector.begin();
311 
312  for(const auto& hit3D : vertexHitVec)
313  {
314  reco::HitPairListPtr::iterator vertexItr = std::find(firstHitItr,clusHitPairVector.end(),hit3D);
315 
316  if (vertexItr == clusHitPairVector.end())
317  {
318  std::cout << indent << ">>>>>>>>>>>>>>>>> Hit not found in input list, cannot happen? <<<<<<<<<<<<<<<<<<<" << std::endl;
319  break;
320  }
321 
322  std::cout << indent << "+> -- Distance from first to current vertex point: " << std::distance(firstHitItr,vertexItr) << " first: " << *firstHitItr << ", vertex: " << *vertexItr;
323 
324  // Require a minimum number of points...
325  if (std::distance(firstHitItr,vertexItr) > minimumClusterSize)
326  {
327  vertexPairList.emplace_back(Hit3DItrPair(firstHitItr,vertexItr));
328  firstHitItr = vertexItr;
329 
330  std::cout << " ++ made pair ";
331  }
332 
333  std::cout << std::endl;
334  }
335 
336  // Not done if there is distance from first to end of list
337  if (std::distance(firstHitItr,clusHitPairVector.end()) > 0)
338  {
339  std::cout << indent << "+> loop over vertices done, remant distance: " << std::distance(firstHitItr,clusHitPairVector.end()) << std::endl;
340 
341  // In the event we don't have the minimum number of hits we simply extend the last pair
342  if (!vertexPairList.empty() && std::distance(firstHitItr,clusHitPairVector.end()) < minimumClusterSize)
343  vertexPairList.back().second = clusHitPairVector.end();
344  else
345  vertexPairList.emplace_back(Hit3DItrPair(firstHitItr,clusHitPairVector.end()));
346  }
347 
348  std::cout << indent << "+> ---> breaking cluster into " << vertexPairList.size() << " subclusters" << std::endl;
349 
350  if (vertexPairList.size() > 1)
351  {
352  storeCurrentCluster = false;
353 
354  // Ok, now loop through our pairs
355  for(auto& hit3DItrPair : vertexPairList)
356  {
357  reco::ClusterParameters clusterParams;
358  reco::HitPairListPtr& hitPairListPtr = clusterParams.getHitPairListPtr();
359 
360  std::cout << indent << "+> -- building new cluster, size: " << std::distance(hit3DItrPair.first,hit3DItrPair.second) << std::endl;
361 
362  // size the container...
363  hitPairListPtr.resize(std::distance(hit3DItrPair.first,hit3DItrPair.second));
364 
365  // and copy the hits into the container
366  std::copy(hit3DItrPair.first,hit3DItrPair.second,hitPairListPtr.begin());
367 
368  // First stage of feature extraction runs here
369  m_pcaAlg.PCAAnalysis_3D(hitPairListPtr, clusterParams.getFullPCA());
370 
371  // Recover the new fullPCA
372  reco::PrincipalComponents& newFullPCA = clusterParams.getFullPCA();
373 
374  // Must have a valid pca
375  if (newFullPCA.getSvdOK())
376  {
377  std::cout << indent << "+> -- >> cluster has a valid Full PCA" << std::endl;
378 
379  // Need to check if the PCA direction has been reversed
380  Eigen::Vector3f fullPrimaryVec(fullPCA.getEigenVectors()[0][0],fullPCA.getEigenVectors()[0][1],fullPCA.getEigenVectors()[0][2]);
381  Eigen::Vector3f newPrimaryVec(newFullPCA.getEigenVectors()[0][0],newFullPCA.getEigenVectors()[0][1],newFullPCA.getEigenVectors()[0][2]);
382 
383  // If the PCA's are opposite the flip the axes
384  if (fullPrimaryVec.dot(newPrimaryVec) < 0.)
385  {
387 
388  eigenVectors.resize(3);
389 
390  for(size_t vecIdx = 0; vecIdx < 3; vecIdx++)
391  {
392  eigenVectors[vecIdx].resize(3,0.);
393 
394  eigenVectors[vecIdx][0] = -newFullPCA.getEigenVectors()[vecIdx][0];
395  eigenVectors[vecIdx][1] = -newFullPCA.getEigenVectors()[vecIdx][1];
396  eigenVectors[vecIdx][2] = -newFullPCA.getEigenVectors()[vecIdx][2];
397  }
398 
399  newFullPCA = reco::PrincipalComponents(true,
400  newFullPCA.getNumHitsUsed(),
401  newFullPCA.getEigenValues(),
402  eigenVectors,
403  newFullPCA.getAvePosition(),
404  newFullPCA.getAveHitDoca());
405  }
406 
407  // Set the skeleton PCA to make sure it has some value
408  clusterParams.getSkeletonPCA() = clusterParams.getFullPCA();
409 
410  positionItr = breakIntoTinyBits(clusterParams, positionItr, outputClusterList, level+4);
411  }
412  }
413  }
414  }
415 
416  // First question, are we done breaking?
417  if (storeCurrentCluster)
418  {
419  // I think this is where we fill out the rest of the parameters?
420  // Start by adding the 2D hits...
421  // See if we can avoid duplicates by temporarily transferring to a set
422  std::set<const reco::ClusterHit2D*> hitSet;
423 
424  // Loop through 3D hits to get a set of unique 2D hits
425  for(const auto& hit3D : clusterToBreak.getHitPairListPtr())
426  {
427  for(const auto& hit2D : hit3D->getHits())
428  {
429  if (hit2D) hitSet.insert(hit2D);
430  }
431  }
432 
433  // Now add these to the new cluster
434  for(const auto& hit2D : hitSet)
435  {
436  hit2D->setStatusBit(reco::ClusterHit2D::USED);
437  clusterToBreak.UpdateParameters(hit2D);
438  }
439 
440  std::cout << indent << "*********>>> storing new subcluster of size " << clusterToBreak.getHitPairListPtr().size() << std::endl;
441 
442  positionItr = outputClusterList.insert(positionItr,clusterToBreak);
443 
444  // The above points to the element, want the next element
445  positionItr++;
446  }
447  else if (inputPositionItr == positionItr) std::cout << indent << "***** DID NOT STORE A CLUSTER *****" << std::endl;
448 
449  return positionItr;
450 }
void PCAAnalysis_calc3DDocas(const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca) const
bool getSvdOK() const
Definition: Cluster3D.h:226
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:112
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
intermediate_table::iterator iterator
reco::PrincipalComponents & getSkeletonPCA()
Definition: Cluster3D.h:455
const float * getAvePosition() const
Definition: Cluster3D.h:230
int getNumHitsUsed() const
Definition: Cluster3D.h:227
reco::HitPairListPtr & getHitPairListPtr()
Definition: Cluster3D.h:453
std::list< EdgeTuple > EdgeList
Definition: Cluster3D.h:326
void buildConvexHull(reco::ClusterParameters &clusterParameters, int level=0) const
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:454
std::string indent(std::size_t const i)
size_t m_minTinyClusterSize
Minimum size for a "tiny" cluster.
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:317
std::vector< std::vector< float > > EigenVectors
Definition: Cluster3D.h:209
reco::ClusterParametersList::iterator breakIntoTinyBits(reco::ClusterParameters &cluster, reco::ClusterParametersList::iterator positionItr, reco::ClusterParametersList &outputClusterList, int level=0) const
Use PCA to try to find path in cluster.
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:104
const float * getEigenValues() const
Definition: Cluster3D.h:228
const float getAveHitDoca() const
Definition: Cluster3D.h:231
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:229
void lar_cluster3d::ClusterPathFinder::buildConvexHull ( reco::ClusterParameters clusterParameters,
int  level = 0 
) const
private

Definition at line 452 of file ClusterPathFinder_tool.cc.

References reco::PrincipalComponents::getAvePosition(), reco::ClusterParameters::getBestEdgeList(), lar_cluster3d::ConvexHull::getConvexHull(), lar_cluster3d::ConvexHull::getConvexHullArea(), reco::PrincipalComponents::getEigenVectors(), reco::ClusterParameters::getFullPCA(), reco::ClusterParameters::getHit3DToEdgeMap(), reco::ClusterParameters::getHitPairListPtr(), reco::ClusterHit3D::getPosition(), art::detail::indent(), art::left(), max, and art::right().

Referenced by breakIntoTinyBits().

453 {
454  // set an indention string
455  std::string minuses(level/2, '-');
456  std::string indent(level/2, ' ');
457 
458  indent += minuses;
459 
460  // The plan is to build the enclosing 2D polygon around the points in the PCA plane of most spread for this cluster
461  // To do so we need to start by building a list of 2D projections onto the plane of most spread...
462  reco::PrincipalComponents& pca = clusterParameters.getFullPCA();
463 
464  // Recover the parameters from the Principal Components Analysis that we need to project and accumulate
465  Eigen::Vector3f pcaCenter(pca.getAvePosition()[0],pca.getAvePosition()[1],pca.getAvePosition()[2]);
466  Eigen::Vector3f planeVec0(pca.getEigenVectors()[0][0],pca.getEigenVectors()[0][1],pca.getEigenVectors()[0][2]);
467  Eigen::Vector3f planeVec1(pca.getEigenVectors()[1][0],pca.getEigenVectors()[1][1],pca.getEigenVectors()[1][2]);
468  Eigen::Vector3f pcaPlaneNrml(pca.getEigenVectors()[2][0],pca.getEigenVectors()[2][1],pca.getEigenVectors()[2][2]);
469 
470  // Let's get the rotation matrix from the standard coordinate system to the PCA system.
471  Eigen::Matrix3f rotationMatrix;
472 
473  rotationMatrix << planeVec0(0), planeVec0(1), planeVec0(2),
474  planeVec1(0), planeVec1(1), planeVec1(2),
475  pcaPlaneNrml(0), pcaPlaneNrml(1), pcaPlaneNrml(2);
476 
477  //dcel2d::PointList pointList;
478  using Point = std::tuple<float,float,const reco::ClusterHit3D*>;
479  using PointList = std::list<Point>;
480  PointList pointList;
481 
482  // Loop through hits and do projection to plane
483  for(const auto& hit3D : clusterParameters.getHitPairListPtr())
484  {
485  Eigen::Vector3f pcaToHitVec(hit3D->getPosition()[0] - pcaCenter(0),
486  hit3D->getPosition()[1] - pcaCenter(1),
487  hit3D->getPosition()[2] - pcaCenter(2));
488  Eigen::Vector3f pcaToHit = rotationMatrix * pcaToHitVec;
489 
490  pointList.emplace_back(dcel2d::Point(pcaToHit(0),pcaToHit(1),hit3D));
491  }
492 
493  // Sort the point vec by increasing x, then increase y
494  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);});
495 
496  // containers for finding the "best" hull...
497  std::vector<ConvexHull> convexHullVec;
498  std::vector<PointList> rejectedListVec;
499  bool increaseDepth(pointList.size() > 5);
500  float lastArea(std::numeric_limits<float>::max());
501 
502  while(increaseDepth)
503  {
504  // Get another convexHull container
505  convexHullVec.push_back(ConvexHull(pointList));
506  rejectedListVec.push_back(PointList());
507 
508  const ConvexHull& convexHull = convexHullVec.back();
509  PointList& rejectedList = rejectedListVec.back();
510  const PointList& convexHullPoints = convexHull.getConvexHull();
511 
512  increaseDepth = false;
513 
514  if (convexHull.getConvexHullArea() > 0.)
515  {
516  std::cout << indent << "-> built convex hull, 3D hits: " << pointList.size() << " with " << convexHullPoints.size() << " vertices" << ", area: " << convexHull.getConvexHullArea() << std::endl;
517  std::cout << indent << "-> -Points:";
518  for(const auto& point : convexHullPoints)
519  std::cout << " (" << std::get<0>(point) << "," << std::get<1>(point) << ")";
520  std::cout << std::endl;
521 
522  if (convexHullVec.size() < 2 || convexHull.getConvexHullArea() < 0.8 * lastArea)
523  {
524  for(auto& point : convexHullPoints)
525  {
526  pointList.remove(point);
527  rejectedList.emplace_back(point);
528  }
529  lastArea = convexHull.getConvexHullArea();
530 // increaseDepth = true;
531  }
532  }
533  }
534 
535  // do we have a valid convexHull?
536  while(!convexHullVec.empty() && convexHullVec.back().getConvexHullArea() < 0.5)
537  {
538  convexHullVec.pop_back();
539  rejectedListVec.pop_back();
540  }
541 
542  // If we found the convex hull then build edges around the region
543  if (!convexHullVec.empty())
544  {
545  size_t nRejectedTotal(0);
546  reco::HitPairListPtr hitPairListPtr = clusterParameters.getHitPairListPtr();
547 
548  for(const auto& rejectedList : rejectedListVec)
549  {
550  nRejectedTotal += rejectedList.size();
551 
552  for(const auto& rejectedPoint : rejectedList)
553  {
554  std::cout << indent << "-> -- Point is " << convexHullVec.back().findNearestDistance(rejectedPoint) << " from nearest edge" << std::endl;
555 
556  if (convexHullVec.back().findNearestDistance(rejectedPoint) > 0.5)
557  hitPairListPtr.remove(std::get<2>(rejectedPoint));
558  }
559  }
560 
561  std::cout << indent << "-> Removed " << nRejectedTotal << " leaving " << pointList.size() << "/" << hitPairListPtr.size() << " points" << std::endl;
562 
563  // Now add "edges" to the cluster to describe the convex hull (for the display)
564  reco::Hit3DToEdgeMap& edgeMap = clusterParameters.getHit3DToEdgeMap();
565  reco::EdgeList& bestEdgeList = clusterParameters.getBestEdgeList();
566 
567  Point lastPoint = convexHullVec.back().getConvexHull().front();
568 
569  for(auto& curPoint : convexHullVec.back().getConvexHull())
570  {
571  if (curPoint == lastPoint) continue;
572 
573  const reco::ClusterHit3D* lastPoint3D = std::get<2>(lastPoint);
574  const reco::ClusterHit3D* curPoint3D = std::get<2>(curPoint);
575 
576  float distBetweenPoints = (curPoint3D->getPosition()[0] - lastPoint3D->getPosition()[0]) * (curPoint3D->getPosition()[0] - lastPoint3D->getPosition()[0])
577  + (curPoint3D->getPosition()[1] - lastPoint3D->getPosition()[1]) * (curPoint3D->getPosition()[1] - lastPoint3D->getPosition()[1])
578  + (curPoint3D->getPosition()[2] - lastPoint3D->getPosition()[2]) * (curPoint3D->getPosition()[2] - lastPoint3D->getPosition()[2]);
579 
580  distBetweenPoints = std::sqrt(distBetweenPoints);
581 
582  reco::EdgeTuple edge(lastPoint3D,curPoint3D,distBetweenPoints);
583 
584  edgeMap[lastPoint3D].push_back(edge);
585  edgeMap[curPoint3D].push_back(edge);
586  bestEdgeList.emplace_back(edge);
587 
588  lastPoint = curPoint;
589  }
590  }
591 
592  return;
593 }
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:112
reco::EdgeList & getBestEdgeList()
Definition: Cluster3D.h:458
const float * getAvePosition() const
Definition: Cluster3D.h:230
reco::Hit3DToEdgeMap & getHit3DToEdgeMap()
Definition: Cluster3D.h:456
reco::HitPairListPtr & getHitPairListPtr()
Definition: Cluster3D.h:453
std::tuple< float, float, const reco::ClusterHit3D * > Point
std::list< EdgeTuple > EdgeList
Definition: Cluster3D.h:326
Int_t max
Definition: plot.C:27
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:454
std::tuple< double, double, const reco::ClusterHit3D * > Point
Definitions used by the VoronoiDiagram algorithm.
Definition: DCEL.h:34
std::string indent(std::size_t const i)
std::tuple< const reco::ClusterHit3D *, const reco::ClusterHit3D *, double > EdgeTuple
Definition: Cluster3D.h:325
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:317
const float * getPosition() const
Definition: Cluster3D.h:147
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:104
std::unordered_map< const reco::ClusterHit3D *, reco::EdgeList > Hit3DToEdgeMap
Definition: Cluster3D.h:328
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:229
void lar_cluster3d::ClusterPathFinder::buildVoronoiDiagram ( reco::ClusterParameters clusterParameters,
int  level = 0 
) const
private

Definition at line 596 of file ClusterPathFinder_tool.cc.

References voronoi2d::VoronoiDiagram::buildVoronoiDiagram(), reco::PrincipalComponents::getAvePosition(), reco::ClusterParameters::getBestEdgeList(), reco::PrincipalComponents::getEigenVectors(), reco::ClusterParameters::getFaceList(), reco::ClusterParameters::getFullPCA(), reco::ClusterParameters::getHalfEdgeList(), reco::ClusterParameters::getHit3DToEdgeMap(), reco::ClusterParameters::getHitPairListPtr(), reco::ClusterHit3D::getPosition(), reco::ClusterParameters::getVertexList(), art::left(), and art::right().

Referenced by ModifyClusters().

597 {
598  // The plan is to build the enclosing 2D polygon around the points in the PCA plane of most spread for this cluster
599  // To do so we need to start by building a list of 2D projections onto the plane of most spread...
600  reco::PrincipalComponents& pca = clusterParameters.getFullPCA();
601 
602  // Recover the parameters from the Principal Components Analysis that we need to project and accumulate
603  Eigen::Vector3f pcaCenter(pca.getAvePosition()[0],pca.getAvePosition()[1],pca.getAvePosition()[2]);
604  Eigen::Vector3f planeVec0(pca.getEigenVectors()[0][0],pca.getEigenVectors()[0][1],pca.getEigenVectors()[0][2]);
605  Eigen::Vector3f planeVec1(pca.getEigenVectors()[1][0],pca.getEigenVectors()[1][1],pca.getEigenVectors()[1][2]);
606  Eigen::Vector3f pcaPlaneNrml(pca.getEigenVectors()[2][0],pca.getEigenVectors()[2][1],pca.getEigenVectors()[2][2]);
607 
608  // Leave the following code bits as an example of a more complicated way to do what we are trying to do here
609  // (but in case I want to use quaternions again!)
610  //
611  //Eigen::Vector3f unitVecX(1.,0.,0.);
612  //
613  //Eigen::Quaternionf rotationMatrix = Eigen::Quaternionf::FromTwoVectors(planeVec0,unitVecX);
614  //
615  //Eigen::Matrix3f Rmatrix = rotationMatrix.toRotationMatrix();
616  //Eigen::Matrix3f RInvMatrix = rotationMatrix.inverse().toRotationMatrix();
617 
618  // Let's get the rotation matrix from the standard coordinate system to the PCA system.
619  Eigen::Matrix3f rotationMatrix;
620 
621  rotationMatrix << planeVec0(0), planeVec0(1), planeVec0(2),
622  planeVec1(0), planeVec1(1), planeVec1(2),
623  pcaPlaneNrml(0), pcaPlaneNrml(1), pcaPlaneNrml(2);
624 
625  dcel2d::PointList pointList;
626 
627  // Loop through hits and do projection to plane
628  for(const auto& hit3D : clusterParameters.getHitPairListPtr())
629  {
630  Eigen::Vector3f pcaToHitVec(hit3D->getPosition()[0] - pcaCenter(0),
631  hit3D->getPosition()[1] - pcaCenter(1),
632  hit3D->getPosition()[2] - pcaCenter(2));
633  Eigen::Vector3f pcaToHit = rotationMatrix * pcaToHitVec;
634 
635  pointList.emplace_back(dcel2d::Point(pcaToHit(0),pcaToHit(1),hit3D));
636  }
637 
638  // Sort the point vec by increasing x, then increase y
639  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);});
640 
641  // Set up the voronoi diagram builder
642  voronoi2d::VoronoiDiagram voronoiDiagram(clusterParameters.getHalfEdgeList(),clusterParameters.getVertexList(),clusterParameters.getFaceList());
643 
644  // And make the diagram
645  voronoiDiagram.buildVoronoiDiagram(pointList);
646 
647  // Recover the voronoi diagram vertex list and the container to store them in
648  dcel2d::VertexList& vertexList = clusterParameters.getVertexList();
649 
650  // Now get the inverse of the rotation matrix so we can get the vertex positions,
651  // which lie in the plane of the two largest PCA axes, in the standard coordinate system
652  Eigen::Matrix3f rotationMatrixInv = rotationMatrix.inverse();
653 
654  // Translate and fill
655  for(auto& vertex : vertexList)
656  {
657  Eigen::Vector3f coords = rotationMatrixInv * vertex.getCoords();
658 
659  coords += pcaCenter;
660 
661  vertex.setCoords(coords);
662  }
663 
664  // Now do the Convex Hull
665  // Now add "edges" to the cluster to describe the convex hull (for the display)
666  reco::Hit3DToEdgeMap& edgeMap = clusterParameters.getHit3DToEdgeMap();
667  reco::EdgeList& bestEdgeList = clusterParameters.getBestEdgeList();
668 
669 // const dcel2d::PointList& edgePoints = voronoiDiagram.getConvexHull();
670 // PointList localList;
671 //
672 // for(const auto& edgePoint : edgePoints) localList.emplace_back(std::get<0>(edgePoint),std::get<1>(edgePoint),std::get<2>(edgePoint));
673 //
674 // // Sort the point vec by increasing x, then increase y
675 // 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);});
676 //
677 // // Why do I need to do this?
678 // ConvexHull convexHull(localList);
679 //
680 // Point lastPoint = convexHull.getConvexHull().front();
681  dcel2d::Point lastPoint = voronoiDiagram.getConvexHull().front();
682 
683 // std::cout << "@@@@>> Build convex hull, voronoi handed " << edgePoints.size() << " points, convexHull cut to " << convexHull.getConvexHull().size() << std::endl;
684 
685 // for(auto& curPoint : convexHull.getConvexHull())
686  for(auto& curPoint : voronoiDiagram.getConvexHull())
687  {
688  if (curPoint == lastPoint) continue;
689 
690  const reco::ClusterHit3D* lastPoint3D = std::get<2>(lastPoint);
691  const reco::ClusterHit3D* curPoint3D = std::get<2>(curPoint);
692 
693  float distBetweenPoints = (curPoint3D->getPosition()[0] - lastPoint3D->getPosition()[0]) * (curPoint3D->getPosition()[0] - lastPoint3D->getPosition()[0])
694  + (curPoint3D->getPosition()[1] - lastPoint3D->getPosition()[1]) * (curPoint3D->getPosition()[1] - lastPoint3D->getPosition()[1])
695  + (curPoint3D->getPosition()[2] - lastPoint3D->getPosition()[2]) * (curPoint3D->getPosition()[2] - lastPoint3D->getPosition()[2]);
696 
697  distBetweenPoints = std::sqrt(distBetweenPoints);
698 
699  reco::EdgeTuple edge(lastPoint3D,curPoint3D,distBetweenPoints);
700 
701  edgeMap[lastPoint3D].push_back(edge);
702  edgeMap[curPoint3D].push_back(edge);
703  bestEdgeList.emplace_back(edge);
704 
705  lastPoint = curPoint;
706  }
707 
708  std::cout << "****> vertexList containted " << vertexList.size() << " vertices" << std::endl;
709 
710  return;
711 }
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:112
reco::EdgeList & getBestEdgeList()
Definition: Cluster3D.h:458
const float * getAvePosition() const
Definition: Cluster3D.h:230
reco::Hit3DToEdgeMap & getHit3DToEdgeMap()
Definition: Cluster3D.h:456
reco::HitPairListPtr & getHitPairListPtr()
Definition: Cluster3D.h:453
std::list< EdgeTuple > EdgeList
Definition: Cluster3D.h:326
VoronoiDiagram class definiton.
Definition: Voronoi.h:33
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:454
std::tuple< double, double, const reco::ClusterHit3D * > Point
Definitions used by the VoronoiDiagram algorithm.
Definition: DCEL.h:34
void buildVoronoiDiagram(const dcel2d::PointList &)
Given an input set of 2D points construct a 2D voronoi diagram.
Definition: Voronoi.cxx:135
std::tuple< const reco::ClusterHit3D *, const reco::ClusterHit3D *, double > EdgeTuple
Definition: Cluster3D.h:325
const float * getPosition() const
Definition: Cluster3D.h:147
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:104
dcel2d::FaceList & getFaceList()
Definition: Cluster3D.h:460
std::list< Point > PointList
Definition: DCEL.h:35
std::unordered_map< const reco::ClusterHit3D *, reco::EdgeList > Hit3DToEdgeMap
Definition: Cluster3D.h:328
dcel2d::HalfEdgeList & getHalfEdgeList()
Definition: Cluster3D.h:462
std::list< Vertex > VertexList
Definition: DCEL.h:178
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:229
dcel2d::VertexList & getVertexList()
Definition: Cluster3D.h:461
vertex reconstruction
float lar_cluster3d::ClusterPathFinder::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 714 of file ClusterPathFinder_tool.cc.

References d, DEFINE_ART_CLASS_TOOL, den, and e.

Referenced by getTimeToExecute().

720 {
721  // Technique is to compute the arclength to each point of closest approach
722  Eigen::Vector3f w0 = P0 - P1;
723  float a(1.);
724  float b(u0.dot(u1));
725  float c(1.);
726  float d(u0.dot(w0));
727  float e(u1.dot(w0));
728  float den(a * c - b * b);
729 
730  float arcLen0 = (b * e - c * d) / den;
731  float arcLen1 = (a * e - b * d) / den;
732 
733  poca0 = P0 + arcLen0 * u0;
734  poca1 = P1 + arcLen1 * u1;
735 
736  return (poca0 - poca1).norm();
737 }
Float_t den
Definition: plot.C:37
Float_t d
Definition: plot.C:237
Float_t e
Definition: plot.C:34
virtual void lar_cluster3d::IClusterModAlg::configure ( const fhicl::ParameterSet )
pure virtualinherited

Interface for configuring the particular algorithm tool.

Parameters
ParameterSetThe input set of parameters for configuration
void lar_cluster3d::ClusterPathFinder::configure ( fhicl::ParameterSet const &  pset)
override

Definition at line 137 of file ClusterPathFinder_tool.cc.

References fhicl::ParameterSet::get(), m_clusterAlg, m_enableMonitoring, m_geometry, m_minTinyClusterSize, and m_timeToProcess.

Referenced by ClusterPathFinder().

138 {
139  m_enableMonitoring = pset.get<bool> ("EnableMonitoring", true );
140  m_minTinyClusterSize = pset.get<size_t>("MinTinyClusterSize",40);
141  m_clusterAlg = art::make_tool<lar_cluster3d::IClusterAlg>(pset.get<fhicl::ParameterSet>("ClusterAlg"));
142 
144 
145  m_geometry = &*geometry;
146 
147  m_timeToProcess = 0.;
148 
149  return;
150 }
std::unique_ptr< lar_cluster3d::IClusterAlg > m_clusterAlg
Algorithm to do 3D space point clustering.
size_t m_minTinyClusterSize
Minimum size for a "tiny" cluster.
bool m_enableMonitoring
Data members to follow.
float lar_cluster3d::ClusterPathFinder::getTimeToExecute ( ) const
inlineoverridevirtual

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

Implements lar_cluster3d::IClusterModAlg.

Definition at line 81 of file ClusterPathFinder_tool.cc.

References breakIntoTinyBits(), closestApproach(), and m_timeToProcess.

void lar_cluster3d::ClusterPathFinder::initializeHistograms ( art::TFileDirectory )
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 152 of file ClusterPathFinder_tool.cc.

153 {
154  return;
155 }
void lar_cluster3d::ClusterPathFinder::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 157 of file ClusterPathFinder_tool.cc.

References breakIntoTinyBits(), buildVoronoiDiagram(), reco::ClusterParameters::daughterList(), reco::ClusterParameters::getHitPairListPtr(), m_clusterAlg, m_enableMonitoring, m_minTinyClusterSize, and m_timeToProcess.

158 {
166  // Initial clustering is done, now trim the list and get output parameters
167  cet::cpu_timer theClockBuildClusters;
168 
169  // Start clocks if requested
170  if (m_enableMonitoring) theClockBuildClusters.start();
171 
172  int countClusters(0);
173 
174  // This is the loop over candidate 3D clusters
175  // Note that it might be that the list of candidate clusters is modified by splitting
176  // So we use the following construct to make sure we get all of them
177  reco::ClusterParametersList::iterator clusterParametersListItr = clusterParametersList.begin();
178 
179  while(clusterParametersListItr != clusterParametersList.end())
180  {
181  // Dereference to get the cluster paramters
182  reco::ClusterParameters& clusterParameters = *clusterParametersListItr;
183 
184  std::cout << "**> Looking at Cluster " << countClusters++ << std::endl;
185 
186  // It turns out that computing the convex hull surrounding the points in the 2D projection onto the
187  // plane of largest spread in the PCA is a good way to break up the cluster... and we do it here since
188  // we (currently) want this to be part of the standard output
189  buildVoronoiDiagram(clusterParameters);
190 
191  // Make sure our cluster has enough hits...
192  if (clusterParameters.getHitPairListPtr().size() > m_minTinyClusterSize)
193  {
194  // Get an interim cluster list
195  reco::ClusterParametersList reclusteredParameters;
196 
197  // Call the main workhorse algorithm for building the local version of candidate 3D clusters
198  m_clusterAlg->Cluster3DHits(clusterParameters.getHitPairListPtr(), reclusteredParameters);
199 
200  std::cout << ">>>>>>>>>>> Reclustered to " << reclusteredParameters.size() << " Clusters <<<<<<<<<<<<<<<" << std::endl;
201 
202  // Only process non-empty results
203  if (!reclusteredParameters.empty())
204  {
205  // Loop over the reclustered set
206  for (auto& cluster : reclusteredParameters)
207  {
208  std::cout << "****> Calling breakIntoTinyBits" << std::endl;
209 
210  // Break our cluster into smaller elements...
211  breakIntoTinyBits(cluster, cluster.daughterList().end(), cluster.daughterList(), 4);
212 
213  std::cout << "****> Broke Cluster with " << cluster.getHitPairListPtr().size() << " into " << cluster.daughterList().size() << " sub clusters";
214  for(auto& clus : cluster.daughterList()) std::cout << ", " << clus.getHitPairListPtr().size();
215  std::cout << std::endl;
216 
217  // Add the daughters to the cluster
218  clusterParameters.daughterList().insert(clusterParameters.daughterList().end(),cluster);
219  }
220  }
221  }
222 
223  // Go to next cluster parameters object
224  clusterParametersListItr++;
225  }
226 
227  if (m_enableMonitoring)
228  {
229  theClockBuildClusters.stop();
230 
231  m_timeToProcess = theClockBuildClusters.accumulated_real_time();
232  }
233 
234  mf::LogDebug("Cluster3D") << ">>>>> Cluster Path finding done" << std::endl;
235 
236  return;
237 }
intermediate_table::iterator iterator
std::unique_ptr< lar_cluster3d::IClusterAlg > m_clusterAlg
Algorithm to do 3D space point clustering.
reco::HitPairListPtr & getHitPairListPtr()
Definition: Cluster3D.h:453
Cluster finding and building.
ClusterParametersList & daughterList()
Definition: Cluster3D.h:427
size_t m_minTinyClusterSize
Minimum size for a "tiny" cluster.
reco::ClusterParametersList::iterator breakIntoTinyBits(reco::ClusterParameters &cluster, reco::ClusterParametersList::iterator positionItr, reco::ClusterParametersList &outputClusterList, int level=0) const
Use PCA to try to find path in cluster.
bool m_enableMonitoring
Data members to follow.
void buildVoronoiDiagram(reco::ClusterParameters &clusterParameters, int level=0) const
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
std::list< ClusterParameters > ClusterParametersList
Definition: Cluster3D.h:381

Member Data Documentation

std::unique_ptr<lar_cluster3d::IClusterAlg> lar_cluster3d::ClusterPathFinder::m_clusterAlg
private

Algorithm to do 3D space point clustering.

Definition at line 119 of file ClusterPathFinder_tool.cc.

Referenced by configure(), and ModifyClusters().

bool lar_cluster3d::ClusterPathFinder::m_enableMonitoring
private

Data members to follow.

Definition at line 113 of file ClusterPathFinder_tool.cc.

Referenced by configure(), and ModifyClusters().

geo::Geometry* lar_cluster3d::ClusterPathFinder::m_geometry
private

Definition at line 117 of file ClusterPathFinder_tool.cc.

Referenced by configure().

size_t lar_cluster3d::ClusterPathFinder::m_minTinyClusterSize
private

Minimum size for a "tiny" cluster.

Definition at line 114 of file ClusterPathFinder_tool.cc.

Referenced by breakIntoTinyBits(), configure(), and ModifyClusters().

PrincipalComponentsAlg lar_cluster3d::ClusterPathFinder::m_pcaAlg
private

Definition at line 120 of file ClusterPathFinder_tool.cc.

Referenced by breakIntoTinyBits().

float lar_cluster3d::ClusterPathFinder::m_timeToProcess
mutableprivate

Definition at line 115 of file ClusterPathFinder_tool.cc.

Referenced by configure(), getTimeToExecute(), and ModifyClusters().


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